diff --git a/crates/coremem/src/driver.rs b/crates/coremem/src/driver.rs index 381012c..b49e7b9 100644 --- a/crates/coremem/src/driver.rs +++ b/crates/coremem/src/driver.rs @@ -28,7 +28,7 @@ pub struct Driver { time_spent_prepping_render: Duration, time_spent_blocked_on_render: Duration, time_spent_rendering: Arc>, - measurements: Vec>, + measurements: Vec>>, stimuli: StimuliAdapter, start_time: Instant, last_diag_time: Instant, @@ -36,7 +36,7 @@ pub struct Driver { sim_end_time: Option, } -impl Driver { +impl Driver { pub fn new(state: S) -> Self { Self { state, @@ -65,7 +65,7 @@ impl Driver { self.stimuli.push(Box::new(s)) } - pub fn add_measurement(&mut self, m: Meas) { + pub fn add_measurement + 'static>(&mut self, m: Meas) { self.measurements.push(Arc::new(m)); } @@ -151,7 +151,7 @@ impl Driver { sender.send(()).unwrap(); trace!("render begin"); let start_time = Instant::now(); - let meas: Vec<&dyn AbstractMeasurement> = their_measurements.iter().map(|m| &**m).collect(); + let meas: Vec<&dyn AbstractMeasurement> = their_measurements.iter().map(|m| &**m).collect(); renderer.render(&their_state, &*meas, Default::default()); *time_spent_rendering.lock().unwrap() += start_time.elapsed(); trace!("render end"); diff --git a/crates/coremem/src/meas.rs b/crates/coremem/src/meas.rs index 4ef9102..5ac727e 100644 --- a/crates/coremem/src/meas.rs +++ b/crates/coremem/src/meas.rs @@ -5,13 +5,18 @@ use crate::sim::GenericSim; use indexmap::IndexMap; use serde::{Serialize, Deserialize}; -pub trait AbstractMeasurement: Send + Sync { - fn eval(&self, state: &dyn GenericSim) -> String; - fn key_value(&self, state: &dyn GenericSim) -> IndexMap; +pub trait AbstractMeasurement: Send + Sync { + fn eval(&self, state: &S) -> String; + fn key_value(&self, state: &S) -> IndexMap; } +pub fn as_dyn_measurements>(meas: &[M]) -> Vec<&dyn AbstractMeasurement> { + meas.into_iter().map(|m| m as &dyn AbstractMeasurement).collect() +} + + /// create one IndexMap out of several measurements -pub fn eval_multiple_kv(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) -> IndexMap { +pub fn eval_multiple_kv(state: &S, meas: &[&dyn AbstractMeasurement]) -> IndexMap { let mut r = IndexMap::new(); for m in meas { let other = m.key_value(state); @@ -20,7 +25,7 @@ pub fn eval_multiple_kv(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement r } -pub fn eval_to_vec(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) -> Vec { +pub fn eval_to_vec(state: &S, meas: &[&dyn AbstractMeasurement]) -> Vec { eval_multiple_kv(state, meas).into_iter().map(|(k, v)| { Evaluated::new(k, v) }).collect() @@ -29,11 +34,11 @@ pub fn eval_to_vec(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) -> #[derive(Clone, Serialize, Deserialize)] pub struct Time; -impl AbstractMeasurement for Time { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Time { + fn eval(&self, state: &S) -> String { format!("{:.3e}s (step {})", state.time(), state.step_no()) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { [ ("step".to_string(), state.step_no().to_string()), ("time".to_string(), state.time().to_string()), @@ -44,11 +49,11 @@ impl AbstractMeasurement for Time { #[derive(Clone, Serialize, Deserialize)] pub struct Meta; -impl AbstractMeasurement for Meta { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Meta { + fn eval(&self, state: &S) -> String { format!("{}x{}x{} feat: {:.1e}m", state.width(), state.height(), state.depth(), state.feature_size()) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { [ ("width".to_string(), state.width().to_string()), ("height".to_string(), state.height().to_string()), @@ -68,13 +73,19 @@ impl Evaluated { pub fn new, S2: Into>(key: S1, value: S2) -> Self { Self(key.into(), value.into()) } + pub fn key(&self) -> &str { + &*self.0 + } + pub fn value(&self) -> &str { + &*self.1 + } } -impl AbstractMeasurement for Evaluated { - fn eval(&self, _state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Evaluated { + fn eval(&self, _state: &S) -> String { self.1.clone() } - fn key_value(&self, _state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, _state: &S) -> IndexMap { [ (self.0.clone(), self.1.clone()), ].into_iter().collect() @@ -95,21 +106,21 @@ impl Volume { } } /// Returns the volume of the region, in units of um^3 - fn data(&self, state: &dyn GenericSim) -> f32 { + fn data(&self, state: &S) -> f32 { let feat_um = state.feature_size() as f64 * 1e6; (state.volume_of_region(&*self.region) as f64 * feat_um * feat_um * feat_um) as f32 } } -impl AbstractMeasurement for Volume { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Volume { + fn eval(&self, state: &S) -> String { format!("Vol({}): {:.2e} um^3", self.name, self.data(state), ) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { [ (format!("Vol({})", self.name), self.data(state).to_string()), ].into_iter().collect() @@ -129,7 +140,7 @@ impl Current { region: Box::new(r) } } - fn data(&self, state: &dyn GenericSim) -> (f32, Vec3) { + fn data(&self, state: &S) -> (f32, Vec3) { let FieldSample(volume, current_mag, current_vec) = state.map_sum_over_enumerated(&*self.region, |coord: Meters, _cell| { let current = state.current(coord); FieldSample(1, current.mag().cast(), current.cast()) @@ -185,15 +196,15 @@ impl std::iter::Sum for FieldSamples<[FieldSample; 3]> { } } -impl AbstractMeasurement for Current { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Current { + fn eval(&self, state: &S) -> String { let (mean_current_mag, mean_current_vec) = self.data(state); format!("I/cell({}): {:.2e} {:.2e}", self.name, mean_current_mag, mean_current_vec) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let (mean_current_mag, mean_current_vec) = self.data(state); [ (format!("Imag/cell({})", self.name), mean_current_mag.to_string()), @@ -216,7 +227,7 @@ impl CurrentLoop { region: r, } } - fn data(&self, state: &dyn GenericSim) -> f32 { + fn data(&self, state: &S) -> f32 { let FieldSample(volume, directed_current, _current_vec) = state.map_sum_over_enumerated(&self.region, |coord: Meters, _cell| { let normal = self.region.axis(); let to_coord = *coord - *self.region.center(); @@ -232,12 +243,12 @@ impl CurrentLoop { } } -impl AbstractMeasurement for CurrentLoop { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for CurrentLoop { + fn eval(&self, state: &S) -> String { let cross_sectional_current = self.data(state); format!("I({}): {:.2e}", self.name, cross_sectional_current) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let cross_sectional_current = self.data(state); [ (format!("I({})", self.name), cross_sectional_current.to_string()), @@ -260,7 +271,7 @@ impl MagneticLoop { region: r, } } - fn data(&self, state: &dyn GenericSim) -> (f32, f32, f32) { + fn data(&self, state: &S) -> (f32, f32, f32) { let FieldSamples([ FieldSample(volume, directed_m, _m_vec), FieldSample(_, directed_b, _b_vec), @@ -300,8 +311,8 @@ impl MagneticLoop { } } -impl AbstractMeasurement for MagneticLoop { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for MagneticLoop { + fn eval(&self, state: &S) -> String { let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state); format!( "M({}): {:.2e}; B({}): {:.2e}; H({}): {:.2e}", @@ -310,7 +321,7 @@ impl AbstractMeasurement for MagneticLoop { self.name, mean_directed_h, ) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state); [ (format!("M({})", self.name), mean_directed_m.to_string()), @@ -334,7 +345,7 @@ impl MagneticFlux { region: Box::new(r) } } - fn data(&self, state: &dyn GenericSim) -> Vec3 { + fn data(&self, state: &S) -> Vec3 { let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| { let b = cell.b(); let mag = b.mag(); @@ -345,12 +356,12 @@ impl MagneticFlux { } } -impl AbstractMeasurement for MagneticFlux { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for MagneticFlux { + fn eval(&self, state: &S) -> String { let mean_mag = self.data(state); format!("Bavg({}): {:.2e}", self.name, mean_mag) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let mean_mag = self.data(state); [ (format!("Bavg({})", self.name), mean_mag.to_string()), @@ -372,7 +383,7 @@ impl Magnetization { region: Box::new(r) } } - fn data(&self, state: &dyn GenericSim) -> Vec3 { + fn data(&self, state: &S) -> Vec3 { let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| { let m = cell.m(); let mag = m.mag(); @@ -383,12 +394,12 @@ impl Magnetization { } } -impl AbstractMeasurement for Magnetization { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Magnetization { + fn eval(&self, state: &S) -> String { let mean_mag = self.data(state); format!("Mavg({}): {:.2e}", self.name, mean_mag) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let mean_mag = self.data(state); [ (format!("Mavg({})", self.name), mean_mag.to_string()), @@ -404,12 +415,12 @@ fn loc(v: Meters) -> String { #[derive(Clone, Serialize, Deserialize)] pub struct MagnetizationAt(pub Meters); -impl AbstractMeasurement for MagnetizationAt { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for MagnetizationAt { + fn eval(&self, state: &S) -> String { let m = state.sample(self.0).m(); format!("M{}: {:.2e}", loc(self.0), m) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let m = state.sample(self.0).m(); [ (format!("M{}", loc(self.0)), m.to_string()), @@ -421,12 +432,12 @@ impl AbstractMeasurement for MagnetizationAt { #[derive(Clone, Serialize, Deserialize)] pub struct MagneticFluxAt(pub Meters); -impl AbstractMeasurement for MagneticFluxAt { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for MagneticFluxAt { + fn eval(&self, state: &S) -> String { let b = state.sample(self.0).b(); format!("B{}: {:.2e}", loc(self.0), b) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let b = state.sample(self.0).b(); [ (format!("B{}", loc(self.0)), b.to_string()), @@ -438,12 +449,12 @@ impl AbstractMeasurement for MagneticFluxAt { #[derive(Clone, Serialize, Deserialize)] pub struct MagneticStrengthAt(pub Meters); -impl AbstractMeasurement for MagneticStrengthAt { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for MagneticStrengthAt { + fn eval(&self, state: &S) -> String { let h = state.sample(self.0).h(); format!("H{}: {:.2e}", loc(self.0), h) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let h = state.sample(self.0).h(); [ (format!("H{}", loc(self.0)), h.to_string()), @@ -454,12 +465,12 @@ impl AbstractMeasurement for MagneticStrengthAt { #[derive(Clone, Serialize, Deserialize)] pub struct ElectricField(pub Meters); -impl AbstractMeasurement for ElectricField { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for ElectricField { + fn eval(&self, state: &S) -> String { let e = state.sample(self.0).e(); format!("E{}: {:.2e}", loc(self.0), e) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let e = state.sample(self.0).e(); [ (format!("E{}", loc(self.0)), e.to_string()), @@ -483,7 +494,7 @@ impl Energy { region: Box::new(region), } } - fn data(&self, state: &dyn GenericSim) -> f32 { + fn data(&self, state: &S) -> f32 { // Potential energy stored in a E/M field: // https://en.wikipedia.org/wiki/Magnetic_energy // https://en.wikipedia.org/wiki/Electric_potential_energy#Energy_stored_in_an_electrostatic_field_distribution @@ -500,12 +511,12 @@ impl Energy { } } -impl AbstractMeasurement for Energy { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Energy { + fn eval(&self, state: &S) -> String { let e = self.data(state); format!("U({}): {:.2e}", self.name, e) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let e = self.data(state); [ (format!("U({})", self.name), e.to_string()), @@ -529,7 +540,7 @@ impl Power { region: Box::new(region), } } - fn data(&self, state: &dyn GenericSim) -> f32 { + fn data(&self, state: &S) -> f32 { // Power is P = IV = A*J*V = L^2*J.(LE) = L^3 J.E // where L is feature size. #[allow(non_snake_case)] @@ -541,12 +552,12 @@ impl Power { } } -impl AbstractMeasurement for Power { - fn eval(&self, state: &dyn GenericSim) -> String { +impl AbstractMeasurement for Power { + fn eval(&self, state: &S) -> String { let power = self.data(state); format!("P({}): {:.2e}", self.name, power) } - fn key_value(&self, state: &dyn GenericSim) -> IndexMap { + fn key_value(&self, state: &S) -> IndexMap { let power = self.data(state); [ (format!("P({})", self.name), power.to_string()), diff --git a/crates/coremem/src/render.rs b/crates/coremem/src/render.rs index 1ee4f1c..30d61a1 100644 --- a/crates/coremem/src/render.rs +++ b/crates/coremem/src/render.rs @@ -129,20 +129,22 @@ impl RenderConfig { struct RenderSteps<'a, S> { im: RgbImage, sim: &'a S, - meas: &'a [&'a dyn AbstractMeasurement], + meas: &'a [&'a dyn AbstractMeasurement], /// Simulation z coordinate to sample z: u32, } impl<'a, S: GenericSim> RenderSteps<'a, S> { + // TODO: this could probably be a single measurement, and we just let collections of + // measurements also behave as measurements /// Render using default configuration constants - fn render(state: &'a S, measurements: &'a [&'a dyn AbstractMeasurement], z: u32) -> RgbImage { + fn render(state: &'a S, measurements: &'a [&'a dyn AbstractMeasurement], z: u32) -> RgbImage { Self::render_configured(state, measurements, z, (640, 480), RenderConfig::default()) } /// Render, controlling things like the size. fn render_configured( state: &'a S, - measurements: &'a [&'a dyn AbstractMeasurement], + measurements: &'a [&'a dyn AbstractMeasurement], z: u32, max_size: (u32, u32), config: RenderConfig, @@ -178,7 +180,7 @@ impl<'a, S: GenericSim> RenderSteps<'a, S> { me.render_measurements(); me.im } - fn new(sim: &'a S, meas: &'a [&'a dyn AbstractMeasurement], width: u32, height: u32, z: u32) -> Self { + fn new(sim: &'a S, meas: &'a [&'a dyn AbstractMeasurement], width: u32, height: u32, z: u32) -> Self { RenderSteps { im: RgbImage::new(width, height), sim, @@ -340,25 +342,25 @@ impl ImageRenderExt for RgbImage { } pub trait Renderer: Send + Sync { - fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig); + fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig); // { // self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements); // } - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig); + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig); /// Not intended to be called directly by users; implement this if you want the image to be /// computed using default settings and you just manage where to display/save it. - fn render_with_image(&self, state: &S, _im: &RgbImage, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_with_image(&self, state: &S, _im: &RgbImage, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { self.render(state, measurements, config); } } fn default_render_z_slice>( - me: &R, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig, + me: &R, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig, ) { me.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements, config); } fn default_render>( - me: &R, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig + me: &R, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig ) { me.render_z_slice(state, state.depth() / 2, measurements, config); } @@ -366,7 +368,7 @@ fn default_render>( // pub struct NumericTermRenderer; // // impl Renderer for NumericTermRenderer { -// fn render(&mut self, state: &SimSnapshot, _measurements: &[&dyn AbstractMeasurement]) { +// fn render(&mut self, state: &SimSnapshot, _measurements: &[&dyn AbstractMeasurement]) { // for y in 0..state.height() { // for x in 0..state.width() { // let cell = state.get((x, y).into()); @@ -387,14 +389,14 @@ fn default_render>( pub struct ColorTermRenderer; impl Renderer for ColorTermRenderer { - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render(self, state, measurements, config) } fn render_z_slice( &self, state: &S, z: u32, - measurements: &[&dyn AbstractMeasurement], + measurements: &[&dyn AbstractMeasurement], config: RenderConfig, ) { let (max_w, mut max_h) = crossterm::terminal::size().unwrap(); @@ -449,13 +451,13 @@ impl Y4MRenderer { } impl Renderer for Y4MRenderer { - fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render_z_slice(self, state, z, measurements, config) } - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render(self, state, measurements, config) } - fn render_with_image(&self, _state: &S, im: &RgbImage, _meas: &[&dyn AbstractMeasurement], _config: RenderConfig) { + fn render_with_image(&self, _state: &S, im: &RgbImage, _meas: &[&dyn AbstractMeasurement], _config: RenderConfig) { { let mut enc = self.encoder.lock().unwrap(); if enc.is_none() { @@ -541,16 +543,16 @@ impl MultiRenderer { } impl Renderer for MultiRenderer { - fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render_z_slice(self, state, z, measurements, config) } - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { if self.renderers.read().unwrap().len() != 0 { self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2), measurements, config); } } - fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { for r in &*self.renderers.read().unwrap() { if r.work_this_frame(state.step_no()) { r.renderer.render_with_image(state, im, measurements, config); @@ -605,10 +607,10 @@ impl SerializerRenderer { } impl SerializerRenderer { - fn serialize(&self, state: &S, measurements: &[&dyn AbstractMeasurement]) { + fn serialize(&self, state: &S, measurements: Vec) { let frame = SerializedFrame { state, - measurements: meas::eval_to_vec(state, measurements), + measurements, }; let name = self.fmt_str.replace("{step_no}", &*frame.state.step_no().to_string()); let out = BufWriter::new(File::create(name).unwrap()); @@ -623,14 +625,14 @@ impl SerializerRenderer { } impl Renderer for SerializerRenderer { - fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render_z_slice(self, state, z, measurements, config) } - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], _config: RenderConfig) { + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], _config: RenderConfig) { if self.prefer_static { - self.serialize(&state.to_static(), measurements); + self.serialize(&state.to_static(), meas::eval_to_vec(state, measurements)); } else { - self.serialize(state, measurements); + self.serialize(state, meas::eval_to_vec(state, measurements)); } } } @@ -666,10 +668,10 @@ impl CsvRenderer { } impl Renderer for CsvRenderer { - fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { + fn render_z_slice(&self, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { default_render_z_slice(self, state, z, measurements, config) } - fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], _config: RenderConfig) { + fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], _config: RenderConfig) { let row = meas::eval_multiple_kv(state, measurements); let step = state.step_no(); let mut lock = self.state.lock().unwrap(); diff --git a/crates/coremem/src/sim/legacy/mod.rs b/crates/coremem/src/sim/legacy/mod.rs index 63aa547..ff470fa 100644 --- a/crates/coremem/src/sim/legacy/mod.rs +++ b/crates/coremem/src/sim/legacy/mod.rs @@ -1201,7 +1201,7 @@ mod test { assert_vec3_eq(actual_df_dt, df_dt(tm)); } - fn energy(s: &dyn GenericSim) -> f32 { + fn energy(s: &S) -> f32 { 0.5 * s.feature_volume() * s.map_sum_enumerated(|_pos: Index, cell| { // println!("{}: {}", _pos, cell.e()); cell.e().mag_sq().to_f64() diff --git a/crates/coremem/src/sim/mod.rs b/crates/coremem/src/sim/mod.rs index 3326a77..3a184eb 100644 --- a/crates/coremem/src/sim/mod.rs +++ b/crates/coremem/src/sim/mod.rs @@ -217,77 +217,6 @@ impl CellStateWithM { } } -impl<'a> dyn GenericSim + 'a { - pub fn get(&self, at: C) -> Sample { - self.sample(at.to_meters(self.feature_size())) - } - - /// Apply `F` to each Cell, and sum the results. - pub fn map_sum(&self, f: F) -> Ret - where - F: Fn(&Sample) -> Ret + Sync, - Ret: Sum + Send, - { - self.map_sum_enumerated(|_at: Index, cell| f(cell)) - } - - pub fn map_sum_enumerated(&self, f: F) -> Ret - where C: Coord, - F: Fn(C, &Sample) -> Ret + Sync, - Ret: Sum + Send, - { - let (w, h, d) = (self.width(), self.height(), self.depth()); - (0..d).into_par_iter().map( - |z| (0..h).into_par_iter().map_with(z, - |&mut z, y| (0..w).into_par_iter().map_with((z, y), - |&mut (z, y), x| - { - let at = Index(Vec3u::new(x, y, z)); - f(C::from_index(at, self.feature_size()), &self.get(at)) - }))).flatten().flatten().sum() - } - - pub fn volume_of_region(&self, region: &R) -> u32 { - self.map_sum_over(region, |_| 1) - } - - /// Apply `F` to each Cell, and sum the results. - pub fn map_sum_over(&self, region: &Reg, f: F) -> Ret - where - F: Fn(&Sample) -> Ret + Sync, - Ret: Sum + Default + Send, - Reg: Region + ?Sized - { - self.map_sum_over_enumerated(region, |_at: Index, cell| f(cell)) - } - - pub fn map_sum_over_enumerated(&self, region: &Reg, f: F) -> Ret - where C: Coord, - F: Fn(C, &Sample) -> Ret + Sync, - Ret: Sum + Default + Send, - Reg: Region + ?Sized, - { - let (w, h, d) = (self.width(), self.height(), self.depth()); - (0..d).into_par_iter().map( - |z| (0..h).into_par_iter().map_with(z, - |&mut z, y| (0..w).into_par_iter().map_with((z, y), - |&mut (z, y), x| - { - let at = Index(Vec3u::new(x, y, z)); - let meters = at.to_meters(self.feature_size()); - if region.contains(meters) { - f(C::from_index(at, self.feature_size()), &self.get(at)) - } else { - Default::default() - } - }))).flatten().flatten().sum() - } - - pub fn current(&self, c: C) -> Vec3 { - self.get(c).current_density() * self.feature_size() * self.feature_size() - } -} - // TODO: the Send/Sync bounds here could be removed with some refactoring pub trait GenericSim: Send + Sync { fn meta(&self) -> SimMeta; @@ -327,4 +256,73 @@ pub trait GenericSim: Send + Sync { fn time(&self) -> f32 { self.timestep() * self.step_no() as f32 } + + fn get(&self, at: C) -> Sample { + self.sample(at.to_meters(self.feature_size())) + } + + /// Apply `F` to each Cell, and sum the results. + fn map_sum(&self, f: F) -> Ret + where + F: Fn(&Sample) -> Ret + Sync, + Ret: Sum + Send, + { + self.map_sum_enumerated(|_at: Index, cell| f(cell)) + } + + fn map_sum_enumerated(&self, f: F) -> Ret + where C: Coord, + F: Fn(C, &Sample) -> Ret + Sync, + Ret: Sum + Send, + { + let (w, h, d) = (self.width(), self.height(), self.depth()); + (0..d).into_par_iter().map( + |z| (0..h).into_par_iter().map_with(z, + |&mut z, y| (0..w).into_par_iter().map_with((z, y), + |&mut (z, y), x| + { + let at = Index(Vec3u::new(x, y, z)); + f(C::from_index(at, self.feature_size()), &self.get(at)) + }))).flatten().flatten().sum() + } + + fn volume_of_region(&self, region: &R) -> u32 { + self.map_sum_over(region, |_| 1) + } + + /// Apply `F` to each Cell, and sum the results. + fn map_sum_over(&self, region: &Reg, f: F) -> Ret + where + F: Fn(&Sample) -> Ret + Sync, + Ret: Sum + Default + Send, + Reg: Region + ?Sized + { + self.map_sum_over_enumerated(region, |_at: Index, cell| f(cell)) + } + + fn map_sum_over_enumerated(&self, region: &Reg, f: F) -> Ret + where C: Coord, + F: Fn(C, &Sample) -> Ret + Sync, + Ret: Sum + Default + Send, + Reg: Region + ?Sized, + { + let (w, h, d) = (self.width(), self.height(), self.depth()); + (0..d).into_par_iter().map( + |z| (0..h).into_par_iter().map_with(z, + |&mut z, y| (0..w).into_par_iter().map_with((z, y), + |&mut (z, y), x| + { + let at = Index(Vec3u::new(x, y, z)); + let meters = at.to_meters(self.feature_size()); + if region.contains(meters) { + f(C::from_index(at, self.feature_size()), &self.get(at)) + } else { + Default::default() + } + }))).flatten().flatten().sum() + } + + fn current(&self, c: C) -> Vec3 { + self.get(c).current_density() * self.feature_size() * self.feature_size() + } } diff --git a/crates/coremem/src/sim/spirv/mod.rs b/crates/coremem/src/sim/spirv/mod.rs index 23836ee..b5a5d4f 100644 --- a/crates/coremem/src/sim/spirv/mod.rs +++ b/crates/coremem/src/sim/spirv/mod.rs @@ -272,20 +272,19 @@ where mod test { use super::*; use crate::real::ToFloat as _; - use crate::sim::GenericSim; use crate::sim::legacy::{self, SimState}; use crate::mat::{self, AnisomorphicConductor}; - fn mean_magnitude_e(sim: &dyn GenericSim) -> f32 { + fn mean_magnitude_e(sim: &S) -> f32 { (sim.map_sum_enumerated(|_pos: Index, cell| { cell.e().mag().to_f64() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() } - fn mean_magnitude_h(sim: &dyn GenericSim) -> f32 { + fn mean_magnitude_h(sim: &S) -> f32 { (sim.map_sum_enumerated(|_pos: Index, cell| { cell.h().mag().to_f64() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() } - fn mean_magnitude_m(sim: &dyn GenericSim) -> f32 { + fn mean_magnitude_m(sim: &S) -> f32 { (sim.map_sum_enumerated(|_pos: Index, cell| { cell.m().mag().to_f64() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() @@ -302,8 +301,8 @@ mod test { for y in 0..dim.y() { for x in 0..dim.x() { let idx = Index::new(x, y, z); - let real_cell = (real_state as &dyn GenericSim).get(idx); - let ref_cell = (ref_state as &dyn GenericSim).get(idx); + let real_cell = real_state.get(idx); + let ref_cell = ref_state.get(idx); let diff_e = real_cell.e() - ref_cell.e(); let diff_h = real_cell.h() - ref_cell.h(); diff --git a/crates/post/src/bin/csv.rs b/crates/post/src/bin/csv.rs index 87ae481..d9a99f3 100644 --- a/crates/post/src/bin/csv.rs +++ b/crates/post/src/bin/csv.rs @@ -14,18 +14,14 @@ fn main() { let mut cache = LoaderCache::new(loader, 2, 2); let mut frame = cache.load_first(); - for meas in frame.dyn_measurements() { - for key in meas.key_value(&**frame).keys() { - print!("\"{}\",", key); - } + for meas in frame.measurements() { + print!("\"{}\",", meas.key()); } println!(""); loop { - for meas in frame.dyn_measurements() { - for value in meas.key_value(&**frame).values() { - print!("\"{}\",", value); - } + for meas in frame.measurements() { + print!("\"{}\",", meas.value()); } println!(""); diff --git a/crates/post/src/lib.rs b/crates/post/src/lib.rs index b68fe96..c6645f5 100644 --- a/crates/post/src/lib.rs +++ b/crates/post/src/lib.rs @@ -1,5 +1,5 @@ //! Post-processing tools -use coremem::meas::{self, AbstractMeasurement}; +use coremem::meas; use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame}; use coremem::sim::{GenericSim, StaticSim}; @@ -40,9 +40,6 @@ impl Frame { pub fn measurements(&self) -> &[meas::Evaluated] { &*self.data.measurements } - pub fn dyn_measurements(&self) -> Vec<&dyn AbstractMeasurement> { - self.measurements().into_iter().map(|m| m as &dyn AbstractMeasurement).collect() - } pub fn path(&self) -> &Path { &*self.path } @@ -277,7 +274,10 @@ impl Viewer { } pub fn render(&self) { self.renderer.render_z_slice( - &**self.viewing, self.z, &*self.viewing.dyn_measurements(), self.render_config + &**self.viewing, + self.z, + &*meas::as_dyn_measurements(self.viewing.measurements()), + self.render_config, ); } pub fn render_config(&mut self) -> &mut RenderConfig {