de-virtualize GenericSim

this should let us fold the GenericSim and MaterialSim traits together.
This commit is contained in:
2022-07-28 22:22:07 -07:00
parent 2d1a15eabc
commit 71ab89c4c9
8 changed files with 185 additions and 179 deletions

View File

@@ -28,7 +28,7 @@ pub struct Driver<S> {
time_spent_prepping_render: Duration, time_spent_prepping_render: Duration,
time_spent_blocked_on_render: Duration, time_spent_blocked_on_render: Duration,
time_spent_rendering: Arc<Mutex<Duration>>, time_spent_rendering: Arc<Mutex<Duration>>,
measurements: Vec<Arc<dyn AbstractMeasurement>>, measurements: Vec<Arc<dyn AbstractMeasurement<S>>>,
stimuli: StimuliAdapter, stimuli: StimuliAdapter,
start_time: Instant, start_time: Instant,
last_diag_time: Instant, last_diag_time: Instant,
@@ -36,7 +36,7 @@ pub struct Driver<S> {
sim_end_time: Option<Frame>, sim_end_time: Option<Frame>,
} }
impl<S> Driver<S> { impl<S: GenericSim> Driver<S> {
pub fn new(state: S) -> Self { pub fn new(state: S) -> Self {
Self { Self {
state, state,
@@ -65,7 +65,7 @@ impl<S> Driver<S> {
self.stimuli.push(Box::new(s)) self.stimuli.push(Box::new(s))
} }
pub fn add_measurement<Meas: AbstractMeasurement + 'static>(&mut self, m: Meas) { pub fn add_measurement<Meas: AbstractMeasurement<S> + 'static>(&mut self, m: Meas) {
self.measurements.push(Arc::new(m)); self.measurements.push(Arc::new(m));
} }
@@ -151,7 +151,7 @@ impl<S: MaterialSim + Clone + Default + Send + Sync + 'static> Driver<S> {
sender.send(()).unwrap(); sender.send(()).unwrap();
trace!("render begin"); trace!("render begin");
let start_time = Instant::now(); let start_time = Instant::now();
let meas: Vec<&dyn AbstractMeasurement> = their_measurements.iter().map(|m| &**m).collect(); let meas: Vec<&dyn AbstractMeasurement<S>> = their_measurements.iter().map(|m| &**m).collect();
renderer.render(&their_state, &*meas, Default::default()); renderer.render(&their_state, &*meas, Default::default());
*time_spent_rendering.lock().unwrap() += start_time.elapsed(); *time_spent_rendering.lock().unwrap() += start_time.elapsed();
trace!("render end"); trace!("render end");

View File

@@ -5,13 +5,18 @@ use crate::sim::GenericSim;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
pub trait AbstractMeasurement: Send + Sync { pub trait AbstractMeasurement<S>: Send + Sync {
fn eval(&self, state: &dyn GenericSim) -> String; fn eval(&self, state: &S) -> String;
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String>; fn key_value(&self, state: &S) -> IndexMap<String, String>;
} }
pub fn as_dyn_measurements<S, M: AbstractMeasurement<S>>(meas: &[M]) -> Vec<&dyn AbstractMeasurement<S>> {
meas.into_iter().map(|m| m as &dyn AbstractMeasurement<S>).collect()
}
/// create one IndexMap out of several measurements /// create one IndexMap out of several measurements
pub fn eval_multiple_kv(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) -> IndexMap<String, String> { pub fn eval_multiple_kv<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> IndexMap<String, String> {
let mut r = IndexMap::new(); let mut r = IndexMap::new();
for m in meas { for m in meas {
let other = m.key_value(state); let other = m.key_value(state);
@@ -20,7 +25,7 @@ pub fn eval_multiple_kv(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement
r r
} }
pub fn eval_to_vec(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) -> Vec<Evaluated> { pub fn eval_to_vec<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> Vec<Evaluated> {
eval_multiple_kv(state, meas).into_iter().map(|(k, v)| { eval_multiple_kv(state, meas).into_iter().map(|(k, v)| {
Evaluated::new(k, v) Evaluated::new(k, v)
}).collect() }).collect()
@@ -29,11 +34,11 @@ pub fn eval_to_vec(state: &dyn GenericSim, meas: &[&dyn AbstractMeasurement]) ->
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct Time; pub struct Time;
impl AbstractMeasurement for Time { impl<S: GenericSim> AbstractMeasurement<S> for Time {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
format!("{:.3e}s (step {})", state.time(), state.step_no()) format!("{:.3e}s (step {})", state.time(), state.step_no())
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
[ [
("step".to_string(), state.step_no().to_string()), ("step".to_string(), state.step_no().to_string()),
("time".to_string(), state.time().to_string()), ("time".to_string(), state.time().to_string()),
@@ -44,11 +49,11 @@ impl AbstractMeasurement for Time {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct Meta; pub struct Meta;
impl AbstractMeasurement for Meta { impl<S: GenericSim> AbstractMeasurement<S> for Meta {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
format!("{}x{}x{} feat: {:.1e}m", state.width(), state.height(), state.depth(), state.feature_size()) format!("{}x{}x{} feat: {:.1e}m", state.width(), state.height(), state.depth(), state.feature_size())
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
[ [
("width".to_string(), state.width().to_string()), ("width".to_string(), state.width().to_string()),
("height".to_string(), state.height().to_string()), ("height".to_string(), state.height().to_string()),
@@ -68,13 +73,19 @@ impl Evaluated {
pub fn new<S1: Into<String>, S2: Into<String>>(key: S1, value: S2) -> Self { pub fn new<S1: Into<String>, S2: Into<String>>(key: S1, value: S2) -> Self {
Self(key.into(), value.into()) Self(key.into(), value.into())
} }
pub fn key(&self) -> &str {
&*self.0
}
pub fn value(&self) -> &str {
&*self.1
}
} }
impl AbstractMeasurement for Evaluated { impl<S> AbstractMeasurement<S> for Evaluated {
fn eval(&self, _state: &dyn GenericSim) -> String { fn eval(&self, _state: &S) -> String {
self.1.clone() self.1.clone()
} }
fn key_value(&self, _state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, _state: &S) -> IndexMap<String, String> {
[ [
(self.0.clone(), self.1.clone()), (self.0.clone(), self.1.clone()),
].into_iter().collect() ].into_iter().collect()
@@ -95,21 +106,21 @@ impl Volume {
} }
} }
/// Returns the volume of the region, in units of um^3 /// Returns the volume of the region, in units of um^3
fn data(&self, state: &dyn GenericSim) -> f32 { fn data<S: GenericSim>(&self, state: &S) -> f32 {
let feat_um = state.feature_size() as f64 * 1e6; 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 (state.volume_of_region(&*self.region) as f64 * feat_um * feat_um * feat_um) as f32
} }
} }
impl AbstractMeasurement for Volume { impl<S: GenericSim> AbstractMeasurement<S> for Volume {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
format!("Vol({}): {:.2e} um^3", format!("Vol({}): {:.2e} um^3",
self.name, self.name,
self.data(state), self.data(state),
) )
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
[ [
(format!("Vol({})", self.name), self.data(state).to_string()), (format!("Vol({})", self.name), self.data(state).to_string()),
].into_iter().collect() ].into_iter().collect()
@@ -129,7 +140,7 @@ impl Current {
region: Box::new(r) region: Box::new(r)
} }
} }
fn data(&self, state: &dyn GenericSim) -> (f32, Vec3<f32>) { fn data<S: GenericSim>(&self, state: &S) -> (f32, Vec3<f32>) {
let FieldSample(volume, current_mag, current_vec) = state.map_sum_over_enumerated(&*self.region, |coord: Meters, _cell| { let FieldSample(volume, current_mag, current_vec) = state.map_sum_over_enumerated(&*self.region, |coord: Meters, _cell| {
let current = state.current(coord); let current = state.current(coord);
FieldSample(1, current.mag().cast(), current.cast()) FieldSample(1, current.mag().cast(), current.cast())
@@ -185,15 +196,15 @@ impl std::iter::Sum for FieldSamples<[FieldSample; 3]> {
} }
} }
impl AbstractMeasurement for Current { impl<S: GenericSim> AbstractMeasurement<S> for Current {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let (mean_current_mag, mean_current_vec) = self.data(state); let (mean_current_mag, mean_current_vec) = self.data(state);
format!("I/cell({}): {:.2e} {:.2e}", format!("I/cell({}): {:.2e} {:.2e}",
self.name, self.name,
mean_current_mag, mean_current_mag,
mean_current_vec) mean_current_vec)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let (mean_current_mag, mean_current_vec) = self.data(state); let (mean_current_mag, mean_current_vec) = self.data(state);
[ [
(format!("Imag/cell({})", self.name), mean_current_mag.to_string()), (format!("Imag/cell({})", self.name), mean_current_mag.to_string()),
@@ -216,7 +227,7 @@ impl CurrentLoop {
region: r, region: r,
} }
} }
fn data(&self, state: &dyn GenericSim) -> f32 { fn data<S: GenericSim>(&self, state: &S) -> f32 {
let FieldSample(volume, directed_current, _current_vec) = state.map_sum_over_enumerated(&self.region, |coord: Meters, _cell| { let FieldSample(volume, directed_current, _current_vec) = state.map_sum_over_enumerated(&self.region, |coord: Meters, _cell| {
let normal = self.region.axis(); let normal = self.region.axis();
let to_coord = *coord - *self.region.center(); let to_coord = *coord - *self.region.center();
@@ -232,12 +243,12 @@ impl CurrentLoop {
} }
} }
impl AbstractMeasurement for CurrentLoop { impl<S: GenericSim> AbstractMeasurement<S> for CurrentLoop {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let cross_sectional_current = self.data(state); let cross_sectional_current = self.data(state);
format!("I({}): {:.2e}", self.name, cross_sectional_current) format!("I({}): {:.2e}", self.name, cross_sectional_current)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let cross_sectional_current = self.data(state); let cross_sectional_current = self.data(state);
[ [
(format!("I({})", self.name), cross_sectional_current.to_string()), (format!("I({})", self.name), cross_sectional_current.to_string()),
@@ -260,7 +271,7 @@ impl MagneticLoop {
region: r, region: r,
} }
} }
fn data(&self, state: &dyn GenericSim) -> (f32, f32, f32) { fn data<S: GenericSim>(&self, state: &S) -> (f32, f32, f32) {
let FieldSamples([ let FieldSamples([
FieldSample(volume, directed_m, _m_vec), FieldSample(volume, directed_m, _m_vec),
FieldSample(_, directed_b, _b_vec), FieldSample(_, directed_b, _b_vec),
@@ -300,8 +311,8 @@ impl MagneticLoop {
} }
} }
impl AbstractMeasurement for MagneticLoop { impl<S: GenericSim> AbstractMeasurement<S> for MagneticLoop {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state); let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state);
format!( format!(
"M({}): {:.2e}; B({}): {:.2e}; H({}): {:.2e}", "M({}): {:.2e}; B({}): {:.2e}; H({}): {:.2e}",
@@ -310,7 +321,7 @@ impl AbstractMeasurement for MagneticLoop {
self.name, mean_directed_h, self.name, mean_directed_h,
) )
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state); let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state);
[ [
(format!("M({})", self.name), mean_directed_m.to_string()), (format!("M({})", self.name), mean_directed_m.to_string()),
@@ -334,7 +345,7 @@ impl MagneticFlux {
region: Box::new(r) region: Box::new(r)
} }
} }
fn data(&self, state: &dyn GenericSim) -> Vec3<f32> { fn data<S: GenericSim>(&self, state: &S) -> Vec3<f32> {
let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| { let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| {
let b = cell.b(); let b = cell.b();
let mag = b.mag(); let mag = b.mag();
@@ -345,12 +356,12 @@ impl MagneticFlux {
} }
} }
impl AbstractMeasurement for MagneticFlux { impl<S: GenericSim> AbstractMeasurement<S> for MagneticFlux {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let mean_mag = self.data(state); let mean_mag = self.data(state);
format!("Bavg({}): {:.2e}", self.name, mean_mag) format!("Bavg({}): {:.2e}", self.name, mean_mag)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let mean_mag = self.data(state); let mean_mag = self.data(state);
[ [
(format!("Bavg({})", self.name), mean_mag.to_string()), (format!("Bavg({})", self.name), mean_mag.to_string()),
@@ -372,7 +383,7 @@ impl Magnetization {
region: Box::new(r) region: Box::new(r)
} }
} }
fn data(&self, state: &dyn GenericSim) -> Vec3<f32> { fn data<S: GenericSim>(&self, state: &S) -> Vec3<f32> {
let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| { let FieldSample(volume, _directed_mag, mag_vec) = state.map_sum_over(&*self.region, |cell| {
let m = cell.m(); let m = cell.m();
let mag = m.mag(); let mag = m.mag();
@@ -383,12 +394,12 @@ impl Magnetization {
} }
} }
impl AbstractMeasurement for Magnetization { impl<S: GenericSim> AbstractMeasurement<S> for Magnetization {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let mean_mag = self.data(state); let mean_mag = self.data(state);
format!("Mavg({}): {:.2e}", self.name, mean_mag) format!("Mavg({}): {:.2e}", self.name, mean_mag)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let mean_mag = self.data(state); let mean_mag = self.data(state);
[ [
(format!("Mavg({})", self.name), mean_mag.to_string()), (format!("Mavg({})", self.name), mean_mag.to_string()),
@@ -404,12 +415,12 @@ fn loc(v: Meters) -> String {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct MagnetizationAt(pub Meters); pub struct MagnetizationAt(pub Meters);
impl AbstractMeasurement for MagnetizationAt { impl<S: GenericSim> AbstractMeasurement<S> for MagnetizationAt {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let m = state.sample(self.0).m(); let m = state.sample(self.0).m();
format!("M{}: {:.2e}", loc(self.0), m) format!("M{}: {:.2e}", loc(self.0), m)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let m = state.sample(self.0).m(); let m = state.sample(self.0).m();
[ [
(format!("M{}", loc(self.0)), m.to_string()), (format!("M{}", loc(self.0)), m.to_string()),
@@ -421,12 +432,12 @@ impl AbstractMeasurement for MagnetizationAt {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct MagneticFluxAt(pub Meters); pub struct MagneticFluxAt(pub Meters);
impl AbstractMeasurement for MagneticFluxAt { impl<S: GenericSim> AbstractMeasurement<S> for MagneticFluxAt {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let b = state.sample(self.0).b(); let b = state.sample(self.0).b();
format!("B{}: {:.2e}", loc(self.0), b) format!("B{}: {:.2e}", loc(self.0), b)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let b = state.sample(self.0).b(); let b = state.sample(self.0).b();
[ [
(format!("B{}", loc(self.0)), b.to_string()), (format!("B{}", loc(self.0)), b.to_string()),
@@ -438,12 +449,12 @@ impl AbstractMeasurement for MagneticFluxAt {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct MagneticStrengthAt(pub Meters); pub struct MagneticStrengthAt(pub Meters);
impl AbstractMeasurement for MagneticStrengthAt { impl<S: GenericSim> AbstractMeasurement<S> for MagneticStrengthAt {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let h = state.sample(self.0).h(); let h = state.sample(self.0).h();
format!("H{}: {:.2e}", loc(self.0), h) format!("H{}: {:.2e}", loc(self.0), h)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let h = state.sample(self.0).h(); let h = state.sample(self.0).h();
[ [
(format!("H{}", loc(self.0)), h.to_string()), (format!("H{}", loc(self.0)), h.to_string()),
@@ -454,12 +465,12 @@ impl AbstractMeasurement for MagneticStrengthAt {
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct ElectricField(pub Meters); pub struct ElectricField(pub Meters);
impl AbstractMeasurement for ElectricField { impl<S: GenericSim> AbstractMeasurement<S> for ElectricField {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let e = state.sample(self.0).e(); let e = state.sample(self.0).e();
format!("E{}: {:.2e}", loc(self.0), e) format!("E{}: {:.2e}", loc(self.0), e)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let e = state.sample(self.0).e(); let e = state.sample(self.0).e();
[ [
(format!("E{}", loc(self.0)), e.to_string()), (format!("E{}", loc(self.0)), e.to_string()),
@@ -483,7 +494,7 @@ impl Energy {
region: Box::new(region), region: Box::new(region),
} }
} }
fn data(&self, state: &dyn GenericSim) -> f32 { fn data<S: GenericSim>(&self, state: &S) -> f32 {
// Potential energy stored in a E/M field: // Potential energy stored in a E/M field:
// https://en.wikipedia.org/wiki/Magnetic_energy // https://en.wikipedia.org/wiki/Magnetic_energy
// https://en.wikipedia.org/wiki/Electric_potential_energy#Energy_stored_in_an_electrostatic_field_distribution // 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 { impl<S: GenericSim> AbstractMeasurement<S> for Energy {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let e = self.data(state); let e = self.data(state);
format!("U({}): {:.2e}", self.name, e) format!("U({}): {:.2e}", self.name, e)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let e = self.data(state); let e = self.data(state);
[ [
(format!("U({})", self.name), e.to_string()), (format!("U({})", self.name), e.to_string()),
@@ -529,7 +540,7 @@ impl Power {
region: Box::new(region), region: Box::new(region),
} }
} }
fn data(&self, state: &dyn GenericSim) -> f32 { fn data<S: GenericSim>(&self, state: &S) -> f32 {
// Power is P = IV = A*J*V = L^2*J.(LE) = L^3 J.E // Power is P = IV = A*J*V = L^2*J.(LE) = L^3 J.E
// where L is feature size. // where L is feature size.
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -541,12 +552,12 @@ impl Power {
} }
} }
impl AbstractMeasurement for Power { impl<S: GenericSim> AbstractMeasurement<S> for Power {
fn eval(&self, state: &dyn GenericSim) -> String { fn eval(&self, state: &S) -> String {
let power = self.data(state); let power = self.data(state);
format!("P({}): {:.2e}", self.name, power) format!("P({}): {:.2e}", self.name, power)
} }
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String> { fn key_value(&self, state: &S) -> IndexMap<String, String> {
let power = self.data(state); let power = self.data(state);
[ [
(format!("P({})", self.name), power.to_string()), (format!("P({})", self.name), power.to_string()),

View File

@@ -129,20 +129,22 @@ impl RenderConfig {
struct RenderSteps<'a, S> { struct RenderSteps<'a, S> {
im: RgbImage, im: RgbImage,
sim: &'a S, sim: &'a S,
meas: &'a [&'a dyn AbstractMeasurement], meas: &'a [&'a dyn AbstractMeasurement<S>],
/// Simulation z coordinate to sample /// Simulation z coordinate to sample
z: u32, z: u32,
} }
impl<'a, S: GenericSim> RenderSteps<'a, S> { 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 /// 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<S>], z: u32) -> RgbImage {
Self::render_configured(state, measurements, z, (640, 480), RenderConfig::default()) Self::render_configured(state, measurements, z, (640, 480), RenderConfig::default())
} }
/// Render, controlling things like the size. /// Render, controlling things like the size.
fn render_configured( fn render_configured(
state: &'a S, state: &'a S,
measurements: &'a [&'a dyn AbstractMeasurement], measurements: &'a [&'a dyn AbstractMeasurement<S>],
z: u32, z: u32,
max_size: (u32, u32), max_size: (u32, u32),
config: RenderConfig, config: RenderConfig,
@@ -178,7 +180,7 @@ impl<'a, S: GenericSim> RenderSteps<'a, S> {
me.render_measurements(); me.render_measurements();
me.im 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<S>], width: u32, height: u32, z: u32) -> Self {
RenderSteps { RenderSteps {
im: RgbImage::new(width, height), im: RgbImage::new(width, height),
sim, sim,
@@ -340,25 +342,25 @@ impl ImageRenderExt for RgbImage {
} }
pub trait Renderer<S>: Send + Sync { pub trait Renderer<S>: 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<S>], config: RenderConfig);
// { // {
// self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements); // 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<S>], config: RenderConfig);
/// Not intended to be called directly by users; implement this if you want the image to be /// 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. /// 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<S>], config: RenderConfig) {
self.render(state, measurements, config); self.render(state, measurements, config);
} }
} }
fn default_render_z_slice<S: GenericSim, R: Renderer<S>>( fn default_render_z_slice<S: GenericSim, R: Renderer<S>>(
me: &R, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement], config: RenderConfig, me: &R, state: &S, z: u32, measurements: &[&dyn AbstractMeasurement<S>], config: RenderConfig,
) { ) {
me.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements, config); me.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements, config);
} }
fn default_render<S: GenericSim, R: Renderer<S>>( fn default_render<S: GenericSim, R: Renderer<S>>(
me: &R, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig me: &R, state: &S, measurements: &[&dyn AbstractMeasurement<S>], config: RenderConfig
) { ) {
me.render_z_slice(state, state.depth() / 2, measurements, config); me.render_z_slice(state, state.depth() / 2, measurements, config);
} }
@@ -366,7 +368,7 @@ fn default_render<S: GenericSim, R: Renderer<S>>(
// pub struct NumericTermRenderer; // pub struct NumericTermRenderer;
// //
// impl Renderer for NumericTermRenderer { // impl Renderer for NumericTermRenderer {
// fn render(&mut self, state: &SimSnapshot, _measurements: &[&dyn AbstractMeasurement]) { // fn render(&mut self, state: &SimSnapshot, _measurements: &[&dyn AbstractMeasurement<S>]) {
// for y in 0..state.height() { // for y in 0..state.height() {
// for x in 0..state.width() { // for x in 0..state.width() {
// let cell = state.get((x, y).into()); // let cell = state.get((x, y).into());
@@ -387,14 +389,14 @@ fn default_render<S: GenericSim, R: Renderer<S>>(
pub struct ColorTermRenderer; pub struct ColorTermRenderer;
impl<S: GenericSim> Renderer<S> for ColorTermRenderer { impl<S: GenericSim> Renderer<S> for ColorTermRenderer {
fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement], config: RenderConfig) { fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement<S>], config: RenderConfig) {
default_render(self, state, measurements, config) default_render(self, state, measurements, config)
} }
fn render_z_slice( fn render_z_slice(
&self, &self,
state: &S, state: &S,
z: u32, z: u32,
measurements: &[&dyn AbstractMeasurement], measurements: &[&dyn AbstractMeasurement<S>],
config: RenderConfig, config: RenderConfig,
) { ) {
let (max_w, mut max_h) = crossterm::terminal::size().unwrap(); let (max_w, mut max_h) = crossterm::terminal::size().unwrap();
@@ -449,13 +451,13 @@ impl Y4MRenderer {
} }
impl<S: GenericSim> Renderer<S> for Y4MRenderer { impl<S: GenericSim> Renderer<S> 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<S>], config: RenderConfig) {
default_render_z_slice(self, state, z, measurements, config) 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<S>], config: RenderConfig) {
default_render(self, state, measurements, config) 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<S>], _config: RenderConfig) {
{ {
let mut enc = self.encoder.lock().unwrap(); let mut enc = self.encoder.lock().unwrap();
if enc.is_none() { if enc.is_none() {
@@ -541,16 +543,16 @@ impl<S> MultiRenderer<S> {
} }
impl<S: GenericSim> Renderer<S> for MultiRenderer<S> { impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
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<S>], config: RenderConfig) {
default_render_z_slice(self, state, z, measurements, config) 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<S>], config: RenderConfig) {
if self.renderers.read().unwrap().len() != 0 { if self.renderers.read().unwrap().len() != 0 {
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2), measurements, config); 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<S>], config: RenderConfig) {
for r in &*self.renderers.read().unwrap() { for r in &*self.renderers.read().unwrap() {
if r.work_this_frame(state.step_no()) { 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);
@@ -605,10 +607,10 @@ impl SerializerRenderer {
} }
impl SerializerRenderer { impl SerializerRenderer {
fn serialize<S: GenericSim + Serialize>(&self, state: &S, measurements: &[&dyn AbstractMeasurement]) { fn serialize<S: GenericSim + Serialize>(&self, state: &S, measurements: Vec<meas::Evaluated>) {
let frame = SerializedFrame { let frame = SerializedFrame {
state, state,
measurements: meas::eval_to_vec(state, measurements), measurements,
}; };
let name = self.fmt_str.replace("{step_no}", &*frame.state.step_no().to_string()); let name = self.fmt_str.replace("{step_no}", &*frame.state.step_no().to_string());
let out = BufWriter::new(File::create(name).unwrap()); let out = BufWriter::new(File::create(name).unwrap());
@@ -623,14 +625,14 @@ impl SerializerRenderer {
} }
impl<S: GenericSim + Serialize> Renderer<S> for SerializerRenderer { impl<S: GenericSim + Serialize> Renderer<S> 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<S>], config: RenderConfig) {
default_render_z_slice(self, state, z, measurements, config) 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<S>], _config: RenderConfig) {
if self.prefer_static { if self.prefer_static {
self.serialize(&state.to_static(), measurements); self.serialize(&state.to_static(), meas::eval_to_vec(state, measurements));
} else { } else {
self.serialize(state, measurements); self.serialize(state, meas::eval_to_vec(state, measurements));
} }
} }
} }
@@ -666,10 +668,10 @@ impl CsvRenderer {
} }
impl<S: GenericSim> Renderer<S> for CsvRenderer { impl<S: GenericSim> Renderer<S> 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<S>], config: RenderConfig) {
default_render_z_slice(self, state, z, measurements, config) 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<S>], _config: RenderConfig) {
let row = meas::eval_multiple_kv(state, measurements); let row = meas::eval_multiple_kv(state, measurements);
let step = state.step_no(); let step = state.step_no();
let mut lock = self.state.lock().unwrap(); let mut lock = self.state.lock().unwrap();

View File

@@ -1201,7 +1201,7 @@ mod test {
assert_vec3_eq(actual_df_dt, df_dt(tm)); assert_vec3_eq(actual_df_dt, df_dt(tm));
} }
fn energy(s: &dyn GenericSim) -> f32 { fn energy<S: GenericSim>(s: &S) -> f32 {
0.5 * s.feature_volume() * s.map_sum_enumerated(|_pos: Index, cell| { 0.5 * s.feature_volume() * s.map_sum_enumerated(|_pos: Index, cell| {
// println!("{}: {}", _pos, cell.e()); // println!("{}: {}", _pos, cell.e());
cell.e().mag_sq().to_f64() cell.e().mag_sq().to_f64()

View File

@@ -217,77 +217,6 @@ impl<R: Real> CellStateWithM<R> {
} }
} }
impl<'a> dyn GenericSim + 'a {
pub fn get<C: Coord>(&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<F, Ret>(&self, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
Ret: Sum<Ret> + Send,
{
self.map_sum_enumerated(|_at: Index, cell| f(cell))
}
pub fn map_sum_enumerated<C, F, Ret>(&self, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
Ret: Sum<Ret> + 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<R: Region + ?Sized>(&self, region: &R) -> u32 {
self.map_sum_over(region, |_| 1)
}
/// Apply `F` to each Cell, and sum the results.
pub fn map_sum_over<F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
Ret: Sum<Ret> + Default + Send,
Reg: Region + ?Sized
{
self.map_sum_over_enumerated(region, |_at: Index, cell| f(cell))
}
pub fn map_sum_over_enumerated<C, F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
Ret: Sum<Ret> + 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<C: Coord>(&self, c: C) -> Vec3<f32> {
self.get(c).current_density() * self.feature_size() * self.feature_size()
}
}
// TODO: the Send/Sync bounds here could be removed with some refactoring // TODO: the Send/Sync bounds here could be removed with some refactoring
pub trait GenericSim: Send + Sync { pub trait GenericSim: Send + Sync {
fn meta(&self) -> SimMeta<f32>; fn meta(&self) -> SimMeta<f32>;
@@ -327,4 +256,73 @@ pub trait GenericSim: Send + Sync {
fn time(&self) -> f32 { fn time(&self) -> f32 {
self.timestep() * self.step_no() as f32 self.timestep() * self.step_no() as f32
} }
fn get<C: Coord>(&self, at: C) -> Sample {
self.sample(at.to_meters(self.feature_size()))
}
/// Apply `F` to each Cell, and sum the results.
fn map_sum<F, Ret>(&self, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
Ret: Sum<Ret> + Send,
{
self.map_sum_enumerated(|_at: Index, cell| f(cell))
}
fn map_sum_enumerated<C, F, Ret>(&self, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
Ret: Sum<Ret> + 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<R: Region + ?Sized>(&self, region: &R) -> u32 {
self.map_sum_over(region, |_| 1)
}
/// Apply `F` to each Cell, and sum the results.
fn map_sum_over<F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where
F: Fn(&Sample) -> Ret + Sync,
Ret: Sum<Ret> + Default + Send,
Reg: Region + ?Sized
{
self.map_sum_over_enumerated(region, |_at: Index, cell| f(cell))
}
fn map_sum_over_enumerated<C, F, Ret, Reg>(&self, region: &Reg, f: F) -> Ret
where C: Coord,
F: Fn(C, &Sample) -> Ret + Sync,
Ret: Sum<Ret> + 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<C: Coord>(&self, c: C) -> Vec3<f32> {
self.get(c).current_density() * self.feature_size() * self.feature_size()
}
} }

View File

@@ -272,20 +272,19 @@ where
mod test { mod test {
use super::*; use super::*;
use crate::real::ToFloat as _; use crate::real::ToFloat as _;
use crate::sim::GenericSim;
use crate::sim::legacy::{self, SimState}; use crate::sim::legacy::{self, SimState};
use crate::mat::{self, AnisomorphicConductor}; use crate::mat::{self, AnisomorphicConductor};
fn mean_magnitude_e(sim: &dyn GenericSim) -> f32 { fn mean_magnitude_e<S: GenericSim>(sim: &S) -> f32 {
(sim.map_sum_enumerated(|_pos: Index, cell| { (sim.map_sum_enumerated(|_pos: Index, cell| {
cell.e().mag().to_f64() cell.e().mag().to_f64()
})/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32()
} }
fn mean_magnitude_h(sim: &dyn GenericSim) -> f32 { fn mean_magnitude_h<S: GenericSim>(sim: &S) -> f32 {
(sim.map_sum_enumerated(|_pos: Index, cell| { (sim.map_sum_enumerated(|_pos: Index, cell| {
cell.h().mag().to_f64() cell.h().mag().to_f64()
})/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32()
} }
fn mean_magnitude_m(sim: &dyn GenericSim) -> f32 { fn mean_magnitude_m<S: GenericSim>(sim: &S) -> f32 {
(sim.map_sum_enumerated(|_pos: Index, cell| { (sim.map_sum_enumerated(|_pos: Index, cell| {
cell.m().mag().to_f64() cell.m().mag().to_f64()
})/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32() })/((sim.width() * sim.height() * sim.depth()) as f64)).to_f32()
@@ -302,8 +301,8 @@ mod test {
for y in 0..dim.y() { for y in 0..dim.y() {
for x in 0..dim.x() { for x in 0..dim.x() {
let idx = Index::new(x, y, z); let idx = Index::new(x, y, z);
let real_cell = (real_state as &dyn GenericSim).get(idx); let real_cell = real_state.get(idx);
let ref_cell = (ref_state as &dyn GenericSim).get(idx); let ref_cell = ref_state.get(idx);
let diff_e = real_cell.e() - ref_cell.e(); let diff_e = real_cell.e() - ref_cell.e();
let diff_h = real_cell.h() - ref_cell.h(); let diff_h = real_cell.h() - ref_cell.h();

View File

@@ -14,18 +14,14 @@ fn main() {
let mut cache = LoaderCache::new(loader, 2, 2); let mut cache = LoaderCache::new(loader, 2, 2);
let mut frame = cache.load_first(); let mut frame = cache.load_first();
for meas in frame.dyn_measurements() { for meas in frame.measurements() {
for key in meas.key_value(&**frame).keys() { print!("\"{}\",", meas.key());
print!("\"{}\",", key);
}
} }
println!(""); println!("");
loop { loop {
for meas in frame.dyn_measurements() { for meas in frame.measurements() {
for value in meas.key_value(&**frame).values() { print!("\"{}\",", meas.value());
print!("\"{}\",", value);
}
} }
println!(""); println!("");

View File

@@ -1,5 +1,5 @@
//! Post-processing tools //! Post-processing tools
use coremem::meas::{self, AbstractMeasurement}; use coremem::meas;
use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame}; use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame};
use coremem::sim::{GenericSim, StaticSim}; use coremem::sim::{GenericSim, StaticSim};
@@ -40,9 +40,6 @@ impl Frame {
pub fn measurements(&self) -> &[meas::Evaluated] { pub fn measurements(&self) -> &[meas::Evaluated] {
&*self.data.measurements &*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 { pub fn path(&self) -> &Path {
&*self.path &*self.path
} }
@@ -277,7 +274,10 @@ impl Viewer {
} }
pub fn render(&self) { pub fn render(&self) {
self.renderer.render_z_slice( 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 { pub fn render_config(&mut self) -> &mut RenderConfig {