meas: finish porting to a concrete type.

this will in future let me more easily test each individual measurement
type
This commit is contained in:
2022-07-30 20:56:19 -07:00
parent 60840aec36
commit 542d700f69
4 changed files with 49 additions and 25 deletions

View File

@@ -1,6 +1,6 @@
use crate::geom::{Meters, Region, Torus, WorldRegion};
use crate::real::{Real as _, ToFloat as _};
use crate::cross::vec::Vec3;
use crate::cross::vec::{Vec3, Vec3u};
use crate::sim::AbstractSim;
use serde::{Serialize, Deserialize};
@@ -15,11 +15,11 @@ pub fn as_dyn_measurements<S, M: AbstractMeasurement<S>>(meas: &[M]) -> Vec<&dyn
/// combine several measurements
pub fn eval_multiple_kv<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> Vec<Measurement>
pub fn eval_multiple_kv<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> Vec<Measurement> {
meas.into_iter().flat_map(|m| m.key_value(state).into_iter()).collect()
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum MeasurementValue {
Field(Vec3<f32>),
Float(f32),
@@ -48,7 +48,7 @@ impl From<Vec3u> for MeasurementValue {
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Measurement {
name: String,
value: MeasurementValue,
@@ -59,7 +59,7 @@ pub struct Measurement {
impl Measurement {
fn new<T: Into<MeasurementValue>>(name: &str, value: T, unit: &str) -> Self {
Self {
name.to_owned(),
name: name.to_owned(),
value: value.into(),
unit: unit.to_owned(),
}
@@ -67,6 +67,30 @@ impl Measurement {
fn new_unitless<T: Into<MeasurementValue>>(name: &str, value: T) -> Self {
Self::new(name, value, "")
}
pub fn name(&self) -> &str {
&self.name
}
pub fn str_value(&self) -> String {
use MeasurementValue::*;
let val = match self.value {
Field(v) => v.to_string(),
Float(f) => f.to_string(),
Int(u) => u.to_string(),
Dim(v) => format!("{}x{}x{}", v.x(), v.y(), v.z()),
};
format!("{}{}", val, self.unit)
}
}
impl<S> AbstractMeasurement<S> for Measurement {
fn eval(&self, _state: &S) -> String {
format!("{}: {}", self.name, self.str_value())
}
fn key_value(&self, _state: &S) -> Vec<Measurement> {
vec![self.clone()]
}
}
enum SiScale {
@@ -149,7 +173,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Time {
fn eval(&self, state: &S) -> String {
format!("{} (step {})", SiScale::format_short(state.time(), "s"), state.step_no())
}
fn key_value(&self, state: &S) -> Vec<Measurement>
fn key_value(&self, state: &S) -> Vec<Measurement> {
vec![
Measurement::new_unitless("step", state.step_no()),
Measurement::new("time", state.time(), "s"),
@@ -166,7 +190,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Meta {
}
fn key_value(&self, state: &S) -> Vec<Measurement> {
vec![
Measurement::new_unitless("dim", state.dim()),
Measurement::new_unitless("dim", state.size().0),
Measurement::new("feature_size", state.feature_size(), "m"),
]
}
@@ -202,7 +226,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Volume {
}
fn key_value(&self, state: &S) -> Vec<Measurement> {
vec![
Measurement::new(&format!("Vol({})", self.name), self.data(), "um^3"),
Measurement::new(&format!("Vol({})", self.name), self.data(state), "um^3"),
]
}
}
@@ -416,9 +440,9 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticLoop {
fn key_value(&self, state: &S) -> Vec<Measurement> {
let (mean_directed_m, mean_directed_b, mean_directed_h) = self.data(state);
vec![
Measurement::new_unitless(&format!("M({})", self.name), mean_directed_current_m),
Beasurement::new_unitless(&format!("B({})", self.name), mean_directed_current_b),
Beasurement::new_unitless(&format!("H({})", self.name), mean_directed_current_h),
Measurement::new_unitless(&format!("M({})", self.name), mean_directed_m),
Measurement::new_unitless(&format!("B({})", self.name), mean_directed_b),
Measurement::new_unitless(&format!("H({})", self.name), mean_directed_h),
]
}
}
@@ -520,7 +544,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagnetizationAt {
fn key_value(&self, state: &S) -> Vec<Measurement> {
let m = state.sample(self.0).m();
vec![
Measurement::new_unitless(&format!("M{}", loc(self.0)), m)
Measurement::new_unitless(&format!("M{}", loc(self.0)), m.cast())
]
}
}
@@ -538,7 +562,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticFluxAt {
let b = state.sample(self.0).b();
vec![
Measurement::new_unitless(
&format!("B{}", loc(self.0)), b
&format!("B{}", loc(self.0)), b.cast()
)
]
}
@@ -557,7 +581,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticStrengthAt {
let h = state.sample(self.0).h();
vec![
Measurement::new_unitless(
&format!("H{}", loc(self.0)), h
&format!("H{}", loc(self.0)), h.cast()
)
]
}
@@ -575,7 +599,7 @@ impl<S: AbstractSim> AbstractMeasurement<S> for ElectricField {
let e = state.sample(self.0).e();
vec![
Measurement::new_unitless(
&format!("E{}", loc(self.0)), e
&format!("E{}", loc(self.0)), e.cast()
)
]
}

View File

@@ -2,7 +2,7 @@ use crate::geom::Index;
use crate::real::ToFloat as _;
use crate::cross::vec::{Vec2, Vec3};
use crate::sim::{AbstractSim, GenericSim, Sample};
use crate::meas::{self, AbstractMeasurement};
use crate::meas::{self, AbstractMeasurement, Measurement};
use crossterm::{cursor, QueueableCommand as _};
use crossterm::style::{style, Color, PrintStyledContent, Stylize as _};
use font8x8::{BASIC_FONTS, GREEK_FONTS, UnicodeFonts as _};
@@ -592,7 +592,7 @@ pub struct SerializedFrame<S> {
pub state: S,
/// although not generally necessary to load the sim, saving the measurements is beneficial for
/// post-processing.
pub measurements: Vec<meas::Evaluated>,
pub measurements: Vec<Measurement>,
}
impl<S: AbstractSim> SerializedFrame<S> {
@@ -633,7 +633,7 @@ impl SerializerRenderer {
}
impl SerializerRenderer {
fn serialize<S: AbstractSim + Serialize>(&self, state: &S, measurements: Vec<meas::Evaluated>) {
fn serialize<S: AbstractSim + Serialize>(&self, state: &S, measurements: Vec<Measurement>) {
let frame = SerializedFrame {
state,
measurements,
@@ -656,9 +656,9 @@ impl<S: AbstractSim + Serialize> Renderer<S> for SerializerRenderer {
}
fn render(&self, state: &S, measurements: &[&dyn AbstractMeasurement<S>], _config: RenderConfig) {
if self.prefer_generic {
self.serialize(&state.to_generic(), meas::eval_to_vec(state, measurements));
self.serialize(&state.to_generic(), meas::eval_multiple_kv(state, measurements));
} else {
self.serialize(state, meas::eval_to_vec(state, measurements));
self.serialize(state, meas::eval_multiple_kv(state, measurements));
}
}
}
@@ -732,13 +732,13 @@ impl<S: AbstractSim> Renderer<S> for CsvRenderer {
file.set_len(0).unwrap();
let mut writer = csv::Writer::from_writer(BufWriter::new(file));
// write the header
writer.write_record(row.keys()).unwrap();
writer.write_record(row.iter().map(|m| m.name())).unwrap();
writer
}
},
CsvState::Writing(writer) => writer,
};
writer.write_record(row.values()).unwrap();
writer.write_record(row.iter().map(|m| m.str_value())).unwrap();
writer.flush().unwrap();
*lock = Some(CsvState::Writing(writer));
}

View File

@@ -15,13 +15,13 @@ fn main() {
let mut frame = cache.load_first();
for meas in frame.measurements() {
print!("\"{}\",", meas.key());
print!("\"{}\",", meas.name());
}
println!("");
loop {
for meas in frame.measurements() {
print!("\"{}\",", meas.value());
print!("\"{}\",", meas.str_value());
}
println!("");

View File

@@ -36,7 +36,7 @@ pub struct Frame {
}
impl Frame {
pub fn measurements(&self) -> &[meas::Evaluated] {
pub fn measurements(&self) -> &[meas::Measurement] {
&*self.data.measurements
}
pub fn sim(&self) -> &GenericSim<f32> {