feat(weak): FitWeak class + plotters (#524)#525
Merged
Conversation
Add a `FitWeak` class (`autolens/weak/fit.py`) that compares a model shear field — derived from a Tracer's mass profiles via the same `LensCalc.shear_yx_2d_via_hessian_from` primitive that `SimulatorShearYX` uses — against an observed `WeakDataset`. Exposes the standard fit interface: `model_shear`, `residual_map`, `chi_squared_map`, `chi_squared`, `noise_normalization`, `log_likelihood`, `figure_of_merit`. Each background galaxy contributes two independent measurements (gamma_1 and gamma_2 carry the same per-galaxy noise but are independent Gaussian draws), so chi-squared sums over N*2 elements and `noise_normalization` carries a factor of 2 to match. Add a matching plotter set (`autolens/weak/plot/fit_weak_plots.py`) with four helpers re-exported into the `aplt` namespace: - plot_data_vs_model -> data + model quivers overlaid (black + red alpha 0.6) - plot_residuals -> headless-quiver of the residual map, RdBu_r colormap - plot_chi_squared_map -> scalar scatter of per-galaxy chi-squared - subplot_fit_weak -> 2x2 mosaic `FitWeak` is standalone — not inheriting from `aa.AbstractFit`, matching the `FitPoint` precedent. The chi-squared / log-likelihood formulas verified against a direct numpy hand-computation in the test suite. Step 3 of the weak-lensing series (issue #524). 10 new tests, all green; existing 16 weak tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 19, 2026
Collaborator
Author
|
Workspace follow-up PR: PyAutoLabs/autolens_workspace#188 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 3 of the weak-lensing series. Adds a
FitWeakclass that compares a model shear field (derived from aTracer's mass profiles) against an observedWeakDataset, plus a matching set of fourapltplotters for visualising the fit.The model shear comes from
LensCalc.from_tracer(tracer).shear_yx_2d_via_hessian_from(grid=...)— the exact primitiveSimulatorShearYXuses. A noise-free round-trip is therefore bit-exact:residual_map ≈ 0for the truth tracer.Each background galaxy contributes two independent measurements (γ₁ and γ₂ share per-galaxy noise but are independent Gaussian draws), so
chi_squaredsums overN × 2elements andnoise_normalizationcarries a factor of 2 to match.API Changes
Pure additions. One new class (
autolens.weak.FitWeak) and four new module-level plot helpers (plot_data_vs_model,plot_residuals,plot_chi_squared_map,subplot_fit_weak), all re-exported intoautolens.plotand accessible at the top level asal.FitWeak. See full details below.Test Plan
pytest test_autolens/weak/ -v→ 26 passed (10 new + 16 existing dataset/simulator/plotter)python -c "import autolens as al; al.FitWeak"resolves without ImportErrorpython -c "import autolens.plot as aplt; aplt.subplot_fit_weak"resolves without ImportErrorgrep "^import jax\|^from jax" autolens/weak/fit.py autolens/weak/plot/fit_weak_plots.py→ empty (numpy-only)Full API Changes (for automation & release notes)
Added
New class
autolens.weak.fit.FitWeak(also reachable asal.FitWeak):FitWeak(dataset: WeakDataset, tracer: Tracer)@cached_property model_shear -> ShearYX2DIrregular@property residual_map -> np.ndarray(shape(N, 2))@property normalized_residual_map -> np.ndarray(shape(N, 2); residual / σ broadcast)@property chi_squared_map -> np.ndarray(shape(N, 2))@property chi_squared -> float(sum overN*2elements)@property noise_normalization -> float(2 * Σ log(2π σ²)— factor of 2 reflects independent γ₁/γ₂)@property log_likelihood -> float(-0.5 * (chi_squared + noise_normalization))@property figure_of_merit -> float(same aslog_likelihood— no inversion / no log_evidence)New module
autolens.weak.plot.fit_weak_plots, all re-exported intoautolens.plot(theapltnamespace):plot_data_vs_model(fit, ax=None, title="Data vs Model", output_path=None, output_filename="data_vs_model", output_format=None)— overlays the data shear field (black) and the model shear field (red, alpha 0.6) as headless quivers on a single axes.plot_residuals(fit, ax=None, title="Residuals", output_path=None, output_filename="residuals", output_format=None)— headless-quiver of the residual map, colour-coded by|residual|with theRdBu_rcolormap.plot_chi_squared_map(fit, ax=None, title=r"$\chi^2$ Map", output_path=None, output_filename="chi_squared_map", output_format=None)— scalar-coloured scatter of per-galaxy chi-squared (sum across γ₁/γ₂) viaautoarray.plot.grid.plot_gridwithcolormap="magma".subplot_fit_weak(fit, output_path=None, output_filename="subplot_fit_weak", output_format=None, title_prefix=None)— 2×2 mosaic: data | model | data-vs-model overlay | chi-squared.Migration
None required — additive change.
Design notes
aa.AbstractFit. That base is shaped for "data + noise_map + mask" pixel-grid fits and doesn't fit shear catalogues cleanly.FitPoint(inautolens.point) follows the same standalone pattern..ellipticities/.phisonly. The fit accesses raw(N, 2)storage but only via element-wise arithmetic (subtraction, division) which is component-symmetric — never raw[:, 0]/[:, 1]indexing.(N, 2)chi-squared shape. Each galaxy contributes two independent measurements. Reflected inchi_squared(sums all2Nelements) andnoise_normalization(factor of 2 over the(N,)noise array).🤖 Generated with Claude Code