| 1 | /* Fitting Formulae for CDM + Baryon + Massive Neutrino (MDM) cosmologies. */
 | 
|---|
| 2 | /* Daniel J. Eisenstein & Wayne Hu, Institute for Advanced Study */
 | 
|---|
| 3 | 
 | 
|---|
| 4 | /* There are two primary routines here, one to set the cosmology, the
 | 
|---|
| 5 | other to construct the transfer function for a single wavenumber k. 
 | 
|---|
| 6 | You should call the former once (per cosmology) and the latter as 
 | 
|---|
| 7 | many times as you want. */
 | 
|---|
| 8 | 
 | 
|---|
| 9 | /* TFmdm_set_cosm() -- User passes all the cosmological parameters as
 | 
|---|
| 10 |         arguments; the routine sets up all of the scalar quantites needed 
 | 
|---|
| 11 |         computation of the fitting formula.  The input parameters are: 
 | 
|---|
| 12 |         1) omega_matter -- Density of CDM, baryons, and massive neutrinos,
 | 
|---|
| 13 |                                 in units of the critical density. 
 | 
|---|
| 14 |         2) omega_baryon -- Density of baryons, in units of critical. 
 | 
|---|
| 15 |         3) omega_hdm    -- Density of massive neutrinos, in units of critical 
 | 
|---|
| 16 |         4) degen_hdm    -- (Int) Number of degenerate massive neutrino species 
 | 
|---|
| 17 |         5) omega_lambda -- Cosmological constant 
 | 
|---|
| 18 |         6) hubble       -- Hubble constant, in units of 100 km/s/Mpc 
 | 
|---|
| 19 |         7) redshift     -- The redshift at which to evaluate */
 | 
|---|
| 20 | 
 | 
|---|
| 21 | /* TFmdm_onek_mpc() -- User passes a single wavenumber, in units of Mpc^-1.
 | 
|---|
| 22 |         Routine returns the transfer function from the Eisenstein & Hu
 | 
|---|
| 23 |         fitting formula, based on the cosmology currently held in the 
 | 
|---|
| 24 |         internal variables.  The routine returns T_cb (the CDM+Baryon
 | 
|---|
| 25 |         density-weighted transfer function), although T_cbn (the CDM+
 | 
|---|
| 26 |         Baryon+Neutrino density-weighted transfer function) is stored
 | 
|---|
| 27 |         in the global variable tf_cbnu. */
 | 
|---|
| 28 | 
 | 
|---|
| 29 | /* We also supply TFmdm_onek_hmpc(), which is identical to the previous
 | 
|---|
| 30 |         routine, but takes the wavenumber in units of h Mpc^-1. */
 | 
|---|
| 31 | 
 | 
|---|
| 32 | /* We hold the internal scalar quantities in global variables, so that
 | 
|---|
| 33 | the user may access them in an external program, via "extern" declarations. */
 | 
|---|
| 34 | 
 | 
|---|
| 35 | /* Please note that all internal length scales are in Mpc, not h^-1 Mpc! */
 | 
|---|
| 36 | 
 | 
|---|
| 37 | /* -------------------------- Prototypes ----------------------------- */
 | 
|---|
| 38 | 
 | 
|---|
| 39 | int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
 | 
|---|
| 40 |         int degen_hdm, double omega_lambda, double hubble, double redshift);
 | 
|---|
| 41 | double TFmdm_onek_mpc(double kk);
 | 
|---|
| 42 | double TFmdm_onek_hmpc(double kk);
 | 
|---|
| 43 | 
 | 
|---|
| 44 | #include <math.h>
 | 
|---|
| 45 | #include <stdio.h>
 | 
|---|
| 46 | #include <stdlib.h>
 | 
|---|
| 47 | 
 | 
|---|
| 48 | /* Convenience from Numerical Recipes in C, 2nd edition
 | 
|---|
| 49 | ------------ COMPLETEMENT DEBILE (cmv) ????????? ------------
 | 
|---|
| 50 | static double sqrarg;
 | 
|---|
| 51 | #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
 | 
|---|
| 52 | */
 | 
