// ************************************************************************ // * class Gauss_Integrator // * - provides routines for non MC Integration of a given 1D function by // * + Gauss-Legendre W(x)=P(x) (General Polinominal Integrator) // * + Gauss-Chebyshev W(x)=(1-x^2)^-1/2 * P(x) // * + Gauss-Laguerre W(x)=x^alf e^-x * P(x) // * + Gauss-Hermite W(x)=e^(-x^2) * P(x) // * + Gauss-Jacobi W(x)=(1-x)^alf (1+x)^bet * P(x) // ************************************************************************ #include "ATOOLS/Math/Gauss_Integrator.H" #include "ATOOLS/Math/MathTools.H" #include #include using namespace ATOOLS; int Gauss_Integrator::s_ngauleg=0; int Gauss_Integrator::s_ngaulag=0; int Gauss_Integrator::s_ngauherm=0; int Gauss_Integrator::s_ngaujac=0; Weight_Module* Gauss_Integrator::s_wlistroot=0; Gauss_Integrator::Gauss_Integrator(Function_Base *func){ m_numberabsc = 0; // precisision (number of points) not jet choosen m_wlistact = 0; // so no precalculated weights or abscissas are available jet; m_func = func; // set function to be integrated } double Gauss_Integrator::Integrate(double x1, double x2, double prec, int mode, int nmax) { if (x1==x2) return 0.; int n = 64; if (n>nmax) n=nmax; double i2=0.,i1=1.; int err; for (;(n<=nmax)&&(dabs(1-i2/i1)>prec);n*=2) { i2=i1; switch (mode) { case 1 : i1=Legendre(x1,x2,n); break; case 2 : return Chebyshev(x1,x2,prec,n*4,err); // case 3 : return Laguerre(n); // case 4 : return Hermite(n); case 5 : i1 = Jacobi(x1,x2,n,-0.5, -0.5); break; default: i1 = Legendre(x1,x2,n); } } return i1; } // * Gauss_Legendre Integation ****************** void Gauss_Integrator::GauLeg(double * x, double * w, int n) { const double EPS=3.0e-11; // calculate Gauss_Legendre weights and abscissas // x[0] .. x[n-1] abscissas // w[0] .. w[n-1] weights int m,j,i; double z1,z,pp,p3,p2,p1; m=(n+1)/2; for (i=1;i<=m;i++) { z=cos(3.141592654*(i-0.25)/(n+0.5)); do { p1=1.0; p2=0.0; for (j=1;j<=n;j++) { p3=p2; p2=p1; p1=((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j; } pp=n*(z*p1-p2)/(z*z-1.0); z1=z; z=z1-p1/pp; } while (fabs(z-z1) > EPS); x[i-1]=-z,x[n-i]=z; w[i-1]=2.0/((1.0-z*z)*pp*pp); w[n-i]=w[i-1]; } } /* (C) Copr. 1986-92 Numerical Recipes Software VsXz&v%120(9p+45$j3D. */ double Gauss_Integrator::Legendre(double x1, double x2,int n=8) { if (n>32) { double xm=0.5*(x1 + x2); int nn = n/2; return Legendre(x1,xm,nn)+Legendre(xm,x2,nn); } else { double sum=0.0; double xm=0.5*(x2+x1); double xl=0.5*(x2-x1); if (n>s_ngauleg) { // generate new weights and abscissas m_wlistact = new Weight_Module; m_wlistact->w = new double[n]; m_wlistact->x = new double[n]; m_wlistact->methode = 1; // legendre m_wlistact->n = n; // number of points if (n>s_ngauleg) s_ngauleg=n; m_wlistact->next = s_wlistroot; // put in list s_wlistroot=m_wlistact; GauLeg(m_wlistact->x, m_wlistact->w, n); } else { // use already calculated abscissas Weight_Module * listitem; listitem = s_wlistroot; m_wlistact = 0; for (;listitem!=0;listitem=listitem->next) if ((listitem->n>=n) && (listitem->methode==1)) if ((m_wlistact==0) || (m_wlistact->n>listitem->n)) m_wlistact=listitem; if ((m_wlistact==0)||(m_wlistact->n>2*n)) { // generate new weights and abscissas m_wlistact = new Weight_Module; m_wlistact->w = new double[n]; m_wlistact->x = new double[n]; m_wlistact->methode = 1; // legendre m_wlistact->n = n; // number of points m_wlistact->next = s_wlistroot; // put in list s_wlistroot = m_wlistact; if (n>s_ngauleg) s_ngauleg = n; GauLeg(m_wlistact->x, m_wlistact->w, n); } ; } // do the summation (the same for all gauss integrations); for (int i=0;ix[i]; sum+=m_wlistact->w[i]*((*m_func)( x )); } sum*=xl; return sum; } } double Gauss_Integrator::Chebyshev( double a, double b, double prec, int n_max, int &i_err ) { // a; lower boundary // b; upper boundary // prec; relative error // n_max; maximum number of steps allowed // *i_err; = 0 for an alleged successful calculation // = 1 otherwise // f; dfunc (integrated function) double ch; // value of integral // ref. 1: j. m. perez-jorda, e. san-fabian, f. moscardo, // comp. phys. comm. 70 (1992) 271 int m, n, i; double di; double s, s0, s1, c, c0, c1, tm, tp, x, t, h; double intalt; double intneu; // initializing m, i_err, n, s0, c0, tsch and p. intalt = intneu = 0.; h = (b-a)/2.; m = 0; n = 1; s0 = 1.; c0 = 0.; t = a + h; ch = (*m_func)( t ); // computing the (2n+1) points quadrature formula. // updating q, p, c1, s1, c0, s0, s and c. while (m<5 || ( dabs( intneu-intalt ) > prec * dabs( intneu ) && mprec * fabs(intneu)) i_err = 1; else i_err = 0; ch = 16. * ch / ( 3. * (n+1) ); ch = h * ch; return ch; } // ******* Gauss Jacobi Interation ************************************* void Gauss_Integrator::GauJac(double * x, double * w, int n, double alf, double bet) { const double EPS = 3.0e-14; const int MAXIT = 10; // calculate Gauss Jacobi weights and abscissas int i,its,j; double alfbet,an,bn,r1,r2,r3; double a,b,c,p1,p2,p3,pp,temp,z=1.,z1; for (i=1;i<=n;i++) { if (i == 1) { an=alf/n; bn=bet/n; r1=(1.0+alf)*(2.78/(4.0+n*n)+0.768*an/n); r2=1.0+1.48*an+0.96*bn+0.452*an*an+0.83*an*bn; z=1.0-r1/r2; } else if (i == 2) { r1=(4.1+alf)/((1.0+alf)*(1.0+0.156*alf)); r2=1.0+0.06*(n-8.0)*(1.0+0.12*alf)/n; r3=1.0+0.012*bet*(1.0+0.25*fabs(alf))/n; z -= (1.0-z)*r1*r2*r3; } else if (i == 3) { r1=(1.67+0.28*alf)/(1.0+0.37*alf); r2=1.0+0.22*(n-8.0)/n; r3=1.0+8.0*bet/((6.28+bet)*n*n); z -= (x[0]-z)*r1*r2*r3; } else if (i == n-1) { r1=(1.0+0.235*bet)/(0.766+0.119*bet); r2=1.0/(1.0+0.639*(n-4.0)/(1.0+0.71*(n-4.0))); r3=1.0/(1.0+20.0*alf/((7.5+alf)*n*n)); z += (z-x[n-4])*r1*r2*r3; } else if (i == n) { r1=(1.0+0.37*bet)/(1.67+0.28*bet); r2=1.0/(1.0+0.22*(n-8.0)/n); r3=1.0/(1.0+8.0*alf/((6.28+alf)*n*n)); z += (z-x[n-3])*r1*r2*r3; } else { z=3.0*x[i-2]-3.0*x[i-3]+x[i-4]; } alfbet=alf+bet; for (its=1;its<=MAXIT;its++) { temp=2.0+alfbet; p1=(alf-bet+temp*z)/2.0; p2=1.0; for (j=2;j<=n;j++) { p3=p2; p2=p1; temp=2*j+alfbet; a=2*j*(j+alfbet)*(temp-2.0); b=(temp-1.0)*(alf*alf-bet*bet+temp*(temp-2.0)*z); c=2.0*(j-1+alf)*(j-1+bet)*temp; p1=(b*p2-c*p3)/a; } pp=(n*(alf-bet-temp*z)*p1+2.0*(n+alf)*(n+bet)*p2)/(temp*(1.0-z*z)); z1=z; z=z1-p1/pp; if (fabs(z-z1) <= EPS) break; } x[i-1]=z; w[i-1]=exp(Gammln(alf+n)+Gammln(bet+n)-Gammln(n+1.0)- Gammln(n+alfbet+1.0))*temp*pow(2.0,alfbet)/(pp*p2) *pow((1.-z),-alf)*pow((1.+z),-bet); } } /* (C) Copr. 1986-92 Numerical Recipes Software VsXz&v%120(9p+45$j3D. */ double Gauss_Integrator::Jacobi(double x1, double x2,int n=8, double alf= -0.5f, double bet= -0.5f) { double sum=0.0; double xm=0.5*(x2+x1); double xl=0.5*(x2-x1); if (n>s_ngaujac) { // generate new weights and abscissas m_wlistact = new Weight_Module; m_wlistact->w = new double[n]; m_wlistact->x = new double[n]; m_wlistact->methode = 5; // Jacobi m_wlistact->n = n; // number of points if (n>s_ngaujac) s_ngaujac = n; m_wlistact->next = s_wlistroot; // put in list s_wlistroot = m_wlistact; GauJac(m_wlistact->x, m_wlistact->w, n, alf, bet); } else { // use already calculated abscissas Weight_Module * listitem; listitem = s_wlistroot; m_wlistact = 0; for (;listitem!=0;listitem=listitem->next) if ((listitem->n>=n)&&(listitem->methode==5)) if ((m_wlistact==0)||(m_wlistact->n>listitem->n)) m_wlistact=listitem; if ((m_wlistact==0)||(m_wlistact->n>2*n)) { // generate new weights and abscissas m_wlistact = new Weight_Module; m_wlistact->w = new double[n]; m_wlistact->x = new double[n]; m_wlistact->methode = 5; // jacobi m_wlistact->n = n; // number of points m_wlistact->next = s_wlistroot; // put in list s_wlistroot = m_wlistact; if (n>s_ngaujac) s_ngaujac = n; GauJac(m_wlistact->x, m_wlistact->w, n, alf, bet); } } // do the summation (the same for all gauss integrations); for (int i=0;ix[i]; sum+=m_wlistact->w[i]*((*m_func)( x )); } sum*=xl; return sum; }