Skip to content

feat: weak-lensing fit class (FitWeak + plotter) — step 3 #524

@Jammy2211

Description

@Jammy2211

Overview

Step 3 of the weak gravitational lensing series. Steps 1–2 added the WeakDataset data class, SimulatorShearYX simulator and the aplt plotters for shear catalogues (PR #523 / autolens_workspace #186, shipped 2026-05-18). This task adds the fit layer — a FitWeak class that mirrors FitImaging, computes residuals/chi-squared/log-likelihood for a model shear field against an observed WeakDataset, and a FitWeak plotter set that overlays the model on the data via quiver.

Plan

  • Add autolens/weak/fit.py with a FitWeak class mirroring autolens/imaging/fit_imaging.py — same six-step pipeline pattern adapted for shear vectors (no PSF blur, no inversion; model shear computed directly from the tracer).
  • Compute model_shear via LensCalc.from_tracer(tracer).shear_yx_2d_via_hessian_from(grid=dataset.positions) (the exact primitive SimulatorShearYX uses), then derive residuals, chi-squared and log-likelihood in the standard -0.5 * (chi_squared + noise_normalization) form.
  • Add a FitWeak plotter set under autolens/weak/plot/fit_weak_plots.pyplot_data_vs_model (two quivers overlaid), plot_residuals, plot_chi_squared_map, subplot_fit_weak (2×2 mosaic). Re-export into the aplt namespace.
  • Add unit tests under test_autolens/weak/test_fit.py and test_autolens/weak/plot/test_fit_weak_plots.py. ~5× fewer tests than test_fit_imaging.py (no linear-light / pixelization variants).
  • Eyeball checkpoint after the first 3 test_fit.py tests, per the prompt.
Detailed implementation plan

Affected Repositories

  • PyAutoLens (primary — autolens/weak/fit.py + plotters + tests)
  • autolens_workspace (workspace follow-up — scripts/weak/fit.py example, after library ships)

Work Classification

Library, with workspace follow-up.

Branch Survey

Repository Current Branch Dirty?
PyAutoLens main clean
autolens_workspace main dirty (unrelated dataset/interferometer/simple/* regenerated artifacts; scripts/weak/ clean)

Suggested branch: feature/weak-fit
Worktree root: ~/Code/PyAutoLabs-wt/weak-fit/ (created later by /start_library)

Implementation Steps

  1. PyAutoLens/autolens/weak/fit.py mirroring autolens/imaging/fit_imaging.py:

    • class FitWeak taking (dataset, tracer).
    • @property model_shearLensCalc.from_tracer(tracer).shear_yx_2d_via_hessian_from(grid=dataset.positions).
    • @property residual_mapdataset.shear_yx - model_shear (operates on the underlying (N, 2) storage; the [:, 0]=γ₂, [:, 1]=γ₁ convention is component-symmetric for subtraction).
    • @property chi_squared_map → per-galaxy ((residual / noise_map) ** 2).sum(axis=-1) (sum across the γ₁, γ₂ components).
    • @property log_likelihood → standard -0.5 * (chi_squared + noise_normalization). No log_evidence (no inversion).
    • figure_of_merit returns log_likelihood.
  2. PyAutoLens/autolens/weak/plot/fit_weak_plots.py (lands on top of the new weak/plot/ package shipped in step 2):

    • plot_data_vs_model(fit, ax=None, ...) — two quivers overlaid: data (color="black") and model (color="red", alpha=0.6), both with the headless pivot="middle", headwidth=0, headlength=0, headaxislength=0 style established by plot_shear_yx_2d.
    • plot_residuals(fit, ax=None, ...) — quiver of residual_map colour-coded by |residual|.
    • plot_chi_squared_map(fit, ax=None, ...) — scalar-coloured scatter via autoarray.plot.grid.plot_grid (same pattern as plot_ellipticities).
    • subplot_fit_weak(fit, ...) — 2×2: data | model | overlay | chi-squared.
    • Wire all 4 into aplt via autolens/plot/__init__.py.
  3. Unit tests — PyAutoLens/test_autolens/weak/test_fit.py (~6 tests):

    • test__model_shear_matches_simulator_for_no_noiseSimulatorShearYX(noise_sigma=0.0) round-trip through FitWeak should give residual_map ≈ 0.
    • test__chi_squared_zero_for_perfect_fit.
    • test__log_likelihood_against_hand_computed (4-galaxy deterministic dataset, hand-computed expected value).
    • test__residual_map_shape ((n_galaxies, 2)).
    • test__log_likelihood_drops_for_wrong_model (perturb einstein_radius by 0.1, assert LL drops by ≥ 1).
    • test__pickle_round_trip (matches the viz-subprocess-feasibility precedent — FitWeak must round-trip cleanly for future JIT/subprocess viz).
  4. Plotter tests — PyAutoLens/test_autolens/weak/plot/test_fit_weak_plots.py (~4 tests, one per fn, using the plot_patch fixture).

  5. Eyeball checkpoint — after the first 3 test_fit.py tests, pause and present them for user review before writing the rest. Per the prompt: "Have me eyeball a few unit tests so I can see they make sense."

Key Files

  • New: PyAutoLens/autolens/weak/fit.py
  • New: PyAutoLens/autolens/weak/plot/fit_weak_plots.py
  • New: PyAutoLens/test_autolens/weak/test_fit.py
  • New: PyAutoLens/test_autolens/weak/plot/test_fit_weak_plots.py
  • Edit: PyAutoLens/autolens/weak/__init__.py — export FitWeak.
  • Edit: PyAutoLens/autolens/plot/__init__.py — add the 4 new plotter imports.

Reused utilities (no need to re-implement)

  • LensCalc.from_tracer(...).shear_yx_2d_via_hessian_from(grid=...)PyAutoGalaxy/autogalaxy/operate/lens_calc.py (the simulator's exact primitive).
  • WeakDataset.{positions, shear_yx, noise_map}PyAutoLens/autolens/weak/dataset.py:76.
  • aplt.plot_shear_yx_2d styling + subplot_save / tight_layout / conf_subplot_figsize from autoarray.plot.utils (shipped in step 2).
  • plot_patch fixture — test_autolens/conftest.py:27.

Verification

  1. pytest test_autolens/weak/ -v — all new tests pass alongside the 16 existing weak tests (5 plotter + 11 dataset/simulator).
  2. JAX cleanliness: grep "^import jax\|^from jax" PyAutoLens/autolens/weak/fit.py PyAutoLens/autolens/weak/plot/fit_weak_plots.py → empty.
  3. Workspace follow-up smoke (post-merge): python autolens_workspace/scripts/weak/fit.py runs end-to-end and writes the fit subplot PNG.
  4. Library-first merge gate: /ship_library first, then /ship_workspace.

Original Prompt

Click to expand starting prompt

We are now going to add weak lensing Fit class

First, we need to create the fit.py module, so inspect @autolens_workspace/scripts/weak and
@PyAutoLens/autolens/imaging/fit modules . We are basically going to make everything weak does from here a "mirror" of
the imaging model API (and also interferoter.)

So, set up a FitWeak module which compute the same key quantities as other Fit objects, such as residuals, chi
squared and log likelihood. Put unit tests in following the imaging unit test stucture, baring in mind there should
be far fewer as there are no variants like linear light profiles of pixelizations. Have me eyeball a few unit tests
so I can see they make sense.

In a second phase, inspect @PyAutoLens/autolens/plot and set up the FitWeak weak_plots.py, you may need to do
some research on how best to plot these quantities, it may be we want to plot the dataset values via quiver on top
of the model ones.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions