stim: remove TimeVarying3

`TimeVarying`(1) is enough for what we want.
This commit is contained in:
2022-08-18 15:51:54 -07:00
parent 570f058ee1
commit 6750feef8d
10 changed files with 83 additions and 112 deletions

View File

@@ -1,7 +1,7 @@
use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{Meters, Torus}; use coremem::geom::{Meters, Torus};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
@@ -89,7 +89,7 @@ fn main() {
assert!(driver.test_region_filled(&sense_region, mat::IsomorphicConductor::new(sense_conductivity))); assert!(driver.test_region_filled(&sense_region, mat::IsomorphicConductor::new(sense_conductivity)));
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -1,7 +1,7 @@
use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{Meters, Torus}; use coremem::geom::{Meters, Torus};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
@@ -81,7 +81,7 @@ fn main() {
} }
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -5,7 +5,7 @@
use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{Meters, Torus}; use coremem::geom::{Meters, Torus};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() { fn main() {
coremem::init_logging(); coremem::init_logging();
@@ -106,7 +106,7 @@ fn main() {
} }
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -12,7 +12,7 @@
use coremem::{Driver, mat, meas, SpirvDriver}; use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{region, Cube, Meters, Spiral, SwapYZ, Torus, Translate, Wrap}; use coremem::geom::{region, Cube, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() { fn main() {
@@ -132,7 +132,7 @@ fn main() {
assert!(driver.test_region_filled(&coupling_region, wire_mat)); assert!(driver.test_region_filled(&coupling_region, wire_mat));
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -1,7 +1,7 @@
use coremem::{Driver, mat, meas, SimState}; use coremem::{Driver, mat, meas, SimState};
use coremem::geom::{Cube, Index, InvertedRegion, Meters, Torus, Union}; use coremem::geom::{Cube, Index, InvertedRegion, Meters, Torus, Union};
use coremem::real::R64 as Real; use coremem::real::R64 as Real;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
use coremem::units::Seconds; use coremem::units::Seconds;
fn main() { fn main() {
@@ -63,10 +63,10 @@ fn main() {
// if I = k*sin(w t) then dE/dt = k*w sin(w t) / (A*\sigma) // if I = k*sin(w t) then dE/dt = k*w sin(w t) / (A*\sigma)
// i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength) // i.e. dE/dt is proportional to I/(A*\sigma), multiplied by w (or, divided by wavelength)
let peak_stim = peak_current/current_duration / (drive_region.cross_section() * conductivity); let peak_stim = peak_current/current_duration / (drive_region.cross_section() * conductivity);
let pos_wave = Sinusoid1::from_wavelength(peak_stim as _, current_duration * 2.0) let pos_wave = Sinusoid::from_wavelength(peak_stim as _, current_duration * 2.0)
.half_cycle(); .half_cycle();
let neg_wave = Sinusoid1::from_wavelength(-peak_stim as _, current_duration * 2.0) let neg_wave = Sinusoid::from_wavelength(-peak_stim as _, current_duration * 2.0)
.half_cycle() .half_cycle()
.shifted(current_duration + current_break); .shifted(current_duration + current_break);

View File

@@ -1,6 +1,6 @@
use coremem::{Driver, mat, meas, SimState, SpirvDriver}; use coremem::{Driver, mat, meas, SimState, SpirvDriver};
use coremem::geom::{Index, Meters, Torus}; use coremem::geom::{Index, Meters, Torus};
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
use coremem::units::Seconds; use coremem::units::Seconds;
fn main() { fn main() {
@@ -64,7 +64,7 @@ fn main() {
driver.add_classical_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z)); driver.add_classical_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z));
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -22,7 +22,7 @@ use coremem::real::{R32, Real as _};
use coremem::render::CsvRenderer; use coremem::render::CsvRenderer;
use coremem::sim::spirv::{SpirvSim, WgpuBackend}; use coremem::sim::spirv::{SpirvSim, WgpuBackend};
use coremem::sim::units::{Seconds, Time as _}; use coremem::sim::units::{Seconds, Time as _};
use coremem::stim::{CurlStimulus, Exp1, Gated, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Exp1, Gated, Sinusoid, StimExt as _};
use log::{error, info, warn}; use log::{error, info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -438,7 +438,7 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
} }
let add_drive_sine_pulse = |driver: &mut Driver<_>, region: &Torus, start: f32, duration: f32, amp: f32| { let add_drive_sine_pulse = |driver: &mut Driver<_>, region: &Torus, start: f32, duration: f32, amp: f32| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -7,7 +7,7 @@ use coremem::{Driver, mat, meas};
use coremem::geom::{Coord as _, Meters, Torus}; use coremem::geom::{Coord as _, Meters, Torus};
use coremem::sim::spirv::{SpirvSim, WgpuBackend}; use coremem::sim::spirv::{SpirvSim, WgpuBackend};
use coremem::sim::units::Seconds; use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _}; use coremem::stim::{CurlStimulus, Sinusoid, StimExt as _};
fn main() { fn main() {
@@ -78,7 +78,7 @@ fn main() {
// helper to schedule a stimulus at the provided start time/duration. // helper to schedule a stimulus at the provided start time/duration.
let mut add_drive_pulse = |region: &Torus, start, duration, amp| { let mut add_drive_pulse = |region: &Torus, start, duration, amp| {
let wave = Sinusoid1::from_wavelength(amp, duration * 2.0) let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle() .half_cycle()
.shifted(start); .shifted(start);
driver.add_stimulus(CurlStimulus::new( driver.add_stimulus(CurlStimulus::new(

View File

@@ -11,7 +11,7 @@ use coremem::{mat, Driver};
use coremem::geom::{Coord as _, Cube, Index}; use coremem::geom::{Coord as _, Cube, Index};
use coremem::units::Seconds; use coremem::units::Seconds;
use coremem::sim::spirv::{self, SpirvSim}; use coremem::sim::spirv::{self, SpirvSim};
use coremem::stim::{RegionGated, TimeVarying as _, UniformStimulus}; use coremem::stim::{RegionGated, StimExt as _, UniformStimulus};
use coremem::cross::vec::Vec3; use coremem::cross::vec::Vec3;
type Mat = mat::FullyGenericMaterial<f32>; type Mat = mat::FullyGenericMaterial<f32>;

View File

@@ -44,6 +44,31 @@ pub struct FieldMags {
pub h: f32, pub h: f32,
} }
impl std::ops::AddAssign for FieldMags {
fn add_assign(&mut self, other: FieldMags) {
self.e += other.e;
self.h += other.h;
}
}
impl std::ops::Add for FieldMags {
type Output = FieldMags;
fn add(mut self, other: FieldMags) -> Self::Output {
self += other;
self
}
}
impl std::ops::Mul<f32> for FieldMags {
type Output = FieldMags;
fn mul(self, scale: f32) -> Self::Output {
FieldMags {
e: self.e * scale,
h: self.h * scale,
}
}
}
pub trait Stimulus: Sync { pub trait Stimulus: Sync {
// TODO: using floats for time and position is not great. // TODO: using floats for time and position is not great.
/// Return the (E, H) field which should be added PER-SECOND to the provided position/time. /// Return the (E, H) field which should be added PER-SECOND to the provided position/time.
@@ -176,12 +201,6 @@ impl Stimulus for UniformStimulus {
self.fields self.fields
} }
} }
impl TimeVarying for UniformStimulus {}
impl TimeVarying3 for UniformStimulus {
fn at(&self, _t_sec: f32) -> Fields {
self.fields
}
}
pub struct RngStimulus { pub struct RngStimulus {
seed: u64, seed: u64,
@@ -261,7 +280,7 @@ impl<R, T> CurlStimulus<R, T> {
} }
} }
impl<R: Region + HasCrossSection, T: TimeVarying1 + Sync> Stimulus for CurlStimulus<R, T> { impl<R: Region + HasCrossSection, T: TimeVarying + Sync> Stimulus for CurlStimulus<R, T> {
fn at(&self, t_sec: f32, pos: Meters) -> Fields { fn at(&self, t_sec: f32, pos: Meters) -> Fields {
if self.region.contains(pos) { if self.region.contains(pos) {
let FieldMags { e, h } = self.stim.at(t_sec); let FieldMags { e, h } = self.stim.at(t_sec);
@@ -278,7 +297,7 @@ impl<R: Region + HasCrossSection, T: TimeVarying1 + Sync> Stimulus for CurlStimu
} }
} }
pub trait TimeVarying: Sized { pub trait StimExt: Sized {
fn shifted(self, new_start: f32) -> Shifted<Self> { fn shifted(self, new_start: f32) -> Shifted<Self> {
Shifted::new(self, new_start) Shifted::new(self, new_start)
} }
@@ -287,19 +306,15 @@ pub trait TimeVarying: Sized {
} }
} }
pub trait TimeVarying1: TimeVarying { impl<T> StimExt for T {}
/// Retrieve the (E, H) impulse to apply PER-SECOND at the provided time (in seconds).
pub trait TimeVarying {
// XXX: this could maybe be just f32?
fn at(&self, t_sec: f32) -> FieldMags; fn at(&self, t_sec: f32) -> FieldMags;
} }
pub trait TimeVarying3: TimeVarying {
/// Retrieve the (E, H) impulse to apply PER-SECOND at the provided time (in seconds).
fn at(&self, t_sec: f32) -> Fields;
}
// assumed to represent the E field // assumed to represent the E field
impl TimeVarying for f32 {} impl TimeVarying for f32 {
impl TimeVarying1 for f32 {
fn at(&self, _t_sec: f32) -> FieldMags { fn at(&self, _t_sec: f32) -> FieldMags {
FieldMags { e: *self, h: 0.0 } FieldMags { e: *self, h: 0.0 }
} }
@@ -307,22 +322,19 @@ impl TimeVarying1 for f32 {
/// E field which changes magnitude sinusoidally as a function of t /// E field which changes magnitude sinusoidally as a function of t
#[derive(Clone)] #[derive(Clone)]
pub struct Sinusoid<A> { pub struct Sinusoid {
amp: A, amp: f32,
omega: f32, omega: f32,
} }
pub type Sinusoid1 = Sinusoid<f32>; impl Sinusoid {
pub type Sinusoid3 = Sinusoid<Vec3<f32>>; pub fn new(amp: f32, freq: f32) -> Self {
impl<A> Sinusoid<A> {
pub fn new(amp: A, freq: f32) -> Self {
Self { Self {
amp, amp,
omega: freq * f32::two_pi(), omega: freq * f32::two_pi(),
} }
} }
pub fn from_wavelength(amp: A, lambda: f32) -> Self { pub fn from_wavelength(amp: f32, lambda: f32) -> Self {
Self::new(amp, 1.0/lambda) Self::new(amp, 1.0/lambda)
} }
pub fn freq(&self) -> f32 { pub fn freq(&self) -> f32 {
@@ -341,9 +353,7 @@ impl<A> Sinusoid<A> {
} }
} }
impl<A> TimeVarying for Sinusoid<A> {} impl TimeVarying for Sinusoid {
impl TimeVarying1 for Sinusoid1 {
fn at(&self, t_sec: f32) -> FieldMags { fn at(&self, t_sec: f32) -> FieldMags {
FieldMags { FieldMags {
e: self.amp * (t_sec * self.omega).sin(), e: self.amp * (t_sec * self.omega).sin(),
@@ -352,15 +362,6 @@ impl TimeVarying1 for Sinusoid1 {
} }
} }
impl TimeVarying3 for Sinusoid3 {
fn at(&self, t_sec: f32) -> Fields {
Fields {
e: self.amp * (t_sec * self.omega).sin(),
h: Vec3::zero(),
}
}
}
/// E field with magnitude that decays exponentially over t. /// E field with magnitude that decays exponentially over t.
#[derive(Clone)] #[derive(Clone)]
pub struct Exp<A> { pub struct Exp<A> {
@@ -368,7 +369,6 @@ pub struct Exp<A> {
tau: f32, tau: f32,
} }
pub type Exp1 = Exp<f32>; pub type Exp1 = Exp<f32>;
pub type Exp3 = Exp<Vec3<f32>>;
impl<A> Exp<A> { impl<A> Exp<A> {
pub fn new(amp: A, half_life: f32) -> Self { pub fn new(amp: A, half_life: f32) -> Self {
@@ -377,29 +377,20 @@ impl<A> Exp<A> {
} }
pub fn new_at(amp: A, start: f32, half_life: f32) -> Shifted<Gated<Self>> { pub fn new_at(amp: A, start: f32, half_life: f32) -> Shifted<Gated<Self>> {
Self::new(amp, half_life) Shifted::new(
.gated(0.0, half_life*100.0) Gated::new(
.shifted(start) Self::new(amp, half_life),
0.0,
half_life*100.0
),
start,
)
} }
} }
impl<A> TimeVarying for Exp<A> {} impl<A: TimeVarying> TimeVarying for Exp<A> {
impl TimeVarying1 for Exp1 {
fn at(&self, t_sec: f32) -> FieldMags { fn at(&self, t_sec: f32) -> FieldMags {
FieldMags { self.amp.at(t_sec) * (t_sec * -self.tau).exp()
e: self.amp * (t_sec * -self.tau).exp(),
h: 0.0,
}
}
}
impl TimeVarying3 for Exp3 {
fn at(&self, t_sec: f32) -> Fields {
Fields {
e: self.amp * (t_sec * -self.tau).exp(),
h: Vec3::zero(),
}
} }
} }
@@ -420,9 +411,9 @@ impl<A: Stimulus> Stimulus for Exp<A> {
#[derive(Clone)] #[derive(Clone)]
pub struct Gated<T> { pub struct Gated<T> {
inner: T,
start: f32, start: f32,
end: f32, end: f32,
inner: T,
} }
impl<T> Gated<T> { impl<T> Gated<T> {
@@ -431,8 +422,7 @@ impl<T> Gated<T> {
} }
} }
impl<T> TimeVarying for Gated<T> {} impl<T: TimeVarying> TimeVarying for Gated<T> {
impl<T: TimeVarying1> TimeVarying1 for Gated<T> {
fn at(&self, t_sec: f32) -> FieldMags { fn at(&self, t_sec: f32) -> FieldMags {
if (self.start..self.end).contains(&t_sec) { if (self.start..self.end).contains(&t_sec) {
self.inner.at(t_sec) self.inner.at(t_sec)
@@ -442,16 +432,6 @@ impl<T: TimeVarying1> TimeVarying1 for Gated<T> {
} }
} }
impl<T: TimeVarying3> TimeVarying3 for Gated<T> {
fn at(&self, t_sec: f32) -> Fields {
if (self.start..self.end).contains(&t_sec) {
self.inner.at(t_sec)
} else {
Default::default()
}
}
}
impl<T: Stimulus> Stimulus for Gated<T> { impl<T: Stimulus> Stimulus for Gated<T> {
fn at(&self, t_sec: f32, pos: Meters) -> Fields { fn at(&self, t_sec: f32, pos: Meters) -> Fields {
if (self.start..self.end).contains(&t_sec) { if (self.start..self.end).contains(&t_sec) {
@@ -469,8 +449,8 @@ impl<T: Stimulus> Stimulus for Gated<T> {
#[derive(Clone)] #[derive(Clone)]
pub struct Shifted<T> { pub struct Shifted<T> {
inner: T,
start_at: f32, start_at: f32,
inner: T,
} }
impl<T> Shifted<T> { impl<T> Shifted<T> {
@@ -479,19 +459,12 @@ impl<T> Shifted<T> {
} }
} }
impl<T> TimeVarying for Shifted<T> {} impl<T: TimeVarying> TimeVarying for Shifted<T> {
impl<T: TimeVarying1> TimeVarying1 for Shifted<T> {
fn at(&self, t_sec: f32) -> FieldMags { fn at(&self, t_sec: f32) -> FieldMags {
self.inner.at(t_sec - self.start_at) self.inner.at(t_sec - self.start_at)
} }
} }
impl<T: TimeVarying3> TimeVarying3 for Shifted<T> {
fn at(&self, t_sec: f32) -> Fields {
self.inner.at(t_sec - self.start_at)
}
}
impl<T: Stimulus> Stimulus for Shifted<T> { impl<T: Stimulus> Stimulus for Shifted<T> {
fn at(&self, t_sec: f32, pos: Meters) -> Fields { fn at(&self, t_sec: f32, pos: Meters) -> Fields {
self.inner.at(t_sec - self.start_at, pos) self.inner.at(t_sec - self.start_at, pos)
@@ -510,31 +483,29 @@ mod test {
let x = $x; let x = $x;
let e = $e; let e = $e;
let h = $h; let h = $h;
let diff_e = (x.e - e).mag(); let diff_e = (x.e - e).abs();
assert!(diff_e <= 0.001, "{:?} != {:?}", x, e); assert!(diff_e <= 0.001, "{:?} != {:?}", x, e);
let diff_h = (x.h - h).mag(); let diff_h = (x.h - h).abs();
assert!(diff_h <= 0.001, "{:?} != {:?}", x, h); assert!(diff_h <= 0.001, "{:?} != {:?}", x, h);
} }
} }
#[test] #[test]
fn sinusoid3() { fn sinusoid() {
let s = Sinusoid3::new(Vec3::new(10.0, 1.0, -100.0), 1000.0); let s = Sinusoid::new(10.0, 1000.0);
assert_eq!(s.at(0.0), Fields::default()); assert_eq!(s.at(0.0), FieldMags::default());
assert_approx_eq!(s.at(0.00025), assert_approx_eq!(s.at(0.00025), 10.0, 0.0);
Vec3::new(10.0, 1.0, -100.0), Vec3::zero() assert_approx_eq!(s.at(0.00050), 0.0, 0.0);
); assert_approx_eq!(s.at(0.00075), -10.0, 0.0);
assert_approx_eq!(s.at(0.00050), Vec3::zero(), Vec3::zero());
assert_approx_eq!(s.at(0.00075), Vec3::new(-10.0, -1.0, 100.0), Vec3::zero());
} }
#[test] #[test]
fn sinusoid3_from_wavelength() { fn sinusoid3_from_wavelength() {
let s = Sinusoid3::from_wavelength(Vec3::new(10.0, 1.0, -100.0), 0.001); let s = Sinusoid::from_wavelength(10.0, 0.001);
assert_eq!(s.at(0.0), Fields::default()); assert_eq!(s.at(0.0), FieldMags::default());
assert_approx_eq!(s.at(0.00025), Vec3::new(10.0, 1.0, -100.0), Vec3::zero()); assert_approx_eq!(s.at(0.00025), 10.0, 0.0);
assert_approx_eq!(s.at(0.00050), Vec3::zero(), Vec3::zero()); assert_approx_eq!(s.at(0.00050), 0.0, 0.0);
assert_approx_eq!(s.at(0.00075), Vec3::new(-10.0, -1.0, 100.0), Vec3::zero()); assert_approx_eq!(s.at(0.00075), -10.0, 0.0);
} }
struct MockRegion { struct MockRegion {