Changelog
All notable changes to CosmoForge will be documented here.
Every pull request that touches package source updates this file; see
CLAUDE.md and the pull-request template.
Unreleased
Version 1.1.0 (2026-07-21)
The in-memory pipeline programme: every input can now be handed in as an array instead of a file path, and nothing is written to disk unless asked.
Breaking changes:
The default computation basis changed.
basis=None— the default — now resolves tomethod="auto"and the ADR-0003 cost selector picks harmonic or pixel-direct. Previously a bareFisher(config)silently used the traditional no-basis pixel path. Passbasis=Falseto restore that path; it also remains the only way to reach the pixel-space attribute surface (noise_cov1,inv_cov1,signal_matrix) and the ADR-0016 disk handoff. Scripts that used the bare constructor as a traditional reference are now comparing auto against auto (ADR-0018).compression=renamed tobasis=onFisher,Spectra, andPICSLike. The old name is accepted for one release and emits aDeprecationWarning; passing both raisesTypeError(ADR-0018).Persistence is opt-in. Every
out*default inInputParamsis nowNone, and providing a path is the save trigger. A bare config writes no files. The gate lives inside the four write primitives, so no call site can reintroduce implicit I/O. Configs that relied on the old default paths now silently write nothing (ADR-0015).do_crossnow defaults toFalse(wasTrue).calibrationandsmooth_polremoved fromInputParams. Thecalibration:YAML key stays recognised so it can refuse:1.0is accepted, anything else raisesValueError. Theread_maps(..., calibration=)kwarg is hard-cut — Python’s ownTypeErrornames it.nspectraremoved as a config key from all shipped and test YAMLs. It remains a derived attribute set bycompute_derived().threadpoolctldropped as a cosmocore dependency, along with the_wide_threadpool()context manager: raising OpenBLAS’s thread limit past its init-time size segfaults under the usualOMP_NUM_THREADS=1.The
main_fisher.py,main_qml.pyandmain_picslike.pyscripts are removed, superseded by the console scripts below. They were never installed — only reachable from a repository checkout — andmain_picslike.pyhad drifted out of sync withPICSLiketo the point of calling three methods that no longer exist. Replacepython main_qml.py cfg.yamlwithqube-run cfg.yaml,main_fisher.pywithqube-fisher-run, andmain_picslike.pywithpicslike-run.do_derivative_steploses itsnpixsandspinsparameters: the signature is now(S, spectrum, current_ell, fields). Both values were always overwritten fromfieldson entry, so no result changes — but a stale call raisesTypeErrorrather than being silently accepted. Removed outright rather than deprecated: they sat ahead of the required arguments, so any shim would have forced defaults ontocurrent_ell/fieldsand silently misbound new-style positional calls (ADR-0018).A spin-2 field’s two mask columns must now be identical. Masking Q differently from U is not representable — the V operator and the 2x2 Lambda blocks assume one pixel set per spin-2 field — and the previous code silently used the second column of the pair for both.
ValueErrorat mask resolution (ADR-0017).Bins.lbinrenamed toBins.lmid. The namelbinimplied an effective multipole, whichBinscannot know — it is only the bin midpoint.lbinsurvives one release as a property that returnslmidand emits aDeprecationWarning; uselmidfor the midpoint orFisher.get_effective_ells()for the effective multipole (ADR-0018, ADR-0019).Bins.bins(),Bins.bin_spectra()andBins.bin_covariance()removed. No production path used them, andbin_spectrareturned a flat bin average that silently disagrees with the Fisher-weighted bandpower the QML estimator produces — useSpectra.convolve_theory_for_inference()to bin theory (ADR-0007 amendment, ADR-0019).``output_convention=”Dl”`` is now an estimator setting, not a presentation one (ADR-0019). The flat-D_ℓ shape weight
w_ℓ = 2π/(ℓ(ℓ+1))enters the binned QML derivative, so the estimated bandpower, its covariance and the Fisher matrix come out asD_bnatively; the post-hocℓ(ℓ+1)/2πscalar evaluated at the bin midpoint is deleted. ExistingDlruns now return differentD_ℓ, covariance and Fisher — varying bin to bin, largest where bins are wide and ℓ is low — with no call site changed and, by design, no runtime warning; pin the previous release to reproduce prior numbers.Cloutput is unchanged.DlandClnow estimate genuinely different observables (D_output ≠ scalar · C_outputfor wide bins), sooutput_conventionmust be fixed beforerun()— flipping it on an already-run instance no longer rescales the output. Consequently the bandpower window (Fisher.get_bandpower_window_function) andSpectra.convolve_theory_for_inferencenow consume per-ℓ theory in the active convention: D_ℓ, not C_ℓ, in Dl mode. A likelihood that fed physical C_ℓ into a Dl window must convert to D_ℓ (× ℓ(ℓ+1)/2π) first.``Spectra.get_effective_ells()`` no longer returns the bin midpoint by default. It now returns the inverse-variance-weighted window centroid (delegated to
Fisher.get_effective_ells()), which requires a completed Fisher run and differs per spectrum. Passuse_midpoint=Truefor the old behaviour (the bin midpoint, no Fisher run). For a multi-spectrum run the default result is now shape(nspectra·nbins,)(spectrum-major), not(nbins,)(ADR-0019).
Added:
In-memory input injection (ADR-0017). Every pipeline input resolves through two adapters — a path in
InputParamsor an in-memory object on the constructor — and the injected object wins. Fixed kwarg vocabulary:mask,noise_cov1/noise_cov2,cls_data,fiducial_cls,beamonCoreand all three orchestration classes;maps1/maps2onSpectraandPICSLikeonly (Fishernever reads maps). An injected object is defined as exactly what the reader would have returned:maskis(npix,)or(npix, nfields),noise_covandmapsare reduced to active pixels, andcls_data/fiducial_clsmust be physical C_ℓ — theinput_conventionD_ℓ → C_ℓ conversion is applied only on the file path. File-based workflows are unchanged.In-memory Fisher → Spectra handoff (ADR-0016).
Spectra(fisher=…)aliases the live Fisher’s covariances instead of round-tripping N and C⁻¹ throughnp.fromfile. Theout*files remain a dormant read adapter.cosmocore.active_pixel_index(mask)andcosmocore.active_pixels(mask): the ordering of every reduced array (noise_cov1/2,maps1/2), as a pure function of the mask. Callers injecting those arrays no longer need to build aFisherto learn the active-pixel ordering (ADR-0017):index = active_pixel_index(mask) maps = maps_full.reshape(nfields * npix, nsims)[index] cov = cov_full[np.ix_(index, index)]
Console scripts. The pipelines are now installed entry points, on
PATHafter a plainpip installwith no repository checkout:qube-fisher-run(Fisher matrix only),qube-spectra-run(QML spectra end to end) with the aliasqube-run, andpicslike-run(pixel likelihood over the grid). They run unmodified under MPI, e.g.mpirun -n 8 qube-run config.yaml. The QUBE commands take an optional config path and fall back to the packagedTEB_defaults.yaml;picslike-runrequires one. Each warns when it finishes a run whose result is not being persisted, rather than exiting quietly (ADR-0015).in_memory_inputs.ipynbnotebook and tutorial page, driving the file and array adapters over the same data and asserting they agree.The demo notebooks now execute in CI (
test-notebooksjob, matrix over qube and picslike), asserting no files land on disk — the ADR-0015/0017 acceptance test.Multi-spectrum bandpower window.
Fisher.get_bandpower_window_function()no longer raises fornspectra > 1; it returns the block-structured window of shape(nspectra·n_bins, nspectra·n_ell)so TEB/TQU runs can convolve per-ℓ theory into expected bandpowers.Spectra.convolve_theory_for_inference()now accepts either a flat(nspectra·n_ell,)per-ℓ array (spectrum-major, matchingget_bandpower_slices) or a label-keyed dict{"TT": …, "EE": …}. Single-spectrum output is numerically unchanged.Bins.shape_weights(convention)returns the per-ℓ bandpower shape weightw_ℓthat declares the in-bin spectrum shape:1for the flat-C_ℓ shape ("Cl"),2π/(ℓ(ℓ+1))for the flat-D_ℓ shape ("Dl"). Requesting"Dl"when a bin includes ℓ = 0 raises, since D_ℓ is undefined at the monopole. This weight now feeds the binned QML derivative (see theoutput_conventionbreaking change above).Fisher.get_effective_ells(): the effective multipole per bin as the inverse-variance-weighted bandpower-window centroid, reported in the activeoutput_conventionand per spectrum. Returns shape(nspectra·nbins,)on rank 0,Noneon workers; it enters the collective per-ℓ Fisher on every rank (no worker early-return) and raises before a completed Fisher run (ADR-0019).Spectra.get_effective_ells(use_midpoint=False)delegates to it, withuse_midpoint=Truefor the bin midpoint.
Fixed:
read_maskhonoursparams.orderingvia an explicitnest=argument.healpy.read_map’s default previously force-converted to RING, silently producing wrong sky positions forordering="NESTED".Different temperature and polarisation masks no longer crash. Unequal active pixel counts across components raised
IndexErrorduring geometry setup — the standard configuration for a CMB analysis.With
spins=[2, 0](polarisation declared before temperature), the temperature field was given the polarisation mask’s sky positions, silently and with no error. Pointing vectors are now built per field.A transposed
(ncomponents, npix)mask is refused instead of silently reducing every array to the wrong pixels.On a harmonic basis, the consumers that need the pixel projector (
get_covariance,get_inverse,to_basis,projector, m-block compression and PICSLikedo_cross) now raise aRuntimeErrornaming the contract when called afterrelease_pixel_projector(), instead of an opaqueValueErrorfrom numpy.Evaluating the same parameter point twice on one
PICSLikeinstance no longer drifts. Beam smoothing multiplied the theory spectra in place, so each evaluation re-smoothed the parameter grid’s own arrays and chi-squared grew with every pass. Spectra handed toset_clsare now copied, which also means an injectedcls_data=array is no longer modified by the run that consumes it.A C_ℓ longer than the analysis
lmaxis truncated on the way in rather than failing to broadcast inside beam smoothing. Handing a full CAMB run to a small-lmaxanalysis is the normal case; only the dict form ofcls_datawas affected, the array form already truncated.Rebuilding the computation basis on a live
PICSLikeinstance no longer produces wrong chi-squared. The compressed-SMW path cached data projected through the previous basis and kept using it against the new one — silently, with no error.setup_computation_basis()now drops that cache, so the documentedsetup_computation_basis → setup_maps → computeorder is no longer the only safe one. The same staleness hit the MPI worker ranks on a second pipeline pass, where the cache outlived the broadcast that replaced the basis it came from; rank 0 stayed correct, so the disagreement was invisible.
Version 1.0.1 (2026-05-21)
Documentation-only patch release. Refreshes the long descriptions on PyPI
for cosmocore, qube-qml, and picslike so they reflect the
published companion paper and the current install path.
Documentation:
Paper I (Galloni & Pagano 2026,
arXiv:2605.21149) cited in all READMEs and inCITATION.cff. BibTeX entries gainedeprint/archivePrefix/primaryClassfields; the legacy"in preparation"notes are removed.CITATION.cffurl:field migrated from the retired GitHub Pages location to the canonical Read the Docs URL.cosmocore,qube-qml, andpicslikeREADMEs gained proper PyPI installation instructions (previously instructed users to clone the repository and runpip install -e); the MPI extra is now documented aspip install <package>[mpi]instead of a barepip install mpi4py.
Version 1.0.0 (2026-05-20)
First stable release. CosmoForge is now a public, paper-validated framework covering QML power spectrum estimation and pixel-space Gaussian likelihood evaluation for spin-0 and spin-2 fields on the sphere.
API stabilisation:
SpectrumKeytype system replaces the legacy(comp_i, comp_j, mode)tuple-based keying across cosmocore, qube, and picslike.SpectrumKindenumerates ordered slot pairs (SS,GG/CC/GC,SG/SC); CMB aliases (TT,EE,BB,EB,BE,TE, …) and theto_cmb_canonicalre-keying helper live incosmocore.conventions.cmb.Label-keyed user-facing accessors on
FisherandSpectra; legacy tuple-keyed inputs and tuple-rewrap shims removed.SymmetryModeflag onFisherandSpectra(SYMMETRICdefault,DIRECTIONALfor calibration diagnostics) controls how cross-component spin-2GC/CGblocks are handled; the directional path uses separateLambdaand derivative E matrices (ADR-0011).
Architecture:
ComputationBasispolymorphism convention closed (ADR-0002):prepare_for_basis/BasisPreparedcontract,quadratic_formabstract method, basis-seam leak inqube/spectra.pyclosed, single SMW-cross quadratic-form path.PixelBasisclass-model cleanup:use_directflag dropped (pixel-direct is the natural default when noepsilon/mode_fractionis passed);basiskwarg renamed tocompression_target;apply_compressioninternalised.Top-level
harmonic.py/pixel.pyrenamed to remove name collision with thebasis/subpackage.
Numerical stability:
Stable SMW rewrite in
qube/spectra.py(replaced the catastrophically-cancellation-proneM - M K^{-1} Mform withM (I + Lambda M)^{-1}); fixes high-SNR negativeVCVTand yields a ~5x speed-up in the multi-spectrum harmonic path.
Packaging:
mpi4pyis now an optional dependency (cosmocore[mpi],qube-qml[mpi],picslike[mpi]). CI runs the test matrix on both branches ofcosmocore._mpi.All remaining
np.linalg/scipy.linalgcall sites routed throughcosmocore.basicsfor consistency.
Validation:
End-to-end reproduction of the Planck low-\(\ell\) Fortran reference for both the QML and pixel-space likelihood pipelines, consistent with double-precision arithmetic.
Documentation:
Hosting migrated from GitHub Pages to Read the Docs.
Doc-drift sweep policy: at the end of every feature touching public surface, grep for renamed symbols, rebuild the Sphinx tree, and verify CONTEXT.md and per-package READMEs.
Tutorials refreshed for the SpectrumKey/SymmetryMode API and re-executed end-to-end at tier-A.
Installation guide reworked (developer install opt-in,
pymaster/namastertrap documented).CONTEXT.mdupdated with Slot, SpectrumKind, SpectrumKey, SymmetryMode.
Distribution:
Three independently pip-installable packages —
cosmocore(foundation),qube-qml(Fisher and QML estimation),picslike(pixel-space Gaussian likelihood) — plus thecosmoforgeumbrella metapackage that installs all three.