use std::f64::consts::PI;
const C: f64 = 299_792_458.0;
const HBAR: f64 = 1.054_571_817e-34;
#[derive(Debug, Clone)]
pub struct WgmMicroresonator {
pub radius: f64,
pub height: f64,
pub width: f64,
pub n_eff: f64,
pub wavelength: f64,
pub q_optical: f64,
pub q_mechanical: f64,
pub omega_mech: f64,
pub g0: f64,
}
impl WgmMicroresonator {
pub fn new(radius: f64, n_eff: f64, wavelength: f64) -> Self {
let omega_opt = 2.0 * PI * C / wavelength;
let g0 = omega_opt / radius;
Self {
radius,
height: 2e-6,
width: 2e-6,
n_eff,
wavelength,
q_optical: 1e7,
q_mechanical: 1e4,
omega_mech: 2.0 * PI * 10e6, g0,
}
}
pub fn optical_frequency(&self) -> f64 {
2.0 * PI * C / self.wavelength
}
pub fn free_spectral_range(&self) -> f64 {
C / (2.0 * PI * self.radius * self.n_eff)
}
pub fn optical_linewidth(&self) -> f64 {
self.optical_frequency() / self.q_optical
}
pub fn quality_factor_radiation(&self) -> f64 {
let phase_per_round = 2.0 * PI * self.n_eff * self.radius / self.wavelength;
let q_rad = (2.0 * phase_per_round).exp();
q_rad.min(self.q_optical * 10.0)
}
pub fn effective_mass(&self) -> f64 {
let rho_silica = 2_200.0; rho_silica * PI * self.radius * self.height * self.width
}
pub fn zero_point_motion(&self) -> f64 {
let m_eff = self.effective_mass();
(HBAR / (2.0 * m_eff * self.omega_mech)).sqrt()
}
pub fn optomechanical_coupling_rate(&self, n_photons: f64) -> f64 {
self.g0 * n_photons.max(0.0).sqrt()
}
pub fn sideband_resolution(&self) -> bool {
self.omega_mech > self.optical_linewidth() / 2.0
}
pub fn cooperativity(&self, n_photons: f64) -> f64 {
let kappa = self.optical_linewidth();
let gamma_m = self.omega_mech / self.q_mechanical;
let g = self.optomechanical_coupling_rate(n_photons);
4.0 * g * g / (kappa * gamma_m)
}
pub fn intracavity_photons(&self, p_in: f64, eta_c: f64) -> f64 {
let omega = self.optical_frequency();
let eta = eta_c.clamp(0.0, 1.0);
eta * p_in * self.q_optical / (HBAR * omega * omega)
}
pub fn optical_spring_shift(&self, n_photons: f64) -> f64 {
let kappa = self.optical_linewidth();
let g = self.optomechanical_coupling_rate(n_photons);
let omega_m = self.omega_mech;
g * g * omega_m / (omega_m * omega_m + (kappa / 2.0).powi(2))
}
pub fn optomechanical_damping_rate(&self, n_photons: f64) -> f64 {
let kappa = self.optical_linewidth();
let g = self.optomechanical_coupling_rate(n_photons);
let omega_m = self.omega_mech;
g * g * kappa / (omega_m * omega_m + (kappa / 2.0).powi(2))
}
}
#[derive(Debug, Clone)]
pub struct DiskResonator {
pub radius: f64,
pub thickness: f64,
pub n_eff: f64,
pub azimuthal_mode_number: usize,
}
impl DiskResonator {
pub fn new(radius: f64, thickness: f64, n_eff: f64, m: usize) -> Self {
Self {
radius,
thickness,
n_eff,
azimuthal_mode_number: m,
}
}
pub fn resonant_frequency(&self) -> f64 {
self.azimuthal_mode_number as f64 * C / (2.0 * PI * self.n_eff * self.radius)
}
pub fn resonant_wavelength(&self) -> f64 {
C / self.resonant_frequency()
}
pub fn free_spectral_range(&self) -> f64 {
C / (2.0 * PI * self.n_eff * self.radius)
}
pub fn coupling_gap_to_q(&self, gap: f64, wavelength: f64) -> f64 {
let n2_minus_1 = (self.n_eff * self.n_eff - 1.0).max(0.0);
if n2_minus_1 < f64::EPSILON {
return 1e3; }
let l_decay = wavelength / (4.0 * PI * n2_minus_1.sqrt());
let q0 = 1e5;
q0 * (gap / l_decay).exp()
}
pub fn mode_volume(&self) -> f64 {
let lambda_over_n = self.resonant_wavelength() / self.n_eff;
2.0 * PI * self.radius * lambda_over_n * lambda_over_n / (4.0 * self.n_eff)
}
pub fn purcell_factor(&self, q_factor: f64) -> f64 {
let lambda_m = self.resonant_wavelength();
let lambda_over_n = lambda_m / self.n_eff;
let v = self.mode_volume();
(3.0 / (4.0 * PI * PI)) * lambda_over_n.powi(3) / v * q_factor
}
pub fn mode_number_for_wavelength(radius: f64, n_eff: f64, target_wl: f64) -> usize {
let m_float = 2.0 * PI * n_eff * radius / target_wl;
m_float.round() as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
fn make_wgm() -> WgmMicroresonator {
WgmMicroresonator::new(50e-6, 1.44, 1550e-9)
}
#[test]
fn test_fsr_positive() {
let wgm = make_wgm();
let fsr = wgm.free_spectral_range();
assert!(
fsr > 1e11 && fsr < 1e13,
"FSR {fsr} Hz out of expected range"
);
let expected = C / (2.0 * PI * 50e-6 * 1.44);
assert_abs_diff_eq!(fsr, expected, epsilon = 1.0);
}
#[test]
fn test_zero_point_motion_finite() {
let wgm = make_wgm();
let xzpf = wgm.zero_point_motion();
assert!(xzpf > 0.0, "zero-point motion must be positive");
assert!(
xzpf < 1e-12,
"zero-point motion should be sub-pm for µm scale resonator"
);
}
#[test]
fn test_sideband_resolution() {
let wgm = make_wgm();
let _resolved = wgm.sideband_resolution();
}
#[test]
fn test_cooperativity_increases_with_photons() {
let wgm = make_wgm();
let c1 = wgm.cooperativity(1e3);
let c2 = wgm.cooperativity(1e6);
assert!(c2 > c1, "cooperativity should increase with photon number");
}
#[test]
fn test_optomechanical_coupling_rate_zero_photons() {
let wgm = make_wgm();
let g = wgm.optomechanical_coupling_rate(0.0);
assert_abs_diff_eq!(g, 0.0, epsilon = 1e-20);
}
#[test]
fn test_disk_resonant_frequency() {
let disk = DiskResonator::new(10e-6, 220e-9, 3.5, 30);
let freq = disk.resonant_frequency();
assert!(
freq > 1e13 && freq < 1e15,
"disk resonant frequency {freq} Hz out of expected range"
);
}
#[test]
fn test_disk_mode_volume_positive() {
let disk = DiskResonator::new(10e-6, 220e-9, 3.5, 30);
let v = disk.mode_volume();
assert!(v > 0.0, "mode volume must be positive");
}
#[test]
fn test_disk_fsr_matches_wgm() {
let disk = DiskResonator::new(50e-6, 2e-6, 1.44, 100);
let fsr = disk.free_spectral_range();
let wgm = WgmMicroresonator::new(50e-6, 1.44, 1550e-9);
let fsr_wgm = wgm.free_spectral_range();
assert_abs_diff_eq!(fsr, fsr_wgm, epsilon = 1.0);
}
#[test]
fn test_mode_number_for_wavelength() {
let m = DiskResonator::mode_number_for_wavelength(50e-6, 1.44, 1550e-9);
assert!(m > 200 && m < 400, "mode number {m} out of expected range");
}
#[test]
fn test_coupling_gap_to_q_increases_with_gap() {
let disk = DiskResonator::new(10e-6, 220e-9, 3.5, 30);
let q1 = disk.coupling_gap_to_q(100e-9, 1550e-9);
let q2 = disk.coupling_gap_to_q(200e-9, 1550e-9);
assert!(
q2 > q1,
"coupling Q should increase (weaker coupling) with larger gap"
);
}
#[test]
fn test_purcell_factor_positive() {
let disk = DiskResonator::new(10e-6, 220e-9, 3.5, 30);
let fp = disk.purcell_factor(1e5);
assert!(fp > 0.0, "Purcell factor must be positive");
}
}