Skip to content

fix(thermo): stable kappa_dot/dkd_dloga gradient via n_H_0 rescaling - #20

Open
MinhMPA wants to merge 1 commit into
smsharma:mainfrom
MinhMPA:fix/kd-dloga-gradient
Open

fix(thermo): stable kappa_dot/dkd_dloga gradient via n_H_0 rescaling#20
MinhMPA wants to merge 1 commit into
smsharma:mainfrom
MinhMPA:fix/kd-dloga-gradient

Conversation

@MinhMPA

@MinhMPA MinhMPA commented May 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes an exploding-gradient bug in the `kappa_dot` spline path. During reverse-mode AD, the Friedmann-scan eigenvalue blows up ~10¹² × for typical `omega_b` perturbations.

Root cause: `kappa_dot ∝ n_H_0 ∝ omega_b / m_H`. The recombination solver builds a spline over a frozen tau grid. During `jax.grad`, JAX differentiates through both the spline evaluation and the frozen-grid construction simultaneously, producing an ill-conditioned Jacobian.

Fix: Rescale at the evaluation site so that traced `n_H_0` enters only as a ratio:
```python
_kd_safe = stop_gradient(kappa_dot) * (n_H_0 / stop_gradient(n_H_0))
```
Value is unchanged (ratio = 1 at evaluation point); gradient routes through the analytic rescaling factor, not the spline Jacobian.

Changes

  • `clax/thermodynamics.py`: `_kd_safe` rescaling in `dkd_dloga` computation
  • `tests/test_thermodynamics.py`: new `TestThermoGradients` — FD-vs-AD comparison for `kappa_dot`, `dkd_dloga`, `exp_m_kappa` at fiducial and off-fiducial cosmologies

Merge order (4-PR AD-correctness series)

  1. Merge this PR first (`fix/kd-dloga-gradient` → `main`)
  2. Merge PR-B (`feat/forward-mode-ad` → `main`) — independent, can be concurrent
  3. After this PR lands: retarget PR-C (`fix/thermo-remaining-gradients`) from this branch to `main`, then merge
  4. After all three land in `smsharma/clax:main`: merge PR-D (`MinhMPA/clax-pt: fix/ad-correctness-clax-pt` → `benchmark/clax-pt`)

Test plan

  • `pytest tests/test_thermodynamics.py -x -q` — all gradient tests GREEN
  • `pytest tests/ --fast -x -q` — smoke gate GREEN
  • Finite-difference oracle confirms `jax.grad` values

…ling

The Friedmann-scan accumulates a spurious d(a_grid[i])/d(omega_b) eigenvalue
product (~10^14 at loga=-8). The spline derivative's 1/h factor amplifies this
by ~1200x, causing AD to return ~10^17 instead of the physical ~-335.

Fix: stop all accumulated gradient in kappa_dot_grid, then restore only the
n_H_0 ∝ omega_b path (exact, since kappa_dot ∝ n_H_0 linearly):
  _kappa_dot_for_deriv = sg(kappa_dot_grid) * n_H_0 / sg(n_H_0)

Also adds dkappa_dot_dloga_of_loga to ThermoResult and the regression test
test_opacity_logderivative_gradient_matches_fd_for_omega_b (<1% vs FD).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant