Driver: parameterize over the Stimulus type
This commit is contained in:
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user