Repository: AMReX-Codes/amrex — pull request #2475 (cpp)
Title: CI: Run 2D and 1D Tests

## Summary

Run tests also for 2D and 1D builds of AMReX.

## Additional background

Related to 2D issues with `DenseBin` in WarpX: https://github.com/ECP-WarpX/WarpX/pull/2550

## Checklist

The proposed changes:
- [x] fix a bug or incorrect behavior in AMReX
- [x] add new capabilities to AMReX
- [ ] changes answers in the test suite to more than roundoff level
- [ ] are likely to significantly affect the results of downstream AMReX users
- [ ] include documentation in the code and/or rst files, if appropriate


Resolved issues:
title: Physical Boundary Conditions - Fortran
body: I cannot find any example fortran code that uses the amrex_physbc fortran interface to supply boundary conditions.  The current examples in Tuturials/*_CF use periodic bcs.  I did notice that in some of the _C tutorials, an f77 file was present which provided a `filcc` routine.  To impose boundary conditions, should I customize the filcc routines or is there a better way utilizing amrex_physbc?

Hints:

Fix patch:
diff --git a/.github/workflows/gcc.yml b/.github/workflows/gcc.yml
index 9ea1ca69516..244b8192a76 100644
--- a/.github/workflows/gcc.yml
+++ b/.github/workflows/gcc.yml
@@ -40,8 +40,8 @@ jobs:
         ctest --output-on-failure
 
   # Build libamrex and all tests
-  tests_build:
-    name: GNU@7.5 C++14 Debug Fortran [tests]
+  tests_build_3D:
+    name: GNU@7.5 C++14 3D Debug Fortran [tests]
     runs-on: ubuntu-18.04
     env: {CXXFLAGS: "-fno-operator-names -Werror -Wall -Wextra -Wpedantic -Wnull-dereference -Wfloat-conversion -Wshadow -Woverloaded-virtual -O1"}
       # It's too slow with -O0
@@ -51,18 +51,65 @@ jobs:
       run: .github/workflows/dependencies/dependencies.sh
     - name: Build & Install
       run: |
-        mkdir build
-        cd build
-        cmake ..                        \
+        cmake -S . -B build             \
             -DCMAKE_BUILD_TYPE=Debug    \
             -DCMAKE_VERBOSE_MAKEFILE=ON \
             -DAMReX_EB=ON               \
             -DAMReX_ENABLE_TESTS=ON     \
             -DAMReX_FORTRAN=ON          \
-            -DAMReX_PARTICLES=ON
-        make -j 2
+            -DAMReX_PARTICLES=ON        \
+            -DAMReX_SPACEDIM=3
+        cmake --build build -j 2
 
-        ctest --output-on-failure
+        ctest --test-dir build --output-on-failure
+
+  tests_build_2D:
+    name: GNU@7.5 C++14 2D Debug Fortran [tests]
+    runs-on: ubuntu-18.04
+    env: {CXXFLAGS: "-fno-operator-names -Wall -Wextra -Wpedantic -Wnull-dereference -Wfloat-conversion -Wshadow -Woverloaded-virtual -O1"}
+      # -Werror temporarily skipped until we have functional testing established
+      # It's too slow with -O0
+    steps:
+    - uses: actions/checkout@v2
+    - name: Dependencies
+      run: .github/workflows/dependencies/dependencies.sh
+    - name: Build & Install
+      run: |
+        cmake -S . -B build             \
+            -DCMAKE_BUILD_TYPE=Debug    \
+            -DCMAKE_VERBOSE_MAKEFILE=ON \
+            -DAMReX_EB=ON               \
+            -DAMReX_ENABLE_TESTS=ON     \
+            -DAMReX_FORTRAN=ON          \
+            -DAMReX_PARTICLES=ON        \
+            -DAMReX_SPACEDIM=2
+        cmake --build build -j 2
+
+        ctest --test-dir build --output-on-failure
+
+  tests_build_1D:
+    name: GNU@7.5 C++14 1D Debug Fortran [tests]
+    runs-on: ubuntu-18.04
+    env: {CXXFLAGS: "-fno-operator-names -Wall -Wextra -Wpedantic -Wnull-dereference -Wfloat-conversion -Wshadow -Woverloaded-virtual -O1"}
+      # -Werror temporarily skipped until we have functional testing established
+      # It's too slow with -O0
+    steps:
+    - uses: actions/checkout@v2
+    - name: Dependencies
+      run: .github/workflows/dependencies/dependencies.sh
+    - name: Build & Install
+      run: |
+        cmake -S . -B build             \
+            -DCMAKE_BUILD_TYPE=Debug    \
+            -DCMAKE_VERBOSE_MAKEFILE=ON \
+            -DAMReX_EB=ON               \
+            -DAMReX_ENABLE_TESTS=ON     \
+            -DAMReX_FORTRAN=ON          \
+            -DAMReX_PARTICLES=ON        \
+            -DAMReX_SPACEDIM=1
+        cmake --build build -j 2
+
+        ctest --test-dir build --output-on-failure
 
   # Build libamrex and all tests
   tests_cxx20:
diff --git a/Src/Particle/AMReX_ParticleInterpolators.H b/Src/Particle/AMReX_ParticleInterpolators.H
new file mode 100644
index 00000000000..f241ac3ff1e
--- /dev/null
+++ b/Src/Particle/AMReX_ParticleInterpolators.H
@@ -0,0 +1,127 @@
+#ifndef AMREX_PARTICLEINTERPOLATORS_H_
+#define AMREX_PARTICLEINTERPOLATORS_H_
+#include <AMReX_Config.H>
+
+#include <AMReX_IntVect.H>
+#include <AMReX_Gpu.H>
+#include <AMReX_Print.H>
+
+namespace amrex
+{
+namespace ParticleInterpolator
+{
+
+template <class Derived, class WeightType>
+struct Base
+{
+    int index[3];
+    WeightType* w;
+
+    template <typename P, typename V, typename F>
+    AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+    void ParticleToMesh (const P& p,
+                         amrex::Array4<V> const& arr,
+                         int src_comp, int dst_comp, int num_comps, F&& f)
+    {
+        static constexpr int stencil_width = Derived::stencil_width;
+        for (int ic=0; ic < num_comps; ++ic) {
+            for (int kk = 0; kk <= Derived::nz; ++kk) {
+                for (int jj = 0; jj <= Derived::ny; ++jj) {
+                    for (int ii = 0; ii <= Derived::nx; ++ii) {
+                        const auto pval = f(p, src_comp+ic);
+                        const auto val = w[0*stencil_width+ii] *
+                                         w[1*stencil_width+jj] *
+                                         w[2*stencil_width+kk] * pval;
+                        Gpu::Atomic::AddNoRet(&arr(index[0]+ii, index[1]+jj, index[2]+kk, ic+dst_comp), val);
+                    }
+                }
+            }
+        }
+    }
+
+    template <typename P, typename V, typename F, typename G>
+    AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+    void MeshToParticle (P& p,
+                         amrex::Array4<const V> const& arr,
+                         int src_comp, int dst_comp, int num_comps, F&& f, G&& g)
+    {
+        static constexpr int stencil_width = Derived::stencil_width;
+        for (int ic=0; ic < num_comps; ++ic) {
+            for (int kk = 0; kk <= Derived::nz; ++kk) {
+                for (int jj = 0; jj <= Derived::ny; ++jj) {
+                    for (int ii = 0; ii <= Derived::nx; ++ii) {
+                        const auto mval = f(arr,index[0]+ii,index[1]+jj,index[2]+kk,src_comp+ic);
+                        const auto val = w[0*stencil_width+ii] *
+                                         w[1*stencil_width+jj] *
+                                         w[2*stencil_width+kk] * mval;
+                        g(p, ic + dst_comp, val);
+                    }
+                }
+            }
+        }
+    }
+};
+
+struct Nearest : public Base<Nearest, int>
+{
+    static constexpr int stencil_width = 1;
+    int weights[3*stencil_width];
+
+    static constexpr int nx = (AMREX_SPACEDIM >= 1) ? stencil_width - 1 : 0;
+    static constexpr int ny = (AMREX_SPACEDIM >= 2) ? stencil_width - 1 : 0;
+    static constexpr int nz = (AMREX_SPACEDIM >= 3) ? stencil_width - 1 : 0;
+
+    template <typename P>
+    AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+    Nearest (const P& p,
+             amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
+             amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& dxi)
+    {
+        w = &weights[0];
+        for (int i = 0; i < AMREX_SPACEDIM; ++i) {
+            amrex::Real l = (p.pos(i) - plo[i]) * dxi[i] + 0.5;
+            index[i] = static_cast<int>(amrex::Math::floor(l));
+            w[i] = 1;
+        }
+        for (int i = AMREX_SPACEDIM; i < 3; ++i) {
+            index[i] = 0;
+            w[i] = 1;
+        }
+    }
+};
+
+struct Linear : public Base<Linear, amrex::Real>
+{
+    static constexpr int stencil_width = 2;
+
+    static constexpr int nx = (AMREX_SPACEDIM >= 1) ? stencil_width - 1 : 0;
+    static constexpr int ny = (AMREX_SPACEDIM >= 2) ? stencil_width - 1 : 0;
+    static constexpr int nz = (AMREX_SPACEDIM >= 3) ? stencil_width - 1 : 0;
+
+    amrex::Real weights[3*stencil_width];
+
+    template <typename P>
+    AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+    Linear (const P& p,
+            amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
+            amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& dxi)
+    {
+        w = &weights[0];
+        for (int i = 0; i < AMREX_SPACEDIM; ++i) {
+            amrex::Real l = (p.pos(i) - plo[i]) * dxi[i] + 0.5;
+            index[i] = static_cast<int>(amrex::Math::floor(l)) - 1;
+            amrex::Real lint = l - (index[i] + 1);
+            w[stencil_width*i + 0] = 1.-lint;
+            w[stencil_width*i + 1] = lint;
+        }
+        for (int i = AMREX_SPACEDIM; i < 3; ++i) {
+            index[i] = 0;
+            w[stencil_width*i + 0] = 1.;
+            w[stencil_width*i + 1] = 0.;
+        }
+    }
+};
+}
+}
+
+#endif // include guard
diff --git a/Src/Particle/CMakeLists.txt b/Src/Particle/CMakeLists.txt
index 7b0efb39d4e..980fdb178ab 100644
--- a/Src/Particle/CMakeLists.txt
+++ b/Src/Particle/CMakeLists.txt
@@ -34,6 +34,7 @@ target_sources( amrex
    AMReX_ParticleBufferMap.cpp
    AMReX_ParticleCommunication.H
    AMReX_ParticleCommunication.cpp
+   AMReX_ParticleInterpolators.H
    AMReX_ParticleReduce.H
    AMReX_ParticleMesh.H
    AMReX_ParticleLocator.H
diff --git a/Src/Particle/Make.package b/Src/Particle/Make.package
index f693b923492..efb65679118 100644
--- a/Src/Particle/Make.package
+++ b/Src/Particle/Make.package
@@ -14,6 +14,7 @@ C$(AMREX_PARTICLE)_headers += AMReX_WriteBinaryParticleData.H
 C$(AMREX_PARTICLE)_headers += AMReX_ParticleContainerBase.H
 C$(AMREX_PARTICLE)_sources += AMReX_ParticleContainerBase.cpp
 C$(AMREX_PARTICLE)_headers += AMReX_ParticleArray.H
+C$(AMREX_PARTICLE)_headers += AMReX_ParticleInterpolators.H
 
 VPATH_LOCATIONS += $(AMREX_HOME)/Src/Particle
 INCLUDE_LOCATIONS += $(AMREX_HOME)/Src/Particle


Test patch:
diff --git a/Tests/AsyncOut/multifab/main.cpp b/Tests/AsyncOut/multifab/main.cpp
index b9b30f297de..d1331d85862 100644
--- a/Tests/AsyncOut/multifab/main.cpp
+++ b/Tests/AsyncOut/multifab/main.cpp
@@ -53,8 +53,12 @@ void main_main ()
         else if (n_boxes_per_rank != 0)
         {
            n_cell_3d[0] = (max_grid_size) - 1;
+#if AMREX_SPACEDIM >= 2
            n_cell_3d[1] = (max_grid_size * n_boxes_per_rank) - 1;
+#endif
+#if AMREX_SPACEDIM == 3
            n_cell_3d[2] = (max_grid_size * ParallelDescriptor::NProcs()) - 1;
+#endif
         }
     }
 
diff --git a/Tests/LinearSolvers/NodalPoisson/CMakeLists.txt b/Tests/LinearSolvers/NodalPoisson/CMakeLists.txt
index f4dadd89154..58b88bfea00 100644
--- a/Tests/LinearSolvers/NodalPoisson/CMakeLists.txt
+++ b/Tests/LinearSolvers/NodalPoisson/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(AMReX_SPACEDIM EQUAL 1)
+   return()
+endif()
+
 set(_sources main.cpp MyTest.cpp MyTest.H MyTestPlotfile.cpp)
 
 set(_input_files inputs-ci)
diff --git a/Tests/MultiBlock/Advection/CMakeLists.txt b/Tests/MultiBlock/Advection/CMakeLists.txt
index ac043eefd8d..cc4890639be 100644
--- a/Tests/MultiBlock/Advection/CMakeLists.txt
+++ b/Tests/MultiBlock/Advection/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(AMReX_SPACEDIM EQUAL 1)
+   return()
+endif()
+
 set(_sources     main.cpp)
 set(_input_files )
 
diff --git a/Tests/MultiBlock/Advection/main.cpp b/Tests/MultiBlock/Advection/main.cpp
index c9167a69545..8b5555b2c75 100644
--- a/Tests/MultiBlock/Advection/main.cpp
+++ b/Tests/MultiBlock/Advection/main.cpp
@@ -87,7 +87,9 @@ class AdvectionAmrCore : public AmrCore {
                                 next(i, j, k, n) = m(i, j, k, n) - a_dt_over_dx * (m(i, j, k, n) - m(i - 1, j, k, n));
                             });
             }
-        } else if (dir == Direction::y) {
+        }
+#if (AMREX_SPACEDIM >= 2)
+        else if (dir == Direction::y) {
 #ifdef AMREX_USE_OMP
 #pragma omp parallel if (Gpu::notInLaunchRegion())
 #endif
@@ -100,6 +102,7 @@ class AdvectionAmrCore : public AmrCore {
                             });
             }
         }
+#endif
         std::swap(mass, mass_next);
     }
 
@@ -231,10 +234,10 @@ void MyMain() {
     RealBox real_box1{{AMREX_D_DECL(-0.5, -0.3, 0.0)}, {AMREX_D_DECL(0.5, 0.7, 1.0)}};
     RealBox real_box2{{AMREX_D_DECL(+0.55, -0.3, 0.0)}, {AMREX_D_DECL(1.55, 0.7, 1.0)}};
 
-    Array<int, AMREX_SPACEDIM> is_periodic1{0, 1};
+    Array<int, AMREX_SPACEDIM> is_periodic1{AMREX_D_DECL(0, 1, 0)};
     Geometry geom1{domain, real_box1, CoordSys::cartesian, is_periodic1};
 
-    Array<int, AMREX_SPACEDIM> is_periodic2{1, 0};
+    Array<int, AMREX_SPACEDIM> is_periodic2{AMREX_D_DECL(1, 0, 0)};
     Geometry geom2{domain, real_box2, CoordSys::cartesian, is_periodic2};
 
     AmrInfo amr_info{};
@@ -243,7 +246,11 @@ void MyMain() {
 #endif
 
     AdvectionAmrCore core_x(Direction::x, geom1, amr_info);
+#if AMREX_SPACEDIM > 2
     AdvectionAmrCore core_y(Direction::y, geom2, amr_info);
+#else // too hack-ish?
+    AdvectionAmrCore core_y(Direction::x, geom2, amr_info);
+#endif
 
     std::vector<OnesidedMultiBlockBoundaryFn> multi_block_boundaries{};
     {   // Fill right boundary of core_x with lower mirror data of core_y
diff --git a/Tests/MultiBlock/IndexType/CMakeLists.txt b/Tests/MultiBlock/IndexType/CMakeLists.txt
index ac043eefd8d..cc4890639be 100644
--- a/Tests/MultiBlock/IndexType/CMakeLists.txt
+++ b/Tests/MultiBlock/IndexType/CMakeLists.txt
@@ -1,3 +1,7 @@
+if(AMReX_SPACEDIM EQUAL 1)
+   return()
+endif()
+
 set(_sources     main.cpp)
 set(_input_files )
 
diff --git a/Tests/MultiBlock/IndexType/main.cpp b/Tests/MultiBlock/IndexType/main.cpp
index ad7a78a8cdb..39a99acbc67 100644
--- a/Tests/MultiBlock/IndexType/main.cpp
+++ b/Tests/MultiBlock/IndexType/main.cpp
@@ -135,9 +135,9 @@ int MyMain()
     Box domain{IntVect{}, IntVect{AMREX_D_DECL(31, 31, 31)}};
     // Loop over all index types
     for (int i = 0; i < AMREX_D_TERM(2,*2,*2); ++i) {
-        const auto ix = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b001));
-        const auto iy = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b010));
-        const auto iz = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b100));
+        AMREX_D_TERM(const auto ix = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b001));,
+                     const auto iy = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b010));,
+                     const auto iz = static_cast<IndexType::CellIndex>(static_cast<bool>(i & 0b100));)
         IndexType itype{AMREX_D_DECL(ix, iy, iz)};
         Box converted_domain = convert(domain, itype);
         iMultiFab mf = InitializeMultiFab(converted_domain);
diff --git a/Tests/Particles/AssignDensity/main.cpp b/Tests/Particles/AssignDensity/main.cpp
index b08693828be..4b0e6635e22 100644
--- a/Tests/Particles/AssignDensity/main.cpp
+++ b/Tests/Particles/AssignDensity/main.cpp
@@ -67,7 +67,7 @@ void test_assign_density(TestParams& parms)
 
   MyParticleContainer::ParticleInitData pdata = {{mass, AMREX_D_DECL(1.0, 2.0, 3.0)}, {}, {}, {}};
   myPC.InitRandom(num_particles, iseed, pdata, serialize);
-  myPC.AssignCellDensitySingleLevel(0, partMF, 0, 4, 0);
+  myPC.AssignCellDensitySingleLevel(0, partMF, 0, 1 + AMREX_SPACEDIM, 0);
 
   //  myPC.AssignDensitySingleLevel(0, partMF, 0, 4, 0);
 
@@ -76,7 +76,7 @@ void test_assign_density(TestParams& parms)
   MultiFab::Copy(density, partMF, 0, 0, 1, 0);
 
   WriteSingleLevelPlotfile("plt00000", partMF,
-                           {"density", "vx", "vy", "vz"},
+                           {"density", AMREX_D_DECL("vx", "vy", "vz")},
                            geom, 0.0, 0);
 
   myPC.Checkpoint("plt00000", "particle0");
diff --git a/Tests/Particles/AsyncIO/main.cpp b/Tests/Particles/AsyncIO/main.cpp
index 98b430e245d..ce484e7b773 100644
--- a/Tests/Particles/AsyncIO/main.cpp
+++ b/Tests/Particles/AsyncIO/main.cpp
@@ -238,7 +238,7 @@ void test_async_io(TestParams& parms)
     MyParticleContainer myPC(geom, dmap, ba, rr);
     myPC.SetVerbose(false);
 
-    myPC.InitParticles(IntVect(2, 2, 2));
+    myPC.InitParticles(IntVect(AMREX_D_DECL(2, 2, 2)));
 
     for (int step = 0; step < 4000; ++step)
     {
diff --git a/Tests/Particles/GhostsAndVirtuals/CMakeLists.txt b/Tests/Particles/GhostsAndVirtuals/CMakeLists.txt
index 4c24bb40f68..6cd0bc5c84d 100644
--- a/Tests/Particles/GhostsAndVirtuals/CMakeLists.txt
+++ b/Tests/Particles/GhostsAndVirtuals/CMakeLists.txt
@@ -1,3 +1,7 @@
+if ( NOT (AMReX_SPACEDIM EQUAL 3) )
+   return ()
+endif ()
+
 set(_sources     main.cpp)
 set(_input_files inputs  particle_file.init  fixed_grids.init)
 
diff --git a/Tests/Particles/InitFromAscii/CMakeLists.txt b/Tests/Particles/InitFromAscii/CMakeLists.txt
index 0615dcae5db..3f63911ef1f 100644
--- a/Tests/Particles/InitFromAscii/CMakeLists.txt
+++ b/Tests/Particles/InitFromAscii/CMakeLists.txt
@@ -1,3 +1,7 @@
+if ( NOT (AMReX_SPACEDIM EQUAL 3) )
+   return ()
+endif ()
+
 set(_sources     main.cpp)
 set(_input_files inputs  )
 
diff --git a/Tests/Particles/NeighborParticles/CheckPair.H b/Tests/Particles/NeighborParticles/CheckPair.H
index 8018e9c49e9..e51e239a167 100644
--- a/Tests/Particles/NeighborParticles/CheckPair.H
+++ b/Tests/Particles/NeighborParticles/CheckPair.H
@@ -2,6 +2,7 @@
 #define MD_K_H_
 
 #include "Constants.H"
+#include <AMReX_SPACE.H>
 
 struct CheckPair
 {
@@ -9,10 +10,10 @@ struct CheckPair
     AMREX_GPU_DEVICE AMREX_FORCE_INLINE
     bool operator()(const P& p1, const P& p2) const
     {
-        amrex::Real d0 = (p1.pos(0) - p2.pos(0));
-        amrex::Real d1 = (p1.pos(1) - p2.pos(1));
-        amrex::Real d2 = (p1.pos(2) - p2.pos(2));
-        amrex::Real dsquared = d0*d0 + d1*d1 + d2*d2;
+        AMREX_D_TERM(amrex::Real d0 = (p1.pos(0) - p2.pos(0));,
+                     amrex::Real d1 = (p1.pos(1) - p2.pos(1));,
+                     amrex::Real d2 = (p1.pos(2) - p2.pos(2));)
+        amrex::Real dsquared = AMREX_D_TERM(d0*d0, + d1*d1, + d2*d2);
         return (dsquared <= 25.0*Params::cutoff*Params::cutoff);
     }
 };
diff --git a/Tests/Particles/NeighborParticles/MDParticleContainer.cpp b/Tests/Particles/NeighborParticles/MDParticleContainer.cpp
index b275e3327ef..b934f664f4e 100644
--- a/Tests/Particles/NeighborParticles/MDParticleContainer.cpp
+++ b/Tests/Particles/NeighborParticles/MDParticleContainer.cpp
@@ -2,6 +2,7 @@
 #include "Constants.H"
 
 #include "CheckPair.H"
+#include <AMReX_SPACE.H>
 
 using namespace amrex;
 
@@ -10,16 +11,24 @@ namespace
     void get_position_unit_cell(Real* r, const IntVect& nppc, int i_part)
     {
         int nx = nppc[0];
+#if AMREX_SPACEDIM >= 2
         int ny = nppc[1];
+#else
+        int ny = 1;
+#endif
+#if AMREX_SPACEDIM == 3
         int nz = nppc[2];
+#else
+        int nz = 1;
+#endif
 
-        int ix_part = i_part/(ny * nz);
-        int iy_part = (i_part % (ny * nz)) % ny;
-        int iz_part = (i_part % (ny * nz)) / ny;
+        AMREX_D_TERM(int ix_part = i_part/(ny * nz);,
+                     int iy_part = (i_part % (ny * nz)) % ny;,
+                     int iz_part = (i_part % (ny * nz)) / ny;)
 
-        r[0] = (0.5+ix_part)/nx;
-        r[1] = (0.5+iy_part)/ny;
-        r[2] = (0.5+iz_part)/nz;
+        AMREX_D_TERM(r[0] = (0.5+ix_part)/nx;,
+                     r[1] = (0.5+iy_part)/ny;,
+                     r[2] = (0.5+iz_part)/nz;)
     }
 
     void get_gaussian_random_momentum(Real* u, Real u_mean, Real u_std) {
@@ -61,7 +70,7 @@ InitParticles(const IntVect& a_num_particles_per_cell,
 
         for (IntVect iv = tile_box.smallEnd(); iv <= tile_box.bigEnd(); tile_box.next(iv)) {
             for (int i_part=0; i_part<num_ppc;i_part++) {
-                Real r[3];
+                Real r[AMREX_SPACEDIM];
                 Real v[3];
 
                 get_position_unit_cell(r, a_num_particles_per_cell, i_part);
@@ -69,16 +78,16 @@ InitParticles(const IntVect& a_num_particles_per_cell,
                 get_gaussian_random_momentum(v, a_thermal_momentum_mean,
                                              a_thermal_momentum_std);
 
-                ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);
-                ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);
-                ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);
+                AMREX_D_TERM(ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);,
+                             ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);,
+                             ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);)
 
                 ParticleType p;
                 p.id()  = ParticleType::NextID();
                 p.cpu() = ParallelDescriptor::MyProc();
-                p.pos(0) = x;
-                p.pos(1) = y;
-                p.pos(2) = z;
+                AMREX_D_TERM(p.pos(0) = x;,
+                             p.pos(1) = y;,
+                             p.pos(2) = z;)
 
                 p.rdata(PIdx::vx) = static_cast<ParticleReal> (v[0]);
                 p.rdata(PIdx::vy) = static_cast<ParticleReal> (v[1]);
@@ -165,11 +174,11 @@ std::pair<Real, Real> MDParticleContainer::minAndMaxDistance()
 
             for (const auto& p2 : nbor_data.getNeighbors(i))
             {
-                Real dx = p1.pos(0) - p2.pos(0);
-                Real dy = p1.pos(1) - p2.pos(1);
-                Real dz = p1.pos(2) - p2.pos(2);
+                AMREX_D_TERM(Real dx = p1.pos(0) - p2.pos(0);,
+                             Real dy = p1.pos(1) - p2.pos(1);,
+                             Real dz = p1.pos(2) - p2.pos(2);)
 
-                Real r2 = dx*dx + dy*dy + dz*dz;
+                Real r2 = AMREX_D_TERM(dx*dx, + dy*dy, + dz*dz);
                 r2 = amrex::max(r2, Params::min_r*Params::min_r);
                 Real r = sqrt(r2);
 
@@ -211,9 +220,9 @@ void MDParticleContainer::moveParticles(amrex::ParticleReal dx)
         AMREX_FOR_1D ( np, i,
         {
             ParticleType& p = pstruct[i];
-            p.pos(0) += dx;
-            p.pos(1) += dx;
-            p.pos(2) += dx;
+            AMREX_D_TERM(p.pos(0) += dx;,
+                         p.pos(1) += dx;,
+                         p.pos(2) += dx;)
         });
     }
 }
@@ -314,11 +323,11 @@ void MDParticleContainer::checkNeighborList()
                 if ( i == j ) continue;
 
                 ParticleType& p2 = h_pstruct[j];
-                Real dx = p1.pos(0) - p2.pos(0);
-                Real dy = p1.pos(1) - p2.pos(1);
-                Real dz = p1.pos(2) - p2.pos(2);
+                AMREX_D_TERM(Real dx = p1.pos(0) - p2.pos(0);,
+                             Real dy = p1.pos(1) - p2.pos(1);,
+                             Real dz = p1.pos(2) - p2.pos(2);)
 
-                Real r2 = dx*dx + dy*dy + dz*dz;
+                Real r2 = AMREX_D_TERM(dx*dx, + dy*dy, + dz*dz);
 
                 Real cutoff_sq = 25.0*Params::cutoff*Params::cutoff;
 
diff --git a/Tests/Particles/ParallelContext/main.cpp b/Tests/Particles/ParallelContext/main.cpp
index a23b9195771..311c39a3bab 100644
--- a/Tests/Particles/ParallelContext/main.cpp
+++ b/Tests/Particles/ParallelContext/main.cpp
@@ -15,25 +15,25 @@ int num_runtime_int = 0;
 
 void get_position_unit_cell(Real* r, const IntVect& nppc, int i_part)
 {
-    int nx = nppc[0];
-#if AMREX_SPACEDIM > 1
-    int ny = nppc[1];
+        int nx = nppc[0];
+#if AMREX_SPACEDIM >= 2
+        int ny = nppc[1];
 #else
-    int ny = 1;
+        int ny = 1;
 #endif
-#if AMREX_SPACEDIM > 2
-    int nz = nppc[2];
+#if AMREX_SPACEDIM == 3
+        int nz = nppc[2];
 #else
-    int nz = 1;
+        int nz = 1;
 #endif
 
-    int ix_part = i_part/(ny * nz);
-    int iy_part = (i_part % (ny * nz)) % ny;
-    int iz_part = (i_part % (ny * nz)) / ny;
+        AMREX_D_TERM(int ix_part = i_part/(ny * nz);,
+                     int iy_part = (i_part % (ny * nz)) % ny;,
+                     int iz_part = (i_part % (ny * nz)) / ny;)
 
-    r[0] = (0.5+ix_part)/nx;
-    r[1] = (0.5+iy_part)/ny;
-    r[2] = (0.5+iz_part)/nz;
+        AMREX_D_TERM(r[0] = (0.5+ix_part)/nx;,
+                     r[1] = (0.5+iy_part)/ny;,
+                     r[2] = (0.5+iz_part)/nz;)
 }
 
 class TestParticleContainer
@@ -92,7 +92,7 @@ class TestParticleContainer
             for (IntVect iv = tile_box.smallEnd(); iv <= tile_box.bigEnd(); tile_box.next(iv))
             {
                 for (int i_part=0; i_part<num_ppc;i_part++) {
-                    Real r[3];
+                    Real r[AMREX_SPACEDIM];
                     get_position_unit_cell(r, a_num_particles_per_cell, i_part);
 
                     ParticleType p;
@@ -322,8 +322,6 @@ void testParallelContext ()
 {
     BL_PROFILE("testParallelContext");
 
-    AMREX_ALWAYS_ASSERT(AMREX_SPACEDIM == 3);
-
     // we always make two subcommunicators.
     // one takes the left half of the domain in direction 0, the other the right.
     int rank_n = ParallelContext::NProcsSub();
diff --git a/Tests/Particles/ParticleIterator/main.cpp b/Tests/Particles/ParticleIterator/main.cpp
index 0c544de7935..d635d11ab13 100644
--- a/Tests/Particles/ParticleIterator/main.cpp
+++ b/Tests/Particles/ParticleIterator/main.cpp
@@ -25,8 +25,8 @@ int main(int argc, char* argv[])
       real_box.setHi(n,1.0);
     }
 
-  IntVect domain_lo(0 , 0, 0);
-  IntVect domain_hi(ncell-1, ncell-1, ncell-1);
+  IntVect domain_lo(AMREX_D_DECL(0 , 0, 0));
+  IntVect domain_hi(AMREX_D_DECL(ncell-1, ncell-1, ncell-1));
 
   const Box domain(domain_lo, domain_hi);
 
diff --git a/Tests/Particles/ParticleMesh/main.cpp b/Tests/Particles/ParticleMesh/main.cpp
index a6fb6094ff5..3e3a3c5045a 100644
--- a/Tests/Particles/ParticleMesh/main.cpp
+++ b/Tests/Particles/ParticleMesh/main.cpp
@@ -6,6 +6,7 @@
 #include "AMReX_Particles.H"
 #include "AMReX_PlotFileUtil.H"
 #include <AMReX_ParticleMesh.H>
+#include <AMReX_ParticleInterpolators.H>
 
 using namespace amrex;
 
@@ -22,7 +23,7 @@ void testParticleMesh (TestParams& parms)
 {
 
   RealBox real_box;
-  for (int n = 0; n < BL_SPACEDIM; n++) {
+  for (int n = 0; n < AMREX_SPACEDIM; n++) {
     real_box.setLo(n, 0.0);
     real_box.setHi(n, 1.0);
   }
@@ -32,8 +33,8 @@ void testParticleMesh (TestParams& parms)
   const Box domain(domain_lo, domain_hi);
 
   // This sets the boundary conditions to be doubly or triply periodic
-  int is_per[BL_SPACEDIM];
-  for (int i = 0; i < BL_SPACEDIM; i++)
+  int is_per[AMREX_SPACEDIM];
+  for (int i = 0; i < AMREX_SPACEDIM; i++)
     is_per[i] = 1;
   Geometry geom(domain, &real_box, CoordSys::cartesian, is_per);
 
@@ -45,13 +46,13 @@ void testParticleMesh (TestParams& parms)
 
   DistributionMapping dmap(ba);
 
-  MultiFab partMF(ba, dmap, 1 + BL_SPACEDIM, 1);
+  MultiFab partMF(ba, dmap, 1 + AMREX_SPACEDIM, 1);
   partMF.setVal(0.0);
 
-  iMultiFab partiMF(ba, dmap, 1 + BL_SPACEDIM, 1);
+  iMultiFab partiMF(ba, dmap, 1 + AMREX_SPACEDIM, 1);
   partiMF.setVal(0);
 
-  typedef ParticleContainer<1 + 2*BL_SPACEDIM, 1> MyParticleContainer;
+  typedef ParticleContainer<1 + 2*AMREX_SPACEDIM, 1> MyParticleContainer;
   MyParticleContainer myPC(geom, dmap, ba);
   myPC.SetVerbose(false);
 
@@ -66,83 +67,63 @@ void testParticleMesh (TestParams& parms)
   MyParticleContainer::ParticleInitData pdata = {{mass, AMREX_D_DECL(1.0, 2.0, 3.0), AMREX_D_DECL(0.0, 0.0, 0.0)}, {},{},{}};
   myPC.InitRandom(num_particles, iseed, pdata, serialize);
 
-  int nc = 1 + BL_SPACEDIM;
+  int nc = 1 + AMREX_SPACEDIM;
   const auto plo = geom.ProbLoArray();
   const auto dxi = geom.InvCellSizeArray();
   amrex::ParticleToMesh(myPC, partMF, 0,
       [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& p,
                             amrex::Array4<amrex::Real> const& rho)
       {
-          amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-          amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-          amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
-
-          int i = static_cast<int>(amrex::Math::floor(lx));
-          int j = static_cast<int>(amrex::Math::floor(ly));
-          int k = static_cast<int>(amrex::Math::floor(lz));
-
-          amrex::Real xint = lx - i;
-          amrex::Real yint = ly - j;
-          amrex::Real zint = lz - k;
-
-          amrex::Real sx[] = {1.-xint, xint};
-          amrex::Real sy[] = {1.-yint, yint};
-          amrex::Real sz[] = {1.-zint, zint};
-
-          for (int kk = 0; kk <= 1; ++kk) {
-              for (int jj = 0; jj <= 1; ++jj) {
-                  for (int ii = 0; ii <= 1; ++ii) {
-                      amrex::Gpu::Atomic::AddNoRet(&rho(i+ii-1, j+jj-1, k+kk-1, 0),
-                                              sx[ii]*sy[jj]*sz[kk]*p.rdata(0));
-                  }
-              }
-          }
-
-          for (int comp=1; comp < nc; ++comp) {
-             for (int kk = 0; kk <= 1; ++kk) {
-                  for (int jj = 0; jj <= 1; ++jj) {
-                      for (int ii = 0; ii <= 1; ++ii) {
-                          amrex::Gpu::Atomic::AddNoRet(&rho(i+ii-1, j+jj-1, k+kk-1, comp),
-                                                  sx[ii]*sy[jj]*sz[kk]*p.rdata(0)*p.rdata(comp));
-                      }
-                  }
-              }
-          }
+          ParticleInterpolator::Linear interp(p, plo, dxi);
+
+          interp.ParticleToMesh(p, rho, 0, 0, 1,
+                      [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& part, int comp)
+                      {
+                          return part.rdata(comp);  // no weighting
+                      });
+
+          interp.ParticleToMesh(p, rho, 1, 1, AMREX_SPACEDIM,
+                      [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& part, int comp)
+                      {
+                          return part.rdata(0) * p.rdata(comp);  // mass weight these comps
+                      });
       });
 
-  MultiFab acceleration(ba, dmap, BL_SPACEDIM, 1);
+  amrex::ParticleToMesh(myPC, partMF, 0,
+      [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& p,
+                            amrex::Array4<amrex::Real> const& rho)
+      {
+          ParticleInterpolator::Nearest interp(p, plo, dxi);
+
+          interp.ParticleToMesh(p, rho, 0, 0, 1,
+              [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& /*p*/,
+                                    int /*comp*/)
+              {
+                  return 1.0;  // no weighting
+              });
+      });
+
+  MultiFab acceleration(ba, dmap, AMREX_SPACEDIM, 1);
   acceleration.setVal(5.0);
 
-  nc = BL_SPACEDIM;
+  nc = AMREX_SPACEDIM;
   amrex::MeshToParticle(myPC, acceleration, 0,
       [=] AMREX_GPU_DEVICE (MyParticleContainer::ParticleType& p,
                             amrex::Array4<const amrex::Real> const& acc)
       {
-          amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-          amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-          amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
-
-          int i = static_cast<int>(amrex::Math::floor(lx));
-          int j = static_cast<int>(amrex::Math::floor(ly));
-          int k = static_cast<int>(amrex::Math::floor(lz));
-
-          amrex::Real xint = lx - i;
-          amrex::Real yint = ly - j;
-          amrex::Real zint = lz - k;
-
-          amrex::Real sx[] = {1.-xint, xint};
-          amrex::Real sy[] = {1.-yint, yint};
-          amrex::Real sz[] = {1.-zint, zint};
-
-          for (int comp=0; comp < nc; ++comp) {
-              for (int kk = 0; kk <= 1; ++kk) {
-                  for (int jj = 0; jj <= 1; ++jj) {
-                      for (int ii = 0; ii <= 1; ++ii) {
-                          p.rdata(4+comp) += static_cast<ParticleReal> (sx[ii]*sy[jj]*sz[kk]*acc(i+ii-1,j+jj-1,k+kk-1,comp));
-                      }
-                  }
-              }
-          }
+          ParticleInterpolator::Linear interp(p, plo, dxi);
+
+          interp.MeshToParticle(p, acc, 0, 0, nc,
+                  [=] AMREX_GPU_DEVICE (amrex::Array4<const amrex::Real> const& arr,
+                                        int i, int j, int k, int comp)
+                  {
+                      return arr(i, j, k, comp);  // no weighting
+                  },
+                  [=] AMREX_GPU_DEVICE (MyParticleContainer::ParticleType& part,
+                                        int comp, amrex::Real val)
+                  {
+                      part.rdata(comp) += val;
+                  });
       });
 
   // now also try the iMultiFab versions
@@ -150,34 +131,36 @@ void testParticleMesh (TestParams& parms)
       [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& p,
                             amrex::Array4<int> const& count)
       {
-          amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-          amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-          amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
-
-          int i = static_cast<int>(amrex::Math::floor(lx));
-          int j = static_cast<int>(amrex::Math::floor(ly));
-          int k = static_cast<int>(amrex::Math::floor(lz));
+          ParticleInterpolator::Nearest interp(p, plo, dxi);
 
-          amrex::Gpu::Atomic::AddNoRet(&count(i, j, k), 1);
+          interp.ParticleToMesh(p, count, 0, 0, 1,
+              [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& /*p*/, int /*comp*/) -> int
+              {
+                  return 1;  // just count the particles per cell
+              });
       });
 
   amrex::MeshToParticle(myPC, partiMF, 0,
       [=] AMREX_GPU_DEVICE (MyParticleContainer::ParticleType& p,
                             amrex::Array4<const int> const& count)
       {
-          amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-          amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-          amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
-
-          int i = static_cast<int>(amrex::Math::floor(lx));
-          int j = static_cast<int>(amrex::Math::floor(ly));
-          int k = static_cast<int>(amrex::Math::floor(lz));
-
-          p.idata(0) = count(i, j, k);
+          ParticleInterpolator::Nearest interp(p, plo, dxi);
+
+          interp.MeshToParticle(p, count, 0, 0, 1,
+                  [=] AMREX_GPU_DEVICE (amrex::Array4<const int> const& arr,
+                                        int i, int j, int k, int comp)
+                  {
+                      return arr(i, j, k, comp);  // no weighting
+                  },
+                  [=] AMREX_GPU_DEVICE (MyParticleContainer::ParticleType& part,
+                                        int comp, int val)
+                  {
+                      part.idata(comp) = val;
+                  });
       });
 
   WriteSingleLevelPlotfile("plot", partMF,
-                           {"density", "vx", "vy", "vz"},
+                           {"density", AMREX_D_DECL("vx", "vy", "vz")},
                            geom, 0.0, 0);
 
   myPC.Checkpoint("plot", "particle0");
