introduce Isomorphic/Anisomorphic conductors into the CPU side

this is needed for the future Spirv optimizations to be possible.
This commit is contained in:
2022-01-28 19:24:36 -08:00
parent 39c13afc10
commit aeec4258c7
10 changed files with 172 additions and 37 deletions

View File

@@ -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; 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. // 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 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); let mut driver: Driver<_> = Driver::new_spirv(g.dim, p.geom.feat_size);
driver.set_steps_per_stim(1000); driver.set_steps_per_stim(1000);

View File

@@ -265,8 +265,8 @@ impl<S: MaterialSim> Driver<S> {
}); });
} }
pub fn add_classical_boundary<C: Coord, R: Real>(&mut self, thickness: C) pub fn add_classical_boundary<C: Coord>(&mut self, thickness: C)
where S::Material: From<mat::Conductor<R>> where S::Material: From<mat::IsomorphicConductor<f32>>
{ {
let timestep = self.state.timestep(); let timestep = self.state.timestep();
self.state.fill_boundary_using(thickness, |boundary_ness| { self.state.fill_boundary_using(thickness, |boundary_ness| {
@@ -274,7 +274,7 @@ impl<S: MaterialSim> Driver<S> {
let cond = b * (0.5 / timestep); let cond = b * (0.5 / timestep);
let iso_cond = cond.x() + cond.y() + cond.z(); 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 iso_conductor
}); });
} }

View File

@@ -1,18 +1,18 @@
//! database of common materials //! database of common materials
use crate::geom::Vec3; use crate::geom::Vec3;
use crate::mat::{Conductor, LinearMagnet, Ferroxcube3R1, MinimalSquare}; use crate::mat::{AnisomorphicConductor, IsomorphicConductor, LinearMagnet, Ferroxcube3R1, MinimalSquare};
use crate::real::Real; use crate::real::Real;
pub fn conductor<R: Real, R2: Real>(conductivity: R2) -> Conductor<R> { pub fn conductor<R: Real, R2: Real>(conductivity: R2) -> IsomorphicConductor<R> {
Conductor::new(conductivity) IsomorphicConductor::new(conductivity.cast())
} }
pub fn anisotropic_conductor<R: Real, R2: Real>(conductivity: Vec3<R2>) -> Conductor<R> { pub fn anisotropic_conductor<R>(conductivity: Vec3<R>) -> AnisomorphicConductor<R> {
Conductor::new_anisotropic(conductivity) AnisomorphicConductor::new(conductivity)
} }
pub fn copper<R: Real>() -> Conductor<R> { pub fn copper<R: Real>() -> IsomorphicConductor<R> {
Conductor::new(50_000_000.0) conductor(50_000_000.0)
} }
// See https://en.wikipedia.org/wiki/Permeability_(electromagnetism)#Values_for_some_common_materials // See https://en.wikipedia.org/wiki/Permeability_(electromagnetism)#Values_for_some_common_materials

View File

@@ -8,29 +8,47 @@ use serde::{Serialize, Deserialize};
/// Material which has a conductivity parameter, but cannot be magnetized /// Material which has a conductivity parameter, but cannot be magnetized
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct Conductor<R> { pub struct Conductor<V> {
conductivity: Vec3<R>, conductivity: V,
} }
impl<R: Real> Conductor<R> { pub type IsomorphicConductor<R> = Conductor<R>;
pub fn new<R2: Real>(conductivity: R2) -> Self { pub type AnisomorphicConductor<R> = Conductor<Vec3<R>>;
impl<V> Conductor<V> {
pub fn new(conductivity: V) -> Self {
Self { Self {
conductivity: Vec3::uniform(conductivity).cast() conductivity
}
}
pub fn new_anisotropic<R2: Real>(conductivity: Vec3<R2>) -> Self {
Self {
conductivity: conductivity.cast(),
} }
} }
} }
impl<R: Real> Material<R> for Conductor<R> { impl<R: Real> Into<AnisomorphicConductor<R>> for IsomorphicConductor<R> {
fn into(self) -> AnisomorphicConductor<R> {
AnisomorphicConductor::new(Vec3::uniform(self.conductivity))
}
}
impl<R: Real> AnisomorphicConductor<R> {
pub fn new_anisotropic<R2: Real>(c: Vec3<R2>) -> Self {
Self {
conductivity: Vec3::new(c.x().cast(), c.y().cast(), c.z().cast())
}
}
}
impl<R: Real> Material<R> for AnisomorphicConductor<R> {
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
StepParametersMut::default().with_conductivity(self.conductivity) 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))
}
}
/// Material which can be magnetized, but has no hysteresis and no coercivity. /// Material which can be magnetized, but has no hysteresis and no coercivity.
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)] #[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct LinearMagnet<R> { pub struct LinearMagnet<R> {

