LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
results_processing.h
1#ifndef HLDO_SPHERE_POST_PROCESSING_RESULTS_PROCESSING_H
2#define HLDO_SPHERE_POST_PROCESSING_RESULTS_PROCESSING_H
3
10#include <lf/io/vtk_writer.h>
11#include <mesh_function_whitney_one.h>
12#include <mesh_function_whitney_two.h>
13#include <mesh_function_whitney_zero.h>
14#include <norms.h>
15#include <sphere_triag_mesh_builder.h>
16
17#include <Eigen/Dense>
18#include <cstdlib>
19#include <cstring>
20#include <filesystem>
21#include <fstream>
22#include <iomanip>
23#include <iostream>
24#include <string>
25#include <vector>
26
27namespace projects::hldo_sphere {
28
29namespace post_processing {
30
31// operator used to subract meshfunctions
32using lf::uscalfe::operator-;
33
39template <typename SCALAR>
41 std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>> mu_zero;
42 std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>> mu_one;
43 std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>> mu_two;
44};
45
52template <typename SCALAR>
54 std::vector<unsigned> levels;
55 std::vector<double> k;
56 // each element in the vector corresponds to one refinement level
57 std::vector<std::shared_ptr<const lf::mesh::Mesh>> mesh;
58 std::vector<ProblemSolution<SCALAR>> solutions;
59};
60
67template <typename... Args>
68static std::string concat(Args &&...args) {
69 std::ostringstream ss;
70 (ss << ... << args);
71 return ss.str();
72}
73
95template <typename SCALAR>
96void compare_results(std::string name,
98 ProblemSolutionWrapper<SCALAR> &results_dirac) {
99 // create results direcotry
100 std::string main_dir = "results";
101 std::filesystem::create_directory(main_dir);
102
103 // each containing number of k values
104 int nk = results_lap.k.size();
105 int nl = results_lap.levels.size();
106
107 // check if results have the same dimensions
108 LF_ASSERT_MSG(nk == results_dirac.k.size(),
109 "Results differ in the number of computed k");
110 LF_ASSERT_MSG(nl == results_dirac.levels.size(),
111 "Results differ in the number of computed refinement levels");
112
113 // prepare output
114 int table_width = 13;
115 int precision = 4;
116
117 // name the csv file accoring to min and max k
118 double min_k = results_lap.k[0];
119 double max_k = results_lap.k[nk - 1];
120
121 // create csv file
122 std::ofstream csv_file;
123 std::string csv_name = concat("result_", name, "_", min_k, "-", max_k);
124 std::replace(csv_name.begin(), csv_name.end(), '.', '_');
125 csv_file.open(concat(main_dir, "/", csv_name, ".csv"));
126 csv_file << "numCells,"
127 << "numEdges,"
128 << "numVerts,"
129 << "hMax";
130
131 // define square functions for norms
132 auto square_scalar = [](SCALAR a) -> double {
133 return std::abs(a) * std::abs(a);
134 };
135 auto square_vector =
136 [](Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> a) -> double {
137 return a.squaredNorm();
138 };
139
140 // define quadrule for norms
142
143 // create solution matrix with levels on rows and ks in
144 Eigen::MatrixXd L2ErrorZero = Eigen::MatrixXd::Zero(nl, nk);
145 Eigen::MatrixXd L2ErrorOne = Eigen::MatrixXd::Zero(nl, nk);
146 Eigen::MatrixXd L2ErrorTwo = Eigen::MatrixXd::Zero(nl, nk);
147 Eigen::VectorXd hMax = Eigen::VectorXd::Zero(nl);
148
149 // tabulate every k value
150 for (int i = 0; i < nk; i++) {
151 csv_file << ",L2ErrorZero_" << results_lap.k[i] << ",RateL2ErrorZero_"
152 << results_lap.k[i] << ",L2ErrorOne_" << results_lap.k[i]
153 << ",RateL2ErrorOne_" << results_lap.k[i] << ",L2ErrorTwo_"
154 << results_lap.k[i] << ",RateL2ErrorTwo_" << results_lap.k[i];
155
156 // create direcotries for each k
157 std::string kstr = concat(results_lap.k[i]);
158 std::replace(kstr.begin(), kstr.end(), '.', '_');
159 std::filesystem::create_directory(concat(main_dir, "/k_", kstr));
160 }
161 csv_file << std::endl;
162
163 // write the k values to the csv file
164 csv_file << ","
165 << ","
166 << ",";
167 for (int i = 0; i < nk; i++) {
168 csv_file << "," << results_lap.k[i] << "," << results_lap.k[i] << ","
169 << results_lap.k[i] << "," << results_lap.k[i] << ","
170 << results_lap.k[i] << "," << results_lap.k[i];
171 }
172 csv_file << std::endl;
173
174 // loop over all levels contained in the solution
175 for (lf::base::size_type lvl = 0; lvl < nl; ++lvl) {
176 // create mesh Functions for solutions the level
177 auto &sol_mesh = results_lap.mesh[lvl];
178 auto &sol_mus_lap = results_lap.solutions[lvl];
179 auto &sol_mus_dirac = results_dirac.solutions[lvl];
180
181 // compute meshwidth
182 for (const lf::mesh::Entity *e : sol_mesh->Entities(1)) {
183 double h = lf::geometry::Volume(*(e->Geometry()));
184 if (h > hMax(lvl)) hMax(lvl) = h;
185 }
186
187 // print level and mesh informations
188 csv_file << sol_mesh->NumEntities(0) << "," << sol_mesh->NumEntities(1)
189 << "," << sol_mesh->NumEntities(2) << "," << hMax(lvl);
190
191 // compute the errors for each k
192 for (int ik = 0; ik < nk; ik++) {
193 std::string kstr = concat(results_lap.k[ik]);
194 std::replace(kstr.begin(), kstr.end(), '.', '_');
195 std::string folder = concat(main_dir, "/k_", kstr);
196
198 mf_zero_lap(sol_mus_lap.mu_zero[ik], sol_mesh);
200 sol_mus_lap.mu_one[ik], sol_mesh);
202 sol_mus_lap.mu_two[ik], sol_mesh);
203
205 mf_zero_dirac(sol_mus_dirac.mu_zero[ik], sol_mesh);
207 mf_one_dirac(sol_mus_dirac.mu_one[ik], sol_mesh);
209 mf_two_dirac(sol_mus_dirac.mu_two[ik], sol_mesh);
210
211 // Compute the error of the solutions
212 auto mf_diff_zero = mf_zero_lap - mf_zero_dirac;
213 auto mf_diff_one = mf_one_lap - mf_one_dirac;
214 auto mf_diff_two = mf_two_lap - mf_two_dirac;
215
216 // Perform post processing on the data
217 lf::io::VtkWriter writer(sol_mesh, concat(folder, "/result_", name, "_",
218 lvl, "_k_", kstr, ".vtk"));
219
220 // get error for zero form
221 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
223 sol_mesh, mf_diff_zero, square_scalar, qr);
224 L2ErrorZero(lvl, ik) = std::get<0>(L2_zero);
225 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_zero =
226 std::get<1>(L2_zero);
227 writer.WriteCellData(concat("mf_zero_diff_", lvl), data_set_error_zero);
228
229 // get error for one form
230 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
232 sol_mesh, mf_diff_one, square_vector, qr);
233 L2ErrorOne(lvl, ik) = std::get<0>(L2_one);
234 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_one =
235 std::get<1>(L2_one);
236 writer.WriteCellData(concat("mf_one_diff_", lvl), data_set_error_one);
237
238 // get error for two form
239 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
241 sol_mesh, mf_diff_two, square_scalar, qr);
242 L2ErrorTwo(lvl, ik) = std::get<0>(L2_two);
243 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_two =
244 std::get<1>(L2_two);
245 writer.WriteCellData(concat("mf_two_diff_", lvl), data_set_error_two);
246
247 double l2RateZero = 0;
248 double l2RateOne = 0;
249 double l2RateTwo = 0;
250
251 // we can only compute order form the second level
252 if (lvl > 0) {
253 l2RateZero =
254 (log(L2ErrorZero(lvl, ik)) - log(L2ErrorZero(lvl - 1, ik))) /
255 (log(hMax(lvl) / hMax(lvl - 1)));
256 l2RateOne = (log(L2ErrorOne(lvl, ik)) - log(L2ErrorOne(lvl - 1, ik))) /
257 (log(hMax(lvl) / hMax(lvl - 1)));
258 l2RateTwo = (log(L2ErrorTwo(lvl, ik)) - log(L2ErrorTwo(lvl - 1, ik))) /
259 (log(hMax(lvl) / hMax(lvl - 1)));
260 }
261
262 /******************************
263 * append solution of the current k in the outputs
264 ******************************/
265
266 csv_file << "," << L2ErrorZero(lvl, ik) << "," << l2RateZero << ","
267 << L2ErrorOne(lvl, ik) << "," << l2RateOne << ","
268 << L2ErrorTwo(lvl, ik) << "," << l2RateTwo;
269
270 } // end loop over k
271
272 csv_file << "\n";
273 } // end loop over levels
274
275 // close csv file
276 csv_file.close();
277}
278
301template <typename U_ZERO, typename U_ONE, typename U_TWO, typename SCALAR>
302void process_results(std::string name, ProblemSolutionWrapper<SCALAR> &results,
303 U_ZERO &u_zero, U_ONE &u_one, U_TWO &u_two, double &k) {
304 // create results direcotry
305 std::string main_dir = "results";
306 std::filesystem::create_directory(main_dir);
307
308 // each containing number of k values
309 int nk = results.k.size();
310 int nl = results.levels.size();
311
312 // prepare output
313 int table_width = 13;
314 int precision = 4;
315
316 // name the csv file accoring to min and max k
317 double min_k = results.k[0];
318 double max_k = results.k[nk - 1];
319
320 // create csv file
321 std::ofstream csv_file;
322 std::string csv_name = concat("result_", name, "_", min_k, "-", max_k);
323 std::replace(csv_name.begin(), csv_name.end(), '.', '_');
324 csv_file.open(concat(main_dir, "/", csv_name, ".csv"));
325 csv_file << "numCells,"
326 << "numEdges,"
327 << "numVerts,"
328 << "hMax";
329
330 // define square functions for norms
331 auto square_scalar = [](SCALAR a) -> double {
332 return std::abs(a) * std::abs(a);
333 };
334 auto square_vector =
335 [](Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> a) -> double {
336 return a.squaredNorm();
337 };
338
339 // define quadrule for norms
341
342 // create solution matrix with levels on rows and ks in colums
343 Eigen::MatrixXd SupErrorZero = Eigen::MatrixXd::Zero(nl, nk);
344 Eigen::MatrixXd SupErrorOne = Eigen::MatrixXd::Zero(nl, nk);
345 Eigen::MatrixXd SupErrorTwo = Eigen::MatrixXd::Zero(nl, nk);
346 Eigen::MatrixXd L2ErrorZero = Eigen::MatrixXd::Zero(nl, nk);
347 Eigen::MatrixXd L2ErrorOne = Eigen::MatrixXd::Zero(nl, nk);
348 Eigen::MatrixXd L2ErrorTwo = Eigen::MatrixXd::Zero(nl, nk);
349 Eigen::VectorXd hMax = Eigen::VectorXd::Zero(nl);
350
351 // tabulate every k value
352 for (int i = 0; i < nk; i++) {
353 csv_file << ",SupErrorZero_" << results.k[i] << ",RateSupErrorZero_"
354 << results.k[i] << ",SupErrorOne_" << results.k[i]
355 << ",RateSupErrorOne_" << results.k[i] << ",SupErrorTwo_"
356 << results.k[i] << ",RateSupErrorTwo_" << results.k[i]
357 << ",L2ErrorZero_" << results.k[i] << ",RateL2ErrorZero_"
358 << results.k[i] << ",L2ErrorOne_" << results.k[i]
359 << ",RateL2ErrorOne_" << results.k[i] << ",L2ErrorTwo_"
360 << results.k[i] << ",RateL2ErrorTwo_" << results.k[i];
361
362 // create direcotries for each k
363 std::string kstr = concat(results.k[i]);
364 std::replace(kstr.begin(), kstr.end(), '.', '_');
365 std::filesystem::create_directory(concat(main_dir, "/k_", kstr));
366 }
367 csv_file << std::endl;
368
369 // write the k values to the csv file
370 csv_file << ","
371 << ","
372 << ",";
373 for (int i = 0; i < nk; i++) {
374 csv_file << "," << results.k[i] << "," << results.k[i] << ","
375 << results.k[i] << "," << results.k[i] << "," << results.k[i]
376 << "," << results.k[i] << "," << results.k[i] << ","
377 << results.k[i] << "," << results.k[i] << "," << results.k[i]
378 << "," << results.k[i] << "," << results.k[i];
379 }
380 csv_file << std::endl;
381
382 // loop over all levels contained in the solution
383 for (lf::base::size_type lvl = 0; lvl < nl; ++lvl) {
384 // create mesh Functions for solutions the level
385 auto &sol_mesh = results.mesh[lvl];
386 auto &sol_mus = results.solutions[lvl];
387
388 // compute meshwidth
389 for (const lf::mesh::Entity *e : sol_mesh->Entities(1)) {
390 double h = lf::geometry::Volume(*(e->Geometry()));
391 if (h > hMax(lvl)) hMax(lvl) = h;
392 }
393
394 // print level and mesh informations
395 csv_file << sol_mesh->NumEntities(0) << "," << sol_mesh->NumEntities(1)
396 << "," << sol_mesh->NumEntities(2) << "," << hMax(lvl);
397
398 // compute the errors for each k
399 for (int ik = 0; ik < nk; ik++) {
400 std::string kstr = concat(results.k[ik]);
401 std::replace(kstr.begin(), kstr.end(), '.', '_');
402 std::string folder = concat(main_dir, "/k_", kstr);
403
405 sol_mus.mu_zero[ik], sol_mesh);
407 sol_mus.mu_one[ik], sol_mesh);
409 sol_mus.mu_two[ik], sol_mesh);
410
411 // set k and therefore change function since the k is used in the
412 // funcitons
413 k = results.k[ik];
417
418 // Compute the error of the solutions
419 auto mf_diff_zero = mf_zero - mf_zero_ana;
420 auto mf_diff_one = mf_one - mf_one_ana;
421 auto mf_diff_two = mf_two - mf_two_ana;
422
423 // Perform post processing on the data
424 lf::io::VtkWriter writer(sol_mesh, concat(folder, "/result_", name, "_",
425 lvl, "_k_", kstr, ".vtk"));
426
427 // get error for zero form
428 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
430 sol_mesh, mf_diff_zero, square_scalar, qr);
431 L2ErrorZero(lvl, ik) = std::get<0>(L2_zero);
432 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_zero =
433 std::get<1>(L2_zero);
434 writer.WriteCellData(concat("mf_zero_diff_", lvl), data_set_error_zero);
435
436 // get error for one form
437 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
439 sol_mesh, mf_diff_one, square_vector, qr);
440 L2ErrorOne(lvl, ik) = std::get<0>(L2_one);
441 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_one =
442 std::get<1>(L2_one);
443 writer.WriteCellData(concat("mf_one_diff_", lvl), data_set_error_one);
444
445 // get error for two form
446 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
448 sol_mesh, mf_diff_two, square_scalar, qr);
449 L2ErrorTwo(lvl, ik) = std::get<0>(L2_two);
450 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_two =
451 std::get<1>(L2_two);
452 writer.WriteCellData(concat("mf_two_diff_", lvl), data_set_error_two);
453
454 // get sup error for zero form
455 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
457 sol_mesh, mf_diff_zero, square_scalar, qr);
458 SupErrorZero(lvl, ik) = std::get<0>(sup_zero);
459 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_sup_zero =
460 std::get<1>(sup_zero);
461 writer.WriteCellData(concat("mf_zero_diff_sup_", lvl),
462 data_set_error_sup_zero);
463
464 // get error for one form
465 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
467 sol_mesh, mf_diff_one, square_vector, qr);
468 SupErrorOne(lvl, ik) = std::get<0>(sup_one);
469 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_sup_one =
470 std::get<1>(sup_one);
471 writer.WriteCellData(concat("mf_one_diff_sup_", lvl),
472 data_set_error_sup_one);
473
474 // get error for two form
475 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>>
477 sol_mesh, mf_diff_two, square_scalar, qr);
478 SupErrorTwo(lvl, ik) = std::get<0>(sup_two);
479 const lf::mesh::utils::CodimMeshDataSet<double> data_set_error_sup_two =
480 std::get<1>(sup_two);
481 writer.WriteCellData(concat("mf_two_diff_sup_", lvl),
482 data_set_error_sup_two);
483
484 double l2RateZero = 0;
485 double l2RateOne = 0;
486 double l2RateTwo = 0;
487 double supRateZero = 0;
488 double supRateOne = 0;
489 double supRateTwo = 0;
490
491 // we can only compute order form the second level
492 if (lvl > 0) {
493 l2RateZero =
494 (log(L2ErrorZero(lvl, ik)) - log(L2ErrorZero(lvl - 1, ik))) /
495 (log(hMax(lvl) / hMax(lvl - 1)));
496 l2RateOne = (log(L2ErrorOne(lvl, ik)) - log(L2ErrorOne(lvl - 1, ik))) /
497 (log(hMax(lvl) / hMax(lvl - 1)));
498 l2RateTwo = (log(L2ErrorTwo(lvl, ik)) - log(L2ErrorTwo(lvl - 1, ik))) /
499 (log(hMax(lvl) / hMax(lvl - 1)));
500 supRateZero =
501 (log(SupErrorZero(lvl, ik)) - log(SupErrorZero(lvl - 1, ik))) /
502 (log(hMax(lvl) / hMax(lvl - 1)));
503 supRateOne =
504 (log(SupErrorOne(lvl, ik)) - log(SupErrorOne(lvl - 1, ik))) /
505 (log(hMax(lvl) / hMax(lvl - 1)));
506 supRateTwo =
507 (log(SupErrorTwo(lvl, ik)) - log(SupErrorTwo(lvl - 1, ik))) /
508 (log(hMax(lvl) / hMax(lvl - 1)));
509 }
510
511 /******************************
512 * append solution of the current k in the outputs
513 ******************************/
514
515 csv_file << "," << SupErrorZero(lvl, ik) << "," << supRateZero << ","
516 << SupErrorOne(lvl, ik) << "," << supRateOne << ","
517 << SupErrorTwo(lvl, ik) << "," << supRateTwo << ","
518 << L2ErrorZero(lvl, ik) << "," << l2RateZero << ","
519 << L2ErrorOne(lvl, ik) << "," << l2RateOne << ","
520 << L2ErrorTwo(lvl, ik) << "," << l2RateTwo;
521
522 } // end loop over k
523
524 csv_file << "\n";
525 } // end loop over levels
526
527 // close csv file
528 csv_file.close();
529}
530
531} // end namespace post_processing
532
533} // namespace projects::hldo_sphere
534
535#endif // HLDO_SPHERE_POST_PROCESSING_RESULTS_PROCESSING_H
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
Write a mesh along with mesh data into a vtk file.
Definition: vtk_writer.h:272
void WriteCellData(const std::string &name, const mesh::utils::MeshDataSet< unsigned char > &mds, unsigned char undefined_value=0)
Add a new unsigned char attribute dataset that attaches data to the cells of the mesh (i....
Definition: vtk_writer.cc:860
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
A MeshDataSet that attaches data of type T to every entity of a mesh that has a specified codimension...
MeshFunction wrapper for a simple function of physical coordinates.
Represents a Quadrature Rule over one of the Reference Elements.
Definition: quad_rule.h:58
Provides Mesh Function for given basis expansion coefficients.
Provides Mesh Function for Whitney two basis expansion coefficients.
Provides Mesh Function for basis expansion coefficients of the zero form.
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
double Volume(const Geometry &geo)
Compute the (approximate) volume (area) of a shape.
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.
static std::string concat(Args &&...args)
Concatenate objects defining an operator<<(std::ostream&)
void process_results(std::string name, ProblemSolutionWrapper< SCALAR > &results, U_ZERO &u_zero, U_ONE &u_one, U_TWO &u_two, double &k)
Generate vtk files containing meshdata and a csv table with results.
std::pair< double, lf::mesh::utils::CodimMeshDataSet< double > > SupNorm(const std::shared_ptr< const lf::mesh::Mesh > &mesh_p, const MF &f, const SQ_F &sq_f, const lf::quad::QuadRule &quadrule)
Computes the supremum norm of the squared values of some MeshFunction (type MF) f.
Definition: norms.h:84
std::pair< double, lf::mesh::utils::CodimMeshDataSet< double > > L2norm(const std::shared_ptr< const lf::mesh::Mesh > &mesh_p, const MF &f, const SQ_F &sq_f, const lf::quad::QuadRule &quadrule)
Computes the L2Norm of some MeshFunction (type MF) f.
Definition: norms.h:33
void compare_results(std::string name, ProblemSolutionWrapper< SCALAR > &results_lap, ProblemSolutionWrapper< SCALAR > &results_dirac)
Generate vtk files containing meshdata and a csv table with results of the comparison of the two give...
Implementation of the thesis Hogde Laplacians and Dirac Operators on the surface of the 3-Sphere.
Definition: assemble.h:15
stores solutions for several k and one refinement level
std::vector< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > mu_one
std::vector< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > mu_zero
std::vector< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > mu_two
stores solutions and setupinformation for a list of refinement levels and k values
std::vector< std::shared_ptr< const lf::mesh::Mesh > > mesh