Skip to content

feat(weak): FitWeak class + plotters (#524) - #525

Merged
Jammy2211 merged 1 commit into
mainfrom
feature/weak-fit
May 19, 2026
Merged

feat(weak): FitWeak class + plotters (#524)#525
Jammy2211 merged 1 commit into
mainfrom
feature/weak-fit

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Summary

Step 3 of the weak-lensing series. Adds a FitWeak class that compares a model shear field (derived from a Tracer's mass profiles) against an observed WeakDataset, plus a matching set of four aplt plotters for visualising the fit.

The model shear comes from LensCalc.from_tracer(tracer).shear_yx_2d_via_hessian_from(grid=...) — the exact primitive SimulatorShearYX uses. A noise-free round-trip is therefore bit-exact: residual_map ≈ 0 for the truth tracer.

Each background galaxy contributes two independent measurements (γ₁ and γ₂ share 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.

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 into autolens.plot and accessible at the top level as al.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 ImportError
  • python -c "import autolens.plot as aplt; aplt.subplot_fit_weak" resolves without ImportError
  • grep "^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 as al.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 over N*2 elements)
  • @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 as log_likelihood — no inversion / no log_evidence)

New module autolens.weak.plot.fit_weak_plots, all re-exported into autolens.plot (the aplt namespace):

  • 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 the RdBu_r colormap.
  • 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 γ₁/γ₂) via autoarray.plot.grid.plot_grid with colormap="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

  • Standalone class — not inheriting from aa.AbstractFit. That base is shaped for "data + noise_map + mask" pixel-grid fits and doesn't fit shear catalogues cleanly. FitPoint (in autolens.point) follows the same standalone pattern.
  • Storage convention preserved. Plotters access the shear field through .ellipticities / .phis only. 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 in chi_squared (sums all 2N elements) and noise_normalization (factor of 2 over the (N,) noise array).
  • Pure numpy. No JAX imports — JAX adoption is a separate ratchet for the whole weak-lensing module.

🤖 Generated with Claude Code

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>
@Jammy2211

Copy link
Copy Markdown
Collaborator Author

Workspace follow-up PR: PyAutoLabs/autolens_workspace#188

@Jammy2211
Jammy2211 merged commit 8feffe0 into main May 19, 2026
6 checks passed
@Jammy2211
Jammy2211 deleted the feature/weak-fit branch May 19, 2026 09:28
nataliehogg pushed a commit to nataliehogg/PyAutoLens that referenced this pull request Jun 3, 2026
Regression test for the failure mode that surfaced in PR PyAutoLabs#525 — al.from_json
on a serialised WeakDataset previously crashed with:

    TypeError: VectorYX2DIrregular.__init__() missing 1 required
    positional argument: 'values'

The library-side fix lives in PyAutoArray (a `values` property on
VectorYX2DIrregular). This test asserts the full simulator → write → load
path, including subclass preservation — loaded.shear_yx returns as
ShearYX2DIrregular, not the base class — plus matching shear values, grid
positions, and noise map.

Refs issue PyAutoLabs#554.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Jammy2211 Jammy2211 removed the pending-release PR queued for the next release build label Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant