Multi-spectrum bandpower window function - #53
Conversation
Lift the single-spectrum guard on Fisher.get_bandpower_window_function so TEB/TQU runs can convolve per-ℓ theory into expected bandpowers. Both the binned Fisher and the per-ℓ Fisher are block-ordered spectrum-major, so Q becomes block-diagonal (np.kron with the identity) and is bit-identical to the previous Q when nspectra == 1. The window is now (nspectra·n_bins, nspectra·n_ell). Spectra.convolve_theory_for_inference accepts either a flat spectrum-major per-ℓ array or a label-keyed dict; the spectrum-label ordering is factored into a shared _spectrum_labels() helper reused by _make_convolve_theory. Prerequisite for the bandpower-shape / effective-ell work (ADR-0019), whose effective multipoles differ per spectrum and so cannot be served for TEB without this. Closes #49
There was a problem hiding this comment.
Pull request overview
This PR extends CosmoForge’s QML inference utilities to support multi-spectrum (e.g., TEB/TQU) workflows when mapping per-ℓ theory to expected binned bandpowers. It removes the prior single-spectrum limitation by making the bandpower window function and the per-ℓ theory convolution operate on spectrum-major, block-ordered flattened vectors (or a label-keyed dict), which is a prerequisite for ADR-0019 follow-on work (effective multipoles per spectrum).
Changes:
- Generalizes
Fisher.get_bandpower_window_function()to return a(nspectra·n_bins, nspectra·n_ell)window fornspectra > 1using a block-diagonal sum-over-ℓ operator. - Extends
Spectra.convolve_theory_for_inference()to accept either a flat(nspectra·n_ell,)spectrum-major vector or a label-keyed dict of per-ℓ theory arrays. - Adds multi-spectrum tests validating window shape/linearity/normalization and dict-vs-flat convolution equivalence, and updates docs + changelog accordingly.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/cosmoforge.qube/qube/fisher.py |
Lifts the single-spectrum guard and builds a block-diagonal Q so the bandpower window supports nspectra > 1. |
src/cosmoforge.qube/qube/spectra.py |
Adds spectrum-label resolution helper and extends per-ℓ theory convolution to accept multi-spectrum flat vectors or label-keyed dicts. |
src/cosmoforge.qube/tests/test_binning.py |
Adds multi-spectrum unit tests for the bandpower window function and dict-input convolution path. |
docs/source/tutorials/basic_usage.rst |
Updates tutorial guidance to reflect multi-spectrum support in convolve_theory_for_inference(). |
docs/source/changelog.rst |
Adds an Unreleased changelog entry describing the new multi-spectrum window + theory-convolution inputs. |
| cl_theory : np.ndarray or dict | ||
| Per-ℓ theory C_ℓ. Accepted formats: |
There was a problem hiding this comment.
Fixed in 79580ce — parameter annotated np.ndarray | dict.
| def _to_perell(arr: np.ndarray, what: str) -> np.ndarray: | ||
| """Trim one per-ℓ array to ℓ=lmin..lmax (accepts n_ell or lmax+1).""" | ||
| if arr.size == n_ell: | ||
| return arr | ||
| if arr.size >= lmax + 1: | ||
| return arr[lmin : lmax + 1] |
There was a problem hiding this comment.
Fixed in 79580ce — added an ndim != 1 guard in _to_perell so a size-matching 2D entry (e.g. (n_ell, 1)) raises early; covered by test_convolve_theory_dict_rejects_2d_entry.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #53 +/- ##
=========================================
Coverage ? 92.14%
=========================================
Files ? 5
Lines ? 1082
Branches ? 0
=========================================
Hits ? 997
Misses ? 85
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Annotate the parameter as np.ndarray | dict to match the accepted forms, and reject non-1D per-ℓ arrays inside the dict path: a (n_ell, 1) entry whose size matches would previously slip past the size check and corrupt the spectrum-major concatenation. The ndim guard lives in _to_perell so every array routed through it is covered.
What changed
Lifts the single-spectrum restriction on
Fisher.get_bandpower_window_functionso multi-spectrum (TEB/TQU) runs can convolve per-ℓ theory into expected bandpowers. Both the binned Fisher and the per-ℓ Fisher are block-ordered spectrum-major, so the sum-over-ℓ operatorQbecomes block-diagonal (np.kronwith the identity) — bit-identical to the previousQwhennspectra == 1. This is the prerequisite for the bandpower-shape / effective-ell work (ADR-0019), whose effective multipoles differ per spectrum and therefore cannot be served for TEB without it.Public surface
Fisher.get_bandpower_window_function()no longer raisesNotImplementedErrorfornspectra > 1; returns a window of shape(nspectra·n_bins, nspectra·n_ell)(was(n_bins, n_ell), still that for a single spectrum). Rows/cols are block-ordered spectrum-major, matchingget_bandpower_slices.Spectra.convolve_theory_for_inference()now accepts a flat(nspectra·n_ell,)per-ℓ array or a label-keyed dict{"TT": …, "EE": …}of per-ℓ theory. Single-spectrum output is numerically unchanged.Checklist
docs/source/changelog.rstupdated under Unreleased (Added).CONTEXT.mdupdated if this introduces or sharpens a domain term — no new term.basic_usage.rstno longer calls the method single-spectrum-only; sphinx build clean (no new warnings).uv run pytest src/cosmoforge.qube/tests/ -s→ 178 passed, 8 skipped).