SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
ni_abm4.cc
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2// ni_abm4.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: Adams-Bashforth-Moulton's
12// predictor-corrector 4th order
13//
14
15////////////////////////////////////////////////////////////////////////////
16// interface
17//
18#include "simlib.h"
19#include "internal.h"
20#include "ni_abm4.h"
21#include <cmath>
22#include <cstddef>
23
24
25////////////////////////////////////////////////////////////////////////////
26// implementation
27//
28namespace simlib3 {
29
31
32
33////////////////////////////////////////////////////////////////////////////
34// Adams-Bashforth-Moulton's predictor-corrector 4th order
35//
36/* Formula:
37
38 for i = 0 to 2 loop
39 z[i] = f(t,y)
40 Self-start by rkf5
41 end for
42 z[3] = f(t,y)
43 pred = y + (55*z[3] - 59*z[2] + 37*z[1] - 9*z[0]) * h/24
44 for i = 0 to 2 loop
45 z[i] = z[i+1]
46 end for
47 t += h
48 z3 = f(t,pred)
49 corr = y + (9*z3 + 19*z[2] - 5*z[1] + z[0]) * h/24
50 err = 0.5 * |pred - corr|
51*/
52
54{
55 const double err_lo = 0.75; // limits an error range
56 const double err_hi = 1.00; // limits an error range
57 const int max_dbl = 8; // avoid stepsize growing too quickly
58 size_t i; // auxiliary variables
59 Iterator ip, end_it; // for loops to go through container of integrators
60 bool DoubleStepFlag; // allows doubling step
61 // WARNING: following variables must be static !!!
62 static double PrevStep; // previous stepsize
63 static int ind = 0; // base index to arrays with values from previous steps
64 static int DoubleCount = 0; // number of good steps for doubling stepsize
65
66 Dprintf((" ABM4 integration step ")); // print debugging info
67 Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
68
69 //--------------------------------------------------------------------------
70 // Step of method
71 //--------------------------------------------------------------------------
72
73 end_it=LastIntegrator(); // end of container of integrators
74 DoubleStepFlag = true; // allow doubling stepsize
75
76begin_step:
77
79
80 if(ABM_Count>0 && PrevStep!=SIMLIB_StepSize) { // stepsize has been changed
81 ABM_Count = 0;
82 Dprintf(("NEW START, Time = %g",(double)Time));
83 }
84 PrevStep = SIMLIB_StepSize;
85
86 Dprintf(("counter: %d, Time = %g",ABM_Count,(double)Time));
87
88 //-----------------------------------------------------------------------
89 // method must be started
90 //-----------------------------------------------------------------------
91
92 if(ABM_Count <= abm_ord-2) {
93 Dprintf(("start, step = %g, Time = %g",SIMLIB_StepSize,(double)Time));
94 ind = 0;
95 DoubleCount = 0;
96 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
97 Z[ABM_Count][i] = (*ip)->GetOldDiff(); // store values for next steps
98 }
99 ABM_Count++; // increment counter of starts
100 SlavePtr()->Integrate(); // call starting method (slave)
101
102 //-----------------------------------------------------------------------
103 // predictor-corrector
104 //-----------------------------------------------------------------------
105
106 } else {
107 SIMLIB_ContractStepFlag = false; // clear reduce step flag
108 SIMLIB_ContractStep = 0.5*SIMLIB_StepSize; // reduce to quater of step
109 Dprintf(("own-method, step = %g, Time = %g",
110 SIMLIB_StepSize,(double)Time));
111
112 //-----------------------------------------------------------------------
113 // compute predictor
114 //-----------------------------------------------------------------------
115
116 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
117 // store values for next steps
118 Z[(ind+3)%abm_ord][i] = (*ip)->GetOldDiff();
119 // predictor
120 (*ip)->SetState( PRED[i] = (*ip)->GetOldState() +
121 ( 55.0 * Z[(ind+3)%abm_ord][i]
122 - 59.0 * Z[(ind+2)%abm_ord][i]
123 + 37.0 * Z[(ind+1)%abm_ord][i]
124 - 9.0 * Z[ind][i]
125 ) * (SIMLIB_StepSize / 24.0)
126 );
127 }
128
131 SIMLIB_Dynamic(); // evaluate new state of model
132 ind=(ind+1)%abm_ord; // increment base index
133
134 //-----------------------------------------------------------------------
135 // compute corrector
136 //-----------------------------------------------------------------------
137
138 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
139 (*ip)->SetState( (*ip)->GetOldState()
140 + ( 9.0 * (*ip)->GetDiff()
141 + 19.0 * Z[(ind+2)%abm_ord][i]
142 - 5.0 * Z[(ind+1)%abm_ord][i]
143 + Z[ind][i]
144 ) * (SIMLIB_StepSize / 24.0)
145 );
146 }
147
148 //-----------------------------------------------------------------------
149 // estimate error
150 //-----------------------------------------------------------------------
151
152 SIMLIB_ERRNO = 0;
153 for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
154 double eerr; // estimated error
155 double terr; // greatest allowed error
156
157 eerr = 0.5 * fabs(PRED[i] - (*ip)->GetState()); // error estimation
158 terr = SIMLIB_AbsoluteError + fabs(SIMLIB_RelativeError*(*ip)->GetState());
159
160 if(eerr < err_lo*terr) // tolerantion is fulfiled with provision
161 continue;
162
163 if(eerr > err_hi*terr) { // tolerantion is overfulfiled
164 if(SIMLIB_StepSize>SIMLIB_MinStep) { // reducing step is possible
165 SIMLIB_OptStep = 0.25*SIMLIB_StepSize; // quater optimal step
166 if(SIMLIB_OptStep < SIMLIB_MinStep) { // limit of optimal step
168 }
170 IsEndStepEvent = false;
171 goto begin_step; // compute again with smaller step
172 }
173 // reducing step is unpossible
174 SIMLIB_ERRNO++; // requested accuracy cannot be achieved
175 _Print("\n Integrator[%i] ",i);
176 if(SIMLIB_ConditionFlag) // event was in half step, step reducing was
177 break; // unpossible and accuracy cannot be achieved
178 }
179 DoubleStepFlag = false; // disable increasing SIMLIB_OptStep,
180 } // accuracy is sufficient, but not well
181 if(SIMLIB_ERRNO) {
183 }
184
185 //-----------------------------------------------------------------------
186 // Analyse system at the end of the step
187 //-----------------------------------------------------------------------
188
189 if(StateCond()) { // check on changes of state conditions at end of step
190 goto begin_step;
191 }
192
193 //-----------------------------------------------------------------------
194 // Results of step have been accepted, take fresh step
195 //-----------------------------------------------------------------------
196
197 // if accuracy has been good, increment counter
198 if(DoubleStepFlag) {
199 DoubleCount++;
200 } else {
201 DoubleCount = 0;
202 }
203 // if accuracy has been good max_dbl-times in previous steps,
204 // increase stepsize
205 if(DoubleCount >= max_dbl) {
206 DoubleCount = 0;
208 }
209 }
210} // ABM4::Integrate
211
212
213////////////////////////////////////////////////////////////////////////////
214// ABM4::PrepareStep
215// prepare object for integration step
216//
218{
219 Dprintf(("ABM4::PrepareStep()"));
220 // prepare inherited part
222 ABM_Count = 0; // method will have to be restarted
223 return true; // some changes
224 }
225 return false; // no changes
226} // ABM4::PrepareStep
227
228}
229// end
230
virtual bool PrepareStep(void) override
prepare the object for the step of integration
Definition: ni_abm4.cc:217
int ABM_Count
Definition: ni_abm4.h:28
Memory Z[abm_ord]
Definition: ni_abm4.h:29
Memory PRED
Definition: ni_abm4.h:30
virtual void Integrate(void) override
Definition: ni_abm4.cc:53
static Iterator LastIntegrator(void)
Definition: simlib.h:1084
virtual void Integrate(void)=0
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
SingleStepMethod * SlavePtr(void)
return pointer to the starting method (initialize it also)
Definition: numint.cc:435
virtual bool PrepareStep(void) override
prepare the object for the step of integration
Definition: numint.cc:449
@ 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
const int abm_ord
Definition: ni_abm4.h:20
double SIMLIB_StepSize
actual step
Definition: intg.cc:40
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
Adams-Bashforth-Moulton 4th order.
Main SIMLIB/C++ interface.