OGS
PETScVector.cpp
Go to the documentation of this file.
1 
21 #include "PETScVector.h"
22 
23 #include <algorithm>
24 #include <cassert>
25 
26 #include "BaseLib/Error.h"
27 
28 namespace MathLib
29 {
30 PETScVector::PETScVector(const PetscInt vec_size, const bool is_global_size)
31 {
32  if (is_global_size)
33  {
34  VecCreate(PETSC_COMM_WORLD, &v_);
35  VecSetSizes(v_, PETSC_DECIDE, vec_size);
36  }
37  else
38  {
39  // Fix size partitioning
40  // the size can be associated to specific memory allocation of a matrix
41  VecCreateMPI(PETSC_COMM_WORLD, vec_size, PETSC_DECIDE, &v_);
42  }
43 
44  config();
45 }
46 
47 PETScVector::PETScVector(const PetscInt vec_size,
48  const std::vector<PetscInt>& ghost_ids,
49  const bool is_global_size)
50  : size_ghosts_{static_cast<PetscInt>(ghost_ids.size())}, has_ghost_id_{true}
51 {
52  PetscInt nghosts = static_cast<PetscInt>(ghost_ids.size());
53  if (is_global_size)
54  {
55  VecCreateGhost(PETSC_COMM_WORLD, PETSC_DECIDE, vec_size, nghosts,
56  ghost_ids.data(), &v_);
57  }
58  else
59  {
60  VecCreate(PETSC_COMM_WORLD, &v_);
61  VecSetType(v_, VECMPI);
62  VecSetSizes(v_, vec_size, PETSC_DECIDE);
63  VecMPISetGhost(v_, nghosts, ghost_ids.data());
64  }
65 
66  config();
67 
68  for (PetscInt i = 0; i < nghosts; i++)
69  global_ids2local_ids_ghost_.emplace(ghost_ids[i], size_loc_ + i);
70 }
71 
72 PETScVector::PETScVector(const PETScVector& existing_vec, const bool deep_copy)
73 {
74  shallowCopy(existing_vec);
75 
76  // Copy values
77  if (deep_copy)
78  {
79  VecCopy(existing_vec.v_, v_);
80  }
81 }
82 
84  : v_{std::move(other.v_)},
85  v_loc_{std::move(other.v_loc_)},
86  start_rank_{other.start_rank_},
87  end_rank_{other.end_rank_},
88  size_{other.size_},
89  size_loc_{other.size_loc_},
90  size_ghosts_{other.size_ghosts_},
91  has_ghost_id_{other.has_ghost_id_},
92  global_ids2local_ids_ghost_{other.global_ids2local_ids_ghost_}
93 {
94 }
95 
97 {
98  VecSetFromOptions(v_);
99  VecGetOwnershipRange(v_, &start_rank_, &end_rank_);
100 
101  VecGetLocalSize(v_, &size_loc_);
102  VecGetSize(v_, &size_);
103 
104  VecSetOption(v_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
105 }
106 
108 {
109  VecAssemblyBegin(v_);
110  VecAssemblyEnd(v_);
111 }
112 
113 void PETScVector::gatherLocalVectors(PetscScalar local_array[],
114  PetscScalar global_array[]) const
115 {
116  // Collect vectors from processors.
117  int size_rank;
118  MPI_Comm_size(PETSC_COMM_WORLD, &size_rank);
119 
120  // number of elements to be sent for each rank
121  std::vector<PetscInt> i_cnt(size_rank);
122 
123  MPI_Allgather(&size_loc_, 1, MPI_INT, &i_cnt[0], 1, MPI_INT,
124  PETSC_COMM_WORLD);
125 
126  // collect local array
127  PetscInt offset = 0;
128  // offset in the receive vector of the data from each rank
129  std::vector<PetscInt> i_disp(size_rank);
130  for (PetscInt i = 0; i < size_rank; i++)
131  {
132  i_disp[i] = offset;
133  offset += i_cnt[i];
134  }
135 
136  MPI_Allgatherv(local_array, size_loc_, MPI_DOUBLE, global_array, &i_cnt[0],
137  &i_disp[0], MPI_DOUBLE, PETSC_COMM_WORLD);
138 }
139 
140 void PETScVector::getGlobalVector(std::vector<PetscScalar>& u) const
141 {
142 #ifdef TEST_MEM_PETSC
143  PetscLogDouble mem1, mem2;
144  PetscMemoryGetCurrentUsage(&mem1);
145 #endif
146 
147  assert(static_cast<PetscInt>(u.size()) == size_);
148 
149  PetscInt state;
150  VecLockGet(v_, &state);
151  if (state != 0)
152  {
153  OGS_FATAL("PETSc vector is already locked for {:s} access.",
154  state > 0 ? "read" : "write");
155  }
156  PetscScalar* xp = nullptr;
157  VecGetArray(v_, &xp);
158 
159  gatherLocalVectors(xp, u.data());
160 
161  // This following line may be needed late on
162  // for a communication load balance:
163  // MPI_Barrier(PETSC_COMM_WORLD);
164 
165  VecRestoreArray(v_, &xp);
166 
167 // TEST
168 #ifdef TEST_MEM_PETSC
169  PetscMemoryGetCurrentUsage(&mem2);
170  PetscPrintf(
171  PETSC_COMM_WORLD,
172  "### Memory usage by Updating. Before :%f After:%f Increase:%d\n", mem1,
173  mem2, (int)(mem2 - mem1));
174 #endif
175 }
176 
178 {
179  if (entry_array_.empty())
180  {
181  const PetscInt array_size = global_ids2local_ids_ghost_.empty()
182  ? size_
184  entry_array_.resize(array_size);
185  }
186 
187  if (!global_ids2local_ids_ghost_.empty())
188  {
189  PetscScalar* loc_x = getLocalVector();
190  std::copy_n(loc_x, size_loc_ + size_ghosts_, entry_array_.begin());
191  restoreArray(loc_x);
192  }
193  else
195 }
196 
197 void PETScVector::copyValues(std::vector<PetscScalar>& u) const
198 {
199  assert(u.size() == (std::size_t)(getLocalSize() + getGhostSize()));
200 
201  PetscScalar* loc_x = getLocalVector();
202  std::copy_n(loc_x, getLocalSize() + getGhostSize(), u.begin());
203  restoreArray(loc_x);
204 }
205 
206 PetscScalar PETScVector::get(const PetscInt idx) const
207 {
208  if (!global_ids2local_ids_ghost_.empty())
209  {
210  return entry_array_[getLocalIndex(idx)];
211  }
212 
213  // Ghost entries, and its original index is 0.
214  const PetscInt id_p = (idx == -size_) ? 0 : std::abs(idx);
215  return entry_array_[id_p];
216 }
217 
218 std::vector<PetscScalar> PETScVector::get(
219  std::vector<IndexType> const& indices) const
220 {
221  std::vector<PetscScalar> local_x(indices.size());
222  // If VecGetValues can get values from different processors,
223  // use VecGetValues(v_, indices.size(), indices.data(),
224  // local_x.data());
225 
226  if (!global_ids2local_ids_ghost_.empty())
227  {
228  for (std::size_t i = 0; i < indices.size(); i++)
229  {
230  local_x[i] = entry_array_[getLocalIndex(indices[i])];
231  }
232  }
233  else
234  {
235  for (std::size_t i = 0; i < indices.size(); i++)
236  {
237  // Ghost entries, and its original index is 0.
238  const IndexType id_p =
239  (indices[i] == -size_) ? 0 : std::abs(indices[i]);
240  local_x[i] = entry_array_[id_p];
241  }
242  }
243 
244  return local_x;
245 }
246 
247 PetscScalar* PETScVector::getLocalVector() const
248 {
249  PetscScalar* loc_array;
250  if (has_ghost_id_)
251  {
252  VecGhostUpdateBegin(v_, INSERT_VALUES, SCATTER_FORWARD);
253  VecGhostUpdateEnd(v_, INSERT_VALUES, SCATTER_FORWARD);
254  VecGhostGetLocalForm(v_, &v_loc_);
255  VecGetArray(v_loc_, &loc_array);
256  }
257  else
258  VecGetArray(v_, &loc_array);
259  return loc_array;
260 }
261 
262 PetscInt PETScVector::getLocalIndex(const PetscInt global_index) const
263 {
264  if (global_index >= 0) // non-ghost entry.
265  return global_index - start_rank_;
266 
267  // A special case for a ghost location with global index equal to
268  // the size of the local vector:
269  PetscInt real_global_index = (-global_index == size_) ? 0 : -global_index;
270 
271  return global_ids2local_ids_ghost_.at(real_global_index);
272 }
273 
274 void PETScVector::restoreArray(PetscScalar* array) const
275 {
276  if (has_ghost_id_)
277  {
278  VecRestoreArray(v_loc_, &array);
279  VecGhostRestoreLocalForm(v_, &v_loc_);
280  }
281  else
282  VecRestoreArray(v_, &array);
283 }
284 
285 void PETScVector::viewer(const std::string& file_name,
286  const PetscViewerFormat vw_format) const
287 {
288  PetscViewer viewer;
289  PetscViewerASCIIOpen(PETSC_COMM_WORLD, file_name.c_str(), &viewer);
290  PetscViewerPushFormat(viewer, vw_format);
291 
292  PetscObjectSetName((PetscObject)v_, file_name.c_str());
293  VecView(v_, viewer);
294 
295 #define nEXIT_TEST
296 #ifdef EXIT_TEST
297  VecDestroy(v_);
298  PetscFinalize();
299  exit(0);
300 #endif
301 }
302 
304 {
305  destroy();
306 
307  VecDuplicate(v.getRawVector(), &v_);
308 
310  end_rank_ = v.end_rank_;
311  size_ = v.size_;
312  size_loc_ = v.size_loc_;
316 
317  VecSetOption(v_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
318 }
319 
321 {
322  vec.finalizeAssembly();
323 }
324 
325 } // namespace MathLib
#define OGS_FATAL(...)
Definition: Error.h:26
Declaration of class PETScVector, which provides an interface to PETSc vector routines.
Wrapper class for PETSc vector.
Definition: PETScVector.h:33
PetscInt start_rank_
Starting index in a rank.
Definition: PETScVector.h:234
void finalizeAssembly()
Perform MPI collection of assembled entries in buffer.
void gatherLocalVectors(PetscScalar local_array[], PetscScalar global_array[]) const
Collect local vectors.
std::vector< PetscScalar > entry_array_
Array containing the entries of the vector. If the vector is created without given ghost IDs,...
Definition: PETScVector.h:255
void config()
A function called by constructors to configure members.
Definition: PETScVector.cpp:96
void setLocalAccessibleVector() const
void restoreArray(PetscScalar *array) const
PetscInt getLocalSize() const
Get the number of entries in the same rank.
Definition: PETScVector.h:84
bool has_ghost_id_
Flag to indicate whether the vector is created with ghost entry indices.
Definition: PETScVector.h:246
PetscInt size_loc_
Size of local entries.
Definition: PETScVector.h:241
PetscScalar * getLocalVector() const
void getGlobalVector(std::vector< PetscScalar > &u) const
std::vector< PetscScalar > get(std::vector< IndexType > const &indices) const
PetscInt size_ghosts_
Size of local ghost entries.
Definition: PETScVector.h:243
void copyValues(std::vector< PetscScalar > &u) const
PetscInt size_
Size of the vector.
Definition: PETScVector.h:239
void shallowCopy(const PETScVector &v)
PetscInt getGhostSize() const
Get the number of ghost entries in the same rank.
Definition: PETScVector.h:86
std::map< PetscInt, PetscInt > global_ids2local_ids_ghost_
Map global indices of ghost entries to local indices.
Definition: PETScVector.h:258
PetscInt getLocalIndex(const PetscInt global_index) const
Get local index by a global index.
PetscInt end_rank_
Ending index in a rank.
Definition: PETScVector.h:236
void viewer(const std::string &file_name, const PetscViewerFormat vw_format=PETSC_VIEWER_ASCII_MATLAB) const
PETSc_Vec & getRawVector()
Exposes the underlying PETSc vector.
Definition: PETScVector.h:171
void finalizeVectorAssembly(VEC_T &)
General function to finalize the vector assembly.