Files
OCCT/src/math/math_KronrodSingleIntegration.cxx
abv d5f74e42d6 0024624: Lost word in license statement in source files
License statement text corrected; compiler warnings caused by Bison 2.41 disabled for MSVC; a few other compiler warnings on 54-bit Windows eliminated by appropriate type cast
Wrong license statements corrected in several files.
Copyright and license statements added in XSD and GLSL files.
Copyright year updated in some files.
Obsolete documentation files removed from DrawResources.
2014-02-20 16:15:17 +04:00

364 lines
10 KiB
C++

// Created on: 2005-12-08
// Created by: Sergey KHROMOV
// Copyright (c) 2005-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <math_KronrodSingleIntegration.ixx>
#include <math_Vector.hxx>
#include <math.hxx>
#include <TColStd_SequenceOfReal.hxx>
//==========================================================================
//function : An empty constructor.
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration() :
myIsDone(Standard_False),
myValue(0.),
myErrorReached(0.),
myNbPntsReached(0),
myNbIterReached(0)
{
}
//==========================================================================
//function : Constructor
//
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration
( math_Function &theFunction,
const Standard_Real theLower,
const Standard_Real theUpper,
const Standard_Integer theNbPnts):
myIsDone(Standard_False),
myValue(0.),
myErrorReached(0.),
myNbPntsReached(0)
{
Perform(theFunction, theLower, theUpper, theNbPnts);
}
//==========================================================================
//function : Constructor
//
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration
( math_Function &theFunction,
const Standard_Real theLower,
const Standard_Real theUpper,
const Standard_Integer theNbPnts,
const Standard_Real theTolerance,
const Standard_Integer theMaxNbIter) :
myIsDone(Standard_False),
myValue(0.),
myErrorReached(0.),
myNbPntsReached(0)
{
Perform(theFunction, theLower, theUpper, theNbPnts,
theTolerance, theMaxNbIter);
}
//==========================================================================
//function : Perform
// Computation of the integral.
//==========================================================================
void math_KronrodSingleIntegration::Perform
( math_Function &theFunction,
const Standard_Real theLower,
const Standard_Real theUpper,
const Standard_Integer theNbPnts)
{
//const Standard_Real aMinVol = Epsilon(1.);
const Standard_Real aPtol = 1.e-9;
myNbIterReached = 0;
if (theNbPnts < 3 ) {
myIsDone = Standard_False;
return;
}
if(theUpper - theLower < aPtol) {
myIsDone = Standard_False;
return;
}
// Get an odd value of number of initial points.
myNbPntsReached = (theNbPnts%2 == 0) ? theNbPnts + 1 : theNbPnts;
myErrorReached = RealLast();
Standard_Integer aNGauss = myNbPntsReached/2;
math_Vector aKronrodP(1, myNbPntsReached);
math_Vector aKronrodW(1, myNbPntsReached);
math_Vector aGaussP(1, aNGauss);
math_Vector aGaussW(1, aNGauss);
if (!math::KronrodPointsAndWeights(myNbPntsReached, aKronrodP, aKronrodW) ||
!math::OrderedGaussPointsAndWeights(aNGauss, aGaussP, aGaussW)) {
myIsDone = Standard_False;
return;
}
myIsDone = GKRule(theFunction, theLower, theUpper, aGaussP, aGaussW, aKronrodP, aKronrodW,
myValue, myErrorReached);
if(!myIsDone) return;
//Standard_Real anAbsVal = Abs(myValue);
myAbsolutError = myErrorReached;
//if (anAbsVal > aMinVol)
//myErrorReached /= anAbsVal;
myNbIterReached++;
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void math_KronrodSingleIntegration::Perform
( math_Function &theFunction,
const Standard_Real theLower,
const Standard_Real theUpper,
const Standard_Integer theNbPnts,
const Standard_Real theTolerance,
const Standard_Integer theMaxNbIter)
{
Standard_Real aMinVol = Epsilon(1.);
myNbIterReached = 0;
// Check prerequisites.
if (theNbPnts < 3 ||
theTolerance <= 0.) {
myIsDone = Standard_False;
return;
}
// Get an odd value of number of initial points.
myNbPntsReached = (theNbPnts%2 == 0) ? theNbPnts + 1 : theNbPnts;
Standard_Integer aNGauss = myNbPntsReached/2;
math_Vector aKronrodP(1, myNbPntsReached);
math_Vector aKronrodW(1, myNbPntsReached);
math_Vector aGaussP(1, aNGauss);
math_Vector aGaussW(1, aNGauss);
if (!math::KronrodPointsAndWeights(myNbPntsReached, aKronrodP, aKronrodW) ||
!math::OrderedGaussPointsAndWeights(aNGauss, aGaussP, aGaussW)) {
myIsDone = Standard_False;
return;
}
//First iteration
myIsDone = GKRule(theFunction, theLower, theUpper, aGaussP, aGaussW, aKronrodP, aKronrodW,
myValue, myErrorReached);
if(!myIsDone) return;
Standard_Real anAbsVal = Abs(myValue);
myAbsolutError = myErrorReached;
if (anAbsVal > aMinVol)
myErrorReached /= anAbsVal;
myNbIterReached++;
if(myErrorReached <= theTolerance) return;
if(myNbIterReached >= theMaxNbIter) return;
TColStd_SequenceOfReal anIntervals;
TColStd_SequenceOfReal anErrors;
TColStd_SequenceOfReal aValues;
anIntervals.Append(theLower);
anIntervals.Append(theUpper);
anErrors.Append(myAbsolutError);
aValues.Append(myValue);
Standard_Integer i, nint, nbints;
Standard_Real maxerr;
Standard_Integer count = 0;
while(myErrorReached > theTolerance && myNbIterReached < theMaxNbIter) {
//Searching interval with max error
nbints = anIntervals.Length() - 1;
nint = 0;
maxerr = 0.;
for(i = 1; i <= nbints; ++i) {
if(anErrors(i) > maxerr) {
maxerr = anErrors(i);
nint = i;
}
}
Standard_Real a = anIntervals(nint);
Standard_Real b = anIntervals(nint+1);
Standard_Real c = 0.5*(a + b);
Standard_Real v1, v2, e1, e2;
myIsDone = GKRule(theFunction, a, c, aGaussP, aGaussW, aKronrodP, aKronrodW,
v1, e1);
if(!myIsDone) return;
myIsDone = GKRule(theFunction, c, b, aGaussP, aGaussW, aKronrodP, aKronrodW,
v2, e2);
if(!myIsDone) return;
myNbIterReached++;
Standard_Real deltav = v1 + v2 - aValues(nint);
myValue += deltav;
if(Abs(deltav) <= Epsilon(Abs(myValue))) ++count;
Standard_Real deltae = e1 + e2 - anErrors(nint);
myAbsolutError += deltae;
if(myAbsolutError <= Epsilon(Abs(myValue))) ++count;
if(Abs(myValue) > aMinVol) myErrorReached = myAbsolutError/Abs(myValue);
else myErrorReached = myAbsolutError;
if(count > 50) return;
//Inserting new interval
anIntervals.InsertAfter(nint, c);
anErrors(nint) = e1;
anErrors.InsertAfter(nint, e2);
aValues(nint) = v1;
aValues.InsertAfter(nint, v2);
}
}
//=======================================================================
//function : GKRule
//purpose :
//=======================================================================
Standard_Boolean math_KronrodSingleIntegration::GKRule(
math_Function &theFunction,
const Standard_Real theLower,
const Standard_Real theUpper,
const math_Vector& /*theGaussP*/,
const math_Vector& theGaussW,
const math_Vector& theKronrodP,
const math_Vector& theKronrodW,
Standard_Real& theValue,
Standard_Real& theError)
{
Standard_Boolean IsDone;
Standard_Integer aNKronrod = theKronrodP.Length();
Standard_Real aGaussVal;
Standard_Integer aNPnt2 = (aNKronrod + 1)/2;
Standard_Integer i;
Standard_Real aDx;
Standard_Real aVal1;
Standard_Real aVal2;
math_Vector f1(1, aNPnt2-1);
math_Vector f2(1, aNPnt2-1);
Standard_Real aXm = 0.5*(theUpper + theLower);
Standard_Real aXr = 0.5*(theUpper - theLower);
// Compute Gauss quadrature
aGaussVal = 0.;
theValue = 0.;
for (i = 2; i < aNPnt2; i += 2) {
aDx = aXr*theKronrodP.Value(i);
if (!theFunction.Value(aXm + aDx, aVal1) ||
!theFunction.Value(aXm - aDx, aVal2)) {
IsDone = Standard_False;
return IsDone;
}
f1(i) = aVal1;
f2(i) = aVal2;
aGaussVal += (aVal1 + aVal2)*theGaussW.Value(i/2);
theValue += (aVal1 + aVal2)*theKronrodW.Value(i);
}
// Compute value in the middle point.
if (!theFunction.Value(aXm, aVal1)) {
IsDone = Standard_False;
return IsDone;
}
Standard_Real fc = aVal1;
theValue += aVal1*theKronrodW.Value(aNPnt2);
if (i == aNPnt2)
aGaussVal += aVal1*theGaussW.Value(aNPnt2/2);
// Compute Kronrod quadrature
for (i = 1; i < aNPnt2; i += 2) {
aDx = aXr*theKronrodP.Value(i);
if (!theFunction.Value(aXm + aDx, aVal1) ||
!theFunction.Value(aXm - aDx, aVal2)) {
IsDone = Standard_False;
return IsDone;
}
f1(i) = aVal1;
f2(i) = aVal2;
theValue += (aVal1 + aVal2)*theKronrodW.Value(i);
}
Standard_Real mean = 0.5*theValue;
Standard_Real asc = Abs(fc-mean)*theKronrodW.Value(aNPnt2);
for(i = 1; i < aNPnt2; ++i) {
asc += theKronrodW.Value(i)*(Abs(f1(i) - mean) + Abs(f2(i) - mean));
}
asc *= aXr;
theValue *= aXr;
aGaussVal *= aXr;
// Compute the error and the new number of Kronrod points.
theError = Abs(theValue - aGaussVal);
Standard_Real scale =1.;
if(asc != 0. && theError != 0.) scale = Pow((200.*theError/asc), 1.5);
if(scale < 1.) theError = Min(theError, asc*scale);
//theFunction.GetStateNumber();
return Standard_True;
}