CosmoBolognaLib
Free Software C++/Python libraries for cosmological calculations
HaloProfile.cpp
Go to the documentation of this file.
1 /********************************************************************
2  * Copyright (C) 2022 by Federico Marulli and Giorgio Lesci *
3  * federico.marulli3@unibo.it *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public *
16  * License along with this program; if not, write to the Free *
17  * Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ********************************************************************/
20 
34 #include "HaloProfile.h"
35 
36 using namespace std;
37 
38 using namespace cbl;
39 using namespace glob;
40 
41 
42 // =====================================================================================
43 
44 
45 cbl::cosmology::HaloProfile::HaloProfile (const cbl::cosmology::Cosmology cosmology, const double redshift, const double conc, const double Mass, const double Delta, const std::string profile_author, const std::string halo_def, const double trunc_fact, const bool miscentering, const bool single_profile, const double sigma_off, const double f_off)
46 {
47  m_set_profile(cosmology, redshift, conc, Mass, Delta, profile_author, halo_def, trunc_fact, miscentering, single_profile, sigma_off, f_off);
48 }
49 
50 
51 // =====================================================================================
52 
53 
54 cbl::cosmology::HaloProfile::HaloProfile (const cbl::cosmology::Cosmology cosmology, const double redshift, const std::string cM_author, const double Mass, const double Delta, const std::string profile_author, const std::string halo_def, const double trunc_fact, const bool miscentering, const bool single_profile, const double sigma_off, const double f_off)
55 {
56  m_set_profile(cosmology, redshift, 0., Mass, Delta, profile_author, halo_def, trunc_fact, miscentering, single_profile, sigma_off, f_off);
57  m_set_cM_relation(cM_author);
58 }
59 
60 
61 // =====================================================================================
62 
63 
65 {
66  const double fact = (m_cosmology->unit()) ? 1 : m_cosmology->hh();
67  const double Mpivot = 2.e12/fact; // in Msun/h
68 
69  return m_A*pow(m_mass/Mpivot, m_B)*pow(1.+m_redshift, m_C);
70 }
71 
72 
73 // =====================================================================================
74 
75 
77 {
78  // Compute rho_s
79  const double conc = (this->*m_return_concentration)();
80  const double rho_s = pow(conc, 3) * m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift) / (3.*(log(1.+conc)-conc/(1.+conc)));
81 
82  return rho_s;
83 }
84 
85 
86 // =====================================================================================
87 
88 
90 {
91  // compute rho_s
92  const double conc = (this->*m_return_concentration)();
93  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
94  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
95  const double r_t = m_trunc_fact * r_s*conc;
96  const double tau = r_t/r_s;
97  const double fact = tau*tau / (2.*pow(tau*tau+1.,3)*(1.+conc)*(tau*tau+conc*conc)) * (conc*(tau*tau+1.) * (conc*(conc+1.) - tau*tau*(conc-1.)*(2.+3.*conc) - 2.*pow(tau,4)) + tau*(conc+1.)*(tau*tau+conc*conc) * (2.*(3.*tau*tau-1.) * std::atan(conc/tau) + tau*(tau*tau-3.)*log(tau*tau*(1.+conc)*(1.+conc)/(tau*tau+conc*conc)))); // Eq. 10 from Oguri & Hamana 2011
98 
99  const double rho_s = pow(conc, 3) * m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift) / (3.*fact);
100 
101  return rho_s;
102 }
103 
104 
105 // =====================================================================================
106 
107 
108 std::vector<double> cbl::cosmology::HaloProfile::m_rho_NFW (const std::vector<double> rad)
109 {
110  // compute rho_s and r_s
111  const double conc = (this->*m_return_concentration)();
112  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
113  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
114  const double rho_s = m_rho_s_NFW();
115 
116  // compute rho
117  std::vector<double> rho(rad.size());
118  for (size_t i=0; i<rad.size(); i++)
119  rho[i] = rho_s/((rad[i]/r_s)*pow(1.+rad[i]/r_s, 2));
120 
121  return rho;
122 }
123 
124 
125 // =====================================================================================
126 
127 
128 std::vector<double> cbl::cosmology::HaloProfile::m_rho_NFW_trunc (const std::vector<double> rad)
129 {
130  // compute rho_s and r_s
131  const double conc = (this->*m_return_concentration)();
132  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
133  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
134  const double r_t = m_trunc_fact * r_s*conc;
135  const double rho_s = m_rho_s_NFW_trunc();
136 
137  // compute rho
138  std::vector<double> rho(rad.size());
139  for (size_t i=0; i<rad.size(); i++)
140  rho[i] = rho_s/((rad[i]/r_s)*pow(1.+rad[i]/r_s, 2)) * pow(r_t*r_t/(rad[i]*rad[i]+r_t*r_t),2);
141 
142  return rho;
143 }
144 
145 
146 // =====================================================================================
147 
148 
149 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_NFW (const std::vector<double> rad)
150 {
151  // Implementation of second part of eq. 4 from Golse et al. 2002 (https://ui.adsabs.harvard.edu/abs/2002A%26A...390..821G/abstract)
152  std::function<double(double)> F = [] (double x) {
153  if (x < 1.)
154  return (1 - std::acosh(1./x)/std::sqrt(1.-x*x)) / (x*x-1.);
155  else if (x == 1.)
156  return 1./3.;
157  else
158  return (1 - std::acos(1./x)/std::sqrt(x*x-1.)) / (x*x-1.);
159  };
160 
161  // compute the density
162  const double conc = (this->*m_return_concentration)();
163  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
164  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
165  const double rho_s = m_rho_s_NFW();
166 
167  std::vector<double> Sigma(rad.size());
168  for (size_t i=0; i<rad.size(); i++)
169  Sigma[i] = 2. * rho_s * r_s * F(rad[i]/r_s) * 1.e-12;
170 
171  return Sigma;
172 }
173 
174 
175 // =====================================================================================
176 
177 
178 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_mean_NFW (const std::vector<double> rad)
179 {
180  // Implementation of eq. 5 from Golse et al. 2002
181  std::function<double(double)> G = [] (double x) {
182  if (x < 1.)
183  return log(x/2.) + std::acosh(1./x) / sqrt(1.-x*x);
184  else if (x == 1.)
185  return 1+log(1./2.);
186  else
187  return log(x/2.) + std::acos(1./x) / sqrt(x*x-1.);;
188  };
189 
190  // compute the density
191  const double conc = (this->*m_return_concentration)();
192  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
193  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
194  const double rho_s = m_rho_s_NFW();
195 
196  std::vector<double> Sigma_mean(rad.size());
197  for (size_t i=0; i<rad.size(); i++) {
198  double x = rad[i]/r_s;
199  Sigma_mean[i] = 4. * rho_s * r_s * G(x)/x/x * 1.e-12;
200  }
201 
202  return Sigma_mean;
203 }
204 
205 
206 // =====================================================================================
207 
208 
209 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_NFW_trunc (const std::vector<double> rad)
210 {
211  // Implementation of eq. A.5 from Baltz et al. 2009 (https://ui.adsabs.harvard.edu/abs/2009JCAP...01..015B/abstract)
212  const double conc = (this->*m_return_concentration)();
213 
214  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
215  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
216  const double r_t = m_trunc_fact * r_s*conc;
217  const double tau = r_t/r_s;
218  const double rho_s = m_rho_s_NFW_trunc();
219 
220  std::function<double(double)> F = [] (double x){
221  if (x < 1.)
222  return std::acosh(1./x) / std::sqrt(1.-x*x);
223  else if (x == 1.)
224  return 1.;
225  else
226  return std::acos(1./x) / std::sqrt(x*x-1.);
227  };
228 
229  // Implementation of eq. A.28 from Baltz et al. 2009
230  std::function<double(double)> G = [&F] (double x){
231  if (x < 1.)
232  return (F(x)-1.) / (1.-x*x);
233  else if (x == 1.)
234  return 1./3.;
235  else
236  return (1.-F(x)) / (x*x-1.);
237  };
238 
239  // Implementation of second part of eq. A.6 from Baltz et al. 2009
240  std::function<double(double)> L = [&tau] (double x){
241  return log(x/(sqrt(x*x+tau*tau)+tau));
242  };
243 
244  // compute the density
245  std::vector<double> Sigma(rad.size());
246  double tausq = tau*tau;
247  double tau4th = tausq*tausq;
248 
249  for (size_t i=0; i<rad.size(); i++) {
250  double x = rad[i]/r_s;
251  double tausq_xsq = tausq+x*x;
252 
253  double prefact = rho_s*r_s*tau4th/(tausq+1.)/(tausq+1.)/(tausq+1.);
254  double a = 2*(tausq+1.)*G(x);
255  double b = 8*F(x);
256  double c = (tau4th-1.)/tausq/tausq_xsq;
257  double d = -cbl::par::pi*(4*tausq_xsq+tausq+1.)/pow(tausq_xsq,1.5);
258  double e = (tausq*(tau4th-1.)+(tausq_xsq)*(3*tau4th-6*tausq-1))*L(x)/(tau*tau*tau)/pow(tausq_xsq,1.5);
259 
260  Sigma[i] = prefact*(a+b+c+d+e) * 1.e-12;
261  }
262 
263  return Sigma;
264 }
265 
266 
267 // =====================================================================================
268 
269 
270 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_mean_NFW_trunc (const std::vector<double> rad)
271 {
272  const double conc = (this->*m_return_concentration)();
273 
274  const double overdensity = m_cosmology->rho_crit(m_redshift)*m_Delta_func(m_Delta,*m_cosmology,m_redshift);
275  const double r_s = pow( 3.*m_mass/(4.*cbl::par::pi*overdensity), 1./3. ) / conc;
276  const double r_t = m_trunc_fact * r_s*conc;
277  const double tau = r_t/r_s;
278  const double rho_s = m_rho_s_NFW_trunc();
279 
280  std::function<double(double)> F = [] (double x) {
281  if (x < 1.)
282  return std::acosh(1./x) / std::sqrt(1.-x*x);
283  else if (x == 1.)
284  return 1.;
285  else
286  return std::acos(1./x) / std::sqrt(x*x-1.);
287  };
288 
289  std::function<double(double)> L = [&tau] (double x) {
290  return log(x/(sqrt(x*x+tau*tau)+tau));
291  };
292 
293  // compute the density
294  std::vector<double> Sigma_mean(rad.size());
295  double tausq = tau*tau;
296  double tau4th = tausq*tausq;
297 
298  for (size_t i=0; i<rad.size(); i++) {
299  double x = rad[i]/r_s;
300  double tausq_xsq = tausq+x*x;
301 
302  double prefact = 2. * cbl::par::pi * rho_s * pow(r_s,3);
303  double term1 = tau4th / (tausq+1.) / (tausq+1.) / (tausq+1.);
304  double term2 = 2. * (tausq + 1. + 4.*(x*x-1.)) * F(x);
305  double term3 = (cbl::par::pi * (3.*tausq-1.) + 2. * tau * (tausq-3.) * log(tau)) / tau;
306  double term4 = tausq * tau * sqrt(tausq_xsq);
307  double term5 = - tausq * tau * cbl::par::pi * (4. * tausq_xsq - tausq - 1.);
308  double term6 = - tausq * (tau4th - 1.) + tausq_xsq * (3. * tau4th - 6. * tausq - 1.);
309 
310  double M_proj = prefact * term1 * (term2 + term3 + (term5 + term6 * L(x)) / term4);
311 
312  Sigma_mean[i] = M_proj / (cbl::par::pi * rad[i]*rad[i]) * 1.e-12;
313  }
314 
315  return Sigma_mean;
316 }
317 
318 
319 // =====================================================================================
320 
321 
322 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_mis (const std::vector<double> rad)
323 {
324  // Define the integrands (where P(R_s) is a Rayleigh distribution)
325 
326  double dummy_R_s, dummy_R;
327 
328  std::function<double(double)> integrand = [&] (double theta) {
329  double new_rad2 = dummy_R*dummy_R + dummy_R_s*dummy_R_s + 2*dummy_R*dummy_R_s*std::cos(theta);
330  return (this->*m_Sigma_cen_ptr)({std::sqrt(new_rad2)})[0];
331  };
332 
333 
334  double r=0, a_meantau=0, b_meantau=0, inv_mis_scale = 1./m_sigma_off/m_sigma_off;
335  std::function<double(double)> tau_factor1 = [&a_meantau,&b_meantau,&inv_mis_scale] (double s) {
336  return (exp(-0.5*(s*s+a_meantau)*inv_mis_scale))/sqrt(b_meantau-a_meantau-s*s);
337  };
338 
339  std::function<double(double)> tau_factor2 = [&a_meantau,&b_meantau,&inv_mis_scale] (double s){
340  return (exp(-0.5*(b_meantau-s*s)*inv_mis_scale))/sqrt(b_meantau-a_meantau-s*s);
341  };
342 
343  std::function<double(double)> sigma_off_int = [&] (double tau) {
344  a_meantau = (tau-r)*(tau-r);
345  b_meantau = (tau+r)*(tau+r);
346  double c_meantau = (a_meantau+b_meantau)*0.5;
347  double upper_limit = std::min(sqrt(c_meantau-a_meantau),sqrt(25*m_sigma_off*m_sigma_off-a_meantau));
348  double sigma_off_int = r*2.*cbl::wrapper::gsl::GSL_integrate_cquad(tau_factor1, 0., upper_limit);
349  if (c_meantau < 25*m_sigma_off*m_sigma_off)
350  {
351  double int_left = std::max(0.,sqrt(b_meantau-25*m_sigma_off*m_sigma_off));
352  double int_right = sqrt(b_meantau-c_meantau);
353  sigma_off_int += r*2.*cbl::wrapper::gsl::GSL_integrate_cquad(tau_factor2, int_left, int_right);
354  }
355  return sigma_off_int * tau * (this->*m_Sigma_cen_ptr)({tau})[0];
356  };
357 
358  // Compute Sigma_mis
359  std::vector<double> Sigma_mis(rad.size());
360 
361  if (m_single_profile) {
362 
363  dummy_R_s = m_sigma_off;
364 
365  for (size_t i=0; i<rad.size(); i++) {
366  dummy_R = rad[i];
367  const double integral = cbl::wrapper::gsl::GSL_integrate_cquad(integrand, 0., cbl::par::pi);
368  Sigma_mis[i] = integral / (cbl::par::pi);
369  }
370 
371  }
372 
373  else {
374 
375  for (size_t i=0; i<rad.size(); i++) {
376 
377  r = rad[i];
378  Sigma_mis[i] = cbl::wrapper::gsl::GSL_integrate_cquad(sigma_off_int, std::max(0., rad[i]-5*m_sigma_off), rad[i]+5.*m_sigma_off) /rad[i]/cbl::par::pi/m_sigma_off/m_sigma_off;
379 
380  }
381 
382  }
383 
384  return Sigma_mis;
385 
386 }
387 
388 
389 // =====================================================================================
390 
391 
392 std::vector<double> cbl::cosmology::HaloProfile::m_Sigma_including_miscentering (const std::vector<double> rad)
393 {
394  if (m_sigma_off > m_sigma_off_threshold && m_f_off > m_f_off_threshold) {
395  const std::vector<double> Sigma_cen = (this->*m_Sigma_cen_ptr)(rad);
396  const std::vector<double> Sigma_mis = (this->*m_Sigma_mis_ptr)(rad);
397 
398  std::vector<double> Sigma_tot(rad.size());
399  for (size_t i=0; i<rad.size(); i++)
400  Sigma_tot[i] = (1.-m_f_off)*Sigma_cen[i] + m_f_off*Sigma_mis[i];
401 
402  return Sigma_tot;
403  }
404  else
405  return (this->*m_Sigma_cen_ptr)(rad);
406 }
407 
408 
409 // =====================================================================================
410 
411 
412 std::vector<double> cbl::cosmology::HaloProfile::m_DeltaSigma_cen (const std::vector<double> rad)
413 {
414  const std::vector<double> Sigma = (this->*m_Sigma_cen_ptr)(rad);
415  const std::vector<double> Sigma_mean = (this->*m_Sigma_mean_cen_ptr)(rad);
416 
417  // Compute DeltaSigma
418  std::vector<double> DeltaSigma(rad.size());
419  for (size_t i=0; i<rad.size(); i++)
420  DeltaSigma[i] = Sigma_mean[i] - Sigma[i];
421 
422  return DeltaSigma;
423 }
424 
425 
426 // =====================================================================================
427 
428 
429 std::vector<double> cbl::cosmology::HaloProfile::m_DeltaSigma_mis (const std::vector<double> rad)
430 {
431  if (m_sigma_off > m_sigma_off_threshold) {
432 
433  // Interpolate Sigma(R)
434  const std::vector<double> rad_forInterp = cbl::logarithmic_bin_vector((size_t)(100), m_min_Smis, m_max_Smis);
435  const std::vector<double> Sigma = (this->*m_Sigma_mis_ptr)(rad_forInterp);
436 
437  cbl::glob::FuncGrid Sigma_interp (rad_forInterp, Sigma, "Spline");
438 
439  // Compute the mean surface density
440  std::function<double(double)> mean_sigma_integrand = [&Sigma_interp] (double rad){
441  return Sigma_interp(rad) * rad;
442  };
443 
444  std::vector<double> Sigma_mean(rad.size());
445  for (size_t i=0; i<rad.size(); i++)
446  Sigma_mean[i] = cbl::wrapper::gsl::GSL_integrate_cquad(mean_sigma_integrand, 0., rad[i]) * 2./rad[i]/rad[i];
447 
448  // Compute DeltaSigma
449  std::vector<double> DeltaSigma(rad.size());
450  for (size_t i=0; i<rad.size(); i++)
451  DeltaSigma[i] = Sigma_mean[i] - Sigma_interp(rad[i]);
452 
453  return DeltaSigma;
454 
455  }
456  else
457  return (this->*m_DeltaSigma_cen_ptr)(rad);
458 }
459 
460 
461 // =====================================================================================
462 
463 
464 std::vector<double> cbl::cosmology::HaloProfile::m_DeltaSigma_including_miscentering (const std::vector<double> rad)
465 {
466  if (m_sigma_off > m_sigma_off_threshold && m_f_off > m_f_off_threshold) {
467  const std::vector<double> DeltaSigma_cen = (this->*m_DeltaSigma_cen_ptr)(rad);
468  const std::vector<double> DeltaSigma_mis = (this->*m_DeltaSigma_mis_ptr)(rad);
469 
470  std::vector<double> DeltaSigma_tot(rad.size());
471  for (size_t i=0; i<rad.size(); i++)
472  DeltaSigma_tot[i] = (1.-m_f_off)*DeltaSigma_cen[i] + m_f_off*DeltaSigma_mis[i];
473 
474  return DeltaSigma_tot;
475  }
476  else
477  return (this->*m_DeltaSigma_cen_ptr)(rad);
478 }
479 
480 
481 // =====================================================================================
482 
483 
484 void cbl::cosmology::HaloProfile::m_set_cM_relation (const std::string cM_author)
485 {
486  m_isSet_cM_relation = true;
487 
488  if (cM_author=="Duffy") {
489  if (m_redshift>2) ErrorCBL("the concentration-mass relation by Duffy et al. has been tested only at z<2", "set_cM_relation", "HaloProfile.cpp");
490 
491  if ( (m_halo_def == "critical" && m_Delta != 200.) || (m_halo_def == "mean" && 200.*m_cosmology->OmegaM(m_redshift) != m_Delta_func(m_Delta,*m_cosmology,m_redshift)) )
492  ErrorCBL("the concentration-mass relation by Duffy et al. has been implemented only for critical/mean overdensity factors equal to 200.", "set_cM_relation", "HaloProfile.cpp");
493 
494  if (m_profile_author=="NFW" || m_profile_author=="NFW_trunc") {
495  if (m_halo_def=="critical") {
496  m_A = 5.71;
497  m_B = -0.084;
498  m_C = -0.47;
499  }
500  else if (m_halo_def=="vir") {
501  m_A = 7.85;
502  m_B = -0.081;
503  m_C = -0.71;
504  }
505  else if (m_halo_def=="mean") {
506  m_A = 10.14;
507  m_B = -0.081;
508  m_C = -1.01;
509  }
510  else ErrorCBL("halo_def not allowed!", "set_cM_relation", "HaloProfile.cpp");
511  }
512  else if (m_profile_author=="Einasto") {
513  if (m_halo_def=="critical") {
514  m_A = 6.4;
515  m_B = -0.108;
516  m_C = -0.62;
517  }
518  else if (m_halo_def=="vir") {
519  m_A = 8.82;
520  m_B = -0.106;
521  m_C = -0.87;
522  }
523  else if (m_halo_def=="mean") {
524  m_A = 11.39;
525  m_B = -0.107;
526  m_C = -1.16;
527  }
528  else ErrorCBL("halo_def not allowed!", "set_cM_relation", "HaloProfile.cpp");
529  }
530  else ErrorCBL("profile not allowed!", "set_cM_relation", "HaloProfile.cpp");
531 
532  m_return_concentration = &cbl::cosmology::HaloProfile::m_concentration_Duffy;
533  }
534  else ErrorCBL("concentration-mass relation author not allowed!", "set_cM_relation", "HaloProfile.cpp");
535 }
536 
537 
538 // =====================================================================================
539 
540 
541 void cbl::cosmology::HaloProfile::m_set_profile (const cbl::cosmology::Cosmology cosmology, const double redshift, const double conc, const double Mass, const double Delta, const std::string profile_author, const std::string halo_def, const double trunc_fact, const bool miscentering, const bool single_profile, const double sigma_off, const double f_off)
542 {
543  if (miscentering && single_profile && f_off != 1.)
544  ErrorCBL("if a single profile is considered in the miscentering model, then f_off must be set equal to 1.", "m_set_profile", "HaloProfile.cpp");
545 
546  m_sigma_off_threshold = 1.e-4;
547  m_f_off_threshold = 1.e-4;
548  m_min_Smis = 1.e-5;
549  m_max_Smis = 300;
550 
551  m_cosmology = make_shared<cosmology::Cosmology>(cosmology::Cosmology(move(cosmology)));
552  m_redshift = redshift;
553  m_concentration = conc;
554  m_mass = Mass;
555  m_Delta = Delta;
556  m_profile_author = profile_author;
557  m_halo_def = halo_def;
558 
559  m_trunc_fact = trunc_fact;
560  m_miscentering = miscentering;
561  m_single_profile = single_profile;
562  m_sigma_off = sigma_off;
563  m_f_off = f_off;
564 
565  // Set the overdensity factor Delta
566  if (halo_def == "critical")
567  m_Delta_func = [] (const double delta, cbl::cosmology::Cosmology cosmo, const double redshift) {
568  (void)cosmo; (void)redshift;
569  return delta;};
570  else if (halo_def == "mean")
571  m_Delta_func = [] (const double delta, cbl::cosmology::Cosmology cosmo, const double redshift) {
572  return delta * cosmo.OmegaM(redshift);};
573  else if (halo_def == "vir")
574  m_Delta_func = [] (const double delta, cbl::cosmology::Cosmology cosmo, const double redshift) {
575  (void)delta;
576  return cosmo.Delta_c(redshift, "BryanNorman");};
577  else
578  ErrorCBL("wrong halo_def declaration!", "m_set_profile", "HaloProfile.cpp");
579 
580  // Set the function returning the concentration
582 
583  // Set the profile
584  if (profile_author == "NFW") {
585 
588 
589  if (miscentering) {
590  m_Sigma_cen_ptr = &cbl::cosmology::HaloProfile::m_Sigma_NFW;
591  m_Sigma_mean_cen_ptr = &cbl::cosmology::HaloProfile::m_Sigma_mean_NFW;
592  m_Sigma_mis_ptr = &cbl::cosmology::HaloProfile::m_Sigma_mis;
594  m_DeltaSigma_cen_ptr = &cbl::cosmology::HaloProfile::m_DeltaSigma_cen;
595  m_DeltaSigma_mis_ptr = &cbl::cosmology::HaloProfile::m_DeltaSigma_mis;
597  }
598  else {
600  m_Sigma_cen_ptr = &cbl::cosmology::HaloProfile::m_Sigma_NFW;
601  m_Sigma_mean_cen_ptr = &cbl::cosmology::HaloProfile::m_Sigma_mean_NFW;
603  }
604 
605  }
606 
607  else if (profile_author == "NFW_trunc") {
608 
611 
612  if (miscentering) {
615  m_Sigma_mis_ptr = &cbl::cosmology::HaloProfile::m_Sigma_mis;
617  m_DeltaSigma_cen_ptr = &cbl::cosmology::HaloProfile::m_DeltaSigma_cen;
618  m_DeltaSigma_mis_ptr = &cbl::cosmology::HaloProfile::m_DeltaSigma_mis;
620  }
621  else {
626  }
627 
628  }
629 
630  else
631  ErrorCBL("density profile author not allowed!", "m_set_profile", "HaloProfile.cpp");
632 }
633 
634 
635 // =====================================================================================
636 
637 
639 {
640  m_cosmology = make_shared<cosmology::Cosmology>(cosmology::Cosmology(move(cosmology)));
641 }
642 
643 
644 // ============================================================================================
645 
646 
648 {
649  return (this->*m_rho_s_ptr)();
650 }
651 
652 // ============================================================================================
653 
654 
655 std::vector<double> cbl::cosmology::HaloProfile::density_profile_3D (const std::vector<double> rad)
656 {
657  return (this->*m_rho_ptr)(rad);
658 }
659 
660 
661 // ============================================================================================
662 
663 
664 std::vector<double> cbl::cosmology::HaloProfile::Sigma (const std::vector<double> rad)
665 {
666  return (this->*m_Sigma_ptr)(rad);
667 }
668 
669 
670 // ============================================================================================
671 
672 
673 std::vector<double> cbl::cosmology::HaloProfile::Sigma_mis (const std::vector<double> rad)
674 {
675  if (m_miscentering == false)
676  ErrorCBL("the miscentering is not set!", "Sigma_mis", "HaloProfile.cpp");
677 
678  if (m_sigma_off > m_sigma_off_threshold)
679  return (this->*m_Sigma_mis_ptr)(rad);
680  else
681  return (this->*m_Sigma_cen_ptr)(rad);
682 }
683 
684 
685 // ============================================================================================
686 
687 
688 std::vector<double> cbl::cosmology::HaloProfile::Sigma_cen (const std::vector<double> rad)
689 {
690  if (m_miscentering == false)
691  ErrorCBL("the miscentering is not set!", "Sigma_cen", "HaloProfile.cpp");
692 
693  return (this->*m_Sigma_cen_ptr)(rad);
694 }
695 
696 
697 // ============================================================================================
698 
699 
700 std::vector<double> cbl::cosmology::HaloProfile::Sigma_2h (const std::vector<double> rad, const double bias, const std::string method_Pk, const std::string interp_type, const bool NL)
701 {
702  if (cbl::Max(rad) > 70. || cbl::Min(rad) < 1.e-2)
703  ErrorCBL("model tested only in the range [1.e-2,70] Mpc.", "Sigma_2h", "HaloProfile.cpp");
704 
705  double Rho_m = m_cosmology->rho_m(m_redshift);
706  double Dl = m_cosmology->D_A(m_redshift);
707 
708  double theta = 0; // in radians
709 
710  // Define the minimum and maximum l
711  const double kl_min = 1.e-4;
712  const double kl_max = 1.e2;
713 
714  // Interpolate P(k)
715  const std::vector<double> kl_forInterp = cbl::logarithmic_bin_vector((size_t)(500), kl_min, kl_max);
716  std::vector<double> Pk = m_cosmology->Pk_matter(kl_forInterp, method_Pk, NL, m_redshift, false, "test", -1, 1.e-4, 100.);
717  cbl::glob::FuncGrid Pk_interp (kl_forInterp, Pk, interp_type);
718 
719  // Integrand function of the integral defining the 2-halo density profile
720  std::function<double(double)> Func = [&] (double l)
721  {
722  l = pow(10,l);
723 
724  double X = theta*l;
725  double kl = l/((1+m_redshift)*Dl);
726  double Pk_ = Pk_interp(kl);
727  double J0 = gsl_sf_bessel_J0(X);
728  return l*J0*Pk_ * l;
729  };
730 
731  std::vector<double> S_2h(rad.size());
732  for (size_t i=0; i<rad.size(); i++) {
733  theta = rad[i]/Dl;
734  const double integral = cbl::wrapper::gsl::GSL_integrate_qag(Func, log10(kl_min * (1.0 + m_redshift) * Dl), log10(kl_max * (1.0 + m_redshift) * Dl)) * log(10);
735  S_2h[i] = 1.e-12 * bias*Rho_m/(2.*cbl::par::pi*pow(Dl,2)*pow(1+m_redshift,3)) * integral;
736  }
737 
738  return S_2h;
739 }
740 
741 
742 // ============================================================================================
743 
744 
745 std::vector<double> cbl::cosmology::HaloProfile::Sigma_2h (const std::vector<double> rad, const std::string bias_author, const std::string method_Pk, const std::string interp_type, const bool NL)
746 {
747  double delta_bkg = m_Delta_func(m_Delta,*m_cosmology,m_redshift)/m_cosmology->OmegaM(m_redshift);
748  double bias = m_cosmology->bias_halo(m_mass, m_redshift, bias_author, method_Pk, false, "test", interp_type, delta_bkg, -1., -1, 0.001, 100);
749 
750  return Sigma_2h (rad, bias, method_Pk, interp_type, NL);
751 }
752 
753 
754 // ============================================================================================
755 
756 
757 std::vector<double> cbl::cosmology::HaloProfile::DeltaSigma (const std::vector<double> rad)
758 {
759  return (this->*m_DeltaSigma_ptr)(rad);
760 }
761 
762 
763 // ============================================================================================
764 
765 
766 std::vector<double> cbl::cosmology::HaloProfile::DeltaSigma_mis (const std::vector<double> rad)
767 {
768  if (m_miscentering == false)
769  ErrorCBL("the miscentering is not set!", "DeltaSigma_mis", "HaloProfile.cpp");
770 
771  return (this->*m_DeltaSigma_mis_ptr)(rad);
772 }
773 
774 
775 // ============================================================================================
776 
777 
778 std::vector<double> cbl::cosmology::HaloProfile::DeltaSigma_cen (const std::vector<double> rad)
779 {
780  if (m_miscentering == false)
781  ErrorCBL("the miscentering is not set!", "DeltaSigma_cen", "HaloProfile.cpp");
782 
783  return (this->*m_DeltaSigma_cen_ptr)(rad);
784 }
785 
786 
787 // ============================================================================================
788 
789 
790 std::vector<double> cbl::cosmology::HaloProfile::DeltaSigma_2h (const std::vector<double> rad, const double bias, const std::string method_Pk, const std::string interp_type, const bool NL)
791 {
792  if (cbl::Max(rad) > 70. || cbl::Min(rad) < 1.e-2)
793  ErrorCBL("model tested only in the range [1.e-2,70] Mpc.", "DeltaSigma_2h", "HaloProfile.cpp");
794 
795  double Rho_m = m_cosmology->rho_m(m_redshift);
796  double Dl = m_cosmology->D_A(m_redshift);
797 
798  double theta = 0; // in radians
799 
800  // Define the minimum and maximum l
801  const double kl_min = 1.e-4;
802  const double kl_max = 1.e2;
803 
804  // Interpolate P(k)
805  const std::vector<double> kl_forInterp = cbl::logarithmic_bin_vector((size_t)(500), kl_min, kl_max);
806  std::vector<double> Pk = m_cosmology->Pk_matter(kl_forInterp, method_Pk, NL, m_redshift, false, "test", -1, 1.e-4, 100.);
807  cbl::glob::FuncGrid Pk_interp (kl_forInterp, Pk, interp_type);
808 
809  // Integrand function of the integral defining the 2-halo density profile
810  std::function<double(double)> Func = [&] (double l)
811  {
812  l = pow(10,l);
813 
814  double X = theta*l;
815  double kl = l/((1+m_redshift)*Dl);
816  double Pk_ = Pk_interp(kl);
817  double J2 = gsl_sf_bessel_Jn(2,X);
818  return l*J2*Pk_ * l;
819  };
820 
821  std::vector<double> DS_2h(rad.size());
822  for (size_t i=0; i<rad.size(); i++) {
823  theta = rad[i]/Dl;
824  const double integral = cbl::wrapper::gsl::GSL_integrate_qag(Func, log10(kl_min * (1.0 + m_redshift) * Dl), log10(kl_max * (1.0 + m_redshift) * Dl)) * log(10);
825  DS_2h[i] = 1.e-12 * bias*Rho_m/(2.*cbl::par::pi*pow(Dl,2)*pow(1+m_redshift,3)) * integral;
826  }
827 
828  return DS_2h;
829 }
830 
831 
832 // ============================================================================================
833 
834 
835 std::vector<double> cbl::cosmology::HaloProfile::DeltaSigma_2h (const std::vector<double> rad, const std::string bias_author, const std::string method_Pk, const std::string interp_type, const bool NL)
836 {
837  double delta_bkg = m_Delta_func(m_Delta,*m_cosmology,m_redshift)/m_cosmology->OmegaM(m_redshift);
838  double bias = m_cosmology->bias_halo(m_mass, m_redshift, bias_author, method_Pk, false, "test", interp_type, delta_bkg, -1., -1, 0.001, 100);
839 
840  return DeltaSigma_2h (rad, bias, method_Pk, interp_type, NL);
841 }
842 
843 
844 // ============================================================================================
845 
846 
848 {
849  const double conc = concentration();
850  const double rho_s = m_cosmology->rho_crit(m_redshift)*m_cosmology->Delta_c(m_redshift)/3.*pow(conc, 3)/(log(1.+conc)-conc/(1.+conc));
851  const double r_s = m_cosmology->r_vir(m_mass, m_redshift)/conc;
852  const double mu = kk*r_s;
853 
854  return 4.*par::pi*rho_s*pow(r_s, 3)/m_mass*(cos(mu)*(gsl_sf_Ci(mu+mu*conc)-gsl_sf_Ci(mu))+sin(mu)*(gsl_sf_Si(mu+mu*conc)-gsl_sf_Si(mu))-sin(mu*conc)/(mu+mu*conc));
855 }
856 
857 
858 // ============================================================================
859 
860 
861 double cbl::cosmology::HaloProfile::concentration2 (const double Vmax, const double Rmax) const
862 {
863  const int nn = 128;
864  vector<double> xxi = linear_bin_vector(nn, 0.1, 50.);
865  vector<double> yyi(nn);
866 
867  for (int i=0; i<nn; i++)
868  // reset 200 for the spherical collapse model
869  yyi[i] = 200./3.*pow(xxi[i],3.)/(log(1.+xxi[i])-xxi[i]/(1.+xxi[i]))-14.426*pow(Vmax/Rmax/m_cosmology->H0(),2.);
870 
871  return interpolated(0., yyi, xxi, "Poly");
872 }
873 
874 
875 // ============================================================================
876 
877 
878 double cbl::cosmology::HaloProfile::Mass_Delta (const double Mass, const double Delta_in, const double Delta_out, const double conc, const bool is_input_conc, const double rRmin_guess, const double rRmax_guess) const
879 {
880  auto func = [&] (const double xx)
881  {
882  const double c_in = (is_input_conc) ? conc : conc*xx;
883  const double c_out = (!is_input_conc) ? conc : conc/xx;
884  const double AA = log(1.+c_out)-c_out/(1.+c_out);
885  const double BB = log(1.+c_in)-c_in/(1.+c_in);
886  return fabs(Delta_in/Delta_out*AA*pow(xx, 3)-BB);
887  };
888 
889  // R_[Delta_out]/R_[Delta_in]
890  const double Rratio = wrapper::gsl::GSL_minimize_1D(func, 1., max(1.e-3, rRmin_guess), rRmax_guess);
891 
892  // M_[Delta_out]
893  return Delta_out/Delta_in/pow(Rratio, 3)*Mass;
894 }
The class HaloProfile.
The class Cosmology.
Definition: Cosmology.h:277
std::vector< double > Sigma(const std::vector< double > rad)
the total surface density profile of the halo.
double density_profile_FourierSpace(const double kk)
the Fourier transform of the normalised halo density
std::vector< double > Sigma_cen(const std::vector< double > rad)
the centered contribution to the total surface density profile of the halo.
std::vector< double > m_Sigma_mis(const std::vector< double > rad)
the mis-centered surface density profile of the halo (see e.g. Bellagamba et al. 2019).
std::vector< double > m_DeltaSigma_cen(const std::vector< double > rad)
Excess surface density without the miscentering contribution.
std::vector< double > m_Sigma_mean_NFW_trunc(const std::vector< double > rad)
Mean surface density of the truncated NFW profile.
std::vector< double > m_Sigma_mean_NFW(const std::vector< double > rad)
Mean surface density of the NFW profile.
std::vector< double > Sigma_mis(const std::vector< double > rad)
the miscentering contribution to the total surface density profile of the halo.
std::vector< double > m_Sigma_including_miscentering(const std::vector< double > rad)
Surface density including the miscentering contribution.
HaloProfile()=default
default constructor
std::vector< double > DeltaSigma_2h(const std::vector< double > rad, const std::string bias_author, const std::string method_Pk="EisensteinHu", const std::string interp_type="Linear", const bool NL=false)
the 2-halo contribution to the excess surface density profile of the halo, computed by assuming a hal...
std::vector< double > density_profile_3D(const std::vector< double > rad)
the 3D halo density profile.
double m_return_set_concentration()
Return the concentration set by the user.
Definition: HaloProfile.h:226
double concentration2(const double Vmax, const double Rmax) const
compute the halo concentration
void m_set_cM_relation(const std::string cM_author="Duffy")
set the concentration-mass relation. A function is set, computing the concentration of a dark matter ...
double rho_s()
the characteristic density of the 3D halo density profile.
double m_concentration_Duffy()
The concentration-mass relation by Duffy et al. (2008):
Definition: HaloProfile.cpp:64
std::vector< double > m_rho_NFW(const std::vector< double > rad)
The NFW 3D density profile.
std::vector< double > DeltaSigma_cen(const std::vector< double > rad)
the centered contribution to the excess surface density profile of the halo.
std::vector< double > m_Sigma_NFW(const std::vector< double > rad)
Surface density of the NFW profile.
std::vector< double > DeltaSigma(const std::vector< double > rad)
the total excess surface density profile of the halo.
std::vector< double > m_DeltaSigma_mis(const std::vector< double > rad)
the mis-centered excess surface density profile of the halo (see e.g. Bellagamba et al....
std::vector< double > m_DeltaSigma_including_miscentering(const std::vector< double > rad)
Excess surface density including the miscentering contribution.
double m_rho_s_NFW()
Characteristic density of the NFW profile.
Definition: HaloProfile.cpp:76
std::vector< double > m_Sigma_NFW_trunc(const std::vector< double > rad)
Surface density of the truncated NFW profile.
std::vector< double > Sigma_2h(const std::vector< double > rad, const std::string bias_author, const std::string method_Pk="EisensteinHu", const std::string interp_type="Linear", const bool NL=false)
the 2-halo contribution to the total surface density profile of the halo, computed by assuming a halo...
void m_set_profile(const cbl::cosmology::Cosmology cosmology, const double redshift, const double conc, const double Mass, const double Delta, const std::string profile_author, const std::string halo_def, const double trunc_fact=3., const bool miscentering=false, const bool single_profile=false, const double sigma_off=0.1, const double f_off=1.)
private function that sets the halo profile parameters. If the miscentering is considered,...
double m_rho_s_NFW_trunc()
Characteristic density of the truncated NFW profile.
Definition: HaloProfile.cpp:89
std::vector< double > m_rho_NFW_trunc(const std::vector< double > rad)
The truncated NFW 3D density profile.
void set_cosmology(const cbl::cosmology::Cosmology cosmology)
set the cosmological model
double Mass_Delta(const double Mass, const double Delta_in, const double Delta_out, const double conc, const bool is_input_conc, const double rRmin_guess=1.e-3, const double rRmax_guess=10.) const
The halo mass converted to a different value of , assuming the Navarro-Frenk-White density profile.
std::vector< double > DeltaSigma_mis(const std::vector< double > rad)
the miscentering contribution to the excess surface density profile of the halo.
The class FuncGrid.
Definition: FuncGrid.h:55
static const double pi
: the ratio of a circle's circumference to its diameter
Definition: Constants.h:199
double bias(const double Mmin, const double sigmalgM, const double M0, const double M1, const double alpha, const std::shared_ptr< void > inputs)
the mean galaxy bias
double GSL_minimize_1D(FunctionDoubleDouble func, const double start, double min=par::defaultDouble, double max=-par::defaultDouble, const int max_iter=1000, const bool verbose=false)
minimize the provided function using GSL procedure
Definition: GSLwrapper.cpp:658
double GSL_integrate_cquad(gsl_function func, const double a, const double b, const double rel_err=1.e-3, const double abs_err=0, const int nevals=100)
integral, using the gsl cquad method
Definition: GSLwrapper.cpp:159
double GSL_integrate_qag(gsl_function Func, const double a, const double b, const double rel_err=1.e-3, const double abs_err=0, const int limit_size=1000, const int rule=6)
integral, computed using the GSL qag method
Definition: GSLwrapper.cpp:180
The global namespace of the CosmoBolognaLib
Definition: CAMB.h:38
T Min(const std::vector< T > vect)
minimum element of a std::vector
Definition: Kernel.h:1324
T Mass(const T RR, const T Rho)
the mass of a sphere of a given radius and density
Definition: Func.h:1243
std::vector< T > logarithmic_bin_vector(const size_t nn, const T min, const T max)
fill a std::vector with logarithmically spaced values
Definition: Kernel.h:1621
std::vector< T > linear_bin_vector(const size_t nn, const T min, const T max)
fill a std::vector with linearly spaced values
Definition: Kernel.h:1604
int ErrorCBL(const std::string msg, const std::string functionCBL, const std::string fileCBL, const cbl::glob::ExitCode exitCode=cbl::glob::ExitCode::_error_)
throw an exception: it is used for handling exceptions inside the CosmoBolognaLib
Definition: Kernel.h:780
T Max(const std::vector< T > vect)
maximum element of a std::vector
Definition: Kernel.h:1336
double interpolated(const double _xx, const std::vector< double > xx, const std::vector< double > yy, const std::string type)
1D interpolation
Definition: Func.cpp:445
double Sigma(const std::vector< double > vect)
the standard deviation of a std::vector
Definition: Func.cpp:925