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 TopologicalClass {
ThreeDimensional,
TwoDimensional,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TopologicalInsulator {
pub name: String,
pub ti_class: TopologicalClass,
pub bulk_gap: f64,
pub fermi_velocity: f64,
pub edelstein_length: f64,
pub spin_hall_conductivity: f64,
pub surface_carrier_density: f64,
pub lattice_constant: f64,
}
impl Default for TopologicalInsulator {
fn default() -> Self {
Self::bi2se3()
}
}
impl TopologicalInsulator {
pub fn bi2se3() -> Self {
Self {
name: "Bi₂Se₃".to_string(),
ti_class: TopologicalClass::ThreeDimensional,
bulk_gap: 0.3, fermi_velocity: 5.0e5, edelstein_length: 1.0, spin_hall_conductivity: 1.0e6, surface_carrier_density: 1.0e17, lattice_constant: 0.414, }
}
pub fn bi2te3() -> Self {
Self {
name: "Bi₂Te₃".to_string(),
ti_class: TopologicalClass::ThreeDimensional,
bulk_gap: 0.17, fermi_velocity: 4.0e5, edelstein_length: 0.8, spin_hall_conductivity: 8.0e5, surface_carrier_density: 5.0e16, lattice_constant: 0.304, }
}
pub fn bi2se2te() -> Self {
Self {
name: "Bi₂Se₂Te".to_string(),
ti_class: TopologicalClass::ThreeDimensional,
bulk_gap: 0.22, fermi_velocity: 4.5e5, edelstein_length: 0.9, spin_hall_conductivity: 9.0e5, surface_carrier_density: 7.0e16, lattice_constant: 0.35, }
}
pub fn bi_sb_te3(sb_fraction: f64) -> Self {
let bulk_gap = 0.17 + sb_fraction * 0.13; let fermi_velocity = 4.0e5 * (1.0 + 0.25 * sb_fraction);
Self {
name: format!("(Bi₁₋ₓSbₓ)₂Te₃ (x={:.2})", sb_fraction),
ti_class: TopologicalClass::ThreeDimensional,
bulk_gap,
fermi_velocity,
edelstein_length: 0.85,
spin_hall_conductivity: 8.5e5,
surface_carrier_density: 6.0e16,
lattice_constant: 0.304,
}
}
pub fn sb2te3() -> Self {
Self {
name: "Sb₂Te₃".to_string(),
ti_class: TopologicalClass::ThreeDimensional,
bulk_gap: 0.28, fermi_velocity: 3.5e5, edelstein_length: 0.7, spin_hall_conductivity: 7.0e5, surface_carrier_density: 4.0e16, lattice_constant: 0.304, }
}
pub fn edelstein_spin_accumulation(&self, current_density: f64) -> f64 {
self.edelstein_length * 1e-9 * current_density
}
pub fn spin_hall_angle(&self, charge_conductivity: f64) -> f64 {
self.spin_hall_conductivity / charge_conductivity
}
pub fn sot_efficiency(&self, current_density: f64, magnetization: f64) -> f64 {
let spin_accum = self.edelstein_spin_accumulation(current_density);
spin_accum / (magnetization * 1e-9) }
pub fn is_suitable_for_spintronics(&self) -> bool {
self.bulk_gap > 0.15 && self.fermi_velocity > 3.0e5 && self.edelstein_length > 0.5 }
pub fn with_edelstein_length(mut self, length: f64) -> Self {
self.edelstein_length = length;
self
}
pub fn with_carrier_density(mut self, density: f64) -> Self {
self.surface_carrier_density = density;
self
}
}
pub fn surface_spin_texture(momentum: Vector3<f64>) -> Vector3<f64> {
let z_axis = Vector3::new(0.0, 0.0, 1.0);
z_axis.cross(&momentum).normalize()
}
impl fmt::Display for TopologicalClass {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TopologicalClass::ThreeDimensional => write!(f, "3D TI"),
TopologicalClass::TwoDimensional => write!(f, "2D TI (QSHI)"),
}
}
}
impl fmt::Display for TopologicalInsulator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} [{}]: E_gap={:.2} eV, v_F={:.2e} m/s, λ_E={:.1} nm",
self.name, self.ti_class, self.bulk_gap, self.fermi_velocity, self.edelstein_length
)
}
}
impl super::traits::TopologicalMaterial for TopologicalInsulator {
fn bulk_gap(&self) -> f64 {
self.bulk_gap
}
fn surface_fermi_velocity(&self) -> f64 {
self.fermi_velocity
}
}
impl super::traits::SpinChargeConverter for TopologicalInsulator {
fn spin_hall_angle(&self) -> f64 {
self.edelstein_length * 1e-9 * 1e9 }
fn spin_hall_conductivity(&self) -> f64 {
self.spin_hall_conductivity
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bi2se3() {
let ti = TopologicalInsulator::bi2se3();
assert_eq!(ti.ti_class, TopologicalClass::ThreeDimensional);
assert!(ti.bulk_gap > 0.2);
assert!(ti.fermi_velocity > 4.0e5);
}
#[test]
fn test_bi2te3() {
let ti = TopologicalInsulator::bi2te3();
assert_eq!(ti.ti_class, TopologicalClass::ThreeDimensional);
assert!(ti.bulk_gap > 0.15);
}
#[test]
fn test_bi_sb_te3_composition() {
let ti_pure_bi = TopologicalInsulator::bi_sb_te3(0.0);
let ti_half_sb = TopologicalInsulator::bi_sb_te3(0.5);
assert!(ti_half_sb.bulk_gap > ti_pure_bi.bulk_gap);
}
#[test]
fn test_edelstein_spin_accumulation() {
let ti = TopologicalInsulator::bi2se3();
let j_c = 1.0e10;
let spin_accum = ti.edelstein_spin_accumulation(j_c);
assert!(spin_accum > 0.0);
}
#[test]
fn test_spin_hall_angle() {
let ti = TopologicalInsulator::bi2se3();
let sigma_c = 1.0e5;
let theta_sh = ti.spin_hall_angle(sigma_c);
assert!(theta_sh > 0.0);
assert!(theta_sh < 100.0);
}
#[test]
fn test_sot_efficiency() {
let ti = TopologicalInsulator::bi2se3();
let j_c = 1.0e10; let ms = 1.0e6;
let efficiency = ti.sot_efficiency(j_c, ms);
assert!(efficiency > 0.0);
}
#[test]
fn test_spintronics_suitability() {
let bi2se3 = TopologicalInsulator::bi2se3();
assert!(bi2se3.is_suitable_for_spintronics());
let weak_ti = TopologicalInsulator::bi2se3().with_edelstein_length(0.1);
assert!(!weak_ti.is_suitable_for_spintronics());
}
#[test]
fn test_builder_pattern() {
let ti = TopologicalInsulator::bi2se3()
.with_edelstein_length(2.0)
.with_carrier_density(1.0e18);
assert_eq!(ti.edelstein_length, 2.0);
assert_eq!(ti.surface_carrier_density, 1.0e18);
}
#[test]
fn test_surface_spin_texture() {
let momentum = Vector3::new(1.0, 0.0, 0.0); let spin = surface_spin_texture(momentum);
assert!(spin.dot(&momentum).abs() < 1e-10);
assert!((spin.magnitude() - 1.0).abs() < 1e-10);
assert!(spin.y.abs() > 0.9);
}
#[test]
fn test_spin_momentum_locking() {
let k1 = Vector3::new(1.0, 0.0, 0.0);
let k2 = Vector3::new(0.0, 1.0, 0.0);
let s1 = surface_spin_texture(k1);
let s2 = surface_spin_texture(k2);
assert!(s1.dot(&s2).abs() < 1e-10);
}
#[test]
fn test_comparison_bi_compounds() {
let bi2se3 = TopologicalInsulator::bi2se3();
let bi2te3 = TopologicalInsulator::bi2te3();
assert!(bi2se3.bulk_gap > bi2te3.bulk_gap);
assert!(bi2se3.is_suitable_for_spintronics());
assert!(bi2te3.is_suitable_for_spintronics());
}
}