Integrator.h
Go to the documentation of this file.
1 #ifndef _utl_Integrator_h_
2 #define _utl_Integrator_h_
3 
4 #include <utl/PolynomialInterpolation.h>
5 #include <utl/ErrorLogger.h>
6 
7 #include <vector>
8 
9 
10 namespace utl {
11 
71  template<class Functor>
72  class Integrator {
73 
74  public:
75  Integrator(Functor& functor, const double accuracy = 1e-5)
76  : fFunctor(functor), fAccuracy(accuracy) { }
77 
79  void SetAccuracy(const double accuracy) { fAccuracy = accuracy; }
80 
82  double GetIntegral(const double a, const double b) const
83  { return GetRombergIntegral(a, b); }
84 
88  double
89  GetRombergIntegral(const double a, const double b,
90  const int order = 5, const int maxIterations = 20)
91  const
92  {
93  const double delta = b - a;
94 
95  std::vector<double> tInt(maxIterations+1);
96  std::vector<double> tStep(maxIterations+1);
97  double oldInt = tInt[0] = GetBoxAverage(a, delta, 2);
98  tStep[0] = delta;
99  int i;
100  for (i = 1; i < order; ++i) {
101  oldInt = tInt[i] = GetTrapezoidalAverage(oldInt, a, delta, i);
102  tStep[i] = delta / (1 << (2*i)); // h^2
103  }
104 
105  const double eps = 0.5*fAccuracy;
106  double extrapolation = 1e10;
107  for ( ; i <= maxIterations; ++i) {
108  oldInt = tInt[i] = GetTrapezoidalAverage(oldInt, a, delta, i);
109  tStep[i] = delta / (1 << (2*i)); // extrapolate h^2 dependence for h->0
110  const int first = i - order + 1;
111  double residual = 0;
112  extrapolation =
113  PolynomialInterpolation(order, &tStep[first], &tInt[first], 0, residual);
114  if (fabs(residual) <= eps*fabs(extrapolation))
115  return delta*extrapolation;
116  }
117  if (fabs(extrapolation) > fAccuracy)
118  WARNING("Maximal level limit reached, result is not accurate.");
119  return delta*extrapolation;
120  }
121 
123  double
124  GetSimpsonIntegral(const double a, const double b,
125  const int minLevel = 4, const int maxLevel = 20)
126  const
127  {
128  const double delta = b - a;
129  double trapezAverage = GetBoxAverage(a, delta, 2);
130 
131  int level;
132  for (level = 1; level < minLevel; ++level)
133  trapezAverage = GetTrapezoidalAverage(trapezAverage, a, delta, level);
134 
135  double trapezOld = trapezAverage;
136  trapezAverage = GetTrapezoidalAverage(trapezAverage, a, delta, level++);
137  double simpsonOld = (4./3)*trapezAverage - (1./3)*trapezOld;
138 
139  for ( ; level <= maxLevel; ++level) {
140  trapezOld = trapezAverage;
141  trapezAverage = GetTrapezoidalAverage(trapezAverage, a, delta, level);
142  const double simpsonAverage = (4./3)*trapezAverage - (1./3)*trapezOld;
143  if (fabs(simpsonAverage - simpsonOld) < fAccuracy*fabs(simpsonAverage) ||
144  (!simpsonAverage && !simpsonOld))
145  return delta*simpsonAverage;
146  simpsonOld = simpsonAverage;
147  }
148  if (fabs(simpsonOld) > fAccuracy)
149  WARNING("Maximal level limit reached, result is not accurate.");
150  return delta*simpsonOld;
151  }
152 
154  double
155  GetTrapezoidalIntegral(const double a, const double b,
156  const int minLevel = 4, const int maxLevel = 20)
157  const
158  {
159  const double delta = b - a;
160  double average = GetBoxAverage(a, delta, 2);
161  int level;
162  for (level = 1; level <= minLevel; ++level)
163  average = GetTrapezoidalAverage(average, a, delta, level);
164  for ( ; level <= maxLevel; ++level) {
165  const double old = average;
166  average = GetTrapezoidalAverage(average, a, delta, level);
167  if (fabs(average - old) < fAccuracy*fabs(average) || (!average && !old))
168  return delta*average;
169  }
170  if (fabs(average) > fAccuracy)
171  WARNING("Maximal level limit reached, result is not accurate.");
172  return delta*average;
173  }
174 
175  private:
202  double
203  GetTrapezoidalAverage(const double previousApproximation,
204  const double a, const double delta, const int level)
205  const
206  {
207  const int n = 1 << (level - 1);
208  const double step = delta/n;
209  return 0.5*(previousApproximation +
210  GetBoxAverage(a+0.5*step, step, n));
211  }
212 
214  double
215  GetBoxAverage(const double start, const double step, const int n)
216  const
217  {
218  double sum = 0;
219  for (int i = 0; i < n; ++i) {
220  const double x = start + i*step;
221  sum += fFunctor(x);
222  }
223  return sum/n;
224  }
225 
226  Functor& fFunctor;
227  double fAccuracy;
228 
229  };
230 
231 
233  template<class Functor>
234  inline
236  MakeIntegrator(Functor& f)
237  {
238  return Integrator<Functor>(f);
239  }
240 
241 
242  template<class Functor, unsigned int dim>
244 
245  public:
246  VectorIntegrator(Functor& functor, const double accuracy = 1e-5)
247  : fFunctor(functor), fAccuracy(accuracy) { }
248 
250  void SetAccuracy(const double accuracy) { fAccuracy = accuracy; }
251 
253  void
254  GetIntegral(double* const result, const double a, const double b,
255  const int order = 5, const int maxIterations = 20)
256  const
257  {
258  for (unsigned int k = 0; k < dim; ++k)
259  result[k] = 0;
260 
261  const double delta = b - a;
262 
263  std::vector<double> tInt[dim];
264  for (unsigned int k = 0; k < dim; ++k)
265  tInt[k].resize(maxIterations+1);
266  std::vector<double> tStep(maxIterations+1);
267  double oldInt[dim];
268  GetBoxAverage(oldInt, a, delta, 2);
269  for (unsigned int k = 0; k < dim; ++k)
270  tInt[k][0] = oldInt[k];
271  tStep[0] = delta;
272  int i;
273  for (i = 1; i < order; ++i) {
274  GetTrapezoidalAverage(oldInt, a, delta, i);
275  for (unsigned int k = 0; k < dim; ++k)
276  tInt[k][i] = oldInt[k];
277  tStep[i] = delta / (1 << (2*i)); // h^2
278  }
279 
280  const double eps = 0.5*fAccuracy;
281  for (unsigned int k = 0; k < dim; ++k)
282  result[k] = 0;
283  for ( ; i <= maxIterations; ++i) {
284  GetTrapezoidalAverage(oldInt, a, delta, i);
285  for (unsigned int k = 0; k < dim; ++k)
286  tInt[k][i] = oldInt[k];
287  tStep[i] = delta / (1 << (2*i)); // extrapolate h^2 dependence for h->0
288  const int first = i - order + 1;
289 
290  unsigned int nAccepted = 0;
291  for (unsigned int k = 0; k < dim; ++k) {
292  double residual = 0;
293  result[k] =
294  PolynomialInterpolation(order, &tStep[first], &tInt[k][first], 0, residual);
295  if (fabs(residual) <= eps*fabs(result[k]))
296  ++nAccepted;
297  }
298  if (nAccepted == dim) {
299  for (unsigned int k = 0; k < dim; ++k)
300  result[k] *= delta;
301  return;
302  }
303  }
304 
305  WARNING("Maximal level limit reached, result is not accurate.");
306  for (unsigned int k = 0; k < dim; ++k)
307  result[k] *= delta;
308  }
309 
310  private:
311  void
312  GetTrapezoidalAverage(double* const previousApproximation,
313  const double a, const double delta, const int level)
314  const
315  {
316  const int n = 1 << (level - 1);
317  const double step = delta/n;
318  double add[dim];
319  GetBoxAverage(add, a+0.5*step, step, n);
320  for (unsigned int k = 0; k < dim; ++k)
321  previousApproximation[k] = 0.5*(previousApproximation[k] + add[k]);
322  }
323 
325  void
326  GetBoxAverage(double* const sum, const double start, const double step, const int n)
327  const
328  {
329  for (unsigned int k = 0; k < dim; ++k)
330  sum[k] = 0;
331 
332  double result[dim];
333  for (int i = 0; i < n; ++i) {
334  const double x = start + i*step;
335  fFunctor(result, x);
336  for (unsigned int k = 0; k < dim; ++k)
337  sum[k] += result[k];
338  }
339 
340  for (unsigned int k = 0; k < dim; ++k)
341  sum[k] /= n;
342  }
343 
344  Functor& fFunctor;
345  double fAccuracy;
346 
347  };
348 
349 }
350 
351 
352 #endif
void SetAccuracy(const double accuracy)
final accuracy goal of the integration
Definition: Integrator.h:250
return sum n
Definition: Integrator.h:223
double GetTrapezoidalAverage(const double previousApproximation, const double a, const double delta, const int level) const
Calculates succsessive approximations to the function average.
Definition: Integrator.h:203
Class for integration of functions with one independent parameter.
Definition: Integrator.h:72
void GetTrapezoidalAverage(double *const previousApproximation, const double a, const double delta, const int level) const
Definition: Integrator.h:312
double GetTrapezoidalIntegral(const double a, const double b, const int minLevel=4, const int maxLevel=20) const
basic trapezoidal integration
Definition: Integrator.h:155
void GetIntegral(double *const result, const double a, const double b, const int order=5, const int maxIterations=20) const
Romberg integration, for details see utl::Integrator.
Definition: Integrator.h:254
double fAccuracy
Definition: Integrator.h:227
Integrator(Functor &functor, const double accuracy=1e-5)
Definition: Integrator.h:75
double GetSimpsonIntegral(const double a, const double b, const int minLevel=4, const int maxLevel=20) const
Simpson improvement build on top of the trapezoidal integration.
Definition: Integrator.h:124
Functor & fFunctor
Definition: Integrator.h:226
void SetAccuracy(const double accuracy)
final accuracy goal of the integration
Definition: Integrator.h:79
double GetIntegral(const double a, const double b) const
call this method when you do not care about the specific implementation
Definition: Integrator.h:82
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
double eps
double result[dim]
Definition: Integrator.h:332
VectorIntegrator(Functor &functor, const double accuracy=1e-5)
Definition: Integrator.h:246
double PolynomialInterpolation(const unsigned int n, const double px[], const double py[], const double x, double &dy)
Perform polynomial interpolation or extrapolation.
Integrator< Functor > MakeIntegrator(Functor &f)
convenience factory
Definition: Integrator.h:236
double GetRombergIntegral(const double a, const double b, const int order=5, const int maxIterations=20) const
Romberg integration Setting order to 2 is equivalent to the Simpson&#39;s method.
Definition: Integrator.h:89

, generated on Tue Sep 26 2023.