Fold SampleableSim and MaterialSim into one
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use coremem::{self, Driver, GenericSim};
|
use coremem::{self, Driver, MaterialSim};
|
||||||
use coremem::sim::legacy::SimState;
|
use coremem::sim::legacy::SimState;
|
||||||
use coremem::sim::spirv::{SpirvSim, WgpuBackend};
|
use coremem::sim::spirv::{SpirvSim, WgpuBackend};
|
||||||
use coremem::cross::mat::FullyGenericMaterial;
|
use coremem::cross::mat::FullyGenericMaterial;
|
||||||
@@ -18,7 +18,7 @@ fn measure<F: FnMut()>(name: &str, n_times: u32, mut f: F) -> f32 {
|
|||||||
avg
|
avg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn measure_steps<S: GenericSim + Clone + Default + Send + Sync + 'static>(name: &str, steps_per_call: u32, mut d: Driver<S>) {
|
fn measure_steps<S: MaterialSim + Clone + Default + Send + Sync + 'static>(name: &str, steps_per_call: u32, mut d: Driver<S>) {
|
||||||
measure(name, 100/steps_per_call, || d.step_multiple(steps_per_call));
|
measure(name, 100/steps_per_call, || d.step_multiple(steps_per_call));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@ use crate::mat;
|
|||||||
use crate::meas::{self, AbstractMeasurement};
|
use crate::meas::{self, AbstractMeasurement};
|
||||||
use crate::real::Real;
|
use crate::real::Real;
|
||||||
use crate::render::{self, MultiRenderer, Renderer};
|
use crate::render::{self, MultiRenderer, Renderer};
|
||||||
use crate::sim::{GenericSim, MaterialSim, SampleableSim};
|
use crate::sim::{GenericSim, MaterialSim};
|
||||||
use crate::sim::units::{Frame, Time};
|
use crate::sim::units::{Frame, Time};
|
||||||
use crate::stim::AbstractStimulus;
|
use crate::stim::AbstractStimulus;
|
||||||
use crate::cross::vec::Vec3;
|
use crate::cross::vec::Vec3;
|
||||||
@@ -83,7 +83,7 @@ impl<S: MaterialSim> Driver<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim> Driver<S> {
|
impl<S: GenericSim> Driver<S> {
|
||||||
pub fn size(&self) -> Index {
|
pub fn size(&self) -> Index {
|
||||||
self.state.size()
|
self.state.size()
|
||||||
}
|
}
|
||||||
@@ -95,8 +95,8 @@ impl<S: SampleableSim> Driver<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
|
impl<S: GenericSim + Send + Sync + 'static> Driver<S> {
|
||||||
pub fn dyn_state(&mut self) -> &mut dyn SampleableSim {
|
pub fn dyn_state(&mut self) -> &mut dyn GenericSim {
|
||||||
&mut self.state
|
&mut self.state
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,14 +122,14 @@ impl<S: SampleableSim + Send + Sync + 'static> Driver<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Send + Sync + Serialize + 'static> Driver<S> {
|
impl<S: GenericSim + Send + Sync + Serialize + 'static> Driver<S> {
|
||||||
pub fn add_serializer_renderer(&mut self, out_base: &str, step_frequency: u64, frame_limit: Option<u64>) {
|
pub fn add_serializer_renderer(&mut self, out_base: &str, step_frequency: u64, frame_limit: Option<u64>) {
|
||||||
let fmt_str = format!("{out_base}{{step_no}}.bc", out_base=out_base);
|
let fmt_str = format!("{out_base}{{step_no}}.bc", out_base=out_base);
|
||||||
self.add_renderer(render::SerializerRenderer::new_static(&*fmt_str), &*fmt_str, step_frequency, frame_limit);
|
self.add_renderer(render::SerializerRenderer::new_static(&*fmt_str), &*fmt_str, step_frequency, frame_limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static> Driver<S> {
|
impl<S: GenericSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static> Driver<S> {
|
||||||
/// instruct the driver to periodically save the simulation state to the provided path.
|
/// instruct the driver to periodically save the simulation state to the provided path.
|
||||||
/// also attempts to load an existing state file, returning `true` on success.
|
/// also attempts to load an existing state file, returning `true` on success.
|
||||||
pub fn add_state_file(&mut self, state_file: &str, snapshot_frequency: u64) -> bool {
|
pub fn add_state_file(&mut self, state_file: &str, snapshot_frequency: u64) -> bool {
|
||||||
@@ -142,7 +142,7 @@ impl<S: SampleableSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'sta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: GenericSim + Clone + Default + Send + Sync + 'static> Driver<S> {
|
impl<S: MaterialSim + Clone + Default + Send + Sync + 'static> Driver<S> {
|
||||||
fn render(&mut self) {
|
fn render(&mut self) {
|
||||||
let prep_start = Instant::now();
|
let prep_start = Instant::now();
|
||||||
let their_state = self.state.clone();
|
let their_state = self.state.clone();
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
use crate::geom::{Meters, Region, Torus, WorldRegion};
|
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::SampleableSim;
|
use crate::sim::GenericSim;
|
||||||
use dyn_clone::{self, DynClone};
|
use dyn_clone::{self, DynClone};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
@@ -10,12 +10,12 @@ use serde::{Serialize, Deserialize};
|
|||||||
// threads? i.e. Sync, and no Clone
|
// threads? i.e. Sync, and no Clone
|
||||||
#[typetag::serde(tag = "type")]
|
#[typetag::serde(tag = "type")]
|
||||||
pub trait AbstractMeasurement: Send + Sync + DynClone {
|
pub trait AbstractMeasurement: Send + Sync + DynClone {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String;
|
fn eval(&self, state: &dyn GenericSim) -> String;
|
||||||
fn key_value(&self, state: &dyn SampleableSim) -> IndexMap<String, String>;
|
fn key_value(&self, state: &dyn GenericSim) -> IndexMap<String, String>;
|
||||||
}
|
}
|
||||||
dyn_clone::clone_trait_object!(AbstractMeasurement);
|
dyn_clone::clone_trait_object!(AbstractMeasurement);
|
||||||
|
|
||||||
pub fn eval_multiple_kv(state: &dyn SampleableSim, meas: &[Box<dyn AbstractMeasurement>]) -> IndexMap<String, String> {
|
pub fn eval_multiple_kv(state: &dyn GenericSim, meas: &[Box<dyn AbstractMeasurement>]) -> 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);
|
||||||
@@ -29,10 +29,10 @@ pub struct Time;
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Time {
|
impl AbstractMeasurement for Time {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -45,10 +45,10 @@ pub struct Meta;
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Meta {
|
impl AbstractMeasurement for Meta {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -69,10 +69,10 @@ impl Label {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Label {
|
impl AbstractMeasurement for Label {
|
||||||
fn eval(&self, _state: &dyn SampleableSim) -> String {
|
fn eval(&self, _state: &dyn GenericSim) -> String {
|
||||||
self.0.clone()
|
self.0.clone()
|
||||||
}
|
}
|
||||||
fn key_value(&self, _state: &dyn SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, _state: &dyn GenericSim) -> IndexMap<String, String> {
|
||||||
[
|
[
|
||||||
(self.0.clone(), self.0.clone()),
|
(self.0.clone(), self.0.clone()),
|
||||||
].into_iter().collect()
|
].into_iter().collect()
|
||||||
@@ -93,7 +93,7 @@ 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 SampleableSim) -> f32 {
|
fn data(&self, state: &dyn GenericSim) -> 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
|
||||||
@@ -102,13 +102,13 @@ impl Volume {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Volume {
|
impl AbstractMeasurement for Volume {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()
|
||||||
@@ -128,7 +128,7 @@ impl Current {
|
|||||||
region: Box::new(r)
|
region: Box::new(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> (f32, Vec3<f32>) {
|
fn data(&self, state: &dyn GenericSim) -> (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())
|
||||||
@@ -186,14 +186,14 @@ impl std::iter::Sum for FieldSamples<[FieldSample; 3]> {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Current {
|
impl AbstractMeasurement for Current {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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 +216,7 @@ impl CurrentLoop {
|
|||||||
region: r,
|
region: r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> f32 {
|
fn data(&self, state: &dyn GenericSim) -> 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();
|
||||||
@@ -234,11 +234,11 @@ impl CurrentLoop {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for CurrentLoop {
|
impl AbstractMeasurement for CurrentLoop {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -261,7 +261,7 @@ impl MagneticLoop {
|
|||||||
region: r,
|
region: r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> (f32, f32, f32) {
|
fn data(&self, state: &dyn GenericSim) -> (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),
|
||||||
@@ -303,7 +303,7 @@ impl MagneticLoop {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for MagneticLoop {
|
impl AbstractMeasurement for MagneticLoop {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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}",
|
||||||
@@ -312,7 +312,7 @@ impl AbstractMeasurement for MagneticLoop {
|
|||||||
self.name, mean_directed_h,
|
self.name, mean_directed_h,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn key_value(&self, state: &dyn SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -336,7 +336,7 @@ impl MagneticFlux {
|
|||||||
region: Box::new(r)
|
region: Box::new(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> Vec3<f32> {
|
fn data(&self, state: &dyn GenericSim) -> 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();
|
||||||
@@ -349,11 +349,11 @@ impl MagneticFlux {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for MagneticFlux {
|
impl AbstractMeasurement for MagneticFlux {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -375,7 +375,7 @@ impl Magnetization {
|
|||||||
region: Box::new(r)
|
region: Box::new(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> Vec3<f32> {
|
fn data(&self, state: &dyn GenericSim) -> 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();
|
||||||
@@ -388,11 +388,11 @@ impl Magnetization {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Magnetization {
|
impl AbstractMeasurement for Magnetization {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -410,11 +410,11 @@ pub struct MagnetizationAt(pub Meters);
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for MagnetizationAt {
|
impl AbstractMeasurement for MagnetizationAt {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -428,11 +428,11 @@ pub struct MagneticFluxAt(pub Meters);
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for MagneticFluxAt {
|
impl AbstractMeasurement for MagneticFluxAt {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -446,11 +446,11 @@ pub struct MagneticStrengthAt(pub Meters);
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for MagneticStrengthAt {
|
impl AbstractMeasurement for MagneticStrengthAt {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -463,11 +463,11 @@ pub struct ElectricField(pub Meters);
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for ElectricField {
|
impl AbstractMeasurement for ElectricField {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -491,7 +491,7 @@ impl Energy {
|
|||||||
region: Box::new(region),
|
region: Box::new(region),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> f32 {
|
fn data(&self, state: &dyn GenericSim) -> 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
|
||||||
@@ -510,11 +510,11 @@ impl Energy {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Energy {
|
impl AbstractMeasurement for Energy {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
@@ -538,7 +538,7 @@ impl Power {
|
|||||||
region: Box::new(region),
|
region: Box::new(region),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn data(&self, state: &dyn SampleableSim) -> f32 {
|
fn data(&self, state: &dyn GenericSim) -> 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)]
|
||||||
@@ -552,11 +552,11 @@ impl Power {
|
|||||||
|
|
||||||
#[typetag::serde]
|
#[typetag::serde]
|
||||||
impl AbstractMeasurement for Power {
|
impl AbstractMeasurement for Power {
|
||||||
fn eval(&self, state: &dyn SampleableSim) -> String {
|
fn eval(&self, state: &dyn GenericSim) -> 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 SampleableSim) -> IndexMap<String, String> {
|
fn key_value(&self, state: &dyn GenericSim) -> 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()),
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
use crate::geom::Meters;
|
use crate::geom::Meters;
|
||||||
use crate::real::ToFloat as _;
|
use crate::real::ToFloat as _;
|
||||||
use crate::cross::vec::{Vec2, Vec3};
|
use crate::cross::vec::{Vec2, Vec3};
|
||||||
use crate::sim::{SampleableSim, Sample, StaticSim};
|
use crate::sim::{GenericSim, Sample, StaticSim};
|
||||||
use crate::meas::{self, AbstractMeasurement};
|
use crate::meas::{self, AbstractMeasurement};
|
||||||
use crossterm::{cursor, QueueableCommand as _};
|
use crossterm::{cursor, QueueableCommand as _};
|
||||||
use crossterm::style::{style, Color, PrintStyledContent, Stylize as _};
|
use crossterm::style::{style, Color, PrintStyledContent, Stylize as _};
|
||||||
@@ -55,7 +55,7 @@ fn scale_vector(x: Vec2<f32>, typical_mag: f32) -> Vec2<f32> {
|
|||||||
x.with_mag(new_mag)
|
x.with_mag(new_mag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn im_size<S: SampleableSim>(state: &S, max_w: u32, max_h: u32) -> (u32, u32) {
|
fn im_size<S: GenericSim>(state: &S, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||||
let mut width = max_w;
|
let mut width = max_w;
|
||||||
let mut height = width * state.height() / state.width();
|
let mut height = width * state.height() / state.width();
|
||||||
if height > max_h {
|
if height > max_h {
|
||||||
@@ -134,7 +134,7 @@ struct RenderSteps<'a, S> {
|
|||||||
z: u32,
|
z: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S: SampleableSim> RenderSteps<'a, S> {
|
impl<'a, S: GenericSim> RenderSteps<'a, S> {
|
||||||
/// Render using default configuration constants
|
/// Render using default configuration constants
|
||||||
fn render(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
fn render(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
||||||
Self::render_configured(state, measurements, z, (640, 480), RenderConfig::default())
|
Self::render_configured(state, measurements, z, (640, 480), RenderConfig::default())
|
||||||
@@ -352,12 +352,12 @@ pub trait Renderer<S>: Send + Sync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_render_z_slice<S: SampleableSim, R: Renderer<S>>(
|
fn default_render_z_slice<S: GenericSim, R: Renderer<S>>(
|
||||||
me: &R, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig,
|
me: &R, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], 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: SampleableSim, R: Renderer<S>>(
|
fn default_render<S: GenericSim, R: Renderer<S>>(
|
||||||
me: &R, state: &S, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig
|
me: &R, state: &S, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig
|
||||||
) {
|
) {
|
||||||
me.render_z_slice(state, state.depth() / 2, measurements, config);
|
me.render_z_slice(state, state.depth() / 2, measurements, config);
|
||||||
@@ -386,7 +386,7 @@ fn default_render<S: SampleableSim, R: Renderer<S>>(
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ColorTermRenderer;
|
pub struct ColorTermRenderer;
|
||||||
|
|
||||||
impl<S: SampleableSim> Renderer<S> for ColorTermRenderer {
|
impl<S: GenericSim> Renderer<S> for ColorTermRenderer {
|
||||||
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
||||||
default_render(self, state, measurements, config)
|
default_render(self, state, measurements, config)
|
||||||
}
|
}
|
||||||
@@ -448,7 +448,7 @@ impl Y4MRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim> Renderer<S> for Y4MRenderer {
|
impl<S: GenericSim> Renderer<S> for Y4MRenderer {
|
||||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
||||||
default_render_z_slice(self, state, z, measurements, config)
|
default_render_z_slice(self, state, z, measurements, config)
|
||||||
}
|
}
|
||||||
@@ -540,7 +540,7 @@ impl<S> MultiRenderer<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim> Renderer<S> for MultiRenderer<S> {
|
impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
|
||||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
||||||
default_render_z_slice(self, state, z, measurements, config)
|
default_render_z_slice(self, state, z, measurements, config)
|
||||||
}
|
}
|
||||||
@@ -567,10 +567,10 @@ pub struct SerializedFrame<S=StaticSim> {
|
|||||||
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim> SerializedFrame<S> {
|
impl<S: GenericSim> SerializedFrame<S> {
|
||||||
pub fn to_static(self) -> SerializedFrame<StaticSim> {
|
pub fn to_static(self) -> SerializedFrame<StaticSim> {
|
||||||
SerializedFrame {
|
SerializedFrame {
|
||||||
state: SampleableSim::to_static(&self.state),
|
state: GenericSim::to_static(&self.state),
|
||||||
measurements: self.measurements,
|
measurements: self.measurements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,7 +605,7 @@ impl SerializerRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SerializerRenderer {
|
impl SerializerRenderer {
|
||||||
fn serialize<S: SampleableSim + Serialize>(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn serialize<S: GenericSim + Serialize>(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
let frame = SerializedFrame {
|
let frame = SerializedFrame {
|
||||||
state,
|
state,
|
||||||
measurements: measurements.iter().cloned().collect(),
|
measurements: measurements.iter().cloned().collect(),
|
||||||
@@ -616,13 +616,13 @@ impl SerializerRenderer {
|
|||||||
bincode::serialize_into(out, &frame).unwrap();
|
bincode::serialize_into(out, &frame).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_load<S: SampleableSim + for <'a> Deserialize<'a>>(&self) -> Option<SerializedFrame<S>> {
|
pub fn try_load<S: GenericSim + for <'a> Deserialize<'a>>(&self) -> Option<SerializedFrame<S>> {
|
||||||
let mut reader = BufReader::new(File::open(&*self.fmt_str).ok()?);
|
let mut reader = BufReader::new(File::open(&*self.fmt_str).ok()?);
|
||||||
bincode::deserialize_from(&mut reader).ok()
|
bincode::deserialize_from(&mut reader).ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim + Serialize> Renderer<S> for SerializerRenderer {
|
impl<S: GenericSim + Serialize> Renderer<S> for SerializerRenderer {
|
||||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
||||||
default_render_z_slice(self, state, z, measurements, config)
|
default_render_z_slice(self, state, z, measurements, config)
|
||||||
}
|
}
|
||||||
@@ -665,7 +665,7 @@ impl CsvRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SampleableSim> Renderer<S> for CsvRenderer {
|
impl<S: GenericSim> Renderer<S> for CsvRenderer {
|
||||||
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>], config: RenderConfig) {
|
||||||
default_render_z_slice(self, state, z, measurements, config)
|
default_render_z_slice(self, state, z, measurements, config)
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,7 @@ use crate::geom::{Coord, Index, Meters};
|
|||||||
use crate::cross::real::{R32, Real};
|
use crate::cross::real::{R32, Real};
|
||||||
use crate::cross::step::SimMeta;
|
use crate::cross::step::SimMeta;
|
||||||
use crate::cross::vec::{Vec3, Vec3u};
|
use crate::cross::vec::{Vec3, Vec3u};
|
||||||
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim, StaticSim};
|
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, StaticSim};
|
||||||
use crate::stim::AbstractStimulus;
|
use crate::stim::AbstractStimulus;
|
||||||
|
|
||||||
use mat::{GenericMaterial, Material, MaterialExt as _};
|
use mat::{GenericMaterial, Material, MaterialExt as _};
|
||||||
@@ -324,26 +324,16 @@ impl<R: Real, M: Material<R> + Clone + Send + Sync + PartialEq> MaterialSim for
|
|||||||
fn get_material<C: Coord>(&self, pos: C) -> &M {
|
fn get_material<C: Coord>(&self, pos: C) -> &M {
|
||||||
self.get_material(pos)
|
self.get_material(pos)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real, M: Material<R> + Send + Sync> SampleableSim for SimState<R, M> {
|
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S) {
|
||||||
fn sample(&self, pos: Meters) -> Sample {
|
for _ in 0..num_steps {
|
||||||
// TODO: smarter sampling than nearest neighbor?
|
self.apply_stimulus(s);
|
||||||
let pos_sim = pos.to_index(self.feature_size());
|
SimState::step(self);
|
||||||
let idx = [pos_sim.z() as usize, pos_sim.y() as _, pos_sim.x() as _];
|
|
||||||
match self.cells.get(idx) {
|
|
||||||
Some(mat) => Sample {
|
|
||||||
state: CellStateWithM {
|
|
||||||
e: self.e[idx].cast(),
|
|
||||||
h: self.h[idx].cast(),
|
|
||||||
m: mat.m().cast(),
|
|
||||||
},
|
|
||||||
conductivity: mat.conductivity().cast(),
|
|
||||||
},
|
|
||||||
None => Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Real, M: Material<R> + Send + Sync> GenericSim for SimState<R, M> {
|
||||||
fn meta(&self) -> SimMeta<f32> {
|
fn meta(&self) -> SimMeta<f32> {
|
||||||
let dim = Vec3u::new(
|
let dim = Vec3u::new(
|
||||||
self.cells.shape()[2] as _,
|
self.cells.shape()[2] as _,
|
||||||
@@ -361,21 +351,28 @@ impl<R: Real, M: Material<R> + Send + Sync> SampleableSim for SimState<R, M> {
|
|||||||
self.step_no
|
self.step_no
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sample(&self, pos: Meters) -> Sample {
|
||||||
|
// TODO: smarter sampling than nearest neighbor?
|
||||||
|
let pos_sim = pos.to_index(self.feature_size());
|
||||||
|
let idx = [pos_sim.z() as usize, pos_sim.y() as _, pos_sim.x() as _];
|
||||||
|
match self.cells.get(idx) {
|
||||||
|
Some(mat) => Sample {
|
||||||
|
state: CellStateWithM {
|
||||||
|
e: self.e[idx].cast(),
|
||||||
|
h: self.h[idx].cast(),
|
||||||
|
m: mat.m().cast(),
|
||||||
|
},
|
||||||
|
conductivity: mat.conductivity().cast(),
|
||||||
|
},
|
||||||
|
None => Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_static(&self) -> StaticSim {
|
fn to_static(&self) -> StaticSim {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<R: Real, M: Material<R> + Send + Sync> GenericSim for SimState<R, M> {
|
|
||||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S) {
|
|
||||||
for _ in 0..num_steps {
|
|
||||||
self.apply_stimulus(s);
|
|
||||||
SimState::step(self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
impl<R: Real, M> SimState<R, M> {
|
impl<R: Real, M> SimState<R, M> {
|
||||||
fn get_material<C: Coord>(&self, c: C) -> &M {
|
fn get_material<C: Coord>(&self, c: C) -> &M {
|
||||||
@@ -1204,14 +1201,14 @@ mod test {
|
|||||||
assert_vec3_eq(actual_df_dt, df_dt(tm));
|
assert_vec3_eq(actual_df_dt, df_dt(tm));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn energy(s: &dyn SampleableSim) -> f32 {
|
fn energy(s: &dyn GenericSim) -> 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()
|
||||||
}).to_f32()
|
}).to_f32()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn energy_now_and_then<S: GenericSim>(state: &mut S, frames: u32) -> (f32, f32) {
|
fn energy_now_and_then<S: MaterialSim>(state: &mut S, frames: u32) -> (f32, f32) {
|
||||||
let energy_0 = energy(state);
|
let energy_0 = energy(state);
|
||||||
for _f in 0..frames {
|
for _f in 0..frames {
|
||||||
// println!("e({}) = {}", _f, energy(state));
|
// println!("e({}) = {}", _f, energy(state));
|
||||||
@@ -1394,7 +1391,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the energy ratio (Eend / Estart)
|
/// Returns the energy ratio (Eend / Estart)
|
||||||
fn pml_test_full_interior<F, S: GenericSim>(state: &mut S, f: F) -> f32
|
fn pml_test_full_interior<F, S: MaterialSim>(state: &mut S, f: F) -> f32
|
||||||
where F: Fn(Index) -> (Vec3<f32>, f32) + Sync // returns (E vector, cycles (like Hz))
|
where F: Fn(Index) -> (Vec3<f32>, f32) + Sync // returns (E vector, cycles (like Hz))
|
||||||
{
|
{
|
||||||
let stim = PmlStim {
|
let stim = PmlStim {
|
||||||
@@ -1418,7 +1415,7 @@ mod test {
|
|||||||
where
|
where
|
||||||
R: Region,
|
R: Region,
|
||||||
F: Fn(Index) -> (Vec3<f32>, f32) + Sync,
|
F: Fn(Index) -> (Vec3<f32>, f32) + Sync,
|
||||||
S: GenericSim
|
S: MaterialSim
|
||||||
{
|
{
|
||||||
let feat = state.feature_size();
|
let feat = state.feature_size();
|
||||||
pml_test_full_interior(state, |idx| {
|
pml_test_full_interior(state, |idx| {
|
||||||
@@ -1430,7 +1427,7 @@ mod test {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pml_test_at<S: GenericSim>(state: &mut S, e: Vec3<f32>, center: Index) -> f32 {
|
fn pml_test_at<S: MaterialSim>(state: &mut S, e: Vec3<f32>, center: Index) -> f32 {
|
||||||
pml_test_full_interior(state, |idx| {
|
pml_test_full_interior(state, |idx| {
|
||||||
if idx == center {
|
if idx == center {
|
||||||
(e, 1.0)
|
(e, 1.0)
|
||||||
@@ -1440,14 +1437,14 @@ mod test {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pml_test<S: GenericSim, R: RangeBounds<f32> + Debug>(state: &mut S, e: Vec3<f32>, en_range: R) {
|
fn pml_test<S: MaterialSim, R: RangeBounds<f32> + Debug>(state: &mut S, e: Vec3<f32>, en_range: R) {
|
||||||
let center = Index(state.size().0 / 2);
|
let center = Index(state.size().0 / 2);
|
||||||
let pml = pml_test_at(state, e, center);
|
let pml = pml_test_at(state, e, center);
|
||||||
// PML should absorb all energy
|
// PML should absorb all energy
|
||||||
assert!(en_range.contains(&pml), "{} not in {:?}", pml, en_range);
|
assert!(en_range.contains(&pml), "{} not in {:?}", pml, en_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pml_test_against_baseline<P: GenericSim, B: GenericSim>(pml_state: &mut P, baseline_state: &mut B, e: Vec3<f32>) {
|
fn pml_test_against_baseline<P: MaterialSim, B: MaterialSim>(pml_state: &mut P, baseline_state: &mut B, e: Vec3<f32>) {
|
||||||
assert_eq!(pml_state.size(), baseline_state.size());
|
assert_eq!(pml_state.size(), baseline_state.size());
|
||||||
let center = Index(pml_state.size().0 / 2);
|
let center = Index(pml_state.size().0 / 2);
|
||||||
let en_pml = pml_test_at(pml_state, e, center);
|
let en_pml = pml_test_at(pml_state, e, center);
|
||||||
|
@@ -23,6 +23,12 @@ pub trait MaterialSim: GenericSim {
|
|||||||
fn put_material<C: Coord, M: Into<Self::Material>>(&mut self, pos: C, mat: M);
|
fn put_material<C: Coord, M: Into<Self::Material>>(&mut self, pos: C, mat: M);
|
||||||
fn get_material<C: Coord>(&self, pos: C) -> &Self::Material;
|
fn get_material<C: Coord>(&self, pos: C) -> &Self::Material;
|
||||||
|
|
||||||
|
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S);
|
||||||
|
fn step(&mut self) {
|
||||||
|
// XXX: try not to exercise this path! NoopStimulus is probably a lot of waste.
|
||||||
|
self.step_multiple(1, &NoopStimulus);
|
||||||
|
}
|
||||||
|
|
||||||
fn fill_region_using<C, Reg, F, M>(&mut self, region: &Reg, f: F)
|
fn fill_region_using<C, Reg, F, M>(&mut self, region: &Reg, f: F)
|
||||||
where
|
where
|
||||||
Reg: Region,
|
Reg: Region,
|
||||||
@@ -121,14 +127,6 @@ pub trait MaterialSim: GenericSim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GenericSim: SampleableSim {
|
|
||||||
fn step(&mut self) {
|
|
||||||
// XXX: try not to exercise this path! NoopStimulus is probably a lot of waste.
|
|
||||||
self.step_multiple(1, &NoopStimulus);
|
|
||||||
}
|
|
||||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Conceptually, one cell looks like this (in 2d):
|
/// Conceptually, one cell looks like this (in 2d):
|
||||||
///
|
///
|
||||||
/// +-------.-------+
|
/// +-------.-------+
|
||||||
@@ -219,7 +217,7 @@ impl<R: Real> CellStateWithM<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> dyn SampleableSim + 'a {
|
impl<'a> dyn GenericSim + 'a {
|
||||||
pub fn get<C: Coord>(&self, at: C) -> Sample {
|
pub fn get<C: Coord>(&self, at: C) -> Sample {
|
||||||
self.sample(at.to_meters(self.feature_size()))
|
self.sample(at.to_meters(self.feature_size()))
|
||||||
}
|
}
|
||||||
@@ -291,10 +289,10 @@ impl<'a> dyn SampleableSim + 'a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 SampleableSim: Send + Sync {
|
pub trait GenericSim: Send + Sync {
|
||||||
fn sample(&self, pos: Meters) -> Sample;
|
|
||||||
fn meta(&self) -> SimMeta<f32>;
|
fn meta(&self) -> SimMeta<f32>;
|
||||||
fn step_no(&self) -> u64;
|
fn step_no(&self) -> u64;
|
||||||
|
fn sample(&self, pos: Meters) -> Sample;
|
||||||
|
|
||||||
/// Take a "snapshot" of the simulation, dropping all material-specific information.
|
/// Take a "snapshot" of the simulation, dropping all material-specific information.
|
||||||
fn to_static(&self) -> StaticSim;
|
fn to_static(&self) -> StaticSim;
|
||||||
|
@@ -4,7 +4,7 @@ use log::{info, trace, warn};
|
|||||||
|
|
||||||
use crate::geom::{Coord, Index, Meters};
|
use crate::geom::{Coord, Index, Meters};
|
||||||
use crate::real::Real;
|
use crate::real::Real;
|
||||||
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim, StaticSim};
|
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, StaticSim};
|
||||||
use crate::stim::AbstractStimulus;
|
use crate::stim::AbstractStimulus;
|
||||||
use crate::cross::vec::Vec3;
|
use crate::cross::vec::Vec3;
|
||||||
use coremem_cross::mat::{FullyGenericMaterial, Material};
|
use coremem_cross::mat::{FullyGenericMaterial, Material};
|
||||||
@@ -88,14 +88,36 @@ where
|
|||||||
let flat_idx = self.flat_index(pos_sim).unwrap();
|
let flat_idx = self.flat_index(pos_sim).unwrap();
|
||||||
&self.mat[flat_idx]
|
&self.mat[flat_idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, stim: &S) {
|
||||||
|
let (stim_e, stim_h) = self.eval_stimulus(stim);
|
||||||
|
self.backend.step_n(
|
||||||
|
self.meta,
|
||||||
|
self.mat.as_slice(),
|
||||||
|
stim_e.as_slice().unwrap(),
|
||||||
|
stim_h.as_slice().unwrap(),
|
||||||
|
self.e.as_mut_slice(),
|
||||||
|
self.h.as_mut_slice(),
|
||||||
|
self.m.as_mut_slice(),
|
||||||
|
num_steps,
|
||||||
|
);
|
||||||
|
self.step_no += num_steps as u64;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, M, B> SampleableSim for SpirvSim<R, M, B>
|
impl<R, M, B> GenericSim for SpirvSim<R, M, B>
|
||||||
where
|
where
|
||||||
R: Real,
|
R: Real,
|
||||||
M: Send + Sync + Material<R>,
|
M: Send + Sync + Material<R>,
|
||||||
B: Send + Sync,
|
B: Send + Sync + SimBackend<R, M>,
|
||||||
{
|
{
|
||||||
|
fn meta(&self) -> SimMeta<f32> {
|
||||||
|
self.meta.cast()
|
||||||
|
}
|
||||||
|
fn step_no(&self) -> u64 {
|
||||||
|
self.step_no
|
||||||
|
}
|
||||||
|
|
||||||
fn sample(&self, pos: Meters) -> Sample {
|
fn sample(&self, pos: Meters) -> Sample {
|
||||||
// TODO: smarter sampling than nearest neighbor?
|
// TODO: smarter sampling than nearest neighbor?
|
||||||
let pos_sim = pos.to_index(self.feature_size());
|
let pos_sim = pos.to_index(self.feature_size());
|
||||||
@@ -113,13 +135,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn meta(&self) -> SimMeta<f32> {
|
|
||||||
self.meta.cast()
|
|
||||||
}
|
|
||||||
fn step_no(&self) -> u64 {
|
|
||||||
self.step_no
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_static(&self) -> StaticSim {
|
fn to_static(&self) -> StaticSim {
|
||||||
let mut mat = Vec::new();
|
let mut mat = Vec::new();
|
||||||
mat.resize(self.e.len(), Default::default());
|
mat.resize(self.e.len(), Default::default());
|
||||||
@@ -135,28 +150,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, M, B> GenericSim for SpirvSim<R, M, B>
|
|
||||||
where
|
|
||||||
R: Real,
|
|
||||||
M: Send + Sync + Material<R>,
|
|
||||||
B: Send + Sync + SimBackend<R, M>
|
|
||||||
{
|
|
||||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, stim: &S) {
|
|
||||||
let (stim_e, stim_h) = self.eval_stimulus(stim);
|
|
||||||
self.backend.step_n(
|
|
||||||
self.meta,
|
|
||||||
self.mat.as_slice(),
|
|
||||||
stim_e.as_slice().unwrap(),
|
|
||||||
stim_h.as_slice().unwrap(),
|
|
||||||
self.e.as_mut_slice(),
|
|
||||||
self.h.as_mut_slice(),
|
|
||||||
self.m.as_mut_slice(),
|
|
||||||
num_steps,
|
|
||||||
);
|
|
||||||
self.step_no += num_steps as u64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real, M: Default, B> SpirvSim<R, M, B>
|
impl<R: Real, M: Default, B> SpirvSim<R, M, B>
|
||||||
{
|
{
|
||||||
pub fn new_with_backend(size: Index, feature_size: f32, backend: B) -> Self {
|
pub fn new_with_backend(size: Index, feature_size: f32, backend: B) -> Self {
|
||||||
@@ -279,20 +272,20 @@ where
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::real::ToFloat as _;
|
use crate::real::ToFloat as _;
|
||||||
use crate::sim::SampleableSim;
|
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 SampleableSim) -> f32 {
|
fn mean_magnitude_e(sim: &dyn GenericSim) -> 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 SampleableSim) -> f32 {
|
fn mean_magnitude_h(sim: &dyn GenericSim) -> 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 SampleableSim) -> f32 {
|
fn mean_magnitude_m(sim: &dyn GenericSim) -> 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()
|
||||||
@@ -309,8 +302,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 SampleableSim).get(idx);
|
let real_cell = (real_state as &dyn GenericSim).get(idx);
|
||||||
let ref_cell = (ref_state as &dyn SampleableSim).get(idx);
|
let ref_cell = (ref_state as &dyn GenericSim).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();
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
//! Post-processing tools
|
//! Post-processing tools
|
||||||
use coremem::meas::AbstractMeasurement;
|
use coremem::meas::AbstractMeasurement;
|
||||||
use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame};
|
use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame};
|
||||||
use coremem::sim::{SampleableSim, StaticSim};
|
use coremem::sim::{GenericSim, StaticSim};
|
||||||
|
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
|
Reference in New Issue
Block a user