20 Commits

Author SHA1 Message Date
7286d272b9 move coremem/mat -> coremem/sim/legacy/mat 2022-07-24 18:31:11 -07:00
d0fcd9b657 hide legacy.rs behind a legacy/ dir 2022-07-24 18:20:58 -07:00
2f0e52a09b split SimState out of sim/mod.rs -> sim/legacy.rs 2022-07-24 18:19:26 -07:00
c8a082d2a1 wavefront: port to spirv driver 2022-07-24 17:45:13 -07:00
e62dc495f1 spirv: remove most of the IntoFfi/IntoLib stuff 2022-07-24 01:04:31 -07:00
193df5415f spirv: remove the last nontrivial Material IntoFfi/FromLib 2022-07-24 00:35:47 -07:00
4bd081ca7a spirv bindings: remove From<Static> conversion 2022-07-24 00:14:38 -07:00
940d86d86e remove unnecessary Ffi impls for AdaptStateless 2022-07-24 00:02:00 -07:00
ce00281c09 fix typo: 'electic' -> 'electric' 2022-07-23 23:58:24 -07:00
048eb7dbef geom: don't re-export coremem_types::vec 2022-07-23 18:57:17 -07:00
d813405cb1 spirv bindings: make compatible with more than just strictly f32 2022-07-23 18:24:09 -07:00
3f5160a8ea replace the CPU MBFerromagnet with a generic wrapper around any stateless coremem_types type 2022-07-23 18:10:49 -07:00
d246b97b5e coremem: remove unused SpirvMBFerromagnet 2022-07-23 17:12:30 -07:00
67872de16f clean up some unused code/imports 2022-07-23 16:27:43 -07:00
98773a350c remove custom cpu-specific MBPgram type 2022-07-23 16:26:50 -07:00
35a0c52f67 coremem tests: comment out dead code 2022-07-22 16:25:15 -07:00
9b149bae65 spirv bindings: split out common materials vs cpu materials 2022-07-22 16:24:59 -07:00
4a6a43fb31 plumb the R type parameter through spirv code 2022-07-22 16:21:03 -07:00
ee2cf47b8d types: remove unused code or mark it as intentionally dead 2022-07-22 16:20:22 -07:00
66ccbd1ada spirv: remove mat.rs and reuse coremem_types::mat everywhere 2022-07-22 15:22:09 -07:00
36 changed files with 2166 additions and 2371 deletions

View File

@@ -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));

View File

@@ -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));

View File

@@ -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| {

View File

@@ -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>;

View File

@@ -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 _};

View File

@@ -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.

View File

@@ -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};

View File

@@ -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 _};

View File

@@ -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))

View File

@@ -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;

View File

@@ -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};

View File

@@ -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> {

View File

@@ -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};

View File

@@ -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};

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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 _};

View File

@@ -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;

View File

@@ -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())

View File

@@ -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};

View File

@@ -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()
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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()
}

View File

@@ -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
));
}
}
}

View File

@@ -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>);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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>;

View File

@@ -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

View File

@@ -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>,

View File

@@ -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>>;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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