jeans 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jeans-1.0.0/LICENSE +21 -0
- jeans-1.0.0/PKG-INFO +45 -0
- jeans-1.0.0/README.md +27 -0
- jeans-1.0.0/pyproject.toml +20 -0
- jeans-1.0.0/setup.cfg +4 -0
- jeans-1.0.0/src/jeans/__init__.py +2 -0
- jeans-1.0.0/src/jeans/main.py +639 -0
- jeans-1.0.0/src/jeans.egg-info/PKG-INFO +45 -0
- jeans-1.0.0/src/jeans.egg-info/SOURCES.txt +10 -0
- jeans-1.0.0/src/jeans.egg-info/dependency_links.txt +1 -0
- jeans-1.0.0/src/jeans.egg-info/requires.txt +4 -0
- jeans-1.0.0/src/jeans.egg-info/top_level.txt +1 -0
jeans-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 mgwalkergit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
jeans-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: jeans
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: package to compute integrals related to spherical Jeans equation, including various parametric functions to describe halo and tracer components
|
|
5
|
+
Author-email: "Matthew G. Walker" <mgwalker@cmu.edu>
|
|
6
|
+
Project-URL: Homepage, https://github.com/mgwalkergit/jeans
|
|
7
|
+
Project-URL: Issues, https://github.com/mgwalkergit/jeans/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: scipy
|
|
16
|
+
Requires-Dist: astropy
|
|
17
|
+
Requires-Dist: matplotlib
|
|
18
|
+
|
|
19
|
+
# jeans
|
|
20
|
+
|
|
21
|
+
A package for ...
|
|
22
|
+
|
|
23
|
+
Author: Matthew G. Walker (2024)
|
|
24
|
+
|
|
25
|
+
# Instructions
|
|
26
|
+
|
|
27
|
+
* Install jeans. You can either pip install the released version or install from github
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
pip install jeans
|
|
31
|
+
```
|
|
32
|
+
# Available Models for 2D position
|
|
33
|
+
|
|
34
|
+
xxx
|
|
35
|
+
|
|
36
|
+
In order to ...:
|
|
37
|
+
|
|
38
|
+
```dmhalo=jeans.dmhalo('nfw',triangle=200,m_triangle=1.e+10,c_triangle=10)```
|
|
39
|
+
|
|
40
|
+
# Examples
|
|
41
|
+
|
|
42
|
+
For examples of ...
|
|
43
|
+
|
|
44
|
+
# Acknowledgement
|
|
45
|
+
|
jeans-1.0.0/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# jeans
|
|
2
|
+
|
|
3
|
+
A package for ...
|
|
4
|
+
|
|
5
|
+
Author: Matthew G. Walker (2024)
|
|
6
|
+
|
|
7
|
+
# Instructions
|
|
8
|
+
|
|
9
|
+
* Install jeans. You can either pip install the released version or install from github
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
pip install jeans
|
|
13
|
+
```
|
|
14
|
+
# Available Models for 2D position
|
|
15
|
+
|
|
16
|
+
xxx
|
|
17
|
+
|
|
18
|
+
In order to ...:
|
|
19
|
+
|
|
20
|
+
```dmhalo=jeans.dmhalo('nfw',triangle=200,m_triangle=1.e+10,c_triangle=10)```
|
|
21
|
+
|
|
22
|
+
# Examples
|
|
23
|
+
|
|
24
|
+
For examples of ...
|
|
25
|
+
|
|
26
|
+
# Acknowledgement
|
|
27
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "jeans"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
authors = [
|
|
5
|
+
{ name="Matthew G. Walker", email="mgwalker@cmu.edu" },
|
|
6
|
+
]
|
|
7
|
+
description = "package to compute integrals related to spherical Jeans equation, including various parametric functions to describe halo and tracer components"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.8"
|
|
10
|
+
dependencies = ["numpy","scipy","astropy","matplotlib"
|
|
11
|
+
]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.urls]
|
|
19
|
+
Homepage = "https://github.com/mgwalkergit/jeans"
|
|
20
|
+
Issues = "https://github.com/mgwalkergit/jeans/issues"
|
jeans-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
from xymass import sampler
|
|
2
|
+
import numpy as np
|
|
3
|
+
import scipy
|
|
4
|
+
import scipy.optimize
|
|
5
|
+
import scipy.special
|
|
6
|
+
import warnings
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
import astropy as ap
|
|
9
|
+
import time
|
|
10
|
+
|
|
11
|
+
g=0.004317#newton's G in units of km/s, pc, Msun
|
|
12
|
+
|
|
13
|
+
def get_nfw_gc(c_triangle):
|
|
14
|
+
return 1./(np.log(1.+c_triangle)-c_triangle/(1.+c_triangle))
|
|
15
|
+
|
|
16
|
+
def get_dehnen_core_gc(c_triangle):
|
|
17
|
+
return ((1.+c_triangle)**3)/c_triangle**3
|
|
18
|
+
|
|
19
|
+
def get_dehnen_cusp_gc(c_triangle):
|
|
20
|
+
return ((1.+c_triangle)**2)/c_triangle**2
|
|
21
|
+
|
|
22
|
+
def get_nfw_scale(triangle,h,m_triangle,c_triangle):#r_triangle, scale radius r_s and scale density rho_s, of NFW halo, units of pc and U(m_triangle) / u(r_scale)**3
|
|
23
|
+
gc=get_nfw_gc(c_triangle)
|
|
24
|
+
r_triangle=(2.*g*m_triangle/triangle/((1.e-4*h)**2))**0.3333333333333333#r_triangle in units of pc, where triangle is overdensity factor = [M_triangle / (4*pi*r_triangle**3)] / rho_crit_0, where rho_crit_0 = 3H_0^2/(8*pi*G), H_0 is hubble constant, m_triangle is given in units of Msun
|
|
25
|
+
r_scale=r_triangle/c_triangle#scale radius in same units as r_triangle, where concentration is defined as c_triangle=r_triangle/r_scale
|
|
26
|
+
return r_triangle,r_scale,gc*m_triangle/4./np.pi/r_scale**3
|
|
27
|
+
|
|
28
|
+
def get_dehnen_core_scale(triangle,h,m_triangle,c_triangle):#r_triangle, scale radius r_s and scale density rho_s, of NFW halo, units of pc and U(m_triangle) / u(r_scale)**3
|
|
29
|
+
gc=get_dehnen_core_gc(c_triangle)
|
|
30
|
+
r_triangle=(2.*g*m_triangle/triangle/((1.e-4*h)**2))**0.3333333333333333#r_triangle in units of pc, where triangle is overdensity factor = [M_triangle / (4*pi*r_triangle**3)] / rho_crit_0, where rho_crit_0 = 3H_0^2/(8*pi*G), H_0 is hubble constant, m_triangle is given in units of Msun
|
|
31
|
+
r_scale=r_triangle/c_triangle#scale radius in same units as r_triangle, where concentration is defined as c_triangle=r_triangle/r_scale
|
|
32
|
+
return r_triangle,r_scale,gc*m_triangle/(4./3.)/np.pi/r_scale**3
|
|
33
|
+
|
|
34
|
+
def get_dehnen_cusp_scale(triangle,h,m_triangle,c_triangle):#r_triangle, scale radius r_s and scale density rho_s, of NFW halo, units of pc and U(m_triangle) / u(r_scale)**3
|
|
35
|
+
gc=get_dehnen_cusp_gc(c_triangle)
|
|
36
|
+
r_triangle=(2.*g*m_triangle/triangle/((1.e-4*h)**2))**0.3333333333333333#r_triangle in units of pc, where triangle is overdensity factor = [M_triangle / (4*pi*r_triangle**3)] / rho_crit_0, where rho_crit_0 = 3H_0^2/(8*pi*G), H_0 is hubble constant, m_triangle is given in units of Msun
|
|
37
|
+
r_scale=r_triangle/c_triangle#scale radius in same units as r_triangle, where concentration is defined as c_triangle=r_triangle/r_scale
|
|
38
|
+
return r_triangle,r_scale,gc*m_triangle/(4./2.)/np.pi/r_scale**3
|
|
39
|
+
|
|
40
|
+
def get_abg_triangle_scale(triangle,h,m_triangle,c_triangle,alpha,beta,gamma):#r_triangle, scale radius r_s and scale density, rho_s, of abg halo, given triangle parameters, units of U(m_triangle)/U(r_triangle)**3
|
|
41
|
+
r_triangle=(2.*g*m_triangle/triangle/((1.e-4*h)**2))**0.3333333333333333#r_triangle in units of pc, where triangle is overdensity factor = [M_triangle / (4*pi*r_triangle**3)] / rho_crit_0, where rho_crit_0 = 3H_0^2/(8*pi*G), H_0 is hubble constant, m_triangle is given in units of Msun
|
|
42
|
+
r_scale=r_triangle/c_triangle#scale radius in same units as r_triangle, where concentration is defined as c_triangle=r_triangle/r_scale
|
|
43
|
+
|
|
44
|
+
a=(3.-gamma)/alpha
|
|
45
|
+
b=(beta-gamma)/alpha
|
|
46
|
+
c=(3.-gamma+alpha)/alpha
|
|
47
|
+
z1=-c_triangle**alpha
|
|
48
|
+
hf1=scipy.special.hyp2f1(a,b,c,z1)
|
|
49
|
+
return r_triangle,r_scale,m_triangle*(3.-gamma)/4./np.pi/(r_scale**3)/c_triangle**(3.-gamma)/hf1
|
|
50
|
+
|
|
51
|
+
def nfw_density(x,c_triangle):# returns rho_NFW(x) / rho_scale, where x = r / r_triangle
|
|
52
|
+
cx=c_triangle*x #r / r_scale
|
|
53
|
+
return 1./cx/(1.+cx)**2
|
|
54
|
+
|
|
55
|
+
def dehnen_core_density(x,c_triangle):# returns rho_NFW(x) / rho_scale, where x = r / r_triangle
|
|
56
|
+
cx=c_triangle*x #r / r_scale
|
|
57
|
+
return 1./(1.+cx)**4
|
|
58
|
+
|
|
59
|
+
def dehnen_cusp_density(x,c_triangle):# returns rho_NFW(x) / rho_scale, where x = r / r_triangle
|
|
60
|
+
cx=c_triangle*x #r / r_scale
|
|
61
|
+
return 1./cx/(1.+cx)**3
|
|
62
|
+
|
|
63
|
+
def nfw_mass(x,c_triangle):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
64
|
+
gc=get_nfw_gc(c_triangle)
|
|
65
|
+
cx=c_triangle*x #r / r_scale
|
|
66
|
+
return gc*(np.log(1.+cx)-cx/(1.+cx))
|
|
67
|
+
|
|
68
|
+
def dehnen_core_mass(x,c_triangle):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
69
|
+
gc=get_dehnen_core_gc(c_triangle)
|
|
70
|
+
cx=c_triangle*x #r / r_scale
|
|
71
|
+
return gc*(cx**3)/(1.+cx)**3
|
|
72
|
+
|
|
73
|
+
def dehnen_cusp_mass(x,c_triangle):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
74
|
+
gc=get_dehnen_cusp_gc(c_triangle)
|
|
75
|
+
cx=c_triangle*x #r / r_scale
|
|
76
|
+
return gc*(cx**2)/(1.+cx)**2
|
|
77
|
+
|
|
78
|
+
def fncore(x,r_core,n_core):#returns f^n(x) for coreNFW model (Read, Walker, Pascal 2018), where x=r/r_triangle, r_core=r_core/r_triangle
|
|
79
|
+
return (np.tanh(np.float64(x)/r_core))**n_core
|
|
80
|
+
|
|
81
|
+
def cnfw_density(x,c_triangle,r_core,n_core):#returns rho_coreNFW(x) / rho_s, where x = r/r_triangle and rho_s is scale radius of NFW profile
|
|
82
|
+
ncorem1=n_core-1.
|
|
83
|
+
two=2.
|
|
84
|
+
return fncore(x,r_core,n_core)*nfw_density(x,c_triangle)+n_core*fncore(x,r_core,ncorem1)*(1.-fncore(x,r_core,two))/(x**2)/get_nfw_gc(c_triangle)*nfw_mass(x,c_triangle)/r_core/(c_triangle**3)
|
|
85
|
+
|
|
86
|
+
def cnfw_mass(x,c_triangle,r_core,n_core):# returns M_cNFW(x) / m_triangle, where x=r/r_triangle, x=r/r_triangle, r_core=(core radius)/ r_triangle
|
|
87
|
+
return fncore(x,r_core,n_core)*nfw_mass(x,c_triangle)
|
|
88
|
+
|
|
89
|
+
def cnfwt_density(x,c_triangle,r_core,n_core,r_tide,delta):#returns rho_coreNFWtides(x) / rho_0, where x = r/r_triangle
|
|
90
|
+
if ((type(x) is float)|(type(x) is np.float64)):
|
|
91
|
+
if x<r_tide:
|
|
92
|
+
return cnfw_density(x,c_triangle,r_core,n_core)
|
|
93
|
+
else:
|
|
94
|
+
return cnfw_density(r_tide,c_triangle,r_core,n_core)*((x/r_tide)**(-delta_halo))
|
|
95
|
+
elif ((type(x) is list)|(type(x) is np.ndarray)):
|
|
96
|
+
val=np.zeros(len(x))
|
|
97
|
+
val[x<r_tide]=cnfw_density(x[x<r_tide],c_triangle,r_core,n_core)
|
|
98
|
+
val[x>=r_tide]=cnfw_density(r_tide,c_triangle,r_core,n_core)*((x[x>=r_tide]/r_tide)**(-delta_halo))
|
|
99
|
+
return val
|
|
100
|
+
|
|
101
|
+
def cnfwt_mass(x,c_triangle,r_core,n_core,r_tide,delta):#returns M_cNFWt(x) / m_triangle, where x=r/r_triangle, r_core=(core radius)/r_triangle, r_tide=(tidal radius)/r_triangle
|
|
102
|
+
if ((type(x) is float)|(type(x) is np.float64)):
|
|
103
|
+
if x<r_tide:
|
|
104
|
+
return cnfw_mass(x,c_triangle,r_core,n_core)
|
|
105
|
+
else:
|
|
106
|
+
return cnfw_mass(r_tide,c_triangle,r_core,n_core,r_tide)+cnfw_density(r_tide,c_triangle,r_core,n_core)*get_nfw_gc(c_triangle)/(3.-delta)*((c_triangle*r_tide)**3)*(((x/r_tide)**(3.-delta))-1.)
|
|
107
|
+
elif ((type(x) is list)|(type(x) is np.ndarray)):
|
|
108
|
+
val=np.zeros(len(x))
|
|
109
|
+
val[x<r_tide]=cnfw_mass(x[x<r_tide],c_triangle,r_core,n_core)
|
|
110
|
+
val[x>=r_tide]=cnfw_mass(r_tide,c_triangle,r_core,n_core)+cnfw_density(r_tide,c_triangle,r_core,n_core)*get_nfw_gc(c_triangle)/(3.-delta)*((c_triangle*r_tide)**3)*(((x[x>=r_tide]/r_tide)**(3.-delta))-1.)
|
|
111
|
+
return val
|
|
112
|
+
|
|
113
|
+
def abg_triangle_density(x,c_triangle,alpha,beta,gamma):# returns rho_abg(x) / rho_scale, where x = r / r_triangle
|
|
114
|
+
cx=params['c_triangle']*x #r / r_scale
|
|
115
|
+
return 1./(cx**gamma)/(1.+cx**alpha)**((beta-gamma)/alpha)
|
|
116
|
+
|
|
117
|
+
def abg_triangle_mass(x,c_triangle,alpha,beta,gamma):# returns enclosed mass M_abg(x) / m_triangle, where x = r/r_triangle
|
|
118
|
+
cx=c_triangle*x #r / r_scale
|
|
119
|
+
a=(3.-gamma)/alpha
|
|
120
|
+
b=(beta-gamma)/alpha
|
|
121
|
+
c=(3.-gamma+alpha)/alpha
|
|
122
|
+
z1=-cx**alpha
|
|
123
|
+
z2=-c_triangle**alpha
|
|
124
|
+
hf1=scipy.special.hyp2f1(a,b,c,z1)
|
|
125
|
+
hf2=scipy.special.hyp2f1(a,b,c,z2)
|
|
126
|
+
return ((cx/c_triangle)**(3.-gamma))*hf1/hf2
|
|
127
|
+
|
|
128
|
+
def get_plum_scale(luminosity_tot,r_scale):#nu0, normalization factor for luminosity density profile
|
|
129
|
+
nu0=3.*luminosity_tot/4./np.pi/r_scale**3
|
|
130
|
+
sigma0=luminosity_tot/np.pi/r_scale**2
|
|
131
|
+
return nu0,sigma0
|
|
132
|
+
|
|
133
|
+
def get_exp_scale(luminosity_tot,r_scale):#nu0, normalization factor for luminosity density profile
|
|
134
|
+
nu0=luminosity_tot/2./np.pi**2/r_scale**3
|
|
135
|
+
sigma0=luminosity_tot/2./np.pi/r_scale**2
|
|
136
|
+
return nu0,sigma0
|
|
137
|
+
|
|
138
|
+
def get_a2bg_scale(luminosity_tot,r_scale,beta,gamma):#nu0, normalization factor for luminosity density profile
|
|
139
|
+
alpha=2.
|
|
140
|
+
a=(3.-gamma)/alpha
|
|
141
|
+
b=(beta-gamma)/alpha
|
|
142
|
+
c=beta/2.
|
|
143
|
+
d=(beta-3.)/alpha
|
|
144
|
+
nu0=luminosity_tot/2./np.pi/r_scale**3/scipy.special.gamma(d)/scipy.special.gamma(a)*scipy.special.gamma(b)
|
|
145
|
+
sigma0=luminosity_tot/4./np.sqrt(np.pi)/(r_scale**2)*(beta-3.)*scipy.special.gamma(b)/scipy.special.gamma(a)/scipy.special.gamma(c)
|
|
146
|
+
return nu0,sigma0
|
|
147
|
+
|
|
148
|
+
def get_abg_nu0(luminosity_tot,r_scale,alpha,beta,gamma):#nu0, normalization factor for luminosity density profile
|
|
149
|
+
a=(3.-gamma)/alpha
|
|
150
|
+
b=(beta-gamma)/alpha
|
|
151
|
+
c=beta/2.
|
|
152
|
+
d=(beta-3.)/alpha
|
|
153
|
+
nu0=luminosity_tot/4./np.pi/r_scale**3*alpha*scipy.special.gamma(b)/scipy.special.gamma(d)/scipy.special.gamma(a)
|
|
154
|
+
sigma0=np.nan#haven't yet implemented, probably a numerical integration
|
|
155
|
+
return nu0,sigma0
|
|
156
|
+
|
|
157
|
+
def plum_density(x):#nu(x) / nu0, x=r/r_scale
|
|
158
|
+
return 1./(1.+x**2)**(2.5)
|
|
159
|
+
|
|
160
|
+
def plum_density_2d(x):#Sigma(X) / Sigma0, X=R/r_scale
|
|
161
|
+
return 1./(1.+x**2)**2
|
|
162
|
+
|
|
163
|
+
def exp_density(x):#nu(x) / nu0, x=r/r_scale
|
|
164
|
+
return scipy.special.kn(0,x)
|
|
165
|
+
|
|
166
|
+
def exp_density_2d(x):#Sigma(X) / Sigma0, X=R/r_scale
|
|
167
|
+
return np.exp(-x)
|
|
168
|
+
|
|
169
|
+
def a2bg_density(x,beta,gamma):#nu(x) / nu0, x=r/r_scale
|
|
170
|
+
return 1./(x**gamma)/(1.+x**2)**((beta-gamma)/2.)
|
|
171
|
+
|
|
172
|
+
def a2bg_density_2d(x,beta,gamma):#Sigma(X)/Sigma0, X=R/r_scale
|
|
173
|
+
if x<1.e-50:
|
|
174
|
+
x=1.e-50
|
|
175
|
+
a=(beta-1.)/2.
|
|
176
|
+
b=(beta-gamma)/2.
|
|
177
|
+
c=beta/2.
|
|
178
|
+
z1=-1./x**2
|
|
179
|
+
hf1=scipy.special.hyp2f1(a,b,c,z1)
|
|
180
|
+
return x**(1.-beta)*hf1
|
|
181
|
+
|
|
182
|
+
def abg_density(x,alpha,beta,gamma):#nu(x) / nu0, x=r/r_scale
|
|
183
|
+
return 1./(x**gamma)/(1.+x**alpha)**((beta-gamma)/alpha)
|
|
184
|
+
|
|
185
|
+
def abg_density_2d(x,alpha,beta,gamma):#Sigma(X)/Sigma0, X=R/r_scale
|
|
186
|
+
return np.nan #requires numerical integration, haven't implemented this yet
|
|
187
|
+
|
|
188
|
+
def plum_number(x):#N(x) / N_tot, x=r/r_scale
|
|
189
|
+
return (x**3)/(1.+x**2)**(1.5)
|
|
190
|
+
|
|
191
|
+
def exp_number(x):#N(x) / N_tot, x=r/r_scale
|
|
192
|
+
if x>100:#fudge to overcome numerical error (function below returns nan)
|
|
193
|
+
return 1.
|
|
194
|
+
return 1./(3.*np.pi)*x*(3.*np.pi*scipy.special.kn(2,x)*scipy.special.modstruve(1,x)+scipy.special.kn(1,x)*(3.*np.pi*scipy.special.modstruve(2,x)-4.*x))
|
|
195
|
+
|
|
196
|
+
def a2bg_number(x,beta,gamma):#N(x)/N_tot, x=r/r_scale
|
|
197
|
+
alpha=2.
|
|
198
|
+
a=(3.-gamma)/alpha
|
|
199
|
+
b=(beta-gamma)/alpha
|
|
200
|
+
c=(3.-gamma+alpha)/alpha
|
|
201
|
+
d=(beta-3.)/alpha
|
|
202
|
+
z1=-x**alpha
|
|
203
|
+
z2=-np.inf**alpha
|
|
204
|
+
hf1=scipy.special.hyp2f1(a,b,c,z1)
|
|
205
|
+
hf2=scipy.special.hyp2f1(a,b,c,z2)
|
|
206
|
+
#return abg_number(x,2.,beta,gamma)
|
|
207
|
+
return alpha/(3.-gamma)*(x**(3.-gamma))*hf1*scipy.special.gamma(b)/scipy.special.gamma(d)/scipy.special.gamma(a)
|
|
208
|
+
|
|
209
|
+
def abg_number(x,alpha,beta,gamma):#N(x)/N_tot, x=r/r_scale
|
|
210
|
+
a=(3.-gamma)/alpha
|
|
211
|
+
b=(beta-gamma)/alpha
|
|
212
|
+
c=(3.-gamma+alpha)/alpha
|
|
213
|
+
d=(beta-3.)/alpha
|
|
214
|
+
z1=-x**alpha
|
|
215
|
+
z2=-np.inf**alpha
|
|
216
|
+
hf1=scipy.special.hyp2f1(a,b,c,z1)
|
|
217
|
+
hf2=scipy.special.hyp2f1(a,b,c,z2)
|
|
218
|
+
#return (x**(3.-gamma))*hf1/hf2 #should be equivalent to below
|
|
219
|
+
return alpha/(3.-gamma)*(x**(3.-gamma))*hf1*scipy.special.gamma(b)/scipy.special.gamma(d)/scipy.special.gamma(a)
|
|
220
|
+
|
|
221
|
+
def plum_nscalenorm():#N(r_scale)/(nu0 *r_scale**3)
|
|
222
|
+
return 4.*np.pi/3./(2.**1.5)
|
|
223
|
+
|
|
224
|
+
def exp_nscalenorm():#N(r_scale)/(nu0 *r_scale**3)
|
|
225
|
+
return 2.*np.pi/3.*(3.*np.pi*scipy.special.kn(2,1.)*scipy.special.modstruve(1,1.)+scipy.special.kn(1,1.)*(3.*np.pi*scipy.special.modstruve(2,1.)-4.))
|
|
226
|
+
|
|
227
|
+
def a2bg_nscalenorm(beta,gamma):#N(r_scale)/(nu0 * r_scale**3)
|
|
228
|
+
alpha=2.
|
|
229
|
+
a=(3.-gamma)/alpha
|
|
230
|
+
b=(beta-gamma)/alpha
|
|
231
|
+
c=(3.-gamma+alpha)/alpha
|
|
232
|
+
z2=-1.
|
|
233
|
+
hf2=scipy.special.hyp2f1(a,b,c,z2)
|
|
234
|
+
return 4.*np.pi/(3.-gamma)*hf2
|
|
235
|
+
|
|
236
|
+
def abg_nscalenorm(alpha,beta,gamma):#N(r_scale)/(nu0 * r_scale**3)
|
|
237
|
+
a=(3.-gamma)/alpha
|
|
238
|
+
b=(beta-gamma)/alpha
|
|
239
|
+
c=(3.-gamma+alpha)/alpha
|
|
240
|
+
z2=-1.
|
|
241
|
+
hf2=scipy.special.hyp2f1(a,b,c,z2)
|
|
242
|
+
return 4.*np.pi/(3.-gamma)*hf2
|
|
243
|
+
|
|
244
|
+
def plum_ntotnorm():#N(r=infinity)/(nu0 * r_scale**3)
|
|
245
|
+
return 4.*np.pi/3.
|
|
246
|
+
|
|
247
|
+
def exp_ntotnorm():#N(r=infinity)/(nu0 * r_scale**3)
|
|
248
|
+
return 2.*(np.pi**2)
|
|
249
|
+
|
|
250
|
+
def a2bg_ntotnorm(beta,gamma):#N(r=infinity)/(nu0 * r_scale**3)
|
|
251
|
+
alpha=2.
|
|
252
|
+
a=(3.-gamma)/alpha
|
|
253
|
+
b=(beta-gamma)/alpha
|
|
254
|
+
#c=(3.-gamma+alpha)/alpha
|
|
255
|
+
d=(beta-3.)/alpha
|
|
256
|
+
return 2.*np.pi*scipy.special.gamma(d)*scipy.special.gamma(a)/scipy.special.gamma(b)
|
|
257
|
+
|
|
258
|
+
def abg_ntotnorm(alpha,beta,gamma):#N(r=infinity)/(nu0 * r_scale**3)
|
|
259
|
+
a=(3.-gamma)/alpha
|
|
260
|
+
b=(beta-gamma)/alpha
|
|
261
|
+
#c=(3.-gamma+alpha)/alpha
|
|
262
|
+
d=(beta-3.)/alpha
|
|
263
|
+
return 4.*np.pi/alpha*scipy.special.gamma(d)*scipy.special.gamma(a)/scipy.special.gamma(b)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def get_dmhalo(model,**params):
|
|
268
|
+
|
|
269
|
+
class dmhalo:
|
|
270
|
+
|
|
271
|
+
def __init__(self,model=None,triangle=None,h=None,m_triangle=None,c_triangle=None,r_triangle=None,r_core=None,n_core=None,r_tide=None,delta=None,alpha=None,beta=None,gamma=None,rho_scale=None,r_scale=None,v_max=None,r_max=None,func_density=None,func_mass=None,func_vcirc=None):
|
|
272
|
+
|
|
273
|
+
self.model=model
|
|
274
|
+
self.triangle=triangle
|
|
275
|
+
self.h=h
|
|
276
|
+
self.m_triangle=m_triangle
|
|
277
|
+
self.c_triangle=c_triangle
|
|
278
|
+
self.r_triangle=r_triangle
|
|
279
|
+
self.r_core=r_core
|
|
280
|
+
self.n_core=n_core
|
|
281
|
+
self.r_tide=r_tide
|
|
282
|
+
self.delta=delta
|
|
283
|
+
self.alpha=alpha
|
|
284
|
+
self.beta=beta
|
|
285
|
+
self.gamma=gamma
|
|
286
|
+
self.rho_scale=rho_scale
|
|
287
|
+
self.r_scale=r_scale
|
|
288
|
+
self.v_max=v_max
|
|
289
|
+
self.r_max=r_max
|
|
290
|
+
self.func_density=func_density
|
|
291
|
+
self.func_mass=func_mass
|
|
292
|
+
self.func_vcirc=func_vcirc
|
|
293
|
+
|
|
294
|
+
if model=='nfw':
|
|
295
|
+
|
|
296
|
+
r_triangle,r_scale,rho_scale=get_nfw_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'])
|
|
297
|
+
|
|
298
|
+
def func_density(x):
|
|
299
|
+
return nfw_density(x,params['c_triangle'])
|
|
300
|
+
def func_mass(x):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
301
|
+
return nfw_mass(x,params['c_triangle'])
|
|
302
|
+
|
|
303
|
+
if model=='dehnen_core':
|
|
304
|
+
|
|
305
|
+
r_triangle,r_scale,rho_scale=get_dehnen_core_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'])
|
|
306
|
+
|
|
307
|
+
def func_density(x):
|
|
308
|
+
return dehnen_core_density(x,params['c_triangle'])
|
|
309
|
+
def func_mass(x):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
310
|
+
return dehnen_core_mass(x,params['c_triangle'])
|
|
311
|
+
|
|
312
|
+
if model=='dehnen_cusp':
|
|
313
|
+
|
|
314
|
+
r_triangle,r_scale,rho_scale=get_dehnen_cusp_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'])
|
|
315
|
+
|
|
316
|
+
def func_density(x):
|
|
317
|
+
return dehnen_cusp_density(x,params['c_triangle'])
|
|
318
|
+
def func_mass(x):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
319
|
+
return dehnen_cusp_mass(x,params['c_triangle'])
|
|
320
|
+
|
|
321
|
+
elif model=='abg_triangle':
|
|
322
|
+
|
|
323
|
+
r_triangle,r_scale,rho_scale=get_abg_triangle_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'],params['alpha'],params['beta'],params['gamma'])
|
|
324
|
+
|
|
325
|
+
def func_density(x):
|
|
326
|
+
return abg_triangle_density(x,params['c_triangle'],params['alpha'],params['beta'],params['gamma'])
|
|
327
|
+
def func_mass(x):
|
|
328
|
+
return abg_triangle_mass(x,params['c_triangle'],params['alpha'],params['beta'],params['gamma'])
|
|
329
|
+
|
|
330
|
+
elif model=='cnfw':
|
|
331
|
+
|
|
332
|
+
r_triangle,r_scale,rho_scale=get_nfw_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'])
|
|
333
|
+
|
|
334
|
+
def func_density(x):
|
|
335
|
+
return cnfw_density(x,params['c_triangle'],params['r_core'],params['n_core'])
|
|
336
|
+
def func_mass(x):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
337
|
+
return cnfw_mass(x,params['c_triangle'],params['r_core'],params['n_core'])
|
|
338
|
+
|
|
339
|
+
elif model=='cnfwt':
|
|
340
|
+
|
|
341
|
+
r_triangle,r_scale,rho_scale=get_nfw_scale(params['triangle'],params['h'],params['m_triangle'],params['c_triangle'])
|
|
342
|
+
|
|
343
|
+
def func_density(x):
|
|
344
|
+
return cnfwt_density(x,params['c_triangle'],params['r_core'],params['n_core'],params['r_tide'],params['delta'])
|
|
345
|
+
def func_mass(x):# returns enclosed mass M(x) / m_triangle, where x = r/r_triangle
|
|
346
|
+
return cnfwt_mass(x,params['c_triangle'],params['r_core'],params['n_core'],params['r_tide'],params['delta'])
|
|
347
|
+
|
|
348
|
+
def func_vcirc(x):# returns circular velocity, km/s
|
|
349
|
+
return np.sqrt(g*func_mass(x)*params['m_triangle']/(x*r_triangle))
|
|
350
|
+
|
|
351
|
+
def neg_vcirc2(x):
|
|
352
|
+
if x<0.:
|
|
353
|
+
return 1.e+30
|
|
354
|
+
return -func_mass(x)/x
|
|
355
|
+
|
|
356
|
+
res=scipy.optimize.minimize(neg_vcirc2,[1.],method='nelder-mead',options={'xatol': 1e-8, 'disp': True})
|
|
357
|
+
r_max=res.x[0]*r_triangle
|
|
358
|
+
v_max=func_vcirc(res.x[0])
|
|
359
|
+
|
|
360
|
+
if model=='nfw':
|
|
361
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
362
|
+
if model=='dehnen_core':
|
|
363
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
364
|
+
if model=='dehnen_cusp':
|
|
365
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
366
|
+
elif model=='abg_triangle':
|
|
367
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,alpha=params['alpha'],beta=params['beta'],gamma=params['gamma'],rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
368
|
+
elif model=='cnfw':
|
|
369
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,r_core=params['r_core'],n_core=params['n_core'],rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
370
|
+
elif model=='cnfwt':
|
|
371
|
+
return dmhalo(model=model,triangle=params['triangle'],h=params['h'],m_triangle=params['m_triangle'],c_triangle=params['c_triangle'],r_triangle=r_triangle,r_core=params['r_core'],n_core=params['n_core'],r_tide=params['r_tide'],delta=params['delta'],rho_scale=rho_scale,r_scale=r_scale,v_max=v_max,r_max=r_max,func_density=func_density,func_mass=func_mass,func_vcirc=func_vcirc)
|
|
372
|
+
else:
|
|
373
|
+
raise TypeError('DM halo not properly specified!')
|
|
374
|
+
|
|
375
|
+
def get_tracer(model,**params):
|
|
376
|
+
|
|
377
|
+
class tracer:
|
|
378
|
+
|
|
379
|
+
def __init__(self,model=None,luminosity_tot=None,upsilon=None,r_scale=None,nu0=None,sigma0=None,nscalenorm=None,ntotnorm=None,alpha=None,beta=None,gamma=None,rhalf_2d=None,rhalf_3d=None,func_density=None,func_density_2d=None,func_number=None):
|
|
380
|
+
|
|
381
|
+
self.model=model
|
|
382
|
+
self.luminosity_tot=luminosity_tot
|
|
383
|
+
self.upsilon=upsilon
|
|
384
|
+
self.r_scale=r_scale
|
|
385
|
+
self.nu0=nu0
|
|
386
|
+
self.sigma0=sigma0
|
|
387
|
+
self.nscalenorm=nscalenorm
|
|
388
|
+
self.ntotnorm=ntotnorm
|
|
389
|
+
self.alpha=alpha
|
|
390
|
+
self.beta=beta
|
|
391
|
+
self.gamma=gamma
|
|
392
|
+
self.rhalf_2d=rhalf_2d
|
|
393
|
+
self.rhalf_3d=rhalf_3d
|
|
394
|
+
self.func_density=func_density
|
|
395
|
+
self.func_density_2d=func_density_2d
|
|
396
|
+
self.func_number=func_number
|
|
397
|
+
|
|
398
|
+
if model=='plum':
|
|
399
|
+
|
|
400
|
+
rhalf_2d,rhalf_3d,xxx,yyy=get_rhalf(model,params['r_scale'],bigsigma0=1.,ellipticity=0.)
|
|
401
|
+
nu0,sigma0=get_plum_scale(params['luminosity_tot'],params['r_scale'])
|
|
402
|
+
def func_density(x):
|
|
403
|
+
return plum_density(x)
|
|
404
|
+
def func_density_2d(x):
|
|
405
|
+
return plum_density_2d(x)
|
|
406
|
+
def func_number(x):
|
|
407
|
+
return plum_number(x)
|
|
408
|
+
|
|
409
|
+
return tracer(model=model,luminosity_tot=params['luminosity_tot'],r_scale=params['r_scale'],upsilon=params['upsilon'],nu0=nu0,sigma0=sigma0,nscalenorm=plum_nscalenorm(),ntotnorm=plum_ntotnorm(),rhalf_2d=rhalf_2d,rhalf_3d=rhalf_3d,func_density=func_density,func_density_2d=func_density_2d,func_number=func_number)
|
|
410
|
+
|
|
411
|
+
if model=='exp':
|
|
412
|
+
|
|
413
|
+
rhalf_2d,rhalf_3d,xxx,yyy=get_rhalf(model,params['r_scale'],bigsigma0=1.,ellipticity=0.)
|
|
414
|
+
nu0,sigma0=get_exp_scale(params['luminosity_tot'],params['r_scale'])
|
|
415
|
+
def func_density(x):
|
|
416
|
+
return exp_density(x)
|
|
417
|
+
def func_density_2d(x):
|
|
418
|
+
return exp_density_2d(x)
|
|
419
|
+
def func_number(x):
|
|
420
|
+
return exp_number(x)
|
|
421
|
+
|
|
422
|
+
return tracer(model=model,luminosity_tot=params['luminosity_tot'],r_scale=params['r_scale'],upsilon=params['upsilon'],nu0=nu0,sigma0=sigma0,nscalenorm=exp_nscalenorm(),ntotnorm=exp_ntotnorm(),rhalf_2d=rhalf_2d,rhalf_3d=rhalf_3d,func_density=func_density,func_density_2d=func_density_2d,func_number=func_number)
|
|
423
|
+
|
|
424
|
+
if model=='a2bg':
|
|
425
|
+
|
|
426
|
+
rhalf_2d,rhalf_3d,xxx,yyy=get_rhalf(model,params['r_scale'],bigsigma0=1.,ellipticity=0.,beta=params['beta'],gamma=params['gamma'])
|
|
427
|
+
nu0,sigma0=get_a2bg_scale(params['luminosity_tot'],params['r_scale'],params['beta'],params['gamma'])
|
|
428
|
+
def func_density(x):
|
|
429
|
+
return a2bg_density(x,params['beta'],params['gamma'])
|
|
430
|
+
def func_density_2d(x):
|
|
431
|
+
return a2bg_density_2d(x,params['beta'],params['gamma'])
|
|
432
|
+
def func_number(x):
|
|
433
|
+
return a2bg_number(x,params['beta'],params['gamma'])
|
|
434
|
+
|
|
435
|
+
return tracer(model=model,luminosity_tot=params['luminosity_tot'],r_scale=params['r_scale'],upsilon=params['upsilon'],nu0=nu0,sigma0=sigma0,nscalenorm=a2bg_nscalenorm(params['beta'],params['gamma']),ntotnorm=a2bg_ntotnorm(params['beta'],params['gamma']),beta=params['beta'],gamma=params['gamma'],rhalf_2d=rhalf_2d,rhalf_3d=rhalf_3d,func_density=func_density,func_density_2d=func_density_2d,func_number=func_number)
|
|
436
|
+
|
|
437
|
+
if model=='abg':
|
|
438
|
+
|
|
439
|
+
rhalf_2d,rhalf_3d,xxx,yyy=get_rhalf(model,params['r_scale'],bigsigma0=1.,ellipticity=0.,alpha=params['alpha'],beta=params['beta'],gamma=params['gamma'])
|
|
440
|
+
nu0,sigma0=get_abg_scale(params['luminosity_tot'],params['r_scale'],params['alpha'],params['beta'],params['gamma'])
|
|
441
|
+
def func_density(x):
|
|
442
|
+
return abg_density(x,params['alpha'],params['beta'],params['gamma'])
|
|
443
|
+
def func_density_2d(x):
|
|
444
|
+
return abg_density_2d(x,params['alpha'],params['beta'],params['gamma'])
|
|
445
|
+
def func_number(x):
|
|
446
|
+
return abg_number(x,params['alpha'],params['beta'],params['gamma'])
|
|
447
|
+
|
|
448
|
+
return tracer(model=model,luminosity_tot=params['luminosity_tot'],r_scale=params['r_scale'],upsilon=params['upsilon'],nu0=nu0,sigma0=sigma0,nscalenorm=abg_nscalenorm(params['alpha'],params['beta'],params['gamma']),ntotnorm=abg_ntotnorm(params['alpha'],params['beta'],params['gamma']),alpha=params['alpha'],beta=params['beta'],gamma=params['gamma'],rhalf_2d=rhalf_2d,rhalf_3d=rhalf_3d,func_density=func_density,func_density_2d=func_density_2d,func_number=func_number)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def get_anisotropy(model,**params):
|
|
452
|
+
|
|
453
|
+
class anisotropy:
|
|
454
|
+
|
|
455
|
+
def __init__(self,model=None,beta_0=None,beta_inf=None,r_beta=None,n_beta=None,f_beta=None,beta=None):
|
|
456
|
+
|
|
457
|
+
self.model=model
|
|
458
|
+
self.beta_0=beta_0
|
|
459
|
+
self.beta_inf=beta_inf
|
|
460
|
+
self.r_beta=r_beta
|
|
461
|
+
self.n_beta=n_beta
|
|
462
|
+
self.f_beta=f_beta
|
|
463
|
+
self.beta=beta
|
|
464
|
+
|
|
465
|
+
if model=='read':
|
|
466
|
+
|
|
467
|
+
def beta(x):#x = r / r_beta
|
|
468
|
+
return params['beta_0']+(params['beta_inf']-params['beta_0'])/(1.+x**(-params['n_beta']))
|
|
469
|
+
def f_beta(x):# x = r / r_beta
|
|
470
|
+
return x**(2.*params['beta_inf'])*(1.+x**(-params['n_beta']))**(2.*(params['beta_inf']-params['beta_0'])/params['n_beta'])
|
|
471
|
+
|
|
472
|
+
return anisotropy(model=model,beta_0=params['beta_0'],beta_inf=params['beta_inf'],r_beta=params['r_beta'],n_beta=params['n_beta'],f_beta=f_beta,beta=beta)
|
|
473
|
+
|
|
474
|
+
else:
|
|
475
|
+
raise TypeError('anisotropy model not properly specified!')
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
def get_rhalf(model,r_scale,**params):
|
|
479
|
+
|
|
480
|
+
if model=='plum':
|
|
481
|
+
rhalf_2d=r_scale
|
|
482
|
+
rhalf_3d=1.30476909*r_scale
|
|
483
|
+
nu0=3*params['bigsigma0']/4/r_scale
|
|
484
|
+
ntot=(1.-params['ellipticity'])*np.pi*r_scale**2*params['bigsigma0']
|
|
485
|
+
elif model=='exp':
|
|
486
|
+
rhalf_2d=1.67835*r_scale
|
|
487
|
+
rhalf_3d=2.22352*r_scale
|
|
488
|
+
nu0=params['bigsigma0']/np.pi/r_scale
|
|
489
|
+
ntot=(1.-params['ellipticity'])*2.*np.pi*r_scale**2*params['bigsigma0']
|
|
490
|
+
elif model=='a2bg':
|
|
491
|
+
def rootfind_2bg_2d(x,beta,gamma):
|
|
492
|
+
return 0.5-np.sqrt(np.pi)*scipy.special.gamma((beta-gamma)/2)/2/scipy.special.gamma(beta/2)/scipy.special.gamma((3-gamma)/2)*x**(3-beta)*scipy.special.hyp2f1((beta-3)/2,(beta-gamma)/2,beta/2,-1/x**2)
|
|
493
|
+
def rootfind_2bg_3d(x,beta,gamma):
|
|
494
|
+
return -0.5+2*scipy.special.gamma((beta-gamma)/2)/scipy.special.gamma((beta-3)/2)/scipy.special.gamma((3-gamma)/2)/(3-gamma)*x**(3-gamma)*scipy.special.hyp2f1((3-gamma)/2,(beta-gamma)/2,(5-gamma)/2,-x**2)
|
|
495
|
+
low0=1.e-20
|
|
496
|
+
high0=1.e+20
|
|
497
|
+
if ((type(r_scale) is float)|(type(r_scale) is np.float64)):
|
|
498
|
+
rhalf_2d=r_scale*scipy.optimize.brentq(rootfind_2bg_2d,low0,high0,args=(params['beta'],params['gamma']),xtol=1.e-12,rtol=1.e-6,maxiter=1000,full_output=False,disp=True)
|
|
499
|
+
rhalf_3d=r_scale*scipy.optimize.brentq(rootfind_2bg_3d,low0,high0,args=(params['beta'],params['gamma']),xtol=1.e-12,rtol=1.e-6,maxiter=100,full_output=False,disp=True)
|
|
500
|
+
else:
|
|
501
|
+
rhalf_2d=[]
|
|
502
|
+
rhalf_3d=[]
|
|
503
|
+
for i in range(0,len(r_scale)):
|
|
504
|
+
rhalf_2d.append(r_scale[i]*scipy.optimize.brentq(rootfind_2bg_2d,low0,high0,args=(params['beta'][i],params['gamma'][i]),xtol=1.e-12,rtol=1.e-6,maxiter=1000,full_output=False,disp=True))
|
|
505
|
+
rhalf_3d.append(r_scale[i]*scipy.optimize.brentq(rootfind_2bg_3d,low0,high0,args=(params['beta'][i],params['gamma'][i]),xtol=1.e-12,rtol=1.e-6,maxiter=100,full_output=False,disp=True))
|
|
506
|
+
rhalf_2d=np.array(rhalf_2d)
|
|
507
|
+
rhalf_3d=np.array(rhalf_3d)
|
|
508
|
+
nu0=params['bigsigma0']*scipy.special.gamma(params['beta']/2)/np.sqrt(np.pi)/r_scale/scipy.special.gamma((params['beta']-1)/2)
|
|
509
|
+
ntot=(1.-params['ellipticity'])*4.*np.sqrt(np.pi)*r_scale**2*params['bigsigma0']/(params['beta']-3)*scipy.special.gamma((3-params['gamma'])/2)*scipy.special.gamma(params['beta']/2)/scipy.special.gamma((params['beta']-params['gamma'])/2)
|
|
510
|
+
|
|
511
|
+
elif model=='abg':
|
|
512
|
+
def rootfind_abg_2d(x,alpha,beta,gamma):
|
|
513
|
+
return np.nan#not computed yet, projection of abg model requires numerical integration
|
|
514
|
+
def rootfind_abg_3d(x,alpha,beta,gamma):
|
|
515
|
+
a=(3.-gamma)/alpha
|
|
516
|
+
b=(beta-gamma)/alpha
|
|
517
|
+
c=(3.-gamma+alpha)/alpha
|
|
518
|
+
d=(beta-3.)/alpha
|
|
519
|
+
z1=-x**alpha
|
|
520
|
+
return -0.5+(x**(3.-gamma))*scipy.special.hyp2f1(a,b,c,z1)*scipy.special.gamma(b)/scipy.special.gamma(d)/scipy.special.gamma(c)
|
|
521
|
+
low0=1.e-20
|
|
522
|
+
high0=1.e+20
|
|
523
|
+
if ((type(r_scale) is float)|(type(r_scale) is np.float64)):
|
|
524
|
+
rhalf_2d=np.nan#not computed yet, projection of abg model requires numerical integration
|
|
525
|
+
rhalf_3d=r_scale*scipy.optimize.brentq(rootfind_abg_3d,low0,high0,args=(params['alpha'],params['beta'],params['gamma']),xtol=1.e-12,rtol=1.e-6,maxiter=100,full_output=False,disp=True)
|
|
526
|
+
else:
|
|
527
|
+
rhalf_2d=[]
|
|
528
|
+
rhalf_3d=[]
|
|
529
|
+
for i in range(0,len(r_scale)):
|
|
530
|
+
rhalf_2d.append(np.nan)#not computed yet, projection of abg model requires numerical integration
|
|
531
|
+
rhalf_3d.append(r_scale[i]*scipy.optimize.brentq(rootfind_abg_3d,low0,high0,args=(params['alpha'],params['beta'][i],params['gamma'][i]),xtol=1.e-12,rtol=1.e-6,maxiter=100,full_output=False,disp=True))
|
|
532
|
+
rhalf_2d=np.array(rhalf_2d)
|
|
533
|
+
rhalf_3d=np.array(rhalf_3d)
|
|
534
|
+
nu0=np.nan#not yet computed
|
|
535
|
+
ntot=np.nan#not yet computed
|
|
536
|
+
|
|
537
|
+
elif model=='captured_truncated':
|
|
538
|
+
return
|
|
539
|
+
else:
|
|
540
|
+
raise ValueError('error in model specification')
|
|
541
|
+
return rhalf_2d,rhalf_3d,nu0,ntot
|
|
542
|
+
|
|
543
|
+
def integrate(bigx,dmhalo,tracer,anisotropy,**params):
|
|
544
|
+
if 'component' not in params:
|
|
545
|
+
params['component']=['los','rad','tan']#default is to calculate all three components
|
|
546
|
+
if not 'upper_limit' in params:#default upper limit is infinity, common alternative is dmhalo.r_triangle
|
|
547
|
+
params['upper_limit']=np.inf
|
|
548
|
+
if not 'epsrel' in params:
|
|
549
|
+
params['epsrel']=1.49e-8
|
|
550
|
+
if not 'epsabs' in params:
|
|
551
|
+
params['epsabs']=1.49e-8
|
|
552
|
+
if not 'limit' in params:
|
|
553
|
+
params['limit']=50
|
|
554
|
+
|
|
555
|
+
def integrand1(x_halo,dmhalo,tracer,anisotropy):
|
|
556
|
+
x_beta=x_halo*dmhalo.r_triangle/tracer.r_scale/anisotropy.r_beta# r / r_beta
|
|
557
|
+
x_tracer=x_halo*dmhalo.r_triangle/tracer.r_scale# r / r_scale
|
|
558
|
+
mass=dmhalo.func_mass(x_halo)+tracer.func_number(x_tracer)*tracer.luminosity_tot*tracer.upsilon/dmhalo.m_triangle
|
|
559
|
+
return mass*tracer.func_density(x_tracer)*anisotropy.f_beta(x_beta)/x_halo**2
|
|
560
|
+
|
|
561
|
+
def integrand_los(x_halo,dmhalo,tracer,anisotropy):
|
|
562
|
+
x_beta=x_halo*dmhalo.r_triangle/tracer.r_scale/anisotropy.r_beta# r / r_beta
|
|
563
|
+
min0=x_halo
|
|
564
|
+
max0=params['upper_limit']
|
|
565
|
+
int1=scipy.integrate.quad(integrand1,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])
|
|
566
|
+
return (1.-anisotropy.beta(x_beta)*(bigx/x_halo)**2)/np.sqrt(1.-(bigx/x_halo)**2)/anisotropy.f_beta(x_beta)*int1[0]
|
|
567
|
+
|
|
568
|
+
def integrand_rad(x_halo,dmhalo,tracer,anisotropy):
|
|
569
|
+
x_beta=x_halo*dmhalo.r_triangle/tracer.r_scale/anisotropy.r_beta# r / r_beta
|
|
570
|
+
min0=x_halo
|
|
571
|
+
max0=params['upper_limit']
|
|
572
|
+
int1=scipy.integrate.quad(integrand1,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])
|
|
573
|
+
return (1.-anisotropy.beta(x_beta)+anisotropy.beta(x_beta)*(bigx/x_halo)**2)/np.sqrt(1.-(bigx/x_halo)**2)/anisotropy.f_beta(x_beta)*int1[0]
|
|
574
|
+
|
|
575
|
+
def integrand_tan(x_halo,dmhalo,tracer,anisotropy):
|
|
576
|
+
x_beta=x_halo*dmhalo.r_triangle/tracer.r_scale/anisotropy.r_beta# r / r_beta
|
|
577
|
+
min0=x_halo
|
|
578
|
+
max0=params['upper_limit']
|
|
579
|
+
int1=scipy.integrate.quad(integrand1,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])
|
|
580
|
+
return (1.-anisotropy.beta(x_beta))/np.sqrt(1.-(bigx/x_halo)**2)/anisotropy.f_beta(x_beta)*int1[0]
|
|
581
|
+
|
|
582
|
+
min0=bigx
|
|
583
|
+
max0=params['upper_limit']
|
|
584
|
+
|
|
585
|
+
if min0==max0:
|
|
586
|
+
bigsigmasigmalos2=0.
|
|
587
|
+
bigsigmasigmarad2=0.
|
|
588
|
+
bigsigmasigmatan2=0.
|
|
589
|
+
|
|
590
|
+
else:
|
|
591
|
+
|
|
592
|
+
if 'los' in params['component']:
|
|
593
|
+
bigsigmasigmalos2=2.*g*dmhalo.m_triangle*scipy.integrate.quad(integrand_los,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])[0]#sigma^2_los(X) * Sigma(X) / nu0
|
|
594
|
+
if 'rad' in params['component']:
|
|
595
|
+
bigsigmasigmarad2=2.*g*dmhalo.m_triangle*scipy.integrate.quad(integrand_rad,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])[0]#sigma^2_rad(X) * Sigma(X) / nu0
|
|
596
|
+
if 'tan' in params['component']:
|
|
597
|
+
bigsigmasigmatan2=2.*g*dmhalo.m_triangle*scipy.integrate.quad(integrand_tan,min0,max0,args=(dmhalo,tracer,anisotropy),epsrel=params['epsrel'],epsabs=params['epsabs'])[0]#sigma^2_tan(X) * Sigma(X) / nu0
|
|
598
|
+
|
|
599
|
+
return bigsigmasigmalos2,bigsigmasigmarad2,bigsigmasigmatan2
|
|
600
|
+
|
|
601
|
+
def integrate_isotropic(bigx,dmhalo,tracer,**params):
|
|
602
|
+
if not 'upper_limit' in params:#default upper limit is infinity, common alternative is dmhalo.r_triangle
|
|
603
|
+
params['upper_limit']=np.inf
|
|
604
|
+
if not 'epsrel' in params:
|
|
605
|
+
params['epsrel']=1.49e-8
|
|
606
|
+
if not 'epsabs' in params:
|
|
607
|
+
params['epsabs']=1.49e-8
|
|
608
|
+
if not 'limit' in params:
|
|
609
|
+
params['limit']=50
|
|
610
|
+
|
|
611
|
+
def integrand1(x_halo,dmhalo,tracer):
|
|
612
|
+
x_tracer=x_halo*dmhalo.r_triangle/tracer.r_scale# r / r_scale
|
|
613
|
+
mass=dmhalo.func_mass(x_halo)+tracer.func_number(x_tracer)*tracer.luminosity_tot*tracer.upsilon/dmhalo.m_triangle
|
|
614
|
+
return np.sqrt(1.-(bigx/x_halo)**2)*mass*tracer.func_density(x_tracer)/x_halo
|
|
615
|
+
|
|
616
|
+
min0=bigx
|
|
617
|
+
max0=params['upper_limit']
|
|
618
|
+
return 2.*g*dmhalo.m_triangle*scipy.integrate.quad(integrand1,min0,max0,args=(dmhalo,tracer),epsrel=params['epsrel'],epsabs=params['epsabs'])[0]#sigma^2_LOS(X) * Sigma(X) / nu0
|
|
619
|
+
|
|
620
|
+
def projected_virial(x_halo,dmhalo,tracer):#computes integral for Wlos from Errani etal (2018)
|
|
621
|
+
x_tracer=x_halo*dmhalo.r_triangle/tracer.r_scale
|
|
622
|
+
totalmass=dmhalo.func_mass(x_halo)+tracer.func_number(x_tracer)*tracer.luminosity_tot*tracer.upsilon/dmhalo.m_triangle
|
|
623
|
+
return x_halo*tracer.func_density(x_tracer)*totalmass
|
|
624
|
+
|
|
625
|
+
def get_virial(dmhalo,tracer,**params):
|
|
626
|
+
if not 'epsrel' in params:
|
|
627
|
+
params['epsrel']=1.e-13
|
|
628
|
+
if not 'epsabs' in params:
|
|
629
|
+
params['epsabs']=0.
|
|
630
|
+
if not 'limit' in params:
|
|
631
|
+
params['limit']=500
|
|
632
|
+
|
|
633
|
+
min0=0.
|
|
634
|
+
max0=np.inf
|
|
635
|
+
val1=scipy.integrate.quad(projected_virial,min0,max0,args=(dmhalo,tracer),epsabs=params['epsabs'],epsrel=params['epsrel'],limit=params['limit'])
|
|
636
|
+
vvar=val1[0]*4.*np.pi*g/3.*dmhalo.m_triangle*(dmhalo.r_triangle**2)/tracer.ntotnorm/tracer.r_scale**3
|
|
637
|
+
mu=g*(dmhalo.func_mass(tracer.rhalf_2d/dmhalo.r_triangle)+tracer.func_number(tracer.rhalf_2d/tracer.r_scale)*tracer.luminosity_tot*tracer.upsilon)*dmhalo.m_triangle/tracer.rhalf_2d/vvar
|
|
638
|
+
return vvar,mu
|
|
639
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: jeans
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: package to compute integrals related to spherical Jeans equation, including various parametric functions to describe halo and tracer components
|
|
5
|
+
Author-email: "Matthew G. Walker" <mgwalker@cmu.edu>
|
|
6
|
+
Project-URL: Homepage, https://github.com/mgwalkergit/jeans
|
|
7
|
+
Project-URL: Issues, https://github.com/mgwalkergit/jeans/issues
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: numpy
|
|
15
|
+
Requires-Dist: scipy
|
|
16
|
+
Requires-Dist: astropy
|
|
17
|
+
Requires-Dist: matplotlib
|
|
18
|
+
|
|
19
|
+
# jeans
|
|
20
|
+
|
|
21
|
+
A package for ...
|
|
22
|
+
|
|
23
|
+
Author: Matthew G. Walker (2024)
|
|
24
|
+
|
|
25
|
+
# Instructions
|
|
26
|
+
|
|
27
|
+
* Install jeans. You can either pip install the released version or install from github
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
pip install jeans
|
|
31
|
+
```
|
|
32
|
+
# Available Models for 2D position
|
|
33
|
+
|
|
34
|
+
xxx
|
|
35
|
+
|
|
36
|
+
In order to ...:
|
|
37
|
+
|
|
38
|
+
```dmhalo=jeans.dmhalo('nfw',triangle=200,m_triangle=1.e+10,c_triangle=10)```
|
|
39
|
+
|
|
40
|
+
# Examples
|
|
41
|
+
|
|
42
|
+
For examples of ...
|
|
43
|
+
|
|
44
|
+
# Acknowledgement
|
|
45
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
jeans
|