use crate::constants::physical::{C, G, HBAR};
use std::f64::consts::PI;
pub fn gw_energy_density_phase_transition(
alpha_pt: f64,
beta_over_h: f64,
t_star_gev: f64,
g_star: f64,
) -> f64 {
let h0 = 2.18e-18;
let kappa = alpha_pt / (1.0 + alpha_pt);
let omega_sw = 2.65e-6 * kappa * kappa * (100.0 / g_star).powf(1.0 / 3.0)
/ (beta_over_h * beta_over_h)
* (alpha_pt / (1.0 + alpha_pt)).powi(2)
* (t_star_gev / 100.0).powi(0);
omega_sw * h0 * h0
}
pub fn peak_frequency_phase_transition(beta_over_h: f64, t_star_gev: f64, g_star: f64) -> f64 {
1.9e-5 * beta_over_h * (t_star_gev / 100.0) * (g_star / 100.0).powf(1.0 / 6.0)
}
pub fn gw_spectrum_sound_waves(f_hz: f64, f_peak_hz: f64, omega_peak: f64) -> f64 {
let s = f_hz / f_peak_hz;
omega_peak * s.powi(3) * (7.0 / (4.0 + 3.0 * s * s)).powf(7.0 / 2.0)
}
pub fn gw_spectrum_bubble_collision(f_hz: f64, f_peak_hz: f64, omega_peak: f64) -> f64 {
let s = f_hz / f_peak_hz;
omega_peak * 3.8 * s.powi(2) * s / (2.8 * s * s + 1.0).powi(2)
}
pub fn gw_spectrum_turbulence(f_hz: f64, f_peak_hz: f64, omega_peak: f64) -> f64 {
let s = f_hz / f_peak_hz;
let h_star = f_peak_hz / 1e-5;
omega_peak * s.powi(3) / ((1.0 + s).powf(11.0 / 3.0) * (1.0 + 8.0 * PI * f_hz / h_star))
}
pub fn binary_gw_frequency_shift(f_gw_hz: f64, rho_dm_kg_m3: f64, r_orbit_m: f64) -> f64 {
let phi_dm = -4.0 / 3.0 * PI * G * rho_dm_kg_m3 * r_orbit_m * r_orbit_m;
f_gw_hz * phi_dm / (C * C)
}
pub fn dynamical_friction_gw_dephasing(
m1_solar: f64,
m2_solar: f64,
rho_dm_kg_m3: f64,
f_gw_hz: f64,
t_obs_s: f64,
) -> f64 {
let m1 = m1_solar * 1.989e30;
let m2 = m2_solar * 1.989e30;
let m_total = m1 + m2;
let mu = m1 * m2 / m_total;
let f_orb = f_gw_hz / 2.0;
let a = (G * m_total / (4.0 * PI * PI * f_orb * f_orb)).powf(1.0 / 3.0);
let v_orb = 2.0 * PI * a * f_orb;
let ln_lambda = 10.0;
let f_df = 4.0 * PI * G * G * m2 * rho_dm_kg_m3 * ln_lambda / (v_orb * v_orb);
let da_dt = -2.0 * a * f_df / (mu * v_orb);
let df_dt = -1.5 * f_orb * da_dt / a;
0.5 * df_dt * t_obs_s * t_obs_s * 2.0 * PI
}
pub fn spike_enhanced_gw_dephasing(
m_bh_solar: f64,
m_companion_solar: f64,
rho_spike_kg_m3: f64,
gamma_sp: f64,
f_gw_hz: f64,
t_obs_yr: f64,
) -> f64 {
let m_bh = m_bh_solar * 1.989e30;
let m_c = m_companion_solar * 1.989e30;
let m_t = m_bh + m_c;
let f_orb = f_gw_hz / 2.0;
let a = (G * m_t / (4.0 * PI * PI * f_orb * f_orb)).powf(1.0 / 3.0);
let v = 2.0 * PI * a * f_orb;
let ln_l = (a * v * v / (G * m_c)).ln().max(1.0);
let rho_at_a = rho_spike_kg_m3 * (a / 1e12).powf(-gamma_sp);
let f_df = 4.0 * PI * G * G * m_c * rho_at_a * ln_l / (v * v);
let t_obs = t_obs_yr * 3.156e7;
f_df * t_obs * t_obs / a * 2.0 * PI
}
pub fn gw_strain_from_dm_halo(
m_halo_solar: f64,
r_halo_kpc: f64,
f_hz: f64,
d_luminosity_mpc: f64,
) -> f64 {
let m = m_halo_solar * 1.989e30;
let r = r_halo_kpc * 3.0857e19;
let d = d_luminosity_mpc * 3.0857e22;
let omega = 2.0 * PI * f_hz;
let q = m * r * r * omega * omega;
2.0 * G * q / (C.powi(4) * d)
}
pub fn lisa_sensitivity_strain(f_hz: f64) -> f64 {
let f_star = 19.09e-3;
let s1 = 5.76e-48 * (1.0 + (0.4e-3 / f_hz).powi(2));
let s2 = 3.6e-41;
let r = 1.0 + (f_hz / 25e-3).powi(2);
let s_n = s1 / (2.0 * PI * f_hz).powi(4)
+ s2
+ s1 * (f_hz / f_star).powi(2) / (2.0 * PI * f_hz).powi(4);
(s_n * r).sqrt()
}
pub fn snr_stochastic_background(
omega_gw: f64,
f_min_hz: f64,
f_max_hz: f64,
t_obs_s: f64,
n_steps: usize,
) -> f64 {
let h0 = 2.18e-18;
let d_log_f = (f_max_hz / f_min_hz).ln() / n_steps as f64;
let mut snr2 = 0.0;
for i in 0..n_steps {
let log_f = f_min_hz.ln() + (i as f64 + 0.5) * d_log_f;
let f = log_f.exp();
let s_h = 3.0 * h0 * h0 * omega_gw / (2.0 * PI * PI * f * f * f);
let s_n = lisa_sensitivity_strain(f).powi(2);
if s_n > 0.0 {
snr2 += (s_h / s_n).powi(2) * f * d_log_f;
}
}
(2.0 * t_obs_s * snr2).sqrt()
}
pub fn gw_energy_from_dm_annihilation(
sigma_v_cm3_s: f64,
rho_dm_gev_cm3: f64,
m_dm_gev: f64,
fraction_to_gw: f64,
) -> f64 {
let n_dm = rho_dm_gev_cm3 / m_dm_gev;
let ann_rate = 0.5 * n_dm * n_dm * sigma_v_cm3_s;
let energy_per_ann = 2.0 * m_dm_gev * 1.602e-10;
ann_rate * energy_per_ann * fraction_to_gw
}
pub fn characteristic_strain(omega_gw: f64, f_hz: f64) -> f64 {
let h0 = 2.18e-18;
let h_c2 = 3.0 * h0 * h0 * omega_gw / (2.0 * PI * PI * f_hz * f_hz);
h_c2.sqrt()
}
pub fn gw_merger_rate_density(n_halo_mpc3: f64, merger_fraction: f64, t_delay_gyr: f64) -> f64 {
let t_delay_s = t_delay_gyr * 3.156e16;
let rate_per_vol = n_halo_mpc3 * merger_fraction;
rate_per_vol / t_delay_s
}
pub fn inspiral_chirp_mass(m1_solar: f64, m2_solar: f64) -> f64 {
let m1 = m1_solar * 1.989e30;
let m2 = m2_solar * 1.989e30;
let mc = (m1 * m2).powf(3.0 / 5.0) / (m1 + m2).powf(1.0 / 5.0);
mc / 1.989e30
}
pub fn inspiral_gw_strain(chirp_mass_solar: f64, f_gw_hz: f64, d_luminosity_mpc: f64) -> f64 {
let mc = chirp_mass_solar * 1.989e30;
let d = d_luminosity_mpc * 3.0857e22;
4.0 * (G * mc).powf(5.0 / 3.0) * (PI * f_gw_hz).powf(2.0 / 3.0) / (C.powi(4) * d)
}
pub fn graviton_energy(f_gw_hz: f64) -> f64 {
HBAR * 2.0 * PI * f_gw_hz
}
pub fn quantum_gw_detector_noise_floor(f_hz: f64, m_detector_kg: f64, l_arm_m: f64) -> f64 {
let omega = 2.0 * PI * f_hz;
(HBAR / (m_detector_kg * omega * l_arm_m * l_arm_m)).sqrt()
}