Skip to content

Commit 6f960f6

Browse files
committed
Merge branch 'main' into feature/array_testing
2 parents e8db9e2 + 7aa4b6d commit 6f960f6

File tree

20 files changed

+296
-125
lines changed

20 files changed

+296
-125
lines changed

autolens/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,4 @@
124124

125125
conf.instance.register(__file__)
126126

127-
__version__ = "2024.11.6.1"
127+
__version__ = "2024.11.13.2"

autolens/aggregator/tracer.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,18 @@ def _tracer_from(
5858

5959
tracer = Tracer(galaxies=galaxies, cosmology=cosmology)
6060

61-
if len(fit.children) > 0:
62-
logger.info(
63-
"""
64-
Using database for a fit with multiple summed Analysis objects.
65-
66-
Tracer objects do not fully support this yet (e.g. model parameters which vary over analyses may be incorrect)
67-
so proceed with caution!
68-
"""
69-
)
70-
71-
return [tracer] * len(fit.children)
61+
if fit.children is not None:
62+
if len(fit.children) > 0:
63+
logger.info(
64+
"""
65+
Using database for a fit with multiple summed Analysis objects.
66+
67+
Tracer objects do not fully support this yet (e.g. model parameters which vary over analyses may be incorrect)
68+
so proceed with caution!
69+
"""
70+
)
71+
72+
return [tracer] * len(fit.children)
7273

7374
return [tracer]
7475

autolens/analysis/result.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
import os
23
import numpy as np
34
from typing import Optional, Union
@@ -15,6 +16,8 @@
1516
from autolens.lens.tracer import Tracer
1617
from autolens.point.solver import PointSolver
1718

19+
logger = logging.getLogger(__name__)
20+
1821

1922
class Result(AgResultDataset):
2023
@property
@@ -101,8 +104,76 @@ def image_plane_multiple_image_positions(self) -> aa.Grid2DIrregular:
101104
source_plane_coordinate=self.source_plane_centre.in_list[0],
102105
)
103106

107+
if multiple_images.shape[0] == 1:
108+
return self.image_plane_multiple_image_positions_for_single_image_from()
109+
104110
return aa.Grid2DIrregular(values=multiple_images)
105111

