build out the fourth buffer prototype

This commit is contained in:
2022-01-03 12:48:51 -08:00
parent fa841b520c
commit 4315d003b2
6 changed files with 305 additions and 13 deletions

197
examples/buffer_proto4.rs Normal file
View File

@@ -0,0 +1,197 @@
//! 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, SampleableSim as _, SimState};
use coremem::real::R32 as Real;
use coremem::geom::{region, Cube, Index, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
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 = 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 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);
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 = 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 + 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);
driver.add_csv_renderer(&*format!("{}/meas-sparse.csv", prefix), 8000);
driver.step_until(duration);
}

View File

@@ -30,6 +30,8 @@ pub struct Driver<S=SimState> {
stimuli: StimuliAdapter, stimuli: StimuliAdapter,
start_time: Instant, start_time: Instant,
last_diag_time: Instant, last_diag_time: Instant,
/// simulation end time
sim_end_time: Option<f32>,
} }
impl<R: Real, M: Default> Driver<SimState<R, M>> { impl<R: Real, M: Default> Driver<SimState<R, M>> {
@@ -65,6 +67,7 @@ impl<S> Driver<S> {
stimuli: StimuliAdapter::new(), stimuli: StimuliAdapter::new(),
start_time: Instant::now(), start_time: Instant::now(),
last_diag_time: Instant::now(), last_diag_time: Instant::now(),
sim_end_time: None,
} }
} }
} }
@@ -171,7 +174,7 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
if self.stimuli.should_apply(start_step) { if self.stimuli.should_apply(start_step) {
self.stimuli.real_time = self.state.time(); self.stimuli.real_time = self.state.time();
self.stimuli.time_step = self.state.timestep(); self.stimuli.time_step = self.state.timestep();
info!("updating stimuli"); trace!("updating stimuli");
} }
if self.renderer.any_work_for_frame(start_step) { if self.renderer.any_work_for_frame(start_step) {
@@ -198,8 +201,13 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
let overall_time = self.start_time.elapsed().as_secs_f64(); let overall_time = self.start_time.elapsed().as_secs_f64();
let fps = (self.state.step_no() as f64) / overall_time; let fps = (self.state.step_no() as f64) / overall_time;
let sim_time = self.state.time() as f64; let sim_time = self.state.time() as f64;
let percent_complete = match self.sim_end_time {
Some(t) => format!("[{:.1}%] ", 100.0 * self.state.time() / t),
None => "".to_owned(),
};
info!( info!(
"t={:.2e} frame {:06} fps: {:6.2} (sim: {:.1}s, stim: {:.1}s, [render: {:.1}s], blocked: {:.1}s, render_prep: {:.1}s, other: {:.1}s)", "{}t={:.2e} frame {:06} fps: {:6.2} (sim: {:.1}s, stim: {:.1}s, [render: {:.1}s], blocked: {:.1}s, render_prep: {:.1}s, other: {:.1}s)",
percent_complete,
sim_time, sim_time,
step, step,
fps, fps,
@@ -223,13 +231,15 @@ impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
self.step_multiple(1); self.step_multiple(1);
} }
pub fn step_until(&mut self, deadline: f32) { pub fn step_until(&mut self, sim_end_time: f32) {
while self.dyn_state().time() < deadline { self.sim_end_time = Some(sim_end_time);
while self.dyn_state().time() < sim_end_time {
self.step_multiple(100); self.step_multiple(100);
} }
// render the final frame // render the final frame
self.render(); self.render();
self.render_pool.join(); self.render_pool.join();
self.sim_end_time = None;
} }
} }

View File

@@ -1,13 +1,15 @@
mod line; mod line;
mod polygon; mod polygon;
mod region; pub mod region;
mod units; mod units;
mod vec; mod vec;
mod vecu; mod vecu;
pub use line::Line2d; pub use line::Line2d;
pub use polygon::Polygon2d; pub use polygon::Polygon2d;
pub use region::{Cube, CylinderZ, InvertedRegion, Region, Sphere, Torus, Union, WorldRegion}; pub use region::{
Cube, CylinderZ, InvertedRegion, Region, Sphere, Spiral, SwapXZ, SwapYZ, Torus, Translate, Union, WorldRegion, Wrap
};
pub use units::{Coord, Meters, Index}; pub use units::{Coord, Meters, Index};
pub use vec::{Vec2, Vec3}; pub use vec::{Vec2, Vec3};
pub use vecu::Vec3u; pub use vecu::Vec3u;

View File

