SIMLIB/C++  3.07
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
ni_rkf3.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 // ni_rkf3.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 3rd order
12 //
13 
14 ////////////////////////////////////////////////////////////////////////////
15 // interface
16 //
17 #include "simlib.h"
18 #include "internal.h"
19 #include "ni_rkf3.h"
20 #include <cmath>
21 #include <cstddef>
22 
23 
24 ////////////////////////////////////////////////////////////////////////////
25 // implementation
26 //
27 
28 namespace simlib3 {
29 
31 
32 
33 ////////////////////////////////////////////////////////////////////////////
34 // Runge-Kutta-Fehlberg's method 3rd order
35 //
36 /* Formula:
37 
38  k1 = h * f(t, y);
39  k2 = h * f(t + 0.5*h, y + 0.5*k1);
40  k3 = h * f(t + 0.75*h, y + 0.75*k2);
41  y += (2.0*k1 + 3.0*k2 + 4.0*k3) / 9.0;
42  t += h;
43  err = |-5.0*k1 + 6.0*k2 + 8.0*k3 - 9.0*h*f(t, y)| / 72.0;
44 */
45 
46 void RKF3::Integrate(void)
47 {
48  const double safety = 0.9; // keeps the new step from growing too large
49  const double max_ratio = 4.0; // ditto
50  const double pshrnk = 0.5; // coefficient for reducing step
51  const double pgrow = 1.0/3.0; // coefficient for increasing step
52  size_t i; // auxiliary variables for loops
53  Iterator ip, end_it; // to go through list of integrators
54  double ratio; // ratio for next step computation
55  double next_step; // recommended stepsize for next step
56  size_t n; // integrator with greatest error
57 
58  Dprintf((" RKF3 integration step ")); // print debugging info
59  Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
60 
61  end_it=LastIntegrator(); // end of container of integrators
62 
63  //--------------------------------------------------------------------------
64  // Step of method
65  //--------------------------------------------------------------------------
66 
67 begin_step:
68 
69  ///////////////////////////////////////////////////////// beginning of step
70 
71  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
72 
73  SIMLIB_ContractStepFlag = false; // clear reduce step flag
74  SIMLIB_ContractStep = 0.5*SIMLIB_StepSize; // implicitly reduce to half step
75 
76  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
77  A1[i] = SIMLIB_StepSize*(*ip)->GetOldDiff(); // compute coefficient
78  (*ip)->SetState((*ip)->GetOldState() + 0.5*A1[i]); // state (y) for next sub-step
79  }
80 
81  ////////////////////////////////////////////////////////////// 1/2 of step
82 
83  _SetTime(Time,SIMLIB_StepStartTime + 0.5*SIMLIB_StepSize); // substep's time
84  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
85 
86  SIMLIB_Dynamic(); // evaluate new state of model (y'=f(t,y)) (1)
87 
88  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
89  A2[i] = SIMLIB_StepSize*(*ip)->GetDiff();
90  (*ip)->SetState((*ip)->GetOldState() + 0.75*A2[i]);
91  }
92 
93  ////////////////////////////////////////////////////////////// 3/4 of step
94 
95  _SetTime(Time,SIMLIB_StepStartTime + 0.75*SIMLIB_StepSize); //substep's time
96  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
97 
98  SIMLIB_Dynamic(); // evaluate new state of model (2)
99 
100  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
101  A3[i] = SIMLIB_StepSize*(*ip)->GetDiff();
102  (*ip)->SetState((*ip)->GetOldState()
103  + (2.0*A1[i] + 3.0*A2[i] + 4.0*A3[i]) / 9.0);
104  }
105 
106  ////////////////////////////////////////////////////////////// 1.0 of step
107 
108  _SetTime(Time, SIMLIB_StepStartTime+SIMLIB_StepSize); // goto end time point
110 
111  SIMLIB_Dynamic(); // evaluate new state of model (3)
112 
113  //--------------------------------------------------------------------------
114  // Check on accuracy of numerical integration, estimate error
115  //--------------------------------------------------------------------------
116 
117  SIMLIB_ERRNO = 0; // OK
118  ratio = 8.0; // 2^3 - ratio for next step computation - initial value
119  n=0; // integrator with greatest error
120  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
121  double eerr; // estimated error
122  double terr; // greatest allowed error
123 
124  eerr = fabs( -5.0*A1[i] // estimation
125  + 6.0*A2[i]
126  + 8.0*A3[i]
127  - 9.0*SIMLIB_StepSize*(*ip)->GetDiff()
128  ) / 72.0;
129  terr = fabs(SIMLIB_AbsoluteError)
130  + fabs(SIMLIB_RelativeError*(*ip)->GetState());
131  if(terr < eerr*ratio) { // avoid arithmetic overflow
132  ratio = terr/eerr; // find the lowest ratio
133  n=i; // remember the integrator
134  }
135  } // for
136 
137  Dprintf(("R: %g",ratio));
138 
139  if(ratio < 1.0) { // error is too large, reduce stepsize
140  ratio = pow(ratio,pshrnk); // coefficient for reduce
141  Dprintf(("Down: %g",ratio));
142  if(SIMLIB_StepSize > SIMLIB_MinStep) { // reducing step is possible
144  SIMLIB_StepSize = SIMLIB_OptStep;
145  IsEndStepEvent = false; // no event will be at the end of the step
146  goto begin_step; // compute again with smaller step
147  }
148  // reducing step is unpossible
149  SIMLIB_ERRNO++; // requested accuracy cannot be achieved
150  _Print("\n Integrator[%lu] ",(unsigned long)n);
152  next_step = SIMLIB_StepSize;
153  } else { // allowed tolerantion is fulfiled
154  if(!IsStartMode()) { // method is not used for start multi-step method
155  ratio = min(pow(ratio,pgrow),max_ratio); // coefficient for increase
156  Dprintf(("Up: %g",ratio));
157  next_step = min(safety*ratio*SIMLIB_StepSize, SIMLIB_MaxStep);
158  } else {
159  next_step = SIMLIB_StepSize;
160  }
161  }
162 
163  //--------------------------------------------------------------------------
164  // Analyse system at the end of the step
165  //--------------------------------------------------------------------------
166 
167  if(StateCond()) { // check on changes of state conditions at end of step
168  goto begin_step;
169  }
170 
171  //--------------------------------------------------------------------------
172  // Results of step have been accepted, take fresh step
173  //--------------------------------------------------------------------------
174 
175  // increase step, if accuracy was good
176  SIMLIB_OptStep = next_step;
177 
178 } // RKF3::Integrate
179 
180 }
181 // end of ni_rkf3.cc
182 
static bool IsEndStepEvent
Definition: simlib.h:1079
Memory A3
Definition: ni_rkf3.h:24
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
Memory A1
Definition: ni_rkf3.h:24
Memory A2
Definition: ni_rkf3.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
virtual void Integrate(void) override
Definition: ni_rkf3.cc:46
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
bool IsStartMode(void)
Definition: simlib.h:1154
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
#define Dprintf(f)
Definition: internal.h:100
Runge-Kutta-Fehlberg 3rd order.
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39