parameterize SpirvSim over R: Real

This commit is contained in:
2022-07-25 14:49:32 -07:00
parent a1784da1cf
commit 47e11474d2
6 changed files with 54 additions and 48 deletions

View File

@@ -389,7 +389,7 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
p.clock_type,
);
let mut driver: SpirvDriver<Mat> = Driver::new_spirv(g.dim, p.geom.feat_size);
let mut driver: SpirvDriver<f32, Mat> = Driver::new_spirv(g.dim, p.geom.feat_size);
driver.set_steps_per_stim(1000);
if !driver.add_state_file(&*format!("{}/state.bc", prefix), 16000) {
// mu_r=881.33, starting at H=25 to H=75.
@@ -414,7 +414,7 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
info!("loaded state file: skipping geometry calculations");
}
let add_drive_sine_pulse = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let add_drive_sine_pulse = |driver: &mut SpirvDriver<f32, Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
.half_cycle()
.shifted(start);
@@ -426,7 +426,7 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
));
};
let add_drive_square_pulse = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let add_drive_square_pulse = |driver: &mut SpirvDriver<f32, Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let wave = Gated::new(amp, start, start+duration);
driver.add_stimulus(CurlStimulus::new(
region.clone(),
@@ -436,7 +436,7 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
));
};
let add_drive_exp_pulse = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let add_drive_exp_pulse = |driver: &mut SpirvDriver<f32, Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let wave = Exp1::new_at(amp, start, 0.5*duration);
driver.add_stimulus(CurlStimulus::new(
region.clone(),
@@ -447,11 +447,11 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
};
// step function: "permanently" increase the current by `amp`.
let _add_drive_step = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, amp: f32| {
let _add_drive_step = |driver: &mut SpirvDriver<f32, Mat>, region: &Torus, start: f32, amp: f32| {
add_drive_square_pulse(driver, region, start, 1.0 /* effectively infinite duration */, amp);
};
let add_drive_pulse = |ty: PulseType, driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
let add_drive_pulse = |ty: PulseType, driver: &mut SpirvDriver<f32, Mat>, region: &Torus, start: f32, duration: f32, amp: f32| {
match ty {
PulseType::Square => add_drive_square_pulse(driver, region, start, duration, amp),
PulseType::Sine => add_drive_sine_pulse(driver, region, start, duration, amp),

View File

@@ -76,7 +76,7 @@ fn main() {
let ferro_mat = wire_mat;
// let ferro_mat = Ferroxcube3R1MH::new(); // uncomment when ready to simulate for real
let mut driver: SpirvDriver<Mat> = Driver::new_spirv(sim_bounds, feat_size);
let mut driver: SpirvDriver<f32, Mat> = Driver::new_spirv(sim_bounds, feat_size);
driver.add_classical_boundary(sim_padding);
driver.fill_region(&drive0, wire_mat);
driver.fill_region(&sense3, wire_mat);

View File

@@ -58,7 +58,7 @@ fn main() {
let coupling_region = Torus::new_xz(Meters::new(0.5*(ferro1_center + ferro2_center), ferro_center_y, half_depth), wire_coupling_major, wire_minor);
let sense_region = Torus::new_xz(Meters::new(ferro2_center + ferro_major, ferro_center_y, half_depth), wire_major, wire_minor);
let mut driver: SpirvDriver<mat::FullyGenericMaterial<f32>> = Driver::new_spirv(Meters::new(width, height, depth), feat_size);
let mut driver: SpirvDriver<f32, mat::FullyGenericMaterial<f32>> = Driver::new_spirv(Meters::new(width, height, depth), feat_size);
// mu_r=881.33, starting at H=25 to H=75.
driver.fill_region(&ferro1_region, mat::MHPgram::new(25.0, 881.33, 44000.0));

View File

@@ -39,7 +39,7 @@ pub struct Driver<S=SimState> {
}
pub type CpuDriver<R=real::R32, M=legacy::mat::GenericMaterial<R>> = Driver<SimState<R, M>>;
pub type SpirvDriver<M=mat::FullyGenericMaterial<f32>> = Driver<SpirvSim<M>>;
pub type SpirvDriver<R=f32, M=mat::FullyGenericMaterial<R>> = Driver<SpirvSim<R, M>>;
impl<R: Real, M: Default> Driver<SimState<R, M>> {
pub fn new<C: Coord>(size: C, feature_size: f32) -> Self {
@@ -47,7 +47,7 @@ impl<R: Real, M: Default> Driver<SimState<R, M>> {
}
}
impl<M: Default + Send + Sync + 'static> SpirvDriver<M>
impl<R: Real, M: Default + Send + Sync + 'static> SpirvDriver<R, M>
{
pub fn new_spirv<C: Coord>(size: C, feature_size: f32) -> Self {
Self::new_with_state(SpirvSim::new(size.to_index(feature_size), feature_size))

View File

@@ -75,8 +75,8 @@ impl<R: Copy, M: Send + Sync + 'static> SimBackend<R, M> for WgpuBackend<R, M> {
&self,
num_steps: u32,
meta: SimMeta<R>,
stim_cpu_e: &[Vec3<R>],
stim_cpu_h: &[Vec3<R>],
stim_cpu_e: &[Vec3<f32>],
stim_cpu_h: &[Vec3<f32>],
mat: &[M],
e: &mut [Vec3<R>],
h: &mut [Vec3<R>],

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use log::{info, trace, warn};
use crate::geom::{Coord, Index, Meters};
use crate::real::Real as _;
use crate::real::Real;
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim};
use crate::stim::AbstractStimulus;
use crate::types::vec::Vec3;
@@ -20,8 +20,8 @@ pub trait SimBackend<R, M> {
&self,
num_steps: u32,
meta: SimMeta<R>,
stim_e: &[Vec3<R>],
stim_h: &[Vec3<R>],
stim_e: &[Vec3<f32>],
stim_h: &[Vec3<f32>],
mat: &[M],
e: &mut [Vec3<R>],
h: &mut [Vec3<R>],
@@ -31,14 +31,14 @@ pub trait SimBackend<R, M> {
/// Wrapper around an inner state object which offloads stepping onto a spirv backend (e.g. GPU).
#[derive(Default, Serialize, Deserialize)]
pub struct SpirvSim<M=FullyGenericMaterial<f32>, B=WgpuBackend<f32, M>>
pub struct SpirvSim<R=f32, M=FullyGenericMaterial<R>, B=WgpuBackend<R, M>>
where M: 'static
{
// TODO: make this generic over R
meta: SimMeta<f32>,
e: Vec<Vec3<f32>>,
h: Vec<Vec3<f32>>,
m: Vec<Vec3<f32>>,
meta: SimMeta<R>,
e: Vec<Vec3<R>>,
h: Vec<Vec3<R>>,
m: Vec<Vec3<R>>,
mat: Vec<M>,
step_no: u64,
// hidden behind an Arc to allow for cheap clones.
@@ -49,7 +49,7 @@ where M: 'static
}
// B isn't always clonable (e.g. gpu backend) so rust can't auto-derive this.
impl<M: Clone, B> Clone for SpirvSim<M, B> {
impl<R: Clone, M: Clone, B> Clone for SpirvSim<R, M, B> {
fn clone(&self) -> Self {
Self {
meta: self.meta.clone(),
@@ -63,11 +63,12 @@ impl<M: Clone, B> Clone for SpirvSim<M, B> {
}
}
impl<M, B> MaterialSim for SpirvSim<M, B>
impl<R, M, B> MaterialSim for SpirvSim<R, M, B>
where
// TODO: extraneous bounds?
M: Send + Sync + Material<f32> + PartialEq + Clone + 'static,
B: Send + Sync + SimBackend<f32, M>,
R: Real,
M: Send + Sync + Material<R> + PartialEq + Clone + 'static,
B: Send + Sync + SimBackend<R, M>,
{
type Material = M;
@@ -84,9 +85,10 @@ where
}
}
impl<M, B> SampleableSim for SpirvSim<M, B>
impl<R, M, B> SampleableSim for SpirvSim<R, M, B>
where
M: Send + Sync + Material<f32>,
R: Real,
M: Send + Sync + Material<R>,
B: Send + Sync,
{
fn sample(&self, pos: Meters) -> Sample {
@@ -96,11 +98,11 @@ where
match flat_idx {
Some(idx) => Sample {
state: CellStateWithM {
h: self.h[idx],
e: self.e[idx],
m: self.m[idx],
h: self.h[idx].cast(),
e: self.e[idx].cast(),
m: self.m[idx].cast(),
},
conductivity: self.mat[idx].conductivity(),
conductivity: self.mat[idx].conductivity().cast(),
},
None => Default::default(),
}
@@ -110,20 +112,21 @@ where
Index(self.meta.dim)
}
fn feature_size(&self) -> f32 {
self.meta.feature_size
self.meta.feature_size.cast()
}
fn timestep(&self) -> f32 {
self.meta.time_step
self.meta.time_step.cast()
}
fn step_no(&self) -> u64 {
self.step_no
}
}
impl<M, B> GenericSim for SpirvSim<M, B>
impl<R, M, B> GenericSim for SpirvSim<R, M, B>
where
M: Send + Sync + Material<f32> + 'static,
B: Send + Sync + SimBackend<f32, M>,
R: Real,
M: Send + Sync + Material<R> + 'static,
B: Send + Sync + SimBackend<R, M>,
{
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, stim: &S) {
let vol = self.size().volume();
@@ -147,23 +150,24 @@ where
fn impulse_e_meters(&mut self, pos: Meters, amount: Vec3<f32>) {
let idx = pos.to_index(self.feature_size());
let flat_idx = self.flat_index(idx).unwrap();
self.e[flat_idx] += amount;
self.e[flat_idx] += amount.cast();
}
fn impulse_h_meters(&mut self, pos: Meters, amount: Vec3<f32>) {
let idx = pos.to_index(self.feature_size());
let flat_idx = self.flat_index(idx).unwrap();
self.h[flat_idx] += amount;
self.h[flat_idx] += amount.cast();
}
fn impulse_b_meters(&mut self, _pos: Meters, _amount: Vec3<f32>) {
unimplemented!()
}
}
impl<M, B> SpirvSim<M, B>
impl<R, M, B> SpirvSim<R, M, B>
where
R: Real,
M: Default + Send + Sync + 'static,
B: SimBackend<f32, M>,
B: SimBackend<R, M>,
{
pub fn new(size: Index, feature_size: f32) -> Self {
Self::new_with_backend(size, feature_size, Some(Arc::new(B::new(size.volume()))))
@@ -179,14 +183,15 @@ where
if flat_size * std::mem::size_of::<M>() >= 0x40000000 {
warn!("simulation size ({:?}) is greater than what is tested for: anything could happen!", size);
}
let courant = 0.577;
let time_step = feature_size / f32::c() * courant;
let feature_size = feature_size.cast::<R>();
let courant = 0.577.cast::<R>();
let time_step = feature_size / R::c() * courant;
let mut mat = Vec::new();
mat.resize_with(flat_size, Default::default);
Self {
meta: SimMeta {
dim: *size,
inv_feature_size: 1.0/feature_size,
inv_feature_size: R::one()/feature_size,
time_step,
feature_size,
},
@@ -200,7 +205,7 @@ where
}
}
impl<M, B> SpirvSim<M, B> {
impl<R, M, B> SpirvSim<R, M, B> {
fn flat_index(&self, idx: Index) -> Option<usize> {
let dim = self.meta.dim;
if idx.x() < dim.x() && idx.y() < dim.y() && idx.z() < dim.z() {
@@ -211,18 +216,19 @@ impl<M, B> SpirvSim<M, B> {
}
}
impl<M, B> SpirvSim<M, B>
impl<R, M, B> SpirvSim<R, M, B>
where
M: Send + Sync + Material<f32> + 'static,
B: Send + Sync + SimBackend<f32, M>,
R: Real,
M: Send + Sync + Material<R> + 'static,
B: Send + Sync + SimBackend<R, M>,
{
#[allow(unused)] // used for test
fn apply_stimulus(&mut self, stim: &dyn AbstractStimulus) {
trace!("apply_stimulus begin");
iterate_stim(stim, self.size(), self.feature_size(), self.time(), self.timestep(), |pos_idx, value_e, value_h| {
let flat_idx = self.flat_index(pos_idx).unwrap();
self.e[flat_idx] += value_e;
self.h[flat_idx] += value_h;
self.e[flat_idx] += value_e.cast();
self.h[flat_idx] += value_h.cast();
});
trace!("apply_stimulus end");
}