1#ifndef AMREX_FFT_HELPER_H_
2#define AMREX_FFT_HELPER_H_
3#include <AMReX_Config.H>
24#if defined(AMREX_USE_CUDA)
26# include <cuComplex.h>
27#elif defined(AMREX_USE_HIP)
28# if __has_include(<rocfft/rocfft.h>)
29# include <rocfft/rocfft.h>
33# include <hip/hip_complex.h>
34#elif defined(AMREX_USE_SYCL)
35# if __has_include(<oneapi/mkl/dft.hpp>)
36# include <oneapi/mkl/dft.hpp>
38# define AMREX_USE_MKL_DFTI_2024 1
39# include <oneapi/mkl/dfti.hpp>
47#include <initializer_list>
77[[nodiscard]]
constexpr int
80#if defined(AMREX_USE_CUDA)
114 int nprocs = std::numeric_limits<int>::max();
198 "amrex::FFT::Info::setOpenBCPaddingNumPrimeFactors: nfactors must be between 3 and 6");
209 auto const& dom = geom.
Domain();
219template <
typename MF>
220void shift_mf (IntVect
const& domain_lo, MF
const& mf, MF& new_mf)
222 BoxArray ba = mf.boxArray();
223 ba.shift(-domain_lo);
224 new_mf.define(ba, mf.DistributionMap(), mf.nComp(), mf.nGrowVect(),
225 MFInfo().SetAlloc(
false));
226 for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
228 fab.shift(-domain_lo);
229 new_mf.setFab(mfi, std::move(fab));
233template <
typename MF>
234void shift_mfs (IntVect
const& domain_lo, MF
const& mf1, MF
const& mf2,
235 MF& new_mf1, MF& new_mf2)
238 mf1.DistributionMap() == mf2.DistributionMap());
239 detail::shift_mf(domain_lo, mf1, new_mf1);
240 detail::shift_mf(domain_lo, mf2, new_mf2);
243inline void next_fast_len_doit (Long target, Long n,
int const* factors,
244 int nfactors,
int ifactor, Long& best)
247 best = std::min(best, n);
251 if (ifactor == nfactors) {
254 Long const max_m3 = std::numeric_limits<int>::max() / 3;
255 Long const max_m2 = std::numeric_limits<int>::max() / 2;
256 for (Long m3 = n; m3 < best; ) {
266 if (!overflow && k < best) {
277 int const factor = factors[ifactor];
278 Long const max_len = std::numeric_limits<int>::max();
279 Long const max_m = max_len / factor;
280 for (Long m = n; m < best; ) {
281 next_fast_len_doit(target, m, factors, nfactors, ifactor+1, best);
302[[nodiscard]]
inline int
306 "amrex::FFT::nextFastLen: target must be positive");
308 "amrex::FFT::nextFastLen: nfactors must be between 3 and 6");
310 int constexpr factors[] = {5, 7, 11, 13, 17};
312 Long const max_len = std::numeric_limits<int>::max();
316 detail::next_fast_len_doit(target,
Long(1), factors, nfactors-2, 0, best);
319 "amrex::FFT::nextFastLen: result exceeds int range");
320 return static_cast<int>(best);
325namespace detail {
void hip_execute (rocfft_plan plan,
void **in,
void **out); }
333inline void assert_no_external_stream ()
337 "SYCL FFT does not support external GPU streams.");
340template <
typename T, Direction direction,
typename P,
typename TI,
typename TO>
341void sycl_execute (P* plan, TI* in, TO* out)
343 assert_no_external_stream();
344#ifndef AMREX_USE_MKL_DFTI_2024
345 std::int64_t workspaceSize = 0;
347 std::size_t workspaceSize = 0;
349 plan->get_value(oneapi::mkl::dft::config_param::WORKSPACE_BYTES,
352 plan->set_workspace(buffer);
354 if (std::is_same_v<TI,TO>) {
356 if constexpr (direction == Direction::forward) {
357 r = oneapi::mkl::dft::compute_forward(*plan, out);
359 r = oneapi::mkl::dft::compute_backward(*plan, out);
362 if constexpr (direction == Direction::forward) {
363 r = oneapi::mkl::dft::compute_forward(*plan, in, out);
365 r = oneapi::mkl::dft::compute_backward(*plan, in, out);
378#if defined(AMREX_USE_CUDA)
381 cuComplex, cuDoubleComplex>;
382#elif defined(AMREX_USE_HIP)
384 using VendorComplex = std::conditional_t<std::is_same_v<float,T>,
386#elif defined(AMREX_USE_SYCL)
387 using mkl_desc_r = oneapi::mkl::dft::descriptor<std::is_same_v<float,T>
388 ? oneapi::mkl::dft::precision::SINGLE
389 : oneapi::mkl::dft::precision::DOUBLE,
390 oneapi::mkl::dft::domain::REAL>;
391 using mkl_desc_c = oneapi::mkl::dft::descriptor<std::is_same_v<float,T>
392 ? oneapi::mkl::dft::precision::SINGLE
393 : oneapi::mkl::dft::precision::DOUBLE,
394 oneapi::mkl::dft::domain::COMPLEX>;
395 using VendorPlan = std::variant<mkl_desc_r*,mkl_desc_c*>;
398 using VendorPlan = std::conditional_t<std::is_same_v<float,T>,
399 fftwf_plan, fftw_plan>;
400 using VendorComplex = std::conditional_t<std::is_same_v<float,T>,
401 fftwf_complex, fftw_complex>;
437#if !defined(AMREX_USE_GPU)
454 template <Direction D>
459 int rank = is_2d_transform ? 2 : 1;
474 int nr = (rank == 1) ? len[0] : len[0]*len[1];
476 int nc = (rank == 1) ? (len[0]/2+1) : (len[1]/2+1)*len[0];
477#if (AMREX_SPACEDIM == 1)
487#if defined(AMREX_USE_CUDA)
491 std::size_t work_size;
493 cufftType fwd_type = std::is_same_v<float,T> ? CUFFT_R2C : CUFFT_D2Z;
495 (cufftMakePlanMany(
plan, rank, len,
nullptr, 1, nr,
nullptr, 1, nc, fwd_type,
howmany, &work_size));
497 cufftType bwd_type = std::is_same_v<float,T> ? CUFFT_C2R : CUFFT_Z2D;
499 (cufftMakePlanMany(
plan, rank, len,
nullptr, 1, nc,
nullptr, 1, nr, bwd_type,
howmany, &work_size));
502#elif defined(AMREX_USE_HIP)
504 auto prec = std::is_same_v<float,T> ? rocfft_precision_single : rocfft_precision_double;
506 std::size_t
length[2] = {std::size_t(len[1]), std::size_t(len[0])};
508 AMREX_ROCFFT_SAFE_CALL
509 (rocfft_plan_create(&
plan, rocfft_placement_notinplace,
510 rocfft_transform_type_real_forward, prec, rank,
513 AMREX_ROCFFT_SAFE_CALL
514 (rocfft_plan_create(&
plan, rocfft_placement_notinplace,
515 rocfft_transform_type_real_inverse, prec, rank,
519#elif defined(AMREX_USE_SYCL)
523 pp =
new mkl_desc_r(len[0]);
525 pp =
new mkl_desc_r({std::int64_t(len[0]), std::int64_t(len[1])});
527#ifndef AMREX_USE_MKL_DFTI_2024
528 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT,
529 oneapi::mkl::dft::config_value::NOT_INPLACE);
531 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT, DFTI_NOT_INPLACE);
533 pp->set_value(oneapi::mkl::dft::config_param::NUMBER_OF_TRANSFORMS,
howmany);
534 pp->set_value(oneapi::mkl::dft::config_param::FWD_DISTANCE, nr);
535 pp->set_value(oneapi::mkl::dft::config_param::BWD_DISTANCE, nc);
536 std::vector<std::int64_t> strides;
537 strides.push_back(0);
538 if (rank == 2) { strides.push_back(len[1]); }
539 strides.push_back(1);
540#ifndef AMREX_USE_MKL_DFTI_2024
541 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides);
544 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides.data());
547 pp->set_value(oneapi::mkl::dft::config_param::WORKSPACE,
548 oneapi::mkl::dft::config_value::WORKSPACE_EXTERNAL);
549 detail::assert_no_external_stream();
550 pp->commit(amrex::Gpu::Device::streamQueue());
555 if constexpr (std::is_same_v<float,T>) {
557 plan = fftwf_plan_many_dft_r2c
558 (rank, len,
howmany, pr,
nullptr, 1, nr, pc,
nullptr, 1, nc,
559 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
561 plan = fftwf_plan_many_dft_c2r
562 (rank, len,
howmany, pc,
nullptr, 1, nc, pr,
nullptr, 1, nr,
563 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
567 plan = fftw_plan_many_dft_r2c
568 (rank, len,
howmany, pr,
nullptr, 1, nr, pc,
nullptr, 1, nc,
569 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
571 plan = fftw_plan_many_dft_c2r
572 (rank, len,
howmany, pc,
nullptr, 1, nc, pr,
nullptr, 1, nr,
573 FFTW_ESTIMATE | FFTW_DESTROY_INPUT);
588 template <Direction D,
int M>
606 template <Direction D>
624#if (AMREX_SPACEDIM >= 2)
625 else if (ndims == 2) {
627#if (AMREX_SPACEDIM == 2)
635#if (AMREX_SPACEDIM == 3)
636 else if (ndims == 3) {
646#if defined(AMREX_USE_CUDA)
650 cufftType t = std::is_same_v<float,T> ? CUFFT_C2C : CUFFT_Z2Z;
651 std::size_t work_size;
653 (cufftMakePlanMany(
plan, ndims, len,
nullptr, 1,
n,
nullptr, 1,
n, t,
howmany, &work_size));
655#elif defined(AMREX_USE_HIP)
657 auto prec = std::is_same_v<float,T> ? rocfft_precision_single
658 : rocfft_precision_double;
660 : rocfft_transform_type_complex_inverse;
664 }
else if (ndims == 2) {
672 AMREX_ROCFFT_SAFE_CALL
673 (rocfft_plan_create(&
plan, rocfft_placement_inplace, dir, prec, ndims,
676#elif defined(AMREX_USE_SYCL)
680 pp =
new mkl_desc_c(
n);
681 }
else if (ndims == 2) {
682 pp =
new mkl_desc_c({std::int64_t(len[0]), std::int64_t(len[1])});
684 pp =
new mkl_desc_c({std::int64_t(len[0]), std::int64_t(len[1]), std::int64_t(len[2])});
686#ifndef AMREX_USE_MKL_DFTI_2024
687 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT,
688 oneapi::mkl::dft::config_value::INPLACE);
690 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT, DFTI_INPLACE);
692 pp->set_value(oneapi::mkl::dft::config_param::NUMBER_OF_TRANSFORMS,
howmany);
693 pp->set_value(oneapi::mkl::dft::config_param::FWD_DISTANCE,
n);
694 pp->set_value(oneapi::mkl::dft::config_param::BWD_DISTANCE,
n);
695 std::vector<std::int64_t> strides(ndims+1);
698 for (
int i = ndims-1; i >= 1; --i) {
699 strides[i] = strides[i+1] * len[i];
701#ifndef AMREX_USE_MKL_DFTI_2024
702 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides);
703 pp->set_value(oneapi::mkl::dft::config_param::BWD_STRIDES, strides);
705 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides.data());
706 pp->set_value(oneapi::mkl::dft::config_param::BWD_STRIDES, strides.data());
708 pp->set_value(oneapi::mkl::dft::config_param::WORKSPACE,
709 oneapi::mkl::dft::config_value::WORKSPACE_EXTERNAL);
710 detail::assert_no_external_stream();
711 pp->commit(amrex::Gpu::Device::streamQueue());
716 if constexpr (std::is_same_v<float,T>) {
718 plan = fftwf_plan_many_dft
719 (ndims, len,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, -1,
722 plan = fftwf_plan_many_dft
723 (ndims, len,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, +1,
728 plan = fftw_plan_many_dft
729 (ndims, len,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, -1,
732 plan = fftw_plan_many_dft
733 (ndims, len,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, +1,
741 template <Direction D>
742 fftw_r2r_kind get_fftw_kind (std::pair<Boundary,Boundary>
const& bc)
762 return fftw_r2r_kind{};
774 template <Direction D>
808 template <Direction D>
809 void init_r2r (
Box const& box, T*
p, std::pair<Boundary,Boundary>
const& bc,
810 int howmany_initval = 1)
822#if defined(AMREX_USE_GPU)
842 int nc = (nex/2) + 1;
844#if defined (AMREX_USE_CUDA)
848 cufftType fwd_type = std::is_same_v<float,T> ? CUFFT_R2C : CUFFT_D2Z;
849 std::size_t work_size;
851 (cufftMakePlanMany(
plan, 1, &nex,
nullptr, 1, nc*2,
nullptr, 1, nc, fwd_type,
howmany, &work_size));
853#elif defined(AMREX_USE_HIP)
856 auto prec = std::is_same_v<float,T> ? rocfft_precision_single : rocfft_precision_double;
857 const std::size_t
length = nex;
858 AMREX_ROCFFT_SAFE_CALL
859 (rocfft_plan_create(&
plan, rocfft_placement_inplace,
860 rocfft_transform_type_real_forward, prec, 1,
863#elif defined(AMREX_USE_SYCL)
865 auto* pp =
new mkl_desc_r(nex);
866#ifndef AMREX_USE_MKL_DFTI_2024
867 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT,
868 oneapi::mkl::dft::config_value::INPLACE);
870 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT, DFTI_INPLACE);
872 pp->set_value(oneapi::mkl::dft::config_param::NUMBER_OF_TRANSFORMS,
howmany);
873 pp->set_value(oneapi::mkl::dft::config_param::FWD_DISTANCE, nc*2);
874 pp->set_value(oneapi::mkl::dft::config_param::BWD_DISTANCE, nc);
875 std::vector<std::int64_t> strides = {0,1};
876#ifndef AMREX_USE_MKL_DFTI_2024
877 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides);
878 pp->set_value(oneapi::mkl::dft::config_param::BWD_STRIDES, strides);
880 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides.data());
881 pp->set_value(oneapi::mkl::dft::config_param::BWD_STRIDES, strides.data());
883 pp->set_value(oneapi::mkl::dft::config_param::WORKSPACE,
884 oneapi::mkl::dft::config_value::WORKSPACE_EXTERNAL);
885 detail::assert_no_external_stream();
886 pp->commit(amrex::Gpu::Device::streamQueue());
892 auto fftw_kind = get_fftw_kind<D>(bc);
893 if constexpr (std::is_same_v<float,T>) {
894 plan = fftwf_plan_many_r2r
895 (1, &
n,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, &fftw_kind,
898 plan = fftw_plan_many_r2r
899 (1, &
n,
howmany,
p,
nullptr, 1,
n,
p,
nullptr, 1,
n, &fftw_kind,
912 template <Direction D>
914 std::pair<Boundary,Boundary>
const& bc)
920#if defined(AMREX_USE_GPU)
936 auto fftw_kind = get_fftw_kind<D>(bc);
937 if constexpr (std::is_same_v<float,T>) {
938 plan = fftwf_plan_many_r2r
939 (1, &
n,
howmany,
p,
nullptr, 2,
n*2,
p,
nullptr, 2,
n*2, &fftw_kind,
941 plan2 = fftwf_plan_many_r2r
942 (1, &
n,
howmany,
p+1,
nullptr, 2,
n*2,
p+1,
nullptr, 2,
n*2, &fftw_kind,
945 plan = fftw_plan_many_r2r
946 (1, &
n,
howmany,
p,
nullptr, 2,
n*2,
p,
nullptr, 2,
n*2, &fftw_kind,
948 plan2 = fftw_plan_many_r2r
949 (1, &
n,
howmany,
p+1,
nullptr, 2,
n*2,
p+1,
nullptr, 2,
n*2, &fftw_kind,
960 template <Direction D>
971#if defined(AMREX_USE_CUDA)
974 std::size_t work_size = 0;
981 if constexpr (std::is_same_v<float,T>) {
987 if constexpr (std::is_same_v<float,T>) {
995#elif defined(AMREX_USE_HIP)
996 detail::hip_execute(
plan, (
void**)&pi, (
void**)&po);
997#elif defined(AMREX_USE_SYCL)
998 detail::sycl_execute<T,D>(std::get<0>(
plan), pi, po);
1001 if constexpr (std::is_same_v<float,T>) {
1002 fftwf_execute(
plan);
1012 template <Direction D>
1020#if defined(AMREX_USE_CUDA)
1023 std::size_t work_size = 0;
1030 if constexpr (std::is_same_v<float,T>) {
1037#elif defined(AMREX_USE_HIP)
1038 detail::hip_execute(
plan, (
void**)&
p, (
void**)&
p);
1039#elif defined(AMREX_USE_SYCL)
1040 detail::sycl_execute<T,D>(std::get<1>(
plan),
p,
p);
1043 if constexpr (std::is_same_v<float,T>) {
1044 fftwf_execute(
plan);
1066 amrex::Abort(
"FFT: alloc_scratch_space: unsupported kind");
1084 auto* pdst = (T*) pbuf;
1087 int ostride = (
n+1)*2;
1095 auto batch = ielem /
Long(nex);
1096 auto i =
int(ielem - batch*nex);
1097 for (
int ir = 0; ir < 2; ++ir) {
1098 auto* po = pdst + (2*batch+ir)*ostride + i;
1099 auto const* pi = psrc + 2*batch*istride + ir;
1103 *po = sign * pi[(2*norig-1-i)*2];
1110 auto batch = ielem /
Long(nex);
1111 auto i =
int(ielem - batch*nex);
1112 auto* po = pdst + batch*ostride + i;
1113 auto const* pi = psrc + batch*istride;
1117 *po = sign * pi[2*norig-1-i];
1122 int ostride = (2*
n+1)*2;
1130 auto batch = ielem /
Long(nex);
1131 auto i =
int(ielem - batch*nex);
1132 for (
int ir = 0; ir < 2; ++ir) {
1133 auto* po = pdst + (2*batch+ir)*ostride + i;
1134 auto const* pi = psrc + 2*batch*istride + ir;
1137 }
else if (i < (2*norig-1)) {
1138 *po = pi[(2*norig-2-i)*2];
1139 }
else if (i == (2*norig-1)) {
1141 }
else if (i < (3*norig)) {
1142 *po = -pi[(i-2*norig)*2];
1143 }
else if (i < (4*norig-1)) {
1144 *po = -pi[(4*norig-2-i)*2];
1153 auto batch = ielem /
Long(nex);
1154 auto i =
int(ielem - batch*nex);
1155 auto* po = pdst + batch*ostride + i;
1156 auto const* pi = psrc + batch*istride;
1159 }
else if (i < (2*norig-1)) {
1160 *po = pi[2*norig-2-i];
1161 }
else if (i == (2*norig-1)) {
1163 }
else if (i < (3*norig)) {
1164 *po = -pi[i-2*norig];
1165 }
else if (i < (4*norig-1)) {
1166 *po = -pi[4*norig-2-i];
1173 int ostride = (2*
n+1)*2;
1181 auto batch = ielem /
Long(nex);
1182 auto i =
int(ielem - batch*nex);
1183 for (
int ir = 0; ir < 2; ++ir) {
1184 auto* po = pdst + (2*batch+ir)*ostride + i;
1185 auto const* pi = psrc + 2*batch*istride + ir;
1188 }
else if (i == norig) {
1190 }
else if (i < (2*norig+1)) {
1191 *po = -pi[(2*norig-i)*2];
1192 }
else if (i < (3*norig)) {
1193 *po = -pi[(i-2*norig)*2];
1194 }
else if (i == 3*norig) {
1197 *po = pi[(4*norig-i)*2];
1204 auto batch = ielem /
Long(nex);
1205 auto i =
int(ielem - batch*nex);
1206 auto* po = pdst + batch*ostride + i;
1207 auto const* pi = psrc + batch*istride;
1210 }
else if (i == norig) {
1212 }
else if (i < (2*norig+1)) {
1213 *po = -pi[2*norig-i];
1214 }
else if (i < (3*norig)) {
1215 *po = -pi[i-2*norig];
1216 }
else if (i == 3*norig) {
1219 *po = pi[4*norig-i];
1224 int ostride = (2*
n+1)*2;
1232 auto batch = ielem /
Long(nex);
1233 auto i =
int(ielem - batch*nex);
1234 for (
int ir = 0; ir < 2; ++ir) {
1235 auto* po = pdst + (2*batch+ir)*ostride + i;
1236 auto const* pi = psrc + 2*batch*istride + ir;
1239 }
else if (i < (2*norig)) {
1240 *po = -pi[(2*norig-1-i)*2];
1241 }
else if (i < (3*norig)) {
1242 *po = -pi[(i-2*norig)*2];
1244 *po = pi[(4*norig-1-i)*2];
1251 auto batch = ielem /
Long(nex);
1252 auto i =
int(ielem - batch*nex);
1253 auto* po = pdst + batch*ostride + i;
1254 auto const* pi = psrc + batch*istride;
1257 }
else if (i < (2*norig)) {
1258 *po = -pi[2*norig-1-i];
1259 }
else if (i < (3*norig)) {
1260 *po = -pi[i-2*norig];
1262 *po = pi[4*norig-1-i];
1267 int ostride = (2*
n+1)*2;
1275 auto batch = ielem /
Long(nex);
1276 auto i =
int(ielem - batch*nex);
1277 for (
int ir = 0; ir < 2; ++ir) {
1278 auto* po = pdst + (2*batch+ir)*ostride + i;
1279 auto const* pi = psrc + 2*batch*istride + ir;
1282 }
else if (i < (2*norig)) {
1283 *po = pi[(2*norig-1-i)*2];
1284 }
else if (i < (3*norig)) {
1285 *po = -pi[(i-2*norig)*2];
1287 *po = -pi[(4*norig-1-i)*2];
1294 auto batch = ielem /
Long(nex);
1295 auto i =
int(ielem - batch*nex);
1296 auto* po = pdst + batch*ostride + i;
1297 auto const* pi = psrc + batch*istride;
1300 }
else if (i < (2*norig)) {
1301 *po = pi[2*norig-1-i];
1302 }
else if (i < (3*norig)) {
1303 *po = -pi[i-2*norig];
1305 *po = -pi[4*norig-1-i];
1310 amrex::Abort(
"FFT: pack_r2r_buffer: unsupported kind");
1332 auto batch = ielem /
Long(norig);
1333 auto k =
int(ielem - batch*norig);
1335 for (
int ir = 0; ir < 2; ++ir) {
1336 auto const& yk = psrc[(2*batch+ir)*istride+k+1];
1337 pdst[2*batch*ostride+ir+k*2] = s * yk.real() - c * yk.imag();
1343 auto batch = ielem /
Long(norig);
1344 auto k =
int(ielem - batch*norig);
1346 auto const& yk = psrc[batch*istride+k+1];
1347 pdst[batch*ostride+k] = s * yk.real() - c * yk.imag();
1351 int istride = 2*
n+1;
1355 auto batch = ielem /
Long(norig);
1356 auto k =
int(ielem - batch*norig);
1358 for (
int ir = 0; ir < 2; ++ir) {
1359 auto const& yk = psrc[(2*batch+ir)*istride+2*k+1];
1360 pdst[2*batch*ostride+ir+k*2] = T(0.5)*(s * yk.real() - c * yk.imag());
1366 auto batch = ielem /
Long(norig);
1367 auto k =
int(ielem - batch*norig);
1369 auto const& yk = psrc[batch*istride+2*k+1];
1370 pdst[batch*ostride+k] = T(0.5)*(s * yk.real() - c * yk.imag());
1378 auto batch = ielem /
Long(norig);
1379 auto k =
int(ielem - batch*norig);
1381 for (
int ir = 0; ir < 2; ++ir) {
1382 auto const& yk = psrc[(2*batch+ir)*istride+k];
1383 pdst[2*batch*ostride+ir+k*2] = c * yk.real() + s * yk.imag();
1389 auto batch = ielem /
Long(norig);
1390 auto k =
int(ielem - batch*norig);
1392 auto const& yk = psrc[batch*istride+k];
1393 pdst[batch*ostride+k] = c * yk.real() + s * yk.imag();
1397 int istride = 2*
n+1;
1401 auto batch = ielem /
Long(norig);
1402 auto k =
int(ielem - batch*norig);
1403 for (
int ir = 0; ir < 2; ++ir) {
1404 auto const& yk = psrc[(2*batch+ir)*istride+2*k+1];
1405 pdst[2*batch*ostride+ir+k*2] = T(0.5) * yk.real();
1411 auto batch = ielem /
Long(norig);
1412 auto k =
int(ielem - batch*norig);
1413 auto const& yk = psrc[batch*istride+2*k+1];
1414 pdst[batch*ostride+k] = T(0.5) * yk.real();
1418 int istride = 2*
n+1;
1422 auto batch = ielem /
Long(norig);
1423 auto k =
int(ielem - batch*norig);
1425 for (
int ir = 0; ir < 2; ++ir) {
1426 auto const& yk = psrc[(2*batch+ir)*istride+2*k+1];
1427 pdst[2*batch*ostride+ir+k*2] = T(0.5) * (c * yk.real() + s * yk.imag());
1433 auto batch = ielem /
Long(norig);
1434 auto k =
int(ielem - batch*norig);
1436 auto const& yk = psrc[batch*istride+2*k+1];
1437 pdst[batch*ostride+k] = T(0.5) * (c * yk.real() + s * yk.imag());
1441 int istride = 2*
n+1;
1445 auto batch = ielem /
Long(norig);
1446 auto k =
int(ielem - batch*norig);
1448 for (
int ir = 0; ir < 2; ++ir) {
1449 auto const& yk = psrc[(2*batch+ir)*istride+2*k+1];
1450 pdst[2*batch*ostride+ir+k*2] = T(0.5) * (s * yk.real() - c * yk.imag());
1456 auto batch = ielem /
Long(norig);
1457 auto k =
int(ielem - batch*norig);
1459 auto const& yk = psrc[batch*istride+2*k+1];
1460 pdst[batch*ostride+k] = T(0.5) * (s * yk.real() - c * yk.imag());
1464 amrex::Abort(
"FFT: unpack_r2r_buffer: unsupported kind");
1472 template <Direction D>
1478#if defined(AMREX_USE_GPU)
1484#if defined(AMREX_USE_CUDA)
1488 std::size_t work_size = 0;
1494 if constexpr (std::is_same_v<float,T>) {
1500#elif defined(AMREX_USE_HIP)
1501 detail::hip_execute(
plan, (
void**)&pscratch, (
void**)&pscratch);
1502#elif defined(AMREX_USE_SYCL)
1503 detail::sycl_execute<T,Direction::forward>(std::get<0>(
plan), (T*)pscratch, (
VendorComplex*)pscratch);
1510#if defined(AMREX_USE_CUDA)
1516 if constexpr (std::is_same_v<float,T>) {
1517 fftwf_execute(
plan);
1532#if defined(AMREX_USE_CUDA)
1534#elif defined(AMREX_USE_HIP)
1535 AMREX_ROCFFT_SAFE_CALL(rocfft_plan_destroy(
plan));
1536#elif defined(AMREX_USE_SYCL)
1537 std::visit([](
auto&&
p) {
delete p; },
plan);
1539 if constexpr (std::is_same_v<float,T>) {
1540 fftwf_destroy_plan(
plan);
1542 fftw_destroy_plan(
plan);
1555 PlanD* get_vendor_plan_d (Key
const& key);
1556 PlanF* get_vendor_plan_f (Key
const& key);
1558 void add_vendor_plan_d (Key
const& key, PlanD plan);
1559 void add_vendor_plan_f (Key
const& key, PlanF plan);
1563template <
typename T>
1564template <Direction D,
int M>
1575 for (
auto s : fft_size) {
n *= s; }
1578#if defined(AMREX_USE_GPU)
1579 Key key = {fft_size.template expand<3>(), ncomp, D,
kind};
1582 if constexpr (std::is_same_v<float,T>) {
1583 cached_plan = detail::get_vendor_plan_f(key);
1585 cached_plan = detail::get_vendor_plan_d(key);
1588 plan = *cached_plan;
1597 for (
int i = 0; i < M; ++i) {
1598 len[i] = fft_size[M-1-i];
1601 int nc = fft_size[0]/2+1;
1602 for (
int i = 1; i < M; ++i) {
1606#if defined(AMREX_USE_CUDA)
1613 type = std::is_same_v<float,T> ? CUFFT_R2C : CUFFT_D2Z;
1617 type = std::is_same_v<float,T> ? CUFFT_C2R : CUFFT_Z2D;
1621 std::size_t work_size;
1623 (cufftMakePlanMany(
plan, M, len,
nullptr, 1, n_in,
nullptr, 1, n_out, type,
howmany, &work_size));
1625#elif defined(AMREX_USE_HIP)
1627 auto prec = std::is_same_v<float,T> ? rocfft_precision_single : rocfft_precision_double;
1629 for (
int idim = 0; idim < M; ++idim) {
length[idim] = fft_size[idim]; }
1631 AMREX_ROCFFT_SAFE_CALL
1632 (rocfft_plan_create(&
plan, rocfft_placement_notinplace,
1633 rocfft_transform_type_real_forward, prec, M,
1636 AMREX_ROCFFT_SAFE_CALL
1637 (rocfft_plan_create(&
plan, rocfft_placement_notinplace,
1638 rocfft_transform_type_real_inverse, prec, M,
1642#elif defined(AMREX_USE_SYCL)
1646 pp =
new mkl_desc_r(fft_size[0]);
1648 std::vector<std::int64_t> len64(M);
1649 for (
int idim = 0; idim < M; ++idim) {
1650 len64[idim] = len[idim];
1652 pp =
new mkl_desc_r(len64);
1654#ifndef AMREX_USE_MKL_DFTI_2024
1655 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT,
1656 oneapi::mkl::dft::config_value::NOT_INPLACE);
1658 pp->set_value(oneapi::mkl::dft::config_param::PLACEMENT, DFTI_NOT_INPLACE);
1660 pp->set_value(oneapi::mkl::dft::config_param::NUMBER_OF_TRANSFORMS,
howmany);
1661 pp->set_value(oneapi::mkl::dft::config_param::FWD_DISTANCE,
n);
1662 pp->set_value(oneapi::mkl::dft::config_param::BWD_DISTANCE, nc);
1663 std::vector<std::int64_t> strides(M+1);
1666 for (
int i = M-1; i >= 1; --i) {
1667 strides[i] = strides[i+1] * fft_size[M-1-i];
1670#ifndef AMREX_USE_MKL_DFTI_2024
1671 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides);
1674 pp->set_value(oneapi::mkl::dft::config_param::FWD_STRIDES, strides.data());
1677 pp->set_value(oneapi::mkl::dft::config_param::WORKSPACE,
1678 oneapi::mkl::dft::config_value::WORKSPACE_EXTERNAL);
1679 detail::assert_no_external_stream();
1680 pp->commit(amrex::Gpu::Device::streamQueue());
1685 if (
pf ==
nullptr ||
pb ==
nullptr) {
1690 if constexpr (std::is_same_v<float,T>) {
1692 plan = fftwf_plan_many_dft_r2c
1693 (M, len,
howmany, (
float*)
pf,
nullptr, 1,
n, (fftwf_complex*)
pb,
nullptr, 1, nc,
1696 plan = fftwf_plan_many_dft_c2r
1697 (M, len,
howmany, (fftwf_complex*)
pb,
nullptr, 1, nc, (
float*)
pf,
nullptr, 1,
n,
1702 plan = fftw_plan_many_dft_r2c
1703 (M, len,
howmany, (
double*)
pf,
nullptr, 1,
n, (fftw_complex*)
pb,
nullptr, 1, nc,
1706 plan = fftw_plan_many_dft_c2r
1707 (M, len,
howmany, (fftw_complex*)
pb,
nullptr, 1, nc, (
double*)
pf,
nullptr, 1,
n,
1713#if defined(AMREX_USE_GPU)
1715 if constexpr (std::is_same_v<float,T>) {
1716 detail::add_vendor_plan_f(key,
plan);
1718 detail::add_vendor_plan_d(key,
plan);
1738 std::size_t max_block_bytes,
bool dense);
1740 struct TransposeMetaData;
1744 inline std::size_t max_block_bytes
1745 (std::initializer_list<std::unique_ptr<TransposeMetaData>
const*> mds);
1748 inline bool transposes_dense
1749 (std::initializer_list<std::unique_ptr<TransposeMetaData>
const*> mds);
1751 template <
typename FA>
1752 Long max_fab_bytes (FA
const& fa)
1754 using T =
typename FA::FABType::value_type::value_type;
1757 auto const& ba = fa.boxArray();
1758 for (
int i = 0, nb =
int(ba.size()); i < nb; ++i) {
1759 n = std::max(n, ba[i].numPts());
1762 return n * fa.nComp() * Long(
sizeof(T));
1768 struct TransposePattern
1770 std::size_t block_bytes = 0;
1777 struct TransposeMetaData
1779 template <
typename... Args>
1780 explicit TransposeMetaData (TransposePattern pattern_, Args&&... args)
1781 : cmd(std::
forward<Args>(args)...), pattern(pattern_) {}
1783 MultiBlockCommMetaData cmd;
1784 NonLocalBC::CommHandler handler;
1785 TransposePattern pattern;
1790 int count_active_procs (std::initializer_list<FabArrayBase const*> fas);
1796 MPI_Comm make_active_comm (
int n_active,
bool& owned);
1799 void free_active_comm (MPI_Comm comm,
bool owned);
1802 inline Vector<std::pair<int,int>> box_intervals (Vector<Box>
const& boxes,
int dir)
1804 Vector<std::pair<int,int>> iv;
1805 iv.reserve(boxes.size());
1806 for (
auto const& b : boxes) {
1807 iv.emplace_back(b.smallEnd(dir), b.bigEnd(dir));
1809 std::sort(iv.begin(), iv.end());
1810 iv.erase(std::unique(iv.begin(), iv.end()), iv.end());
1822 template <
typename FA,
typename DTOS>
1823 TransposePattern transpose_pattern (FA
const& dst, Box
const& dstbox, FA
const& src,
1824 DTOS
const& dtos,
int n_active)
1826 using T =
typename FA::FABType::value_type::value_type;
1827 auto const& dstba = dst.boxArray();
1828 auto const& srcba = src.boxArray();
1834 for (
int i = 0, n =
int(dstba.size()); i < n; ++i) {
1835 Box const b = dstba[i] & dstbox;
1837 dboxes.push_back(NonLocalBC::Image(dtos, b).setType(srcba.ixType()));
1838 dindex.push_back(i);
1842 for (
int k = 0, n =
int(srcba.size()); k < n; ++k) {
1843 sboxes.push_back(srcba[k]);
1851 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
1852 auto const div = box_intervals(dboxes, idim);
1853 auto const siv = box_intervals(sboxes, idim);
1857 for (
auto const& a : div) {
1858 while (j0 < siv.size() && siv[j0].second < a.first) { ++j0; }
1859 for (
auto j = j0; j < siv.size() && siv[j].first <= a.second; ++j) {
1861 maxlen = std::max(maxlen, std::min(a.second, siv[j].second)
1862 - std::max(a.first, siv[j].first) + 1);
1871 for (Long i = 0; i < dboxes.size(); ++i) {
1872 int const j = dindex[i];
1873 if (j < sboxes.size() && dboxes[i].intersects(sboxes[j])) { --npairs; }
1875 if (npairs <= 0) { npairs = 0; maxpts = 0; }
1878 p.block_bytes =
amrex::aligned_size(
alignof(T), std::size_t(maxpts) * dst.nComp() *
sizeof(T));
1881 p.dense = (2*npairs >=
Long(n_active) *
Long(n_active));
1885 inline std::size_t max_block_bytes
1886 (std::initializer_list<std::unique_ptr<TransposeMetaData>
const*> mds)
1889 for (
auto const* md : mds) {
1890 if (*md) { n = std::max(n, (*md)->pattern.block_bytes); }
1895 inline bool transposes_dense
1896 (std::initializer_list<std::unique_ptr<TransposeMetaData>
const*> mds)
1899 for (
auto const* md : mds) {
1900 if (*md) { dense = dense && (*md)->pattern.dense; }
1905 template <
typename FA,
typename DTOS>
1906 std::unique_ptr<TransposeMetaData>
1907 make_transpose (
int n_active, FA& dst, Box
const& dstbox, FA
const& src,
1908 IntVect
const& ngrow, DTOS
const& dtos)
1910 return std::make_unique<TransposeMetaData>
1911 (transpose_pattern(dst, dstbox, src, dtos, n_active), dst, dstbox, src, ngrow, dtos);
1916 template <
typename FA,
typename DTOS>
1917 void transpose (FA& dst, FA
const& src, TransposeMetaData& md,
int ncomp,
1918 DTOS
const& dtos, CommStrategy strategy, MPI_Comm comm)
1921 if (strategy == CommStrategy::pointtopoint) {
1922 NonLocalBC::ParallelCopy(dst, src, md.cmd, 0, 0, ncomp, dtos);
1923 }
else if (comm == MPI_COMM_NULL) {
1925 }
else if (strategy == CommStrategy::alltoall && md.pattern.dense) {
1928 NonLocalBC::ParallelCopy_alltoall(dst, src, md.cmd, 0, 0, ncomp, dtos,
1929 NonLocalBC::Identity{}, md.pattern.block_bytes,
1932 NonLocalBC::ParallelCopy_alltoallv(dst, src, md.cmd, 0, 0, ncomp, dtos,
1933 NonLocalBC::Identity{}, &md.handler, comm);
1937 template <
typename FA>
1938 typename FA::FABType::value_type * get_fab (FA& fa)
1940 auto myproc = ParallelContext::MyProcSub();
1941 if (myproc < fa.size()) {
1942 return fa.fabPtr(myproc);
1948 template <
typename FA1,
typename FA2>
1949 std::unique_ptr<char,DataDeleter> make_mfs_share (FA1& fa1, FA2& fa2)
1951 bool not_same_fa =
true;
1952 if constexpr (std::is_same_v<FA1,FA2>) {
1953 not_same_fa = (&fa1 != &fa2);
1955 using FAB1 =
typename FA1::FABType::value_type;
1956 using FAB2 =
typename FA2::FABType::value_type;
1957 using T1 =
typename FAB1::value_type;
1958 using T2 =
typename FAB2::value_type;
1959 auto myproc = ParallelContext::MyProcSub();
1960 bool alloc_1 = (myproc < fa1.size());
1961 bool alloc_2 = (myproc < fa2.size()) && not_same_fa;
1963 if (alloc_1 && alloc_2) {
1964 Box const& box1 = fa1.fabbox(myproc);
1965 Box const& box2 = fa2.fabbox(myproc);
1966 int ncomp1 = fa1.nComp();
1967 int ncomp2 = fa2.nComp();
1969 sizeof(T2)*box2.numPts()*ncomp2));
1970 fa1.setFab(myproc, FAB1(box1, ncomp1, (T1*)
p));
1971 fa2.setFab(myproc, FAB2(box2, ncomp2, (T2*)
p));
1972 }
else if (alloc_1) {
1973 Box const& box1 = fa1.fabbox(myproc);
1974 int ncomp1 = fa1.nComp();
1976 fa1.setFab(myproc, FAB1(box1, ncomp1, (T1*)
p));
1977 }
else if (alloc_2) {
1978 Box const& box2 = fa2.fabbox(myproc);
1979 int ncomp2 = fa2.nComp();
1981 fa2.setFab(myproc, FAB2(box2, ncomp2, (T2*)
p));
1985 return std::unique_ptr<char,DataDeleter>((
char*)
p, DataDeleter{
The_Arena()});
1994 [[nodiscard]]
constexpr Dim3 operator() (Dim3 i)
const noexcept
1996 return Dim3{.x = i.y, .y = i.x, .z = i.z};
1999 static constexpr Dim3 Inverse (Dim3 i)
2001 return Dim3{.x = i.y, .y = i.x, .z = i.z};
2004 [[nodiscard]]
constexpr IndexType operator() (IndexType it)
const noexcept
2009 static constexpr IndexType Inverse (IndexType it)
2017 [[nodiscard]]
constexpr Dim3 operator() (Dim3 i)
const noexcept
2019 return Dim3{.x = i.z, .y = i.y, .z = i.x};
2022 static constexpr Dim3 Inverse (Dim3 i)
2024 return Dim3{.x = i.z, .y = i.y, .z = i.x};
2027 [[nodiscard]]
constexpr IndexType operator() (IndexType it)
const noexcept
2032 static constexpr IndexType Inverse (IndexType it)
2041 [[nodiscard]]
constexpr Dim3 operator() (Dim3 i)
const noexcept
2043 return Dim3{.x = i.y, .y = i.z, .z = i.x};
2047 static constexpr Dim3 Inverse (Dim3 i)
2049 return Dim3{.x = i.z, .y = i.x, .z = i.y};
2052 [[nodiscard]]
constexpr IndexType operator() (IndexType it)
const noexcept
2057 static constexpr IndexType Inverse (IndexType it)
2066 [[nodiscard]]
constexpr Dim3 operator() (Dim3 i)
const noexcept
2068 return Dim3{.x = i.z, .y = i.x, .z = i.y};
2072 static constexpr Dim3 Inverse (Dim3 i)
2074 return Dim3{.x = i.y, .y = i.z, .z = i.x};
2077 [[nodiscard]]
constexpr IndexType operator() (IndexType it)
const noexcept
2082 static constexpr IndexType Inverse (IndexType it)
2095 explicit SubHelper (Box
const& domain);
2097 [[nodiscard]]
Box make_box (Box
const& box)
const;
2099 [[nodiscard]] Periodicity make_periodicity (Periodicity
const& period)
const;
2101 [[nodiscard]]
bool ghost_safe (IntVect
const& ng)
const;
2104 [[nodiscard]]
IntVect make_iv (IntVect
const& iv)
const;
2107 [[nodiscard]]
IntVect make_safe_ghost (IntVect
const& ng)
const;
2109 [[nodiscard]] BoxArray inverse_boxarray (BoxArray
const& ba)
const;
2111 [[nodiscard]]
IntVect inverse_order (IntVect
const& order)
const;
2113 template <
typename T>
2114 [[nodiscard]] T make_array (T
const& a)
const
2116#if (AMREX_SPACEDIM == 1)
2119#elif (AMREX_SPACEDIM == 2)
2120 if (m_case == case_1n) {
2121 return T{a[1],a[0]};
2126 if (m_case == case_11n) {
2127 return T{a[2],a[0],a[1]};
2128 }
else if (m_case == case_1n1) {
2129 return T{a[1],a[0],a[2]};
2130 }
else if (m_case == case_1nn) {
2131 return T{a[1],a[2],a[0]};
2132 }
else if (m_case == case_n1n) {
2133 return T{a[0],a[2],a[1]};
2140 [[nodiscard]] GpuArray<int,3> xyz_order ()
const;
2142 template <
typename FA>
2143 FA make_alias_mf (FA
const& mf)
2145 BoxList bl = mf.boxArray().boxList();
2146 for (
auto& b : bl) {
2149 auto const& ng = make_iv(mf.nGrowVect());
2150 FA submf(BoxArray(std::move(bl)), mf.DistributionMap(), mf.nComp(), ng, MFInfo{}.SetAlloc(
false));
2151 using FAB =
typename FA::fab_type;
2152 for (MFIter mfi(submf, MFItInfo().DisableDeviceSync()); mfi.isValid(); ++mfi) {
2153 submf.setFab(mfi, FAB(mfi.fabbox(), mf.nComp(), mf[mfi].dataPtr()));
2158#if (AMREX_SPACEDIM == 2)
2159 enum Case { case_1n, case_other };
2160 int m_case = case_other;
2161#elif (AMREX_SPACEDIM == 3)
2162 enum Case { case_11n, case_1n1, case_1nn, case_n1n, case_other };
2163 int m_case = case_other;
Runtime initialization/finalization helpers and global diagnostics.
#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
Lightweight Arena-backed allocator and deleter helpers.
Maps FABs in a FabArray to MPI processes.
Enum reflection utilities and the AMREX_ENUM macro.
Distributed container of FAB objects plus copy and fill utilities.
Problem-domain geometry: maps between index space and physical space.
#define AMREX_CUFFT_SAFE_CALL(call)
Definition AMReX_GpuError.H:92
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
Convenience header for the core AMReX GPU facilities.
while parser_exe_t p
Definition AMReX_Parser_Exe_Body.H:33
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
virtual void free(void *pt)=0
Free a previously allocated block pointed to by pt.
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
__host__ __device__ IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:167
__host__ __device__ const IntVectND< dim > & smallEnd() const &noexcept
Return the inclusive lower bound of the box.
Definition AMReX_Box.H:124
int CoordInt() const noexcept
Returns the CoordType as an int.
Definition AMReX_CoordSys.H:52
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:51
Rectangular problem domain geometry.
Definition AMReX_Geometry.H:87
const Box & Domain() const noexcept
Returns our rectangular domain.
Definition AMReX_Geometry.H:246
const RealBox & ProbDomain() const noexcept
Returns the problem domain.
Definition AMReX_Geometry.H:202
bool isPeriodic(int dir) const noexcept
Is the domain periodic in the specified direction?
Definition AMReX_Geometry.H:399
static bool usingExternalStream() noexcept
Definition AMReX_GpuDevice.cpp:973
An Integer Vector in dim-Dimensional Space.
Definition AMReX_IntVect.H:149
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
__host__ __device__ Dim3 length(Array4< T > const &a) noexcept
Return the spatial extents of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1379
__host__ __device__ BoxND< dim > shift(const BoxND< dim > &b, int dir, int nzones) noexcept
Return a copy of b shifted by nzones cells in direction dir.
Definition AMReX_Box.H:1550
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:39
Arena * The_Arena()
Definition AMReX_Arena.cpp:839
#define AMREX_ENUM(CLASS,...)
Declare a scoped enum with reflection support.
Definition AMReX_Enum.H:270
Definition AMReX_FFT_CrossProj.H:8
CommStrategy
How the distributed transposes exchange data between processes.
Definition AMReX_FFT_Helper.H:62
@ alltoall
Definition AMReX_FFT_Helper.H:62
@ automatic
Definition AMReX_FFT_Helper.H:62
@ pointtopoint
Definition AMReX_FFT_Helper.H:62
@ alltoallv
Definition AMReX_FFT_Helper.H:62
constexpr int FastNumPrimeFactors() noexcept
Return the default factor count used for selecting fast FFT lengths.
Definition AMReX_FFT_Helper.H:78
int nextFastLen(int target, int nfactors=FastNumPrimeFactors())
Return the smallest fast FFT length greater than or equal to target.
Definition AMReX_FFT_Helper.H:303
Direction
Definition AMReX_FFT_Helper.H:57
@ backward
Definition AMReX_FFT_Helper.H:57
@ none
Definition AMReX_FFT_Helper.H:57
@ forward
Definition AMReX_FFT_Helper.H:57
@ both
Definition AMReX_FFT_Helper.H:57
Boundary
Definition AMReX_FFT_Helper.H:64
@ odd
Definition AMReX_FFT_Helper.H:64
@ even
Definition AMReX_FFT_Helper.H:64
@ periodic
Definition AMReX_FFT_Helper.H:64
DomainStrategy
Definition AMReX_FFT_Helper.H:59
@ automatic
Definition AMReX_FFT_Helper.H:59
@ pencil
Definition AMReX_FFT_Helper.H:59
@ slab
Definition AMReX_FFT_Helper.H:59
Kind
Definition AMReX_FFT_Helper.H:66
@ r2r_ee_f
Definition AMReX_FFT_Helper.H:66
@ r2r_oo_b
Definition AMReX_FFT_Helper.H:67
@ r2c_b
Definition AMReX_FFT_Helper.H:66
@ none
Definition AMReX_FFT_Helper.H:66
@ r2r_oe
Definition AMReX_FFT_Helper.H:67
@ r2c_f
Definition AMReX_FFT_Helper.H:66
@ r2r_ee_b
Definition AMReX_FFT_Helper.H:66
@ r2r_oo_f
Definition AMReX_FFT_Helper.H:67
@ c2c_f
Definition AMReX_FFT_Helper.H:66
@ r2r_eo
Definition AMReX_FFT_Helper.H:67
@ c2c_b
Definition AMReX_FFT_Helper.H:66
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:329
gpuStream_t gpuStream() noexcept
Definition AMReX_GpuDevice.H:310
__host__ __device__ std::pair< double, double > sincospi(double x)
Return sin(pi*x) and cos(pi*x) given x.
Definition AMReX_Math.H:347
int MPI_Comm
Definition AMReX_ccse-mpi.H:51
@ 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:273
@ overflow
Definition AMReX.H:561
BoxND< 3 > Box
Box is an alias for amrex::BoxND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:35
Direction
Definition AMReX_Orientation.H:14
@ x
Definition AMReX_Orientation.H:14
IndexTypeND< 3 > IndexType
IndexType is an alias for amrex::IndexTypeND instantiated with AMREX_SPACEDIM.
Definition AMReX_BaseFwd.H:41
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
const int[]
Definition AMReX_BLProfiler.cpp:1665
Definition AMReX_FFT_Helper.H:88
bool twod_mode
Definition AMReX_FFT_Helper.H:99
Info & setCommStrategy(CommStrategy s)
Select how the distributed transposes communicate.
Definition AMReX_FFT_Helper.H:180
CommStrategy comm_strategy
Communication strategy for the distributed transposes.
Definition AMReX_FFT_Helper.H:117
Info & setNumProcs(int n)
Cap the number of MPI ranks used by FFT.
Definition AMReX_FFT_Helper.H:171
bool oned_mode
Definition AMReX_FFT_Helper.H:108
int batch_size
Batched FFT size. Only support in R2C, not R2X.
Definition AMReX_FFT_Helper.H:111
Info & setOpenBCPadding(bool x)
Enable or disable OpenBCSolver internal FFT padding.
Definition AMReX_FFT_Helper.H:187
Info & setOpenBCPaddingNumPrimeFactors(int n)
Set the factor count used for OpenBCSolver FFT padding.
Definition AMReX_FFT_Helper.H:194
Info & setDomainStrategy(DomainStrategy s)
Select how the domain is decomposed across MPI ranks.
Definition AMReX_FFT_Helper.H:132
DomainStrategy domain_strategy
Domain composition strategy.
Definition AMReX_FFT_Helper.H:90
int nprocs
Max number of processes to use.
Definition AMReX_FFT_Helper.H:114
int pencil_threshold
Definition AMReX_FFT_Helper.H:94
bool openbc_padding
Whether OpenBCSolver pads internal FFT lengths for better performance.
Definition AMReX_FFT_Helper.H:120
Info & setOneDMode(bool x)
Flag the degenerate 2-D mode (nx==1 or ny==1) that still batches along z.
Definition AMReX_FFT_Helper.H:157
Info & setBatchSize(int bsize)
Specify the batch size for FFT.
Definition AMReX_FFT_Helper.H:164
int openbc_padding_nfactors
Definition AMReX_FFT_Helper.H:124
Info & setPencilThreshold(int t)
Override the slab→pencil break-even threshold for the automatic strategy.
Definition AMReX_FFT_Helper.H:139
Info & setTwoDMode(bool x)
Restrict transforms to the first two dimensions (3-D problems only).
Definition AMReX_FFT_Helper.H:146
Definition AMReX_FFT_Helper.H:377
void * pf
Definition AMReX_FFT_Helper.H:412
void unpack_r2r_buffer(T *pdst, void const *pbuf) const
Collapse the spectral R2R result back into the original real layout.
Definition AMReX_FFT_Helper.H:1320
VendorPlan plan2
Definition AMReX_FFT_Helper.H:411
int n
Definition AMReX_FFT_Helper.H:404
void destroy()
Release any vendor FFT plan objects owned by this Plan.
Definition AMReX_FFT_Helper.H:431
bool defined2
Definition AMReX_FFT_Helper.H:409
void init_r2r(Box const &box, VendorComplex *pc, std::pair< Boundary, Boundary > const &bc)
Initialize a real-to-real plan that reads/writes complex storage.
Definition AMReX_FFT_Helper.H:913
void pack_r2r_buffer(void *pbuf, T const *psrc) const
Expand the real R2R input into the symmetry-extended buffer expected by CUFFT/rocFFT.
Definition AMReX_FFT_Helper.H:1082
static void free_scratch_space(void *p)
Release GPU scratch allocated via alloc_scratch_space().
Definition AMReX_FFT_Helper.H:1074
static void destroy_vendor_plan(VendorPlan plan)
Helper that destroys a vendor plan of the appropriate backend type.
Definition AMReX_FFT_Helper.H:1530
Kind get_r2r_kind(std::pair< Boundary, Boundary > const &bc)
Map boundary conditions to the Plan Kind for real-to-real transforms.
Definition AMReX_FFT_Helper.H:775
cufftHandle VendorPlan
Definition AMReX_FFT_Helper.H:379
Kind kind
Definition AMReX_FFT_Helper.H:406
void init_c2c(Box const &box, VendorComplex *p, int ncomp=1, int ndims=1)
Initialize a complex-to-complex plan across 1/2/3 dimensions.
Definition AMReX_FFT_Helper.H:607
int howmany
Definition AMReX_FFT_Helper.H:405
void * pb
Definition AMReX_FFT_Helper.H:413
void init_r2c(Box const &box, T *pr, VendorComplex *pc, bool is_2d_transform=false, int ncomp=1)
Initialize a 1-D or 2-D real-to-complex plan over the supplied Box.
Definition AMReX_FFT_Helper.H:455
void compute_r2r()
Execute the real-to-real plan, including GPU packing/unpacking.
Definition AMReX_FFT_Helper.H:1473
std::conditional_t< std::is_same_v< float, T >, cuComplex, cuDoubleComplex > VendorComplex
Definition AMReX_FFT_Helper.H:380
void compute_c2c()
Execute the complex-to-complex plan in place.
Definition AMReX_FFT_Helper.H:1013
bool r2r_data_is_complex
Definition AMReX_FFT_Helper.H:407
void * alloc_scratch_space() const
Allocate GPU scratch space large enough to hold packed R2R data.
Definition AMReX_FFT_Helper.H:1057
VendorPlan plan
Definition AMReX_FFT_Helper.H:410
void compute_r2c()
Execute the previously initialized real-to-complex plan.
Definition AMReX_FFT_Helper.H:961
bool defined
Definition AMReX_FFT_Helper.H:408
void set_ptrs(void *p0, void *p1)
Register device pointers used by the forward/backward executions.
Definition AMReX_FFT_Helper.H:422
void init_r2r(Box const &box, T *p, std::pair< Boundary, Boundary > const &bc, int howmany_initval=1)
Initialize a real-to-real (cosine/sine) plan that operates on real buffers.
Definition AMReX_FFT_Helper.H:809
A host / device complex number type, because std::complex doesn't work in device code with Cuda yet.
Definition AMReX_GpuComplex.H:30