Reference documentation for deal.II version GIT relicensing-218-g1f873f3929 2024-03-28 15:00:02+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_raviart_thomas.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2003 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
15
21#include <deal.II/base/table.h>
23
25
26#include <deal.II/fe/fe.h>
28#include <deal.II/fe/fe_tools.h>
30#include <deal.II/fe/mapping.h>
31
32#include <deal.II/grid/tria.h>
34
35#include <iostream>
36#include <memory>
37#include <sstream>
38
39
41
42
43template <int dim>
45 : FE_PolyTensor<dim>(
46 PolynomialsRaviartThomas<dim>(deg + 1, deg),
47 FiniteElementData<dim>(get_dpo_vector(deg),
48 dim,
49 deg + 1,
50 FiniteElementData<dim>::Hdiv),
51 std::vector<bool>(PolynomialsRaviartThomas<dim>::n_polynomials(deg + 1,
52 deg),
53 true),
54 std::vector<ComponentMask>(
55 PolynomialsRaviartThomas<dim>::n_polynomials(deg + 1, deg),
56 ComponentMask(std::vector<bool>(dim, true))))
57{
58 Assert(dim >= 2, ExcImpossibleInDim(dim));
59 const unsigned int n_dofs = this->n_dofs_per_cell();
60
62 // First, initialize the
63 // generalized support points and
64 // quadrature weights, since they
65 // are required for interpolation.
67
68 // Now compute the inverse node matrix, generating the correct
69 // basis functions from the raw ones. For a discussion of what
70 // exactly happens here, see FETools::compute_node_matrix.
72 this->inverse_node_matrix.reinit(n_dofs, n_dofs);
74 // From now on, the shape functions provided by FiniteElement::shape_value
75 // and similar functions will be the correct ones, not
76 // the raw shape functions from the polynomial space anymore.
77
78 // Reinit the vectors of
79 // restriction and prolongation
80 // matrices to the right sizes.
81 // Restriction only for isotropic
82 // refinement
84 // Fill prolongation matrices with embedding operators
87
88 // TODO: the implementation makes the assumption that all faces have the
89 // same number of dofs
91 const unsigned int face_no = 0;
92
93 // TODO[TL]: for anisotropic refinement we will probably need a table of
94 // submatrices with an array for each refine case
96 for (unsigned int i = 0; i < GeometryInfo<dim>::max_children_per_face; ++i)
97 face_embeddings[i].reinit(this->n_dofs_per_face(face_no),
98 this->n_dofs_per_face(face_no));
99 FETools::compute_face_embedding_matrices<dim, double>(*this,
100 face_embeddings,
101 0,
102 0);
103 this->interface_constraints.reinit((1 << (dim - 1)) *
104 this->n_dofs_per_face(face_no),
105 this->n_dofs_per_face(face_no));
106 unsigned int target_row = 0;
107 for (unsigned int d = 0; d < GeometryInfo<dim>::max_children_per_face; ++d)
108 for (unsigned int i = 0; i < face_embeddings[d].m(); ++i)
109 {
110 for (unsigned int j = 0; j < face_embeddings[d].n(); ++j)
111 this->interface_constraints(target_row, j) = face_embeddings[d](i, j);
112 ++target_row;
113 }
114
115 // We need to initialize the dof permutation table and the one for the sign
116 // change.
118}
119
120
121
122template <int dim>
123std::string
125{
126 // note that the
127 // FETools::get_fe_by_name
128 // function depends on the
129 // particular format of the string
130 // this function returns, so they
131 // have to be kept in synch
132
133 // note that this->degree is the maximal
134 // polynomial degree and is thus one higher
135 // than the argument given to the
136 // constructor
137 std::ostringstream namebuf;
138 namebuf << "FE_RaviartThomas<" << dim << ">(" << this->degree - 1 << ")";
139
140 return namebuf.str();
141}
142
143
144template <int dim>
145std::unique_ptr<FiniteElement<dim, dim>>
147{
148 return std::make_unique<FE_RaviartThomas<dim>>(*this);
149}
150
151
152//---------------------------------------------------------------------------
153// Auxiliary and internal functions
154//---------------------------------------------------------------------------
155
156
157template <int dim>
158void
160{
161 QGauss<dim> cell_quadrature(deg + 1);
162 const unsigned int n_interior_points = (deg > 0) ? cell_quadrature.size() : 0;
163
164 // TODO: the implementation makes the assumption that all faces have the
165 // same number of dofs
166 AssertDimension(this->n_unique_faces(), 1);
167 const unsigned int face_no = 0;
168
169 unsigned int n_face_points = (dim > 1) ? 1 : 0;
170 // compute (deg+1)^(dim-1)
171 for (unsigned int d = 1; d < dim; ++d)
172 n_face_points *= deg + 1;
173
174
175 this->generalized_support_points.resize(
176 GeometryInfo<dim>::faces_per_cell * n_face_points + n_interior_points);
177 this->generalized_face_support_points[face_no].resize(n_face_points);
178
179 // Number of the point being entered
180 unsigned int current = 0;
181
182 if (dim > 1)
183 {
184 QGauss<dim - 1> face_points(deg + 1);
185 TensorProductPolynomials<dim - 1> legendre =
187
188 boundary_weights.reinit(n_face_points, legendre.n());
189
190 for (unsigned int k = 0; k < n_face_points; ++k)
191 {
192 this->generalized_face_support_points[face_no][k] =
193 face_points.point(k);
194 // Compute its quadrature
195 // contribution for each
196 // moment.
197 for (unsigned int i = 0; i < legendre.n(); ++i)
198 {
199 boundary_weights(k, i) =
200 face_points.weight(k) *
201 legendre.compute_value(i, face_points.point(k));
202 }
203 }
204
205 Quadrature<dim> faces =
206 QProjector<dim>::project_to_all_faces(this->reference_cell(),
207 face_points);
208 for (; current < GeometryInfo<dim>::faces_per_cell * n_face_points;
209 ++current)
210 {
211 // Enter the support point
212 // into the vector
213 this->generalized_support_points[current] = faces.point(
214 current +
216 this->reference_cell(), 0, true, false, false, n_face_points));
217 }
218 }
219
220 if (deg == 0)
221 return;
222
223 // Create Legendre basis for the space D_xi Q_k
224 std::unique_ptr<AnisotropicPolynomials<dim>> polynomials[dim];
225 for (unsigned int dd = 0; dd < dim; ++dd)
226 {
227 std::vector<std::vector<Polynomials::Polynomial<double>>> poly(dim);
228 for (unsigned int d = 0; d < dim; ++d)
231
232 polynomials[dd] = std::make_unique<AnisotropicPolynomials<dim>>(poly);
233 }
234
235 interior_weights.reinit(
236 TableIndices<3>(n_interior_points, polynomials[0]->n(), dim));
237
238 for (unsigned int k = 0; k < cell_quadrature.size(); ++k)
239 {
240 this->generalized_support_points[current++] = cell_quadrature.point(k);
241 for (unsigned int i = 0; i < polynomials[0]->n(); ++i)
242 for (unsigned int d = 0; d < dim; ++d)
243 interior_weights(k, i, d) =
244 cell_quadrature.weight(k) *
245 polynomials[d]->compute_value(i, cell_quadrature.point(k));
246 }
247
248 Assert(current == this->generalized_support_points.size(),
250}
251
252
253template <int dim>
254void
256{
257 // For 1d do nothing.
258 //
259 // TODO: For 2d we simply keep the legacy behavior for now. This should be
260 // changed in the future and can be taken care of by similar means as the 3d
261 // case below. The legacy behavior can be found in fe_poly_tensor.cc in the
262 // function internal::FE_PolyTensor::get_dof_sign_change_h_div(...)
263 if (dim < 3)
264 return;
265
266 // TODO: the implementation makes the assumption that all faces have the
267 // same number of dofs
268 AssertDimension(this->n_unique_faces(), 1);
269 const unsigned int face_no = 0;
270
271 Assert(
272 this->adjust_quad_dof_index_for_face_orientation_table[0].n_elements() ==
273 this->reference_cell().n_face_orientations(face_no) *
274 this->n_dofs_per_quad(face_no),
276
277 // The 3d RaviartThomas space has tensor_degree*tensor_degree face dofs
278 const unsigned int n = this->tensor_degree();
279 Assert(n * n == this->n_dofs_per_quad(face_no), ExcInternalError());
280
281 // The vector of tables adjust_quad_dof_index_for_face_orientation_table
282 // contains offsets for local face_dofs and is being filled with zeros in
283 // fe.cc. We need to fill it with the correct values in case of non-standard,
284 // flipped (rotated by +180 degrees) or rotated (rotated by +90 degrees) faces
285
286 // The dofs on a face are connected to a n x n matrix. for example, for
287 // tensor_degree==3 we have the following dofs on a quad:
288
289 // ___________
290 // | |
291 // | 6 7 8 |
292 // | |
293 // | 3 4 5 |
294 // | |
295 // | 0 1 2 |
296 // |___________|
297 //
298 // We have dof_index=i+n*j with index i in x-direction and index j in
299 // y-direction running from 0 to n-1. to extract i and j we can use
300 // i=dof_index%n and j=dof_index/n. The indices i and j can then be used to
301 // compute the offset.
302
303 // Example: if the switches are (true | true | true) that means we rotate the
304 // face first by + 90 degree(counterclockwise) then by another +180
305 // degrees but we do not flip it since the face has standard
306 // orientation. The flip axis is the diagonal from the lower left to the upper
307 // right corner of the face. With these flags the configuration above becomes:
308 // ___________
309 // | |
310 // | 2 5 8 |
311 // | |
312 // | 1 4 7 |
313 // | |
314 // | 0 3 6 |
315 // |___________|
316 //
317 // This is exactly what is realized by the formulas implemented below. Note
318 // that the necessity of a permuattion depends on the three flags.
319
320 // There is also a pattern for the sign change of the mapped face_dofs
321 // depending on the switches. In the above example it would be
322 // ___________
323 // | |
324 // | + - + |
325 // | |
326 // | + - + |
327 // | |
328 // | + - + |
329 // |___________|
330 //
331
332 for (unsigned int local_face_dof = 0;
333 local_face_dof < this->n_dofs_per_quad(face_no);
334 ++local_face_dof)
335 {
336 // Row and column
337 unsigned int i = local_face_dof % n;
338 unsigned int j = local_face_dof / n;
339
340 // We have 8 cases that are all treated the same way. Note that the
341 // corresponding case to case_no is just its binary representation.
342 // The above example of (false | true | true) would be case_no=3
343 for (const bool face_orientation : {false, true})
344 for (const bool face_flip : {false, true})
345 for (const bool face_rotation : {false, true})
346 {
347 const auto case_no =
349 face_rotation,
350 face_flip);
351
352 if (((!face_orientation) && (!face_rotation)) ||
353 ((face_orientation) && (face_rotation)))
354 {
355 // We flip across the diagonal
356 // This is the local face dof offset
357 this
358 ->adjust_quad_dof_index_for_face_orientation_table[face_no](
359 local_face_dof, case_no) = j + i * n - local_face_dof;
360 }
361 else
362 {
363 // Offset is zero
364 this
365 ->adjust_quad_dof_index_for_face_orientation_table[face_no](
366 local_face_dof, case_no) = 0;
367 } // if face needs dof permutation
368
369 // Get new local face_dof by adding offset
370 const unsigned int new_local_face_dof =
371 local_face_dof +
372 this->adjust_quad_dof_index_for_face_orientation_table[face_no](
373 local_face_dof, case_no);
374 // compute new row and column index
375 i = new_local_face_dof % n;
376 j = new_local_face_dof / n;
377
378 /*
379 * Now compute if a sign change is necessary. This is done for the
380 * case of face_orientation==true
381 */
382 // flip = false, rotation=true
383 if (!face_flip && face_rotation)
384 {
385 this
386 ->adjust_quad_dof_sign_for_face_orientation_table[face_no](
387 local_face_dof, case_no) = ((j % 2) == 1);
388 }
389 // flip = true, rotation=false
390 else if (face_flip && !face_rotation)
391 {
392 // This case is symmetric (although row and column may be
393 // switched)
394 this
395 ->adjust_quad_dof_sign_for_face_orientation_table[face_no](
396 local_face_dof, case_no) =
397 ((j % 2) == 1) != ((i % 2) == 1);
398 }
399 // flip = true, rotation=true
400 else if (face_flip && face_rotation)
401 {
402 this
403 ->adjust_quad_dof_sign_for_face_orientation_table[face_no](
404 local_face_dof, case_no) = ((i % 2) == 1);
405 }
406 /*
407 * flip = false, rotation=false => nothing to do
408 */
409
410 /*
411 * If face_orientation==false the sign flip is exactly the
412 * opposite.
413 */
414 if (!face_orientation)
415 this->adjust_quad_dof_sign_for_face_orientation_table[face_no](
416 local_face_dof, case_no) =
417 !this
418 ->adjust_quad_dof_sign_for_face_orientation_table[face_no](
419 local_face_dof, case_no);
420 } // case_no
421 } // local_face_dof
422}
423
424
425template <>
426void
428{
429 // there is only one refinement case in 1d,
430 // which is the isotropic one (first index of
431 // the matrix array has to be 0)
432 for (unsigned int i = 0; i < GeometryInfo<1>::max_children_per_cell; ++i)
433 this->restriction[0][i].reinit(0, 0);
434}
435
436
437
438// This function is the same Raviart-Thomas interpolation performed by
439// interpolate. Still, we cannot use interpolate, since it was written
440// for smooth functions. The functions interpolated here are not
441// smooth, maybe even not continuous. Therefore, we must double the
442// number of quadrature points in each direction in order to integrate
443// only smooth functions.
444
445// Then again, the interpolated function is chosen such that the
446// moments coincide with the function to be interpolated.
447
448template <int dim>
449void
451{
452 const unsigned int iso = RefinementCase<dim>::isotropic_refinement - 1;
453
454 QGauss<dim - 1> q_base(this->degree);
455 const unsigned int n_face_points = q_base.size();
456 // First, compute interpolation on
457 // subfaces
458 for (const unsigned int face : GeometryInfo<dim>::face_indices())
459 {
460 // The shape functions of the
461 // child cell are evaluated
462 // in the quadrature points
463 // of a full face.
464 Quadrature<dim> q_face =
465 QProjector<dim>::project_to_face(this->reference_cell(), q_base, face);
466 // Store shape values, since the
467 // evaluation suffers if not
468 // ordered by point
469 Table<2, double> cached_values_on_face(this->n_dofs_per_cell(),
470 q_face.size());
471 for (unsigned int k = 0; k < q_face.size(); ++k)
472 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
473 cached_values_on_face(i, k) = this->shape_value_component(
475
476 for (unsigned int sub = 0; sub < GeometryInfo<dim>::max_children_per_face;
477 ++sub)
478 {
479 // The weight functions for
480 // the coarse face are
481 // evaluated on the subface
482 // only.
484 this->reference_cell(), q_base, face, sub);
485 const unsigned int child = GeometryInfo<dim>::child_cell_on_face(
487
488 // On a certain face, we must
489 // compute the moments of ALL
490 // fine level functions with
491 // the coarse level weight
492 // functions belonging to
493 // that face. Due to the
494 // orthogonalization process
495 // when building the shape
496 // functions, these weights
497 // are equal to the
498 // corresponding shape
499 // functions.
500 for (unsigned int k = 0; k < n_face_points; ++k)
501 for (unsigned int i_child = 0; i_child < this->n_dofs_per_cell();
502 ++i_child)
503 for (unsigned int i_face = 0;
504 i_face < this->n_dofs_per_face(face);
505 ++i_face)
506 {
507 // The quadrature
508 // weights on the
509 // subcell are NOT
510 // transformed, so we
511 // have to do it here.
512 this->restriction[iso][child](
513 face * this->n_dofs_per_face(face) + i_face, i_child) +=
514 Utilities::fixed_power<dim - 1>(.5) * q_sub.weight(k) *
515 cached_values_on_face(i_child, k) *
516 this->shape_value_component(
517 face * this->n_dofs_per_face(face) + i_face,
518 q_sub.point(k),
520 }
521 }
522 }
523
524 if (this->degree == 1)
525 return;
526
527 // Create Legendre basis for the space D_xi Q_k. Here, we cannot
528 // use the shape functions
529 std::unique_ptr<AnisotropicPolynomials<dim>> polynomials[dim];
530 for (unsigned int dd = 0; dd < dim; ++dd)
531 {
532 std::vector<std::vector<Polynomials::Polynomial<double>>> poly(dim);
533 for (unsigned int d = 0; d < dim; ++d)
534 poly[d] =
536 poly[dd] =
538
539 polynomials[dd] = std::make_unique<AnisotropicPolynomials<dim>>(poly);
540 }
541
542 // TODO: the implementation makes the assumption that all faces have the
543 // same number of dofs
544 AssertDimension(this->n_unique_faces(), 1);
545 const unsigned int face_no = 0;
546
547 QGauss<dim> q_cell(this->degree);
548 const unsigned int start_cell_dofs =
549 GeometryInfo<dim>::faces_per_cell * this->n_dofs_per_face(face_no);
550
551 // Store shape values, since the
552 // evaluation suffers if not
553 // ordered by point
554 Table<3, double> cached_values_on_cell(this->n_dofs_per_cell(),
555 q_cell.size(),
556 dim);
557 for (unsigned int k = 0; k < q_cell.size(); ++k)
558 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
559 for (unsigned int d = 0; d < dim; ++d)
560 cached_values_on_cell(i, k, d) =
561 this->shape_value_component(i, q_cell.point(k), d);
562
563 for (unsigned int child = 0; child < GeometryInfo<dim>::max_children_per_cell;
564 ++child)
565 {
566 Quadrature<dim> q_sub =
567 QProjector<dim>::project_to_child(this->reference_cell(),
568 q_cell,
569 child);
570
571 for (unsigned int k = 0; k < q_sub.size(); ++k)
572 for (unsigned int i_child = 0; i_child < this->n_dofs_per_cell();
573 ++i_child)
574 for (unsigned int d = 0; d < dim; ++d)
575 for (unsigned int i_weight = 0; i_weight < polynomials[d]->n();
576 ++i_weight)
577 {
578 this->restriction[iso][child](start_cell_dofs + i_weight * dim +
579 d,
580 i_child) +=
581 q_sub.weight(k) * cached_values_on_cell(i_child, k, d) *
582 polynomials[d]->compute_value(i_weight, q_sub.point(k));
583 }
584 }
585}
586
587
588
589template <int dim>
590std::vector<unsigned int>
592{
593 // the element is face-based and we have
594 // (deg+1)^(dim-1) DoFs per face
595 unsigned int dofs_per_face = 1;
596 for (unsigned int d = 1; d < dim; ++d)
597 dofs_per_face *= deg + 1;
598
599 // and then there are interior dofs
600 const unsigned int interior_dofs = dim * deg * dofs_per_face;
601
602 std::vector<unsigned int> dpo(dim + 1);
603 dpo[dim - 1] = dofs_per_face;
604 dpo[dim] = interior_dofs;
605
606 return dpo;
607}
608
609
610
611template <int dim>
612std::pair<Table<2, bool>, std::vector<unsigned int>>
614{
615 Table<2, bool> constant_modes(dim, this->n_dofs_per_cell());
616 for (unsigned int d = 0; d < dim; ++d)
617 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
618 constant_modes(d, i) = true;
619 std::vector<unsigned int> components;
620 for (unsigned int d = 0; d < dim; ++d)
621 components.push_back(d);
622 return std::pair<Table<2, bool>, std::vector<unsigned int>>(constant_modes,
623 components);
624}
625
626
627
628//---------------------------------------------------------------------------
629// Data field initialization
630//---------------------------------------------------------------------------
631
632
633template <int dim>
634bool
635FE_RaviartThomas<dim>::has_support_on_face(const unsigned int shape_index,
636 const unsigned int face_index) const
637{
638 AssertIndexRange(shape_index, this->n_dofs_per_cell());
640
641 // Return computed values if we
642 // know them easily. Otherwise, it
643 // is always safe to return true.
644 switch (this->degree)
645 {
646 case 1:
647 {
648 switch (dim)
649 {
650 case 2:
651 {
652 // only on the one
653 // non-adjacent face
654 // are the values
655 // actually zero. list
656 // these in a table
657 return (face_index !=
659 }
660
661 default:
662 return true;
663 }
664 }
665
666 default: // other rt_order
667 return true;
668 }
669
670 return true;
671}
672
673
674
675template <int dim>
676void
678 const std::vector<Vector<double>> &support_point_values,
679 std::vector<double> &nodal_values) const
680{
681 Assert(support_point_values.size() == this->generalized_support_points.size(),
682 ExcDimensionMismatch(support_point_values.size(),
683 this->generalized_support_points.size()));
684 Assert(nodal_values.size() == this->n_dofs_per_cell(),
685 ExcDimensionMismatch(nodal_values.size(), this->n_dofs_per_cell()));
686 Assert(support_point_values[0].size() == this->n_components(),
687 ExcDimensionMismatch(support_point_values[0].size(),
688 this->n_components()));
689
690 std::fill(nodal_values.begin(), nodal_values.end(), 0.);
691
692 const unsigned int n_face_points = boundary_weights.size(0);
693 for (const unsigned int face : GeometryInfo<dim>::face_indices())
694 for (unsigned int k = 0; k < n_face_points; ++k)
695 for (unsigned int i = 0; i < boundary_weights.size(1); ++i)
696 {
697 nodal_values[i + face * this->n_dofs_per_face(face)] +=
698 boundary_weights(k, i) *
699 support_point_values[face * n_face_points + k](
701 }
702
703 // TODO: the implementation makes the assumption that all faces have the
704 // same number of dofs
705 AssertDimension(this->n_unique_faces(), 1);
706 const unsigned int face_no = 0;
707
708 const unsigned int start_cell_dofs =
709 GeometryInfo<dim>::faces_per_cell * this->n_dofs_per_face(face_no);
710 const unsigned int start_cell_points =
711 GeometryInfo<dim>::faces_per_cell * n_face_points;
712
713 for (unsigned int k = 0; k < interior_weights.size(0); ++k)
714 for (unsigned int i = 0; i < interior_weights.size(1); ++i)
715 for (unsigned int d = 0; d < dim; ++d)
716 nodal_values[start_cell_dofs + i * dim + d] +=
717 interior_weights(k, i, d) *
718 support_point_values[k + start_cell_points](d);
719}
720
721
722
723template <int dim>
724std::size_t
730
731
732
733// explicit instantiations
734#include "fe_raviart_thomas.inst"
735
736
FullMatrix< double > inverse_node_matrix
std::vector< MappingKind > mapping_kind
virtual std::size_t memory_consumption() 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
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
void initialize_quad_dof_index_permutation_and_sign_change()
virtual std::unique_ptr< FiniteElement< dim, dim > > clone() const override
friend class FE_RaviartThomas
void initialize_support_points(const unsigned int rt_degree)
static std::vector< unsigned int > get_dpo_vector(const unsigned int degree)
virtual std::string get_name() const override
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_unique_faces() const
void reinit_restriction_and_prolongation_matrices(const bool isotropic_restriction_only=false, const bool isotropic_prolongation_only=false)
FullMatrix< double > interface_constraints
Definition fe.h:2423
std::vector< std::vector< FullMatrix< double > > > prolongation
Definition fe.h:2411
size_type n() const
void invert(const FullMatrix< number2 > &M)
size_type m() const
static std::vector< Polynomial< double > > generate_complete_basis(const unsigned int degree)
static Quadrature< dim > project_to_child(const ReferenceCell &reference_cell, const Quadrature< dim > &quadrature, const unsigned int child_no)
static Quadrature< dim > project_to_all_faces(const ReferenceCell &reference_cell, const hp::QCollection< dim - 1 > &quadrature)
static void project_to_subface(const ReferenceCell &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 &reference_cell, const SubQuadrature &quadrature, const unsigned int face_no, std::vector< Point< dim > > &q_points)
const Point< dim > & point(const unsigned int i) const
double weight(const unsigned int i) const
unsigned int size() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:502
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:503
#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)
@ mapping_raviart_thomas
Definition mapping.h:132
#define DEAL_II_NOT_IMPLEMENTED()
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)
FullMatrix< double > compute_node_matrix(const FiniteElement< dim, spacedim > &fe)
unsigned char combined_face_orientation(const bool face_orientation, const bool face_rotation, const bool face_flip)
STL namespace.
static unsigned int child_cell_on_face(const RefinementCase< dim > &ref_case, const unsigned int face, const unsigned int subface, const bool face_orientation=true, const bool face_flip=false, const bool face_rotation=false, const RefinementCase< dim - 1 > &face_refinement_case=RefinementCase< dim - 1 >::isotropic_refinement)
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()