LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
convergence.cc
1
6#define _USE_MATH_DEFINES
7#include <build_system_matrix.h>
8#include <lf/assemble/dofhandler.h>
9#include <lf/io/gmsh_reader.h>
10#include <lf/io/vtk_writer.h>
11#include <lf/mesh/entity.h>
12#include <lf/mesh/hybrid2d/mesh_factory.h>
13#include <lf/mesh/utils/tp_triag_mesh_builder.h>
14#include <lf/mesh/utils/utils.h>
15#include <lf/quad/quad.h>
16#include <lf/refinement/mesh_function_transfer.h>
17#include <lf/refinement/refinement.h>
18#include <mesh_function_velocity.h>
19#include <norms.h>
20#include <piecewise_const_element_matrix_provider.h>
21#include <piecewise_const_element_vector_provider.h>
22#include <solution_to_mesh_data_set.h>
23
24#include <cmath>
25#include <iomanip>
26#include <iostream>
27#include <numeric>
28#include <sstream>
29#include <string>
30
31using lf::uscalfe::operator-;
32using lf::uscalfe::operator*;
33
40template <typename... Args>
41static std::string concat(Args &&... args) {
42 std::ostringstream ss;
43 (ss << ... << args);
44 return ss.str();
45}
46
51 std::shared_ptr<const lf::mesh::Mesh> mesh;
52 std::shared_ptr<const lf::assemble::DofHandler> dofh;
53 Eigen::SparseMatrix<double> A;
54 Eigen::SparseMatrix<double> A_modified;
55 Eigen::VectorXd rhs;
56 Eigen::VectorXd solution;
57 Eigen::VectorXd solution_modified;
58};
59
68int main() {
69 const unsigned refinement_level = 7;
70
71 // Build the mesh
72 std::unique_ptr<lf::mesh::MeshFactory> factory =
73 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
74 lf::mesh::utils::TPTriagMeshBuilder builder(std::move(factory));
75 builder.setBottomLeftCorner(0, 0);
76 builder.setTopRightCorner(1, 1);
77 builder.setNumXCells(2);
78 builder.setNumYCells(2);
79 auto mesh0 = builder.Build();
80
81 // Generate a mesh hierarchy by regular refinement
82 const auto mesh_hierarchy =
84 refinement_level);
85
86 // Solve the problem for each mesh in the hierarchy
87 std::vector<ProblemSolution> solutions(refinement_level + 1);
88 for (lf::base::size_type lvl = 0; lvl < refinement_level + 1; ++lvl) {
89 const auto &mesh = mesh_hierarchy->getMesh(lvl);
90 auto &sol = solutions[lvl];
91 sol.mesh = mesh;
92 sol.dofh = std::shared_ptr<const lf::assemble::DofHandler>(
94 mesh, {{lf::base::RefEl::kPoint(), 1},
96 // No volume forces are present in this experiment
97 auto f = [](const Eigen::Vector2d & /*unused*/) -> Eigen::Vector2d {
98 return Eigen::Vector2d::Zero();
99 };
100 // The top lid is driven with velocity 1
101 auto dirichlet_funct = [](const lf::mesh::Entity &edge) -> Eigen::Vector2d {
102 static constexpr double eps = 1e-10;
103 const auto *const geom = edge.Geometry();
104 const auto vertices = geom->Global(edge.RefEl().NodeCoords());
105 Eigen::Vector2d v;
106 v << 1, 0;
107 if (vertices(1, 0) <= 1 + eps && vertices(1, 0) >= 1 - eps &&
108 vertices(1, 1) <= 1 + eps && vertices(1, 1) >= 1 - eps) {
109 return -v;
110 }
111 return Eigen::Vector2d::Zero();
112 };
113 const auto [A, rhs] =
115 sol.mesh, *(sol.dofh), f, dirichlet_funct, 100,
117 sol.A = A.makeSparse();
118 sol.rhs = rhs;
119 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
120 solver.compute(sol.A);
121 sol.solution = solver.solve(rhs);
122 const auto [A_modified, rhs_modified] =
124 sol.mesh, *(sol.dofh), f, dirichlet_funct, 100,
126 sol.A_modified = A_modified.makeSparse();
127 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver_modified(
128 sol.A_modified);
129 sol.solution_modified = solver_modified.solve(rhs_modified);
130 }
131
132 // Perform post processing on the data
133 const auto fe_space_fine =
134 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(
135 solutions.back().mesh);
137 velocity_exact(fe_space_fine, solutions.back().solution);
139 velocity_exact_modified(fe_space_fine,
140 solutions.back().solution_modified);
141 lf::io::VtkWriter writer(solutions.back().mesh, "result.vtk");
142 for (lf::base::size_type lvl = 0; lvl < refinement_level; ++lvl) {
143 const auto fe_space_lvl =
144 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(
145 solutions[lvl].mesh);
147 velocity_lvl(fe_space_lvl, solutions[lvl].solution);
149 velocity_lvl_modified(fe_space_lvl, solutions[lvl].solution_modified);
151 *mesh_hierarchy, velocity_lvl, lvl, mesh_hierarchy->NumLevels() - 1);
152 lf::refinement::MeshFunctionTransfer velocity_fine_modified(
153 *mesh_hierarchy, velocity_lvl_modified, lvl,
154 mesh_hierarchy->NumLevels() - 1);
155 writer.WriteCellData(concat("v_", solutions[lvl].mesh->NumEntities(2)),
156 velocity_fine);
157 writer.WriteCellData(
158 concat("v_modified", solutions[lvl].mesh->NumEntities(2)),
159 velocity_fine_modified);
160 // We need to implement our own binary mesh function for multiplication
161 const auto qr_provider = [](const lf::mesh::Entity &e) {
162 return lf::quad::make_QuadRule(e.RefEl(), 0);
163 };
164 const auto weight =
165 lf::mesh::utils::MeshFunctionGlobal([](const Eigen::Vector2d &x) {
166 return x[1] >= 0.9 ? (1 - std::cos(M_PI / 0.1 * (1 - x[1]))) / 2 : 1.;
167 });
168 const auto diff = velocity_fine - velocity_exact;
169 const auto diff_weighted = weight * diff;
170 const auto diff_modified = velocity_fine_modified - velocity_exact_modified;
171 const auto diff_weighted_modified = weight * diff_modified;
173 solutions.back().mesh, diff, qr_provider);
175 solutions.back().mesh, diff_weighted, qr_provider);
177 solutions.back().mesh, diff,
179 Eigen::Matrix2d::Zero()),
180 qr_provider);
181 const double L2_modified = projects::ipdg_stokes::post_processing::L2norm(
182 solutions.back().mesh, diff_modified, qr_provider);
183 const double L2w_modified = projects::ipdg_stokes::post_processing::L2norm(
184 solutions.back().mesh, diff_weighted_modified, qr_provider);
185 const double DG_modified = projects::ipdg_stokes::post_processing::DGnorm(
186 solutions.back().mesh, diff_modified,
188 Eigen::Matrix2d::Zero()),
189 qr_provider);
190 std::cout << lvl << ' ' << solutions[lvl].mesh->NumEntities(2) << ' ' << L2
191 << ' ' << L2w << ' ' << DG << ' ' << L2_modified << ' '
192 << L2w_modified << ' ' << DG_modified << std::endl;
193 }
194
195 return 0;
196}
Dofhandler for uniform finite element spaces.
Definition: dofhandler.h:257
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
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
A MeshFunction which takes the same constant value on the whole mesh.
MeshFunction wrapper for a simple function of physical coordinates.
StructuredMeshBuilder & setTopRightCorner(const VECTOR &&trc)
StructuredMeshBuilder & setBottomLeftCorner(const VECTOR &blc)
StructuredMeshBuilder & setNumXCells(size_type nxc)
StructuredMeshBuilder & setNumYCells(size_type nyc)
Implements a MeshBuilder that generates a triangular structured mesh.
std::shared_ptr< mesh::Mesh > Build() override
actual construction of the mesh
A MeshFunction representing interpolation on a lf::refinement::MeshHierarchy.
A MeshFunction returning the velocity computed from the basis function coefficients of a vector poten...
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
QuadRule make_TriaQR_MidpointRule()
midpoint quadrature rule for triangles
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.
std::shared_ptr< MeshHierarchy > GenerateMeshHierarchyByUniformRefinemnt(const std::shared_ptr< lf::mesh::Mesh > &mesh_p, lf::base::size_type ref_lev, RefPat ref_pat)
Generated a sequence of nested 2D hybrid mehes by regular or barycentric refinement.
std::tuple< lf::assemble::COOMatrix< double >, Eigen::VectorXd > buildSystemMatrixNoFlow(const std::shared_ptr< const lf::mesh::Mesh > &mesh, const lf::assemble::DofHandler &dofh, const std::function< Eigen::Vector2d(const Eigen::Vector2d &)> &f, const std::function< Eigen::Vector2d(const lf::mesh::Entity &)> &dirichlet_data, double sigma, const lf::quad::QuadRule &quadrule, bool modified_penalty)
Build the system matrix for the stokes system with no flow boundary conditions.
double DGnorm(const std::shared_ptr< const lf::mesh::Mesh > &mesh, const MF_F &f, const MF_GRAD &f_grad, const QR_SELECTOR &qr_selector)
Compute the DG-norm of a vector valued function over a mesh.
Definition: norms.h:68
double L2norm(const std::shared_ptr< const lf::mesh::Mesh > &mesh, const MF &f, const QR_SELECTOR &qr_selector)
Compute the -norm of a vector valued function over a mesh.
Definition: norms.h:40
stores information to recover convergence properties
Definition: convergence.cc:50
Eigen::VectorXd solution
Definition: convergence.cc:56
Eigen::SparseMatrix< double > A_modified
Definition: convergence.cc:54
Eigen::VectorXd solution_modified
Definition: convergence.cc:57
Eigen::SparseMatrix< double > A
Definition: convergence.cc:53
std::shared_ptr< const lf::mesh::Mesh > mesh
Definition: convergence.cc:51
Eigen::VectorXd rhs
Definition: convergence.cc:55
std::shared_ptr< const lf::assemble::DofHandler > dofh
Definition: convergence.cc:52