Make Current measurement serializable
Note that this REALLY slows it down, since it forces the Region to be Boxed. It might make sense at some point to consider introducing a RegionBitmap type. Maybe keep the original Region type -- for serializing -- but cache a Bitmap version where perf matters more.
This commit is contained in:
@@ -14,9 +14,9 @@ fn main() {
|
|||||||
let ferro_minor = 40e-6;
|
let ferro_minor = 40e-6;
|
||||||
let wire_minor = 20e-6;
|
let wire_minor = 20e-6;
|
||||||
let wire_major = 80e-6;
|
let wire_major = 80e-6;
|
||||||
let peak_current = 2e3;
|
let peak_current = 2e4;
|
||||||
let current_duration = 1e-9; // half-wavelength of the sine wave
|
let current_duration = 1e-9; // half-wavelength of the sine wave
|
||||||
let conductivity = 1.0e5;
|
let conductivity = 1.0e9;
|
||||||
|
|
||||||
let from_m = |m| (m/feat_size) as u32;
|
let from_m = |m| (m/feat_size) as u32;
|
||||||
let m_to_um = |px| (px * 1e6) as u32;
|
let m_to_um = |px| (px * 1e6) as u32;
|
||||||
@@ -29,10 +29,10 @@ fn main() {
|
|||||||
let size_px = Index((width_px, width_px, depth_px).into());
|
let size_px = Index((width_px, width_px, depth_px).into());
|
||||||
let mut driver = Driver::new(size_px, feat_size);
|
let mut driver = Driver::new(size_px, feat_size);
|
||||||
driver.set_steps_per_frame(120);
|
driver.set_steps_per_frame(120);
|
||||||
let base = "wrapped_torus-2";
|
let base = "wrapped_torus-3";
|
||||||
let ferro_region = Torus::new_xy(Meters((half_width, half_width, half_depth).into()), ferro_major, ferro_minor);
|
let ferro_region = Torus::new_xy(Meters((half_width, half_width, half_depth).into()), ferro_major, ferro_minor);
|
||||||
let drive_region = Torus::new_xy(Meters((half_width - ferro_major, half_width, half_depth).into()), wire_major, wire_minor);
|
let drive_region = Torus::new_xz(Meters((half_width - ferro_major, half_width, half_depth).into()), wire_major, wire_minor);
|
||||||
let sense_region = Torus::new_xy(Meters((half_width + ferro_major, half_width, half_depth).into()), wire_major, wire_minor);
|
let sense_region = Torus::new_xz(Meters((half_width + ferro_major, half_width, half_depth).into()), wire_major, wire_minor);
|
||||||
|
|
||||||
driver.fill_region(&ferro_region, mat::db::ferroxcube_3r1());
|
driver.fill_region(&ferro_region, mat::db::ferroxcube_3r1());
|
||||||
driver.fill_region(&drive_region, mat::Static::conductor(conductivity).into());
|
driver.fill_region(&drive_region, mat::Static::conductor(conductivity).into());
|
||||||
@@ -45,10 +45,12 @@ fn main() {
|
|||||||
|
|
||||||
driver.add_stimulus(Stimulus::new(
|
driver.add_stimulus(Stimulus::new(
|
||||||
Sphere::new(
|
Sphere::new(
|
||||||
Meters((half_width - wire_major, half_width, half_depth).into()),
|
Meters((half_width - ferro_major + wire_major, half_width, half_depth).into()),
|
||||||
wire_minor),
|
wire_minor),
|
||||||
Sinusoid::from_wavelength(Vec3::new(0.0, 0.0, peak_current), current_duration * 2.0)
|
Sinusoid::from_wavelength(Vec3::new(0.0, 0.0, peak_current), current_duration * 2.0)
|
||||||
));
|
));
|
||||||
|
driver.add_measurement(meas::Current::new("sense", sense_region.clone()));
|
||||||
|
driver.add_measurement(meas::Current::new("drive", drive_region.clone()));
|
||||||
// TODO: simulate current in the drive element
|
// TODO: simulate current in the drive element
|
||||||
//driver.add_stimulus(Stimulus::new(
|
//driver.add_stimulus(Stimulus::new(
|
||||||
// conductor_region.clone(),
|
// conductor_region.clone(),
|
||||||
|
@@ -7,6 +7,7 @@ pub use vec::{Vec2, Vec3};
|
|||||||
pub use vecu::Vec3u;
|
pub use vecu::Vec3u;
|
||||||
|
|
||||||
use crate::flt::{Flt, Real};
|
use crate::flt::{Flt, Real};
|
||||||
|
use dyn_clone::{self, DynClone};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
@@ -182,9 +183,11 @@ impl Polygon2d {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Region {
|
#[typetag::serde(tag = "type")]
|
||||||
|
pub trait Region: Send + DynClone {
|
||||||
fn contains(&self, p: Meters) -> bool;
|
fn contains(&self, p: Meters) -> bool;
|
||||||
}
|
}
|
||||||
|
dyn_clone::clone_trait_object!(Region);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Serialize, Deserialize)]
|
||||||
pub struct CylinderZ {
|
pub struct CylinderZ {
|
||||||
@@ -202,6 +205,7 @@ impl CylinderZ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[typetag::serde]
|
||||||
impl Region for CylinderZ {
|
impl Region for CylinderZ {
|
||||||
fn contains(&self, p: Meters) -> bool {
|
fn contains(&self, p: Meters) -> bool {
|
||||||
p.xy().distance_sq(self.center) <= (self.radius * self.radius).into()
|
p.xy().distance_sq(self.center) <= (self.radius * self.radius).into()
|
||||||
@@ -242,6 +246,7 @@ impl Torus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[typetag::serde]
|
||||||
impl Region for Torus {
|
impl Region for Torus {
|
||||||
fn contains(&self, p: Meters) -> bool {
|
fn contains(&self, p: Meters) -> bool {
|
||||||
// a torus is the set of all points < distance `r` from the circle of radius `R`,
|
// a torus is the set of all points < distance `r` from the circle of radius `R`,
|
||||||
@@ -273,6 +278,7 @@ impl Sphere {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[typetag::serde]
|
||||||
impl Region for Sphere {
|
impl Region for Sphere {
|
||||||
fn contains(&self, p: Meters) -> bool {
|
fn contains(&self, p: Meters) -> bool {
|
||||||
(*p - *self.center).mag() < self.rad.into_inner()
|
(*p - *self.center).mag() < self.rad.into_inner()
|
||||||
|
57
src/meas.rs
57
src/meas.rs
@@ -1,12 +1,13 @@
|
|||||||
use crate::flt::Flt;
|
use crate::flt::Flt;
|
||||||
use crate::geom::{Meters, Region};
|
use crate::geom::{Meters, Region, Vec3};
|
||||||
use crate::mat::Material as _;
|
use crate::mat::Material as _;
|
||||||
use crate::sim::{Cell, GenericSim};
|
use crate::sim::{Cell, GenericSim};
|
||||||
use dyn_clone::{self, DynClone};
|
use dyn_clone::{self, DynClone};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use std::fmt::Display;
|
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
|
|
||||||
|
// TODO: remove this Clone and Send requirement? Have Measurements be shared by-reference across
|
||||||
|
// threads? i.e. Sync, and no Clone
|
||||||
#[typetag::serde(tag = "type")]
|
#[typetag::serde(tag = "type")]
|
||||||
pub trait AbstractMeasurement: Send + DynClone {
|
pub trait AbstractMeasurement: Send + DynClone {
|
||||||
fn eval(&self, state: &dyn GenericSim) -> String;
|
fn eval(&self, state: &dyn GenericSim) -> String;
|
||||||
@@ -49,8 +50,7 @@ impl AbstractMeasurement for Label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sum_over_region<T: Default + Sum<T>, R: Region, F: Fn(Meters, &Cell) -> T>(state: &dyn GenericSim, r: &R, f: F) -> T {
|
fn sum_over_region<T: Default + Sum<T>, F: Fn(Meters, &Cell) -> T>(state: &dyn GenericSim, r: &dyn Region, f: F) -> T {
|
||||||
// TODO: z coordinate?
|
|
||||||
state.map_sum_enumerated(|coord, cell| {
|
state.map_sum_enumerated(|coord, cell| {
|
||||||
if r.contains(coord) {
|
if r.contains(coord) {
|
||||||
f(coord, cell)
|
f(coord, cell)
|
||||||
@@ -61,16 +61,49 @@ fn sum_over_region<T: Default + Sum<T>, R: Region, F: Fn(Meters, &Cell) -> T>(st
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Current<R>(pub R);
|
pub struct Current {
|
||||||
|
name: String,
|
||||||
|
region: Box<dyn Region>,
|
||||||
|
}
|
||||||
|
|
||||||
#[typetag::serialize]
|
impl Current {
|
||||||
impl<R: Region + Clone + Display + Send + Sync + Serialize + Deserialize<'static>> AbstractMeasurement for Current<R> {
|
pub fn new<R: Region + 'static>(name: &str, r: R) -> Self {
|
||||||
fn eval(&self, state: &dyn GenericSim) -> String {
|
Self {
|
||||||
let current = sum_over_region(state, &self.0, |coord, _cell| state.current(coord));
|
name: name.into(),
|
||||||
format!("I({}): ({:.2e}, {:.2e}, {:.2e})", self.0, current.x(), current.y(), current.z())
|
region: Box::new(r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn typetag_deserialize(&self) {
|
}
|
||||||
todo!()
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct CurrentSample(usize, Flt, Vec3);
|
||||||
|
impl std::iter::Sum for CurrentSample {
|
||||||
|
fn sum<I>(iter: I) -> Self
|
||||||
|
where I: Iterator<Item = Self>
|
||||||
|
{
|
||||||
|
let mut s = CurrentSample::default();
|
||||||
|
for CurrentSample(a, b, c) in iter {
|
||||||
|
s = CurrentSample(s.0 + a, s.1 + b, s.2 + c)
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[typetag::serde]
|
||||||
|
impl AbstractMeasurement for Current {
|
||||||
|
fn eval(&self, state: &dyn GenericSim) -> String {
|
||||||
|
let CurrentSample(volume, current_mag, current_new) = sum_over_region(state, &*self.region, |coord, _cell| {
|
||||||
|
let current = state.current(coord);
|
||||||
|
CurrentSample(1, current.mag(), current)
|
||||||
|
});
|
||||||
|
let mean_current_mag = current_mag / (volume as Flt);
|
||||||
|
let mean_current_vec = current_new / (volume as Flt);
|
||||||
|
format!("I({}): {:.2e}, avg ({:.2e}, {:.2e}, {:.2e})",
|
||||||
|
self.name,
|
||||||
|
mean_current_mag,
|
||||||
|
mean_current_vec.x(),
|
||||||
|
mean_current_vec.y(),
|
||||||
|
mean_current_vec.z())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -304,6 +304,8 @@ impl Renderer for ColorTermRenderer {
|
|||||||
|
|
||||||
stdout.queue(PrintStyledContent(style(format!("z: {}", z)))).unwrap();
|
stdout.queue(PrintStyledContent(style(format!("z: {}", z)))).unwrap();
|
||||||
for m in measurements {
|
for m in measurements {
|
||||||
|
// Measurements can be slow to compute
|
||||||
|
stdout.flush().unwrap();
|
||||||
let meas_string = m.eval(state);
|
let meas_string = m.eval(state);
|
||||||
stdout.queue(cursor::MoveDown(1)).unwrap();
|
stdout.queue(cursor::MoveDown(1)).unwrap();
|
||||||
stdout.queue(cursor::MoveToColumn(1)).unwrap();
|
stdout.queue(cursor::MoveToColumn(1)).unwrap();
|
||||||
|
Reference in New Issue
Block a user