deal.II version GIT relicensing-6809-ge913b9bb34 2026-09-25 17: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
dof_tools.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 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
16#include <deal.II/base/mpi.h>
18#include <deal.II/base/table.h>
20#include <deal.II/base/types.h>
21
24
28
29#include <deal.II/fe/fe.h>
30#include <deal.II/fe/fe_tools.h>
32
35#include <deal.II/grid/tria.h>
37
42
46#include <deal.II/lac/vector.h>
47
49
50#include <algorithm>
51#include <complex>
52#include <numeric>
53
55
56
57
58namespace DoFTools
59{
60 namespace internal
61 {
76 template <int dim, typename Number = double>
78 {
84 bool
86 const Point<dim, Number> &rhs) const
87 {
88 double downstream_size = 0;
89 double weight = 1.;
90 for (unsigned int d = 0; d < dim; ++d)
91 {
92 downstream_size += (rhs[d] - lhs[d]) * weight;
93 weight *= 1e-5;
94 }
95 if (downstream_size < 0)
96 return false;
97 else if (downstream_size > 0)
98 return true;
99 else
100 {
101 for (unsigned int d = 0; d < dim; ++d)
102 {
103 if (lhs[d] == rhs[d])
104 continue;
105 return lhs[d] < rhs[d];
106 }
107 return false;
108 }
109 }
110 };
111
112
113
114 // return an array that for each dof on the reference cell
115 // lists the corresponding vector component.
116 //
117 // if an element is non-primitive then we assign to each degree of freedom
118 // the following component:
119 // - if the nonzero components that belong to a shape function are not
120 // selected in the component_mask, then the shape function is assigned
121 // to the first nonzero vector component that corresponds to this
122 // shape function
123 // - otherwise, the shape function is assigned the first component selected
124 // in the component_mask that corresponds to this shape function
125 template <int dim, int spacedim>
126 std::vector<unsigned char>
128 const ComponentMask &component_mask)
129 {
130 std::vector<unsigned char> local_component_association(
131 fe.n_dofs_per_cell(), static_cast<unsigned char>(-1));
132
133 // compute the component each local dof belongs to.
134 // if the shape function is primitive, then this
135 // is simple and we can just associate it with
136 // what system_to_component_index gives us
137 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
138 if (fe.is_primitive(i))
139 local_component_association[i] =
140 fe.system_to_component_index(i).first;
141 else
142 // if the shape function is not primitive, then either use the
143 // component of the first nonzero component corresponding
144 // to this shape function (if the component is not specified
145 // in the component_mask), or the first component of this block
146 // that is listed in the component_mask (if the block this
147 // component corresponds to is indeed specified in the component
148 // mask)
149 {
150 const unsigned int first_comp =
152
153 if ((fe.get_nonzero_components(i) & component_mask)
154 .n_selected_components(fe.n_components()) == 0)
155 local_component_association[i] = first_comp;
156 else
157 // pick the component selected. we know from the previous 'if'
158 // that within the components that are nonzero for this
159 // shape function there must be at least one for which the
160 // mask is true, so we will for sure run into the break()
161 // at one point
162 for (unsigned int c = first_comp; c < fe.n_components(); ++c)
163 if (component_mask[c] == true)
164 {
165 local_component_association[i] = c;
166 break;
167 }
168 }
169
170 Assert(std::find(local_component_association.begin(),
171 local_component_association.end(),
172 static_cast<unsigned char>(-1)) ==
173 local_component_association.end(),
175
176 return local_component_association;
177 }
178
179
180 // this internal function assigns to each dof the respective component
181 // of the vector system.
182 //
183 // the output array dofs_by_component lists for each dof the
184 // corresponding vector component. if the DoFHandler is based on a
185 // parallel distributed triangulation then the output array is index by
186 // dof_handler.locally_owned_dofs().index_within_set(indices[i])
187 //
188 // if an element is non-primitive then we assign to each degree of
189 // freedom the following component:
190 // - if the nonzero components that belong to a shape function are not
191 // selected in the component_mask, then the shape function is assigned
192 // to the first nonzero vector component that corresponds to this
193 // shape function
194 // - otherwise, the shape function is assigned the first component selected
195 // in the component_mask that corresponds to this shape function
196 template <int dim, int spacedim>
197 void
199 const DoFHandler<dim, spacedim> &dof_handler,
200 const ComponentMask &component_mask,
201 std::vector<unsigned char> &dofs_by_component,
202 const unsigned int mg_level = numbers::invalid_unsigned_int)
203 {
204 const ::hp::FECollection<dim, spacedim> &fe_collection =
205 dof_handler.get_fe_collection();
206 Assert(fe_collection.n_components() < 256, ExcNotImplemented());
207
208 const auto &locally_owned_dofs =
209 (mg_level == numbers::invalid_unsigned_int) ?
210 dof_handler.locally_owned_dofs() :
211 dof_handler.locally_owned_mg_dofs(mg_level);
212
213 AssertDimension(dofs_by_component.size(),
214 locally_owned_dofs.n_elements());
215
216 // next set up a table for the degrees of freedom on each of the
217 // cells (regardless of the fact whether it is listed in the
218 // component_select argument or not)
219 //
220 // for each element 'f' of the FECollection,
221 // local_component_association[f][d] then returns the vector
222 // component that degree of freedom 'd' belongs to
223 std::vector<std::vector<unsigned char>> local_component_association(
224 fe_collection.size());
225 for (unsigned int f = 0; f < fe_collection.size(); ++f)
226 {
227 const FiniteElement<dim, spacedim> &fe = fe_collection[f];
228 local_component_association[f] =
229 get_local_component_association(fe, component_mask);
230 }
231
232 // then loop over all cells and do the work
233 std::vector<types::global_dof_index> indices;
234
235 const auto runner = [&](const auto &task) {
236 if (mg_level == numbers::invalid_unsigned_int)
237 {
238 for (const auto &cell : dof_handler.active_cell_iterators() |
240 {
241 indices.resize(cell->get_fe().n_dofs_per_cell());
242 cell->get_dof_indices(indices);
243
244 task(cell);
245 }
246 }
247 else
248 {
249 for (const auto &cell :
250 dof_handler.cell_iterators_on_level(mg_level))
251 if (cell->is_locally_owned_on_level())
252 {
253 indices.resize(cell->get_fe().n_dofs_per_cell());
254 cell->get_mg_dof_indices(indices);
255
256 task(cell);
257 }
258 }
259 };
260
261 runner([&](const auto &cell) {
262 const types::fe_index fe_index = cell->active_fe_index();
263 for (unsigned int i = 0; i < cell->get_fe().n_dofs_per_cell(); ++i)
264 if (locally_owned_dofs.is_element(indices[i]))
265 dofs_by_component[locally_owned_dofs.index_within_set(indices[i])] =
266 local_component_association[fe_index][i];
267 });
268 }
269
270
271 // this is the function corresponding to the one above but working on
272 // blocks instead of components.
273 //
274 // the output array dofs_by_block lists for each dof the corresponding
275 // vector block. if the DoFHandler is based on a parallel distributed
276 // triangulation then the output array is index by
277 // dof.locally_owned_dofs().index_within_set(indices[i])
278 template <int dim, int spacedim>
279 void
281 std::vector<unsigned char> &dofs_by_block)
282 {
283 const ::hp::FECollection<dim, spacedim> &fe_collection =
284 dof.get_fe_collection();
285 Assert(fe_collection.n_components() < 256, ExcNotImplemented());
286 Assert(dofs_by_block.size() == dof.n_locally_owned_dofs(),
287 ExcDimensionMismatch(dofs_by_block.size(),
288 dof.n_locally_owned_dofs()));
289
290 // next set up a table for the degrees of freedom on each of the
291 // cells (regardless of the fact whether it is listed in the
292 // component_select argument or not)
293 //
294 // for each element 'f' of the FECollection,
295 // local_block_association[f][d] then returns the vector block that
296 // degree of freedom 'd' belongs to
297 std::vector<std::vector<unsigned char>> local_block_association(
298 fe_collection.size());
299 for (unsigned int f = 0; f < fe_collection.size(); ++f)
300 {
301 const FiniteElement<dim, spacedim> &fe = fe_collection[f];
302 local_block_association[f].resize(fe.n_dofs_per_cell(),
303 static_cast<unsigned char>(-1));
304 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
305 local_block_association[f][i] = fe.system_to_block_index(i).first;
306
307 Assert(std::find(local_block_association[f].begin(),
308 local_block_association[f].end(),
309 static_cast<unsigned char>(-1)) ==
310 local_block_association[f].end(),
312 }
313
314 // then loop over all cells and do the work
315 std::vector<types::global_dof_index> indices;
316 for (const auto &cell : dof.active_cell_iterators())
317 if (cell->is_locally_owned())
318 {
319 const types::fe_index fe_index = cell->active_fe_index();
320 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
321 indices.resize(dofs_per_cell);
322 cell->get_dof_indices(indices);
323 for (unsigned int i = 0; i < dofs_per_cell; ++i)
324 if (dof.locally_owned_dofs().is_element(indices[i]))
325 dofs_by_block[dof.locally_owned_dofs().index_within_set(
326 indices[i])] = local_block_association[fe_index][i];
327 }
328 }
329 } // namespace internal
330
331
332
333 template <int dim, int spacedim, typename Number>
334 void
336 const Vector<Number> &cell_data,
337 Vector<double> &dof_data,
338 const unsigned int component)
339 {
340 const Triangulation<dim, spacedim> &tria = dof_handler.get_triangulation();
341 (void)tria;
342
343 AssertDimension(cell_data.size(), tria.n_active_cells());
344 AssertDimension(dof_data.size(), dof_handler.n_dofs());
345 const auto &fe_collection = dof_handler.get_fe_collection();
346 AssertIndexRange(component, fe_collection.n_components());
347 for (unsigned int i = 0; i < fe_collection.size(); ++i)
348 {
349 Assert(fe_collection[i].is_primitive() == true,
351 }
352
353 // store a flag whether we should care about different components. this
354 // is just a simplification, we could ask for this at every single
355 // place equally well
356 const bool consider_components =
357 (dof_handler.get_fe_collection().n_components() != 1);
358
359 // zero out the components that we will touch
360 if (consider_components == false)
361 dof_data = 0;
362 else
363 {
364 std::vector<unsigned char> component_dofs(
365 dof_handler.n_locally_owned_dofs());
367 dof_handler,
368 fe_collection.component_mask(FEValuesExtractors::Scalar(component)),
369 component_dofs);
370
371 for (unsigned int i = 0; i < dof_data.size(); ++i)
372 if (component_dofs[i] == static_cast<unsigned char>(component))
373 dof_data(i) = 0;
374 }
375
376 // count how often we have added a value in the sum for each dof
377 std::vector<unsigned char> touch_count(dof_handler.n_dofs(), 0);
378
379 std::vector<types::global_dof_index> dof_indices;
380 dof_indices.reserve(fe_collection.max_dofs_per_cell());
381
382 for (const auto &cell : dof_handler.active_cell_iterators())
383 {
384 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
385 dof_indices.resize(dofs_per_cell);
386 cell->get_dof_indices(dof_indices);
387
388 for (unsigned int i = 0; i < dofs_per_cell; ++i)
389 // consider this dof only if it is the right component. if there
390 // is only one component, short cut the test
391 if (!consider_components ||
392 (cell->get_fe().system_to_component_index(i).first == component))
393 {
394 // sum up contribution of the present_cell to this dof
395 dof_data(dof_indices[i]) += cell_data(cell->active_cell_index());
396
397 // note that we added another summand
398 ++touch_count[dof_indices[i]];
399 }
400 }
401
402 // compute the mean value on all the dofs by dividing with the number
403 // of summands.
404 for (types::global_dof_index i = 0; i < dof_handler.n_dofs(); ++i)
405 {
406 // assert that each dof was used at least once. this needs not be
407 // the case if the vector has more than one component
408 Assert(consider_components || (touch_count[i] != 0),
410 if (touch_count[i] != 0)
411 dof_data(i) /= touch_count[i];
412 }
413 }
414
415
416
417 template <int dim, int spacedim>
420 const ComponentMask &component_mask)
421 {
422 Assert(component_mask.represents_n_components(
425 "The given component mask is not sized correctly to represent the "
426 "components of the given finite element."));
427
428 // Two special cases: no component is selected, and all components are
429 // selected; both rather stupid, but easy to catch
430 if (component_mask.n_selected_components(
431 dof.get_fe_collection().n_components()) == 0)
432 return IndexSet(dof.n_dofs());
433 else if (component_mask.n_selected_components(
436 return dof.locally_owned_dofs();
437
438 // get the component association of each DoF and then select the ones
439 // that match the given set of components
440 std::vector<unsigned char> dofs_by_component(dof.n_locally_owned_dofs());
441 internal::get_component_association(dof, component_mask, dofs_by_component);
442
443 // fill the selected components in a vector
444 std::vector<types::global_dof_index> selected_dofs;
445 selected_dofs.reserve(dof.n_locally_owned_dofs());
446 for (types::global_dof_index i = 0; i < dofs_by_component.size(); ++i)
447 if (component_mask[dofs_by_component[i]] == true)
448 selected_dofs.push_back(dof.locally_owned_dofs().nth_index_in_set(i));
449
450 // fill vector of indices to return argument
451 IndexSet result(dof.n_dofs());
452 result.add_indices(selected_dofs.begin(), selected_dofs.end());
453 return result;
454 }
455
456
457
458 template <int dim, int spacedim>
461 const BlockMask &block_mask)
462 {
463 // simply forward to the function that works based on a component mask
464 return extract_dofs<dim, spacedim>(
465 dof, dof.get_fe_collection().component_mask(block_mask));
466 }
467
468
469
470 template <int dim, int spacedim>
471 std::vector<IndexSet>
473 const ComponentMask &component_mask)
474 {
475 const auto n_comps = dof.get_fe_collection().n_components();
476 Assert(component_mask.represents_n_components(n_comps),
478 "The given component mask is not sized correctly to represent the "
479 "components of the given finite element."));
480
481 const auto &locally_owned_dofs = dof.locally_owned_dofs();
482
483 // get the component association of each DoF and then select the ones
484 // that match the given set of components
485 std::vector<unsigned char> dofs_by_component(dof.n_locally_owned_dofs());
486 internal::get_component_association(dof, component_mask, dofs_by_component);
487
488 std::vector<IndexSet> index_per_comp(n_comps, IndexSet(dof.n_dofs()));
489
490 for (types::global_dof_index i = 0; i < dof.n_locally_owned_dofs(); ++i)
491 {
492 const auto &comp_i = dofs_by_component[i];
493 if (component_mask[comp_i])
494 index_per_comp[comp_i].add_index(
495 locally_owned_dofs.nth_index_in_set(i));
496 }
497 for (const auto &c : index_per_comp)
498 c.compress();
499 return index_per_comp;
500 }
501
502
503
504 template <int dim, int spacedim>
505 void
506 extract_level_dofs(const unsigned int level,
507 const DoFHandler<dim, spacedim> &dof,
508 const ComponentMask &component_mask,
509 std::vector<bool> &selected_dofs)
510 {
511 const FiniteElement<dim, spacedim> &fe = dof.get_fe();
512
513 Assert(component_mask.represents_n_components(
516 "The given component mask is not sized correctly to represent the "
517 "components of the given finite element."));
518 Assert(selected_dofs.size() == dof.n_dofs(level),
519 ExcDimensionMismatch(selected_dofs.size(), dof.n_dofs(level)));
520
521 // two special cases: no component is selected, and all components are
522 // selected, both rather stupid, but easy to catch
523 if (component_mask.n_selected_components(
524 dof.get_fe_collection().n_components()) == 0)
525 {
526 std::fill_n(selected_dofs.begin(), dof.n_dofs(level), false);
527 return;
528 }
529 else if (component_mask.n_selected_components(
532 {
533 std::fill_n(selected_dofs.begin(), dof.n_dofs(level), true);
534 return;
535 }
536
537 // preset all values by false
538 std::fill_n(selected_dofs.begin(), dof.n_dofs(level), false);
539
540 // next set up a table for the degrees of freedom on each of the cells
541 // whether it is something interesting or not
542 std::vector<unsigned char> local_component_association =
544 std::vector<bool> local_selected_dofs(fe.n_dofs_per_cell());
545 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
546 local_selected_dofs[i] = component_mask[local_component_association[i]];
547
548 // then loop over all cells and do work
549 std::vector<types::global_dof_index> indices(fe.n_dofs_per_cell());
550 for (const auto &cell : dof.cell_iterators_on_level(level))
551 {
552 cell->get_mg_dof_indices(indices);
553 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
554 selected_dofs[indices[i]] = local_selected_dofs[i];
555 }
556 }
557
558
559
560 template <int dim, int spacedim>
561 void
562 extract_level_dofs(const unsigned int level,
563 const DoFHandler<dim, spacedim> &dof,
564 const BlockMask &block_mask,
565 std::vector<bool> &selected_dofs)
566 {
567 // simply defer to the other extract_level_dofs() function
569 dof,
570 dof.get_fe().component_mask(block_mask),
571 selected_dofs);
572 }
573
574
575
576 template <int dim, int spacedim>
577 void
579 const ComponentMask &component_mask,
580 std::vector<bool> &selected_dofs,
581 const std::set<types::boundary_id> &boundary_ids)
582 {
583 Assert((dynamic_cast<
585 &dof_handler.get_triangulation()) == nullptr),
587 "This function can not be used with distributed triangulations. "
588 "See the documentation for more information."));
589
590 IndexSet indices =
591 extract_boundary_dofs(dof_handler, component_mask, boundary_ids);
592
593 // clear and reset array by default values
594 selected_dofs.clear();
595 selected_dofs.resize(dof_handler.n_dofs(), false);
596
597 // then convert the values computed above to the binary vector
598 indices.fill_binary_vector(selected_dofs);
599 }
600
601
602
603 template <int dim, int spacedim>
604 void
606 const ComponentMask &component_mask,
607 IndexSet &selected_dofs,
608 const std::set<types::boundary_id> &boundary_ids)
609 {
610 // Simply forward to the other function
611 selected_dofs =
612 extract_boundary_dofs(dof_handler, component_mask, boundary_ids);
613 }
614
615
616
617 template <int dim, int spacedim>
620 const ComponentMask &component_mask,
621 const std::set<types::boundary_id> &boundary_ids)
622 {
623 Assert(component_mask.represents_n_components(
624 dof_handler.get_fe_collection().n_components()),
625 ExcMessage("Component mask has invalid size."));
626 Assert(boundary_ids.find(numbers::internal_face_boundary_id) ==
627 boundary_ids.end(),
629
630 IndexSet selected_dofs(dof_handler.n_dofs());
631
632 // let's see whether we have to check for certain boundary indicators
633 // or whether we can accept all
634 const bool check_boundary_id = (boundary_ids.size() != 0);
635
636 // also see whether we have to check whether a certain vector component
637 // is selected, or all
638 const bool check_vector_component =
639 ((component_mask.represents_the_all_selected_mask() == false) ||
640 (component_mask.n_selected_components(
641 dof_handler.get_fe_collection().n_components()) !=
642 dof_handler.get_fe_collection().n_components()));
643
644 std::vector<types::global_dof_index> face_dof_indices;
645 face_dof_indices.reserve(
646 dof_handler.get_fe_collection().max_dofs_per_face());
647
648 // now loop over all cells and check whether their faces are at the
649 // boundary. note that we need not take special care of single lines
650 // being at the boundary (using @p{cell->has_boundary_lines}), since we
651 // do not support boundaries of dimension dim-2, and so every isolated
652 // boundary line is also part of a boundary face which we will be
653 // visiting sooner or later
654 for (const auto &cell : dof_handler.active_cell_iterators())
655 // only work on cells that are either locally owned or at least ghost
656 // cells
657 if (cell->is_artificial() == false)
658 for (const unsigned int face : cell->face_indices())
659 if (cell->at_boundary(face))
660 if (!check_boundary_id ||
661 (boundary_ids.find(cell->face(face)->boundary_id()) !=
662 boundary_ids.end()))
663 {
664 const FiniteElement<dim, spacedim> &fe = cell->get_fe();
665
666 const auto reference_cell = cell->reference_cell();
667
668 const unsigned int n_vertices_per_cell =
669 reference_cell.n_vertices();
670 const unsigned int n_lines_per_cell = reference_cell.n_lines();
671 const unsigned int n_vertices_per_face =
672 reference_cell.face_reference_cell(face).n_vertices();
673 const unsigned int n_lines_per_face =
674 reference_cell.face_reference_cell(face).n_lines();
675
676 const unsigned int dofs_per_face = fe.n_dofs_per_face(face);
677 face_dof_indices.resize(dofs_per_face);
678 cell->face(face)->get_dof_indices(face_dof_indices,
679 cell->active_fe_index());
680
681 for (unsigned int i = 0; i < fe.n_dofs_per_face(face); ++i)
682 if (!check_vector_component)
683 selected_dofs.add_index(face_dof_indices[i]);
684 else
685 // check for component is required. somewhat tricky as
686 // usual for the case that the shape function is
687 // non-primitive, but use usual convention (see docs)
688 {
689 // first get at the cell-global number of a face dof,
690 // to ask the FE certain questions
691 const unsigned int cell_index =
692 (dim == 1 ?
693 i :
694 (dim == 2 ?
695 (i < 2 * fe.n_dofs_per_vertex() ?
696 i :
697 i + 2 * fe.n_dofs_per_vertex()) :
698 (dim == 3 ? (i < n_vertices_per_face *
699 fe.n_dofs_per_vertex() ?
700 i :
701 (i < n_vertices_per_face *
702 fe.n_dofs_per_vertex() +
703 n_lines_per_face *
704 fe.n_dofs_per_line() ?
705 (i - n_vertices_per_face *
706 fe.n_dofs_per_vertex()) +
707 n_vertices_per_cell *
708 fe.n_dofs_per_vertex() :
709 (i -
710 n_vertices_per_face *
711 fe.n_dofs_per_vertex() -
712 n_lines_per_face *
713 fe.n_dofs_per_line()) +
714 n_vertices_per_cell *
715 fe.n_dofs_per_vertex() +
716 n_lines_per_cell *
717 fe.n_dofs_per_line())) :
719 if (fe.is_primitive(cell_index))
720 {
721 if (component_mask[fe.face_system_to_component_index(
722 i, face)
723 .first] == true)
724 selected_dofs.add_index(face_dof_indices[i]);
725 }
726 else // not primitive
727 {
728 const unsigned int first_nonzero_comp =
731 Assert(first_nonzero_comp < fe.n_components(),
733
734 if (component_mask[first_nonzero_comp] == true)
735 selected_dofs.add_index(face_dof_indices[i]);
736 }
737 }
738 }
739
740 return selected_dofs;
741 }
742
743
744
745 template <int dim, int spacedim>
746 void
748 const DoFHandler<dim, spacedim> &dof_handler,
749 const ComponentMask &component_mask,
750 std::vector<bool> &selected_dofs,
751 const std::set<types::boundary_id> &boundary_ids)
752 {
753 Assert(component_mask.represents_n_components(
754 dof_handler.get_fe_collection().n_components()),
755 ExcMessage("This component mask has the wrong size."));
756 Assert(boundary_ids.find(numbers::internal_face_boundary_id) ==
757 boundary_ids.end(),
759
760 // let's see whether we have to check for certain boundary indicators
761 // or whether we can accept all
762 const bool check_boundary_id = (boundary_ids.size() != 0);
763
764 // also see whether we have to check whether a certain vector component
765 // is selected, or all
766 const bool check_vector_component =
767 (component_mask.represents_the_all_selected_mask() == false);
768
769 // clear and reset array by default values
770 selected_dofs.clear();
771 selected_dofs.resize(dof_handler.n_dofs(), false);
772 std::vector<types::global_dof_index> cell_dof_indices;
773 cell_dof_indices.reserve(
774 dof_handler.get_fe_collection().max_dofs_per_cell());
775
776 // now loop over all cells and check whether their faces are at the
777 // boundary. note that we need not take special care of single lines
778 // being at the boundary (using @p{cell->has_boundary_lines}), since we
779 // do not support boundaries of dimension dim-2, and so every isolated
780 // boundary line is also part of a boundary face which we will be
781 // visiting sooner or later
782 for (const auto &cell : dof_handler.active_cell_iterators())
783 for (const unsigned int face : cell->face_indices())
784 if (cell->at_boundary(face))
785 if (!check_boundary_id ||
786 (boundary_ids.find(cell->face(face)->boundary_id()) !=
787 boundary_ids.end()))
788 {
789 const FiniteElement<dim, spacedim> &fe = cell->get_fe();
790
791 const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
792 cell_dof_indices.resize(dofs_per_cell);
793 cell->get_dof_indices(cell_dof_indices);
794
795 for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
796 if (fe.has_support_on_face(i, face))
797 {
798 if (!check_vector_component)
799 selected_dofs[cell_dof_indices[i]] = true;
800 else
801 // check for component is required. somewhat tricky
802 // as usual for the case that the shape function is
803 // non-primitive, but use usual convention (see docs)
804 {
805 if (fe.is_primitive(i))
806 selected_dofs[cell_dof_indices[i]] =
807 (component_mask[fe.system_to_component_index(i)
808 .first] == true);
809 else // not primitive
810 {
811 const unsigned int first_nonzero_comp =
814 Assert(first_nonzero_comp < fe.n_components(),
816
817 selected_dofs[cell_dof_indices[i]] =
818 (component_mask[first_nonzero_comp] == true);
819 }
820 }
821 }
822 }
823 }
824
825
826
827 template <int dim, int spacedim, typename number>
830 const DoFHandler<dim, spacedim> &dof_handler,
831 const std::function<
833 &predicate,
835 {
836 const std::function<bool(
838 predicate_local =
839 [=](
841 -> bool { return cell->is_locally_owned() && predicate(cell); };
842
843 std::vector<types::global_dof_index> local_dof_indices;
844 local_dof_indices.reserve(
845 dof_handler.get_fe_collection().max_dofs_per_cell());
846
847 // Get all the DoFs that live on the locally owned subdomain part
848 std::set<types::global_dof_index> predicate_dofs_owned_cells;
849
850 for (const auto &cell :
851 dof_handler.active_cell_iterators() | predicate_local)
852 {
853 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
854 cell->get_dof_indices(local_dof_indices);
855 predicate_dofs_owned_cells.insert(local_dof_indices.begin(),
856 local_dof_indices.end());
857 }
858
859 IndexSet predicate_owned_set(dof_handler.n_dofs());
860 predicate_owned_set.add_indices(predicate_dofs_owned_cells.begin(),
861 predicate_dofs_owned_cells.end());
862 predicate_owned_set.compress();
863
864 // Build halo layer around locally owned part of subdomain and sort the
865 // cells into one of two buckets:
866 // - locally owned cells not fulfilling the predicate -> add to
867 // non_predicate_halo_set
868 // - ghost cells fulfilling the predicate -> add to predicate_ghost_set
869 // - ghost cells not fulfilling the predicate -> add to non_predicate_halo
870 // set
871 // (Note that some ghost cells in the halo may satisfy the predicate
872 // because we first build the halo around the *locally owned cells that
873 // also satisfy the predicate*. I.e., there are cells returned by
874 // GridTools::compute_active_cell_halo_layer() that are in the halo
875 // of 'predicate_local' but actually inside the subdomain described by
876 // 'predicate'.)
877 std::set<types::global_dof_index> non_predicate_dofs_halo_cells;
878 std::set<types::global_dof_index> predicate_dofs_ghosts;
879
880 for (const auto &cell :
882 predicate_local))
883 {
884 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
885 local_dof_indices.resize(dofs_per_cell);
886 cell->get_dof_indices(local_dof_indices);
887 if (predicate(cell))
888 {
889 Assert(cell->is_ghost(), ExcInternalError());
890 predicate_dofs_ghosts.insert(local_dof_indices.begin(),
891 local_dof_indices.end());
892 }
893 else
894 non_predicate_dofs_halo_cells.insert(local_dof_indices.begin(),
895 local_dof_indices.end());
896 }
897
898 /*
899 Handle the special case of a locally active Dof (DoF marked with an x)
900 that constrains a DoF (DoF marked with an o), which is supported on
901 predicate ghost cells (marked by #g#) of the current process and on a
902 artificial cell the current process has no information about.
903
904 +---+---+---+---+
905 |###|###|#g#| a1|
906 +---+---+---+---+
907 |###|###|#g#| a2|
908 +---+---x---o---+
909 |#######|###g###|
910 |#######|###g###|
911 +-------+-------+
912 current |neighboring
913 process |process
914
915 ##### = predicate region
916 #g# = predicate ghost cell
917 a1,a2 = artificial cell
918
919 To handle this case the neighboring process needs to send its
920 non_predicate_dofs_halo_cells that are locally relevant to the current
921 process. If the received set contains the DoF marked with an o the
922 artificial cell a2 does not fulfill the predicate and the constraining dof
923 marked with an x is removed from the support_set below.
924 */
925 if (const auto parallel_triangulation =
926 dynamic_cast<const ::parallel::TriangulationBase<dim> *>(
927 &dof_handler.get_triangulation()))
928 {
929 // Step 1: Send all non_predicate_dofs_halo_cells to ghost cell owners
930 const std::set<::types::subdomain_id> ghost_owners =
931 parallel_triangulation->ghost_owners();
932
933 std::map<unsigned, std::set<::types::global_dof_index>>
934 data_to_send;
935 for (const auto rank : ghost_owners)
936 {
937 data_to_send[rank] = non_predicate_dofs_halo_cells;
938 }
939
940 const auto additional_non_predicate_halo_dofs =
942 dof_handler.get_mpi_communicator(), data_to_send);
943
944 // Step 2: Add all received indices that are locally relevant.
945 const IndexSet &locally_stored_constraints = cm.get_local_lines();
946
947 for (const auto &[rank, indices] : additional_non_predicate_halo_dofs)
948 {
949 for (const auto index : indices)
950 {
951 if (locally_stored_constraints.is_element(index))
952 {
953 non_predicate_dofs_halo_cells.insert(index);
954 }
955 }
956 }
957 }
958
959 IndexSet non_predicate_halo_set(dof_handler.n_dofs());
960 non_predicate_halo_set.add_indices(non_predicate_dofs_halo_cells.begin(),
961 non_predicate_dofs_halo_cells.end());
962 non_predicate_halo_set.compress();
963
964 IndexSet predicate_ghost_set(dof_handler.n_dofs());
965 predicate_ghost_set.add_indices(predicate_dofs_ghosts.begin(),
966 predicate_dofs_ghosts.end());
967 predicate_ghost_set.compress();
968
969 // Get DoFs contained in the predicate_ghost_set that constrain a DoF in the
970 // predicate_owned_set. We need to add the constraining entries to the
971 // support_set as locally active DoFs will contribute to these constraining
972 // DoFs.
973 IndexSet constraining_predicate_ghost_set(dof_handler.n_dofs());
974 if (cm.n_constraints() > 0 && predicate_ghost_set.n_elements() > 0)
975 {
976 std::set<types::global_dof_index> constraining_ghost_dofs;
977 for (const auto dof : predicate_owned_set)
978 {
979 if (const auto *line_ptr = cm.get_constraint_entries(dof))
980 {
981 const unsigned int line_size = line_ptr->size();
982 for (unsigned int j = 0; j < line_size; ++j)
983 {
984 constraining_ghost_dofs.insert((*line_ptr)[j].first);
985 }
986 }
987 }
988 constraining_predicate_ghost_set.add_indices(
989 constraining_ghost_dofs.begin(), constraining_ghost_dofs.end());
990 }
991
992 // Now we collected all DoFs that we need to add to the support_set
993 IndexSet support_set(dof_handler.n_dofs());
994 support_set.add_indices(predicate_owned_set);
995 support_set.add_indices(constraining_predicate_ghost_set);
996
997
998 // Remove the following from the support_set:
999 // - The non_predicate_halo_set
1000 // - DoFs constraining the non_predicate_halo_set DoFs:
1001 // A DoF living on locally owned predicate cells that constrains non
1002 // predicate halo DoFs must be removed to not extend the support outside the
1003 // predicate domain.
1004 support_set.subtract_set(non_predicate_halo_set);
1005
1006 if (cm.n_constraints() > 0)
1007 {
1008 std::set<types::global_dof_index> dofs_constraining_halo;
1009 for (const auto dof : non_predicate_halo_set)
1010 {
1011 if (const auto *line_ptr = cm.get_constraint_entries(dof))
1012 {
1013 const unsigned int line_size = line_ptr->size();
1014 for (unsigned int j = 0; j < line_size; ++j)
1015 dofs_constraining_halo.insert((*line_ptr)[j].first);
1016 }
1017 }
1018
1019 IndexSet dofs_constraining_halo_set(dof_handler.n_dofs());
1020 dofs_constraining_halo_set.add_indices(dofs_constraining_halo.begin(),
1021 dofs_constraining_halo.end());
1022 support_set.subtract_set(dofs_constraining_halo_set);
1023 }
1024
1025 support_set.compress();
1026
1027 // we intentionally do not want to limit the output to locally owned DoFs.
1028 return support_set;
1029 }
1030
1031
1032
1033 namespace internal
1034 {
1035 namespace
1036 {
1037 template <int spacedim>
1038 IndexSet
1040 {
1041 // there are no hanging nodes in 1d
1042 return IndexSet(dof_handler.n_dofs());
1043 }
1044
1045
1046 template <int spacedim>
1047 IndexSet
1049 {
1050 const unsigned int dim = 2;
1051
1052 IndexSet selected_dofs(dof_handler.n_dofs());
1053
1054 const FiniteElement<dim, spacedim> &fe = dof_handler.get_fe();
1055
1056 // this function is similar to the make_sparsity_pattern function,
1057 // see there for more information
1058 for (const auto &cell : dof_handler.active_cell_iterators())
1059 if (!cell->is_artificial())
1060 {
1061 for (const unsigned int face : cell->face_indices())
1062 if (cell->face(face)->has_children())
1063 {
1065 line = cell->face(face);
1066
1067 for (unsigned int dof = 0; dof != fe.n_dofs_per_vertex();
1068 ++dof)
1069 selected_dofs.add_index(
1070 line->child(0)->vertex_dof_index(1, dof));
1071
1072 for (unsigned int child = 0; child < 2; ++child)
1073 {
1074 if (cell->neighbor_child_on_subface(face, child)
1075 ->is_artificial())
1076 continue;
1077 for (unsigned int dof = 0; dof != fe.n_dofs_per_line();
1078 ++dof)
1079 selected_dofs.add_index(
1080 line->child(child)->dof_index(dof));
1081 }
1082 }
1083 }
1084
1085 selected_dofs.compress();
1086 return selected_dofs;
1087 }
1088
1089
1090 template <int spacedim>
1091 IndexSet
1093 {
1094 const unsigned int dim = 3;
1095
1096 IndexSet selected_dofs(dof_handler.n_dofs());
1097 IndexSet unconstrained_dofs(dof_handler.n_dofs());
1098
1099 const FiniteElement<dim, spacedim> &fe = dof_handler.get_fe();
1100
1101 for (const auto &cell : dof_handler.active_cell_iterators())
1102 if (!cell->is_artificial())
1103 for (auto f : cell->face_indices())
1104 {
1105 const typename DoFHandler<dim, spacedim>::face_iterator face =
1106 cell->face(f);
1107 if (cell->face(f)->has_children())
1108 {
1109 for (unsigned int child = 0; child < 4; ++child)
1110 if (!cell->neighbor_child_on_subface(f, child)
1111 ->is_artificial())
1112 {
1113 // simply take all DoFs that live on this subface
1114 std::vector<types::global_dof_index> ldi(
1115 fe.n_dofs_per_face(f, child));
1116 face->child(child)->get_dof_indices(ldi);
1117 selected_dofs.add_indices(ldi.begin(), ldi.end());
1118 }
1119
1120 // and subtract (in the end) all the indices which a shared
1121 // between this face and its subfaces
1122 for (unsigned int vertex = 0; vertex < 4; ++vertex)
1123 for (unsigned int dof = 0; dof != fe.n_dofs_per_vertex();
1124 ++dof)
1125 unconstrained_dofs.add_index(
1126 face->vertex_dof_index(vertex, dof));
1127 }
1128 }
1129 selected_dofs.subtract_set(unconstrained_dofs);
1130 return selected_dofs;
1131 }
1132 } // namespace
1133 } // namespace internal
1134
1135
1136
1137 template <int dim, int spacedim>
1138 IndexSet
1140 {
1141 return internal::extract_hanging_node_dofs(dof_handler);
1142 }
1143
1144
1145
1146 template <int dim, int spacedim>
1147 void
1149 const types::subdomain_id subdomain_id,
1150 std::vector<bool> &selected_dofs)
1151 {
1152 Assert(selected_dofs.size() == dof_handler.n_dofs(),
1153 ExcDimensionMismatch(selected_dofs.size(), dof_handler.n_dofs()));
1154
1155 // preset all values by false
1156 std::fill_n(selected_dofs.begin(), dof_handler.n_dofs(), false);
1157
1158 std::vector<types::global_dof_index> local_dof_indices;
1159 local_dof_indices.reserve(
1160 dof_handler.get_fe_collection().max_dofs_per_cell());
1161
1162 // this function is similar to the make_sparsity_pattern function, see
1163 // there for more information
1164 for (const auto &cell : dof_handler.active_cell_iterators())
1165 if (cell->subdomain_id() == subdomain_id)
1166 {
1167 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
1168 local_dof_indices.resize(dofs_per_cell);
1169 cell->get_dof_indices(local_dof_indices);
1170 for (unsigned int i = 0; i < dofs_per_cell; ++i)
1171 selected_dofs[local_dof_indices[i]] = true;
1172 }
1173 }
1174
1175
1176
1177 template <int dim, int spacedim>
1178 IndexSet
1180 {
1181 // collect all the locally owned dofs
1182 IndexSet dof_set = dof_handler.locally_owned_dofs();
1183
1184 // add the DoF on the adjacent ghost cells to the IndexSet, cache them
1185 // in a set. need to check each dof manually because we can't be sure
1186 // that the dof range of locally_owned_dofs is really contiguous.
1187 std::vector<types::global_dof_index> dof_indices;
1188 std::set<types::global_dof_index> global_dof_indices;
1189
1190 for (const auto &cell : dof_handler.active_cell_iterators() |
1192 {
1193 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1194 cell->get_dof_indices(dof_indices);
1195
1196 for (const types::global_dof_index dof_index : dof_indices)
1197 if (!dof_set.is_element(dof_index))
1198 global_dof_indices.insert(dof_index);
1199 }
1200
1201 dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
1202
1203 dof_set.compress();
1204
1205 return dof_set;
1206 }
1207
1208
1209
1210 template <int dim, int spacedim>
1211 void
1213 IndexSet &dof_set)
1214 {
1215 dof_set = extract_locally_active_dofs(dof_handler);
1216 }
1217
1218
1219
1220 template <int dim, int spacedim>
1221 IndexSet
1223 const DoFHandler<dim, spacedim> &dof_handler,
1224 const unsigned int level)
1225 {
1226 // collect all the locally owned dofs
1227 IndexSet dof_set = dof_handler.locally_owned_mg_dofs(level);
1228
1229 // add the DoF on the adjacent ghost cells to the IndexSet, cache them
1230 // in a set. need to check each dof manually because we can't be sure
1231 // that the dof range of locally_owned_dofs is really contiguous.
1232 std::vector<types::global_dof_index> dof_indices;
1233 std::set<types::global_dof_index> global_dof_indices;
1234
1235 const auto filtered_iterators_range =
1238 for (const auto &cell : filtered_iterators_range)
1239 {
1240 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1241 cell->get_mg_dof_indices(dof_indices);
1242
1243 for (const types::global_dof_index dof_index : dof_indices)
1244 if (!dof_set.is_element(dof_index))
1245 global_dof_indices.insert(dof_index);
1246 }
1247
1248 dof_set.add_indices(global_dof_indices.begin(), global_dof_indices.end());
1249
1250 dof_set.compress();
1251
1252 return dof_set;
1253 }
1254
1255
1256
1257 template <int dim, int spacedim>
1258 void
1260 const DoFHandler<dim, spacedim> &dof_handler,
1261 IndexSet &dof_set,
1262 const unsigned int level)
1263 {
1264 dof_set = extract_locally_active_level_dofs(dof_handler, level);
1265 }
1266
1267
1268
1269 template <int dim, int spacedim>
1270 IndexSet
1272 {
1273 // collect all the locally owned dofs
1274 IndexSet dof_set = dof_handler.locally_owned_dofs();
1275
1276 // now add the DoF on the adjacent ghost cells to the IndexSet
1277
1278 // Note: For certain meshes (in particular in 3d and with many
1279 // processors), it is really necessary to cache intermediate data. After
1280 // trying several objects such as std::set, a vector that is always kept
1281 // sorted, and a vector that is initially unsorted and sorted once at the
1282 // end, the latter has been identified to provide the best performance.
1283 // Martin Kronbichler
1284 std::vector<types::global_dof_index> dof_indices;
1285 std::vector<types::global_dof_index> dofs_on_ghosts;
1286
1287 for (const auto &cell : dof_handler.active_cell_iterators())
1288 if (cell->is_ghost())
1289 {
1290 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1291 cell->get_dof_indices(dof_indices);
1292 for (const auto dof_index : dof_indices)
1293 if (!dof_set.is_element(dof_index))
1294 dofs_on_ghosts.push_back(dof_index);
1295 }
1296
1297 // sort and put into an index set
1298 std::sort(dofs_on_ghosts.begin(), dofs_on_ghosts.end());
1299 dof_set.add_indices(dofs_on_ghosts.begin(), dofs_on_ghosts.end());
1300 dof_set.compress();
1301
1302 return dof_set;
1303 }
1304
1305
1306
1307 template <int dim, int spacedim>
1308 void
1310 IndexSet &dof_set)
1311 {
1312 dof_set = extract_locally_relevant_dofs(dof_handler);
1313 }
1314
1315
1316
1317 template <int dim, int spacedim>
1318 IndexSet
1320 const DoFHandler<dim, spacedim> &dof_handler,
1321 const unsigned int level)
1322 {
1323 // collect all the locally owned dofs
1324 IndexSet dof_set = dof_handler.locally_owned_mg_dofs(level);
1325
1326 // add the DoF on the adjacent ghost cells to the IndexSet
1327
1328 // Note: For certain meshes (in particular in 3d and with many
1329 // processors), it is really necessary to cache intermediate data. After
1330 // trying several objects such as std::set, a vector that is always kept
1331 // sorted, and a vector that is initially unsorted and sorted once at the
1332 // end, the latter has been identified to provide the best performance.
1333 // Martin Kronbichler
1334 std::vector<types::global_dof_index> dof_indices;
1335 std::vector<types::global_dof_index> dofs_on_ghosts;
1336
1337 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
1338 {
1339 const types::subdomain_id id = cell->level_subdomain_id();
1340
1341 // skip artificial and own cells (only look at ghost cells)
1342 if (id == dof_handler.get_triangulation().locally_owned_subdomain() ||
1344 continue;
1345
1346 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1347 cell->get_mg_dof_indices(dof_indices);
1348 for (const auto dof_index : dof_indices)
1349 if (!dof_set.is_element(dof_index))
1350 dofs_on_ghosts.push_back(dof_index);
1351 }
1352
1353 // sort and fill into an index set
1354 std::sort(dofs_on_ghosts.begin(), dofs_on_ghosts.end());
1355 dof_set.add_indices(dofs_on_ghosts.begin(), dofs_on_ghosts.end());
1356 dof_set.compress();
1357
1358 return dof_set;
1359 }
1360
1361
1362
1363 template <int dim, int spacedim>
1364 void
1366 const DoFHandler<dim, spacedim> &dof_handler,
1367 const unsigned int level,
1368 IndexSet &dof_set)
1369 {
1370 dof_set = extract_locally_relevant_level_dofs(dof_handler, level);
1371 }
1372
1373
1374 namespace internal
1375 {
1376 template <int dim, int spacedim>
1377 std::vector<std::vector<bool>>
1379 const ComponentMask &component_mask,
1380 const unsigned int mg_level)
1381 {
1382 std::vector<std::vector<bool>> constant_modes;
1383
1384 const auto &locally_owned_dofs =
1385 (mg_level == numbers::invalid_unsigned_int) ?
1386 dof_handler.locally_owned_dofs() :
1387 dof_handler.locally_owned_mg_dofs(mg_level);
1388
1389 // If there are no locally owned DoFs, return with an empty
1390 // constant_modes object:
1391 if (locally_owned_dofs.n_elements() == 0)
1392 {
1393 return std::vector<std::vector<bool>>(0);
1394 }
1395
1396 const unsigned int n_components = dof_handler.get_fe(0).n_components();
1397 Assert(component_mask.represents_n_components(n_components),
1398 ExcDimensionMismatch(n_components, component_mask.size()));
1399
1400 std::vector<unsigned char> dofs_by_component(
1401 locally_owned_dofs.n_elements());
1403 component_mask,
1404 dofs_by_component,
1405 mg_level);
1406 unsigned int n_selected_dofs = 0;
1407 for (unsigned int i = 0; i < n_components; ++i)
1408 if (component_mask[i] == true)
1409 n_selected_dofs +=
1410 std::count(dofs_by_component.begin(), dofs_by_component.end(), i);
1411
1412 // Find local numbering within the selected components
1413 std::vector<unsigned int> component_numbering(
1414 locally_owned_dofs.n_elements(), numbers::invalid_unsigned_int);
1415 for (unsigned int i = 0, count = 0; i < locally_owned_dofs.n_elements();
1416 ++i)
1417 if (component_mask[dofs_by_component[i]])
1418 component_numbering[i] = count++;
1419
1420 // get the element constant modes and find a translation table between
1421 // index in the constant modes and the components.
1422 //
1423 // TODO: We might be able to extend this also for elements which do not
1424 // have the same constant modes, but that is messy...
1425 const ::hp::FECollection<dim, spacedim> &fe_collection =
1426 dof_handler.get_fe_collection();
1427 std::vector<Table<2, bool>> element_constant_modes;
1428 std::vector<std::vector<std::pair<unsigned int, unsigned int>>>
1429 constant_mode_to_component_translation(n_components);
1430 {
1431 unsigned int n_constant_modes = 0;
1432 int first_non_empty_constant_mode = -1;
1433 for (unsigned int f = 0; f < fe_collection.size(); ++f)
1434 {
1435 std::pair<Table<2, bool>, std::vector<unsigned int>> data =
1436 fe_collection[f].get_constant_modes();
1437
1438 // Store the index of the current element if it is the first that
1439 // has non-empty constant modes.
1440 if (first_non_empty_constant_mode < 0 && data.first.n_rows() > 0)
1441 {
1442 first_non_empty_constant_mode = f;
1443 // This is the first non-empty constant mode, so we figure out
1444 // the translation between index in the constant modes and the
1445 // components
1446 for (unsigned int i = 0; i < data.second.size(); ++i)
1447 if (component_mask[data.second[i]])
1448 constant_mode_to_component_translation[data.second[i]]
1449 .emplace_back(n_constant_modes++, i);
1450 }
1451
1452 // Add the constant modes of this element to the list and assert
1453 // that there are as many constant modes as for the other elements
1454 // (or zero constant modes).
1455 element_constant_modes.push_back(data.first);
1456 Assert(element_constant_modes.back().n_rows() == 0 ||
1457 element_constant_modes.back().n_rows() ==
1458 element_constant_modes[first_non_empty_constant_mode]
1459 .n_rows(),
1461 }
1462 AssertIndexRange(first_non_empty_constant_mode, fe_collection.size());
1463
1464 // Now we know the number of constant modes and resize the return vector
1465 // accordingly
1466 constant_modes.clear();
1467 constant_modes.resize(n_constant_modes,
1468 std::vector<bool>(n_selected_dofs, false));
1469 }
1470
1471 // Loop over all owned cells and ask the element for the constant modes
1472 std::vector<types::global_dof_index> dof_indices;
1473
1474 const auto runner = [&](const auto &task) {
1475 if (mg_level == numbers::invalid_unsigned_int)
1476 {
1477 for (const auto &cell : dof_handler.active_cell_iterators() |
1479 {
1480 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1481 cell->get_dof_indices(dof_indices);
1482
1483 task(cell);
1484 }
1485 }
1486 else
1487 {
1488 for (const auto &cell :
1489 dof_handler.cell_iterators_on_level(mg_level))
1490 if (cell->is_locally_owned_on_level())
1491 {
1492 dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1493 cell->get_mg_dof_indices(dof_indices);
1494
1495 task(cell);
1496 }
1497 }
1498 };
1499
1500 runner([&](const auto &cell) {
1501 for (unsigned int i = 0; i < dof_indices.size(); ++i)
1502 if (locally_owned_dofs.is_element(dof_indices[i]))
1503 {
1504 const unsigned int loc_index =
1505 locally_owned_dofs.index_within_set(dof_indices[i]);
1506 const unsigned int comp = dofs_by_component[loc_index];
1507 if (component_mask[comp])
1508 for (auto &indices :
1509 constant_mode_to_component_translation[comp])
1510 constant_modes[indices
1511 .first][component_numbering[loc_index]] =
1512 element_constant_modes[cell->active_fe_index()](
1513 indices.second, i);
1514 }
1515 });
1516
1517 return constant_modes;
1518 }
1519
1520
1521
1525 template <int dim>
1526 class RigidBodyMotion : public Function<dim>
1527 {
1528 public:
1529 static constexpr unsigned int n_modes = dim * (dim + 1) / 2;
1530
1531 RigidBodyMotion(const unsigned int type);
1532
1533 virtual double
1534 value(const Point<dim> &p, const unsigned int component) const override;
1535
1536 private:
1537 const unsigned int type;
1538 };
1539
1540
1541
1542 template <int dim>
1544 : Function<dim>(dim)
1545 , type(type)
1546 {
1548 }
1549
1550
1551
1553 cross_product(const Tensor<1, 2> &tensor1, const Tensor<1, 1> &tensor2)
1554 {
1555 // |a| |0| |+bc|
1556 // |b| x |0| = |-ac|
1557 // |0| |c| | 0 |
1558
1559 Tensor<1, 2> cproduct;
1560 cproduct[0] = +tensor1[1] * tensor2[0];
1561 cproduct[1] = -tensor1[0] * tensor2[0];
1562 return cproduct;
1563 }
1564
1565
1566
1568 cross_product(const Tensor<1, 3> &tensor1, const Tensor<1, 3> &tensor2)
1569 {
1570 Tensor<1, 3> cproduct;
1571 cproduct[0] = +tensor1[1] * tensor2[2] - tensor1[2] * tensor2[1];
1572 cproduct[1] = +tensor1[2] * tensor2[0] - tensor1[0] * tensor2[2];
1573 cproduct[2] = +tensor1[0] * tensor2[1] - tensor1[1] * tensor2[0];
1574 return cproduct;
1575 }
1576
1577
1578
1579 template <int dim>
1580 double
1582 const unsigned int component) const
1583 {
1584 if (type < dim) // translation modes
1585 return static_cast<double>(component == type);
1586
1587 if constexpr (dim >= 2) // rotation modes
1588 {
1589 Tensor<1, n_modes - dim> dir;
1590 dir[type - dim] = 1.0;
1591
1592 return cross_product(p, dir)[component];
1593 }
1594 else
1595 {
1596 Assert(false, ExcNotImplemented());
1597
1598 return 0.0;
1599 }
1600 }
1601
1602
1603
1604 template <int dim, int spacedim>
1605 std::vector<std::vector<double>>
1607 const DoFHandler<dim, spacedim> &dof_handler,
1608 const ComponentMask &component_mask,
1609 const unsigned int mg_level)
1610 {
1611 AssertDimension(dim, spacedim);
1612
1613 constexpr unsigned int n_modes = RigidBodyMotion<dim>::n_modes;
1614
1615 std::vector<std::vector<double>> rigid_body_modes(n_modes);
1616
1617 LinearAlgebra::distributed::Vector<double> rigid_body_modes_dealii(
1618 mg_level == numbers::invalid_unsigned_int ?
1619 dof_handler.locally_owned_dofs() :
1620 dof_handler.locally_owned_mg_dofs(mg_level),
1621 mg_level == numbers::invalid_unsigned_int ?
1623 DoFTools::extract_locally_active_level_dofs(dof_handler, mg_level),
1624 dof_handler.get_mpi_communicator());
1625
1626 for (unsigned int i = 0; i < n_modes; ++i)
1627 {
1629 dof_handler,
1631 rigid_body_modes_dealii,
1632 component_mask,
1633 mg_level);
1634
1635 // copy to right format
1636 rigid_body_modes[i].assign(rigid_body_modes_dealii.begin(),
1637 rigid_body_modes_dealii.end());
1638 }
1639
1640 return rigid_body_modes;
1641 }
1642
1643 } // namespace internal
1644
1645
1646
1647 template <int dim, int spacedim>
1648 std::vector<std::vector<bool>>
1650 const ComponentMask &component_mask)
1651 {
1652 return internal::extract_constant_modes(dof_handler,
1653 component_mask,
1655 }
1656
1657
1658
1659 template <int dim, int spacedim>
1660 void
1662 const ComponentMask &component_mask,
1663 std::vector<std::vector<bool>> &constant_modes)
1664 {
1665 const auto temp =
1667 component_mask,
1669 constant_modes = temp;
1670 }
1671
1672
1673
1674 template <int dim, int spacedim>
1675 std::vector<std::vector<bool>>
1677 const DoFHandler<dim, spacedim> &dof_handler,
1678 const ComponentMask &component_mask)
1679 {
1680 return internal::extract_constant_modes(dof_handler, component_mask, level);
1681 }
1682
1683
1684
1685 template <int dim, int spacedim>
1686 void
1688 const DoFHandler<dim, spacedim> &dof_handler,
1689 const ComponentMask &component_mask,
1690 std::vector<std::vector<bool>> &constant_modes)
1691 {
1692 const auto temp =
1693 internal::extract_constant_modes(dof_handler, component_mask, level);
1694 constant_modes = temp;
1695 }
1696
1697
1698
1699 template <int dim, int spacedim>
1700 std::vector<std::vector<double>>
1702 const DoFHandler<dim, spacedim> &dof_handler,
1703 const ComponentMask &component_mask)
1704 {
1706 dof_handler,
1707 component_mask,
1709 }
1710
1711
1712
1713 template <int dim, int spacedim>
1714 std::vector<std::vector<double>>
1716 const Mapping<dim, spacedim> &mapping,
1717 const DoFHandler<dim, spacedim> &dof_handler,
1718 const ComponentMask &component_mask)
1719 {
1721 dof_handler,
1722 component_mask,
1723 level);
1724 }
1725
1726
1727
1728 template <int dim, int spacedim>
1729 std::map<typename DoFHandler<dim - 1, spacedim>::active_cell_iterator,
1730 std::pair<typename DoFHandler<dim, spacedim>::active_cell_iterator,
1731 unsigned int>>
1735 &c1_to_c0_face,
1736 const DoFHandler<dim, spacedim> &c0_dh,
1737 const DoFHandler<dim - 1, spacedim> &c1_dh)
1738 {
1739 // This is the returned object: a map of codimension-1 active dof cell
1740 // iterators to codimension-0 cells and face indices
1741 std::map<typename DoFHandler<dim - 1, spacedim>::active_cell_iterator,
1742 std::pair<typename DoFHandler<dim, spacedim>::active_cell_iterator,
1743 unsigned int>>
1744 c1_to_c0_cell_and_face;
1745
1746 // Shortcut if there are no faces to check
1747 if (c1_to_c0_face.empty())
1748 return c1_to_c0_cell_and_face;
1749
1750 // This is the partial inverse of the map passed as input, for dh
1751 std::map<typename Triangulation<dim, spacedim>::face_iterator,
1752 typename DoFHandler<dim - 1, spacedim>::active_cell_iterator>
1753 c0_to_c1;
1754
1755 // map volume mesh face -> codimension 1 dof cell
1756 for (const auto &[c1_cell, c0_cell] : c1_to_c0_face)
1757 if (!c1_cell->has_children())
1758 c0_to_c1[c0_cell] = c1_cell->as_dof_handler_iterator(c1_dh);
1759
1760 // generate a mapping that maps codimension-1 cells
1761 // to codimension-0 cells and faces
1762 for (const auto &cell :
1763 c0_dh.active_cell_iterators()) // disp_dof.active_cell_iterators())
1764 for (const auto f : cell->face_indices())
1765 if (cell->face(f)->at_boundary())
1766 {
1767 const auto &it = c0_to_c1.find(cell->face(f));
1768 if (it != c0_to_c1.end())
1769 {
1770 const auto &c1_cell = it->second;
1771 c1_to_c0_cell_and_face[c1_cell] = {cell, f};
1772 c0_to_c1.erase(it);
1773 }
1774 }
1775 // Check the dimensions: make sure all active cells we had have been mapped.
1776 AssertDimension(c0_to_c1.size(), 0);
1777 return c1_to_c0_cell_and_face;
1778 }
1779
1780
1781
1782 template <int dim, int spacedim>
1783 std::vector<IndexSet>
1785 {
1786 Assert(dof_handler.n_dofs() > 0,
1787 ExcMessage("The given DoFHandler has no DoFs."));
1788
1789 // If the Triangulation is distributed, the only thing we can usefully
1790 // ask is for its locally owned subdomain
1791 Assert((dynamic_cast<
1793 &dof_handler.get_triangulation()) == nullptr),
1794 ExcMessage(
1795 "For parallel::distributed::Triangulation objects and "
1796 "associated DoF handler objects, asking for any information "
1797 "related to a subdomain other than the locally owned one does "
1798 "not make sense."));
1799
1800 // The following is a random process (flip of a coin), thus should be called
1801 // once only.
1802 std::vector<::types::subdomain_id> subdomain_association(
1803 dof_handler.n_dofs());
1805 subdomain_association);
1806
1807 // Figure out how many subdomain ids there are.
1808 //
1809 // if this is a parallel triangulation, then we can just ask the
1810 // triangulation for this. if this is a sequential triangulation, we loop
1811 // over all cells and take the largest subdomain_id value we find; the
1812 // number of subdomains is then the largest found value plus one. (we here
1813 // assume that all subdomain ids up to the largest are actually used; this
1814 // may not be true for a sequential triangulation where these values have
1815 // been set by hand and not in accordance with some MPI communicator; but
1816 // the function returns an array indexed starting at zero, so we need to
1817 // collect information for each subdomain index anyway, not just for the
1818 // used one.)
1819 const unsigned int n_subdomains =
1820 (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
1821 &dof_handler.get_triangulation()) == nullptr ?
1822 [&dof_handler]() {
1823 unsigned int max_subdomain_id = 0;
1824 for (const auto &cell : dof_handler.active_cell_iterators())
1825 max_subdomain_id =
1826 std::max(max_subdomain_id, cell->subdomain_id());
1827 return max_subdomain_id + 1;
1828 }() :
1830 dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
1831 &dof_handler.get_triangulation())
1833 Assert(n_subdomains > *std::max_element(subdomain_association.begin(),
1834 subdomain_association.end()),
1836
1837 std::vector<::IndexSet> index_sets(
1838 n_subdomains, ::IndexSet(dof_handler.n_dofs()));
1839
1840 // loop over subdomain_association and populate IndexSet when a
1841 // change in subdomain ID is found
1842 ::types::global_dof_index i_min = 0;
1843 ::types::global_dof_index this_subdomain = subdomain_association[0];
1844
1845 for (::types::global_dof_index index = 1;
1846 index < subdomain_association.size();
1847 ++index)
1848 {
1849 // found index different from the current one
1850 if (subdomain_association[index] != this_subdomain)
1851 {
1852 index_sets[this_subdomain].add_range(i_min, index);
1853 i_min = index;
1854 this_subdomain = subdomain_association[index];
1855 }
1856 }
1857
1858 // the very last element is of different index
1859 if (i_min == subdomain_association.size() - 1)
1860 {
1861 index_sets[this_subdomain].add_index(i_min);
1862 }
1863
1864 // otherwise there are at least two different indices
1865 else
1866 {
1867 index_sets[this_subdomain].add_range(i_min,
1868 subdomain_association.size());
1869 }
1870
1871 for (unsigned int i = 0; i < n_subdomains; ++i)
1872 index_sets[i].compress();
1873
1874 return index_sets;
1875 }
1876
1877 template <int dim, int spacedim>
1878 std::vector<IndexSet>
1880 const DoFHandler<dim, spacedim> &dof_handler)
1881 {
1882 // If the Triangulation is distributed, the only thing we can usefully
1883 // ask is for its locally owned subdomain
1884 Assert((dynamic_cast<
1886 &dof_handler.get_triangulation()) == nullptr),
1887 ExcMessage(
1888 "For parallel::distributed::Triangulation objects and "
1889 "associated DoF handler objects, asking for any information "
1890 "related to a subdomain other than the locally owned one does "
1891 "not make sense."));
1892
1893 // Collect all the locally owned DoFs
1894 // Note: Even though the distribution of DoFs by the
1895 // locally_owned_dofs_per_subdomain function is pseudo-random, we will
1896 // collect all the DoFs on the subdomain and its layer cell. Therefore, the
1897 // random nature of this function does not play a role in the extraction of
1898 // the locally relevant DoFs
1899 std::vector<IndexSet> dof_set =
1901 const ::types::subdomain_id n_subdomains = dof_set.size();
1902
1903 // Add the DoFs on the adjacent (equivalent ghost) cells to the IndexSet,
1904 // cache them in a set. Need to check each DoF manually because we can't
1905 // be sure that the DoF range of locally_owned_dofs is really contiguous.
1906 for (::types::subdomain_id subdomain_id = 0;
1907 subdomain_id < n_subdomains;
1908 ++subdomain_id)
1909 {
1910 // Extract the layer of cells around this subdomain
1911 std::function<bool(
1913 predicate = IteratorFilters::SubdomainEqualTo(subdomain_id);
1914 const std::vector<
1916 active_halo_layer =
1917 GridTools::compute_active_cell_halo_layer(dof_handler, predicate);
1918
1919 // Extract DoFs associated with halo layer
1920 std::vector<types::global_dof_index> local_dof_indices;
1921 std::set<types::global_dof_index> subdomain_halo_global_dof_indices;
1922 for (typename std::vector<
1924 const_iterator it_cell = active_halo_layer.begin();
1925 it_cell != active_halo_layer.end();
1926 ++it_cell)
1927 {
1929 &cell = *it_cell;
1930 Assert(
1931 cell->subdomain_id() != subdomain_id,
1932 ExcMessage(
1933 "The subdomain ID of the halo cell should not match that of the vector entry."));
1934
1935 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
1936 cell->get_dof_indices(local_dof_indices);
1937
1938 for (const types::global_dof_index local_dof_index :
1939 local_dof_indices)
1940 subdomain_halo_global_dof_indices.insert(local_dof_index);
1941 }
1942
1943 dof_set[subdomain_id].add_indices(
1944 subdomain_halo_global_dof_indices.begin(),
1945 subdomain_halo_global_dof_indices.end());
1946
1947 dof_set[subdomain_id].compress();
1948 }
1949
1950 return dof_set;
1951 }
1952
1953 template <int dim, int spacedim>
1954 void
1956 const DoFHandler<dim, spacedim> &dof_handler,
1957 std::vector<types::subdomain_id> &subdomain_association)
1958 {
1959 // if the Triangulation is distributed, the only thing we can usefully
1960 // ask is for its locally owned subdomain
1961 Assert((dynamic_cast<
1963 &dof_handler.get_triangulation()) == nullptr),
1964 ExcMessage(
1965 "For parallel::distributed::Triangulation objects and "
1966 "associated DoF handler objects, asking for any subdomain other "
1967 "than the locally owned one does not make sense."));
1968
1969 Assert(subdomain_association.size() == dof_handler.n_dofs(),
1970 ExcDimensionMismatch(subdomain_association.size(),
1971 dof_handler.n_dofs()));
1972
1973 // catch an error that happened in some versions of the shared tria
1974 // distribute_dofs() function where we were trying to call this
1975 // function at a point in time when not all internal DoFHandler
1976 // structures were quite set up yet.
1977 Assert(dof_handler.n_dofs() > 0, ExcInternalError());
1978
1979 // In case this function is executed with parallel::shared::Triangulation
1980 // with possibly artificial cells, we need to take "true" subdomain IDs
1981 // (i.e. without artificial cells). Otherwise we are good to use
1982 // subdomain_id as stored in cell->subdomain_id().
1983 std::vector<types::subdomain_id> cell_owners(
1984 dof_handler.get_triangulation().n_active_cells());
1987 &dof_handler.get_triangulation())))
1988 {
1989 cell_owners = tr->get_true_subdomain_ids_of_cells();
1990 Assert(tr->get_true_subdomain_ids_of_cells().size() ==
1991 tr->n_active_cells(),
1993 }
1994 else
1995 {
1996 for (const auto &cell : dof_handler.active_cell_iterators() |
1998 cell_owners[cell->active_cell_index()] = cell->subdomain_id();
1999 }
2000
2001 // preset all values by an invalid value
2002 std::fill_n(subdomain_association.begin(),
2003 dof_handler.n_dofs(),
2005
2006 std::vector<types::global_dof_index> local_dof_indices;
2007 local_dof_indices.reserve(
2008 dof_handler.get_fe_collection().max_dofs_per_cell());
2009
2010 // loop over all cells and record which subdomain a DoF belongs to.
2011 // give to the smaller subdomain_id in case it is on an interface
2012 for (const auto &cell : dof_handler.active_cell_iterators())
2013 {
2014 const types::subdomain_id subdomain_id =
2015 cell_owners[cell->active_cell_index()];
2016 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
2017 local_dof_indices.resize(dofs_per_cell);
2018 cell->get_dof_indices(local_dof_indices);
2019
2020 // set subdomain ids. if dofs already have their values set then
2021 // they must be on partition interfaces. in that case assign them
2022 // to either the previous association or the current processor
2023 // with the smaller subdomain id.
2024 for (unsigned int i = 0; i < dofs_per_cell; ++i)
2025 if (subdomain_association[local_dof_indices[i]] ==
2027 subdomain_association[local_dof_indices[i]] = subdomain_id;
2028 else if (subdomain_association[local_dof_indices[i]] > subdomain_id)
2029 {
2030 subdomain_association[local_dof_indices[i]] = subdomain_id;
2031 }
2032 }
2033
2034 Assert(std::find(subdomain_association.begin(),
2035 subdomain_association.end(),
2037 subdomain_association.end(),
2039 }
2040
2041
2042
2043 template <int dim, int spacedim>
2044 unsigned int
2046 const DoFHandler<dim, spacedim> &dof_handler,
2047 const types::subdomain_id subdomain)
2048 {
2049 std::vector<types::subdomain_id> subdomain_association(
2050 dof_handler.n_dofs());
2051 get_subdomain_association(dof_handler, subdomain_association);
2052
2053 return std::count(subdomain_association.begin(),
2054 subdomain_association.end(),
2055 subdomain);
2056 }
2057
2058
2059
2060 template <int dim, int spacedim>
2061 IndexSet
2063 const DoFHandler<dim, spacedim> &dof_handler,
2064 const types::subdomain_id subdomain)
2065 {
2066 // If we have a distributed::Triangulation only allow locally_owned
2067 // subdomain.
2070 (subdomain ==
2072 ExcMessage(
2073 "For parallel::distributed::Triangulation objects and "
2074 "associated DoF handler objects, asking for any subdomain other "
2075 "than the locally owned one does not make sense."));
2076
2077 IndexSet index_set(dof_handler.n_dofs());
2078
2079 std::vector<types::global_dof_index> local_dof_indices;
2080 local_dof_indices.reserve(
2081 dof_handler.get_fe_collection().max_dofs_per_cell());
2082
2083 // first generate an unsorted list of all indices which we fill from
2084 // the back. could also insert them directly into the IndexSet, but
2085 // that inserts indices in the middle, which is an O(n^2) algorithm and
2086 // hence too expensive. Could also use std::set, but that is in general
2087 // more expensive than a vector
2088 std::vector<types::global_dof_index> subdomain_indices;
2089
2090 for (const auto &cell : dof_handler.active_cell_iterators())
2091 if ((cell->is_artificial() == false) &&
2092 (cell->subdomain_id() == subdomain))
2093 {
2094 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
2095 local_dof_indices.resize(dofs_per_cell);
2096 cell->get_dof_indices(local_dof_indices);
2097 subdomain_indices.insert(subdomain_indices.end(),
2098 local_dof_indices.begin(),
2099 local_dof_indices.end());
2100 }
2101 // sort indices and put into an index set:
2102 std::sort(subdomain_indices.begin(), subdomain_indices.end());
2103 index_set.add_indices(subdomain_indices.begin(), subdomain_indices.end());
2104 index_set.compress();
2105
2106 return index_set;
2107 }
2108
2109
2110
2111 template <int dim, int spacedim>
2112 void
2114 const DoFHandler<dim, spacedim> &dof_handler,
2115 const types::subdomain_id subdomain,
2116 std::vector<unsigned int> &n_dofs_on_subdomain)
2117 {
2118 Assert(n_dofs_on_subdomain.size() == dof_handler.get_fe(0).n_components(),
2119 ExcDimensionMismatch(n_dofs_on_subdomain.size(),
2120 dof_handler.get_fe(0).n_components()));
2121 std::fill(n_dofs_on_subdomain.begin(), n_dofs_on_subdomain.end(), 0);
2122
2123 // Make sure there are at least some cells with this subdomain id
2124 Assert(std::any_of(
2125 dof_handler.begin_active(),
2127 dof_handler.end()},
2128 [subdomain](
2129 const typename DoFHandler<dim, spacedim>::cell_accessor &cell) {
2130 return cell.subdomain_id() == subdomain;
2131 }),
2132 ExcMessage("There are no cells for the given subdomain!"));
2133
2134 std::vector<types::subdomain_id> subdomain_association(
2135 dof_handler.n_dofs());
2136 get_subdomain_association(dof_handler, subdomain_association);
2137
2138 std::vector<unsigned char> component_association(dof_handler.n_dofs());
2140 ComponentMask(std::vector<bool>()),
2141 component_association);
2142
2143 for (unsigned int c = 0; c < dof_handler.get_fe(0).n_components(); ++c)
2144 {
2145 for (types::global_dof_index i = 0; i < dof_handler.n_dofs(); ++i)
2146 if ((subdomain_association[i] == subdomain) &&
2147 (component_association[i] == static_cast<unsigned char>(c)))
2148 ++n_dofs_on_subdomain[c];
2149 }
2150 }
2151
2152
2153
2154 namespace internal
2155 {
2156 // TODO: why is this function so complicated? It would be nice to have
2157 // comments that explain why we can't just loop over all components and
2158 // count the entries in dofs_by_component that have this component's
2159 // index
2160 template <int dim, int spacedim>
2161 void
2163 const std::vector<unsigned char> &dofs_by_component,
2164 const std::vector<unsigned int> &target_component,
2165 const bool only_once,
2166 std::vector<types::global_dof_index> &dofs_per_component,
2167 unsigned int &component)
2168 {
2169 for (unsigned int b = 0; b < fe.n_base_elements(); ++b)
2170 {
2171 const FiniteElement<dim, spacedim> &base = fe.base_element(b);
2172 // Dimension of base element
2173 unsigned int d = base.n_components();
2174
2175 for (unsigned int m = 0; m < fe.element_multiplicity(b); ++m)
2176 {
2177 if (base.n_base_elements() > 1)
2178 resolve_components(base,
2179 dofs_by_component,
2180 target_component,
2181 only_once,
2182 dofs_per_component,
2183 component);
2184 else
2185 {
2186 for (unsigned int dd = 0; dd < d; ++dd, ++component)
2187 dofs_per_component[target_component[component]] +=
2188 std::count(dofs_by_component.begin(),
2189 dofs_by_component.end(),
2190 component);
2191
2192 // if we have non-primitive FEs and want all components
2193 // to show the number of dofs, need to copy the result to
2194 // those components
2195 if (!base.is_primitive() && !only_once)
2196 for (unsigned int dd = 1; dd < d; ++dd)
2197 dofs_per_component[target_component[component - d + dd]] =
2198 dofs_per_component[target_component[component - d]];
2199 }
2200 }
2201 }
2202 }
2203
2204
2205 template <int dim, int spacedim>
2206 void
2208 const std::vector<unsigned char> &dofs_by_component,
2209 const std::vector<unsigned int> &target_component,
2210 const bool only_once,
2211 std::vector<types::global_dof_index> &dofs_per_component,
2212 unsigned int &component)
2213 {
2214 // assert that all elements in the collection have the same structure
2215 // (base elements and multiplicity, components per base element) and
2216 // then simply call the function above
2217 for (unsigned int fe = 1; fe < fe_collection.size(); ++fe)
2218 {
2219 Assert(fe_collection[fe].n_components() ==
2220 fe_collection[0].n_components(),
2222 Assert(fe_collection[fe].n_base_elements() ==
2223 fe_collection[0].n_base_elements(),
2225 for (unsigned int b = 0; b < fe_collection[0].n_base_elements(); ++b)
2226 {
2227 Assert(fe_collection[fe].base_element(b).n_components() ==
2228 fe_collection[0].base_element(b).n_components(),
2230 Assert(fe_collection[fe].base_element(b).n_base_elements() ==
2231 fe_collection[0].base_element(b).n_base_elements(),
2233 }
2234 }
2235
2236 resolve_components(fe_collection[0],
2237 dofs_by_component,
2238 target_component,
2239 only_once,
2240 dofs_per_component,
2241 component);
2242 }
2243 } // namespace internal
2244
2245
2246
2247 namespace internal
2248 {
2249 namespace
2250 {
2255 template <int dim, int spacedim>
2256 bool
2257 all_elements_are_primitive(
2258 const ::hp::FECollection<dim, spacedim> &fe_collection)
2259 {
2260 for (unsigned int i = 0; i < fe_collection.size(); ++i)
2261 if (fe_collection[i].is_primitive() == false)
2262 return false;
2263
2264 return true;
2265 }
2266 } // namespace
2267 } // namespace internal
2268
2269
2270
2271 template <int dim, int spacedim>
2272 std::vector<types::global_dof_index>
2274 const DoFHandler<dim, spacedim> &dof_handler,
2275 const bool only_once,
2276 const std::vector<unsigned int> &target_component_)
2277 {
2278 const unsigned int n_components = dof_handler.get_fe(0).n_components();
2279
2280 // If the empty vector was given as default argument, set up this
2281 // vector as identity.
2282 std::vector<unsigned int> target_component = target_component_;
2283 if (target_component.empty())
2284 {
2285 target_component.resize(n_components);
2286 for (unsigned int i = 0; i < n_components; ++i)
2287 target_component[i] = i;
2288 }
2289 else
2290 Assert(target_component.size() == n_components,
2291 ExcDimensionMismatch(target_component.size(), n_components));
2292
2293
2294 const unsigned int max_component =
2295 *std::max_element(target_component.begin(), target_component.end());
2296 const unsigned int n_target_components = max_component + 1;
2297
2298 std::vector<types::global_dof_index> dofs_per_component(
2299 n_target_components, types::global_dof_index(0));
2300
2301 // special case for only one component. treat this first since it does
2302 // not require any computations
2303 if (n_components == 1)
2304 {
2305 dofs_per_component[0] = dof_handler.n_locally_owned_dofs();
2306 return dofs_per_component;
2307 }
2308
2309
2310 // otherwise determine the number of dofs in each component separately.
2311 // do so in parallel
2312 std::vector<unsigned char> dofs_by_component(
2313 dof_handler.n_locally_owned_dofs());
2315 ComponentMask(),
2316 dofs_by_component);
2317
2318 // next count what we got
2319 unsigned int component = 0;
2321 dofs_by_component,
2322 target_component,
2323 only_once,
2324 dofs_per_component,
2325 component);
2326 Assert(n_components == component, ExcInternalError());
2327
2328 // finally sanity check. this is only valid if the finite element is
2329 // actually primitive, so exclude other elements from this
2330 Assert((internal::all_elements_are_primitive(
2331 dof_handler.get_fe_collection()) == false) ||
2332 (std::accumulate(dofs_per_component.begin(),
2333 dofs_per_component.end(),
2335 dof_handler.n_locally_owned_dofs()),
2337
2338 // reduce information from all CPUs
2339#ifdef DEAL_II_WITH_MPI
2340
2342 (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
2343 &dof_handler.get_triangulation())))
2344 {
2345 std::vector<types::global_dof_index> local_dof_count =
2346 dofs_per_component;
2347
2348 const int ierr = MPI_Allreduce(
2349 local_dof_count.data(),
2350 dofs_per_component.data(),
2351 n_target_components,
2352 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
2353 MPI_SUM,
2354 tria->get_mpi_communicator());
2355 AssertThrowMPI(ierr);
2356 }
2357#endif
2358
2359 return dofs_per_component;
2360 }
2361
2362
2363
2364 template <int dim, int spacedim>
2365 std::vector<types::global_dof_index>
2367 const std::vector<unsigned int> &target_block_)
2368 {
2369 const ::hp::FECollection<dim, spacedim> &fe_collection =
2370 dof_handler.get_fe_collection();
2371 Assert(fe_collection.size() < 256, ExcNotImplemented());
2372
2373 // If the empty vector for target_block(e.g., as default argument), then
2374 // set up this vector as identity. We do this set up with the first
2375 // element of the collection, but the whole thing can only work if
2376 // all elements have the same number of blocks anyway -- so check
2377 // that right after
2378 const unsigned int n_blocks = fe_collection[0].n_blocks();
2379
2380 std::vector<unsigned int> target_block = target_block_;
2381 if (target_block.empty())
2382 {
2383 target_block.resize(fe_collection[0].n_blocks());
2384 for (unsigned int i = 0; i < n_blocks; ++i)
2385 target_block[i] = i;
2386 }
2387 else
2388 Assert(target_block.size() == n_blocks,
2389 ExcDimensionMismatch(target_block.size(), n_blocks));
2390 for (unsigned int f = 1; f < fe_collection.size(); ++f)
2391 Assert(fe_collection[0].n_blocks() == fe_collection[f].n_blocks(),
2392 ExcMessage("This function can only work if all elements in a "
2393 "collection have the same number of blocks."));
2394
2395 // special case for only one block. treat this first since it does
2396 // not require any computations
2397 if (n_blocks == 1)
2398 {
2399 std::vector<types::global_dof_index> dofs_per_block(1);
2400 dofs_per_block[0] = dof_handler.n_dofs();
2401 return dofs_per_block;
2402 }
2403
2404 // Otherwise set up the right-sized object and start working
2405 const unsigned int max_block =
2406 *std::max_element(target_block.begin(), target_block.end());
2407 const unsigned int n_target_blocks = max_block + 1;
2408
2409 std::vector<types::global_dof_index> dofs_per_block(n_target_blocks);
2410
2411 // Loop over the elements of the collection, but really only consider
2412 // the last element (see #9271)
2413 for (unsigned int this_fe = fe_collection.size() - 1;
2414 this_fe < fe_collection.size();
2415 ++this_fe)
2416 {
2417 const FiniteElement<dim, spacedim> &fe = fe_collection[this_fe];
2418
2419 std::vector<unsigned char> dofs_by_block(
2420 dof_handler.n_locally_owned_dofs());
2421 internal::get_block_association(dof_handler, dofs_by_block);
2422
2423 // next count what we got
2424 for (unsigned int block = 0; block < fe.n_blocks(); ++block)
2425 dofs_per_block[target_block[block]] +=
2426 std::count(dofs_by_block.begin(), dofs_by_block.end(), block);
2427
2428#ifdef DEAL_II_WITH_MPI
2429 // if we are working on a parallel mesh, we now need to collect
2430 // this information from all processors
2432 (dynamic_cast<const parallel::TriangulationBase<dim, spacedim> *>(
2433 &dof_handler.get_triangulation())))
2434 {
2435 std::vector<types::global_dof_index> local_dof_count =
2436 dofs_per_block;
2437 const int ierr = MPI_Allreduce(
2438 local_dof_count.data(),
2439 dofs_per_block.data(),
2440 n_target_blocks,
2441 Utilities::MPI::mpi_type_id_for_type<types::global_dof_index>,
2442 MPI_SUM,
2443 tria->get_mpi_communicator());
2444 AssertThrowMPI(ierr);
2445 }
2446#endif
2447 }
2448
2449 return dofs_per_block;
2450 }
2451
2452
2453
2454 template <int dim, int spacedim>
2455 void
2457 std::vector<types::global_dof_index> &mapping)
2458 {
2459 mapping.clear();
2460 mapping.insert(mapping.end(),
2461 dof_handler.n_dofs(),
2463
2464 std::vector<types::global_dof_index> dofs_on_face;
2465 dofs_on_face.reserve(dof_handler.get_fe_collection().max_dofs_per_face());
2466 types::global_dof_index next_boundary_index = 0;
2467
2468 // now loop over all cells and check whether their faces are at the
2469 // boundary. note that we need not take special care of single lines
2470 // being at the boundary (using @p{cell->has_boundary_lines}), since we
2471 // do not support boundaries of dimension dim-2, and so every isolated
2472 // boundary line is also part of a boundary face which we will be
2473 // visiting sooner or later
2474 for (const auto &cell : dof_handler.active_cell_iterators())
2475 for (const unsigned int f : cell->face_indices())
2476 if (cell->at_boundary(f))
2477 {
2478 const unsigned int dofs_per_face =
2479 cell->get_fe().n_dofs_per_face(f);
2480 dofs_on_face.resize(dofs_per_face);
2481 cell->face(f)->get_dof_indices(dofs_on_face,
2482 cell->active_fe_index());
2483 for (unsigned int i = 0; i < dofs_per_face; ++i)
2484 if (mapping[dofs_on_face[i]] == numbers::invalid_dof_index)
2485 mapping[dofs_on_face[i]] = next_boundary_index++;
2486 }
2487
2488 AssertDimension(next_boundary_index, dof_handler.n_boundary_dofs());
2489 }
2490
2491
2492
2493 template <int dim, int spacedim>
2494 void
2496 const std::set<types::boundary_id> &boundary_ids,
2497 std::vector<types::global_dof_index> &mapping)
2498 {
2499 Assert(boundary_ids.find(numbers::internal_face_boundary_id) ==
2500 boundary_ids.end(),
2502
2503 mapping.clear();
2504 mapping.insert(mapping.end(),
2505 dof_handler.n_dofs(),
2507
2508 // return if there is nothing to do
2509 if (boundary_ids.empty())
2510 return;
2511
2512 std::vector<types::global_dof_index> dofs_on_face;
2513 dofs_on_face.reserve(dof_handler.get_fe_collection().max_dofs_per_face());
2514 types::global_dof_index next_boundary_index = 0;
2515
2516 for (const auto &cell : dof_handler.active_cell_iterators())
2517 for (const unsigned int f : cell->face_indices())
2518 if (boundary_ids.find(cell->face(f)->boundary_id()) !=
2519 boundary_ids.end())
2520 {
2521 const unsigned int dofs_per_face =
2522 cell->get_fe().n_dofs_per_face(f);
2523 dofs_on_face.resize(dofs_per_face);
2524 cell->face(f)->get_dof_indices(dofs_on_face,
2525 cell->active_fe_index());
2526 for (unsigned int i = 0; i < dofs_per_face; ++i)
2527 if (mapping[dofs_on_face[i]] == numbers::invalid_dof_index)
2528 mapping[dofs_on_face[i]] = next_boundary_index++;
2529 }
2530
2531 AssertDimension(next_boundary_index,
2532 dof_handler.n_boundary_dofs(boundary_ids));
2533 }
2534
2535 namespace internal
2536 {
2537 namespace
2538 {
2539 template <int dim, int spacedim>
2540 std::map<types::global_dof_index, Point<spacedim>>
2543 const DoFHandler<dim, spacedim> &dof_handler,
2544 const ComponentMask &in_mask,
2545 const bool map_locally_relevant_dofs)
2546 {
2547 std::map<types::global_dof_index, Point<spacedim>> support_points;
2548
2549 const hp::FECollection<dim, spacedim> &fe_collection =
2550 dof_handler.get_fe_collection();
2551 hp::QCollection<dim> q_coll_dummy;
2552
2553 // Take care of components
2554 const ComponentMask mask =
2555 (in_mask.size() == 0 ?
2556 ComponentMask(fe_collection.n_components(), true) :
2557 in_mask);
2558
2559 for (unsigned int fe_index = 0; fe_index < fe_collection.size();
2560 ++fe_index)
2561 {
2562 // check whether every FE in the collection has support points
2563 Assert(
2564 (fe_collection[fe_index].get_sub_fe(mask).n_dofs_per_cell() ==
2565 0) ||
2566 (fe_collection[fe_index].get_sub_fe(mask).has_support_points()),
2568 q_coll_dummy.push_back(
2569 Quadrature<dim>(fe_collection[fe_index]
2570 .get_sub_fe(mask)
2571 .get_unit_support_points()));
2572 }
2573
2574
2575
2576 // Now loop over all cells and enquire the support points on each
2577 // of these. we use dummy quadrature formulas where the quadrature
2578 // points are located at the unit support points to enquire the
2579 // location of the support points in real space.
2580 //
2581 // The weights of the quadrature rule have been set to invalid
2582 // values by the used constructor.
2583 hp::FEValues<dim, spacedim> hp_fe_values(mapping,
2584 fe_collection,
2585 q_coll_dummy,
2587
2588 const IndexSet &locally_owned_dofs = dof_handler.locally_owned_dofs();
2589 std::vector<types::global_dof_index> local_dof_indices;
2590 for (const auto &cell : dof_handler.active_cell_iterators())
2591 // Work on locally relevant or locally owned cells. Exclude cells
2592 // without DoFs (e.g., if a cell has FE_Nothing associated with it)
2593 // because that trips up internal assertions about using FEValues with
2594 // quadrature formulas without quadrature points.
2595 if ((cell->is_artificial() == false) &&
2596 (map_locally_relevant_dofs || cell->is_locally_owned()) &&
2597 (cell->get_fe().n_dofs_per_cell() > 0))
2598 {
2599 hp_fe_values.reinit(cell);
2600 const FEValues<dim, spacedim> &fe_values =
2601 hp_fe_values.get_present_fe_values();
2602
2603 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
2604 cell->get_dof_indices(local_dof_indices);
2605
2606 const std::vector<Point<spacedim>> &points =
2607 fe_values.get_quadrature_points();
2608
2609 // When using a component mask, the quadrature points only
2610 // correspond to the selected components (via get_sub_fe(mask)).
2611 // So we map between the DoF indices and the filtered support
2612 // point indices.
2613 unsigned int point_index = 0;
2614 for (unsigned int i = 0; i < cell->get_fe().n_dofs_per_cell();
2615 ++i)
2616 {
2617 const unsigned int dof_comp =
2618 cell->get_fe().system_to_component_index(i).first;
2619
2620 // insert the values into the map if it is a valid component
2621 if (mask[dof_comp])
2622 {
2623 // make sure we do not go out of bounds
2624 Assert(point_index < points.size(), ExcInternalError());
2625
2626 // For continuous elements, we encounter some DoFs more
2627 // than once, namely from each cell that is adjacent to a
2628 // DoF. If everything is alright then a DoF should have
2629 // the same support point on all elements over which it
2630 // has support.
2631 //
2632 // This assertion verifies exactly that: if a DoF is
2633 // encountered more than once in this function, then its
2634 // support point should be the same (up to a numerical
2635 // tolerance).
2636 if constexpr (running_in_debug_mode())
2637 {
2638 const auto it =
2639 support_points.find(local_dof_indices[i]);
2640 // if we have degree p Lagrange elements and width dx
2641 // cells, then points are approximately dx / (p ** 2)
2642 // apart. Make that tolerance stricter (we should
2643 // catch other errors), but not much stricter so that
2644 // we don't unnecessarily constrain huge elements
2645 // which may exhibit major roundoff problems when we
2646 // subtract
2647 if (it != support_points.end())
2648 {
2649 const auto p = cell->get_fe().tensor_degree();
2650 Assert((it->second - points[point_index]).norm() <
2651 cell->diameter() / (4.0 * p * p),
2653 }
2654 }
2655
2656 if (map_locally_relevant_dofs ||
2657 locally_owned_dofs.is_element(local_dof_indices[i]))
2658 support_points[local_dof_indices[i]] =
2659 points[point_index];
2660
2661 ++point_index;
2662 }
2663 }
2664 }
2665
2666 return support_points;
2667 }
2668
2669
2670 template <int dim, int spacedim>
2671 std::vector<Point<spacedim>>
2672 map_dofs_to_support_points_vector(
2674 const DoFHandler<dim, spacedim> &dof_handler,
2675 const ComponentMask &mask,
2676 const bool map_locally_relevant_dofs)
2677 {
2678 std::vector<Point<spacedim>> support_points(dof_handler.n_dofs());
2679
2680 // get the data in the form of the map as above
2681 const std::map<types::global_dof_index, Point<spacedim>>
2682 x_support_points = map_dofs_to_support_points(
2683 mapping, dof_handler, mask, map_locally_relevant_dofs);
2684
2685 // now convert from the map to the linear vector. make sure every
2686 // entry really appeared in the map
2687 for (types::global_dof_index i = 0; i < dof_handler.n_dofs(); ++i)
2688 {
2689 Assert(x_support_points.find(i) != x_support_points.end(),
2691
2692 support_points[i] = x_support_points.find(i)->second;
2693 }
2694
2695 return support_points;
2696 }
2697 } // namespace
2698 } // namespace internal
2699
2700
2701 template <int dim, int spacedim>
2702 void
2704 const DoFHandler<dim, spacedim> &dof_handler,
2705 std::vector<Point<spacedim>> &support_points,
2706 const ComponentMask &mask,
2707 const bool map_locally_relevant_dofs)
2708 {
2709 AssertDimension(support_points.size(), dof_handler.n_dofs());
2710 Assert((dynamic_cast<
2712 &dof_handler.get_triangulation()) == nullptr),
2713 ExcMessage(
2714 "This function can not be used with distributed triangulations. "
2715 "See the documentation for more information."));
2716
2717 // Let the internal function do all the work, just make sure that it
2718 // gets a MappingCollection
2719 const hp::MappingCollection<dim, spacedim> mapping_collection(mapping);
2720
2721 support_points = internal::map_dofs_to_support_points_vector(
2722 mapping_collection, dof_handler, mask, map_locally_relevant_dofs);
2723 }
2724
2725
2726 template <int dim, int spacedim>
2727 void
2730 const DoFHandler<dim, spacedim> &dof_handler,
2731 std::vector<Point<spacedim>> &support_points,
2732 const ComponentMask &mask,
2733 const bool map_locally_relevant_dofs)
2734 {
2735 AssertDimension(support_points.size(), dof_handler.n_dofs());
2736 Assert((dynamic_cast<
2738 &dof_handler.get_triangulation()) == nullptr),
2739 ExcMessage(
2740 "This function can not be used with distributed triangulations. "
2741 "See the documentation for more information."));
2742
2743 // Let the internal function do all the work, just make sure that it
2744 // gets a MappingCollection
2745 support_points = internal::map_dofs_to_support_points_vector(
2746 mapping, dof_handler, mask, map_locally_relevant_dofs);
2747 }
2748
2749
2750 template <int dim, int spacedim>
2751 std::map<types::global_dof_index, Point<spacedim>>
2753 const DoFHandler<dim, spacedim> &dof_handler,
2754 const ComponentMask &mask,
2755 const bool map_locally_relevant_dofs)
2756 {
2757 // Let the internal function do all the work, just make sure that it
2758 // gets a MappingCollection
2759 const hp::MappingCollection<dim, spacedim> mapping_collection(mapping);
2760
2761 return internal::map_dofs_to_support_points(mapping_collection,
2762 dof_handler,
2763 mask,
2764 map_locally_relevant_dofs);
2765 }
2766
2767
2768 template <int dim, int spacedim>
2769 std::map<types::global_dof_index, Point<spacedim>>
2772 const DoFHandler<dim, spacedim> &dof_handler,
2773 const ComponentMask &mask,
2774 const bool map_locally_relevant_dofs)
2775 {
2776 return internal::map_dofs_to_support_points(mapping,
2777 dof_handler,
2778 mask,
2779 map_locally_relevant_dofs);
2780 }
2781
2782
2783 template <int spacedim>
2784 void
2786 std::ostream &out,
2787 const std::map<types::global_dof_index, Point<spacedim>> &support_points)
2788 {
2789 AssertThrow(out.fail() == false, ExcIO());
2790
2791 std::map<Point<spacedim>,
2792 std::vector<types::global_dof_index>,
2794 point_map;
2795
2796 // convert to map point -> list of DoFs
2797 for (const auto &it : support_points)
2798 {
2799 std::vector<types::global_dof_index> &v = point_map[it.second];
2800 v.push_back(it.first);
2801 }
2802
2803 // print the newly created map:
2804 for (const auto &it : point_map)
2805 {
2806 out << it.first << " \"";
2807 const std::vector<types::global_dof_index> &v = it.second;
2808 for (unsigned int i = 0; i < v.size(); ++i)
2809 {
2810 if (i > 0)
2811 out << ", ";
2812 out << v[i];
2813 }
2814
2815 out << "\"\n";
2816 }
2817
2818 out << std::flush;
2819 }
2820
2821
2822 template <int dim, int spacedim>
2823 void
2825 const Table<2, Coupling> &table,
2826 std::vector<Table<2, Coupling>> &tables_by_block)
2827 {
2828 if (dof_handler.has_hp_capabilities() == false)
2829 {
2830 const FiniteElement<dim, spacedim> &fe = dof_handler.get_fe();
2831 const unsigned int nb = fe.n_blocks();
2832
2833 tables_by_block.resize(1);
2834 tables_by_block[0].reinit(nb, nb);
2835 tables_by_block[0].fill(none);
2836
2837 for (unsigned int i = 0; i < fe.n_components(); ++i)
2838 {
2839 const unsigned int ib = fe.component_to_block_index(i);
2840 for (unsigned int j = 0; j < fe.n_components(); ++j)
2841 {
2842 const unsigned int jb = fe.component_to_block_index(j);
2843 tables_by_block[0](ib, jb) |= table(i, j);
2844 }
2845 }
2846 }
2847 else
2848 {
2849 const hp::FECollection<dim> &fe_collection =
2850 dof_handler.get_fe_collection();
2851 tables_by_block.resize(fe_collection.size());
2852
2853 for (unsigned int f = 0; f < fe_collection.size(); ++f)
2854 {
2855 const FiniteElement<dim, spacedim> &fe = fe_collection[f];
2856
2857 const unsigned int nb = fe.n_blocks();
2858 tables_by_block[f].reinit(nb, nb);
2859 tables_by_block[f].fill(none);
2860 for (unsigned int i = 0; i < fe.n_components(); ++i)
2861 {
2862 const unsigned int ib = fe.component_to_block_index(i);
2863 for (unsigned int j = 0; j < fe.n_components(); ++j)
2864 {
2865 const unsigned int jb = fe.component_to_block_index(j);
2866 tables_by_block[f](ib, jb) |= table(i, j);
2867 }
2868 }
2869 }
2870 }
2871 }
2872
2873
2874
2875 template <int dim, int spacedim>
2876 void
2878 const DoFHandler<dim, spacedim> &dof_handler,
2879 const unsigned int level,
2880 const std::vector<bool> &selected_dofs,
2881 const types::global_dof_index offset)
2882 {
2883 std::vector<types::global_dof_index> indices;
2884
2885 unsigned int i = 0;
2886
2887 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
2888 if (cell->is_locally_owned_on_level())
2889 ++i;
2890 block_list.reinit(i,
2891 dof_handler.n_dofs(),
2892 dof_handler.get_fe().n_dofs_per_cell());
2893 i = 0;
2894 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
2895 if (cell->is_locally_owned_on_level())
2896 {
2897 indices.resize(cell->get_fe().n_dofs_per_cell());
2898 cell->get_mg_dof_indices(indices);
2899
2900 if (selected_dofs.size() != 0)
2901 AssertDimension(indices.size(), selected_dofs.size());
2902
2903 for (types::global_dof_index j = 0; j < indices.size(); ++j)
2904 {
2905 if (selected_dofs.empty())
2906 block_list.add(i, indices[j] - offset);
2907 else
2908 {
2909 if (selected_dofs[j])
2910 block_list.add(i, indices[j] - offset);
2911 }
2912 }
2913 ++i;
2914 }
2915 }
2916
2917
2918 template <int dim, int spacedim>
2919 void
2921 const DoFHandler<dim, spacedim> &dof_handler,
2922 const unsigned int level,
2923 const bool interior_only)
2924 {
2925 const FiniteElement<dim> &fe = dof_handler.get_fe();
2926 block_list.reinit(1, dof_handler.n_dofs(level), dof_handler.n_dofs(level));
2927
2928 std::vector<types::global_dof_index> indices;
2929 std::vector<bool> exclude;
2930
2931 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
2932 {
2933 indices.resize(cell->get_fe().n_dofs_per_cell());
2934 cell->get_mg_dof_indices(indices);
2935
2936 if (interior_only)
2937 {
2938 // Exclude degrees of freedom on faces opposite to the vertex
2939 exclude.resize(fe.n_dofs_per_cell());
2940 std::fill(exclude.begin(), exclude.end(), false);
2941
2942 for (const unsigned int face : cell->face_indices())
2943 if (cell->at_boundary(face) ||
2944 cell->neighbor(face)->level() != cell->level())
2945 for (unsigned int i = 0; i < fe.n_dofs_per_face(face); ++i)
2946 exclude[fe.face_to_cell_index(i, face)] = true;
2947 for (types::global_dof_index j = 0; j < indices.size(); ++j)
2948 if (!exclude[j])
2949 block_list.add(0, indices[j]);
2950 }
2951 else
2952 {
2953 for (const auto index : indices)
2954 block_list.add(0, index);
2955 }
2956 }
2957 }
2958
2959
2960 template <int dim, int spacedim>
2961 void
2963 const DoFHandler<dim, spacedim> &dof_handler,
2964 const unsigned int level,
2965 const bool interior_dofs_only,
2966 const bool boundary_dofs)
2967 {
2968 Assert(level > 0 && level < dof_handler.get_triangulation().n_levels(),
2969 ExcIndexRange(level, 1, dof_handler.get_triangulation().n_levels()));
2970
2971 std::vector<types::global_dof_index> indices;
2972 std::vector<bool> exclude;
2973
2974 unsigned int block = 0;
2975 for (const auto &pcell : dof_handler.cell_iterators_on_level(level - 1))
2976 {
2977 if (pcell->is_active())
2978 continue;
2979
2980 for (unsigned int child = 0; child < pcell->n_children(); ++child)
2981 {
2982 const auto cell = pcell->child(child);
2983
2984 // For hp, only this line here would have to be replaced.
2985 const FiniteElement<dim> &fe = dof_handler.get_fe();
2986 const unsigned int n_dofs = fe.n_dofs_per_cell();
2987 indices.resize(n_dofs);
2988 exclude.resize(n_dofs);
2989 std::fill(exclude.begin(), exclude.end(), false);
2990 cell->get_mg_dof_indices(indices);
2991
2992 if (interior_dofs_only)
2993 {
2994 // Eliminate dofs on faces of the child which are on faces
2995 // of the parent
2996 for (unsigned int d = 0; d < dim; ++d)
2997 {
2998 const unsigned int face =
3000 for (unsigned int i = 0; i < fe.n_dofs_per_face(face); ++i)
3001 exclude[fe.face_to_cell_index(i, face)] = true;
3002 }
3003
3004 // Now remove all degrees of freedom on the domain boundary
3005 // from the exclusion list
3006 if (boundary_dofs)
3007 for (const unsigned int face :
3009 if (cell->at_boundary(face))
3010 for (unsigned int i = 0; i < fe.n_dofs_per_face(face);
3011 ++i)
3012 exclude[fe.face_to_cell_index(i, face)] = false;
3013 }
3014
3015 for (unsigned int i = 0; i < n_dofs; ++i)
3016 if (!exclude[i])
3017 block_list.add(block, indices[i]);
3018 }
3019 ++block;
3020 }
3021 }
3022
3023 template <int dim, int spacedim>
3024 std::vector<unsigned int>
3026 const DoFHandler<dim, spacedim> &dof_handler,
3027 const unsigned int level,
3028 const bool interior_only,
3029 const bool boundary_patches,
3030 const bool level_boundary_patches,
3031 const bool single_cell_patches,
3032 const bool invert_vertex_mapping)
3033 {
3034 const unsigned int n_blocks = dof_handler.get_fe().n_blocks();
3035 BlockMask exclude_boundary_dofs = BlockMask(n_blocks, interior_only);
3036 return make_vertex_patches(block_list,
3037 dof_handler,
3038 level,
3039 exclude_boundary_dofs,
3040 boundary_patches,
3041 level_boundary_patches,
3042 single_cell_patches,
3043 invert_vertex_mapping);
3044 }
3045
3046 template <int dim, int spacedim>
3047 std::vector<unsigned int>
3049 const DoFHandler<dim, spacedim> &dof_handler,
3050 const unsigned int level,
3051 const BlockMask &exclude_boundary_dofs,
3052 const bool boundary_patches,
3053 const bool level_boundary_patches,
3054 const bool single_cell_patches,
3055 const bool invert_vertex_mapping)
3056 {
3057 // Vector mapping from vertex index in the triangulation to consecutive
3058 // block indices on this level The number of cells at a vertex
3059 std::vector<unsigned int> vertex_cell_count(
3060 dof_handler.get_triangulation().n_vertices(), 0);
3061
3062 // Is a vertex at the boundary?
3063 std::vector<bool> vertex_boundary(
3064 dof_handler.get_triangulation().n_vertices(), false);
3065
3066 std::vector<unsigned int> vertex_mapping(
3067 dof_handler.get_triangulation().n_vertices(),
3069
3070 // Estimate for the number of dofs at this point
3071 std::vector<unsigned int> vertex_dof_count(
3072 dof_handler.get_triangulation().n_vertices(), 0);
3073
3074 // Identify all vertices active on this level and remember some data
3075 // about them
3076 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
3077 for (const unsigned int v : cell->vertex_indices())
3078 {
3079 const unsigned int vg = cell->vertex_index(v);
3080 vertex_dof_count[vg] += cell->get_fe().n_dofs_per_cell();
3081 ++vertex_cell_count[vg];
3082 for (unsigned int d = 0; d < dim; ++d)
3083 {
3084 const unsigned int face = GeometryInfo<dim>::vertex_to_face[v][d];
3085 if (cell->at_boundary(face))
3086 vertex_boundary[vg] = true;
3087 else if ((!level_boundary_patches) &&
3088 (cell->neighbor(face)->level() !=
3089 static_cast<int>(level)))
3090 vertex_boundary[vg] = true;
3091 }
3092 }
3093 // From now on, only vertices with positive dof count are "in".
3094
3095 // Remove vertices at boundaries or in corners
3096 for (unsigned int vg = 0; vg < vertex_dof_count.size(); ++vg)
3097 if ((!single_cell_patches && vertex_cell_count[vg] < 2) ||
3098 (!boundary_patches && vertex_boundary[vg]))
3099 vertex_dof_count[vg] = 0;
3100
3101 // Create a mapping from all vertices to the ones used here
3102 unsigned int n_vertex_count = 0;
3103 for (unsigned int vg = 0; vg < vertex_mapping.size(); ++vg)
3104 if (vertex_dof_count[vg] != 0)
3105 vertex_mapping[vg] = n_vertex_count++;
3106
3107 // Compactify dof count
3108 for (unsigned int vg = 0; vg < vertex_mapping.size(); ++vg)
3109 if (vertex_dof_count[vg] != 0)
3110 vertex_dof_count[vertex_mapping[vg]] = vertex_dof_count[vg];
3111
3112 // Now that we have all the data, we reduce it to the part we actually
3113 // want
3114 vertex_dof_count.resize(n_vertex_count);
3115
3116 // At this point, the list of patches is ready. Now we enter the dofs
3117 // into the sparsity pattern.
3118 block_list.reinit(vertex_dof_count.size(),
3119 dof_handler.n_dofs(level),
3120 vertex_dof_count);
3121
3122 std::vector<types::global_dof_index> indices;
3123 std::vector<bool> exclude;
3124
3125 for (const auto &cell : dof_handler.cell_iterators_on_level(level))
3126 {
3127 const FiniteElement<dim> &fe = cell->get_fe();
3128 indices.resize(fe.n_dofs_per_cell());
3129 cell->get_mg_dof_indices(indices);
3130
3131 for (const unsigned int v : cell->vertex_indices())
3132 {
3133 const unsigned int vg = cell->vertex_index(v);
3134 const unsigned int block = vertex_mapping[vg];
3135 if (block == numbers::invalid_unsigned_int)
3136 continue;
3137
3138 // Collect excluded dofs for some block(s) if boundary dofs
3139 // for a block are decided to be excluded
3140 if (exclude_boundary_dofs.size() == 0 ||
3141 exclude_boundary_dofs.n_selected_blocks() != 0)
3142 {
3143 // Exclude degrees of freedom on faces opposite to the
3144 // vertex
3145 exclude.resize(fe.n_dofs_per_cell());
3146 std::fill(exclude.begin(), exclude.end(), false);
3147
3148 for (unsigned int d = 0; d < dim; ++d)
3149 {
3150 const unsigned int a_face =
3152 const unsigned int face =
3154 for (unsigned int i = 0; i < fe.n_dofs_per_face(face); ++i)
3155 {
3156 // For each dof, get the block it is in and decide to
3157 // exclude it or not
3158 if (exclude_boundary_dofs[fe.system_to_block_index(
3160 i, face))
3161 .first] == true)
3162 exclude[fe.face_to_cell_index(i, face)] = true;
3163 }
3164 }
3165 for (unsigned int j = 0; j < indices.size(); ++j)
3166 if (!exclude[j])
3167 block_list.add(block, indices[j]);
3168 }
3169 else
3170 {
3171 for (const auto index : indices)
3172 block_list.add(block, index);
3173 }
3174 }
3175 }
3176
3177 if (invert_vertex_mapping)
3178 {
3179 // Compress vertex mapping
3180 unsigned int n_vertex_count = 0;
3181 for (unsigned int vg = 0; vg < vertex_mapping.size(); ++vg)
3182 if (vertex_mapping[vg] != numbers::invalid_unsigned_int)
3183 vertex_mapping[n_vertex_count++] = vg;
3184
3185 // Now we reduce it to the part we actually want
3186 vertex_mapping.resize(n_vertex_count);
3187 }
3188
3189 return vertex_mapping;
3190 }
3191
3192
3193 template <int dim, int spacedim>
3194 unsigned int
3196 const std::vector<typename DoFHandler<dim, spacedim>::active_cell_iterator>
3197 &patch)
3198 {
3199 std::set<types::global_dof_index> dofs_on_patch;
3200 std::vector<types::global_dof_index> local_dof_indices;
3201
3202 // loop over the cells in the patch and get the DoFs on each.
3203 // add all of them to a std::set which automatically makes sure
3204 // all duplicates are ignored
3205 for (unsigned int i = 0; i < patch.size(); ++i)
3206 {
3208 patch[i];
3209 Assert(cell->is_artificial() == false,
3210 ExcMessage("This function can not be called with cells that are "
3211 "not either locally owned or ghost cells."));
3212 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
3213 cell->get_dof_indices(local_dof_indices);
3214 dofs_on_patch.insert(local_dof_indices.begin(),
3215 local_dof_indices.end());
3216 }
3217
3218 // now return the number of DoFs (duplicates were ignored)
3219 return dofs_on_patch.size();
3220 }
3221
3222
3223
3224 template <int dim, int spacedim>
3225 std::vector<types::global_dof_index>
3227 const std::vector<typename DoFHandler<dim, spacedim>::active_cell_iterator>
3228 &patch)
3229 {
3230 std::set<types::global_dof_index> dofs_on_patch;
3231 std::vector<types::global_dof_index> local_dof_indices;
3232
3233 // loop over the cells in the patch and get the DoFs on each.
3234 // add all of them to a std::set which automatically makes sure
3235 // all duplicates are ignored
3236 for (unsigned int i = 0; i < patch.size(); ++i)
3237 {
3239 patch[i];
3240 Assert(cell->is_artificial() == false,
3241 ExcMessage("This function can not be called with cells that are "
3242 "not either locally owned or ghost cells."));
3243 local_dof_indices.resize(cell->get_fe().n_dofs_per_cell());
3244 cell->get_dof_indices(local_dof_indices);
3245 dofs_on_patch.insert(local_dof_indices.begin(),
3246 local_dof_indices.end());
3247 }
3248
3249 Assert((dofs_on_patch.size() == count_dofs_on_patch<dim, spacedim>(patch)),
3251
3252 // return a vector with the content of the set above. copying
3253 // also ensures that we retain sortedness as promised in the
3254 // documentation and as necessary to retain the block structure
3255 // also on the local system
3256 return std::vector<types::global_dof_index>(dofs_on_patch.begin(),
3257 dofs_on_patch.end());
3258 }
3259
3260
3261} // end of namespace DoFTools
3262
3263
3264
3265// explicit instantiations
3266
3267#include "dofs/dof_tools.inst"
3268
3269
3270
*  iterator end()
*  *  for(const auto &cell :triangulation.active_cell_iterators())
*  *  iterator begin()
*  *  const_iterator()=default
const IndexSet & get_local_lines() const
const std::vector< std::pair< size_type, number > > * get_constraint_entries(const size_type line_n) const
size_type n_constraints() const
unsigned int size() const
unsigned int n_selected_blocks(const unsigned int overall_number_of_blocks=numbers::invalid_unsigned_int) const
bool represents_n_components(const unsigned int n) const
bool represents_the_all_selected_mask() const
unsigned int size() const
unsigned int n_selected_components(const unsigned int overall_number_of_components=numbers::invalid_unsigned_int) const
unsigned int first_selected_component(const unsigned int overall_number_of_components=numbers::invalid_unsigned_int) const
const hp::FECollection< dim, spacedim > & get_fe_collection() const
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
const IndexSet & locally_owned_mg_dofs(const unsigned int level) const
types::global_dof_index n_boundary_dofs() const
const Triangulation< dim, spacedim > & get_triangulation() const
const IndexSet & locally_owned_dofs() const
active_cell_iterator begin_active(const unsigned int level=0) const
bool has_hp_capabilities() const
types::global_dof_index n_dofs() const
MPI_Comm get_mpi_communicator() const
types::global_dof_index n_locally_owned_dofs() const
virtual double value(const Point< dim > &p, const unsigned int component) const override
RigidBodyMotion(const unsigned int type)
static constexpr unsigned int n_modes
const std::vector< Point< spacedim > > & get_quadrature_points() const
const FEValues< dim, spacedim > & get_present_fe_values() const
unsigned int n_dofs_per_vertex() const
unsigned int n_dofs_per_cell() const
unsigned int n_dofs_per_line() const
unsigned int n_dofs_per_face(unsigned int face_no=0, unsigned int child=0) const
unsigned int n_blocks() const
unsigned int n_components() const
std::pair< unsigned int, types::global_dof_index > system_to_block_index(const unsigned int component) const
const ComponentMask & get_nonzero_components(const unsigned int i) const
virtual const FiniteElement< dim, spacedim > & base_element(const unsigned int index) const
ComponentMask component_mask(const FEValuesExtractors::Scalar &scalar) const
bool is_primitive() const
virtual bool has_support_on_face(const unsigned int shape_index, const unsigned int face_index) const
unsigned int component_to_block_index(const unsigned int component) const
std::pair< unsigned int, unsigned int > system_to_component_index(const unsigned int index) const
unsigned int element_multiplicity(const unsigned int index) const
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
unsigned int n_base_elements() const
std::pair< unsigned int, unsigned int > face_system_to_component_index(const unsigned int index, const unsigned int face_no=0) const
const unsigned int n_components
Definition function.h:162
size_type index_within_set(const size_type global_index) const
Definition index_set.h:1977
size_type n_elements() const
Definition index_set.h:1917
bool is_element(const size_type index) const
Definition index_set.h:1877
void add_index(const size_type index)
Definition index_set.h:1778
void fill_binary_vector(VectorType &vector) const
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
size_type nth_index_in_set(const size_type local_index) const
Definition index_set.h:1958
void compress() const
Definition index_set.h:1767
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition index_set.h:1814
Abstract base class for mapping classes.
Definition mapping.h:318
Definition point.h:111
void reinit(const size_type m, const size_type n, const ArrayView< const unsigned int > &row_lengths)
void add(const size_type i, const size_type j)
virtual types::subdomain_id locally_owned_subdomain() const
unsigned int n_active_cells() const
unsigned int n_levels() const
unsigned int n_vertices() const
virtual size_type size() const override
unsigned int size() const
Definition collection.h:314
unsigned int max_dofs_per_face() const
ComponentMask component_mask(const FEValuesExtractors::Scalar &scalar) const
unsigned int n_components() const
unsigned int max_dofs_per_cell() const
void push_back(const Quadrature< dim_in > &new_quadrature)
virtual MPI_Comm get_mpi_communicator() const override
Definition tria_base.cc:158
#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
unsigned int level
Definition grid_out.cc:4642
unsigned int cell_index
IteratorRange< active_cell_iterator > active_cell_iterators() const
IteratorRange< FilteredIterator< BaseIterator > > filter_iterators(IteratorRange< BaseIterator > i, const Predicate &p)
IteratorRange< cell_iterator > cell_iterators_on_level(const unsigned int level) const
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcInvalidBoundaryIndicator()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcIndexRange(std::size_t arg1, std::size_t arg2, std::size_t arg3)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
typename ActiveSelector::line_iterator line_iterator
typename ActiveSelector::face_iterator face_iterator
typename ActiveSelector::active_cell_iterator active_cell_iterator
typename ActiveSelector::CellAccessor cell_accessor
@ update_quadrature_points
Transformed quadrature points.
std::vector< index_type > data
Definition mpi.cc:734
void get_block_association(const DoFHandler< dim, spacedim > &dof, std::vector< unsigned char > &dofs_by_block)
Definition dof_tools.cc:280
Tensor< 1, 2 > cross_product(const Tensor< 1, 2 > &tensor1, const Tensor< 1, 1 > &tensor2)
std::vector< std::vector< double > > extract_rigid_body_modes(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask, const unsigned int mg_level)
std::vector< unsigned char > get_local_component_association(const FiniteElement< dim, spacedim > &fe, const ComponentMask &component_mask)
Definition dof_tools.cc:127
void get_component_association(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask, std::vector< unsigned char > &dofs_by_component, const unsigned int mg_level=numbers::invalid_unsigned_int)
Definition dof_tools.cc:198
void resolve_components(const FiniteElement< dim, spacedim > &fe, const std::vector< unsigned char > &dofs_by_component, const std::vector< unsigned int > &target_component, const bool only_once, std::vector< types::global_dof_index > &dofs_per_component, unsigned int &component)
std::vector< std::vector< bool > > extract_constant_modes(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask, const unsigned int mg_level)
void get_subdomain_association(const DoFHandler< dim, spacedim > &dof_handler, std::vector< types::subdomain_id > &subdomain)
IndexSet dof_indices_with_subdomain_association(const DoFHandler< dim, spacedim > &dof_handler, const types::subdomain_id subdomain)
IndexSet extract_dofs_with_support_contained_within(const DoFHandler< dim, spacedim > &dof_handler, const std::function< bool(const typename DoFHandler< dim, spacedim >::active_cell_iterator &)> &predicate, const AffineConstraints< number > &constraints={})
Definition dof_tools.cc:829
std::vector< IndexSet > locally_owned_dofs_per_subdomain(const DoFHandler< dim, spacedim > &dof_handler)
IndexSet extract_boundary_dofs(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask={}, const std::set< types::boundary_id > &boundary_ids={})
Definition dof_tools.cc:619
std::vector< std::vector< bool > > extract_level_constant_modes(const unsigned int level, const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask={})
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
std::vector< std::vector< bool > > extract_constant_modes(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask={})
std::map< typename DoFHandler< dim - 1, spacedim >::active_cell_iterator, std::pair< typename DoFHandler< dim, spacedim >::active_cell_iterator, unsigned int > > map_boundary_to_bulk_dof_iterators(const std::map< typename Triangulation< dim - 1, spacedim >::cell_iterator, typename Triangulation< dim, spacedim >::face_iterator > &c1_to_c0, const DoFHandler< dim, spacedim > &c0_dh, const DoFHandler< dim - 1, spacedim > &c1_dh)
void make_cell_patches(SparsityPattern &block_list, const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level, const std::vector< bool > &selected_dofs={}, const types::global_dof_index offset=0)
IndexSet extract_dofs(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask)
Definition dof_tools.cc:419
IndexSet extract_locally_active_dofs(const DoFHandler< dim, spacedim > &dof_handler)
IndexSet extract_locally_relevant_level_dofs(const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level)
std::vector< std::vector< double > > extract_rigid_body_modes(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask={})
void write_gnuplot_dof_support_point_info(std::ostream &out, const std::map< types::global_dof_index, Point< spacedim > > &support_points)
void extract_subdomain_dofs(const DoFHandler< dim, spacedim > &dof_handler, const types::subdomain_id subdomain_id, std::vector< bool > &selected_dofs)
IndexSet extract_locally_active_level_dofs(const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level)
std::vector< unsigned int > make_vertex_patches(SparsityPattern &block_list, const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level, const bool interior_dofs_only, const bool boundary_patches=false, const bool level_boundary_patches=false, const bool single_cell_patches=false, const bool invert_vertex_mapping=false)
std::vector< types::global_dof_index > count_dofs_per_fe_block(const DoFHandler< dim, spacedim > &dof, const std::vector< unsigned int > &target_block=std::vector< unsigned int >())
void extract_level_dofs(const unsigned int level, const DoFHandler< dim, spacedim > &dof, const ComponentMask &component_mask, std::vector< bool > &selected_dofs)
Definition dof_tools.cc:506
void extract_dofs_with_support_on_boundary(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask, std::vector< bool > &selected_dofs, const std::set< types::boundary_id > &boundary_ids=std::set< types::boundary_id >())
Definition dof_tools.cc:747
void distribute_cell_to_dof_vector(const DoFHandler< dim, spacedim > &dof_handler, const Vector< Number > &cell_data, Vector< double > &dof_data, const unsigned int component=0)
Definition dof_tools.cc:335
std::vector< types::global_dof_index > count_dofs_per_fe_component(const DoFHandler< dim, spacedim > &dof_handler, const bool vector_valued_once=false, const std::vector< unsigned int > &target_component={})
void make_child_patches(SparsityPattern &block_list, const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level, const bool interior_dofs_only, const bool boundary_dofs=false)
void map_dof_to_boundary_indices(const DoFHandler< dim, spacedim > &dof_handler, std::vector< types::global_dof_index > &mapping)
std::vector< IndexSet > locally_relevant_dofs_per_subdomain(const DoFHandler< dim, spacedim > &dof_handler)
void make_single_patch(SparsityPattern &block_list, const DoFHandler< dim, spacedim > &dof_handler, const unsigned int level, const bool interior_dofs_only=false)
std::vector< types::global_dof_index > get_dofs_on_patch(const std::vector< typename DoFHandler< dim, spacedim >::active_cell_iterator > &patch)
std::vector< IndexSet > locally_owned_dofs_per_component(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &components={})
Definition dof_tools.cc:472
unsigned int count_dofs_with_subdomain_association(const DoFHandler< dim, spacedim > &dof_handler, const types::subdomain_id subdomain)
void map_dofs_to_support_points(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, std::vector< Point< spacedim > > &support_points, const ComponentMask &mask={}, const bool map_locally_relevant_dofs=true)
unsigned int count_dofs_on_patch(const std::vector< typename DoFHandler< dim, spacedim >::active_cell_iterator > &patch)
void convert_couplings_to_blocks(const DoFHandler< dim, spacedim > &dof_handler, const Table< 2, Coupling > &table_by_component, std::vector< Table< 2, Coupling > > &tables_by_block)
IndexSet extract_hanging_node_dofs(const DoFHandler< dim, spacedim > &dof_handler)
std::vector< std::vector< double > > extract_level_rigid_body_modes(const unsigned int level, const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask={})
std::vector< typename MeshType::active_cell_iterator > compute_active_cell_halo_layer(const MeshType &mesh, const std::function< bool(const typename MeshType::active_cell_iterator &)> &predicate)
*  *  if(update_pressure &update_flags) *  compute_pressure(constitutive_request
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
void interpolate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Function< spacedim, typename VectorType::value_type > &function, VectorType &vec, const ComponentMask &component_mask={}, const unsigned int level=numbers::invalid_unsigned_int)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
constexpr types::boundary_id internal_face_boundary_id
Definition types.h:319
constexpr types::subdomain_id artificial_subdomain_id
Definition types.h:406
constexpr types::subdomain_id invalid_subdomain_id
Definition types.h:385
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
unsigned short int fe_index
Definition types.h:70
bool operator()(const Point< dim, Number > &lhs, const Point< dim, Number > &rhs) const
Definition dof_tools.cc:85
static std_cxx20::ranges::iota_view< unsigned int, unsigned int > face_indices()