Source code for lenstronomy.LensModel.Profiles.hernquist

import numpy as np
from lenstronomy.LensModel.Profiles.base_profile import LensProfileBase

__all__ = ['Hernquist']


[docs]class Hernquist(LensProfileBase): """ class to compute the Hernquist 1990 model, which is in 3d: rho(r) = rho0 / (r/Rs * (1 + (r/Rs))**3) in lensing terms, the normalization parameter 'sigma0' is defined such that the deflection at projected RS leads to alpha = 2./3 * Rs * sigma0 """ _diff = 0.00000001 _s = 0.00001 param_names = ['sigma0', 'Rs', 'center_x', 'center_y'] lower_limit_default = {'sigma0': 0, 'Rs': 0, 'center_x': -100, 'center_y': -100} upper_limit_default = {'sigma0': 100, 'Rs': 100, 'center_x': 100, 'center_y': 100}
[docs] def density(self, r, rho0, Rs): """ computes the 3-d density :param r: 3-d radius :param rho0: density normalization :param Rs: Hernquist radius :return: density at radius r """ rho = rho0 / (r/Rs * (1 + (r/Rs))**3) return rho
[docs] def density_lens(self, r, sigma0, Rs): """ Density as a function of 3d radius in lensing parameters This function converts the lensing definition sigma0 into the 3d density :param r: 3d radius :param sigma0: rho0 * Rs (units of projected density) :param Rs: Hernquist radius :return: enclosed mass in 3d """ rho0 = self.sigma2rho(sigma0, Rs) return self.density(r, rho0, Rs)
[docs] def density_2d(self, x, y, rho0, Rs, center_x=0, center_y=0): """ projected density along the line of sight at coordinate (x, y) :param x: x-coordinate :param y: y-coordinate :param rho0: density normalization :param Rs: Hernquist radius :param center_x: x-center of the profile :param center_y: y-center of the profile :return: projected density """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) X = r/Rs sigma0 = self.rho2sigma(rho0, Rs) if isinstance(X, int) or isinstance(X, float): if X == 1: X = 1.000001 else: X[X == 1] = 1.000001 sigma = sigma0 / (X**2-1)**2 * (-3 + (2+X**2)*self._F(X)) return sigma
[docs] def mass_3d(self, r, rho0, Rs): """ mass enclosed a 3d sphere or radius r :param r: 3-d radius within the mass is integrated (same distance units as density definition) :param rho0: density normalization :param Rs: Hernquist radius :return: enclosed mass """ mass_3d = 2*np.pi*Rs**3*rho0 * r**2/(r + Rs)**2 return mass_3d
[docs] def mass_3d_lens(self, r, sigma0, Rs): """ mass enclosed a 3d sphere or radius r for lens parameterisation This function converts the lensing definition sigma0 into the 3d density :param sigma0: rho0 * Rs (units of projected density) :param Rs: Hernquist radius :return: enclosed mass in 3d """ rho0 = self.sigma2rho(sigma0, Rs) return self.mass_3d(r, rho0, Rs)
[docs] def mass_2d(self, r, rho0, Rs): """ mass enclosed projected 2d sphere of radius r :param r: projected radius :param rho0: density normalization :param Rs: Hernquist radius :return: mass enclosed 2d projected radius """ sigma0 = self.rho2sigma(rho0, Rs) return self.mass_2d_lens(r, sigma0, Rs)
[docs] def mass_2d_lens(self, r, sigma0, Rs): """ mass enclosed projected 2d sphere of radius r Same as mass_2d but with input normalization in units of projected density :param r: projected radius :param sigma0: rho0 * Rs (units of projected density) :param Rs: Hernquist radius :return: mass enclosed 2d projected radius """ X = r/Rs alpha_r = 2*sigma0 * Rs * X * (1-self._F(X)) / (X**2-1) mass_2d = alpha_r * r * np.pi return mass_2d
[docs] def mass_tot(self, rho0, Rs): """ total mass within the profile :param rho0: density normalization :param Rs: Hernquist radius :return: total mass within profile """ m_tot = 2*np.pi*rho0*Rs**3 return m_tot
[docs] def function(self, x, y, sigma0, Rs, center_x=0, center_y=0): """ lensing potential :param x: x-coordinate position (units of angle) :param y: y-coordinate position (units of angle) :param sigma0: normalization parameter defined such that the deflection at projected RS leads to alpha = 2./3 * Rs * sigma0 :param Rs: Hernquist radius in units of angle :param center_x: x-center of the profile (units of angle) :param center_y: y-center of the profile (units of angle) :return: lensing potential at (x,y) """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) r = np.maximum(r, self._s) X = r / Rs f_ = sigma0 * Rs ** 2 * (np.log(X ** 2 / 4.) + 2 * self._F(X)) return f_
[docs] def derivatives(self, x, y, sigma0, Rs, center_x=0, center_y=0): """ :param x: x-coordinate position (units of angle) :param y: y-coordinate position (units of angle) :param sigma0: normalization parameter defined such that the deflection at projected RS leads to alpha = 2./3 * Rs * sigma0 :param Rs: Hernquist radius in units of angle :param center_x: x-center of the profile (units of angle) :param center_y: y-center of the profile (units of angle) :return: derivative of function (deflection angles in x- and y-direction) """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) r = np.maximum(r, self._s) X = r/Rs if isinstance(r, int) or isinstance(r, float): #f = (1 - self._F(X)) / (X ** 2 - 1) # this expression is 1/3 for X=1 if X == 1: f = 1./3 else: f = (1 - self._F(X)) / (X ** 2 - 1) else: f = np.empty_like(X) f[X == 1] = 1./3 X_ = X[X != 1] f[X != 1] = (1 - self._F(X_)) / (X_ ** 2 - 1) alpha_r = 2 * sigma0 * Rs * f * X f_x = alpha_r * x_/r f_y = alpha_r * y_/r return f_x, f_y
[docs] def hessian(self, x, y, sigma0, Rs, center_x=0, center_y=0): """ Hessian terms of the function :param x: x-coordinate position (units of angle) :param y: y-coordinate position (units of angle) :param sigma0: normalization parameter defined such that the deflection at projected RS leads to alpha = 2./3 * Rs * sigma0 :param Rs: Hernquist radius in units of angle :param center_x: x-center of the profile (units of angle) :param center_y: y-center of the profile (units of angle) :return: df/dxdx, df/dxdy, df/dydx, df/dydy """ alpha_ra, alpha_dec = self.derivatives(x, y, sigma0, Rs, center_x, center_y) diff = self._diff alpha_ra_dx, alpha_dec_dx = self.derivatives(x + diff, y, sigma0, Rs, center_x, center_y) alpha_ra_dy, alpha_dec_dy = self.derivatives(x, y + diff, sigma0, Rs, center_x, center_y) f_xx = (alpha_ra_dx - alpha_ra) / diff f_xy = (alpha_ra_dy - alpha_ra) / diff f_yx = (alpha_dec_dx - alpha_dec) / diff f_yy = (alpha_dec_dy - alpha_dec) / diff return f_xx, f_xy, f_yx, f_yy
[docs] def rho2sigma(self, rho0, Rs): """ converts 3d density into 2d projected density parameter :param rho0: 3d density normalization of Hernquist model :param Rs: Hernquist radius :return: sigma0 defined quantity in projected units """ return rho0 * Rs
[docs] def sigma2rho(self, sigma0, Rs): """ converts projected density parameter (in units of deflection) into 3d density parameter :param sigma0: density defined quantity in projected units :param Rs: Hernquist radius :return: rho0 the 3d density normalization of Hernquist model """ return sigma0 / Rs
def _F(self, X): """ function 48 in https://arxiv.org/pdf/astro-ph/0102341.pdf :param X: r/rs :return: F(X) """ c = self._s if isinstance(X, int) or isinstance(X, float): X = max(X, c) if X < 1 and X > 0: a = 1. / np.sqrt(1 - X ** 2) * np.arctanh(np.sqrt(1 - X**2)) elif X == 1: a = 1. elif X > 1: a = 1. / np.sqrt(X ** 2 - 1) * np.arctan(np.sqrt(X**2 - 1)) else: # X == 0: a = 1. / np.sqrt(1 - c ** 2) * np.arctanh(np.sqrt((1 - c ** 2))) else: a = np.empty_like(X) X[X < c] = c x = X[X < 1] a[X < 1] = 1 / np.sqrt(1 - x ** 2) * np.arctanh(np.sqrt((1 - x**2))) x = X[X == 1] a[X == 1] = 1. x = X[X > 1] a[X > 1] = 1 / np.sqrt(x ** 2 - 1) * np.arctan(np.sqrt(x**2 - 1)) # a[X>y] = 0 return a
[docs] def grav_pot(self, x, y, rho0, Rs, center_x=0, center_y=0): """ #TODO decide whether these functions are needed or not gravitational potential (modulo 4 pi G and rho0 in appropriate units) :param x: x-coordinate position (units of angle) :param y: y-coordinate position (units of angle) :param rho0: density normalization parameter of Hernquist profile :param Rs: Hernquist radius in units of angle :param center_x: x-center of the profile (units of angle) :param center_y: y-center of the profile (units of angle) :return: gravitational potential at projected radius """ x_ = x - center_x y_ = y - center_y r = np.sqrt(x_**2 + y_**2) M = self.mass_tot(rho0, Rs) pot = M / (r + Rs) return pot