diff --git a/Tests/Particles/ParticleMeshMultiLevel/main.cpp b/Tests/Particles/ParticleMeshMultiLevel/main.cpp
index d77c8786966..f52c2899706 100644
--- a/Tests/Particles/ParticleMeshMultiLevel/main.cpp
+++ b/Tests/Particles/ParticleMeshMultiLevel/main.cpp
@@ -95,31 +95,14 @@ void testParticleMesh (TestParams& parms)
                               amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
                               amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& dxi) noexcept
         {
-          amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-          amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-          amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
-
-          int i = static_cast<int>(amrex::Math::floor(lx));
-          int j = static_cast<int>(amrex::Math::floor(ly));
-          int k = static_cast<int>(amrex::Math::floor(lz));
-
-          amrex::Real xint = lx - i;
-          amrex::Real yint = ly - j;
-          amrex::Real zint = lz - k;
-
-          amrex::Real sx[] = {1.-xint, xint};
-          amrex::Real sy[] = {1.-yint, yint};
-          amrex::Real sz[] = {1.-zint, zint};
-
-          for (int kk = 0; kk <= 1; ++kk) {
-              for (int jj = 0; jj <= 1; ++jj) {
-                  for (int ii = 0; ii <= 1; ++ii) {
-                      amrex::Gpu::Atomic::AddNoRet(&rho(i+ii-1, j+jj-1, k+kk-1, 0),
-                                                   sx[ii]*sy[jj]*sz[kk]*p.rdata(0));
-                  }
-              }
-          }
-      });
+            ParticleInterpolator::Linear interp(p, plo, dxi);
+
+            interp.ParticleToMesh(p, rho, 0, 0, 1,
+                [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& part, int comp)
+                {
+                    return part.rdata(comp);  // no weighting
+                });
+        });
 
     //
     // Here we provide an example of another way to call ParticleToMesh
