IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
HaloCells.hpp
Go to the documentation of this file.
1//
2// Class HaloCells
3// The guard / ghost cells of BareField.
4//
5
6#include <memory>
7#include <vector>
8
10
12
13namespace ippl {
14 namespace detail {
15 template <typename T, unsigned Dim, class... ViewArgs>
17
18 template <typename T, unsigned Dim, class... ViewArgs>
22
23 template <typename T, unsigned Dim, class... ViewArgs>
27 template <typename T, unsigned Dim, class... ViewArgs>
31
32 template <typename T, unsigned Dim, class... ViewArgs>
33 template <class Op>
35 SendOrder order, int nghost) {
36 using neighbor_list = typename Layout_t::neighbor_list;
37 using range_list = typename Layout_t::neighbor_range_list;
38
39 auto& comm = layout->comm;
40
41 const neighbor_list& neighbors = layout->getNeighbors();
42 const range_list &sendRanges = layout->getNeighborsSendRange(),
43 &recvRanges = layout->getNeighborsRecvRange();
44
45 auto ldom = layout->getLocalNDIndex();
46 for (const auto& axis : ldom) {
47 if ((axis.length() == 1) && (Dim != 1)) {
48 throw std::runtime_error(
49 "HaloCells: Cannot do neighbour exchange when domain decomposition "
50 "contains planes!");
51 }
52 }
53
54 // needed for the NOGHOST approach - we want to remove the ghost
55 // cells on the boundaries of the global domain from the halo
56 // exchange when we set HALO_TO_INTERNAL_NOGHOST
57 const auto domain = layout->getDomain();
58 const auto& ldomains = layout->getHostLocalDomains();
59
60 size_t totalRequests = 0;
61 for (const auto& componentNeighbors : neighbors) {
62 totalRequests += componentNeighbors.size();
63 }
64
65 int me=Comm->rank();
66
67 using memory_space = typename view_type::memory_space;
69 std::vector<MPI_Request> requests(totalRequests);
70 // sending loop
71 constexpr size_t cubeCount = detail::countHypercubes(Dim) - 1;
72 size_t requestIndex = 0;
73 for (size_t index = 0; index < cubeCount; index++) {
74 int tag = mpi::tag::HALO + index;
75 const auto& componentNeighbors = neighbors[index];
76 for (size_t i = 0; i < componentNeighbors.size(); i++) {
77 int targetRank = componentNeighbors[i];
78
79 bound_type range;
80 if (order == INTERNAL_TO_HALO) {
81 /*We store only the sending and receiving ranges
82 * of INTERNAL_TO_HALO and use the fact that the
83 * sending range of HALO_TO_INTERNAL is the receiving
84 * range of INTERNAL_TO_HALO and vice versa
85 */
86 range = sendRanges[index][i];
87 } else if (order == HALO_TO_INTERNAL_NOGHOST) {
88 range = recvRanges[index][i];
89
90 for (size_t j = 0; j < Dim; ++j) {
91 bool isLower = ((range.lo[j] + ldomains[me][j].first()
92 - nghost) == domain[j].min());
93 bool isUpper = ((range.hi[j] - 1 +
94 ldomains[me][j].first() - nghost)
95 == domain[j].max());
96 range.lo[j] += isLower * (nghost);
97 range.hi[j] -= isUpper * (nghost);
98 }
99 } else {
100 range = recvRanges[index][i];
101 }
102
103 size_type nsends;
104 pack(range, view, haloData_m, nsends);
105
106 buffer_type buf = comm.template getBuffer<memory_space, T>(nsends);
107
108 comm.isend(targetRank, tag, haloData_m, *buf, requests[requestIndex++], nsends);
109 buf->resetWritePos();
110 }
111 }
112
113 // receiving loop
114 for (size_t index = 0; index < cubeCount; index++) {
116 const auto& componentNeighbors = neighbors[index];
117 for (size_t i = 0; i < componentNeighbors.size(); i++) {
118 int sourceRank = componentNeighbors[i];
119
120 bound_type range;
121 if (order == INTERNAL_TO_HALO) {
122 range = recvRanges[index][i];
123 } else if (order == HALO_TO_INTERNAL_NOGHOST) {
124 range = sendRanges[index][i];
125
126 for (size_t j = 0; j < Dim; ++j) {
127 bool isLower = ((range.lo[j] + ldomains[me][j].first()
128 - nghost) == domain[j].min());
129 bool isUpper = ((range.hi[j] - 1 +
130 ldomains[me][j].first() - nghost)
131 == domain[j].max());
132 range.lo[j] += isLower * (nghost);
133 range.hi[j] -= isUpper * (nghost);
134 }
135 } else {
136 range = sendRanges[index][i];
137 }
138
139 size_type nrecvs = range.size();
140
141 buffer_type buf = comm.template getBuffer<memory_space, T>(nrecvs);
142
143 comm.recv(sourceRank, tag, haloData_m, *buf, nrecvs * sizeof(T), nrecvs);
144 buf->resetReadPos();
145
146 unpack<Op>(range, view, haloData_m);
147 }
148 }
149
150 if (totalRequests > 0) {
151 MPI_Waitall(totalRequests, requests.data(), MPI_STATUSES_IGNORE);
152 }
153
154 comm.freeAllBuffers();
155 }
156
157 template <typename T, unsigned Dim, class... ViewArgs>
159 databuffer_type& fd, size_type& nsends) {
160 auto subview = makeSubview(view, range);
161
162 auto& buffer = fd.buffer;
163
164 size_t size = subview.size();
165 nsends = size;
166 if (buffer.size() < size) {
167 int overalloc = Comm->getDefaultOverallocation();
168 Kokkos::realloc(buffer, size * overalloc);
169 }
170
171 using index_array_type =
174 "HaloCells::pack()", getRangePolicy(subview),
175 KOKKOS_LAMBDA(const index_array_type& args) {
176 int l = 0;
177
178 for (unsigned d1 = 0; d1 < Dim; d1++) {
179 int next = args[d1];
180 for (unsigned d2 = 0; d2 < d1; d2++) {
181 next *= subview.extent(d2);
182 }
183 l += next;
184 }
185
186 buffer(l) = apply(subview, args);
187 });
188 Kokkos::fence();
189 }
190
191 template <typename T, unsigned Dim, class... ViewArgs>
192 template <typename Op>
194 databuffer_type& fd) {
195 auto subview = makeSubview(view, range);
196 auto buffer = fd.buffer;
197
198 // 29. November 2020
199 // https://stackoverflow.com/questions/3735398/operator-as-template-parameter
200 Op op;
201
202 using index_array_type =
205 "HaloCells::unpack()", getRangePolicy(subview),
206 KOKKOS_LAMBDA(const index_array_type& args) {
207 int l = 0;
208
209 for (unsigned d1 = 0; d1 < Dim; d1++) {
210 int next = args[d1];
211 for (unsigned d2 = 0; d2 < d1; d2++) {
212 next *= subview.extent(d2);
213 }
214 l += next;
215 }
216
217 op(apply(subview, args), buffer(l));
218 });
219 Kokkos::fence();
220 }
221
222 template <typename T, unsigned Dim, class... ViewArgs>
224 const bound_type& intersect) {
225 auto makeSub = [&]<size_t... Idx>(const std::index_sequence<Idx...>&) {
226 return Kokkos::subview(view,
227 Kokkos::make_pair(intersect.lo[Idx], intersect.hi[Idx])...);
228 };
229 return makeSub(std::make_index_sequence<Dim>{});
230 }
231
232 template <typename T, unsigned Dim, class... ViewArgs>
233 template <typename Op>
235 const Layout_t* layout,
236 const int nghost) {
237 int myRank = layout->comm.rank();
238 const auto& lDomains = layout->getHostLocalDomains();
239 const auto& domain = layout->getDomain();
240
241 using exec_space = typename view_type::execution_space;
242 using index_type = typename RangePolicy<Dim, exec_space>::index_type;
243
244 Kokkos::Array<index_type, Dim> ext, begin, end;
245
246 for (size_t i = 0; i < Dim; ++i) {
247 ext[i] = view.extent(i);
248 begin[i] = 0;
249 }
250
251 Op op;
252
253 for (unsigned d = 0; d < Dim; ++d) {
254 end = ext;
255 end[d] = nghost;
256
257 if (lDomains[myRank][d].length() == domain[d].length()) {
258 int N = view.extent(d) - 1;
259
260 using index_array_type =
261 typename RangePolicy<Dim,
262 typename view_type::execution_space>::index_array_type;
264 "applyPeriodicSerialDim", createRangePolicy<Dim, exec_space>(begin, end),
265 KOKKOS_LAMBDA(index_array_type & coords) {
266 // The ghosts are filled starting from the inside
267 // of the domain proceeding outwards for both lower
268 // and upper faces. The extra brackets and explicit
269 // mention
270
271 // nghost + i
272 coords[d] += nghost;
273 auto&& left = apply(view, coords);
274
275 // N - nghost - i
276 coords[d] = N - coords[d];
277 auto&& right = apply(view, coords);
278
279 // nghost - 1 - i
280 coords[d] += 2 * nghost - 1 - N;
281 op(apply(view, coords), right);
282
283 // N - (nghost - 1 - i) = N - (nghost - 1) + i
284 coords[d] = N - coords[d];
285 op(apply(view, coords), left);
286 });
287
288 Kokkos::fence();
289 }
290 }
291 }
292 } // namespace detail
293} // namespace ippl
constexpr unsigned Dim
void unpack(const ippl::NDIndex< 3 > intersect, const Kokkos::View< Tf *** > &view, ippl::detail::FieldBufferData< Tb > &fd, int nghost, const ippl::NDIndex< 3 > ldom, bool x=false, bool y=false, bool z=false)
void pack(const ippl::NDIndex< 3 > intersect, Kokkos::View< Tf *** > &view, ippl::detail::FieldBufferData< Tb > &fd, int nghost, const ippl::NDIndex< 3 > ldom, ippl::mpi::Communicator::size_type &nsends)
Definition Archive.h:20
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
RangePolicy< Dim, PolicyArgs... >::policy_type createRangePolicy(const Kokkos::Array< typename RangePolicy< Dim, PolicyArgs... >::index_type, Dim > &begin, const Kokkos::Array< typename RangePolicy< Dim, PolicyArgs... >::index_type, Dim > &end)
RangePolicy< View::rank, typenameView::execution_space, PolicyArgs... >::policy_type getRangePolicy(const View &view, int shift=0)
KOKKOS_INLINE_FUNCTION Vector< T, Dim > min(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
Definition Vector.hpp:217
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
std::unique_ptr< mpi::Communicator > Comm
Definition Ippl.h:22
std::size_t size_type
Definition IpplTypes.h:13
KOKKOS_INLINE_FUNCTION constexpr unsigned int countHypercubes(unsigned int dim)
Definition FieldLayout.h:44
bool isUpper(unsigned int face)
int rank() const noexcept
std::shared_ptr< archive_type< MemorySpace > > buffer_type
auto makeSubview(const view_type &view, const bound_type &intersect)
void accumulateHalo_noghost(view_type &view, Layout_t *layout, int nghost)
Definition HaloCells.hpp:24
typename detail::ViewType< T, Dim, ViewArgs... >::view_type view_type
Definition HaloCells.h:41
databuffer_type haloData_m
Definition HaloCells.h:152
void applyPeriodicSerialDim(view_type &view, const Layout_t *layout, const int nghost)
void pack(const bound_type &range, const view_type &view, databuffer_type &fd, size_type &nsends)
FieldLayout< Dim > Layout_t
Definition HaloCells.h:42
void exchangeBoundaries(view_type &view, Layout_t *layout, SendOrder order, int nghost=1)
Definition HaloCells.hpp:34
FieldBufferData< T, ViewArgs... > databuffer_type
Definition HaloCells.h:44
void unpack(const bound_type &range, const view_type &view, databuffer_type &fd)
typename Layout_t::bound_type bound_type
Definition HaloCells.h:43
void accumulateHalo(view_type &view, Layout_t *layout)
Definition HaloCells.hpp:19
void fillHalo(view_type &, Layout_t *layout)
Definition HaloCells.hpp:28
const neighbor_list & getNeighbors() const
const host_mirror_type getHostLocalDomains() const
const NDIndex< Dim > & getDomain() const
std::array< rank_list, detail::countHypercubes(Dim) - 1 > neighbor_list
const NDIndex_t & getLocalNDIndex() const
mpi::Communicator comm
std::array< bounds_list, detail::countHypercubes(Dim) - 1 > neighbor_range_list
const neighbor_range_list & getNeighborsSendRange() const
const neighbor_range_list & getNeighborsRecvRange() const
static int getMatchingIndex(int index)
::ippl::Vector< index_type, Dim > index_array_type
typename policy_type::array_index_type index_type