|---|
| 53 | #define SQR(a) (a*a)
 | 
|---|
| 54 | 
 | 
|---|
| 55 | /* ------------------------- Global Variables ------------------------ */
 | 
|---|
| 56 | 
 | 
|---|
| 57 | /* The following are set in TFmdm_set_cosm() */
 | 
|---|
| 58 | double   alpha_gamma,   /* sqrt(alpha_nu) */
 | 
|---|
| 59 |         alpha_nu,       /* The small-scale suppression */
 | 
|---|
| 60 |         beta_c,         /* The correction to the log in the small-scale */
 | 
|---|
| 61 |         num_degen_hdm,  /* Number of degenerate massive neutrino species */
 | 
|---|
| 62 |         f_baryon,       /* Baryon fraction */
 | 
|---|
| 63 |         f_bnu,          /* Baryon + Massive Neutrino fraction */
 | 
|---|
| 64 |         f_cb,           /* Baryon + CDM fraction */
 | 
|---|
| 65 |         f_cdm,          /* CDM fraction */
 | 
|---|
| 66 |         f_hdm,          /* Massive Neutrino fraction */
 | 
|---|
| 67 |         growth_k0,      /* D_1(z) -- the growth function as k->0 */
 | 
|---|
| 68 |         growth_to_z0,   /* D_1(z)/D_1(0) -- the growth relative to z=0 */
 | 
|---|
| 69 |         hhubble,        /* Need to pass Hubble constant to TFmdm_onek_hmpc() */
 | 
|---|
| 70 |         k_equality,     /* The comoving wave number of the horizon at equality*/
 | 
|---|
| 71 |         obhh,           /* Omega_baryon * hubble^2 */
 | 
|---|
| 72 |         omega_curv,     /* = 1 - omega_matter - omega_lambda */
 | 
|---|
| 73 |         omega_lambda_z, /* Omega_lambda at the given redshift */
 | 
|---|
| 74 |         omega_matter_z, /* Omega_matter at the given redshift */
 | 
|---|
| 75 |         omhh,           /* Omega_matter * hubble^2 */
 | 
|---|
| 76 |         onhh,           /* Omega_hdm * hubble^2 */
 | 
|---|
| 77 |         p_c,            /* The correction to the exponent before drag epoch */
 | 
|---|
| 78 |         p_cb,           /* The correction to the exponent after drag epoch */
 | 
|---|
| 79 |         sound_horizon_fit,  /* The sound horizon at the drag epoch */
 | 
|---|
| 80 |         theta_cmb,      /* The temperature of the CMB, in units of 2.7 K */
 | 
|---|
| 81 |         y_drag,         /* Ratio of z_equality to z_drag */
 | 
|---|
| 82 |         z_drag,         /* Redshift of the drag epoch */
 | 
|---|
| 83 |         z_equality;     /* Redshift of matter-radiation equality */
 | 
|---|
| 84 | 
 | 
|---|
| 85 | /* The following are set in TFmdm_onek_mpc() */
 | 
|---|
| 86 | double  gamma_eff,      /* Effective \Gamma */
 | 
|---|
| 87 |         growth_cb,      /* Growth factor for CDM+Baryon perturbations */
 | 
|---|
| 88 |         growth_cbnu,    /* Growth factor for CDM+Baryon+Neutrino pert. */
 | 
|---|
| 89 |         max_fs_correction,  /* Correction near maximal free streaming */
 | 
|---|
| 90 |         qq,             /* Wavenumber rescaled by \Gamma */
 | 
|---|
| 91 |         qq_eff,         /* Wavenumber rescaled by effective Gamma */
 | 
|---|
| 92 |         qq_nu,          /* Wavenumber compared to maximal free streaming */
 | 
|---|
| 93 |         tf_master,      /* Master TF */
 | 
