Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v31r0 (aeb156f0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  namespace GaudiMathImplementation {
49 
51  gsl_function* fn;
52  };
53 
54  // ========================================================================
55 
56  // ========================================================================
71  // ========================================================================
72  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
73  const double a, const GaudiMath::Integration::Limit limit,
76  const double epsabs, const double epsrel,
77  const size_t size )
78  : AbsFunction()
79  , m_function( function.clone() )
81  , m_index( index )
82  , m_a( a )
83  , m_limit( limit )
84  , m_type( type )
86  , m_rule( rule )
87  //
88  , m_epsabs( epsabs )
89  , m_epsrel( epsrel )
90  //
91  , m_size( size )
94  if ( m_index >= m_DIM ) { Exception( "::constructor: invalid variable index" ); }
95  }
96  // ========================================================================
97 
108  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
109  const double a, const Points& points,
111  const double epsabs, const double epsrel,
112  const size_t size )
113  : AbsFunction()
114  , m_function( function.clone() )
116  , m_index( index )
117  , m_a( a )
118  , m_limit( limit )
122  , m_points( points )
123  , m_epsabs( epsabs )
124  , m_epsrel( epsrel )
125  //
126  , m_size( size )
128  if ( m_index >= m_DIM ) { Exception( "::constructor: invalid variable index" ); }
129  m_points.push_back( a );
132  }
133 
134  // ========================================================================
142  // ========================================================================
143  NumericalIndefiniteIntegral::NumericalIndefiniteIntegral( const AbsFunction& function, const size_t index,
145  const double epsabs, const double epsrel,
146  const size_t size )
147  : AbsFunction()
148  , m_function( function.clone() )
150  , m_index( index )
151  , m_a( GSL_NEGINF ) // should not be used!
152  , m_limit( limit )
156  , m_epsabs( epsabs )
157  , m_epsrel( epsrel )
158  , m_size( size )
160  if ( m_index >= m_DIM ) { Exception( "::constructor: invalid variable index" ); }
161  }
162  // ========================================================================
163 
164  // ========================================================================
166  // ========================================================================
168  : AbsFunction()
169  , m_function( right.m_function->clone() )
170  , m_DIM( right.m_DIM )
171  , m_index( right.m_index )
172  , m_a( right.m_a )
173  , m_limit( right.m_limit )
174  , m_type( right.m_type )
175  , m_category( right.m_category )
176  , m_rule( right.m_rule )
177  , m_points( right.m_points )
178  , m_epsabs( right.m_epsabs )
179  , m_epsrel( right.m_epsrel )
180  , m_size( right.m_size )
181  , m_argument( right.m_argument ) {}
182  // ========================================================================
183 
184  // ========================================================================
185  // throw the exception
186  // ========================================================================
188  throw GaudiException( "NumericalIndefiniteIntegral::" + message, "*GaudiMath*", sc );
189  return sc;
190  }
191  // ========================================================================
192 
193  // ========================================================================
195  // ========================================================================
196  double NumericalIndefiniteIntegral::operator()( const double argument ) const {
197  // reset the result and the error
198  m_result = GSL_NEGINF;
199  m_error = GSL_POSINF;
200 
201  // check the argument
202  if ( 1 != m_DIM ) { Exception( "operator(): invalid argument size " ); };
203 
204  m_argument[0] = argument;
205  return ( *this )( m_argument );
206  }
207  // ========================================================================
208 
209  // ========================================================================
211  // ========================================================================
213  if ( idx >= m_DIM ) { Exception( "::partial(i): invalid variable index " ); };
214  if ( idx != m_index ) {
215  const AbsFunction& aux = NumericalDerivative( *this, idx );
216  return Genfun::FunctionNoop( &aux );
218  const AbsFunction& aux = -1 * function();
219  return Genfun::FunctionNoop( &aux );
220  }
221  const AbsFunction& aux = function();
222  return Genfun::FunctionNoop( &aux );
223  }
224 
225  // ========================================================================
227  // ========================================================================
228  double NumericalIndefiniteIntegral::operator()( const Argument& argument ) const {
229  // reset the result and the error
230  m_result = GSL_NEGINF;
231  m_error = GSL_POSINF;
232 
233  // check the argument
234  if ( argument.dimension() != m_DIM ) { Exception( "operator(): invalid argument size " ); };
235 
236  // copy the argument
237  for ( size_t i = 0; i < m_DIM; ++i ) { m_argument[i] = argument[i]; }
238 
239  // create the helper object
241 
242  // use GSL to evaluate the numerical derivative
243  gsl_function F;
244  F.function = &GSL_Adaptor;
245  F.params = &helper;
246  _Function F1;
247  F1.fn = &F;
248 
249  switch ( category() ) {
251  return QAGI( &F1 );
253  return QAGP( &F1 );
255  switch ( type() ) {
257  return QNG( &F1 );
259  return QAG( &F1 );
261  return QAGS( &F1 );
262  default:
263  Exception( "::operator(): invalid type " );
264  }
265  break;
266  default:
267  Exception( "::operator(): invalid category " );
268  }
269  return 0;
270  }
271  // ========================================================================
272 
273  // ========================================================================
275  // ========================================================================
277  if ( !m_ws ) {
278  m_ws.reset( new _Workspace() );
279  m_ws->ws = gsl_integration_workspace_alloc( size() );
280  if ( !m_ws->ws ) { Exception( "allocate()::invalid workspace" ); };
281  }
282  return m_ws.get();
283  }
284  // ========================================================================
285 
286  // ========================================================================
287  // adaptive integration on infinite interval
288  // ========================================================================
290  // check the argument
291  if ( !F ) { Exception( "::QAGI: invalid function" ); }
292 
293  const double x = m_argument[m_index];
294 
295  // allocate workspace
296  allocate();
297 
298  int ierror = 0;
299  switch ( limit() ) {
301  ierror = gsl_integration_qagiu( F->fn, x, m_epsabs, m_epsrel, size(), ws()->ws, &m_result, &m_error );
302  break;
304  ierror = gsl_integration_qagil( F->fn, x, m_epsabs, m_epsrel, size(), ws()->ws, &m_result, &m_error );
305  break;
306  default:
307  Exception( "::QAGI: invalid mode" );
308  };
309 
310  if ( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGI", __FILE__, __LINE__, ierror ); }
311 
312  return m_result;
313  }
314  // ========================================================================
315 
316  // ========================================================================
317  // adaptive integration with known singular points
318  // ========================================================================
320  if ( !F ) { Exception( "QAGP::invalid function" ); }
321 
322  const double x = m_argument[m_index];
323  if ( m_a == x ) {
324  m_result = 0;
325  m_error = 0; // EXACT !
326  return m_result;
327  }
328 
329  // no known singular points ?
330  if ( points().empty() ) { return QAGS( F ); }
331 
332  // integration limits
333  const auto limits = std::minmax( m_a, x );
334 
335  // "active" singular points
336  auto lower = std::lower_bound( points().begin(), points().end(), limits.first );
337  auto upper = std::upper_bound( points().begin(), points().end(), limits.second );
338 
339  Points pnts;
340  pnts.reserve( std::distance( lower, upper ) );
341  std::copy( lower, upper, std::back_inserter( pnts ) );
342  if ( *lower != limits.first ) { pnts.insert( pnts.begin(), limits.first ); }
343  if ( *upper != limits.second ) { pnts.insert( pnts.end(), limits.second ); }
344 
345  // use GSL
346  int ierror = gsl_integration_qagp( F->fn, pnts.data(), pnts.size(), m_epsabs, m_epsrel, size(), ws()->ws,
347  &m_result, &m_error );
348 
349  if ( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGI ", __FILE__, __LINE__, ierror ); }
350 
351  // sign
353  m_result *= -1;
354  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
355  m_result *= -1;
356  }
357 
358  return m_result;
359  }
360  // ========================================================================
361 
362  // ========================================================================
363  // non-adaptive integration
364  // ========================================================================
366  if ( !F ) { Exception( "QNG::invalid function" ); }
367 
368  const double x = m_argument[m_index];
369  if ( m_a == x ) {
370  m_result = 0;
371  m_error = 0; // EXACT !
372  return m_result;
373  }
374 
375  // integration limits
376  const double a = std::min( m_a, x );
377  const double b = std::max( m_a, x );
378 
379  size_t neval = 0;
380  int ierror = gsl_integration_qng( F->fn, a, b, m_epsabs, m_epsrel, &m_result, &m_error, &neval );
381 
382  if ( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QNG ", __FILE__, __LINE__, ierror ); }
383 
384  // sign
386  m_result *= -1;
387  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
388  m_result *= -1;
389  }
390 
391  return m_result;
392  }
393 
394  // ========================================================================
395  // simple adaptive integration
396  // ========================================================================
398  if ( !F ) { Exception( "QAG::invalid function" ); }
399 
400  const double x = m_argument[m_index];
401  if ( m_a == x ) {
402  m_result = 0;
403  m_error = 0; // EXACT !
404  return m_result;
405  }
406 
407  // allocate workspace
408  allocate();
409 
410  // integration limits
411  const auto limits = std::minmax( m_a, x );
412 
413  int ierror = gsl_integration_qag( F->fn, limits.first, limits.second, m_epsabs, m_epsrel, size(), (int)rule(),
414  ws()->ws, &m_result, &m_error );
415 
416  if ( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAG ", __FILE__, __LINE__, ierror ); }
417 
418  // sign
420  m_result *= -1;
421  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
422  m_result *= -1;
423  }
424 
425  return m_result;
426  }
427  // ========================================================================
428 
429  // ========================================================================
430  // adaptive integration with singularities
431  // ========================================================================
433  if ( !F ) { Exception( "QAG::invalid function" ); }
434 
435  const double x = m_argument[m_index];
436  if ( m_a == x ) {
437  m_result = 0;
438  m_error = 0; // EXACT !
439  return m_result;
440  }
441 
442  // allocate workspace
443  allocate();
444 
445  // integration limits
446  const auto limits = std::minmax( m_a, x );
447 
448  int ierror = gsl_integration_qags( F->fn, limits.first, limits.second, m_epsabs, m_epsrel, size(), ws()->ws,
449  &m_result, &m_error );
450 
451  if ( ierror ) { gsl_error( "NumericalIndefiniteIntegral::QAGS ", __FILE__, __LINE__, ierror ); }
452 
453  // sign
455  m_result *= -1;
456  } else if ( GaudiMath::Integration::VariableLowLimit == limit() && x > m_a ) {
457  m_result *= -1;
458  }
459 
460  return m_result;
461  }
462  // ========================================================================
463  } // end of namespace GaudiMathImplementation
464 } // end of namespace Genfun
465 
466 // ============================================================================
467 // The END
468 // ============================================================================
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:26
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:50
_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:22
T erase(T...args)
double GSL_Adaptor(double x, void *params)
Definition: Helpers.cpp:25
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:20
GaudiMath.h GaudiMath/GaudiMath.h.
Definition: Adapters.h:13
KronrodRule
integration rule
Definition: Integration.h:26
T sort(T...args)
CLHEP.
Definition: IEqSolver.h:13
AttribStringParser::Iterator begin(const AttribStringParser &parser)
the simple structure to be used for adaption interface Genfun::AbsFunction to gsl_function structure ...
Definition: Helpers.h:23
T reserve(T...args)
collection of common types for classes NumericalIndefiniteIntegral and NumericalDefiniteIntegral ...