RK5ODEIntegrator.h
Go to the documentation of this file.
1 #ifndef _utl_RK5ODEIntegrator_h_
2 #define _utl_RK5ODEIntegrator_h_
3 
4 #include <cmath>
5 
6 
7 namespace utl {
8 
10  public:
11  template<class VectorType>
12  void
13  operator()(const unsigned int n, const double dx,
14  const VectorType& y, const VectorType& dYdX,
15  VectorType& errorScaling)
16  const
17  {
18  for (unsigned int i = 0; i < n; ++i)
19  errorScaling[i] = std::abs(y[i]) + std::abs(dx*dYdX[i]) + 1e-30;
20  }
21  };
22 
23 
35  template<class DerivativeFunctor, class VectorType>
36  class RK5Iterator {
37  public:
38  RK5Iterator(const double x, const VectorType& y,
39  DerivativeFunctor& d)
40  : fX(x), fDerivativeFunctor(d), fStatus(true)
41  {
42  Copy(d, y, fY);
43  Clear(d, fYError);
44  }
45 
46  double GetX() const { return fX; }
47 
48  VectorType& GetY() { return fY; }
49 
50  const VectorType& GetY() const { return fY; }
51 
52  const VectorType& GetYError() const { return fYError; }
53 
54  bool
55  Advance(const double dx, const VectorType& dYdX)
56  {
57  if (Step(dx, fY, dYdX)) {
58  fX += dx;
59  return fStatus = true;
60  }
61  return fStatus = false;
62  }
63 
64  bool
65  Advance(const double dx)
66  {
67  VectorType dYdX;
68  fDerivativeFunctor(fX, fY, dYdX);
69  return Advance(dx, dYdX);
70  }
71 
72  RK5Iterator& operator+=(const double dx)
73  { Advance(dx); return *this; }
74 
75  RK5Iterator& operator-=(const double dx)
76  { Advance(-dx); return *this; }
77 
78  DerivativeFunctor& GetDerivativeFunctor()
79  { return fDerivativeFunctor; }
80 
81  explicit operator bool() const { return fStatus; }
82 
83  void ClearStatus() { fStatus = true; }
84 
85  private:
86  bool
87  Step(const double dx, VectorType& yNew, const VectorType& dYdX)
88  {
89  const unsigned int n = fDerivativeFunctor;
90  VectorType y1;
91  VectorType dYdXt[5];
92  for (unsigned int k = 0; k < 5; ++k) {
93  for (unsigned int i = 0; i < n; ++i) {
94  double dy = fB[k][0] * dYdX[i];
95  for (unsigned int j = 1; j <= k; ++j)
96  dy += fB[k][j] * dYdXt[j-1][i];
97  y1[i] = fY[i] + dx * dy;
98  }
99  if (!fDerivativeFunctor(fX + fA[k] * dx, y1, dYdXt[k]))
100  return fStatus = false;
101  }
102  for (unsigned int i = 0; i < n; ++i) {
103  double dy = fC[0] * dYdX[i];
104  double de = fD[0] * dYdX[i];
105  for (unsigned int j = 1; j < 5; ++j) {
106  dy += fC[j] * dYdXt[j][i];
107  de += fD[j] * dYdXt[j][i];
108  }
109  yNew[i] = fY[i] + dx * dy;
110  fYError[i] = dx * de;
111  }
112  return fStatus = true;
113  }
114 
115  static
116  void
117  Copy(const unsigned int n, const VectorType& a, VectorType& b)
118  {
119  for (unsigned int i = 0; i < n; ++i)
120  b[i] = a[i];
121  }
122 
123  static
124  void
125  Clear(const unsigned int n, VectorType& b)
126  {
127  for (unsigned int i = 0; i < n; ++i)
128  b[i] = 0;
129  }
130 
131  double fX;
132  VectorType fY;
133  VectorType fYError;
134  DerivativeFunctor& fDerivativeFunctor;
135  bool fStatus;
136 
137  // constants
138  static const double fA[6];
139  static const double fB[5][5];
140  static const double fC[5];
141  static const double fD[5];
142 
143  template<class A, class B, class C>
144  friend class AdaptiveRK5Iterator;
145  };
146 
147  template<class DerivativeFunctor, class VectorType>
149  0.2, 0.3, 0.6, 1, 0.875
150  };
151 
152  template<class DerivativeFunctor, class VectorType>
153  const double RK5Iterator<DerivativeFunctor, VectorType>::fB[][5] = {
154  { 0.2 },
155  { 0.075, 0.225 },
156  { 0.3, -0.9, 1.2 },
157  { -11./54, 2.5, -70./27, 35./27 },
158  { 1631./55296, 175./512, 575./13824, 44275./110592, 253./4096 }
159  };
160 
161  template<class DerivativeFunctor, class VectorType>
162  const double RK5Iterator<DerivativeFunctor, VectorType>::fC[] = {
163  37./378, 250./621, 125./594, 0, 512./1771
164  };
165 
166  template<class DerivativeFunctor, class VectorType>
167  const double RK5Iterator<DerivativeFunctor, VectorType>::fD[] = {
168  RK5Iterator<DerivativeFunctor, VectorType>::fC[0] - 2825./27648,
169  RK5Iterator<DerivativeFunctor, VectorType>::fC[1] - 18575./48384,
170  RK5Iterator<DerivativeFunctor, VectorType>::fC[2] - 13525./55296,
171  RK5Iterator<DerivativeFunctor, VectorType>::fC[3] - 277./14336,
172  RK5Iterator<DerivativeFunctor, VectorType>::fC[4] - 0.25
173  };
174 
175 
188  template<class DerivativeFunctor,
189  class VectorType,
190  class ErrorScalingPolicy = DefaultRK5ErrorScaling>
192  public:
193  AdaptiveRK5Iterator(const double x0, const double dx0,
194  const VectorType& y0,
195  DerivativeFunctor& d,
196  const double accuracy = 1e-5,
197  const ErrorScalingPolicy& errorScaling =
199  fIterator(x0, y0, d),
200  fNextStepSize(dx0),
201  fAccuracy(accuracy),
202  fErrorScaling(errorScaling)
203  { }
204 
205  AdaptiveRK5Iterator(const double dx0,
207  const double accuracy = 1e-5,
208  const ErrorScalingPolicy& errorScaling =
210  fIterator(rk5It),
211  fNextStepSize(dx0),
212  fAccuracy(accuracy),
213  fErrorScaling(errorScaling)
214  { }
215 
216  double GetX() const { return fIterator.fX; }
217 
218  VectorType& GetY() { return fIterator.fY; }
219 
220  const VectorType& GetY() const { return fIterator.fY; }
221 
222  const VectorType& GetYError() const { return fIterator.fYError; }
223 
224  bool
225  Advance(const double dx)
226  {
227  double& x = fIterator.fX;
228  VectorType& y = fIterator.fY;
229  VectorType& yError = fIterator.fYError;
230  const unsigned int n = fIterator.GetDerivativeFunctor();
231 
232  VectorType dYdX;
233  fIterator.GetDerivativeFunctor()(x, y, dYdX);
234  VectorType y1;
235  double dxAttempt = dx;
236  double x1 = x + dxAttempt;
237  VectorType scaling;
238  fErrorScaling(n, dx, y, dYdX, scaling);
239  double relErr;
240  while (true) {
241  double stepFactor = 0.1;
242  if (fIterator.Step(dxAttempt, y1, dYdX)) {
243  relErr = GetMaxScaledError(n, yError, scaling) / fAccuracy;
244  if (relErr < 1)
245  break;
246  stepFactor = std::max(0.1, fSlightlyLess * std::pow(relErr, fPowerDown));
247  }
248  dxAttempt *= stepFactor;
249  x1 = x + dxAttempt;
250  if (x1 == x) {
251  fNextStepSize = dx;
252  return fIterator.fStatus = false;
253  }
254  }
255  fNextStepSize = dxAttempt *
256  ((relErr > fPowerLawThreshold) ? fSlightlyLess * std::pow(relErr, fPowerUp) : 5);
257  x = x1;
258  fIterator.Copy(n, y1, y);
259  return fIterator.fStatus = true;
260  }
261 
262  bool Advance() { return Advance(fNextStepSize); }
263 
264  AdaptiveRK5Iterator& operator+=(const double dx)
265  { Advance(dx); return *this; }
266 
267  AdaptiveRK5Iterator& operator-=(const double dx)
268  { Advance(-dx); return *this; }
269 
271  { Advance(); return *this; }
272 
273  double GetNextStepSize() const { return fNextStepSize; }
274 
275  void ClearStatus() { fIterator.ClearStatus(); }
276 
277  explicit operator bool() const { return fIterator; }
278 
279  private:
280  static
281  double
282  GetMaxScaledError(const unsigned int n,
283  const VectorType& error, const VectorType& scaling)
284  {
285  double max = std::abs(error[0] / scaling[0]);
286  for (unsigned int i = 1; i < n; ++i) {
287  const double se = std::abs(error[i] / scaling[i]);
288  if (se > max)
289  max = se;
290  }
291  return max;
292  }
293 
296  double fAccuracy;
297  const ErrorScalingPolicy& fErrorScaling;
298 
299  static const double fPowerUp;
300  static const double fPowerDown;
301  static const double fSlightlyLess;
302  static const double fPowerLawThreshold;
303  };
304 
305  template<
306  class DerivativeFunctor,
307  class VectorType,
308  class ErrorScalingPolicy
309  > const double AdaptiveRK5Iterator<
310  DerivativeFunctor,
311  VectorType,
312  ErrorScalingPolicy
313  >::fPowerUp = -0.2;
314 
315  template<
316  class DerivativeFunctor,
317  class VectorType,
318  class ErrorScalingPolicy
319  > const double AdaptiveRK5Iterator<
320  DerivativeFunctor,
321  VectorType,
322  ErrorScalingPolicy
323  >::fPowerDown = -0.25;
324 
325  template<
326  class DerivativeFunctor,
327  class VectorType,
328  class ErrorScalingPolicy
329  > const double AdaptiveRK5Iterator<
330  DerivativeFunctor,
331  VectorType,
332  ErrorScalingPolicy
333  >::fSlightlyLess = 0.9;
334 
335  template<
336  class DerivativeFunctor,
337  class VectorType,
338  class ErrorScalingPolicy
339  > const double AdaptiveRK5Iterator<
340  DerivativeFunctor,
341  VectorType,
342  ErrorScalingPolicy
343  >::fPowerLawThreshold = 1.889568e-4;
344 
345 
406  template<class DerivativeFunctor>
408  public:
409  RK5ODEIntegrator(DerivativeFunctor& d)
410  : fDerivativeFunctor(d) { }
411 
412  template<class VectorType>
414  Begin(const double x, const VectorType& y)
415  {
416  return
418  <DerivativeFunctor, VectorType>(x, y, fDerivativeFunctor);
419  }
420 
421  template<class VectorType>
423  AdaptiveBegin(const double x, const double dx, const VectorType& y,
424  const double accuracy = 1e-5)
425  {
426  return
428  x, dx, y, fDerivativeFunctor, accuracy
429  );
430  }
431 
432  template<class VectorType,
433  class ErrorScalingPolicy>
435  AdaptiveBegin(const double x, const double dx, const VectorType& y,
436  const double accuracy, ErrorScalingPolicy& es)
437  {
438  return
440  x, dx, y, fDerivativeFunctor, accuracy, es
441  );
442  }
443 
444  DerivativeFunctor& GetDerivativeFunctor()
445  { return fDerivativeFunctor; }
446 
447  private:
448  DerivativeFunctor& fDerivativeFunctor;
449  };
450 
451 }
452 
453 
454 #endif
AdaptiveRK5Iterator & operator+=(const double dx)
AdaptiveRK5Iterator< DerivativeFunctor, VectorType, ErrorScalingPolicy > AdaptiveBegin(const double x, const double dx, const VectorType &y, const double accuracy, ErrorScalingPolicy &es)
DerivativeFunctor & fDerivativeFunctor
const VectorType & GetY() const
static const double fPowerLawThreshold
bool Step(const double dx, VectorType &yNew, const VectorType &dYdX)
const ErrorScalingPolicy & fErrorScaling
AdaptiveRK5Iterator(const double x0, const double dx0, const VectorType &y0, DerivativeFunctor &d, const double accuracy=1e-5, const ErrorScalingPolicy &errorScaling=DefaultRK5ErrorScaling())
AdaptiveRK5Iterator & operator-=(const double dx)
VectorType & GetY()
static const double fB[5][5]
static const double fA[6]
RK5Iterator< DerivativeFunctor, VectorType > Begin(const double x, const VectorType &y)
RK5Iterator(const double x, const VectorType &y, DerivativeFunctor &d)
double pow(const double x, const unsigned int i)
double GetX() const
#define max(a, b)
static const double fPowerUp
RK5Iterator & operator-=(const double dx)
double abs(const SVector< n, T > &v)
AdaptiveRK5Iterator & operator++()
double GetNextStepSize() const
DerivativeFunctor & GetDerivativeFunctor()
DerivativeFunctor & fDerivativeFunctor
static double GetMaxScaledError(const unsigned int n, const VectorType &error, const VectorType &scaling)
static const double fPowerDown
const VectorType & GetYError() const
static const double fSlightlyLess
const VectorType & GetYError() const
AdaptiveRK5Iterator< DerivativeFunctor, VectorType > AdaptiveBegin(const double x, const double dx, const VectorType &y, const double accuracy=1e-5)
DerivativeFunctor & GetDerivativeFunctor()
void operator()(const unsigned int n, const double dx, const VectorType &y, const VectorType &dYdX, VectorType &errorScaling) const
static void Clear(const unsigned int n, VectorType &b)
RK5Iterator< DerivativeFunctor, VectorType > fIterator
bool Advance(const double dx, const VectorType &dYdX)
AdaptiveRK5Iterator(const double dx0, const RK5Iterator< DerivativeFunctor, VectorType > &rk5It, const double accuracy=1e-5, const ErrorScalingPolicy &errorScaling=DefaultRK5ErrorScaling())
static const double fC[5]
bool Advance(const double dx)
RK5Iterator & operator+=(const double dx)
static const double fD[5]
bool Advance(const double dx)
static void Copy(const unsigned int n, const VectorType &a, VectorType &b)
RK5ODEIntegrator(DerivativeFunctor &d)
const VectorType & GetY() const

, generated on Tue Sep 26 2023.