coremem_types: IsomorphicConductor, AnisomorphicConductor are now used by both spirv and cpu impls
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
use coremem::{Driver, mat, meas, SpirvDriver};
|
||||
use coremem::geom::{region, Cube, Dilate, Memoize, Meters, Region, Spiral, SwapYZ, Torus, Translate, Wrap};
|
||||
use coremem::mat::Ferroxcube3R1MH;
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr};
|
||||
use coremem::real::{R32, Real as _};
|
||||
use coremem::render::CsvRenderer;
|
||||
use coremem::stim::{CurlStimulus, Exp1, Gated, Sinusoid1, TimeVarying as _};
|
||||
@@ -14,7 +14,7 @@ use coremem::util::cache::DiskCache;
|
||||
use log::{error, info, warn};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
type Mat = spirv::IsoConductorOr<Ferroxcube3R1MH>;
|
||||
type Mat = IsoConductorOr<f32, Ferroxcube3R1MH>;
|
||||
|
||||
#[allow(unused)]
|
||||
use coremem::geom::{Coord as _, Region as _};
|
||||
|
@@ -38,11 +38,11 @@
|
||||
|
||||
use coremem::geom::{Meters, Torus};
|
||||
use coremem::sim::units::Seconds;
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsomorphicConductor};
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor};
|
||||
use coremem::spirv;
|
||||
use coremem::{Driver, SpirvDriver};
|
||||
|
||||
type Mat = spirv::IsoConductorOr<Ferroxcube3R1MH>;
|
||||
type Mat = IsoConductorOr<f32, Ferroxcube3R1MH>;
|
||||
|
||||
fn main() {
|
||||
coremem::init_logging();
|
||||
|
@@ -1,6 +1,6 @@
|
||||
use coremem::{Driver, SimState, SpirvDriver};
|
||||
use coremem::geom::Index;
|
||||
use coremem::mat::{Ferroxcube3R1MH, GenericMaterial, GenericMaterialNoPml, GenericMaterialOneField};
|
||||
use coremem::mat::{Ferroxcube3R1MH, IsoConductorOr, GenericMaterial, GenericMaterialNoPml, GenericMaterialOneField};
|
||||
use coremem::real::R32;
|
||||
use coremem::sim::spirv::{self, SpirvSim};
|
||||
use criterion::{BenchmarkId, criterion_group, criterion_main, Criterion};
|
||||
@@ -28,7 +28,7 @@ pub fn bench_step_spirv(c: &mut Criterion) {
|
||||
}
|
||||
|
||||
pub fn bench_step_spirv_iso_3r1(c: &mut Criterion) {
|
||||
type Mat = spirv::IsoConductorOr<Ferroxcube3R1MH>;
|
||||
type Mat = IsoConductorOr<f32, Ferroxcube3R1MH>;
|
||||
for size in &[10, 20, 40, 80, 160] {
|
||||
let sim: SpirvSim<Mat> = SpirvSim::new(Index::new(*size, *size, *size), 1e-5);
|
||||
c.bench_with_input(BenchmarkId::new("Driver::spirv_ISO3R1", size), &sim, |b, sim| {
|
||||
|
@@ -2,58 +2,9 @@ use crate::CellState;
|
||||
use crate::geom::Vec3;
|
||||
use crate::mat::Material;
|
||||
use crate::real::Real;
|
||||
use crate::sim::StepParametersMut;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
/// Material which has a conductivity parameter, but cannot be magnetized
|
||||
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Conductor<V> {
|
||||
pub conductivity: V,
|
||||
}
|
||||
|
||||
pub type IsomorphicConductor<R> = Conductor<(R,)>;
|
||||
pub type AnisomorphicConductor<R> = Conductor<Vec3<R>>;
|
||||
|
||||
impl<V> IsomorphicConductor<V> {
|
||||
pub fn new(conductivity: V) -> Self {
|
||||
Self {
|
||||
conductivity: (conductivity,)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<V: Clone> IsomorphicConductor<V> {
|
||||
pub fn iso_conductivity(&self) -> V {
|
||||
self.conductivity.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AnisomorphicConductor<R> {
|
||||
pub fn new(conductivity: Vec3<R>) -> Self {
|
||||
Self {
|
||||
conductivity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Into<AnisomorphicConductor<R>> for IsomorphicConductor<R> {
|
||||
fn into(self) -> AnisomorphicConductor<R> {
|
||||
AnisomorphicConductor::new(Vec3::uniform(self.conductivity.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Material<R> for AnisomorphicConductor<R> {
|
||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
||||
StepParametersMut::default().with_conductivity(self.conductivity)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Material<R> for IsomorphicConductor<R> {
|
||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
||||
StepParametersMut::default().with_conductivity(Vec3::uniform(self.conductivity.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Material which can be magnetized, but has no hysteresis and no coercivity.
|
||||
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LinearMagnet<R> {
|
||||
|
@@ -13,7 +13,7 @@ mod linear;
|
||||
|
||||
pub use bh_ferromagnet::*;
|
||||
pub use mb_ferromagnet::*;
|
||||
pub use coremem_types::mat::{MHPgram, Ferroxcube3R1MH};
|
||||
pub use coremem_types::mat::{AnisomorphicConductor, Ferroxcube3R1MH, IsoConductorOr, IsomorphicConductor, MHPgram};
|
||||
pub use linear::*;
|
||||
|
||||
#[enum_dispatch]
|
||||
@@ -311,3 +311,17 @@ impl<R: Real> Material<R> for GenericMaterialOneField<R> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// coremem_types adapters
|
||||
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);
|
||||
StepParametersMut::default().with_conductivity(c)
|
||||
}
|
||||
}
|
||||
impl<R: Real> Material<R> for IsomorphicConductor<R> {
|
||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
||||
let c = coremem_types::mat::Material::conductivity(self);
|
||||
StepParametersMut::default().with_conductivity(c)
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ use serde::de::Deserializer;
|
||||
use serde::ser::Serializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::mat::{AnisomorphicConductor, IsomorphicConductor, Ferroxcube3R1MH, MaterialExt as _, MBFerromagnet, MBPgram, MHPgram, Static};
|
||||
use crate::mat::{AnisomorphicConductor, IsoConductorOr, IsomorphicConductor, Ferroxcube3R1MH, MaterialExt as _, MBFerromagnet, MBPgram, MHPgram, Static};
|
||||
use crate::geom::{Index, Vec3, Vec3u};
|
||||
|
||||
/// hide the actual spirv backend structures inside a submodule to make their use/boundary clear.
|
||||
@@ -10,7 +10,7 @@ mod ffi {
|
||||
pub use spirv_backend::entry_points;
|
||||
pub use spirv_backend::sim::SerializedSimMeta;
|
||||
pub use spirv_backend::support::Optional;
|
||||
pub use spirv_backend::mat::{FullyGenericMaterial, IsoConductorOr};
|
||||
pub use spirv_backend::mat::FullyGenericMaterial;
|
||||
pub use coremem_types::mat::MBPgram;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ impl IntoLib for ffi::MBPgram<f32> {
|
||||
|
||||
identity!( => MHPgram<f32>);
|
||||
identity!( => Ferroxcube3R1MH);
|
||||
identity!(R, M, => IsoConductorOr<R, M>);
|
||||
|
||||
#[derive(Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FullyGenericMaterial {
|
||||
@@ -170,52 +171,6 @@ impl From<Ferroxcube3R1MH> for FullyGenericMaterial {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct IsoConductorOr<M> {
|
||||
value: f32,
|
||||
mat: M,
|
||||
}
|
||||
|
||||
impl<L: IntoFfi> IntoFfi for IsoConductorOr<L> {
|
||||
type Ffi = ffi::IsoConductorOr<L::Ffi>;
|
||||
fn into_ffi(self) -> Self::Ffi {
|
||||
Self::Ffi {
|
||||
value: self.value,
|
||||
mat: self.mat.into_ffi(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: IntoLib> IntoLib for ffi::IsoConductorOr<F> {
|
||||
type Lib = IsoConductorOr<F::Lib>;
|
||||
fn into_lib(self) -> Self::Lib {
|
||||
Self::Lib {
|
||||
value: self.value,
|
||||
mat: self.mat.into_lib(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Default> From<IsomorphicConductor<f32>> for IsoConductorOr<M> {
|
||||
fn from(m: IsomorphicConductor<f32>) -> Self {
|
||||
IsoConductorOr {
|
||||
value: m.iso_conductivity(),
|
||||
mat: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: can't do this for generic M, because that creates duplicate `From` impls for the
|
||||
// IsomorphicConductor itself
|
||||
impl From<Ferroxcube3R1MH> for IsoConductorOr<Ferroxcube3R1MH> {
|
||||
fn from(mat: Ferroxcube3R1MH) -> Self {
|
||||
IsoConductorOr {
|
||||
value: -1.0,
|
||||
mat,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is bitwise- and type-compatible with the spirv SimMeta, except we need serde traits
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
pub struct SimMeta {
|
||||
|
@@ -15,7 +15,7 @@ use crate::stim::AbstractStimulus;
|
||||
use coremem_types::mat::Material;
|
||||
|
||||
mod bindings;
|
||||
pub use bindings::{entry_points, IntoFfi, IntoLib, IsoConductorOr, FullyGenericMaterial, Remote, SimMeta};
|
||||
pub use bindings::{entry_points, IntoFfi, IntoLib, FullyGenericMaterial, Remote, SimMeta};
|
||||
|
||||
/// Wrapper around an inner state object which offloads stepping onto a spirv backend (e.g. GPU).
|
||||
#[derive(Clone, Default, Serialize, Deserialize)]
|
||||
@@ -892,15 +892,16 @@ mod test {
|
||||
rng.gen_range(0.0..1e6),
|
||||
rng.gen_range(0.0..1e6),
|
||||
);
|
||||
ref_state.put_material(Index::new(x, y, z), AnisomorphicConductor::new(cond.cast()));
|
||||
dut_state.put_material(Index::new(x, y, z), AnisomorphicConductor::new(cond.cast()));
|
||||
let m = AnisomorphicConductor::new(cond.cast());
|
||||
ref_state.put_material(Index::new(x, y, z), m);
|
||||
let m = AnisomorphicConductor::new(cond.cast());
|
||||
dut_state.put_material(Index::new(x, y, z), m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ref_state.apply_stimulus(&RngStimulus::new(seed));
|
||||
dut_state.apply_stimulus(&RngStimulus::new(seed));
|
||||
|
||||
test_same_explicit(ref_state, dut_state, steps);
|
||||
}
|
||||
|
||||
|
@@ -25,41 +25,5 @@ impl Material<f32> for FullyGenericMaterial {
|
||||
}
|
||||
}
|
||||
|
||||
/// Optimized material aimed at saving space for the common case of a simulation that contains
|
||||
/// isomorphic conductors plus one exception material.
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct IsoConductorOr<M> {
|
||||
/// conductivity, if >= 0, else ignored & used to signal the other material
|
||||
pub value: f32,
|
||||
pub mat: M,
|
||||
}
|
||||
|
||||
impl<M: Default> IsoConductorOr<M> {
|
||||
pub fn new_conductor(conductivity: f32) -> Self {
|
||||
Self {
|
||||
value: conductivity,
|
||||
mat: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn new_other() -> Self {
|
||||
Self {
|
||||
value: -1.0,
|
||||
mat: Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<M: Material<f32> + Copy> Material<f32> for IsoConductorOr<M> {
|
||||
fn conductivity(&self) -> Vec3<f32> {
|
||||
Vec3::uniform(self.value.max(0.0))
|
||||
}
|
||||
fn move_b_vec(&self, m: Vec3<f32>, target_b: Vec3<f32>) -> Vec3<f32> {
|
||||
if self.value < 0.0 {
|
||||
let mat = self.mat; //< XXX hack for ZST
|
||||
mat.move_b_vec(m, target_b)
|
||||
} else {
|
||||
m
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type IsoConductorOr<M> = coremem_types::mat::IsoConductorOr<f32, M>;
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
use crate::mat::Material;
|
||||
use crate::mat::{Discriminable, Material};
|
||||
use crate::real::Real;
|
||||
use crate::vec::Vec3;
|
||||
|
||||
@@ -10,7 +10,31 @@ use serde::{Serialize, Deserialize};
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct Conductor<T>(T);
|
||||
pub type AnisomorphicConductor<R> = Conductor<Vec3<R>>;
|
||||
pub type IsomorphicConductor<R> = Conductor<R>;
|
||||
pub type IsomorphicConductor<R> = Conductor<(R,)>;
|
||||
|
||||
impl<R> IsomorphicConductor<R> {
|
||||
pub fn new(c: R) -> Self {
|
||||
Self((c,))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Clone> IsomorphicConductor<V> {
|
||||
pub fn iso_conductivity(&self) -> V {
|
||||
self.0.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> AnisomorphicConductor<R> {
|
||||
pub fn new(c: Vec3<R>) -> Self {
|
||||
Self(c)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Into<AnisomorphicConductor<R>> for IsomorphicConductor<R> {
|
||||
fn into(self) -> AnisomorphicConductor<R> {
|
||||
AnisomorphicConductor::new(Vec3::uniform(self.iso_conductivity()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Material<R> for AnisomorphicConductor<R> {
|
||||
fn conductivity(&self) -> Vec3<R> {
|
||||
@@ -20,7 +44,20 @@ impl<R: Real> Material<R> for AnisomorphicConductor<R> {
|
||||
|
||||
impl<R: Real> Material<R> for IsomorphicConductor<R> {
|
||||
fn conductivity(&self) -> Vec3<R> {
|
||||
Vec3::uniform(self.0)
|
||||
Vec3::uniform(self.iso_conductivity())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real> Discriminable for IsomorphicConductor<R> {
|
||||
fn discr(&self) -> u32 {
|
||||
let cond = self.iso_conductivity();
|
||||
if cond < R::zero() {
|
||||
(-cond.to_f32()) as u32
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
fn make_discr(d: u32) -> Self {
|
||||
Self::new(R::from_primitive(-(d as i32)))
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,10 @@ pub use conductor::{AnisomorphicConductor, IsomorphicConductor};
|
||||
pub use mb_pgram::MBPgram;
|
||||
pub use mh_pgram::{Ferroxcube3R1MH, MHPgram};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
|
||||
pub trait Material<R: Real>: Sized {
|
||||
fn conductivity(&self) -> Vec3<R> {
|
||||
Default::default()
|
||||
@@ -19,3 +23,144 @@ pub trait Material<R: Real>: Sized {
|
||||
m
|
||||
}
|
||||
}
|
||||
|
||||
/// any type which may hold a discriminant internally.
|
||||
pub trait Discriminable {
|
||||
fn discr(&self) -> u32;
|
||||
fn make_discr(d: u32) -> Self;
|
||||
}
|
||||
|
||||
pub struct D0<T>(pub T);
|
||||
pub struct D1<T>(pub T);
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||
#[cfg_attr(feature = "fmt", derive(Debug))]
|
||||
#[derive(Copy, Clone, Default, PartialEq)]
|
||||
pub struct DiscrMat2<M0, M1> {
|
||||
m0: M0,
|
||||
m1: M1,
|
||||
}
|
||||
|
||||
impl<M0, M1> DiscrMat2<M0, M1> {
|
||||
fn new_from_fields(m0: M0, m1: M1) -> Self {
|
||||
Self { m0, m1 }
|
||||
}
|
||||
}
|
||||
|
||||
impl<M0: Discriminable, M1: Default> DiscrMat2<M0, M1> {
|
||||
pub fn new0(m: M0) -> Self {
|
||||
D0(m).into()
|
||||
}
|
||||
pub fn new1(m: M1) -> Self {
|
||||
D1(m).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<M0: Discriminable, M1: Default> From<D0<M0>> for DiscrMat2<M0, M1> {
|
||||
fn from(m0: D0<M0>) -> Self {
|
||||
let m0 = m0.0;
|
||||
assert!(m0.discr() == 0, "unexpected non-zero discriminant");
|
||||
Self::new_from_fields(m0, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<M0: Discriminable, M1> From<D1<M1>> for DiscrMat2<M0, M1> {
|
||||
fn from(m1: D1<M1>) -> Self {
|
||||
let m1 = m1.0;
|
||||
Self::new_from_fields(M0::make_discr(1), m1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Real, M0: Discriminable + Material<R>, M1: Material<R> + Copy> Material<R> for DiscrMat2<M0, M1> {
|
||||
fn conductivity(&self) -> Vec3<R> {
|
||||
match self.m0.discr() {
|
||||
0 => self.m0.conductivity(),
|
||||
1 => {
|
||||
let mat = self.m1; //< XXX hack for ZST
|
||||
mat.conductivity()
|
||||
}
|
||||
_ => panic!()
|
||||
// _ => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn move_b_vec(&self, m: Vec3<R>, target_b: Vec3<R>) -> Vec3<R> {
|
||||
match self.m0.discr() {
|
||||
0 => self.m0.move_b_vec(m, target_b),
|
||||
1 => {
|
||||
let mat = self.m1; //< XXX hack for ZST
|
||||
mat.move_b_vec(m, target_b)
|
||||
}
|
||||
_ => panic!()
|
||||
// _ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type IsoConductorOr<R, M1> = DiscrMat2<IsomorphicConductor<R>, M1>;
|
||||
|
||||
impl<R: Real, M1: Default> IsoConductorOr<R, M1> {
|
||||
pub fn new_conductor(conductivity: R) -> Self {
|
||||
Self::new0(IsomorphicConductor::new(conductivity))
|
||||
}
|
||||
pub fn new_other(other: M1) -> Self {
|
||||
Self::new1(other)
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: can't do this for generic M, because that creates duplicate `From` impls for the
|
||||
// IsomorphicConductor itself
|
||||
impl<R: Real> From<Ferroxcube3R1MH> for IsoConductorOr<R, Ferroxcube3R1MH> {
|
||||
fn from(mat: Ferroxcube3R1MH) -> Self {
|
||||
IsoConductorOr::new1(mat)
|
||||
}
|
||||
}
|
||||
impl<R: Real> From<IsomorphicConductor<R>> for IsoConductorOr<R, Ferroxcube3R1MH> {
|
||||
fn from(mat: IsomorphicConductor<R>) -> Self {
|
||||
IsoConductorOr::new0(mat)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::real::R32;
|
||||
|
||||
#[test]
|
||||
fn iso_conductor_discr() {
|
||||
type T = IsomorphicConductor<f32>;
|
||||
let c = T::make_discr(5);
|
||||
assert_eq!(c.discr(), 5);
|
||||
|
||||
let c = T::make_discr(0);
|
||||
assert_eq!(c.discr(), 0);
|
||||
|
||||
let c = T::new(5.0);
|
||||
assert_eq!(c.discr(), 0);
|
||||
|
||||
let c = T::new(0.0);
|
||||
assert_eq!(c.discr(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iso_conductor_or_3r1() {
|
||||
let c: IsoConductorOr<f32, Ferroxcube3R1MH> = IsomorphicConductor::new(22.0f32).into();
|
||||
assert!(c.conductivity() == Vec3::uniform(22.0f32));
|
||||
|
||||
let c: IsoConductorOr<f32, Ferroxcube3R1MH> = Ferroxcube3R1MH::new().into();
|
||||
assert!(c.conductivity() == Vec3::zero());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iso_conductor_or_aniso() {
|
||||
type I = IsoConductorOr<R32, AnisomorphicConductor<R32>>;
|
||||
|
||||
let c = I::new0(IsomorphicConductor::new(22f32.cast()));
|
||||
assert!(c.conductivity() == Vec3::uniform(22.0).cast());
|
||||
|
||||
let c = I::new1(AnisomorphicConductor::new(
|
||||
Vec3::new(2.0, 3.0, 4.0).cast()
|
||||
));
|
||||
|
||||
assert!(c.conductivity() == Vec3::new(2.0, 3.0, 4.0).cast());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user