Skip to content

Additive-bias subtraction in calibration zeroes the signal on constant-shear sims (m = −1) #226

Description

@cailmdaley

Found while running the image-sim m-bias chain end-to-end (#225): the m-bias came back at m ≈ −1 (no shear response at all) even after the estimator itself was fixed. The cause is a calibration step that is correct for data and silently fatal for constant-shear simulations.

Mechanism (exact, not just empirical)

scripts/calibration/calibrate_comprehensive_cat.py builds the science shear via calibration.get_calibrated_m_c():

# get_calibrated_quantities: correct ensemble metacal
g_corr = np.linalg.inv(R).dot(g_uncorr)          # R = ensemble 2x2 (shear + selection)

# get_calibrated_m_c: additive-bias removal — the problem for sims
c = np.mean(g_uncorr[comp])                       # "additive bias" := mean uncalibrated shear
g_corr_mc = g_corr - np.linalg.inv(R).dot(c)      # subtracted from every object

The multiplicative step is right. But the additive step subtracts each catalogue's own mean — and since ⟨g_corr⟩ = R⁻¹⟨g_uncorr⟩ = R⁻¹c, we get ⟨g_corr_mc⟩ = 0 exactly, for every sim. For real data this is the intended additive-systematics removal (mean cosmic shear ≈ 0, so the mean is PSF leakage / additive bias). For a constant-shear sim the mean is the injected signal, so the subtraction deletes exactly what the m-bias measures: each of 1p2z/1m2z/1z2p/1z2m ends up with ⟨e⟩ = 0 by construction, the response is a difference of zeros, and m = −1.

Evidence (grid_1, 1 tile, inverse-variance weighted, paired estimator)

shear column response 1+m₁ response 1+m₂
e_uncal (raw) +0.84 +0.92
e = g_corr_mc (what the m-bias currently reads) +0.20 +0.02 ← signal gone
ensemble R⁻¹ on paired e_uncal, no additive step +1.14 → m₁ = +0.14 ± 0.10 +1.27 → m₂ = +0.27 ± 0.11

The last row is a hand-diagnostic using only the per-object R_g** columns (it omits the selection-response part of the ensemble R, a few-% term), so it's the cross-check that the pipeline is otherwise healthy — not the final number.

Possible fixes — design call needed, since this touches the shared calibration path

  1. Sim-mode flag (my leaning): an additive_correction: true/false knob on calibrate_comprehensive_cat.py, default true so the data path is provably unchanged; the image-sim mask config sets it false and the calibration writes g_corr (multiplicative-only) as e1/e2. Full ensemble R preserved; minimal diff.
  2. Always expose g_corr as extra columns (e1_mult_only/e2_mult_only); the sim m-bias reads those. Non-invasive but adds columns for everyone.
  3. The m-bias estimator applies R itself from e_uncal + R_g**. No shared-code change, but it can only apply the per-object shear response, not the global selection response — a good cross-check, not the final number.

Leaving the choice open — @-free ping via the PR thread. Note this finding is the image-sim gate working: it caught a real calibration/sim incompatibility before merge. Whether the data path's additive step is doing the right thing there is probably fine (mean shear ≈ 0 on data) but may deserve a look while we're here.

— Fable, on behalf of Cail

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions