//! this example stacks buffers vertically so that we can couple them with MANY wire loops. //! the conclusion is that denser loops gets the coupling closer to 1:1 (counteracts losses), //! but it likely won't ever achieve amplification. use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::geom::{Meters, Torus}; use coremem::sim::units::Seconds; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _}; fn main() { coremem::init_logging(); let feat_size = 40e-6f32; let buffer_xy = 160e-6; let buffer_z = 160e-6; let boundary_xy = 320e-6; let boundary_z = 320e-6; let ferro_major = 640e-6; let ferro_minor = 60e-6; let ferro_buffer = 160e-6; // vertical space between ferros let wire_minor = 40e-6; let wire_set_major = 140e-6; // this just needs to exceed ferro_minor + wire_minor; less than ferro_buffer - wire_minor let wire_coupling_major = 280e-6; // (ferro_minor*4 + ferro_buffer)/2 + wire_minor = 220 let drive_conductivity = 5e6f32; let peak_set_current = 15.0; let peak_clock_current = 100.0; let set_duration = 10e-9; // half-wavelength of the sine wave let steady_time = 500e-9; // how long to wait for sets to stabilize let clock_duration = 1e-9; let m_to_um = |m: f32| (m * 1e6).round() as u32; let feat_vol = feat_size * feat_size * feat_size; let base = "buffer3-13"; let width = 2.0*(ferro_major + wire_coupling_major + wire_minor + buffer_xy + boundary_xy); let height = width; let depth = 2.0*(wire_coupling_major + wire_minor + buffer_z + boundary_z); let ferro1_center = Meters::new(0.5 * width, 0.5 * height, 0.5 * depth - ferro_minor - 0.5 * ferro_buffer); let ferro2_center = Meters::new(0.5 * width, 0.5 * height, 0.5 * depth + ferro_minor + 0.5 * ferro_buffer); // reserve the left/right locations for the SET wires. let set1_center = (ferro1_center + ferro2_center) * 0.5 + Meters::new(-ferro_major, 0.0, -wire_set_major); let set2_center = (ferro1_center + ferro2_center) * 0.5 + Meters::new(ferro_major, 0.0, wire_set_major); let ferro1_region = Torus::new_xy(ferro1_center, ferro_major, ferro_minor); let ferro2_region = Torus::new_xy(ferro2_center, ferro_major, ferro_minor); let set1_region = Torus::new_xz(set1_center, wire_set_major, wire_minor); let set2_region = Torus::new_xz(set2_center, wire_set_major, wire_minor); let rev = 6.283185307179586; // let coupling_angles = [0.25*rev, 0.75*rev]; // let coupling_angles = [0.125*rev, 0.25*rev, 0.375*rev, 0.625*rev, 0.75*rev, 0.875*rev]; let coupling_angles = [ 0.0625*rev, 0.1250*rev, 0.1875*rev, 0.2500*rev, 0.3125*rev, 0.3750*rev, 0.4375*rev, 0.5625*rev, 0.6250*rev, 0.6875*rev, 0.7500*rev, 0.8125*rev, 0.8750*rev, 0.9375*rev, ]; let define_coupling_region = |angle: f32| -> Torus { let ferro_center = (ferro1_center + ferro2_center) * 0.5; let tor_center = ferro_center + Meters::new(angle.cos(), angle.sin(), 0.0) * ferro_major; let tor_normal = Meters::new(-angle.sin(), angle.cos(), 0.0); Torus::new(tor_center, tor_normal, wire_coupling_major, wire_minor) }; let coupling_regions: Vec<_> = coupling_angles.iter().cloned().map(define_coupling_region).collect(); // mu_r=881.33, starting at H=25 to H=75. let ferro_mat = mat::MHPgram::new(25.0, 881.33, 44000.0); // let ferro_mat = mat::db::conductor(drive_conductivity); let wire_mat = mat::IsomorphicConductor::new(drive_conductivity); let mut driver: SpirvDriver = Driver::new_spirv(Meters::new(width, height, depth), feat_size); driver.set_steps_per_stim(1000); driver.fill_region(&ferro1_region, ferro_mat); driver.fill_region(&ferro2_region, ferro_mat); driver.fill_region(&set1_region, wire_mat); driver.fill_region(&set2_region, wire_mat); for r in &coupling_regions { driver.fill_region(r, wire_mat); } println!("boundary: {}um; {}um", m_to_um(boundary_xy), m_to_um(boundary_z)); println!("size: {}, {}, {}", width, height, depth); println!("ferro1: {:?}", ferro1_center); println!("ferro2: {:?}", ferro2_center); driver.add_classical_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z)); assert!(driver.test_region_filled(&ferro1_region, ferro_mat)); assert!(driver.test_region_filled(&ferro2_region, ferro_mat)); assert!(driver.test_region_filled(&set1_region, wire_mat)); assert!(driver.test_region_filled(&set2_region, wire_mat)); for r in &coupling_regions { assert!(driver.test_region_filled(r, wire_mat)); } let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let wave = Sinusoid::from_wavelength(amp, duration * 2.0) .half_cycle() .shifted(start); driver.add_stimulus(CurlStimulus::new( region.clone(), wave.clone(), region.center(), region.axis() )); }; // J=\sigma E // dJ/dt = \sigma dE/dT // dE/dt = dJ/dt / \sigma // dE/dt = dI/dt / (A*\sigma) // if I = k*sin(w t) then dE/dt = k*w cos(w t) / (A*\sigma) // i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength) let peak_set = peak_set_current / feat_vol / (set1_region.cross_section() * drive_conductivity); let peak_clock = peak_clock_current / feat_vol / (set1_region.cross_section() * drive_conductivity); // SET cores add_drive_pulse(&set1_region, 0.01*set_duration, set_duration, -peak_set); add_drive_pulse(&set2_region, 0.01*set_duration, set_duration, -peak_set); // CLEAR core1 add_drive_pulse(&set1_region, set_duration + steady_time, clock_duration, peak_clock); let duration = 2.5*steady_time; for (i, r) in coupling_regions.iter().enumerate() { driver.add_measurement(meas::CurrentLoop::new(&*format!("coupling{}", i), r.clone())); } driver.add_measurement(meas::Volume::new("mem1", ferro1_region.clone())); driver.add_measurement(meas::MagneticLoop::new("mem1", ferro1_region.clone())); driver.add_measurement(meas::Volume::new("mem2", ferro2_region.clone())); driver.add_measurement(meas::MagneticLoop::new("mem2", ferro2_region.clone())); driver.add_measurement(meas::CurrentLoop::new("set1", set1_region.clone())); driver.add_measurement(meas::Power::new("set1", set1_region.clone())); driver.add_measurement(meas::CurrentLoop::new("set2", set2_region.clone())); let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um-{}xcoupling", base, base, *driver.size(), (peak_set_current * 1e3).round() as i64, (set_duration * 1e12).round() as i64, (peak_clock_current * 1e3).round() as i64, (clock_duration * 1e12).round() as i64, (feat_size * 1e6).round() as i64, coupling_regions.len(), ); let _ = std::fs::create_dir_all(&prefix); driver.add_state_file(&*format!("{}/state.bc", prefix), 16000); // driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000, None); driver.add_csv_renderer(&*format!("{}/meas.csv", prefix), 200, None); driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 8000, None); driver.step_until(Seconds(duration)); }