Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_NonLocalBCImpl.H
Go to the documentation of this file.
1#ifndef AMREX_NONLOCAL_BC_H_
2#include "AMReX_NonLocalBC.H"
3#endif
4
5#ifndef AMREX_NONLOCAL_BC_IMPL_H_
6#define AMREX_NONLOCAL_BC_IMPL_H_
7#include <AMReX_Config.H>
8#include <AMReX_TypeTraits.H>
9
10namespace amrex::NonLocalBC {
11struct Rotate90ClockWise {
13 IntVect operator() (IntVect const& iv) const noexcept {
14 return IntVect{AMREX_D_DECL(iv[1], -1-iv[0], iv[2])};
15 }
16
18 Dim3 operator() (Dim3 const& a) const noexcept {
19 return Dim3{.x = a.y, .y = -1-a.x, .z = a.z};
20 }
21
22 Box operator() (Box const& box) const noexcept {
23 return Box(operator()(IntVect{AMREX_D_DECL(box.bigEnd (0),
24 box.smallEnd(1),
25 box.smallEnd(2))}),
26 operator()(IntVect{AMREX_D_DECL(box.smallEnd(0),
27 box.bigEnd (1),
28 box.bigEnd (2))}));
29 }
30};
31
32struct Rotate90CounterClockWise {
34 IntVect operator() (IntVect const& iv) const noexcept {
35 return IntVect{AMREX_D_DECL(-1-iv[1], iv[0], iv[2])};
36 }
37
39 Dim3 operator() (Dim3 const& a) const noexcept {
40 return Dim3{.x = -1-a.y, .y = a.x, .z = a.z};
41 }
42
43 Box operator() (Box const& box) const noexcept {
44 return Box(operator()(IntVect{AMREX_D_DECL(box.smallEnd(0),
45 box.bigEnd (1),
46 box.smallEnd(2))}),
47 operator()(IntVect{AMREX_D_DECL(box.bigEnd (0),
48 box.smallEnd(1),
49 box.bigEnd (2))}));
50 }
51};
52
53struct Rotate90DstToSrc
54{
56 Dim3 operator() (Dim3 const& a) const noexcept {
57 if (a.x < 0) {
58 return Rotate90ClockWise()(a);
59 } else {
60 return Rotate90CounterClockWise()(a);
61 }
62 }
63};
64
65struct Rotate180Fn {
66 int Ly;
67
69 IntVect operator() (IntVect const& iv) const noexcept {
70 return IntVect{AMREX_D_DECL(-1-iv[0], Ly-1-iv[1], iv[2])};
71 }
72
74 Dim3 operator() (Dim3 const& a) const noexcept {
75 return Dim3{.x = -1-a.x, .y = Ly-1-a.y, .z = a.z};
76 }
77
78 Box operator() (Box const& box) const noexcept {
79 return Box(operator()(IntVect{AMREX_D_DECL(box.bigEnd (0),
80 box.bigEnd (1),
81 box.smallEnd(2))}),
82 operator()(IntVect{AMREX_D_DECL(box.smallEnd(0),
83 box.smallEnd(1),
84 box.bigEnd (2))}));
85 }
86};
87
88struct PolarFn {
89 int Lx, Ly;
90
91 [[nodiscard]] AMREX_GPU_HOST_DEVICE
92 int i_index (int i) const noexcept {
93 return (i < Lx/2) ? -1-i : 2*Lx-1-i;
94 }
95
96 [[nodiscard]] AMREX_GPU_HOST_DEVICE
97 int j_index (int j) const noexcept {
98 return (j < Ly/2) ? j+Ly/2 : j-Ly/2;
99 }
100
101 [[nodiscard]] AMREX_GPU_HOST_DEVICE
102 IntVect operator() (IntVect const& iv) const noexcept {
103 return IntVect{AMREX_D_DECL(i_index(iv[0]), j_index(iv[1]), iv[2])};
104 }
105
106 [[nodiscard]] AMREX_GPU_HOST_DEVICE
107 Dim3 operator() (Dim3 const& a) const noexcept {
108 return Dim3{.x = i_index(a.x), .y = j_index(a.y), .z = a.z};
109 }
110
111 [[nodiscard]] Box operator() (Box const& box) const noexcept {
112 return Box(operator()(IntVect{AMREX_D_DECL(box.bigEnd (0),
113 box.smallEnd(1),
114 box.smallEnd(2))}),
115 operator()(IntVect{AMREX_D_DECL(box.smallEnd(0),
116 box.bigEnd (1),
117 box.bigEnd (2))}));
118 }
119};
120
121struct PolarFn2 { // for the x-y corners
122 int Lx, Ly;
123
124 [[nodiscard]] AMREX_GPU_HOST_DEVICE
125 int i_index (int i) const noexcept {
126 return (i < Lx/2) ? -1-i : 2*Lx-1-i;
127 }
128
129 [[nodiscard]] AMREX_GPU_HOST_DEVICE
130 int j_index (int j) const noexcept {
131 if (j < 0) { // NOLINT
132 return j+Ly/2;
133 } else if (j >= Ly) { // NOLINT
134 return j-Ly/2;
135 } else if (j < Ly/2) {
136 return j-Ly/2;
137 } else {
138 return j+Ly/2;
139 }
140 }
141
142 [[nodiscard]] AMREX_GPU_HOST_DEVICE
143 IntVect operator() (IntVect const& iv) const noexcept {
144 return IntVect{AMREX_D_DECL(i_index(iv[0]), j_index(iv[1]), iv[2])};
145 }
146
147 [[nodiscard]] AMREX_GPU_HOST_DEVICE
148 Dim3 operator() (Dim3 const& a) const noexcept {
149 return Dim3{.x = i_index(a.x), .y = j_index(a.y), .z = a.z};
150 }
151
152 [[nodiscard]] Box operator() (Box const& box) const noexcept {
153 return Box(operator()(IntVect{AMREX_D_DECL(box.bigEnd (0),
154 box.smallEnd(1),
155 box.smallEnd(2))}),
156 operator()(IntVect{AMREX_D_DECL(box.smallEnd(0),
157 box.bigEnd (1),
158 box.bigEnd (2))}));
159 }
160};
161
185template <BaseFabType FAB, class DTOS, class Proj>
186requires (IsCallableR<Dim3, DTOS, Dim3>::value && IsFabProjection<Proj, FAB>::value)
187void
188local_copy_cpu (FabArray<FAB>& dest, const FabArray<FAB>& src, int dcomp, int scomp, int ncomp,
189 FabArrayBase::CopyComTagsContainer const& local_tags, DTOS const& dtos, Proj const& proj) noexcept
190{
191 const auto N_locs = static_cast<int>(local_tags.size());
192 if (N_locs == 0) { return; }
193#ifdef AMREX_USE_OMP
194#pragma omp parallel for
195#endif
196 for (int itag = 0; itag < N_locs; ++itag) {
197 const auto& tag = local_tags[itag];
198 auto const& sfab = src.const_array(tag.srcIndex);
199 auto const& dfab = dest.array (tag.dstIndex);
200 amrex::LoopConcurrentOnCpu(tag.dbox, ncomp, [=] (int i, int j, int k, int n) noexcept
201 {
202 auto const si = dtos(Dim3{.x = i, .y = j, .z = k});
203 dfab(i,j,k,dcomp+n) = proj(sfab,si,scomp+n);
204 });
205 }
206}
207
213template <BaseFabType FAB, class DTOS, class Proj>
214requires (IsCallableR<Dim3, DTOS, Dim3>::value && IsFabProjection<Proj, FAB>::value)
215void
216unpack_recv_buffer_cpu (FabArray<FAB>& mf, int dcomp, int ncomp, Vector<char*> const& recv_data,
217 Vector<std::size_t> const& recv_size,
218 Vector<FabArrayBase::CopyComTagsContainer const*> const& recv_cctc,
219 DTOS const& dtos, Proj const& proj) noexcept
220{
221 amrex::ignore_unused(recv_size);
222
223 const auto N_rcvs = static_cast<int>(recv_cctc.size());
224 if (N_rcvs == 0) { return; }
225
226 using T = typename FAB::value_type;
227#ifdef AMREX_USE_OMP
228 if (omp_get_max_threads() > 1) {
229 // Threads share tags, not neighbor ranks, which are often fewer than threads.
230 Vector<std::pair<const char*,FabArrayBase::CopyComTag const*>> tags;
231 for (int ircv = 0; ircv < N_rcvs; ++ircv) {
232 const char* dptr = recv_data[ircv];
233 for (auto const& tag : *recv_cctc[ircv]) {
234 tags.emplace_back(dptr, &tag);
235 dptr += tag.sbox.numPts() * ncomp * sizeof(T);
236 AMREX_ASSERT(dptr <= recv_data[ircv] + recv_size[ircv]);
237 }
238 }
239
240 const auto N_tags = static_cast<int>(tags.size());
241 // Small chunks keep threads on nearby boxes, which share cache lines.
242 int const chunk = std::clamp(N_tags/omp_get_max_threads(), 1, 64);
243#pragma omp parallel for schedule(static,chunk)
244 for (int itag = 0; itag < N_tags; ++itag) {
245 auto const& tag = *tags[itag].second;
246 auto const& dfab = mf.array(tag.dstIndex);
247 auto const& sfab = amrex::makeArray4((T const*)(tags[itag].first), tag.sbox, ncomp);
248 amrex::LoopConcurrentOnCpu(tag.dbox, ncomp, [=](int i, int j, int k, int n) noexcept {
249 auto const si = dtos(Dim3{.x = i, .y = j, .z = k});
250 dfab(i, j, k, dcomp + n) = proj(sfab, si, n);
251 });
252 }
253 return;
254 }
255#endif
256
257 for (int ircv = 0; ircv < N_rcvs; ++ircv) {
258 const char* dptr = recv_data[ircv];
259 auto const& cctc = *recv_cctc[ircv];
260 for (auto const& tag : cctc) {
261 auto const& dfab = mf.array(tag.dstIndex);
262 auto const& sfab = amrex::makeArray4((T const*)(dptr), tag.sbox, ncomp);
263 amrex::LoopConcurrentOnCpu(tag.dbox, ncomp, [=](int i, int j, int k, int n) noexcept {
264 auto const si = dtos(Dim3{.x = i, .y = j, .z = k});
265 dfab(i, j, k, dcomp + n) = proj(sfab, si, n);
266 });
267 dptr += tag.sbox.numPts() * ncomp * sizeof(T);
268 AMREX_ASSERT(dptr <= recv_data[ircv] + recv_size[ircv]);
269 }
270 }
271}
272
273#ifdef AMREX_USE_GPU
274template <class T>
275struct Array4Array4Box {
276 Array4<T > dfab;
277 Array4<T const> sfab;
278 Box dbox;
279
281 Box const& box () const noexcept { return dbox; }
282};
283
284template <BaseFabType FAB, class DTOS, class Proj>
285requires (IsCallableR<Dim3, DTOS, Dim3>::value && IsFabProjection<Proj, FAB>::value)
286void
287local_copy_gpu (FabArray<FAB>& dest, const FabArray<FAB>& src, int dcomp, int scomp, int ncomp,
288 FabArrayBase::CopyComTagsContainer const& local_tags, DTOS const& dtos, Proj const& proj) noexcept
289{
290 int N_locs = local_tags.size();
291 if (N_locs == 0) { return; }
292
293 using T = typename FAB::value_type;
294 Vector<Array4Array4Box<T> > loc_copy_tags;
295 loc_copy_tags.reserve(N_locs);
296 for (auto const& tag : local_tags) {
297 loc_copy_tags.push_back(Array4Array4Box<T>{.dfab = dest.array(tag.dstIndex),
298 .sfab = src.const_array(tag.srcIndex),
299 .dbox = tag.dbox});
300 }
301
302 ParallelFor(loc_copy_tags, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n,
303 Array4Array4Box<T> const& tag) noexcept
304 {
305 auto const si = dtos(Dim3{.x = i, .y = j, .z = k});
306 tag.dfab(i,j,k,dcomp+n) = proj(tag.sfab, si, scomp+n);
307 });
308}
309
310template <BaseFabType FAB, class DTOS, class Proj>
311requires (IsCallableR<Dim3, DTOS, Dim3>::value && IsFabProjection<Proj, FAB>::value)
312void
313unpack_recv_buffer_gpu (FabArray<FAB>& mf, int scomp, int ncomp,
314 Vector<char*> const& recv_data,
315 Vector<std::size_t> const& recv_size,
316 Vector<FabArrayBase::CopyComTagsContainer const*> const& recv_cctc,
317 DTOS const& dtos, Proj const& proj)
318{
319 amrex::ignore_unused(recv_size);
320
321 const int N_rcvs = recv_cctc.size();
322 if (N_rcvs == 0) { return; }
323
324 char* pbuffer = recv_data[0];
325#if 0
326 std::size_t szbuffer = 0;
327 // For linear solver test on summit, this is slower than writing to
328 // pinned memory directly on device.
329 if (not ParallelDescriptor::UseGpuAwareMpi()) {
330 // Memory in recv_data is pinned.
331 szbuffer = (recv_data[N_rcvs-1]-recv_data[0]) + recv_size[N_rcvs-1];
332 pbuffer = (char*)The_Arena()->alloc(szbuffer);
333 Gpu::copyAsync(Gpu::hostToDevice,recv_data[0],recv_data[0]+szbuffer,pbuffer);
334 Gpu::streamSynchronize();
335 }
336#endif
337
338 using T = typename FAB::value_type;
339 using TagType = Array4Array4Box<T>;
340 Vector<TagType> tags;
341 tags.reserve(N_rcvs);
342
343 for (int k = 0; k < N_rcvs; ++k)
344 {
345 std::size_t offset = recv_data[k]-recv_data[0];
346 const char* dptr = pbuffer + offset;
347 auto const& cctc = *recv_cctc[k];
348 for (auto const& tag : cctc)
349 {
350 tags.emplace_back(TagType{mf.array(tag.dstIndex),
351 amrex::makeArray4((T const*)dptr, tag.sbox, ncomp),
352 tag.dbox});
353 dptr += tag.dbox.numPts() * ncomp * sizeof(T);
354 BL_ASSERT(dptr <= pbuffer + offset + recv_size[k]);
355 }
356 }
357
358 ParallelFor(tags, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n,
359 Array4Array4Box<T> const& tag) noexcept
360 {
361 auto const si = dtos(Dim3{.x = i, .y = j, .z = k});
362 tag.dfab(i,j,k,scomp+n) = proj(tag.sfab, si ,n);
363 });
364
365 // There is Gpu::streamSynchronize in ParallelFor above
366
367 if (pbuffer != recv_data[0]) {
368 The_Arena()->free(pbuffer);
369 }
370}
371#endif
372
373template <typename DTOS>
374requires (IsIndexMapping<DTOS>::value)
375MultiBlockCommMetaData::MultiBlockCommMetaData (const FabArrayBase& dst, const Box& dstbox, const FabArrayBase& src,
376 const IntVect& ngrow, DTOS const& dtos)
377 : MultiBlockCommMetaData(dst.boxArray(), dst.DistributionMap(), dstbox, src.boxArray(),
378 src.DistributionMap(), ngrow, dtos) {}
379
380template <typename DTOS>
381requires (IsIndexMapping<DTOS>::value)
382MultiBlockCommMetaData::MultiBlockCommMetaData (const BoxArray& dstba, const DistributionMapping& dstdm,
383 const Box& dstbox, const BoxArray& srcba,
384 const DistributionMapping& srcdm, const IntVect& ngrow, DTOS const& dtos)
385{
386 define(dstba, dstdm, dstbox, srcba, srcdm, ngrow, dtos);
387}
388
389template <typename DTOS>
390requires (IsIndexMapping<DTOS>::value)
391void
392MultiBlockCommMetaData::define (const BoxArray& dstba, const DistributionMapping& dstdm, const Box& dstbox,
393 const BoxArray& srcba, const DistributionMapping& srcdm, const IntVect& ngrow,
394 DTOS const& dtos)
395{
396 m_LocTags = std::make_unique<FabArrayBase::CopyComTagsContainer>();
397 m_SndTags = std::make_unique<FabArrayBase::MapOfCopyComTagContainers>();
398 m_RcvTags = std::make_unique<FabArrayBase::MapOfCopyComTagContainers>();
399 const int myproc = ParallelDescriptor::MyProc();
400 for (int i = 0, N = static_cast<int>(dstba.size()); i < N; ++i) {
401 const int dest_owner = dstdm[i];
402 const Box partial_dstbox = grow(dstba[i], ngrow) & dstbox;
403 if (partial_dstbox.isEmpty()) {
404 continue;
405 }
406 const Box partial_dstbox_mapped_in_src = Image(dtos, partial_dstbox).setType(srcba.ixType());
407 enum { not_first_only = 0, first_only = 1 };
408 std::vector<std::pair<int, Box>> boxes_from_src =
409 srcba.intersections(partial_dstbox_mapped_in_src, not_first_only, ngrow);
410 for (std::pair<int, Box> counted_box : boxes_from_src) {
411 const int k = counted_box.first;
412 const Box src_box = counted_box.second;
413 AMREX_ASSERT(k < srcba.size());
414 const int src_owner = srcdm[k];
415 if (dest_owner == myproc || src_owner == myproc) {
416 if (src_owner == dest_owner) {
417 const BoxList tilelist(src_box, FabArrayBase::comm_tile_size);
418 for (const Box& tilebox : tilelist) {
419 const Box inverse_image = InverseImage(dtos, tilebox).setType(dstba.ixType());
420 if ((inverse_image & partial_dstbox).ok()) {
421 m_LocTags->emplace_back(inverse_image, tilebox, i, k);
422 }
423 }
424 } else {
425 const Box inverse_image = InverseImage(dtos, src_box).setType(dstba.ixType());
426 if ((inverse_image & partial_dstbox).ok()) {
427 FabArrayBase::CopyComTagsContainer& copy_tags =
428 (src_owner == myproc) ? (*m_SndTags)[dest_owner]
429 : (*m_RcvTags)[src_owner];
430 copy_tags.emplace_back(inverse_image, src_box, i, k);
431 }
432 }
433 }
434 }
435 }
436}
437
438template <BaseFabType FAB, class DTOS, class Proj>
439#ifdef AMREX_USE_MPI
440[[nodiscard]]
441#endif
442CommHandler
443Comm_nowait (FabArray<FAB>& mf, int scomp, int ncomp, FabArrayBase::CommMetaData const& cmd,
444 DTOS const& dtos, Proj const& proj)
445{
446#ifdef AMREX_USE_MPI
447 if (ParallelContext::NProcsSub() == 1)
448#endif
449 {
450 if (cmd.m_LocTags->empty()) { return CommHandler{}; }
451#ifdef AMREX_USE_GPU
452 if (Gpu::inLaunchRegion()) {
453 local_copy_gpu(mf, mf, scomp, scomp, ncomp, *cmd.m_LocTags, dtos, proj);
454 } else
455#endif
456 {
457 local_copy_cpu(mf, mf, scomp, scomp, ncomp, *cmd.m_LocTags, dtos, proj);
458 }
459 return CommHandler{};
460 }
461
462#ifdef AMREX_USE_MPI
463 //
464 // Do this before prematurely exiting if running in parallel.
465 // Otherwise sequence numbers will not match across MPI processes.
466 //
467 int SeqNum = ParallelDescriptor::SeqNum();
468
469 const auto N_locs = cmd.m_LocTags->size();
470 const auto N_rcvs = cmd.m_RcvTags->size();
471 const auto N_snds = cmd.m_SndTags->size();
472
473 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
474 // No work to do.
475 return CommHandler{};
476 }
477
478 CommHandler handler{};
479 handler.mpi_tag = SeqNum;
480
481 if (N_rcvs > 0) {
482 handler.recv.the_data = FabArray<FAB>::PostRcvs(*cmd.m_RcvTags, handler.recv.data, handler.recv.size,
483 handler.recv.rank, handler.recv.request, ncomp, SeqNum);
484 }
485
486 if (N_snds > 0) {
487 handler.send.the_data =
488 FabArray<FAB>::PrepareSendBuffers(*cmd.m_SndTags, handler.send.data, handler.send.size,
489 handler.send.rank, handler.send.request, handler.send.cctc, ncomp);
490 handler.send.id = FabArrayBase::getNextCommMetaDataId();
491
492#ifdef AMREX_USE_GPU
493 if (Gpu::inLaunchRegion()) {
494 FabArray<FAB>::pack_send_buffer_gpu(mf, scomp, ncomp, handler.send.data,
495 handler.send.size, handler.send.cctc, handler.send.id);
496 } else
497#endif
498 {
499 FabArray<FAB>::pack_send_buffer_cpu(mf, scomp, ncomp, handler.send.data,
500 handler.send.size, handler.send.cctc);
501 }
502
503 FabArray<FAB>::PostSnds(handler.send.data, handler.send.size, handler.send.rank, handler.send.request, SeqNum);
504 }
505
506 if (N_locs > 0)
507 {
508#ifdef AMREX_USE_GPU
509 if (Gpu::inLaunchRegion()) {
510 local_copy_gpu(mf, mf, scomp, scomp, ncomp, *cmd.m_LocTags, dtos, proj);
511 } else
512#endif
513 {
514 local_copy_cpu(mf, mf, scomp, scomp, ncomp, *cmd.m_LocTags, dtos, proj);
515 }
516 }
517
518 return handler;
519#endif
520}
521
522#ifdef AMREX_USE_MPI
523template <BaseFabType FAB, class DTOS, class Proj>
524void
525Comm_finish (FabArray<FAB>& mf, int scomp, int ncomp, FabArrayBase::CommMetaData const& cmd,
526 CommHandler handler, DTOS const& dtos, Proj const& proj)
527{
528 if (ParallelContext::NProcsSub() == 1) { return; }
529
530 const auto N_rcvs = static_cast<int>(cmd.m_RcvTags->size());
531 if (N_rcvs > 0)
532 {
533 handler.recv.cctc.resize(N_rcvs, nullptr);
534 for (int k = 0; k < N_rcvs; ++k) {
535 auto const& cctc = cmd.m_RcvTags->at(handler.recv.rank[k]);
536 handler.recv.cctc[k] = &cctc;
537 }
538 handler.recv.stats.resize(handler.recv.request.size());
539 ParallelDescriptor::Waitall(handler.recv.request, handler.recv.stats);
540#ifdef AMREX_DEBUG
541 if (!CheckRcvStats(handler.recv.stats, handler.recv.size, handler.mpi_tag)) {
542 amrex::Abort("NonLocalBC::Comm_finish failed with wrong message size");
543 }
544#endif
545
546#ifdef AMREX_USE_GPU
547 if (Gpu::inLaunchRegion())
548 {
549 unpack_recv_buffer_gpu(mf, scomp, ncomp, handler.recv.data,
550 handler.recv.size, handler.recv.cctc, dtos, proj);
551 } else
552#endif
553 {
554 unpack_recv_buffer_cpu(mf, scomp, ncomp, handler.recv.data,
555 handler.recv.size, handler.recv.cctc, dtos, proj);
556 }
557 }
558
559 if ( ! cmd.m_SndTags->empty() ) {
560 handler.send.stats.resize(handler.send.request.size());
561 ParallelDescriptor::Waitall(handler.send.request, handler.send.stats);
562 }
563}
564#endif
565
566template <BaseFabType FAB>
567void
568Rotate90 (FabArray<FAB>& mf, int scomp, int ncomp, IntVect const& nghost, Box const& domain)
569{
570 BL_PROFILE("Rotate90");
571
572 AMREX_ASSERT(domain.cellCentered());
573 AMREX_ASSERT(domain.smallEnd() == 0);
574 AMREX_ASSERT(domain.length(0) == domain.length(1));
575 AMREX_ASSERT(mf.is_cell_centered());
576 AMREX_ASSERT(scomp < mf.nComp() && scomp+ncomp <= mf.nComp());
577 AMREX_ASSERT(nghost.allLE(mf.nGrowVect()) && nghost[0] == nghost[1]);
578
579 if (nghost[0] <= 0) { return; }
580
581 const FabArrayBase::RB90& TheRB90 = mf.getRB90(nghost, domain);
582
583 auto handler = Comm_nowait(mf, scomp, ncomp, TheRB90,Rotate90DstToSrc{},
584 Identity{});
585
586 Box corner(-nghost, IntVect{AMREX_D_DECL(-1,-1,domain.bigEnd(2)+nghost[2])});
587#ifdef AMREX_USE_OMP
588#pragma omp parallel if (Gpu::notInLaunchRegion())
589#endif
590 for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
591 Box const& bx = corner & mfi.fabbox();
592 if (bx.ok()) {
593 auto const& fab = mf.array(mfi);
594 AMREX_HOST_DEVICE_PARALLEL_FOR_4D(bx,ncomp,i,j,k,n,
595 {
596 fab(i,j,k,scomp+n) = fab(-i-1,-j-1,k,scomp+n);
597 });
598 }
599 }
600
601#ifdef AMREX_USE_MPI
602 Comm_finish(mf, scomp, ncomp, TheRB90, std::move(handler), Rotate90DstToSrc{},
603 Identity{});
604#else
605 amrex::ignore_unused(handler);
606#endif
607}
608
609template <BaseFabType FAB>
610void
611Rotate90 (FabArray<FAB>& mf, Box const& domain)
612{
613 Rotate90(mf, 0, mf.nComp(), mf.nGrowVect(), domain);
614}
615
616template <BaseFabType FAB>
617void
618Rotate180 (FabArray<FAB>& mf, int scomp, int ncomp, IntVect const& nghost, Box const& domain)
619{
620 BL_PROFILE("Rotate180");
621
622 AMREX_ASSERT(domain.cellCentered());
623 AMREX_ASSERT(domain.smallEnd() == 0);
624 AMREX_ASSERT(domain.length(1) % 2 == 0);
625 AMREX_ASSERT(mf.is_cell_centered());
626 AMREX_ASSERT(scomp < mf.nComp() && scomp+ncomp <= mf.nComp());
627 AMREX_ASSERT(nghost.allLE(mf.nGrowVect()));
628
629 if (nghost[0] <= 0) { return; }
630
631 const FabArrayBase::RB180& TheRB180 = mf.getRB180(nghost, domain);
632
633 auto handler = Comm_nowait(mf, scomp, ncomp, TheRB180,
634 Rotate180Fn{domain.length(1)}, Identity{});
635
636#ifdef AMREX_USE_MPI
637 Comm_finish(mf, scomp, ncomp, TheRB180, std::move(handler),
638 Rotate180Fn{domain.length(1)}, Identity{});
639#else
640 amrex::ignore_unused(handler);
641#endif
642}
643
644template <BaseFabType FAB>
645void
646Rotate180 (FabArray<FAB>& mf, Box const& domain)
647{
648 Rotate180(mf, 0, mf.nComp(), mf.nGrowVect(), domain);
649}
650
651template <BaseFabType FAB>
652void
653FillPolar (FabArray<FAB>& mf, int scomp, int ncomp, IntVect const& nghost, Box const& domain)
654{
655 BL_PROFILE("FillPolar");
656
657 AMREX_ASSERT(domain.cellCentered());
658 AMREX_ASSERT(domain.smallEnd() == 0);
659 AMREX_ASSERT(domain.length(1) % 2 == 0);
660 AMREX_ASSERT(mf.is_cell_centered());
661 AMREX_ASSERT(scomp < mf.nComp() && scomp+ncomp <= mf.nComp());
662 AMREX_ASSERT(nghost.allLE(mf.nGrowVect()));
663
664 if (nghost[0] <= 0) { return; }
665
666 const FabArrayBase::PolarB& ThePolarB = mf.getPolarB(nghost, domain);
667
668 auto handler = Comm_nowait(mf, scomp, ncomp, ThePolarB,
669 PolarFn{.Lx = domain.length(0), .Ly = domain.length(1)},
670 Identity{});
671
672#ifdef AMREX_USE_MPI
673 Comm_finish(mf, scomp, ncomp, ThePolarB, std::move(handler),
674 PolarFn{.Lx = domain.length(0), .Ly = domain.length(1)}, Identity{});
675#else
676 amrex::ignore_unused(handler);
677#endif
678}
679
680template <BaseFabType FAB>
681void
682FillPolar (FabArray<FAB>& mf, Box const& domain)
683{
684 FillPolar(mf, 0, mf.nComp(), mf.nGrowVect(), domain);
685}
686
687template <BaseFabType FAB, typename DTOS, typename Proj>
688requires (IsCallableR<Dim3,DTOS,Dim3>::value && IsFabProjection<Proj,FAB>::value)
689CommHandler
690FillBoundary_nowait (FabArray<FAB>& mf, const FabArrayBase::CommMetaData& cmd,
691 int scomp, int ncomp, DTOS const& dtos, Proj const& proj)
692{
693 BL_PROFILE("FillBoundary_nowait(cmd)");
694 AMREX_ASSERT(scomp < mf.nComp() && scomp+ncomp <= mf.nComp());
695 return Comm_nowait(mf, scomp, ncomp, cmd, dtos, proj);
696}
697
698template <BaseFabType FAB, typename DTOS, typename Proj>
699requires (IsCallableR<Dim3,DTOS,Dim3>::value && IsFabProjection<Proj,FAB>::value)
700void
701FillBoundary_finish (CommHandler handler,
702 FabArray<FAB>& mf, const FabArrayBase::CommMetaData& cmd,
703 int scomp, int ncomp, DTOS const& dtos, Proj const& proj)
704{
705#ifdef AMREX_USE_MPI
706 BL_PROFILE("FillBoundary_finish(cmd)");
707 Comm_finish(mf, scomp, ncomp, cmd, std::move(handler), dtos, proj);
708#else
709 amrex::ignore_unused(handler,mf,cmd,scomp,ncomp,dtos,proj);
710#endif
711}
712
713template <typename DTOS>
714Vector<std::pair<Box,Box>>
715get_src_dst_boxes (DTOS const& dtos, Box const& dstbox, Box const& domain)
716{
717 Vector<std::pair<Box,Box>> r;
718 IntVect mapped_smallend(dtos(amrex::lbound(dstbox)));
719 IntVect mapped_bigend (dtos(amrex::ubound(dstbox)));
720 if (!domain.contains(mapped_smallend) || !domain.contains(mapped_bigend)) {
721 return r;
722 }
723
724 auto sign = dtos.sign(amrex::lbound(dstbox));
725 auto perm = dtos.permutation(amrex::lbound(dstbox));
726 auto dtype = dstbox.type();
727 IntVect stype{AMREX_D_DECL(dtype[perm[0]],
728 dtype[perm[1]],
729 dtype[perm[2]])};
730 Array<Array<std::pair<int,int>,2>,AMREX_SPACEDIM> ends;
731 Array<Array<std::pair<int,int>,2>,AMREX_SPACEDIM> dst_ends;
732 Array<int,AMREX_SPACEDIM> nboxes;
733 for (int ddim = 0; ddim < AMREX_SPACEDIM; ++ddim) {
734 int sdim = perm[ddim];
735 auto mm = std::minmax(mapped_smallend[sdim],mapped_bigend[sdim]);
736 if (((sign[ddim] > 0) && (mapped_smallend[sdim] <= mapped_bigend[sdim])) ||
737 ((sign[ddim] < 0) && (mapped_bigend[sdim] <= mapped_smallend[sdim])))
738 {
739 nboxes[sdim] = 1;
740 ends[sdim][0] = mm;
741 dst_ends[ddim][0] = std::make_pair(dstbox.smallEnd(ddim),
742 dstbox.bigEnd(ddim));
743 } else {
744 nboxes[sdim] = 2;
745 ends[sdim][0].first = domain.smallEnd(sdim);
746 ends[sdim][0].second = mm.first;
747 ends[sdim][1].first = mm.second;
748 ends[sdim][1].second = domain.bigEnd(sdim);
749 int n0 = ends[sdim][0].second - ends[sdim][0].first;
750 int n1 = ends[sdim][1].second - ends[sdim][1].first;
751 if (mm.first == mapped_smallend[sdim]) {
752 dst_ends[ddim][0] = std::make_pair(dstbox.smallEnd(ddim),
753 dstbox.smallEnd(ddim)+n0);
754 dst_ends[ddim][1] = std::make_pair(dstbox.bigEnd(ddim)-n1,
755 dstbox.bigEnd(ddim));
756 } else {
757 dst_ends[ddim][0] = std::make_pair(dstbox.bigEnd(ddim)-n0,
758 dstbox.bigEnd(ddim));
759 dst_ends[ddim][1] = std::make_pair(dstbox.smallEnd(ddim),
760 dstbox.smallEnd(ddim)+n1);
761 }
762 }
763 }
764
765 r.reserve(AMREX_D_TERM(nboxes[0],*nboxes[1],*nboxes[2]));
766
767#if (AMREX_SPACEDIM == 3)
768 for (int kbox = 0; kbox < nboxes[2]; ++kbox) {
769#endif
770#if (AMREX_SPACEDIM >=2 )
771 for (int jbox = 0; jbox < nboxes[1]; ++jbox) {
772#endif
773 for (int ibox = 0; ibox < nboxes[0]; ++ibox)
774 {
775 IntVect siv(AMREX_D_DECL(ibox,jbox,kbox));
776 IntVect div(AMREX_D_DECL(siv[perm[0]],siv[perm[1]],siv[perm[2]]));
777 r.emplace_back(Box(IntVect(AMREX_D_DECL(ends[0][ibox].first,
778 ends[1][jbox].first,
779 ends[2][kbox].first)),
780 IntVect(AMREX_D_DECL(ends[0][ibox].second,
781 ends[1][jbox].second,
782 ends[2][kbox].second)),
783 stype),
784 Box(IntVect(AMREX_D_DECL(dst_ends[0][div[0]].first,
785 dst_ends[1][div[1]].first,
786 dst_ends[2][div[2]].first)),
787 IntVect(AMREX_D_DECL(dst_ends[0][div[0]].second,
788 dst_ends[1][div[1]].second,
789 dst_ends[2][div[2]].second)),
790 dtype));
791 AMREX_D_TERM(},},})
792
793 return r;
794}
795
796template <typename DTOS>
797Box get_dst_subbox (DTOS const& dtos, std::pair<Box,Box> const& sdboxes,
798 Box const& srcsubbox)
799{
800 Box const& srcbox = sdboxes.first;
801 Box const& dstbox = sdboxes.second;
802 if (srcbox == srcsubbox) {
803 return dstbox;
804 } else {
805 auto sign = dtos.sign(amrex::lbound(dstbox));
806 auto perm = dtos.permutation(amrex::lbound(dstbox));
807 Box dstsubbox = dstbox;
808 for (int ddim = 0; ddim < AMREX_SPACEDIM; ++ddim) {
809 int sdim = perm[ddim];
810 if (sign[ddim] > 0) {
811 dstsubbox.growLo(ddim, srcbox.smallEnd(sdim)-srcsubbox.smallEnd(sdim));
812 dstsubbox.growHi(ddim, srcsubbox.bigEnd(sdim)-srcbox.bigEnd(sdim));
813 } else {
814 dstsubbox.growLo(ddim, srcsubbox.bigEnd(sdim)-srcbox.bigEnd(sdim));
815 dstsubbox.growHi(ddim, srcbox.smallEnd(sdim)-srcsubbox.smallEnd(sdim));
816 }
817 }
818 return dstsubbox;
819 }
820}
821
823namespace detail {
824 void split_boxes (BoxList& bl, Box const& domain);
825}
827
828template <BaseFabType FAB, typename DTOS>
829requires (IsCallableR<Dim3,DTOS,Dim3>::value)
830FabArrayBase::CommMetaData
831makeFillBoundaryMetaData (FabArray<FAB>& mf, IntVect const& nghost,
832 Geometry const& geom, DTOS const& dtos)
833{
834 FabArrayBase::CommMetaData cmd;
835 cmd.m_LocTags = std::make_unique<FabArrayBase::CopyComTagsContainer>();
836 cmd.m_SndTags = std::make_unique<FabArrayBase::MapOfCopyComTagContainers>();
837 cmd.m_RcvTags = std::make_unique<FabArrayBase::MapOfCopyComTagContainers>();
838
839 // Normal FillBoundary part
840 mf.define_fb_metadata(cmd, nghost, false, geom.periodicity(), false);
841
842 BoxArray const& ba = mf.boxArray();
843 DistributionMapping const& dm = mf.DistributionMap();
844 Box dombox = amrex::convert(geom.Domain(), ba.ixType());
845 Box pdombox = amrex::convert(geom.growPeriodicDomain(nghost), ba.ixType());
846
847 const int myproc = ParallelDescriptor::MyProc();
848 const auto nboxes = static_cast<int>(ba.size());
849 std::vector<std::pair<int,Box> > isects;
850
851 for (int i = 0; i < nboxes; ++i) {
852 Box const& gbx = amrex::grow(ba[i], nghost);
853 BoxList bl = amrex::boxDiff(gbx, pdombox);
854 if (bl.isEmpty()) { continue; }
855
856 detail::split_boxes(bl, dombox);
857
858 const int dst_owner = dm[i];
859 for (auto const& dst_box : bl) {
860 auto const& src_dst_boxes = get_src_dst_boxes(dtos, dst_box, dombox);
861 for (auto const& sd_box_pair : src_dst_boxes) {
862 ba.intersections(sd_box_pair.first, isects);
863 for (auto const& is : isects) {
864 int const k = is.first;
865 Box const src_b = is.second;
866 int const src_owner = dm[k];
867 if (dst_owner == myproc || src_owner == myproc) {
868 Box const& dst_b = get_dst_subbox(dtos, sd_box_pair, src_b);
869 if (src_owner == dst_owner) {
870 cmd.m_LocTags->emplace_back(dst_b, src_b, i, k);
871 } else {
872 auto& tags = (dst_owner == myproc) ?
873 (*cmd.m_RcvTags)[src_owner] :
874 (*cmd.m_SndTags)[dst_owner];
875 tags.emplace_back(dst_b, src_b, i, k);
876 }
877 }
878 }
879 }
880 }
881 }
882
883 return cmd;
884}
885
886struct SphThetaPhiRIndexMapping
887{
888 SphThetaPhiRIndexMapping (Box const& a_domain)
889 : nx(a_domain.length(0)),
890 ny(a_domain.length(1)),
891 nz(a_domain.length(2))
892 {
893 AMREX_ASSERT(a_domain.smallEnd() == 0);
894 }
895
896 [[nodiscard]] AMREX_GPU_HOST_DEVICE
897 Dim3 operator() (Dim3 const& ijk) const noexcept
898 {
899 const int i = ijk.x;
900 const int j = ijk.y;
901 const int k = ijk.z;
902 bool ilo = i < 0;
903 bool ihi = i >= nx;
904 bool imd = i >= 0 && i < nx;
905 bool jlo = j < 0;
906 bool jhi = j >= ny;
907 bool jmd = j >= 0 && j < ny;
908 bool klo = k < 0;
909 bool kmd = k >= 0 && k < nz;
910 // We do not need to do anything at the theta-lo/r-lo edge,
911 // theta-hi/r-lo edge, and r > r-hi.
912 if (ilo && jmd && kmd)
913 {
914 return Dim3{.x = -1-i, .y = (j+ny/2)%ny, .z = k};
915 }
916 else if (ihi && jmd && kmd)
917 {
918 return Dim3{.x = 2*nx-1-i, .y = (j+ny/2)%ny, .z = k};
919 }
920 else if (imd && jlo && kmd)
921 {
922 return Dim3{.x = i, .y = j+ny, .z = k};
923 }
924 else if (imd && jhi && kmd)
925 {
926 return Dim3{.x = i, .y = j-ny, .z = k};
927 }
928 else if (imd && jmd && klo)
929 {
930 return Dim3{.x = nx-1-i, .y = (j+ny/2)%ny, .z = -1-k};
931 }
932 else if (ilo && jlo && kmd)
933 {
934 return Dim3{.x = -1-i, .y = (j+ny/2)%ny, .z = k};
935 }
936 else if (ihi && jlo && kmd)
937 {
938 return Dim3{.x = 2*nx-1-i, .y = (j+ny/2)%ny, .z = k};
939 }
940 else if (ilo && jhi && kmd)
941 {
942 return Dim3{.x = -1-i, .y = (j+ny/2)%ny, .z = k};
943 }
944 else if (ihi && jhi && kmd)
945 {
946 return Dim3{.x = 2*nx-1-i, .y = (j+ny/2)%ny, .z = k};
947 }
948 else if (imd && jlo && klo)
949 {
950 return Dim3{.x = nx-1-i, .y = (j+ny/2)%ny, .z = -1-k};
951 }
952 else if (imd && jhi && klo)
953 {
954 return Dim3{.x = nx-1-i, .y = (j+ny/2)%ny, .z = -1-k};
955 }
956 else
957 {
958 return ijk;
959 }
960 }
961
962 [[nodiscard]] IntVect sign (Dim3 const& ijk) const noexcept
963 {
964 if (ijk.z < 0) {
965 return IntVect{AMREX_D_DECL(-1, 1,-1)};
966 } else if (ijk.z >=0 && ijk.z < nz &&
967 (ijk.x < 0 || ijk.x >= nx)) {
968 return IntVect{AMREX_D_DECL(-1, 1, 1)};
969 } else {
970 return IntVect{AMREX_D_DECL( 1, 1, 1)};
971 }
972 }
973
974 [[nodiscard]] IntVect permutation (Dim3 const& /*ijk*/) const noexcept // NOLINT(readability-convert-member-functions-to-static)
975 {
976 return IntVect(AMREX_D_DECL(0,1,2));
977 }
978
979private:
980 int nx, ny, nz;
981};
982
983struct SphThetaPhiRComponentMapping
984{
985 SphThetaPhiRComponentMapping (Box const& a_domain, int a_start_index)
986 : nx(a_domain.length(0)),
987 ny(a_domain.length(1)),
988 nz(a_domain.length(2)),
989 scomp(a_start_index) {}
990
991 template <typename T>
992 [[nodiscard]] AMREX_GPU_HOST_DEVICE
993 T operator()(Array4<const T> const& a, Dim3 const& ijk, int n) const noexcept
994 {
995 const int i = ijk.x;
996 const int j = ijk.y;
997 const int k = ijk.z;
998 auto r = a(i,j,k,n);
999 if (n == scomp) {
1000 if ((i >= 0 && i < nx) &&
1001 (j < 0 || j >= ny) &&
1002 (k >= 0 && k < nz)) {
1003 return r;
1004 } else {
1005 // We do not need to worry about the theta-lo/r-lo edge,
1006 // theta-hi/r-lo edge, and r > r-hi.
1007 return -r;
1008 }
1009 } else if (n == scomp+2) {
1010 if (k < 0) {
1011 return -r;
1012 } else {
1013 return r;
1014 }
1015 } else {
1016 return r;
1017 }
1018 }
1019private:
1020 int nx, ny, nz;
1021 int scomp;
1022};
1023
1024extern template MultiBlockCommMetaData ParallelCopy(FabArray<FArrayBox>& dest, const Box& destbox,
1025 const FabArray<FArrayBox>& src, int destcomp,
1026 int srccomp, int numcomp, const IntVect& ngrow,
1027 MultiBlockIndexMapping const&, Identity const&);
1028}
1029
1030#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#define BL_ASSERT(EX)
Definition AMReX_BLassert.H:39
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_HOST_DEVICE_PARALLEL_FOR_4D(...)
Definition AMReX_GpuLaunchMacrosC.nolint.H:111
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
virtual void free(void *pt)=0
Free a previously allocated block pointed to by pt.
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
__host__ __device__ BoxND & setType(const IndexTypeND< dim > &t) noexcept
Set indexing type.
Definition AMReX_Box.H:534
CopyComTag::CopyComTagsContainer CopyComTagsContainer
Definition AMReX_FabArrayBase.H:236
__host__ __device__ Dim3 ubound(Array4< T > const &a) noexcept
Return the inclusive upper bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1365
__host__ __device__ Dim3 length(Array4< T > const &a) noexcept
Return the spatial extents of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1379
__host__ __device__ Dim3 lbound(Array4< T > const &a) noexcept
Return the inclusive lower bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1351
__host__ __device__ BoxND< dim > convert(const BoxND< dim > &b, const IntVectND< dim > &typ) noexcept
Return a copy of b converted to the nodal flags typ.
Definition AMReX_Box.H:1632
__host__ __device__ BoxND< dim > grow(const BoxND< dim > &b, int i) noexcept
Return a copy of b grown uniformly by i cells in every direction.
Definition AMReX_Box.H:1328
Arena * The_Arena()
Definition AMReX_Arena.cpp:839
Definition AMReX_NonLocalBC.cpp:39
void Rotate90(FabArray< FAB > &mf, int scomp, int ncomp, IntVect const &nghost, Box const &domain)
void unpack_recv_buffer_cpu(FabArray< FAB > &mf, int dcomp, int ncomp, Vector< char * > const &recv_data, Vector< std::size_t > const &recv_size, Vector< FabArrayBase::CopyComTagsContainer const * > const &recv_cctc, DTOS const &dtos=DTOS{}, Proj const &proj=Proj{}) noexcept
Box InverseImage(DTOS const &dtos, const Box &box)
Applies the inverse Dim3 to Dim3 mapping onto Boxes without changing the index type.
Definition AMReX_NonLocalBC.H:189
void Rotate180(FabArray< FAB > &mf, int scomp, int ncomp, IntVect const &nghost, Box const &domain)
void local_copy_cpu(FabArray< FAB > &dest, const FabArray< FAB > &src, int dcomp, int scomp, int ncomp, FabArrayBase::CopyComTagsContainer const &local_tags, DTOS const &dtos=DTOS{}, Proj const &proj=Proj{}) noexcept
void FillPolar(FabArray< FAB > &mf, int scomp, int ncomp, IntVect const &nghost, Box const &domain)
void local_copy_gpu(FabArray< FAB > &dest, const FabArray< FAB > &src, int dcomp, int scomp, int ncomp, FabArrayBase::CopyComTagsContainer const &local_tags, DTOS const &dtos=DTOS{}, Proj const &proj=Proj{}) noexcept
Box Image(DTOS const &dtos, const Box &box)
Applies the Dim3 to Dim3 mapping onto Boxes but does not change the index type.
Definition AMReX_NonLocalBC.H:123
void unpack_recv_buffer_gpu(FabArray< FAB > &mf, int scomp, int ncomp, Vector< char * > const &recv_data, Vector< std::size_t > const &recv_size, Vector< FabArrayBase::CopyComTagsContainer const * > const &recv_cctc, DTOS const &dtos=DTOS{}, Proj const &proj=Proj{})
int SeqNum() noexcept
Returns sequential message sequence numbers, usually used as tags for send/recv.
Definition AMReX_ParallelDescriptor.H:678
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
__host__ __device__ Array4< T > makeArray4(T *p, Box const &bx, int ncomp) noexcept
Definition AMReX_BaseFab.H:123
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
BoxList boxDiff(const Box &b1in, const Box &b2)
Returns a BoxList defining the complement of b2 in b1in.
Definition AMReX_BoxList.cpp:610
void ParallelCopy(MF &dst, MF const &src, int scomp, int dcomp, int ncomp, IntVect const &ng_src=IntVect(0), IntVect const &ng_dst=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic())
dst = src w/ MPI communication
Definition AMReX_FabArrayUtility.H:2256
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
void LoopConcurrentOnCpu(Dim3 lo, Dim3 hi, F const &f) noexcept
Definition AMReX_Loop.H:388
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:244
This type trait tests if a type P is a projection for FAB.
Definition AMReX_NonLocalBC.H:282