clean up the SR latch example so that it runs

This commit is contained in:
Colin 2022-04-30 00:56:18 -07:00
parent f94c55b27c
commit 5871292bfd
1 changed files with 57 additions and 70 deletions

View File

@ -1,75 +1,75 @@
use coremem::{Driver, mat, meas, SampleableSim as _, SimState};
use coremem::{Driver, mat, meas, SampleableSim as _, SimState, SpirvDriver};
use coremem::real::R32 as Real;
use coremem::geom::{Index, Meters, Torus};
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying1 as _};
use coremem::sim::spirv;
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _, TimeVarying1 as _};
fn main() {
coremem::init_logging();
// feature size: the side-length of each discrete grid cell to model (in Meters)
let feat_size = 20e-6f32;
// parameters used below to describe the components we construct below. units are (M, A or S).
let depth = 1600e-6;
let buffer_x = 240e-6;
let buffer_y = 240e-6;
// let buffer_z = 240e-6;
// closest distance between the non-vacuum component and the dissipating boundary
// longer distances cause boundary reflections to be more dissipated (generally good).
let buffer_xy = 240e-6;
// length of our energy-dissipating boundary. longer distances decrease boundary reflections (good)
let boundary_xy = 500e-6;
// geometry parameters for the ferrite cores (modeled as torii)
let ferro_major = 320e-6;
let ferro_minor = 60e-6;
let ferro_buffer = 60e-6;
// geometry parameters for the coupling, drive, and sense wires (modeled as torii)
let wire_minor = 40e-6;
let wire_major = 160e-6;
let wire_coupling_major = 280e-6; // (ferro_minor*4 + ferro_buffer)/2 + wire_minor = 190
let peak_current = 7.5e6;
let current_duration = 6.0e-9; // half-wavelength of the sine wave
// let current_break = 0.2e-9; // time between 'set' pulse and 'clear' pulse
let drive_conductivity = 5e6f32;
let sense_conductivity = 5e3f32;
let m_to_um = |m: f32| (m * 1e6).round() as u32;
let half_depth = depth * 0.5;
let base = "sr-latch-13-mh-44000-881mu-20feat-gradual";
let boundary_xy = 500e-6;
let boundary_z = 300e-6;
let ferro_top_mid = boundary_xy + buffer_y + wire_minor + wire_major;
// intermediate computed geometric parameters
let ferro_top_mid = boundary_xy + buffer_xy + wire_minor + wire_major;
let ferro_center_y = ferro_top_mid + ferro_major;
let ferro_bot_mid = ferro_center_y + ferro_major;
let height = ferro_bot_mid + wire_major + wire_minor + buffer_y + boundary_xy;
let ferro1_left_edge = boundary_xy + buffer_x;
let height = ferro_bot_mid + wire_major + wire_minor + buffer_xy + boundary_xy;
let ferro1_left_edge = boundary_xy + buffer_xy;
let ferro1_center = ferro1_left_edge + ferro_minor + ferro_major;
let ferro1_right_edge = ferro1_center + ferro_major + ferro_minor;
let ferro2_left_edge = ferro1_right_edge + ferro_buffer;
let ferro2_center = ferro2_left_edge + ferro_minor + ferro_major;
let ferro2_right_edge = ferro2_center + ferro_major + ferro_minor;
let width = ferro2_right_edge + wire_major + wire_minor + buffer_x + boundary_xy;
let width = ferro2_right_edge + wire_major + wire_minor + buffer_xy + boundary_xy;
// create actual Regions from the computed parameters
let ferro1_region = Torus::new_xy(Meters::new(ferro1_center, ferro_center_y, half_depth), ferro_major, ferro_minor);
let ferro2_region = Torus::new_xy(Meters::new(ferro2_center, ferro_center_y, half_depth), ferro_major, ferro_minor);
let set_region = Torus::new_yz(Meters::new(ferro1_center, ferro_center_y - ferro_major, half_depth), wire_major, wire_minor);
let reset_region = Torus::new_yz(Meters::new(ferro1_center, ferro_center_y + ferro_major, half_depth), wire_major, wire_minor);
let coupling_region = Torus::new_xz(Meters::new(0.5*(ferro1_center + ferro2_center), ferro_center_y, half_depth), wire_coupling_major, wire_minor);
let sense_region = Torus::new_xz(Meters::new(ferro2_center + ferro_major, ferro_center_y, half_depth), wire_major, wire_minor);
// TODO: make sure none of the regions overlap
let mut driver: Driver<_> = Driver::new_spirv(Meters::new(width, height, depth), feat_size);
driver.set_steps_per_stim(1000);
//driver.fill_region(&ferro1_region, mat::db::linear_iron());
// Original, 3R1-LIKE ferromagnet (only a vague likeness), sr-latch-8:
// driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
// driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
// sr-latch-9; dead spot from B=[-0.03, 0.03]. This will help us see if the math is H-triggered
// or B-triggered
// driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3300, 0.3900, 310_000.0));
// driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3300, 0.3900, 310_000.0));
let mut driver: SpirvDriver<spirv::FullyGenericMaterial> = Driver::new_spirv(Meters::new(width, height, depth), feat_size);
// mu_r=881.33, starting at H=25 to H=75.
driver.fill_region(&ferro1_region, mat::MHPgram::new(25.0, 881.33, 44000.0));
driver.fill_region(&ferro2_region, mat::MHPgram::new(25.0, 881.33, 44000.0));
driver.fill_region(&set_region, mat::db::conductor(drive_conductivity));
driver.fill_region(&reset_region, mat::db::conductor(drive_conductivity));
driver.fill_region(&coupling_region, mat::db::conductor(drive_conductivity));
driver.fill_region(&sense_region, mat::db::conductor(sense_conductivity));
driver.fill_region(&set_region, mat::IsomorphicConductor::new(drive_conductivity));
driver.fill_region(&reset_region, mat::IsomorphicConductor::new(drive_conductivity));
driver.fill_region(&coupling_region, mat::IsomorphicConductor::new(drive_conductivity));
driver.fill_region(&sense_region, mat::IsomorphicConductor::new(sense_conductivity));
println!("boundary: {}um; {}um", m_to_um(boundary_xy), m_to_um(boundary_z));
// fill the edge of the simulation with a graded conductor:
// on the inside of the simulation it matches vacuum (conductivity of 0), and
// ramps up conductivity (to dissipate energy) as it approaches the edge of the simulation.
driver.add_classical_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z));
// helper to schedule a stimulus at the provided start time/duration.
let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
.half_cycle()
@ -82,6 +82,7 @@ fn main() {
));
};
// stimuli apply some delta_E to the simulation, so we need to map our current to E:
// J=\sigma E
// dJ/dt = \sigma dE/dT
// dE/dt = dJ/dt / \sigma
@ -90,38 +91,27 @@ fn main() {
// i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength)
let peak_stim1 = peak_current/current_duration / (set_region.cross_section() * drive_conductivity);
// SET
// pulse the SET wire near the start of the simulation
add_drive_pulse(&set_region, 0.01*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 2.0*current_duration, current_duration, peak_stim1);
// RESET
add_drive_pulse(&reset_region, 6.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&reset_region, 8.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&reset_region, 4.0*current_duration, current_duration, peak_stim1);
// TOGGLE
add_drive_pulse(&set_region, 12.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 8.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&reset_region, 10.0*current_duration, current_duration, peak_stim1);
// TOGETHER
add_drive_pulse(&reset_region, 14.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 14.0*current_duration, current_duration, peak_stim1);
// TOGETHER
add_drive_pulse(&reset_region, 18.0*current_duration, current_duration, peak_stim1);
// SET TWICE
add_drive_pulse(&set_region, 18.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 20.0*current_duration, current_duration, peak_stim1);
// TOGETHER
add_drive_pulse(&reset_region, 21.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 21.0*current_duration, current_duration, peak_stim1);
// RESET
add_drive_pulse(&reset_region, 34.0*current_duration, current_duration, peak_stim1);
// TOGETHER
add_drive_pulse(&reset_region, 38.0*current_duration, current_duration, peak_stim1);
add_drive_pulse(&set_region, 38.0*current_duration, current_duration, peak_stim1);
// SET
add_drive_pulse(&set_region, 42.0*current_duration, current_duration, peak_stim1);
let duration = 60.0*current_duration;
let duration = 25.0*current_duration;
// measure a bunch of items of interest throughout the whole simulation duration:
driver.add_measurement(meas::CurrentLoop::new("coupling", coupling_region.clone()));
driver.add_measurement(meas::Current::new("coupling", coupling_region.clone()));
driver.add_measurement(meas::CurrentLoop::new("sense", sense_region.clone()));
@ -135,24 +125,21 @@ fn main() {
driver.add_measurement(meas::Power::new("set", set_region.clone()));
driver.add_measurement(meas::CurrentLoop::new("reset", reset_region.clone()));
let prefix = format!("out/{}/{}-{}-feat{}um-{}mA-{}ps--radii{}um-{}um-{}um-{}um",
base,
base,
*driver.state.size(),
m_to_um(feat_size),
(peak_current * 1e3).round() as i64,
(current_duration * 1e12).round() as i64,
m_to_um(ferro_major),
m_to_um(ferro_minor),
m_to_um(wire_major),
m_to_um(wire_minor),
);
// XXX: if you change any parameters (above), then change this prefix. otherwise simulations
// will try to load state generated by an earlier run and use it to compute the current
// (differently-parameterized) run.
let prefix = "out/examples/sr-latch/";
let _ = std::fs::create_dir_all(&prefix);
driver.add_state_file(&*format!("{}/state.bc", prefix), 9600);
driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 36000);
driver.add_csv_renderer(&*format!("{}/meas.csv", prefix), 200);
driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 1600);
// add a state file for easy resumption
driver.add_state_file(&*format!("{}state.bc", prefix), 9600);
// serialize frames for later viewing with `cargo run --release --bin viewer`
driver.add_serializer_renderer(&*format!("{}frame-", prefix), 36000, None);
// render a couple CSV files: one very detailed and the other more sparsely detailed
driver.add_csv_renderer(&*format!("{}meas.csv", prefix), 200, None);
driver.add_csv_renderer(&*format!("{}meas-sparse.csv", prefix), 1600, None);
// how frequently to re-evaluate the stimulus (Sample & Hold interpolation between evaluations)
driver.set_steps_per_stim(1000);
driver.step_until(duration);
driver.step_until(Seconds(duration));
}