LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
strangsplitting.cc
1
8#include "strangsplitting.h"
9
10namespace FisherKPP {
11
12/* Member Function StrangSplit
13 * Computes the Evolution Operator for the linear parabolic diffusion term
14 */
16 bool firstcall, const Eigen::VectorXd &mu) {
17 Eigen::VectorXd evol_op;
18
19 /* Precomputation */
20 /* solver.compute(M_ + tau * kappa_ * A_);
21 LF_VERIFY_MSG(solver.info() == Eigen::Success, "LU decomposition failed");
22 */
23 Eigen::VectorXd rhs = -A_ * mu;
24
25 if (firstcall) {
26 /* First stage SDIRK-2 */
27 Eigen::VectorXd k1 = solver1.solve(rhs);
28 LF_VERIFY_MSG(solver1.info() == Eigen::Success, "LU decomposition failed");
29 /* Second stage SDIRK-2 */
30 Eigen::VectorXd k2 =
31 solver1.solve(rhs - 0.5 * tau_ * (1 - kappa_) * A_ * k1);
32 LF_VERIFY_MSG(solver1.info() == Eigen::Success, "LU decomposition failed");
33
34 evol_op = mu + 0.5 * tau_ * (1 - kappa_) * k1 + 0.5 * tau_ * kappa_ * k2;
35
36 } else {
37 /* First stage SDIRK-2 */
38 Eigen::VectorXd k1 = solver2.solve(rhs);
39 LF_VERIFY_MSG(solver2.info() == Eigen::Success, "LU decomposition failed");
40 /* Second stage SDIRK-2 */
41 Eigen::VectorXd k2 = solver2.solve(rhs - tau_ * (1 - kappa_) * A_ * k1);
42 LF_VERIFY_MSG(solver2.info() == Eigen::Success, "LU decomposition failed");
43
44 evol_op = mu + tau_ * (1 - kappa_) * k1 + tau_ * kappa_ * k2;
45 }
46
47 return evol_op;
48}
49
50/* Member Function StrangSplit
51 * Computes the Evolution for m_ timesteps
52 */
53Eigen::VectorXd StrangSplit::Evolution(const Eigen::VectorXd &cap,
54 const Eigen::VectorXd &mu) {
55 const lf::assemble::DofHandler &dofh{fe_space_->LocGlobMap()};
56 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
57
58 Eigen::VectorXd sol(N_dofs);
59 Eigen::VectorXd sol_cur(N_dofs);
60 Eigen::VectorXd sol_next(N_dofs);
61
62 Eigen::VectorXd ones = Eigen::VectorXd::Ones(N_dofs);
63
64 /* Time Steps */
65 // double tau = T_ / m_;
66
67 /* Strang Splitting Method
68 * First half time step [0, tau/2]: Diffusion
69 */
70 bool firstcall = true;
71 sol_cur = StrangSplit::diffusionEvolutionOperator(firstcall, mu);
72 firstcall = false;
73 /* loop through time steps */
74 for (unsigned int i = 1; i < m_ - 1; i++) {
75 /* Reaction for next full time step */
76 sol_next = cap.cwiseQuotient(ones + (cap.cwiseQuotient(sol_cur) - ones) *
77 std::exp(-lambda_ * tau_));
78 sol_cur = sol_next;
79 /* Diffusion for next full time step */
80 sol_next = StrangSplit::diffusionEvolutionOperator(firstcall, sol_cur);
81 sol_cur = sol_next;
82 }
83
84 /* Last half time step: Reaction */
85 sol_next = cap.cwiseQuotient(ones + (cap.cwiseQuotient(sol_cur) - ones) *
86 std::exp(-lambda_ * tau_ / 2.));
87 sol_cur = sol_next;
88
89 sol = sol_cur;
90 return sol;
91}
92
93} /* namespace FisherKPP */
Eigen::SparseMatrix< double > A_
Eigen::SparseLU< Eigen::SparseMatrix< double > > solver2
Eigen::VectorXd Evolution(const Eigen::VectorXd &cap, const Eigen::VectorXd &mu)
Eigen::SparseLU< Eigen::SparseMatrix< double > > solver1
Eigen::VectorXd diffusionEvolutionOperator(bool firstcall, const Eigen::VectorXd &mu)
const std::shared_ptr< lf::uscalfe::UniformScalarFESpace< double > > fe_space_
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
lf::assemble::size_type size_type
Definition: lagr_fe.h:30