DUBeat 1.0.1
High-order discontinuous Galerkin methods and applications to cardiac electrophysiology
Loading...
Searching...
No Matches
heat_dg.hpp
Go to the documentation of this file.
1/********************************************************************************
2 Copyright (C) 2024 by the DUBeat authors.
3
4 This file is part of DUBeat.
5
6 DUBeat is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 DUBeat is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with DUBeat. If not, see <http://www.gnu.org/licenses/>.
18********************************************************************************/
19
27#ifndef HEAT_DG_HPP_
28#define HEAT_DG_HPP_
29
30#include <math.h>
31
32#include <memory>
33#include <vector>
34
35#include "../source/DUBValues.hpp"
36#include "../source/DUB_FEM_handler.hpp"
37#include "../source/assemble_DG.hpp"
38#include "../source/face_handler_DG.hpp"
39#include "../source/model_DG_t.hpp"
40#include "../source/volume_handler_DG.hpp"
41#include "source/core_model.hpp"
42#include "source/geometry/mesh_handler.hpp"
43#include "source/init.hpp"
44#include "source/io/data_writer.hpp"
45#include "source/numerics/bc_handler.hpp"
46#include "source/numerics/linear_solver_handler.hpp"
47#include "source/numerics/preconditioner_handler.hpp"
48#include "source/numerics/tools.hpp"
49
51{
52 namespace heat_DG
53 {
57 class ExactSolution : public lifex::utils::FunctionDirichlet
58 {
59 public:
62 : lifex::utils::FunctionDirichlet()
63 {}
64
66 virtual double
67 value(const dealii::Point<lifex::dim> &p,
68 const unsigned int /*component*/ = 0) const override
69 {
70 if (lifex::dim == 2)
71 return std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
72 std::exp(-5 * this->get_time());
73 else
74 return std::sin(2 * M_PI * p[0] + M_PI / 4) *
75 std::sin(2 * M_PI * p[1] + M_PI / 4) *
76 std::sin(2 * M_PI * p[2] + M_PI / 4) *
77 std::exp(-5 * this->get_time());
78 }
79 };
80
84 class RightHandSide : public lifex::Function<lifex::dim>
85 {
86 public:
89 : lifex::Function<lifex::dim>()
90 {}
91
93 virtual double
94 value(const dealii::Point<lifex::dim> &p,
95 const unsigned int /*component*/ = 0) const override
96 {
97 if (lifex::dim == 2)
98 return std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
99 std::exp(-5 * this->get_time()) * (8 * M_PI * M_PI - 5);
100 else
101 return std::sin(2 * M_PI * p[0] + M_PI / 4) *
102 std::sin(2 * M_PI * p[1] + M_PI / 4) *
103 std::sin(2 * M_PI * p[2] + M_PI / 4) *
104 std::exp(-5 * this->get_time()) * (12 * M_PI * M_PI - 5);
105 }
106 };
107
111 class BCNeumann : public lifex::Function<lifex::dim>
112 {
113 public:
116 : lifex::Function<lifex::dim>()
117 {}
118
120 virtual double
121 value(const dealii::Point<lifex::dim> &p,
122 const unsigned int /*component*/ = 0) const override
123 {
124 if (lifex::dim == 2)
125 return -2 * M_PI * std::sin(2 * M_PI * p[0]) *
126 std::cos(2 * M_PI * p[1]) * std::exp(-5 * this->get_time()) *
127 (std::abs(p[1]) < 1e-10) +
128 2 * M_PI * std::cos(2 * M_PI * p[0]) *
129 std::sin(2 * M_PI * p[1]) * std::exp(-5 * this->get_time()) *
130 (std::abs(p[0] - 1) < 1e-10) +
131 2 * M_PI * std::sin(2 * M_PI * p[0]) *
132 std::cos(2 * M_PI * p[1]) * std::exp(-5 * this->get_time()) *
133 (std::abs(p[1] - 1) < 1e-10) -
134 2 * M_PI * std::cos(2 * M_PI * p[0]) *
135 std::sin(2 * M_PI * p[1]) * std::exp(-5 * this->get_time()) *
136 (std::abs(p[0]) < 1e-10);
137 else
138 return 2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
139 std::sin(2 * M_PI * p[1] + M_PI / 4) *
140 std::sin(2 * M_PI * p[2] + M_PI / 4) *
141 std::exp(-5 * this->get_time()) *
142 (std::abs(p[0] - 1) < 1e-10) -
143 2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
144 std::sin(2 * M_PI * p[1] + M_PI / 4) *
145 std::sin(2 * M_PI * p[2] + M_PI / 4) *
146 std::exp(-5 * this->get_time()) * (std::abs(p[0]) < 1e-10) +
147 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
148 std::cos(2 * M_PI * p[1] + M_PI / 4) *
149 std::sin(2 * M_PI * p[2] + M_PI / 4) *
150 std::exp(-5 * this->get_time()) *
151 (std::abs(p[1] - 1) < 1e-10) -
152 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
153 std::cos(2 * M_PI * p[1] + M_PI / 4) *
154 std::sin(2 * M_PI * p[2] + M_PI / 4) *
155 std::exp(-5 * this->get_time()) * (std::abs(p[1]) < 1e-10) +
156 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
157 std::sin(2 * M_PI * p[1] + M_PI / 4) *
158 std::cos(2 * M_PI * p[2] + M_PI / 4) *
159 std::exp(-5 * this->get_time()) *
160 (std::abs(p[2] - 1) < 1e-10) -
161 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
162 std::sin(2 * M_PI * p[1] + M_PI / 4) *
163 std::cos(2 * M_PI * p[2] + M_PI / 4) *
164 std::exp(-5 * this->get_time()) * (std::abs(p[2]) < 1e-10);
165 }
166 };
167
171 class GradExactSolution : public lifex::Function<lifex::dim>
172 {
173 public:
176 : lifex::Function<lifex::dim>()
177 {}
178
180 virtual double
181 value(const dealii::Point<lifex::dim> &p,
182 const unsigned int component = 0) const override
183 {
184 if (lifex::dim == 2)
185 {
186 if (component == 0) // x
187 return 2 * M_PI * std::cos(2 * M_PI * p[0]) *
188 std::sin(2 * M_PI * p[1]) *
189 std::exp(-5 * this->get_time());
190 else // y
191 return 2 * M_PI * std::sin(2 * M_PI * p[0]) *
192 std::cos(2 * M_PI * p[1]) *
193 std::exp(-5 * this->get_time());
194 }
195 else // dim=3
196 {
197 if (component == 0) // x
198 return 2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
199 std::sin(2 * M_PI * p[1] + M_PI / 4) *
200 std::sin(2 * M_PI * p[2] + M_PI / 4) *
201 std::exp(-5 * this->get_time());
202 if (component == 1) // y
203 return 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
204 std::cos(2 * M_PI * p[1] + M_PI / 4) *
205 std::sin(2 * M_PI * p[2] + M_PI / 4) *
206 std::exp(-5 * this->get_time());
207 else // z
208 return 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
209 std::sin(2 * M_PI * p[1] + M_PI / 4) *
210 std::cos(2 * M_PI * p[2] + M_PI / 4) *
211 std::exp(-5 * this->get_time());
212 }
213 }
214 };
215 } // namespace heat_DG
216
258 template <class basis>
259 class HeatDG : public ModelDG_t<basis>
260 {
261 public:
264 : ModelDG_t<basis>("Heat")
265 {
266 this->u_ex = std::make_shared<heat_DG::ExactSolution>();
267 this->grad_u_ex = std::make_shared<heat_DG::GradExactSolution>();
268 this->f_ex = std::make_shared<heat_DG::RightHandSide>();
269 this->g_n = std::make_shared<heat_DG::BCNeumann>();
270 }
271
272 private:
273 void
274 assemble_system() override;
275 };
276
278 template <class basis>
279 void
281 {
282 this->matrix = 0;
283 this->rhs = 0;
284
285 // The method is needed to define how the system matrix and rhs term are
286 // defined for the heat problem with Neumann boundary conditions. The full
287 // matrix is composed by different sub-matrices that are called with simple
288 // capital letters. We refer here to the DG_Assemble methods for their
289 // definition.
290
291 // See DG_Assemble::local_V().
292 dealii::FullMatrix<double> V(this->dofs_per_cell, this->dofs_per_cell);
293 // See DG_Assemble::local_M().
294 dealii::FullMatrix<double> M(this->dofs_per_cell, this->dofs_per_cell);
295 // See DG_Assemble::local_SC().
296 dealii::FullMatrix<double> SC(this->dofs_per_cell, this->dofs_per_cell);
297 // See DG_Assemble::local_IC().
298 dealii::FullMatrix<double> IC(this->dofs_per_cell, this->dofs_per_cell);
299 // Transpose of IC.
300 dealii::FullMatrix<double> IC_t(this->dofs_per_cell, this->dofs_per_cell);
301 // See DG_Assemble::local_IN().
302 dealii::FullMatrix<double> IN(this->dofs_per_cell, this->dofs_per_cell);
303 // Transpose of IN.
304 dealii::FullMatrix<double> IN_t(this->dofs_per_cell, this->dofs_per_cell);
305 // See DG_Assemble::local_SN().
306 dealii::FullMatrix<double> SN(this->dofs_per_cell, this->dofs_per_cell);
307
308 // See DG_Assemble::local_rhs().
309 dealii::Vector<double> cell_rhs(this->dofs_per_cell);
310 // See DG_Assemble::local_rhs_edge_neumann().
311 dealii::Vector<double> cell_rhs_edge(this->dofs_per_cell);
312 // See DG_Assemble::local_u0_M_rhs().
313 dealii::Vector<double> u0_rhs(this->dofs_per_cell);
314
315 std::vector<lifex::types::global_dof_index> dof_indices(
316 this->dofs_per_cell);
317 dealii::IndexSet owned_dofs = this->dof_handler.locally_owned_dofs();
318 const double &alpha_bdf = this->bdf_handler.get_alpha();
319
320 for (const auto &cell : this->dof_handler.active_cell_iterators())
321 {
322 if (cell->is_locally_owned())
323 {
324 this->assemble->reinit(cell);
325 dof_indices = this->dof_handler.get_dof_indices(cell);
326
327 V = this->assemble->local_V();
328 M = this->assemble->local_M();
329 M /= this->prm_time_step;
330 M *= alpha_bdf;
331
332 cell_rhs = this->assemble->local_rhs(this->f_ex);
333 u0_rhs =
334 this->assemble->local_u0_M_rhs(this->solution_bdf, dof_indices);
335 u0_rhs /= this->prm_time_step;
336
337 this->matrix.add(dof_indices, V);
338 this->matrix.add(dof_indices, M);
339 this->rhs.add(dof_indices, cell_rhs);
340 this->rhs.add(dof_indices, u0_rhs);
341
342 for (const auto &edge : cell->face_indices())
343 {
344 this->assemble->reinit(cell, edge);
345 std::vector<lifex::types::global_dof_index> dof_indices_neigh(
346 this->dofs_per_cell);
347
348 if (!cell->at_boundary(edge))
349 {
350 SC = this->assemble->local_SC(this->prm_stability_coeff);
351 std::tie(IC, IC_t) =
352 this->assemble->local_IC(this->prm_penalty_coeff);
353 this->matrix.add(dof_indices, SC);
354 this->matrix.add(dof_indices, IC);
355 this->matrix.add(dof_indices, IC_t);
356
357 const auto neighcell = cell->neighbor(edge);
359 this->dof_handler.get_dof_indices(neighcell);
360
361 std::tie(IN, IN_t) =
362 this->assemble->local_IN(this->prm_penalty_coeff);
363 SN = this->assemble->local_SN(this->prm_stability_coeff);
364
365 this->matrix.add(dof_indices, dof_indices_neigh, IN);
366 this->matrix.add(dof_indices_neigh, dof_indices, IN_t);
367 this->matrix.add(dof_indices, dof_indices_neigh, SN);
368 }
369 else
370 {
372 this->assemble->local_rhs_edge_neumann(this->g_n);
373 this->rhs.add(dof_indices, cell_rhs_edge);
374 }
375 }
376 }
377 }
378
379 this->matrix.compress(dealii::VectorOperation::add);
380 this->rhs.compress(dealii::VectorOperation::add);
381 }
382} // namespace DUBeat::models
383
384#endif /* HEAT_DG_HPP_*/
Class to solve the heat equation using the Discontinuous Galerkin method.
Definition heat_dg.hpp:260
HeatDG()
Constructor.
Definition heat_dg.hpp:263
void assemble_system() override
Assembly of the linear system.
Definition heat_dg.hpp:280
Neumann boundary condition.
Definition heat_dg.hpp:112
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the Neumann boundary condition function in a point.
Definition heat_dg.hpp:121
Exact solution of the problem.
Definition heat_dg.hpp:58
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the exact solution in a point.
Definition heat_dg.hpp:67
Gradient of the exact solution.
Definition heat_dg.hpp:172
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int component=0) const override
Evaluate the gradient of the exact solution in a point.
Definition heat_dg.hpp:181
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the source term in a point.
Definition heat_dg.hpp:94
Class representing the resolution of time-dependent problems using discontinuous Galerkin methods.
double prm_time_step
Time-step amplitude.
lifex::LinAlg::MPI::Vector solution_bdf
BDF solution, with ghost entries.
lifex::utils::BDFHandler< lifex::LinAlg::MPI::Vector > bdf_handler
BDF time advancing handler.
lifex::LinAlg::MPI::SparseMatrix matrix
Distributed matrix of the linear system.
Definition model_DG.hpp:239
std::shared_ptr< dealii::Function< lifex::dim > > g_n
Neumann boundary conditions.
Definition model_DG.hpp:257
double prm_stability_coeff
DG stabilty coefficient.
Definition model_DG.hpp:220
std::unique_ptr< AssembleDG< basis > > assemble
Matrix assembler.
Definition model_DG.hpp:233
DoFHandlerDG< basis > dof_handler
DoFHandler (internal use for useful already implemented methods).
Definition model_DG.hpp:228
std::shared_ptr< dealii::Function< lifex::dim > > f_ex
Known forcing term.
Definition model_DG.hpp:255
double prm_penalty_coeff
DG Penalty coefficient.
Definition model_DG.hpp:218
std::shared_ptr< dealii::Function< lifex::dim > > grad_u_ex
Pointer to exact gradient solution Function.
Definition model_DG.hpp:253
unsigned int dofs_per_cell
Number of degrees of freedom per cell.
Definition model_DG.hpp:226
std::shared_ptr< lifex::utils::FunctionDirichlet > u_ex
Pointer to exact solution function.
Definition model_DG.hpp:251
lifex::LinAlg::MPI::Vector rhs
Distributed right hand side vector of the linear system.
Definition model_DG.hpp:241