27 #ifndef COMPUTE_ERRORS_DG_HPP_
28 #define COMPUTE_ERRORS_DG_HPP_
30 #include <deal.II/base/quadrature.h>
32 #include <deal.II/dofs/dof_handler.h>
34 #include <deal.II/fe/fe.h>
35 #include <deal.II/fe/mapping_q1_eulerian.h>
37 #include <deal.II/lac/trilinos_vector.h>
70 template <
class basis>
76 const double stability_coeff,
77 const unsigned int local_dofs,
79 const unsigned int nref_,
80 const std::string &title)
82 ,
n_quad_points(
static_cast<int>(std::pow(degree + 2, lifex::dim)))
89 ,
basis_ptr(std::make_unique<basis>(degree))
108 reinit(
const lifex::LinAlg::MPI::Vector &sol_owned,
109 const lifex::LinAlg::MPI::Vector &sol_ex_owned,
110 const std::shared_ptr<dealii::Function<lifex::dim>> &u_ex_input,
111 const std::shared_ptr<dealii::Function<lifex::dim>> &grad_u_ex_input,
112 const char *solution_name_input);
118 std::list<const char *> errors_defs = {
"inf",
"L2",
"H1",
"DG"});
125 std::list<const char *> errors_defs = {
"inf",
"L2",
"H1",
"DG"})
const;
192 std::shared_ptr<dealii::Function<lifex::dim>>
u_ex;
195 std::shared_ptr<dealii::Function<lifex::dim>>
grad_u_ex;
209 template <
class basis>
212 const lifex::LinAlg::MPI::Vector &sol_owned,
213 const lifex::LinAlg::MPI::Vector &sol_ex_owned,
214 const std::shared_ptr<dealii::Function<lifex::dim>> &u_ex_input,
215 const std::shared_ptr<dealii::Function<lifex::dim>> &grad_u_ex_input,
216 const char *solution_name_input)
218 solution_owned = sol_owned;
219 solution_ex_owned = sol_ex_owned;
221 grad_u_ex = grad_u_ex_input;
222 solution_name = (
char *)solution_name_input;
225 template <
class basis>
229 AssertThrow(u_ex !=
nullptr,
230 dealii::StandardExceptions::ExcMessage(
231 "No valid pointer to the exact solution."));
233 AssertThrow(grad_u_ex !=
nullptr,
234 dealii::StandardExceptions::ExcMessage(
235 "No valid pointer to the gradient of the exact solution."));
237 AssertThrow(solution_owned.size() == solution_ex_owned.size(),
238 dealii::StandardExceptions::ExcMessage(
239 "The exact solution vector and the approximate solution vector "
240 "must have the same length."));
242 if (std::find(errors_defs.begin(), errors_defs.end(),
"inf") !=
245 this->compute_error_inf();
250 if (std::find(errors_defs.begin(), errors_defs.end(),
"DG") !=
253 this->compute_error_L2();
254 this->compute_error_H1();
255 this->compute_error_DG();
257 else if (std::find(errors_defs.begin(), errors_defs.end(),
"H1") !=
260 this->compute_error_L2();
261 this->compute_error_H1();
263 else if (std::find(errors_defs.begin(), errors_defs.end(),
"L2") !=
266 this->compute_error_L2();
270 template <
class basis>
274 std::vector<double> output_errors = {};
276 for (
auto error_def = errors_defs.begin(); error_def != errors_defs.end();
279 AssertThrow(*error_def ==
"inf" || *error_def ==
"L2" ||
280 *error_def ==
"H1" || *error_def ==
"DG",
281 dealii::StandardExceptions::ExcMessage(
282 "Error definition must be inf, L2, H1 or DG."));
284 if (*error_def ==
"inf")
285 output_errors.push_back(
errors[0]);
286 else if (*error_def ==
"L2")
287 output_errors.push_back(
errors[1]);
288 else if (*error_def ==
"H1")
289 output_errors.push_back(
errors[2]);
291 output_errors.push_back(
errors[3]);
293 return output_errors;
296 template <
class basis>
300 lifex::LinAlg::MPI::Vector difference = solution_owned;
301 difference -= solution_ex_owned;
303 errors[0] = difference.linfty_norm();
312 lifex::LinAlg::MPI::Vector solution_fem =
313 dub_fem_values->dubiner_to_fem(solution_owned);
314 lifex::LinAlg::MPI::Vector solution_ex_fem =
315 dub_fem_values->dubiner_to_fem(solution_ex_owned);
317 lifex::LinAlg::MPI::Vector difference = solution_fem;
318 difference -= solution_ex_fem;
320 errors[0] = difference.linfty_norm();
323 template <
class basis>
330 std::vector<lifex::types::global_dof_index> dof_indices(dofs_per_cell);
334 for (
const auto &cell : dof_handler.active_cell_iterators())
338 if (cell->is_locally_owned())
340 const dealii::Tensor<2, lifex::dim> BJinv =
342 const double det = 1 / determinant(BJinv);
344 dof_indices = dof_handler.get_dof_indices(cell);
348 for (
unsigned int q = 0; q < n_quad_points; ++q)
355 for (
unsigned int i = 0; i < dofs_per_cell; ++i)
359 solution_owned[dof_indices[i]];
370 errors[1] = sqrt(error_L2);
373 template <
class basis>
377 double error_semi_H1 = 0;
378 dealii::Tensor<1, lifex::dim> local_approx_gradient;
379 dealii::Tensor<1, lifex::dim> local_grad_exact;
380 dealii::Tensor<1, lifex::dim> pointwise_diff;
383 std::vector<lifex::types::global_dof_index> dof_indices(dofs_per_cell);
385 for (
const auto &cell : dof_handler.active_cell_iterators())
389 if (cell->is_locally_owned())
391 const dealii::Tensor<2, lifex::dim> BJinv =
393 const double det = 1 / determinant(BJinv);
395 dof_indices = dof_handler.get_dof_indices(cell);
399 for (
unsigned int q = 0; q < n_quad_points; ++q)
401 local_grad_exact = 0;
402 local_approx_gradient = 0;
405 for (
unsigned int j = 0; j < lifex::dim; ++j)
409 local_grad_exact[j] =
416 for (
unsigned int i = 0; i < dofs_per_cell; ++i)
418 local_approx_gradient[j] +=
419 basis_ptr->shape_grad(
421 solution_owned[dof_indices[i]];
426 local_grad_exact - (local_approx_gradient * BJinv);
428 error_semi_H1 += pointwise_diff * pointwise_diff * det *
439 template <
class basis>
446 std::vector<lifex::types::global_dof_index> dof_indices(dofs_per_cell);
450 for (
const auto &cell : dof_handler.active_cell_iterators())
454 if (cell->is_locally_owned())
456 dof_indices = dof_handler.get_dof_indices(cell);
458 for (
const auto &edge : cell->face_indices())
460 face_handler.
reinit(cell, edge);
462 const double face_measure = face_handler.
get_measure();
463 const double unit_face_measure = (4.0 - lifex::dim) / 2;
464 const double measure_ratio = face_measure / unit_face_measure;
465 const double h_local = (cell->measure()) / face_measure;
467 lifex::LinAlg::MPI::Vector difference = solution_owned;
468 difference -= solution_ex_owned;
470 const double local_stability_coeff =
471 (stability_coefficient * pow(fe_degree, 2)) / h_local;
473 std::vector<lifex::types::global_dof_index> dof_indices_neigh(
478 for (
unsigned int q = 0; q < n_quad_points_face; ++q)
480 for (
unsigned int i = 0; i < dofs_per_cell; ++i)
482 for (
unsigned int j = 0; j < dofs_per_cell; ++j)
485 difference[dof_indices[i]] *
486 difference[dof_indices[j]] * local_stability_coeff *
487 basis_ptr->shape_value(
489 basis_ptr->shape_value(
493 if (!cell->at_boundary(edge))
495 const auto neighcell = cell->neighbor(edge);
496 const auto neighedge =
497 cell->neighbor_face_no(edge);
499 dof_handler.get_dof_indices(neighcell);
500 face_handler_neigh.
reinit(neighcell, neighedge);
502 const unsigned int nq =
504 q, face_handler_neigh);
507 difference[dof_indices[i]] *
508 difference[dof_indices_neigh[j]] *
509 local_stability_coeff *
510 basis_ptr->shape_value(
512 basis_ptr->shape_value(
526 errors[3] = sqrt(error_semi_H1 + error_DG);
529 template <
class basis>
533 std::ofstream outdata;
534 outdata.open(
"errors_" + model_name +
"_" + std::to_string(lifex::dim) +
535 "D_" + solution_name +
".data");
538 std::cerr <<
"Error: file could not be opened" << std::endl;
542 const std::string date = get_date();
544 outdata <<
"nref" <<
'\t' <<
"l_inf" <<
'\t' <<
"l_2" <<
'\t' <<
"h_1" <<
'\t'
545 <<
"DG" <<
'\t' <<
"date" << std::endl;
547 for (
unsigned int i = 1; i <= 5; ++i)
548 outdata << i <<
'\t' <<
"x" <<
'\t' <<
"x" <<
'\t' <<
"x" <<
'\t' <<
"x"
549 <<
'\t' << date << std::endl;
554 template <
class basis>
562 localtime_r(&curr_time, &curr_tm);
563 strftime(date, 100,
"%D %T", &curr_tm);
567 template <
class basis>
571 const std::string filename =
"errors_" + model_name +
"_" +
572 std::to_string(lifex::dim) +
"D_" +
573 solution_name +
".data";
576 if (!std::filesystem::exists(filename))
577 initialize_datafile();
579 std::ifstream indata;
580 std::ofstream outdata;
581 indata.open(filename);
582 outdata.open(
"errors_tmp.data");
584 if (!outdata || !indata)
586 std::cerr <<
"Error: file could not be opened" << std::endl;
591 std::getline(indata, line);
593 const char n_ref_c =
'0' + nref;
595 outdata << line << std::endl;
597 const std::string date = get_date();
599 for (
unsigned int i = 0; i < 10; ++i)
601 std::getline(indata, line);
603 if (line[0] == n_ref_c)
604 outdata << nref <<
'\t' <<
errors[0] <<
'\t' <<
errors[1] <<
'\t'
605 <<
errors[2] <<
'\t' <<
errors[3] <<
'\t' << date << std::endl;
607 outdata << line << std::endl;
613 std::ifstream indata2(
"errors_tmp.data");
614 std::ofstream outdata2(filename);
615 outdata2 << indata2.rdbuf();
619 if (remove(
"errors_tmp.data") != 0)
621 std::cerr <<
"Error in deleting file" << std::endl;
Class to compute the errors between the numerical solution (solution_owned) and the exact solution (s...
const DoFHandlerDG< basis > & dof_handler
Dof handler object of the problem.
void initialize_datafile() const
Create the datafile for the errors.
void update_datafile() const
Update the datafile with the new errors.
void compute_error_inf()
Compute the error.
void compute_error_L2()
Compute the error.
const unsigned int n_quad_points_face
Number of quadrature points on the face element.
const std::unique_ptr< basis > basis_ptr
Pointer to the basis handler.
std::shared_ptr< dealii::Function< lifex::dim > > u_ex
Analytical exact solution.
std::shared_ptr< dealii::Function< lifex::dim > > grad_u_ex
Gradient of the analytical exact solution.
std::shared_ptr< DUBFEMHandler< basis > > dub_fem_values
Member to compute conversion to FEM basis, needed for L^inf error.
const std::string model_name
Name of the model.
lifex::LinAlg::MPI::Vector solution_owned
Computed solution.
const unsigned int n_quad_points
Number of quadrature points in the volume element.
const unsigned int nref
Number of refinements.
void compute_error_H1()
Compute the error.
char * solution_name
String that contains the solution name (to write on output files, default "u").
void compute_errors(std::list< const char * > errors_defs={"inf", "L2", "H1", "DG"})
Compute errors following the preferences in the list.
void reinit(const lifex::LinAlg::MPI::Vector &sol_owned, const lifex::LinAlg::MPI::Vector &sol_ex_owned, const std::shared_ptr< dealii::Function< lifex::dim >> &u_ex_input, const std::shared_ptr< dealii::Function< lifex::dim >> &grad_u_ex_input, const char *solution_name_input)
Reinitialization with new computed and exact solutions.
std::array< double, 4 > errors
Array that contains the current errors (in order, , , , ).
std::string get_date() const
Return the current date and time.
void compute_error_DG()
Compute the error.
lifex::LinAlg::MPI::Vector solution_ex_owned
Exact solution to compare with the numerical one.
const unsigned int fe_degree
Polynomial degree.
const double stability_coefficient
Stability coefficient, needed for the computation of the error.
std::vector< double > output_errors(std::list< const char * > errors_defs={"inf", "L2", "H1", "DG"}) const
Output of the errors following the preferences in the list.
const unsigned int dofs_per_cell
Number of degrees of freedom per cell.
Class used to discretize analytical solutions as linear combinations of Lagrangian or Dubiner basis.
Class to work with global and local degrees of freedom and their mapping.
dealii::Point< dim > quadrature_ref(const unsigned int q) const override
Return the -th spatial quadrature point position on the reference element.
double quadrature_weight(const unsigned int q) const override
Return the quadrature weight associated to the -th quadrature point.
double get_measure() const
Measure of face.
int corresponding_neigh_index(const unsigned int q, const FaceHandlerDG< dim > &FaceHandlerDG_neigh) const
To manually obtain the associated quadrature point index in the neighbor element on the shared face.
void reinit(const typename dealii::DoFHandler< dim >::active_cell_iterator &new_cell, const unsigned int new_edge)
Reinit objects on the current new_cell and new_edge.
virtual double quadrature_weight(const unsigned int q) const
Return the quadrature weight associated to the -th quadrature point.
void reinit(const typename dealii::DoFHandler< dim >::active_cell_iterator &new_cell)
Reinit objects on the current new_cell.
virtual dealii::Point< dim > quadrature_ref(const unsigned int q) const
Return the -th spatial quadrature point position on the reference element.
virtual dealii::Point< dim > quadrature_real(const unsigned int q) const
Return the -th spatial quadrature point position on the actual element.
dealii::Tensor< 2, dim > get_jacobian_inverse() const
Inverse of the Jacobian of the reference-to-actual transformation.