Driver: parameterize over the Stimulus type
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use crate::diagnostics::SyncDiagnostics;
|
use crate::diagnostics::SyncDiagnostics;
|
||||||
use crate::geom::{Coord, Index, Meters, Region};
|
use crate::geom::{Coord, Index, Region};
|
||||||
use crate::mat;
|
use crate::mat;
|
||||||
use crate::meas::{self, AbstractMeasurement};
|
use crate::meas::{self, AbstractMeasurement};
|
||||||
use crate::real::Real;
|
use crate::real::Real;
|
||||||
@@ -16,14 +16,14 @@ use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use threadpool::ThreadPool;
|
use threadpool::ThreadPool;
|
||||||
|
|
||||||
pub struct Driver<S> {
|
pub struct Driver<S, Stim=DynStimuli> {
|
||||||
state: S,
|
state: S,
|
||||||
renderer: Arc<MultiRenderer<S>>,
|
renderer: Arc<MultiRenderer<S>>,
|
||||||
// TODO: use Rayon's thread pool?
|
// TODO: use Rayon's thread pool?
|
||||||
render_pool: ThreadPool,
|
render_pool: ThreadPool,
|
||||||
render_channel: (SyncSender<()>, Receiver<()>),
|
render_channel: (SyncSender<()>, Receiver<()>),
|
||||||
measurements: Vec<Arc<dyn AbstractMeasurement<S>>>,
|
measurements: Vec<Arc<dyn AbstractMeasurement<S>>>,
|
||||||
stimuli: DynStimuli,
|
stimuli: Stim,
|
||||||
/// simulation end time
|
/// simulation end time
|
||||||
sim_end_time: Option<Frame>,
|
sim_end_time: Option<Frame>,
|
||||||
diag: SyncDiagnostics,
|
diag: SyncDiagnostics,
|
||||||
@@ -33,7 +33,7 @@ pub struct Driver<S> {
|
|||||||
/// generic stimuli collection which monomorphizes everything by boxing it.
|
/// generic stimuli collection which monomorphizes everything by boxing it.
|
||||||
pub type DynStimuli = Vec<Box<dyn AbstractStimulus>>;
|
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 {
|
pub fn new(mut state: S) -> Self {
|
||||||
let diag = SyncDiagnostics::new();
|
let diag = SyncDiagnostics::new();
|
||||||
state.use_diagnostics(diag.clone());
|
state.use_diagnostics(diag.clone());
|
||||||
@@ -48,23 +48,25 @@ impl<S: AbstractSim> Driver<S> {
|
|||||||
Arc::new(meas::Energy::world()),
|
Arc::new(meas::Energy::world()),
|
||||||
Arc::new(meas::Power::world()),
|
Arc::new(meas::Power::world()),
|
||||||
],
|
],
|
||||||
stimuli: DynStimuli::new(),
|
stimuli: Default::default(),
|
||||||
sim_end_time: None,
|
sim_end_time: None,
|
||||||
diag,
|
diag,
|
||||||
last_diag_time: Instant::now(),
|
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) {
|
pub fn add_measurement<Meas: AbstractMeasurement<S> + 'static>(&mut self, m: Meas) {
|
||||||
self.measurements.push(Arc::new(m));
|
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) {
|
pub fn fill_region<Reg: Region, M: Into<S::Material> + Clone>(&mut self, region: &Reg, mat: M) {
|
||||||
self.state.fill_region(region, mat);
|
self.state.fill_region(region, mat);
|
||||||
}
|
}
|
||||||
@@ -75,9 +77,7 @@ impl<S: AbstractSim> Driver<S> {
|
|||||||
{
|
{
|
||||||
self.state.test_region_filled(region, mat)
|
self.state.test_region_filled(region, mat)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: AbstractSim> Driver<S> {
|
|
||||||
pub fn size(&self) -> Index {
|
pub fn size(&self) -> Index {
|
||||||
self.state.size()
|
self.state.size()
|
||||||
}
|
}
|
||||||
@@ -87,9 +87,31 @@ impl<S: AbstractSim> Driver<S> {
|
|||||||
pub fn time(&self) -> f32 {
|
pub fn time(&self) -> f32 {
|
||||||
self.state.time()
|
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>(
|
fn add_renderer<Rend: Renderer<S> + 'static>(
|
||||||
&mut self, renderer: Rend, name: &str, step_frequency: u64, frame_limit: Option<u64>
|
&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>) {
|
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_generic(&*fmt_str), &*fmt_str, step_frequency, frame_limit);
|
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.
|
/// 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 {
|
||||||
@@ -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) {
|
fn render(&mut self) {
|
||||||
self.diag.instrument_render_prep(|| {
|
self.diag.instrument_render_prep(|| {
|
||||||
let diag_handle = self.diag.clone();
|
let diag_handle = self.diag.clone();
|
||||||
@@ -223,27 +252,3 @@ impl<S: AbstractSim + Clone + Default + Send + 'static> Driver<S> {
|
|||||||
self.sim_end_time = None;
|
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