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
43 // Only a plain FillBoundary brings the halo up to date. The other
44 // operations here either touch valid data or only part of the halo, so
45 // they make no claim about it.
46 if (enforce_periodicity_only || override_sync || sumboundary) {
47 n_filled = IntVect::TheZeroVector();
48 } else {
49 n_filled = nghost;
50 }
51
52 if (!work_to_do) { return; }
53
54 const FB& TheFB = getFB(nghost, period, cross, enforce_periodicity_only, override_sync, sumboundary_src_nghost);
55
57 {
58 //
59 // There can only be local work to do.
60 //
61 int N_locs = (*TheFB.m_LocTags).size();
62 if (N_locs == 0) { return; }
63#ifdef AMREX_USE_GPU
65 {
66#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
67 if (Gpu::inGraphRegion() && !sumboundary)
68 {
69 FB_local_copy_cuda_graph_1(TheFB, scomp, ncomp);
70 }
71 else
72#endif
73 {
74 if (sumboundary) {
76 FB_local_add_gpu(TheFB, scomp, ncomp, deterministic);
77 } else {
78 amrex::Abort("SumBoundary requires operator+=");
79 }
80 } else {
81 FB_local_copy_gpu(TheFB, scomp, ncomp);
82 if (!Gpu::inNoSyncRegion()) {
84 }
85 }
86 }
87 }
88 else
89#endif
90 {
91 if (sumboundary) {
93 FB_local_add_cpu(TheFB, scomp, ncomp);
94 } else {
95 amrex::Abort("SumBoundary requires operator+=");
96 }
97 } else {
98 FB_local_copy_cpu(TheFB, scomp, ncomp);
99 }
100 }
101
102 return;
103 }
104
105#ifdef BL_USE_MPI
106
107 //
108 // Do this before prematurely exiting if running in parallel.
109 // Otherwise sequence numbers will not match across MPI processes.
110 //
111 int SeqNum = ParallelDescriptor::SeqNum();
112
113 const int N_locs = TheFB.m_LocTags->size();
114 const int N_rcvs = TheFB.m_RcvTags->size();
115 const int N_snds = TheFB.m_SndTags->size();
116
117 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
118 // No work to do.
119 return;
120 }
121
122 fbd = std::make_unique<FBData<FAB>>();
123 fbd->fb = &TheFB;
124 fbd->scomp = scomp;
125 fbd->ncomp = ncomp;
126 fbd->tag = SeqNum;
127 fbd->deterministic = deterministic;
128
129 //
130 // Post rcvs. Allocate one chunk of space to hold'm all.
131 //
132
133 if (N_rcvs > 0) {
134 PostRcvs<BUF>(*TheFB.m_RcvTags, fbd->the_recv_data,
135 fbd->recv_data, fbd->recv_size, fbd->recv_from, fbd->recv_reqs,
136 ncomp, SeqNum);
137 fbd->recv_stat.resize(N_rcvs);
138 }
139
140 //
141 // Post send's
142 //
143 char*& the_send_data = fbd->the_send_data;
144 Vector<char*> & send_data = fbd->send_data;
145 Vector<std::size_t> send_size;
146 Vector<int> send_rank;
147 Vector<MPI_Request>& send_reqs = fbd->send_reqs;
149
150 if (N_snds > 0)
151 {
152 PrepareSendBuffers<BUF>(*TheFB.m_SndTags, the_send_data, send_data, send_size, send_rank,
153 send_reqs, send_cctc, ncomp);
154
155#ifdef AMREX_USE_GPU
157 {
158#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
159 if (std::is_same_v<BUF,value_type> && Gpu::inGraphRegion()) {
160 FB_pack_send_buffer_cuda_graph(TheFB, scomp, ncomp, send_data, send_size, send_cctc);
161 }
162 else
163#endif
164 {
165 pack_send_buffer_gpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc, TheFB.m_id);
166 }
167 }
168 else
169#endif
170 {
171 pack_send_buffer_cpu<BUF>(*this, scomp, ncomp, send_data, send_size, send_cctc);
172 }
173
174 AMREX_ASSERT(send_reqs.size() == N_snds);
175 PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
176 }
177
178 FillBoundary_test();
179
180 //
181 // Do the local work. Hope for a bit of communication/computation overlap.
182 //
183 if (N_locs > 0)
184 {
185#ifdef AMREX_USE_GPU
187 {
188#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
189 if (Gpu::inGraphRegion() && !sumboundary) {
190 FB_local_copy_cuda_graph_n(TheFB, scomp, ncomp);
191 }
192 else
193#endif
194 {
195 if (sumboundary) {
197 FB_local_add_gpu(TheFB, scomp, ncomp, deterministic);
198 } else {
199 amrex::Abort("SumBoundary requires operator+=");
200 }
201 } else {
202 FB_local_copy_gpu(TheFB, scomp, ncomp);
203 if (!Gpu::inNoSyncRegion() && N_rcvs == 0) {
205 }
206 }
207 }
208 }
209 else
210#endif
211 {
212 if (sumboundary) {
214 FB_local_add_cpu(TheFB, scomp, ncomp);
215 } else {
216 amrex::Abort("SumBoundary requires operator+=");
217 }
218 } else {
219 FB_local_copy_cpu(TheFB, scomp, ncomp);
220 }
221 }
222
223 FillBoundary_test();
224 }
225
226#endif /*BL_USE_MPI*/
227
228#ifndef AMREX_USE_GPU
229 amrex::ignore_unused(deterministic);
230#endif
231}
232
233template <class FAB>
234template <typename BUF, class F>
235requires (BaseFabType<F>)
236void
238{
239#ifdef AMREX_USE_MPI
240
241 BL_PROFILE("FillBoundary_finish()");
243
244 if (!fbd) { return; }
245
246 const FB* TheFB = fbd->fb;
247 bool sumboundary = TheFB->m_sb_snghost.allGE(0);
248 const auto N_rcvs = static_cast<int>(TheFB->m_RcvTags->size());
249 if (N_rcvs > 0)
250 {
251 Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
252 for (int k = 0; k < N_rcvs; k++)
253 {
254 if (fbd->recv_size[k] > 0)
255 {
256 auto const& cctc = TheFB->m_RcvTags->at(fbd->recv_from[k]);
257 recv_cctc[k] = &cctc;
258 }
259 }
260
261 int actual_n_rcvs = N_rcvs - std::ranges::count(fbd->recv_data, nullptr);
262
263 if (actual_n_rcvs > 0) {
264 ParallelDescriptor::Waitall(fbd->recv_reqs, fbd->recv_stat);
265#ifdef AMREX_DEBUG
266 if (!CheckRcvStats(fbd->recv_stat, fbd->recv_size, fbd->tag))
267 {
268 amrex::Abort("FillBoundary_finish failed with wrong message size");
269 }
270#endif
271 }
272
273 bool is_thread_safe = TheFB->m_threadsafe_rcv;
274 auto op = sumboundary ? FabArrayBase::ADD : FabArrayBase::COPY;
275
276#ifdef AMREX_USE_GPU
278 {
279#if defined(__CUDACC__) && defined(AMREX_USE_CUDA)
280 if (std::is_same_v<BUF,value_type> && Gpu::inGraphRegion() && !sumboundary)
281 {
282 FB_unpack_recv_buffer_cuda_graph(*TheFB, fbd->scomp, fbd->ncomp,
283 fbd->recv_data, fbd->recv_size,
284 recv_cctc, is_thread_safe);
285 }
286 else
287#endif
288 {
289 bool deterministic = fbd->deterministic;
290 unpack_recv_buffer_gpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
291 recv_cctc, op, is_thread_safe, TheFB->m_id, deterministic);
292 }
293 }
294 else
295#endif
296 {
297 unpack_recv_buffer_cpu<BUF>(*this, fbd->scomp, fbd->ncomp, fbd->recv_data, fbd->recv_size,
298 recv_cctc, op, is_thread_safe);
299 }
300
301 if (fbd->the_recv_data)
302 {
303 amrex::The_Comms_Arena()->free(fbd->the_recv_data);
304 fbd->the_recv_data = nullptr;
305 }
306 }
307
308 const auto N_snds = static_cast<int>(TheFB->m_SndTags->size());
309 if (N_snds > 0) {
310 Vector<MPI_Status> stats(fbd->send_reqs.size());
311 ParallelDescriptor::Waitall(fbd->send_reqs, stats);
312 amrex::The_Comms_Arena()->free(fbd->the_send_data);
313 fbd->the_send_data = nullptr;
314 }
315
316 fbd.reset();
317
318#endif
319}
320
321template <class FAB>
322void
324 int scomp,
325 int dcomp,
326 int ncomp,
327 const IntVect& snghost,
328 const IntVect& dnghost,
329 const Periodicity& period,
330 CpOp op,
331 const FabArrayBase::CPC * a_cpc,
332 bool deterministic)
333{
334 BL_PROFILE("FabArray::ParallelCopy()");
335
336 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period, op, a_cpc,
337 false, deterministic);
338 ParallelCopy_finish();
339}
340
341template <class FAB>
342void
343FabArray<FAB>::ParallelCopy (const FabArray<FAB>& src, int src_comp, int dest_comp,
344 int num_comp, const IntVect& snghost, const IntVect& dnghost,
345 const IntVect& offset, const Periodicity& period)
346{
347 BL_PROFILE("FabArray::ParallelCopy()");
348
349 ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,snghost,dnghost,offset,period);
350 ParallelCopy_finish();
351}
352
353template <class FAB>
354void
355FabArray<FAB>::ParallelAdd (const FabArray<FAB>& src, int src_comp, int dest_comp,
356 int num_comp, const IntVect& snghost, const IntVect& dnghost,
357 const IntVect& offset, const Periodicity& period)
358{
359 BL_PROFILE("FabArray::ParallelAdd()");
360
361 ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,snghost,dnghost,offset,period,
363 ParallelCopy_finish();
364}
365
366template <class FAB>
367void
369 int scomp,
370 int dcomp,
371 int ncomp,
372 const IntVect& snghost,
373 const IntVect& dnghost,
374 const Periodicity& period)
375{
376 BL_PROFILE("FabArray::ParallelCopyToGhost()");
377
378 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
379 FabArrayBase::COPY, nullptr, true);
380 ParallelCopy_finish();
381}
382
383template <class FAB>
384void
386 int scomp,
387 int dcomp,
388 int ncomp,
389 const IntVect& snghost,
390 const IntVect& dnghost,
391 const Periodicity& period)
392{
393 ParallelCopy_nowait(src, scomp, dcomp, ncomp, snghost, dnghost, period,
394 FabArrayBase::COPY, nullptr, true);
395}
396
397template <class FAB>
398void
400{
401 ParallelCopy_finish();
402}
403
404
405template <class FAB>
406void
408 int scomp,
409 int dcomp,
410 int ncomp,
411 const IntVect& snghost,
412 const IntVect& dnghost,
413 const Periodicity& period,
414 CpOp op,
415 const FabArrayBase::CPC * a_cpc,
416 bool to_ghost_cells_only,
417 bool deterministic)
418{
419 ParallelCopy_nowait(src,scomp,dcomp,ncomp,snghost,dnghost,IntVect(0),period,op,a_cpc,
420 to_ghost_cells_only, deterministic);
421}
422
423template <class FAB>
424void
426 int scomp,
427 int dcomp,
428 int ncomp,
429 const IntVect& snghost,
430 const IntVect& dnghost,
431 const IntVect& offset,
432 const Periodicity& period,
433 CpOp op,
434 const FabArrayBase::CPC * a_cpc,
435 bool to_ghost_cells_only,
436 bool deterministic)
437{
438 BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: PC");
439 BL_PROFILE("FabArray::ParallelCopy_nowait()");
440
441 AMREX_ASSERT_WITH_MESSAGE(!pcd, "ParallelCopy_nowait() called when comm operation already in progress.");
442
443 if (empty() || src.empty()) {
444 return;
445 }
446
448 BL_ASSERT(boxArray().ixType() == src.boxArray().ixType());
449 BL_ASSERT(src.nGrowVect().allGE(snghost));
450 BL_ASSERT( nGrowVect().allGE(dnghost));
451
452 n_filled = dnghost;
453
454 if ((ParallelDescriptor::NProcs() == 1) &&
455 (this->size() == 1) && (src.size() == 1) &&
456 !period.isAnyPeriodic() && !to_ghost_cells_only && (offset == 0))
457 {
458 if (this != &src) { // avoid self copy or plus
459 auto const& da = this->array(0, dcomp);
460 auto const& sa = src.const_array(0, scomp);
461 Box box = amrex::grow(src.box(0),snghost)
462 & amrex::grow(this->box(0),dnghost);
463 if (op == FabArrayBase::COPY) {
464#ifdef AMREX_USE_GPU
465 if (Gpu::inLaunchRegion()) {
466 ParallelFor(box, ncomp,
467 [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
468 da(i,j,k,n) = sa(i,j,k,n);
469 });
470 if (!Gpu::inNoSyncRegion()) {
472 }
473 } else
474#endif
475 {
476 auto const& lo = amrex::lbound(box);
477 auto const& hi = amrex::ubound(box);
478#ifdef AMREX_USE_OMP
479#pragma omp parallel for collapse(3)
480#endif
481 for (int n = 0; n < ncomp; ++n) {
482 for (int k = lo.z; k <= hi.z; ++k) {
483 for (int j = lo.y; j <= hi.y; ++j) {
485 for (int i = lo.x; i <= hi.x; ++i) {
486 da(i,j,k,n) = sa(i,j,k,n);
487 }}}}
488 }
489 } else {
490#ifdef AMREX_USE_GPU
491 if (Gpu::inLaunchRegion()) {
492 ParallelFor(box, ncomp,
493 [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) {
494 da(i,j,k,n) += sa(i,j,k,n);
495 });
496 if (!Gpu::inNoSyncRegion()) {
498 }
499 } else
500#endif
501 {
502 auto const& lo = amrex::lbound(box);
503 auto const& hi = amrex::ubound(box);
504#ifdef AMREX_USE_OMP
505#pragma omp parallel for collapse(3)
506#endif
507 for (int n = 0; n < ncomp; ++n) {
508 for (int k = lo.z; k <= hi.z; ++k) {
509 for (int j = lo.y; j <= hi.y; ++j) {
511 for (int i = lo.x; i <= hi.x; ++i) {
512 da(i,j,k,n) += sa(i,j,k,n);
513 }}}}
514 }
515 }
516 }
517 return;
518 }
519
520 if ((src.boxArray().ixType().cellCentered() || op == FabArrayBase::COPY) &&
521 (boxarray == src.boxarray && distributionMap == src.distributionMap) &&
522 snghost == IntVect::TheZeroVector() &&
523 dnghost == IntVect::TheZeroVector() &&
524 !period.isAnyPeriodic() && !to_ghost_cells_only && (offset == 0))
525 {
526 //
527 // Short-circuit full intersection code if we're doing copy()s or if
528 // we're doing plus()s on cell-centered data. Don't do plus()s on
529 // non-cell-centered data this simplistic way.
530 //
531 if (this != &src) { // avoid self copy or plus
532 if (op == FabArrayBase::COPY) {
533 Copy(*this, src, scomp, dcomp, ncomp, IntVect(0));
534 } else {
535 Add(*this, src, scomp, dcomp, ncomp, IntVect(0));
536 }
537 }
538 return;
539 }
540
541 const CPC& thecpc = (a_cpc) ? *a_cpc : getCPC(dnghost, src, snghost, period,
542 to_ghost_cells_only,offset);
543
545 {
546 //
547 // There can only be local work to do.
548 //
549
550 int N_locs = (*thecpc.m_LocTags).size();
551 if (N_locs == 0) { return; }
552#ifdef AMREX_USE_GPU
554 {
555 PC_local_gpu(thecpc, src, scomp, dcomp, ncomp, op,
556 deterministic && (op == FabArrayBase::ADD));
557 }
558 else
559#endif
560 {
561 PC_local_cpu(thecpc, src, scomp, dcomp, ncomp, op);
562 }
563
564 return;
565 }
566
567#ifdef BL_USE_MPI
568
569 //
570 // Do this before prematurely exiting if running in parallel.
571 // Otherwise sequence numbers will not match across MPI processes.
572 //
573 int tag = ParallelDescriptor::SeqNum();
574
575 const int N_snds = thecpc.m_SndTags->size();
576 const int N_rcvs = thecpc.m_RcvTags->size();
577 const int N_locs = thecpc.m_LocTags->size();
578
579 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) {
580 //
581 // No work to do.
582 //
583
584 return;
585 }
586
587 //
588 // Send/Recv at most MaxComp components at a time to cut down memory usage.
589 //
590 int NCompLeft = ncomp;
591 int SC = scomp, DC = dcomp, NC;
592
593 for (int ipass = 0; ipass < ncomp; )
594 {
595 pcd = std::make_unique<PCData<FAB>>();
596 pcd->cpc = &thecpc;
597 pcd->src = &src;
598 pcd->op = op;
599 pcd->tag = tag;
600 // Deterministic GPU unpacking is currently implemented only for ADD.
601 pcd->deterministic = deterministic && (op == FabArrayBase::ADD);
602
603 NC = std::min(NCompLeft,FabArrayBase::MaxComp);
604 const bool last_iter = (NCompLeft == NC);
605
606 pcd->SC = SC;
607 pcd->DC = DC;
608 pcd->NC = NC;
609
610 //
611 // Post rcvs. Allocate one chunk of space to hold'm all.
612 //
613 pcd->the_recv_data = nullptr;
614
615 pcd->actual_n_rcvs = 0;
616 if (N_rcvs > 0) {
617 PostRcvs(*thecpc.m_RcvTags, pcd->the_recv_data,
618 pcd->recv_data, pcd->recv_size, pcd->recv_from, pcd->recv_reqs, NC, pcd->tag);
619 pcd->actual_n_rcvs = N_rcvs - std::ranges::count(pcd->recv_size, 0);
620 }
621
622 //
623 // Post send's
624 //
625 Vector<char*> send_data;
626 Vector<std::size_t> send_size;
627 Vector<int> send_rank;
629
630 if (N_snds > 0)
631 {
632 src.PrepareSendBuffers(*thecpc.m_SndTags, pcd->the_send_data, send_data, send_size,
633 send_rank, pcd->send_reqs, send_cctc, NC);
634
635#ifdef AMREX_USE_GPU
637 {
638 pack_send_buffer_gpu(src, SC, NC, send_data, send_size, send_cctc, thecpc.m_id);
639 }
640 else
641#endif
642 {
643 pack_send_buffer_cpu(src, SC, NC, send_data, send_size, send_cctc);
644 }
645
646 AMREX_ASSERT(pcd->send_reqs.size() == N_snds);
647 FabArray<FAB>::PostSnds(send_data, send_size, send_rank, pcd->send_reqs, pcd->tag);
648 }
649
650 //
651 // Do the local work. Hope for a bit of communication/computation overlap.
652 //
653 if (N_locs > 0)
654 {
655#ifdef AMREX_USE_GPU
657 {
658 PC_local_gpu(thecpc, src, SC, DC, NC, op,
659 deterministic && (op == FabArrayBase::ADD));
660 }
661 else
662#endif
663 {
664 PC_local_cpu(thecpc, src, SC, DC, NC, op);
665 }
666 }
667
668 if (!last_iter)
669 {
670 ParallelCopy_finish();
671 BL_PROFILE_SYNC_START_TIMED("SyncBeforeComms: PC");
672
673 SC += NC;
674 DC += NC;
675 }
676
677 ipass += NC;
678 NCompLeft -= NC;
679 }
680
681#endif /*BL_USE_MPI*/
682
683#ifndef AMREX_USE_GPU
684 amrex::ignore_unused(deterministic);
685#endif
686}
687
688template <class FAB>
689void
691{
692
693#ifdef BL_USE_MPI
694
695 BL_PROFILE("FabArray::ParallelCopy_finish()");
697
698 if (!pcd) { return; }
699
700 const CPC* thecpc = pcd->cpc;
701
702 const auto N_snds = static_cast<int>(thecpc->m_SndTags->size());
703 const auto N_rcvs = static_cast<int>(thecpc->m_RcvTags->size());
704
705 if (N_rcvs > 0)
706 {
707 Vector<const CopyComTagsContainer*> recv_cctc(N_rcvs,nullptr);
708 for (int k = 0; k < N_rcvs; ++k)
709 {
710 if (pcd->recv_size[k] > 0)
711 {
712 auto const& cctc = thecpc->m_RcvTags->at(pcd->recv_from[k]);
713 recv_cctc[k] = &cctc;
714 }
715 }
716
717 if (pcd->actual_n_rcvs > 0) {
718 Vector<MPI_Status> stats(N_rcvs);
719 ParallelDescriptor::Waitall(pcd->recv_reqs, stats);
720#ifdef AMREX_DEBUG
721 if (!CheckRcvStats(stats, pcd->recv_size, pcd->tag))
722 {
723 amrex::Abort("ParallelCopy failed with wrong message size");
724 }
725#endif
726 }
727
728 bool is_thread_safe = thecpc->m_threadsafe_rcv;
729
730#ifdef AMREX_USE_GPU
732 {
733 unpack_recv_buffer_gpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
734 recv_cctc, pcd->op, is_thread_safe, thecpc->m_id,
735 pcd->deterministic);
736 }
737 else
738#endif
739 {
740 unpack_recv_buffer_cpu(*this, pcd->DC, pcd->NC, pcd->recv_data, pcd->recv_size,
741 recv_cctc, pcd->op, is_thread_safe);
742 }
743
744 if (pcd->the_recv_data)
745 {
746 amrex::The_Comms_Arena()->free(pcd->the_recv_data);
747 pcd->the_recv_data = nullptr;
748 }
749 }
750
751 if (N_snds > 0) {
752 if (! thecpc->m_SndTags->empty()) {
753 Vector<MPI_Status> stats(pcd->send_reqs.size());
754 ParallelDescriptor::Waitall(pcd->send_reqs, stats);
755 }
756 amrex::The_Comms_Arena()->free(pcd->the_send_data);
757 pcd->the_send_data = nullptr;
758 }
759
760 pcd.reset();
761
762#endif /*BL_USE_MPI*/
763}
764
765template <class FAB>
766void
767FabArray<FAB>::copyTo (FAB& dest, int scomp, int dcomp, int ncomp, int nghost) const
768{
769 BL_PROFILE("FabArray::copy(fab)");
770
771 BL_ASSERT(dcomp + ncomp <= dest.nComp());
772 BL_ASSERT(IntVect(nghost).allLE(nGrowVect()));
773
774 int root_proc = this->DistributionMap()[0];
775
776 BoxArray ba(dest.box());
777 DistributionMapping dm(Vector<int>{root_proc});
778 FabArray<FAB> destmf(ba, dm, ncomp, 0, MFInfo().SetAlloc(false));
779 if (ParallelDescriptor::MyProc() == root_proc) {
780 destmf.setFab(0, FAB(dest, amrex::make_alias, dcomp, ncomp));
781 }
782
783 destmf.ParallelCopy(*this, scomp, 0, ncomp, nghost, 0);
784
785#ifdef BL_USE_MPI
786 using T = typename FAB::value_type;
787 if (ParallelContext::NProcsSub() > 1) {
788 Long count = dest.numPts()*ncomp;
789 T* const p0 = dest.dataPtr(dcomp);
790 T* pb = p0;
791#ifdef AMREX_USE_GPU
792 if (dest.arena()->isDevice() && !ParallelDescriptor::UseGpuAwareMpi()) {
793 pb = (T*)The_Pinned_Arena()->alloc(sizeof(T)*count);
794 Gpu::dtoh_memcpy_async(pb, p0, sizeof(T)*count);
796 }
797#endif
800#ifdef AMREX_USE_GPU
801 if (pb != p0) {
802 Gpu::htod_memcpy_async(p0, pb, sizeof(T)*count);
804 The_Pinned_Arena()->free(pb);
805 }
806#endif
807 }
808#endif
809}
810
811#ifdef BL_USE_MPI
812template <class FAB>
813template <typename BUF>
814[[nodiscard]] TheFaArenaPointer
815FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers& SndTags,
816 Vector<char*>& send_data,
817 Vector<std::size_t>& send_size,
818 Vector<int>& send_rank,
819 Vector<MPI_Request>& send_reqs,
821 int ncomp)
822{
823 char* pointer = nullptr;
824 PrepareSendBuffers<BUF>(SndTags, pointer, send_data, send_size, send_rank, send_reqs, send_cctc, ncomp);
825 return TheFaArenaPointer(pointer);
826}
827
828template <class FAB>
829template <typename BUF>
830void
831FabArray<FAB>::PrepareSendBuffers (const MapOfCopyComTagContainers& SndTags,
832 char*& the_send_data,
833 Vector<char*>& send_data,
834 Vector<std::size_t>& send_size,
835 Vector<int>& send_rank,
836 Vector<MPI_Request>& send_reqs,
837 Vector<const CopyComTagsContainer*>& send_cctc,
838 int ncomp)
839{
840 send_data.clear();
841 send_size.clear();
842 send_rank.clear();
843 send_reqs.clear();
844 send_cctc.clear();
845 const auto N_snds = SndTags.size();
846 if (N_snds == 0) { return; }
847 send_data.reserve(N_snds);
848 send_size.reserve(N_snds);
849 send_rank.reserve(N_snds);
850 send_reqs.reserve(N_snds);
851 send_cctc.reserve(N_snds);
852
853 Vector<std::size_t> offset; offset.reserve(N_snds);
854 std::size_t total_volume = 0;
855 for (auto const& kv : SndTags)
856 {
857 auto const& cctc = kv.second;
858
859 std::size_t nbytes = 0;
860 for (auto const& cct : kv.second)
861 {
862 nbytes += cct.sbox.numPts() * ncomp * sizeof(BUF);
863 }
864
865 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
866 nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
867
868 // Also need to align the offset properly
869 total_volume = amrex::aligned_size(std::max(alignof(BUF), acd),
870 total_volume);
871
872 offset.push_back(total_volume);
873 total_volume += nbytes;
874
875 send_data.push_back(nullptr);
876 send_size.push_back(nbytes);
877 send_rank.push_back(kv.first);
878 send_reqs.push_back(MPI_REQUEST_NULL);
879 send_cctc.push_back(&cctc);
880 }
881
882 if (total_volume > 0)
883 {
884 the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(total_volume));
885 for (int i = 0, N = static_cast<int>(send_size.size()); i < N; ++i) {
886 send_data[i] = the_send_data + offset[i];
887 }
888 } else {
889 the_send_data = nullptr;
890 }
891}
892
893template <class FAB>
894void
895FabArray<FAB>::PostSnds (Vector<char*> const& send_data,
896 Vector<std::size_t> const& send_size,
897 Vector<int> const& send_rank,
898 Vector<MPI_Request>& send_reqs,
899 int SeqNum)
900{
902
903 const auto N_snds = static_cast<int>(send_reqs.size());
904 for (int j = 0; j < N_snds; ++j)
905 {
906 if (send_size[j] > 0) {
907 const int rank = ParallelContext::global_to_local_rank(send_rank[j]);
908 send_reqs[j] = ParallelDescriptor::Asend
909 (send_data[j], send_size[j], rank, SeqNum, comm).req();
910 }
911 }
912}
913
914template <class FAB>
915template <typename BUF>
916TheFaArenaPointer FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers& RcvTags,
917 Vector<char*>& recv_data,
918 Vector<std::size_t>& recv_size,
919 Vector<int>& recv_from,
920 Vector<MPI_Request>& recv_reqs,
921 int ncomp,
922 int SeqNum)
923{
924 char* pointer = nullptr;
925 PostRcvs(RcvTags, pointer, recv_data, recv_size, recv_from, recv_reqs, ncomp, SeqNum);
926 return TheFaArenaPointer(pointer);
927}
928
929template <class FAB>
930template <typename BUF>
931void
932FabArray<FAB>::PostRcvs (const MapOfCopyComTagContainers& RcvTags,
933 char*& the_recv_data,
934 Vector<char*>& recv_data,
935 Vector<std::size_t>& recv_size,
936 Vector<int>& recv_from,
937 Vector<MPI_Request>& recv_reqs,
938 int ncomp,
939 int SeqNum)
940{
941 recv_data.clear();
942 recv_size.clear();
943 recv_from.clear();
944 recv_reqs.clear();
945
946 Vector<std::size_t> offset;
947 std::size_t TotalRcvsVolume = 0;
948 for (const auto& kv : RcvTags) // loop over senders
949 {
950 std::size_t nbytes = 0;
951 for (auto const& cct : kv.second)
952 {
953 nbytes += cct.dbox.numPts() * ncomp * sizeof(BUF);
954 }
955
956 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
957 nbytes = amrex::aligned_size(acd, nbytes); // so that nbytes are aligned
958
959 // Also need to align the offset properly
960 TotalRcvsVolume = amrex::aligned_size(std::max(alignof(BUF),acd),
961 TotalRcvsVolume);
962
963 offset.push_back(TotalRcvsVolume);
964 TotalRcvsVolume += nbytes;
965
966 recv_data.push_back(nullptr);
967 recv_size.push_back(nbytes);
968 recv_from.push_back(kv.first);
969 recv_reqs.push_back(MPI_REQUEST_NULL);
970 }
971
972 const auto nrecv = static_cast<int>(recv_from.size());
973
975
976 if (TotalRcvsVolume == 0)
977 {
978 the_recv_data = nullptr;
979 }
980 else
981 {
982 the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
983
984 for (int i = 0; i < nrecv; ++i)
985 {
986 recv_data[i] = the_recv_data + offset[i];
987 if (recv_size[i] > 0)
988 {
989 const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
990 recv_reqs[i] = ParallelDescriptor::Arecv
991 (recv_data[i], recv_size[i], rank, SeqNum, comm).req();
992 }
993 }
994 }
995}
996#endif
997
998template <class FAB>
999void
1001 int scomp,
1002 int dcomp,
1003 int ncomp,
1004 const IntVect& nghost)
1005{
1007 "FabArray::Redistribute: must have the same BoxArray");
1008
1009 if (ParallelContext::NProcsSub() == 1)
1010 {
1011 Copy(*this, src, scomp, dcomp, ncomp, nghost);
1012 return;
1013 }
1014
1015#ifdef BL_USE_MPI
1016
1018
1019 ParallelCopy(src, scomp, dcomp, ncomp, nghost, nghost, Periodicity::NonPeriodic(),
1020 FabArrayBase::COPY, &cpc);
1021
1022#endif
1023}
1024
1025template <class FAB>
1026void
1028{
1029#if defined(AMREX_USE_MPI) && !defined(AMREX_DEBUG)
1030 // We only test if no DEBUG because in DEBUG we check the status later.
1031 // If Test is done here, the status check will fail.
1032 int flag;
1033 ParallelDescriptor::Test(fbd->recv_reqs, flag, fbd->recv_stat);
1034#endif
1035}
1036
1038namespace detail {
1039template <class TagT>
1040void fbv_copy (Vector<TagT> const& tags)
1041{
1042 const int N = tags.size();
1043 if (N == 0) { return; }
1044#ifdef AMREX_USE_GPU
1045 if (Gpu::inLaunchRegion()) {
1046 ParallelFor(tags, 1,
1047 [=] AMREX_GPU_DEVICE (int i, int j, int k, int, TagT const& tag) noexcept
1048 {
1049 const int ncomp = tag.dfab.nComp();
1050 for (int n = 0; n < ncomp; ++n) {
1051 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
1052 }
1053 });
1054 } else
1055#endif
1056 {
1057#ifdef AMREX_USE_OMP
1058#pragma omp parallel for
1059#endif
1060 for (int itag = 0; itag < N; ++itag) {
1061 auto const& tag = tags[itag];
1062 const int ncomp = tag.dfab.nComp();
1063 AMREX_LOOP_4D(tag.dbox, ncomp, i, j, k, n,
1064 {
1065 tag.dfab(i,j,k,n) = tag.sfab(i+tag.offset.x,j+tag.offset.y,k+tag.offset.z,n);
1066 });
1067 }
1068 }
1069}
1070}
1072
1086template <FabArrayType MF>
1087void
1089 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1090 Vector<Periodicity> const& period,
1091 Vector<int> const& cross = {})
1092{
1093 BL_PROFILE("FillBoundary_nowait(Vector)");
1094 const int N = mf.size();
1095 for (int i = 0; i < N; ++i) {
1096 mf[i]->FillBoundary_nowait(scomp[i], ncomp[i], nghost[i], period[i],
1097 cross.empty() ? 0 : cross[i]);
1098 }
1099}
1100
1109template <FabArrayType MF>
1110void
1112 const Periodicity& a_period = Periodicity::NonPeriodic())
1113{
1114 Vector<int> scomp(mf.size(), 0);
1115 Vector<int> ncomp;
1116 Vector<IntVect> nghost;
1117 Vector<Periodicity> period(mf.size(), a_period);
1118 ncomp.reserve(mf.size());
1119 nghost.reserve(mf.size());
1120 for (auto const& x : mf) {
1121 ncomp.push_back(x->nComp());
1122 nghost.push_back(x->nGrowVect());
1123 }
1124 FillBoundary_nowait(mf, scomp, ncomp, nghost, period);
1125}
1126
1132template <FabArrayType MF>
1133void
1135{
1136 BL_PROFILE("FillBoundary_finish(Vector)");
1137 const int N = mf.size();
1138 for (int i = 0; i < N; ++i) {
1139 mf[i]->FillBoundary_finish();
1140 }
1141}
1142
1155template <FabArrayType MF>
1156void
1158 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1159 Vector<Periodicity> const& period)
1160{
1161 BL_PROFILE("FillBoundaryAndSync_nowait(Vector)");
1162 const int N = mf.size();
1163 for (int i = 0; i < N; ++i) {
1164 mf[i]->FillBoundaryAndSync_nowait(scomp[i], ncomp[i], nghost[i], period[i]);
1165 }
1166}
1167
1174template <FabArrayType MF>
1175void
1177 const Periodicity& a_period = Periodicity::NonPeriodic())
1178{
1179 Vector<int> scomp(mf.size(), 0);
1180 Vector<int> ncomp;
1181 Vector<IntVect> nghost;
1182 Vector<Periodicity> period(mf.size(), a_period);
1183 ncomp.reserve(mf.size());
1184 nghost.reserve(mf.size());
1185 for (auto const& x : mf) {
1186 ncomp.push_back(x->nComp());
1187 nghost.push_back(x->nGrowVect());
1188 }
1189 FillBoundaryAndSync_nowait(mf, scomp, ncomp, nghost, period);
1190}
1191
1197template <FabArrayType MF>
1198void
1200{
1201 BL_PROFILE("FillBoundaryAndSync_finish(Vector)");
1202 const int N = mf.size();
1203 for (int i = 0; i < N; ++i) {
1204 mf[i]->FillBoundaryAndSync_finish();
1205 }
1206}
1207
1223template <FabArrayType MF>
1224void
1225FillBoundary (Vector<MF*> const& mf, Vector<int> const& scomp,
1226 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1227 Vector<Periodicity> const& period, Vector<int> const& cross = {})
1228{
1229 BL_PROFILE("FillBoundary(Vector)");
1230#if 1
1231 const int N = mf.size();
1232 for (int i = 0; i < N; ++i) {
1233 mf[i]->FillBoundary_nowait(scomp[i], ncomp[i], nghost[i], period[i],
1234 cross.empty() ? 0 : cross[i]);
1236 for (int i = 0; i < N; ++i) {
1237 mf[i]->FillBoundary_finish();
1238 }
1239
1240#else
1241 using FAB = typename MF::FABType::value_type;
1242 using T = typename FAB::value_type;
1243
1244 const int nmfs = mf.size();
1245 Vector<FabArrayBase::CommMetaData const*> cmds;
1246 int N_locs = 0;
1247 int N_rcvs = 0;
1248 int N_snds = 0;
1249 for (int imf = 0; imf < nmfs; ++imf) {
1250 if (nghost[imf].max() > 0) {
1251 auto const& TheFB = mf[imf]->getFB(nghost[imf], period[imf],
1252 cross.empty() ? 0 : cross[imf]);
1253 // The FB is cached. Therefore it's safe take its address for later use.
1254 cmds.push_back(static_cast<FabArrayBase::CommMetaData const*>(&TheFB));
1255 N_locs += TheFB.m_LocTags->size();
1256 N_rcvs += TheFB.m_RcvTags->size();
1257 N_snds += TheFB.m_SndTags->size();
1258 } else {
1259 cmds.push_back(nullptr);
1260 }
1261 }
1262
1263 using TagT = Array4CopyTag<T>;
1264 Vector<TagT> local_tags;
1265 local_tags.reserve(N_locs);
1266 static_assert(amrex::IsStoreAtomic<T>::value, "FillBoundary(Vector): storing T is not atomic");
1267 for (int imf = 0; imf < nmfs; ++imf) {
1268 if (cmds[imf]) {
1269 auto const& tags = *(cmds[imf]->m_LocTags);
1270 for (auto const& tag : tags) {
1271 local_tags.push_back(TagT{.dfab = (*mf[imf])[tag.dstIndex].array(scomp[imf],ncomp[imf]),
1272 .dindex = tag.dstIndex,
1273 .sfab = (*mf[imf])[tag.srcIndex].const_array(scomp[imf],ncomp[imf]),
1274 .dbox = tag.dbox,
1275 .offset = (tag.sbox.smallEnd()-tag.dbox.smallEnd()).dim3()});
1276 }
1277 }
1278 }
1279
1280 if (ParallelContext::NProcsSub() == 1) {
1281 detail::fbv_copy(local_tags);
1282 return;
1283 }
1284
1285#ifdef AMREX_USE_MPI
1286 //
1287 // Do this before prematurely exiting if running in parallel.
1288 // Otherwise sequence numbers will not match across MPI processes.
1289 //
1290 int SeqNum = ParallelDescriptor::SeqNum();
1292
1293 if (N_locs == 0 && N_rcvs == 0 && N_snds == 0) { return; } // No work to do
1295 char* the_recv_data = nullptr;
1296 Vector<int> recv_from;
1297 Vector<std::size_t> recv_size;
1298 Vector<MPI_Request> recv_reqs;
1299 Vector<MPI_Status> recv_stat;
1300 Vector<TagT> recv_tags;
1301
1302 if (N_rcvs > 0) {
1303
1304 for (int imf = 0; imf < nmfs; ++imf) {
1305 if (cmds[imf]) {
1306 auto const& tags = *(cmds[imf]->m_RcvTags);
1307 for (const auto& kv : tags) {
1308 recv_from.push_back(kv.first);
1309 }
1310 }
1311 }
1312 amrex::RemoveDuplicates(recv_from);
1313 const int nrecv = recv_from.size();
1314
1315 recv_reqs.resize(nrecv, MPI_REQUEST_NULL);
1316 recv_stat.resize(nrecv);
1317
1318 recv_tags.reserve(N_rcvs);
1319
1320 Vector<Vector<std::size_t> > recv_offset(nrecv);
1321 Vector<std::size_t> offset;
1322 recv_size.reserve(nrecv);
1323 offset.reserve(nrecv);
1324 std::size_t TotalRcvsVolume = 0;
1325 for (int i = 0; i < nrecv; ++i) {
1326 std::size_t nbytes = 0;
1327 for (int imf = 0; imf < nmfs; ++imf) {
1328 if (cmds[imf]) {
1329 auto const& tags = *(cmds[imf]->m_RcvTags);
1330 auto it = tags.find(recv_from[i]);
1331 if (it != tags.end()) {
1332 for (auto const& cct : it->second) {
1333 auto& dfab = (*mf[imf])[cct.dstIndex];
1334 recv_offset[i].push_back(nbytes);
1335 recv_tags.push_back(TagT{
1336 .dfab = dfab.array(scomp[imf],ncomp[imf]),
1337 .dindex = cct.dstIndex,
1338 .sfab = makeArray4<T const>(nullptr,cct.dbox,ncomp[imf]),
1339 .dbox = cct.dbox,
1340 .offset = Dim3{.x = 0, .y = 0, .z = 0}
1341 });
1342 nbytes += dfab.nBytes(cct.dbox,ncomp[imf]);
1343 }
1344 }
1345 }
1346 }
1347
1348 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
1349 nbytes = amrex::aligned_size(acd, nbytes); // so that nbytes are aligned
1350
1351 // Also need to align the offset properly
1352 TotalRcvsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalRcvsVolume);
1353
1354 offset.push_back(TotalRcvsVolume);
1355 TotalRcvsVolume += nbytes;
1356
1357 recv_size.push_back(nbytes);
1358 }
1359
1360 the_recv_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalRcvsVolume));
1361
1362 int k = 0;
1363 for (int i = 0; i < nrecv; ++i) {
1364 char* p = the_recv_data + offset[i];
1365 const int rank = ParallelContext::global_to_local_rank(recv_from[i]);
1366 recv_reqs[i] = ParallelDescriptor::Arecv
1367 (p, recv_size[i], rank, SeqNum, comm).req();
1368 for (int j = 0, nj = recv_offset[i].size(); j < nj; ++j) {
1369 recv_tags[k++].sfab.p = (T const*)(p + recv_offset[i][j]);
1370 }
1372 }
1373
1374 char* the_send_data = nullptr;
1375 Vector<int> send_rank;
1376 Vector<char*> send_data;
1377 Vector<std::size_t> send_size;
1378 Vector<MPI_Request> send_reqs;
1379 if (N_snds > 0) {
1380 for (int imf = 0; imf < nmfs; ++imf) {
1381 if (cmds[imf]) {
1382 auto const& tags = *(cmds[imf]->m_SndTags);
1383 for (auto const& kv : tags) {
1384 send_rank.push_back(kv.first);
1385 }
1386 }
1387 }
1388 amrex::RemoveDuplicates(send_rank);
1389 const int nsend = send_rank.size();
1390
1391 send_data.resize(nsend, nullptr);
1392 send_reqs.resize(nsend, MPI_REQUEST_NULL);
1393
1394 Vector<TagT> send_tags;
1395 send_tags.reserve(N_snds);
1396
1397 Vector<Vector<std::size_t> > send_offset(nsend);
1398 Vector<std::size_t> offset;
1399 send_size.reserve(nsend);
1400 offset.reserve(nsend);
1401 std::size_t TotalSndsVolume = 0;
1402 for (int i = 0; i < nsend; ++i) {
1403 std::size_t nbytes = 0;
1404 for (int imf = 0; imf < nmfs; ++imf) {
1405 if (cmds[imf]) {
1406 auto const& tags = *(cmds[imf]->m_SndTags);
1407 auto it = tags.find(send_rank[i]);
1408 if (it != tags.end()) {
1409 for (auto const& cct : it->second) {
1410 auto const& sfab = (*mf[imf])[cct.srcIndex];
1411 send_offset[i].push_back(nbytes);
1412 send_tags.push_back(TagT{
1413 .dfab = amrex::makeArray4<T>(nullptr,cct.sbox,ncomp[imf]),
1414 .dindex = cct.dstIndex,
1415 .sfab = sfab.const_array(scomp[imf],ncomp[imf]),
1416 .dbox = cct.sbox,
1417 .offset = Dim3{.x = 0, .y = 0, .z = 0}
1418 });
1419 nbytes += sfab.nBytes(cct.sbox,ncomp[imf]);
1420 }
1421 }
1422 }
1423 }
1424
1425 std::size_t acd = ParallelDescriptor::sizeof_selected_comm_data_type(nbytes);
1426 nbytes = amrex::aligned_size(acd, nbytes); // so that bytes are aligned
1427
1428 // Also need to align the offset properly
1429 TotalSndsVolume = amrex::aligned_size(std::max(alignof(T),acd), TotalSndsVolume);
1430
1431 offset.push_back(TotalSndsVolume);
1432 TotalSndsVolume += nbytes;
1433
1434 send_size.push_back(nbytes);
1435 }
1437 the_send_data = static_cast<char*>(amrex::The_Comms_Arena()->alloc(TotalSndsVolume));
1438 int k = 0;
1439 for (int i = 0; i < nsend; ++i) {
1440 send_data[i] = the_send_data + offset[i];
1441 for (int j = 0, nj = send_offset[i].size(); j < nj; ++j) {
1442 send_tags[k++].dfab.p = (T*)(send_data[i] + send_offset[i][j]);
1443 }
1444 }
1445
1446 detail::fbv_copy(send_tags);
1447
1448 FabArray<FAB>::PostSnds(send_data, send_size, send_rank, send_reqs, SeqNum);
1449 }
1450
1451#if !defined(AMREX_DEBUG)
1452 int recv_flag;
1453 ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
1454#endif
1455
1456 if (N_locs > 0) {
1457 detail::fbv_copy(local_tags);
1458#if !defined(AMREX_DEBUG)
1459 ParallelDescriptor::Test(recv_reqs, recv_flag, recv_stat);
1460#endif
1461 }
1462
1463 if (N_rcvs > 0) {
1464 ParallelDescriptor::Waitall(recv_reqs, recv_stat);
1465#ifdef AMREX_DEBUG
1466 if (!FabArrayBase::CheckRcvStats(recv_stat, recv_size, SeqNum)) {
1467 amrex::Abort("FillBoundary(vector) failed with wrong message size");
1468 }
1469#endif
1470
1471 detail::fbv_copy(recv_tags);
1472
1473 amrex::The_Comms_Arena()->free(the_recv_data);
1474 }
1475
1476 if (N_snds > 0) {
1477 Vector<MPI_Status> stats(send_reqs.size());
1478 ParallelDescriptor::Waitall(send_reqs, stats);
1479 amrex::The_Comms_Arena()->free(the_send_data);
1480 }
1481
1482#endif // #ifdef AMREX_USE_MPI
1483#endif // #if 1 #else
1484}
1485
1498template <FabArrayType MF>
1499void
1501 Vector<int> const& ncomp, Vector<IntVect> const& nghost,
1502 Vector<Periodicity> const& period)
1503{
1504 BL_PROFILE("FillBoundaryAndSync(Vector)");
1505 const int N = mf.size();
1506 for (int i = 0; i < N; ++i) {
1507 mf[i]->FillBoundaryAndSync_nowait(scomp[i], ncomp[i], nghost[i], period[i]);
1508 }
1509 for (int i = 0; i < N; ++i) {
1510 mf[i]->FillBoundaryAndSync_finish();
1511 }
1512}
1513
1515template <FabArrayType MF>
1516void
1518{
1519 FillBoundary_nowait(mf, a_period);
1521}
1522
1524template <FabArrayType MF>
1525void
1531
1532}
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:562
#define BL_PROFILE_SYNC_STOP()
Definition AMReX_BLProfiler.H:656
#define BL_PROFILE_SYNC_START_TIMED(fname)
Definition AMReX_BLProfiler.H:655
#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:1131
#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:681
IndexType ixType() const noexcept
Return index type of this BoxArray.
Definition AMReX_BoxArray.H:1268
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:399
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:1000
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:368
void ParallelCopy_finish()
Finish the current nowait ParallelCopy or ParallelAdd operation.
Definition AMReX_FabArrayCommI.H:690
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:385
void FillBoundary_test()
Definition AMReX_FabArrayCommI.H:1027
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:2976
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:1365
__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 > 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:875
Arena * The_Pinned_Arena()
Definition AMReX_Arena.cpp:855
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:105
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:101
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:1224
Message Asend(const T *, size_t n, int pid, int tag)
Definition AMReX_ParallelDescriptor.H:1163
bool UseGpuAwareMpi()
Definition AMReX_ParallelDescriptor.H:113
void Waitall(Vector< MPI_Request > &, Vector< MPI_Status > &)
Definition AMReX_ParallelDescriptor.cpp:1312
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:1205
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:1134
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:2870
DistributionMapping const & DistributionMap(FabArrayBase const &fa)
Convenience wrapper that forwards to fa.DistributionMap().
Definition AMReX_FabArrayBase.cpp:2875
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:1088
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:1157
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:1500
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:2251
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:2865
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:242
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:1199
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:1225
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