Compare commits
20 Commits
2022-07-20
...
2022-07-22
Author | SHA1 | Date | |
---|---|---|---|
7286d272b9 | |||
d0fcd9b657 | |||
2f0e52a09b | |||
c8a082d2a1 | |||
e62dc495f1 | |||
193df5415f | |||
4bd081ca7a | |||
940d86d86e | |||
ce00281c09 | |||
048eb7dbef | |||
d813405cb1 | |||
3f5160a8ea | |||
d246b97b5e | |||
67872de16f | |||
98773a350c | |||
35a0c52f67 | |||
9b149bae65 | |||
4a6a43fb31 | |||
ee2cf47b8d | |||
66ccbd1ada |
@@ -60,12 +60,12 @@ fn main() {
|
||||
driver.set_steps_per_stim(1000);
|
||||
//driver.fill_region(&ferro1_region, mat::db::linear_iron());
|
||||
// Original, 3R1-LIKE ferromagnet (only a vague likeness), sr-latch-8:
|
||||
// driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro1_region, mat::MBPgram::new(-0.3899, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro2_region, mat::MBPgram::new(-0.3899, 0.3900, 310_000.0));
|
||||
// sr-latch-9; dead spot from B=[-0.03, 0.03]. This will help us see if the math is H-triggered
|
||||
// or B-triggered
|
||||
// driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3300, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3300, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro1_region, mat::MBPgram::new(-0.3300, 0.3900, 310_000.0));
|
||||
// driver.fill_region(&ferro2_region, mat::MBPgram::new(-0.3300, 0.3900, 310_000.0));
|
||||
// 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));
|
||||
driver.fill_region(&ferro2_region, mat::MHPgram::new(25.0, 881.33, 44000.0));
|
||||
|
@@ -45,7 +45,7 @@ fn main() {
|
||||
let sense1_region = Torus::new_xz(Meters::new(ferro1_center + ferro_major, half_height, half_depth), wire_major, wire_minor);
|
||||
|
||||
//driver.fill_region(&ferro1_region, mat::db::linear_iron());
|
||||
driver.fill_region(&ferro1_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
|
||||
driver.fill_region(&ferro1_region, mat::MBPgram::new(-0.3899, 0.3900, 310_000.0));
|
||||
driver.fill_region(&drive1_region, mat::IsomorphicConductor::new(drive_conductivity));
|
||||
driver.fill_region(&sense1_region, mat::IsomorphicConductor::new(sense_conductivity));
|
||||
|
||||
@@ -54,7 +54,7 @@ fn main() {
|
||||
let drive2_region = Torus::new_xz(Meters::new(ferro2_center - ferro_major, half_height, half_depth), wire_major, wire_minor);
|
||||
let sense2_region = Torus::new_xz(Meters::new(ferro2_center + ferro_major, half_height, half_depth), wire_major, wire_minor);
|
||||
|
||||
driver.fill_region(&ferro2_region, mat::MBFerromagnet::new(-0.3899, 0.3900, 310_000.0));
|
||||
driver.fill_region(&ferro2_region, mat::MBPgram::new(-0.3899, 0.3900, 310_000.0));
|
||||
driver.fill_region(&drive2_region, mat::IsomorphicConductor::new(drive_conductivity));
|
||||
driver.fill_region(&sense2_region, mat::IsomorphicConductor::new(sense_conductivity));
|
||||
|
||||
|
@@ -3,13 +3,12 @@
|
||||
//! search for the conditions which maximize energy transfer from the one core to the other.
|
||||
|
||||
use coremem::{Driver, mat, meas, SpirvDriver};
|
||||
use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Region, Spiral, SwapYZ, Torus, Translate, Wrap};
|
||||
use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Spiral, SwapYZ, Torus, Translate, Wrap};
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr};
|
||||
use coremem::real::{R32, Real as _};
|
||||
use coremem::render::CsvRenderer;
|
||||
use coremem::stim::{CurlStimulus, Exp1, Gated, Sinusoid1, TimeVarying as _};
|
||||
use coremem::sim::units::{Seconds, Frame, Time as _};
|
||||
use coremem::sim::spirv;
|
||||
use coremem::sim::units::{Seconds, Time as _};
|
||||
use coremem::util::cache::DiskCache;
|
||||
use log::{error, info, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -151,24 +150,43 @@ struct Geometries {
|
||||
wrap2_len: f32,
|
||||
}
|
||||
|
||||
/// computed measurements which get written to disk for later, manual (or grep-based) analysis.
|
||||
/// because we only write these (except for the Debug impl reading them to write to disk),
|
||||
/// rustc thinks all the fields are dead.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct Results {
|
||||
#[allow(dead_code)]
|
||||
m1_peak: f32,
|
||||
#[allow(dead_code)]
|
||||
m2_peak: f32,
|
||||
#[allow(dead_code)]
|
||||
m1_stable: f32,
|
||||
#[allow(dead_code)]
|
||||
m2_stable: f32,
|
||||
#[allow(dead_code)]
|
||||
h1_peak: f32,
|
||||
#[allow(dead_code)]
|
||||
h2_max: f32,
|
||||
#[allow(dead_code)]
|
||||
h2_min: f32,
|
||||
#[allow(dead_code)]
|
||||
h1_stable: f32,
|
||||
#[allow(dead_code)]
|
||||
h2_stable: f32,
|
||||
#[allow(dead_code)]
|
||||
iset_min: f32,
|
||||
#[allow(dead_code)]
|
||||
iset_max: f32,
|
||||
#[allow(dead_code)]
|
||||
icoupling_peak: f32,
|
||||
#[allow(dead_code)]
|
||||
peak_m_ratio: f32,
|
||||
#[allow(dead_code)]
|
||||
stable_m_ratio: f32,
|
||||
/// m2_stable divided by m1_peak. i.e. "amplification"
|
||||
#[allow(dead_code)]
|
||||
m2_stable_m1_peak: f32,
|
||||
#[allow(dead_code)]
|
||||
t: f32,
|
||||
}
|
||||
|
||||
@@ -428,8 +446,9 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results {
|
||||
));
|
||||
};
|
||||
|
||||
let add_drive_step = |driver: &mut SpirvDriver<Mat>, region: &Torus, start: f32, amp: f32| {
|
||||
add_drive_square_pulse(driver, region, start, 1.0, amp);
|
||||
// step function: "permanently" increase the current by `amp`.
|
||||
let _add_drive_step = |driver: &mut SpirvDriver<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| {
|
||||
|
@@ -39,7 +39,6 @@
|
||||
use coremem::geom::{Meters, Torus};
|
||||
use coremem::sim::units::Seconds;
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
|
||||
use coremem::spirv;
|
||||
use coremem::{Driver, SpirvDriver};
|
||||
|
||||
type Mat = IsoConductorOr<f32, Ferroxcube3R1MH>;
|
||||
|
@@ -5,7 +5,6 @@
|
||||
|
||||
use coremem::{Driver, mat, meas, SpirvDriver};
|
||||
use coremem::geom::{Meters, Torus};
|
||||
use coremem::sim::spirv;
|
||||
use coremem::sim::units::Seconds;
|
||||
use coremem::stim::{CurlStimulus, Sinusoid1, TimeVarying as _};
|
||||
|
||||
|
@@ -8,9 +8,10 @@
|
||||
//! happens when you just use the default boundary conditions.
|
||||
|
||||
use coremem::{mat, driver};
|
||||
use coremem::geom::{Coord as _, Cube, Index, Vec3};
|
||||
use coremem::geom::{Coord as _, Cube, Index};
|
||||
use coremem::units::Seconds;
|
||||
use coremem::stim::{Stimulus, TimeVarying as _, UniformStimulus};
|
||||
use coremem::types::vec::Vec3;
|
||||
|
||||
fn main() {
|
||||
coremem::init_logging();
|
||||
@@ -21,10 +22,10 @@ fn main() {
|
||||
// each cell represents 1um x 1um x 1um volume
|
||||
let feature_size = 1e-6;
|
||||
|
||||
// Create the simulation "driver" which uses the CPU as backend.
|
||||
// by default all the computations are done with R32: a f32 which panics on NaN/Inf
|
||||
// you can parameterize it to use R64, or unchecked f32 -- see src/driver.rs for the definition
|
||||
let mut driver: driver::CpuDriver = driver::Driver::new(size, feature_size);
|
||||
// create the simulation "driver".
|
||||
// by default all the computations are done with R32: a f32 which panics on NaN/Inf.
|
||||
// you can parameterize it to use R64, or unchecked f32 -- see src/driver.rs for definition.
|
||||
let mut driver: driver::SpirvDriver = driver::Driver::new_spirv(size, feature_size);
|
||||
|
||||
// uncomment to use the Spirv/GPU driver. this one is restricted to unchecked f32.
|
||||
// note: this won't have better perf unless you reduce the y4m/term renderer framerate below.
|
||||
|
@@ -1,4 +1,5 @@
|
||||
use coremem::{self, Driver, GenericSim, SimState};
|
||||
use coremem::{self, Driver, GenericSim};
|
||||
use coremem::sim::legacy::SimState;
|
||||
use coremem::sim::spirv::SpirvSim;
|
||||
use coremem::geom::Index;
|
||||
use std::time::{Instant, Duration};
|
||||
|
@@ -1,7 +1,9 @@
|
||||
use coremem::*;
|
||||
use coremem::geom::*;
|
||||
use coremem::real::{Real as _, ToFloat as _};
|
||||
use coremem::sim::legacy::mat::Static;
|
||||
use coremem::stim::AbstractStimulus;
|
||||
use coremem::types::vec::Vec3;
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng as _, SeedableRng as _};
|
||||
|
||||
|
@@ -1,12 +1,15 @@
|
||||
use crate::geom::{Coord, Index, Meters, Region, Vec3};
|
||||
use crate::mat::{self, Pml};
|
||||
use crate::geom::{Coord, Index, Meters, Region};
|
||||
use crate::mat;
|
||||
use crate::meas::{self, AbstractMeasurement};
|
||||
use crate::real::{self, Real};
|
||||
use crate::render::{self, MultiRenderer, Renderer};
|
||||
use crate::sim::{GenericSim, MaterialSim, SampleableSim, SimState};
|
||||
use crate::sim::{GenericSim, MaterialSim, SampleableSim};
|
||||
use crate::sim::legacy::{self, SimState};
|
||||
use crate::sim::legacy::mat::Pml;
|
||||
use crate::sim::units::{Frame, Time};
|
||||
use crate::sim::spirv::{self, SpirvSim};
|
||||
use crate::sim::spirv::SpirvSim;
|
||||
use crate::stim::AbstractStimulus;
|
||||
use crate::types::vec::Vec3;
|
||||
|
||||
use log::{info, trace};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -35,7 +38,7 @@ pub struct Driver<S=SimState> {
|
||||
sim_end_time: Option<Frame>,
|
||||
}
|
||||
|
||||
pub type CpuDriver<R=real::R32, M=mat::GenericMaterial<R>> = Driver<SimState<R, M>>;
|
||||
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>>;
|
||||
|
||||
impl<R: Real, M: Default> Driver<SimState<R, M>> {
|
||||
@@ -44,8 +47,7 @@ impl<R: Real, M: Default> Driver<SimState<R, M>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: spirv::IntoFfi> SpirvDriver<M>
|
||||
where M::Ffi: Default + 'static
|
||||
impl<M: Default + 'static> SpirvDriver<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))
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use crate::geom::Vec2;
|
||||
use crate::real::Real;
|
||||
use coremem_types::real::Real;
|
||||
use coremem_types::vec::Vec2;
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
|
@@ -9,5 +9,4 @@ pub use region::{
|
||||
Cube, CylinderZ, Dilate, InvertedRegion, Memoize, Region, Sphere, Spiral, SwapXZ, SwapYZ, Torus, Translate, Union, WorldRegion, Wrap
|
||||
};
|
||||
pub use units::{Coord, Meters, OrdMeters, Index};
|
||||
pub use coremem_types::vec::{Vec2, Vec3, Vec3u};
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use crate::geom::{Line2d, Vec2};
|
||||
use crate::real::Real;
|
||||
use crate::geom::Line2d;
|
||||
use coremem_types::real::Real;
|
||||
use coremem_types::vec::Vec2;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Polygon2d<R> {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use crate::geom::{Meters, Vec2, Vec3};
|
||||
use crate::real::Real as _;
|
||||
use crate::geom::Meters;
|
||||
use coremem_types::real::Real as _;
|
||||
use coremem_types::vec::{Vec2, Vec3};
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::fmt::{self, Display};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
use crate::real::ToFloat;
|
||||
use coremem_types::real::ToFloat;
|
||||
use coremem_types::vec::{Vec3, Vec3u};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use super::{Vec3, Vec3u};
|
||||
use std::fmt::{self, Display};
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Add, Deref, Div, Mul, Neg, Sub};
|
||||
|
@@ -9,7 +9,6 @@ use log::info;
|
||||
|
||||
pub mod driver;
|
||||
pub mod geom;
|
||||
pub mod mat;
|
||||
pub mod meas;
|
||||
pub mod render;
|
||||
pub mod sim;
|
||||
@@ -17,9 +16,10 @@ pub mod stim;
|
||||
pub mod util;
|
||||
|
||||
pub use driver::*;
|
||||
pub use mat::*;
|
||||
pub use sim::*;
|
||||
pub use coremem_types as types;
|
||||
pub use coremem_types::real;
|
||||
pub use coremem_types::mat;
|
||||
|
||||
// Some things to keep in mind:
|
||||
// B = mu_r*H + M
|
||||
|
@@ -1,195 +0,0 @@
|
||||
use crate::geom::{Line2d, Vec2, Vec3};
|
||||
use crate::mat::Material;
|
||||
use crate::real::Real;
|
||||
use crate::sim::CellState;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// M(B) parallelogram
|
||||
///
|
||||
///```text
|
||||
/// ____________
|
||||
/// / /
|
||||
/// / . /
|
||||
/// / /
|
||||
/// /___________/
|
||||
/// ```
|
||||
///
|
||||
/// The `.` depicts (0, 0). X axis is B; y axis is M.
|
||||
/// As B increases, M remains constant until it hits an edge.
|
||||
/// Then M rises up to its max.
|
||||
/// Same thing happens on the left edge, as B decreases and M falls to its min.
|
||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MBPgram<R> {
|
||||
/// Vertical range of the graph
|
||||
pub max_m: R,
|
||||
/// X coordinate at which the upward slope starts
|
||||
pub b_start: R,
|
||||
/// X coordinate at which the upward slope ends
|
||||
pub b_end: R,
|
||||
}
|
||||
|
||||
impl<R: Real> MBPgram<R> {
|
||||
pub fn new(b_start: R, b_end: R, max_m: R) -> Self {
|
||||
Self { b_start, b_end, max_m }
|
||||
}
|
||||
|
||||
/// Return the new `M`
|
||||
pub fn move_b(&self, m: R, target_b: R) -> R {
|
||||
let right_edge = Line2d::new(
|
||||
Vec2::new(self.b_start, -self.max_m),
|
||||
Vec2::new(self.b_end, self.max_m),
|
||||
);
|
||||
let left_edge = Line2d::new(
|
||||
Vec2::new(-self.b_start, self.max_m),
|
||||
Vec2::new(-self.b_end, -self.max_m),
|
||||
);
|
||||
// m must be at least this much:
|
||||
let min_m = right_edge.clamp_by_x(target_b).y();
|
||||
// m must be no more than this:
|
||||
let max_m = left_edge.clamp_by_x(target_b).y();
|
||||
m.max_or_undefined(min_m).min_or_undefined(max_m)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct NativeMBFerromagnet<R> {
|
||||
m: Vec3<R>,
|
||||
curve: MBPgram<R>,
|
||||
}
|
||||
|
||||
impl<R: Real> NativeMBFerromagnet<R> {
|
||||
pub fn new<R2: Real>(b_start: R2, b_end: R2, max_m: R2) -> Self {
|
||||
Self {
|
||||
m: Vec3::zero(),
|
||||
curve: MBPgram::new(b_start.cast(), b_end.cast(), max_m.cast()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn curve(&self) -> MBPgram<R> {
|
||||
self.curve
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Material<R> for NativeMBFerromagnet<R> {
|
||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
||||
let target_b = context.with_m(self.m).b() + delta_b;
|
||||
// println!("step_b {}", target_b);
|
||||
self.m = Vec3::new(
|
||||
self.curve.move_b(self.m.x(), target_b.x()),
|
||||
self.curve.move_b(self.m.y(), target_b.y()),
|
||||
self.curve.move_b(self.m.z(), target_b.z()),
|
||||
);
|
||||
}
|
||||
fn m(&self) -> Vec3<R> {
|
||||
self.m
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SpirvMBFerromagnet<R>(NativeMBFerromagnet<R>);
|
||||
|
||||
impl<R: Real> SpirvMBFerromagnet<R> {
|
||||
pub fn new<R2: Real>(b_start: R2, b_end: R2, max_m: R2) -> Self {
|
||||
Self(NativeMBFerromagnet::new(b_start, b_end, max_m))
|
||||
}
|
||||
|
||||
pub fn curve(&self) -> MBPgram<R> {
|
||||
self.0.curve()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Material<R> for SpirvMBFerromagnet<R> {
|
||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
||||
let target_b = context.with_m(self.m()).b() + delta_b;
|
||||
let curve = coremem_types::mat::MBPgram::new(
|
||||
self.0.curve.b_start,
|
||||
self.0.curve.b_end,
|
||||
self.0.curve.max_m,
|
||||
);
|
||||
// println!("step_b {}", target_b);
|
||||
self.0.m = Vec3::new(
|
||||
curve.move_b(self.0.m.x(), target_b.x()),
|
||||
curve.move_b(self.0.m.y(), target_b.y()),
|
||||
curve.move_b(self.0.m.z(), target_b.z()),
|
||||
);
|
||||
}
|
||||
fn m(&self) -> Vec3<R> {
|
||||
self.0.m()
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: for debugging, use the same MBFerromagnet impl as we do in spirv impl.
|
||||
// pub type MBFerromagnet<R> = SpirvMBFerromagnet<R>;
|
||||
pub type MBFerromagnet<R> = NativeMBFerromagnet<R>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use float_eq::assert_float_eq;
|
||||
|
||||
#[test]
|
||||
fn curve_interior() {
|
||||
let curve = MBPgram::new(4.0, 6.0, 20.0f32);
|
||||
|
||||
assert_float_eq!(curve.move_b(0.0, 2.0), 0.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(0.0, 5.0), 0.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(1.0, 5.0), 1.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(20.0, 5.0), 20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-20.0, 4.0), -20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-20.0, -6.0), -20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(20.0, -4.0), 20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(10.0, -2.0), 10.0, abs <= 1e-5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn curve_exterior() {
|
||||
let curve = MBPgram::new(4.0, 6.0, 20.0f32);
|
||||
assert_float_eq!(curve.move_b(0.0, 6.0), 20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(0.0, 7.0), 20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(0.0, -6.0), -20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(0.0, -7.0), -20.0, abs <= 1e-5);
|
||||
|
||||
|
||||
assert_float_eq!(curve.move_b(2.0, -6.0), -20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(20.0, -6.0), -20.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(20.0, -5.0), 0.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(20.0, -4.5), 10.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-15.0, 4.5), -10.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-15.0, 5.0), 0.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-15.0, 5.5), 10.0, abs <= 1e-5);
|
||||
assert_float_eq!(curve.move_b(-15.0, 7.5), 20.0, abs <= 1e-5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn curve_3r1() {
|
||||
// slope of 3r1 is about M=793210*B
|
||||
// This is almost identical to iron (795615)!
|
||||
let curve = MBPgram::new(-0.3899, 0.3900, 310000f32);
|
||||
|
||||
// magnetizing:
|
||||
// v.s. 198893 in B(H) curve
|
||||
assert_float_eq!(curve.move_b(0.0, 0.250), 198703.0, abs <= 1.0);
|
||||
// v.s. 278321 in B(H) curve
|
||||
assert_float_eq!(curve.move_b(198703.0, 0.350), 278201.0, abs <= 1.0);
|
||||
assert_float_eq!(curve.move_b(278201.0, 0.390), 310000.0, abs <= 1.0);
|
||||
|
||||
// de-magnetizing:
|
||||
// From saturation, decreasing B causes NO decrease in M: instead, it causes a decrease in
|
||||
// H. This is probably BAD: in the B(H) curve, a large change in H always causes a large
|
||||
// change in B. The movement of H here is likely to induce current, whereas it SHOULDN'T.
|
||||
assert_float_eq!(curve.move_b(310000.0, 0.38995), 310000.0, abs <= 1.0);
|
||||
// v.s. 258626 in B(H); H = 220
|
||||
assert_float_eq!(curve.move_b(310000.0, 0.325), 258406.0, abs <= 1.0);
|
||||
// here's where H crosses 0 (v.s. B=0.325 in the B(H) curve... quite a difference)
|
||||
assert_float_eq!(curve.move_b(310000.0, 0.050), 39788.438, abs <= 1.0);
|
||||
// v.s. 35.0 in B(H)
|
||||
assert_float_eq!(curve.move_b(310000.0, 0.0), 39.75, abs <= 1.0);
|
||||
|
||||
// negative magnetization:
|
||||
// erase the magnetization: H = -40
|
||||
assert_float_eq!(curve.move_b(310000.0, -0.00005), 0.0, abs <= 0.1);
|
||||
// the magnetization has been completely erased:
|
||||
assert_float_eq!(curve.move_b(310000.0, -0.25), -198703.0, abs <= 1.0);
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
use crate::geom::{Meters, Region, Torus, Vec3, WorldRegion};
|
||||
use crate::geom::{Meters, Region, Torus, WorldRegion};
|
||||
use crate::real::{Real as _, ToFloat as _};
|
||||
use crate::types::vec::Vec3;
|
||||
use crate::sim::SampleableSim;
|
||||
use dyn_clone::{self, DynClone};
|
||||
use indexmap::IndexMap;
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use crate::geom::{Meters, Vec2, Vec3};
|
||||
use crate::geom::Meters;
|
||||
use crate::real::ToFloat as _;
|
||||
use crate::types::vec::{Vec2, Vec3};
|
||||
use crate::sim::{SampleableSim, Sample, StaticSim};
|
||||
use crate::meas::{self, AbstractMeasurement};
|
||||
use crossterm::{cursor, QueueableCommand as _};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
use crate::CellState;
|
||||
use crate::geom::{Line2d, Vec2, Vec3, Polygon2d};
|
||||
use crate::mat::Material;
|
||||
use super::Material;
|
||||
use crate::geom::{Line2d, Polygon2d};
|
||||
use crate::real::Real;
|
||||
use crate::sim::StepParametersMut;
|
||||
use crate::sim::legacy::{CellState, StepParametersMut};
|
||||
use crate::types::vec::{Vec2, Vec3};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use log::trace;
|
@@ -1,8 +1,8 @@
|
||||
//! database of common materials
|
||||
|
||||
use crate::geom::Vec3;
|
||||
use crate::mat::{AnisomorphicConductor, IsomorphicConductor, LinearMagnet, Ferroxcube3R1, MinimalSquare};
|
||||
use super::{AnisomorphicConductor, IsomorphicConductor, LinearMagnet, Ferroxcube3R1, MinimalSquare};
|
||||
use crate::real::Real;
|
||||
use crate::types::vec::Vec3;
|
||||
|
||||
pub fn conductor<R: Real, R2: Real>(conductivity: R2) -> IsomorphicConductor<R> {
|
||||
IsomorphicConductor::new(conductivity.cast())
|
@@ -1,7 +1,7 @@
|
||||
use crate::CellState;
|
||||
use crate::geom::Vec3;
|
||||
use crate::mat::Material;
|
||||
use super::Material;
|
||||
use crate::real::Real;
|
||||
use crate::sim::legacy::CellState;
|
||||
use crate::types::vec::Vec3;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
@@ -1,25 +1,22 @@
|
||||
use crate::CellState;
|
||||
use crate::geom::Vec3;
|
||||
use crate::real::Real;
|
||||
use crate::sim::{PmlParameters, PmlState, StepParameters, StepParametersMut};
|
||||
use crate::sim::legacy::{CellState, PmlParameters, PmlState, StepParameters, StepParametersMut};
|
||||
use crate::types::vec::Vec3;
|
||||
|
||||
use enum_dispatch::enum_dispatch;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
pub mod db;
|
||||
mod bh_ferromagnet;
|
||||
mod mb_ferromagnet;
|
||||
mod linear;
|
||||
|
||||
pub use bh_ferromagnet::*;
|
||||
pub use mb_ferromagnet::*;
|
||||
pub use coremem_types::mat::{
|
||||
AnisomorphicConductor,
|
||||
Ferroxcube3R1MH,
|
||||
FullyGenericMaterial,
|
||||
IsoConductorOr,
|
||||
IsomorphicConductor,
|
||||
MHPgram
|
||||
MHPgram,
|
||||
};
|
||||
pub use linear::*;
|
||||
|
||||
@@ -119,7 +116,7 @@ pub enum GenericMaterial<R> {
|
||||
Conductor(AnisomorphicConductor<R>),
|
||||
LinearMagnet(LinearMagnet<R>),
|
||||
Pml(Pml<R>),
|
||||
MBFerromagnet(MBFerromagnet<R>),
|
||||
MBPgram(MBPgram<R>),
|
||||
Ferroxcube3R1(Ferroxcube3R1<R>),
|
||||
MinimalSquare(MinimalSquare<R>),
|
||||
}
|
||||
@@ -155,9 +152,9 @@ impl<R> From<Pml<R>> for GenericMaterial<R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<MBFerromagnet<R>> for GenericMaterial<R> {
|
||||
fn from(inner: MBFerromagnet<R>) -> Self {
|
||||
Self::MBFerromagnet(inner)
|
||||
impl<R> From<MBPgram<R>> for GenericMaterial<R> {
|
||||
fn from(inner: MBPgram<R>) -> Self {
|
||||
Self::MBPgram(inner)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +177,7 @@ impl<R: Real> Material<R> for GenericMaterial<R> {
|
||||
Conductor(inner) => inner.step_parameters_mut(),
|
||||
LinearMagnet(inner) => inner.step_parameters_mut(),
|
||||
Pml(inner) => inner.step_parameters_mut(),
|
||||
MBFerromagnet(inner) => inner.step_parameters_mut(),
|
||||
MBPgram(inner) => inner.step_parameters_mut(),
|
||||
Ferroxcube3R1(inner) => inner.step_parameters_mut(),
|
||||
MinimalSquare(inner) => inner.step_parameters_mut(),
|
||||
}
|
||||
@@ -192,7 +189,7 @@ impl<R: Real> Material<R> for GenericMaterial<R> {
|
||||
Conductor(inner) => inner.m(),
|
||||
LinearMagnet(inner) => inner.m(),
|
||||
Pml(inner) => inner.m(),
|
||||
MBFerromagnet(inner) => inner.m(),
|
||||
MBPgram(inner) => inner.m(),
|
||||
Ferroxcube3R1(inner) => Material::m(inner),
|
||||
MinimalSquare(inner) => Material::m(inner),
|
||||
}
|
||||
@@ -204,7 +201,7 @@ impl<R: Real> Material<R> for GenericMaterial<R> {
|
||||
Conductor(inner) => inner.step_b(context, delta_b),
|
||||
LinearMagnet(inner) => inner.step_b(context, delta_b),
|
||||
Pml(inner) => inner.step_b(context, delta_b),
|
||||
MBFerromagnet(inner) => inner.step_b(context, delta_b),
|
||||
MBPgram(inner) => inner.step_b(context, delta_b),
|
||||
Ferroxcube3R1(inner) => inner.step_b(context, delta_b),
|
||||
MinimalSquare(inner) => inner.step_b(context, delta_b),
|
||||
}
|
||||
@@ -216,7 +213,7 @@ impl<R: Real> Material<R> for GenericMaterial<R> {
|
||||
pub enum GenericMaterialNoPml<R> {
|
||||
Conductor(AnisomorphicConductor<R>),
|
||||
LinearMagnet(LinearMagnet<R>),
|
||||
MBFerromagnet(MBFerromagnet<R>),
|
||||
MBPgram(MBPgram<R>),
|
||||
Ferroxcube3R1(Ferroxcube3R1<R>),
|
||||
MinimalSquare(MinimalSquare<R>),
|
||||
}
|
||||
@@ -239,7 +236,7 @@ impl<R: Real> Material<R> for GenericMaterialNoPml<R> {
|
||||
match self {
|
||||
Conductor(inner) => inner.step_parameters_mut(),
|
||||
LinearMagnet(inner) => inner.step_parameters_mut(),
|
||||
MBFerromagnet(inner) => inner.step_parameters_mut(),
|
||||
MBPgram(inner) => inner.step_parameters_mut(),
|
||||
Ferroxcube3R1(inner) => inner.step_parameters_mut(),
|
||||
MinimalSquare(inner) => inner.step_parameters_mut(),
|
||||
}
|
||||
@@ -250,7 +247,7 @@ impl<R: Real> Material<R> for GenericMaterialNoPml<R> {
|
||||
match self {
|
||||
Conductor(inner) => inner.m(),
|
||||
LinearMagnet(inner) => inner.m(),
|
||||
MBFerromagnet(inner) => inner.m(),
|
||||
MBPgram(inner) => inner.m(),
|
||||
Ferroxcube3R1(inner) => Material::m(inner),
|
||||
MinimalSquare(inner) => Material::m(inner),
|
||||
}
|
||||
@@ -261,7 +258,7 @@ impl<R: Real> Material<R> for GenericMaterialNoPml<R> {
|
||||
match self {
|
||||
Conductor(inner) => inner.step_b(context, delta_b),
|
||||
LinearMagnet(inner) => inner.step_b(context, delta_b),
|
||||
MBFerromagnet(inner) => inner.step_b(context, delta_b),
|
||||
MBPgram(inner) => inner.step_b(context, delta_b),
|
||||
Ferroxcube3R1(inner) => inner.step_b(context, delta_b),
|
||||
MinimalSquare(inner) => inner.step_b(context, delta_b),
|
||||
}
|
||||
@@ -320,6 +317,46 @@ impl<R: Real> Material<R> for GenericMaterialOneField<R> {
|
||||
}
|
||||
|
||||
// coremem_types adapters
|
||||
// TODO: move this to a dedicated file
|
||||
|
||||
/// the coremem_types Materials are stateless;
|
||||
/// rather than hold onto their own magnetic fields (for example), the simulation holds that.
|
||||
/// that's counter to the original cpu-only simulation, in which materials hold their own state.
|
||||
///
|
||||
/// this type adapts any stateless coremem_types::mat::Material type to be a coremem::mat::Material.
|
||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AdaptStateless<R, M> {
|
||||
mat: M,
|
||||
m: Vec3<R>,
|
||||
}
|
||||
|
||||
impl<R, M> AdaptStateless<R, M> {
|
||||
pub fn into_inner(self) -> M {
|
||||
self.mat
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Default, M> From<M> for AdaptStateless<R, M> {
|
||||
fn from(mat: M) -> Self {
|
||||
Self { mat, m: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real, M: coremem_types::mat::Material<R>> Material<R> for AdaptStateless<R, M> {
|
||||
fn m(&self) -> Vec3<R> {
|
||||
self.m
|
||||
}
|
||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
||||
let c = self.mat.conductivity();
|
||||
StepParametersMut::default().with_conductivity(c)
|
||||
}
|
||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
||||
let target_b = context.with_m(self.m).b() + delta_b;
|
||||
self.m = self.mat.move_b_vec(self.m, target_b);
|
||||
}
|
||||
}
|
||||
|
||||
// conductors: these are truly stateless
|
||||
impl<R: Real> Material<R> for AnisomorphicConductor<R> {
|
||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
||||
let c = coremem_types::mat::Material::conductivity(self);
|
||||
@@ -332,3 +369,10 @@ impl<R: Real> Material<R> for IsomorphicConductor<R> {
|
||||
StepParametersMut::default().with_conductivity(c)
|
||||
}
|
||||
}
|
||||
|
||||
pub type MBPgram<R> = AdaptStateless<R, coremem_types::mat::MBPgram<R>>;
|
||||
impl<R: Real> MBPgram<R> {
|
||||
pub fn new(b_start: R, b_end: R, m_max: R) -> Self {
|
||||
coremem_types::mat::MBPgram::new(b_start, b_end, m_max).into()
|
||||
}
|
||||
}
|
1696
crates/coremem/src/sim/legacy/mod.rs
Normal file
1696
crates/coremem/src/sim/legacy/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,13 @@
|
||||
use serde::de::Deserializer;
|
||||
use serde::ser::Serializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::mat::{
|
||||
AnisomorphicConductor,
|
||||
IsoConductorOr,
|
||||
IsomorphicConductor,
|
||||
Ferroxcube3R1MH,
|
||||
FullyGenericMaterial,
|
||||
MaterialExt as _,
|
||||
MBFerromagnet,
|
||||
MBPgram,
|
||||
MHPgram,
|
||||
Static
|
||||
};
|
||||
use crate::geom::{Index, Vec3, Vec3u};
|
||||
use crate::geom::Index;
|
||||
use coremem_types::vec::{Vec3, Vec3u};
|
||||
|
||||
/// hide the actual spirv backend structures inside a submodule to make their use/boundary clear.
|
||||
mod ffi {
|
||||
pub use spirv_backend::entry_points;
|
||||
pub use spirv_backend::sim::SerializedSimMeta;
|
||||
pub use spirv_backend::support::Optional;
|
||||
pub use coremem_types::mat::MBPgram;
|
||||
}
|
||||
|
||||
// conversion traits for types defined cross-lib
|
||||
@@ -35,29 +21,25 @@ pub trait IntoLib {
|
||||
fn into_lib(self) -> Self::Lib;
|
||||
}
|
||||
|
||||
macro_rules! identity {
|
||||
($($param:ident,)* => $t:ty) => {
|
||||
impl<$($param: IntoFfi),*> IntoFfi for $t {
|
||||
type Ffi = $t;
|
||||
fn into_ffi(self) -> Self::Ffi {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl<$($param: IntoLib),*> IntoLib for $t {
|
||||
type Lib = $t;
|
||||
fn into_lib(self) -> Self::Lib {
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
pub trait Identity { }
|
||||
impl<T: Identity> IntoFfi for T {
|
||||
type Ffi = Self;
|
||||
fn into_ffi(self) -> Self::Ffi {
|
||||
self
|
||||
}
|
||||
}
|
||||
impl<T: Identity> IntoLib for T {
|
||||
type Lib = Self;
|
||||
fn into_lib(self) -> Self::Lib {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: should work for any other lifetime, not just 'static
|
||||
identity!(=> f32);
|
||||
identity!(=> &'static str);
|
||||
identity!(T0, T1, => (T0, T1));
|
||||
identity!(=> Vec3u);
|
||||
identity!(T, => Vec3<T>);
|
||||
impl Identity for f32 {}
|
||||
impl<'a> Identity for &'a str {}
|
||||
impl<T0: Identity, T1: Identity> Identity for (T0, T1) {}
|
||||
impl Identity for Vec3u {}
|
||||
impl<T: Identity> Identity for Vec3<T> {}
|
||||
|
||||
impl<L: IntoFfi> IntoFfi for Option<L>
|
||||
where L::Ffi: Default
|
||||
@@ -82,113 +64,31 @@ impl<F: Copy + IntoLib> IntoLib for ffi::Optional<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoFfi for MBPgram<f32> {
|
||||
type Ffi = ffi::MBPgram<f32>;
|
||||
fn into_ffi(self) -> Self::Ffi {
|
||||
Self::Ffi::new(self.b_start, self.b_end, self.max_m)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoLib for ffi::MBPgram<f32> {
|
||||
type Lib = MBPgram<f32>;
|
||||
fn into_lib(self) -> Self::Lib {
|
||||
Self::Lib::new(self.b_start, self.b_end, self.max_m)
|
||||
}
|
||||
}
|
||||
|
||||
identity!( => MHPgram<f32>);
|
||||
identity!( => Ferroxcube3R1MH);
|
||||
identity!( => FullyGenericMaterial<f32>);
|
||||
identity!(R, M, => IsoConductorOr<R, M>);
|
||||
|
||||
// N.B.: this isn't fully correct, as Static also encodes the magnetic component
|
||||
impl From<Static<f32>> for FullyGenericMaterial<f32> {
|
||||
fn from(m: Static<f32>) -> Self {
|
||||
AnisomorphicConductor::new(m.conductivity).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MBFerromagnet<f32>> for FullyGenericMaterial<f32> {
|
||||
fn from(m: MBFerromagnet<f32>) -> Self {
|
||||
m.curve().into_ffi().into()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: if we lift this type out of the spirv crate we can derive serde based on a feature flag
|
||||
// this is bitwise- and type-compatible with the spirv SimMeta, except we need serde traits
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct SimMeta {
|
||||
pub struct SimMeta<R> {
|
||||
pub(crate) dim: Index,
|
||||
pub(crate) inv_feature_size: f32,
|
||||
pub(crate) time_step: f32,
|
||||
pub(crate) feature_size: f32,
|
||||
pub(crate) inv_feature_size: R,
|
||||
pub(crate) time_step: R,
|
||||
pub(crate) feature_size: R,
|
||||
}
|
||||
|
||||
impl IntoFfi for SimMeta {
|
||||
type Ffi = ffi::SerializedSimMeta;
|
||||
impl<R: IntoFfi> IntoFfi for SimMeta<R> {
|
||||
type Ffi = ffi::SerializedSimMeta<R::Ffi>;
|
||||
fn into_ffi(self) -> Self::Ffi {
|
||||
Self::Ffi {
|
||||
dim: self.dim.0.into_ffi(),
|
||||
inv_feature_size: self.inv_feature_size,
|
||||
time_step: self.time_step,
|
||||
feature_size: self.feature_size,
|
||||
inv_feature_size: self.inv_feature_size.into_ffi(),
|
||||
time_step: self.time_step.into_ffi(),
|
||||
feature_size: self.feature_size.into_ffi(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Store the FFI form in memory, but serialize via the lib form.
|
||||
#[derive(Clone, Default, PartialEq)]
|
||||
pub struct Remote<F>(F);
|
||||
|
||||
impl<F> Remote<F> {
|
||||
pub fn into_inner(self) -> F {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: IntoFfi> From<L> for Remote<L::Ffi> {
|
||||
fn from(l: L) -> Self {
|
||||
Remote(l.into_ffi())
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> std::ops::Deref for Remote<F> {
|
||||
type Target = F;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Serialize for Remote<F>
|
||||
where F: Clone + IntoLib,
|
||||
F::Lib: Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let local = self.0.clone().into_lib();
|
||||
local.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, F> Deserialize<'de> for Remote<F>
|
||||
where F: IntoLib,
|
||||
F::Lib: Deserialize<'de> + IntoFfi<Ffi=F>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let local: F::Lib = Deserialize::deserialize(deserializer)?;
|
||||
Ok(Remote(local.into_ffi()))
|
||||
}
|
||||
}
|
||||
|
||||
// FUNCTION BINDINGS
|
||||
pub fn entry_points<L>() -> Option<(&'static str, &'static str)>
|
||||
where
|
||||
L: IntoFfi,
|
||||
L::Ffi: 'static
|
||||
pub fn entry_points<L: 'static>() -> Option<(&'static str, &'static str)>
|
||||
{
|
||||
ffi::entry_points::<L::Ffi>().into_lib()
|
||||
ffi::entry_points::<L>().into_lib()
|
||||
}
|
||||
|
@@ -8,27 +8,26 @@ use wgpu;
|
||||
use wgpu::util::DeviceExt as _;
|
||||
use log::{info, trace, warn};
|
||||
|
||||
use crate::geom::{Coord, Index, Meters, Vec3};
|
||||
use crate::geom::{Coord, Index, Meters};
|
||||
use crate::real::Real as _;
|
||||
use crate::sim::{CellStateWithM, GenericSim, MaterialSim, Sample, SampleableSim};
|
||||
use crate::stim::AbstractStimulus;
|
||||
use crate::types::vec::Vec3;
|
||||
use coremem_types::mat::{FullyGenericMaterial, Material};
|
||||
|
||||
mod bindings;
|
||||
pub use bindings::{entry_points, IntoFfi, IntoLib, Remote, SimMeta};
|
||||
pub use bindings::{entry_points, IntoFfi as _, SimMeta};
|
||||
|
||||
/// Wrapper around an inner state object which offloads stepping onto a spirv backend (e.g. GPU).
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
#[serde(bound(serialize = "M: Serialize + IntoFfi, M::Ffi: Clone + IntoLib<Lib=M>"))]
|
||||
#[serde(bound(deserialize = "M: Deserialize<'de> + IntoFfi, M::Ffi: IntoLib<Lib=M>"))]
|
||||
pub struct SpirvSim<M=FullyGenericMaterial<f32>>
|
||||
where M: IntoFfi,
|
||||
{
|
||||
meta: SimMeta,
|
||||
// TODO: make this generic over R
|
||||
meta: SimMeta<f32>,
|
||||
e: Vec<Vec3<f32>>,
|
||||
h: Vec<Vec3<f32>>,
|
||||
m: Vec<Vec3<f32>>,
|
||||
mat: Vec<Remote<M::Ffi>>,
|
||||
mat: Vec<M>,
|
||||
step_no: u64,
|
||||
// hidden behind an Arc to allow for cheap clones.
|
||||
// XXX not confident that wgpu is actually properly synchronized for us to omit a Mutex here
|
||||
@@ -46,8 +45,7 @@ struct WgpuData {
|
||||
}
|
||||
|
||||
impl WgpuData {
|
||||
pub fn new<M: IntoFfi>(volume: u64) -> Self
|
||||
where M::Ffi: 'static
|
||||
pub fn new<M: 'static>(volume: u64) -> Self
|
||||
{
|
||||
info!("WgpuData::new({})", volume);
|
||||
use std::mem::size_of;
|
||||
@@ -74,28 +72,29 @@ impl Default for WgpuData {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi + PartialEq> MaterialSim for SpirvSim<M>
|
||||
impl<M> MaterialSim for SpirvSim<M>
|
||||
where
|
||||
M::Ffi: Send + Sync + Material<f32> + Clone + IntoLib<Lib=M> + 'static
|
||||
// TODO: extraneous bounds?
|
||||
M: Send + Sync + Material<f32> + PartialEq + Clone + 'static
|
||||
{
|
||||
type Material = M;
|
||||
|
||||
fn put_material<C: Coord, M2: Into<Self::Material>>(&mut self, pos: C, mat: M2) {
|
||||
let pos_sim = pos.to_index(self.feature_size());
|
||||
let flat_idx = self.flat_index(pos_sim).unwrap();
|
||||
self.mat[flat_idx] = Remote::from(mat.into());
|
||||
self.mat[flat_idx] = mat.into();
|
||||
}
|
||||
|
||||
fn get_material<C: Coord>(&self, pos: C) -> Self::Material {
|
||||
let pos_sim = pos.to_index(self.feature_size());
|
||||
let flat_idx = self.flat_index(pos_sim).unwrap();
|
||||
self.mat[flat_idx].clone().into_inner().into_lib()
|
||||
self.mat[flat_idx].clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi> SampleableSim for SpirvSim<M>
|
||||
impl<M> SampleableSim for SpirvSim<M>
|
||||
where
|
||||
M::Ffi: Send + Sync + Material<f32>
|
||||
M: Send + Sync + Material<f32>
|
||||
{
|
||||
fn sample(&self, pos: Meters) -> Sample {
|
||||
// TODO: smarter sampling than nearest neighbor?
|
||||
@@ -128,9 +127,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi> GenericSim for SpirvSim<M>
|
||||
impl<M> GenericSim for SpirvSim<M>
|
||||
where
|
||||
M::Ffi: Send + Sync + Material<f32> + 'static
|
||||
M: Send + Sync + Material<f32> + 'static
|
||||
{
|
||||
fn step_multiple<S: AbstractStimulus>(&mut self, num_steps: u32, s: &S) {
|
||||
self.step_spirv(num_steps, s);
|
||||
@@ -153,8 +152,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi> SpirvSim<M>
|
||||
where M::Ffi: Default + 'static
|
||||
impl<M> SpirvSim<M>
|
||||
where M: Default + 'static
|
||||
{
|
||||
pub fn new(size: Index, feature_size: f32) -> Self {
|
||||
Self::new_with_wgpu_handle(size, feature_size, Some(Arc::new(WgpuData::new::<M>(size.volume()))))
|
||||
@@ -167,7 +166,7 @@ impl<M: IntoFfi> SpirvSim<M>
|
||||
fn new_with_wgpu_handle(size: Index, feature_size: f32, wgpu: Option<Arc<WgpuData>>) -> Self {
|
||||
info!("SpirvSim::new({:?}, {})", size, feature_size);
|
||||
let flat_size = size.volume() as usize;
|
||||
if flat_size * std::mem::size_of::<M::Ffi>() >= 0x40000000 {
|
||||
if flat_size * std::mem::size_of::<M>() >= 0x40000000 {
|
||||
warn!("simulation size ({:?}) is greater than what is tested for: anything could happen!", size);
|
||||
}
|
||||
if flat_size > spirv_backend::support::MAX_UNSIZED_ARRAY {
|
||||
@@ -198,7 +197,7 @@ impl<M: IntoFfi> SpirvSim<M>
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi> SpirvSim<M> {
|
||||
impl<M> SpirvSim<M> {
|
||||
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() {
|
||||
@@ -209,9 +208,9 @@ impl<M: IntoFfi> SpirvSim<M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: IntoFfi> SpirvSim<M>
|
||||
impl<M> SpirvSim<M>
|
||||
where
|
||||
M::Ffi: Send + Sync + Material<f32> + 'static
|
||||
M: Send + Sync + Material<f32> + 'static
|
||||
{
|
||||
#[allow(unused)] // used for test
|
||||
fn apply_stimulus(&mut self, stim: &dyn AbstractStimulus) {
|
||||
@@ -652,9 +651,9 @@ fn make_pipelines(device: &wgpu::Device, shader_module: &wgpu::ShaderModule, ent
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::real::ToFloat as _;
|
||||
use crate::sim::{SampleableSim, SimState};
|
||||
use crate::sim::SampleableSim;
|
||||
use crate::sim::legacy::{self, SimState};
|
||||
use crate::mat::{self, AnisomorphicConductor};
|
||||
use more_asserts::assert_lt;
|
||||
fn mean_magnitude_e(sim: &dyn SampleableSim) -> f32 {
|
||||
(sim.map_sum_enumerated(|_pos: Index, cell| {
|
||||
cell.e().mag().to_f64()
|
||||
@@ -715,30 +714,6 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
mod details {
|
||||
use super::*;
|
||||
use rand::{Rng as _, SeedableRng as _};
|
||||
#[test]
|
||||
fn mbpgram() {
|
||||
for seed in 0..1000 {
|
||||
let mut rng = rand::rngs::StdRng::seed_from_u64(seed);
|
||||
let max_m = rng.gen_range(0.0..1e5);
|
||||
let b_end = rng.gen_range(0.0..1e-3);
|
||||
let b_start = rng.gen_range(-b_end..b_end);
|
||||
let ref_mbp = crate::mat::MBPgram::new(b_start, b_end, max_m);
|
||||
let dut_mbp = coremem_types::mat::MBPgram::new(b_start, b_end, max_m);
|
||||
println!("Using max_m: {}, b: ({}, {})", max_m, b_start, b_end);
|
||||
for _ in 0..1000 {
|
||||
let start_m = rng.gen_range(-2e5..2e5);
|
||||
let target_b = rng.gen_range(-2e-3..2e-3);
|
||||
let ref_m = ref_mbp.move_b(start_m, target_b);
|
||||
let dut_m = dut_mbp.move_b(start_m, target_b);
|
||||
assert_lt!((dut_m - ref_m).abs(), 0.05, "(M:{}, b -> {}) -> {} v.s. {} expected", start_m, target_b, dut_m, ref_m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod cpu {
|
||||
//! Validate the spirv_backend implementation against the reference, but
|
||||
//! invoke it natively -- not through rgpu
|
||||
@@ -934,8 +909,12 @@ mod test {
|
||||
let slope = rng.gen_range(0.0..0.9*f32::mu0_inv());
|
||||
let b_end = b_start + b_range;
|
||||
let m_max = b_range * slope;
|
||||
ref_state.put_material(Index::new(x, y, z), mat::MBFerromagnet::new(b_start, b_end, m_max));
|
||||
dut_state.put_material(Index::new(x, y, z), mat::MBFerromagnet::new(b_start, b_end, m_max));
|
||||
ref_state.put_material(Index::new(x, y, z), legacy::mat::MBPgram::new(
|
||||
b_start.cast(), b_end.cast(), m_max.cast()
|
||||
));
|
||||
dut_state.put_material(Index::new(x, y, z), coremem_types::mat::MBPgram::new(
|
||||
b_start, b_end, m_max
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -960,8 +939,8 @@ mod test {
|
||||
// let size = Index::new(3, 3, 3);
|
||||
// let seed = 0; // 0 => 28, 4 => 28
|
||||
// let steps = 1000;
|
||||
// let ref_mat = mat::MBFerromagnet::new(0e-4, 9.02e-3, 1e4).into();
|
||||
// let dut_mat = mat::MBFerromagnet::new(0e-4, 9.02e-3, 1e4);
|
||||
// let ref_mat = mat::MBPgram::new(0e-4, 9.02e-3, 1e4).into();
|
||||
// let dut_mat = mat::MBPgram::new(0e-4, 9.02e-3, 1e4);
|
||||
// let mut ref_state = SimState::new(size, 1e-3);
|
||||
// let mut dut_state = SpirvSim::new(size, 1e-3);
|
||||
// ref_state.put_material(Index::new(1, 1, 1), ref_mat);
|
||||
@@ -978,8 +957,8 @@ mod test {
|
||||
// let size = Index::new(3, 3, 1);
|
||||
// let seed = 0; // 0 => 28, 4 => 28
|
||||
// let steps = 1000;
|
||||
// let ref_mat = mat::MBFerromagnet::new(0e-4, 9.02e-3, 1e4).into();
|
||||
// let dut_mat = mat::MBFerromagnet::new(0e-4, 9.02e-3, 1e4);
|
||||
// let ref_mat = mat::MBPgram::new(0e-4, 9.02e-3, 1e4).into();
|
||||
// let dut_mat = mat::MBPgram::new(0e-4, 9.02e-3, 1e4);
|
||||
// let mut ref_state = SimState::new(size, 1e-3);
|
||||
// let mut dut_state = SpirvSim::new(size, 1e-3);
|
||||
// ref_state.put_material(Index::new(1, 1, 0), ref_mat);
|
||||
@@ -1198,8 +1177,12 @@ mod test {
|
||||
let slope = rng.gen_range(0.0..0.9*f32::mu0_inv());
|
||||
let b_end = b_start + b_range;
|
||||
let m_max = b_range * slope;
|
||||
ref_state.put_material(Index::new(x, y, z), mat::MBFerromagnet::new(b_start, b_end, m_max));
|
||||
dut_state.put_material(Index::new(x, y, z), mat::MBFerromagnet::new(b_start, b_end, m_max));
|
||||
ref_state.put_material(Index::new(x, y, z), legacy::mat::MBPgram::new(
|
||||
b_start.cast(), b_end.cast(), m_max.cast()
|
||||
));
|
||||
dut_state.put_material(Index::new(x, y, z), coremem_types::mat::MBPgram::new(
|
||||
b_start, b_end, m_max
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use crate::real::*;
|
||||
use crate::geom::{Meters, Region, Vec3};
|
||||
use crate::types::vec::Vec3;
|
||||
use crate::geom::{Meters, Region};
|
||||
use rand;
|
||||
|
||||
type Fields = (Vec3<f32>, Vec3<f32>);
|
||||
|
@@ -1,7 +1,8 @@
|
||||
//! Post-processing tools
|
||||
use coremem::meas::AbstractMeasurement;
|
||||
use coremem::render::{ColorTermRenderer, Renderer as _, RenderConfig, SerializedFrame};
|
||||
use coremem::sim::{SimState, StaticSim};
|
||||
use coremem::sim::StaticSim;
|
||||
use coremem::sim::legacy::SimState;
|
||||
|
||||
use itertools::Itertools as _;
|
||||
use lru::LruCache;
|
||||
|
@@ -12,32 +12,30 @@ pub use spirv_std::glam;
|
||||
#[cfg(not(target_arch = "spirv"))]
|
||||
use spirv_std::macros::spirv;
|
||||
|
||||
pub mod mat;
|
||||
pub mod sim;
|
||||
pub mod support;
|
||||
|
||||
pub use sim::{SerializedSimMeta, SerializedStepE, SerializedStepH};
|
||||
pub use support::{Optional, UnsizedArray};
|
||||
|
||||
use mat::{IsoConductorOr, FullyGenericMaterial};
|
||||
|
||||
use coremem_types::mat::{Ferroxcube3R1MH, Material};
|
||||
use coremem_types::mat::{Ferroxcube3R1MH, FullyGenericMaterial, IsoConductorOr, Material};
|
||||
use coremem_types::real::Real;
|
||||
use coremem_types::vec::{Vec3, Vec3u};
|
||||
|
||||
type Iso3R1 = IsoConductorOr<Ferroxcube3R1MH>;
|
||||
type Iso3R1<R> = IsoConductorOr<R, Ferroxcube3R1MH>;
|
||||
|
||||
fn glam_vec_to_internal(v: glam::UVec3) -> Vec3u {
|
||||
Vec3u::new(v.x, v.y, v.z)
|
||||
}
|
||||
|
||||
fn step_h<M: Material<f32>>(
|
||||
fn step_h<R: Real, M: Material<R>>(
|
||||
id: Vec3u,
|
||||
meta: &SerializedSimMeta,
|
||||
stimulus_h: &UnsizedArray<Vec3<f32>>,
|
||||
meta: &SerializedSimMeta<R>,
|
||||
stimulus_h: &UnsizedArray<Vec3<R>>,
|
||||
material: &UnsizedArray<M>,
|
||||
e: &UnsizedArray<Vec3<f32>>,
|
||||
h: &mut UnsizedArray<Vec3<f32>>,
|
||||
m: &mut UnsizedArray<Vec3<f32>>,
|
||||
e: &UnsizedArray<Vec3<R>>,
|
||||
h: &mut UnsizedArray<Vec3<R>>,
|
||||
m: &mut UnsizedArray<Vec3<R>>,
|
||||
) {
|
||||
if id.x() < meta.dim.x() && id.y() < meta.dim.y() && id.z() < meta.dim.z() {
|
||||
let sim_state = SerializedStepH::new(meta, stimulus_h, material, e, h, m);
|
||||
@@ -46,13 +44,13 @@ fn step_h<M: Material<f32>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn step_e<M: Material<f32>>(
|
||||
fn step_e<R: Real, M: Material<R>>(
|
||||
id: Vec3u,
|
||||
meta: &SerializedSimMeta,
|
||||
stimulus_e: &UnsizedArray<Vec3<f32>>,
|
||||
meta: &SerializedSimMeta<R>,
|
||||
stimulus_e: &UnsizedArray<Vec3<R>>,
|
||||
material: &UnsizedArray<M>,
|
||||
e: &mut UnsizedArray<Vec3<f32>>,
|
||||
h: &UnsizedArray<Vec3<f32>>,
|
||||
e: &mut UnsizedArray<Vec3<R>>,
|
||||
h: &UnsizedArray<Vec3<R>>,
|
||||
) {
|
||||
if id.x() < meta.dim.x() && id.y() < meta.dim.y() && id.z() < meta.dim.z() {
|
||||
let sim_state = SerializedStepE::new(meta, stimulus_e, material, e, h);
|
||||
@@ -66,10 +64,10 @@ fn step_e<M: Material<f32>>(
|
||||
pub fn entry_points<M: 'static>() -> Optional<(&'static str, &'static str)> {
|
||||
use core::any::TypeId;
|
||||
let mappings = [
|
||||
(TypeId::of::<FullyGenericMaterial>(),
|
||||
(TypeId::of::<FullyGenericMaterial<f32>>(),
|
||||
("step_h_generic_material", "step_e_generic_material")
|
||||
),
|
||||
(TypeId::of::<Iso3R1>(),
|
||||
(TypeId::of::<Iso3R1<f32>>(),
|
||||
("step_h_iso_3r1", "step_e_iso_3r1")
|
||||
),
|
||||
];
|
||||
@@ -83,19 +81,19 @@ pub fn entry_points<M: 'static>() -> Optional<(&'static str, &'static str)> {
|
||||
}
|
||||
|
||||
macro_rules! steps {
|
||||
($mat:ty, $step_h:ident, $step_e:ident) => {
|
||||
($flt:ty, $mat:ty, $step_h:ident, $step_e:ident) => {
|
||||
// LocalSize/numthreads
|
||||
#[spirv(compute(threads(4, 4, 4)))]
|
||||
pub fn $step_h(
|
||||
#[spirv(global_invocation_id)] id: glam::UVec3,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta<$flt>,
|
||||
// XXX: delete this input?
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus_e: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] stimulus_h: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] _unused_stimulus_e: &UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] stimulus_h: &UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] material: &UnsizedArray<$mat>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] e: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] h: &mut UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 6)] m: &mut UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] e: &UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] h: &mut UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 6)] m: &mut UnsizedArray<Vec3<$flt>>,
|
||||
) {
|
||||
step_h(glam_vec_to_internal(id), meta, stimulus_h, material, e, h, m)
|
||||
}
|
||||
@@ -103,20 +101,20 @@ macro_rules! steps {
|
||||
#[spirv(compute(threads(4, 4, 4)))]
|
||||
pub fn $step_e(
|
||||
#[spirv(global_invocation_id)] id: glam::UVec3,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stimulus_e: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 0)] meta: &SerializedSimMeta<$flt>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] stimulus_e: &UnsizedArray<Vec3<$flt>>,
|
||||
// XXX: delete this input?
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] _unused_stimulus_h: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 2)] _unused_stimulus_h: &UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 3)] material: &UnsizedArray<$mat>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] e: &mut UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] h: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 4)] e: &mut UnsizedArray<Vec3<$flt>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 5)] h: &UnsizedArray<Vec3<$flt>>,
|
||||
// XXX: can/should this m input be deleted?
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 6)] _unused_m: &UnsizedArray<Vec3<f32>>,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 6)] _unused_m: &UnsizedArray<Vec3<$flt>>,
|
||||
) {
|
||||
step_e(glam_vec_to_internal(id), meta, stimulus_e, material, e, h)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
steps!(FullyGenericMaterial, step_h_generic_material, step_e_generic_material);
|
||||
steps!(Iso3R1, step_h_iso_3r1, step_e_iso_3r1);
|
||||
steps!(f32, FullyGenericMaterial<f32>, step_h_generic_material, step_e_generic_material);
|
||||
steps!(f32, Iso3R1<f32>, step_h_iso_3r1, step_e_iso_3r1);
|
||||
|
@@ -1,4 +0,0 @@
|
||||
// TODO: plumb the R parameter through and remove this.
|
||||
pub type FullyGenericMaterial = coremem_types::mat::FullyGenericMaterial<f32>;
|
||||
pub type IsoConductorOr<M> = coremem_types::mat::IsoConductorOr<f32, M>;
|
||||
|
@@ -3,43 +3,45 @@ use crate::support::{
|
||||
Array3, Array3Mut, ArrayHandle, ArrayHandleMut, Optional, UnsizedArray
|
||||
};
|
||||
use coremem_types::mat::Material;
|
||||
use coremem_types::real::{Real as _};
|
||||
use coremem_types::real::Real;
|
||||
use coremem_types::vec::{Vec3, Vec3u};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SerializedSimMeta {
|
||||
pub struct SerializedSimMeta<R> {
|
||||
pub dim: Vec3u,
|
||||
pub inv_feature_size: f32,
|
||||
pub time_step: f32,
|
||||
pub feature_size: f32,
|
||||
pub inv_feature_size: R,
|
||||
pub time_step: R,
|
||||
pub feature_size: R,
|
||||
}
|
||||
|
||||
|
||||
/// Whatever data we received from the host in their call to step_h
|
||||
pub struct SerializedStepH<'a, M> {
|
||||
meta: &'a SerializedSimMeta,
|
||||
stimulus_h: &'a UnsizedArray<Vec3<f32>>,
|
||||
pub struct SerializedStepH<'a, R, M> {
|
||||
meta: &'a SerializedSimMeta<R>,
|
||||
stimulus_h: &'a UnsizedArray<Vec3<R>>,
|
||||
material: &'a UnsizedArray<M>,
|
||||
e: &'a UnsizedArray<Vec3<f32>>,
|
||||
h: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
m: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
e: &'a UnsizedArray<Vec3<R>>,
|
||||
h: &'a mut UnsizedArray<Vec3<R>>,
|
||||
m: &'a mut UnsizedArray<Vec3<R>>,
|
||||
}
|
||||
|
||||
impl<'a, M> SerializedStepH<'a, M> {
|
||||
impl<'a, R, M> SerializedStepH<'a, R, M> {
|
||||
pub fn new(
|
||||
meta: &'a SerializedSimMeta,
|
||||
stimulus_h: &'a UnsizedArray<Vec3<f32>>,
|
||||
meta: &'a SerializedSimMeta<R>,
|
||||
stimulus_h: &'a UnsizedArray<Vec3<R>>,
|
||||
material: &'a UnsizedArray<M>,
|
||||
e: &'a UnsizedArray<Vec3<f32>>,
|
||||
h: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
m: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
e: &'a UnsizedArray<Vec3<R>>,
|
||||
h: &'a mut UnsizedArray<Vec3<R>>,
|
||||
m: &'a mut UnsizedArray<Vec3<R>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
meta, stimulus_h, material, e, h, m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(self, idx: Vec3u) -> StepHContext<'a, M> {
|
||||
impl<'a, R: Real, M> SerializedStepH<'a, R, M> {
|
||||
pub fn index(self, idx: Vec3u) -> StepHContext<'a, R, M> {
|
||||
let dim = self.meta.dim;
|
||||
let stim_h_matrix = Array3::new(self.stimulus_h, dim);
|
||||
let mat_matrix = Array3::new(self.material, dim);
|
||||
@@ -71,28 +73,30 @@ impl<'a, M> SerializedStepH<'a, M> {
|
||||
}
|
||||
|
||||
/// Whatever data we received from the host in their call to step_e
|
||||
pub struct SerializedStepE<'a, M> {
|
||||
meta: &'a SerializedSimMeta,
|
||||
stimulus_e: &'a UnsizedArray<Vec3<f32>>,
|
||||
pub struct SerializedStepE<'a, R, M> {
|
||||
meta: &'a SerializedSimMeta<R>,
|
||||
stimulus_e: &'a UnsizedArray<Vec3<R>>,
|
||||
material: &'a UnsizedArray<M>,
|
||||
e: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
h: &'a UnsizedArray<Vec3<f32>>,
|
||||
e: &'a mut UnsizedArray<Vec3<R>>,
|
||||
h: &'a UnsizedArray<Vec3<R>>,
|
||||
}
|
||||
|
||||
impl<'a, M> SerializedStepE<'a, M> {
|
||||
impl<'a, R, M> SerializedStepE<'a, R, M> {
|
||||
pub fn new(
|
||||
meta: &'a SerializedSimMeta,
|
||||
stimulus_e: &'a UnsizedArray<Vec3<f32>>,
|
||||
meta: &'a SerializedSimMeta<R>,
|
||||
stimulus_e: &'a UnsizedArray<Vec3<R>>,
|
||||
material: &'a UnsizedArray<M>,
|
||||
e: &'a mut UnsizedArray<Vec3<f32>>,
|
||||
h: &'a UnsizedArray<Vec3<f32>>,
|
||||
e: &'a mut UnsizedArray<Vec3<R>>,
|
||||
h: &'a UnsizedArray<Vec3<R>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
meta, stimulus_e, material, e, h
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn index(self, idx: Vec3u) -> StepEContext<'a, M> {
|
||||
impl<'a, R: Real, M> SerializedStepE<'a, R, M> {
|
||||
pub fn index(self, idx: Vec3u) -> StepEContext<'a, R, M> {
|
||||
let dim = self.meta.dim;
|
||||
let stim_e_matrix = Array3::new(self.stimulus_e, dim);
|
||||
let mat_matrix = Array3::new(self.material, dim);
|
||||
@@ -140,16 +144,16 @@ impl<'a, M> SerializedStepE<'a, M> {
|
||||
/// Particular those at negative offsets from the midpoint.
|
||||
/// This is used in step_e when looking at the H field deltas.
|
||||
#[derive(Copy, Clone)]
|
||||
struct VolumeSampleNeg {
|
||||
mid: Vec3<f32>,
|
||||
xm1: Optional<Vec3<f32>>,
|
||||
ym1: Optional<Vec3<f32>>,
|
||||
zm1: Optional<Vec3<f32>>,
|
||||
struct VolumeSampleNeg<R> {
|
||||
mid: Vec3<R>,
|
||||
xm1: Optional<Vec3<R>>,
|
||||
ym1: Optional<Vec3<R>>,
|
||||
zm1: Optional<Vec3<R>>,
|
||||
}
|
||||
|
||||
impl VolumeSampleNeg {
|
||||
impl<R: Real> VolumeSampleNeg<R> {
|
||||
/// Calculate the delta in H values amongst this cell and its neighbors (left/up/out)
|
||||
fn delta_h(self) -> FieldDeltas {
|
||||
fn delta_h(self) -> FieldDeltas<R> {
|
||||
let mid = self.mid;
|
||||
// let (dfy_dx, dfz_dx) = self.xm1.map(|xm1| {
|
||||
// (mid.y() - xm1.y(), mid.z() - xm1.z())
|
||||
@@ -166,19 +170,19 @@ impl VolumeSampleNeg {
|
||||
let (dfy_dx, dfz_dx) = if self.xm1.is_some() {
|
||||
(mid.y() - self.xm1.unwrap().y(), mid.z() - self.xm1.unwrap().z())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
let (dfx_dy, dfz_dy) = if self.ym1.is_some() {
|
||||
(mid.x() - self.ym1.unwrap().x(), mid.z() - self.ym1.unwrap().z())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
let (dfx_dz, dfy_dz) = if self.zm1.is_some() {
|
||||
(mid.x() - self.zm1.unwrap().x(), mid.y() - self.zm1.unwrap().y())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
FieldDeltas {
|
||||
@@ -197,16 +201,16 @@ impl VolumeSampleNeg {
|
||||
/// Particular those at positive offsets from the midpoint.
|
||||
/// This is used in step_h when looking at the E field deltas.
|
||||
#[derive(Copy, Clone)]
|
||||
struct VolumeSamplePos {
|
||||
mid: Vec3<f32>,
|
||||
xp1: Optional<Vec3<f32>>,
|
||||
yp1: Optional<Vec3<f32>>,
|
||||
zp1: Optional<Vec3<f32>>
|
||||
struct VolumeSamplePos<R> {
|
||||
mid: Vec3<R>,
|
||||
xp1: Optional<Vec3<R>>,
|
||||
yp1: Optional<Vec3<R>>,
|
||||
zp1: Optional<Vec3<R>>
|
||||
}
|
||||
|
||||
impl VolumeSamplePos {
|
||||
impl<R: Real> VolumeSamplePos<R> {
|
||||
/// Calculate the delta in E values amongst this cell and its neighbors (right/down/in)
|
||||
fn delta_e(self) -> FieldDeltas {
|
||||
fn delta_e(self) -> FieldDeltas<R> {
|
||||
let mid = self.mid;
|
||||
// let (dfy_dx, dfz_dx) = self.xp1.map(|xp1| {
|
||||
// (xp1.y() - mid.y(), xp1.z() - mid.z())
|
||||
@@ -223,19 +227,19 @@ impl VolumeSamplePos {
|
||||
let (dfy_dx, dfz_dx) = if self.xp1.is_some() {
|
||||
(self.xp1.unwrap().y() - mid.y(), self.xp1.unwrap().z() - mid.z())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
let (dfx_dy, dfz_dy) = if self.yp1.is_some() {
|
||||
(self.yp1.unwrap().x() - mid.x(), self.yp1.unwrap().z() - mid.z())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
let (dfx_dz, dfy_dz) = if self.zp1.is_some() {
|
||||
(self.zp1.unwrap().x() - mid.x(), self.zp1.unwrap().y() - mid.y())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
(R::zero(), R::zero())
|
||||
};
|
||||
|
||||
FieldDeltas {
|
||||
@@ -249,17 +253,17 @@ impl VolumeSamplePos {
|
||||
}
|
||||
}
|
||||
|
||||
struct FieldDeltas {
|
||||
dfy_dx: f32,
|
||||
dfz_dx: f32,
|
||||
dfx_dy: f32,
|
||||
dfz_dy: f32,
|
||||
dfx_dz: f32,
|
||||
dfy_dz: f32,
|
||||
struct FieldDeltas<R> {
|
||||
dfy_dx: R,
|
||||
dfz_dx: R,
|
||||
dfx_dy: R,
|
||||
dfz_dy: R,
|
||||
dfx_dz: R,
|
||||
dfy_dz: R,
|
||||
}
|
||||
|
||||
impl FieldDeltas {
|
||||
fn nabla(self) -> Vec3<f32> {
|
||||
impl<R: Real> FieldDeltas<R> {
|
||||
fn nabla(self) -> Vec3<R> {
|
||||
Vec3::new(
|
||||
self.dfz_dy - self.dfy_dz,
|
||||
self.dfx_dz - self.dfz_dx,
|
||||
@@ -268,20 +272,20 @@ impl FieldDeltas {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StepEContext<'a, M> {
|
||||
inv_feature_size: f32,
|
||||
time_step: f32,
|
||||
stim_e: Vec3<f32>,
|
||||
pub struct StepEContext<'a, R, M> {
|
||||
inv_feature_size: R,
|
||||
time_step: R,
|
||||
stim_e: Vec3<R>,
|
||||
mat: ArrayHandle<'a, M>,
|
||||
/// Input field sampled near this location
|
||||
in_h: VolumeSampleNeg,
|
||||
in_h: VolumeSampleNeg<R>,
|
||||
/// Handle to the output field at one specific index.
|
||||
out_e: ArrayHandleMut<'a, Vec3<f32>>,
|
||||
out_e: ArrayHandleMut<'a, Vec3<R>>,
|
||||
}
|
||||
|
||||
impl<'a, M: Material<f32>> StepEContext<'a, M> {
|
||||
impl<'a, R: Real, M: Material<R>> StepEContext<'a, R, M> {
|
||||
pub fn step_e(mut self) {
|
||||
let twice_eps0 = f32::twice_eps0();
|
||||
let twice_eps0 = R::twice_eps0();
|
||||
let deltas = self.in_h.delta_h();
|
||||
// \nabla x H
|
||||
let nabla_h = deltas.nabla() * self.inv_feature_size;
|
||||
@@ -292,29 +296,29 @@ impl<'a, M: Material<f32>> StepEContext<'a, M> {
|
||||
let e_prev = self.out_e.get();
|
||||
let delta_e = (nabla_h - e_prev.elem_mul(sigma)).elem_div(
|
||||
sigma*self.time_step + Vec3::uniform(twice_eps0)
|
||||
)*(2.0*self.time_step);
|
||||
)*(R::two()*self.time_step);
|
||||
// println!("spirv-step_e delta_e: {:?}", delta_e);
|
||||
self.out_e.write(e_prev + delta_e + self.stim_e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct StepHContext<'a, M> {
|
||||
inv_feature_size: f32,
|
||||
time_step: f32,
|
||||
stim_h: Vec3<f32>,
|
||||
pub struct StepHContext<'a, R, M> {
|
||||
inv_feature_size: R,
|
||||
time_step: R,
|
||||
stim_h: Vec3<R>,
|
||||
mat: ArrayHandle<'a, M>,
|
||||
/// Input field sampled near this location
|
||||
in_e: VolumeSamplePos,
|
||||
in_e: VolumeSamplePos<R>,
|
||||
/// Handle to the output field at one specific index.
|
||||
out_h: ArrayHandleMut<'a, Vec3<f32>>,
|
||||
out_m: ArrayHandleMut<'a, Vec3<f32>>,
|
||||
out_h: ArrayHandleMut<'a, Vec3<R>>,
|
||||
out_m: ArrayHandleMut<'a, Vec3<R>>,
|
||||
}
|
||||
|
||||
impl<'a, M: Material<f32>> StepHContext<'a, M> {
|
||||
impl<'a, R: Real, M: Material<R>> StepHContext<'a, R, M> {
|
||||
pub fn step_h(mut self) {
|
||||
let mu0 = f32::mu0();
|
||||
let mu0_inv = f32::mu0_inv();
|
||||
let mu0 = R::mu0();
|
||||
let mu0_inv = R::mu0_inv();
|
||||
let deltas = self.in_e.delta_e();
|
||||
// println!("spirv-step_h delta_e_struct: {:?}", deltas);
|
||||
// \nabla x E
|
||||
|
@@ -66,7 +66,7 @@ where
|
||||
}
|
||||
|
||||
impl DiscrDispatch<P0> for Discr<P0> {
|
||||
fn dispatch<H: DiscrHandler<P0, O>, O>(&self, h: H) -> O {
|
||||
fn dispatch<H: DiscrHandler<P0, O>, O>(&self, _h: H) -> O {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
@@ -148,9 +148,12 @@ where
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct Enum<D, L>(D, L);
|
||||
|
||||
/// Users should prefer this type rather than rely on the internal Enum struct implementation.
|
||||
#[allow(dead_code)]
|
||||
pub type InternallyDiscriminated<Args> = Enum<(), List<Args>>;
|
||||
|
||||
impl<P: Peano, L> Enum<(Discr<P>,), L> {
|
||||
#![allow(dead_code)]
|
||||
pub fn new<Variants>(v: Variants) -> Self
|
||||
where
|
||||
Variants: IntoList<List=L>,
|
||||
@@ -160,6 +163,7 @@ impl<P: Peano, L> Enum<(Discr<P>,), L> {
|
||||
}
|
||||
}
|
||||
impl<L> Enum<(), L> {
|
||||
#![allow(dead_code)]
|
||||
pub fn internally_discriminated<Variants>(v: Variants) -> Self
|
||||
where
|
||||
Variants: IntoList<List=L>,
|
||||
@@ -168,13 +172,6 @@ impl<L> Enum<(), L> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D, L> Enum<D, L> {
|
||||
/// use with care. long term, this probably shouldn't stay public.
|
||||
pub fn from_components(discr: D, list: L) -> Self {
|
||||
Self(discr, list)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait EnumRequirements {
|
||||
type NumVariants: Peano;
|
||||
fn decode_discr(&self) -> Discr<Self::NumVariants>;
|
||||
@@ -225,6 +222,7 @@ where
|
||||
}
|
||||
|
||||
/// invoke the closure on the active variant, passing the variant by mutable reference
|
||||
#[allow(dead_code)]
|
||||
pub fn dispatch_mut<'a, F, R>(&'a mut self, f: F) -> R
|
||||
where
|
||||
DispatchIndexable<&'a mut L, F>: DiscrHandler<<Self as EnumRequirements>::NumVariants, R>,
|
||||
|
@@ -127,15 +127,20 @@ pub trait IntoList {
|
||||
fn into_list(self) -> Self::List;
|
||||
}
|
||||
|
||||
pub type List<Args> = <Args as IntoList>::List;
|
||||
pub type List1<E0> = Node<E0, Null>;
|
||||
pub type List2<E0, E1> = Node<E0, List1<E1>>;
|
||||
pub type List3<E0, E1, E2> = Node<E0, List2<E1, E2>>;
|
||||
pub type List4<E0, E1, E2, E3> = Node<E0, List3<E1, E2, E3>>;
|
||||
|
||||
impl<H> Meta for Node<H, Null> {
|
||||
type Length = P1;
|
||||
}
|
||||
impl<H, T: Meta> Meta for Node<H, T> {
|
||||
type Length = PNext<T::Length>;
|
||||
}
|
||||
|
||||
/// these are exported for the convenience of potential consumers: not needed internally
|
||||
pub(crate) mod exports {
|
||||
#![allow(dead_code)]
|
||||
use super::{IntoList, Node, Null};
|
||||
pub type List<Args> = <Args as IntoList>::List;
|
||||
pub type List1<E0> = Node<E0, Null>;
|
||||
pub type List2<E0, E1> = Node<E0, List1<E1>>;
|
||||
pub type List3<E0, E1, E2> = Node<E0, List2<E1, E2>>;
|
||||
pub type List4<E0, E1, E2, E3> = Node<E0, List3<E1, E2, E3>>;
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
use crate::compound::peano::{Peano, PeanoNonZero};
|
||||
|
||||
mod flat;
|
||||
mod linked;
|
||||
mod tuple_consumer;
|
||||
// mod linked;
|
||||
// mod tuple_consumer;
|
||||
// pub use tuple_consumer::*;
|
||||
// pub use linked::*;
|
||||
pub use flat::*;
|
||||
pub use flat::IntoList;
|
||||
pub use flat::exports::*;
|
||||
|
||||
pub trait Indexable<P: Peano> {
|
||||
type Element;
|
||||
|
@@ -1,15 +1,37 @@
|
||||
//! Peano numbers (also known as Church numerals) are type-level natural numbers.
|
||||
//! each non-zero Peano number is defined as the unique successor of a previous Peano number.
|
||||
//!
|
||||
//! - given some Peano number I, we can derive its successor by S=PNext<I>.
|
||||
//! - given a Peano number PNext<I>, we can define its predecessor as I=P.
|
||||
//! - the base Peano number, which represents 0, is `P0`.
|
||||
//! - the `Peano` trait exposes alternative syntaxes for these: `P::Next` and `P::Prev`,
|
||||
//! however the type system can reason less about these (they're just a convenience).
|
||||
//!
|
||||
//! the primary use of Peano numbers is to allow types to specialize on a specific natural number
|
||||
//! out of some larger set of natural numbers. e.g. one might have a `struct List<Length: Peano>`
|
||||
//! to allow constructing a list of compile-time constant length.
|
||||
//!
|
||||
//! this whole module will hopefully be obsoleted as Rust's type-level integers become more
|
||||
//! capable, but in 2022 Peano numbers enable more operations (arithmetic, specialization) than type-level integers.
|
||||
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct PNext<P>(P);
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct P0;
|
||||
|
||||
pub type P1 = PNext<P0>;
|
||||
pub type P2 = PNext<P1>;
|
||||
pub type P3 = PNext<P2>;
|
||||
pub type P4 = PNext<P3>;
|
||||
pub type P5 = PNext<P4>;
|
||||
pub type P6 = PNext<P5>;
|
||||
pub type P7 = PNext<P6>;
|
||||
|
||||
/// these are exported for the convenience of potential consumers: not needed internally
|
||||
mod exports {
|
||||
#![allow(dead_code)]
|
||||
use super::{P1, PNext};
|
||||
pub type P2 = PNext<P1>;
|
||||
pub type P3 = PNext<P2>;
|
||||
pub type P4 = PNext<P3>;
|
||||
pub type P5 = PNext<P4>;
|
||||
pub type P6 = PNext<P5>;
|
||||
pub type P7 = PNext<P6>;
|
||||
}
|
||||
pub use exports::*;
|
||||
|
||||
pub trait Peano: Copy + Clone + Default + PartialEq {
|
||||
type Next: PeanoNonZero;
|
||||
|
@@ -26,12 +26,6 @@ pub struct DiscrMat<Mats>(Enum<(), Mats>);
|
||||
pub type DiscrMat2<M0, M1> = DiscrMat<List2<M0, M1>>;
|
||||
pub type DiscrMat3<M0, M1, M2> = DiscrMat<List3<M0, M1, M2>>;
|
||||
|
||||
impl<Mats> DiscrMat<Mats> {
|
||||
fn new_from_fields(mats: Mats) -> Self {
|
||||
Self(Enum::from_components((), mats))
|
||||
}
|
||||
}
|
||||
|
||||
impl<Mats: Default> DiscrMat<Mats> {
|
||||
fn new<P: Peano>(m: Mats::Element) -> Self
|
||||
where
|
||||
|
Reference in New Issue
Block a user