deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_simplex_p_bubbles.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2021 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/config.h>
14
17
18#include <deal.II/fe/fe_dgq.h>
20#include <deal.II/fe/fe_q.h>
22#include <deal.II/fe/fe_tools.h>
23
25
27{
28 template <int dim>
29 std::vector<unsigned int>
30 get_dpo_vector(const unsigned int degree)
31 {
32 std::vector<unsigned int> dpo(dim + 1);
33 if (degree == 0)
34 {
35 dpo[dim] = 1; // single interior dof
36 }
37 else
38 {
39 Assert(degree == 1 || degree == 2, ExcNotImplemented());
40 dpo[0] = 1; // vertex dofs
41
42 if (degree == 2)
43 {
44 dpo[1] = 1; // line dofs
45
46 if (dim > 1)
47 dpo[dim] = 1; // the internal bubble function
48 if (dim == 3)
49 dpo[dim - 1] = 1; // face bubble functions
50 }
51 }
52
53 return dpo;
54 }
55
56
57
58 template <int dim>
59 std::vector<Point<dim>>
60 unit_support_points(const unsigned int degree)
61 {
62 Assert(degree < 3, ExcNotImplemented());
63 // Start with the points used by FE_SimplexP, and then add bubbles.
64 FE_SimplexP<dim> fe_p(degree);
65 std::vector<Point<dim>> points = fe_p.get_unit_support_points();
66
67 const auto reference_cell = fe_p.reference_cell();
68 const Point<dim> centroid = reference_cell.barycenter();
69
70 switch (dim)
71 {
72 case 1:
73 // nothing more to do
74 return points;
75 case 2:
76 {
77 if (degree == 2)
78 points.push_back(centroid);
79 return points;
80 }
81 case 3:
82 {
83 if (degree == 2)
84 {
85 for (const auto &face_no : reference_cell.face_indices())
86 {
87 Point<dim> midpoint;
88 for (const auto face_vertex_no :
89 reference_cell.face_reference_cell(0).vertex_indices())
90 {
91 const auto vertex_no =
92 reference_cell.face_to_cell_vertices(
93 face_no,
94 face_vertex_no,
96
97 midpoint += reference_cell.vertex(vertex_no);
98 }
99
100 midpoint /=
101 reference_cell.face_reference_cell(0).n_vertices();
102 points.push_back(midpoint);
103 }
104
105 points.push_back(centroid);
106 }
107 return points;
108 }
109 default:
111 }
112 return points;
113 }
114
115
116
117 template <>
118 std::vector<Point<0>>
119 unit_support_points<0>(const unsigned int /*degree*/)
120 {
121 std::vector<Point<0>> points;
122 points.emplace_back();
123 return points;
124 }
125
126
127
128 template <int dim>
130 get_basis(const unsigned int degree)
131 {
132 const auto reference_cell = ReferenceCells::get_simplex<dim>();
133 const Point<dim> centroid = reference_cell.barycenter();
134
135 auto M = [](const unsigned int d) {
137 };
138
139 switch (degree)
140 {
141 // we don't need to add bubbles to P0 or P1
142 case 0:
143 case 1:
145 case 2:
146 {
147 const auto fe_p =
149 // no further work is needed in 1d
150 if (dim == 1)
151 return fe_p;
152
153 // in 2d and 3d we add a centroid bubble function
154 auto c_bubble = BarycentricPolynomial<dim>() + 1;
155 for (const auto &vertex : reference_cell.vertex_indices())
156 c_bubble = c_bubble * M(vertex);
157 c_bubble = c_bubble / c_bubble.value(centroid);
158
159 std::vector<BarycentricPolynomial<dim>> bubble_functions;
160 if (dim == 2)
161 {
162 bubble_functions.push_back(c_bubble);
163 }
164 else if (dim == 3)
165 {
166 // need 'face bubble' functions in addition to the centroid.
167 // Furthermore we need to subtract them off from the other
168 // functions so that we end up with an interpolatory basis
169 for (const auto &face_no : reference_cell.face_indices())
170 {
171 std::vector<unsigned int> vertices;
172 for (const auto face_vertex_no :
173 reference_cell.face_reference_cell(0).vertex_indices())
174 vertices.push_back(reference_cell.face_to_cell_vertices(
175 face_no,
176 face_vertex_no,
178
179 Assert(vertices.size() == 3, ExcInternalError());
180 auto b =
181 27.0 * M(vertices[0]) * M(vertices[1]) * M(vertices[2]);
182 bubble_functions.push_back(b -
183 b.value(centroid) * c_bubble);
184 }
185
186 bubble_functions.push_back(c_bubble);
187 }
188
189 // Extract out the support points for the extra bubble (both
190 // volume and face) functions:
191 const std::vector<Point<dim>> support_points =
192 unit_support_points<dim>(degree);
193 const std::vector<Point<dim>> bubble_support_points(
194 support_points.begin() + fe_p.n(), support_points.end());
195 Assert(bubble_support_points.size() == bubble_functions.size(),
197 const unsigned int n_bubbles = bubble_support_points.size();
198
199 // Assemble the final basis:
200 std::vector<BarycentricPolynomial<dim>> lump_polys;
201 for (unsigned int i = 0; i < fe_p.n(); ++i)
202 {
203 BarycentricPolynomial<dim> p = fe_p[i];
204
205 for (unsigned int j = 0; j < n_bubbles; ++j)
206 {
207 p = p -
208 p.value(bubble_support_points[j]) * bubble_functions[j];
209 }
210
211 lump_polys.push_back(p);
212 }
213
214 for (auto &p : bubble_functions)
215 lump_polys.push_back(std::move(p));
216
217 // Sanity check:
218 if constexpr (running_in_debug_mode())
219 {
221 for (const auto &p : lump_polys)
222 unity = unity + p;
223
224 Point<dim> test;
225 for (unsigned int d = 0; d < dim; ++d)
226 test[d] = 2.0;
227 Assert(std::abs(unity.value(test) - 1.0) < 1e-10,
229 }
230
231 return BarycentricPolynomials<dim>(lump_polys);
232 }
233 default:
234 Assert(degree < 3, ExcNotImplemented());
235 }
236
237 Assert(degree < 3, ExcNotImplemented());
238 // bogus return to placate compilers
240 }
241
242
243
244 template <int dim>
246 get_fe_data(const unsigned int degree)
247 {
248 // It's not efficient, but delegate computation of the degree of the
249 // finite element (which is different from the input argument) to the
250 // basis.
251 const auto polys = get_basis<dim>(degree);
252 return FiniteElementData<dim>(get_dpo_vector<dim>(degree),
253 ReferenceCells::get_simplex<dim>(),
254 1, // n_components
255 polys.degree(),
257 }
258} // namespace FE_P_BubblesImplementation
259
260
261
262template <int dim, int spacedim>
264 const unsigned int degree)
265 : FE_SimplexPoly<dim, spacedim>(
266 FE_P_BubblesImplementation::get_basis<dim>(degree),
267 FE_P_BubblesImplementation::get_fe_data<dim>(degree),
268 false,
269 FE_P_BubblesImplementation::unit_support_points<dim>(degree),
271 // Interface constraints are not yet implemented
273 , approximation_degree(degree)
274{}
275
276
277
278template <int dim, int spacedim>
279std::string
281{
282 return "FE_SimplexP_Bubbles<" + Utilities::dim_string(dim, spacedim) + ">" +
283 "(" + std::to_string(approximation_degree) + ")";
284}
285
286
287
288template <int dim, int spacedim>
289std::unique_ptr<FiniteElement<dim, spacedim>>
291{
292 return std::make_unique<FE_SimplexP_Bubbles<dim, spacedim>>(*this);
293}
294
295// explicit instantiations
296#include "fe/fe_simplex_p_bubbles.inst"
297
Number value(const Point< dim > &point) const
static BarycentricPolynomial< dim, Number > monomial(const unsigned int d)
static BarycentricPolynomials< dim > get_fe_p_basis(const unsigned int degree)
FE_SimplexP_Bubbles(const unsigned int degree)
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
virtual std::string get_name() const override
const unsigned int degree
Definition fe_data.h:450
ReferenceCell< dim > reference_cell() const
const std::vector< Point< dim > > & get_unit_support_points() const
Definition point.h:111
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
BarycentricPolynomials< dim > get_basis(const unsigned int degree)
std::vector< Point< dim > > unit_support_points(const unsigned int degree)
std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
std::vector< Point< 0 > > unit_support_points< 0 >(const unsigned int)
FiniteElementData< dim > get_fe_data(const unsigned int degree)
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)