use super::rate_equations::GeneralizedRateEquations;
use std::f64::consts::PI;
const C_LIGHT: f64 = 2.997_924_58e8;
#[derive(Debug, Clone)]
pub struct PlasmonicCavity {
pub mode_volume_nm3: f64,
pub q_factor: f64,
pub purcell_factor: f64,
pub resonance_wavelength: f64,
}
impl PlasmonicCavity {
pub fn compute_purcell(
mode_volume_nm3: f64,
q_factor: f64,
wavelength_m: f64,
n_eff: f64,
) -> f64 {
let v_m3 = mode_volume_nm3 * 1e-27;
let lambda_n = wavelength_m / n_eff;
(3.0 / (4.0 * PI * PI)) * (lambda_n.powi(3) / v_m3) * q_factor
}
pub fn linewidth_nm(&self) -> f64 {
let lambda_nm = self.resonance_wavelength * 1e9;
lambda_nm / self.q_factor
}
pub fn linewidth_thz(&self) -> f64 {
C_LIGHT / (self.q_factor * self.resonance_wavelength) * 1e-12
}
}
#[derive(Debug, Clone)]
pub enum GainMaterial {
InGaAsP,
CdSe,
Dye {
peak_wavelength: f64,
gain_cross_section: f64,
},
ErbiumDoped,
}
impl GainMaterial {
pub fn peak_wavelength_m(&self) -> f64 {
match self {
GainMaterial::InGaAsP => 1.3e-6,
GainMaterial::CdSe => 620e-9,
GainMaterial::Dye {
peak_wavelength, ..
} => *peak_wavelength,
GainMaterial::ErbiumDoped => 1.55e-6,
}
}
pub fn emission_cross_section_m2(&self) -> f64 {
match self {
GainMaterial::InGaAsP => 2.0e-20,
GainMaterial::CdSe => 5.0e-19,
GainMaterial::Dye {
gain_cross_section, ..
} => *gain_cross_section,
GainMaterial::ErbiumDoped => 6.0e-25,
}
}
}
#[derive(Debug, Clone)]
pub struct GainMedium {
pub material: GainMaterial,
pub carrier_density: f64,
pub peak_gain: f64,
pub transparency_density: f64,
}
impl GainMedium {
pub fn net_gain_cm(&self) -> f64 {
let sigma = self.material.emission_cross_section_m2();
let g_m = sigma * (self.carrier_density - self.transparency_density);
g_m * 100.0 }
}
#[derive(Debug, Clone)]
pub struct Spaser {
pub plasmonic_cavity: PlasmonicCavity,
pub gain_medium: GainMedium,
pub threshold_gain: f64,
}
impl Spaser {
pub fn new_bowtie_spaser(gap_nm: f64, dye_concentration: f64) -> Self {
let wavelength = 620e-9; let v_nm3 = (gap_nm * 0.5).powi(3) * PI; let q = 10.0; let n_eff = 1.5;
let fp = PlasmonicCavity::compute_purcell(v_nm3.max(1.0), q, wavelength, n_eff);
let avogadro = 6.022_140_76e23;
let n_dye = dye_concentration * avogadro * 1e3; let gain_medium = GainMedium {
material: GainMaterial::Dye {
peak_wavelength: 620e-9,
gain_cross_section: 3e-20,
},
carrier_density: n_dye,
peak_gain: 200.0, transparency_density: n_dye * 0.5,
};
let cavity = PlasmonicCavity {
mode_volume_nm3: v_nm3.max(1.0),
q_factor: q,
purcell_factor: fp,
resonance_wavelength: wavelength,
};
let g_th = gain_medium.net_gain_cm().abs() * 0.5;
Self {
plasmonic_cavity: cavity,
gain_medium,
threshold_gain: g_th.max(10.0),
}
}
pub fn new_nanodisk_spaser(radius_nm: f64) -> Self {
let wavelength = 700e-9;
let height_nm = radius_nm * 0.3;
let v_nm3 = PI * radius_nm.powi(2) * height_nm;
let q = 15.0;
let n_eff = 2.0;
let fp = PlasmonicCavity::compute_purcell(v_nm3.max(1.0), q, wavelength, n_eff);
let gain_medium = GainMedium {
material: GainMaterial::CdSe,
carrier_density: 1e25,
peak_gain: 500.0,
transparency_density: 5e24,
};
let cavity = PlasmonicCavity {
mode_volume_nm3: v_nm3.max(1.0),
q_factor: q,
purcell_factor: fp,
resonance_wavelength: wavelength,
};
Self {
plasmonic_cavity: cavity,
gain_medium,
threshold_gain: 100.0,
}
}
pub fn threshold_gain_per_cm(&self) -> f64 {
self.threshold_gain
}
pub fn stimulated_rate_enhanced(&self, photon_number: f64) -> f64 {
let tau_sp_s = 1e-9; let r_sp0 =
self.gain_medium.carrier_density * self.plasmonic_cavity.mode_volume_nm3 * 1e-27
/ tau_sp_s;
self.plasmonic_cavity.purcell_factor * photon_number * r_sp0
}
pub fn linewidth_nm(&self) -> f64 {
let alpha_h = 3.0_f64; let linewidth_base = self.plasmonic_cavity.linewidth_nm();
linewidth_base * (1.0_f64 + alpha_h * alpha_h).sqrt()
}
pub fn efficiency(&self) -> f64 {
let q_rad = self.plasmonic_cavity.q_factor * 0.05; q_rad / self.plasmonic_cavity.q_factor
}
}
#[derive(Debug, Clone)]
pub struct PhcNanolaser {
pub cavity: GeneralizedRateEquations,
pub q_factor: f64,
pub mode_volume_lambda3: f64,
pub beta_factor: f64,
pub purcell_factor: f64,
}
impl PhcNanolaser {
pub fn new_l3_inp(current_ua: f64) -> Self {
let wavelength = 1.3e-6_f64;
let n_eff = 3.17_f64;
let lambda_n_m = wavelength / n_eff;
let mode_vol_lambda3 = 0.7_f64;
let v_m3 = mode_vol_lambda3 * lambda_n_m.powi(3);
let q = 2500.0;
let fp = PlasmonicCavity::compute_purcell(v_m3 * 1e27, q, wavelength, n_eff).min(200.0);
let beta = (fp * 1e-2).clamp(0.05, 0.95);
let gre = GeneralizedRateEquations::new_nanolaser(current_ua * 1e3, beta, fp);
Self {
cavity: gre,
q_factor: q,
mode_volume_lambda3: mode_vol_lambda3,
beta_factor: beta,
purcell_factor: fp,
}
}
pub fn new_h0_gaas(current_ua: f64) -> Self {
let wavelength = 1.0e-6_f64; let n_eff = 3.5_f64;
let lambda_n_m = wavelength / n_eff;
let mode_vol_lambda3 = 0.02_f64;
let v_m3 = mode_vol_lambda3 * lambda_n_m.powi(3);
let q = 1000.0;
let fp = PlasmonicCavity::compute_purcell(v_m3 * 1e27, q, wavelength, n_eff).min(5000.0);
let beta = (fp * 1e-3).clamp(0.5, 0.999);
let gre = GeneralizedRateEquations::new_nanolaser(current_ua * 1e3, beta, fp);
Self {
cavity: gre,
q_factor: q,
mode_volume_lambda3: mode_vol_lambda3,
beta_factor: beta,
purcell_factor: fp,
}
}
pub fn threshold_current_na(&self) -> f64 {
self.cavity.threshold_current_ua() * 1e3 }
pub fn output_power_nw(&self, current_na: f64) -> f64 {
let current_ua = current_na * 1e-3;
let s = self.cavity.steady_state_photons(current_ua);
let h_planck = 6.626_070_15e-34;
let wavelength = 1.3e-6; let hnu = h_planck * C_LIGHT / wavelength;
let tau_ph_s = self.cavity.photon_lifetime_ps * 1e-12;
s * hnu / tau_ph_s * 1e9 }
pub fn thresholdless_parameter(&self) -> f64 {
self.beta_factor * self.purcell_factor
}
pub fn is_thresholdless(&self) -> bool {
self.thresholdless_parameter() > 1.0
}
}
#[derive(Debug, Clone)]
pub struct Vecsel {
pub active_diameter_mm: f64,
pub pump_power_w: f64,
pub pump_wavelength: f64,
pub signal_wavelength: f64,
pub n_quantum_wells: usize,
pub output_coupler_reflectivity: f64,
}
impl Vecsel {
pub fn new_1064nm(diameter_mm: f64, pump_w: f64) -> Self {
Self {
active_diameter_mm: diameter_mm,
pump_power_w: pump_w,
pump_wavelength: 808e-9, signal_wavelength: 1064e-9,
n_quantum_wells: 12,
output_coupler_reflectivity: 0.98,
}
}
pub fn conversion_efficiency(&self) -> f64 {
let quantum_defect = self.pump_wavelength / self.signal_wavelength;
let eta_abs = 0.9_f64;
let eta_slope = 0.8_f64;
let qw_factor = (self.n_quantum_wells as f64 / 10.0).min(1.0);
quantum_defect * eta_abs * eta_slope * qw_factor
}
pub fn output_power_w(&self) -> f64 {
self.pump_power_w * self.conversion_efficiency()
}
pub fn m_squared(&self) -> f64 {
let thermal_correction = (self.pump_power_w / 10.0) * 0.01;
(1.0 + thermal_correction).min(1.3)
}
pub fn saturation_fluence_uj_per_cm2(&self) -> f64 {
let h_planck = 6.626_070_15e-34;
let hnu = h_planck * C_LIGHT / self.signal_wavelength; let sigma_m2 = 1e-19; let nqw = self.n_quantum_wells as f64;
let f_sat_j_per_m2 = hnu / (sigma_m2 * nqw);
f_sat_j_per_m2 * 1e-4 * 1e6 }
pub fn round_trip_gain(&self) -> f64 {
let t_oc = 1.0 - self.output_coupler_reflectivity;
let eta = self.conversion_efficiency().max(1e-6);
(t_oc / eta).min(1.0) }
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_purcell_factor_increases_with_q() {
let fp_low = PlasmonicCavity::compute_purcell(1e4, 100.0, 1.3e-6, 3.4);
let fp_high = PlasmonicCavity::compute_purcell(1e4, 10000.0, 1.3e-6, 3.4);
assert!(
fp_high > fp_low,
"Higher Q should give higher Purcell factor"
);
}
#[test]
fn test_spaser_bowtie_threshold_finite() {
let spaser = Spaser::new_bowtie_spaser(20.0, 0.01);
let g_th = spaser.threshold_gain_per_cm();
assert!(
g_th.is_finite() && g_th > 0.0,
"Threshold gain should be positive finite: {}",
g_th
);
}
#[test]
fn test_spaser_efficiency_low() {
let spaser = Spaser::new_nanodisk_spaser(50.0);
let eff = spaser.efficiency();
assert!(eff < 0.1, "SPASER efficiency should be < 10%, got {}", eff);
}
#[test]
fn test_phc_nanolaser_l3_thresholdless() {
let laser = PhcNanolaser::new_l3_inp(1.0);
let param = laser.thresholdless_parameter();
assert!(
param.is_finite(),
"Thresholdless parameter should be finite"
);
let _ = laser.is_thresholdless();
}
#[test]
fn test_phc_nanolaser_h0_very_high_purcell() {
let laser = PhcNanolaser::new_h0_gaas(0.1);
assert!(laser.purcell_factor > 0.0);
let i_th_na = laser.threshold_current_na();
assert!(
i_th_na.is_finite() && i_th_na > 0.0,
"Threshold should be positive: {} nA",
i_th_na
);
}
#[test]
fn test_vecsel_output_power_positive() {
let v = Vecsel::new_1064nm(1.0, 5.0);
let p = v.output_power_w();
assert!(
p > 0.0 && p < 5.0,
"Output power should be between 0 and pump: {} W",
p
);
}
#[test]
fn test_vecsel_m_squared_near_unity() {
let v = Vecsel::new_1064nm(0.5, 1.0);
let m2 = v.m_squared();
assert!(
(1.0..=1.3).contains(&m2),
"M² should be ≥ 1 and near 1: {}",
m2
);
}
#[test]
fn test_gain_medium_net_gain_sign() {
let gm = GainMedium {
material: GainMaterial::InGaAsP,
carrier_density: 2e24,
peak_gain: 100.0,
transparency_density: 1e24,
};
let g = gm.net_gain_cm();
assert!(
g > 0.0,
"Net gain above transparency should be positive: {}",
g
);
}
}