Gaudi Framework, version v21r11

Home   Generated: 30 Sep 2010

NumericalIndefiniteIntegral.cpp

Go to the documentation of this file.
00001 // $Id: NumericalIndefiniteIntegral.cpp,v 1.2 2007/05/24 14:39:11 hmd Exp $
00002 // ============================================================================
00003 // CVS tag $Name:  $ 
00004 // ============================================================================
00005 // Include
00006 // ============================================================================
00007 // STD & STL 
00008 // ============================================================================
00009 #include <vector>
00010 #include <algorithm>
00011 // ============================================================================
00012 // GSL
00013 // ============================================================================
00014 #include "gsl/gsl_errno.h"
00015 #include "gsl/gsl_integration.h"
00016 // ============================================================================
00017 // GaudiMath 
00018 // ============================================================================
00019 #include "GaudiMath/NumericalIndefiniteIntegral.h"
00020 #include "GaudiMath/NumericalDerivative.h"
00021 // ============================================================================
00022 // GaudiKernel
00023 // ============================================================================
00024 #include "GaudiKernel/GaudiException.h"
00025 // ============================================================================
00026 // local 
00027 // ============================================================================
00028 #include "Helpers.h"
00029 // ============================================================================
00030 
00031 // ============================================================================
00036 // ============================================================================
00037 
00038 #ifdef __ICC
00039 // disable icc remark #1572: floating-point equality and inequality comparisons are unreliable
00040 //   The comparison are meant
00041 #pragma warning(disable:1572)
00042 #endif
00043 
00044 namespace Genfun 
00045 {
00046   namespace GaudiMathImplementation 
00047   {
00048     
00049     struct NumericalIndefiniteIntegral::_Workspace 
00050     { gsl_integration_workspace* ws ; };
00051     struct NumericalIndefiniteIntegral::_Function  
00052     { gsl_function*              fn ; };
00053     
00054     // ========================================================================
00056     // ========================================================================
00057     FUNCTION_OBJECT_IMP( NumericalIndefiniteIntegral )
00058     // ========================================================================
00059 
00060     // ========================================================================
00075     // ========================================================================
00076     NumericalIndefiniteIntegral::NumericalIndefiniteIntegral
00077     ( const AbsFunction&                         function  ,
00078       const size_t                               index     , 
00079       const double                               a         , 
00080       const GaudiMath::Integration::Limit        limit     , 
00081       const GaudiMath::Integration::Type         type      , 
00082       const GaudiMath::Integration::KronrodRule  rule      , 
00083       const double                               epsabs    , 
00084       const double                               epsrel    , 
00085       const size_t                               size      ) 
00086       : AbsFunction () 
00087       , m_function  ( function.clone()                    )
00088       , m_DIM       ( function.dimensionality()           )
00089       , m_index     ( index                               )
00090       , m_a         ( a                                   ) 
00091       , m_limit     ( limit                               )
00092       , m_type      ( type                                ) 
00093       , m_category  ( GaudiMath::Integration::Finite      ) 
00094       , m_rule      ( rule                                ) 
00095       //
00096       , m_points    (                                     ) 
00097       , m_pdata     ( 0                                   )
00098       //
00099       , m_epsabs    ( epsabs                              ) 
00100       , m_epsrel    ( epsrel                              ) 
00101       //
00102       , m_result    ( GSL_NEGINF                          ) 
00103       , m_error     ( GSL_POSINF                          ) 
00104       //
00105       , m_size      ( size                                ) 
00106       , m_ws        ( 0                                   ) 
00107       , m_argument  ( function.dimensionality()           ) 
00108     {
00109       if ( GaudiMath::Integration::Fixed == m_rule ) 
00110         { m_rule = GaudiMath::Integration::Default ; }
00111       if ( m_index >= m_DIM  ) 
00112         { Exception("::constructor: invalid variable index") ; }
00113     }
00114     // ========================================================================
00115     
00126     NumericalIndefiniteIntegral::NumericalIndefiniteIntegral 
00127     ( const AbsFunction&                   function ,
00128       const size_t                         index    , 
00129       const double                         a        , 
00130       const Points&                        points   ,
00131       const GaudiMath::Integration::Limit  limit    , 
00132       const double                         epsabs   , 
00133       const double                         epsrel   ,
00134       const size_t                         size     ) 
00135       : AbsFunction () 
00136       , m_function  ( function.clone()          )
00137       , m_DIM       ( function.dimensionality() ) 
00138       , m_index     ( index                     ) 
00139       , m_a         ( a                         )
00140       , m_limit     ( limit                     )
00141       , m_type      ( GaudiMath::Integration::    Other )
00142       , m_category  ( GaudiMath::Integration:: Singular )
00143       , m_rule      ( GaudiMath::Integration::    Fixed )
00144       , m_points    ( points  ) 
00145       , m_pdata     ( 0       ) 
00146       , m_epsabs    ( epsabs  )
00147       , m_epsrel    ( epsrel  ) 
00148       //
00149       , m_result    ( GSL_NEGINF                          ) 
00150       , m_error     ( GSL_POSINF                          ) 
00151       //
00152       , m_size      ( size                                ) 
00153       , m_ws        ( 0                                   ) 
00154       , m_argument  ( function.dimensionality()           ) 
00155     {
00156       if ( m_index >= m_DIM ) 
00157         { Exception("::constructor: invalid variable index") ; } 
00158       m_pdata = new double[ 2 + m_points.size() ] ;
00159       m_points.push_back( a ) ;
00160       std::sort( m_points.begin() , m_points.end() ) ;
00161       m_points.erase ( std::unique( m_points.begin () , 
00162                                     m_points.end   () ) , m_points.end() );
00163     }
00164     
00165     // ========================================================================
00173     // ========================================================================
00174     NumericalIndefiniteIntegral::NumericalIndefiniteIntegral 
00175     ( const AbsFunction&                  function  ,
00176       const size_t                        index     , 
00177       const GaudiMath::Integration::Limit limit     ,
00178       const double                        epsabs    , 
00179       const double                        epsrel    , 
00180       const size_t                        size      ) 
00181       : AbsFunction () 
00182       , m_function  ( function.clone() ) 
00183       , m_DIM       ( function.dimensionality() )
00184       , m_index     ( index            )
00185       , m_a         ( GSL_NEGINF       ) // should not be used! 
00186       , m_limit     ( limit            )
00187       , m_type      ( GaudiMath::Integration::    Other ) 
00188       , m_category  ( GaudiMath::Integration:: Infinite )
00189       , m_rule      ( GaudiMath::Integration::    Fixed )
00190       , m_points    (            ) 
00191       , m_pdata     ( 0          )
00192       , m_epsabs    ( epsabs     ) 
00193       , m_epsrel    ( epsrel     )
00194       , m_result    ( GSL_NEGINF ) 
00195       , m_error     ( GSL_POSINF ) 
00196       , m_size      ( size       ) 
00197       , m_ws        ( 0          ) 
00198       , m_argument  ( function.dimensionality()           ) 
00199     {
00200       if ( m_index >= m_DIM ) 
00201         { Exception("::constructor: invalid variable index") ; }
00202     }
00203     // ========================================================================
00204 
00205     
00206     // ========================================================================
00208     // ========================================================================
00209     NumericalIndefiniteIntegral::
00210     NumericalIndefiniteIntegral( const NumericalIndefiniteIntegral& right )
00211       : AbsFunction () 
00212       , m_function  ( right.m_function->clone() ) 
00213       , m_DIM       ( right.m_DIM      ) 
00214       , m_index     ( right.m_index    ) 
00215       , m_a         ( right.m_a        ) 
00216       , m_limit     ( right.m_limit    ) 
00217       , m_type      ( right.m_type     ) 
00218       , m_category  ( right.m_category )
00219       , m_rule      ( right.m_rule     )
00220       , m_points    ( right.m_points   ) 
00221       , m_pdata     ( 0 )           // attention 
00222       , m_epsabs    ( right.m_epsabs   ) 
00223       , m_epsrel    ( right.m_epsrel   ) 
00224       , m_result    ( GSL_NEGINF       ) 
00225       , m_error     ( GSL_POSINF       )
00226       , m_size      ( right.m_size     ) 
00227       , m_ws        ( 0                )
00228       , m_argument  ( right.m_argument )
00229     {
00230       m_pdata = new double[ 2 + m_points.size() ] ; // attention! 
00231     }
00232     // ========================================================================
00233 
00234       
00235     // ========================================================================
00237     // ========================================================================
00238     NumericalIndefiniteIntegral::~NumericalIndefiniteIntegral()
00239     {
00240       if( 0 != m_ws ) 
00241         { 
00242           gsl_integration_workspace_free ( m_ws->ws ) ;
00243           delete m_ws ;
00244           m_ws = 0 ;
00245         }
00246       if ( 0 != m_pdata    ) { delete m_pdata    ; m_pdata    = 0 ; }
00247       if ( 0 != m_function ) { delete m_function ; m_function = 0 ; }
00248     }
00249     // ========================================================================
00250 
00251     // ========================================================================
00252     // throw the exception
00253     // ========================================================================
00254     StatusCode NumericalIndefiniteIntegral::Exception 
00255     ( const std::string& message , 
00256       const StatusCode&  sc      ) const 
00257     {
00258       throw GaudiException( "NumericalIndefiniteIntegral::" + message , 
00259                             "*GaudiMath*" , sc ) ;
00260       return sc ;
00261     }
00262     // ========================================================================
00263     
00264     // ========================================================================
00266     // ========================================================================
00267     double NumericalIndefiniteIntegral::operator() 
00268       ( const double argument ) const 
00269     {
00270       // reset the result and the error  
00271       m_result = GSL_NEGINF ;
00272       m_error  = GSL_POSINF ;
00273       
00274       // check the argument 
00275       if( 1 != m_DIM ) { Exception ( "operator(): invalid argument size " ) ; };
00276       
00277       m_argument[0] = argument ;
00278       return (*this) ( m_argument );
00279     }
00280     // ========================================================================
00281 
00282     // ========================================================================
00284     // ========================================================================
00285     Genfun::Derivative 
00286     NumericalIndefiniteIntegral::partial ( unsigned int idx ) const
00287     {
00288       if      ( idx >= m_DIM   )
00289         { Exception ( "::partial(i): invalid variable index " ) ; };
00290       if      ( idx != m_index )
00291         {
00292           const AbsFunction& aux = NumericalDerivative( *this , idx ) ;
00293           return Genfun::FunctionNoop( &aux ) ;
00294         }
00295       else if ( GaudiMath::Integration::VariableLowLimit == limit () ) 
00296         { 
00297           const AbsFunction& aux = -1 * function() ;
00298           return Genfun::FunctionNoop( &aux ) ;
00299         }
00300       const AbsFunction& aux = function() ;
00301       return Genfun::FunctionNoop( &aux ) ;
00302     }
00303     
00304     // ========================================================================
00306     // ========================================================================
00307     double NumericalIndefiniteIntegral::operator() 
00308       ( const Argument& argument ) const 
00309     {
00310       // reset the result and the error  
00311       m_result = GSL_NEGINF ;
00312       m_error  = GSL_POSINF ;
00313       
00314       // check the argument 
00315       if( argument.dimension() != m_DIM ) 
00316         { Exception ( "operator(): invalid argument size " ) ; };
00317       
00318       // copy the argument 
00319       {for( size_t i  = 0 ; i < m_DIM ; ++i ){ m_argument[i] = argument[i];}}
00320       
00321       // create the helper object 
00322       GSL_Helper helper( *m_function , m_argument , m_index );
00323       
00324       // use GSL to evaluate the numerical derivative 
00325       gsl_function F ;
00326       F.function = &GSL_Adaptor ;
00327       F.params   = &helper                 ;
00328       _Function F1    ;
00329       F1.fn      = &F ;
00330       
00331       if        (  GaudiMath::Integration::Infinite         == category () )
00332         { return   QAGI ( &F1 ) ; }                                // RETURN
00333       else if   (  GaudiMath::Integration::Singular         == category () )
00334         { return   QAGP ( &F1 ) ; }                                // RETURN
00335       else if   (  GaudiMath::Integration::Finite           == category () )
00336         if      (  GaudiMath::Integration::NonAdaptive      == type     () ) 
00337           { return QNG  ( &F1 ) ; }                                // RETURN
00338         else if (  GaudiMath::Integration::Adaptive         == type     () ) 
00339           { return QAG  ( &F1 ) ; }                                // RETURN
00340         else if (  GaudiMath::Integration::AdaptiveSingular == type     () ) 
00341           { return QAGS ( &F1 ) ; }                                // RETURN
00342         else 
00343           { Exception ( "::operator(): invalid type "  ); }
00344       else 
00345         { Exception ( "::operator(): invalid category "  ); }
00346       
00347       return 0 ;
00348     }
00349     // ========================================================================
00350     
00351     // ========================================================================
00353     // ======================================================================== 
00354     NumericalIndefiniteIntegral::_Workspace* 
00355     NumericalIndefiniteIntegral::allocate() const 
00356     {
00357       if ( 0 != m_ws ) { return m_ws; }
00358       gsl_integration_workspace* aux = 
00359         gsl_integration_workspace_alloc( size () );
00360       if ( 0 == aux ) { Exception ( "allocate()::invalid workspace" ) ; };
00361       m_ws = new _Workspace() ;
00362       m_ws->ws = aux ;
00363       return m_ws ;
00364     }
00365     // ========================================================================
00366     
00367     // ========================================================================
00368     // adaptive integration on infinite interval
00369     // ========================================================================
00370     double NumericalIndefiniteIntegral::QAGI ( _Function* F ) const 
00371     {
00372       // check the argument 
00373       if( 0 == F ) { Exception("::QAGI: invalid function"); }
00374       
00375       const double x = m_argument[m_index] ;
00376       
00377       // allocate workspace 
00378       if( 0 == ws() ) { allocate() ; }
00379       
00380       int ierror = 0 ;
00381       switch ( limit() ) 
00382         {
00383         case GaudiMath::Integration::VariableLowLimit  : 
00384           ierror = gsl_integration_qagiu ( F->fn     , x        ,  
00385                                            m_epsabs  , m_epsrel , 
00386                                            size ()   , ws()->ws , 
00387                                            &m_result , &m_error ) ; break ;
00388         case GaudiMath::Integration::VariableHighLimit :
00389           ierror = gsl_integration_qagil ( F->fn     , x        ,
00390                                            m_epsabs  , m_epsrel , 
00391                                            size ()   , ws()->ws , 
00392                                            &m_result , &m_error ) ; break ;
00393         default :
00394           Exception ( "::QAGI: invalid mode" ) ;
00395         };
00396       
00397       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGI" , 
00398                                 __FILE__ , __LINE__ , ierror ) ;}
00399       
00400       return m_result ;
00401     }
00402     // ========================================================================
00403     
00404     // ========================================================================
00405     // adaptive integration with known singular points 
00406     // ========================================================================
00407     double NumericalIndefiniteIntegral::QAGP( _Function* F ) const 
00408     {
00409       if( 0 == F ) { Exception("QAGP::invalid function") ; }
00410       
00411       const double x = m_argument[m_index] ;
00412       if ( m_a == x  ) 
00413         { 
00414           m_result = 0    ;
00415           m_error  = 0    ;   // EXACT !
00416           return m_result ; 
00417         }
00418       
00419       // no known singular points ?
00420       if( points().empty() ) { return QAGS( F ) ; }
00421       
00422       // integration limits 
00423       const double a = std::min ( m_a , x ) ;
00424       const double b = std::max ( m_a , x ) ;
00425       
00426       // "active" singular points
00427       Points::const_iterator lower = 
00428         std::lower_bound ( points().begin() , points().end() , a ) ;
00429       Points::const_iterator upper = 
00430         std::upper_bound ( points().begin() , points().end() , b ) ;
00431       
00432       Points pnts ( upper - lower ) ;
00433       std::copy( lower , upper , pnts.begin() );
00434       if ( *lower != a       ) { pnts.insert( pnts.begin () , a ) ; }
00435       if ( *upper != b       ) { pnts.insert( pnts.end   () , b ) ; }
00436       std::copy( pnts.begin() , pnts.end() , m_pdata );
00437       const size_t npts = pnts.size() ;
00438       
00439       // use GSL 
00440       int ierror = 
00441         gsl_integration_qagp ( F->fn                , 
00442                                m_pdata   , npts     , 
00443                                m_epsabs  , m_epsrel ,
00444                                size ()   , ws()->ws , 
00445                                &m_result , &m_error ) ;
00446       
00447       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGI " , 
00448                                 __FILE__ , __LINE__ , ierror ) ; }
00449       
00450       // sign
00451       if      ( GaudiMath::Integration::VariableHighLimit == limit() 
00452                 &&  x < m_a  ) { m_result *= -1 ; }
00453       else if ( GaudiMath::Integration::VariableLowLimit  == limit() 
00454                 &&  x > m_a  ) { m_result *= -1 ; }
00455       
00456       return m_result ;
00457     }
00458     // ========================================================================
00459     
00460     // ========================================================================
00461     // non-adaptive integration 
00462     // ========================================================================
00463     double NumericalIndefiniteIntegral::QNG ( _Function* F ) const 
00464     {
00465       if( 0 == F ) { Exception("QNG::invalid function") ; }
00466       
00467       const double x = m_argument[m_index] ;
00468       if ( m_a == x  ) 
00469         { 
00470           m_result = 0    ;
00471           m_error  = 0    ;   // EXACT !
00472           return m_result ; 
00473         }
00474       
00475       // integration limits 
00476       const double a = std::min ( m_a , x ) ;
00477       const double b = std::max ( m_a , x ) ;
00478       
00479       size_t neval = 0 ;
00480       int ierror = 
00481         gsl_integration_qng ( F->fn                 ,  
00482                               a         ,         b , 
00483                               m_epsabs  ,  m_epsrel , 
00484                               &m_result , &m_error  , &neval  ) ;
00485       
00486       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QNG " , 
00487                                 __FILE__ , __LINE__ , ierror ) ; }
00488       
00489       // sign
00490       if      ( GaudiMath::Integration::VariableHighLimit == limit() 
00491                 &&  x < m_a  ) { m_result *= -1 ; }
00492       else if ( GaudiMath::Integration::VariableLowLimit  == limit() 
00493                 &&  x > m_a  ) { m_result *= -1 ; }
00494 
00495       return m_result ;
00496     }
00497     
00498     // ========================================================================
00499     // simple adaptive integration 
00500     // ========================================================================
00501     double NumericalIndefiniteIntegral::QAG ( _Function* F ) const 
00502     {
00503       if( 0 == F ) { Exception("QAG::invalid function") ; }
00504       
00505       const double x = m_argument[m_index] ;
00506       if ( m_a == x  ) 
00507         { 
00508           m_result = 0    ;
00509           m_error  = 0    ;   // EXACT !
00510           return m_result ; 
00511         }
00512       
00513       // allocate workspace 
00514       if( 0 == ws () ) { allocate () ; }
00515       
00516       // integration limits 
00517       const double a = std::min ( m_a , x ) ;
00518       const double b = std::max ( m_a , x ) ;
00519       
00520       int ierror = 
00521         gsl_integration_qag ( F->fn                    , 
00522                               a         ,            b , 
00523                               m_epsabs  ,     m_epsrel , 
00524                               size   () , (int) rule() , ws ()->ws , 
00525                               &m_result ,     &m_error             );
00526       
00527       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAG " , 
00528                                 __FILE__ , __LINE__ , ierror ) ; }
00529       
00530       // sign
00531       if      ( GaudiMath::Integration::VariableHighLimit == limit() 
00532                 &&  x < m_a  ) { m_result *= -1 ; }
00533       else if ( GaudiMath::Integration::VariableLowLimit  == limit() 
00534                 &&  x > m_a  ) { m_result *= -1 ; }
00535       
00536       return m_result ;
00537     }
00538     // ========================================================================
00539     
00540     // ========================================================================
00541     // adaptive integration with singularities 
00542     // ========================================================================
00543     double NumericalIndefiniteIntegral::QAGS ( _Function* F ) const 
00544     {
00545       if( 0 == F ) { Exception("QAG::invalid function") ; }
00546       
00547       const double x = m_argument[m_index] ;
00548       if ( m_a == x  ) 
00549         { 
00550           m_result = 0    ;
00551           m_error  = 0    ;   // EXACT !
00552           return m_result ; 
00553         }
00554       
00555       // allocate workspace 
00556       if( 0 == ws () ) { allocate () ; }
00557       
00558       // integration limits 
00559       const double a = std::min ( m_a , x ) ;
00560       const double b = std::max ( m_a , x ) ;
00561       
00562       int ierror = 
00563         gsl_integration_qags ( F->fn                , 
00564                                a         , b        , 
00565                                m_epsabs  , m_epsrel , 
00566                                size   () , ws()->ws , 
00567                                &m_result , &m_error );
00568       
00569       if( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGS " , 
00570                                 __FILE__ , __LINE__ , ierror ) ; }
00571       
00572       // sign
00573       if      ( GaudiMath::Integration::VariableHighLimit == limit() 
00574                 &&  x < m_a  ) { m_result *= -1 ; }
00575       else if ( GaudiMath::Integration::VariableLowLimit  == limit() 
00576                 &&  x > m_a  ) { m_result *= -1 ; }
00577       
00578       return m_result ;
00579     }
00580     // ========================================================================
00581 
00582   } // end of namespace GaudiMathImplementation
00583 } // end of namespace Genfun
00584 
00585 
00586 // ============================================================================
00587 // The END 
00588 // ============================================================================

Generated at Thu Sep 30 09:57:30 2010 for Gaudi Framework, version v21r11 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004