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 InverseSpinHall {
pub theta_sh: f64,
pub rho: f64,
}
impl Default for InverseSpinHall {
fn default() -> Self {
Self {
theta_sh: 0.08, rho: 2.0e-7, }
}
}
impl InverseSpinHall {
pub fn platinum() -> Self {
Self {
theta_sh: 0.08,
rho: 2.0e-7,
}
}
pub fn tantalum() -> Self {
Self {
theta_sh: 0.12,
rho: 1.8e-7,
}
}
pub fn tungsten() -> Self {
Self {
theta_sh: -0.3,
rho: 5.0e-8,
}
}
#[inline]
pub fn convert(&self, js_flow: Vector3<f64>, js_polarization: Vector3<f64>) -> Vector3<f64> {
let cross = js_flow.cross(&js_polarization);
cross * (self.rho * self.theta_sh)
}
#[inline]
pub fn voltage(
&self,
js_flow: Vector3<f64>,
js_polarization: Vector3<f64>,
strip_width: f64,
) -> f64 {
let e_field = self.convert(js_flow, js_polarization);
e_field.magnitude() * strip_width
}
pub fn efficiency(&self) -> f64 {
self.rho * self.theta_sh.abs()
}
pub fn with_theta_sh(mut self, theta_sh: f64) -> Self {
self.theta_sh = theta_sh;
self
}
pub fn with_rho(mut self, rho: f64) -> Self {
self.rho = rho;
self
}
}
impl fmt::Display for InverseSpinHall {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"InverseSpinHall(θ_SH={:.3}, ρ={:.2e} Ω·m)",
self.theta_sh, self.rho
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ishe_perpendicularity() {
let ishe = InverseSpinHall::default();
let js_flow = Vector3::new(1.0, 0.0, 0.0);
let js_pol = Vector3::new(0.0, 1.0, 0.0);
let e_field = ishe.convert(js_flow, js_pol);
assert!(e_field.dot(&js_flow).abs() < 1e-10);
assert!(e_field.dot(&js_pol).abs() < 1e-10);
}
#[test]
fn test_ishe_zero_current() {
let ishe = InverseSpinHall::default();
let js_flow = Vector3::new(0.0, 0.0, 0.0);
let js_pol = Vector3::new(0.0, 1.0, 0.0);
let e_field = ishe.convert(js_flow, js_pol);
assert!(e_field.magnitude() < 1e-50);
}
#[test]
fn test_ishe_parallel_vectors() {
let ishe = InverseSpinHall::default();
let js_flow = Vector3::new(1.0, 0.0, 0.0);
let js_pol = Vector3::new(1.0, 0.0, 0.0);
let e_field = ishe.convert(js_flow, js_pol);
assert!(e_field.magnitude() < 1e-50);
}
#[test]
fn test_material_properties() {
let pt = InverseSpinHall::platinum();
let ta = InverseSpinHall::tantalum();
let w = InverseSpinHall::tungsten();
assert!(pt.theta_sh > 0.0);
assert!(ta.theta_sh > 0.0);
assert!(w.theta_sh < 0.0); }
}