LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
convergence_tau_main.cc
1
8#include <lf/io/io.h>
9
10#include <cstdlib>
11#include <filesystem>
12#include <fstream>
13#include <iostream>
14#include <stdexcept>
15#include <string>
16
17#include "strangsplitting.h"
18
21
22double getMeshSize(const std::shared_ptr<const lf::mesh::Mesh> &mesh_p) {
23 double mesh_size = 0.0;
24 /* Find maximal edge length */
25 double edge_length;
26 for (const lf::mesh::Entity *edge : mesh_p->Entities(1)) {
27 /* Compute the length of the edge */
28 auto endpoints = lf::geometry::Corners(*(edge->Geometry()));
29 edge_length = (endpoints.col(0) - endpoints.col(1)).norm();
30 if (mesh_size < edge_length) {
31 mesh_size = edge_length;
32 }
33 }
34 return mesh_size;
35}
36
37int main(int /*argc*/, char ** /*argv*/) {
38 /* Diffusion Coefficient */
39 auto c = [](const Eigen::Vector2d & /*x*/) -> double { return 1.2; };
40 /* Growth Factor */
41 double lambda = 2.1;
42
43 /* Obtain mesh */
44 auto mesh_factory = std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
45 std::filesystem::path here = __FILE__;
46 auto mesh_file = (here.parent_path() / "/meshes/test4.msh").string();
47 lf::io::GmshReader reader(std::move(mesh_factory), mesh_file);
48 std::shared_ptr<lf::mesh::Mesh> mesh_p = reader.mesh();
49
50 /* Finite Element Space */
51 std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> fe_space =
52 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
53 /* Dofhandler */
54 const lf::assemble::DofHandler &dofh{fe_space->LocGlobMap()};
55 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
56
57 std::cout << "Num of dofs " << N_dofs << std::endl;
58
59 /* Initial Population density */
60 Eigen::VectorXd u0(N_dofs);
61 u0.setZero();
62 u0(104) = 0.3;
63
64 /* Non Local Boundary Conditions */
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 /* This h is to be used as a function handle for the gain term.
79 * Use it in the MassEdgeMatrix Provider.
80 */
81 auto h = [fe_space, mesh_p, edge_pred](const Eigen::Vector2d &x) -> double {
82 double res = 0.0;
83
84 auto g = [&x](const Eigen::Vector2d &y) -> double {
85 double tmp_res = 0.0;
86 if ((x - y).norm() >= 15 && (x - y).norm() <= 35) {
87 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
88 }
89 return tmp_res;
90 };
91
92 const auto *fe = fe_space->ShapeFunctionLayout(lf::base::RefEl::kSegment());
94 *mesh_p,
97 2 * fe->Degree())},
99 g, 1, edge_pred);
100 return res;
101 };
102
103 /* In what follows, the loss term is assembled. */
104 Eigen::MatrixXd L(N_dofs, N_dofs);
105 for (int j = 0; j < N_dofs; j++) {
106 if (boundary_nodes(j)) {
107 auto L_j = [fe_space, &dofh, N_dofs, edge_pred,
108 j](const Eigen::Vector2d &x) -> double {
109 auto g_j = [&x](const Eigen::Vector2d &y) -> double {
110 double tmp_res = 0.0;
111 if ((x - y).norm() >= 15 && (x - y).norm() <= 35) {
112 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
113 }
114 return tmp_res;
115 };
116
117 Eigen::VectorXd L1(N_dofs);
118 L1.setZero();
119
121 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_g),
122 decltype(edge_pred)>
123 edgeVec_y(fe_space, mf_g, edge_pred);
124 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_y, L1);
125
126 return L1(j);
127 };
128
129 Eigen::VectorXd L2(N_dofs);
130 L2.setZero();
131
133 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_L),
134 decltype(edge_pred)>
135 edgeVec_x(fe_space, mf_L, edge_pred);
136 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_x, L2);
137
138 L.col(j) = L2;
139 }
140
141 else {
142 L.col(j) = Eigen::VectorXd::Zero(N_dofs);
143 }
144 }
145
146 /* Strang Splitting Method
147 * SDIRK-2 evolution of linear parabolic term
148 * Exact Evolution for nonlinear reaction term
149 */
150
151 /* Total number of timesteps */
152 Eigen::VectorXd numSteps(6);
153 numSteps.setZero();
154 Eigen::VectorXd tau(6);
155 tau.setZero();
156 double T = 1.;
157
158 for (int i = 0; i < 6; i++) {
159 numSteps(i) = 80 * std::pow(2, i);
160 tau(i) = T / numSteps(i);
161 }
162
163 /* Carrying Capacity. */
164 Eigen::VectorXd cap(N_dofs);
165 cap.setZero();
166 cap = 0.8 * Eigen::VectorXd::Ones(N_dofs);
167
168 StrangSplit StrangSplitter1(fe_space, T, numSteps(0), lambda, c, h, L);
169 StrangSplit StrangSplitter2(fe_space, T, numSteps(1), lambda, c, h, L);
170 StrangSplit StrangSplitter3(fe_space, T, numSteps(2), lambda, c, h, L);
171 StrangSplit StrangSplitter4(fe_space, T, numSteps(3), lambda, c, h, L);
172 StrangSplit StrangSplitter5(fe_space, T, numSteps(4), lambda, c, h, L);
173 StrangSplit StrangSplitter6(fe_space, T, numSteps(5), lambda, c, h, L);
174
175 Eigen::VectorXd sol1(N_dofs);
176 sol1.setZero();
177 sol1 = StrangSplitter1.Evolution(cap, u0);
178 std::cout << "sol1 " << std::endl;
179
180 Eigen::VectorXd sol2(N_dofs);
181 sol2.setZero();
182 sol2 = StrangSplitter2.Evolution(cap, u0);
183 std::cout << "sol2 " << std::endl;
184
185 Eigen::VectorXd sol3(N_dofs);
186 sol3.setZero();
187 sol3 = StrangSplitter3.Evolution(cap, u0);
188 std::cout << "sol3 " << std::endl;
189
190 Eigen::VectorXd sol4(N_dofs);
191 sol4.setZero();
192 sol4 = StrangSplitter4.Evolution(cap, u0);
193 std::cout << "sol4 " << std::endl;
194
195 Eigen::VectorXd sol5(N_dofs);
196 sol5.setZero();
197 sol5 = StrangSplitter5.Evolution(cap, u0);
198 std::cout << "sol5 " << std::endl;
199
200 Eigen::VectorXd sol6(N_dofs);
201 sol6.setZero();
202 sol6 = StrangSplitter6.Evolution(cap, u0);
203 std::cout << "sol6 " << std::endl;
204
205 Eigen::VectorXd eL2(5);
206 eL2.setZero();
207 eL2(0) = (sol6 - sol1).lpNorm<2>();
208 eL2(1) = (sol6 - sol2).lpNorm<2>();
209 eL2(2) = (sol6 - sol3).lpNorm<2>();
210 eL2(3) = (sol6 - sol4).lpNorm<2>();
211 eL2(4) = (sol6 - sol5).lpNorm<2>();
212 std::cout << "errors computed" << std::endl;
213
214 for (int l = 0; l < 6; l++) {
215 if (l < 5) {
216 std::cout << "errorL2 solcol0 for l = " << l << " : " << eL2(l)
217 << std::endl;
218 }
219
220 std::cout << "number of timesteps for l = " << l << " : " << numSteps(l)
221 << std::endl;
222 std::cout << "tau for l = " << l << " : " << tau(l) << std::endl;
223 }
224
225 /* Define output file format */
226 const static Eigen::IOFormat CSVFormat(Eigen::StreamPrecision,
227 Eigen::DontAlignCols, ", ", "\n");
228
229 std::ofstream file;
230
231 file.open("eL2.csv");
232 file << eL2.format(CSVFormat);
233 file.close();
234
235 file.open("tau.csv");
236 file << tau.format(CSVFormat);
237 file.close();
238
239 file.open("numSteps.csv");
240 file << numSteps.format(CSVFormat);
241 file.close();
242
243 file.open("sol1.csv");
244 file << sol1.format(CSVFormat);
245 file.close();
246
247 file.open("sol2.csv");
248 file << sol2.format(CSVFormat);
249 file.close();
250
251 file.open("sol3.csv");
252 file << sol3.format(CSVFormat);
253 file.close();
254
255 file.open("sol4.csv");
256 file << sol4.format(CSVFormat);
257 file.close();
258
259 file.open("sol5.csv");
260 file << sol5.format(CSVFormat);
261 file.close();
262
263 file.open("sol6.csv");
264 file << sol6.format(CSVFormat);
265 file.close();
266
267 return 0;
268}
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
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)
Eigen::MatrixXd Corners(const Geometry &geo)
The corners of a shape with piecewise smooth boundary.
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