Block-Structured AMR Software Framework
 
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
190 template <typename F, Direction DIR=D,
191 std::enable_if_t<DIR == Direction::both, int> = 0>
192 void forwardThenBackward (MF const& inmf, MF& outmf, F const& post_forward,
193 int incomp = 0, int outcomp = 0)
194 {
195 BL_PROFILE("FFT::R2C::forwardbackward");
196 this->forward(inmf, incomp);
197 this->post_forward_doit_0(post_forward);
198 this->backward(outmf, outcomp);
199 }
200
211 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
212 DIR == Direction::both, int> = 0>
213 void forward (MF const& inmf, int incomp = 0);
214
226 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
227 DIR == Direction::both, int> = 0>
228 void forward (MF const& inmf, cMF& outmf, int incomp = 0, int outcomp = 0);
229
243 template <typename RT, typename CT, Direction DIR=D, bool CP=C,
244 std::enable_if_t<(DIR == Direction::forward ||
245 DIR == Direction::both)
246 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
247 (sizeof(RT) == sizeof(CT) && CP)), int> = 0>
248 void forward (RT const* in, CT* out);
249
259 template <Direction DIR=D, std::enable_if_t<DIR == Direction::both, int> = 0>
260 void backward (MF& outmf, int outcomp = 0);
261
273 template <Direction DIR=D, std::enable_if_t<DIR == Direction::backward ||
274 DIR == Direction::both, int> = 0>
275 void backward (cMF const& inmf, MF& outmf, int incomp = 0, int outcomp = 0);
276
290 template <typename CT, typename RT, Direction DIR=D, bool CP=C,
291 std::enable_if_t<(DIR == Direction::backward ||
292 DIR == Direction::both)
293 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
294 (sizeof(RT) == sizeof(CT) && CP)), int> = 0>
295 void backward (CT const* in, RT* out);
296
300 [[nodiscard]] T scalingFactor () const;
301
311 template <Direction DIR=D, std::enable_if_t<DIR == Direction::forward ||
312 DIR == Direction::both, int> = 0>
313 std::pair<cMF*,IntVect> getSpectralData () const;
314
322 [[nodiscard]] std::pair<BoxArray,DistributionMapping> getSpectralDataLayout () const;
323
324 // This is a private function, but it's public for cuda.
325 template <typename F>
326 void post_forward_doit_0 (F const& post_forward);
327
328 template <typename F>
329 void post_forward_doit_1 (F const& post_forward);
330
331private:
332
334
335 void backward_doit (MF& outmf, IntVect const& ngout = IntVect(0),
336 Periodicity const& period = Periodicity::NonPeriodic(),
337 int outcomp = 0);
338
339 void backward_doit (cMF const& inmf, MF& outmf,
340 IntVect const& ngout = IntVect(0),
341 Periodicity const& period = Periodicity::NonPeriodic(),
342 int incomp = 0, int outcomp = 0);
343
344 std::pair<Plan<T>,Plan<T>> make_c2c_plans (cMF& inout, int ndims) const;
345
346 static Box make_domain_x (Box const& domain)
347 {
348 if constexpr (C) {
349 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(0)-1,
350 domain.length(1)-1,
351 domain.length(2)-1)),
352 domain.ixType());
353 } else {
354 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(0)/2,
355 domain.length(1)-1,
356 domain.length(2)-1)),
357 domain.ixType());
358 }
359 }
360
361 static Box make_domain_y (Box const& domain)
362 {
363 if constexpr (C) {
364 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(1)-1,
365 domain.length(0)-1,
366 domain.length(2)-1)),
367 domain.ixType());
368 } else {
369 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(1)-1,
370 domain.length(0)/2,
371 domain.length(2)-1)),
372 domain.ixType());
373 }
374 }
375
376 static Box make_domain_z (Box const& domain)
377 {
378 if constexpr (C) {
379 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(2)-1,
380 domain.length(0)-1,
381 domain.length(1)-1)),
382 domain.ixType());
383 } else {
384 return Box(IntVect(0), IntVect(AMREX_D_DECL(domain.length(2)-1,
385 domain.length(0)/2,
386 domain.length(1)-1)),
387 domain.ixType());
388 }
389 }
390
391 static std::pair<BoxArray,DistributionMapping>
392 make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM> const& local_start,
393 std::array<int,AMREX_SPACEDIM> const& local_size);
394
395 template <typename FA, typename RT>
396 std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
397 install_raw_ptr (FA& fa, RT const* p);
398
407
408 // Comm meta-data. In the forward phase, we start with (x,y,z),
409 // transpose to (y,x,z) and then (z,x,y). In the backward phase, we
410 // perform inverse transpose.
411 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2y; // (x,y,z) -> (y,x,z)
412 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2x; // (y,x,z) -> (x,y,z)
413 std::unique_ptr<MultiBlockCommMetaData> m_cmd_y2z; // (y,x,z) -> (z,x,y)
414 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2y; // (z,x,y) -> (y,x,z)
415 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z; // (x,y,z) -> (z,x,y)
416 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x; // (z,x,y) -> (x,y,z)
417 std::unique_ptr<MultiBlockCommMetaData> m_cmd_x2z_half; // for openbc
418 std::unique_ptr<MultiBlockCommMetaData> m_cmd_z2x_half; // for openbc
425
430
431 mutable MF m_raw_mf;
432 mutable cMF m_raw_cmf;
433
434 std::unique_ptr<char,DataDeleter> m_data_1;
435 std::unique_ptr<char,DataDeleter> m_data_2;
436
441
442 std::unique_ptr<R2C<T,D,C>> m_r2c_sub;
444
446
447 bool m_do_alld_fft = false;
448 bool m_slab_decomp = false;
449 bool m_openbc_half = false;
450};
451
452template <typename T, Direction D, bool C>
453R2C<T,D,C>::R2C (Box const& domain, Info const& info)
454 : m_real_domain(domain),
455 m_spectral_domain_x(make_domain_x(domain)),
456#if (AMREX_SPACEDIM >= 2)
457 m_spectral_domain_y(make_domain_y(domain)),
458#if (AMREX_SPACEDIM == 3)
459 m_spectral_domain_z(make_domain_z(domain)),
460#endif
461#endif
462 m_sub_helper(domain),
463 m_info(info)
464{
465 BL_PROFILE("FFT::R2C");
466
467 static_assert(std::is_same_v<float,T> || std::is_same_v<double,T>);
468
470#if (AMREX_SPACEDIM == 2)
472#else
473 if (m_info.twod_mode) {
474 AMREX_ALWAYS_ASSERT((int(domain.length(0) > 1) +
475 int(domain.length(1) > 1) +
476 int(domain.length(2) > 1)) >= 2);
477 }
478#endif
479
480 {
482 if (subbox.size() != m_real_domain.size()) {
483 m_r2c_sub = std::make_unique<R2C<T,D,C>>(subbox, m_info);
484 return;
485 }
486 }
487
488 int myproc = ParallelContext::MyProcSub();
489 int nprocs = std::min(ParallelContext::NProcsSub(), m_info.nprocs);
490
491#if (AMREX_SPACEDIM == 3)
493 if (m_info.twod_mode) {
495 } else {
496 int shortside = m_real_domain.shortside();
497 if (shortside < m_info.pencil_threshold*nprocs) {
499 } else {
501 }
502 }
503 }
504
505 if (!m_info.oned_mode) {
506 if (m_info.twod_mode) {
507 m_slab_decomp = true;
509 m_slab_decomp = true;
510 }
511 }
512
513#endif
514
515 auto const ncomp = m_info.batch_size;
516
517 auto bax = amrex::decompose(m_real_domain, nprocs,
518 {AMREX_D_DECL(false,!m_slab_decomp,m_real_domain.length(2)>1)}, true);
519
521 m_rx.define(bax, dmx, ncomp, 0, MFInfo().SetAlloc(false));
522
523 {
524 BoxList bl = bax.boxList();
525 for (auto & b : bl) {
527 b.setBig(0, m_spectral_domain_x.bigEnd(0));
528 }
529 BoxArray cbax(std::move(bl));
530 m_cx.define(cbax, dmx, ncomp, 0, MFInfo().SetAlloc(false));
531 }
532
534
535 if (!m_do_alld_fft) // do a series of 1d or 2d ffts
536 {
537 //
538 // make data containers
539 //
540
541#if (AMREX_SPACEDIM >= 2)
544 {
545 auto cbay = amrex::decompose(m_spectral_domain_y, nprocs,
546 {AMREX_D_DECL(false,true,true)}, true);
547 if (cbay.size() == dmx.size()) {
548 cdmy = dmx;
549 } else {
550 cdmy = detail::make_iota_distromap(cbay.size());
551 }
552 m_cy.define(cbay, cdmy, ncomp, 0, MFInfo().SetAlloc(false));
553 }
554#endif
555
556#if (AMREX_SPACEDIM == 3)
557 if (m_real_domain.length(1) > 1 &&
558 (! m_info.twod_mode && m_real_domain.length(2) > 1))
559 {
560 auto cbaz = amrex::decompose(m_spectral_domain_z, nprocs,
561 {false,true,true}, true);
563 if (cbaz.size() == dmx.size()) {
564 cdmz = dmx;
565 } else if (cbaz.size() == cdmy.size()) {
566 cdmz = cdmy;
567 } else {
568 cdmz = detail::make_iota_distromap(cbaz.size());
569 }
570 m_cz.define(cbaz, cdmz, ncomp, 0, MFInfo().SetAlloc(false));
571 }
572#endif
573
574 if constexpr (C) {
575 if (m_slab_decomp) {
578 } else {
581 // make m_cx an alias to m_rx
582 if (myproc < m_cx.size()) {
583 Box const& box = m_cx.fabbox(myproc);
584 using FAB = typename cMF::FABType::value_type;
585 m_cx.setFab(myproc, FAB(box, ncomp, m_rx[myproc].dataPtr()));
586 }
587 }
588 } else {
589 if (m_slab_decomp) {
592 } else {
595 }
596 }
597
598 //
599 // make copiers
600 //
601
602#if (AMREX_SPACEDIM >= 2)
603 if (! m_cy.empty()) {
604 // comm meta-data between x and y phases
605 m_cmd_x2y = std::make_unique<MultiBlockCommMetaData>
607 m_cmd_y2x = std::make_unique<MultiBlockCommMetaData>
609 }
610#endif
611#if (AMREX_SPACEDIM == 3)
612 if (! m_cz.empty() ) {
613 if (m_slab_decomp) {
614 // comm meta-data between xy and z phases
615 m_cmd_x2z = std::make_unique<MultiBlockCommMetaData>
617 m_cmd_z2x = std::make_unique<MultiBlockCommMetaData>
619 } else {
620 // comm meta-data between y and z phases
621 m_cmd_y2z = std::make_unique<MultiBlockCommMetaData>
623 m_cmd_z2y = std::make_unique<MultiBlockCommMetaData>
625 }
626 }
627#endif
628
629 //
630 // make plans
631 //
632
633 if (myproc < m_rx.size())
634 {
635 if constexpr (C) {
636 int ndims = m_slab_decomp ? 2 : 1;
637 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx, ndims);
638 } else {
639 Box const& box = m_rx.box(myproc);
640 auto* pr = m_rx[myproc].dataPtr();
641 auto* pc = (typename Plan<T>::VendorComplex *)m_cx[myproc].dataPtr();
642#ifdef AMREX_USE_SYCL
643 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
645#else
646 if constexpr (D == Direction::both || D == Direction::forward) {
647 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pr, pc, m_slab_decomp, ncomp);
648 }
649 if constexpr (D == Direction::both || D == Direction::backward) {
650 m_fft_bwd_x.template init_r2c<Direction::backward>(box, pr, pc, m_slab_decomp, ncomp);
651 }
652#endif
653 }
654 }
655
656#if (AMREX_SPACEDIM >= 2)
657 if (! m_cy.empty()) {
659 }
660#endif
661#if (AMREX_SPACEDIM == 3)
662 if (! m_cz.empty()) {
664 }
665#endif
666 }
667 else // do fft in all dimensions at the same time
668 {
669 if constexpr (C) {
671 std::tie(m_fft_fwd_x, m_fft_bwd_x) = make_c2c_plans(m_cx,AMREX_SPACEDIM);
672 } else {
675
676 auto const& len = m_real_domain.length();
677 auto* pr = (void*)m_rx[0].dataPtr();
678 auto* pc = (void*)m_cx[0].dataPtr();
679#ifdef AMREX_USE_SYCL
680 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc, false, ncomp);
682#else
683 if constexpr (D == Direction::both || D == Direction::forward) {
684 m_fft_fwd_x.template init_r2c<Direction::forward>(len, pr, pc, false, ncomp);
685 }
686 if constexpr (D == Direction::both || D == Direction::backward) {
687 m_fft_bwd_x.template init_r2c<Direction::backward>(len, pr, pc, false, ncomp);
688 }
689#endif
690 }
691 }
692}
693
694template <typename T, Direction D, bool C>
695R2C<T,D,C>::R2C (std::array<int,AMREX_SPACEDIM> const& domain_size, Info const& info)
696 : R2C<T,D,C>(Box(IntVect(0),IntVect(domain_size)-1), info)
697{}
698
699template <typename T, Direction D, bool C>
701{
702 if (m_fft_bwd_x.plan != m_fft_fwd_x.plan) {
703 m_fft_bwd_x.destroy();
704 }
705 if (m_fft_bwd_y.plan != m_fft_fwd_y.plan) {
706 m_fft_bwd_y.destroy();
707 }
708 if (m_fft_bwd_z.plan != m_fft_fwd_z.plan) {
709 m_fft_bwd_z.destroy();
710 }
711 m_fft_fwd_x.destroy();
712 m_fft_fwd_y.destroy();
713 m_fft_fwd_z.destroy();
714 if (m_fft_bwd_x_half.plan != m_fft_fwd_x_half.plan) {
715 m_fft_bwd_x_half.destroy();
716 }
717 m_fft_fwd_x_half.destroy();
718}
719
720template <typename T, Direction D, bool C>
721std::pair<BoxArray,DistributionMapping>
722R2C<T,D,C>::make_layout_from_local_domain (std::array<int,AMREX_SPACEDIM> const& local_start,
723 std::array<int,AMREX_SPACEDIM> const& local_size)
724{
725 IntVect lo(local_start);
726 IntVect len(local_size);
727 Box bx(lo, lo+len-1);
728#ifdef AMREX_USE_MPI
730 MPI_Allgather(&bx, 1, ParallelDescriptor::Mpi_typemap<Box>::type(),
731 allboxes.data(), 1, ParallelDescriptor::Mpi_typemap<Box>::type(),
733 Vector<int> pmap;
734 pmap.reserve(allboxes.size());
735 for (int i = 0; i < allboxes.size(); ++i) {
736 if (allboxes[i].ok()) {
737 pmap.push_back(i);
738 }
739 }
740 allboxes.erase(std::remove_if(allboxes.begin(), allboxes.end(),
741 [=] (Box const& b) { return b.isEmpty(); }),
742 allboxes.end());
743 BoxList bl(std::move(allboxes));
744 return std::make_pair(BoxArray(std::move(bl)), DistributionMapping(std::move(pmap)));
745#else
746 return std::make_pair(BoxArray(bx), DistributionMapping(Vector<int>({0})));
747#endif
748}
749
750template <typename T, Direction D, bool C>
751void R2C<T,D,C>::setLocalDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
752 std::array<int,AMREX_SPACEDIM> const& local_size)
753{
754 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
755 m_raw_mf = MF(ba, dm, m_rx.nComp(), 0, MFInfo().SetAlloc(false));
756}
757
758template <typename T, Direction D, bool C>
759std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
761{
762 m_raw_mf = MF(m_rx.boxArray(), m_rx.DistributionMap(), m_rx.nComp(), 0,
763 MFInfo{}.SetAlloc(false));
764
765 auto const myproc = ParallelDescriptor::MyProc();
766 if (myproc < m_rx.size()) {
767 Box const& box = m_rx.box(myproc);
768 return std::make_pair(box.smallEnd().toArray(),
769 box.length().toArray());
770 } else {
771 return std::make_pair(std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)},
772 std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)});
773 }
774}
775
776template <typename T, Direction D, bool C>
777void R2C<T,D,C>::setLocalSpectralDomain (std::array<int,AMREX_SPACEDIM> const& local_start,
778 std::array<int,AMREX_SPACEDIM> const& local_size)
779{
780 auto const& [ba, dm] = make_layout_from_local_domain(local_start, local_size);
781 m_raw_cmf = cMF(ba, dm, m_rx.nComp(), 0, MFInfo().SetAlloc(false));
782}
783
784template <typename T, Direction D, bool C>
785std::pair<std::array<int,AMREX_SPACEDIM>,std::array<int,AMREX_SPACEDIM>>
787{
788 auto const ncomp = m_info.batch_size;
789 auto const& [ba, dm] = getSpectralDataLayout();
790
791 m_raw_cmf = cMF(ba, dm, ncomp, 0, MFInfo{}.SetAlloc(false));
792
793 auto const myproc = ParallelDescriptor::MyProc();
794 if (myproc < m_raw_cmf.size()) {
795 Box const& box = m_raw_cmf.box(myproc);
796 return std::make_pair(box.smallEnd().toArray(), box.length().toArray());
797 } else {
798 return std::make_pair(std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)},
799 std::array<int,AMREX_SPACEDIM>{AMREX_D_DECL(0,0,0)});
800 }
801}
802
803template <typename T, Direction D, bool C>
805{
806 if (C || m_r2c_sub) { amrex::Abort("R2C: OpenBC not supported with reduced dimensions or complex inputs"); }
807
808#if (AMREX_SPACEDIM == 3)
809 if (m_do_alld_fft) { return; }
810
811 auto const ncomp = m_info.batch_size;
812
813 if (m_slab_decomp && ! m_fft_fwd_x_half.defined) {
814 auto* fab = detail::get_fab(m_rx);
815 if (fab) {
816 Box bottom_half = m_real_domain;
817 bottom_half.growHi(2,-m_real_domain.length(2)/2);
818 Box box = fab->box() & bottom_half;
819 if (box.ok()) {
820 auto* pr = fab->dataPtr();
821 auto* pc = (typename Plan<T>::VendorComplex *)
822 detail::get_fab(m_cx)->dataPtr();
823#ifdef AMREX_USE_SYCL
824 m_fft_fwd_x_half.template init_r2c<Direction::forward>
825 (box, pr, pc, m_slab_decomp, ncomp);
826 m_fft_bwd_x_half = m_fft_fwd_x_half;
827#else
828 if constexpr (D == Direction::both || D == Direction::forward) {
829 m_fft_fwd_x_half.template init_r2c<Direction::forward>
830 (box, pr, pc, m_slab_decomp, ncomp);
831 }
832 if constexpr (D == Direction::both || D == Direction::backward) {
833 m_fft_bwd_x_half.template init_r2c<Direction::backward>
834 (box, pr, pc, m_slab_decomp, ncomp);
835 }
836#endif
837 }
838 }
839 } // else todo
840
841 if (m_cmd_x2z && ! m_cmd_x2z_half) {
842 Box bottom_half = m_spectral_domain_z;
843 // Note that z-direction's index is 0 because we z is the
844 // unit-stride direction here.
845 bottom_half.growHi(0,-m_spectral_domain_z.length(0)/2);
846 m_cmd_x2z_half = std::make_unique<MultiBlockCommMetaData>
847 (m_cz, bottom_half, m_cx, IntVect(0), m_dtos_x2z);
848 }
849
850 if (m_cmd_z2x && ! m_cmd_z2x_half) {
851 Box bottom_half = m_spectral_domain_x;
852 bottom_half.growHi(2,-m_spectral_domain_x.length(2)/2);
853 m_cmd_z2x_half = std::make_unique<MultiBlockCommMetaData>
854 (m_cx, bottom_half, m_cz, IntVect(0), m_dtos_z2x);
855 }
856#endif
857}
858
859template <typename T, Direction D, bool C>
860template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
861 DIR == Direction::both, int> >
862void R2C<T,D,C>::forward (MF const& inmf, int incomp)
863{
864 BL_PROFILE("FFT::R2C::forward(in)");
865
866 auto const ncomp = m_info.batch_size;
867
868 if (m_r2c_sub) {
869 if (m_sub_helper.ghost_safe(inmf.nGrowVect())) {
870 m_r2c_sub->forward(m_sub_helper.make_alias_mf(inmf), incomp);
871 } else {
872 MF tmp(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
873 tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
874 m_r2c_sub->forward(m_sub_helper.make_alias_mf(tmp),0);
875 }
876 return;
877 }
878
879 if (&m_rx != &inmf) {
880 m_rx.ParallelCopy(inmf, incomp, 0, ncomp);
881 }
882
883 if (m_do_alld_fft) {
884 if constexpr (C) {
885 m_fft_fwd_x.template compute_c2c<Direction::forward>();
886 } else {
887 m_fft_fwd_x.template compute_r2c<Direction::forward>();
888 }
889 return;
890 }
891
892 auto& fft_x = m_openbc_half ? m_fft_fwd_x_half : m_fft_fwd_x;
893 if constexpr (C) {
894 fft_x.template compute_c2c<Direction::forward>();
895 } else {
896 fft_x.template compute_r2c<Direction::forward>();
897 }
898
899 if ( m_cmd_x2y) {
900 ParallelCopy(m_cy, m_cx, *m_cmd_x2y, 0, 0, ncomp, m_dtos_x2y);
901 }
902 m_fft_fwd_y.template compute_c2c<Direction::forward>();
903
904 if ( m_cmd_y2z) {
905 ParallelCopy(m_cz, m_cy, *m_cmd_y2z, 0, 0, ncomp, m_dtos_y2z);
906 }
907#if (AMREX_SPACEDIM == 3)
908 else if ( m_cmd_x2z) {
909 if (m_openbc_half) {
910 NonLocalBC::PackComponents components{};
911 components.n_components = ncomp;
913 {components, m_dtos_x2z};
914 auto handler = ParallelCopy_nowait(m_cz, m_cx, *m_cmd_x2z_half, packing);
915
916 Box upper_half = m_spectral_domain_z;
917 // Note that z-direction's index is 0 because we z is the
918 // unit-stride direction here.
919 upper_half.growLo (0,-m_spectral_domain_z.length(0)/2);
920 m_cz.setVal(0, upper_half, 0, ncomp);
921
922 ParallelCopy_finish(m_cz, std::move(handler), *m_cmd_x2z_half, packing);
923 } else {
924 ParallelCopy(m_cz, m_cx, *m_cmd_x2z, 0, 0, ncomp, m_dtos_x2z);
925 }
926 }
927#endif
928 m_fft_fwd_z.template compute_c2c<Direction::forward>();
929}
930
931template <typename T, Direction D, bool C>
932template <typename FA, typename RT>
933std::pair<std::unique_ptr<char,DataDeleter>,std::size_t>
934R2C<T,D,C>::install_raw_ptr (FA& fa, RT const* p)
935{
936 AMREX_ALWAYS_ASSERT(!fa.empty());
937
938 using FAB = typename FA::FABType::value_type;
939 using T_FAB = typename FAB::value_type;
940 static_assert(sizeof(T_FAB) == sizeof(RT));
941
942 auto const ncomp = m_info.batch_size;
943 auto const& ia = fa.IndexArray();
944
945 T_FAB* pp = nullptr;
946 std::size_t sz = 0;
947
948 if ( ! ia.empty() ) {
949 int K = ia[0];
950 Box const& box = fa.fabbox(K);
951 if ((alignof(T_FAB) == alignof(RT)) || amrex::is_aligned(p,alignof(T_FAB))) {
952 pp = (T_FAB*)p;
953 } else {
954 sz = sizeof(T_FAB) * box.numPts() * ncomp;
955 pp = (T_FAB*) The_Arena()->alloc(sz);
956 }
957 fa.setFab(K, FAB(box,ncomp,pp));
958 }
959
960 if (sz == 0) {
961 return std::make_pair(std::unique_ptr<char,DataDeleter>{},std::size_t(0));
962 } else {
963 return std::make_pair(std::unique_ptr<char,DataDeleter>
964 {(char*)pp,DataDeleter{The_Arena()}}, sz);
965 }
966}
967
968
969template <typename T, Direction D, bool C>
970template <typename RT, typename CT, Direction DIR, bool CP,
971 std::enable_if_t<(DIR == Direction::forward ||
972 DIR == Direction::both)
973 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
974 (sizeof(RT) == sizeof(CT) && CP)), int> >
975void R2C<T,D,C>::forward (RT const* in, CT* out)
976{
977 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, in);
978 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, out);
979
980 if (rsz > 0) {
981 Gpu::dtod_memcpy_async(rdata.get(),in,rsz);
983 }
984
985 forward(m_raw_mf, m_raw_cmf);
986
987 if (csz) {
988 Gpu::dtod_memcpy_async(out,cdata.get(),csz);
990 }
991}
992
993template <typename T, Direction D, bool C>
994template <Direction DIR, std::enable_if_t<DIR == Direction::both, int> >
995void R2C<T,D,C>::backward (MF& outmf, int outcomp)
996{
997 backward_doit(outmf, IntVect(0), Periodicity::NonPeriodic(), outcomp);
998}
999
1000template <typename T, Direction D, bool C>
1001void R2C<T,D,C>::backward_doit (MF& outmf, IntVect const& ngout,
1002 Periodicity const& period, int outcomp)
1003{
1004 BL_PROFILE("FFT::R2C::backward(out)");
1005
1006 auto const ncomp = m_info.batch_size;
1007
1008 if (m_r2c_sub) {
1009 if (m_sub_helper.ghost_safe(outmf.nGrowVect())) {
1010 MF submf = m_sub_helper.make_alias_mf(outmf);
1011 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1012 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
1013 m_r2c_sub->backward_doit(submf, subngout, subperiod, outcomp);
1014 } else {
1015 MF tmp(outmf.boxArray(), outmf.DistributionMap(), ncomp,
1016 m_sub_helper.make_safe_ghost(outmf.nGrowVect()));
1017 this->backward_doit(tmp, ngout, period, 0);
1018 outmf.LocalCopy(tmp, 0, outcomp, ncomp, tmp.nGrowVect());
1019 }
1020 return;
1021 }
1022
1023 if (m_do_alld_fft) {
1024 if constexpr (C) {
1025 m_fft_bwd_x.template compute_c2c<Direction::backward>();
1026 } else {
1027 m_fft_bwd_x.template compute_r2c<Direction::backward>();
1028 }
1029 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp, IntVect(0),
1030 amrex::elemwiseMin(ngout,outmf.nGrowVect()), period);
1031 return;
1032 }
1033
1034 m_fft_bwd_z.template compute_c2c<Direction::backward>();
1035 if ( m_cmd_z2y) {
1036 ParallelCopy(m_cy, m_cz, *m_cmd_z2y, 0, 0, ncomp, m_dtos_z2y);
1037 }
1038#if (AMREX_SPACEDIM == 3)
1039 else if ( m_cmd_z2x) {
1040 auto const& cmd = m_openbc_half ? m_cmd_z2x_half : m_cmd_z2x;
1041 ParallelCopy(m_cx, m_cz, *cmd, 0, 0, ncomp, m_dtos_z2x);
1042 }
1043#endif
1044
1045 m_fft_bwd_y.template compute_c2c<Direction::backward>();
1046 if ( m_cmd_y2x) {
1047 ParallelCopy(m_cx, m_cy, *m_cmd_y2x, 0, 0, ncomp, m_dtos_y2x);
1048 }
1049
1050 auto& fft_x = m_openbc_half ? m_fft_bwd_x_half : m_fft_bwd_x;
1051 if constexpr (C) {
1052 fft_x.template compute_c2c<Direction::backward>();
1053 } else {
1054 fft_x.template compute_r2c<Direction::backward>();
1055 }
1056 outmf.ParallelCopy(m_rx, 0, outcomp, ncomp, IntVect(0),
1057 amrex::elemwiseMin(ngout,outmf.nGrowVect()), period);
1058}
1059
1060template <typename T, Direction D, bool C>
1061template <typename CT, typename RT, Direction DIR, bool CP,
1062 std::enable_if_t<(DIR == Direction::backward ||
1063 DIR == Direction::both)
1064 && ((sizeof(RT)*2 == sizeof(CT) && !CP) ||
1065 (sizeof(RT) == sizeof(CT) && CP)), int> >
1066void R2C<T,D,C>::backward (CT const* in, RT* out)
1067{
1068 auto [rdata, rsz] = install_raw_ptr(m_raw_mf, out);
1069 auto [cdata, csz] = install_raw_ptr(m_raw_cmf, in);
1070
1071 if (csz) {
1072 Gpu::dtod_memcpy_async(cdata.get(),in,csz);
1074 }
1075
1076 backward(m_raw_cmf, m_raw_mf);
1077
1078 if (rsz > 0) {
1079 Gpu::dtod_memcpy_async(out,rdata.get(),rsz);
1081 }
1082}
1083
1084template <typename T, Direction D, bool C>
1085std::pair<Plan<T>, Plan<T>>
1086R2C<T,D,C>::make_c2c_plans (cMF& inout, int ndims) const
1087{
1088 Plan<T> fwd;
1089 Plan<T> bwd;
1090
1091 auto* fab = detail::get_fab(inout);
1092 if (!fab) { return {fwd, bwd};}
1093
1094 Box const& box = fab->box();
1095 auto* pio = (typename Plan<T>::VendorComplex *)fab->dataPtr();
1096
1097 auto const ncomp = m_info.batch_size;
1098
1099#ifdef AMREX_USE_SYCL
1100 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1101 bwd = fwd;
1102#else
1103 if constexpr (D == Direction::both || D == Direction::forward) {
1104 fwd.template init_c2c<Direction::forward>(box, pio, ncomp, ndims);
1105 }
1106 if constexpr (D == Direction::both || D == Direction::backward) {
1107 bwd.template init_c2c<Direction::backward>(box, pio, ncomp, ndims);
1108 }
1109#endif
1110
1111 return {fwd, bwd};
1112}
1113
1114template <typename T, Direction D, bool C>
1115template <typename F>
1116void R2C<T,D,C>::post_forward_doit_0 (F const& post_forward)
1117{
1118 if (m_info.twod_mode || m_info.batch_size > 1) {
1119 amrex::Abort("xxxxx todo: post_forward");
1120#if (AMREX_SPACEDIM > 1)
1121 } else if (m_r2c_sub) {
1122 // We need to pass the originally ordered indices to post_forward.
1123#if (AMREX_SPACEDIM == 2)
1124 // The original domain is (1,ny). The sub domain is (ny,1).
1125 m_r2c_sub->post_forward_doit_1
1126 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1127 {
1128 post_forward(0, i, 0, sp);
1129 });
1130#else
1131 if (m_real_domain.length(0) == 1 && m_real_domain.length(1) == 1) {
1132 // Original domain: (1, 1, nz). Sub domain: (nz, 1, 1)
1133 m_r2c_sub->post_forward_doit_1
1134 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1135 {
1136 post_forward(0, 0, i, sp);
1137 });
1138 } else if (m_real_domain.length(0) == 1 && m_real_domain.length(2) == 1) {
1139 // Original domain: (1, ny, 1). Sub domain: (ny, 1, 1)
1140 m_r2c_sub->post_forward_doit_1
1141 ([=] AMREX_GPU_DEVICE (int i, int, int, auto& sp)
1142 {
1143 post_forward(0, i, 0, sp);
1144 });
1145 } else if (m_real_domain.length(0) == 1) {
1146 // Original domain: (1, ny, nz). Sub domain: (ny, nz, 1)
1147 m_r2c_sub->post_forward_doit_1
1148 ([=] AMREX_GPU_DEVICE (int i, int j, int, auto& sp)
1149 {
1150 post_forward(0, i, j, sp);
1151 });
1152 } else if (m_real_domain.length(1) == 1) {
1153 // Original domain: (nx, 1, nz). Sub domain: (nx, nz, 1)
1154 m_r2c_sub->post_forward_doit_1
1155 ([=] AMREX_GPU_DEVICE (int i, int j, int, auto& sp)
1156 {
1157 post_forward(i, 0, j, sp);
1158 });
1159 } else {
1160 amrex::Abort("R2c::post_forward_doit_0: how did this happen?");
1161 }
1162#endif
1163#endif
1164 } else {
1165 this->post_forward_doit_1(post_forward);
1166 }
1167}
1168
1169template <typename T, Direction D, bool C>
1170template <typename F>
1171void R2C<T,D,C>::post_forward_doit_1 (F const& post_forward)
1172{
1173 if (m_info.twod_mode || m_info.batch_size > 1) {
1174 amrex::Abort("xxxxx todo: post_forward");
1175 } else if (m_r2c_sub) {
1176 amrex::Abort("R2C::post_forward_doit_1: How did this happen?");
1177 } else {
1178 if ( ! m_cz.empty()) {
1179 auto* spectral_fab = detail::get_fab(m_cz);
1180 if (spectral_fab) {
1181 auto const& a = spectral_fab->array(); // m_cz's ordering is z,x,y
1182 ParallelForOMP(spectral_fab->box(),
1183 [=] AMREX_GPU_DEVICE (int iz, int jx, int ky)
1184 {
1185 post_forward(jx,ky,iz,a(iz,jx,ky));
1186 });
1187 }
1188 } else if ( ! m_cy.empty()) {
1189 auto* spectral_fab = detail::get_fab(m_cy);
1190 if (spectral_fab) {
1191 auto const& a = spectral_fab->array(); // m_cy's ordering is y,x,z
1192 ParallelForOMP(spectral_fab->box(),
1193 [=] AMREX_GPU_DEVICE (int iy, int jx, int k)
1194 {
1195 post_forward(jx,iy,k,a(iy,jx,k));
1196 });
1197 }
1198 } else {
1199 auto* spectral_fab = detail::get_fab(m_cx);
1200 if (spectral_fab) {
1201 auto const& a = spectral_fab->array();
1202 ParallelForOMP(spectral_fab->box(),
1203 [=] AMREX_GPU_DEVICE (int i, int j, int k)
1204 {
1205 post_forward(i,j,k,a(i,j,k));
1206 });
1207 }
1208 }
1209 }
1210}
1211
1212template <typename T, Direction D, bool C>
1214{
1215#if (AMREX_SPACEDIM == 3)
1216 if (m_info.twod_mode) {
1217 return T(1)/T(Long(m_real_domain.length(0)) *
1218 Long(m_real_domain.length(1)));
1219 } else
1220#endif
1221 {
1222 return T(1)/T(m_real_domain.numPts());
1223 }
1224}
1225
1226template <typename T, Direction D, bool C>
1227template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
1228 DIR == Direction::both, int> >
1229std::pair<typename R2C<T,D,C>::cMF *, IntVect>
1231{
1232#if (AMREX_SPACEDIM > 1)
1233 if (m_r2c_sub) {
1234 auto [cmf, order] = m_r2c_sub->getSpectralData();
1235 return std::make_pair(cmf, m_sub_helper.inverse_order(order));
1236 } else
1237#endif
1238 if (!m_cz.empty()) {
1239 return std::make_pair(const_cast<cMF*>(&m_cz), IntVect{AMREX_D_DECL(2,0,1)});
1240 } else if (!m_cy.empty()) {
1241 return std::make_pair(const_cast<cMF*>(&m_cy), IntVect{AMREX_D_DECL(1,0,2)});
1242 } else {
1243 return std::make_pair(const_cast<cMF*>(&m_cx), IntVect{AMREX_D_DECL(0,1,2)});
1244 }
1245}
1246
1247template <typename T, Direction D, bool C>
1248template <Direction DIR, std::enable_if_t<DIR == Direction::forward ||
1249 DIR == Direction::both, int> >
1250void R2C<T,D,C>::forward (MF const& inmf, cMF& outmf, int incomp, int outcomp)
1251{
1252 BL_PROFILE("FFT::R2C::forward(inout)");
1253
1254 auto const ncomp = m_info.batch_size;
1255
1256 if (m_r2c_sub)
1257 {
1258 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1259 MF inmf_sub, inmf_tmp;
1260 int incomp_sub;
1261 if (inmf_safe) {
1262 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1263 incomp_sub = incomp;
1264 } else {
1265 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1266 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
1267 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1268 incomp_sub = 0;
1269 }
1270
1271 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1272 cMF outmf_sub, outmf_tmp;
1273 int outcomp_sub;
1274 if (outmf_safe) {
1275 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1276 outcomp_sub = outcomp;
1277 } else {
1278 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), ncomp, 0);
1279 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1280 outcomp_sub = 0;
1281 }
1282
1283 m_r2c_sub->forward(inmf_sub, outmf_sub, incomp_sub, outcomp_sub);
1284
1285 if (!outmf_safe) {
1286 outmf.LocalCopy(outmf_tmp, 0, outcomp, ncomp, IntVect(0));
1287 }
1288 }
1289 else
1290 {
1291 forward(inmf, incomp);
1292 if (!m_cz.empty()) { // m_cz's order (z,x,y) -> (x,y,z)
1293 RotateBwd dtos{};
1295 (outmf, m_spectral_domain_x, m_cz, IntVect(0), dtos);
1296 ParallelCopy(outmf, m_cz, cmd, 0, outcomp, ncomp, dtos);
1297 } else if (!m_cy.empty()) { // m_cy's order (y,x,z) -> (x,y,z)
1299 (outmf, m_spectral_domain_x, m_cy, IntVect(0), m_dtos_y2x);
1300 ParallelCopy(outmf, m_cy, cmd, 0, outcomp, ncomp, m_dtos_y2x);
1301 } else {
1302 outmf.ParallelCopy(m_cx, 0, outcomp, ncomp);
1303 }
1304 }
1305}
1306
1307template <typename T, Direction D, bool C>
1308template <Direction DIR, std::enable_if_t<DIR == Direction::backward ||
1309 DIR == Direction::both, int> >
1310void R2C<T,D,C>::backward (cMF const& inmf, MF& outmf, int incomp, int outcomp)
1311{
1312 backward_doit(inmf, outmf, IntVect(0), Periodicity::NonPeriodic(), incomp, outcomp);
1313}
1314
1315template <typename T, Direction D, bool C>
1316void R2C<T,D,C>::backward_doit (cMF const& inmf, MF& outmf, IntVect const& ngout,
1317 Periodicity const& period, int incomp, int outcomp)
1318{
1319 BL_PROFILE("FFT::R2C::backward(inout)");
1320
1321 auto const ncomp = m_info.batch_size;
1322
1323 if (m_r2c_sub)
1324 {
1325 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1326 cMF inmf_sub, inmf_tmp;
1327 int incomp_sub;
1328 if (inmf_safe) {
1329 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1330 incomp_sub = incomp;
1331 } else {
1332 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), ncomp, 0);
1333 inmf_tmp.LocalCopy(inmf, incomp, 0, ncomp, IntVect(0));
1334 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1335 incomp_sub = 0;
1336 }
1337
1338 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1339 MF outmf_sub, outmf_tmp;
1340 int outcomp_sub;
1341 if (outmf_safe) {
1342 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1343 outcomp_sub = outcomp;
1344 } else {
1345 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
1346 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), ncomp, ngtmp);
1347 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1348 outcomp_sub = 0;
1349 }
1350
1351 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1352 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
1353 m_r2c_sub->backward_doit(inmf_sub, outmf_sub, subngout, subperiod, incomp_sub, outcomp_sub);
1354
1355 if (!outmf_safe) {
1356 outmf.LocalCopy(outmf_tmp, 0, outcomp, ncomp, outmf_tmp.nGrowVect());
1357 }
1358 }
1359 else
1360 {
1361 if (!m_cz.empty()) { // (x,y,z) -> m_cz's order (z,x,y)
1362 RotateFwd dtos{};
1364 (m_cz, m_spectral_domain_z, inmf, IntVect(0), dtos);
1365 ParallelCopy(m_cz, inmf, cmd, incomp, 0, ncomp, dtos);
1366 } else if (!m_cy.empty()) { // (x,y,z) -> m_cy's ordering (y,x,z)
1368 (m_cy, m_spectral_domain_y, inmf, IntVect(0), m_dtos_x2y);
1369 ParallelCopy(m_cy, inmf, cmd, incomp, 0, ncomp, m_dtos_x2y);
1370 } else {
1371 m_cx.ParallelCopy(inmf, incomp, 0, ncomp);
1372 }
1373 backward_doit(outmf, ngout, period, outcomp);
1374 }
1375}
1376
1377template <typename T, Direction D, bool C>
1378std::pair<BoxArray,DistributionMapping>
1380{
1381#if (AMREX_SPACEDIM > 1)
1382 if (m_r2c_sub) {
1383 auto const& [ba, dm] = m_r2c_sub->getSpectralDataLayout();
1384 return std::make_pair(m_sub_helper.inverse_boxarray(ba), dm);
1385 }
1386#endif
1387
1388#if (AMREX_SPACEDIM == 3)
1389 if (!m_cz.empty()) {
1390 BoxList bl = m_cz.boxArray().boxList();
1391 for (auto& b : bl) {
1392 auto lo = b.smallEnd();
1393 auto hi = b.bigEnd();
1394 std::swap(lo[0], lo[1]);
1395 std::swap(lo[1], lo[2]);
1396 std::swap(hi[0], hi[1]);
1397 std::swap(hi[1], hi[2]);
1398 b.setSmall(lo);
1399 b.setBig(hi);
1400 }
1401 return std::make_pair(BoxArray(std::move(bl)), m_cz.DistributionMap());
1402 } else
1403#endif
1404#if (AMREX_SPACEDIM >= 2)
1405 if (!m_cy.empty()) {
1406 BoxList bl = m_cy.boxArray().boxList();
1407 for (auto& b : bl) {
1408 auto lo = b.smallEnd();
1409 auto hi = b.bigEnd();
1410 std::swap(lo[0], lo[1]);
1411 std::swap(hi[0], hi[1]);
1412 b.setSmall(lo);
1413 b.setBig(hi);
1414 }
1415 return std::make_pair(BoxArray(std::move(bl)), m_cy.DistributionMap());
1416 } else
1417#endif
1418 {
1419 return std::make_pair(m_cx.boxArray(), m_cx.DistributionMap());
1420 }
1421}
1422
1424template <typename T = Real, FFT::Direction D = FFT::Direction::both>
1426
1427}
1428
1429#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
#define AMREX_D_DECL(a, b, c)
Definition AMReX_SPACE.H:171
virtual void * alloc(std::size_t sz)=0
A collection of Boxes stored in an Array.
Definition AMReX_BoxArray.H:551
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.
Definition AMReX_BoxList.cpp:565
__host__ __device__ const IntVectND< dim > & bigEnd() const &noexcept
Get the bigend.
Definition AMReX_Box.H:119
__host__ __device__ Long numPts() const noexcept
Returns the number of points contained in the BoxND.
Definition AMReX_Box.H:349
__host__ __device__ IntVectND< dim > length() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:149
__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:430
__host__ __device__ IntVectND< dim > size() const noexcept
Return the length of the BoxND.
Definition AMReX_Box.H:142
__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:651
__host__ __device__ IndexTypeND< dim > ixType() const noexcept
Returns the indexing type.
Definition AMReX_Box.H:130
__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:662
__host__ __device__ bool ok() const noexcept
Checks if it is a proper BoxND (including a valid type).
Definition AMReX_Box.H:203
__host__ __device__ const IntVectND< dim > & smallEnd() const &noexcept
Get the smallend of the BoxND.
Definition AMReX_Box.H:108
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:146
Poisson solver for periodic, Dirichlet & Neumann boundaries using FFT.
Definition AMReX_FFT_Poisson.H:58
Parallel Discrete Fourier Transform.
Definition AMReX_FFT_R2C.H:40
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2z_half
Definition AMReX_FFT_R2C.H:417
Info m_info
Definition AMReX_FFT_R2C.H:445
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:1316
void backward_doit(MF &outmf, IntVect const &ngout=IntVect(0), Periodicity const &period=Periodicity::NonPeriodic(), int outcomp=0)
Definition AMReX_FFT_R2C.H:1001
Box m_spectral_domain_y
Definition AMReX_FFT_R2C.H:439
cMF m_cy
Definition AMReX_FFT_R2C.H:428
Plan< T > m_fft_fwd_y
Definition AMReX_FFT_R2C.H:401
MF m_raw_mf
Definition AMReX_FFT_R2C.H:431
Plan< T > m_fft_fwd_z
Definition AMReX_FFT_R2C.H:403
void forward(MF const &inmf, cMF &outmf, int incomp=0, int outcomp=0)
Forward transform.
Definition AMReX_FFT_R2C.H:1250
~R2C()
Definition AMReX_FFT_R2C.H:700
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2x_half
Definition AMReX_FFT_R2C.H:418
void setLocalDomain(std::array< int, 3 > const &local_start, std::array< int, 3 > const &local_size)
Set local domain.
Definition AMReX_FFT_R2C.H:751
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2y
Definition AMReX_FFT_R2C.H:411
static Box make_domain_x(Box const &domain)
Definition AMReX_FFT_R2C.H:346
Box m_spectral_domain_x
Definition AMReX_FFT_R2C.H:438
static std::pair< BoxArray, DistributionMapping > make_layout_from_local_domain(std::array< int, 3 > const &local_start, std::array< int, 3 > const &local_size)
Definition AMReX_FFT_R2C.H:722
R2C(Box const &domain, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:453
cMF m_cx
Definition AMReX_FFT_R2C.H:427
Plan< T > m_fft_bwd_x
Definition AMReX_FFT_R2C.H:400
std::unique_ptr< char, DataDeleter > m_data_2
Definition AMReX_FFT_R2C.H:435
static Box make_domain_y(Box const &domain)
Definition AMReX_FFT_R2C.H:361
void backward(cMF const &inmf, MF &outmf, int incomp=0, int outcomp=0)
Backward transform.
Definition AMReX_FFT_R2C.H:1310
Swap02 m_dtos_y2z
Definition AMReX_FFT_R2C.H:421
R2C(R2C &&)=delete
void backward(MF &outmf, int outcomp=0)
Backward transform.
Definition AMReX_FFT_R2C.H:995
bool m_do_alld_fft
Definition AMReX_FFT_R2C.H:447
void post_forward_doit_1(F const &post_forward)
Definition AMReX_FFT_R2C.H:1171
Swap01 m_dtos_x2y
Definition AMReX_FFT_R2C.H:419
std::unique_ptr< MultiBlockCommMetaData > m_cmd_x2z
Definition AMReX_FFT_R2C.H:415
RotateFwd m_dtos_x2z
Definition AMReX_FFT_R2C.H:423
std::unique_ptr< MultiBlockCommMetaData > m_cmd_y2z
Definition AMReX_FFT_R2C.H:413
Plan< T > m_fft_bwd_x_half
Definition AMReX_FFT_R2C.H:406
T scalingFactor() const
Definition AMReX_FFT_R2C.H:1213
Box m_spectral_domain_z
Definition AMReX_FFT_R2C.H:440
cMF m_cz
Definition AMReX_FFT_R2C.H:429
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2y
Definition AMReX_FFT_R2C.H:414
std::unique_ptr< R2C< T, D, C > > m_r2c_sub
Definition AMReX_FFT_R2C.H:442
void post_forward_doit_0(F const &post_forward)
Definition AMReX_FFT_R2C.H:1116
detail::SubHelper m_sub_helper
Definition AMReX_FFT_R2C.H:443
Swap01 m_dtos_y2x
Definition AMReX_FFT_R2C.H:420
std::pair< std::array< int, 3 >, std::array< int, 3 > > getLocalDomain() const
Get local domain.
Definition AMReX_FFT_R2C.H:760
std::pair< Plan< T >, Plan< T > > make_c2c_plans(cMF &inout, int ndims) const
Definition AMReX_FFT_R2C.H:1086
std::pair< std::unique_ptr< char, DataDeleter >, std::size_t > install_raw_ptr(FA &fa, RT const *p)
Definition AMReX_FFT_R2C.H:934
void forward(RT const *in, CT *out)
Forward transform.
Definition AMReX_FFT_R2C.H:975
R2C(R2C const &)=delete
Plan< T > m_fft_bwd_z
Definition AMReX_FFT_R2C.H:404
Plan< T > m_fft_fwd_x_half
Definition AMReX_FFT_R2C.H:405
std::unique_ptr< MultiBlockCommMetaData > m_cmd_z2x
Definition AMReX_FFT_R2C.H:416
bool m_openbc_half
Definition AMReX_FFT_R2C.H:449
std::pair< BoxArray, DistributionMapping > getSpectralDataLayout() const
Get BoxArray and DistributionMapping for spectral data.
Definition AMReX_FFT_R2C.H:1379
void prepare_openbc()
Definition AMReX_FFT_R2C.H:804
static Box make_domain_z(Box const &domain)
Definition AMReX_FFT_R2C.H:376
std::pair< cMF *, IntVect > getSpectralData() const
Get the internal spectral data.
R2C(std::array< int, 3 > const &domain_size, Info const &info=Info{})
Constructor.
Definition AMReX_FFT_R2C.H:695
FabArray< BaseFab< GpuComplex< T > > > cMF
Definition AMReX_FFT_R2C.H:42
std::pair< std::array< int, 3 >, std::array< int, 3 > > getLocalSpectralDomain() const
Get local spectral domain.
Definition AMReX_FFT_R2C.H:786
std::unique_ptr< MultiBlockCommMetaData > m_cmd_y2x
Definition AMReX_FFT_R2C.H:412
Box m_real_domain
Definition AMReX_FFT_R2C.H:437
bool m_slab_decomp
Definition AMReX_FFT_R2C.H:448
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:192
void setLocalSpectralDomain(std::array< int, 3 > const &local_start, std::array< int, 3 > const &local_size)
Set local spectral domain.
Definition AMReX_FFT_R2C.H:777
MF m_rx
Definition AMReX_FFT_R2C.H:426
cMF m_raw_cmf
Definition AMReX_FFT_R2C.H:432
Plan< T > m_fft_bwd_y
Definition AMReX_FFT_R2C.H:402
void backward(CT const *in, RT *out)
Backward transform.
Definition AMReX_FFT_R2C.H:1066
std::unique_ptr< char, DataDeleter > m_data_1
Definition AMReX_FFT_R2C.H:434
Plan< T > m_fft_fwd_x
Definition AMReX_FFT_R2C.H:399
RotateBwd m_dtos_z2x
Definition AMReX_FFT_R2C.H:424
void forward(MF const &inmf, int incomp=0)
Forward transform.
Definition AMReX_FFT_R2C.H:862
Swap02 m_dtos_z2y
Definition AMReX_FFT_R2C.H:422
IntVect nGrowVect() const noexcept
Definition AMReX_FabArrayBase.H:80
int size() const noexcept
Return the number of FABs in the FabArray.
Definition AMReX_FabArrayBase.H:110
const DistributionMapping & DistributionMap() const noexcept
Return constant reference to associated DistributionMapping.
Definition AMReX_FabArrayBase.H:131
bool empty() const noexcept
Definition AMReX_FabArrayBase.H:89
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.
Definition AMReX_FabArrayBase.cpp:220
const BoxArray & boxArray() const noexcept
Return a constant reference to the BoxArray that defines the valid region associated with this FabArr...
Definition AMReX_FabArrayBase.H:95
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:2312
void ParallelCopy(const FabArray< FAB > &src, const Periodicity &period=Periodicity::NonPeriodic(), CpOp op=FabArrayBase::COPY)
Definition AMReX_FabArray.H:845
typename std::conditional_t< IsBaseFab< BaseFab< GpuComplex< T > > >::value, BaseFab< GpuComplex< T > >, FABType >::value_type value_type
Definition AMReX_FabArray.H:356
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:2128
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:1909
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:28
Long size() const noexcept
Definition AMReX_Vector.H:53
std::unique_ptr< char, DataDeleter > make_mfs_share(FA1 &fa1, FA2 &fa2)
Definition AMReX_FFT_Helper.H:1387
FA::FABType::value_type * get_fab(FA &fa)
Definition AMReX_FFT_Helper.H:1376
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:317
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:260
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
void ParallelForOMP(T n, L const &f) noexcept
Definition AMReX_GpuLaunch.H:249
BoxND< 3 > Box
Definition AMReX_BaseFwd.H:27
bool is_aligned(const void *p, std::size_t alignment) noexcept
Definition AMReX_Arena.H:35
BoxArray decompose(Box const &domain, int nboxes, Array< bool, 3 > const &decomp, bool no_overlap)
Decompose domain box into BoxArray.
Definition AMReX_BoxArray.cpp:1931
IntVectND< 3 > IntVect
Definition AMReX_BaseFwd.H:30
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:1967
Arena * The_Arena()
Definition AMReX_Arena.cpp:705
__host__ __device__ constexpr T elemwiseMin(T const &a, T const &b) noexcept
Definition AMReX_Algorithm.H:49
Definition AMReX_DataAllocator.H:29
Definition AMReX_FFT_Helper.H:58
bool twod_mode
Definition AMReX_FFT_Helper.H:69
bool oned_mode
We might have a special twod_mode: nx or ny == 1 && nz > 1.
Definition AMReX_FFT_Helper.H:72
int batch_size
Batched FFT size. Only support in R2C, not R2X.
Definition AMReX_FFT_Helper.H:75
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:78
int pencil_threshold
Definition AMReX_FFT_Helper.H:64
Definition AMReX_FFT_Helper.H:130
std::conditional_t< std::is_same_v< float, T >, cuComplex, cuDoubleComplex > VendorComplex
Definition AMReX_FFT_Helper.H:134
Definition AMReX_FFT_Helper.H:1499
Definition AMReX_FFT_Helper.H:1474
Definition AMReX_FFT_Helper.H:1428
Definition AMReX_FFT_Helper.H:1451
Definition AMReX_FFT_Helper.H:1526
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:626
This is the index mapping based on the DTOS MultiBlockDestToSrc.
Definition AMReX_NonLocalBC.H:216
Contains information about which components take part of the data transaction.
Definition AMReX_NonLocalBC.H:539
int n_components
Definition AMReX_NonLocalBC.H:542
Communication datatype (note: this structure also works without MPI)
Definition AMReX_ccse-mpi.H:78