Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
ccl_test_redshifts.py
Go to the documentation of this file.
1 import numpy as np
2 from numpy.testing import assert_allclose, run_module_suite
3 import numpy.testing
4 import pyccl as ccl
5 
6 # Set tolerances
7 TOLERANCE = 1e-4
8 
10  """
11  Compare the redshift functions to an analytic toy case.
12  """
13  # Redshift input
14  z_lst = [0., 0.5, 1., 1.5, 2.]
15 
16  # p(z) function for which we can calculate and analytic dNdz_tomog
17  # when pairs with the toy dndz_ana below
18  def pz_ana(z_ph, z_s, args):
19  return (np.exp(- (z_ph - z_s)**2. / 2. / 0.1**2) / np.sqrt(2.
20  * np.pi) / 0.1)
21 
22  # PhotoZFunction class
23  PZ_ana = ccl.PhotoZFunction(pz_ana)
24 
25  # Introduce an unrealistic, simple true function for dNdz for which
26  # we can calculate dNdz_tomog analytically for comparison.
27  def dndz_ana(z, args):
28  if ((z>=0.) and (z<=1.0)):
29  return 1.0
30  else:
31  return 0.
32 
33  # import math erf and erfc functions:
34  from math import erf, erfc
35 
36  # Return the analytic result for dNdz_tomog using
37  # dndz_ana with a Gaussian p(z,z'), to which we compare.
38 
39  # This is obtained by analytically evaluating (in pseudo-latex):
40  # \frac{ dndz_ana(z) \int_{zpmin}^{zpmax} dz_p pz_ana(z_p, z_s)}
41  # {\int_{0}^{1} dz_s dndz_ana(z_s) \int_{zpmin}^{zpmax} dz_p
42  # pz_ana(z_p, z_s)}
43  # (which we did using Wolfram Mathematica)
44 
45  def dNdz_tomog_analytic(z, sigz, zmin, zmax):
46  if ( (z>=0.) and (z<=1.0) ):
47  return (erf((z-zmin) / np.sqrt(2.)/sigz) - erf((z-zmax)/
48  np.sqrt(2.)/sigz)) / (-1. + (-np.exp(-(zmax-1)**2
49  / 2. / sigz**2) + np.exp(-zmax**2 / 2. / sigz**2) +
50  np.exp(-(zmin-1)**2 / 2. / sigz**2) - np.exp(
51  -zmin**2 / 2 /sigz**2)) * np.sqrt(2. / np.pi)*sigz
52  + erf( (zmax-1) / np.sqrt(2.) / sigz) + erfc(
53  (zmin-1.)/np.sqrt(2.)/sigz) + zmax * (erf(zmax/
54  np.sqrt(2.)/sigz) - erf( (zmax-1.) / np.sqrt(2.)/
55  sigz)) + zmin * ( erf( (zmin-1.)/np.sqrt(2.)
56  / sigz) - erf(zmin/np.sqrt(2.)/sigz)))
57  else:
58  return 0.
59 
60  # dNdzFunction class
61  dNdZ_ana = ccl.dNdzFunction(dndz_ana)
62 
63  # Check that for the analytic case introduced above, we get the
64  # correct value.
65  zmin = 0.
66  zmax = 1.
67  # math erf funcs are not vectorized so loop over z values
68  for z in z_lst:
69  assert_allclose(ccl.dNdz_tomog(z, zmin, zmax, PZ_ana,
70  dNdZ_ana), dNdz_tomog_analytic(z, 0.1, zmin,
71  zmax), rtol=TOLERANCE)
72 
74  """
75  Compare the redshift functions to a high precision integral.
76  """
77  # Redshift input
78  z_lst = [0., 0.5, 1., 1.5, 2.]
79 
80  # p(z) function for dNdz_tomog
81  def pz1(z_ph, z_s, args):
82  return np.exp(- (z_ph - z_s)**2. / 2.)
83 
84  # Lambda function p(z) function for dNdz_tomog
85  pz2 = lambda z_ph, z_s, args: np.exp(-(z_ph - z_s)**2. / 2.)
86 
87  # Set up a function equivalent to the PhotoZGaussian
88  def pz3(z_ph, z_s, sigz):
89  sig = sigz*(1.+ z_s)
90  return (np.exp(- (z_ph - z_s)**2. / 2. / sig**2) / np.sqrt(2.
91  *np.pi) / sig)
92 
93  # PhotoZFunction classes
94  PZ1 = ccl.PhotoZFunction(pz1)
95  PZ2 = ccl.PhotoZFunction(pz2)
96  PZ3 = ccl.PhotoZGaussian(sigma_z0=0.1)
97 
98  # dNdz (in terms of true redshift) function for dNdz_tomog
99  def dndz1(z, args):
100  return z**1.24 * np.exp(- (z / 0.51)**1.01)
101 
102  # dNdzFunction classes
103  dNdZ1 = ccl.dNdzFunction(dndz1)
104  dNdZ2 = ccl.dNdzSmail(alpha = 1.24, beta = 1.01, z0 = 0.51)
105 
106  # Do the integral in question directly in numpy at high precision
107  zmin = 0.
108  zmax = 1.
109  zp = np.linspace(zmin, zmax, 10000)
110  zs = np.linspace(0., 5., 10000) # Assume any dNdz does not extend
111  # above z=5
112  denom_zp_1 =np.asarray([np.trapz(pz1(zp, z, []), zp) for z in zs])
113  denom_zp_2 =np.asarray([np.trapz(pz2(zp, z, []), zp) for z in zs])
114  denom_zp_3 =np.asarray([np.trapz(pz3(zp, z, 0.1), zp) for z in zs])
115  np_dndz_1 = ([ dndz1(z, []) * np.trapz(pz1(zp, z, []), zp) /
116  np.trapz(dndz1(zs, []) * denom_zp_1, zs) for z in
117  z_lst])
118  np_dndz_2 = ([ dndz1(z, []) * np.trapz(pz2(zp, z, []), zp) /
119  np.trapz(dndz1(zs, []) * denom_zp_2, zs) for z in
120  z_lst])
121  np_dndz_3 = ([ dndz1(z, []) * np.trapz(pz3(zp, z, 0.1), zp) /
122  np.trapz(dndz1(zs, []) * denom_zp_3, zs) for z in
123  z_lst])
124 
125  # Check that for the analytic case introduced above, we get the
126  # correct value.
127  for i in range(0, len(z_lst)):
128  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ1,
129  dNdZ1), np_dndz_1[i], rtol=TOLERANCE)
130  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ1,
131  dNdZ2), np_dndz_1[i], rtol=TOLERANCE)
132  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ2,
133  dNdZ1), np_dndz_2[i], rtol=TOLERANCE)
134  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ2,
135  dNdZ2), np_dndz_2[i], rtol=TOLERANCE)
136  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ3,
137  dNdZ1), np_dndz_3[i], rtol=TOLERANCE)
138  assert_allclose(ccl.dNdz_tomog(z_lst[i], zmin, zmax, PZ3,
139  dNdZ2), np_dndz_3[i], rtol=TOLERANCE)
140 
141 if __name__ == "__main__":
142  run_module_suite()
auto range(T const &first, T const &last) -> Generator< T >
Definition: catch.hpp:3156