SIMLIB/C++  3.07
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 //
28 namespace 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 
54 void RKE::Integrate(void)
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 
72 begin_step:
73 
74  ///////////////////////////////////////////////////////// beginning of step
75 
76  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
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
91  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
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 
111  _SetTime(Time, SIMLIB_StepStartTime+dthlf);
112  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
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);
141  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
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
189  terr = SIMLIB_AbsoluteError + fabs(SIMLIB_RelativeError*si[i]);
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;
232  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
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 
Memory di
Definition: ni_rke.h:26
Memory si
Definition: ni_rke.h:26
Memory A1
Definition: ni_rke.h:25
static bool IsEndStepEvent
Definition: simlib.h:1079
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
const double & OptStep
optimal integration step
Definition: intg.cc:49
static void StoreState(Memory &di, Memory &si, StatusMemory &xi)
store state of integrators and status variables
Definition: numint.cc:570
Memory A3
Definition: ni_rke.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 A7
Definition: ni_rke.h:25
double SIMLIB_RelativeError
relative error
Definition: intg.cc:43
int SIMLIB_ERRNO
Definition: intg.cc:32
static void RestoreState(double dthlf, Memory &di, Memory &si, StatusMemory &xi)
restore state of integrators and status variables
Definition: numint.cc:594
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
StatusMemory xi
Definition: ni_rke.h:27
double SIMLIB_StepSize
actual step
Definition: intg.cc:40
static bool StateCond(void)
check on changes of state conditions
Definition: numint.cc:175
Memory A5
Definition: ni_rke.h:25
double min(double a, double b)
Definition: internal.h:285
double SIMLIB_AbsoluteError
absolute error
Definition: intg.cc:42
bool SIMLIB_ContractStepFlag
requests shorter step
Definition: intg.cc:58
Internal header file for SIMLIB/C++.
static Iterator LastIntegrator(void)
Definition: simlib.h:1084
Memory A4
Definition: ni_rke.h:25
Memory A6
Definition: ni_rke.h:25
static Iterator FirstIntegrator(void)
Definition: simlib.h:1081
Main SIMLIB/C++ interface.
virtual void Integrate(void) override
Definition: ni_rke.cc:54
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
static void GoToState(Memory &di, Memory &si, StatusMemory &xi)
move startpoint to given state
Definition: numint.cc:622
bool SIMLIB_ConditionFlag
Definition: cond.cc:30
double SIMLIB_MinStep
minimal step
Definition: intg.cc:38
bool IsStartMode(void)
Definition: simlib.h:1154
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
#define Dprintf(f)
Definition: internal.h:100
Memory A2
Definition: ni_rke.h:25
Runge-Kutta-England method (default)
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39