13#include "Utility/IpplException.h"
14#include "Utility/IpplTimings.h"
15#include "Utility/PAssert.h"
17#include "FieldLayout/FieldLayout.h"
21 template <
unsigned Dim>
27 static const int digit_swap[3] = {1, 0, 2};
29 for (
unsigned d = 1; d < detail::countHypercubes(Dim); d *= 3) {
30 match += digit_swap[index % 3] * d;
36 template <
unsigned Dim>
39 , dLocalDomains_m(
"local domains (device)", 0)
40 , hLocalDomains_m(Kokkos::create_mirror_view(dLocalDomains_m)) {
41 for (
unsigned int d = 0; d < Dim; ++d) {
46 template <
unsigned Dim>
48 std::array<bool, Dim> isParallel,
bool isAllPeriodic)
50 initialize(domain, isParallel, isAllPeriodic);
53 template <
unsigned Dim>
54 void FieldLayout<Dim>::updateLayout(
const std::vector<NDIndex<Dim>>& domains) {
55 if (domains.empty()) {
59 for (
unsigned int i = 0; i < domains.size(); i++) {
60 hLocalDomains_m(i) = domains[i];
65 Kokkos::deep_copy(dLocalDomains_m, hLocalDomains_m);
70 template <
unsigned Dim>
71 void FieldLayout<Dim>::initialize(
const NDIndex<Dim>& domain, std::array<bool, Dim> isParallel,
73 int nRanks = comm.size();
77 isAllPeriodic_m = isAllPeriodic;
79 isParallelDim_m = isParallel;
82 Kokkos::resize(dLocalDomains_m, nRanks);
83 Kokkos::resize(hLocalDomains_m, nRanks);
84 hLocalDomains_m(0) = domain;
85 Kokkos::deep_copy(dLocalDomains_m, hLocalDomains_m);
93 for (
unsigned d = 0; d < Dim; ++d) {
94 totparelems *= isParallelDim_m[d] ? domain[d].length() : 1;
97 if (totparelems < nRanks) {
98 throw std::runtime_error(
"FieldLayout:initialize: domain can only be partitioned in to "
99 + std::to_string(totparelems) +
" local domains, but there are " + std::to_string(nRanks) +
" ranks, decrease the number of ranks or increase the domain.");
102 Kokkos::resize(dLocalDomains_m, nRanks);
103 Kokkos::resize(hLocalDomains_m, nRanks);
105 detail::Partitioner<Dim> partitioner;
106 partitioner.split(domain, hLocalDomains_m, isParallel, nRanks);
110 Kokkos::deep_copy(dLocalDomains_m, hLocalDomains_m);
115 template <
unsigned Dim>
116 const typename FieldLayout<Dim>::NDIndex_t& FieldLayout<Dim>::getLocalNDIndex()
const {
117 return hLocalDomains_m(comm.rank());
120 template <
unsigned Dim>
121 const typename FieldLayout<Dim>::NDIndex_t& FieldLayout<Dim>::getLocalNDIndex(
int rank)
const {
123 PAssert(rank >= 0 && rank < comm.size());
125 return hLocalDomains_m(rank);
128 template <
unsigned Dim>
129 const typename FieldLayout<Dim>::host_mirror_type FieldLayout<Dim>::getHostLocalDomains()
131 return hLocalDomains_m;
134 template <
unsigned Dim>
135 const typename FieldLayout<Dim>::view_type FieldLayout<Dim>::getDeviceLocalDomains()
const {
136 return dLocalDomains_m;
139 template <
unsigned Dim>
144 template <
unsigned Dim>
147 return neighborsSendRange_m;
150 template <
unsigned Dim>
153 return neighborsRecvRange_m;
156 template <
unsigned Dim>
158 if (comm.rank() > 0) {
162 out <<
"Domain = " << gDomain_m <<
"\n"
163 <<
"Total number of boxes = " << hLocalDomains_m.size() <<
"\n";
165 using size_type =
typename host_mirror_type::size_type;
166 for (size_type i = 0; i < hLocalDomains_m.size(); ++i) {
167 out <<
" Box " << i <<
" " << hLocalDomains_m(i) <<
"\n";
171 template <
unsigned Dim>
172 void FieldLayout<Dim>::calcWidths() {
174 for (
unsigned int d = 0; d < Dim; ++d) {
175 minWidth_m[d] = gDomain_m[d].length();
178 using size_type =
typename host_mirror_type::size_type;
179 for (size_type i = 0; i < hLocalDomains_m.size(); ++i) {
180 const NDIndex_t& dom = hLocalDomains_m(i);
181 for (
unsigned int d = 0; d < Dim; ++d) {
182 if ((
unsigned int)dom[d].length() < minWidth_m[d]) {
183 minWidth_m[d] = dom[d].length();
189 template <
unsigned Dim>
193 std::map<unsigned int, int>& offsets,
unsigned d0,
195 for (
unsigned int d = d0; d < Dim; ++d) {
198 for (
int k = 0; k < 2; ++k) {
199 auto offset = offsets[d] = getPeriodicOffset(localDomain, d, k);
206 if (grown.touches(neighborDomain)) {
207 auto intersect = grown.
intersect(neighborDomain);
208 for (
auto& [d, offset] : offsets) {
209 neighborDomain[d] -= offset;
211 addNeighbors(grown, localDomain, neighborDomain, intersect, nghost, rank);
212 for (
auto& [d, offset] : offsets) {
213 neighborDomain[d] += offset;
216 if (codim + 1 < Dim) {
217 findPeriodicNeighbors(nghost, localDomain, grown, neighborDomain, rank, offsets,
227 template <
unsigned Dim>
232 for (
size_t i = 0; i < detail::countHypercubes(Dim) - 1; i++) {
233 neighbors_m[i].clear();
234 neighborsSendRange_m[i].clear();
235 neighborsRecvRange_m[i].clear();
238 int myRank = comm.rank();
241 auto& nd = hLocalDomains_m[myRank];
244 auto gnd = nd.
grow(nghost);
246 static IpplTimings::TimerRef findInternalNeighborsTimer =
247 IpplTimings::getTimer(
"findInternal");
248 static IpplTimings::TimerRef findPeriodicNeighborsTimer =
249 IpplTimings::getTimer(
"findPeriodic");
250 for (
int rank = 0; rank < comm.size(); ++rank) {
251 if (rank == myRank) {
256 auto& ndNeighbor = hLocalDomains_m[rank];
257 IpplTimings::startTimer(findInternalNeighborsTimer);
259 if (gnd.touches(ndNeighbor)) {
260 auto intersect = gnd.intersect(ndNeighbor);
261 addNeighbors(gnd, nd, ndNeighbor, intersect, nghost, rank);
263 IpplTimings::stopTimer(findInternalNeighborsTimer);
265 IpplTimings::startTimer(findPeriodicNeighborsTimer);
266 if (isAllPeriodic_m) {
267 std::map<unsigned int, int> offsets;
268 findPeriodicNeighbors(nghost, nd, gnd, ndNeighbor, rank, offsets);
270 IpplTimings::stopTimer(findPeriodicNeighborsTimer);
274 template <
unsigned Dim>
277 int nghost,
int rank) {
279 rangeSend = getBounds(nd, ndNeighbor, nd, nghost);
281 rangeRecv = getBounds(ndNeighbor, nd, nd, nghost);
284 for (
unsigned d = 0, digit = 1; d < Dim; d++, digit *= 3) {
291 if (intersect[d].length() == 1) {
292 if (gnd[d].first() != intersect[d].first()) {
299 neighbors_m[index].push_back(rank);
300 neighborsSendRange_m[index].push_back(rangeSend);
301 neighborsRecvRange_m[index].push_back(rangeRecv);
304 template <
unsigned Dim>
306 const NDIndex_t& nd2,
307 const NDIndex_t& offset,
313 bound_type intersect;
318 for (
size_t i = 0; i < Dim; ++i) {
319 intersect.lo[i] = overlap[i].first() - offset[i].first() + nghost;
320 intersect.hi[i] = overlap[i].last() - offset[i].first() + nghost + 1;
326 template <
unsigned Dim>
327 int FieldLayout<Dim>::getPeriodicOffset(
const NDIndex_t& nd,
const unsigned int d,
331 if (nd[d].max() == gDomain_m[d].max()) {
332 return -gDomain_m[d].length();
336 if (nd[d].min() == gDomain_m[d].min()) {
337 return gDomain_m[d].length();
341 throw IpplException(
"FieldLayout:getPeriodicOffset",
"k has to be either 0 or 1");
Definition IpplException.h:6
Definition FieldLayout.h:166
void findNeighbors(int nghost=1)
Definition FieldLayout.hpp:228
const neighbor_list & getNeighbors() const
Definition FieldLayout.hpp:140
void addNeighbors(const NDIndex_t &gnd, const NDIndex_t &nd, const NDIndex_t &ndNeighbor, const NDIndex_t &intersect, int nghost, int rank)
Definition FieldLayout.hpp:275
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)
Definition FieldLayout.hpp:190
FieldLayout(const mpi::Communicator &=MPI_COMM_WORLD)
Definition FieldLayout.hpp:37
const neighbor_range_list & getNeighborsSendRange() const
Definition FieldLayout.hpp:145
const neighbor_range_list & getNeighborsRecvRange() const
Definition FieldLayout.hpp:151
static int getMatchingIndex(int index)
Definition FieldLayout.hpp:22
KOKKOS_INLINE_FUNCTION NDIndex< Dim > intersect(const NDIndex< Dim > &) const
Definition NDIndex.hpp:59
KOKKOS_INLINE_FUNCTION NDIndex< Dim > grow(int ncells) const
Definition NDIndex.hpp:68
Definition Communicator.h:31
Definition FieldLayout.h:172