PyCosmo 2.3.2__tar.gz → 2.3.3__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.
Files changed (95) hide show
  1. {pycosmo-2.3.2/src/PyCosmo.egg-info → pycosmo-2.3.3}/PKG-INFO +1 -1
  2. {pycosmo-2.3.2 → pycosmo-2.3.3}/pyproject.toml +1 -1
  3. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/Background.py +47 -5
  4. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/Cosmo.py +9 -7
  5. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/LinearPerturbationApprox.py +34 -4
  6. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/Obs.py +11 -9
  7. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral.c +194 -194
  8. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_1h.c +194 -194
  9. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_2h.c +194 -194
  10. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_HI_1h.c +194 -194
  11. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_HI_2h.c +194 -194
  12. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/rho_HI_integral.c +194 -194
  13. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/rho_m_integral.c +194 -194
  14. {pycosmo-2.3.2 → pycosmo-2.3.3/src/PyCosmo.egg-info}/PKG-INFO +1 -1
  15. {pycosmo-2.3.2 → pycosmo-2.3.3}/AUTHORS.rst +0 -0
  16. {pycosmo-2.3.2 → pycosmo-2.3.3}/LICENSE +0 -0
  17. {pycosmo-2.3.2 → pycosmo-2.3.3}/MANIFEST.in +0 -0
  18. {pycosmo-2.3.2 → pycosmo-2.3.3}/README.md +0 -0
  19. {pycosmo-2.3.2 → pycosmo-2.3.3}/setup.cfg +0 -0
  20. {pycosmo-2.3.2 → pycosmo-2.3.3}/setup.py +0 -0
  21. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/BoltzmannSolver/Fields.py +0 -0
  22. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/BoltzmannSolver/LinearPerturbationBoltzmann.py +0 -0
  23. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/BoltzmannSolver/LsodaSolver.py +0 -0
  24. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/BoltzmannSolver/ScipySolver.py +0 -0
  25. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/BoltzmannSolver/__init__.py +0 -0
  26. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore.py +0 -0
  27. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_massivenu.py +0 -0
  28. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_massivenu_rsa.py +0 -0
  29. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_massivenu_wcdm.py +0 -0
  30. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_massivenu_wcdm_rsa.py +0 -0
  31. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_rsa.py +0 -0
  32. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_wcdm.py +0 -0
  33. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/CosmologyCore_wcdm_rsa.py +0 -0
  34. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/LinearPerturbationBase.py +0 -0
  35. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/NonLinearPerturbationHaloFit.py +0 -0
  36. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/NonLinearPerturbationMead.py +0 -0
  37. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/NonLinearPerturbation_HI.py +0 -0
  38. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/NonLinearPerturbation_HaloModel.py +0 -0
  39. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/PerturbationBase.py +0 -0
  40. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/PerturbationTable.py +0 -0
  41. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/Projection.py +0 -0
  42. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/TheoryPredTables.py +0 -0
  43. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_Cosmics.py +0 -0
  44. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_Recombination.py +0 -0
  45. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_RecombinationClass.py +0 -0
  46. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_RecombinationCosmics.py +0 -0
  47. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_Util.py +0 -0
  48. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/__init__.py +0 -0
  49. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/_scipy_utils.py +0 -0
  50. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/build.py +0 -0
  51. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/__init__.py +0 -0
  52. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_lcdm.ini +0 -0
  53. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_lcdm_rsa.ini +0 -0
  54. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_mnulcdm.ini +0 -0
  55. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_mnulcdm_rsa.ini +0 -0
  56. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_mnuwcdm.ini +0 -0
  57. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_mnuwcdm_rsa.ini +0 -0
  58. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_wcdm.ini +0 -0
  59. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/default_wcdm_rsa.ini +0 -0
  60. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/config/load_parameters_ini.py +0 -0
  61. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/core_file_handling.py +0 -0
  62. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/__init__.py +0 -0
  63. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/const.c +0 -0
  64. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/constf.c +0 -0
  65. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral.pyx +0 -0
  66. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_1h.pyx +0 -0
  67. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_2h.pyx +0 -0
  68. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_HI_1h.pyx +0 -0
  69. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/halo_integral_HI_2h.pyx +0 -0
  70. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/logf.c +0 -0
  71. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/main.c +0 -0
  72. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/mconf.h +0 -0
  73. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/mtherr.c +0 -0
  74. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/polevl.c +0 -0
  75. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/polevlf.c +0 -0
  76. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/protos.h +0 -0
  77. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/rho_HI_integral.pyx +0 -0
  78. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/rho_m_integral.pyx +0 -0
  79. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/sici.c +0 -0
  80. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/sici.h +0 -0
  81. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/sici32.c +0 -0
  82. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/sicif.c +0 -0
  83. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/cython/sinf.c +0 -0
  84. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/disable_multithreading.py +0 -0
  85. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/ini_handling.py +0 -0
  86. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/model_config.py +0 -0
  87. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/optimize_nq.py +0 -0
  88. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/patches.py +0 -0
  89. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo/predefined_k_grids.py +0 -0
  90. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/SOURCES.txt +0 -0
  91. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/dependency_links.txt +0 -0
  92. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/entry_points.txt +0 -0
  93. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/not-zip-safe +0 -0
  94. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/requires.txt +0 -0
  95. {pycosmo-2.3.2 → pycosmo-2.3.3}/src/PyCosmo.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyCosmo
