From 48c39efded98c9db0bfe488744162d5093a6f633 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Sat, 31 May 2025 17:39:20 +0100 Subject: [PATCH] all unit tests fixed --- autogalaxy/ellipse/ellipse/ellipse.py | 17 +-- autogalaxy/ellipse/fit_ellipse.py | 55 +-------- .../ellipse/plot/fit_ellipse_plotters.py | 6 +- autogalaxy/gui/scribbler.py | 9 +- autogalaxy/operate/deflections.py | 35 +++--- .../ellipse/ellipse/test_ellipse.py | 1 - .../ellipse/model/test_analysis_ellipse.py | 8 +- test_autogalaxy/ellipse/test_fit_ellipse.py | 116 ++---------------- test_autogalaxy/operate/test_deflections.py | 9 +- 9 files changed, 57 insertions(+), 199 deletions(-) diff --git a/autogalaxy/ellipse/ellipse/ellipse.py b/autogalaxy/ellipse/ellipse/ellipse.py index 1578c9bac..8986d085f 100644 --- a/autogalaxy/ellipse/ellipse/ellipse.py +++ b/autogalaxy/ellipse/ellipse/ellipse.py @@ -106,7 +106,7 @@ def total_points_from(self, pixel_scale: float) -> int: return np.min([500, int(np.round(circular_radius_pixels, 1))]) - def angles_from_x0_from(self, pixel_scale: float, n_i : int = 0) -> np.ndarray: + def angles_from_x0_from(self, pixel_scale: float, n_i: int = 0) -> np.ndarray: """ Returns the angles from the x-axis to a discrete number of points ranging from 0.0 to 2.0 * np.pi radians. @@ -138,7 +138,9 @@ def angles_from_x0_from(self, pixel_scale: float, n_i : int = 0) -> np.ndarray: return np.linspace(0.0, 2.0 * np.pi, total_points + n_i)[:-1] - def ellipse_radii_from_major_axis_from(self, pixel_scale: float, n_i : int = 0) -> np.ndarray: + def ellipse_radii_from_major_axis_from( + self, pixel_scale: float, n_i: int = 0 + ) -> np.ndarray: """ Returns the distance from the centre of the ellipse to every point on the ellipse, which are called the ellipse radii. @@ -173,7 +175,7 @@ def ellipse_radii_from_major_axis_from(self, pixel_scale: float, n_i : int = 0) ), ) - def x_from_major_axis_from(self, pixel_scale: float, n_i : int = 0) -> np.ndarray: + def x_from_major_axis_from(self, pixel_scale: float, n_i: int = 0) -> np.ndarray: """ Returns the x-coordinates of the points on the ellipse, starting from the x-coordinate of the major-axis of the ellipse after rotation by its `angle` and moving counter-clockwise. @@ -198,9 +200,7 @@ def x_from_major_axis_from(self, pixel_scale: float, n_i : int = 0) -> np.ndarra return ellipse_radii_from_major_axis * np.cos(angles_from_x0) + self.centre[1] - def y_from_major_axis_from( - self, pixel_scale: float, n_i : int = 0 - ) -> np.ndarray: + def y_from_major_axis_from(self, pixel_scale: float, n_i: int = 0) -> np.ndarray: """ Returns the y-coordinates of the points on the ellipse, starting from the y-coordinate of the major-axis of the ellipse after rotation by its `angle` and moving counter-clockwise. @@ -231,7 +231,10 @@ def y_from_major_axis_from( - self.centre[0] ) - def points_from_major_axis_from(self, pixel_scale: float, n_i : int = 0, + def points_from_major_axis_from( + self, + pixel_scale: float, + n_i: int = 0, ) -> np.ndarray: """ Returns the (y,x) coordinates of the points on the ellipse, starting from the major-axis of the ellipse diff --git a/autogalaxy/ellipse/fit_ellipse.py b/autogalaxy/ellipse/fit_ellipse.py index 237417349..fa5b3d7d0 100644 --- a/autogalaxy/ellipse/fit_ellipse.py +++ b/autogalaxy/ellipse/fit_ellipse.py @@ -70,8 +70,9 @@ def points_from_major_axis_from(self) -> np.ndarray: if total_points_required == total_points - total_points_masked: continue - points = self.ellipse.points_from_major_axis_from(pixel_scale=self.dataset.pixel_scales[0], - n_i=i) + points = self.ellipse.points_from_major_axis_from( + pixel_scale=self.dataset.pixel_scales[0], n_i=i + ) if i == i_total: @@ -108,52 +109,6 @@ def _points_from_major_axis(self) -> np.ndarray: """ return self.points_from_major_axis_from() - # @property - # def mask_interp(self) -> np.ndarray: - # """ - # Returns the mask values of the dataset that the ellipse fits, which are computed by overlaying the ellipse over - # the 2D data and performing a 2D interpolation at discrete (y,x) coordinates on the ellipse on the dataset's - # mask. - # - # When an input (y,x) coordinate intepolates only unmasked values (`data.mask=False`) the intepolatred value - # is 0.0, where if it interpolates one or a masked value (`data.mask=True`), the interpolated value is positive. - # To mask all values which interpolate a masked value, all interpolated values above 1 and converted to `True`. - # - # This mask is used to remove these pixels from a fit and evaluate how many ellipse points are used for each - # ellipse fit. - # - # The (y,x) coordinates on the ellipse where the interpolation occurs are computed in the - # `points_from_major_axis` property of the `Ellipse` class, with the documentation describing how these points - # are computed. - # - # Returns - # ------- - # The data values of the ellipse fits, computed via a 2D interpolation of where the ellipse - # overlaps the data. - # """ - # return self.interp.mask_interp(self._points_from_major_axis) > 0.0 - - # @property - # def total_points_interp(self) -> int: - # """ - # Returns the total number of points used to interpolate the data and noise-map values of the ellipse. - # - # For example, if the ellipse spans 10 pixels, the total number of points will be 10. - # - # The calculation removes points if one or more interpolated value uses a masked value, meaning the interpolation - # is not reliable. - # - # The (y,x) coordinates on the ellipse where the interpolation occurs are computed in the - # `points_from_major_axis` property of the `Ellipse` class, with the documentation describing how these points - # are computed. - # - # Returns - # ------- - # The noise-map values of the ellipse fits, computed via a 2D interpolation of where the ellipse - # overlaps the noise-map. - # """ - # return self.data_interp[np.invert(self.mask_interp)].shape[0] - @property def data_interp(self) -> aa.ArrayIrregular: """ @@ -174,8 +129,6 @@ def data_interp(self) -> aa.ArrayIrregular: """ data = self.interp.data_interp(self._points_from_major_axis) - # data[self.mask_interp] = np.nan - return aa.ArrayIrregular(values=data) @property @@ -198,8 +151,6 @@ def noise_map_interp(self) -> aa.ArrayIrregular: """ noise_map = self.interp.noise_map_interp(self._points_from_major_axis) - # noise_map[self.mask_interp] = np.nan - return aa.ArrayIrregular(values=noise_map) @property diff --git a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py index aac66bf1b..b6d99eeb7 100644 --- a/autogalaxy/ellipse/plot/fit_ellipse_plotters.py +++ b/autogalaxy/ellipse/plot/fit_ellipse_plotters.py @@ -88,16 +88,14 @@ def figures_2d( points = fit.points_from_major_axis_from() x = points[:, 1] - y = points[:, 0] * -1.0 # flip for plot + y = points[:, 0] * -1.0 # flip for plot ellipse_list.append(aa.Grid2DIrregular.from_yx_1d(y=y, x=x)) visuals_2d = self.get_visuals_2d() + Visuals2D( - positions=ellipse_list, - lines=ellipse_list + positions=ellipse_list, lines=ellipse_list ) - self.mat_plot_2d.plot_array( array=self.fit_list[0].data, visuals_2d=visuals_2d, diff --git a/autogalaxy/gui/scribbler.py b/autogalaxy/gui/scribbler.py index d108ca824..8362a0fee 100644 --- a/autogalaxy/gui/scribbler.py +++ b/autogalaxy/gui/scribbler.py @@ -4,6 +4,7 @@ import matplotlib.pyplot as plt from typing import Tuple + class Scribbler: def __init__( self, @@ -31,25 +32,25 @@ def __init__( origin = image.geometry.origin pixel_scales = image.geometry.pixel_scales - x0_pix = int( + x0_pix = int( (extent[0] - origin[1]) / pixel_scales[1] + central_pixel_coordinates[1] + 0.5 ) - x1_pix = int( + x1_pix = int( (extent[1] - origin[1]) / pixel_scales[1] + central_pixel_coordinates[1] + 0.5 ) - y0_pix = int( + y0_pix = int( (extent[2] - origin[0]) / pixel_scales[0] + central_pixel_coordinates[0] + 0.5 ) - y1_pix = int( + y1_pix = int( (extent[3] - origin[0]) / pixel_scales[0] + central_pixel_coordinates[0] + 0.5 diff --git a/autogalaxy/operate/deflections.py b/autogalaxy/operate/deflections.py index 8cdc1f154..be4ef24b1 100644 --- a/autogalaxy/operate/deflections.py +++ b/autogalaxy/operate/deflections.py @@ -114,27 +114,27 @@ def __eq__(self, other): def time_delay_geometry_term_from(self, grid) -> aa.Array2D: """ - Returns the geometric time delay term of the Fermat potential for a given grid of image-plane positions. + Returns the geometric time delay term of the Fermat potential for a given grid of image-plane positions. - This term is given by: + This term is given by: - .. math:: - \[\tau_{\text{geom}}(\boldsymbol{\theta}) = \frac{1}{2} |\boldsymbol{\theta} - \boldsymbol{\beta}|^2\] + .. math:: + \[\tau_{\text{geom}}(\boldsymbol{\theta}) = \frac{1}{2} |\boldsymbol{\theta} - \boldsymbol{\beta}|^2\] - where: - - \( \boldsymbol{\theta} \) is the image-plane coordinate, - - \( \boldsymbol{\beta} = \boldsymbol{\theta} - \boldsymbol{\alpha}(\boldsymbol{\theta}) \) is the source-plane coordinate, - - \( \boldsymbol{\alpha} \) is the deflection angle at each image-plane coordinate. + where: + - \( \boldsymbol{\theta} \) is the image-plane coordinate, + - \( \boldsymbol{\beta} = \boldsymbol{\theta} - \boldsymbol{\alpha}(\boldsymbol{\theta}) \) is the source-plane coordinate, + - \( \boldsymbol{\alpha} \) is the deflection angle at each image-plane coordinate. - Parameters - ---------- - grid - The 2D grid of (y,x) arc-second coordinates the deflection angles and time delay geometric term are computed - on. + Parameters + ---------- + grid + The 2D grid of (y,x) arc-second coordinates the deflection angles and time delay geometric term are computed + on. - Returns - ------- - The geometric time delay term at each grid position. + Returns + ------- + The geometric time delay term at each grid position. """ deflections = self.deflections_yx_2d_from(grid=grid) @@ -194,7 +194,8 @@ def time_delays_from(self, grid) -> aa.Array2D: deflections_yx = self.deflections_yx_2d_from(grid=grid) return aa.Array2D( - values=deflections_yx[:, 0] * grid[:, 0] + deflections_yx[:, 1] * grid[:, 1], + values=deflections_yx[:, 0] * grid[:, 0] + + deflections_yx[:, 1] * grid[:, 1], mask=grid.mask, ) diff --git a/test_autogalaxy/ellipse/ellipse/test_ellipse.py b/test_autogalaxy/ellipse/ellipse/test_ellipse.py index 57a863401..1b99a13ee 100644 --- a/test_autogalaxy/ellipse/ellipse/test_ellipse.py +++ b/test_autogalaxy/ellipse/ellipse/test_ellipse.py @@ -152,4 +152,3 @@ def test__points_from_major_axis(): assert ellipse.points_from_major_axis_from(pixel_scale=1.0)[1][0] == pytest.approx( -0.2123224755, 1.0e-4 ) - diff --git a/test_autogalaxy/ellipse/model/test_analysis_ellipse.py b/test_autogalaxy/ellipse/model/test_analysis_ellipse.py index a298cb49d..29cb4aead 100644 --- a/test_autogalaxy/ellipse/model/test_analysis_ellipse.py +++ b/test_autogalaxy/ellipse/model/test_analysis_ellipse.py @@ -11,8 +11,8 @@ def test__make_result__result_imaging_is_returned(masked_imaging_7x7): ellipse_list = af.Collection(af.Model(ag.Ellipse) for _ in range(2)) - ellipse_list[0].major_axis = 1.0 - ellipse_list[1].major_axis = 2.0 + ellipse_list[0].major_axis = 0.2 + ellipse_list[1].major_axis = 0.4 model = af.Collection(ellipses=ellipse_list) @@ -30,8 +30,8 @@ def test__figure_of_merit( ): ellipse_list = af.Collection(af.Model(ag.Ellipse) for _ in range(2)) - ellipse_list[0].major_axis = 1.0 - ellipse_list[1].major_axis = 2.0 + ellipse_list[0].major_axis = 0.2 + ellipse_list[1].major_axis = 0.4 multipole_0_prior_0 = af.UniformPrior(lower_limit=0.0, upper_limit=0.1) multipole_0_prior_1 = af.UniformPrior(lower_limit=0.0, upper_limit=0.1) diff --git a/test_autogalaxy/ellipse/test_fit_ellipse.py b/test_autogalaxy/ellipse/test_fit_ellipse.py index 73fcbd67d..110a4e4a7 100644 --- a/test_autogalaxy/ellipse/test_fit_ellipse.py +++ b/test_autogalaxy/ellipse/test_fit_ellipse.py @@ -79,18 +79,6 @@ def test___points_from_major_axis__multipole(imaging_lh): # assert fit.mask_interp == pytest.approx([False, True, True, True, True], 1.0e-4) -def test__total_points_interp(imaging_lh, imaging_lh_masked): - ellipse_0 = ag.Ellipse(centre=(0.0, 0.0), ell_comps=(0.0, 0.0), major_axis=1.0) - - fit = ag.FitEllipse(dataset=imaging_lh, ellipse=ellipse_0) - - assert fit.total_points_interp == 5 - - fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - - assert fit.total_points_interp == 1 - - def test__data_interp(imaging_lh, imaging_lh_masked): ellipse_0 = ag.Ellipse(centre=(0.0, 0.0), ell_comps=(0.0, 0.0), major_axis=1.0) @@ -102,8 +90,7 @@ def test__data_interp(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.data_interp[0] == pytest.approx(6.0, 1.0e-4) - assert np.isnan(fit.data_interp[1:5]).all() + assert fit.data_interp[0] == pytest.approx(1.8378134567395, 1.0e-4) def test__noise_map_interp(imaging_lh, imaging_lh_masked): @@ -116,7 +103,6 @@ def test__noise_map_interp(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) assert fit.noise_map_interp[0] == pytest.approx(2.0, 1.0e-4) - assert np.isnan(fit.noise_map_interp[1:5]).all() def test__signal_to_noise_map_interp(imaging_lh, imaging_lh_masked): @@ -130,8 +116,7 @@ def test__signal_to_noise_map_interp(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.signal_to_noise_map_interp[0] == pytest.approx(3.0, 1.0e-4) - assert np.isnan(fit.signal_to_noise_map_interp[1:5]).all() + assert fit.signal_to_noise_map_interp[0] == pytest.approx(0.91890672836, 1.0e-4) def test__residual_map(imaging_lh, imaging_lh_masked): @@ -145,8 +130,7 @@ def test__residual_map(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.residual_map[0] == pytest.approx(0.0, 1.0e-4) - assert np.isnan(fit.noise_map_interp[1:5]).all() + assert fit.residual_map[0] == pytest.approx(-2.514972947, 1.0e-4) def test__normalized_residual_map(imaging_lh, imaging_lh_masked): @@ -160,8 +144,7 @@ def test__normalized_residual_map(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.normalized_residual_map[0] == pytest.approx(0.0, 1.0e-4) - assert np.isnan(fit.noise_map_interp[1:5]).all() + assert fit.normalized_residual_map[0] == pytest.approx(-1.25748647, 1.0e-4) def test__chi_squared_map(imaging_lh, imaging_lh_masked): @@ -175,8 +158,7 @@ def test__chi_squared_map(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.chi_squared_map[0] == pytest.approx(0.0, 1.0e-4) - assert np.isnan(fit.noise_map_interp[1:5]).all() + assert fit.chi_squared_map[0] == pytest.approx(1.58127223199, 1.0e-4) def test__chi_squared(imaging_lh, imaging_lh_masked): @@ -190,7 +172,7 @@ def test__chi_squared(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.chi_squared == pytest.approx(0.0, 1.0e-4) + assert fit.chi_squared == pytest.approx(5.72639320225, 1.0e-4) def test__noise_normalization(imaging_lh, imaging_lh_masked): @@ -202,7 +184,7 @@ def test__noise_normalization(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.noise_normalization == pytest.approx(3.224171427, 1.0e-4) + assert fit.noise_normalization == pytest.approx(16.120857137646, 1.0e-4) def test__log_likelihood(imaging_lh, imaging_lh_masked): @@ -214,86 +196,4 @@ def test__log_likelihood(imaging_lh, imaging_lh_masked): fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - assert fit.log_likelihood == pytest.approx(0.0, 1.0e-4) - - -def test__points_from_major_axis_from__with_mask_interp_but_mask_all_false(imaging_lh, imaging_lh_masked): - - ellipse_0 = ag.Ellipse(centre=(0.0, 0.0), ell_comps=(0.0, 0.0), major_axis=1.0) - - # fit = ag.FitEllipse(dataset=imaging_lh, ellipse=ellipse_0) - # points = fit.points_from_major_axis_from() - - fit = ag.FitEllipse(dataset=imaging_lh_masked, ellipse=ellipse_0) - points_masked = fit.points_from_major_axis_from() - - assert points.shape[0] == points_masked.shape[0] == 5 - - fff - - - print(fit.points_from_major_axis_from()) - ffff - - assert fit.mask_interp == pytest.approx([False, True, True, True, True], 1.0e-4) - - ellipse = ag.Ellipse(centre=(0.0, 0.0), ell_comps=(0.0, 0.0), major_axis=1.0) - - points = ellipse.points_from_major_axis_from(pixel_scale=1.0) - - print(points) - - data = ag.Array2D.ones( - shape_native=(3, 3), - pixel_scales=1.0 - ) - noise_map = ag.Array2D.ones(shape_native=(3, 3), pixel_scales=1.0) - - mask = ag.Mask2D( - mask=np.array( - [[False, False, False], [False, False, False], [False, False, False]] - ), - pixel_scales=1.0, - ) - - dataset = ag.Imaging(data=data, noise_map=noise_map) - dataset = dataset.apply_mask(mask=mask) - interp = ag.DatasetInterp(dataset=dataset) - - assert ellipse.points_from_major_axis_from(pixel_scale=1.0, mask_interp=interp.mask_interp)[0][1] == pytest.approx( - 1.0, 1.0e-4 - ) - assert ellipse.points_from_major_axis_from(pixel_scale=1.0, mask_interp=interp.mask_interp)[0][0] == pytest.approx( - 0.0, 1.0e-4 - ) - - -def test__points_from_major_axis_from__with_mask_interp_but_mask_removes_points(): - ellipse = ag.Ellipse(centre=(0.0, 0.0), ell_comps=(0.0, 0.0), major_axis=1.0) - - data = ag.Array2D.ones( - shape_native=(3, 3), - pixel_scales=1.0 - ) - noise_map = ag.Array2D.ones(shape_native=(3, 3), pixel_scales=1.0) - - mask = ag.Mask2D( - mask=np.array( - [[False, False, False], [True, False, False], [False, False, True]] - ), - pixel_scales=1.0, - ) - - dataset = ag.Imaging(data=data, noise_map=noise_map) - dataset = dataset.apply_mask(mask=mask) - interp = ag.DatasetInterp(dataset=dataset) - - points = ellipse.points_from_major_axis_from(pixel_scale=1.0, mask_interp=interp.mask_interp) - - assert len(points) == 5 - assert points[1][1] == pytest.approx( - 1.0, 1.0e-4 - ) - # assert ellipse.points_from_major_axis_from(pixel_scale=1.0, mask_interp=interp.mask_interp)[0][0] == pytest.approx( - # 0.0, 1.0e-4 - # ) + assert fit.log_likelihood == pytest.approx(-0.169821080058, 1.0e-4) diff --git a/test_autogalaxy/operate/test_deflections.py b/test_autogalaxy/operate/test_deflections.py index daa18b252..a69414f88 100644 --- a/test_autogalaxy/operate/test_deflections.py +++ b/test_autogalaxy/operate/test_deflections.py @@ -55,6 +55,7 @@ def caustics_via_magnification_from(mass_profile, grid): return caustics + def test__time_delay_geometry_term_from(): grid = ag.Grid2DIrregular(values=[(0.7, 0.5), (1.0, 1.0)]) @@ -65,7 +66,9 @@ def test__time_delay_geometry_term_from(): time_delay_geometry_term = mp.time_delay_geometry_term_from(grid=grid) - assert time_delay_geometry_term == pytest.approx(np.array([1.92815688, 1.97625436]), 1.0e-4) + assert time_delay_geometry_term == pytest.approx( + np.array([1.92815688, 1.97625436]), 1.0e-4 + ) def test__fermat_potential_from(): @@ -78,7 +81,9 @@ def test__fermat_potential_from(): fermat_potential = mp.fermat_potential_from(grid=grid) - assert fermat_potential == pytest.approx(np.array([0.24329033, -0.82766592]), 1.0e-4) + assert fermat_potential == pytest.approx( + np.array([0.24329033, -0.82766592]), 1.0e-4 + ) def test__hessian_from():