Files
geant4/source/global/HEPNumerics/include/G4Integrator.icc
2020-06-26 10:23:25 +02:00

1478 lines
46 KiB
Plaintext

//
// ********************************************************************
// * License and Disclaimer *
// * *
// * The Geant4 software is copyright of the Copyright Holders of *
// * the Geant4 Collaboration. It is provided under the terms and *
// * conditions of the Geant4 Software License, included in the file *
// * LICENSE and available at http://cern.ch/geant4/license . These *
// * include a list of copyright holders. *
// * *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work make any representation or warranty, express or implied, *
// * regarding this software system or assume any liability for its *
// * use. Please see the license in the file LICENSE and URL above *
// * for the full disclaimer and the limitation of liability. *
// * *
// * This code implementation is the result of the scientific and *
// * technical work of the GEANT4 collaboration. *
// * By using, copying, modifying or distributing the software (or *
// * any work based on the software) you agree to acknowledge its *
// * use in resulting scientific publications, and indicate your *
// * acceptance of all terms of the Geant4 Software license. *
// ********************************************************************
//
// G4Integrator inline methods implementation
//
// Author: V.Grichine, 04.09.1999 - First implementation based on
// G4SimpleIntegration class with H.P.Wellisch, G.Cosmo, and
// E.TCherniaev advises
// --------------------------------------------------------------------
/////////////////////////////////////////////////////////////////////
//
// Sympson integration method
//
/////////////////////////////////////////////////////////////////////
//
// Integration of class member functions T::f by Simpson method.
template <class T, class F>
G4double G4Integrator<T, F>::Simpson(T& typeT, F f, G4double xInitial,
G4double xFinal, G4int iterationNumber)
{
G4int i;
G4double step = (xFinal - xInitial) / iterationNumber;
G4double x = xInitial;
G4double xPlus = xInitial + 0.5 * step;
G4double mean = ((typeT.*f)(xInitial) + (typeT.*f)(xFinal)) * 0.5;
G4double sum = (typeT.*f)(xPlus);
for(i = 1; i < iterationNumber; ++i)
{
x += step;
xPlus += step;
mean += (typeT.*f)(x);
sum += (typeT.*f)(xPlus);
}
mean += 2.0 * sum;
return mean * step / 3.0;
}
/////////////////////////////////////////////////////////////////////
//
// Integration of class member functions T::f by Simpson method.
// Convenient to use with 'this' pointer
template <class T, class F>
G4double G4Integrator<T, F>::Simpson(T* ptrT, F f, G4double xInitial,
G4double xFinal, G4int iterationNumber)
{
G4int i;
G4double step = (xFinal - xInitial) / iterationNumber;
G4double x = xInitial;
G4double xPlus = xInitial + 0.5 * step;
G4double mean = ((ptrT->*f)(xInitial) + (ptrT->*f)(xFinal)) * 0.5;
G4double sum = (ptrT->*f)(xPlus);
for(i = 1; i < iterationNumber; ++i)
{
x += step;
xPlus += step;
mean += (ptrT->*f)(x);
sum += (ptrT->*f)(xPlus);
}
mean += 2.0 * sum;
return mean * step / 3.0;
}
/////////////////////////////////////////////////////////////////////
//
// Integration of class member functions T::f by Simpson method.
// Convenient to use, when function f is defined in global scope, i.e. in main()
// program
template <class T, class F>
G4double G4Integrator<T, F>::Simpson(G4double (*f)(G4double), G4double xInitial,
G4double xFinal, G4int iterationNumber)
{
G4int i;
G4double step = (xFinal - xInitial) / iterationNumber;
G4double x = xInitial;
G4double xPlus = xInitial + 0.5 * step;
G4double mean = ((*f)(xInitial) + (*f)(xFinal)) * 0.5;
G4double sum = (*f)(xPlus);
for(i = 1; i < iterationNumber; ++i)
{
x += step;
xPlus += step;
mean += (*f)(x);
sum += (*f)(xPlus);
}
mean += 2.0 * sum;
return mean * step / 3.0;
}
//////////////////////////////////////////////////////////////////////////
//
// Adaptive Gauss method
//
//////////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
G4double G4Integrator<T, F>::Gauss(T& typeT, F f, G4double xInitial,
G4double xFinal)
{
static const G4double root = 1.0 / std::sqrt(3.0);
G4double xMean = (xInitial + xFinal) / 2.0;
G4double Step = (xFinal - xInitial) / 2.0;
G4double delta = Step * root;
G4double sum = ((typeT.*f)(xMean + delta) + (typeT.*f)(xMean - delta));
return sum * Step;
}
//////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
G4double G4Integrator<T, F>::Gauss(T* ptrT, F f, G4double a, G4double b)
{
return Gauss(*ptrT, f, a, b);
}
///////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
G4double G4Integrator<T, F>::Gauss(G4double (*f)(G4double), G4double xInitial,
G4double xFinal)
{
static const G4double root = 1.0 / std::sqrt(3.0);
G4double xMean = (xInitial + xFinal) / 2.0;
G4double Step = (xFinal - xInitial) / 2.0;
G4double delta = Step * root;
G4double sum = ((*f)(xMean + delta) + (*f)(xMean - delta));
return sum * Step;
}
///////////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
void G4Integrator<T, F>::AdaptGauss(T& typeT, F f, G4double xInitial,
G4double xFinal, G4double fTolerance,
G4double& sum, G4int& depth)
{
if(depth > 100)
{
G4cout << "G4Integrator<T,F>::AdaptGauss: WARNING !!!" << G4endl;
G4cout << "Function varies too rapidly to get stated accuracy in 100 steps "
<< G4endl;
return;
}
G4double xMean = (xInitial + xFinal) / 2.0;
G4double leftHalf = Gauss(typeT, f, xInitial, xMean);
G4double rightHalf = Gauss(typeT, f, xMean, xFinal);
G4double full = Gauss(typeT, f, xInitial, xFinal);
if(std::fabs(leftHalf + rightHalf - full) < fTolerance)
{
sum += full;
}
else
{
++depth;
AdaptGauss(typeT, f, xInitial, xMean, fTolerance, sum, depth);
AdaptGauss(typeT, f, xMean, xFinal, fTolerance, sum, depth);
}
}
template <class T, class F>
void G4Integrator<T, F>::AdaptGauss(T* ptrT, F f, G4double xInitial,
G4double xFinal, G4double fTolerance,
G4double& sum, G4int& depth)
{
AdaptGauss(*ptrT, f, xInitial, xFinal, fTolerance, sum, depth);
}
/////////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
void G4Integrator<T, F>::AdaptGauss(G4double (*f)(G4double), G4double xInitial,
G4double xFinal, G4double fTolerance,
G4double& sum, G4int& depth)
{
if(depth > 100)
{
G4cout << "G4SimpleIntegration::AdaptGauss: WARNING !!!" << G4endl;
G4cout << "Function varies too rapidly to get stated accuracy in 100 steps "
<< G4endl;
return;
}
G4double xMean = (xInitial + xFinal) / 2.0;
G4double leftHalf = Gauss(f, xInitial, xMean);
G4double rightHalf = Gauss(f, xMean, xFinal);
G4double full = Gauss(f, xInitial, xFinal);
if(std::fabs(leftHalf + rightHalf - full) < fTolerance)
{
sum += full;
}
else
{
++depth;
AdaptGauss(f, xInitial, xMean, fTolerance, sum, depth);
AdaptGauss(f, xMean, xFinal, fTolerance, sum, depth);
}
}
////////////////////////////////////////////////////////////////////////
//
// Adaptive Gauss integration with accuracy 'e'
// Convenient for using with class object typeT
template <class T, class F>
G4double G4Integrator<T, F>::AdaptiveGauss(T& typeT, F f, G4double xInitial,
G4double xFinal, G4double e)
{
G4int depth = 0;
G4double sum = 0.0;
AdaptGauss(typeT, f, xInitial, xFinal, e, sum, depth);
return sum;
}
////////////////////////////////////////////////////////////////////////
//
// Adaptive Gauss integration with accuracy 'e'
// Convenient for using with 'this' pointer
template <class T, class F>
G4double G4Integrator<T, F>::AdaptiveGauss(T* ptrT, F f, G4double xInitial,
G4double xFinal, G4double e)
{
return AdaptiveGauss(*ptrT, f, xInitial, xFinal, e);
}
////////////////////////////////////////////////////////////////////////
//
// Adaptive Gauss integration with accuracy 'e'
// Convenient for using with global scope function f
template <class T, class F>
G4double G4Integrator<T, F>::AdaptiveGauss(G4double (*f)(G4double),
G4double xInitial, G4double xFinal,
G4double e)
{
G4int depth = 0;
G4double sum = 0.0;
AdaptGauss(f, xInitial, xFinal, e, sum, depth);
return sum;
}
////////////////////////////////////////////////////////////////////////////
// Gauss integration methods involving ortogonal polynomials
////////////////////////////////////////////////////////////////////////////
//
// Methods involving Legendre polynomials
//
/////////////////////////////////////////////////////////////////////////
//
// The value nLegendre set the accuracy required, i.e the number of points
// where the function pFunction will be evaluated during integration.
// The function creates the arrays for abscissas and weights that used
// in Gauss-Legendre quadrature method.
// The values a and b are the limits of integration of the function f .
// nLegendre MUST BE EVEN !!!
// Returns the integral of the function f between a and b, by 2*fNumber point
// Gauss-Legendre integration: the function is evaluated exactly
// 2*fNumber times at interior points in the range of integration.
// Since the weights and abscissas are, in this case, symmetric around
// the midpoint of the range of integration, there are actually only
// fNumber distinct values of each.
// Convenient for using with some class object dataT
template <class T, class F>
G4double G4Integrator<T, F>::Legendre(T& typeT, F f, G4double a, G4double b,
G4int nLegendre)
{
G4double nwt, nwt1, temp1, temp2, temp3, temp;
G4double xDiff, xMean, dx, integral;
const G4double tolerance = 1.6e-10;
G4int i, j, k = nLegendre;
G4int fNumber = (nLegendre + 1) / 2;
if(2 * fNumber != k)
{
G4Exception("G4Integrator<T,F>::Legendre(T&,F, ...)", "InvalidCall",
FatalException, "Invalid (odd) nLegendre in constructor.");
}
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; ++i) // Loop over the desired roots
{
nwt = std::cos(CLHEP::pi * (i - 0.25) /
(k + 0.5)); // Initial root approximation
do // loop of Newton's method
{
temp1 = 1.0;
temp2 = 0.0;
for(j = 1; j <= k; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 = ((2.0 * j - 1.0) * nwt * temp2 - (j - 1.0) * temp3) / j;
}
temp = k * (nwt * temp1 - temp2) / (nwt * nwt - 1.0);
nwt1 = nwt;
nwt = nwt1 - temp1 / temp; // Newton's method
} while(std::fabs(nwt - nwt1) > tolerance);
fAbscissa[fNumber - i] = nwt;
fWeight[fNumber - i] = 2.0 / ((1.0 - nwt * nwt) * temp * temp);
}
//
// Now we ready to get integral
//
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < fNumber; ++i)
{
dx = xDiff * fAbscissa[i];
integral += fWeight[i] * ((typeT.*f)(xMean + dx) + (typeT.*f)(xMean - dx));
}
delete[] fAbscissa;
delete[] fWeight;
return integral *= xDiff;
}
///////////////////////////////////////////////////////////////////////
//
// Convenient for using with the pointer 'this'
template <class T, class F>
G4double G4Integrator<T, F>::Legendre(T* ptrT, F f, G4double a, G4double b,
G4int nLegendre)
{
return Legendre(*ptrT, f, a, b, nLegendre);
}
///////////////////////////////////////////////////////////////////////
//
// Convenient for using with global scope function f
template <class T, class F>
G4double G4Integrator<T, F>::Legendre(G4double (*f)(G4double), G4double a,
G4double b, G4int nLegendre)
{
G4double nwt, nwt1, temp1, temp2, temp3, temp;
G4double xDiff, xMean, dx, integral;
const G4double tolerance = 1.6e-10;
G4int i, j, k = nLegendre;
G4int fNumber = (nLegendre + 1) / 2;
if(2 * fNumber != k)
{
G4Exception("G4Integrator<T,F>::Legendre(...)", "InvalidCall",
FatalException, "Invalid (odd) nLegendre in constructor.");
}
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; i++) // Loop over the desired roots
{
nwt = std::cos(CLHEP::pi * (i - 0.25) /
(k + 0.5)); // Initial root approximation
do // loop of Newton's method
{
temp1 = 1.0;
temp2 = 0.0;
for(j = 1; j <= k; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 = ((2.0 * j - 1.0) * nwt * temp2 - (j - 1.0) * temp3) / j;
}
temp = k * (nwt * temp1 - temp2) / (nwt * nwt - 1.0);
nwt1 = nwt;
nwt = nwt1 - temp1 / temp; // Newton's method
} while(std::fabs(nwt - nwt1) > tolerance);
fAbscissa[fNumber - i] = nwt;
fWeight[fNumber - i] = 2.0 / ((1.0 - nwt * nwt) * temp * temp);
}
//
// Now we ready to get integral
//
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < fNumber; ++i)
{
dx = xDiff * fAbscissa[i];
integral += fWeight[i] * ((*f)(xMean + dx) + (*f)(xMean - dx));
}
delete[] fAbscissa;
delete[] fWeight;
return integral *= xDiff;
}
////////////////////////////////////////////////////////////////////////////
//
// Returns the integral of the function to be pointed by T::f between a and b,
// by ten point Gauss-Legendre integration: the function is evaluated exactly
// ten times at interior points in the range of integration. Since the weights
// and abscissas are, in this case, symmetric around the midpoint of the
// range of integration, there are actually only five distinct values of each
// Convenient for using with class object typeT
template <class T, class F>
G4double G4Integrator<T, F>::Legendre10(T& typeT, F f, G4double a, G4double b)
{
G4int i;
G4double xDiff, xMean, dx, integral;
// From Abramowitz M., Stegan I.A. 1964 , Handbook of Math... , p. 916
static const G4double abscissa[] = { 0.148874338981631, 0.433395394129247,
0.679409568299024, 0.865063366688985,
0.973906528517172 };
static const G4double weight[] = { 0.295524224714753, 0.269266719309996,
0.219086362515982, 0.149451349150581,
0.066671344308688 };
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < 5; ++i)
{
dx = xDiff * abscissa[i];
integral += weight[i] * ((typeT.*f)(xMean + dx) + (typeT.*f)(xMean - dx));
}
return integral *= xDiff;
}
///////////////////////////////////////////////////////////////////////////
//
// Convenient for using with the pointer 'this'
template <class T, class F>
G4double G4Integrator<T, F>::Legendre10(T* ptrT, F f, G4double a, G4double b)
{
return Legendre10(*ptrT, f, a, b);
}
//////////////////////////////////////////////////////////////////////////
//
// Convenient for using with global scope functions
template <class T, class F>
G4double G4Integrator<T, F>::Legendre10(G4double (*f)(G4double), G4double a,
G4double b)
{
G4int i;
G4double xDiff, xMean, dx, integral;
// From Abramowitz M., Stegan I.A. 1964 , Handbook of Math... , p. 916
static const G4double abscissa[] = { 0.148874338981631, 0.433395394129247,
0.679409568299024, 0.865063366688985,
0.973906528517172 };
static const G4double weight[] = { 0.295524224714753, 0.269266719309996,
0.219086362515982, 0.149451349150581,
0.066671344308688 };
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < 5; ++i)
{
dx = xDiff * abscissa[i];
integral += weight[i] * ((*f)(xMean + dx) + (*f)(xMean - dx));
}
return integral *= xDiff;
}
///////////////////////////////////////////////////////////////////////
//
// Returns the integral of the function to be pointed by T::f between a and b,
// by 96 point Gauss-Legendre integration: the function is evaluated exactly
// ten Times at interior points in the range of integration. Since the weights
// and abscissas are, in this case, symmetric around the midpoint of the
// range of integration, there are actually only five distinct values of each
// Convenient for using with some class object typeT
template <class T, class F>
G4double G4Integrator<T, F>::Legendre96(T& typeT, F f, G4double a, G4double b)
{
G4int i;
G4double xDiff, xMean, dx, integral;
// From Abramowitz M., Stegan I.A. 1964 , Handbook of Math... , p. 919
static const G4double abscissa[] = {
0.016276744849602969579, 0.048812985136049731112,
0.081297495464425558994, 0.113695850110665920911,
0.145973714654896941989, 0.178096882367618602759, // 6
0.210031310460567203603, 0.241743156163840012328,
0.273198812591049141487, 0.304364944354496353024,
0.335208522892625422616, 0.365696861472313635031, // 12
0.395797649828908603285, 0.425478988407300545365,
0.454709422167743008636, 0.483457973920596359768,
0.511694177154667673586, 0.539388108324357436227, // 18
0.566510418561397168404, 0.593032364777572080684,
0.618925840125468570386, 0.644163403784967106798,
0.668718310043916153953, 0.692564536642171561344, // 24
0.715676812348967626225, 0.738030643744400132851,
0.759602341176647498703, 0.780369043867433217604,
0.800308744139140817229, 0.819400310737931675539, // 30
0.837623511228187121494, 0.854959033434601455463,
0.871388505909296502874, 0.886894517402420416057,
0.901460635315852341319, 0.915071423120898074206, // 36
0.927712456722308690965, 0.939370339752755216932,
0.950032717784437635756, 0.959688291448742539300,
0.968326828463264212174, 0.975939174585136466453, // 42
0.982517263563014677447, 0.988054126329623799481,
0.992543900323762624572, 0.995981842987209290650,
0.998364375863181677724, 0.999689503883230766828 // 48
};
static const G4double weight[] = {
0.032550614492363166242, 0.032516118713868835987,
0.032447163714064269364, 0.032343822568575928429,
0.032206204794030250669, 0.032034456231992663218, // 6
0.031828758894411006535, 0.031589330770727168558,
0.031316425596862355813, 0.031010332586313837423,
0.030671376123669149014, 0.030299915420827593794, // 12
0.029896344136328385984, 0.029461089958167905970,
0.028994614150555236543, 0.028497411065085385646,
0.027970007616848334440, 0.027412962726029242823, // 18
0.026826866725591762198, 0.026212340735672413913,
0.025570036005349361499, 0.024900633222483610288,
0.024204841792364691282, 0.023483399085926219842, // 24
0.022737069658329374001, 0.021966644438744349195,
0.021172939892191298988, 0.020356797154333324595,
0.019519081140145022410, 0.018660679627411467385, // 30
0.017782502316045260838, 0.016885479864245172450,
0.015970562902562291381, 0.015038721026994938006,
0.014090941772314860916, 0.013128229566961572637, // 36
0.012151604671088319635, 0.011162102099838498591,
0.010160770535008415758, 0.009148671230783386633,
0.008126876925698759217, 0.007096470791153865269, // 42
0.006058545504235961683, 0.005014202742927517693,
0.003964554338444686674, 0.002910731817934946408,
0.001853960788946921732, 0.000796792065552012429 // 48
};
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < 48; ++i)
{
dx = xDiff * abscissa[i];
integral += weight[i] * ((typeT.*f)(xMean + dx) + (typeT.*f)(xMean - dx));
}
return integral *= xDiff;
}
///////////////////////////////////////////////////////////////////////
//
// Convenient for using with the pointer 'this'
template <class T, class F>
G4double G4Integrator<T, F>::Legendre96(T* ptrT, F f, G4double a, G4double b)
{
return Legendre96(*ptrT, f, a, b);
}
///////////////////////////////////////////////////////////////////////
//
// Convenient for using with global scope function f
template <class T, class F>
G4double G4Integrator<T, F>::Legendre96(G4double (*f)(G4double), G4double a,
G4double b)
{
G4int i;
G4double xDiff, xMean, dx, integral;
// From Abramowitz M., Stegan I.A. 1964 , Handbook of Math... , p. 919
static const G4double abscissa[] = {
0.016276744849602969579, 0.048812985136049731112,
0.081297495464425558994, 0.113695850110665920911,
0.145973714654896941989, 0.178096882367618602759, // 6
0.210031310460567203603, 0.241743156163840012328,
0.273198812591049141487, 0.304364944354496353024,
0.335208522892625422616, 0.365696861472313635031, // 12
0.395797649828908603285, 0.425478988407300545365,
0.454709422167743008636, 0.483457973920596359768,
0.511694177154667673586, 0.539388108324357436227, // 18
0.566510418561397168404, 0.593032364777572080684,
0.618925840125468570386, 0.644163403784967106798,
0.668718310043916153953, 0.692564536642171561344, // 24
0.715676812348967626225, 0.738030643744400132851,
0.759602341176647498703, 0.780369043867433217604,
0.800308744139140817229, 0.819400310737931675539, // 30
0.837623511228187121494, 0.854959033434601455463,
0.871388505909296502874, 0.886894517402420416057,
0.901460635315852341319, 0.915071423120898074206, // 36
0.927712456722308690965, 0.939370339752755216932,
0.950032717784437635756, 0.959688291448742539300,
0.968326828463264212174, 0.975939174585136466453, // 42
0.982517263563014677447, 0.988054126329623799481,
0.992543900323762624572, 0.995981842987209290650,
0.998364375863181677724, 0.999689503883230766828 // 48
};
static const G4double weight[] = {
0.032550614492363166242, 0.032516118713868835987,
0.032447163714064269364, 0.032343822568575928429,
0.032206204794030250669, 0.032034456231992663218, // 6
0.031828758894411006535, 0.031589330770727168558,
0.031316425596862355813, 0.031010332586313837423,
0.030671376123669149014, 0.030299915420827593794, // 12
0.029896344136328385984, 0.029461089958167905970,
0.028994614150555236543, 0.028497411065085385646,
0.027970007616848334440, 0.027412962726029242823, // 18
0.026826866725591762198, 0.026212340735672413913,
0.025570036005349361499, 0.024900633222483610288,
0.024204841792364691282, 0.023483399085926219842, // 24
0.022737069658329374001, 0.021966644438744349195,
0.021172939892191298988, 0.020356797154333324595,
0.019519081140145022410, 0.018660679627411467385, // 30
0.017782502316045260838, 0.016885479864245172450,
0.015970562902562291381, 0.015038721026994938006,
0.014090941772314860916, 0.013128229566961572637, // 36
0.012151604671088319635, 0.011162102099838498591,
0.010160770535008415758, 0.009148671230783386633,
0.008126876925698759217, 0.007096470791153865269, // 42
0.006058545504235961683, 0.005014202742927517693,
0.003964554338444686674, 0.002910731817934946408,
0.001853960788946921732, 0.000796792065552012429 // 48
};
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
integral = 0.0;
for(i = 0; i < 48; ++i)
{
dx = xDiff * abscissa[i];
integral += weight[i] * ((*f)(xMean + dx) + (*f)(xMean - dx));
}
return integral *= xDiff;
}
//////////////////////////////////////////////////////////////////////////////
//
// Methods involving Chebyshev polynomials
//
///////////////////////////////////////////////////////////////////////////
//
// Integrates function pointed by T::f from a to b by Gauss-Chebyshev
// quadrature method.
// Convenient for using with class object typeT
template <class T, class F>
G4double G4Integrator<T, F>::Chebyshev(T& typeT, F f, G4double a, G4double b,
G4int nChebyshev)
{
G4int i;
G4double xDiff, xMean, dx, integral = 0.0;
G4int fNumber = nChebyshev; // Try to reduce fNumber twice ??
G4double cof = CLHEP::pi / fNumber;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 0; i < fNumber; ++i)
{
fAbscissa[i] = std::cos(cof * (i + 0.5));
fWeight[i] = cof * std::sqrt(1 - fAbscissa[i] * fAbscissa[i]);
}
//
// Now we ready to estimate the integral
//
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
for(i = 0; i < fNumber; ++i)
{
dx = xDiff * fAbscissa[i];
integral += fWeight[i] * (typeT.*f)(xMean + dx);
}
delete[] fAbscissa;
delete[] fWeight;
return integral *= xDiff;
}
///////////////////////////////////////////////////////////////////////
//
// Convenient for using with 'this' pointer
template <class T, class F>
G4double G4Integrator<T, F>::Chebyshev(T* ptrT, F f, G4double a, G4double b,
G4int n)
{
return Chebyshev(*ptrT, f, a, b, n);
}
////////////////////////////////////////////////////////////////////////
//
// For use with global scope functions f
template <class T, class F>
G4double G4Integrator<T, F>::Chebyshev(G4double (*f)(G4double), G4double a,
G4double b, G4int nChebyshev)
{
G4int i;
G4double xDiff, xMean, dx, integral = 0.0;
G4int fNumber = nChebyshev; // Try to reduce fNumber twice ??
G4double cof = CLHEP::pi / fNumber;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 0; i < fNumber; ++i)
{
fAbscissa[i] = std::cos(cof * (i + 0.5));
fWeight[i] = cof * std::sqrt(1 - fAbscissa[i] * fAbscissa[i]);
}
//
// Now we ready to estimate the integral
//
xMean = 0.5 * (a + b);
xDiff = 0.5 * (b - a);
for(i = 0; i < fNumber; ++i)
{
dx = xDiff * fAbscissa[i];
integral += fWeight[i] * (*f)(xMean + dx);
}
delete[] fAbscissa;
delete[] fWeight;
return integral *= xDiff;
}
//////////////////////////////////////////////////////////////////////
//
// Method involving Laguerre polynomials
//
//////////////////////////////////////////////////////////////////////
//
// Integral from zero to infinity of std::pow(x,alpha)*std::exp(-x)*f(x).
// The value of nLaguerre sets the accuracy.
// The function creates arrays fAbscissa[0,..,nLaguerre-1] and
// fWeight[0,..,nLaguerre-1] .
// Convenient for using with class object 'typeT' and (typeT.*f) function
// (T::f)
template <class T, class F>
G4double G4Integrator<T, F>::Laguerre(T& typeT, F f, G4double alpha,
G4int nLaguerre)
{
const G4double tolerance = 1.0e-10;
const G4int maxNumber = 12;
G4int i, j, k;
G4double nwt = 0., nwt1, temp1, temp2, temp3, temp, cofi;
G4double integral = 0.0;
G4int fNumber = nLaguerre;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; ++i) // Loop over the desired roots
{
if(i == 1)
{
nwt = (1.0 + alpha) * (3.0 + 0.92 * alpha) /
(1.0 + 2.4 * fNumber + 1.8 * alpha);
}
else if(i == 2)
{
nwt += (15.0 + 6.25 * alpha) / (1.0 + 0.9 * alpha + 2.5 * fNumber);
}
else
{
cofi = i - 2;
nwt += ((1.0 + 2.55 * cofi) / (1.9 * cofi) +
1.26 * cofi * alpha / (1.0 + 3.5 * cofi)) *
(nwt - fAbscissa[i - 3]) / (1.0 + 0.3 * alpha);
}
for(k = 1; k <= maxNumber; ++k)
{
temp1 = 1.0;
temp2 = 0.0;
for(j = 1; j <= fNumber; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 =
((2 * j - 1 + alpha - nwt) * temp2 - (j - 1 + alpha) * temp3) / j;
}
temp = (fNumber * temp1 - (fNumber + alpha) * temp2) / nwt;
nwt1 = nwt;
nwt = nwt1 - temp1 / temp;
if(std::fabs(nwt - nwt1) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Laguerre(T,F, ...)", "Error",
FatalException, "Too many (>12) iterations.");
}
fAbscissa[i - 1] = nwt;
fWeight[i - 1] = -std::exp(GammaLogarithm(alpha + fNumber) -
GammaLogarithm((G4double) fNumber)) /
(temp * fNumber * temp2);
}
//
// Integral evaluation
//
for(i = 0; i < fNumber; ++i)
{
integral += fWeight[i] * (typeT.*f)(fAbscissa[i]);
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
//////////////////////////////////////////////////////////////////////
//
//
template <class T, class F>
G4double G4Integrator<T, F>::Laguerre(T* ptrT, F f, G4double alpha,
G4int nLaguerre)
{
return Laguerre(*ptrT, f, alpha, nLaguerre);
}
////////////////////////////////////////////////////////////////////////
//
// For use with global scope functions f
template <class T, class F>
G4double G4Integrator<T, F>::Laguerre(G4double (*f)(G4double), G4double alpha,
G4int nLaguerre)
{
const G4double tolerance = 1.0e-10;
const G4int maxNumber = 12;
G4int i, j, k;
G4double nwt = 0., nwt1, temp1, temp2, temp3, temp, cofi;
G4double integral = 0.0;
G4int fNumber = nLaguerre;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; ++i) // Loop over the desired roots
{
if(i == 1)
{
nwt = (1.0 + alpha) * (3.0 + 0.92 * alpha) /
(1.0 + 2.4 * fNumber + 1.8 * alpha);
}
else if(i == 2)
{
nwt += (15.0 + 6.25 * alpha) / (1.0 + 0.9 * alpha + 2.5 * fNumber);
}
else
{
cofi = i - 2;
nwt += ((1.0 + 2.55 * cofi) / (1.9 * cofi) +
1.26 * cofi * alpha / (1.0 + 3.5 * cofi)) *
(nwt - fAbscissa[i - 3]) / (1.0 + 0.3 * alpha);
}
for(k = 1; k <= maxNumber; ++k)
{
temp1 = 1.0;
temp2 = 0.0;
for(j = 1; j <= fNumber; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 =
((2 * j - 1 + alpha - nwt) * temp2 - (j - 1 + alpha) * temp3) / j;
}
temp = (fNumber * temp1 - (fNumber + alpha) * temp2) / nwt;
nwt1 = nwt;
nwt = nwt1 - temp1 / temp;
if(std::fabs(nwt - nwt1) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Laguerre( ...)", "Error", FatalException,
"Too many (>12) iterations.");
}
fAbscissa[i - 1] = nwt;
fWeight[i - 1] = -std::exp(GammaLogarithm(alpha + fNumber) -
GammaLogarithm((G4double) fNumber)) /
(temp * fNumber * temp2);
}
//
// Integral evaluation
//
for(i = 0; i < fNumber; i++)
{
integral += fWeight[i] * (*f)(fAbscissa[i]);
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
///////////////////////////////////////////////////////////////////////
//
// Auxiliary function which returns the value of std::log(gamma-function(x))
// Returns the value ln(Gamma(xx) for xx > 0. Full accuracy is obtained for
// xx > 1. For 0 < xx < 1. the reflection formula (6.1.4) can be used first.
// (Adapted from Numerical Recipes in C)
//
template <class T, class F>
G4double G4Integrator<T, F>::GammaLogarithm(G4double xx)
{
static const G4double cof[6] = { 76.18009172947146, -86.50532032941677,
24.01409824083091, -1.231739572450155,
0.1208650973866179e-2, -0.5395239384953e-5 };
G4int j;
G4double x = xx - 1.0;
G4double tmp = x + 5.5;
tmp -= (x + 0.5) * std::log(tmp);
G4double ser = 1.000000000190015;
for(j = 0; j <= 5; ++j)
{
x += 1.0;
ser += cof[j] / x;
}
return -tmp + std::log(2.5066282746310005 * ser);
}
///////////////////////////////////////////////////////////////////////
//
// Method involving Hermite polynomials
//
///////////////////////////////////////////////////////////////////////
//
//
// Gauss-Hermite method for integration of std::exp(-x*x)*f(x)
// from minus infinity to plus infinity .
//
template <class T, class F>
G4double G4Integrator<T, F>::Hermite(T& typeT, F f, G4int nHermite)
{
const G4double tolerance = 1.0e-12;
const G4int maxNumber = 12;
G4int i, j, k;
G4double integral = 0.0;
G4double nwt = 0., nwt1, temp1, temp2, temp3, temp;
G4double piInMinusQ =
std::pow(CLHEP::pi, -0.25); // 1.0/std::sqrt(std::sqrt(pi)) ??
G4int fNumber = (nHermite + 1) / 2;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; ++i)
{
if(i == 1)
{
nwt = std::sqrt((G4double)(2 * nHermite + 1)) -
1.85575001 * std::pow((G4double)(2 * nHermite + 1), -0.16666999);
}
else if(i == 2)
{
nwt -= 1.14001 * std::pow((G4double) nHermite, 0.425999) / nwt;
}
else if(i == 3)
{
nwt = 1.86002 * nwt - 0.86002 * fAbscissa[0];
}
else if(i == 4)
{
nwt = 1.91001 * nwt - 0.91001 * fAbscissa[1];
}
else
{
nwt = 2.0 * nwt - fAbscissa[i - 3];
}
for(k = 1; k <= maxNumber; ++k)
{
temp1 = piInMinusQ;
temp2 = 0.0;
for(j = 1; j <= nHermite; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 = nwt * std::sqrt(2.0 / j) * temp2 -
std::sqrt(((G4double)(j - 1)) / j) * temp3;
}
temp = std::sqrt((G4double) 2 * nHermite) * temp2;
nwt1 = nwt;
nwt = nwt1 - temp1 / temp;
if(std::fabs(nwt - nwt1) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Hermite(T,F, ...)", "Error",
FatalException, "Too many (>12) iterations.");
}
fAbscissa[i - 1] = nwt;
fWeight[i - 1] = 2.0 / (temp * temp);
}
//
// Integral calculation
//
for(i = 0; i < fNumber; ++i)
{
integral +=
fWeight[i] * ((typeT.*f)(fAbscissa[i]) + (typeT.*f)(-fAbscissa[i]));
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
////////////////////////////////////////////////////////////////////////
//
// For use with 'this' pointer
template <class T, class F>
G4double G4Integrator<T, F>::Hermite(T* ptrT, F f, G4int n)
{
return Hermite(*ptrT, f, n);
}
////////////////////////////////////////////////////////////////////////
//
// For use with global scope f
template <class T, class F>
G4double G4Integrator<T, F>::Hermite(G4double (*f)(G4double), G4int nHermite)
{
const G4double tolerance = 1.0e-12;
const G4int maxNumber = 12;
G4int i, j, k;
G4double integral = 0.0;
G4double nwt = 0., nwt1, temp1, temp2, temp3, temp;
G4double piInMinusQ =
std::pow(CLHEP::pi, -0.25); // 1.0/std::sqrt(std::sqrt(pi)) ??
G4int fNumber = (nHermite + 1) / 2;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= fNumber; ++i)
{
if(i == 1)
{
nwt = std::sqrt((G4double)(2 * nHermite + 1)) -
1.85575001 * std::pow((G4double)(2 * nHermite + 1), -0.16666999);
}
else if(i == 2)
{
nwt -= 1.14001 * std::pow((G4double) nHermite, 0.425999) / nwt;
}
else if(i == 3)
{
nwt = 1.86002 * nwt - 0.86002 * fAbscissa[0];
}
else if(i == 4)
{
nwt = 1.91001 * nwt - 0.91001 * fAbscissa[1];
}
else
{
nwt = 2.0 * nwt - fAbscissa[i - 3];
}
for(k = 1; k <= maxNumber; ++k)
{
temp1 = piInMinusQ;
temp2 = 0.0;
for(j = 1; j <= nHermite; ++j)
{
temp3 = temp2;
temp2 = temp1;
temp1 = nwt * std::sqrt(2.0 / j) * temp2 -
std::sqrt(((G4double)(j - 1)) / j) * temp3;
}
temp = std::sqrt((G4double) 2 * nHermite) * temp2;
nwt1 = nwt;
nwt = nwt1 - temp1 / temp;
if(std::fabs(nwt - nwt1) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Hermite(...)", "Error", FatalException,
"Too many (>12) iterations.");
}
fAbscissa[i - 1] = nwt;
fWeight[i - 1] = 2.0 / (temp * temp);
}
//
// Integral calculation
//
for(i = 0; i < fNumber; ++i)
{
integral += fWeight[i] * ((*f)(fAbscissa[i]) + (*f)(-fAbscissa[i]));
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
////////////////////////////////////////////////////////////////////////////
//
// Method involving Jacobi polynomials
//
////////////////////////////////////////////////////////////////////////////
//
// Gauss-Jacobi method for integration of ((1-x)^alpha)*((1+x)^beta)*f(x)
// from minus unit to plus unit .
//
template <class T, class F>
G4double G4Integrator<T, F>::Jacobi(T& typeT, F f, G4double alpha,
G4double beta, G4int nJacobi)
{
const G4double tolerance = 1.0e-12;
const G4double maxNumber = 12;
G4int i, k, j;
G4double alphaBeta, alphaReduced, betaReduced, root1 = 0., root2 = 0.,
root3 = 0.;
G4double a, b, c, nwt1, nwt2, nwt3, nwt, temp, root = 0., rootTemp;
G4int fNumber = nJacobi;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= nJacobi; ++i)
{
if(i == 1)
{
alphaReduced = alpha / nJacobi;
betaReduced = beta / nJacobi;
root1 = (1.0 + alpha) * (2.78002 / (4.0 + nJacobi * nJacobi) +
0.767999 * alphaReduced / nJacobi);
root2 = 1.0 + 1.48 * alphaReduced + 0.96002 * betaReduced +
0.451998 * alphaReduced * alphaReduced +
0.83001 * alphaReduced * betaReduced;
root = 1.0 - root1 / root2;
}
else if(i == 2)
{
root1 = (4.1002 + alpha) / ((1.0 + alpha) * (1.0 + 0.155998 * alpha));
root2 = 1.0 + 0.06 * (nJacobi - 8.0) * (1.0 + 0.12 * alpha) / nJacobi;
root3 =
1.0 + 0.012002 * beta * (1.0 + 0.24997 * std::fabs(alpha)) / nJacobi;
root -= (1.0 - root) * root1 * root2 * root3;
}
else if(i == 3)
{
root1 = (1.67001 + 0.27998 * alpha) / (1.0 + 0.37002 * alpha);
root2 = 1.0 + 0.22 * (nJacobi - 8.0) / nJacobi;
root3 = 1.0 + 8.0 * beta / ((6.28001 + beta) * nJacobi * nJacobi);
root -= (fAbscissa[0] - root) * root1 * root2 * root3;
}
else if(i == nJacobi - 1)
{
root1 = (1.0 + 0.235002 * beta) / (0.766001 + 0.118998 * beta);
root2 = 1.0 / (1.0 + 0.639002 * (nJacobi - 4.0) /
(1.0 + 0.71001 * (nJacobi - 4.0)));
root3 = 1.0 / (1.0 + 20.0 * alpha / ((7.5 + alpha) * nJacobi * nJacobi));
root += (root - fAbscissa[nJacobi - 4]) * root1 * root2 * root3;
}
else if(i == nJacobi)
{
root1 = (1.0 + 0.37002 * beta) / (1.67001 + 0.27998 * beta);
root2 = 1.0 / (1.0 + 0.22 * (nJacobi - 8.0) / nJacobi);
root3 =
1.0 / (1.0 + 8.0 * alpha / ((6.28002 + alpha) * nJacobi * nJacobi));
root += (root - fAbscissa[nJacobi - 3]) * root1 * root2 * root3;
}
else
{
root = 3.0 * fAbscissa[i - 2] - 3.0 * fAbscissa[i - 3] + fAbscissa[i - 4];
}
alphaBeta = alpha + beta;
for(k = 1; k <= maxNumber; ++k)
{
temp = 2.0 + alphaBeta;
nwt1 = (alpha - beta + temp * root) / 2.0;
nwt2 = 1.0;
for(j = 2; j <= nJacobi; ++j)
{
nwt3 = nwt2;
nwt2 = nwt1;
temp = 2 * j + alphaBeta;
a = 2 * j * (j + alphaBeta) * (temp - 2.0);
b = (temp - 1.0) *
(alpha * alpha - beta * beta + temp * (temp - 2.0) * root);
c = 2.0 * (j - 1 + alpha) * (j - 1 + beta) * temp;
nwt1 = (b * nwt2 - c * nwt3) / a;
}
nwt = (nJacobi * (alpha - beta - temp * root) * nwt1 +
2.0 * (nJacobi + alpha) * (nJacobi + beta) * nwt2) /
(temp * (1.0 - root * root));
rootTemp = root;
root = rootTemp - nwt1 / nwt;
if(std::fabs(root - rootTemp) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Jacobi(T,F, ...)", "Error",
FatalException, "Too many (>12) iterations.");
}
fAbscissa[i - 1] = root;
fWeight[i - 1] =
std::exp(GammaLogarithm((G4double)(alpha + nJacobi)) +
GammaLogarithm((G4double)(beta + nJacobi)) -
GammaLogarithm((G4double)(nJacobi + 1.0)) -
GammaLogarithm((G4double)(nJacobi + alphaBeta + 1.0))) *
temp * std::pow(2.0, alphaBeta) / (nwt * nwt2);
}
//
// Calculation of the integral
//
G4double integral = 0.0;
for(i = 0; i < fNumber; ++i)
{
integral += fWeight[i] * (typeT.*f)(fAbscissa[i]);
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
/////////////////////////////////////////////////////////////////////////
//
// For use with 'this' pointer
template <class T, class F>
G4double G4Integrator<T, F>::Jacobi(T* ptrT, F f, G4double alpha, G4double beta,
G4int n)
{
return Jacobi(*ptrT, f, alpha, beta, n);
}
/////////////////////////////////////////////////////////////////////////
//
// For use with global scope f
template <class T, class F>
G4double G4Integrator<T, F>::Jacobi(G4double (*f)(G4double), G4double alpha,
G4double beta, G4int nJacobi)
{
const G4double tolerance = 1.0e-12;
const G4double maxNumber = 12;
G4int i, k, j;
G4double alphaBeta, alphaReduced, betaReduced, root1 = 0., root2 = 0.,
root3 = 0.;
G4double a, b, c, nwt1, nwt2, nwt3, nwt, temp, root = 0., rootTemp;
G4int fNumber = nJacobi;
G4double* fAbscissa = new G4double[fNumber];
G4double* fWeight = new G4double[fNumber];
for(i = 1; i <= nJacobi; ++i)
{
if(i == 1)
{
alphaReduced = alpha / nJacobi;
betaReduced = beta / nJacobi;
root1 = (1.0 + alpha) * (2.78002 / (4.0 + nJacobi * nJacobi) +
0.767999 * alphaReduced / nJacobi);
root2 = 1.0 + 1.48 * alphaReduced + 0.96002 * betaReduced +
0.451998 * alphaReduced * alphaReduced +
0.83001 * alphaReduced * betaReduced;
root = 1.0 - root1 / root2;
}
else if(i == 2)
{
root1 = (4.1002 + alpha) / ((1.0 + alpha) * (1.0 + 0.155998 * alpha));
root2 = 1.0 + 0.06 * (nJacobi - 8.0) * (1.0 + 0.12 * alpha) / nJacobi;
root3 =
1.0 + 0.012002 * beta * (1.0 + 0.24997 * std::fabs(alpha)) / nJacobi;
root -= (1.0 - root) * root1 * root2 * root3;
}
else if(i == 3)
{
root1 = (1.67001 + 0.27998 * alpha) / (1.0 + 0.37002 * alpha);
root2 = 1.0 + 0.22 * (nJacobi - 8.0) / nJacobi;
root3 = 1.0 + 8.0 * beta / ((6.28001 + beta) * nJacobi * nJacobi);
root -= (fAbscissa[0] - root) * root1 * root2 * root3;
}
else if(i == nJacobi - 1)
{
root1 = (1.0 + 0.235002 * beta) / (0.766001 + 0.118998 * beta);
root2 = 1.0 / (1.0 + 0.639002 * (nJacobi - 4.0) /
(1.0 + 0.71001 * (nJacobi - 4.0)));
root3 = 1.0 / (1.0 + 20.0 * alpha / ((7.5 + alpha) * nJacobi * nJacobi));
root += (root - fAbscissa[nJacobi - 4]) * root1 * root2 * root3;
}
else if(i == nJacobi)
{
root1 = (1.0 + 0.37002 * beta) / (1.67001 + 0.27998 * beta);
root2 = 1.0 / (1.0 + 0.22 * (nJacobi - 8.0) / nJacobi);
root3 =
1.0 / (1.0 + 8.0 * alpha / ((6.28002 + alpha) * nJacobi * nJacobi));
root += (root - fAbscissa[nJacobi - 3]) * root1 * root2 * root3;
}
else
{
root = 3.0 * fAbscissa[i - 2] - 3.0 * fAbscissa[i - 3] + fAbscissa[i - 4];
}
alphaBeta = alpha + beta;
for(k = 1; k <= maxNumber; ++k)
{
temp = 2.0 + alphaBeta;
nwt1 = (alpha - beta + temp * root) / 2.0;
nwt2 = 1.0;
for(j = 2; j <= nJacobi; ++j)
{
nwt3 = nwt2;
nwt2 = nwt1;
temp = 2 * j + alphaBeta;
a = 2 * j * (j + alphaBeta) * (temp - 2.0);
b = (temp - 1.0) *
(alpha * alpha - beta * beta + temp * (temp - 2.0) * root);
c = 2.0 * (j - 1 + alpha) * (j - 1 + beta) * temp;
nwt1 = (b * nwt2 - c * nwt3) / a;
}
nwt = (nJacobi * (alpha - beta - temp * root) * nwt1 +
2.0 * (nJacobi + alpha) * (nJacobi + beta) * nwt2) /
(temp * (1.0 - root * root));
rootTemp = root;
root = rootTemp - nwt1 / nwt;
if(std::fabs(root - rootTemp) <= tolerance)
{
break;
}
}
if(k > maxNumber)
{
G4Exception("G4Integrator<T,F>::Jacobi(...)", "Error", FatalException,
"Too many (>12) iterations.");
}
fAbscissa[i - 1] = root;
fWeight[i - 1] =
std::exp(GammaLogarithm((G4double)(alpha + nJacobi)) +
GammaLogarithm((G4double)(beta + nJacobi)) -
GammaLogarithm((G4double)(nJacobi + 1.0)) -
GammaLogarithm((G4double)(nJacobi + alphaBeta + 1.0))) *
temp * std::pow(2.0, alphaBeta) / (nwt * nwt2);
}
//
// Calculation of the integral
//
G4double integral = 0.0;
for(i = 0; i < fNumber; ++i)
{
integral += fWeight[i] * (*f)(fAbscissa[i]);
}
delete[] fAbscissa;
delete[] fWeight;
return integral;
}
//
//
///////////////////////////////////////////////////////////////////