Skip to content

Commit 1999d59

Browse files
committed
merge main
2 parents 4d031d6 + 023d823 commit 1999d59

26 files changed

+636
-67
lines changed

autolens/__init__.py

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

124124
conf.instance.register(__file__)
125125

126-
__version__ = "2024.9.21.2"
126+
__version__ = "2024.11.6.1"

autolens/aggregator/tracer.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ def _tracer_from(
4141
galaxies = instance.galaxies
4242

4343
if hasattr(instance, "extra_galaxies"):
44-
galaxies = galaxies + fit.instance.extra_galaxies
44+
if fit.instance.extra_galaxies is not None:
45+
galaxies = galaxies + fit.instance.extra_galaxies
4546

4647
else:
4748
galaxies = fit.instance.galaxies
4849

4950
if hasattr(fit.instance, "extra_galaxies"):
50-
galaxies = galaxies + fit.instance.extra_galaxies
51+
if fit.instance.extra_galaxies is not None:
52+
galaxies = galaxies + fit.instance.extra_galaxies
5153

5254
try:
5355
cosmology = instance.cosmology

autolens/analysis/result.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,36 @@ def positions_likelihood_from(
169169
use_resample=False,
170170
positions: Optional[aa.Grid2DIrregular] = None,
171171
) -> Union[PositionsLHPenalty, PositionsLHResample]:
172+
"""
173+
Returns a `PositionsLH` object from the result of a lens model-fit, where the maximum log likelihood mass
174+
and source models are used to determine the multiple image positions in the image-plane and source-plane
175+
and ray-trace them to the source-plane to determine the threshold.
176+
177+
In chained fits, for example the SLaM pipelines, this means that a simple initial fit (e.g. SIE mass model,
178+
parametric source) can be used to determine the multiple image positions and threshold for a more complex
179+
subsequent fit (e.g. power-law mass model, pixelized source).
180+
181+
Parameters
182+
----------
183+
factor
184+
The value the computed threshold is multiplied by to make the position threshold larger or smaller than the
185+
maximum log likelihood model's threshold.
186+
minimum_threshold
187+
The output threshold is rounded up to this value if it is below it, to avoid extremely small threshold
188+
values.
189+
use_resample
190+
If `False` the `PositionsLH` object is created using the `PositionsLHPenalty` class, which uses the
191+
threshold to apply a penalty term to the likelihood. If `True` the `PositionsLH` object is created using
192+
the `PositionsLHResample` class, which resamples the positions to the threshold.
193+
positions
194+
If input, these positions are used instead of the computed multiple image positions from the lens mass
195+
model.
196+
197+
Returns
198+
-------
199+
The `PositionsLH` object used to apply a likelihood penalty or resample the positions.
200+
"""
201+
172202
if os.environ.get("PYAUTOFIT_TEST_MODE") == "1":
173203
return None
174204

autolens/config/visualize/plots.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
psf: false
88
positions: # Settings for plots with resampling image-positions on (e.g. the image).
99
image_with_positions: true
10+
point_dataset: # Settings for plots of point source datasets (e.g. PointDatasetPlotter).
11+
subplot_dataset: true # Plot subplot containing all dataset quantities (e.g. the data, noise-map, etc.)?
12+
positions: false # Plot the positions of th multiple images of the point source in the image plane?
13+
fluxes: false # Plot the fluxes of the multiple images of the point source in the image plane?
1014
fit: # Settings for plots of all fits (e.g. FitImagingPlotter, FitInterferometerPlotter).
1115
subplot_fit: true # Plot subplot of all fit quantities for any dataset (e.g. the model data, residual-map, etc.)?
1216
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?
@@ -25,6 +29,9 @@
2529
subtracted_images_of_planes: false # Plot individual plots of each plane's subtracted image?
2630
plane_images_of_planes: false # Plot individual plots of each plane's image (e.g. in the source plane)?
2731
fit_imaging: {} # Settings for plots of fits to imaging datasets (e.g. FitImagingPlotter).
32+
fit_point_dataset: # Settings for plots of fits to point source datasets (e.g. FitPointDatasetPlotter).
33+
positions: false # Plot the positions of th multiple images of the point source in the image plane?
34+
fluxes: false # Plot the fluxes of the multiple images of the point source in the image plane?
2835
tracer: # Settings for plots of tracers (e.g. TracerPlotter).
2936
subplot_tracer: true # Plot subplot of all quantities in each tracer (e.g. images, convergence)?
3037
all_at_end_png: true # Plot all individual plots listed below as .png (even if False)?

autolens/imaging/plot/fit_imaging_plotters.py

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ 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,
152+
plane_signal_to_noise_map: bool = False,
151153
use_source_vmax: bool = False,
152154
zoom_to_brightest: bool = True,
153155
interpolate_to_uniform: bool = False,
@@ -178,6 +180,14 @@ def figures_2d_of_planes(
178180
Whether to make a 2D plot (via `imshow`) of the image of a plane in its source-plane (e.g. unlensed).
179181
Depending on how the fit is performed, this could either be an image of light profiles of the reconstruction
180182
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.
187+
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,
189+
where the signal-to-noise map values can only be computed when a pixelized source reconstruction and they
190+
are the ratio of reconstructed flux to error in each pixel.
181191
use_source_vmax
182192
If `True`, the maximum value of the lensed source (e.g. in the image-plane) is used to set the `vmax` of
183193
certain plots (e.g. the `data`) in order to ensure the lensed source is visible compared to the lens.
@@ -283,6 +293,14 @@ def figures_2d_of_planes(
283293

284294
elif self.tracer.planes[plane_index].has(cls=aa.Pixelization):
285295

296+
pix = self.tracer.planes[plane_index].cls_list_from(cls=aa.Pixelization)[0]
297+
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+
286304
inversion_plotter = self.inversion_plotter_of_plane(
287305
plane_index=plane_index
288306
)
@@ -294,8 +312,41 @@ def figures_2d_of_planes(
294312
interpolate_to_uniform=interpolate_to_uniform
295313
)
296314

297-
if use_source_vmax:
298-
self.mat_plot_2d.cmap.kwargs.pop("vmax")
315+
if use_source_vmax:
316+
try:
317+
self.mat_plot_2d.cmap.kwargs.pop("vmax")
318+
except KeyError:
319+
pass
320+
321+
if plane_errors:
322+
323+
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
324+
325+
inversion_plotter = self.inversion_plotter_of_plane(
326+
plane_index=plane_index
327+
)
328+
329+
inversion_plotter.figures_2d_of_pixelization(
330+
pixelization_index=0,
331+
errors=True,
332+
zoom_to_brightest=zoom_to_brightest,
333+
interpolate_to_uniform=interpolate_to_uniform
334+
)
335+
336+
if plane_signal_to_noise_map:
337+
338+
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
339+
340+
inversion_plotter = self.inversion_plotter_of_plane(
341+
plane_index=plane_index
342+
)
343+
344+
inversion_plotter.figures_2d_of_pixelization(
345+
pixelization_index=0,
346+
signal_to_noise_map=True,
347+
zoom_to_brightest=zoom_to_brightest,
348+
interpolate_to_uniform=interpolate_to_uniform
349+
)
299350

300351
def subplot_of_planes(self, plane_index: Optional[int] = None):
301352
"""
@@ -614,7 +665,12 @@ def subplot_mappings_of_plane(self, plane_index: Optional[int] = None, auto_file
614665
"total_mappings_pixels"
615666
]
616667

617-
pix_indexes = inversion_plotter.inversion.brightest_pixel_list_from(
668+
mapper = inversion_plotter.inversion.cls_list_from(cls=aa.AbstractMapper)[0]
669+
mapper_valued = aa.MapperValued(
670+
values=inversion_plotter.inversion.reconstruction_dict[mapper],
671+
mapper=mapper,
672+
)
673+
pix_indexes = mapper_valued.max_pixel_list_from(
618674
total_pixels=total_pixels, filter_neighbors=True
619675
)
620676

autolens/interferometer/plot/fit_interferometer_plotters.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,12 @@ def subplot_mappings_of_plane(
229229
"total_mappings_pixels"
230230
]
231231

232-
pix_indexes = inversion_plotter.inversion.brightest_pixel_list_from(
232+
mapper = inversion_plotter.inversion.cls_list_from(cls=aa.AbstractMapper)[0]
233+
mapper_valued = aa.MapperValued(
234+
values=inversion_plotter.inversion.reconstruction_dict[mapper],
235+
mapper=mapper,
236+
)
237+
pix_indexes = mapper_valued.max_pixel_list_from(
233238
total_pixels=total_pixels, filter_neighbors=True
234239
)
235240

@@ -370,7 +375,10 @@ def figures_2d_of_planes(
370375
self,
371376
plane_index: Optional[int] = None,
372377
plane_image: bool = False,
378+
plane_errors: bool = False,
379+
plane_signal_to_noise_map: bool = False,
373380
zoom_to_brightest: bool = True,
381+
interpolate_to_uniform: bool = False,
374382
):
375383
"""
376384
Plots images representing each individual `Plane` in the fit's `Tracer` in 2D, which are computed via the
@@ -390,9 +398,20 @@ def figures_2d_of_planes(
390398
Whether to make a 2D plot (via `imshow`) of the image of a plane in its source-plane (e.g. unlensed).
391399
Depending on how the fit is performed, this could either be an image of light profiles of the reconstruction
392400
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.
405+
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,
407+
where the signal-to-noise map values can only be computed when a pixelized source reconstruction and they
408+
are the ratio of reconstructed flux to error in each pixel.
393409
zoom_to_brightest
394410
For images not in the image-plane (e.g. the `plane_image`), whether to automatically zoom the plot to
395411
the brightest regions of the galaxies being plotted as opposed to the full extent of the grid.
412+
interpolate_to_uniform
413+
If `True`, the mapper's reconstruction is interpolated to a uniform grid before plotting, for example
414+
meaning that an irregular Delaunay grid can be plotted as a uniform grid.
396415
"""
397416
if plane_image:
398417
if not self.tracer.planes[plane_index].has(cls=aa.Pixelization):
@@ -408,6 +427,33 @@ def figures_2d_of_planes(
408427
pixelization_index=0,
409428
reconstruction=True,
410429
zoom_to_brightest=zoom_to_brightest,
430+
interpolate_to_uniform=interpolate_to_uniform,
431+
)
432+
433+
if plane_errors:
434+
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
435+
inversion_plotter = self.inversion_plotter_of_plane(
436+
plane_index=plane_index
437+
)
438+
439+
inversion_plotter.figures_2d_of_pixelization(
440+
pixelization_index=0,
441+
errors=True,
442+
zoom_to_brightest=zoom_to_brightest,
443+
interpolate_to_uniform=interpolate_to_uniform,
444+
)
445+
446+
if plane_signal_to_noise_map:
447+
if self.tracer.planes[plane_index].has(cls=aa.Pixelization):
448+
inversion_plotter = self.inversion_plotter_of_plane(
449+
plane_index=plane_index
450+
)
451+
452+
inversion_plotter.figures_2d_of_pixelization(
453+
pixelization_index=0,
454+
signal_to_noise_map=True,
455+
zoom_to_brightest=zoom_to_brightest,
456+
interpolate_to_uniform=interpolate_to_uniform,
411457
)
412458

413459
def subplot_fit_real_space(self):

autolens/lens/sensitivity.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,109 @@ def set_auto_filename(
360360

361361
return False
362362

363+
def subplot_sensitivity(self):
364+
365+
log_likelihoods = self.result.figure_of_merit_array(
366+
use_log_evidences=False,
367+
remove_zeros=True,
368+
)
369+
370+
try:
371+
log_evidences = self.result.figure_of_merit_array(
372+
use_log_evidences=True,
373+
remove_zeros=True,
374+
)
375+
except TypeError:
376+
log_evidences = np.zeros_like(log_likelihoods)
377+
378+
self.open_subplot_figure(number_subplots=8, subplot_shape=(2,4))
379+
380+
plotter = aplt.Array2DPlotter(
381+
array=self.data_subtracted,
382+
mat_plot_2d=self.mat_plot_2d,
383+
)
384+
385+
plotter.figure_2d()
386+
387+
self.mat_plot_2d.plot_array(
388+
array=log_evidences,
389+
visuals_2d=self.visuals_2d,
390+
auto_labels=AutoLabels(title="Increase in Log Evidence"),
391+
)
392+
393+
self.mat_plot_2d.plot_array(
394+
array=log_likelihoods,
395+
visuals_2d=self.visuals_2d,
396+
auto_labels=AutoLabels(title="Increase in Log Likelihood"),
397+
)
398+
399+
above_threshold = np.where(log_likelihoods > 5.0, 1.0, 0.0)
400+
401+
above_threshold = aa.Array2D(
402+
values=above_threshold,
403+
mask=log_likelihoods.mask
404+
)
405+
406+
self.mat_plot_2d.plot_array(
407+
array=above_threshold,
408+
visuals_2d=self.visuals_2d,
409+
auto_labels=AutoLabels(title="Log Likelihood > 5.0"),
410+
)
411+
412+
try:
413+
log_evidences_base = self.result._array_2d_from(self.result.log_evidences_base)
414+
log_evidences_perturbed = self.result._array_2d_from(self.result.log_evidences_perturbed)
415+
416+
log_evidences_base_min = np.nanmin(np.where(log_evidences_base == 0, np.nan, log_evidences_base))
417+
log_evidences_base_max = np.nanmax(np.where(log_evidences_base == 0, np.nan, log_evidences_base))
418+
log_evidences_perturbed_min = np.nanmin(np.where(log_evidences_perturbed == 0, np.nan, log_evidences_perturbed))
419+
log_evidences_perturbed_max = np.nanmax(np.where(log_evidences_perturbed == 0, np.nan, log_evidences_perturbed))
420+
421+
self.mat_plot_2d.cmap.kwargs["vmin"] = np.min([log_evidences_base_min, log_evidences_perturbed_min])
422+
self.mat_plot_2d.cmap.kwargs["vmax"] = np.max([log_evidences_base_max, log_evidences_perturbed_max])
423+
424+
self.mat_plot_2d.plot_array(
425+
array=log_evidences_base,
426+
visuals_2d=self.visuals_2d,
427+
auto_labels=AutoLabels(title="Log Evidence Base"),
428+
)
429+
430+
self.mat_plot_2d.plot_array(
431+
array=log_evidences_perturbed,
432+
visuals_2d=self.visuals_2d,
433+
auto_labels=AutoLabels(title="Log Evidence Perturb"),
434+
435+
)
436+
except TypeError:
437+
pass
438+
439+
log_likelihoods_base = self.result._array_2d_from(self.result.log_likelihoods_base)
440+
log_likelihoods_perturbed = self.result._array_2d_from(self.result.log_likelihoods_perturbed)
441+
442+
log_likelihoods_base_min = np.nanmin(np.where(log_likelihoods_base == 0, np.nan, log_likelihoods_base))
443+
log_likelihoods_base_max = np.nanmax(np.where(log_likelihoods_base == 0, np.nan, log_likelihoods_base))
444+
log_likelihoods_perturbed_min = np.nanmin(np.where(log_likelihoods_perturbed == 0, np.nan, log_likelihoods_perturbed))
445+
log_likelihoods_perturbed_max = np.nanmax(np.where(log_likelihoods_perturbed == 0, np.nan, log_likelihoods_perturbed))
446+
447+
self.mat_plot_2d.cmap.kwargs["vmin"] = np.min([log_likelihoods_base_min, log_likelihoods_perturbed_min])
448+
self.mat_plot_2d.cmap.kwargs["vmax"] = np.max([log_likelihoods_base_max, log_likelihoods_perturbed_max])
449+
450+
self.mat_plot_2d.plot_array(
451+
array=log_likelihoods_base,
452+
visuals_2d=self.visuals_2d,
453+
auto_labels=AutoLabels(title="Log Likelihood Base"),
454+
)
455+
456+
self.mat_plot_2d.plot_array(
457+
array=log_likelihoods_perturbed,
458+
visuals_2d=self.visuals_2d,
459+
auto_labels=AutoLabels(title="Log Likelihood Perturb"),
460+
)
461+
462+
self.mat_plot_2d.output.subplot_to_figure(auto_filename="subplot_sensitivity")
463+
464+
self.close_subplot_figure()
465+
363466
def subplot_figures_of_merit_grid(
364467
self,
365468
use_log_evidences: bool = True,

0 commit comments

Comments
 (0)