deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
fe_system.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) 1999 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
16
18
20#include <deal.II/fe/fe_tools.h>
22#include <deal.II/fe/mapping.h>
23
24#include <deal.II/grid/tria.h>
26
27#include <limits>
28#include <memory>
29#include <sstream>
30
31
33
34namespace
35{
36 unsigned int
37 count_nonzeros(const std::vector<unsigned int> &vec)
38 {
39 return std::count_if(vec.begin(), vec.end(), [](const unsigned int i) {
40 return i > 0;
41 });
42 }
43} // namespace
44
45namespace internal
46{
52 template <int dim, int spacedim = dim>
55 const unsigned int base_no)
56 {
59 fe.base_element(base_no).n_dofs_per_cell());
60 // 0 is a bad default value since it is a valid index
62
63 unsigned int out_index = 0;
64 for (unsigned int system_index = 0; system_index < fe.n_dofs_per_cell();
65 ++system_index)
66 {
67 if (fe.system_to_base_index(system_index).first.first == base_no)
68 {
69 Assert(fe.n_nonzero_components(system_index) == 1,
71 const unsigned int base_component =
72 fe.system_to_base_index(system_index).first.second;
73 const unsigned int base_index =
74 fe.system_to_base_index(system_index).second;
75 Assert(base_index < fe.base_element(base_no).n_dofs_per_cell(),
77
78 table[base_component][base_index] = out_index;
79 }
80 out_index += fe.n_nonzero_components(system_index);
81 }
82
83 return table;
84 }
85
89 template <int dim, int spacedim = dim>
90 std::vector<typename FESystem<dim, spacedim>::BaseOffsets>
92 const unsigned int base_no)
93 {
94 std::vector<typename FESystem<dim, spacedim>::BaseOffsets> table;
95 const FiniteElement<dim, spacedim> &base_fe = fe.base_element(base_no);
96
97 unsigned int out_index = 0;
98 for (unsigned int system_index = 0; system_index < fe.n_dofs_per_cell();
99 ++system_index)
100 {
101 if (fe.system_to_base_index(system_index).first.first == base_no)
102 {
103 const unsigned int base_index =
104 fe.system_to_base_index(system_index).second;
105 Assert(base_index < base_fe.n_dofs_per_cell(), ExcInternalError());
106 table.emplace_back();
107
108 table.back().n_nonzero_components =
109 fe.n_nonzero_components(system_index);
110 unsigned int in_index = 0;
111 for (unsigned int i = 0; i < base_index; ++i)
112 in_index += base_fe.n_nonzero_components(i);
113
114 table.back().in_index = in_index;
115 table.back().out_index = out_index;
116 }
117 out_index += fe.n_nonzero_components(system_index);
118 }
119
120 Assert(table.size() ==
121 base_fe.n_dofs_per_cell() * fe.element_multiplicity(base_no),
123 return table;
124 }
125
130 template <int dim, int spacedim = dim>
131 void
133 const FESystem<dim, spacedim> &fe,
134 const unsigned int base_no,
135 const UpdateFlags base_flags,
136 const Table<2, unsigned int> &base_to_system_table,
138 &base_data,
140 &output_data)
141 {
143 const unsigned int n_components = fe.element_multiplicity(base_no);
144 const unsigned int n_dofs_per_cell =
145 fe.base_element(base_no).n_dofs_per_cell();
146
147 auto copy_row = [](const auto &row_in, const auto &row_out) {
148 std::copy(row_in.begin(), row_in.end(), row_out.begin());
149 };
150
151 if (base_flags & update_values)
152 for (unsigned int component = 0; component < n_components; ++component)
153 for (unsigned int b = 0; b < n_dofs_per_cell; ++b)
154 copy_row(
155 base_data.shape_values[b],
156 output_data.shape_values[base_to_system_table[component][b]]);
157
158 if (base_flags & update_gradients)
159 for (unsigned int component = 0; component < n_components; ++component)
160 for (unsigned int b = 0; b < n_dofs_per_cell; ++b)
161 copy_row(
162 base_data.shape_gradients[b],
163 output_data.shape_gradients[base_to_system_table[component][b]]);
164
165 if (base_flags & update_hessians)
166 for (unsigned int component = 0; component < n_components; ++component)
167 for (unsigned int b = 0; b < n_dofs_per_cell; ++b)
168 copy_row(
169 base_data.shape_hessians[b],
170 output_data.shape_hessians[base_to_system_table[component][b]]);
171
172 if (base_flags & update_3rd_derivatives)
173 for (unsigned int component = 0; component < n_components; ++component)
174 for (unsigned int b = 0; b < n_dofs_per_cell; ++b)
175 copy_row(
176 base_data.shape_3rd_derivatives[b],
177 output_data
178 .shape_3rd_derivatives[base_to_system_table[component][b]]);
179 }
180
185 template <int dim, int spacedim = dim>
186 void
188 const FESystem<dim, spacedim> &fe,
189 const unsigned int base_no,
190 const unsigned int n_q_points,
191 const UpdateFlags base_flags,
192 const std::vector<typename FESystem<dim, spacedim>::BaseOffsets> &offsets,
194 &base_data,
196 &output_data)
197 {
199
200 for (const auto &offset : offsets)
201 {
202 if (base_flags & update_values)
203 for (unsigned int s = 0; s < offset.n_nonzero_components; ++s)
204 for (unsigned int q = 0; q < n_q_points; ++q)
205 output_data.shape_values[offset.out_index + s][q] =
206 base_data.shape_values[offset.in_index + s][q];
207
208 if (base_flags & update_gradients)
209 for (unsigned int s = 0; s < offset.n_nonzero_components; ++s)
210 for (unsigned int q = 0; q < n_q_points; ++q)
211 output_data.shape_gradients[offset.out_index + s][q] =
212 base_data.shape_gradients[offset.in_index + s][q];
213
214 if (base_flags & update_hessians)
215 for (unsigned int s = 0; s < offset.n_nonzero_components; ++s)
216 for (unsigned int q = 0; q < n_q_points; ++q)
217 output_data.shape_hessians[offset.out_index + s][q] =
218 base_data.shape_hessians[offset.in_index + s][q];
219
220 if (base_flags & update_3rd_derivatives)
221 for (unsigned int s = 0; s < offset.n_nonzero_components; ++s)
222 for (unsigned int q = 0; q < n_q_points; ++q)
223 output_data.shape_3rd_derivatives[offset.out_index + s][q] =
224 base_data.shape_3rd_derivatives[offset.in_index + s][q];
225 }
226 }
227} // namespace internal
228
229/* ----------------------- FESystem::InternalData ------------------- */
230#ifndef DOXYGEN
231
232template <int dim, int spacedim>
234 const unsigned int n_base_elements)
235 : base_fe_datas(n_base_elements)
236 , base_fe_output_objects(n_base_elements)
237{}
238
239
240
241template <int dim, int spacedim>
243{
244 // delete pointers and set them to zero to avoid inadvertent use
245 for (unsigned int i = 0; i < base_fe_datas.size(); ++i)
246 base_fe_datas[i].reset();
247}
248
249
250template <int dim, int spacedim>
253 const unsigned int base_no) const
254{
255 AssertIndexRange(base_no, base_fe_datas.size());
256 return *base_fe_datas[base_no];
257}
258
259
260
261template <int dim, int spacedim>
262void
264 const unsigned int base_no,
265 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase> ptr)
266{
267 AssertIndexRange(base_no, base_fe_datas.size());
268 base_fe_datas[base_no] = std::move(ptr);
269}
270
271
272
273template <int dim, int spacedim>
276 const unsigned int base_no) const
277{
278 AssertIndexRange(base_no, base_fe_output_objects.size());
279 return base_fe_output_objects[base_no];
280}
281
282
283
284/* ---------------------------------- FESystem ------------------- */
285
286
287template <int dim, int spacedim>
289
290
291template <int dim, int spacedim>
293 const unsigned int n_elements)
294 : FiniteElement<dim, spacedim>(
295 FETools::Compositing::multiply_dof_numbers<dim, spacedim>({&fe},
296 {n_elements}),
298 spacedim>(
299 {&fe},
300 {n_elements}),
301 FETools::Compositing::compute_nonzero_components<dim, spacedim>(
302 {&fe},
303 {n_elements}))
304 , base_elements((n_elements > 0))
305{
306 const std::vector<const FiniteElement<dim, spacedim> *> fes = {&fe};
307 const std::vector<unsigned int> multiplicities = {n_elements};
308 initialize(fes, multiplicities);
309}
310
311
312
313template <int dim, int spacedim>
315 const unsigned int n1,
317 const unsigned int n2)
318 : FiniteElement<dim, spacedim>(
319 FETools::Compositing::multiply_dof_numbers<dim, spacedim>({&fe1, &fe2},
320 {n1, n2}),
322 spacedim>(
323 {&fe1, &fe2},
324 {n1, n2}),
325 FETools::Compositing::compute_nonzero_components<dim, spacedim>({&fe1,
326 &fe2},
327 {n1, n2}))
328 , base_elements(static_cast<int>(n1 > 0) + static_cast<int>(n2 > 0))
329{
330 const std::vector<const FiniteElement<dim, spacedim> *> fes = {&fe1, &fe2};
331 const std::vector<unsigned int> multiplicities = {n1, n2};
332 initialize(fes, multiplicities);
333}
334
335
336
337template <int dim, int spacedim>
339 const unsigned int n1,
341 const unsigned int n2,
343 const unsigned int n3)
344 : FiniteElement<dim, spacedim>(
345 FETools::Compositing::multiply_dof_numbers<dim, spacedim>(
346 {&fe1, &fe2, &fe3},
347 {n1, n2, n3}),
349 spacedim>(
350 {&fe1, &fe2, &fe3},
351 {n1, n2, n3}),
352 FETools::Compositing::compute_nonzero_components<dim, spacedim>(
353 {&fe1, &fe2, &fe3},
354 {n1, n2, n3}))
355 , base_elements(static_cast<int>(n1 > 0) + static_cast<int>(n2 > 0) +
356 static_cast<int>(n3 > 0))
357{
358 const std::vector<const FiniteElement<dim, spacedim> *> fes = {&fe1,
359 &fe2,
360 &fe3};
361 const std::vector<unsigned int> multiplicities = {n1, n2, n3};
362 initialize(fes, multiplicities);
363}
364
365
366
367template <int dim, int spacedim>
369 const unsigned int n1,
371 const unsigned int n2,
373 const unsigned int n3,
375 const unsigned int n4)
376 : FiniteElement<dim, spacedim>(
377 FETools::Compositing::multiply_dof_numbers<dim, spacedim>(
378 {&fe1, &fe2, &fe3, &fe4},
379 {n1, n2, n3, n4}),
381 spacedim>(
382 {&fe1, &fe2, &fe3, &fe4},
383 {n1, n2, n3, n4}),
384 FETools::Compositing::compute_nonzero_components<dim, spacedim>(
385 {&fe1, &fe2, &fe3, &fe4},
386 {n1, n2, n3, n4}))
387 , base_elements(static_cast<int>(n1 > 0) + static_cast<int>(n2 > 0) +
388 static_cast<int>(n3 > 0) + static_cast<int>(n4 > 0))
389{
390 const std::vector<const FiniteElement<dim, spacedim> *> fes = {&fe1,
391 &fe2,
392 &fe3,
393 &fe4};
394 const std::vector<unsigned int> multiplicities = {n1, n2, n3, n4};
395 initialize(fes, multiplicities);
396}
397
398
399
400template <int dim, int spacedim>
402 const unsigned int n1,
404 const unsigned int n2,
406 const unsigned int n3,
408 const unsigned int n4,
410 const unsigned int n5)
411 : FiniteElement<dim, spacedim>(
412 FETools::Compositing::multiply_dof_numbers<dim, spacedim>(
413 {&fe1, &fe2, &fe3, &fe4, &fe5},
414 {n1, n2, n3, n4, n5}),
416 spacedim>(
417 {&fe1, &fe2, &fe3, &fe4, &fe5},
418 {n1, n2, n3, n4, n5}),
419 FETools::Compositing::compute_nonzero_components<dim, spacedim>(
420 {&fe1, &fe2, &fe3, &fe4, &fe5},
421 {n1, n2, n3, n4, n5}))
422 , base_elements(static_cast<int>(n1 > 0) + static_cast<int>(n2 > 0) +
423 static_cast<int>(n3 > 0) + static_cast<int>(n4 > 0) +
424 static_cast<int>(n5 > 0))
425{
426 const std::vector<const FiniteElement<dim, spacedim> *> fes = {
427 &fe1, &fe2, &fe3, &fe4, &fe5};
428 const std::vector<unsigned int> multiplicities = {n1, n2, n3, n4, n5};
429 initialize(fes, multiplicities);
430}
431
432
433
434template <int dim, int spacedim>
436 const std::vector<const FiniteElement<dim, spacedim> *> &fes,
437 const std::vector<unsigned int> &multiplicities)
438 : FiniteElement<dim, spacedim>(
439 FETools::Compositing::multiply_dof_numbers(fes, multiplicities),
441 fes,
442 multiplicities),
443 FETools::Compositing::compute_nonzero_components(fes, multiplicities))
444 , base_elements(count_nonzeros(multiplicities))
445{
446 initialize(fes, multiplicities);
447}
448
449
450
451template <int dim, int spacedim>
452std::string
454{
455 // note that the
456 // FETools::get_fe_by_name
457 // function depends on the
458 // particular format of the string
459 // this function returns, so they
460 // have to be kept in synch
461
462 std::ostringstream namebuf;
463
464 namebuf << "FESystem<" << Utilities::dim_string(dim, spacedim) << ">[";
465 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
466 {
467 namebuf << base_element(i).get_name();
468 if (this->element_multiplicity(i) != 1)
469 namebuf << '^' << this->element_multiplicity(i);
470 if (i != this->n_base_elements() - 1)
471 namebuf << '-';
472 }
473 namebuf << ']';
474
475 return namebuf.str();
476}
477
478
479
480template <int dim, int spacedim>
481std::unique_ptr<FiniteElement<dim, spacedim>>
483{
484 std::vector<const FiniteElement<dim, spacedim> *> fes;
485 std::vector<unsigned int> multiplicities;
486
487 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
488 {
489 fes.push_back(&base_element(i));
490 multiplicities.push_back(this->element_multiplicity(i));
491 }
492 return std::make_unique<FESystem<dim, spacedim>>(fes, multiplicities);
493}
494
495
496
497template <int dim, int spacedim>
500 const unsigned int first_component,
501 const unsigned int n_selected_components) const
502{
503 Assert(first_component + n_selected_components <= this->n_components(),
504 ExcMessage("Invalid arguments (not a part of this FiniteElement)."));
505
506 // If we are asked to select all components, just return the current element:
507 if ((first_component == 0) && (n_selected_components == this->n_components()))
508 return *this;
509
510 // Otherwise, it should be a sub-element:
511 const unsigned int base_index =
512 this->component_to_base_table[first_component].first.first;
513 const unsigned int component_in_base =
514 this->component_to_base_table[first_component].first.second;
515 const unsigned int base_components =
516 this->base_element(base_index).n_components();
517
518 if (n_selected_components <= base_components)
519 return this->base_element(base_index)
520 .get_sub_fe(component_in_base, n_selected_components);
521 else
522 {
523 Assert(false,
524 ExcMessage("You can not select " +
525 std::to_string(n_selected_components) +
526 " components starting at component " +
527 std::to_string(first_component) +
528 " because these components are not jointly a "
529 "sub-element of the current element. Sub-elements "
530 "are the elements provided to the constructor "
531 "of FESystem."));
533 }
534}
535
536
537
538template <int dim, int spacedim>
539double
540FESystem<dim, spacedim>::shape_value(const unsigned int i,
541 const Point<dim> &p) const
542{
543 AssertIndexRange(i, this->n_dofs_per_cell());
544 Assert(this->is_primitive(i),
546 i)));
547
548 return (base_element(this->system_to_base_table[i].first.first)
549 .shape_value(this->system_to_base_table[i].second, p));
550}
551
552
553
554template <int dim, int spacedim>
555double
557 const unsigned int i,
558 const Point<dim> &p,
559 const unsigned int component) const
560{
561 AssertIndexRange(i, this->n_dofs_per_cell());
562 AssertIndexRange(component, this->n_components());
563
564 // if this value is supposed to be
565 // zero, then return right away...
566 if (this->nonzero_components[i][component] == false)
567 return 0;
568
569 // ...otherwise: first find out to
570 // which of the base elements this
571 // desired component belongs, and
572 // which component within this base
573 // element it is
574 const unsigned int base = this->component_to_base_index(component).first;
575 const unsigned int component_in_base =
576 this->component_to_base_index(component).second;
577
578 // then get value from base
579 // element. note that that will
580 // throw an error should the
581 // respective shape function not be
582 // primitive; thus, there is no
583 // need to check this here
584 return (base_element(base).shape_value_component(
585 this->system_to_base_table[i].second, p, component_in_base));
586}
587
588
589
590template <int dim, int spacedim>
592FESystem<dim, spacedim>::shape_grad(const unsigned int i,
593 const Point<dim> &p) const
594{
595 AssertIndexRange(i, this->n_dofs_per_cell());
596 Assert(this->is_primitive(i),
598 i)));
599
600 return (base_element(this->system_to_base_table[i].first.first)
601 .shape_grad(this->system_to_base_table[i].second, p));
602}
603
604
605
606template <int dim, int spacedim>
609 const unsigned int i,
610 const Point<dim> &p,
611 const unsigned int component) const
612{
613 AssertIndexRange(i, this->n_dofs_per_cell());
614 AssertIndexRange(component, this->n_components());
615
616 // if this value is supposed to be zero, then return right away...
617 if (this->nonzero_components[i][component] == false)
618 return Tensor<1, dim>();
619
620 // ...otherwise: first find out to which of the base elements this desired
621 // component belongs, and which component within this base element it is
622 const unsigned int base = this->component_to_base_index(component).first;
623 const unsigned int component_in_base =
624 this->component_to_base_index(component).second;
625
626 // then get value from base element. note that that will throw an error
627 // should the respective shape function not be primitive; thus, there is no
628 // need to check this here
629 return (base_element(base).shape_grad_component(
630 this->system_to_base_table[i].second, p, component_in_base));
631}
632
633
634
635template <int dim, int spacedim>
638 const Point<dim> &p) const
639{
640 AssertIndexRange(i, this->n_dofs_per_cell());
641 Assert(this->is_primitive(i),
643 i)));
644
645 return (base_element(this->system_to_base_table[i].first.first)
646 .shape_grad_grad(this->system_to_base_table[i].second, p));
647}
648
649
650
651template <int dim, int spacedim>
654 const unsigned int i,
655 const Point<dim> &p,
656 const unsigned int component) const
657{
658 AssertIndexRange(i, this->n_dofs_per_cell());
659 AssertIndexRange(component, this->n_components());
660
661 // if this value is supposed to be zero, then return right away...
662 if (this->nonzero_components[i][component] == false)
663 return Tensor<2, dim>();
664
665 // ...otherwise: first find out to which of the base elements this desired
666 // component belongs, and which component within this base element it is
667 const unsigned int base = this->component_to_base_index(component).first;
668 const unsigned int component_in_base =
669 this->component_to_base_index(component).second;
670
671 // then get value from base element. note that that will throw an error
672 // should the respective shape function not be primitive; thus, there is no
673 // need to check this here
674 return (base_element(base).shape_grad_grad_component(
675 this->system_to_base_table[i].second, p, component_in_base));
676}
677
678
679
680template <int dim, int spacedim>
683 const Point<dim> &p) const
684{
685 AssertIndexRange(i, this->n_dofs_per_cell());
686 Assert(this->is_primitive(i),
688 i)));
689
690 return (base_element(this->system_to_base_table[i].first.first)
691 .shape_3rd_derivative(this->system_to_base_table[i].second, p));
692}
693
694
695
696template <int dim, int spacedim>
699 const unsigned int i,
700 const Point<dim> &p,
701 const unsigned int component) const
702{
703 AssertIndexRange(i, this->n_dofs_per_cell());
704 AssertIndexRange(component, this->n_components());
705
706 // if this value is supposed to be zero, then return right away...
707 if (this->nonzero_components[i][component] == false)
708 return Tensor<3, dim>();
709
710 // ...otherwise: first find out to which of the base elements this desired
711 // component belongs, and which component within this base element it is
712 const unsigned int base = this->component_to_base_index(component).first;
713 const unsigned int component_in_base =
714 this->component_to_base_index(component).second;
715
716 // then get value from base element. note that that will throw an error
717 // should the respective shape function not be primitive; thus, there is no
718 // need to check this here
719 return (base_element(base).shape_3rd_derivative_component(
720 this->system_to_base_table[i].second, p, component_in_base));
721}
722
723
724
725template <int dim, int spacedim>
728 const Point<dim> &p) const
729{
730 AssertIndexRange(i, this->n_dofs_per_cell());
731 Assert(this->is_primitive(i),
733 i)));
734
735 return (base_element(this->system_to_base_table[i].first.first)
736 .shape_4th_derivative(this->system_to_base_table[i].second, p));
737}
738
739
740
741template <int dim, int spacedim>
744 const unsigned int i,
745 const Point<dim> &p,
746 const unsigned int component) const
747{
748 AssertIndexRange(i, this->n_dofs_per_cell());
749 AssertIndexRange(component, this->n_components());
750
751 // if this value is supposed to be zero, then return right away...
752 if (this->nonzero_components[i][component] == false)
753 return Tensor<4, dim>();
754
755 // ...otherwise: first find out to which of the base elements this desired
756 // component belongs, and which component within this base element it is
757 const unsigned int base = this->component_to_base_index(component).first;
758 const unsigned int component_in_base =
759 this->component_to_base_index(component).second;
760
761 // then get value from base element. note that that will throw an error
762 // should the respective shape function not be primitive; thus, there is no
763 // need to check this here
764 return (base_element(base).shape_4th_derivative_component(
765 this->system_to_base_table[i].second, p, component_in_base));
766}
767
768
769
770template <int dim, int spacedim>
771void
773 const FiniteElement<dim, spacedim> &x_source_fe,
774 FullMatrix<double> &interpolation_matrix) const
775{
776 // check that the size of the matrices is correct. for historical
777 // reasons, if you call matrix.reinit(8,0), it sets the sizes
778 // to m==n==0 internally. this may happen when we use a FE_Nothing,
779 // so write the test in a more lenient way
780 Assert((interpolation_matrix.m() == this->n_dofs_per_cell()) ||
781 (x_source_fe.n_dofs_per_cell() == 0),
782 ExcDimensionMismatch(interpolation_matrix.m(),
783 this->n_dofs_per_cell()));
784 Assert((interpolation_matrix.n() == x_source_fe.n_dofs_per_cell()) ||
785 (this->n_dofs_per_cell() == 0),
786 ExcDimensionMismatch(interpolation_matrix.m(),
787 x_source_fe.n_dofs_per_cell()));
788
789 // there are certain conditions that the two elements have to satisfy so
790 // that this can work.
791 //
792 // condition 1: the other element must also be a system element
793
795 (x_source_fe.get_name().find("FESystem<") == 0) ||
796 (dynamic_cast<const FESystem<dim, spacedim> *>(&x_source_fe) != nullptr),
798
799 // ok, source is a system element, so we may be able to do the work
800 const FESystem<dim, spacedim> &source_fe =
801 dynamic_cast<const FESystem<dim, spacedim> &>(x_source_fe);
802
803 // condition 2: same number of basis elements
805 this->n_base_elements() == source_fe.n_base_elements(),
807
808 // condition 3: same number of basis elements
809 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
811 this->element_multiplicity(i) == source_fe.element_multiplicity(i),
812 (typename FiniteElement<dim,
813 spacedim>::ExcInterpolationNotImplemented()));
814
815 // ok, so let's try whether it works:
816
817 // first let's see whether all the basis elements actually generate their
818 // interpolation matrices. if we get past the following loop, then
819 // apparently none of the called base elements threw an exception, so we're
820 // fine continuing and assembling the one big matrix from the small ones of
821 // the base elements
822 std::vector<FullMatrix<double>> base_matrices(this->n_base_elements());
823 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
824 {
825 base_matrices[i].reinit(base_element(i).n_dofs_per_cell(),
826 source_fe.base_element(i).n_dofs_per_cell());
827 base_element(i).get_interpolation_matrix(source_fe.base_element(i),
828 base_matrices[i]);
829 }
830
831 // first clear big matrix, to make sure that entries that would couple
832 // different bases (or multiplicity indices) are really zero. then assign
833 // entries
834 interpolation_matrix = 0;
835 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
836 for (unsigned int j = 0; j < source_fe.n_dofs_per_cell(); ++j)
837 if (this->system_to_base_table[i].first ==
838 source_fe.system_to_base_table[j].first)
839 interpolation_matrix(i, j) =
840 (base_matrices[this->system_to_base_table[i].first.first](
841 this->system_to_base_table[i].second,
842 source_fe.system_to_base_table[j].second));
843}
844
845
846
847template <int dim, int spacedim>
848const FullMatrix<double> &
850 const unsigned int child,
851 const RefinementCase<dim> &refinement_case) const
852{
853 AssertIndexRange(refinement_case,
857 "Restriction matrices are only available for refined cells!"));
858 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
859
860
861
862 // initialization upon first request
863 if (this->restriction[refinement_case - 1][child].n() == 0)
864 {
865 std::scoped_lock lock(restriction_matrix_mutex);
866
867 // check if updated while waiting for lock
868 if (this->restriction[refinement_case - 1][child].n() ==
869 this->n_dofs_per_cell())
870 return this->restriction[refinement_case - 1][child];
871
872 // shortcut for accessing local restrictions further down
873 std::vector<const FullMatrix<double> *> base_matrices(
874 this->n_base_elements());
875
876 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
877 {
878 base_matrices[i] =
879 &base_element(i).get_restriction_matrix(child, refinement_case);
880
881 Assert(base_matrices[i]->n() == base_element(i).n_dofs_per_cell(),
883 }
884
885 FullMatrix<double> restriction(this->n_dofs_per_cell(),
886 this->n_dofs_per_cell());
887
888 // distribute the matrices of the base finite elements to the
889 // matrices of this object. for this, loop over all degrees of
890 // freedom and take the respective entry of the underlying base
891 // element.
892 //
893 // note that we by definition of a base element, they are
894 // independent, i.e. do not couple. only DoFs that belong to the
895 // same instance of a base element may couple
896 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
897 for (unsigned int j = 0; j < this->n_dofs_per_cell(); ++j)
898 {
899 // first find out to which base element indices i and j
900 // belong, and which instance thereof in case the base element
901 // has a multiplicity greater than one. if they should not
902 // happen to belong to the same instance of a base element,
903 // then they cannot couple, so go on with the next index
904 if (this->system_to_base_table[i].first !=
905 this->system_to_base_table[j].first)
906 continue;
907
908 // so get the common base element and the indices therein:
909 const unsigned int base = this->system_to_base_table[i].first.first;
910
911 const unsigned int base_index_i =
912 this->system_to_base_table[i].second,
913 base_index_j =
914 this->system_to_base_table[j].second;
915
916 // if we are sure that DoFs i and j may couple, then copy
917 // entries of the matrices:
918 restriction(i, j) =
919 (*base_matrices[base])(base_index_i, base_index_j);
920 }
921
922 const_cast<FullMatrix<double> &>(
923 this->restriction[refinement_case - 1][child]) = std::move(restriction);
924 }
925
926 return this->restriction[refinement_case - 1][child];
927}
928
929
930
931template <int dim, int spacedim>
932const FullMatrix<double> &
934 const unsigned int child,
935 const RefinementCase<dim> &refinement_case) const
936{
937 AssertIndexRange(refinement_case,
941 "Restriction matrices are only available for refined cells!"));
942 AssertIndexRange(child, this->reference_cell().n_children(refinement_case));
943
944 // initialization upon first request, construction completely analogous to
945 // restriction matrix
946 if (this->prolongation[refinement_case - 1][child].n() == 0)
947 {
948 std::scoped_lock lock(prolongation_matrix_mutex);
949
950 if (this->prolongation[refinement_case - 1][child].n() ==
951 this->n_dofs_per_cell())
952 return this->prolongation[refinement_case - 1][child];
953
954 std::vector<const FullMatrix<double> *> base_matrices(
955 this->n_base_elements());
956 for (unsigned int i = 0; i < this->n_base_elements(); ++i)
957 {
958 base_matrices[i] =
959 &base_element(i).get_prolongation_matrix(child, refinement_case);
960
961 Assert(base_matrices[i]->n() == base_element(i).n_dofs_per_cell(),
963 }
964
965 FullMatrix<double> prolongate(this->n_dofs_per_cell(),
966 this->n_dofs_per_cell());
967
968 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
969 for (unsigned int j = 0; j < this->n_dofs_per_cell(); ++j)
970 {
971 if (this->system_to_base_table[i].first !=
972 this->system_to_base_table[j].first)
973 continue;
974 const unsigned int base = this->system_to_base_table[i].first.first;
975
976 const unsigned int base_index_i =
977 this->system_to_base_table[i].second,
978 base_index_j =
979 this->system_to_base_table[j].second;
980 prolongate(i, j) =
981 (*base_matrices[base])(base_index_i, base_index_j);
982 }
983
984 const_cast<FullMatrix<double> &>(
985 this->prolongation[refinement_case - 1][child]) = std::move(prolongate);
986 }
987
988 return this->prolongation[refinement_case - 1][child];
989}
990
991
992template <int dim, int spacedim>
993unsigned int
995 const unsigned int face_dof_index,
996 const unsigned int face,
997 const types::geometric_orientation combined_orientation) const
998{
999 // we need to ask the base elements how they want to translate
1000 // the DoFs within their own numbering. thus, translate to
1001 // the base element numbering and then back
1002 const std::pair<std::pair<unsigned int, unsigned int>, unsigned int>
1003 face_base_index = this->face_system_to_base_index(face_dof_index, face);
1004
1005 const unsigned int base_face_to_cell_index =
1006 this->base_element(face_base_index.first.first)
1007 .face_to_cell_index(face_base_index.second, face, combined_orientation);
1008
1009 // it would be nice if we had a base_to_system_index function, but
1010 // all that exists is a component_to_system_index function. we can't do
1011 // this here because it won't work for non-primitive elements. consequently,
1012 // simply do a loop over all dofs till we find whether it corresponds
1013 // to the one we're interested in -- crude, maybe, but works for now
1014 const std::pair<std::pair<unsigned int, unsigned int>, unsigned int> target =
1015 std::make_pair(face_base_index.first, base_face_to_cell_index);
1016 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
1017 if (this->system_to_base_index(i) == target)
1018 return i;
1019
1022}
1023
1024
1025
1026//---------------------------------------------------------------------------
1027// Data field initialization
1028//---------------------------------------------------------------------------
1029
1030
1031
1032template <int dim, int spacedim>
1035{
1037 // generate maximal set of flags
1038 // that are necessary
1039 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1040 out |= base_element(base_no).requires_update_flags(flags);
1041 return out;
1042}
1043
1044
1045
1046template <int dim, int spacedim>
1047std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1049 const UpdateFlags flags,
1050 const Mapping<dim, spacedim> &mapping,
1051 const Quadrature<dim> &quadrature,
1053 spacedim>
1054 & /*output_data*/) const
1055{
1056 // create an internal data object and set the update flags we will need
1057 // to deal with. the current object does not make use of these flags,
1058 // but we need to nevertheless set them correctly since we look
1059 // into the update_each flag of base elements in fill_fe_values,
1060 // and so the current object's update_each flag needs to be
1061 // correct in case the current FESystem is a base element for another,
1062 // higher-level FESystem itself.
1063 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1064 data_ptr = std::make_unique<InternalData>(this->n_base_elements());
1065 auto &data = dynamic_cast<InternalData &>(*data_ptr);
1066 data.update_each = requires_update_flags(flags);
1067
1068 // get data objects from each of the base elements and store
1069 // them. one might think that doing this in parallel (over the
1070 // base elements) would be a good idea, but this turns out to
1071 // be wrong because we would then run these jobs on different
1072 // threads/processors and this allocates memory in different
1073 // NUMA domains; this has large detrimental effects when later
1074 // writing into these objects in fill_fe_*_values. all of this
1075 // is particularly true when using FEValues objects in
1076 // WorkStream contexts where we explicitly make sure that
1077 // every function only uses objects previously allocated
1078 // in the same NUMA context and on the same thread as the
1079 // function is called
1080 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1081 {
1083 &base_fe_output_object = data.get_fe_output_object(base_no);
1084 base_fe_output_object.initialize(
1085 quadrature.size(),
1086 base_element(base_no),
1087 flags | base_element(base_no).requires_update_flags(flags));
1088
1089 // let base objects produce their scratch objects. they may
1090 // also at this time write into the output objects we provide
1091 // for them; it would be nice if we could already copy something
1092 // out of the base output object into the system output object,
1093 // but we can't because we can't know what the elements already
1094 // copied and/or will want to update on every cell
1095 auto base_fe_data = base_element(base_no).get_data(flags,
1096 mapping,
1097 quadrature,
1098 base_fe_output_object);
1099
1100 data.set_fe_data(base_no, std::move(base_fe_data));
1101 }
1102
1103 return data_ptr;
1104}
1105
1106// The following function is a clone of get_data, with the exception
1107// that get_face_data of the base elements is called.
1108
1109template <int dim, int spacedim>
1110std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1112 const UpdateFlags flags,
1113 const Mapping<dim, spacedim> &mapping,
1114 const hp::QCollection<dim - 1> &quadrature,
1116 spacedim>
1117 & /*output_data*/) const
1118{
1119 // create an internal data object and set the update flags we will need
1120 // to deal with. the current object does not make use of these flags,
1121 // but we need to nevertheless set them correctly since we look
1122 // into the update_each flag of base elements in fill_fe_values,
1123 // and so the current object's update_each flag needs to be
1124 // correct in case the current FESystem is a base element for another,
1125 // higher-level FESystem itself.
1126 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1127 data_ptr = std::make_unique<InternalData>(this->n_base_elements());
1128 auto &data = dynamic_cast<InternalData &>(*data_ptr);
1129 data.update_each = requires_update_flags(flags);
1130
1131 // get data objects from each of the base elements and store
1132 // them. one might think that doing this in parallel (over the
1133 // base elements) would be a good idea, but this turns out to
1134 // be wrong because we would then run these jobs on different
1135 // threads/processors and this allocates memory in different
1136 // NUMA domains; this has large detrimental effects when later
1137 // writing into these objects in fill_fe_*_values. all of this
1138 // is particularly true when using FEValues objects in
1139 // WorkStream contexts where we explicitly make sure that
1140 // every function only uses objects previously allocated
1141 // in the same NUMA context and on the same thread as the
1142 // function is called
1143 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1144 {
1146 &base_fe_output_object = data.get_fe_output_object(base_no);
1147 base_fe_output_object.initialize(
1148 quadrature.max_n_quadrature_points(),
1149 base_element(base_no),
1150 flags | base_element(base_no).requires_update_flags(flags));
1151
1152 // let base objects produce their scratch objects. they may
1153 // also at this time write into the output objects we provide
1154 // for them; it would be nice if we could already copy something
1155 // out of the base output object into the system output object,
1156 // but we can't because we can't know what the elements already
1157 // copied and/or will want to update on every cell
1158 auto base_fe_data = base_element(base_no).get_face_data(
1159 flags, mapping, quadrature, base_fe_output_object);
1160
1161 data.set_fe_data(base_no, std::move(base_fe_data));
1162 }
1163
1164 return data_ptr;
1165}
1166
1167
1168
1169// The following function is a clone of get_data, with the exception
1170// that get_subface_data of the base elements is called.
1171
1172template <int dim, int spacedim>
1173std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1175 const UpdateFlags flags,
1176 const Mapping<dim, spacedim> &mapping,
1177 const Quadrature<dim - 1> &quadrature,
1179 spacedim>
1180 & /*output_data*/) const
1181{
1182 // create an internal data object and set the update flags we will need
1183 // to deal with. the current object does not make use of these flags,
1184 // but we need to nevertheless set them correctly since we look
1185 // into the update_each flag of base elements in fill_fe_values,
1186 // and so the current object's update_each flag needs to be
1187 // correct in case the current FESystem is a base element for another,
1188 // higher-level FESystem itself.
1189 std::unique_ptr<typename FiniteElement<dim, spacedim>::InternalDataBase>
1190 data_ptr = std::make_unique<InternalData>(this->n_base_elements());
1191 auto &data = dynamic_cast<InternalData &>(*data_ptr);
1192
1193 data.update_each = requires_update_flags(flags);
1194
1195 // get data objects from each of the base elements and store
1196 // them. one might think that doing this in parallel (over the
1197 // base elements) would be a good idea, but this turns out to
1198 // be wrong because we would then run these jobs on different
1199 // threads/processors and this allocates memory in different
1200 // NUMA domains; this has large detrimental effects when later
1201 // writing into these objects in fill_fe_*_values. all of this
1202 // is particularly true when using FEValues objects in
1203 // WorkStream contexts where we explicitly make sure that
1204 // every function only uses objects previously allocated
1205 // in the same NUMA context and on the same thread as the
1206 // function is called
1207 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1208 {
1210 &base_fe_output_object = data.get_fe_output_object(base_no);
1211 base_fe_output_object.initialize(
1212 quadrature.size(),
1213 base_element(base_no),
1214 flags | base_element(base_no).requires_update_flags(flags));
1215
1216 // let base objects produce their scratch objects. they may
1217 // also at this time write into the output objects we provide
1218 // for them; it would be nice if we could already copy something
1219 // out of the base output object into the system output object,
1220 // but we can't because we can't know what the elements already
1221 // copied and/or will want to update on every cell
1222 auto base_fe_data = base_element(base_no).get_subface_data(
1223 flags, mapping, quadrature, base_fe_output_object);
1224
1225 data.set_fe_data(base_no, std::move(base_fe_data));
1226 }
1227
1228 return data_ptr;
1229}
1230
1231
1232
1233template <int dim, int spacedim>
1234void
1237 const CellSimilarity::Similarity cell_similarity,
1238 const Quadrature<dim> &quadrature,
1239 const Mapping<dim, spacedim> &mapping,
1240 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_internal,
1242 &mapping_data,
1243 const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
1245 spacedim>
1246 &output_data) const
1247{
1248 compute_fill(mapping,
1249 cell,
1250 invalid_face_number,
1251 invalid_face_number,
1252 quadrature,
1253 cell_similarity,
1254 mapping_internal,
1255 fe_internal,
1256 mapping_data,
1257 output_data);
1258}
1259
1260
1261
1262template <int dim, int spacedim>
1263void
1266 const unsigned int face_no,
1267 const hp::QCollection<dim - 1> &quadrature,
1268 const Mapping<dim, spacedim> &mapping,
1269 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_internal,
1271 &mapping_data,
1272 const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
1274 spacedim>
1275 &output_data) const
1276{
1277 compute_fill(mapping,
1278 cell,
1279 face_no,
1280 invalid_face_number,
1281 quadrature,
1283 mapping_internal,
1284 fe_internal,
1285 mapping_data,
1286 output_data);
1287}
1288
1289
1290
1291template <int dim, int spacedim>
1292void
1295 const unsigned int face_no,
1296 const unsigned int sub_no,
1297 const Quadrature<dim - 1> &quadrature,
1298 const Mapping<dim, spacedim> &mapping,
1299 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_internal,
1301 &mapping_data,
1302 const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
1304 spacedim>
1305 &output_data) const
1306{
1307 compute_fill(mapping,
1308 cell,
1309 face_no,
1310 sub_no,
1311 quadrature,
1313 mapping_internal,
1314 fe_internal,
1315 mapping_data,
1316 output_data);
1317}
1318
1319
1320
1321template <int dim, int spacedim>
1322template <class Q_or_QC>
1323void
1325 const Mapping<dim, spacedim> &mapping,
1327 const unsigned int face_no,
1328 const unsigned int sub_no,
1329 const Q_or_QC &quadrature,
1330 const CellSimilarity::Similarity cell_similarity,
1331 const typename Mapping<dim, spacedim>::InternalDataBase &mapping_internal,
1332 const typename FiniteElement<dim, spacedim>::InternalDataBase &fe_internal,
1334 &mapping_data,
1336 &output_data) const
1337{
1338 // convert data object to internal
1339 // data for this class. fails with
1340 // an exception if that is not
1341 // possible
1342 Assert(dynamic_cast<const InternalData *>(&fe_internal) != nullptr,
1344 const InternalData &fe_data = static_cast<const InternalData &>(fe_internal);
1345
1346 const UpdateFlags flags = fe_data.update_each;
1347
1348
1349 // loop over the base elements, let them compute what they need to compute,
1350 // and then copy what is necessary.
1351 //
1352 // one may think that it would be a good idea to parallelize this over
1353 // base elements, but it turns out to be not worthwhile: doing so lets
1354 // multiple threads access data objects that were created by the current
1355 // thread, leading to many NUMA memory access inefficiencies. we specifically
1356 // want to avoid this if this class is called in a WorkStream context where
1357 // we very carefully allocate objects only on the thread where they
1358 // will actually be used; spawning new tasks here would be counterproductive
1361 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1362 {
1363 const FiniteElement<dim, spacedim> &base_fe = base_element(base_no);
1364 typename FiniteElement<dim, spacedim>::InternalDataBase &base_fe_data =
1365 fe_data.get_fe_data(base_no);
1367 spacedim>
1368 &base_data = fe_data.get_fe_output_object(base_no);
1369
1370 // If we have mixed meshes we need to support a QCollection here, hence
1371 // this pointer casting workaround:
1372 const Quadrature<dim> *cell_quadrature = nullptr;
1373 const hp::QCollection<dim - 1> *face_quadrature = nullptr;
1374 const Quadrature<dim - 1> *sub_face_quadrature = nullptr;
1375 unsigned int n_q_points = numbers::invalid_unsigned_int;
1376
1377 // static cast through the common base class:
1378 if (face_no == invalid_face_number)
1379 {
1380 cell_quadrature =
1381 dynamic_cast<const Quadrature<dim> *>(&quadrature);
1382 Assert(cell_quadrature != nullptr, ExcInternalError());
1383 n_q_points = cell_quadrature->size();
1384 }
1385 else if (sub_no == invalid_face_number)
1386 {
1387 // If we don't have wedges or pyramids then there should only be one
1388 // quadrature rule here
1389 face_quadrature =
1390 dynamic_cast<const hp::QCollection<dim - 1> *>(&quadrature);
1391 Assert(face_quadrature != nullptr, ExcInternalError());
1392
1393 n_q_points =
1394 (*face_quadrature)[face_quadrature->size() == 1 ? 0 : face_no]
1395 .size();
1396 }
1397 else
1398 {
1399 sub_face_quadrature =
1400 dynamic_cast<const Quadrature<dim - 1> *>(&quadrature);
1401 Assert(sub_face_quadrature != nullptr, ExcInternalError());
1402
1403 n_q_points = sub_face_quadrature->size();
1404 }
1406
1407
1408 // Make sure that in the case of fill_fe_values the data is only
1409 // copied from base_data to data if base_data is changed. therefore
1410 // use fe_fe_data.current_update_flags()
1411 //
1412 // for the case of fill_fe_(sub)face_values the data needs to be
1413 // copied from base_data to data on each face, therefore use
1414 // base_fe_data.update_flags.
1415 if (face_no == invalid_face_number)
1416 base_fe.fill_fe_values(cell,
1417 cell_similarity,
1418 *cell_quadrature,
1419 mapping,
1420 mapping_internal,
1421 mapping_data,
1422 base_fe_data,
1423 base_data);
1424 else if (sub_no == invalid_face_number)
1425 base_fe.fill_fe_face_values(cell,
1426 face_no,
1427 *face_quadrature,
1428 mapping,
1429 mapping_internal,
1430 mapping_data,
1431 base_fe_data,
1432 base_data);
1433 else
1434 base_fe.fill_fe_subface_values(cell,
1435 face_no,
1436 sub_no,
1437 *sub_face_quadrature,
1438 mapping,
1439 mapping_internal,
1440 mapping_data,
1441 base_fe_data,
1442 base_data);
1443
1444 // now data has been generated, so copy it. This procedure is different
1445 // for primitive and non-primitive base elements, so at this point we
1446 // dispatch to helper functions.
1447 const UpdateFlags base_flags = base_fe_data.update_each;
1448
1449 if (base_fe.is_primitive())
1450 {
1452 *this,
1453 base_no,
1454 base_flags,
1455 primitive_offset_tables[base_no],
1456 base_data,
1457 output_data);
1458 }
1459 else
1460 {
1462 *this,
1463 base_no,
1464 n_q_points,
1465 base_flags,
1466 nonprimitive_offset_tables[base_no],
1467 base_data,
1468 output_data);
1469 }
1470 }
1471}
1472
1473
1474template <int dim, int spacedim>
1475void
1477{
1478 // check whether all base elements implement their interface constraint
1479 // matrices. if this is not the case, then leave the interface constraints of
1480 // this composed element empty as well; however, the rest of the element is
1481 // usable
1482 for (unsigned int base = 0; base < this->n_base_elements(); ++base)
1483 if (base_element(base).constraints_are_implemented() == false)
1484 return;
1485
1486 // TODO: the implementation makes the assumption that all faces have the
1487 // same number of dofs
1488 AssertDimension(this->n_unique_faces(), 1);
1489 const unsigned int face_no = 0;
1490
1491 this->interface_constraints.TableBase<2, double>::reinit(
1492 this->interface_constraints_size());
1493
1494 // the layout of the constraints matrix is described in the FiniteElement
1495 // class. you may want to look there first before trying to understand the
1496 // following, especially the mapping of the @p{m} index.
1497 //
1498 // in order to map it to the fe-system class, we have to know which base
1499 // element a degree of freedom within a vertex, line, etc belongs to. this
1500 // can be accomplished by the system_to_component_index function in
1501 // conjunction with the numbers first_{line,quad,...}_index
1502 for (unsigned int n = 0; n < this->interface_constraints.n(); ++n)
1503 for (unsigned int m = 0; m < this->interface_constraints.m(); ++m)
1504 {
1505 // for the pair (n,m) find out which base element they belong to and
1506 // the number therein
1507 //
1508 // first for the n index. this is simple since the n indices are in
1509 // the same order as they are usually on a face. note that for the
1510 // data type, first value in pair is (base element,instance of base
1511 // element), second is index within this instance
1512 const std::pair<std::pair<unsigned int, unsigned int>, unsigned int>
1513 n_index = this->face_system_to_base_table[face_no][n];
1514
1515 // likewise for the m index. this is more complicated due to the
1516 // strange ordering we have for the dofs on the refined faces.
1517 std::pair<std::pair<unsigned int, unsigned int>, unsigned int> m_index;
1518 switch (dim)
1519 {
1520 case 1:
1521 {
1522 // we should never get here! (in 1d, the constraints matrix
1523 // should be of size zero)
1525 break;
1526 }
1527
1528 case 2:
1529 {
1530 // the indices m=0..d_v-1 are from the center vertex. their
1531 // order is the same as for the first vertex of the whole cell,
1532 // so we can use the system_to_base_table variable (using the
1533 // face_s_t_base_t function would yield the same)
1534 if (m < this->n_dofs_per_vertex())
1535 m_index = this->system_to_base_table[m];
1536 else
1537 // then come the two sets of line indices
1538 {
1539 const unsigned int index_in_line =
1540 (m - this->n_dofs_per_vertex()) % this->n_dofs_per_line();
1541 const unsigned int sub_line =
1542 (m - this->n_dofs_per_vertex()) / this->n_dofs_per_line();
1543 Assert(sub_line < 2, ExcInternalError());
1544
1545 // from this information, try to get base element and
1546 // instance of base element. we do so by constructing the
1547 // corresponding face index of m in the present element,
1548 // then use face_system_to_base_table
1549 const unsigned int tmp1 =
1550 2 * this->n_dofs_per_vertex() + index_in_line;
1551 m_index.first =
1552 this->face_system_to_base_table[face_no][tmp1].first;
1553
1554 // what we are still missing is the index of m within the
1555 // base elements interface_constraints table
1556 //
1557 // here, the second value of face_system_to_base_table can
1558 // help: it denotes the face index of that shape function
1559 // within the base element. since we know that it is a line
1560 // dof, we can construct the rest: tmp2 will denote the
1561 // index of this shape function among the line shape
1562 // functions:
1563 Assert(
1564 this->face_system_to_base_table[face_no][tmp1].second >=
1565 2 *
1566 base_element(m_index.first.first).n_dofs_per_vertex(),
1568 const unsigned int tmp2 =
1569 this->face_system_to_base_table[face_no][tmp1].second -
1570 2 * base_element(m_index.first.first).n_dofs_per_vertex();
1571 Assert(tmp2 < base_element(m_index.first.first)
1572 .n_dofs_per_line(),
1574 m_index.second =
1575 base_element(m_index.first.first).n_dofs_per_vertex() +
1576 base_element(m_index.first.first).n_dofs_per_line() *
1577 sub_line +
1578 tmp2;
1579 }
1580 break;
1581 }
1582
1583 case 3:
1584 {
1585 Assert(this->reference_cell() ==
1586 ReferenceCells::get_hypercube<dim>(),
1588
1589 // same way as above, although a little more complicated...
1590
1591 // the indices m=0..5*d_v-1 are from the center and the four
1592 // subline vertices. their order is the same as for the first
1593 // vertex of the whole cell, so we can use the simple arithmetic
1594 if (m < 5 * this->n_dofs_per_vertex())
1595 m_index = this->system_to_base_table[m];
1596 else
1597 // then come the 12 sets of line indices
1598 if (m < 5 * this->n_dofs_per_vertex() +
1599 12 * this->n_dofs_per_line())
1600 {
1601 // for the meaning of all this, see the 2d part
1602 const unsigned int index_in_line =
1603 (m - 5 * this->n_dofs_per_vertex()) %
1604 this->n_dofs_per_line();
1605 const unsigned int sub_line =
1606 (m - 5 * this->n_dofs_per_vertex()) /
1607 this->n_dofs_per_line();
1608 Assert(sub_line < 12, ExcInternalError());
1609
1610 const unsigned int tmp1 =
1611 4 * this->n_dofs_per_vertex() + index_in_line;
1612 m_index.first =
1613 this->face_system_to_base_table[face_no][tmp1].first;
1614
1615 Assert(
1616 this->face_system_to_base_table[face_no][tmp1].second >=
1617 4 * base_element(m_index.first.first)
1618 .n_dofs_per_vertex(),
1620 const unsigned int tmp2 =
1621 this->face_system_to_base_table[face_no][tmp1].second -
1622 4 *
1623 base_element(m_index.first.first).n_dofs_per_vertex();
1624 Assert(tmp2 < base_element(m_index.first.first)
1625 .n_dofs_per_line(),
1627 m_index.second =
1628 5 * base_element(m_index.first.first)
1629 .n_dofs_per_vertex() +
1630 base_element(m_index.first.first).n_dofs_per_line() *
1631 sub_line +
1632 tmp2;
1633 }
1634 else
1635 // on one of the four sub-quads
1636 {
1637 // for the meaning of all this, see the 2d part
1638 const unsigned int index_in_quad =
1639 (m - 5 * this->n_dofs_per_vertex() -
1640 12 * this->n_dofs_per_line()) %
1641 this->n_dofs_per_quad(face_no);
1642 Assert(index_in_quad < this->n_dofs_per_quad(face_no),
1644 const unsigned int sub_quad =
1645 ((m - 5 * this->n_dofs_per_vertex() -
1646 12 * this->n_dofs_per_line()) /
1647 this->n_dofs_per_quad(face_no));
1648 Assert(sub_quad < 4, ExcInternalError());
1649
1650 const unsigned int tmp1 = 4 * this->n_dofs_per_vertex() +
1651 4 * this->n_dofs_per_line() +
1652 index_in_quad;
1653 Assert(tmp1 <
1654 this->face_system_to_base_table[face_no].size(),
1656 m_index.first =
1657 this->face_system_to_base_table[face_no][tmp1].first;
1658
1659 Assert(
1660 this->face_system_to_base_table[face_no][tmp1].second >=
1661 4 * base_element(m_index.first.first)
1662 .n_dofs_per_vertex() +
1663 4 * base_element(m_index.first.first)
1664 .n_dofs_per_line(),
1666 const unsigned int tmp2 =
1667 this->face_system_to_base_table[face_no][tmp1].second -
1668 4 * base_element(m_index.first.first)
1669 .n_dofs_per_vertex() -
1670 4 * base_element(m_index.first.first).n_dofs_per_line();
1671 Assert(tmp2 < base_element(m_index.first.first)
1672 .n_dofs_per_quad(face_no),
1674 m_index.second =
1675 5 * base_element(m_index.first.first)
1676 .n_dofs_per_vertex() +
1677 12 *
1678 base_element(m_index.first.first).n_dofs_per_line() +
1679 base_element(m_index.first.first)
1680 .n_dofs_per_quad(face_no) *
1681 sub_quad +
1682 tmp2;
1683 }
1684
1685 break;
1686 }
1687
1688 default:
1690 }
1691
1692 // now that we gathered all information: use it to build the
1693 // matrix. note that if n and m belong to different base elements or
1694 // instances, then there definitely will be no coupling
1695 if (n_index.first == m_index.first)
1696 this->interface_constraints(m, n) =
1697 (base_element(n_index.first.first)
1698 .constraints()(m_index.second, n_index.second));
1699 }
1700}
1701
1702
1703
1704template <int dim, int spacedim>
1705void
1707 const std::vector<const FiniteElement<dim, spacedim> *> &fes,
1708 const std::vector<unsigned int> &multiplicities)
1709{
1710 Assert(fes.size() == multiplicities.size(),
1711 ExcDimensionMismatch(fes.size(), multiplicities.size()));
1712 Assert(fes.size() > 0,
1713 ExcMessage("Need to pass at least one finite element."));
1714 Assert(count_nonzeros(multiplicities) > 0,
1715 ExcMessage("You only passed FiniteElements with multiplicity 0."));
1716
1717 const ReferenceCell reference_cell = fes.front()->reference_cell();
1718 Assert(std::all_of(fes.begin(),
1719 fes.end(),
1720 [reference_cell](const FiniteElement<dim, spacedim> *fe) {
1721 return fe->reference_cell() == reference_cell;
1722 }),
1723 ExcMessage("You cannot combine finite elements defined on "
1724 "different reference cells into a combined element "
1725 "such as an FESystem or FE_Enriched object."));
1726
1727 // Note that we need to skip every FE with multiplicity 0 in the following
1728 // block of code
1729
1730 this->base_to_block_indices.reinit(0, 0);
1731
1732 for (unsigned int i = 0; i < fes.size(); ++i)
1733 if (multiplicities[i] > 0)
1734 this->base_to_block_indices.push_back(multiplicities[i]);
1735
1736 {
1737 Threads::TaskGroup<> clone_base_elements;
1738
1739 unsigned int ind = 0;
1740 for (unsigned int i = 0; i < fes.size(); ++i)
1741 if (multiplicities[i] > 0)
1742 {
1743 clone_base_elements += Threads::new_task([&, i, ind]() {
1744 base_elements[ind] = {fes[i]->clone(), multiplicities[i]};
1745 });
1746 ++ind;
1747 }
1748 Assert(ind > 0, ExcInternalError());
1749
1750 // wait for all of these clone operations to finish
1751 clone_base_elements.join_all();
1752 }
1753
1754
1755 {
1756 // If the system is not primitive, these have not been initialized by
1757 // FiniteElement
1758 this->system_to_component_table.resize(this->n_dofs_per_cell());
1759
1760 FETools::Compositing::build_cell_tables(this->system_to_base_table,
1761 this->system_to_component_table,
1762 this->component_to_base_table,
1763 *this);
1764
1765 this->face_system_to_component_table.resize(this->n_unique_faces());
1766
1767 for (unsigned int face_no = 0; face_no < this->n_unique_faces(); ++face_no)
1768 {
1769 this->face_system_to_component_table[face_no].resize(
1770 this->n_dofs_per_face(face_no));
1771
1773 this->face_system_to_base_table[face_no],
1774 this->face_system_to_component_table[face_no],
1775 *this,
1776 true,
1777 face_no);
1778 }
1779 }
1780
1781 // now initialize interface constraints, support points, and other tables.
1782 // (restriction and prolongation matrices are only built on demand.) do
1783 // this in parallel
1784
1785 Threads::TaskGroup<> init_tasks;
1786
1787 init_tasks +=
1788 Threads::new_task([&]() { this->build_interface_constraints(); });
1789
1790 init_tasks += Threads::new_task([&]() {
1791 // if one of the base elements has no support points, then it makes no sense
1792 // to define support points for the composed element, so return an empty
1793 // array to demonstrate that fact. Note that we ignore FE_Nothing in this
1794 // logic.
1795 for (unsigned int base_el = 0; base_el < this->n_base_elements(); ++base_el)
1796 if (!base_element(base_el).has_support_points() &&
1797 base_element(base_el).n_dofs_per_cell() != 0)
1798 {
1799 this->unit_support_points.resize(0);
1800 return;
1801 }
1802
1803 // generate unit support points from unit support points of sub elements
1804 this->unit_support_points.resize(this->n_dofs_per_cell());
1805
1806 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
1807 {
1808 const unsigned int base = this->system_to_base_table[i].first.first,
1809 base_index = this->system_to_base_table[i].second;
1810 // Do not use `this` in Assert because nvcc when using C++20 assumes
1811 // that `this` is an integer and we get the following error: base
1812 // operand of '->' is not a pointer
1813 const unsigned int n_base_elements = this->n_base_elements();
1814 Assert(base < n_base_elements, ExcInternalError());
1815 Assert(base_index < base_element(base).unit_support_points.size(),
1817 this->unit_support_points[i] =
1818 base_element(base).unit_support_points[base_index];
1819 }
1820 });
1821
1822 init_tasks += Threads::new_task([&]() {
1823 primitive_offset_tables.resize(this->n_base_elements());
1824
1825 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1826 if (base_element(base_no).is_primitive())
1827 primitive_offset_tables[base_no] =
1829 });
1830
1831 init_tasks += Threads::new_task([&]() {
1832 nonprimitive_offset_tables.resize(this->n_base_elements());
1833
1834 for (unsigned int base_no = 0; base_no < this->n_base_elements(); ++base_no)
1835 if (!base_element(base_no).is_primitive())
1836 nonprimitive_offset_tables[base_no] =
1838 });
1839
1840 // initialize face support points (for dim==2,3). same procedure as above
1841 if (dim > 1)
1842 init_tasks += Threads::new_task([&]() {
1843 for (unsigned int face_no = 0; face_no < this->n_unique_faces();
1844 ++face_no)
1845 {
1846 // if one of the base elements has no support points, then it makes
1847 // no sense to define support points for the composed element. In
1848 // that case, return an empty array to demonstrate that fact (note
1849 // that we ask whether the base element has no support points at
1850 // all, not only none on the face!)
1851 //
1852 // on the other hand, if there is an element that simply has no
1853 // degrees of freedom on the face at all, then we don't care whether
1854 // it has support points or not. this is, for example, the case for
1855 // the stable Stokes element Q(p)^dim \times DGP(p-1).
1856 bool flag_has_no_support_points = false;
1857
1858 for (unsigned int base_el = 0; base_el < this->n_base_elements();
1859 ++base_el)
1860 if (!base_element(base_el).has_support_points() &&
1861 (base_element(base_el).n_dofs_per_face(face_no) > 0))
1862 {
1863 this->unit_face_support_points[face_no].resize(0);
1864 flag_has_no_support_points = true;
1865 break;
1866 }
1867
1868
1869 if (flag_has_no_support_points)
1870 continue;
1871
1872 // generate unit face support points from unit support points of sub
1873 // elements
1874 this->unit_face_support_points[face_no].resize(
1875 this->n_dofs_per_face(face_no));
1876
1877 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
1878 {
1879 const unsigned int base_i =
1880 this->face_system_to_base_table[face_no][i].first.first;
1881 const unsigned int index_in_base =
1882 this->face_system_to_base_table[face_no][i].second;
1883
1884 Assert(
1885 index_in_base <
1886 base_element(base_i).unit_face_support_points[face_no].size(),
1888
1889 this->unit_face_support_points[face_no][i] =
1890 base_element(base_i)
1891 .unit_face_support_points[face_no][index_in_base];
1892 }
1893 }
1894 });
1895
1896 // Initialize generalized support points and an (internal) index table
1897 init_tasks += Threads::new_task([&]() {
1898 // Iterate over all base elements, extract a representative set of
1899 // _unique_ generalized support points and store the information how
1900 // generalized support points of base elements are mapped to this list
1901 // of representatives. Complexity O(n^2), where n is the number of
1902 // generalized support points.
1903
1904 generalized_support_points_index_table.resize(this->n_base_elements());
1905
1906 for (unsigned int base = 0; base < this->n_base_elements(); ++base)
1907 {
1908 // If the current base element does not have generalized support
1909 // points, ignore it. Note that
1910 // * FESystem::convert_generalized_support_point_values_to_dof_values
1911 // will simply skip such non-interpolatory base elements by
1912 // assigning NaN to all dofs.
1913 // * If this routine does not pick up any generalized support
1914 // points the corresponding vector will be empty and
1915 // FiniteElement::has_generalized_support_points will return
1916 // false.
1917 if (!base_element(base).has_generalized_support_points())
1918 continue;
1919
1920 for (const auto &point :
1921 base_element(base).get_generalized_support_points())
1922 {
1923 // Is point already an element of generalized_support_points?
1924 const auto p =
1925 std::find(std::begin(this->generalized_support_points),
1926 std::end(this->generalized_support_points),
1927 point);
1928
1929 if (p == std::end(this->generalized_support_points))
1930 {
1931 // If no, update the table and add the point to the vector
1932 const auto n = this->generalized_support_points.size();
1933 generalized_support_points_index_table[base].push_back(n);
1934 this->generalized_support_points.push_back(point);
1935 }
1936 else
1937 {
1938 // If yes, just add the correct index to the table.
1939 const auto n = p - std::begin(this->generalized_support_points);
1940 generalized_support_points_index_table[base].push_back(n);
1941 }
1942 }
1943 }
1944
1945 if constexpr (running_in_debug_mode())
1946 {
1947 // check generalized_support_points_index_table for consistency
1948 for (unsigned int i = 0; i < base_elements.size(); ++i)
1949 {
1950 if (!base_element(i).has_generalized_support_points())
1951 continue;
1952
1953 const auto &points =
1954 base_elements[i].first->get_generalized_support_points();
1955 for (unsigned int j = 0; j < points.size(); ++j)
1956 {
1957 const auto n = generalized_support_points_index_table[i][j];
1958 Assert(this->generalized_support_points[n] == points[j],
1960 }
1961 }
1962 } /* DEBUG */
1963 });
1964
1965 // initialize quad dof index permutation in 3d and higher
1966 if (dim >= 3)
1967 init_tasks += Threads::new_task([&]() {
1968 for (unsigned int face_no = 0; face_no < this->n_unique_faces();
1969 ++face_no)
1970 {
1971 // the array into which we want to write should have the correct size
1972 // already.
1973 // Do not use `this` in Assert because nvcc when using C++20 assumes
1974 // that `this` is an integer and we get the following error: base
1975 // operand of '->' is not a pointer
1976 const unsigned int n_elements =
1977 this->adjust_quad_dof_index_for_face_orientation_table[face_no]
1978 .n_elements();
1979 const unsigned int n_face_orientations =
1980 this->reference_cell().n_face_orientations(face_no);
1981 const unsigned int n_dofs_per_quad = this->n_dofs_per_quad(face_no);
1982 Assert(n_elements == n_face_orientations * n_dofs_per_quad,
1984
1985 // to obtain the shifts for this composed element, copy the shift
1986 // information of the base elements
1987 unsigned int index = 0;
1988 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
1989 {
1990 const Table<2, int> &temp =
1991 this->base_element(b)
1992 .adjust_quad_dof_index_for_face_orientation_table[face_no];
1993 for (unsigned int c = 0; c < this->element_multiplicity(b); ++c)
1994 {
1995 for (unsigned int i = 0; i < temp.size(0); ++i)
1996 for (unsigned int j = 0;
1997 j <
1998 this->reference_cell().n_face_orientations(face_no);
1999 ++j)
2000 this->adjust_quad_dof_index_for_face_orientation_table
2001 [face_no](index + i, j) = temp(i, j);
2002 index += temp.size(0);
2003 }
2004 }
2005 Assert(index == n_dofs_per_quad, ExcInternalError());
2006 }
2007 });
2008
2009 if (dim > 1)
2010 init_tasks += Threads::new_task([&]() {
2011 // additionally compose the permutation information for lines
2012 // Do not use `this` in Assert because nvcc when using C++20 assumes that
2013 // `this` is an integer and we get the following error: base operand of
2014 // '->' is not a pointer
2015 const unsigned int table_size =
2016 this->adjust_line_dof_index_for_line_orientation_table.size();
2017 const unsigned int n_dofs_per_line = this->n_dofs_per_line();
2018 Assert(table_size == n_dofs_per_line, ExcInternalError());
2019 unsigned int index = 0;
2020 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2021 {
2022 const std::vector<int> &temp2 =
2023 this->base_element(b)
2024 .adjust_line_dof_index_for_line_orientation_table;
2025 for (unsigned int c = 0; c < this->element_multiplicity(b); ++c)
2026 {
2027 std::copy(
2028 temp2.begin(),
2029 temp2.end(),
2030 this->adjust_line_dof_index_for_line_orientation_table.begin() +
2031 index);
2032 index += temp2.size();
2033 }
2034 }
2035 Assert(index == n_dofs_per_line, ExcInternalError());
2036 });
2037
2038
2039 // Compute local_dof_sparsity_pattern if any of our base elements contains a
2040 // non-empty one (empty denotes the default of all DoFs coupling within a
2041 // cell). Note the we currently only handle coupling within a base element and
2042 // not between two different base elements. Handling the latter could be
2043 // doable if the underlying element happens to be identical, but we currently
2044 // have no functionality to compute the coupling between different elements
2045 // with a pattern (for example FE_Q_iso_Q1 with different degrees).
2046 {
2047 // Does any of our base elements not couple all DoFs?
2048 const bool have_nonempty = [&]() -> bool {
2049 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2050 {
2051 if (!this->base_element(b).get_local_dof_sparsity_pattern().empty() &&
2052 (this->element_multiplicity(b) > 0))
2053 return true;
2054 }
2055 return false;
2056 }();
2057
2058 if (have_nonempty)
2059 {
2060 this->local_dof_sparsity_pattern.reinit(this->n_dofs_per_cell(),
2061 this->n_dofs_per_cell());
2062
2063 // by default, everything couples:
2064 this->local_dof_sparsity_pattern.fill(true);
2065
2066 // Find shape functions within the same base element. If we do, grab the
2067 // coupling from that base element pattern:
2068 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
2069 for (unsigned int j = 0; j < this->n_dofs_per_cell(); ++j)
2070 {
2071 const auto vi = this->system_to_base_index(i);
2072 const auto vj = this->system_to_base_index(j);
2073
2074 const auto base_index_i = vi.first.first;
2075 const auto base_index_j = vj.first.first;
2076 if (base_index_i == base_index_j)
2077 {
2078 const auto shape_index_i = vi.second;
2079 const auto shape_index_j = vj.second;
2080
2081 const auto &pattern = this->base_element(base_index_i)
2082 .get_local_dof_sparsity_pattern();
2083
2084 if (!pattern.empty())
2085 this->local_dof_sparsity_pattern(i, j) =
2086 pattern(shape_index_i, shape_index_j);
2087 }
2088 }
2089 }
2090 }
2091
2092
2093 // wait for all of this to finish
2094 init_tasks.join_all();
2095}
2096
2097
2098
2099template <int dim, int spacedim>
2100bool
2102{
2103 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2104 if (base_element(b).hp_constraints_are_implemented() == false)
2105 return false;
2106
2107 return true;
2108}
2109
2110
2111
2112template <int dim, int spacedim>
2113void
2115 const FiniteElement<dim, spacedim> &x_source_fe,
2116 FullMatrix<double> &interpolation_matrix,
2117 const unsigned int face_no) const
2118{
2119 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
2120 ExcDimensionMismatch(interpolation_matrix.n(),
2121 this->n_dofs_per_face(face_no)));
2122 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
2123 ExcDimensionMismatch(interpolation_matrix.m(),
2124 x_source_fe.n_dofs_per_face(face_no)));
2125
2126 // since dofs for each base are independent, we only have to stack things up
2127 // from base element to base element
2128 //
2129 // the problem is that we have to work with two FEs (this and
2130 // fe_other). only deal with the case that both are FESystems and that they
2131 // both have the same number of bases (counting multiplicity) each of which
2132 // match in their number of components. this covers
2133 // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
2134 // FESystem(FE_Q(p),1,FE_Q(q),2) vs
2135 // FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
2136 if (const auto *fe_other_system =
2137 dynamic_cast<const FESystem<dim, spacedim> *>(&x_source_fe))
2138 {
2139 // clear matrix, since we will not get to set all elements
2140 interpolation_matrix = 0;
2141
2142 // loop over all the base elements of this and the other element, counting
2143 // their multiplicities
2144 unsigned int base_index = 0, base_index_other = 0;
2145 unsigned int multiplicity = 0, multiplicity_other = 0;
2146
2147 FullMatrix<double> base_to_base_interpolation;
2148
2149 while (true)
2150 {
2151 const FiniteElement<dim, spacedim> &base = base_element(base_index),
2152 &base_other =
2153 fe_other_system->base_element(
2154 base_index_other);
2155
2156 Assert(base.n_components() == base_other.n_components(),
2158
2159 // get the interpolation from the bases
2160 base_to_base_interpolation.reinit(base_other.n_dofs_per_face(face_no),
2161 base.n_dofs_per_face(face_no));
2162 base.get_face_interpolation_matrix(base_other,
2163 base_to_base_interpolation,
2164 face_no);
2165
2166 // now translate entries. we'd like to have something like
2167 // face_base_to_system_index, but that doesn't exist. rather, all we
2168 // have is the reverse. well, use that then
2169 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
2170 if (this->face_system_to_base_index(i, face_no).first ==
2171 std::make_pair(base_index, multiplicity))
2172 for (unsigned int j = 0;
2173 j < fe_other_system->n_dofs_per_face(face_no);
2174 ++j)
2175 if (fe_other_system->face_system_to_base_index(j, face_no)
2176 .first ==
2177 std::make_pair(base_index_other, multiplicity_other))
2178 interpolation_matrix(j, i) = base_to_base_interpolation(
2179 fe_other_system->face_system_to_base_index(j, face_no)
2180 .second,
2181 this->face_system_to_base_index(i, face_no).second);
2182
2183 // advance to the next base element for this and the other fe_system;
2184 // see if we can simply advance the multiplicity by one, or if have to
2185 // move on to the next base element
2186 ++multiplicity;
2187 if (multiplicity == this->element_multiplicity(base_index))
2188 {
2189 multiplicity = 0;
2190 ++base_index;
2191 }
2192 ++multiplicity_other;
2193 if (multiplicity_other ==
2194 fe_other_system->element_multiplicity(base_index_other))
2195 {
2196 multiplicity_other = 0;
2197 ++base_index_other;
2198 }
2199
2200 // see if we have reached the end of the present element. if so, we
2201 // should have reached the end of the other one as well
2202 if (base_index == this->n_base_elements())
2203 {
2204 Assert(base_index_other == fe_other_system->n_base_elements(),
2206 break;
2207 }
2208
2209 // if we haven't reached the end of this element, we shouldn't have
2210 // reached the end of the other one either
2211 Assert(base_index_other != fe_other_system->n_base_elements(),
2213 }
2214 }
2215 else
2216 {
2217 // repeat the cast to make the exception message more useful
2219 (dynamic_cast<const FESystem<dim, spacedim> *>(&x_source_fe) !=
2220 nullptr),
2221 (typename FiniteElement<dim,
2222 spacedim>::ExcInterpolationNotImplemented()));
2223 }
2224}
2225
2226
2227
2228template <int dim, int spacedim>
2229void
2231 const FiniteElement<dim, spacedim> &x_source_fe,
2232 const unsigned int subface,
2233 FullMatrix<double> &interpolation_matrix,
2234 const unsigned int face_no) const
2235{
2237 (x_source_fe.get_name().find("FESystem<") == 0) ||
2238 (dynamic_cast<const FESystem<dim, spacedim> *>(&x_source_fe) != nullptr),
2240
2241 Assert(interpolation_matrix.n() == this->n_dofs_per_face(face_no),
2242 ExcDimensionMismatch(interpolation_matrix.n(),
2243 this->n_dofs_per_face(face_no)));
2244 Assert(interpolation_matrix.m() == x_source_fe.n_dofs_per_face(face_no),
2245 ExcDimensionMismatch(interpolation_matrix.m(),
2246 x_source_fe.n_dofs_per_face(face_no)));
2247
2248 // since dofs for each base are independent, we only have to stack things up
2249 // from base element to base element
2250 //
2251 // the problem is that we have to work with two FEs (this and
2252 // fe_other). only deal with the case that both are FESystems and that they
2253 // both have the same number of bases (counting multiplicity) each of which
2254 // match in their number of components. this covers
2255 // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
2256 // FESystem(FE_Q(p),1,FE_Q(q),2) vs
2257 // FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
2258 const FESystem<dim, spacedim> *fe_other_system =
2259 dynamic_cast<const FESystem<dim, spacedim> *>(&x_source_fe);
2260 if (fe_other_system != nullptr)
2261 {
2262 // clear matrix, since we will not get to set all elements
2263 interpolation_matrix = 0;
2264
2265 // loop over all the base elements of this and the other element, counting
2266 // their multiplicities
2267 unsigned int base_index = 0, base_index_other = 0;
2268 unsigned int multiplicity = 0, multiplicity_other = 0;
2269
2270 FullMatrix<double> base_to_base_interpolation;
2271
2272 while (true)
2273 {
2274 const FiniteElement<dim, spacedim> &base = base_element(base_index),
2275 &base_other =
2276 fe_other_system->base_element(
2277 base_index_other);
2278
2279 Assert(base.n_components() == base_other.n_components(),
2281
2282 // get the interpolation from the bases
2283 base_to_base_interpolation.reinit(base_other.n_dofs_per_face(face_no),
2284 base.n_dofs_per_face(face_no));
2285 base.get_subface_interpolation_matrix(base_other,
2286 subface,
2287 base_to_base_interpolation,
2288 face_no);
2289
2290 // now translate entries. we'd like to have something like
2291 // face_base_to_system_index, but that doesn't exist. rather, all we
2292 // have is the reverse. well, use that then
2293 for (unsigned int i = 0; i < this->n_dofs_per_face(face_no); ++i)
2294 if (this->face_system_to_base_index(i, face_no).first ==
2295 std::make_pair(base_index, multiplicity))
2296 for (unsigned int j = 0;
2297 j < fe_other_system->n_dofs_per_face(face_no);
2298 ++j)
2299 if (fe_other_system->face_system_to_base_index(j, face_no)
2300 .first ==
2301 std::make_pair(base_index_other, multiplicity_other))
2302 interpolation_matrix(j, i) = base_to_base_interpolation(
2303 fe_other_system->face_system_to_base_index(j, face_no)
2304 .second,
2305 this->face_system_to_base_index(i, face_no).second);
2306
2307 // advance to the next base element for this and the other fe_system;
2308 // see if we can simply advance the multiplicity by one, or if have to
2309 // move on to the next base element
2310 ++multiplicity;
2311 if (multiplicity == this->element_multiplicity(base_index))
2312 {
2313 multiplicity = 0;
2314 ++base_index;
2315 }
2316 ++multiplicity_other;
2317 if (multiplicity_other ==
2318 fe_other_system->element_multiplicity(base_index_other))
2319 {
2320 multiplicity_other = 0;
2321 ++base_index_other;
2322 }
2323
2324 // see if we have reached the end of the present element. if so, we
2325 // should have reached the end of the other one as well
2326 if (base_index == this->n_base_elements())
2327 {
2328 Assert(base_index_other == fe_other_system->n_base_elements(),
2330 break;
2331 }
2332
2333 // if we haven't reached the end of this element, we shouldn't have
2334 // reached the end of the other one either
2335 Assert(base_index_other != fe_other_system->n_base_elements(),
2337 }
2338 }
2339 else
2340 {
2341 // we should have caught this at the start, but check again anyway
2342 Assert(
2343 fe_other_system != nullptr,
2344 (typename FiniteElement<dim,
2345 spacedim>::ExcInterpolationNotImplemented()));
2346 }
2347}
2348
2349
2350
2351template <int dim, int spacedim>
2352template <int structdim>
2353std::vector<std::pair<unsigned int, unsigned int>>
2355 const FiniteElement<dim, spacedim> &fe_other,
2356 const unsigned int face_no) const
2357{
2358 // since dofs on each subobject (vertex, line, ...) are ordered such that
2359 // first come all from the first base element all multiplicities, then
2360 // second base element all multiplicities, etc., we simply have to stack all
2361 // the identities after each other
2362 //
2363 // the problem is that we have to work with two FEs (this and
2364 // fe_other). only deal with the case that both are FESystems and that they
2365 // both have the same number of bases (counting multiplicity) each of which
2366 // match in their number of components. this covers
2367 // FESystem(FE_Q(p),1,FE_Q(q),2) vs FESystem(FE_Q(r),2,FE_Q(s),1), but not
2368 // FESystem(FE_Q(p),1,FE_Q(q),2) vs
2369 // FESystem(FESystem(FE_Q(r),2),1,FE_Q(s),1)
2370 if (const FESystem<dim, spacedim> *fe_other_system =
2371 dynamic_cast<const FESystem<dim, spacedim> *>(&fe_other))
2372 {
2373 // loop over all the base elements of this and the other element,
2374 // counting their multiplicities
2375 unsigned int base_index = 0, base_index_other = 0;
2376 unsigned int multiplicity = 0, multiplicity_other = 0;
2377
2378 // we also need to keep track of the number of dofs already treated for
2379 // each of the elements
2380 unsigned int dof_offset = 0, dof_offset_other = 0;
2381
2382 std::vector<std::pair<unsigned int, unsigned int>> identities;
2383
2384 while (true)
2385 {
2386 const FiniteElement<dim, spacedim> &base = base_element(base_index),
2387 &base_other =
2388 fe_other_system->base_element(
2389 base_index_other);
2390
2391 Assert(base.n_components() == base_other.n_components(),
2393
2394 // now translate the identities returned by the base elements to the
2395 // indices of this system element
2396 std::vector<std::pair<unsigned int, unsigned int>> base_identities;
2397 switch (structdim)
2398 {
2399 case 0:
2400 base_identities = base.hp_vertex_dof_identities(base_other);
2401 break;
2402 case 1:
2403 base_identities = base.hp_line_dof_identities(base_other);
2404 break;
2405 case 2:
2406 base_identities =
2407 base.hp_quad_dof_identities(base_other, face_no);
2408 break;
2409 default:
2411 }
2412
2413 for (const auto &base_identity : base_identities)
2414 identities.emplace_back(base_identity.first + dof_offset,
2415 base_identity.second + dof_offset_other);
2416
2417 // record the dofs treated above as already taken care of
2418 dof_offset += base.template n_dofs_per_object<structdim>();
2419 dof_offset_other +=
2420 base_other.template n_dofs_per_object<structdim>();
2421
2422 // advance to the next base element for this and the other
2423 // fe_system; see if we can simply advance the multiplicity by one,
2424 // or if have to move on to the next base element
2425 ++multiplicity;
2426 if (multiplicity == this->element_multiplicity(base_index))
2427 {
2428 multiplicity = 0;
2429 ++base_index;
2430 }
2431 ++multiplicity_other;
2432 if (multiplicity_other ==
2433 fe_other_system->element_multiplicity(base_index_other))
2434 {
2435 multiplicity_other = 0;
2436 ++base_index_other;
2437 }
2438
2439 // see if we have reached the end of the present element. if so, we
2440 // should have reached the end of the other one as well
2441 if (base_index == this->n_base_elements())
2442 {
2443 Assert(base_index_other == fe_other_system->n_base_elements(),
2445 break;
2446 }
2447
2448 // if we haven't reached the end of this element, we shouldn't have
2449 // reached the end of the other one either
2450 Assert(base_index_other != fe_other_system->n_base_elements(),
2452 }
2453
2454 return identities;
2455 }
2456 else
2457 {
2459 return std::vector<std::pair<unsigned int, unsigned int>>();
2460 }
2461}
2462
2463
2464
2465template <int dim, int spacedim>
2466std::vector<std::pair<unsigned int, unsigned int>>
2468 const FiniteElement<dim, spacedim> &fe_other) const
2469{
2470 return hp_object_dof_identities<0>(fe_other);
2471}
2472
2473template <int dim, int spacedim>
2474std::vector<std::pair<unsigned int, unsigned int>>
2476 const FiniteElement<dim, spacedim> &fe_other) const
2477{
2478 return hp_object_dof_identities<1>(fe_other);
2479}
2480
2481
2482
2483template <int dim, int spacedim>
2484std::vector<std::pair<unsigned int, unsigned int>>
2486 const FiniteElement<dim, spacedim> &fe_other,
2487 const unsigned int face_no) const
2488{
2489 return hp_object_dof_identities<2>(fe_other, face_no);
2490}
2491
2492
2493
2494template <int dim, int spacedim>
2497 const FiniteElement<dim, spacedim> &fe_other,
2498 const unsigned int codim) const
2499{
2500 Assert(codim <= dim, ExcImpossibleInDim(dim));
2501
2502 // vertex/line/face/cell domination
2503 // --------------------------------
2504 if (const FESystem<dim, spacedim> *fe_sys_other =
2505 dynamic_cast<const FESystem<dim, spacedim> *>(&fe_other))
2506 {
2507 Assert(this->n_components() == fe_sys_other->n_components(),
2508 ExcMessage("You can only compare two elements for domination "
2509 "that have the same number of vector components. The "
2510 "current element has " +
2511 std::to_string(this->n_components()) +
2512 " vector components, and you are comparing it "
2513 "against an element with " +
2514 std::to_string(fe_sys_other->n_components()) +
2515 " vector components."));
2516
2519
2520 // If the two elements have the same number of base elements,
2521 // and the base elements have the same multiplicities, we can
2522 // get away with only comparing each of the bases:
2523 if ((this->n_base_elements() == fe_sys_other->n_base_elements()) &&
2524 // Use a lambda function to test whether all base elements have
2525 // the same multiplicity:
2526 [&]() {
2527 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2528 if (this->element_multiplicity(b) !=
2529 fe_sys_other->element_multiplicity(b))
2530 return false;
2531 return true;
2532 }())
2533 {
2534 for (unsigned int b = 0; b < this->n_base_elements(); ++b)
2535 {
2536 Assert(this->base_element(b).n_components() ==
2537 fe_sys_other->base_element(b).n_components(),
2539 // for this pair of base elements, check who dominates and combine
2540 // with previous result
2541 const FiniteElementDomination::Domination base_domination =
2542 (this->base_element(b).compare_for_domination(
2543 fe_sys_other->base_element(b), codim));
2544
2545 domination = domination & base_domination;
2546 }
2547 }
2548 else
2549 // The two elements do not line up either with their numbers of
2550 // base elements, or with the multiplicities of the base elements
2551 {
2552 for (unsigned int c = 0; c < this->n_components(); ++c)
2553 {
2554 const unsigned int base_element_index_in_fe_sys_this =
2555 this->component_to_base_index(c).first;
2556 const unsigned int base_element_index_in_fe_sys_other =
2557 fe_sys_other->component_to_base_index(c).first;
2558
2559 Assert(this->base_element(base_element_index_in_fe_sys_this)
2560 .n_components() ==
2561 fe_sys_other
2562 ->base_element(base_element_index_in_fe_sys_other)
2563 .n_components(),
2565
2566 // for this pair of base elements, check who dominates and combine
2567 // with previous result
2568 const FiniteElementDomination::Domination base_domination =
2569 (this->base_element(base_element_index_in_fe_sys_this)
2570 .compare_for_domination(
2571 fe_sys_other->base_element(
2572 base_element_index_in_fe_sys_other),
2573 codim));
2574
2575 domination = domination & base_domination;
2576 }
2577 }
2578
2579 return domination;
2580 }
2581
2584}
2585
2586
2587
2588template <int dim, int spacedim>
2590FESystem<dim, spacedim>::base_element(const unsigned int index) const
2591{
2592 AssertIndexRange(index, base_elements.size());
2593 return *base_elements[index].first;
2594}
2595
2596
2597
2598template <int dim, int spacedim>
2599bool
2601 const unsigned int shape_index,
2602 const unsigned int face_index) const
2603{
2604 return (base_element(this->system_to_base_index(shape_index).first.first)
2605 .has_support_on_face(this->system_to_base_index(shape_index).second,
2606 face_index));
2607}
2608
2609
2610
2611template <int dim, int spacedim>
2613FESystem<dim, spacedim>::unit_support_point(const unsigned int index) const
2614{
2615 AssertIndexRange(index, this->n_dofs_per_cell());
2616 Assert((this->unit_support_points.size() == this->n_dofs_per_cell()) ||
2617 (this->unit_support_points.empty()),
2619
2620 // let's see whether we have the information pre-computed
2621 if (this->unit_support_points.size() != 0)
2622 return this->unit_support_points[index];
2623 else
2624 // no. ask the base element whether it would like to provide this
2625 // information
2626 return (base_element(this->system_to_base_index(index).first.first)
2627 .unit_support_point(this->system_to_base_index(index).second));
2628}
2629
2630
2631
2632template <int dim, int spacedim>
2633Point<dim - 1>
2635 const unsigned int index,
2636 const unsigned int face_no) const
2637{
2638 AssertIndexRange(index, this->n_dofs_per_face(face_no));
2639 Assert(
2640 (this->unit_face_support_points[this->n_unique_faces() == 1 ? 0 : face_no]
2641 .size() == this->n_dofs_per_face(face_no)) ||
2642 (this->unit_face_support_points[this->n_unique_faces() == 1 ? 0 : face_no]
2643 .empty()),
2644 (typename FiniteElement<dim, spacedim>::ExcFEHasNoSupportPoints()));
2645
2646 // let's see whether we have the information pre-computed
2647 if (this->unit_face_support_points[this->n_unique_faces() == 1 ? 0 : face_no]
2648 .size() != 0)
2649 return this
2650 ->unit_face_support_points[this->n_unique_faces() == 1 ? 0 : face_no]
2651 [index];
2652 else
2653 // no. ask the base element whether it would like to provide this
2654 // information
2655 return (
2656 base_element(this->face_system_to_base_index(index, face_no).first.first)
2657 .unit_face_support_point(
2658 this->face_system_to_base_index(index, face_no).second, face_no));
2659}
2660
2661
2662
2663template <int dim, int spacedim>
2664std::pair<Table<2, bool>, std::vector<unsigned int>>
2666{
2667 // Note that this->n_components() is actually only an estimate of how many
2668 // constant modes we will need. There might be more than one such mode
2669 // (e.g. FE_Q_DG0).
2670 Table<2, bool> constant_modes(this->n_components(), this->n_dofs_per_cell());
2671 std::vector<unsigned int> components;
2672 for (unsigned int i = 0; i < base_elements.size(); ++i)
2673 {
2674 const std::pair<Table<2, bool>, std::vector<unsigned int>> base_table =
2675 base_elements[i].first->get_constant_modes();
2676 AssertDimension(base_table.first.n_rows(), base_table.second.size());
2677 const unsigned int element_multiplicity = this->element_multiplicity(i);
2678
2679 // there might be more than one constant mode for some scalar elements,
2680 // so make sure the table actually fits: Create a new table with more
2681 // rows
2682 const unsigned int comp = components.size();
2683 if (constant_modes.n_rows() <
2684 comp + base_table.first.n_rows() * element_multiplicity)
2685 {
2686 Table<2, bool> new_constant_modes(comp + base_table.first.n_rows() *
2687 element_multiplicity,
2688 constant_modes.n_cols());
2689 for (unsigned int r = 0; r < comp; ++r)
2690 for (unsigned int c = 0; c < this->n_dofs_per_cell(); ++c)
2691 new_constant_modes(r, c) = constant_modes(r, c);
2692
2693 constant_modes = std::move(new_constant_modes);
2694 }
2695
2696 // next, fill the constant modes from the individual components as well
2697 // as the component numbers corresponding to the constant mode rows
2698 for (unsigned int k = 0; k < this->n_dofs_per_cell(); ++k)
2699 {
2700 std::pair<std::pair<unsigned int, unsigned int>, unsigned int> ind =
2701 this->system_to_base_index(k);
2702 if (ind.first.first == i)
2703 for (unsigned int c = 0; c < base_table.first.n_rows(); ++c)
2704 constant_modes(comp +
2705 ind.first.second * base_table.first.n_rows() + c,
2706 k) = base_table.first(c, ind.second);
2707 }
2708 for (unsigned int r = 0; r < element_multiplicity; ++r)
2709 for (const unsigned int c : base_table.second)
2710 components.push_back(
2711 comp + r * this->base_elements[i].first->n_components() + c);
2712 }
2713 AssertDimension(components.size(), constant_modes.n_rows());
2714 return std::pair<Table<2, bool>, std::vector<unsigned int>>(constant_modes,
2715 components);
2716}
2717
2718
2719
2720template <int dim, int spacedim>
2721void
2723 const std::vector<Vector<double>> &point_values,
2724 std::vector<double> &dof_values) const
2725{
2726 Assert(this->has_generalized_support_points(),
2727 ExcMessage("The FESystem does not have generalized support points"));
2728
2730 this->get_generalized_support_points().size());
2731 AssertDimension(dof_values.size(), this->n_dofs_per_cell());
2732
2733 std::vector<double> base_dof_values;
2734 std::vector<Vector<double>> base_point_values;
2735
2736 // loop over all base elements (respecting multiplicity) and let them do
2737 // the work on their share of the input argument
2738
2739 unsigned int current_vector_component = 0;
2740 for (unsigned int base = 0; base < base_elements.size(); ++base)
2741 {
2742 // We need access to the base_element, its multiplicity, the
2743 // number of generalized support points (n_base_points) and the
2744 // number of components we're dealing with.
2745 const auto &base_element = this->base_element(base);
2746 const unsigned int multiplicity = this->element_multiplicity(base);
2747 const unsigned int n_base_dofs = base_element.n_dofs_per_cell();
2748 const unsigned int n_base_components = base_element.n_components();
2749
2750 // If the number of base degrees of freedom is zero, there is nothing
2751 // to do, skip the rest of the body in this case and continue with
2752 // the next element
2753 if (n_base_dofs == 0)
2754 {
2755 current_vector_component += multiplicity * n_base_components;
2756 continue;
2757 }
2758
2759 if (base_element.has_generalized_support_points())
2760 {
2761 const unsigned int n_base_points =
2762 base_element.get_generalized_support_points().size();
2763
2764 base_dof_values.resize(n_base_dofs);
2765 base_point_values.resize(n_base_points);
2766
2767 for (unsigned int m = 0; m < multiplicity;
2768 ++m, current_vector_component += n_base_components)
2769 {
2770 // populate base_point_values for a recursive call to
2771 // convert_generalized_support_point_values_to_dof_values
2772 for (unsigned int j = 0; j < base_point_values.size(); ++j)
2773 {
2774 base_point_values[j].reinit(n_base_components, false);
2775
2776 const auto n =
2777 generalized_support_points_index_table[base][j];
2778
2779 // we have to extract the correct slice out of the global
2780 // vector of values:
2781 const auto *const begin =
2782 std::begin(point_values[n]) + current_vector_component;
2783 const auto *const end = begin + n_base_components;
2784 std::copy(begin, end, std::begin(base_point_values[j]));
2785 }
2786
2787 base_element
2788 .convert_generalized_support_point_values_to_dof_values(
2789 base_point_values, base_dof_values);
2790
2791 // Finally put these dof values back into global dof values
2792 // vector.
2793
2794 // To do this, we could really use a base_to_system_index()
2795 // function, but that doesn't exist -- just do it by using the
2796 // reverse table -- the amount of work done here is not worth
2797 // trying to optimizing this.
2798 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
2799 if (this->system_to_base_index(i).first ==
2800 std::make_pair(base, m))
2801 dof_values[i] =
2802 base_dof_values[this->system_to_base_index(i).second];
2803 } /*for*/
2804 }
2805 else
2806 {
2807 // If the base element is non-interpolatory, assign NaN to all
2808 // DoFs associated to it.
2809
2810 // To do this, we could really use a base_to_system_index()
2811 // function, but that doesn't exist -- just do it by using the
2812 // reverse table -- the amount of work done here is not worth
2813 // trying to optimizing this.
2814 for (unsigned int m = 0; m < multiplicity; ++m)
2815 for (unsigned int i = 0; i < this->n_dofs_per_cell(); ++i)
2816 if (this->system_to_base_index(i).first ==
2817 std::make_pair(base, m))
2818 dof_values[i] = std::numeric_limits<double>::signaling_NaN();
2819
2820 current_vector_component += multiplicity * n_base_components;
2821 }
2822 } /*for*/
2823}
2824
2825
2826
2827template <int dim, int spacedim>
2828std::size_t
2830{
2831 // neglect size of data stored in @p{base_elements} due to some problems
2832 // with the compiler. should be neglectable after all, considering the size
2833 // of the data of the subelements
2835 sizeof(base_elements));
2836 for (unsigned int i = 0; i < base_elements.size(); ++i)
2837 mem += MemoryConsumption::memory_consumption(*base_elements[i].first);
2838 return mem;
2839}
2840
2841#endif
2842
2843// explicit instantiations
2844#include "fe/fe_system.inst"
2845
*  iterator end()
*  *  iterator begin()
***mech_lbc_system increment_interpolation_handlers push_back(scale_z_handler)
void set_fe_data(const unsigned int base_no, std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase >)
InternalData(const unsigned int n_base_elements)
std::vector< std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > > base_fe_datas
Definition fe_system.h:1309
FiniteElement< dim, spacedim >::InternalDataBase & get_fe_data(const unsigned int base_no) const
internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > & get_fe_output_object(const unsigned int base_no) const
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim > &quadrature, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
virtual Tensor< 2, dim > shape_grad_grad(const unsigned int i, const Point< dim > &p) const override
virtual const FiniteElement< dim, spacedim > & base_element(const unsigned int index) const override
FESystem()=delete
virtual Point< dim > unit_support_point(const unsigned int index) const override
virtual void fill_fe_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const typename FiniteElement< dim, spacedim >::InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
virtual Tensor< 3, dim > shape_3rd_derivative(const unsigned int i, const Point< dim > &p) const override
virtual std::string get_name() 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 const FiniteElement< dim, spacedim > & get_sub_fe(const unsigned int first_component, const unsigned int n_selected_components) const override
virtual Tensor< 1, dim > shape_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual UpdateFlags requires_update_flags(const UpdateFlags update_flags) 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
virtual FiniteElementDomination::Domination compare_for_domination(const FiniteElement< dim, spacedim > &fe_other, const unsigned int codim=0) const override final
virtual void fill_fe_face_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const hp::QCollection< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const typename FiniteElement< dim, spacedim >::InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_quad_dof_identities(const FiniteElement< dim, spacedim > &fe_other, const unsigned int face_no=0) const override
void compute_fill(const Mapping< dim, spacedim > &mapping, const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int sub_no, const Q_or_QC &quadrature, const CellSimilarity::Similarity cell_similarity, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const typename FiniteElement< dim, spacedim >::InternalDataBase &fe_data, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const
virtual Tensor< 3, dim > shape_3rd_derivative_component(const unsigned int i, const Point< dim > &p, const unsigned int component) 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 get_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix) const override
virtual Tensor< 1, dim > shape_grad(const unsigned int i, const Point< dim > &p) const override
virtual std::pair< Table< 2, bool >, std::vector< unsigned int > > get_constant_modes() const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_face_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const hp::QCollection< dim - 1 > &quadrature, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
virtual bool hp_constraints_are_implemented() const override
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const override
void build_interface_constraints()
virtual Tensor< 4, dim > shape_4th_derivative_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual Point< dim - 1 > unit_face_support_point(const unsigned int index, const unsigned int face_no=0) const override
void initialize(const std::vector< const FiniteElement< dim, spacedim > * > &fes, const std::vector< unsigned int > &multiplicities)
virtual void convert_generalized_support_point_values_to_dof_values(const std::vector< Vector< double > > &support_point_values, std::vector< double > &dof_values) const override
std::vector< std::pair< unsigned int, unsigned int > > hp_object_dof_identities(const FiniteElement< dim, spacedim > &fe_other, const unsigned int face_no=0) const
virtual void fill_fe_subface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int sub_no, const Quadrature< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const typename FiniteElement< dim, spacedim >::InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const override
virtual double shape_value_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual double shape_value(const unsigned int i, const Point< dim > &p) const override
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual Tensor< 2, dim > shape_grad_grad_component(const unsigned int i, const Point< dim > &p, const unsigned int component) const override
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const override
virtual std::unique_ptr< FiniteElement< dim, spacedim > > clone() const override
virtual std::size_t memory_consumption() const override
virtual Tensor< 4, dim > shape_4th_derivative(const unsigned int i, const Point< dim > &p) const override
virtual std::unique_ptr< typename FiniteElement< dim, spacedim >::InternalDataBase > get_subface_data(const UpdateFlags update_flags, const Mapping< dim, spacedim > &mapping, const Quadrature< dim - 1 > &quadrature, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) 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_components() const
virtual std::string get_name() const =0
virtual void fill_fe_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const CellSimilarity::Similarity cell_similarity, const Quadrature< dim > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const =0
virtual 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
virtual void fill_fe_face_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const hp::QCollection< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const
bool is_primitive() const
virtual void fill_fe_subface_values(const typename Triangulation< dim, spacedim >::cell_iterator &cell, const unsigned int face_no, const unsigned int sub_no, const Quadrature< dim - 1 > &quadrature, const Mapping< dim, spacedim > &mapping, const typename Mapping< dim, spacedim >::InternalDataBase &mapping_internal, const internal::FEValuesImplementation::MappingRelatedData< dim, spacedim > &mapping_data, const InternalDataBase &fe_internal, ::internal::FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data) const =0
virtual void get_subface_interpolation_matrix(const FiniteElement< dim, spacedim > &source, const unsigned int subface, FullMatrix< double > &matrix, const unsigned int face_no=0) const
std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > system_to_base_table
Definition fe.h:2670
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_line_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
std::pair< std::pair< unsigned int, unsigned int >, unsigned int > system_to_base_index(const unsigned int index) const
std::pair< std::pair< unsigned int, unsigned int >, unsigned int > face_system_to_base_index(const unsigned int index, const unsigned int face_no=0) const
unsigned int element_multiplicity(const unsigned int index) const
unsigned int n_nonzero_components(const unsigned int i) const
unsigned int n_base_elements() const
virtual void get_face_interpolation_matrix(const FiniteElement< dim, spacedim > &source, FullMatrix< double > &matrix, const unsigned int face_no=0) const
virtual std::size_t memory_consumption() const
virtual std::vector< std::pair< unsigned int, unsigned int > > hp_vertex_dof_identities(const FiniteElement< dim, spacedim > &fe_other) const
size_type n() const
size_type m() const
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
unsigned int size() const
unsigned int n_face_orientations(const unsigned int face_no) const
unsigned int max_n_quadrature_points() const
void initialize(const unsigned int n_quadrature_points, const FiniteElement< dim, spacedim > &fe, const UpdateFlags flags)
Definition fe_values.cc:49
#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()
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
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)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
UpdateFlags
@ update_hessians
Second derivatives of shape functions.
@ update_values
Shape function values.
@ update_3rd_derivatives
Third derivatives of shape functions.
@ update_gradients
Shape function gradients.
@ update_default
No update.
Task< RT > new_task(const std::function< RT()> &function)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
void build_face_tables(std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > &face_system_to_base_table, std::vector< std::pair< unsigned int, unsigned int > > &face_system_to_component_table, const FiniteElement< dim, spacedim > &finite_element, const bool do_tensor_product=true, const unsigned int face_no=0)
std::vector< ComponentMask > compute_nonzero_components(const std::vector< const FiniteElement< dim, spacedim > * > &fes, const std::vector< unsigned int > &multiplicities, const bool do_tensor_product=true)
std::vector< bool > compute_restriction_is_additive_flags(const std::vector< const FiniteElement< dim, spacedim > * > &fes, const std::vector< unsigned int > &multiplicities)
void build_cell_tables(std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > &system_to_base_table, std::vector< std::pair< unsigned int, unsigned int > > &system_to_component_table, std::vector< std::pair< std::pair< unsigned int, unsigned int >, unsigned int > > &component_to_base_table, const FiniteElement< dim, spacedim > &finite_element, const bool do_tensor_product=true)
FiniteElementData< dim > multiply_dof_numbers(const std::vector< const FiniteElement< dim, spacedim > * > &fes, const std::vector< unsigned int > &multiplicities, const bool do_tensor_product=true)
void reference_cell(Triangulation< dim, spacedim > &tria, const ReferenceCell< dim > &reference_cell)
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
std::string dim_string(const int dim, const int spacedim)
Definition utilities.cc:547
std::vector< typename FEPointEvaluation< n_components, dim, spacedim, typename VectorType::value_type >::value_type > point_values(const Mapping< dim > &mapping, const MeshType< dim, spacedim > &mesh, const VectorType &vector, const std::vector< Point< spacedim > > &evaluation_points, Utilities::MPI::RemotePointEvaluation< dim, spacedim > &cache, const EvaluationFlags::EvaluationFlags flags=EvaluationFlags::avg, const unsigned int first_selected_component=0)
std::vector< Point< dim > > unit_support_points(const std::vector< Point< 1 > > &line_support_points, const std::vector< unsigned int > &renumbering)
std::vector< typename FESystem< dim, spacedim >::BaseOffsets > setup_nonprimitive_offset_table(const FESystem< dim, spacedim > &fe, const unsigned int base_no)
Definition fe_system.cc:91
Table< 2, unsigned int > setup_primitive_offset_table(const FESystem< dim, spacedim > &fe, const unsigned int base_no)
Definition fe_system.cc:54
void copy_nonprimitive_base_element_values(const FESystem< dim, spacedim > &fe, const unsigned int base_no, const unsigned int n_q_points, const UpdateFlags base_flags, const std::vector< typename FESystem< dim, spacedim >::BaseOffsets > &offsets, const FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &base_data, FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data)
Definition fe_system.cc:187
void copy_primitive_base_element_values(const FESystem< dim, spacedim > &fe, const unsigned int base_no, const UpdateFlags base_flags, const Table< 2, unsigned int > &base_to_system_table, const FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &base_data, FEValuesImplementation::FiniteElementRelatedData< dim, spacedim > &output_data)
Definition fe_system.cc:132
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
std::uint8_t geometric_orientation
Definition types.h:38