SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
ni_rkf5.cc
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2// ni_rkf5.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 5th order
12//
13
14////////////////////////////////////////////////////////////////////////////
15// interface
16//
17#include "simlib.h"
18#include "internal.h"
19#include "ni_rkf5.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 5th order
34//
35/* Formula:
36
37 k1 = h*f(t,y);
38 k2 = h*f(t+0.2*h, y + 0.2*k1);
39 k3 = h*f(t+0.3*h, y + (3.0*k1+9.0*k2)/40.0);
40 k4 = h*f(t+0.6*h, y + 0.3*k1 - 0.9*k2 + 1.2*k3);
41 k5 = h*f(t+h, y - 11.0/54.0*k1 + 2.5*k2
42 - 70.0/27.0*k3 + 35.0/27.0*k4);
43 k6 = h*f(t+0.875*h,y + 1631.0 / 55296.0 * k1
44 + 175.0 / 512.0 * k2
45 + 575.0 / 13824.0 * k3
46 + 44275.0 / 110592.0 * k4
47 + 253.0 / 4096.0 * k5);
48 y += 37.0 / 378.0 * k1
49 + 250.0 / 621.0 * k3
50 + 125.0 / 594.0 * k4
51 + 512.0 / 1771.0 * k6;
52 err = fabs( -277.0 / 64512.0 * k1
53 + 6925.0 / 370944.0 * k3
54 - 6925.0 / 202752.0 * k4
55 - 277.0 / 14336.0 * k5
56 + 277.0 / 7084.0 * k6);
57*/
58
60{
61 const double safety = 0.9; // keeps the new step from growing too large
62 const double max_ratio = 4.0; // ditto
63 const double pshrnk = 0.25; // coefficient for reducing step
64 const double pgrow = 0.20; // coefficient for increasing step
65 size_t i; // auxiliary variables for loops to go through list
66 Iterator ip, end_it; // of integrators
67 double ratio; // ratio for next step computation
68 double next_step; // recommended stepsize for next step
69 size_t n; // integrator with the greatest error
70
71 Dprintf((" RKF5 integration step ")); // print debugging info
72 Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
73
74 end_it=LastIntegrator(); // end of container of integrators
75
76 //--------------------------------------------------------------------------
77 // Step of method
78 //--------------------------------------------------------------------------
79
80begin_step:
81
82 ///////////////////////////////////////////////////////// beginning of step
83
85
86 SIMLIB_ContractStepFlag = false; // clear reduce step flag
87 SIMLIB_ContractStep = 0.5*SIMLIB_StepSize; // implicitly reduce to half step
88
89 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
90 A1[i] = SIMLIB_StepSize*(*ip)->GetOldDiff(); // compute coefficient
91 (*ip)->SetState((*ip)->GetOldState() + 0.2*A1[i]); // state (y) for next sub-step
92 }
93
94 ////////////////////////////////////////////////////////////// 0.2 of step
95
96 _SetTime(Time,SIMLIB_StepStartTime + 0.2*SIMLIB_StepSize); // substep's time
98
99 SIMLIB_Dynamic(); // evaluate new state of model (y'=f(t,y)) (1)
100
101 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
102 A2[i] = SIMLIB_StepSize*(*ip)->GetDiff();
103 (*ip)->SetState((*ip)->GetOldState() + (3.0*A1[i] + 9.0*A2[i]) / 40.0);
104 }
105
106 ////////////////////////////////////////////////////////////// 0.3 of step
107
108 _SetTime(Time,SIMLIB_StepStartTime + 0.3*SIMLIB_StepSize); //substep's time
110
111 SIMLIB_Dynamic(); // evaluate new state of model (2)
112
113 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
114 A3[i] = SIMLIB_StepSize*(*ip)->GetDiff();
115 (*ip)->SetState((*ip)->GetOldState() + 0.3 * A1[i] - 0.9 * A2[i] + 1.2 * A3[i]);
116 }
117
118 ////////////////////////////////////////////////////////////// 0.6 of step
119
122
123 SIMLIB_Dynamic(); // evaluate new state of model (3)
124
125 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
126 A4[i] = SIMLIB_StepSize*(*ip)->GetDiff();
127 (*ip)->SetState((*ip)->GetOldState() - 11.0 / 54.0 * A1[i]
128 + 2.5 * A2[i]
129 - 70.0 / 27.0 * A3[i]
130 + 35.0 / 27.0 * A4[i]);
131 }
132
133 ////////////////////////////////////////////////////////////// 1.0 of step
134
137
138 SIMLIB_Dynamic(); // evaluate new state of model (4)
139
140 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
141 A5[i] = SIMLIB_StepSize*(*ip)->GetDiff();
142 (*ip)->SetState((*ip)->GetOldState() + 1631.0 / 55296.0 * A1[i]
143 + 175.0 / 512.0 * A2[i]
144 + 575.0 / 13824.0 * A3[i]
145 + 44275.0 / 110592.0 * A4[i]
146 + 253.0 / 4096.0 * A5[i]);
147 }
148
149 ///////////////////////////////////////////////////////////// 0.875 of step
150
153
154 SIMLIB_Dynamic(); // evaluate new state of model (5)
155
156 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
157 A6[i] = SIMLIB_StepSize*(*ip)->GetDiff();
158 (*ip)->SetState((*ip)->GetOldState() + 37.0 / 378.0 * A1[i] // final state
159 + 250.0 / 621.0 * A3[i]
160 + 125.0 / 594.0 * A4[i]
161 + 512.0 / 1771.0 * A6[i]);
162 }
163
164 ////////////////////////////////////////////////////////////// end of step
165
166 _SetTime(Time, SIMLIB_StepStartTime+SIMLIB_StepSize); // go to end of step
169
170 //--------------------------------------------------------------------------
171 // Check on accuracy of numerical integration, estimate error
172 //--------------------------------------------------------------------------
173
174 SIMLIB_ERRNO = 0; // OK
175 ratio = 32.0; // 2^5 - ratio for stepsize computation - initial value
176 n=0; // integrator with greatest error
177 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
178 double eerr; // estimated error
179 double terr; // greatest allowed error
180
181 eerr = fabs( -277.0 / 64512.0 * A1[i] // estimation
182 + 6925.0 / 370944.0 * A3[i]
183 - 6925.0 / 202752.0 * A4[i]
184 - 277.0 / 14336.0 * A5[i]
185 + 277.0 / 7084.0 * A6[i]);
186 terr = fabs(SIMLIB_AbsoluteError)
187 + fabs(SIMLIB_RelativeError*(*ip)->GetState());
188 if(terr < eerr*ratio) { // avoid arithmetic overflow
189 ratio = terr/eerr; // find the lowest ratio
190 n=i; // remember the integrator
191 }
192 } // for
193
194 Dprintf(("R: %g",ratio));
195
196 if(ratio < 1.0) { // error is too large, reduce stepsize
197 ratio = pow(ratio,pshrnk); // coefficient for reduce
198 Dprintf(("Down: %g",ratio));
199 if(SIMLIB_StepSize > SIMLIB_MinStep) { // reducing step is possible
202 IsEndStepEvent = false; // no event will be at the end of the step
203 goto begin_step; // compute again with smaller step
204 }
205 // reducing step is unpossible
206 SIMLIB_ERRNO++; // requested accuracy cannot be achieved
207 _Print("\n Integrator[%lu] ",(unsigned long)n);
209 next_step = SIMLIB_StepSize;
210 } else { // allowed tolerantion is fulfiled
211 if(!IsStartMode()) { // method is not used for start multi-step method
212 ratio = min(pow(ratio,pgrow),max_ratio); // coefficient for increase
213 Dprintf(("Up: %g",ratio));
214 next_step = min(safety*ratio*SIMLIB_StepSize, SIMLIB_MaxStep);
215 } else {
216 next_step = SIMLIB_StepSize;
217 }
218 }
219
220 //--------------------------------------------------------------------------
221 // Analyse system at the end of the step
222 //--------------------------------------------------------------------------
223
224 if(StateCond()) { // check on changes of state conditions at end of step
225 goto begin_step;
226 }
227
228 //--------------------------------------------------------------------------
229 // Results of step have been accepted, take fresh step
230 //--------------------------------------------------------------------------
231
232 // increase step, if accuracy is good
233 SIMLIB_OptStep = next_step;
234
235} // RKF5::Integrate
236
237
238}
239// end of ni_rkf5.cc
240
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 A2
Definition: ni_rkf5.h:24
Memory A4
Definition: ni_rkf5.h:24
Memory A5
Definition: ni_rkf5.h:24
Memory A1
Definition: ni_rkf5.h:24
virtual void Integrate(void) override
Definition: ni_rkf5.cc:59
Memory A6
Definition: ni_rkf5.h:24
Memory A3
Definition: ni_rkf5.h:24
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 5th order.
Main SIMLIB/C++ interface.