@@ -128,8 +111,8 @@ void testParticleMesh (TestParams& parms)
     int start_mesh_comp = 0;
     int        num_comp = 1;
 
-    ParticleToMesh(myPC,GetVecOfPtrs(density2),0,parms.nlevs-1,
-                   TrilinearDeposition{start_part_comp,start_mesh_comp,num_comp});
+    amrex::ParticleToMesh(myPC,GetVecOfPtrs(density2),0,parms.nlevs-1,
+                          TrilinearDeposition{start_part_comp,start_mesh_comp,num_comp});
 
     //
     // Now write the output from each into separate plotfiles for comparison
diff --git a/Tests/Particles/ParticleMeshMultiLevel/trilinear_deposition_K.H b/Tests/Particles/ParticleMeshMultiLevel/trilinear_deposition_K.H
index 47f1e5049fb..fba78c9fc3e 100644
--- a/Tests/Particles/ParticleMeshMultiLevel/trilinear_deposition_K.H
+++ b/Tests/Particles/ParticleMeshMultiLevel/trilinear_deposition_K.H
@@ -4,46 +4,26 @@
 #include <AMReX_MultiFabUtil.H>
 #include <AMReX_Particles.H>
 #include <AMReX_AmrParticles.H>
+#include <AMReX_ParticleInterpolators.H>
 
 struct TrilinearDeposition
 {
-  int start_part_comp;
-  int start_mesh_comp;
-  int   num_comp;
+    int start_part_comp;
+    int start_mesh_comp;
+    int   num_comp;
 
-  AMREX_GPU_DEVICE
-  void operator()
-                  (const MyParticleContainer::ParticleType& p,
-                   amrex::Array4<amrex::Real> const& rho,
-                   amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
-                   amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& dxi) const noexcept
-  {
-      amrex::Real lx = (p.pos(0) - plo[0]) * dxi[0] + 0.5;
-      amrex::Real ly = (p.pos(1) - plo[1]) * dxi[1] + 0.5;
-      amrex::Real lz = (p.pos(2) - plo[2]) * dxi[2] + 0.5;
+    AMREX_GPU_DEVICE AMREX_FORCE_INLINE
+    void operator() (const MyParticleContainer::ParticleType& p,
+                     amrex::Array4<amrex::Real> const& rho,
+                     amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& plo,
+                     amrex::GpuArray<amrex::Real,AMREX_SPACEDIM> const& dxi) const noexcept
+    {
+        amrex::ParticleInterpolator::Linear interp(p, plo, dxi);
 
-      int i = static_cast<int>(amrex::Math::floor(lx));
-      int j = static_cast<int>(amrex::Math::floor(ly));
-      int k = static_cast<int>(amrex::Math::floor(lz));
-
-      amrex::Real xint = lx - i;
-      amrex::Real yint = ly - j;
-      amrex::Real zint = lz - k;
-
-      amrex::Real sx[] = {1.-xint, xint};
-      amrex::Real sy[] = {1.-yint, yint};
-      amrex::Real sz[] = {1.-zint, zint};
-
-      for (int kk = 0; kk <= 1; ++kk) {
-          for (int jj = 0; jj <= 1; ++jj) {
-              for (int ii = 0; ii <= 1; ++ii) {
-                  for (int icomp = 0; icomp < num_comp; icomp++)
-                  {
-                      amrex::Gpu::Atomic::AddNoRet(&rho(i+ii-1, j+jj-1, k+kk-1, start_mesh_comp+icomp),
-                                                   sx[ii]*sy[jj]*sz[kk]*p.rdata(start_part_comp+icomp));
-                  }
-              }
-          }
-      }
-  }
+        interp.ParticleToMesh(p, rho, start_part_comp, start_mesh_comp, num_comp,
+            [=] AMREX_GPU_DEVICE (const MyParticleContainer::ParticleType& part, int comp)
+            {
+                return part.rdata(comp);  // no weighting
+            });
+    }
 };
