deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00: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_parallel_vector.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) 2004 - 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
13#include <deal.II/base/mpi.h>
14
16
17#ifdef DEAL_II_WITH_PETSC
18
19# include <algorithm>
20# include <cmath>
21
22
23#endif // DEAL_II_WITH_PETSC
24
26
27#ifdef DEAL_II_WITH_PETSC
28
29namespace PETScWrappers
30{
31 namespace MPI
32 {
33 // Check that the class we declare here satisfies the
34 // vector-space-vector concept. If we catch it here,
35 // any mistake in the vector class declaration would
36 // show up in uses of this class later on as well.
37# ifdef DEAL_II_HAVE_CXX20
39# endif
40
42 {
43 // virtual functions called in constructors and destructors never use the
44 // override in a derived class
45 // for clarity be explicit on which function is called
46 Vector::create_vector(MPI_COMM_SELF, 0, 0);
47 }
48
49
50
51 Vector::Vector(const MPI_Comm communicator,
52 const size_type n,
54 {
56 }
57
58
59
61 const IndexSet &ghost,
62 const MPI_Comm communicator)
63 {
64 Assert(local.is_ascending_and_one_to_one(communicator),
66
67 IndexSet ghost_set = ghost;
68 ghost_set.subtract_set(local);
69
70 Vector::create_vector(communicator,
71 local.size(),
72 local.n_elements(),
73 ghost_set);
74 }
75
76
77
79 : VectorBase()
80 {
81 if (v.has_ghost_elements())
83 v.size(),
86 else
88 v.size(),
90
91 this->operator=(v);
92 }
93
94
95
96 Vector::Vector(const IndexSet &local, const MPI_Comm communicator)
97 {
98 Assert(local.is_ascending_and_one_to_one(communicator),
100 Vector::create_vector(communicator, local.size(), local.n_elements());
101 }
102
103
104
105 Vector &
107 {
108 // make sure left- and right-hand side of the assignment are
109 // compress()'ed:
111 internal::VectorReference::ExcWrongMode(VectorOperation::unknown,
112 v.last_action));
114 internal::VectorReference::ExcWrongMode(VectorOperation::unknown,
115 last_action));
116
117 // if the vectors have different sizes,
118 // then first resize the present one
119 if (size() != v.size())
120 {
121 if (v.has_ghost_elements())
125 else
127 v.size(),
129 true);
130 }
131
132 if (ghosted)
134
135 PetscErrorCode ierr = VecCopy(v.vector, vector);
136 AssertThrow(ierr == 0, ExcPETScError(ierr));
137
138 if (has_ghost_elements())
139 {
140 ierr = VecGhostUpdateBegin(vector, INSERT_VALUES, SCATTER_FORWARD);
141 AssertThrow(ierr == 0, ExcPETScError(ierr));
142 ierr = VecGhostUpdateEnd(vector, INSERT_VALUES, SCATTER_FORWARD);
143 AssertThrow(ierr == 0, ExcPETScError(ierr));
144
146 }
147 return *this;
148 }
149
150
151
152 void
154 {
156
157 create_vector(MPI_COMM_SELF, 0, 0);
158 }
159
160
161
162 void
163 Vector::reinit(const MPI_Comm communicator,
164 const size_type n,
165 const size_type local_sz,
166 const bool omit_zeroing_entries)
167 {
168 // only do something if the sizes
169 // mismatch (may not be true for every proc)
170 const bool update_size =
172 (locally_owned_size() != local_sz),
174
175 if (update_size || has_ghost_elements())
176 {
177 if (has_ghost_elements())
179
180 // PETSc doesn't support resizing non-empty vectors so create a new
181 // one:
182 const PetscErrorCode ierr = VecDestroy(&vector);
183 AssertThrow(ierr == 0, ExcPETScError(ierr));
184
185 create_vector(communicator, n, local_sz);
186 }
187
188 // finally clear the new vector if so
189 // desired
190 if (omit_zeroing_entries == false)
191 *this = 0;
192
193 if (has_ghost_elements())
195 }
196
197
198
199 void
200 Vector::reinit(const Vector &v, const bool omit_zeroing_entries)
201 {
202 if (v.has_ghost_elements())
203 {
207 if (!omit_zeroing_entries)
208 {
209 const PetscErrorCode ierr = VecSet(vector, 0.0);
210 AssertThrow(ierr == 0, ExcPETScError(ierr));
211 }
212 }
213 else
215 v.size(),
217 omit_zeroing_entries);
218 }
219
220
221
222 void
224 const IndexSet &ghost,
225 const MPI_Comm comm)
226 {
227 if (ghosted)
229
230 const PetscErrorCode ierr = VecDestroy(&vector);
231 AssertThrow(ierr == 0, ExcPETScError(ierr));
232
234
235 IndexSet ghost_set = ghost;
236 ghost_set.subtract_set(local);
237
238 create_vector(comm, local.size(), local.n_elements(), ghost_set);
239 }
240
241 void
243 {
244 if (ghosted)
246
247 const PetscErrorCode ierr = VecDestroy(&vector);
248 AssertThrow(ierr == 0, ExcPETScError(ierr));
249
251 Assert(local.size() > 0, ExcMessage("can not create vector of size 0."));
252 create_vector(comm, local.size(), local.n_elements());
253 }
254
255 void
257 const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner,
258 const bool make_ghosted)
259 {
260 if (make_ghosted)
261 {
262 Assert(partitioner->ghost_indices_initialized(),
263 ExcMessage("You asked to create a ghosted vector, but the "
264 "partitioner does not provide ghost indices."));
265
266 this->reinit(partitioner->locally_owned_range(),
267 partitioner->ghost_indices(),
268 partitioner->get_mpi_communicator());
269 }
270 else
271 {
272 this->reinit(partitioner->locally_owned_range(),
273 partitioner->get_mpi_communicator());
274 }
275 }
276
277
278 void
279 Vector::create_vector(const MPI_Comm communicator,
280 const size_type n,
282 {
284 ghosted = false;
285
286 const PetscErrorCode ierr = VecCreateMPI(communicator,
288 PETSC_DETERMINE,
289 &vector);
290 AssertThrow(ierr == 0, ExcPETScError(ierr));
291
292 Assert(size() == n, ExcDimensionMismatch(size(), n));
293 }
294
295
296
297 void
298 Vector::create_vector(const MPI_Comm communicator,
299 const size_type n,
301 const IndexSet &ghostnodes)
302 {
304 // If the size of the index set can be converted to a PetscInt then every
305 // index can also be converted
306 AssertThrowIntegerConversion(static_cast<PetscInt>(n), n);
307 ghosted = true;
308 ghost_indices = ghostnodes;
309
310 std::size_t i = 0;
311 std::vector<PetscInt> petsc_ghost_indices(ghostnodes.n_elements());
312 for (const auto &index : ghostnodes)
313 {
314 petsc_ghost_indices[i] = static_cast<PetscInt>(index);
315 ++i;
316 }
317
318 PetscErrorCode ierr = VecCreateGhost(communicator,
320 PETSC_DETERMINE,
321 petsc_ghost_indices.size(),
322 petsc_ghost_indices.data(),
323 &vector);
324 AssertThrow(ierr == 0, ExcPETScError(ierr));
325
326 Assert(size() == n, ExcDimensionMismatch(size(), n));
327
328 if constexpr (running_in_debug_mode())
329 {
330 // test ghost allocation in debug mode
331 PetscInt begin, end;
332
333 ierr = VecGetOwnershipRange(vector, &begin, &end);
334 AssertThrow(ierr == 0, ExcPETScError(ierr));
335
337 static_cast<size_type>(end - begin));
338
339 Vec l;
340 ierr = VecGhostGetLocalForm(vector, &l);
341 AssertThrow(ierr == 0, ExcPETScError(ierr));
342
343 PetscInt lsize;
344 ierr = VecGetSize(l, &lsize);
345 AssertThrow(ierr == 0, ExcPETScError(ierr));
346
347 ierr = VecGhostRestoreLocalForm(vector, &l);
348 AssertThrow(ierr == 0, ExcPETScError(ierr));
349
350 AssertDimension(lsize,
351 end - begin +
352 static_cast<PetscInt>(ghost_indices.n_elements()));
353 }
354
356 }
357
358
359
360 void
361 Vector::print(std::ostream &out,
362 const unsigned int precision,
363 const bool scientific,
364 const bool across) const
365 {
366 AssertThrow(out.fail() == false, ExcIO());
367
368 // get a representation of the vector and
369 // loop over all the elements
370 const PetscScalar *val;
371 PetscInt nlocal, istart, iend;
372
373 PetscErrorCode ierr = VecGetArrayRead(vector, &val);
374 AssertThrow(ierr == 0, ExcPETScError(ierr));
375
376 ierr = VecGetLocalSize(vector, &nlocal);
377 AssertThrow(ierr == 0, ExcPETScError(ierr));
378
379 ierr = VecGetOwnershipRange(vector, &istart, &iend);
380 AssertThrow(ierr == 0, ExcPETScError(ierr));
381
382 // save the state of out stream
383 std::ios::fmtflags old_flags = out.flags();
384 unsigned int old_precision = out.precision(precision);
385
386 out.precision(precision);
387 if (scientific)
388 out.setf(std::ios::scientific, std::ios::floatfield);
389 else
390 out.setf(std::ios::fixed, std::ios::floatfield);
391
392 // let each processor produce its output in turn. this requires
393 // synchronizing output between processors using a barrier --
394 // which is clearly slow, but nobody is going to print a whole
395 // matrix this way on a regular basis for production runs, so
396 // the slowness of the barrier doesn't matter
397 MPI_Comm communicator = this->get_mpi_communicator();
398 for (unsigned int i = 0;
399 i < Utilities::MPI::n_mpi_processes(communicator);
400 i++)
401 {
402 const int mpi_ierr = MPI_Barrier(communicator);
403 AssertThrowMPI(mpi_ierr);
404
405 if (i == Utilities::MPI::this_mpi_process(communicator))
406 {
407 if (across)
408 {
409 out << "[Proc" << i << " " << istart << "-" << iend - 1 << "]"
410 << ' ';
411 for (PetscInt i = 0; i < nlocal; ++i)
412 out << val[i] << ' ';
413 }
414 else
415 {
416 out << "[Proc " << i << " " << istart << "-" << iend - 1
417 << "]" << std::endl;
418 for (PetscInt i = 0; i < nlocal; ++i)
419 out << val[i] << std::endl;
420 }
421 out << std::endl;
422 }
423 }
424 // reset output format
425 out.flags(old_flags);
426 out.precision(old_precision);
427
428 // restore the representation of the
429 // vector
430 ierr = VecRestoreArrayRead(vector, &val);
431 AssertThrow(ierr == 0, ExcPETScError(ierr));
432
433 AssertThrow(out.fail() == false, ExcIO());
434 }
435
436 } // namespace MPI
437
438} // namespace PETScWrappers
439
440
441#endif // DEAL_II_WITH_PETSC
*  iterator end()
*  *  iterator begin()
bool is_ascending_and_one_to_one(const MPI_Comm communicator) const
size_type size() const
Definition index_set.h:1759
size_type n_elements() const
Definition index_set.h:1917
void subtract_set(const IndexSet &other)
Definition index_set.cc:496
void print(std::ostream &out, const unsigned int precision=3, const bool scientific=true, const bool across=true) const
Vector & operator=(const Vector &v)
virtual void create_vector(const MPI_Comm comm, const size_type n, const size_type locally_owned_size)
void reinit(const MPI_Comm communicator, const size_type N, const size_type locally_owned_size, const bool omit_zeroing_entries=false)
VectorOperation::values last_action
IndexSet locally_owned_elements() const
MPI_Comm get_mpi_communicator() const
bool has_ghost_elements() const
size_type locally_owned_size() const
size_type size() const override
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
constexpr bool running_in_debug_mode()
Definition config.h:76
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertThrowIntegerConversion(index1, index2)
static ::ExceptionBase & ExcIO()
static ::ExceptionBase & ExcNotImplemented()
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertThrowMPI(error_code)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
const MPI_Comm comm
Definition mpi.cc:912
types::global_dof_index locally_owned_size
Definition mpi.cc:821
T logical_or(const T &t, const MPI_Comm mpi_communicator)
unsigned int n_mpi_processes(const MPI_Comm mpi_communicator)
Definition mpi.cc:103
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
Definition mpi.cc:118