Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 09:20:49

0001 // Copyright (c) 2025 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _MathInteg_Gauss_HeaderFile
0015 #define _MathInteg_Gauss_HeaderFile
0016 
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020 #include <MathUtils_Gauss.hxx>
0021 
0022 #include <algorithm>
0023 #include <cmath>
0024 
0025 //! Numerical integration algorithms.
0026 namespace MathInteg
0027 {
0028 using namespace MathUtils;
0029 
0030 //! Gauss-Legendre quadrature for definite integrals.
0031 //! Computes integral of f(x) from theLower to theUpper using n-point Gauss-Legendre rule.
0032 //!
0033 //! Algorithm:
0034 //! 1. Transform interval [theLower, theUpper] to [-1, 1]
0035 //! 2. Evaluate f at Gauss-Legendre points
0036 //! 3. Sum weighted function values
0037 //!
0038 //! Exact for polynomials of degree up to 2n-1.
0039 //!
0040 //! @tparam Function type with Value(double theX, double& theF) method
0041 //! @param theFunc function to integrate
0042 //! @param theLower lower integration bound
0043 //! @param theUpper upper integration bound
0044 //! @param theNbPoints number of quadrature points (>= 1)
0045 //! @return result containing integral value
0046 template <typename Function>
0047 IntegResult Gauss(Function& theFunc, double theLower, double theUpper, int theNbPoints = 15)
0048 {
0049   IntegResult aResult;
0050   if (theNbPoints < 1)
0051   {
0052     aResult.Status = Status::InvalidInput;
0053     return aResult;
0054   }
0055 
0056   // Get quadrature points and weights
0057   math_Vector aPoints(1, theNbPoints);
0058   math_Vector aWeights(1, theNbPoints);
0059 
0060   if (!MathUtils::GetGaussPointsAndWeights(theNbPoints, aPoints, aWeights))
0061   {
0062     aResult.Status = Status::InvalidInput;
0063     return aResult;
0064   }
0065 
0066   // Transform from [-1, 1] to [theLower, theUpper]
0067   const double aHalfLen = 0.5 * (theUpper - theLower);
0068   const double aMid     = 0.5 * (theUpper + theLower);
0069 
0070   double aSum = 0.0;
0071   for (int i = 1; i <= theNbPoints; ++i)
0072   {
0073     const double aX = aMid + aHalfLen * aPoints(i);
0074     double       aF = 0.0;
0075     if (!theFunc.Value(aX, aF))
0076     {
0077       aResult.Status = Status::NumericalError;
0078       return aResult;
0079     }
0080     aSum += aWeights(i) * aF;
0081   }
0082 
0083   aResult.Status       = Status::OK;
0084   aResult.Value        = aHalfLen * aSum;
0085   aResult.NbPoints     = theNbPoints;
0086   aResult.NbIterations = 1;
0087   return aResult;
0088 }
0089 
0090 //! Adaptive Gauss-Legendre integration.
0091 //! Recursively subdivides interval until error estimate is below tolerance.
0092 //!
0093 //! Algorithm:
0094 //! 1. Compute integral using n and 2n points
0095 //! 2. Estimate error as difference between the two
0096 //! 3. If error > tolerance, subdivide and recurse
0097 //!
0098 //! @tparam Function type with Value(double theX, double& theF) method
0099 //! @param theFunc function to integrate
0100 //! @param theLower lower integration bound
0101 //! @param theUpper upper integration bound
0102 //! @param theConfig integration configuration
0103 //! @return result containing integral value and error estimate
0104 template <typename Function>
0105 IntegResult GaussAdaptive(Function&          theFunc,
0106                           double             theLower,
0107                           double             theUpper,
0108                           const IntegConfig& theConfig = IntegConfig())
0109 {
0110   IntegResult aResult;
0111 
0112   if (theConfig.InitialOrder < 1 || theConfig.MaxOrder < theConfig.InitialOrder
0113       || theConfig.MaxOrder > 61 || theConfig.MaxIterations < 1)
0114   {
0115     aResult.Status = Status::InvalidInput;
0116     return aResult;
0117   }
0118 
0119   int aCoarseOrder = theConfig.InitialOrder;
0120   int aFineOrder   = std::min(theConfig.MaxOrder, std::min(61, 2 * aCoarseOrder));
0121   if (aFineOrder == aCoarseOrder)
0122   {
0123     if (aCoarseOrder > 1)
0124     {
0125       aCoarseOrder -= 1;
0126     }
0127     else if (theConfig.MaxOrder > 1)
0128     {
0129       aFineOrder = 2;
0130     }
0131   }
0132 
0133   // Compute with coarse and fine grids
0134   IntegResult aCoarse = Gauss(theFunc, theLower, theUpper, aCoarseOrder);
0135   if (!aCoarse.IsDone())
0136   {
0137     return aCoarse;
0138   }
0139 
0140   IntegResult aFine = Gauss(theFunc, theLower, theUpper, aFineOrder);
0141   if (!aFine.IsDone())
0142   {
0143     return aFine;
0144   }
0145 
0146   const double aError = std::abs(*aFine.Value - *aCoarse.Value);
0147   const double aScale = std::max(std::abs(*aFine.Value), 1.0e-15);
0148 
0149   // Check if converged
0150   if (aError < theConfig.Tolerance * aScale)
0151   {
0152     aResult.Status        = Status::OK;
0153     aResult.Value         = *aFine.Value;
0154     aResult.AbsoluteError = aError;
0155     aResult.RelativeError = aError / aScale;
0156     aResult.NbPoints      = static_cast<size_t>(aFineOrder);
0157     aResult.NbIterations  = 1;
0158     return aResult;
0159   }
0160 
0161   // Need to subdivide - check iteration limit
0162   if (theConfig.MaxIterations <= 1)
0163   {
0164     aResult.Status        = Status::MaxIterations;
0165     aResult.Value         = *aFine.Value;
0166     aResult.AbsoluteError = aError;
0167     aResult.RelativeError = aError / aScale;
0168     aResult.NbPoints      = static_cast<size_t>(aFineOrder);
0169     aResult.NbIterations  = 1;
0170     return aResult;
0171   }
0172 
0173   // Subdivide interval
0174   const double aMid = 0.5 * (theLower + theUpper);
0175 
0176   IntegConfig aSubConfig   = theConfig;
0177   aSubConfig.MaxIterations = theConfig.MaxIterations - 1;
0178 
0179   IntegResult aLeft = GaussAdaptive(theFunc, theLower, aMid, aSubConfig);
0180   if (!aLeft.IsDone())
0181   {
0182     aResult.Status = aLeft.Status;
0183     aResult.Value  = aLeft.Value;
0184     return aResult;
0185   }
0186 
0187   IntegResult aRight = GaussAdaptive(theFunc, aMid, theUpper, aSubConfig);
0188   if (!aRight.IsDone())
0189   {
0190     aResult.Status = aRight.Status;
0191     aResult.Value  = *aLeft.Value + (aRight.Value ? *aRight.Value : 0.0);
0192     return aResult;
0193   }
0194 
0195   aResult.Status        = Status::OK;
0196   aResult.Value         = *aLeft.Value + *aRight.Value;
0197   aResult.AbsoluteError = *aLeft.AbsoluteError + *aRight.AbsoluteError;
0198   aResult.RelativeError = *aResult.AbsoluteError / std::max(std::abs(*aResult.Value), 1.0e-15);
0199   aResult.NbPoints      = aLeft.NbPoints + aRight.NbPoints;
0200   aResult.NbIterations  = std::max(aLeft.NbIterations, aRight.NbIterations) + 1;
0201   return aResult;
0202 }
0203 
0204 //! Composite Gauss-Legendre integration.
0205 //! Divides interval into subintervals and applies Gauss-Legendre to each.
0206 //! Simple alternative to adaptive integration.
0207 //!
0208 //! @tparam Function type with Value(double theX, double& theF) method
0209 //! @param theFunc function to integrate
0210 //! @param theLower lower integration bound
0211 //! @param theUpper upper integration bound
0212 //! @param theNbIntervals number of subintervals
0213 //! @param theNbPoints Gauss points per interval (>= 1)
0214 //! @return result containing integral value
0215 template <typename Function>
0216 IntegResult GaussComposite(Function& theFunc,
0217                            double    theLower,
0218                            double    theUpper,
0219                            int       theNbIntervals,
0220                            int       theNbPoints = 7)
0221 {
0222   IntegResult aResult;
0223 
0224   if (theNbIntervals < 1)
0225   {
0226     aResult.Status = Status::InvalidInput;
0227     return aResult;
0228   }
0229 
0230   const double aH           = (theUpper - theLower) / theNbIntervals;
0231   double       aSum         = 0.0;
0232   size_t       aTotalPoints = 0;
0233 
0234   for (int i = 0; i < theNbIntervals; ++i)
0235   {
0236     const double aA = theLower + i * aH;
0237     const double aB = aA + aH;
0238 
0239     IntegResult aSubResult = Gauss(theFunc, aA, aB, theNbPoints);
0240     if (!aSubResult.IsDone())
0241     {
0242       aResult.Status   = aSubResult.Status;
0243       aResult.Value    = aSum;
0244       aResult.NbPoints = aTotalPoints;
0245       return aResult;
0246     }
0247 
0248     aSum += *aSubResult.Value;
0249     aTotalPoints += aSubResult.NbPoints;
0250   }
0251 
0252   aResult.Status       = Status::OK;
0253   aResult.Value        = aSum;
0254   aResult.NbPoints     = aTotalPoints;
0255   aResult.NbIterations = 1;
0256   return aResult;
0257 }
0258 
0259 } // namespace MathInteg
0260 
0261 #endif // _MathInteg_Gauss_HeaderFile