|---|
| 94 |         tf_sup,         /* Suppressed TF */
 | 
|---|
| 95 |         y_freestream;   /* The epoch of free-streaming for a given scale */
 | 
|---|
| 96 | 
 | 
|---|
| 97 | /* Finally, TFmdm_onek_mpc() and TFmdm_onek_hmpc() give their answers as */
 | 
|---|
| 98 | double   tf_cb,         /* The transfer function for density-weighted
 | 
|---|
| 99 |                         CDM + Baryon perturbations. */
 | 
|---|
| 100 |         tf_cbnu;        /* The transfer function for density-weighted
 | 
|---|
| 101 |                         CDM + Baryon + Massive Neutrino perturbations. */
 | 
|---|
| 102 | 
 | 
|---|
| 103 | /* By default, these functions return tf_cb */
 | 
|---|
| 104 | 
 | 
|---|
| 105 | /* ------------------------- TFmdm_set_cosm() ------------------------ */
 | 
|---|
| 106 | int TFmdm_set_cosm(double omega_matter, double omega_baryon, double omega_hdm,
 | 
|---|
| 107 |         int degen_hdm, double omega_lambda, double hubble, double redshift)
 | 
|---|
| 108 | /* This routine takes cosmological parameters and a redshift and sets up
 | 
|---|
| 109 | all the internal scalar quantities needed to compute the transfer function. */
 | 
|---|
| 110 | /* INPUT: omega_matter -- Density of CDM, baryons, and massive neutrinos,
 | 
|---|
| 111 |                                 in units of the critical density. */
 | 
|---|
| 112 | /*        omega_baryon -- Density of baryons, in units of critical. */
 | 
|---|
| 113 | /*        omega_hdm    -- Density of massive neutrinos, in units of critical */
 | 
|---|
| 114 | /*        degen_hdm    -- (Int) Number of degenerate massive neutrino species */
 | 
|---|
| 115 | /*        omega_lambda -- Cosmological constant */
 | 
|---|
| 116 | /*        hubble       -- Hubble constant, in units of 100 km/s/Mpc */
 | 
|---|
| 117 | /*        redshift     -- The redshift at which to evaluate */
 | 
|---|
| 118 | /* OUTPUT: Returns 0 if all is well, 1 if a warning was issued.  Otherwise,
 | 
|---|
| 119 |         sets many global variables for use in TFmdm_onek_mpc() */
 | 
