From fd7d866f7883f31deb053cc85fa6697350e39a97 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Fri, 29 May 2026 08:42:28 +0100 Subject: [PATCH] fix: restore lost setup scaffolding in chapter 2 tutorial_2_practicalities The imports, dataset load, mask and model setup were accidentally deleted from this tutorial. Git history pinpoints the cause: the autolens_workspace commit ce1bf623 "Add __Contents__ sections to all scripts" overwrote the region spanning the old Contents list down through the __Search__ prose, collaterally removing ~119 lines of setup code. The file dropped 421 -> 302 lines there. The later HowToLens bootstrap (62a5f3a) faithfully copied the already-broken file, so the first runnable line was `search = af.Nautilus(...)` referencing undefined `dataset_name`, `dataset` and `model`. This restores the verbatim scaffolding from the last-complete version (autolens_workspace 241cc8c0): imports, __PyAutoFit__, __Initial Setup__ (with auto-simulation), __Mask__ and __Model__. The dataset is `simple__no_lens_light__mass_sis` (IsothermalSph mass + linear ExponentialCoreSph source), the same fit as tutorial_1, matching the tutorial's own prose ("the same dataset we fitted in the previous tutorial"). Modernized to current-repo conventions: setup_notebook header, `scripts/simulator/...` subprocess path, and the PyAutoLabs/PyAutoFit URL. Verified runnable end-to-end in fast mode (PYAUTO_TEST_MODE=2 + skip flags): model composes (6 free params), dataset loads, search and likelihood evaluation complete (exit 0). Scanned both HowTo repos and the source commit's deletion footprint: tutorial_2 was the only tutorial damaged this way; all other candidates were verified false positives. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../tutorial_2_practicalities.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/scripts/chapter_2_lens_modeling/tutorial_2_practicalities.py b/scripts/chapter_2_lens_modeling/tutorial_2_practicalities.py index 19bda0e..12ef488 100755 --- a/scripts/chapter_2_lens_modeling/tutorial_2_practicalities.py +++ b/scripts/chapter_2_lens_modeling/tutorial_2_practicalities.py @@ -74,6 +74,104 @@ is outputting results, try increasing this value to ensure the model-fit runs efficiently.** """ +from autoconf import jax_wrapper # Sets JAX environment before other imports + +# from autoconf import setup_notebook; setup_notebook() + +from pathlib import Path +import autolens as al +import autolens.plot as aplt + +""" +__PyAutoFit__ + +Modeling uses the probabilistic programming language +[PyAutoFit](https://github.com/PyAutoLabs/PyAutoFit), an open-source project that allows complex model +fitting techniques to be straightforwardly integrated into scientific modeling software. + +The majority of tools that make model-fitting practical are provided by PyAutoFit, for example it handles +all output of the non-linear search to hard-disk, the visualization of results and the estimation of run-times. +""" +import autofit as af + +""" +__Initial Setup__ + +Lets first load the `Imaging` dataset we'll fit a model with using a non-linear search. + +This is the same dataset we fitted in the previous tutorial, and we'll repeat the same fit, as we simply want +to illustrate the practicalities of model-fitting in this tutorial. +""" +dataset_name = "simple__no_lens_light__mass_sis" +dataset_path = Path("dataset") / "imaging" / dataset_name + +""" +__Dataset Auto-Simulation__ + +If the dataset does not already exist on your system, it will be created by running the corresponding +simulator script. This ensures that all example scripts can be run without manually simulating data first. +""" +if not dataset_path.exists(): + import subprocess + import sys + + subprocess.run( + [sys.executable, "scripts/simulator/no_lens_light__mass_sis.py"], + check=True, + ) + +dataset = al.Imaging.from_fits( + data_path=dataset_path / "data.fits", + noise_map_path=dataset_path / "noise_map.fits", + psf_path=dataset_path / "psf.fits", + pixel_scales=0.1, +) + +aplt.subplot_imaging_dataset(dataset=dataset) + +""" +__Mask__ + +The non-linear fit also needs a `Mask2D`, lets use a 3.0" circle. +""" +mask_radius = 3.0 + +mask = al.Mask2D.circular( + shape_native=dataset.shape_native, + pixel_scales=dataset.pixel_scales, + radius=mask_radius, +) + +dataset = dataset.apply_mask(mask=mask) + +aplt.subplot_imaging_dataset(dataset=dataset) + +""" +__Model__ + +We compose the model using the same API as the previous tutorial. + +This model is the same as the previous tutorial, an `IsothermalSph` spherical mass profile representing the lens +galaxy and a `ExponentialCoreSph` light profile representing the source galaxy. +""" +# Lens: + +mass = af.Model(al.mp.IsothermalSph) + +lens = af.Model(al.Galaxy, redshift=0.5, mass=mass) + +# Source: + +bulge = af.Model(al.lp_linear.ExponentialCoreSph) + +source = af.Model(al.Galaxy, redshift=1.0, bulge=bulge) + +# Overall Lens Model: + +model = af.Collection(galaxies=af.Collection(lens=lens, source=source)) + +print(model.info) + search = af.Nautilus( path_prefix=Path("howtolens") / "chapter_2", name="tutorial_2_practicalities",