use std::f64::consts::PI;
use crate::units::conversion::{EPSILON_0, SPEED_OF_LIGHT};
#[derive(Debug, Clone)]
pub struct PhCNonlinearEnhancement {
pub group_index: f64,
pub mode_volume: f64,
pub n2_bulk: f64,
pub chi2_bulk: f64,
}
impl PhCNonlinearEnhancement {
pub fn new(ng: f64, mode_volume: f64, n2: f64) -> Self {
Self {
group_index: ng.max(1.0),
mode_volume: mode_volume.max(1e-30),
n2_bulk: n2,
chi2_bulk: 0.0,
}
}
pub fn with_chi2(mut self, chi2: f64) -> Self {
self.chi2_bulk = chi2;
self
}
pub fn effective_n2(&self) -> f64 {
let n_bg = 3.476_f64;
let s_slow = (self.group_index / n_bg).powi(2);
self.n2_bulk * s_slow
}
pub fn self_phase_modulation_coeff(&self, wavelength: f64) -> f64 {
let omega = 2.0 * PI * SPEED_OF_LIGHT / wavelength.max(1e-20);
let a_eff = self.mode_volume.powf(2.0 / 3.0);
let n2_eff = self.effective_n2();
omega * n2_eff / (SPEED_OF_LIGHT * a_eff)
}
pub fn chi2_enhancement_factor(&self) -> f64 {
let n_bg = 3.476_f64;
(self.group_index / n_bg).powf(1.5)
}
pub fn optical_bistability_threshold(&self, cavity_q: f64, wavelength: f64) -> f64 {
let omega = 2.0 * PI * SPEED_OF_LIGHT / wavelength.max(1e-20);
let n2_eff = self.effective_n2();
if n2_eff.abs() < 1e-40 || cavity_q < 1.0 {
return f64::INFINITY;
}
let n_bg = 3.476_f64;
EPSILON_0 * n_bg * n_bg * SPEED_OF_LIGHT * omega * self.mode_volume
/ (2.0 * n2_eff * cavity_q * cavity_q)
}
pub fn fwm_phase_matching_detuning(&self) -> f64 {
let wavelength = 1550e-9;
let omega = 2.0 * PI * SPEED_OF_LIGHT / wavelength;
let gamma = self.self_phase_modulation_coeff(wavelength);
let beta2 = self.group_index.powi(2) / (SPEED_OF_LIGHT * omega);
if beta2.abs() < 1e-30 || gamma.abs() < 1e-30 {
return 0.0;
}
(2.0 * gamma / beta2.abs()).sqrt()
}
}
#[derive(Debug, Clone)]
pub struct SlowLightShg {
pub l1: f64,
pub ng1: f64,
pub ng2: f64,
pub chi2: f64,
pub a_eff: f64,
}
impl SlowLightShg {
pub fn new(length: f64, ng1: f64, ng2: f64, chi2: f64, a_eff: f64) -> Self {
Self {
l1: length.max(0.0),
ng1: ng1.max(1.0),
ng2: ng2.max(1.0),
chi2,
a_eff: a_eff.max(1e-20),
}
}
fn d_eff_enhanced(&self) -> f64 {
let n_bg = 3.476_f64;
let f_slow = (self.ng1 * self.ng2).sqrt() / n_bg;
(self.chi2 / 2.0) * f_slow
}
pub fn phase_mismatch(&self) -> f64 {
let lambda_fund = 1550e-9;
let omega = 2.0 * PI * SPEED_OF_LIGHT / lambda_fund;
2.0 * omega / SPEED_OF_LIGHT * (self.ng2 - self.ng1).abs()
}
pub fn coherence_length(&self) -> f64 {
let dk = self.phase_mismatch();
if dk < 1e-10 {
return f64::INFINITY;
}
PI / dk
}
pub fn conversion_efficiency(&self, pump_power: f64, wavelength: f64) -> f64 {
let _omega = 2.0 * PI * SPEED_OF_LIGHT / wavelength.max(1e-20);
let d_eff = self.d_eff_enhanced();
let dk = self.phase_mismatch();
let n_eff = 3.476_f64;
let arg = dk * self.l1 / 2.0;
let sinc_sq = if arg.abs() < 1e-10 {
1.0
} else {
(arg.sin() / arg).powi(2)
};
let num = 8.0 * PI * PI * d_eff * d_eff * self.l1 * self.l1;
let den = EPSILON_0 * n_eff.powi(3) * SPEED_OF_LIGHT * wavelength * wavelength * self.a_eff;
if den.abs() < 1e-60 {
return 0.0;
}
let eta_norm = num / den * sinc_sq;
(eta_norm * pump_power).clamp(0.0, 1.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
fn si_kerr() -> PhCNonlinearEnhancement {
let lambda = 1550e-9_f64;
let n = 3.476_f64;
let v_eff = 0.7 * (lambda / n).powi(3);
PhCNonlinearEnhancement::new(30.0, v_eff, 6e-18)
}
#[test]
fn effective_n2_larger_than_bulk() {
let enh = si_kerr();
assert!(enh.effective_n2() > enh.n2_bulk);
}
#[test]
fn spm_coeff_positive() {
let enh = si_kerr();
let gamma = enh.self_phase_modulation_coeff(1550e-9);
assert!(gamma > 0.0, "γ = {gamma}");
}
#[test]
fn chi2_enhancement_factor_greater_than_one_for_slow_light() {
let enh = si_kerr();
let f = enh.chi2_enhancement_factor();
assert!(f > 1.0, "enhancement = {f:.3}");
}
#[test]
fn bistability_threshold_finite_for_high_q() {
let enh = si_kerr();
let p_th = enh.optical_bistability_threshold(1e5, 1550e-9);
assert!(p_th.is_finite(), "P_th = {p_th}");
assert!(p_th > 0.0, "P_th must be positive, got {p_th}");
}
#[test]
fn bistability_threshold_decreases_with_higher_q() {
let enh = si_kerr();
let p_low_q = enh.optical_bistability_threshold(1e4, 1550e-9);
let p_high_q = enh.optical_bistability_threshold(1e5, 1550e-9);
assert!(
p_high_q < p_low_q,
"p_high_q={p_high_q} < p_low_q={p_low_q}"
);
}
#[test]
fn fwm_detuning_positive() {
let enh = si_kerr();
let omega_pm = enh.fwm_phase_matching_detuning();
assert!(omega_pm >= 0.0, "Ω_pm = {omega_pm}");
}
#[test]
fn effective_n2_scales_with_ng_squared() {
let v = 1e-21_f64;
let enh1 = PhCNonlinearEnhancement::new(10.0, v, 6e-18);
let enh2 = PhCNonlinearEnhancement::new(20.0, v, 6e-18);
let ratio = enh2.effective_n2() / enh1.effective_n2();
assert_abs_diff_eq!(ratio, 4.0, epsilon = 0.01);
}
fn example_shg() -> SlowLightShg {
SlowLightShg::new(1e-3, 5.0, 8.0, 3e-11, 1e-12)
}
#[test]
fn shg_phase_mismatch_positive() {
let shg = example_shg();
assert!(shg.phase_mismatch() > 0.0);
}
#[test]
fn shg_coherence_length_positive_and_finite() {
let shg = example_shg();
let lc = shg.coherence_length();
assert!(lc > 0.0 && lc.is_finite(), "L_c = {lc}");
}
#[test]
fn shg_efficiency_between_zero_and_one() {
let shg = example_shg();
let eta = shg.conversion_efficiency(1.0, 1550e-9);
assert!((0.0..=1.0).contains(&eta), "η = {eta}");
}
#[test]
fn shg_perfect_phase_match_higher_efficiency() {
let shg_pm = SlowLightShg::new(1e-3, 5.0, 5.0, 3e-11, 1e-12);
let shg_mm = SlowLightShg::new(1e-3, 5.0, 8.0, 3e-11, 1e-12);
let eta_pm = shg_pm.conversion_efficiency(1.0, 1550e-9);
let eta_mm = shg_mm.conversion_efficiency(1.0, 1550e-9);
assert!(
eta_pm >= eta_mm,
"phase-matched η={eta_pm} should ≥ mismatched η={eta_mm}"
);
}
#[test]
fn shg_d_eff_enhanced_positive_for_nonzero_chi2() {
let shg = example_shg();
let d_eff = shg.d_eff_enhanced();
assert!(d_eff > 0.0, "d_eff = {d_eff}");
}
}