#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 "lagsht_numbers.h" using namespace std; #define DEBUG 1 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, int 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) */ double newtoncorr (double x, int N) const { using namespace std; if(N<1) return 0.; double pnm1=0., pn=1.; double c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { double 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; } } double ppn=(N*pn-(N+alpha_)*pnm1)/x; return -pn/ppn; }//newtoncorr /*! returns L_N^alpha(x)*exp(-x/2) */ double value(double x, int N) const { using namespace std; if (N<0) return 0; double log2expfac = -0.5*x*inv_ln2; int scale=int(log2expfac/large_exponent2); log2expfac-=scale*large_exponent2; double pnm1=0., pn=exp(ln2*log2expfac); double c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { double 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) { using namespace std; if (N<0) { res.resize(0); return; } res.resize(N+1); res[0]=exp(-0.5*x); double log2expfac = -0.5*x*inv_ln2; int scale=int(log2expfac/large_exponent2); log2expfac-=scale*large_exponent2; double pnm1=0., pn=exp(ln2*log2expfac); double c1=alpha_-1., c2=alpha_-1.; for(int i=1;i<=N;i++) { double 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); double tmp1 = N+alpha_; for (int i=1;i= 1 cout << "Sum roots = " << sumR << " -> diff with theory: " << sumR - sumRTh << endl; cout << "Sum weights = " << sumW << " -> diff with theory: " << sumW - sumWTh << endl; #endif 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; } }//nodes_and_weights protected: int N_; //!< Order of the polynomial int alpha_; //!< second parameter of the generalized Laguerre polynomial private: enum { large_exponent2=90, minscale=-14, maxscale=14 }; double ln2, inv_ln2, fsmall, fbig; std::vector xi; std::vector cf; }; //LaguerreFuncQuad } // Fin du namespace #undef DEBUG #endif //LAGUERREBUILDER_SEEN