All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
RunKutODESolver.h
Go to the documentation of this file.
1 #ifndef RUNKUTODESOLVER_H
2 #define RUNKUTODESOLVER_H 1
3 
4 #include <cstdlib>
5 #include <math.h>
6 #include "Colours.h"
7 
8 // Include Marlin
9 #include <streamlog/streamlog.h>
10 
11 /**
12 \addtogroup SiStripDigi SiStripDigi
13 @{
14 */
15 
16 namespace sistrip {
17 
18 #define MAXSTEPS 1000
19 #define FCE2(x,y) (_pTemplate->*_fce)(x,y)
20 
21 //! Double precision first-order ODE (IVP, i.e. initial-value problem) solver,
22 //! that utilizes 4th order Runge-Kutta algorithm with or without adaptive
23 //! control of its stepsize or so-called 5th(4th) order Runge-Kutta-Fehlberg
24 //! algorithm with adaptive control of its stepsize (The template class represents
25 //! class whose method corresponds to a right-hand side FCE2(x,y) of the ODE,
26 //! defined as dy/dx = FCE2(x,y)!). The template class doesn't have *.cpp file!
27 //!
28 //! @see RKCSolve
29 //! @see RKFSolve
30 //! @see _eps
31 //!
32 //! @author Z. Drasal, Charles University Prague
33 //!
34 
35 template <class T> class RunKutODESolver {
36 
37  public:
38 
39 //!Constructor - sets ODE right-hand side and required absolut accumulated precision
40  RunKutODESolver(double (T::* fce)(double, double), T* pTemplate, float eps) :
41  _fce(fce), _pTemplate(pTemplate), _eps(eps) {;}
42 
43 //!Destructor
45 
46 //!This method returns a solution y(x) to the so-called ODE initial value problem
47 //!(IVP), using 4th order Runge-Kutta method. Where IVP is defined as follows:
48 //!
49 //! &nbsp;&nbsp; y' = dy/dx = f(x,y) with initial condition f(x0) = y0
50 //!
51 //! Calculation (w(x,h) corresponds to the best approximation of y(x)):
52 //!
53 //! &nbsp;&nbsp; w_0 = y0
54 //!
55 //! &nbsp;&nbsp; for i = 0,1,2 ... (i-th step) <br>
56 //! &nbsp;&nbsp; w_i+1 = w_i + h*Phi(x_i,w_i;h;f) <br>
57 //! &nbsp;&nbsp; x_i+1 = x_i + h, x_0 = x0
58 //!
59 //! &nbsp;&nbsp; Euler method gives Phi(x,y;h;f) = f(x,y)
60 //!
61 //!This algorithm doesn't implement adaptive stepsize control, each stepsize is
62 //!calculated as relative precision * (x-xo). (Epsilon ~ 0.001, i.e 1000 iterations,
63 //!gives approximately good results.)
64 //!
65 //!For more details see J.Stoer, R.Bulirsch: Introduction to Numerical Analysis,
66 //!chap. 7, 3rd ed., and <a href=http://www.nr.com/oldverswitcher.html>www.nr.com</a>
67 //!
68  double RKSolve(double x0, double y0, double x);
69 
70 //!This method returns a solution y(x) to the so-called ODE initial value problem
71 //!(IVP), using 4th order Runge-Kutta method with adaptive stepsize control. The
72 //!stepsize control algorithm is performed as follows: first, an approximative
73 //!solution w(x0+h;h) using stepsize h is calculated and then is compared to the
74 //!solution w(x0+h;h/2), obtained in the same way, but using two consequent
75 //!stepsizes h/2. If the difference is not similar to the required epsilon,
76 //!then the ratio of a new proposed stepsize and the old stepsize must be much
77 //!bigger than 2 (i.e. take for example bigger or equal than 3), else it's
78 //!approximately equal to 2. Hence, in both cases the stepsize is set as 2 times
79 //!stepsize H, that corresponds to required precision, but in the first case, one
80 //!must perform the algorithm once again, while in the latter the approximative
81 //!solution w_i+1 and a stepsize for new iteration are found. The epsilon
82 //!corresponds to precision in each step!!! The IVP problem is defined as:
83 //!
84 //! &nbsp;&nbsp; y' = dy/dx = f(x,y) with initial condition f(x0) = y0
85 //!
86 //! Calculation (w(x,h) corresponds to the best approximation of y(x)):
87 //!
88 //! &nbsp;&nbsp; w_0 = y0
89 //!
90 //! &nbsp;&nbsp; for i = 0,1,2 ... (i-th step) <br>
91 //! &nbsp;&nbsp; w_i+1 = w_i + h*Phi(x_i,w_i;h;f) <br>
92 //! &nbsp;&nbsp; x_i+1 = x_i + h, x_0 = x0
93 //!
94 //! &nbsp;&nbsp; Euler method gives Phi(x,y;h;f) = f(x,y)
95 //!
96 //! Stepsize calculation (H denotes required stepsize, h current stepsize):
97 //!
98 //! &nbsp;&nbsp; h/H = (16/15*(|w_i+1(x_i+h;h) - w_i+1(x_i+h;h/2)|/eps))^0.20 <br>
99 //! &nbsp;&nbsp; if h/H >> 2 -> h = 2*H -> required precision not achieved -> stepsize recalculation <br>
100 //! &nbsp;&nbsp; if h/H ~ 2 -> h = 2*H -> required precision achieved -> use h for another iteration
101 //!
102 //!For more details see J.Stoer, R.Bulirsch: Introduction to Numerical Analysis,
103 //!chap. 7, 3rd ed., and <a href=http://www.nr.com/oldverswitcher.html>www.nr.com</a>
104 //!
105  double RKCSolve(double x0, double y0, double x, double hTry);
106 
107 //!This method returns a solution y(x) to the so-called ODE initial value problem
108 //!(IVP), using 5th(4th) order Runge-Kutta-Fehlberg method with adaptive stepsize
109 //!control. The stepsize control algorithm is performed as follows: first two
110 //!approximations to the exact solution w(x_i+1,h) (O(h6)) and v(x_i+1,h) (O(h5))
111 //!are calculated and then the difference proportional to h*C(x) is expressed
112 //!and used for calculation of a new stepsize, i.e. used as an estimate of the
113 //!error. Due to a fact that the required precision _eps represents an accumulated
114 //!error, permitted in maximum, C(x) is also dependent on h and thus expressed
115 //!in more complicated way (Two coefficients: 0.25 and 0.20 are used), see
116 //!Stepsize calculation. The IVP problem is defined as:
117 //!
118 //! &nbsp;&nbsp; y' = dy/dx = f(x,y) with initial condition f(x0) = y0
119 //!
120 //! Calculation (w(x,h), resp. v(x,h), correspond to the best approximation of y(x)):
121 //!
122 //! &nbsp;&nbsp; w_0 = y0 <br>
123 //! &nbsp;&nbsp; v_0 = y0
124 //!
125 //! &nbsp;&nbsp; for i = 0,1,2 ... (i-th step) <br>
126 //! &nbsp;&nbsp; w_i+1 = w_i + h*PhiI(x_i,w_i;h;f) <br>
127 //! &nbsp;&nbsp; v_i+1 = v_i + h*PhiII(x_i,w_i;h;f) <br>
128 //! &nbsp;&nbsp; x_i+1 = x_i + h, x_0 = x0
129 //!
130 //! Stepsize calculation (H denotes required stepsize, h current stepsize):
131 //!
132 //! &nbsp;&nbsp; fraction = |eps*h/(x - x0)/(h*PhiI - h*PhiII)| <br>
133 //! &nbsp;&nbsp; if fraction <= 1. -> reduce stepsize h = 0.9*h*fraction^0.25 <br>
134 //! &nbsp;&nbsp; if fraction > 1. -> increase stepsize h = 0.9*h*fraction^0.2
135 //!
136 //!For more details see J.Stoer, R.Bulirsch: Introduction to Numerical Analysis,
137 //!chap. 7, 3rd ed., and <a href=http://www.nr.com/oldverswitcher.html>www.nr.com</a>
138 //!
139  double RKFSolve( double x0, double y0, double x, double hTry);
140 
141  protected:
142 
143 //!This method based on 4th order Runge-Kutta algorithm returns an approximation
144 //!w(x_i+1,h) to the exact solution y(x_i+1) of the so-called initial value
145 //!problem (IVP) at position x_i+1 = x_i + h and using given "integration" stepsize
146 //!h, where the IVP is defined as y' = f(x,y), y(x0) = y0 and for equidistant
147 //!stepsizes h the coordinate x_i can be expressed as x_i = x0 + ih.
148 //!
149 //! General numerical algorithm for approximate values' calculation:
150 //!
151 //! &nbsp;&nbsp; w_0 = y0
152 //! &nbsp;&nbsp; w_i+1 = w_i + h*Phi(x_i,w_i;h;f)
153 //! &nbsp;&nbsp; x_i+1 = x_i + h, x_0 = x0
154 //!
155 //! &nbsp;&nbsp; Euler method gives Phi(x,y;h;f) = f(x,y)
156 //!
157 //! Calculation using Runge-Kutta algorithm:
158 //!
159 //! &nbsp;&nbsp; k1 = f(x_i, w_i)
160 //! &nbsp;&nbsp; k2 = f(x_i + h/2, w_i + h/2*k1)
161 //! &nbsp;&nbsp; k3 = f(x_i + h/2, w_i + h/2*k2)
162 //! &nbsp;&nbsp; k4 = f(x_i + h, w_i + h*k3)
163 //!
164 //! &nbsp;&nbsp; Phi(x_i,w_i;h;f) = 1/6*[k1 + 2*k2 + 2*k3 + k4]
165 //!
166 //!Parameters: position x_i, approximation w_i, stepsize h and evaluated righ-hand
167 //!side of the ODE dydx_i (It may be called more than once, thus given as param!)
168 //!
169 //!For more details see J.Stoer, R.Bulirsch: Introduction to Numerical Analysis,
170 //!chap. 7, 3rd ed., and <a href=http://www.nr.com/oldverswitcher.html>www.nr.com</a>
171 //!
172  double RK4Method(double x_i, double w_i, double h, double dydx_i);
173 
174 //!This method based on 5th(4th) order Runge-Kutta-Fehlberg algorithm returns
175 //!two approximations: w(x_i+1,h) (O(h6)) and v(x_i+1,h) (O(h5)), that approximate
176 //!the exact solution y(x_i+1) of given initial value problem (IVP) at position
177 //!x_i+1 = x_i + h and using an integration stepsize h. These approximative solutions
178 //!are effectively used, when controlling required precision. The difference is
179 //!proportional to h*C(x) and hence can be used to estimate an error and find
180 //!a more suitable stepsize H. Due to a fact, that different schemes can be used to
181 //!calculate w or v, we've chosen the one of Cash and Karp. The IVP is defined as
182 //!y' = f(x,y), y(x0) = y0.
183 //!
184 //! Rung-Kutta-Fehlberg algorithm for approximate values' calculation:
185 //!
186 //! &nbsp;&nbsp; w_0 = y0 <br>
187 //! &nbsp;&nbsp; v_0 = y0 <br>
188 //! &nbsp;&nbsp; w_i+1 = w_i + h*PhiI(x_i,w_i;h;f) <br>
189 //! &nbsp;&nbsp; v_i+1 = v_i + h*PhiII(x_i,w_i;h;f) <br>
190 //! &nbsp;&nbsp; x_i+1 = x_i + h, x_0 = x0
191 //!
192 //! &nbsp;&nbsp; PhiI(x_i,w_i;h;f) = Sum(k=0, 5){c_kI * f_k(x_i, w_i; h)} <br>
193 //! &nbsp;&nbsp; PhiII(x_i,w_i;h;f) = Sum(k=0, 5){c_kII * f_k(x_i, w_i; h)} <br>
194 //! &nbsp;&nbsp; f_k(x_i,w_i;h) = f(x_i + a_k*h, w_i + h * Sum(l=0, k-1){b_kl * f_l)
195 //!
196 //! &nbsp;&nbsp; a_k, b_kl, c_k ...... Cash-Karp parameters
197 //!
198 //! <table style="text-align: center">
199 //! <tr><td> k </td><td> a_k </td><td> b_k0 </td><td> b_k1 </td><td> b_k2 </td><td> b_k3 </td><td> b_k4 </td><td> c_kI </td><td> c_kII </td></tr>
200 //! <tr><td> 0 </td><td> 0 </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> 37/378 </td><td> 2825/27648 </td></tr>
201 //! <tr><td> 1 </td><td> 1/5 </td><td> 1/5 </td><td> </td><td> </td><td> </td><td> </td><td> 0 </td><td> 0 </td></tr>
202 //! <tr><td> 2 </td><td> 3/10 </td><td> 3/40 </td><td> 9/40 </td><td> </td><td> </td><td> </td><td> 250/621 </td><td> 18575/48384 </td></tr>
203 //! <tr><td> 3 </td><td> 3/5 </td><td> 3/10 </td><td> -9/10 </td><td> 6/5 </td><td> </td><td> </td><td> 125/594 </td><td> 13525/55296 </td></tr>
204 //! <tr><td> 4 </td><td> 1 </td><td> -11/54 </td><td> 5/2 </td><td> -70/27 </td><td> 35/27 </td><td> </td><td> 0 </td><td> 277/14336 </td></tr>
205 //! <tr><td> 5 </td><td> 7/8 </td><td> 1631/55296 </td><td> 175/512 </td><td> 575/13824 </td><td> 44275/110592 </td><td> 253/4096 </td><td> 512/1771 </td><td> 1/4 </td></tr>
206 //! </table>
207 //!
208 //!Parameters: position x_i, approximation w_i, stepsize h, evaluated righ-hand
209 //!side of the ODE dydx_i and estimated error between 5th and 4th order (i.e.
210 //!the difference between w_i+1 and v_i+1, defined as wDiff).
211 //!
212 //!For more details see J.Stoer, R.Bulirsch: Introduction to Numerical Analysis,
213 //!chap. 7, 3rd ed., and <a href=http://www.nr.com/oldverswitcher.html>www.nr.com</a>
214 //!
215  double RKFMethod(double x_i, double w_i, double h, double dydx_i, double * wDiffPointer);
216 
217 
218  double (T::* _fce)(double, double);//!< Relative pointer to an integrated function
219 
220  T * _pTemplate;//!< Pointer to the template class
221 
222  float _eps;//!< Absolute precision (to hold "global" accumulation of errors constant)
223 
224 }; // Class
225 
226 //
227 // 4th order Runge-Kutta solver without adaptive stepsize control
228 //
229 template <class T>
230 double RunKutODESolver<T>::RKSolve(double x0, double y0, double x)
231 {
232 // Approximation to the required y(x_i) for given x_i
233  double x_i = x0;
234  double w_i = y0;
235 
236 // Set stepsize and number of iterations
237  int nIter = (int)( 1/_eps );
238  double h = (x - x0)/nIter;
239 
240 // Perform n steps
241  for(int i=0; i<=nIter; i++) { //nSteps; i++) {
242 
243  // Calculate new approximation w_i+1 (denoted again as w_i)
244  w_i = RK4Method(x_i, w_i, h, FCE2(x_i, w_i));
245 
246  // Verify that step is not beyond machine precision
247  if( (double)(x_i+h) == x_i ) {
248 // std::cout << "Error - RunKutSolver::RKSolve: Stepsize is too small!!!"
249  streamlog_out(ERROR) << "RunKutSolver::RKSolve: Stepsize is too small!!!"
250  << std::endl;
251  exit(1);
252  }
253  else x_i = x_i + h;
254  }
255 
256 // std::cout << "Number of iterations: " << nIter+1 << std::endl;
257  streamlog_out(MESSAGE0) << " ODESolver - number of iterations: " << nIter+1 << std::endl;
258 
259  // Result
260  return w_i;
261 }
262 
263 //
264 // 4th order Runge-Kutta solver with adaptive stepsize control
265 //
266 template <class T>
267 double RunKutODESolver<T>::RKCSolve(double x0, double y0, double x, double hTry)
268 {
269 // Approximation to the required y(x_i), resp. y(x_i+1), for given x_i, resp. x_i+1, and using stepsize hTry
270  double x_i = x0;
271  double w_i = y0;
272  double w_i1 = 0.;
273 
274 // Approximation to the required y(x_i+1) for given x_i+1 and using 2 * half-stepsize hTry/2
275  double w2_i1 = 0.;
276 
277 // Stepsize (h = actual stepsize, H = new proposed stepsize)
278  double h = hTry;
279  double h2 = h/2.;
280  double H = 0.;
281 
282 // Number of iterations
283  int nIter = 0;
284 
285 // Allow MAXSTEPS steps in maximum
286  for (int i=0; i<MAXSTEPS; i++) {
287 
288  // Evaluate ODE right-hand side
289  double dydx_i = FCE2(x_i, w_i);
290 
291  // Actual position + stepsize cannot be bigger than the final position x
292  if ( (x_i+h - x)*(x_i+h - x0) > 0.) h = x - x_i;
293 
294  // Adapt stepsize and calculate new approximation w_i+1
295  bool adapt = true;
296  while (adapt) {
297 
298  nIter++;
299 
300  // Calculate w_i+1(x_i + h; h) (denoted as w_i1) using stepsize h
301  w_i1 = RK4Method(x_i, w_i, h, dydx_i);
302 
303  // Calculate w_i+1(x_i + h; h/2) (denoted as w2_i1) using 2 * stepsize h/2
304  w2_i1 = RK4Method(x_i, w_i, h2, dydx_i);
305  w2_i1 = RK4Method(x_i + h2, w2_i1, h2, FCE2(x_i + h2, w2_i1));
306 
307  // Verify if w_i+1(x_i + h; h) - w_i+1(x_i + h; h/2) is within required
308  // precision
309  double fraction = fabs(_eps/(w_i1 - w2_i1));
310  H = h * pow(15./16. * fraction, 0.2 );
311 
312  // If not, try again
313  if ((h/H) > 2.5) {
314  // Reduce stepsize, no more than 10 times
315  h = ( ((2*H) > (0.1*h)) ? (2*H) : (0.1*h) );
316  h2 = h/2.;
317 
318  adapt = true;
319  }
320  else {
321  // New step
322  hTry = 2*H;
323 
324  adapt = false;
325  }
326  } // While
327 
328  // Verify that the step was not beyond machine precision
329  if( (double)(x_i+h) == x_i ) {
330 // std::cout << "Error - RunKutSolver::RKSolve: Stepsize is too small!!!"
331  streamlog_out(ERROR) << "RunKutSolver::RKCSolve: Stepsize is too small!!!"
332  << std::endl;
333  exit(1);
334  }
335  // Calculate x_i+1 position
336  x_i += h;
337 
338  // Set new w_i+1 position
339  w_i = w2_i1;
340 
341  // Final position x achived?
342  if ( (x_i - x)*(x - x0) >= 0. ) {
343 
344 // std::cout << "Number of iterations: " << nIter+1 << std::endl;
345  streamlog_out(MESSAGE0) << " ODESolver - number of iterations: " << nIter+1 << std::endl;
346  return w2_i1;
347  }
348 
349  // If not, set new stepsize
350  h = hTry;
351  h2 = hTry/2.;
352 
353  } // For
354 
355 // Too many steps peformed
356 // std::cout << "Error - RunKutSolver::RKSolve: Stepsize is too small!!!"
357  streamlog_out(ERROR) << "RunKutSolver::RKCSolve: Too many steps performed!!!"
358  << std::endl;
359  exit(1);
360 }
361 
362 //
363 // 5th(4th) order Runge-Kutta-Fehlberg solver with adaptive stepsize control
364 //
365 template <class T>
366 double RunKutODESolver<T>::RKFSolve(double x0, double y0, double x, double hTry)
367 {
368 // Approximation to the required y(x_i), resp. y(x_i+1), for given x_i, resp. x_i+1
369  double x_i = x0;
370  double w_i = y0;
371  double w_i1 = 0;
372 
373 // Estimated precision of current step
374  double wDiff = 0.;
375 
376 // Stepsize (h = actual stepsize, H = new stepsize)
377  double h = hTry;
378  double H = 0.;
379 
380 // Number of iterations
381  int nIter = 0;
382 
383 // Allow MAXSTEPS steps in maximum
384  for (int i=0; i<MAXSTEPS; i++) {
385 
386  // Evaluate ODE right-hand side
387  double dydx_i = FCE2(x_i, w_i);
388 
389  // Actual position + stepsize cannot be bigger than the final position x
390  if ( (x_i+h - x)*(x_i+h - x0) > 0.) h = x - x_i;
391 
392  // Adapt stepsize and calculate new approximation w_i+1
393  bool adapt = true;
394  while (adapt) {
395 
396  nIter++;
397 
398  // Calculate w_i+1(x_i + h; h) (denoted as w_i) using stepsize h and get
399  // estimated precision of obtained result
400  w_i1 = RKFMethod(x_i, w_i, h, dydx_i, &wDiff);
401 
402  // Verify if wDiff is within required precision
403  double fraction = fabs((_eps*h/(x - x0))/wDiff);
404 
405  // If not, try again
406  if (fraction <= 1.) {
407 
408  // Reduce stepsize
409  H = 0.9 * h * pow(fraction, 0.25);
410 
411  // No more than 10 times
412  h = ( (H > (0.1*h)) ? H : (0.1*h) );
413 
414  adapt = true;
415  }
416  // Step suceeded
417  else {
418 
419  // Suggest new step
420  H = 0.9 * h * pow(fraction, 0.2);
421  hTry = H;
422 
423  adapt = false;
424  }
425  } // While
426 
427  // Verify that the step was not beyond machine precision
428  if( (double)(x_i+h) == x_i ) {
429 // std::cout << "Error - RunKutSolver::RKSolve: Stepsize is too small!!!"
430  streamlog_out(ERROR) << "RunKutSolver::RKFSolve: Stepsize is too small!!!"
431  << std::endl;
432  exit(1);
433  }
434  // Calculate x_i+1 position
435  x_i += h;
436 
437  // Set new w_i+1 positio
438  w_i = w_i1;
439 
440  // Final position x achived?
441  if ( (x_i - x)*(x - x0) >= 0. ) {
442 
443 // std::cout << "Number of iterations: " << nIter+1 << std::endl;
444  streamlog_out(MESSAGE0) << " ODESolver - number of iterations: " << nIter+1 << std::endl;
445  return w_i1;
446  }
447 
448  // If not, set new stepsize
449  h = hTry;
450 
451  } // For
452 
453 // Too many steps peformed
454 // std::cout << "Error - RunKutSolver::RKSolve: Stepsize is too small!!!"
455  streamlog_out(ERROR) << "RunKutSolver::RKFSolve: Too many steps performed!!!"
456  << std::endl;
457  exit(1);
458 }
459 
460 
461 //
462 // 4th order Runge-Kutta method - calculates i+1-th step, when solving 1st order ODE
463 //
464 template <class T>
465 double RunKutODESolver<T>::RK4Method(double x_i, double w_i, double h, double dydx_i)
466 {
467  double h2 = h/2.;
468  double k1, k2, k3, k4;
469  double Phi;
470 
471 // First step
472  k1 = dydx_i;
473 
474 // Second step
475  k2 = FCE2(x_i + h2, w_i + h2*k1);
476 
477 // Third step
478  k3 = FCE2(x_i + h2, w_i + h2*k2);
479 
480 // Fourth step
481  k4 = FCE2(x_i + h, w_i + h*k3);
482 
483 // Phi(x,y;h)
484  Phi = 1./6. * (k1 + 2*k2 + 2*k3 + k4);
485 
486 // Result w(x_i+1,h) = w_i+1
487  return (w_i + h*Phi);
488 }
489 
490 //
491 // 5th(4th) order Runge-Kutta-Fehlberg method - calculates i+1-th step, when solving 1st order ODE
492 //
493 template <class T>
494 double RunKutODESolver<T>::RKFMethod(double x_i, double w_i, double h, double dydx_i, double * wDiffPointer)
495 {
496  static float a1 = 0.2, a2 = 0.3, a3 = 0.6, a4 = 1., a5 = 0.875;
497  static float b10= 0.2, b20= 0.075, b30= 0.3, b40=-11./54., b50= 1631./55296.,
498  b21= 0.225, b31=-0.9, b41= 2.5, b51= 175./512.,
499  b32= 1.2, b42=-70./27., b52= 575./13824.,
500  b43= 35./27., b53= 44275./110592.,
501  b54= 253./4096.;
502 
503  static float c0I = 37./378., c2I = 250./621., c3I = 125./594., c4I = 0., c5I = 512./1771.,
504  c0II = 2825./27648., c2II = 18575./48384., c3II = 13525./55296., c4II = 277./14336., c5II = 0.25,
505  difc0= c0I - c0II, difc2= c2I - c2II, difc3= c3I - c3II, difc4= c4I - c4II, difc5= c5I - c5II;
506 
507  double f0, f1, f2, f3, f4, f5;
508  double PhiI;
509 
510 // First step
511  f0 = dydx_i;
512 
513 // Second step
514  f1 = FCE2(x_i + a1*h, w_i + h*(b10*f0));
515 
516 // Third step
517  f2 = FCE2(x_i + a2*h, w_i + h*(b20*f0 + b21*f1));
518 
519 // Fourth step
520  f3 = FCE2(x_i + a3*h, w_i + h*(b30*f0 + b31*f1 + b32*f2));
521 
522 // Fifth step
523  f4 = FCE2(x_i + a4*h, w_i + h*(b40*f0 + b41*f1 + b42*f2 + b43*f3));
524 
525 // Sixth step
526  f5 = FCE2(x_i + a5*h, w_i + h*(b50*f0 + b51*f1 + b52*f2 + b53*f3 + b54*f4));
527 
528 // Phi(x,y;h) (c1I = 0 and c4I = 0)
529  PhiI = c0I*f0 + c2I*f2 + c3I*f3 + c5I*f5;
530 
531 // Estimated precision wDiff = w(x_i+1,h) - v(x_i+1,h)
532  *wDiffPointer = h*(difc0*f0 + difc2*f2 + difc3*f3 + difc4*f4 + difc5*f5);
533 
534 // Result w(x_i+1,h) = w_i+1
535  return (w_i + h*PhiI);
536 }
537 
538 } // Namespace
539 
540 /** @} */
541 
542 #endif // RUNKUTODESOLVER_H
double(T::* _fce)(double, double)
Relative pointer to an integrated function.
double RKCSolve(double x0, double y0, double x, double hTry)
This method returns a solution y(x) to the so-called ODE initial value problem (IVP), using 4th order Runge-Kutta method with adaptive stepsize control.
#define FCE2(x, y)
float _eps
Absolute precision (to hold &quot;global&quot; accumulation of errors constant)
double RKFSolve(double x0, double y0, double x, double hTry)
This method returns a solution y(x) to the so-called ODE initial value problem (IVP), using 5th(4th) order Runge-Kutta-Fehlberg method with adaptive stepsize control.
double RKFMethod(double x_i, double w_i, double h, double dydx_i, double *wDiffPointer)
This method based on 5th(4th) order Runge-Kutta-Fehlberg algorithm returns two approximations: w(x_i+...
static const float T
~RunKutODESolver()
Destructor.
RunKutODESolver(double(T::*fce)(double, double), T *pTemplate, float eps)
Constructor - sets ODE right-hand side and required absolut accumulated precision.
double RK4Method(double x_i, double w_i, double h, double dydx_i)
This method based on 4th order Runge-Kutta algorithm returns an approximation w(x_i+1,h) to the exact solution y(x_i+1) of the so-called initial value problem (IVP) at position x_i+1 = x_i + h and using given &quot;integration&quot; stepsize h, where the IVP is defined as y&#39; = f(x,y), y(x0) = y0 and for equidistant stepsizes h the coordinate x_i can be expressed as x_i = x0 + ih.
Double precision first-order ODE (IVP, i.e.
double RKSolve(double x0, double y0, double x)
This method returns a solution y(x) to the so-called ODE initial value problem (IVP), using 4th order Runge-Kutta method.
#define MAXSTEPS
T * _pTemplate
Pointer to the template class.