SIMLIB/C++  3.07
ni_euler.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 // ni_euler.cc
3 //
4 // Copyright (c) 1991-2004 Petr Peringer
5 // Copyright (c) 1996-1997 David Leska
6 //
7 // This library is licensed under GNU Library GPL. See the file COPYING.
8 //
9 
10 //
11 // numerical integration: Euler's method
12 //
13 
14 ////////////////////////////////////////////////////////////////////////////
15 // interface
16 //
17 #include "simlib.h"
18 #include "internal.h"
19 #include "ni_euler.h"
20 #include <cmath>
21 #include <cstddef>
22 
23 
24 ////////////////////////////////////////////////////////////////////////////
25 // implementation
26 //
27 
28 namespace simlib3 {
29 
31 
32 
33 ////////////////////////////////////////////////////////////////////////////
34 // Euler's method
35 //
36 /* Formula:
37 
38  y'(t) = f(t, y);
39  y(t+h/2) = y(t) + h/2 * y'(t);
40  y'(t+h/2) = f(t+h/2, y(t+h/2));
41  y(t+h) = y(t+h/2) + h/2 * y'(t+h/2);
42  y'(t+h) = f(t+h, y(t+h));
43  err = h * |y'(t) - y'(t+h/2)|;
44 */
45 
46 void EULER::Integrate(void)
47 {
48  const double err_coef = 0.02; // limits an error range
49  static double dthlf; // half step
50  size_t i; // auxiliary variables for loops to go through list
51  Iterator ip, end_it; // of integrators
52  static bool DoubleStepFlag; // flag - allow increasing (doubling) the step
53 
54  Dprintf((" Euler integration step ")); // print debugging info
55  Dprintf((" Time = %g, optimal step = %g", (double)Time, OptStep));
56 
57  end_it=LastIntegrator(); // end of container of integrators
58 
59  //--------------------------------------------------------------------------
60  // Step of method
61  //--------------------------------------------------------------------------
62 
63 begin_step: // beginning of step
64 
65  SIMLIB_StepSize = max(SIMLIB_StepSize, SIMLIB_MinStep); // low step limit
66 
67  dthlf = 0.5*SIMLIB_StepSize; // half step
68 
69  SIMLIB_ContractStepFlag = false; // clear reduce step flag
70  SIMLIB_ContractStep = 0.5*dthlf; // implicitly reduce to half
71 
72  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
73  A[i] = (*ip)->GetOldDiff();
74  (*ip)->SetState((*ip)->GetOldState() + dthlf*(*ip)->GetDiff()); // state y(t+h/2)
75  }
76 
77  ////////////////////////////////////////////////////////////// 1/2 of step
78 
79  _SetTime(Time, SIMLIB_StepStartTime+dthlf);
81 
82  SIMLIB_Dynamic(); // compute new state of model (1)
83 
84  if(StateCond()) { // check on changes of state conditions in 1/2 of step
85  goto begin_step;
86  }
87 
88  bool wasContractStepFlag = SIMLIB_ContractStepFlag; // remember value
89  SIMLIB_ContractStepFlag = false; // not reduce step
90  SIMLIB_ContractStep = dthlf; // implicitly reduce to half of step
91 
92  StoreState(di, si, xi); // store values in 1/2 of step
93 
94  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
95  // difference of differentiations for error estimation
96  A[i] -= (*ip)->GetDiff();
97  (*ip)->SetState(si[i] + dthlf*(*ip)->GetDiff());
98  }
99 
100  //////////////////////////////////////////////////////////// end of step
101 
104 
105  SIMLIB_Dynamic(); // compute new state of model (2)
106 
107  //--------------------------------------------------------------------------
108  // Check on accuracy of numerical integration, estimate error
109  //--------------------------------------------------------------------------
110 
111  DoubleStepFlag = true; // allow doubling the step
112  SIMLIB_ERRNO = 0; // OK
113  for(ip=FirstIntegrator(),i=0; ip!=end_it; ip++,i++) {
114  double eerr; // estimated error
115  double terr; // greatest allowed error
116 
117  eerr = fabs(SIMLIB_StepSize*A[i]); // error estimation
118  terr = SIMLIB_AbsoluteError + fabs(SIMLIB_RelativeError*si[i]);
119 
120  if(eerr < err_coef*terr) // allowed tolerantion is fulfiled with provision
121  continue;
122 
123  if(eerr > terr) { // allowed tolerantion is overfulfiled
124  if(SIMLIB_StepSize > SIMLIB_MinStep) { // reducing step is possible
125  SIMLIB_OptStep = 0.5*SIMLIB_StepSize; // halve optimal step
126  if(SIMLIB_OptStep < SIMLIB_MinStep) { // limit of optimal step
128  }
130  IsEndStepEvent = false;
131  goto begin_step; // compute again with smaller step
132  }
133  // reducing step is unpossible
134  SIMLIB_ERRNO++; // requested accuracy cannot be achieved
135  _Print("\n Integrator[%lu] ",(unsigned long)i);
136  if(SIMLIB_ConditionFlag) // event has been within the step
137  break;
138  }
139 
140  DoubleStepFlag = false; // disable increasing SIMLIB_OptStep,
141  // accuracy is sufficient, but not well
142  } // for
143 
144  if(SIMLIB_ERRNO) {
146  }
147 
148  //--------------------------------------------------------------------------
149  // Computation is continuing, compute y(t+h)
150  //--------------------------------------------------------------------------
151 
152  if(wasContractStepFlag) {
153  // step reducing has been requested in half step and it is unpossible
154  RestoreState(dthlf, di, si, xi); // restore halfstep state
155  } else { // go to half step and complete the computation
156 
157  GoToState(di, si, xi);
158 
159  SIMLIB_StepStartTime += dthlf;
160  SIMLIB_DeltaTime = double(Time) - SIMLIB_StepStartTime;
161 
162  //-----------------------------------------------------------------------
163  // Analyse system at the end of the step
164  //-----------------------------------------------------------------------
165 
166  if(StateCond()) { // check on changes of state conditions at end of step
167  goto begin_step;
168  }
169  }
170 
171  //--------------------------------------------------------------------------
172  // Results of step have been accepted, take fresh step
173  //--------------------------------------------------------------------------
174 
175  // increase step, if accuracy was good
176  // step increasing is allowed
177  // && method is not used to start multi-step method
178  if(DoubleStepFlag && !IsStartMode()) {
179  SIMLIB_OptStep += SIMLIB_OptStep; // step doubling
180  }
181  SIMLIB_OptStep = min(SIMLIB_OptStep,SIMLIB_MaxStep); // limit step size
182 
183 } // EULER::Integrate
184 
185 
186 }
187 
Memory si
Definition: ni_euler.h:24
static bool IsEndStepEvent
Definition: simlib.h:1079
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
StatusMemory xi
Definition: ni_euler.h:25
const double & OptStep
optimal integration step
Definition: intg.cc:49
static void StoreState(Memory &di, Memory &si, StatusMemory &xi)
store state of integrators and status variables
Definition: numint.cc:570
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
Memory A
Definition: ni_euler.h:24
double SIMLIB_RelativeError
relative error
Definition: intg.cc:43
int SIMLIB_ERRNO
Definition: intg.cc:32
static void RestoreState(double dthlf, Memory &di, Memory &si, StatusMemory &xi)
restore state of integrators and status variables
Definition: numint.cc:594
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
virtual void Integrate(void) override
Definition: ni_euler.cc:46
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.
Modified Euler method.
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
static void GoToState(Memory &di, Memory &si, StatusMemory &xi)
move startpoint to given state
Definition: numint.cc:622
bool SIMLIB_ConditionFlag
Definition: cond.cc:30
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
Memory di
Definition: ni_euler.h:24
double SIMLIB_OptStep
optimal step
Definition: intg.cc:37
double SIMLIB_MaxStep
max. step
Definition: intg.cc:39