Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
ccl_background.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <string.h>
5 
6 #include <gsl/gsl_errno.h>
7 #include <gsl/gsl_odeiv2.h>
8 #include <gsl/gsl_spline.h>
9 #include <gsl/gsl_integration.h>
10 #include <gsl/gsl_roots.h>
11 
12 #include "ccl.h"
13 #include "ccl_params.h"
14 
15 /* --------- ROUTINE: h_over_h0 ---------
16 INPUT: scale factor, cosmology
17 TASK: Compute E(a)=H(a)/H0
18 */
19 static double h_over_h0(double a, ccl_cosmology * cosmo, int *status)
20 {
21  // Check if massive neutrinos are present - if not, we don't need to
22  // compute their contribution
23  double Om_mass_nu;
24  if ((cosmo->params.N_nu_mass)>1e-12) {
25  Om_mass_nu = ccl_Omeganuh2(
26  a, cosmo->params.N_nu_mass, cosmo->params.mnu, cosmo->params.T_CMB,
27  cosmo->data.accelerator, status) / (cosmo->params.h) / (cosmo->params.h);
28  ccl_check_status(cosmo, status);
29  }
30  else {
31  Om_mass_nu = 0;
32  }
33 
34  /* Calculate h^2 using the formula (eqn 2 in the CCL paper):
35  E(a)^2 = Omega_m a^-3 +
36  Omega_l a^(-3*(1+w0+wa)) exp(3*wa*(a-1)) +
37  Omega_k a^-2 +
38  (Omega_g + Omega_n_rel) a^-4 +
39  Om_mass_nu
40  */
41  return sqrt(
42  (cosmo->params.Omega_m +
43  cosmo->params.Omega_l *
44  pow(a,-3*(cosmo->params.w0+cosmo->params.wa)) *
45  exp(3*cosmo->params.wa*(a-1)) +
46  cosmo->params.Omega_k * a +
47  (cosmo->params.Omega_g + cosmo->params.Omega_n_rel) / a +
48  Om_mass_nu * a*a*a) / (a*a*a));
49 }
50 
51 /* --------- ROUTINE: ccl_omega_x ---------
52 INPUT: cosmology object, scale factor, species label
53 TASK: Compute the density relative to critical, Omega(a) for a given species.
54 Possible values for "label":
55 ccl_species_crit_label <- critical (physical)
56 ccl_species_m_label <- matter
57 ccl_species_l_label <- DE
58 ccl_species_g_label <- radiation
59 ccl_species_k_label <- curvature
60 ccl_species_ur_label <- massless neutrinos
61 ccl_species_nu_label <- massive neutrinos
62 */
63 double ccl_omega_x(ccl_cosmology * cosmo, double a, ccl_species_x_label label, int *status)
64 {
65  // If massive neutrinos are present, compute the phase-space integral and
66  // get OmegaNuh2. If not, set OmegaNuh2 to zero.
67  double OmNuh2;
68  if ((cosmo->params.N_nu_mass) > 0.0001) {
69  // Call the massive neutrino density function just once at this redshift.
70  OmNuh2 = ccl_Omeganuh2(a, cosmo->params.N_nu_mass, cosmo->params.mnu,
71  cosmo->params.T_CMB, cosmo->data.accelerator, status);
72  ccl_check_status(cosmo, status);
73  }
74  else {
75  OmNuh2 = 0.;
76  }
77 
78  double hnorm = h_over_h0(a, cosmo, status);
79 
80  switch(label) {
82  return 1.;
83  case ccl_species_m_label :
84  return cosmo->params.Omega_m / (a*a*a) / hnorm / hnorm;
85  case ccl_species_l_label :
86  return
87  cosmo->params.Omega_l *
88  pow(a,-3 * (1 + cosmo->params.w0 + cosmo->params.wa)) *
89  exp(3 * cosmo->params.wa * (a-1)) / hnorm / hnorm;
90  case ccl_species_g_label :
91  return cosmo->params.Omega_g / (a*a*a*a) / hnorm / hnorm;
92  case ccl_species_k_label :
93  return cosmo->params.Omega_k / (a*a) / hnorm / hnorm;
95  return cosmo->params.Omega_n_rel / (a*a*a*a) / hnorm / hnorm;
97  return OmNuh2 / (cosmo->params.h) / (cosmo->params.h) / hnorm / hnorm;
98  default:
99  *status = CCL_ERROR_PARAMETERS;
101  cosmo, "ccl_background.c: ccl_omega_x(): Species %d not supported\n", label);
102  return NAN;
103  }
104 }
105 
106 /* --------- ROUTINE: ccl_rho_x ---------
107 INPUT: cosmology object, scale factor, species label
108 TASK: Compute rho_x(a), with x defined by species label.
109 Possible values for "label":
110 ccl_species_crit_label <- critical (physical)
111 ccl_species_m_label <- matter (physical)
112 ccl_species_l_label <- DE (physical)
113 ccl_species_g_label <- radiation (physical)
114 ccl_species_k_label <- curvature (physical)
115 ccl_species_ur_label <- massless neutrinos (physical)
116 ccl_species_nu_label <- massive neutrinos (physical)
117 */
118 double ccl_rho_x(ccl_cosmology * cosmo, double a, ccl_species_x_label label, int is_comoving, int *status)
119 {
120  double comfac;
121  if (is_comoving) {
122  comfac = a*a*a;
123  } else {
124  comfac = 1.0;
125  }
126  double hnorm = h_over_h0(a, cosmo, status);
127  double rhocrit =
128  RHO_CRITICAL *
129  (cosmo->params.h) *
130  (cosmo->params.h) * hnorm * hnorm * comfac;
131 
132  return rhocrit * ccl_omega_x(cosmo, a, label, status);
133 }
134 
135 // Structure to hold parameters of chi_integrand
136 typedef struct {
138  int * status;
139 } chipar;
140 
141 /* --------- ROUTINE: chi_integrand ---------
142 INPUT: scale factor
143 TASK: compute the integrand of the comoving distance
144 */
145 static double chi_integrand(double a, void * params_void)
146 {
147  ccl_cosmology * cosmo = ((chipar *)params_void)->cosmo;
148  int *status = ((chipar *)params_void)->status;
149 
150  return CLIGHT_HMPC/(a*a*h_over_h0(a, cosmo, status));
151 }
152 
153 /* --------- ROUTINE: growth_ode_system ---------
154 INPUT: scale factor
155 TASK: Define the ODE system to be solved in order to compute the growth (of the density)
156 */
157 static int growth_ode_system(double a,const double y[],double dydt[],void *params)
158 {
159  int status = 0;
161 
162  double hnorm=h_over_h0(a,cosmo, &status);
163  double om=ccl_omega_x(cosmo, a, ccl_species_m_label, &status);
164 
165  dydt[0]=y[1]/(a*a*a*hnorm);
166  dydt[1]=1.5*hnorm*a*om*y[0];
167 
168  return status;
169 }
170 
171 /* --------- ROUTINE: df_integrand ---------
172 INPUT: scale factor, spline object
173 TASK: Compute integrand from modified growth function
174 */
175 static double df_integrand(double a,void * spline_void)
176 {
177  if(a<=0)
178  return 0;
179  else {
180  gsl_spline *df_a_spline=(gsl_spline *)spline_void;
181 
182  return gsl_spline_eval(df_a_spline,a,NULL)/a;
183  }
184 }
185 
186 /* --------- ROUTINE: growth_factor_and_growth_rate ---------
187 INPUT: scale factor, cosmology
188 TASK: compute the growth (D(z)) and the growth rate, logarithmic derivative (f?)
189 */
190 
191 static int growth_factor_and_growth_rate(double a,double *gf,double *fg,ccl_cosmology *cosmo, int *stat)
192 {
193  if(a<EPS_SCALEFAC_GROWTH) {
194  *gf=a;
195  *fg=1;
196  return 0;
197  }
198  else {
199  int gslstatus;
200  double y[2];
201  double ainit=EPS_SCALEFAC_GROWTH;
202  gsl_odeiv2_system sys={growth_ode_system,NULL,2,cosmo};
203  gsl_odeiv2_driver *d=
204  gsl_odeiv2_driver_alloc_y_new(&sys,gsl_odeiv2_step_rkck,0.1*EPS_SCALEFAC_GROWTH,0,ccl_gsl->ODE_GROWTH_EPSREL);
205 
206  y[0]=EPS_SCALEFAC_GROWTH;
208  h_over_h0(EPS_SCALEFAC_GROWTH,cosmo, stat);
209 
210  gslstatus=gsl_odeiv2_driver_apply(d,&ainit,a,y);
211  gsl_odeiv2_driver_free(d);
212 
213  if(gslstatus != GSL_SUCCESS) {
214  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: growth_factor_and_growth_rate():");
215  return NAN;
216  }
217 
218  *gf=y[0];
219  *fg=y[1]/(a*a*h_over_h0(a,cosmo, stat)*y[0]);
220  return 0;
221  }
222 }
223 
224 
225 /* --------- ROUTINE: compute_chi ---------
226 INPUT: scale factor, cosmology
227 OUTPUT: chi -> radial comoving distance
228 TASK: compute radial comoving distance at a
229 */
230 static void compute_chi(double a, ccl_cosmology *cosmo, double * chi, int * stat)
231 {
232  int gslstatus;
233  double result;
234  chipar p;
235 
236  p.cosmo=cosmo;
237  p.status=stat;
238 
239  gsl_integration_cquad_workspace * workspace = gsl_integration_cquad_workspace_alloc(ccl_gsl->N_ITERATION);
240  gsl_function F;
241  F.function = &chi_integrand;
242  F.params = &p;
243  //TODO: CQUAD is great, but slower than other methods. This could be sped up if it becomes an issue.
244  gslstatus=gsl_integration_cquad(
245  &F, a, 1.0, 0.0, ccl_gsl->INTEGRATION_DISTANCE_EPSREL, workspace, &result, NULL, NULL);
246  *chi=result/cosmo->params.h;
247  gsl_integration_cquad_workspace_free(workspace);
248 
249  if (gslstatus != GSL_SUCCESS) {
250  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: compute_chi():");
251  *stat = CCL_ERROR_COMPUTECHI;
252  }
253 }
254 
255 
256 //Root finding for a(chi)
257 typedef struct {
258  double chi;
260  int * status;
261 } Fpar;
262 
263 static double fzero(double a,void *params)
264 {
265  double chi,chia,a_use=a;
266 
267  chi=((Fpar *)params)->chi;
268  compute_chi(a_use,((Fpar *)params)->cosmo,&chia, ((Fpar *)params)->status);
269 
270  return chi-chia;
271 }
272 
273 static double dfzero(double a,void *params)
274 {
275  ccl_cosmology *cosmo=((Fpar *)params)->cosmo;
276  int *stat = ((Fpar *)params)->status;
277 
278  chipar p;
279  p.cosmo=cosmo;
280  p.status=stat;
281 
282  return chi_integrand(a,&p)/cosmo->params.h;
283 }
284 
285 static void fdfzero(double a,void *params,double *f,double *df)
286 {
287  *f=fzero(a,params);
288  *df=dfzero(a,params);
289 }
290 
291 /* --------- ROUTINE: a_of_chi ---------
292 INPUT: comoving distance chi, cosmology, stat, a_old, gsl_root_fdfsolver
293 OUTPUT: scale factor
294 TASK: compute the scale factor that corresponds to a given comoving distance chi
295 Note: This routine uses a root solver to find an a such that compute_chi(a) = chi.
296 The root solver uses the derivative of compute_chi (which is chi_integrand) and
297 the value itself.
298 */
299 static void a_of_chi(double chi, ccl_cosmology *cosmo, int* stat, double *a_old, gsl_root_fdfsolver *s)
300 {
301  if(chi==0) {
302  *a_old=1;
303  }
304  else {
305  Fpar p;
306  gsl_function_fdf FDF;
307  double a_previous,a_current=*a_old;
308 
309  p.cosmo=cosmo;
310  p.chi=chi;
311  p.status=stat;
312  FDF.f=&fzero;
313  FDF.df=&dfzero;
314  FDF.fdf=&fdfzero;
315  FDF.params=&p;
316  gsl_root_fdfsolver_set(s,&FDF,a_current);
317 
318  int iter=0, gslstatus;
319  do {
320  iter++;
321  gslstatus=gsl_root_fdfsolver_iterate(s);
322  if(gslstatus!=GSL_SUCCESS) ccl_raise_gsl_warning(gslstatus, "ccl_background.c: a_of_chi():");
323  a_previous=a_current;
324  a_current=gsl_root_fdfsolver_root(s);
325  gslstatus=gsl_root_test_delta(a_current, a_previous, 0, ccl_gsl->ROOT_EPSREL);
326  } while(gslstatus==GSL_CONTINUE && iter <= ccl_gsl->ROOT_N_ITERATION);
327 
328  *a_old=a_current;
329 
330  // Allows us to pass a status to h_over_h0 for the neutrino integral calculation.
331  if(gslstatus==GSL_SUCCESS) {
332  *stat = *(p.status);
333  }
334  else {
335  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: a_of_chi():");
336  *stat = CCL_ERROR_COMPUTECHI;
337  }
338  }
339 }
340 
341 /* ----- ROUTINE: ccl_cosmology_compute_distances ------
342 INPUT: cosmology
343 TASK: if not already there, make a table of comoving distances and of E(a)
344 */
345 
347 {
348 
349  //Do nothing if everything is computed already
350  if(cosmo->computed_distances)
351  return;
352 
353  if(ccl_splines->A_SPLINE_MAX>1.) {
354  *status = CCL_ERROR_COMPUTECHI;
355  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
356  return;
357  }
358 
359  // Create logarithmically and then linearly-spaced values of the scale factor
364  // Allocate arrays for all three of E(a), chi(a), and a(chi)
365  double *E_a = malloc(sizeof(double)*na);
366  double *chi_a = malloc(sizeof(double)*na);
367  // Allocate E(a) and chi(a) splines
368  gsl_spline * E = gsl_spline_alloc(A_SPLINE_TYPE, na);
369  gsl_spline * chi = gsl_spline_alloc(A_SPLINE_TYPE, na);
370  // a(chi) spline allocated below
371 
372  //Check for too little memory
373  if (a==NULL || E_a==NULL || chi_a==NULL){
374  *status=CCL_ERROR_MEMORY;
375 
376  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): ran out of memory\n");
377  }
378 
379  //Check for messed up scale factor conditions
380  if (!*status){
381  if ((fabs(a[0]-ccl_splines->A_SPLINE_MINLOG)>1e-5) ||
382  (fabs(a[na-1]-ccl_splines->A_SPLINE_MAX)>1e-5) ||
383  (a[na-1]>1.0)) {
384  *status = CCL_ERROR_LINSPACE;
385  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): Error creating first logarithmic and then linear spacing in a\n");
386  }
387  }
388 
389  // Fill in E(a) - note, this step cannot change the status variable
390  if (!*status)
391  for (int i=0; i<na; i++)
392  E_a[i] = h_over_h0(a[i], cosmo, status);
393 
394  // Create a E(a) spline
395  if (!*status){
396  if (gsl_spline_init(E, a, E_a, na)){
397  *status = CCL_ERROR_SPLINE;
398  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): Error creating E(a) spline\n");
399  }
400  }
401 
402  // Compute chi(a)
403  if (!*status){
404  for (int i=0; i<na; i++)
405  compute_chi(a[i], cosmo, &chi_a[i], status);
406  if (*status){
407  *status = CCL_ERROR_INTEG;
408  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): chi(a) integration error \n");
409  }
410  }
411 
412  // Initialize chi(a) spline
413  if (!*status){
414  if (gsl_spline_init(chi, a, chi_a, na)){//in Mpc
415  *status = CCL_ERROR_SPLINE;
416  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): Error creating chi(a) spline\n");
417  }
418  }
419 
420  if (*status){//If there was an error, free the GSL splines and return
421  gsl_spline_free(E); //Note: you are allowed to call gsl_free() on NULL
422  gsl_spline_free(chi);
423  }
424 
425  // Set up the boundaries for the a(chi) spline
426  double dchi, chi0, chif, a0, af;
427  if(!*status){
428  dchi=5.;
429  chi0=chi_a[na-1];
430  chif=chi_a[0];
431  a0=a[na-1];
432  af=a[0];
433  }
434 
435  //TODO: The interval in chi (5. Mpc) should be made a macro
436  free(a); //Free these, in preparation for making a(chi) splines
437  free(E_a);
438  free(chi_a);
439  //Note: you are allowed to call free() on NULL
440 
442  //Below here na (length of some arrays) changes, so this function has to be split at this point.
444 
445  na = (int)((chif-chi0)/dchi);
446  dchi = (chif-chi0)/na; // <=5, since na is an integer
447  //Allocate new arrays for a and chi(a)
448  chi_a = ccl_linear_spacing(chi0, chif, na);
449  a = malloc(sizeof(double)*na);
450  //Allocate space for GSL root finders
451  const gsl_root_fdfsolver_type *T=gsl_root_fdfsolver_newton;
452  gsl_root_fdfsolver *s=gsl_root_fdfsolver_alloc(T);
453  gsl_spline *achi;
454 
455  //Check for too little memory
456  if (!*status){
457  achi=gsl_spline_alloc(A_SPLINE_TYPE, na);
458  if (a==NULL || chi_a==NULL){
459  *status=CCL_ERROR_MEMORY;
460  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): ran out of memory\n");
461  }else if(fabs(chi_a[0]-chi0)>1e-5 || fabs(chi_a[na-1]-chif)>1e-5) { //Check for messed up chi conditions
462  *status = CCL_ERROR_LINSPACE;
463  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): Error creating linear spacing in chi\n");
464  }
465  }
466 
467  // Calculate a(chi)
468  if (!*status){
469  a[0]=a0; a[na-1]=af;
470  for(int i=1;i<na-1;i++) {
471  // we are using the previous value as a guess here to help the root finder
472  // as long as we use small steps in a this should be fine
473  a_of_chi(chi_a[i],cosmo, status, &a0, s);
474  a[i]=a0;
475  }
476  if(*status) {
477  *status = CCL_ERROR_ROOT;
478  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): a(chi) root-finding error \n");
479  }
480  }
481 
482  // Initialize the a(chi) spline
483  if (!*status){
484  if(gsl_spline_init(achi, chi_a, a, na)){
485  *status = CCL_ERROR_SPLINE;
486  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): Error creating a(chi) spline\n");
487  }
488  }
489 
490  free(a);
491  free(chi_a); //Note: you are allowed to call free() on NULL
492  gsl_root_fdfsolver_free(s);
493  if (*status){//If there was an error, free the GSL splines and return
494  gsl_spline_free(E); //Note: you are allowed to call gsl_free() on NULL
495  gsl_spline_free(chi);
496  gsl_spline_free(achi);
497  return;
498  }
499 
500  //If there were no errors, attach the splines to the cosmo struct and end the function.
501  if(cosmo->data.accelerator==NULL)
502  cosmo->data.accelerator=gsl_interp_accel_alloc();
503  cosmo->data.E = E;
504  cosmo->data.chi = chi;
505  cosmo->data.achi = achi;
506  cosmo->computed_distances = true;
507 }
508 
509 
510 /* ----- ROUTINE: ccl_cosmology_compute_growth ------
511 INPUT: cosmology
512 TASK: if not already there, make a table of growth function and growth rate
513  normalize growth to input parameter growth0
514 */
515 
517 {
518 
519  // This is not valid for massive neutrinos; if we have massive neutrinos, exit.
520  if (cosmo->params.N_nu_mass>0){
521  *status = CCL_ERROR_NOT_IMPLEMENTED;
522  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Support for the growth rate in cosmologies with massive neutrinos is not yet implemented.\n");
523  return;
524  }
525 
526  if(cosmo->computed_growth)
527  return;
528 
529  // Create logarithmically and then linearly-spaced values of the scale factor
530  int chistatus = 0, na = ccl_splines->A_SPLINE_NA+ccl_splines->A_SPLINE_NLOG-1;
532  if (a==NULL ||
533  (fabs(a[0]-ccl_splines->A_SPLINE_MINLOG)>1e-5) ||
534  (fabs(a[na-1]-ccl_splines->A_SPLINE_MAX)>1e-5) ||
535  (a[na-1]>1.0)
536  ) {
537  free(a);
538  *status = CCL_ERROR_LINSPACE;
539  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error creating logarithmically and then linear spacing in a\n");
540  return;
541  }
542 
543  gsl_integration_cquad_workspace * workspace=NULL;
544  gsl_function F;
545  gsl_spline *df_a_spline=NULL;
546  if(cosmo->params.has_mgrowth) {
547  double *df_arr=malloc(na*sizeof(double));
548  if(df_arr==NULL) {
549  free(a);
550  *status=CCL_ERROR_MEMORY;
551  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): ran out of memory\n");
552  return;
553  }
554  //Generate spline for Delta f(z) that we will then interpolate into an array of a
555  gsl_spline *df_z_spline=gsl_spline_alloc(A_SPLINE_TYPE,cosmo->params.nz_mgrowth);
556  chistatus=gsl_spline_init(df_z_spline,cosmo->params.z_mgrowth,cosmo->params.df_mgrowth,
557  cosmo->params.nz_mgrowth);
558 
559  if(chistatus) {
560  free(a);
561  free(df_arr);
562  gsl_spline_free(df_z_spline);
563  *status = CCL_ERROR_SPLINE;
564  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error creating Delta f(z) spline\n");
565  return;
566  }
567  for (int i=0; i<na; i++) {
568  if(a[i]>0) {
569  double z=1./a[i]-1.;
570 
571  if(z<=cosmo->params.z_mgrowth[0])
572  df_arr[i]=cosmo->params.df_mgrowth[0];
573  else if(z>cosmo->params.z_mgrowth[cosmo->params.nz_mgrowth-1])
574  df_arr[i]=cosmo->params.df_mgrowth[cosmo->params.nz_mgrowth-1];
575  else
576  chistatus |= gsl_spline_eval_e(df_z_spline,z,NULL,&df_arr[i]);
577  } else {
578  df_arr[i]=0;
579  }
580  }
581  if(chistatus) {
582  free(a);
583  free(df_arr);
584  gsl_spline_free(df_z_spline);
585  *status = CCL_ERROR_SPLINE;
586  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error evaluating Delta f(z) spline\n");
587  return;
588  }
589  gsl_spline_free(df_z_spline);
590 
591  //Generate Delta(f) spline
592  df_a_spline=gsl_spline_alloc(A_SPLINE_TYPE,na);
593  chistatus=gsl_spline_init(df_a_spline,a,df_arr,na);
594  free(df_arr);
595  if (chistatus) {
596  free(a);
597  gsl_spline_free(df_a_spline);
598  *status = CCL_ERROR_SPLINE;
599  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error creating Delta f(a) spline\n");
600  return;
601  }
602 
603  workspace=gsl_integration_cquad_workspace_alloc(ccl_gsl->N_ITERATION);
604  F.function=&df_integrand;
605  F.params=df_a_spline;
606  }
607 
608  // allocate space for y, which will be all three
609  // of E(a), chi(a), D(a) and f(a) in turn.
610  int status_mg=0, gslstatus;
611  double growth0,fgrowth0;
612  double *y = malloc(sizeof(double)*na);
613  if(y==NULL) {
614  free(a);
615  *status=CCL_ERROR_MEMORY;
616  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): ran out of memory\n");
617  return;
618  }
619  double *y2 = malloc(sizeof(double)*na);
620  if(y2==NULL) {
621  free(a);
622  free(y);
623  *status=CCL_ERROR_MEMORY;
624  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_distances(): ran out of memory\n");
625  return;
626  }
627 
628  chistatus|=growth_factor_and_growth_rate(1.,&growth0,&fgrowth0,cosmo, status);
629  for(int i=0; i<na; i++) {
630  chistatus|=growth_factor_and_growth_rate(a[i],&(y[i]),&(y2[i]),cosmo, status);
631  if(cosmo->params.has_mgrowth) {
632  if(a[i]>0) {
633  double df,integ;
634  //Add modification to f
635  gslstatus = gsl_spline_eval_e(df_a_spline,a[i],NULL,&df);
636  if(gslstatus != GSL_SUCCESS) {
637  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_cosmology_compute_growth():");
638  status_mg |= gslstatus;
639  }
640  y2[i]+=df;
641  //Multiply D by exp(-int(df))
642  gslstatus = gsl_integration_cquad(&F,a[i],1.0,0.0,ccl_gsl->INTEGRATION_DISTANCE_EPSREL,workspace,&integ,NULL,NULL);
643  if(gslstatus != GSL_SUCCESS) {
644  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_cosmology_compute_growth():");
645  status_mg |= gslstatus;
646  }
647  y[i]*=exp(-integ);
648  }
649  }
650  y[i]/=growth0;
651  }
652  if(chistatus || status_mg || *status) {
653  free(a);
654  free(y);
655  free(y2);
656  if(df_a_spline!=NULL)
657  gsl_spline_free(df_a_spline);
658  if(workspace!=NULL)
659  gsl_integration_cquad_workspace_free(workspace);
660  if (chistatus) {
661  *status = CCL_ERROR_INTEG;
662  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): integral for linear growth factor didn't converge\n");
663  }
664  if(status_mg) {
665  *status = CCL_ERROR_INTEG;
666  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): integral for MG growth factor didn't converge\n");
667  }
668  return;
669  }
670 
671  if(cosmo->params.has_mgrowth) {
672  gsl_spline_free(df_a_spline);
673  gsl_integration_cquad_workspace_free(workspace);
674  }
675 
676  gsl_spline * growth = gsl_spline_alloc(A_SPLINE_TYPE, na);
677  chistatus = gsl_spline_init(growth, a, y, na);
678  if(chistatus) {
679  free(a);
680  free(y);
681  free(y2);
682  gsl_spline_free(growth);
683  *status = CCL_ERROR_SPLINE;
684  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error creating D(a) spline\n");
685  return;
686  }
687 
688  gsl_spline * fgrowth = gsl_spline_alloc(A_SPLINE_TYPE, na);
689  chistatus = gsl_spline_init(fgrowth, a, y2, na);
690  if(chistatus) {
691  free(a);
692  free(y);
693  free(y2);
694  gsl_spline_free(growth);
695  gsl_spline_free(fgrowth);
696  *status = CCL_ERROR_SPLINE;
697  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_cosmology_compute_growth(): Error creating f(a) spline\n");
698  return;
699  }
700 
701  // Initialize the accelerator which speeds the splines and
702  // assign all the splines we've just made to the structure.
703  if(cosmo->data.accelerator==NULL)
704  cosmo->data.accelerator=gsl_interp_accel_alloc();
705  cosmo->data.growth = growth;
706  cosmo->data.fgrowth = fgrowth;
707  cosmo->data.growth0 = growth0;
708  cosmo->computed_growth = true;
709 
710  free(a);
711  free(y);
712  free(y2);
713 
714  return;
715 }
716 
717 //Expansion rate normalized to 1 today
718 
719 double ccl_h_over_h0(ccl_cosmology * cosmo, double a, int* status)
720 {
721 
722  if(!cosmo->computed_distances) {
723  ccl_cosmology_compute_distances(cosmo,status);
724  ccl_check_status(cosmo, status);
725  }
726 
727  double h_over_h0;
728  int gslstatus = gsl_spline_eval_e(cosmo->data.E, a, cosmo->data.accelerator,&h_over_h0);
729  if(gslstatus != GSL_SUCCESS) {
730  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_h_over_h0():");
731  *status = gslstatus;
732  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_h_over_h0(): Scale factor outside interpolation range.\n");
733  return NAN;
734  }
735 
736  return h_over_h0;
737 }
738 
739 
740 void ccl_h_over_h0s(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
741 {
742  int _status;
743 
744  for (int i=0; i<na; i++) {
745  _status = 0;
746  output[i] = ccl_h_over_h0(cosmo, a[i], &_status);
747  *status |= _status;
748  }
749 }
750 
751 // Distance-like function examples, all in Mpc
752 double ccl_comoving_radial_distance(ccl_cosmology * cosmo, double a, int * status)
753 {
754  if((a > (1.0 - 1.e-8)) && (a<=1.0)) {
755  return 0.;
756  }
757  else if(a>1.) {
758  *status = CCL_ERROR_COMPUTECHI;
759  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
760  ccl_check_status(cosmo,status);
761  return NAN;
762  }
763  else {
764  if(!cosmo->computed_distances) {
765  ccl_cosmology_compute_distances(cosmo, status);
766  ccl_check_status(cosmo,status);
767  }
768 
769  double crd;
770  int gslstatus = gsl_spline_eval_e(cosmo->data.chi, a, cosmo->data.accelerator, &crd);
771  if(gslstatus != GSL_SUCCESS) {
772  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_comoving_radial_distance():");
773  *status = gslstatus;
774  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_comoving_radial_distance(): Scale factor outside interpolation range.\n");
775  return NAN;
776  }
777  return crd;
778  }
779 }
780 
781 void ccl_comoving_radial_distances(ccl_cosmology * cosmo, int na, double a[], double output[], int* status)
782 {
783  int _status;
784 
785  for (int i=0; i<na; i++) {
786  _status = 0;
787  output[i] = ccl_comoving_radial_distance(cosmo, a[i], &_status);
788  *status |= _status;
789  }
790 }
791 
792 double ccl_sinn(ccl_cosmology *cosmo, double chi, int *status)
793 {
795  // { sin(x) , if k==1
796  // sinn(x)={ x , if k==0
797  // { sinh(x) , if k==-1
798  switch(cosmo->params.k_sign) {
799  case -1:
800  return sinh(cosmo->params.sqrtk * chi) / cosmo->params.sqrtk;
801  case 1:
802  return sin(cosmo->params.sqrtk*chi) / cosmo->params.sqrtk;
803  case 0:
804  return chi;
805  default:
806  *status = CCL_ERROR_PARAMETERS;
807  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_sinn: ill-defined cosmo->params.k_sign = %d",
808  cosmo->params.k_sign);
809  return NAN;
810  }
811 }
812 
813 double ccl_comoving_angular_distance(ccl_cosmology * cosmo, double a, int* status)
814 {
815  if((a > (1.0 - 1.e-8)) && (a<=1.0)) {
816  return 0.;
817  }
818  else if(a>1.) {
819  *status = CCL_ERROR_COMPUTECHI;
820  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
821  ccl_check_status(cosmo,status);
822  return NAN;
823  }
824  else {
825  if (!cosmo->computed_distances) {
826  ccl_cosmology_compute_distances(cosmo, status);
827  ccl_check_status(cosmo, status);
828  }
829 
830  double chi;
831  int gslstatus = gsl_spline_eval_e(cosmo->data.chi, a,
832  cosmo->data.accelerator,&chi);
833  if(gslstatus != GSL_SUCCESS) {
834  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_comoving_angular_distance():");
835  *status |= gslstatus;
836  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_comoving_angular_distance(): Scale factor outside interpolation range.\n");
837  return NAN;
838  }
839  return ccl_sinn(cosmo,chi,status);
840  }
841 }
842 
844  double output[], int* status)
845 {
846  int _status;
847 
848  for (int i=0; i < na; i++) {
849  _status = 0;
850  output[i] = ccl_comoving_angular_distance(cosmo, a[i], &_status);
851  *status |= _status;
852  }
853 }
854 
855 double ccl_luminosity_distance(ccl_cosmology * cosmo, double a, int* status)
856 {
857  return ccl_comoving_angular_distance(cosmo, a, status) / a;
858 }
859 
860 void ccl_luminosity_distances(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
861 {
862  int _status;
863 
864  for (int i=0; i<na; i++) {
865  _status = 0;
866  output[i] = ccl_luminosity_distance(cosmo, a[i], &_status);
867  *status |= _status;
868  }
869 }
870 
871 double ccl_distance_modulus(ccl_cosmology * cosmo, double a, int* status)
872 {
873  if((a > (1.0 - 1.e-8)) && (a<=1.0)) {
874  *status = CCL_ERROR_COMPUTECHI;
875  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: distance_modulus undefined for a=1.\n");
876  ccl_check_status(cosmo,status);
877  return NAN;
878  } else if(a>1.) {
879  *status = CCL_ERROR_COMPUTECHI;
880  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
881  ccl_check_status(cosmo,status);
882  return NAN;
883  } else {
884  if (!cosmo->computed_distances) {
885  ccl_cosmology_compute_distances(cosmo, status);
886  ccl_check_status(cosmo, status);
887  }
888  /* distance modulus = 5 * log10(d) - 5
889  Since d in CCL is in Mpc, you get
890  5*log10(10^6) - 5 = 30 - 5 = 25
891  for the constant.
892  */
893  return 5 * log10(ccl_luminosity_distance(cosmo, a, status)) + 25;
894  }
895 }
896 
897 
898 void ccl_distance_moduli(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
899 {
900  int _status;
901 
902  for (int i=0; i<na; i++) {
903  _status = 0;
904  output[i] = ccl_distance_modulus(cosmo, a[i], &_status);
905  *status |= _status;
906  }
907 }
908 
909 //Scale factor for a given distance
910 double ccl_scale_factor_of_chi(ccl_cosmology * cosmo, double chi, int * status)
911 {
912  if((chi < 1.e-8) && (chi>=0.)) {
913  return 1.;
914  }
915  else if(chi<0.) {
916  *status = CCL_ERROR_COMPUTECHI;
917  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: distance cannot be smaller than 0.\n");
918  ccl_check_status(cosmo,status);
919  return NAN;
920  }
921  else {
922  if (!cosmo->computed_distances) {
923  ccl_cosmology_compute_distances(cosmo,status);
924  ccl_check_status(cosmo,status);
925  }
926  double a;
927  int gslstatus = gsl_spline_eval_e(cosmo->data.achi, chi,cosmo->data.accelerator_achi, &a);
928  if(gslstatus != GSL_SUCCESS) {
929  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_scale_factor_of_chi():");
930  *status |= gslstatus;
931  }
932  return a;
933  }
934 }
935 
936 //
937 void ccl_scale_factor_of_chis(ccl_cosmology * cosmo, int nchi, double chi[], double output[], int * status)
938 {
939  int _status;
940 
941  for (int i=0; i<nchi; i++) {
942  _status = 0;
943  output[i] = ccl_scale_factor_of_chi(cosmo, chi[i], &_status);
944  *status |= _status;
945  }
946 }
947 
948 double ccl_growth_factor(ccl_cosmology * cosmo, double a, int * status)
949 {
950  if(a==1.){
951  return 1.;
952  }
953  else if(a>1.) {
954  *status = CCL_ERROR_COMPUTECHI;
955  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
956  ccl_check_status(cosmo,status);
957  return NAN;
958  }
959  else {
960  if (!cosmo->computed_growth) {
961  ccl_cosmology_compute_growth(cosmo, status);
962  ccl_check_status(cosmo, status);
963  }
964  if (*status!= CCL_ERROR_NOT_IMPLEMENTED) {
965  double D;
966  int gslstatus = gsl_spline_eval_e(cosmo->data.growth, a, cosmo->data.accelerator,&D);
967  if(gslstatus != GSL_SUCCESS) {
968  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_growth_factor():");
969  *status |= gslstatus;
970  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_growth_factor(): Scale factor outside interpolation range.\n");
971  return NAN;
972  }
973  return D;
974  }
975  else {
976  return NAN;
977  }
978  }
979 }
980 
981 void ccl_growth_factors(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
982 {
983  int _status;
984 
985  for (int i=0; i<na; i++) {
986  _status = 0;
987  output[i] = ccl_growth_factor(cosmo, a[i], &_status);
988  *status |= _status;
989  }
990 }
991 
992 double ccl_growth_factor_unnorm(ccl_cosmology * cosmo, double a, int * status)
993 {
994 
995  if (!cosmo->computed_growth) {
996  ccl_cosmology_compute_growth(cosmo, status);
997  ccl_check_status(cosmo, status);
998  }
999 
1000  if (*status != CCL_ERROR_NOT_IMPLEMENTED) {
1001  return cosmo->data.growth0 * ccl_growth_factor(cosmo, a, status);
1002  } else {
1003  return NAN;
1004  }
1005 }
1006 
1007 void ccl_growth_factors_unnorm(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
1008 {
1009  int _status;
1010 
1011  for (int i=0; i<na; i++) {
1012  _status = 0;
1013  output[i] = ccl_growth_factor_unnorm(cosmo, a[i], &_status);
1014  *status |= _status;
1015  }
1016 }
1017 
1018 double ccl_growth_rate(ccl_cosmology * cosmo, double a, int * status)
1019 {
1020  if(a>1.) {
1021  *status = CCL_ERROR_COMPUTECHI;
1022  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: scale factor cannot be larger than 1.\n");
1023  ccl_check_status(cosmo,status);
1024  return NAN;
1025  } else {
1026  if (!cosmo->computed_growth) {
1027  ccl_cosmology_compute_growth(cosmo, status);
1028  ccl_check_status(cosmo, status);
1029  }
1030  if(*status != CCL_ERROR_NOT_IMPLEMENTED) {
1031  double g;
1032  int gslstatus = gsl_spline_eval_e(cosmo->data.fgrowth, a, cosmo->data.accelerator,&g);
1033  if(gslstatus != GSL_SUCCESS) {
1034  ccl_raise_gsl_warning(gslstatus, "ccl_background.c: ccl_growth_rate():");
1035  *status |= gslstatus;
1036  ccl_cosmology_set_status_message(cosmo, "ccl_background.c: ccl_growth_rate(): Scale factor outside interpolation range.\n");
1037  return NAN;
1038  }
1039  return g;
1040  } else {
1041  return NAN;
1042  }
1043  }
1044 }
1045 
1046 void ccl_growth_rates(ccl_cosmology * cosmo, int na, double a[], double output[], int * status)
1047 {
1048  int _status;
1049 
1050  for (int i=0; i<na; i++) {
1051  _status = 0;
1052  output[i] = ccl_growth_rate(cosmo, a[i], &_status);
1053  *status |= _status;
1054  }
1055 }
static double dfzero(double a, void *params)
#define CCL_ERROR_INTEG
Definition: ccl_error.h:15
double Omega_g
Definition: ccl_core.h:53
void ccl_growth_rates(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double chi
static double chi_integrand(double a, void *params_void)
static double df_integrand(double a, void *spline_void)
void ccl_growth_factors_unnorm(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double ccl_luminosity_distance(ccl_cosmology *cosmo, double a, int *status)
double * df_mgrowth
Definition: ccl_core.h:70
void ccl_raise_gsl_warning(int gslstatus, const char *msg,...)
Definition: ccl_error.c:75
double growth0
Definition: ccl_core.h:81
void ccl_growth_factors(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double * mnu
Definition: ccl_core.h:40
#define CCL_ERROR_NOT_IMPLEMENTED
Definition: ccl_error.h:25
double ccl_omega_x(ccl_cosmology *cosmo, double a, ccl_species_x_label label, int *status)
bool has_mgrowth
Definition: ccl_core.h:67
ccl_parameters params
Definition: ccl_core.h:124
ccl_species_x_label
Definition: ccl_background.h:8
void ccl_check_status(ccl_cosmology *cosmo, int *status)
Definition: ccl_error.c:88
double * ccl_linlog_spacing(double xminlog, double xmin, double xmax, int Nlin, int Nlog)
Definition: ccl_utils.c:43
#define CLIGHT_HMPC
Definition: ccl_constants.h:33
void ccl_scale_factor_of_chis(ccl_cosmology *cosmo, int nchi, double chi[], double output[], int *status)
#define A_SPLINE_TYPE
Definition: ccl_constants.h:7
ccl_cosmology * cosmo
ccl_spline_params * ccl_splines
Definition: ccl_core.c:47
CCL_BEGIN_DECLS double * ccl_linear_spacing(double xmin, double xmax, int N)
Definition: ccl_utils.c:14
double h
Definition: ccl_core.h:33
void ccl_luminosity_distances(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double w0
Definition: ccl_core.h:28
double A_SPLINE_MINLOG
Definition: ccl_params.h:19
double Omega_l
Definition: ccl_core.h:63
#define CCL_ERROR_SPLINE
Definition: ccl_error.h:13
void ccl_h_over_h0s(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
void ccl_comoving_angular_distances(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double * z_mgrowth
Definition: ccl_core.h:69
void ccl_distance_moduli(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
double INTEGRATION_DISTANCE_EPSREL
Definition: ccl_params.h:64
double ccl_growth_factor(ccl_cosmology *cosmo, double a, int *status)
double ROOT_EPSREL
Definition: ccl_params.h:74
#define CCL_ERROR_LINSPACE
Definition: ccl_error.h:11
void ccl_cosmology_compute_distances(ccl_cosmology *cosmo, int *status)
void ccl_cosmology_set_status_message(ccl_cosmology *cosmo, const char *status_message,...)
Definition: ccl_core.c:792
ccl_gsl_params * ccl_gsl
Definition: ccl_core.c:48
Grid< NDIM, T > sqrt(Grid< NDIM, T > lhs)
Definition: grid.h:231
double A_SPLINE_MAX
Definition: ccl_params.h:18
gsl_interp_accel * accelerator_achi
Definition: ccl_core.h:92
double ccl_rho_x(ccl_cosmology *cosmo, double a, ccl_species_x_label label, int is_comoving, int *status)
static double h_over_h0(double a, ccl_cosmology *cosmo, int *status)
gsl_spline * chi
Definition: ccl_core.h:82
double sqrtk
Definition: ccl_core.h:23
int * status
double ODE_GROWTH_EPSREL
Definition: ccl_params.h:78
static void a_of_chi(double chi, ccl_cosmology *cosmo, int *stat, double *a_old, gsl_root_fdfsolver *s)
gsl_spline * E
Definition: ccl_core.h:85
#define CCL_ERROR_MEMORY
Definition: ccl_error.h:10
double Omega_n_rel
Definition: ccl_core.h:43
double T_CMB
Definition: ccl_core.h:54
int * status
size_t N_ITERATION
Definition: ccl_params.h:55
static int growth_ode_system(double a, const double y[], double dydt[], void *params)
dictionary params
Definition: halomod_bm.py:27
gsl_spline * achi
Definition: ccl_core.h:86
double ccl_sinn(ccl_cosmology *cosmo, double chi, int *status)
gsl_interp_accel * accelerator
Definition: ccl_core.h:91
gsl_spline * fgrowth
Definition: ccl_core.h:84
bool computed_growth
Definition: ccl_core.h:129
static void fdfzero(double a, void *params, double *f, double *df)
static double z[8]
double ccl_Omeganuh2(double a, int N_nu_mass, double *mnu, double T_CMB, gsl_interp_accel *accel, int *status)
void ccl_comoving_radial_distances(ccl_cosmology *cosmo, int na, double a[], double output[], int *status)
#define CCL_ERROR_COMPUTECHI
Definition: ccl_error.h:18
double ccl_growth_rate(ccl_cosmology *cosmo, double a, int *status)
double ccl_distance_modulus(ccl_cosmology *cosmo, double a, int *status)
static int p
Definition: ccl_emu17.c:25
static void compute_chi(double a, ccl_cosmology *cosmo, double *chi, int *stat)
#define CCL_ERROR_PARAMETERS
Definition: ccl_error.h:21
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
#define CCL_ERROR_ROOT
Definition: ccl_error.h:16
double ccl_comoving_radial_distance(ccl_cosmology *cosmo, double a, int *status)
static double fzero(double a, void *params)
#define EPS_SCALEFAC_GROWTH
int nz_mgrowth
Definition: ccl_core.h:68
void ccl_cosmology_compute_growth(ccl_cosmology *cosmo, int *status)
bool computed_distances
Definition: ccl_core.h:128
double ccl_growth_factor_unnorm(ccl_cosmology *cosmo, double a, int *status)
double Omega_k
Definition: ccl_core.h:22
double ccl_h_over_h0(ccl_cosmology *cosmo, double a, int *status)
double ccl_scale_factor_of_chi(ccl_cosmology *cosmo, double chi, int *status)
double Omega_m
Definition: ccl_core.h:21
ccl_cosmology * cosmo
#define RHO_CRITICAL
Definition: ccl_constants.h:61
gsl_spline * growth
Definition: ccl_core.h:83
ccl_data data
Definition: ccl_core.h:126
static int growth_factor_and_growth_rate(double a, double *gf, double *fg, ccl_cosmology *cosmo, int *stat)
double A_SPLINE_MIN
Definition: ccl_params.h:15
double wa
Definition: ccl_core.h:29
double ccl_comoving_angular_distance(ccl_cosmology *cosmo, double a, int *status)