diff --git a/Tests/Particles/ParticleReduce/main.cpp b/Tests/Particles/ParticleReduce/main.cpp
index cdecf985430..382c9191804 100644
--- a/Tests/Particles/ParticleReduce/main.cpp
+++ b/Tests/Particles/ParticleReduce/main.cpp
@@ -3,6 +3,8 @@
 #include <AMReX_MultiFab.H>
 #include <AMReX_Particles.H>
 
+#include <cmath>
+
 using namespace amrex;
 
 static constexpr int NSR = 4;
@@ -12,17 +14,25 @@ static constexpr int NAI = 1;
 
 void get_position_unit_cell(Real* r, const IntVect& nppc, int i_part)
 {
-    int nx = nppc[0];
-    int ny = nppc[1];
-    int nz = nppc[2];
-
-    int ix_part = i_part/(ny * nz);
-    int iy_part = (i_part % (ny * nz)) % ny;
-    int iz_part = (i_part % (ny * nz)) / ny;
-
-    r[0] = (0.5+ix_part)/nx;
-    r[1] = (0.5+iy_part)/ny;
-    r[2] = (0.5+iz_part)/nz;
+        int nx = nppc[0];
+#if AMREX_SPACEDIM >= 2
+        int ny = nppc[1];
+#else
+        int ny = 1;
+#endif
+#if AMREX_SPACEDIM == 3
+        int nz = nppc[2];
+#else
+        int nz = 1;
+#endif
+
+        AMREX_D_TERM(int ix_part = i_part/(ny * nz);,
+                     int iy_part = (i_part % (ny * nz)) % ny;,
+                     int iz_part = (i_part % (ny * nz)) / ny;)
+
+        AMREX_D_TERM(r[0] = (0.5+ix_part)/nx;,
+                     r[1] = (0.5+iy_part)/ny;,
+                     r[2] = (0.5+iz_part)/nz;)
 }
 
 class TestParticleContainer
