Skip to content
Merged
9 changes: 9 additions & 0 deletions autolens/aggregator/subplot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
from enum import Enum


class FITSGalaxyImages(Enum):
"""
The HDUs that can be extracted from the fit.fits file.
"""

lens_light_image = "GALAXY_0"
lensed_source_image = "GALAXY_1"


class FITSModelGalaxyImages(Enum):
"""
The HDUs that can be extracted from the fit.fits file.
Expand Down
5 changes: 3 additions & 2 deletions autolens/config/visualize/plots.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# These can be disabled to save on hard-disk space but will lead to certain database functionality being disabled.

subplot_format: [png] # Output format of all subplots, can be png, pdf or both (e.g. [png, pdf])
fits_are_zoomed: true # If true, output .fits files are zoomed in on the center of the unmasked region image, saving hard-disk space.
fits_are_zoomed: false # If true, output .fits files are zoomed in on the center of the unmasked region image, saving hard-disk space.

dataset: # Settings for plots of all datasets (e.g. ImagingPlotter, InterferometerPlotter).
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the data, noise-map, etc.)?
Expand All @@ -26,7 +26,8 @@ fit: # Settings for plots of all fits (e.g
subplot_of_planes: false # Plot subplot of the model-image, subtracted image and other quantities of each plane?
subplot_galaxies_images: false # Plot subplot of the image of each plane in the model?
fits_fit: false # Output a .fits file containing the fit model data, residual map, normalized residual map and chi-squared?
fits_model_galaxy_images : false # Output a .fits file containing the model images of every galaxy?
fits_galaxy_images : false # Output a .fits file containing the images (e.g. without PSF convolution) of every galaxy?
fits_model_galaxy_images : false # Output a .fits file containing the model images (e.g. with PSF convolution) of every galaxy?

fit_imaging: {} # Settings for plots of fits to imaging datasets (e.g. FitImagingPlotter).

Expand Down
31 changes: 28 additions & 3 deletions autolens/imaging/fit_imaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def __init__(

super().__init__(dataset=dataset, dataset_model=dataset_model, xp=xp)
AbstractFitInversion.__init__(
self=self, model_obj=tracer, settings_inversion=settings_inversion
self=self, model_obj=tracer, settings_inversion=settings_inversion,xp=xp
)

self.tracer = tracer
Expand Down Expand Up @@ -151,10 +151,35 @@ def model_data(self) -> aa.Array2D:

if self.perform_inversion:

return self.blurred_image + self.inversion.mapped_reconstructed_data
return self.blurred_image + self.inversion.mapped_reconstructed_operated_data

return self.blurred_image

@property
def galaxy_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
"""
A dictionary which associates every galaxy in the tracer before operation (e.g. no PSF convolution
or NUFFT performed).

This image is the image of the sum of:

- The images of all ordinary light profiles in that plane summed before any operation is performed on them.
- The images of all linear objects (e.g. linear light profiles / pixelizations), where the images are solved
for first via the inversion.

This dictionary is used to output to .fits file the galaxy images.
"""

galaxy_image_2d_dict = self.tracer.galaxy_image_2d_dict_from(
grid=self.grids.lp,
)

galaxy_linear_obj_image_dict = self.galaxy_linear_obj_data_dict_from(
use_operated=False,
)

return {**galaxy_image_2d_dict, **galaxy_linear_obj_image_dict}

@property
def galaxy_model_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
"""
Expand All @@ -177,7 +202,7 @@ def galaxy_model_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
)

galaxy_linear_obj_image_dict = self.galaxy_linear_obj_data_dict_from(
use_image=True
use_operated=True,
)

