IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
FieldLayout.h
Go to the documentation of this file.
1//
2// Class FieldLayout
3// FieldLayout describes how a given index space (represented by an NDIndex
4// object) is distributed among MPI ranks. It performs the initial
5// partitioning. The user may request that a particular dimension not be
6// partitioned by flagging that axis as 'SERIAL' (instead of 'PARALLEL').
7//
8#ifndef IPPL_FIELD_LAYOUT_H
9#define IPPL_FIELD_LAYOUT_H
10
11#include <array>
12#include <iostream>
13#include <map>
14#include <vector>
15
16#include "Types/ViewTypes.h"
17
19#include "Index/NDIndex.h"
21
22namespace ippl {
23
24 template <unsigned Dim>
25 class FieldLayout;
26
27 template <unsigned Dim>
28 std::ostream& operator<<(std::ostream&, const FieldLayout<Dim>&);
29
30 // enumeration used to describe a hypercube's relation to
31 // a particular axis in a given bounded domain
33 UPPER = 0,
34 LOWER = 1,
36 };
37
38 namespace detail {
44 KOKKOS_INLINE_FUNCTION constexpr unsigned int countHypercubes(unsigned int dim) {
45 unsigned int ret = 1;
46 for (unsigned int d = 0; d < dim; d++) {
47 ret *= 3;
48 }
49 return ret;
50 }
51
57 constexpr unsigned int factorial(unsigned x) {
58 return x == 0 ? 1 : x * factorial(x - 1);
59 }
60
68 constexpr unsigned int binomialCoefficient(unsigned a, unsigned b) {
69 return factorial(a) / (factorial(b) * factorial(a - b));
70 }
71
79 template <unsigned Dim>
80 constexpr unsigned int countCubes(unsigned m) {
81 return (1 << (Dim - m)) * binomialCoefficient(Dim, m);
82 }
83
92 bool isUpper(unsigned int face);
93
101 unsigned int getFaceDim(unsigned int face);
102
109 template <unsigned Dim>
110 unsigned int indexToFace(unsigned int index) {
111 // facets are group low/high by axis
112 unsigned int axis = index / 2;
113 // the digit to subtract is determined by whether the index describes an upper
114 // face (even index) or lower face (odd index) and that digit's position is
115 // determined by the axis of the face
116 unsigned int toRemove = (2 - index % 2) * countHypercubes(axis);
117 // start with all 2s (in base 3) and change the correct digit to get the encoded face
118 return countHypercubes(Dim) - 1 - toRemove;
119 }
120
128 template <
129 unsigned Dim, typename... CubeTags,
130 typename = std::enable_if_t<sizeof...(CubeTags) == Dim - 1>,
131 typename = std::enable_if_t<std::conjunction_v<std::is_same<e_cube_tag, CubeTags>...>>>
132 unsigned int getCube(e_cube_tag tag, CubeTags... tags) {
133 if constexpr (Dim == 1) {
134 return tag;
135 } else {
136 return tag + 3 * getCube<Dim - 1>(tags...);
137 }
138 }
139
143 template <size_t... Idx>
144 unsigned int getFace_impl(const std::array<e_cube_tag, sizeof...(Idx)>& args,
145 const std::index_sequence<Idx...>&) {
146 return getCube<sizeof...(Idx)>(args[Idx]...);
147 }
148
156 template <unsigned Dim>
157 unsigned int getFace(unsigned int axis, e_cube_tag side) {
158 std::array<e_cube_tag, Dim> args;
159 args.fill(IS_PARALLEL);
160 args[axis] = side;
161 return getFace_impl(args, std::make_index_sequence<Dim>{});
162 }
163 } // namespace detail
164
165 template <unsigned Dim>
167 public:
170 using host_mirror_type = typename view_type::host_mirror_type;
171
172 struct bound_type {
173 // lower bounds (ordering: x, y, z, ...)
174 std::array<long, Dim> lo;
175 // upper bounds (ordering: x, y, z, ...)
176 std::array<long, Dim> hi;
177
182 long size() const {
183 long total = 1;
184 for (unsigned d = 0; d < Dim; d++) {
185 total *= hi[d] - lo[d];
186 }
187 return total;
188 }
189 };
190
191 using rank_list = std::vector<int>;
192 using bounds_list = std::vector<bound_type>;
193
196
201 FieldLayout(const mpi::Communicator& = MPI_COMM_WORLD);
202
203 FieldLayout(mpi::Communicator, const NDIndex<Dim>& domain, std::array<bool, Dim> decomp,
204 bool isAllPeriodic = false);
205
206 // Destructor: Everything deletes itself automatically ... the base
207 // class destructors inform all the FieldLayoutUser's we're going away.
208 virtual ~FieldLayout() = default;
209
210 // Initialization functions, only to be called by the user of FieldLayout
211 // objects when the FieldLayout was created using the default constructor;
212 // otherwise these are only called internally by the various non-default
213 // FieldLayout constructors:
214
215 void initialize(const NDIndex<Dim>& domain, std::array<bool, Dim> decomp,
216 bool isAllPeriodic = false);
217
218 // Return the domain.
219 const NDIndex<Dim>& getDomain() const { return gDomain_m; }
220
221 // Compare FieldLayouts to see if they represent the same domain; if
222 // dimensionalities are different, the NDIndex operator==() will return
223 // false:
224 template <unsigned Dim2>
225 bool operator==(const FieldLayout<Dim2>& x) const {
226
227 // Throw exception if the domains are not the same
228 if (gDomain_m != x.getDomain()) {
229 throw std::runtime_error("FieldLayout: only FieldLayouts with the same global domain should be compared");
230 }
231
232 return gDomain_m == x.getDomain();
233 }
234
235 bool operator==(const FieldLayout<Dim>& x) const {
236
237 // Throw exception if the domains are not the same
238 if (gDomain_m != x.getDomain()) {
239 throw std::runtime_error("FieldLayout: only FieldLayouts with the same global domain should be compared");
240 }
241
242 for (unsigned int i = 0; i < Dim; ++i) {
243 if (hLocalDomains_m(comm.rank())[i] != x.getLocalNDIndex()[i]) {
244 return false;
245 }
246 }
247 return true;
248 }
249
250 // for the requested dimension, report if the distribution is
251 // SERIAL or PARALLEL
252 bool getDistribution(unsigned int d) const {
253 return minWidth_m[d] == (unsigned int)gDomain_m[d].length();
254 }
255
256 // for the requested dimension, report if the distribution was requested to
257 // be SERIAL or PARALLEL
258 std::array<bool, Dim> isParallel() const { return isParallelDim_m; }
259
260 // Get the local domain for the current rank.
261 const NDIndex_t& getLocalNDIndex() const;
262
263 // Get the local domain for a specific rank.
264 const NDIndex_t& getLocalNDIndex(int rank) const;
265
267
268 const view_type getDeviceLocalDomains() const;
269
275 const neighbor_list& getNeighbors() const;
276
283
290
310 static int getMatchingIndex(int index);
311
324 void findPeriodicNeighbors(const int nghost, const NDIndex<Dim>& localDomain,
325 NDIndex<Dim>& grown, NDIndex<Dim>& neighborDomain,
326 const int rank, std::map<unsigned int, int>& offsets,
327 unsigned d0 = 0, unsigned codim = 0);
328
333 void findNeighbors(int nghost = 1);
334
344 void addNeighbors(const NDIndex_t& gnd, const NDIndex_t& nd, const NDIndex_t& ndNeighbor,
345 const NDIndex_t& intersect, int nghost, int rank);
346
347 void write(std::ostream& = std::cout) const;
348
349 void updateLayout(const std::vector<NDIndex_t>& domains);
350
352
354
355 private:
365 bound_type getBounds(const NDIndex_t& nd1, const NDIndex_t& nd2, const NDIndex_t& offset,
366 int nghost);
367
368 int getPeriodicOffset(const NDIndex_t& nd, const unsigned int d, const int k);
369
370 // List of all the neighboring ranks, arranged by ternary encoding
372
373 // Lower and upper bounds of the regions to send and receive to and from neighbors,
374 // arranged by ternary encoding
376
377 protected:
380
383
386
387 std::array<bool, Dim> isParallelDim_m;
388
389 // Minimum width of all the local domains for each dimension
390 unsigned int minWidth_m[Dim];
391
392 void calcWidths();
393 };
394
395 template <unsigned Dim>
396 inline std::ostream& operator<<(std::ostream& out, const FieldLayout<Dim>& f) {
397 f.write(out);
398 return out;
399 }
400} // namespace ippl
401
403
404#endif
typename ippl::detail::ViewType< ippl::Vector< double, Dim >, 1 >::view_type view_type
constexpr unsigned Dim
Definition Archive.h:20
@ IS_PARALLEL
Definition FieldLayout.h:35
@ LOWER
Definition FieldLayout.h:34
@ UPPER
Definition FieldLayout.h:33
std::ostream & operator<<(std::ostream &os, const BConds< Field, Dim > &bc)
Definition BConds.h:49
constexpr unsigned int factorial(unsigned x)
Definition FieldLayout.h:57
unsigned int getFaceDim(unsigned int face)
constexpr unsigned int binomialCoefficient(unsigned a, unsigned b)
Definition FieldLayout.h:68
unsigned int getFace_impl(const std::array< e_cube_tag, sizeof...(Idx)> &args, const std::index_sequence< Idx... > &)
unsigned int getFace(unsigned int axis, e_cube_tag side)
unsigned int indexToFace(unsigned int index)
unsigned int getCube(e_cube_tag tag, CubeTags... tags)
constexpr unsigned int countCubes(unsigned m)
Definition FieldLayout.h:80
KOKKOS_INLINE_FUNCTION constexpr unsigned int countHypercubes(unsigned int dim)
Definition FieldLayout.h:44
bool isUpper(unsigned int face)
std::array< bool, Dim > isParallelDim_m
typename view_type::host_mirror_type host_mirror_type
void findNeighbors(int nghost=1)
const neighbor_list & getNeighbors() const
bool operator==(const FieldLayout< Dim2 > &x) const
std::vector< bound_type > bounds_list
const host_mirror_type getHostLocalDomains() const
unsigned int minWidth_m[Dim]
void addNeighbors(const NDIndex_t &gnd, const NDIndex_t &nd, const NDIndex_t &ndNeighbor, const NDIndex_t &intersect, int nghost, int rank)
const view_type getDeviceLocalDomains() const
const NDIndex< Dim > & getDomain() const
neighbor_list neighbors_m
bool getDistribution(unsigned int d) const
neighbor_range_list neighborsSendRange_m
std::array< bool, Dim > isParallel() const
std::array< rank_list, detail::countHypercubes(Dim) - 1 > neighbor_list
typename detail::ViewType< NDIndex_t, 1 >::view_type view_type
void initialize(const NDIndex< Dim > &domain, std::array< bool, Dim > decomp, bool isAllPeriodic=false)
const NDIndex_t & getLocalNDIndex() const
void findPeriodicNeighbors(const int nghost, const NDIndex< Dim > &localDomain, NDIndex< Dim > &grown, NDIndex< Dim > &neighborDomain, const int rank, std::map< unsigned int, int > &offsets, unsigned d0=0, unsigned codim=0)
int getPeriodicOffset(const NDIndex_t &nd, const unsigned int d, const int k)
neighbor_range_list neighborsRecvRange_m
mpi::Communicator comm
view_type dLocalDomains_m
Local domains (device view).
FieldLayout(const mpi::Communicator &=MPI_COMM_WORLD)
host_mirror_type hLocalDomains_m
Local domains (host mirror view).
void write(std::ostream &=std::cout) const
virtual ~FieldLayout()=default
std::array< bounds_list, detail::countHypercubes(Dim) - 1 > neighbor_range_list
std::vector< int > rank_list
const neighbor_range_list & getNeighborsSendRange() const
NDIndex< Dim > NDIndex_t
const neighbor_range_list & getNeighborsRecvRange() const
bound_type getBounds(const NDIndex_t &nd1, const NDIndex_t &nd2, const NDIndex_t &offset, int nghost)
NDIndex_t gDomain_m
Global domain.
void updateLayout(const std::vector< NDIndex_t > &domains)
bool operator==(const FieldLayout< Dim > &x) const
static int getMatchingIndex(int index)
std::array< long, Dim > lo
std::array< long, Dim > hi
Kokkos::View< typename NPtr< T, Dim >::type, Properties... > view_type
Definition ViewTypes.h:45