use std::f64::consts::PI;
use super::chain::SpinChain;
use crate::constants::HBAR;
use crate::vector3::Vector3;
#[derive(Debug, Clone)]
pub struct SpinPumpingDetector {
pub position_idx: usize,
pub g_r: f64,
pub theta_sh: f64,
pub rho: f64,
pub strip_width: f64,
pub interface_normal: Vector3<f64>,
prev_m: Option<Vector3<f64>>,
}
impl SpinPumpingDetector {
pub fn new(position_idx: usize, g_r: f64, theta_sh: f64, rho: f64, strip_width: f64) -> Self {
Self {
position_idx,
g_r,
theta_sh,
rho,
strip_width,
interface_normal: Vector3::new(0.0, 1.0, 0.0),
prev_m: None,
}
}
pub fn yig_pt(position_idx: usize, strip_width: f64) -> Self {
Self::new(
position_idx,
1.0e19, 0.08, 2.0e-7, strip_width,
)
}
pub fn py_pt(position_idx: usize, strip_width: f64) -> Self {
Self::new(
position_idx,
5.0e19, 0.08, 2.0e-7, strip_width,
)
}
pub fn detect(&mut self, chain: &SpinChain, dt: f64) -> f64 {
let m_curr = chain.spins[self.position_idx];
let dm_dt = if let Some(prev_m) = self.prev_m {
(m_curr - prev_m) * (1.0 / dt)
} else {
self.prev_m = Some(m_curr);
return 0.0;
};
self.prev_m = Some(m_curr);
let js_vector = m_curr.cross(&dm_dt);
let prefactor = HBAR / (4.0 * PI);
let js_magnitude = prefactor * self.g_r * js_vector.magnitude();
let e_field = self.rho * self.theta_sh * js_magnitude;
e_field * self.strip_width
}
pub fn spin_current_density(&self, chain: &SpinChain, dt: f64) -> f64 {
if let Some(prev_m) = self.prev_m {
let m_curr = chain.spins[self.position_idx];
let dm_dt = (m_curr - prev_m) * (1.0 / dt);
let js_vector = m_curr.cross(&dm_dt);
let prefactor = HBAR / (4.0 * PI);
prefactor * self.g_r * js_vector.magnitude()
} else {
0.0
}
}
pub fn reset(&mut self) {
self.prev_m = None;
}
pub fn conversion_efficiency(&self) -> f64 {
self.rho * self.theta_sh * self.strip_width
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::magnon::chain::{ChainParameters, SpinChain};
#[test]
fn test_detector_creation() {
let detector = SpinPumpingDetector::yig_pt(50, 1.0e-3);
assert_eq!(detector.position_idx, 50);
assert!(detector.g_r > 0.0);
assert!(detector.theta_sh > 0.0);
}
#[test]
fn test_no_dynamics_no_signal() {
let chain = SpinChain::new(100, ChainParameters::default());
let mut detector = SpinPumpingDetector::yig_pt(50, 1.0e-3);
let v1 = detector.detect(&chain, 1.0e-13);
assert_eq!(v1, 0.0);
let v2 = detector.detect(&chain, 1.0e-13);
assert!(v2.abs() < 1e-30);
}
#[test]
fn test_magnetization_change_produces_signal() {
let mut chain = SpinChain::new(100, ChainParameters::default());
let mut detector = SpinPumpingDetector::yig_pt(50, 1.0e-3);
detector.detect(&chain, 1.0e-13);
chain.spins[50] = Vector3::new(0.9, 0.1, 0.0).normalize();
let voltage = detector.detect(&chain, 1.0e-13);
assert!(voltage.abs() > 0.0);
}
#[test]
fn test_conversion_efficiency() {
let detector = SpinPumpingDetector::yig_pt(50, 1.0e-3);
let efficiency = detector.conversion_efficiency();
assert!(efficiency > 0.0);
let detector2 = SpinPumpingDetector::yig_pt(50, 2.0e-3);
assert!(detector2.conversion_efficiency() > efficiency);
}
#[test]
fn test_reset() {
let chain = SpinChain::new(100, ChainParameters::default());
let mut detector = SpinPumpingDetector::yig_pt(50, 1.0e-3);
detector.detect(&chain, 1.0e-13);
assert!(detector.prev_m.is_some());
detector.reset();
assert!(detector.prev_m.is_none());
}
}