ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
particle_reduction.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2025 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <config/config.hpp>
23
24#include "Particle.hpp"
26
27#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
28#include <Kokkos_Core.hpp>
29#endif
30
31#include <concepts>
32#include <functional>
33#include <utility>
34
35namespace Reduction {
36
37/** @brief Kernel that adds the result from a single particle to a reduction */
38template <typename ResultType>
40 std::function<void(ResultType &, Particle const &)>;
41
42/** @brief Join two partial reduction results */
43template <typename ResultType>
44using ReductionOp = std::function<void(ResultType &, ResultType const &)>;
45
46#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
47
48/** @brief Custom reduction in the form required by Kokkos */
49template <typename ResultType, typename Kernel> class KokkosReducer {
50public:
51 // Kokkos reduction functors need the value_type typedef.
52 // This is the type of the result of the reduction.
53 using value_type = ResultType;
54
55 // Just like with parallel_for functors, you may specify
56 // an execution_space typedef. If not provided, Kokkos
57 // will use the default execution space by default.
58
59 // kernels to wrap
61 Kernel kernel;
65 : reduction_op(other.reduction_op), kernel(other.kernel) {};
66
67 KOKKOS_INLINE_FUNCTION void operator()(std::integral auto const i,
68 value_type &update) const {
69 kernel(i, update);
70 }
71
72 // "Join" intermediate results from different threads.
73 // This should normally implement the same reduction
74 // operation as operator() above.
75 KOKKOS_INLINE_FUNCTION void join(value_type &dst,
76 value_type const &src) const {
77 reduction_op(dst, src);
78 }
79};
80
81template <typename ResultType, typename Kernel>
82KokkosReducer<ResultType, Kernel>
84 return KokkosReducer<ResultType, Kernel>(k, reduce_op);
85}
86
87#endif // ESPRESSO_SHARED_MEMORY_PARALLELISM
88
89} // namespace Reduction
90
91/** @brief performs a reduction over all particles
92 *
93 * @param cs cell structure to iterate over
94 * @param add_partial is a function that adds a reduction result from a single
95 * particle
96 * @param reduce_op is a function that joins two reduction results
97 *
98 * both functions have to implement the same reduction.
99 */
100template <typename ResultType>
102 CellStructure const &cs,
104 [[maybe_unused]] Reduction::ReductionOp<ResultType> reduce_op) {
105
106 ResultType result{};
107
108#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
109 auto const &cells = cs.decomposition().local_cells();
110 if (cells.size() > 1) { // parallel loop over cells
111 auto reducer = Reduction::make_kokkos_reducer<ResultType>(
112 [&cells, add_partial](std::size_t const c_index, ResultType &res) {
113 for (auto const &p : cells[c_index]->particles()) {
114 add_partial(res, p);
115 }
116 },
117 reduce_op);
118 Kokkos::parallel_reduce( // loop over cells
119 "reduce_on_local_particle", cells.size(), reducer, result);
120 return result;
121 }
122 // single cell case
123 auto const &particles = cells.front()->particles();
124 auto reducer = Reduction::make_kokkos_reducer<ResultType>(
125 [&particles, add_partial](std::size_t const p_index, ResultType &res) {
126 add_partial(res, std::as_const(*(particles.begin() + p_index)));
127 },
128 reduce_op);
129 Kokkos::parallel_reduce( // loop over particles
130 "reduce_on_local_particle", particles.size(), reducer, result);
131 return result;
132#else // ESPRESSO_SHARED_MEMORY_PARALLELISM
133 for (auto const &p : cs.local_particles()) {
134 add_partial(result, p);
135 }
136 return result;
137#endif
138}
Describes a cell structure / cell system.
ParticleDecomposition const & decomposition() const
Get the underlying particle decomposition.
ParticleRange local_particles() const
virtual std::span< Cell *const > local_cells() const =0
Get pointer to local cells.
base_type::size_type size() const
Custom reduction in the form required by Kokkos.
KokkosReducer(Kernel kernel, ReductionOp< ResultType > reduction_op)
ReductionOp< ResultType > reduction_op
KOKKOS_INLINE_FUNCTION void join(value_type &dst, value_type const &src) const
KokkosReducer(KokkosReducer const &other)
KOKKOS_INLINE_FUNCTION void operator()(std::integral auto const i, value_type &update) const
std::function< void(ResultType &, ResultType const &)> ReductionOp
Join two partial reduction results.
KokkosReducer< ResultType, Kernel > make_kokkos_reducer(Kernel k, ReductionOp< ResultType > reduce_op)
std::function< void(ResultType &, Particle const &)> AddPartialResultKernel
Kernel that adds the result from a single particle to a reduction.
STL namespace.
ResultType reduce_over_local_particles(CellStructure const &cs, Reduction::AddPartialResultKernel< ResultType > add_partial, Reduction::ReductionOp< ResultType > reduce_op)
performs a reduction over all particles
Struct holding all information for one particle.
Definition Particle.hpp:450