CosmoBolognaLib
Free Software C++/Python libraries for cosmological calculations
LegendrePolynomials.cpp
1 /********************************************************************
2  * Copyright (C) 2015 by Federico Marulli and Alfonso Veropalumbo *
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 
36 #include "LegendrePolynomials.h"
37 
38 #include <boost/math/special_functions/beta.hpp>
39 
40 using namespace std;
41 
42 using namespace cbl;
43 
44 
45 // ============================================================================================
46 
47 
49 {
50 
51  auto old_handler = gsl_set_error_handler_off();
52  (void)old_handler;
53 
54  m_nOrders = lMax+1;
55 
56  m_coefficients.resize(m_nOrders, m_nOrders);
57 
58  auto binomial_coeff = [&] (const double n, const double k) {
59 
60  gsl_sf_result lng_n, lng_k, lng_nmk;
61  double lng_n_sgn, lng_k_sgn, lng_nmk_sgn;
62 
63  int status_n = gsl_sf_lngamma_sgn_e(n+1, &lng_n, &lng_n_sgn);
64  int status_k = gsl_sf_lngamma_sgn_e(k+1, &lng_k, &lng_k_sgn);
65  int status_nmk = gsl_sf_lngamma_sgn_e(n-k+1, &lng_nmk, &lng_nmk_sgn);
66 
67  if(status_n != 0 or status_k != 0 or status_nmk != 0) {
68  return 0.;
69  }
70 
71  return lng_n_sgn/(lng_k_sgn*lng_nmk_sgn)*exp(lng_n.val-lng_k.val-lng_nmk.val);
72 
73  };
74 
75  for (int i=0; i<static_cast<int>(m_nOrders); i++) {
76  double fact = pow(2, i);
77  for (int j=0; j<static_cast<int>(m_nOrders); j++)
78  m_coefficients(i,j) = fact*binomial_coeff(i, j)*binomial_coeff( double(i+j-1)*0.5, i);
79  }
80 
81  //gsl_set_error_handler(old_handler);
82 }
83 
84 
85 // ============================================================================================
86 
87 
88 cbl::glob::LegendrePolynomials::LegendrePolynomials (const int lMax, const bool safe)
89 {
90  set(lMax);
91  (void)safe;
92 }
93 
94 
95 // ============================================================================================
96 
97 
99 {
100  m_set_coefficients (lMax);
101 }
102 
103 
104 // ============================================================================================
105 
106 
107 double cbl::glob::LegendrePolynomials::operator() (const double x, const int ell)
108 {
109  Eigen::VectorXd m_powers(m_nOrders);
110 
111  m_powers[0] = 1.;
112  m_powers[1] = x;
113 
114  for (size_t i=2; i<m_nOrders; i++)
115  m_powers[i] = m_powers[i-1]*x;
116 
117  return m_coefficients.row(ell).dot(m_powers);
118 }
119 
120 
121 // ============================================================================================
122 
123 
124 vector<double> cbl::glob::LegendrePolynomials::operator() (const double x)
125 {
126  Eigen::VectorXd m_powers(m_nOrders);
127 
128  m_powers[0] = 1.;
129  m_powers[1] = x;
130 
131  for (size_t i=2; i<m_nOrders; i++)
132  m_powers[i] = m_powers[i-1]*x;
133 
134  Eigen::VectorXd leg_pols = m_coefficients*m_powers;
135 
136  vector<double> vv(leg_pols.data(), leg_pols.data()+leg_pols.size());
137  return vv;
138 }
139 
140 
141 // ============================================================================================
142 
143 
144 double cbl::glob::LegendrePolynomials::integral (const double x_min, const double x_max, const int ell)
145 {
146  Eigen::VectorXd min(m_nOrders);
147  Eigen::VectorXd max(m_nOrders);
148  Eigen::VectorXd norm(m_nOrders);
149 
150  min[0] = x_min;
151  max[0] = x_max;
152  norm[0] = 1.;
153 
154  for (size_t i=1; i<m_nOrders; i++) {
155  min[i] = min[i-1]*x_min;
156  max[i] = max[i-1]*x_max;
157  norm[i] = norm[i-1]+1;
158  }
159 
160  return m_coefficients.row(ell).dot( (max-min).cwiseQuotient(norm) )/(x_max-x_min);
161 }
162 
163 
164 // ============================================================================================
165 
166 
167 vector<double> cbl::glob::LegendrePolynomials::integral (const double x_min, const double x_max)
168 {
169  Eigen::VectorXd min(m_nOrders);
170  Eigen::VectorXd max(m_nOrders);
171  Eigen::VectorXd norm(m_nOrders);
172 
173  min[0] = x_min;
174  max[0] = x_max;
175  norm[0] = 1.;
176 
177  for (size_t i=1; i<m_nOrders; i++) {
178  min[i] = min[i-1]*x_min;
179  max[i] = max[i-1]*x_max;
180  norm[i] = norm[i-1]+1;
181  }
182 
183  Eigen::VectorXd leg_pols = m_coefficients*( (max-min).cwiseQuotient(norm) )/(x_max-x_min);
184 
185  vector<double> vv(leg_pols.data(), leg_pols.data()+leg_pols.size());
186  return vv;
187 }
188 
189 
190 // ============================================================================================
191 
192 vector<vector<double>> cbl::glob::LegendrePolynomials::triangle (const double r12, const double r13, const double r23)
193 {
194  double mu_23 = (r12*r12+r13*r13-r23*r23)/(2*r12*r13);
195  double mu_13 = (r12*r12+r23*r23-r13*r13)/(2*r12*r23);
196  double mu_12 = (r23*r23+r13*r13-r12*r12)/(2*r23*r13);
197 
198  vector<vector<double>> leg_pols;
199  leg_pols.push_back(this->operator()(mu_23));
200  leg_pols.push_back(this->operator()(mu_13));
201  leg_pols.push_back(this->operator()(mu_12));
202 
203  return leg_pols;
204 }
205 
206 
207 // ============================================================================================
208 
209 
210 vector<double> cbl::glob::LegendrePolynomials::triangle_integral (const double r12_min, const double r12_max, const double r13_min, const double r13_max, const double r23_min, const double r23_max, const double rel_err, const int nevals)
211 {
212  double norm = 2*(pow(r12_max, 3)-pow(r12_min,3))*(pow(r13_max, 3)-pow(r13_min, 3))/9;
213 
214  Eigen::VectorXd m_powers(m_nOrders);
215 
216  for (int i=0; i<static_cast<int>(m_nOrders); i++) {
217 
218  size_t exponent = i+1;
219 
220  auto r12_integrand = [&] (const double r12) {
221  auto r13_integrand = [&] (const double r13) {
222  double x_min = (r12*r12+r13*r13-r23_max*r23_max)/(2*r12*r13);
223  double x_max = (r12*r12+r13*r13-r23_min*r23_min)/(2*r12*r13);
224 
225  if ( x_min>1 or x_max < -1)
226  return 0.;
227 
228  //double low = pow(max(x_min, -1.), exponent);
229  //double up = pow(min(1., x_max), exponent);
230  double low = gsl_pow_uint(max(x_min, -1.), exponent);
231  double up = gsl_pow_uint(min(x_max, 1.), exponent);
232  return r13*r13*(up-low)/exponent;
233  };
234  return r12*r12*cbl::wrapper::gsl::GSL_integrate_cquad(r13_integrand, r13_min, r13_max, rel_err, 0., nevals);
235  };
236 
237  m_powers[i] = cbl::wrapper::gsl::GSL_integrate_cquad(r12_integrand, r12_min, r12_max, rel_err, 0., nevals)/norm;
238  }
239 
240  Eigen::VectorXd leg_pols = m_coefficients*m_powers;
241 
242  vector<double> vv(leg_pols.data(), leg_pols.data()+leg_pols.size());
243  return vv;
244 }
Class to manage Legendre polymials computation.
double operator()(const double x, const int ell)
evaluate the Legendre polynomial of order ell at x
std::vector< double > triangle_integral(const double r12_min, const double r12_max, const double r13_min, const double r13_max, const double r23_min, const double r23_max, const double rel_err=1.e-4, const int nevals=10000)
evaluate the bin-averaged Legendre polynomials over a triangle. Triangle side can vary from a minimum...
double integral(const double x_min, const double x_max, const int ell)
evaluate the bin-averaged Legendre polynomial of order ell
std::vector< std::vector< double > > triangle(const double r12, const double r13, const double r23)
evaluate the Legendre polynomials for triangle angles.
void set(const int lMax)
set maximum order of expansion
void m_set_coefficients(const int lMax)
set internal attribute m_coefficients
LegendrePolynomials()
Default constructor of LegendrePolynomials.
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
The global namespace of the CosmoBolognaLib
Definition: CAMB.h:38