Overview
Step 4 of the weak-lensing series (PyAutoMind/z_features/weak_shear.md): add al.AnalysisWeak so a non-linear search can fit lens mass models to a WeakDataset shear catalogue, mirroring the established model API of imaging/point, plus a workspace scripts/weak/modeling.py tutorial. This is the keystone of the weak-lensing home-straight push — series steps 5 (likelihood_function), 7 (Abell 2744 real data) and 8 (combined strong+weak via summed analyses) all depend on it.
Science scope: cluster/group-scale weak shear complementing strong lensing (Niemiec et al. 2020 hybrid-Lenstool; Oguri et al. 2012 SGAS) — not cosmic shear or galaxy-galaxy lensing.
Plan
- Add
autolens/weak/model/ mirroring autolens/point/model/ (the right template — FitWeak already follows FitPoint's standalone pattern): AnalysisWeak, ResultWeak, VisualizerWeak, PlotterWeak.
AnalysisWeak.log_likelihood_function builds a Tracer from the model instance and returns FitWeak(dataset, tracer).log_likelihood.
- Wire on-the-fly visualization through the existing nine weak plotters (
subplot_weak_dataset, subplot_fit_weak, subplot_fit_quick), with new weak_dataset / fit_weak sections in the packaged config/visualize/plots.yaml.
- Export
al.AnalysisWeak in autolens/__init__.py; NumPy-only unit tests mirroring test_autolens/point/model/.
- Ship library PR first; workspace follow-up adds
scripts/weak/modeling.py (judgment-tier tutorial prose, style of scripts/imaging/modeling.py) and mirrors the new plots.yaml keys into workspace config.
Detailed implementation plan
Affected Repositories
- PyAutoLens (primary — library)
- autolens_workspace (follow-up — workspace tutorial + config mirror)
Branch Survey
| Repository |
Current Branch |
Dirty? |
| ./PyAutoLens |
main |
clean |
| ./autolens_workspace |
main |
dirty (7 pre-existing regenerated dataset files + stray dataset.fits, unrelated to this task) |
Suggested branch: feature/weak-modeling
Worktree: ~/Code/PyAutoLabs-wt/weak-modeling/
Note: autolens_workspace is currently claimed by task lenstool-example. Library work proceeds first (combined workflow); the workspace follow-up uses the parallel-worktree pattern proven twice in this series (scripts/weak/ has zero file overlap with lenstool work) if the claim still stands at ship time.
Implementation Steps
autolens/weak/model/__init__.py — empty, matching point/model.
autolens/weak/model/analysis.py — class AnalysisWeak(AgAnalysis, AnalysisLens):
Visualizer = VisualizerWeak, Result = ResultWeak class attributes.
__init__(self, dataset: WeakDataset, cosmology=None, title_prefix=None, use_jax=False, **kwargs). use_jax=False default: FitWeak is NumPy (cached_property + np.asarray, no xp threading); JAX support is deliberate future work (needs pytree registration like AnalysisPoint._register_fit_point_pytrees) — do NOT bolt it on here.
log_likelihood_function(instance) → self.fit_from(instance).log_likelihood.
fit_from(instance) → tracer_via_instance_from(instance) → FitWeak(dataset=self.dataset, tracer=tracer).
save_attributes(paths) → ag.output_to_json(self.dataset, paths._files_path / "dataset.json") (round-trip works since the weak-dataset-from-json fix).
autolens/weak/model/result.py — ResultWeak(Result) mirroring ResultPoint (13 lines): fallback uniform grid property + max_log_likelihood_fit via analysis.fit_from(self.instance).
autolens/weak/model/plotter.py — PlotterWeak(Plotter) mirroring PlotterPoint: dataset_weak() → subplot_weak_dataset behind plot_setting(section=["weak_dataset"], ...); fit_weak(fit, quick_update=False) → subplot_fit_weak / subplot_fit_quick behind plot_setting(section=["fit_weak"], ...).
autolens/weak/model/visualizer.py — VisualizerWeak(af.Visualizer) mirroring VisualizerPoint (107 lines): visualize_before_fit plots the dataset; visualize plots the fit from the instance, forwarding quick_update.
- Config: add to
autolens/config/visualize/plots.yaml (after the point_dataset/fit_point_dataset block, same comment style):
weak_dataset: with subplot_dataset: true
fit_weak: with subplot_fit: true
- Exports:
autolens/__init__.py — from .weak.model.analysis import AnalysisWeak (alongside the existing weak exports at lines 128-130).
- Tests (NumPy-only, no JAX per repo rules):
test_autolens/weak/test_analysis.py (+ plotter test if cheap) mirroring test_autolens/point/model/test_analysis_point.py:
log_likelihood_function(instance) == FitWeak(dataset, tracer).log_likelihood for a SimulatorShearYX(seed=1) dataset and Isothermal instance.
- noise-free round-trip: simulator tracer fitted to its own noise-free output gives chi_squared == 0 (bit-exact, both use
shear_yx_2d_via_hessian_from).
save_attributes writes a loadable dataset.json (al.from_json round-trip).
- Use direct module imports in tests (the
al.plot.X pytest recursion gotcha from step 2 applies).
- Run full
python -m pytest test_autolens/ before PR.
Workspace follow-up (second PR, after library merges)
autolens_workspace/scripts/weak/modeling.py — Nautilus fit of an Isothermal lens to the dataset/weak/simple dataset, prose in the style of scripts/imaging/modeling.py (judgment-tier tutorial prose per WORKFLOW.md).
- Mirror the new
weak_dataset / fit_weak plots.yaml sections into autolens_workspace/config/visualize/plots.yaml (workspace configs override packaged defaults).
Key Files
autolens/point/model/{analysis,result,plotter,visualizer}.py — the template (233/13/97/107 lines).
autolens/weak/fit.py — FitWeak, already exposes log_likelihood.
autolens/weak/plot/{weak_dataset_plots,fit_weak_plots}.py — the nine existing plot helpers + subplot_fit_quick.
autolens/config/visualize/plots.yaml — visualization settings read by plot_setting.
Autonomy
--auto launch 2026-07-09, effective level supervised (header supervised, feature cap supervised): plan-to-issue (this issue), mechanical stretches proceed, ship sign-off parks as a batched question here, merge stays human. No Heart YELLOW acknowledgement was given at launch. Brain Feature Agent scored this too-large and suggested a 4-phase split; consolidated to the series' proven 2-PR shape (library, then workspace) — recorded here for post-hoc review.
Original Prompt
Click to expand starting prompt
We are now going to add weak lensing modeling.
First, we need to create the analysis.py module, so inspect @autolens_workspace/scripts/weak and
@PyAutoLens/autolens/imaging/model . We are basically going to make everything weak does from here a "mirror" of
the imaging model API (and also interferoter.)
The log_likelihod_function is in particular important, we already have the codw which creates the shear field
show in the @autolens_workspace/scripts/weak/simulator.py file and we can turn it into a fit in
@PyAutoLens/autolens/imaging/fit.py, so shouldnt be hard to work out the pattern and whats needed here.
I believe everything else (plotter.py, result.py, visualizer.py) should be relatively straight forward to work
out by simply copying the patterns and logic from the imaging module, but keep an eye out for unexpected tricky
parts.
Finally, read @autolens_workspace/scripts/imaging/modeling.py and then make an equivalent for
weak lensing.
Overview
Step 4 of the weak-lensing series (
PyAutoMind/z_features/weak_shear.md): addal.AnalysisWeakso a non-linear search can fit lens mass models to aWeakDatasetshear catalogue, mirroring the established model API ofimaging/point, plus a workspacescripts/weak/modeling.pytutorial. This is the keystone of the weak-lensing home-straight push — series steps 5 (likelihood_function), 7 (Abell 2744 real data) and 8 (combined strong+weak via summed analyses) all depend on it.Science scope: cluster/group-scale weak shear complementing strong lensing (Niemiec et al. 2020 hybrid-Lenstool; Oguri et al. 2012 SGAS) — not cosmic shear or galaxy-galaxy lensing.
Plan
autolens/weak/model/mirroringautolens/point/model/(the right template —FitWeakalready followsFitPoint's standalone pattern):AnalysisWeak,ResultWeak,VisualizerWeak,PlotterWeak.AnalysisWeak.log_likelihood_functionbuilds aTracerfrom the model instance and returnsFitWeak(dataset, tracer).log_likelihood.subplot_weak_dataset,subplot_fit_weak,subplot_fit_quick), with newweak_dataset/fit_weaksections in the packagedconfig/visualize/plots.yaml.al.AnalysisWeakinautolens/__init__.py; NumPy-only unit tests mirroringtest_autolens/point/model/.scripts/weak/modeling.py(judgment-tier tutorial prose, style ofscripts/imaging/modeling.py) and mirrors the new plots.yaml keys into workspace config.Detailed implementation plan
Affected Repositories
Branch Survey
dataset.fits, unrelated to this task)Suggested branch:
feature/weak-modelingWorktree:
~/Code/PyAutoLabs-wt/weak-modeling/Note: autolens_workspace is currently claimed by task
lenstool-example. Library work proceeds first (combined workflow); the workspace follow-up uses the parallel-worktree pattern proven twice in this series (scripts/weak/has zero file overlap with lenstool work) if the claim still stands at ship time.Implementation Steps
autolens/weak/model/__init__.py— empty, matchingpoint/model.autolens/weak/model/analysis.py—class AnalysisWeak(AgAnalysis, AnalysisLens):Visualizer = VisualizerWeak,Result = ResultWeakclass attributes.__init__(self, dataset: WeakDataset, cosmology=None, title_prefix=None, use_jax=False, **kwargs).use_jax=Falsedefault:FitWeakis NumPy (cached_property+np.asarray, noxpthreading); JAX support is deliberate future work (needs pytree registration likeAnalysisPoint._register_fit_point_pytrees) — do NOT bolt it on here.log_likelihood_function(instance)→self.fit_from(instance).log_likelihood.fit_from(instance)→tracer_via_instance_from(instance)→FitWeak(dataset=self.dataset, tracer=tracer).save_attributes(paths)→ag.output_to_json(self.dataset, paths._files_path / "dataset.json")(round-trip works since theweak-dataset-from-jsonfix).autolens/weak/model/result.py—ResultWeak(Result)mirroringResultPoint(13 lines): fallback uniformgridproperty +max_log_likelihood_fitviaanalysis.fit_from(self.instance).autolens/weak/model/plotter.py—PlotterWeak(Plotter)mirroringPlotterPoint:dataset_weak()→subplot_weak_datasetbehindplot_setting(section=["weak_dataset"], ...);fit_weak(fit, quick_update=False)→subplot_fit_weak/subplot_fit_quickbehindplot_setting(section=["fit_weak"], ...).autolens/weak/model/visualizer.py—VisualizerWeak(af.Visualizer)mirroringVisualizerPoint(107 lines):visualize_before_fitplots the dataset;visualizeplots the fit from the instance, forwardingquick_update.autolens/config/visualize/plots.yaml(after thepoint_dataset/fit_point_datasetblock, same comment style):weak_dataset:withsubplot_dataset: truefit_weak:withsubplot_fit: trueautolens/__init__.py—from .weak.model.analysis import AnalysisWeak(alongside the existing weak exports at lines 128-130).test_autolens/weak/test_analysis.py(+ plotter test if cheap) mirroringtest_autolens/point/model/test_analysis_point.py:log_likelihood_function(instance)==FitWeak(dataset, tracer).log_likelihoodfor aSimulatorShearYX(seed=1)dataset and Isothermal instance.shear_yx_2d_via_hessian_from).save_attributeswrites a loadabledataset.json(al.from_jsonround-trip).al.plot.Xpytest recursion gotcha from step 2 applies).python -m pytest test_autolens/before PR.Workspace follow-up (second PR, after library merges)
autolens_workspace/scripts/weak/modeling.py— Nautilus fit of an Isothermal lens to thedataset/weak/simpledataset, prose in the style ofscripts/imaging/modeling.py(judgment-tier tutorial prose per WORKFLOW.md).weak_dataset/fit_weakplots.yaml sections intoautolens_workspace/config/visualize/plots.yaml(workspace configs override packaged defaults).Key Files
autolens/point/model/{analysis,result,plotter,visualizer}.py— the template (233/13/97/107 lines).autolens/weak/fit.py—FitWeak, already exposeslog_likelihood.autolens/weak/plot/{weak_dataset_plots,fit_weak_plots}.py— the nine existing plot helpers +subplot_fit_quick.autolens/config/visualize/plots.yaml— visualization settings read byplot_setting.Autonomy
--autolaunch 2026-07-09, effective level supervised (header supervised, feature cap supervised): plan-to-issue (this issue), mechanical stretches proceed, ship sign-off parks as a batched question here, merge stays human. No Heart YELLOW acknowledgement was given at launch. Brain Feature Agent scored this too-large and suggested a 4-phase split; consolidated to the series' proven 2-PR shape (library, then workspace) — recorded here for post-hoc review.Original Prompt
Click to expand starting prompt
We are now going to add weak lensing modeling.
First, we need to create the analysis.py module, so inspect @autolens_workspace/scripts/weak and
@PyAutoLens/autolens/imaging/model . We are basically going to make everything weak does from here a "mirror" of
the imaging model API (and also interferoter.)
The log_likelihod_function is in particular important, we already have the codw which creates the shear field
show in the @autolens_workspace/scripts/weak/simulator.py file and we can turn it into a fit in
@PyAutoLens/autolens/imaging/fit.py, so shouldnt be hard to work out the pattern and whats needed here.
I believe everything else (plotter.py, result.py, visualizer.py) should be relatively straight forward to work
out by simply copying the patterns and logic from the imaging module, but keep an eye out for unexpected tricky
parts.
Finally, read @autolens_workspace/scripts/imaging/modeling.py and then make an equivalent for
weak lensing.