stim: remove `TimeVarying3`

`TimeVarying`(1) is enough for what we want.
This commit is contained in:
colin 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::geom::{Meters, Torus};
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() {
coremem::init_logging();
@ -89,7 +89,7 @@ fn main() {
assert!(driver.test_region_filled(&sense_region, mat::IsomorphicConductor::new(sense_conductivity)));
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -1,7 +1,7 @@
use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{Meters, Torus};
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() {
coremem::init_logging();
@ -81,7 +81,7 @@ fn main() {
}
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -5,7 +5,7 @@
use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{Meters, Torus};
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() {
coremem::init_logging();
@ -106,7 +106,7 @@ fn main() {
}
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -12,7 +12,7 @@
use coremem::{Driver, mat, meas, SpirvDriver};
use coremem::geom::{region, Cube, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
fn main() {
@ -132,7 +132,7 @@ fn main() {
assert!(driver.test_region_filled(&coupling_region, wire_mat));
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -1,7 +1,7 @@
use coremem::{Driver, mat, meas, SimState};
use coremem::geom::{Cube, Index, InvertedRegion, Meters, Torus, Union};
use coremem::real::R64 as Real;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
use coremem::units::Seconds;
fn main() {
@ -63,10 +63,10 @@ fn main() {
// 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)
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();
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()
.shifted(current_duration + current_break);

View File

@ -1,6 +1,6 @@
use coremem::{Driver, mat, meas, SimState, SpirvDriver};
use coremem::geom::{Index, Meters, Torus};
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, TimeVarying as _};
use coremem::units::Seconds;
fn main() {
@ -64,7 +64,7 @@ fn main() {
driver.add_classical_boundary(Meters::new(boundary_xy, boundary_xy, boundary_z));
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -22,7 +22,7 @@ use coremem::real::{R32, Real as _};
use coremem::render::CsvRenderer;
use coremem::sim::spirv::{SpirvSim, WgpuBackend};
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 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 wave = Sinusoid1::from_wavelength(amp, duration * 2.0)
let wave = Sinusoid::from_wavelength(amp, duration * 2.0)
.half_cycle()
.shifted(start);
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::sim::spirv::{SpirvSim, WgpuBackend};
use coremem::sim::units::Seconds;
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
use coremem::stim::{CurlStimulus, Sinusoid, StimExt as _};
fn main() {
@ -78,7 +78,7 @@ fn main() {
// helper to schedule a stimulus at the provided start time/duration.
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()
.shifted(start);
driver.add_stimulus(CurlStimulus::new(

View File

@ -11,7 +11,7 @@ use coremem::{mat, Driver};
use coremem::geom::{Coord as _, Cube, Index};
use coremem::units::Seconds;
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;
type Mat = mat::FullyGenericMaterial<f32>;

View File

@ -44,6 +44,31 @@ pub struct FieldMags {
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 {
// 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.
@ -176,12 +201,6 @@ impl Stimulus for UniformStimulus {
self.fields
}
}
impl TimeVarying for UniformStimulus {}
impl TimeVarying3 for UniformStimulus {
fn at(&self, _t_sec: f32) -> Fields {
self.fields
}
}
pub struct RngStimulus {
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 {
if self.region.contains(pos) {
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> {
Shifted::new(self, new_start)
}
@ -287,19 +306,15 @@ pub trait TimeVarying: Sized {
}
}
pub trait TimeVarying1: TimeVarying {
/// Retrieve the (E, H) impulse to apply PER-SECOND at the provided time (in seconds).
impl<T> StimExt for T {}
pub trait TimeVarying {
// XXX: this could maybe be just f32?
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
impl TimeVarying for f32 {}
impl TimeVarying1 for f32 {
impl TimeVarying for f32 {
fn at(&self, _t_sec: f32) -> FieldMags {
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
#[derive(Clone)]
pub struct Sinusoid<A> {
amp: A,
pub struct Sinusoid {
amp: f32,
omega: f32,
}
pub type Sinusoid1 = Sinusoid<f32>;
pub type Sinusoid3 = Sinusoid<Vec3<f32>>;
impl<A> Sinusoid<A> {
pub fn new(amp: A, freq: f32) -> Self {
impl Sinusoid {
pub fn new(amp: f32, freq: f32) -> Self {
Self {
amp,
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)
}
pub fn freq(&self) -> f32 {
@ -341,9 +353,7 @@ impl<A> Sinusoid<A> {
}
}
impl<A> TimeVarying for Sinusoid<A> {}
impl TimeVarying1 for Sinusoid1 {
impl TimeVarying for Sinusoid {
fn at(&self, t_sec: f32) -> FieldMags {
FieldMags {
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.
#[derive(Clone)]
pub struct Exp<A> {
@ -368,7 +369,6 @@ pub struct Exp<A> {
tau: f32,
}
pub type Exp1 = Exp<f32>;
pub type Exp3 = Exp<Vec3<f32>>;
impl<A> Exp<A> {
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>> {
Self::new(amp, half_life)
.gated(0.0, half_life*100.0)
.shifted(start)
Shifted::new(
Gated::new(
Self::new(amp, half_life),
0.0,
half_life*100.0
),
start,
)
}
}
impl<A> TimeVarying for Exp<A> {}
impl TimeVarying1 for Exp1 {
impl<A: TimeVarying> TimeVarying for Exp<A> {
fn at(&self, t_sec: f32) -> FieldMags {
FieldMags {
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(),
}
self.amp.at(t_sec) * (t_sec * -self.tau).exp()
}
}
@ -420,9 +411,9 @@ impl<A: Stimulus> Stimulus for Exp<A> {
#[derive(Clone)]
pub struct Gated<T> {
inner: T,
start: f32,
end: f32,
inner: T,
}
impl<T> Gated<T> {
@ -431,8 +422,7 @@ impl<T> Gated<T> {
}
}
impl<T> TimeVarying for Gated<T> {}
impl<T: TimeVarying1> TimeVarying1 for Gated<T> {
impl<T: TimeVarying> TimeVarying for Gated<T> {
fn at(&self, t_sec: f32) -> FieldMags {
if (self.start..self.end).contains(&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> {
fn at(&self, t_sec: f32, pos: Meters) -> Fields {
if (self.start..self.end).contains(&t_sec) {
@ -469,8 +449,8 @@ impl<T: Stimulus> Stimulus for Gated<T> {
#[derive(Clone)]
pub struct Shifted<T> {
inner: T,
start_at: f32,
inner: T,
}
impl<T> Shifted<T> {
@ -479,19 +459,12 @@ impl<T> Shifted<T> {
}
}
impl<T> TimeVarying for Shifted<T> {}
impl<T: TimeVarying1> TimeVarying1 for Shifted<T> {
impl<T: TimeVarying> TimeVarying for Shifted<T> {
fn at(&self, t_sec: f32) -> FieldMags {
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> {
fn at(&self, t_sec: f32, pos: Meters) -> Fields {
self.inner.at(t_sec - self.start_at, pos)
@ -510,31 +483,29 @@ mod test {
let x = $x;
let e = $e;
let h = $h;
let diff_e = (x.e - e).mag();
let diff_e = (x.e - e).abs();
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);
}
}
#[test]
fn sinusoid3() {
let s = Sinusoid3::new(Vec3::new(10.0, 1.0, -100.0), 1000.0);
assert_eq!(s.at(0.0), Fields::default());
assert_approx_eq!(s.at(0.00025),
Vec3::new(10.0, 1.0, -100.0), Vec3::zero()
);
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());
fn sinusoid() {
let s = Sinusoid::new(10.0, 1000.0);
assert_eq!(s.at(0.0), FieldMags::default());
assert_approx_eq!(s.at(0.00025), 10.0, 0.0);
assert_approx_eq!(s.at(0.00050), 0.0, 0.0);
assert_approx_eq!(s.at(0.00075), -10.0, 0.0);
}
#[test]
fn sinusoid3_from_wavelength() {
let s = Sinusoid3::from_wavelength(Vec3::new(10.0, 1.0, -100.0), 0.001);
assert_eq!(s.at(0.0), Fields::default());
assert_approx_eq!(s.at(0.00025), Vec3::new(10.0, 1.0, -100.0), Vec3::zero());
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());
let s = Sinusoid::from_wavelength(10.0, 0.001);
assert_eq!(s.at(0.0), FieldMags::default());
assert_approx_eq!(s.at(0.00025), 10.0, 0.0);
assert_approx_eq!(s.at(0.00050), 0.0, 0.0);
assert_approx_eq!(s.at(0.00075), -10.0, 0.0);
}
struct MockRegion {