SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
ni_rke.cc
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2//! \file ni_rke.cc Numerical integration method - Runge-Kutta-England
3//
4// Copyright (c) 1991-2004 Petr Peringer
5// Copyright (c) 1996-1997 David Leska
6//
7// This library is licensed under GNU Library GPL. See the file COPYING.
8//
9
10//
11// numerical integration: Runge-Kutta-England's method
12// this method is the default
13//
14
15////////////////////////////////////////////////////////////////////////////
16// interface
17//
18#include "simlib.h"
19#include "internal.h"
20#include "ni_rke.h"
21#include <cmath>
22#include <cstddef>
23
24
25////////////////////////////////////////////////////////////////////////////
26// implementation
27//
28namespace simlib3 {
29
31
32
33////////////////////////////////////////////////////////////////////////////
34// Runge-Kutta-England's method
35//
36/* Formula:
37
38 dt=0.5*h;
39 a1=dt*f(t,y);
40 a2=dt*f(t+0.5*dt,y+0.5*a1);
41 a3=dt*f(t+0.5*dt,y+0.25*(a1+a2));
42 t+=dt;
43 a4=dt*f(t,y+(2.0*a3-a2));
44 yt1=y+((a1+a4)+4.0*a3)/6.0;
45 a5=dt*f(t,yt1);
46 a6=dt*f(t+0.5*dt,yt1+0.5*a5);
47 a7=dt*f(t+0.5*dt,yt1+0.25*(a5+a6));
48 t+=dt;
49 r=dt*f(t,y+(-a1-96.0*a2+92.0*a3-121.0*a4+144.0*a5+6.0*a6-12.0*a7)/6.0);
50 err=fabs((-a1+4.0*a3+17.0*a4-23.0*a5+4.0*a7-r)/90.0);
51 yt2 = yt1+(a5+4.0*a7+dt*f(t,yt1+(2.0*a7-a6)))/6.0;
52*/
53
55{
56 static const double err_coef = 0.02; // limits an error range
57 static double dthlf; // half step
58 static double dtqrt; // quater step
59 static bool DoubleStepFlag; // flag - allow increasing (doubling) the step
60 size_t i; // auxiliary variables for loops to go through list
61 Iterator ip, end_it; // of integrators
62
63 Dprintf((" RKE integration step ")); // print debugging info
64 Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
65
66 end_it=LastIntegrator(); // end of container of integrators
67
68 //--------------------------------------------------------------------------
69 // Step of method
70 //--------------------------------------------------------------------------
71
72begin_step:
73
74 ///////////////////////////////////////////////////////// beginning of step
75
77 dthlf = 0.5*SIMLIB_StepSize; // half step
78 dtqrt = 0.5*dthlf; // quater step
79
80 SIMLIB_ContractStepFlag = false; // clear reduce step flag
81 SIMLIB_ContractStep = dtqrt; // implicitly reduce to quater of step
82
83 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
84 A1[i] = dthlf*(*ip)->GetOldDiff(); // compute coefficient
85 (*ip)->SetState((*ip)->GetOldState()+0.5*A1[i]); // state (y) for next sub-step
86 }
87
88 ////////////////////////////////////////////////////////////// 1/4 of step
89
90 _SetTime(Time,SIMLIB_StepStartTime + dtqrt); // time (t) for next sub-step
92
93 SIMLIB_Dynamic(); // evaluate new state of model (y'=f(t,y)) (1)
94
95 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
96 A2[i] = dthlf*(*ip)->GetDiff();
97 (*ip)->SetState((*ip)->GetOldState() + 0.25*(A1[i]+A2[i]));
98 }
99
100 SIMLIB_Dynamic(); // evaluate new state of model (2)
101
102 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
103 A3[i] = dthlf*(*ip)->GetDiff();
104 (*ip)->SetState((*ip)->GetOldState() - A2[i] + A3[i] + A3[i]);
105 }
106
107 //////////////////////////////////////////////////////////////
108 // 1/2 of step
109 //////////////////////////////////////////////////////////////
110
113
114 SIMLIB_Dynamic(); // evaluate new state of model (3)
115
116 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
117 A4[i] = dthlf*(*ip)->GetDiff();
118 (*ip)->SetState((*ip)->GetOldState() + (A1[i] + 4.0*A3[i] + A4[i]) / 6.0);
119 }
120
121 if(StateCond()) { // check on changes of state conditions in 1/2 of step
122 goto begin_step; // compute again
123 }
124
125 bool wasContractStepFlag = SIMLIB_ContractStepFlag; // remember value
126 SIMLIB_ContractStepFlag = false; // not reduce step
127 SIMLIB_ContractStep = dthlf; // implicitly reduce to half of step
128
129 StoreState(di, si, xi); // store values in 1/2 of step
130
131 SIMLIB_Dynamic(); // evaluate new state of model (4)
132
133 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
134 A5[i] = dthlf*(*ip)->GetDiff();
135 (*ip)->SetState(si[i] + 0.5*A5[i]);
136 }
137
138 ////////////////////////////////////////////////////////////// 3/4 of step
139
140 _SetTime(Time, SIMLIB_StepStartTime+dthlf+dtqrt);
142
143 SIMLIB_Dynamic(); // evaluate new state of model (5)
144
145 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
146 A6[i] = dthlf * (*ip)->GetDiff();
147 (*ip)->SetState(si[i] + 0.25*(A5[i] + A6[i]));
148 }
149
150 SIMLIB_Dynamic(); // evaluate new state of model (6)
151
152 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
153 A7[i] = dthlf*(*ip)->GetDiff();
154 (*ip)->SetState((*ip)->GetOldState()
155 + ( - A1[i]
156 - 96.0 * A2[i]
157 + 92.0 * A3[i]
158 - 121.0 * A4[i]
159 + 144.0 * A5[i]
160 + 6.0 * A6[i]
161 - 12.0 * A7[i]
162 ) / 6.0);
163 }
164
165 //////////////////////////////////////////////////////////// end of step
166
169
170 SIMLIB_Dynamic(); // evaluate new state of model (7)
171
172 //--------------------------------------------------------------------------
173 // Check on accuracy of numerical integration, estimate error
174 //--------------------------------------------------------------------------
175
176 DoubleStepFlag = true;
177 SIMLIB_ERRNO = 0;
178 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
179 double eerr; // estimated error
180 double terr; // greatest allowed error
181
182 eerr = fabs(( - A1[i]
183 + 4.0 * A3[i]
184 + 17.0 * A4[i]
185 - 23.0 * A5[i]
186 + 4.0 * A7[i]
187 - dthlf * (*ip)->GetDiff()
188 ) / 90.0); // error estimation
190
191 if(eerr < err_coef*terr) // allowed tolerantion is fulfiled with provision
192 continue;
193
194 if(eerr > terr) { // allowed tolerantion is overfulfiled
195 if(SIMLIB_StepSize>SIMLIB_MinStep) { // reducing step is possible
196 SIMLIB_OptStep = 0.5*SIMLIB_StepSize; // halve optimal step
197 if(SIMLIB_OptStep < SIMLIB_MinStep) { // limit of optimal step
199 }
201 IsEndStepEvent = false;
202 goto begin_step; // compute again with smaller step
203 }
204 // reducing step is unpossible
205 SIMLIB_ERRNO++; // requested accuracy cannot be achieved
206 _Print("\n Integrator[%lu] ",(unsigned long)i);
207 if(SIMLIB_ConditionFlag) // event was in half step, step reducing was
208 break; // unpossible and accuracy cannot be achieved
209 }
210 DoubleStepFlag = false; // disable increasing SIMLIB_OptStep,
211 } // accuracy is sufficient, but not well
212 if(SIMLIB_ERRNO) {
214 }
215
216 //--------------------------------------------------------------------------
217 // Computation is continuing, compute y(t2)
218 //--------------------------------------------------------------------------
219
220 if(wasContractStepFlag) {
221 // step reducing has been requested in half step and it is unpossible
222 RestoreState(dthlf, di, si, xi);// restore half step state
223 } else { // go to half step and complete the computation
224
225 GoToState(di, si, xi);
226
227 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
228 (*ip)->SetState(si[i] - A6[i] + A7[i] + A7[i]);
229 }
230
231 SIMLIB_StepStartTime += dthlf;
233
234 SIMLIB_Dynamic(); // evaluate new state of model (8)
235
236 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
237 // new state
238 (*ip)->SetState(si[i] + (A5[i] + 4.0*A7[i] + dthlf*(*ip)->GetDiff()) / 6.0);
239 }
240
241 if(StateCond()) { // check on changes of state conditions at end of step
242 goto begin_step;
243 }
244 }
245
246 //--------------------------------------------------------------------------
247 // Results of step have been accepted, take fresh step
248 //--------------------------------------------------------------------------
249
250 // increase step, if accuracy was good
251 // step increasing is allowed
252 // && method is not used to start multi-step method
253 if(DoubleStepFlag && !IsStartMode()) {
254 SIMLIB_OptStep += SIMLIB_OptStep; // step doubling
255 }
256 SIMLIB_OptStep = min(SIMLIB_OptStep,SIMLIB_MaxStep); // limit step size
257
258} // RKE::Integrate
259
260
261}
262// end
263
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 A6
Definition: ni_rke.h:25
Memory di
Definition: ni_rke.h:26
Memory A7
Definition: ni_rke.h:25
Memory si
Definition: ni_rke.h:26
Memory A5
Definition: ni_rke.h:25
Memory A1
Definition: ni_rke.h:25
StatusMemory xi
Definition: ni_rke.h:27
Memory A3
Definition: ni_rke.h:25
Memory A4
Definition: ni_rke.h:25
virtual void Integrate(void) override
Definition: ni_rke.cc:54
Memory A2
Definition: ni_rke.h:25
bool IsStartMode(void)
Definition: simlib.h:1154
static void StoreState(Memory &di, Memory &si, StatusMemory &xi)
store state of integrators and status variables
Definition: numint.cc:570
static void RestoreState(double dthlf, Memory &di, Memory &si, StatusMemory &xi)
restore state of integrators and status variables
Definition: numint.cc:594
static void GoToState(Memory &di, Memory &si, StatusMemory &xi)
move startpoint to given state
Definition: numint.cc:622
@ 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
bool SIMLIB_ConditionFlag
Definition: cond.cc:30
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-England method (default)
Main SIMLIB/C++ interface.