Heidelberg Educational Numerics Library Version 0.27 (from 15 March 2021)
rungekutta.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil -*-
2#ifndef HDNUM_RUNGEKUTTA_HH
3#define HDNUM_RUNGEKUTTA_HH
4
5#include "vector.hh"
6#include "newton.hh"
7
12namespace hdnum {
15 template<class M>
17 {
18 public:
20 typedef typename M::size_type size_type;
21
23 typedef typename M::time_type time_type;
24
26 typedef typename M::number_type number_type;
27
36 : model(model_) , u(model.size())
37 {
38 A = A_;
39 b = b_;
40 c = c_;
41 s = A_.rowsize ();
42 dt = dt_;
43 n = model.size();
44 t = t_;
45 u = u_;
46 }
47
49 std::size_t size () const
50 {
51 return n*s;
52 }
53
56 {
58 for (int i = 0; i < s; i++)
59 {
60 xx[i].resize(n,number_type(0));
61 for(int k = 0; k < n; k++)
62 {
63 xx[i][k] = x[i*n + k];
64 }
65 }
67 for (int i = 0; i < s; i++)
68 {
69 f[i].resize(n, number_type(0));
70 model.f(t + c[i] * dt, u + xx[i], f[i]);
71 }
73 for (int i = 0; i < s; i++)
74 {
75 hr[i].resize(n, number_type(0));
76 }
77 for (int i = 0; i < s; i++)
78 {
80 for (int j = 0; j < s; j++)
81 {
82 sum.update(dt*A[i][j], f[j]);
83 }
84 hr[i] = xx[i] - sum;
85 }
86 //translating hr into result
87 for (int i = 0; i < s; i++)
88 {
89 for (int j = 0; j < n; j++)
90 {
91 result[i*n + j] = hr[i][j];
92 }
93 }
94 }
95
98 {
100 for (int i = 0; i < s; i++)
101 {
102 xx[i].resize(n);
103 for(int k = 0; k < n; k++)
104 {
105 xx[i][k] = x[i*n + k];
106 }
107 }
108 DenseMatrix<number_type> I (n, n, 0.0);
109 for (int i = 0; i < n; i++)
110 {
111 I[i][i] = 1.0;
112 }
113 for (int i = 0; i < s; i++)
114 {
115 for (int j = 0; j < s; j++)
116 {
119 model.f_x(t+c[j]*dt, u + xx[j],H);
120 J.update(-dt*A[i][j],H);
121 if(i==j) //add I on diagonal
122 {
123 J+=I;
124 }
125 for (int k = 0; k < n; k++)
126 {
127 for (int l = 0; l < n; l++)
128 {
129 result[n * i + k][n * j + l] = J[k][l];
130 }
131 }
132 }
133 }
134 }
135
136 private:
137 const M& model;
138 time_type t, dt;
140 int n, s; // dimension of matrix A and model.size
141 DenseMatrix<number_type> A; // A, b, c as in the butcher tableau
144 };
145
146
156 template<class M, class S = Newton>
158 {
159 public:
161 typedef typename M::size_type size_type;
162
164 typedef typename M::time_type time_type;
165
167 typedef typename M::number_type number_type;
168
174 : model(model_), u(model.size()), w(model.size()), K(A_.rowsize ())
175 {
176 A = A_;
177 b = b_;
178 c = c_;
179 s = A_.rowsize ();
180 n = model.size();
181 model.initialize(t,u);
182 dt = 0.1;
183 for (int i = 0; i < s; i++)
184 {
185 K[i].resize(n, number_type(0));
186 }
187 sigma = 0.01;
188 verbosity = 0;
189
190 if (A_.rowsize()!=A_.colsize())
191 HDNUM_ERROR("need square and nonempty matrix");
192 if (A_.rowsize()!=b_.size())
193 HDNUM_ERROR("vector incompatible with matrix");
194 if (A_.colsize()!=c_.size())
195 HDNUM_ERROR("vector incompatible with matrix");
196 }
197
204 : model(model_), u(model.size()), w(model.size()), K(A_.rowsize ())
205 {
206 A = A_;
207 b = b_;
208 c = c_;
209 s = A_.rowsize ();
210 n = model.size();
211 model.initialize(t,u);
212 dt = 0.1;
213 for (int i = 0; i < s; i++)
214 {
215 K[i].resize(n, number_type(0));
216 }
217 sigma = sigma_;
218 verbosity = 0;
219 if (A_.rowsize()!=A_.colsize())
220 HDNUM_ERROR("need square and nonempty matrix");
221 if (A_.rowsize()!=b_.size())
222 HDNUM_ERROR("vector incompatible with matrix");
223 if (A_.colsize()!=c_.size())
224 HDNUM_ERROR("vector incompatible with matrix");
225 }
226
229 {
230 dt = dt_;
231 }
232
235 {
236 bool is_explicit = true;
237 for (int i = 0; i < s; i++)
238 {
239 for (int j = i; j < s; j++)
240 {
241 if (A[i][j] != 0.0)
242 {
243 is_explicit = false;
244 }
245 }
246 }
247 return is_explicit;
248 }
249
251 void step ()
252 {
253 if (check_explicit())
254 {
255 // compute k_1
256 w = u;
257 model.f(t, w, K[0]);
258 for (int i = 0; i < s; i++)
259 {
260 Vector<number_type> sum (K[0].size(), 0.0);
261 sum.update(b[0], K[0]);
262 //compute k_i
263 for (int j = 0; j < i+1; j++)
264 {
265 sum.update(A[i][j],K[j]);
266 }
268 model.f(t + c[i]*dt, wert, K[i]);
269 u.update(dt *b[i], K[i]);
270 }
271 }
272 if (not check_explicit())
273 {
274 // In the implicit case we need to solve a nonlinear problem
275 // to do a time step.
276 ImplicitRungeKuttaStepProblem<M> problem(model, A, b, c, t, u, dt);
277 bool last_row_eq_b = true;
278 for (int i = 0; i<s; i++)
279 {
280 if (A[s-1][i] != b[i])
281 {
282 last_row_eq_b = false;
283 }
284 }
285
286 // Solve nonlinear problem and determine coefficients
287 S solver;
288 solver.set_maxit(2000);
289 solver.set_verbosity(verbosity);
290 solver.set_reduction(1e-10);
291 solver.set_abslimit(1e-10);
292 solver.set_linesearchsteps(10);
293 solver.set_sigma(0.01);
294 Vector<number_type> zij (s*n,0.0);
295 solver.solve(problem,zij);
296
297
299 if (not last_row_eq_b)
300 {
301 // Compute LR decomposition of A
308 Temp = A;
311
312 // Use LR decomposition to calculate inverse of A
313 for (int i=0; i<s; i++)
314 {
316 e[i]=number_type(1);
319 solveL(Temp,e,e);
320 solveR(Temp,z,e);
322 for (int j = 0; j < s; j++)
323 {
324 Ainv[j][i] = z[j];
325 }
326 }
327 }
328
329 Vector<Vector<number_type> > Z (s, 0.0);
330 for(int i=0; i<s; i++)
331 {
333 Z[i] = zero;
334 for (int j = 0; j < n; j++)
335 {
336 Z[i][j] = zij[i*n+j];
337 }
338 }
339 if (last_row_eq_b)
340 {
341 u += Z[s-1];
342 }
343 else
344 {
345 // compute ki
347 for (int i = 0; i < s; i++)
348 {
349 K[i] = zero;
350 for (int j=0; j < s; j++)
351 {
352 K[i].update(Ainv[i][j],Z[j]);
353 }
354 K[i]*= (1.0/dt);
355
356 // compute u
357 u.update(dt*b[i], K[i]);
358 }
359 }
360 }
361 t = t+dt;
362 }
363
366 {
367 t = t_;
368 u = u_;
369 }
370
373 {
374 return u;
375 }
376
379 {
380 return t;
381 }
382
385 {
386 return dt;
387 }
388
391 {
392 verbosity = verbosity_;
393 }
394
395 private:
396 const M& model;
397 time_type t, dt;
400 Vector<Vector<number_type> > K; // save ki
401 int n; // dimension of matrix A
402 int s;
403 DenseMatrix<number_type> A; // A, b, c as in the butcher tableau
406 number_type sigma;
407 int verbosity;
408 };
409
410
422 template<class M, class S>
423 void ordertest(const M& model,
424 S solver,
425 typename M::number_type T,
426 typename M::number_type h_0,
427 int l)
428 {
429 // Get types
430 typedef typename M::time_type time_type;
431 typedef typename M::number_type number_type;
432
433 // error_array[i] = ||u(T)-u_i(T)||
434 number_type error_array[l];
435
437 model.exact_solution(T, exact_solution);
438
439 for (int i=0; i<l; i++)
440 {
441 // Set initial time and value
442 time_type t_start;
444 model.initialize(t_start, initial_solution);
445 solver.set_state(t_start, initial_solution);
446
447 // Initial time step
448 time_type dt = h_0/pow(2,i) ;
449 solver.set_dt(dt);
450
451 // Time loop
452 while (solver.get_time()<T-2*solver.get_dt())
453 {
454 solver.step();
455 }
456
457 // Last steps
458 if (solver.get_time()<T-solver.get_dt())
459 {
460 solver.set_dt((T-solver.get_time())/2.0);
461 for(int i=0; i<2; i++)
462 {
463 solver.step();
464 }
465 }
466 else
467 {
468 solver.set_dt(T-solver.get_time());
469 solver.step();
470 }
471
472 // Error
473 Vector<number_type> state = solver.get_state();
475
476 if(i==0)
477 {
478 std::cout << "dt: "
479 << std::scientific << std::showpoint << std::setprecision(8)
480 << dt
481 << " "
482 << "Error: "
483 << error_array[0] << std::endl;
484 }
485 if(i>0)
486 {
487 number_type rate = log(error_array[i-1]/error_array[i])/log(2);
488 std::cout << "dt: "
489 << std::scientific << std::showpoint << std::setprecision(8)
490 << dt
491 << " "
492 << "Error: "
493 << error_array[i]
494 << " "
495 << "Rate: "
496 << rate << std::endl;
497 }
498 }
499 }
500
501} // namespace hdnum
502
503#endif
Class with mathematical matrix operations.
Definition densematrix.hh:33
void update(const REAL s, const DenseMatrix &B)
Scaled update of a Matrix.
Definition densematrix.hh:489
size_t rowsize() const
get number of rows of the matrix
Definition densematrix.hh:136
size_t colsize() const
get number of columns of the matrix
Definition densematrix.hh:153
Nonlinear problem we need to solve to do one step of an implicit Runge Kutta method.
Definition rungekutta.hh:17
M::number_type number_type
export number_type
Definition rungekutta.hh:26
void F_x(const Vector< number_type > &x, DenseMatrix< number_type > &result) const
jacobian evaluation needed for newton in implicite solvers
Definition rungekutta.hh:97
std::size_t size() const
return number of componentes for the model
Definition rungekutta.hh:49
M::size_type size_type
export size_type
Definition rungekutta.hh:20
M::time_type time_type
export time_type
Definition rungekutta.hh:23
ImplicitRungeKuttaStepProblem(const M &model_, DenseMatrix< number_type > A_, Vector< number_type > b_, Vector< number_type > c_, time_type t_, Vector< number_type > u_, time_type dt_)
constructor stores parameter lambda
Definition rungekutta.hh:29
void F(const Vector< number_type > &x, Vector< number_type > &result) const
model evaluation
Definition rungekutta.hh:55
classical Runge-Kutta method (order n with n stages)
Definition rungekutta.hh:158
M::number_type number_type
export number_type
Definition rungekutta.hh:167
M::size_type size_type
export size_type
Definition rungekutta.hh:161
time_type get_dt() const
get dt used in last step (i.e. to compute current state)
Definition rungekutta.hh:384
time_type get_time() const
get current time
Definition rungekutta.hh:378
void set_verbosity(int verbosity_)
how much should the ODE solver talk
Definition rungekutta.hh:390
RungeKutta(const M &model_, DenseMatrix< number_type > A_, Vector< number_type > b_, Vector< number_type > c_)
constructor stores reference to the model
Definition rungekutta.hh:170
void set_state(time_type t_, const Vector< number_type > &u_)
set current state
Definition rungekutta.hh:365
void step()
do one step
Definition rungekutta.hh:251
M::time_type time_type
export time_type
Definition rungekutta.hh:164
void set_dt(time_type dt_)
set time step for subsequent steps
Definition rungekutta.hh:228
const Vector< number_type > & get_state() const
get current state
Definition rungekutta.hh:372
RungeKutta(const M &model_, DenseMatrix< number_type > A_, Vector< number_type > b_, Vector< number_type > c_, number_type sigma_)
constructor stores reference to the model
Definition rungekutta.hh:199
bool check_explicit()
test if method is explicit
Definition rungekutta.hh:234
Vector & update(const REAL alpha, const Vector &y)
Update vector by addition of a scaled vector (x += a y )
Definition vector.hh:201
void permute_forward(const Vector< std::size_t > &p, Vector< T > &b)
apply permutations to a right hand side vector
Definition lr.hh:160
void lr_fullpivot(DenseMatrix< T > &A, Vector< std::size_t > &p, Vector< std::size_t > &q)
lr decomposition of A with full pivoting
Definition lr.hh:107
void permute_backward(const Vector< std::size_t > &q, Vector< T > &z)
apply permutations to a solution vector
Definition lr.hh:171
void apply_equilibrate(Vector< T > &s, Vector< T > &b)
apply row equilibration to right hand side vector
Definition lr.hh:203
void solveR(const DenseMatrix< T > &A, Vector< T > &x, const Vector< T > &b)
Assume R = upper triangle of A and solve R x = b.
Definition lr.hh:233
void solveL(const DenseMatrix< T > &A, Vector< T > &x, const Vector< T > &b)
Assume L = lower triangle of A with l_ii=1, solve L x = b.
Definition lr.hh:215
void row_equilibrate(DenseMatrix< T > &A, Vector< T > &s)
perform a row equilibration of a matrix; return scaling for later use
Definition lr.hh:182
Newton's method with line search.
void ordertest(const M &model, S solver, typename M::number_type T, typename M::number_type h_0, int l)
Test convergence order of an ODE solver applied to a model problem.
Definition rungekutta.hh:423