Gaudi Framework, version v23r4

Home   Generated: Mon Sep 17 2012

NumericalDefiniteIntegral.cpp

Go to the documentation of this file.
00001 // $Id: NumericalDefiniteIntegral.cpp,v 1.4 2007/11/20 13:00:17 marcocle Exp $
00002 // ============================================================================
00003 // Include
00004 // ============================================================================
00005 // STD & STL
00006 // ============================================================================
00007 #include <vector>
00008 #include <algorithm>
00009 // ============================================================================
00010 // GSL
00011 // ============================================================================
00012 #include "gsl/gsl_errno.h"
00013 #include "gsl/gsl_integration.h"
00014 // ============================================================================
00015 // GaudiKernel
00016 // ============================================================================
00017 #include "GaudiKernel/GaudiException.h"
00018 // ============================================================================
00019 // GaudiMath
00020 // ============================================================================
00021 #include "GaudiMath/NumericalDefiniteIntegral.h"
00022 #include "GaudiMath/NumericalDerivative.h"
00023 // ============================================================================
00024 // Local
00025 // ============================================================================
00026 #include "Helpers.h"
00027 // ============================================================================
00028 
00029 
00030 #ifdef __ICC
00031 // disable icc remark #1572: floating-point equality and inequality comparisons are unreliable
00032 //   The comparison are meant
00033 #pragma warning(disable:1572)
00034 #endif
00035 #ifdef WIN32
00036 // Disable the warning
00037 //    C4996: 'std::copy': Function call with parameters that may be unsafe
00038 // The parameters are checked
00039 #pragma warning(disable:4996)
00040 #endif
00041 
00042 namespace Genfun
00043 {
00044   namespace GaudiMathImplementation
00045   {
00046 
00047     struct NumericalDefiniteIntegral::_Workspace
00048     { gsl_integration_workspace* ws ; };
00049     struct NumericalDefiniteIntegral::_Function
00050     { gsl_function*              fn ; };
00051 
00052     // ========================================================================
00054     // ========================================================================
00055     FUNCTION_OBJECT_IMP( NumericalDefiniteIntegral )
00056     // ========================================================================
00057 
00058     
00109     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00110     ( const AbsFunction&                        function ,
00111       const size_t                              index    ,
00112       const double                              a        ,
00113       const double                              b        ,
00114       const GaudiMath::Integration::Type        type     ,
00115       const GaudiMath::Integration::KronrodRule rule     ,
00116       const double                              epsabs   ,
00117       const double                              epsrel   ,
00118       const size_t                              size     )
00119       : AbsFunction ()
00120       , m_function  ( function.clone          ()    )
00121       , m_DIM       ( 0                             )
00122       , m_index     ( index                         )
00123       , m_a         ( a      )
00124       , m_b         ( b      )
00125       , m_ia        ( false  )
00126       , m_ib        ( false  )
00127       , m_type      ( type   )
00128       , m_category  ( GaudiMath::Integration::Finite )
00129       , m_rule      ( rule       )
00130       , m_points    (            )
00131       , m_pdata     ( 0          )
00132       , m_epsabs    ( epsabs     )
00133       , m_epsrel    ( epsrel     )
00134       , m_result    ( GSL_NEGINF )
00135       , m_error     ( GSL_POSINF )
00136       , m_size      ( size       )
00137       , m_ws        ()
00138       , m_argument  ()
00139       , m_argF      ()
00140     {
00141       if ( GaudiMath::Integration::Fixed == m_rule )
00142         { m_rule = GaudiMath::Integration::Default ; }
00143       if ( function.dimensionality() < 2          )
00144         { Exception("::constructor: invalid dimensionality ") ; }
00145       if ( m_index >= function.dimensionality()   )
00146         { Exception("::constructor: invalid variable index") ; }
00147 
00148       m_DIM = function.dimensionality() - 1 ;
00149       m_argument = Argument( m_DIM      ) ;
00150       m_argF     = Argument( m_DIM + 1  ) ;
00151 
00152     }
00153 
00154 
00164     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00165     ( const AbsFunction&                       function ,
00166       const size_t                             index    ,
00167       const double                             a        ,
00168       const double                             b        ,
00169       const NumericalDefiniteIntegral::Points& points   ,
00170       const double                             epsabs   ,
00171       const double                             epsrel   ,
00172       const size_t                             size     )
00173       : AbsFunction ()
00174       , m_function  ( function.clone()             )
00175       , m_DIM       ( 0                            )
00176       , m_index     ( index                        )
00177       , m_a         ( a                            )
00178       , m_b         ( b                            )
00179       , m_ia        ( false  )
00180       , m_ib        ( false  )
00181       , m_type      ( GaudiMath::Integration::    Other )
00182       , m_category  ( GaudiMath::Integration:: Singular )
00183       , m_rule      ( GaudiMath::Integration::    Fixed )
00184       , m_points    ( points  )
00185       , m_pdata     ( 0       )
00186       , m_epsabs    ( epsabs  )
00187       , m_epsrel    ( epsrel  )
00188       //
00189       , m_result    ( GSL_NEGINF                          )
00190       , m_error     ( GSL_POSINF                          )
00191       //
00192       , m_size      ( size                                )
00193       , m_ws        ( 0                                   )
00194       , m_argument  ()
00195       , m_argF      ()
00196     {
00197       if ( function.dimensionality() < 2          )
00198         { Exception("::constructor: invalid dimensionality ") ; }
00199       if ( m_index >= function.dimensionality()   )
00200         { Exception("::constructor: invalid variable index") ; }
00201 
00202       m_DIM = function.dimensionality() - 1 ;
00203       m_argument = Argument( m_DIM      ) ;
00204       m_argF     = Argument( m_DIM + 1  ) ;
00205 
00206       const double l1 = std::min ( a , b ) ;
00207       const double l2 = std::max ( a , b ) ;
00208       m_points.push_back ( l1 ) ;
00209       m_points.push_back ( l2 ) ;
00210       std::sort ( m_points.begin() , m_points.end() ) ;
00211       m_points.erase( std::unique( m_points.begin () ,
00212                                    m_points.end   () ) ,
00213                       m_points.end() );
00214 
00215       Points::iterator lower =
00216         std::lower_bound ( m_points.begin () , m_points.end () , l1 ) ;
00217       m_points.erase     ( m_points.begin () , lower                ) ;
00218       Points::iterator upper =
00219         std::upper_bound ( m_points.begin () , m_points.end () , l2 ) ;
00220       m_points.erase     ( upper             , m_points.end ()      ) ;
00221 
00222       m_pdata = new double[ m_points.size() ] ;
00223       std::copy( m_points.begin() , m_points.end() , m_pdata );
00224     }
00225 
00251     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00252     ( const AbsFunction&                      function  ,
00253       const size_t                            index     ,
00254       const double                            a         ,
00255       const GaudiMath::Integration::Inf       /* b  */  ,
00256       const double                            epsabs    ,
00257       const double                            epsrel    ,
00258       const size_t                            size      )
00259       : AbsFunction()
00260       , m_function  ( function.clone()             )
00261       , m_DIM       ( 0                            )
00262       , m_index     ( index                        )
00263       , m_a         ( a                            )
00264       , m_b         ( GSL_POSINF                   )
00265       , m_ia        ( false  )
00266       , m_ib        ( true   )
00267       , m_type      ( GaudiMath::Integration::    Other )
00268       , m_category  ( GaudiMath::Integration:: Infinite )
00269       , m_rule      ( GaudiMath::Integration::    Fixed )
00270       , m_points    (         )
00271       , m_pdata     ( 0       )
00272       , m_epsabs    ( epsabs  )
00273       , m_epsrel    ( epsrel  )
00274       //
00275       , m_result    ( GSL_NEGINF                          )
00276       , m_error     ( GSL_POSINF                          )
00277       //
00278       , m_size      ( size                                )
00279       , m_ws        ( 0                                   )
00280       , m_argument  ()
00281       , m_argF      ()
00282     {
00283       if ( function.dimensionality() < 2          )
00284         { Exception("::constructor: invalid dimensionality ") ; }
00285       if ( m_index >= function.dimensionality()   )
00286         { Exception("::constructor: invalid variable index") ; }
00287 
00288       m_DIM = function.dimensionality() - 1 ;
00289       m_argument = Argument( m_DIM      ) ;
00290       m_argF     = Argument( m_DIM + 1  ) ;
00291 
00292     }
00293 
00294 
00320     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00321     ( const AbsFunction&                      function  ,
00322       const size_t                            index     ,
00323       const GaudiMath::Integration::Inf       /* a  */  ,
00324       const double                            b         ,
00325       const double                            epsabs    ,
00326       const double                            epsrel    ,
00327       const size_t                            size      )
00328       : AbsFunction()
00329       , m_function  ( function.clone()             )
00330       , m_DIM       ( 0                            )
00331       , m_index     ( index                        )
00332       , m_a         ( GSL_NEGINF                   )
00333       , m_b         ( b                            )
00334       , m_ia        ( true   )
00335       , m_ib        ( false  )
00336       , m_type      ( GaudiMath::Integration::    Other )
00337       , m_category  ( GaudiMath::Integration:: Infinite )
00338       , m_rule      ( GaudiMath::Integration::    Fixed )
00339       , m_points    (         )
00340       , m_pdata     ( 0       )
00341       , m_epsabs    ( epsabs  )
00342       , m_epsrel    ( epsrel  )
00343       //
00344       , m_result    ( GSL_NEGINF                          )
00345       , m_error     ( GSL_POSINF                          )
00346       //
00347       , m_size      ( size                                )
00348       , m_ws        ( 0                                   )
00349       , m_argument  ()
00350       , m_argF      ()
00351     {
00352       if ( function.dimensionality() < 2          )
00353         { Exception("::constructor: invalid dimensionality ") ; }
00354       if ( m_index >= function.dimensionality()   )
00355         { Exception("::constructor: invalid variable index") ; }
00356 
00357       m_DIM = function.dimensionality() - 1 ;
00358       m_argument = Argument( m_DIM      ) ;
00359       m_argF     = Argument( m_DIM + 1  ) ;
00360     }
00361 
00385     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00386     ( const AbsFunction&                      function  ,
00387       const size_t                            index     ,
00388       const float                             epsabs    ,
00389       const float                             epsrel    ,
00390       const size_t                            size      )
00391       : AbsFunction()
00392       , m_function  ( function.clone()             )
00393       , m_DIM       ( 0      )
00394       , m_index     ( index                        )
00395       , m_a         ( GSL_NEGINF                   )
00396       , m_b         ( GSL_POSINF                   )
00397       , m_ia        ( true   )
00398       , m_ib        ( true   )
00399       , m_type      ( GaudiMath::Integration::    Other )
00400       , m_category  ( GaudiMath::Integration:: Infinite )
00401       , m_rule      ( GaudiMath::Integration::    Fixed )
00402       , m_points    (         )
00403       , m_pdata     ( 0       )
00404       , m_epsabs    ( epsabs  )
00405       , m_epsrel    ( epsrel  )
00406       //
00407       , m_result    ( GSL_NEGINF                          )
00408       , m_error     ( GSL_POSINF                          )
00409       //
00410       , m_size      ( size                                )
00411       , m_ws        ( 0                                   )
00412       , m_argument  ()
00413       , m_argF      ()
00414     {
00415       if ( function.dimensionality() < 2          )
00416         { Exception("::constructor: invalid dimensionality ") ; }
00417       if ( m_index >= function.dimensionality()   )
00418         { Exception("::constructor: invalid variable index") ; }
00419 
00420       m_DIM = function.dimensionality() - 1 ;
00421       m_argument = Argument( m_DIM      ) ;
00422       m_argF     = Argument( m_DIM + 1  ) ;
00423 
00424     }
00425 
00427     NumericalDefiniteIntegral::NumericalDefiniteIntegral
00428     ( const NumericalDefiniteIntegral& right )
00429       : AbsFunction ()
00430       , m_function  ( right.m_function->clone() )
00431       , m_DIM       ( right.m_DIM      )
00432       , m_index     ( right.m_index    )
00433       , m_a         ( right.m_a        )
00434       , m_b         ( right.m_b        )
00435       , m_ia        ( right.m_ia       )
00436       , m_ib        ( right.m_ib       )
00437       , m_type      ( right.m_type     )
00438       , m_category  ( right.m_category )
00439       , m_rule      ( right.m_rule     )
00440       , m_points    ( right.m_points   )
00441       , m_pdata     ( 0                )
00442       , m_epsabs    ( right.m_epsabs   )
00443       , m_epsrel    ( right.m_epsrel   )
00444       , m_result    ( GSL_NEGINF       )
00445       , m_error     ( GSL_POSINF       )
00446       , m_size      ( right.m_size     )
00447       , m_ws        ( 0                )
00448       , m_argument  ( right.m_argument )
00449       , m_argF      ( right.m_argF     )
00450     {
00451       if( 0 != right.m_pdata )
00452         {
00453           m_pdata = new double[m_points.size()] ;
00454           std::copy( m_points.begin() , m_points.end() , m_pdata );
00455         }
00456     }
00457 
00458     NumericalDefiniteIntegral::~NumericalDefiniteIntegral()
00459     {
00460       if( 0 != m_function ) { delete   m_function ; m_function = 0 ; }
00461       if( 0 != m_pdata    ) { delete[] m_pdata    ; m_pdata    = 0 ; }
00462     }
00463 
00464     // ========================================================================
00465     // throw the exception
00466     // ========================================================================
00467     StatusCode NumericalDefiniteIntegral::Exception
00468     ( const std::string& message ,
00469       const StatusCode&  sc      ) const
00470     {
00471       throw GaudiException( "NumericalDefiniteIntegral::" + message ,
00472                             "*GaudiMath*" , sc ) ;
00473       return sc ;
00474     }
00475     // ========================================================================
00476 
00477     // ========================================================================
00479     // ========================================================================
00480     double NumericalDefiniteIntegral::operator()
00481       ( const double argument ) const
00482     {
00483       // reset the result and the error
00484       m_result = GSL_NEGINF ;
00485       m_error  = GSL_POSINF ;
00486 
00487       // check the argument
00488       if( 1 != m_DIM ) { Exception ( "operator(): invalid argument size " ) ; };
00489 
00490       m_argument[0] = argument ;
00491       return (*this) ( m_argument );
00492     }
00493     // ========================================================================
00494 
00495     // ========================================================================
00497     // ========================================================================
00498     Genfun::Derivative
00499     NumericalDefiniteIntegral::partial ( unsigned int idx ) const
00500     {
00501       if      ( idx >= m_DIM   )
00502         { Exception ( "::partial(i): invalid variable index " ) ; };
00503       //
00504       const AbsFunction& aux = NumericalDerivative( *this , idx ) ;
00505       return Genfun::FunctionNoop( &aux ) ;
00506     }
00507     // ========================================================================
00508 
00509 
00510     // ========================================================================
00512     // ========================================================================
00513     double NumericalDefiniteIntegral::operator()
00514       ( const Argument& argument ) const
00515     {
00516       // reset the result and the error
00517       m_result = GSL_NEGINF ;
00518       m_error  = GSL_POSINF ;
00519 
00520       // check the argument
00521       if( argument.dimension() != m_DIM )
00522         { Exception ( "operator(): invalid argument size " ) ; };
00523 
00524       // copy the argument
00525 
00526       for( size_t i  = 0 ; i < m_DIM ; ++i )
00527         {
00528           m_argument [i] = argument [i] ;
00529           const size_t j =  i < m_index ? i : i + 1 ;
00530           m_argF     [j] = argument [i] ;
00531         };
00532 
00533       // create the helper object
00534       GSL_Helper helper( *m_function , m_argF , m_index );
00535 
00536       // use GSL to evaluate the numerical derivative
00537       gsl_function F ;
00538       F.function = &GSL_Adaptor ;
00539       F.params   = &helper                 ;
00540       _Function F1    ;
00541       F1.fn      = &F ;
00542 
00543       if        (  GaudiMath::Integration::Infinite         == category () )
00544         { return   QAGI ( &F1 ) ; }                                // RETURN
00545 
00546       if ( m_a == m_b )
00547         {
00548           m_result = 0    ; m_error  = 0    ;                      // EXACT
00549           return m_result ;                                       // RETURN
00550         }
00551 
00552       if        (  GaudiMath::Integration::Singular         == category () )
00553          { return   QAGP ( &F1 ) ; }                                // RETURN
00554       else if   (  GaudiMath::Integration::Finite           == category () )
00555         if      (  GaudiMath::Integration::NonAdaptive      == type     () )
00556           { return QNG  ( &F1 ) ; }                                // RETURN
00557         else if (  GaudiMath::Integration::Adaptive         == type     () )
00558           { return QAG  ( &F1 ) ; }                                // RETURN
00559         else if (  GaudiMath::Integration::AdaptiveSingular == type     () )
00560           { return QAGS ( &F1 ) ; }                                // RETURN
00561         else
00562           { Exception ( "::operator(): invalid type "  ); }
00563       else
00564         { Exception ( "::operator(): invalid category "  ); }
00565 
00566       return 0 ;
00567     }
00568     // ========================================================================
00569 
00570     // ========================================================================
00572     // ========================================================================
00573     NumericalDefiniteIntegral::_Workspace*
00574     NumericalDefiniteIntegral::allocate() const
00575     {
00576       if ( 0 != m_ws ) { return m_ws; }
00577       gsl_integration_workspace* aux =
00578         gsl_integration_workspace_alloc( size () );
00579       if ( 0 == aux ) { Exception ( "allocate()::invalid workspace" ) ; };
00580       m_ws = new _Workspace() ;
00581       m_ws->ws = aux ;
00582       return m_ws ;
00583     }
00584     // ========================================================================
00585 
00586     // ========================================================================
00587     // adaptive integration on infinite interval
00588     // ========================================================================
00589     double NumericalDefiniteIntegral::QAGI ( _Function* F ) const
00590     {
00591       // check the argument
00592       if ( 0 == F    ) { Exception("::QAGI: invalid function"); }
00593 
00594       // allocate workspace
00595       if ( 0 == ws() ) { allocate() ; }
00596 
00597       int ierror = 0 ;
00598 
00599       if ( m_ia && m_ib )
00600         {
00601           ierror = gsl_integration_qagi  ( F->fn                ,
00602                                            m_epsabs  , m_epsrel ,
00603                                            size ()   , ws()->ws ,
00604                                            &m_result , &m_error ) ;
00605         }
00606       else if ( m_ia )
00607         {
00608           ierror = gsl_integration_qagil ( F->fn     , m_b      ,
00609                                            m_epsabs  , m_epsrel ,
00610                                            size ()   , ws()->ws ,
00611                                            &m_result , &m_error ) ;
00612         }
00613       else if ( m_ib )
00614         {
00615           ierror = gsl_integration_qagiu ( F->fn     , m_a      ,
00616                                            m_epsabs  , m_epsrel ,
00617                                            size ()   , ws()->ws ,
00618                                            &m_result , &m_error ) ;
00619         }
00620       else
00621         { Exception ( "::QAGI: invalid mode" ) ; };
00622 
00623       if( ierror ) { gsl_error( "NumericalDefiniteIntegral::QAGI" ,
00624                                 __FILE__ , __LINE__ , ierror ) ;}
00625 
00626       return m_result ;
00627     }
00628     // ========================================================================
00629 
00630     // ========================================================================
00631     // adaptive integration with known singular points
00632     // ========================================================================
00633     double NumericalDefiniteIntegral::QAGP( _Function* F ) const
00634     {
00635       if( 0 == F ) { Exception("QAGP::invalid function") ; }
00636 
00637       // no known singular points ?
00638       if( points().empty() || 0 == m_pdata ) { return QAGS( F ) ; }
00639 
00640       const size_t npts = points().size();
00641 
00642       // use GSL
00643       int ierror =
00644         gsl_integration_qagp ( F->fn                ,
00645                                m_pdata   , npts     ,
00646                                m_epsabs  , m_epsrel ,
00647                                size ()   , ws()->ws ,
00648                                &m_result , &m_error ) ;
00649 
00650       if( ierror ) { gsl_error( "NumericalDefiniteIntegral::QAGI " ,
00651                                 __FILE__ , __LINE__ , ierror ) ; }
00652 
00653       // the sign
00654       if ( m_a > m_b ) { m_result *= -1 ; }
00655 
00656       return m_result ;
00657     }
00658     // ========================================================================
00659 
00660     // ========================================================================
00661     // non-adaptive integration
00662     // ========================================================================
00663     double NumericalDefiniteIntegral::QNG ( _Function* F ) const
00664     {
00665       if( 0 == F ) { Exception("QNG::invalid function") ; }
00666 
00667       // integration limits
00668       const double low  = std::min ( m_a , m_b ) ;
00669       const double high = std::max ( m_a , m_b ) ;
00670 
00671       size_t neval = 0 ;
00672       int ierror =
00673         gsl_integration_qng ( F->fn                 ,
00674                               low       ,      high ,
00675                               m_epsabs  ,  m_epsrel ,
00676                               &m_result , &m_error  , &neval  ) ;
00677 
00678       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QNG " ,
00679                                 __FILE__ , __LINE__ , ierror ) ; }
00680 
00681       // sign
00682       if ( m_a > m_b ) { m_result *= -1 ; }
00683 
00684       return m_result ;
00685     }
00686     // ========================================================================
00687 
00688 
00689     // ========================================================================
00690     // simple adaptive integration
00691     // ========================================================================
00692     double NumericalDefiniteIntegral::QAG ( _Function* F ) const
00693     {
00694       if( 0 == F ) { Exception("QAG::invalid function") ; }
00695 
00696       // allocate workspace
00697       if( 0 == ws () ) { allocate () ; }
00698 
00699       // integration limits
00700       const double low  = std::min ( m_a , m_b ) ;
00701       const double high = std::max ( m_a , m_b ) ;
00702 
00703       int ierror =
00704         gsl_integration_qag ( F->fn                    ,
00705                               low       ,         high ,
00706                               m_epsabs  ,     m_epsrel ,
00707                               size   () , (int) rule() , ws ()->ws ,
00708                               &m_result ,     &m_error             );
00709 
00710       if( ierror ) { gsl_error( "NumericalDefiniteIntegral::QAG " ,
00711                                 __FILE__ , __LINE__ , ierror ) ; }
00712 
00713       // sign
00714       if ( m_a > m_b ) { m_result *= -1 ; }
00715 
00716       return m_result ;
00717     }
00718     // ========================================================================
00719 
00720     // ========================================================================
00721     // adaptive integration with singularities
00722     // ========================================================================
00723     double NumericalDefiniteIntegral::QAGS ( _Function* F ) const
00724     {
00725       if( 0 == F ) { Exception("QAG::invalid function") ; }
00726 
00727       if ( m_a == m_b )
00728         {
00729           m_result = 0    ;
00730           m_error  = 0    ;   // EXACT !
00731           return m_result ;
00732         }
00733 
00734       // allocate workspace
00735       if( 0 == ws () ) { allocate () ; }
00736 
00737       // integration limits
00738       const double low  = std::min ( m_a , m_b ) ;
00739       const double high = std::max ( m_a , m_b ) ;
00740 
00741       int ierror =
00742         gsl_integration_qags ( F->fn                ,
00743                                low       , high     ,
00744                                m_epsabs  , m_epsrel ,
00745                                size   () , ws()->ws ,
00746                                &m_result , &m_error );
00747 
00748       if( ierror ) { gsl_error( "NumericalDefiniteIntegral::QAGS " ,
00749                                 __FILE__ , __LINE__ , ierror ) ; }
00750 
00751       // sign
00752       if ( m_a > m_b ) { m_result *= -1 ; }
00753 
00754       return m_result ;
00755     }
00756     // ========================================================================
00757 
00758 
00759   } // end of namespace GaudiMathImplementation
00760 } // end of namespace Genfun
00761 
00762 
00763 
00764 // ============================================================================
00765 // The END
00766 // ============================================================================
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Mon Sep 17 2012 13:49:29 for Gaudi Framework, version v23r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004