3
- Version: 2.3.2
3
+ Version: 2.3.3
4
4
  Summary: A multi-purpose cosmology calculation tool
5
5
  Author-email: Uwe Schmitt et al <uwe.schmitt@id.ethz.ch>
6
6
  License-Expression: GPL-3.0
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
 
6
6
  [project]
7
7
  name = "PyCosmo"
8
- version = "2.3.2"
8
+ version = "2.3.3"
9
9
  license = "GPL-3.0"
10
10
  description = "A multi-purpose cosmology calculation tool"
11
11
  authors = [{name = "Uwe Schmitt et al", email = "uwe.schmitt@id.ethz.ch"}]
@@ -14,6 +14,28 @@
14
14
  # You should have received a copy of the GNU General Public License along with this
15
15
  # program. If not, see <http://www.gnu.org/licenses/>.
16
16
 
17
+ """
18
+ Background cosmology: expansion history, distances and thermodynamics.
19
+
20
+ Unit conventions
21
+ ----------------
22
+ Two conventions coexist in this module, so pay attention to the units stated
23
+ in each docstring:
24
+
25
+ * Geometry / distances are in *physical* Mpc: ``dist_rad_a``, ``dist_trans_a``,
26
+ ``dist_ang_a`` and ``dist_lum_a`` all return physical Mpc.
27
+ * The sound horizon ``r_s`` is returned in Mpc/h, i.e. its numerical value
28
+ equals the physical value multiplied by ``h``.
29
+ * The curvature scale is ``c/H0`` in physical Mpc. Be careful with
30
+ ``params.rh``: it is ``(c/H0) * h``, i.e. the value of ``c/H0`` expressed in
31
+ units of Mpc/h (numerically ~2997.9, independent of ``h``). It must be
32
+ divided by ``h`` before it can be combined with the physical-Mpc distances
33
+ above. Equivalently, the physical curvature scale is ``params.c / params.H0``.
34
+ * Quantities tied to the perturbation/thermodynamics core follow the Mpc/h
35
+ convention: ``taudot`` is in h/Mpc and the conformal time ``eta`` is in
36
+ Mpc/h. ``g_a`` converts ``taudot`` back to 1/Mpc by multiplying by ``h``.
37
+ """
38
+
17
39
  import numpy as np
18
40
  from scipy import integrate
19
41
  from scipy.interpolate import interp1d
