SIMLIB/C++  3.07
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 //
28 namespace 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 
53 void ABM4::Integrate(void)
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 
76 begin_step:
77 
78  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
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 
129  _SetTime(Time,SIMLIB_StepStartTime + SIMLIB_StepSize); // endpoint time
130  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
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 
static bool IsEndStepEvent
Definition: simlib.h:1079
int _Print(const char *fmt,...)
output of messages to stdout, too
Definition: print.cc:68
Memory Z[abm_ord]
Definition: ni_abm4.h:29
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
int ABM_Count
Definition: ni_abm4.h:28
virtual bool PrepareStep(void) override
prepare the object for the step of integration
Definition: ni_abm4.cc:217
virtual void Integrate(void) override
Definition: ni_abm4.cc:53
const double & OptStep
optimal integration step
Definition: intg.cc:49
const int abm_ord
Definition: ni_abm4.h:20
Adams-Bashforth-Moulton 4th order.
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
virtual void Integrate(void)=0
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
bool SIMLIB_ConditionFlag
Definition: cond.cc:30
double SIMLIB_MinStep
minimal step
Definition: intg.cc:38
SingleStepMethod * SlavePtr(void)
return pointer to the starting method (initialize it also)
Definition: numint.cc:435
double SIMLIB_DeltaTime
Time-SIMLIB_StepStartTime.
Definition: intg.cc:35
#define Dprintf(f)
Definition: internal.h:100
virtual bool PrepareStep(void) override
prepare the object for the step of integration
Definition: numint.cc:449
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
Memory PRED
Definition: ni_abm4.h:30
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39