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_face.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) 2009 - 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
15
16#include <deal.II/fe/fe_face.h>
18#include <deal.II/fe/fe_poly_face.templates.h>
19#include <deal.II/fe/fe_tools.h>
20
22
23#include <memory>
24#include <sstream>
25
27
28
29namespace internal
30{
31 namespace FE_FaceQImplementation
32 {
33 namespace
34 {
35 std::vector<Point<1>>
36 get_QGaussLobatto_points(const unsigned int degree)
37 {
38 if (degree > 0)
39 return QGaussLobatto<1>(degree + 1).get_points();
40 else
41 return std::vector<Point<1>>(1, Point<1>(0.5));
42 }
43 } // namespace
44 } // namespace FE_FaceQImplementation
45} // namespace internal
46
47template <int dim, int spacedim>
48FE_FaceQ<dim, spacedim>::FE_FaceQ(const unsigned int degree)
49 : FE_PolyFace<TensorProductPolynomials<dim - 1>, dim, spacedim>(
51 Polynomials::generate_complete_Lagrange_basis(
52 internal::FE_FaceQImplementation::get_QGaussLobatto_points(degree))),
53 FiniteElementData<dim>(get_dpo_vector(degree),
54 1,
55 degree,
56 FiniteElementData<dim>::L2),
57 std::vector<bool>(1, true))
58{
59 // initialize unit face support points
60 const unsigned int codim = dim - 1;
61 this->unit_face_support_points[0].resize(
62 Utilities::fixed_power<codim>(this->degree + 1));
63
64 if (this->degree == 0)
65 for (unsigned int d = 0; d < codim; ++d)
66 this->unit_face_support_points[0][0][d] = 0.5;
67 else
68 {
69 std::vector<Point<1>> points =
70 internal::FE_FaceQImplementation::get_QGaussLobatto_points(degree);
71
72 unsigned int k = 0;
73 for (unsigned int iz = 0; iz <= ((codim > 2) ? this->degree : 0); ++iz)
74 for (unsigned int iy = 0; iy <= ((codim > 1) ? this->degree : 0); ++iy)
75 for (unsigned int ix = 0; ix <= this->degree; ++ix)
76 {
78
79 p[0] = points[ix][0];
80 if (codim > 1)
81 p[1] = points[iy][0];
82 if (codim > 2)
83 p[2] = points[iz][0];
84
85 this->unit_face_support_points[0][k++] = p;
86 }
88 }
89
90 // initialize unit support points (this makes it possible to assign initial
91 // values to FE_FaceQ)
94 const unsigned int n_face_dofs = this->unit_face_support_points[0].size();
95 for (unsigned int i = 0; i < n_face_dofs; ++i)
96 for (unsigned int d = 0; d < dim; ++d)
97 {
98 for (unsigned int e = 0, c = 0; e < dim; ++e)
99 if (d != e)
100 {
101 // faces in y-direction are oriented differently
102 unsigned int renumber = i;
103 if (dim == 3 && d == 1)
104 renumber = i / (degree + 1) + (degree + 1) * (i % (degree + 1));
105 this->unit_support_points[n_face_dofs * 2 * d + i][e] =
106 this->unit_face_support_points[0][renumber][c];
107 this->unit_support_points[n_face_dofs * (2 * d + 1) + i][e] =
108 this->unit_face_support_points[0][renumber][c];
109 this->unit_support_points[n_face_dofs * (2 * d + 1) + i][d] = 1;
110 ++c;
111 }
112 }
113}
114
115
116
117template <int dim, int spacedim>
118std::unique_ptr<FiniteElement<dim, spacedim>>
120{
121 return std::make_unique<FE_FaceQ<dim, spacedim>>(this->degree);
122}
123
124
125
126template <int dim, int spacedim>
127std::string
129{
130 // note that the FETools::get_fe_by_name function depends on the
131 // particular format of the string this function returns, so they have to be
132 // kept in synch
133 std::ostringstream namebuf;
134 namebuf << "FE_FaceQ<" << Utilities::dim_string(dim, spacedim) << ">("
135 << this->degree << ")";
136
137 return namebuf.str();
138}
139
140
141
142template <int dim, int spacedim>
143void
145 const FiniteElement<dim, spacedim> &source_fe,
146 FullMatrix<double> &interpolation_matrix,
147 const unsigned int face_no) const
148{
149 get_subface_interpolation_matrix(source_fe,
151 interpolation_matrix,
152 face_no);
153}
154
155
156
157template <int dim, int spacedim>
158void
160 const FiniteElement<dim, spacedim> &x_source_fe,
161 const unsigned int subface,
162 FullMatrix<double> &interpolation_matrix,
163 const unsigned int face_no) const
164{
165 // this function is similar to the respective method in FE_Q
166
167 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
168 ExcDimensionMismatch(interpolation_matrix.n(),
169 this->n_dofs_per_face(face_no)));
170 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
171 ExcDimensionMismatch(interpolation_matrix.m(),
172 x_source_fe.n_dofs_per_face(face_no)));
173
174 // see if source is a FaceQ element
175 if (const FE_FaceQ<dim, spacedim> *source_fe =
176 dynamic_cast<const FE_FaceQ<dim, spacedim> *>(&x_source_fe))
177 {
178 // Make sure that the element for which the DoFs should be constrained
179 // is the one with the higher polynomial degree. Actually the procedure
180 // will work also if this assertion is not satisfied. But the matrices
181 // produced in that case might lead to problems in the hp-procedures,
182 // which use this method.
183 Assert(
184 this->n_dofs_per_face(face_no) <= source_fe->n_dofs_per_face(face_no),
185 (typename FiniteElement<dim,
186 spacedim>::ExcInterpolationNotImplemented()));
187
188 // generate a quadrature with the unit face support points.
189 const Quadrature<dim - 1> face_quadrature(
190 source_fe->get_unit_face_support_points(face_no));
191
192 // Rule of thumb for FP accuracy, that can be expected for a given
193 // polynomial degree. This value is used to cut off values close to
194 // zero.
195 const double eps = 2e-13 * (this->degree + 1) * (dim - 1);
196
197 // compute the interpolation matrix by simply taking the value at the
198 // support points.
199 for (unsigned int i = 0; i < source_fe->n_dofs_per_face(face_no); ++i)
200 {
201 const Point<dim - 1> p =
203 face_quadrature.point(i) :
205 face_quadrature.point(i), subface);
206
207 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
208 {
209 double matrix_entry = this->poly_space.compute_value(j, p);
210
211 // Correct the interpolated value. I.e. if it is close to 1 or 0,
212 // make it exactly 1 or 0. Unfortunately, this is required to
213 // avoid problems with higher order elements.
214 if (std::fabs(matrix_entry - 1.0) < eps)
215 matrix_entry = 1.0;
216 if (std::fabs(matrix_entry) < eps)
217 matrix_entry = 0.0;
218
219 interpolation_matrix(i, j) = matrix_entry;
220 }
221 }
222
223 if constexpr (running_in_debug_mode())
224 {
225 // make sure that the row sum of each of the matrices is 1 at this
226 // point. this must be so since the shape functions sum up to 1
227 for (unsigned int j = 0; j < source_fe->n_dofs_per_face(face_no); ++j)
228 {
229 double sum = 0.;
230
231 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
232 sum += interpolation_matrix(j, i);
233
234 Assert(std::fabs(sum - 1) < eps, ExcInternalError());
235 }
236 }
237 }
238 else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != nullptr)
239 {
240 // nothing to do here, the FE_Nothing has no degrees of freedom anyway
241 }
242 else
244 false,
245 (typename FiniteElement<dim,
246 spacedim>::ExcInterpolationNotImplemented()));
247}
248
249
250
251template <int dim, int spacedim>
252bool
254 const unsigned int shape_index,
255 const unsigned int face_index) const
256{
257 return (face_index == (shape_index / this->n_dofs_per_face(face_index)));
258}
259
260
261
262template <int dim, int spacedim>
263std::vector<unsigned int>
265{
266 std::vector<unsigned int> dpo(dim + 1, 0U);
267 dpo[dim - 1] = deg + 1;
268 for (unsigned int i = 1; i < dim - 1; ++i)
269 dpo[dim - 1] *= deg + 1;
270 return dpo;
271}
272
273
274
275template <int dim, int spacedim>
276bool
281
282
283
284template <int dim, int spacedim>
285std::vector<std::pair<unsigned int, unsigned int>>
287 const FiniteElement<dim, spacedim> & /*fe_other*/) const
288{
289 // this element is always discontinuous at vertices
290 return std::vector<std::pair<unsigned int, unsigned int>>();
291}
292
293
294
295template <int dim, int spacedim>
296std::vector<std::pair<unsigned int, unsigned int>>
298 const FiniteElement<dim, spacedim> &fe_other) const
299{
300 Assert(dim >= 2, ExcInternalError());
301
302 // this element is continuous only for the highest dimensional bounding object
303 if (dim > 2)
304 return std::vector<std::pair<unsigned int, unsigned int>>();
305 else
306 {
307 // this is similar to the FE_Q_Base class
308 if (const FE_FaceQ<dim, spacedim> *fe_q_other =
309 dynamic_cast<const FE_FaceQ<dim, spacedim> *>(&fe_other))
310 {
311 // dofs are located along lines, so two dofs are identical if they are
312 // located at identical positions.
313 // Therefore, read the points in unit_support_points for the
314 // first coordinate direction. We take the lexicographic ordering of
315 // the points in the second direction (i.e., y-direction) since we
316 // know that the first p+1 dofs are located at the left (x=0) face.
317 const unsigned int p = this->degree;
318 const unsigned int q = fe_q_other->degree;
319
320 std::vector<std::pair<unsigned int, unsigned int>> identities;
321
322 const std::vector<unsigned int> &index_map_inverse =
323 this->poly_space.get_numbering_inverse();
324 const std::vector<unsigned int> &index_map_inverse_other =
325 fe_q_other->poly_space.get_numbering_inverse();
326
327 for (unsigned int i = 0; i < p + 1; ++i)
328 for (unsigned int j = 0; j < q + 1; ++j)
329 if (std::fabs(
330 this->unit_support_points[index_map_inverse[i]][dim - 1] -
331 fe_q_other->unit_support_points[index_map_inverse_other[j]]
332 [dim - 1]) < 1e-14)
333 identities.emplace_back(i, j);
334
335 return identities;
336 }
337 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
338 {
339 // the FE_Nothing has no degrees of freedom, so there are no
340 // equivalencies to be recorded
341 return std::vector<std::pair<unsigned int, unsigned int>>();
342 }
343 else if (fe_other.n_unique_faces() == 1 &&
344 fe_other.n_dofs_per_face(0) == 0)
345 {
346 // if the other element has no elements on faces at all,
347 // then it would be impossible to enforce any kind of
348 // continuity even if we knew exactly what kind of element
349 // we have -- simply because the other element declares
350 // that it is discontinuous because it has no DoFs on
351 // its faces. in that case, just state that we have no
352 // constraints to declare
353 return std::vector<std::pair<unsigned int, unsigned int>>();
354 }
355 else
356 {
358 return std::vector<std::pair<unsigned int, unsigned int>>();
359 }
360 }
361}
362
363
364
365template <int dim, int spacedim>
366std::vector<std::pair<unsigned int, unsigned int>>
368 const FiniteElement<dim, spacedim> &fe_other,
369 const unsigned int) const
370{
371 Assert(dim >= 3, ExcInternalError());
372
373 // this element is continuous only for the highest dimensional bounding object
374 if (dim > 3)
375 return std::vector<std::pair<unsigned int, unsigned int>>();
376 else
377 {
378 // this is similar to the FE_Q_Base class
379 if (const FE_FaceQ<dim, spacedim> *fe_q_other =
380 dynamic_cast<const FE_FaceQ<dim, spacedim> *>(&fe_other))
381 {
382 // this works exactly like the line case above, except that now we
383 // have to have two indices i1, i2 and j1, j2 to characterize the dofs
384 // on the face of each of the finite elements. since they are ordered
385 // lexicographically along the first line and we have a tensor
386 // product, the rest is rather straightforward
387 const unsigned int p = this->degree;
388 const unsigned int q = fe_q_other->degree;
389
390 std::vector<std::pair<unsigned int, unsigned int>> identities;
391
392 const std::vector<unsigned int> &index_map_inverse =
393 this->poly_space.get_numbering_inverse();
394 const std::vector<unsigned int> &index_map_inverse_other =
395 fe_q_other->poly_space.get_numbering_inverse();
396
397 std::vector<std::pair<unsigned int, unsigned int>> identities_1d;
398
399 for (unsigned int i = 0; i < p + 1; ++i)
400 for (unsigned int j = 0; j < q + 1; ++j)
401 if (std::fabs(
402 this->unit_support_points[index_map_inverse[i]][dim - 2] -
403 fe_q_other->unit_support_points[index_map_inverse_other[j]]
404 [dim - 2]) < 1e-14)
405 identities_1d.emplace_back(i, j);
406
407 for (unsigned int n1 = 0; n1 < identities_1d.size(); ++n1)
408 for (unsigned int n2 = 0; n2 < identities_1d.size(); ++n2)
409 identities.emplace_back(identities_1d[n1].first * (p + 1) +
410 identities_1d[n2].first,
411 identities_1d[n1].second * (q + 1) +
412 identities_1d[n2].second);
413
414 return identities;
415 }
416 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
417 {
418 // the FE_Nothing has no degrees of freedom, so there are no
419 // equivalencies to be recorded
420 return std::vector<std::pair<unsigned int, unsigned int>>();
421 }
422 else if (fe_other.n_unique_faces() == 1 &&
423 fe_other.n_dofs_per_face(0) == 0)
424 {
425 // if the other element has no elements on faces at all,
426 // then it would be impossible to enforce any kind of
427 // continuity even if we knew exactly what kind of element
428 // we have -- simply because the other element declares
429 // that it is discontinuous because it has no DoFs on
430 // its faces. in that case, just state that we have no
431 // constraints to declare
432 return std::vector<std::pair<unsigned int, unsigned int>>();
433 }
434 else
435 {
437 return std::vector<std::pair<unsigned int, unsigned int>>();
438 }
439 }
440}
441
442
443
444template <int dim, int spacedim>
447 const FiniteElement<dim, spacedim> &fe_other,
448 const unsigned int codim) const
449{
450 Assert(codim <= dim, ExcImpossibleInDim(dim));
451
452 // vertex/line/face/cell domination
453 // --------------------------------
454 if (const FE_FaceQ<dim, spacedim> *fe_faceq_other =
455 dynamic_cast<const FE_FaceQ<dim, spacedim> *>(&fe_other))
456 {
457 if (this->degree < fe_faceq_other->degree)
459 else if (this->degree == fe_faceq_other->degree)
461 else
463 }
464 else if (const FE_Nothing<dim> *fe_nothing =
465 dynamic_cast<const FE_Nothing<dim> *>(&fe_other))
466 {
467 if (fe_nothing->is_dominating())
469 else
470 // the FE_Nothing has no degrees of freedom and it is typically used
471 // in a context where we don't require any continuity along the
472 // interface
474 }
475
478}
479
480template <int dim, int spacedim>
481std::pair<Table<2, bool>, std::vector<unsigned int>>
483{
484 Table<2, bool> constant_modes(1, this->n_dofs_per_cell());
485 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
486 constant_modes(0, i) = true;
487 return std::pair<Table<2, bool>, std::vector<unsigned int>>(
488 constant_modes, std::vector<unsigned int>(1, 0));
489}
490
491template <int dim, int spacedim>
492void
494 const std::vector<Vector<double>> &support_point_values,
495 std::vector<double> &nodal_values) const
496{
497 AssertDimension(support_point_values.size(),
498 this->get_unit_support_points().size());
499 AssertDimension(support_point_values.size(), nodal_values.size());
500 AssertDimension(this->n_dofs_per_cell(), nodal_values.size());
501
502 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
503 {
504 AssertDimension(support_point_values[i].size(), 1);
505
506 nodal_values[i] = support_point_values[i](0);
507 }
508}
509
510// ----------------------------- FE_FaceQ<1,spacedim> ------------------------
511
512template <int spacedim>
513FE_FaceQ<1, spacedim>::FE_FaceQ(const unsigned int degree)
514 : FiniteElement<1, spacedim>(
515 FiniteElementData<1>(get_dpo_vector(degree),
516 1,
517 degree,
518 FiniteElementData<1>::L2),
519 std::vector<bool>(1, true),
520 std::vector<ComponentMask>(1, ComponentMask(1, true)))
521{
522 this->unit_face_support_points[0].resize(1);
523
524 // initialize unit support points (this makes it possible to assign initial
525 // values to FE_FaceQ)
527 this->unit_support_points[1] = Point<1>(1.);
528}
529
530
531
532template <int spacedim>
533std::unique_ptr<FiniteElement<1, spacedim>>
535{
536 return std::make_unique<FE_FaceQ<1, spacedim>>(this->degree);
537}
538
539
540
541template <int spacedim>
542std::string
544{
545 // note that the FETools::get_fe_by_name function depends on the
546 // particular format of the string this function returns, so they have to be
547 // kept in synch
548 std::ostringstream namebuf;
549 namebuf << "FE_FaceQ<" << Utilities::dim_string(1, spacedim) << ">("
550 << this->degree << ")";
551
552 return namebuf.str();
553}
554
555
556
557template <int spacedim>
558void
560 const FiniteElement<1, spacedim> &source_fe,
561 FullMatrix<double> &interpolation_matrix,
562 const unsigned int face_no) const
563{
564 get_subface_interpolation_matrix(source_fe,
566 interpolation_matrix,
567 face_no);
568}
569
570
571
572template <int spacedim>
573void
575 const FiniteElement<1, spacedim> &x_source_fe,
576 const unsigned int /*subface*/,
577 FullMatrix<double> &interpolation_matrix,
578 const unsigned int face_no) const
579{
580 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
581 ExcDimensionMismatch(interpolation_matrix.n(),
582 this->n_dofs_per_face(face_no)));
583 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
584 ExcDimensionMismatch(interpolation_matrix.m(),
585 x_source_fe.n_dofs_per_face(face_no)));
586 interpolation_matrix(0, 0) = 1.;
587}
588
589
590
591template <int spacedim>
592bool
593FE_FaceQ<1, spacedim>::has_support_on_face(const unsigned int shape_index,
594 const unsigned int face_index) const
595{
596 AssertIndexRange(shape_index, 2);
597 return (face_index == shape_index);
598}
599
600
601
602template <int spacedim>
603std::vector<unsigned int>
605{
606 std::vector<unsigned int> dpo(2, 0U);
607 dpo[0] = 1;
608 return dpo;
609}
610
611
612
613template <int spacedim>
614bool
619
620template <int spacedim>
621std::vector<std::pair<unsigned int, unsigned int>>
623 const FiniteElement<1, spacedim> & /*fe_other*/) const
624{
625 // this element is always discontinuous at vertices
626 return std::vector<std::pair<unsigned int, unsigned int>>(1,
627 std::make_pair(0U,
628 0U));
629}
630
631
632
633template <int spacedim>
634std::vector<std::pair<unsigned int, unsigned int>>
636 const FiniteElement<1, spacedim> &) const
637{
638 // this element is continuous only for the highest dimensional bounding object
639 return std::vector<std::pair<unsigned int, unsigned int>>();
640}
641
642
643
644template <int spacedim>
645std::vector<std::pair<unsigned int, unsigned int>>
648 const unsigned int) const
649{
650 // this element is continuous only for the highest dimensional bounding object
651 return std::vector<std::pair<unsigned int, unsigned int>>();
652}
653
654
655
656template <int spacedim>
657std::pair<Table<2, bool>, std::vector<unsigned int>>
659{
660 Table<2, bool> constant_modes(1, this->n_dofs_per_cell());
661 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
662 constant_modes(0, i) = true;
663 return std::pair<Table<2, bool>, std::vector<unsigned int>>(
664 constant_modes, std::vector<unsigned int>(1, 0));
665}
666
667
668
669template <int spacedim>
683
684
685template <int spacedim>
686void
690 const Quadrature<1> &,
691 const Mapping<1, spacedim> &,
696 spacedim>
697 &) const
698{
699 // Do nothing, since we do not have values in the interior
700}
701
702
703
704template <int spacedim>
705void
708 const unsigned int face,
709 const hp::QCollection<0> &,
710 const Mapping<1, spacedim> &,
713 const typename FiniteElement<1, spacedim>::InternalDataBase &fe_internal,
715 spacedim>
716 &output_data) const
717{
718 const unsigned int foffset = face;
719 if (fe_internal.update_each & update_values)
720 {
721 for (unsigned int k = 0; k < this->n_dofs_per_cell(); ++k)
722 output_data.shape_values(k, 0) = 0.;
723 output_data.shape_values(foffset, 0) = 1;
724 }
725}
726
727
728template <int spacedim>
729void
732 const unsigned int,
733 const unsigned int,
734 const Quadrature<0> &,
735 const Mapping<1, spacedim> &,
740 spacedim>
741 &) const
742{
743 Assert(false, ExcMessage("There are no sub-face values to fill in 1d!"));
744}
745
746
747
748// --------------------------------------- FE_FaceP --------------------------
749
750template <int dim, int spacedim>
751FE_FaceP<dim, spacedim>::FE_FaceP(const unsigned int degree)
752 : FE_PolyFace<PolynomialSpace<dim - 1>, dim, spacedim>(
753 PolynomialSpace<dim - 1>(
754 Polynomials::Legendre::generate_complete_basis(degree)),
755 FiniteElementData<dim>(get_dpo_vector(degree),
756 1,
757 degree,
758 FiniteElementData<dim>::L2),
759 std::vector<bool>(1, true))
760{}
761
762
763
764template <int dim, int spacedim>
765std::unique_ptr<FiniteElement<dim, spacedim>>
767{
768 return std::make_unique<FE_FaceP<dim, spacedim>>(this->degree);
769}
770
771
772
773template <int dim, int spacedim>
774std::string
776{
777 // note that the FETools::get_fe_by_name function depends on the
778 // particular format of the string this function returns, so they have to be
779 // kept in synch
780 std::ostringstream namebuf;
781 namebuf << "FE_FaceP<" << Utilities::dim_string(dim, spacedim) << ">("
782 << this->degree << ")";
783
784 return namebuf.str();
785}
786
787
788
789template <int dim, int spacedim>
790bool
792 const unsigned int shape_index,
793 const unsigned int face_index) const
794{
795 return (face_index == (shape_index / this->n_dofs_per_face(face_index)));
796}
797
798
799
800template <int dim, int spacedim>
801std::vector<unsigned int>
803{
804 std::vector<unsigned int> dpo(dim + 1, 0U);
805 dpo[dim - 1] = deg + 1;
806 for (unsigned int i = 1; i < dim - 1; ++i)
807 {
808 dpo[dim - 1] *= deg + 1 + i;
809 dpo[dim - 1] /= i + 1;
810 }
811 return dpo;
812}
813
814
815
816template <int dim, int spacedim>
817bool
822
823
824
825template <int dim, int spacedim>
828 const FiniteElement<dim, spacedim> &fe_other,
829 const unsigned int codim) const
830{
831 Assert(codim <= dim, ExcImpossibleInDim(dim));
832
833 // vertex/line/face/cell domination
834 // --------------------------------
835 if (const FE_FaceP<dim, spacedim> *fe_facep_other =
836 dynamic_cast<const FE_FaceP<dim, spacedim> *>(&fe_other))
837 {
838 if (this->degree < fe_facep_other->degree)
840 else if (this->degree == fe_facep_other->degree)
842 else
844 }
845 else if (const FE_Nothing<dim> *fe_nothing =
846 dynamic_cast<const FE_Nothing<dim> *>(&fe_other))
847 {
848 if (fe_nothing->is_dominating())
850 else
851 // the FE_Nothing has no degrees of freedom and it is typically used
852 // in a context where we don't require any continuity along the
853 // interface
855 }
856
859}
860
861
862
863template <int dim, int spacedim>
864void
866 const FiniteElement<dim, spacedim> &source_fe,
867 FullMatrix<double> &interpolation_matrix,
868 const unsigned int face_no) const
869{
870 get_subface_interpolation_matrix(source_fe,
872 interpolation_matrix,
873 face_no);
874}
875
876
877
878template <int dim, int spacedim>
879void
881 const FiniteElement<dim, spacedim> &x_source_fe,
882 const unsigned int subface,
883 FullMatrix<double> &interpolation_matrix,
884 const unsigned int face_no) const
885{
886 // this function is similar to the respective method in FE_Q
887
888 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
889 ExcDimensionMismatch(interpolation_matrix.n(),
890 this->n_dofs_per_face(face_no)));
891 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
892 ExcDimensionMismatch(interpolation_matrix.m(),
893 x_source_fe.n_dofs_per_face(face_no)));
894
895 // see if source is a FaceP element
896 if (const FE_FaceP<dim, spacedim> *source_fe =
897 dynamic_cast<const FE_FaceP<dim, spacedim> *>(&x_source_fe))
898 {
899 // Make sure that the element for which the DoFs should be constrained
900 // is the one with the higher polynomial degree. Actually the procedure
901 // will work also if this assertion is not satisfied. But the matrices
902 // produced in that case might lead to problems in the hp-procedures,
903 // which use this method.
904 Assert(
905 this->n_dofs_per_face(face_no) <= source_fe->n_dofs_per_face(face_no),
906 (typename FiniteElement<dim,
907 spacedim>::ExcInterpolationNotImplemented()));
908
909 // do this as in FETools by solving a least squares problem where we
910 // force the source FE polynomial to be equal the given FE on all
911 // quadrature points
912 const QGauss<dim - 1> face_quadrature(source_fe->degree + 1);
913
914 // Rule of thumb for FP accuracy, that can be expected for a given
915 // polynomial degree. This value is used to cut off values close to
916 // zero.
917 const double eps = 2e-13 * (this->degree + 1) * (dim - 1);
918
919 FullMatrix<double> mass(face_quadrature.size(),
920 source_fe->n_dofs_per_face(face_no));
921
922 for (unsigned int k = 0; k < face_quadrature.size(); ++k)
923 {
924 const Point<dim - 1> p =
926 face_quadrature.point(k) :
928 face_quadrature.point(k), subface);
929
930 for (unsigned int j = 0; j < source_fe->n_dofs_per_face(face_no); ++j)
931 mass(k, j) = source_fe->poly_space.compute_value(j, p);
932 }
933
934 Householder<double> H(mass);
935 Vector<double> v_in(face_quadrature.size());
936 Vector<double> v_out(source_fe->n_dofs_per_face(face_no));
937
938
939 // compute the interpolation matrix by evaluating on the fine side and
940 // then solving the least squares problem
941 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
942 {
943 for (unsigned int k = 0; k < face_quadrature.size(); ++k)
944 {
945 const Point<dim - 1> p =
947 face_quadrature.point(k) :
949 face_quadrature.point(k), subface);
950 v_in(k) = this->poly_space.compute_value(i, p);
951 }
952 const double result = H.least_squares(v_out, v_in);
953 Assert(result < 1e-12, FETools::ExcLeastSquaresError(result));
954
955 for (unsigned int j = 0; j < source_fe->n_dofs_per_face(face_no); ++j)
956 {
957 double matrix_entry = v_out(j);
958
959 // Correct the interpolated value. I.e. if it is close to 1 or 0,
960 // make it exactly 1 or 0. Unfortunately, this is required to
961 // avoid problems with higher order elements.
962 if (std::fabs(matrix_entry - 1.0) < eps)
963 matrix_entry = 1.0;
964 if (std::fabs(matrix_entry) < eps)
965 matrix_entry = 0.0;
966
967 interpolation_matrix(j, i) = matrix_entry;
968 }
969 }
970 }
971 else if (dynamic_cast<const FE_Nothing<dim> *>(&x_source_fe) != nullptr)
972 {
973 // nothing to do here, the FE_Nothing has no degrees of freedom anyway
974 }
975 else
977 false,
978 (typename FiniteElement<dim,
979 spacedim>::ExcInterpolationNotImplemented()));
980}
981
982
983
984template <int dim, int spacedim>
985std::pair<Table<2, bool>, std::vector<unsigned int>>
987{
988 Table<2, bool> constant_modes(1, this->n_dofs_per_cell());
989 for (const unsigned int face : GeometryInfo<dim>::face_indices())
990 constant_modes(0, face * this->n_dofs_per_face(face)) = true;
991 return std::pair<Table<2, bool>, std::vector<unsigned int>>(
992 constant_modes, std::vector<unsigned int>(1, 0));
993}
994
995
996
997template <int spacedim>
998FE_FaceP<1, spacedim>::FE_FaceP(const unsigned int degree)
999 : FE_FaceQ<1, spacedim>(degree)
1000{}
1001
1002
1003
1004template <int spacedim>
1005std::string
1007{
1008 // note that the FETools::get_fe_by_name function depends on the
1009 // particular format of the string this function returns, so they have to be
1010 // kept in synch
1011 std::ostringstream namebuf;
1012 namebuf << "FE_FaceP<" << Utilities::dim_string(1, spacedim) << ">("
1013 << this->degree << ")";
1014
1015 return namebuf.str();
1016}
1017
1018
1019
1020// explicit instantiations
1021#include "fe/fe_face.inst"
1022
1023
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
Definition fe_face.cc:986
virtual bool hp_constraints_are_implemented() const override
Definition fe_face.cc:818
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const override
Definition fe_face.cc:791
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim=0) const override final
Definition fe_face.cc:827
virtual std::string get_name() const override
Definition fe_face.cc:775
static std::vector< unsigned int > get_dpo_vector(const unsigned int deg)
Definition fe_face.cc:802
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_face.cc:880
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
Definition fe_face.cc:766
FE_FaceP(unsigned int p)
Definition fe_face.cc:751
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
Definition fe_face.cc:865
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim=0) const override final
Definition fe_face.cc:446
virtual std::string get_name() const override
Definition fe_face.cc:128
static std::vector< unsigned int > get_dpo_vector(const unsigned int deg)
Definition fe_face.cc:264
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_face.cc:493
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
Definition fe_face.cc:482
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
Definition fe_face.cc:144
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition fe_face.cc:297
FE_FaceQ(const unsigned int p)
Definition fe_face.cc:48
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
Definition fe_face.cc:119
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_face.cc:159
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const override
Definition fe_face.cc:253
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
Definition fe_face.cc:286
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
Definition fe_face.cc:367
virtual bool hp_constraints_are_implemented() const override
Definition fe_face.cc:277
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_unique_faces() const
virtual void fill_fe_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const =0
std::vector< std::vector< Point< dim - 1 > > > unit_face_support_points
Definition fe.h:2592
virtual void fill_fe_face_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const hp::QCollection< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const
virtual void fill_fe_subface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int sub_no, const Quadrature< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const =0
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) const =0
std::vector< Point< dim > > unit_support_points
Definition fe.h:2585
size_type n() const
size_type m() const
number2 least_squares(Vector< number2 > &dst, const Vector< number2 > &src) const
Abstract base class for mapping classes.
Definition mapping.h:318
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()
Point< 2 > second
Definition grid_out.cc:4640
#define Assert(cond, exc)
static ::ExceptionBase & ExcLeastSquaresError(double arg1)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
UpdateFlags
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_normal_vectors
Normal vectors.
@ update_JxW_values
Transformed quadrature weights.
@ update_covariant_transformation
Covariant transformation.
@ update_gradients
Shape function gradients.
std::size_t size
Definition mpi.cc:733
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
STL namespace.
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()
static Point< dim > child_to_cell_coordinates(const Point< dim > &p, const unsigned int child_index, const RefinementCase< dim > refine_case=RefinementCase< dim >::isotropic_refinement)