app: multi_core_inverter: de-virtualize the stimuli
this gets like a 5% perf gain. there are obviously cleaner ways to do it (e.g. use a ListVisitor), but this is only a proof of concept. given the low perf difference, i'll likely revert this or explore other options.
This commit is contained in:
@@ -36,13 +36,14 @@
|
||||
//! $ pushd crates/coremem; cargo run --release --bin viewer ../../out/applications/multi_core_inverter/0/ ; popd
|
||||
//! ```
|
||||
|
||||
use coremem::cross::compound::list::{self, Prependable};
|
||||
use coremem::geom::{Coord as _, Meters, Torus};
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
|
||||
use coremem::meas;
|
||||
use coremem::real::{self, Real as _};
|
||||
use coremem::sim::spirv::{self, SpirvSim};
|
||||
use coremem::sim::units::Seconds;
|
||||
use coremem::stim::{CurlStimulus, Exp, Gated, Sinusoid1, TimeVarying as _};
|
||||
use coremem::stim::{CurlStimulus, Exp, Gated, Shifted};
|
||||
use coremem::Driver;
|
||||
|
||||
type R = real::R32;
|
||||
@@ -60,6 +61,52 @@ enum DriveType {
|
||||
Float,
|
||||
}
|
||||
|
||||
struct HoldHigh;
|
||||
struct ReleaseHigh;
|
||||
struct HoldLow;
|
||||
struct ReleaseLow;
|
||||
struct Float;
|
||||
|
||||
impl HoldHigh {
|
||||
fn stim<P: Prependable>(
|
||||
&self, prev: P, p: Params, cycle: u32, r: Torus
|
||||
) -> list::Prepended<HoldStim, P> {
|
||||
prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldHigh))
|
||||
}
|
||||
}
|
||||
|
||||
impl ReleaseHigh {
|
||||
fn stim<P: Prependable>(
|
||||
&self, prev: P, p: Params, cycle: u32, r: Torus
|
||||
) -> list::Prepended<ReleaseStim, P> {
|
||||
prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseHigh))
|
||||
}
|
||||
}
|
||||
|
||||
impl HoldLow {
|
||||
fn stim<P: Prependable>(
|
||||
&self, prev: P, p: Params, cycle: u32, r: Torus
|
||||
) -> list::Prepended<HoldStim, P> {
|
||||
prev.prepend(control_signal_hold(p, r, cycle, DriveType::HoldLow))
|
||||
}
|
||||
}
|
||||
|
||||
impl ReleaseLow {
|
||||
fn stim<P: Prependable>(
|
||||
&self, prev: P, p: Params, cycle: u32, r: Torus
|
||||
) -> list::Prepended<ReleaseStim, P> {
|
||||
prev.prepend(control_signal_release(p, r, cycle, DriveType::ReleaseLow))
|
||||
}
|
||||
}
|
||||
|
||||
impl Float {
|
||||
fn stim<P>(
|
||||
&self, prev: P, _p: Params, _cycle: u32, _r: Torus
|
||||
) -> P {
|
||||
prev
|
||||
}
|
||||
}
|
||||
|
||||
impl DriveType {
|
||||
fn direction(&self) -> i32 {
|
||||
use DriveType::*;
|
||||
@@ -83,6 +130,40 @@ impl DriveType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Params {
|
||||
input_magnitude: f32,
|
||||
clock_phase_duration: f32,
|
||||
clock_decay: f32, // exp decay half-life
|
||||
}
|
||||
|
||||
type HoldStim = CurlStimulus<Torus, Gated<f32>>;
|
||||
type ReleaseStim = CurlStimulus<Torus, Shifted<Gated<Exp<f32>>>>;
|
||||
fn control_signal_hold(params: Params, region: Torus, cycle: u32, ty: DriveType) -> HoldStim {
|
||||
let area = region.cross_section();
|
||||
let amp = ty.direction() as f32 * params.input_magnitude / area;
|
||||
let start = params.clock_phase_duration * cycle as f32;
|
||||
// simple square wave:
|
||||
let wave = Gated::new(amp, start, start + params.clock_phase_duration);
|
||||
CurlStimulus::new(
|
||||
region.clone(),
|
||||
wave.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
fn control_signal_release(params: Params, region: Torus, cycle: u32, ty: DriveType) -> ReleaseStim {
|
||||
let area = region.cross_section();
|
||||
let amp = ty.direction() as f32 * params.input_magnitude / area;
|
||||
let start = params.clock_phase_duration * cycle as f32;
|
||||
// decaying exponential wave:
|
||||
let wave = Exp::new_at(amp, start, params.clock_decay);
|
||||
CurlStimulus::new(
|
||||
region.clone(),
|
||||
wave.clone(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
coremem::init_logging();
|
||||
// coremem::init_debug();
|
||||
@@ -91,9 +172,11 @@ fn main() {
|
||||
let ps = |n| n as f32 * 1e-12;
|
||||
let feat_size = um(10);
|
||||
|
||||
let input_magnitude = 1.0e9;
|
||||
let clock_phase_duration = ps(4000);
|
||||
let clock_decay = ps(250); // exp decay half-life
|
||||
let params = Params {
|
||||
input_magnitude: 1.0e9,
|
||||
clock_phase_duration: ps(4000),
|
||||
clock_decay: ps(250),
|
||||
};
|
||||
|
||||
// 's' = core (ferromagnetic part)
|
||||
let s_major = um(160);
|
||||
@@ -123,83 +206,56 @@ fn main() {
|
||||
let s = |n| Torus::new_xy(Meters::new(sx(n), sy, sz), s_major, s_minor);
|
||||
// coupling(n) is the wire which couples core n into core n+1
|
||||
let coupling = |n| Torus::new_xz(Meters::new(couplingx(n), sy, sz), coupling_major, coupling_minor);
|
||||
|
||||
let control_signal = |driver: &mut Driver<Sim>, region: &Torus, cycle: u32, ty: DriveType| {
|
||||
let area = region.cross_section();
|
||||
let amp = ty.direction() as f32 * input_magnitude / area;
|
||||
let start = clock_phase_duration * cycle as f32;
|
||||
if ty.is_hold() {
|
||||
// simple square wave:
|
||||
let wave = Gated::new(amp, start, start + clock_phase_duration);
|
||||
let stim = CurlStimulus::new(
|
||||
region.clone(),
|
||||
wave.clone(),
|
||||
);
|
||||
driver.add_stimulus(stim);
|
||||
} else if ty.is_release() {
|
||||
// decaying exponential wave:
|
||||
let wave = Exp::new_at(amp, start, clock_decay);
|
||||
let stim = CurlStimulus::new(
|
||||
region.clone(),
|
||||
wave.clone(),
|
||||
);
|
||||
driver.add_stimulus(stim);
|
||||
} // else: Float
|
||||
// sine wave (untested):
|
||||
// let wave = Sinusoid1::from_wavelength(direction as f32 * input_magnitude / area, clock_phase_duration * 2.0)
|
||||
// .half_cycle()
|
||||
// .shifted(clock_phase_duration * cycle as f32);
|
||||
};
|
||||
|
||||
|
||||
//////// define the control signals/transitions
|
||||
// each row N denotes the drive currents at clock cycle N.
|
||||
// each col M denotes the drive current at core M.
|
||||
use DriveType::*;
|
||||
// let s0_init_state = HoldHigh; // logic high
|
||||
let s0_init_state = HoldLow; // logic low
|
||||
let s0_rel_state = ReleaseLow;
|
||||
let drive_map = [
|
||||
let drive_map = (
|
||||
// charge each device to '1'
|
||||
[s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh],
|
||||
(s0_init_state,HoldHigh, HoldHigh, HoldHigh, HoldHigh),
|
||||
// this is when we'd ordinarily open S0 for write
|
||||
[s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh],
|
||||
(s0_rel_state, HoldHigh, HoldHigh, HoldHigh, HoldHigh),
|
||||
|
||||
// this is when S0 would ordinarily receive a write
|
||||
[Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh],
|
||||
(Float, HoldHigh, HoldHigh, HoldHigh, HoldHigh),
|
||||
// open S1 for write
|
||||
[Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh],
|
||||
(Float, ReleaseHigh, HoldHigh, HoldHigh, HoldHigh),
|
||||
|
||||
// write S0' => S1
|
||||
[HoldLow, Float, HoldHigh, HoldHigh, HoldHigh],
|
||||
(HoldLow, Float, HoldHigh, HoldHigh, HoldHigh),
|
||||
// open S2 for write
|
||||
[HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh],
|
||||
(HoldLow, Float, ReleaseHigh, HoldHigh, HoldHigh),
|
||||
|
||||
// write S1' => S2
|
||||
[HoldLow, HoldLow, Float, HoldHigh, HoldHigh],
|
||||
(HoldLow, HoldLow, Float, HoldHigh, HoldHigh),
|
||||
// open S3 for write
|
||||
[HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh],
|
||||
(HoldLow, HoldLow, Float, ReleaseHigh, HoldHigh),
|
||||
|
||||
// write S2' => S3; RESET S0
|
||||
[HoldHigh, HoldLow, HoldLow, Float, HoldHigh],
|
||||
(HoldHigh, HoldLow, HoldLow, Float, HoldHigh),
|
||||
// open S4 for write
|
||||
[HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh],
|
||||
(HoldHigh, HoldLow, HoldLow, Float, ReleaseHigh),
|
||||
|
||||
// write S3' => S4; RESET S1
|
||||
[HoldHigh, HoldHigh, HoldLow, HoldLow, Float],
|
||||
(HoldHigh, HoldHigh, HoldLow, HoldLow, Float),
|
||||
// open S0 for write
|
||||
[ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float],
|
||||
(ReleaseHigh, HoldHigh, HoldLow, HoldLow, Float),
|
||||
|
||||
// write S4' => output; RESET S2
|
||||
[Float, HoldHigh, HoldHigh, HoldLow, HoldLow],
|
||||
(Float, HoldHigh, HoldHigh, HoldLow, HoldLow),
|
||||
// open S1 for write
|
||||
[Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow],
|
||||
];
|
||||
(Float, ReleaseHigh, HoldHigh, HoldLow, HoldLow),
|
||||
);
|
||||
let num_cores = 5;
|
||||
let num_cycles = 14;
|
||||
|
||||
let wire_mat = IsomorphicConductor::new(1e6f32.cast::<R>());
|
||||
// let ferro_mat = wire_mat;
|
||||
let ferro_mat = Ferroxcube3R1MH::new();
|
||||
|
||||
let num_cores = drive_map[0].len();
|
||||
let last_core = num_cores - 1;
|
||||
|
||||
let mut driver = Driver::new(Sim::new(
|
||||
@@ -246,17 +302,96 @@ fn main() {
|
||||
}
|
||||
|
||||
|
||||
let cycles = drive_map.len() as u32;
|
||||
let duration = Seconds(clock_phase_duration * (cycles + 3) as f32);
|
||||
let duration = Seconds(params.clock_phase_duration * (num_cycles + 3) as f32);
|
||||
|
||||
for cycle in 0..cycles {
|
||||
for core in 0..num_cores {
|
||||
// current polarity of the drive wires is inverted in this model v.s. the blog article,
|
||||
// so invert our currents in order to achieve the magnetic states of the article.
|
||||
let sig = drive_map[cycle as usize][core as usize];
|
||||
control_signal(&mut driver, &ctl(core), cycle, sig);
|
||||
}
|
||||
}
|
||||
let stim = list::Empty::default();
|
||||
|
||||
let stim = drive_map.0.0.stim(stim, params, 0, ctl(0));
|
||||
let stim = drive_map.0.1.stim(stim, params, 0, ctl(1));
|
||||
let stim = drive_map.0.2.stim(stim, params, 0, ctl(2));
|
||||
let stim = drive_map.0.3.stim(stim, params, 0, ctl(3));
|
||||
let stim = drive_map.0.4.stim(stim, params, 0, ctl(4));
|
||||
|
||||
let stim = drive_map.1.0.stim(stim, params, 1, ctl(0));
|
||||
let stim = drive_map.1.1.stim(stim, params, 1, ctl(1));
|
||||
let stim = drive_map.1.2.stim(stim, params, 1, ctl(2));
|
||||
let stim = drive_map.1.3.stim(stim, params, 1, ctl(3));
|
||||
let stim = drive_map.1.4.stim(stim, params, 1, ctl(4));
|
||||
|
||||
let stim = drive_map.2.0.stim(stim, params, 2, ctl(0));
|
||||
let stim = drive_map.2.1.stim(stim, params, 2, ctl(1));
|
||||
let stim = drive_map.2.2.stim(stim, params, 2, ctl(2));
|
||||
let stim = drive_map.2.3.stim(stim, params, 2, ctl(3));
|
||||
let stim = drive_map.2.4.stim(stim, params, 2, ctl(4));
|
||||
|
||||
let stim = drive_map.3.0.stim(stim, params, 3, ctl(0));
|
||||
let stim = drive_map.3.1.stim(stim, params, 3, ctl(1));
|
||||
let stim = drive_map.3.2.stim(stim, params, 3, ctl(2));
|
||||
let stim = drive_map.3.3.stim(stim, params, 3, ctl(3));
|
||||
let stim = drive_map.3.4.stim(stim, params, 3, ctl(4));
|
||||
|
||||
let stim = drive_map.4.0.stim(stim, params, 4, ctl(0));
|
||||
let stim = drive_map.4.1.stim(stim, params, 4, ctl(1));
|
||||
let stim = drive_map.4.2.stim(stim, params, 4, ctl(2));
|
||||
let stim = drive_map.4.3.stim(stim, params, 4, ctl(3));
|
||||
let stim = drive_map.4.4.stim(stim, params, 4, ctl(4));
|
||||
|
||||
let stim = drive_map.5.0.stim(stim, params, 5, ctl(0));
|
||||
let stim = drive_map.5.1.stim(stim, params, 5, ctl(1));
|
||||
let stim = drive_map.5.2.stim(stim, params, 5, ctl(2));
|
||||
let stim = drive_map.5.3.stim(stim, params, 5, ctl(3));
|
||||
let stim = drive_map.5.4.stim(stim, params, 5, ctl(4));
|
||||
|
||||
let stim = drive_map.6.0.stim(stim, params, 6, ctl(0));
|
||||
let stim = drive_map.6.1.stim(stim, params, 6, ctl(1));
|
||||
let stim = drive_map.6.2.stim(stim, params, 6, ctl(2));
|
||||
let stim = drive_map.6.3.stim(stim, params, 6, ctl(3));
|
||||
let stim = drive_map.6.4.stim(stim, params, 6, ctl(4));
|
||||
|
||||
let stim = drive_map.7.0.stim(stim, params, 7, ctl(0));
|
||||
let stim = drive_map.7.1.stim(stim, params, 7, ctl(1));
|
||||
let stim = drive_map.7.2.stim(stim, params, 7, ctl(2));
|
||||
let stim = drive_map.7.3.stim(stim, params, 7, ctl(3));
|
||||
let stim = drive_map.7.4.stim(stim, params, 7, ctl(4));
|
||||
|
||||
let stim = drive_map.8.0.stim(stim, params, 8, ctl(0));
|
||||
let stim = drive_map.8.1.stim(stim, params, 8, ctl(1));
|
||||
let stim = drive_map.8.2.stim(stim, params, 8, ctl(2));
|
||||
let stim = drive_map.8.3.stim(stim, params, 8, ctl(3));
|
||||
let stim = drive_map.8.4.stim(stim, params, 8, ctl(4));
|
||||
|
||||
let stim = drive_map.9.0.stim(stim, params, 9, ctl(0));
|
||||
let stim = drive_map.9.1.stim(stim, params, 9, ctl(1));
|
||||
let stim = drive_map.9.2.stim(stim, params, 9, ctl(2));
|
||||
let stim = drive_map.9.3.stim(stim, params, 9, ctl(3));
|
||||
let stim = drive_map.9.4.stim(stim, params, 9, ctl(4));
|
||||
|
||||
let stim = drive_map.10.0.stim(stim, params, 10, ctl(0));
|
||||
let stim = drive_map.10.1.stim(stim, params, 10, ctl(1));
|
||||
let stim = drive_map.10.2.stim(stim, params, 10, ctl(2));
|
||||
let stim = drive_map.10.3.stim(stim, params, 10, ctl(3));
|
||||
let stim = drive_map.10.4.stim(stim, params, 10, ctl(4));
|
||||
|
||||
let stim = drive_map.11.0.stim(stim, params, 11, ctl(0));
|
||||
let stim = drive_map.11.1.stim(stim, params, 11, ctl(1));
|
||||
let stim = drive_map.11.2.stim(stim, params, 11, ctl(2));
|
||||
let stim = drive_map.11.3.stim(stim, params, 11, ctl(3));
|
||||
let stim = drive_map.11.4.stim(stim, params, 11, ctl(4));
|
||||
|
||||
let stim = drive_map.12.0.stim(stim, params, 12, ctl(0));
|
||||
let stim = drive_map.12.1.stim(stim, params, 12, ctl(1));
|
||||
let stim = drive_map.12.2.stim(stim, params, 12, ctl(2));
|
||||
let stim = drive_map.12.3.stim(stim, params, 12, ctl(3));
|
||||
let stim = drive_map.12.4.stim(stim, params, 12, ctl(4));
|
||||
|
||||
let stim = drive_map.13.0.stim(stim, params, 13, ctl(0));
|
||||
let stim = drive_map.13.1.stim(stim, params, 13, ctl(1));
|
||||
let stim = drive_map.13.2.stim(stim, params, 13, ctl(2));
|
||||
let stim = drive_map.13.3.stim(stim, params, 13, ctl(3));
|
||||
let stim = drive_map.13.4.stim(stim, params, 13, ctl(4));
|
||||
assert_eq!(num_cycles, 14);
|
||||
assert_eq!(num_cores, 5);
|
||||
let mut driver = driver.with_stimulus(stim);
|
||||
|
||||
let prefix = "out/applications/multi_core_inverter/13/";
|
||||
let _ = std::fs::create_dir_all(&prefix);
|
||||
|
Reference in New Issue
Block a user