1 | /* Code to calculate sigma8 for COBE-normalized CDM and MDM models,
|
---|
2 | using the approximation of Eisenstein & Hu (1997). */
|
---|
3 |
|
---|
4 | /* This code will calculate sigma_8 and other quantities for CDM and
|
---|
5 | MDM models. Because the fitting form for the transfer function does not
|
---|
6 | include the baryon oscillations, the answer will not be accurate for
|
---|
7 | large baryon fractions. The COBE normalization is from the papers
|
---|
8 | on Bunn & White (1997) and Hu & White (1997). */
|
---|
9 |
|
---|
10 | /* Accuracy is generally better than 5%. Recall that the COBE normalization
|
---|
11 | is only 7% accurate (1-sigma). This program gives low answers compared to
|
---|
12 | CMBfast for lower values of Omega_0*h^2, and vice versa for higher values.
|
---|
13 | Values of Omega_0 near 0.2 can produce answers that are 5% low. */
|
---|
14 |
|
---|
15 | /* The integrator used here is a bit crude, but suffices for rapid
|
---|
16 | 10^-3 accuracy. You could get better performance by substituting an
|
---|
17 | integrator from a numerical package. See the end of the file for details. */
|
---|
18 |
|
---|
19 | /* This program uses the routines TFmdm_set_cosm() and TFmdm_onek_hmpc(),
|
---|
20 | available from http://www.sns.ias.edu/~whu/power/power.html in the file
|
---|
21 | power.c. To compile this program, you'll need that file as well, e.g.
|
---|
22 | cc -O sigma8.c power.c -o sigma8 -lm */
|
---|
23 |
|
---|
24 | /* Lists of versions and bugs:
|
---|
25 | v1.0 -- 10/23/97 -- Original release version.
|
---|
26 | v1.1 -- 11/13/97 -- We correct a missing factor of omega_m in the
|
---|
27 | conversion between mass and length scales [lines
|
---|
28 | 32 and 34 of main()]. This only affects the results
|
---|
29 | if you explicitly used the -mass option.
|
---|
30 | v1.2 -- 04/08/98 -- We correct a typo in the second-order tilt scaling
|
---|
31 | of the COBE normalization for flat models with tensors.
|
---|
32 | v1.3 -- 09/15/98 -- We correct a typo in the tilt scaling of the COBE
|
---|
33 | normalization for open models with tensors.
|
---|
34 | v1.4 -- 12/02/98 -- We correct the COBE normalization for tilted open models,
|
---|
35 | undoing the change of v1.3 and fixing what was
|
---|
36 | wrong there to begin with.
|
---|
37 | */
|
---|
38 |
|
---|
39 | #include <math.h>
|
---|
40 | #include <stdio.h>
|
---|
41 | #include <stdlib.h>
|
---|
42 | #include <string.h>
|
---|
43 |
|
---|
44 | int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
|
---|
45 | int degen_hdm, double omega_lambda, double hubble, double redshift);
|
---|
46 | double TFmdm_onek_hmpc(double kk);
|
---|
47 |
|
---|
48 | double sig2tophat(double x);
|
---|
49 | double sig2gauss(double x);
|
---|
50 | double sig2sharpk(double x);
|
---|
51 | double sig2tophatnu(double x);
|
---|
52 | double sig2gaussnu(double x);
|
---|
53 | double sig2sharpknu(double x);
|
---|
54 |
|
---|
55 | #define WEIRD -2538 /* A strange number, unlikely to be entered */
|
---|
56 | #define RHOCRIT 2.78e11 /* The critical density, for h=1, in Msun/Mpc^3 */
|
---|
57 |
|
---|
58 | /* Convenience from Numerical Recipes in C, 2nd edition
|
---|
59 | ------------ COMPLETEMENT DEBILE (cmv) ????????? ------------
|
---|
60 | static double sqrarg;
|
---|
61 | #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
|
---|
62 | */
|
---|
63 | #define SQR(a) (a*a)
|
---|
64 |
|
---|
65 | /* Global variable */
|
---|
66 | double omega_m, omega_b, omega_n,
|
---|
67 | numdegen, lambda, redshift,
|
---|
68 | hubble, scale, mass, tilt;
|
---|
69 | double deltaH; /* COBE-normalization */
|
---|
70 | double sig2_scale; /* For passing a length scale to the integrator */
|
---|
71 | int qtensors, quiet, qredshift;
|
---|
72 |
|
---|
73 | /* ========================== User interaction routines ============== */
|
---|
74 | void usage()
|
---|
75 | /* Print out information about the allowed options and then quit. */
|
---|
76 | {
|
---|
77 | fprintf(stderr,"Command line options:\n");
|
---|
78 | fprintf(stderr,"-om or -omega <omega_matter, including CDM, baryons, massive neutrinos>\n");
|
---|
79 | fprintf(stderr,"-ob <omega_baryon> -fb <baryon_fraction>\n");
|
---|
80 | fprintf(stderr,"-on <omega_neutrino> -fn <neutrino_fraction>\n");
|
---|
81 | fprintf(stderr,"-numdegen or -Nnu <number of degenerate neutrino species>, default 1\n");
|
---|
82 | fprintf(stderr,"-lambda <omega_lambda> -flat (choose lambda appropriately)\n");
|
---|
83 | fprintf(stderr,"-h or -hubble <H_0, units of 100 km/s/Mpc>\n");
|
---|
84 | fprintf(stderr,"-H or -Hubble <H_0, units of 1 km/s/Mpc>\n");
|
---|
85 | fprintf(stderr,"-tilt or -n <scalar spectral tilt>, no tensors.\n");
|
---|
86 | fprintf(stderr,"-Tilt or -N <scalar spectral tilt>, power-law tensors.\n");
|
---|
87 | fprintf(stderr,"-z <redshift>, if none given then appropriate value assumed.\n");
|
---|
88 | fprintf(stderr,"The following request the rms fluctuations inside a tophat window function:\n");
|
---|
89 | fprintf(stderr,"-scale <comoving length scale, h^-1 Mpc>\n");
|
---|
90 | fprintf(stderr,"-mass <mass scale, h^-1 Msun>\n");
|
---|
91 | fprintf(stderr,"If neither -scale or -mass is given, sigma_8 and other quantities are computed.\n");
|
---|
92 | fprintf(stderr,"-quiet (print only answer to stdout)\n");
|
---|
93 | exit(1);
|
---|
94 | return;
|
---|
95 | }
|
---|
96 |
|
---|
97 | void crash(char *s)
|
---|
98 | {
|
---|
99 | fprintf(stderr,"%s\n", s); exit(1); return;
|
---|
100 | }
|
---|
101 |
|
---|
102 | void warn(char *s)
|
---|
103 | {
|
---|
104 | fprintf(stderr,"%s\n", s); return;
|
---|
105 | }
|
---|
106 |
|
---|
107 |
|
---|
108 | void parse_command_line(int argc, char *argv[])
|
---|
109 | /* Parse the command line, and look for illegal entries */
|
---|
110 | {
|
---|
111 | int i;
|
---|
112 | if (argc==1) usage();
|
---|
113 | i = 1;
|
---|
114 | omega_m = 1.0;
|
---|
115 | omega_b = 0.05;
|
---|
116 | omega_n = 0.0;
|
---|
117 | numdegen = 1.0;
|
---|
118 | lambda = 0.0;
|
---|
119 | redshift = 0.0;
|
---|
120 | hubble = 0.5;
|
---|
121 | scale = -1.0;
|
---|
122 | mass = -1.0;
|
---|
123 | qtensors = 0;
|
---|
124 | quiet = 0;
|
---|
125 | tilt = 1.0;
|
---|
126 | qredshift = 0;
|
---|
127 |
|
---|
128 | while (i<argc) {
|
---|
129 | if (!strcmp(argv[i],"-om")||!strcmp(argv[i],"-omega")) {
|
---|
130 | ++i;
|
---|
131 | if (i>=argc) usage();
|
---|
132 | sscanf(argv[i],"%lf",&omega_m); ++i;
|
---|
133 | } else if (!strcmp(argv[i],"-ob")) {
|
---|
134 | ++i;
|
---|
135 | if (i>=argc) usage();
|
---|
136 | sscanf(argv[i],"%lf",&omega_b); ++i;
|
---|
137 | } else if (!strcmp(argv[i],"-fb")) {
|
---|
138 | ++i;
|
---|
139 | if (i>=argc) usage();
|
---|
140 | sscanf(argv[i],"%lf",&omega_b); ++i;
|
---|
141 | omega_b *= -1.0; /* Signal that a fraction was desired */
|
---|
142 | } else if (!strcmp(argv[i],"-on")) {
|
---|
143 | ++i;
|
---|
144 | if (i>=argc) usage();
|
---|
145 | sscanf(argv[i],"%lf",&omega_n); ++i;
|
---|
146 | } else if (!strcmp(argv[i],"-fn")) {
|
---|
147 | ++i;
|
---|
148 | if (i>=argc) usage();
|
---|
149 | sscanf(argv[i],"%lf",&omega_n); ++i;
|
---|
150 | omega_n *= -1.0; /* Signal that a fraction was desired */
|
---|
151 | } else if (!strcmp(argv[i],"-h")||!strcmp(argv[i],"-hubble")) {
|
---|
152 | ++i;
|
---|
153 | if (i>=argc) usage();
|
---|
154 | sscanf(argv[i],"%lf",&hubble); ++i;
|
---|
155 | } else if (!strcmp(argv[i],"-H")||!strcmp(argv[i],"-Hubble")) {
|
---|
156 | ++i;
|
---|
157 | if (i>=argc) usage();
|
---|
158 | sscanf(argv[i],"%lf",&hubble); ++i;
|
---|
159 | hubble /= 100.0; /* Units were 1 km/s/Mpc */
|
---|
160 | } else if (!strcmp(argv[i],"-lambda")) {
|
---|
161 | ++i;
|
---|
162 | if (i>=argc) usage();
|
---|
163 | sscanf(argv[i],"%lf",&lambda); ++i;
|
---|
164 | } else if (!strcmp(argv[i],"-flat")) {
|
---|
165 | ++i;
|
---|
166 | lambda = WEIRD;
|
---|
167 | } else if (!strcmp(argv[i],"-numdegen")||!strcmp(argv[i],"-Nnu")) {
|
---|
168 | ++i;
|
---|
169 | if (i>=argc) usage();
|
---|
170 | sscanf(argv[i],"%lf",&numdegen); ++i;
|
---|
171 | } else if (!strcmp(argv[i],"-n")||!strcmp(argv[i],"-tilt")) {
|
---|
172 | ++i;
|
---|
173 | if (i>=argc) usage();
|
---|
174 | sscanf(argv[i],"%lf",&tilt); ++i;
|
---|
175 | qtensors = 0;
|
---|
176 | } else if (!strcmp(argv[i],"-N")||!strcmp(argv[i],"-Tilt")) {
|
---|
177 | ++i;
|
---|
178 | if (i>=argc) usage();
|
---|
179 | sscanf(argv[i],"%lf",&tilt); ++i;
|
---|
180 | qtensors = 1;
|
---|
181 | } else if (!strcmp(argv[i],"-z")) {
|
---|
182 | ++i;
|
---|
183 | if (i>=argc) usage();
|
---|
184 | sscanf(argv[i],"%lf",&redshift); ++i;
|
---|
185 | qredshift = 1;
|
---|
186 | } else if (!strcmp(argv[i],"-scale")) {
|
---|
187 | ++i;
|
---|
188 | if (i>=argc) usage();
|
---|
189 | sscanf(argv[i],"%lf",&scale); ++i;
|
---|
190 | } else if (!strcmp(argv[i],"-mass")) {
|
---|
191 | ++i;
|
---|
192 | if (i>=argc) usage();
|
---|
193 | sscanf(argv[i],"%lf",&mass); ++i;
|
---|
194 | } else if (!strcmp(argv[i],"-quiet")) {
|
---|
195 | ++i;
|
---|
196 | quiet = 1;
|
---|
197 | } else usage();
|
---|
198 | }
|
---|
199 |
|
---|
200 | /* Look for illegal entries */
|
---|
201 | if (omega_m<=0.0) crash("Omega must be positive.");
|
---|
202 | if (hubble<=0.0) crash("Hubble constant must be positive.");
|
---|
203 | else if (hubble>10.0) warn("Did you get the Hubble units right?");
|
---|
204 | if (numdegen<0) {
|
---|
205 | warn("Negative number of degenerate species reset to 1.");
|
---|
206 | numdegen = 1.0;
|
---|
207 | }
|
---|
208 | if (redshift<=-1.0) crash("Redshift must exceed -1.");
|
---|
209 | if (scale>0.0 && mass>0.0) {
|
---|
210 | warn("Input length OR mass scale. Defaulting to length.");
|
---|
211 | mass = -1.0;
|
---|
212 | }
|
---|
213 |
|
---|
214 | /* Now look for fractions, if they were input. */
|
---|
215 | if (omega_b<0.0) omega_b = omega_m*(-omega_b);
|
---|
216 | if (omega_n<0.0) omega_n = omega_m*(-omega_n);
|
---|
217 | if (lambda== WEIRD) lambda = 1-omega_m; /* Set to be flat */
|
---|
218 |
|
---|
219 | if (omega_b+omega_n>omega_m) crash("Baryons + Neutrinos exceeds Omega_0.");
|
---|
220 | else if (omega_b+omega_n>0.6*omega_m)
|
---|
221 | warn("CDM fraction is below range of TF fitting formula.");
|
---|
222 | if (tilt>1.3 || tilt < 0.7)
|
---|
223 | warn("Tilt out of range of Bunn and White fitting formula.");
|
---|
224 | if (tilt!=1 && (omega_m<0.2 || omega_m>1.0))
|
---|
225 | warn("Omega out of range of Bunn and White fitting formula.");
|
---|
226 | if (tilt==1 && (omega_m<0.2 || omega_m>1.6 || lambda<0.0 || lambda>0.8))
|
---|
227 | warn("Omega or Lambda out of range of Bunn and White fitting formula.");
|
---|
228 | if (qtensors!=0&&(tilt>1.0||
|
---|
229 | (fabs(lambda)>1e-5&&fabs(1.0-omega_m-lambda)>1e-5)))
|
---|
230 | crash("Tensor formulae only hold for tilts < 1 and simple cosmologies.");
|
---|
231 | if (omega_b/omega_m>0.4) warn("Baryon oscillations will be large. TF fitting form will be inaccurate.");
|
---|
232 | if (omega_n/omega_m>0.4) warn("Neutrino fraction outside of range of TF fitting form.");
|
---|
233 | if (omega_m*hubble*hubble>0.4) warn("Omega_0 h^2 outside of range of TF fitting form.");
|
---|
234 | if (omega_m*hubble*hubble<0.06) warn("Omega_0 h^2 outside of range of TF fitting form.");
|
---|
235 | if (redshift>29) warn("Redshift is higher than range of TF fitting form.");
|
---|
236 |
|
---|
237 | return;
|
---|
238 | }
|
---|
239 |
|
---|
240 | /* ==================================== MAIN() ========================= */
|
---|
241 |
|
---|
242 | void main(int argc, char *argv[])
|
---|
243 | {
|
---|
244 | double erfcc(double x);
|
---|
245 | double sigma, sigma8;
|
---|
246 | extern double growth_to_z0, z_equality, alpha_nu, beta_c;
|
---|
247 | double cobenorm();
|
---|
248 | double integrate(double (*func)(double));
|
---|
249 | parse_command_line(argc, argv);
|
---|
250 |
|
---|
251 | /* Set all the background quantities */
|
---|
252 | TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda,
|
---|
253 | hubble, redshift);
|
---|
254 | deltaH = cobenorm();
|
---|
255 |
|
---|
256 | if (!quiet) { /* Echo cosmological information to the screen */
|
---|
257 | printf("Omega_0 = %5.3f, Omega_baryon = %5.3f, Omega_neutrino = %5.3f\n",
|
---|
258 | omega_m, omega_b, omega_n);
|
---|
259 | printf("Hubble = %5.3f, Lambda = %5.3f, N_neutrinos = %d\n",
|
---|
260 | hubble, lambda, (int) numdegen);
|
---|
261 | printf("Redshift = %5.3f, Growth = %6.4f relative to z=0\n",
|
---|
262 | redshift, growth_to_z0);
|
---|
263 | printf("Tilt = %5.3f, COBE normalization: deltaH = %8.3e",
|
---|
264 | tilt, deltaH);
|
---|
265 | if (tilt!=1.0)
|
---|
266 | if (qtensors) printf(" with tensors.\n");
|
---|
267 | else printf(" without tensors.\n");
|
---|
268 | else printf("\n");
|
---|
269 | }
|
---|
270 | /* If we've been asked to compute for a particular scale, do that */
|
---|
271 | if (scale>0 || mass>0) {
|
---|
272 | if (mass<0)
|
---|
273 | mass = 4.0*M_PI/3.0*omega_m*RHOCRIT*scale*scale*scale;
|
---|
274 | else if (scale<0)
|
---|
275 | scale = pow(3.0/4.0/M_PI/RHOCRIT/omega_m*mass, 1.0/3.0);
|
---|
276 | /* Integrate tophat for the given scale */
|
---|
277 | sig2_scale = scale;
|
---|
278 | sigma = sqrt(integrate(sig2tophatnu));
|
---|
279 |
|
---|
280 | /* Print out the result */
|
---|
281 | if (!quiet) printf("For length scale %6.4f h^-1 Mpc, mass scale %8.3e h^-1 Msun.\nrms tophat fluctuations are ",
|
---|
282 | sig2_scale, mass);
|
---|
283 | printf("%6.4f\n", sigma);
|
---|
284 | } else {
|
---|
285 | /* No scale was requested, so we do the standard tasks */
|
---|
286 | /* Calculate sigma_8 */
|
---|
287 | sig2_scale = 8.0;
|
---|
288 | sigma8 = sqrt(integrate(sig2tophatnu));
|
---|
289 | if (quiet) {
|
---|
290 | printf("%6.4f\n", sigma8);
|
---|
291 | return; /* This is all we're doing */
|
---|
292 | }
|
---|
293 | printf("Sigma_8 = %6.4f\n", sigma8);
|
---|
294 |
|
---|
295 | /* Calculate sigma_50 */
|
---|
296 | sig2_scale = 50.0;
|
---|
297 | sigma = sqrt(integrate(sig2tophatnu));
|
---|
298 | printf("Sigma_50 = %6.4f Sigma_50/sigma_8 = %6.4f\n",
|
---|
299 | sigma, sigma/sigma8);
|
---|
300 |
|
---|
301 | /* We default to z=4 for DLA */
|
---|
302 | if (!qredshift) {
|
---|
303 | redshift = 4.0;
|
---|
304 | TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda,
|
---|
305 | hubble, redshift);
|
---|
306 | }
|
---|
307 | sig2_scale = 50.0/100.0/sqrt(1+redshift)/sqrt(2*3.14159)*
|
---|
308 | pow(8.0*3.14159/3.0/sqrt(89.0),1./3.);
|
---|
309 | sigma = sqrt(integrate(sig2gaussnu));
|
---|
310 | printf("Omega_gas = %8.3e at redshift %5.3f due to \n sigma(50 km/s) = sigma(%5.3f h^-1 Mpc) = %6.4f (DLA, Klypin et al. 1994)\n",
|
---|
311 | omega_b*erfcc(1.33/1.414/sigma), redshift, sig2_scale, sigma);
|
---|
312 |
|
---|
313 | /* We default to z=3 for Lyman alpha forest */
|
---|
314 | if (!qredshift) {
|
---|
315 | redshift = 3.0;
|
---|
316 | TFmdm_set_cosm(omega_m, omega_b, omega_n, (int) numdegen, lambda,
|
---|
317 | hubble, redshift);
|
---|
318 | }
|
---|
319 | sig2_scale = 1.0/(34.0*sqrt(omega_m/2.0)); /* Gnedin's k_34 */
|
---|
320 | sigma = sqrt(integrate(sig2gauss));
|
---|
321 | printf("Sigma_Lya = %6.4f at redshift %5.3f (Ly-alpha forest, Gnedin 1997)\n",
|
---|
322 | sigma, redshift);
|
---|
323 |
|
---|
324 | printf("Small-scale: alpha_nu = %6.4f, beta_c = %6.4f\n",
|
---|
325 | alpha_nu, beta_c);
|
---|
326 | }
|
---|
327 | return;
|
---|
328 | }
|
---|
329 |
|
---|
330 | /* ========================== Integration Kernals ======================= */
|
---|
331 |
|
---|
332 | double W2tophat(double x)
|
---|
333 | /* The square of the tophat window */
|
---|
334 | {
|
---|
335 | double j1onx;
|
---|
336 | if (x<0.03)
|
---|
337 | j1onx = (1.0/3.0-x*x*1.0/30.0);
|
---|
338 | else j1onx = (cos(x)-sin(x)/x)/x/x;
|
---|
339 | return 9.0*j1onx*j1onx;
|
---|
340 | }
|
---|
341 |
|
---|
342 | double sig2tophat(double x)
|
---|
343 | /* This is the integrand for the mass fluctuation integral
|
---|
344 | sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
|
---|
345 | broken and recombined so that one integrates on (0,1] in a new variable x. */
|
---|
346 | /* Here, the window is a real-space tophat of radius sig2_scale, the
|
---|
347 | latter being passed from outside in units of h^-1 Mpc */
|
---|
348 | {
|
---|
349 | double powerspcb(double k);
|
---|
350 | return (powerspcb(x/sig2_scale)*W2tophat(x)+
|
---|
351 | powerspcb(1.0/x/sig2_scale)*W2tophat(1.0/x))/x;
|
---|
352 | }
|
---|
353 |
|
---|
354 | double sig2tophatnu(double x)
|
---|
355 | /* Same as sig2tophat(), but with P_cbnu */
|
---|
356 | {
|
---|
357 | double powerspcbnu(double k);
|
---|
358 | return (powerspcbnu(x/sig2_scale)*W2tophat(x)+
|
---|
359 | powerspcbnu(1.0/x/sig2_scale)*W2tophat(1.0/x))/x;
|
---|
360 | }
|
---|
361 |
|
---|
362 | double sig2gauss(double x)
|
---|
363 | /* This is the integrand for the mass fluctuation integral
|
---|
364 | sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
|
---|
365 | broken and recombined so that one integrates on (0,1] in a new variable x. */
|
---|
366 | /* Here, the window is a gaussian of radius sig2_scale, the
|
---|
367 | latter being passed from outside in units of h^-1 Mpc */
|
---|
368 | {
|
---|
369 | double powerspcb(double k);
|
---|
370 | return (powerspcb(x/sig2_scale)*exp(-x*x)+
|
---|
371 | powerspcb(1.0/x/sig2_scale)*exp(-1.0/x/x))/x;
|
---|
372 | }
|
---|
373 |
|
---|
374 | double sig2gaussnu(double x)
|
---|
375 | /* Same as sig2gauss(), but with P_cbnu */
|
---|
376 | {
|
---|
377 | double powerspcbnu(double k);
|
---|
378 | return (powerspcbnu(x/sig2_scale)*exp(-x*x)+
|
---|
379 | powerspcbnu(1.0/x/sig2_scale)*exp(-1.0/x/x))/x;
|
---|
380 | }
|
---|
381 |
|
---|
382 | double sig2sharpk(double x)
|
---|
383 | /* This is the integrand for the mass fluctuation integral
|
---|
384 | sig2 = \int_0^\infty (dk/k) Delta^2(k) W^2(kr)
|
---|
385 | broken and recombined so that one integrates on (0,1] in a new variable x. */
|
---|
386 | /* Here, the window is a k-space tophat of radius 1/sig2_scale, the
|
---|
387 | latter being passed from outside in units of h^-1 Mpc */
|
---|
388 | {
|
---|
389 | double powerspcb(double k);
|
---|
390 | return (powerspcb(x/sig2_scale))/x;
|
---|
391 | }
|
---|
392 |
|
---|
393 | double sig2sharpknu(double x)
|
---|
394 | /* Same as sig2sharpk(), but with P_cbnu */
|
---|
395 | {
|
---|
396 | double powerspcbnu(double k);
|
---|
397 | return (powerspcbnu(x/sig2_scale))/x;
|
---|
398 | }
|
---|
399 |
|
---|
400 | /* ============================ Power Spectrum and COBE ================ */
|
---|
401 | double powerspcbnu(double k)
|
---|
402 | /* Returns Delta^2(k), COBE-normalized, based on the approximations of
|
---|
403 | Eisenstein & Hu (1997). k is in h^-1 Mpc. */
|
---|
404 | /* TFmdm_set_cosm() and cobenorm() must have been called before this */
|
---|
405 | /* Returns the density-weighted CDM+Baryon+Neutrino power spectrum */
|
---|
406 | {
|
---|
407 | extern double tf_cbnu, growth_to_z0;
|
---|
408 | TFmdm_onek_hmpc(k); /* This sets the value in tf_cbnu */
|
---|
409 | return pow(2997.0*k, tilt+3.0)*SQR(deltaH*tf_cbnu*growth_to_z0);
|
---|
410 | }
|
---|
411 |
|
---|
412 | double powerspcb(double k)
|
---|
413 | /* Returns Delta^2(k), COBE-normalized, based on the approximations of
|
---|
414 | Eisenstein & Hu (1997). k is in h^-1 Mpc. */
|
---|
415 | /* TFmdm_set_cosm() and cobenorm() must have been called before this */
|
---|
416 | /* Returns the density-weighted CDM+Baryon power spectrum */
|
---|
417 | {
|
---|
418 | extern double growth_to_z0;
|
---|
419 | return pow(2997.0*k, tilt+3.0)*SQR(deltaH*TFmdm_onek_hmpc(k)*growth_to_z0);
|
---|
420 | }
|
---|
421 |
|
---|
422 | double cobenorm()
|
---|
423 | /* Return the Bunn & White (1997) fit for delta_H */
|
---|
424 | /* Given lambda, omega_m, qtensors, and tilt */
|
---|
425 | /* Open model with tensors is from Hu & White */
|
---|
426 | {
|
---|
427 | double n;
|
---|
428 | n = tilt-1;
|
---|
429 | if (fabs(omega_m+lambda-1.0)<1e-5) { /* Flat universe */
|
---|
430 | if (qtensors)
|
---|
431 | return 1.94e-5*pow(omega_m, -0.785-0.05*log(omega_m))*
|
---|
432 | exp(n+1.97*n*n);
|
---|
433 | else return 1.94e-5*pow(omega_m, -0.785-0.05*log(omega_m))*
|
---|
434 | exp(-0.95*n-0.169*n*n);
|
---|
435 | /* Error -- was 0.0169 in earlier version of code */
|
---|
436 | } else if (fabs(lambda)<1e-5) { /* No lambda */
|
---|
437 | if (qtensors)
|
---|
438 | return 1.95e-5*pow(omega_m,-0.35-0.19*log(omega_m)-0.15*n)*
|
---|
439 | exp(+1.02*n+1.7*n*n);
|
---|
440 | /* Error -- was exp(-1.02n-1.7*n*n) in earlier version (v1-1.3)*/
|
---|
441 | else return 1.95e-5*pow(omega_m, -0.35-0.19*log(omega_m)-0.17*n)*
|
---|
442 | exp(-n-0.14*n*n);
|
---|
443 | /* Error -- was exp(-n-0.14*n*n) in earlier version (v1-1.2)*/
|
---|
444 | /* Error -- was exp(n+0.14*n*n) in earlier version (v1.3) */
|
---|
445 | } else return 1e-5*(2.422-1.166*exp(omega_m)+0.800*exp(lambda)
|
---|
446 | +3.780*omega_m-2.267*omega_m*exp(lambda)+0.487*SQR(omega_m)+
|
---|
447 | 0.561*lambda+3.329*lambda*exp(omega_m)-8.568*omega_m*lambda+
|
---|
448 | 1.080*SQR(lambda));
|
---|
449 | }
|
---|
450 |
|
---|
451 | /* The following routine is from Numerical Recipes in C, 2nd edition,
|
---|
452 | by Press, Teulkolsky, Vetterling, and Flannery, (Cambridge Univ. Press) */
|
---|
453 | double erfcc(double x)
|
---|
454 | {
|
---|
455 | double t,z,ans;
|
---|
456 | z=fabs(x);
|
---|
457 | t=1.0/(1.0+0.5*z);
|
---|
458 | ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+
|
---|
459 | t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+
|
---|
460 | t*(-0.82215223+t*0.17087277)))))))));
|
---|
461 | return x >= 0.0 ? ans : 2.0-ans;
|
---|
462 | }
|
---|
463 |
|
---|
464 | /* ======================= Integration Engine ======================= */
|
---|
465 |
|
---|
466 | double midpoint_int(double (*func)(double))
|
---|
467 | /* Integrate the function func() on the range (0,1] */
|
---|
468 | /* Use midpoint rule, expanding by factor of 3 each time */
|
---|
469 | /* Linearly extrapolate to zero stepsize. Not fancy */
|
---|
470 | {
|
---|
471 | int iter, bins, j;
|
---|
472 | double width, xeval, sum[11];
|
---|
473 |
|
---|
474 | sum[0] = (*func)(0.5); /* First step is easy */
|
---|
475 | bins = 1; width = 1.0;
|
---|
476 | for (iter=1; iter<11; iter++) { /* Now start increasing the bins */
|
---|
477 | bins *= 3;
|
---|
478 | width /= 3.0;
|
---|
479 | sum[iter]=0.0;
|
---|
480 | for (xeval=width/2.0,j=1;j<=bins;xeval+=width,j++) {
|
---|
481 | if (j%3==2) continue; /* We've already done this one */
|
---|
482 | sum[iter]+=(*func)(xeval);
|
---|
483 | }
|
---|
484 | /* Add the new evaluations to the old ones. */
|
---|
485 | sum[iter]=sum[iter]*width+sum[iter-1]/3.0;
|
---|
486 | /* printf("%d iteration, sum = %f\n", iter, sum[iter]); */
|
---|
487 | /* Now decide if we're done */
|
---|
488 | if (iter<4) continue; /* We certainly want to do some work */
|
---|
489 | /* If error scales as width^2, then linear extrapolation in
|
---|
490 | quantity width^2 is sum[iter]+(sum[iter]-sum[iter-1])/8.0 */
|
---|
491 | if (fabs( (sum[iter]+(sum[iter]-sum[iter-1])/8.0)/
|
---|
492 | (sum[iter-1]+(sum[iter-1]-sum[iter-2])/8.0)-1.0)<1e-4)
|
---|
493 | return sum[iter]+(sum[iter]-sum[iter-1])/8.0;
|
---|
494 | /* if (fabs(sum[iter-1]/sum[iter]-1)<1e-4) return sum[iter]; */
|
---|
495 | }
|
---|
496 | crash("Too many steps in the integration.");
|
---|
497 | }
|
---|
498 |
|
---|
499 | double integrate(double (*func)(double))
|
---|
500 | /* Integrate the function func() on the range (0,1] */
|
---|
501 | {
|
---|
502 | double midpoint_int(double (*func)(double));
|
---|
503 | return midpoint_int(func);
|
---|
504 | }
|
---|
505 |
|
---|
506 | /* The above is a simple integrator. You could get faster execution times
|
---|
507 | by using a more accurate integrator. The following is an example from
|
---|
508 | Numerical Recipes, but all that is needed is for the call to integrate()
|
---|
509 | to return the value of func() integrated on the range (0,1]. */
|
---|
510 |
|
---|
511 | #ifdef YES_NR
|
---|
512 | #include "qromo.c"
|
---|
513 | #include "midpnt.c"
|
---|
514 | #include "polint.c"
|
---|
515 | #include "nrutil.c"
|
---|
516 |
|
---|
517 | float integrate(float (*func)(float))
|
---|
518 | /* Integrate the function func() on the range (0,1] */
|
---|
519 | {
|
---|
520 | float qromo(float (*func)(float), float a, float b,
|
---|
521 | float (*choose)(float(*)(float),float,float,int));
|
---|
522 | float midpnt(float (*func)(float), float a, float b, int n);
|
---|
523 | return qromo(func,0,1,midpnt);
|
---|
524 | }
|
---|
525 | #endif
|
---|
526 |
|
---|