use crate::CellState; use crate::geom::Vec3; use crate::real::Real; use crate::sim::{PmlParameters, PmlState, StepParameters, StepParametersMut}; use enum_dispatch::enum_dispatch; use serde::{Serialize, Deserialize}; pub mod db; mod bh_ferromagnet; mod mb_ferromagnet; mod mh_ferromagnet; mod linear; pub use bh_ferromagnet::*; pub use mb_ferromagnet::*; pub use mh_ferromagnet::*; pub use linear::*; #[enum_dispatch] pub trait Material { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { // by default, behave as a vacuum StepParametersMut::default() } /// Return the magnetization. fn m(&self) -> Vec3 { Vec3::zero() } /// Called just before magnetic field is updated. Optionally change any internal state (e.g. magnetization). fn step_b(&mut self, _context: &CellState, _delta_b: Vec3) { } } pub trait MaterialExt { fn step_parameters<'a>(&'a self) -> StepParameters<'a, R>; fn conductivity(&self) -> Vec3; } impl> MaterialExt for M { fn step_parameters<'a>(&'a self) -> StepParameters<'a, R> { unsafe { &mut *(self as *const M as *mut M) }.step_parameters_mut().into() } fn conductivity(&self) -> Vec3 { self.step_parameters().conductivity() } } /// Capable of capturing all field-related information about a material at any /// snapshot moment-in-time. Useful for serializing state. #[derive(Clone, Default, PartialEq, Serialize, Deserialize)] pub struct Static { pub conductivity: Vec3, // pub pml: Option<(PmlState, PmlParameters)>, pub m: Vec3, } impl Static { pub fn from_material>(m: &M) -> Self { let p = m.step_parameters(); Self { conductivity: p.conductivity(), // pml: p.pml().map(|(s, p)| (*s, p)), m: m.m(), } } // pub fn from_pml(pseudo_conductivity: Vec3) -> Self { // Self::from_material(&Pml::new(pseudo_conductivity)) // } } impl Material for Static { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { StepParametersMut::new( self.conductivity, None, // self.pml.as_mut().map(|(s, p)| (s, *p)), ) } fn m(&self) -> Vec3 { self.m } } impl From for Static where T: Into> { fn from(mat: T) -> Self { let generic = mat.into(); Self::from_material(&generic) } } #[derive(Clone, Default, PartialEq, Serialize, Deserialize)] pub struct Pml(PmlState, PmlParameters); impl Pml { pub fn new(pseudo_conductivity: Vec3) -> Self { Self(PmlState::new(), PmlParameters::new(pseudo_conductivity)) } } impl Material for Pml { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { StepParametersMut::default().with_pml(&mut self.0, self.1) } } // #[enum_dispatch(Material)] #[derive(Clone, PartialEq, Serialize, Deserialize)] pub enum GenericMaterial { Conductor(AnisomorphicConductor), LinearMagnet(LinearMagnet), Pml(Pml), MBFerromagnet(MBFerromagnet), Ferroxcube3R1(Ferroxcube3R1), MinimalSquare(MinimalSquare), } impl Default for GenericMaterial { fn default() -> Self { Self::Conductor(Default::default()) } } impl From> for GenericMaterial { fn from(inner: AnisomorphicConductor) -> Self { Self::Conductor(inner) } } impl From> for GenericMaterial { fn from(inner: IsomorphicConductor) -> Self { let iso_r = IsomorphicConductor::new(inner.conductivity.cast::()); Self::Conductor(iso_r.into()) } } impl From> for GenericMaterial { fn from(inner: LinearMagnet) -> Self { Self::LinearMagnet(inner) } } impl From> for GenericMaterial { fn from(inner: Pml) -> Self { Self::Pml(inner) } } impl From> for GenericMaterial { fn from(inner: MBFerromagnet) -> Self { Self::MBFerromagnet(inner) } } impl From> for GenericMaterial { fn from(inner: Ferroxcube3R1) -> Self { Self::Ferroxcube3R1(inner) } } impl From> for GenericMaterial { fn from(inner: MinimalSquare) -> Self { Self::MinimalSquare(inner) } } impl Material for GenericMaterial { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { use GenericMaterial::*; match self { Conductor(inner) => inner.step_parameters_mut(), LinearMagnet(inner) => inner.step_parameters_mut(), Pml(inner) => inner.step_parameters_mut(), MBFerromagnet(inner) => inner.step_parameters_mut(), Ferroxcube3R1(inner) => inner.step_parameters_mut(), MinimalSquare(inner) => inner.step_parameters_mut(), } } /// Return the magnetization. fn m(&self) -> Vec3 { use GenericMaterial::*; match self { Conductor(inner) => inner.m(), LinearMagnet(inner) => inner.m(), Pml(inner) => inner.m(), MBFerromagnet(inner) => inner.m(), Ferroxcube3R1(inner) => Material::m(inner), MinimalSquare(inner) => Material::m(inner), } } /// Called just before magnetic field is updated. Optionally change any internal state (e.g. magnetization). fn step_b(&mut self, context: &CellState, delta_b: Vec3) { use GenericMaterial::*; match self { 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), Ferroxcube3R1(inner) => inner.step_b(context, delta_b), MinimalSquare(inner) => inner.step_b(context, delta_b), } } } // #[enum_dispatch(Material)] #[derive(Clone, Serialize, Deserialize)] pub enum GenericMaterialNoPml { Conductor(Conductor), LinearMagnet(LinearMagnet), MBFerromagnet(MBFerromagnet), Ferroxcube3R1(Ferroxcube3R1), MinimalSquare(MinimalSquare), } impl Default for GenericMaterialNoPml { fn default() -> Self { Conductor::default().into() } } impl From> for GenericMaterialNoPml { fn from(inner: Conductor) -> Self { Self::Conductor(inner) } } impl Material for GenericMaterialNoPml { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { use GenericMaterialNoPml::*; match self { Conductor(inner) => inner.step_parameters_mut(), LinearMagnet(inner) => inner.step_parameters_mut(), MBFerromagnet(inner) => inner.step_parameters_mut(), Ferroxcube3R1(inner) => inner.step_parameters_mut(), MinimalSquare(inner) => inner.step_parameters_mut(), } } /// Return the magnetization. fn m(&self) -> Vec3 { use GenericMaterialNoPml::*; match self { Conductor(inner) => inner.m(), LinearMagnet(inner) => inner.m(), MBFerromagnet(inner) => inner.m(), Ferroxcube3R1(inner) => Material::m(inner), MinimalSquare(inner) => Material::m(inner), } } /// Called just before magnetic field is updated. Optionally change any internal state (e.g. magnetization). fn step_b(&mut self, context: &CellState, delta_b: Vec3) { use GenericMaterialNoPml::*; 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), Ferroxcube3R1(inner) => inner.step_b(context, delta_b), MinimalSquare(inner) => inner.step_b(context, delta_b), } } } /// Materials which have only 1 Vec3. // #[enum_dispatch(Material)] #[derive(Clone, Serialize, Deserialize)] pub enum GenericMaterialOneField { Conductor(Conductor), Ferroxcube3R1(Ferroxcube3R1), MinimalSquare(MinimalSquare), } impl Default for GenericMaterialOneField { fn default() -> Self { Conductor::default().into() } } impl From> for GenericMaterialOneField { fn from(inner: Conductor) -> Self { Self::Conductor(inner) } } impl Material for GenericMaterialOneField { fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> { use GenericMaterialOneField::*; match self { Conductor(inner) => inner.step_parameters_mut(), Ferroxcube3R1(inner) => inner.step_parameters_mut(), MinimalSquare(inner) => inner.step_parameters_mut(), } } /// Return the magnetization. fn m(&self) -> Vec3 { use GenericMaterialOneField::*; match self { Conductor(inner) => inner.m(), Ferroxcube3R1(inner) => Material::m(inner), MinimalSquare(inner) => Material::m(inner), } } /// Called just before magnetic field is updated. Optionally change any internal state (e.g. magnetization). fn step_b(&mut self, context: &CellState, delta_b: Vec3) { use GenericMaterialOneField::*; match self { Conductor(inner) => inner.step_b(context, delta_b), Ferroxcube3R1(inner) => inner.step_b(context, delta_b), MinimalSquare(inner) => inner.step_b(context, delta_b), } } }