ExaDG
Loading...
Searching...
No Matches
finite_element.h
1/* ______________________________________________________________________
2 *
3 * ExaDG - High-Order Discontinuous Galerkin for the Exa-Scale
4 *
5 * Copyright (C) 2023 by the ExaDG authors
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 * ______________________________________________________________________
20 */
21
22#ifndef INCLUDE_EXADG_OPERATORS_FINITE_ELEMENT_H_
23#define INCLUDE_EXADG_OPERATORS_FINITE_ELEMENT_H_
24
25// deal.II
26#include <deal.II/fe/fe_dgq.h>
27#include <deal.II/fe/fe_q.h>
28#include <deal.II/fe/fe_simplex_p.h>
29#include <deal.II/fe/fe_system.h>
30
31// ExaDG
32#include <exadg/grid/grid_data.h>
33#include <exadg/utilities/exceptions.h>
34
35namespace ExaDG
36{
43template<int dim>
44std::shared_ptr<dealii::FiniteElement<dim>>
45create_finite_element(ElementType const & element_type,
46 bool const is_dg,
47 unsigned int const n_components,
48 unsigned int const degree)
49{
50 std::shared_ptr<dealii::FiniteElement<dim>> fe;
51
52 // For n_components = 1, we would not need FESystem around the finite element. We do this
53 // nevertheless in order to use the same code path for all cases, since this is not a
54 // performance-critical part of the code.
55
56 if(is_dg)
57 {
58 if(element_type == ElementType::Hypercube)
59 {
60 fe = std::make_shared<dealii::FESystem<dim>>(dealii::FE_DGQ<dim>(degree), n_components);
61 }
62 else if(element_type == ElementType::Simplex)
63 {
64 fe =
65 std::make_shared<dealii::FESystem<dim>>(dealii::FE_SimplexDGP<dim>(degree), n_components);
66 }
67 else
68 {
69 AssertThrow(false, ExcNotImplemented());
70 }
71 }
72 else
73 {
74 if(element_type == ElementType::Hypercube)
75 {
76 fe = std::make_shared<dealii::FESystem<dim>>(dealii::FE_Q<dim>(degree), n_components);
77 }
78 else if(element_type == ElementType::Simplex)
79 {
80 fe = std::make_shared<dealii::FESystem<dim>>(dealii::FE_SimplexP<dim>(degree), n_components);
81 }
82 else
83 {
84 AssertThrow(false, ExcNotImplemented());
85 }
86 }
87
88 return fe;
89}
90
91inline unsigned int
92get_dofs_per_element_simplex_scalar(unsigned int const n_points_1d, unsigned int const dim)
93{
94 if(n_points_1d == 0)
95 return 0;
96 else if(n_points_1d == 1)
97 return 1;
98 else
99 {
100 unsigned int scalar_inner_dofs = 1;
101 for(unsigned int d = 0; d < dim; ++d)
102 scalar_inner_dofs = (scalar_inner_dofs * (n_points_1d + d)) / (d + 1);
103
104 return scalar_inner_dofs;
105 }
106}
107
108inline double
109get_dofs_per_element(ExaDG::ElementType const element_type,
110 bool const is_dg,
111 unsigned int const n_components,
112 unsigned int const degree,
113 unsigned int const dim)
114{
115 double scalar_dofs_per_element = 0.;
116
117 if(element_type == ElementType::Hypercube)
118 {
119 unsigned int n_points_1d = degree;
120 if(is_dg)
121 n_points_1d += 1;
122
123 scalar_dofs_per_element = dealii::Utilities::pow(n_points_1d, dim);
124 }
125 else if(element_type == ElementType::Simplex)
126 {
127 unsigned int n_points_1d = degree + 1;
128
129 if(is_dg)
130 {
131 scalar_dofs_per_element = get_dofs_per_element_simplex_scalar(n_points_1d, dim);
132 }
133 else // continuous Galerkin
134 {
135 if(dim == 2)
136 {
137 // consider a quadrilateral element that is subdivided into 2 triangular elements; the
138 // quadrilateral element has one unique corner shared by 2 triangular elements; each
139 // face/edge is shared by 2 triangular elements; inner dofs are unique per triangular
140 // element
141
142 scalar_dofs_per_element = 1. / 2.; // corners
143 scalar_dofs_per_element += 3. * (n_points_1d - 2) / 2.; // faces/edges
144 if(n_points_1d >= 3)
145 {
146 scalar_dofs_per_element +=
147 get_dofs_per_element_simplex_scalar(n_points_1d - 3, dim); // inner
148 }
149 }
150 else if(dim == 3)
151 {
152 // consider a hexahedral element that is subdivided into 5 tetrahedral elements; the
153 // "hexahedral element" has one unique corner shared by 5 tetrahedral elements; assume that
154 // each of the 6 unique edges of the "hexahedral element" (with 5 tets inside) is shared by
155 // 5 tetrahedra; and each of the 4 unique faces per tetrahedral element is shared by
156 // 2 tetrahedra; inner dofs are unique per tetrahedral element
157
158 scalar_dofs_per_element = 1. / 5.; // corners
159 scalar_dofs_per_element += 6. * (n_points_1d - 2) / 5.; // edges
160 if(n_points_1d >= 3)
161 {
162 scalar_dofs_per_element +=
163 4. * get_dofs_per_element_simplex_scalar(n_points_1d - 3, dim - 1) / 2.; // faces
164 }
165 if(n_points_1d >= 4)
166 {
167 scalar_dofs_per_element +=
168 get_dofs_per_element_simplex_scalar(n_points_1d - 4, dim); // inner
169 }
170 }
171 else
172 {
173 AssertThrow(false, dealii::ExcMessage("Not implemented."));
174 }
175 }
176 }
177 else
178 {
179 AssertThrow(false, ExcNotImplemented());
180 }
181
182 return scalar_dofs_per_element * n_components;
183}
184
185} // namespace ExaDG
186
187
188
189#endif /* INCLUDE_EXADG_OPERATORS_FINITE_ELEMENT_H_ */
Definition driver.cpp:33
std::shared_ptr< dealii::FiniteElement< dim > > create_finite_element(ElementType const &element_type, bool const is_dg, unsigned int const n_components, unsigned int const degree)
Definition finite_element.h:45