diff --git a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py index 39b8fd81..72db4310 100644 --- a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py +++ b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py @@ -501,6 +501,9 @@ def _convergence(self, radii, xp=np): * (1 / xp.sqrt(a**2 + radsq) - 1 / xp.sqrt(s**2 + radsq)) ) + def convergence_func(self, grid_radius, xp=np): + return self._convergence(grid_radius, xp=xp) + @aa.decorators.to_array @aa.decorators.transform def convergence_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): diff --git a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py index c555675b..e0e67b6e 100644 --- a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py +++ b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py @@ -129,6 +129,9 @@ def _convergence(self, radii, xp=np): * (1 / xp.sqrt(a**2 + radsq) - 1 / xp.sqrt(s**2 + radsq)) ) + def convergence_func(self, grid_radius, xp=np): + return self._convergence(grid_radius, xp=xp) + @aa.decorators.to_vector_yx @aa.decorators.transform(rotate_back=True) def deflections_yx_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): diff --git a/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_mass.py b/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_mass.py index 5d0e30af..af12334f 100644 --- a/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_mass.py +++ b/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_mass.py @@ -45,3 +45,30 @@ def test__deflections_yx_2d_from__elliptical_vs_spherical(): assert elliptical.deflections_yx_2d_from(grid=grid).array == pytest.approx( spherical.deflections_yx_2d_from(grid=grid).array, 1e-1 ) + + +def test__convergence_func__matches_private_helper(): + """Regression: dPIEMass must override the abstract `convergence_func` + so MGEDecomposer.decompose_convergence_via_mge (which walks the + convergence radially during MGE potential decomposition) doesn't + fall through to the abstract NotImplementedError. The shim delegates + to the existing `_convergence` radial helper that `convergence_2d_from` + already uses.""" + + import numpy as np + + mp = ag.mp.dPIEMass(centre=(0.0, 0.0), b0=5.2, ra=2.0, rs=3.0) + + # Scalar radius: equals the _convergence formula directly. + assert mp.convergence_func(1.5) == pytest.approx(mp._convergence(1.5), 1e-12) + + # 1-D array of radii: shape preserved, element-wise equality. + radii = np.array([0.1, 0.5, 1.0, 2.5, 5.0]) + expected = mp._convergence(radii) + actual = mp.convergence_func(radii) + assert actual.shape == radii.shape + assert actual == pytest.approx(expected, 1e-12) + + # dPIEMassSph inherits the override from dPIEMass. + sph = ag.mp.dPIEMassSph(centre=(0.0, 0.0), b0=5.2, ra=2.0, rs=3.0) + assert sph.convergence_func(1.5) == pytest.approx(sph._convergence(1.5), 1e-12) diff --git a/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_potential.py b/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_potential.py index dcf6bbc7..8edb6ef4 100644 --- a/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_potential.py +++ b/test_autogalaxy/profiles/mass/total/test_dual_pseudo_isothermal_potential.py @@ -108,3 +108,25 @@ def test__convergence_2d_from__elliptical_vs_spherical(): assert elliptical.convergence_2d_from(grid=grid).array == pytest.approx( spherical.convergence_2d_from(grid=grid).array, 1e-4 ) + + +def test__convergence_func__matches_private_helper(): + """Regression: dPIEPotential must override the abstract `convergence_func` + so MGEDecomposer.decompose_convergence_via_mge doesn't fall through to the + abstract NotImplementedError. The shim delegates to the existing + `_convergence` radial helper that `convergence_2d_from` already uses.""" + + import numpy as np + + mp = ag.mp.dPIEPotential(centre=(0.0, 0.0), b0=5.2, ra=2.0, rs=3.0) + + assert mp.convergence_func(1.5) == pytest.approx(mp._convergence(1.5), 1e-12) + + radii = np.array([0.1, 0.5, 1.0, 2.5, 5.0]) + expected = mp._convergence(radii) + actual = mp.convergence_func(radii) + assert actual.shape == radii.shape + assert actual == pytest.approx(expected, 1e-12) + + sph = ag.mp.dPIEPotentialSph(centre=(0.0, 0.0), b0=5.2, ra=2.0, rs=3.0) + assert sph.convergence_func(1.5) == pytest.approx(sph._convergence(1.5), 1e-12)