spirv: test: prototype a ray_propagation test

it needs some more work to be useful
This commit is contained in:
2022-08-28 02:02:06 -07:00
parent a811561f14
commit a45d27a2e9

View File

@@ -344,12 +344,17 @@ mod test {
mod $shortname {
use super::*;
use crate::geom::WorldRegion;
use crate::stim::{NoopStimulus, RngStimulus};
use crate::geom::{Coord as _, WorldRegion};
use crate::sim::Cube;
use crate::stim::{DynStimuli, FieldMags, NoopStimulus, RegionGated, RngStimulus};
use coremem_cross::mat::{AnisomorphicConductor, IsomorphicConductor};
use float_eq::assert_float_eq;
use more_asserts::{assert_gt, assert_lt};
////////// SMOKE/SANITY TESTS //////////
// these test that everything is roughly wired together right, but don't ensure
// that the simulations will particularly reflect reality.
#[test]
fn accessors() {
let size = Index::new(15, 17, 19);
@@ -542,6 +547,84 @@ mod test {
fn mh_ferromagnet_smoke_100_steps_larger() {
mh_ferromagnet_smoke_test(0x1234, 100, Index::new(328, 252, 160));
}
////////// APPLICATION TESTS //////////
// these test that the simulation accurately models *specific* applications
#[test]
fn ray_propagation() {
let size = Index::new(1, 1, 100);
let feat_size = 1e-3;
let mut sim = SpirvSim::<R32, FullyGenericMaterial<R32>, $backend>::new(size, feat_size);
// we'll inject this stimulus at a single point
let region = Cube::new_centered(
Index::new(0, 0, 50).to_meters(feat_size),
Index::new(1, 1, 1).to_meters(feat_size),
);
let duration_frames = 40;
let duration = 40.0 * sim.timestep();
let inv_ts = sim.timestep().inv().to_r32();
// let f = inv_ts * 0.05.to_r32();
// see https://en.wikipedia.org/wiki/Electromagnetic_radiation
let amp_e = Sinusoid::from_wavelength(duration.to_r32())
.scaled(FieldMags::new_e(inv_ts));
// since H is shifted a half grid-space, we delay it by one half timestep
let amp_h = Sinusoid::from_wavelength(duration.to_r32())
// .shifted(sim.timestep().to_r32() * -R32::half())
.scaled(FieldMags::new_h(inv_ts * R32::c_inv() * R32::mu0_inv()));
// h will be a cosine wave
// let amp_h = Sinusoid::new(1.0, f).shifted(0.25 * duration);
let stim_e = ModulatedVectorField::new(
RegionGated::new(region.clone(), stim::Fields::new_e(Vec3::new(R32::one(), R32::zero(), R32::zero()))),
amp_e,
);
let stim_h = ModulatedVectorField::new(
RegionGated::new(region.clone(), stim::Fields::new_e(Vec3::new(R32::zero(), R32::one(), R32::zero()))),
amp_h,
);
// let stim_h = ModulatedVectorField::new(
// amp_h,
// RegionGated::new(region.clone(), stim::Fields::new_e(Vec3::new(0.0, 0.0, 1.0))),
// );
let stim = DynStimuli::from_vec(vec![Box::new(stim_e), Box::new(stim_h)]);
for _ in 0..duration_frames {
sim.step_multiple(1, &stim);
}
// we should now have one wavelength of the wave propagated along the z axis.
// TODO: assert correct sim state
// this looks about right, just need to scale it and assert against expected
// values
let mut eh: Vec<_> = (0..100).into_iter().map(|z| {
let f = sim.fields_at_index(Index::new(0, 0, z));
(f.e().cast::<f32>(), f.h().cast::<f32>())
}).collect();
// normalize so peaks are 1.0
let amp_e = eh.iter().map(|(e, _h)| e.x().abs())
.fold(0f32, |a, b| a.max(b));
let amp_h = eh.iter().map(|(_e, h)| h.y().abs())
.fold(0f32, |a, b| a.max(b));
for i in &mut eh {
i.0 /= amp_e;
i.1 /= amp_h;
}
// unpack the Ex and Hy components
let mut eh_scalars = Vec::new();
for i in eh {
// Ey, Ez == 0
assert_float_eq!(i.0.y(), 0.0, abs <= 1e-6);
assert_float_eq!(i.0.z(), 0.0, abs <= 1e-6);
// Hx, Hz == 0
assert_float_eq!(i.1.x(), 0.0, abs <= 1e-6);
assert_float_eq!(i.1.z(), 0.0, abs <= 1e-6);
eh_scalars.push((i.0.x(), i.1.y()));
}
panic!("{:?}", eh_scalars);
}
}
}
}