OGS
PETScVector.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "PETScVector.h"
5
6#include <algorithm>
7#include <cassert>
8
9#include "BaseLib/Algorithm.h"
10#include "BaseLib/Error.h"
11#include "BaseLib/MPI.h"
12
13namespace MathLib
14{
15PETScVector::PETScVector(const PetscInt vec_size, const bool is_global_size)
16{
17 if (is_global_size)
18 {
19 PetscCallAbort(PETSC_COMM_WORLD, VecCreate(PETSC_COMM_WORLD, &v_));
20 PetscCallAbort(PETSC_COMM_WORLD,
21 VecSetSizes(v_, PETSC_DECIDE, vec_size));
22 }
23 else
24 {
25 // Fix size partitioning
26 // the size can be associated to specific memory allocation of a matrix
27 PetscCallAbort(
28 PETSC_COMM_WORLD,
29 VecCreateMPI(PETSC_COMM_WORLD, vec_size, PETSC_DECIDE, &v_));
30 }
31
32 config();
33}
34
35PETScVector::PETScVector(const PetscInt vec_size,
36 const std::vector<PetscInt>& ghost_ids,
37 const bool is_global_size)
38 : size_ghosts_{static_cast<PetscInt>(ghost_ids.size())},
40{
41 PetscInt nghosts = static_cast<PetscInt>(ghost_ids.size());
42 if (is_global_size)
43 {
44 PetscCallAbort(PETSC_COMM_WORLD,
45 VecCreateGhost(PETSC_COMM_WORLD, PETSC_DECIDE, vec_size,
46 nghosts, ghost_ids.data(), &v_));
47 }
48 else
49 {
50 PetscCallAbort(PETSC_COMM_WORLD, VecCreate(PETSC_COMM_WORLD, &v_));
51 PetscCallAbort(PETSC_COMM_WORLD, VecSetType(v_, VECMPI));
52 PetscCallAbort(PETSC_COMM_WORLD,
53 VecSetSizes(v_, vec_size, PETSC_DECIDE));
54 PetscCallAbort(PETSC_COMM_WORLD,
55 VecMPISetGhost(v_, nghosts, ghost_ids.data()));
56 }
57
58 config();
59
60 for (PetscInt i = 0; i < nghosts; i++)
61 {
62 global_ids2local_ids_ghost_.emplace(ghost_ids[i], size_loc_ + i);
63 }
64}
65
66PETScVector::PETScVector(const PETScVector& existing_vec, const bool deep_copy)
67{
68 shallowCopy(existing_vec);
69
70 // Copy values
71 if (deep_copy)
72 {
73 PetscCallAbort(PETSC_COMM_WORLD, VecCopy(existing_vec.v_, v_));
74 }
75}
76
89
91{
92 PetscCallAbort(PETSC_COMM_WORLD, VecSetFromOptions(v_));
93 PetscCallAbort(PETSC_COMM_WORLD,
94 VecGetOwnershipRange(v_, &start_rank_, &end_rank_));
95
96 PetscCallAbort(PETSC_COMM_WORLD, VecGetLocalSize(v_, &size_loc_));
97 PetscCallAbort(PETSC_COMM_WORLD, VecGetSize(v_, &size_));
98
99 PetscCallAbort(PETSC_COMM_WORLD,
100 VecSetOption(v_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE));
101}
102
104{
105 PetscCallAbort(PETSC_COMM_WORLD, VecAssemblyBegin(v_));
106 PetscCallAbort(PETSC_COMM_WORLD, VecAssemblyEnd(v_));
107}
108
109void PETScVector::getGlobalVector(std::vector<PetscScalar>& u) const
110{
111#ifdef TEST_MEM_PETSC
112 PetscLogDouble mem1, mem2;
113 PetscMemoryGetCurrentUsage(&mem1);
114#endif
115
116 assert(static_cast<PetscInt>(u.size()) == size_);
117
118 PetscInt state;
119 PetscCallAbort(PETSC_COMM_WORLD, VecLockGet(v_, &state));
120 if (state != 0)
121 {
122 OGS_FATAL("PETSc vector is already locked for {:s} access.",
123 state > 0 ? "read" : "write");
124 }
125 PetscScalar* xp = nullptr;
126 PetscCallAbort(PETSC_COMM_WORLD, VecGetArray(v_, &xp));
127
128 BaseLib::MPI::Mpi mpi{PETSC_COMM_WORLD};
129 BaseLib::MPI::allgatherv(std::span(xp, size_loc_), u, mpi);
130
131 // This following line may be needed late on
132 // for a communication load balance:
133 // MPI_Barrier(PETSC_COMM_WORLD);
134
135 PetscCallAbort(PETSC_COMM_WORLD, VecRestoreArray(v_, &xp));
136
137// TEST
138#ifdef TEST_MEM_PETSC
139 PetscMemoryGetCurrentUsage(&mem2);
140 PetscPrintf(
141 PETSC_COMM_WORLD,
142 "### Memory usage by Updating. Before :%f After:%f Increase:%d\n", mem1,
143 mem2, (int)(mem2 - mem1));
144#endif
145}
146
148{
150 {
152 return;
153 }
154
155 entry_array_.resize(size_);
157}
158
159void PETScVector::copyValues(std::vector<PetscScalar>& u) const
160{
161 u.resize(getLocalSize() + getGhostSize());
162
163 PetscScalar* loc_x = getLocalVector();
164 std::copy_n(loc_x, getLocalSize() + getGhostSize(), u.begin());
165 restoreArray(loc_x);
166}
167
168void PETScVector::copyValues(std::span<PetscScalar> u) const
169{
170 if (u.size() != static_cast<std::size_t>(getLocalSize() + getGhostSize()))
171 {
172 OGS_FATAL(
173 "PETScVector::copyValues() size mismatch. Trying to copy a vector "
174 "of size {:d} to a span of size {:d}.",
175 getLocalSize() + getGhostSize(), u.size());
176 }
177
178 PetscScalar* loc_x = getLocalVector();
179 std::copy_n(loc_x, getLocalSize() + getGhostSize(), u.begin());
180 restoreArray(loc_x);
181}
182
183PetscScalar PETScVector::get(const PetscInt idx) const
184{
186 {
187 return entry_array_[getLocalIndex(idx)];
188 }
189
190 return entry_array_[idx];
191}
192
193std::vector<PetscScalar> PETScVector::get(
194 std::vector<IndexType> const& indices) const
195{
196 std::vector<PetscScalar> local_x(indices.size());
197 std::transform(indices.begin(), indices.end(), local_x.begin(),
198 [this](IndexType index) { return get(index); });
199 return local_x;
200}
201
202PetscScalar* PETScVector::getLocalVector() const
203{
204 PetscScalar* loc_array;
206 {
207 PetscCallAbort(PETSC_COMM_WORLD,
208 VecGhostUpdateBegin(v_, INSERT_VALUES, SCATTER_FORWARD));
209 PetscCallAbort(PETSC_COMM_WORLD,
210 VecGhostUpdateEnd(v_, INSERT_VALUES, SCATTER_FORWARD));
211 PetscCallAbort(PETSC_COMM_WORLD, VecGhostGetLocalForm(v_, &v_loc_));
212 PetscCallAbort(PETSC_COMM_WORLD, VecGetArray(v_loc_, &loc_array));
213 }
214 else
215 {
216 PetscCallAbort(PETSC_COMM_WORLD, VecGetArray(v_, &loc_array));
217 }
218
219 return loc_array;
220}
221
222PetscInt PETScVector::getLocalIndex(const PetscInt global_index) const
223{
224 if (global_index >= 0) // non-ghost entry.
225 {
226#ifndef NDEBUG
227 if (global_index < start_rank_ || global_index >= end_rank_)
228 {
229 OGS_FATAL(
230 "The global index {:d} is out of the range `[`{:d}, {:d}`)` of "
231 "the current rank.",
232 global_index, start_rank_, end_rank_);
233 }
234#endif
235 return global_index - start_rank_;
236 }
237
238 // A special case for a ghost location with global index equal to
239 // the size of the local vector:
240 PetscInt real_global_index = (-global_index == size_) ? 0 : -global_index;
241
242#ifndef NDEBUG
243 if (global_ids2local_ids_ghost_.find(real_global_index) ==
246 {
247 OGS_FATAL("The global index {:d} is not found as a ghost ID",
248 global_index);
249 }
250#endif
251
252 return global_ids2local_ids_ghost_.at(real_global_index);
253}
254
255void PETScVector::restoreArray(PetscScalar* array) const
256{
258 {
259 PetscCallAbort(PETSC_COMM_WORLD, VecRestoreArray(v_loc_, &array));
260 PetscCallAbort(PETSC_COMM_WORLD, VecGhostRestoreLocalForm(v_, &v_loc_));
261 }
262 else
263 {
264 PetscCallAbort(PETSC_COMM_WORLD, VecRestoreArray(v_, &array));
265 }
266}
267
268void PETScVector::viewer(const std::string& file_name,
269 const PetscViewerFormat vw_format) const
270{
271 PetscViewer viewer;
272 PetscViewerASCIIOpen(PETSC_COMM_WORLD, file_name.c_str(), &viewer);
273 PetscViewerPushFormat(viewer, vw_format);
274
275 PetscObjectSetName((PetscObject)v_, file_name.c_str());
276 VecView(v_, viewer);
277
278#define nEXIT_TEST
279#ifdef EXIT_TEST
280 VecDestroy(v_);
281 PetscFinalize();
282 exit(0);
283#endif
284}
285
287{
288 destroy();
289
290 PetscCallAbort(PETSC_COMM_WORLD, VecDuplicate(v.getRawVector(), &v_));
291
292 start_rank_ = v.start_rank_;
293 end_rank_ = v.end_rank_;
294 size_ = v.size_;
295 size_loc_ = v.size_loc_;
296 size_ghosts_ = v.size_ghosts_;
297 created_with_ghost_id_ = v.created_with_ghost_id_;
298 global_ids2local_ids_ghost_ = v.global_ids2local_ids_ghost_;
299
300 config();
301}
302
307
308} // namespace MathLib
#define OGS_FATAL(...)
Definition Error.h:19
PetscInt start_rank_
Starting index in a rank.
void finalizeAssembly()
Perform MPI collection of assembled entries in buffer.
std::vector< PetscScalar > entry_array_
Array containing the entries of the vector. If the vector is created without given ghost IDs,...
void config()
A function called by constructors to configure members.
void setLocalAccessibleVector() const
void restoreArray(PetscScalar *array) const
PetscInt getLocalSize() const
Get the number of entries in the same rank.
Definition PETScVector.h:79
PetscInt size_loc_
Size of local entries.
bool created_with_ghost_id_
Flag to indicate whether the vector is created with ghost entry indices.
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.
void copyValues(std::vector< PetscScalar > &u) const
PetscInt size_
Size of the vector.
PetscInt size() const
Get the global size of the vector.
Definition PETScVector.h:77
void shallowCopy(const PETScVector &v)
PetscInt getGhostSize() const
Get the number of ghost entries in the same rank.
Definition PETScVector.h:81
std::map< PetscInt, PetscInt > global_ids2local_ids_ghost_
Map global indices of ghost entries to local indices.
PetscInt getLocalIndex(const PetscInt global_index) const
Get local index by a global index.
PetscInt end_rank_
Ending index in a rank.
void viewer(const std::string &file_name, const PetscViewerFormat vw_format=PETSC_VIEWER_ASCII_MATLAB) const
static std::vector< int > allgatherv(std::span< T > const send_buffer, std::vector< std::remove_const_t< T > > &receive_buffer, Mpi const &mpi)
Definition MPI.h:147
void finalizeVectorAssembly(VEC_T &)
General function to finalize the vector assembly.
static const double u
static const double v