diff --git a/autogalaxy/profiles/mass/abstract/cse.py b/autogalaxy/profiles/mass/abstract/cse.py index b3497126..8d880dc4 100644 --- a/autogalaxy/profiles/mass/abstract/cse.py +++ b/autogalaxy/profiles/mass/abstract/cse.py @@ -4,6 +4,36 @@ class MassProfileCSE(ABC): + r""" + Cored Steep Ellipsoid (CSE) decomposition mixin for mass profiles. + + Provides the machinery to decompose an arbitrary projected convergence profile into + a sum of cored steep ellipsoid (CSE) basis functions, enabling analytic deflection + angle evaluation via Oguri (2021). + + The 1-D CSE convergence basis function (Oguri 2021 Eq. 14) is: + + .. math:: + + \kappa_{\rm CSE}(r; s) = \frac{1}{2(s^2 + r^2)^{3/2}} + + where :math:`s` is the CSE core radius. An arbitrary convergence profile + :math:`\kappa(r)` is approximated as: + + .. math:: + + \kappa(r) \approx \sum_{j} A_j \, \kappa_{\rm CSE}(r; s_j) + + The amplitudes :math:`A_j` and core radii :math:`s_j` are found by linear least + squares on a log-spaced radial grid. The deflection angles of each CSE component + are computed analytically from Oguri (2021) Eq. 19–20, and the total deflection is + their sum. + + References + ---------- + - Oguri 2021, PASP, 133, 074504 (arXiv:2106.11464) + """ + @staticmethod def convergence_cse_1d_from( grid_radii: np.ndarray, core_radius: float, xp=np diff --git a/autogalaxy/profiles/mass/abstract/mge.py b/autogalaxy/profiles/mass/abstract/mge.py index 7f7a9e21..f5261790 100644 --- a/autogalaxy/profiles/mass/abstract/mge.py +++ b/autogalaxy/profiles/mass/abstract/mge.py @@ -5,11 +5,31 @@ class MGEDecomposer: - """ - This class speeds up deflection angle calculations of certain mass profiles by decompositing them into many - Gaussians. + r""" + Multi-Gaussian Expansion (MGE) decomposer for arbitrary mass profiles. + + Accelerates deflection-angle and convergence calculations by decomposing a mass + profile's projected convergence (or 3-D density) into a sum of Gaussian components, + each of which has an analytic deflection-angle formula via the Faddeeva (scaled + complementary error) function. + + The decomposition of an arbitrary radial function :math:`f(\sigma)` into Gaussians + with amplitudes :math:`A_j` and widths :math:`\sigma_j` follows the numerical + contour-integration quadrature of Shajib (2019) Eq. 6: + + .. math:: + + f(\sigma) \approx \sum_{j} A_j \exp\!\left(-\frac{r^2}{2\sigma_j^2}\right) + + The deflection angles of each Gaussian component are then evaluated analytically via + the complex Faddeeva function :math:`w(z) = e^{-z^2}\,\mathrm{erfc}(-iz)`. + + Supported ellipticity conventions for the scale-parameter :math:`\sigma` are + ``'major'``, ``'circularised'``, and ``'minor'`` (see :meth:`sigmas_factor_from`). - This follows the method of Shajib 2019 - https://academic.oup.com/mnras/article/488/1/1387/5526256 + References + ---------- + - Shajib 2019, MNRAS, 488, 1387 (arXiv:1906.08263) """ def __init__( diff --git a/autogalaxy/profiles/mass/dark/abstract.py b/autogalaxy/profiles/mass/dark/abstract.py index ee65c473..07e5c858 100644 --- a/autogalaxy/profiles/mass/dark/abstract.py +++ b/autogalaxy/profiles/mass/dark/abstract.py @@ -15,6 +15,36 @@ class DarkProfile: class AbstractgNFW(MassProfile, DarkProfile): + r""" + Abstract base class for generalised NFW (gNFW) dark matter halo profiles. + + The three-dimensional density profile of the gNFW family is: + + .. math:: + + \rho(r) = \frac{\rho_s}{(r/r_s)^{\gamma}(1 + r/r_s)^{3-\gamma}} + + where :math:`\gamma` is the inner logarithmic slope (``inner_slope``), :math:`r_s` is + the scale radius, and :math:`\rho_s` is the characteristic density related to the + dimensionless convergence normalisation :math:`\kappa_s` via: + + .. math:: + + \kappa_s = \frac{\rho_s \, r_s}{\Sigma_{\rm crit}} + + The projected convergence is computed from this 3-D density via line-of-sight integration + using the auxiliary coordinate functions :math:`f(x)`, :math:`g(x)`, and :math:`h(x)`, + where :math:`x = \xi / r_s` and :math:`\xi` is the elliptical radius. + + The standard NFW profile (:class:`NFW`) is recovered for :math:`\gamma = 1`. + + References + ---------- + - Navarro, Frenk & White 1996, ApJ, 462, 563 + - Navarro, Frenk & White 1997, ApJ, 490, 493 + - Wyithe, Turner & Spergel 2001, ApJ, 555, 504 + """ + epsrel = 1.49e-5 def __init__( diff --git a/autogalaxy/profiles/mass/dark/cnfw.py b/autogalaxy/profiles/mass/dark/cnfw.py index dcb7c6b3..9ade2cf5 100644 --- a/autogalaxy/profiles/mass/dark/cnfw.py +++ b/autogalaxy/profiles/mass/dark/cnfw.py @@ -9,6 +9,29 @@ class cNFW(AbstractgNFW): + r""" + Elliptical cored NFW (cNFW) dark matter halo profile. + + The three-dimensional density profile introduces a constant-density core of + radius :math:`r_c` that suppresses the central cusp of the standard NFW profile: + + .. math:: + + \rho(r) = \frac{\rho_0 \, r_s^3}{(r + r_c)(r + r_s)^2} + + where :math:`r_c` is the core radius (``core_radius``) and :math:`r_s` is the + scale radius (``scale_radius``). In the limit :math:`r_c \to 0` the profile + approaches the standard NFW density. + + The convergence and deflection angles are computed via a Multi-Gaussian + Expansion (MGE) decomposition following Shajib (2019). + + References + ---------- + - Read, Agertz & Collins 2016, MNRAS, 459, 2573 + - Shajib 2019, MNRAS, 488, 1387 (arXiv:1906.08263) + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -17,9 +40,7 @@ def __init__( scale_radius: float = 1.0, core_radius: float = 0.01, ): - """ - Represents a cored NFW density distribution - + r""" Parameters ---------- centre @@ -28,11 +49,11 @@ def __init__( 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) + (:math:`\kappa_s = \rho_0 D_d r_s / \Sigma_{\rm crit}`). scale_radius - The cored NFW scale radius `theta_s`, as an angle on the sky in arcseconds. + The cored NFW scale radius :math:`r_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. + The cored NFW core radius :math:`r_c`, as an angle on the sky in arcseconds. """ super().__init__(centre=centre, ell_comps=ell_comps) @@ -103,6 +124,22 @@ def potential_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): class cNFWSph(cNFW): + r""" + Spherical cored NFW (cNFW) dark matter halo profile. + + A special case of :class:`cNFW` with no ellipticity (:math:`q = 1`). The 3-D + density and projected convergence follow the same cored-NFW expressions with + an analytic deflection-angle formula available for the spherical case: + + .. math:: + + \rho(r) = \frac{\rho_0 \, r_s^3}{(r + r_c)(r + r_s)^2} + + References + ---------- + - Read, Agertz & Collins 2016, MNRAS, 459, 2573 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -110,20 +147,18 @@ def __init__( scale_radius: float = 1.0, core_radius: float = 0.01, ): - """ - Represents a spherical cored NFW density distribution - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. kappa_s The overall normalization of the dark matter halo - (kappa_s = (rho_0 * D_d * scale_radius)/lensing_critical_density) + (:math:`\kappa_s = \rho_0 D_d r_s / \Sigma_{\rm crit}`). scale_radius - The cored NFW scale radius `theta_s`, as an angle on the sky in arcseconds. + The cored NFW scale radius :math:`r_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. + The cored NFW core radius :math:`r_c`, as an angle on the sky in arcseconds. """ super().__init__(centre=centre, ell_comps=(0.0, 0.0)) diff --git a/autogalaxy/profiles/mass/dark/gnfw.py b/autogalaxy/profiles/mass/dark/gnfw.py index 8a182c17..9afd7805 100644 --- a/autogalaxy/profiles/mass/dark/gnfw.py +++ b/autogalaxy/profiles/mass/dark/gnfw.py @@ -8,6 +8,38 @@ class gNFW(AbstractgNFW): + r""" + Elliptical generalised NFW (gNFW) dark matter halo profile with a free inner slope. + + The three-dimensional density profile is: + + .. math:: + + \rho(r) = \frac{\rho_s}{(r/r_s)^{\gamma}(1 + r/r_s)^{3-\gamma}} + + where :math:`\gamma` is the inner logarithmic slope (``inner_slope``). For + :math:`\gamma = 1` this reduces to the standard :class:`NFW` profile. + + The projected convergence is computed by numerical line-of-sight integration: + + .. math:: + + \kappa(\xi) = 2 \kappa_s \, (\xi/r_s)^{1-\gamma} + \left[ + (1 + \xi/r_s)^{\gamma-3} + + (3 - \gamma) \int_0^1 \frac{(y + \xi/r_s)^{\gamma-4} + \left(1 - \sqrt{1 - y^2}\right)}{1} \, \mathrm{d}y + \right] + + Deflection angles are computed via a Multi-Gaussian Expansion (MGE) decomposition + following Shajib (2019). + + References + ---------- + - Wyithe, Turner & Spergel 2001, ApJ, 555, 504 + - Shajib 2019, MNRAS, 488, 1387 (arXiv:1906.08263) + """ + 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) @@ -60,6 +92,22 @@ def integral_y(y, eta): class gNFWSph(gNFW): + r""" + Spherical generalised NFW (gNFW) dark matter halo profile with a free inner slope. + + A special case of :class:`gNFW` with no ellipticity (:math:`q = 1`). The 3-D + density and projected convergence follow the same gNFW expressions as the + elliptical variant but evaluated on a circular radial grid. + + .. math:: + + \rho(r) = \frac{\rho_s}{(r/r_s)^{\gamma}(1 + r/r_s)^{3-\gamma}} + + References + ---------- + - Wyithe, Turner & Spergel 2001, ApJ, 555, 504 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -67,21 +115,18 @@ def __init__( inner_slope: float = 1.0, scale_radius: float = 1.0, ): - """ - The spherical NFW profiles, used to fit the dark matter halo of the lens. - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. kappa_s - The overall normalization of the dark matter halo \ - (kappa_s = (rho_s * scale_radius)/lensing_critical_density) + The overall normalization of the dark matter halo + (:math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}`). inner_slope - The inner slope of the dark matter halo. + The inner logarithmic slope :math:`\gamma` of the dark matter density profile. scale_radius - The arc-second radius where the average density within this radius is 200 times the critical density of \ - the Universe.. + The NFW scale radius :math:`r_s`, as an angle on the sky in arcseconds. """ super().__init__( diff --git a/autogalaxy/profiles/mass/dark/nfw.py b/autogalaxy/profiles/mass/dark/nfw.py index 3b755170..9963211d 100644 --- a/autogalaxy/profiles/mass/dark/nfw.py +++ b/autogalaxy/profiles/mass/dark/nfw.py @@ -10,6 +10,42 @@ class NFW(gNFW, MassProfileCSE): + r""" + Elliptical Navarro-Frenk-White (NFW) dark matter halo profile. + + The NFW profile is the special case of the generalised NFW with inner slope + :math:`\gamma = 1`. The projected surface mass density (convergence) is: + + .. math:: + + \kappa_{\rm NFW}(x) = 2 \kappa_s \, g(x), \qquad x = \frac{\xi}{r_s} + + where :math:`\xi` is the elliptical radius, :math:`r_s` is the scale radius, + :math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}` is the dimensionless + characteristic convergence, and + + .. math:: + + g(x) = \begin{cases} + \dfrac{1 - \tfrac{1}{\sqrt{1-x^2}}\,\mathrm{arccosh}(1/x)}{x^2 - 1} + & x < 1 \\[6pt] + \dfrac{1}{3} & x = 1 \\[6pt] + \dfrac{1 - \tfrac{1}{\sqrt{x^2-1}}\,\arccos(1/x)}{x^2 - 1} + & x > 1 + \end{cases} + + Deflection angles are computed analytically via the Heyrovský & Karamazov (2024) + formalism, or alternatively via a cored-steep-ellipsoid (CSE) decomposition + following Oguri (2021). + + References + ---------- + - Navarro, Frenk & White 1996, ApJ, 462, 563 + - Navarro, Frenk & White 1997, ApJ, 490, 493 + - Oguri 2021, PASP, 133, 074504 (arXiv:2106.11464) + - Heyrovský & Karamazov 2024 (arXiv:2407.xxxxx) + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -18,8 +54,6 @@ def __init__( scale_radius: float = 1.0, ): r""" - The elliptical NFW profiles, used to fit the dark matter halo of the lens. - Parameters ---------- centre @@ -27,10 +61,10 @@ def __init__( 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_s * scale_radius)/lensing_critical_density) + The overall normalization of the dark matter halo + (:math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}`). scale_radius - The NFW scale radius `r_s`, as an angle on the sky in arcseconds. + The NFW scale radius :math:`r_s`, as an angle on the sky in arcseconds. """ super().__init__( @@ -267,6 +301,32 @@ def convergence_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): class NFWSph(NFW): + r""" + Spherical Navarro-Frenk-White (NFW) dark matter halo profile. + + A special case of :class:`NFW` with no ellipticity (:math:`q = 1`). The convergence + is the standard NFW convergence evaluated on a circular radial grid: + + .. math:: + + \kappa_{\rm NFW}(r) = 2 \kappa_s \, g(r/r_s) + + and the analytic deflection angle at projected radius :math:`r` is: + + .. math:: + + \alpha(r) = \frac{4 \kappa_s r_s}{r/r_s}\,h(r/r_s) + + where :math:`h(x) = \ln(x/2) + f(x)` and :math:`f(x)` is the standard NFW + auxiliary function. The lensing potential is also available analytically. + + References + ---------- + - Navarro, Frenk & White 1996, ApJ, 462, 563 + - Navarro, Frenk & White 1997, ApJ, 490, 493 + - Wright & Brainerd 2000, ApJ, 534, 34 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -274,18 +334,15 @@ def __init__( scale_radius: float = 1.0, ): r""" - The spherical NFW profiles, used to fit the dark matter halo of the lens. - Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. kappa_s - The overall normalization of the dark matter halo \ - (kappa_s = (rho_s * scale_radius)/lensing_critical_density) + The overall normalization of the dark matter halo + (:math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}`). scale_radius - The arc-second radius where the average density within this radius is 200 times the critical density of \ - the Universe.. + The NFW scale radius :math:`r_s`, as an angle on the sky in arcseconds. """ super().__init__( diff --git a/autogalaxy/profiles/mass/dark/nfw_truncated.py b/autogalaxy/profiles/mass/dark/nfw_truncated.py index aeb15f43..5a9e8df3 100644 --- a/autogalaxy/profiles/mass/dark/nfw_truncated.py +++ b/autogalaxy/profiles/mass/dark/nfw_truncated.py @@ -8,6 +8,37 @@ class NFWTruncatedSph(AbstractgNFW): + r""" + Spherical truncated NFW (tNFW) dark matter halo profile (Baltz, Marshall & Oguri 2009). + + The tNFW profile introduces a smooth truncation of the NFW density at a truncation + radius :math:`r_t`, characterised by the dimensionless truncation ratio + :math:`\tau = r_t / r_s`: + + .. math:: + + \rho(r) = \frac{\rho_s}{(r/r_s)(1 + r/r_s)^2} + \left(\frac{\tau^2}{\tau^2 + (r/r_s)^2}\right) + + where :math:`r_s` is the scale radius and :math:`\rho_s` is related to the + dimensionless convergence normalisation via + :math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}`. + + The projected convergence is given by: + + .. math:: + + \kappa(x) = 2 \kappa_s \, L(x, \tau) + + where :math:`L(x, \tau)` is the auxiliary function defined in Baltz et al. (2009) + (implemented here as ``coord_func_l``). + + References + ---------- + - Baltz, Marshall & Oguri 2009, JCAP, 2009, 015 (arXiv:0705.0735) + - Navarro, Frenk & White 1997, ApJ, 490, 493 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -15,6 +46,20 @@ def __init__( scale_radius: float = 1.0, truncation_radius: float = 2.0, ): + r""" + Parameters + ---------- + centre + The (y,x) arc-second coordinates of the profile centre. + kappa_s + The dimensionless convergence normalisation + (:math:`\kappa_s = \rho_s r_s / \Sigma_{\rm crit}`). + scale_radius + The NFW scale radius :math:`r_s`, as an angle on the sky in arcseconds. + truncation_radius + The truncation radius :math:`r_t`, as an angle on the sky in arcseconds. + The dimensionless truncation ratio is :math:`\tau = r_t / r_s`. + """ super().__init__( centre=centre, ell_comps=(0.0, 0.0), diff --git a/autogalaxy/profiles/mass/point/point.py b/autogalaxy/profiles/mass/point/point.py index 163a7682..495c0052 100644 --- a/autogalaxy/profiles/mass/point/point.py +++ b/autogalaxy/profiles/mass/point/point.py @@ -8,18 +8,43 @@ class PointMass(MassProfile): + r""" + Point mass lens profile. + + A point mass produces a convergence that is a Dirac delta function at the lens + centre, a logarithmic potential, and a deflection angle that falls off as + :math:`1/r`: + + .. math:: + + \kappa(\boldsymbol{\theta}) = \pi \theta_E^2 \, \delta^{(2)}(\boldsymbol{\theta}) + + .. math:: + + \psi(\boldsymbol{\theta}) = \theta_E^2 \ln r + + .. math:: + + \boldsymbol{\alpha}(\boldsymbol{\theta}) = \frac{\theta_E^2}{r}\,\hat{r} + + where :math:`\theta_E` is the Einstein radius (``einstein_radius``) and :math:`r` + is the angular distance from the lens centre. + + This profile is used to represent compact objects such as black holes or stars. + In practice the convergence grid value at the centre pixel is set to zero; the + point-mass nature is captured entirely through the deflection and potential. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), einstein_radius: float = 1.0 ): - """ - Represents a point-mass. - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. einstein_radius - The arc-second Einstein radius of the point-mass. + The Einstein radius :math:`\theta_E` of the point mass (arcseconds). """ super().__init__(centre=centre, ell_comps=(0.0, 0.0)) self.einstein_radius = einstein_radius diff --git a/autogalaxy/profiles/mass/point/smbh.py b/autogalaxy/profiles/mass/point/smbh.py index 9fde5825..c358e177 100644 --- a/autogalaxy/profiles/mass/point/smbh.py +++ b/autogalaxy/profiles/mass/point/smbh.py @@ -5,6 +5,28 @@ class SMBH(PointMass): + r""" + Supermassive black hole (SMBH) modelled as a point mass lens. + + The SMBH is represented by a :class:`PointMass` profile whose Einstein radius + :math:`\theta_E` is derived from the physical mass :math:`M` and the critical + surface density :math:`\Sigma_{\rm crit}` between the SMBH and the source: + + .. math:: + + \theta_E = \sqrt{\frac{M}{\pi \, \Sigma_{\rm crit}}} + + The lensing potential and deflections then follow the point-mass expressions: + + .. math:: + + \psi(\boldsymbol{\theta}) = \theta_E^2 \ln r, \qquad + \boldsymbol{\alpha}(\boldsymbol{\theta}) = \frac{\theta_E^2}{r}\,\hat{r} + + This profile is used to model the gravitational influence of a central SMBH on + lensed images passing near the nucleus. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -12,22 +34,18 @@ def __init__( redshift_object: float = 0.5, redshift_source: float = 1.0, ): - """ - Represents a supermassive black hole (SMBH). - - This uses the `PointMass` mass profile to represent the SMBH, where the SMBH mass in converted to the - `PointMass` Einstein radius value. - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. mass - The mass of the SMBH in solar masses. + The mass of the SMBH in solar masses :math:`M_\odot`. redshift_object - The redshift of the SMBH, which is used to convert its mass to an Einstein radius. + The redshift of the SMBH (lens plane), used to convert mass to an Einstein radius. redshift_source - The redshift of the source galaxy, which is used to convert the mass of the SMBH to an Einstein radius. + The redshift of the lensed source galaxy, used to compute + :math:`\Sigma_{\rm crit}` and hence the Einstein radius. """ from autogalaxy.cosmology.model import Planck15 diff --git a/autogalaxy/profiles/mass/point/smbh_binary.py b/autogalaxy/profiles/mass/point/smbh_binary.py index 9a0a3823..60968cf1 100644 --- a/autogalaxy/profiles/mass/point/smbh_binary.py +++ b/autogalaxy/profiles/mass/point/smbh_binary.py @@ -8,6 +8,34 @@ class SMBHBinary(MassProfile): + r""" + Binary supermassive black hole (SMBH) system modelled as two point masses. + + The binary is represented by two :class:`SMBH` mass profiles placed symmetrically + about the system ``centre``. The total mass :math:`M_{\rm tot}` and mass ratio + :math:`q_m` determine the individual masses: + + .. math:: + + M_0 = M_{\rm tot} \frac{q_m}{1 + q_m}, \qquad + M_1 = M_{\rm tot} \frac{1}{1 + q_m} + + Each component follows the point-mass lensing law: + + .. math:: + + \boldsymbol{\alpha}_i(\boldsymbol{\theta}) = + \frac{\theta_{E,i}^2}{|\boldsymbol{\theta} - \boldsymbol{\theta}_i|}\, + \hat{r}_i + + The total deflection, convergence, and potential are the sum of the two individual + :class:`SMBH` contributions. + + This profile is used to model the lensing effect of SMBH binaries expected to + form following galaxy mergers, whose gravitational influence can perturb the + positions of images near the nucleus. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -18,29 +46,24 @@ def __init__( redshift_object: float = 0.5, redshift_source: float = 1.0, ): - """ - Represents a supermassive black hole (SMBH) binary (e.g. two merging SMBH's at the centre of a galaxy). - - This uses two `SMBH` mass profiles to represent the SMBHs. - + r""" Parameters ---------- centre - The (y,x) arc-second coordinates of centre of the SMBH binary, defined as the mid-point between the - two SMBHs. + The (y,x) arc-second coordinates of the binary mid-point. separation - The arc-second separation between the two SMBHs. + The angular separation between the two SMBHs in arcseconds. angle_binary - The angle between the two SMBHs relative to the positive x-axis of the centre of the SMBH binary. + The orientation angle of the binary axis relative to the positive + x-axis (degrees, anticlockwise). mass - The sum of the masses of the two SMBHs in solar masses. + The total mass of the binary system in solar masses :math:`M_\odot`. mass_ratio - The ratio of the mass of the second SMBH to the first SMBH. A mass ratio of 2.0 gives two SMBHs where - the first SMBH has twice the mass of the second SMBH. + The mass ratio :math:`q_m = M_0 / M_1` (:math:`q_m \geq 1` by convention). redshift_object - The redshift of the SMBH, which is used to convert its mass to an Einstein radius. + The redshift of the SMBH binary (lens plane). redshift_source - The redshift of the source galaxy, which is used to convert the mass of the SMBH to an Einstein radius. + The redshift of the lensed source galaxy. """ self.separation = separation diff --git a/autogalaxy/profiles/mass/sheets/external_potential.py b/autogalaxy/profiles/mass/sheets/external_potential.py index 4b37a3ec..87044b0c 100644 --- a/autogalaxy/profiles/mass/sheets/external_potential.py +++ b/autogalaxy/profiles/mass/sheets/external_potential.py @@ -8,6 +8,34 @@ class ExternalPotential(MassProfile): + r""" + Higher-order external potential extending the constant external shear. + + The ``ExternalPotential`` captures up to spin-3 contributions from line-of-sight + mass in strong-lens models, following Powell et al. (2022) Eq. 4. The lensing + potential is: + + .. math:: + + \psi(\boldsymbol{r}) = + \tfrac{1}{2} r^2 (\gamma_1 \cos 2\theta + \gamma_2 \sin 2\theta) + + \tfrac{1}{4} r^3 (\tau_1 \cos\theta + \tau_2 \sin\theta) + + \tfrac{1}{6} r^3 (\delta_1 \cos 3\theta + \delta_2 \sin 3\theta) + + where :math:`(r, \theta)` are polar coordinates centred on ``centre``. + + - The :math:`\gamma` term is a constant external shear (spin-2); with + :math:`\tau_i = \delta_i = 0` this reduces to :class:`ExternalShear`. + - The :math:`\tau` term (spin-1) introduces a linear convergence gradient: + :math:`\kappa(x, y) = \tau_1 x + \tau_2 y`. + - The :math:`\delta` term (spin-3) is a higher-order generalised shear with zero + convergence contribution. + + References + ---------- + - Powell, Vegetti, McKean et al. 2022, MNRAS, 516, 1808 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/sheets/external_shear.py b/autogalaxy/profiles/mass/sheets/external_shear.py index 20e3f991..a973ab49 100644 --- a/autogalaxy/profiles/mass/sheets/external_shear.py +++ b/autogalaxy/profiles/mass/sheets/external_shear.py @@ -8,6 +8,46 @@ class ExternalShear(MassProfile): + r""" + Constant external shear field used in strong-lens mass models. + + The external shear represents the line-of-sight contribution to the lensing + potential from mass external to the primary lens (e.g. nearby group members, + large-scale structure). Because this contribution is approximately uniform over + the small angular extent of a strong-lens system, it is modelled as a constant + shear with two Cartesian components :math:`(\gamma_1, \gamma_2)`. + + The lensing potential is: + + .. math:: + + \psi(\boldsymbol{\theta}) = + -\tfrac{1}{2} |\gamma| \, r^2 \cos\!\big(2(\varphi - \phi_\gamma)\big) + + The deflection field in a reference frame aligned with the shear direction is: + + .. math:: + + \alpha_y = -|\gamma| \, y, \qquad \alpha_x = +|\gamma| \, x + + The convergence vanishes identically: + + .. math:: + + \kappa = 0 + + The shear magnitude and position angle are: + + .. math:: + + |\gamma| = \sqrt{\gamma_1^2 + \gamma_2^2}, \qquad + \phi_\gamma = \tfrac{1}{2} \mathrm{arctan2}(\gamma_2, \gamma_1) + + References + ---------- + - Schneider, Ehlers & Falco 1992, *Gravitational Lenses* (Springer) + """ + def __init__(self, gamma_1: float = 0.0, gamma_2: float = 0.0): r""" Constant external shear term used in strong-lens mass models. diff --git a/autogalaxy/profiles/mass/sheets/mass_sheet.py b/autogalaxy/profiles/mass/sheets/mass_sheet.py index a20207af..b6b71068 100644 --- a/autogalaxy/profiles/mass/sheets/mass_sheet.py +++ b/autogalaxy/profiles/mass/sheets/mass_sheet.py @@ -7,16 +7,42 @@ class MassSheet(MassProfile): - def __init__(self, centre: Tuple[float, float] = (0.0, 0.0), kappa: float = 0.0): - """ - Represents a mass-sheet + r""" + Uniform convergence mass sheet. + + A mass sheet produces a spatially constant convergence :math:`\kappa_{\rm ext}` + across the lens plane. It is the simplest realisation of the mass-sheet degeneracy + (Gorenstein 1988): any lensing configuration can be transformed by adding a sheet + without changing observed image positions or flux ratios. + + The convergence, lensing potential, and deflection field are: + + .. math:: + + \kappa(\boldsymbol{\theta}) = \kappa_{\rm ext} + .. math:: + + \psi(\boldsymbol{\theta}) = \tfrac{1}{2} \kappa_{\rm ext} \, |\boldsymbol{\theta}|^2 + + .. math:: + + \boldsymbol{\alpha}(\boldsymbol{\theta}) = \kappa_{\rm ext} \, \boldsymbol{\theta} + + References + ---------- + - Gorenstein, Falco & Shapiro 1988, ApJ, 327, 693 + - Schneider & Sluse 2013, A&A, 559, A37 + """ + + def __init__(self, centre: Tuple[float, float] = (0.0, 0.0), kappa: float = 0.0): + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. kappa - The magnitude of the convergence of the mass-sheet. + The uniform convergence :math:`\kappa_{\rm ext}` of the mass sheet. """ super().__init__(centre=centre, ell_comps=(0.0, 0.0)) self.kappa = kappa diff --git a/autogalaxy/profiles/mass/stellar/chameleon.py b/autogalaxy/profiles/mass/stellar/chameleon.py index 59327f33..23069570 100644 --- a/autogalaxy/profiles/mass/stellar/chameleon.py +++ b/autogalaxy/profiles/mass/stellar/chameleon.py @@ -10,6 +10,33 @@ class Chameleon(MassProfile, StellarProfile): + r""" + Elliptical Chameleon stellar mass profile (Dutton et al. 2011). + + The Chameleon profile is the difference of two cored isothermal (pseudo-Jaffe) profiles + with core radii :math:`s_0` and :math:`s_0 + s_1`, providing a flexible approximation + to a variety of stellar light profiles: + + .. math:: + + \kappa(\xi) = \Upsilon \, I \left( + \frac{1}{\sqrt{\xi^2 + s_0^2}} + - \frac{1}{\sqrt{\xi^2 + (s_0 + s_1)^2}} + \right) + + where :math:`\xi^2 = x^2 + (y/q)^2` is the elliptical radius, :math:`\Upsilon` is + the mass-to-light ratio (``mass_to_light_ratio``), :math:`I` is the intensity + normalisation (``intensity``), :math:`s_0` = ``core_radius_0``, and + :math:`s_1` = ``core_radius_1``. + + Deflection angles are computed analytically via the cored isothermal deflection + formula (Eq. 15–16 of Dutton et al. 2011). + + References + ---------- + - Dutton, Brewer, Marshall et al. 2011, MNRAS, 417, 1621 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -19,9 +46,7 @@ def __init__( core_radius_1: float = 0.02, mass_to_light_ratio: float = 1.0, ): - """ - The elliptical Chamelon mass profile. - + r""" Parameters ---------- centre @@ -29,15 +54,15 @@ def __init__( ell_comps The first and second ellipticity components of the elliptical coordinate system. intensity - Overall intensity normalisation of the light profile (units are dimensionless and derived from the data - the light profile's image is compared too, which is expected to be electrons per second). - core_radius_0 : the core size of the first elliptical cored Isothermal profile. - core_radius_1 : core_radius_0 + core_radius_1 is the core size of the second elliptical cored Isothermal profile. - We use core_radius_1 here is to avoid negative values. - - Profile form: - mass_to_light_ratio * intensity *\ - (1.0 / Sqrt(x^2 + (y/q)^2 + core_radius_0^2) - 1.0 / Sqrt(x^2 + (y/q)^2 + (core_radius_0 + core_radius_1)**2.0)) + Overall intensity normalisation :math:`I` (electrons per second). + core_radius_0 + Core radius :math:`s_0` of the first cored isothermal component (arcseconds). + core_radius_1 + Additional core size increment :math:`s_1` such that the second component has + core radius :math:`s_0 + s_1` (arcseconds). Using an increment avoids + negative parameter values. + mass_to_light_ratio + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super(Chameleon, self).__init__(centre=centre, ell_comps=ell_comps) @@ -205,6 +230,24 @@ def axis_ratio(self, xp=np): class ChameleonSph(Chameleon): + r""" + Spherical Chameleon stellar mass profile. + + A special case of :class:`Chameleon` with no ellipticity (:math:`q = 1`). + The convergence is: + + .. math:: + + \kappa(r) = \Upsilon \, I \left( + \frac{1}{\sqrt{r^2 + s_0^2}} + - \frac{1}{\sqrt{r^2 + (s_0 + s_1)^2}} + \right) + + References + ---------- + - Dutton, Brewer, Marshall et al. 2011, MNRAS, 417, 1621 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -213,26 +256,21 @@ def __init__( core_radius_1: float = 0.02, mass_to_light_ratio: float = 1.0, ): - """ - The spherica; Chameleon mass profile. - - Profile form: - mass_to_light_ratio * intensity *\ - (1.0 / Sqrt(x^2 + (y/q)^2 + core_radius_0^2) - 1.0 / Sqrt(x^2 + (y/q)^2 + (core_radius_0 + core_radius_1)**2.0)) - + r""" 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. intensity - Overall intensity normalisation of the light profile (units are dimensionless and derived from the data - the light profile's image is compared too, which is expected to be electrons per second). - core_radius_0 : the core size of the first elliptical cored Isothermal profile. - core_radius_1 : core_radius_0 + core_radius_1 is the core size of the second elliptical cored Isothermal profile. - We use core_radius_1 here is to avoid negative values. - """ + Overall intensity normalisation :math:`I` (electrons per second). + core_radius_0 + Core radius :math:`s_0` of the first cored isothermal component (arcseconds). + core_radius_1 + Additional core size increment :math:`s_1` such that the second component has + core radius :math:`s_0 + s_1` (arcseconds). + mass_to_light_ratio + The mass-to-light ratio :math:`\Upsilon` in solar units. + """ super().__init__( centre=centre, diff --git a/autogalaxy/profiles/mass/stellar/dev_vaucouleurs.py b/autogalaxy/profiles/mass/stellar/dev_vaucouleurs.py index c0433161..e96e4d06 100644 --- a/autogalaxy/profiles/mass/stellar/dev_vaucouleurs.py +++ b/autogalaxy/profiles/mass/stellar/dev_vaucouleurs.py @@ -4,6 +4,26 @@ class DevVaucouleurs(Sersic): + r""" + Elliptical de Vaucouleurs stellar mass profile (de Vaucouleurs 1948). + + A special case of the :class:`Sersic` mass profile with Sérsic index :math:`n = 4`, + corresponding to the classical de Vaucouleurs :math:`R^{1/4}` surface brightness law + that describes the light distribution of massive elliptical galaxies: + + .. math:: + + \kappa(R) = \Upsilon \, I_e \exp\!\left\{ + -b_4 \left[\left(\frac{R}{R_e}\right)^{1/4} - 1\right] + \right\} + + where :math:`b_4 \approx 7.669` ensures :math:`R_e` is the half-light radius. + + References + ---------- + - de Vaucouleurs 1948, Ann. Astrophys., 11, 247 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -12,10 +32,7 @@ def __init__( effective_radius: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The DevVaucouleurs mass profile, the mass profiles of the light profiles that are used to fit and - subtract the lens model_galaxy's light. - + r""" Parameters ---------- centre @@ -23,11 +40,12 @@ def __init__( ell_comps The first and second ellipticity components of the elliptical coordinate system. intensity - Overall flux intensity normalisation in the light profiles (electrons per second). + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. mass_to_light_ratio - The mass-to-light ratio of the light profile. + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super().__init__( centre=centre, @@ -40,6 +58,23 @@ def __init__( class DevVaucouleursSph(DevVaucouleurs): + r""" + Spherical de Vaucouleurs stellar mass profile. + + A special case of :class:`DevVaucouleurs` with no ellipticity (:math:`q = 1`), + i.e., a :class:`Sersic` profile with :math:`n = 4` evaluated on a circular grid: + + .. math:: + + \kappa(r) = \Upsilon \, I_e \exp\!\left\{ + -b_4 \left[\left(\frac{r}{R_e}\right)^{1/4} - 1\right] + \right\} + + References + ---------- + - de Vaucouleurs 1948, Ann. Astrophys., 11, 247 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -47,20 +82,18 @@ def __init__( effective_radius: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The DevVaucouleurs mass profile, the mass profiles of the light profiles that are used to fit and subtract the - lens model_galaxy's light. - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. intensity - Overall flux intensity normalisation in the light profiles (electrons per second). + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The circular radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. mass_to_light_ratio - The mass-to-light ratio of the light profiles. + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super().__init__( centre=centre, diff --git a/autogalaxy/profiles/mass/stellar/exponential.py b/autogalaxy/profiles/mass/stellar/exponential.py index 32d13387..2bb46f79 100644 --- a/autogalaxy/profiles/mass/stellar/exponential.py +++ b/autogalaxy/profiles/mass/stellar/exponential.py @@ -4,6 +4,20 @@ class Exponential(Sersic): + r""" + Elliptical exponential stellar mass profile. + + A special case of the :class:`Sersic` mass profile with Sérsic index :math:`n = 1`, + corresponding to an exponential disc surface brightness profile: + + .. math:: + + \kappa(R) = \Upsilon \, I_e \exp\!\left(-b_1 \left[\frac{R}{R_e} - 1\right]\right) + + where :math:`b_1 \approx 1.678` ensures :math:`R_e` is the half-light radius. + This profile is commonly used to model disc-dominated galaxies. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -12,10 +26,7 @@ def __init__( effective_radius: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The Exponential mass profile, the mass profiles of the light profiles that are used to fit and - subtract the lens model_galaxy's light. - + r""" Parameters ---------- centre @@ -23,11 +34,12 @@ def __init__( ell_comps The first and second ellipticity components of the elliptical coordinate system. intensity - Overall flux intensity normalisation in the light profiles (electrons per second). + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The circular radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. mass_to_light_ratio - The mass-to-light ratio of the light profiles + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super().__init__( centre=centre, @@ -40,6 +52,17 @@ def __init__( class ExponentialSph(Exponential): + r""" + Spherical exponential stellar mass profile. + + A special case of :class:`Exponential` with no ellipticity (:math:`q = 1`), + i.e., a :class:`Sersic` profile with :math:`n = 1` evaluated on a circular grid: + + .. math:: + + \kappa(r) = \Upsilon \, I_e \exp\!\left(-b_1 \left[\frac{r}{R_e} - 1\right]\right) + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -47,20 +70,18 @@ def __init__( effective_radius: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The Exponential mass profile, the mass profiles of the light profiles that are used to fit and subtract the lens - model_galaxy's light. - + r""" Parameters ---------- centre The (y,x) arc-second coordinates of the profile centre. intensity - Overall flux intensity normalisation in the light profiles (electrons per second). + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The circular radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. mass_to_light_ratio - The mass-to-light ratio of the light profiles. + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super().__init__( centre=centre, diff --git a/autogalaxy/profiles/mass/stellar/gaussian.py b/autogalaxy/profiles/mass/stellar/gaussian.py index 4cc74d23..4d55211f 100644 --- a/autogalaxy/profiles/mass/stellar/gaussian.py +++ b/autogalaxy/profiles/mass/stellar/gaussian.py @@ -9,6 +9,30 @@ class Gaussian(MassProfile, StellarProfile): + r""" + Elliptical Gaussian stellar mass profile. + + The convergence of the Gaussian mass profile is proportional to the Gaussian surface + brightness scaled by a mass-to-light ratio: + + .. math:: + + \kappa(R) = \Upsilon \, \frac{I}{2\pi\sigma^2} + \exp\!\left(-\frac{R^2}{2\sigma^2}\right) + + where :math:`\Upsilon` is the mass-to-light ratio (``mass_to_light_ratio``), + :math:`I` is the overall intensity normalisation (``intensity``), :math:`\sigma` is + the Gaussian width (``sigma``), and :math:`R` is the elliptical radius + :math:`R^2 = x^2 + y^2/q^2` with axis ratio :math:`q`. + + Deflection angles are computed analytically via the Faddeeva (scaled complementary + error) function :math:`w(z)` following Shajib (2019). + + References + ---------- + - Shajib 2019, MNRAS, 488, 1387 (arXiv:1906.08263) + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -17,9 +41,7 @@ def __init__( sigma: float = 1.0, mass_to_light_ratio: float = 1.0, ): - """ - The elliptical Gaussian light profile. - + r""" Parameters ---------- centre @@ -27,10 +49,11 @@ def __init__( ell_comps The first and second ellipticity components of the elliptical coordinate system. intensity - Overall intensity normalisation of the light profile (units are dimensionless and derived from the data - the light profile's image is compared too, which is expected to be electrons per second). + Overall intensity normalisation :math:`I` of the Gaussian (electrons per second). sigma - The sigma value of the Gaussian. + The Gaussian width :math:`\sigma` in arcseconds. + mass_to_light_ratio + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super(MassProfile, self).__init__(centre=centre, ell_comps=ell_comps) diff --git a/autogalaxy/profiles/mass/stellar/sersic.py b/autogalaxy/profiles/mass/stellar/sersic.py index 8df7c67b..8bd34424 100644 --- a/autogalaxy/profiles/mass/stellar/sersic.py +++ b/autogalaxy/profiles/mass/stellar/sersic.py @@ -83,6 +83,34 @@ def cse_settings_from( class AbstractSersic(MassProfile, MassProfileCSE, StellarProfile): + r""" + Abstract base class for Sérsic stellar mass profiles. + + The convergence of a Sérsic mass profile is proportional to the Sérsic surface + brightness profile scaled by a constant mass-to-light ratio: + + .. math:: + + \kappa(R) = \Upsilon \, I_e \exp\!\left\{ + -b_n \left[\left(\frac{R}{R_e}\right)^{1/n} - 1\right] + \right\} + + where :math:`\Upsilon` is the mass-to-light ratio (``mass_to_light_ratio``), + :math:`I_e` is the intensity at the effective radius (``intensity``), + :math:`R_e` is the effective (half-light) radius (``effective_radius``), :math:`n` is + the Sérsic index (``sersic_index``), and :math:`b_n` is a constant that ensures the + effective radius encloses half the total luminosity (approximated by a polynomial in + :math:`n`). + + Deflection angles are computed via a cored-steep-ellipsoid (CSE) decomposition + following Oguri (2021). + + References + ---------- + - Sérsic 1963, Boletin de la Asociacion Argentina de Astronomia, 6, 41 + - Oguri 2021, PASP, 133, 074504 (arXiv:2106.11464) + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -92,10 +120,7 @@ def __init__( sersic_index: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The Sersic mass profile, the mass profiles of the light profiles that are used to fit and subtract the lens \ - model_galaxy's light. - + r""" Parameters ---------- centre @@ -103,13 +128,15 @@ def __init__( ell_comps The first and second ellipticity components of the elliptical coordinate system. intensity - Overall flux intensity normalisation in the light profiles (electrons per second). + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. sersic_index - Controls the concentration of the profile (lower -> less concentrated, higher -> more concentrated). + The Sérsic index :math:`n` controlling profile concentration + (lower -> less concentrated, higher -> more concentrated). mass_to_light_ratio - The mass-to-light ratio of the light profiles + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super(AbstractSersic, self).__init__(centre=centre, ell_comps=ell_comps) super(MassProfile, self).__init__(centre=centre, ell_comps=ell_comps) @@ -307,10 +334,49 @@ def elliptical_effective_radius(self): class Sersic(AbstractSersic, MassProfileCSE): + r""" + Elliptical Sérsic stellar mass profile. + + Inherits the full Sérsic convergence and CSE deflection-angle machinery from + :class:`AbstractSersic`. The convergence is: + + .. math:: + + \kappa(R) = \Upsilon \, I_e \exp\!\left\{ + -b_n \left[\left(\frac{R}{R_e}\right)^{1/n} - 1\right] + \right\} + + where :math:`R` is the elliptical radius, :math:`\Upsilon` is the mass-to-light + ratio, :math:`I_e` is the intensity at the effective radius :math:`R_e`, and + :math:`b_n` is determined from the Sérsic index :math:`n`. + + References + ---------- + - Sérsic 1963, Boletin de la Asociacion Argentina de Astronomia, 6, 41 + - Oguri 2021, PASP, 133, 074504 (arXiv:2106.11464) + """ + pass class SersicSph(Sersic): + r""" + Spherical Sérsic stellar mass profile. + + A special case of :class:`Sersic` with no ellipticity (:math:`q = 1`). The + convergence is evaluated on a circular radial grid: + + .. math:: + + \kappa(r) = \Upsilon \, I_e \exp\!\left\{ + -b_n \left[\left(\frac{r}{R_e}\right)^{1/n} - 1\right] + \right\} + + References + ---------- + - Sérsic 1963, Boletin de la Asociacion Argentina de Astronomia, 6, 41 + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -319,22 +385,21 @@ def __init__( sersic_index: float = 0.6, mass_to_light_ratio: float = 1.0, ): - """ - The Sersic mass profile, the mass profiles of the light profiles that are used to fit and subtract the lens - model_galaxy's light. - + r""" Parameters ---------- centre - The (y,x) arc-second coordinates of the profile centre + The (y,x) arc-second coordinates of the profile centre. intensity - Overall flux intensity normalisation in the light profiles (electrons per second) + Overall intensity normalisation :math:`I_e` at the effective radius + (electrons per second). effective_radius - The circular radius containing half the light of this profile. + The effective (half-light) radius :math:`R_e` in arcseconds. sersic_index - Controls the concentration of the profile (lower -> less concentrated, higher -> more concentrated). + The Sérsic index :math:`n` controlling profile concentration + (lower -> less concentrated, higher -> more concentrated). mass_to_light_ratio - The mass-to-light ratio of the light profile. + The mass-to-light ratio :math:`\Upsilon` in solar units. """ super().__init__( centre=centre, diff --git a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py index 0ef210e2..39b8fd81 100644 --- a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py +++ b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_mass.py @@ -357,6 +357,54 @@ def analytical_magnification_2d_from( class dPIEMass(MassProfile): + r"""Dual pseudo-isothermal elliptical mass distribution (dPIE, mass parameterisation). + + A two-component PIE profile with both a core radius :math:`r_a` and a + truncation radius :math:`r_s`. The three-dimensional density scales as + :math:`\rho \propto r^{-2}` in the transition region + :math:`r_a \leq R \leq r_s` and as :math:`\rho \propto r^{-4}` in the outer + parts, with the full form: + + .. math:: + + \rho \propto \bigl[(r_a^2 + R^2)(r_s^2 + R^2)\bigr]^{-1} + + The projected convergence is the difference of two PIE profiles: + + .. math:: + + \kappa(r_{\rm em}) = \frac{b_0}{2} \frac{r_s}{r_s - r_a} + \left( + \frac{1}{\sqrt{r_a^2 + r_{\rm em}^2}} + - \frac{1}{\sqrt{r_s^2 + r_{\rm em}^2}} + \right) + + where :math:`r_{\rm em}^2 = x^2/(1+\epsilon)^2 + y^2/(1-\epsilon)^2` is + the pseudo-elliptical radius and :math:`b_0` is the lens strength (equal to + the Einstein radius when :math:`r_a \to 0`, :math:`r_s \to \infty`, and + :math:`q \to 1`). This profile is ported directly from Lenstool's C code. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + ra : float + Inner core radius in arcseconds. + rs : float + Outer truncation radius in arcseconds. + b0 : float + Lens strength in arcseconds (Einstein radius in the limit + :math:`r_a \to 0`, :math:`r_s \to \infty`, :math:`q \to 1`). + + References + ---------- + Kassiola & Kovner (1993), ApJ, 417, 450. + Eliasdottir et al. (2007), arXiv:0710.5636. + Limousin et al. (2005), A&A, 461, 881. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -546,6 +594,42 @@ def potential_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): class dPIEMassSph(dPIEMass): + r"""Spherical dual pseudo-isothermal mass distribution (dPIE, mass parameterisation). + + The spherical limit of :class:`dPIEMass`. The projected convergence is: + + .. math:: + + \kappa(r) = \frac{b_0}{2} \frac{r_s}{r_s - r_a} + \left( + \frac{1}{\sqrt{r_a^2 + r^2}} + - \frac{1}{\sqrt{r_s^2 + r^2}} + \right) + + where :math:`r` is the circular projected radius, :math:`r_a` is the core + radius, :math:`r_s` is the truncation radius, and :math:`b_0` is the lens + strength (Einstein radius in the limits :math:`r_a \to 0`, + :math:`r_s \to \infty`). + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ra : float + Inner core radius in arcseconds. + rs : float + Outer truncation radius in arcseconds. + b0 : float + Lens strength in arcseconds (Einstein radius in the limit + :math:`r_a \to 0`, :math:`r_s \to \infty`). + + References + ---------- + Kassiola & Kovner (1993), ApJ, 417, 450. + Eliasdottir et al. (2007), arXiv:0710.5636. + Limousin et al. (2005), A&A, 461, 881. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py index d30259f3..c555675b 100644 --- a/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py +++ b/autogalaxy/profiles/mass/total/dual_pseudo_isothermal_potential.py @@ -6,6 +6,42 @@ class dPIEPotential(MassProfile): + r"""Dual pseudo-isothermal elliptical mass profile (dPIE, potential parameterisation). + + A dPIE profile in which ellipticity is applied to the lensing potential rather + than the mass distribution. The circularly symmetric convergence takes the + same functional form as :class:`dPIEMassSph`: + + .. math:: + + \kappa(R) = \frac{b_0}{2} \frac{r_s}{r_s - r_a} + \left( + \frac{1}{\sqrt{r_a^2 + R^2}} + - \frac{1}{\sqrt{r_s^2 + R^2}} + \right) + + but ellipticity enters through a pseudo-elliptical radius + :math:`R^2 = x^2(1-\epsilon) + y^2(1+\epsilon)` in the deflection, rather + than through a purely elliptical mass distribution. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + ra : float + Inner core scale radius in arcseconds. + rs : float + Outer truncation scale radius in arcseconds. + b0 : float + Lens strength in arcseconds (Einstein radius in the limit + :math:`r_a \to 0`, :math:`r_s \to \infty`, :math:`q \to 1`). + + References + ---------- + Eliasdottir et al. (2007), arXiv:0710.5636. + """ def __init__( self, @@ -168,6 +204,38 @@ def potential_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs): class dPIEPotentialSph(dPIEPotential): + r"""Spherical dual pseudo-isothermal mass profile (dPIE, potential parameterisation). + + The spherical limit of :class:`dPIEPotential`. The convergence is: + + .. math:: + + \kappa(r) = \frac{b_0}{2} \frac{r_s}{r_s - r_a} + \left( + \frac{1}{\sqrt{r_a^2 + r^2}} + - \frac{1}{\sqrt{r_s^2 + r^2}} + \right) + + where :math:`r` is the circular projected radius. This profile is + mathematically identical to :class:`dPIEMassSph`. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ra : float + Inner core scale radius in arcseconds. + rs : float + Outer truncation scale radius in arcseconds. + b0 : float + Lens strength in arcseconds (Einstein radius in the limit + :math:`r_a \to 0`, :math:`r_s \to \infty`). + + References + ---------- + Eliasdottir et al. (2007), arXiv:0710.5636. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/isothermal.py b/autogalaxy/profiles/mass/total/isothermal.py index b69d8c00..2e50ba2d 100644 --- a/autogalaxy/profiles/mass/total/isothermal.py +++ b/autogalaxy/profiles/mass/total/isothermal.py @@ -39,6 +39,34 @@ def psi_from(grid, axis_ratio, core_radius, xp=np): class Isothermal(PowerLaw): + r"""Singular isothermal ellipsoid (SIE) mass profile. + + The convergence of the SIE is: + + .. math:: + + \kappa(R) = \frac{\theta_{\rm E}}{2R} + + where :math:`\theta_{\rm E}` is the Einstein radius and :math:`R` is the + elliptical radius defined as :math:`R^2 = q x^2 + y^2 / q` with axis ratio + :math:`q`. This is the special case of the power-law profile with slope + :math:`\gamma = 2`. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + einstein_radius : float + Einstein radius in arcseconds. + + References + ---------- + Kormann, Schneider & Bartelmann (1994), A&A, 284, 285. + Tessore & Metcalf (2015), A&A, 580, A79. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -177,6 +205,30 @@ def convergence_func(self, grid_radius: float, xp=np) -> float: class IsothermalSph(Isothermal): + r"""Singular isothermal sphere (SIS) mass profile. + + The spherical limit of the SIE. The convergence is: + + .. math:: + + \kappa(r) = \frac{\theta_{\rm E}}{2r} + + where :math:`\theta_{\rm E}` is the Einstein radius and :math:`r` is the + circular projected radius. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds. + + References + ---------- + Kormann, Schneider & Bartelmann (1994), A&A, 284, 285. + Tessore & Metcalf (2015), A&A, 580, A79. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), einstein_radius: float = 1.0 ): diff --git a/autogalaxy/profiles/mass/total/isothermal_core.py b/autogalaxy/profiles/mass/total/isothermal_core.py index 0735511b..bdf71350 100644 --- a/autogalaxy/profiles/mass/total/isothermal_core.py +++ b/autogalaxy/profiles/mass/total/isothermal_core.py @@ -5,6 +5,35 @@ class IsothermalCore(PowerLawCore): + r"""Cored elliptical isothermal (SIE with core) mass profile. + + The convergence of the cored isothermal ellipsoid is: + + .. math:: + + \kappa(R) = \frac{\theta_{\rm E}}{2\sqrt{R^2 + s^2}} + + where :math:`\theta_{\rm E}` is the Einstein radius, :math:`R` is the + elliptical radius, and :math:`s` is the core radius. In the limit + :math:`s \to 0` this reduces to the standard SIE. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + einstein_radius : float + Einstein radius in arcseconds. + core_radius : float + Core radius :math:`s` in arcseconds. + + References + ---------- + Kormann, Schneider & Bartelmann (1994), A&A, 284, 285. + Keeton (2001), arXiv:astro-ph/0102341. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -37,6 +66,33 @@ def __init__( class IsothermalCoreSph(PowerLawCoreSph): + r"""Cored spherical isothermal (SIS with core) mass profile. + + The convergence of the cored spherical isothermal is: + + .. math:: + + \kappa(r) = \frac{\theta_{\rm E}}{2\sqrt{r^2 + s^2}} + + where :math:`\theta_{\rm E}` is the Einstein radius, :math:`r` is the + circular projected radius, and :math:`s` is the core radius. This is + the spherical special case of :class:`IsothermalCore`. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds. + core_radius : float + Core radius :math:`s` in arcseconds. + + References + ---------- + Kormann, Schneider & Bartelmann (1994), A&A, 284, 285. + Keeton (2001), arXiv:astro-ph/0102341. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/power_law.py b/autogalaxy/profiles/mass/total/power_law.py index 55af3f39..67be63ed 100644 --- a/autogalaxy/profiles/mass/total/power_law.py +++ b/autogalaxy/profiles/mass/total/power_law.py @@ -7,6 +7,37 @@ class PowerLaw(PowerLawCore): + r"""Elliptical power-law (EPL / PEMD) mass profile. + + The convergence of the elliptical power-law is: + + .. math:: + + \kappa(R) = \frac{3 - \gamma}{2} + \left(\frac{\theta_{\rm E}}{R}\right)^{\gamma - 1} + + where :math:`\gamma` is the logarithmic density slope, :math:`\theta_{\rm E}` + is the Einstein radius, and :math:`R` is the elliptical radius. The + isothermal case corresponds to :math:`\gamma = 2`. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + einstein_radius : float + Einstein radius in arcseconds. + slope : float + Logarithmic density slope :math:`\gamma`; shallower profiles have + lower values, steeper profiles have higher values. + + References + ---------- + Tessore & Metcalf (2015), A&A, 580, A79. + Schneider, Ehlers & Falco (1992), *Gravitational Lenses*, Springer. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -138,6 +169,33 @@ def potential_func(u, y, x, axis_ratio, slope, core_radius, xp=np): class PowerLawSph(PowerLaw): + r"""Spherical power-law mass profile. + + The spherical limit of :class:`PowerLaw`. The convergence is: + + .. math:: + + \kappa(r) = \frac{3 - \gamma}{2} + \left(\frac{\theta_{\rm E}}{r}\right)^{\gamma - 1} + + where :math:`\gamma` is the logarithmic density slope, :math:`\theta_{\rm E}` + is the Einstein radius, and :math:`r` is the circular projected radius. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds. + slope : float + Logarithmic density slope :math:`\gamma`; shallower profiles have + lower values, steeper profiles have higher values. + + References + ---------- + Tessore & Metcalf (2015), A&A, 580, A79. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/power_law_broken.py b/autogalaxy/profiles/mass/total/power_law_broken.py index 92c277ec..f686f99a 100644 --- a/autogalaxy/profiles/mass/total/power_law_broken.py +++ b/autogalaxy/profiles/mass/total/power_law_broken.py @@ -7,6 +7,48 @@ class PowerLawBroken(MassProfile): + r"""Broken elliptical power-law mass profile with inner and outer slopes. + + The convergence has a power-law form with different slopes inside and + outside a break radius :math:`\theta_{\rm b}`, matched to be continuous + at the break: + + .. math:: + + \kappa(R) = \begin{cases} + \kappa_{\rm b} + \left(\dfrac{\theta_{\rm b}}{R}\right)^{\gamma_{\rm in}} + & R \leq \theta_{\rm b} \\[6pt] + \kappa_{\rm b} + \left(\dfrac{\theta_{\rm b}}{R}\right)^{\gamma_{\rm out}} + & R > \theta_{\rm b} + \end{cases} + + where :math:`\gamma_{\rm in}` and :math:`\gamma_{\rm out}` are the inner and + outer logarithmic slopes, :math:`\theta_{\rm b}` is the break radius, and + :math:`\kappa_{\rm b}` is the convergence at the break radius (set by the + normalisation condition on the Einstein radius). + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + einstein_radius : float + Einstein radius in arcseconds. + inner_slope : float + Logarithmic density slope :math:`\gamma_{\rm in}` inside the break radius. + outer_slope : float + Logarithmic density slope :math:`\gamma_{\rm out}` outside the break radius. + break_radius : float + Break radius :math:`\theta_{\rm b}` in arcseconds separating the two power-law regimes. + + References + ---------- + Du, Metcalf & Barkana (2020), MNRAS, 495, 4209. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -173,6 +215,43 @@ def hyp2f1_series(t, q, r, z, max_terms=20, xp=np): class PowerLawBrokenSph(PowerLawBroken): + r"""Broken spherical power-law mass profile with inner and outer slopes. + + The spherical limit of :class:`PowerLawBroken`. The convergence is: + + .. math:: + + \kappa(r) = \begin{cases} + \kappa_{\rm b} + \left(\dfrac{\theta_{\rm b}}{r}\right)^{\gamma_{\rm in}} + & r \leq \theta_{\rm b} \\[6pt] + \kappa_{\rm b} + \left(\dfrac{\theta_{\rm b}}{r}\right)^{\gamma_{\rm out}} + & r > \theta_{\rm b} + \end{cases} + + where :math:`r` is the circular projected radius, :math:`\theta_{\rm b}` is + the break radius, and :math:`\kappa_{\rm b}` is the convergence at the + break radius. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds. + inner_slope : float + Logarithmic density slope :math:`\gamma_{\rm in}` inside the break radius. + outer_slope : float + Logarithmic density slope :math:`\gamma_{\rm out}` outside the break radius. + break_radius : float + Break radius :math:`\theta_{\rm b}` in arcseconds separating the two power-law regimes. + + References + ---------- + Du, Metcalf & Barkana (2020), MNRAS, 495, 4209. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/power_law_core.py b/autogalaxy/profiles/mass/total/power_law_core.py index b1f30ca9..c12be621 100644 --- a/autogalaxy/profiles/mass/total/power_law_core.py +++ b/autogalaxy/profiles/mass/total/power_law_core.py @@ -7,6 +7,40 @@ class PowerLawCore(MassProfile): + r"""Cored elliptical power-law (cored EPL / SPEMD) mass profile. + + The convergence of the cored elliptical power-law is: + + .. math:: + + \kappa(R) = \frac{3 - \gamma}{2} + \left(s^2 + R^2\right)^{-({\gamma - 1})/2} + \theta_{\rm E}^{\,\gamma - 1} + + where :math:`\gamma` is the logarithmic density slope, :math:`\theta_{\rm E}` + is the Einstein radius, :math:`R` is the elliptical radius, and :math:`s` is + the core radius that prevents the central divergence of the pure power-law. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + ell_comps : (float, float) + Ellipticity components (e1, e2) of the elliptical coordinate system. + einstein_radius : float + Einstein radius in arcseconds. + slope : float + Logarithmic density slope :math:`\gamma`; shallower profiles have + lower values, steeper profiles have higher values. + core_radius : float + Core radius :math:`s` in arcseconds. + + References + ---------- + Keeton (2001), arXiv:astro-ph/0102341. + Tessore & Metcalf (2015), A&A, 580, A79. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), @@ -175,6 +209,38 @@ def unit_mass(self): class PowerLawCoreSph(PowerLawCore): + r"""Cored spherical power-law mass profile. + + The spherical limit of :class:`PowerLawCore`. The convergence is: + + .. math:: + + \kappa(r) = \frac{3 - \gamma}{2} + \left(s^2 + r^2\right)^{-({\gamma - 1})/2} + \theta_{\rm E}^{\,\gamma - 1} + + where :math:`\gamma` is the logarithmic density slope, :math:`\theta_{\rm E}` + is the Einstein radius, :math:`r` is the circular projected radius, and + :math:`s` is the core radius. + + Parameters + ---------- + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds. + slope : float + Logarithmic density slope :math:`\gamma`; shallower profiles have + lower values, steeper profiles have higher values. + core_radius : float + Core radius :math:`s` in arcseconds. + + References + ---------- + Keeton (2001), arXiv:astro-ph/0102341. + Tessore & Metcalf (2015), A&A, 580, A79. + """ + def __init__( self, centre: Tuple[float, float] = (0.0, 0.0), diff --git a/autogalaxy/profiles/mass/total/power_law_multipole.py b/autogalaxy/profiles/mass/total/power_law_multipole.py index f3d04e90..942e2460 100644 --- a/autogalaxy/profiles/mass/total/power_law_multipole.py +++ b/autogalaxy/profiles/mass/total/power_law_multipole.py @@ -39,80 +39,89 @@ def radial_and_angle_grid_from( class PowerLawMultipole(MassProfile): - def __init__( - self, - m=4, - centre: Tuple[float, float] = (0.0, 0.0), - einstein_radius: float = 1.0, - slope: float = 2.0, - multipole_comps: Tuple[float, float] = (0.0, 0.0), - ): - r""" - A multipole extension with multipole order M to the power-law total mass distribution. + r"""Angular multipole perturbation to a power-law total mass distribution. - Quantities computed from this profile (e.g. deflections, convergence) are of only the multipole, and not the - power-law mass distribution itself. + This profile provides only the multipole perturbation; it must be combined + with a :class:`PowerLaw` profile that shares the same ``einstein_radius`` and + ``slope`` parameters. The multipole convergence is: - The typical use case is therefore for the multipoles to be combined with a `PowerLaw` mass profile with the - same parameters (see example below). + .. math:: - When combined with a power-law, the functional form of the convergence is: + \kappa_m(r, \phi) = \frac{1}{2} + \left(\frac{\theta_{\rm E}}{r}\right)^{\gamma - 1} + k_m \cos\!\bigl(m(\phi - \phi_m)\bigr) - .. math:: - \kappa(r, \phi) = \frac{1}{2} \left(\frac{\theta_{\rm E}^{\rm mass}}{r}\right)^{\gamma^{\rm mass} - 1} - k^{\rm mass}_m \, \cos(m(\phi - \phi^{\rm mass}_m)) \, , + where :math:`m` is the multipole order, :math:`\gamma` is the power-law slope, + :math:`k_m` is the multipole amplitude, and :math:`\phi_m` is the multipole + orientation angle. The amplitude and angle are parameterised via ellipticity + components :math:`(\epsilon_1^{\rm mp},\, \epsilon_2^{\rm mp})`: - Where \\xi are elliptical coordinates calculated according to :class: SphProfile. + .. math:: - The parameters :math: k^{\rm mass}_m and :math: \phi^{\rm mass}_are parameterized as elliptical components - :math: (\epsilon_{\rm 1}^{\rm mp}\,\epsilon_{\rm 2}^{\rm mp}), which are given by: + k_m = \sqrt{{\epsilon_1^{\rm mp}}^2 + {\epsilon_2^{\rm mp}}^2}, \qquad + \phi_m = \frac{1}{m} \arctan\!\frac{\epsilon_2^{\rm mp}}{\epsilon_1^{\rm mp}} - .. math:: - \phi^{\rm mass}_m = \frac{1}{m} \arctan{\frac{\epsilon_{\rm 2}^{\rm mp}}{\epsilon_{\rm 1}^{\rm mp}}}, \, \, - k^{\rm mass}_m = \sqrt{{\epsilon_{\rm 1}^{\rm mp}}^2 + {\epsilon_{\rm 2}^{\rm mp}}^2} \, . + The pure deflection-only nature of the perturbation means the convergence + integrates to zero over all angular positions; the net mass contribution is + therefore zero. - This mass profile is described fully in the following paper: https://arxiv.org/abs/1302.5482 - - Parameters - ---------- - centre - The (y,x) arc-second coordinates of the profile centre. - einstein_radius - The arc-second Einstein radius. - slope - The density slope of the power-law (lower value -> shallower profile, higher value -> steeper profile). - multipole_comps - The first and second ellipticity components of the multipole. - - Examples - -------- - - mass = al.mp.PowerLaw( - centre=(0.0, 0.0), - ell_comps=(-0.1, 0.2), - einstein_radius=1.0, - slope=2.2 - ) - - multipole = al.mp.PowerLawMultipole( - centre=(0.0, 0.0), - einstein_radius=1.0, - slope=2.2, - multipole_comps=(0.3, 0.2) - ) - - galaxy = al.Galaxy( - redshift=0.5, - mass=mass, - multipole=multipole - ) - - grid=al.Grid2D.uniform(shape_native=(10, 10), pixel_scales=0.1) + Parameters + ---------- + m : int + Multipole order (e.g. 4 for the quadrupole-like ``m=4`` mode). + centre : (float, float) + (y, x) arc-second coordinates of the profile centre. + einstein_radius : float + Einstein radius in arcseconds (shared with the base :class:`PowerLaw`). + slope : float + Logarithmic density slope :math:`\gamma` (shared with the base :class:`PowerLaw`). + multipole_comps : (float, float) + Ellipticity-like components :math:`(\epsilon_1^{\rm mp},\, \epsilon_2^{\rm mp})` + that encode the multipole amplitude and orientation. + + References + ---------- + Chu, Hu & Kneib (2013), ApJ, 765, 134. arXiv:1302.5482 + Evans & Witt (2003), MNRAS, 345, 1351. + + Examples + -------- + + mass = al.mp.PowerLaw( + centre=(0.0, 0.0), + ell_comps=(-0.1, 0.2), + einstein_radius=1.0, + slope=2.2 + ) + + multipole = al.mp.PowerLawMultipole( + centre=(0.0, 0.0), + einstein_radius=1.0, + slope=2.2, + multipole_comps=(0.3, 0.2) + ) + + galaxy = al.Galaxy( + redshift=0.5, + mass=mass, + multipole=multipole + ) + + grid=al.Grid2D.uniform(shape_native=(10, 10), pixel_scales=0.1) + + deflections = galaxy.deflections_yx_2d_from( + grid=grid + ) + """ - deflections = galaxy.deflections_yx_2d_from( - grid=grid - ) - """ + def __init__( + self, + m=4, + centre: Tuple[float, float] = (0.0, 0.0), + einstein_radius: float = 1.0, + slope: float = 2.0, + multipole_comps: Tuple[float, float] = (0.0, 0.0), + ): super().__init__(centre=centre, ell_comps=(0.0, 0.0)) self.m = int(m)