@@ -58,19 +68,19 @@ class TestParticleContainer
             for (IntVect iv = tile_box.smallEnd(); iv <= tile_box.bigEnd(); tile_box.next(iv))
             {
                 for (int i_part=0; i_part<num_ppc;i_part++) {
-                    Real r[3];
+                    Real r[AMREX_SPACEDIM];
                     get_position_unit_cell(r, a_num_particles_per_cell, i_part);
 
-                    ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);
-                    ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);
-                    ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);
+                    AMREX_D_TERM(ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);,
+                                 ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);,
+                                 ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);)
 
                     ParticleType p;
                     p.id()  = ParticleType::NextID();
                     p.cpu() = ParallelDescriptor::MyProc();
-                    p.pos(0) = x;
-                    p.pos(1) = y;
-                    p.pos(2) = z;
+                    AMREX_D_TERM(p.pos(0) = x;,
+                                 p.pos(1) = y;,
+                                 p.pos(2) = z;)
 
                     for (int i = 0; i < NSR; ++i) p.rdata(i) = i;
                     for (int i = 0; i < NSI; ++i) p.idata(i) = i;
@@ -225,7 +235,7 @@ void testReduce ()
                return {a, b, c};
            }, reduce_ops);
 
-        AMREX_ALWAYS_ASSERT(amrex::get<0>(r) == 16777216.0);
+        AMREX_ALWAYS_ASSERT(amrex::get<0>(r) == amrex::Real(std::pow(256, AMREX_SPACEDIM)));
         AMREX_ALWAYS_ASSERT(amrex::get<1>(r) == 2.0);
         AMREX_ALWAYS_ASSERT(amrex::get<2>(r) == 1);
     }
