libode
Easy to compile, fast ODE integrators as C++ classes
Loading...
Searching...
No Matches
ode_adaptive.cc
Go to the documentation of this file.
1
2
3#include "ode_adaptive.h"
4
5namespace ode {
6
7OdeAdaptive::OdeAdaptive (unsigned long neq, bool need_jac) :
8 OdeBase (neq, need_jac) {
9
10 //rejected step counter
11 nrej_ = 0;
12 //error tolerances
13 abstol_ = 1e-6;
14 reltol_ = 1e-6;
15 //hard upper time step limit
16 dtmax_ = INFINITY;
17 //previous solution for step reversals
18 solprev_ = new double[neq];
19}
20
22 delete [] solprev_;
23}
24
25//---------------------------------------
26//integration with adaptive time stepping
27
28void OdeAdaptive::solve_adaptive_ (double tint, double dt0, bool extra) {
29
30 //store the time step
31 double dt = dt0;
32 //stopping time
33 double tend = t_ + tint;
34 //don't step over the edge
35 if (t_ + dt > tend) dt = tend - t_;
36 //solve to the stopping time
37 while ( !solve_done_adaptive(tend) ) {
38 //take a step, which might be rejected
39 step_adaptive_(dt, extra);
40 //compute a new time step
41 dt = dt_adapt_(tend);
42 }
43}
44
45void OdeAdaptive::solve_adaptive (double tint, double dt0, bool extras) {
46
47 //checks
48 check_pre_solve(tint, dt0);
49 if (extras) {
50 //extra initial things
52 //solve
53 solve_adaptive_(tint, dt0, true);
54 //extra completion things (to be overridden in derived class)
56 } else {
57 solve_adaptive_(tint, dt0, false);
58 }
59}
60
61void OdeAdaptive::solve_adaptive (double tint, double dt0, const char *dirout, int inter) {
62
63 //checks
64 check_pre_solve(tint, dt0);
65 if (inter < 1) ode_print_exit("inter must be greater than or equal to 1");
66 //indices
67 unsigned long i, j;
68 //output file strings
69 std::string fnout;
70 dirout_ = dirout;
71 //output vectors
72 std::vector<double> tout;
73 std::vector<double> *solout = new std::vector<double>[neq_];
74 //stopping time
75 double tend = t_ + tint;
76
77 //extra initial things (to be overridden in derived class)
79
80 //store values at time zero
81 for (i=0; i<neq_; i++) solout[i].push_back( sol_[i] );
82 tout.push_back( t_ );
83 //solve while storing solution values
84 double dt = dt0;
85 bool suc;
86 j = 0;
87 while ( !solve_done_adaptive(tend) ) {
88 //take a step
89 suc = step_adaptive_(dt);
90 //compute a new time step
91 dt = dt_adapt_(tend);
92 //if the step was successful, see if values should be stored
93 if (suc) {
94 //count another successful step
95 j++;
96 //check if storing
97 if ( j % inter == 0 ) {
99 //store
100 for (i=0; i<neq_; i++) solout[i].push_back( sol_[i] );
101 tout.push_back( t_ );
102 }
103 }
104 }
105 //store the final time step if need be
106 if ( j-1 % inter != 0 ) {
107 for (i=0; i<neq_; i++) solout[i].push_back( sol_[i] );
108 tout.push_back( t_ );
109 }
110
111 //write output
112 for (i=0; i<neq_; i++) {
113 fnout = dirout_ + "/" + name_ + "_" + ode_int_to_string(i);
114 ode_write(fnout.data(), solout[i].data(), solout[i].size());
115 }
116 fnout = dirout_ + "/" + name_ + "_t";
117 ode_write(fnout.data(), tout.data(), tout.size());
118
119 //extra completion things (to be overridden in derived class)
120 after_solve();
121
122 //clear output directory
123 dirout_ = "";
124}
125
126void OdeAdaptive::solve_adaptive (double tint, double dt0, unsigned long nsnap, const char *dirout) {
127 //checks
128 check_pre_solve(tint, dt0);
129 //stopping time
130 double tend = t_ + tint;
131 //make an array of the snap times
132 double *tsnap = new double[nsnap];
133 for (unsigned long i=0; i<nsnap; i++) tsnap[i] = t_ + i*(tend - t_)/double(nsnap - 1);
134 //call the other snapping function with the computed snap times
135 solve_adaptive(dt0, tsnap, nsnap, dirout);
136 //free the snap times
137 delete [] tsnap;
138}
139
140void OdeAdaptive::solve_adaptive (double dt0, double *tsnap, unsigned long nsnap, const char *dirout) {
141
142 //checks
143 check_pre_snaps(dt0, tsnap, nsnap);
144 //index
145 unsigned long i;
146 //store the output directory
147 dirout_ = dirout;
148
149 //extra initial things (to be overridden in derived class)
150 before_solve();
151
152 //solve to each snap time and take a snap
153 double dt = dt0;
154 for (i=0; i<nsnap; i++) {
155 //basic adaptive solve
156 solve_adaptive_(tsnap[i] - t_, dt);
157 //write the current solution to file
158 snap(dirout, i, t_);
159 //store the estimate for the current best time step
160 dt = dt_adapt_(INFINITY);
161 }
162 //write the snap times
163 if ( !silent_snap_ )
164 ode_write((dirout_ + "/" + name_ + "_snap_t").data(), tsnap, nsnap);
165
166 //extra completion things (to be overridden in derived class)
167 after_solve();
168
169 //clear output directory
170 dirout_ = "";
171}
172
173//--------------
174//adapting stuff
175
176void OdeAdaptive::adapt (double abstol, double reltol) {
177 (void)abstol;
178 (void)reltol;
179}
180
181bool OdeAdaptive::is_rejected () { return(false); }
182
184 ode_print_exit("An adaptive solving method was called without a time step choosing algorithm implemented! You must at least implement the dt_adapt() function to use solve_adaptive().");
185 return(1);
186}
187
189
190 if ( ode_is_close(t_, tend, 1e-13) || (t_ >= tend) )
191 return(true);
192 return(false);
193}
194
195//--------------
196//wrappers
197
198bool OdeAdaptive::step_adaptive_ (double dt, bool extra) {
199
200 //store the current solution in case the step is rejected
201 memcpy(solprev_, sol_, neq_*sizeof(double));
202 //store the time step for access in derived classes
203 dt_ = dt;
204 //call the basic stepper
205 step_(dt);
206 //count the step, even if it's subsequently rejected
207 nstep_++;
208 //execute adaptive calculations
210 //see if the step should be rejected
211 if ( is_rejected() ) {
212 //reject the step by putting solprev back into sol
213 memcpy(sol_, solprev_, neq_*sizeof(double));
214 //count the rejection
215 nrej_++;
216 //return failure
217 return(false);
218 } else {
219 //increment the time
220 t_ += dt;
221 //check for nans and infs
222 if (nstep_ % icheck_ == 0) check_sol_integrity();
223 //do any extra stuff
224 if (extra) after_step(t_);
225 //return success
226 return(true);
227 }
228}
229
230double OdeAdaptive::dt_adapt_ (double tend) {
231
232 //get next time step from virtual function
233 double dt = dt_adapt();
234 //make sure the new dt doesn't exceed the stopping time
235 if ( tend < t_ + dt*1.01 ) dt = tend - t_;
236 //make sure the new dt is not larger than the maximum time step
237 if ( dt > dtmax_ ) dt = dtmax_;
238
239 return(dt);
240}
241
242} // namespace ode
double reltol_
absolute error tolerance
double dt_adapt_(double tend)
wrapper around dt_adapt() to perform additional checks
long unsigned nrej_
counter for rejected steps
double dtmax_
maximum allowable time step
void solve_adaptive_(double tint, double dt0, bool extra=true)
integrates without output or any counters, trackers, extra functions...
virtual ~OdeAdaptive()
destructs
bool solve_done_adaptive(double tend)
determines whether an adaptive solve is finished
bool step_adaptive_(double dt, bool extra=true)
executes a single time and calls all necessary adapting functions
double abstol_
absolute error tolerance
void solve_adaptive(double tint, double dt0, bool extras=true)
integrates for a specified duration of independent variable without output
virtual bool is_rejected()
retreives a bool determining whether a step is accepted/rejected, false by default
OdeAdaptive(unsigned long neq, bool need_jac)
constructs
virtual double dt_adapt()
retrieves the best time step for the next step
virtual void adapt(double abstol, double reltol)
executes whatever calculations need to be performed for adapting, including a determination of whethe...
Lowest base class for all solvers.
Definition ode_base.h:184
virtual void after_capture(double t)
does any extra stuff only when a step is captured
Definition ode_base.cc:330
long unsigned icheck_
interval of steps after which to check for nans and infs (zero to ignore)
Definition ode_base.h:339
unsigned long neq_
number of equations in the system of ODEs
Definition ode_base.h:327
double t_
time, initialized to zero
Definition ode_base.h:329
std::string name_
the "name" of the system, which is used for output
Definition ode_base.h:317
virtual void before_solve()
does any extra stuff before starting a solve
Definition ode_base.cc:323
virtual void after_solve()
does any extra stuff after completing a solve
Definition ode_base.cc:342
double dt_
time step is stored and updated during solves
Definition ode_base.h:331
void snap(std::string dirout, long isnap, double tsnap)
writes the current value of the solution to a binary file
Definition ode_base.cc:122
long unsigned nstep_
number of time steps
Definition ode_base.h:335
virtual void step_(double dt)=0
advances a single time step (without changing counters or the time) and must be defined in the derive...
void check_sol_integrity()
checks solution for nans and infs, exiting the program if they're found
Definition ode_base.cc:151
bool silent_snap_
whether to skip writing the solution vector to file when snapping but still execute after_snap()
Definition ode_base.h:325
void check_pre_snaps(double dt, double *tsnap, unsigned long nsnap)
checks that snap times are monotonically increasing and > current time
Definition ode_base.cc:169
double * sol_
array for the solution, changing over time
Definition ode_base.h:333
virtual void after_step(double t)
does any extra stuff after each step
Definition ode_base.cc:325
void check_pre_solve(double tint, double dt)
checks that a solve can be performed with given tend and dt values
Definition ode_base.cc:161
std::string dirout_
output directory if one is being used by a solver
Definition ode_base.h:321
void ode_print_exit(const char *msg)
print a message and exit with failure
Definition ode_io.cc:17
void ode_write(char const *fn, T *a, unsigned long n)
write an array to a binary file
Definition ode_io.h:27
std::string ode_int_to_string(long i)
converts an integer into a string
Definition ode_io.cc:25
bool ode_is_close(double a, double b, double thresh)
Checks if two numbers are very close to each other.
Definition ode_util.cc:17