| 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 | 
 | 
|---|