peclet.voro 1.0.4
Device-native moving-particle Voronoi dynamics
Loading...
Searching...
No Matches
distributed.hpp
Go to the documentation of this file.
1
22#ifndef PECLET_VORO_FV_DISTRIBUTED_HPP
23#define PECLET_VORO_FV_DISTRIBUTED_HPP
24
25#include <mpi.h>
26
27#include <Kokkos_Core.hpp>
28#include <type_traits>
29#include <vector>
30
33
34namespace peclet::voro::fv {
35
36template <class Real>
38 using Mem = peclet::core::MemSpace;
39 using Exec = peclet::core::ExecSpace;
41 int nOwned = 0, nGhost = 0;
47 bool devicePack = true;
48 // flat topology (host) + device send index list
50 int nSend = 0, nReceived = 0;
51 Kokkos::View<int*, Mem> dSendIdx, dSelfIdx;
52 Kokkos::View<Real*, Mem> dSendBuf, dRecvBuf;
53 std::vector<Real> hSendBuf, hRecvBuf;
54
56 halo = &h;
57 nOwned = owned;
58 nGhost = h.numGhost();
59 auto t = h.flatTopology();
60 sendRanks = t.sendRanks;
61 sendCounts = t.sendCounts;
62 sendOffsets = t.sendOffsets;
63 recvRanks = t.recvRanks;
64 recvCounts = t.recvCounts;
65 recvOffsets.assign(t.recvOffsets.begin(), t.recvOffsets.end());
66 nSend = (int)t.sendIdx.size();
67 nReceived = (int)t.numReceived;
68 dSendIdx = Kokkos::View<int*, Mem>("gx.sendIdx", nSend);
69 {
70 auto hh = Kokkos::create_mirror_view(dSendIdx);
71 for (int i = 0; i < nSend; ++i)
72 hh(i) = (int)t.sendIdx[i];
73 Kokkos::deep_copy(dSendIdx, hh);
74 }
75 dSelfIdx = Kokkos::View<int*, Mem>("gx.selfIdx", t.selfIdx.size());
76 {
77 auto hh = Kokkos::create_mirror_view(dSelfIdx);
78 for (std::size_t i = 0; i < t.selfIdx.size(); ++i)
79 hh(i) = (int)t.selfIdx[i];
80 Kokkos::deep_copy(dSelfIdx, hh);
81 }
82 }
84 void exchange(const DV<Real>& f, int nc) const {
85 if (!halo || nGhost == 0)
86 return;
87 if (!devicePack) {
88 exchangeHost(f, nc);
89 return;
90 }
91 auto* self = const_cast<GhostExchange*>(this);
92 const std::size_t sb = (std::size_t)nc * nSend, rb = (std::size_t)nc * nReceived;
93 if (self->dSendBuf.extent(0) < sb)
94 self->dSendBuf = Kokkos::View<Real*, Mem>("gx.sendBuf", sb);
95 if (self->dRecvBuf.extent(0) < rb)
96 self->dRecvBuf = Kokkos::View<Real*, Mem>("gx.recvBuf", rb);
97 self->hSendBuf.resize(sb);
98 self->hRecvBuf.resize(rb);
99 // pack on the device: buffer[nc*k + c] = f[nc*sendIdx[k] + c]
100 {
101 const auto idx = dSendIdx;
102 const auto buf = dSendBuf;
103 const int ncl = nc;
104 Kokkos::parallel_for(
105 "gx.pack", Kokkos::RangePolicy<Exec>(0, nSend), KOKKOS_LAMBDA(const int k) {
106 for (int c = 0; c < ncl; ++c)
107 buf(ncl * k + c) = f(ncl * idx(k) + c);
108 });
109 }
110 Kokkos::deep_copy(Kokkos::View<Real*, Kokkos::HostSpace>(self->hSendBuf.data(), sb),
111 Kokkos::subview(dSendBuf, std::make_pair((std::size_t)0, sb)));
112 const int ns = (int)sendRanks.size(), nr = (int)recvRanks.size();
113 std::vector<MPI_Request> sreq(ns, MPI_REQUEST_NULL), rreq(nr, MPI_REQUEST_NULL);
114 const MPI_Datatype T = std::is_same_v<Real, double> ? MPI_DOUBLE : MPI_FLOAT;
115 for (int p = 0; p < nr; ++p)
116 MPI_Irecv(self->hRecvBuf.data() + (std::size_t)nc * recvOffsets[p], nc * recvCounts[p], T,
117 recvRanks[p], 7601, halo->comm(), &rreq[p]);
118 for (int k = 0; k < ns; ++k)
119 MPI_Isend(self->hSendBuf.data() + (std::size_t)nc * sendOffsets[k], nc * sendCounts[k], T,
120 sendRanks[k], 7601, halo->comm(), &sreq[k]);
121 MPI_Waitall(nr, rreq.data(), MPI_STATUSES_IGNORE);
122 MPI_Waitall(ns, sreq.data(), MPI_STATUSES_IGNORE);
123 // the received ghosts are contiguous in ghost order: scatter straight into the ghost slots
124 if (rb > 0) {
125 Kokkos::deep_copy(Kokkos::subview(dRecvBuf, std::make_pair((std::size_t)0, rb)),
126 Kokkos::View<const Real*, Kokkos::HostSpace>(self->hRecvBuf.data(), rb));
127 const auto buf = dRecvBuf;
128 const int base = nc * nOwned;
129 Kokkos::parallel_for(
130 "gx.unpack", Kokkos::RangePolicy<Exec>(0, (int)rb),
131 KOKKOS_LAMBDA(const int i) { f(base + i) = buf(i); });
132 }
133 // local periodic self-ghosts (none with includePeriodicSelf = false)
134 const int nSelf = (int)dSelfIdx.extent(0);
135 if (nSelf > 0) {
136 const auto sidx = dSelfIdx;
137 const int ncl = nc, base = nc * (nOwned + nReceived);
138 Kokkos::parallel_for(
139 "gx.self", Kokkos::RangePolicy<Exec>(0, nSelf), KOKKOS_LAMBDA(const int j) {
140 for (int c = 0; c < ncl; ++c)
141 f(base + ncl * j + c) = f(ncl * sidx(j) + c);
142 });
143 }
144 Kokkos::fence();
145 }
147 void exchangeHost(const DV<Real>& f, int nc) const {
148 auto h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace{}, f);
149 std::vector<Real> own(nOwned), gh(nGhost);
150 for (int c = 0; c < nc; ++c) {
151 for (int i = 0; i < nOwned; ++i)
152 own[i] = h(nc * i + c);
153 halo->forward(own.data(), gh.data());
154 for (int j = 0; j < nGhost; ++j)
155 h(nc * (nOwned + j) + c) = gh[j];
156 }
157 Kokkos::deep_copy(f, h);
158 }
159 Real sum(Real v) const {
160 if (!halo)
161 return v;
162 Real g = 0;
163 MPI_Allreduce(&v, &g, 1, std::is_same_v<Real, double> ? MPI_DOUBLE : MPI_FLOAT, MPI_SUM,
164 halo->comm());
165 return g;
166 }
167 Real max(Real v) const {
168 if (!halo)
169 return v;
170 Real g = 0;
171 MPI_Allreduce(&v, &g, 1, std::is_same_v<Real, double> ? MPI_DOUBLE : MPI_FLOAT, MPI_MAX,
172 halo->comm());
173 return g;
174 }
175};
176
177} // namespace peclet::voro::fv
178
179#endif // PECLET_VORO_FV_DISTRIBUTED_HPP
Definition voronoi_halo.hpp:38
int numGhost() const
Number of ghosts in the last gather() (the established topology).
Definition voronoi_halo.hpp:126
peclet::core::halo::ParticleHaloTopology< 3 >::FlatTopo flatTopology() const
Definition voronoi_halo.hpp:136
Definition collocated.hpp:38
Kokkos::View< Real *, peclet::core::MemSpace > DV
Definition operators.hpp:26
Track C, rung C1: the discrete operators of the staggered COVOLUME scheme on a face mesh (plan verdic...
Definition distributed.hpp:37
void init(peclet::voro::mpi::VoronoiHalo< Real > &h, int owned)
Definition distributed.hpp:55
void exchangeHost(const DV< Real > &f, int nc) const
The host reference path: VoronoiHalo::forward per component through a host mirror.
Definition distributed.hpp:147
Real max(Real v) const
Definition distributed.hpp:167
peclet::core::ExecSpace Exec
Definition distributed.hpp:39
std::vector< Real > hRecvBuf
Definition distributed.hpp:53
Kokkos::View< Real *, Mem > dSendBuf
Definition distributed.hpp:52
int nSend
Definition distributed.hpp:50
std::vector< int > sendRanks
Definition distributed.hpp:49
void exchange(const DV< Real > &f, int nc) const
Refresh the ghost entries [nOwned, nOwned + nGhost) of an nc-component cell field.
Definition distributed.hpp:84
peclet::core::MemSpace Mem
Definition distributed.hpp:38
Real sum(Real v) const
Definition distributed.hpp:159
int nGhost
Definition distributed.hpp:41
std::vector< int > sendCounts
Definition distributed.hpp:49
Kokkos::View< int *, Mem > dSelfIdx
Definition distributed.hpp:51
Kokkos::View< Real *, Mem > dRecvBuf
Definition distributed.hpp:52
Kokkos::View< int *, Mem > dSendIdx
Definition distributed.hpp:51
std::vector< Real > hSendBuf
Definition distributed.hpp:53
peclet::voro::mpi::VoronoiHalo< Real > * halo
Definition distributed.hpp:40
std::vector< int > recvOffsets
Definition distributed.hpp:49
bool devicePack
Definition distributed.hpp:47
std::vector< int > sendOffsets
Definition distributed.hpp:49
std::vector< int > recvRanks
Definition distributed.hpp:49
int nOwned
Definition distributed.hpp:41
int nReceived
Definition distributed.hpp:50
std::vector< int > recvCounts
Definition distributed.hpp:49
Distributed Voronoi halo over core (migration Phase 6).