From 0143da3b50ce3f462a7b679f75cb7934c0697278 Mon Sep 17 00:00:00 2001 From: James Nightingale Date: Thu, 13 Aug 2026 21:36:39 -0400 Subject: [PATCH 1/2] fix: make circular Sersic gradients finite --- autogalaxy/profiles/light/standard/sersic.py | 45 ++++++++++++++++++- .../profiles/light/standard/test_sersic.py | 29 ++++++++++++ 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/autogalaxy/profiles/light/standard/sersic.py b/autogalaxy/profiles/light/standard/sersic.py index f3749ec1..8c184b74 100644 --- a/autogalaxy/profiles/light/standard/sersic.py +++ b/autogalaxy/profiles/light/standard/sersic.py @@ -166,10 +166,46 @@ def image_2d_via_radii_from( ), ) + @aa.decorators.to_array + def _eccentric_radii_grid_from_cartesian( + self, grid: aa.type.Grid2DLike, xp=np, **kwargs + ) -> np.ndarray: + """Return eccentric radii without converting ``ell_comps`` to polar form.""" + ell_comps_y, ell_comps_x = self.ell_comps + ell_comps_norm = xp.sqrt( + xp.maximum( + xp.add(xp.square(ell_comps_y), xp.square(ell_comps_x)), + 1.0e-12, + ) + ) + ell_comps_scale = xp.minimum(1.0, 0.999 / ell_comps_norm) + + ell_comps_y = xp.multiply(ell_comps_y, ell_comps_scale) + ell_comps_x = xp.multiply(ell_comps_x, ell_comps_scale) + ell_comps_norm_squared = xp.add(xp.square(ell_comps_y), xp.square(ell_comps_x)) + + y = xp.add(grid.array[:, 0], -self.centre[0]) + x = xp.add(grid.array[:, 1], -self.centre[1]) + + numerator = xp.add( + xp.multiply( + xp.add(1.0 + ell_comps_norm_squared, -2.0 * ell_comps_x), + xp.square(x), + ), + xp.add( + xp.multiply(-4.0 * ell_comps_y, xp.multiply(x, y)), + xp.multiply( + xp.add(1.0 + ell_comps_norm_squared, 2.0 * ell_comps_x), + xp.square(y), + ), + ), + ) + + return xp.sqrt(xp.divide(numerator, 1.0 - ell_comps_norm_squared)) + @aa.over_sample @aa.decorators.to_array @check_operated_only - @aa.decorators.transform def image_2d_from( self, grid: aa.type.Grid2DLike, @@ -194,7 +230,12 @@ def image_2d_from( The image of the Sersic evaluated at every (y,x) coordinate on the transformed grid. """ - grid_radii = self.eccentric_radii_grid_from(grid=grid, xp=xp, **kwargs) + if getattr(grid, "is_transformed", False): + grid_radii = self.eccentric_radii_grid_from(grid=grid, xp=xp, **kwargs) + else: + grid_radii = self._eccentric_radii_grid_from_cartesian( + grid=grid, xp=xp, **kwargs + ) return self.image_2d_via_radii_from(grid_radii=grid_radii, xp=xp, **kwargs) diff --git a/test_autogalaxy/profiles/light/standard/test_sersic.py b/test_autogalaxy/profiles/light/standard/test_sersic.py index 6919442b..6bb5f185 100644 --- a/test_autogalaxy/profiles/light/standard/test_sersic.py +++ b/test_autogalaxy/profiles/light/standard/test_sersic.py @@ -59,3 +59,32 @@ def test__image_2d_from__spherical_profile__matches_elliptical_with_zero_ellipti image_spherical = spherical.image_2d_from(grid=grid) assert image_elliptical.array == pytest.approx(image_spherical.array, 1.0e-4) + +@pytest.mark.parametrize( + "ell_comps", + [(0.0, 0.0), (0.18, 0.22), (-0.31, 0.14), (0.0, 0.9995)], +) +def test__image_2d_from__cartesian_radii_match_transformed_reference_frame( + ell_comps, +): + profile = ag.lp.Sersic( + centre=(0.07, -0.11), + ell_comps=ell_comps, + intensity=1.3, + effective_radius=0.8, + sersic_index=2.2, + ) + grid = ag.Grid2DIrregular( + [[0.13, -0.22], [0.51, 0.37], [-0.42, 0.81], [1.2, -0.63]] + ) + + transformed_grid = profile.transformed_to_reference_frame_grid_from(grid=grid) + transformed_grid.is_transformed = True + + image = profile.image_2d_from(grid=grid) + image_via_transformed_grid = profile.image_2d_from(grid=transformed_grid) + + assert image.array == pytest.approx( + image_via_transformed_grid.array, rel=2.0e-12, abs=2.0e-12 + ) + From 4418ddcccf79341de0ad731534fbf1083a4dac4c Mon Sep 17 00:00:00 2001 From: James Nightingale Date: Thu, 13 Aug 2026 21:37:23 -0400 Subject: [PATCH 2/2] style: separate Sersic test cases --- test_autogalaxy/profiles/light/standard/test_sersic.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_autogalaxy/profiles/light/standard/test_sersic.py b/test_autogalaxy/profiles/light/standard/test_sersic.py index 6bb5f185..a79b4497 100644 --- a/test_autogalaxy/profiles/light/standard/test_sersic.py +++ b/test_autogalaxy/profiles/light/standard/test_sersic.py @@ -60,6 +60,7 @@ def test__image_2d_from__spherical_profile__matches_elliptical_with_zero_ellipti assert image_elliptical.array == pytest.approx(image_spherical.array, 1.0e-4) + @pytest.mark.parametrize( "ell_comps", [(0.0, 0.0), (0.18, 0.22), (-0.31, 0.14), (0.0, 0.9995)],