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 { pub conductivity: V, } pub type IsomorphicConductor = Conductor; pub type AnisomorphicConductor = Conductor>; impl Conductor { pub fn new(conductivity: V) -> Self { Self { conductivity } } } 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 { /// \mu_r relative_permeability: Vec3, m: Vec3, } impl LinearMagnet { pub fn new(relative_permeability: R2) -> Self { Self { relative_permeability: Vec3::uniform(relative_permeability).cast(), m: Vec3::zero(), } } pub fn new_anisotropic(relative_permeability: Vec3) -> Self { Self { relative_permeability: relative_permeability.cast(), m: Vec3::zero() } } } impl Material for LinearMagnet { fn m(&self) -> Vec3 { self.m } fn step_b(&mut self, _context: &CellState, delta_b: Vec3) { //```tex // $B = \mu_0 (H + M) = \mu_0 \mu_r H$ // $\mu_r H = H + M$ // $M = (\mu_r - 1) H$ // $B = \mu_0 (1/(\mu_r - 1) M + M)$ // $B = \mu_0 \mu_r/(\mu_r - 1) M$ //``` let mu_r = self.relative_permeability; let delta_m = (delta_b*R::mu0_inv()).elem_mul(mu_r - Vec3::unit()).elem_div(mu_r); self.m += delta_m; } } #[cfg(test)] mod test { use super::*; use float_eq::assert_float_eq; #[test] fn linear_magnet_steep() { let mut mag = LinearMagnet::::new(5000.0); // M = B/mu0 * (mu_r-1)/(mu_r) mag.step_b(&CellState::default(), Vec3::uniform(1.0)); assert_float_eq!(mag.m().x(), 795615.56, abs <= 1.0); mag.step_b(&CellState::default(), Vec3::uniform(1.0)); assert_float_eq!(mag.m().x(), 1591231.12, abs <= 1.0); mag.step_b(&CellState::default(), Vec3::uniform(-1.0)); assert_float_eq!(mag.m().x(), 795615.56, abs <= 1.0); mag.step_b(&CellState::default(), Vec3::uniform(-1.0)); assert_float_eq!(mag.m().x(), 0.0, abs <= 1.0); } #[test] fn linear_magnet_shallow() { let mut mag = LinearMagnet::::new(2.0); mag.step_b(&CellState::default(), Vec3::uniform(1.0)); assert_float_eq!(mag.m().x(), 397887.36, abs <= 1.0); mag.step_b(&CellState::default(), Vec3::uniform(-3.0)); assert_float_eq!(mag.m().x(), -795774.72, abs <= 1.0); } #[test] fn linear_magnet_accuracy() { let mut mag = LinearMagnet::::new(5000.0); let mut b = Vec3::zero(); while b.x() < 1.0 { let delta_b = Vec3::uniform(0.00002); mag.step_b(&CellState::default(), delta_b); b += delta_b; } while b.x() > 0.0 { let delta_b = Vec3::uniform(-0.00001); mag.step_b(&CellState::default(), delta_b); b += delta_b; } // TODO: This error is WAY too big! // Need to make sure that M+H == mu0*B always assert_float_eq!(mag.m().x(), b.x() * f32::mu0_inv(), abs <= 900.0); } }