Source code for caustics.lenses.func.nfw

from ...backend_obj import backend
from ...utils import translate_rotate
from ...constants import G_over_c2, arcsec_to_rad, rad_to_arcsec


[docs] def scale_radius_nfw(critical_density, mass, c, DELTA=200.0): """ Compute the scale radius of the NFW profile. Parameters ---------- critical_density: ArrayLike The critical density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^3* mass: ArrayLike The mass of the halo. *Unit: Msun* c: ArrayLike The concentration parameter of the halo. *Unit: unitless* DELTA: float The overdensity parameter. Amount above the critical surface density at which the scale radius is computed *Unit: unitless* Returns ------- ArrayLike The scale radius of the NFW profile. *Unit: Mpc* """ r_delta = (3 * mass / (4 * backend.pi * DELTA * critical_density)) ** (1 / 3) # fmt: skip return r_delta / c
[docs] def scale_density_nfw(critical_density, c, DELTA=200.0): """ Compute the scale density of the NFW profile. Parameters ---------- critical_density: ArrayLike The critical density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^3* c: ArrayLike The concentration parameter of the halo. *Unit: unitless* DELTA: float The overdensity parameter. Amount above the critical surface density at which the scale radius is computed *Unit: unitless* Returns ------- ArrayLike The scale density of the NFW profile. *Unit: solar mass per square kiloparsec* """ c_ = 1 + c return DELTA / 3 * critical_density * c**3 / (backend.log(c_) - c / c_) # fmt: skip
[docs] def convergence_s_nfw(critical_surface_density, critical_density, mass, c, DELTA): """ Compute the dimensionaless surface mass density of the lens. critical_surface_density: ArrayLike The critical surface density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^2* critical_density: ArrayLike The critical density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^3* mass: ArrayLike The mass of the halo. *Unit: Msun* c: ArrayLike The concentration parameter of the halo. *Unit: unitless* DELTA: float The overdensity parameter. Amount above the critical surface density at which the scale radius is computed *Unit: unitless* Returns ------- ArrayLike The dimensionless surface mass density of the lens. *Unit: unitless* """ Rs = scale_radius_nfw(critical_density, mass, c, DELTA) Ds = scale_density_nfw(critical_density, c, DELTA) return Rs * Ds / critical_surface_density
def _f_nfw(x): """ Helper method for computing convergence. This can be found in the Meneghetti Lecture notes equation 3.69. Parameters ---------- x: ArrayLike The input to the function. Returns ------- ArrayLike The value of the function f(x). """ # fmt: off x_gt1 = backend.clamp(x, min=1 + 1e-6) x_lt1 = backend.clamp(x, max=1 - 1e-6) f_pos = 1 - 2 * backend.atan(backend.sqrt((x_gt1 - 1) / (x_gt1 + 1))) / backend.sqrt(x_gt1 ** 2 - 1) f_neg = 1 - 2 * backend.atanh(backend.sqrt((1 - x_lt1) / (1 + x_lt1))) / backend.sqrt(1 - x_lt1 ** 2) return backend.where(x > 1, f_pos, backend.where(x < 1, f_neg, backend.zeros_like(x))) # fmt: on def _g_nfw(x): """ Helper method for computing potential. This can be found in the Meneghetti Lecture notes equation 3.71. Parameters ---------- x: ArrayLike The input to the function. Returns ------- ArrayLike The value of the function g(x). """ term_1 = backend.log(x / 2) ** 2 x_gt1 = backend.clamp(x, min=1 + 1e-6) x_lt1 = backend.clamp(x, max=1 - 1e-6) g_pos = backend.arccos(1 / x_gt1) ** 2 g_neg = -backend.arccosh(1 / x_lt1) ** 2 term_2 = backend.where( x > 1, g_pos, backend.where(x < 1, g_neg, backend.zeros_like(x)) ) return term_1 + term_2 def _h_nfw(x): """ Helper method for computing deflection angles. This can be found in the Meneghetti Lecture notes equation 3.73. Parameters ---------- x: ArrayLike The input to the function. Returns ------- ArrayLike The value of the function h(x). """ term_1 = backend.log(x / 2) x_gt1 = backend.clamp(x, min=1 + 1e-6) x_lt1 = backend.clamp(x, max=1 - 1e-6) h_pos = backend.arccos(1 / x_gt1) / backend.sqrt(x_gt1**2 - 1) h_neg = backend.arccosh(1 / x_lt1) / backend.sqrt(1 - x_lt1**2) term_2 = backend.where( x > 1, h_pos, backend.where(x < 1, h_neg, backend.ones_like(x)) ) return term_1 + term_2
[docs] def physical_deflection_angle_nfw( x0, y0, mass, c, critical_density, d_l, x, y, DELTA=200.0, s=0.0, ): """ Compute the physical deflection angles. This is an expanded form of the Meneghetti notes equation 3.72 Parameters ---------- x0: ArrayLike x-coordinate of the center of the lens. *Unit: arcsec* y0: ArrayLike y-coordinate of the center of the lens. *Unit: arcsec* mass: ArrayLike Mass of the lens. Default is None. *Unit: Msun* c: ArrayLike Concentration parameter of the lens. Default is None. *Unit: unitless* x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* s: float Softening parameter to avoid singularities at the center of the lens. Default is 0.0. *Unit: arcsec* """ x, y = translate_rotate(x, y, x0, y0) th = backend.sqrt(x**2 + y**2) + s scale_radius = scale_radius_nfw(critical_density, mass, c, DELTA) xi = d_l * th * arcsec_to_rad r = xi / scale_radius deflection_angle = 16 * backend.pi * G_over_c2 * scale_density_nfw(critical_density, c, DELTA) * scale_radius**3 * _h_nfw(r) * rad_to_arcsec / xi # fmt: skip ax = deflection_angle * x / th ay = deflection_angle * y / th return ax, ay # fmt: skip
[docs] def convergence_nfw( critical_surface_density, critical_density, x0, y0, mass, c, x, y, d_l, DELTA=200.0, s=0.0, ): """ Compute the convergence. This can be found in the Meneghetti Lecture notes equation 3.74. Parameters ---------- critical_surface_density: ArrayLike The critical surface density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^2* critical_density: ArrayLike The critical density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^3* mass: ArrayLike The mass of the halo c: Optional[ArrayLike] Concentration parameter of the lens. Default is None. *Unit: unitless* x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* s: float Softening parameter to avoid singularities at the center of the lens. Default is 0.0. *Unit: arcsec* """ x, y = translate_rotate(x, y, x0, y0) th = backend.sqrt(x**2 + y**2) + s scale_radius = scale_radius_nfw(critical_density, mass, c, DELTA) xi = d_l * th * arcsec_to_rad r = xi / scale_radius # xi / xi_0 convergence_s = convergence_s_nfw( critical_surface_density, critical_density, mass, c, DELTA ) return 2 * convergence_s * _f_nfw(r) / (r**2 - 1) # fmt: skip
[docs] def potential_nfw( critical_surface_density, critical_density, x0, y0, mass, c, d_l, x, y, DELTA=200.0, s=0.0, ): """ Compute the convergence. This can be found in the Meneghetti Lecture notes equation 3.70. Parameters ---------- critical_surface_density: ArrayLike The critical surface density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^2* critical_density: ArrayLike The critical density of the Universe at the appropriate redshift. *Unit: Msun/Mpc^3* mass: ArrayLike The mass of the halo c: Optional[ArrayLike] Concentration parameter of the lens. Default is None. *Unit: unitless* x: ArrayLike x-coordinates in the lens plane. *Unit: arcsec* y: ArrayLike y-coordinates in the lens plane. *Unit: arcsec* s: float Softening parameter to avoid singularities at the center of the lens. Default is 0.0. *Unit: arcsec* """ x, y = translate_rotate(x, y, x0, y0) th = backend.sqrt(x**2 + y**2) + s scale_radius = scale_radius_nfw(critical_density, mass, c, DELTA) xi = d_l * th * arcsec_to_rad r = xi / scale_radius # xi / xi_0 convergence_s = convergence_s_nfw( critical_surface_density, critical_density, mass, c, DELTA ) return 2 * convergence_s * _g_nfw(r) * scale_radius**2 / (d_l**2 * arcsec_to_rad**2) # fmt: skip