Driver: parameterize over the Stimulus type

This commit is contained in:
2022-08-12 14:47:45 -07:00
parent e141047bec
commit a74e7fa9a0

View File

@@ -1,5 +1,5 @@
use crate::diagnostics::SyncDiagnostics;
use crate::geom::{Coord, Index, Meters, Region};
use crate::geom::{Coord, Index, Region};
use crate::mat;
use crate::meas::{self, AbstractMeasurement};
use crate::real::Real;
@@ -16,14 +16,14 @@ use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
use std::time::Instant;
use threadpool::ThreadPool;
pub struct Driver<S> {
pub struct Driver<S, Stim=DynStimuli> {
state: S,
renderer: Arc<MultiRenderer<S>>,
// TODO: use Rayon's thread pool?
render_pool: ThreadPool,
render_channel: (SyncSender<()>, Receiver<()>),
measurements: Vec<Arc<dyn AbstractMeasurement<S>>>,
stimuli: DynStimuli,
stimuli: Stim,
/// simulation end time
sim_end_time: Option<Frame>,
diag: SyncDiagnostics,
@@ -33,7 +33,7 @@ pub struct Driver<S> {
/// generic stimuli collection which monomorphizes everything by boxing it.
pub type DynStimuli = Vec<Box<dyn AbstractStimulus>>;
impl<S: AbstractSim> Driver<S> {
impl<S: AbstractSim, Stim: Default> Driver<S, Stim> {
pub fn new(mut state: S) -> Self {
let diag = SyncDiagnostics::new();
state.use_diagnostics(diag.clone());
@@ -48,23 +48,25 @@ impl<S: AbstractSim> Driver<S> {
Arc::new(meas::Energy::world()),
Arc::new(meas::Power::world()),
],
stimuli: DynStimuli::new(),
stimuli: Default::default(),
sim_end_time: None,
diag,
last_diag_time: Instant::now(),
}
}
pub fn add_stimulus<Stim: AbstractStimulus + 'static>(&mut self, s: Stim) {
self.stimuli.push(Box::new(s))
}
pub fn add_measurement<Meas: AbstractMeasurement<S> + 'static>(&mut self, m: Meas) {
self.measurements.push(Arc::new(m));
}
}
impl<S: AbstractSim> Driver<S> {
impl<S> Driver<S, DynStimuli> {
pub fn add_stimulus<Stim: AbstractStimulus + 'static>(&mut self, s: Stim) {
self.stimuli.push(Box::new(s))
}
}
impl<S: AbstractSim, Stim> Driver<S, Stim> {
pub fn fill_region<Reg: Region, M: Into<S::Material> + Clone>(&mut self, region: &Reg, mat: M) {
self.state.fill_region(region, mat);
}
@@ -75,9 +77,7 @@ impl<S: AbstractSim> Driver<S> {
{
self.state.test_region_filled(region, mat)
}
}
impl<S: AbstractSim> Driver<S> {
pub fn size(&self) -> Index {
self.state.size()
}
@@ -87,9 +87,31 @@ impl<S: AbstractSim> Driver<S> {
pub fn time(&self) -> f32 {
self.state.time()
}
pub fn add_classical_boundary<C: Coord>(&mut self, thickness: C)
where S::Material: From<mat::IsomorphicConductor<f32>>
{
self.add_classical_boundary_explicit::<f32, _>(thickness)
}
/// the CPU code is parameterized over `Real`: you'll need to use this interface to get access
/// to that, if using a CPU driver. otherwise, use `add_classical_boundary`
pub fn add_classical_boundary_explicit<R: Real, C: Coord>(&mut self, thickness: C)
where S::Material: From<mat::IsomorphicConductor<R>>
{
let timestep = self.state.timestep();
self.state.fill_boundary_using(thickness, |boundary_ness| {
let b = boundary_ness.elem_pow(3.0);
let cond = b * (0.5 / timestep);
let iso_cond = cond.x() + cond.y() + cond.z();
let iso_conductor = mat::IsomorphicConductor::new(iso_cond.cast());
iso_conductor
});
}
}
impl<S: AbstractSim + 'static> Driver<S> {
impl<S: AbstractSim + 'static, Stim> Driver<S, Stim> {
fn add_renderer<Rend: Renderer<S> + 'static>(
&mut self, renderer: Rend, name: &str, step_frequency: u64, frame_limit: Option<u64>
) {
@@ -112,14 +134,17 @@ impl<S: AbstractSim + 'static> Driver<S> {
}
}
impl<S: AbstractSim + Serialize + 'static> Driver<S> {
impl<S: AbstractSim + Serialize + 'static, Stim> Driver<S, Stim> {
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);
self.add_renderer(render::SerializerRenderer::new_generic(&*fmt_str), &*fmt_str, step_frequency, frame_limit);
}
}
impl<S: AbstractSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static> Driver<S> {
impl<S, Stim> Driver<S, Stim>
where
S: AbstractSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'static
{
/// 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.
pub fn add_state_file(&mut self, state_file: &str, snapshot_frequency: u64) -> bool {
@@ -133,7 +158,11 @@ impl<S: AbstractSim + Send + Sync + Serialize + for<'a> Deserialize<'a> + 'stati
}
}
impl<S: AbstractSim + Clone + Default + Send + 'static> Driver<S> {
impl<S, Stim> Driver<S, Stim>
where
S: AbstractSim + Clone + Default + Send + 'static,
Stim: AbstractStimulus,
{
fn render(&mut self) {
self.diag.instrument_render_prep(|| {
let diag_handle = self.diag.clone();
@@ -223,27 +252,3 @@ impl<S: AbstractSim + Clone + Default + Send + 'static> Driver<S> {
self.sim_end_time = None;
}
}
impl<S: AbstractSim> Driver<S> {
pub fn add_classical_boundary<C: Coord>(&mut self, thickness: C)
where S::Material: From<mat::IsomorphicConductor<f32>>
{
self.add_classical_boundary_explicit::<f32, _>(thickness)
}
/// the CPU code is parameterized over `Real`: you'll need to use this interface to get access
/// to that, if using a CPU driver. otherwise, use `add_classical_boundary`
pub fn add_classical_boundary_explicit<R: Real, C: Coord>(&mut self, thickness: C)
where S::Material: From<mat::IsomorphicConductor<R>>
{
let timestep = self.state.timestep();
self.state.fill_boundary_using(thickness, |boundary_ness| {
let b = boundary_ness.elem_pow(3.0);
let cond = b * (0.5 / timestep);
let iso_cond = cond.x() + cond.y() + cond.z();
let iso_conductor = mat::IsomorphicConductor::new(iso_cond.cast());
iso_conductor
});
}
}