LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
modelproblem_threecircles_main.cc
1
8#include <lf/io/io.h>
9
10#include <cstdlib>
11#include <filesystem>
12#include <iostream>
13#include <stdexcept>
14#include <string>
15#include <vector>
16
17#include "strangsplitting.h"
18
21
22int main(int /*argc*/, char** /*argv*/) {
23 /* Obtain mesh */
24 auto mesh_factory = std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
25 std::filesystem::path here = __FILE__;
26
27 /* In case of three circles: Mesh 2. */
28 auto mesh_file = (here.parent_path() / "/meshes/threecircles.msh").string();
29
30 const lf::io::GmshReader reader(std::move(mesh_factory), mesh_file);
31 std::shared_ptr<const lf::mesh::Mesh> mesh_p = reader.mesh();
32 /* Finite Element Space */
33 std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> fe_space =
34 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
35 /* Dofhandler */
36 const lf::assemble::DofHandler& dofh{fe_space->LocGlobMap()};
37 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
38
39 std::cout << "N_dofs :" << N_dofs << std::endl;
40
41 /* Initial Population density */
42 Eigen::VectorXd u0(N_dofs);
43 u0.setZero();
44 /* In case of three circles: Mesh 2. */
45 u0(0) = 0.00008;
46
47 /* Diffusion Coefficient */
48 auto c = [](const Eigen::Vector2d & /*x*/) -> double {
49 /* In case of three circles: Mesh 2. */
50 return 0.004;
51 };
52
53 /* Growth Factor */
54 /* In case of three circles: Mesh 2. */
55 double lambda = 0.0042;
56
57 /* Boundary Conditions. */
58
59 /* In case of homogeneous Neumann boundary conditions for Mesh 2. */
60 /* auto h = [] (const Eigen::Vector2d& x) -> double { return 0.0;};
61 * Eigen::MatrixXd L(N_dofs, N_dofs); L.setZero();
62 */
63
64 /* Else in case of non-local boundary condition for Mesh 2. */
65
66 /* This predicate returns true for nodes on the boundary */
67 auto bd_flags{lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 2)};
68 auto boundary_nodes = [&bd_flags, &dofh](unsigned int idx) -> bool {
69 return bd_flags(dofh.Entity(idx));
70 };
71
72 /* This predicate returns true for edges on the boundary */
73 auto bd_flags_edge{lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 1)};
74 auto edge_pred = [&bd_flags_edge](const lf::mesh::Entity& edge) -> bool {
75 return bd_flags_edge(edge);
76 };
77
78 auto h = [fe_space, mesh_p, edge_pred](const Eigen::Vector2d& x) -> double {
79 double res = 0.0;
80
81 /* The kernel g_1: No bounds on \| x - y \|. */
82 auto g_1 = [&x](const Eigen::Vector2d& y) -> double {
83 double tmp_res = 0.0;
84 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
85 return tmp_res;
86 };
87
88 /* The kernel g_2: Only an upper bound. */
89 auto g_2 = [&x](const Eigen::Vector2d& y) -> double {
90 double tmp_res = 0.0;
91 if ((x - y).norm() <= 1.75) {
92 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
93 }
94 return tmp_res;
95 };
96
97 /* The kernel g_3: Lower and Upper bound. */
98 auto g_3 = [&x](const Eigen::Vector2d& y) -> double {
99 double tmp_res = 0.0;
100 if (1.25 <= (x - y).norm() && (x - y).norm() <= 1.75) {
101 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
102 }
103 return tmp_res;
104 };
105
106 const auto* fe = fe_space->ShapeFunctionLayout(lf::base::RefEl::kSegment());
107 res = localQuadFunction(
108 *mesh_p,
111 2 * fe->Degree())},
113 g_1, 1, edge_pred);
114
115 return res;
116 };
117
118 Eigen::MatrixXd L(N_dofs, N_dofs);
119 for (int j = 0; j < N_dofs; j++) {
120 if (boundary_nodes(j)) {
121 auto L_j = [fe_space, &dofh, N_dofs, edge_pred,
122 j](const Eigen::Vector2d& x) -> double {
123 /* The kernel g_1: No bounds on \| x - y \|. */
124 auto g_1_j = [&x](const Eigen::Vector2d& y) -> double {
125 double tmp_res = 0.0;
126 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
127 return tmp_res;
128 };
129
130 /* The kernel g_2: Only an upper bound. */
131 auto g_2_j = [&x](const Eigen::Vector2d& y) -> double {
132 double tmp_res = 0.0;
133 if ((x - y).norm() <= 1.75) {
134 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
135 }
136 return tmp_res;
137 };
138
139 /* The kernel g_3: Lower and Upper bound. */
140 auto g_3_j = [&x](const Eigen::Vector2d& y) -> double {
141 double tmp_res = 0.0;
142 if (1.25 <= (x - y).norm() && (x - y).norm() <= 1.75) {
143 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
144 }
145 return tmp_res;
146 };
147
148 Eigen::VectorXd L1(N_dofs);
149 L1.setZero();
150
152 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_g),
153 decltype(edge_pred)>
154 edgeVec_y(fe_space, mf_g, edge_pred);
155 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_y, L1);
156
157 return L1(j);
158 };
159
160 Eigen::VectorXd L2(N_dofs);
161 L2.setZero();
162
164 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_L),
165 decltype(edge_pred)>
166 edgeVec_x(fe_space, mf_L, edge_pred);
167 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_x, L2);
168
169 L.col(j) = L2;
170 }
171
172 else {
173 L.col(j) = Eigen::VectorXd::Zero(N_dofs);
174 }
175 }
176
177 /* Strang Splitting Method
178 * SDIRK-2 evolution of linear parabolic term
179 * Exact Evolution for nonlinear reaction term
180 */
181
182 /* Total number of timesteps */
183 unsigned int m = 100;
184 double T = 1.; // the timestepsize tau will equal T/m = 0.01
185
186 /* First we assemble the carrying capacity maps */
187
188 Eigen::VectorXd cap(N_dofs);
189 cap.setZero();
190 cap = 0.8 * Eigen::VectorXd::Ones(N_dofs);
191
192 /* Now we may compute the solution */
193 StrangSplit StrangSplitter(fe_space, T, m, lambda, c, h, L);
194
195 Eigen::MatrixXd sol(N_dofs, 20);
196
197 sol.col(0) = StrangSplitter.Evolution(cap, u0);
198 std::cout << "sol1" << std::endl;
199 sol.col(1) = StrangSplitter.Evolution(cap, sol.col(0));
200 std::cout << "sol2" << std::endl;
201 sol.col(2) = StrangSplitter.Evolution(cap, sol.col(1));
202 std::cout << "sol3" << std::endl;
203 sol.col(3) = StrangSplitter.Evolution(cap, sol.col(2));
204 std::cout << "sol4" << std::endl;
205 sol.col(4) = StrangSplitter.Evolution(cap, sol.col(3));
206 std::cout << "sol5" << std::endl;
207
208 /* Use VTK-Writer for Visualization of solution */
209
210 for (int k = 1; k < 6; k++) {
211 std::stringstream filename;
212 filename << "sol" << k << ".vtk";
213
214 lf::io::VtkWriter vtk_writer(mesh_p, filename.str());
215 auto nodal_data = lf::mesh::utils::make_CodimMeshDataSet<double>(mesh_p, 2);
216 for (int global_idx = 0; global_idx < N_dofs; global_idx++) {
217 nodal_data->operator()(dofh.Entity(global_idx)) =
218 sol.col(k - 1)[global_idx];
219 }
220
221 vtk_writer.WritePointData("sol", *nodal_data);
222 }
223
224 return 0;
225}
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
Reads a Gmsh *.msh file into a mesh::MeshFactory and provides a link between mesh::Entity objects and...
Definition: gmsh_reader.h:70
Write a mesh along with mesh data into a vtk file.
Definition: vtk_writer.h:272
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
MeshFunction wrapper for a simple function of physical coordinates.
auto squaredNorm(const A &a)
Pointwise squared norm of another mesh function.
Local edge contributions to element vector.
void AssembleVectorLocally(dim_t codim, const DofHandler &dof_handler, ENTITY_VECTOR_PROVIDER &entity_vector_provider, VECTOR &resultvector)
entity-local assembly of (right-hand-side) vectors from element vectors
Definition: assembler.h:297
QuadRule make_TriaQR_EdgeMidpointRule()
edge midpoint quadrature rule for reference triangles
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
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.
lf::assemble::size_type size_type
Definition: lagr_fe.h:30