SIMLIB/C++  3.07
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 //
27 namespace 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 
59 void RKF5::Integrate(void)
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 
80 begin_step:
81 
82  ///////////////////////////////////////////////////////// beginning of step
83 
84  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
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
97  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
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
109  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
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 
121  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
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 
136  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
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 
152  SIMLIB_DeltaTime = double(Time)-SIMLIB_StepStartTime;
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
168  SIMLIB_Dynamic();
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
201  SIMLIB_StepSize = SIMLIB_OptStep;
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 bool IsEndStepEvent
Definition: simlib.h:1079
Memory A5
Definition: ni_rkf5.h:24
int _Print(const char *fmt,...)
output of messages to stdout, too
Definition: print.cc:68
Runge-Kutta-Fehlberg 5th order.
Memory A2
Definition: ni_rkf5.h:24
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
Memory A4
Definition: ni_rkf5.h:24
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
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
double SIMLIB_StepSize
actual step
Definition: intg.cc:40
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
bool SIMLIB_ContractStepFlag
requests shorter step
Definition: intg.cc:58
Internal header file for SIMLIB/C++.
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
virtual void Integrate(void) override
Definition: ni_rkf5.cc:59
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 A3
Definition: ni_rkf5.h:24
Memory A6
Definition: ni_rkf5.h:24
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
Memory A1
Definition: ni_rkf5.h:24
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39