[3315] | 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 |
|
---|