View File

@@ -1,7 +1,7 @@
use crate::real::Real; use crate::real::Real;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)] #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct MHPgram<R> { pub struct MHPgram<R> {
/// X coordinate at which M is always zero. /// X coordinate at which M is always zero.
pub h_intercept: R, pub h_intercept: R,
@@ -16,3 +16,18 @@ impl<R: Real> MHPgram<R> {
Self { h_intercept, mu_r, max_m } 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<R: Real> Into<MHPgram<R>> for Ferroxcube3R1MH {
fn into(self) -> MHPgram<R> {
MHPgram::new(R::from_f32(25.0), R::from_f32(881.33), R::from_f32(44000.0))
}
}

View File

@@ -110,7 +110,7 @@ impl<R: Real> Material<R> for Pml<R> {
// #[enum_dispatch(Material)] // #[enum_dispatch(Material)]
#[derive(Clone, PartialEq, Serialize, Deserialize)] #[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum GenericMaterial<R> { pub enum GenericMaterial<R> {
Conductor(Conductor<R>), Conductor(AnisomorphicConductor<R>),
LinearMagnet(LinearMagnet<R>), LinearMagnet(LinearMagnet<R>),
Pml(Pml<R>), Pml(Pml<R>),
MBFerromagnet(MBFerromagnet<R>), MBFerromagnet(MBFerromagnet<R>),
@@ -120,16 +120,22 @@ pub enum GenericMaterial<R> {
impl<R: Real> Default for GenericMaterial<R> { impl<R: Real> Default for GenericMaterial<R> {
fn default() -> Self { fn default() -> Self {
Conductor::default().into() Self::Conductor(Default::default())
} }
} }
impl<R> From<Conductor<R>> for GenericMaterial<R> { impl<R> From<AnisomorphicConductor<R>> for GenericMaterial<R> {
fn from(inner: Conductor<R>) -> Self { fn from(inner: AnisomorphicConductor<R>) -> Self {
Self::Conductor(inner) Self::Conductor(inner)
} }
} }
impl<R: Real> From<IsomorphicConductor<R>> for GenericMaterial<R> {
fn from(inner: IsomorphicConductor<R>) -> Self {
Self::Conductor(inner.into())
}
}
impl<R> From<LinearMagnet<R>> for GenericMaterial<R> { impl<R> From<LinearMagnet<R>> for GenericMaterial<R> {
fn from(inner: LinearMagnet<R>) -> Self { fn from(inner: LinearMagnet<R>) -> Self {
Self::LinearMagnet(inner) Self::LinearMagnet(inner)

View File

@@ -1679,7 +1679,7 @@ mod test {
#[test] #[test]
fn conductor_dissipates_energy() { 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); assert_float_eq!(energy_1/energy_0, 0.0, abs <= 1e-6);
} }
@@ -1734,8 +1734,8 @@ mod test {
let timestep = state.timestep(); let timestep = state.timestep();
state.fill_boundary_using(size/4, |boundary_ness| { state.fill_boundary_using(size/4, |boundary_ness| {
let b = boundary_ness.elem_pow(3.0); let b = boundary_ness.elem_pow(3.0);
let conductivity = Vec3::uniform(f32::eps0() * b.mag() * 0.5 / timestep); let conductivity = f32::eps0() * b.mag() * 0.5 / timestep;
Conductor::new_anisotropic(conductivity) Conductor::new(conductivity.cast())
}); });
state state
} }

View File

@@ -2,14 +2,14 @@ use serde::de::Deserializer;
use serde::ser::Serializer; use serde::ser::Serializer;
use serde::{Deserialize, Serialize}; 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}; use crate::geom::{Index, Vec3, Vec3u};
/// hide the actual spirv backend structures inside a submodule to make their use/boundary clear. /// hide the actual spirv backend structures inside a submodule to make their use/boundary clear.
mod ffi { mod ffi {
pub use spirv_backend_lib::sim::SerializedSimMeta; pub use spirv_backend_lib::sim::SerializedSimMeta;
pub use spirv_backend_lib::support::{Optional, Vec3Std, UVec3Std}; 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 // 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<f32> = 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<f32> = 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)] #[derive(Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct FullyGenericMaterial { pub struct FullyGenericMaterial {
pub conductivity: Vec3<f32>, pub conductivity: Vec3<f32>,
@@ -138,8 +160,17 @@ impl From<Static<f32>> for FullyGenericMaterial {
} }
} }
impl From<Conductor<f32>> for FullyGenericMaterial { impl From<AnisomorphicConductor<f32>> for FullyGenericMaterial {
fn from(m: Conductor<f32>) -> Self { fn from(m: AnisomorphicConductor<f32>) -> Self {
FullyGenericMaterial {
conductivity: m.conductivity(),
.. Default::default()
}
}
}
impl From<IsomorphicConductor<f32>> for FullyGenericMaterial {
fn from(m: IsomorphicConductor<f32>) -> Self {
FullyGenericMaterial { FullyGenericMaterial {
conductivity: m.conductivity(), conductivity: m.conductivity(),
.. Default::default() .. Default::default()
@@ -165,6 +196,13 @@ impl From<MHPgram<f32>> for FullyGenericMaterial {
} }
} }
impl From<Ferroxcube3R1MH> for FullyGenericMaterial {
fn from(m: Ferroxcube3R1MH) -> Self {
let curve: MHPgram<f32> = m.into();
curve.into()
}
}
#[derive(Clone, Default, Serialize, Deserialize)] #[derive(Clone, Default, Serialize, Deserialize)]
pub struct SimMeta { pub struct SimMeta {
pub(crate) dim: Index, pub(crate) dim: Index,

View File

@@ -4,6 +4,7 @@
register_attr(spirv), register_attr(spirv),
no_std no_std
)] )]
#![feature(const_fn_floating_point_arithmetic)]
extern crate spirv_std; extern crate spirv_std;

View File

@@ -1,5 +1,7 @@
use crate::support::{Optional, Vec3Std}; use crate::support::{Optional, Vec3Std};
use core::marker::PhantomData;
pub trait Material: Sized { pub trait Material: Sized {
fn conductivity(&self) -> Vec3Std { fn conductivity(&self) -> Vec3Std {
Default::default() Default::default()
@@ -88,7 +90,7 @@ impl Material for MBPgram {
} }
} }
#[derive(Copy, Clone, Default, PartialEq)] #[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct MHPgram { pub struct MHPgram {
/// optimized form of mu_0^-1 * (1-mu_r^-1) /// optimized form of mu_0^-1 * (1-mu_r^-1)
b_mult: f32, b_mult: f32,
@@ -101,7 +103,7 @@ pub struct MHPgram {
impl MHPgram { impl MHPgram {
/// h_intercept: X coordinate at which M is always zero. /// h_intercept: X coordinate at which M is always zero.
/// mu_r: relative mu value along the non-flat edges of the parallelogram. /// 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; const MU0_INV: f32 = 795774.715025073;
let one_minus_mu_r_inv = 1.0 - 1.0/mu_r; let one_minus_mu_r_inv = 1.0 - 1.0/mu_r;
Self { 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<MHPgram> 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<M> {
/// conductivity, if >= 0, else ignored & used to signal the other material
value: f32,
_mat: PhantomData<M>,
}
impl<M> 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 + Default> Material for IsoConductorOr<M> {
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)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;