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