Reference documentation for deal.II version 9.1.0-pre
petsc_parallel_vector.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2004 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/base/mpi.h>
17 
18 #include <deal.II/lac/petsc_vector.h>
19 
20 #ifdef DEAL_II_WITH_PETSC
21 
22 # include <algorithm>
23 # include <cmath>
24 
25 DEAL_II_NAMESPACE_OPEN
26 
27 namespace PETScWrappers
28 {
29  namespace MPI
30  {
32  : communicator(MPI_COMM_SELF)
33  {
34  // virtual functions called in constructors and destructors never use the
35  // override in a derived class
36  // for clarity be explicit on which function is called
38  }
39 
40 
41 
42  Vector::Vector(const MPI_Comm &communicator,
43  const size_type n,
44  const size_type local_size)
45  : communicator(communicator)
46  {
47  Vector::create_vector(n, local_size);
48  }
49 
50 
51 
52  Vector::Vector(const MPI_Comm & communicator,
53  const VectorBase &v,
54  const size_type local_size)
55  : VectorBase(v)
56  , communicator(communicator)
57  {
58  // In the past (before it was deprecated) this constructor did a
59  // byte-for-byte copy of v. This choice resulted in two problems:
60  // 1. The created vector will have the same size as v, not local size.
61  // 2. Since both the created vector and v maintain ownership of the same
62  // PETSc Vec, both will try to destroy it: this does not make sense.
63  //
64  // For the sake of backwards compatibility, preserve the behavior of the
65  // copy, but correct the ownership bug. Note that in both this (and the
66  // original) implementation local_size is ultimately unused.
67  (void)local_size;
68  }
69 
70 
71 
72  Vector::Vector(const IndexSet &local,
73  const IndexSet &ghost,
74  const MPI_Comm &communicator)
75  : communicator(communicator)
76  {
77  Assert(local.is_ascending_and_one_to_one(communicator),
79 
80  IndexSet ghost_set = ghost;
81  ghost_set.subtract_set(local);
82 
83  Vector::create_vector(local.size(), local.n_elements(), ghost_set);
84  }
85 
86 
87 
88  Vector::Vector(const IndexSet &local, const MPI_Comm &communicator)
89  : communicator(communicator)
90  {
91  Assert(local.is_ascending_and_one_to_one(communicator),
93  Vector::create_vector(local.size(), local.n_elements());
94  }
95 
96 
97 
98  Vector &
100  {
101  // make sure left- and right-hand side of the assignment are
102  // compress()'ed:
104  internal::VectorReference::ExcWrongMode(VectorOperation::unknown,
105  v.last_action));
107  internal::VectorReference::ExcWrongMode(VectorOperation::unknown,
108  last_action));
109 
110  // if the vectors have different sizes,
111  // then first resize the present one
112  if (size() != v.size())
113  {
114  if (v.has_ghost_elements())
116  else
117  reinit(v.communicator, v.size(), v.local_size(), true);
118  }
119 
120  PetscErrorCode ierr = VecCopy(v.vector, vector);
121  AssertThrow(ierr == 0, ExcPETScError(ierr));
122 
123  if (has_ghost_elements())
124  {
125  ierr = VecGhostUpdateBegin(vector, INSERT_VALUES, SCATTER_FORWARD);
126  AssertThrow(ierr == 0, ExcPETScError(ierr));
127  ierr = VecGhostUpdateEnd(vector, INSERT_VALUES, SCATTER_FORWARD);
128  AssertThrow(ierr == 0, ExcPETScError(ierr));
129  }
130  return *this;
131  }
132 
133 
134 
135  void
137  {
138  obtained_ownership = true;
140 
141  create_vector(0, 0);
142  }
143 
144 
145 
146  void
147  Vector::reinit(const MPI_Comm &comm,
148  const size_type n,
149  const size_type local_sz,
150  const bool omit_zeroing_entries)
151  {
152  communicator = comm;
153 
154  // only do something if the sizes
155  // mismatch (may not be true for every proc)
156 
157  int k_global, k = ((size() != n) || (local_size() != local_sz));
158  {
159  const int ierr =
160  MPI_Allreduce(&k, &k_global, 1, MPI_INT, MPI_LOR, communicator);
161  AssertThrowMPI(ierr);
162  }
163 
164  if (k_global || has_ghost_elements())
165  {
166  // FIXME: I'd like to use this here,
167  // but somehow it leads to odd errors
168  // somewhere down the line in some of
169  // the tests:
170  // const PetscErrorCode ierr = VecSetSizes (vector, n, n);
171  // AssertThrow (ierr == 0, ExcPETScError(ierr));
172 
173  // so let's go the slow way:
174 
175  const PetscErrorCode ierr = VecDestroy(&vector);
176  AssertThrow(ierr == 0, ExcPETScError(ierr));
177 
178  create_vector(n, local_sz);
179  }
180 
181  // finally clear the new vector if so
182  // desired
183  if (omit_zeroing_entries == false)
184  *this = 0;
185  }
186 
187 
188 
189  void
190  Vector::reinit(const Vector &v, const bool omit_zeroing_entries)
191  {
192  if (v.has_ghost_elements())
193  {
195  if (!omit_zeroing_entries)
196  {
197  const PetscErrorCode ierr = VecSet(vector, 0.0);
198  AssertThrow(ierr == 0, ExcPETScError(ierr));
199  }
200  }
201  else
202  reinit(v.communicator, v.size(), v.local_size(), omit_zeroing_entries);
203  }
204 
205 
206 
207  void
208  Vector::reinit(const IndexSet &local,
209  const IndexSet &ghost,
210  const MPI_Comm &comm)
211  {
212  const PetscErrorCode ierr = VecDestroy(&vector);
213  AssertThrow(ierr == 0, ExcPETScError(ierr));
214 
215  communicator = comm;
216 
218 
219  IndexSet ghost_set = ghost;
220  ghost_set.subtract_set(local);
221 
222  create_vector(local.size(), local.n_elements(), ghost_set);
223  }
224 
225  void
226  Vector::reinit(const IndexSet &local, const MPI_Comm &comm)
227  {
228  const PetscErrorCode ierr = VecDestroy(&vector);
229  AssertThrow(ierr == 0, ExcPETScError(ierr));
230 
231  communicator = comm;
232 
234  Assert(local.size() > 0, ExcMessage("can not create vector of size 0."));
235  create_vector(local.size(), local.n_elements());
236  }
237 
238 
239  void
241  {
242  (void)n;
243  Assert(local_size <= n, ExcIndexRange(local_size, 0, n));
244  ghosted = false;
245 
246  const PetscErrorCode ierr =
247  VecCreateMPI(communicator, local_size, PETSC_DETERMINE, &vector);
248  AssertThrow(ierr == 0, ExcPETScError(ierr));
249 
250  Assert(size() == n, ExcDimensionMismatch(size(), n));
251  }
252 
253 
254 
255  void
257  const size_type local_size,
258  const IndexSet &ghostnodes)
259  {
260  (void)n;
261  Assert(local_size <= n, ExcIndexRange(local_size, 0, n));
262  ghosted = true;
263  ghost_indices = ghostnodes;
264 
265  std::vector<size_type> ghostindices;
266  ghostnodes.fill_index_vector(ghostindices);
267 
268  const PetscInt *ptr =
269  (ghostindices.size() > 0 ? (const PetscInt *)(&(ghostindices[0])) :
270  nullptr);
271 
272  PetscErrorCode ierr = VecCreateGhost(communicator,
273  local_size,
274  PETSC_DETERMINE,
275  ghostindices.size(),
276  ptr,
277  &vector);
278  AssertThrow(ierr == 0, ExcPETScError(ierr));
279 
280  Assert(size() == n, ExcDimensionMismatch(size(), n));
281 
282 # if DEBUG
283  {
284  // test ghost allocation in debug mode
285  PetscInt begin, end;
286 
287  ierr = VecGetOwnershipRange(vector, &begin, &end);
288  AssertThrow(ierr == 0, ExcPETScError(ierr));
289 
290  Assert(local_size == (size_type)(end - begin), ExcInternalError());
291 
292  Vec l;
293  ierr = VecGhostGetLocalForm(vector, &l);
294  AssertThrow(ierr == 0, ExcPETScError(ierr));
295 
296  PetscInt lsize;
297  ierr = VecGetSize(l, &lsize);
298  AssertThrow(ierr == 0, ExcPETScError(ierr));
299 
300  ierr = VecGhostRestoreLocalForm(vector, &l);
301  AssertThrow(ierr == 0, ExcPETScError(ierr));
302 
303  Assert(lsize == end - begin + (PetscInt)ghost_indices.n_elements(),
304  ExcInternalError());
305  }
306 # endif
307 
308 
309  // in PETSc versions up to 3.5, VecCreateGhost zeroed out the locally
310  // owned vector elements but forgot about the ghost elements. we need to
311  // do this ourselves
312  //
313  // see https://code.google.com/p/dealii/issues/detail?id=233
314 # if DEAL_II_PETSC_VERSION_LT(3, 6, 0)
316  zero.reinit(communicator, this->size(), local_size);
317  *this = zero;
318 # endif
319  }
320 
321 
322 
323  bool
325  {
326  unsigned int has_nonzero = VectorBase::all_zero() ? 0 : 1;
327 # ifdef DEAL_II_WITH_MPI
328  // in parallel, check that the vector
329  // is zero on _all_ processors.
330  unsigned int num_nonzero = Utilities::MPI::sum(has_nonzero, communicator);
331  return num_nonzero == 0;
332 # else
333  return has_nonzero == 0;
334 # endif
335  }
336 
337 
338  void
339  Vector::print(std::ostream & out,
340  const unsigned int precision,
341  const bool scientific,
342  const bool across) const
343  {
344  AssertThrow(out, ExcIO());
345 
346  // get a representation of the vector and
347  // loop over all the elements
348  PetscScalar *val;
349  PetscInt nlocal, istart, iend;
350 
351  PetscErrorCode ierr = VecGetArray(vector, &val);
352  AssertThrow(ierr == 0, ExcPETScError(ierr));
353 
354  ierr = VecGetLocalSize(vector, &nlocal);
355  AssertThrow(ierr == 0, ExcPETScError(ierr));
356 
357  ierr = VecGetOwnershipRange(vector, &istart, &iend);
358  AssertThrow(ierr == 0, ExcPETScError(ierr));
359 
360  // save the state of out stream
361  std::ios::fmtflags old_flags = out.flags();
362  unsigned int old_precision = out.precision(precision);
363 
364  out.precision(precision);
365  if (scientific)
366  out.setf(std::ios::scientific, std::ios::floatfield);
367  else
368  out.setf(std::ios::fixed, std::ios::floatfield);
369 
370  // let each processor produce its output in turn. this requires
371  // synchronizing output between processors using a barrier --
372  // which is clearly slow, but nobody is going to print a whole
373  // matrix this way on a regular basis for production runs, so
374  // the slowness of the barrier doesn't matter
375  for (unsigned int i = 0;
377  i++)
378  {
379  const int mpi_ierr = MPI_Barrier(communicator);
380  AssertThrowMPI(mpi_ierr);
381 
383  {
384  if (across)
385  {
386  out << "[Proc" << i << " " << istart << "-" << iend - 1 << "]"
387  << ' ';
388  for (PetscInt i = 0; i < nlocal; ++i)
389  out << val[i] << ' ';
390  }
391  else
392  {
393  out << "[Proc " << i << " " << istart << "-" << iend - 1
394  << "]" << std::endl;
395  for (PetscInt i = 0; i < nlocal; ++i)
396  out << val[i] << std::endl;
397  }
398  out << std::endl;
399  }
400  }
401  // reset output format
402  out.flags(old_flags);
403  out.precision(old_precision);
404 
405  // restore the representation of the
406  // vector
407  ierr = VecRestoreArray(vector, &val);
408  AssertThrow(ierr == 0, ExcPETScError(ierr));
409 
410  AssertThrow(out, ExcIO());
411  }
412 
413  } // namespace MPI
414 
415 } // namespace PETScWrappers
416 
417 DEAL_II_NAMESPACE_CLOSE
418 
419 #endif // DEAL_II_WITH_PETSC
static::ExceptionBase & ExcIO()
bool is_ascending_and_one_to_one(const MPI_Comm &communicator) const
Definition: index_set.cc:593
size_type n_elements() const
Definition: index_set.h:1743
bool has_ghost_elements() const
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
size_type size() const
Definition: index_set.h:1611
virtual void clear() override
static::ExceptionBase & ExcIndexRange(int arg1, int arg2, int arg3)
static::ExceptionBase & ExcMessage(std::string arg1)
T sum(const T &t, const MPI_Comm &mpi_communicator)
void subtract_set(const IndexSet &other)
Definition: index_set.cc:265
void fill_index_vector(std::vector< size_type > &indices) const
Definition: index_set.cc:503
VectorOperation::values last_action
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
types::global_dof_index size_type
Definition: petsc_vector.h:164
void print(std::ostream &out, const unsigned int precision=3, const bool scientific=true, const bool across=true) const
unsigned int n_mpi_processes(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:69
Vector & operator=(const Vector &v)
size_type local_size() const
#define AssertThrowMPI(error_code)
Definition: exceptions.h:1443
void reinit(const MPI_Comm &communicator, const size_type N, const size_type local_size, const bool omit_zeroing_entries=false)
virtual void create_vector(const size_type n, const size_type local_size)
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:80
static::ExceptionBase & ExcNotImplemented()
IndexSet locally_owned_elements() const
static::ExceptionBase & ExcInternalError()