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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions