Gaudi Framework, version v22r2

Home   Generated: Tue May 10 2011

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

Generated at Tue May 10 2011 18:53:24 for Gaudi Framework, version v22r2 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004