ryujin 2.1.1 revision ee5cbcbf2346c1299c942d0e1f13b46449973c18
Loading...
Searching...
No Matches
local_index_handling.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2020 - 2025 by the ryujin authors
4//
5
6#pragma once
7
8#include <compile_time_options.h>
9
10#include <deal.II/base/partitioner.h>
11#include <deal.II/dofs/dof_handler.h>
12#include <deal.II/dofs/dof_renumbering.h>
13#include <deal.II/dofs/dof_tools.h>
14#include <deal.II/lac/affine_constraints.h>
15#include <deal.II/lac/dynamic_sparsity_pattern.h>
16#include <deal.II/lac/sparsity_tools.h>
17
18namespace ryujin
19{
28 template <typename Number>
30 const dealii::Utilities::MPI::Partitioner &partitioner,
31 dealii::AffineConstraints<Number> &affine_constraints)
32 {
33 affine_constraints.close();
34
35 dealii::AffineConstraints<Number> temporary;
36
37 for (auto line : affine_constraints.get_lines()) {
38 /* translate into local index ranges: */
39 line.index = partitioner.global_to_local(line.index);
40 std::transform(line.entries.begin(),
41 line.entries.end(),
42 line.entries.begin(),
43 [&](auto entry) {
44 return std::make_pair(
45 partitioner.global_to_local(entry.first),
46 entry.second);
47 });
48
49 temporary.add_line(line.index);
50 temporary.add_entries(line.index, line.entries);
51 temporary.set_inhomogeneity(line.index, line.inhomogeneity);
52 }
53
54 temporary.close();
55
56 affine_constraints = std::move(temporary);
57 }
58
59
68 template <typename VECTOR>
70 const dealii::Utilities::MPI::Partitioner &partitioner, VECTOR &vector)
71 {
72 std::transform(
73 vector.begin(), vector.end(), vector.begin(), [&](auto index) {
74 return partitioner.global_to_local(index);
75 });
76 }
77
78
85 namespace DoFRenumbering
86 {
91 using dealii::DoFRenumbering::Cuthill_McKee;
92
102 template <int dim>
103 unsigned int export_indices_first(dealii::DoFHandler<dim> &dof_handler,
104 const MPI_Comm &mpi_communicator,
105 const unsigned int n_locally_internal,
106 const std::size_t warp_size)
107 {
108 using namespace dealii;
109
110 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
111 const auto n_locally_owned = locally_owned.n_elements();
112
113 /* The locally owned index range has to be contiguous */
114 Assert(locally_owned.is_contiguous() == true,
115 dealii::ExcMessage(
116 "Need a contiguous set of locally owned indices."));
117
118 /* Offset to translate from global to local index range */
119 const auto offset = n_locally_owned != 0 ? *locally_owned.begin() : 0;
120
121 const auto locally_relevant =
122 DoFTools::extract_locally_relevant_dofs(dof_handler);
123
124 /* Create a temporary MPI partitioner: */
125
126 Utilities::MPI::Partitioner partitioner(
127 locally_owned, locally_relevant, mpi_communicator);
128
129 IndexSet export_indices(n_locally_owned);
130 for (const auto &it : partitioner.import_indices()) {
131 export_indices.add_range(it.first, it.second);
132 }
133
134 std::vector<dealii::types::global_dof_index> new_order(n_locally_owned);
135
136 /*
137 * First pass: reorder all strides containing export indices and mark
138 * all other indices with numbers::invalid_dof_index:
139 */
140
141 unsigned int n_export_indices = 0;
142
143 Assert(n_locally_internal <= n_locally_owned, dealii::ExcInternalError());
144
145 for (unsigned int i = 0; i < n_locally_internal; i += warp_size) {
146 bool export_index_present = false;
147 for (unsigned int j = 0; j < warp_size; ++j) {
148 if (export_indices.is_element(i + j)) {
149 export_index_present = true;
150 break;
151 }
152 }
153
154 if (export_index_present) {
155 Assert(n_export_indices % warp_size == 0, dealii::ExcInternalError());
156 for (unsigned int j = 0; j < warp_size; ++j) {
157 new_order[i + j] = offset + n_export_indices++;
158 }
159 } else {
160 for (unsigned int j = 0; j < warp_size; ++j)
161 new_order[i + j] = dealii::numbers::invalid_dof_index;
162 }
163 }
164
165#if DEBUG
166 unsigned int n_other = 0;
167 for (unsigned int i = n_locally_internal; i < n_locally_owned; ++i)
168 if (export_indices.is_element(i))
169 n_other++;
170
171 Assert(n_other + n_export_indices >= export_indices.n_elements(),
172 dealii::ExcInternalError());
173#endif
174
175 unsigned int running_index = n_export_indices;
176
177 /*
178 * Second pass: append the rest:
179 */
180
181 for (unsigned int i = 0; i < n_locally_internal; i += warp_size) {
182 if (new_order[i] == dealii::numbers::invalid_dof_index) {
183 for (unsigned int j = 0; j < warp_size; ++j) {
184 Assert(new_order[i + j] == dealii::numbers::invalid_dof_index,
185 dealii::ExcInternalError());
186 new_order[i + j] = offset + running_index++;
187 }
188 }
189 }
190
191 Assert(running_index == n_locally_internal, dealii::ExcInternalError());
192
193 for (unsigned int i = n_locally_internal; i < n_locally_owned; i++) {
194 new_order[i] = offset + running_index++;
195 }
196
197 Assert(running_index == n_locally_owned, dealii::ExcInternalError());
198
199 dof_handler.renumber_dofs(new_order);
200
201 Assert(n_export_indices % warp_size == 0, dealii::ExcInternalError());
202 Assert(n_export_indices <= n_locally_internal,
203 dealii::ExcInternalError());
204 return n_export_indices;
205 }
206
207
214 template <int dim>
215 unsigned int
216 inconsistent_strides_last(dealii::DoFHandler<dim> &dof_handler,
217 const dealii::DynamicSparsityPattern &sparsity,
218 const unsigned int n_locally_internal,
219 const std::size_t warp_size)
220 {
221 using namespace dealii;
222
223 const IndexSet &locally_owned = dof_handler.locally_owned_dofs();
224 const auto n_locally_owned = locally_owned.n_elements();
225
226 /* The locally owned index range has to be contiguous */
227 Assert(locally_owned.is_contiguous() == true,
228 dealii::ExcMessage(
229 "Need a contiguous set of locally owned indices."));
230
231 /* Offset to translate from global to local index range */
232 const auto offset = n_locally_owned != 0 ? *locally_owned.begin() : 0;
233
234 std::vector<dealii::types::global_dof_index> new_order(n_locally_owned);
235
236 /*
237 * First pass: keep all strides with consistent row length at the
238 * beginning of the locally internal index range and mark all other
239 * indices with numbers::invalid_dof_index:
240 */
241
242 unsigned int n_consistent_range = 0;
243
244 Assert(n_locally_internal <= n_locally_owned, dealii::ExcInternalError());
245
246 for (unsigned int i = 0; i < n_locally_internal; i += warp_size) {
247
248 bool stride_is_consistent = true;
249 const auto warp_row_length = sparsity.row_length(offset + i);
250 for (unsigned int j = 0; j < warp_size; ++j) {
251 if (warp_row_length != sparsity.row_length(offset + i + j)) {
252 stride_is_consistent = false;
253 break;
254 }
255 }
256
257 if (stride_is_consistent) {
258 for (unsigned int j = 0; j < warp_size; ++j) {
259 new_order[i + j] = offset + n_consistent_range++;
260 }
261 } else {
262 for (unsigned int j = 0; j < warp_size; ++j)
263 new_order[i + j] = dealii::numbers::invalid_dof_index;
264 }
265 }
266
267 /*
268 * Second pass: append the rest:
269 */
270
271 unsigned int running_index = n_consistent_range;
272
273 for (unsigned int i = 0; i < n_locally_internal; i += warp_size) {
274 if (new_order[i] == dealii::numbers::invalid_dof_index) {
275 for (unsigned int j = 0; j < warp_size; ++j) {
276 Assert(new_order[i + j] == dealii::numbers::invalid_dof_index,
277 dealii::ExcInternalError());
278 new_order[i + j] = offset + running_index++;
279 }
280 }
281 }
282
283 Assert(running_index == n_locally_internal, dealii::ExcInternalError());
284
285 for (unsigned int i = n_locally_internal; i < n_locally_owned; i++) {
286 new_order[i] = offset + running_index++;
287 }
288
289 Assert(running_index == n_locally_owned, dealii::ExcInternalError());
290
291 dof_handler.renumber_dofs(new_order);
292
293 Assert(n_consistent_range % warp_size == 0, dealii::ExcInternalError());
294 Assert(n_consistent_range <= n_locally_internal,
295 dealii::ExcInternalError());
296 return n_consistent_range;
297 }
298
299
315 template <int dim>
316 unsigned int internal_range(dealii::DoFHandler<dim> &dof_handler,
317 const dealii::DynamicSparsityPattern &sparsity,
318 const std::size_t warp_size)
319 {
320 using namespace dealii;
321
322 const auto &locally_owned = dof_handler.locally_owned_dofs();
323 const auto n_locally_owned = locally_owned.n_elements();
324
325 /* The locally owned index range has to be contiguous */
326
327 Assert(locally_owned.is_contiguous() == true,
328 dealii::ExcMessage(
329 "Need a contiguous set of locally owned indices."));
330
331 /* Offset to translate from global to local index range */
332 const auto offset = n_locally_owned != 0 ? *locally_owned.begin() : 0;
333
334 using dof_type = dealii::types::global_dof_index;
335 std::vector<dof_type> new_order(n_locally_owned);
336 dof_type current_index = offset;
337
338 /*
339 * Sort degrees of freedom into a map grouped by stencil size. Write
340 * out dof indices into the new_order vector in warps of warp_size
341 * consecutive indices with same stencil size.
342 */
343
344 std::map<unsigned int, std::set<dof_type>> bins;
345
346 for (unsigned int i = 0; i < n_locally_owned; ++i) {
347 const dof_type index = i;
348 const unsigned int row_length = sparsity.row_length(offset + index);
349 bins[row_length].insert(index);
350
351 if (bins[row_length].size() == warp_size) {
352 for (const auto &index : bins[row_length])
353 new_order[index] = current_index++;
354 bins.erase(row_length);
355 }
356 }
357
358 unsigned int n_locally_internal = current_index - offset;
359
360 /* Write out the rest. */
361
362 for (const auto &entries : bins) {
363 Assert(entries.second.size() > 0, ExcInternalError());
364 for (const auto &index : entries.second)
365 new_order[index] = current_index++;
366 }
367 Assert(current_index == offset + n_locally_owned, ExcInternalError());
368
369 dof_handler.renumber_dofs(new_order);
370
371 Assert(n_locally_internal % warp_size == 0, ExcInternalError());
372 return n_locally_internal;
373 }
374 } // namespace DoFRenumbering
375
376
383 namespace DoFTools
384 {
386 using dealii::DoFTools::extract_locally_relevant_dofs;
387
389 using dealii::DoFTools::make_hanging_node_constraints;
390
392 using dealii::DoFTools::make_periodicity_constraints;
393
395 using dealii::DoFTools::make_sparsity_pattern;
396
397
405 template <int dim, typename Number, typename SPARSITY>
407 const dealii::DoFHandler<dim> &dof_handler,
408 SPARSITY &dsp,
409 const dealii::AffineConstraints<Number> &affine_constraints,
410 bool keep_constrained)
411 {
412 std::vector<dealii::types::global_dof_index> dof_indices;
413
414 for (auto cell : dof_handler.active_cell_iterators()) {
415 /* iterate over locally owned cells and the ghost layer */
416 if (cell->is_artificial())
417 continue;
418
419 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
420 dof_indices.resize(dofs_per_cell);
421 cell->get_dof_indices(dof_indices);
422
423 affine_constraints.add_entries_local_to_global(
424 dof_indices, dsp, keep_constrained);
425 }
426 }
427
428
437 template <int dim, typename Number, typename SPARSITY>
439 const dealii::DoFHandler<dim> &dof_handler,
440 SPARSITY &dsp,
441 const dealii::AffineConstraints<Number> &affine_constraints,
442 bool keep_constrained)
443 {
444 Assert(affine_constraints.n_constraints() == 0,
445 dealii::ExcMessage("I don't think constraints make sense for dG"));
446
447 std::vector<dealii::types::global_dof_index> dof_indices;
448 std::vector<dealii::types::global_dof_index> neighbor_dof_indices;
449
450 /*
451 * We collect all coupling dof indices on a face and store the result
452 * in a vector.
453 */
454 std::vector<dealii::types::global_dof_index> coupling_indices;
455 std::vector<dealii::types::global_dof_index> neighbor_coupling_indices;
456
457 /* we iterate over locally owned cells and the ghost layer */
458 for (auto cell : dof_handler.active_cell_iterators()) {
459 if (cell->is_artificial())
460 continue;
461
462 const unsigned int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
463 dof_indices.resize(dofs_per_cell);
464 cell->get_dof_indices(dof_indices);
465
466 affine_constraints.add_entries_local_to_global(
467 dof_indices, dsp, keep_constrained);
468
469 for (const auto f_index : cell->face_indices()) {
470 const auto &face = cell->face(f_index);
471
472 /* Skip faces without neighbors... */
473 const bool has_neighbor =
474 !face->at_boundary() || cell->has_periodic_neighbor(f_index);
475 if (!has_neighbor)
476 continue;
477
478 /* Avoid artificial cells: */
479 const auto neighbor_cell =
480 cell->neighbor_or_periodic_neighbor(f_index);
481 if (neighbor_cell->is_artificial())
482 continue;
483
484 const unsigned int neighbor_dofs_per_cell =
485 neighbor_cell->get_fe().n_dofs_per_cell();
486 neighbor_dof_indices.resize(neighbor_dofs_per_cell);
487 neighbor_cell->get_dof_indices(neighbor_dof_indices);
488
489 const unsigned int f_index_neighbor =
490 cell->has_periodic_neighbor(f_index)
491 ? cell->periodic_neighbor_of_periodic_neighbor(f_index)
492 : cell->neighbor_of_neighbor(f_index);
493
494 /*
495 * Construct all couplings between current and neighbor cell with
496 * DoFs located at the boundary:
497 */
498
499 coupling_indices.resize(0);
500 for (unsigned int i = 0; i < dofs_per_cell; ++i)
501 if (cell->get_fe().has_support_on_face(i, f_index))
502 coupling_indices.push_back(dof_indices[i]);
503
504 neighbor_coupling_indices.resize(0);
505 for (unsigned int j = 0; j < neighbor_dofs_per_cell; ++j)
506 if (neighbor_cell->get_fe().has_support_on_face(j,
507 f_index_neighbor))
508 neighbor_coupling_indices.push_back(neighbor_dof_indices[j]);
509
510 affine_constraints.add_entries_local_to_global(
511 coupling_indices,
512 neighbor_coupling_indices,
513 dsp,
514 keep_constrained);
515 }
516 }
517 }
518
519
520 } // namespace DoFTools
521
522} // namespace ryujin
void make_extended_sparsity_pattern(const dealii::DoFHandler< dim > &dof_handler, SPARSITY &dsp, const dealii::AffineConstraints< Number > &affine_constraints, bool keep_constrained)
void transform_to_local_range(const dealii::Utilities::MPI::Partitioner &partitioner, dealii::AffineConstraints< Number > &affine_constraints)
unsigned int inconsistent_strides_last(dealii::DoFHandler< dim > &dof_handler, const dealii::DynamicSparsityPattern &sparsity, const unsigned int n_locally_internal, const std::size_t warp_size)
unsigned int export_indices_first(dealii::DoFHandler< dim > &dof_handler, const MPI_Comm &mpi_communicator, const unsigned int n_locally_internal, const std::size_t warp_size)
unsigned int internal_range(dealii::DoFHandler< dim > &dof_handler, const dealii::DynamicSparsityPattern &sparsity, const std::size_t warp_size)
void make_extended_sparsity_pattern_dg(const dealii::DoFHandler< dim > &dof_handler, SPARSITY &dsp, const dealii::AffineConstraints< Number > &affine_constraints, bool keep_constrained)
constexpr unsigned int warp_size
Definition gpu.h:46