new example which stacks cores vertically, for denser coupling.
This commit is contained in:
158
examples/buffer_proto3.rs
Normal file
158
examples/buffer_proto3.rs
Normal file
@@ -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);
|
||||||
|
}
|
@@ -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::mat::{self, Pml};
|
||||||
use crate::meas::{self, AbstractMeasurement};
|
use crate::meas::{self, AbstractMeasurement};
|
||||||
use crate::real::Real;
|
use crate::real::Real;
|
||||||
@@ -92,6 +92,12 @@ impl<S: MaterialSim> Driver<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: SampleableSim> Driver<S> {
|
||||||
|
pub fn size(&self) -> Index {
|
||||||
|
self.state.size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
|
impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
|
||||||
pub fn dyn_state(&mut self) -> &mut dyn SampleableSim {
|
pub fn dyn_state(&mut self) -> &mut dyn SampleableSim {
|
||||||
&mut self.state
|
&mut self.state
|
||||||
|
@@ -60,6 +60,20 @@ impl Sub<Meters> for Meters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Div<f32> for Meters {
|
||||||
|
type Output = Meters;
|
||||||
|
fn div(self, s: f32) -> Self {
|
||||||
|
Self(self.0/s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mul<f32> for Meters {
|
||||||
|
type Output = Meters;
|
||||||
|
fn mul(self, s: f32) -> Self {
|
||||||
|
Self(self.0*s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for Meters {
|
impl Display for Meters {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "Meters{}", self.0)
|
write!(f, "Meters{}", self.0)
|
||||||
|
@@ -7,7 +7,7 @@ use crate::sim::StepParametersMut;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
/// Material which has a conductivity parameter, but cannot be magnetized
|
/// 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<R> {
|
pub struct Conductor<R> {
|
||||||
conductivity: Vec3<R>,
|
conductivity: Vec3<R>,
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ impl<R: Real> Material<R> for Conductor<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Material which can be magnetized, but has no hysteresis and no coercivity.
|
/// 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<R> {
|
pub struct LinearMagnet<R> {
|
||||||
/// \mu_r
|
/// \mu_r
|
||||||
relative_permeability: Vec3<R>,
|
relative_permeability: Vec3<R>,
|
||||||
|
Reference in New Issue
Block a user