Changelog
0.9.5 (2026-05-29)
New modules — simulation pipeline and GLASS mocks
sys_mapping.simulation— end-to-end validation framework for systematic contamination recovery. Providesinject_systematics()(per-galaxy contamination weights from the forward model, Eq. 11-13 of Berlfein et al. 2024),ContaminationConfig(9-point grid of level × scenario), FITS I/O helpers, andrun_wtheta_recovery()(runs all decontamination methods and compares recovered \(w(\theta)\) to truth).sys_mapping.glass_mocks— full-sky lognormal mock generation via GLASS (Tessore et al. 2023):generate_glass_fullsky_mock()andmeasure_nz(). Advantage over the existingmocks.make_mock_catalog: proper full-sky catalogs with physically realistic clustering, no galactic-cut artefacts.
Bug fixes (five pipeline bugs, all in regression / simulation / scripts)
Bug A — w(θ) correction applied to wrong sample.
run_wtheta_recoverywas multiplying the correction weight by the clean galaxy catalog instead of the contaminated one. The effective weight is now correctlyweight_cont × weight_recovered. Before this fix, the recovered \(w(\theta)\) was anti-contaminated — biased in the opposite direction from truth — producing residuals of order 10 000× the contamination bias.Bug B — bias metric blow-up at zero-crossings. The fractional-bias metric used a per-bin denominator
|w_true(θ)| + 1e-6. For shot-noise-dominated mocks (e.g. GLASS full-sky) where \(w_{\rm true} \sim 10^{-4}\), this produced artifacts of order \(10^6\). Fixed to scalarmax_θ|w_true(θ)|throughoutrun_simulation_tests.py,plot_simulation_tests.py, andrun_paper_validation.py.Bug C — unclipped OLS / MCMC correction weights.
_compute_weightsreturned values up to \(10^6\) for pixels where \(1 + \hat{a}\cdot t \to 0\). OLS and MCMC methods now clip to \([1/20,\, 20]\), matching the existing ISD and ElasticNet behaviour. Same fix applied inmethod_comparison(),run_mock_analysis_real_templates.py, andrun_mock_analysis_diagnostic.py.Bug D — MCMC-comb correction weight was a flawed approximation. The combined-model weight used \(1/(1+(a+b)\cdot t)\), which overcorrects by ~2× when the inferred \(\hat{b}\neq 0\) in a purely additive scenario (where \(b_{\rm true}=0\)). Replaced with the exact pixel-level inverse of the contamination model: \(w(p) = (1+\hat\delta_g^{\rm clean}(p))/(1+\delta_g^{\rm obs}(p))\) computed via
invert_contamination(). This cancelsweight_contexactly when parameters equal their true values.Bug E — MCMC walker initialisation too narrow; chain too short. Walkers were initialised at \(\mathcal{N}(0,\,10^{-3})\) — 20–100× narrower than the typical contamination amplitude (0.02–0.10). Changed to \(\mathcal{N}(0,\,0.05)\). Default
n_stepsraised from 600 to 1200;n_burnfrom 100 to 200.
Test suite
28 real-template integration tests (
tests/test_real_templates.py) now run instead of skipping: FITS files reside in~/data/legacysurvey/dr10/systematics/0032/, not the directory root.ElasticNet timing budget raised from 120 s to 600 s to accommodate CPU-only machines under load.
New tests:
tests/test_simulation.py(19 tests) andtests/test_glass_mocks.py(12 tests).
Deprecations / cleanup
Five scripts moved to
scripts/archive/:build_systematic_maps.py,generate_recommendations.py,generate_results_ls10_summary.py,generate_sample_pages.py,patch_params_from_partials.py. These were development utilities referenced only in the changelog.
Documentation
New results page
results_simulation_tests.rstcovering the full 3 × 3 contamination grid on GLASS and Uchuu mocks at NSIDE 32 and 64.New API pages
api/simulation.rstandapi/glass_mocks.rst.results_real_template_validation.rstupdated to reflect NSIDE = 64 footprint (22 641 pixels) and correct FITS file paths.All five documentation result pages regenerated with fresh figures from the fixed pipeline: mock analysis, systematic tests, validation, progressive contamination, real-template validation.
Package metadata
Version bumped to 0.9.5.
glass>=2026.1andcorrfuncadded as optional extras inpyproject.toml(pip install sys_mapping[glass],pip install sys_mapping[corrfunc]).
0.2.4 (2026-05-11)
ISD-3 speed and accuracy improvements:
Speed — normal equations replace per-iteration SVD.
iterative_systematics_decontaminationnow precomputesXt = X.Tonce outside the loop. Each iteration forms the weighted normal equations \((\mathbf{X}^\top \mathbf{W} \mathbf{X} + \mathbf{\Lambda})\hat{\boldsymbol\alpha} = \mathbf{X}^\top \mathbf{W} \hat{\boldsymbol\delta}_g\) via a single broadcast-scale + BLAS-3 matmul, then callslstsqon the resulting \((N_{\rm exp} \times N_{\rm exp})\) system (e.g. 55×55 for \(n_s=5, d=3\)) rather than on the full \((N_{\rm pix} \times N_{\rm exp})\) matrix. Measured speedup: 5–15× per iteration for \(N_{\rm pix} \gtrsim 10^4\).Accuracy — ridge penalty on polynomial-only columns. New
lambda_poly: float = 0.0parameter added toiterative_systematics_decontamination(). When positive it adds a diagonal ridge term \(\lambda_{\rm poly}\) to all polynomial expansion columns (indices \(n_s:\)) while leaving the \(n_s\) linear columns unpenalised. This prevents the polynomial cross-terms from absorbing signal that belongs to the linear coefficients — which are the only ones used in the weight update — resolving the fixed-point inconsistency that caused ISD-3 to converge to implausible solutions. Recommended value:1e-3 * np.var(delta_g_obs). Default0.0(backward-compatible).Interface.
run_decontamination()gainsisd_lambda_poly: float = 0.0, forwarded to both the pass-1 and pass-2 ISD calls.Documentation. Methods Reference ISD section rewritten to document the normal-equations formulation, the fixed-point inconsistency root cause, and the
lambda_polyparameter with its mathematical derivation.
0.2.3 (2026-05-06)
Pipeline refactoring — method-first execution:
New orchestration script
scripts/run_all_methods_sequential.shruns the LS10 BGS dataset for each fitting method in speed order: OLS (seconds) → ElasticNet (minutes) → MCMC-add (hours) → MCMC-comb (hours). Sphinx HTML docs are rebuilt after each method phase so intermediate results are immediately browsable.All four analysis scripts gain
--only-methods(restrict which methods run in a given invocation) and--force(ignore skip-if-done cache). The shell script exposesFORCE=1as an environment variable.Skip-if-done cache:
run_bin()andrun_sample()check for an existingresults_partial_{slug}.json(partial run) orresults.json(full run) at the start of each bin/sample and return immediately if found. Delete the file or pass--forceto recompute.Partial results JSON written after fast-method phases (OLS, ElasticNet, MCMC-add) — lightweight dict with
schema_version,methods_run,timestamp_utc,n_sys_*,syst_names,delta_g_std/skew, and per-method sub-dicts. The MCMC-comb phase merges these into the finalresults.json.Incremental RST updates via sentinel-comment protocol:
.. _auto-method-OLS-start:/.. _auto-method-OLS-end:markers are written toresults_ls10.rstafter each method phase; re-running replaces (not duplicates) the section.
Figures — consistent per-method color palette:
New module
sys_mapping/plotting.pywith sharedMETHOD_COLORS,METHOD_LINESTYLES,METHOD_MARKERS,METHOD_LABELS, andMETHOD_ORDERconstants exported from the package. The palette is Tableau-10-inspired and colorblind-safe: OLS (#4E79A7 steel blue), ElasticNet (#59A14F forest green), ISD-1 (#F28E2B amber), ISD-3 (#E15759 coral red), MCMC-add (#B07AA1 purple), MCMC-comb (#76B7B2 teal).run_ls10_analysis.py: 2PCF diagnostic plot updated to useMETHOD_COLORS.
0.2.2 (2026-05-06)
Bug fix (runtime):
scripts/run_mock_analysis_real_templates.py— both ISD blocks computednp.asarray(alpha_hat[-1])[:n_sys]instead ofnp.asarray(alpha_hat)[:n_sys].alpha_hatis a 1-D array of shape(n_expanded,);alpha_hat[-1]is a scalar, and slicing it raisesIndexError. The surroundingexcept Exceptionsilently swallowed the error, so ISD results were always missing from this script. Fixed by removing the erroneous[-1]index.Bug fix (consistency):
scripts/run_systematic_tests.py— ElasticNet discarded the weight map returned byelasticnet_contamination_fit()and applied additive correctionδ_obs − α̂·tinstead of weight-basedw(p)·(1+δ_obs)−1. Fixed to store the weights in the results dict so thatcorrected_delta()applies the paper-correct correction consistent withrun_validation.pyand Weaverdyck & Huterer (2020) Eq. 46-47.Consistency:
scripts/run_systematic_tests.py— OLS and MCMC-additive now also use weight-based correctionw(p) = 1/(1 + α̂·t(p)), making all six methods consistent with Weaverdyck & Huterer (2020) Eq. 46-47 and withrun_validation.py. The_compute_weights()helper is used directly.Documentation: re-ran
run_systematic_tests.py,run_validation.py,run_mock_analysis.py, andrun_mock_analysis_progressive.py; updated all result tables throughout the docs.
0.2.1 (2026-05-06)
Bug fix (performance):
iterative_systematics_decontaminationwas allocating an explicit(n_pix × n_pix)diagonal weight matrix vianp.diag(weights)at every iteration. For realistic pixel counts (NSIDE ≥ 64, n_pix ≳ 50 000) this consumed tens of GB and made each ISD iteration orders of magnitude slower than necessary. Fixed by replacingX.T @ np.diag(w)with the equivalent broadcastX.T * w[np.newaxis, :](regression.py).Bug fix (correctness): The
lstsqfallback path inside the ISD loop was scaling both sides byweightsinstead ofsqrt(weights), minimising \(\sum_p w(p)^2 (\delta - \alpha t)^2\) rather than the correct weighted least-squares objective \(\sum_p w(p)(\delta - \alpha t)^2\). Fixed by usingsw = sqrt(weights)on both the design matrix and the response (regression.py).Minor: moved
X = delta_t_expanded.Toutside the ISD iteration loop (it is constant across iterations).Validation: re-ran
scripts/run_validation.pyat NSIDE=32; all ISD metrics are numerically identical to the pre-fix run (the bugs affected performance, not output for the converging cases in the validation suite). ElasticNet results added to all scenario tables indocs/results_validation.rst.
0.2.0 (2026-05-05)
Scripts: converted all notebook-based analyses to standalone Python scripts in
scripts/(build_systematic_maps, run_paper_validation, run_ls10_analysis, run_mock_analysis).Execution: added SLURM job templates in
slurm/and nohup bash wrappers inbash/for 32-core server execution.Bug fix: corrected template 2PCF estimator and covariance propagation (commit
10c01d0); all prior results should be regenerated.Environment: switched from conda to mamba (
$HOME/miniforge3/envs/sys_map).Notebooks: deprecated executed/bloated notebooks moved to
notebooks/deprecated/; clean versions kept for interactive exploration.Corrfunc: added
measure_two_point_function_corrfuncutility and benchmarking scriptscripts/benchmark_corrfunc_vs_treecorr.py.
0.1.0 (2026-04-23)
Initial release.
Joint inference of additive and multiplicative systematics via JAX JIT-compiled likelihoods.
emcee MCMC backend (250 walkers, 1500 steps).
Noise debiasing (Eq. 21) and two-point function correction (Eq. 15-16).
PCA template rotation (Appendix A).
Likelihood ratio model selection (Eq. 19).
Block bootstrap variance estimation (Sec. 6.2).
Five HEALPix systematic template families (Sec. 4.2).
TreeCorr Landy-Szalay two-point function measurement.