30 #include <deal.II/base/exceptions.h>
31 #include <deal.II/base/parameter_handler.h>
33 #include <deal.II/fe/mapping_q1_eulerian.h>
35 #include <deal.II/lac/full_matrix.h>
46 #include "source/core_model.hpp"
47 #include "source/geometry/mesh_handler.hpp"
48 #include "source/init.hpp"
49 #include "source/io/data_writer.hpp"
50 #include "source/numerics/bc_handler.hpp"
51 #include "source/numerics/linear_solver_handler.hpp"
52 #include "source/numerics/preconditioner_handler.hpp"
53 #include "source/numerics/tools.hpp"
61 template <
class basis>
70 std::make_shared<lifex::utils::MeshHandler>(prm_subsection_path,
73 {
"CG",
"GMRES",
"BiCGStab"},
116 dealii::DynamicSparsityPattern &sparsity,
117 const dealii::AffineConstraints<double> &constraints =
118 dealii::AffineConstraints<double>(),
119 const bool keep_constrained_dofs =
true,
120 const dealii::types::subdomain_id subdomain_id =
121 dealii::numbers::invalid_subdomain_id);
126 lifex::LinAlg::MPI::Vector &
solution);
151 const std::shared_ptr<dealii::Function<lifex::dim>> &
u_ex,
152 const std::shared_ptr<dealii::Function<lifex::dim>> &
grad_u_ex,
153 const char *solution_name = (
char *)
"u")
const;
172 virtual lifex::LinAlg::MPI::Vector
181 const std::string fem_file_path,
182 const unsigned int degree_fem = 1,
192 virtual lifex::LinAlg::MPI::Vector
201 const std::string fem_file_path,
202 const unsigned int degree_fem = 1,
208 const std::shared_ptr<dealii::Function<lifex::dim>> &u_analytical,
209 lifex::LinAlg::MPI::Vector &sol_owned);
235 lifex::utils::LinearSolverHandler<lifex::LinAlg::MPI::Vector>
linear_solver;
241 lifex::LinAlg::MPI::Vector
rhs;
251 std::shared_ptr<lifex::utils::FunctionDirichlet>
u_ex;
253 std::shared_ptr<dealii::Function<lifex::dim>>
grad_u_ex;
255 std::shared_ptr<dealii::Function<lifex::dim>>
f_ex;
257 std::shared_ptr<dealii::Function<lifex::dim>>
g_n;
260 template <
class basis>
265 linear_solver.declare_parameters(params);
266 preconditioner.declare_parameters(params);
269 params.enter_subsection(
"Mesh and space discretization");
271 params.declare_entry(
272 "Number of refinements",
274 dealii::Patterns::Integer(0),
275 "Number of global mesh refinement steps applied to initial grid.");
276 params.declare_entry(
"FE space degree",
278 dealii::Patterns::Integer(1),
279 "Degree of the FE space.");
281 params.leave_subsection();
283 params.enter_subsection(
"Discontinuous Galerkin");
285 params.declare_entry(
286 "Penalty coefficient",
288 dealii::Patterns::Double(-1, 1),
289 "Penalty coefficient in the Discontinuous Galerkin formulation.");
290 params.declare_entry(
291 "Stability coefficient",
293 dealii::Patterns::Double(0),
294 "Stabilization term in the Discontinuous Galerkin formulation.");
296 params.leave_subsection();
299 template <
class basis>
306 linear_solver.parse_parameters(params);
307 preconditioner.parse_parameters(params);
310 params.enter_subsection(
"Mesh and space discretization");
311 prm_n_refinements = params.get_integer(
"Number of refinements");
313 prm_fe_degree = params.get_integer(
"FE space degree");
314 params.leave_subsection();
316 params.enter_subsection(
"Discontinuous Galerkin");
317 prm_penalty_coeff = params.get_double(
"Penalty coefficient");
318 AssertThrow(prm_penalty_coeff == 1. || prm_penalty_coeff == 0. ||
319 prm_penalty_coeff == -1.,
320 dealii::StandardExceptions::ExcMessage(
321 "Penalty coefficient must be 1 (SIP method) or 0 (IIP method) "
322 "or -1 (NIP method)."));
324 prm_stability_coeff = params.get_double(
"Stability coefficient");
325 params.leave_subsection();
328 template <
class basis>
336 unsigned int denominator = 1;
337 unsigned int nominator = 1;
339 for (
unsigned int i = 1; i <= lifex::dim; i++)
342 nominator *= prm_fe_degree + i;
345 return (
int)(nominator / denominator);
349 template <
class basis>
356 initialize_solution(solution_owned, solution);
357 initialize_solution(solution_ex_owned, solution_ex);
358 discretize_analytical_solution(u_ex, solution_ex_owned);
362 solution_ex = solution_ex_owned;
363 solution = solution_owned = 0;
371 compute_errors(solution_owned, solution_ex_owned, u_ex, grad_u_ex,
"u");
374 conversion_to_fem(solution_ex);
375 solution = solution_owned;
376 conversion_to_fem(solution);
380 template <
class basis>
384 assemble = std::make_unique<AssembleDG<basis>>(prm_fe_degree);
386 dof_handler.reinit(triangulation->get());
387 dof_handler.distribute_dofs(prm_fe_degree);
389 std::make_shared<DUBFEMHandler<basis>>(prm_fe_degree, dof_handler);
391 triangulation->get_info().print(prm_subsection_path,
392 dof_handler.n_dofs(),
395 dealii::IndexSet owned_dofs = dof_handler.locally_owned_dofs();
396 dealii::IndexSet relevant_dofs = owned_dofs;
397 dealii::DynamicSparsityPattern dsp(relevant_dofs);
401 dofs_per_cell = get_dofs_per_cell();
402 std::vector<lifex::types::global_dof_index> dof_indices(dofs_per_cell);
403 std::vector<lifex::types::global_dof_index> dof_indices_neigh(dofs_per_cell);
406 for (
const auto &cell : dof_handler.active_cell_iterators())
408 dof_indices = dof_handler.get_dof_indices(cell);
410 for (
const auto &edge : cell->face_indices())
412 if (!cell->at_boundary(edge))
414 const auto neighcell = cell->neighbor(edge);
415 dof_indices_neigh = dof_handler.get_dof_indices(neighcell);
416 for (
unsigned int i = 0; i < dofs_per_cell; ++i)
418 for (
unsigned int j = 0; j < dofs_per_cell; ++j)
420 dsp.add(dof_indices[i], dof_indices_neigh[j]);
427 make_sparsity_pattern(dof_handler, dsp);
428 lifex::SparsityTools::distribute_sparsity_pattern(dsp,
432 lifex::utils::initialize_matrix(matrix, owned_dofs, dsp);
434 rhs.reinit(owned_dofs, mpi_comm);
438 template <
class basis>
442 dealii::DynamicSparsityPattern &sparsity,
443 const dealii::AffineConstraints<double> &constraints,
444 const bool keep_constrained_dofs,
445 const dealii::types::subdomain_id subdomain_id)
447 Assert(sparsity.n_rows() == n_dofs,
448 ExcDimensionMismatch(sparsity.n_rows(), n_dofs));
449 Assert(sparsity.n_cols() == n_dofs,
450 ExcDimensionMismatch(sparsity.n_cols(), n_dofs));
455 if (
const auto *triangulation =
dynamic_cast<
456 const dealii::parallel::DistributedTriangulationBase<lifex::dim> *
>(
457 &dof.get_triangulation()))
459 Assert((subdomain_id == numbers::invalid_subdomain_id) ||
460 (subdomain_id == triangulation->locally_owned_subdomain()),
462 "For distributed Triangulation objects and associated "
463 "DoFHandler objects, asking for any subdomain other than the "
464 "locally owned one does not make sense."));
466 std::vector<dealii::types::global_dof_index> dofs_on_this_cell;
472 for (
const auto &cell : dof.active_cell_iterators())
473 if (((subdomain_id == dealii::numbers::invalid_subdomain_id) ||
474 (subdomain_id == cell->subdomain_id())) &&
475 cell->is_locally_owned())
483 constraints.add_entries_local_to_global(dofs_on_this_cell,
485 keep_constrained_dofs);
490 template <
class basis>
493 lifex::LinAlg::MPI::Vector &solution)
495 dealii::IndexSet owned_dofs = dof_handler.locally_owned_dofs();
496 dealii::IndexSet relevant_dofs = owned_dofs;
498 solution_owned.reinit(owned_dofs, mpi_comm);
499 solution.reinit(owned_dofs, relevant_dofs, mpi_comm);
502 template <
class basis>
506 std::string mesh_path =
"../meshes/" + std::to_string(lifex::dim) +
"D_" +
507 std::to_string(prm_n_refinements) +
".msh";
508 AssertThrow(std::filesystem::exists(mesh_path),
509 dealii::StandardExceptions::ExcMessage(
510 "This mesh file/directory does not exist."));
515 triangulation->initialize_from_file(mesh_path, this->scaling_factor);
516 triangulation->set_element_type(lifex::utils::MeshHandler::ElementType::Tet);
517 triangulation->create_mesh();
520 template <
class basis>
524 AssertThrow(std::filesystem::exists(mesh_path),
525 dealii::StandardExceptions::ExcMessage(
526 "This mesh file/directory does not exist."));
531 triangulation->initialize_from_file(mesh_path, this->scaling_factor);
532 triangulation->set_element_type(lifex::utils::MeshHandler::ElementType::Tet);
533 triangulation->create_mesh();
536 template <
class basis>
540 preconditioner.initialize(matrix);
541 linear_solver.solve(matrix, solution_owned, rhs, preconditioner);
542 solution = solution_owned;
545 template <
class basis>
548 const lifex::LinAlg::MPI::Vector &solution_owned,
549 const lifex::LinAlg::MPI::Vector &solution_ex_owned,
550 const std::shared_ptr<dealii::Function<lifex::dim>> &u_ex,
551 const std::shared_ptr<dealii::Function<lifex::dim>> &grad_u_ex,
552 const char *solution_name)
const
561 solution_owned, solution_ex_owned, u_ex, grad_u_ex, solution_name);
566 << solution_name <<
":" << std::endl
567 <<
"Error L^inf: " << std::setw(6) << std::fixed << std::setprecision(6)
569 <<
"Error L^2: " << std::setw(6) << std::fixed << std::setprecision(6)
571 <<
"Error H^1: " << std::setw(6) << std::fixed << std::setprecision(6)
573 <<
"Error DG: " << std::setw(6) << std::fixed << std::setprecision(6)
574 <<
errors[3] << std::endl;
579 template <
class basis>
583 lifex::DataOut<lifex::dim> data_out;
588 const unsigned int output_fe_degree = (prm_fe_degree < 3) ? prm_fe_degree : 2;
589 dealii::FE_SimplexDGP<lifex::dim> fe(output_fe_degree);
590 dealii::DoFHandler<lifex::dim> dof_handler_fem;
591 dof_handler_fem.reinit(triangulation->get());
592 dof_handler_fem.distribute_dofs(fe);
594 data_out.add_data_vector(dof_handler_fem, solution,
"u");
595 data_out.build_patches();
596 data_out.add_data_vector(dof_handler_fem, solution_ex,
"u_ex");
597 data_out.build_patches();
598 lifex::utils::dataout_write_hdf5(data_out, output_name,
false);
605 template <
class basis>
617 lifex::LinAlg::MPI::Vector &sol_owned)
619 sol_owned = dub_fem_values->dubiner_to_fem(sol_owned);
623 template <
class basis>
624 lifex::LinAlg::MPI::Vector
626 const lifex::LinAlg::MPI::Vector &sol_owned)
const
633 lifex::LinAlg::MPI::Vector
635 const lifex::LinAlg::MPI::Vector &sol_owned)
const
637 lifex::LinAlg::MPI::Vector sol_fem =
638 dub_fem_values->dubiner_to_fem(sol_owned);
642 template <
class basis>
645 const std::string fem_file_path,
646 const unsigned int degree_fem,
647 const double scaling_factor)
const
655 lifex::LinAlg::MPI::Vector &sol_owned,
656 const std::string fem_file_path,
657 const unsigned int degree_fem,
658 const double scaling_factor)
const
660 sol_owned = dub_fem_values->dubiner_to_fem(sol_owned,
670 template <
class basis>
682 lifex::LinAlg::MPI::Vector &sol_owned)
684 sol_owned = dub_fem_values->fem_to_dubiner(sol_owned);
688 template <
class basis>
689 lifex::LinAlg::MPI::Vector
691 const lifex::LinAlg::MPI::Vector &sol_owned)
const
698 lifex::LinAlg::MPI::Vector
700 const lifex::LinAlg::MPI::Vector &sol_owned)
const
702 lifex::LinAlg::MPI::Vector sol_dub =
703 dub_fem_values->fem_to_dubiner(sol_owned);
707 template <
class basis>
710 const std::string fem_file_path,
711 const unsigned int degree_fem,
712 const double scaling_factor)
const
720 lifex::LinAlg::MPI::Vector &sol_owned,
721 const std::string fem_file_path,
722 const unsigned int degree_fem,
723 const double scaling_factor)
const
725 sol_owned = dub_fem_values->fem_to_dubiner(sol_owned,
738 const std::shared_ptr<dealii::Function<lifex::dim>> &u_analytical,
739 lifex::LinAlg::MPI::Vector &sol_owned)
741 dealii::VectorTools::interpolate(dof_handler, *u_analytical, sol_owned);
749 const std::shared_ptr<dealii::Function<lifex::dim>> &u_analytical,
750 lifex::LinAlg::MPI::Vector &sol_owned)
752 sol_owned = dub_fem_values->analytical_to_dubiner(sol_owned, u_analytical);
Class to compute the errors between the numerical solution (solution_owned) and the exact solution (s...
void update_datafile() const
Update the datafile with the new errors.
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::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.
Class to work with global and local degrees of freedom and their mapping.
std::vector< lifex::types::global_dof_index > get_dof_indices(active_cell_iterator cell) const
Returns the global dofs referred to the input cell.
unsigned int n_dofs_per_cell() const
Return copy of n_dofs_per_cell.
Class representing the resolution of problems using discontinuous Galerkin methods.
const std::string model_name
Name of the class/problem.
lifex::LinAlg::MPI::SparseMatrix matrix
Distributed matrix of the linear system.
std::shared_ptr< dealii::Function< lifex::dim > > g_n
Neumann boundary conditions.
unsigned int prm_n_refinements
Mesh refinement level (>=1).
void compute_errors(const lifex::LinAlg::MPI::Vector &solution_owned, const lifex::LinAlg::MPI::Vector &solution_ex_owned, const std::shared_ptr< dealii::Function< lifex::dim >> &u_ex, const std::shared_ptr< dealii::Function< lifex::dim >> &grad_u_ex, const char *solution_name=(char *)"u") const
To compute the error, the error, the error and the error at the end of system solving,...
virtual void conversion_to_dub(lifex::LinAlg::MPI::Vector &sol_owned)
To convert a discretized solution in Dubiner basis (only for problems using Dubiner basis).
void initialize_solution(lifex::LinAlg::MPI::Vector &solution_owned, lifex::LinAlg::MPI::Vector &solution)
To inizialize the solutions using the deal.II reinit.
virtual void assemble_system()=0
Assembly of the linear system, pure virtual.
unsigned int prm_fe_degree
Polynomials degree.
double prm_stability_coeff
DG stabilty coefficient.
void make_sparsity_pattern(const DoFHandlerDG< basis > &dof, dealii::DynamicSparsityPattern &sparsity, const dealii::AffineConstraints< double > &constraints=dealii::AffineConstraints< double >(), const bool keep_constrained_dofs=true, const dealii::types::subdomain_id subdomain_id=dealii::numbers::invalid_subdomain_id)
Creation of the sparsity pattern to assign to the system matrix before assembling.
std::shared_ptr< DUBFEMHandler< basis > > dub_fem_values
Member used for conversions between analytical, nodal and modal representations of the solutions.
lifex::LinAlg::MPI::Vector solution
Distributed solution vector, with ghost entries.
std::unique_ptr< AssembleDG< basis > > assemble
Matrix assembler.
lifex::LinAlg::MPI::Vector solution_ex
Distributed exact solution vector, without ghost entries.
virtual void declare_parameters(lifex::ParamHandler ¶ms) const override
Declare main parameters.
DoFHandlerDG< basis > dof_handler
DoFHandler (internal use for useful already implemented methods).
virtual void conversion_to_fem(lifex::LinAlg::MPI::Vector &sol_owned)
To convert a discretized solution from modal to nodal basis (does nothing if problem is already in no...
void create_mesh()
Load the mesh from the default path.
lifex::LinAlg::MPI::Vector solution_owned
Distributed solution vector, without ghost entries.
ModelDG(std::string model_name)
Constructor.
std::shared_ptr< dealii::Function< lifex::dim > > f_ex
Known forcing term.
virtual ~ModelDG()=default
Destructor.
lifex::utils::PreconditionerHandler preconditioner
Preconditioner handler.
double prm_penalty_coeff
DG Penalty coefficient.
std::shared_ptr< dealii::Function< lifex::dim > > grad_u_ex
Pointer to exact gradient solution Function.
virtual void output_results(std::string output_name="solution") const
Output of results.
unsigned int dofs_per_cell
Number of degrees of freedom per cell.
void solve_system()
System solving.
std::shared_ptr< lifex::utils::MeshHandler > triangulation
Triangulation (internal use for useful already implemented methods).
double scaling_factor
Scaling factor.
std::shared_ptr< lifex::utils::FunctionDirichlet > u_ex
Pointer to exact solution function.
lifex::LinAlg::MPI::Vector solution_ex_owned
Distributed exact solution vector, without ghost entries.
virtual void run() override
Run the simulation.
lifex::LinAlg::MPI::Vector rhs
Distributed right hand side vector of the linear system.
unsigned int get_dofs_per_cell() const
Return the number of degrees of freedom per element.
lifex::utils::LinearSolverHandler< lifex::LinAlg::MPI::Vector > linear_solver
Linear solver handler.
virtual void setup_system()
Setup of the problem before the resolution.
void discretize_analytical_solution(const std::shared_ptr< dealii::Function< lifex::dim >> &u_analytical, lifex::LinAlg::MPI::Vector &sol_owned)
Conversion of an analytical solution from FEM to basis coefficients.
virtual void parse_parameters(lifex::ParamHandler ¶ms) override
Parse parameters from .prm file.