use std::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::vector3::Vector3;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum DmiType {
Bulk,
Interfacial,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DmiParameters {
pub d: f64,
pub dmi_type: DmiType,
pub dmi_vector: Vector3<f64>,
}
impl Default for DmiParameters {
fn default() -> Self {
Self {
d: 1.5e-3, dmi_type: DmiType::Interfacial,
dmi_vector: Vector3::new(0.0, 0.0, 1.0),
}
}
}
impl DmiParameters {
pub fn pt_co() -> Self {
Self {
d: 1.5e-3,
dmi_type: DmiType::Interfacial,
..Default::default()
}
}
pub fn pt_cofeb() -> Self {
Self {
d: 1.3e-3,
dmi_type: DmiType::Interfacial,
..Default::default()
}
}
pub fn w_cofeb() -> Self {
Self {
d: 2.0e-3,
dmi_type: DmiType::Interfacial,
..Default::default()
}
}
pub fn ta_cofeb() -> Self {
Self {
d: 1.1e-3,
dmi_type: DmiType::Interfacial,
..Default::default()
}
}
pub fn ir_co() -> Self {
Self {
d: 2.5e-3,
dmi_type: DmiType::Interfacial,
..Default::default()
}
}
pub fn mnsi() -> Self {
Self {
d: 0.18e-3,
dmi_type: DmiType::Bulk,
dmi_vector: Vector3::new(0.0, 0.0, 1.0),
}
}
pub fn fege() -> Self {
Self {
d: 0.85e-3,
dmi_type: DmiType::Bulk,
dmi_vector: Vector3::new(0.0, 0.0, 1.0),
}
}
pub fn dmi_field(
&self,
_m: Vector3<f64>,
dm_dx: Vector3<f64>,
dm_dy: Vector3<f64>,
) -> Vector3<f64> {
match self.dmi_type {
DmiType::Interfacial => {
let prefactor = 2.0 * self.d / 1.0e6;
Vector3::new(
prefactor * dm_dx.z,
prefactor * dm_dy.z,
-prefactor * (dm_dx.x + dm_dy.y),
)
},
DmiType::Bulk => {
let curl_m_z = dm_dy.x - dm_dx.y;
let curl_m_x = dm_dy.z; let curl_m_y = -dm_dx.z;
Vector3::new(curl_m_x, curl_m_y, curl_m_z) * (self.d / 1.0e6)
},
}
}
pub fn critical_dmi(exchange_a: f64, anisotropy_k: f64) -> f64 {
use std::f64::consts::PI;
4.0 * (exchange_a * anisotropy_k).sqrt() / PI
}
pub fn supports_skyrmions(&self, exchange_a: f64, anisotropy_k: f64) -> bool {
self.d > Self::critical_dmi(exchange_a, anisotropy_k)
}
pub fn skyrmion_diameter(&self, exchange_a: f64) -> f64 {
use std::f64::consts::PI;
4.0 * PI * (exchange_a / self.d).sqrt()
}
#[allow(dead_code)]
pub fn domain_wall_width(&self, exchange_a: f64, anisotropy_k: f64) -> f64 {
(exchange_a / anisotropy_k).sqrt()
}
pub fn with_d(mut self, d: f64) -> Self {
self.d = d;
self
}
pub fn with_type(mut self, dmi_type: DmiType) -> Self {
self.dmi_type = dmi_type;
self
}
pub fn with_vector(mut self, vector: Vector3<f64>) -> Self {
self.dmi_vector = vector.normalize();
self
}
}
impl fmt::Display for DmiType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DmiType::Bulk => write!(f, "Bulk"),
DmiType::Interfacial => write!(f, "Interfacial"),
}
}
}
impl fmt::Display for DmiParameters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "DMI[{}]: D={:.2} mJ/m²", self.dmi_type, self.d * 1e3)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dmi_parameters() {
let pt_co = DmiParameters::pt_co();
assert_eq!(pt_co.dmi_type, DmiType::Interfacial);
let mnsi = DmiParameters::mnsi();
assert_eq!(mnsi.dmi_type, DmiType::Bulk);
}
#[test]
fn test_critical_dmi() {
let a_ex = 1.0e-11; let k_u = 1.0e5;
let d_c = DmiParameters::critical_dmi(a_ex, k_u);
assert!(d_c > 0.0);
assert!(d_c < 1.0e-2); }
#[test]
fn test_skyrmion_stability() {
let strong_dmi = DmiParameters::ir_co();
let _weak_dmi = DmiParameters::mnsi();
let a_ex = 1.0e-11;
let k_u = 1.0e5;
assert!(strong_dmi.supports_skyrmions(a_ex, k_u));
}
#[test]
fn test_pt_cofeb() {
let dmi = DmiParameters::pt_cofeb();
assert_eq!(dmi.dmi_type, DmiType::Interfacial);
assert!(dmi.d > 1.0e-3);
}
#[test]
fn test_w_cofeb() {
let dmi = DmiParameters::w_cofeb();
assert!(dmi.d > 1.5e-3); }
#[test]
fn test_ta_cofeb() {
let dmi = DmiParameters::ta_cofeb();
assert_eq!(dmi.dmi_type, DmiType::Interfacial);
}
#[test]
fn test_fege_bulk() {
let dmi = DmiParameters::fege();
assert_eq!(dmi.dmi_type, DmiType::Bulk);
assert!(dmi.d > 0.5e-3); }
#[test]
fn test_skyrmion_diameter() {
let dmi = DmiParameters::pt_cofeb();
let a_ex = 1.5e-11;
let diameter = dmi.skyrmion_diameter(a_ex);
assert!(diameter > 0.0); assert!(diameter.is_finite()); }
#[test]
fn test_skyrmion_size_vs_dmi() {
let a_ex = 1.5e-11;
let weak_dmi = DmiParameters::pt_cofeb();
let strong_dmi = DmiParameters::ir_co();
let d_weak = weak_dmi.skyrmion_diameter(a_ex);
let d_strong = strong_dmi.skyrmion_diameter(a_ex);
assert!(d_strong < d_weak);
}
#[test]
fn test_builder_methods() {
let dmi = DmiParameters::pt_co()
.with_d(3.0e-3)
.with_type(DmiType::Bulk);
assert_eq!(dmi.d, 3.0e-3);
assert_eq!(dmi.dmi_type, DmiType::Bulk);
}
#[test]
fn test_vector_normalization() {
let dmi = DmiParameters::default().with_vector(Vector3::new(1.0, 1.0, 1.0));
let norm =
(dmi.dmi_vector.x.powi(2) + dmi.dmi_vector.y.powi(2) + dmi.dmi_vector.z.powi(2)).sqrt();
assert!((norm - 1.0).abs() < 1e-10);
}
}