use std::f64::consts::PI;
const C_LIGHT: f64 = 2.997_924_58e8;
#[derive(Debug, Clone)]
pub struct DbMirror {
pub n_high: f64,
pub n_low: f64,
pub n_pairs: usize,
pub center_wavelength_m: f64,
}
impl DbMirror {
pub fn reflectivity(&self) -> f64 {
let ratio = self.n_high / self.n_low;
let rho_2n = ratio.powi(2 * self.n_pairs as i32);
let r = ((rho_2n - 1.0) / (rho_2n + 1.0)).powi(2);
r.min(1.0)
}
pub fn penetration_depth_m(&self) -> f64 {
let dn = self.n_high - self.n_low;
if dn <= 0.0 {
return 0.0;
}
let l_pen_inf = self.center_wavelength_m / (4.0 * dn);
let n_eff = self.n_pairs as f64 * (self.n_high / self.n_low).ln();
l_pen_inf * n_eff.tanh()
}
pub fn photon_lifetime_s(&self, cavity_length_m: f64) -> f64 {
let r = self.reflectivity();
let t = 1.0 - r;
if t < f64::EPSILON {
return f64::INFINITY;
}
let l_eff = cavity_length_m + 2.0 * self.penetration_depth_m();
2.0 * l_eff / (C_LIGHT * t)
}
pub fn q_factor(&self, cavity_length_m: f64) -> f64 {
let omega_0 = 2.0 * PI * C_LIGHT / self.center_wavelength_m;
omega_0 * self.photon_lifetime_s(cavity_length_m)
}
pub fn stop_band_width_m(&self) -> f64 {
let ratio = (self.n_high - self.n_low) / (self.n_high + self.n_low);
let arcsin = ratio.clamp(-1.0, 1.0).asin();
(4.0 / PI) * arcsin * self.center_wavelength_m
}
pub fn high_layer_thickness_m(&self) -> f64 {
self.center_wavelength_m / (4.0 * self.n_high)
}
pub fn low_layer_thickness_m(&self) -> f64 {
self.center_wavelength_m / (4.0 * self.n_low)
}
}
#[derive(Debug, Clone)]
pub struct PlanarMicrocavity {
pub top_mirror: DbMirror,
pub bottom_mirror: DbMirror,
pub spacer_thickness_m: f64,
pub spacer_n: f64,
pub qw_positions: Vec<f64>,
}
impl PlanarMicrocavity {
pub fn cavity_wavelength_m(&self) -> f64 {
let l_eff = self.effective_length_m();
2.0 * self.spacer_n * l_eff
}
pub fn effective_length_m(&self) -> f64 {
self.spacer_thickness_m
+ self.top_mirror.penetration_depth_m()
+ self.bottom_mirror.penetration_depth_m()
}
pub fn finesse(&self) -> f64 {
let r_t = self.top_mirror.reflectivity();
let r_b = self.bottom_mirror.reflectivity();
let sqrt_r = (r_t * r_b).sqrt();
if (1.0 - sqrt_r).abs() < f64::EPSILON {
return f64::INFINITY;
}
PI * sqrt_r.sqrt() / (1.0 - sqrt_r)
}
pub fn mode_volume_m3(&self) -> f64 {
let lambda_n = self.top_mirror.center_wavelength_m / self.spacer_n;
let l_eff = self.effective_length_m();
lambda_n * lambda_n * l_eff
}
pub fn total_q(&self) -> f64 {
let lambda_c = self.top_mirror.center_wavelength_m;
let omega_0 = 2.0 * PI * C_LIGHT / lambda_c;
let r_t = self.top_mirror.reflectivity();
let r_b = self.bottom_mirror.reflectivity();
let t_eff = (1.0 - r_t + 1.0 - r_b) / 2.0;
if t_eff < f64::EPSILON {
return f64::INFINITY;
}
let l_eff = self.effective_length_m();
omega_0 * l_eff / (C_LIGHT * t_eff)
}
pub fn qw_field_enhancement(&self, qw_pos_fraction: f64) -> f64 {
let z_frac = qw_pos_fraction.clamp(0.0, 1.0);
(PI * z_frac).sin().powi(2)
}
pub fn total_qw_coupling_factor(&self) -> f64 {
self.qw_positions
.iter()
.map(|&z| self.qw_field_enhancement(z))
.sum()
}
pub fn photon_effective_mass_kg(&self) -> f64 {
const HBAR: f64 = 1.054_571_817e-34;
let omega_0 = 2.0 * PI * C_LIGHT / self.top_mirror.center_wavelength_m;
let l_eff = self.effective_length_m();
HBAR * omega_0 * self.spacer_n * self.spacer_n / (C_LIGHT * C_LIGHT)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn gaas_dbr_top() -> DbMirror {
DbMirror {
n_high: 3.6, n_low: 2.95, n_pairs: 25,
center_wavelength_m: 850e-9,
}
}
fn gaas_dbr_bot() -> DbMirror {
DbMirror {
n_high: 3.6,
n_low: 2.95,
n_pairs: 30, center_wavelength_m: 850e-9,
}
}
fn gaas_microcavity() -> PlanarMicrocavity {
let n_s = 3.6_f64;
let lambda_0 = 850e-9_f64;
let l_c = lambda_0 / (2.0 * n_s); PlanarMicrocavity {
top_mirror: gaas_dbr_top(),
bottom_mirror: gaas_dbr_bot(),
spacer_thickness_m: l_c,
spacer_n: n_s,
qw_positions: vec![0.5], }
}
#[test]
fn dbr_reflectivity_approaches_unity() {
let dbr = gaas_dbr_top();
let r = dbr.reflectivity();
assert!(r > 0.99, "25-pair GaAs/AlAs DBR should have R > 99%, got R={:.4}", r);
assert!(r <= 1.0, "Reflectivity cannot exceed 1, got {}", r);
}
#[test]
fn penetration_depth_positive() {
let dbr = gaas_dbr_top();
let l_pen = dbr.penetration_depth_m();
assert!(l_pen > 0.0 && l_pen.is_finite(), "Penetration depth should be finite positive, got {}", l_pen);
}
#[test]
fn stop_band_width_physical() {
let dbr = gaas_dbr_top();
let bw = dbr.stop_band_width_m();
assert!(bw > 20e-9 && bw < 200e-9, "Stop band width should be 20–200 nm, got {} nm", bw * 1e9);
}
#[test]
fn microcavity_finesse_high() {
let mc = gaas_microcavity();
let f = mc.finesse();
assert!(f > 100.0 && f.is_finite(), "GaAs microcavity finesse should be >100, got {}", f);
}
#[test]
fn qw_at_antinode_maximum_coupling() {
let mc = gaas_microcavity();
let eta_antinode = mc.qw_field_enhancement(0.5);
let eta_node = mc.qw_field_enhancement(0.0);
assert!((eta_antinode - 1.0).abs() < 1e-10, "Antinode enhancement should be 1, got {}", eta_antinode);
assert!(eta_node.abs() < 1e-10, "Node enhancement should be 0, got {}", eta_node);
}
#[test]
fn effective_length_larger_than_spacer() {
let mc = gaas_microcavity();
let l_eff = mc.effective_length_m();
assert!(l_eff > mc.spacer_thickness_m, "L_eff should exceed spacer thickness");
}
#[test]
fn total_q_positive_finite() {
let mc = gaas_microcavity();
let q = mc.total_q();
assert!(q > 0.0 && q.is_finite(), "Total Q should be finite positive, got {}", q);
assert!(q > 100.0 && q < 1e8, "GaAs microcavity Q out of range: {}", q);
}
#[test]
fn photon_effective_mass_small() {
let mc = gaas_microcavity();
let m_eff = mc.photon_effective_mass_kg();
const ME: f64 = 9.109_383_701_5e-31;
let ratio = m_eff / ME;
assert!(
ratio > 1e-7 && ratio < 1e-3,
"Photon effective mass fraction should be ~1e-5, got {:.2e}",
ratio
);
}
}