AMDiS  0.3
The Adaptive Multi-Dimensional Simulation Toolbox
VectorBackend.hpp
1 #pragma once
2 
3 #include <petscvec.h>
4 
5 #include <dune/common/ftraits.hh>
6 #include <dune/common/rangeutilities.hh>
7 #include <dune/common/shared_ptr.hh>
8 #include <dune/functions/functionspacebases/flatmultiindex.hh>
9 
10 #include <amdis/Output.hpp>
11 #include <amdis/algorithm/ForEach.hpp>
12 #include <amdis/algorithm/InnerProduct.hpp>
13 #include <amdis/algorithm/Transform.hpp>
14 #include <amdis/common/FakeContainer.hpp>
15 #include <amdis/operations/Assigner.hpp>
16 #include <amdis/typetree/MultiIndex.hpp>
17 
18 namespace AMDiS
19 {
21  template <class DofMap>
23  {
24  template <class A>
25  using AssignMode = std::conditional_t<std::is_same_v<A,Assigner::plus_assign>,
26  std::integral_constant<::InsertMode, ADD_VALUES>,
27  std::integral_constant<::InsertMode, INSERT_VALUES>>;
28 
29  public:
31  using BaseVector = ::Vec;
32 
34  using value_type = PetscScalar;
35 
37  using size_type = PetscInt;
38 
39  public:
41  template <class Basis>
42  explicit PetscVector(Basis const& basis)
43  : dofMap_(basis.communicator().dofMap())
44  {}
45 
48  : dofMap_(other.dofMap_)
49  {
50  swap(*this, other);
51  }
52 
54  PetscVector(PetscVector const& other)
55  : dofMap_(other.dofMap_)
56  , initialized_(other.initialized_)
57  {
58  if (other.initialized_) {
59  VecDuplicate(other.vector_, &vector_);
60  VecCopy(other.vector_, vector_);
61  }
62  }
63 
66  {
67  destroy();
68  }
69 
72  {
73  swap(*this, other);
74  return *this;
75  }
76 
79  {
80  return *this = PetscVector(other);
81  }
82 
84  BaseVector const& vector() const
85  {
86  return vector_;
87  }
88 
91  {
92  return vector_;
93  }
94 
96  std::size_t localSize() const
97  {
98  return dofMap_.localSize();
99  }
100 
102  std::size_t globalSize() const
103  {
104  return dofMap_.globalSize();
105  }
106 
108  // [[possibly collective]]
109  template <class SizeInfo>
110  void init(SizeInfo const&, bool clear)
111  {
112  Dune::Timer t;
113  if (!initialized_) {
114  // create the vector
115  create();
116  info(3, " create new vector needed {} seconds", t.elapsed());
117  t.reset();
118  }
119  else {
120  PetscInt localSize = 0, globalSize = 0;
121  VecGetSize(vector_, &globalSize);
122  VecGetLocalSize(vector_, &localSize);
123 
124  // re-create the vector
125  if (std::size_t(localSize) != dofMap_.localSize() ||
126  std::size_t(globalSize) != dofMap_.globalSize()) {
127  destroy();
128  create();
129  info(3, " destroy old and create new vector needed {} seconds", t.elapsed());
130  t.reset();
131  }
132  }
133 
134  if (clear)
135  setZero();
136 
137  initialized_ = true;
138  }
139 
141  // [[collective]]
142  void finish()
143  {
144  Dune::Timer t;
145  VecAssemblyBegin(vector_);
146  VecAssemblyEnd(vector_);
147  info(3, " finish vector assembly needed {} seconds", t.elapsed());
148  }
149 
151  // [[collective]]
152  void synchronize()
153  {
154  Dune::Timer t;
155  VecGhostUpdateBegin(vector_, INSERT_VALUES, SCATTER_FORWARD);
156  VecGhostUpdateEnd(vector_, INSERT_VALUES, SCATTER_FORWARD);
157  info(3, " synchronize vector needed {} seconds", t.elapsed());
158  }
159 
161  // [[not collective]]
162  template <class MultiIndex>
163  PetscScalar at(MultiIndex const& idx) const
164  {
165  PetscScalar y = 0;
166  gather(std::array<MultiIndex,1>{idx}, &y);
167  return y;
168  }
169 
171  // [[not collective]]
172  template <class MultiIndex, class Assign>
173  void insert(MultiIndex const& dof, PetscScalar value, Assign)
174  {
175  assert(initialized_);
176  VecSetValue(vector_, dofMap_.global(flatMultiIndex(dof)), value, AssignMode<Assign>::value);
177  }
178 
180  // [[not collective]]
181  template <class IndexRange, class OutputIterator>
182  void gather(IndexRange const& localInd, OutputIterator buffer) const
183  {
184  forEach(localInd, [&buffer](auto&&, auto const& value) { *buffer = value; ++buffer; });
185  }
186 
188 
192  // [[not collective]]
193  template <class IndexRange, class LocalValues, class MaskRange, class Assign>
194  void scatter(IndexRange const& localInd, LocalValues const& localVal, MaskRange const& mask, Assign)
195  {
196  static_assert(std::is_same_v<typename LocalValues::value_type, PetscScalar>, "");
197  assert(initialized_);
198  assert(localInd.size() == localVal.size());
199 
200  // map local to global indices
201  std::vector<PetscInt> globalInd;
202  globalInd.reserve(localInd.size());
203 
204  auto ind_it = std::begin(localInd);
205  auto mask_it = std::begin(mask);
206  for (; ind_it != std::end(localInd); ++mask_it, ++ind_it)
207  globalInd.push_back(*mask_it ? dofMap_.global(flatMultiIndex(*ind_it)) : -1);
208 
209  if (!std::is_same_v<MaskRange, FakeContainer<bool,true>>)
210  VecSetOption(vector_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_TRUE);
211 
212  VecSetValues(vector_, globalInd.size(), globalInd.data(), localVal.data(), AssignMode<Assign>::value);
213  VecSetOption(vector_, VEC_IGNORE_NEGATIVE_INDICES, PETSC_FALSE);
214  }
215 
217  // [[not collective]]
218  template <class IndexRange, class Func>
219  void forEach(IndexRange const& localInd, Func&& f) const
220  {
221  // Obtains the local ghosted representation of a parallel vector
222  Vec localGhostedVec = nullptr;
223  VecGhostGetLocalForm(vector_, &localGhostedVec);
224  assert(localGhostedVec != nullptr);
225 
226  // A pointer to a contiguous array that contains this processor's portion of the vector data.
227  PetscScalar* ptr;
228  VecGetArray(localGhostedVec, &ptr);
229 
230  for (auto const& dof : localInd)
231  {
232  size_type i = flatMultiIndex(dof);
233  if (dofMap_.owner(i)) {
234  // the index is a purely local entry
235  f(dof, ptr[dofMap_.dofToLocal(i)]);
236  }
237  else {
238  // ghost entries are stored at the end of the array
239  f(dof, ptr[dofMap_.localSize() + dofMap_.dofToGhost(i)]);
240  }
241  }
242 
243  VecRestoreArray(localGhostedVec, &ptr);
244  VecGhostRestoreLocalForm(vector_, &localGhostedVec);
245  }
246 
248  // [[not collective]]
249  template <class Func>
250  void forEachLocal(Func&& f) const
251  {
252  // A pointer to a contiguous array that contains this processor's portion of the vector data.
253  PetscScalar const* ptr;
254  VecGetArrayRead(vector_, &ptr);
255 
256  for (size_type i = 0; i < localSize(); ++i)
257  f(ptr[dofMap_.dofToLocal(i)]);
258 
259  VecRestoreArrayRead(vector_, &ptr);
260  }
261 
263  // [[mutable]]
264  // [[not collective]]
265  template <class Func>
266  void forEachLocal(Func&& f)
267  {
268  // A pointer to a contiguous array that contains this processor's portion of the vector data.
269  PetscScalar *ptr;
270  VecGetArray(vector_, &ptr);
271 
272  for (size_type i = 0; i < localSize(); ++i)
273  f(ptr[dofMap_.dofToLocal(i)]);
274 
275  VecRestoreArray(vector_, &ptr);
276  }
277 
279  // [[not collective]]
280  template <class Operation, class... VecIns>
281  static void transformLocal(PetscVector& vecOut, Operation op, VecIns const&... vecIn)
282  {
283  PetscScalar *ptrOut;
284  std::array<PetscScalar const*,sizeof...(VecIns)> ptrsIn{};
285 
286  // Obtain ptrs to internal local arrays
287  VecGetArray(vecOut.vector_, &ptrOut);
288  Ranges::forIndices<sizeof...(VecIns)>([&](auto ii) {
289  VecGetArrayRead(std::get<ii>(std::tie(vecIn...)).vector_, &ptrsIn[ii]);
290  });
291 
292  for (size_type i = 0; i < vecOut.localSize(); ++i) {
293  auto idx = vecOut.dofMap_.dofToLocal(i);
294  Ranges::applyIndices<sizeof...(VecIns)>([&](auto... ii) {
295  ptrOut[idx] = op(ptrsIn[ii][idx]...);
296  });
297  }
298 
299  // Restore array obtained with VecGetArray[Read]()
300  VecRestoreArray(vecOut.vector_, &ptrOut);
301  Ranges::forIndices<sizeof...(VecIns)>([&](auto ii) {
302  VecRestoreArrayRead(std::get<ii>(std::tie(vecIn...)).vector_, &ptrsIn[ii]);
303  });
304  }
305 
307  // [[not collective]]
308  template <class T, class BinOp1, class BinOp2>
309  static T innerProductLocal(PetscVector const& in1, PetscVector const& in2, T init, BinOp1 op1, BinOp2 op2)
310  {
311  PetscScalar const* ptr1;
312  PetscScalar const* ptr2;
313 
314  // Obtain ptrs to internal local arrays
315  VecGetArrayRead(in1.vector_, &ptr1);
316  VecGetArrayRead(in2.vector_, &ptr2);
317 
318  for (size_type i = 0; i < in1.localSize(); ++i) {
319  auto idx = in1.dofMap_.dofToLocal(i);
320  init = op1(std::move(init), op2(ptr1[idx], ptr2[idx]));
321  }
322 
323  // Restore array obtained with VecGetArrayRead()
324  VecRestoreArrayRead(in1.vector_, &ptr1);
325  VecRestoreArrayRead(in2.vector_, &ptr2);
326 
327  return init;
328  }
329 
331  // [[not collective]]
332  void set(PetscScalar value)
333  {
334  Vec localGhostedVec = nullptr;
335  VecGhostGetLocalForm(vector_, &localGhostedVec);
336  assert(localGhostedVec != nullptr);
337 
338  VecSet(localGhostedVec, value);
339  VecGhostRestoreLocalForm(vector_, &localGhostedVec);
340  }
341 
343  // [[not collective]]
344  void setZero()
345  {
346  Vec localGhostedVec = nullptr;
347  VecGhostGetLocalForm(vector_, &localGhostedVec);
348  assert(localGhostedVec != nullptr);
349 
350  VecZeroEntries(localGhostedVec);
351  VecGhostRestoreLocalForm(vector_, &localGhostedVec);
352  }
353 
354  friend void swap(PetscVector& lhs, PetscVector& rhs)
355  {
356  assert(&lhs.dofMap_ == &rhs.dofMap_);
357  std::swap(lhs.vector_, rhs.vector_);
358  std::swap(lhs.initialized_, rhs.initialized_);
359  }
360 
361  private:
362  // An MPI Communicator or PETSC_COMM_SELF
363  MPI_Comm comm() const
364  {
365 #if HAVE_MPI
366  return Environment::comm();
367 #else
368  return PETSC_COMM_SELF;
369 #endif
370  }
371 
372  // Create a new Vector
373  void create()
374  {
375  VecCreateGhost(comm(),
376  dofMap_.localSize(), dofMap_.globalSize(), dofMap_.ghostSize(), dofMap_.ghostIndices().data(),
377  &vector_);
378  }
379 
380  // Destroy an old vector if created before
381  void destroy()
382  {
383  if (initialized_)
384  VecDestroy(&vector_);
385 
386  initialized_ = false;
387  }
388 
389  private:
390  // The local-to-global map
391  DofMap const& dofMap_;
392 
394  mutable Vec vector_ = nullptr;
395  bool initialized_ = false;
396  };
397 
398 
399  namespace Recursive
400  {
401  template <class DofMap>
402  struct ForEach<PetscVector<DofMap>>
403  {
404  template <class Vec, class UnaryFunction>
405  static void impl(Vec&& vec, UnaryFunction f)
406  {
407  vec.forEachLocal(f);
408  }
409  };
410 
411  template <class DofMap>
412  struct Transform<PetscVector<DofMap>>
413  {
414  template <class Operation, class... VecIns>
415  static void impl(PetscVector<DofMap>& vecOut, Operation op, VecIns const&... vecIn)
416  {
417  PetscVector<DofMap>::transformLocal(vecOut, op, vecIn...);
418  }
419  };
420 
421  template <class DofMap>
422  struct InnerProduct<PetscVector<DofMap>>
423  {
424  template <class T, class BinOp1, class BinOp2>
425  static T impl(PetscVector<DofMap> const& in1, PetscVector<DofMap> const& in2, T init, BinOp1 op1, BinOp2 op2)
426  {
427  return PetscVector<DofMap>::innerProductLocal(in1, in2, std::move(init), op1, op2);
428  }
429  };
430 
431  } // end namespace Recursive
432 } // end namespace AMDiS
void forEachLocal(Func &&f) const
Perform the f(value) on the local elements of this vector.
Definition: VectorBackend.hpp:250
constexpr bool MultiIndex
A multi-index type.
Definition: Concepts.hpp:150
BaseVector const & vector() const
Return the data-vector vector_.
Definition: VectorBackend.hpp:84
PetscVector(PetscVector &&other)
Move constructor.
Definition: VectorBackend.hpp:47
BaseVector & vector()
Return the data-vector vector_.
Definition: VectorBackend.hpp:90
PetscVector(PetscVector const &other)
Copy constructor.
Definition: VectorBackend.hpp:54
~PetscVector()
Destructor.
Definition: VectorBackend.hpp:65
void forEachLocal(Func &&f)
Perform the f(value) on the local elements of this vector.
Definition: VectorBackend.hpp:266
std::size_t globalSize() const
Return the number of entries in the global vector.
Definition: VectorBackend.hpp:102
void forEach(IndexRange const &localInd, Func &&f) const
Apply the functor f to each vector entry to local index in localInd range.
Definition: VectorBackend.hpp:219
PetscScalar value_type
The type of the elements of the DOFVector.
Definition: VectorBackend.hpp:34
void insert(MultiIndex const &dof, PetscScalar value, Assign)
Access the entry i of the vector with write-access.
Definition: VectorBackend.hpp:173
Definition: AdaptBase.hpp:6
PetscVector & operator=(PetscVector &&other)
Move assignment operator.
Definition: VectorBackend.hpp:71
static void transformLocal(PetscVector &vecOut, Operation op, VecIns const &... vecIn)
Perform the valueOut = op(valueIn...) on the local elements of [vecOut] and [vecIn...].
Definition: VectorBackend.hpp:281
PetscVector & operator=(PetscVector const &other)
Copy assignment operator.
Definition: VectorBackend.hpp:78
void init(SizeInfo const &, bool clear)
Resize the vector_ to the size s.
Definition: VectorBackend.hpp:110
void setZero()
Zero all entries, including the ghost entries.
Definition: VectorBackend.hpp:344
void scatter(IndexRange const &localInd, LocalValues const &localVal, MaskRange const &mask, Assign)
Store all values given by localVal with indices localInd in the vector.
Definition: VectorBackend.hpp:194
std::size_t localSize() const
Return the number of entries in the local part of the vector.
Definition: VectorBackend.hpp:96
void gather(IndexRange const &localInd, OutputIterator buffer) const
Collect all values from this vector to indices given by localInd and store it into the output buffer...
Definition: VectorBackend.hpp:182
A container-like data-structure not storing anything and with empty implementations in many container...
Definition: FakeContainer.hpp:34
PetscVector(Basis const &basis)
Constructor. Constructs new BaseVector.
Definition: VectorBackend.hpp:42
PetscInt size_type
The index/size - type.
Definition: VectorBackend.hpp:37
static T innerProductLocal(PetscVector const &in1, PetscVector const &in2, T init, BinOp1 op1, BinOp2 op2)
Perform the op1(init, op2(value1, value2)) on the local elements of [in1] and [in2].
Definition: VectorBackend.hpp:309
void synchronize()
Update the ghost regions with values from the owning process.
Definition: VectorBackend.hpp:152
::Vec BaseVector
The type of the base vector.
Definition: VectorBackend.hpp:31
void finish()
Finish assembly. Must be called before vector can be used in a KSP.
Definition: VectorBackend.hpp:142
PetscScalar at(MultiIndex const &idx) const
Access the entry i of the vector with read-only-access.
Definition: VectorBackend.hpp:163
The basic container that stores a base vector data.
Definition: VectorBackend.hpp:22
static Dune::MPIHelper::MPICommunicator comm()
Return the MPI_Comm object (or a fake communicator)
Definition: Environment.hpp:86