CLHEP VERSION Reference Documentation
CLHEP Home Page CLHEP Documentation CLHEP Bug Reports |
00001 // -*- C++ -*- 00002 // $Id: DefiniteIntegral.cc,v 1.6 2010/06/16 18:22:01 garren Exp $ 00003 00004 #include <cmath> 00005 #include <vector> 00006 #include <stdexcept> 00007 #include "CLHEP/GenericFunctions/DefiniteIntegral.hh" 00008 #include "CLHEP/GenericFunctions/AbsFunction.hh" 00009 00010 00011 namespace Genfun { 00012 00013 00014 class DefiniteIntegral::Clockwork { 00015 00016 // 00017 // This class has limited visibility its functions, data, 00018 // and nested classes are all public: 00019 // 00020 00021 public: 00022 00023 class QuadratureRule { 00024 00025 public: 00026 00027 // Constructorctor: 00028 QuadratureRule() {}; 00029 00030 // Destructor: 00031 virtual ~QuadratureRule() {}; 00032 00033 // Integrate at the j^th level of refinement: 00034 virtual double integrate(const AbsFunction & function, 00035 double a, 00036 double b, 00037 unsigned int j) const=0; 00038 00039 // Return the step multiplier: 00040 virtual unsigned int stepMultiplier () const=0; 00041 00042 // Return the number of function calls: 00043 virtual unsigned int numFunctionCalls() const =0; 00044 00045 }; 00046 00047 class TrapezoidQuadratureRule:public QuadratureRule { 00048 00049 public: 00050 00051 // Constructor: 00052 TrapezoidQuadratureRule():retVal(0),nFunctionCalls(0) {}; 00053 00054 // Destructor: 00055 ~TrapezoidQuadratureRule() {}; 00056 00057 // Integrate at the j^th level of refinement: 00058 virtual double integrate(const AbsFunction & function, 00059 double a, 00060 double b, 00061 unsigned int j) const; 00062 00063 // The step is doubled at each level of refinement: 00064 virtual unsigned int stepMultiplier () const {return 2;} 00065 00066 // Returns number of function calls: 00067 virtual unsigned int numFunctionCalls() const {return nFunctionCalls;}; 00068 00069 private: 00070 00071 mutable double retVal; 00072 mutable unsigned int nFunctionCalls; 00073 00074 }; 00075 00076 class XtMidpointQuadratureRule:public QuadratureRule { 00077 00078 public: 00079 00080 // Constructor: 00081 XtMidpointQuadratureRule():retVal(0),nFunctionCalls(0) {}; 00082 00083 // Destructorctor: 00084 ~XtMidpointQuadratureRule() {}; 00085 00086 // Integrate at the j^th level of refinement: 00087 virtual double integrate(const AbsFunction & function, 00088 double a, 00089 double b, 00090 unsigned int j) const; 00091 00092 // The step is tripled at each level of refinement: 00093 virtual unsigned int stepMultiplier () const {return 3;} 00094 00095 // Returns number of function calls: 00096 virtual unsigned int numFunctionCalls() const {return nFunctionCalls;}; 00097 00098 private: 00099 00100 mutable double retVal; 00101 mutable unsigned int nFunctionCalls; 00102 }; 00103 00104 double a; // lower limit of integration 00105 double b; // upper limit of integration 00106 DefiniteIntegral::Type type; // open or closed 00107 mutable unsigned int nFunctionCalls; // bookkeeping 00108 unsigned int MAXITER; // Max no of step doubling, tripling, etc. 00109 double EPS; // Target precision 00110 unsigned int K; // Minimum order =2*5=10 00111 00112 // Polynomial interpolation with Neville's method: 00113 void polint(std::vector<double>::iterator xArray, std::vector<double>::iterator yArray, double x, double & y, double & deltay) const; 00114 00115 }; 00116 00117 00118 DefiniteIntegral::DefiniteIntegral(double a, double b, Type type): 00119 c(new Clockwork()) { 00120 c->a = a; 00121 c->b = b; 00122 c->type = type; 00123 c->nFunctionCalls = 0; 00124 c->MAXITER = type==OPEN ? 20 : 14; 00125 c->EPS = 1.0E-6; 00126 c->K = 5; 00127 } 00128 00129 DefiniteIntegral::~DefiniteIntegral() { 00130 delete c; 00131 } 00132 00133 DefiniteIntegral::DefiniteIntegral(const DefiniteIntegral & right) 00134 :AbsFunctional(right), c(new Clockwork(*right.c)) { 00135 } 00136 00137 DefiniteIntegral & DefiniteIntegral::operator = (const DefiniteIntegral & right) { 00138 if (this!=&right) { 00139 delete c; 00140 c = new Clockwork(*right.c); 00141 } 00142 return *this; 00143 } 00144 00145 void DefiniteIntegral::setEpsilon(double eps) { 00146 c->EPS=eps; 00147 } 00148 00149 void DefiniteIntegral::setMaxIter(unsigned int maxIter) { 00150 c->MAXITER=maxIter; 00151 } 00152 00153 void DefiniteIntegral::setMinOrder(unsigned int minOrder) { 00154 c->K=(minOrder+1)/2; 00155 } 00156 00157 double DefiniteIntegral::operator [] (const AbsFunction & function) const { 00158 00159 const Clockwork::QuadratureRule * rule = c->type==OPEN ? 00160 (Clockwork::QuadratureRule *) new Clockwork::XtMidpointQuadratureRule() : 00161 (Clockwork::QuadratureRule *) new Clockwork::TrapezoidQuadratureRule(); 00162 double xMult=rule->stepMultiplier(); 00163 00164 c->nFunctionCalls=0; 00165 std::vector<double> s(c->MAXITER+2),h(c->MAXITER+2); 00166 h[1]=1.0; 00167 for (unsigned int j=1;j<=c->MAXITER;j++) { 00168 s[j]=rule->integrate(function, c->a, c->b, j); 00169 c->nFunctionCalls=rule->numFunctionCalls(); 00170 if (j>=c->K) { 00171 double ss, dss; 00172 c->polint(h.begin()+j-c->K,s.begin()+j-c->K,0.0,ss, dss); 00173 if (fabs(dss) <= c->EPS*fabs(ss)) { 00174 delete rule; 00175 return ss; 00176 } 00177 } 00178 s[j+1]=s[j]; 00179 h[j+1]=h[j]/xMult/xMult; 00180 } 00181 delete rule; 00182 throw std::runtime_error("DefiniteIntegral: too many steps. No convergence"); 00183 return 0.0; // Never get here. 00184 } 00185 00186 void DefiniteIntegral::Clockwork::polint(std::vector<double>::iterator xArray, std::vector<double>::iterator yArray, double x, double & y, double & deltay) const { 00187 double dif = fabs(x-xArray[1]),dift; 00188 std::vector<double> c(K+1),d(K+1); 00189 unsigned int ns=1; 00190 for (unsigned int i=1;i<=K;i++) { 00191 dift=fabs(x-xArray[i]); 00192 if (dift<dif) { 00193 ns=i; 00194 dif=dift; 00195 } 00196 c[i]=d[i]=yArray[i]; 00197 } 00198 y = yArray[ns--]; 00199 for (unsigned int m=1;m<K;m++) { 00200 for (unsigned int i=1;i<=K-m;i++) { 00201 double ho = xArray[i]-x; 00202 double hp= xArray[i+m]-x; 00203 double w=c[i+1]-d[i]; 00204 double den=ho-hp; 00205 if (den==0) 00206 std::cerr 00207 << "Error in polynomial extrapolation" 00208 << std::endl; 00209 den=w/den; 00210 d[i]=hp*den; 00211 c[i]=ho*den; 00212 } 00213 deltay = 2*ns < (K-m) ? c[ns+1]: d[ns--]; 00214 y += deltay; 00215 } 00216 } 00217 00218 unsigned int DefiniteIntegral::numFunctionCalls() const { 00219 return c->nFunctionCalls; 00220 } 00221 00222 // Quadrature rules: 00223 double DefiniteIntegral::Clockwork::TrapezoidQuadratureRule::integrate(const AbsFunction & function, double a, double b, unsigned int n) const { 00224 unsigned int it, j; 00225 if (n==1) { 00226 retVal = 0.5*(b-a)*(function(a)+function(b)); 00227 nFunctionCalls+=2; 00228 } 00229 else { 00230 for (it=1,j=1;j<n-1;j++) it <<=1; 00231 double tnm=it; 00232 double del = (b-a)/tnm; 00233 double x=a+0.5*del; 00234 double sum; 00235 for (sum=0.0,j=1;j<=it;j++,x+=del) { 00236 sum +=function(x); 00237 nFunctionCalls++; 00238 } 00239 retVal = 0.5*(retVal+(b-a)*sum/tnm); 00240 } 00241 return retVal; 00242 } 00243 00244 // Quadrature rules: 00245 double DefiniteIntegral::Clockwork::XtMidpointQuadratureRule::integrate(const AbsFunction & function, double a, double b, unsigned int n) const { 00246 unsigned int it, j; 00247 if (n==1) { 00248 retVal = (b-a)*(function((a+b)/2.0)); 00249 nFunctionCalls+=1; 00250 } 00251 else { 00252 for (it=1,j=1;j<n-1;j++) it *=3; 00253 double tnm=it; 00254 double del = (b-a)/(3.0*tnm); 00255 double ddel = del+del; 00256 double x=a+0.5*del; 00257 double sum=0; 00258 for (j=1;j<=it;j++) { 00259 sum +=function(x); 00260 x+=ddel; 00261 sum +=function(x); 00262 x+=del; 00263 nFunctionCalls+=2; 00264 } 00265 retVal = (retVal+(b-a)*sum/tnm)/3.0; 00266 } 00267 return retVal; 00268 } 00269 00270 00271 00272 } // namespace Genfun