Fast Methods for Cosmological Simulations
FastSim serves as a tool for quick N-body simulations in modified gravity.
ccl_correlation.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_integration.h>
7 #include <gsl/gsl_errno.h>
8 #include <gsl/gsl_roots.h>
9 #include <gsl/gsl_spline.h>
10 #include <gsl/gsl_sf_bessel.h>
11 #include <gsl/gsl_sf_legendre.h>
12 
13 #include "fftlog.h"
14 
15 #include "ccl.h"
16 #include "ccl_params.h"
17 
18 /*--------ROUTINE: taper_cl ------
19 TASK:n Apply cosine tapering to Cls to reduce aliasing
20 INPUT: number of ell bins for Cl, ell vector, C_ell vector, limits for tapering
21  e.g., ell_limits=[low_ell_limit_lower,low_ell_limit_upper,high_ell_limit_lower,high_ell_limit_upper]
22 */
23 static int taper_cl(int n_ell,double *ell,double *cl, double *ell_limits)
24 {
25 
26  for(int i=0;i<n_ell;i++) {
27  if(ell[i]<ell_limits[0] || ell[i]>ell_limits[3]) {
28  cl[i]=0;//ell outside desirable range
29  continue;
30  }
31  if(ell[i]>=ell_limits[1] && ell[i]<=ell_limits[2])
32  continue;//ell within good ell range
33 
34  if(ell[i]<ell_limits[1])//tapering low ell
35  cl[i]*=cos((ell[i]-ell_limits[1])/(ell_limits[1]-ell_limits[0])*M_PI/2.);
36 
37  if(ell[i]>ell_limits[2])//tapering high ell
38  cl[i]*=cos((ell[i]-ell_limits[2])/(ell_limits[3]-ell_limits[2])*M_PI/2.);
39  }
40 
41  return 0;
42 }
43 
44 /*--------ROUTINE: ccl_tracer_corr_fftlog ------
45 TASK: For a given tracer, get the correlation function
46  Following function takes a function to calculate angular cl as well.
47  By default above function will call it using ccl_angular_cl
48 INPUT: type of tracer, number of theta values to evaluate = NL, theta vector
49  */
51  int n_ell,double *ell,double *cls,
52  int n_theta,double *theta,double *wtheta,
53  int corr_type,int do_taper_cl,double *taper_cl_limits,
54  int *status)
55 {
56  int i;
57  double *l_arr,*cl_arr,*th_arr,*wth_arr;
58 
60  if(l_arr==NULL) {
61  *status=CCL_ERROR_LINSPACE;
62  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_fftlog ran out of memory\n");
63  return;
64  }
65  cl_arr=malloc(ccl_splines->N_ELL_CORR*sizeof(double));
66  if(cl_arr==NULL) {
67  free(l_arr);
68  *status=CCL_ERROR_MEMORY;
69  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_fftlog ran out of memory\n");
70  return;
71  }
72 
73  //Interpolate input Cl into array needed for FFTLog
74  SplPar *cl_spl=ccl_spline_init(n_ell,ell,cls,cls[0],0);
75  if(cl_spl==NULL) {
76  free(l_arr);
77  free(cl_arr);
78  *status=CCL_ERROR_MEMORY;
79  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_fftlog ran out of memory\n");
80  return;
81  }
82 
83  double cl_tilt,l_edge,cl_edge;
84  l_edge=ell[n_ell-1];
85  if((cls[n_ell-1]*cls[n_ell-2]<0) || (cls[n_ell-2]==0)) {
86  cl_tilt=0;
87  cl_edge=0;
88  }
89  else {
90  cl_tilt=log(cls[n_ell-1]/cls[n_ell-2])/log(ell[n_ell-1]/ell[n_ell-2]);
91  cl_edge=cls[n_ell-1];
92  }
93  for(i=0;i<ccl_splines->N_ELL_CORR;i++) {
94  if(l_arr[i]>=l_edge)
95  cl_arr[i]=cl_edge*pow(l_arr[i]/l_edge,cl_tilt);
96  else
97  cl_arr[i]=ccl_spline_eval(l_arr[i],cl_spl);
98  }
99  ccl_spline_free(cl_spl);
100 
101  if (do_taper_cl)
102  taper_cl(ccl_splines->N_ELL_CORR,l_arr,cl_arr,taper_cl_limits);
103 
104  th_arr=malloc(sizeof(double)*ccl_splines->N_ELL_CORR);
105  if(th_arr==NULL) {
106  free(l_arr);
107  free(cl_arr);
108  *status=CCL_ERROR_MEMORY;
109  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_fftlog ran out of memory\n");
110  return;
111  }
112  wth_arr=(double *)malloc(sizeof(double)*ccl_splines->N_ELL_CORR);
113  if(wth_arr==NULL) {
114  free(l_arr); free(cl_arr); free(th_arr);
115  *status=CCL_ERROR_MEMORY;
116  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_fftlog ran out of memory\n");
117  return;
118  }
119 
120  for(i=0;i<ccl_splines->N_ELL_CORR;i++)
121  th_arr[i]=0;
122  //Although set here to 0, theta is modified by FFTlog to obtain the correlation at ~1/l
123 
124  int i_bessel=0;
125  if(corr_type==CCL_CORR_GG) i_bessel=0;
126  if(corr_type==CCL_CORR_GL) i_bessel=2;
127  if(corr_type==CCL_CORR_LP) i_bessel=0;
128  if(corr_type==CCL_CORR_LM) i_bessel=4;
129  fftlog_ComputeXi2D(i_bessel,ccl_splines->N_ELL_CORR,l_arr,cl_arr,th_arr,wth_arr);
130 
131  // Interpolate to output values of theta
132  SplPar *wth_spl=ccl_spline_init(ccl_splines->N_ELL_CORR,th_arr,wth_arr,wth_arr[0],0);
133  for(i=0;i<n_theta;i++)
134  wtheta[i]=ccl_spline_eval(theta[i]*M_PI/180.,wth_spl);
135  ccl_spline_free(wth_spl);
136 
137  free(l_arr); free(cl_arr);
138  free(th_arr); free(wth_arr);
139 
140  return;
141 }
142 
143 typedef struct {
144  int nell;
145  double ell0;
146  double ellf;
147  double cl0;
148  double clf;
151  double tilt0;
152  double tiltf;
154  int i_bessel;
155  double th;
156 } corr_int_par;
157 
158 static double corr_bessel_integrand(double l,void *params)
159 {
160  double cl,jbes;
161  corr_int_par *p=(corr_int_par *)params;
162  double x=l*p->th;
163 
164  if(l<p->ell0) {
165  if(p->extrapol_0)
166  cl=p->cl0*pow(l/p->ell0,p->tilt0);
167  else
168  cl=0;
169  }
170  else if(l>p->ellf) {
171  if(p->extrapol_f)
172  cl=p->clf*pow(l/p->ellf,p->tiltf);
173  else
174  cl=0;
175  }
176  else
177  cl=ccl_spline_eval(l,p->cl_spl);
178 
179  jbes=gsl_sf_bessel_Jn(p->i_bessel,x);
180 
181  return l*jbes*cl;
182 }
183 
185  int n_ell,double *ell,double *cls,
186  int n_theta,double *theta,double *wtheta,
187  int corr_type,int *status)
188 {
189  corr_int_par *cp=malloc(sizeof(corr_int_par));
190  if(cp==NULL) {
191  *status=CCL_ERROR_MEMORY;
192  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_bessel ran out of memory\n");
193  return;
194  }
195 
196  cp->nell=n_ell;
197  cp->ell0=ell[0];
198  cp->ellf=ell[n_ell-1];
199  cp->cl0=cls[0];
200  cp->clf=cls[n_ell-1];
201  cp->cl_spl=ccl_spline_init(n_ell,ell,cls,cls[0],0);
202  if(cp->cl_spl==NULL) {
203  free(cp);
204  *status=CCL_ERROR_MEMORY;
205  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_bessel ran out of memory\n");
206  return;
207  }
208  switch(corr_type) {
209  case CCL_CORR_GG :
210  cp->i_bessel=0;
211  break;
212  case CCL_CORR_GL :
213  cp->i_bessel=2;
214  break;
215  case CCL_CORR_LP :
216  cp->i_bessel=0;
217  break;
218  case CCL_CORR_LM :
219  cp->i_bessel=4;
220  break;
221  }
222 
223  if(cls[0]*cls[1]<=0)
224  cp->extrapol_0=0;
225  else {
226  cp->extrapol_0=1;
227  cp->tilt0=log10(cls[1]/cls[0])/log10(ell[1]/ell[0]);
228  }
229 
230  if(cls[n_ell-2]*cls[n_ell-1]<=0)
231  cp->extrapol_f=0;
232  else {
233  cp->extrapol_f=1;
234  cp->tiltf=log10(cls[n_ell-1]/cls[n_ell-2])/log10(ell[n_ell-1]/ell[n_ell-2]);
235  }
236 
237  int ith, gslstatus;
238  double result,eresult;
239  gsl_function F;
240  gsl_integration_workspace *w=gsl_integration_workspace_alloc(ccl_gsl->N_ITERATION);
241  for(ith=0;ith<n_theta;ith++) {
242  cp->th=theta[ith]*M_PI/180;
243  F.function=&corr_bessel_integrand;
244  F.params=cp;
245  //TODO: Split into intervals between first bessel zeros before integrating
246  //This will help both speed and accuracy of the integral.
247  gslstatus = gsl_integration_qag(&F, 0, ccl_splines->ELL_MAX_CORR, 0,
250  w, &result, &eresult);
251  if(gslstatus != GSL_SUCCESS) {
252  ccl_raise_gsl_warning(gslstatus, "ccl_correlation.c: ccl_tracer_corr_bessel():");
253  *status |= gslstatus;
254  }
255  wtheta[ith]=result/(2*M_PI);
256  }
257  gsl_integration_workspace_free(w);
258  ccl_spline_free(cp->cl_spl);
259  free(cp);
260 }
261 
262 
263 /*--------ROUTINE: ccl_compute_legendre_polynomial ------
264 TASK: Compute input factor for ccl_tracer_corr_legendre
265 INPUT: tracer 1, tracer 2, i_bessel, theta array, n_theta, L_max, output Pl_theta
266  */
267 static void ccl_compute_legendre_polynomial(int corr_type,double theta,int ell_max,double *Pl_theta)
268 {
269  int i,j;
270  double k=0;
271  double cth=cos(theta*M_PI/180);
272 
273  //Initialize Pl_theta
274  for (j=0;j<=ell_max;j++)
275  Pl_theta[j]=0.;
276 
277  if(corr_type==CCL_CORR_GG) {
278  gsl_sf_legendre_Pl_array(ell_max,cth,Pl_theta);
279  for (j=0;j<=ell_max;j++)
280  Pl_theta[j]*=(2*j+1);
281  }
282  else if(corr_type==CCL_CORR_GL) {
283  for (j=2;j<=ell_max;j++) {//https://arxiv.org/pdf/1007.4809.pdf
284  Pl_theta[j]=gsl_sf_legendre_Plm(j,2,cth);
285  Pl_theta[j]*=(2*j+1.)/((j+0.)*(j+1.));
286  }
287  }
288 }
289 
290 /*--------ROUTINE: ccl_tracer_corr_legendre ------
291 TASK: Compute correlation function via Legendre polynomials
292 INPUT: cosmology, number of theta bins, theta array, tracer 1, tracer 2, i_bessel, boolean
293  for tapering, vector of tapering limits, correlation vector, angular_cl function.
294  */
296  int n_ell,double *ell,double *cls,
297  int n_theta,double *theta,double *wtheta,
298  int corr_type,int do_taper_cl,double *taper_cl_limits,
299  int *status)
300 {
301  int i;
302  double *l_arr,*cl_arr,*Pl_theta;
303  SplPar *cl_spl;
304 
305  if(corr_type==CCL_CORR_LM || corr_type==CCL_CORR_LP){
307  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: CCL does not support full-sky xi+- calcuations.\nhttps://arxiv.org/abs/1702.05301 indicates flat-sky to be sufficient.\n");
308  }
309 
310  if(*status==0) {
311  l_arr=malloc(((int)(ccl_splines->ELL_MAX_CORR)+1)*sizeof(double));
312  if(l_arr==NULL) {
313  *status=CCL_ERROR_MEMORY;
314  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_legendre ran out of memory\n");
315  }
316  }
317 
318  if(*status==0) {
319  cl_arr=malloc(((int)(ccl_splines->ELL_MAX_CORR)+1)*sizeof(double));
320  if(cl_arr==NULL) {
321  *status=CCL_ERROR_MEMORY;
322  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_legendre ran out of memory\n");
323  }
324  }
325 
326  if(*status==0) {
327  //Interpolate input Cl into
328  cl_spl=ccl_spline_init(n_ell,ell,cls,cls[0],0);
329  if(cl_spl==NULL) {
330  *status=CCL_ERROR_MEMORY;
331  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_legendre ran out of memory\n");
332  }
333  }
334 
335  if(*status==0) {
336  double cl_tilt,l_edge,cl_edge;
337  l_edge=ell[n_ell-1];
338  if((cls[n_ell-1]*cls[n_ell-2]<0) || (cls[n_ell-2]==0)) {
339  cl_tilt=0;
340  cl_edge=0;
341  }
342  else {
343  cl_tilt=log(cls[n_ell-1]/cls[n_ell-2])/log(ell[n_ell-1]/ell[n_ell-2]);
344  cl_edge=cls[n_ell-1];
345  }
346  for(i=0;i<=(int)(ccl_splines->ELL_MAX_CORR);i++) {
347  double l=(double)i;
348  l_arr[i]=l;
349  if(l>=l_edge)
350  cl_arr[i]=cl_edge*pow(l/l_edge,cl_tilt);
351  else
352  cl_arr[i]=ccl_spline_eval(l,cl_spl);
353  }
354  ccl_spline_free(cl_spl);
355 
356  if (do_taper_cl)
357  *status=taper_cl((int)(ccl_splines->ELL_MAX_CORR)+1,l_arr,cl_arr,taper_cl_limits);
358  }
359 
360  if(*status==0) {
361  Pl_theta=malloc(sizeof(double)*((int)(ccl_splines->ELL_MAX_CORR)+1));
362  if(Pl_theta==NULL) {
363  *status=CCL_ERROR_MEMORY;
364  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_tracer_corr_legendre ran out of memory\n");
365  }
366  }
367 
368  if(*status==0) {
369  for (int i=0;i<n_theta;i++) {
370  wtheta[i]=0;
371  ccl_compute_legendre_polynomial(corr_type,theta[i],(int)(ccl_splines->ELL_MAX_CORR),Pl_theta);
372  for(int i_L=1;i_L<(int)(ccl_splines->ELL_MAX_CORR);i_L+=1)
373  wtheta[i]+=cl_arr[i_L]*Pl_theta[i_L];
374  wtheta[i]/=(M_PI*4);
375  }
376  }
377 
378  free(Pl_theta);
379  free(l_arr);
380  free(cl_arr);
381 }
382 
383 /*--------ROUTINE: ccl_tracer_corr ------
384 TASK: For a given tracer, get the correlation function. Do so by running
385  ccl_angular_cls. If you already have Cls calculated, go to the next
386  function to pass them directly.
387 INPUT: cosmology, number of theta values to evaluate = NL, theta vector,
388  tracer 1, tracer 2, i_bessel, key for tapering, limits of tapering
389  correlation function.
390  */
392  int n_ell,double *ell,double *cls,
393  int n_theta,double *theta,double *wtheta,
394  int corr_type,int do_taper_cl,double *taper_cl_limits,int flag_method,
395  int *status)
396 {
397  switch(flag_method) {
398  case CCL_CORR_FFTLOG :
399  ccl_tracer_corr_fftlog(cosmo,n_ell,ell,cls,n_theta,theta,wtheta,corr_type,
400  do_taper_cl,taper_cl_limits,status);
401  break;
402  case CCL_CORR_LGNDRE :
403  ccl_tracer_corr_legendre(cosmo,n_ell,ell,cls,n_theta,theta,wtheta,corr_type,
404  do_taper_cl,taper_cl_limits,status);
405  break;
406  case CCL_CORR_BESSEL :
407  ccl_tracer_corr_bessel(cosmo,n_ell,ell,cls,n_theta,theta,wtheta,corr_type,status);
408  break;
409  default :
410  *status=CCL_ERROR_INCONSISTENT;
411  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_correlation. Unknown algorithm\n");
412  }
413 
414  ccl_check_status(cosmo,status);
415 }
416 
417 /*--------ROUTINE: ccl_correlation_3d ------
418 TASK: Calculate the 3d-correlation function. Do so by using FFTLog.
419 
420 INPUT: cosmology, scale factor a,
421  number of r values, r values,
422  key for tapering, limits of tapering
423 
424 Correlation function result will be in array xi
425  */
426 
428  int n_r,double *r,double *xi,
429  int do_taper_pk,double *taper_pk_limits,
430  int *status)
431 {
432  int i,N_ARR;
433  double *k_arr,*pk_arr,*r_arr,*xi_arr;
434 
435  //number of data points for k and pk array
436  N_ARR=(int)(ccl_splines->N_K_3DCOR*log10(ccl_splines->K_MAX/ccl_splines->K_MIN));
437 
439  if(k_arr==NULL) {
440  *status=CCL_ERROR_MEMORY;
441  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_correlation_3d ran out of memory\n");
442  return;
443  }
444 
445  pk_arr=malloc(N_ARR*sizeof(double));
446  if(pk_arr==NULL) {
447  free(k_arr);
448  *status=CCL_ERROR_MEMORY;
449  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_correlation_3d ran out of memory\n");
450  return;
451  }
452 
453  for (i=0; i<N_ARR; i++)
454  pk_arr[i] = ccl_nonlin_matter_power(cosmo, k_arr[i], a, status);
455 
456  if (do_taper_pk)
457  taper_cl(N_ARR,k_arr,pk_arr,taper_pk_limits);
458 
459  r_arr=malloc(sizeof(double)*N_ARR);
460  if(r_arr==NULL) {
461  free(k_arr);
462  free(pk_arr);
463  *status=CCL_ERROR_MEMORY;
464  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_correlation_3d ran out of memory\n");
465  return;
466  }
467  xi_arr=malloc(sizeof(double)*N_ARR);
468  if(xi_arr==NULL) {
469  free(k_arr); free(pk_arr); free(r_arr);
470  *status=CCL_ERROR_MEMORY;
471  ccl_cosmology_set_status_message(cosmo, "ccl_correlation.c: ccl_correlation_3d ran out of memory\n");
472  return;
473  }
474 
475  for(i=0;i<N_ARR;i++)
476  r_arr[i]=0;
477 
478  pk2xi(N_ARR,k_arr,pk_arr,r_arr,xi_arr);
479 
480  // Interpolate to output values of r
481  SplPar *xi_spl=ccl_spline_init(N_ARR,r_arr,xi_arr,xi_arr[0],0);
482  for(i=0;i<n_r;i++)
483  xi[i]=ccl_spline_eval(r[i],xi_spl);
484  ccl_spline_free(xi_spl);
485 
486  free(k_arr); free(pk_arr);
487  free(r_arr); free(xi_arr);
488 
489  ccl_check_status(cosmo,status);
490 
491  return;
492 }
#define CCL_CORR_LP
static void ccl_tracer_corr_bessel(ccl_cosmology *cosmo, int n_ell, double *ell, double *cls, int n_theta, double *theta, double *wtheta, int corr_type, int *status)
double double
Definition: precision.hpp:19
void ccl_correlation(ccl_cosmology *cosmo, int n_ell, double *ell, double *cls, int n_theta, double *theta, double *wtheta, int corr_type, int do_taper_cl, double *taper_cl_limits, int flag_method, int *status)
void ccl_correlation_3d(ccl_cosmology *cosmo, double a, int n_r, double *r, double *xi, int do_taper_pk, double *taper_pk_limits, int *status)
void ccl_raise_gsl_warning(int gslstatus, const char *msg,...)
Definition: ccl_error.c:75
int INTEGRATION_GAUSS_KRONROD_POINTS
Definition: ccl_params.h:58
#define CCL_ERROR_NOT_IMPLEMENTED
Definition: ccl_error.h:25
double ccl_nonlin_matter_power(ccl_cosmology *cosmo, double k, double a, int *status)
Definition: ccl_power.c:1562
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
void fftlog_ComputeXi2D(double bessel_order, int N, const double l[], const double cl[], double th[], double xi[])
Definition: fftlog.c:144
ccl_spline_params * ccl_splines
Definition: ccl_core.c:47
static void ccl_tracer_corr_legendre(ccl_cosmology *cosmo, int n_ell, double *ell, double *cls, int n_theta, double *theta, double *wtheta, int corr_type, int do_taper_cl, double *taper_cl_limits, int *status)
#define M_PI
Definition: ccl_constants.h:22
static void ccl_compute_legendre_polynomial(int corr_type, double theta, int ell_max, double *Pl_theta)
double ELL_MAX_CORR
Definition: ccl_params.h:41
#define CCL_ERROR_LINSPACE
Definition: ccl_error.h:11
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
double INTEGRATION_EPSREL
Definition: ccl_params.h:59
double ccl_spline_eval(double x, SplPar *spl)
Definition: ccl_utils.c:170
static CCL_BEGIN_DECLS double x[111][8]
#define CCL_CORR_GL
void ccl_spline_free(SplPar *spl)
Definition: ccl_utils.c:316
#define CCL_CORR_LM
#define CCL_CORR_BESSEL
#define CCL_ERROR_MEMORY
Definition: ccl_error.h:10
size_t N_ITERATION
Definition: ccl_params.h:55
double ELL_MIN_CORR
Definition: ccl_params.h:40
dictionary params
Definition: halomod_bm.py:27
#define CCL_CORR_GG
static void ccl_tracer_corr_fftlog(ccl_cosmology *cosmo, int n_ell, double *ell, double *cls, int n_theta, double *theta, double *wtheta, int corr_type, int do_taper_cl, double *taper_cl_limits, int *status)
#define CCL_CORR_FFTLOG
#define CCL_ERROR_INCONSISTENT
Definition: ccl_error.h:12
static int p
Definition: ccl_emu17.c:25
float pow(float base, unsigned long int exp)
Definition: precision.hpp:39
void pk2xi(int N, const double k[], const double pk[], double r[], double xi[])
Definition: fftlog.c:176
#define CCL_CORR_LGNDRE
static int taper_cl(int n_ell, double *ell, double *cl, double *ell_limits)
static double corr_bessel_integrand(double l, void *params)
static double w[2][28][111]
Definition: ccl_emu17.c:33
SplPar * ccl_spline_init(int n, double *x, double *y, double y0, double yf)
Definition: ccl_utils.c:146