SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
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
28namespace 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
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
67begin_step:
68
69 ///////////////////////////////////////////////////////// beginning of step
70
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
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
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
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 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
virtual void Integrate(void) override
Definition: ni_rkf3.cc:46
Memory A3
Definition: ni_rkf3.h:24
Memory A2
Definition: ni_rkf3.h:24
Memory A1
Definition: ni_rkf3.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 3rd order.
Main SIMLIB/C++ interface.