#[derive(Debug, Clone, Copy, PartialEq)]
pub enum RelaxationMechanism {
ElliottYafet,
DyakonovPerel,
BirAronovPikus,
}
#[derive(Debug, Clone)]
pub struct RelaxationTime {
pub tau_s: f64,
pub mechanism: RelaxationMechanism,
}
impl Default for RelaxationTime {
fn default() -> Self {
Self {
tau_s: 100.0e-12, mechanism: RelaxationMechanism::ElliottYafet,
}
}
}
impl RelaxationTime {
pub fn copper() -> Self {
Self {
tau_s: 100.0e-12,
mechanism: RelaxationMechanism::ElliottYafet,
}
}
pub fn aluminum() -> Self {
Self {
tau_s: 200.0e-12,
mechanism: RelaxationMechanism::ElliottYafet,
}
}
pub fn silicon() -> Self {
Self {
tau_s: 1.0e-9, mechanism: RelaxationMechanism::DyakonovPerel,
}
}
pub fn spin_diffusion_length(&self, diffusion_const: f64) -> f64 {
(diffusion_const * self.tau_s).sqrt()
}
}
#[derive(Debug, Clone)]
pub struct SpinAccumulation {
pub mu_s: f64,
pub mu_c: f64,
pub position: f64,
pub relaxation: RelaxationTime,
}
impl Default for SpinAccumulation {
fn default() -> Self {
Self {
mu_s: 0.0,
mu_c: 0.0,
position: 0.0,
relaxation: RelaxationTime::default(),
}
}
}
impl SpinAccumulation {
pub fn new(position: f64, relaxation: RelaxationTime) -> Self {
Self {
mu_s: 0.0,
mu_c: 0.0,
position,
relaxation,
}
}
pub fn from_spin_current(&mut self, spin_current: f64, spin_resistance: f64, area: f64) {
self.mu_s = (2.0 * spin_resistance / area) * spin_current;
}
pub fn polarization(&self, fermi_energy: f64) -> f64 {
if fermi_energy > 0.0 {
self.mu_s / fermi_energy
} else {
0.0
}
}
pub fn evolve(&mut self, source: f64, dt: f64) {
let decay = -self.mu_s / self.relaxation.tau_s;
let dmu_dt = decay + source;
self.mu_s += dmu_dt * dt;
}
pub fn steady_state(&mut self, source: f64) {
self.mu_s = source * self.relaxation.tau_s;
}
pub fn spin_current_from_gradient(&self, gradient: f64, spin_conductivity: f64) -> f64 {
-spin_conductivity * gradient
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_relaxation_time() {
let cu = RelaxationTime::copper();
let al = RelaxationTime::aluminum();
let si = RelaxationTime::silicon();
assert!(cu.tau_s < al.tau_s);
assert!(al.tau_s < si.tau_s);
}
#[test]
fn test_spin_diffusion_length() {
let relaxation = RelaxationTime::copper();
let d = 1.0e-3;
let lambda_s = relaxation.spin_diffusion_length(d);
assert!(lambda_s > 0.0);
assert!(lambda_s < 1.0e-3); }
#[test]
fn test_spin_accumulation_evolution() {
let mut acc = SpinAccumulation::new(0.0, RelaxationTime::copper());
let source = 1.0e-15; let dt = 1.0e-12;
for _ in 0..1000 {
acc.evolve(source, dt);
}
let expected_steady = source * acc.relaxation.tau_s;
assert!((acc.mu_s - expected_steady).abs() / expected_steady < 0.1);
}
#[test]
fn test_steady_state() {
let mut acc = SpinAccumulation::new(0.0, RelaxationTime::aluminum());
let source = 1.0e-15;
acc.steady_state(source);
assert!((acc.mu_s - source * acc.relaxation.tau_s).abs() < 1e-20);
}
}