use std::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use crate::constants::HBAR;
use crate::vector3::Vector3;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SpinOrbitTorque {
pub theta_sh: f64,
pub resistivity: f64,
pub thickness: f64,
pub lambda_sd: f64,
pub transparency: f64,
}
impl Default for SpinOrbitTorque {
fn default() -> Self {
Self::platinum_cofeb()
}
}
impl SpinOrbitTorque {
pub fn platinum_cofeb() -> Self {
Self {
theta_sh: 0.07, resistivity: 2.0e-7, thickness: 5.0e-9, lambda_sd: 1.5e-9, transparency: 0.5, }
}
pub fn tantalum_cofeb() -> Self {
Self {
theta_sh: -0.15, resistivity: 1.8e-7,
thickness: 5.0e-9,
lambda_sd: 1.2e-9,
transparency: 0.6,
}
}
pub fn tungsten_cofeb() -> Self {
Self {
theta_sh: -0.3, resistivity: 2.5e-7,
thickness: 5.0e-9,
lambda_sd: 1.0e-9,
transparency: 0.4,
}
}
pub fn effective_spin_hall_efficiency(&self) -> f64 {
let tanh_factor = (self.thickness / self.lambda_sd).tanh();
self.theta_sh * tanh_factor * self.transparency
}
#[inline]
pub fn damping_like_field(
&self,
j_charge: f64,
m: Vector3<f64>,
current_direction: Vector3<f64>,
ms: f64,
) -> Vector3<f64> {
let normal = Vector3::new(0.0, 0.0, 1.0);
let spin_polarization = current_direction.cross(&normal).normalize();
let theta_eff = self.effective_spin_hall_efficiency();
let e_charge = 1.602e-19; let prefactor = (HBAR / (2.0 * e_charge)) * j_charge * theta_eff / (ms * self.thickness);
m.cross(&spin_polarization) * prefactor
}
#[inline]
pub fn field_like_field(
&self,
j_charge: f64,
m: Vector3<f64>,
current_direction: Vector3<f64>,
ms: f64,
field_like_ratio: f64,
) -> Vector3<f64> {
let h_dl = self.damping_like_field(j_charge, m, current_direction, ms);
h_dl.cross(&m) * (-field_like_ratio)
}
pub fn total_field(
&self,
j_charge: f64,
m: Vector3<f64>,
current_direction: Vector3<f64>,
ms: f64,
field_like_ratio: f64,
) -> (Vector3<f64>, Vector3<f64>) {
let h_dl = self.damping_like_field(j_charge, m, current_direction, ms);
let h_fl = self.field_like_field(j_charge, m, current_direction, ms, field_like_ratio);
(h_dl, h_fl)
}
#[allow(dead_code)]
pub fn critical_current_density(&self, ms: f64, h_k: f64) -> f64 {
let e_charge = 1.602e-19;
let theta_eff = self.effective_spin_hall_efficiency();
let h_eff = h_k + ms;
(2.0 * e_charge / HBAR) * (ms * self.thickness / theta_eff.abs()) * h_eff
}
pub fn with_theta_sh(mut self, theta_sh: f64) -> Self {
self.theta_sh = theta_sh;
self
}
pub fn with_resistivity(mut self, rho: f64) -> Self {
self.resistivity = rho;
self
}
pub fn with_thickness(mut self, thickness: f64) -> Self {
self.thickness = thickness;
self
}
pub fn with_lambda_sd(mut self, lambda_sd: f64) -> Self {
self.lambda_sd = lambda_sd;
self
}
pub fn with_transparency(mut self, transparency: f64) -> Self {
self.transparency = transparency.clamp(0.0, 1.0);
self
}
}
impl fmt::Display for SpinOrbitTorque {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"SpinOrbitTorque(θ_SH={:.3}, t={:.1} nm, λ_sd={:.1} nm, T={:.2})",
self.theta_sh,
self.thickness * 1e9,
self.lambda_sd * 1e9,
self.transparency
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_platinum_sot() {
let sot = SpinOrbitTorque::platinum_cofeb();
assert!(sot.theta_sh > 0.0); assert!(sot.theta_sh < 0.1);
}
#[test]
fn test_tantalum_sot() {
let sot = SpinOrbitTorque::tantalum_cofeb();
assert!(sot.theta_sh < 0.0); assert!(sot.theta_sh.abs() > 0.1);
}
#[test]
fn test_tungsten_sot() {
let sot = SpinOrbitTorque::tungsten_cofeb();
assert!(sot.theta_sh < -0.2); }
#[test]
fn test_effective_spin_hall_efficiency() {
let sot = SpinOrbitTorque::platinum_cofeb();
let theta_eff = sot.effective_spin_hall_efficiency();
assert!(theta_eff < sot.theta_sh);
assert!(theta_eff > 0.0);
}
#[test]
fn test_damping_like_field() {
let sot = SpinOrbitTorque::platinum_cofeb();
let m = Vector3::new(0.0, 0.1, 1.0).normalize(); let j_charge = 1.0e11; let current_dir = Vector3::new(1.0, 0.0, 0.0); let ms = 1.0e6;
let h_dl = sot.damping_like_field(j_charge, m, current_dir, ms);
assert!(h_dl.dot(&m).abs() < 1e-6);
let h_magnitude = h_dl.magnitude();
assert!(h_magnitude > 0.0);
assert!(h_magnitude < 1.0e5); }
#[test]
fn test_field_like_field() {
let sot = SpinOrbitTorque::platinum_cofeb();
let m = Vector3::new(0.0, 0.0, 1.0); let j_charge = 1.0e11;
let current_dir = Vector3::new(1.0, 0.0, 0.0);
let ms = 1.0e6;
let fl_ratio = 0.2;
let h_fl = sot.field_like_field(j_charge, m, current_dir, ms, fl_ratio);
let h_dl = sot.damping_like_field(j_charge, m, current_dir, ms);
assert!(h_fl.magnitude() < h_dl.magnitude());
}
#[test]
fn test_critical_current() {
let sot = SpinOrbitTorque::platinum_cofeb();
let ms = 1.0e6; let h_k = 1.0e5;
let j_c = sot.critical_current_density(ms, h_k);
assert!(j_c > 0.0);
assert!(j_c > 1.0e10); }
#[test]
fn test_total_field() {
let sot = SpinOrbitTorque::platinum_cofeb();
let m = Vector3::new(0.0, 0.1, 1.0).normalize();
let j_charge = 1.0e11;
let current_dir = Vector3::new(1.0, 0.0, 0.0);
let ms = 1.0e6;
let fl_ratio = 0.2;
let (h_dl, h_fl) = sot.total_field(j_charge, m, current_dir, ms, fl_ratio);
assert!(h_dl.magnitude() > 0.0);
assert!(h_fl.magnitude() > 0.0);
assert!(h_dl.magnitude() > h_fl.magnitude());
}
}