|---|
| 120 | {
 | 
|---|
| 121 |     double z_drag_b1, z_drag_b2, omega_denom;
 | 
|---|
| 122 |     int qwarn;
 | 
|---|
| 123 |     qwarn = 0;
 | 
|---|
| 124 | 
 | 
|---|
| 125 |     theta_cmb = 2.728/2.7;      /* Assuming T_cmb = 2.728 K */
 | 
|---|
| 126 | 
 | 
|---|
| 127 |     /* Look for strange input */
 | 
|---|
| 128 |     if (omega_baryon<0.0) {
 | 
|---|
| 129 |         fprintf(stderr,
 | 
|---|
| 130 |           "TFmdm_set_cosm(): Negative omega_baryon set to trace amount.\n");
 | 
|---|
| 131 |         qwarn = 1;
 | 
|---|
| 132 |     }
 | 
|---|
| 133 |     if (omega_hdm<0.0) {
 | 
|---|
| 134 |         fprintf(stderr,
 | 
|---|
| 135 |           "TFmdm_set_cosm(): Negative omega_hdm set to trace amount.\n");
 | 
|---|
| 136 |         qwarn = 1;
 | 
|---|
| 137 |     }
 | 
|---|
| 138 |     if (hubble<=0.0) {
 | 
|---|
| 139 |         fprintf(stderr,"TFmdm_set_cosm(): Negative Hubble constant illegal.\n");
 | 
|---|
| 140 |         exit(1);  /* Can't recover */
 | 
|---|
| 141 |     } else if (hubble>2.0) {
 | 
|---|
| 142 |         fprintf(stderr,"TFmdm_set_cosm(): Hubble constant should be in units of 100 km/s/Mpc.\n");
 | 
|---|
| 143 |         qwarn = 1;
 | 
|---|
| 144 |     }
 | 
|---|
| 145 |     if (redshift<=-1.0) {
 | 
|---|
| 146 |         fprintf(stderr,"TFmdm_set_cosm(): Redshift < -1 is illegal.\n");
 | 
|---|
| 147 |         exit(1);
 | 
|---|
| 148 |     } else if (redshift>99.0) {
 | 
|---|
| 149 |         fprintf(stderr,
 | 
|---|
| 150 |           "TFmdm_set_cosm(): Large redshift entered.  TF may be inaccurate.\n");
 | 
|---|
| 151 |         qwarn = 1;
 | 
|---|
| 152 |     }
 | 
|---|
| 153 |     if (degen_hdm<1) degen_hdm=1;
 | 
|---|
| 154 |     num_degen_hdm = (double) degen_hdm; 
 | 
|---|
| 155 |         /* Have to save this for TFmdm_onek_mpc() */
 | 
|---|
| 156 |     /* This routine would crash if baryons or neutrinos were zero, 
 | 
|---|
| 157 |         so don't allow that */
 | 
|---|
| 158 |     if (omega_baryon<=0) omega_baryon=1e-5;
 | 
|---|
| 159 |     if (omega_hdm<=0) omega_hdm=1e-5;
 | 
|---|
| 160 | 
 | 
|---|
| 161 |     omega_curv = 1.0-omega_matter-omega_lambda;
 | 
|---|
| 162 |     omhh = omega_matter*SQR(hubble);
 | 
|---|
| 163 |     obhh = omega_baryon*SQR(hubble);
 | 
|---|
| 164 |     onhh = omega_hdm*SQR(hubble);
 | 
|---|
| 165 |     f_baryon = omega_baryon/omega_matter;
 | 
|---|
| 166 |     f_hdm = omega_hdm/omega_matter;
 | 
|---|
| 167 |     f_cdm = 1.0-f_baryon-f_hdm;
 | 
|---|
| 168 |     f_cb = f_cdm+f_baryon;
 | 
|---|
| 169 |     f_bnu = f_baryon+f_hdm;
 | 
|---|
| 170 | 
 | 
|---|
| 171 |     /* Compute the equality scale. */
 | 
|---|
| 172 |     z_equality = 25000.0*omhh/SQR(SQR(theta_cmb));      /* Actually 1+z_eq */
 | 
|---|
| 173 |     k_equality = 0.0746*omhh/SQR(theta_cmb);
 | 
|---|
| 174 | 
 | 
|---|
| 175 |     /* Compute the drag epoch and sound horizon */
 | 
|---|
| 176 |     z_drag_b1 = 0.313*pow(omhh,-0.419)*(1+0.607*pow(omhh,0.674));
 | 
|---|
| 177 |     z_drag_b2 = 0.238*pow(omhh,0.223);
 | 
|---|
| 178 |     z_drag = 1291*pow(omhh,0.251)/(1.0+0.659*pow(omhh,0.828))*
 | 
|---|
| 179 |                 (1.0+z_drag_b1*pow(obhh,z_drag_b2));
 | 
|---|
| 180 |     y_drag = z_equality/(1.0+z_drag);
 | 
|---|
| 181 | 
 | 
|---|
| 182 |     sound_horizon_fit = 44.5*log(9.83/omhh)/sqrt(1.0+10.0*pow(obhh,0.75));
 | 
|---|
| 183 | 
 | 
|---|
| 184 |     /* Set up for the free-streaming & infall growth function */
 | 
|---|
| 185 |     p_c = 0.25*(5.0-sqrt(1+24.0*f_cdm));
 | 
|---|
| 186 |     p_cb = 0.25*(5.0-sqrt(1+24.0*f_cb));
 | 
|---|
| 187 | 
 | 
|---|
| 188 |     omega_denom = omega_lambda+SQR(1.0+redshift)*(omega_curv+
 | 
|---|
| 189 |                         omega_matter*(1.0+redshift));
 | 
|---|
| 190 |     omega_lambda_z = omega_lambda/omega_denom;
 | 
|---|
| 191 |     omega_matter_z = omega_matter*SQR(1.0+redshift)*(1.0+redshift)/omega_denom;
 | 
|---|
| 192 |     growth_k0 = z_equality/(1.0+redshift)*2.5*omega_matter_z/
 | 
|---|
| 193 |             (pow(omega_matter_z,4.0/7.0)-omega_lambda_z+
 | 
|---|
| 194 |             (1.0+omega_matter_z/2.0)*(1.0+omega_lambda_z/70.0));
 | 
|---|
| 195 |     growth_to_z0 = z_equality*2.5*omega_matter/(pow(omega_matter,4.0/7.0)
 | 
|---|
| 196 |             -omega_lambda + (1.0+omega_matter/2.0)*(1.0+omega_lambda/70.0));
 | 
|---|
| 197 |     growth_to_z0 = growth_k0/growth_to_z0;      
 | 
|---|
| 198 |     
 | 
|---|
| 199 |     /* Compute small-scale suppression */
 | 
|---|
| 200 |     alpha_nu = f_cdm/f_cb*(5.0-2.*(p_c+p_cb))/(5.-4.*p_cb)*
 | 
|---|
| 201 |         pow(1+y_drag,p_cb-p_c)*
 | 
|---|
| 202 |         (1+f_bnu*(-0.553+0.126*f_bnu*f_bnu))/
 | 
|---|
| 203 |         (1-0.193*sqrt(f_hdm*num_degen_hdm)+0.169*f_hdm*pow(num_degen_hdm,0.2))*
 | 
|---|
| 204 |         (1+(p_c-p_cb)/2*(1+1/(3.-4.*p_c)/(7.-4.*p_cb))/(1+y_drag));
 | 
|---|
| 205 |     alpha_gamma = sqrt(alpha_nu);
 | 
|---|
| 206 |     beta_c = 1/(1-0.949*f_bnu);
 | 
|---|
| 207 |     /* Done setting scalar variables */
 | 
|---|
| 208 |     hhubble = hubble;   /* Need to pass Hubble constant to TFmdm_onek_hmpc() */
 | 
|---|
| 209 |     return qwarn;
 | 
|---|
| 210 | }
 | 
