pub struct DcbrCoupling<'a> {
pub emission_rates: &'a [f64],
pub n_eq_minus_n_pl: &'a [f64],
pub dem_drho_eq: &'a [f64],
pub dneq_drho_eq: &'a [f64],
pub photon_source: Option<&'a [f64]>,
pub cn_dcbr: bool,
}Expand description
DC/BR coupling data for implicit backward Euler within the Kompaneets step.
Instead of a precomputed frozen source dcbr_source[i] = (neq-Δn_old)(1-e^{-dτ·em}),
we pass the emission rates and equilibrium targets so DC/BR is solved implicitly
(backward Euler) inside the Newton iteration. This ensures DC/BR and Kompaneets
see the same evolving Δn, matching CosmoTherm’s approach.
Fields§
§emission_rates: &'a [f64]DC/BR absorption rates: R[i] = (K/x³)(e^{x_e}-1), capped at 1e8.
n_eq_minus_n_pl: &'a [f64]Equilibrium target: neq[i] = n_pl(x/ρ_eq) - n_pl(x).
dem_drho_eq: &'a [f64]Analytical derivative d(emission_rates)/d(ρ_eq) at the precomputed
ρ_eq. Used in the bordered Newton c-vector so the Δn-row Jacobian
reflects how the DC/BR absorption rate shifts when the Newton
updates the ρ_e iterate. Dominant term:
d(em)/d(ρ_eq) = -(K/x³) · exp(x/ρ_eq) · x/ρ_eq².
Pass None (empty slice) to retain the legacy Picard-in-ρ_e
behaviour, which is correct to O(Δρ_e per step) but only linearly
convergent at z ≳ 10⁶.
dneq_drho_eq: &'a [f64]Analytical derivative d(n_eq_minus_n_pl)/d(ρ_eq). Formula: d(neq)/d(ρ_eq) = n_pl(x/ρ_eq)(1 + n_pl(x/ρ_eq)) · x/ρ_eq².
photon_source: Option<&'a [f64]>Integrated photon source over the step: S_i = source_rate(x_i, z_mid)·dt.
When Some, the Newton residual picks up the −S_i term directly
rather than relying on the caller to pre-add S_i to Δn_old. This
avoids poisoning the Kompaneets CN “old” flux with the source (the
pre-add approach effectively treats the source as injected at
t_old, which over-Comptonises by roughly O(dt · ∂K/∂t) per step
during a narrow injection window). None preserves the legacy
pre-add caller code path.
cn_dcbr: boolUse Crank-Nicolson (instead of backward Euler) for DC/BR. Requires old-step DC/BR buffers in the workspace.