add Stimulus::render() and use it inside the driver and SpirvSim

This commit is contained in:
colin 2022-08-20 17:36:23 -07:00
parent d662ef24d3
commit 053943df01
3 changed files with 59 additions and 49 deletions

View File

@ -14,7 +14,6 @@ use crate::stim::{
Stimulus,
StimuliVec,
TimeVarying,
RenderedStimulus,
VectorField,
};
use coremem_cross::compound::list;
@ -262,9 +261,10 @@ where
}
trace!("step begin");
self.diag.instrument_step(can_step as u64, || {
let stim = self.stimuli.optimized_for(self.state.meta(), start_step);
let stim = stim_to_vector_field(self.state.meta(), self.state.time(), stim.as_ref());
self.state.step_multiple(can_step, &stim);
let meta = self.state.meta();
let stim = self.stimuli.optimized_for(meta, start_step);
let stim = stim.as_ref().rendered(meta.time_step(), self.state.time().cast(), meta.feature_size(), meta.dim());
self.state.step_multiple(can_step, &*stim);
});
trace!("step end");
if self.last_diag_time.elapsed().as_secs_f64() >= 5.0 {
@ -428,42 +428,3 @@ impl<T: TimeVarying> DriverStimulus for DriverStimulusModulated<T> {
/// a Stimulus where the field has been pre-calculated
pub type ModulatedStaticField<T> = ModulatedVectorField<DimSlice<Vec<Fields>>, T>;
pub type StaticFields = RenderedStimulus;
fn stim_to_vector_field<S: Stimulus>(meta: SimMeta<f32>, t_sec: f32, stim: &S) -> StaticFields {
let dim = meta.dim();
let dim_len = dim.product_sum_usize();
let feature_size = meta.feature_size();
let time_step = meta.time_step();
let mut e = Vec::new();
e.resize_with(dim_len, Default::default);
let mut h = Vec::new();
h.resize_with(dim_len, Default::default);
rayon::scope(|s| {
let mut undispatched_e = &mut e[..];
let mut undispatched_h = &mut h[..];
for z in 0..dim.z() {
for y in 0..dim.y() {
let (this_e, this_h);
(this_e, undispatched_e) = undispatched_e.split_at_mut(dim.x() as usize);
(this_h, undispatched_h) = undispatched_h.split_at_mut(dim.x() as usize);
s.spawn(move |_| {
for (x, (out_e, out_h)) in this_e.iter_mut().zip(this_h.iter_mut()).enumerate() {
let Fields { e, h } = stim.at(t_sec, feature_size, Index::new(x as u32, y, z));
*out_e = e * time_step;
*out_h = h * time_step;
}
});
}
}
});
let field_e = DimSlice::new(dim, e);
let field_h = DimSlice::new(dim, h);
RenderedStimulus::new(
field_e, field_h, time_step, feature_size, t_sec
)
}

View File

@ -5,7 +5,7 @@ use crate::diagnostics::SyncDiagnostics;
use crate::geom::Index;
use crate::real::Real;
use crate::sim::{AbstractSim, Fields, GenericSim, StaticSim};
use crate::stim::{Stimulus, RenderedStimulus};
use crate::stim::Stimulus;
use coremem_cross::mat::{FullyGenericMaterial, Material};
use coremem_cross::step::SimMeta;
use coremem_cross::vec::Vec3;
@ -234,15 +234,12 @@ where
let t_sec = self.time();
let timestep = self.meta.time_step;
// TODO: use `Stimulus::render()` instead
let stim: &RenderedStimulus = unsafe { std::mem::transmute(stim) };
let stim = stim.rendered(timestep.cast(), t_sec, feature_size, dim.into());
assert_eq!(stim.scale(), timestep.cast());
assert_eq!(stim.feature_size(), feature_size);
assert_eq!(stim.time(), t_sec);
let (e, h) = (stim.e().into_inner(), stim.h().into_inner());
assert_eq!(e.len(), dim_len);
assert_eq!(h.len(), dim_len);
// TODO: find a way to remove this
unsafe { std::mem::transmute((e, h)) }
});
trace!("eval_stimulus end");

View File

@ -5,6 +5,7 @@ use coremem_cross::compound::list::{Visit, Visitor};
use coremem_cross::dim::{DimSlice, OffsetDimSlice};
use coremem_cross::vec::Vec3u;
use std::borrow::Cow;
use std::ops::Deref;
use rand;
@ -126,6 +127,47 @@ pub trait Stimulus: Sync {
*out += self.at(t_sec, feat_size, Index::from(idx));
}
}
/// compute the value of this stimulus across all the simulation space
fn rendered<'a>(
&'a self, scale: f32, t_sec: f32, feature_size: f32, dim: Vec3u
) -> Cow<'a, RenderedStimulus> {
Cow::Owned(render_stim(self, scale, t_sec, feature_size, dim))
}
}
fn render_stim<S: Stimulus + ?Sized>(
stim: &S, scale: f32, t_sec: f32, feature_size: f32, dim: Vec3u
) -> RenderedStimulus {
let dim_len = dim.product_sum_usize();
let mut e = Vec::new();
e.resize_with(dim_len, Default::default);
let mut h = Vec::new();
h.resize_with(dim_len, Default::default);
rayon::scope(|s| {
let mut undispatched_e = &mut e[..];
let mut undispatched_h = &mut h[..];
for z in 0..dim.z() {
for y in 0..dim.y() {
let (this_e, this_h);
(this_e, undispatched_e) = undispatched_e.split_at_mut(dim.x() as usize);
(this_h, undispatched_h) = undispatched_h.split_at_mut(dim.x() as usize);
s.spawn(move |_| {
for (x, (out_e, out_h)) in this_e.iter_mut().zip(this_h.iter_mut()).enumerate() {
let Fields { e, h } = stim.at(t_sec, feature_size, Index::new(x as u32, y, z));
*out_e = e * scale;
*out_h = h * scale;
}
});
}
}
});
let field_e = DimSlice::new(dim, e);
let field_h = DimSlice::new(dim, h);
RenderedStimulus::new(
field_e, field_h, scale, feature_size, t_sec
)
}
/// a static vector field. different value at each location, but constant in time.
@ -153,6 +195,7 @@ where
}
}
#[derive(Clone)]
pub struct RenderedStimulus {
e: DimSlice<Vec<Vec3<f32>>>,
h: DimSlice<Vec<Vec3<f32>>>,
@ -197,6 +240,15 @@ impl Stimulus for RenderedStimulus {
fn at(&self, _t_sec: f32, _feat_size: f32, loc: Index) -> Fields {
Fields::new_eh(self.e[loc.into()], self.h[loc.into()])
}
fn rendered<'a>(
&'a self, scale: f32, t_sec: f32, feature_size: f32, dim: Vec3u
) -> Cow<'a, RenderedStimulus> {
if (self.scale, self.t_sec, self.feature_size, self.e.dim()) == (scale, t_sec, feature_size, dim) {
Cow::Borrowed(self)
} else {
Cow::Owned(render_stim(self, scale, t_sec, feature_size, dim))
}
}
}
impl Stimulus for Fields {