|---|
| 211 | 
 | 
|---|
| 212 | /* ---------------------------- TFmdm_onek_mpc() ---------------------- */
 | 
|---|
| 213 | 
 | 
|---|
| 214 | double TFmdm_onek_mpc(double kk)
 | 
|---|
| 215 | /* Given a wavenumber in Mpc^-1, return the transfer function for the
 | 
|---|
| 216 | cosmology held in the global variables. */
 | 
|---|
| 217 | /* Input: kk -- Wavenumber in Mpc^-1 */
 | 
|---|
| 218 | /* Output: The following are set as global variables:
 | 
|---|
| 219 |         growth_cb -- the transfer function for density-weighted
 | 
|---|
| 220 |                         CDM + Baryon perturbations. 
 | 
|---|
| 221 |         growth_cbnu -- the transfer function for density-weighted
 | 
|---|
| 222 |                         CDM + Baryon + Massive Neutrino perturbations. */
 | 
|---|
| 223 | /* The function returns growth_cb */
 | 
|---|
| 224 | {
 | 
|---|
| 225 |     double tf_sup_L, tf_sup_C;
 | 
|---|
| 226 |     double temp1, temp2;
 | 
|---|
| 227 | 
 | 
|---|
| 228 |     qq = kk/omhh*SQR(theta_cmb);
 | 
|---|
| 229 | 
 | 
|---|
| 230 |     /* Compute the scale-dependent growth functions */
 | 
|---|
| 231 |     y_freestream = 17.2*f_hdm*(1+0.488*pow(f_hdm,-7.0/6.0))*
 | 
|---|
| 232 |                 SQR(num_degen_hdm*qq/f_hdm);
 | 
|---|
| 233 |     temp1 = pow(growth_k0, 1.0-p_cb);
 | 
|---|
| 234 |     temp2 = pow(growth_k0/(1+y_freestream),0.7);
 | 
|---|
| 235 |     growth_cb = pow(1.0+temp2, p_cb/0.7)*temp1;
 | 
|---|
| 236 |     growth_cbnu = pow(pow(f_cb,0.7/p_cb)+temp2, p_cb/0.7)*temp1;
 | 
|---|
| 237 | 
 | 
|---|
| 238 |     /* Compute the master function */
 | 
|---|
| 239 |     gamma_eff =omhh*(alpha_gamma+(1-alpha_gamma)/
 | 
|---|
| 240 |                 (1+SQR(SQR(kk*sound_horizon_fit*0.43))));
 | 
|---|
| 241 |     qq_eff = qq*omhh/gamma_eff;
 | 
|---|
| 242 | 
 | 
|---|
| 243 |     tf_sup_L = log(2.71828+1.84*beta_c*alpha_gamma*qq_eff);
 | 
|---|
| 244 |     tf_sup_C = 14.4+325/(1+60.5*pow(qq_eff,1.11));
 | 
|---|
| 245 |     tf_sup = tf_sup_L/(tf_sup_L+tf_sup_C*SQR(qq_eff));
 | 
|---|
| 246 | 
 | 
|---|
| 247 |     qq_nu = 3.92*qq*sqrt(num_degen_hdm/f_hdm);
 | 
|---|
| 248 |     max_fs_correction = 1+1.2*pow(f_hdm,0.64)*pow(num_degen_hdm,0.3+0.6*f_hdm)/
 | 
|---|
| 249 |                 (pow(qq_nu,-1.6)+pow(qq_nu,0.8));
 | 
|---|
| 250 |     tf_master = tf_sup*max_fs_correction;
 | 
|---|
| 251 | 
 | 
|---|
| 252 |     /* Now compute the CDM+HDM+baryon transfer functions */
 | 
|---|
| 253 |     tf_cb = tf_master*growth_cb/growth_k0;
 | 
|---|
| 254 |     tf_cbnu = tf_master*growth_cbnu/growth_k0;
 | 
|---|
| 255 |     return tf_cb;
 | 
|---|
| 256 | }
 | 
|---|
| 257 | 
 | 
|---|
| 258 | /* ---------------------------- TFmdm_onek_hmpc() ---------------------- */
 | 
|---|
| 259 | 
 | 
|---|
| 260 | double TFmdm_onek_hmpc(double kk)
 | 
|---|
| 261 | /* Given a wavenumber in h Mpc^-1, return the transfer function for the
 | 
|---|
| 262 | cosmology held in the global variables. */
 | 
|---|
| 263 | /* Input: kk -- Wavenumber in h Mpc^-1 */
 | 
|---|
| 264 | /* Output: The following are set as global variables:
 | 
|---|
| 265 |         growth_cb -- the transfer function for density-weighted
 | 
|---|
| 266 |                         CDM + Baryon perturbations. 
 | 
|---|
| 267 |         growth_cbnu -- the transfer function for density-weighted
 | 
|---|
| 268 |                         CDM + Baryon + Massive Neutrino perturbations. */
 | 
|---|
| 269 | /* The function returns growth_cb */
 | 
|---|
| 270 | {
 | 
|---|
| 271 |     return TFmdm_onek_mpc(kk*hhubble);
 | 
|---|
| 272 | }
 | 
|---|
| 273 | 
 | 
|---|
| 274 | 
 | 
|---|