Gaudi Framework, version v21r9

Home   Generated: 3 May 2010

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

Generated at Mon May 3 12:14:11 2010 for Gaudi Framework, version v21r9 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004