Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_ParticleReduceSIMD.H
Go to the documentation of this file.
1#ifndef AMREX_PARTICLEREDUCE_SIMD_H_
2#define AMREX_PARTICLEREDUCE_SIMD_H_
3#include <AMReX_Config.H>
4
5#include <AMReX_ParticleReduce.H> // provides amrex::SIMDindex via AMReX_Gpu.H
6#include <AMReX_ReduceSIMD.H>
7#include <AMReX_SIMD.H>
8#include <AMReX_Tuple.H>
9#include <AMReX_TypeTraits.H>
10#include <AMReX_Vector.H>
11
12#include <type_traits>
13#include <utility>
14
15namespace amrex {
16
18namespace particle_detail {
19
21 template <typename F>
22 struct SIMDTupleWrapper
23 {
24 F m_f;
25
26 template <typename PTD, typename SI>
28 auto operator() (PTD const& ptd, SI const si) const noexcept
29 {
30 return amrex::makeTuple(m_f(ptd, si));
31 }
32 };
33
41 template <typename F, typename PTD>
42 struct SIMDKernelBinder
43 {
44 F m_f;
45 PTD m_ptd;
46
47 template <typename SI>
49 auto operator() (SI const si) const noexcept
50 {
51 return m_f(m_ptd, si);
52 }
53 };
54}
56
116template <class RD,
117 int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
118 class PC, class F, typename... Ps>
119 requires(IsParticleContainer<PC>::value)
120typename RD::Type ParticleReduceSIMD(PC const &pc, int lev_min, int lev_max,
121 F const &f, ReduceOps<Ps...> &reduce_ops) {
122 // enforce the documented contract in every configuration (CPU with and
123 // without SIMD support, GPU), not just where evalReduceSIMD is called
124 static_assert(WIDTH >= 1, "ParticleReduceSIMD: WIDTH must be at least 1");
125 static_assert((Reduce::detail::is_simd_reduce_op<Ps> && ...),
126 "ParticleReduceSIMD supports only ReduceOpSum, ReduceOpMin and "
127 "ReduceOpMax");
128
129 RD reduce_data(reduce_ops);
130 for (int lev = lev_min; lev <= lev_max; ++lev) {
131 const auto &plev = pc.GetParticles(lev);
132 Vector<std::pair<int, int>> grid_tile_ids;
134 for (auto &kv : plev) {
135 grid_tile_ids.push_back(kv.first);
136 ptile_ptrs.push_back(&(kv.second));
137 }
138
139 // We avoid ParIter here to allow reductions after grids change but prior to
140 // calling Redistribute()
141#if !defined(AMREX_USE_GPU) && defined(AMREX_USE_OMP)
142#pragma omp parallel for
143#endif
144 for (int pmap_it = 0; pmap_it < std::ssize(ptile_ptrs); ++pmap_it)
145 {
146 const auto& tile = plev.at(grid_tile_ids[pmap_it]);
147 const auto np = tile.numParticles();
148 const auto& ptd = tile.getConstParticleTileData();
149#ifdef AMREX_USE_GPU
150 reduce_ops.eval(np, reduce_data,
151 [=] AMREX_GPU_DEVICE (const int i) noexcept
152 {
153 return f(ptd, SIMDindex<1, int>{i});
154 });
155#else
156#ifdef AMREX_USE_SIMD
157 constexpr int EffWidth = WIDTH;
158#else
159 constexpr int EffWidth = 1; // explicit WIDTH > 1 still compiles, scalar
160#endif
161 using PTDType = std::decay_t<decltype(ptd)>;
162 evalReduceSIMD<EffWidth>(np, reduce_data,
163 particle_detail::SIMDKernelBinder<F, PTDType>{f, ptd},
164 reduce_ops);
165#endif
166 }
167 }
168 return reduce_data.value(reduce_ops);
169}
170
183template <class RD,
184 int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
185 class PC, class F, typename... Ps>
186 requires(IsParticleContainer<PC>::value)
187typename RD::Type ParticleReduceSIMD(PC const &pc, int lev, F const &f,
188 ReduceOps<Ps...> &reduce_ops) {
189 return ParticleReduceSIMD<RD, WIDTH>(pc, lev, lev, f, reduce_ops);
190}
191
203template <class RD,
204 int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
205 class PC, class F, typename... Ps>
206 requires(IsParticleContainer<PC>::value)
207typename RD::Type ParticleReduceSIMD(PC const &pc, F const &f,
208 ReduceOps<Ps...> &reduce_ops) {
209 return ParticleReduceSIMD<RD, WIDTH>(pc, 0, pc.finestLevel(), f, reduce_ops);
210}
211
248template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
249 class PC, class F>
250requires (IsParticleContainer<PC>::value)
251auto
252ReduceSumSIMD (PC const& pc, int lev_min, int lev_max, F const& f)
253{
254 using ConstPTDType = typename PC::ConstPTDType;
255 using T = std::decay_t<std::invoke_result_t<F, ConstPTDType const&, SIMDindex<1, int>>>;
256 ReduceOps<ReduceOpSum> reduce_ops;
257 auto r = ParticleReduceSIMD<ReduceData<T>, WIDTH>(
258 pc, lev_min, lev_max, particle_detail::SIMDTupleWrapper<F>{f}, reduce_ops);
259 return amrex::get<0>(r);
260}
261
273template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
274 class PC, class F>
275requires (IsParticleContainer<PC>::value)
276auto
277ReduceSumSIMD (PC const& pc, int lev, F const& f)
278{
279 return ReduceSumSIMD<WIDTH>(pc, lev, lev, f);
280}
281
292template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
293 class PC, class F>
294requires (IsParticleContainer<PC>::value)
295auto
296ReduceSumSIMD (PC const& pc, F const& f)
297{
298 return ReduceSumSIMD<WIDTH>(pc, 0, pc.finestLevel(), f);
299}
300
319template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
320 class PC, class F>
321requires (IsParticleContainer<PC>::value)
322auto
323ReduceMinSIMD (PC const& pc, int lev_min, int lev_max, F const& f)
324{
325 using ConstPTDType = typename PC::ConstPTDType;
326 using T = std::decay_t<std::invoke_result_t<F, ConstPTDType const&, SIMDindex<1, int>>>;
327 ReduceOps<ReduceOpMin> reduce_ops;
328 auto r = ParticleReduceSIMD<ReduceData<T>, WIDTH>(
329 pc, lev_min, lev_max, particle_detail::SIMDTupleWrapper<F>{f}, reduce_ops);
330 return amrex::get<0>(r);
331}
332
343template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
344 class PC, class F>
345requires (IsParticleContainer<PC>::value)
346auto
347ReduceMinSIMD (PC const& pc, int lev, F const& f)
348{
349 return ReduceMinSIMD<WIDTH>(pc, lev, lev, f);
350}
351
361template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
362 class PC, class F>
363requires (IsParticleContainer<PC>::value)
364auto
365ReduceMinSIMD (PC const& pc, F const& f)
366{
367 return ReduceMinSIMD<WIDTH>(pc, 0, pc.finestLevel(), f);
368}
369
388template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
389 class PC, class F>
390requires (IsParticleContainer<PC>::value)
391auto
392ReduceMaxSIMD (PC const& pc, int lev_min, int lev_max, F const& f)
393{
394 using ConstPTDType = typename PC::ConstPTDType;
395 using T = std::decay_t<std::invoke_result_t<F, ConstPTDType const&, SIMDindex<1, int>>>;
396 ReduceOps<ReduceOpMax> reduce_ops;
397 auto r = ParticleReduceSIMD<ReduceData<T>, WIDTH>(
398 pc, lev_min, lev_max, particle_detail::SIMDTupleWrapper<F>{f}, reduce_ops);
399 return amrex::get<0>(r);
400}
401
412template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
413 class PC, class F>
414requires (IsParticleContainer<PC>::value)
415auto
416ReduceMaxSIMD (PC const& pc, int lev, F const& f)
417{
418 return ReduceMaxSIMD<WIDTH>(pc, lev, lev, f);
419}
420
430template <int WIDTH = static_cast<int>(simd::native_simd_size_particlereal),
431 class PC, class F>
432requires (IsParticleContainer<PC>::value)
433auto
434ReduceMaxSIMD (PC const& pc, F const& f)
435{
436 return ReduceMaxSIMD<WIDTH>(pc, 0, pc.finestLevel(), f);
437}
438
439}
440
441#endif
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
#define AMREX_GPU_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
Definition AMReX_Reduce.H:597
void eval(MF const &mf, IntVect const &nghost, D &reduce_data, F &&f)
Definition AMReX_Reduce.H:731
This class is a thin wrapper around std::vector. Unlike vector, Vector::operator[] provides bound che...
Definition AMReX_Vector.H:29
constexpr auto native_simd_size_particlereal
Definition AMReX_SIMD.H:221
Definition AMReX_Amr.cpp:50
auto ReduceMaxSIMD(PC const &pc, int lev_min, int lev_max, F const &f)
A SIMD-vectorized max reduction over the particles in a ParticleContainer. This version operates from...
Definition AMReX_ParticleReduceSIMD.H:392
__host__ __device__ constexpr GpuTuple< detail::tuple_decay_t< Ts >... > makeTuple(Ts &&... args)
Definition AMReX_Tuple.H:269
auto ReduceMinSIMD(PC const &pc, int lev_min, int lev_max, F const &f)
A SIMD-vectorized min reduction over the particles in a ParticleContainer. This version operates from...
Definition AMReX_ParticleReduceSIMD.H:323
auto ReduceSumSIMD(PC const &pc, int lev_min, int lev_max, F const &f)
A SIMD-vectorized sum reduction over the particles in a ParticleContainer. This version operates from...
Definition AMReX_ParticleReduceSIMD.H:252
RD::Type ParticleReduceSIMD(PC const &pc, int lev_min, int lev_max, F const &f, ReduceOps< Ps... > &reduce_ops)
A general SIMD-vectorized reduction method for the particles in a ParticleContainer....
Definition AMReX_ParticleReduceSIMD.H:120
Definition AMReX_GpuLaunchFunctsSIMD.H:24