1#ifndef AMREX_FFT_R2C_H_
2#define AMREX_FFT_R2C_H_
3#include <AMReX_Config.H>
22template <
typename T>
class Poisson;
46template <
typename T = Real, FFT::Direction D = FFT::Direction::both,
bool C = false>
51 using MF = std::conditional_t
52 <
C,
cMF, std::conditional_t<std::is_same_v<T,Real>,
56 template <
typename U>
friend class Poisson;
77 explicit R2C (std::array<int,AMREX_SPACEDIM>
const& domain_size,
111 std::array<int,AMREX_SPACEDIM>
const& local_size);
126 std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
158 std::array<int,AMREX_SPACEDIM>
const& local_size);
178 std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
210 template <
typename F, Direction DIR=D>
213 int incomp = 0,
int outcomp = 0)
217 "FFT::R2C::forwardThenBackward(post_forward) currently supports only !twod_mode");
234 template <Direction DIR=D>
249 template <Direction DIR=D>
251 void forward (
MF const& inmf,
cMF& outmf,
int incomp = 0,
int outcomp = 0);
269 template <
typename RT,
typename CT, Direction DIR=D,
bool CP=C>
271 && (((
sizeof(RT)*2 ==
sizeof(CT)) && (!CP))
272 || ((
sizeof(RT) ==
sizeof(CT)) && CP))
284 template <Direction DIR=D>
299 template <Direction DIR=D>
301 void backward (
cMF const& inmf,
MF& outmf,
int incomp = 0,
int outcomp = 0);
319 template <
typename CT,
typename RT, Direction DIR=D,
bool CP=C>
321 && (((
sizeof(RT)*2 ==
sizeof(CT)) && (!CP))
322 || ((
sizeof(RT) ==
sizeof(CT)) && CP))
345 template <Direction DIR=D>
366 template <
typename F>
369 template <
typename F>
379 void prepare_openbc ();
385 void backward_doit (
cMF const& inmf,
MF& outmf,
388 int incomp = 0,
int outcomp = 0);
390 std::pair<Plan<T>,
Plan<T>> make_c2c_plans (
cMF& inout,
int ndims)
const;
392 [[nodiscard]]
MF& make_m_rx_alias (
IndexType const& ix_type);
397 static Box make_domain_x (
Box const& domain)
412 static Box make_domain_y (
Box const& domain)
417 domain.length(2)-1)),
422 domain.length(2)-1)),
427 static Box make_domain_z (
Box const& domain)
432 domain.length(1)-1)),
437 domain.length(1)-1)),
442 static std::pair<BoxArray,DistributionMapping>
443 make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM>
const& local_start,
444 std::array<int,AMREX_SPACEDIM>
const& local_size);
446 template <
typename FA,
typename RT>
447 std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
448 install_raw_ptr (FA& fa, RT
const*
p);
450 Plan<T> m_fft_fwd_x{};
451 Plan<T> m_fft_bwd_x{};
452 Plan<T> m_fft_fwd_y{};
453 Plan<T> m_fft_bwd_y{};
454 Plan<T> m_fft_fwd_z{};
455 Plan<T> m_fft_bwd_z{};
456 Plan<T> m_fft_fwd_x_half{};
457 Plan<T> m_fft_bwd_x_half{};
462 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2y;
463 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2x;
464 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2z;
465 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2y;
466 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z;
467 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x;
468 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z_half;
469 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x_half;
474 RotateFwd m_dtos_x2z{};
475 RotateBwd m_dtos_z2x{};
483 mutable cMF m_raw_cmf;
485 std::map<IntVect,MF> m_rx_aliases;
487 std::unique_ptr<char,DataDeleter> m_data_1;
488 std::unique_ptr<char,DataDeleter> m_data_2;
491 Box m_spectral_domain_x;
492 Box m_spectral_domain_y;
493 Box m_spectral_domain_z;
495 std::unique_ptr<R2C<T,D,C>> m_r2c_sub;
496 detail::SubHelper m_sub_helper;
500 bool m_do_alld_fft =
false;
501 bool m_slab_decomp =
false;
502 bool m_openbc_half =
false;
505template <
typename T, Direction D,
bool C>
507 : m_real_domain(domain),
508 m_spectral_domain_x(make_domain_x(domain)),
509#if (AMREX_SPACEDIM >= 2)
510 m_spectral_domain_y(make_domain_y(domain)),
511#if (AMREX_SPACEDIM == 3)
512 m_spectral_domain_z(make_domain_z(domain)),
515 m_sub_helper(domain),
520 static_assert(std::is_same_v<float,T> || std::is_same_v<double,T>);
523#if (AMREX_SPACEDIM == 2)
526 if (m_info.twod_mode) {
528 int(domain.
length(1) > 1) +
529 int(domain.
length(2) > 1)) >= 2);
534 Box subbox = m_sub_helper.make_box(m_real_domain);
535 if (subbox.
size() != m_real_domain.size()) {
536 m_r2c_sub = std::make_unique<R2C<T,D,C>>(subbox, m_info);
544#if (AMREX_SPACEDIM == 3)
546 if (m_info.twod_mode) {
549 int shortside = m_real_domain.shortside();
550 if (shortside < m_info.pencil_threshold*nprocs) {
558 if (!m_info.oned_mode) {
559 if (m_info.twod_mode) {
560 m_slab_decomp =
true;
562 m_slab_decomp =
true;
567 auto const ncomp = m_info.batch_size;
570 {
AMREX_D_DECL(
false,!m_slab_decomp,m_real_domain.length(2)>1)},
true);
573 m_rx.define(bax, dmx, ncomp, 0,
MFInfo().SetAlloc(
false));
577 for (
auto & b : bl) {
578 b.shift(-m_real_domain.smallEnd());
579 b.setBig(0, m_spectral_domain_x.bigEnd(0));
582 m_cx.define(cbax, dmx, ncomp, 0,
MFInfo().SetAlloc(
false));
586 (! m_info.twod_mode) && (! m_info.oned_mode);
594#if (AMREX_SPACEDIM >= 2)
596 if ((m_real_domain.length(1) > 1) && !m_slab_decomp && !m_info.oned_mode)
600 if (cbay.size() == dmx.size()) {
603 cdmy = detail::make_iota_distromap(cbay.size());
605 m_cy.
define(cbay, cdmy, ncomp, 0,
MFInfo().SetAlloc(
false));
609#if (AMREX_SPACEDIM == 3)
610 if (!m_info.oned_mode && !m_info.twod_mode &&
611 m_real_domain.length(1) > 1 &&
612 m_real_domain.length(2) > 1)
615 {
false,
true,
true},
true);
617 if (cbaz.size() == dmx.size()) {
619 }
else if (cbaz.size() == cdmy.
size()) {
622 cdmz = detail::make_iota_distromap(cbaz.size());
624 m_cz.
define(cbaz, cdmz, ncomp, 0,
MFInfo().SetAlloc(
false));
630 m_data_1 = detail::make_mfs_share(m_rx, m_cx);
631 m_data_2 = detail::make_mfs_share(m_cz, m_cz);
633 m_data_1 = detail::make_mfs_share(m_rx, m_cz);
634 m_data_2 = detail::make_mfs_share(m_cy, m_cy);
636 if (myproc < m_cx.size()) {
637 Box const& box = m_cx.fabbox(myproc);
639 m_cx.setFab(myproc, FAB(box, ncomp, m_rx[myproc].dataPtr()));
644 m_data_1 = detail::make_mfs_share(m_rx, m_cz);
645 m_data_2 = detail::make_mfs_share(m_cx, m_cx);
647 m_data_1 = detail::make_mfs_share(m_rx, m_cy);
648 m_data_2 = detail::make_mfs_share(m_cx, m_cz);
656#if (AMREX_SPACEDIM >= 2)
657 if (! m_cy.empty()) {
659 m_cmd_x2y = std::make_unique<MultiBlockCommMetaData>
660 (m_cy, m_spectral_domain_y, m_cx,
IntVect(0), m_dtos_x2y);
661 m_cmd_y2x = std::make_unique<MultiBlockCommMetaData>
662 (m_cx, m_spectral_domain_x, m_cy,
IntVect(0), m_dtos_y2x);
665#if (AMREX_SPACEDIM == 3)
666 if (! m_cz.empty() ) {
669 m_cmd_x2z = std::make_unique<MultiBlockCommMetaData>
670 (m_cz, m_spectral_domain_z, m_cx,
IntVect(0), m_dtos_x2z);
671 m_cmd_z2x = std::make_unique<MultiBlockCommMetaData>
672 (m_cx, m_spectral_domain_x, m_cz,
IntVect(0), m_dtos_z2x);
675 m_cmd_y2z = std::make_unique<MultiBlockCommMetaData>
676 (m_cz, m_spectral_domain_z, m_cy,
IntVect(0), m_dtos_y2z);
677 m_cmd_z2y = std::make_unique<MultiBlockCommMetaData>
678 (m_cy, m_spectral_domain_y, m_cz,
IntVect(0), m_dtos_z2y);
687 if (myproc < m_rx.size())
690 int ndims = m_slab_decomp ? 2 : 1;
691 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx, ndims);
693 Box const& box = m_rx.box(myproc);
694 auto* pr = m_rx[myproc].dataPtr();
697 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
698 m_fft_bwd_x = m_fft_fwd_x;
701 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
704 m_fft_bwd_x.template init_r2c<Direction::backward>(box, pr, pc, m_slab_decomp, ncomp);
710#if (AMREX_SPACEDIM >= 2)
711 if (! m_cy.empty()) {
712 std::tie(m_fft_fwd_y, m_fft_bwd_y) = make_c2c_plans(m_cy,1);
715#if (AMREX_SPACEDIM == 3)
716 if (! m_cz.empty()) {
717 std::tie(m_fft_fwd_z, m_fft_bwd_z) = make_c2c_plans(m_cz,1);
724 m_data_1 = detail::make_mfs_share(m_rx, m_cx);
725 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx,AMREX_SPACEDIM);
727 m_data_1 = detail::make_mfs_share(m_rx, m_rx);
728 m_data_2 = detail::make_mfs_share(m_cx, m_cx);
730 auto const& len = m_real_domain.length();
731 auto* pr = (
void*)m_rx[0].dataPtr();
732 auto* pc = (
void*)m_cx[0].dataPtr();
734 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc,
false, ncomp);
735 m_fft_bwd_x = m_fft_fwd_x;
738 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc,
false, ncomp);
741 m_fft_bwd_x.template init_r2c<Direction::backward>(len, pr, pc,
false, ncomp);
748template <
typename T, Direction D,
bool C>
753template <
typename T, Direction D,
bool C>
756 if (m_fft_bwd_x.plan != m_fft_fwd_x.plan) {
757 m_fft_bwd_x.destroy();
759 if (m_fft_bwd_y.plan != m_fft_fwd_y.plan) {
760 m_fft_bwd_y.destroy();
762 if (m_fft_bwd_z.plan != m_fft_fwd_z.plan) {
763 m_fft_bwd_z.destroy();
765 m_fft_fwd_x.destroy();
766 m_fft_fwd_y.destroy();
767 m_fft_fwd_z.destroy();
768 if (m_fft_bwd_x_half.plan != m_fft_fwd_x_half.plan) {
769 m_fft_bwd_x_half.destroy();
771 m_fft_fwd_x_half.destroy();
774template <
typename T, Direction D,
bool C>
775std::pair<BoxArray,DistributionMapping>
776R2C<T,D,C>::make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM>
const& local_start,
777 std::array<int,AMREX_SPACEDIM>
const& local_size)
781 Box bx(lo, lo+len-1);
788 pmap.reserve(allboxes.size());
789 for (
int i = 0; i < allboxes.size(); ++i) {
790 if (allboxes[i].ok()) {
794 std::erase_if(allboxes, [=] (
Box const& b) {
return b.isEmpty(); });
795 BoxList bl(std::move(allboxes));
796 return std::make_pair(BoxArray(std::move(bl)), DistributionMapping(std::move(pmap)));
798 return std::make_pair(BoxArray(bx), DistributionMapping(Vector<int>({0})));
802template <
typename T, Direction D,
bool C>
804 std::array<int,AMREX_SPACEDIM>
const& local_size)
806 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
807 m_raw_mf =
MF(ba, dm, m_info.batch_size, 0,
MFInfo().SetAlloc(
false));
810template <
typename T, Direction D,
bool C>
811std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
814 auto const ncomp = m_info.batch_size;
816#if (AMREX_SPACEDIM > 1)
818 m_raw_mf =
MF(m_sub_helper.inverse_boxarray(m_r2c_sub->m_rx.boxArray()),
819 m_r2c_sub->m_rx.DistributionMap(), ncomp, 0,
824 m_raw_mf =
MF(m_rx.boxArray(), m_rx.DistributionMap(), ncomp, 0,
829 if (myproc < m_raw_mf.size()) {
830 Box const& box = m_raw_mf.box(myproc);
831 return std::make_pair(box.
smallEnd().toArray(),
834 return std::make_pair(std::array<int,AMREX_SPACEDIM>{
AMREX_D_DECL(0,0,0)},
839template <
typename T, Direction D,
bool C>
841 std::array<int,AMREX_SPACEDIM>
const& local_size)
843 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
844 m_raw_cmf =
cMF(ba, dm, m_info.batch_size, 0,
MFInfo().SetAlloc(
false));
847template <
typename T, Direction D,
bool C>
848std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
851 auto const ncomp = m_info.batch_size;
857 if (myproc < m_raw_cmf.size()) {
858 Box const& box = m_raw_cmf.box(myproc);
859 return std::make_pair(box.
smallEnd().toArray(), box.
length().toArray());
861 return std::make_pair(std::array<int,AMREX_SPACEDIM>{
AMREX_D_DECL(0,0,0)},
866template <
typename T, Direction D,
bool C>
867void R2C<T,D,C>::prepare_openbc ()
869 if (
C || m_r2c_sub) {
amrex::Abort(
"R2C: OpenBC not supported with reduced dimensions or complex inputs"); }
871#if (AMREX_SPACEDIM == 3)
872 if (m_do_alld_fft) {
return; }
874 auto const ncomp = m_info.batch_size;
876 if (m_slab_decomp && ! m_fft_fwd_x_half.defined) {
877 auto* fab = detail::get_fab(m_rx);
879 Box bottom_half = m_real_domain;
880 bottom_half.
growHi(2,-m_real_domain.length(2)/2);
881 Box box = fab->box() & bottom_half;
883 auto* pr = fab->dataPtr();
885 detail::get_fab(m_cx)->dataPtr();
887 m_fft_fwd_x_half.template init_r2c<Direction::forward>
888 (box, pr, pc, m_slab_decomp, ncomp);
889 m_fft_bwd_x_half = m_fft_fwd_x_half;
892 m_fft_fwd_x_half.template init_r2c<Direction::forward>
893 (box, pr, pc, m_slab_decomp, ncomp);
896 m_fft_bwd_x_half.template init_r2c<Direction::backward>
897 (box, pr, pc, m_slab_decomp, ncomp);
904 if (m_cmd_x2z && ! m_cmd_x2z_half) {
905 Box bottom_half = m_spectral_domain_z;
908 bottom_half.
growHi(0,-m_spectral_domain_z.length(0)/2);
909 m_cmd_x2z_half = std::make_unique<MultiBlockCommMetaData>
910 (m_cz, bottom_half, m_cx,
IntVect(0), m_dtos_x2z);
913 if (m_cmd_z2x && ! m_cmd_z2x_half) {
914 Box bottom_half = m_spectral_domain_x;
915 bottom_half.
growHi(2,-m_spectral_domain_x.length(2)/2);
916 m_cmd_z2x_half = std::make_unique<MultiBlockCommMetaData>
917 (m_cx, bottom_half, m_cz,
IntVect(0), m_dtos_z2x);
922template <
typename T, Direction D,
bool C>
924R2C<T,D,C>::make_m_rx_alias (
IndexType const& ix_type)
926 auto const key = ix_type.ixType();
927 auto it = m_rx_aliases.find(key);
928 if (it != m_rx_aliases.end()) {
933 for (
auto b : m_rx.boxArray().boxList()) {
938 MF alias(BoxArray(std::move(bl)), m_rx.DistributionMap(), m_rx.nComp(),
939 m_rx.nGrowVect(), MFInfo{}.SetAlloc(
false));
941 using FAB =
typename MF::fab_type;
942 for (MFIter mfi(alias, MFItInfo().DisableDeviceSync()); mfi.isValid(); ++mfi) {
943 alias.setFab(mfi, FAB(mfi.fabbox(), m_rx.nComp(), m_rx[mfi.index()].dataPtr()));
946 auto [alias_it, inserted] = m_rx_aliases.emplace(key, std::move(alias));
948 return alias_it->second;
951template <
typename T, Direction D,
bool C>
953R2C<T,D,C>::make_m_rx_alias_periodicity (
IndexType const& ix_type,
954 Periodicity
const& period)
const
956 IntVect per = period.intVect();
957 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
958 if (ix_type.nodeCentered(idim) && per[idim] == 0) {
959 per[idim] = m_real_domain.length(idim);
962 return Periodicity(per);
965template <
typename T, Direction D,
bool C>
966template <Direction DIR>
972 auto const ncomp = m_info.batch_size;
975 if (m_sub_helper.ghost_safe(inmf.nGrowVect())) {
976 m_r2c_sub->forward(m_sub_helper.make_alias_mf(inmf), incomp);
978 MF tmp(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
979 tmp.LocalCopy(inmf, incomp, 0, ncomp,
IntVect(0));
980 m_r2c_sub->forward(m_sub_helper.make_alias_mf(tmp),0);
985 if (&m_rx != &inmf) {
986 if (m_rx.boxArray().ixType() == inmf.boxArray().ixType()) {
987 m_rx.ParallelCopy(inmf, incomp, 0, ncomp);
989 MF& rx_alias = make_m_rx_alias(inmf.boxArray().ixType());
990 rx_alias.ParallelCopy(inmf, incomp, 0, ncomp);
996 m_fft_fwd_x.template compute_c2c<Direction::forward>();
998 m_fft_fwd_x.template compute_r2c<Direction::forward>();
1003 auto& fft_x = m_openbc_half ? m_fft_fwd_x_half : m_fft_fwd_x;
1005 fft_x.template compute_c2c<Direction::forward>();
1007 fft_x.template compute_r2c<Direction::forward>();
1011 ParallelCopy(m_cy, m_cx, *m_cmd_x2y, 0, 0, ncomp, m_dtos_x2y);
1013 m_fft_fwd_y.template compute_c2c<Direction::forward>();
1016 ParallelCopy(m_cz, m_cy, *m_cmd_y2z, 0, 0, ncomp, m_dtos_y2z);
1018#if (AMREX_SPACEDIM == 3)
1019 else if ( m_cmd_x2z) {
1020 if (m_openbc_half) {
1024 {components, m_dtos_x2z};
1027 Box upper_half = m_spectral_domain_z;
1030 upper_half.
growLo (0,-m_spectral_domain_z.length(0)/2);
1031 m_cz.setVal(0, upper_half, 0, ncomp);
1035 ParallelCopy(m_cz, m_cx, *m_cmd_x2z, 0, 0, ncomp, m_dtos_x2z);
1039 m_fft_fwd_z.template compute_c2c<Direction::forward>();
1042template <
typename T, Direction D,
bool C>
1043template <
typename FA,
typename RT>
1044std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
1045R2C<T,D,C>::install_raw_ptr (FA& fa, RT
const*
p)
1049 using FAB =
typename FA::FABType::value_type;
1050 using T_FAB =
typename FAB::value_type;
1051 static_assert(
sizeof(T_FAB) ==
sizeof(RT));
1053 auto const ncomp = m_info.batch_size;
1054 auto const& ia = fa.IndexArray();
1056 T_FAB* pp =
nullptr;
1059 if ( ! ia.empty() ) {
1061 Box const& box = fa.fabbox(K);
1065 sz =
sizeof(T_FAB) * box.
numPts() * ncomp;
1068 fa.setFab(K, FAB(box,ncomp,pp));
1072 return std::make_pair(std::unique_ptr<char,DataDeleter>{},std::size_t(0));
1074 return std::make_pair(std::unique_ptr<char,DataDeleter>
1075 {(
char*)pp,DataDeleter{
The_Arena()}}, sz);
1080template <
typename T, Direction D,
bool C>
1081template <
typename RT,
typename CT, Direction DIR,
bool CP>
1083 && (((
sizeof(RT)*2 ==
sizeof(CT)) && (!CP))
1084 || ((
sizeof(RT) ==
sizeof(CT)) && CP))
1087 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, in);
1088 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, out);
1103template <
typename T, Direction D,
bool C>
1104template <Direction DIR>
1111template <
typename T, Direction D,
bool C>
1112void R2C<T,D,C>::backward_doit (MF& outmf,
IntVect const& ngout,
1117 auto const ncomp = m_info.batch_size;
1120 if (m_sub_helper.ghost_safe(outmf.nGrowVect())) {
1121 MF submf = m_sub_helper.make_alias_mf(outmf);
1122 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1123 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
1124 m_r2c_sub->backward_doit(submf, subngout, subperiod, outcomp);
1126 MF tmp(outmf.boxArray(), outmf.DistributionMap(), ncomp,
1127 m_sub_helper.make_safe_ghost(outmf.nGrowVect()));
1128 this->backward_doit(tmp, ngout, period, 0);
1129 outmf.LocalCopy(tmp, 0, outcomp, ncomp, tmp.nGrowVect());
1134 if (m_do_alld_fft) {
1136 m_fft_bwd_x.template compute_c2c<Direction::backward>();
1138 m_fft_bwd_x.template compute_r2c<Direction::backward>();
1141 if (m_rx.boxArray().ixType() == outmf.boxArray().ixType()) {
1142 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp,
IntVect(0),
1143 dst_nghost, period);
1145 MF& rx_alias = make_m_rx_alias(outmf.boxArray().ixType());
1146 auto const copy_period = make_m_rx_alias_periodicity(outmf.boxArray().ixType(), period);
1147 outmf.ParallelCopy(rx_alias, 0, outcomp, ncomp,
IntVect(0),
1148 dst_nghost, copy_period);
1153 m_fft_bwd_z.template compute_c2c<Direction::backward>();
1155 ParallelCopy(m_cy, m_cz, *m_cmd_z2y, 0, 0, ncomp, m_dtos_z2y);
1157#if (AMREX_SPACEDIM == 3)
1158 else if ( m_cmd_z2x) {
1159 auto const& cmd = m_openbc_half ? m_cmd_z2x_half : m_cmd_z2x;
1160 ParallelCopy(m_cx, m_cz, *cmd, 0, 0, ncomp, m_dtos_z2x);
1164 m_fft_bwd_y.template compute_c2c<Direction::backward>();
1166 ParallelCopy(m_cx, m_cy, *m_cmd_y2x, 0, 0, ncomp, m_dtos_y2x);
1169 auto& fft_x = m_openbc_half ? m_fft_bwd_x_half : m_fft_bwd_x;
1171 fft_x.template compute_c2c<Direction::backward>();
1173 fft_x.template compute_r2c<Direction::backward>();
1176 if (m_rx.boxArray().ixType() == outmf.boxArray().ixType()) {
1177 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp,
IntVect(0),
1178 dst_nghost, period);
1180 MF& rx_alias = make_m_rx_alias(outmf.boxArray().ixType());
1181 auto const copy_period = make_m_rx_alias_periodicity(outmf.boxArray().ixType(), period);
1182 outmf.ParallelCopy(rx_alias, 0, outcomp, ncomp,
IntVect(0),
1183 dst_nghost, copy_period);
1187template <
typename T, Direction D,
bool C>
1188template <
typename CT,
typename RT, Direction DIR,
bool CP>
1190 && (((
sizeof(RT)*2 ==
sizeof(CT)) && (!CP))
1191 || ((
sizeof(RT) ==
sizeof(CT)) && CP))
1194 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, out);
1195 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, in);
1210template <
typename T, Direction D,
bool C>
1212R2C<T,D,C>::make_c2c_plans (cMF& inout,
int ndims)
const
1217 auto* fab = detail::get_fab(inout);
1218 if (!fab) {
return {fwd, bwd};}
1220 Box const& box = fab->box();
1223 auto const ncomp = m_info.batch_size;
1225#ifdef AMREX_USE_SYCL
1226 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1230 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1233 bwd.template init_c2c<Direction::backward>(box, pio, ncomp, ndims);
1240namespace fft_detail {
1247 template <
typename F,
typename T>
1249 auto call_post_forward (
F const& f,
int i,
int j,
int k,
Array4<T> const& a,
1250 int ii,
int jj,
int kk,
int)
1251 noexcept ->
decltype(void(f(0,0,0,a(0,0,0))))
1253 for (
int n = 0; n < a.nComp(); ++n) {
1254 f(i,j,k,a(ii,jj,kk,n));
1258 template <
typename F,
typename T>
1260 auto call_post_forward (
F const& f,
int i,
int j,
int k,
Array4<T> const& a,
1261 int ii,
int jj,
int kk,
long)
1262 noexcept ->
decltype(void(f(0,0,0,a.cellData(0,0,0))))
1264 f(i,j,k,a.cellData(ii,jj,kk));
1268template <
typename T, Direction D,
bool C>
1269template <
typename F>
1272 if (m_info.twod_mode) {
1274#if (AMREX_SPACEDIM > 1)
1275 }
else if (m_r2c_sub) {
1277#if (AMREX_SPACEDIM == 2)
1279 m_r2c_sub->post_forward_doit_1
1281 ->
decltype(
void(post_forward(0,0,0,
static_cast<decltype(sp)
>(sp))))
1283 post_forward(0, i, 0,
static_cast<decltype(sp)
>(sp));
1286 if (m_real_domain.length(0) == 1 && m_real_domain.length(1) == 1) {
1288 m_r2c_sub->post_forward_doit_1
1290 ->
decltype(
void(post_forward(0,0,0,
static_cast<decltype(sp)
>(sp))))
1292 post_forward(0, 0, i,
static_cast<decltype(sp)
>(sp));
1294 }
else if (m_real_domain.length(0) == 1 && m_real_domain.length(2) == 1) {
1296 m_r2c_sub->post_forward_doit_1
1298 ->
decltype(
void(post_forward(0,0,0,
static_cast<decltype(sp)
>(sp))))
1300 post_forward(0, i, 0,
static_cast<decltype(sp)
>(sp));
1302 }
else if (m_real_domain.length(0) == 1) {
1304 m_r2c_sub->post_forward_doit_1
1306 ->
decltype(
void(post_forward(0,0,0,
static_cast<decltype(sp)
>(sp))))
1308 post_forward(0, i, j,
static_cast<decltype(sp)
>(sp));
1310 }
else if (m_real_domain.length(1) == 1) {
1312 m_r2c_sub->post_forward_doit_1
1314 ->
decltype(
void(post_forward(0,0,0,
static_cast<decltype(sp)
>(sp))))
1316 post_forward(i, 0, j,
static_cast<decltype(sp)
>(sp));
1319 amrex::Abort(
"R2c::post_forward_doit_0: how did this happen?");
1328template <
typename T, Direction D,
bool C>
1329template <
typename F>
1332 if (m_info.twod_mode) {
1334 }
else if (m_r2c_sub) {
1335 amrex::Abort(
"R2C::post_forward_doit_1: How did this happen?");
1337 if ( ! m_cz.empty()) {
1338 auto* spectral_fab = detail::get_fab(m_cz);
1340 auto const& a = spectral_fab->array();
1344 fft_detail::call_post_forward(post_forward,
1345 jx,ky,iz,a,iz,jx,ky,0);
1348 }
else if ( ! m_cy.empty()) {
1349 auto* spectral_fab = detail::get_fab(m_cy);
1351 auto const& a = spectral_fab->array();
1355 fft_detail::call_post_forward(post_forward,
1356 jx,iy,k,a,iy,jx,k,0);
1360 auto* spectral_fab = detail::get_fab(m_cx);
1362 auto const& a = spectral_fab->array();
1366 fft_detail::call_post_forward(post_forward,
1374template <
typename T, Direction D,
bool C>
1377#if (AMREX_SPACEDIM > 1)
1379 if (m_r2c_sub) {
return m_r2c_sub->scalingFactor(); }
1382#if (AMREX_SPACEDIM == 3)
1384 if (m_info.oned_mode) {
1385 return T(1)/T(
Long(m_real_domain.length(0)));
1386 }
else if (m_info.twod_mode) {
1387 return T(1)/T(
Long(m_real_domain.length(0)) *
1388 Long(m_real_domain.length(1)));
1390#elif (AMREX_SPACEDIM == 2)
1391 if (m_info.oned_mode) {
1392 return T(1)/T(
Long(m_real_domain.length(0)));
1396 return T(1)/T(m_real_domain.numPts());
1400template <
typename T, Direction D,
bool C>
1401template <Direction DIR>
1406#if (AMREX_SPACEDIM > 1)
1408 auto [cmf, order] = m_r2c_sub->getSpectralData();
1409 return std::make_pair(cmf, m_sub_helper.inverse_order(order));
1412 if (!m_cz.empty()) {
1414 }
else if (!m_cy.empty()) {
1421template <
typename T, Direction D,
bool C>
1422template <Direction DIR>
1428 auto const ncomp = m_info.batch_size;
1432 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1433 MF inmf_sub, inmf_tmp;
1436 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1437 incomp_sub = incomp;
1439 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1440 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp,
IntVect(0));
1441 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1445 bool outmf_safe = m_sub_helper.ghost_safe(outmf.
nGrowVect());
1446 cMF outmf_sub, outmf_tmp;
1449 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1450 outcomp_sub = outcomp;
1453 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1457 m_r2c_sub->forward(inmf_sub, outmf_sub, incomp_sub, outcomp_sub);
1466 if (!m_cz.empty()) {
1469 (outmf, m_spectral_domain_x, m_cz,
IntVect(0), dtos);
1470 ParallelCopy(outmf, m_cz, cmd, 0, outcomp, ncomp, dtos);
1471 }
else if (!m_cy.empty()) {
1473 (outmf, m_spectral_domain_x, m_cy,
IntVect(0), m_dtos_y2x);
1474 ParallelCopy(outmf, m_cy, cmd, 0, outcomp, ncomp, m_dtos_y2x);
1481template <
typename T, Direction D,
bool C>
1482template <Direction DIR>
1489template <
typename T, Direction D,
bool C>
1490void R2C<T,D,C>::backward_doit (cMF
const& inmf, MF& outmf,
IntVect const& ngout,
1491 Periodicity const& period,
int incomp,
int outcomp)
1495 auto const ncomp = m_info.batch_size;
1499 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1500 cMF inmf_sub, inmf_tmp;
1503 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1504 incomp_sub = incomp;
1506 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1507 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp,
IntVect(0));
1508 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1512 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1513 MF outmf_sub, outmf_tmp;
1516 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1517 outcomp_sub = outcomp;
1519 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
1520 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), ncomp, ngtmp);
1521 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1525 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1526 Periodicity
const& subperiod = m_sub_helper.make_periodicity(period);
1527 m_r2c_sub->backward_doit(inmf_sub, outmf_sub, subngout, subperiod, incomp_sub, outcomp_sub);
1530 outmf.LocalCopy(outmf_tmp, 0, outcomp, ncomp, outmf_tmp.nGrowVect());
1535 if (!m_cz.empty()) {
1537 MultiBlockCommMetaData cmd
1538 (m_cz, m_spectral_domain_z, inmf,
IntVect(0), dtos);
1540 }
else if (!m_cy.empty()) {
1541 MultiBlockCommMetaData cmd
1542 (m_cy, m_spectral_domain_y, inmf,
IntVect(0), m_dtos_x2y);
1543 ParallelCopy(m_cy, inmf, cmd, incomp, 0, ncomp, m_dtos_x2y);
1545 m_cx.ParallelCopy(inmf, incomp, 0, ncomp);
1547 backward_doit(outmf, ngout, period, outcomp);
1551template <
typename T, Direction D,
bool C>
1552std::pair<BoxArray,DistributionMapping>
1555#if (AMREX_SPACEDIM > 1)
1557 auto const& [ba, dm] = m_r2c_sub->getSpectralDataLayout();
1558 return std::make_pair(m_sub_helper.inverse_boxarray(ba), dm);
1562#if (AMREX_SPACEDIM == 3)
1563 if (!m_cz.empty()) {
1564 BoxList bl = m_cz.boxArray().boxList();
1565 for (
auto& b : bl) {
1566 auto lo = b.smallEnd();
1567 auto hi = b.bigEnd();
1568 std::swap(lo[0], lo[1]);
1569 std::swap(lo[1], lo[2]);
1570 std::swap(hi[0], hi[1]);
1571 std::swap(hi[1], hi[2]);
1575 return std::make_pair(
BoxArray(std::move(bl)), m_cz.DistributionMap());
1578#if (AMREX_SPACEDIM >= 2)
1579 if (!m_cy.empty()) {
1580 BoxList bl = m_cy.boxArray().boxList();
1581 for (
auto& b : bl) {
1582 auto lo = b.smallEnd();
1583 auto hi = b.bigEnd();
1584 std::swap(lo[0], lo[1]);
1585 std::swap(hi[0], hi[1]);
1589 return std::make_pair(
BoxArray(std::move(bl)), m_cy.DistributionMap());
1593 return std::make_pair(m_cx.boxArray(), m_cx.DistributionMap());
1598template <
typename T = Real, FFT::Direction D = FFT::Direction::both>
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:593
#define AMREX_ALWAYS_ASSERT_WITH_MESSAGE(EX, MSG)
Definition AMReX_BLassert.H:49
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
while parser_exe_t p
Definition AMReX_Parser_Exe_Body.H:33
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
Reference-counted collection of Boxes.
Definition AMReX_BoxArray.H:681
void define(const Box &bx)
Initialize the BoxArray from a single box.
Definition AMReX_BoxArray.cpp:352
A list of Boxes sharing a common IndexType.
Definition AMReX_BoxList.H:109
__host__ __device__ Long numPts() const noexcept
Return the number of points contained in the BoxND.
Definition AMReX_Box.H:385
__host__ __device__ IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:167
__host__ __device__ IntVectND< dim > size() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:160
__host__ __device__ BoxND & growLo(int idir, int n_cell=1) noexcept
Grow on the low end by n_cell cells in direction idir (negative shrinks).
Definition AMReX_Box.H:690
__host__ __device__ IndexTypeND< dim > ixType() const noexcept
Return the indexing type.
Definition AMReX_Box.H:148
__host__ __device__ BoxND & growHi(int idir, int n_cell=1) noexcept
Grow on the high end by n_cell cells in direction idir (negative shrinks).
Definition AMReX_Box.H:702
__host__ __device__ const IntVectND< dim > & smallEnd() const &noexcept
Return the inclusive lower bound of the box.
Definition AMReX_Box.H:124
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
Long size() const noexcept
Length of the underlying processor map.
Definition AMReX_DistributionMapping.H:169
void define(const BoxArray &boxes, int nprocs=ParallelDescriptor::NProcs())
Build a mapping from a BoxArray using the current strategy.
Definition AMReX_DistributionMapping.cpp:347
Convolution-based solver for open boundary conditions using Green's functions.
Definition AMReX_FFT_OpenBCSolver.H:26
3D Poisson solver for periodic, Dirichlet & Neumann boundaries in the first two dimensions,...
Definition AMReX_FFT_Poisson.H:164
Poisson solver for periodic, Dirichlet & Neumann boundaries using FFT.
Definition AMReX_FFT_Poisson.H:32
Parallel Discrete Fourier Transform.
Definition AMReX_FFT_R2C.H:48
R2C & operator=(R2C const &)=delete
void forward(MF const &inmf, int incomp=0)
Forward transform.
Definition AMReX_FFT_R2C.H:968
void forward(RT const *in, CT *out)
Forward transform.
Definition AMReX_FFT_R2C.H:1085
friend class Poisson
Definition AMReX_FFT_R2C.H:56
~R2C()
Definition AMReX_FFT_R2C.H:754
std::conditional_t< C, cMF, std::conditional_t< std::is_same_v< T, Real >, MultiFab, FabArray< BaseFab< T > > > > MF
Definition AMReX_FFT_R2C.H:51
void setLocalDomain(std::array< int, 3 > const &local_start, std::array< int, 3 > const &local_size)
Set local domain.
Definition AMReX_FFT_R2C.H:803
R2C(Box const &domain, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:506
void backward(MF &outmf, int outcomp=0)
Backward transform.
Definition AMReX_FFT_R2C.H:1106
void post_forward_doit_1(F const &post_forward)
CUDA-visible helper that redistributes and applies post_forward for the batched layout.
Definition AMReX_FFT_R2C.H:1330
void backward(CT const *in, RT *out)
Backward transform.
Definition AMReX_FFT_R2C.H:1192
T scalingFactor() const
Scaling factor. If the data goes through forward and then backward, the result multiplied by the scal...
Definition AMReX_FFT_R2C.H:1375
std::pair< cMF *, IntVect > getSpectralData() const
void post_forward_doit_0(F const &post_forward)
CUDA-visible hook that walks internal spectral data and applies post_forward.
Definition AMReX_FFT_R2C.H:1270
std::pair< std::array< int, 3 >, std::array< int, 3 > > getLocalDomain() const
Get local domain.
Definition AMReX_FFT_R2C.H:812
friend class PoissonHybrid
Definition AMReX_FFT_R2C.H:57
friend class CrossProj
Definition AMReX_FFT_R2C.H:58
std::pair< BoxArray, DistributionMapping > getSpectralDataLayout() const
Get BoxArray and DistributionMapping for spectral data.
Definition AMReX_FFT_R2C.H:1553
void forwardThenBackward(MF const &inmf, MF &outmf, F const &post_forward, int incomp=0, int outcomp=0)
Definition AMReX_FFT_R2C.H:212
R2C(std::array< int, 3 > const &domain_size, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:749
FabArray< BaseFab< GpuComplex< T > > > cMF
Definition AMReX_FFT_R2C.H:50
std::pair< std::array< int, 3 >, std::array< int, 3 > > getLocalSpectralDomain() const
Get local spectral domain.
Definition AMReX_FFT_R2C.H:849
void setLocalSpectralDomain(std::array< int, 3 > const &local_start, std::array< int, 3 > const &local_size)
Set local spectral domain.
Definition AMReX_FFT_R2C.H:840
friend class OpenBCSolver
Definition AMReX_FFT_R2C.H:55
IntVect nGrowVect() const noexcept
Definition AMReX_FabArrayBase.H:85
const DistributionMapping & DistributionMap() const noexcept
Return constant reference to associated DistributionMapping.
Definition AMReX_FabArrayBase.H:135
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 ParallelCopy(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Definition AMReX_FabArray.H:971
typename std::conditional_t< IsBaseFab< FAB >::value, BaseFab< GpuComplex< T > >, FABType >::value_type value_type
Definition AMReX_FabArray.H:367
void define(const BoxArray &bxs, const DistributionMapping &dm, int nvar, int ngrow, const MFInfo &info=MFInfo(), const FabFactory< FAB > &factory=DefaultFabFactory< FAB >())
Define this FabArray identically to that performed by the constructor having an analogous function si...
Definition AMReX_FabArray.H:2489
void LocalCopy(FabArray< SFAB > const &src, int scomp, int dcomp, int ncomp, IntVect const &nghost)
Perform local copy of FabArray data.
Definition AMReX_FabArray.H:2265
A collection (stored as an array) of FArrayBox objects.
Definition AMReX_MultiFab.H:40
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
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
amrex_long Long
Definition AMReX_INT.H:30
void ParallelForOMP(T n, L const &f) noexcept
Performance-portable kernel launch function with optional OpenMP threading.
Definition AMReX_GpuLaunch.H:328
ArrayND< T, 4, true > Array4
Convenient alias for a 4D ArrayND with three spatial dimensions plus a component dimension.
Definition AMReX_Array4.H:1340
bool is_aligned(const void *p, std::size_t alignment) noexcept
Definition AMReX_Arena.H:46
Arena * The_Arena()
Definition AMReX_Arena.cpp:839
int NProcs() noexcept
Definition AMReX_ParallelDescriptor.H:255
__host__ __device__ constexpr T elemwiseMin(T const &a, T const &b) noexcept
Definition AMReX_Algorithm.H:75
Definition AMReX_FFT_CrossProj.H:8
R2C< T, D, true > C2C
FFT between complex data.
Definition AMReX_FFT_R2C.H:1599
@ backward
Definition AMReX_FFT_Helper.H:55
@ forward
Definition AMReX_FFT_Helper.H:55
@ both
Definition AMReX_FFT_Helper.H:55
@ automatic
Definition AMReX_FFT_Helper.H:57
@ pencil
Definition AMReX_FFT_Helper.H:57
@ slab
Definition AMReX_FFT_Helper.H:57
void dtod_memcpy_async(void *p_d_dst, const void *p_d_src, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:468
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:329
MPI_Comm CommunicatorSub() noexcept
sub-communicator for current frame
Definition AMReX_ParallelContext.H:70
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int local_to_global_rank(int rank) noexcept
translate between local rank and global rank
Definition AMReX_ParallelContext.H:98
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:273
@ C
Definition AMReX_Order.H:7
@ F
Definition AMReX_Order.H:7
void ParallelCopy_finish(FabArray< FAB > &dest, CommHandler handler, const FabArrayBase::CommMetaData &cmd, const DataPacking &data_packing)
Definition AMReX_NonLocalBC.H:821
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
void ParallelCopy(MF &dst, MF const &src, int scomp, int dcomp, int ncomp, IntVect const &ng_src=IntVect(0), IntVect const &ng_dst=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic())
dst = src w/ MPI communication
Definition AMReX_FabArrayUtility.H:2256
BoxArray decompose(Box const &domain, int nboxes, Array< bool, 3 > const &decomp, bool no_overlap)
Decompose domain box into BoxArray.
Definition AMReX_BoxArray.cpp:1961
IndexTypeND< 3 > IndexType
IndexType is an alias for amrex::IndexTypeND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:41
CommHandler ParallelCopy_nowait(NoLocalCopy, FabArray< FAB > &dest, const FabArray< FAB > &src, const FabArrayBase::CommMetaData &cmd, const DataPacking &data_packing)
Definition AMReX_NonLocalBC.H:729
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:244
Definition AMReX_FFT_Helper.H:83
Definition AMReX_FFT_Helper.H:360
std::conditional_t< std::is_same_v< float, T >, cuComplex, cuDoubleComplex > VendorComplex
Definition AMReX_FFT_Helper.H:363
FabArray memory allocation information.
Definition AMReX_FabArray.H:73
MFInfo & SetAlloc(bool a) noexcept
Control whether FAB storage is allocated when the FabArray is defined.
Definition AMReX_FabArray.H:81
This class specializes behaviour on local copies and unpacking receive buffers.
Definition AMReX_NonLocalBC.H:642
Contains information about which components take part of the data transaction.
Definition AMReX_NonLocalBC.H:550
int n_components
Definition AMReX_NonLocalBC.H:553
static MPI_Datatype type()