deal.II version GIT relicensing-6834-g5b78e6bcdf 2026-10-01 11:20:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
dof_info.cc
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2020 - 2025 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13
17
19
22
23#include <deal.II/matrix_free/dof_info.templates.h>
25
26#include <iostream>
27
29
30namespace internal
31{
32 namespace MatrixFreeFunctions
33 {
34 // ensure that the type defined in both dof_info.h and
35 // hanging_nodes_internal.h is consistent
36 static_assert(std::is_same_v<compressed_constraint_kind, std::uint8_t>,
37 "Unexpected type for compressed hanging node indicators!");
38
39
40
42 {
43 clear();
44 }
45
46
47
48 void
50 {
51 row_starts.clear();
52 dof_indices.clear();
54 vector_partitioner.reset();
55 ghost_dofs.clear();
56 dofs_per_cell.clear();
57 dofs_per_face.clear();
61 n_components.clear();
62 start_components.clear();
64 plain_dof_indices.clear();
66 for (unsigned int i = 0; i < 3; ++i)
67 {
68 index_storage_variants[i].clear();
69 dof_indices_contiguous[i].clear();
72 }
73 store_plain_indices = false;
75 max_fe_index = 0;
76 fe_index_conversion.clear();
77 }
78
79
80
81 void
82 DoFInfo::get_dof_indices_on_cell_batch(std::vector<unsigned int> &my_rows,
83 const unsigned int cell,
84 const bool apply_constraints) const
85 {
86 const unsigned int n_fe_components = start_components.back();
87 const unsigned int fe_index =
88 dofs_per_cell.size() == 1 ? 0 : cell_active_fe_index[cell];
89 const unsigned int dofs_this_cell = dofs_per_cell[fe_index];
90
91 const unsigned int n_vectorization = vectorization_length;
92 constexpr auto dof_access_index = dof_access_cell;
94 n_vectorization_lanes_filled[dof_access_index].size());
95 const unsigned int n_vectorization_actual =
96 n_vectorization_lanes_filled[dof_access_index][cell];
97
98 // we might have constraints, so the final number
99 // of indices is not known a priori.
100 // conservatively reserve the maximum without constraints
101 my_rows.reserve(n_vectorization * dofs_this_cell);
102 my_rows.resize(0);
103 unsigned int total_size = 0;
104 for (unsigned int v = 0; v < n_vectorization_actual; ++v)
105 {
106 const unsigned int ib =
107 (cell * n_vectorization + v) * n_fe_components;
108 const unsigned int ie =
109 (cell * n_vectorization + v + 1) * n_fe_components;
110
111 auto do_copy = [&](const unsigned int *begin,
112 const unsigned int *end) {
113 const unsigned int shift = total_size;
114 total_size += (end - begin);
115 my_rows.resize(total_size);
116 std::copy(begin, end, my_rows.begin() + shift);
117 };
118
119 // figure out whether the plain indices should be read by checking
120 // the respective entry in the row_starts_plain_indices
121 if (apply_constraints ||
122 row_starts_plain_indices[cell * n_vectorization + v] ==
124 {
125 const unsigned int *begin =
126 dof_indices.data() + row_starts[ib].first;
127 const unsigned int *end =
128 dof_indices.data() + row_starts[ie].first;
129 do_copy(begin, end);
130 }
131 else
132 {
133 const unsigned int *begin =
134 plain_dof_indices.data() +
135 row_starts_plain_indices[cell * n_vectorization + v];
136 const unsigned int *end = begin + dofs_this_cell;
137 do_copy(begin, end);
138 }
139 }
140 }
141
142
143
144 void
145 DoFInfo::assign_ghosts(const std::vector<unsigned int> &boundary_cells,
146 const MPI_Comm communicator_sm,
147 const bool use_vector_data_exchanger_full)
148 {
149 Assert(boundary_cells.size() < row_starts.size(), ExcInternalError());
150
151 // sort ghost dofs and compress out duplicates
152 const unsigned int n_owned = (vector_partitioner->local_range().second -
153 vector_partitioner->local_range().first);
154 const std::size_t n_ghosts = ghost_dofs.size();
155 if constexpr (running_in_debug_mode())
156 {
157 for (const auto dof_index : dof_indices)
158 if (dof_index != numbers::invalid_unsigned_int)
159 AssertIndexRange(dof_index, n_owned + n_ghosts);
160 }
161
162 const unsigned int n_components = start_components.back();
163 std::vector<unsigned int> ghost_numbering(n_ghosts);
164 IndexSet ghost_indices(vector_partitioner->size());
165 if (n_ghosts > 0)
166 {
167 unsigned int n_unique_ghosts = 0;
168 // since we need to go back to the local_to_global indices and
169 // replace the temporary numbering of ghosts by the real number in
170 // the index set, we need to store these values
171 std::vector<std::pair<types::global_dof_index, unsigned int>>
172 ghost_origin(n_ghosts);
173 for (std::size_t i = 0; i < n_ghosts; ++i)
174 {
175 ghost_origin[i].first = ghost_dofs[i];
176 ghost_origin[i].second = i;
177 }
178 std::sort(ghost_origin.begin(), ghost_origin.end());
179
180 types::global_dof_index last_contiguous_start = ghost_origin[0].first;
181 ghost_numbering[ghost_origin[0].second] = 0;
182 for (std::size_t i = 1; i < n_ghosts; ++i)
183 {
184 if (ghost_origin[i].first > ghost_origin[i - 1].first + 1)
185 {
186 ghost_indices.add_range(last_contiguous_start,
187 ghost_origin[i - 1].first + 1);
188 last_contiguous_start = ghost_origin[i].first;
189 }
190 if (ghost_origin[i].first > ghost_origin[i - 1].first)
191 ++n_unique_ghosts;
192 ghost_numbering[ghost_origin[i].second] = n_unique_ghosts;
193 }
194 ++n_unique_ghosts;
195 ghost_indices.add_range(last_contiguous_start,
196 ghost_origin.back().first + 1);
197 ghost_indices.compress();
198
199 // make sure that we got the correct local numbering of the ghost
200 // dofs. the ghost index set should store the same number
201 {
202 AssertDimension(n_unique_ghosts, ghost_indices.n_elements());
203 for (std::size_t i = 0; i < n_ghosts; ++i)
204 Assert(ghost_numbering[i] ==
205 ghost_indices.index_within_set(ghost_dofs[i]),
207 }
208
209 // apply correct numbering for ghost indices: We previously just
210 // enumerated them according to their appearance in the
211 // local_to_global structure. Above, we derived a relation between
212 // this enumeration and the actual number
213 const unsigned int n_boundary_cells = boundary_cells.size();
214 for (unsigned int i = 0; i < n_boundary_cells; ++i)
215 {
216 unsigned int *data_ptr =
217 dof_indices.data() +
218 row_starts[boundary_cells[i] * n_components].first;
219 const unsigned int *row_end =
220 dof_indices.data() +
221 row_starts[(boundary_cells[i] + 1) * n_components].first;
222 for (; data_ptr != row_end; ++data_ptr)
223 *data_ptr = ((*data_ptr < n_owned ||
224 *data_ptr == numbers::invalid_unsigned_int) ?
225 *data_ptr :
226 n_owned + ghost_numbering[*data_ptr - n_owned]);
227
228 // now the same procedure for plain indices
229 if (store_plain_indices == true &&
230 row_starts_plain_indices[boundary_cells[i]] !=
232 {
233 const unsigned int fe_index =
234 (cell_active_fe_index.empty() ||
235 dofs_per_cell.size() == 1) ?
236 0 :
237 cell_active_fe_index[boundary_cells[i]];
238 AssertIndexRange(fe_index, dofs_per_cell.size());
239
240 unsigned int *data_ptr =
241 plain_dof_indices.data() +
242 row_starts_plain_indices[boundary_cells[i]];
243 const unsigned int *row_end =
244 data_ptr + dofs_per_cell[fe_index];
245 for (; data_ptr != row_end; ++data_ptr)
246 *data_ptr =
247 ((*data_ptr < n_owned) ?
248 *data_ptr :
249 n_owned + ghost_numbering[*data_ptr - n_owned]);
250 }
251 }
252 }
253
254 std::vector<types::global_dof_index> empty;
255 ghost_dofs.swap(empty);
256
257 // set the ghost indices now. need to cast away constness here, but that
258 // is uncritical since we reset the Partitioner in the same initialize
259 // call as this call here.
262 vec_part->set_ghost_indices(ghost_indices);
263
264 if (use_vector_data_exchanger_full == false)
265 vector_exchanger = std::make_shared<
268 else
270 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
271 vector_partitioner, communicator_sm);
272 }
273
274
275
276 void
278 const TaskInfo &task_info,
279 const std::vector<unsigned int> &renumbering,
280 const std::vector<unsigned int> &constraint_pool_row_index,
281 const std::vector<unsigned char> &irregular_cells)
282 {
283 // first reorder the active FE index.
284 const bool have_hp = dofs_per_cell.size() > 1;
285 if (cell_active_fe_index.size() > 0)
286 {
287 std::vector<unsigned int> new_active_fe_index;
288 new_active_fe_index.reserve(task_info.cell_partition_data.back());
289 unsigned int position_cell = 0;
290 for (unsigned int cell = 0;
291 cell < task_info.cell_partition_data.back();
292 ++cell)
293 {
294 const unsigned int n_comp =
295 (irregular_cells[cell] > 0 ? irregular_cells[cell] :
297
298 // take maximum FE index among the ones present (we might have
299 // lumped some lower indices into higher ones)
300 unsigned int fe_index =
301 cell_active_fe_index[renumbering[position_cell]];
302 for (unsigned int j = 1; j < n_comp; ++j)
303 fe_index = std::max(
304 fe_index,
305 cell_active_fe_index[renumbering[position_cell + j]]);
306
307 new_active_fe_index.push_back(fe_index);
308 position_cell += n_comp;
309 }
310 std::swap(new_active_fe_index, cell_active_fe_index);
311 }
312 if (have_hp)
314 task_info.cell_partition_data.back());
315
316 const unsigned int n_components = start_components.back();
317
318 std::vector<std::pair<unsigned int, unsigned int>> new_row_starts(
320 task_info.cell_partition_data.back() +
321 1);
322 std::vector<unsigned int> new_dof_indices;
323 std::vector<std::pair<unsigned short, unsigned short>>
324 new_constraint_indicator;
325 std::vector<unsigned int> new_plain_indices, new_rowstart_plain;
326 unsigned int position_cell = 0;
327 new_dof_indices.reserve(dof_indices.size());
328 new_constraint_indicator.reserve(constraint_indicator.size());
329
330 std::vector<compressed_constraint_kind> new_hanging_node_constraint_masks;
331 new_hanging_node_constraint_masks.reserve(
333
335 {
336 new_rowstart_plain.resize(vectorization_length *
337 task_info.cell_partition_data.back(),
339 new_plain_indices.reserve(plain_dof_indices.size());
340 }
341
342 // copy the indices and the constraint indicators to the new data field,
343 // where we will go through the cells in the renumbered way. in case the
344 // vectorization length does not exactly match up, we fill invalid
345 // numbers to the rowstart data. for contiguous cell indices, we skip
346 // the rowstarts field completely and directly go into the
347 // new_dof_indices field (this layout is used in FEEvaluation).
348 for (unsigned int i = 0; i < task_info.cell_partition_data.back(); ++i)
349 {
350 const unsigned int n_lanes_filled =
351 (irregular_cells[i] > 0 ? irregular_cells[i] :
353 const unsigned int dofs_per_cell =
354 have_hp ? this->dofs_per_cell[cell_active_fe_index[i]] :
355 this->dofs_per_cell[0];
356
357 for (unsigned int j = 0; j < n_lanes_filled; ++j)
358 {
359 const unsigned int cell_no = renumbering[position_cell + j];
360
361 if (!hanging_node_constraint_masks.empty() &&
363 new_hanging_node_constraint_masks.push_back(
365
366 for (unsigned int comp = 0; comp < n_components; ++comp)
367 {
368 new_row_starts[(i * vectorization_length + j) * n_components +
369 comp]
370 .first = new_dof_indices.size();
371 new_row_starts[(i * vectorization_length + j) * n_components +
372 comp]
373 .second = new_constraint_indicator.size();
374
375 const unsigned int idx = cell_no * n_components + comp;
376 new_dof_indices.insert(new_dof_indices.end(),
377 dof_indices.data() +
378 row_starts[idx].first,
379 dof_indices.data() +
380 row_starts[idx + 1].first);
381 for (unsigned int index = row_starts[idx].second;
382 index != row_starts[idx + 1].second;
383 ++index)
384 new_constraint_indicator.push_back(
386 }
387
390 {
391 new_rowstart_plain[i * vectorization_length + j] =
392 new_plain_indices.size();
393 new_plain_indices.insert(new_plain_indices.end(),
394 plain_dof_indices.data() +
396 plain_dof_indices.data() +
397 row_starts_plain_indices[cell_no] +
399 }
400 }
401 for (unsigned int j = n_lanes_filled; j < vectorization_length; ++j)
402 for (unsigned int comp = 0; comp < n_components; ++comp)
403 {
404 new_row_starts[(i * vectorization_length + j) * n_components +
405 comp]
406 .first = new_dof_indices.size();
407 new_row_starts[(i * vectorization_length + j) * n_components +
408 comp]
409 .second = new_constraint_indicator.size();
410 }
411
412 for (unsigned int j = n_lanes_filled; j < vectorization_length; ++j)
413 if (hanging_node_constraint_masks.size() > 0)
414 new_hanging_node_constraint_masks.push_back(
416
417 position_cell += n_lanes_filled;
418 }
419 AssertDimension(position_cell * n_components + 1, row_starts.size());
420
421 AssertDimension(dof_indices.size(), new_dof_indices.size());
422 new_row_starts[task_info.cell_partition_data.back() *
424 .first = new_dof_indices.size();
425 new_row_starts[task_info.cell_partition_data.back() *
427 .second = new_constraint_indicator.size();
428
430 new_constraint_indicator.size());
431
432 new_row_starts.swap(row_starts);
433 new_dof_indices.swap(dof_indices);
434 new_constraint_indicator.swap(constraint_indicator);
435 new_plain_indices.swap(plain_dof_indices);
436 new_rowstart_plain.swap(row_starts_plain_indices);
437 new_hanging_node_constraint_masks.swap(hanging_node_constraint_masks);
438
439 if constexpr (running_in_debug_mode())
440 {
441 // sanity check 1: all indices should be smaller than the number of
442 // dofs locally owned plus the number of ghosts
443 const unsigned int index_range =
444 (vector_partitioner->local_range().second -
445 vector_partitioner->local_range().first) +
446 vector_partitioner->ghost_indices().n_elements();
447 for (const auto dof_index : dof_indices)
448 if (dof_index != numbers::invalid_unsigned_int)
449 AssertIndexRange(dof_index, index_range);
450
451 // sanity check 2: for the constraint indicators, the first index
452 // should be smaller than the number of indices in the row, and the
453 // second index should be smaller than the number of constraints in
454 // the constraint pool.
455 for (unsigned int row = 0; row < task_info.cell_partition_data.back();
456 ++row)
457 {
458 const unsigned int row_length_ind =
460 .first -
464 .second,
465 constraint_indicator.size() + 1);
466 const std::pair<unsigned short, unsigned short>
467 *con_it =
468 constraint_indicator.data() +
470 *end_con =
471 constraint_indicator.data() +
473 .second;
474 for (; con_it != end_con; ++con_it)
475 {
476 AssertIndexRange(con_it->first, row_length_ind + 1);
477 AssertIndexRange(con_it->second,
478 constraint_pool_row_index.size() - 1);
479 }
480 }
481
482 // sanity check 3: check the number of cells once again
483 unsigned int n_active_cells = 0;
484 for (unsigned int c = 0;
485 c < *(task_info.cell_partition_data.end() - 2);
486 ++c)
487 if (irregular_cells[c] > 0)
488 n_active_cells += irregular_cells[c];
489 else
490 n_active_cells += vectorization_length;
491 AssertDimension(n_active_cells, task_info.n_active_cells);
492 }
493
494 compute_cell_index_compression(irregular_cells);
495 }
496
497
498
499 void
501 const std::vector<unsigned char> &irregular_cells)
502 {
503 const bool have_hp = dofs_per_cell.size() > 1;
504 const unsigned int n_components = start_components.back();
505
507 row_starts.size() % vectorization_length == 1,
509 if (vectorization_length > 1)
511 irregular_cells.size());
513 irregular_cells.size(), IndexStorageVariants::full);
515 irregular_cells.size());
516 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
517 if (irregular_cells[i] > 0)
518 n_vectorization_lanes_filled[dof_access_cell][i] = irregular_cells[i];
519 else
522
524 irregular_cells.size() * vectorization_length,
529 irregular_cells.size() * vectorization_length,
531
532 std::vector<unsigned int> index_kinds(
533 static_cast<unsigned int>(
535 1);
536 std::vector<unsigned int> offsets(vectorization_length);
537 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
538 {
539 const unsigned int ndofs =
540 dofs_per_cell[have_hp ? cell_active_fe_index[i] : 0];
541 const unsigned int n_lanes_filled =
543
544 // check 1: Check if there are constraints -> no compression possible
545 bool has_constraints = false;
546 for (unsigned int j = 0; j < n_lanes_filled; ++j)
547 {
548 const unsigned int cell_no = i * vectorization_length + j;
549 if (row_starts[cell_no * n_components].second !=
550 row_starts[(cell_no + 1) * n_components].second)
551 {
552 has_constraints = true;
553 break;
554 }
555 }
556 if (has_constraints)
559 else
560 {
561 bool indices_are_contiguous = (ndofs > 0);
562 for (unsigned int j = 0; j < n_lanes_filled; ++j)
563 {
564 const unsigned int cell_no = i * vectorization_length + j;
565 const unsigned int *dof_indices =
566 this->dof_indices.data() +
567 row_starts[cell_no * n_components].first;
569 ndofs,
570 row_starts[(cell_no + 1) * n_components].first -
571 row_starts[cell_no * n_components].first);
572 if (ndofs == 0 ||
574 {
575 indices_are_contiguous = false;
576 break;
577 }
578 for (unsigned int i = 1; i < ndofs; ++i)
580 dof_indices[i] != dof_indices[0] + i)
581 {
582 indices_are_contiguous = false;
583 break;
584 }
585 }
586
587 bool indices_are_interleaved_and_contiguous =
588 (ndofs > 1 && n_lanes_filled == vectorization_length);
589
590 {
591 const unsigned int *dof_indices =
592 this->dof_indices.data() +
594 for (unsigned int k = 0;
595 k < ndofs && indices_are_interleaved_and_contiguous;
596 ++k)
597 for (unsigned int j = 0; j < n_lanes_filled; ++j)
598 if (dof_indices[j * ndofs + k] ==
600 dof_indices[j * ndofs + k] !=
601 dof_indices[0] + k * n_lanes_filled + j)
602 {
603 indices_are_interleaved_and_contiguous = false;
604 break;
605 }
606 }
607
608 if (indices_are_contiguous ||
609 indices_are_interleaved_and_contiguous)
610 {
611 for (unsigned int j = 0; j < n_lanes_filled; ++j)
612 {
613 const unsigned int start_index =
616 .first;
617 AssertIndexRange(start_index, dof_indices.size());
619 [i * vectorization_length + j] =
620 this->dof_indices.empty() ?
621 0 :
622 this->dof_indices[start_index];
623 }
624 }
625
626 if (indices_are_interleaved_and_contiguous)
627 {
628 Assert(n_lanes_filled == vectorization_length,
632 for (unsigned int j = 0; j < n_lanes_filled; ++j)
634 j] = n_lanes_filled;
635 }
636 else if (indices_are_contiguous)
637 {
640 for (unsigned int j = 0; j < n_lanes_filled; ++j)
642 j] = 1;
643 }
644 else if (ndofs > 0)
645 {
646 int indices_are_interleaved_and_mixed = 2;
647 const unsigned int *dof_indices =
648 &this->dof_indices[row_starts[i * vectorization_length *
650 .first];
651 for (unsigned int j = 0; j < n_lanes_filled; ++j)
652 offsets[j] =
653 dof_indices[j * ndofs + 1] - dof_indices[j * ndofs];
654 for (unsigned int k = 0;
655 k < ndofs && indices_are_interleaved_and_mixed != 0;
656 ++k)
657 for (unsigned int j = 0; j < n_lanes_filled; ++j)
658 // the first if case is to avoid negative offsets
659 // (invalid)
660 if (dof_indices[j * ndofs + k] ==
662 dof_indices[j * ndofs + 1] < dof_indices[j * ndofs] ||
663 dof_indices[j * ndofs + k] !=
664 dof_indices[j * ndofs] + k * offsets[j])
665 {
666 indices_are_interleaved_and_mixed = 0;
667 break;
668 }
669 if (indices_are_interleaved_and_mixed == 2)
670 {
671 for (unsigned int j = 0; j < n_lanes_filled; ++j)
674 offsets[j];
675 for (unsigned int j = 0; j < n_lanes_filled; ++j)
677 [i * vectorization_length + j] =
678 dof_indices[j * ndofs];
679 for (unsigned int j = 0; j < n_lanes_filled; ++j)
680 if (offsets[j] != vectorization_length)
681 {
682 indices_are_interleaved_and_mixed = 1;
683 break;
684 }
685 if (indices_are_interleaved_and_mixed == 1 ||
686 n_lanes_filled != vectorization_length)
690 else
693 }
694 else
695 {
696 if (n_lanes_filled == vectorization_length)
699 else
702 }
703 }
704 else // ndofs == 0
707 }
708 index_kinds[static_cast<unsigned int>(
710 }
711
712 // Cleanup phase: we want to avoid single cells with different properties
713 // than the bulk of the domain in order to avoid extra checks in the face
714 // identification.
715
716 // Step 1: check whether the interleaved indices were only assigned to
717 // the single cell within a vectorized array.
718 auto fix_single_interleaved_indices =
719 [&](const IndexStorageVariants variant) {
720 if (index_kinds[static_cast<unsigned int>(
722 0 &&
723 index_kinds[static_cast<unsigned int>(variant)] > 0)
724 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
725 {
732 [i * vectorization_length] ==
733 1))
734 {
736 index_kinds[static_cast<unsigned int>(
739 index_kinds[static_cast<unsigned int>(variant)]++;
740 }
741 }
742 };
743
744 fix_single_interleaved_indices(IndexStorageVariants::full);
745 fix_single_interleaved_indices(IndexStorageVariants::contiguous);
746 fix_single_interleaved_indices(IndexStorageVariants::interleaved);
747
748 unsigned int n_interleaved =
749 index_kinds[static_cast<unsigned int>(
751 index_kinds[static_cast<unsigned int>(
753 index_kinds[static_cast<unsigned int>(
755
756 // Step 2: fix single contiguous cell among others with interleaved
757 // storage
758 if (n_interleaved > 0 && index_kinds[static_cast<unsigned int>(
760 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
763 {
766 index_kinds[static_cast<unsigned int>(
768 index_kinds[static_cast<unsigned int>(
770 }
771
772 // Step 3: Interleaved cells are left but also some non-contiguous ones
773 // -> revert all to full storage
774 if (n_interleaved > 0 &&
775 index_kinds[static_cast<unsigned int>(IndexStorageVariants::full)] +
776 index_kinds[static_cast<unsigned int>(
778 0)
779 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
782 {
783 index_kinds[static_cast<unsigned int>(
784 index_storage_variants[2][i])]--;
789 else
792 index_kinds[static_cast<unsigned int>(
794 }
795
796 // Step 4: Copy the interleaved indices into their own data structure
797 for (unsigned int i = 0; i < irregular_cells.size(); ++i)
800 {
803 {
806 continue;
807 }
808 const unsigned int ndofs =
809 dofs_per_cell[have_hp ? cell_active_fe_index[i] : 0];
810 const unsigned int *dof_indices =
811 &this->dof_indices
813 unsigned int *interleaved_dof_indices =
815 [row_starts[i * vectorization_length * n_components].first];
816 AssertDimension(this->dof_indices.size(),
817 this->dof_indices_interleaved.size());
822 this->dof_indices_interleaved.size() + 1);
824 row_starts[i * vectorization_length * n_components].first +
825 ndofs * vectorization_length,
826 this->dof_indices_interleaved.size() + 1);
827 for (unsigned int k = 0; k < ndofs; ++k)
828 {
829 const unsigned int *my_dof_indices = dof_indices + k;
830 const unsigned int *end =
831 interleaved_dof_indices + vectorization_length;
832 for (; interleaved_dof_indices != end;
833 ++interleaved_dof_indices, my_dof_indices += ndofs)
834 *interleaved_dof_indices = *my_dof_indices;
835 }
836 }
837 }
838
839
840
841 void
843 const Table<2, ShapeInfo<double>> &shape_info,
844 const unsigned int n_owned_cells,
845 const unsigned int n_lanes,
846 const std::vector<FaceToCellTopology<1>> &inner_faces,
847 const std::vector<FaceToCellTopology<1>> &ghosted_faces,
848 const bool fill_cell_centric,
849 const MPI_Comm communicator_sm,
850 const bool use_vector_data_exchanger_full)
851 {
853
854 // partitioner 0: no face integrals, simply use the indices present
855 // on the cells
856 std::vector<types::global_dof_index> ghost_indices;
857 {
858 const unsigned int n_components = start_components.back();
859 for (unsigned int cell = 0; cell < n_owned_cells; ++cell)
860 {
861 for (unsigned int i = row_starts[cell * n_components].first;
862 i < row_starts[(cell + 1) * n_components].first;
863 ++i)
864 if (dof_indices[i] >= part.locally_owned_size() &&
866 ghost_indices.push_back(part.local_to_global(dof_indices[i]));
867
868 const unsigned int fe_index =
869 dofs_per_cell.size() == 1 ? 0 :
870 cell_active_fe_index[cell / n_lanes];
871 const unsigned int dofs_this_cell = dofs_per_cell[fe_index];
872
873 for (unsigned int i = row_starts_plain_indices[cell];
874 i < row_starts_plain_indices[cell] + dofs_this_cell;
875 ++i)
876 if (plain_dof_indices[i] >= part.locally_owned_size())
877 ghost_indices.push_back(
879 }
880 std::sort(ghost_indices.begin(), ghost_indices.end());
881 IndexSet compressed_set(part.size());
882 compressed_set.add_indices(ghost_indices.begin(), ghost_indices.end());
883 compressed_set.subtract_set(part.locally_owned_range());
884 const bool all_ghosts_equal =
885 Utilities::MPI::logical_and(compressed_set.n_elements() ==
886 part.ghost_indices().n_elements(),
887 part.get_mpi_communicator());
888
889 std::shared_ptr<const Utilities::MPI::Partitioner> temp_0;
890
891 if (all_ghosts_equal)
892 temp_0 = vector_partitioner;
893 else
894 {
895 temp_0 = std::make_shared<Utilities::MPI::Partitioner>(
897 const_cast<Utilities::MPI::Partitioner *>(temp_0.get())
898 ->set_ghost_indices(compressed_set, part.ghost_indices());
899 }
900
901 if (use_vector_data_exchanger_full == false)
902 vector_exchanger_face_variants[0] = std::make_shared<
904 temp_0);
905 else
907 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
908 temp_0, communicator_sm);
909 }
910
911 // construct a numbering of faces
912 std::vector<FaceToCellTopology<1>> all_faces(inner_faces);
913 all_faces.insert(all_faces.end(),
914 ghosted_faces.begin(),
915 ghosted_faces.end());
916 Table<2, unsigned int> cell_and_face_to_faces(
917 (row_starts.size() - 1) / start_components.back(),
918 2 * shape_info(0, 0).n_dimensions);
919 cell_and_face_to_faces.fill(numbers::invalid_unsigned_int);
920 for (unsigned int f = 0; f < all_faces.size(); ++f)
921 {
922 cell_and_face_to_faces(all_faces[f].cells_interior[0],
923 all_faces[f].interior_face_no) = f;
924 Assert(all_faces[f].cells_exterior[0] !=
927 cell_and_face_to_faces(all_faces[f].cells_exterior[0],
928 all_faces[f].exterior_face_no) = f;
929 }
930
931 // lambda function to detect objects on face pairs
932 const auto loop_over_faces =
933 [&](const std::function<
934 void(const unsigned int, const unsigned int, const bool)> &fu) {
935 for (const auto &face : inner_faces)
936 {
937 AssertIndexRange(face.cells_interior[0], n_owned_cells);
938 fu(face.cells_exterior[0], face.exterior_face_no, false /*flag*/);
939 }
940 };
941
942 const auto loop_over_all_faces =
943 [&](const std::function<
944 void(const unsigned int, const unsigned int, const bool)> &fu) {
945 for (unsigned int c = 0; c < cell_and_face_to_faces.size(0); ++c)
946 for (unsigned int d = 0; d < cell_and_face_to_faces.size(1); ++d)
947 {
948 const unsigned int f = cell_and_face_to_faces(c, d);
950 continue;
951
952 const unsigned int cell_m = all_faces[f].cells_interior[0];
953 const unsigned int cell_p = all_faces[f].cells_exterior[0];
954
955 const bool ext = c == cell_m;
956
957 if (ext && cell_p == numbers::invalid_unsigned_int)
958 continue;
959
960 const unsigned int p = ext ? cell_p : cell_m;
961 const unsigned int face_no = ext ?
962 all_faces[f].exterior_face_no :
963 all_faces[f].interior_face_no;
964
965 fu(p, face_no, true);
966 }
967 };
968
969 const auto process_values =
970 [&](
971 std::shared_ptr<const Utilities::MPI::Partitioner>
972 &vector_partitioner_values,
973 const std::function<void(
974 const std::function<void(
975 const unsigned int, const unsigned int, const bool)> &)> &loop) {
976 bool all_nodal_and_tensorial = shape_info.size(1) == 1;
977
978 if (all_nodal_and_tensorial)
979 for (unsigned int c = 0; c < n_base_elements; ++c)
980 {
981 const auto &si =
982 shape_info(global_base_element_offset + c, 0).data.front();
983 if (!si.nodal_at_cell_boundaries ||
984 (si.element_type ==
986 all_nodal_and_tensorial = false;
987 }
988
989 if (all_nodal_and_tensorial == false)
990 vector_partitioner_values = vector_partitioner;
991 else
992 {
993 bool has_noncontiguous_cell = false;
994
995 loop([&](const unsigned int cell_no,
996 const unsigned int face_no,
997 const bool flag) {
998 const unsigned int index =
1000 if (flag || (index != numbers::invalid_unsigned_int &&
1001 index >= part.locally_owned_size()))
1002 {
1003 const unsigned int stride =
1004 dof_indices_interleave_strides[dof_access_cell][cell_no];
1005 unsigned int i = 0;
1006 for (unsigned int e = 0; e < n_base_elements; ++e)
1007 for (unsigned int c = 0; c < n_components[e]; ++c)
1008 {
1009 const ShapeInfo<double> &shape =
1010 shape_info(global_base_element_offset + e, 0);
1011 for (unsigned int j = 0;
1012 j < shape.dofs_per_component_on_face;
1013 ++j)
1014 ghost_indices.push_back(part.local_to_global(
1015 index + i +
1016 shape.face_to_cell_index_nodal(face_no, j) *
1017 stride));
1018 i += shape.dofs_per_component_on_cell * stride;
1019 }
1020 AssertDimension(i, dofs_per_cell[0] * stride);
1021 }
1023 has_noncontiguous_cell = true;
1024 });
1025 has_noncontiguous_cell =
1026 Utilities::MPI::logical_and(has_noncontiguous_cell,
1027 part.get_mpi_communicator());
1028
1029 std::sort(ghost_indices.begin(), ghost_indices.end());
1030 IndexSet compressed_set(part.size());
1031 compressed_set.add_indices(ghost_indices.begin(),
1032 ghost_indices.end());
1033 compressed_set.subtract_set(part.locally_owned_range());
1034 const bool all_ghosts_equal =
1035 Utilities::MPI::logical_and(compressed_set.n_elements() ==
1036 part.ghost_indices().n_elements(),
1037 part.get_mpi_communicator());
1038 if (all_ghosts_equal || has_noncontiguous_cell)
1039 vector_partitioner_values = vector_partitioner;
1040 else
1041 {
1042 vector_partitioner_values =
1043 std::make_shared<Utilities::MPI::Partitioner>(
1045 const_cast<Utilities::MPI::Partitioner *>(
1046 vector_partitioner_values.get())
1047 ->set_ghost_indices(compressed_set, part.ghost_indices());
1048 }
1049 }
1050 };
1051
1052
1053 const auto process_gradients =
1054 [&](
1055 const std::shared_ptr<const Utilities::MPI::Partitioner>
1056 &vector_partitoner_values,
1057 std::shared_ptr<const Utilities::MPI::Partitioner>
1058 &vector_partitioner_gradients,
1059 const std::function<void(
1060 const std::function<void(
1061 const unsigned int, const unsigned int, const bool)> &)> &loop) {
1062 bool all_hermite = shape_info.size(1) == 1;
1063
1064 if (all_hermite)
1065 for (unsigned int c = 0; c < n_base_elements; ++c)
1066 if (shape_info(global_base_element_offset + c, 0).element_type !=
1068 all_hermite = false;
1069 if (all_hermite == false ||
1070 vector_partitoner_values.get() == vector_partitioner.get())
1071 vector_partitioner_gradients = vector_partitioner;
1072 else
1073 {
1074 loop([&](const unsigned int cell_no,
1075 const unsigned int face_no,
1076 const bool flag) {
1077 const unsigned int index =
1078 dof_indices_contiguous[dof_access_cell][cell_no];
1079 if (flag || (index != numbers::invalid_unsigned_int &&
1080 index >= part.locally_owned_size()))
1081 {
1082 const unsigned int stride =
1083 dof_indices_interleave_strides[dof_access_cell][cell_no];
1084 unsigned int i = 0;
1085 for (unsigned int e = 0; e < n_base_elements; ++e)
1086 for (unsigned int c = 0; c < n_components[e]; ++c)
1087 {
1088 const ShapeInfo<double> &shape =
1089 shape_info(global_base_element_offset + e, 0);
1090 for (unsigned int j = 0;
1091 j < 2 * shape.dofs_per_component_on_face;
1092 ++j)
1093 ghost_indices.push_back(part.local_to_global(
1094 index + i +
1095 shape.face_to_cell_index_hermite(face_no, j) *
1096 stride));
1097 i += shape.dofs_per_component_on_cell * stride;
1098 }
1099 AssertDimension(i, dofs_per_cell[0] * stride);
1100 }
1101 });
1102 std::sort(ghost_indices.begin(), ghost_indices.end());
1103 IndexSet compressed_set(part.size());
1104 compressed_set.add_indices(ghost_indices.begin(),
1105 ghost_indices.end());
1106 compressed_set.subtract_set(part.locally_owned_range());
1107 const bool all_ghosts_equal =
1108 Utilities::MPI::logical_and(compressed_set.n_elements() ==
1109 part.ghost_indices().n_elements(),
1110 part.get_mpi_communicator());
1111 if (all_ghosts_equal)
1112 vector_partitioner_gradients = vector_partitioner;
1113 else
1114 {
1115 vector_partitioner_gradients =
1116 std::make_shared<Utilities::MPI::Partitioner>(
1117 part.locally_owned_range(), part.get_mpi_communicator());
1118 const_cast<Utilities::MPI::Partitioner *>(
1119 vector_partitioner_gradients.get())
1120 ->set_ghost_indices(compressed_set, part.ghost_indices());
1121 }
1122 }
1123 };
1124
1125 std::shared_ptr<const Utilities::MPI::Partitioner> temp_1, temp_2, temp_3,
1126 temp_4;
1127
1128 // partitioner 1: values on faces
1129 process_values(temp_1, loop_over_faces);
1130
1131 // partitioner 2: values and gradients on faces
1132 process_gradients(temp_1, temp_2, loop_over_faces);
1133
1134 if (fill_cell_centric)
1135 {
1136 ghost_indices.clear();
1137 // partitioner 3: values on all faces
1138 process_values(temp_3, loop_over_all_faces);
1139 // partitioner 4: values and gradients on faces
1140 process_gradients(temp_3, temp_4, loop_over_all_faces);
1141 }
1142 else
1143 {
1144 temp_3 = std::make_shared<Utilities::MPI::Partitioner>(
1145 part.locally_owned_range(), part.get_mpi_communicator());
1146 temp_4 = std::make_shared<Utilities::MPI::Partitioner>(
1147 part.locally_owned_range(), part.get_mpi_communicator());
1148 }
1149
1150 if (use_vector_data_exchanger_full == false)
1151 {
1152 vector_exchanger_face_variants[1] = std::make_shared<
1153 MatrixFreeFunctions::VectorDataExchange::PartitionerWrapper>(
1154 temp_1);
1155 vector_exchanger_face_variants[2] = std::make_shared<
1156 MatrixFreeFunctions::VectorDataExchange::PartitionerWrapper>(
1157 temp_2);
1158 vector_exchanger_face_variants[3] = std::make_shared<
1159 MatrixFreeFunctions::VectorDataExchange::PartitionerWrapper>(
1160 temp_3);
1161 vector_exchanger_face_variants[4] = std::make_shared<
1162 MatrixFreeFunctions::VectorDataExchange::PartitionerWrapper>(
1163 temp_4);
1164 }
1165 else
1166 {
1167 vector_exchanger_face_variants[1] =
1168 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
1169 temp_1, communicator_sm);
1170 vector_exchanger_face_variants[2] =
1171 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
1172 temp_2, communicator_sm);
1173 vector_exchanger_face_variants[3] =
1174 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
1175 temp_3, communicator_sm);
1176 vector_exchanger_face_variants[4] =
1177 std::make_shared<MatrixFreeFunctions::VectorDataExchange::Full>(
1178 temp_4, communicator_sm);
1179 }
1180 }
1181
1182
1183
1184 void
1185 DoFInfo::compute_shared_memory_contiguous_indices(
1186 std::array<std::vector<std::pair<unsigned int, unsigned int>>, 3>
1187 &cell_indices_contiguous_sm)
1188 {
1189 AssertDimension(dofs_per_cell.size(), 1);
1190
1191 for (unsigned int i = 0; i < 3; ++i)
1192 {
1193 dof_indices_contiguous_sm[i].resize(
1194 cell_indices_contiguous_sm[i].size());
1195
1196 for (unsigned int j = 0; j < cell_indices_contiguous_sm[i].size();
1197 ++j)
1198 if (cell_indices_contiguous_sm[i][j].first !=
1200 dof_indices_contiguous_sm[i][j] = {
1201 cell_indices_contiguous_sm[i][j].first,
1202 cell_indices_contiguous_sm[i][j].second * dofs_per_cell[0]};
1203 else
1204 dof_indices_contiguous_sm[i][j] = {numbers::invalid_unsigned_int,
1206 }
1207 }
1208
1209
1210
1211 namespace internal
1212 {
1213 // We construct the connectivity graph in parallel. we use one lock for
1214 // 256 degrees of freedom to keep the number of locks down to a
1215 // reasonable level and reduce the cost of locking to some extent.
1216 static constexpr unsigned int bucket_size_threading = 256;
1217
1218
1219
1220 void
1221 compute_row_lengths(const unsigned int begin,
1222 const unsigned int end,
1223 const DoFInfo &dof_info,
1224 std::vector<std::mutex> &mutexes,
1225 std::vector<unsigned int> &row_lengths)
1226 {
1227 std::vector<unsigned int> scratch;
1228 const unsigned int n_components = dof_info.start_components.back();
1229 for (unsigned int block = begin; block < end; ++block)
1230 {
1231 scratch.assign(
1232 dof_info.dof_indices.data() +
1233 dof_info.row_starts[block * n_components].first,
1234 dof_info.dof_indices.data() +
1235 dof_info.row_starts[(block + 1) * n_components].first);
1236 std::sort(scratch.begin(), scratch.end());
1237
1238 const std::vector<unsigned int>::const_iterator end_unique =
1239 std::unique(scratch.begin(), scratch.end());
1240 for (std::vector<unsigned int>::const_iterator it = scratch.begin();
1241 it != end_unique && *it != numbers::invalid_unsigned_int;
1242 /* update in loop body */)
1243 {
1244 // In this code, the procedure is that we insert all elements
1245 // that are within the range of one lock at once
1246 const unsigned int next_bucket =
1248
1249 std::scoped_lock lock(mutexes[*it / bucket_size_threading]);
1250 for (; it != end_unique && *it < next_bucket; ++it)
1251 {
1252 AssertIndexRange(*it, row_lengths.size());
1253 ++row_lengths[*it];
1254 }
1255 }
1256 }
1257 }
1258
1259 void
1260 fill_connectivity_dofs(const unsigned int begin,
1261 const unsigned int end,
1262 const DoFInfo &dof_info,
1263 const std::vector<unsigned int> &row_lengths,
1264 std::vector<std::mutex> &mutexes,
1265 ::SparsityPattern &connectivity_dof)
1266 {
1267 std::vector<unsigned int> scratch;
1268 const unsigned int n_components = dof_info.start_components.back();
1269 for (unsigned int block = begin; block < end; ++block)
1270 {
1271 scratch.assign(
1272 dof_info.dof_indices.data() +
1273 dof_info.row_starts[block * n_components].first,
1274 dof_info.dof_indices.data() +
1275 dof_info.row_starts[(block + 1) * n_components].first);
1276 std::sort(scratch.begin(), scratch.end());
1277
1278 const std::vector<unsigned int>::const_iterator end_unique =
1279 std::unique(scratch.begin(), scratch.end());
1280 for (std::vector<unsigned int>::const_iterator it = scratch.begin();
1281 it != end_unique && *it != numbers::invalid_unsigned_int;
1282 /* update in loop body */)
1283 {
1284 const unsigned int next_bucket =
1286
1287 std::scoped_lock lock(mutexes[*it / bucket_size_threading]);
1288 for (; it != end_unique && *it < next_bucket; ++it)
1289 if (row_lengths[*it] > 0)
1290 connectivity_dof.add(*it, block);
1291 }
1292 }
1293 }
1294
1295
1296
1297 void
1298 fill_connectivity(const unsigned int begin,
1299 const unsigned int end,
1300 const DoFInfo &dof_info,
1301 const std::vector<unsigned int> &renumbering,
1302 const ::SparsityPattern &connectivity_dof,
1303 DynamicSparsityPattern &connectivity)
1304 {
1305 ordered_vector row_entries;
1306 const unsigned int n_components = dof_info.start_components.back();
1307 for (unsigned int block = begin; block < end; ++block)
1308 {
1309 row_entries.clear();
1310
1311 const unsigned int
1312 *it = dof_info.dof_indices.data() +
1313 dof_info.row_starts[block * n_components].first,
1314 *end_cell = dof_info.dof_indices.data() +
1315 dof_info.row_starts[(block + 1) * n_components].first;
1316 for (; it != end_cell; ++it)
1318 {
1319 SparsityPattern::iterator sp = connectivity_dof.begin(*it);
1320 std::vector<types::global_dof_index>::iterator insert_pos =
1321 row_entries.begin();
1322 for (; sp != connectivity_dof.end(*it); ++sp)
1323 if (sp->column() != block)
1324 row_entries.insert(renumbering[sp->column()], insert_pos);
1325 }
1326 connectivity.add_entries(renumbering[block],
1327 row_entries.begin(),
1328 row_entries.end());
1329 }
1330 }
1331
1332 } // namespace internal
1333
1334 void
1335 DoFInfo::make_connectivity_graph(
1336 const TaskInfo &task_info,
1337 const std::vector<unsigned int> &renumbering,
1338 DynamicSparsityPattern &connectivity) const
1339 {
1340 unsigned int n_rows = (vector_partitioner->local_range().second -
1341 vector_partitioner->local_range().first) +
1342 vector_partitioner->ghost_indices().n_elements();
1343
1344 // Avoid square sparsity patterns that allocate the diagonal entry
1345 if (n_rows == task_info.n_active_cells)
1346 ++n_rows;
1347
1348 // first determine row lengths
1349 std::vector<unsigned int> row_lengths(n_rows);
1350 std::vector<std::mutex> mutexes(n_rows / internal::bucket_size_threading +
1351 1);
1353 0,
1354 task_info.n_active_cells,
1355 [this, &mutexes, &row_lengths](const unsigned int begin,
1356 const unsigned int end) {
1357 internal::compute_row_lengths(
1358 begin, end, *this, mutexes, row_lengths);
1359 },
1360 20);
1361
1362 // disregard dofs that only sit on a single cell because they cannot
1363 // couple
1364 for (unsigned int row = 0; row < n_rows; ++row)
1365 if (row_lengths[row] <= 1)
1366 row_lengths[row] = 0;
1367
1368 // Create a temporary sparsity pattern that holds to each degree of
1369 // freedom on which cells it appears, i.e., store the connectivity
1370 // between cells and dofs
1371 SparsityPattern connectivity_dof(n_rows,
1372 task_info.n_active_cells,
1373 row_lengths);
1375 0,
1376 task_info.n_active_cells,
1377 [this, &row_lengths, &mutexes, &connectivity_dof](
1378 const unsigned int begin, const unsigned int end) {
1379 internal::fill_connectivity_dofs(
1380 begin, end, *this, row_lengths, mutexes, connectivity_dof);
1381 },
1382 20);
1383 connectivity_dof.compress();
1384
1385
1386 // Invert renumbering for use in fill_connectivity.
1387 std::vector<unsigned int> reverse_numbering(task_info.n_active_cells);
1388 reverse_numbering = Utilities::invert_permutation(renumbering);
1389
1390 // From the above connectivity between dofs and cells, we can finally
1391 // create a connectivity list between cells. The connectivity graph
1392 // should apply the renumbering, i.e., the entry for cell j is the entry
1393 // for cell renumbering[j] in the original ordering.
1395 0,
1396 task_info.n_active_cells,
1397 [this, &reverse_numbering, &connectivity_dof, &connectivity](
1398 const unsigned int begin, const unsigned int end) {
1399 internal::fill_connectivity(begin,
1400 end,
1401 *this,
1402 reverse_numbering,
1403 connectivity_dof,
1404 connectivity);
1405 },
1406 20);
1407 }
1408
1409
1410
1411 void
1412 DoFInfo::compute_dof_renumbering(
1413 std::vector<types::global_dof_index> &renumbering)
1414 {
1415 const unsigned int locally_owned_size =
1416 vector_partitioner->locally_owned_size();
1417 renumbering.resize(0);
1419
1420 types::global_dof_index counter = 0;
1421 const unsigned int n_components = start_components.back();
1422 const unsigned int n_cell_batches =
1423 n_vectorization_lanes_filled[dof_access_cell].size();
1424 Assert(n_cell_batches <=
1425 (row_starts.size() - 1) / vectorization_length / n_components,
1427 for (unsigned int cell_no = 0; cell_no < n_cell_batches; ++cell_no)
1428 {
1429 // do not renumber in case we have constraints
1430 if (row_starts[cell_no * n_components * vectorization_length]
1431 .second ==
1432 row_starts[(cell_no + 1) * n_components * vectorization_length]
1433 .second)
1434 {
1435 const unsigned int ndofs =
1436 dofs_per_cell.size() == 1 ?
1437 dofs_per_cell[0] :
1438 (dofs_per_cell[cell_active_fe_index.size() > 0 ?
1439 cell_active_fe_index[cell_no] :
1440 0]);
1441 const unsigned int *dof_ind =
1442 dof_indices.data() +
1443 row_starts[cell_no * n_components * vectorization_length].first;
1444 for (unsigned int i = 0; i < ndofs; ++i)
1445 for (unsigned int j = 0;
1446 j < n_vectorization_lanes_filled[dof_access_cell][cell_no];
1447 ++j)
1448 if (dof_ind[j * ndofs + i] < locally_owned_size)
1449 if (renumbering[dof_ind[j * ndofs + i]] ==
1451 renumbering[dof_ind[j * ndofs + i]] = counter++;
1452 }
1453 }
1454
1456 for (types::global_dof_index &dof_index : renumbering)
1457 if (dof_index == numbers::invalid_dof_index)
1458 dof_index = counter++;
1459
1460 // transform indices to global index space
1461 for (types::global_dof_index &dof_index : renumbering)
1462 dof_index = vector_partitioner->local_to_global(dof_index);
1463
1464 AssertDimension(counter, renumbering.size());
1465 }
1466
1467
1468
1469 std::size_t
1470 DoFInfo::memory_consumption() const
1471 {
1472 std::size_t memory = sizeof(*this);
1473 for (const auto &storage : index_storage_variants)
1474 memory += storage.capacity() * sizeof(storage[0]);
1475 memory +=
1476 (row_starts.capacity() * sizeof(std::pair<unsigned int, unsigned int>));
1477 memory += MemoryConsumption::memory_consumption(dof_indices);
1478 memory += MemoryConsumption::memory_consumption(dof_indices_interleaved);
1479 memory += MemoryConsumption::memory_consumption(dof_indices_contiguous);
1480 memory +=
1481 MemoryConsumption::memory_consumption(dof_indices_contiguous_sm);
1482 memory +=
1483 MemoryConsumption::memory_consumption(dof_indices_interleave_strides);
1484 memory +=
1485 MemoryConsumption::memory_consumption(n_vectorization_lanes_filled);
1487 hanging_node_constraint_masks_comp);
1488 memory +=
1489 MemoryConsumption::memory_consumption(hanging_node_constraint_masks);
1490 memory += MemoryConsumption::memory_consumption(constrained_dofs);
1491 memory += MemoryConsumption::memory_consumption(row_starts_plain_indices);
1492 memory += MemoryConsumption::memory_consumption(plain_dof_indices);
1493 memory += MemoryConsumption::memory_consumption(constraint_indicator);
1494 memory += MemoryConsumption::memory_consumption(*vector_partitioner);
1495 memory += MemoryConsumption::memory_consumption(n_components);
1496 memory += MemoryConsumption::memory_consumption(start_components);
1497 memory += MemoryConsumption::memory_consumption(component_to_base_index);
1498 memory +=
1499 MemoryConsumption::memory_consumption(component_dof_indices_offset);
1500 memory += MemoryConsumption::memory_consumption(dofs_per_cell);
1501 memory += MemoryConsumption::memory_consumption(dofs_per_face);
1502 memory += MemoryConsumption::memory_consumption(cell_active_fe_index);
1503 memory += MemoryConsumption::memory_consumption(fe_index_conversion);
1504 memory +=
1505 MemoryConsumption::memory_consumption(vector_zero_range_list_index);
1506 memory += MemoryConsumption::memory_consumption(vector_zero_range_list);
1507 memory += MemoryConsumption::memory_consumption(cell_loop_pre_list_index);
1508 memory += MemoryConsumption::memory_consumption(cell_loop_pre_list);
1509 memory +=
1510 MemoryConsumption::memory_consumption(cell_loop_post_list_index);
1511 memory += MemoryConsumption::memory_consumption(cell_loop_post_list);
1512 return memory;
1513 }
1514 } // namespace MatrixFreeFunctions
1515} // namespace internal
1516
1517namespace internal
1518{
1519 namespace MatrixFreeFunctions
1520 {
1521 template void
1522 DoFInfo::read_dof_indices<double>(
1523 const std::vector<types::global_dof_index> &,
1524 const std::vector<types::global_dof_index> &,
1525 const bool,
1526 const ::AffineConstraints<double> &,
1527 const unsigned int,
1528 ConstraintValues<double> &,
1529 bool &);
1530
1531 template void
1532 DoFInfo::read_dof_indices<float>(
1533 const std::vector<types::global_dof_index> &,
1534 const std::vector<types::global_dof_index> &,
1535 const bool,
1536 const ::AffineConstraints<float> &,
1537 const unsigned int,
1538 ConstraintValues<double> &,
1539 bool &);
1540
1541 template bool
1542 DoFInfo::process_hanging_node_constraints<1>(
1543 const HangingNodes<1> &,
1544 const std::vector<std::vector<unsigned int>> &,
1545 const unsigned int,
1547 std::vector<types::global_dof_index> &);
1548 template bool
1549 DoFInfo::process_hanging_node_constraints<2>(
1550 const HangingNodes<2> &,
1551 const std::vector<std::vector<unsigned int>> &,
1552 const unsigned int,
1554 std::vector<types::global_dof_index> &);
1555 template bool
1556 DoFInfo::process_hanging_node_constraints<3>(
1557 const HangingNodes<3> &,
1558 const std::vector<std::vector<unsigned int>> &,
1559 const unsigned int,
1561 std::vector<types::global_dof_index> &);
1562
1563 template void
1564 DoFInfo::compute_face_index_compression<1>(
1565 const std::vector<FaceToCellTopology<1>> &,
1566 bool);
1567 template void
1568 DoFInfo::compute_face_index_compression<2>(
1569 const std::vector<FaceToCellTopology<2>> &,
1570 bool);
1571 template void
1572 DoFInfo::compute_face_index_compression<4>(
1573 const std::vector<FaceToCellTopology<4>> &,
1574 bool);
1575 template void
1576 DoFInfo::compute_face_index_compression<8>(
1577 const std::vector<FaceToCellTopology<8>> &,
1578 bool);
1579 template void
1580 DoFInfo::compute_face_index_compression<16>(
1581 const std::vector<FaceToCellTopology<16>> &,
1582 bool);
1583
1584 template void
1585 DoFInfo::compute_vector_zero_access_pattern<1>(
1586 const TaskInfo &,
1587 const std::vector<FaceToCellTopology<1>> &);
1588 template void
1589 DoFInfo::compute_vector_zero_access_pattern<2>(
1590 const TaskInfo &,
1591 const std::vector<FaceToCellTopology<2>> &);
1592 template void
1593 DoFInfo::compute_vector_zero_access_pattern<4>(
1594 const TaskInfo &,
1595 const std::vector<FaceToCellTopology<4>> &);
1596 template void
1597 DoFInfo::compute_vector_zero_access_pattern<8>(
1598 const TaskInfo &,
1599 const std::vector<FaceToCellTopology<8>> &);
1600 template void
1601 DoFInfo::compute_vector_zero_access_pattern<16>(
1602 const TaskInfo &,
1603 const std::vector<FaceToCellTopology<16>> &);
1604
1605 template void
1606 DoFInfo::print_memory_consumption<std::ostream>(std::ostream &,
1607 const TaskInfo &) const;
1608 template void
1609 DoFInfo::print_memory_consumption<ConditionalOStream>(
1611 const TaskInfo &) const;
1612
1613 template void
1614 DoFInfo::print<double>(const std::vector<double> &,
1615 const std::vector<unsigned int> &,
1616 std::ostream &) const;
1617
1618 template void
1619 DoFInfo::print<float>(const std::vector<float> &,
1620 const std::vector<unsigned int> &,
1621 std::ostream &) const;
1622 } // namespace MatrixFreeFunctions
1623} // namespace internal
1624
*  iterator end()
*  *  iterator begin()
void add_entries(const size_type row, ForwardIterator begin, ForwardIterator end, const bool indices_are_unique_and_sorted=false)
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
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
void add_range(const size_type begin, const size_type end)
Definition index_set.h:1786
void compress() const
Definition index_set.h:1767
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition index_set.h:1814
void add(const size_type i, const size_type j)
const IndexSet & locally_owned_range() const
const IndexSet & ghost_indices() const
unsigned int locally_owned_size() const
types::global_dof_index local_to_global(const unsigned int local_index) const
virtual MPI_Comm get_mpi_communicator() const override
void set_ghost_indices(const IndexSet &ghost_indices, const IndexSet &larger_ghost_index_set=IndexSet())
types::global_dof_index size() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
Point< 2 > second
Definition grid_out.cc:4640
Point< 2 > first
Definition grid_out.cc:4639
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcInternalError()
std::size_t size
Definition mpi.cc:733
types::global_dof_index locally_owned_size
Definition mpi.cc:821
std::enable_if_t< std::is_fundamental_v< T >, std::size_t > memory_consumption(const T &t)
bool logical_and(const bool t, const MPI_Comm mpi_communicator)
std::vector< Integer > invert_permutation(const std::vector< Integer > &permutation)
Definition utilities.h:1670
void fill_connectivity_dofs(const unsigned int begin, const unsigned int end, const DoFInfo &dof_info, const std::vector< unsigned int > &row_lengths, std::vector< std::mutex > &mutexes, ::SparsityPattern &connectivity_dof)
Definition dof_info.cc:1260
void fill_connectivity(const unsigned int begin, const unsigned int end, const DoFInfo &dof_info, const std::vector< unsigned int > &renumbering, const ::SparsityPattern &connectivity_dof, DynamicSparsityPattern &connectivity)
Definition dof_info.cc:1298
void compute_row_lengths(const unsigned int begin, const unsigned int end, const DoFInfo &dof_info, std::vector< std::mutex > &mutexes, std::vector< unsigned int > &row_lengths)
Definition dof_info.cc:1221
static constexpr unsigned int bucket_size_threading
Definition dof_info.cc:1216
constexpr compressed_constraint_kind unconstrained_compressed_constraint_kind
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
constexpr unsigned int invalid_unsigned_int
Definition types.h:228
void apply_to_subranges(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, const Function &f, const unsigned int grainsize)
Definition parallel.h:266
::VectorizedArray< Number, width > max(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)
void reorder_cells(const TaskInfo &task_info, const std::vector< unsigned int > &renumbering, const std::vector< unsigned int > &constraint_pool_row_index, const std::vector< unsigned char > &irregular_cells)
Definition dof_info.cc:277
std::vector< std::pair< unsigned short, unsigned short > > constraint_indicator
Definition dof_info.h:536
std::vector< std::pair< unsigned int, unsigned int > > row_starts
Definition dof_info.h:495
void compute_tight_partitioners(const Table< 2, ShapeInfo< double > > &shape_info, const unsigned int n_owned_cells, const unsigned int n_lanes, const std::vector< FaceToCellTopology< 1 > > &inner_faces, const std::vector< FaceToCellTopology< 1 > > &ghosted_faces, const bool fill_cell_centric, const MPI_Comm communicator_sm, const bool use_vector_data_exchanger_full)
Definition dof_info.cc:842
std::vector< std::vector< bool > > hanging_node_constraint_masks_comp
Definition dof_info.h:518
void get_dof_indices_on_cell_batch(std::vector< unsigned int > &local_indices, const unsigned int cell_batch, const bool with_constraints=true) const
Definition dof_info.cc:82
void compute_cell_index_compression(const std::vector< unsigned char > &irregular_cells)
Definition dof_info.cc:500
std::vector< unsigned int > dofs_per_cell
Definition dof_info.h:693
void assign_ghosts(const std::vector< unsigned int > &boundary_cells, const MPI_Comm communicator_sm, const bool use_vector_data_exchanger_full)
Definition dof_info.cc:145
std::shared_ptr< const internal::MatrixFreeFunctions::VectorDataExchange::Base > vector_exchanger
Definition dof_info.h:598
std::vector< std::vector< unsigned int > > fe_index_conversion
Definition dof_info.h:721
std::vector< unsigned int > dof_indices
Definition dof_info.h:512
std::shared_ptr< const Utilities::MPI::Partitioner > vector_partitioner
Definition dof_info.h:591
std::vector< compressed_constraint_kind > hanging_node_constraint_masks
Definition dof_info.h:524
std::array< std::vector< unsigned int >, 3 > dof_indices_interleave_strides
Definition dof_info.h:572
std::vector< unsigned int > row_starts_plain_indices
Definition dof_info.h:635
std::vector< unsigned int > dofs_per_face
Definition dof_info.h:698
std::vector< unsigned int > n_components
Definition dof_info.h:663
std::vector< types::global_dof_index > ghost_dofs
Definition dof_info.h:728
std::array< std::vector< unsigned int >, 3 > dof_indices_contiguous
Definition dof_info.h:551
std::vector< unsigned int > cell_active_fe_index
Definition dof_info.h:708
std::array< std::shared_ptr< const internal::MatrixFreeFunctions::VectorDataExchange::Base >, 5 > vector_exchanger_face_variants
Definition dof_info.h:623
std::vector< unsigned int > plain_dof_indices
Definition dof_info.h:645
std::array< std::vector< unsigned char >, 3 > n_vectorization_lanes_filled
Definition dof_info.h:583
std::vector< unsigned int > start_components
Definition dof_info.h:669
std::vector< unsigned int > dof_indices_interleaved
Definition dof_info.h:541
std::array< std::vector< IndexStorageVariants >, 3 > index_storage_variants
Definition dof_info.h:487
std::vector< unsigned int > cell_partition_data
Definition task_info.h:472