deal.II version GIT relicensing-7058-gb35ee29762 2026-11-11 09:30:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_simplex_p.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) 2020 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#include <deal.II/base/config.h>
14
18#include <deal.II/base/types.h>
19
20#include <deal.II/fe/fe_dgq.h>
23#include <deal.II/fe/fe_q.h>
25#include <deal.II/fe/fe_tools.h>
27#include <deal.II/fe/mapping.h>
28
31
33
34namespace
35{
40 std::vector<unsigned int>
41 get_dpo_vector_fe_p(const unsigned int dim, const unsigned int degree)
42 {
43 Assert(degree != 0, ExcNotImplemented());
44
45 switch (dim)
46 {
47 case 1:
48 return {1, degree - 1};
49 case 2:
50 // the number of support points on the face is
51 // \sum_{i=1}^{degree - 2} i = (degree-2)*(degree-1)/2
52 return {1, degree - 1, (degree - 2) * (degree - 1) / 2};
53 case 3:
54 // the number of support points in the volume are that of a tet
55 // with a lower degree (degree-4)
56 return {1,
57 degree - 1,
58 (degree - 2) * (degree - 1) / 2,
59 (degree - 3) * (degree - 2) * (degree - 1) / 6};
60 }
61
63 return {};
64 }
65
66
67
72 template <int dim>
73 std::vector<Point<dim>>
74 unit_support_points_fe_p(const unsigned int degree)
75 {
76 Assert(dim != 0, ExcInternalError());
77 std::vector<Point<dim>> unit_points;
78 const auto reference_cell = ReferenceCells::get_simplex<dim>();
79
80 // Piecewise constants are a special case: use a support point at the
81 // centroid and only the centroid
82 if (degree == 0)
83 {
84 unit_points.emplace_back(reference_cell.barycenter());
85 return unit_points;
86 }
87
88 // otherwise write everything as linear combinations of vertices
89 const auto dpo = get_dpo_vector_fe_p(dim, degree);
90 Assert(dpo.size() == dim + 1, ExcInternalError());
91 Assert(dpo[0] == 1, ExcNotImplemented());
93 // vertices:
94 for (const unsigned int d : reference_cell.vertex_indices())
95 unit_points.push_back(reference_cell.vertex(d));
96
97 // lines:
98 for (const unsigned int l : reference_cell.line_indices())
99 {
100 const Point<dim> p0 =
101 unit_points[reference_cell.line_to_cell_vertices(l, 0)];
102 const Point<dim> p1 =
103 unit_points[reference_cell.line_to_cell_vertices(l, 1)];
104 for (unsigned int p = 0; p < dpo[1]; ++p)
105 unit_points.push_back((double(dpo[1] - p) / (dpo[1] + 1)) * p0 +
106 (double(p + 1) / (dpo[1] + 1)) * p1);
107 }
108
109 // faces:
110 if constexpr (dim == 2)
111 {
112 unsigned int counter = 0;
113 for (unsigned int i = 1; i < degree; ++i)
114 for (unsigned int j = 1; j < degree - i; ++j, ++counter)
115 {
116 const double x = static_cast<double>(j) / degree;
117 const double y = static_cast<double>(i) / degree;
118
119 unit_points.push_back(Point<dim>(x, y));
120 }
121 Assert(counter == dpo[2], ExcInternalError());
122 }
123
124 if constexpr (dim == 3)
125 for (const unsigned int f : reference_cell.face_indices())
126 {
127 const Point<dim> p0 =
128 unit_points[reference_cell.face_to_cell_vertices(
130 const Point<dim> p1 =
131 unit_points[reference_cell.face_to_cell_vertices(
133 const Point<dim> p2 =
134 unit_points[reference_cell.face_to_cell_vertices(
136
137 unsigned int counter = 0;
138 for (unsigned int i = 1; i < degree; ++i)
139 for (unsigned int j = 1; j < degree - i; ++j, ++counter)
140 {
141 const double a = static_cast<double>(j) / degree;
142 const double b = static_cast<double>(i) / degree;
143 const double c = 1.0 - a - b;
144 unit_points.push_back(c * p0 + a * p1 + b * p2);
145 }
146 Assert(counter == dpo[2], ExcInternalError());
147 }
148
149 // interior
150 if constexpr (dim == 3)
151 {
152 unsigned int counter = 0;
153 for (unsigned int i = 1; i < degree; ++i)
154 for (unsigned int j = 1; j < degree - i; ++j)
155 for (unsigned int k = 1; k < degree - i - j; ++k, ++counter)
156 {
157 const double x = static_cast<double>(i) / degree;
158 const double y = static_cast<double>(j) / degree;
159 const double z = static_cast<double>(k) / degree;
160
161 unit_points.push_back(Point<dim>(x, y, z));
162 }
163 Assert(counter == dpo[3], ExcInternalError());
164 }
165
166 return unit_points;
167 }
168
169 template <>
170 std::vector<Point<0>>
171 unit_support_points_fe_p(const unsigned int /*degree*/)
172 {
173 return {Point<0>()};
174 }
175
180 template <int dim>
181 std::vector<std::vector<Point<dim - 1>>>
182 unit_face_support_points_fe_p(
183 const unsigned int degree,
184 typename FiniteElementData<dim>::Conformity conformity)
185 {
186 // Discontinuous elements don't have face support points
188 return {};
189
190 // this concept doesn't exist in 1d so just return an empty vector
191 if (dim == 1)
192 return {};
193
194 std::vector<std::vector<Point<dim - 1>>> unit_face_points;
195
196 // all faces have the same support points
197 for (auto face_n : ReferenceCells::get_simplex<dim>().face_indices())
198 {
199 (void)face_n;
200 unit_face_points.emplace_back(
201 unit_support_points_fe_p<dim - 1>(degree));
202 }
203
204 return unit_face_points;
205 }
206
212 template <int dim>
214 constraints_fe_p(const unsigned int /*degree*/)
215 {
216 // no constraints in 1d
217 // constraints in 3d not implemented yet
218 return FullMatrix<double>();
219 }
220
221 template <>
223 constraints_fe_p<2>(const unsigned int degree)
224 {
225 constexpr int dim = 2;
226
227 // the following implements the 2d case
228 // (the 3d case is not implemented yet)
229 //
230 // consult FE_Q_Base::Implementation::initialize_constraints()
231 // for more information
232
233 std::vector<Point<dim - 1>> constraint_points;
234 // midpoint
235 constraint_points.emplace_back(0.5);
236 // subface 0
237 for (unsigned int i = 1; i < degree; ++i)
238 constraint_points.push_back(
240 Point<dim - 1>(i / double(degree)), 0));
241 // subface 1
242 for (unsigned int i = 1; i < degree; ++i)
243 constraint_points.push_back(
245 Point<dim - 1>(i / double(degree)), 1));
246
247 // Now construct relation between destination (child) and source (mother)
248 // dofs.
249
250 const unsigned int n_dofs_constrained = constraint_points.size();
251 unsigned int n_dofs_per_face = degree + 1;
252 FullMatrix<double> interface_constraints(n_dofs_constrained,
253 n_dofs_per_face);
254
255 const auto poly = BarycentricPolynomials<dim - 1>::get_fe_p_basis(degree);
256
257 for (unsigned int i = 0; i < n_dofs_constrained; ++i)
258 for (unsigned int j = 0; j < n_dofs_per_face; ++j)
259 {
260 interface_constraints(i, j) =
261 poly.compute_value(j, constraint_points[i]);
262
263 // if the value is small up to round-off, then simply set it to zero
264 // to avoid unwanted fill-in of the constraint matrices (which would
265 // then increase the number of other DoFs a constrained DoF would
266 // couple to)
267 if (std::fabs(interface_constraints(i, j)) < 1e-13)
268 interface_constraints(i, j) = 0;
269 }
270 return interface_constraints;
271 }
272
273
274
279 std::vector<unsigned int>
280 get_dpo_vector_fe_dgp(const unsigned int dim, const unsigned int degree)
281 {
282 // First treat the case of piecewise constant elements:
283 if (degree == 0)
284 {
285 std::vector<unsigned int> dpo(dim + 1, 0U);
286 dpo[dim] = 1;
287 return dpo;
288 }
289 else
290 {
291 // This element has the same degrees of freedom as the continuous one,
292 // but they are all counted for the interior of the cell because
293 // it is continuous. Rather than hard-code how many DoFs the element
294 // has, we just get the numbers from the continuous case and add them
295 // up
296 const auto continuous_dpo = get_dpo_vector_fe_p(dim, degree);
297
298 switch (dim)
299 {
300 case 1:
301 return {0U,
302 ReferenceCells::Line.n_vertices() * continuous_dpo[0] +
303 continuous_dpo[dim]};
304
305 case 2:
306 return {0U,
307 0U,
309 continuous_dpo[0] +
310 ReferenceCells::Triangle.n_lines() * continuous_dpo[1] +
311 continuous_dpo[dim]};
312
313 case 3:
314 return {
315 0U,
316 0U,
317 0U,
318 ReferenceCells::Tetrahedron.n_vertices() * continuous_dpo[0] +
319 ReferenceCells::Tetrahedron.n_lines() * continuous_dpo[1] +
320 ReferenceCells::Tetrahedron.n_faces() * continuous_dpo[2] +
321 continuous_dpo[dim]};
322 }
323
325 return {};
326 }
327 }
328} // namespace
329
330
331
332template <int dim, int spacedim>
334 const BarycentricPolynomials<dim> polynomials,
335 const FiniteElementData<dim> &fe_data,
336 const bool prolongation_is_additive,
337 const std::vector<Point<dim>> &unit_support_points,
338 const std::vector<std::vector<Point<dim - 1>>> unit_face_support_points,
339 const FullMatrix<double> &interface_constraints)
340 : ::FE_Poly<dim, spacedim>(
341 polynomials,
342 fe_data,
343 std::vector<bool>(fe_data.dofs_per_cell, prolongation_is_additive),
344 std::vector<ComponentMask>(fe_data.dofs_per_cell,
345 ComponentMask(std::vector<bool>(1, true))))
346{
349 this->interface_constraints = interface_constraints;
350}
351
352
353
354template <int dim, int spacedim>
355std::pair<Table<2, bool>, std::vector<unsigned int>>
357{
358 Table<2, bool> constant_modes(1, this->n_dofs_per_cell());
359 constant_modes.fill(true);
360 return std::pair<Table<2, bool>, std::vector<unsigned int>>(
361 constant_modes, std::vector<unsigned int>(1, 0));
362}
363
364
365
366template <int dim, int spacedim>
367const FullMatrix<double> &
369 const unsigned int child,
370 const RefinementCase<dim> &refinement_case) const
371{
372 if (dim == 3)
373 Assert(RefinementCase<dim>(refinement_case) ==
375 static_cast<char>(IsotropicRefinementChoice::cut_tet_68)) ||
376 RefinementCase<dim>(refinement_case) ==
378 static_cast<char>(IsotropicRefinementChoice::cut_tet_57)) ||
379 RefinementCase<dim>(refinement_case) ==
381 static_cast<char>(IsotropicRefinementChoice::cut_tet_49)),
383 else
384 Assert(refinement_case ==
387 AssertDimension(dim, spacedim);
388
389 // initialization upon first request
390 if (this->prolongation[refinement_case - 1][child].n() == 0)
391 {
392 std::scoped_lock lock(prolongation_matrix_mutex);
393
394 // if matrix got updated while waiting for the lock
395 if (this->prolongation[refinement_case - 1][child].n() ==
396 this->n_dofs_per_cell())
397 return this->prolongation[refinement_case - 1][child];
398
399 // now do the work. need to get a non-const version of data in order to
400 // be able to modify them inside a const function
401 auto &this_nonconst = const_cast<FE_SimplexPoly<dim, spacedim> &>(*this);
402
403 if (dim == 2)
404 {
405 std::vector<std::vector<FullMatrix<double>>> isotropic_matrices(
407 isotropic_matrices.back().resize(
408 this->reference_cell().n_children(
409 RefinementCase<dim>(refinement_case)),
410 FullMatrix<double>(this->n_dofs_per_cell(),
411 this->n_dofs_per_cell()));
412
413 FETools::compute_embedding_matrices(*this, isotropic_matrices, true);
414
415 this_nonconst.prolongation[refinement_case - 1] =
416 std::move(isotropic_matrices.back());
417 }
418 else if (dim == 3)
419 {
420 std::vector<std::vector<FullMatrix<double>>> matrices(
421 static_cast<unsigned int>(IsotropicRefinementChoice::cut_tet_49),
422 std::vector<FullMatrix<double>>(
423 this->reference_cell().n_children(
424 RefinementCase<dim>(refinement_case)),
425 FullMatrix<double>(this->n_dofs_per_cell(),
426 this->n_dofs_per_cell())));
427 FETools::compute_embedding_matrices(*this, matrices, true);
428 for (unsigned int refinement_direction = static_cast<unsigned int>(
430 refinement_direction <=
431 static_cast<unsigned int>(IsotropicRefinementChoice::cut_tet_49);
432 refinement_direction++)
433 this_nonconst.prolongation[refinement_direction - 1] =
434 std::move(matrices[refinement_direction - 1]);
435 }
436 else
438 }
439
440 // finally return the matrix
441 return this->prolongation[refinement_case - 1][child];
442}
443
444
445
446template <int dim, int spacedim>
447bool
449 const unsigned int shape_index,
450 const unsigned int face_index) const
451{
452 AssertIndexRange(shape_index, this->n_dofs_per_cell());
453 AssertIndexRange(face_index, this->reference_cell().n_faces());
454
455 //
456 // A support point lies on the face if its offset from the face vertex is
457 // orthogonal to the face normal.
458 //
459
460 const ReferenceCell<dim> reference_cell = this->reference_cell();
461 const auto offset = this->unit_support_points[shape_index] -
462 reference_cell.face_vertex_location(face_index, 0);
463 const auto normal = reference_cell.face_normal_vector(face_index);
464
465 return std::abs(offset * normal) < 1e-10;
466}
467
468
469
470template <int dim, int spacedim>
471unsigned int
473 const unsigned int face_dof_index,
474 const unsigned int face,
475 const types::geometric_orientation combined_orientation) const
476{
477 return FETools::face_to_cell_index(*this,
478 face_dof_index,
479 face,
480 combined_orientation);
481}
482
483
484
485template <int dim, int spacedim>
486const FullMatrix<double> &
488 const unsigned int child,
489 const RefinementCase<dim> &refinement_case) const
490{
491 if (dim == 3)
492 Assert(RefinementCase<dim>(refinement_case) ==
494 static_cast<char>(IsotropicRefinementChoice::cut_tet_68)) ||
495 RefinementCase<dim>(refinement_case) ==
497 static_cast<char>(IsotropicRefinementChoice::cut_tet_57)) ||
498 RefinementCase<dim>(refinement_case) ==
500 static_cast<char>(IsotropicRefinementChoice::cut_tet_49)),
502 else
505 AssertDimension(dim, spacedim);
506
507 // initialization upon first request
508 if (this->restriction[refinement_case - 1][child].n() == 0)
509 {
510 std::scoped_lock lock(restriction_matrix_mutex);
511
512 // if matrix got updated while waiting for the lock
513 if (this->restriction[refinement_case - 1][child].n() ==
514 this->n_dofs_per_cell())
515 return this->restriction[refinement_case - 1][child];
516
517 // get the restriction matrix
518 // Refine a unit cell. As the parent cell is a unit
519 // cell, the reference cell of the children equals the parent, i.e. they
520 // have the support points at the same locations. So we just have to check
521 // if a support point of the parent is one of the interpolation points of
522 // the child. If this is not the case we find the interpolation of the
523 // point.
524
525 const double eps = 1e-12;
526 FullMatrix<double> restriction_mat(this->n_dofs_per_cell(),
527 this->n_dofs_per_cell());
528
529 // first get all support points on the reference cell
530 const std::vector<Point<dim>> unit_support_points =
531 this->get_unit_support_points();
532
533 // now create children on the reference cell
535 GridGenerator::reference_cell(tria, this->reference_cell());
536 tria.begin_active()->set_refine_flag(
538 if (dim == 3)
539 tria.begin_active()->set_refine_choice(refinement_case);
541
542 const auto &child_cell = tria.begin(0)->child(child);
543
544 // iterate over all support points and transform them to the unit cell of
545 // the child
546 for (unsigned int i = 0; i < unit_support_points.size(); i++)
547 {
548 std::vector<Point<dim>> transformed_point(1);
549 const std::vector<Point<spacedim>> unit_support_point = {
550 dim == 2 ? Point<spacedim>(unit_support_points[i][0],
551 unit_support_points[i][1]) :
552 Point<spacedim>(unit_support_points[i][0],
553 unit_support_points[i][1],
554 unit_support_points[i][2])};
555 this->reference_cell()
556 .template get_default_linear_mapping<spacedim>()
557 .transform_points_real_to_unit_cell(
558 child_cell,
559 make_array_view(unit_support_point),
560 make_array_view(transformed_point));
561
562 // if point is inside the unit cell iterate over all shape functions
563 if (this->reference_cell().contains_point(transformed_point[0], eps))
564 for (unsigned int j = 0; j < this->n_dofs_per_cell(); j++)
565 restriction_mat[i][j] =
566 this->shape_value(j, transformed_point[0]);
567 }
568 if constexpr (running_in_debug_mode())
569 {
570 for (unsigned int i = 0; i < this->n_dofs_per_cell(); i++)
571 {
572 double sum = 0.;
573
574 for (unsigned int j = 0; j < this->n_dofs_per_cell(); j++)
575 sum += restriction_mat[i][j];
576
577 Assert(std::fabs(sum - 1) < eps || std::fabs(sum) < eps,
579 "The entries in a row of the local "
580 "restriction matrix do not add to zero or one. "
581 "This typically indicates that the "
582 "polynomial interpolation is "
583 "ill-conditioned such that round-off "
584 "prevents the sum to be one."));
585 }
586 }
587
588 // Remove small entries from the matrix
589 for (unsigned int i = 0; i < restriction_mat.m(); ++i)
590 for (unsigned int j = 0; j < restriction_mat.n(); ++j)
591 {
592 if (std::fabs(restriction_mat(i, j)) < eps)
593 restriction_mat(i, j) = 0.;
594 if (std::fabs(restriction_mat(i, j) - 1) < eps)
595 restriction_mat(i, j) = 1.;
596 }
597
598 const_cast<FullMatrix<double> &>(
599 this->restriction[refinement_case - 1][child]) =
600 std::move(restriction_mat);
601 }
602
603 // finally return the matrix
604 return this->restriction[refinement_case - 1][child];
605}
606
607
608
609template <int dim, int spacedim>
610void
612 const FiniteElement<dim, spacedim> &source_fe,
613 FullMatrix<double> &interpolation_matrix,
614 const unsigned int face_no) const
615{
616 Assert(interpolation_matrix.m() == source_fe.n_dofs_per_face(face_no),
617 ExcDimensionMismatch(interpolation_matrix.m(),
618 source_fe.n_dofs_per_face(face_no)));
619
620 // see if source is a P or Q element
621 if ((dynamic_cast<const FE_SimplexPoly<dim, spacedim> *>(&source_fe) !=
622 nullptr) ||
623 (dynamic_cast<const FE_Q_Base<dim, spacedim> *>(&source_fe) != nullptr))
624 {
625 const Quadrature<dim - 1> quad_face_support(
626 source_fe.get_unit_face_support_points(face_no));
627
628 const double eps = 2e-13 * this->degree * (dim - 1);
629
630 const std::vector<Point<dim>> face_quadrature_points =
631 QProjector<dim>::project_to_face(this->reference_cell(),
632 quad_face_support,
633 face_no,
635 .get_points();
636
637 for (unsigned int i = 0; i < source_fe.n_dofs_per_face(face_no); ++i)
638 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
639 {
640 double matrix_entry =
641 this->shape_value(this->face_to_cell_index(j, 0),
642 face_quadrature_points[i]);
643
644 // Correct the interpolated value. I.e. if it is close to 1 or
645 // 0, make it exactly 1 or 0. Unfortunately, this is required to
646 // avoid problems with higher order elements.
647 if (std::fabs(matrix_entry - 1.0) < eps)
648 matrix_entry = 1.0;
649 if (std::fabs(matrix_entry) < eps)
650 matrix_entry = 0.0;
651
652 interpolation_matrix(i, j) = matrix_entry;
653 }
654
655 if constexpr (running_in_debug_mode())
656 {
657 for (unsigned int j = 0; j < source_fe.n_dofs_per_face(face_no); ++j)
658 {
659 double sum = 0.;
660
661 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
662 sum += interpolation_matrix(j, i);
663
664 Assert(std::fabs(sum - 1) < eps, ExcInternalError());
665 }
666 }
667 }
668 else if (dynamic_cast<const FE_Nothing<dim> *>(&source_fe) != nullptr)
669 {
670 // nothing to do here, the FE_Nothing has no degrees of freedom anyway
671 }
672 else
674 false,
675 (typename FiniteElement<dim,
676 spacedim>::ExcInterpolationNotImplemented()));
677}
678
679
680
681template <int dim, int spacedim>
682void
684 const FiniteElement<dim, spacedim> &source_fe,
685 const unsigned int subface,
686 FullMatrix<double> &interpolation_matrix,
687 const unsigned int face_no) const
688{
689 Assert(interpolation_matrix.m() == source_fe.n_dofs_per_face(face_no),
690 ExcDimensionMismatch(interpolation_matrix.m(),
691 source_fe.n_dofs_per_face(face_no)));
692
693 // see if source is a P or Q element
694 if ((dynamic_cast<const FE_SimplexPoly<dim, spacedim> *>(&source_fe) !=
695 nullptr) ||
696 (dynamic_cast<const FE_Q_Base<dim, spacedim> *>(&source_fe) != nullptr))
697 {
698 const Quadrature<dim - 1> quad_face_support(
699 source_fe.get_unit_face_support_points(face_no));
700
701 const double eps = 2e-13 * this->degree * (dim - 1);
702
703 const Quadrature<dim> subface_quadrature =
705 this->reference_cell(),
706 quad_face_support,
707 face_no,
708 subface,
711
712 for (unsigned int i = 0; i < source_fe.n_dofs_per_face(face_no); ++i)
713 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
714 {
715 double matrix_entry =
716 this->shape_value(this->face_to_cell_index(j, 0),
717 subface_quadrature.point(i));
718
719 // Correct the interpolated value. I.e. if it is close to 1 or
720 // 0, make it exactly 1 or 0. Unfortunately, this is required to
721 // avoid problems with higher order elements.
722 if (std::fabs(matrix_entry - 1.0) < eps)
723 matrix_entry = 1.0;
724 if (std::fabs(matrix_entry) < eps)
725 matrix_entry = 0.0;
726
727 interpolation_matrix(i, j) = matrix_entry;
728 }
729
730 if constexpr (running_in_debug_mode())
731 {
732 for (unsigned int j = 0; j < source_fe.n_dofs_per_face(face_no); ++j)
733 {
734 double sum = 0.;
735
736 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
737 sum += interpolation_matrix(j, i);
738
739 Assert(std::fabs(sum - 1) < eps, ExcInternalError());
740 }
741 }
742 }
743 else if (dynamic_cast<const FE_Nothing<dim> *>(&source_fe) != nullptr)
744 {
745 // nothing to do here, the FE_Nothing has no degrees of freedom anyway
746 }
747 else
749 false,
750 (typename FiniteElement<dim,
751 spacedim>::ExcInterpolationNotImplemented()));
752}
753
754
755
756template <int dim, int spacedim>
757bool
762
763
764
765template <int dim, int spacedim>
766void
769 const std::vector<Vector<double>> &support_point_values,
770 std::vector<double> &nodal_values) const
771{
772 AssertDimension(support_point_values.size(),
773 this->get_unit_support_points().size());
774 AssertDimension(support_point_values.size(), nodal_values.size());
775 AssertDimension(this->dofs_per_cell, nodal_values.size());
776
777 for (unsigned int i = 0; i < this->dofs_per_cell; ++i)
778 {
779 AssertDimension(support_point_values[i].size(), 1);
780
781 nodal_values[i] = support_point_values[i](0);
782 }
783}
784
785
786
787template <int dim, int spacedim>
789 : FE_SimplexPoly<dim, spacedim>(
790 BarycentricPolynomials<dim>::get_fe_p_basis(degree),
791 FiniteElementData<dim>(get_dpo_vector_fe_p(dim, degree),
792 ReferenceCells::get_simplex<dim>(),
793 1,
794 degree,
795 FiniteElementData<dim>::H1),
796 false,
797 unit_support_points_fe_p<dim>(degree),
798 unit_face_support_points_fe_p<dim>(degree, FiniteElementData<dim>::H1),
799 constraints_fe_p<dim>(degree))
800{
801 if (degree > 2)
802 for (unsigned int i = 0; i < this->n_dofs_per_line(); ++i)
804 this->n_dofs_per_line() - 1 - i - i;
805
806 // for 1d and 2d or if there are no DoFs on the quads
807 // we can skip adjust_quad_dof_index_for_face_orientation_table
808 if (dim < 3 || degree < 3)
809 return;
810
811 // do some sanity checks
813 const unsigned int face_no = 0;
814
815 Assert(
817 this->reference_cell().n_face_orientations(face_no) *
818 this->n_dofs_per_quad(face_no),
820
821 Assert((degree - 2) * (degree - 1) / 2 == this->n_dofs_per_quad(face_no),
823
824 const auto face_reference_cell =
825 this->reference_cell().face_reference_cell(face_no);
826
827 // the interior nodes build a new triangle with lower degree r
828 const unsigned int r = degree - 3;
829
830 // now loop over all DoFs on the triangle
831 // 0 <= i + j <= r holds on the triangle
832 for (unsigned int j = 0, dof_index = 0; j <= r; ++j)
833 for (unsigned int i = 0; i <= r - j; ++i, ++dof_index)
834 {
835 // index in the style of barycentric coordinates
836 // the first entry is the remainder as i + j <= r has to hold
837 const std::array<unsigned int, 3> local_indices{{r - i - j, i, j}};
838
839 // go over all possible orientations
840 for (types::geometric_orientation orientation = 0;
841 orientation < this->reference_cell().n_face_orientations(face_no);
842 ++orientation)
843 {
844 // get the correct permutation for the current orientation
845 const auto permuted_indices =
846 face_reference_cell.permute_by_combined_orientation(
847 make_array_view(local_indices),
848 face_reference_cell.get_inverse_combined_orientation(
849 orientation));
850
851 // now reconstruct the index of from the permuted i and j
852 // take orientation 0 which is the standard orientation
853 // then the index k is k = i + j*(r+1) - (j*(j-1))/2
854 const unsigned int k =
855 permuted_indices[1] + permuted_indices[2] * (r + 1) -
856 (permuted_indices[2] * (permuted_indices[2] - 1)) / 2;
857
858 const int offset =
859 static_cast<int>(k) - static_cast<int>(dof_index);
861 dof_index, orientation) = offset;
862 }
863 }
864}
865
866
867
868template <int dim, int spacedim>
869std::unique_ptr<FiniteElement<dim, spacedim>>
871{
872 return std::make_unique<FE_SimplexP<dim, spacedim>>(*this);
873}
874
875
876
877template <int dim, int spacedim>
878std::string
880{
881 std::ostringstream namebuf;
882 namebuf << "FE_SimplexP<" << Utilities::dim_string(dim, spacedim) << ">("
883 << this->degree << ")";
884
885 return namebuf.str();
886}
887
888
889
890template <int dim, int spacedim>
893 const FiniteElement<dim, spacedim> &fe_other,
894 const unsigned int codim) const
895{
896 Assert(codim <= dim, ExcImpossibleInDim(dim));
897
898 // vertex/line/face domination
899 // (if fe_other is derived from FE_SimplexDGP)
900 // ------------------------------------
901 if (codim > 0)
902 if (dynamic_cast<const FE_SimplexDGP<dim, spacedim> *>(&fe_other) !=
903 nullptr)
904 // there are no requirements between continuous and discontinuous
905 // elements
907
908 // vertex/line/face domination
909 // (if fe_other is not derived from FE_SimplexDGP)
910 // & cell domination
911 // ----------------------------------------
912 if (const FE_SimplexP<dim, spacedim> *fe_p_other =
913 dynamic_cast<const FE_SimplexP<dim, spacedim> *>(&fe_other))
914 {
915 if (this->degree < fe_p_other->degree)
917 else if (this->degree == fe_p_other->degree)
919 else
921 }
922 else if (const FE_Q<dim, spacedim> *fe_q_other =
923 dynamic_cast<const FE_Q<dim, spacedim> *>(&fe_other))
924 {
925 if (this->degree < fe_q_other->degree)
927 else if (this->degree == fe_q_other->degree)
929 else
931 }
932 else if (const FE_PyramidP<dim, spacedim> *fe_p_other =
933 dynamic_cast<const FE_PyramidP<dim, spacedim> *>(&fe_other))
934 {
935 if (this->degree < fe_p_other->degree)
937 else if (this->degree == fe_p_other->degree)
939 else
941 }
942 else if (const FE_WedgeP<dim, spacedim> *fe_p_other =
943 dynamic_cast<const FE_WedgeP<dim, spacedim> *>(&fe_other))
944 {
945 if (this->degree < fe_p_other->degree)
947 else if (this->degree == fe_p_other->degree)
949 else
951 }
952 else if (const FE_Nothing<dim, spacedim> *fe_nothing =
953 dynamic_cast<const FE_Nothing<dim, spacedim> *>(&fe_other))
954 {
955 if (fe_nothing->is_dominating())
957 else
958 // the FE_Nothing has no degrees of freedom and it is typically used
959 // in a context where we don't require any continuity along the
960 // interface
962 }
963
966}
967
968
969
970template <int dim, int spacedim>
971std::vector<std::pair<unsigned int, unsigned int>>
973 const FiniteElement<dim, spacedim> &fe_other) const
974{
975 if ((dynamic_cast<const FE_SimplexP<dim, spacedim> *>(&fe_other) !=
976 nullptr) ||
977 (dynamic_cast<const FE_Q<dim, spacedim> *>(&fe_other) != nullptr) ||
978 (dynamic_cast<const FE_PyramidP<dim, spacedim> *>(&fe_other) !=
979 nullptr) ||
980 (dynamic_cast<const FE_WedgeP<dim, spacedim> *>(&fe_other) != nullptr))
981 {
982 // there should be exactly one single DoF of each FE at a vertex, and
983 // they should have identical value
984 return {{0U, 0U}};
985 }
986 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
987 {
988 // the FE_Nothing has no degrees of freedom, so there are no
989 // equivalencies to be recorded
990 return {};
991 }
992 else if (fe_other.n_unique_faces() == 1 && fe_other.n_dofs_per_face(0) == 0)
993 {
994 // if the other element has no DoFs on faces at all,
995 // then it would be impossible to enforce any kind of
996 // continuity even if we knew exactly what kind of element
997 // we have -- simply because the other element declares
998 // that it is discontinuous because it has no DoFs on
999 // its faces. in that case, just state that we have no
1000 // constraints to declare
1001 return {};
1002 }
1003 else
1004 {
1006 return {};
1007 }
1008}
1009
1010
1011
1012template <int dim, int spacedim>
1013std::vector<std::pair<unsigned int, unsigned int>>
1015 const FiniteElement<dim, spacedim> &fe_other) const
1016{
1017 if ((dynamic_cast<const FE_SimplexP<dim, spacedim> *>(&fe_other)) ||
1018 (dynamic_cast<const FE_Q<dim, spacedim> *>(&fe_other)) ||
1019 (dynamic_cast<const FE_PyramidP<dim, spacedim> *>(&fe_other)) ||
1020 (dynamic_cast<const FE_WedgeP<dim, spacedim> *>(&fe_other)))
1021 {
1022 std::vector<std::pair<unsigned int, unsigned int>> identities;
1023 // check if the support points are the same location on the line
1024 // to avoid rescaling for pyramids use the support points on the faces
1025 const auto &face_support_points = this->get_unit_face_support_points(0);
1026 const auto &face_support_points_other =
1027 fe_other.get_unit_face_support_points(0);
1028
1029 // now just compare the DoFs on the line going from [0,0] to [1,0]
1030 // for a triangular face that is the first line
1031 // for a quad face that is the third line
1032 // adjust the offsets accordingly
1033 // face number 0 of the tet is a triangle
1034 const unsigned int offset =
1035 this->reference_cell().face_reference_cell(0).n_vertices();
1036
1037 const unsigned int offset_other =
1038 fe_other.reference_cell().face_reference_cell(0).is_simplex() ?
1039 fe_other.reference_cell().face_reference_cell(0).n_vertices() :
1040 fe_other.reference_cell().face_reference_cell(0).n_vertices() +
1041 2 * fe_other.n_dofs_per_line();
1042
1043 // now get the identities
1044 for (unsigned int i = 0; i < this->degree - 1; ++i)
1045 for (unsigned int j = 0; j < fe_other.degree - 1; ++j)
1046 if (face_support_points[i + offset].distance(
1047 face_support_points_other[j + offset_other]) < 1e-14)
1048 identities.emplace_back(i, j);
1049
1050 return identities;
1051 }
1052 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
1053 {
1054 // The FE_Nothing has no degrees of freedom, so there are no
1055 // equivalencies to be recorded. (If the FE_Nothing is dominating,
1056 // then this will also leads to constraints, but we are not concerned
1057 // with this here.)
1058 return {};
1059 }
1060 else if (fe_other.n_unique_faces() == 1 && fe_other.n_dofs_per_face(0) == 0)
1061 {
1062 // if the other element has no elements on faces at all,
1063 // then it would be impossible to enforce any kind of
1064 // continuity even if we knew exactly what kind of element
1065 // we have -- simply because the other element declares
1066 // that it is discontinuous because it has no DoFs on
1067 // its faces. in that case, just state that we have no
1068 // constraints to declare
1069 return {};
1070 }
1071 else
1072 {
1074 return {};
1075 }
1076}
1077
1078
1079
1080template <int dim, int spacedim>
1081std::vector<std::pair<unsigned int, unsigned int>>
1083 const FiniteElement<dim, spacedim> &fe_other,
1084 const unsigned int) const
1085{
1086 AssertDimension(dim, 3);
1087
1088 if ((dynamic_cast<const FE_SimplexP<dim> *>(&fe_other) != nullptr) ||
1089 (dynamic_cast<const FE_WedgeP<dim> *>(&fe_other) != nullptr) ||
1090 (dynamic_cast<const FE_PyramidP<dim> *>(&fe_other) != nullptr))
1091 {
1092 std::vector<std::pair<unsigned int, unsigned int>> result;
1093 const unsigned int face_no_neighbor =
1094 (dynamic_cast<const FE_PyramidP<dim> *>(&fe_other) != nullptr) ? 1 : 0;
1095
1096 // compare the face support points
1097 const auto &face_support_points = this->get_unit_face_support_points(0);
1098 const auto &face_support_points_other =
1099 fe_other.get_unit_face_support_points(face_no_neighbor);
1100
1101 // get the offsets to only compare the DoFs within the face as the
1102 // vertices and lines were done before
1103 const auto face_reference_cell =
1104 this->reference_cell().face_reference_cell(0);
1105
1106 Assert(face_reference_cell ==
1107 fe_other.reference_cell().face_reference_cell(face_no_neighbor),
1109
1110 const unsigned int offset =
1111 face_reference_cell.n_vertices() +
1112 face_reference_cell.n_lines() * this->n_dofs_per_line();
1113
1114 const unsigned int offset_other =
1115 face_reference_cell.n_vertices() +
1116 face_reference_cell.n_lines() * fe_other.n_dofs_per_line();
1117
1118 // do the comparison
1119 for (unsigned int i = 0; i < this->n_dofs_per_quad(0); ++i)
1120 for (unsigned int j = 0; j < fe_other.n_dofs_per_quad(face_no_neighbor);
1121 ++j)
1122 if (face_support_points[i + offset].distance(
1123 face_support_points_other[j + offset_other]) < 1e-14)
1124 result.emplace_back(i, j);
1125
1126 return result;
1127 }
1128 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
1129 {
1130 // the FE_Nothing has no degrees of freedom, so there are no
1131 // equivalencies to be recorded
1132 return std::vector<std::pair<unsigned int, unsigned int>>();
1133 }
1134 else if (fe_other.n_unique_faces() == 1 && fe_other.n_dofs_per_face(0) == 0)
1135 {
1136 // if the other element has no elements on faces at all,
1137 // then it would be impossible to enforce any kind of
1138 // continuity even if we knew exactly what kind of element
1139 // we have -- simply because the other element declares
1140 // that it is discontinuous because it has no DoFs on
1141 // its faces. in that case, just state that we have no
1142 // constraints to declare
1143 return std::vector<std::pair<unsigned int, unsigned int>>();
1144 }
1145 else
1146 {
1148 return std::vector<std::pair<unsigned int, unsigned int>>();
1149 }
1150}
1151
1152
1153
1154template <int dim, int spacedim>
1156 : FE_SimplexPoly<dim, spacedim>(
1157 BarycentricPolynomials<dim>::get_fe_p_basis(degree),
1158 FiniteElementData<dim>(get_dpo_vector_fe_dgp(dim, degree),
1159 ReferenceCells::get_simplex<dim>(),
1160 1,
1161 degree,
1162 FiniteElementData<dim>::L2),
1163 true,
1164 unit_support_points_fe_p<dim>(degree),
1165 unit_face_support_points_fe_p<dim>(degree, FiniteElementData<dim>::L2),
1166 constraints_fe_p<dim>(degree))
1167{}
1168
1169
1170
1171template <int dim, int spacedim>
1172std::unique_ptr<FiniteElement<dim, spacedim>>
1174{
1175 return std::make_unique<FE_SimplexDGP<dim, spacedim>>(*this);
1176}
1177
1178
1179
1180template <int dim, int spacedim>
1181std::string
1183{
1184 std::ostringstream namebuf;
1185 namebuf << "FE_SimplexDGP<" << Utilities::dim_string(dim, spacedim) << ">("
1186 << this->degree << ")";
1187
1188 return namebuf.str();
1189}
1190
1191
1192template <int dim, int spacedim>
1195 const FiniteElement<dim, spacedim> &fe_other,
1196 const unsigned int codim) const
1197{
1198 Assert(codim <= dim, ExcImpossibleInDim(dim));
1199
1200 // vertex/line/face domination
1201 // ---------------------------
1202 if (codim > 0)
1203 // this is a discontinuous element, so by definition there will
1204 // be no constraints wherever this element comes together with
1205 // any other kind of element
1207
1208 // cell domination
1209 // ---------------
1210 if (const FE_SimplexDGP<dim, spacedim> *fe_dgp_other =
1211 dynamic_cast<const FE_SimplexDGP<dim, spacedim> *>(&fe_other))
1212 {
1213 if (this->degree < fe_dgp_other->degree)
1215 else if (this->degree == fe_dgp_other->degree)
1217 else
1219 }
1220 else if (const FE_DGQ<dim, spacedim> *fe_dgq_other =
1221 dynamic_cast<const FE_DGQ<dim, spacedim> *>(&fe_other))
1222 {
1223 if (this->degree < fe_dgq_other->degree)
1225 else if (this->degree == fe_dgq_other->degree)
1227 else
1229 }
1230 else if (const FE_Nothing<dim, spacedim> *fe_nothing =
1231 dynamic_cast<const FE_Nothing<dim, spacedim> *>(&fe_other))
1232 {
1233 if (fe_nothing->is_dominating())
1235 else
1236 // the FE_Nothing has no degrees of freedom and it is typically used
1237 // in a context where we don't require any continuity along the
1238 // interface
1240 }
1241
1244}
1245
1246
1247
1248template <int dim, int spacedim>
1249std::vector<std::pair<unsigned int, unsigned int>>
1251 const FiniteElement<dim, spacedim> &fe_other) const
1252{
1253 (void)fe_other;
1254
1255 return {};
1256}
1257
1258
1259
1260template <int dim, int spacedim>
1261std::vector<std::pair<unsigned int, unsigned int>>
1263 const FiniteElement<dim, spacedim> &fe_other) const
1264{
1265 (void)fe_other;
1266
1267 return {};
1268}
1269
1270
1271
1272template <int dim, int spacedim>
1273const FullMatrix<double> &
1275 const unsigned int child,
1276 const RefinementCase<dim> &refinement_case) const
1277{
1278 if (dim == 3)
1279 Assert(RefinementCase<dim>(refinement_case) ==
1281 static_cast<char>(IsotropicRefinementChoice::cut_tet_68)) ||
1282 RefinementCase<dim>(refinement_case) ==
1284 static_cast<char>(IsotropicRefinementChoice::cut_tet_57)) ||
1285 RefinementCase<dim>(refinement_case) ==
1287 static_cast<char>(IsotropicRefinementChoice::cut_tet_49)),
1289 else
1292 AssertDimension(dim, spacedim);
1293
1294 // initialization upon first request
1295 if (this->restriction[refinement_case - 1][child].n() == 0)
1296 {
1297 std::scoped_lock lock(this->restriction_matrix_mutex);
1298
1299 // if matrix got updated while waiting for the lock
1300 if (this->restriction[refinement_case - 1][child].n() ==
1301 this->n_dofs_per_cell())
1302 return this->restriction[refinement_case - 1][child];
1303
1304 // now do the work. need to get a non-const version of data in order to
1305 // be able to modify them inside a const function
1306 auto &this_nonconst = const_cast<FE_SimplexDGP<dim, spacedim> &>(*this);
1307
1308 if (dim == 2)
1309 {
1310 std::vector<std::vector<FullMatrix<double>>> isotropic_matrices(
1312 isotropic_matrices.back().resize(
1313 this->reference_cell().n_children(
1314 RefinementCase<dim>(refinement_case)),
1315 FullMatrix<double>(this->n_dofs_per_cell(),
1316 this->n_dofs_per_cell()));
1317
1318 FETools::compute_projection_matrices(*this, isotropic_matrices, true);
1319
1320 this_nonconst.restriction[refinement_case - 1] =
1321 std::move(isotropic_matrices.back());
1322 }
1323 else if (dim == 3)
1324 {
1325 std::vector<std::vector<FullMatrix<double>>> matrices(
1326 static_cast<unsigned int>(IsotropicRefinementChoice::cut_tet_49),
1327 std::vector<FullMatrix<double>>(
1328 this->reference_cell().n_children(
1329 RefinementCase<dim>(refinement_case)),
1330 FullMatrix<double>(this->n_dofs_per_cell(),
1331 this->n_dofs_per_cell())));
1332 FETools::compute_projection_matrices(*this, matrices, true);
1333 for (unsigned int refinement_direction = static_cast<unsigned int>(
1335 refinement_direction <=
1336 static_cast<unsigned int>(IsotropicRefinementChoice::cut_tet_49);
1337 refinement_direction++)
1338 this_nonconst.restriction[refinement_direction - 1] =
1339 std::move(matrices[refinement_direction - 1]);
1340 }
1341 else
1343 }
1344
1345 // finally return the matrix
1346 return this->restriction[refinement_case - 1][child];
1347}
1348
1349// explicit instantiations
1350#include "fe/fe_simplex_p.inst"
1351
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
ArrayView< std::remove_reference_t< typename std::iterator_traits< Iterator >::reference >, MemorySpaceType > make_array_view(const Iterator begin, const Iterator end)
static BarycentricPolynomials< dim > get_fe_p_basis(const unsigned int degree)
Definition fe_q.h:552
FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim) const override
std::string get_name() const override
std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
FE_SimplexDGP(const unsigned int degree)
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
FE_SimplexP(const unsigned int degree)
std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim) const override
std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
std::string get_name() const override
std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
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
FE_SimplexPoly(const BarycentricPolynomials< dim > polynomials, const FiniteElementData< dim > &fe_data, const bool prolongation_is_additive, const std::vector< Point< dim > > &unit_support_points, const std::vector< std::vector< Point< dim - 1 > > > unit_face_support_points, const FullMatrix< double > &interface_constraints)
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &x_source_fe, const unsigned int subface, FullMatrix< double > &interpolation_matrix, const unsigned int face_no) 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 bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const override
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
bool hp_constraints_are_implemented() const override
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
virtual unsigned int face_to_cell_index(const unsigned int face_dof_index, const unsigned int face, const types::geometric_orientation combined_orientation=numbers::default_geometric_orientation) const override
void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source_fe, FullMatrix< double > &interpolation_matrix, const unsigned int face_no) const override
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_line() const
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_unique_faces() const
unsigned int n_dofs_per_quad(unsigned int face_no=0) const
ReferenceCell< dim > reference_cell() const
std::vector< std::vector< Point< dim - 1 > > > unit_face_support_points
Definition fe.h:2592
std::vector< Table< 2, int > > adjust_quad_dof_index_for_face_orientation_table
Definition fe.h:2621
const std::vector< Point< dim - 1 > > & get_unit_face_support_points(const unsigned int face_no=0) const
std::vector< int > adjust_line_dof_index_for_line_orientation_table
Definition fe.h:2634
std::vector< Point< dim > > unit_support_points
Definition fe.h:2585
FullMatrix< double > interface_constraints
Definition fe.h:2573
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)
constexpr unsigned int n_vertices() const
constexpr unsigned int n_lines() const
cell_iterator begin(const unsigned int level=0) const
virtual void execute_coarsening_and_refinement()
active_cell_iterator begin_active(const unsigned int level=0) const
#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_ASSERT_UNREACHABLE()
#define DEAL_II_NOT_IMPLEMENTED()
unsigned int vertex_indices[2]
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
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)
#define AssertThrow(cond, exc)
std::size_t size
Definition mpi.cc:733
unsigned int face_to_cell_index(const FiniteElement< dim, spacedim > &fe, const unsigned int face_dof_index, const unsigned int face_no, const types::geometric_orientation combined_orientation)
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_projection_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false)
void reference_cell(Triangulation< dim, spacedim > &tria, const ReferenceCell< dim > &reference_cell)
constexpr char U
constexpr ReferenceCell< 1 > Line
constexpr ReferenceCell< 2 > Triangle
constexpr ReferenceCell< 3 > Tetrahedron
constexpr const ReferenceCell< dim > & get_simplex()
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:342
STL namespace.
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
std::uint8_t geometric_orientation
Definition types.h:38