introduce Isomorphic/Anisomorphic conductors into the CPU side
this is needed for the future Spirv optimizations to be possible.
This commit is contained in:
@@ -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);
|
||||
|
@@ -265,8 +265,8 @@ impl<S: MaterialSim> Driver<S> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn add_classical_boundary<C: Coord, R: Real>(&mut self, thickness: C)
|
||||
where S::Material: From<mat::Conductor<R>>
|
||||
pub fn add_classical_boundary<C: Coord>(&mut self, thickness: C)
|
||||
where S::Material: From<mat::IsomorphicConductor<f32>>
|
||||
{
|
||||
let timestep = self.state.timestep();
|
||||
self.state.fill_boundary_using(thickness, |boundary_ness| {
|
||||
@@ -274,7 +274,7 @@ impl<S: MaterialSim> Driver<S> {
|
||||
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
|
||||
});
|
||||
}
|
||||
|
@@ -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<R: Real, R2: Real>(conductivity: R2) -> Conductor<R> {
|
||||
Conductor::new(conductivity)
|
||||
pub fn conductor<R: Real, R2: Real>(conductivity: R2) -> IsomorphicConductor<R> {
|
||||
IsomorphicConductor::new(conductivity.cast())
|
||||
}
|
||||
pub fn anisotropic_conductor<R: Real, R2: Real>(conductivity: Vec3<R2>) -> Conductor<R> {
|
||||
Conductor::new_anisotropic(conductivity)
|
||||
pub fn anisotropic_conductor<R>(conductivity: Vec3<R>) -> AnisomorphicConductor<R> {
|
||||
AnisomorphicConductor::new(conductivity)
|
||||
}
|
||||
|
||||
pub fn copper<R: Real>() -> Conductor<R> {
|
||||
Conductor::new(50_000_000.0)
|
||||
pub fn copper<R: Real>() -> IsomorphicConductor<R> {
|
||||
conductor(50_000_000.0)
|
||||
}
|
||||
|
||||
// See https://en.wikipedia.org/wiki/Permeability_(electromagnetism)#Values_for_some_common_materials
|
||||
|
@@ -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<R> {
|
||||
conductivity: Vec3<R>,
|
||||
pub struct Conductor<V> {
|
||||
conductivity: V,
|
||||
}
|
||||
|
||||
impl<R: Real> Conductor<R> {
|
||||
pub fn new<R2: Real>(conductivity: R2) -> Self {
|
||||
pub type IsomorphicConductor<R> = Conductor<R>;
|
||||
pub type AnisomorphicConductor<R> = Conductor<Vec3<R>>;
|
||||
|
||||
impl<V> Conductor<V> {
|
||||
pub fn new(conductivity: V) -> Self {
|
||||
Self {
|
||||
conductivity: Vec3::uniform(conductivity).cast()
|
||||
}
|
||||
}
|
||||
pub fn new_anisotropic<R2: Real>(conductivity: Vec3<R2>) -> Self {
|
||||
Self {
|
||||
conductivity: conductivity.cast(),
|
||||
conductivity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
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.
|
||||
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct LinearMagnet<R> {
|
||||
|
@@ -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<R> {
|
||||
/// X coordinate at which M is always zero.
|
||||
pub h_intercept: R,
|
||||
@@ -16,3 +16,18 @@ impl<R: Real> MHPgram<R> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@@ -110,7 +110,7 @@ impl<R: Real> Material<R> for Pml<R> {
|
||||
// #[enum_dispatch(Material)]
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum GenericMaterial<R> {
|
||||
Conductor(Conductor<R>),
|
||||
Conductor(AnisomorphicConductor<R>),
|
||||
LinearMagnet(LinearMagnet<R>),
|
||||
Pml(Pml<R>),
|
||||
MBFerromagnet(MBFerromagnet<R>),
|
||||
@@ -120,16 +120,22 @@ pub enum GenericMaterial<R> {
|
||||
|
||||
impl<R: Real> Default for GenericMaterial<R> {
|
||||
fn default() -> Self {
|
||||
Conductor::default().into()
|
||||
Self::Conductor(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> From<Conductor<R>> for GenericMaterial<R> {
|
||||
fn from(inner: Conductor<R>) -> Self {
|
||||
impl<R> From<AnisomorphicConductor<R>> for GenericMaterial<R> {
|
||||
fn from(inner: AnisomorphicConductor<R>) -> Self {
|
||||
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> {
|
||||
fn from(inner: LinearMagnet<R>) -> Self {
|
||||
Self::LinearMagnet(inner)
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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<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)]
|
||||
pub struct FullyGenericMaterial {
|
||||
pub conductivity: Vec3<f32>,
|
||||
@@ -138,8 +160,17 @@ impl From<Static<f32>> for FullyGenericMaterial {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Conductor<f32>> for FullyGenericMaterial {
|
||||
fn from(m: Conductor<f32>) -> Self {
|
||||
impl From<AnisomorphicConductor<f32>> for FullyGenericMaterial {
|
||||
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 {
|
||||
conductivity: m.conductivity(),
|
||||
.. 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)]
|
||||
pub struct SimMeta {
|
||||
pub(crate) dim: Index,
|
||||
|
@@ -4,6 +4,7 @@
|
||||
register_attr(spirv),
|
||||
no_std
|
||||
)]
|
||||
#![feature(const_fn_floating_point_arithmetic)]
|
||||
|
||||
extern crate spirv_std;
|
||||
|
||||
|
@@ -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<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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
Reference in New Issue
Block a user