From aeec4258c7d5e971b18320e16aff3e32ee1d6f60 Mon Sep 17 00:00:00 2001 From: Colin Date: Fri, 28 Jan 2022 19:24:36 -0800 Subject: [PATCH] introduce Isomorphic/Anisomorphic conductors into the CPU side this is needed for the future Spirv optimizations to be possible. --- examples/buffer_proto5.rs | 4 +- src/driver.rs | 6 +-- src/mat/db.rs | 14 +++--- src/mat/linear.rs | 40 ++++++++++++----- src/mat/mh_ferromagnet.rs | 17 ++++++- src/mat/mod.rs | 14 ++++-- src/sim/mod.rs | 6 +-- src/sim/spirv/bindings.rs | 46 +++++++++++++++++-- src/sim/spirv/spirv_backend/src/lib.rs | 1 + src/sim/spirv/spirv_backend/src/mat.rs | 61 +++++++++++++++++++++++++- 10 files changed, 172 insertions(+), 37 deletions(-) diff --git a/examples/buffer_proto5.rs b/examples/buffer_proto5.rs index 26e7968..67353bb 100644 --- a/examples/buffer_proto5.rs +++ b/examples/buffer_proto5.rs @@ -337,9 +337,9 @@ fn run_sim(id: u32, p: Params, g: Geometries) -> Results { let feat_vol = p.geom.feat_size * p.geom.feat_size * p.geom.feat_size; // mu_r=881.33, starting at H=25 to H=75. - let ferro_mat = mat::MHPgram::new(25.0, 881.33, 44000.0); + let ferro_mat = mat::Ferroxcube3R1MH::new(); // let ferro_mat = mat::db::conductor(wire_conductivity); - let wire_mat = mat::db::conductor(p.wire_conductivity); + let wire_mat = mat::IsomorphicConductor::new(p.wire_conductivity); let mut driver: Driver<_> = Driver::new_spirv(g.dim, p.geom.feat_size); driver.set_steps_per_stim(1000); diff --git a/src/driver.rs b/src/driver.rs index 862ac38..a2b31b9 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -265,8 +265,8 @@ impl Driver { }); } - pub fn add_classical_boundary(&mut self, thickness: C) - where S::Material: From> + pub fn add_classical_boundary(&mut self, thickness: C) + where S::Material: From> { let timestep = self.state.timestep(); self.state.fill_boundary_using(thickness, |boundary_ness| { @@ -274,7 +274,7 @@ impl Driver { let cond = b * (0.5 / timestep); let iso_cond = cond.x() + cond.y() + cond.z(); - let iso_conductor = mat::db::conductor(iso_cond); + let iso_conductor = mat::IsomorphicConductor::new(iso_cond); iso_conductor }); } diff --git a/src/mat/db.rs b/src/mat/db.rs index 05b80e4..46e89cb 100644 --- a/src/mat/db.rs +++ b/src/mat/db.rs @@ -1,18 +1,18 @@ //! database of common materials use crate::geom::Vec3; -use crate::mat::{Conductor, LinearMagnet, Ferroxcube3R1, MinimalSquare}; +use crate::mat::{AnisomorphicConductor, IsomorphicConductor, LinearMagnet, Ferroxcube3R1, MinimalSquare}; use crate::real::Real; -pub fn conductor(conductivity: R2) -> Conductor { - Conductor::new(conductivity) +pub fn conductor(conductivity: R2) -> IsomorphicConductor { + IsomorphicConductor::new(conductivity.cast()) } -pub fn anisotropic_conductor(conductivity: Vec3) -> Conductor { - Conductor::new_anisotropic(conductivity) +pub fn anisotropic_conductor(conductivity: Vec3) -> AnisomorphicConductor { + AnisomorphicConductor::new(conductivity) } -pub fn copper() -> Conductor { - Conductor::new(50_000_000.0) +pub fn copper() -> IsomorphicConductor { + conductor(50_000_000.0) } // See https://en.wikipedia.org/wiki/Permeability_(electromagnetism)#Values_for_some_common_materials diff --git a/src/mat/linear.rs b/src/mat/linear.rs index c2df619..15851dc 100644 --- a/src/mat/linear.rs +++ b/src/mat/linear.rs @@ -8,29 +8,47 @@ use serde::{Serialize, Deserialize}; /// Material which has a conductivity parameter, but cannot be magnetized #[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] -pub struct Conductor { - conductivity: Vec3, +pub struct Conductor { + conductivity: V, } -impl Conductor { - pub fn new(conductivity: R2) -> Self { +pub type IsomorphicConductor = Conductor; +pub type AnisomorphicConductor = Conductor>; + +impl Conductor { + pub fn new(conductivity: V) -> Self { Self { - conductivity: Vec3::uniform(conductivity).cast() - } - } - pub fn new_anisotropic(conductivity: Vec3) -> Self { - Self { - conductivity: conductivity.cast(), + conductivity } } } -impl Material for Conductor { +impl Into> for IsomorphicConductor { + fn into(self) -> AnisomorphicConductor { + AnisomorphicConductor::new(Vec3::uniform(self.conductivity)) + } +} + +impl AnisomorphicConductor { + pub fn new_anisotropic(c: Vec3) -> Self { + Self { + conductivity: Vec3::new(c.x().cast(), c.y().cast(), c.z().cast()) + } + } +} + +impl Material for AnisomorphicConductor { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { StepParametersMut::default().with_conductivity(self.conductivity) } } +impl Material for IsomorphicConductor { + fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { + StepParametersMut::default().with_conductivity(Vec3::uniform(self.conductivity)) + } +} + /// Material which can be magnetized, but has no hysteresis and no coercivity. #[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] pub struct LinearMagnet { diff --git a/src/mat/mh_ferromagnet.rs b/src/mat/mh_ferromagnet.rs index 0f787a5..f778d6d 100644 --- a/src/mat/mh_ferromagnet.rs +++ b/src/mat/mh_ferromagnet.rs @@ -1,7 +1,7 @@ use crate::real::Real; use serde::{Serialize, Deserialize}; -#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct MHPgram { /// X coordinate at which M is always zero. pub h_intercept: R, @@ -16,3 +16,18 @@ impl MHPgram { Self { h_intercept, mu_r, max_m } } } + +#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Ferroxcube3R1MH; + +impl Ferroxcube3R1MH { + pub fn new() -> Self { + Self::default() + } +} + +impl Into> for Ferroxcube3R1MH { + fn into(self) -> MHPgram { + MHPgram::new(R::from_f32(25.0), R::from_f32(881.33), R::from_f32(44000.0)) + } +} diff --git a/src/mat/mod.rs b/src/mat/mod.rs index 983140b..4d756f3 100644 --- a/src/mat/mod.rs +++ b/src/mat/mod.rs @@ -110,7 +110,7 @@ impl Material for Pml { // #[enum_dispatch(Material)] #[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum GenericMaterial { - Conductor(Conductor), + Conductor(AnisomorphicConductor), LinearMagnet(LinearMagnet), Pml(Pml), MBFerromagnet(MBFerromagnet), @@ -120,16 +120,22 @@ pub enum GenericMaterial { impl Default for GenericMaterial { fn default() -> Self { - Conductor::default().into() + Self::Conductor(Default::default()) } } -impl From> for GenericMaterial { - fn from(inner: Conductor) -> Self { +impl From> for GenericMaterial { + fn from(inner: AnisomorphicConductor) -> Self { Self::Conductor(inner) } } +impl From> for GenericMaterial { + fn from(inner: IsomorphicConductor) -> Self { + Self::Conductor(inner.into()) + } +} + impl From> for GenericMaterial { fn from(inner: LinearMagnet) -> Self { Self::LinearMagnet(inner) diff --git a/src/sim/mod.rs b/src/sim/mod.rs index 73623d4..10b6f9f 100644 --- a/src/sim/mod.rs +++ b/src/sim/mod.rs @@ -1679,7 +1679,7 @@ mod test { #[test] fn conductor_dissipates_energy() { - let (energy_0, energy_1) = conductor_test(Conductor::new(1e3)); + let (energy_0, energy_1) = conductor_test(Conductor::new(R64::from_f32(1e3))); assert_float_eq!(energy_1/energy_0, 0.0, abs <= 1e-6); } @@ -1734,8 +1734,8 @@ mod test { let timestep = state.timestep(); state.fill_boundary_using(size/4, |boundary_ness| { let b = boundary_ness.elem_pow(3.0); - let conductivity = Vec3::uniform(f32::eps0() * b.mag() * 0.5 / timestep); - Conductor::new_anisotropic(conductivity) + let conductivity = f32::eps0() * b.mag() * 0.5 / timestep; + Conductor::new(conductivity.cast()) }); state } diff --git a/src/sim/spirv/bindings.rs b/src/sim/spirv/bindings.rs index b28bcf2..7f808e3 100644 --- a/src/sim/spirv/bindings.rs +++ b/src/sim/spirv/bindings.rs @@ -2,14 +2,14 @@ use serde::de::Deserializer; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; -use crate::mat::{Conductor, MaterialExt as _, MBFerromagnet, MBPgram, MHPgram, Static}; +use crate::mat::{AnisomorphicConductor, 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. mod ffi { pub use spirv_backend_lib::sim::SerializedSimMeta; pub use spirv_backend_lib::support::{Optional, Vec3Std, UVec3Std}; - pub use spirv_backend_lib::mat::{FullyGenericMaterial, Material, MBPgram, MHPgram}; + pub use spirv_backend_lib::mat::{Ferroxcube3R1MH, FullyGenericMaterial, Material, MBPgram, MHPgram}; } // conversion traits for types defined cross-lib @@ -100,6 +100,28 @@ impl IntoLib for ffi::MHPgram { } } +impl IntoFfi for Ferroxcube3R1MH { + type Ffi = ffi::Ferroxcube3R1MH; + fn into_ffi(self) -> Self::Ffi { + let ffi_self = ffi::Ferroxcube3R1MH; + let ffi_curve: ffi::MHPgram = ffi_self.into(); + let lib_curve: MHPgram = self.into(); + assert_eq!(lib_curve.into_ffi(), ffi_curve); + ffi_self + } +} + +impl IntoLib for ffi::Ferroxcube3R1MH { + type Lib = Ferroxcube3R1MH; + fn into_lib(self) -> Self::Lib { + let lib_self = Ferroxcube3R1MH; + let lib_curve: MHPgram = lib_self.into(); + let ffi_curve: ffi::MHPgram = self.into(); + assert_eq!(ffi_curve.into_lib(), lib_curve); + lib_self + } +} + #[derive(Clone, Default, PartialEq, Serialize, Deserialize)] pub struct FullyGenericMaterial { pub conductivity: Vec3, @@ -138,8 +160,17 @@ impl From> for FullyGenericMaterial { } } -impl From> for FullyGenericMaterial { - fn from(m: Conductor) -> Self { +impl From> for FullyGenericMaterial { + fn from(m: AnisomorphicConductor) -> Self { + FullyGenericMaterial { + conductivity: m.conductivity(), + .. Default::default() + } + } +} + +impl From> for FullyGenericMaterial { + fn from(m: IsomorphicConductor) -> Self { FullyGenericMaterial { conductivity: m.conductivity(), .. Default::default() @@ -165,6 +196,13 @@ impl From> for FullyGenericMaterial { } } +impl From for FullyGenericMaterial { + fn from(m: Ferroxcube3R1MH) -> Self { + let curve: MHPgram = m.into(); + curve.into() + } +} + #[derive(Clone, Default, Serialize, Deserialize)] pub struct SimMeta { pub(crate) dim: Index, diff --git a/src/sim/spirv/spirv_backend/src/lib.rs b/src/sim/spirv/spirv_backend/src/lib.rs index c4a8695..afbc7ba 100644 --- a/src/sim/spirv/spirv_backend/src/lib.rs +++ b/src/sim/spirv/spirv_backend/src/lib.rs @@ -4,6 +4,7 @@ register_attr(spirv), no_std )] +#![feature(const_fn_floating_point_arithmetic)] extern crate spirv_std; diff --git a/src/sim/spirv/spirv_backend/src/mat.rs b/src/sim/spirv/spirv_backend/src/mat.rs index 5f8573b..3df1e66 100644 --- a/src/sim/spirv/spirv_backend/src/mat.rs +++ b/src/sim/spirv/spirv_backend/src/mat.rs @@ -1,5 +1,7 @@ use crate::support::{Optional, Vec3Std}; +use core::marker::PhantomData; + pub trait Material: Sized { fn conductivity(&self) -> Vec3Std { Default::default() @@ -88,7 +90,7 @@ impl Material for MBPgram { } } -#[derive(Copy, Clone, Default, PartialEq)] +#[derive(Copy, Clone, Debug, Default, PartialEq)] pub struct MHPgram { /// optimized form of mu_0^-1 * (1-mu_r^-1) b_mult: f32, @@ -101,7 +103,7 @@ pub struct MHPgram { impl MHPgram { /// h_intercept: X coordinate at which M is always zero. /// mu_r: relative mu value along the non-flat edges of the parallelogram. - pub fn new(h_intercept: f32, mu_r: f32, max_m: f32) -> Self { + pub const fn new(h_intercept: f32, mu_r: f32, max_m: f32) -> Self { const MU0_INV: f32 = 795774.715025073; let one_minus_mu_r_inv = 1.0 - 1.0/mu_r; Self { @@ -198,6 +200,61 @@ impl Material for FullyGenericMaterial { } } +/// MHPgram that's vaguely similar to Ferroxcube's 3R1 material +#[derive(Copy, Clone, Default, PartialEq)] +pub struct Ferroxcube3R1MH; + +impl Into for Ferroxcube3R1MH { + fn into(self) -> MHPgram { + const CURVE: MHPgram = MHPgram::new(25.0, 881.33, 44000.0); + CURVE + } +} + +impl Material for Ferroxcube3R1MH { + fn move_b_vec(&self, m: Vec3Std, target_b: Vec3Std) -> Vec3Std { + let curve: MHPgram = (*self).into(); + curve.move_b_vec(m, target_b) + } +} + +/// 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 { + /// conductivity, if >= 0, else ignored & used to signal the other material + value: f32, + _mat: PhantomData, +} + +impl IsoConductorOr { + 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 Material for IsoConductorOr { + fn conductivity(&self) -> Vec3Std { + Vec3Std::uniform(self.value.max(0.0)) + } + fn move_b_vec(&self, m: Vec3Std, target_b: Vec3Std) -> Vec3Std { + if self.value < 0.0 { + M::default().move_b_vec(m, target_b) + } else { + m + } + } +} + #[cfg(test)] mod test { use super::*;