deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20: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_bernstein.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) 2015 - 2025 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
18
20#include <deal.II/fe/fe_dgq.h>
22#include <deal.II/fe/fe_q.h>
23#include <deal.II/fe/fe_tools.h>
24
25#include <memory>
26#include <sstream>
27#include <vector>
28
29
31
32
33
34template <int dim, int spacedim>
36 : FE_Q_Base<dim, spacedim>(this->renumber_bases(degree),
37 FiniteElementData<dim>(this->get_dpo_vector(
38 degree),
39 1,
40 degree,
41 FiniteElementData<dim>::H1),
42 std::vector<bool>(1, false))
43{}
44
45
46
47template <int dim, int spacedim>
48void
51 FullMatrix<double> &) const
52{
53 // no interpolation possible. throw exception, as documentation says
55 false,
57}
58
59
60
61template <int dim, int spacedim>
64 const unsigned int,
65 const RefinementCase<dim> &) const
66{
67 AssertThrow(false,
69 // return dummy, nothing will happen because the base class FE_Q_Base
70 // implements lazy evaluation of those matrices
71 return this->restriction[0][0];
72}
73
74
75
76template <int dim, int spacedim>
79 const unsigned int,
80 const RefinementCase<dim> &) const
81{
82 AssertThrow(false,
84 // return dummy, nothing will happen because the base class FE_Q_Base
85 // implements lazy evaluation of those matrices
86 return this->prolongation[0][0];
87}
88
89
90
91template <int dim, int spacedim>
92void
94 const FiniteElement<dim, spacedim> &source_fe,
95 FullMatrix<double> &interpolation_matrix,
96 const unsigned int face_no) const
97{
98 get_subface_interpolation_matrix(source_fe,
100 interpolation_matrix,
101 face_no);
102}
103
104
105template <int dim, int spacedim>
106void
108 const FiniteElement<dim, spacedim> &x_source_fe,
109 const unsigned int subface,
110 FullMatrix<double> &interpolation_matrix,
111 const unsigned int face_no) const
112{
113 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
114 ExcDimensionMismatch(interpolation_matrix.m(),
115 x_source_fe.n_dofs_per_face(face_no)));
116
117 // see if source is a Bernstein element
118 if (const FE_Bernstein<dim, spacedim> *source_fe =
119 dynamic_cast<const FE_Bernstein<dim, spacedim> *>(&x_source_fe))
120 {
121 // have this test in here since a table of size 2x0 reports its size as
122 // 0x0
123 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
124 ExcDimensionMismatch(interpolation_matrix.n(),
125 this->n_dofs_per_face(face_no)));
126
127 // Make sure that the element for which the DoFs should be constrained
128 // is the one with the higher polynomial degree. Actually the procedure
129 // will work also if this assertion is not satisfied. But the matrices
130 // produced in that case might lead to problems in the hp-procedures,
131 // which use this method.
132 Assert(
133 this->n_dofs_per_face(face_no) <= source_fe->n_dofs_per_face(face_no),
134 (typename FiniteElement<dim,
135 spacedim>::ExcInterpolationNotImplemented()));
136
137 const Quadrature<dim - 1> quad_face_support(
138 FE_Q<dim, spacedim>(QIterated<1>(QTrapezoid<1>(), source_fe->degree))
140
141 // Rule of thumb for FP accuracy, that can be expected for a given
142 // polynomial degree. This value is used to cut off values close to
143 // zero.
144 const double eps = 2e-13 * std::max(this->degree, source_fe->degree) *
145 std::max(dim - 1, 1);
146
147 // compute the interpolation matrix by simply taking the value at the
148 // support points.
149 // TODO: Verify that all faces are the same with respect to
150 // these support points. Furthermore, check if something has to
151 // be done for the face orientation flag in 3d.
152 const Quadrature<dim> subface_quadrature =
155 this->reference_cell(),
156 quad_face_support,
157 0,
160 this->reference_cell(),
161 quad_face_support,
162 0,
163 subface,
166
167 for (unsigned int i = 0; i < source_fe->n_dofs_per_face(face_no); ++i)
168 {
169 const Point<dim> &p = subface_quadrature.point(i);
170 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
171 {
172 double matrix_entry =
173 this->shape_value(this->face_to_cell_index(j, 0), p);
174
175 // Correct the interpolated value. I.e. if it is close to 1 or
176 // 0, make it exactly 1 or 0. Unfortunately, this is required to
177 // avoid problems with higher order elements.
178 if (std::fabs(matrix_entry - 1.0) < eps)
179 matrix_entry = 1.0;
180 if (std::fabs(matrix_entry) < eps)
181 matrix_entry = 0.0;
182
183 interpolation_matrix(i, j) = matrix_entry;
184 }
185 }
186
187 if constexpr (running_in_debug_mode())
188 {
189 // make sure that the row sum of each of the matrices is 1 at this
190 // point. this must be so since the shape functions sum up to 1
191 for (unsigned int j = 0; j < source_fe->n_dofs_per_face(face_no); ++j)
192 {
193 double sum = 0.;
194
195 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
196 sum += interpolation_matrix(j, i);
197
198 Assert(std::fabs(sum - 1) < eps, ExcInternalError());
199 }
200 }
201 }
202 else
203 {
204 // When the incoming element is not FE_Bernstein we can just delegate to
205 // the base class to create the interpolation matrix.
207 x_source_fe, subface, interpolation_matrix, face_no);
208 }
209}
210
211
212
213template <int dim, int spacedim>
214bool
219
220
221template <int dim, int spacedim>
222std::vector<std::pair<unsigned int, unsigned int>>
224 const FiniteElement<dim, spacedim> &fe_other) const
225{
226 // we can presently only compute these identities if both FEs are
227 // FE_Bernsteins or if the other one is an FE_Nothing. in the first case,
228 // there should be exactly one single DoF of each FE at a vertex, and they
229 // should have identical value
230 if (dynamic_cast<const FE_Bernstein<dim, spacedim> *>(&fe_other) != nullptr)
231 {
232 return std::vector<std::pair<unsigned int, unsigned int>>(
233 1, std::make_pair(0U, 0U));
234 }
235 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
236 {
237 // the FE_Nothing has no degrees of freedom, so there are no
238 // equivalencies to be recorded
239 return std::vector<std::pair<unsigned int, unsigned int>>();
240 }
241 else if (fe_other.n_unique_faces() == 1 && fe_other.n_dofs_per_face(0) == 0)
242 {
243 // if the other element has no elements on faces at all,
244 // then it would be impossible to enforce any kind of
245 // continuity even if we knew exactly what kind of element
246 // we have -- simply because the other element declares
247 // that it is discontinuous because it has no DoFs on
248 // its faces. in that case, just state that we have no
249 // constraints to declare
250 return std::vector<std::pair<unsigned int, unsigned int>>();
251 }
252 else
253 {
255 return std::vector<std::pair<unsigned int, unsigned int>>();
256 }
257}
258
259
260template <int dim, int spacedim>
261std::vector<std::pair<unsigned int, unsigned int>>
263 const FiniteElement<dim, spacedim> &) const
264{
265 // Since this FE is not interpolatory but on the vertices, we can
266 // not identify dofs on lines and on quads even if there are dofs
267 // on lines and on quads.
268 //
269 // we also have nothing to say about interpolation to other finite
270 // elements. consequently, we never have anything to say at all
271 return std::vector<std::pair<unsigned int, unsigned int>>();
272}
273
274
275template <int dim, int spacedim>
276std::vector<std::pair<unsigned int, unsigned int>>
279 const unsigned int) const
280{
281 // Since this FE is not interpolatory but on the vertices, we can
282 // not identify dofs on lines and on quads even if there are dofs
283 // on lines and on quads.
284 //
285 // we also have nothing to say about interpolation to other finite
286 // elements. consequently, we never have anything to say at all
287 return std::vector<std::pair<unsigned int, unsigned int>>();
288}
289
290
291template <int dim, int spacedim>
294 const FiniteElement<dim, spacedim> &fe_other,
295 const unsigned int codim) const
296{
297 Assert(codim <= dim, ExcImpossibleInDim(dim));
298
299 // vertex/line/face domination
300 // (if fe_other is derived from FE_DGQ)
301 // ------------------------------------
302 if (codim > 0)
303 if (dynamic_cast<const FE_DGQ<dim, spacedim> *>(&fe_other) != nullptr)
304 // there are no requirements between continuous and discontinuous elements
306
307 // vertex/line/face domination
308 // (if fe_other is not derived from FE_DGQ)
309 // & cell domination
310 // ----------------------------------------
311 if (const FE_Bernstein<dim, spacedim> *fe_b_other =
312 dynamic_cast<const FE_Bernstein<dim, spacedim> *>(&fe_other))
313 {
314 if (this->degree < fe_b_other->degree)
316 else if (this->degree == fe_b_other->degree)
318 else
320 }
321 else if (const FE_Nothing<dim, spacedim> *fe_nothing =
322 dynamic_cast<const FE_Nothing<dim, spacedim> *>(&fe_other))
323 {
324 if (fe_nothing->is_dominating())
326 else
327 // the FE_Nothing has no degrees of freedom and it is typically used
328 // in a context where we don't require any continuity along the
329 // interface
331 }
332
335}
336
337
338template <int dim, int spacedim>
339std::string
341{
342 // note that the FETools::get_fe_by_name function depends on the
343 // particular format of the string this function returns, so they have to be
344 // kept in synch
345
346 std::ostringstream namebuf;
347 namebuf << "FE_Bernstein<" << Utilities::dim_string(dim, spacedim) << ">("
348 << this->degree << ")";
349 return namebuf.str();
350}
351
352
353template <int dim, int spacedim>
354std::unique_ptr<FiniteElement<dim, spacedim>>
356{
357 return std::make_unique<FE_Bernstein<dim, spacedim>>(*this);
358}
359
360
364template <int dim, int spacedim>
365std::vector<unsigned int>
367{
368 AssertThrow(deg > 0, ExcMessage("FE_Bernstein needs to be of degree > 0."));
369 std::vector<unsigned int> dpo(dim + 1, 1U);
370 for (unsigned int i = 1; i < dpo.size(); ++i)
371 dpo[i] = dpo[i - 1] * (deg - 1);
372 return dpo;
373}
374
375
376template <int dim, int spacedim>
379{
381 ::generate_complete_bernstein_basis<double>(deg));
382 tpp.set_numbering(FETools::hierarchic_to_lexicographic_numbering<dim>(deg));
383 return tpp;
384}
385
386
387// explicit instantiations
388#include "fe/fe_bernstein.inst"
389
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
FE_Bernstein(const unsigned int p)
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim=0) const override final
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim, spacedim > &fe_other, const unsigned int face_no=0) const override
virtual bool hp_constraints_are_implemented() const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
TensorProductPolynomials< dim > renumber_bases(const unsigned int degree)
virtual std::string get_name() const override
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
virtual void get_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const override
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
Definition fe_q.h:552
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_unique_faces() const
const std::vector< Point< dim - 1 > > & get_unit_face_support_points(const unsigned int face_no=0) const
size_type n() const
size_type m() const
Definition point.h:111
static Quadrature< dim > project_to_face(const ReferenceCell< dim > &reference_cell, const SubQuadrature &quadrature, const unsigned int face_no, const types::geometric_orientation combined_orientation)
static Quadrature< dim > project_to_subface(const ReferenceCell< dim > &reference_cell, const SubQuadrature &quadrature, const unsigned int face_no, const unsigned int subface_no, const types::geometric_orientation combined_orientation, const RefinementCase< dim - 1 > &ref_case)
const Point< dim > & point(const unsigned int i) const
void set_numbering(const std::vector< unsigned int > &renumber)
#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()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
STL namespace.
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)