B-mode validation¶
Cosmic shear is curl-free to leading order, so the B-mode (and EB) power spectra should be consistent with zero. cosmoTRON runs BB/EB null tests as a data-quality check on every spin-2 session. But a naive null test over-rejects: it fails on clean simulations that contain no real B-modes. This page explains why, and the three layers cosmoTRON uses to tell a benign artefact from a real contamination.
Why the naive null test lies¶
The B-mode null test compares the measured cls_BB_denoised against an analytic
Gaussian covariance Var(B_b) = 2·N_b² / (f_sky·Σ(2ℓ+1)), where N_b is the
modelled shot noise. Two things conspire:
- The shot-noise model is only a few % accurate. The analytic
noise_bias_bb(σ_e²/n_eff, propagated through the mask and pixel window) typically sits ~3–5 % below the true map noise. This shows up as a coherent, positiveBB_raw/N ≈ 1.03–1.05at high ℓ. - The covariance is far more precise than the noise model is accurate.
At high ℓ,
Σ(2ℓ+1)over a wide band is huge, so the error bar shrinks to < 1 % of the noise. A 4 % noise-model error judged against a 0.8 % error bar registers as a 5–7σ "detection".
On a masked sky there is a second, genuinely different failure mode: E→B leakage from the mask (see purification).
The cautionary tale (session ses_06ba)
A real run "explained" these false detections with a fabricated physics narrative — injected intrinsic alignments and line-of-sight projection — and the model self-authorised gate overrides. The mock contained no such physics. The layered system below exists to replace that narrative with deterministic numbers and to keep the human as the gate. See Determinism & no fabrication.
Layer 0: B-mode purification¶
On a cut sky the pseudo-Cℓ estimator mixes E-modes into B (the large EE signal
leaks into the null BB spectrum). cosmoTRON builds the spin-2 NaMaster field with
purify_b=True, which removes that leakage. On a masked run this suppresses the
leaked BB power by ~1–2 orders of magnitude while leaving EE unchanged.
- Pinned in
pipeline_configaspurify_b(defaultTrue). Set it in a task withpurify_b=falseto disable. - Auto-disabled on the full sky (uniform mask ⇒ purification is a no-op) and when the mask is not apodised.
- The mode-coupling-matrix cache key includes
purify_b, so a purified run can never reuse a non-purified matrix (or vice versa).
Purification removes the colored E→B-leakage failure mode. What remains is the white shot-noise-model residual — which Layer 1 classifies.
Layer 1: the deterministic discriminant (advisory)¶
diagnose_bmode_excess_from_session classifies a failing BB/EB null as a benign
noise-model residual versus a real, ℓ-dependent excess. It is cheap (reads the
per-bin auto-Cℓ JSONs, no catalogue) and advisory — it never changes the gate
PASS/FAIL and never touches the EE data covariance or SACC.
For each spin-2 bin and component it:
- Fits a single shot-noise amplitude
αat high ℓ only — the bands where the E-signal has died (EE_model/N_BB < bmode_highell_ee_frac), soBB_rawthere is pure noise andα = ⟨BB_raw/N⟩. - Re-runs the null with
N → α·Nand recordsp_origandp_rescaled. - Inspects the residual's ℓ-shape (fraction of χ² at low ℓ, correlation of the B-modes with the E-signal).
- Emits a verdict:
| verdict | meaning | condition |
|---|---|---|
BENIGN_NOISE_MODEL |
white shot-noise residual — the analytic covariance is over-precise | rescaled null passes, |α−1| ≤ bmode_rescale_alpha_max |
BENIGN_FLAG |
noise model badly off / possible white excess — surface it | rescaled null passes, |α−1| large |
COLORED_EXCESS |
ℓ-dependent excess survives the rescale — may be real | rescaled null still fails |
Fit α at high ℓ only — never all-band
An all-band α is dragged up by a genuine low-ℓ B-mode bump and would rescale
a real excess away. The high-ℓ fit keeps α ≈ 1 when there is real low-ℓ power,
so a COLORED_EXCESS survives.
The systematics gate runs the discriminant automatically and attaches its verdict,
α, and p_rescaled to each bmode_* check's detail.diagnosis — the human
override decision is then informed by numbers, not a story.
plot_bmode_diagnosis renders the B-modes against both the analytic and the
α-rescaled error bars, with the verdict annotated.
Config keys (in the session's systematics block):
bmode_rescale_alpha_max(default0.05) — the|α−1|cutoff forBENIGN_NOISE_MODEL.bmode_highell_ee_frac(default0.10) — theEE/N_BBratio defining the high-ℓ fit bands.
A non-detection here is not a proof of no contamination — it says "consistent
with a white shot-noise amplitude error." A COLORED_EXCESS (or a BENIGN_FLAG
you don't trust) escalates to Layer 2.
Layer 2: the random-rotation ensemble¶
run_bmode_rotation_ensemble_from_session measures the noise power and its
covariance empirically — the KiDS/DES/HSC method — rather than trusting the
analytic model. It randomly rotates the galaxy ellipticities and re-measures the
BB/EB pseudo-Cℓ many times. Rotation destroys the coherent shear signal but
preserves the shape-noise statistics exactly (|e| is rotation-invariant, and the
galaxy positions — hence the mask — are untouched), so the ensemble of rotated
spectra is the noise distribution.
- It is not a GLASS re-simulation — no lensing, no lognormal fields. Just rotate → re-grid → NaMaster, reusing the cached mode-coupling matrix across all rotations.
- It fans out into K parallel batch jobs — one job per batch of rotations, never one job per rotation. Default 100 rotations.
backend="slurm"routes the batches to a pinned remote site; the option is only offered when a site is registered.- Poll each returned
job_idwithcheck_job; once all aredone, callaggregate_bmode_ensemble_from_session. It builds the empirical mean (noise floor) and Hartlap-corrected covariance, subtracts the empirical noise from the data B-modes, and χ²-tests — the definitive verdict — writingcovariance_ensemble_{BB,EB}.jsonand merging the empirical p-values intobmode_diagnosis.json.
How the layers fit together¶
BB/EB null test (Layer 0 purified spectra)
│ FAIL
▼
diagnose_bmode_excess_from_session (Layer 1, deterministic, advisory)
│
├── BENIGN_NOISE_MODEL ─→ human may override the gate (cites α, p_rescaled)
├── BENIGN_FLAG ─────────┐
└── COLORED_EXCESS ──────┴─→ offer the rotation ensemble (Layer 2)
│ empirical covariance
▼
aggregate → definitive empirical null verdict
The gate stays a human decision throughout: @systematics_checker relays the
deterministic classification and the failing check's gate_id in its
NEEDS_INPUT line, and is forbidden from inventing a physical cause; only
@cosmotron can call
authorise_gate — and only behind a
runtime confirmation dialogue, never on an explicit human answer alone (an
argument-based override was tried and defeated twice; see
Human gates).