Skip to content

Commit fce8e58

Browse files
authored
Merge pull request #266 from Jammy2211/feature/cored_NFW
Feature/cored nfw the cored spherical NFW deflection angles. Best used with the profile cNFWMCRLudlowSph
2 parents e2e3015 + dec498c commit fce8e58

9 files changed

Lines changed: 458 additions & 1 deletion

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
cNFWSph:
2+
centre_0:
3+
type: Gaussian
4+
mean: 0.0
5+
sigma: 0.1
6+
width_modifier:
7+
type: Absolute
8+
value: 0.05
9+
limits:
10+
lower: -inf
11+
upper: inf
12+
centre_1:
13+
type: Gaussian
14+
mean: 0.0
15+
sigma: 0.1
16+
width_modifier:
17+
type: Absolute
18+
value: 0.05
19+
limits:
20+
lower: -inf
21+
upper: inf
22+
kappa_s:
23+
type: Uniform
24+
lower_limit: 0.0
25+
upper_limit: 1.0
26+
width_modifier:
27+
type: Relative
28+
value: 0.2
29+
limits:
30+
lower: 0.0
31+
upper: inf
32+
scale_radius:
33+
type: Uniform
34+
lower_limit: 0.0
35+
upper_limit: 30.0
36+
width_modifier:
37+
type: Relative
38+
value: 0.2
39+
limits:
40+
lower: 0.0
41+
upper: inf
42+
core_radius:
43+
type: Uniform
44+
lower_limit: 0.0
45+
upper_limit: 15.0
46+
width_modifier:
47+
type: Relative
48+
value: 0.2
49+
limits:
50+
lower: 0.0
51+
upper: inf
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
cNFWMCRLudlowSph:
2+
centre_0:
3+
type: Gaussian
4+
mean: 0.0
5+
sigma: 0.1
6+
width_modifier:
7+
type: Absolute
8+
value: 0.05
9+
limits:
10+
lower: -inf
11+
upper: inf
12+
centre_1:
13+
type: Gaussian
14+
mean: 0.0
15+
sigma: 0.1
16+
width_modifier:
17+
type: Absolute
18+
value: 0.05
19+
limits:
20+
lower: -inf
21+
upper: inf
22+
mass_at_200:
23+
type: LogUniform
24+
lower_limit: 100000000.0
25+
upper_limit: 1000000000000000.0
26+
width_modifier:
27+
type: Relative
28+
value: 0.5
29+
limits:
30+
lower: 0.0
31+
upper: inf
32+
f_c:
33+
type: Uniform
34+
lower_limit: 0.0001
35+
upper_limit: 0.5
36+
width_modifier:
37+
type: Relative
38+
value: 0.2
39+
limits:
40+
lower: 0.0001
41+
upper: inf
42+
redshift_object:
43+
type: Uniform
44+
lower_limit: 0.0
45+
upper_limit: 1.0
46+
width_modifier:
47+
type: Relative
48+
value: 0.5
49+
limits:
50+
lower: 0.0
51+
upper: inf
52+
redshift_source:
53+
type: Uniform
54+
lower_limit: 0.0
55+
upper_limit: 1.0
56+
width_modifier:
57+
type: Relative
58+
value: 0.5
59+
limits:
60+
lower: 0.0
61+
upper: inf

