Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_FabArrayCommI.H
Go to the documentation of this file.
1
2#include <AMReX_FBI.H>
3#include <AMReX_PCI.H>
4
11namespace amrex {
12
13template <class FAB>
14template <typename BUF, class F>
15requires (BaseFabType<F>)
16void
17FabArray<FAB>::FBEP_nowait (int scomp, int ncomp, const IntVect& nghost,
18 const Periodicity& period, bool cross,
19 bool enforce_periodicity_only,
20 bool override_sync,
21 IntVect const& sumboundary_src_nghost,
22 bool deterministic) // so far the deterministic is for sumboundary only
23{
24 BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: FB");
25 BL_PROFILE("FillBoundary_nowait()");
26
27 AMREX_ASSERT_WITH_MESSAGE(!fbd, "FillBoundary_nowait() called when comm operation already in progress.");
28 AMREX_ASSERT(!enforce_periodicity_only || !override_sync);
29
30 bool sumboundary = sumboundary_src_nghost.allGE(0);
31
32 bool work_to_do;
33 if (enforce_periodicity_only) {
34 work_to_do = period.isAnyPeriodic();
35 } else if (override_sync) {
36 work_to_do = (nghost.max() > 0) || !is_cell_centered();
37 } else if (sumboundary) {
38 work_to_do = true;
39 } else {
40 work_to_do = nghost.max() > 0;
41 }
42 if (!work_to_do) { return; }
43
44 const FB& TheFB = getFB(nghost, period, cross, enforce_periodicity_only, override_sync, sumboundary_src_nghost);
45
47 {
48 //
49 // There can only be local work to do.
50 //
51 int N_locs = (*TheFB.m_LocTags).size();
52 if (N_locs == 0) { return; }
53#ifdef AMREX_USE_GPU
55 {
56#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
57 if (Gpu::inGraphRegion() && !sumboundary)
58 {
59 FB_local_copy_cuda_graph_1(TheFB, scomp, ncomp);
60 }
61 else
62#endif
63 {
64 if (sumboundary) {
66 FB_local_add_gpu(TheFB, scomp, ncomp, deterministic);
67 } else {
68 amrex::Abort("SumBoundary requires operator+=");
69 }
70 } else {
71 FB_local_copy_gpu(TheFB, scomp, ncomp);
72 if (!Gpu::inNoSyncRegion()) {
74 }
75 }
76 }
77 }
78 else
79#endif
80 {
81 if (sumboundary) {
83 FB_local_add_cpu(TheFB, scomp, ncomp);
84 } else {
85 amrex::Abort("SumBoundary requires operator+=");
86 }
87 } else {
88 FB_local_copy_cpu(TheFB, scomp, ncomp);
89 }
90 }
91
92 return;
93 }
94
95#ifdef BL_USE_MPI
96
97 //
98 // Do this before prematurely exiting if running in parallel.
99 // Otherwise sequence numbers will not match across MPI processes.
100 //
101 int SeqNum = ParallelDescriptor::SeqNum();
102
103 const int N_locs = TheFB.m_LocTags->size();
104 const int N_rcvs = TheFB.m_RcvTags->size();
105 const int N_snds = TheFB.m_SndTags->size();
106
107 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
108 // No work to do.
109 return;
110 }
111
112 fbd = std::make_unique<FBData<FAB>>();
113 fbd->fb = &TheFB;
114 fbd->scomp = scomp;
115 fbd->ncomp = ncomp;
116 fbd->tag = SeqNum;
117 fbd->deterministic = deterministic;
118
119 //
120 // Post rcvs. Allocate one chunk of space to hold'm all.
121 //
122
123 if (N_rcvs > 0) {
124 PostRcvs<BUF>(*TheFB.m_RcvTags, fbd->the_recv_data,
125 fbd->recv_data, fbd->recv_size, fbd->recv_from, fbd->recv_reqs,
126 ncomp, SeqNum);
127 fbd->recv_stat.resize(N_rcvs);
128 }
129
130 //
131 // Post send's
132 //
133 char*& the_send_data = fbd->the_send_data;
134 Vector<char*> & send_data = fbd->send_data;
135 Vector<std::size_t> send_size;
136 Vector<int> send_rank;
137 Vector<MPI_Request>& send_reqs = fbd->send_reqs;
139
140 if (N_snds > 0)
141 {
142 PrepareSendBuffers<BUF>(*TheFB.m_SndTags, the_send_data, send_data, send_size, send_rank,
143 send_reqs, send_cctc, ncomp);
144
145#ifdef AMREX_USE_GPU
147 {
148#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
149 if (Gpu::inGraphRegion()) {
150 FB_pack_send_buffer_cuda_graph(TheFB, scomp, ncomp, send_data, send_size, send_cctc);
151 }
152 else
153#endif
154 {
155 pack_send_buffer_gpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc, TheFB.m_id);
156 }
157 }
158 else
159#endif
160 {
161 pack_send_buffer_cpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc);
162 }
163
164 AMREX_ASSERT(send_reqs.size() == N_snds);
165 PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
166 }
167
168 FillBoundary_test();
169
170 //
171 // Do the local work. Hope for a bit of communication/computation overlap.
172 //
173 if (N_locs > 0)
174 {
175#ifdef AMREX_USE_GPU
177 {
178#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
179 if (Gpu::inGraphRegion() && !sumboundary) {
180 FB_local_copy_cuda_graph_n(TheFB, scomp, ncomp);
181 }
182 else
183#endif
184 {
185 if (sumboundary) {
187 FB_local_add_gpu(TheFB, scomp, ncomp, deterministic);
188 } else {
189 amrex::Abort("SumBoundary requires operator+=");
190 }
191 } else {
192 FB_local_copy_gpu(TheFB, scomp, ncomp);
193 if (!Gpu::inNoSyncRegion() && N_rcvs == 0) {
195 }
196 }
197 }
198 }
199 else
200#endif
201 {
202 if (sumboundary) {
204 FB_local_add_cpu(TheFB, scomp, ncomp);
205 } else {
206 amrex::Abort("SumBoundary requires operator+=");
207 }
208 } else {
209 FB_local_copy_cpu(TheFB, scomp, ncomp);
210 }
211 }
212
213 FillBoundary_test();
214 }
215
216#endif /*BL_USE_MPI*/
217
218#ifndef AMREX_USE_GPU
219 amrex::ignore_unused(deterministic);
220#endif
221}
222
223template <class FAB>
224template <typename BUF, class F>
225requires (BaseFabType<F>)
226void
228{
229#ifdef AMREX_USE_MPI
230
231 BL_PROFILE("FillBoundary_finish()");
233
234 if (!fbd) { n_filled = IntVect::TheZeroVector(); return; }
235
236 const FB* TheFB = fbd->fb;
237 bool sumboundary = TheFB->m_sb_snghost.allGE(0);
238 const auto N_rcvs = static_cast<int>(TheFB->m_RcvTags->size());
239 if (N_rcvs > 0)
240 {
241 Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
242 for (int k = 0; k < N_rcvs; k++)
243 {
244 if (fbd->recv_size[k] > 0)
245 {
246 auto const& cctc = TheFB->m_RcvTags->at(fbd->recv_from[k]);
247 recv_cctc[k] = &cctc;
248 }
249 }
250
251 int actual_n_rcvs = N_rcvs - std::ranges::count(fbd->recv_data, nullptr);
252
253 if (actual_n_rcvs > 0) {
254 ParallelDescriptor::Waitall(fbd->recv_reqs, fbd->recv_stat);
255#ifdef AMREX_DEBUG
256 if (!CheckRcvStats(fbd->recv_stat, fbd->recv_size, fbd->tag))
257 {
258 amrex::Abort("FillBoundary_finish failed with wrong message size");
259 }
260#endif
261 }
262
263 bool is_thread_safe = TheFB->m_threadsafe_rcv;
264 auto op = sumboundary ? FabArrayBase::ADD : FabArrayBase::COPY;
265
266#ifdef AMREX_USE_GPU
268 {
269#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
270 if (Gpu::inGraphRegion() && !sumboundary)
271 {
272 FB_unpack_recv_buffer_cuda_graph(*TheFB, fbd->scomp, fbd->ncomp,
273 fbd->recv_data, fbd->recv_size,
274 recv_cctc, is_thread_safe);
275 }
276 else
277#endif
278 {
279 bool deterministic = fbd->deterministic;
280 unpack_recv_buffer_gpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
281 recv_cctc, op, is_thread_safe, TheFB->m_id, deterministic);
282 }
283 }
284 else
285#endif
286 {
287 unpack_recv_buffer_cpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
288 recv_cctc, op, is_thread_safe);
289 }
290
291 if (fbd->the_recv_data)
292 {
293 amrex::The_Comms_Arena()->free(fbd->the_recv_data);
294 fbd->the_recv_data = nullptr;
295 }
296 }
297
298 const auto N_snds = static_cast<int>(TheFB->m_SndTags->size());
299 if (N_snds > 0) {
300 Vector<MPI_Status> stats(fbd->send_reqs.size());
301 ParallelDescriptor::Waitall(fbd->send_reqs, stats);
302 amrex::The_Comms_Arena()->free(fbd->the_send_data);
303 fbd->the_send_data = nullptr;
304 }
305
306 fbd.reset();
307
308#endif
309}
310
311template <class FAB>
312void
314 int scomp,
315 int dcomp,
316 int ncomp,
317 const IntVect& snghost,
318 const IntVect& dnghost,
319 const Periodicity& period,
320 CpOp op,
321 const FabArrayBase::CPC * a_cpc,
322 bool deterministic)
323{
324 BL_PROFILE("FabArray::ParallelCopy()");
325
326 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period, op, a_cpc,
327 false, deterministic);
328 ParallelCopy_finish();
329}
330
331template <class FAB>
332void
333FabArray<FAB>::ParallelCopy (const FabArray<FAB>& src, int src_comp, int dest_comp,
334 int num_comp, const IntVect& snghost, const IntVect& dnghost,
335 const IntVect& offset, const Periodicity& period)
336{
337 BL_PROFILE("FabArray::ParallelCopy()");
338
339 ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,snghost,dnghost,offset,period);
340 ParallelCopy_finish();
341}
342
343template <class FAB>
344void
345FabArray<FAB>::ParallelAdd (const FabArray<FAB>& src, int src_comp, int dest_comp,
346 int num_comp, const IntVect& snghost, const IntVect& dnghost,
347 const IntVect& offset, const Periodicity& period)
348{
349 BL_PROFILE("FabArray::ParallelAdd()");
350
351 ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,snghost,dnghost,offset,period,
353 ParallelCopy_finish();
354}
355
356template <class FAB>
357void
359 int scomp,
360 int dcomp,
361 int ncomp,
362 const IntVect& snghost,
363 const IntVect& dnghost,
364 const Periodicity& period)
365{
366 BL_PROFILE("FabArray::ParallelCopyToGhost()");
367
368 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
369 FabArrayBase::COPY, nullptr, true);
370 ParallelCopy_finish();
371}
372
373template <class FAB>
374void
376 int scomp,
377 int dcomp,
378 int ncomp,
379 const IntVect& snghost,
380 const IntVect& dnghost,
381 const Periodicity& period)
382{
383 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
384 FabArrayBase::COPY, nullptr, true);
385}
386
387template <class FAB>
388void
390{
391 ParallelCopy_finish();
392}
393
394
395template <class FAB>
396void
398 int scomp,
399 int dcomp,
400 int ncomp,
401 const IntVect& snghost,
402 const IntVect& dnghost,
403 const Periodicity& period,
404 CpOp op,
405 const FabArrayBase::CPC * a_cpc,
406 bool to_ghost_cells_only,
407 bool deterministic)
408{
409 ParallelCopy_nowait(src,scomp,dcomp,ncomp,snghost,dnghost,IntVect(0),period,op,a_cpc,
410 to_ghost_cells_only, deterministic);
411}
412
413template <class FAB>
414void
416 int scomp,
417 int dcomp,
418 int ncomp,
419 const IntVect& snghost,
420 const IntVect& dnghost,
421 const IntVect& offset,
422 const Periodicity& period,
423 CpOp op,
424 const FabArrayBase::CPC * a_cpc,
425 bool to_ghost_cells_only,
426 bool deterministic)
427{
428 BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: PC");
429 BL_PROFILE("FabArray::ParallelCopy_nowait()");
430
431 AMREX_ASSERT_WITH_MESSAGE(!pcd, "ParallelCopy_nowait() called when comm operation already in progress.");
432
433 if (empty() || src.empty()) {
434 return;
435 }
436
438 BL_ASSERT(boxArray().ixType() == src.boxArray().ixType());
439 BL_ASSERT(src.nGrowVect().allGE(snghost));
440 BL_ASSERT( nGrowVect().allGE(dnghost));
441
442 n_filled = dnghost;
443
444 if ((ParallelDescriptor::NProcs() == 1) &&
445 (this->size() == 1) && (src.size() == 1) &&
446 !period.isAnyPeriodic() && !to_ghost_cells_only && (offset == 0))
447 {
448 if (this != &src) { // avoid self copy or plus
449 auto const& da = this->array(0, dcomp);
450 auto const& sa = src.const_array(0, scomp);
451 Box box = amrex::grow(src.box(0),snghost)
452 & amrex::grow(this->box(0),dnghost);
453 if (op == FabArrayBase::COPY) {
454#ifdef AMREX_USE_GPU
455 if (Gpu::inLaunchRegion()) {
456 ParallelFor(box, ncomp,
457 [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
458 da(i,j,k,n) = sa(i,j,k,n);
459 });
460 if (!Gpu::inNoSyncRegion()) {
462 }
463 } else
464#endif
465 {
466 auto const& lo = amrex::lbound(box);
467 auto const& hi = amrex::ubound(box);
468#ifdef AMREX_USE_OMP
469#pragma omp parallel for collapse(3)
470#endif
471 for (int n = 0; n < ncomp; ++n) {
472 for (int k = lo.z; k <= hi.z; ++k) {
473 for (int j = lo.y; j <= hi.y; ++j) {
475 for (int i = lo.x; i <= hi.x; ++i) {
476 da(i,j,k,n) = sa(i,j,k,n);
477 }}}}
478 }
479 } else {
480#ifdef AMREX_USE_GPU
481 if (Gpu::inLaunchRegion()) {
482 ParallelFor(box, ncomp,
483 [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
484 da(i,j,k,n) += sa(i,j,k,n);
485 });
486 if (!Gpu::inNoSyncRegion()) {
488 }
489 } else
490#endif
491 {
492 auto const& lo = amrex::lbound(box);
493 auto const& hi = amrex::ubound(box);
494#ifdef AMREX_USE_OMP
495#pragma omp parallel for collapse(3)
496#endif
497 for (int n = 0; n < ncomp; ++n) {
498 for (int k = lo.z; k <= hi.z; ++k) {
499 for (int j = lo.y; j <= hi.y; ++j) {
501 for (int i = lo.x; i <= hi.x; ++i) {
502 da(i,j,k,n) += sa(i,j,k,n);
503 }}}}
504 }
505 }
506 }
507 return;
508 }
509
510 if ((src.boxArray().ixType().cellCentered() || op == FabArrayBase::COPY) &&
511 (boxarray == src.boxarray && distributionMap == src.distributionMap) &&
512 snghost == IntVect::TheZeroVector() &&
513 dnghost == IntVect::TheZeroVector() &&
514 !period.isAnyPeriodic() && !to_ghost_cells_only && (offset == 0))
515 {
516 //
517 // Short-circuit full intersection code if we're doing copy()s or if
518 // we're doing plus()s on cell-centered data. Don't do plus()s on
519 // non-cell-centered data this simplistic way.
520 //
521 if (this != &src) { // avoid self copy or plus
522 if (op == FabArrayBase::COPY) {
523 Copy(*this, src, scomp, dcomp, ncomp, IntVect(0));
524 } else {
525 Add(*this, src, scomp, dcomp, ncomp, IntVect(0));
526 }
527 }
528 return;
529 }
530
531 const CPC& thecpc = (a_cpc) ? *a_cpc : getCPC(dnghost, src, snghost, period,
532 to_ghost_cells_only,offset);
533
535 {
536 //
537 // There can only be local work to do.
538 //
539
540 int N_locs = (*thecpc.m_LocTags).size();
541 if (N_locs == 0) { return; }
542#ifdef AMREX_USE_GPU
544 {
545 PC_local_gpu(thecpc, src, scomp, dcomp, ncomp, op,
546 deterministic && (op == FabArrayBase::ADD));
547 }
548 else
549#endif
550 {
551 PC_local_cpu(thecpc, src, scomp, dcomp, ncomp, op);
552 }
553
554 return;
555 }
556
557#ifdef BL_USE_MPI
558
559 //
560 // Do this before prematurely exiting if running in parallel.
561 // Otherwise sequence numbers will not match across MPI processes.
562 //
563 int tag = ParallelDescriptor::SeqNum();
564
565 const int N_snds = thecpc.m_SndTags->size();
566 const int N_rcvs = thecpc.m_RcvTags->size();
567 const int N_locs = thecpc.m_LocTags->size();
568
569 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
570 //
571 // No work to do.
572 //
573
574 return;
575 }
576
577 //
578 // Send/Recv at most MaxComp components at a time to cut down memory usage.
579 //
580 int NCompLeft = ncomp;
581 int SC = scomp, DC = dcomp, NC;
582
583 for (int ipass = 0; ipass < ncomp; )
584 {
585 pcd = std::make_unique<PCData<FAB>>();
586 pcd->cpc = &thecpc;
587 pcd->src = &src;
588 pcd->op = op;
589 pcd->tag = tag;
590 // Deterministic GPU unpacking is currently implemented only for ADD.
591 pcd->deterministic = deterministic && (op == FabArrayBase::ADD);
592
593 NC = std::min(NCompLeft,FabArrayBase::MaxComp);
594 const bool last_iter = (NCompLeft == NC);
595
596 pcd->SC = SC;
597 pcd->DC = DC;
598 pcd->NC = NC;
599
600 //
601 // Post rcvs. Allocate one chunk of space to hold'm all.
602 //
603 pcd->the_recv_data = nullptr;
604
605 pcd->actual_n_rcvs = 0;
606 if (N_rcvs > 0) {
607 PostRcvs(*thecpc.m_RcvTags, pcd->the_recv_data,
608 pcd->recv_data, pcd->recv_size, pcd->recv_from, pcd->recv_reqs, NC, pcd->tag);
609 pcd->actual_n_rcvs = N_rcvs - std::ranges::count(pcd->recv_size, 0);
610 }
611
612 //
613 // Post send's
614 //
615 Vector<char*> send_data;
616 Vector<std::size_t> send_size;
617 Vector<int> send_rank;
619
620 if (N_snds > 0)
621 {
622 src.PrepareSendBuffers(*thecpc.m_SndTags, pcd->the_send_data, send_data, send_size,
623 send_rank, pcd->send_reqs, send_cctc, NC);
624
625#ifdef AMREX_USE_GPU
627 {
628 pack_send_buffer_gpu(src, SC, NC, send_data, send_size, send_cctc, thecpc.m_id);
629 }
630 else
631#endif
632 {
633 pack_send_buffer_cpu(src, SC, NC, send_data, send_size, send_cctc);
634 }
635
636 AMREX_ASSERT(pcd->send_reqs.size() == N_snds);
637 FabArray<FAB>::PostSnds(send_data, send_size, send_rank, pcd->send_reqs, pcd->tag);
638 }
639
640 //
641 // Do the local work. Hope for a bit of communication/computation overlap.
642 //
643 if (N_locs > 0)
644 {
645#ifdef AMREX_USE_GPU
647 {
648 PC_local_gpu(thecpc, src, SC, DC, NC, op,
649 deterministic && (op == FabArrayBase::ADD));
650 }
651 else
652#endif
653 {
654 PC_local_cpu(thecpc, src, SC, DC, NC, op);
655 }
656 }
657
658 if (!last_iter)
659 {
660 ParallelCopy_finish();
661
662 SC += NC;
663 DC += NC;
664 }
665
666 ipass += NC;
667 NCompLeft -= NC;
668 }
669
670#endif /*BL_USE_MPI*/
671
672#ifndef AMREX_USE_GPU
673 amrex::ignore_unused(deterministic);
674#endif
675}
676
677template <class FAB>
678void
680{
681
682#ifdef BL_USE_MPI
683
684 BL_PROFILE("FabArray::ParallelCopy_finish()");
686
687 if (!pcd) { return; }
688
689 const CPC* thecpc = pcd->cpc;
690
691 const auto N_snds = static_cast<int>(thecpc->m_SndTags->size());
692 const auto N_rcvs = static_cast<int>(thecpc->m_RcvTags->size());
693
694 if (N_rcvs > 0)
695 {
696 Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
697 for (int k = 0; k < N_rcvs; ++k)
698 {
699 if (pcd->recv_size[k] > 0)
700 {
701 auto const& cctc = thecpc->m_RcvTags->at(pcd->recv_from[k]);
702 recv_cctc[k] = &cctc;
703 }
704 }
705
706 if (pcd->actual_n_rcvs > 0) {
707 Vector<MPI_Status> stats(N_rcvs);
708 ParallelDescriptor::Waitall(pcd->recv_reqs, stats);
709#ifdef AMREX_DEBUG
710 if (!CheckRcvStats(stats, pcd->recv_size, pcd->tag))
711 {
712 amrex::Abort("ParallelCopy failed with wrong message size");
713 }
714#endif
715 }
716
717 bool is_thread_safe = thecpc->m_threadsafe_rcv;
718
719#ifdef AMREX_USE_GPU
721 {
722 unpack_recv_buffer_gpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
723 recv_cctc, pcd->op, is_thread_safe, thecpc->m_id,
724 pcd->deterministic);
725 }
726 else
727#endif
728 {
729 unpack_recv_buffer_cpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
730 recv_cctc, pcd->op, is_thread_safe);
731 }
732
733 if (pcd->the_recv_data)
734 {
735 amrex::The_Comms_Arena()->free(pcd->the_recv_data);
736 pcd->the_recv_data = nullptr;
737 }
738 }
739
740 if (N_snds > 0) {
741 if (! thecpc->m_SndTags->empty()) {
742 Vector<MPI_Status> stats(pcd->send_reqs.size());
743 ParallelDescriptor::Waitall(pcd->send_reqs, stats);
744 }
745 amrex::The_Comms_Arena()->free(pcd->the_send_data);
746 pcd->the_send_data = nullptr;
747 }
748
749 pcd.reset();
750
751#endif /*BL_USE_MPI*/
752}
753
754template <class FAB>
755void
756FabArray<FAB>::copyTo (FAB& dest, int scomp, int dcomp, int ncomp, int nghost) const
757{
758 BL_PROFILE("FabArray::copy(fab)");
759
760 BL_ASSERT(dcomp + ncomp <= dest.nComp());
761 BL_ASSERT(IntVect(nghost).allLE(nGrowVect()));
762
763 int root_proc = this->DistributionMap()[0];
764
765 BoxArray ba(dest.box());
766 DistributionMapping dm(Vector<int>{root_proc});
767 FabArray<FAB> destmf(ba, dm, ncomp, 0, MFInfo().SetAlloc(false));
768 if (ParallelDescriptor::MyProc() == root_proc) {
769 destmf.setFab(0, FAB(dest, amrex::make_alias, dcomp, ncomp));
770 }
771
772 destmf.ParallelCopy(*this, scomp, 0, ncomp, nghost, 0);
773
774#ifdef BL_USE_MPI
775 using T = typename FAB::value_type;
776 if (ParallelContext::NProcsSub() > 1) {
777 Long count = dest.numPts()*ncomp;
778 T* const p0 = dest.dataPtr(dcomp);
779 T* pb = p0;
780#ifdef AMREX_USE_GPU
781 if (dest.arena()->isDevice() && !ParallelDescriptor::UseGpuAwareMpi()) {
782 pb = (T*)The_Pinned_Arena()->alloc(sizeof(T)*count);
783 Gpu::dtoh_memcpy_async(pb, p0, sizeof(T)*count);
785 }
786#endif
789#ifdef AMREX_USE_GPU
790 if (pb != p0) {
791 Gpu::htod_memcpy_async(p0, pb, sizeof(T)*count);
793 The_Pinned_Arena()->free(pb);
794 }
795#endif
796 }
797#endif
798}
799
800#ifdef BL_USE_MPI
801template <class FAB>
802template <typename BUF>
803[[nodiscard]] TheFaArenaPointer
804FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers& SndTags,
805 Vector<char*>& send_data,
806 Vector<std::size_t>& send_size,
807 Vector<int>& send_rank,
808 Vector<MPI_Request>& send_reqs,
810 int ncomp)
811{
812 char* pointer = nullptr;
813 PrepareSendBuffers<BUF>(SndTags, pointer, send_data, send_size, send_rank, send_reqs, send_cctc, ncomp);
814 return TheFaArenaPointer(pointer);
815}
816
817template <class FAB>
818template <typename BUF>
819void
820FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers& SndTags,
821 char*& the_send_data,
822 Vector<char*>& send_data,
823 Vector<std::size_t>& send_size,
824 Vector<int>& send_rank,
825 Vector<MPI_Request>& send_reqs,
826 Vector<const CopyComTagsContainer*>& send_cctc,
827 int ncomp)
828{
829 send_data.clear();
830 send_size.clear();
831 send_rank.clear();
832 send_reqs.clear();
833 send_cctc.clear();
834 const auto N_snds = SndTags.size();
835 if (N_snds == 0) { return; }
836 send_data.reserve(N_snds);
837 send_size.reserve(N_snds);
838 send_rank.reserve(N_snds);
839 send_reqs.reserve(N_snds);
840 send_cctc.reserve(N_snds);
841
842 Vector<std::size_t> offset; offset.reserve(N_snds);
843 std::size_t total_volume = 0;
844 for (auto const& kv : SndTags)
845 {
846 auto const& cctc = kv.second;
847
848 std::size_t nbytes = 0;
849 for (auto const& cct : kv.second)
850 {
851 nbytes += cct.sbox.numPts() * ncomp * sizeof(BUF);
852 }
853
854 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
855 nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
856
857 // Also need to align the offset properly
858 total_volume = amrex::aligned_size(std::max(alignof(BUF), acd),
859 total_volume);
860
861 offset.push_back(total_volume);
862 total_volume += nbytes;
863
864 send_data.push_back(nullptr);
865 send_size.push_back(nbytes);
866 send_rank.push_back(kv.first);
867 send_reqs.push_back(MPI_REQUEST_NULL);
868 send_cctc.push_back(&cctc);
869 }
870
871 if (total_volume > 0)
872 {
873 the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(total_volume));
874 for (int i = 0, N = static_cast<int>(send_size.size()); i < N; ++i) {
875 send_data[i] = the_send_data + offset[i];
876 }
877 } else {
878 the_send_data = nullptr;
879 }
880}
881
882template <class FAB>
883void
884FabArray<FAB>::PostSnds (Vector<char*> const& send_data,
885 Vector<std::size_t> const& send_size,
886 Vector<int> const& send_rank,
887 Vector<MPI_Request>& send_reqs,
888 int SeqNum)
889{
891
892 const auto N_snds = static_cast<int>(send_reqs.size());
893 for (int j = 0; j < N_snds; ++j)
894 {
895 if (send_size[j] > 0) {
896 const int rank = ParallelContext::global_to_local_rank(send_rank[j]);
897 send_reqs[j] = ParallelDescriptor::Asend
898 (send_data[j], send_size[j], rank, SeqNum, comm).req();
899 }
900 }
901}
902
903template <class FAB>
904template <typename BUF>
905TheFaArenaPointer FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers& RcvTags,
906 Vector<char*>& recv_data,
907 Vector<std::size_t>& recv_size,
908 Vector<int>& recv_from,
909 Vector<MPI_Request>& recv_reqs,
910 int ncomp,
911 int SeqNum)
912{
913 char* pointer = nullptr;
914 PostRcvs(RcvTags, pointer, recv_data, recv_size, recv_from, recv_reqs, ncomp, SeqNum);
915 return TheFaArenaPointer(pointer);
916}
917
918template <class FAB>
919template <typename BUF>
920void
921FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers& RcvTags,
922 char*& the_recv_data,
923 Vector<char*>& recv_data,
924 Vector<std::size_t>& recv_size,
925 Vector<int>& recv_from,
926 Vector<MPI_Request>& recv_reqs,
927 int ncomp,
928 int SeqNum)
929{
930 recv_data.clear();
931 recv_size.clear();
932 recv_from.clear();
933 recv_reqs.clear();
934
935 Vector<std::size_t> offset;
936 std::size_t TotalRcvsVolume = 0;
937 for (const auto& kv : RcvTags) // loop over senders
938 {
939 std::size_t nbytes = 0;
940 for (auto const& cct : kv.second)
941 {
942 nbytes += cct.dbox.numPts() * ncomp * sizeof(BUF);
943 }
944
945 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
946 nbytes = amrex::aligned_size(acd, nbytes); // so that nbytes are aligned
947
948 // Also need to align the offset properly
949 TotalRcvsVolume = amrex::aligned_size(std::max(alignof(BUF),acd),
950 TotalRcvsVolume);
951
952 offset.push_back(TotalRcvsVolume);
953 TotalRcvsVolume += nbytes;
954
955 recv_data.push_back(nullptr);
956 recv_size.push_back(nbytes);
957 recv_from.push_back(kv.first);
958 recv_reqs.push_back(MPI_REQUEST_NULL);
959 }
960
961 const auto nrecv = static_cast<int>(recv_from.size());
962
964
965 if (TotalRcvsVolume == 0)
966 {
967 the_recv_data = nullptr;
968 }
969 else
970 {
971 the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
972
973 for (int i = 0; i < nrecv; ++i)
974 {
975 recv_data[i] = the_recv_data + offset[i];
976 if (recv_size[i] > 0)
977 {
978 const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
979 recv_reqs[i] = ParallelDescriptor::Arecv
980 (recv_data[i], recv_size[i], rank, SeqNum, comm).req();
981 }
982 }
983 }
984}
985#endif
986
987template <class FAB>
988void
990 int scomp,
991 int dcomp,
992 int ncomp,
993 const IntVect& nghost)
994{
996 "FabArray::Redistribute: must have the same BoxArray");
997
999 {
1000 Copy(*this, src, scomp, dcomp, ncomp, nghost);
1001 return;
1002 }
1003
1004#ifdef BL_USE_MPI
1005
1007
1008 ParallelCopy(src, scomp, dcomp, ncomp, nghost, nghost, Periodicity::NonPeriodic(),
1009 FabArrayBase::COPY, &cpc);
1010
1011#endif
1012}
1013
1014template <class FAB>
1015void
1017{
1018#if defined(AMREX_USE_MPI) && !defined(AMREX_DEBUG)
1019 // We only test if no DEBUG because in DEBUG we check the status later.
1020 // If Test is done here, the status check will fail.
1021 int flag;
1022 ParallelDescriptor::Test(fbd->recv_reqs, flag, fbd->recv_stat);
1023#endif
1024}
1025
1027namespace detail {
1028template <class TagT>
1029void fbv_copy (Vector<TagT> const& tags)
1030{
1031 const int N = tags.size();
1032 if (N == 0) { return; }
1033#ifdef AMREX_USE_GPU
1034 if (Gpu::inLaunchRegion()) {
1035 ParallelFor(tags, 1,
1036 [=] AMREX_GPU_DEVICE (int i, int j, int k, int, TagT const& tag) noexcept
1037 {
1038 const int ncomp = tag.dfab.nComp();
1039 for (int n = 0; n < ncomp; ++n) {
1040 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
1041 }
1042 });
1043 } else
1044#endif
1045 {
1046#ifdef AMREX_USE_OMP
1047#pragma omp parallel for
1048#endif
1049 for (int itag = 0; itag < N; ++itag) {
1050 auto const& tag = tags[itag];
1051 const int ncomp = tag.dfab.nComp();
1052 AMREX_LOOP_4D(tag.dbox, ncomp, i, j, k, n,
1053 {
1054 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
1055 });
1056 }
1057 }
1058}
1059}
1061
1075template <FabArrayType MF>
1076void
1078 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1079 Vector<Periodicity> const& period,
1080 Vector<int> const& cross = {})
1081{
1082 BL_PROFILE("FillBoundary_nowait(Vector)");
1083 const int N = mf.size();
1084 for (int i = 0; i < N; ++i) {
1085 mf[i]->FillBoundary_nowait(scomp[i], ncomp[i], nghost[i], period[i],
1086 cross.empty() ? 0 : cross[i]);
1087 }
1088}
1089
1098template <FabArrayType MF>
1099void
1101 const Periodicity& a_period = Periodicity::NonPeriodic())
1102{
1103 Vector<int> scomp(mf.size(), 0);
1105 Vector<IntVect> nghost;
1106 Vector<Periodicity> period(mf.size(), a_period);
1107 ncomp.reserve(mf.size());
1108 nghost.reserve(mf.size());
1109 for (auto const& x : mf) {
1110 ncomp.push_back(x->nComp());
1111 nghost.push_back(x->nGrowVect());
1112 }
1113 FillBoundary_nowait(mf, scomp, ncomp, nghost, period);
1114}
1115
1121template <FabArrayType MF>
1122void
1124{
1125 BL_PROFILE("FillBoundary_finish(Vector)");
1126 const int N = mf.size();
1127 for (int i = 0; i < N; ++i) {
1128 mf[i]->FillBoundary_finish();
1129 }
1130}
1131
1144template <FabArrayType MF>
1145void
1147 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1148 Vector<Periodicity> const& period)
1149{
1150 BL_PROFILE("FillBoundaryAndSync_nowait(Vector)");
1151 const int N = mf.size();
1152 for (int i = 0; i < N; ++i) {
1153 mf[i]->FillBoundaryAndSync_nowait(scomp[i], ncomp[i], nghost[i], period[i]);
1154 }
1155}
1156
1163template <FabArrayType MF>
1164void
1166 const Periodicity& a_period = Periodicity::NonPeriodic())
1167{
1168 Vector<int> scomp(mf.size(), 0);
1169 Vector<int> ncomp;
1170 Vector<IntVect> nghost;
1171 Vector<Periodicity> period(mf.size(), a_period);
1172 ncomp.reserve(mf.size());
1173 nghost.reserve(mf.size());
1174 for (auto const& x : mf) {
1175 ncomp.push_back(x->nComp());
1176 nghost.push_back(x->nGrowVect());
1177 }
1178 FillBoundaryAndSync_nowait(mf, scomp, ncomp, nghost, period);
1179}
1180
1186template <FabArrayType MF>
1187void
1189{
1190 BL_PROFILE("FillBoundaryAndSync_finish(Vector)");
1191 const int N = mf.size();
1192 for (int i = 0; i < N; ++i) {
1193 mf[i]->FillBoundaryAndSync_finish();
1194 }
1195}
1196
1212template <FabArrayType MF>
1213void
1214FillBoundary (Vector<MF*> const& mf, Vector<int> const& scomp,
1215 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1216 Vector<Periodicity> const& period, Vector<int> const& cross = {})
1217{
1218 BL_PROFILE("FillBoundary(Vector)");
1219#if 1
1220 const int N = mf.size();
1221 for (int i = 0; i < N; ++i) {
1222 mf[i]->FillBoundary_nowait(scomp[i], ncomp[i], nghost[i], period[i],
1223 cross.empty() ? 0 : cross[i]);
1224 }
1225 for (int i = 0; i < N; ++i) {
1226 mf[i]->FillBoundary_finish();
1227 }
1228
1229#else
1230 using FAB = typename MF::FABType::value_type;
1231 using T = typename FAB::value_type;
1232
1233 const int nmfs = mf.size();
1234 Vector<FabArrayBase::CommMetaData const*> cmds;
1235 int N_locs = 0;
1236 int N_rcvs = 0;
1237 int N_snds = 0;
1238 for (int imf = 0; imf < nmfs; ++imf) {
1239 if (nghost[imf].max() > 0) {
1240 auto const& TheFB = mf[imf]->getFB(nghost[imf], period[imf],
1241 cross.empty() ? 0 : cross[imf]);
1242 // The FB is cached. Therefore it's safe take its address for later use.
1243 cmds.push_back(static_cast<FabArrayBase::CommMetaData const*>(&TheFB));
1244 N_locs += TheFB.m_LocTags->size();
1245 N_rcvs += TheFB.m_RcvTags->size();
1246 N_snds += TheFB.m_SndTags->size();
1247 } else {
1248 cmds.push_back(nullptr);
1249 }
1250 }
1252 using TagT = Array4CopyTag<T>;
1253 Vector<TagT> local_tags;
1254 local_tags.reserve(N_locs);
1255 static_assert(amrex::IsStoreAtomic<T>::value, "FillBoundary(Vector): storing T is not atomic");
1256 for (int imf = 0; imf < nmfs; ++imf) {
1257 if (cmds[imf]) {
1258 auto const& tags = *(cmds[imf]->m_LocTags);
1259 for (auto const& tag : tags) {
1260 local_tags.push_back(TagT{.dfab = (*mf[imf])[tag.dstIndex].array(scomp[imf],ncomp[imf]),
1261 .dindex = tag.dstIndex,
1262 .sfab = (*mf[imf])[tag.srcIndex].const_array(scomp[imf],ncomp[imf]),
1263 .dbox = tag.dbox,
1264 .offset = (tag.sbox.smallEnd()-tag.dbox.smallEnd()).dim3()});
1265 }
1266 }
1267 }
1268
1269 if (ParallelContext::NProcsSub() == 1) {
1270 detail::fbv_copy(local_tags);
1271 return;
1272 }
1273
1274#ifdef AMREX_USE_MPI
1275 //
1276 // Do this before prematurely exiting if running in parallel.
1277 // Otherwise sequence numbers will not match across MPI processes.
1278 //
1281
1282 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) { return; } // No work to do
1283
1284 char* the_recv_data = nullptr;
1285 Vector<int> recv_from;
1286 Vector<std::size_t> recv_size;
1287 Vector<MPI_Request> recv_reqs;
1288 Vector<MPI_Status> recv_stat;
1289 Vector<TagT> recv_tags;
1290
1291 if (N_rcvs > 0) {
1292
1293 for (int imf = 0; imf < nmfs; ++imf) {
1294 if (cmds[imf]) {
1295 auto const& tags = *(cmds[imf]->m_RcvTags);
1296 for (const auto& kv : tags) {
1297 recv_from.push_back(kv.first);
1298 }
1299 }
1300 }
1301 amrex::RemoveDuplicates(recv_from);
1302 const int nrecv = recv_from.size();
1303
1304 recv_reqs.resize(nrecv, MPI_REQUEST_NULL);
1305 recv_stat.resize(nrecv);
1306
1307 recv_tags.reserve(N_rcvs);
1309 Vector<Vector<std::size_t> > recv_offset(nrecv);
1311 recv_size.reserve(nrecv);
1312 offset.reserve(nrecv);
1313 std::size_t TotalRcvsVolume = 0;
1314 for (int i = 0; i < nrecv; ++i) {
1315 std::size_t nbytes = 0;
1316 for (int imf = 0; imf < nmfs; ++imf) {
1317 if (cmds[imf]) {
1318 auto const& tags = *(cmds[imf]->m_RcvTags);
1319 auto it = tags.find(recv_from[i]);
1320 if (it != tags.end()) {
1321 for (auto const& cct : it->second) {
1322 auto& dfab = (*mf[imf])[cct.dstIndex];
1323 recv_offset[i].push_back(nbytes);
1324 recv_tags.push_back(TagT{
1325 .dfab = dfab.array(scomp[imf],ncomp[imf]),
1326 .dindex = cct.dstIndex,
1327 .sfab = makeArray4<T const>(nullptr,cct.dbox,ncomp[imf]),
1328 .dbox = cct.dbox,
1329 .offset = Dim3{.x = 0, .y = 0, .z = 0}
1330 });
1331 nbytes += dfab.nBytes(cct.dbox,ncomp[imf]);
1332 }
1333 }
1334 }
1335 }
1336
1337 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
1338 nbytes = amrex::aligned_size(acd, nbytes); // so that nbytes are aligned
1339
1340 // Also need to align the offset properly
1341 TotalRcvsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalRcvsVolume);
1342
1343 offset.push_back(TotalRcvsVolume);
1344 TotalRcvsVolume += nbytes;
1345
1346 recv_size.push_back(nbytes);
1347 }
1348
1349 the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
1350
1351 int k = 0;
1352 for (int i = 0; i < nrecv; ++i) {
1353 char* p = the_recv_data + offset[i];
1354 const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
1355 recv_reqs[i] = ParallelDescriptor::Arecv
1356 (p, recv_size[i], rank, SeqNum, comm).req();
1357 for (int j = 0, nj = recv_offset[i].size(); j < nj; ++j) {
1358 recv_tags[k++].sfab.p = (T const*)(p + recv_offset[i][j]);
1359 }
1360 }
1361 }
1362
1363 char* the_send_data = nullptr;
1364 Vector<int> send_rank;
1365 Vector<char*> send_data;
1366 Vector<std::size_t> send_size;
1367 Vector<MPI_Request> send_reqs;
1368 if (N_snds > 0) {
1369 for (int imf = 0; imf < nmfs; ++imf) {
1370 if (cmds[imf]) {
1371 auto const& tags = *(cmds[imf]->m_SndTags);
1372 for (auto const& kv : tags) {
1373 send_rank.push_back(kv.first);
1374 }
1375 }
1376 }
1377 amrex::RemoveDuplicates(send_rank);
1378 const int nsend = send_rank.size();
1379
1380 send_data.resize(nsend, nullptr);
1381 send_reqs.resize(nsend, MPI_REQUEST_NULL);
1382
1383 Vector<TagT> send_tags;
1384 send_tags.reserve(N_snds);
1385
1386 Vector<Vector<std::size_t> > send_offset(nsend);
1387 Vector<std::size_t> offset;
1388 send_size.reserve(nsend);
1389 offset.reserve(nsend);
1390 std::size_t TotalSndsVolume = 0;
1391 for (int i = 0; i < nsend; ++i) {
1392 std::size_t nbytes = 0;
1393 for (int imf = 0; imf < nmfs; ++imf) {
1394 if (cmds[imf]) {
1395 auto const& tags = *(cmds[imf]->m_SndTags);
1396 auto it = tags.find(send_rank[i]);
1397 if (it != tags.end()) {
1398 for (auto const& cct : it->second) {
1399 auto const& sfab = (*mf[imf])[cct.srcIndex];
1400 send_offset[i].push_back(nbytes);
1401 send_tags.push_back(TagT{
1402 .dfab = amrex::makeArray4<T>(nullptr,cct.sbox,ncomp[imf]),
1403 .dindex = cct.dstIndex,
1404 .sfab = sfab.const_array(scomp[imf],ncomp[imf]),
1405 .dbox = cct.sbox,
1406 .offset = Dim3{.x = 0, .y = 0, .z = 0}
1407 });
1408 nbytes += sfab.nBytes(cct.sbox,ncomp[imf]);
1409 }
1410 }
1411 }
1412 }
1413
1414 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
1415 nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
1416
1417 // Also need to align the offset properly
1418 TotalSndsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalSndsVolume);
1419
1420 offset.push_back(TotalSndsVolume);
1421 TotalSndsVolume += nbytes;
1422
1423 send_size.push_back(nbytes);
1424 }
1425
1426 the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalSndsVolume));
1427 int k = 0;
1428 for (int i = 0; i < nsend; ++i) {
1429 send_data[i] = the_send_data + offset[i];
1430 for (int j = 0, nj = send_offset[i].size(); j < nj; ++j) {
1431 send_tags[k++].dfab.p = (T*)(send_data[i] + send_offset[i][j]);
1432 }
1433 }
1435 detail::fbv_copy(send_tags);
1437 FabArray<FAB>::PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
1438 }
1439
1440#if !defined(AMREX_DEBUG)
1441 int recv_flag;
1442 ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
1443#endif
1444
1445 if (N_locs > 0) {
1446 detail::fbv_copy(local_tags);
1447#if !defined(AMREX_DEBUG)
1448 ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
1449#endif
1450 }
1451
1452 if (N_rcvs > 0) {
1453 ParallelDescriptor::Waitall(recv_reqs, recv_stat);
1454#ifdef AMREX_DEBUG
1455 if (!FabArrayBase::CheckRcvStats(recv_stat, recv_size, SeqNum)) {
1456 amrex::Abort("FillBoundary(vector) failed with wrong message size");
1457 }
1458#endif
1459
1460 detail::fbv_copy(recv_tags);
1461
1462 amrex::The_Comms_Arena()->free(the_recv_data);
1463 }
1464
1465 if (N_snds > 0) {
1466 Vector<MPI_Status> stats(send_reqs.size());
1467 ParallelDescriptor::Waitall(send_reqs, stats);
1468 amrex::The_Comms_Arena()->free(the_send_data);
1469 }
1470
1471#endif // #ifdef AMREX_USE_MPI
1472#endif // #if 1 #else
1473}
1474
1487template <FabArrayType MF>
1488void
1490 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1491 Vector<Periodicity> const& period)
1492{
1493 BL_PROFILE("FillBoundaryAndSync(Vector)");
1494 const int N = mf.size();
1495 for (int i = 0; i < N; ++i) {
1496 mf[i]->FillBoundaryAndSync_nowait(scomp[i], ncomp[i], nghost[i], period[i]);
1497 }
1498 for (int i = 0; i < N; ++i) {
1499 mf[i]->FillBoundaryAndSync_finish();
1500 }
1501}
1502
1504template <FabArrayType MF>
1505void
1507{
1508 FillBoundary_nowait(mf, a_period);
1510}
1511
1513template <FabArrayType MF>
1514void
1520
1521}
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define BL_PROFILE_SYNC_STOP()
Definition AMReX_BLProfiler.H:645
#define BL_PROFILE_SYNC_START_TIMED(fname)
Definition AMReX_BLProfiler.H:644
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define BL_ASSERT(EX)
Definition AMReX_BLassert.H:39
#define AMREX_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:37
#define AMREX_ASSERT(EX)
Definition AMReX_BLassert.H:38
#define AMREX_PRAGMA_SIMD
Definition AMReX_Extension.H:85
Internal Fab copy tags and GPU helpers used by FabArray transfers.
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1129
#define AMREX_LOOP_4D(bx, ncomp, i, j, k, n, block)
Definition AMReX_Loop.nolint.H:16
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.
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:676
IndexType ixType() const noexcept
Return index type of this BoxArray.
Definition AMReX_BoxArray.H:1252
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
IntVect nGrowVect() const noexcept
Definition AMReX_FabArrayBase.H:85
int size() const noexcept
Return the number of FABs in the FabArray.
Definition AMReX_FabArrayBase.H:115
const DistributionMapping & DistributionMap() const noexcept
Return constant reference to associated DistributionMapping.
Definition AMReX_FabArrayBase.H:135
bool empty() const noexcept
Definition AMReX_FabArrayBase.H:94
CpOp
parallel copy or add
Definition AMReX_FabArrayBase.H:411
@ ADD
Definition AMReX_FabArrayBase.H:411
@ COPY
Definition AMReX_FabArrayBase.H:411
Box box(int K) const noexcept
Return the Kth Box in the BoxArray. That is, the valid region of the Kth grid.
Definition AMReX_FabArrayBase.H:106
DistributionMapping distributionMap
Definition AMReX_FabArrayBase.H:515
static int MaxComp
The maximum number of components to copy() at a time.
Definition AMReX_FabArrayBase.H:309
BoxArray boxarray
Definition AMReX_FabArrayBase.H:514
const BoxArray & boxArray() const noexcept
Return a constant reference to the BoxArray that defines the valid region associated with this FabArr...
Definition AMReX_FabArrayBase.H:100
An Array of FortranArrayBox(FAB)-like Objects.
Definition AMReX_FabArray.H:356
void ParallelCopyToGhost_finish()
Finish the current ParallelCopyToGhost_nowait() operation.
Definition AMReX_FabArrayCommI.H:389
void ParallelCopy(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Definition AMReX_FabArray.H:971
void Redistribute(const FabArray< FAB > &src, int scomp, int dcomp, int ncomp, const IntVect &nghost)
Copy from src to this. this and src have the same BoxArray, but different DistributionMapping.
Definition AMReX_FabArrayCommI.H:989
void ParallelCopyToGhost(const FabArray< FAB > &src, int scomp, int dcomp, int ncomp, const IntVect &snghost, const IntVect &dnghost, const Periodicity &period=Periodicity::NonPeriodic())
Copy source data to destination ghost cells only.
Definition AMReX_FabArrayCommI.H:358
void ParallelCopy_finish()
Finish the current nowait ParallelCopy or ParallelAdd operation.
Definition AMReX_FabArrayCommI.H:679
void ParallelAdd(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic())
This function copies data from src to this FabArray. Each FAB in fa is intersected with all FABs in t...
Definition AMReX_FabArray.H:968
void ParallelCopyToGhost_nowait(const FabArray< FAB > &src, int scomp, int dcomp, int ncomp, const IntVect &snghost, const IntVect &dnghost, const Periodicity &period=Periodicity::NonPeriodic())
Start an asynchronous version of ParallelCopyToGhost().
Definition AMReX_FabArrayCommI.H:375
void FillBoundary_test()
Definition AMReX_FabArrayCommI.H:1016
void copyTo(FAB &dest, int nghost=0) const
Copy the values contained in the intersection of the valid + nghost region of this FabArray with the ...
Definition AMReX_FabArray.H:2941
void ParallelCopy_nowait(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Start an asynchronous ParallelCopy that copies every component.
Definition AMReX_FabArray.H:1003
Array4< typename FabArray< FAB >::value_type const > const_array(const MFIter &mfi) const noexcept
Synonym for array(const MFIter&) that highlights read-only semantics.
Definition AMReX_FabArray.H:649
__host__ __device__ bool cellCentered() const noexcept
True if the IndexTypeND is CELL based in all directions.
Definition AMReX_IndexType.H:102
__host__ __device__ constexpr bool allGE(const IntVectND< dim > &rhs) const noexcept
Returns true if this is greater than or equal to argument for all components. NOTE: This is NOT a str...
Definition AMReX_IntVect.H:542
__host__ static __device__ constexpr IntVectND< dim > TheZeroVector() noexcept
This static member function returns a reference to a constant IntVectND object, all of whose dim argu...
Definition AMReX_IntVect.H:771
__host__ __device__ constexpr int max() const noexcept
maximum (no absolute values) value
Definition AMReX_IntVect.H:313
MPI_Request req() const
Definition AMReX_ParallelDescriptor.H:74
This provides length of period for periodic domains. 0 means it is not periodic in that direction....
Definition AMReX_Periodicity.H:17
static const Periodicity & NonPeriodic() noexcept
Definition AMReX_Periodicity.cpp:52
bool isAnyPeriodic() const noexcept
Definition AMReX_Periodicity.H:22
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
Long size() const noexcept
Definition AMReX_Vector.H:54
Checks if a type is derived from amrex::BaseFab.
Definition AMReX_Concepts.H:13
amrex_long Long
Definition AMReX_INT.H:30
__host__ __device__ Dim3 ubound(Array4< T > const &a) noexcept
Return the inclusive upper bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1364
__host__ __device__ Dim3 lbound(Array4< T > const &a) noexcept
Return the inclusive lower bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1350
__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:1326
Arena * The_Comms_Arena()
Definition AMReX_Arena.cpp:880
Arena * The_Pinned_Arena()
Definition AMReX_Arena.cpp:860
std::size_t aligned_size(std::size_t align_requirement, std::size_t size) noexcept
Return the smallest multiple of align_requirement that is >= size.
Definition AMReX_Arena.H:38
int MyProc() noexcept
Definition AMReX_ParallelDescriptor.H:128
void Bcast(Gpu::DeviceVector< T > &v, int root, MPI_Comm comm)
Definition AMReX_GpuParallelReduce.H:100
int NProcs() noexcept
Definition AMReX_ParallelDescriptor.H:255
__host__ __device__ constexpr const T & max(const T &a, const T &b) noexcept
Definition AMReX_Algorithm.H:53
bool inGraphRegion()
Definition AMReX_GpuControl.H:117
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
void dtoh_memcpy_async(void *p_h, const void *p_d, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:435
bool inLaunchRegion() noexcept
Definition AMReX_GpuControl.H:88
bool inNoSyncRegion() noexcept
Definition AMReX_GpuControl.H:148
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:421
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int global_to_local_rank(int rank) noexcept
Definition AMReX_ParallelContext.H:98
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
void Test(MPI_Request &, int &, MPI_Status &)
Definition AMReX_ParallelDescriptor.cpp:1220
Message Asend(const T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1154
bool UseGpuAwareMpi()
Definition AMReX_ParallelDescriptor.H:113
void Waitall(Vector< MPI_Request > &, Vector< MPI_Status > &)
Definition AMReX_ParallelDescriptor.cpp:1308
int SeqNum() noexcept
Returns sequential message sequence numbers, usually used as tags for send/recv.
Definition AMReX_ParallelDescriptor.H:678
Message Arecv(T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1196
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
static constexpr int MPI_REQUEST_NULL
Definition AMReX_ccse-mpi.H:57
Definition AMReX_Amr.cpp:50
@ make_alias
Definition AMReX_MakeType.H:7
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:259
void FillBoundary_finish(Vector< MF * > const &mf)
Wait for outstanding FillBoundary_nowait operations launched with the vector helper to complete.
Definition AMReX_FabArrayCommI.H:1123
void Copy(FabArray< DFAB > &dst, FabArray< SFAB > const &src, int srccomp, int dstcomp, int numcomp, int nghost)
Definition AMReX_FabArray.H:192
void Add(FabArray< FAB > &dst, FabArray< FAB > const &src, int srccomp, int dstcomp, int numcomp, int nghost)
Definition AMReX_FabArray.H:251
std::unique_ptr< char, TheFaArenaDeleter > TheFaArenaPointer
Definition AMReX_FabArray.H:118
BoxArray const & boxArray(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.boxArray().
Definition AMReX_FabArrayBase.cpp:2862
DistributionMapping const & DistributionMap(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.DistributionMap().
Definition AMReX_FabArrayBase.cpp:2867
void FillBoundary_nowait(Vector< MF * > const &mf, Vector< int > const &scomp, Vector< int > const &ncomp, Vector< IntVect > const &nghost, Vector< Periodicity > const &period, Vector< int > const &cross={})
Launch FillBoundary_nowait across a vector of FabArrays.
Definition AMReX_FabArrayCommI.H:1077
void FillBoundaryAndSync_nowait(Vector< MF * > const &mf, Vector< int > const &scomp, Vector< int > const &ncomp, Vector< IntVect > const &nghost, Vector< Periodicity > const &period)
Launch FillBoundaryAndSync_nowait across a vector of FabArrays.
Definition AMReX_FabArrayCommI.H:1146
void FillBoundaryAndSync(Vector< MF * > const &mf, Vector< int > const &scomp, Vector< int > const &ncomp, Vector< IntVect > const &nghost, Vector< Periodicity > const &period)
Perform FillBoundaryAndSync on a batch of FabArrays (e.g., MultiFabs).
Definition AMReX_FabArrayCommI.H:1489
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
double second() noexcept
Definition AMReX_Utility.cpp:919
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:2233
IntVectND< 3 > IntVect
IntVect is an alias for amrex::IntVectND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:38
IntVect nGrowVect(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.nGrowVect().
Definition AMReX_FabArrayBase.cpp:2857
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:241
void RemoveDuplicates(Vector< T > &vec)
Definition AMReX_Vector.H:210
void FillBoundaryAndSync_finish(Vector< MF * > const &mf)
Wait for outstanding FillBoundaryAndSync_nowait operations launched with the vector helper to complet...
Definition AMReX_FabArrayCommI.H:1188
void FillBoundary(Vector< MF * > const &mf, Vector< int > const &scomp, Vector< int > const &ncomp, Vector< IntVect > const &nghost, Vector< Periodicity > const &period, Vector< int > const &cross={})
Perform FillBoundary on a batch of FabArrays (e.g., MultiFabs).
Definition AMReX_FabArrayCommI.H:1214
Definition AMReX_TagParallelFor.H:26
A simple struct holding 3 int values for a 3D index.
Definition AMReX_Dim3.H:24
parallel copy or add
Definition AMReX_FabArrayBase.H:630
std::uint64_t m_id
Definition AMReX_FabArrayBase.H:645
Definition AMReX_FabArrayBase.H:542
bool m_threadsafe_rcv
Definition AMReX_FabArrayBase.H:545
std::unique_ptr< MapOfCopyComTagContainers > m_RcvTags
Definition AMReX_FabArrayBase.H:548
std::unique_ptr< MapOfCopyComTagContainers > m_SndTags
Definition AMReX_FabArrayBase.H:547
std::unique_ptr< CopyComTagsContainer > m_LocTags
Definition AMReX_FabArrayBase.H:546
FillBoundary.
Definition AMReX_FabArrayBase.H:567
std::uint64_t m_id
Definition AMReX_FabArrayBase.H:573
IntVect m_sb_snghost
Definition AMReX_FabArrayBase.H:577
Definition AMReX_TypeTraits.H:61
Definition AMReX_TypeTraits.H:277
FabArray memory allocation information.
Definition AMReX_FabArray.H:73