deal.II version 9.8.0
\(\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_bdm.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) 2010 - 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
17
19
20#include <deal.II/fe/fe.h>
21#include <deal.II/fe/fe_bdm.h>
22#include <deal.II/fe/fe_tools.h>
24#include <deal.II/fe/mapping.h>
25
26#include <deal.II/grid/tria.h>
28
29#include <iostream>
30#include <memory>
31#include <sstream>
32
33
35
36// TODO: implement the adjust_quad_dof_index_for_face_orientation_table and
37// adjust_line_dof_index_for_line_orientation_table fields, and write tests
38// similar to bits/face_orientation_and_fe_q_*
39
40template <int dim>
41FE_BDM<dim>::FE_BDM(const unsigned int deg)
42 : FE_PolyTensor<dim>(
43 PolynomialsBDM<dim>(deg),
45 dim,
46 deg + 1,
48 get_ria_vector(deg),
49 std::vector<ComponentMask>(PolynomialsBDM<dim>::n_polynomials(deg),
50 ComponentMask(std::vector<bool>(dim, true))))
51{
52 Assert(dim >= 2, ExcImpossibleInDim(dim));
53 Assert(
54 deg > 0,
56 "Lowest order BDM element are degree 1, but you asked for degree 0"));
57
58 const unsigned int n_dofs = this->n_dofs_per_cell();
59
60 this->mapping_kind = {mapping_bdm};
61 // These must be done first, since
62 // they change the evaluation of
63 // basis functions
64
65 // Set up the generalized support
66 // points
68
69 // Now compute the inverse node matrix, generating the correct
70 // basis functions from the raw ones. For a discussion of what
71 // exactly happens here, see FETools::compute_node_matrix.
73 this->inverse_node_matrix.reinit(n_dofs, n_dofs);
74 this->inverse_node_matrix.invert(M);
75 // From now on, the shape functions provided by FiniteElement::shape_value
76 // and similar functions will be the correct ones, not
77 // the raw shape functions from the polynomial space anymore.
78
79 // Embedding errors become pretty large, so we just replace the
80 // regular threshold in both "computing_..." functions by 1.
83
85 const unsigned int face_no = 0;
86
88 for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
89 face_embeddings[i].reinit(this->n_dofs_per_face(face_no),
90 this->n_dofs_per_face(face_no));
92 *this, make_array_view(face_embeddings), 0, 0, 1.);
93 this->interface_constraints.reinit((1 << (dim - 1)) *
94 this->n_dofs_per_face(face_no),
95 this->n_dofs_per_face(face_no));
96 unsigned int target_row = 0;
97 for (unsigned int d = 0; d < GeometryInfo<dim>::max_children_per_face; ++d)
98 for (unsigned int i = 0; i < face_embeddings[d].m(); ++i)
99 {
100 for (unsigned int j = 0; j < face_embeddings[d].n(); ++j)
101 this->interface_constraints(target_row, j) = face_embeddings[d](i, j);
102 ++target_row;
103 }
104
105 // We need to initialize the dof permutation table and the one for the sign
106 // change.
108}
109
110
111template <int dim>
112void
114{
115 // for 1d and 2d, do nothing
116 if (dim < 3)
117 return;
118
119 // TODO: Implement this for this class
120 return;
121}
122
123
124template <int dim>
125std::string
127{
128 // note that the
129 // FETools::get_fe_by_name
130 // function depends on the
131 // particular format of the string
132 // this function returns, so they
133 // have to be kept in synch
134
135 // note that this->degree is the maximal
136 // polynomial degree and is thus one higher
137 // than the argument given to the
138 // constructor
139 std::ostringstream namebuf;
140 namebuf << "FE_BDM<" << dim << ">(" << this->degree - 1 << ")";
141
142 return namebuf.str();
143}
144
145
146template <int dim>
147std::unique_ptr<FiniteElement<dim, dim>>
149{
150 return std::make_unique<FE_BDM<dim>>(*this);
151}
152
153
154
155template <int dim>
156void
158 const std::vector<Vector<double>> &support_point_values,
159 std::vector<double> &nodal_values) const
160{
161 Assert(support_point_values.size() == this->generalized_support_points.size(),
162 ExcDimensionMismatch(support_point_values.size(),
163 this->generalized_support_points.size()));
164 AssertDimension(support_point_values[0].size(), dim);
165 Assert(nodal_values.size() == this->n_dofs_per_cell(),
166 ExcDimensionMismatch(nodal_values.size(), this->n_dofs_per_cell()));
167
168 // First do interpolation on faces. There, the component evaluated
169 // depends on the face direction and orientation.
170
171 // The index of the first dof on this face or the cell
172 unsigned int dbase = 0;
173 // The index of the first generalized support point on this face or the cell
174 unsigned int pbase = 0;
175 for (auto f : GeometryInfo<dim>::face_indices())
176 {
177 // Old version with no moments in 2d. See comment below in
178 // initialize_support_points()
179 if (test_values_face.empty())
180 {
181 for (unsigned int i = 0; i < this->n_dofs_per_face(f); ++i)
182 nodal_values[dbase + i] =
183 support_point_values[pbase + i]
185 pbase += this->n_dofs_per_face(f);
186 }
187 else
188 {
189 for (unsigned int i = 0; i < this->n_dofs_per_face(f); ++i)
190 {
191 double s = 0.;
192 for (unsigned int k = 0; k < test_values_face.size(); ++k)
193 s +=
194 support_point_values
196 test_values_face[k][i];
197 nodal_values[dbase + i] = s;
198 }
199 pbase += test_values_face.size();
200 }
201 dbase += this->n_dofs_per_face(f);
202 }
203
205 const unsigned int face_no = 0;
206 (void)face_no;
207
208 AssertDimension(dbase,
209 this->n_dofs_per_face(face_no) *
211 AssertDimension(pbase,
212 this->generalized_support_points.size() -
213 test_values_cell.size());
214
215 // Done for BDM1
216 if (dbase == this->n_dofs_per_cell())
217 return;
218
219 // What's missing are the interior
220 // degrees of freedom. In each
221 // point, we take all components of
222 // the solution.
223 Assert((this->n_dofs_per_cell() - dbase) % dim == 0, ExcInternalError());
224
225 for (unsigned int d = 0; d < dim; ++d, dbase += test_values_cell[0].size())
226 {
227 for (unsigned int i = 0; i < test_values_cell[0].size(); ++i)
228 {
229 double s = 0.;
230 for (unsigned int k = 0; k < test_values_cell.size(); ++k)
231 s += support_point_values[pbase + k][d] * test_values_cell[k][i];
232 nodal_values[dbase + i] = s;
233 }
234 }
235
236 Assert(dbase == this->n_dofs_per_cell(), ExcInternalError());
237}
238
239
240
241template <int dim>
242std::vector<unsigned int>
243FE_BDM<dim>::get_dpo_vector(const unsigned int deg)
244{
245 // compute the number of unknowns per cell interior/face/edge
246 //
247 // for the number of interior dofs, this is the number of
248 // polynomials up to degree deg-2 in dim dimensions.
249 //
250 // the element is face-based and we have as many degrees of freedom
251 // on the faces as there are polynomials of degree up to
252 // deg. Observe the odd convention of
253 // PolynomialSpace::n_polynomials()!
254
255 std::vector<unsigned int> dpo(dim + 1, 0u);
256 dpo[dim] =
257 (deg > 1 ? dim * PolynomialSpace<dim>::n_polynomials(deg - 1) : 0u);
258 dpo[dim - 1] = PolynomialSpace<dim - 1>::n_polynomials(deg + 1);
259
260 return dpo;
261}
262
263
264
265template <int dim>
266std::vector<bool>
267FE_BDM<dim>::get_ria_vector(const unsigned int deg)
268{
269 if (dim == 1)
270 {
271 Assert(false, ExcImpossibleInDim(1));
272 return std::vector<bool>();
273 }
274
275 const unsigned int dofs_per_cell = PolynomialsBDM<dim>::n_polynomials(deg);
276 const unsigned int dofs_per_face =
278
281
282 // all dofs need to be
283 // non-additive, since they have
284 // continuity requirements.
285 // however, the interior dofs are
286 // made additive
287 std::vector<bool> ret_val(dofs_per_cell, false);
288 for (unsigned int i = GeometryInfo<dim>::faces_per_cell * dofs_per_face;
289 i < dofs_per_cell;
290 ++i)
291 ret_val[i] = true;
292
293 return ret_val;
294}
295
296
297namespace internal
298{
299 namespace FE_BDM
300 {
301 namespace
302 {
303 // This function sets up the values of the polynomials we want to
304 // take moments with in the quadrature points. In fact, we multiply
305 // those by the weights, such that the sum of function values and
306 // test_values over quadrature points yields the interpolated degree
307 // of freedom.
308 template <int dim>
309 void
310 initialize_test_values(std::vector<std::vector<double>> &test_values,
311 const Quadrature<dim> &quadrature,
312 const unsigned int deg)
313 {
314 PolynomialsP<dim> poly(deg);
315 std::vector<Tensor<1, dim>> dummy1;
316 std::vector<Tensor<2, dim>> dummy2;
317 std::vector<Tensor<3, dim>> dummy3;
318 std::vector<Tensor<4, dim>> dummy4;
319
320 test_values.resize(quadrature.size());
321
322 for (unsigned int k = 0; k < quadrature.size(); ++k)
323 {
324 test_values[k].resize(poly.n());
325 poly.evaluate(quadrature.point(k),
326 test_values[k],
327 dummy1,
328 dummy2,
329 dummy3,
330 dummy4);
331 for (unsigned int i = 0; i < poly.n(); ++i)
332 {
333 test_values[k][i] *= quadrature.weight(k);
334 }
335 }
336 }
337
338 // This specialization only serves to avoid error messages. Nothing
339 // useful can be computed in dimension zero and thus the vector
340 // length stays zero.
341 template <>
342 void
343 initialize_test_values(std::vector<std::vector<double>> &,
344 const Quadrature<0> &,
345 const unsigned int)
346 {}
347 } // namespace
348 } // namespace FE_BDM
349} // namespace internal
350
351
352template <int dim>
353void
355{
356 // Our support points are quadrature points on faces and inside the
357 // cell. First on the faces, we have to test polynomials of degree
358 // up to deg, which means we need dg+1 points in each direction. The
359 // fact that we do not have tensor product polynomials will be
360 // considered later. In 2d, we can use point values.
361 const QGauss<dim - 1> face_points(deg + 1);
362
363 // TODO: the implementation makes the assumption that all faces have the
364 // same number of dofs
366 const unsigned int face_no = 0;
367
368 // Copy the quadrature formula to the face points.
369 this->generalized_face_support_points[face_no].resize(face_points.size());
370 for (unsigned int k = 0; k < face_points.size(); ++k)
371 this->generalized_face_support_points[face_no][k] = face_points.point(k);
372
373 // In the interior, we only test with polynomials of degree up to
374 // deg-2, thus we use deg points. Note that deg>=1 and the lowest
375 // order element has no points in the cell, such that we have to
376 // distinguish this case.
377 const QGauss<dim> cell_points(deg == 1 ? 0 : deg);
378
379 // Compute the size of the whole support point set
380 const unsigned int npoints =
381 GeometryInfo<dim>::faces_per_cell * face_points.size() + cell_points.size();
382
383 this->generalized_support_points.resize(npoints);
384
385 const Quadrature<dim> faces =
387
388 for (unsigned int face_no = 0; face_no < GeometryInfo<dim>::faces_per_cell;
389 ++face_no)
390 {
392 this->reference_cell(),
393 face_no,
395 face_points.size());
396 for (unsigned int face_point = 0; face_point < face_points.size();
397 ++face_point)
398 this->generalized_support_points[face_points.size() * face_no +
399 face_point] =
400 faces.point(offset + face_point);
401 }
402
403 // Currently, for backward compatibility, we do not use moments, but
404 // point values on faces in 2d. In 3d, this is impossible, since the
405 // moments are only taken with respect to PolynomialsP.
406 if (dim > 2)
407 internal::FE_BDM::initialize_test_values(test_values_face,
408 face_points,
409 deg);
410
411 if (deg <= 1)
412 return;
413
414 // Remember where interior points start
415 const unsigned int ibase =
416 face_points.size() * GeometryInfo<dim>::faces_per_cell;
417 for (unsigned int k = 0; k < cell_points.size(); ++k)
418 {
419 this->generalized_support_points[ibase + k] = cell_points.point(k);
420 }
421 // Finally, compute the values of
422 // the test functions in the
423 // interior quadrature points
424
425 internal::FE_BDM::initialize_test_values(test_values_cell,
426 cell_points,
427 deg - 2);
428}
429
430
431
432/*-------------- Explicit Instantiations -------------------------------*/
433#include "fe/fe_bdm.inst"
434
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
std::vector< std::vector< double > > test_values_face
Definition fe_bdm.h:111
void initialize_support_points(const unsigned int bdm_degree)
Definition fe_bdm.cc:354
FE_BDM(const unsigned int p)
Definition fe_bdm.cc:41
std::vector< std::vector< double > > test_values_cell
Definition fe_bdm.h:117
static std::vector< bool > get_ria_vector(const unsigned int degree)
Definition fe_bdm.cc:267
virtual std::unique_ptr< FiniteElement< dim, dim > > clone() const override
Definition fe_bdm.cc:148
virtual void convert_generalized_support_point_values_to_dof_values(const std::vector< Vector< double > > &support_point_values, std::vector< double > &nodal_values) const override
Definition fe_bdm.cc:157
void initialize_quad_dof_index_permutation_and_sign_change()
Definition fe_bdm.cc:113
virtual std::string get_name() const override
Definition fe_bdm.cc:126
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
Definition fe_bdm.cc:243
FullMatrix< double > inverse_node_matrix
std::vector< MappingKind > mapping_kind
FE_PolyTensor(const TensorPolynomialsBase< dim > &polynomials, const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_cell() const
const unsigned int dofs_per_face
Definition fe_data.h:420
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_unique_faces() const
const unsigned int dofs_per_cell
Definition fe_data.h:434
FiniteElementData(const std::vector< unsigned int > &dofs_per_object, const unsigned int n_components, const unsigned int degree, const Conformity conformity=unknown, const BlockIndices &block_indices=BlockIndices())
Definition fe_data.cc:112
ReferenceCell< dim > reference_cell() const
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
std::vector< std::vector< Point< dim - 1 > > > generalized_face_support_points
Definition fe.h:2604
FullMatrix< double > interface_constraints
Definition fe.h:2573
std::vector< Point< dim > > generalized_support_points
Definition fe.h:2598
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition fe.h:2561
size_type n() const
size_type m() const
static unsigned int n_polynomials(const unsigned int n)
void evaluate(const Point< dim > &unit_point, std::vector< double > &values, std::vector< Tensor< 1, dim > > &grads, std::vector< Tensor< 2, dim > > &grad_grads, std::vector< Tensor< 3, dim > > &third_derivatives, std::vector< Tensor< 4, dim > > &fourth_derivatives) const override
static unsigned int n_polynomials(const unsigned int degree)
static DataSetDescriptor face(const ReferenceCell< dim > &reference_cell, const unsigned int face_no, const bool face_orientation, const bool face_flip, const bool face_rotation, const unsigned int n_quadrature_points)
static Quadrature< dim > project_to_all_faces(const ReferenceCell< dim > &reference_cell, const hp::QCollection< dim - 1 > &quadrature)
const Point< dim > & point(const unsigned int i) const
double weight(const unsigned int i) const
unsigned int size() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
@ mapping_bdm
Definition mapping.h:139
void compute_embedding_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false, const double threshold=1.e-12)
void compute_face_embedding_matrices(const FiniteElement< dim, spacedim > &fe, const ArrayView< FullMatrix< number > > &matrices, const unsigned int face_coarse, const unsigned int face_fine, const double threshold=1.e-12)
FullMatrix< double > compute_node_matrix(const FiniteElement< dim, spacedim > &fe)
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:350
STL namespace.
static constexpr unsigned int max_children_per_face
static constexpr unsigned int faces_per_cell
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()
static constexpr std::array< unsigned int, faces_per_cell > unit_normal_direction