diff --git a/autogalaxy/config/priors/mass/dark/cnfw.yaml b/autogalaxy/config/priors/mass/dark/cnfw.yaml index 265c9782d..17e632783 100644 --- a/autogalaxy/config/priors/mass/dark/cnfw.yaml +++ b/autogalaxy/config/priors/mass/dark/cnfw.yaml @@ -1,3 +1,78 @@ +cNFW: + centre_0: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + centre_1: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + ell_comps_0: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + ell_comps_1: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + kappa_s: + type: Uniform + lower_limit: 0.0 + upper_limit: 1.0 + width_modifier: + type: Relative + value: 0.2 + limits: + lower: 0.0 + upper: inf + scale_radius: + type: Uniform + lower_limit: 0.0 + upper_limit: 30.0 + width_modifier: + type: Relative + value: 0.2 + limits: + lower: 0.0 + upper: inf + core_radius: + type: Uniform + lower_limit: 0.0 + upper_limit: 15.0 + width_modifier: + type: Relative + value: 0.2 + limits: + lower: 0.0 + upper: inf cNFWSph: centre_0: type: Gaussian diff --git a/autogalaxy/config/priors/mass/dark/cnfw_mcr.yaml b/autogalaxy/config/priors/mass/dark/cnfw_mcr.yaml index 4fd52d85d..b67291de7 100644 --- a/autogalaxy/config/priors/mass/dark/cnfw_mcr.yaml +++ b/autogalaxy/config/priors/mass/dark/cnfw_mcr.yaml @@ -1,3 +1,88 @@ +cNFWMCRLudlow: + centre_0: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + centre_1: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + ell_comps_0: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + ell_comps_1: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + mass_at_200: + type: LogUniform + lower_limit: 100000000.0 + upper_limit: 1000000000000000.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf + f_c: + type: Uniform + lower_limit: 0.0001 + upper_limit: 0.5 + width_modifier: + type: Relative + value: 0.2 + limits: + lower: 0.0001 + upper: inf + redshift_object: + type: Uniform + lower_limit: 0.0 + upper_limit: 1.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf + redshift_source: + type: Uniform + lower_limit: 0.0 + upper_limit: 1.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf cNFWMCRLudlowSph: centre_0: type: Gaussian diff --git a/autogalaxy/config/priors/mass/dark/cnfw_mcr_scatter.yaml b/autogalaxy/config/priors/mass/dark/cnfw_mcr_scatter.yaml index 5cd63266a..0e1fb16e7 100644 --- a/autogalaxy/config/priors/mass/dark/cnfw_mcr_scatter.yaml +++ b/autogalaxy/config/priors/mass/dark/cnfw_mcr_scatter.yaml @@ -1,3 +1,98 @@ +cNFWMCRScatterLudlow: + centre_0: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + centre_1: + type: Gaussian + mean: 0.0 + sigma: 0.1 + width_modifier: + type: Absolute + value: 0.05 + limits: + lower: -inf + upper: inf + ell_comps_0: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + ell_comps_1: + type: TruncatedGaussian + mean: 0.0 + sigma: 0.3 + lower_limit: -1.0 + upper_limit: 1.0 + width_modifier: + type: Absolute + value: 0.2 + limits: + lower: -1.0 + upper: 1.0 + mass_at_200: + type: LogUniform + lower_limit: 100000000.0 + upper_limit: 1000000000000000.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf + f_c: + type: Uniform + lower_limit: 0.0001 + upper_limit: 0.5 + width_modifier: + type: Relative + value: 0.2 + limits: + lower: 0.0001 + upper: inf + redshift_object: + type: Uniform + lower_limit: 0.0 + upper_limit: 1.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf + redshift_source: + type: Uniform + lower_limit: 0.0 + upper_limit: 1.0 + width_modifier: + type: Relative + value: 0.5 + limits: + lower: 0.0 + upper: inf + scatter_sigma: + type: Gaussian + mean: 0.0 + sigma: 3.0 + width_modifier: + type: Absolute + value: 1.0 + limits: + lower: -inf + upper: inf cNFWMCRScatterLudlowSph: centre_0: type: Gaussian diff --git a/autogalaxy/profiles/mass/__init__.py b/autogalaxy/profiles/mass/__init__.py index 083f3e9db..b6dd37958 100644 --- a/autogalaxy/profiles/mass/__init__.py +++ b/autogalaxy/profiles/mass/__init__.py @@ -37,8 +37,11 @@ NFWMCRLudlow, gNFWMCRLudlow, NFWVirialMassConcSph, + cNFW, cNFWSph, + cNFWMCRLudlow, cNFWMCRLudlowSph, + cNFWMCRScatterLudlow, cNFWMCRScatterLudlowSph, ) from .stellar import ( diff --git a/autogalaxy/profiles/mass/dark/__init__.py b/autogalaxy/profiles/mass/dark/__init__.py index 4fdc2cae5..ff0264eb2 100644 --- a/autogalaxy/profiles/mass/dark/__init__.py +++ b/autogalaxy/profiles/mass/dark/__init__.py @@ -9,6 +9,6 @@ from .nfw_truncated_mcr import NFWTruncatedMCRLudlowSph, NFWTruncatedMCRDuffySph from .nfw_truncated_mcr_scatter import NFWTruncatedMCRScatterLudlowSph from .nfw_virial_mass_conc import NFWVirialMassConcSph -from .cnfw import cNFWSph -from .cnfw_mcr import cNFWMCRLudlowSph -from .cnfw_mcr_scatter import cNFWMCRScatterLudlowSph +from .cnfw import cNFW, cNFWSph +from .cnfw_mcr import cNFWMCRLudlow, cNFWMCRLudlowSph +from .cnfw_mcr_scatter import cNFWMCRScatterLudlow, cNFWMCRScatterLudlowSph diff --git a/autogalaxy/profiles/mass/dark/cnfw.py b/autogalaxy/profiles/mass/dark/cnfw.py index 53cba11c7..d39ae55cf 100644 --- a/autogalaxy/profiles/mass/dark/cnfw.py +++ b/autogalaxy/profiles/mass/dark/cnfw.py @@ -3,11 +3,80 @@ from typing import Tuple from autogalaxy.profiles.mass.dark.abstract import AbstractgNFW +from autogalaxy.profiles.mass.abstract.mge import MGEDecomposer import autoarray as aa -class cNFWSph(AbstractgNFW): +class cNFW(AbstractgNFW): + def __init__( + self, + centre: Tuple[float, float] = (0.0, 0.0), + ell_comps: Tuple[float, float] = (0.0, 0.0), + kappa_s: float = 0.05, + scale_radius: float = 1.0, + core_radius: float = 0.01, + ): + """ + Represents a cored NFW density distribution + + Parameters + ---------- + centre + The (y,x) arc-second coordinates of the profile centre. + ell_comps + The first and second ellipticity components of the elliptical coordinate system. + kappa_s + The overall normalization of the dark matter halo + (kappa_s = (rho_0 * D_d * scale_radius)/lensing_critical_density) + scale_radius + The cored NFW scale radius `theta_s`, as an angle on the sky in arcseconds. + core_radius + The cored NFW core radius `theta_c`, as an angle on the sky in arcseconds. + """ + + super().__init__(centre=centre, ell_comps=ell_comps) + + self.kappa_s = kappa_s + self.scale_radius = scale_radius + self.core_radius = core_radius + + + def deflections_yx_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): + return self.deflections_2d_via_mge_from(grid=grid, xp=xp, **kwargs) + + def deflections_2d_via_mge_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): + radii_min = self.scale_radius / 1000.0 + radii_max = self.scale_radius * 200.0 + log_sigmas = xp.linspace(xp.log(radii_min), xp.log(radii_max), 20) + sigmas = xp.exp(log_sigmas) + + mge_decomp = MGEDecomposer(mass_profile=self) + + deflections_via_mge = mge_decomp.deflections_2d_via_mge_from( + grid=grid, + xp=xp, + sigma_log_list=sigmas, + ellipticity_convention='major', + three_D=True + ) + return deflections_via_mge + + def density_3d_func(self, r, xp=np): + + rho_at_scale_radius = ( + self.kappa_s / self.scale_radius + ) # density parameter of 3D gNFW + + return ( + rho_at_scale_radius + * self.scale_radius**3.0 + * (r.array + self.core_radius) ** (-1.0) + * (r.array + self.scale_radius) ** (-2.0) + ) + + +class cNFWSph(cNFW): def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -23,7 +92,7 @@ def __init__( centre The (y,x) arc-second coordinates of the profile centre. kappa_s - The overall normalization of the dark matter halo \| + The overall normalization of the dark matter halo (kappa_s = (rho_0 * D_d * scale_radius)/lensing_critical_density) scale_radius The cored NFW scale radius `theta_s`, as an angle on the sky in arcseconds. @@ -165,16 +234,3 @@ def potential_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): This is not yet implemented for `cNFWSph`. """ return xp.zeros(shape=grid.shape[0]) - - def density_3d_func(self, theta, xp=np): - - rho_at_scale_radius = ( - self.kappa_s / self.scale_radius - ) # density parameter of 3D gNFW - - return ( - rho_at_scale_radius - * self.scale_radius**3.0 - * (theta.array + self.core_radius) ** (-1.0) - * (theta.array + self.scale_radius) ** (-2.0) - ) diff --git a/autogalaxy/profiles/mass/dark/cnfw_mcr.py b/autogalaxy/profiles/mass/dark/cnfw_mcr.py index 7c7946a36..f55086f3f 100644 --- a/autogalaxy/profiles/mass/dark/cnfw_mcr.py +++ b/autogalaxy/profiles/mass/dark/cnfw_mcr.py @@ -1,30 +1,23 @@ from typing import Tuple -from autogalaxy.profiles.mass.dark.cnfw import cNFWSph +from autogalaxy.profiles.mass.dark.cnfw_mcr_scatter import ( + cNFWMCRScatterLudlow, + cNFWMCRScatterLudlowSph, +) -from autogalaxy.profiles.mass.dark import mcr_util - - -class cNFWMCRLudlowSph(cNFWSph): +class cNFWMCRLudlow(cNFWMCRScatterLudlow): def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), + ell_comps: Tuple[float, float] = (0.0, 0.0), mass_at_200: float = 1e9, f_c: float = 0.01, redshift_object: float = 0.5, redshift_source: float = 1.0, ): - self.mass_at_200 = mass_at_200 - self.f_c = f_c - self.redshift_object = redshift_object - self.redshift_source = redshift_source - - ( - kappa_s, - scale_radius, - core_radius, - radius_at_200, - ) = mcr_util.kappa_s_scale_radius_and_core_radius_for_ludlow( + super().__init__( + centre=centre, + ell_comps=ell_comps, mass_at_200=mass_at_200, scatter_sigma=0.0, f_c=f_c, @@ -32,9 +25,20 @@ def __init__( redshift_source=redshift_source, ) +class cNFWMCRLudlowSph(cNFWMCRScatterLudlowSph): + def __init__( + self, + centre: Tuple[float, float] = (0.0, 0.0), + mass_at_200: float = 1e9, + f_c: float = 0.01, + redshift_object: float = 0.5, + redshift_source: float = 1.0, + ): super().__init__( centre=centre, - kappa_s=kappa_s, - scale_radius=scale_radius, - core_radius=core_radius, + mass_at_200=mass_at_200, + scatter_sigma=0.0, + f_c=f_c, + redshift_object=redshift_object, + redshift_source=redshift_source, ) diff --git a/autogalaxy/profiles/mass/dark/cnfw_mcr_scatter.py b/autogalaxy/profiles/mass/dark/cnfw_mcr_scatter.py index 84122ebb7..a0cc91425 100644 --- a/autogalaxy/profiles/mass/dark/cnfw_mcr_scatter.py +++ b/autogalaxy/profiles/mass/dark/cnfw_mcr_scatter.py @@ -1,17 +1,55 @@ from typing import Tuple -from autogalaxy.profiles.mass.dark.cnfw import cNFWSph +from autogalaxy.profiles.mass.dark.cnfw import (cNFW, cNFWSph) from autogalaxy.profiles.mass.dark import mcr_util +class cNFWMCRScatterLudlow(cNFW): + def __init__( + self, + centre: Tuple[float, float] = (0.0, 0.0), + ell_comps: Tuple[float, float] = (0.0, 0.0), + mass_at_200: float = 1e9, + scatter_sigma: float = 0.0, + f_c: float = 0.01, + redshift_object: float = 0.5, + redshift_source: float = 1.0, + ): + self.mass_at_200 = mass_at_200 + self.scatter_sigma = scatter_sigma + self.f_c = f_c + self.redshift_object = redshift_object + self.redshift_source = redshift_source + + ( + kappa_s, + scale_radius, + core_radius, + radius_at_200, + ) = mcr_util.kappa_s_scale_radius_and_core_radius_for_ludlow( + mass_at_200=mass_at_200, + scatter_sigma=scatter_sigma, + f_c=f_c, + redshift_object=redshift_object, + redshift_source=redshift_source, + ) + + super().__init__( + centre=centre, + ell_comps=ell_comps, + kappa_s=kappa_s, + scale_radius=scale_radius, + core_radius=core_radius, + ) + class cNFWMCRScatterLudlowSph(cNFWSph): def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), mass_at_200: float = 1e9, scatter_sigma: float = 0.0, - f_c=0.01, + f_c: float = 0.01, redshift_object: float = 0.5, redshift_source: float = 1.0, ): diff --git a/test_autogalaxy/profiles/mass/dark/test_nfw_mcr.py b/test_autogalaxy/profiles/mass/dark/test_nfw_mcr.py index b2aff11ca..477f65319 100644 --- a/test_autogalaxy/profiles/mass/dark/test_nfw_mcr.py +++ b/test_autogalaxy/profiles/mass/dark/test_nfw_mcr.py @@ -272,3 +272,56 @@ def test__same_as_above_but_cored_nfw(): deflections = cnfw_kappa_s.deflections_yx_2d_from(grid=grid) assert (deflections_ludlow == deflections).all() + + mp = ag.mp.cNFWMCRLudlow( + centre=(1.0, 2.0), + ell_comps=(0.1, 0.2), + mass_at_200=1.0e9, + f_c=0.01, + redshift_object=0.6, + redshift_source=2.5, + ) + + mass_at_200_via_mass = mp.mass_at_200_solar_masses( + redshift_object=0.6, redshift_source=2.5, cosmology=cosmology + ) + concentration_via_mass = mp.concentration( + redshift_profile=0.6, redshift_source=2.5, cosmology=cosmology + ) + + cnfw_kappa_s = ag.mp.cNFW( + centre=(1.0, 2.0), + ell_comps=(0.1, 0.2), + kappa_s=mp.kappa_s, + scale_radius=mp.scale_radius, + core_radius=mp.core_radius, + ) + + mass_at_200_via_kappa_s = cnfw_kappa_s.mass_at_200_solar_masses( + redshift_object=0.6, redshift_source=2.5, cosmology=cosmology + ) + concentration_via_kappa_s = cnfw_kappa_s.concentration( + redshift_profile=0.6, redshift_source=2.5, cosmology=cosmology + ) + + # We are using the NFWTruncatedSph to check the mass gives a consistent kappa_s, given certain radii. + + assert mass_at_200_via_kappa_s == mass_at_200_via_mass + assert concentration_via_kappa_s == concentration_via_mass + + assert mp.centre == (1.0, 2.0) + + assert mp.ell_comps == (0.1, 0.2) + + assert mp.axis_ratio() == cnfw_kappa_s.axis_ratio() + + assert mp.angle() == cnfw_kappa_s.angle() + + assert mp.scale_radius == pytest.approx(0.21158, 1.0e-4) + + assert mp.core_radius == pytest.approx(0.0021158, 1.0e-4) + + deflections_ludlow = mp.deflections_yx_2d_from(grid=grid) + deflections = cnfw_kappa_s.deflections_yx_2d_from(grid=grid) + + assert (deflections_ludlow == deflections).all() \ No newline at end of file diff --git a/test_autogalaxy/profiles/mass/dark/test_nfw_scatter.py b/test_autogalaxy/profiles/mass/dark/test_nfw_scatter.py index 9bb2eb066..7cd95e008 100644 --- a/test_autogalaxy/profiles/mass/dark/test_nfw_scatter.py +++ b/test_autogalaxy/profiles/mass/dark/test_nfw_scatter.py @@ -81,3 +81,25 @@ def test__scatter_is_nonzero_cored(): ) assert cnfw_sph.scale_radius == pytest.approx(0.29886, 1.0e-4) + + cnfw = ag.mp.cNFWMCRScatterLudlow( + ell_comps=(-0.1, 0.2), + mass_at_200=1.0e9, + scatter_sigma=1.0, + f_c=0.01, + redshift_object=0.6, + redshift_source=2.5, + ) + + assert cnfw.scale_radius == pytest.approx(0.14978, 1.0e-4) + + cnfw_sph = ag.mp.cNFWMCRScatterLudlow( + mass_at_200=1.0e9, + scatter_sigma=-1.0, + f_c=0.01, + redshift_object=0.6, + redshift_source=2.5, + ) + + assert cnfw_sph.scale_radius == pytest.approx(0.29886, 1.0e-4) +