app: stacked_cores: try adding multiple control loops

This commit is contained in:
colin 2022-10-01 04:35:04 -07:00
parent 2353eb531c
commit 8c9e02a77f
4 changed files with 322 additions and 53 deletions

View File

@ -12,6 +12,10 @@ class SimParams:
self.um = um
self.drive_str = drive
@property
def run(self) -> str:
raise NotImplementedError
@property
def drive(self) -> int:
return int(float(self.drive_str))
@ -31,11 +35,11 @@ class SimParams:
@property
def machine_name(self) -> str:
return f"40-{self.um_str}rad-{self.couplings}coupling-{self.wrappings}_1_winding-{self.drive_str}-drive"
return f"{self.run}-{self.um_str}rad-{self.couplings}coupling-{self.wrappings}_1_winding-{self.drive_str}-drive"
@property
def human_name(self) -> str:
return f"40 {self.couplings}x {self.wrappings}:1 ({self.um}um, {self.drive_str} I)"
return f"{self.run} {self.couplings}x {self.wrappings}:1 ({self.um}um, {self.drive_str} I)"
@property
def tuple(self):
@ -53,50 +57,64 @@ class SimParams:
)
return self.tuple == match_tuple
class SimParams40(SimParams):
@property
def run(self) -> str:
return "40"
class SimParams41(SimParams):
@property
def run(self) -> str:
return "41"
sims = [
# params, human friendly db name, normalization
(SimParams(12, 1, 400, "5e10"), "fwd_40_12_3_1_5e10", 17000),
(SimParams(6, 1, 400, "5e10"), "fwd_40_6_3_1_5e10", 17000),
(SimParams(6, 3, 400, "5e10"), "fwd_40_6_7_1_5e10", 15000),
(SimParams40(12, 1, 400, "5e10"), "fwd_40_12_3_1_5e10", 17000),
(SimParams40(6, 1, 400, "5e10"), "fwd_40_6_3_1_5e10", 17000),
(SimParams40(6, 3, 400, "5e10"), "fwd_40_6_7_1_5e10", 15000),
(SimParams(20, 1, 600, "3e10"), "fwd_40_600um_20_3_1_3e10", 10000),
(SimParams(20, 1, 600, "5e10"), "fwd_40_600um_20_3_1_5e10", 19000),
(SimParams(20, 1, 600, "1e11"), "fwd_40_600um_20_3_1_1e11", 15000),
(SimParams(20, 1, 600, "2e11"), "fwd_40_600um_20_3_1_2e11", 15000),
(SimParams(12, 2, 600, "5e10"), "fwd_40_600um_12_5_1_5e10", 12000),
(SimParams(12, 2, 600, "1e11"), "fwd_40_600um_12_5_1_1e11", 14000),
(SimParams(12, 2, 600, "2e11"), "fwd_40_600um_12_5_1_2e11", 14000),
(SimParams(8, 3, 600, "5e10"), "fwd_40_600um_8_7_1_5e10", 12000),
(SimParams(8, 3, 600, "1e11"), "fwd_40_600um_8_7_1_1e11", 12000),
(SimParams(6, 4, 600, "5e10"), "fwd_40_600um_6_9_1_5e10", 12000),
(SimParams(6, 4, 600, "1e11"), "fwd_40_600um_6_9_1_1e11", 12000),
(SimParams(6, 5, 600, "5e10"), "fwd_40_600um_6_11_1_5e10", 10000),
(SimParams40(20, 1, 600, "3e10"), "fwd_40_600um_20_3_1_3e10", 10000),
(SimParams40(20, 1, 600, "5e10"), "fwd_40_600um_20_3_1_5e10", 19000),
(SimParams40(20, 1, 600, "1e11"), "fwd_40_600um_20_3_1_1e11", 15000),
(SimParams40(20, 1, 600, "2e11"), "fwd_40_600um_20_3_1_2e11", 15000),
(SimParams40(12, 2, 600, "5e10"), "fwd_40_600um_12_5_1_5e10", 12000),
(SimParams40(12, 2, 600, "1e11"), "fwd_40_600um_12_5_1_1e11", 14000),
(SimParams40(12, 2, 600, "2e11"), "fwd_40_600um_12_5_1_2e11", 14000),
(SimParams40(8, 3, 600, "5e10"), "fwd_40_600um_8_7_1_5e10", 12000),
(SimParams40(8, 3, 600, "1e11"), "fwd_40_600um_8_7_1_1e11", 12000),
(SimParams40(6, 4, 600, "5e10"), "fwd_40_600um_6_9_1_5e10", 12000),
(SimParams40(6, 4, 600, "1e11"), "fwd_40_600um_6_9_1_1e11", 12000),
(SimParams40(6, 5, 600, "5e10"), "fwd_40_600um_6_11_1_5e10", 10000),
(SimParams(6, 3, 600, "5e10"), "fwd_40_600um_6_7_1_5e10", 20000),
# (SimParams(10, 3, 600, "5e10"), "fwd_40_600um_10_7_1_5e10", 20000),
(SimParams(6, 2, 600, "5e10"), "fwd_40_600um_6_5_1_5e10", 20000),
(SimParams(8, 2, 600, "5e10"), "fwd_40_600um_8_5_1_5e10", 20000),
(SimParams(10, 2, 600, "5e10"), "fwd_40_600um_10_5_1_5e10", 20000),
(SimParams40(6, 3, 600, "5e10"), "fwd_40_600um_6_7_1_5e10", 20000),
# (SimParams40(10, 3, 600, "5e10"), "fwd_40_600um_10_7_1_5e10", 20000),
(SimParams40(6, 2, 600, "5e10"), "fwd_40_600um_6_5_1_5e10", 20000),
(SimParams40(8, 2, 600, "5e10"), "fwd_40_600um_8_5_1_5e10", 20000),
(SimParams40(10, 2, 600, "5e10"), "fwd_40_600um_10_5_1_5e10", 20000),
(SimParams(24, 1, 800, "1e11"), "fwd_40_800um_24_3_1_1e11", 12000),
(SimParams(18, 2, 800, "1e11"), "fwd_40_800um_18_5_1_1e11", 10000),
(SimParams(12, 3, 800, "5e10"), "fwd_40_800um_12_7_1_5e10", 8000),
(SimParams40(24, 1, 800, "1e11"), "fwd_40_800um_24_3_1_1e11", 12000),
(SimParams40(18, 2, 800, "1e11"), "fwd_40_800um_18_5_1_1e11", 10000),
(SimParams40(12, 3, 800, "5e10"), "fwd_40_800um_12_7_1_5e10", 8000),
# partially complete
(SimParams(18, 2, 800, "5e10"), "fwd_40_800um_18_5_1_5e10", 10000),
(SimParams(12, 3, 800, "1e11"), "fwd_40_800um_12_7_1_1e11", 8000),
(SimParams(10, 4, 800, "2e11"), "fwd_40_800um_10_9_1_2e11", 8000),
(SimParams(8, 5, 800, "5e10"), "fwd_40_800um_8_11_1_5e10", 8000),
(SimParams(12, 2, 800, "5e10"), "fwd_40_800um_12_5_1_5e10", 8000),
(SimParams(10, 4, 800, "5e10"), "fwd_40_800um_10_9_1_5e10", 8000),
(SimParams(12, 2, 800, "1e11"), "fwd_40_800um_12_5_1_1e11", 8000),
(SimParams40(18, 2, 800, "5e10"), "fwd_40_800um_18_5_1_5e10", 10000),
(SimParams40(12, 3, 800, "1e11"), "fwd_40_800um_12_7_1_1e11", 8000),
(SimParams40(10, 4, 800, "2e11"), "fwd_40_800um_10_9_1_2e11", 8000),
(SimParams40(8, 5, 800, "5e10"), "fwd_40_800um_8_11_1_5e10", 8000),
(SimParams40(12, 2, 800, "5e10"), "fwd_40_800um_12_5_1_5e10", 8000),
(SimParams40(10, 4, 800, "5e10"), "fwd_40_800um_10_9_1_5e10", 8000),
(SimParams40(12, 2, 800, "1e11"), "fwd_40_800um_12_5_1_1e11", 8000),
(SimParams(12, 4, 1200, "1e11"), "fwd_40_1200um_12_9_1_1e11", 8000),
(SimParams(8, 5, 800, "1e11"), "fwd_40_800um_8_11_1_1e11", 8000),
(SimParams(10, 4, 800, "1e11"), "fwd_40_800um_10_9_1_1e11", 8000),
(SimParams(10, 5, 1200, "1e11"), "fwd_40_1200um_10_11_1_1e11", 8000),
(SimParams(12, 4, 1200, "2e11"), "fwd_40_1200um_12_9_1_2e11", 8000),
(SimParams40(12, 4, 1200, "1e11"), "fwd_40_1200um_12_9_1_1e11", 8000),
(SimParams40(8, 5, 800, "1e11"), "fwd_40_800um_8_11_1_1e11", 8000),
(SimParams40(10, 4, 800, "1e11"), "fwd_40_800um_10_9_1_1e11", 8000),
(SimParams40(10, 5, 1200, "1e11"), "fwd_40_1200um_10_11_1_1e11", 8000),
(SimParams40(12, 4, 1200, "2e11"), "fwd_40_1200um_12_9_1_2e11", 8000),
(SimParams41(9, 1, 400, "3e9"), None, 20000),
(SimParams41(9, 3, 600, "3e9"), None, 20000),
(SimParams41(10, 3, 800, "3e9"), None, 20000),
]
measurements = { real.machine_name: [human, norm, None, None] for (real, human, norm) in sims }
@ -122,7 +140,8 @@ def set_meas(real: str, expr: str):
pw = eval(expr)
measurements[real][2] = expr
human, norm, _, _ = measurements[real]
globals()[human] = measurements[real][3] = pw.normalized(norm)
if human:
globals()[human] = measurements[real][3] = pw.normalized(norm)
def try_measure(real: str):
try:
@ -1095,6 +1114,7 @@ Piecewise(
[
[ -7871, -3446 ], # -1.0
[ -4722, -2357 ], # -0.15
[ -3688, -1830 ], # -0.1
[ -1468, -971 ], # -0.05
[ 506, -5 ], # 0.0
[ 2001, 524 ], # 0.05
@ -1104,4 +1124,23 @@ Piecewise(
)
""")
set_meas("41-0.0004rad-9coupling-3_1_winding-3e9-drive", """
Piecewise(
[
[ -16802, -4812 ], # -1.0
[ -9667, -2573 ], # 0.0
[ -9056, -2372 ], # 0.05
[ 16994, 6381 ], # 1.0
]
)
""")
set_meas("41-0.0008rad-10coupling-7_1_winding-3e9-drive", """
Piecewise(
[
[ -16374, 8010 ], # -1.0
]
)
""")
if __name__ == '__main__': main()

View File

@ -26,7 +26,15 @@ use coremem::meas;
use coremem::real::{self, Real as _};
use coremem::sim::spirv::{self, SpirvSim};
use coremem::sim::units::{Seconds, Time as _};
use coremem::stim::{CurlVectorField, Exp, Gated, ModulatedVectorField, Scaled, Shifted, TimeVaryingExt as _};
use coremem::stim::{
CurlVectorField,
Exp,
Gated,
ModulatedVectorField,
Scaled,
Shifted,
TimeVaryingExt as _,
};
use coremem::Driver;
// type R = real::R32;
@ -82,6 +90,8 @@ impl ClockState {
#[derive(Copy, Clone)]
enum CouplingMethod {
/// "external" input, really just a torus that doesn't couple anything
Control,
/// toroidal coupling loop that connects two points -- and anything in between them.
Direct,
/// couple the points by first directing a loop outside of the core stack, thereby ensuring
@ -109,6 +119,7 @@ enum CouplingMethod {
#[derive(Clone)]
struct Params {
hardcoded_control_and_sense: bool,
input_magnitude: f32,
clock_phase_duration: f32,
clock_decay: f32, // exp decay half-life
@ -153,6 +164,7 @@ impl Params {
}
/// control loop for core n (alternately called "drive" loop)
fn ctl(&self, n: u32) -> Torus {
assert!(self.hardcoded_control_and_sense);
Torus::new_xz(Meters::new(self.sx() - self.s_major, self.sy(), self.sz(n)), self.io_major, self.io_minor)
}
/// the last core gets an external output in place of its coupling loop
@ -162,7 +174,7 @@ impl Params {
fn s(&self, n: u32) -> Torus {
Torus::new_xy(Meters::new(self.sx(), self.sy(), self.sz(n)), self.s_major, self.s_minor)
}
fn coupling_angle(&self, loop_: u32, set_id: u32, of_set: u32) -> f32 {
fn coupling_angle_legacy(&self, loop_: u32, set_id: u32, of_set: u32) -> f32 {
// plus 1 control and an optional sense.
let total_loops = self.coupling_loops * of_set + 2;
// + 1 because we reserve loop 0 for control.
@ -173,6 +185,32 @@ impl Params {
}
idx as f32 / total_loops as f32 * f32::two_pi()
}
fn coupling_angle(&self, loop_: u32, set_id: u32, of_set: u32) -> f32 {
if self.hardcoded_control_and_sense {
self.coupling_angle_legacy(loop_, set_id, of_set)
} else {
let total_loops = self.coupling_loops * of_set;
let idx = loop_ * of_set + set_id;
idx as f32 / total_loops as f32 * f32::two_pi()
}
}
fn coupling_self(&self, from: u32, to: u32, loop_: u32, set_id: u32, of_set: u32) -> Translate<Rotate<Torus>> {
assert_eq!(from, to);
let angle = self.coupling_angle(loop_, set_id, of_set);
let z = self.sz(from);
Translate::new(
Rotate::about_z(
angle,
Torus::new_xz(
Meters::new(self.s_major, 0.0, 0.0),
self.coupling_major,
self.coupling_minor,
)
),
Meters::new(self.sx(), self.sy(), z)
)
}
/// creates the wire loop which couples core `from` to core `to`.
/// - `of_set` indicates how many sets of loops this core has (e.g. 2 if it's coupling separately
/// to the above and below cores, equally).
@ -428,6 +466,13 @@ impl Params {
.shifted(start.cast())
}
//////// BUILDER FUNCTIONS
fn without_hardcoded_control_and_sense(&self) -> Self {
let mut me = self.clone();
me.hardcoded_control_and_sense = false;
me
}
fn with_input_magnitude(&self, p: f32) -> Self {
let mut me = self.clone();
me.input_magnitude = p;
@ -1056,11 +1101,34 @@ fn drive_map_fork_then_join_m2_out(amp0: f32) -> [[ClockState; 4]; 3] {
]
}
fn asymmetric_inverter_name(p: &Params, sim_id: &str, windings: u32, init_flt: f32) -> String {
let init_int = (init_flt.abs() * 100.0 + 0.5) as u32;
let init_level = if init_flt > 0.0 {
format!("p{init_int:03}")
} else if init_flt < 0.0 {
format!("n{init_int:03}")
} else {
"000".to_owned()
};
let s_major = p.s_major;
let coupling_loops = p.coupling_loops;
let mut input_leading = p.input_magnitude as u64;
let mut input_exp = 0;
while input_leading != 0 && input_leading % 10 == 0 {
input_leading /= 10;
input_exp += 1;
}
format!("{sim_id}-{s_major}rad-{coupling_loops}coupling-{windings}_1_winding-{input_leading}e{input_exp}-drive-{init_level}")
}
fn main() {
coremem::init_logging();
// coremem::init_debug();
let params = Params {
hardcoded_control_and_sense: true,
input_magnitude: 0.0,
clock_phase_duration: 0.0,
clock_decay: 0.0,
@ -1080,6 +1148,8 @@ fn main() {
sz1: um(320),
couplings: Vec::new(),
};
let params_v2 = params.without_hardcoded_control_and_sense();
// if false {
// let p17x = params
// .with_clock_phase_duration(ps(2000))
@ -3775,7 +3845,7 @@ fn main() {
}
}
if true {
if false {
let p40xx = params
.with_clock_phase_duration(ps(1000))
.with_clock_decay(ps(50))
@ -3922,6 +3992,107 @@ fn main() {
}
}
}
if true {
let p41xx = params_v2
.with_clock_phase_duration(ps(1000))
.with_clock_decay(ps(50))
.with_ctl_conductivity(5e2)
.with_coupling_conductivity(5e3)
;
for init_set in [
&[
// establish the domain/range
1.00,
-1.00,
0.00,
// ][..],
// &[
// establish the slope around the most likely stable/amplifying region
-0.05,
0.05,
-0.15,
0.10,
-0.10,
-0.07,
-0.17,
-0.13,
][..],
&[
// fill in the hopefully-less-interesting/impactful regions
0.50,
-0.50,
2.00,
-2.00,
0.30,
-0.30,
0.80,
-0.80,
// ][..],
// &[
0.20,
-0.20,
-0.25,
-0.40,
-0.60,
1.50,
-1.50,
][..],
] {
for (coupling_loops, s0_loops, s_major, cur_flt) in [
// VIABLE INVERTERS from 40xx, modified for new control
(9, 1, um(400), 3e9), // unstarted
(9, 3, um(600), 3e9), // unstarted
(10, 3, um(800), 25e8), // unstarted; verified geom.
// (10, 3, um(800), 2e9), // unstarted; verified geom. too low current
// (10, 3, um(800), 3e9), // incomplete; verified geom. mildly high current
// (10, 3, um(800), 1e9), // incomplete; verified geom. too low current
// (10, 3, um(800), 5e9), // incomplete; verified geom. too high current
// (10, 3, um(800), 5e10), // incomplete; verified geom. too high current
] {
for &init_flt in init_set {
let net_slots = 2*s0_loops + 1;
let mut params = p41xx
.with_s_major(s_major)
.with_coupling_loops(coupling_loops)
.with_input_magnitude(cur_flt)
// couple S0 to S1
.with_coupling(0, 1, 1, net_slots, CouplingMethod::DirectHalfExterior)
.with_coupling(0, 1, net_slots-1, net_slots, CouplingMethod::DirectHalfInterior)
;
// control loops
params = params
.with_coupling(0, 0, 0, net_slots, CouplingMethod::Control)
.with_coupling(1, 1, 0, net_slots, CouplingMethod::Control)
;
// "loops" for S1 (note: this just connects the two ends of the coupling)
for i in 1..net_slots-1 {
params = params.with_coupling(1, 1, i, net_slots, CouplingMethod::SelfAngularTop);
}
// loops for S0:
for i in 0..s0_loops {
if i != 0 {
// bridge this loop to the previous one
params = params.with_coupling(0, 0, 2*i, net_slots, CouplingMethod::SelfAngularBot);
}
params = params
.with_coupling(0, 0, 2*i + 1, net_slots, CouplingMethod::SelfLoopHalfInterior)
.with_coupling(0, 0, 2*i + 1, net_slots, CouplingMethod::SelfAngularTop)
.with_coupling(0, 0, 2*i + 2, net_slots, CouplingMethod::SelfLoopHalfExterior)
;
}
let name = asymmetric_inverter_name(&params, "41", 2*s0_loops + 1, init_flt);
run_sim(
&name,
drive_map_2stack_with_init(-init_flt), /* XXX: inversion to preserve legacy orientation */
params,
);
}
}
}
}
}
@ -3966,7 +4137,8 @@ fn run_sim<const C: usize, const R: usize>(
return; // all our work is done
}
driver.add_serializer_renderer(&*format!("{}frame-", prefix), 6400, Some(12800));
// driver.add_serializer_renderer(&*format!("{}frame-", prefix), 6400, Some(12800));
driver.add_serializer_renderer(&*format!("{}frame-", prefix), 32000, None);
// driver.add_csv_renderer(&*format!("{}meas-detailed.csv", prefix), 100, None);
driver.add_csv_renderer(&*format!("{}meas.csv", prefix), 1600, None);
driver.add_csv_renderer(&*format!("{}meas-sparse.csv", prefix), 12800, None);
@ -3977,11 +4149,16 @@ fn run_sim<const C: usize, const R: usize>(
// driver.fill_region(&params.sense(last_core), coupling_mat);
for core in 0..num_cores {
driver.fill_region(&params.s(core), ferro_mat);
driver.fill_region(&params.ctl(core), ctl_mat);
if params.hardcoded_control_and_sense {
driver.fill_region(&params.ctl(core), ctl_mat);
}
}
for &(from, to, id, of, meth) in &params.couplings {
for loop_ in 0..params.coupling_loops {
match meth {
CouplingMethod::Control => driver.fill_region(
&params.coupling_self(from, to, loop_, id, of), ctl_mat
),
CouplingMethod::Direct => driver.fill_region(
&params.coupling_direct(from, to, loop_, id, of), coupling_mat
),
@ -4011,11 +4188,13 @@ fn run_sim<const C: usize, const R: usize>(
}
//////// monitor some measurements
for core in 0..num_cores {
driver.add_measurement(meas::CurrentLoop::new(
&format!("drive{}", core),
params.ctl(core),
));
if params.hardcoded_control_and_sense {
for core in 0..num_cores {
driver.add_measurement(meas::CurrentLoop::new(
&format!("drive{}", core),
params.ctl(core),
));
}
}
for &(from, to, id, of, meth) in &params.couplings {
let name = format!("sense{}_{}", from, to);
@ -4034,6 +4213,7 @@ fn run_sim<const C: usize, const R: usize>(
},
}
}
for core in 0..num_cores {
driver.add_measurement(meas::MagneticLoop::new(
&format!("state{}", core),
@ -4049,17 +4229,41 @@ fn run_sim<const C: usize, const R: usize>(
core_drivers[core as usize].extend(clock.time_stimulus(&params, cycle as u32));
}
}
assert_eq!(core_drivers.len(), num_cores as usize);
let stim: Vec<_> = core_drivers.into_iter()
.enumerate()
.map(|(core, time_varying)| {
let region = params.ctl(core as u32);
let area = region.cross_section();
// we assume each control loop has the same cross section
let mut v_fields = Vec::new();
let mut area = 1.0;
if params.hardcoded_control_and_sense {
// noop translation/rotation for the sake of monomorphization
let region = Translate::new(
Rotate::about_z(0.0, params.ctl(core as u32)),
Meters::default()
);
area = region.cross_section();
v_fields.push(CurlVectorField::new(region));
}
for &(from, to, id, of, meth) in &params.couplings {
if from == core as u32 {
if let CouplingMethod::Control = meth {
for loop_ in 0..params.coupling_loops {
let region = params.coupling_self(from, to, loop_, id, of);
area = region.cross_section();
v_fields.push(CurlVectorField::new(region));
}
}
}
}
let amp = 1.0 / area;
let v_field = CurlVectorField::new(region.clone());
ModulatedVectorField::new(v_field, time_varying.scaled(amp.cast::<R>()))
ModulatedVectorField::new(v_fields, time_varying.scaled(amp.cast::<R>()))
})
.collect();
assert_eq!(stim.len(), num_cores as usize);
let mut driver = driver.with_modulated_stimulus();
driver.set_steps_per_stimulus(200);

View File

@ -5,6 +5,7 @@ use coremem_cross::vec::Vec3;
use rayon::prelude::*;
use serde::{Serialize, Deserialize};
use std::collections::BTreeSet;
use std::ops::Deref;
use std::sync::Arc;
mod constructed;
@ -197,6 +198,13 @@ impl<R> Translate<R> {
}
}
impl<R> Deref for Translate<R> {
type Target = R;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<R: Region> Region for Translate<R> {
fn contains(&self, p: Meters) -> bool {
self.inner.contains(p - self.shift)
@ -356,6 +364,13 @@ impl<R> Rotate<R> {
}
}
impl<R> Deref for Rotate<R> {
type Target = R;
fn deref(&self) -> &Self::Target {
&self.region
}
}
impl<R: Region> Region for Rotate<R> {
fn contains(&self, p: Meters) -> bool {
self.region.contains(Meters(self.rotate_into_region(p.0)))

View File

@ -11,6 +11,17 @@ pub trait VectorField<R> {
fn at(&self, feat_size: R, loc: Index) -> Fields<R>;
}
// a vec of VectorFields is the sum of those fields
impl<R: Real, V: VectorField<R>> VectorField<R> for Vec<V> {
fn at(&self, feat_size: R, loc: Index) -> Fields<R> {
let mut acc = Fields::default();
for v in self {
acc += v.at(feat_size, loc);
}
acc
}
}
// uniform vector field
impl<R: Real> VectorField<R> for Fields<R> {
fn at(&self, _feat_size: R, _loc: Index) -> Fields<R> {