LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
whitney_one_curl_test.h
1#ifndef HLDO_SPHERE_WHITNEY_ONE_CURL_TEST_H
2#define HLDO_SPHERE_WHITNEY_ONE_CURL_TEST_H
3
8#include <lf/assemble/coomatrix.h>
9#include <lf/assemble/dofhandler.h>
10#include <lf/mesh/entity.h>
11#include <lf/mesh/hybrid2d/mesh.h>
12#include <lf/mesh/hybrid2d/mesh_factory.h>
13#include <lf/quad/quad.h>
14#include <rot_whitney_one_div_matrix_provider.h>
15#include <sphere_triag_mesh_builder.h>
16
17#include <Eigen/Dense>
18#include <cmath>
19#include <iomanip>
20#include <iostream>
21
22#include "whitney_one_basis_expansion_coeffs.h"
23
24namespace projects::hldo_sphere {
25
26namespace debugging {
27
47 public:
52 // create basic function everyting 0 valued by default
53 auto v = [](Eigen::Matrix<double, 3, 1> x) -> double { return 0; };
54 auto u = [](Eigen::Matrix<double, 3, 1> x) -> Eigen::Matrix<double, 3, 1> {
55 return Eigen::Matrix<double, 3, 1>::Zero();
56 };
57 v_ = v;
58 u_ = u;
59 discrete_sols_ = Eigen::VectorXd::Zero(1);
60 meshs_ = std::vector<std::shared_ptr<const lf::mesh::Mesh>>(1);
61 }
62
72 void Compute(int max_ref) {
73 // create matrix provider for the matrix
75 matrix_div_provider;
76
77 // Read the mesh from the gmsh file
78 std::unique_ptr<lf::mesh::MeshFactory> factory =
79 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(3);
80
83
84 // we always take the same radius
85 sphere.setRadius(1.);
86
87 discrete_sols_.resize(max_ref + 1);
88
89 meshs_.resize(max_ref + 1);
90
91 // start timer for total time
92 std::chrono::steady_clock::time_point start_time_total =
93 std::chrono::steady_clock::now();
94
95 // Loop over refinement levels
96 for (unsigned lvl = 0; lvl <= max_ref; ++lvl) {
97 std::cout << "\nstart computation of max_ref " << lvl << std::flush;
98
99 // start timer
100 std::chrono::steady_clock::time_point start_time =
101 std::chrono::steady_clock::now();
102
103 // get mesh
104 sphere.setRefinementLevel(lvl);
105 const std::shared_ptr<lf::mesh::Mesh> mesh = sphere.Build();
106 meshs_[lvl] = mesh;
107
108 // end timer
109 std::chrono::steady_clock::time_point end_time =
110 std::chrono::steady_clock::now();
111 double elapsed_sec =
112 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
113 start_time)
114 .count() /
115 1000.;
116
117 std::cout << " -> built mesh " << elapsed_sec << " [s] " << std::flush;
118
119 // start timer
120 start_time = std::chrono::steady_clock::now();
121
122 // computes the assemby matrix
123 const lf::assemble::DofHandler &dof_handler_edge =
126 const lf::assemble::DofHandler &dof_handler_cell =
128 {{lf::base::RefEl::kTria(), 1}});
129
130 // create coo matrix
131 const lf::assemble::size_type n_dofs_edge(dof_handler_edge.NumDofs());
132 const lf::assemble::size_type n_dofs_cell(dof_handler_cell.NumDofs());
133
134 // note that the rotwoneformdivelementmatrixprovider returns the
135 lf::assemble::COOMatrix<double> coo_mat(n_dofs_edge, n_dofs_cell);
136 coo_mat.setZero();
137
138 // create matrix with n_dofs_edge_rows and n_dofs_cell columns
139 lf::assemble::AssembleMatrixLocally<lf::assemble::COOMatrix<double>>(
140 0, dof_handler_cell, dof_handler_edge, matrix_div_provider, coo_mat);
141
142 // compute basis expansion coefficients
144 one_coeffs.SetMesh(mesh);
145 one_coeffs.SetFunction(u_);
146 one_coeffs.Compute();
147 Eigen::Matrix<double, Eigen::Dynamic, 1> u_h(n_dofs_edge);
148 u_h = one_coeffs.GetMu();
149
150 // get analytical values at the cell midpoints for the expansion
151 // coefficients of v
152 Eigen::Matrix<double, Eigen::Dynamic, 1> v_h(n_dofs_cell);
153 for (const lf::mesh::Entity *c : mesh->Entities(0)) {
154 Eigen::MatrixXd points(3, 3);
155 points = lf::geometry::Corners(*(c->Geometry()));
156 Eigen::VectorXd midpoint =
157 (points.col(0) + points.col(1) + points.col(2)) / 3.;
158
159 // scale up on sphere
160 midpoint = midpoint / midpoint.norm();
161
162 unsigned glob_idx = mesh->Index(*c);
163 v_h(glob_idx) = v_(midpoint);
164 }
165
166 discrete_sols_[lvl] = u_h.transpose() * coo_mat.makeSparse() * v_h;
167
168 // end timer
169 end_time = std::chrono::steady_clock::now();
170 elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
171 end_time - start_time)
172 .count() /
173 1000.;
174
175 std::cout << " -> computed discret solution " << elapsed_sec << " [s] "
176 << std::flush;
177
178 } // end loop level
179
180 // end timer total
181 std::chrono::steady_clock::time_point end_time_total =
182 std::chrono::steady_clock::now();
183 double elapsed_sec_total =
184 std::chrono::duration_cast<std::chrono::milliseconds>(end_time_total -
185 start_time_total)
186 .count() /
187 1000.;
188
189 std::cout << "\nTotal computation time for all levels " << elapsed_sec_total
190 << " [s]\n";
191
192 // output the erros in a file
193
194 // create results direcotry
195 std::string main_dir = "results";
196 std::filesystem::create_directory(main_dir);
197
198 // prepare output
199 int table_width = 13;
200 int precision = 4;
201
202 // create csv file
203 std::ofstream csv_file;
204 std::string csv_name = concat("whitney_one_curl_test_", max_ref);
205 std::replace(csv_name.begin(), csv_name.end(), '.', '_');
206 csv_file.open(concat(main_dir, "/", csv_name, ".csv"));
207 csv_file << "numCells,"
208 << "numEdges,"
209 << "numVerts,"
210 << "hMax";
211
212 // introduce columns for errors
213 csv_file << ",Errors";
214 csv_file << std::endl;
215
216 Eigen::VectorXd hMax(max_ref + 1);
217 hMax.setZero();
218
219 // loop over all levels contained in the solution
220 for (lf::base::size_type lvl = 0; lvl <= max_ref; ++lvl) {
221 // create mesh Functions for solutions the level
222 auto &sol_mesh = meshs_[lvl];
223
224 // compute meshwidth
225 for (const lf::mesh::Entity *e : sol_mesh->Entities(1)) {
226 double h = lf::geometry::Volume(*(e->Geometry()));
227 if (h > hMax(lvl)) hMax(lvl) = h;
228 }
229
230 // print level and mesh informations
231 csv_file << sol_mesh->NumEntities(0) << "," << sol_mesh->NumEntities(1)
232 << "," << sol_mesh->NumEntities(2) << "," << hMax(lvl);
233
234 csv_file << "," << std::abs(ana_sol_ - discrete_sols_[lvl]) << "\n";
235 } // end loop over levels
236
237 // close csv file
238 csv_file.close();
239 }
240
247 void SetAnaSol(double sol) { ana_sol_ = sol; }
248
256 std::function<double(const Eigen::Matrix<double, 3, 1> &)> v,
257 std::function<
258 Eigen::Matrix<double, 3, 1>(const Eigen::Matrix<double, 3, 1> &)>
259 u) {
260 v_ = v;
261 u_ = u;
262 }
263
264 private:
265 std::function<double(const Eigen::Matrix<double, 3, 1> &)> v_;
266 std::function<Eigen::Matrix<double, 3, 1>(
267 const Eigen::Matrix<double, 3, 1> &)>
269 double ana_sol_;
270 Eigen::VectorXd discrete_sols_;
271 std::vector<std::shared_ptr<const lf::mesh::Mesh>> meshs_;
272};
273
274} // namespace debugging
275
276} // namespace projects::hldo_sphere
277
278#endif // THESIS_OPERATORS_WHITNEY_ONE_HODGE_LAPLACE_H
A temporary data structure for matrix in COO format.
Definition: coomatrix.h:52
void setZero()
Erase all entries of the matrix.
Definition: coomatrix.h:98
Eigen::SparseMatrix< Scalar > makeSparse() const
Create an Eigen::SparseMatrix out of the COO format.
Definition: coomatrix.h:172
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual size_type NumDofs() const =0
total number of dof's handled by the object
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 kTria()
Returns the reference triangle.
Definition: ref_el.h:158
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
Class to find the "best" basisexpansion coefficients with the analytical solution.
Tests convergence of the below bilinear form on the Mesh to the analytical solution.
std::function< double(const Eigen::Matrix< double, 3, 1 > &)> v_
std::function< Eigen::Matrix< double, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> u_
void Compute(int max_ref)
Computes the error up to the refinemet level 'max_ref'.
std::vector< std::shared_ptr< const lf::mesh::Mesh > > meshs_
void SetAnaSol(double sol)
Sets the value of the analytical solution .
WhitneyOneCurlTest()
Constructor creates an object with zero testfunctions.
void SetFunctions(std::function< double(const Eigen::Matrix< double, 3, 1 > &)> v, std::function< Eigen::Matrix< double, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> u)
Sets the test functions.
void setRefinementLevel(lf::base::size_type n)
Set the refinement level.
std::shared_ptr< lf::mesh::Mesh > Build()
Build the mesh.
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
lf::base::size_type size_type
Eigen::MatrixXd Corners(const Geometry &geo)
The corners of a shape with piecewise smooth boundary.
double Volume(const Geometry &geo)
Compute the (approximate) volume (area) of a shape.
static std::string concat(Args &&...args)
Concatenate objects defining an operator<<(std::ostream&)
Definition: debugging.h:26
Implementation of the thesis Hogde Laplacians and Dirac Operators on the surface of the 3-Sphere.
Definition: assemble.h:15