improve verification for buffer_proto5

verify that different pieces of the sim are properly connected.
This commit is contained in:
2022-01-11 14:03:46 -08:00
parent be16f7d21c
commit fe5eab5e43
9 changed files with 310 additions and 59 deletions

View File

@@ -2,10 +2,13 @@
//! v.s. the fourth prototype, it changes the couplings in an attempt to reduce unwanted //! v.s. the fourth prototype, it changes the couplings in an attempt to reduce unwanted
//! clock -> mem2 coupling //! clock -> mem2 coupling
use coremem::{Driver, mat, meas, SampleableSim as _, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::real::R32 as Real; use coremem::geom::{region, Cube, Dilate, Meters, Region, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::geom::{region, Cube, Dilate, Index, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::stim::{CurlStimulus, Gated, Sinusoid1, TimeVarying1 as _}; use coremem::stim::{CurlStimulus, Gated, Sinusoid1, TimeVarying1 as _};
use log::info;
#[allow(unused)]
use coremem::geom::{Coord as _, Region as _};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct Params { struct Params {
@@ -108,23 +111,27 @@ fn run_sim(id: u32, p: Params) {
ferro_center + Meters::new_y(p.ferro_major + 4.0*p.wire_wrap_minor + 12.0*p.feat_size), ferro_center + Meters::new_y(p.ferro_major + 4.0*p.wire_wrap_minor + 12.0*p.feat_size),
Meters::new(p.ferro_buffer + 2.0*p.ferro_major + 4.0*p.feat_size, 2.0*p.feat_size, 2.0*p.feat_size) Meters::new(p.ferro_buffer + 2.0*p.ferro_major + 4.0*p.feat_size, 2.0*p.feat_size, 2.0*p.feat_size)
); );
let coupling_stub_top_left = Cube::new_including_negatives(
coupling_wire_top.bot_left_out(),
coupling_wire_top.bot_left_out() + Meters::new(4.0*p.feat_size, 10.0*p.feat_size, 2.0*p.feat_size)
);
let coupling_stub_top_right = Cube::new_including_negatives(
coupling_wire_top.bot_right_out(),
coupling_wire_top.bot_right_out() + Meters::new(-4.0*p.feat_size, 10.0*p.feat_size, 2.0*p.feat_size)
);
let coupling_stub_bot_left = Cube::new_including_negatives(
coupling_wire_bot.top_left_out(),
coupling_wire_bot.top_left_out() + Meters::new(4.0*p.feat_size, -10.0*p.feat_size, 2.0*p.feat_size)
);
let coupling_stub_bot_right = Cube::new_including_negatives(
coupling_wire_bot.top_right_out(),
coupling_wire_bot.top_right_out() + Meters::new(-4.0*p.feat_size, -10.0*p.feat_size, 2.0*p.feat_size)
);
let coupling_stubs = region::Union::new() let coupling_stubs = region::Union::new()
.with(Cube::new_including_negatives( .with(coupling_stub_top_left.clone())
coupling_wire_top.bot_left_out(), .with(coupling_stub_top_right.clone())
coupling_wire_top.bot_left_out() + Meters::new(4.0*p.feat_size, 10.0*p.feat_size, 2.0*p.feat_size) .with(coupling_stub_bot_left.clone())
)) .with(coupling_stub_bot_right.clone())
.with(Cube::new_including_negatives(
coupling_wire_top.bot_right_out(),
coupling_wire_top.bot_right_out() + Meters::new(-4.0*p.feat_size, 10.0*p.feat_size, 2.0*p.feat_size)
))
.with(Cube::new_including_negatives(
coupling_wire_bot.top_left_out(),
coupling_wire_bot.top_left_out() + Meters::new(4.0*p.feat_size, -10.0*p.feat_size, 2.0*p.feat_size)
))
.with(Cube::new_including_negatives(
coupling_wire_bot.top_right_out(),
coupling_wire_bot.top_right_out() + Meters::new(-4.0*p.feat_size, -10.0*p.feat_size, 2.0*p.feat_size)
))
; ;
let coupling_wires = region::Union::new() let coupling_wires = region::Union::new()
@@ -160,6 +167,33 @@ fn run_sim(id: u32, p: Params) {
p.feat_size, p.feat_size,
), "{:?}", p); ), "{:?}", p);
assert!(wrap1_with_coupling.contains(
coupling_stub_top_left.center().to_index(p.feat_size).to_meters(p.feat_size),
));
assert!(wrap1_with_coupling.contains(
coupling_stub_bot_left.center().to_index(p.feat_size).to_meters(p.feat_size),
));
assert!(wrap2_with_coupling.contains(
coupling_stub_top_right.center().to_index(p.feat_size).to_meters(p.feat_size),
));
assert!(wrap2_with_coupling.contains(
coupling_stub_bot_right.center().to_index(p.feat_size).to_meters(p.feat_size),
));
info!("wrap1 length: {}", region::distance_to(
&wrap1_with_coupling,
coupling_stub_top_left.center().to_index(p.feat_size),
coupling_stub_bot_left.center().to_index(p.feat_size),
p.feat_size,
).unwrap());
info!("wrap2 length: {}", region::distance_to(
&wrap2_with_coupling,
coupling_stub_top_right.center().to_index(p.feat_size),
coupling_stub_bot_right.center().to_index(p.feat_size),
p.feat_size,
).unwrap());
return;
// mu_r=881.33, starting at H=25 to H=75. // 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::MHPgram::new(25.0, 881.33, 44000.0);
// let ferro_mat = mat::db::conductor(wire_conductivity); // let ferro_mat = mat::db::conductor(wire_conductivity);
@@ -173,10 +207,10 @@ fn run_sim(id: u32, p: Params) {
driver.fill_region(&set2_region, wire_mat); driver.fill_region(&set2_region, wire_mat);
driver.fill_region(&coupling_region, wire_mat); driver.fill_region(&coupling_region, wire_mat);
println!("boundary: {}um; {}um", m_to_um(p.boundary_xy), m_to_um(p.boundary_z)); info!("boundary: {}um; {}um", m_to_um(p.boundary_xy), m_to_um(p.boundary_z));
println!("size: {}, {}, {}", width, height, depth); info!("size: {}, {}, {}", width, height, depth);
println!("ferro1: {:?}", ferro1_center); info!("ferro1: {:?}", ferro1_center);
println!("ferro2: {:?}", ferro2_center); info!("ferro2: {:?}", ferro2_center);
driver.add_classical_boundary(Meters::new(p.boundary_xy, p.boundary_xy, p.boundary_z)); driver.add_classical_boundary(Meters::new(p.boundary_xy, p.boundary_xy, p.boundary_z));
assert!(driver.test_region_filled(&ferro1_region, ferro_mat)); assert!(driver.test_region_filled(&ferro1_region, ferro_mat));
@@ -271,15 +305,20 @@ fn run_sim(id: u32, p: Params) {
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
for (i, dump_frames, wraps1, wraps2) in [ for (i, dump_frames, wraps1, wraps2) in [
(38, Some(1000000), 20.0, 12.0), // (38, Some(1000000), 20.0, 12.0),
(39, Some(1000000), 20.0, 8.0), // (39, Some(1000000), 20.0, 8.0),
(40, Some(1000000), 20.0, 16.0), // (51, Some(1000000), 16.0, 16.0),
(41, Some(1000000), 20.0, 20.0), // (41, Some(1000000), 20.0, 20.0),
// // (42, Some(1000000), 24.0, 12.0), // // (42, Some(1000000), 24.0, 12.0), // FAILS auto connection check
// // (43, Some(1000000), 28.0, 12.0), // // (43, Some(1000000), 28.0, 12.0),
// // (44, Some(1000000), 32.0, 12.0), // // (44, Some(1000000), 32.0, 12.0),
// // (45, Some(1000000), 24.0, 16.0), // // (45, Some(1000000), 24.0, 16.0),
// // (46, Some(1000000), 24.0, 20.0), // // (46, Some(1000000), 24.0, 20.0),
(47, Some(1000000), 24.0, 16.0),
(48, Some(1000000), 24.0, 20.0), // passes auto connection check
(49, Some(1000000), 28.0, 16.0), // passes auto connection check
(50, Some(1000000), 28.0, 20.0), // passes auto connection check
// // (51, Some(1000000), 32.0, 16.0), // FAILS auto connection check
].iter().copied() { ].iter().copied() {
run_sim(i, Params { run_sim(i, Params {
feat_size: 40e-6f32, feat_size: 40e-6f32,
@@ -289,7 +328,7 @@ fn main() {
boundary_xy: 320e-6, boundary_xy: 320e-6,
boundary_z: 320e-6, boundary_z: 320e-6,
ferro_major: 1240e-6, ferro_major: 1360e-6,
ferro_minor: 60e-6, ferro_minor: 60e-6,
ferro_buffer: 1320e-6, ferro_buffer: 1320e-6,
wire_minor: 40e-6, wire_minor: 40e-6,

View File

@@ -34,13 +34,15 @@ pub struct Driver<S=SimState> {
sim_end_time: Option<f32>, sim_end_time: Option<f32>,
} }
pub type SpirvDriver = Driver<SpirvSim>;
impl<R: Real, M: Default> Driver<SimState<R, M>> { impl<R: Real, M: Default> Driver<SimState<R, M>> {
pub fn new<C: Coord>(size: C, feature_size: f32) -> Self { pub fn new<C: Coord>(size: C, feature_size: f32) -> Self {
Self::new_with_state(SimState::new(size.to_index(feature_size), feature_size)) Self::new_with_state(SimState::new(size.to_index(feature_size), feature_size))
} }
} }
impl Driver<SpirvSim> { impl SpirvDriver {
pub fn new_spirv<C: Coord>(size: C, feature_size: f32) -> Self { pub fn new_spirv<C: Coord>(size: C, feature_size: f32) -> Self {
Self::new_with_state(SpirvSim::new(size.to_index(feature_size), feature_size)) Self::new_with_state(SpirvSim::new(size.to_index(feature_size), feature_size))
} }
@@ -107,31 +109,31 @@ impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
} }
fn add_renderer<Rend: Renderer<S> + 'static>( fn add_renderer<Rend: Renderer<S> + 'static>(
&mut self, renderer: Rend, name: &str, step_frequency: u64 &mut self, renderer: Rend, name: &str, step_frequency: u64, frame_limit: Option<u64>
) { ) {
info!("render to {} at f={}", name, step_frequency); info!("render to {} at f={} until f={:?}", name, step_frequency, frame_limit);
self.renderer.push(renderer, step_frequency); self.renderer.push(renderer, step_frequency, frame_limit);
} }
pub fn add_y4m_renderer<P: Into<PathBuf>>(&mut self, output: P, step_frequency: u64) { pub fn add_y4m_renderer<P: Into<PathBuf>>(&mut self, output: P, step_frequency: u64, frame_limit: Option<u64>) {
let output = output.into(); let output = output.into();
let name = output.to_string_lossy().into_owned(); let name = output.to_string_lossy().into_owned();
self.add_renderer(render::Y4MRenderer::new(output), &*name, step_frequency); self.add_renderer(render::Y4MRenderer::new(output), &*name, step_frequency, frame_limit);
} }
pub fn add_term_renderer(&mut self, step_frequency: u64) { pub fn add_term_renderer(&mut self, step_frequency: u64, frame_limit: Option<u64>) {
self.add_renderer(render::ColorTermRenderer, "terminal", step_frequency); self.add_renderer(render::ColorTermRenderer, "terminal", step_frequency, frame_limit);
} }
pub fn add_csv_renderer(&mut self, path: &str, step_frequency: u64) { pub fn add_csv_renderer(&mut self, path: &str, step_frequency: u64, frame_limit: Option<u64>) {
self.add_renderer(render::CsvRenderer::new(path), path, step_frequency); self.add_renderer(render::CsvRenderer::new(path), path, step_frequency, frame_limit);
} }
} }
impl<S: SampleableSim + Send + Sync + Serialize + 'static> Driver<S> { impl<S: SampleableSim + Send + Sync + Serialize + 'static> Driver<S> {
pub fn add_serializer_renderer(&mut self, out_base: &str, step_frequency: u64) { pub fn add_serializer_renderer(&mut self, out_base: &str, step_frequency: u64, frame_limit: Option<u64>) {
let fmt_str = format!("{out_base}{{step_no}}.bc", out_base=out_base); let fmt_str = format!("{out_base}{{step_no}}.bc", out_base=out_base);
self.add_renderer(render::SerializerRenderer::new_static(&*fmt_str), &*fmt_str, step_frequency); self.add_renderer(render::SerializerRenderer::new_static(&*fmt_str), &*fmt_str, step_frequency, frame_limit);
} }
} }
@@ -141,7 +143,7 @@ impl<S: SampleableSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'sta
if let Some(state) = ser.try_load() { if let Some(state) = ser.try_load() {
self.state = state.state; self.state = state.state;
} }
self.add_renderer(ser, state_file, snapshot_frequency); self.add_renderer(ser, state_file, snapshot_frequency, None);
} }
} }

View File

@@ -8,7 +8,7 @@ mod vecu;
pub use line::Line2d; pub use line::Line2d;
pub use polygon::Polygon2d; pub use polygon::Polygon2d;
pub use region::{ pub use region::{
Cube, CylinderZ, InvertedRegion, Region, Sphere, Spiral, SwapXZ, SwapYZ, Torus, Translate, Union, WorldRegion, Wrap Cube, CylinderZ, Dilate, 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};

View File

@@ -1,7 +1,8 @@
use crate::geom::Meters; use crate::geom::{Coord, Index, Meters};
use dyn_clone::{self, DynClone}; use dyn_clone::{self, DynClone};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use std::collections::{BTreeMap, BTreeSet};
mod primitives; mod primitives;
pub use primitives::*; pub use primitives::*;
@@ -25,6 +26,61 @@ pub fn union<T1: Region + 'static, T2: Region + 'static>(r1: T1, r2: T2) -> Unio
Union::new().with(r1).with(r2) Union::new().with(r1).with(r2)
} }
/// returns true if there's a path (via the cardinal directions) from p0 to p1 within this region.
pub fn is_connected<R: Region, C: Coord>(r: &R, p0: C, p1: C, feat_size: f32) -> bool {
let mut pts = BTreeSet::new();
pts = crawl_to(pts, r, p0.to_index(feat_size), p1.to_index(feat_size), feat_size);
pts.contains(&p1.to_index(feat_size))
}
fn crawl_to<R: Region>(mut pts: BTreeSet<Index>, r: &R, p0: Index, p1: Index, feat_size: f32) -> BTreeSet<Index> {
if pts.contains(&p1) || pts.contains(&p0) {
// either already reached the goal, or already crawled this location
return pts;
}
if r.contains(p0.to_meters(feat_size)) {
pts.insert(p0);
pts = crawl_to(pts, r, p0.left(), p1, feat_size);
pts = crawl_to(pts, r, p0.right(), p1, feat_size);
pts = crawl_to(pts, r, p0.up(), p1, feat_size);
pts = crawl_to(pts, r, p0.down(), p1, feat_size);
pts = crawl_to(pts, r, p0.out(), p1, feat_size);
pts = crawl_to(pts, r, p0.in_(), p1, feat_size);
}
pts
}
/// returns the minimal distance to crawl from p0 to p1 (via movements along a cardinal direction)
pub fn distance_to<R: Region, C: Coord>(r: &R, p0: C, p1: C, feat_size: f32) -> Option<f32> {
let mut pts = BTreeMap::new();
crawl_with_distance(&mut pts, r, p0.to_index(feat_size), 0, feat_size);
println!("pts size: {}", pts.len());
pts.get(&p1.to_index(feat_size)).map(|d| *d as f32 * feat_size)
}
fn crawl_with_distance<R: Region>(pts: &mut BTreeMap<Index, u32>, r: &R, current: Index, current_value: u32, feat_size: f32) {
use std::collections::btree_map::Entry;
if !r.contains(current.to_meters(feat_size)) {
return;
}
match pts.entry(current) {
Entry::Occupied(old_value) if *old_value.get() <= current_value => {
return; // already crawled
}
other => {
*other.or_default() = current_value;
}
}
// crawl neighbors
crawl_with_distance(pts, r, current.left(), current_value+1, feat_size);
crawl_with_distance(pts, r, current.right(), current_value+1, feat_size);
crawl_with_distance(pts, r, current.up(), current_value+1, feat_size);
crawl_with_distance(pts, r, current.down(), current_value+1, feat_size);
crawl_with_distance(pts, r, current.out(), current_value+1, feat_size);
crawl_with_distance(pts, r, current.in_(), current_value+1, feat_size);
}
/// Region describing the entire simulation space /// Region describing the entire simulation space
#[derive(Copy, Clone, Serialize, Deserialize)] #[derive(Copy, Clone, Serialize, Deserialize)]
pub struct WorldRegion; pub struct WorldRegion;
@@ -200,6 +256,38 @@ impl Region for Wrap {
} }
} }
#[derive(Clone, Serialize, Deserialize)]
pub struct Dilate {
inner: Box<dyn Region>,
rad: f32,
}
impl Dilate {
pub fn new<T: Region + 'static>(inner: T, rad: f32) -> Self {
Self { inner: Box::new(inner), rad }
}
pub fn new_iterated<T: Region + 'static>(inner: T, resolution: f32, iters: usize) -> Self {
let mut it = Self::new(inner, resolution);
for _ in 1..iters {
it = Self::new(it, resolution);
}
it
}
}
#[typetag::serde]
impl Region for Dilate {
fn contains(&self, p: Meters) -> bool {
self.inner.contains(p)
|| self.inner.contains(p + Meters::new(self.rad, 0.0, 0.0))
|| self.inner.contains(p + Meters::new(0.0, -self.rad, 0.0))
|| self.inner.contains(p + Meters::new(0.0, self.rad, 0.0))
|| self.inner.contains(p + Meters::new(0.0, -self.rad, 0.0))
|| self.inner.contains(p + Meters::new(0.0, 0.0, self.rad))
|| self.inner.contains(p + Meters::new(0.0, 0.0, -self.rad))
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;

View File

@@ -14,7 +14,7 @@ pub struct CylinderZ {
} }
impl CylinderZ { impl CylinderZ {
// TODO: should be unit-typed // TODO: should be unit-typed (Meters)
pub fn new(center: Vec2<f32>, radius: f32) -> Self { pub fn new(center: Vec2<f32>, radius: f32) -> Self {
Self { Self {
center, center,
@@ -127,27 +127,84 @@ impl Region for Sphere {
#[derive(Copy, Clone, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Default, Serialize, Deserialize)]
pub struct Cube { pub struct Cube {
/// Lower corner (i.e. (x0, y0, z0)) /// (x0, y0, z0))
lower: Meters, small: Meters,
/// Upper corner (i.e. (x1, y1, z1)) where x1 >= x0, y1 >= y0, z1 >= z0 /// (i.e. (x1, y1, z1)) where x1 >= x0, y1 >= y0, z1 >= z0
upper: Meters, large: Meters,
} }
impl Cube { impl Cube {
pub fn new(lower: Meters, upper: Meters) -> Self { pub fn new(small: Meters, large: Meters) -> Self {
Self { lower, upper } Self { small, large }
} }
pub fn new_centered(center: Meters, size: Meters) -> Self { pub fn new_centered(center: Meters, size: Meters) -> Self {
Self::new(center - size*0.5, center + size*0.5) Self::new(center - size*0.5, center + size*0.5)
} }
/// 'new', but handle the case where pt1's coordinate is lower than pt0 by 'swapping' them
pub fn new_including_negatives(pt0: Meters, pt1: Meters) -> Self {
Self::new(
Meters::new(pt0.x().min(pt1.x()), pt0.y().min(pt1.y()), pt0.z().min(pt1.z())),
Meters::new(pt0.x().max(pt1.x()), pt0.y().max(pt1.y()), pt0.z().max(pt1.z())),
)
}
pub fn x_range(&self) -> Range<f32> { pub fn x_range(&self) -> Range<f32> {
self.lower.x()..self.upper.x() self.small.x()..self.large.x()
} }
pub fn y_range(&self) -> Range<f32> { pub fn y_range(&self) -> Range<f32> {
self.lower.y()..self.upper.y() self.small.y()..self.large.y()
} }
pub fn z_range(&self) -> Range<f32> { pub fn z_range(&self) -> Range<f32> {
self.lower.z()..self.upper.z() self.small.z()..self.large.z()
}
pub fn small(&self) -> Meters {
self.small
}
pub fn large(&self) -> Meters {
self.large
}
pub fn center(&self) -> Meters {
(self.small + self.large) * 0.5
}
pub fn bot_left_out(&self) -> Meters {
Meters::new(self.small.x(), self.large.y(), self.small.z())
}
pub fn bot_left_center(&self) -> Meters {
Meters::new(self.small.x(), self.large.y(), self.center().z())
}
pub fn bot_left_in(&self) -> Meters {
Meters::new(self.small.x(), self.large.y(), self.large.z())
}
pub fn bot_right_out(&self) -> Meters {
Meters::new(self.large.x(), self.large.y(), self.small.z())
}
pub fn bot_right_center(&self) -> Meters {
Meters::new(self.large.x(), self.large.y(), self.center().z())
}
pub fn bot_right_in(&self) -> Meters {
Meters::new(self.large.x(), self.large.y(), self.large.z())
}
pub fn top_left_out(&self) -> Meters {
Meters::new(self.small.x(), self.small.y(), self.small.z())
}
pub fn top_left_center(&self) -> Meters {
Meters::new(self.small.x(), self.small.y(), self.center().z())
}
pub fn top_left_in(&self) -> Meters {
Meters::new(self.small.x(), self.small.y(), self.large.z())
}
pub fn top_right_out(&self) -> Meters {
Meters::new(self.large.x(), self.small.y(), self.small.z())
}
pub fn top_right_center(&self) -> Meters {
Meters::new(self.large.x(), self.small.y(), self.center().z())
}
pub fn top_right_in(&self) -> Meters {
Meters::new(self.large.x(), self.small.y(), self.large.z())
} }
} }

View File

@@ -6,7 +6,10 @@ use std::ops::{Add, Deref, Div, Mul, Neg, Sub};
pub trait Coord: Copy + Clone { pub trait Coord: Copy + Clone {
fn to_meters(&self, feature_size: f32) -> Meters; fn to_meters(&self, feature_size: f32) -> Meters;
/// rounds
fn to_index(&self, feature_size: f32) -> Index; fn to_index(&self, feature_size: f32) -> Index;
fn to_index_ceil(&self, feature_size: f32) -> Index;
fn to_index_floor(&self, feature_size: f32) -> Index;
fn from_meters(other: Meters, feature_size: f32) -> Self; fn from_meters(other: Meters, feature_size: f32) -> Self;
fn from_index(other: Index, feature_size: f32) -> Self; fn from_index(other: Index, feature_size: f32) -> Self;
fn from_either(i: Index, m: Meters) -> Self; fn from_either(i: Index, m: Meters) -> Self;
@@ -19,6 +22,15 @@ impl Meters {
pub fn new<R: ToFloat>(x: R, y: R, z: R) -> Self { pub fn new<R: ToFloat>(x: R, y: R, z: R) -> Self {
Self(Vec3::new(x.to_f32(), y.to_f32(), z.to_f32())) Self(Vec3::new(x.to_f32(), y.to_f32(), z.to_f32()))
} }
pub fn new_x<R: ToFloat>(x: R) -> Self {
Self::new(x.to_f32(), 0.0, 0.0)
}
pub fn new_y<R: ToFloat>(y: R) -> Self {
Self::new(0.0, y.to_f32(), 0.0)
}
pub fn new_z<R: ToFloat>(z: R) -> Self {
Self::new(0.0, 0.0, z.to_f32())
}
} }
impl Coord for Meters { impl Coord for Meters {
@@ -28,6 +40,12 @@ impl Coord for Meters {
fn to_index(&self, feature_size: f32) -> Index { fn to_index(&self, feature_size: f32) -> Index {
Index((self.0 / feature_size).round().into()) Index((self.0 / feature_size).round().into())
} }
fn to_index_ceil(&self, feature_size: f32) -> Index {
Index((self.0 / feature_size).ceil().into())
}
fn to_index_floor(&self, feature_size: f32) -> Index {
Index((self.0 / feature_size).floor().into())
}
fn from_meters(other: Meters, _feature_size: f32) -> Self { fn from_meters(other: Meters, _feature_size: f32) -> Self {
other other
} }
@@ -106,6 +124,25 @@ impl Index {
pub fn volume(&self) -> usize { pub fn volume(&self) -> usize {
(self.0.x() as usize) * (self.0.y() as usize) * (self.0.z() as usize) (self.0.x() as usize) * (self.0.y() as usize) * (self.0.z() as usize)
} }
pub fn left(&self) -> Self {
Self::new(self.x() - 1, self.y(), self.z())
}
pub fn right(&self) -> Self {
Self::new(self.x() + 1, self.y(), self.z())
}
pub fn up(&self) -> Self {
Self::new(self.x(), self.y() - 1, self.z())
}
pub fn down(&self) -> Self {
Self::new(self.x(), self.y() + 1, self.z())
}
pub fn out(&self) -> Self {
Self::new(self.x(), self.y(), self.z() - 1)
}
pub fn in_(&self) -> Self {
Self::new(self.x(), self.y(), self.z() + 1)
}
} }
impl Coord for Index { impl Coord for Index {
@@ -115,6 +152,12 @@ impl Coord for Index {
fn to_index(&self, _feature_size: f32) -> Index { fn to_index(&self, _feature_size: f32) -> Index {
*self *self
} }
fn to_index_ceil(&self, _feature_size: f32) -> Index {
*self
}
fn to_index_floor(&self, _feature_size: f32) -> Index {
*self
}
fn from_meters(other: Meters, feature_size: f32) -> Self { fn from_meters(other: Meters, feature_size: f32) -> Self {
other.to_index(feature_size) other.to_index(feature_size)
} }

View File

@@ -327,6 +327,12 @@ impl<R: Real> Vec3<R> {
pub fn round(&self) -> Self { pub fn round(&self) -> Self {
Self::new(self.x().round(), self.y().round(), self.z().round()) Self::new(self.x().round(), self.y().round(), self.z().round())
} }
pub fn ceil(&self) -> Self {
Self::new(self.x().ceil(), self.y().ceil(), self.z().ceil())
}
pub fn floor(&self) -> Self {
Self::new(self.x().floor(), self.y().floor(), self.z().floor())
}
} }
impl<R> Into<(R, R, R)> for Vec3<R> { impl<R> Into<(R, R, R)> for Vec3<R> {

View File

@@ -494,9 +494,18 @@ impl<S: SampleableSim> Renderer<S> for Y4MRenderer {
struct MultiRendererElement<S> { struct MultiRendererElement<S> {
step_frequency: u64, step_frequency: u64,
step_limit: Option<u64>,
renderer: Box<dyn Renderer<S>>, renderer: Box<dyn Renderer<S>>,
} }
impl<S> MultiRendererElement<S> {
fn work_this_frame(&self, frame: u64) -> bool {
frame % self.step_frequency == 0 && match self.step_limit {
None => true,
Some(end) => frame < end,
}
}
}
pub struct MultiRenderer<S> { pub struct MultiRenderer<S> {
renderers: RwLock<Vec<MultiRendererElement<S>>>, renderers: RwLock<Vec<MultiRendererElement<S>>>,
@@ -514,18 +523,19 @@ impl<S> MultiRenderer<S> {
pub fn new() -> Self { pub fn new() -> Self {
Default::default() Default::default()
} }
pub fn push<R: Renderer<S> + 'static>(&self, renderer: R, step_frequency: u64) { pub fn push<R: Renderer<S> + 'static>(&self, renderer: R, step_frequency: u64, step_limit: Option<u64>) {
self.renderers.write().unwrap().push(MultiRendererElement { self.renderers.write().unwrap().push(MultiRendererElement {
step_frequency, step_frequency,
step_limit,
renderer: Box::new(renderer), renderer: Box::new(renderer),
}); });
} }
pub fn with<R: Renderer<S> + 'static>(self, renderer: R, step_frequency: u64) -> Self { pub fn with<R: Renderer<S> + 'static>(self, renderer: R, step_frequency: u64, step_limit: Option<u64>) -> Self {
self.push(renderer, step_frequency); self.push(renderer, step_frequency, step_limit);
self self
} }
pub fn any_work_for_frame(&self, frame: u64) -> bool { pub fn any_work_for_frame(&self, frame: u64) -> bool {
self.renderers.read().unwrap().iter().any(|m| frame % m.step_frequency == 0) self.renderers.read().unwrap().iter().any(|m| m.work_this_frame(frame))
} }
} }
@@ -541,7 +551,7 @@ impl<S: SampleableSim> Renderer<S> for MultiRenderer<S> {
fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) { fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
for r in &*self.renderers.read().unwrap() { for r in &*self.renderers.read().unwrap() {
if state.step_no() % r.step_frequency == 0 { if r.work_this_frame(state.step_no()) {
r.renderer.render_with_image(state, im, measurements, config); r.renderer.render_with_image(state, im, measurements, config);
} }
} }

View File

@@ -153,6 +153,12 @@ pub trait TimeVarying3: Sized {
} }
} }
impl TimeVarying1 for f32 {
fn at(&self, _t_sec: f32) -> f32 {
*self
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct Sinusoid<A> { pub struct Sinusoid<A> {
amp: A, amp: A,