autogalaxy/profiles/mass/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
NFWMCRLudlow,
3737
gNFWMCRLudlow,
3838
NFWVirialMassConcSph,
39+
cNFWSph,
40+
cNFWMCRLudlowSph,
3941
)
4042
from .stellar import (
4143
Gaussian,

autogalaxy/profiles/mass/dark/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@
99
from .nfw_truncated_mcr import NFWTruncatedMCRLudlowSph, NFWTruncatedMCRDuffySph
1010
from .nfw_truncated_mcr_scatter import NFWTruncatedMCRScatterLudlowSph
1111
from .nfw_virial_mass_conc import NFWVirialMassConcSph
12+
from .cnfw import cNFWSph
13+
from .cnfw_mcr import cNFWMCRLudlowSph
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import numpy as np
2+
3+
from typing import Tuple
4+
5+
from autogalaxy.profiles.mass.dark.abstract import AbstractgNFW
6+
7+
import autoarray as aa
8+
9+
class cNFWSph(AbstractgNFW):
10+
def __init__(
11+
self,
12+
centre: Tuple[float, float] = (0.0, 0.0),
13+
kappa_s: float = 0.05,
14+
scale_radius: float = 1.0,
15+
core_radius: float = 0.01,
16+
):
17+
"""
18+
Represents a spherical cored NFW density distribution
19+
20+
Parameters
21+
----------
22+
centre
23+
The (y,x) arc-second coordinates of the profile centre.
24+
kappa_s
25+
The overall normalization of the dark matter halo \|
26+
(kappa_s = (rho_0 * D_d * scale_radius)/lensing_critical_density)
27+
scale_radius
28+
The cored NFW scale radius `theta_s`, as an angle on the sky in arcseconds.
29+
core_radius
30+
The cored NFW core radius `theta_c`, as an angle on the sky in arcseconds.
31+
"""
32+
33+
super().__init__(
34+
centre=centre,
35+
ell_comps=(0.0, 0.0))
36+
37+
self.kappa_s = kappa_s
38+
self.scale_radius = scale_radius
39+
self.core_radius = core_radius
40+
41+
42+
@aa.grid_dec.to_vector_yx
43+
@aa.grid_dec.transform
44+
def deflections_yx_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs):
45+
"""
46+
Calculate the deflection angles on a grid of (y,x) arc-second coordinates.
47+
48+
The input grid of (y,x) coordinates are transformed to a coordinate system centred on the profile centre with
49+
and rotated based on the position angle defined from its `ell_comps` (this is described fully below).
50+
51+
The numerical backend can be selected via the ``xp`` argument, allowing this
52+
method to be used with both NumPy and JAX (e.g. inside ``jax.jit``-compiled
53+
code). This is described fully later in this example.
54+
55+
Parameters
56+
----------
57+
grid
58+
The grid of (y,x) arc-second coordinates the deflection angles are computed on.
59+
xp
60+
The numerical backend to use, either `numpy` or `jax.numpy`.
61+
"""
62+
theta = self.radial_grid_from(grid=grid, xp=xp, **kwargs).array
63+
theta = xp.maximum(theta, 1e-8)
64+
65+
factor = (
66+
4.0
67+
* self.kappa_s
68+
* self.scale_radius**2
69+
)
70+
71+
deflection_r = (
72+
factor
73+
* (self.F_func(theta, self.scale_radius, xp=xp) - self.F_func(theta, self.core_radius, xp=xp)
74+
- (self.scale_radius - self.core_radius) * self.dev_F_func(theta, self.scale_radius, xp=xp)
75+
)
76+
/ (theta * (self.scale_radius - self.core_radius)**2)
77+
)
78+
79+
80+
return self._cartesian_grid_via_radial_from(
81+
grid=grid,
82+
radius=deflection_r,
83+
xp=xp,
84+
**kwargs,
85+
)
86+
87+
def F_func(self, theta, radius, xp=np):
88+
89+
F = theta * 0.0
90+
91+
# theta < radius
92+
mask1 = (theta > 0) & (theta < radius)
93+
94+
# theta > radius
95+
mask2 = theta > radius
96+
97+
F = xp.where(
98+
mask1,
99+
(
100+
radius / 2 * xp.log(2 * radius / theta)
101+
- xp.sqrt(radius ** 2 - theta ** 2)
102+
* xp.arctanh(xp.sqrt((radius - theta) / (radius + theta)))
103+
),
104+
F,
105+
)
106+
107+
F = xp.where(
108+
mask2,
109+
(
110+
radius / 2 * xp.log(2 * radius / theta)
111+
+ xp.sqrt(theta ** 2 - radius ** 2)
112+
* xp.arctan(xp.sqrt((theta - radius) / (theta + radius)))
113+
),
114+
F,
115+
)
116+
117+
return 2 * radius * F
118+
119+
def dev_F_func(self, theta, radius, xp=np):
120+
121+
dev_F = theta * 0.0
122+
123+
mask1 = (theta > 0) & (theta < radius)
124+
mask2 = theta == radius
125+
mask3 = theta > radius
126+
127+
dev_F = xp.where(
128+
mask1,
129+
(
130+
radius * xp.log(2 * radius / theta)
131+
- (2 * radius ** 2 - theta ** 2) / xp.sqrt(radius ** 2 - theta ** 2)
132+
* xp.arctanh(xp.sqrt((radius - theta) / (radius + theta)))
133+
),
134+
dev_F,
135+
)
136+
137+
dev_F = xp.where(
138+
mask2,
139+
radius * (xp.log(2) - 1 / 2),
140+
dev_F,
141+
)
142+
143+
dev_F = xp.where(
144+
mask3,
145+
(
146+
radius * xp.log(2 * radius / theta)
147+
+ (theta ** 2 - 2 * radius ** 2) / xp.sqrt(theta ** 2 - radius ** 2)
148+
* xp.arctan(xp.sqrt((theta - radius) / (theta + radius)))
149+
),
150+
dev_F,
151+
)
152+
153+
return 2 * dev_F
154+
155+
@aa.grid_dec.to_array
156+
def convergence_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs):
157+
"""
158+
Convergence (dimensionless surface mass density) for the cored NFW profile.
159+
This is not yet implemented for `cNFWSph`.
160+
"""
161+
raise NotImplementedError(
162+
"convergence_2d_from is not implemented for cNFWSph; a physical cNFW "
163+
"convergence expression must be added before use."
164+
)
165+
166+
@aa.grid_dec.to_array
167+
def potential_2d_from(self, grid: aa.type.Grid2DLike, xp=np, **kwargs):
168+
"""
169+
Lensing potential for the cored NFW profile.
170+
This is not yet implemented for `cNFWSph`.
171+
"""
172+
raise NotImplementedError(
173+
"potential_2d_from is not implemented for cNFWSph; a physical cNFW "
174+
"potential expression must be added before use."
175+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from typing import Tuple
2+
3+
from autogalaxy.profiles.mass.dark.cnfw import cNFWSph
4+
5+
from autogalaxy.profiles.mass.dark import mcr_util
6+
7+
class cNFWMCRLudlowSph(cNFWSph):
8+
def __init__(
9+
self,
10+
centre: Tuple[float, float] = (0.0, 0.0),
11+
mass_at_200: float = 1e9,
12+
f_c = 0.01,
13+
redshift_object: float = 0.5,
14+
redshift_source: float = 1.0,
15+
):
16+
self.mass_at_200 = mass_at_200
17+
self.f_c = f_c
18+
self.redshift_object = redshift_object
19+
self.redshift_source = redshift_source
20+
21+
(
22+
kappa_s,
23+
scale_radius,
24+
core_radius,
25+
radius_at_200,
26+
) = mcr_util.kappa_s_scale_radius_and_core_radius_for_ludlow(
27+
mass_at_200=mass_at_200,
28+
scatter_sigma=0.0,
29+
f_c=f_c,
30+
redshift_object=redshift_object,
31+
redshift_source=redshift_source,
32+
)
33+
34+
super().__init__(centre=centre, kappa_s=kappa_s, scale_radius=scale_radius, core_radius=core_radius)

0 commit comments

Comments
 (0)