SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
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//
27namespace 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
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
62begin_step:
63
64 ///////////////////////////////////////////////////////// beginning of step
65
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
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
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
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
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
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
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
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
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
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
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
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
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
static Iterator LastIntegrator(void)
Definition: simlib.h:1084
static bool IsEndStepEvent
Definition: simlib.h:1079
IntegratorContainer::iterator Iterator
Definition: simlib.h:1080
static bool StateCond(void)
check on changes of state conditions
Definition: numint.cc:175
static Iterator FirstIntegrator(void)
Definition: simlib.h:1081
Memory A5
Definition: ni_rkf8.h:24
Memory A12
Definition: ni_rkf8.h:25
Memory A4
Definition: ni_rkf8.h:24
Memory A3
Definition: ni_rkf8.h:24
Memory A2
Definition: ni_rkf8.h:24
virtual void Integrate(void) override
Definition: ni_rkf8.cc:41
Memory A7
Definition: ni_rkf8.h:24
Memory A1
Definition: ni_rkf8.h:24
Memory A8
Definition: ni_rkf8.h:25
Memory A9
Definition: ni_rkf8.h:25
Memory A10
Definition: ni_rkf8.h:25
Memory A6
Definition: ni_rkf8.h:24
Memory A13
Definition: ni_rkf8.h:25
Memory A11
Definition: ni_rkf8.h:25
bool IsStartMode(void)
Definition: simlib.h:1154
@ AccuracyError
Definition: errors.h:23
Internal header file for SIMLIB/C++.
#define Dprintf(f)
Definition: internal.h:100
#define _SetTime(t, x)
macro for simple assignement to internal time variables
Definition: internal.h:228
Implementation of class CalendarList interface is static - using global functions in SQS namespace.
Definition: algloop.cc:32
const double & Time
model time (is NOT the block)
Definition: run.cc:48
double SIMLIB_RelativeError
relative error
Definition: intg.cc:43
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
bool SIMLIB_ContractStepFlag
requests shorter step
Definition: intg.cc:58
void SIMLIB_Dynamic()
performs evaluation of integrators and status blocks
Definition: continuous.cc:35
int _Print(const char *fmt,...)
output of messages to stdout, too
Definition: print.cc:68
double min(double a, double b)
Definition: internal.h:285
double max(double a, double b)
Definition: internal.h:286
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
double SIMLIB_AbsoluteError
absolute error
Definition: intg.cc:42
double SIMLIB_MinStep
minimal step
Definition: intg.cc:38
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39
int SIMLIB_ERRNO
Definition: intg.cc:32
const double & OptStep
optimal integration step
Definition: intg.cc:49
double SIMLIB_ContractStep
requested step size
Definition: intg.cc:59
double SIMLIB_StepStartTime
last step time
Definition: intg.cc:34
double SIMLIB_StepSize
actual step
Definition: intg.cc:40
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
Runge-Kutta-Fehlberg 8th order.
Main SIMLIB/C++ interface.