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