112+
def image_plane_multiple_image_positions_for_single_image_from(
113+
self, increments: int = 20
114+
) -> aa.Grid2DIrregular:
115+
"""
116+
If the standard point solver only locates one multiple image, finds one or more additional images, which are
117+
not technically multiple image in the point source regime, but are close enough to it they can be used
118+
in a position threshold likelihood.
119+
120+
This is performed by incrementally moving the source-plane centre's coordinates towards the centre of the
121+
source-plane at (0.0", 0.0"). This ensures that the centre will eventually go inside the caustic, where
122+
multiple images are formed.
123+
124+
To move the source-plane centre, the original source-plane centre is multiplied by a factor that decreases
125+
from 1.0 to 0.0 in increments of 1/increments. For example, if the source-plane centre is (1.0", -0.5") and
126+
the `factor` is 0.5, the input source-plane centre is (0.5", -0.25").
127+
128+
The multiple images are always computed for the same mass model, thus they will always be valid multiple images
129+
for the model being fitted, but as the factor decrease the multiple images may move furhter from their observed
130+
positions.
131+
132+
Parameters
133+
----------
134+
increments
135+
The number of increments the source-plane centre is moved to compute multiple images.
136+
"""
137+
138+
logger.info(
139+
"""
140+
Could not find multiple images for maximum likelihood lens model.
141+
142+
Incrementally moving source centre inwards towards centre of source-plane until caustic crossing occurs
143+
and multiple images are formed.
144+
"""
145+
)
146+
147+
grid = self.analysis.dataset.mask.derive_grid.all_false
148+
149+
centre = self.source_plane_centre.in_list[0]
150+
151+
solver = PointSolver.for_grid(
152+
grid=grid,
153+
pixel_scale_precision=0.001,
154+
)
155+
156+
for i in range(1, increments):
157+
factor = 1.0 - (1.0 * (i / increments))
158+
159+
multiple_images = solver.solve(
160+
tracer=self.max_log_likelihood_tracer,
161+
source_plane_coordinate=(centre[0] * factor, centre[1] * factor),
162+
)
163+
164+
if multiple_images.shape[0] > 1:
165+
return aa.Grid2DIrregular(values=multiple_images)
166+
167+
logger.info(
168+
"""
169+
Could not find multiple images for maximum likelihood lens model, even after incrementally moving the source
170+
centre inwards to the centre of the source-plane.
171+
172+
Set the multiple image postiions to two images at (1.0", 1.0") so code continues to run.
173+
"""
174+
)
175+
return aa.Grid2DIrregular(values=[(1.0, 1.0), (1.0, 1.0)])
176+
106177
def positions_threshold_from(
107178
self,
108179
factor=1.0,
@@ -168,6 +239,7 @@ def positions_likelihood_from(
168239
minimum_threshold=None,
169240
use_resample=False,
170241
positions: Optional[aa.Grid2DIrregular] = None,
242+
mass_centre_radial_distance_min: float = None,
171243
) -> Union[PositionsLHPenalty, PositionsLHResample]:
172244
"""
173245
Returns a `PositionsLH` object from the result of a lens model-fit, where the maximum log likelihood mass
@@ -178,6 +250,11 @@ def positions_likelihood_from(
178250
parametric source) can be used to determine the multiple image positions and threshold for a more complex
179251
subsequent fit (e.g. power-law mass model, pixelized source).
180252
253+
The mass model central image is removed from the solution, as this is rarely physically observed and therefore
254+
should not be included in the likelihood penalty or resampling. It is removed by setting a positive
255+
magnification threshold in the `PointSolver`. For strange lens models the central image may still be
256+
solved for, in which case the `mass_centre_radial_distance_min` parameter can be used to remove it.
257+
181258
Parameters
182259
----------
183260
factor
@@ -193,6 +270,10 @@ def positions_likelihood_from(
193270
positions
194271
If input, these positions are used instead of the computed multiple image positions from the lens mass
195272
model.
273+
mass_centre_radial_distance_min
274+
The minimum radial distance from the mass model centre that a multiple image position must be to be
275+
included in the likelihood penalty or resampling. If `None` all positions are used. This is an additional
276+
method to remove central images that may make it through the point solver's magnification threshold.
196277
197278
Returns
198279
-------
@@ -207,6 +288,18 @@ def positions_likelihood_from(
207288
if positions is None
208289
else positions
209290
)
291+
292+
if mass_centre_radial_distance_min is not None:
293+
mass_centre = self.max_log_likelihood_tracer.extract_attribute(
294+
cls=ag.mp.MassProfile, attr_name="centre"
295+
)
296+
297+
distances = positions.distances_to_coordinate_from(
298+
coordinate=mass_centre[0]
299+
)
300+
301+
positions = positions[distances > mass_centre_radial_distance_min]
302+
210303
threshold = self.positions_threshold_from(
211304
factor=factor, minimum_threshold=minimum_threshold, positions=positions
212305
)

autolens/config/visualize/plots.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
5656
all_at_end_fits: true # Plot all individual plots listed below as .fits (even if False)?
5757
all_at_end_pdf: false # Plot all individual plots listed below as publication-quality .pdf (even if False)?
58-
errors: false
58+
reconstruction_noise_map: false
5959
reconstructed_image: false
6060
reconstruction: false
6161
regularization_weights: false

autolens/imaging/plot/fit_imaging_plotters.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def figures_2d_of_planes(
148148
subtracted_image: bool = False,
149149
model_image: bool = False,
150150
plane_image: bool = False,
151-
plane_errors: bool = False,
151+
plane_noise_map: bool = False,
152152
plane_signal_to_noise_map: bool = False,
153153
use_source_vmax: bool = False,
154154
zoom_to_brightest: bool = True,
@@ -180,12 +180,12 @@ def figures_2d_of_planes(
180180
Whether to make a 2D plot (via `imshow`) of the image of a plane in its source-plane (e.g. unlensed).
181181
Depending on how the fit is performed, this could either be an image of light profiles of the reconstruction
182182
of an `Inversion`.
183-
plane_errors
184-
Whether to make a 2D plot (via `imshow`) of the errors of a plane in its source-plane, where the
185-
errors can only be computed when a pixelized source reconstruction is performed and they correspond to
186-
the errors in each reconstructed pixel as given by the inverse curvature matrix.
183+
plane_noise_map
184+
Whether to make a 2D plot of the noise-map of a plane in its source-plane, where the
185+
noise map can only be computed when a pixelized source reconstruction is performed and they correspond to
186+
the noise map in each reconstructed pixel as given by the inverse curvature matrix.
187187
plane_signal_to_noise_map
188-
Whether to make a 2D plot (via `imshow`) of the signal-to-noise map of a plane in its source-plane,
188+
Whether to make a 2D plot of the signal-to-noise map of a plane in its source-plane,
189189
where the signal-to-noise map values can only be computed when a pixelized source reconstruction and they
190190
are the ratio of reconstructed flux to error in each pixel.
191191
use_source_vmax
@@ -295,12 +295,6 @@ def figures_2d_of_planes(
295295

296296
pix = self.tracer.planes[plane_index].cls_list_from(cls=aa.Pixelization)[0]
297297

298-
if isinstance(pix.mesh, aa.mesh.Delaunay):
299-
try:
300-
self.mat_plot_2d.cmap.kwargs.pop("vmax")
301-
except KeyError:
302-
pass
303-
304298
inversion_plotter = self.inversion_plotter_of_plane(
305299
plane_index=plane_index
306300
)
@@ -318,7 +312,7 @@ def figures_2d_of_planes(
318312
except KeyError:
319313
pass
320314

321-
if plane_errors:
315+
if plane_noise_map:
322316

323317
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
324318

@@ -328,7 +322,7 @@ def figures_2d_of_planes(
328322

329323
inversion_plotter.figures_2d_of_pixelization(
330324
pixelization_index=0,
331-
errors=True,
325+
reconstruction_noise_map=True,
332326
zoom_to_brightest=zoom_to_brightest,
333327
interpolate_to_uniform=interpolate_to_uniform
334328
)

autolens/imaging/simulator.py

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,30 @@ class SimulatorImaging(aa.SimulatorImaging):
99

1010
def via_tracer_from(self, tracer : Tracer, grid : aa.type.Grid2DLike) -> aa.Imaging:
1111
"""
12-
Simulate an `Imaging` dataset from an input tracer and grid.
12+
Simulate an `Imaging` dataset from an input `Tracer` object and a 2D grid of (y,x) coordinates.
1313
14-
The tracer is used to perform ray-tracing and generate the image of the strong lens galaxies (e.g.
15-
the lens light, lensed source light, etc) which is simulated.
14+
The mass profiles of each galaxy in the tracer are used to perform ray-tracing of the input 2D grid and
15+
their light profiles are used to generate the image of the galaxies which are simulated.
1616
1717
The steps of the `SimulatorImaging` simulation process (e.g. PSF convolution, noise addition) are
18-
described in the `SimulatorImaging` `__init__` method docstring.
18+
described in the `SimulatorImaging` `__init__` method docstring, found in the PyAutoArray project.
19+
20+
If one of more galaxy light profiles are a `LightProfileSNR` object, the `intensity` of the light profile is
21+
automatically set such that the signal-to-noise ratio of the light profile is equal to its input
22+
`signal_to_noise_ratio` value.
23+
24+
For example, if a `LightProfileSNR` object has a `signal_to_noise_ratio` of 5.0, the intensity of the light
25+
profile is set such that the peak surface brightness of the profile is 5.0 times the background noise level of
26+
the image.
1927
2028
Parameters
2129
----------
2230
tracer
2331
The tracer, which describes the ray-tracing and strong lens configuration used to simulate the imaging
24-
dataset.
32+
dataset as well as the light profiles of the galaxies used to simulate the image of the galaxies.
2533
grid
26-
The image-plane grid which the image of the strong lens is generated on.
34+
The 2D grid of (y,x) coordinates which the mass profiles of the galaxies in the tracer are ray-traced using
35+
in order to generate the image of the galaxies via their light profiles.
2736
"""
2837

2938
tracer.set_snr_of_snr_light_profiles(
@@ -44,21 +53,30 @@ def via_tracer_from(self, tracer : Tracer, grid : aa.type.Grid2DLike) -> aa.Imag
4453

4554
def via_galaxies_from(self, galaxies : List[ag.Galaxy], grid : aa.type.Grid2DLike) -> aa.Imaging:
4655
"""
47-
Simulate an `Imaging` dataset from an input list of galaxies and grid.
56+
Simulate an `Imaging` dataset from an input list of `Galaxy` objects and a 2D grid of (y,x) coordinates.
4857
49-
The galaxies are used to create a tracer, which performs ray-tracing and generate the image of the strong lens
50-
galaxies (e.g. the lens light, lensed source light, etc) which is simulated.
58+
The galaxies are used to create a `Tracer`. The mass profiles of each galaxy in the tracer are used to
59+
perform ray-tracing of the input 2D grid and their light profiles are used to generate the image of the
60+
galaxies which are simulated.
5161
5262
The steps of the `SimulatorImaging` simulation process (e.g. PSF convolution, noise addition) are
5363
described in the `SimulatorImaging` `__init__` method docstring.
5464
65+
If one of more galaxy light profiles are a `LightProfileSNR` object, the `intensity` of the light profile is
66+
automatically set such that the signal-to-noise ratio of the light profile is equal to its input
67+
`signal_to_noise_ratio` value.
68+
69+
For example, if a `LightProfileSNR` object has a `signal_to_noise_ratio` of 5.0, the intensity of the light
70+
profile is set such that the peak surface brightness of the profile is 5.0 times the background noise level of
71+
the image.
72+
5573
Parameters
5674
----------
5775
galaxies
5876
The galaxies used to create the tracer, which describes the ray-tracing and strong lens configuration
5977
used to simulate the imaging dataset.
6078
grid
61-
The image-plane grid which the image of the strong lens is generated on.
79+
The image-plane 2D grid of (y,x) coordinates grid which the image of the strong lens is generated on.
6280
"""
6381

6482
tracer = Tracer(galaxies=galaxies)
@@ -87,7 +105,7 @@ def via_deflections_and_galaxies_from(self, deflections : aa.VectorYX2D, galaxie
87105
The galaxies used to create the tracer, which describes the ray-tracing and strong lens configuration
88106
used to simulate the imaging dataset.
89107
grid
90-
The image-plane grid which the image of the strong lens is generated on.
108+
The image-plane 2D grid of (y,x) coordinates grid which the image of the strong lens is generated on.
91109
"""
92110
grid = aa.Grid2D.uniform(
93111
shape_native=deflections.shape_native,
@@ -105,10 +123,10 @@ def via_source_image_from(self, tracer : Tracer, grid : aa.type.Grid2DLike, sour
105123
Simulate an `Imaging` dataset from an input image of a source galaxy.
106124
107125
This input image is on a uniform and regular 2D array, meaning it can simulate the source's irregular
108-
and assymetric source galaxy morphological features.
126+
and asymmetric source galaxy morphological features.
109127
110128
The typical use case is inputting the image of an irregular galaxy in the source-plane (whose values are
111-
on a uniform array) and using this function computing the lensed image of this source galaxy.
129+
on a uniform array) and using this function to compute the lensed image of this source galaxy.
112130
113131
The tracer is used to perform ray-tracing and generate the image of the strong lens galaxies (e.g.
114132
the lens light, lensed source light, etc) which is simulated.
@@ -125,7 +143,7 @@ def via_source_image_from(self, tracer : Tracer, grid : aa.type.Grid2DLike, sour
125143
The tracer, which describes the ray-tracing and strong lens configuration used to simulate the imaging
126144
dataset.
127145
grid
128-
The image-plane grid which the image of the strong lens is generated on.
146+
The image-plane 2D grid of (y,x) coordinates grid which the image of the strong lens is generated on.
129147
source_image
130148
The image of the source-plane and source galaxy which is interpolated to compute the lensed image.
131149
"""

autolens/interferometer/plot/fit_interferometer_plotters.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def figures_2d_of_planes(
375375
self,
376376
plane_index: Optional[int] = None,
377377
plane_image: bool = False,
378-
plane_errors: bool = False,
378+
plane_noise_map: bool = False,
379379
plane_signal_to_noise_map: bool = False,
380380
zoom_to_brightest: bool = True,
381381
interpolate_to_uniform: bool = False,
@@ -398,12 +398,12 @@ def figures_2d_of_planes(
398398
Whether to make a 2D plot (via `imshow`) of the image of a plane in its source-plane (e.g. unlensed).
399399
Depending on how the fit is performed, this could either be an image of light profiles of the reconstruction
400400
of an `Inversion`.
401-
plane_errors
402-
Whether to make a 2D plot (via `imshow`) of the errors of a plane in its source-plane, where the
403-
errors can only be computed when a pixelized source reconstruction is performed and they correspond to
404-
the errors in each reconstructed pixel as given by the inverse curvature matrix.
401+
plane_noise_map
402+
Whether to make a 2D plot of the noise-map of a plane in its source-plane, where the
403+
noise map can only be computed when a pixelized source reconstruction is performed and they correspond to
404+
the noise map in each reconstructed pixel as given by the inverse curvature matrix.
405405
plane_signal_to_noise_map
406-
Whether to make a 2D plot (via `imshow`) of the signal-to-noise map of a plane in its source-plane,
406+
Whether to make a 2D plot of the signal-to-noise map of a plane in its source-plane,
407407
where the signal-to-noise map values can only be computed when a pixelized source reconstruction and they
408408
are the ratio of reconstructed flux to error in each pixel.
409409
zoom_to_brightest
@@ -430,15 +430,15 @@ def figures_2d_of_planes(
430430
interpolate_to_uniform=interpolate_to_uniform,
431431
)
432432

433-
if plane_errors:
433+
if plane_noise_map:
434434
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
435435
inversion_plotter = self.inversion_plotter_of_plane(
436436
plane_index=plane_index
437437
)
438438

439439
inversion_plotter.figures_2d_of_pixelization(
440440
pixelization_index=0,
441-
errors=True,
441+
reconstruction_noise_map=True,
442442
zoom_to_brightest=zoom_to_brightest,
443443
interpolate_to_uniform=interpolate_to_uniform,
444444
)

0 commit comments

Comments
 (0)