sim/legacy: remove
that crazy tangle of legacy code evolved over 2+ years into the beast it is today. but it has no relevance in the GPU-enabled world of today, particularly one with more rigid Material abstractions. good things come to an end. i'll try not to be too sentimental.
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
use coremem::{self, Driver, AbstractSim};
|
use coremem::{self, Driver, AbstractSim};
|
||||||
use coremem::sim::legacy::SimState;
|
|
||||||
use coremem::sim::spirv::{SpirvSim, WgpuBackend};
|
use coremem::sim::spirv::{SpirvSim, WgpuBackend};
|
||||||
use coremem::sim::units::Frame;
|
use coremem::sim::units::Frame;
|
||||||
use coremem::cross::mat::FullyGenericMaterial;
|
use coremem::cross::mat::FullyGenericMaterial;
|
||||||
@@ -28,26 +27,14 @@ fn main() {
|
|||||||
measure_steps("spirv/80", 1, Driver::new(
|
measure_steps("spirv/80", 1, Driver::new(
|
||||||
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
||||||
));
|
));
|
||||||
measure_steps("sim/80", 1, Driver::<_, SimState>::new(
|
|
||||||
SimState::new(Index::new(80, 80, 80), 1e-3)
|
|
||||||
));
|
|
||||||
measure_steps("spirv/80 step(2)", 2, Driver::new(
|
measure_steps("spirv/80 step(2)", 2, Driver::new(
|
||||||
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
||||||
));
|
));
|
||||||
measure_steps("sim/80 step(2)", 2, Driver::<_, SimState>::new(
|
|
||||||
SimState::new(Index::new(80, 80, 80), 1e-3)
|
|
||||||
));
|
|
||||||
measure_steps("spirv/80 step(10)", 10, Driver::new(
|
measure_steps("spirv/80 step(10)", 10, Driver::new(
|
||||||
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
||||||
));
|
));
|
||||||
measure_steps("sim/80 step(10)", 10, Driver::<_, SimState>::new(
|
|
||||||
SimState::new(Index::new(80, 80, 80), 1e-3)
|
|
||||||
));
|
|
||||||
measure_steps("spirv/80 step(100)", 100, Driver::new(
|
measure_steps("spirv/80 step(100)", 100, Driver::new(
|
||||||
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
SpirvSim::<f32, FullyGenericMaterial<f32>, WgpuBackend>::new(Index::new(80, 80, 80), 1e-3)
|
||||||
));
|
));
|
||||||
measure_steps("sim/80 step(100)", 100, Driver::<_, SimState>::new(
|
|
||||||
SimState::new(Index::new(80, 80, 80), 1e-3)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,365 +0,0 @@
|
|||||||
use super::Material;
|
|
||||||
use crate::material_compat;
|
|
||||||
use crate::geom::{Line2d, Polygon2d};
|
|
||||||
use crate::real::Real;
|
|
||||||
use crate::sim::legacy::{CellState, StepParametersMut};
|
|
||||||
use crate::cross::vec::{Vec2, Vec3};
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
use log::trace;
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
use std::any::{Any, TypeId};
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
fn step_linear_ferro<R: Real>(m_mut: &mut Vec3<R>, mh_curve: &MHCurve<R>, context: &CellState<R>, delta_b: Vec3<R>) {
|
|
||||||
trace!("step_b enter");
|
|
||||||
let (h, m) = (context.h(), *m_mut);
|
|
||||||
let target_hm = h + m + delta_b * R::mu0_inv();
|
|
||||||
|
|
||||||
// TODO: this is probably not the best way to generalize a BH curve into 3d.
|
|
||||||
let (_hx, mx) = mh_curve.move_to(
|
|
||||||
h.x(),
|
|
||||||
m.x(),
|
|
||||||
target_hm.x(),
|
|
||||||
);
|
|
||||||
let (_hy, my) = mh_curve.move_to(
|
|
||||||
h.y(),
|
|
||||||
m.y(),
|
|
||||||
target_hm.y(),
|
|
||||||
);
|
|
||||||
let (_hz, mz) = mh_curve.move_to(
|
|
||||||
h.z(),
|
|
||||||
m.z(),
|
|
||||||
target_hm.z(),
|
|
||||||
);
|
|
||||||
|
|
||||||
*m_mut = Vec3::new(mx, my, mz);
|
|
||||||
// let ret = Vec3::new(hx, hy, hz);
|
|
||||||
trace!("step_b end");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// M as a function of H
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
struct MHCurve<R> {
|
|
||||||
geom: Polygon2d<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
impl<R: Real> MHCurve<R> {
|
|
||||||
/// Construct a M(H) curve from a sweep from M = 0 to Ms and back down to M = 0.
|
|
||||||
/// The curve below M = 0 is derived by symmetry.
|
|
||||||
fn new<R2: Real>(points: &[Vec2<R2>]) -> Self {
|
|
||||||
let full_pts: Vec<_> =
|
|
||||||
points.iter().cloned()
|
|
||||||
.chain(points.iter().cloned().map(|p| -p))
|
|
||||||
.map(|p| p.cast())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
geom: Polygon2d::new(full_pts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_bh<R2: Real>(points: &[(R2, R2)]) -> Self {
|
|
||||||
let mh_points: Vec<_> = points.iter().cloned().map(|(h, b)| {
|
|
||||||
Vec2::new(h, b / R2::mu0() - h)
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
Self::new(&*mh_points)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_mh<R2: Real>(points: &[(R2, R2)]) -> Self {
|
|
||||||
let mh_points: Vec<_> = points.iter().cloned().map(|(h, m)| {
|
|
||||||
Vec2::new(h, m)
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
Self::new(&*mh_points)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return (Hmax, Mmax)
|
|
||||||
pub fn extremes(&self) -> Vec2<R> {
|
|
||||||
Vec2::new(self.geom.max_x(), self.geom.max_y())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Moves (h, m) towards some location in the MH curve where H + M = target_hm.
|
|
||||||
/// Returns `Ok((h, m))` if complete; `Err((h, m))` if there's more work to be done (call it
|
|
||||||
/// again).
|
|
||||||
fn step_toward(&self, h: R, m: R, target_hm: R) -> Result<Vec2<R>, Vec2<R>> {
|
|
||||||
let is_ascending = match target_hm.partial_cmp(&(h + m)).unwrap_or_else(|| panic!("{} {}", h, m)) {
|
|
||||||
Ordering::Greater => true,
|
|
||||||
Ordering::Less => false,
|
|
||||||
_ => return Ok(Vec2::new(h, m))
|
|
||||||
};
|
|
||||||
if (is_ascending && m == self.geom.max_y()) || (!is_ascending && m == self.geom.min_y()) {
|
|
||||||
// Fully saturated. m is fixed, while h moves freely
|
|
||||||
return Ok(Vec2::new(target_hm - m, m));
|
|
||||||
}
|
|
||||||
// Locate the segment which would contain the current point
|
|
||||||
let mut segments = self.geom.segments();
|
|
||||||
let active_segment = loop {
|
|
||||||
let line = segments.next().unwrap_or_else(|| {
|
|
||||||
panic!("failed to find segment for h:{}, m:{}, {:?}", h, m, self.geom.segments().collect::<Vec<_>>());
|
|
||||||
});
|
|
||||||
if line.contains_y(m) && line.is_ascending() == is_ascending {
|
|
||||||
if line.contains_x(h) && line.distance_sq(Vec2::new(h, m)) < R::from_primitive(1.0e-6) {
|
|
||||||
// (h, m) resides on this line
|
|
||||||
break line;
|
|
||||||
} else {
|
|
||||||
// need to move the point toward this line
|
|
||||||
let h_intercept = line.x(m);
|
|
||||||
break Line2d::new(Vec2::new(h, m), Vec2::new(h_intercept, m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
trace!("active segment: {:?}", active_segment);
|
|
||||||
|
|
||||||
// Find some m(h) on the active_segment such that sum(h) = h + m(h) = target_hm
|
|
||||||
let sum_h = active_segment + Line2d::new(Vec2::zero(), Vec2::unit());
|
|
||||||
trace!("sum_h: {:?}", sum_h);
|
|
||||||
let new_h = if sum_h.to().y() != sum_h.from().y() {
|
|
||||||
sum_h.move_toward_y_unclamped(h, target_hm)
|
|
||||||
} else {
|
|
||||||
// avoid a division-by-zero.
|
|
||||||
// We could be anywhere along this line, but we prefer the endpoint
|
|
||||||
// so as to escape out of any permanent loops
|
|
||||||
active_segment.to().x()
|
|
||||||
};
|
|
||||||
trace!("new_h: {}", new_h);
|
|
||||||
|
|
||||||
if sum_h.contains_x(new_h) {
|
|
||||||
// the segment contains a point with the target H+M
|
|
||||||
Ok(active_segment.at_x(new_h))
|
|
||||||
} else {
|
|
||||||
// the segment doesn't contain the desired point: clamp and try the next segment
|
|
||||||
Err(active_segment.clamp_by_x(new_h))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn move_to(&self, mut h: R, mut m: R, target_hm: R) -> (R, R) {
|
|
||||||
let mut i = 0;
|
|
||||||
loop {
|
|
||||||
i += 1;
|
|
||||||
match self.step_toward(h, m, target_hm) {
|
|
||||||
Ok(v) => break (v.x(), v.y()),
|
|
||||||
Err(v) => {
|
|
||||||
h = v.x();
|
|
||||||
m = v.y();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if i % 2048 == 0 {
|
|
||||||
panic!("unusually high iteration count without converging: {}. args: {}, {}, {}", i, h, m, target_hm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Ferroxcube3R1<R> {
|
|
||||||
m: Vec3<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Ferroxcube3R1<R> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Ferroxcube3R1<R> {
|
|
||||||
fn curve() -> &'static MHCurve<R> {
|
|
||||||
lazy_static! {
|
|
||||||
static ref CURVES: Mutex<HashMap<TypeId, Box<dyn Any + Send>>> = Mutex::new(HashMap::new());
|
|
||||||
}
|
|
||||||
let mut lock = CURVES.lock().unwrap();
|
|
||||||
let curve = lock.entry(TypeId::of::<R>()).or_insert_with(|| {
|
|
||||||
Box::new(MHCurve::<R>::from_bh(&[
|
|
||||||
( 35.0, 0.0),
|
|
||||||
( 50.0, 0.250),
|
|
||||||
( 100.0, 0.325),
|
|
||||||
( 200.0, 0.350),
|
|
||||||
(1000.0, 0.390),
|
|
||||||
// Falling
|
|
||||||
( 200.0, 0.360),
|
|
||||||
( 100.0, 0.345),
|
|
||||||
( 50.0, 0.340),
|
|
||||||
( 0.0, 0.325),
|
|
||||||
]))
|
|
||||||
}).downcast_ref::<MHCurve<R>>().unwrap();
|
|
||||||
unsafe { std::mem::transmute::<&MHCurve<R>, &'static MHCurve<R>>(curve) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for Ferroxcube3R1<R> {
|
|
||||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
|
||||||
step_linear_ferro(&mut self.m, Self::curve(), context, delta_b)
|
|
||||||
}
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
self.m
|
|
||||||
}
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
StepParametersMut::default().with_conductivity(Vec3::uniform(1e-3))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, Ferroxcube3R1<R>);
|
|
||||||
|
|
||||||
/// Simple, square-loop ferrite
|
|
||||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct MinimalSquare<R> {
|
|
||||||
m: Vec3<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> MinimalSquare<R> {
|
|
||||||
fn curve() -> &'static MHCurve<R> {
|
|
||||||
lazy_static! {
|
|
||||||
static ref CURVES: Mutex<HashMap<TypeId, Box<dyn Any + Send>>> = Mutex::new(HashMap::new());
|
|
||||||
}
|
|
||||||
let mut lock = CURVES.lock().unwrap();
|
|
||||||
let curve = lock.entry(TypeId::of::<R>()).or_insert_with(|| {
|
|
||||||
Box::new(MHCurve::<R>::from_bh(&[
|
|
||||||
( 1.0, 0.0),
|
|
||||||
( 2.0, 1000000.0),
|
|
||||||
// Falling
|
|
||||||
( 0.0, 900000.0),
|
|
||||||
]))
|
|
||||||
}).downcast_ref::<MHCurve<R>>().unwrap();
|
|
||||||
unsafe { std::mem::transmute::<&MHCurve<R>, &'static MHCurve<R>>(curve) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for MinimalSquare<R> {
|
|
||||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
|
||||||
step_linear_ferro(&mut self.m, Self::curve(), context, delta_b)
|
|
||||||
}
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
self.m
|
|
||||||
}
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
StepParametersMut::default().with_conductivity(Vec3::uniform(1e-3))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, MinimalSquare<R>);
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
fn mh_curve_for_test() -> MHCurve<f32> {
|
|
||||||
MHCurve::new(&[
|
|
||||||
// rising
|
|
||||||
Vec2::new( 10.0, 0.0),
|
|
||||||
Vec2::new( 20.0, 100.0),
|
|
||||||
Vec2::new( 30.0, 150.0),
|
|
||||||
// falling
|
|
||||||
Vec2::new( 0.0, 120.0),
|
|
||||||
// negative rising
|
|
||||||
Vec2::new(-10.0, 0.0),
|
|
||||||
Vec2::new(-20.0, -100.0),
|
|
||||||
Vec2::new(-30.0, -150.0),
|
|
||||||
// negative falling
|
|
||||||
Vec2::new( 0.0, -120.0),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_step_toward_symmetric(h: f32, m: f32, target_mh: f32, target: Result<Vec2<f32>, Vec2<f32>>) {
|
|
||||||
let curve = mh_curve_for_test();
|
|
||||||
let target = match target {
|
|
||||||
Ok(v) => Ok(v),
|
|
||||||
Err(v) => Err(v),
|
|
||||||
};
|
|
||||||
let neg_target = match target {
|
|
||||||
Ok(v) => Ok(-v),
|
|
||||||
Err(v) => Err(-v),
|
|
||||||
};
|
|
||||||
assert_eq!(curve.step_toward(h, m, target_mh), target);
|
|
||||||
assert_eq!(curve.step_toward(-h, -m, -target_mh), neg_target);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assert_move_to_symmetric(h: f32, m: f32, target_mh: f32, target: (f32, f32)) {
|
|
||||||
let curve = mh_curve_for_test();
|
|
||||||
assert_eq!(curve.move_to(h, m, target_mh), target);
|
|
||||||
assert_eq!(curve.move_to(-h, -m, -target_mh), (-target.0, -target.1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mh_curve_move_from_inner_to_inner() {
|
|
||||||
assert_step_toward_symmetric(0.0, 0.0, 5.0, Ok(Vec2::new(5.0, 0.0)));
|
|
||||||
assert_step_toward_symmetric(0.0, 5.0, 10.0, Ok(Vec2::new(5.0, 5.0)));
|
|
||||||
|
|
||||||
assert_step_toward_symmetric(-5.0, 5.0, -3.0, Ok(Vec2::new(-8.0, 5.0)));
|
|
||||||
assert_step_toward_symmetric(-5.0, 5.0, 7.0, Ok(Vec2::new(2.0, 5.0)));
|
|
||||||
|
|
||||||
assert_step_toward_symmetric(5.0, -5.0, -3.0, Ok(Vec2::new(2.0, -5.0)));
|
|
||||||
assert_step_toward_symmetric(5.0, -5.0, 3.0, Ok(Vec2::new(8.0, -5.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mh_curve_magnetize_along_edge() {
|
|
||||||
// start of segment NOOP
|
|
||||||
assert_step_toward_symmetric(10.0, 0.0, 10.0, Ok(Vec2::new(10.0, 0.0)));
|
|
||||||
// start of segment to middle of segment
|
|
||||||
assert_step_toward_symmetric(10.0, 0.0, 32.0, Ok(Vec2::new(12.0, 20.0)));
|
|
||||||
// middle of segment NOOP
|
|
||||||
assert_step_toward_symmetric(12.0, 20.0, 32.0, Ok(Vec2::new(12.0, 20.0)));
|
|
||||||
// middle of segment to middle of segment
|
|
||||||
assert_step_toward_symmetric(12.0, 20.0, 54.0, Ok(Vec2::new(14.0, 40.0)));
|
|
||||||
// middle of segment to end of segment
|
|
||||||
assert_step_toward_symmetric(12.0, 20.0, 120.0, Err(Vec2::new(20.0, 100.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mh_curve_demagnetize_along_edge() {
|
|
||||||
// start of segment NOOP
|
|
||||||
assert_step_toward_symmetric(30.0, 150.0, 180.0, Ok(Vec2::new(30.0, 150.0)));
|
|
||||||
// start of segment to middle of segment
|
|
||||||
assert_step_toward_symmetric(30.0, 150.0, 160.0, Ok(Vec2::new(20.0, 140.0)));
|
|
||||||
// middle of segment NOOP
|
|
||||||
assert_step_toward_symmetric(20.0, 140.0, 160.0, Ok(Vec2::new(20.0, 140.0)));
|
|
||||||
// middle of segment to middle of segment
|
|
||||||
assert_step_toward_symmetric(20.0, 140.0, 140.0, Ok(Vec2::new(10.0, 130.0)));
|
|
||||||
// middle of segment to end of segment
|
|
||||||
assert_step_toward_symmetric(20.0, 140.0, 120.0, Err(Vec2::new(0.0, 120.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mh_curve_magnetize_across_edges() {
|
|
||||||
// Rising from start to middle
|
|
||||||
assert_move_to_symmetric(10.0, 0.0, 132.0, (22.0, 110.0));
|
|
||||||
// Rising from start to saturation
|
|
||||||
assert_move_to_symmetric(10.0, 0.0, 180.0, (30.0, 150.0));
|
|
||||||
// Rising from start to post-saturation
|
|
||||||
assert_move_to_symmetric(10.0, 0.0, 400.0, (250.0, 150.0));
|
|
||||||
// Rising from negative saturation to start
|
|
||||||
assert_move_to_symmetric(-30.0, -150.0, 10.0, (10.0, 0.0));
|
|
||||||
// Rising from negative post-saturation to start
|
|
||||||
assert_move_to_symmetric(-250.0, -150.0, 10.0, (10.0, 0.0));
|
|
||||||
// Rising from negative middle to middle
|
|
||||||
assert_move_to_symmetric(-22.0, -110.0, 132.0, (22.0, 110.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn mh_curve_demagnetize_across_edges() {
|
|
||||||
// Falling from saturation to start
|
|
||||||
assert_move_to_symmetric(30.0, 150.0, 120.0, (0.0, 120.0));
|
|
||||||
// Falling from post-saturation to post-saturation
|
|
||||||
assert_move_to_symmetric(250.0, 150.0, 200.0, (50.0, 150.0));
|
|
||||||
// Falling from post-saturation to saturation
|
|
||||||
assert_move_to_symmetric(250.0, 150.0, 180.0, (30.0, 150.0));
|
|
||||||
// Falling from post-saturation to start
|
|
||||||
assert_move_to_symmetric(250.0, 150.0, 120.0, (0.0, 120.0));
|
|
||||||
// Falling from post-saturation to negative saturation
|
|
||||||
assert_move_to_symmetric(250.0, 150.0, -180.0, (-30.0, -150.0));
|
|
||||||
// Falling from post-saturation to negative post-saturation
|
|
||||||
assert_move_to_symmetric(250.0, 150.0, -400.0, (-250.0, -150.0));
|
|
||||||
// Falling from interior to middle
|
|
||||||
assert_move_to_symmetric(28.0, 130.0, 140.0, (10.0, 130.0));
|
|
||||||
// Falling from interior to middle
|
|
||||||
assert_move_to_symmetric(28.0, 130.0, 130.0, (5.0, 125.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Float rounding would cause `inf`s, which manifested as infinite looping.
|
|
||||||
#[test]
|
|
||||||
fn regression_no_convergence_3r1() {
|
|
||||||
let curve = Ferroxcube3R1::curve();
|
|
||||||
curve.move_to(-202.04596, -278400.53, -278748.66);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,35 +0,0 @@
|
|||||||
//! database of common materials
|
|
||||||
|
|
||||||
use super::{AnisomorphicConductor, IsomorphicConductor, LinearMagnet, Ferroxcube3R1, MinimalSquare};
|
|
||||||
use crate::real::Real;
|
|
||||||
use crate::cross::vec::Vec3;
|
|
||||||
|
|
||||||
pub fn conductor<R: Real, R2: Real>(conductivity: R2) -> IsomorphicConductor<R> {
|
|
||||||
IsomorphicConductor::new(conductivity.cast())
|
|
||||||
}
|
|
||||||
pub fn anisotropic_conductor<R>(conductivity: Vec3<R>) -> AnisomorphicConductor<R> {
|
|
||||||
AnisomorphicConductor::new(conductivity)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
/// This is a simplified form of iron annealed in H.
|
|
||||||
pub fn linear_annealed_iron<R: Real>() -> LinearMagnet<R> {
|
|
||||||
LinearMagnet::new(200_000.0)
|
|
||||||
}
|
|
||||||
/// This is a simplified form of iron
|
|
||||||
pub fn linear_iron<R: Real>() -> LinearMagnet<R> {
|
|
||||||
LinearMagnet::new(5000.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://www.ferroxcube.com/upload/media/product/file/MDS/3r1.pdf
|
|
||||||
pub fn ferroxcube_3r1<R: Real>() -> Ferroxcube3R1<R> {
|
|
||||||
Ferroxcube3R1::default()
|
|
||||||
}
|
|
||||||
pub fn minimal_square_ferrite<R: Real>() -> MinimalSquare<R> {
|
|
||||||
MinimalSquare::default()
|
|
||||||
}
|
|
||||||
|
|
@@ -1,103 +0,0 @@
|
|||||||
use super::Material;
|
|
||||||
use crate::material_compat;
|
|
||||||
use crate::real::Real;
|
|
||||||
use crate::sim::legacy::CellState;
|
|
||||||
use crate::cross::vec::Vec3;
|
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
/// Material which can be magnetized, but has no hysteresis and no coercivity.
|
|
||||||
#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct LinearMagnet<R> {
|
|
||||||
/// \mu_r
|
|
||||||
relative_permeability: Vec3<R>,
|
|
||||||
m: Vec3<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> LinearMagnet<R> {
|
|
||||||
pub fn new<R2: Real>(relative_permeability: R2) -> Self {
|
|
||||||
Self {
|
|
||||||
relative_permeability: Vec3::uniform(relative_permeability).cast(),
|
|
||||||
m: Vec3::zero(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn new_anisotropic<R2: Real>(relative_permeability: Vec3<R2>) -> Self {
|
|
||||||
Self {
|
|
||||||
relative_permeability: relative_permeability.cast(),
|
|
||||||
m: Vec3::zero()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for LinearMagnet<R> {
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
self.m
|
|
||||||
}
|
|
||||||
fn step_b(&mut self, _context: &CellState<R>, delta_b: Vec3<R>) {
|
|
||||||
//```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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, LinearMagnet<R>);
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use float_eq::assert_float_eq;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn linear_magnet_steep() {
|
|
||||||
let mut mag = LinearMagnet::<f64>::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::<f64>::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::<f32>::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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,395 +0,0 @@
|
|||||||
use crate::real::Real;
|
|
||||||
use crate::sim::legacy::{CellState, PmlParameters, PmlState, StepParameters, StepParametersMut};
|
|
||||||
use crate::cross::vec::Vec3;
|
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
pub mod db;
|
|
||||||
mod bh_ferromagnet;
|
|
||||||
mod linear;
|
|
||||||
|
|
||||||
pub use bh_ferromagnet::*;
|
|
||||||
pub use coremem_cross::mat::{
|
|
||||||
AnisomorphicConductor,
|
|
||||||
Ferroxcube3R1MH,
|
|
||||||
FullyGenericMaterial,
|
|
||||||
IsoConductorOr,
|
|
||||||
IsomorphicConductor,
|
|
||||||
MHPgram,
|
|
||||||
};
|
|
||||||
pub use linear::*;
|
|
||||||
|
|
||||||
pub trait Material<R: Real> {
|
|
||||||
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<R> {
|
|
||||||
Vec3::zero()
|
|
||||||
}
|
|
||||||
/// Called just before magnetic field is updated. Optionally change any internal state (e.g. magnetization).
|
|
||||||
fn step_b(&mut self, _context: &CellState<R>, _delta_b: Vec3<R>) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! material_compat {
|
|
||||||
(R, $mat:path) => {
|
|
||||||
// XXX this is not that useful an implementation.
|
|
||||||
// it exists mostly because some users want the `Material::conductivity()` method.
|
|
||||||
impl<R: Real> crate::mat::Material<R> for $mat {
|
|
||||||
fn conductivity(&self) -> Vec3<R> {
|
|
||||||
crate::sim::legacy::mat::MaterialExt::step_parameters(self).conductivity()
|
|
||||||
}
|
|
||||||
fn move_b_vec(&self, _m: Vec3<R>, _target_b: Vec3<R>) -> Vec3<R> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub trait MaterialExt<R> {
|
|
||||||
fn step_parameters<'a>(&'a self) -> StepParameters<'a, R>;
|
|
||||||
fn conductivity(&self) -> Vec3<R>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real, M: Material<R>> MaterialExt<R> 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<R> {
|
|
||||||
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<R> {
|
|
||||||
pub conductivity: Vec3<R>,
|
|
||||||
// pub pml: Option<(PmlState, PmlParameters)>,
|
|
||||||
pub m: Vec3<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Static<R> {
|
|
||||||
pub fn from_material<M: Material<R>>(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<flt::Real>) -> Self {
|
|
||||||
// Self::from_material(&Pml::new(pseudo_conductivity))
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for Static<R> {
|
|
||||||
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<R> {
|
|
||||||
self.m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, Static<R>);
|
|
||||||
|
|
||||||
impl<R: Real, T> From<T> for Static<R>
|
|
||||||
where T: Into<GenericMaterial<R>>
|
|
||||||
{
|
|
||||||
fn from(mat: T) -> Self {
|
|
||||||
let generic = mat.into();
|
|
||||||
Self::from_material(&generic)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Default, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct Pml<R>(PmlState<R>, PmlParameters<R>);
|
|
||||||
|
|
||||||
impl<R: Real> Pml<R> {
|
|
||||||
pub fn new<R2: Real>(pseudo_conductivity: Vec3<R2>) -> Self {
|
|
||||||
Self(PmlState::new(), PmlParameters::new(pseudo_conductivity))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for Pml<R> {
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
StepParametersMut::default().with_pml(&mut self.0, self.1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, Pml<R>);
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub enum GenericMaterial<R> {
|
|
||||||
Conductor(AnisomorphicConductor<R>),
|
|
||||||
LinearMagnet(LinearMagnet<R>),
|
|
||||||
Pml(Pml<R>),
|
|
||||||
MBPgram(MBPgram<R>),
|
|
||||||
Ferroxcube3R1(Ferroxcube3R1<R>),
|
|
||||||
MinimalSquare(MinimalSquare<R>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Default for GenericMaterial<R> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Conductor(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<AnisomorphicConductor<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: AnisomorphicConductor<R>) -> Self {
|
|
||||||
Self::Conductor(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real, V: Real> From<IsomorphicConductor<V>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: IsomorphicConductor<V>) -> Self {
|
|
||||||
let iso_r = IsomorphicConductor::new(inner.iso_conductivity().cast::<R>());
|
|
||||||
Self::Conductor(iso_r.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<LinearMagnet<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: LinearMagnet<R>) -> Self {
|
|
||||||
Self::LinearMagnet(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<Pml<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: Pml<R>) -> Self {
|
|
||||||
Self::Pml(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<MBPgram<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: MBPgram<R>) -> Self {
|
|
||||||
Self::MBPgram(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<Ferroxcube3R1<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: Ferroxcube3R1<R>) -> Self {
|
|
||||||
Self::Ferroxcube3R1(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<MinimalSquare<R>> for GenericMaterial<R> {
|
|
||||||
fn from(inner: MinimalSquare<R>) -> Self {
|
|
||||||
Self::MinimalSquare(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for GenericMaterial<R> {
|
|
||||||
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(),
|
|
||||||
MBPgram(inner) => inner.step_parameters_mut(),
|
|
||||||
Ferroxcube3R1(inner) => inner.step_parameters_mut(),
|
|
||||||
MinimalSquare(inner) => inner.step_parameters_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Return the magnetization.
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
use GenericMaterial::*;
|
|
||||||
match self {
|
|
||||||
Conductor(inner) => inner.m(),
|
|
||||||
LinearMagnet(inner) => inner.m(),
|
|
||||||
Pml(inner) => inner.m(),
|
|
||||||
MBPgram(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<R>, delta_b: Vec3<R>) {
|
|
||||||
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),
|
|
||||||
MBPgram(inner) => inner.step_b(context, delta_b),
|
|
||||||
Ferroxcube3R1(inner) => inner.step_b(context, delta_b),
|
|
||||||
MinimalSquare(inner) => inner.step_b(context, delta_b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, GenericMaterial<R>);
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub enum GenericMaterialNoPml<R> {
|
|
||||||
Conductor(AnisomorphicConductor<R>),
|
|
||||||
LinearMagnet(LinearMagnet<R>),
|
|
||||||
MBPgram(MBPgram<R>),
|
|
||||||
Ferroxcube3R1(Ferroxcube3R1<R>),
|
|
||||||
MinimalSquare(MinimalSquare<R>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Default for GenericMaterialNoPml<R> {
|
|
||||||
fn default() -> Self {
|
|
||||||
AnisomorphicConductor::default().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<AnisomorphicConductor<R>> for GenericMaterialNoPml<R> {
|
|
||||||
fn from(inner: AnisomorphicConductor<R>) -> Self {
|
|
||||||
Self::Conductor(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for GenericMaterialNoPml<R> {
|
|
||||||
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(),
|
|
||||||
MBPgram(inner) => inner.step_parameters_mut(),
|
|
||||||
Ferroxcube3R1(inner) => inner.step_parameters_mut(),
|
|
||||||
MinimalSquare(inner) => inner.step_parameters_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Return the magnetization.
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
use GenericMaterialNoPml::*;
|
|
||||||
match self {
|
|
||||||
Conductor(inner) => inner.m(),
|
|
||||||
LinearMagnet(inner) => inner.m(),
|
|
||||||
MBPgram(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<R>, delta_b: Vec3<R>) {
|
|
||||||
use GenericMaterialNoPml::*;
|
|
||||||
match self {
|
|
||||||
Conductor(inner) => inner.step_b(context, delta_b),
|
|
||||||
LinearMagnet(inner) => inner.step_b(context, delta_b),
|
|
||||||
MBPgram(inner) => inner.step_b(context, delta_b),
|
|
||||||
Ferroxcube3R1(inner) => inner.step_b(context, delta_b),
|
|
||||||
MinimalSquare(inner) => inner.step_b(context, delta_b),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, GenericMaterialNoPml<R>);
|
|
||||||
|
|
||||||
|
|
||||||
/// Materials which have only 1 Vec3.
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
pub enum GenericMaterialOneField<R> {
|
|
||||||
Conductor(AnisomorphicConductor<R>),
|
|
||||||
Ferroxcube3R1(Ferroxcube3R1<R>),
|
|
||||||
MinimalSquare(MinimalSquare<R>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Default for GenericMaterialOneField<R> {
|
|
||||||
fn default() -> Self {
|
|
||||||
AnisomorphicConductor::default().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R> From<AnisomorphicConductor<R>> for GenericMaterialOneField<R> {
|
|
||||||
fn from(inner: AnisomorphicConductor<R>) -> Self {
|
|
||||||
Self::Conductor(inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real> Material<R> for GenericMaterialOneField<R> {
|
|
||||||
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<R> {
|
|
||||||
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<R>, delta_b: Vec3<R>) {
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, GenericMaterialOneField<R>);
|
|
||||||
|
|
||||||
// coremem_cross adapters
|
|
||||||
// TODO: move this to a dedicated file
|
|
||||||
|
|
||||||
/// the coremem_cross Materials are stateless;
|
|
||||||
/// rather than hold onto their own magnetic fields (for example), the simulation holds that.
|
|
||||||
/// that's counter to the original cpu-only simulation, in which materials hold their own state.
|
|
||||||
///
|
|
||||||
/// this type adapts any stateless coremem_cross::mat::Material type to be a coremem::mat::Material.
|
|
||||||
#[derive(Default, Copy, Clone, PartialEq, Serialize, Deserialize)]
|
|
||||||
pub struct AdaptStateless<R, M> {
|
|
||||||
mat: M,
|
|
||||||
m: Vec3<R>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R, M> AdaptStateless<R, M> {
|
|
||||||
pub fn into_inner(self) -> M {
|
|
||||||
self.mat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Default, M> From<M> for AdaptStateless<R, M> {
|
|
||||||
fn from(mat: M) -> Self {
|
|
||||||
Self { mat, m: Default::default() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Real, M: coremem_cross::mat::Material<R>> Material<R> for AdaptStateless<R, M> {
|
|
||||||
fn m(&self) -> Vec3<R> {
|
|
||||||
self.m
|
|
||||||
}
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
let c = self.mat.conductivity();
|
|
||||||
StepParametersMut::default().with_conductivity(c)
|
|
||||||
}
|
|
||||||
fn step_b(&mut self, context: &CellState<R>, delta_b: Vec3<R>) {
|
|
||||||
let target_b = context.with_m(self.m).b() + delta_b;
|
|
||||||
self.m = self.mat.move_b_vec(self.m, target_b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// conductors: these are truly stateless
|
|
||||||
impl<R: Real> Material<R> for AnisomorphicConductor<R> {
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
let c = coremem_cross::mat::Material::conductivity(self);
|
|
||||||
StepParametersMut::default().with_conductivity(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<R: Real> Material<R> for IsomorphicConductor<R> {
|
|
||||||
fn step_parameters_mut<'a>(&'a mut self) -> StepParametersMut<'a, R> {
|
|
||||||
let c = coremem_cross::mat::Material::conductivity(self);
|
|
||||||
StepParametersMut::default().with_conductivity(c)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type MBPgram<R> = AdaptStateless<R, coremem_cross::mat::MBPgram<R>>;
|
|
||||||
impl<R: Real> MBPgram<R> {
|
|
||||||
pub fn new(b_start: R, b_end: R, m_max: R) -> Self {
|
|
||||||
coremem_cross::mat::MBPgram::new(b_start, b_end, m_max).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
material_compat!(R, MBPgram<R>);
|
|
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ use rayon::prelude::*;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use std::iter::Sum;
|
use std::iter::Sum;
|
||||||
|
|
||||||
pub mod legacy;
|
|
||||||
pub mod spirv;
|
pub mod spirv;
|
||||||
pub mod units;
|
pub mod units;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user