#ifndef LAGUERREBUILDER_SEEN #define LAGUERREBUILDER_SEEN /* * This file is part of LagSHT. * * LagSHT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * LagSHT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with libsharp; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * LagSHT is being developed at the Linear Accelerateur Laboratory (LAL) * 91898 ORSAY CEDEX - FRANCE * main author: J.E Campagne */ #include //very important for abs definition #include #include #include // std::setprecision //JEC 12/1/16: alpha becomes double instead of int //JEC (N+alpha)! -> Gamma[N+alpha+1]. Use Boost::tgamma function #include "boost/math/special_functions/gamma.hpp" #include "lagsht_numbers.h" using namespace std; #define DEBUG 0 namespace LagSHT { ///////////////////////////////////////////////////////////////////////////////////////////// //// - -Class generalized Laguerre Function and Gauss-Laguerre Quadrature -------------- // //// The Laguerre Function is scaled by exp(-r/2) compared to the Laguerre Polynomials // //// the exp(r_i) scales the weights compared to the Polynomial Gauss-Laguerre Quadrature// //// (nb. an public heritance from LaguerrePolyQuad would made confusion) // ///////////////////////////////////////////////////////////////////////////////////////////// class LaguerreFuncQuad { public: //! Creator LaguerreFuncQuad(int N, r_8 alpha=2): N_(N), alpha_(alpha), ln2(0.693147180559945309417232121458176), inv_ln2(1.4426950408889634073599246810018921), fsmall(std::ldexp(1.,-large_exponent2)), fbig(std::ldexp(1.,large_exponent2)), xi(N+2), cf(maxscale+1-minscale) { using namespace std; xi[0]=0.; for (size_t i=1; i& nodes, vector& weights) const; //! Compute L_n^alpha(x) * exp(-x/2) * scale with n = N_ r_8 Value(r_8 x, r_8 scale=1.0) const; //! Compute L_n^alpha(x) * exp(-x/2) * scale with n=0,...,N_ (included) void Values(r_8 x, vector& vals, r_8 scale=1.0); protected: /*! returns the amount by which x must be shifted to go closer to a root of L_N^alpha(x) */ r_8 newtoncorr (r_8 x, int N) const { using namespace std; if(N<1) return 0.; r_8 pnm1=0., pn=1.; r_8 c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { r_8 pnm2 = pnm1; pnm1 = pn; c1+=2.; c2+=1.; pn = ((c1-x)*pnm1 - c2*pnm2)*xi[i]; // if necessary, scale down // the function result is independent of the absolute scale while (abs(pn)>=fbig) { pn*=fsmall; pnm1*=fsmall; } } r_8 ppn=(N*pn-(N+alpha_)*pnm1)/x; return -pn/ppn; }//newtoncorr //JEC 12/1/16 add a normalization factor /*! returns L_N^alpha(x)*exp(-x/2)*norm */ r_8 value(r_8 x, int N, r_8 norm = 1.0) const { using namespace std; if (N<0) return 0; r_8 log2expfac = -0.5*x*inv_ln2; int scale=int(log2expfac/large_exponent2); log2expfac-=scale*large_exponent2; r_8 pnm1=0., pn=exp(ln2*log2expfac)*norm; r_8 c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { r_8 pnm2 = pnm1; pnm1 = pn; c1+=2.; c2+=1.; pn = ((c1-x)*pnm1 - c2*pnm2)*xi[i]; while (abs(pn)>=fbig) // if necessary, scale down and count rescalings { pn*=fsmall; pnm1*=fsmall; ++scale; } } return (scale &res, r_8 norm=1.0) { using namespace std; if (N<0) { res.resize(0); return; } res.resize(N+1); res[0]=exp(-0.5*x)*norm; r_8 log2expfac = -0.5*x*inv_ln2; int scale=int(log2expfac/large_exponent2); log2expfac-=scale*large_exponent2; r_8 pnm1=0., pn=exp(ln2*log2expfac)*norm; r_8 c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { r_8 pnm2 = pnm1; pnm1 = pn; c1+=2.; c2+=1.; pn = ((c1-x)*pnm1 - c2*pnm2)*xi[i]; while (abs(pn)>=fbig) // if necessary, scale down and count rescalings { pn*=fsmall; pnm1*=fsmall; ++scale; } res[i] = (scale &nodes, std::vector &weights) const { using namespace std; nodes.resize(N); weights.resize(N); /* JEC 12/1/16 alpha is r_8. tmp1 = (N+alpha)!/N!/(N+1)^2 = Gamma(N+alpha+1)/Gamma(N+1)/(N+1)^2 r_8 tmp1 = N+alpha_; for (int i=1;i= 1 //verification r_16 sumR = 0.; r_16 sumW = 0.; r_16 wip; for (int i=0;i diff with theory: " << sumR - sumRTh << endl; cout << "Sum weights = " << sumW << " -> diff with theory: " << sumW - sumWTh << endl; if (fabs(sumR-sumRTh)>(0.000001*sumRTh)) { cout << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << "WARNING!!!! verify LaguerrePolyQuad sum of nodes not accurate: " << " current value " << sumR << " theoretical value : " << sumRTh << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << endl; } if (fabs(sumW-sumWTh)>(0.000001*sumWTh)) { cout << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << "WARNING!!!! verify LaguerrePolyQuad sum of weights not accurate: " << " current value " << sumW << " theoretical value : " << sumWTh << " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" << endl; } #endif }//nodes_and_weights protected: int N_; //!< Order of the polynomial r_8 alpha_; //!< second parameter of the generalized Laguerre polynomial private: enum { large_exponent2=90, minscale=-14, maxscale=14 }; r_8 ln2, inv_ln2, fsmall, fbig; std::vector xi; std::vector cf; }; //LaguerreFuncQuad } // Fin du namespace #undef DEBUG #endif //LAGUERREBUILDER_SEEN