Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright (c) 2025 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_GaussSingleIntegration.hxx>
#include <math_KronrodSingleIntegration.hxx>
#include <math_Function.hxx>
#include <gtest/gtest.h>
#include <Standard_Real.hxx>
#include <Standard_Integer.hxx>
#include <StdFail_NotDone.hxx>
#include <Precision.hxx>
#include <cmath>
namespace
{
// Test function classes for numerical integration
// Constant function: f(x) = c
class ConstantFunction : public math_Function
{
private:
double myValue;
public:
ConstantFunction(double theValue)
: myValue(theValue)
{
}
bool Value(const double /*theX*/, double& theF) override
{
theF = myValue;
return true;
}
};
// Linear function: f(x) = ax + b
class LinearFunction : public math_Function
{
private:
double myA, myB;
public:
LinearFunction(double theA, double theB)
: myA(theA),
myB(theB)
{
}
bool Value(const double theX, double& theF) override
{
theF = myA * theX + myB;
return true;
}
};
// Quadratic function: f(x) = ax^2 + bx + c
class QuadraticFunction : public math_Function
{
private:
double myA, myB, myC;
public:
QuadraticFunction(double theA, double theB, double theC)
: myA(theA),
myB(theB),
myC(theC)
{
}
bool Value(const double theX, double& theF) override
{
theF = myA * theX * theX + myB * theX + myC;
return true;
}
};
// Polynomial function: f(x) = x^n
class PowerFunction : public math_Function
{
private:
int myPower;
public:
PowerFunction(int thePower)
: myPower(thePower)
{
}
bool Value(const double theX, double& theF) override
{
theF = pow(theX, myPower);
return true;
}
};
// Trigonometric function: f(x) = sin(x)
class SineFunction : public math_Function
{
public:
bool Value(const double theX, double& theF) override
{
theF = sin(theX);
return true;
}
};
// Exponential function: f(x) = e^x
class ExponentialFunction : public math_Function
{
public:
bool Value(const double theX, double& theF) override
{
theF = exp(theX);
return true;
}
};
// Tests for math_GaussSingleIntegration
TEST(MathIntegrationTest, GaussConstantFunction)
{
ConstantFunction aFunc(5.0);
double aLower = 0.0;
double anUpper = 2.0;
int anOrder = 4;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Gauss integration should succeed for constant function";
// Integral of constant 5 from 0 to 2 should be 5 * (2-0) = 10
double anExpected = 5.0 * (anUpper - aLower);
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "Constant function integration should be exact";
}
TEST(MathIntegrationTest, GaussLinearFunction)
{
LinearFunction aFunc(2.0, 3.0); // f(x) = 2x + 3
double aLower = 1.0;
double anUpper = 4.0;
int anOrder = 2; // Should be exact for linear functions
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Gauss integration should succeed for linear function";
// Integral of 2x + 3 from 1 to 4: [x^2 + 3x] from 1 to 4 = (16 + 12) - (1 + 3) = 24
double anExpected = 24.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "Linear function integration should be exact with order 2";
}
TEST(MathIntegrationTest, GaussQuadraticFunction)
{
QuadraticFunction aFunc(1.0, -2.0, 1.0); // f(x) = x^2 - 2x + 1 = (x-1)^2
double aLower = 0.0;
double anUpper = 2.0;
int anOrder = 3; // Should be exact for quadratic functions
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Gauss integration should succeed for quadratic function";
// Integral of (x-1)^2 from 0 to 2: [(x-1)^3/3] from 0 to 2 = (1/3) - (-1/3) = 2/3
double anExpected = 2.0 / 3.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "Quadratic function integration should be exact with order 3";
}
TEST(MathIntegrationTest, GaussSineFunction)
{
SineFunction aFunc;
double aLower = 0.0;
double anUpper = M_PI;
int anOrder = 10;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Gauss integration should succeed for sine function";
// Integral of sin(x) from 0 to PI: [-cos(x)] from 0 to PI = -(-1) - (-1) = 2
double anExpected = 2.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-10)
<< "Sine function integration should be accurate";
}
TEST(MathIntegrationTest, GaussExponentialFunction)
{
ExponentialFunction aFunc;
double aLower = 0.0;
double anUpper = 1.0;
int anOrder = 15;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Gauss integration should succeed for exponential function";
// Integral of e^x from 0 to 1: [e^x] from 0 to 1 = e - 1 approximately 1.71828
double anExpected = exp(1.0) - 1.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-8)
<< "Exponential function integration should be accurate";
}
TEST(MathIntegrationTest, GaussDifferentOrders)
{
QuadraticFunction aFunc(1.0, 0.0, 0.0); // f(x) = x^2
double aLower = 0.0;
double anUpper = 1.0;
// Expected result: integral of x^2 from 0 to 1 = [x^3/3] = 1/3
double anExpected = 1.0 / 3.0;
// Test different orders
std::vector<int> anOrders = {2, 3, 5, 10, 20};
for (int anOrder : anOrders)
{
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Integration should succeed for order " << anOrder;
if (anOrder >= 3)
{
// Should be exact for order 3 and above (quadratic function)
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "High order integration should be exact for order " << anOrder;
}
else
{
// Lower order might not be exact but should be reasonable
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-6)
<< "Low order integration should be reasonably accurate for order " << anOrder;
}
}
}
TEST(MathIntegrationTest, GaussWithTolerance)
{
QuadraticFunction aFunc(1.0, 0.0, 0.0); // f(x) = x^2
double aLower = 0.0;
double anUpper = 1.0;
int anOrder = 5;
double aTolerance = 1.0e-10;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder, aTolerance);
EXPECT_TRUE(anIntegrator.IsDone()) << "Integration with tolerance should succeed";
double anExpected = 1.0 / 3.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, aTolerance * 10)
<< "Integration with tolerance should meet accuracy requirements";
}
TEST(MathIntegrationTest, GaussNegativeInterval)
{
LinearFunction aFunc(1.0, 0.0); // f(x) = x
double aLower = -2.0;
double anUpper = 2.0;
int anOrder = 3;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Integration over symmetric interval should succeed";
// Integral of x from -2 to 2: [x^2/2] from -2 to 2 = 2 - 2 = 0
EXPECT_NEAR(anIntegrator.Value(), 0.0, 1.0e-12)
<< "Symmetric odd function integral should be zero";
}
// Tests for math_KronrodSingleIntegration
TEST(MathIntegrationTest, KronrodConstantFunction)
{
ConstantFunction aFunc(3.0);
double aLower = 1.0;
double anUpper = 5.0;
int anOrder = 15; // Kronrod typically uses 15, 21, 31, etc.
math_KronrodSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Kronrod integration should succeed for constant function";
// Integral of constant 3 from 1 to 5 should be 3 * (5-1) = 12
double anExpected = 3.0 * (anUpper - aLower);
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "Constant function integration should be exact";
}
TEST(MathIntegrationTest, KronrodQuadraticFunction)
{
QuadraticFunction aFunc(2.0, -1.0, 3.0); // f(x) = 2x^2 - x + 3
double aLower = 0.0;
double anUpper = 1.0;
int anOrder = 15;
math_KronrodSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Kronrod integration should succeed for quadratic function";
// Integral of 2x^2 - x + 3 from 0 to 1: [2x^3/3 - x^2/2 + 3x] from 0 to 1 = 2/3 - 1/2 + 3 = 2/3 -
// 3/6 + 18/6 = 4/6 + 18/6 - 3/6 = 19/6
double anExpected = 19.0 / 6.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-10)
<< "Quadratic function integration should be very accurate";
}
TEST(MathIntegrationTest, KronrodSineFunction)
{
SineFunction aFunc;
double aLower = 0.0;
double anUpper = M_PI / 2.0;
int anOrder = 21;
math_KronrodSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "Kronrod integration should succeed for sine function";
// Integral of sin(x) from 0 to PI/2: [-cos(x)] from 0 to PI/2 = 0 - (-1) = 1
double anExpected = 1.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "Sine function integration should be very accurate";
}
TEST(MathIntegrationTest, GaussVsKronrodComparison)
{
PowerFunction aFunc(4); // f(x) = x^4
double aLower = 0.0;
double anUpper = 2.0;
// Expected: integral of x^4 from 0 to 2 = [x^5/5] from 0 to 2 = 32/5 = 6.4
double anExpected = 32.0 / 5.0;
// Gauss integration
math_GaussSingleIntegration aGaussIntegrator(aFunc, aLower, anUpper, 10);
EXPECT_TRUE(aGaussIntegrator.IsDone()) << "Gauss integration should succeed";
// Kronrod integration
math_KronrodSingleIntegration aKronrodIntegrator(aFunc, aLower, anUpper, 21);
EXPECT_TRUE(aKronrodIntegrator.IsDone()) << "Kronrod integration should succeed";
// Both should be accurate
EXPECT_NEAR(aGaussIntegrator.Value(), anExpected, 1.0e-10)
<< "Gauss integration should be accurate for x^4";
EXPECT_NEAR(aKronrodIntegrator.Value(), anExpected, 1.0e-10)
<< "Kronrod integration should be accurate for x^4";
// Results should be similar (within tolerance)
EXPECT_NEAR(aGaussIntegrator.Value(), aKronrodIntegrator.Value(), 1.0e-8)
<< "Gauss and Kronrod results should be similar";
}
TEST(MathIntegrationTest, DefaultConstructorAndPerform)
{
// Test default constructor followed by separate computation
math_GaussSingleIntegration anIntegrator1;
LinearFunction aFunc(1.0, 2.0); // f(x) = x + 2
double aLower = 0.0;
double anUpper = 3.0;
int anOrder = 5;
// Note: We can't call Perform directly in the public interface,
// so we test by creating with parameters after default construction
// This tests that the default constructor doesn't crash
math_GaussSingleIntegration anIntegrator2(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator2.IsDone()) << "Integration after explicit construction should succeed";
// Integral of x + 2 from 0 to 3: [x^2/2 + 2x] from 0 to 3 = 9/2 + 6 = 10.5
EXPECT_NEAR(anIntegrator2.Value(), 10.5, 1.0e-12) << "Linear function integral should be exact";
}
// Tests for edge cases and error handling
TEST(MathIntegrationTest, ZeroLengthInterval)
{
ConstantFunction aFunc(1.0);
double aLower = 5.0;
double anUpper = 5.0; // Same as lower
int anOrder = 5;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
// Integration over zero-length interval should give zero
if (anIntegrator.IsDone())
{
EXPECT_NEAR(anIntegrator.Value(), 0.0, Precision::Confusion())
<< "Zero-length interval should give zero integral";
}
}
TEST(MathIntegrationTest, ReverseInterval)
{
LinearFunction aFunc(1.0, 0.0); // f(x) = x
double aLower = 2.0;
double anUpper = 0.0; // Upper < Lower
int anOrder = 5;
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
if (anIntegrator.IsDone())
{
// Integral from 2 to 0 should be negative of integral from 0 to 2
// Integral of x from 0 to 2 = [x^2/2] = 2, so from 2 to 0 = -2
EXPECT_NEAR(anIntegrator.Value(), -2.0, 1.0e-12)
<< "Reverse interval should give negative result";
}
}
TEST(MathIntegrationTest, HighOrderIntegration)
{
PowerFunction aFunc(10); // f(x) = x^10
double aLower = 0.0;
double anUpper = 1.0;
int anOrder = 30; // High order
math_GaussSingleIntegration anIntegrator(aFunc, aLower, anUpper, anOrder);
EXPECT_TRUE(anIntegrator.IsDone()) << "High order integration should succeed";
// Integral of x^10 from 0 to 1 = [x^11/11] = 1/11
double anExpected = 1.0 / 11.0;
EXPECT_NEAR(anIntegrator.Value(), anExpected, 1.0e-12)
<< "High order integration of polynomial should be exact";
}
} // anonymous namespace