WIP: make the measurement type concrete
This commit is contained in:
@@ -2,12 +2,11 @@ use crate::geom::{Meters, Region, Torus, WorldRegion};
|
|||||||
use crate::real::{Real as _, ToFloat as _};
|
use crate::real::{Real as _, ToFloat as _};
|
||||||
use crate::cross::vec::Vec3;
|
use crate::cross::vec::Vec3;
|
||||||
use crate::sim::AbstractSim;
|
use crate::sim::AbstractSim;
|
||||||
use indexmap::IndexMap;
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
pub trait AbstractMeasurement<S>: Send + Sync {
|
pub trait AbstractMeasurement<S>: Send + Sync {
|
||||||
fn eval(&self, state: &S) -> String;
|
fn eval(&self, state: &S) -> String;
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String>;
|
fn key_value(&self, state: &S) -> Vec<Measurement>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_dyn_measurements<S, M: AbstractMeasurement<S>>(meas: &[M]) -> Vec<&dyn AbstractMeasurement<S>> {
|
pub fn as_dyn_measurements<S, M: AbstractMeasurement<S>>(meas: &[M]) -> Vec<&dyn AbstractMeasurement<S>> {
|
||||||
@@ -15,20 +14,59 @@ pub fn as_dyn_measurements<S, M: AbstractMeasurement<S>>(meas: &[M]) -> Vec<&dyn
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// create one IndexMap out of several measurements
|
/// combine several measurements
|
||||||
pub fn eval_multiple_kv<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> IndexMap<String, String> {
|
pub fn eval_multiple_kv<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> Vec<Measurement>
|
||||||
let mut r = IndexMap::new();
|
meas.into_iter().flat_map(|m| m.key_value(state).into_iter()).collect()
|
||||||
for m in meas {
|
|
||||||
let other = m.key_value(state);
|
|
||||||
r.extend(other.into_iter());
|
|
||||||
}
|
|
||||||
r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_to_vec<S>(state: &S, meas: &[&dyn AbstractMeasurement<S>]) -> Vec<Evaluated> {
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
eval_multiple_kv(state, meas).into_iter().map(|(k, v)| {
|
pub enum MeasurementValue {
|
||||||
Evaluated::new(k, v)
|
Field(Vec3<f32>),
|
||||||
}).collect()
|
Float(f32),
|
||||||
|
Int(u64),
|
||||||
|
Dim(Vec3u),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Vec3<f32>> for MeasurementValue {
|
||||||
|
fn from(v: Vec3<f32>) -> Self {
|
||||||
|
Self::Field(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<f32> for MeasurementValue {
|
||||||
|
fn from(v: f32) -> Self {
|
||||||
|
Self::Float(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<u64> for MeasurementValue {
|
||||||
|
fn from(v: u64) -> Self {
|
||||||
|
Self::Int(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<Vec3u> for MeasurementValue {
|
||||||
|
fn from(v: Vec3u) -> Self {
|
||||||
|
Self::Dim(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub struct Measurement {
|
||||||
|
name: String,
|
||||||
|
value: MeasurementValue,
|
||||||
|
/// e.g. "A" for Amps
|
||||||
|
unit: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Measurement {
|
||||||
|
fn new<T: Into<MeasurementValue>>(name: &str, value: T, unit: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
name.to_owned(),
|
||||||
|
value: value.into(),
|
||||||
|
unit: unit.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn new_unitless<T: Into<MeasurementValue>>(name: &str, value: T) -> Self {
|
||||||
|
Self::new(name, value, "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SiScale {
|
enum SiScale {
|
||||||
@@ -111,11 +149,11 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Time {
|
|||||||
fn eval(&self, state: &S) -> String {
|
fn eval(&self, state: &S) -> String {
|
||||||
format!("{} (step {})", SiScale::format_short(state.time(), "s"), state.step_no())
|
format!("{} (step {})", SiScale::format_short(state.time(), "s"), state.step_no())
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement>
|
||||||
[
|
vec![
|
||||||
("step".to_string(), state.step_no().to_string()),
|
Measurement::new_unitless("step", state.step_no()),
|
||||||
("time".to_string(), state.time().to_string()),
|
Measurement::new("time", state.time(), "s"),
|
||||||
].into_iter().collect()
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,42 +164,11 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Meta {
|
|||||||
fn eval(&self, state: &S) -> 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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
[
|
vec![
|
||||||
("width".to_string(), state.width().to_string()),
|
Measurement::new_unitless("dim", state.dim()),
|
||||||
("height".to_string(), state.height().to_string()),
|
Measurement::new("feature_size", state.feature_size(), "m"),
|
||||||
("depth".to_string(), state.depth().to_string()),
|
]
|
||||||
("feature_size".to_string(), state.feature_size().to_string()),
|
|
||||||
].into_iter().collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// some measurement which has already been evaluated.
|
|
||||||
/// this is used particularly if we need to monomorphize a measurement (e.g. for serialization)
|
|
||||||
/// and know it won't be applied to a new/different state.
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub struct Evaluated(String, String);
|
|
||||||
|
|
||||||
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<S> AbstractMeasurement<S> for Evaluated {
|
|
||||||
fn eval(&self, _state: &S) -> String {
|
|
||||||
format!("{}: {}", self.0, self.1)
|
|
||||||
}
|
|
||||||
fn key_value(&self, _state: &S) -> IndexMap<String, String> {
|
|
||||||
[
|
|
||||||
(self.0.clone(), self.1.clone()),
|
|
||||||
].into_iter().collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,10 +200,10 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Volume {
|
|||||||
self.data(state),
|
self.data(state),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
[
|
vec![
|
||||||
(format!("Vol({})", self.name), self.data(state).to_string()),
|
Measurement::new(&format!("Vol({})", self.name), self.data(), "um^3"),
|
||||||
].into_iter().collect()
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,12 +284,20 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Current {
|
|||||||
mean_current_mag,
|
mean_current_mag,
|
||||||
mean_current_vec)
|
mean_current_vec)
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let (mean_current_mag, mean_current_vec) = self.data(state);
|
let (mean_current_mag, mean_current_vec) = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("Imag/cell({})", self.name), mean_current_mag.to_string()),
|
Measurement::new(
|
||||||
(format!("I/cell({})", self.name), mean_current_vec.to_string()),
|
&format!("Imag/cell({})", self.name),
|
||||||
].into_iter().collect()
|
mean_current_mag,
|
||||||
|
"A",
|
||||||
|
),
|
||||||
|
Measurement::new(
|
||||||
|
&format!("/cell({})", self.name),
|
||||||
|
mean_current_vec,
|
||||||
|
"A",
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,11 +336,15 @@ impl<S: AbstractSim> AbstractMeasurement<S> for CurrentLoop {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let cross_sectional_current = self.data(state);
|
let cross_sectional_current = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("I({})", self.name), cross_sectional_current.to_string()),
|
Measurement::new(
|
||||||
].into_iter().collect()
|
&format!("I({})", self.name),
|
||||||
|
cross_sectional_current,
|
||||||
|
"A"
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,13 +413,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticLoop {
|
|||||||
self.name, mean_directed_h,
|
self.name, mean_directed_h,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
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);
|
||||||
[
|
vec![
|
||||||
(format!("M({})", self.name), mean_directed_m.to_string()),
|
Measurement::new_unitless(&format!("M({})", self.name), mean_directed_current_m),
|
||||||
(format!("B({})", self.name), mean_directed_b.to_string()),
|
Beasurement::new_unitless(&format!("B({})", self.name), mean_directed_current_b),
|
||||||
(format!("H({})", self.name), mean_directed_h.to_string()),
|
Beasurement::new_unitless(&format!("H({})", self.name), mean_directed_current_h),
|
||||||
].into_iter().collect()
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,11 +453,14 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticFlux {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let mean_mag = self.data(state);
|
let mean_mag = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("Bavg({})", self.name), mean_mag.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("Bavg({})", self.name),
|
||||||
|
mean_mag,
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,11 +494,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Magnetization {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let mean_mag = self.data(state);
|
let mean_mag = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("Mavg({})", self.name), mean_mag.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("Mavg({})", self.name), mean_mag
|
||||||
|
),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,11 +517,11 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagnetizationAt {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let m = state.sample(self.0).m();
|
let m = state.sample(self.0).m();
|
||||||
[
|
vec![
|
||||||
(format!("M{}", loc(self.0)), m.to_string()),
|
Measurement::new_unitless(&format!("M{}", loc(self.0)), m)
|
||||||
].into_iter().collect()
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,11 +534,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticFluxAt {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let b = state.sample(self.0).b();
|
let b = state.sample(self.0).b();
|
||||||
[
|
vec![
|
||||||
(format!("B{}", loc(self.0)), b.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("B{}", loc(self.0)), b
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,11 +553,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for MagneticStrengthAt {
|
|||||||
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: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let h = state.sample(self.0).h();
|
let h = state.sample(self.0).h();
|
||||||
[
|
vec![
|
||||||
(format!("H{}", loc(self.0)), h.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("H{}", loc(self.0)), h
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,11 +571,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for ElectricField {
|
|||||||
let e = state.sample(self.0).e();
|
let e = state.sample(self.0).e();
|
||||||
format!("E{}: {}", loc(self.0), e)
|
format!("E{}: {}", loc(self.0), e)
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let e = state.sample(self.0).e();
|
let e = state.sample(self.0).e();
|
||||||
[
|
vec![
|
||||||
(format!("E{}", loc(self.0)), e.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("E{}", loc(self.0)), e
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -589,11 +619,13 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Energy {
|
|||||||
let e = self.data(state);
|
let e = self.data(state);
|
||||||
format!("U({}): {}", self.name, SiScale::format_short(e, "J"))
|
format!("U({}): {}", self.name, SiScale::format_short(e, "J"))
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let e = self.data(state);
|
let e = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("U({})", self.name), e.to_string()),
|
Measurement::new_unitless(
|
||||||
].into_iter().collect()
|
&format!("U({})", self.name), e
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,10 +662,12 @@ impl<S: AbstractSim> AbstractMeasurement<S> for Power {
|
|||||||
let power = self.data(state);
|
let power = self.data(state);
|
||||||
format!("P({}): {}", self.name, SiScale::format_short(power, "W"))
|
format!("P({}): {}", self.name, SiScale::format_short(power, "W"))
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &S) -> IndexMap<String, String> {
|
fn key_value(&self, state: &S) -> Vec<Measurement> {
|
||||||
let power = self.data(state);
|
let power = self.data(state);
|
||||||
[
|
vec![
|
||||||
(format!("P({})", self.name), power.to_string()),
|
Measurement::new(
|
||||||
].into_iter().collect()
|
&format!("P({})", self.name), power, "W"
|
||||||
|
)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user