diff --git a/crates/coremem/src/sim/legacy/mod.rs b/crates/coremem/src/sim/legacy/mod.rs index c9dd179..1228e37 100644 --- a/crates/coremem/src/sim/legacy/mod.rs +++ b/crates/coremem/src/sim/legacy/mod.rs @@ -1254,12 +1254,14 @@ mod test { energy_now_and_then(&mut state, 1000) } + // PORT-STATUS: done #[test] fn conductor_dissipates_energy() { let (energy_0, energy_1) = conductor_test(IsomorphicConductor::new(R64::from_f32(1e3))); assert_float_eq!(energy_1/energy_0, 0.0, abs <= 1e-6); } + // PORT-STATUS: done #[test] fn anisotropic_conductor_inactive_x() { let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( @@ -1270,6 +1272,7 @@ mod test { assert_lt!(energy_1, 1.5*energy_0); } + // PORT-STATUS: done #[test] fn anisotropic_conductor_inactive_y() { let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( @@ -1279,6 +1282,7 @@ mod test { assert_lt!(energy_1, 1.5*energy_0); } + // PORT-STATUS: done #[test] fn anisotropic_conductor_active_z() { let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( diff --git a/crates/coremem/src/sim/spirv/mod.rs b/crates/coremem/src/sim/spirv/mod.rs index 3daa9b7..edeccaa 100644 --- a/crates/coremem/src/sim/spirv/mod.rs +++ b/crates/coremem/src/sim/spirv/mod.rs @@ -610,6 +610,7 @@ mod test { use super::backend_agnostic::*; use super::*; + use crate::geom::WorldRegion; use crate::meas::Energy; use crate::stim::{ self, @@ -619,7 +620,9 @@ mod test { StimExt as _, VectorField }; + use coremem_cross::mat::{AnisomorphicConductor, IsomorphicConductor}; use float_eq::assert_float_eq; + use more_asserts::{assert_gt, assert_lt}; #[test] fn accessors() { @@ -650,30 +653,41 @@ mod test { } } - fn smooth_pulse_at(timestep: f32, loc: Index, frames: u32) -> impl Stimulus { + fn smooth_pulse_at(timestep: f32, feat_size: f32, loc: Index, frames: u32) -> impl Stimulus { let wl = (timestep * frames as f32).to_r32(); let quarter_wl = wl * (0.25).to_r32(); + let amp = (timestep*feat_size*feat_size).inv().to_r32(); + let window = Sinusoid::from_wavelength(R32::one(), wl) + .shifted(quarter_wl) + .summed(R32::one()); ModulatedVectorField::new( IndexGatedEField { loc }, - Sinusoid::from_wavelength(R32::one(), wl).scaled( - Sinusoid::from_wavelength(R32::one(), wl).shifted(quarter_wl).summed(R32::one()) - ), + // amp, + // window.scaled(amp), + // Sinusoid::from_wavelength(amp, wl).shifted(quarter_wl) + // Sinusoid::from_wavelength(amp, wl * R32::two()), + Sinusoid::from_wavelength(amp, wl).scaled(window), ) } + fn step_n>(state: &mut S, stim: &Stim, frames: u32) -> f32 { + for _ in 0..frames { + state.step_multiple(1, stim); + } + Energy::world().data(state) + } + #[test] fn energy_conservation_over_time() { let mut state = SpirvSim::, $backend>::new( Index((2001, 1, 1).into()), 1e-6 ); - let stim = smooth_pulse_at(state.timestep(), Index::new(1000, 0, 0), 100); + let stim = smooth_pulse_at(state.timestep(), state.feature_size(), Index::new(1000, 0, 0), 100); - state.step_multiple(100, &stim); - let energy_0 = Energy::world().data(&state); - state.step_multiple(800, &NoopStimulus); - let energy_1 = Energy::world().data(&state); + let energy_0 = step_n(&mut state, &stim, 100); + let energy_1 = step_n(&mut state, &NoopStimulus, 800); - assert_float_eq!(energy_1, energy_0, r2nd <= 1e-9); + assert_float_eq!(energy_1, energy_0, r2nd <= 1e-4); // TODO: assert that energy is something reasonable to begin with, and not 0. } @@ -682,15 +696,64 @@ mod test { let mut state = SpirvSim::, $backend>::new( Index((21, 21, 21).into()), 1e-6 ); - let stim = smooth_pulse_at(state.timestep(), Index::new(10, 10, 10), 40); + let stim = smooth_pulse_at(state.timestep(), state.feature_size(), Index::new(10, 10, 10), 40); - state.step_multiple(40, &stim); - let energy_0 = Energy::world().data(&state); - state.step_multiple(500, &NoopStimulus); - let energy_1 = Energy::world().data(&state); + let energy_0 = step_n(&mut state, &stim, 40); + let energy_1 = step_n(&mut state, &NoopStimulus, 500); // Default boundary conditions reflect waves. - assert_float_eq!(energy_1, energy_0, r2nd <= 1e-2); + // but maybe not *perfectly* + assert_lt!(energy_1, energy_0); + assert_gt!(energy_1, 0.5 * energy_0); + } + + /// Fill the world with the provided material and a stimulus. + /// Measure energy at the start, and then again after advancing many steps. + /// Return these two measurements (energy(t=0), energy(t=~=1000)) + fn conductor_test>>(mat: M) -> (f32, f32) { + let mut state = SpirvSim::, $backend>::new( + Index::new(201, 1, 1), 1e-6 + ); + state.fill_region(&WorldRegion, mat.into()); + let stim = smooth_pulse_at(state.timestep(), state.feature_size(), Index::new(100, 0, 0), 100); + + let energy_0 = step_n(&mut state, &stim, 100); + let energy_1 = step_n(&mut state, &NoopStimulus, 1000); + + (energy_0, energy_1) + } + + #[test] + fn conductor_dissipates_energy() { + let (energy_0, energy_1) = conductor_test(IsomorphicConductor::new(1e3.cast())); + assert_float_eq!(energy_1/energy_0, 0.0, abs <= 1e-6); + } + + #[test] + fn anisotropic_conductor_inactive_x() { + let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( + Vec3::new_x(1e3).cast() + )); + assert_gt!(energy_1, 0.9*energy_0); + // XXX: I think this gains energy because we only set the E field and not the H field + assert_lt!(energy_1, 1.8*energy_0); + } + + #[test] + fn anisotropic_conductor_inactive_y() { + let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( + Vec3::new_y(1e3).cast() + )); + assert_gt!(energy_1, 0.9*energy_0); + assert_lt!(energy_1, 1.8*energy_0); + } + + #[test] + fn anisotropic_conductor_active_z() { + let (energy_0, energy_1) = conductor_test(AnisomorphicConductor::new( + Vec3::new_z(1e3).cast() + )); + assert_float_eq!(energy_1/energy_0, 0.0, abs <= 1e-6); } #[test]