@@ -13,6 +13,17 @@ pub trait Region: Send + Sync + DynClone {
} }
dyn_clone::clone_trait_object!(Region); dyn_clone::clone_trait_object!(Region);
pub fn and<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection {
Intersection::new().and(r1).and(r2)
}
pub fn and_not<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Intersection {
and(r1, InvertedRegion::new(r2))
}
pub fn union<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Union {
Union::new().with(r1).with(r2)
}
/// Region describing the entire simulation space /// Region describing the entire simulation space
#[derive(Copy, Clone, Serialize, Deserialize)] #[derive(Copy, Clone, Serialize, Deserialize)]
@@ -46,13 +57,16 @@ pub struct Union(Vec<Box<dyn Region>>);
impl Union { impl Union {
pub fn new() -> Self { pub fn new() -> Self {
Union(Vec::new()) Self(Vec::new())
} }
pub fn new_with<R: Region + 'static>(r: R) -> Self { pub fn new_with<R: Region + 'static>(r: R) -> Self {
Self::new().with(r) Self::new().with(r)
} }
pub fn with<R: Region + 'static>(mut self, r: R) -> Self { pub fn with<R: Region + 'static>(self, r: R) -> Self {
self.0.push(Box::new(r)); self.with_box(Box::new(r))
}
pub fn with_box(mut self, r: Box<dyn Region>) -> Self {
self.0.push(r);
self self
} }
} }
@@ -64,6 +78,33 @@ impl Region for Union {
} }
} }
#[derive(Clone, Serialize, Deserialize)]
pub struct Intersection(Vec<Box<dyn Region>>);
impl Intersection {
pub fn new() -> Self {
Self(Vec::new())
}
pub fn new_with<R: Region + 'static>(r: R) -> Self {
Self::new().and(r)
}
pub fn and<R: Region + 'static>(self, r: R) -> Self {
self.and_box(Box::new(r))
}
pub fn and_box(mut self, r: Box<dyn Region>) -> Self {
self.0.push(r);
self
}
}
#[typetag::serde]
impl Region for Intersection {
fn contains(&self, p: Meters) -> bool {
self.0.iter().all(|r| r.contains(p))
}
}
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct Translate { pub struct Translate {
inner: Box<dyn Region>, inner: Box<dyn Region>,
@@ -83,6 +124,45 @@ impl Region for Translate {
} }
} }
#[derive(Clone, Serialize, Deserialize)]
pub struct SwapXZ {
inner: Box<dyn Region>,
}
impl SwapXZ {
pub fn new<T: Region + 'static>(inner: T) -> Self {
Self { inner: Box::new(inner) }
}
}
#[typetag::serde]
impl Region for SwapXZ {
fn contains(&self, p: Meters) -> bool {
let p = Meters::new(p.z(), p.y(), p.z());
self.inner.contains(p)
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct SwapYZ {
inner: Box<dyn Region>,
}
impl SwapYZ {
pub fn new<T: Region + 'static>(inner: T) -> Self {
Self { inner: Box::new(inner) }
}
}
#[typetag::serde]
impl Region for SwapYZ {
fn contains(&self, p: Meters) -> bool {
let mapped = Meters::new(p.x(), p.z(), p.y());
self.inner.contains(mapped)
}
}
/// "wraps" the inner region into a donut shape. /// "wraps" the inner region into a donut shape.
/// this donut is traced out over the xy plane, leaving z untouched. /// this donut is traced out over the xy plane, leaving z untouched.
/// the center of the donut is (0, 0). /// the center of the donut is (0, 0).
@@ -90,7 +170,7 @@ impl Region for Translate {
/// so that (0, 0) is mapped to (0, 0), and (1, 0) is mapped to (1, 0) and (0, 1) is mapped to /// so that (0, 0) is mapped to (0, 0), and (1, 0) is mapped to (1, 0) and (0, 1) is mapped to
/// (1, 0.5*y_max) and (-5, 0) is mapped to (5, 0.5*y_max). /// (1, 0.5*y_max) and (-5, 0) is mapped to (5, 0.5*y_max).
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
struct Wrap { pub struct Wrap {
inner: Box<dyn Region>, inner: Box<dyn Region>,
y_max: f32, y_max: f32,
about: Meters, about: Meters,
@@ -108,8 +188,8 @@ impl Wrap {
fn map(&self, p: Meters) -> Meters { fn map(&self, p: Meters) -> Meters {
let p_rel = p - self.about; let p_rel = p - self.about;
let xy = p_rel.xy(); let xy = p_rel.xy();
let y = xy.arg() / std::f32::consts::PI * self.y_max; let rev = xy.arg() / std::f32::consts::PI * self.y_max;
Meters::new(xy.mag() - self.about.xy().mag(), y, p.z()) Meters::new(xy.mag() + self.about.x(), rev, p.z())
} }
} }

View File

@@ -137,6 +137,9 @@ impl Cube {
pub fn new(lower: Meters, upper: Meters) -> Self { pub fn new(lower: Meters, upper: Meters) -> Self {
Self { lower, upper } Self { lower, upper }
} }
pub fn new_centered(center: Meters, size: Meters) -> Self {
Self::new(center - size*0.5, center + size*0.5)
}
pub fn x_range(&self) -> Range<f32> { pub fn x_range(&self) -> Range<f32> {
self.lower.x()..self.upper.x() self.lower.x()..self.upper.x()
} }

View File

@@ -26,7 +26,7 @@ pub use sim::*;
// For a vacuum, B = H // For a vacuum, B = H
pub fn init_logging() { pub fn init_logging() {
let conf = env_logger::Env::new().default_filter_or("INFO"); let conf = env_logger::Env::new().default_filter_or("INFO,wgpu_core=WARN");
env_logger::Builder::from_env(conf).init(); env_logger::Builder::from_env(conf).init();
info!("logging initialized"); info!("logging initialized");
} }