DUBeat 1.0.1
High-order discontinuous Galerkin methods and applications to cardiac electrophysiology
Loading...
Searching...
No Matches
monodomain_fhn_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 MONODOMAIN_FHN_DG_HPP_
28#define MONODOMAIN_FHN_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.hpp"
40#include "../source/model_DG_t.hpp"
41#include "../source/volume_handler_DG.hpp"
42#include "source/core_model.hpp"
43#include "source/geometry/mesh_handler.hpp"
44#include "source/init.hpp"
45#include "source/io/data_writer.hpp"
46#include "source/numerics/bc_handler.hpp"
47#include "source/numerics/linear_solver_handler.hpp"
48#include "source/numerics/preconditioner_handler.hpp"
49#include "source/numerics/tools.hpp"
50
51namespace DUBeat::models
52{
53 namespace monodomain_fhn_DG
54 {
58 class ExactSolution : public lifex::utils::FunctionDirichlet
59 {
60 public:
63 : lifex::utils::FunctionDirichlet()
64 {}
65
67 virtual double
68 value(const dealii::Point<lifex::dim> &p,
69 const unsigned int /*component*/ = 0) const override
70 {
71 if (lifex::dim == 2)
72 return std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
73 std::exp(-5 * this->get_time());
74 else
75 return std::sin(2 * M_PI * p[0] + M_PI / 4) *
76 std::sin(2 * M_PI * p[1] + M_PI / 4) *
77 std::sin(2 * M_PI * p[2] + M_PI / 4) *
78 std::exp(-5 * this->get_time());
79 }
80 };
81
85 class RightHandSide : public lifex::Function<lifex::dim>
86 {
87 private:
89 double ChiM;
90
92 double Sigma;
93
95 double Cm;
96
98 double kappa;
99
101 double epsilon;
102
104 double gamma;
105
107 double a;
108
109 public:
112 double Sigma,
113 double Cm,
114 double kappa,
115 double epsilon,
116 double gamma,
117 double a)
118 : lifex::Function<lifex::dim>()
119 , ChiM(ChiM)
120 , Sigma(Sigma)
121 , Cm(Cm)
122 , kappa(kappa)
124 , gamma(gamma)
125 , a(a)
126 {}
127
129 virtual double
130 value(const dealii::Point<lifex::dim> &p,
131 const unsigned int /*component*/ = 0) const override
132 {
133 if (lifex::dim == 2)
134 return std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
135 std::exp(-5 * this->get_time()) *
136 (-ChiM * Cm * 5 + Sigma * 8 * pow(M_PI, 2) +
137 ChiM * kappa *
138 (std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
139 std::exp(-5 * this->get_time()) -
140 a) *
141 (std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
142 std::exp(-5 * this->get_time()) -
143 1) +
144 ChiM * (epsilon / (epsilon * gamma - 5)));
145 else
146 return std::sin(2 * M_PI * p[0] + M_PI / 4) *
147 std::sin(2 * M_PI * p[1] + M_PI / 4) *
148 std::sin(2 * M_PI * p[2] + M_PI / 4) *
149 std::exp(-5 * this->get_time()) *
150 (-ChiM * Cm * 5 + Sigma * 12 * pow(M_PI, 2) +
151 ChiM * kappa *
152 (std::sin(2 * M_PI * p[0] + M_PI / 4) *
153 std::sin(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()) -
156 a) *
157 (std::sin(2 * M_PI * p[0] + M_PI / 4) *
158 std::sin(2 * M_PI * p[1] + M_PI / 4) *
159 std::sin(2 * M_PI * p[2] + M_PI / 4) *
160 std::exp(-5 * this->get_time()) -
161 1) +
162 ChiM * (epsilon / (epsilon * gamma - 5)));
163 }
164 };
165
169 class BCNeumann : public lifex::Function<lifex::dim>
170 {
171 private:
173 double Sigma;
174
175 public:
178 : lifex::Function<lifex::dim>()
179 , Sigma(Sigma)
180 {}
181
183 virtual double
184 value(const dealii::Point<lifex::dim> &p,
185 const unsigned int /*component*/ = 0) const override
186 {
187 if (lifex::dim == 2)
188 return Sigma *
189 (-2 * M_PI * std::sin(2 * M_PI * p[0]) *
190 std::cos(2 * M_PI * p[1]) *
191 std::exp(-5 * this->get_time()) * (std::abs(p[1]) < 1e-10) +
192 2 * M_PI * std::cos(2 * M_PI * p[0]) *
193 std::sin(2 * M_PI * p[1]) *
194 std::exp(-5 * this->get_time()) *
195 (std::abs(p[0] - 1) < 1e-10) +
196 2 * M_PI * std::sin(2 * M_PI * p[0]) *
197 std::cos(2 * M_PI * p[1]) *
198 std::exp(-5 * this->get_time()) *
199 (std::abs(p[1] - 1) < 1e-10) -
200 2 * M_PI * std::cos(2 * M_PI * p[0]) *
201 std::sin(2 * M_PI * p[1]) *
202 std::exp(-5 * this->get_time()) * (std::abs(p[0]) < 1e-10));
203 else
204 return Sigma *
205 (2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
206 std::sin(2 * M_PI * p[1] + M_PI / 4) *
207 std::sin(2 * M_PI * p[2] + M_PI / 4) *
208 std::exp(-5 * this->get_time()) *
209 (std::abs(p[0] - 1) < 1e-10) -
210 2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
211 std::sin(2 * M_PI * p[1] + M_PI / 4) *
212 std::sin(2 * M_PI * p[2] + M_PI / 4) *
213 std::exp(-5 * this->get_time()) * (std::abs(p[0]) < 1e-10) +
214 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
215 std::cos(2 * M_PI * p[1] + M_PI / 4) *
216 std::sin(2 * M_PI * p[2] + M_PI / 4) *
217 std::exp(-5 * this->get_time()) *
218 (std::abs(p[1] - 1) < 1e-10) -
219 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
220 std::cos(2 * M_PI * p[1] + M_PI / 4) *
221 std::sin(2 * M_PI * p[2] + M_PI / 4) *
222 std::exp(-5 * this->get_time()) * (std::abs(p[1]) < 1e-10) +
223 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
224 std::sin(2 * M_PI * p[1] + M_PI / 4) *
225 std::cos(2 * M_PI * p[2] + M_PI / 4) *
226 std::exp(-5 * this->get_time()) *
227 (std::abs(p[2] - 1) < 1e-10) -
228 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
229 std::sin(2 * M_PI * p[1] + M_PI / 4) *
230 std::cos(2 * M_PI * p[2] + M_PI / 4) *
231 std::exp(-5 * this->get_time()) * (std::abs(p[2]) < 1e-10));
232 }
233 };
234
238 class GradExactSolution : public lifex::Function<lifex::dim>
239 {
240 public:
243 : lifex::Function<lifex::dim>()
244 {}
245
247 virtual double
248 value(const dealii::Point<lifex::dim> &p,
249 const unsigned int component = 0) const override
250 {
251 if (lifex::dim == 2)
252 {
253 if (component == 0) // x
254 return 2 * M_PI * std::cos(2 * M_PI * p[0]) *
255 std::sin(2 * M_PI * p[1]) *
256 std::exp(-5 * this->get_time());
257 else // y
258 return 2 * M_PI * std::sin(2 * M_PI * p[0]) *
259 std::cos(2 * M_PI * p[1]) *
260 std::exp(-5 * this->get_time());
261 }
262 else // dim=3
263 {
264 if (component == 0) // x.
265 return 2 * M_PI * std::cos(2 * M_PI * p[0] + M_PI / 4) *
266 std::sin(2 * M_PI * p[1] + M_PI / 4) *
267 std::sin(2 * M_PI * p[2] + M_PI / 4) *
268 std::exp(-5 * this->get_time());
269 if (component == 1) // y.
270 return 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
271 std::cos(2 * M_PI * p[1] + M_PI / 4) *
272 std::sin(2 * M_PI * p[2] + M_PI / 4) *
273 std::exp(-5 * this->get_time());
274 else // z.
275 return 2 * M_PI * std::sin(2 * M_PI * p[0] + M_PI / 4) *
276 std::sin(2 * M_PI * p[1] + M_PI / 4) *
277 std::cos(2 * M_PI * p[2] + M_PI / 4) *
278 std::exp(-5 * this->get_time());
279 }
280 }
281 };
282
286 class ExactSolution_w : public lifex::utils::FunctionDirichlet
287 {
288 private:
290 double epsilon;
291
293 double gamma;
294
295 public:
298 : lifex::utils::FunctionDirichlet()
300 , gamma(gamma)
301 {}
302
304 virtual double
305 value(const dealii::Point<lifex::dim> &p,
306 const unsigned int /*component*/ = 0) const override
307 {
308 if (lifex::dim == 2)
309 return epsilon / (epsilon * gamma - 5) * std::sin(2 * M_PI * p[0]) *
310 std::sin(2 * M_PI * p[1]) * std::exp(-5 * this->get_time());
311 else
312 return epsilon / (epsilon * gamma - 5) * std::sin(2 * M_PI * p[0]) *
313 std::sin(2 * M_PI * p[1]) * std::sin(2 * M_PI * p[2]) *
314 std::exp(-5 * this->get_time());
315 }
316 };
317
321 class GradExactSolution_w : public lifex::Function<lifex::dim>
322 {
323 private:
325 double epsilon;
326
328 double gamma;
329
330 public:
333 : lifex::Function<lifex::dim>()
335 , gamma(gamma)
336 {}
337
339 virtual double
340 value(const dealii::Point<lifex::dim> &p,
341 const unsigned int component = 0) const override
342 {
343 if (lifex::dim == 2)
344 {
345 if (component == 0) // x
346 return 2 * M_PI * epsilon / (epsilon * gamma - 5) *
347 std::cos(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
348 std::exp(-5 * this->get_time());
349 else // y
350 return 2 * M_PI * epsilon / (epsilon * gamma - 5) *
351 std::sin(2 * M_PI * p[0]) * std::cos(2 * M_PI * p[1]) *
352 std::exp(-5 * this->get_time());
353 }
354 else // dim=3
355 {
356 if (component == 0) // x
357 return 2 * M_PI * epsilon / (epsilon * gamma - 5) *
358 std::cos(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
359 std::sin(2 * M_PI * p[2]) *
360 std::exp(-5 * this->get_time());
361 if (component == 1) // y
362 return 2 * M_PI * epsilon / (epsilon * gamma - 5) *
363 std::sin(2 * M_PI * p[0]) * std::cos(2 * M_PI * p[1]) *
364 std::sin(2 * M_PI * p[2]) *
365 std::exp(-5 * this->get_time());
366 else // z
367 return 2 * M_PI * epsilon / (epsilon * gamma - 5) *
368 std::sin(2 * M_PI * p[0]) * std::sin(2 * M_PI * p[1]) *
369 std::cos(2 * M_PI * p[2]) *
370 std::exp(-5 * this->get_time());
371 }
372 }
373 };
374 } // namespace monodomain_fhn_DG
375
445 template <class basis>
446 class MonodomainFHNDG : public ModelDG_t<basis>
447 {
448 public:
451 : ModelDG_t<basis>("Monodomain Fitzhugh-Nagumo")
452 {}
453
454 private:
456 double ChiM;
458 double Sigma;
460 double Cm;
462 double kappa;
464 double epsilon;
466 double gamma;
468 double a;
470 lifex::LinAlg::MPI::Vector solution_owned_w;
472 lifex::LinAlg::MPI::Vector solution_w;
474 lifex::LinAlg::MPI::Vector solution_ex_owned_w;
476 lifex::LinAlg::MPI::Vector solution_ex_w;
478 std::shared_ptr<lifex::utils::FunctionDirichlet> w_ex;
480 std::shared_ptr<dealii::Function<lifex::dim>> grad_w_ex;
482 lifex::utils::BDFHandler<lifex::LinAlg::MPI::Vector> bdf_handler_w;
484 lifex::LinAlg::MPI::Vector solution_bdf_w;
486 lifex::LinAlg::MPI::Vector solution_ext_w;
487
489 lifex::LinAlg::MPI::SparseMatrix matrix_t0;
490
492 virtual void
493 declare_parameters(lifex::ParamHandler &params) const override;
494
496 virtual void
497 parse_parameters(lifex::ParamHandler &params) override;
498
500 void
501 run() override;
502
504 void
505 update_time() override;
506
508 void
509 time_initialization() override;
510
512 void
513 assemble_system() override;
514 };
515
516 template <class basis>
517 void
519 {
520 // Default parameters.
521 this->linear_solver.declare_parameters(params);
522 this->preconditioner.declare_parameters(params);
523
524 // Extra parameters.
525 params.enter_subsection("Mesh and space discretization");
526 {
527 params.declare_entry(
528 "Number of refinements",
529 "2",
530 dealii::Patterns::Integer(0),
531 "Number of global mesh refinement steps applied to initial grid.");
532 params.declare_entry("FE space degree",
533 "1",
534 dealii::Patterns::Integer(1),
535 "Degree of the FE space.");
536 }
537 params.leave_subsection();
538
539 params.enter_subsection("Discontinuous Galerkin");
540 {
541 params.declare_entry(
542 "Penalty coefficient",
543 "1",
544 dealii::Patterns::Double(-1, 1),
545 "Penalty coefficient in the Discontinuous Galerkin formulation.");
546 params.declare_entry(
547 "Stability coefficient",
548 "10",
549 dealii::Patterns::Double(0),
550 "Stabilization term in the Discontinuous Galerkin formulation.");
551 }
552 params.leave_subsection();
553
554 params.enter_subsection("Time solver");
555 {
556 params.declare_entry("Initial time",
557 "0",
558 dealii::Patterns::Double(0),
559 "Initial time.");
560 params.declare_entry("Final time",
561 "0.001",
562 dealii::Patterns::Double(0),
563 "Final time.");
564 params.declare_entry("Time step",
565 "0.0001",
566 dealii::Patterns::Double(0),
567 "Time step.");
568 params.declare_entry("BDF order",
569 "1",
570 dealii::Patterns::Integer(1, 3),
571 "BDF order: 1, 2, 3.");
572 }
573 params.leave_subsection();
574
575 params.enter_subsection("Parameters of the model");
576 {
577 params.declare_entry("ChiM",
578 "1e5",
579 dealii::Patterns::Double(0),
580 "Surface-to-volume ratio of cells parameter.");
581 params.declare_entry("Cm",
582 "1e-2",
583 dealii::Patterns::Double(0),
584 "Membrane capacity.");
585 params.declare_entry("Sigma",
586 "0.12",
587 dealii::Patterns::Double(0),
588 "Diffusion parameter in the principal directions.");
589 params.declare_entry(
590 "kappa",
591 "19.5",
592 dealii::Patterns::Double(0),
593 "Factor for the nonlinear reaction in Fitzhugh Nagumo model.");
594 params.declare_entry("epsilon",
595 "1.2",
596 dealii::Patterns::Double(0),
597 "Parameter for Fitzhugh Nagumo model.");
598 params.declare_entry("gamma",
599 "0.1",
600 dealii::Patterns::Double(0),
601 "Parameter for Fitzhugh Nagumo model.");
602 params.declare_entry("a",
603 "13e-3",
604 dealii::Patterns::Double(0),
605 "Parameter for Fitzhugh Nagumo model.");
606 }
607 params.leave_subsection();
608 }
609
610 template <class basis>
611 void
613 {
614 // Parse input file.
615 params.parse();
616 // Read input parameters.
617 this->linear_solver.parse_parameters(params);
618 this->preconditioner.parse_parameters(params);
619
620 // Extra parameters.
621 params.enter_subsection("Mesh and space discretization");
622 this->prm_n_refinements = params.get_integer("Number of refinements");
623 this->prm_fe_degree = params.get_integer("FE space degree");
624 params.leave_subsection();
625
626 params.enter_subsection("Discontinuous Galerkin");
627 this->prm_penalty_coeff = params.get_double("Penalty coefficient");
629 this->prm_penalty_coeff == 1. || this->prm_penalty_coeff == 0. ||
630 this->prm_penalty_coeff == -1.,
631 dealii::StandardExceptions::ExcMessage(
632 "Penalty coefficient must be 1 (SIP method) or 0 (IIP method) "
633 "or -1 (NIP method)."));
634
635 this->prm_stability_coeff = params.get_double("Stability coefficient");
636 params.leave_subsection();
637
638 params.enter_subsection("Time solver");
639 this->prm_time_init = params.get_double("Initial time");
640 this->prm_time_final = params.get_double("Final time");
642 dealii::StandardExceptions::ExcMessage(
643 "Final time must be greater than initial time."));
644
645 this->prm_time_step = params.get_double("Time step");
646 this->prm_bdf_order = params.get_integer("BDF order");
647 params.leave_subsection();
648
649 params.enter_subsection("Parameters of the model");
650 ChiM = params.get_double("ChiM");
651 Cm = params.get_double("Cm");
652 Sigma = params.get_double("Sigma");
653 kappa = params.get_double("kappa");
654 epsilon = params.get_double("epsilon");
655 gamma = params.get_double("gamma");
656 a = params.get_double("a");
657 params.leave_subsection();
658 }
659
660 template <class basis>
661 void
663 {
664 this->create_mesh();
665 this->setup_system();
666
667 this->initialize_solution(this->solution_owned, this->solution);
669 this->initialize_solution(this->solution_owned_w, this->solution_w);
670 this->initialize_solution(this->solution_ex_owned_w, this->solution_ex_w);
671
673
674 while (this->time < this->prm_time_final)
675 {
676 this->time += this->prm_time_step;
677 ++this->timestep_number;
678
679 pcout << "Time step " << std::setw(6) << this->timestep_number
680 << " at t = " << std::setw(8) << std::fixed
681 << std::setprecision(6) << this->time << std::endl;
682
683 this->update_time();
684 this->solution_ext = this->bdf_handler.get_sol_extrapolation();
685
686 this->assemble_system();
687
688 // Initial guess.
689 this->solution_owned = this->solution_ext;
690 this->solve_system();
691
693 this->solution_ex_owned,
694 this->u_ex,
695 "u");
696 this->intermediate_error_print(this->solution_owned_w,
697 this->solution_ex_owned_w,
698 this->w_ex,
699 "w");
700 }
701
702
703 this->compute_errors(this->solution_owned,
704 this->solution_ex_owned,
705 this->u_ex,
706 this->grad_u_ex,
707 "u");
708 this->compute_errors(this->solution_owned_w,
709 this->solution_ex_owned_w,
710 this->w_ex,
711 this->grad_w_ex,
712 "w");
713
714 // Generation of the graphical output.
715 this->solution_ex = this->solution_ex_owned;
716 this->conversion_to_fem(this->solution_ex);
717 this->solution = this->solution_owned;
718 this->conversion_to_fem(this->solution);
719 this->output_results();
720 }
721
722 template <class basis>
723 void
725 {
726 this->u_ex->set_time(this->time);
727 this->f_ex->set_time(this->time);
728 this->g_n->set_time(this->time);
729 this->grad_u_ex->set_time(this->time);
730
731 w_ex->set_time(this->time);
732 grad_w_ex->set_time(this->time);
733
734 this->bdf_handler.time_advance(this->solution_owned, true);
735 this->solution_bdf = this->bdf_handler.get_sol_bdf();
736 bdf_handler_w.time_advance(solution_owned_w, true);
737 solution_bdf_w = this->bdf_handler_w.get_sol_bdf();
738
739 // Update solution_ex_owned from the updated u_ex.
741 this->discretize_analytical_solution(this->w_ex, this->solution_ex_owned_w);
742 }
743
744 template <class basis>
745 void
747 {
748 this->u_ex = std::make_shared<monodomain_fhn_DG::ExactSolution>();
749 this->grad_u_ex = std::make_shared<monodomain_fhn_DG::GradExactSolution>();
750 this->f_ex = std::make_shared<monodomain_fhn_DG::RightHandSide>(
751 ChiM, Sigma, Cm, kappa, epsilon, gamma, a);
752 this->g_n = std::make_shared<monodomain_fhn_DG::BCNeumann>(Sigma);
753 w_ex = std::make_shared<monodomain_fhn_DG::ExactSolution_w>(epsilon, gamma);
754 grad_w_ex =
755 std::make_shared<monodomain_fhn_DG::GradExactSolution_w>(epsilon, gamma);
756
757 this->u_ex->set_time(this->prm_time_init);
759 this->solution_ex = this->solution_ex_owned;
760 this->solution = this->solution_owned = this->solution_ex_owned;
761
762 w_ex->set_time(this->prm_time_init);
763 this->discretize_analytical_solution(this->w_ex, this->solution_ex_owned_w);
764 solution_ex_w = solution_ex_owned_w;
765 solution_w = solution_owned_w = solution_ex_owned_w;
766
767 const std::vector<lifex::LinAlg::MPI::Vector> sol_init(
768 this->prm_bdf_order, this->solution_owned);
769
770 this->bdf_handler.initialize(this->prm_bdf_order, sol_init);
771
772 const std::vector<lifex::LinAlg::MPI::Vector> sol_init_w(
773 this->prm_bdf_order, solution_owned_w);
774
775 bdf_handler_w.initialize(this->prm_bdf_order, sol_init_w);
776 }
777
778 template <class basis>
779 void
781 {
782 const double &alpha_bdf = this->bdf_handler.get_alpha();
783
784 solution_owned_w *= -gamma;
785 solution_owned_w.add(1, this->solution_owned);
786 solution_owned_w *= epsilon;
787 solution_owned_w.add(1 / this->prm_time_step, this->solution_bdf_w);
788 solution_owned_w *= this->prm_time_step / alpha_bdf;
789
790 solution_w = solution_owned_w;
791
792 this->matrix = 0;
793 this->rhs = 0;
794
795 // The method is needed to define how the system matrix and rhs term are
796 // defined for the monodomain problem with Fithugh-Nagumo ionic model. The
797 // full matrix is composed by different sub-matrices that are called with
798 // simple capital letters. We refer here to the DG_Assemble methods for
799 // their definition.
800
801 // See DG_Assemble::local_non_linear_fitzhugh().
802 dealii::FullMatrix<double> C(this->dofs_per_cell, this->dofs_per_cell);
803 dealii::Vector<double> cell_rhs(this->dofs_per_cell);
804 dealii::Vector<double> cell_rhs_edge(this->dofs_per_cell);
805 dealii::Vector<double> u0_rhs(this->dofs_per_cell);
806 dealii::Vector<double> w0_rhs(this->dofs_per_cell);
807 std::vector<lifex::types::global_dof_index> dof_indices(
808 this->dofs_per_cell);
809
810 dealii::IndexSet owned_dofs = this->dof_handler.locally_owned_dofs();
811
812
813 // This part of the LHS matrix is assembled only once and not at each time
814 // step.
815 if (this->timestep_number == 1)
816 {
817 this->matrix_t0.reinit(this->matrix);
818
819 // See DG_Assemble::local_V().
820 dealii::FullMatrix<double> V(this->dofs_per_cell, this->dofs_per_cell);
821 // See DG_Assemble::local_M().
822 dealii::FullMatrix<double> M(this->dofs_per_cell, this->dofs_per_cell);
823 // See DG_Assemble::local_SC().
824 dealii::FullMatrix<double> SC(this->dofs_per_cell, this->dofs_per_cell);
825 // See DG_Assemble::local_IC().
826 dealii::FullMatrix<double> IC(this->dofs_per_cell, this->dofs_per_cell);
827 // Transpose of IC.
828 dealii::FullMatrix<double> IC_t(this->dofs_per_cell,
829 this->dofs_per_cell);
830 // See DG_Assemble::local_IN().
831 dealii::FullMatrix<double> IN(this->dofs_per_cell, this->dofs_per_cell);
832 // Transpose of IN.
833 dealii::FullMatrix<double> IN_t(this->dofs_per_cell,
834 this->dofs_per_cell);
835 // See DG_Assemble::local_SN().
836 dealii::FullMatrix<double> SN(this->dofs_per_cell, this->dofs_per_cell);
837
838 for (const auto &cell : this->dof_handler.active_cell_iterators())
839 {
840 if (cell->is_locally_owned())
841 {
842 this->assemble->reinit(cell);
843 dof_indices = this->dof_handler.get_dof_indices(cell);
844
845 V = this->assemble->local_V();
846 V *= Sigma;
847 M = this->assemble->local_M();
848 M /= this->prm_time_step;
849 M *= alpha_bdf;
850 M *= ChiM;
851 M *= Cm;
852
853 this->matrix_t0.add(dof_indices, V);
854 this->matrix_t0.add(dof_indices, M);
855
856 for (const auto &edge : cell->face_indices())
857 {
858 this->assemble->reinit(cell, edge);
859 std::vector<lifex::types::global_dof_index>
861
862 if (!cell->at_boundary(edge))
863 {
864 SC =
865 this->assemble->local_SC(this->prm_stability_coeff);
866 SC *= Sigma;
867 std::tie(IC, IC_t) =
868 this->assemble->local_IC(this->prm_penalty_coeff);
869 IC *= Sigma;
870 IC_t *= Sigma;
871 this->matrix_t0.add(dof_indices, SC);
872 this->matrix_t0.add(dof_indices, IC);
873 this->matrix_t0.add(dof_indices, IC_t);
874
875 const auto neighcell = cell->neighbor(edge);
877 this->dof_handler.get_dof_indices(neighcell);
878
879 std::tie(IN, IN_t) =
880 this->assemble->local_IN(this->prm_penalty_coeff);
881 IN *= Sigma;
882 IN_t *= Sigma;
883 SN =
884 this->assemble->local_SN(this->prm_stability_coeff);
885 SN *= Sigma;
886
887 this->matrix_t0.add(dof_indices, dof_indices_neigh, IN);
888 this->matrix_t0.add(dof_indices_neigh,
890 IN_t);
891 this->matrix_t0.add(dof_indices, dof_indices_neigh, SN);
892 }
893 }
894 }
895 }
896 this->matrix_t0.compress(lifex::VectorOperation::add);
897 }
898
899 // The LHS matrix is the sum of matrix_t0 plus the components that depend on
900 // time.
901 this->matrix.copy_from(this->matrix_t0);
902
903 for (const auto &cell : this->dof_handler.active_cell_iterators())
904 {
905 if (cell->is_locally_owned())
906 {
907 this->assemble->reinit(cell);
908 dof_indices = this->dof_handler.get_dof_indices(cell);
909
910 C = this->assemble->local_non_linear_fitzhugh(this->solution_owned,
911 a,
913 C *= kappa * ChiM;
914
915 cell_rhs = this->assemble->local_rhs(this->f_ex);
916
917 u0_rhs =
918 this->assemble->local_u0_M_rhs(this->solution_bdf, dof_indices);
919 u0_rhs *= Cm * ChiM / this->prm_time_step;
920
921 w0_rhs =
922 this->assemble->local_w0_M_rhs(solution_owned_w, dof_indices);
923 w0_rhs *= -ChiM;
924
925 if (cell->at_boundary())
926 {
927 for (const auto &edge : cell->face_indices())
928 {
929 if (cell->at_boundary(edge))
930 {
931 this->assemble->reinit(cell, edge);
933 this->assemble->local_rhs_edge_neumann(this->g_n);
934 this->rhs.add(dof_indices, cell_rhs_edge);
935 }
936 }
937 }
938
939 this->matrix.add(dof_indices, C);
940 this->rhs.add(dof_indices, cell_rhs);
941 this->rhs.add(dof_indices, u0_rhs);
942 this->rhs.add(dof_indices, w0_rhs);
943 }
944 }
945
946 this->matrix.compress(lifex::VectorOperation::add);
947 this->rhs.compress(lifex::VectorOperation::add);
948 }
949} // namespace DUBeat::models
950
951#endif /* MONODOMAIN_FHN_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
Class to solve the monodomain equation with Fitzhugh-Nagumo ionic model for the cardiac electrophysio...
lifex::LinAlg::MPI::Vector solution_bdf_w
BDF solution, with ghost entries.
lifex::LinAlg::MPI::Vector solution_ex_owned_w
Solution exact gating variable, without ghost entries.
double kappa
Factor for the nonlinear reaction in Fitzhugh Nagumo model.
std::shared_ptr< dealii::Function< lifex::dim > > grad_w_ex
dealii::Pointer to exact gradient solution Function gating variable
std::shared_ptr< lifex::utils::FunctionDirichlet > w_ex
dealii::Pointer to exact solution function gating variable.
virtual void declare_parameters(lifex::ParamHandler &params) const override
Override for declaration of additional parameters.
lifex::LinAlg::MPI::Vector solution_ex_w
Solution exact gating variable, without ghost entries.
void run() override
Override for the simulation run.
lifex::LinAlg::MPI::Vector solution_owned_w
Solution gating variable, without ghost entries.
void time_initialization() override
Override to initialize both u and w.
lifex::utils::BDFHandler< lifex::LinAlg::MPI::Vector > bdf_handler_w
BDF time advancing handler.
void update_time() override
Override to update time for both u and w.
lifex::LinAlg::MPI::Vector solution_w
Solution gating variable, with ghost entries.
lifex::LinAlg::MPI::Vector solution_ext_w
BDF extrapolated solution, with ghost entries.
double Sigma
Diffusion scalar parameter.
void assemble_system() override
Assembly of the Monodomain system.
double ChiM
Monodomain equation parameter.
virtual void parse_parameters(lifex::ParamHandler &params) override
Override to parse additional parameters.
lifex::LinAlg::MPI::SparseMatrix matrix_t0
Component of the system matrix that does not depend on time.
Neumann boundary condition of the trans-membrane potential.
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the Neumann boundary condition function in a point.
ExactSolution_w(double epsilon, double gamma)
Constructor.
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the exact solution in a point.
Exact solution of the trans-membrane potential.
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the exact solution in a point.
GradExactSolution_w(double epsilon, double gamma)
Constructor.
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.
Gradient of the trans-membrane potential.
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.
RightHandSide(double ChiM, double Sigma, double Cm, double kappa, double epsilon, double gamma, double a)
Constructor.
double kappa
Factor for the nonlinear reaction in Fitzhugh Nagumo model.
double ChiM
Parameter monodomain equation.
virtual double value(const dealii::Point< lifex::dim > &p, const unsigned int=0) const override
Evaluate the source term in a point.
Class representing the resolution of time-dependent problems using discontinuous Galerkin methods.
virtual void declare_parameters(lifex::ParamHandler &params) const override
Override for declaration of additional parameters.
double prm_time_step
Time-step amplitude.
double time
Current time.
lifex::LinAlg::MPI::Vector solution_bdf
BDF solution, with ghost entries.
lifex::LinAlg::MPI::Vector solution_ext
BDF extrapolated solution, with ghost entries.
lifex::utils::BDFHandler< lifex::LinAlg::MPI::Vector > bdf_handler
BDF time advancing handler.
virtual void intermediate_error_print(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 char *solution_name=(char *)"u")
Computation of the error at an intermediate time-step.
double prm_time_init
Initial time.
virtual void parse_parameters(lifex::ParamHandler &params) override
Override to parse additional parameters.
unsigned int prm_bdf_order
BDF order.
double prm_time_final
Final time.
unsigned int timestep_number
Current time-step number.
virtual void update_time()
To perform the time increment.
virtual void time_initialization()
Setup for the time-dependent problems at the initial time-step.
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
unsigned int prm_n_refinements
Mesh refinement level (>=1).
Definition model_DG.hpp:216
void initialize_solution(lifex::LinAlg::MPI::Vector &solution_owned, lifex::LinAlg::MPI::Vector &solution)
To inizialize the solutions using the deal.II reinit.
Definition model_DG.hpp:492
unsigned int prm_fe_degree
Polynomials degree.
Definition model_DG.hpp:214
double prm_stability_coeff
DG stabilty coefficient.
Definition model_DG.hpp:220
lifex::LinAlg::MPI::Vector solution
Distributed solution vector, with ghost entries.
Definition model_DG.hpp:245
std::unique_ptr< AssembleDG< basis > > assemble
Matrix assembler.
Definition model_DG.hpp:233
lifex::LinAlg::MPI::Vector solution_ex
Distributed exact solution vector, without ghost entries.
Definition model_DG.hpp:249
DoFHandlerDG< basis > dof_handler
DoFHandler (internal use for useful already implemented methods).
Definition model_DG.hpp:228
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...
Definition model_DG.hpp:607
void create_mesh()
Load the mesh from the default path.
Definition model_DG.hpp:504
lifex::LinAlg::MPI::Vector solution_owned
Distributed solution vector, without ghost entries.
Definition model_DG.hpp:243
std::shared_ptr< dealii::Function< lifex::dim > > f_ex
Known forcing term.
Definition model_DG.hpp:255
lifex::utils::PreconditionerHandler preconditioner
Preconditioner handler.
Definition model_DG.hpp:237
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
virtual void output_results(std::string output_name="solution") const
Output of results.
Definition model_DG.hpp:581
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,...
Definition model_DG.hpp:547
unsigned int dofs_per_cell
Number of degrees of freedom per cell.
Definition model_DG.hpp:226
void solve_system()
System solving.
Definition model_DG.hpp:538
std::shared_ptr< lifex::utils::FunctionDirichlet > u_ex
Pointer to exact solution function.
Definition model_DG.hpp:251
lifex::LinAlg::MPI::Vector solution_ex_owned
Distributed exact solution vector, without ghost entries.
Definition model_DG.hpp:247
lifex::LinAlg::MPI::Vector rhs
Distributed right hand side vector of the linear system.
Definition model_DG.hpp:241
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.
lifex::utils::LinearSolverHandler< lifex::LinAlg::MPI::Vector > linear_solver
Linear solver handler.
Definition model_DG.hpp:235
virtual void setup_system()
Setup of the problem before the resolution.
Definition model_DG.hpp:382