From 6a420696594bcc7a7cddeb69ce33c05c93d08b16 Mon Sep 17 00:00:00 2001 From: Colin Date: Thu, 23 Dec 2021 06:30:26 -0800 Subject: [PATCH] new example which stacks cores vertically, for denser coupling. --- examples/buffer_proto3.rs | 158 ++++++++++++++++++++++++++++++++++++++ src/driver.rs | 8 +- src/geom/units.rs | 14 ++++ src/mat/linear.rs | 4 +- 4 files changed, 181 insertions(+), 3 deletions(-) create mode 100644 examples/buffer_proto3.rs diff --git a/examples/buffer_proto3.rs b/examples/buffer_proto3.rs new file mode 100644 index 0000000..e96f9d1 --- /dev/null +++ b/examples/buffer_proto3.rs @@ -0,0 +1,158 @@ +//! this example stacks buffers vertically so that we can couple them with MANY wire loops. + +use coremem::{Driver, mat, meas, SampleableSim as _, SimState}; +use coremem::real::R32 as Real; +use coremem::geom::{Index, Meters, Torus}; +use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying1 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 = 480e-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-10"; + + 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 mut 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::db::conductor(drive_conductivity); + + 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, 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 = Sinusoid1::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); + driver.add_csv_renderer(&*format!("{}/meas.csv", prefix), 200); + driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 8000); + + driver.step_until(duration); +} diff --git a/src/driver.rs b/src/driver.rs index 7bd4689..ab525e9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,4 +1,4 @@ -use crate::geom::{Coord, Meters, Region, Vec3}; +use crate::geom::{Coord, Index, Meters, Region, Vec3}; use crate::mat::{self, Pml}; use crate::meas::{self, AbstractMeasurement}; use crate::real::Real; @@ -92,6 +92,12 @@ impl Driver { } } +impl Driver { + pub fn size(&self) -> Index { + self.state.size() + } +} + impl Driver { pub fn dyn_state(&mut self) -> &mut dyn SampleableSim { &mut self.state diff --git a/src/geom/units.rs b/src/geom/units.rs index c70ce8d..dbafecd 100644 --- a/src/geom/units.rs +++ b/src/geom/units.rs @@ -60,6 +60,20 @@ impl Sub for Meters { } } +impl Div for Meters { + type Output = Meters; + fn div(self, s: f32) -> Self { + Self(self.0/s) + } +} + +impl Mul for Meters { + type Output = Meters; + fn mul(self, s: f32) -> Self { + Self(self.0*s) + } +} + impl Display for Meters { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Meters{}", self.0) diff --git a/src/mat/linear.rs b/src/mat/linear.rs index bf15cd5..c2df619 100644 --- a/src/mat/linear.rs +++ b/src/mat/linear.rs @@ -7,7 +7,7 @@ use crate::sim::StepParametersMut; use serde::{Serialize, Deserialize}; /// Material which has a conductivity parameter, but cannot be magnetized -#[derive(Clone, Default, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct Conductor { conductivity: Vec3, } @@ -32,7 +32,7 @@ impl Material for Conductor { } /// Material which can be magnetized, but has no hysteresis and no coercivity. -#[derive(Clone, Default, PartialEq, Serialize, Deserialize)] +#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct LinearMagnet { /// \mu_r relative_permeability: Vec3,