LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
modelproblem_island_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 auto mesh_file = (here.parent_path() / "/meshes/Island.msh").string();
27 const lf::io::GmshReader reader(std::move(mesh_factory), mesh_file);
28 std::shared_ptr<const lf::mesh::Mesh> mesh_p = reader.mesh();
29 /* Finite Element Space */
30 std::shared_ptr<lf::uscalfe::UniformScalarFESpace<double>> fe_space =
31 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(mesh_p);
32 /* Dofhandler */
33 const lf::assemble::DofHandler &dofh{fe_space->LocGlobMap()};
34 const lf::uscalfe::size_type N_dofs(dofh.NumDofs());
35
36 std::cout << "N_dofs :" << N_dofs << std::endl;
37
38 /* Initial Population density */
39 Eigen::VectorXd u0(N_dofs);
40 u0.setZero();
41 u0(1099) = 0.3;
42
43 /* Diffusion Coefficient */
44 auto c = [](const Eigen::Vector2d & /*x*/) -> double { return 1.2; };
45 /* In the case where we intend to model a low diffusion coefficient,
46 * such that sea crossings are more attractive than diffusion on land.
47 */
48 /* auto c = [](const Eigen::Vector2d &x) -> double { return 0.0625; }; */
49
50 /* Growth Factor */
51 double lambda = 2.1;
52
53 /* In the case of a low diffusion coefficient. */
54 /* double lambda = 1.1; */
55
56 /* Non Local Boundary Conditions */
57
58 /* This predicate returns true for nodes on the boundary */
59 auto bd_flags{lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 2)};
60 auto boundary_nodes = [&bd_flags, &dofh](unsigned int idx) -> bool {
61 return bd_flags(dofh.Entity(idx));
62 };
63
64 /* This predicate returns true for edges on the boundary */
65 auto bd_flags_edge{lf::mesh::utils::flagEntitiesOnBoundary(mesh_p, 1)};
66 auto edge_pred = [&bd_flags_edge](const lf::mesh::Entity &edge) -> bool {
67 return bd_flags_edge(edge);
68 };
69
70 /* This h is to be used as a function handle for the gain term.
71 * Use it in the MassEdgeMatrix Provider.
72 */
73 auto h = [fe_space, mesh_p, edge_pred](const Eigen::Vector2d &x) -> double {
74 double res = 0.0;
75 /* Decaying function handle depending on x and y. */
76 auto g = [&x](const Eigen::Vector2d &y) -> double {
77 double tmp_res = 0.0;
78 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
79 return tmp_res;
80 };
81
82 const auto *fe = fe_space->ShapeFunctionLayout(lf::base::RefEl::kSegment());
84 *mesh_p,
87 2 * fe->Degree())},
89 g, 1, edge_pred);
90 return res;
91 };
92 /* In what follows, the loss term is assembled. */
93 Eigen::MatrixXd L(N_dofs, N_dofs);
94 for (int j = 0; j < N_dofs; j++) {
95 if (boundary_nodes(j)) {
96 auto L_j = [fe_space, &dofh, N_dofs, edge_pred,
97 j](const Eigen::Vector2d &x) -> double {
98 auto g_j = [&x](const Eigen::Vector2d &y) -> double {
99 double tmp_res = 0.0;
100 tmp_res = (1.0 / (1.0 + (x - y).squaredNorm()));
101 return tmp_res;
102 };
103
104 Eigen::VectorXd L1(N_dofs);
105 L1.setZero();
106
108 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_g),
109 decltype(edge_pred)>
110 edgeVec_y(fe_space, mf_g, edge_pred);
111 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_y, L1);
112
113 return L1(j);
114 };
115
116 Eigen::VectorXd L2(N_dofs);
117 L2.setZero();
118
120 lf::uscalfe::ScalarLoadEdgeVectorProvider<double, decltype(mf_L),
121 decltype(edge_pred)>
122 edgeVec_x(fe_space, mf_L, edge_pred);
123 lf::assemble::AssembleVectorLocally(1, dofh, edgeVec_x, L2);
124
125 L.col(j) = L2;
126 }
127
128 else {
129 L.col(j) = Eigen::VectorXd::Zero(N_dofs);
130 }
131 }
132
133 /* Strang Splitting Method
134 * SDIRK-2 evolution of linear parabolic term
135 * Exact Evolution for nonlinear reaction term
136 */
137
138 /* Total number of timesteps */
139 unsigned int m = 120;
140 double T = 1.;
141
142 /* Now we may compute the solution */
143 StrangSplit StrangSplitter(fe_space, T, m, lambda, c, h, L);
144
145 Eigen::MatrixXd sol(N_dofs, 12);
146 Eigen::VectorXd cap(N_dofs);
147 cap.setZero();
148 cap = 0.9 * Eigen::VectorXd::Ones(N_dofs);
149
150 sol.col(0) = StrangSplitter.Evolution(cap, u0);
151 for (int i = 1; i < 6; i++) {
152 sol.col(i) = StrangSplitter.Evolution(cap, sol.col(i - 1));
153 }
154
155 /* Use VTK-Writer for Visualization of solution */
156 for (int k = 1; k < 7; k++) {
157 std::stringstream filename;
158 filename << "sol" << k << ".vtk";
159
160 lf::io::VtkWriter vtk_writer(mesh_p, filename.str());
161 auto nodal_data = lf::mesh::utils::make_CodimMeshDataSet<double>(mesh_p, 2);
162 for (int global_idx = 0; global_idx < N_dofs; global_idx++) {
163 nodal_data->operator()(dofh.Entity(global_idx)) =
164 sol.col(k - 1)[global_idx];
165 }
166
167 vtk_writer.WritePointData("sol", *nodal_data);
168 }
169
170 return 0;
171}
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