Hermes2D  3.0
runge_kutta.h
1 // This file is part of Hermes2D.
2 //
3 // Hermes2D is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // Hermes2D is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Hermes2D. If not, see <http://www.gnu.org/licenses/>.
15 
16 #ifndef __H2D_RUNGE_KUTTA_H
17 #define __H2D_RUNGE_KUTTA_H
18 
19 #include "global.h"
20 #include "weakform/weakform.h"
21 #include "function/filter.h"
22 #include "exceptions.h"
23 #include "mixins2d.h"
24 namespace Hermes
25 {
26  namespace Hermes2D
27  {
28  // TODO LIST:
29  //
30  // (1) With explicit and diagonally implicit methods, the matrix is treated
31  // in the same way as with fully implicit ones. To make this more
32  // efficient, with explicit and diagonally implicit methods one should
33  // first only solve for the upper left block, then eliminate all blocks
34  // under it, then solve for block at position 22, eliminate all blocks
35  // under it, etc. Currently this is not done and everything is left to
36  // the matrix solver.
37  //
38  // (2) In example 03-timedep-adapt-space-and-time with implicit Euler
39  // method, Newton's method takes much longer than in 01-timedep-adapt-space-only
40  // (that also uses implicit Euler method). This means that the initial guess for
41  // the K_vector should be improved (currently it is zero).
42  //
43  // (3) At the end of rk_time_step_newton(), the previous time level solution is
44  // projected onto the space of the new_ time-level solution so that
45  // it can be added to the stages. This projection is slow so we should
46  // find a way to do this differently. In any case, the projection
47  // is not necessary when no adaptivity in space takes place and the
48  // two spaces are the same (but it is done anyway).
49  //
50  // (4) We do not take advantage of the fact that all blocks in the
51  // Jacobian matrix have the same structure. Thus it is enough to
52  // assemble the matrix M (one block) and copy the sparsity structure
53  // into all remaining nonzero blocks (and diagonal blocks). Right
54  // now, the sparsity structure is created expensively in each block
55  // again.
56  //
57  // (5) If space does not change, the sparsity does not change. Right now
58  // we discard everything at the end of every time step, we should not
59  // do it.
60  //
61  // (6) If the problem does not depend explicitly on time, then all the blocks
62  // in the Jacobian matrix of the stationary residual are the same up
63  // to a multiplicative constant. Thus they do not have to be aassembled
64  // from scratch.
65  //
66  //
67  // (7) In practice, Butcher's tables are being transformed to the
68  // Jordan canonical form (I think) for better performance. This
69  // can be found, I think, in newer Butcher's papers or presentation
70  // (he has them online), and possibly in his book.
72  template<typename Scalar>
73  class HERMES_API RungeKutta :
74  public Hermes::Mixins::Loggable,
75  public Hermes::Mixins::TimeMeasurable,
76  public Hermes::Mixins::IntegrableWithGlobalOrder,
77  public Hermes::Mixins::SettableComputationTime,
79  public Hermes::Algebra::Mixins::MatrixRhsOutput < Scalar >
80  {
81  public:
85  RungeKutta(WeakFormSharedPtr<Scalar> wf, std::vector<SpaceSharedPtr<Scalar> > spaces, ButcherTable* bt);
86 
88  RungeKutta(WeakFormSharedPtr<Scalar> wf, SpaceSharedPtr<Scalar> space, ButcherTable* bt);
89 
90  void set_start_from_zero_K_vector();
91  void set_residual_as_solutions();
92  void set_block_diagonal_jacobian();
93 
95  ~RungeKutta();
96 
97  // Perform one explicit or implicit time step using the Runge-Kutta method
98  // corresponding to a given Butcher's table. If err_vec != nullptr then it will be
99  // filled with an error vector calculated using the second B-row of the Butcher's
100  // table (the second B-row B2 must be nonzero in that case). The negative default
101  // values for newton_tol and newton_max_iter are for linear problems.
102  // Many improvements are needed, a todo list is presented at the beginning of
103  // the corresponding .cpp file.
104  // freeze_jacobian... if true then the Jacobian is not recalculated in each
105  // iteration of the Newton's method.
106  // block_diagonal_jacobian... if true then the tensor product block Jacobian is
107  // reduced to just the diagonal blocks.
108  void rk_time_step_newton(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev, std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new, std::vector<MeshFunctionSharedPtr<Scalar> > error_fns);
109  void rk_time_step_newton(MeshFunctionSharedPtr<Scalar> slns_time_prev, MeshFunctionSharedPtr<Scalar> slns_time_new, MeshFunctionSharedPtr<Scalar> error_fn);
110 
111  // This is a wrapper for the previous function if error_fn is not provided
112  // (adaptive time stepping is not wanted).
113  void rk_time_step_newton(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev, std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_new);
114  void rk_time_step_newton(MeshFunctionSharedPtr<Scalar> sln_time_prev, MeshFunctionSharedPtr<Scalar> sln_time_new);
115 
116  void set_freeze_jacobian();
117  void set_tolerance(double newton_tol);
118  void set_max_allowed_iterations(int newton_max_iter);
119  void set_newton_damping_coeff(double newton_damping_coeff);
120  void set_newton_max_allowed_residual_norm(double newton_max_allowed_residual_norm);
121 
122  virtual void set_spaces(std::vector<SpaceSharedPtr<Scalar> > spaces);
123  virtual void set_space(SpaceSharedPtr<Scalar> space);
124  virtual std::vector<SpaceSharedPtr<Scalar> > get_spaces();
125 
137  void set_filters_to_reinit(std::vector<Filter<Scalar>*> filters_to_reinit);
138 
139  protected:
141  void init();
142 
149  void multiply_as_diagonal_block_matrix(SparseMatrix<Scalar>* matrix_left, int num_stages,
150  Scalar* stage_coeff_vec, Scalar* vector_left);
151 
157  void create_stage_wf(unsigned int size, bool block_diagonal_jacobian);
158 
160  void update_stage_wf(std::vector<MeshFunctionSharedPtr<Scalar> > slns_time_prev);
161 
162  // Prepare u_ext_vec.
163  void prepare_u_ext_vec();
164 
166  Hermes::Algebra::SparseMatrix<Scalar>* matrix_left;
167 
169  Hermes::Algebra::SparseMatrix<Scalar>* matrix_right;
170  Hermes::Algebra::Vector<Scalar>* vector_right;
171 
173  Hermes::Solvers::LinearMatrixSolver<Scalar>* solver;
174 
176  const WeakFormSharedPtr<Scalar> wf;
177 
179  std::vector<SpaceSharedPtr<Scalar> > spaces;
180  std::vector<unsigned int> spaces_seqs;
181 
183  ButcherTable* bt;
184 
186  unsigned int num_stages;
187 
189  // For the main part equation (written on the right),
191  WeakFormSharedPtr<Scalar> stage_wf_right;
192  DiscreteProblem<Scalar>* stage_dp_right;
193 
195  WeakFormSharedPtr<Scalar> stage_wf_left;
196  DiscreteProblem<Scalar>* stage_dp_left;
197 
198  bool start_from_zero_K_vector;
199  bool block_diagonal_jacobian;
200  bool residual_as_vector;
201 
203  unsigned int iteration;
204 
205  bool freeze_jacobian;
206  double newton_tol;
207  int newton_max_iter;
208  double newton_damping_coeff;
209  double newton_max_allowed_residual_norm;
210 
211  std::vector<MeshFunctionSharedPtr<Scalar> > residuals_vector;
212 
215  Scalar* K_vector;
216 
218  Scalar* u_ext_vec;
219 
221  Scalar* vector_left;
222 
224  std::vector<Filter<Scalar>*> filters_to_reinit;
225  };
226  }
227 }
228 #endif
Definition: adapt.h:24
Common definitions for Hermes2D.