Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
ccl_power.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 
5 #include <gsl/gsl_integration.h>
6 #include <gsl/gsl_interp.h>
7 #include <gsl/gsl_spline.h>
8 #include <gsl/gsl_errno.h>
9 
10 #include <class.h> /* from extern/ */
11 
12 #include "ccl.h"
13 #include "ccl_params.h"
14 #include "ccl_emu17.h"
15 #include "ccl_emu17_params.h"
16 
17 
18 /*------ ROUTINE: ccl_cosmology_compute_power_class -----
19 INPUT: ccl_cosmology * cosmo
20 */
22  struct background *ba,
23  struct thermo *th,
24  struct perturbs *pt,
25  struct transfers *tr,
26  struct primordial *pm,
27  struct spectra *sp,
28  struct nonlinear *nl,
29  struct lensing *le,
30  int *init_arr,
31  int * status)
32 {
33  int i_init=6;
34  if(init_arr[i_init--]) {
35  if (spectra_free(sp) == _FAILURE_) {
36  *status = CCL_ERROR_CLASS;
37  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS spectra:%s\n", sp->error_message);
38  return;
39  }
40  }
41 
42  if(init_arr[i_init--]) {
43  if (transfer_free(tr) == _FAILURE_) {
44  *status = CCL_ERROR_CLASS;
45  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS transfer:%s\n", tr->error_message);
46  return;
47  }
48  }
49 
50  if(init_arr[i_init--]) {
51  if (nonlinear_free(nl) == _FAILURE_) {
52  *status = CCL_ERROR_CLASS;
53  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS nonlinear:%s\n", nl->error_message);
54  return;
55  }
56  }
57 
58  if(init_arr[i_init--]) {
59  if (primordial_free(pm) == _FAILURE_) {
60  *status = CCL_ERROR_CLASS;
61  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS pm:%s\n", pm->error_message);
62  return;
63  }
64  }
65 
66  if(init_arr[i_init--]) {
67  if (perturb_free(pt) == _FAILURE_) {
68  *status = CCL_ERROR_CLASS;
69  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS pt:%s\n", pt->error_message);
70  return;
71  }
72  }
73 
74  if(init_arr[i_init--]) {
75  if (thermodynamics_free(th) == _FAILURE_) {
76  *status = CCL_ERROR_CLASS;
77  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS thermo:%s\n", th->error_message);
78  return;
79  }
80  }
81 
82  if(init_arr[i_init--]) {
83  if (background_free(ba) == _FAILURE_) {
84  *status = CCL_ERROR_CLASS;
85  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_free_class_structs(): Error freeing CLASS bg:%s\n", ba->error_message);
86  return;
87  }
88  }
89 
90  return;
91 }
92 
93 static void ccl_class_preinit(struct background *ba,
94  struct thermo *th,
95  struct perturbs *pt,
96  struct transfers *tr,
97  struct primordial *pm,
98  struct spectra *sp,
99  struct nonlinear *nl,
100  struct lensing *le)
101 {
102  //pre-initialize all fields that are freed by *_free() routine
103  //prevents crashes if *_init()failed and did not initialize all tables freed by *_free()
104 
105  //init for background_free
106  ba->tau_table = NULL;
107  ba->z_table = NULL;
108  ba->d2tau_dz2_table = NULL;
109  ba->background_table = NULL;
110  ba->d2background_dtau2_table = NULL;
111 
112  //init for thermodynamics_free
113  th->z_table = NULL;
114  th->thermodynamics_table = NULL;
115  th->d2thermodynamics_dz2_table = NULL;
116 
117  //init for perturb_free
118  pt->tau_sampling = NULL;
119  pt->tp_size = NULL;
120  pt->ic_size = NULL;
121  pt->k = NULL;
122  pt->k_size_cmb = NULL;
123  pt->k_size_cl = NULL;
124  pt->k_size = NULL;
125  pt->sources = NULL;
126 
127  //init for primordial_free
128  pm->amplitude = NULL;
129  pm->tilt = NULL;
130  pm->running = NULL;
131  pm->lnpk = NULL;
132  pm->ddlnpk = NULL;
133  pm->is_non_zero = NULL;
134  pm->ic_size = NULL;
135  pm->ic_ic_size = NULL;
136  pm->lnk = NULL;
137 
138  //init for nonlinear_free
139  nl->k = NULL;
140  nl->tau = NULL;
141  nl->nl_corr_density = NULL;
142  nl->k_nl = NULL;
143 
144  //init for transfer_free
145  tr->tt_size = NULL;
146  tr->l_size_tt = NULL;
147  tr->l_size = NULL;
148  tr->l = NULL;
149  tr->q = NULL;
150  tr->k = NULL;
151  tr->transfer = NULL;
152 
153  //init for spectra_free
154  //spectra_free checks all other data fields before freeing
155  sp->is_non_zero = NULL;
156  sp->ic_size = NULL;
157  sp->ic_ic_size = NULL;
158 }
159 
161  struct file_content *fc,
162  struct precision* pr,
163  struct background* ba,
164  struct thermo* th,
165  struct perturbs* pt,
166  struct transfers* tr,
167  struct primordial* pm,
168  struct spectra* sp,
169  struct nonlinear* nl,
170  struct lensing* le,
171  struct output* op,
172  int *init_arr,
173  int * status)
174 {
175  ErrorMsg errmsg; // for error messages
176  int i_init=0;
177  ccl_class_preinit(ba,th,pt,tr,pm,sp,nl,le);
178 
179  if(input_init(fc,pr,ba,th,pt,tr,pm,sp,nl,le,op,errmsg) == _FAILURE_) {
180  *status = CCL_ERROR_CLASS;
181  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS input:%s\n", errmsg);
182  return;
183  }
184  if (background_init(pr,ba) == _FAILURE_) {
185  *status = CCL_ERROR_CLASS;
186  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS background:%s\n", ba->error_message);
187  return;
188  }
189  init_arr[i_init++]=1;
190  if (thermodynamics_init(pr,ba,th) == _FAILURE_) {
191  *status = CCL_ERROR_CLASS;
192  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS thermodynamics:%s\n", th->error_message);
193  return;
194  }
195  init_arr[i_init++]=1;
196  if (perturb_init(pr,ba,th,pt) == _FAILURE_) {
197  *status = CCL_ERROR_CLASS;
198  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS pertubations:%s\n", pt->error_message);
199  return;
200  }
201  init_arr[i_init++]=1;
202  if (primordial_init(pr,pt,pm) == _FAILURE_) {
203  *status = CCL_ERROR_CLASS;
204  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS primordial:%s\n", pm->error_message);
205  return;
206  }
207  init_arr[i_init++]=1;
208  if (nonlinear_init(pr,ba,th,pt,pm,nl) == _FAILURE_) {
209  *status = CCL_ERROR_CLASS;
210  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS nonlinear:%s\n", nl->error_message);
211  return;
212  }
213  init_arr[i_init++]=1;
214  if (transfer_init(pr,ba,th,pt,nl,tr) == _FAILURE_) {
215  *status = CCL_ERROR_CLASS;
216  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS transfer:%s\n", tr->error_message);
217  return;
218  }
219  init_arr[i_init++]=1;
220  if (spectra_init(pr,ba,pt,pm,nl,tr,sp) == _FAILURE_) {
221  *status = CCL_ERROR_CLASS;
222  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error running CLASS spectra:%s\n", sp->error_message);
223  return;
224  }
225  init_arr[i_init++]=1;
226 }
227 
228 static double ccl_get_class_As(ccl_cosmology *cosmo, struct file_content *fc, int position_As,
229  double sigma8, int * status)
230 {
231  //structures for class test run
232  struct precision pr; // for precision parameters
233  struct background ba; // for cosmological background
234  struct thermo th; // for thermodynamics
235  struct perturbs pt; // for source functions
236  struct transfers tr; // for transfer functions
237  struct primordial pm; // for primordial spectra
238  struct spectra sp; // for output spectra
239  struct nonlinear nl; // for non-linear spectra
240  struct lensing le;
241  struct output op;
242 
243  //temporarily overwrite P_k_max_1/Mpc to speed up sigma8 calculation
244  double k_max_old = 0.;
245  int position_kmax =2;
246  double A_s_guess;
247  int init_arr[7]={0,0,0,0,0,0,0};
248 
249  if (strcmp(fc->name[position_kmax],"P_k_max_1/Mpc")) {
250  k_max_old = strtof(fc->value[position_kmax],NULL);
251  sprintf(fc->value[position_kmax],"%.15e",10.);
252  }
253  A_s_guess = 2.43e-9/0.87659*sigma8;
254  sprintf(fc->value[position_As],"%.15e",A_s_guess);
255 
256  ccl_run_class(cosmo, fc,&pr,&ba,&th,&pt,&tr,&pm,&sp,&nl,&le,&op,init_arr,status);
257  if (cosmo->status != CCL_ERROR_CLASS) A_s_guess*=pow(sigma8/sp.sigma8,2.);
258  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
259 
260  if (k_max_old >0) {
261  sprintf(fc->value[position_kmax],"%.15e",k_max_old);
262  }
263  return A_s_guess;
264 }
265 
266 static void ccl_fill_class_parameters(ccl_cosmology * cosmo, struct file_content * fc,
267  int parser_length, int * status)
268 
269 {
270 
271  // initialize fc fields
272  //silences Valgrind's "Conditional jump or move depends on uninitialised value" warning
273  for (int i = 0; i< parser_length; i++){
274  strcpy(fc->name[i]," ");
275  strcpy(fc->value[i]," ");
276  }
277 
278  strcpy(fc->name[0],"output");
279  strcpy(fc->value[0],"mPk");
280 
281  strcpy(fc->name[1],"non linear");
283  strcpy(fc->value[1],"Halofit");
284  else
285  strcpy(fc->value[1],"none");
286 
287  strcpy(fc->name[2],"P_k_max_1/Mpc");
288  sprintf(fc->value[2],"%.15e",ccl_splines->K_MAX_SPLINE); //in units of 1/Mpc, corroborated with ccl_constants.h
289 
290  strcpy(fc->name[3],"z_max_pk");
291  sprintf(fc->value[3],"%.15e",1./ccl_splines->A_SPLINE_MINLOG_PK-1.);
292 
293  strcpy(fc->name[4],"modes");
294  strcpy(fc->value[4],"s");
295 
296  strcpy(fc->name[5],"lensing");
297  strcpy(fc->value[5],"no");
298 
299  // now, copy over cosmology parameters
300  strcpy(fc->name[6],"h");
301  sprintf(fc->value[6],"%.15e",cosmo->params.h);
302 
303  strcpy(fc->name[7],"Omega_cdm");
304  sprintf(fc->value[7],"%.15e",cosmo->params.Omega_c);
305 
306  strcpy(fc->name[8],"Omega_b");
307  sprintf(fc->value[8],"%.15e",cosmo->params.Omega_b);
308 
309  strcpy(fc->name[9],"Omega_k");
310  sprintf(fc->value[9],"%.15e",cosmo->params.Omega_k);
311 
312  strcpy(fc->name[10],"n_s");
313  sprintf(fc->value[10],"%.15e",cosmo->params.n_s);
314 
315 
316  //cosmological constant?
317  // set Omega_Lambda = 0.0 if w !=-1
318  if ((cosmo->params.w0 !=-1.0) || (cosmo->params.wa !=0)) {
319  strcpy(fc->name[11],"Omega_Lambda");
320  sprintf(fc->value[11],"%.15e",0.0);
321 
322  strcpy(fc->name[12],"w0_fld");
323  sprintf(fc->value[12],"%.15e",cosmo->params.w0);
324 
325  strcpy(fc->name[13],"wa_fld");
326  sprintf(fc->value[13],"%.15e",cosmo->params.wa);
327  }
328  //neutrino parameters
329  //massless neutrinos
330  if (cosmo->params.N_nu_rel > 1.e-4) {
331  strcpy(fc->name[14],"N_ur");
332  sprintf(fc->value[14],"%.15e",cosmo->params.N_nu_rel);
333  }
334  else {
335  strcpy(fc->name[14],"N_ur");
336  sprintf(fc->value[14],"%.15e", 0.);
337  }
338  if (cosmo->params.N_nu_mass > 0) {
339  strcpy(fc->name[15],"N_ncdm");
340  sprintf(fc->value[15],"%d",cosmo->params.N_nu_mass);
341  strcpy(fc->name[16],"m_ncdm");
342  sprintf(fc->value[16],"%f", (cosmo->params.mnu)[0]);
343  if (cosmo->params.N_nu_mass >=1){
344  for (int i = 1; i < cosmo->params.N_nu_mass; i++) {
345  char tmp[20];
346  sprintf(tmp,", %f",(cosmo->params.mnu)[i]);
347  strcat(fc->value[16],tmp);
348  }
349  }
350 
351  }
352 
353  strcpy(fc->name[17],"T_cmb");
354  sprintf(fc->value[17],"%.15e",cosmo->params.T_CMB);
355 
356  //normalization comes last, so that all other parameters are filled in for determining A_s if sigma8 is specified
357  if (isfinite(cosmo->params.sigma8) && isfinite(cosmo->params.A_s)){
358  *status = CCL_ERROR_INCONSISTENT;
359  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: class_parameters(): Error initializing CLASS parameters: both sigma8 and A_s defined\n");
360  return;
361  }
362  if (isfinite(cosmo->params.sigma8)) {
363  strcpy(fc->name[parser_length-1],"A_s");
364  sprintf(fc->value[parser_length-1],"%.15e",ccl_get_class_As(cosmo,fc,parser_length-1,cosmo->params.sigma8, status));
365  }
366  else if (isfinite(cosmo->params.A_s)) {
367  strcpy(fc->name[parser_length-1],"A_s");
368  sprintf(fc->value[parser_length-1],"%.15e",cosmo->params.A_s);
369  }
370  else {
371  *status = CCL_ERROR_INCONSISTENT;
372  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: class_parameters(): Error initializing CLASS pararmeters: neither sigma8 nor A_s defined\n");
373  return;
374  }
375 
376 }
377 
379 {
380  struct precision pr; // for precision parameters
381  struct background ba; // for cosmological background
382  struct thermo th; // for thermodynamics
383  struct perturbs pt; // for source functions
384  struct transfers tr; // for transfer functions
385  struct primordial pm; // for primordial spectra
386  struct spectra sp; // for output spectra
387  struct nonlinear nl; // for non-linear spectra
388  struct lensing le;
389  struct output op;
390  struct file_content fc;
391 
392  ErrorMsg errmsg; // for error messages
393  // generate file_content structure
394  // CLASS configuration parameters will be passed through this structure,
395  // to avoid writing and reading .ini files for every call
396  int parser_length = 20;
397  int init_arr[7]={0,0,0,0,0,0,0};
398  if (parser_init(&fc,parser_length,"none",errmsg) == _FAILURE_) {
399  *status = CCL_ERROR_CLASS;
400  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): parser init error:%s\n", errmsg);
401  return;
402  }
403 
404  ccl_fill_class_parameters(cosmo,&fc,parser_length, status);
405 
406  if (*status != CCL_ERROR_CLASS)
407  ccl_run_class(cosmo, &fc,&pr,&ba,&th,&pt,&tr,&pm,&sp,&nl,&le,&op,init_arr,status);
408 
409  if (*status == CCL_ERROR_CLASS) {
410  //printed error message while running CLASS
411  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
412  return;
413  }
414 
415  if (parser_free(&fc)== _FAILURE_) {
416  *status = CCL_ERROR_CLASS;
417  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error freeing CLASS parser\n");
418  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
419  return;
420  }
421 
422  //These are the limits of the splining range
423  cosmo->data.k_min_lin=2*exp(sp.ln_k[0]);
425 
426  //CLASS calculations done - now allocate CCL splines
427  double kmin = cosmo->data.k_min_lin;
428  double kmax = ccl_splines->K_MAX_SPLINE;
429  //Compute nk from number of decades and N_K = # k per decade
430  double ndecades = log10(kmax) - log10(kmin);
431  int nk = (int)ceil(ndecades*ccl_splines->N_K);
432  double amin = ccl_splines->A_SPLINE_MINLOG_PK;
433  double amax = ccl_splines->A_SPLINE_MAX;
435 
436  // The x array is initially k, but will later
437  // be overwritten with log(k)
438  double * x = ccl_log_spacing(kmin, kmax, nk);
440  double * y2d_lin = malloc(nk * na * sizeof(double));
441  double * y2d_nl = malloc(nk * na * sizeof(double));
442 
443 
444  //If error, store status, we will free later
445  if (a==NULL|| x==NULL || y2d_lin==NULL || y2d_nl==NULL) {
446  *status = CCL_ERROR_SPLINE;
447  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): memory allocation error\n");
448  }
449 
450  //Status flags
451  int newstatus=0;
452  int pwstatus=0;
453 
454  //If not, proceed
455  if(!*status){
456 
457  // After this loop x will contain log(k)
458  // all in Mpc, not Mpc/h units!
459  double psout_l,ic;
460  for (int i=0; i<nk; i++) {
461  for (int j = 0; j < na; j++) {
462  //The 2D interpolation routines access the function values y_{k_ia_j} with the following ordering:
463  //y_ij = y2d[j*N_k + i]
464  //with i = 0,...,N_k-1 and j = 0,...,N_a-1.
465  newstatus |= spectra_pk_at_k_and_z(&ba, &pm, &sp,x[i],1./a[j]-1., &psout_l,&ic);
466  y2d_lin[j*nk+i] = log(psout_l);
467  }
468  x[i] = log(x[i]);
469  }
470 
471 
472  //If error, store status, we will free later
473  if(newstatus) {
474  *status = CCL_ERROR_CLASS;
475  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error computing CLASS power spectrum\n");
476  }
477 
478 
479  }
480 
481 
482  //If no error, proceed
483  if(!*status) {
484 
485  gsl_spline2d * log_power = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, nk,na);
486  pwstatus = gsl_spline2d_init(log_power, x, a, y2d_lin,nk,na);
487 
488  //If not, proceed
489  if(!pwstatus){
490  cosmo->data.p_lin = log_power;
491  } else {
492  gsl_spline2d_free(log_power);
493  *status = CCL_ERROR_SPLINE;
494  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error creating log_power spline\n");
495  }
496 
497  }
498 
499  if(*status){ //Linear power spec failed, so we return without proceeding to nonlinear.
500  free(x);
501  free(a);
502  free(y2d_nl);
503  free(y2d_lin);
504  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
505  return;
506  }
507 
508  //Non-linear power
509  //At the moment KMIN can't be less than CLASS's kmin in the nonlinear case.
510 
511  //If error, store status, we will free later
512  if (kmin<(exp(sp.ln_k[0]))) {
513  *status = CCL_ERROR_CLASS;
514  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): K_MIN is less than CLASS's kmin. Not yet supported for nonlinear P(k).\n");
515  }
516 
517  //If not, proceed
518  if(!*status){
519 
520  //These are the limits of the splining range
521  cosmo->data.k_min_nl=2*exp(sp.ln_k[0]);
523 
525 
526  double psout_nl;
527  for (int i=0; i<nk; i++) {
528  for (int j = 0; j < na; j++) {
529  newstatus |= spectra_pk_nl_at_k_and_z(&ba, &pm, &sp,exp(x[i]),1./a[j]-1.,&psout_nl);
530  y2d_nl[j*nk+i] = log(psout_nl);
531  }
532  }
533  }
534 
535  if(newstatus){
536  *status = CCL_ERROR_CLASS;
537  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error computing CLASS power spectrum\n");
538  }
539 
540  }
541 
542  if(!*status){
543 
544  gsl_spline2d * log_power_nl = gsl_spline2d_alloc(PNL_SPLINE_TYPE, nk,na);
545  pwstatus = gsl_spline2d_init(log_power_nl, x, a, y2d_nl,nk,na);
546 
547  if(!pwstatus){
548  cosmo->data.p_nl = log_power_nl;
549  } else {
550  gsl_spline2d_free(log_power_nl);
551  *status = CCL_ERROR_SPLINE;
552  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error creating log_power_nl spline\n");
553  }
554 
555  }
556 
557  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
558  free(x);
559  free(a);
560  free(y2d_nl);
561  free(y2d_lin);
562 
563  return;
564 
565 }
566 
567 /* BCM correction
568  See Schneider & Teyssier (2015) for details of the model.
569  The equations inside this function correspond to those in that
570  work for:
571  gf -> G(k)
572  scomp -> S(k)
573 */
574 double ccl_bcm_model_fka(ccl_cosmology * cosmo, double k, double a, int *status){
575 
576  double fka;
577  double b0;
578  double bfunc, bfunc4;
579  double kg;
580  double gf,scomp;
581  double kh;
582  double z;
583 
584  z=1./a-1.;
585  kh = k/cosmo->params.h; //convert to h/Mpc
586  b0 = 0.105*cosmo->params.bcm_log10Mc-1.27; //Eq. 4.4
587  bfunc = b0/(1.+pow(z/2.3,2.5)); //Eq. 4.3
588  bfunc4 = (1-bfunc)*(1-bfunc)*(1-bfunc)*(1-bfunc); //B^4(z)
589  kg = 0.7*bfunc4*pow(cosmo->params.bcm_etab,-1.6); //Eq. 4.3
590  gf = bfunc/(1+pow(kh/kg,3.))+1.-bfunc; //Eq. 4.2, k in h/Mpc
591  scomp = 1+(kh/cosmo->params.bcm_ks)*(kh/cosmo->params.bcm_ks); //Eq 4.5, k in h/Mpc
592  fka = gf*scomp;
593  return fka;
594 }
595 
596 void ccl_cosmology_write_power_class_z(char *filename, ccl_cosmology * cosmo, double z, int * status)
597 {
598  struct precision pr; // for precision parameters
599  struct background ba; // for cosmological background
600  struct thermo th; // for thermodynamics
601  struct perturbs pt; // for source functions
602  struct transfers tr; // for transfer functions
603  struct primordial pm; // for primordial spectra
604  struct spectra sp; // for output spectra
605  struct nonlinear nl; // for non-linear spectra
606  struct lensing le;
607  struct output op;
608  struct file_content fc;
609 
610  ErrorMsg errmsg; // for error messages
611  // generate file_content structure
612  // CLASS configuration parameters will be passed through this structure,
613  // to avoid writing and reading .ini files for every call
614  int parser_length = 20;
615  int init_arr[7]={0,0,0,0,0,0,0};
616  if (parser_init(&fc,parser_length,"none",errmsg) == _FAILURE_) {
617  *status = CCL_ERROR_CLASS;
618  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: write_power_class_z(): parser init error:%s\n", errmsg);
619  return;
620  }
621 
622  ccl_fill_class_parameters(cosmo,&fc,parser_length, status);
623 
624  if (*status != CCL_ERROR_CLASS)
625  ccl_run_class(cosmo, &fc,&pr,&ba,&th,&pt,&tr,&pm,&sp,&nl,&le,&op,init_arr,status);
626 
627  if (*status == CCL_ERROR_CLASS) {
628  //printed error message while running CLASS
629  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
630  return;
631  }
632  if (parser_free(&fc)== _FAILURE_) {
633  *status = CCL_ERROR_CLASS;
634  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: write_power_class_z(): Error freeing CLASS parser\n");
635  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
636  return;
637  }
638  FILE *f;
639  f = fopen(filename,"w");
640  if (!f){
641  *status = CCL_ERROR_CLASS;
642  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: write_power_class_z(): Error opening output file\n");
643  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
644  fclose(f);
645  return;
646  }
647  double psout_l,ic;
648  int s=0;
649  for (int i=0; i<sp.ln_k_size; i++) {
650  s |= spectra_pk_at_k_and_z(&ba, &pm, &sp,exp(sp.ln_k[i]),z, &psout_l,&ic);
651  fprintf(f,"%e %e\n",exp(sp.ln_k[i]),psout_l);
652  }
653  fclose(f);
654  if(s) {
655  *status = CCL_ERROR_CLASS;
656  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: write_power_class_z(): Error writing CLASS power spectrum\n");
657  }
658 
659  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
660 }
661 
662 
663 typedef struct {
664  double rsound;
665  double zeq;
666  double keq;
667  double zdrag;
668  double kSilk;
670  double th2p7;
671  double alphac;
672  double alphab;
673  double betac;
674  double betab;
675  double bnode;
676 } eh_struct;
677 
679 {
681  // Computes Eisenstein & Hu parameters for
682  // P_k and r_sound
683  // see astro-ph/9709112 for the relevant equations
684  double OMh2,OBh2;
685  double th2p7;
686  eh_struct *eh=malloc(sizeof(eh_struct));
687  if(eh==NULL)
688  return NULL;
689 
690  OMh2=params->Omega_m*params->h*params->h; //Cosmo params scaled by h^2
691  OBh2=params->Omega_b*params->h*params->h;
692  th2p7=params->T_CMB/2.7; //This is Theta_{2.7} in E&Hu notation
693  eh->th2p7=th2p7; //This is Theta_{2.7} in E&Hu notation
694  eh->zeq=2.5E4*OMh2/pow(th2p7,4);// Eq 2
695  eh->keq=0.0746*OMh2/(params->h*th2p7*th2p7);//Eq. 3
696 
697  //These group corresponds to Eq. 4
698  double b1,b2;
699  b1=0.313*pow(OMh2,-0.419)*(1+0.607*pow(OMh2,0.674));
700  b2=0.238*pow(OMh2,0.223);
701  eh->zdrag=1291*pow(OMh2,0.251)*(1+b1*pow(OBh2,b2))/(1+0.659*pow(OMh2,0.828));
702 
703  //These are the baryon-to-photon ratios
704  //at equality (Req) and drag (Rd) epochs
705  //Eq. 5
706  double Req,Rd;
707  Req=31.5*OBh2*1000./(eh->zeq*pow(th2p7,4));
708  Rd=31.5*OBh2*1000./((1+eh->zdrag)*pow(th2p7,4));
709  eh->rsound=2/(3*eh->keq)*sqrt(6/Req)*
710  log((sqrt(1+Rd)+sqrt(Rd+Req))/(1+sqrt(Req)));
711 
712  //This is Eq. 7 (but in h/Mpc)
713  eh->kSilk=1.6*pow(OBh2,0.52)*pow(OMh2,0.73)*(1+pow(10.4*OMh2,-0.95))/params->h;
714 
715  //These are Eqs. 11
716  double a1,a2,b_frac;
717  a1=pow(46.9*OMh2,0.670)*(1+pow(32.1*OMh2,-0.532));
718  a2=pow(12.0*OMh2,0.424)*(1+pow(45.0*OMh2,-0.582));
719  b_frac=OBh2/OMh2;
720  eh->alphac=pow(a1,-b_frac)*pow(a2,-b_frac*b_frac*b_frac);
721 
722  //These are Eqs. 12
723  double bb1,bb2;
724  bb1=0.944/(1+pow(458*OMh2,-0.708));
725  bb2=pow(0.395*OMh2,-0.0266);
726  eh->betac=1/(1+bb1*(pow(1-b_frac,bb2)-1));
727 
728  double y=eh->zeq/(1+eh->zdrag);
729  double sqy=sqrt(1+y);
730  double gy=y*(-6*sqy+(2+3*y)*log((sqy+1)/(sqy-1))); //Eq 15
731  //Baryon suppression Eq. 14
732  eh->alphab=2.07*eh->keq*eh->rsound*pow(1+Rd,-0.75)*gy;
733 
734  //Baryon envelope shift Eq. 24
735  eh->betab=0.5+b_frac+(3-2*b_frac)*sqrt(pow(17.2*OMh2,2)+1);
736 
737  //Node shift parameter Eq. 23
738  eh->bnode=8.41*pow(OMh2,0.435);
739 
740  //Approx for the sound horizon, Eq. 26
741  eh->rsound_approx=params->h*44.5*log(9.83/OMh2)/
742  sqrt(1+10*pow(OBh2,0.75));
743 
744  return eh;
745 }
746 
747 static double tkEH_0(double keq,double k,double a,double b)
748 {
750  // Eisentstein & Hu's Tk_0
751  // see astro-ph/9709112 for the relevant equations
752  double q=k/(13.41*keq); //Eq 10
753  double c=14.2/a+386./(1+69.9*pow(q,1.08)); //Eq 20
754  double l=log(M_E+1.8*b*q); //Change of var for Eq 19
755  return l/(l+c*q*q); //Returns Eq 19
756 }
757 
758 static double tkEH_c(eh_struct *eh,double k)
759 {
761  // Eisenstein & Hu's Tk_c
762  // see astro-ph/9709112 for the relevant equations
763  double f=1/(1+pow(k*eh->rsound/5.4,4)); //Eq 18
764  return f*tkEH_0(eh->keq,k,1,eh->betac)+
765  (1-f)*tkEH_0(eh->keq,k,eh->alphac,eh->betac); //Returns Eq 17
766 }
767 
768 static double jbes0(double x)
769 {
770  double jl;
771  double ax2=x*x;
772 
773  if(ax2<1e-4) jl=1-ax2*(1-ax2/20.)/6.;
774  else jl=sin(x)/x;
775 
776  return jl;
777 }
778 
779 static double tkEH_b(eh_struct *eh,double k)
780 {
782  // Eisenstein & Hu's Tk_b (Eq 21)
783  // see astro-ph/9709112 for the relevant equations
784  double x_bessel,part1,part2,jbes;
785  double x=k*eh->rsound;
786 
787  //First term of Eq. 21
788  if(k==0) x_bessel=0;
789  else {
790  x_bessel=x*pow(1+eh->bnode*eh->bnode*eh->bnode/(x*x*x),-1./3.);
791  }
792 
793  part1=tkEH_0(eh->keq,k,1,1)/(1+pow(x/5.2,2));
794 
795  //Second term of Eq. 21
796  if(k==0)
797  part2=0;
798  else
799  part2=eh->alphab/(1+pow(eh->betab/x,3))*exp(-pow(k/eh->kSilk,1.4));
800 
801  return jbes0(x_bessel)*(part1+part2);
802 }
803 
804 static double tsqr_EH(ccl_parameters *params,eh_struct * eh,double k,int wiggled)
805 {
807  // Eisenstein & Hu's Tk_c
808  // see astro-ph/9709112 for the relevant equations
809  // Notice the last parameter in eh_power controls
810  // whether to introduce wiggles (BAO) in the power spectrum.
811  // We do this by default when obtaining the power spectrum.
812  double tk;
813  double b_frac=params->Omega_b/params->Omega_m;
814  if(wiggled)
815  //Case with baryons (Eq 8)
816  tk=b_frac*tkEH_b(eh,k)+(1-b_frac)*tkEH_c(eh,k);
817  else {
818  //Zero baryon case (sec 4.2)
819  double OMh2=params->Omega_m*params->h*params->h;
820  // Compute Eq. 31
821  double alpha_gamma=1-0.328*log(431*OMh2)*b_frac+0.38*log(22.3*OMh2)*b_frac*b_frac;
822  // Compute Eq. 30
823  double gamma_eff=params->Omega_m*params->h*(alpha_gamma+(1-alpha_gamma)/
824  (1+pow(0.43*k*eh->rsound_approx,4)));
825  // Compute Eq. 28 (assume k in h/Mpc)
826  double q=k*eh->th2p7*eh->th2p7/gamma_eff;
827  // Compute Eqs. 29
828  double l0=log(2*M_E+1.8*q);
829  double c0=14.2+731/(1+62.5*q);
830  tk=l0/(l0+c0*q*q); //T_0 of Eq. 29
831  }
832 
833  return tk*tk; //Return T_0^2
834 }
835 
836 static double eh_power(ccl_parameters *params,eh_struct *eh,double k,int wiggled)
837 {
838  //Wavenumber in units of Mpc^-1
839  double kinvh=k/params->h; //Changed to h/Mpc
840  return pow(k,params->n_s)*tsqr_EH(params,eh,kinvh,wiggled);
841 }
843 {
844  //These are the limits of the splining range
845  cosmo->data.k_min_lin = ccl_splines->K_MIN;
846  cosmo->data.k_min_nl = ccl_splines->K_MIN;
847  cosmo->data.k_max_lin = ccl_splines->K_MAX;
848  cosmo->data.k_max_nl = ccl_splines->K_MAX;
849  double kmin = cosmo->data.k_min_lin;
850  double kmax = ccl_splines->K_MAX;
851 
852  // Compute nk from number of decades and N_K = # k per decade
853  double ndecades = log10(kmax) - log10(kmin);
854  int nk = (int)ceil(ndecades*ccl_splines->N_K);
855 
856  // Compute na using predefined spline spacing
857  double amin = ccl_splines->A_SPLINE_MINLOG_PK;
858  double amax = ccl_splines->A_SPLINE_MAX;
860 
861  // Exit if sigma8 wasn't specified
862  if (isnan(cosmo->params.sigma8)) {
863  *status = CCL_ERROR_INCONSISTENT;
864  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): sigma8 was not set, but is required for E&H method\n");
865  return;
866  }
867 
868  // New struct for EH parameters
869  eh_struct *eh = eh_struct_new(&(cosmo->params));
870  if (eh == NULL) {
871  *status = CCL_ERROR_MEMORY;
872  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): memory allocation error\n");
873  return;
874  }
875 
876  // Build grids in k and a that P(k, a) will be evaluated on
877  // NB: The x array is initially k, but will later be overwritten with log(k)
878  double * x = ccl_log_spacing(kmin, kmax, nk);
879  double * y = malloc(sizeof(double)*nk);
880  double * a = ccl_linlog_spacing(amin, ccl_splines->A_SPLINE_MIN_PK,
883  double * y2d = malloc(nk * na * sizeof(double));
884  if (a==NULL || y==NULL || x==NULL || y2d==NULL) {
885  free(eh);free(x);free(y);
886  free(a);free(y2d);
887  *status = CCL_ERROR_MEMORY;
888  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): memory allocation error\n");
889  return;
890  }
891 
892  // Calculate P(k) on k grid. After this loop, x will contain log(k) and y
893  // will contain log(pk) [which has not yet been normalized]
894  // Notice the last parameter in eh_power controls
895  // whether to introduce wiggles (BAO) in the power spectrum.
896  // We do this by default.
897  for (int i=0; i<nk; i++) {
898  y[i] = log(eh_power(&cosmo->params, eh, x[i], 1));
899  x[i] = log(x[i]);
900  }
901 
902  // Apply growth factor, D(a), to P(k) and store in 2D (k, a) array
903  double gfac, g2;
904  gsl_spline2d *log_power_lin = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, nk,na);
905  for (int j = 0; j < na; j++) {
906  gfac = ccl_growth_factor(cosmo, a[j], status);
907  g2 = 2.*log(gfac);
908  for (int i=0; i<nk; i++) {
909  y2d[j*nk+i] = y[i]+g2;
910  } // end loop over k
911  } // end loop over a
912 
913  // Check that ccl_growth_factor didn't fail
914  if (*status) {
915  free(eh); free(x); free(y); free(a); free(y2d);
916  gsl_spline2d_free(log_power_lin);
917  return;
918  }
919 
920  // Initialize a 2D spline over P(k, a) [which is still unnormalized by sigma8]
921  int splinstatus = gsl_spline2d_init(log_power_lin, x, a, y2d,nk,na);
922  if (splinstatus) {
923  free(eh); free(x); free(y); free(a); free(y2d);
924  gsl_spline2d_free(log_power_lin);
925  *status = CCL_ERROR_SPLINE;
926  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): Error creating log_power_lin spline\n");
927  return;
928  }
929 
930  // Calculate sigma8 for the unnormalized P(k), using the standard
931  // ccl_sigma8() function
932  cosmo->data.p_lin = log_power_lin;
933  cosmo->computed_power = true; // Temporarily set this to true
934  double sigma8 = ccl_sigma8(cosmo, status);
935  cosmo->computed_power = false;
936 
937  // Check that ccl_sigma8 didn't fail
938  if (*status) {
939  free(eh); free(x); free(y); free(a); free(y2d);
940  gsl_spline2d_free(log_power_lin);
941  return;
942  }
943 
944  // Calculate normalization factor using computed value of sigma8, then
945  // recompute P(k, a) using this normalization
946  double log_normalization_factor = 2*(log(cosmo->params.sigma8) - log(sigma8));
947  for (int i=0; i < nk; i++) {
948  y[i] += log_normalization_factor;
949  }
950  for (int j = 0; j < na; j++) {
951  gfac = ccl_growth_factor(cosmo, a[j], status);
952  g2 = 2.*log(gfac);
953  for (int i=0; i<nk; i++) {
954  y2d[j*nk+i] = y[i]+g2; // Replace previous values
955  } // end k loop
956  } // end a loop
957 
958  splinstatus = gsl_spline2d_init(log_power_lin, x, a, y2d, nk, na);
959  if (splinstatus) {
960  free(eh); free(x); free(y); free(a); free(y2d);
961  gsl_spline2d_free(log_power_lin);
962  *status = CCL_ERROR_SPLINE;
963  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): Error creating log_power_lin spline\n");
964  return;
965  }
966  else
967  cosmo->data.p_lin = log_power_lin;
968 
969  // Allocate a 2D spline for the nonlinear P(k) [which is just a copy of the
970  // linear one for E&H]
971  gsl_spline2d * log_power_nl = gsl_spline2d_alloc(PNL_SPLINE_TYPE, nk, na);
972  splinstatus = gsl_spline2d_init(log_power_nl, x, a, y2d, nk, na);
973 
974  if (splinstatus) {
975  free(eh); free(x); free(y); free(a); free(y2d);
976  gsl_spline2d_free(log_power_lin);
977  gsl_spline2d_free(log_power_nl);
978  *status = CCL_ERROR_SPLINE;
979  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_eh(): Error creating log_power_nl spline\n");
980  return;
981  }
982  else
983  cosmo->data.p_nl = log_power_nl;
984 
985  // Free temporary arrays
986  free(eh); free(x); free(y); free(a); free(y2d);
987 }
988 
989 /*------ ROUTINE: tsqr_BBKS -----
990 INPUT: ccl_parameters and k wavenumber in 1/Mpc
991 TASK: provide the square of the BBKS transfer function with baryonic correction
992 NOTE: Bardeen et al. (1986) as implemented in Sugiyama (1995)
993 */
994 
995 static double tsqr_BBKS(ccl_parameters * params, double k)
996 {
997  double q = k/(params->Omega_m*params->h*params->h*exp(-params->Omega_b*(1.0+pow(2.*params->h,.5)/params->Omega_m)));
998  return pow(log(1.+2.34*q)/(2.34*q),2.0)/pow(1.+3.89*q+pow(16.1*q,2.0)+pow(5.46*q,3.0)+pow(6.71*q,4.0),0.5);
999 }
1000 
1001 /*------ ROUTINE: bbks_power -----
1002 INPUT: ccl_parameters and k wavenumber in 1/Mpc
1003 TASK: provide the BBKS power spectrum with baryonic correction at single k
1004 */
1005 
1006 //Calculate Normalization see Cosmology Notes 8.105 (TODO: whose comment is this?)
1007 static double bbks_power(ccl_parameters * params, double k)
1008 {
1009  return pow(k,params->n_s)*tsqr_BBKS(params, k);
1010 }
1011 
1012 /*------ ROUTINE: ccl_cosmology_compute_bbks_power -----
1013 INPUT: cosmology
1014 TASK: provide spline for the BBKS power spectrum with baryonic correction
1015 */
1016 
1018 {
1019  //These are the limits of the splining range
1020  cosmo->data.k_min_lin=ccl_splines->K_MIN;
1021  cosmo->data.k_min_nl=ccl_splines->K_MIN;
1022  cosmo->data.k_max_lin=ccl_splines->K_MAX;
1023  cosmo->data.k_max_nl=ccl_splines->K_MAX;
1024  double kmin = cosmo->data.k_min_lin;
1025  double kmax = ccl_splines->K_MAX;
1026  //Compute nk from number of decades and N_K = # k per decade
1027  double ndecades = log10(kmax) - log10(kmin);
1028  int nk = (int)ceil(ndecades*ccl_splines->N_K);
1029  double amin = ccl_splines->A_SPLINE_MINLOG_PK;
1030  double amax = ccl_splines->A_SPLINE_MAX;
1032 
1033  // Exit if sigma8 wasn't specified
1034  if (isnan(cosmo->params.sigma8)) {
1035  *status = CCL_ERROR_INCONSISTENT;
1036  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_bbks(): sigma8 not set, required for BBKS\n");
1037  return; //Return without anything to free
1038  }
1039 
1040  // The x array is initially k, but will later
1041  // be overwritten with log(k)
1042  double * x = ccl_log_spacing(kmin, kmax, nk);
1043  double * y = malloc(sizeof(double)*nk);
1045  double * y2d = malloc(nk * na * sizeof(double));
1046 
1047  //If error, store status, we will free later
1048  if (a==NULL||y==NULL|| x==NULL || y2d==0) {
1049  *status=CCL_ERROR_MEMORY;
1050  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_bbks(): memory allocation error\n");
1051  }
1052 
1053  //Status flags
1054  int splinstatus=0;
1055 
1056  if(!*status){
1057 
1058  // After this loop x will contain log(k)
1059  for (int i=0; i<nk; i++) {
1060  y[i] = log(bbks_power(&cosmo->params, x[i]));
1061  x[i] = log(x[i]);
1062  }
1063 
1064  for (int j = 0; j < na; j++) {
1065  double gfac = ccl_growth_factor(cosmo,a[j], status);
1066  double g2 = 2.*log(gfac);
1067  for (int i=0; i<nk; i++) {
1068  y2d[j*nk+i] = y[i]+g2;
1069  }
1070  }
1071  }
1072 
1073  if(!*status){
1074 
1075  // Initialize a 2D spline over P(k, a) [which is still unnormalized by sigma8]
1076  gsl_spline2d * log_power_lin_unnorm = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, nk,na);
1077  splinstatus = gsl_spline2d_init(log_power_lin_unnorm, x, a, y2d,nk,na);
1078 
1079  //If not, proceed
1080  if (!splinstatus) {
1081  cosmo->data.p_lin=log_power_lin_unnorm;
1082  cosmo->computed_power=true;
1083  } else {
1084  gsl_spline2d_free(log_power_lin_unnorm);
1085  *status = CCL_ERROR_SPLINE;
1086  ccl_cosmology_set_status_message(cosmo,"ccl_power.c: ccl_cosmology_compute_power_bbks(): Error creating log_power_lin spline\n");
1087  }
1088  }
1089 
1090  if(*status){
1091  free(x); free(y); free(a); free(y2d);
1092  return;
1093  }
1094 
1095  // Calculate sigma8 for the unnormalized P(k), using the standard
1096  // ccl_sigma8() function
1097  double sigma8 = ccl_sigma8(cosmo,status);
1098  cosmo->computed_power=false;
1099 
1100  // Check that ccl_sigma8 didn't fail
1101  if (!*status) {
1102 
1103  // Calculate normalization factor using computed value of sigma8, then
1104  // recompute P(k, a) using this normalization
1105  double log_normalization_factor = 2*(log(cosmo->params.sigma8) - log(sigma8));
1106  for (int i=0; i<nk; i++) {
1107  y[i] += log_normalization_factor;
1108  }
1109  for (int j = 0; j < na; j++) {
1110  double gfac = ccl_growth_factor(cosmo,a[j], status);
1111  double g2 = 2.*log(gfac);
1112  for (int i=0; i<nk; i++) {
1113  y2d[j*nk+i] = y[i]+g2;
1114  }
1115  }
1116  }
1117 
1118  //Check growth didn't fail
1119  if (!*status) {
1120 
1121  gsl_spline2d * log_power_lin = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, nk,na);
1122  splinstatus = gsl_spline2d_init(log_power_lin, x, a, y2d,nk,na);
1123 
1124  if (!splinstatus) {
1125  cosmo->data.p_lin=log_power_lin;
1126  } else {
1127  gsl_spline2d_free(log_power_lin);
1128  *status = CCL_ERROR_SPLINE;
1129  ccl_cosmology_set_status_message(cosmo,"ccl_power.c: ccl_cosmology_compute_power_bbks(): Error creating log_power_lin spline\n");
1130  }
1131  }
1132 
1133  if(!*status){
1134  // Allocate a 2D spline for the nonlinear P(k)
1135  //[which is just a copy of the linear one for BBKS]
1136  gsl_spline2d * log_power_nl = gsl_spline2d_alloc(PNL_SPLINE_TYPE, nk,na);
1137  splinstatus = gsl_spline2d_init(log_power_nl, x, a, y2d,nk,na);
1138  if (!splinstatus) {
1139  cosmo->data.p_nl = log_power_nl;
1140  } else {
1141  gsl_spline2d_free(log_power_nl);
1142  *status = CCL_ERROR_SPLINE;
1143  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_bbks(): Error creating log_power_nl spline\n");
1144  }
1145  }
1146 
1147  free(x); free(y); free(a); free(y2d);
1148  return;
1149 }
1150 
1151 
1152 
1153 /*------ ROUTINE: ccl_cosmology_compute_power_emu -----
1154 INPUT: cosmology
1155 TASK: provide spline for the emulated power spectrum from Cosmic EMU
1156 */
1157 
1159 {
1160 
1161  struct precision pr; // for precision parameters
1162  struct background ba; // for cosmological background
1163  struct thermo th; // for thermodynamics
1164  struct perturbs pt; // for source functions
1165  struct transfers tr; // for transfer functions
1166  struct primordial pm; // for primordial spectra
1167  struct spectra sp; // for output spectra
1168  struct nonlinear nl; // for non-linear spectra
1169  struct lensing le;
1170  struct output op;
1171  struct file_content fc;
1172 
1173  double Omeganuh2_eq;
1174  double w0wacomb = -cosmo->params.w0 - cosmo->params.wa;
1175 
1176  ErrorMsg errmsg; // for error messages
1177  // generate file_content structure
1178  // Configuration parameters will be passed through this structure,
1179  // to avoid writing and reading .ini files for every call
1180  int parser_length = 20;
1181  int init_arr[7]={0,0,0,0,0,0,0};
1182 
1183  //Check initialization
1184  if (parser_init(&fc,parser_length,"none",errmsg) == _FAILURE_) {
1185  *status = CCL_ERROR_CLASS;
1186  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): parser init error:%s\n", errmsg);
1187  }
1188 
1189  // Check ranges to see if the cosmology is valid
1190  if((cosmo->params.h<0.55) || (cosmo->params.h>0.85)){
1191  *status=CCL_ERROR_INCONSISTENT;
1192  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): h is outside allowed range\n");
1193  }
1194  if(w0wacomb<8.1e-3){ //0.3^4
1195  *status=CCL_ERROR_INCONSISTENT;
1196  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): w0 and wa do not satisfy the emulator bound\n");
1197  }
1198  if(cosmo->params.Omega_n_mass*cosmo->params.h*cosmo->params.h>0.01){
1199  *status=CCL_ERROR_INCONSISTENT;
1200  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Omega_nu does not satisfy the emulator bound\n");
1201  }
1202 
1203  // Check to see if sigma8 was defined
1204  if(isnan(cosmo->params.sigma8)){
1205  *status=CCL_ERROR_INCONSISTENT;
1206  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): sigma8 is not defined; specify sigma8 instead of A_s\n");
1207  }
1208 
1209  //If one of the previous test was unsuccessful, quit:
1210  if(*status) return;
1211 
1212  // Check if the cosmology has been set up with equal neutrino masses for the emulator
1213  // If not, check if the user has forced redistribution of masses and if so do this.
1214  if(cosmo->params.N_nu_mass>0) {
1216  if (cosmo->params.N_nu_mass==3){
1217  //double diff1 = pow((cosmo->params.mnu[0] - cosmo->params.mnu[1]) * (cosmo->params.mnu[0] - cosmo->params.mnu[1]), 0.5);
1218  //double diff2 = pow((cosmo->params.mnu[1] - cosmo->params.mnu[2]) * (cosmo->params.mnu[1] - cosmo->params.mnu[2]), 0.5);
1219  //double diff3 = pow((cosmo->params.mnu[2] - cosmo->params.mnu[0]) * (cosmo->params.mnu[2] - cosmo->params.mnu[0]), 0.5);
1220  //if (diff1>1e-12 || diff2>1e-12 || diff3>1e-12){
1221  if (cosmo->params.mnu[0] != cosmo->params.mnu[1] || cosmo->params.mnu[0] != cosmo->params.mnu[2] || cosmo->params.mnu[1] != cosmo->params.mnu[2]){
1222  *status = CCL_ERROR_INCONSISTENT;
1223  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): In the default configuration, you must pass a list of 3 equal neutrino masses or pass a sum and set mnu_type = ccl_mnu_sum_equal. If you wish to over-ride this, set config->emulator_neutrinos_method = 'ccl_emu_equalize'. This will force the neutrinos to be of equal mass but will result in internal inconsistencies.\n");
1224  }
1225  } else if (cosmo->params.N_nu_mass!=3){
1226  *status = CCL_ERROR_INCONSISTENT;
1227  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): In the default configuration, you must pass a list of 3 equal neutrino masses or pass a sum and set mnu_type = ccl_mnu_sum_equal. If you wish to over-ride this, set config->emulator_neutrinos_method = 'ccl_emu_equalize'. This will force the neutrinos to be of equal mass but will result in internal inconsistencies.\n");
1228  }
1229  } else if (cosmo->config.emulator_neutrinos_method == ccl_emu_equalize){
1230  // Reset the masses to equal
1231  double mnu_eq[3] = {cosmo->params.sum_nu_masses / 3., cosmo->params.sum_nu_masses / 3., cosmo->params.sum_nu_masses / 3.};
1232  Omeganuh2_eq = ccl_Omeganuh2(1.0, 3, mnu_eq, cosmo->params.T_CMB, cosmo->data.accelerator, status);
1233  }
1234  } else {
1235  if(fabs(cosmo->params.N_nu_rel - 3.04)>1.e-6){
1236  *status=CCL_ERROR_INCONSISTENT;
1237  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Set Neff = 3.04 for cosmic emulator predictions in absence of massive neutrinos.\n");
1238  }
1239  }
1240 
1241  if(!*status){
1242  // Prepare to run CLASS for linear scales
1243  ccl_fill_class_parameters(cosmo,&fc,parser_length, status);
1244  }
1245 
1246  if (!*status){
1247  ccl_run_class(cosmo, &fc,&pr,&ba,&th,&pt,&tr,&pm,&sp,&nl,&le,&op,init_arr,status);
1248  }
1249 
1250  if (*status){
1251  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
1252  if (parser_free(&fc)== _FAILURE_) {
1253  *status = CCL_ERROR_CLASS;
1254  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): Error freeing CLASS parser\n");
1255  }
1256  return;
1257  }
1258 
1259  //These are the limits of the splining range
1260  cosmo->data.k_min_lin=2*exp(sp.ln_k[0]);
1262  //CLASS calculations done - now allocate CCL splines
1263  double kmin = cosmo->data.k_min_lin;
1264  double kmax = ccl_splines->K_MAX_SPLINE;
1265  //Compute nk from number of decades and N_K = # k per decade
1266  double ndecades = log10(kmax) - log10(kmin);
1267  int nk = (int)ceil(ndecades*ccl_splines->N_K);
1268  double amin = ccl_splines->A_SPLINE_MINLOG_PK;
1269  double amax = ccl_splines->A_SPLINE_MAX;
1271 
1272  // The x array is initially k, but will later
1273  // be overwritten with log(k)
1274  double * x = ccl_log_spacing(kmin, kmax, nk);
1276  double * y2d_lin = malloc(nk * na * sizeof(double));
1277  if (a==NULL|| x==NULL || y2d_lin==NULL) {
1278  *status = CCL_ERROR_SPLINE;
1279  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_class(): memory allocation error\n");
1280  }
1281 
1282  if(!*status){
1283  // After this loop x will contain log(k), y will contain log(P_nl), z will contain log(P_lin)
1284  // all in Mpc, not Mpc/h units!
1285  double psout_l,ic;
1286  int s=0;
1287  for (int i=0; i<nk; i++) {
1288  for (int j = 0; j < na; j++) {
1289  //The 2D interpolation routines access the function values y_{k_ia_j} with the following ordering:
1290  //y_ij = y2d[j*N_k + i]
1291  //with i = 0,...,N_k-1 and j = 0,...,N_a-1.
1292  s |= spectra_pk_at_k_and_z(&ba, &pm, &sp,x[i],1./a[j]-1., &psout_l,&ic);
1293  y2d_lin[j*nk+i] = log(psout_l);
1294  }
1295  x[i] = log(x[i]);
1296  }
1297  if(s) {
1298  *status = CCL_ERROR_CLASS;
1299  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Error computing CLASS power spectrum\n");
1300  }
1301  }
1302 
1303  if(!*status){
1304 
1305  gsl_spline2d * log_power = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, nk,na);
1306  int pwstatus = gsl_spline2d_init(log_power, x, a, y2d_lin,nk,na);
1307  if (!pwstatus) {
1308  cosmo->data.p_lin = log_power;
1309  } else {
1310  gsl_spline2d_free(log_power);
1311  *status = CCL_ERROR_SPLINE;
1312  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Error creating log_power spline\n");
1313  }
1314  }
1315 
1316  if(*status){ //Linear power spectrum failed, so quit.
1317  free(x);
1318  free(a);
1319  free(y2d_lin);
1320  ccl_free_class_structs(cosmo, &ba,&th,&pt,&tr,&pm,&sp,&nl,&le,init_arr,status);
1321  return;
1322  }
1323 
1324  //Now start the NL computation with the emulator
1325  //These are the limits of the splining range
1326  cosmo->data.k_min_nl=K_MIN_EMU;
1327  cosmo->data.k_max_nl=K_MAX_EMU;
1328  amin = A_MIN_EMU; //limit of the emulator
1329  amax = ccl_splines->A_SPLINE_MAX;
1331  // The x array is initially k, but will later
1332  // be overwritten with log(k)
1333  double * logx= malloc(NK_EMU*sizeof(double));
1334  double * y;
1335  double * xstar = malloc(9 * sizeof(double));
1336  double * aemu = ccl_linear_spacing(amin,amax, na);
1337  double * y2d = malloc(NK_EMU * na * sizeof(double));
1338  if (aemu==NULL || y2d==NULL || logx==NULL || xstar==NULL){
1339  *status=CCL_ERROR_MEMORY;
1340  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): memory allocation error\n");
1341  }
1342 
1343  if(!*status){
1344 
1345  //For each redshift:
1346  for (int j = 0; j < na; j++){
1347 
1348  //Turn cosmology into xstar:
1349  xstar[0] = (cosmo->params.Omega_c+cosmo->params.Omega_b)*cosmo->params.h*cosmo->params.h;
1350  xstar[1] = cosmo->params.Omega_b*cosmo->params.h*cosmo->params.h;
1351  xstar[2] = cosmo->params.sigma8;
1352  xstar[3] = cosmo->params.h;
1353  xstar[4] = cosmo->params.n_s;
1354  xstar[5] = cosmo->params.w0;
1355  xstar[6] = cosmo->params.wa;
1357  xstar[7] = Omeganuh2_eq;
1358  } else {
1359  xstar[7] = cosmo->params.Omega_n_mass*cosmo->params.h*cosmo->params.h;
1360  }
1361  xstar[8] = 1./aemu[j]-1;
1362  //Need to have this here because otherwise overwritten by emu in each loop
1363 
1364  //Call emulator at this redshift
1365  ccl_pkemu(xstar,&y, status, cosmo);
1366  if (y == NULL){
1367  *status = CCL_ERROR_MEMORY;
1368  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Error obtaining emulator predictions\n");
1369  }
1370  for (int i=0; i<NK_EMU; i++){
1371  logx[i] = log(mode[i]);
1372  y2d[j*NK_EMU+i] = log(y[i]);
1373  }
1374  }
1375  }
1376 
1377  if(!*status){
1378 
1379  gsl_spline2d * log_power_nl = gsl_spline2d_alloc(PLIN_SPLINE_TYPE, NK_EMU,na);
1380  int splinstatus = gsl_spline2d_init(log_power_nl, logx, aemu, y2d,NK_EMU,na);
1381  //Note the minimum k of the spline is different from the linear one.
1382 
1383  if (!splinstatus){
1384  cosmo->data.p_nl = log_power_nl;
1385  } else {
1386  gsl_spline2d_free(log_power_nl);
1387  *status = CCL_ERROR_SPLINE;
1388  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power_emu(): Error creating log_power spline\n");
1389  }
1390  }
1391 
1392  free(x); free(a); free(y);
1393  free(xstar); free(logx); free(aemu);
1394  free(y2d_lin); free(y2d);
1395 }
1396 
1397 
1398 
1399 /*------ ROUTINE: ccl_cosmology_compute_power -----
1400 INPUT: ccl_cosmology * cosmo
1401 TASK: compute power spectrum
1402 */
1404 {
1405 
1406  if (cosmo->computed_power) return;
1407  switch(cosmo->config.transfer_function_method){
1408  case ccl_bbks:
1409  ccl_cosmology_compute_power_bbks(cosmo,status);
1410  break;
1411  case ccl_eisenstein_hu:
1412  ccl_cosmology_compute_power_eh(cosmo,status);
1413  break;
1414  case ccl_boltzmann_class:
1415  ccl_cosmology_compute_power_class(cosmo,status);
1416  break;
1417  case ccl_emulator:
1418  ccl_cosmology_compute_power_emu(cosmo,status);
1419  break;
1420  default:
1421  *status = CCL_ERROR_INCONSISTENT;
1422  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_cosmology_compute_power(): Unknown or non-implemented transfer function method: %d \n", cosmo->config.transfer_function_method);
1423  }
1424 
1425  ccl_check_status(cosmo,status);
1426  if (*status==0){
1427  cosmo->computed_power = true;
1428  }
1429  return;
1430 }
1431 
1432 
1433 /*------ ROUTINE: ccl_power_extrapol_highk -----
1434 INPUT: ccl_cosmology * cosmo, a, k [1/Mpc]
1435 TASK: extrapolate power spectrum at high k
1436 */
1437 static double ccl_power_extrapol_highk(ccl_cosmology * cosmo, double k, double a,
1438  gsl_spline2d * powerspl, double kmax_spline, int * status)
1439 {
1440  double log_p_1;
1441  double deltak=1e-2; //step for numerical derivative;
1442  double deriv_pk_kmid,deriv2_pk_kmid;
1443  double lkmid;
1444  double lpk_kmid;
1445 
1446  lkmid = log(kmax_spline)-2*deltak;
1447 
1448  int gslstatus = gsl_spline2d_eval_e(powerspl, lkmid,a,NULL ,NULL ,&lpk_kmid);
1449  if(gslstatus != GSL_SUCCESS) {
1450  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_power_extrapol_highk():");
1451  *status = CCL_ERROR_SPLINE_EV;
1452  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_power_extrapol_highk(): Spline evaluation error\n");
1453  return NAN;
1454  }
1455  //GSL derivatives
1456  gslstatus = gsl_spline2d_eval_deriv_x_e (powerspl, lkmid, a, NULL,NULL,&deriv_pk_kmid);
1457  if(gslstatus != GSL_SUCCESS) {
1458  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_power_extrapol_highk():");
1459  *status = CCL_ERROR_SPLINE_EV;
1460  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_power_extrapol_highk(): Spline evaluation error\n");
1461  return NAN;
1462  }
1463  gslstatus = gsl_spline2d_eval_deriv_xx_e (powerspl, lkmid, a, NULL,NULL,&deriv2_pk_kmid);
1464  if(gslstatus != GSL_SUCCESS) {
1465  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_power_extrapol_highk():");
1466  *status = CCL_ERROR_SPLINE_EV;
1467  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_power_extrapol_highk(): Spline evaluation error\n");
1468  return NAN;
1469  }
1470  log_p_1=lpk_kmid+deriv_pk_kmid*(log(k)-lkmid)+deriv2_pk_kmid/2.*(log(k)-lkmid)*(log(k)-lkmid);
1471 
1472  return log_p_1;
1473 
1474 }
1475 
1476 /*------ ROUTINE: ccl_power_extrapol_lowk -----
1477 INPUT: ccl_cosmology * cosmo, a, k [1/Mpc]
1478 TASK: extrapolate power spectrum at low k
1479 */
1480 static double ccl_power_extrapol_lowk(ccl_cosmology * cosmo, double k, double a,
1481  gsl_spline2d * powerspl, double kmin_spline, int * status)
1482 {
1483  double log_p_1;
1484  double deltak=1e-2; //safety step
1485  double lkmin=log(kmin_spline)+deltak;
1486  double lpk_kmin;
1487  int gslstatus = gsl_spline2d_eval_e(powerspl,lkmin,a,NULL,NULL,&lpk_kmin);
1488 
1489  if(gslstatus != GSL_SUCCESS) {
1490  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_power_extrapol_lowk():");
1491  *status=CCL_ERROR_SPLINE_EV;
1492  ccl_cosmology_set_status_message(cosmo,"ccl_power.c: ccl_power_extrapol_lowk(): Spline evaluation error\n");
1493  return NAN;
1494  }
1495 
1496  return lpk_kmin+cosmo->params.n_s*(log(k)-lkmin);
1497 }
1498 
1499 
1500 /*------ ROUTINE: ccl_linear_matter_power -----
1501 INPUT: ccl_cosmology * cosmo, k [1/Mpc],a
1502 TASK: compute the linear power spectrum at a given redshift
1503  by rescaling using the growth function
1504 */
1505 
1506 double ccl_linear_matter_power(ccl_cosmology * cosmo, double k, double a, int * status)
1507 
1508 {
1509  if ((cosmo->config.transfer_function_method == ccl_emulator) && (a<A_MIN_EMU)){
1510  *status = CCL_ERROR_INCONSISTENT;
1511  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: the cosmic emulator cannot be used above a=%f\n",A_MIN_EMU);
1512  return NAN;
1513  }
1514 
1515  if (!cosmo->computed_power) ccl_cosmology_compute_power(cosmo, status);
1516  // Return if compilation failed
1517  //if (cosmo->data.p_lin == NULL) return NAN;
1518  if (!cosmo->computed_power) return NAN;
1519 
1520  double log_p_1;
1521  int gslstatus;
1522 
1523  if(a<ccl_splines->A_SPLINE_MINLOG_PK) { //Extrapolate linearly at high redshift
1524  double pk0=ccl_linear_matter_power(cosmo,k,ccl_splines->A_SPLINE_MINLOG_PK,status);
1525  double gf=ccl_growth_factor(cosmo,a,status)/ccl_growth_factor(cosmo,ccl_splines->A_SPLINE_MINLOG_PK,status);
1526 
1527  return pk0*gf*gf;
1528  }
1529  if (*status!=CCL_ERROR_INCONSISTENT){
1530  if(k<=cosmo->data.k_min_lin) {
1531  log_p_1=ccl_power_extrapol_lowk(cosmo,k,a,cosmo->data.p_lin,cosmo->data.k_min_lin,status);
1532 
1533  return exp(log_p_1);
1534  }
1535  else if(k<cosmo->data.k_max_lin){
1536  gslstatus = gsl_spline2d_eval_e(cosmo->data.p_lin, log(k), a,NULL,NULL,&log_p_1);
1537  if(gslstatus != GSL_SUCCESS) {
1538  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_linear_matter_power():");
1539  *status = CCL_ERROR_SPLINE_EV;
1540  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_linear_matter_power(): Spline evaluation error\n");
1541  return NAN;
1542  }
1543  else {
1544  return exp(log_p_1);
1545  }
1546  }
1547  else { //Extrapolate using log derivative
1548  log_p_1 = ccl_power_extrapol_highk(cosmo,k,a,cosmo->data.p_lin,cosmo->data.k_max_lin,status);
1549  return exp(log_p_1);
1550  }
1551  }
1552 
1553  return exp(log_p_1);
1554 }
1555 
1556 
1557 /*------ ROUTINE: ccl_nonlin_matter_power -----
1558 INPUT: ccl_cosmology * cosmo, a, k [1/Mpc]
1559 TASK: compute the nonlinear power spectrum at a given redshift
1560 */
1561 
1562 double ccl_nonlin_matter_power(ccl_cosmology * cosmo, double k, double a, int *status)
1563 {
1564  double log_p_1, pk;
1565 
1566  switch(cosmo->config.matter_power_spectrum_method) {
1567 
1568  //If the matter PS specified was linear, then do the linear compuation
1569  case ccl_linear:
1570  return ccl_linear_matter_power(cosmo,k,a,status);
1571 
1572  case ccl_halofit:
1573  if (!cosmo->computed_power)
1574  ccl_cosmology_compute_power(cosmo, status);
1575  if (cosmo->data.p_nl == NULL) return NAN; // Return if computation failed
1576 
1577  if(a<ccl_splines->A_SPLINE_MINLOG_PK) { //Extrapolate linearly at high redshift
1578  double pk0=ccl_nonlin_matter_power(cosmo,k,ccl_splines->A_SPLINE_MINLOG_PK,status);
1579  double gf=ccl_growth_factor(cosmo,a,status)/ccl_growth_factor(cosmo,ccl_splines->A_SPLINE_MINLOG_PK,status);
1580  return pk0*gf*gf;
1581  }
1582  break;
1583 
1584  case ccl_emu:
1585  if ((cosmo->config.transfer_function_method == ccl_emulator) && (a<A_MIN_EMU)){
1586  *status = CCL_ERROR_EMULATOR_BOUND;
1587  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: the cosmic emulator cannot be used above z=2\n");
1588  return NAN;
1589  }
1590 
1591  // Compute power spectrum if needed; return if computation failed
1592  if (!cosmo->computed_power){
1593  ccl_cosmology_compute_power(cosmo,status);
1594  }
1595  if (cosmo->data.p_nl == NULL) return NAN;
1596  break;
1597 
1598  default:
1601  "config.matter_power_spectrum_method = %d not yet supported "
1602  "continuing with linear power spectrum\n", cosmo->config.matter_power_spectrum_method);
1604  return ccl_linear_matter_power(cosmo,k,a,status);
1605  } // end switch
1606 
1607  // if we get here, try to evaluate the power spectrum
1608  // we need to account for bounds below and above
1609  if (k <= cosmo->data.k_min_nl) {
1610  // we assume no baryonic effects below k_min_nl
1611  log_p_1 = ccl_power_extrapol_lowk(cosmo, k, a, cosmo->data.p_nl, cosmo->data.k_min_nl, status);
1612  return exp(log_p_1);
1613  }
1614 
1615  if (k < cosmo->data.k_max_nl) {
1616  int gslstatus = gsl_spline2d_eval_e(cosmo->data.p_nl, log(k), a, NULL ,NULL, &log_p_1);
1617  if (gslstatus != GSL_SUCCESS) {
1618  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_nonlin_matter_power():");
1619  *status = CCL_ERROR_SPLINE_EV;
1620  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_nonlin_matter_power(): Spline evaluation error\n");
1621  return NAN;
1622  } else {
1623  pk = exp(log_p_1);
1624  }
1625  } else {
1626  // Extrapolate NL regime using log derivative
1627  log_p_1 = ccl_power_extrapol_highk(cosmo, k, a, cosmo->data.p_nl, cosmo->data.k_max_nl, status);
1628  pk = exp(log_p_1);
1629  }
1630 
1631  // Add baryonic correction
1633  int pwstatus = 0;
1634  double fbcm = ccl_bcm_model_fka(cosmo, k, a, &pwstatus);
1635  pk *= fbcm;
1636  if (pwstatus) {
1637  *status = CCL_ERROR_SPLINE_EV;
1638  ccl_cosmology_set_status_message(cosmo, "ccl_power.c: ccl_nonlin_matter_power(): Error in BCM correction\n");
1639  return NAN;
1640  }
1641  }
1642 
1643  return pk;
1644 }
1645 
1646 // Params for sigma(R) integrand
1647 typedef struct {
1649  double R;
1650  int* status;
1651 } SigmaR_pars;
1652 
1653 typedef struct {
1655  double R;
1656  int* status;
1657 } SigmaV_pars;
1658 
1659 /* --------- ROUTINE: w_tophat ---------
1660 INPUT: kR, ususally a wavenumber multiplied by a smoothing radius
1661 TASK: Output W(x)=[sin(x)-x*cos(x)]*(3/x)^3
1662 */
1663 static double w_tophat(double kR)
1664 {
1665  double w;
1666  double kR2 = kR*kR;
1667 
1668  // This is the Maclaurin expansion of W(x)=[sin(x)-xcos(x)]*(3/x)**3 to O(x^7), with x=kR.
1669  // Necessary numerically because at low x W(x) relies on the fine cancellation of two terms
1670  if(kR<0.1) {
1671  w = 1. + kR2*(-0.1 +
1672  kR2*(0.003561429 +
1673  kR2*(-6.61376e-5 +
1674  kR2*(7.51563e-7))));
1675  /*w =1.-0.1*kR*kR+0.003571429*kR*kR*kR*kR
1676  -6.61376E-5*kR*kR*kR*kR*kR*kR
1677  +7.51563E-7*kR*kR*kR*kR*kR*kR*kR*kR;*/
1678  }
1679  else
1680  w = 3.*(sin(kR) - kR*cos(kR))/(kR2*kR);
1681  return w;
1682 }
1683 
1684 // Integrand for sigmaR integral
1685 static double sigmaR_integrand(double lk,void *params)
1686 {
1687  SigmaR_pars *par=(SigmaR_pars *)params;
1688 
1689  double k=pow(10.,lk);
1690  double pk=ccl_linear_matter_power(par->cosmo,k, 1.,par->status);
1691  double kR=k*par->R;
1692  double w = w_tophat(kR);
1693 
1694  return pk*k*k*k*w*w;
1695 }
1696 
1697 // Integrand for sigmaV integral
1698 static double sigmaV_integrand(double lk,void *params)
1699 {
1700  SigmaV_pars *par=(SigmaV_pars *)params;
1701 
1702  double k=pow(10.,lk);
1703  double pk=ccl_linear_matter_power(par->cosmo,k, 1.,par->status);
1704  double kR=k*par->R;
1705  double w = w_tophat(kR);
1706 
1707  return pk*k*w*w/3.0;
1708 }
1709 
1710 /* --------- ROUTINE: ccl_sigmaR ---------
1711 INPUT: cosmology, comoving smoothing radius, scale factor
1712 TASK: compute sigmaR, the variance in the *linear* density field
1713 smoothed with a tophat filter of comoving size R
1714 */
1715 double ccl_sigmaR(ccl_cosmology *cosmo,double R,double a,int *status)
1716 {
1717  SigmaR_pars par;
1718  par.status = status;
1719 
1720  par.cosmo=cosmo;
1721  par.R=R;
1722  gsl_integration_cquad_workspace *workspace=gsl_integration_cquad_workspace_alloc(ccl_gsl->N_ITERATION);
1723  gsl_function F;
1724  F.function=&sigmaR_integrand;
1725  F.params=&par;
1726  double sigma_R;
1727  int gslstatus = gsl_integration_cquad(&F, log10(ccl_splines->K_MIN), log10(ccl_splines->K_MAX),
1729  workspace,&sigma_R,NULL,NULL);
1730  if(gslstatus != GSL_SUCCESS) {
1731  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_sigmaR():");
1732  *status |= gslstatus;
1733  }
1734 
1735  gsl_integration_cquad_workspace_free(workspace);
1736 
1737  return sqrt(sigma_R*M_LN10/(2*M_PI*M_PI))*ccl_growth_factor(cosmo, a, status);
1738 }
1739 
1740 /* --------- ROUTINE: ccl_sigmaV ---------
1741 INPUT: cosmology, comoving smoothing radius, scale factor
1742 TASK: compute sigmaV, the variance in the *linear* displacement field
1743 smoothed with a tophat filter of comoving size R
1744 The linear displacement field is the gradient of the linear density field
1745 */
1746 double ccl_sigmaV(ccl_cosmology *cosmo,double R,double a,int *status)
1747 {
1748  SigmaV_pars par;
1749  par.status = status;
1750 
1751  par.cosmo=cosmo;
1752  par.R=R;
1753  gsl_integration_cquad_workspace *workspace=gsl_integration_cquad_workspace_alloc(ccl_gsl->N_ITERATION);
1754  gsl_function F;
1755  F.function=&sigmaV_integrand;
1756  F.params=&par;
1757  double sigma_V;
1758  int gslstatus = gsl_integration_cquad(&F, log10(ccl_splines->K_MIN), log10(ccl_splines->K_MAX),
1760  workspace,&sigma_V,NULL,NULL);
1761 
1762  if(gslstatus != GSL_SUCCESS) {
1763  ccl_raise_gsl_warning(gslstatus, "ccl_power.c: ccl_sigmaV():");
1764  *status |= gslstatus;
1765  }
1766 
1767  gsl_integration_cquad_workspace_free(workspace);
1768 
1769  return sqrt(sigma_V*M_LN10/(2*M_PI*M_PI))*ccl_growth_factor(cosmo, a, status);
1770 }
1771 
1772 /* --------- ROUTINE: ccl_sigma8 ---------
1773 INPUT: cosmology
1774 TASK: compute sigma8, the variance in the *linear* density field at a=1
1775 smoothed with a tophat filter of comoving size 8 Mpc/h
1776 */
1777 double ccl_sigma8(ccl_cosmology *cosmo, int *status)
1778 {
1779  return ccl_sigmaR(cosmo,8/cosmo->params.h, 1.,status);
1780 }
double k_min_nl
Definition: ccl_core.h:114
bool computed_power
Definition: ccl_core.h:130
double alphab
Definition: ccl_power.c:672
double ccl_nonlin_matter_power(ccl_cosmology *cosmo, double k, double a, int *status)
Definition: ccl_power.c:1562
double INTEGRATION_SIGMAR_EPSREL
Definition: ccl_params.h:68
static double bbks_power(ccl_parameters *params, double k)
Definition: ccl_power.c:1007
static double tsqr_BBKS(ccl_parameters *params, double k)
Definition: ccl_power.c:995
double K_MAX_SPLINE
Definition: ccl_params.h:33
ccl_cosmology * cosmo
Definition: ccl_power.c:1654
#define K_MAX_EMU
Definition: ccl_emu17.h:5
double rsound_approx
Definition: ccl_power.c:669
double zdrag
Definition: ccl_power.c:667
void ccl_raise_gsl_warning(int gslstatus, const char *msg,...)
Definition: ccl_error.c:75
#define NK_EMU
Definition: ccl_emu17.h:7
double * mnu
Definition: ccl_core.h:40
#define CCL_ERROR_NOT_IMPLEMENTED
Definition: ccl_error.h:25
static double sigmaR_integrand(double lk, void *params)
Definition: ccl_power.c:1685
matter_power_spectrum_t matter_power_spectrum_method
Definition: ccl_config.h:112
double Omega_b
Definition: ccl_core.h:20
ccl_parameters params
Definition: ccl_core.h:124
double N_nu_rel
Definition: ccl_core.h:39
double ccl_growth_factor(ccl_cosmology *cosmo, double a, int *status)
static void ccl_cosmology_compute_power_eh(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:842
static double ccl_power_extrapol_lowk(ccl_cosmology *cosmo, double k, double a, gsl_spline2d *powerspl, double kmin_spline, int *status)
Definition: ccl_power.c:1480
double * ccl_log_spacing(double xmin, double xmax, int N)
Definition: ccl_utils.c:102
void ccl_check_status(ccl_cosmology *cosmo, int *status)
Definition: ccl_error.c:88
#define A_MIN_EMU
Definition: ccl_emu17.h:4
static double ccl_power_extrapol_highk(ccl_cosmology *cosmo, double k, double a, gsl_spline2d *powerspl, double kmax_spline, int *status)
Definition: ccl_power.c:1437
double * ccl_linlog_spacing(double xminlog, double xmin, double xmax, int Nlin, int Nlog)
Definition: ccl_utils.c:43
static double w_tophat(double kR)
Definition: ccl_power.c:1663
static double tkEH_0(double keq, double k, double a, double b)
Definition: ccl_power.c:747
#define CCL_ERROR_SPLINE_EV
Definition: ccl_error.h:14
static double ccl_get_class_As(ccl_cosmology *cosmo, struct file_content *fc, int position_As, double sigma8, int *status)
Definition: ccl_power.c:228
double Omega_n_mass
Definition: ccl_core.h:42
ccl_spline_params * ccl_splines
Definition: ccl_core.c:47
static void ccl_free_class_structs(ccl_cosmology *cosmo, struct background *ba, struct thermo *th, struct perturbs *pt, struct transfers *tr, struct primordial *pm, struct spectra *sp, struct nonlinear *nl, struct lensing *le, int *init_arr, int *status)
Definition: ccl_power.c:21
void ccl_cosmology_compute_power(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:1403
CCL_BEGIN_DECLS double * ccl_linear_spacing(double xmin, double xmax, int N)
Definition: ccl_utils.c:14
double n_s
Definition: ccl_core.h:50
double h
Definition: ccl_core.h:33
CCL_BEGIN_DECLS void ccl_pkemu(double *xstarin, double **Pkemu, int *status, ccl_cosmology *cosmo)
Definition: ccl_emu17.c:141
double w0
Definition: ccl_core.h:28
double th2p7
Definition: ccl_power.c:670
#define M_PI
Definition: ccl_constants.h:22
double bcm_ks
Definition: ccl_core.h:59
static double spectra(char *tr1, char *tr2, int l, RunParams *par)
Definition: spectra.c:22
#define CCL_ERROR_SPLINE
Definition: ccl_error.h:13
double ccl_bcm_model_fka(ccl_cosmology *cosmo, double k, double a, int *status)
Definition: ccl_power.c:574
static void ccl_class_preinit(struct background *ba, struct thermo *th, struct perturbs *pt, struct transfers *tr, struct primordial *pm, struct spectra *sp, struct nonlinear *nl, struct lensing *le)
Definition: ccl_power.c:93
transfer_function_t transfer_function_method
Definition: ccl_config.h:111
double ccl_sigmaR(ccl_cosmology *cosmo, double R, double a, int *status)
Definition: ccl_power.c:1715
#define CCL_ERROR_CLASS
Definition: ccl_error.h:17
#define K_MIN_EMU
Definition: ccl_emu17.h:6
if(pnl->method==nl_baryon)
Definition: bcm_bm.c:13
gsl_spline2d * p_lin
Definition: ccl_core.h:111
static void ccl_cosmology_compute_power_emu(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:1158
void ccl_cosmology_set_status_message(ccl_cosmology *cosmo, const char *status_message,...)
Definition: ccl_core.c:792
double sum_nu_masses
Definition: ccl_core.h:41
ccl_gsl_params * ccl_gsl
Definition: ccl_core.c:48
double kSilk
Definition: ccl_power.c:668
double A_s
Definition: ccl_core.h:49
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
static eh_struct * eh_struct_new(ccl_parameters *params)
Definition: ccl_power.c:678
double A_SPLINE_MAX
Definition: ccl_params.h:18
double betac
Definition: ccl_power.c:673
double ccl_sigmaV(ccl_cosmology *cosmo, double R, double a, int *status)
Definition: ccl_power.c:1746
double zeq
Definition: ccl_power.c:665
static CCL_BEGIN_DECLS double x[111][8]
static void ccl_fill_class_parameters(ccl_cosmology *cosmo, struct file_content *fc, int parser_length, int *status)
Definition: ccl_power.c:266
static double tkEH_b(eh_struct *eh, double k)
Definition: ccl_power.c:779
#define CCL_ERROR_MEMORY
Definition: ccl_error.h:10
gsl_spline2d * p_nl
Definition: ccl_core.h:112
double T_CMB
Definition: ccl_core.h:54
static double sigmaV_integrand(double lk, void *params)
Definition: ccl_power.c:1698
size_t N_ITERATION
Definition: ccl_params.h:55
void ccl_raise_warning(int err, const char *msg,...)
Definition: ccl_error.c:56
dictionary params
Definition: halomod_bm.py:27
#define CCL_ERROR_EMULATOR_BOUND
Definition: ccl_error.h:23
gsl_interp_accel * accelerator
Definition: ccl_core.h:91
double R
Definition: ccl_power.c:1649
baryons_power_spectrum_t baryons_power_spectrum_method
Definition: ccl_config.h:113
int * status
Definition: ccl_power.c:1650
static double z[8]
double bnode
Definition: ccl_power.c:675
double ccl_Omeganuh2(double a, int N_nu_mass, double *mnu, double T_CMB, gsl_interp_accel *accel, int *status)
static double eh_power(ccl_parameters *params, eh_struct *eh, double k, int wiggled)
Definition: ccl_power.c:836
double sigma8
Definition: ccl_core.h:62
double rsound
Definition: ccl_power.c:664
ccl_cosmology * cosmo
Definition: ccl_power.c:1648
double k_min_lin
Definition: ccl_core.h:113
double bcm_etab
Definition: ccl_core.h:58
double keq
Definition: ccl_power.c:666
#define CCL_ERROR_INCONSISTENT
Definition: ccl_error.h:12
double k_max_nl
Definition: ccl_core.h:116
double ccl_sigma8(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:1777
double alphac
Definition: ccl_power.c:671
static double tsqr_EH(ccl_parameters *params, eh_struct *eh, double k, int wiggled)
Definition: ccl_power.c:804
double Omega_c
Definition: ccl_core.h:19
double R
Definition: ccl_power.c:1655
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
#define PLIN_SPLINE_TYPE
Definition: ccl_constants.h:13
void ccl_cosmology_write_power_class_z(char *filename, ccl_cosmology *cosmo, double z, int *status)
Definition: ccl_power.c:596
double A_SPLINE_MIN_PK
Definition: ccl_params.h:17
static double mode[351]
double k_max_lin
Definition: ccl_core.h:115
ccl_configuration config
Definition: ccl_core.h:125
double bcm_log10Mc
Definition: ccl_core.h:57
double Omega_k
Definition: ccl_core.h:22
double Omega_m
Definition: ccl_core.h:21
double ccl_linear_matter_power(ccl_cosmology *cosmo, double k, double a, int *status)
Definition: ccl_power.c:1506
static double jbes0(double x)
Definition: ccl_power.c:768
double A_SPLINE_MINLOG_PK
Definition: ccl_params.h:16
static void ccl_run_class(ccl_cosmology *cosmo, struct file_content *fc, struct precision *pr, struct background *ba, struct thermo *th, struct perturbs *pt, struct transfers *tr, struct primordial *pm, struct spectra *sp, struct nonlinear *nl, struct lensing *le, struct output *op, int *init_arr, int *status)
Definition: ccl_power.c:160
double betab
Definition: ccl_power.c:674
emulator_neutrinos_t emulator_neutrinos_method
Definition: ccl_config.h:116
#define PNL_SPLINE_TYPE
Definition: ccl_constants.h:12
ccl_data data
Definition: ccl_core.h:126
static double w[2][28][111]
Definition: ccl_emu17.c:33
static double tkEH_c(eh_struct *eh, double k)
Definition: ccl_power.c:758
int * status
Definition: ccl_power.c:1656
double wa
Definition: ccl_core.h:29
static void ccl_cosmology_compute_power_class(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:378
static void ccl_cosmology_compute_power_bbks(ccl_cosmology *cosmo, int *status)
Definition: ccl_power.c:1017