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
petsc_communication_pattern.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) 2023 - 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
14
15#ifdef DEAL_II_WITH_PETSC
16
17# include <deal.II/base/mpi.h>
18
20
21
22#endif // DEAL_II_WITH_PETSC
23
25
26#ifdef DEAL_II_WITH_PETSC
27// Shorthand notation for PETSc error codes.
28# define AssertPETSc(code) \
29 do \
30 { \
31 PetscErrorCode ierr = (code); \
32 AssertThrow(ierr == 0, ExcPETScError(ierr)); \
33 } \
34 while (false)
35
36namespace PETScWrappers
37{
41
42
43
48
49
50
51 void
53 const IndexSet &ghost_indices,
54 const MPI_Comm communicator)
55 {
56 clear();
57 AssertIndexRange(local_size, ghost_indices.size() + 1);
58 // If the size of the index set can be converted to a PetscInt then every
59 // index can also be converted
60 AssertThrowIntegerConversion(ghost_indices.size(),
61 static_cast<PetscInt>(ghost_indices.size()));
62
63 PetscLayout layout;
64 AssertPETSc(PetscLayoutCreate(communicator, &layout));
65 const auto petsc_local_size = static_cast<PetscInt>(local_size);
66 AssertThrowIntegerConversion(local_size, petsc_local_size);
67 AssertPETSc(PetscLayoutSetLocalSize(layout, petsc_local_size));
68 AssertPETSc(PetscLayoutSetUp(layout));
69
70 PetscInt start, end;
71 AssertPETSc(PetscLayoutGetRange(layout, &start, &end));
72
73 IndexSet want;
74 want.add_range(start, end);
75 want.add_indices(ghost_indices);
76 want.compress();
77
78 const PetscInt *idxs;
79 PetscInt n;
80 IS is = want.make_petsc_is(communicator);
81 AssertPETSc(ISGetLocalSize(is, &n));
82 AssertPETSc(ISGetIndices(is, &idxs));
83
84 AssertPETSc(PetscSFCreate(communicator, &sf));
86 PetscSFSetGraphLayout(sf, layout, n, nullptr, PETSC_OWN_POINTER, idxs));
87 AssertPETSc(PetscSFSetUp(sf));
88
89 AssertPETSc(ISRestoreIndices(is, &idxs));
90 AssertPETSc(ISDestroy(&is));
91 AssertPETSc(PetscLayoutDestroy(&layout));
92 }
93
94
95
96 void
97 CommunicationPattern::reinit(const IndexSet &locally_owned_indices,
98 const IndexSet &ghost_indices,
99 const MPI_Comm communicator)
100 {
101 // If the sizes of the index sets can be converted to PetscInts then every
102 // index can also be converted
103 AssertThrowIntegerConversion(static_cast<PetscInt>(
104 locally_owned_indices.size()),
105 locally_owned_indices.size());
106 AssertThrowIntegerConversion(static_cast<PetscInt>(ghost_indices.size()),
107 ghost_indices.size());
108
109 const auto in_deal = locally_owned_indices.get_index_vector();
110 std::vector<PetscInt> in_petsc(in_deal.begin(), in_deal.end());
111
112 const auto out_deal = ghost_indices.get_index_vector();
113 std::vector<PetscInt> out_petsc(out_deal.begin(), out_deal.end());
114
115 std::vector<PetscInt> dummy;
116
117 this->do_reinit(in_petsc, dummy, out_petsc, dummy, communicator);
118 }
119
120
121
122 void
124 const std::vector<types::global_dof_index> &indices_has,
125 const std::vector<types::global_dof_index> &indices_want,
126 const MPI_Comm communicator)
127 {
128 // Clean vectors from numbers::invalid_dof_index (indicating padding)
129 std::vector<PetscInt> indices_has_clean, indices_has_loc;
130 std::vector<PetscInt> indices_want_clean, indices_want_loc;
131 indices_want_clean.reserve(indices_want.size());
132 indices_want_loc.reserve(indices_want.size());
133 indices_has_clean.reserve(indices_has.size());
134 indices_has_loc.reserve(indices_has.size());
135
136 PetscInt loc = 0;
137 bool has_invalid = false;
138 for (const auto i : indices_has)
139 {
141 {
142 const auto petsc_i = static_cast<PetscInt>(i);
144 indices_has_clean.push_back(petsc_i);
145 indices_has_loc.push_back(loc);
146 }
147 else
148 has_invalid = true;
149 ++loc;
150 }
151 if (!has_invalid)
152 indices_has_loc.clear();
153
154 loc = 0;
155 has_invalid = false;
156 for (const auto i : indices_want)
157 {
159 {
160 const auto petsc_i = static_cast<PetscInt>(i);
162 indices_want_clean.push_back(petsc_i);
163 indices_want_loc.push_back(loc);
164 }
165 else
166 has_invalid = true;
167 ++loc;
168 }
169 if (!has_invalid)
170 indices_want_loc.clear();
171
172 this->do_reinit(indices_has_clean,
173 indices_has_loc,
174 indices_want_clean,
175 indices_want_loc,
176 communicator);
177 }
178
179
180
181 void
182 CommunicationPattern::do_reinit(const std::vector<PetscInt> &inidx,
183 const std::vector<PetscInt> &inloc,
184 const std::vector<PetscInt> &outidx,
185 const std::vector<PetscInt> &outloc,
186 const MPI_Comm communicator)
187 {
188 clear();
189
190 // inidx is assumed to be unstructured and non-overlapping.
191 // However, it may have holes in it and not be a full cover.
192 //
193 // We create two PETSc SFs and compose them to get
194 // the final communication pattern
195 //
196 // sf1 : local distributed to tmp
197 // sf2 : tmp to local with ghosts
198 // sf(x) = sf2(sf1(x))
199 PetscSF sf1, sf2;
200
201 // First create an SF where leaves are inidx (at location inloc)
202 // and roots are unique indices in contiguous way
203 // Code adapted from MatZeroRowsMapLocal_Private in PETSc
204 PetscInt n = static_cast<PetscInt>(inidx.size());
205 PetscInt lN = n > 0 ? *std::max_element(inidx.begin(), inidx.end()) : -1;
206 PetscInt N, nl;
207
208 Utilities::MPI::internal::all_reduce<PetscInt>(
209 MPI_MAX,
211 communicator,
212 ArrayView<PetscInt>(&N, 1));
213
214 PetscSFNode *remotes;
215 AssertPETSc(PetscMalloc1(n, &remotes));
216
217 PetscLayout layout;
218 AssertPETSc(PetscLayoutCreate(communicator, &layout));
219 AssertPETSc(PetscLayoutSetSize(layout, N + 1));
220 AssertPETSc(PetscLayoutSetUp(layout));
221 AssertPETSc(PetscLayoutGetLocalSize(layout, &nl));
222
223 const PetscInt *ranges;
224 AssertPETSc(PetscLayoutGetRanges(layout, &ranges));
225
226 PetscInt cnt = 0;
227# if DEAL_II_PETSC_VERSION_GTE(3, 13, 0)
228 PetscMPIInt owner = 0;
229# else
230 PetscInt owner = 0;
231# endif
232 for (const auto idx : inidx)
233 {
234 // short-circuit the search if the last owner owns this index too
235 if (idx < ranges[owner] || ranges[owner + 1] <= idx)
236 {
237 AssertPETSc(PetscLayoutFindOwner(layout, idx, &owner));
238 }
239 remotes[cnt].rank = owner;
240 remotes[cnt].index = idx - ranges[owner];
241 ++cnt;
242 }
243
244 AssertPETSc(PetscSFCreate(communicator, &sf2));
245 AssertPETSc(PetscSFSetGraph(sf2,
246 nl,
247 n,
248 const_cast<PetscInt *>(
249 inloc.size() > 0 ? inloc.data() : nullptr),
250 PETSC_COPY_VALUES,
251 remotes,
252 PETSC_OWN_POINTER));
253 AssertPETSc(PetscSFSetUp(sf2));
254 // We need to invert root and leaf space to create the first SF
255 AssertPETSc(PetscSFCreateInverseSF(sf2, &sf1));
256 AssertPETSc(PetscSFDestroy(&sf2));
257
258 // Now create the SF from the contiguous space to the local output space
259 n = static_cast<PetscInt>(outidx.size());
260 AssertPETSc(PetscSFCreate(communicator, &sf2));
261 AssertPETSc(PetscSFSetGraphLayout(
262 sf2,
263 layout,
264 n,
265 const_cast<PetscInt *>(outloc.size() > 0 ? outloc.data() : nullptr),
266 PETSC_COPY_VALUES,
267 const_cast<PetscInt *>(n > 0 ? outidx.data() : nullptr)));
268 AssertPETSc(PetscSFSetUp(sf2));
269
270 // The final SF is the composition of the two
271 AssertPETSc(PetscSFCompose(sf1, sf2, &sf));
272
273 // Cleanup
274 AssertPETSc(PetscLayoutDestroy(&layout));
275 AssertPETSc(PetscSFDestroy(&sf1));
276 AssertPETSc(PetscSFDestroy(&sf2));
277 }
278
279
280
281 void
283 {
284 AssertPETSc(PetscSFDestroy(&sf));
285 }
286
287
288
291 {
292 return PetscObjectComm(reinterpret_cast<PetscObject>(sf));
293 }
294
295
296
297 template <typename Number>
298 void
300 const ArrayView<const Number> &src,
301 const ArrayView<Number> &dst) const
302 {
303 auto datatype = Utilities::MPI::mpi_type_id_for_type<Number>;
304
305# if DEAL_II_PETSC_VERSION_LT(3, 15, 0)
306 AssertPETSc(PetscSFBcastBegin(sf, datatype, src.data(), dst.data()));
307# else
309 PetscSFBcastBegin(sf, datatype, src.data(), dst.data(), MPI_REPLACE));
310# endif
311 }
312
313
314
315 template <typename Number>
316 void
318 const ArrayView<const Number> &src,
319 const ArrayView<Number> &dst) const
320 {
321 auto datatype = Utilities::MPI::mpi_type_id_for_type<Number>;
322
323# if DEAL_II_PETSC_VERSION_LT(3, 15, 0)
324 AssertPETSc(PetscSFBcastEnd(sf, datatype, src.data(), dst.data()));
325# else
327 PetscSFBcastEnd(sf, datatype, src.data(), dst.data(), MPI_REPLACE));
328# endif
329 }
330
331
332
333 template <typename Number>
334 void
342
343
344
345 template <typename Number>
346 void
349 const ArrayView<const Number> &src,
350 const ArrayView<Number> &dst) const
351 {
352 MPI_Op mpiop = (op == VectorOperation::insert) ? MPI_REPLACE : MPI_SUM;
353 auto datatype = Utilities::MPI::mpi_type_id_for_type<Number>;
354
356 PetscSFReduceBegin(sf, datatype, src.data(), dst.data(), mpiop));
357 }
358
359
360
361 template <typename Number>
362 void
365 const ArrayView<const Number> &src,
366 const ArrayView<Number> &dst) const
367 {
368 MPI_Op mpiop = (op == VectorOperation::insert) ? MPI_REPLACE : MPI_SUM;
369 auto datatype = Utilities::MPI::mpi_type_id_for_type<Number>;
370
371 AssertPETSc(PetscSFReduceEnd(sf, datatype, src.data(), dst.data(), mpiop));
372 }
373
374
375
376 template <typename Number>
377 void
386
387# ifndef DOXYGEN
388
389 // Partitioner
390
392 : ghost()
393 , larger_ghost()
394 , ghost_indices_data()
395 , n_ghost_indices_data(numbers::invalid_dof_index)
396 , n_ghost_indices_larger(numbers::invalid_dof_index)
397 {}
398
399
400
401 void
402 Partitioner::reinit(const IndexSet &locally_owned_indices,
403 const IndexSet &ghost_indices,
404 const MPI_Comm communicator)
405 {
407 ghost_indices_data.subtract_set(locally_owned_indices);
409
410 ghost.reinit(locally_owned_indices, ghost_indices_data, communicator);
412
415 }
416
417 void
418 Partitioner::reinit(const IndexSet &locally_owned_indices,
419 const IndexSet &ghost_indices,
420 const IndexSet &larger_ghost_indices,
421 const MPI_Comm communicator)
422 {
424 ghost_indices_data.subtract_set(locally_owned_indices);
426
427 std::vector<types::global_dof_index> expanded_ghost_indices(
428 larger_ghost_indices.n_elements(), numbers::invalid_dof_index);
429 for (auto index : ghost_indices_data)
430 {
431 Assert(larger_ghost_indices.is_element(index),
432 ExcMessage("The given larger ghost index set must contain "
433 "all indices in the actual index set."));
434 auto tmp_index = larger_ghost_indices.index_within_set(index);
435 expanded_ghost_indices[tmp_index] = index;
436 }
437
438 ghost.reinit(locally_owned_indices, ghost_indices_data, communicator);
439 larger_ghost.reinit(locally_owned_indices.get_index_vector(),
440 expanded_ghost_indices,
441 communicator);
443 n_ghost_indices_larger = larger_ghost_indices.n_elements();
444 }
445
448 {
450 }
451
452 template <typename Number>
453 void
455 const ArrayView<Number> &dst) const
456 {
457 if (dst.size() == n_ghost_indices_larger)
458 {
460 }
461 else
462 {
464 }
465 }
466
467 template <typename Number>
468 void
470 const ArrayView<const Number> &src,
471 const ArrayView<Number> &dst) const
472 {
473 if (dst.size() == n_ghost_indices_larger)
474 {
476 }
477 else
478 {
480 }
481 }
482
483 template <typename Number>
484 void
486 const ArrayView<Number> &dst) const
487 {
490 }
491
492 template <typename Number>
493 void
496 const ArrayView<const Number> &src,
497 const ArrayView<Number> &dst) const
498 {
499 if (src.size() == n_ghost_indices_larger)
500 {
502 }
503 else
504 {
506 }
507 }
508
509 template <typename Number>
510 void
513 const ArrayView<const Number> &src,
514 const ArrayView<Number> &dst) const
515 {
516 if (src.size() == n_ghost_indices_larger)
517 {
519 }
520 else
521 {
523 }
524 }
525
526 template <typename Number>
527 void
529 const ArrayView<const Number> &src,
530 const ArrayView<Number> &dst) const
531 {
534 }
535# endif
536} // namespace PETScWrappers
537
538// Explicit instantiations
539# include "lac/petsc_communication_pattern.inst"
540
541
542#endif // DEAL_II_WITH_PETSC
*  iterator end()
value_type * data() const noexcept
Definition array_view.h:714
std::size_t size() const
Definition array_view.h:737
IS make_petsc_is(const MPI_Comm communicator=MPI_COMM_WORLD) const
size_type size() const
Definition index_set.h:1759
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 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
std::vector< size_type > get_index_vector() const
Definition index_set.cc:911
void add_indices(const ForwardIterator &begin, const ForwardIterator &end)
Definition index_set.h:1814
void import_from_ghosted_array(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
void export_to_ghosted_array_start(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
void export_to_ghosted_array(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
void export_to_ghosted_array_finish(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
void import_from_ghosted_array_finish(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
void do_reinit(const std::vector< PetscInt > &inidx, const std::vector< PetscInt > &inloc, const std::vector< PetscInt > &outidx, const std::vector< PetscInt > &outloc, const MPI_Comm communicator)
virtual void reinit(const IndexSet &locally_owned_indices, const IndexSet &ghost_indices, const MPI_Comm communicator) override
void import_from_ghosted_array_start(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
types::global_dof_index n_ghost_indices_data
virtual void reinit(const IndexSet &locally_owned_indices, const IndexSet &ghost_indices, const MPI_Comm communicator) override
void import_from_ghosted_array(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
void export_to_ghosted_array_finish(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
MPI_Comm get_mpi_communicator() const override
void export_to_ghosted_array(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
void export_to_ghosted_array_start(const ArrayView< const Number > &locally_owned_array, const ArrayView< Number > &ghost_array) const
void import_from_ghosted_array_start(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
void import_from_ghosted_array_finish(const VectorOperation::values op, const ArrayView< const Number > &ghost_array, const ArrayView< Number > &locally_owned_array) const
types::global_dof_index n_ghost_indices_larger
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertThrowIntegerConversion(index1, index2)
#define Assert(cond, exc)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcMessage(std::string arg1)
constexpr types::global_dof_index invalid_dof_index
Definition types.h:259
#define AssertPETSc(code)