diff --git a/autogalaxy/abstract_fit.py b/autogalaxy/abstract_fit.py index d0581f41a..6747fb4c5 100644 --- a/autogalaxy/abstract_fit.py +++ b/autogalaxy/abstract_fit.py @@ -117,7 +117,8 @@ def linear_light_profile_intensity_dict( return linear_light_profile_intensity_dict def galaxy_linear_obj_data_dict_from( - self, use_image: bool = False + self, + use_operated: bool = True, ) -> Dict[Galaxy, aa.Array2D]: """ Returns a dictionary mapping every galaxy containing a linear @@ -129,16 +130,17 @@ def galaxy_linear_obj_data_dict_from( This is used to create the overall `galaxy_model_image_dict`, which maps every galaxy to its overall `model_data` (e.g. including the `model_data` of orindary light profiles too). - If `use_image=False`, the `reconstructed_data` of the inversion (e.g. an image for dataset data, + If `use_operated=False`, the `reconstructed_data` of the inversion (e.g. an image for dataset data, visibilities for interferometer data) is input in the dictionary. - if `use_image=True`, the `reconstructed_image` of the inversion (e.g. the image for dataset data, the + if `use_operated=True`, the `reconstructed_operated_data` of the inversion (e.g. the image for dataset data, the real-space image for interferometer data) is input in the dictionary. Parameters ---------- - use_image - Whether to put the reconstructed data or images in the dictionary. + use_operated + Whether to use the operated (e.g PSF convolved) images of the linear objects in the dictionary, or + the unoperated images. Returns ------- @@ -156,13 +158,12 @@ def galaxy_linear_obj_data_dict_from( except KeyError: continue - if not use_image: - mapped_reconstructed = self.inversion.mapped_reconstructed_data_dict[ - linear_obj - ] - + if use_operated: + mapped_reconstructed = ( + self.inversion.mapped_reconstructed_operated_data_dict[linear_obj] + ) else: - mapped_reconstructed = self.inversion.mapped_reconstructed_image_dict[ + mapped_reconstructed = self.inversion.mapped_reconstructed_data_dict[ linear_obj ] diff --git a/autogalaxy/config/visualize/plots.yaml b/autogalaxy/config/visualize/plots.yaml index b61299e42..20c0f09e5 100644 --- a/autogalaxy/config/visualize/plots.yaml +++ b/autogalaxy/config/visualize/plots.yaml @@ -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.)? @@ -23,7 +23,8 @@ fit: # Settings for plots of all fits (e.g subplot_of_galaxies: false # Plot subplot of the model-image, subtracted image and other quantities of each galaxy? subplot_galaxy_images: false # Plot subplot of the image of each galaxy 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). diff --git a/autogalaxy/imaging/fit_imaging.py b/autogalaxy/imaging/fit_imaging.py index dfa777f16..dc8b0fd56 100644 --- a/autogalaxy/imaging/fit_imaging.py +++ b/autogalaxy/imaging/fit_imaging.py @@ -161,10 +161,37 @@ 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[Galaxy, np.ndarray]: + """ + A dictionary which associates every galaxy in the fit with its image 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 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.galaxies.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[Galaxy, np.ndarray]: """ @@ -187,7 +214,7 @@ def galaxy_model_image_dict(self) -> Dict[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} diff --git a/autogalaxy/imaging/model/plotter_interface.py b/autogalaxy/imaging/model/plotter_interface.py index e562be12a..a8655856b 100644 --- a/autogalaxy/imaging/model/plotter_interface.py +++ b/autogalaxy/imaging/model/plotter_interface.py @@ -60,6 +60,22 @@ def fits_to_fits( hdu_list.writeto(image_path / "fit.fits", overwrite=True) + if should_plot("fits_galaxy_images"): + number_plots = len(fit.galaxy_image_dict.keys()) + 1 + + image_list = [image.native_for_fits for image in fit.galaxy_image_dict.values()] + + hdu_list = hdu_list_for_output_from( + values_list=[image_list[0].mask.astype("float")] + image_list, + ext_name_list=[ + "mask", + ] + + [f"galaxy_{i}" for i in range(number_plots)], + header_dict=fit.mask.header_dict, + ) + + hdu_list.writeto(image_path / "galaxy_images.fits", overwrite=True) + if should_plot("fits_model_galaxy_images"): number_plots = len(fit.galaxy_model_image_dict.keys()) + 1 diff --git a/autogalaxy/interferometer/fit_interferometer.py b/autogalaxy/interferometer/fit_interferometer.py index 8f0bdacdf..f9a5d0a81 100644 --- a/autogalaxy/interferometer/fit_interferometer.py +++ b/autogalaxy/interferometer/fit_interferometer.py @@ -139,12 +139,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[Galaxy, np.ndarray]: + def galaxy_image_dict(self) -> Dict[Galaxy, np.ndarray]: """ A dictionary which associates every galaxy with its `image`. @@ -157,15 +160,13 @@ def galaxy_model_image_dict(self) -> Dict[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.galaxies.galaxy_image_2d_dict_from( - grid=self.grids.lp - ) + galaxy_image_dict = self.galaxies.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[Galaxy, np.ndarray]: @@ -186,7 +187,7 @@ def galaxy_model_visibilities_dict(self) -> Dict[Galaxy, np.ndarray]: ) galaxy_linear_obj_data_dict = self.galaxy_linear_obj_data_dict_from( - use_image=False + use_operated=True ) return {**galaxy_model_visibilities_dict, **galaxy_linear_obj_data_dict} diff --git a/autogalaxy/interferometer/model/plotter_interface.py b/autogalaxy/interferometer/model/plotter_interface.py index a5df14d04..afefab74e 100644 --- a/autogalaxy/interferometer/model/plotter_interface.py +++ b/autogalaxy/interferometer/model/plotter_interface.py @@ -35,20 +35,18 @@ def fits_to_fits( The fit to output to a .fits file. """ - if should_plot("fits_model_galaxy_images"): + if should_plot("fits_galaxy_images"): - image_list = [ - image.native_for_fits for image in fit.galaxy_model_image_dict.values() - ] + image_list = [image.native_for_fits for image in fit.galaxy_image_dict.values()] hdu_list = hdu_list_for_output_from( values_list=[image_list[0].mask.astype("float")] + image_list, ext_name_list=["mask"] - + [f"galaxy_{i}" for i in range(len(fit.galaxy_model_image_dict.values()))], + + [f"galaxy_{i}" for i in range(len(fit.galaxy_image_dict.values()))], header_dict=fit.dataset.real_space_mask.header_dict, ) - hdu_list.writeto(image_path / "model_galaxy_images.fits", overwrite=True) + hdu_list.writeto(image_path / "galaxy_images.fits", overwrite=True) if should_plot("fits_dirty_images"): diff --git a/autogalaxy/interferometer/plot/fit_interferometer_plotters.py b/autogalaxy/interferometer/plot/fit_interferometer_plotters.py index 8a671605b..de764522b 100644 --- a/autogalaxy/interferometer/plot/fit_interferometer_plotters.py +++ b/autogalaxy/interferometer/plot/fit_interferometer_plotters.py @@ -179,7 +179,7 @@ def subplot_fit_real_space(self): mapper_index = 0 self.inversion_plotter.figures_2d_of_pixelization( - pixelization_index=mapper_index, reconstructed_image=True + pixelization_index=mapper_index, reconstructed_operated_data=True ) self.inversion_plotter.figures_2d_of_pixelization( pixelization_index=mapper_index, reconstruction=True diff --git a/test_autogalaxy/config/visualize.yaml b/test_autogalaxy/config/visualize.yaml index 754ce9375..bc57d7878 100644 --- a/test_autogalaxy/config/visualize.yaml +++ b/test_autogalaxy/config/visualize.yaml @@ -331,13 +331,15 @@ mat_wrap_2d: marker: . s: 17 plots: + fits_are_zoomed: true dataset: subplot_dataset: true fit: subplot_fit: true subplot_of_galaxies: 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: fits_dirty_images: true # output dirty_images.fits showing the dirty image, noise-map, model-data, resiual-map, normalized residual map and chi-squared map? diff --git a/test_autogalaxy/galaxy/test_to_inversion.py b/test_autogalaxy/galaxy/test_to_inversion.py index dcf87d2bf..55a3ec6c6 100644 --- a/test_autogalaxy/galaxy/test_to_inversion.py +++ b/test_autogalaxy/galaxy/test_to_inversion.py @@ -180,7 +180,7 @@ def test__inversion_imaging_from(grid_2d_7x7, masked_imaging_7x7): inversion = to_inversion.inversion - assert inversion.mapped_reconstructed_image == pytest.approx( + assert inversion.mapped_reconstructed_operated_data == pytest.approx( masked_imaging_7x7.data, 1.0e-2 ) @@ -215,7 +215,7 @@ def test__inversion_interferometer_from(grid_2d_7x7, interferometer_7): inversion = to_inversion.inversion - assert inversion.mapped_reconstructed_data.real == pytest.approx( + assert inversion.mapped_reconstructed_operated_data.real == pytest.approx( interferometer_7.data.real, 1.0e-2 ) diff --git a/test_autogalaxy/imaging/test_fit_imaging.py b/test_autogalaxy/imaging/test_fit_imaging.py index 3bc9bbcc7..030d8593a 100644 --- a/test_autogalaxy/imaging/test_fit_imaging.py +++ b/test_autogalaxy/imaging/test_fit_imaging.py @@ -234,6 +234,73 @@ def test__fit__model_dataset__grid_offset__handles_special_behaviour( assert fit.figure_of_merit == pytest.approx(-22.914118686169, 1.0e-4) +def test__galaxy_image_dict(masked_imaging_7x7): + # Normal Light Profiles Only + + g0 = ag.Galaxy(redshift=0.5, bulge=ag.lp.Sersic(intensity=1.0)) + g1 = ag.Galaxy(redshift=0.5, bulge=ag.lp.Sersic(intensity=2.0)) + g2 = ag.Galaxy( + redshift=0.5, + light_profile_0=ag.lp.Sersic(intensity=1.0), + light_profile_1=ag.lp.Sersic(intensity=2.0), + ) + g3 = ag.Galaxy(redshift=0.5) + + fit = ag.FitImaging(dataset=masked_imaging_7x7, galaxies=[g0, g1, g2, g3]) + + g0_image_2d = g0.image_2d_from( + grid=masked_imaging_7x7.grids.lp, + ) + + g1_image_2d = g1.image_2d_from( + grid=masked_imaging_7x7.grids.lp, + ) + + assert fit.galaxy_image_dict[g0] == pytest.approx(g0_image_2d.array, 1.0e-4) + assert fit.galaxy_image_dict[g1] == pytest.approx(g1_image_2d.array, 1.0e-4) + assert fit.galaxy_image_dict[g2] == pytest.approx( + g0_image_2d.array + g1_image_2d.array, 1.0e-4 + ) + assert (fit.galaxy_image_dict[g3].slim == np.zeros(9)).all() + + # Linear Light PRofiles + Pixelization + Regularizaiton + + g0 = ag.Galaxy(redshift=0.5, bulge=ag.lp.Sersic(intensity=1.0, centre=(0.05, 0.05))) + g1_linear = ag.Galaxy(redshift=0.5, bulge=ag.lp_linear.Sersic(centre=(0.05, 0.05))) + + pixelization = ag.Pixelization( + mesh=ag.mesh.RectangularUniform(shape=(3, 3)), + regularization=ag.reg.Constant(coefficient=1.0), + ) + + galaxy_pix_0 = ag.Galaxy(redshift=0.5, pixelization=pixelization) + galaxy_pix_1 = ag.Galaxy(redshift=0.5, pixelization=pixelization) + + masked_imaging_7x7.data[0] = 3.0 + + fit = ag.FitImaging( + dataset=masked_imaging_7x7, + galaxies=[g0, g1_linear, g3, galaxy_pix_0, galaxy_pix_1], + ) + + assert (fit.galaxy_image_dict[g3] == np.zeros(9)).all() + + assert fit.galaxy_image_dict[g0][4] == pytest.approx(23.944378406, 1.0e-4) + assert fit.galaxy_image_dict[g1_linear][4] == pytest.approx(-28.1424200, 1.0e-4) + assert fit.galaxy_image_dict[galaxy_pix_0][4] == pytest.approx(1.107972830, 1.0e-4) + assert fit.galaxy_image_dict[galaxy_pix_1][4] == pytest.approx(1.1079728213, 1.0e-4) + + mapped_reconstructed_data = ( + fit.galaxy_image_dict[g1_linear] + + fit.galaxy_image_dict[galaxy_pix_0] + + fit.galaxy_image_dict[galaxy_pix_1] + ) + + assert mapped_reconstructed_data == pytest.approx( + fit.inversion.mapped_reconstructed_data.array, 1.0e-4 + ) + + def test__galaxy_model_image_dict(masked_imaging_7x7): # Normal Light Profiles Only @@ -309,7 +376,7 @@ def test__galaxy_model_image_dict(masked_imaging_7x7): assert fit.galaxy_model_image_dict[g1][4] == pytest.approx(1.25795063, 1.0e-4) assert fit.galaxy_model_image_dict[g1].native.array == pytest.approx( - fit.inversion.mapped_reconstructed_image.native.array, 1.0e-4 + fit.inversion.mapped_reconstructed_operated_data.native.array, 1.0e-4 ) assert fit.model_data.native.array == pytest.approx( @@ -349,19 +416,19 @@ def test__galaxy_model_image_dict(masked_imaging_7x7): 1.10780906, 1.0e-4 ) - mapped_reconstructed_image = ( + mapped_reconstructed_operated_data = ( fit.galaxy_model_image_dict[g1_linear] + fit.galaxy_model_image_dict[galaxy_pix_0] + fit.galaxy_model_image_dict[galaxy_pix_1] ) - assert mapped_reconstructed_image == pytest.approx( - fit.inversion.mapped_reconstructed_image.array, 1.0e-4 + assert mapped_reconstructed_operated_data == pytest.approx( + fit.inversion.mapped_reconstructed_operated_data.array, 1.0e-4 ) assert fit.model_data == pytest.approx( fit.galaxy_model_image_dict[g0].array - + fit.inversion.mapped_reconstructed_image.array, + + fit.inversion.mapped_reconstructed_operated_data.array, 1.0e-4, ) diff --git a/test_autogalaxy/interferometer/test_fit_interferometer.py b/test_autogalaxy/interferometer/test_fit_interferometer.py index 6731675bf..4dcb55648 100644 --- a/test_autogalaxy/interferometer/test_fit_interferometer.py +++ b/test_autogalaxy/interferometer/test_fit_interferometer.py @@ -109,7 +109,7 @@ def test__fit_figure_of_merit(interferometer_7): assert fit.figure_of_merit == pytest.approx(-37.4081355120388, 1.0e-4) -def test___galaxy_model_image_dict(interferometer_7): +def test___galaxy_image_dict(interferometer_7): # Normal Light Profiles Only g0 = ag.Galaxy(redshift=0.5, bulge=ag.lp.Sersic(intensity=1.0, centre=(0.05, 0.05))) @@ -128,9 +128,9 @@ def test___galaxy_model_image_dict(interferometer_7): g0_image = g0.image_2d_from(grid=interferometer_7.grids.lp) g1_image = g1.image_2d_from(grid=interferometer_7.grids.lp) - assert fit.galaxy_model_image_dict[g0] == pytest.approx(g0_image.array, 1.0e-4) - assert fit.galaxy_model_image_dict[g1] == pytest.approx(g1_image.array, 1.0e-4) - assert fit.galaxy_model_image_dict[g2] == pytest.approx( + assert fit.galaxy_image_dict[g0] == pytest.approx(g0_image.array, 1.0e-4) + assert fit.galaxy_image_dict[g1] == pytest.approx(g1_image.array, 1.0e-4) + assert fit.galaxy_image_dict[g2] == pytest.approx( g0_image.array + g1_image.array, 1.0e-4 ) @@ -143,9 +143,7 @@ def test___galaxy_model_image_dict(interferometer_7): galaxies=[g0_linear], ) - assert fit.galaxy_model_image_dict[g0_linear][4] == pytest.approx( - 0.9876689631, 1.0e-4 - ) + assert fit.galaxy_image_dict[g0_linear][4] == pytest.approx(0.9876689631, 1.0e-4) # Pixelization + Regularizaiton only @@ -181,10 +179,10 @@ def test___galaxy_model_image_dict(interferometer_7): linear_obj_list=[mapper], ) - assert (fit.galaxy_model_image_dict[g0].native == 0.0 + 0.0j * np.zeros((7,))).all() + assert (fit.galaxy_image_dict[g0].native == 0.0 + 0.0j * np.zeros((7,))).all() - assert fit.galaxy_model_image_dict[galaxy_pix_0].array == pytest.approx( - inversion.mapped_reconstructed_image.slim.array, 1.0e-4 + assert fit.galaxy_image_dict[galaxy_pix_0].array == pytest.approx( + inversion.mapped_reconstructed_data.slim.array, 1.0e-4 ) # Linear Light PRofiles + Pixelization + Regularizaiton @@ -201,25 +199,19 @@ def test___galaxy_model_image_dict(interferometer_7): galaxies=[g0_linear, g1, galaxy_pix_0, galaxy_pix_1], ) - assert fit.galaxy_model_image_dict[g0_linear][4] == pytest.approx( - -46.8820117, 1.0e-2 - ) - assert fit.galaxy_model_image_dict[g1] == pytest.approx(g1_image.array, 1.0e-4) - assert fit.galaxy_model_image_dict[galaxy_pix_0][4] == pytest.approx( - -0.00541699, 1.0e-2 - ) - assert fit.galaxy_model_image_dict[galaxy_pix_1][4] == pytest.approx( - -0.00563034, 1.0e-2 - ) + assert fit.galaxy_image_dict[g0_linear][4] == pytest.approx(-46.8820117, 1.0e-2) + assert fit.galaxy_image_dict[g1] == pytest.approx(g1_image.array, 1.0e-4) + assert fit.galaxy_image_dict[galaxy_pix_0][4] == pytest.approx(-0.00541699, 1.0e-2) + assert fit.galaxy_image_dict[galaxy_pix_1][4] == pytest.approx(-0.00563034, 1.0e-2) - mapped_reconstructed_image = ( - fit.galaxy_model_image_dict[g0_linear] - + fit.galaxy_model_image_dict[galaxy_pix_0] - + fit.galaxy_model_image_dict[galaxy_pix_1] + mapped_reconstructed_data = ( + fit.galaxy_image_dict[g0_linear] + + fit.galaxy_image_dict[galaxy_pix_0] + + fit.galaxy_image_dict[galaxy_pix_1] ) - assert mapped_reconstructed_image.array == pytest.approx( - fit.inversion.mapped_reconstructed_image.array, 1.0e-4 + assert mapped_reconstructed_data.array == pytest.approx( + fit.inversion.mapped_reconstructed_data.array, 1.0e-4 ) @@ -306,7 +298,7 @@ def test___galaxy_model_visibilities_dict(interferometer_7): assert (fit.galaxy_model_visibilities_dict[g0] == 0.0 + 0.0j * np.zeros((7,))).all() assert fit.galaxy_model_visibilities_dict[galaxy_pix_0].array == pytest.approx( - inversion.mapped_reconstructed_data.array, 1.0e-4 + inversion.mapped_reconstructed_operated_data.array, 1.0e-4 ) # Linear Light PRofiles + Pixelization + Regularizaiton @@ -343,7 +335,7 @@ def test___galaxy_model_visibilities_dict(interferometer_7): ) assert mapped_reconstructed_visibilities.array == pytest.approx( - fit.inversion.mapped_reconstructed_data.array, 1.0e-4 + fit.inversion.mapped_reconstructed_operated_data.array, 1.0e-4 ) diff --git a/test_autogalaxy/interferometer/test_simulate_and_fit_interferometer.py b/test_autogalaxy/interferometer/test_simulate_and_fit_interferometer.py index ba64d8968..d4b178cc4 100644 --- a/test_autogalaxy/interferometer/test_simulate_and_fit_interferometer.py +++ b/test_autogalaxy/interferometer/test_simulate_and_fit_interferometer.py @@ -204,7 +204,7 @@ def test__linear_light_profiles_agree_with_standard_light_profiles(): galaxy_image = galaxy.image_2d_from(grid=dataset.grids.lp) - assert fit_linear.galaxy_model_image_dict[galaxy_linear] == pytest.approx( + assert fit_linear.galaxy_image_dict[galaxy_linear] == pytest.approx( galaxy_image.array, 1.0e-4 ) diff --git a/test_autogalaxy/plot/mat_wrap/config/visualize/plots.ini b/test_autogalaxy/plot/mat_wrap/config/visualize/plots.ini index ddf91ea9a..838af48ce 100644 --- a/test_autogalaxy/plot/mat_wrap/config/visualize/plots.ini +++ b/test_autogalaxy/plot/mat_wrap/config/visualize/plots.ini @@ -27,7 +27,7 @@ model_images_of_galaxies=False [inversion] all_at_end_png=False subplot_inversion=True -reconstructed_image=False +reconstructed_operated_data=False reconstruction=False reconstruction_noise_map=False residual_map=False