deal.II version 9.8.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_raviart_thomas_nodal.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) 2005 - 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
18
20
21#include <deal.II/fe/fe.h>
24#include <deal.II/fe/fe_tools.h>
25#include <deal.II/fe/mapping.h>
26
27#include <memory>
28#include <sstream>
29
30
32
33
34// ---------------- polynomial class for FE_RaviartThomasNodal ---------------
35
36namespace
37{
38 // Return a vector of "dofs per object" where the components of the returned
39 // vector refer to:
40 // 0 = vertex
41 // 1 = edge
42 // 2 = face (which is a cell in 2d)
43 // 3 = cell
44 std::vector<unsigned int>
45 get_rt_dpo_vector(const unsigned int dim, const unsigned int degree)
46 {
47 std::vector<unsigned int> dpo(dim + 1);
48 dpo[0] = 0;
49 dpo[1] = 0;
50 unsigned int dofs_per_face = 1;
51 for (unsigned int d = 1; d < dim; ++d)
52 dofs_per_face *= (degree + 1);
53
54 dpo[dim - 1] = dofs_per_face;
55 dpo[dim] = dim * degree * dofs_per_face;
56
57 return dpo;
58 }
59} // namespace
60
61
62
63// --------------------- actual implementation of element --------------------
64
65template <int dim>
67 : FE_PolyTensor<dim>(
69 degree + 1,
70 degree,
71 FE_RaviartThomas<dim>::get_lexicographic_numbering(degree)),
72 FiniteElementData<dim>(get_rt_dpo_vector(dim, degree),
73 dim,
74 degree + 1,
76 std::vector<bool>(1, false),
77 std::vector<ComponentMask>(
78 PolynomialsVectorAnisotropic<dim>::n_polynomials(degree + 1, degree),
79 ComponentMask(std::vector<bool>(dim, true))))
80{
81 Assert(dim >= 2, ExcImpossibleInDim(dim));
82
84
85 const std::vector<unsigned int> numbering =
87
88 // First, initialize the generalized support points and quadrature weights,
89 // since they are required for interpolation.
94 this->n_dofs_per_cell());
95
96 const unsigned int face_no = 0;
97 if (dim > 1)
98 this->generalized_face_support_points[face_no] =
99 degree == 0 ? QGauss<dim - 1>(1).get_points() :
100 QGaussLobatto<dim - 1>(degree + 1).get_points();
101
103 for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
104 face_embeddings[i].reinit(this->n_dofs_per_face(face_no),
105 this->n_dofs_per_face(face_no));
107 face_embeddings,
108 0,
109 0);
111 this->n_dofs_per_face(face_no),
112 this->n_dofs_per_face(face_no));
113 unsigned int target_row = 0;
114 for (unsigned int d = 0; d < GeometryInfo<dim>::max_children_per_face; ++d)
115 for (unsigned int i = 0; i < face_embeddings[d].m(); ++i)
116 {
117 for (unsigned int j = 0; j < face_embeddings[d].n(); ++j)
118 this->interface_constraints(target_row, j) = face_embeddings[d](i, j);
119 ++target_row;
120 }
121
122 // We need to initialize the dof permutation table and the one for the sign
123 // change.
125}
126
127
128
129template <int dim>
130std::string
132{
133 // note that the FETools::get_fe_by_name function depends on the particular
134 // format of the string this function returns, so they have to be kept in
135 // synch
136
137 // note that this->degree is the maximal polynomial degree and is thus one
138 // higher than the argument given to the constructor
139 return "FE_RaviartThomasNodal<" + std::to_string(dim) + ">(" +
140 std::to_string(this->degree - 1) + ")";
141}
142
143
144template <int dim>
145std::unique_ptr<FiniteElement<dim, dim>>
147{
148 return std::make_unique<FE_RaviartThomasNodal<dim>>(*this);
149}
150
151
152//---------------------------------------------------------------------------
153// Auxiliary and internal functions
154//---------------------------------------------------------------------------
155
156
157
158template <int dim>
159void
162{
163 // for 1d and 2d, do nothing
164 if (dim < 3)
165 return;
166
167 const unsigned int n = this->degree;
168 const unsigned int face_no = 0;
169 Assert(n * n == this->n_dofs_per_quad(face_no), ExcInternalError());
170 for (unsigned int local = 0; local < this->n_dofs_per_quad(face_no); ++local)
171 // face support points are in lexicographic ordering with x running
172 // fastest. invert that (y running fastest)
173 {
174 unsigned int i = local % n, j = local / n;
175
176 // face_orientation=false, face_rotation=false, face_flip=false
178 local, internal::combined_face_orientation(false, false, false)) =
179 j + i * n - local;
180 // face_orientation=false, face_rotation=true, face_flip=false
182 local, internal::combined_face_orientation(false, true, false)) =
183 i + (n - 1 - j) * n - local;
184 // face_orientation=false, face_rotation=false, face_flip=true
186 local, internal::combined_face_orientation(false, false, true)) =
187 (n - 1 - j) + (n - 1 - i) * n - local;
188 // face_orientation=false, face_rotation=true, face_flip=true
190 local, internal::combined_face_orientation(false, true, true)) =
191 (n - 1 - i) + j * n - local;
192 // face_orientation=true, face_rotation=false, face_flip=false
194 local, internal::combined_face_orientation(true, false, false)) = 0;
195 // face_orientation=true, face_rotation=true, face_flip=false
197 local, internal::combined_face_orientation(true, true, false)) =
198 j + (n - 1 - i) * n - local;
199 // face_orientation=true, face_rotation=false, face_flip=true
201 local, internal::combined_face_orientation(true, false, true)) =
202 (n - 1 - i) + (n - 1 - j) * n - local;
203 // face_orientation=true, face_rotation=true, face_flip=true
205 local, internal::combined_face_orientation(true, true, true)) =
206 (n - 1 - j) + i * n - local;
207
208 // for face_orientation == false, we need to switch the sign
209 for (const bool rotation : {false, true})
210 for (const bool flip : {false, true})
212 local, internal::combined_face_orientation(false, rotation, flip)) =
213 1;
214 }
215}
216
217
218
219template <int dim>
220bool
222 const unsigned int shape_index,
223 const unsigned int face_index) const
224{
225 AssertIndexRange(shape_index, this->n_dofs_per_cell());
227
228 // The first degrees of freedom are on the faces and each face has degree
229 // degrees.
230 const unsigned int support_face = shape_index / this->n_dofs_per_face();
231
232 // The only thing we know for sure is that shape functions with support on
233 // one face are zero on the opposite face.
234 if (support_face < GeometryInfo<dim>::faces_per_cell)
235 return (face_index != GeometryInfo<dim>::opposite_face[support_face]);
236
237 // In all other cases, return true, which is safe
238 return true;
239}
240
241
242
243template <int dim>
244void
247 const std::vector<Vector<double>> &support_point_values,
248 std::vector<double> &nodal_values) const
249{
250 Assert(support_point_values.size() == this->generalized_support_points.size(),
251 ExcDimensionMismatch(support_point_values.size(),
252 this->generalized_support_points.size()));
253 Assert(nodal_values.size() == this->n_dofs_per_cell(),
254 ExcDimensionMismatch(nodal_values.size(), this->n_dofs_per_cell()));
255 Assert(support_point_values[0].size() == this->n_components(),
256 ExcDimensionMismatch(support_point_values[0].size(),
257 this->n_components()));
258
259 // First do interpolation on faces. There, the component evaluated depends
260 // on the face direction and orientation.
261 unsigned int fbase = 0;
262 unsigned int f = 0;
263 for (; f < GeometryInfo<dim>::faces_per_cell;
264 ++f, fbase += this->n_dofs_per_face(f))
265 {
266 for (unsigned int i = 0; i < this->n_dofs_per_face(f); ++i)
267 {
268 nodal_values[fbase + i] = support_point_values[fbase + i](
270 }
271 }
272
273 // The remaining points form dim chunks, one for each component
274 const unsigned int istep = (this->n_dofs_per_cell() - fbase) / dim;
275 Assert((this->n_dofs_per_cell() - fbase) % dim == 0, ExcInternalError());
276
277 f = 0;
278 while (fbase < this->n_dofs_per_cell())
279 {
280 for (unsigned int i = 0; i < istep; ++i)
281 {
282 nodal_values[fbase + i] = support_point_values[fbase + i](f);
283 }
284 fbase += istep;
285 ++f;
286 }
287 Assert(fbase == this->n_dofs_per_cell(), ExcInternalError());
288}
289
290
291
292// TODO: There are tests that check that the following few functions don't
293// produce assertion failures, but none that actually check whether they do the
294// right thing. one example for such a test would be to project a function onto
295// an hp-space and make sure that the convergence order is correct with regard
296// to the lowest used polynomial degree
297
298template <int dim>
299bool
304
305
306template <int dim>
307std::vector<std::pair<unsigned int, unsigned int>>
309 const FiniteElement<dim> &fe_other) const
310{
311 // we can presently only compute these identities if both FEs are
312 // FE_RaviartThomasNodals or the other is FE_Nothing. In either case, no
313 // dofs are assigned on the vertex, so we shouldn't be getting here at all.
314 if (dynamic_cast<const FE_RaviartThomasNodal<dim> *>(&fe_other) != nullptr)
315 return std::vector<std::pair<unsigned int, unsigned int>>();
316 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
317 return std::vector<std::pair<unsigned int, unsigned int>>();
318 else
319 {
321 return std::vector<std::pair<unsigned int, unsigned int>>();
322 }
323}
324
325
326
327template <int dim>
328std::vector<std::pair<unsigned int, unsigned int>>
330 const FiniteElement<dim> &fe_other) const
331{
332 // we can presently only compute these identities if both FEs are
333 // FE_RaviartThomasNodals or if the other one is FE_Nothing
334 if (const FE_RaviartThomasNodal<dim> *fe_q_other =
335 dynamic_cast<const FE_RaviartThomasNodal<dim> *>(&fe_other))
336 {
337 // dofs are located on faces; these are only lines in 2d
338 if (dim != 2)
339 return std::vector<std::pair<unsigned int, unsigned int>>();
340
341 // dofs are located along lines, so two dofs are identical only if in
342 // the following two cases (remember that the face support points are
343 // Gauss points):
344 // 1. this->degree = fe_q_other->degree,
345 // in the case, all the dofs on the line are identical
346 // 2. this->degree-1 and fe_q_other->degree-1
347 // are both even, i.e. this->dof_per_line and fe_q_other->dof_per_line
348 // are both odd, there exists only one point (the middle one) such
349 // that dofs are identical on this point
350 //
351 // to understand this, note that this->degree is the *maximal*
352 // polynomial degree, and is thus one higher than the argument given to
353 // the constructor
354 const unsigned int p = this->degree - 1;
355 const unsigned int q = fe_q_other->degree - 1;
356
357 std::vector<std::pair<unsigned int, unsigned int>> identities;
358
359 if (p == q)
360 for (unsigned int i = 0; i < p + 1; ++i)
361 identities.emplace_back(i, i);
362
363 else if (p % 2 == 0 && q % 2 == 0)
364 identities.emplace_back(p / 2, q / 2);
365
366 return identities;
367 }
368 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
369 {
370 // the FE_Nothing has no degrees of freedom, so there are no
371 // equivalencies to be recorded
372 return std::vector<std::pair<unsigned int, unsigned int>>();
373 }
374 else
375 {
377 return std::vector<std::pair<unsigned int, unsigned int>>();
378 }
379}
380
381
382template <int dim>
383std::vector<std::pair<unsigned int, unsigned int>>
385 const FiniteElement<dim> &fe_other,
386 const unsigned int face_no) const
387{
388 // we can presently only compute these identities if both FEs are
389 // FE_RaviartThomasNodals or if the other one is FE_Nothing
390 if (const FE_RaviartThomasNodal<dim> *fe_q_other =
391 dynamic_cast<const FE_RaviartThomasNodal<dim> *>(&fe_other))
392 {
393 // dofs are located on faces; these are only quads in 3d
394 if (dim != 3)
395 return std::vector<std::pair<unsigned int, unsigned int>>();
396
397 // this works exactly like the line case above
398 const unsigned int p = this->n_dofs_per_quad(face_no);
399
400 AssertDimension(fe_q_other->n_unique_faces(), 1);
401 const unsigned int q = fe_q_other->n_dofs_per_quad(0);
402
403 std::vector<std::pair<unsigned int, unsigned int>> identities;
404
405 if (p == q)
406 for (unsigned int i = 0; i < p; ++i)
407 identities.emplace_back(i, i);
408
409 else if (p % 2 != 0 && q % 2 != 0)
410 identities.emplace_back(p / 2, q / 2);
411
412 return identities;
413 }
414 else if (dynamic_cast<const FE_Nothing<dim> *>(&fe_other) != nullptr)
415 {
416 // the FE_Nothing has no degrees of freedom, so there are no
417 // equivalencies to be recorded
418 return std::vector<std::pair<unsigned int, unsigned int>>();
419 }
420 else
421 {
423 return std::vector<std::pair<unsigned int, unsigned int>>();
424 }
425}
426
427
428template <int dim>
431 const FiniteElement<dim> &fe_other,
432 const unsigned int codim) const
433{
434 Assert(codim <= dim, ExcImpossibleInDim(dim));
435 (void)codim;
436
437 // vertex/line/face/cell domination
438 // --------------------------------
439 if (const FE_RaviartThomasNodal<dim> *fe_rt_nodal_other =
440 dynamic_cast<const FE_RaviartThomasNodal<dim> *>(&fe_other))
441 {
442 if (this->degree < fe_rt_nodal_other->degree)
444 else if (this->degree == fe_rt_nodal_other->degree)
446 else
448 }
449 else if (const FE_Nothing<dim> *fe_nothing =
450 dynamic_cast<const FE_Nothing<dim> *>(&fe_other))
451 {
452 if (fe_nothing->is_dominating())
454 else
455 // the FE_Nothing has no degrees of freedom and it is typically used
456 // in a context where we don't require any continuity along the
457 // interface
459 }
460
463}
464
465
466
467template <>
468void
470 const FiniteElement<1, 1> & /*x_source_fe*/,
471 FullMatrix<double> & /*interpolation_matrix*/,
472 const unsigned int) const
473{
474 Assert(false, ExcImpossibleInDim(1));
475}
476
477
478template <>
479void
481 const FiniteElement<1, 1> & /*x_source_fe*/,
482 const unsigned int /*subface*/,
483 FullMatrix<double> & /*interpolation_matrix*/,
484 const unsigned int) const
485{
486 Assert(false, ExcImpossibleInDim(1));
487}
488
489
490
491template <int dim>
492void
494 const FiniteElement<dim> &x_source_fe,
495 FullMatrix<double> &interpolation_matrix,
496 const unsigned int face_no) const
497{
498 // this is only implemented, if the
499 // source FE is also a
500 // RaviartThomasNodal element
501 AssertThrow((x_source_fe.get_name().find("FE_RaviartThomasNodal<") == 0) ||
502 (dynamic_cast<const FE_RaviartThomasNodal<dim> *>(
503 &x_source_fe) != nullptr),
505
506 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
507 ExcDimensionMismatch(interpolation_matrix.n(),
508 this->n_dofs_per_face(face_no)));
509 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
510 ExcDimensionMismatch(interpolation_matrix.m(),
511 x_source_fe.n_dofs_per_face(face_no)));
512
513 // ok, source is a RaviartThomasNodal element, so we will be able to do the
514 // work
515 const FE_RaviartThomasNodal<dim> &source_fe =
516 dynamic_cast<const FE_RaviartThomasNodal<dim> &>(x_source_fe);
517
518 // Make sure that the element for which the DoFs should be constrained is
519 // the one with the higher polynomial degree. Actually the procedure will
520 // work also if this assertion is not satisfied. But the matrices produced
521 // in that case might lead to problems in the hp-procedures, which use this
522 // method.
523 Assert(this->n_dofs_per_face(face_no) <= source_fe.n_dofs_per_face(face_no),
525
526 // generate a quadrature with the generalized support points. This is later
527 // based as a basis for the QProjector, which returns the support points on
528 // the face.
529 Quadrature<dim - 1> quad_face_support(
530 source_fe.generalized_face_support_points[face_no]);
531
532 // Rule of thumb for FP accuracy, that can be expected for a given
533 // polynomial degree. This value is used to cut off values close to zero.
534 double eps = 2e-13 * this->degree * (dim - 1);
535
536 // compute the interpolation matrix by simply taking the value at the
537 // support points.
538 const Quadrature<dim> face_projection =
540 quad_face_support,
541 0,
543
544 for (unsigned int i = 0; i < source_fe.n_dofs_per_face(face_no); ++i)
545 {
546 const Point<dim> &p = face_projection.point(i);
547
548 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
549 {
550 double matrix_entry =
551 this->shape_value_component(this->face_to_cell_index(j, 0), p, 0);
552
553 // Correct the interpolated value. I.e. if it is close to 1 or 0,
554 // make it exactly 1 or 0. Unfortunately, this is required to avoid
555 // problems with higher order elements.
556 if (std::fabs(matrix_entry - 1.0) < eps)
557 matrix_entry = 1.0;
558 if (std::fabs(matrix_entry) < eps)
559 matrix_entry = 0.0;
560
561 interpolation_matrix(i, j) = matrix_entry;
562 }
563 }
564
565 if constexpr (running_in_debug_mode())
566 {
567 // make sure that the row sum of each of the matrices is 1 at this
568 // point. this must be so since the shape functions sum up to 1
569 for (unsigned int j = 0; j < source_fe.n_dofs_per_face(face_no); ++j)
570 {
571 double sum = 0.;
572
573 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
574 sum += interpolation_matrix(j, i);
575
576 Assert(std::fabs(sum - 1) < 2e-13 * this->degree * (dim - 1),
578 }
579 }
580}
581
582
583template <int dim>
584void
586 const FiniteElement<dim> &x_source_fe,
587 const unsigned int subface,
588 FullMatrix<double> &interpolation_matrix,
589 const unsigned int face_no) const
590{
591 // this is only implemented, if the source FE is also a RaviartThomasNodal
592 // element
593 AssertThrow((x_source_fe.get_name().find("FE_RaviartThomasNodal<") == 0) ||
594 (dynamic_cast<const FE_RaviartThomasNodal<dim> *>(
595 &x_source_fe) != nullptr),
597
598 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
599 ExcDimensionMismatch(interpolation_matrix.n(),
600 this->n_dofs_per_face(face_no)));
601 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
602 ExcDimensionMismatch(interpolation_matrix.m(),
603 x_source_fe.n_dofs_per_face(face_no)));
604
605 // ok, source is a RaviartThomasNodal element, so we will be able to do the
606 // work
607 const FE_RaviartThomasNodal<dim> &source_fe =
608 dynamic_cast<const FE_RaviartThomasNodal<dim> &>(x_source_fe);
609
610 // Make sure that the element for which the DoFs should be constrained is
611 // the one with the higher polynomial degree. Actually the procedure will
612 // work also if this assertion is not satisfied. But the matrices produced
613 // in that case might lead to problems in the hp-procedures, which use this
614 // method.
615 Assert(this->n_dofs_per_face(face_no) <= source_fe.n_dofs_per_face(face_no),
617
618 // generate a quadrature with the generalized support points. This is later
619 // based as a basis for the QProjector, which returns the support points on
620 // the face.
621 Quadrature<dim - 1> quad_face_support(
622 source_fe.generalized_face_support_points[face_no]);
623
624 // Rule of thumb for FP accuracy, that can be expected for a given
625 // polynomial degree. This value is used to cut off values close to zero.
626 double eps = 2e-13 * this->degree * (dim - 1);
627
628 // compute the interpolation matrix by simply taking the value at the
629 // support points.
630 const Quadrature<dim> subface_projection =
632 this->reference_cell(),
633 quad_face_support,
634 0,
635 subface,
638
639 for (unsigned int i = 0; i < source_fe.n_dofs_per_face(face_no); ++i)
640 {
641 const Point<dim> &p = subface_projection.point(i);
642
643 for (unsigned int j = 0; j < this->n_dofs_per_face(face_no); ++j)
644 {
645 double matrix_entry =
646 this->shape_value_component(this->face_to_cell_index(j, 0), p, 0);
647
648 // Correct the interpolated value. I.e. if it is close to 1 or 0,
649 // make it exactly 1 or 0. Unfortunately, this is required to avoid
650 // problems with higher order elements.
651 if (std::fabs(matrix_entry - 1.0) < eps)
652 matrix_entry = 1.0;
653 if (std::fabs(matrix_entry) < eps)
654 matrix_entry = 0.0;
655
656 interpolation_matrix(i, j) = matrix_entry;
657 }
658 }
659
660 if constexpr (running_in_debug_mode())
661 {
662 // make sure that the row sum of each of the matrices is 1 at this
663 // point. this must be so since the shape functions sum up to 1
664 for (unsigned int j = 0; j < source_fe.n_dofs_per_face(face_no); ++j)
665 {
666 double sum = 0.;
667
668 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
669 sum += interpolation_matrix(j, i);
670
671 Assert(std::fabs(sum - 1) < 2e-13 * this->degree * (dim - 1),
673 }
674 }
675}
676
677
678
679template <int dim>
680const FullMatrix<double> &
682 const unsigned int child,
683 const RefinementCase<dim> &refinement_case) const
684{
685 AssertIndexRange(refinement_case,
689 "Prolongation matrices are only available for refined cells!"));
690 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
691
692 // initialization upon first request
693 if (this->prolongation[refinement_case - 1][child].n() == 0)
694 {
695 std::scoped_lock lock(prolongation_matrix_mutex);
696
697 // if matrix got updated while waiting for the lock
698 if (this->prolongation[refinement_case - 1][child].n() ==
699 this->n_dofs_per_cell())
700 return this->prolongation[refinement_case - 1][child];
701
702 // now do the work. need to get a non-const version of data in order to
703 // be able to modify them inside a const function
704 FE_RaviartThomasNodal<dim> &this_nonconst =
705 const_cast<FE_RaviartThomasNodal<dim> &>(*this);
706 if (refinement_case == RefinementCase<dim>::isotropic_refinement)
707 {
708 std::vector<std::vector<FullMatrix<double>>> isotropic_matrices(
710 isotropic_matrices.back().resize(
711 this->reference_cell().n_children(
712 RefinementCase<dim>(refinement_case)),
714 this->n_dofs_per_cell()));
715 FETools::compute_embedding_matrices(*this, isotropic_matrices, true);
716 this_nonconst.prolongation[refinement_case - 1] =
717 std::move(isotropic_matrices.back());
718 }
719 else
720 {
721 // must compute both restriction and prolongation matrices because
722 // we only check for their size and the reinit call initializes them
723 // all
726 this_nonconst.prolongation);
728 this_nonconst.restriction);
729 }
730 }
731
732 // finally return the matrix
733 return this->prolongation[refinement_case - 1][child];
734}
735
736
737
738template <int dim>
739const FullMatrix<double> &
741 const unsigned int child,
742 const RefinementCase<dim> &refinement_case) const
743{
744 AssertIndexRange(refinement_case,
748 "Restriction matrices are only available for refined cells!"));
749 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
750
751 // initialization upon first request
752 if (this->restriction[refinement_case - 1][child].n() == 0)
753 {
754 std::scoped_lock lock(restriction_matrix_mutex);
755
756 // if matrix got updated while waiting for the lock...
757 if (this->restriction[refinement_case - 1][child].n() ==
758 this->n_dofs_per_cell())
759 return this->restriction[refinement_case - 1][child];
760
761 // now do the work. need to get a non-const version of data in order to
762 // be able to modify them inside a const function
763 FE_RaviartThomasNodal<dim> &this_nonconst =
764 const_cast<FE_RaviartThomasNodal<dim> &>(*this);
765 if (refinement_case == RefinementCase<dim>::isotropic_refinement)
766 {
767 std::vector<std::vector<FullMatrix<double>>> isotropic_matrices(
769 isotropic_matrices.back().resize(
770 this->reference_cell().n_children(
771 RefinementCase<dim>(refinement_case)),
773 this->n_dofs_per_cell()));
774 FETools::compute_projection_matrices(*this, isotropic_matrices, true);
775 this_nonconst.restriction[refinement_case - 1] =
776 std::move(isotropic_matrices.back());
777 }
778 else
779 {
780 // must compute both restriction and prolongation matrices because
781 // we only check for their size and the reinit call initializes them
782 // all
785 this_nonconst.prolongation);
787 this_nonconst.restriction);
788 }
789 }
790
791 // finally return the matrix
792 return this->restriction[refinement_case - 1][child];
793}
794
795
796
797// explicit instantiations
798#include "fe/fe_raviart_thomas_nodal.inst"
799
800
std::vector< Table< 2, bool > > adjust_quad_dof_sign_for_face_orientation_table
virtual double shape_value_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
std::vector< MappingKind > mapping_kind
FE_PolyTensor(const TensorPolynomialsBase< dim > &polynomials, const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
virtual std::unique_ptr< FiniteElement< dim, dim > > clone() 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
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const override
Threads::Mutex restriction_matrix_mutex
virtual const FullMatrix< double > & get_restriction_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
void initialize_quad_dof_index_permutation_and_sign_change()
Threads::Mutex prolongation_matrix_mutex
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim > &fe_other) const override
virtual void get_face_interpolation_matrix(const FiniteElement< dim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual std::string get_name() const override
virtual bool hp_constraints_are_implemented() const override
virtual void get_subface_interpolation_matrix(const FiniteElement< dim > &source, const unsigned int subface, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim > &fe_other, const unsigned int codim=0) const override final
virtual const FullMatrix< double > & get_prolongation_matrix(const unsigned int child, const RefinementCase< dim > &refinement_case=RefinementCase< dim >::isotropic_refinement) const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim > &fe_other) const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim > &fe_other, const unsigned int face_no=0) const override
FE_RaviartThomasNodal(const unsigned int p)
static std::vector< unsigned int > get_lexicographic_numbering(const unsigned int degree)
const unsigned int degree
Definition fe_data.h:450
unsigned int n_dofs_per_cell() const
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_components() const
unsigned int n_dofs_per_quad(unsigned int face_no=0) const
FiniteElementData(const std::vector< unsigned int > &dofs_per_object, const unsigned int n_components, const unsigned int degree, const Conformity conformity=unknown, const BlockIndices &block_indices=BlockIndices())
Definition fe_data.cc:112
ReferenceCell< dim > reference_cell() const
virtual std::string get_name() const =0
std::vector< std::vector< FullMatrix< double > > > restriction
Definition fe.h:2547
std::vector< Table< 2, int > > adjust_quad_dof_index_for_face_orientation_table
Definition fe.h:2621
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
std::vector< std::vector< Point< dim - 1 > > > generalized_face_support_points
Definition fe.h:2604
FiniteElement(const FiniteElementData< dim > &fe_data, const std::vector< bool > &restriction_is_additive_flags, const std::vector< ComponentMask > &nonzero_components)
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
FullMatrix< double > interface_constraints
Definition fe.h:2573
std::vector< Point< dim > > generalized_support_points
Definition fe.h:2598
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition fe.h:2561
size_type n() const
size_type m() const
Definition point.h:111
std::vector< Point< dim > > get_polynomial_support_points() const
static void project_to_subface(const ReferenceCell< dim > &reference_cell, const SubQuadrature &quadrature, const unsigned int face_no, const unsigned int subface_no, std::vector< Point< dim > > &q_points, const RefinementCase< dim - 1 > &ref_case=RefinementCase< dim - 1 >::isotropic_refinement)
static void project_to_face(const ReferenceCell< dim > &reference_cell, const SubQuadrature &quadrature, const unsigned int face_no, std::vector< Point< dim > > &q_points)
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define DEAL_II_NOT_IMPLEMENTED()
#define Assert(cond, exc)
static ::ExceptionBase & ExcImpossibleInDim(int arg1)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcInterpolationNotImplemented()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
@ mapping_raviart_thomas
Definition mapping.h:134
void compute_embedding_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false, const double threshold=1.e-12)
void compute_face_embedding_matrices(const FiniteElement< dim, spacedim > &fe, const ArrayView< FullMatrix< number > > &matrices, const unsigned int face_coarse, const unsigned int face_fine, const double threshold=1.e-12)
void compute_projection_matrices(const FiniteElement< dim, spacedim > &fe, std::vector< std::vector< FullMatrix< number > > > &matrices, const bool isotropic_only=false)
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
types::geometric_orientation combined_face_orientation(const bool face_orientation, const bool face_rotation, const bool face_flip)
constexpr types::geometric_orientation default_geometric_orientation
Definition types.h:350
STL namespace.
static constexpr unsigned int max_children_per_face
static constexpr unsigned int faces_per_cell
static constexpr std::array< unsigned int, faces_per_cell > unit_normal_direction
static constexpr std::array< unsigned int, faces_per_cell > opposite_face