00001
00002
00003
00004
00005
00006
00007 #include <vector>
00008 #include <algorithm>
00009
00010
00011
00012 #include "gsl/gsl_errno.h"
00013 #include "gsl/gsl_integration.h"
00014
00015
00016
00017 #include "GaudiKernel/GaudiException.h"
00018
00019
00020
00021 #include "GaudiMath/NumericalDefiniteIntegral.h"
00022 #include "GaudiMath/NumericalDerivative.h"
00023
00024
00025
00026 #include "Helpers.h"
00027
00028
00029
00030 #ifdef __ICC
00031
00032
00033 #pragma warning(disable:1572)
00034 #endif
00035 #ifdef WIN32
00036
00037
00038
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 ,
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 ,
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
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
00484 m_result = GSL_NEGINF ;
00485 m_error = GSL_POSINF ;
00486
00487
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
00517 m_result = GSL_NEGINF ;
00518 m_error = GSL_POSINF ;
00519
00520
00521 if( argument.dimension() != m_DIM )
00522 { Exception ( "operator(): invalid argument size " ) ; };
00523
00524
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
00534 GSL_Helper helper( *m_function , m_argF , m_index );
00535
00536
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 ) ; }
00545
00546 if ( m_a == m_b )
00547 {
00548 m_result = 0 ; m_error = 0 ;
00549 return m_result ;
00550 }
00551
00552 if ( GaudiMath::Integration::Singular == category () )
00553 { return QAGP ( &F1 ) ; }
00554 else if ( GaudiMath::Integration::Finite == category () )
00555 if ( GaudiMath::Integration::NonAdaptive == type () )
00556 { return QNG ( &F1 ) ; }
00557 else if ( GaudiMath::Integration::Adaptive == type () )
00558 { return QAG ( &F1 ) ; }
00559 else if ( GaudiMath::Integration::AdaptiveSingular == type () )
00560 { return QAGS ( &F1 ) ; }
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
00588
00589 double NumericalDefiniteIntegral::QAGI ( _Function* F ) const
00590 {
00591
00592 if ( 0 == F ) { Exception("::QAGI: invalid function"); }
00593
00594
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
00632
00633 double NumericalDefiniteIntegral::QAGP( _Function* F ) const
00634 {
00635 if( 0 == F ) { Exception("QAGP::invalid function") ; }
00636
00637
00638 if( points().empty() || 0 == m_pdata ) { return QAGS( F ) ; }
00639
00640 const size_t npts = points().size();
00641
00642
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
00654 if ( m_a > m_b ) { m_result *= -1 ; }
00655
00656 return m_result ;
00657 }
00658
00659
00660
00661
00662
00663 double NumericalDefiniteIntegral::QNG ( _Function* F ) const
00664 {
00665 if( 0 == F ) { Exception("QNG::invalid function") ; }
00666
00667
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
00682 if ( m_a > m_b ) { m_result *= -1 ; }
00683
00684 return m_result ;
00685 }
00686
00687
00688
00689
00690
00691
00692 double NumericalDefiniteIntegral::QAG ( _Function* F ) const
00693 {
00694 if( 0 == F ) { Exception("QAG::invalid function") ; }
00695
00696
00697 if( 0 == ws () ) { allocate () ; }
00698
00699
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
00714 if ( m_a > m_b ) { m_result *= -1 ; }
00715
00716 return m_result ;
00717 }
00718
00719
00720
00721
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 ;
00731 return m_result ;
00732 }
00733
00734
00735 if( 0 == ws () ) { allocate () ; }
00736
00737
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
00752 if ( m_a > m_b ) { m_result *= -1 ; }
00753
00754 return m_result ;
00755 }
00756
00757
00758
00759 }
00760 }
00761
00762
00763
00764
00765
00766