1 | # Licensed under a 3-clause BSD style license - see LICENSE.rst |
||
2 | """Dark matter profiles.""" |
||
3 | from __future__ import absolute_import, division, print_function, unicode_literals |
||
4 | import abc |
||
5 | import numpy as np |
||
6 | import astropy.units as u |
||
7 | from ...extern import six |
||
8 | from ...utils.fitting import Parameter, Parameters |
||
9 | from ...spectrum.utils import integrate_spectrum |
||
10 | |||
11 | __all__ = [ |
||
12 | "DMProfile", |
||
13 | "NFWProfile", |
||
14 | "EinastoProfile", |
||
15 | "IsothermalProfile", |
||
16 | "BurkertProfile", |
||
17 | "MooreProfile", |
||
18 | ] |
||
19 | |||
20 | |||
21 | @six.add_metaclass(abc.ABCMeta) |
||
0 ignored issues
–
show
Unused Code
introduced
by
Loading history...
|
|||
22 | class DMProfile(object): |
||
23 | """DMProfile model base class.""" |
||
24 | |||
25 | LOCAL_DENSITY = 0.3 * u.GeV / (u.cm ** 3) |
||
0 ignored issues
–
show
|
|||
26 | """Local dark matter density as given in refenrece 2""" |
||
27 | DISTANCE_GC = 8.33 * u.kpc |
||
0 ignored issues
–
show
|
|||
28 | """Distance to the Galactic Center as given in reference 2""" |
||
29 | |||
30 | def __call__(self, radius): |
||
31 | """Call evaluate method of derived classes.""" |
||
32 | kwargs = dict() |
||
33 | for par in self.parameters.parameters: |
||
0 ignored issues
–
show
|
|||
34 | kwargs[par.name] = par.quantity |
||
35 | |||
36 | return self.evaluate(radius, **kwargs) |
||
0 ignored issues
–
show
|
|||
37 | |||
38 | def scale_to_local_density(self): |
||
39 | """Scale to local density.""" |
||
40 | scale = (self.LOCAL_DENSITY / self(self.DISTANCE_GC)).to_value("") |
||
41 | self.parameters["rho_s"].value *= scale |
||
0 ignored issues
–
show
|
|||
42 | |||
43 | def _eval_squared(self, radius): |
||
44 | """Squared density at given radius.""" |
||
45 | return self(radius) ** 2 |
||
46 | |||
47 | def integral(self, rmin, rmax, **kwargs): |
||
48 | r"""Integrate squared dark matter profile numerically. |
||
49 | |||
50 | .. math:: |
||
51 | |||
52 | F(r_{min}, r_{max}) = \int_{r_{min}}^{r_{max}}\rho(r)^2 dr |
||
53 | |||
54 | |||
55 | Parameters |
||
56 | ---------- |
||
57 | rmin, rmax : `~astropy.units.Quantity` |
||
58 | Lower and upper bound of integration range. |
||
59 | **kwargs : dict |
||
60 | Keyword arguments passed to :func:`~gammapy.spectrum.integrate_spectrum` |
||
61 | """ |
||
62 | integral = integrate_spectrum(self._eval_squared, rmin, rmax, **kwargs) |
||
63 | return integral.to("GeV2 / cm5") |
||
64 | |||
65 | |||
66 | View Code Duplication | class NFWProfile(DMProfile): |
|
0 ignored issues
–
show
|
|||
67 | r"""NFW Profile. |
||
68 | |||
69 | .. math:: |
||
70 | |||
71 | \rho(r) = \rho_s \frac{r_s}{r}\left(1 + \frac{r}{r_s}\right)^{-2} |
||
72 | |||
73 | Parameters |
||
74 | ---------- |
||
75 | r_s : `~astropy.units.Quantity` |
||
76 | Scale radius, :math:`r_s` |
||
77 | rho_s : `~astropy.units.Quantity` |
||
78 | Characteristic density, :math:`\rho_s` |
||
79 | |||
80 | References |
||
81 | ---------- |
||
82 | * `1997ApJ...490..493 <http://adsabs.harvard.edu/abs/1997ApJ...490..493N>`_ |
||
83 | * `2011JCAP...03..051 <http://adsabs.harvard.edu/abs/2011JCAP...03..051>`_ |
||
84 | """ |
||
85 | |||
86 | DEFAULT_SCALE_RADIUS = 24.42 * u.kpc |
||
0 ignored issues
–
show
|
|||
87 | """Default scale radius as given in reference 2""" |
||
88 | |||
89 | def __init__(self, r_s=None, rho_s=1 * u.Unit("GeV / cm3")): |
||
90 | r_s = self.DEFAULT_SCALE_RADIUS if r_s is None else r_s |
||
91 | self.parameters = Parameters( |
||
92 | [Parameter("r_s", u.Quantity(r_s)), Parameter("rho_s", u.Quantity(rho_s))] |
||
93 | ) |
||
94 | |||
95 | @staticmethod |
||
96 | def evaluate(radius, r_s, rho_s): |
||
97 | rr = radius / r_s |
||
98 | return rho_s / (rr * (1 + rr) ** 2) |
||
99 | |||
100 | |||
101 | class EinastoProfile(DMProfile): |
||
0 ignored issues
–
show
|
|||
102 | r"""Einasto Profile. |
||
103 | |||
104 | .. math:: |
||
105 | |||
106 | \rho(r) = \rho_s \exp{ |
||
107 | \left(-\frac{2}{\alpha}\left[ |
||
108 | \left(\frac{r}{r_s}\right)^{\alpha} - 1\right] \right)} |
||
109 | |||
110 | Parameters |
||
111 | ---------- |
||
112 | r_s : `~astropy.units.Quantity` |
||
113 | Scale radius, :math:`r_s` |
||
114 | alpha : `~astropy.units.Quantity` |
||
115 | :math:`\alpha` |
||
116 | rho_s : `~astropy.units.Quantity` |
||
117 | Characteristic density, :math:`\rho_s` |
||
118 | |||
119 | References |
||
120 | ---------- |
||
121 | * `1965TrAlm...5...87E <http://adsabs.harvard.edu/abs/1965TrAlm...5...87E>`_ |
||
122 | * `2011JCAP...03..051 <http://adsabs.harvard.edu/abs/2011JCAP...03..051>`_ |
||
123 | """ |
||
124 | |||
125 | DEFAULT_SCALE_RADIUS = 28.44 * u.kpc |
||
0 ignored issues
–
show
|
|||
126 | """Default scale radius as given in reference 2""" |
||
127 | DEFAULT_ALPHA = 0.17 |
||
128 | """Default scale radius as given in reference 2""" |
||
129 | |||
130 | def __init__(self, r_s=None, alpha=None, rho_s=1 * u.Unit("GeV / cm3")): |
||
131 | alpha = self.DEFAULT_ALPHA if alpha is None else alpha |
||
132 | r_s = self.DEFAULT_SCALE_RADIUS if r_s is None else r_s |
||
133 | |||
134 | self.parameters = Parameters( |
||
135 | [ |
||
136 | Parameter("r_s", u.Quantity(r_s)), |
||
137 | Parameter("alpha", u.Quantity(alpha)), |
||
138 | Parameter("rho_s", u.Quantity(rho_s)), |
||
139 | ] |
||
140 | ) |
||
141 | |||
142 | @staticmethod |
||
143 | def evaluate(radius, r_s, alpha, rho_s): |
||
144 | rr = radius / r_s |
||
145 | exponent = (2 / alpha) * (rr ** alpha - 1) |
||
146 | return rho_s * np.exp(-1 * exponent) |
||
147 | |||
148 | |||
149 | View Code Duplication | class IsothermalProfile(DMProfile): |
|
0 ignored issues
–
show
|
|||
150 | r"""Isothermal Profile. |
||
151 | |||
152 | .. math:: |
||
153 | |||
154 | \rho(r) = \frac{\rho_s}{1 + (r/r_s)^2} |
||
155 | |||
156 | Parameters |
||
157 | ---------- |
||
158 | r_s : `~astropy.units.Quantity` |
||
159 | Scale radius, :math:`r_s` |
||
160 | |||
161 | References |
||
162 | ---------- |
||
163 | * `1991MNRAS.249..523B <http://adsabs.harvard.edu/abs/1991MNRAS.249..523B>`_ |
||
164 | * `2011JCAP...03..051 <http://adsabs.harvard.edu/abs/2011JCAP...03..051>`_ |
||
165 | """ |
||
166 | |||
167 | DEFAULT_SCALE_RADIUS = 4.38 * u.kpc |
||
0 ignored issues
–
show
|
|||
168 | """Default scale radius as given in reference 2""" |
||
169 | |||
170 | def __init__(self, r_s=None, rho_s=1 * u.Unit("GeV / cm3")): |
||
171 | r_s = self.DEFAULT_SCALE_RADIUS if r_s is None else r_s |
||
172 | |||
173 | self.parameters = Parameters( |
||
174 | [Parameter("r_s", u.Quantity(r_s)), Parameter("rho_s", u.Quantity(rho_s))] |
||
175 | ) |
||
176 | |||
177 | @staticmethod |
||
178 | def evaluate(radius, r_s, rho_s): |
||
179 | rr = radius / r_s |
||
180 | return rho_s / (1 + rr ** 2) |
||
181 | |||
182 | |||
183 | View Code Duplication | class BurkertProfile(DMProfile): |
|
0 ignored issues
–
show
|
|||
184 | r"""Burkert Profile. |
||
185 | |||
186 | .. math:: |
||
187 | |||
188 | \rho(r) = \frac{\rho_s}{(1 + r/r_s)(1 + (r/r_s)^2)} |
||
189 | |||
190 | Parameters |
||
191 | ---------- |
||
192 | r_s : `~astropy.units.Quantity` |
||
193 | Scale radius, :math:`r_s` |
||
194 | |||
195 | References |
||
196 | ---------- |
||
197 | * `1995ApJ...447L..25B <http://adsabs.harvard.edu/abs/1995ApJ...447L..25B>`_ |
||
198 | * `2011JCAP...03..051 <http://adsabs.harvard.edu/abs/2011JCAP...03..051>`_ |
||
199 | """ |
||
200 | |||
201 | DEFAULT_SCALE_RADIUS = 12.67 * u.kpc |
||
0 ignored issues
–
show
|
|||
202 | """Default scale radius as given in reference 2""" |
||
203 | |||
204 | def __init__(self, r_s=None, rho_s=1 * u.Unit("GeV / cm3")): |
||
205 | r_s = self.DEFAULT_SCALE_RADIUS if r_s is None else r_s |
||
206 | |||
207 | self.parameters = Parameters( |
||
208 | [Parameter("r_s", u.Quantity(r_s)), Parameter("rho_s", u.Quantity(rho_s))] |
||
209 | ) |
||
210 | |||
211 | @staticmethod |
||
212 | def evaluate(radius, r_s, rho_s): |
||
213 | rr = radius / r_s |
||
214 | return rho_s / ((1 + rr) * (1 + rr ** 2)) |
||
215 | |||
216 | |||
217 | View Code Duplication | class MooreProfile(DMProfile): |
|
0 ignored issues
–
show
|
|||
218 | r"""Moore Profile. |
||
219 | |||
220 | .. math:: |
||
221 | |||
222 | \rho(r) = \rho_s \left(\frac{r_s}{r}\right)^{1.16} |
||
223 | \left(1 + \frac{r}{r_s} \right)^{-1.84} |
||
224 | |||
225 | Parameters |
||
226 | ---------- |
||
227 | r_s : `~astropy.units.Quantity` |
||
228 | Scale radius, :math:`r_s` |
||
229 | |||
230 | References |
||
231 | ---------- |
||
232 | * `2004MNRAS.353..624D <http://adsabs.harvard.edu/abs/2004MNRAS.353..624D>`_ |
||
233 | * `2011JCAP...03..051 <http://adsabs.harvard.edu/abs/2011JCAP...03..051>`_ |
||
234 | """ |
||
235 | |||
236 | DEFAULT_SCALE_RADIUS = 30.28 * u.kpc |
||
0 ignored issues
–
show
|
|||
237 | """Default scale radius as given in reference 2""" |
||
238 | |||
239 | def __init__(self, r_s=None, rho_s=1 * u.Unit("GeV / cm3")): |
||
240 | r_s = self.DEFAULT_SCALE_RADIUS if r_s is None else r_s |
||
241 | |||
242 | self.parameters = Parameters( |
||
243 | [Parameter("r_s", u.Quantity(r_s)), Parameter("rho_s", u.Quantity(rho_s))] |
||
244 | ) |
||
245 | |||
246 | @staticmethod |
||
247 | def evaluate(radius, r_s, rho_s): |
||
248 | rr = radius / r_s |
||
249 | rr_ = r_s / radius |
||
250 | return rho_s * rr_ ** 1.16 * (1 + rr) ** (-1.84) |
||
251 |