//! this example positions buffers adjacently and uses an ASYMMETRIC coil winding //! it demonstrates a logic-high transmission rate > 1, but also a rapid degradation of logic-low. //! i believe logic-low values are degraded MOSTLY because of direct coupling between the clock //! wire and the coupling wire (instead of coupling achieved exclusively via the core). //! //! this models an inverter function that's something like mem2 = 700 - 0.15*mem1. //! that 0.15 factor is too small for a cascadable inverter, which needs to be at least 1.0. //! this factor can be increased by increasing the energy dumped into the clock -- but in order for //! that to be workable i need to first decrease the direct coupling between the clock and mem2. //! that will be the goal of buffer_proto5. use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::geom::{region, Cube, Meters, Spiral, SwapYZ, Torus, Translate, Wrap}; 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 = 640e-6; // horizontal space between ferros let wire_minor = 40e-6; let wire_wrap_minor = 240e-6; // 2x wire_wrap_minor + feat_size must be < ferro_buffer let wire_set_major = 600e-6; // this just needs to exceed ferro_minor + wire_wrap_minor + feat_size + wire_minor let drive_conductivity = 5e6f32; let peak_set_current = 60.0; let peak_clock_current = 5.0; let set_duration = 20e-9; // half-wavelength of the sine wave let steady_time = 160e-9; // how long to wait for sets to stabilize let clock_duration = 40e-9; let m_to_um = |m: f32| (m * 1e6).round() as u32; let feat_vol = feat_size * feat_size * feat_size; let base = "buffer4-NN"; let width = 4.0*ferro_major + 2.0*(buffer_xy + boundary_xy + wire_set_major + wire_minor) + ferro_buffer; let height = 2.0*(ferro_major + ferro_minor + 2.0*wire_wrap_minor + feat_size + buffer_xy + boundary_xy); let depth = 2.0*(wire_set_major + wire_minor + buffer_z + boundary_z); let ferro1_center = Meters::new( buffer_xy + boundary_xy + wire_set_major + wire_minor + ferro_major, buffer_xy + boundary_xy + ferro_major + ferro_minor + 2.0*wire_wrap_minor + feat_size, buffer_z + boundary_z + wire_set_major + wire_minor ); let ferro2_center = ferro1_center + Meters::new(2.0*ferro_major + ferro_buffer, 0.0, 0.0); let ferro_center = (ferro1_center + ferro2_center)*0.5; // reserve the left/right locations for the SET wires. let set1_center = ferro1_center - Meters::new(ferro_major, 0.0, 0.0); let set2_center = ferro2_center + Meters::new(ferro_major, 0.0, 0.0); 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 coupling_region1 = Wrap::new_about( Translate::new( SwapYZ::new(region::and_not( Spiral::new(ferro_minor + wire_wrap_minor + feat_size, wire_wrap_minor, 0.125), Cube::new(Meters::new(-1.0, -1.0, -0.125), Meters::new(1.0, 1.0, 0.125)) )), ferro1_center + Meters::new(1.0*ferro_major, 0.0, 0.0), ), 1.0, // one half-rev => y=1.0 ferro1_center, ); let coupling_region2 = Wrap::new_about( Translate::new( SwapYZ::new(region::and_not( Spiral::new(ferro_minor + wire_wrap_minor + feat_size, wire_wrap_minor, 0.125), Cube::new(Meters::new(-1.0, -1.0, -0.875), Meters::new(1.0, 1.0, 0.875)) )), ferro2_center + Meters::new(1.0*ferro_major, 0.0, 0.0), ), 1.0, // one half-rev => y=1.0 ferro2_center, ); let coupling_wire_top = Cube::new_centered( ferro_center - Meters::new(0.0, 0.45*ferro_major, 0.0), Meters::new(ferro_buffer - 3.0*feat_size, 1.0*feat_size, 2.0*feat_size) ); let coupling_wire_bot = Cube::new_centered( ferro_center + Meters::new(0.0, 0.45*ferro_major, 0.0), Meters::new(ferro_buffer - 3.0*feat_size, 1.0*feat_size, 2.0*feat_size) ); let coupling_region = region::Union::new() .with(coupling_region1.clone()) .with(coupling_region2.clone()) // we don't actually need these coupling wires: the wraps touch naturally. // .with(coupling_wire_top.clone()) // .with(coupling_wire_bot.clone()) ; // mu_r=881.33, starting at H=25 to H=75. let ferro_mat = mat::MHPgram::new(25.0, 881.33, 44000.0); 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); driver.fill_region(&coupling_region, 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)); assert!(driver.test_region_filled(&coupling_region, 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 + set_duration + clock_duration; 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())); // driver.add_measurement(meas::CurrentLoop::new("coupling1", coupling_region1.clone())); // driver.add_measurement(meas::CurrentLoop::new("coupling2", coupling_region2.clone())); // driver.add_measurement(meas::CurrentLoop::new("couplingtop", coupling_wire_top.clone())); // driver.add_measurement(meas::CurrentLoop::new("couplingbot", coupling_wire_bot.clone())); let prefix = format!("out/{}/{}-{}-{}setmA-{}setps-{}clkmA-{}clkps-{}um", 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, ); let _ = std::fs::create_dir_all(&prefix); driver.add_state_file(&*format!("{}/state.bc", prefix), 16000); // driver.add_serializer_renderer(&*format!("{}/frame-", prefix), 32000); 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)); }