DUBeat  1.0.1
High-order discontinuous Galerkin methods and applications to cardiac electrophysiology
QGaussLegendreSimplex.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 QGAUSSLEGENDRESIMPLEX_HPP_
28 #define QGAUSSLEGENDRESIMPLEX_HPP_
29 
30 #include <deal.II/base/config.h>
31 
32 #include <deal.II/base/quadrature.h>
33 
34 #include <utility>
35 #include <vector>
36 
39 extern std::pair<std::vector<dealii::Point<1>>, std::vector<double>>
40 gauleg(const double left_position,
41  const double right_position,
42  const unsigned int n)
43 {
44  AssertThrow(left_position < right_position,
45  dealii::StandardExceptions::ExcMessage(
46  "(a,b) is an interval, hence a must be lower than b."));
47 
48  // The following lines follow the definition of Gauss-Legendre nodes on an
49  // interval.
50 
51  const double middle_point = 0.5 * (right_position + left_position);
52  const double half_length = 0.5 * (right_position - left_position);
53 
54  std::vector<dealii::Point<1>> coords(n);
55  std::vector<double> weights(n);
56 
57  double z, z1, p1, p2, p3, pp = 0.0;
58 
59  for (unsigned int i = 1; i <= (n + 1) / 2.; ++i)
60  {
61  z = std::cos(M_PI * (i - 0.25) / (n + 0.5));
62  z1 = z + 1.;
63 
64  while (!(std::abs(z - z1) < 1e-10))
65  {
66  p1 = 1.0;
67  p2 = 0.0;
68 
69  for (unsigned int j = 1; j <= n; ++j)
70  {
71  p3 = p2;
72  p2 = p1;
73  p1 = ((2 * j - 1) * z * p2 - (j - 1) * p3) / j;
74  }
75 
76  pp = n * (z * p1 - p2) / (pow(z, 2) - 1);
77  z1 = z;
78  z = z1 - p1 / pp;
79  }
80 
81  const dealii::Point<1> P1(middle_point - half_length * z);
82  const dealii::Point<1> P2(middle_point + half_length * z);
83  coords[i - 1] = P1;
84  coords[n - i] = P2;
85  weights[i - 1] = 2.0 * half_length / ((1.0 - z * z) * pp * pp);
86  weights[n - i] = weights[i - 1];
87  }
88 
89  return {coords, weights};
90 }
91 
98 template <unsigned int dim>
99 class QGaussLegendreSimplex : public dealii::Quadrature<dim>
100 {
101 public:
103  QGaussLegendreSimplex<dim>(const unsigned int n);
104 };
105 
107 template <>
109  : dealii::Quadrature<1>(n)
110 {
111  std::vector<dealii::Point<1>> coords_1D(n);
112  std::vector<double> weights_1D(n);
113  std::tie(coords_1D, weights_1D) = gauleg(0, 1, n);
114 
115  this->quadrature_points = coords_1D;
116  this->weights = weights_1D;
117 }
118 
121 template <>
123  : dealii::Quadrature<2>(n)
124 {
125  std::vector<dealii::Point<1>> coords_1D(n);
126  std::vector<double> weights_1D(n);
127  std::tie(coords_1D, weights_1D) = gauleg(-1, 1, n);
128 
129  std::vector<dealii::Point<2>> coords_2D;
130  std::vector<double> weights_2D;
131 
132  for (unsigned int i = 0; i < n; ++i)
133  {
134  for (unsigned int j = 0; j < n; ++j)
135  {
136  const dealii::Point<2> P((1 + coords_1D[i][0]) / 2,
137  (1 - coords_1D[i][0]) *
138  (1 + coords_1D[j][0]) / 4);
139 
140  coords_2D.push_back(P);
141  weights_2D.push_back((1 - coords_1D[i][0]) * weights_1D[i] *
142  weights_1D[j] / 8);
143  }
144  }
145 
146  this->quadrature_points = coords_2D;
147  this->weights = weights_2D;
148 }
149 
153 template <>
155  : dealii::Quadrature<3>(n)
156 {
157  std::vector<dealii::Point<1>> coords_1D(n);
158  std::vector<double> weights_1D(n);
159  std::tie(coords_1D, weights_1D) = gauleg(-1, 1, n);
160 
161  std::vector<dealii::Point<3>> coords_3D;
162  std::vector<double> weights_3D;
163 
164  for (unsigned int i = 0; i < n; ++i)
165  {
166  for (unsigned int j = 0; j < n; ++j)
167  {
168  for (unsigned int k = 0; k < n; ++k)
169  {
170  const dealii::Point<3> new_coords((coords_1D[i][0] + 1) *
171  (coords_1D[j][0] - 1) *
172  (coords_1D[k][0] - 1) / 8,
173  (1 - coords_1D[k][0]) *
174  (1 + coords_1D[j][0]) / 4,
175  (coords_1D[k][0] + 1) / 2);
176 
177  coords_3D.push_back(new_coords);
178  weights_3D.push_back((1 - coords_1D[k][0]) *
179  (1 - coords_1D[k][0]) *
180  (1 - coords_1D[j][0]) * weights_1D[i] *
181  weights_1D[j] * weights_1D[k] / 64);
182  }
183  }
184  }
185 
186  this->quadrature_points = coords_3D;
187  this->weights = weights_3D;
188 }
189 
190 #endif /* QGAUSSLEGENDRESIMPLEX_HPP_*/
std::pair< std::vector< dealii::Point< 1 > >, std::vector< double > > gauleg(const double left_position, const double right_position, const unsigned int n)
This routine computes the Gauss-Legendre nodes and weights on a given interval (a,...
Class representing the Gauss-Legendre quadrature formula on simplex elements.
QGaussLegendreSimplex(const unsigned int n)
Constructor.