LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
strangsplitting.h
1
8#ifndef STRANG_SPLIT_H
9#define STRANG_SPLIT_H
10
11#include <lf/assemble/assemble.h>
12#include <lf/base/base.h>
13#include <lf/geometry/geometry.h>
14#include <lf/mesh/hybrid2d/hybrid2d.h>
15#include <lf/mesh/test_utils/test_meshes.h>
16#include <lf/mesh/utils/utils.h>
17#include <lf/uscalfe/uscalfe.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <Eigen/Dense>
22#include <Eigen/LU>
23#include <Eigen/Sparse>
24#include <memory>
25#include <utility>
26
27namespace FisherKPP {
28
30 public:
31 /* Disabled constructors */
32 StrangSplit() = delete;
33 StrangSplit(const StrangSplit &) = delete;
35 StrangSplit &operator=(const StrangSplit &) = delete;
36 StrangSplit &operator=(const StrangSplit &&) = delete;
37 /* Main constructor */
38 template <typename DIFF_COEFF, typename NONLOC_BC>
39 explicit StrangSplit(
40 std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> &fe_space,
41 double T, unsigned int m, double lambda, DIFF_COEFF &&c, NONLOC_BC &&h,
42 const Eigen::MatrixXd &L);
43 /* Destructor */
44 virtual ~StrangSplit() = default;
45
46 /* Member Functions */
47 Eigen::VectorXd diffusionEvolutionOperator(bool firstcall,
48 const Eigen::VectorXd &mu);
49 Eigen::VectorXd Evolution(const Eigen::VectorXd &cap,
50 const Eigen::VectorXd &mu);
51
52 private:
53 /* Finite Element Space */
54 const std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> fe_space_;
55 /* Final Time */
56 double T_;
57 /* Number of Timesteps */
58 unsigned int m_;
59 /* Time step size */
60 double tau_;
61 /* Growth Factor */
62 double lambda_;
63 /* coefficient for SDIRK-2 Butcher Tableau */
64 double kappa_;
65 /* Galerkin matrix corresponding to the negative Laplacian with Robin Boundary
66 * Conditions */
67 Eigen::SparseMatrix<double> A_;
68 /* Galerkin matrix for the Mass Matrix */
69 Eigen::SparseMatrix<double> M_;
70 /* Precompute LU decomposition needed for time stepping */
71 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver1;
72 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver2;
73};
74
75template <typename FUNCTOR>
77 const lf::mesh::Mesh &mesh,
78 std::map<lf::base::RefEl, lf::quad::QuadRule> quadrules, FUNCTOR &&f,
79 unsigned int codim,
80 const std::function<bool(const lf::mesh::Entity &)> &pred) {
81 LF_ASSERT_MSG(mesh.DimMesh() >= codim, "Illegal codim = " << codim);
82 /* Variable for summing the result */
83 using value_t = std::invoke_result_t<FUNCTOR, Eigen::VectorXd>;
84 value_t sum_var{};
85 /* Loop over entities of co-dimension codim */
86 for (const lf::mesh::Entity *entity : mesh.Entities(codim)) {
87 if (pred(*entity)) {
88 /* Obtain geometry information for entity */
89 const lf::geometry::Geometry &geo{*entity->Geometry()};
90 /* obtain quadrature rule suitable for entity type */
91 auto tmp = quadrules.find(entity->RefEl());
92 if (tmp != quadrules.end()) {
93 /* A quadrature rule has been found */
94 const lf::quad::QuadRule &qr{tmp->second};
95 /* Number of quadrature points */
96 const lf::base::size_type P = qr.NumPoints();
97 /* Quadrature points */
98 const Eigen::MatrixXd &zeta_ref{qr.Points()};
99 /* Map quadrature points to physical/world coordinates */
100 const Eigen::MatrixXd zeta{geo.Global(zeta_ref)};
101 /* Quadrature weights */
102 const Eigen::VectorXd &w_ref{qr.Weights()};
103 /* Gramian determinants */
104 const Eigen::VectorXd gram_dets{geo.IntegrationElement(zeta_ref)};
105 /* Iterate over the quadrature points */
106 for (int l = 0; l < P; ++l) {
107 sum_var += w_ref[l] * f(zeta.col(l)) * gram_dets[l];
108 }
109 } else {
110 LF_VERIFY_MSG(false, "Missing quadrature rule for " << entity->RefEl());
111 }
112 }
113 }
114 return sum_var;
115}
116
117/* Function for the assembly of both Galerkin Matrices, the Mass matrix and the
118 * Stiffness matrix */
119template <typename DIFF_COEFF, typename NONLOC_BC>
120std::pair<Eigen::SparseMatrix<double>, Eigen::SparseMatrix<double>>
122 NONLOC_BC &&h, const Eigen::MatrixXd &L) {
123 std::pair<Eigen::SparseMatrix<double>, Eigen::SparseMatrix<double>> A_M;
124
125 std::shared_ptr<const lf::mesh::Mesh> mesh = dofh.Mesh();
126 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
127 auto fe_space =
128 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh);
129
130 auto bd_flags{lf::mesh::utils::flagEntitiesOnBoundary(mesh, 1)};
131 auto edges_predicate = [&bd_flags](const lf::mesh::Entity &edge) -> bool {
132 return bd_flags(edge);
133 };
134
135 lf::assemble::COOMatrix<double> A_COO(N_dofs, N_dofs);
136 lf::assemble::COOMatrix<double> M_COO(N_dofs, N_dofs);
137 lf::assemble::COOMatrix<double> G_COO(N_dofs, N_dofs);
138
139 auto one = [](const Eigen::Vector2d & /*x*/) -> double { return 1.0; };
140 auto zero = [](const Eigen::Vector2d & /*x*/) -> double { return 0.0; };
141
146
148 decltype(mf_zero)>
149 elMat_Stiff(fe_space, mf_c, mf_zero);
151 decltype(mf_one)>
152 elMat_Mass(fe_space, mf_zero, mf_one);
153 lf::uscalfe::MassEdgeMatrixProvider<double, decltype(mf_h),
154 decltype(edges_predicate)>
155 elMat_Edge(fe_space, mf_h, edges_predicate);
156
157 lf::assemble::AssembleMatrixLocally(0, dofh, dofh, elMat_Stiff, A_COO);
158 lf::assemble::AssembleMatrixLocally(0, dofh, dofh, elMat_Mass, M_COO);
159 lf::assemble::AssembleMatrixLocally(1, dofh, dofh, elMat_Edge, A_COO);
160
161 Eigen::SparseMatrix<double> A_sps = A_COO.makeSparse();
162 Eigen::SparseMatrix<double> M(N_dofs, N_dofs);
163 M = M_COO.makeSparse();
164
165 Eigen::MatrixXd A_ds(A_sps);
166 Eigen::MatrixXd A_ds1 = A_ds - L;
167
168 Eigen::SparseMatrix<double> A(N_dofs, N_dofs);
169 A = A_ds1.sparseView();
170
171 A_M = std::make_pair(A, M);
172
173 return A_M;
174}
175
176/* Constructor for StrangSplit */
177template <typename DIFF_COEFF, typename NONLOC_BC>
179 std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> &fe_space,
180 double T, unsigned m, double lambda, DIFF_COEFF &&c, NONLOC_BC &&h,
181 const Eigen::MatrixXd &L)
182 : fe_space_(fe_space), T_(T), m_(m), lambda_(lambda) {
183 const lf::assemble::DofHandler &dofh{fe_space_->LocGlobMap()};
184 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
185 std::pair<Eigen::SparseMatrix<double>, Eigen::SparseMatrix<double>>
186 galerkinpair = assembleGalerkinMatrices(dofh, c, h, L);
187 A_ = galerkinpair.first;
188 M_ = galerkinpair.second;
189
190 /* Butcher Tableau Coefficient for SDIRK-2 */
191 kappa_ = 1.0 - 0.5 * sqrt(2.0);
192
193 tau_ = T_ / m_;
194 solver1.compute(M_ + 0.5 * tau_ * kappa_ * A_);
195 LF_VERIFY_MSG(solver1.info() == Eigen::Success, "LU decomposition failed");
196 solver2.compute(M_ + tau_ * kappa_ * A_);
197 LF_VERIFY_MSG(solver2.info() == Eigen::Success, "LU decomposition failed");
198}
199
200} /* namespace FisherKPP */
201
202#endif
Eigen::SparseMatrix< double > A_
StrangSplit & operator=(const StrangSplit &&)=delete
StrangSplit(std::shared_ptr< lf::uscalfe::UniformScalarFESpace< double > > &fe_space, double T, unsigned int m, double lambda, DIFF_COEFF &&c, NONLOC_BC &&h, const Eigen::MatrixXd &L)
StrangSplit(StrangSplit &&)=delete
StrangSplit(const StrangSplit &)=delete
Eigen::SparseLU< Eigen::SparseMatrix< double > > solver2
Eigen::SparseMatrix< double > M_
Eigen::VectorXd Evolution(const Eigen::VectorXd &cap, const Eigen::VectorXd &mu)
virtual ~StrangSplit()=default
StrangSplit & operator=(const StrangSplit &)=delete
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 temporary data structure for matrix in COO format.
Definition: coomatrix.h:52
Eigen::SparseMatrix< Scalar > makeSparse() const
Create an Eigen::SparseMatrix out of the COO format.
Definition: coomatrix.h:172
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual std::shared_ptr< const lf::mesh::Mesh > Mesh() const =0
Acess to underlying mesh object.
virtual size_type NumDofs() const =0
total number of dof's handled by the object
Interface class for shape information on a mesh cell in the spirit of parametric finite element metho...
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
Abstract interface for objects representing a single mesh.
virtual unsigned DimMesh() const =0
The dimension of the manifold described by the mesh, or equivalently the maximum dimension of the ref...
virtual nonstd::span< const Entity *const > Entities(unsigned codim) const =0
All entities of a given codimension.
MeshFunction wrapper for a simple function of physical coordinates.
Represents a Quadrature Rule over one of the Reference Elements.
Definition: quad_rule.h:58
base::size_type NumPoints() const
Return the total number of quadrature points (num of columns of points/weights)
Definition: quad_rule.h:158
Quadrature-based computation of local mass matrix for an edge.
Class for local quadrature based computations for Lagrangian finite elements and second-order scalar ...
Space of scalar valued finite element functions on a hybrid 2D mesh
void AssembleMatrixLocally(dim_t codim, const DofHandler &dof_handler_trial, const DofHandler &dof_handler_test, ENTITY_MATRIX_PROVIDER &entity_matrix_provider, TMPMATRIX &matrix)
Assembly function for standard assembly of finite element matrices.
Definition: assembler.h:113
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
std::pair< Eigen::SparseMatrix< double >, Eigen::SparseMatrix< double > > assembleGalerkinMatrices(const lf::assemble::DofHandler &dofh, DIFF_COEFF &&c, NONLOC_BC &&h, const Eigen::MatrixXd &L)
auto localQuadFunction(const lf::mesh::Mesh &mesh, std::map< lf::base::RefEl, lf::quad::QuadRule > quadrules, FUNCTOR &&f, unsigned int codim, const std::function< bool(const lf::mesh::Entity &)> &pred)
CodimMeshDataSet< bool > flagEntitiesOnBoundary(const std::shared_ptr< const Mesh > &mesh_p, lf::base::dim_t codim)
flag entities of a specific co-dimension located on the boundary
lf::assemble::size_type size_type
Definition: lagr_fe.h:30