use std::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::vector3::Vector3;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Ferromagnet {
pub alpha: f64,
pub ms: f64,
pub anisotropy_k: f64,
pub easy_axis: Vector3<f64>,
pub exchange_a: f64,
}
impl Default for Ferromagnet {
fn default() -> Self {
Self {
alpha: 0.01,
ms: 1.4e5,
anisotropy_k: 0.0,
easy_axis: Vector3::new(0.0, 0.0, 1.0),
exchange_a: 1.0e-11,
}
}
}
impl Ferromagnet {
pub fn yig() -> Self {
Self {
alpha: 0.0001,
ms: 1.4e5,
anisotropy_k: 0.0,
easy_axis: Vector3::new(0.0, 0.0, 1.0),
exchange_a: 3.7e-12,
}
}
pub fn permalloy() -> Self {
Self {
alpha: 0.01,
ms: 8.0e5,
anisotropy_k: 0.0,
easy_axis: Vector3::new(1.0, 0.0, 0.0),
exchange_a: 1.3e-11,
}
}
pub fn cofeb() -> Self {
Self {
alpha: 0.004,
ms: 1.0e6,
anisotropy_k: 1.0e5,
easy_axis: Vector3::new(0.0, 0.0, 1.0),
exchange_a: 2.0e-11,
}
}
pub fn iron() -> Self {
Self {
alpha: 0.002,
ms: 1.71e6, anisotropy_k: 4.8e4, easy_axis: Vector3::new(1.0, 0.0, 0.0), exchange_a: 2.1e-11,
}
}
pub fn cobalt() -> Self {
Self {
alpha: 0.005,
ms: 1.4e6,
anisotropy_k: 5.0e5, easy_axis: Vector3::new(0.0, 0.0, 1.0), exchange_a: 3.0e-11,
}
}
pub fn nickel() -> Self {
Self {
alpha: 0.045, ms: 4.8e5,
anisotropy_k: -4.5e3, easy_axis: Vector3::new(1.0, 1.0, 1.0), exchange_a: 0.9e-11,
}
}
pub fn cofe() -> Self {
Self {
alpha: 0.003,
ms: 1.95e6, anisotropy_k: 1.0e4,
easy_axis: Vector3::new(0.0, 0.0, 1.0),
exchange_a: 2.5e-11,
}
}
pub fn py() -> Self {
Self::permalloy()
}
pub fn with_alpha(mut self, alpha: f64) -> Self {
self.alpha = alpha;
self
}
pub fn with_ms(mut self, ms: f64) -> Self {
self.ms = ms;
self
}
pub fn with_anisotropy(mut self, k: f64) -> Self {
self.anisotropy_k = k;
self
}
pub fn with_easy_axis(mut self, axis: Vector3<f64>) -> Self {
self.easy_axis = axis.normalize();
self
}
pub fn with_exchange(mut self, a: f64) -> Self {
self.exchange_a = a;
self
}
pub fn custom(
alpha: f64,
ms: f64,
anisotropy_k: f64,
easy_axis: Vector3<f64>,
exchange_a: f64,
) -> Self {
Self {
alpha,
ms,
anisotropy_k,
easy_axis: easy_axis.normalize(),
exchange_a,
}
}
}
impl fmt::Display for Ferromagnet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Ferromagnet(α={:.4}, Ms={:.2e} A/m, K={:.2e} J/m³, A={:.2e} J/m)",
self.alpha, self.ms, self.anisotropy_k, self.exchange_a
)
}
}
impl super::traits::MagneticMaterial for Ferromagnet {
fn saturation_magnetization(&self) -> f64 {
self.ms
}
fn damping(&self) -> f64 {
self.alpha
}
fn exchange_stiffness(&self) -> f64 {
self.exchange_a
}
fn anisotropy(&self) -> f64 {
self.anisotropy_k
}
fn easy_axis(&self) -> Vector3<f64> {
self.easy_axis
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_ferromagnet() {
let fm = Ferromagnet::default();
assert!(fm.alpha > 0.0);
assert!(fm.ms > 0.0);
}
#[test]
fn test_yig_properties() {
let yig = Ferromagnet::yig();
assert!(yig.alpha < 0.001);
assert!((yig.ms - 1.4e5).abs() < 1.0);
}
#[test]
fn test_permalloy_properties() {
let py = Ferromagnet::permalloy();
assert!((py.ms - 8.0e5).abs() < 1.0);
assert_eq!(py.anisotropy_k, 0.0); }
#[test]
fn test_cofeb_properties() {
let cofeb = Ferromagnet::cofeb();
assert!(cofeb.ms > 9.0e5);
assert!(cofeb.anisotropy_k > 0.0); }
#[test]
fn test_iron_properties() {
let fe = Ferromagnet::iron();
assert!(fe.ms > 1.5e6); assert!(fe.alpha < 0.01); }
#[test]
fn test_cobalt_properties() {
let co = Ferromagnet::cobalt();
assert!(co.anisotropy_k > 1.0e5); assert!((co.easy_axis.z - 1.0).abs() < 1e-10); }
#[test]
fn test_nickel_properties() {
let ni = Ferromagnet::nickel();
assert!(ni.alpha > 0.04); assert!(ni.ms < 5.0e5);
}
#[test]
fn test_cofe_properties() {
let cofe = Ferromagnet::cofe();
assert!(cofe.ms > 1.9e6); assert!(cofe.alpha < 0.01); }
#[test]
fn test_builder_pattern() {
let custom = Ferromagnet::yig().with_alpha(0.01).with_ms(2.0e5);
assert_eq!(custom.alpha, 0.01);
assert_eq!(custom.ms, 2.0e5);
}
#[test]
fn test_custom_ferromagnet() {
let custom = Ferromagnet::custom(0.015, 1.0e6, 1.0e5, Vector3::new(1.0, 1.0, 0.0), 1.5e-11);
assert_eq!(custom.alpha, 0.015);
assert_eq!(custom.ms, 1.0e6);
let norm =
(custom.easy_axis.x.powi(2) + custom.easy_axis.y.powi(2) + custom.easy_axis.z.powi(2))
.sqrt();
assert!((norm - 1.0).abs() < 1e-10);
}
#[test]
fn test_py_alias() {
let py1 = Ferromagnet::py();
let py2 = Ferromagnet::permalloy();
assert_eq!(py1.alpha, py2.alpha);
assert_eq!(py1.ms, py2.ms);
}
}