Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// 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.hxx>
#include <math_Function.hxx>
#include <math_KronrodSingleIntegration.hxx>
#include <math_Vector.hxx>
#include <NCollection_Sequence.hxx>
//==========================================================================
// function : An empty constructor.
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration()
: myIsDone(false),
myValue(0.),
myErrorReached(0.),
myAbsolutError(0.),
myNbPntsReached(0),
myNbIterReached(0)
{
}
//==========================================================================
// function : Constructor
//
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration(math_Function& theFunction,
const double theLower,
const double theUpper,
const int theNbPnts)
: myIsDone(false),
myValue(0.),
myErrorReached(0.),
myAbsolutError(0.),
myNbPntsReached(0),
myNbIterReached(0)
{
Perform(theFunction, theLower, theUpper, theNbPnts);
}
//==========================================================================
// function : Constructor
//
//==========================================================================
math_KronrodSingleIntegration::math_KronrodSingleIntegration(math_Function& theFunction,
const double theLower,
const double theUpper,
const int theNbPnts,
const double theTolerance,
const int theMaxNbIter)
: myIsDone(false),
myValue(0.),
myErrorReached(0.),
myAbsolutError(0.),
myNbPntsReached(0),
myNbIterReached(0)
{
Perform(theFunction, theLower, theUpper, theNbPnts, theTolerance, theMaxNbIter);
}
//==========================================================================
// function : Perform
// Computation of the integral.
//==========================================================================
void math_KronrodSingleIntegration::Perform(math_Function& theFunction,
const double theLower,
const double theUpper,
const int theNbPnts)
{
// const double aMinVol = Epsilon(1.);
const double aPtol = 1.e-9;
myNbIterReached = 0;
if (theNbPnts < 3)
{
myIsDone = false;
return;
}
if (theUpper - theLower < aPtol)
{
myIsDone = false;
return;
}
// Get an odd value of number of initial points.
myNbPntsReached = (theNbPnts % 2 == 0) ? theNbPnts + 1 : theNbPnts;
myErrorReached = RealLast();
int 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 = false;
return;
}
myIsDone = GKRule(theFunction,
theLower,
theUpper,
aGaussP,
aGaussW,
aKronrodP,
aKronrodW,
myValue,
myErrorReached);
if (!myIsDone)
{
return;
}
// double anAbsVal = std::abs(myValue);
myAbsolutError = myErrorReached;
// if (anAbsVal > aMinVol)
// myErrorReached /= anAbsVal;
myNbIterReached++;
}
//=================================================================================================
void math_KronrodSingleIntegration::Perform(math_Function& theFunction,
const double theLower,
const double theUpper,
const int theNbPnts,
const double theTolerance,
const int theMaxNbIter)
{
double aMinVol = Epsilon(1.);
myNbIterReached = 0;
// Check prerequisites.
if (theNbPnts < 3 || theTolerance <= 0.)
{
myIsDone = false;
return;
}
// Get an odd value of number of initial points.
myNbPntsReached = (theNbPnts % 2 == 0) ? theNbPnts + 1 : theNbPnts;
int 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 = false;
return;
}
// First iteration
myIsDone = GKRule(theFunction,
theLower,
theUpper,
aGaussP,
aGaussW,
aKronrodP,
aKronrodW,
myValue,
myErrorReached);
if (!myIsDone)
{
return;
}
double anAbsVal = std::abs(myValue);
myAbsolutError = myErrorReached;
if (anAbsVal > aMinVol)
{
myErrorReached /= anAbsVal;
}
myNbIterReached++;
if (myErrorReached <= theTolerance)
{
return;
}
if (myNbIterReached >= theMaxNbIter)
{
return;
}
NCollection_Sequence<double> anIntervals;
NCollection_Sequence<double> anErrors;
NCollection_Sequence<double> aValues;
anIntervals.Append(theLower);
anIntervals.Append(theUpper);
anErrors.Append(myAbsolutError);
aValues.Append(myValue);
int i, nint, nbints;
double maxerr;
int 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;
}
}
double a = anIntervals(nint);
double b = anIntervals(nint + 1);
double c = 0.5 * (a + b);
double 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++;
double deltav = v1 + v2 - aValues(nint);
myValue += deltav;
if (std::abs(deltav) <= Epsilon(std::abs(myValue)))
{
++count;
}
double deltae = e1 + e2 - anErrors(nint);
myAbsolutError += deltae;
if (myAbsolutError <= Epsilon(std::abs(myValue)))
{
++count;
}
if (std::abs(myValue) > aMinVol)
{
myErrorReached = myAbsolutError / std::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);
}
}
//=================================================================================================
bool math_KronrodSingleIntegration::GKRule(math_Function& theFunction,
const double theLower,
const double theUpper,
const math_Vector& /*theGaussP*/,
const math_Vector& theGaussW,
const math_Vector& theKronrodP,
const math_Vector& theKronrodW,
double& theValue,
double& theError)
{
bool IsDone;
int aNKronrod = theKronrodP.Length();
double aGaussVal;
int aNPnt2 = (aNKronrod + 1) / 2;
int i;
double aDx;
double aVal1;
double aVal2;
math_Vector f1(1, aNPnt2 - 1);
math_Vector f2(1, aNPnt2 - 1);
double aXm = 0.5 * (theUpper + theLower);
double 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 = 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 = false;
return IsDone;
}
double 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 = false;
return IsDone;
}
f1(i) = aVal1;
f2(i) = aVal2;
theValue += (aVal1 + aVal2) * theKronrodW.Value(i);
}
double mean = 0.5 * theValue;
double asc = std::abs(fc - mean) * theKronrodW.Value(aNPnt2);
for (i = 1; i < aNPnt2; ++i)
{
asc += theKronrodW.Value(i) * (std::abs(f1(i) - mean) + std::abs(f2(i) - mean));
}
asc *= aXr;
theValue *= aXr;
aGaussVal *= aXr;
// Compute the error and the new number of Kronrod points.
theError = std::abs(theValue - aGaussVal);
double scale = 1.;
if (asc != 0. && theError != 0.)
{
scale = std::pow((200. * theError / asc), 1.5);
}
if (scale < 1.)
{
theError = std::min(theError, asc * scale);
}
// theFunction.GetStateNumber();
return true;
}