The Gaudi Framework  v30r3 (a5ef0a68)
NumericalIndefiniteIntegral.cpp
Go to the documentation of this file.
1 // ============================================================================
2 // Include
3 // ============================================================================
4 // STD & STL
5 // ============================================================================
6 #include <algorithm>
7 #include <vector>
8 // ============================================================================
9 // GSL
10 // ============================================================================
11 #include "gsl/gsl_errno.h"
12 #include "gsl/gsl_integration.h"
13 // ============================================================================
14 // GaudiMath
15 // ============================================================================
18 // ============================================================================
19 // GaudiKernel
20 // ============================================================================
22 // ============================================================================
23 // local
24 // ============================================================================
25 #include "Helpers.h"
26 // ============================================================================
27 
28 // ============================================================================
33 // ============================================================================
34 
35 #ifdef __ICC
36 // disable icc remark #1572: floating-point equality and inequality comparisons are unreliable
37 // The comparison are meant
38 #pragma warning( disable : 1572 )
39 #endif
40 #ifdef WIN32
41 // Disable the warning
42 // C4996: 'std::copy': Function call with parameters that may be unsafe
43 // The parameters are checked
44 #pragma warning( disable : 4996 )
45 #endif
46 
47 namespace Genfun
48 {
49  namespace GaudiMathImplementation
50  {
51 
53  gsl_function* fn;
54  };
55 
56  // ========================================================================
57 
58  // ========================================================================
73  // ========================================================================
74  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
75  const double a, const GaudiMath::Integration::Limit limit,
78  const double epsabs, const double epsrel,
79  const size_t size )
80  : AbsFunction()
81  , m_function( function.clone() )
83  , m_index( index )
84  , m_a( a )
85  , m_limit( limit )
86  , m_type( type )
88  , m_rule( rule )
89  //
90  , m_epsabs( epsabs )
91  , m_epsrel( epsrel )
92  //
93  , m_size( size )
95  {
98  }
99  if ( m_index >= m_DIM ) {
100  Exception( "::constructor: invalid variable index" );
101  }
102  }
103  // ========================================================================
104 
115  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
116  const double a, const Points& points,
118  const double epsabs, const double epsrel,
119  const size_t size )
120  : AbsFunction()
121  , m_function( function.clone() )
123  , m_index( index )
124  , m_a( a )
125  , m_limit( limit )
129  , m_points( points )
130  , m_epsabs( epsabs )
131  , m_epsrel( epsrel )
132  //
133  , m_size( size )
135  {
136  if ( m_index >= m_DIM ) {
137  Exception( "::constructor: invalid variable index" );
138  }
139  m_points.push_back( a );
142  }
143 
144  // ========================================================================
152  // ========================================================================
153  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
155  const double epsabs, const double epsrel,
156  const size_t size )
157  : AbsFunction()
158  , m_function( function.clone() )
160  , m_index( index )
161  , m_a( GSL_NEGINF ) // should not be used!
162  , m_limit( limit )
166  , m_epsabs( epsabs )
167  , m_epsrel( epsrel )
168  , m_size( size )
170  {
171  if ( m_index >= m_DIM ) {
172  Exception( "::constructor: invalid variable index" );
173  }
174  }
175  // ========================================================================
176 
177  // ========================================================================
179  // ========================================================================
181  : AbsFunction()
182  , m_function( right.m_function->clone() )
183  , m_DIM( right.m_DIM )
184  , m_index( right.m_index )
185  , m_a( right.m_a )
186  , m_limit( right.m_limit )
187  , m_type( right.m_type )
188  , m_category( right.m_category )
189  , m_rule( right.m_rule )
190  , m_points( right.m_points )
191  , m_epsabs( right.m_epsabs )
192  , m_epsrel( right.m_epsrel )
193  , m_size( right.m_size )
194  , m_argument( right.m_argument )
195  {
196  }
197  // ========================================================================
198 
199  // ========================================================================
200  // throw the exception
201  // ========================================================================
203  {
204  throw GaudiException( "NumericalIndefiniteIntegral::" + message, "*GaudiMath*", sc );
205  return sc;
206  }
207  // ========================================================================
208 
209  // ========================================================================
211  // ========================================================================
212  double NumericalIndefiniteIntegral::operator()( const double argument ) const
213  {
214  // reset the result and the error
215  m_result = GSL_NEGINF;
216  m_error = GSL_POSINF;
217 
218  // check the argument
219  if ( 1 != m_DIM ) {
220  Exception( "operator(): invalid argument size " );
221  };
222 
223  m_argument[0] = argument;
224  return ( *this )( m_argument );
225  }
226  // ========================================================================
227 
228  // ========================================================================
230  // ========================================================================
232  {
233  if ( idx >= m_DIM ) {
234  Exception( "::partial(i): invalid variable index " );
235  };
236  if ( idx != m_index ) {
237  const AbsFunction& aux = NumericalDerivative( *this, idx );
238  return Genfun::FunctionNoop( &aux );
240  const AbsFunction& aux = -1 * function();
241  return Genfun::FunctionNoop( &aux );
242  }
243  const AbsFunction& aux = function();
244  return Genfun::FunctionNoop( &aux );
245  }
246 
247  // ========================================================================
249  // ========================================================================
250  double NumericalIndefiniteIntegral::operator()( const Argument& argument ) const
251  {
252  // reset the result and the error
253  m_result = GSL_NEGINF;
254  m_error = GSL_POSINF;
255 
256  // check the argument
257  if ( argument.dimension() != m_DIM ) {
258  Exception( "operator(): invalid argument size " );
259  };
260 
261  // copy the argument
262  for ( size_t i = 0; i < m_DIM; ++i ) {
263  m_argument[i] = argument[i];
264  }
265 
266  // create the helper object
268 
269  // use GSL to evaluate the numerical derivative
270  gsl_function F;
271  F.function = &GSL_Adaptor;
272  F.params = &helper;
273  _Function F1;
274  F1.fn = &F;
275 
276  switch ( category() ) {
278  return QAGI( &F1 );
280  return QAGP( &F1 );
282  switch ( type() ) {
284  return QNG( &F1 );
286  return QAG( &F1 );
288  return QAGS( &F1 );
289  default:
290  Exception( "::operator(): invalid type " );
291  }
292  break;
293  default:
294  Exception( "::operator(): invalid category " );
295  }
296  return 0;
297  }
298  // ========================================================================
299 
300  // ========================================================================
302  // ========================================================================
304  {
305  if ( !m_ws ) {
306  m_ws.reset( new _Workspace() );
307  m_ws->ws = gsl_integration_workspace_alloc( size() );
308  if ( !m_ws->ws ) {
309  Exception( "allocate()::invalid workspace" );
310  };
311  }
312  return m_ws.get();
313  }
314  // ========================================================================
315 
316  // ========================================================================
317  // adaptive integration on infinite interval
318  // ========================================================================
320  {
321  // check the argument
322  if ( !F ) {
323  Exception( "::QAGI: invalid function" );
324  }
325 
326  const double x = m_argument[m_index];
327 
328  // allocate workspace
329  allocate();
330 
331  int ierror = 0;
332  switch ( limit() ) {
334  ierror = gsl_integration_qagiu( F->fn, x, m_epsabs, m_epsrel, size(), ws()->ws, &m_result, &m_error );
335  break;
337  ierror = gsl_integration_qagil( F->fn, x, m_epsabs, m_epsrel, size(), ws()->ws, &m_result, &m_error );
338  break;
339  default:
340  Exception( "::QAGI: invalid mode" );
341  };
342 
343  if ( ierror ) {
344  gsl_error( "NumericalIndefiniteIntegral::QAGI", __FILE__, __LINE__, ierror );
345  }
346 
347  return m_result;
348  }
349  // ========================================================================
350 
351  // ========================================================================
352  // adaptive integration with known singular points
353  // ========================================================================
355  {
356  if ( !F ) {
357  Exception( "QAGP::invalid function" );
358  }
359 
360  const double x = m_argument[m_index];
361  if ( m_a == x ) {
362  m_result = 0;
363  m_error = 0; // EXACT !
364  return m_result;
365  }
366 
367  // no known singular points ?
368  if ( points().empty() ) {
369  return QAGS( F );
370  }
371 
372  // integration limits
373  const auto limits = std::minmax( m_a, x );
374 
375  // "active" singular points
376  auto lower = std::lower_bound( points().begin(), points().end(), limits.first );
377  auto upper = std::upper_bound( points().begin(), points().end(), limits.second );
378 
379  Points pnts;
380  pnts.reserve( std::distance( lower, upper ) );
381  std::copy( lower, upper, std::back_inserter( pnts ) );
382  if ( *lower != limits.first ) {
383  pnts.insert( pnts.begin(), limits.first );
384  }
385  if ( *upper != limits.second ) {
386  pnts.insert( pnts.end(), limits.second );
387  }
388 
389  // use GSL
390  int ierror = gsl_integration_qagp( F->fn, pnts.data(), pnts.size(), m_epsabs, m_epsrel, size(), ws()->ws,
391  &m_result, &m_error );
392 
393  if ( ierror ) {
394  gsl_error( "NumericalIndefiniteIntegral::QAGI ", __FILE__, __LINE__, ierror );
395  }
396 
397  // sign
399  m_result *= -1;
400  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
401  m_result *= -1;
402  }
403 
404  return m_result;
405  }
406  // ========================================================================
407 
408  // ========================================================================
409  // non-adaptive integration
410  // ========================================================================
412  {
413  if ( !F ) {
414  Exception( "QNG::invalid function" );
415  }
416 
417  const double x = m_argument[m_index];
418  if ( m_a == x ) {
419  m_result = 0;
420  m_error = 0; // EXACT !
421  return m_result;
422  }
423 
424  // integration limits
425  const double a = std::min( m_a, x );
426  const double b = std::max( m_a, x );
427 
428  size_t neval = 0;
429  int ierror = gsl_integration_qng( F->fn, a, b, m_epsabs, m_epsrel, &m_result, &m_error, &neval );
430 
431  if ( ierror ) {
432  gsl_error( "NumericalIndefiniteIntegral::QNG ", __FILE__, __LINE__, ierror );
433  }
434 
435  // sign
437  m_result *= -1;
438  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
439  m_result *= -1;
440  }
441 
442  return m_result;
443  }
444 
445  // ========================================================================
446  // simple adaptive integration
447  // ========================================================================
449  {
450  if ( !F ) {
451  Exception( "QAG::invalid function" );
452  }
453 
454  const double x = m_argument[m_index];
455  if ( m_a == x ) {
456  m_result = 0;
457  m_error = 0; // EXACT !
458  return m_result;
459  }
460 
461  // allocate workspace
462  allocate();
463 
464  // integration limits
465  const auto limits = std::minmax( m_a, x );
466 
467  int ierror = gsl_integration_qag( F->fn, limits.first, limits.second, m_epsabs, m_epsrel, size(), (int)rule(),
468  ws()->ws, &m_result, &m_error );
469 
470  if ( ierror ) {
471  gsl_error( "NumericalIndefiniteIntegral::QAG ", __FILE__, __LINE__, ierror );
472  }
473 
474  // sign
476  m_result *= -1;
477  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
478  m_result *= -1;
479  }
480 
481  return m_result;
482  }
483  // ========================================================================
484 
485  // ========================================================================
486  // adaptive integration with singularities
487  // ========================================================================
489  {
490  if ( !F ) {
491  Exception( "QAG::invalid function" );
492  }
493 
494  const double x = m_argument[m_index];
495  if ( m_a == x ) {
496  m_result = 0;
497  m_error = 0; // EXACT !
498  return m_result;
499  }
500 
501  // allocate workspace
502  allocate();
503 
504  // integration limits
505  const auto limits = std::minmax( m_a, x );
506 
507  int ierror = gsl_integration_qags( F->fn, limits.first, limits.second, m_epsabs, m_epsrel, size(), ws()->ws,
508  &m_result, &m_error );
509 
510  if ( ierror ) {
511  gsl_error( "NumericalIndefiniteIntegral::QAGS ", __FILE__, __LINE__, ierror );
512  }
513 
514  // sign
516  m_result *= -1;
517  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
518  m_result *= -1;
519  }
520 
521  return m_result;
522  }
523  // ========================================================================
524  } // end of namespace GaudiMathImplementation
525 } // end of namespace Genfun
526 
527 // ============================================================================
528 // The END
529 // ============================================================================
Genfun::Derivative partial(unsigned int index) const override
Derivatives.
T copy(T...args)
Define general base for Gaudi exception.
T distance(T...args)
T minmax(T...args)
StatusCode Exception(const std::string &message, const StatusCode &sc=StatusCode::FAILURE) const
T upper_bound(T...args)
T end(T...args)
GaudiMath::Integration::Limit limit() const
integration limit
Genfun::GaudiMathImplementation::NumericalDerivative Derivative
Definition: GaudiMath.h:27
T lower_bound(T...args)
T unique(T...args)
GaudiMath::Integration::Category category() const
integration category
STL class.
T min(T...args)
T push_back(T...args)
T data(T...args)
GaudiMath::Integration::KronrodRule rule() const
integration rule
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:51
_Workspace * allocate() const
allocate the integration workspace
double operator()(double argument) const override
Function value.
Type
type of integration (for finite limits)
Definition: Integration.h:24
T erase(T...args)
double GSL_Adaptor(double x, void *params)
Definition: Helpers.cpp:31
T max(T...args)
Numerical derivative (using GSL adaptive numerical differentiation)
unsigned int dimensionality() const override
dimensionality of the problem
GaudiMath::Integration::Type type() const
integration type
T insert(T...args)
T size(T...args)
T begin(T...args)
T back_inserter(T...args)
const AbsFunction & function() const
accessor to the function itself
Limit
how to distinguish variable low and variable high limits
Definition: Integration.h:22
GaudiMath.h GaudiMath/GaudiMath.h.
KronrodRule
integration rule
Definition: Integration.h:28
T sort(T...args)
AttribStringParser::Iterator begin(const AttribStringParser &parser)
the simple structure to be used for adaption interface Genfun::AbsFunction to gsl_function structure ...
Definition: Helpers.h:25
T reserve(T...args)
collection of common types for classes NumericalIndefiniteIntegral and NumericalDefiniteIntegral ...