103 template <
typename F>
147 void backward (
MF const& inmf,
MF& outmf,
IntVect const& ngout,
157 void backward (
cMF const& inmf,
MF& outmf,
IntVect const& ngout,
169 Plan<T> m_fft_fwd_y{};
170 Plan<T> m_fft_bwd_y{};
171 Plan<T> m_fft_fwd_z{};
172 Plan<T> m_fft_bwd_z{};
174 std::unique_ptr<MultiBlockCommMetaData> m_cmd_cx2cy;
175 std::unique_ptr<MultiBlockCommMetaData> m_cmd_rx2ry;
176 std::unique_ptr<MultiBlockCommMetaData> m_cmd_cy2cz;
177 std::unique_ptr<MultiBlockCommMetaData> m_cmd_ry2rz;
179 std::unique_ptr<MultiBlockCommMetaData> m_cmd_cy2cx;
180 std::unique_ptr<MultiBlockCommMetaData> m_cmd_ry2rx;
181 std::unique_ptr<MultiBlockCommMetaData> m_cmd_cz2cy;
182 std::unique_ptr<MultiBlockCommMetaData> m_cmd_rz2ry;
196 std::unique_ptr<char,DataDeleter> m_data_1;
197 std::unique_ptr<char,DataDeleter> m_data_2;
206 std::unique_ptr<R2X<T>> m_r2x_sub;
207 detail::SubHelper m_sub_helper;
214 Array<std::pair<Boundary,Boundary>,AMREX_SPACEDIM>
const& bc,
218 m_sub_helper(domain),
223 static_assert(std::is_same_v<float,T> || std::is_same_v<double,T>);
226#if (AMREX_SPACEDIM == 2)
231 int(domain.
length(1) > 1) +
232 int(domain.
length(2) > 1)) >= 2);
236 for (
int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
244 Box subbox = m_sub_helper.make_box(m_dom_0);
245 if (subbox.
size() != m_dom_0.
size()) {
246 m_r2x_sub = std::make_unique<R2X<T>>
247 (subbox, m_sub_helper.make_array(bc), info);
262 m_rx.define(bax, dmx, 1, 0,
MFInfo().SetAlloc(
false));
271 for (
auto & b : bl) {
272 b.setBig(0, m_dom_cx.
bigEnd(0));
278#if (AMREX_SPACEDIM >= 2)
280 if (! m_cx.
empty()) {
287 if (ba.size() == m_cx.
size()) {
290 dm = detail::make_iota_distromap(ba.size());
304 if (ba.size() == m_rx.size()) {
305 dm = m_rx.DistributionMap();
307 dm = detail::make_iota_distromap(ba.size());
309 m_ry.define(ba, dm, 1, 0,
MFInfo().SetAlloc(
false));
319 for (
auto & b : bl) {
320 b.setBig(0, m_dom_cy.
bigEnd(0));
329#if (AMREX_SPACEDIM == 3)
331 if (! m_cy.
empty()) {
338 if (ba.size() == m_cy.
size()) {
341 dm = detail::make_iota_distromap(ba.size());
355 if (ba.size() == m_ry.size()) {
356 dm = m_ry.DistributionMap();
358 dm = detail::make_iota_distromap(ba.size());
360 m_rz.define(ba, dm, 1, 0,
MFInfo().SetAlloc(
false));
370 for (
auto & b : bl) {
371 b.setBig(0, m_dom_cz.
bigEnd(0));
402 if (! m_cx.
empty()) {
403 m_data_1 = detail::make_mfs_share(m_rx, m_cy);
404 m_data_2 = detail::make_mfs_share(m_cx, m_cz);
405 }
else if (! m_cy.
empty()) {
406 m_data_1 = detail::make_mfs_share(m_rx, m_cy);
407 m_data_2 = detail::make_mfs_share(m_ry, m_cz);
408 }
else if (! m_cz.
empty()) {
409 m_data_1 = detail::make_mfs_share(m_rx, m_rz);
410 m_data_2 = detail::make_mfs_share(m_ry, m_cz);
412 m_data_1 = detail::make_mfs_share(m_rx, m_rz);
413 m_data_2 = detail::make_mfs_share(m_ry, m_cz);
420#if (AMREX_SPACEDIM >= 2)
421 if (!m_cy.
empty() || !m_ry.empty()) {
422 if (! m_cx.
empty()) {
424 m_cmd_cx2cy = std::make_unique<MultiBlockCommMetaData>
425 (m_cy, m_dom_cy, m_cx,
IntVect(0), m_dtos_x2y);
426 m_cmd_cy2cx = std::make_unique<MultiBlockCommMetaData>
427 (m_cx, m_dom_cx, m_cy,
IntVect(0), m_dtos_y2x);
430 m_cmd_rx2ry = std::make_unique<MultiBlockCommMetaData>
431 (m_ry, m_dom_ry, m_rx,
IntVect(0), m_dtos_x2y);
432 m_cmd_ry2rx = std::make_unique<MultiBlockCommMetaData>
433 (m_rx, m_dom_rx, m_ry,
IntVect(0), m_dtos_y2x);
438#if (AMREX_SPACEDIM == 3)
439 if (!m_cz.
empty() || !m_rz.empty()) {
440 if (! m_cy.
empty()) {
442 m_cmd_cy2cz = std::make_unique<MultiBlockCommMetaData>
443 (m_cz, m_dom_cz, m_cy,
IntVect(0), m_dtos_y2z);
444 m_cmd_cz2cy = std::make_unique<MultiBlockCommMetaData>
445 (m_cy, m_dom_cy, m_cz,
IntVect(0), m_dtos_z2y);
448 m_cmd_ry2rz = std::make_unique<MultiBlockCommMetaData>
449 (m_rz, m_dom_rz, m_ry,
IntVect(0), m_dtos_y2z);
450 m_cmd_rz2ry = std::make_unique<MultiBlockCommMetaData>
451 (m_ry, m_dom_ry, m_rz,
IntVect(0), m_dtos_z2y);
462 if (myproc < m_rx.size())
464 Box const& box = m_rx.box(myproc);
465 auto* pf = m_rx[myproc].dataPtr();
467 auto* pb = (VendorComplex*) m_cx[myproc].dataPtr();
468 m_fft_fwd_x.template init_r2c<Direction::forward>(box, pf, pb);
469#if defined(AMREX_USE_SYCL)
470 m_fft_bwd_x = m_fft_fwd_x;
472 m_fft_bwd_x.template init_r2c<Direction::backward>(box, pf, pb);
475 m_fft_fwd_x.template init_r2r<Direction::forward>(box, pf, bc[0]);
476#if defined(AMREX_USE_GPU)
479 m_fft_bwd_x = m_fft_fwd_x;
483 m_fft_bwd_x.template init_r2r<Direction::backward>(box, pf, bc[0]);
488#if (AMREX_SPACEDIM >= 2)
490 if (myproc < m_cy.
size()) {
491 Box const& box = m_cy.
box(myproc);
492 auto* p = (VendorComplex *)m_cy[myproc].dataPtr();
493 m_fft_fwd_y.template init_c2c<Direction::forward>(box, p);
494#if defined(AMREX_USE_SYCL)
495 m_fft_bwd_y = m_fft_fwd_y;
497 m_fft_bwd_y.template init_c2c<Direction::backward>(box, p);
501 if (myproc < m_ry.size()) {
502 Box const& box = m_ry.box(myproc);
503 auto* pr = m_ry[myproc].dataPtr();
504 auto* pc = (VendorComplex*)m_cy[myproc].dataPtr();
505 m_fft_fwd_y.template init_r2c<Direction::forward>(box, pr, pc);
506#if defined(AMREX_USE_SYCL)
507 m_fft_bwd_y = m_fft_fwd_y;
509 m_fft_bwd_y.template init_r2c<Direction::backward>(box, pr, pc);
512 }
else if (!m_cy.
empty()) {
513 if (myproc < m_cy.
size()) {
514 Box const& box = m_cy.
box(myproc);
515 auto* p = (VendorComplex*) m_cy[myproc].dataPtr();
516 m_fft_fwd_y.template init_r2r<Direction::forward>(box, p, bc[1]);
517#if defined(AMREX_USE_GPU)
520 m_fft_bwd_y = m_fft_fwd_y;
524 m_fft_bwd_y.template init_r2r<Direction::backward>(box, p, bc[1]);
528 if (myproc < m_ry.size()) {
529 Box const& box = m_ry.box(myproc);
530 auto* p = m_ry[myproc].dataPtr();
531 m_fft_fwd_y.template init_r2r<Direction::forward>(box, p, bc[1]);
532#if defined(AMREX_USE_GPU)
535 m_fft_bwd_y = m_fft_fwd_y;
539 m_fft_bwd_y.template init_r2r<Direction::backward>(box, p, bc[1]);
545#if (AMREX_SPACEDIM == 3)
547 if (myproc < m_cz.
size()) {
548 Box const& box = m_cz.
box(myproc);
549 auto* p = (VendorComplex*)m_cz[myproc].dataPtr();
550 m_fft_fwd_z.template init_c2c<Direction::forward>(box, p);
551#if defined(AMREX_USE_SYCL)
552 m_fft_bwd_z = m_fft_fwd_z;
554 m_fft_bwd_z.template init_c2c<Direction::backward>(box, p);
558 if (myproc < m_rz.size()) {
559 Box const& box = m_rz.box(myproc);
560 auto* pr = m_rz[myproc].dataPtr();
561 auto* pc = (VendorComplex*)m_cz[myproc].dataPtr();
562 m_fft_fwd_z.template init_r2c<Direction::forward>(box, pr, pc);
563#if defined(AMREX_USE_SYCL)
564 m_fft_bwd_z = m_fft_fwd_z;
566 m_fft_bwd_z.template init_r2c<Direction::backward>(box, pr, pc);
569 }
else if (!m_cz.
empty()) {
570 if (myproc < m_cz.
size()) {
571 Box const& box = m_cz.
box(myproc);
572 auto* p = (VendorComplex*) m_cz[myproc].dataPtr();
573 m_fft_fwd_z.template init_r2r<Direction::forward>(box, p, bc[2]);
574#if defined(AMREX_USE_GPU)
577 m_fft_bwd_z = m_fft_fwd_z;
581 m_fft_bwd_z.template init_r2r<Direction::backward>(box, p, bc[2]);
585 if (myproc < m_rz.size()) {
586 Box const& box = m_rz.box(myproc);
587 auto* p = m_rz[myproc].dataPtr();
588 m_fft_fwd_z.template init_r2r<Direction::forward>(box, p, bc[2]);
589#if defined(AMREX_USE_GPU)
592 m_fft_bwd_z = m_fft_fwd_z;
596 m_fft_bwd_z.template init_r2r<Direction::backward>(box, p, bc[2]);
606 if (m_fft_bwd_x.plan != m_fft_fwd_x.plan) {
607 m_fft_bwd_x.destroy();
609 if (m_fft_bwd_y.plan != m_fft_fwd_y.plan) {
610 m_fft_bwd_y.destroy();
612 if (m_fft_bwd_z.plan != m_fft_fwd_z.plan) {
613 m_fft_bwd_z.destroy();
615 m_fft_fwd_x.destroy();
616 m_fft_fwd_y.destroy();
617 m_fft_fwd_z.destroy();
624 int ndims = m_info.twod_mode ? AMREX_SPACEDIM-1 : AMREX_SPACEDIM;
625#if (AMREX_SPACEDIM == 3)
626 if (m_info.twod_mode && m_dom_0.length(2) == 1) { ndims = 1; };
628 for (
int idim = 0; idim < ndims; ++idim) {
629 r *= m_dom_0.length(idim);
641 forwardThenBackward_doit_0(inmf, outmf, post_forward);
647 F const& post_forward,
654 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
655 MF inmf_sub, inmf_tmp;
657 inmf_sub = m_sub_helper.make_alias_mf(inmf);
659 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
660 inmf_tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
661 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
664 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
665 MF outmf_sub, outmf_tmp;
667 outmf_sub = m_sub_helper.make_alias_mf(outmf);
669 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
670 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), 1, ngtmp);
671 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
674 IntVect const& subngout = m_sub_helper.make_iv(ngout);
675 Periodicity const& subperiod = m_sub_helper.make_periodicity(period);
677 m_r2x_sub->forwardThenBackward_doit_1
678 (inmf_sub, outmf_sub,
682 post_forward(idx[order[0]], idx[order[1]], idx[order[2]], sp);
684 subngout, subperiod);
687 outmf.LocalCopy(outmf_tmp, 0, 0, 1, outmf_tmp.nGrowVect());
692 this->forwardThenBackward_doit_1(inmf, outmf, post_forward, ngout, period);
699 F const& post_forward,
706 amrex::Abort(
"R2X::forwardThenBackward_doit_1: How did this happen?");
714 int actual_dim = AMREX_SPACEDIM;
715#if (AMREX_SPACEDIM >= 2)
716 if (m_dom_0.length(1) == 1) { actual_dim = 1; }
718#if (AMREX_SPACEDIM == 3)
719 if ((m_dom_0.length(2) == 1) && (m_dom_0.length(1) > 1)) { actual_dim = 2; }
722 if (actual_dim == 1) {
724 post_forward_doit<0>(detail::get_fab(m_rx), post_forward);
726 post_forward_doit<0>(detail::get_fab(m_cx), post_forward);
729#if (AMREX_SPACEDIM >= 2)
730 else if (actual_dim == 2) {
732 post_forward_doit<1>(detail::get_fab(m_ry), post_forward);
734 post_forward_doit<1>(detail::get_fab(m_cy), post_forward);
738#if (AMREX_SPACEDIM == 3)
739 else if (actual_dim == 3) {
741 post_forward_doit<2>(detail::get_fab(m_rz), post_forward);
743 post_forward_doit<2>(detail::get_fab(m_cz), post_forward);
750 outmf.ParallelCopy(m_rx, 0, 0, 1,
IntVect(0),
761 if (m_sub_helper.ghost_safe(inmf.nGrowVect())) {
762 m_r2x_sub->forward(m_sub_helper.make_alias_mf(inmf));
764 MF tmp(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
765 tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
766 m_r2x_sub->forward(m_sub_helper.make_alias_mf(tmp));
771 m_rx.ParallelCopy(inmf, 0, 0, 1);
773 m_fft_fwd_x.template compute_r2c<Direction::forward>();
775 m_fft_fwd_x.template compute_r2r<Direction::forward>();
778#if (AMREX_SPACEDIM >= 2)
780 ParallelCopy(m_cy, m_cx, *m_cmd_cx2cy, 0, 0, 1, m_dtos_x2y);
781 }
else if ( m_cmd_rx2ry) {
782 ParallelCopy(m_ry, m_rx, *m_cmd_rx2ry, 0, 0, 1, m_dtos_x2y);
786 m_fft_fwd_y.template compute_r2r<Direction::forward>();
790 m_fft_fwd_y.template compute_c2c<Direction::forward>();
794 m_fft_fwd_y.template compute_r2c<Direction::forward>();
798#if (AMREX_SPACEDIM == 3)
800 ParallelCopy(m_cz, m_cy, *m_cmd_cy2cz, 0, 0, 1, m_dtos_y2z);
801 }
else if ( m_cmd_ry2rz) {
802 ParallelCopy(m_rz, m_ry, *m_cmd_ry2rz, 0, 0, 1, m_dtos_y2z);
806 m_fft_fwd_z.template compute_r2r<Direction::forward>();
811 m_fft_fwd_z.template compute_c2c<Direction::forward>();
815 m_fft_fwd_z.template compute_r2c<Direction::forward>();
821void R2X<T>::forward (MF
const& inmf, MF& outmf)
825 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
826 MF inmf_sub, inmf_tmp;
828 inmf_sub = m_sub_helper.make_alias_mf(inmf);
830 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
831 inmf_tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
832 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
835 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
836 MF outmf_sub, outmf_tmp;
838 outmf_sub = m_sub_helper.make_alias_mf(outmf);
840 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), 1, 0);
841 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
844 m_r2x_sub->forward(inmf_sub, outmf_sub);
847 outmf.LocalCopy(outmf_tmp, 0, 0, 1,
IntVect(0));
854#if (AMREX_SPACEDIM == 3)
855 if (m_info.twod_mode) {
856 if (m_cy.empty() && !m_ry.empty()) {
858 }
else if (m_ry.empty() && m_cy.empty() && m_cx.empty()) {
859 outmf.ParallelCopy(m_rx, 0, 0, 1);
861 amrex::Abort(
"R2X::forward(MF,MF): How did this happen?");
873void R2X<T>::forward (MF
const& inmf, cMF& outmf)
877 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
878 MF inmf_sub, inmf_tmp;
880 inmf_sub = m_sub_helper.make_alias_mf(inmf);
882 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
883 inmf_tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
884 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
887 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
888 cMF outmf_sub, outmf_tmp;
890 outmf_sub = m_sub_helper.make_alias_mf(outmf);
892 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), 1, 0);
893 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
896 m_r2x_sub->forward(inmf_sub, outmf_sub);
899 outmf.LocalCopy(outmf_tmp, 0, 0, 1,
IntVect(0));
906#if (AMREX_SPACEDIM == 3)
907 if (m_info.twod_mode) {
909 auto lo = m_dom_cy.smallEnd();
910 auto hi = m_dom_cy.bigEnd();
911 std::swap(lo[0],lo[1]);
912 std::swap(hi[0],hi[1]);
915 }
else if (m_ry.empty() && m_cy.empty() && !m_cx.empty()) {
916 outmf.ParallelCopy(m_cx, 0, 0, 1);
918 amrex::Abort(
"R2X::forward(MF,cMF): How did this happen?");
930void R2X<T>::backward ()
936#if (AMREX_SPACEDIM == 3)
939 m_fft_bwd_z.template compute_r2r<Direction::backward>();
944 m_fft_bwd_z.template compute_c2c<Direction::backward>();
948 m_fft_bwd_z.template compute_r2c<Direction::backward>();
951 ParallelCopy(m_cy, m_cz, *m_cmd_cz2cy, 0, 0, 1, m_dtos_z2y);
952 }
else if ( m_cmd_rz2ry) {
953 ParallelCopy(m_ry, m_rz, *m_cmd_rz2ry, 0, 0, 1, m_dtos_z2y);
957#if (AMREX_SPACEDIM >= 2)
960 m_fft_bwd_y.template compute_r2r<Direction::backward>();
964 m_fft_bwd_y.template compute_c2c<Direction::backward>();
968 m_fft_bwd_y.template compute_r2c<Direction::backward>();
971 ParallelCopy(m_cx, m_cy, *m_cmd_cy2cx, 0, 0, 1, m_dtos_y2x);
972 }
else if ( m_cmd_ry2rx) {
973 ParallelCopy(m_rx, m_ry, *m_cmd_ry2rx, 0, 0, 1, m_dtos_y2x);
978 m_fft_bwd_x.template compute_r2c<Direction::backward>();
980 m_fft_bwd_x.template compute_r2r<Direction::backward>();
985void R2X<T>::backward (MF
const& inmf, MF& outmf,
IntVect const& ngout,
986 Periodicity
const& period)
990 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
991 MF inmf_sub, inmf_tmp;
993 inmf_sub = m_sub_helper.make_alias_mf(inmf);
995 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
996 inmf_tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
997 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1000 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1001 MF outmf_sub, outmf_tmp;
1003 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1005 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
1006 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), 1, ngtmp);
1007 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1010 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1011 Periodicity
const& subperiod = m_sub_helper.make_periodicity(period);
1012 m_r2x_sub->backward(inmf_sub, outmf_sub, subngout, subperiod);
1015 outmf.LocalCopy(outmf_tmp, 0, 0, 1, outmf_tmp.nGrowVect());
1020#if (AMREX_SPACEDIM == 3)
1021 if (m_info.twod_mode) {
1022 if (m_cy.empty() && !m_ry.empty()) {
1024 }
else if (m_ry.empty() && m_cy.empty() && m_cx.empty()) {
1025 m_rx.ParallelCopy(inmf, 0, 0, 1);
1027 amrex::Abort(
"R2X::backward(MF,MF): How did this happen?");
1038 outmf.ParallelCopy(m_rx, 0, 0, 1,
IntVect(0),
1043template <
typename T>
1044void R2X<T>::backward (cMF
const& inmf, MF& outmf,
IntVect const& ngout,
1045 Periodicity
const& period)
1049 bool inmf_safe = m_sub_helper.ghost_safe(inmf.nGrowVect());
1050 cMF inmf_sub, inmf_tmp;
1052 inmf_sub = m_sub_helper.make_alias_mf(inmf);
1054 inmf_tmp.define(inmf.boxArray(), inmf.DistributionMap(), 1, 0);
1055 inmf_tmp.LocalCopy(inmf, 0, 0, 1,
IntVect(0));
1056 inmf_sub = m_sub_helper.make_alias_mf(inmf_tmp);
1059 bool outmf_safe = m_sub_helper.ghost_safe(outmf.nGrowVect());
1060 MF outmf_sub, outmf_tmp;
1062 outmf_sub = m_sub_helper.make_alias_mf(outmf);
1064 IntVect const& ngtmp = m_sub_helper.make_safe_ghost(outmf.nGrowVect());
1065 outmf_tmp.define(outmf.boxArray(), outmf.DistributionMap(), 1, ngtmp);
1066 outmf_sub = m_sub_helper.make_alias_mf(outmf_tmp);
1069 IntVect const& subngout = m_sub_helper.make_iv(ngout);
1070 Periodicity
const& subperiod = m_sub_helper.make_periodicity(period);
1071 m_r2x_sub->backward(inmf_sub, outmf_sub, subngout, subperiod);
1074 outmf.LocalCopy(outmf_tmp, 0, 0, 1, outmf_tmp.nGrowVect());
1079#if (AMREX_SPACEDIM == 3)
1080 if (m_info.twod_mode) {
1081 if (!m_cy.empty()) {
1083 }
else if (m_ry.empty() && m_cy.empty() && !m_cx.empty()) {
1084 m_cx.ParallelCopy(inmf, 0, 0, 1);
1086 amrex::Abort(
"R2X::backward(cMF,MF): How did this happen?");
1097 outmf.ParallelCopy(m_rx, 0, 0, 1,
IntVect(0),
1102template <
typename T>
1103template <
int dim,
typename FAB,
typename F>
1106 if (m_info.twod_mode) {
1110 auto const& a = fab->array();
1114 if constexpr (dim == 0) {
1116 }
else if constexpr (dim == 1) {