SIMLIB/C++  3.07
ni_rkf8.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 // ni_rkf8.cc
3 //
4 // Copyright (c) 1996-1997 David Leska
5 // Copyright (c) 1998-2004 Petr Peringer
6 //
7 // This library is licensed under GNU Library GPL. See the file COPYING.
8 //
9 
10 //
11 // numerical integration: Runge-Kutta-Fehlberg's method 8th order
12 //
13 
14 ////////////////////////////////////////////////////////////////////////////
15 // interface
16 //
17 #include "simlib.h"
18 #include "internal.h"
19 #include "ni_rkf8.h"
20 #include <cmath>
21 #include <cstddef>
22 
23 
24 ////////////////////////////////////////////////////////////////////////////
25 // implementation
26 //
27 namespace simlib3 {
28 
30 
31 
32 ////////////////////////////////////////////////////////////////////////////
33 // Runge-Kutta-Fehlberg's method 8th order
34 //
35 /* Formula:
36 
37  is too large, for information see next source code
38  or documentation (if is any ;-))
39 */
40 
41 void RKF8::Integrate(void)
42 {
43  const double safety = 0.9; // keeps the new step from growing too large
44  const double max_ratio = 4.0; // ditto
45  const double pshrnk = 1.0/7.0; // coefficient for reducing step
46  const double pgrow = 1.0/8.0; // coefficient for increasing step
47  size_t i; // auxiliary variables for loops
48  Iterator ip, end_it; // to go through list of integrators
49  double ratio; // ratio for next stepsize computation
50  double next_step; // recommended stepsize for next step
51  size_t n; // integrator with greatest error
52 
53  Dprintf((" RKF8 integration step ")); // print debugging info
54  Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
55 
56  end_it=LastIntegrator(); // end of container of integrators
57 
58  //--------------------------------------------------------------------------
59  // Step of method
60  //--------------------------------------------------------------------------
61 
62 begin_step:
63 
64  ///////////////////////////////////////////////////////// beginning of step
65 
66  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
67 
68  SIMLIB_ContractStepFlag = false; // clear reduce step flag
69  SIMLIB_ContractStep = 0.5*SIMLIB_StepSize; // implicitly reduce to half step
70 
71  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
72  A1[i] = SIMLIB_StepSize*(*ip)->GetOldDiff(); // compute coefficient
73  (*ip)->SetState((*ip)->GetOldState() + 0.25*A1[i]); // state (y) for next substep
74  }
75 
76  ////////////////////////////////////////////////////////////// 1/4 of step
77 
78  _SetTime(Time,SIMLIB_StepStartTime + 0.25*SIMLIB_StepSize); // substep time
79  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
80 
81  SIMLIB_Dynamic(); // evaluate new state of model (y'=f(t,y)) (1)
82 
83  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
84  A2[i] = SIMLIB_StepSize*(*ip)->GetDiff();
85  (*ip)->SetState((*ip)->GetOldState() + (5.0*A1[i] + A2[i]) / 72.0);
86  }
87 
88  ////////////////////////////////////////////////////////////// 1/12 of step
89 
90  _SetTime(Time,SIMLIB_StepStartTime + 1.0/12.0*SIMLIB_StepSize); // substep
91  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
92 
93  SIMLIB_Dynamic(); // evaluate new state of model (2)
94 
95  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
96  A3[i] = SIMLIB_StepSize*(*ip)->GetDiff();
97  (*ip)->SetState((*ip)->GetOldState() + (A1[i] + 3.0*A3[i]) / 32.0);
98  }
99 
100  ////////////////////////////////////////////////////////////// 1/8 of step
101 
103  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
104 
105  SIMLIB_Dynamic(); // evaluate new state of model (3)
106 
107  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
108  A4[i] = SIMLIB_StepSize*(*ip)->GetDiff();
109  (*ip)->SetState((*ip)->GetOldState() + ( 106.0 * A1[i]
110  - 408.0 * A3[i]
111  + 352.0 * A4[i]
112  ) / 125.0);
113  }
114 
115  ////////////////////////////////////////////////////////////// 2/5 of step
116 
118  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
119 
120  SIMLIB_Dynamic(); // evaluate new state of model (4)
121 
122  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
123  A5[i] = SIMLIB_StepSize*(*ip)->GetDiff();
124  (*ip)->SetState((*ip)->GetOldState() + 1.0 / 48.0 * A1[i]
125  + 8.0 / 33.0 * A4[i]
126  + 125.0 / 528.0 * A5[i]);
127  }
128 
129  ///////////////////////////////////////////////////////////// 1/2 of step
130 
132  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
133 
134  SIMLIB_Dynamic(); // evaluate new state of model (5)
135 
136  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
137  A6[i] = SIMLIB_StepSize*(*ip)->GetDiff();
138  (*ip)->SetState((*ip)->GetOldState() - 1263.0 / 2401.0 * A1[i]
139  + 39936.0 / 26411.0 * A4[i]
140  - 64125.0 / 26411.0 * A5[i]
141  + 5520.0 / 2401.0 * A6[i]);
142  }
143 
144  ///////////////////////////////////////////////////////////// 6/7 of step
145 
147  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
148 
149  SIMLIB_Dynamic(); // evaluate new state of model (6)
150 
151  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
152  A7[i] = SIMLIB_StepSize*(*ip)->GetDiff();
153  (*ip)->SetState((*ip)->GetOldState() + 37.0 / 392.0 * A1[i]
154  + 1625.0 / 9408.0 * A5[i]
155  - 2.0 / 15.0 * A6[i]
156  + 61.0 / 6720.0 * A7[i]);
157  }
158 
159  ///////////////////////////////////////////////////////////// 1/7 of step
160 
162  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
163 
164  SIMLIB_Dynamic(); // evaluate new state of model (7)
165 
166  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
167  A8[i] = SIMLIB_StepSize*(*ip)->GetDiff();
168  (*ip)->SetState((*ip)->GetOldState() + 17176.0 / 25515.0 * A1[i]
169  - 47104.0 / 25515.0 * A4[i]
170  + 1325.0 / 504.0 * A5[i]
171  - 41792.0 / 25515.0 * A6[i]
172  + 20237.0 / 145800.0 * A7[i]
173  + 4312.0 / 6075.0 * A8[i]);
174  }
175 
176  ///////////////////////////////////////////////////////////// 2/3 of step
177 
179  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
180 
181  SIMLIB_Dynamic(); // evaluate new state of model (8)
182 
183  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
184  A9[i] = SIMLIB_StepSize*(*ip)->GetDiff();
185  (*ip)->SetState((*ip)->GetOldState() - 23834.0 / 180075.0 * A1[i]
186  - 77824.0 / 1980825.0 * A4[i]
187  - 636635.0 / 633864.0 * A5[i]
188  + 254048.0 / 300125.0 * A6[i]
189  - 183.0 / 7000.0 * A7[i]
190  + 8.0 / 11.0 * A8[i]
191  - 324.0 / 3773.0 * A9[i]);
192  }
193 
194  ///////////////////////////////////////////////////////////// 2/7 of step
195 
197  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
198 
199  SIMLIB_Dynamic(); // evaluate new state of model (9)
200 
201  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
202  A10[i] = SIMLIB_StepSize*(*ip)->GetDiff();
203  (*ip)->SetState((*ip)->GetOldState() + 12733.0 / 7600.0 * A1[i]
204  - 20032.0 / 5225.0 * A4[i]
205  + 456485.0 / 80256.0 * A5[i]
206  - 42599.0 / 7125.0 * A6[i]
207  + 339227.0 / 912000.0 * A7[i]
208  - 1029.0 / 4180.0 * A8[i]
209  + 1701.0 / 1408.0 * A9[i]
210  + 5145.0 / 2432.0 * A10[i]);
211  }
212 
213  ///////////////////////////////////////////////////////////// 1/1 of step
214 
216  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
217 
218  SIMLIB_Dynamic(); // evaluate new state of model (10)
219 
220  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
221  A11[i] = SIMLIB_StepSize*(*ip)->GetDiff();
222  (*ip)->SetState((*ip)->GetOldState() - 27061.0 / 204120.0 * A1[i]
223  + 40448.0 / 280665.0 * A4[i]
224  - 1353775.0 / 1197504.0 * A5[i]
225  + 17662.0 / 25515.0 * A6[i]
226  - 71687.0 / 1166400.0 * A7[i]
227  + 98.0 / 225.0 * A8[i]
228  + 1.0 / 16.0 * A9[i]
229  + 3773.0 / 11664.0 * A10[i]);
230  }
231 
232  ///////////////////////////////////////////////////////////// 1/3 of step
233 
235  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
236 
237  SIMLIB_Dynamic(); // evaluate new state of model (11)
238 
239  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
240  A12[i] = SIMLIB_StepSize*(*ip)->GetDiff();
241  (*ip)->SetState((*ip)->GetOldState() + 11203.0 / 8680.0 * A1[i]
242  - 38144.0 / 11935.0 * A4[i]
243  + 2354425.0 / 458304.0 * A5[i]
244  - 84046.0 / 16275.0 * A6[i]
245  + 673309.0 / 1636800.0 * A7[i]
246  + 4704.0 / 8525.0 * A8[i]
247  + 9477.0 / 10912.0 * A9[i]
248  - 1029.0 / 992.0 * A10[i]
249  + 729.0 / 341.0 * A12[i]);
250  }
251 
252  ////////////////////////////////////////////////////////////// 1/1 of step
253 
256 
257  SIMLIB_Dynamic(); // evaluate new state of model (9)
258 
259  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
260  A13[i] = SIMLIB_StepSize*(*ip)->GetDiff();
261  (*ip)->SetState((*ip)->GetOldState()+ 31.0/720.0 * (A1[i]+A13[i])
262  + 16.0/75.0 * A6[i]
263  +16807.0/79200.0 * (A7[i]+A8[i])
264  + 243.0/1760.0 * (A9[i]+A12[i]));
265  }
266 
267  //--------------------------------------------------------------------------
268  // Check on accuracy of numerical integration, estimate error
269  //--------------------------------------------------------------------------
270 
271  SIMLIB_ERRNO = 0; // OK
272  ratio = 256.0; // 2^8 - ratio for stepsize computation - initial value
273  n=0; // integrator with greatest error
274  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
275  double eerr; // estimated error
276  double terr; // greatest allowed error
277  eerr = fabs( -1.0 / 480.0 * A1[i]
278  - 16.0 / 375.0 * A6[i]
279  - 2401.0 / 528000.0 * A7[i]
280  + 2401.0 / 132000.0 * A8[i]
281  + 243.0 / 14080.0 * A9[i]
282  - 2401.0 / 19200.0 * A10[i]
283  - 19.0 / 450.0 * A11[i]
284  + 243.0 / 1760.0 * A12[i]
285  + 31.0 / 720.0 * A13[i]
286  );
287  terr = fabs(SIMLIB_AbsoluteError)
288  + fabs(SIMLIB_RelativeError*(*ip)->GetState());
289  if(terr < eerr*ratio) { // avoid arithmetic overflow
290  ratio = terr/eerr; // find the lowest ratio
291  n=i; // remember the integrator
292  }
293  } // for
294 
295  Dprintf(("R: %g",ratio));
296 
297  if(ratio < 1.0) { // error is too large, reduce stepsize
298  ratio = pow(ratio,pshrnk); // coefficient for reduce
299  Dprintf(("Down: %g",ratio));
300  if(SIMLIB_StepSize > SIMLIB_MinStep) { // reducing step is possible
302  SIMLIB_StepSize = SIMLIB_OptStep;
303  IsEndStepEvent = false; // no event will be at the end of the step
304  goto begin_step; // compute again with smaller step
305  }
306  // reducing step is unpossible
307  SIMLIB_ERRNO++; // requested accuracy cannot be achieved
308  _Print("\n Integrator[%lu] ",(unsigned long)n);
310  next_step = SIMLIB_StepSize;
311  } else { // allowed tolerantion is fulfiled
312  if(!IsStartMode()) { // method is not used for start multi-step method
313  ratio = min(pow(ratio,pgrow),max_ratio); // coefficient for increase
314  Dprintf(("Up: %g",ratio));
315  next_step = min(safety*ratio*SIMLIB_StepSize, SIMLIB_MaxStep);
316  } else {
317  next_step = SIMLIB_StepSize;
318  }
319  }
320 
321  //--------------------------------------------------------------------------
322  // Analyse system at the end of the step
323  //--------------------------------------------------------------------------
324 
325  if(StateCond()) { // check on changes of state conditions at end of step
326  goto begin_step;
327  }
328 
329  //--------------------------------------------------------------------------
330  // Results of step have been accepted, take fresh step
331  //--------------------------------------------------------------------------
332 
333  // increase step, if accuracy was good
334  SIMLIB_OptStep = next_step;
335 
336 } // RKF8::Integrate
337 
338 }
339 // end of ni_rkf8.cc
340 
Runge-Kutta-Fehlberg 8th order.
static bool IsEndStepEvent
Definition: simlib.h:1079
Memory A7
Definition: ni_rkf8.h:24
int _Print(const char *fmt,...)
output of messages to stdout, too
Definition: print.cc:68
void SIMLIB_Dynamic()
performs evaluation of integrators and status blocks
Definition: continuous.cc:35
double SIMLIB_StepStartTime
last step time
Definition: intg.cc:34
double SIMLIB_ContractStep
requested step size
Definition: intg.cc:59
Memory A13
Definition: ni_rkf8.h:25
const double & OptStep
optimal integration step
Definition: intg.cc:49
Memory A2
Definition: ni_rkf8.h:24
Memory A6
Definition: ni_rkf8.h:24
Memory A11
Definition: ni_rkf8.h:25
Implementation of class CalendarList interface is static - using global functions in SQS namespace...
Definition: algloop.cc:32
double max(double a, double b)
Definition: internal.h:286
Memory A4
Definition: ni_rkf8.h:24
double SIMLIB_RelativeError
relative error
Definition: intg.cc:43
int SIMLIB_ERRNO
Definition: intg.cc:32
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
const double & Time
model time (is NOT the block)
Definition: run.cc:48
Memory A8
Definition: ni_rkf8.h:25
double SIMLIB_StepSize
actual step
Definition: intg.cc:40
Memory A1
Definition: ni_rkf8.h:24
virtual void Integrate(void) override
Definition: ni_rkf8.cc:41
Memory A9
Definition: ni_rkf8.h:25
static bool StateCond(void)
check on changes of state conditions
Definition: numint.cc:175
double min(double a, double b)
Definition: internal.h:285
double SIMLIB_AbsoluteError
absolute error
Definition: intg.cc:42
Memory A5
Definition: ni_rkf8.h:24
bool SIMLIB_ContractStepFlag
requests shorter step
Definition: intg.cc:58
Internal header file for SIMLIB/C++.
Memory A3
Definition: ni_rkf8.h:24
static Iterator LastIntegrator(void)
Definition: simlib.h:1084
static Iterator FirstIntegrator(void)
Definition: simlib.h:1081
Main SIMLIB/C++ interface.
IntegratorContainer::iterator Iterator
Definition: simlib.h:1080
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
#define _SetTime(t, x)
macro for simple assignement to internal time variables
Definition: internal.h:228
double SIMLIB_MinStep
minimal step
Definition: intg.cc:38
bool IsStartMode(void)
Definition: simlib.h:1154
Memory A10
Definition: ni_rkf8.h:25
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
#define Dprintf(f)
Definition: internal.h:100
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
Memory A12
Definition: ni_rkf8.h:25
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39