Block-Structured AMR Software Framework
 
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
AMReX_FFT_R2C.H
Go to the documentation of this file.
1#ifndef AMREX_FFT_R2C_H_
2#define AMREX_FFT_R2C_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_MultiFab.H>
6#include <AMReX_FFT_Helper.H>
7#include <algorithm>
8#include <numeric>
9#include <tuple>
10
11namespace amrex::FFT
12{
13
14template <typename T> class OpenBCSolver;
15template <typename T> class Poisson;
16template <typename T> class PoissonHybrid;
17
38template <typename T = Real, FFT::Direction D = FFT::Direction::both, bool C = false>
39class R2C
40{
41public:
43 using MF = std::conditional_t
44 <C, cMF, std::conditional_t<std::is_same_v<T,Real>,
46
47 template <typename U> friend class OpenBCSolver;
48 template <typename U> friend class Poisson;
49 template <typename U> friend class PoissonHybrid;
50
57 explicit R2C (Box const& domain, Info const& info = Info{});
58
68 explicit R2C (std::array<int,AMREX_SPACEDIM> const& domain_size,
69 Info const& info = Info{});
70
71 ~R2C ();
72
73 R2C (R2C const&) = delete;
74 R2C (R2C &&) = delete;
75 R2C& operator= (R2C const&) = delete;
76 R2C& operator= (R2C &&) = delete;
77
101 void setLocalDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
102 std::array<int,AMREX_SPACEDIM> const& local_size);
103
115 std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
117
146 void setLocalSpectralDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
147 std::array<int,AMREX_SPACEDIM> const& local_size);
148
166 std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
168
188 template <typename F, Direction DIR=D,
189 std::enable_if_t<DIR == Direction::both, int> = 0>
190 void forwardThenBackward (MF const& inmf, MF& outmf, F const& post_forward,
191 int incomp = 0, int outcomp = 0)
192 {
193 BL_PROFILE("FFT::R2C::forwardbackward");
194 this->forward(inmf, incomp);
195 this->post_forward_doit_0(post_forward);
196 this->backward(outmf, outcomp);
197 }
198
208 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
209 DIR == Direction::both, int> = 0>
210 void forward (MF const& inmf, int incomp = 0);
211
221 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
222 DIR == Direction::both, int> = 0>
223 void forward (MF const& inmf, cMF& outmf, int incomp = 0, int outcomp = 0);
224
238 template <typename RT, typename CT, Direction DIR=D, bool CP=C,
239 std::enable_if_t<(DIR == Direction::forward ||
240 DIR == Direction::both)
241 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
242 (sizeof(RT) == sizeof(CT) && CP)), int> = 0>
243 void forward (RT const* in, CT* out);
244
253 template <Direction DIR=D, std::enable_if_t<DIR == Direction::both, int> = 0>
254 void backward (MF& outmf, int outcomp = 0);
255
265 template <Direction DIR=D, std::enable_if_t<DIR == Direction::backward ||
266 DIR == Direction::both, int> = 0>
267 void backward (cMF const& inmf, MF& outmf, int incomp = 0, int outcomp = 0);
268
282 template <typename CT, typename RT, Direction DIR=D, bool CP=C,
283 std::enable_if_t<(DIR == Direction::backward ||
284 DIR == Direction::both)
285 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
286 (sizeof(RT) == sizeof(CT) && CP)), int> = 0>
287 void backward (CT const* in, RT* out);
288
292 [[nodiscard]] T scalingFactor () const;
293
303 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
304 DIR == Direction::both, int> = 0>
305 std::pair<cMF*,IntVect> getSpectralData () const;
306
314 [[nodiscard]] std::pair<BoxArray,DistributionMapping> getSpectralDataLayout () const;
315
316 // This is a private function, but it's public for cuda.
317 template <typename F>
318 void post_forward_doit_0 (F const& post_forward);
319
320 template <typename F>
321 void post_forward_doit_1 (F const& post_forward);
322
323private:
324
326
327 void backward_doit (MF& outmf, IntVect const& ngout = IntVect(0),
328 Periodicity const& period = Periodicity::NonPeriodic(),
329 int outcomp = 0);
330
331 void backward_doit (cMF const& inmf, MF& outmf,
332 IntVect const& ngout = IntVect(0),
333 Periodicity const& period = Periodicity::NonPeriodic(),
334 int incomp = 0, int outcomp = 0);
335
336 std::pair<Plan<T>,Plan<T>> make_c2c_plans (cMF& inout, int ndims) const;
337
338 static Box make_domain_x (Box const& domain)
339 {
340 if constexpr (C) {
341 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(0)-1,
342 domain.length(1)-1,
343 domain.length(2)-1)),
344 domain.ixType());
345 } else {
346 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(0)/2,
347 domain.length(1)-1,
348 domain.length(2)-1)),
349 domain.ixType());
350 }
351 }
352
353 static Box make_domain_y (Box const& domain)
354 {
355 if constexpr (C) {
356 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(1)-1,
357 domain.length(0)-1,
358 domain.length(2)-1)),
359 domain.ixType());
360 } else {
361 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(1)-1,
362 domain.length(0)/2,
363 domain.length(2)-1)),
364 domain.ixType());
365 }
366 }
367
368 static Box make_domain_z (Box const& domain)
369 {
370 if constexpr (C) {
371 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(2)-1,
372 domain.length(0)-1,
373 domain.length(1)-1)),
374 domain.ixType());
375 } else {
376 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(2)-1,
377 domain.length(0)/2,
378 domain.length(1)-1)),
379 domain.ixType());
380 }
381 }
382
383 static std::pair<BoxArray,DistributionMapping>
384 make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM> const& local_start,
385 std::array<int,AMREX_SPACEDIM> const& local_size);
386
387 template <typename FA, typename RT>
388 std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
389 install_raw_ptr (FA& fa, RT const* p);
390
399
400 // Comm meta-data. In the forward phase, we start with (x,y,z),
401 // transpose to (y,x,z) and then (z,x,y). In the backward phase, we
402 // perform inverse transpose.
403 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2y; // (x,y,z) -> (y,x,z)
404 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2x; // (y,x,z) -> (x,y,z)
405 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2z; // (y,x,z) -> (z,x,y)
406 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2y; // (z,x,y) -> (y,x,z)
407 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z; // (x,y,z) -> (z,x,y)
408 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x; // (z,x,y) -> (x,y,z)
409 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z_half; // for openbc
410 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x_half; // for openbc
417
422
423 mutable MF m_raw_mf;
424 mutable cMF m_raw_cmf;
425
426 std::unique_ptr<char,DataDeleter> m_data_1;
427 std::unique_ptr<char,DataDeleter> m_data_2;
428
433
434 std::unique_ptr<R2C<T,D,C>> m_r2c_sub;
436
438
439 bool m_do_alld_fft = false;
440 bool m_slab_decomp = false;
441 bool m_openbc_half = false;
442};
443
444template <typename T, Direction D, bool C>
445R2C<T,D,C>::R2C (Box const& domain, Info const& info)
446 : m_real_domain(domain),
447 m_spectral_domain_x(make_domain_x(domain)),
448#if (AMREX_SPACEDIM >= 2)
449 m_spectral_domain_y(make_domain_y(domain)),
450#if (AMREX_SPACEDIM == 3)
451 m_spectral_domain_z(make_domain_z(domain)),
452#endif
453#endif
454 m_sub_helper(domain),
455 m_info(info)
456{
457 BL_PROFILE("FFT::R2C");
458
459 static_assert(std::is_same_v<float,T> || std::is_same_v<double,T>);
460
462#if (AMREX_SPACEDIM == 2)
464#else
465 if (m_info.twod_mode) {
466 AMREX_ALWAYS_ASSERT((int(domain.length(0) > 1) +
467 int(domain.length(1) > 1) +
468 int(domain.length(2) > 1)) >= 2);
469 }
470#endif
471
472 {
474 if (subbox.size() != m_real_domain.size()) {
475 m_r2c_sub = std::make_unique<R2C<T,D,C>>(subbox, m_info);
476 return;
477 }
478 }
479
480 int myproc = ParallelContext::MyProcSub();
481 int nprocs = std::min(ParallelContext::NProcsSub(), m_info.nprocs);
482
483#if (AMREX_SPACEDIM == 3)
485 if (m_info.twod_mode) {
486 if (m_real_domain.length(2) < nprocs) {
488 } else {
490 }
491 } else {
492 int shortside = m_real_domain.shortside();
493 if (shortside < m_info.pencil_threshold*nprocs) {
495 } else {
497 }
498 }
499 }
501 if (m_info.twod_mode && m_real_domain.length(2) == 1) {
502 m_slab_decomp = false;
503 } else {
504 m_slab_decomp = true;
505 }
506 }
507#endif
508
509 auto const ncomp = m_info.batch_size;
510
511 auto bax = amrex::decompose(m_real_domain, nprocs,
512 {AMREX_D_DECL(false,!m_slab_decomp,true)}, true);
514 m_rx.define(bax, dmx, ncomp, 0, MFInfo().SetAlloc(false));
515
516 {
517 BoxList bl = bax.boxList();
518 for (auto & b : bl) {
520 b.setBig(0, m_spectral_domain_x.bigEnd(0));
521 }
522 BoxArray cbax(std::move(bl));
523 m_cx.define(cbax, dmx, ncomp, 0, MFInfo().SetAlloc(false));
524 }
525
527
528 if (!m_do_alld_fft) // do a series of 1d or 2d ffts
529 {
530 //
531 // make data containers
532 //
533
534#if (AMREX_SPACEDIM >= 2)
535#if (AMREX_SPACEDIM == 2)
536 bool batch_on_y = false;
537#else
538 bool batch_on_y = m_info.twod_mode && (m_real_domain.length(2) == 1);
539#endif
541 if ((m_real_domain.length(1) > 1) && !m_slab_decomp && !batch_on_y)
542 {
543 auto cbay = amrex::decompose(m_spectral_domain_y, nprocs,
544 {AMREX_D_DECL(false,true,true)}, true);
545 if (cbay.size() == dmx.size()) {
546 cdmy = dmx;
547 } else {
548 cdmy = detail::make_iota_distromap(cbay.size());
549 }
550 m_cy.define(cbay, cdmy, ncomp, 0, MFInfo().SetAlloc(false));
551 }
552#endif
553
554#if (AMREX_SPACEDIM == 3)
555 if (m_real_domain.length(1) > 1 &&
556 (! m_info.twod_mode && m_real_domain.length(2) > 1))
557 {
558 auto cbaz = amrex::decompose(m_spectral_domain_z, nprocs,
559 {false,true,true}, true);
561 if (cbaz.size() == dmx.size()) {
562 cdmz = dmx;
563 } else if (cbaz.size() == cdmy.size()) {
564 cdmz = cdmy;
565 } else {
566 cdmz = detail::make_iota_distromap(cbaz.size());
567 }
568 m_cz.define(cbaz, cdmz, ncomp, 0, MFInfo().SetAlloc(false));
569 }
570#endif
571
572 if constexpr (C) {
573 if (m_slab_decomp) {
576 } else {
579 // make m_cx an alias to m_rx
580 if (myproc < m_cx.size()) {
581 Box const& box = m_cx.fabbox(myproc);
582 using FAB = typename cMF::FABType::value_type;
583 m_cx.setFab(myproc, FAB(box, ncomp, m_rx[myproc].dataPtr()));
584 }
585 }
586 } else {
587 if (m_slab_decomp) {
590 } else {
593 }
594 }
595
596 //
597 // make copiers
598 //
599
600#if (AMREX_SPACEDIM >= 2)
601 if (! m_cy.empty()) {
602 // comm meta-data between x and y phases
603 m_cmd_x2y = std::make_unique<MultiBlockCommMetaData>
605 m_cmd_y2x = std::make_unique<MultiBlockCommMetaData>
607 }
608#endif
609#if (AMREX_SPACEDIM == 3)
610 if (! m_cz.empty() ) {
611 if (m_slab_decomp) {
612 // comm meta-data between xy and z phases
613 m_cmd_x2z = std::make_unique<MultiBlockCommMetaData>
615 m_cmd_z2x = std::make_unique<MultiBlockCommMetaData>
617 } else {
618 // comm meta-data between y and z phases
619 m_cmd_y2z = std::make_unique<MultiBlockCommMetaData>
621 m_cmd_z2y = std::make_unique<MultiBlockCommMetaData>
623 }
624 }
625#endif
626
627 //
628 // make plans
629 //
630
631 if (myproc < m_rx.size())
632 {
633 if constexpr (C) {
634 int ndims = m_slab_decomp ? 2 : 1;
635 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx, ndims);
636 } else {
637 Box const& box = m_rx.box(myproc);
638 auto* pr = m_rx[myproc].dataPtr();
639 auto* pc = (typename Plan<T>::VendorComplex *)m_cx[myproc].dataPtr();
640#ifdef AMREX_USE_SYCL
641 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
643#else
644 if constexpr (D == Direction::both || D == Direction::forward) {
645 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
646 }
647 if constexpr (D == Direction::both || D == Direction::backward) {
648 m_fft_bwd_x.template init_r2c<Direction::backward>(box, pr, pc, m_slab_decomp, ncomp);
649 }
650#endif
651 }
652 }
653
654#if (AMREX_SPACEDIM >= 2)
655 if (! m_cy.empty()) {
657 }
658#endif
659#if (AMREX_SPACEDIM == 3)
660 if (! m_cz.empty()) {
662 }
663#endif
664 }
665 else // do fft in all dimensions at the same time
666 {
667 if constexpr (C) {
669 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx,AMREX_SPACEDIM);
670 } else {
673
674 auto const& len = m_real_domain.length();
675 auto* pr = (void*)m_rx[0].dataPtr();
676 auto* pc = (void*)m_cx[0].dataPtr();
677#ifdef AMREX_USE_SYCL
678 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc, false, ncomp);
680#else
681 if constexpr (D == Direction::both || D == Direction::forward) {
682 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc, false, ncomp);
683 }
684 if constexpr (D == Direction::both || D == Direction::backward) {
685 m_fft_bwd_x.template init_r2c<Direction::backward>(len, pr, pc, false, ncomp);
686 }
687#endif
688 }
689 }
690}
691
692template <typename T, Direction D, bool C>
693R2C<T,D,C>::R2C (std::array<int,AMREX_SPACEDIM> const& domain_size, Info const& info)
694 : R2C<T,D,C>(Box(IntVect(0),IntVect(domain_size)-1), info)
695{}
696
697template <typename T, Direction D, bool C>
699{
700 if (m_fft_bwd_x.plan != m_fft_fwd_x.plan) {
701 m_fft_bwd_x.destroy();
702 }
703 if (m_fft_bwd_y.plan != m_fft_fwd_y.plan) {
704 m_fft_bwd_y.destroy();
705 }
706 if (m_fft_bwd_z.plan != m_fft_fwd_z.plan) {
707 m_fft_bwd_z.destroy();
708 }
709 m_fft_fwd_x.destroy();
710 m_fft_fwd_y.destroy();
711 m_fft_fwd_z.destroy();
712 if (m_fft_bwd_x_half.plan != m_fft_fwd_x_half.plan) {
713 m_fft_bwd_x_half.destroy();
714 }
715 m_fft_fwd_x_half.destroy();
716}
717
718template <typename T, Direction D, bool C>
719std::pair<BoxArray,DistributionMapping>
720R2C<T,D,C>::make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM> const& local_start,
721 std::array<int,AMREX_SPACEDIM> const& local_size)
722{
723 IntVect lo(local_start);
724 IntVect len(local_size);
725 Box bx(lo, lo+len-1);
726#ifdef AMREX_USE_MPI
728 MPI_Allgather(&bx, 1, ParallelDescriptor::Mpi_typemap<Box>::type(),
729 allboxes.data(), 1, ParallelDescriptor::Mpi_typemap<Box>::type(),
731 Vector<int> pmap;
732 pmap.reserve(allboxes.size());
733 for (int i = 0; i < allboxes.size(); ++i) {
734 if (allboxes[i].ok()) {
735 pmap.push_back(i);
736 }
737 }
738 allboxes.erase(std::remove_if(allboxes.begin(), allboxes.end(),
739 [=] (Box const& b) { return b.isEmpty(); }),
740 allboxes.end());
741 BoxList bl(std::move(allboxes));
742 return std::make_pair(BoxArray(std::move(bl)), DistributionMapping(std::move(pmap)));
743#else
744 return std::make_pair(BoxArray(bx), DistributionMapping(Vector<int>({0})));
745#endif
746}
747
748template <typename T, Direction D, bool C>
749void R2C<T,D,C>::setLocalDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
750 std::array<int,AMREX_SPACEDIM> const& local_size)
751{
752 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
753 m_raw_mf = MF(ba, dm, m_rx.nComp(), 0, MFInfo().SetAlloc(false));
754}
755
756template <typename T, Direction D, bool C>
757std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
759{
760 m_raw_mf = MF(m_rx.boxArray(), m_rx.DistributionMap(), m_rx.nComp(), 0,
761 MFInfo{}.SetAlloc(false));
762
763 auto const myproc = ParallelDescriptor::MyProc();
764 if (myproc < m_rx.size()) {
765 Box const& box = m_rx.box(myproc);
766 return std::make_pair(box.smallEnd().toArray(),
767 box.length().toArray());
768 } else {
769 return std::make_pair(std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)},
770 std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)});
771 }
772}
773
774template <typename T, Direction D, bool C>
775void R2C<T,D,C>::setLocalSpectralDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
776 std::array<int,AMREX_SPACEDIM> const& local_size)
777{
778 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
779 m_raw_cmf = cMF(ba, dm, m_rx.nComp(), 0, MFInfo().SetAlloc(false));
780}
781
782template <typename T, Direction D, bool C>
783std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
785{
786 auto const ncomp = m_info.batch_size;
787 auto const& [ba, dm] = getSpectralDataLayout();
788
789 m_raw_cmf = cMF(ba, dm, ncomp, 0, MFInfo{}.SetAlloc(false));
790
791 auto const myproc = ParallelDescriptor::MyProc();
792 if (myproc < m_raw_cmf.size()) {
793 Box const& box = m_raw_cmf.box(myproc);
794 return std::make_pair(box.smallEnd().toArray(), box.length().toArray());
795 } else {
796 return std::make_pair(std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)},
797 std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)});
798 }
799}
800
801template <typename T, Direction D, bool C>
803{
804 if (C || m_r2c_sub) { amrex::Abort("R2C: OpenBC not supported with reduced dimensions or complex inputs"); }
805
806#if (AMREX_SPACEDIM == 3)
807 if (m_do_alld_fft) { return; }
808
809 auto const ncomp = m_info.batch_size;
810
811 if (m_slab_decomp && ! m_fft_fwd_x_half.defined) {
812 auto* fab = detail::get_fab(m_rx);
813 if (fab) {
814 Box bottom_half = m_real_domain;
815 bottom_half.growHi(2,-m_real_domain.length(2)/2);
816 Box box = fab->box() & bottom_half;
817 if (box.ok()) {
818 auto* pr = fab->dataPtr();
819 auto* pc = (typename Plan<T>::VendorComplex *)
820 detail::get_fab(m_cx)->dataPtr();
821#ifdef AMREX_USE_SYCL
822 m_fft_fwd_x_half.template init_r2c<Direction::forward>
823 (box, pr, pc, m_slab_decomp, ncomp);
824 m_fft_bwd_x_half = m_fft_fwd_x_half;
825#else
826 if constexpr (D == Direction::both || D == Direction::forward) {
827 m_fft_fwd_x_half.template init_r2c<Direction::forward>
828 (box, pr, pc, m_slab_decomp, ncomp);
829 }
830 if constexpr (D == Direction::both || D == Direction::backward) {
831 m_fft_bwd_x_half.template init_r2c<Direction::backward>
832 (box, pr, pc, m_slab_decomp, ncomp);
833 }
834#endif
835 }
836 }
837 } // else todo
838
839 if (m_cmd_x2z && ! m_cmd_x2z_half) {
840 Box bottom_half = m_spectral_domain_z;
841 // Note that z-direction's index is 0 because we z is the
842 // unit-stride direction here.
843 bottom_half.growHi(0,-m_spectral_domain_z.length(0)/2);
844 m_cmd_x2z_half = std::make_unique<MultiBlockCommMetaData>
845 (m_cz, bottom_half, m_cx, IntVect(0), m_dtos_x2z);
846 }
847
848 if (m_cmd_z2x && ! m_cmd_z2x_half) {
849 Box bottom_half = m_spectral_domain_x;
850 bottom_half.growHi(2,-m_spectral_domain_x.length(2)/2);
851 m_cmd_z2x_half = std::make_unique<MultiBlockCommMetaData>
852 (m_cx, bottom_half, m_cz, IntVect(0), m_dtos_z2x);
853 }
854#endif
855}
856
857template <typename T, Direction D, bool C>
858template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
859 DIR == Direction::both, int> >
860void R2C<T,D,C>::forward (MF const& inmf, int incomp)
861{
862 BL_PROFILE("FFT::R2C::forward(in)");
863
864 auto const ncomp = m_info.batch_size;
865
866 if (m_r2c_sub) {
867 if (m_sub_helper.ghost_safe(inmf.nGrowVect())) {
868 m_r2c_sub->forward(m_sub_helper.make_alias_mf(inmf), incomp);
869 } else {
870 MF tmp(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
871 tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
872 m_r2c_sub->forward(m_sub_helper.make_alias_mf(tmp),0);
873 }
874 return;
875 }
876
877 if (&m_rx != &inmf) {
878 m_rx.ParallelCopy(inmf, incomp, 0, ncomp);
879 }
880
881 if (m_do_alld_fft) {
882 if constexpr (C) {
883 m_fft_fwd_x.template compute_c2c<Direction::forward>();
884 } else {
885 m_fft_fwd_x.template compute_r2c<Direction::forward>();
886 }
887 return;
888 }
889
890 auto& fft_x = m_openbc_half ? m_fft_fwd_x_half : m_fft_fwd_x;
891 if constexpr (C) {
892 fft_x.template compute_c2c<Direction::forward>();
893 } else {
894 fft_x.template compute_r2c<Direction::forward>();
895 }
896
897 if ( m_cmd_x2y) {
898 ParallelCopy(m_cy, m_cx, *m_cmd_x2y, 0, 0, ncomp, m_dtos_x2y);
899 }
900 m_fft_fwd_y.template compute_c2c<Direction::forward>();
901
902 if ( m_cmd_y2z) {
903 ParallelCopy(m_cz, m_cy, *m_cmd_y2z, 0, 0, ncomp, m_dtos_y2z);
904 }
905#if (AMREX_SPACEDIM == 3)
906 else if ( m_cmd_x2z) {
907 if (m_openbc_half) {
908 NonLocalBC::PackComponents components{};
909 components.n_components = ncomp;
911 {components, m_dtos_x2z};
912 auto handler = ParallelCopy_nowait(m_cz, m_cx, *m_cmd_x2z_half, packing);
913
914 Box upper_half = m_spectral_domain_z;
915 // Note that z-direction's index is 0 because we z is the
916 // unit-stride direction here.
917 upper_half.growLo (0,-m_spectral_domain_z.length(0)/2);
918 m_cz.setVal(0, upper_half, 0, ncomp);
919
920 ParallelCopy_finish(m_cz, std::move(handler), *m_cmd_x2z_half, packing);
921 } else {
922 ParallelCopy(m_cz, m_cx, *m_cmd_x2z, 0, 0, ncomp, m_dtos_x2z);
923 }
924 }
925#endif
926 m_fft_fwd_z.template compute_c2c<Direction::forward>();
927}
928
929template <typename T, Direction D, bool C>
930template <typename FA, typename RT>
931std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
932R2C<T,D,C>::install_raw_ptr (FA& fa, RT const* p)
933{
934 AMREX_ALWAYS_ASSERT(!fa.empty());
935
936 using FAB = typename FA::FABType::value_type;
937 using T_FAB = typename FAB::value_type;
938 static_assert(sizeof(T_FAB) == sizeof(RT));
939
940 auto const ncomp = m_info.batch_size;
941 auto const& ia = fa.IndexArray();
942
943 T_FAB* pp = nullptr;
944 std::size_t sz = 0;
945
946 if ( ! ia.empty() ) {
947 int K = ia[0];
948 Box const& box = fa.fabbox(K);
949 if ((alignof(T_FAB) == alignof(RT)) || amrex::is_aligned(p,alignof(T_FAB))) {
950 pp = (T_FAB*)p;
951 } else {
952 sz = sizeof(T_FAB) * box.numPts() * ncomp;
953 pp = (T_FAB*) The_Arena()->alloc(sz);
954 }
955 fa.setFab(K, FAB(box,ncomp,pp));
956 }
957
958 if (sz == 0) {
959 return std::make_pair(std::unique_ptr<char,DataDeleter>{},std::size_t(0));
960 } else {
961 return std::make_pair(std::unique_ptr<char,DataDeleter>
962 {(char*)pp,DataDeleter{The_Arena()}}, sz);
963 }
964}
965
966
967template <typename T, Direction D, bool C>
968template <typename RT, typename CT, Direction DIR, bool CP,
969 std::enable_if_t<(DIR == Direction::forward ||
970 DIR == Direction::both)
971 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
972 (sizeof(RT) == sizeof(CT) && CP)), int> >
973void R2C<T,D,C>::forward (RT const* in, CT* out)
974{
975 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, in);
976 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, out);
977
978 if (rsz > 0) {
979#ifdef AMREX_USE_GPU
980 Gpu::dtod_memcpy_async(rdata.get(),in,rsz);
982#else
983 std::memcpy(rdata.get(),in,rsz);
984#endif
985 }
986
987 forward(m_raw_mf, m_raw_cmf);
988
989 if (csz) {
990#ifdef AMREX_USE_GPU
991 Gpu::dtod_memcpy_async(out,cdata.get(),csz);
993#else
994 std::memcpy(out,cdata.get(),csz);
995#endif
996 }
997}
998
999template <typename T, Direction D, bool C>
1000template <Direction DIR, std::enable_if_t<DIR == Direction::both, int> >
1001void R2C<T,D,C>::backward (MF& outmf, int outcomp)
1002{
1003 backward_doit(outmf, IntVect(0), Periodicity::NonPeriodic(), outcomp);
1004}
1005
1006template <typename T, Direction D, bool C>
1007void R2C<T,D,C>::backward_doit (MF& outmf, IntVect const& ngout,
1008 Periodicity const& period, int outcomp)
1009{
1010 BL_PROFILE("FFT::R2C::backward(out)");
1011
1012 auto const ncomp = m_info.batch_size;
1013
1014 if (m_r2c_sub) {
1015 if (m_sub_helper.ghost_safe(outmf.nGrowVect())) {
1016 MF submf = m_sub_helper.make_alias_mf(outmf);
1017 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1018 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
1019 m_r2c_sub->backward_doit(submf, subngout, subperiod, outcomp);
1020 } else {
1021 MF tmp(outmf.boxArray(), outmf.DistributionMap(), ncomp,
1022 m_sub_helper.make_safe_ghost(outmf.nGrowVect()));
1023 this->backward_doit(tmp, ngout, period, 0);
1024 outmf.LocalCopy(tmp, 0, outcomp, ncomp, tmp.nGrowVect());
1025 }
1026 return;
1027 }
1028
1029 if (m_do_alld_fft) {
1030 if constexpr (C) {
1031 m_fft_bwd_x.template compute_c2c<Direction::backward>();
1032 } else {
1033 m_fft_bwd_x.template compute_r2c<Direction::backward>();
1034 }
1035 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp, IntVect(0),
1036 amrex::elemwiseMin(ngout,outmf.nGrowVect()), period);
1037 return;
1038 }
1039
1040 m_fft_bwd_z.template compute_c2c<Direction::backward>();
1041 if ( m_cmd_z2y) {
1042 ParallelCopy(m_cy, m_cz, *m_cmd_z2y, 0, 0, ncomp, m_dtos_z2y);
1043 }
1044#if (AMREX_SPACEDIM == 3)
1045 else if ( m_cmd_z2x) {
1046 auto const& cmd = m_openbc_half ? m_cmd_z2x_half : m_cmd_z2x;
1047 ParallelCopy(m_cx, m_cz, *cmd, 0, 0, ncomp, m_dtos_z2x);
1048 }
1049#endif
1050
1051 m_fft_bwd_y.template compute_c2c<Direction::backward>();
1052 if ( m_cmd_y2x) {
1053 ParallelCopy(m_cx, m_cy, *m_cmd_y2x, 0, 0, ncomp, m_dtos_y2x);
1054 }
1055
1056 auto& fft_x = m_openbc_half ? m_fft_bwd_x_half : m_fft_bwd_x;
1057 if constexpr (C) {
1058 fft_x.template compute_c2c<Direction::backward>();
1059 } else {
1060 fft_x.template compute_r2c<Direction::backward>();
1061 }
1062 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp, IntVect(0),
1063 amrex::elemwiseMin(ngout,outmf.nGrowVect()), period);
1064}
1065
1066template <typename T, Direction D, bool C>
1067template <typename CT, typename RT, Direction DIR, bool CP,
1068 std::enable_if_t<(DIR == Direction::backward ||
1069 DIR == Direction::both)
1070 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
1071 (sizeof(RT) == sizeof(CT) && CP)), int> >
1072void R2C<T,D,C>::backward (CT const* in, RT* out)
1073{
1074 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, out);
1075 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, in);
1076
1077 if (csz) {
1078#ifdef AMREX_USE_GPU
1079 Gpu::dtod_memcpy_async(cdata.get(),in,csz);
1081#else
1082 std::memcpy(cdata.get(),in,csz);
1083#endif
1084 }
1085
1086 backward(m_raw_cmf, m_raw_mf);
1087
1088 if (rsz > 0) {
1089#ifdef AMREX_USE_GPU
1090 Gpu::dtod_memcpy_async(out,rdata.get(),rsz);
1092#else
1093 std::memcpy(out,rdata.get(),rsz);
1094#endif
1095 }
1096}
1097
1098template <typename T, Direction D, bool C>
1099std::pair<Plan<T>, Plan<T>>
1100R2C<T,D,C>::make_c2c_plans (cMF& inout, int ndims) const
1101{
1102 Plan<T> fwd;
1103 Plan<T> bwd;
1104
1105 auto* fab = detail::get_fab(inout);
1106 if (!fab) { return {fwd, bwd};}
1107
1108 Box const& box = fab->box();
1109 auto* pio = (typename Plan<T>::VendorComplex *)fab->dataPtr();
1110
1111 auto const ncomp = m_info.batch_size;
1112
1113#ifdef AMREX_USE_SYCL
1114 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1115 bwd = fwd;
1116#else
1117 if constexpr (D == Direction::both || D == Direction::forward) {
1118 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1119 }
1120 if constexpr (D == Direction::both || D == Direction::backward) {
1121 bwd.template init_c2c<Direction::backward>(box, pio, ncomp, ndims);
1122 }
1123#endif
1124
1125 return {fwd, bwd};
1126}
1127
1128template <typename T, Direction D, bool C>
1129template <typename F>
1130void R2C<T,D,C>::post_forward_doit_0 (F const& post_forward)
1131{
1132 if (m_info.twod_mode || m_info.batch_size > 1) {
1133 amrex::Abort("xxxxx todo: post_forward");
1134#if (AMREX_SPACEDIM > 1)
1135 } else if (m_r2c_sub) {
1136 // We need to pass the originally ordered indices to post_forward.
1137#if (AMREX_SPACEDIM == 2)
1138 // The original domain is (1,ny). The sub domain is (ny,1).
1139 m_r2c_sub->post_forward_doit_1
1140 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1141 {
1142 post_forward(0, i, 0, sp);
1143 });
1144#else
1145 if (m_real_domain.length(0) == 1 && m_real_domain.length(1) == 1) {
1146 // Original domain: (1, 1, nz). Sub domain: (nz, 1, 1)
1147 m_r2c_sub->post_forward_doit_1
1148 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1149 {
1150 post_forward(0, 0, i, sp);
1151 });
1152 } else if (m_real_domain.length(0) == 1 && m_real_domain.length(2) == 1) {
1153 // Original domain: (1, ny, 1). Sub domain: (ny, 1, 1)
1154 m_r2c_sub->post_forward_doit_1
1155 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1156 {
1157 post_forward(0, i, 0, sp);
1158 });
1159 } else if (m_real_domain.length(0) == 1) {
1160 // Original domain: (1, ny, nz). Sub domain: (ny, nz, 1)
1161 m_r2c_sub->post_forward_doit_1
1162 ([=] AMREX_GPU_DEVICE (int i, int j, int, auto& sp)
1163 {
1164 post_forward(0, i, j, sp);
1165 });
1166 } else if (m_real_domain.length(1) == 1) {
1167 // Original domain: (nx, 1, nz). Sub domain: (nx, nz, 1)
1168 m_r2c_sub->post_forward_doit_1
1169 ([=] AMREX_GPU_DEVICE (int i, int j, int, auto& sp)
1170 {
1171 post_forward(i, 0, j, sp);
1172 });
1173 } else {
1174 amrex::Abort("R2c::post_forward_doit_0: how did this happen?");
1175 }
1176#endif
1177#endif
1178 } else {
1179 this->post_forward_doit_1(post_forward);
1180 }
1181}
1182
1183template <typename T, Direction D, bool C>
1184template <typename F>
1185void R2C<T,D,C>::post_forward_doit_1 (F const& post_forward)
1186{
1187 if (m_info.twod_mode || m_info.batch_size > 1) {
1188 amrex::Abort("xxxxx todo: post_forward");
1189 } else if (m_r2c_sub) {
1190 amrex::Abort("R2C::post_forward_doit_1: How did this happen?");
1191 } else {
1192 if ( ! m_cz.empty()) {
1193 auto* spectral_fab = detail::get_fab(m_cz);
1194 if (spectral_fab) {
1195 auto const& a = spectral_fab->array(); // m_cz's ordering is z,x,y
1196 ParallelFor(spectral_fab->box(),
1197 [=] AMREX_GPU_DEVICE (int iz, int jx, int ky)
1198 {
1199 post_forward(jx,ky,iz,a(iz,jx,ky));
1200 });
1201 }
1202 } else if ( ! m_cy.empty()) {
1203 auto* spectral_fab = detail::get_fab(m_cy);
1204 if (spectral_fab) {
1205 auto const& a = spectral_fab->array(); // m_cy's ordering is y,x,z
1206 ParallelFor(spectral_fab->box(),
1207 [=] AMREX_GPU_DEVICE (int iy, int jx, int k)
1208 {
1209 post_forward(jx,iy,k,a(iy,jx,k));
1210 });
1211 }
1212 } else {
1213 auto* spectral_fab = detail::get_fab(m_cx);
1214 if (spectral_fab) {
1215 auto const& a = spectral_fab->array();
1216 ParallelFor(spectral_fab->box(),
1217 [=] AMREX_GPU_DEVICE (int i, int j, int k)
1218 {
1219 post_forward(i,j,k,a(i,j,k));
1220 });
1221 }
1222 }
1223 }
1224}
1225
1226template <typename T, Direction D, bool C>
1228{
1229#if (AMREX_SPACEDIM == 3)
1230 if (m_info.twod_mode) {
1231 if (m_real_domain.length(2) > 1) {
1232 return T(1)/T(Long(m_real_domain.length(0)) *
1233 Long(m_real_domain.length(1)));
1234 } else {
1235 return T(1)/T(m_real_domain.length(0));
1236 }
1237 } else
1238#endif
1239 {
1240 return T(1)/T(m_real_domain.numPts());
1241 }
1242}
1243
1244template <typename T, Direction D, bool C>
1245template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
1246 DIR == Direction::both, int> >
1247std::pair<typename R2C<T,D,C>::cMF *, IntVect>
1249{
1250#if (AMREX_SPACEDIM > 1)
1251 if (m_r2c_sub) {
1252 auto [cmf, order] = m_r2c_sub->getSpectralData();
1253 return std::make_pair(cmf, m_sub_helper.inverse_order(order));
1254 } else
1255#endif
1256 if (!m_cz.empty()) {
1257 return std::make_pair(const_cast<cMF*>(&m_cz), IntVect{AMREX_D_DECL(2,0,1)});
1258 } else if (!m_cy.empty()) {
1259 return std::make_pair(const_cast<cMF*>(&m_cy), IntVect{AMREX_D_DECL(1,0,2)});
1260 } else {
1261 return std::make_pair(const_cast<cMF*>(&m_cx), IntVect{AMREX_D_DECL(0,1,2)});
1262 }
1263}
1264
1265template <typename T, Direction D, bool C>
1266template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
1267 DIR == Direction::both, int> >
1268void R2C<T,D,C>::forward (MF const& inmf, cMF& outmf, int incomp, int outcomp)
1269{
1270 BL_PROFILE("FFT::R2C::forward(inout)");
1271
1272 auto const ncomp = m_info.batch_size;
1273
1274 if (m_r2c_sub)
1275 {
1276 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1277 MF inmf_sub, inmf_tmp;
1278 int incomp_sub;
1279 if (inmf_safe) {
1280 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1281 incomp_sub = incomp;
1282 } else {
1283 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1284 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
1285 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1286 incomp_sub = 0;
1287 }
1288
1289 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1290 cMF outmf_sub, outmf_tmp;
1291 int outcomp_sub;
1292 if (outmf_safe) {
1293 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1294 outcomp_sub = outcomp;
1295 } else {
1296 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), ncomp, 0);
1297 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1298 outcomp_sub = 0;
1299 }
1300
1301 m_r2c_sub->forward(inmf_sub, outmf_sub, incomp_sub, outcomp_sub);
1302
1303 if (!outmf_safe) {
1304 outmf.LocalCopy(outmf_tmp, 0, outcomp, ncomp, IntVect(0));
1305 }
1306 }
1307 else
1308 {
1309 forward(inmf, incomp);
1310 if (!m_cz.empty()) { // m_cz's order (z,x,y) -> (x,y,z)
1311 RotateBwd dtos{};
1313 (outmf, m_spectral_domain_x, m_cz, IntVect(0), dtos);
1314 ParallelCopy(outmf, m_cz, cmd, 0, outcomp, ncomp, dtos);
1315 } else if (!m_cy.empty()) { // m_cy's order (y,x,z) -> (x,y,z)
1317 (outmf, m_spectral_domain_x, m_cy, IntVect(0), m_dtos_y2x);
1318 ParallelCopy(outmf, m_cy, cmd, 0, outcomp, ncomp, m_dtos_y2x);
1319 } else {
1320 outmf.ParallelCopy(m_cx, 0, outcomp, ncomp);
1321 }
1322 }
1323}
1324
1325template <typename T, Direction D, bool C>
1326template <Direction DIR, std::enable_if_t<DIR == Direction::backward ||
1327 DIR == Direction::both, int> >
1328void R2C<T,D,C>::backward (cMF const& inmf, MF& outmf, int incomp, int outcomp)
1329{
1330 backward_doit(inmf, outmf, IntVect(0), Periodicity::NonPeriodic(), incomp, outcomp);
1331}
1332
1333template <typename T, Direction D, bool C>
1334void R2C<T,D,C>::backward_doit (cMF const& inmf, MF& outmf, IntVect const& ngout,
1335 Periodicity const& period, int incomp, int outcomp)
1336{
1337 BL_PROFILE("FFT::R2C::backward(inout)");
1338
1339 auto const ncomp = m_info.batch_size;
1340
1341 if (m_r2c_sub)
1342 {
1343 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1344 cMF inmf_sub, inmf_tmp;
1345 int incomp_sub;
1346 if (inmf_safe) {
1347 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1348 incomp_sub = incomp;
1349 } else {
1350 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1351 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
1352 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1353 incomp_sub = 0;
1354 }
1355
1356 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1357 MF outmf_sub, outmf_tmp;
1358 int outcomp_sub;
1359 if (outmf_safe) {
1360 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1361 outcomp_sub = outcomp;
1362 } else {
1363 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
1364 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), ncomp, ngtmp);
1365 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1366 outcomp_sub = 0;
1367 }
1368
1369 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1370 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
1371 m_r2c_sub->backward_doit(inmf_sub, outmf_sub, subngout, subperiod, incomp_sub, outcomp_sub);
1372
1373 if (!outmf_safe) {
1374 outmf.LocalCopy(outmf_tmp, 0, outcomp, ncomp, outmf_tmp.nGrowVect());
1375 }
1376 }
1377 else
1378 {
1379 if (!m_cz.empty()) { // (x,y,z) -> m_cz's order (z,x,y)
1380 RotateFwd dtos{};
1382 (m_cz, m_spectral_domain_z, inmf, IntVect(0), dtos);
1383 ParallelCopy(m_cz, inmf, cmd, incomp, 0, ncomp, dtos);
1384 } else if (!m_cy.empty()) { // (x,y,z) -> m_cy's ordering (y,x,z)
1386 (m_cy, m_spectral_domain_y, inmf, IntVect(0), m_dtos_x2y);
1387 ParallelCopy(m_cy, inmf, cmd, incomp, 0, ncomp, m_dtos_x2y);
1388 } else {
1389 m_cx.ParallelCopy(inmf, incomp, 0, ncomp);
1390 }
1391 backward_doit(outmf, ngout, period, outcomp);
1392 }
1393}
1394
1395template <typename T, Direction D, bool C>
1396std::pair<BoxArray,DistributionMapping>
1398{
1399#if (AMREX_SPACEDIM > 1)
1400 if (m_r2c_sub) {
1401 auto const& [ba, dm] = m_r2c_sub->getSpectralDataLayout();
1402 return std::make_pair(m_sub_helper.inverse_boxarray(ba), dm);
1403 }
1404#endif
1405
1406#if (AMREX_SPACEDIM == 3)
1407 if (!m_cz.empty()) {
1408 BoxList bl = m_cz.boxArray().boxList();
1409 for (auto& b : bl) {
1410 auto lo = b.smallEnd();
1411 auto hi = b.bigEnd();
1412 std::swap(lo[0], lo[1]);
1413 std::swap(lo[1], lo[2]);
1414 std::swap(hi[0], hi[1]);
1415 std::swap(hi[1], hi[2]);
1416 b.setSmall(lo);
1417 b.setBig(hi);
1418 }
1419 return std::make_pair(BoxArray(std::move(bl)), m_cz.DistributionMap());
1420 } else
1421#endif
1422#if (AMREX_SPACEDIM >= 2)
1423 if (!m_cy.empty()) {
1424 BoxList bl = m_cy.boxArray().boxList();
1425 for (auto& b : bl) {
1426 auto lo = b.smallEnd();
1427 auto hi = b.bigEnd();
1428 std::swap(lo[0], lo[1]);
1429 std::swap(hi[0], hi[1]);
1430 b.setSmall(lo);
1431 b.setBig(hi);
1432 }
1433 return std::make_pair(BoxArray(std::move(bl)), m_cy.DistributionMap());
1434 } else
1435#endif
1436 {
1437 return std::make_pair(m_cx.boxArray(), m_cx.DistributionMap());
1438 }
1439}
1440
1442template <typename T = Real, FFT::Direction D = FFT::Direction::both>
1444
1445}
1446
1447#endif
#define BL_PROFILE(a)
Definition AMReX_BLProfiler.H:551
#define AMREX_ALWAYS_ASSERT(EX)
Definition AMReX_BLassert.H:50
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
amrex::ParmParse pp
Input file parser instance for the given namespace.
Definition AMReX_HypreIJIface.cpp:15
if(!(yy_init))
Definition amrex_iparser.lex.nolint.H:935
virtual void * alloc(std::size_t sz)=0
A collection of Boxes stored in an Array.
Definition AMReX_BoxArray.H:550
A class for managing a List of Boxes that share a common IndexType. This class implements operations ...
Definition AMReX_BoxList.H:52
BoxList & shift(int dir, int nzones)
Applies Box::shift(int,int) to each Box in the BoxList.
AMREX_GPU_HOST_DEVICE int shortside(int &dir) const noexcept
Returns length of shortest side. dir is modified to give direction with shortest side: 0....
Definition AMReX_Box.H:427
AMREX_GPU_HOST_DEVICE IndexTypeND< dim > ixType() const noexcept
Returns the indexing type.
Definition AMReX_Box.H:127
AMREX_GPU_HOST_DEVICE IntVectND< dim > size() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:139
AMREX_GPU_HOST_DEVICE IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:146
AMREX_GPU_HOST_DEVICE BoxND & growLo(int idir, int n_cell=1) noexcept
Grow the BoxND on the low end by n_cell cells in direction idir. NOTE: n_cell negative shrinks the Bo...
Definition AMReX_Box.H:648
AMREX_GPU_HOST_DEVICE BoxND & growHi(int idir, int n_cell=1) noexcept
Grow the BoxND on the high end by n_cell cells in direction idir. NOTE: n_cell negative shrinks the B...
Definition AMReX_Box.H:659
AMREX_GPU_HOST_DEVICE const IntVectND< dim > & smallEnd() const &noexcept
Get the smallend of the BoxND.
Definition AMReX_Box.H:105
AMREX_GPU_HOST_DEVICE bool ok() const noexcept
Checks if it is a proper BoxND (including a valid type).
Definition AMReX_Box.H:200
AMREX_GPU_HOST_DEVICE Long numPts() const noexcept
Returns the number of points contained in the BoxND.
Definition AMReX_Box.H:346
AMREX_GPU_HOST_DEVICE const IntVectND< dim > & bigEnd() const &noexcept
Get the bigend.
Definition AMReX_Box.H:116
Calculates the distribution of FABs to MPI processes.
Definition AMReX_DistributionMapping.H:41
Long size() const noexcept
Length of the underlying processor map.
Definition AMReX_DistributionMapping.H:127
Definition AMReX_FFT_OpenBCSolver.H:11
3D Poisson solver for periodic, Dirichlet & Neumann boundaries in the first two dimensions,...
Definition AMReX_FFT_Poisson.H:106
Poisson solver for periodic, Dirichlet & Neumann boundaries using FFT.
Definition AMReX_FFT_Poisson.H:22
Parallel Discrete Fourier Transform.
Definition AMReX_FFT_R2C.H:40
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2z_half
Definition AMReX_FFT_R2C.H:409
Info m_info
Definition AMReX_FFT_R2C.H:437
std::conditional_t< C, cMF, std::conditional_t< std::is_same_v< T, Real >, MultiFab, FabArray< BaseFab< T > > > > MF
Definition AMReX_FFT_R2C.H:45
R2C & operator=(R2C const &)=delete
void backward_doit(cMF const &inmf, MF &outmf, IntVect const &ngout=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic(), int incomp=0, int outcomp=0)
Definition AMReX_FFT_R2C.H:1334
void backward_doit(MF &outmf, IntVect const &ngout=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic(), int outcomp=0)
Definition AMReX_FFT_R2C.H:1007
Box m_spectral_domain_y
Definition AMReX_FFT_R2C.H:431
cMF m_cy
Definition AMReX_FFT_R2C.H:420
Plan< T > m_fft_fwd_y
Definition AMReX_FFT_R2C.H:393
MF m_raw_mf
Definition AMReX_FFT_R2C.H:423
Plan< T > m_fft_fwd_z
Definition AMReX_FFT_R2C.H:395
std::pair< std::array< int, AMREX_SPACEDIM >, std::array< int, AMREX_SPACEDIM > > getLocalSpectralDomain() const
Get local spectral domain.
Definition AMReX_FFT_R2C.H:784
void forward(MF const &inmf, cMF &outmf, int incomp=0, int outcomp=0)
Forward transform.
Definition AMReX_FFT_R2C.H:1268
std::pair< std::array< int, AMREX_SPACEDIM >, std::array< int, AMREX_SPACEDIM > > getLocalDomain() const
Get local domain.
Definition AMReX_FFT_R2C.H:758
~R2C()
Definition AMReX_FFT_R2C.H:698
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2x_half
Definition AMReX_FFT_R2C.H:410
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2y
Definition AMReX_FFT_R2C.H:403
static Box make_domain_x(Box const &domain)
Definition AMReX_FFT_R2C.H:338
Box m_spectral_domain_x
Definition AMReX_FFT_R2C.H:430
R2C(Box const &domain, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:445
cMF m_cx
Definition AMReX_FFT_R2C.H:419
Plan< T > m_fft_bwd_x
Definition AMReX_FFT_R2C.H:392
std::unique_ptr< char, DataDeleter > m_data_2
Definition AMReX_FFT_R2C.H:427
static Box make_domain_y(Box const &domain)
Definition AMReX_FFT_R2C.H:353
void backward(cMF const &inmf, MF &outmf, int incomp=0, int outcomp=0)
Backward transform.
Definition AMReX_FFT_R2C.H:1328
Swap02 m_dtos_y2z
Definition AMReX_FFT_R2C.H:413
R2C(R2C &&)=delete
void backward(MF &outmf, int outcomp=0)
Backward transform.
Definition AMReX_FFT_R2C.H:1001
bool m_do_alld_fft
Definition AMReX_FFT_R2C.H:439
void setLocalSpectralDomain(std::array< int, AMREX_SPACEDIM > const &local_start, std::array< int, AMREX_SPACEDIM > const &local_size)
Set local spectral domain.
Definition AMReX_FFT_R2C.H:775
void post_forward_doit_1(F const &post_forward)
Definition AMReX_FFT_R2C.H:1185
Swap01 m_dtos_x2y
Definition AMReX_FFT_R2C.H:411
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2z
Definition AMReX_FFT_R2C.H:407
RotateFwd m_dtos_x2z
Definition AMReX_FFT_R2C.H:415
std::unique_ptr< MultiBlockCommMetaData > m_cmd_y2z
Definition AMReX_FFT_R2C.H:405
Plan< T > m_fft_bwd_x_half
Definition AMReX_FFT_R2C.H:398
T scalingFactor() const
Definition AMReX_FFT_R2C.H:1227
Box m_spectral_domain_z
Definition AMReX_FFT_R2C.H:432
cMF m_cz
Definition AMReX_FFT_R2C.H:421
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2y
Definition AMReX_FFT_R2C.H:406
std::unique_ptr< R2C< T, D, C > > m_r2c_sub
Definition AMReX_FFT_R2C.H:434
void post_forward_doit_0(F const &post_forward)
Definition AMReX_FFT_R2C.H:1130
detail::SubHelper m_sub_helper
Definition AMReX_FFT_R2C.H:435
R2C(std::array< int, AMREX_SPACEDIM > const &domain_size, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:693
Swap01 m_dtos_y2x
Definition AMReX_FFT_R2C.H:412
std::pair< Plan< T >, Plan< T > > make_c2c_plans(cMF &inout, int ndims) const
Definition AMReX_FFT_R2C.H:1100
std::pair< std::unique_ptr< char, DataDeleter >, std::size_t > install_raw_ptr(FA &fa, RT const *p)
Definition AMReX_FFT_R2C.H:932
void forward(RT const *in, CT *out)
Forward transform.
Definition AMReX_FFT_R2C.H:973
R2C(R2C const &)=delete
Plan< T > m_fft_bwd_z
Definition AMReX_FFT_R2C.H:396
Plan< T > m_fft_fwd_x_half
Definition AMReX_FFT_R2C.H:397
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2x
Definition AMReX_FFT_R2C.H:408
bool m_openbc_half
Definition AMReX_FFT_R2C.H:441
std::pair< BoxArray, DistributionMapping > getSpectralDataLayout() const
Get BoxArray and DistributionMapping for spectral data.
Definition AMReX_FFT_R2C.H:1397
void prepare_openbc()
Definition AMReX_FFT_R2C.H:802
static Box make_domain_z(Box const &domain)
Definition AMReX_FFT_R2C.H:368
std::pair< cMF *, IntVect > getSpectralData() const
Get the internal spectral data.
FabArray< BaseFab< GpuComplex< T > > > cMF
Definition AMReX_FFT_R2C.H:42
std::unique_ptr< MultiBlockCommMetaData > m_cmd_y2x
Definition AMReX_FFT_R2C.H:404
Box m_real_domain
Definition AMReX_FFT_R2C.H:429
bool m_slab_decomp
Definition AMReX_FFT_R2C.H:440
void forwardThenBackward(MF const &inmf, MF &outmf, F const &post_forward, int incomp=0, int outcomp=0)
Forward and then backward transform.
Definition AMReX_FFT_R2C.H:190
MF m_rx
Definition AMReX_FFT_R2C.H:418
cMF m_raw_cmf
Definition AMReX_FFT_R2C.H:424
static std::pair< BoxArray, DistributionMapping > make_layout_from_local_domain(std::array< int, AMREX_SPACEDIM > const &local_start, std::array< int, AMREX_SPACEDIM > const &local_size)
Definition AMReX_FFT_R2C.H:720
Plan< T > m_fft_bwd_y
Definition AMReX_FFT_R2C.H:394
void backward(CT const *in, RT *out)
Backward transform.
Definition AMReX_FFT_R2C.H:1072
std::unique_ptr< char, DataDeleter > m_data_1
Definition AMReX_FFT_R2C.H:426
Plan< T > m_fft_fwd_x
Definition AMReX_FFT_R2C.H:391
void setLocalDomain(std::array< int, AMREX_SPACEDIM > const &local_start, std::array< int, AMREX_SPACEDIM > const &local_size)
Set local domain.
Definition AMReX_FFT_R2C.H:749
RotateBwd m_dtos_z2x
Definition AMReX_FFT_R2C.H:416
void forward(MF const &inmf, int incomp=0)
Forward transform.
Definition AMReX_FFT_R2C.H:860
Swap02 m_dtos_z2y
Definition AMReX_FFT_R2C.H:414
IntVect nGrowVect() const noexcept
Definition AMReX_FabArrayBase.H:79
int size() const noexcept
Return the number of FABs in the FabArray.
Definition AMReX_FabArrayBase.H:109
const DistributionMapping & DistributionMap() const noexcept
Return constant reference to associated DistributionMapping.
Definition AMReX_FabArrayBase.H:130
bool empty() const noexcept
Definition AMReX_FabArrayBase.H:88
Box fabbox(int K) const noexcept
Return the Kth FABs Box in the FabArray. That is, the region the Kth fab is actually defined on.
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:94
void setFab(int boxno, std::unique_ptr< FAB > elem)
Explicitly set the Kth FAB in the FabArray to point to elem.
Definition AMReX_FabArray.H:2126
void ParallelCopy(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Definition AMReX_FabArray.H:840
typename std::conditional_t< IsBaseFab< BaseFab< GpuComplex< T > > >::value, BaseFab< GpuComplex< T > >, FABType >::value_type value_type
Definition AMReX_FabArray.H:355
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:1942
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:1733
A collection (stored as an array) of FArrayBox objects.
Definition AMReX_MultiFab.H:38
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:27
Long size() const noexcept
Definition AMReX_Vector.H:50
std::unique_ptr< char, DataDeleter > make_mfs_share(FA1 &fa1, FA2 &fa2)
Definition AMReX_FFT_Helper.H:1383
FA::FABType::value_type * get_fab(FA &fa)
Definition AMReX_FFT_Helper.H:1372
DistributionMapping make_iota_distromap(Long n)
Definition AMReX_FFT.cpp:88
Definition AMReX_FFT.cpp:7
Direction
Definition AMReX_FFT_Helper.H:48
void dtod_memcpy_async(void *p_d_dst, const void *p_d_src, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:279
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:237
int MyProcSub() noexcept
my sub-rank in current frame
Definition AMReX_ParallelContext.H:76
int NProcsSub() noexcept
number of ranks in current frame
Definition AMReX_ParallelContext.H:74
MPI_Comm Communicator() noexcept
Definition AMReX_ParallelDescriptor.H:210
int MyProc() noexcept
return the rank number local to the current Parallel Context
Definition AMReX_ParallelDescriptor.H:125
int NProcs() noexcept
return the number of MPI ranks local to the current Parallel Context
Definition AMReX_ParallelDescriptor.H:243
std::enable_if_t< std::is_integral_v< T > > ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:191
BoxND< AMREX_SPACEDIM > Box
Definition AMReX_BaseFwd.H:27
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE constexpr T elemwiseMin(T const &a, T const &b) noexcept
Definition AMReX_Algorithm.H:49
bool is_aligned(const void *p, std::size_t alignment) noexcept
Definition AMReX_Arena.H:35
IntVectND< AMREX_SPACEDIM > IntVect
Definition AMReX_BaseFwd.H:30
BoxArray decompose(Box const &domain, int nboxes, Array< bool, AMREX_SPACEDIM > const &decomp={AMREX_D_DECL(true, true, true)}, bool no_overlap=false)
Decompose domain box into BoxArray.
void Abort(const std::string &msg)
Print out message to cerr and exit via abort().
Definition AMReX.cpp:230
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:1873
Arena * The_Arena()
Definition AMReX_Arena.cpp:616
Definition AMReX_DataAllocator.H:29
Definition AMReX_FFT_Helper.H:58
bool twod_mode
Definition AMReX_FFT_Helper.H:69
int batch_size
Batched FFT size. Only support in R2C, not R2X.
Definition AMReX_FFT_Helper.H:72
DomainStrategy domain_strategy
Domain composition strategy.
Definition AMReX_FFT_Helper.H:60
int nprocs
Max number of processes to use.
Definition AMReX_FFT_Helper.H:75
int pencil_threshold
Definition AMReX_FFT_Helper.H:64
Definition AMReX_FFT_Helper.H:126
std::conditional_t< std::is_same_v< float, T >, cuComplex, cuDoubleComplex > VendorComplex
Definition AMReX_FFT_Helper.H:130
Definition AMReX_FFT_Helper.H:1495
Definition AMReX_FFT_Helper.H:1470
Definition AMReX_FFT_Helper.H:1424
Definition AMReX_FFT_Helper.H:1447
Definition AMReX_FFT_Helper.H:1522
Box make_box(Box const &box) const
Definition AMReX_FFT.cpp:142
FabArray memory allocation information.
Definition AMReX_FabArray.H:66
MFInfo & SetAlloc(bool a) noexcept
Definition AMReX_FabArray.H:73
This class specializes behaviour on local copies and unpacking receive buffers.
Definition AMReX_NonLocalBC.H:619
This is the index mapping based on the DTOS MultiBlockDestToSrc.
Definition AMReX_NonLocalBC.H:210
Contains information about which components take part of the data transaction.
Definition AMReX_NonLocalBC.H:532
int n_components
Definition AMReX_NonLocalBC.H:535
Communication datatype (note: this structure also works without MPI)
Definition AMReX_ccse-mpi.H:68