PyCosmo 2.3.1__cp313-cp313-macosx_14_0_arm64.whl
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.
- PyCosmo/Background.py +464 -0
- PyCosmo/BoltzmannSolver/Fields.py +123 -0
- PyCosmo/BoltzmannSolver/LinearPerturbationBoltzmann.py +580 -0
- PyCosmo/BoltzmannSolver/LsodaSolver.py +130 -0
- PyCosmo/BoltzmannSolver/ScipySolver.py +354 -0
- PyCosmo/BoltzmannSolver/__init__.py +15 -0
- PyCosmo/Cosmo.py +837 -0
- PyCosmo/CosmologyCore.py +645 -0
- PyCosmo/CosmologyCore_massivenu.py +954 -0
- PyCosmo/CosmologyCore_massivenu_rsa.py +341 -0
- PyCosmo/CosmologyCore_massivenu_wcdm.py +1010 -0
- PyCosmo/CosmologyCore_massivenu_wcdm_rsa.py +367 -0
- PyCosmo/CosmologyCore_rsa.py +233 -0
- PyCosmo/CosmologyCore_wcdm.py +712 -0
- PyCosmo/CosmologyCore_wcdm_rsa.py +261 -0
- PyCosmo/LinearPerturbationApprox.py +793 -0
- PyCosmo/LinearPerturbationBase.py +132 -0
- PyCosmo/NonLinearPerturbationHaloFit.py +513 -0
- PyCosmo/NonLinearPerturbationMead.py +857 -0
- PyCosmo/NonLinearPerturbation_HI.py +424 -0
- PyCosmo/NonLinearPerturbation_HaloModel.py +1266 -0
- PyCosmo/Obs.py +934 -0
- PyCosmo/PerturbationBase.py +80 -0
- PyCosmo/PerturbationTable.py +222 -0
- PyCosmo/Projection.py +427 -0
- PyCosmo/TheoryPredTables.py +236 -0
- PyCosmo/_Cosmics.py +162 -0
- PyCosmo/_Recombination.py +171 -0
- PyCosmo/_RecombinationClass.py +80 -0
- PyCosmo/_RecombinationCosmics.py +79 -0
- PyCosmo/_Util.py +54 -0
- PyCosmo/__init__.py +39 -0
- PyCosmo/_scipy_utils.py +42 -0
- PyCosmo/build.py +73 -0
- PyCosmo/config/__init__.py +17 -0
- PyCosmo/config/default_lcdm.ini +96 -0
- PyCosmo/config/default_lcdm_rsa.ini +100 -0
- PyCosmo/config/default_mnulcdm.ini +99 -0
- PyCosmo/config/default_mnulcdm_rsa.ini +101 -0
- PyCosmo/config/default_mnuwcdm.ini +100 -0
- PyCosmo/config/default_mnuwcdm_rsa.ini +102 -0
- PyCosmo/config/default_wcdm.ini +99 -0
- PyCosmo/config/default_wcdm_rsa.ini +101 -0
- PyCosmo/config/load_parameters_ini.py +367 -0
- PyCosmo/core_file_handling.py +124 -0
- PyCosmo/cython/__init__.py +26 -0
- PyCosmo/cython/const.c +252 -0
- PyCosmo/cython/constf.c +20 -0
- PyCosmo/cython/halo_integral.c +32954 -0
- PyCosmo/cython/halo_integral.cpython-313-darwin.so +0 -0
- PyCosmo/cython/halo_integral.pyx +288 -0
- PyCosmo/cython/halo_integral_1h.c +33369 -0
- PyCosmo/cython/halo_integral_1h.cpython-313-darwin.so +0 -0
- PyCosmo/cython/halo_integral_1h.pyx +298 -0
- PyCosmo/cython/halo_integral_2h.c +33530 -0
- PyCosmo/cython/halo_integral_2h.cpython-313-darwin.so +0 -0
- PyCosmo/cython/halo_integral_2h.pyx +306 -0
- PyCosmo/cython/halo_integral_HI_1h.c +33702 -0
- PyCosmo/cython/halo_integral_HI_1h.cpython-313-darwin.so +0 -0
- PyCosmo/cython/halo_integral_HI_1h.pyx +303 -0
- PyCosmo/cython/halo_integral_HI_2h.c +33881 -0
- PyCosmo/cython/halo_integral_HI_2h.cpython-313-darwin.so +0 -0
- PyCosmo/cython/halo_integral_HI_2h.pyx +314 -0
- PyCosmo/cython/logf.c +128 -0
- PyCosmo/cython/main.c +11 -0
- PyCosmo/cython/mconf.h +175 -0
- PyCosmo/cython/mtherr.c +102 -0
- PyCosmo/cython/polevl.c +97 -0
- PyCosmo/cython/polevlf.c +99 -0
- PyCosmo/cython/protos.h +148 -0
- PyCosmo/cython/rho_HI_integral.c +33004 -0
- PyCosmo/cython/rho_HI_integral.cpython-313-darwin.so +0 -0
- PyCosmo/cython/rho_HI_integral.pyx +257 -0
- PyCosmo/cython/rho_m_integral.c +32804 -0
- PyCosmo/cython/rho_m_integral.cpython-313-darwin.so +0 -0
- PyCosmo/cython/rho_m_integral.pyx +246 -0
- PyCosmo/cython/sici.c +675 -0
- PyCosmo/cython/sici.h +2 -0
- PyCosmo/cython/sici32.c +675 -0
- PyCosmo/cython/sicif.c +275 -0
- PyCosmo/cython/sinf.c +282 -0
- PyCosmo/disable_multithreading.py +13 -0
- PyCosmo/ini_handling.py +133 -0
- PyCosmo/model_config.py +209 -0
- PyCosmo/optimize_nq.py +61 -0
- PyCosmo/patches.py +24 -0
- PyCosmo/predefined_k_grids.py +87 -0
- pycosmo-2.3.1.dist-info/METADATA +54 -0
- pycosmo-2.3.1.dist-info/RECORD +94 -0
- pycosmo-2.3.1.dist-info/WHEEL +5 -0
- pycosmo-2.3.1.dist-info/entry_points.txt +2 -0
- pycosmo-2.3.1.dist-info/licenses/AUTHORS.rst +21 -0
- pycosmo-2.3.1.dist-info/licenses/LICENSE +15 -0
- pycosmo-2.3.1.dist-info/top_level.txt +1 -0
PyCosmo/Background.py
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
# This file is part of PyCosmo, a multipurpose cosmology calculation tool in Python.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2013-2021 ETH Zurich, Institute for Particle and Astrophysics and SIS
|
|
4
|
+
# ID.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify it under the
|
|
7
|
+
# terms of the GNU General Public License as published by the Free Software Foundation,
|
|
8
|
+
# either version 3 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
12
|
+
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License along with this
|
|
15
|
+
# program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
import numpy as np
|
|
18
|
+
from scipy import integrate
|
|
19
|
+
from scipy.interpolate import interp1d
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _call(wrapper, function, a=None):
|
|
23
|
+
if a is None:
|
|
24
|
+
return getattr(wrapper, function)()
|
|
25
|
+
elif isinstance(a, (float, int)):
|
|
26
|
+
return getattr(wrapper, function)(a)
|
|
27
|
+
elif isinstance(a, list):
|
|
28
|
+
a = np.array(a)
|
|
29
|
+
assert isinstance(a, np.ndarray)
|
|
30
|
+
return getattr(wrapper, function)(a.astype(float))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Background(object):
|
|
34
|
+
"""
|
|
35
|
+
The background calculations are based on a
|
|
36
|
+
Friedmann-Robertson-Walker model for which the evolution is governed by
|
|
37
|
+
the Friedmann equation.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
# The first part contains the functions that deal with the elements
|
|
41
|
+
# of the Friedmann equation. In particular the focus in the Hubble
|
|
42
|
+
# function. In the PyCosmo notes, this is section 1.2
|
|
43
|
+
|
|
44
|
+
def __init__(self, cosmo, params, rec, wrapper):
|
|
45
|
+
self._cosmo = cosmo
|
|
46
|
+
self._params = params
|
|
47
|
+
self._rec = rec
|
|
48
|
+
self._wrapper = wrapper
|
|
49
|
+
self._eta_to_a = None
|
|
50
|
+
|
|
51
|
+
def _setup_eta_to_a(self):
|
|
52
|
+
a = np.logspace(-100, 0.0, 1000)
|
|
53
|
+
eta = self.eta(a)
|
|
54
|
+
a = a[eta > 0]
|
|
55
|
+
eta = eta[eta > 0]
|
|
56
|
+
self._eta_to_a = interp1d(
|
|
57
|
+
eta, a, "cubic", bounds_error=False, fill_value="extrapolate"
|
|
58
|
+
)
|
|
59
|
+
self._eta_min = np.min(eta)
|
|
60
|
+
self._eta_max = np.max(eta)
|
|
61
|
+
|
|
62
|
+
def H(self, a):
|
|
63
|
+
"""
|
|
64
|
+
Calculates the Hubble parameter for a given scale factor
|
|
65
|
+
by calling the expression from CosmologyCore_model.py.
|
|
66
|
+
|
|
67
|
+
:param a: scale factor [1]
|
|
68
|
+
:return: Hubble parameter :math:`H(a) [km/s/Mpc]`.
|
|
69
|
+
|
|
70
|
+
Example:
|
|
71
|
+
|
|
72
|
+
.. code-block:: python
|
|
73
|
+
|
|
74
|
+
cosmo.background.H(a)
|
|
75
|
+
"""
|
|
76
|
+
self._cosmo.reset_wrapper_globals()
|
|
77
|
+
return _call(self._wrapper, "H", a)
|
|
78
|
+
|
|
79
|
+
_hubble = H
|
|
80
|
+
|
|
81
|
+
def _H2_H02_a(self, a=1.0):
|
|
82
|
+
result = self._H2_H02_Omegar_a(a=a)
|
|
83
|
+
result += self._H2_H02_Omegam_a(a=a)
|
|
84
|
+
result += self._H2_H02_Omegak_a(a=a)
|
|
85
|
+
result += self._H2_H02_Omegal_a(a=a)
|
|
86
|
+
return result
|
|
87
|
+
|
|
88
|
+
def _H2_H02_Omegar_a(self, a=1.0):
|
|
89
|
+
return self._params.omega_r / a**4
|
|
90
|
+
|
|
91
|
+
def _H2_H02_Omegam_a(self, a=1.0):
|
|
92
|
+
self._cosmo.reset_wrapper_globals()
|
|
93
|
+
return (
|
|
94
|
+
self._params.omega_m / a**3 + _call(self._wrapper, "omega_nu_m", a) / a**4
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def _H2_H02_Omegak_a(self, a=1.0):
|
|
98
|
+
return self._params.omega_k / a**2
|
|
99
|
+
|
|
100
|
+
def _H2_H02_Omegal_a(self, a=1.0):
|
|
101
|
+
self._cosmo.reset_wrapper_globals()
|
|
102
|
+
return _call(self._wrapper, "omega_l_a", a)
|
|
103
|
+
|
|
104
|
+
def _H2_H02_Omega_nu_m_a(self, a=1.0):
|
|
105
|
+
self._cosmo.reset_wrapper_globals()
|
|
106
|
+
return _call(self._wrapper, "omega_nu_m", a) / a**4
|
|
107
|
+
|
|
108
|
+
def _w_a(self, a=1.0):
|
|
109
|
+
self._cosmo.reset_wrapper_globals()
|
|
110
|
+
return self._params.w0 + (1.0 - a) * self._params.wa
|
|
111
|
+
|
|
112
|
+
#########################################################
|
|
113
|
+
# A series of functions for calculating #
|
|
114
|
+
# cosmological distances: #
|
|
115
|
+
#########################################################
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# TODO: have a closer look at this method, can we compile this?
|
|
119
|
+
# math formula should be in notebook
|
|
120
|
+
|
|
121
|
+
def dist_rad_a(self, a=1.0):
|
|
122
|
+
r"""
|
|
123
|
+
Calculates the radial comoving distance, also known as the comoving radius.
|
|
124
|
+
|
|
125
|
+
:param a: scale factor [1]
|
|
126
|
+
:return: Radial comoving distance, :math:`\chi(a)`, in :math:`[Mpc]`.
|
|
127
|
+
|
|
128
|
+
Example:
|
|
129
|
+
|
|
130
|
+
.. code-block:: python
|
|
131
|
+
|
|
132
|
+
cosmo.background.dist_rad_a(a)
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
return self._chi(a) * self._params.c
|
|
137
|
+
|
|
138
|
+
def _chi(self, a):
|
|
139
|
+
r"""
|
|
140
|
+
Calculates the comoving horizon, by calling the CosmologyCore_model.py
|
|
141
|
+
|
|
142
|
+
:param a: scale factor [1]
|
|
143
|
+
:return: Radial comoving horizon, :math:`\chi(a)`, in :math:`[Mpc s/km]`.
|
|
144
|
+
"""
|
|
145
|
+
return _call(self._wrapper, "chi", a)
|
|
146
|
+
|
|
147
|
+
def dist_trans_a(self, a=1.0):
|
|
148
|
+
r"""
|
|
149
|
+
Calculates the transverse comoving distance, also known as comoving
|
|
150
|
+
angular-diameter distance.
|
|
151
|
+
|
|
152
|
+
:param a: scale factor [1]
|
|
153
|
+
:return: Transverse comoving distance, :math:`r(\chi)`, in :math:`[Mpc]`.
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
|
|
157
|
+
.. code-block:: python
|
|
158
|
+
|
|
159
|
+
cosmo.background.dist_trans_a(a)
|
|
160
|
+
"""
|
|
161
|
+
|
|
162
|
+
Dc = self.dist_rad_a(a)
|
|
163
|
+
if self._params.omega_k == 0.0:
|
|
164
|
+
Dm = Dc
|
|
165
|
+
elif self._params.omega_k > 0.0:
|
|
166
|
+
Dm = (
|
|
167
|
+
self._params.rh
|
|
168
|
+
* np.sinh(self._params.sqrtk * Dc / self._params.rh)
|
|
169
|
+
/ self._params.sqrtk
|
|
170
|
+
)
|
|
171
|
+
elif self._params.omega_k < 0.0:
|
|
172
|
+
Dm = (
|
|
173
|
+
self._params.rh
|
|
174
|
+
* np.sin(self._params.sqrtk * Dc / self._params.rh)
|
|
175
|
+
/ self._params.sqrtk
|
|
176
|
+
)
|
|
177
|
+
return Dm
|
|
178
|
+
|
|
179
|
+
def dist_ang_a(self, a=1.0):
|
|
180
|
+
"""
|
|
181
|
+
Calculates the angular-diameter distance to a given scale factor.
|
|
182
|
+
|
|
183
|
+
:param a: scale factor [1]
|
|
184
|
+
:return: Angular diameter distance, :math:`D_A(a)`, in :math:`[Mpc]`.
|
|
185
|
+
|
|
186
|
+
Example:
|
|
187
|
+
|
|
188
|
+
.. code-block:: python
|
|
189
|
+
|
|
190
|
+
cosmo.background.dist_ang_a(a)
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
return self.dist_trans_a(a) * a
|
|
194
|
+
|
|
195
|
+
def dist_lum_a(self, a=1.0):
|
|
196
|
+
"""
|
|
197
|
+
Calculates the luminosity distance to a given scale factor.
|
|
198
|
+
|
|
199
|
+
:param a: scale factor [1]
|
|
200
|
+
:return: Luminosity distance, :math:`D_L(a)`, in :math:`[Mpc]`.
|
|
201
|
+
|
|
202
|
+
Example:
|
|
203
|
+
|
|
204
|
+
.. code-block:: python
|
|
205
|
+
|
|
206
|
+
cosmo.background.dist_lum_a(a)
|
|
207
|
+
"""
|
|
208
|
+
|
|
209
|
+
return self.dist_trans_a(a) / a
|
|
210
|
+
|
|
211
|
+
def eta_to_a(self, eta):
|
|
212
|
+
if self._eta_to_a is None:
|
|
213
|
+
self._setup_eta_to_a()
|
|
214
|
+
eta = np.atleast_1d(eta)
|
|
215
|
+
if np.any(eta < 0.95 * self._eta_min) or np.any(eta > self._eta_max * 1.05):
|
|
216
|
+
raise ValueError(
|
|
217
|
+
f"eta value(s) outside of range {self._eta_min:e} .. {self._eta_max:e}"
|
|
218
|
+
)
|
|
219
|
+
return self._eta_to_a(eta)
|
|
220
|
+
|
|
221
|
+
def eta(self, a):
|
|
222
|
+
a = np.atleast_1d(a)
|
|
223
|
+
af = a[a > 1e-100]
|
|
224
|
+
af = np.concatenate(([1e-100], af))
|
|
225
|
+
y, meta = self._wrapper.solve_fast_eta(
|
|
226
|
+
np.array((0.0,)),
|
|
227
|
+
af,
|
|
228
|
+
1e-8,
|
|
229
|
+
1e-8,
|
|
230
|
+
)
|
|
231
|
+
eta = np.zeros_like(a)
|
|
232
|
+
eta[a > 1e-100] = y.flatten()[1:]
|
|
233
|
+
return eta
|
|
234
|
+
|
|
235
|
+
#########################################################
|
|
236
|
+
# A series of functions to compute thermodynamical #
|
|
237
|
+
# variables including recombination #
|
|
238
|
+
#########################################################
|
|
239
|
+
|
|
240
|
+
def taudot(self, a=1.0):
|
|
241
|
+
r"""
|
|
242
|
+
Calculates :math:`\dot{\tau} = \frac{d\tau}{d\eta}`,
|
|
243
|
+
where :math:`\tau` is the optical depth and :math:`\eta` is the conformal time.
|
|
244
|
+
|
|
245
|
+
:param a: scale factor [1]
|
|
246
|
+
:return: :math:`\dot{\tau} = \frac{d\tau}{d\eta}` in units of
|
|
247
|
+
[:math:`h \mathrm{Mpc}^{-1}`]
|
|
248
|
+
|
|
249
|
+
Example:
|
|
250
|
+
|
|
251
|
+
.. code-block:: python
|
|
252
|
+
|
|
253
|
+
cosmo.background.taudot(a)
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
a = np.atleast_1d(a)
|
|
257
|
+
return self._rec.taudot_a(a) # h/Mpc
|
|
258
|
+
|
|
259
|
+
def cs(self, a):
|
|
260
|
+
"""
|
|
261
|
+
Returns the photon-baryon fluid sound speed [1]
|
|
262
|
+
from the Recombination module
|
|
263
|
+
|
|
264
|
+
:param a: scale factor [1]
|
|
265
|
+
:return: cs: photon-baryon sound speed [1]
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
|
|
269
|
+
.. code-block:: python
|
|
270
|
+
|
|
271
|
+
cosmo.background.cs(a)
|
|
272
|
+
"""
|
|
273
|
+
a = np.atleast_1d(a)
|
|
274
|
+
return self._rec.cs_a(a)
|
|
275
|
+
|
|
276
|
+
# Flagged: More comments needed, might need to be speed up at some point.
|
|
277
|
+
def tau(self, a=1.0):
|
|
278
|
+
"""
|
|
279
|
+
Calculates the optical depth of the photon-baryon fluid,
|
|
280
|
+
by integrating taudot from the Recombination module.
|
|
281
|
+
|
|
282
|
+
:param a: scale factor [1]
|
|
283
|
+
:return: tau: optical depth [1]
|
|
284
|
+
|
|
285
|
+
Example:
|
|
286
|
+
|
|
287
|
+
.. code-block:: python
|
|
288
|
+
|
|
289
|
+
cosmo.background.tau(a)
|
|
290
|
+
"""
|
|
291
|
+
a = np.atleast_1d(a)
|
|
292
|
+
return np.array(
|
|
293
|
+
[
|
|
294
|
+
integrate.fixed_quad(self._tau_intgd, np.log(aa), 0.0, n=100)[0]
|
|
295
|
+
for aa in a
|
|
296
|
+
]
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
def _tau_intgd(self, lna):
|
|
300
|
+
a = np.exp(lna)
|
|
301
|
+
return -self.taudot(a=a) / (a * self.H(a=a) / self._params.H0 / self._params.rh)
|
|
302
|
+
|
|
303
|
+
def tau_b(self, a=1.0):
|
|
304
|
+
"""
|
|
305
|
+
Calculates the optical depth of the baryon fluid,
|
|
306
|
+
by integrating taudot from the Recombination module,
|
|
307
|
+
weighted with R, the baryon-photon fraction.
|
|
308
|
+
|
|
309
|
+
:param a: scale factor [1]
|
|
310
|
+
:return: tau: optical depth [1]
|
|
311
|
+
|
|
312
|
+
Example:
|
|
313
|
+
|
|
314
|
+
.. code-block:: python
|
|
315
|
+
|
|
316
|
+
cosmo.background.tau(a)
|
|
317
|
+
"""
|
|
318
|
+
a = np.atleast_1d(a)
|
|
319
|
+
return np.array(
|
|
320
|
+
[
|
|
321
|
+
integrate.fixed_quad(self._tau_b_intgd, np.log(aa), 0.0, n=100)[0]
|
|
322
|
+
for aa in a
|
|
323
|
+
]
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
def _tau_b_intgd(self, lna):
|
|
327
|
+
a = np.exp(lna)
|
|
328
|
+
result = -self.taudot(a=a) / (
|
|
329
|
+
a**2
|
|
330
|
+
* self.H(a=a)
|
|
331
|
+
/ self._params.H0
|
|
332
|
+
/ self._params.rh
|
|
333
|
+
* 3
|
|
334
|
+
* self._params.omega_b
|
|
335
|
+
/ (4 * self._params.omega_gamma)
|
|
336
|
+
)
|
|
337
|
+
return result
|
|
338
|
+
|
|
339
|
+
def g_a(self, a=1.0):
|
|
340
|
+
"""
|
|
341
|
+
Calculates the visibility function for a given scale factor.
|
|
342
|
+
|
|
343
|
+
:param a: scale factor [1]
|
|
344
|
+
:return: visibility function [1/Mpc]
|
|
345
|
+
|
|
346
|
+
Example:
|
|
347
|
+
|
|
348
|
+
.. code-block:: python
|
|
349
|
+
|
|
350
|
+
cosmo.background.g_a(a)
|
|
351
|
+
"""
|
|
352
|
+
a = np.atleast_1d(a)
|
|
353
|
+
return -self.taudot(a) * np.exp(-self.tau(a)) * self._params.h
|
|
354
|
+
|
|
355
|
+
def r_s(self):
|
|
356
|
+
r"""
|
|
357
|
+
Calculates the sound horizon at drag epoch.
|
|
358
|
+
|
|
359
|
+
:return: sound horizon [:math:`\mathrm{Mpc} / h`]
|
|
360
|
+
"""
|
|
361
|
+
a_log = np.logspace(np.log10(2e-4), np.log10(2e-3), 200)
|
|
362
|
+
a_drag = np.where(self.tau_b(a_log) >= 1.0)[0]
|
|
363
|
+
|
|
364
|
+
if not len(a_drag):
|
|
365
|
+
return np.inf
|
|
366
|
+
a_drag = a_drag[-1]
|
|
367
|
+
|
|
368
|
+
return integrate.fixed_quad(self._r_s_intg, np.log(a_drag), 0.0, n=100)[0]
|
|
369
|
+
|
|
370
|
+
def _r_s_intg(self, lna):
|
|
371
|
+
a = np.exp(lna)
|
|
372
|
+
return -1 / (
|
|
373
|
+
a
|
|
374
|
+
* self.H(a=a)
|
|
375
|
+
/ self._params.H0
|
|
376
|
+
/ self._params.rh
|
|
377
|
+
* np.sqrt(3 * self._params.omega_b / (4 * self._params.omega_gamma) * a)
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
def _r_bph_a(self, a=1.0): # baryon to photon ratio r_bph(a) [1]
|
|
381
|
+
return 3.0 / 4.0 * self._params.omega_b / self._params.omega_gamma * a
|
|
382
|
+
|
|
383
|
+
def _cs_approx(self, a): # photon-baryon fluid sound speed [1]
|
|
384
|
+
# this is a simple expression which is probably a simple approximation - needs
|
|
385
|
+
# refining
|
|
386
|
+
return np.sqrt(1.0 / (3.0 * (1.0 + self._r_bph_a(a))))
|
|
387
|
+
|
|
388
|
+
def _dlnh_dlna(self, a=1.0):
|
|
389
|
+
a = np.atleast_1d(a)
|
|
390
|
+
temp = (
|
|
391
|
+
-0.5
|
|
392
|
+
/ self._H2_H02_a(a)
|
|
393
|
+
* (
|
|
394
|
+
3.0 * self._H2_H02_Omegam_a(a=a)
|
|
395
|
+
+ 3.0 * (1.0 + self._w_a(a)) * self._H2_H02_Omegal_a(a=a)
|
|
396
|
+
+ 2.0 * self._H2_H02_Omegak_a(a=a)
|
|
397
|
+
)
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
return temp
|
|
401
|
+
|
|
402
|
+
#########################################################
|
|
403
|
+
# The next section lists a set of functions for #
|
|
404
|
+
# calculating the density parameters as a function of #
|
|
405
|
+
# a. This is also consistent with the notes in #
|
|
406
|
+
# section 1.2 of the PyCosmo notes. #
|
|
407
|
+
#########################################################
|
|
408
|
+
|
|
409
|
+
def _omega_m_a(self, a=1.0):
|
|
410
|
+
"""
|
|
411
|
+
Calculates the matter density for a given scale factor
|
|
412
|
+
(includes massive neutrinos as matter)
|
|
413
|
+
input: a - scale factor [1]
|
|
414
|
+
output: [1]
|
|
415
|
+
"""
|
|
416
|
+
return self._H2_H02_Omegam_a(a=a) / self._H2_H02_a(a=a)
|
|
417
|
+
|
|
418
|
+
def _omega_r_a(self, a=1.0):
|
|
419
|
+
"""
|
|
420
|
+
Calculates the radiation density for a given scale factor
|
|
421
|
+
includes photons and massless neutrinos
|
|
422
|
+
input: a - scale factor [1]
|
|
423
|
+
output: [1]
|
|
424
|
+
"""
|
|
425
|
+
return self._H2_H02_Omegar_a(a=a) / self._H2_H02_a(a=a)
|
|
426
|
+
|
|
427
|
+
def _omega_l_a(self, a=1.0):
|
|
428
|
+
"""
|
|
429
|
+
Calculates the dark energy density for a given scale factor
|
|
430
|
+
input: a - scale factor [1]
|
|
431
|
+
output: [1]
|
|
432
|
+
"""
|
|
433
|
+
result = self._H2_H02_Omegal_a(a=a)
|
|
434
|
+
result /= self._H2_H02_a(a=a)
|
|
435
|
+
return result
|
|
436
|
+
|
|
437
|
+
def _omega_nu_m_a(self, a=1.0):
|
|
438
|
+
"""
|
|
439
|
+
Calculates the massive neutrinos density for a given scale factor
|
|
440
|
+
input: a - scale factor [1]
|
|
441
|
+
output: [1]
|
|
442
|
+
"""
|
|
443
|
+
return self._H2_H02_Omega_nu_m_a(a=a) / self._H2_H02_a(a=a)
|
|
444
|
+
|
|
445
|
+
def _omega_a(self, a=1.0):
|
|
446
|
+
"""
|
|
447
|
+
Calculates the total density for a given scale factor
|
|
448
|
+
input: a - scale factor [1]
|
|
449
|
+
output: [1]
|
|
450
|
+
"""
|
|
451
|
+
return (
|
|
452
|
+
self._omega_m_a(a=a)
|
|
453
|
+
+ self._omega_r_a(a=a)
|
|
454
|
+
+ self._omega_l_a(a=a)
|
|
455
|
+
+ self._omega_nu_m_a(a=a)
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
def _omega_k_a(self, a=1.0):
|
|
459
|
+
"""
|
|
460
|
+
Calculates the curvature for a given scale factor
|
|
461
|
+
input: a - scale factor [1]
|
|
462
|
+
output: [1]
|
|
463
|
+
"""
|
|
464
|
+
return 1.0 - self._omega_a(a=a)
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# This file is part of PyCosmo, a multipurpose cosmology calculation tool in Python.
|
|
2
|
+
#
|
|
3
|
+
# Copyright (C) 2013-2021 ETH Zurich, Institute for Particle and Astrophysics and SIS
|
|
4
|
+
# ID.
|
|
5
|
+
#
|
|
6
|
+
# This program is free software: you can redistribute it and/or modify it under the
|
|
7
|
+
# terms of the GNU General Public License as published by the Free Software Foundation,
|
|
8
|
+
# either version 3 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
11
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
12
|
+
# PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License along with this
|
|
15
|
+
# program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
from collections import defaultdict
|
|
18
|
+
|
|
19
|
+
import numpy as np
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Fields(object):
|
|
23
|
+
"""
|
|
24
|
+
Class for linear perturbations field objects.
|
|
25
|
+
Usage example: fields.delta(5) returns the dark matter density perturbation at the
|
|
26
|
+
5th time step
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
cosmology,
|
|
32
|
+
):
|
|
33
|
+
self._cosmology = cosmology
|
|
34
|
+
self._wrapper = cosmology._wrapper
|
|
35
|
+
|
|
36
|
+
self._y = None
|
|
37
|
+
self.lna = None
|
|
38
|
+
self._offsets = defaultdict(list)
|
|
39
|
+
|
|
40
|
+
def set_results(self, lna, solver_result):
|
|
41
|
+
self.lna = lna
|
|
42
|
+
|
|
43
|
+
fields_map = self._wrapper.fields(lna, solver_result, self._cosmology)
|
|
44
|
+
|
|
45
|
+
offsets = defaultdict(list)
|
|
46
|
+
self._symbols = []
|
|
47
|
+
_y = []
|
|
48
|
+
for i, (symbol, yvec) in enumerate(fields_map.items()):
|
|
49
|
+
self._symbols.append(symbol)
|
|
50
|
+
_y.append(yvec)
|
|
51
|
+
|
|
52
|
+
if "[" not in symbol:
|
|
53
|
+
offsets[symbol] = i
|
|
54
|
+
continue
|
|
55
|
+
|
|
56
|
+
index = int(symbol.split("[")[1].split("]")[0])
|
|
57
|
+
stem = symbol.split("[")[0]
|
|
58
|
+
offsets[stem].append((index, i))
|
|
59
|
+
|
|
60
|
+
self._y = np.array(_y)
|
|
61
|
+
assert self._y.shape[1] == len(lna), "fields and lna vector mismatch"
|
|
62
|
+
self._offsets = offsets
|
|
63
|
+
|
|
64
|
+
def __dir__(self):
|
|
65
|
+
return super().__dir__() + list(map(str, self._symbols))
|
|
66
|
+
|
|
67
|
+
def __getattr__(self, symbol):
|
|
68
|
+
# needed to support pickling:
|
|
69
|
+
if "_offsets" not in vars(self):
|
|
70
|
+
raise AttributeError()
|
|
71
|
+
|
|
72
|
+
if symbol not in self._offsets:
|
|
73
|
+
return self.__getattribute__(symbol)
|
|
74
|
+
|
|
75
|
+
index = self._offsets[symbol]
|
|
76
|
+
if isinstance(index, int):
|
|
77
|
+
return self._y[index, :]
|
|
78
|
+
|
|
79
|
+
assert isinstance(index, list)
|
|
80
|
+
index = [j for (i, j) in sorted(index)]
|
|
81
|
+
return VectorWrapper(self._y, index)
|
|
82
|
+
|
|
83
|
+
def __getstate__(self):
|
|
84
|
+
return self.__dict__
|
|
85
|
+
|
|
86
|
+
def __setstate__(self, dd):
|
|
87
|
+
self.__dict__.update(dd)
|
|
88
|
+
|
|
89
|
+
@property
|
|
90
|
+
def a(self):
|
|
91
|
+
"""
|
|
92
|
+
a(a_index): scale factor [1]
|
|
93
|
+
"""
|
|
94
|
+
return np.exp(self.lna)
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def d_t(self):
|
|
98
|
+
"""
|
|
99
|
+
d_t: time step in ln(a) units (one fewer value than ln(a) [1]
|
|
100
|
+
"""
|
|
101
|
+
a = self.a
|
|
102
|
+
return a[1:] - a[:-1]
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class VectorWrapper:
|
|
106
|
+
def __init__(self, y, indices):
|
|
107
|
+
self.y = y
|
|
108
|
+
self.indices = indices
|
|
109
|
+
|
|
110
|
+
# supports conversion to np.ndarray using np.array(...):
|
|
111
|
+
# (inspired from https://stackoverflow.com/questions/39376892/)
|
|
112
|
+
data = y[indices, :]
|
|
113
|
+
self.__array_interface__ = dict(
|
|
114
|
+
shape=data.shape,
|
|
115
|
+
typestr=data.dtype.kind,
|
|
116
|
+
data=data.__array_interface__["data"],
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def __len__(self):
|
|
120
|
+
return len(self.indices)
|
|
121
|
+
|
|
122
|
+
def __getitem__(self, index):
|
|
123
|
+
return self.y[self.indices[index], :]
|