diff --git a/Tests/Particles/ParticleTransformations/main.cpp b/Tests/Particles/ParticleTransformations/main.cpp
index 0931165200f..e60a6762f93 100644
--- a/Tests/Particles/ParticleTransformations/main.cpp
+++ b/Tests/Particles/ParticleTransformations/main.cpp
@@ -12,17 +12,25 @@ static constexpr int NAI = 2;
 
 void get_position_unit_cell(Real* r, const IntVect& nppc, int i_part)
 {
-    int nx = nppc[0];
-    int ny = nppc[1];
-    int nz = nppc[2];
-
-    int ix_part = i_part/(ny * nz);
-    int iy_part = (i_part % (ny * nz)) % ny;
-    int iz_part = (i_part % (ny * nz)) / ny;
-
-    r[0] = (0.5+ix_part)/nx;
-    r[1] = (0.5+iy_part)/ny;
-    r[2] = (0.5+iz_part)/nz;
+        int nx = nppc[0];
+#if AMREX_SPACEDIM >= 2
+        int ny = nppc[1];
+#else
+        int ny = 1;
+#endif
+#if AMREX_SPACEDIM == 3
+        int nz = nppc[2];
+#else
+        int nz = 1;
+#endif
+
+        AMREX_D_TERM(int ix_part = i_part/(ny * nz);,
+                     int iy_part = (i_part % (ny * nz)) % ny;,
+                     int iz_part = (i_part % (ny * nz)) / ny;)
+
+        AMREX_D_TERM(r[0] = (0.5+ix_part)/nx;,
+                     r[1] = (0.5+iy_part)/ny;,
+                     r[2] = (0.5+iz_part)/nz;)
 }
 
 class TestParticleContainer
@@ -64,16 +72,16 @@ class TestParticleContainer
                     Real r[3];
                     get_position_unit_cell(r, a_num_particles_per_cell, i_part);
 
-                    ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);
-                    ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);
-                    ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);
+                    AMREX_D_TERM(ParticleReal x = static_cast<ParticleReal> (plo[0] + (iv[0] + r[0])*dx[0]);,
+                                 ParticleReal y = static_cast<ParticleReal> (plo[1] + (iv[1] + r[1])*dx[1]);,
+                                 ParticleReal z = static_cast<ParticleReal> (plo[2] + (iv[2] + r[2])*dx[2]);)
 
                     ParticleType p;
                     p.id()  = ParticleType::NextID();
                     p.cpu() = ParallelDescriptor::MyProc();
-                    p.pos(0) = x;
-                    p.pos(1) = y;
-                    p.pos(2) = z;
+                    AMREX_D_TERM(p.pos(0) = x;,
+                                 p.pos(1) = y;,
+                                 p.pos(2) = z;)
 
                     for (int i = 0; i < NSR; ++i) p.rdata(i) = i;
                     for (int i = 0; i < NSI; ++i) p.idata(i) = i;