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_blocked_on_render: Duration,
time_spent_rendering: Arc<Mutex<Duration>>,
measurements: Vec<Arc<dyn AbstractMeasurement>>,
measurements: Vec<Arc<dyn AbstractMeasurement<S>>>,
stimuli: StimuliAdapter,
start_time: Instant,
last_diag_time: Instant,
@@ -36,7 +36,7 @@ pub struct Driver<S> {
sim_end_time: Option<Frame>,
}
impl<S> Driver<S> {
impl<S: GenericSim> Driver<S> {
pub fn new(state: S) -> Self {
Self {
state,
@@ -65,7 +65,7 @@ impl<S> Driver<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));
}
@@ -151,7 +151,7 @@ impl<S: MaterialSim + Clone + Default + Send + Sync + 'static> Driver<S> {
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<S>> = 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");

View File

@@ -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<String, String>;
pub trait AbstractMeasurement<S>: Send + Sync {
fn eval(&self, state: &S) -> 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
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();
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<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)| {
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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
[
("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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
[
("width".to_string(), state.width().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 {
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<S> AbstractMeasurement<S> for Evaluated {
fn eval(&self, _state: &S) -> String {
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()),
].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<S: GenericSim>(&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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
[
(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<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 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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim>(&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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim>(&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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<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 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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<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 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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim>(&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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
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<S: GenericSim>(&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<S: GenericSim> AbstractMeasurement<S> 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<String, String> {
fn key_value(&self, state: &S) -> IndexMap<String, String> {
let power = self.data(state);
[
(format!("P({})", self.name), power.to_string()),

View File

@@ -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<S>],
/// 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<S>], 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<S>],
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<S>], 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<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);
// }
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
/// 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);
}
}
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);
}
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);
}
@@ -366,7 +368,7 @@ fn default_render<S: GenericSim, R: Renderer<S>>(
// 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<S>]) {
// 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<S: GenericSim, R: Renderer<S>>(
pub struct 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)
}
fn render_z_slice(
&self,
state: &S,
z: u32,
measurements: &[&dyn AbstractMeasurement],
measurements: &[&dyn AbstractMeasurement<S>],
config: RenderConfig,
) {
let (max_w, mut max_h) = crossterm::terminal::size().unwrap();
@@ -449,13 +451,13 @@ impl 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)
}
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)
}
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();
if enc.is_none() {
@@ -541,16 +543,16 @@ impl<S> 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)
}
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 {
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() {
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<S: GenericSim + Serialize>(&self, state: &S, measurements: &[&dyn AbstractMeasurement]) {
fn serialize<S: GenericSim + Serialize>(&self, state: &S, measurements: Vec<meas::Evaluated>) {
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<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)
}
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 {
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<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)
}
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 step = state.step_no();
let mut lock = self.state.lock().unwrap();

View File

@@ -1201,7 +1201,7 @@ mod test {
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| {
// println!("{}: {}", _pos, cell.e());
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
pub trait GenericSim: Send + Sync {
fn meta(&self) -> SimMeta<f32>;
@@ -327,4 +256,73 @@ pub trait GenericSim: Send + Sync {
fn time(&self) -> 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 {
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<S: GenericSim>(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<S: GenericSim>(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<S: GenericSim>(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();

View File

@@ -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!("");

View File

@@ -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 {