return {**galaxy_blurred_image_2d_dict, **galaxy_linear_obj_image_dict}
Expand Down
2 changes: 1 addition & 1 deletion autolens/imaging/plot/fit_imaging_plotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ def subplot_mappings_of_plane(
inversion_plotter.visuals_2d.indexes = indexes

inversion_plotter.figures_2d_of_pixelization(
pixelization_index=pixelization_index, reconstructed_image=True
pixelization_index=pixelization_index, reconstructed_operated_data=True
)

self.visuals_2d.source_plane_mesh_indexes = [
Expand Down
19 changes: 10 additions & 9 deletions autolens/interferometer/fit_interferometer.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def __init__(
xp=xp,
)
AbstractFitInversion.__init__(
self=self, model_obj=tracer, settings_inversion=settings_inversion
self=self, model_obj=tracer, settings_inversion=settings_inversion, xp=xp
)

self.preloads = preloads
Expand Down Expand Up @@ -152,12 +152,15 @@ def model_data(self) -> aa.Visibilities:
"""

if self.perform_inversion:
return self.profile_visibilities + self.inversion.mapped_reconstructed_data
return (
self.profile_visibilities
+ self.inversion.mapped_reconstructed_operated_data
)

return self.profile_visibilities

@property
def galaxy_model_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
def galaxy_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
"""
A dictionary which associates every galaxy in the tracer with its `image`.

Comment on lines 162 to 166

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FitInterferometer defines galaxy_image_dict but the previous galaxy_model_image_dict property appears to have been removed. The test suite (e.g. test_fit_interferometer.py::test___galaxy_model_image_dict) still references galaxy_model_image_dict, and this is also likely part of the public API. Please either reintroduce galaxy_model_image_dict (e.g. as an alias to galaxy_image_dict for backwards compatibility) or update all call sites/tests and document the breaking change.

Copilot uses AI. Check for mistakes.
Expand All @@ -170,15 +173,13 @@ def galaxy_model_image_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
For modeling, this dictionary is used to set up the `adapt_images` that adapt certain pixelizations to the
data being fitted.
"""
galaxy_model_image_dict = self.tracer.galaxy_image_2d_dict_from(
grid=self.grids.lp
)
galaxy_image_dict = self.tracer.galaxy_image_2d_dict_from(grid=self.grids.lp)

galaxy_linear_obj_image_dict = self.galaxy_linear_obj_data_dict_from(
use_image=True
use_operated=False
)

return {**galaxy_model_image_dict, **galaxy_linear_obj_image_dict}
return {**galaxy_image_dict, **galaxy_linear_obj_image_dict}

@property
def galaxy_model_visibilities_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
Expand All @@ -197,7 +198,7 @@ def galaxy_model_visibilities_dict(self) -> Dict[ag.Galaxy, np.ndarray]:
)

galaxy_linear_obj_visibilities_dict = self.galaxy_linear_obj_data_dict_from(
use_image=False
use_operated=True
)

return {**galaxy_model_visibilities_dict, **galaxy_linear_obj_visibilities_dict}
Expand Down
6 changes: 3 additions & 3 deletions autolens/interferometer/plot/fit_interferometer_plotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def figures_2d(
inversion_plotter = self.inversion_plotter_of_plane(
plane_index=plane_index
)
inversion_plotter.figures_2d(reconstructed_image=True)
inversion_plotter.figures_2d(reconstructed_operated_data=True)

if dirty_model_image:
self.mat_plot_2d.plot_array(
Expand Down Expand Up @@ -467,7 +467,7 @@ def subplot_mappings_of_plane(
inversion_plotter.visuals_2d.radial_critical_curves = None

inversion_plotter.figures_2d_of_pixelization(
pixelization_index=pixelization_index, reconstructed_image=True
pixelization_index=pixelization_index, reconstructed_operated_data=True
)

self.visuals_2d.source_plane_mesh_indexes = [
Expand Down Expand Up @@ -516,7 +516,7 @@ def subplot_fit_real_space(self):
inversion_plotter = self.inversion_plotter_of_plane(plane_index=1)

inversion_plotter.figures_2d_of_pixelization(
pixelization_index=0, reconstructed_image=True
pixelization_index=0, reconstructed_operated_data=True
)
inversion_plotter.figures_2d_of_pixelization(
pixelization_index=0, reconstruction=True
Expand Down
2 changes: 1 addition & 1 deletion test_autolens/analysis/test_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def test__use_border_relocator__determines_if_border_pixel_relocation_is_used(

grid = fit.inversion.linear_obj_list[0].source_plane_data_grid.over_sampled

assert grid[2] == pytest.approx([-82.89544515, 52.7491249], 1.0e-4)
assert grid[2] == pytest.approx([-82.991148773, 52.81254921], 1.0e-4)
Comment on lines 121 to +124

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both assertions in this test currently expect (effectively) the same grid[2] value for use_border_relocator=False and use_border_relocator=True, so the test no longer verifies that the flag changes behavior. Consider asserting that the two grids differ (or checking a specific relocation effect) so the setting is actually exercised.

Copilot uses AI. Check for mistakes.


def test__modify_before_fit__inversion_no_positions_likelihood__raises_exception(
Expand Down
2 changes: 1 addition & 1 deletion test_autolens/analysis/test_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def test__source_plane_centre(analysis_imaging_7x7):
)

assert result.source_plane_centre_from().in_list[0] == pytest.approx(
(0.916666, -0.916666), 1.0e-4
(-0.916666673333, -0.916666), 1.0e-4
)


Expand Down
1 change: 1 addition & 0 deletions test_autolens/config/general.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ inversion:
use_positive_only_solver: false # If True, inversion's use a positive-only linear algebra solver by default, which is slower but prevents unphysical negative values in the reconstructed solutuion.
no_regularization_add_to_curvature_diag_value: 1.0e-8 # The default value added to the curvature matrix's diagonal when regularization is not applied to a linear object, which prevents inversion's failing due to the matrix being singular.
positive_only_uses_p_initial: false # If True, the positive-only solver of an inversion's uses an initial guess of the reconstructed data's values as which values should be positive, speeding up the solver.
use_border_relocator: false # If True, by default a pixelization's border is used to relocate all pixels outside its border to the border.
numba:
cache: true
nopython: true
Expand Down
4 changes: 3 additions & 1 deletion test_autolens/config/visualize.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@ mat_wrap_2d:
marker: .
s: 17
plots:
fits_are_zoomed: true
dataset:
subplot_dataset: true
fit:
subplot_fit: true
subplots_of_planes: false
fits_fit: true # Output a .fits file containing the fit model data, residual map, normalized residual map and chi-squared?
fits_model_galaxy_images : true # Output a .fits file containing the model images of every galaxy?
fits_galaxy_images : true # Output a .fits file containing the images (e.g. without PSF convolution) of every galaxy?
fits_model_galaxy_images : true # Output a .fits file containing the model images (e.g. with PSF convolution) of every galaxy?
fit_imaging: {}
fit_interferometer:
subplot_fit_real_space: true
Expand Down
78 changes: 74 additions & 4 deletions test_autolens/imaging/test_fit_imaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def test__fit_figure_of_merit(masked_imaging_7x7, masked_imaging_covariance_7x7)
fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer)

assert fit.perform_inversion is True
assert fit.figure_of_merit == pytest.approx(-22.79906, 1.0e-4)
assert fit.figure_of_merit == pytest.approx(-22.801816971, 1.0e-4)

g0_operated = al.Galaxy(
redshift=0.5,
Expand Down Expand Up @@ -341,7 +341,7 @@ def test__fit_figure_of_merit__sub_2(image_7x7, psf_3x3, noise_map_7x7, mask_2d_
fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer)

assert fit.perform_inversion is True
assert fit.figure_of_merit == pytest.approx( -22.8021113243233, 1.0e-4)
assert fit.figure_of_merit == pytest.approx( -22.8051006673, 1.0e-4)

g0_operated = al.Galaxy(
redshift=0.5,
Expand Down Expand Up @@ -459,7 +459,77 @@ def test__fit__model_dataset__grid_offset__handles_special_behaviour(masked_imag
fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer,
dataset_model=al.DatasetModel(grid_offset=(1.0, 2.0))
)
assert fit.figure_of_merit == pytest.approx(-22.8021112977481, 1.0e-4)
assert fit.figure_of_merit == pytest.approx(-22.8051006, 1.0e-4)


def test__galaxy_image_dict(masked_imaging_7x7):

# Normal Light Profiles Only

g0 = al.Galaxy(
redshift=0.5,
bulge=al.lp.Sersic(centre=(0.05, 0.05), intensity=1.0),
mass_profile=al.mp.IsothermalSph(centre=(0.05, 0.05), einstein_radius=1.0),
)
g1 = al.Galaxy(redshift=1.0, bulge=al.lp.Sersic(centre=(0.05, 0.05), intensity=1.0))
g2 = al.Galaxy(redshift=1.0)

tracer = al.Tracer(galaxies=[g0, g1, g2])

fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer)

image_2d_list = tracer.image_2d_list_from(
grid=masked_imaging_7x7.grids.lp,
)

assert fit.galaxy_image_dict[g0] == pytest.approx(
image_2d_list[0].array, 1.0e-4
)
assert fit.galaxy_image_dict[g1] == pytest.approx(
image_2d_list[1].array, 1.0e-4
)
assert (fit.galaxy_image_dict[g2] == np.zeros(9)).all()

# Normal light + Linear Light PRofiles + Pixelization + Regularizaiton

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: PRofiles should be Profiles.

Suggested change
# Normal light + Linear Light PRofiles + Pixelization + Regularizaiton
# Normal light + Linear Light Profiles + Pixelization + Regularizaiton

Copilot uses AI. Check for mistakes.

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in comment: Regularizaiton should be Regularization.

Suggested change
# Normal light + Linear Light PRofiles + Pixelization + Regularizaiton
# Normal light + Linear Light PRofiles + Pixelization + Regularization

Copilot uses AI. Check for mistakes.

g0_linear = al.Galaxy(
redshift=0.5,
bulge=al.lp_linear.Sersic(),
mass_profile=al.mp.IsothermalSph(einstein_radius=1.0),
)

pixelization = al.Pixelization(
mesh=al.mesh.RectangularUniform(shape=(3, 3)),
regularization=al.reg.Constant(coefficient=1.0),
)

galaxy_pix_0 = al.Galaxy(redshift=1.0, pixelization=pixelization)

galaxy_pix_1 = al.Galaxy(redshift=1.0, pixelization=pixelization)

tracer = al.Tracer(
galaxies=[g0, g0_linear, g2, galaxy_pix_0, galaxy_pix_1]
)

masked_imaging_7x7.data[0] = 3.0

fit = al.FitImaging(dataset=masked_imaging_7x7, tracer=tracer)

assert fit.galaxy_image_dict[g0] == pytest.approx(
image_2d_list[0].array, 1.0e-4
)

assert fit.galaxy_image_dict[g0_linear][4] == pytest.approx(
-27.926926, 1.0e-4
)

assert fit.galaxy_image_dict[galaxy_pix_0][4] == pytest.approx(
0.94954435552, 1.0e-4
)
assert fit.galaxy_image_dict[galaxy_pix_1][4] == pytest.approx(
0.94954436798, 1.0e-4
)
assert (fit.galaxy_image_dict[g2] == np.zeros(9)).all()


def test__galaxy_model_image_dict(masked_imaging_7x7):
Expand Down Expand Up @@ -688,7 +758,7 @@ def test__model_images_of_planes_list(masked_imaging_7x7_sub_2):
1.0e-4,
)

assert fit.model_images_of_planes_list[2][0] == pytest.approx(1.56110288, 1.0e-4)
assert fit.model_images_of_planes_list[2][0] == pytest.approx(1.5614163282, 1.0e-4)


def test__subtracted_images_of_planes_list(masked_imaging_7x7_no_blur, masked_imaging_7x7_no_blur_sub_2):
Expand Down
Loading
Loading