@@ -137,7 +159,10 @@ class Background(object):
137
159
 
138
160
  def _chi(self, a):
139
161
  r"""
140
- Calculates the comoving horizon, by calling the CosmologyCore_model.py
162
+ Calculates the raw comoving horizon integral, by calling the
163
+ CosmologyCore_model.py. This is the distance divided by the speed of
164
+ light: multiply the result by ``params.c`` to obtain physical Mpc
165
+ (see :meth:`dist_rad_a`).
141
166
 
142
167
  :param a: scale factor [1]
143
168
  :return: Radial comoving horizon, :math:`\chi(a)`, in :math:`[Mpc s/km]`.
@@ -160,18 +185,23 @@ class Background(object):
160
185
  """
161
186
 
162
187
  Dc = self.dist_rad_a(a)
188
+ # Dc is in physical Mpc, so the curvature scale must be c/H0 in physical
189
+ # Mpc as well. Note that params.rh = c/H0 * h is in Mpc/h, i.e. it is the
190
+ # h-independent value of c/H0; using it here would introduce a spurious
191
+ # 1/h factor in the sinh/sin argument.
192
+ c_over_H0 = self._params.c / self._params.H0
163
193
  if self._params.omega_k == 0.0:
164
194
  Dm = Dc
165
195
  elif self._params.omega_k > 0.0:
166
196
  Dm = (
167
- self._params.rh
168
- * np.sinh(self._params.sqrtk * Dc / self._params.rh)
197
+ c_over_H0
198
+ * np.sinh(self._params.sqrtk * Dc / c_over_H0)
169
199
  / self._params.sqrtk
170
200
  )
171
201
  elif self._params.omega_k < 0.0:
172
202
  Dm = (
173
- self._params.rh
174
- * np.sin(self._params.sqrtk * Dc / self._params.rh)
203
+ c_over_H0
204
+ * np.sin(self._params.sqrtk * Dc / c_over_H0)
175
205
  / self._params.sqrtk
176
206
  )
177
207
  return Dm
@@ -219,6 +249,14 @@ class Background(object):
219
249
  return self._eta_to_a(eta)
220
250
 
221
251
  def eta(self, a):
252
+ r"""
253
+ Calculates the conformal time :math:`\eta(a)`. Note that this follows
254
+ the Mpc/h convention of the perturbation/thermodynamics core (it is the
255
+ physical conformal time multiplied by ``h``).
256
+
257
+ :param a: scale factor [1]
258
+ :return: Conformal time, :math:`\eta(a)`, in :math:`[Mpc/h]`.
259
+ """
222
260
  a = np.atleast_1d(a)
223
261
  af = a[a > 1e-100]
224
262
  af = np.concatenate(([1e-100], af))
@@ -356,6 +394,10 @@ class Background(object):
356
394
  r"""
357
395
  Calculates the sound horizon at drag epoch.
358
396
 
397
+ Note the unit: the returned value is in Mpc/h, i.e. it equals the
398
+ physical sound horizon (in Mpc) multiplied by ``h``. This differs from
399
+ the physical-Mpc distances returned by e.g. :meth:`dist_rad_a`.
400
+
359
401
  :return: sound horizon [:math:`\mathrm{Mpc} / h`]
360
402
  """
361
403
  a_log = np.logspace(np.log10(2e-4), np.log10(2e-3), 200)
@@ -509,9 +509,11 @@ class Cosmo(object):
509
509
  derived_parameters.H0 = (
510
510
  100.0 * params.h * nudge[0]
511
511
  ) # Hubble constant [km/s/Mpc]
512
- derived_parameters.rh = (
513
- params.c / derived_parameters.H0 * params.h
514
- ) # Hubble radius (=c/H0) at z=0 [h^-1 Mpc]
512
+ # Hubble radius rh = c/H0 at z=0, expressed in units of h^-1 Mpc. The
513
+ # factor h makes the numerical value h-independent (~2997.9); the
514
+ # physical scale is c/H0 = rh / h in Mpc. Do not combine rh directly
515
+ # with quantities in physical Mpc (see the units note in Background.py).
516
+ derived_parameters.rh = params.c / derived_parameters.H0 * params.h
515
517
  # critical density at z=0 [h^2 M_sun Mpc^-3]
