Skip to content

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:

  1. 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, positive BB_raw/N ≈ 1.03–1.05 at high ℓ.
  2. 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_config as purify_b (default True). Set it in a task with purify_b=false to 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:

  1. 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), so BB_raw there is pure noise and α = ⟨BB_raw/N⟩.
  2. Re-runs the null with N → α·N and records p_orig and p_rescaled.
  3. Inspects the residual's ℓ-shape (fraction of χ² at low ℓ, correlation of the B-modes with the E-signal).
  4. 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 (default 0.05) — the |α−1| cutoff for BENIGN_NOISE_MODEL.
  • bmode_highell_ee_frac (default 0.10) — the EE/N_BB ratio 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_id with check_job; once all are done, call aggregate_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 — writing covariance_ensemble_{BB,EB}.json and merging the empirical p-values into bmode_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).