ThunderEgg  1.0.0
Vector.h
Go to the documentation of this file.
1 /***************************************************************************
2  * ThunderEgg, a library for solvers on adaptively refined block-structured
3  * Cartesian grids.
4  *
5  * Copyright (c) 2019-2021 Scott Aiton
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  ***************************************************************************/
20 
21 #ifndef THUNDEREGG_VECTOR_H
22 #define THUNDEREGG_VECTOR_H
23 
28 #include <ThunderEgg/Domain.h>
29 #include <ThunderEgg/Face.h>
30 #include <ThunderEgg/Loops.h>
31 #include <ThunderEgg/PatchView.h>
32 #include <cmath>
33 #include <mpi.h>
34 #include <utility>
35 namespace ThunderEgg {
41 template<int D>
42 class Vector
43 {
44 private:
48  Communicator comm;
49 
53  std::vector<double*> patch_starts;
54 
58  std::array<int, D + 1> strides;
62  std::array<int, D + 1> lengths;
63 
67  int num_ghost_cells = 0;
68 
72  std::vector<double> data;
73 
78  int num_local_cells = 0;
79 
83  void determineStrides()
84  {
85  int curr_stride = 1;
86  for (int i = 0; i < D; i++) {
87  strides[i] = curr_stride;
88  curr_stride *= lengths[i] + 2 * num_ghost_cells;
89  }
90  strides[D] = curr_stride;
91  }
92 
98  void allocateData(int num_local_patches)
99  {
100  int patch_stride = strides[D] * lengths[D];
101  data.resize(patch_stride * num_local_patches);
102  patch_starts.resize(num_local_patches);
103  for (int i = 0; i < num_local_patches; i++) {
104  patch_starts[i] = data.data() + i * patch_stride;
105  }
106  }
107 
108 public:
113  {
114  strides.fill(0);
115  lengths.fill(0);
116  }
126  const std::array<int, D>& ns,
127  int num_components,
128  int num_local_patches,
129  int num_ghost_cells)
130  : comm(comm)
131  , num_ghost_cells(num_ghost_cells)
132  {
133  for (int i = 0; i < D; i++) {
134  lengths[i] = ns[i];
135  }
136  lengths[D] = num_components;
137  int size = 1;
138  num_local_cells = 1;
139  for (int i = 0; i < D; i++) {
140  strides[i] = size;
141  size *= lengths[i] + 2 * num_ghost_cells;
142  num_local_cells *= lengths[i];
143  }
144  strides[D] = size;
145  size *= lengths[D];
146  int patch_stride = size;
147  size *= num_local_patches;
148  num_local_cells *= num_local_patches;
149  data.resize(size);
150  patch_starts.resize(num_local_patches);
151  for (int i = 0; i < num_local_patches; i++) {
152  patch_starts[i] = data.data() + i * patch_stride;
153  }
154  }
161  Vector(const Domain<D>& domain, int num_components)
162  : comm(domain.getCommunicator())
163  , num_ghost_cells(domain.getNumGhostCells())
164  , num_local_cells(domain.getNumLocalCells())
165  {
166  const std::array<int, D>& ns = domain.getNs();
167  int num_local_patches = domain.getNumLocalPatches();
168  for (int i = 0; i < D; i++) {
169  lengths[i] = ns[i];
170  }
171  lengths[D] = num_components;
172  int size = 1;
173  num_local_cells = 1;
174  for (int i = 0; i < D; i++) {
175  strides[i] = size;
176  size *= lengths[i] + 2 * num_ghost_cells;
177  num_local_cells *= lengths[i];
178  }
179  strides[D] = size;
180  size *= lengths[D];
181  int patch_stride = size;
182  size *= num_local_patches;
183  num_local_cells *= num_local_patches;
184  data.resize(size);
185  patch_starts.resize(num_local_patches);
186  for (int i = 0; i < num_local_patches; i++) {
187  patch_starts[i] = data.data() + i * patch_stride;
188  }
189  }
200  const std::vector<double*>& patch_starts,
201  const std::array<int, D + 1>& strides,
202  const std::array<int, D + 1>& lengths,
203  int num_ghost_cells)
204  : comm(comm)
205  , patch_starts(patch_starts)
206  , strides(strides)
207  , lengths(lengths)
208  , num_ghost_cells(num_ghost_cells)
209  {
210  num_local_cells = 1;
211  for (int i = 0; i < D; i++) {
212  num_local_cells *= lengths[i];
213  }
214  num_local_cells *= patch_starts.size();
215  }
223  Vector(const Vector<D>& other)
224  : comm(other.comm)
225  , lengths(other.lengths)
226  , num_ghost_cells(other.num_ghost_cells)
227  , num_local_cells(other.num_local_cells)
228  {
229  if (other.data.empty()) {
230  determineStrides();
231  allocateData(other.getNumLocalPatches());
232  copyWithGhost(other);
233  } else {
234  strides = other.strides;
235  data = other.data;
236  int patch_stride = data.size() / other.getNumLocalPatches();
237  patch_starts.resize(other.patch_starts.size());
238  for (int i = 0; i < patch_starts.size(); i++) {
239  patch_starts[i] = data.data() + i * patch_stride;
240  }
241  }
242  }
252  {
253  comm = other.comm;
254  lengths = other.lengths;
255  num_ghost_cells = other.num_ghost_cells;
256  num_local_cells = other.num_local_cells;
257  if (other.data.empty()) {
258  determineStrides();
259  allocateData(other.getNumLocalPatches());
260  copyWithGhost(other);
261  } else {
262  strides = other.strides;
263  data = other.data;
264  int patch_stride = data.size() / other.getNumLocalPatches();
265  patch_starts.resize(other.patch_starts.size());
266  for (int i = 0; i < patch_starts.size(); i++) {
267  patch_starts[i] = data.data() + i * patch_stride;
268  }
269  }
270  return *this;
271  }
277  Vector(Vector<D>&& other)
278  : comm(std::exchange(other.comm, Communicator()))
279  , patch_starts(std::exchange(other.patch_starts, std::vector<double*>()))
280  , num_ghost_cells(std::exchange(other.num_ghost_cells, 0))
281  , data(std::exchange(other.data, std::vector<double>()))
282  , num_local_cells(std::exchange(other.num_local_cells, 0))
283  {
284  lengths.fill(0);
285  std::swap(lengths, other.lengths);
286  strides.fill(0);
287  std::swap(strides, other.strides);
288  }
296  {
297  std::swap(comm, other.comm);
298  std::swap(lengths, other.lengths);
299  std::swap(num_ghost_cells, other.num_ghost_cells);
300  std::swap(num_local_cells, other.num_local_cells);
301  std::swap(strides, other.strides);
302  std::swap(data, other.data);
303  std::swap(patch_starts, other.patch_starts);
304  return *this;
305  }
311  const Communicator& getCommunicator() const { return comm; }
312  int getNumComponents() const { return lengths[D]; }
316  int getNumLocalPatches() const { return patch_starts.size(); }
322  int getNumLocalCells() const { return num_local_cells; }
328  int getNumGhostCells() const { return num_ghost_cells; }
336  ComponentView<double, D> getComponentView(int component_index, int patch_local_index)
337  {
338  return getPatchView(patch_local_index).getComponentView(component_index);
339  }
347  ComponentView<const double, D> getComponentView(int component_index, int patch_local_index) const
348  {
349  return getPatchView(patch_local_index).getComponentView(component_index);
350  }
358  PatchView<double, D> getPatchView(int patch_local_index)
359  {
360  if constexpr (ENABLE_DEBUG) {
361  if (patch_local_index < 0 || patch_local_index >= getNumLocalPatches()) {
362  throw RuntimeError("invalid patch index");
363  }
364  }
365  return PatchView<double, D>(patch_starts[patch_local_index], strides, lengths, num_ghost_cells);
366  }
367 
375  PatchView<const double, D> getPatchView(int patch_local_index) const
376  {
377  if constexpr (ENABLE_DEBUG) {
378  if (patch_local_index < 0 || patch_local_index >= getNumLocalPatches()) {
379  throw RuntimeError("invalid patch index");
380  }
381  }
383  patch_starts[patch_local_index], strides, lengths, num_ghost_cells);
384  }
385 
391  void set(double alpha)
392  {
393  for (int i = 0; i < getNumLocalPatches(); i++) {
395  Loop::OverInteriorIndexes<D + 1>(
396  view, [&](const std::array<int, D + 1>& coord) { view[coord] = alpha; });
397  }
398  }
404  void setWithGhost(double alpha)
405  {
406  for (int i = 0; i < getNumLocalPatches(); i++) {
408  Loop::OverAllIndexes<D + 1>(
409  view, [&](const std::array<int, D + 1>& coord) { view[coord] = alpha; });
410  }
411  }
417  void scale(double alpha)
418  {
419  for (int i = 0; i < getNumLocalPatches(); i++) {
421  Loop::OverInteriorIndexes<D + 1>(
422  view, [&](const std::array<int, D + 1>& coord) { view[coord] *= alpha; });
423  }
424  }
430  void shift(double delta)
431  {
432  for (int i = 0; i < getNumLocalPatches(); i++) {
434  Loop::OverInteriorIndexes<D + 1>(
435  view, [&](const std::array<int, D + 1>& coord) { view[coord] += delta; });
436  }
437  }
443  void copy(const Vector<D>& b)
444  {
445  for (int i = 0; i < getNumLocalPatches(); i++) {
448  Loop::OverInteriorIndexes<D + 1>(
449  view, [&](const std::array<int, D + 1>& coord) { view[coord] = b_view[coord]; });
450  }
451  }
457  void copyWithGhost(const Vector<D>& b)
458  {
459  for (int i = 0; i < getNumLocalPatches(); i++) {
462  Loop::OverAllIndexes<D + 1>(
463  view, [&](const std::array<int, D + 1>& coord) { view[coord] = b_view[coord]; });
464  }
465  }
471  void add(const Vector<D>& b)
472  {
473  for (int i = 0; i < getNumLocalPatches(); i++) {
476  Loop::OverInteriorIndexes<D + 1>(
477  view, [&](const std::array<int, D + 1>& coord) { view[coord] += b_view[coord]; });
478  }
479  }
483  void addScaled(double alpha, const Vector<D>& b)
484  {
485  for (int i = 0; i < getNumLocalPatches(); i++) {
488  Loop::OverInteriorIndexes<D + 1>(
489  view, [&](const std::array<int, D + 1>& coord) { view[coord] += b_view[coord] * alpha; });
490  }
491  }
495  void addScaled(double alpha, const Vector<D>& a, double beta, const Vector<D>& b)
496  {
497  for (int i = 0; i < getNumLocalPatches(); i++) {
501  Loop::OverInteriorIndexes<D + 1>(view, [&](const std::array<int, D + 1>& coord) {
502  view[coord] += a_view[coord] * alpha + b_view[coord] * beta;
503  });
504  }
505  }
509  void scaleThenAdd(double alpha, const Vector<D>& b)
510  {
511  for (int i = 0; i < getNumLocalPatches(); i++) {
514  Loop::OverInteriorIndexes<D + 1>(view, [&](const std::array<int, D + 1>& coord) {
515  view[coord] = view[coord] * alpha + b_view[coord];
516  });
517  }
518  }
522  void scaleThenAddScaled(double alpha, double beta, const Vector<D>& b)
523  {
524  for (int i = 0; i < getNumLocalPatches(); i++) {
527  Loop::OverInteriorIndexes<D + 1>(view, [&](const std::array<int, D + 1>& coord) {
528  view[coord] = view[coord] * alpha + b_view[coord] * beta;
529  });
530  }
531  }
535  void scaleThenAddScaled(double alpha,
536  double beta,
537  const Vector<D>& b,
538  double gamma,
539  const Vector<D>& c)
540  {
541  for (int i = 0; i < getNumLocalPatches(); i++) {
545  Loop::OverInteriorIndexes<D + 1>(view, [&](const std::array<int, D + 1>& coord) {
546  view[coord] = view[coord] * alpha + b_view[coord] * beta + c_view[coord] * gamma;
547  });
548  }
549  }
553  double twoNorm() const
554  {
555  double sum = 0;
556  for (int i = 0; i < getNumLocalPatches(); i++) {
558  Loop::OverInteriorIndexes<D + 1>(
559  view, [&](const std::array<int, D + 1>& coord) { sum += view[coord] * view[coord]; });
560  }
561  double global_sum;
562  MPI_Allreduce(&sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, comm.getMPIComm());
563  return sqrt(global_sum);
564  }
568  double infNorm() const
569  {
570  double max = 0;
571  for (int i = 0; i < getNumLocalPatches(); i++) {
573  Loop::OverInteriorIndexes<D + 1>(
574  view, [&](const std::array<int, D + 1>& coord) { max = fmax(view[coord], max); });
575  }
576  double global_max;
577  MPI_Allreduce(&max, &global_max, 1, MPI_DOUBLE, MPI_MAX, comm.getMPIComm());
578  return global_max;
579  }
583  double dot(const Vector<D>& b) const
584  {
585  double retval = 0;
586  for (int i = 0; i < getNumLocalPatches(); i++) {
589  Loop::OverInteriorIndexes<D + 1>(
590  view, [&](const std::array<int, D + 1>& coord) { retval += view[coord] * b_view[coord]; });
591  }
592  double global_retval;
593  MPI_Allreduce(&retval, &global_retval, 1, MPI_DOUBLE, MPI_SUM, comm.getMPIComm());
594  return global_retval;
595  }
602  {
603  Vector<D> clone;
604  clone.comm = comm;
605  clone.lengths = lengths;
606  clone.num_ghost_cells = num_ghost_cells;
607  clone.num_local_cells = num_local_cells;
608  clone.determineStrides();
609  clone.allocateData(getNumLocalPatches());
610  return clone;
611  }
612 };
613 extern template class Vector<1>;
614 extern template class Vector<2>;
615 extern template class Vector<3>;
616 } // namespace ThunderEgg
617 #endif
ThunderEgg::Vector::getComponentView
ComponentView< double, D > getComponentView(int component_index, int patch_local_index)
Get the ComponentView for the specified patch and component.
Definition: Vector.h:336
ThunderEgg::Vector::scaleThenAddScaled
void scaleThenAddScaled(double alpha, double beta, const Vector< D > &b, double gamma, const Vector< D > &c)
this = alpha * this + beta * b + gamma * c
Definition: Vector.h:535
ThunderEgg::Vector::scaleThenAdd
void scaleThenAdd(double alpha, const Vector< D > &b)
this = alpha * this + b
Definition: Vector.h:509
ThunderEgg::Vector::Vector
Vector()
Construct a new Vector object of size 0.
Definition: Vector.h:112
ThunderEgg::Vector::Vector
Vector(const Domain< D > &domain, int num_components)
Construct a new Vector object for a given domain.
Definition: Vector.h:161
ThunderEgg::Vector::scale
void scale(double alpha)
scale all elements in the vector
Definition: Vector.h:417
ThunderEgg::Vector::Vector
Vector(Communicator comm, const std::array< int, D > &ns, int num_components, int num_local_patches, int num_ghost_cells)
Construct a new Vector object with managed memory.
Definition: Vector.h:125
ThunderEgg::Vector::Vector
Vector(Vector< D > &&other)
Move constructor.
Definition: Vector.h:277
ThunderEgg::Vector::getComponentView
ComponentView< const double, D > getComponentView(int component_index, int patch_local_index) const
Get the ComponentView for the specified patch and component.
Definition: Vector.h:347
ThunderEgg::Communicator::getMPIComm
MPI_Comm getMPIComm() const
Get the raw MPI_Comm object.
Face.h
Face class.
ThunderEgg::Vector::operator=
Vector< D > & operator=(Vector< D > &&other)
Move assignment.
Definition: Vector.h:295
ThunderEgg::Domain::getNs
const std::array< int, D > & getNs() const
Get the number of cells in each direction.
Definition: Domain.h:264
ThunderEgg::Vector::getCommunicator
const Communicator & getCommunicator() const
get the MPI Comm that this vector uses
Definition: Vector.h:311
ThunderEgg::ComponentView< double, D >
ThunderEgg::Domain
Uses a collection of PatchInfo objects to represent the domain of the problem.
Definition: Domain.h:50
ThunderEgg::Vector::copyWithGhost
void copyWithGhost(const Vector< D > &b)
copy the values of the other vector include ghost cell values
Definition: Vector.h:457
ThunderEgg::Vector::scaleThenAddScaled
void scaleThenAddScaled(double alpha, double beta, const Vector< D > &b)
this = alpha * this + beta * b
Definition: Vector.h:522
ThunderEgg::Vector::set
void set(double alpha)
set all value in the vector
Definition: Vector.h:391
ThunderEgg::Vector::addScaled
void addScaled(double alpha, const Vector< D > &b)
this = this + alpha * b
Definition: Vector.h:483
ThunderEgg::Domain::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Domain.h:272
ThunderEgg::Vector::getNumLocalCells
int getNumLocalCells() const
Get the number of local cells int he vector (excluding ghost cells)
Definition: Vector.h:322
PatchView.h
PatchView class.
ThunderEgg::PatchView< double, D >
ThunderEgg
The ThunderEgg namespace.
Definition: BiLinearGhostFiller.h:31
ThunderEgg::Vector::copy
void copy(const Vector< D > &b)
copy the values of the other vector
Definition: Vector.h:443
ThunderEgg::Vector::operator=
Vector< D > & operator=(const Vector< D > &other)
Copy assignment.
Definition: Vector.h:251
ThunderEgg::Vector::twoNorm
double twoNorm() const
get the l2norm
Definition: Vector.h:553
ThunderEgg::Vector::add
void add(const Vector< D > &b)
add the other vector to this vector
Definition: Vector.h:471
Loops.h
Loop templates.
ThunderEgg::Vector::setWithGhost
void setWithGhost(double alpha)
set all values in the vector (including ghost cells)
Definition: Vector.h:404
ThunderEgg::Vector::shift
void shift(double delta)
shift all the values in the vector
Definition: Vector.h:430
Domain.h
Domain class.
ThunderEgg::Vector::Vector
Vector(Communicator comm, const std::vector< double * > &patch_starts, const std::array< int, D+1 > &strides, const std::array< int, D+1 > &lengths, int num_ghost_cells)
Construct a new Vector object with unmanaged memory.
Definition: Vector.h:199
ThunderEgg::Vector::addScaled
void addScaled(double alpha, const Vector< D > &a, double beta, const Vector< D > &b)
this = this + alpha * a + beta * b
Definition: Vector.h:495
ThunderEgg::Vector::Vector
Vector(const Vector< D > &other)
Copy constructor.
Definition: Vector.h:223
ThunderEgg::Vector::infNorm
double infNorm() const
get the infnorm
Definition: Vector.h:568
ThunderEgg::Vector::getPatchView
PatchView< double, D > getPatchView(int patch_local_index)
Get the View objects for the specified patch index of View object will correspond to component index.
Definition: Vector.h:358
ThunderEgg::Communicator
wrapper arount MPI_Comm, provides proper copy operators. Classes that have a communicator are meant t...
Definition: Communicator.h:36
ThunderEgg::Vector
Vector class for use in thunderegg.
Definition: Vector.h:42
ThunderEgg::Vector::dot
double dot(const Vector< D > &b) const
get the dot product
Definition: Vector.h:583
ThunderEgg::Vector::getPatchView
PatchView< const double, D > getPatchView(int patch_local_index) const
Get the View objects for the specified patch index of View object will correspond to component index.
Definition: Vector.h:375
ThunderEgg::Vector::getZeroClone
Vector< D > getZeroClone() const
Get a vector of the same length initialized to zero.
Definition: Vector.h:601
ThunderEgg::Vector::getNumLocalPatches
int getNumLocalPatches() const
Get the number of local patches.
Definition: Vector.h:316
ThunderEgg::Vector::getNumGhostCells
int getNumGhostCells() const
Get the number of ghost cells.
Definition: Vector.h:328
ThunderEgg::RuntimeError
ThunderEgg runtime exception.
Definition: RuntimeError.h:36