516
518
  derived_parameters.rho_crit = (
517
519
  3.0
@@ -769,12 +771,12 @@ class Cosmo(object):
769
771
 
770
772
  DERIVED_INFO = dict(
771
773
  _sigma_27="Dimensionless CMB temperature [1]",
772
- _z_equality="Redshift of matter-radiation equlity [1]",
774
+ _z_equality="Redshift of matter-radiation equality [1]",
773
775
  _z_drag="Redshift of drag epoch [1]",
774
- _k_eq="Particle horizon at equality epoch [Mpc-1]",
775
- _sound_horiz="Sound horizon [Mpc-1]",
776
+ _k_eq="Wavenumber at matter-radiation equality [Mpc^-1]",
777
+ _sound_horiz="Sound horizon [Mpc]",
776
778
  H0="Hubble constant (H0) [km/s/Mpc]",
777
- rh="Hubble radius (rh) [Mpc/h]",
779
+ rh="Hubble radius (c/H0, value in h^-1 Mpc) [Mpc/h]",
778
780
  rho_crit="Critical Density (rho_crit) [h^2 M_sun/Mpc^3]",
779
781
  omega_dm="Dark Matter density (omega_dm) [1]",
780
782
  omega_gamma="Photon density (omega_gamma) [1]",
@@ -61,6 +61,15 @@ class LinearPerturbationApprox(LinearPerturbationBase):
61
61
  def max_redshift(self, k):
62
62
  """computes max redshift for which this model is applicable.
63
63
 
64
+ The matter-era start used for the growth integration and for the
65
+ tabulation grids is the scale factor at which the matter density
66
+ fraction is maximal. For a closed universe (``omega_k < 0``) the
67
+ negative-curvature term lowers :math:`E^2(a)` at late times and thereby
68
+ inflates :math:`\\Omega_m(a)`, moving the maximum to a spurious, late
69
+ scale factor. The curvature term is therefore dropped when locating
70
+ the maximum, so that the onset of matter domination is found
71
+ independently of curvature.
72
+
64
73
  :param k: wavenumber k, introduced in the abstract base class since this
65
74
  might be needed for some models.
66
75
  [:math:`h Mpc^{-1}`]
@@ -68,7 +77,13 @@ class LinearPerturbationApprox(LinearPerturbationBase):
68
77
  """
69
78
  k = np.atleast_1d(k)
70
79
  avec = np.linspace(1e-4, 1, 10000)
71
- ai = avec[np.argmax(self._background._omega_m_a(avec))]
80
+ if self._params.omega_k < 0.0:
81
+ e2 = self._background._H2_H02_a(a=avec)
82
+ e2 -= self._background._H2_H02_Omegak_a(a=avec)
83
+ omega_m_a = self._background._H2_H02_Omegam_a(a=avec) / e2
84
+ ai = avec[np.argmax(omega_m_a)]
85
+ else:
86
+ ai = avec[np.argmax(self._background._omega_m_a(avec))]
72
87
  return (1 / ai - 1).repeat(len(k))
73
88
 
74
89
  def _D1(self, a=1.0, norm=0):
@@ -91,8 +106,19 @@ class LinearPerturbationApprox(LinearPerturbationBase):
91
106
  a_start = min(
92
107
  np.concatenate((a, np.array([ai])))
93
108
  ) # initial condition for integration
94
- if a_start < ai:
95
- raise ValueError(f"initial a_start={a_start} too high (at max {ai})")
109
+ # The matter-era initial conditions used below are valid throughout the
110
+ # matter era, i.e. also for a below ``ai = 1/(1+max_redshift)``, which is
111
+ # only the location of the maximum of Omega_m(a). Refuse to start only
112
+ # once radiation dominates, where those initial conditions break down.
113
+ # (For closed or low-Omega_Lambda cosmologies ``ai`` is pushed to late
114
+ # times, so growth_a(a < ai) used to fail even though ``a`` is still
115
+ # well inside the matter era.)
116
+ a_eq = getattr(self._params, "a_eq", np.nan)
117
+ if np.isfinite(a_eq) and a_start < a_eq:
118
+ raise ValueError(
119
+ f"initial a_start={a_start} is below matter-radiation equality "
120
+ f"a_eq={a_eq}"
121
+ )
96
122
 
97
123
  a = np.atleast_1d(a)
98
124
  a_out = np.concatenate((np.array([a_start]), a, np.array([1.0])))
@@ -208,7 +234,11 @@ class LinearPerturbationApprox(LinearPerturbationBase):
208
234
  OL = 1.0 - Om # flat complement, NOT omega_l (which includes radiation)
209
235
  x = -OL * a**3 / Om
210
236
  x1 = -OL / Om
211
- return a * special.hyp2f1(1.0 / 3, 1.0, 11.0 / 6, x) / special.hyp2f1(1.0 / 3, 1.0, 11.0 / 6, x1)
237
+ return (
238
+ a
239
+ * special.hyp2f1(1.0 / 3, 1.0, 11.0 / 6, x)
240
+ / special.hyp2f1(1.0 / 3, 1.0, 11.0 / 6, x1)
241
+ )
212
242
 
213
243
  def transfer_k(self, k):
214
244
  r"""
@@ -447,6 +447,9 @@ class Obs(object):
447
447
  chi = cosmo.background.dist_rad_a(a=a_temp)
448
448
  chi_a = cosmo.background.dist_rad_a(a=a_vec)
449
449
  rchi_a = cosmo.background.dist_trans_a(a=a_vec)
450
+ # chi is in physical Mpc, so the curvature scale is c/H0 in physical Mpc.
451
+ # params.rh = c/H0 * h is in Mpc/h and must not be used with physical Mpc.
452
+ c_over_H0 = cosmo.params.c / cosmo.params.H0
450
453
 
451
454
  for i in range(len(a_vec)):
452
455
  if cosmo.params.omega_k == 0.0:
@@ -457,21 +460,20 @@ class Obs(object):
457
460
  integrand = (
458
461
  pz[: anum + i]
459
462
  * np.sin(
460
- cosmo.params.sqrtk
461
- * (chi[: anum + i] - chi_a[i])
462
- / cosmo.params.rh
463
+ cosmo.params.sqrtk * (chi[: anum + i] - chi_a[i]) / c_over_H0
463
464
  )
464
- / np.sin(cosmo.params.sqrtk * chi[: anum + i] / cosmo.params.rh)
465
+ / np.sin(cosmo.params.sqrtk * chi[: anum + i] / c_over_H0)
465
466
  )
466
467
  else:
468
+ # Open universe (omega_k > 0, negative curvature): the transverse
469
+ # comoving distance is R*sinh(chi/R), so both the numerator (the
470
+ # lens-to-source distance) and the denominator must use sinh.
467
471
  integrand = (
468
472
  pz[: anum + i]
469
- * np.sin(
470
- cosmo.params.sqrtk
471
- * (chi[: anum + i] - chi_a[i])
472
- / cosmo.params.rh
473
+ * np.sinh(
474
+ cosmo.params.sqrtk * (chi[: anum + i] - chi_a[i]) / c_over_H0
473
475
  )
474
- / np.sinh(cosmo.params.sqrtk * chi[: anum + i] / cosmo.params.rh)
476
+ / np.sinh(cosmo.params.sqrtk * chi[: anum + i] / c_over_H0)
475
477
  )
476
478
 
477
479
  wind = np.trapezoid(integrand, a_temp[: anum + i])