LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
manufactured_solution.cc
1
6#define _USE_MATH_DEFINES
7#include <build_system_matrix.h>
8#include <lf/assemble/dofhandler.h>
9#include <lf/fe/fe.h>
10#include <lf/io/gmsh_reader.h>
11#include <lf/io/vtk_writer.h>
12#include <lf/mesh/entity.h>
13#include <lf/mesh/hybrid2d/mesh_factory.h>
14#include <lf/mesh/utils/tp_triag_mesh_builder.h>
15#include <lf/mesh/utils/utils.h>
16#include <lf/quad/quad.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 <filesystem>
25#include <iomanip>
26#include <iostream>
27#include <numeric>
28#include <sstream>
29#include <string>
30
37Eigen::Vector2d computeU(int n, Eigen::Vector2d x) {
38 const double r = x.norm();
39 const double u0 = 1 - std::cos(2 * M_PI * n * r);
40 Eigen::Vector2d u;
41 u << -x[1], x[0];
42 return u0 * u.normalized();
43}
44
51Eigen::Matrix2d computeUGrad(int n, Eigen::Vector2d x) {
52 const double r = x.norm();
53 const double r2 = r * r;
54 const double r3 = r2 * r;
55 const double phi = 2 * M_PI * n * r;
56 const double cphi = std::cos(phi);
57 const double sphi = std::sin(phi);
58 Eigen::Matrix2d grad;
59 grad << x[0] * x[1] / r3 * (1 - cphi) -
60 2 * M_PI * n * x[0] * x[1] / r2 * sphi,
61 (1. / r - x[0] * x[0] / r3) * (1 - cphi) +
62 2 * M_PI * n * x[0] * x[0] / r2 * sphi,
63 (x[0] * x[1] / r3 - 1. / r) * (1 - cphi) +
64 2 * M_PI * n * x[1] * x[1] / r2 * sphi,
65 -x[0] * x[1] / r3 * (1 - cphi) + 2 * M_PI * n * x[0] * x[1] / r2 * sphi;
66 return grad;
67}
68
75Eigen::Vector2d computeF(int n, Eigen::Vector2d x) {
76 const double r = x.norm();
77 const double f0 = r == 0 ? -6 * n * n * M_PI * M_PI
78 : (1 -
79 (1 + 4 * n * n * M_PI * M_PI * r * r) *
80 std::cos(2 * M_PI * n * r) -
81 2 * M_PI * n * r * std::sin(2 * M_PI * n * r)) /
82 (r * r);
83 Eigen::Vector2d f;
84 f << -x[1], x[0];
85 return f0 * f.normalized();
86}
87
94template <typename... Args>
95static std::string concat(Args&&... args) {
96 std::ostringstream ss;
97 (ss << ... << args);
98 return ss.str();
99}
100
104struct ProblemSolution {
105 std::shared_ptr<const lf::mesh::Mesh> mesh;
106 std::shared_ptr<const lf::assemble::DofHandler> dofh;
107 Eigen::SparseMatrix<double> A;
108 Eigen::SparseMatrix<double> A_modified;
109 Eigen::VectorXd rhs;
110 Eigen::VectorXd solution;
111 Eigen::VectorXd solution_modified;
112};
113
122int main() {
123 const unsigned mesh_count = 6;
124 const int n = 3;
125 const unsigned quadrule_degree = 10;
126
127 // Compute the solution for each mesh
128 std::vector<ProblemSolution> solutions(mesh_count);
129 for (lf::base::size_type lvl = 0; lvl < mesh_count; ++lvl) {
130 std::filesystem::path meshpath = __FILE__;
131 meshpath = meshpath.parent_path() / concat("disk", lvl, ".msh");
132 std::unique_ptr<lf::mesh::MeshFactory> factory =
133 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
134 lf::io::GmshReader reader(std::move(factory), meshpath.string());
135 auto mesh = reader.mesh();
136 auto& sol = solutions[lvl];
137 sol.mesh = mesh;
138 sol.dofh = std::shared_ptr<const lf::assemble::DofHandler>(
140 mesh, {{lf::base::RefEl::kPoint(), 1},
142 // Use the volume forces returned by computeF
143 auto f = [n](const Eigen::Vector2d& x) -> Eigen::Vector2d {
144 return computeF(n, x);
145 };
146 // The velocity on the boundary is zero everywhere
147 auto dirichlet_funct = [](const lf::mesh::Entity &
148 /*unused*/) -> Eigen::Vector2d {
149 return Eigen::Vector2d::Zero();
150 };
151 const auto [A, rhs] =
153 sol.mesh, *(sol.dofh), f, dirichlet_funct, 1,
155 false);
156 sol.A = A.makeSparse();
157 sol.rhs = rhs;
158 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver;
159 solver.compute(sol.A);
160 sol.solution = solver.solve(rhs);
161 const auto [A_modified, rhs_modified] =
163 sol.mesh, *(sol.dofh), f, dirichlet_funct, 1,
165 true);
166 sol.A_modified = A_modified.makeSparse();
167 Eigen::SparseLU<Eigen::SparseMatrix<double>> solver_modified(
168 sol.A_modified);
169 sol.solution_modified = solver_modified.solve(rhs_modified);
170 }
171
172 // Perform post processing on the data
173 const auto analyticU = lf::mesh::utils::MeshFunctionGlobal(
174 [&](const Eigen::Vector2d& x) -> Eigen::Vector2d {
175 return computeU(n, x);
176 });
177 const auto analyticF = lf::mesh::utils::MeshFunctionGlobal(
178 [&](const Eigen::Vector2d& x) -> Eigen::Vector2d {
179 return computeF(n, x);
180 });
181 for (lf::base::size_type lvl = 0; lvl < mesh_count; ++lvl) {
182 const auto fe_space =
183 std::make_shared<lf::uscalfe::FeSpaceLagrangeO1<double>>(
184 solutions[lvl].mesh);
185 const auto velocity_exact = lf::mesh::utils::MeshFunctionGlobal(
186 [n](const Eigen::Vector2d& x) { return computeU(n, x); });
187 const auto grad_exact = lf::mesh::utils::MeshFunctionGlobal(
188 [n](const Eigen::Vector2d& x) -> Eigen::Matrix2d {
189 return computeUGrad(n, x);
190 });
192 velocity(fe_space, solutions[lvl].solution);
194 velocity_modified(fe_space, solutions[lvl].solution_modified);
195 lf::io::VtkWriter writer(solutions[lvl].mesh,
196 concat("result", lvl, ".vtk"));
197 writer.WriteCellData("analyticU", analyticU);
198 writer.WriteCellData("analyticF", analyticF);
199 writer.WriteCellData("U", velocity);
200 writer.WriteCellData("U_modified", velocity_modified);
201 // The error in the velocity
202 const auto diff_v = velocity - velocity_exact;
203 const auto diff_v_modified = velocity_modified - velocity_exact;
204 // The error in the gradient of the velocity
205 const auto diff_grad = -grad_exact;
206 const auto diff_grad_modified = -grad_exact;
207 // Approximately compute the factor the numerical solution is off by
208 const auto qr_provider = [](const lf::mesh::Entity& e) {
209 return lf::quad::make_QuadRule(e.RefEl(), 0);
210 };
211 const double factor =
213 *(solutions[lvl].mesh),
214 lf::mesh::utils::transpose(velocity) * velocity_exact,
215 qr_provider)(0, 0) /
216 lf::fe::IntegrateMeshFunction(*(solutions[lvl].mesh),
217 lf::mesh::utils::squaredNorm(velocity),
218 qr_provider);
219 const double factor_modified =
221 *(solutions[lvl].mesh),
222 lf::mesh::utils::transpose(velocity_modified) * velocity_exact,
223 qr_provider)(0, 0) /
225 *(solutions[lvl].mesh),
226 lf::mesh::utils::squaredNorm(velocity_modified), qr_provider);
227 std::cout << factor << std::endl;
228 // The error in the corrected velocity
229 const auto velocity_scaled =
231 const auto velocity_scaled_modified =
233 velocity_modified;
234 const auto diff_v_fac = velocity_scaled - velocity_exact;
235 const auto diff_v_fac_modified = velocity_scaled_modified - velocity_exact;
236 // The error in the gradient of the corrected velocty
237 const auto& diff_g_fac = diff_grad;
238 const auto& diff_g_fac_modified = diff_grad_modified;
240 solutions[lvl].mesh, diff_v, qr_provider);
242 solutions[lvl].mesh, diff_v, diff_grad, qr_provider);
244 solutions[lvl].mesh, diff_v_fac, qr_provider);
246 solutions[lvl].mesh, diff_v_fac, diff_g_fac, qr_provider);
247 const double L2_modified = projects::ipdg_stokes::post_processing::L2norm(
248 solutions[lvl].mesh, diff_v_modified, qr_provider);
249 const double DG_modified = projects::ipdg_stokes::post_processing::DGnorm(
250 solutions[lvl].mesh, diff_v_modified, diff_grad_modified, qr_provider);
251 const double L2f_modified = projects::ipdg_stokes::post_processing::L2norm(
252 solutions[lvl].mesh, diff_v_fac_modified, qr_provider);
253 const double DGf_modified = projects::ipdg_stokes::post_processing::DGnorm(
254 solutions[lvl].mesh, diff_v_fac_modified, diff_g_fac_modified,
255 qr_provider);
256 std::cout << lvl << ' ' << solutions[lvl].mesh->NumEntities(2) << ' ' << L2
257 << ' ' << DG << ' ' << L2f << ' ' << DGf << ' ' << L2_modified
258 << ' ' << DG_modified << ' ' << L2f_modified << ' '
259 << DGf_modified << std::endl;
260 }
261}
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
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
A MeshFunction which takes the same constant value on the whole mesh.
MeshFunction wrapper for a simple function of physical coordinates.
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
auto IntegrateMeshFunction(const lf::mesh::Mesh &mesh, const MF &mf, const QR_SELECTOR &qr_selector, const ENTITY_PREDICATE &ep=base::PredicateTrue{}, int codim=0) -> mesh::utils::MeshFunctionReturnType< MF >
Integrate a MeshFunction over a mesh (with quadrature rules)
Definition: fe_tools.h:111
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.
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