Branch data Line data Source code
1 : : //
2 : : // Class ParticleAttrib
3 : : // Templated class for all particle attribute classes.
4 : : //
5 : : // This templated class is used to represent a single particle attribute.
6 : : // An attribute is one data element within a particle object, and is
7 : : // stored as a Kokkos::View. This class stores the type information for the
8 : : // attribute, and provides methods to create and destroy new items, and
9 : : // to perform operations involving this attribute with others.
10 : : //
11 : : // ParticleAttrib is the primary element involved in expressions for
12 : : // particles (just as BareField is the primary element there). This file
13 : : // defines the necessary templated classes and functions to make
14 : : // ParticleAttrib a capable expression-template participant.
15 : : //
16 : : #include "Ippl.h"
17 : :
18 : : #include "Communicate/DataTypes.h"
19 : :
20 : : #include "Utility/IpplTimings.h"
21 : :
22 : : namespace ippl {
23 : :
24 : : template <typename T, class... Properties>
25 : 252 : void ParticleAttrib<T, Properties...>::create(size_type n) {
26 : 252 : size_type required = *(this->localNum_mp) + n;
27 [ + - ]: 252 : if (this->size() < required) {
28 : 252 : int overalloc = Comm->getDefaultOverallocation();
29 : 252 : this->realloc(required * overalloc);
30 : : }
31 : 252 : }
32 : :
33 : : template <typename T, class... Properties>
34 : 24 : void ParticleAttrib<T, Properties...>::destroy(const hash_type& deleteIndex,
35 : : const hash_type& keepIndex,
36 : : size_type invalidCount) {
37 : : // Replace all invalid particles in the valid region with valid
38 : : // particles in the invalid region
39 : : using policy_type = Kokkos::RangePolicy<execution_space>;
40 [ + - + - ]: 24 : Kokkos::parallel_for(
41 : 24 : "ParticleAttrib::destroy()", policy_type(0, invalidCount),
42 [ + - + - : 12048 : KOKKOS_CLASS_LAMBDA(const size_t i) {
+ - + - -
- - - ]
43 : 0 : dview_m(deleteIndex(i)) = dview_m(keepIndex(i));
44 : : });
45 : 24 : }
46 : :
47 : : template <typename T, class... Properties>
48 : 0 : void ParticleAttrib<T, Properties...>::pack(const hash_type& hash) {
49 : 0 : auto size = hash.extent(0);
50 [ # # ]: 0 : if (buf_m.extent(0) < size) {
51 : 0 : int overalloc = Comm->getDefaultOverallocation();
52 : 0 : Kokkos::realloc(buf_m, size * overalloc);
53 : : }
54 : :
55 : : using policy_type = Kokkos::RangePolicy<execution_space>;
56 [ # # # # ]: 0 : Kokkos::parallel_for(
57 : 0 : "ParticleAttrib::pack()", policy_type(0, size),
58 [ # # # # : 0 : KOKKOS_CLASS_LAMBDA(const size_t i) { buf_m(i) = dview_m(hash(i)); });
# # # # ]
59 [ # # # # ]: 0 : Kokkos::fence();
60 : 0 : }
61 : :
62 : : template <typename T, class... Properties>
63 : 0 : void ParticleAttrib<T, Properties...>::unpack(size_type nrecvs) {
64 : 0 : auto size = dview_m.extent(0);
65 : 0 : size_type required = *(this->localNum_mp) + nrecvs;
66 [ # # ]: 0 : if (size < required) {
67 : 0 : int overalloc = Comm->getDefaultOverallocation();
68 : 0 : this->resize(required * overalloc);
69 : : }
70 : :
71 : 0 : size_type count = *(this->localNum_mp);
72 : : using policy_type = Kokkos::RangePolicy<execution_space>;
73 [ # # # # ]: 0 : Kokkos::parallel_for(
74 : 0 : "ParticleAttrib::unpack()", policy_type(0, nrecvs),
75 [ # # # # : 0 : KOKKOS_CLASS_LAMBDA(const size_t i) { dview_m(count + i) = buf_m(i); });
# # ]
76 [ # # # # ]: 0 : Kokkos::fence();
77 : 0 : }
78 : :
79 : : template <typename T, class... Properties>
80 : : // KOKKOS_INLINE_FUNCTION
81 : 48 : ParticleAttrib<T, Properties...>& ParticleAttrib<T, Properties...>::operator=(T x) {
82 : : using policy_type = Kokkos::RangePolicy<execution_space>;
83 [ + - + - ]: 48 : Kokkos::parallel_for(
84 : 48 : "ParticleAttrib::operator=()", policy_type(0, *(this->localNum_mp)),
85 [ + - + - : 3936 : KOKKOS_CLASS_LAMBDA(const size_t i) { dview_m(i) = x; });
- - ]
86 : 48 : return *this;
87 : : }
88 : :
89 : : template <typename T, class... Properties>
90 : : template <typename E, size_t N>
91 : : // KOKKOS_INLINE_FUNCTION
92 : 0 : ParticleAttrib<T, Properties...>& ParticleAttrib<T, Properties...>::operator=(
93 : : detail::Expression<E, N> const& expr) {
94 : : using capture_type = detail::CapturedExpression<E, N>;
95 : 0 : capture_type expr_ = reinterpret_cast<const capture_type&>(expr);
96 : :
97 : : using policy_type = Kokkos::RangePolicy<execution_space>;
98 [ # # # # ]: 0 : Kokkos::parallel_for(
99 : 0 : "ParticleAttrib::operator=()", policy_type(0, *(this->localNum_mp)),
100 [ # # # # : 0 : KOKKOS_CLASS_LAMBDA(const size_t i) { dview_m(i) = expr_(i); });
# # ]
101 : 0 : return *this;
102 : : }
103 : :
104 : : template <typename T, class... Properties>
105 : : template <typename Field, class PT, typename policy_type>
106 : 24 : void ParticleAttrib<T, Properties...>::scatter(
107 : : Field& f, const ParticleAttrib<Vector<PT, Field::dim>, Properties...>& pp,
108 : : policy_type iteration_policy, hash_type hash_array) const {
109 : 24 : constexpr unsigned Dim = Field::dim;
110 : : using PositionType = typename Field::Mesh_t::value_type;
111 : :
112 [ + - + - : 24 : static IpplTimings::TimerRef scatterTimer = IpplTimings::getTimer("scatter");
+ - - - ]
113 [ + - ]: 24 : IpplTimings::startTimer(scatterTimer);
114 : : using view_type = typename Field::view_type;
115 [ + - ]: 24 : view_type view = f.getView();
116 : :
117 : : using mesh_type = typename Field::Mesh_t;
118 : 24 : const mesh_type& mesh = f.get_mesh();
119 : :
120 : : using vector_type = typename mesh_type::vector_type;
121 : : using value_type = typename ParticleAttrib<T, Properties...>::value_type;
122 : :
123 : 24 : const vector_type& dx = mesh.getMeshSpacing();
124 : 24 : const vector_type& origin = mesh.getOrigin();
125 [ + - + - ]: 24 : const vector_type invdx = 1.0 / dx;
[ # # ]
126 : :
127 [ + - ]: 24 : const FieldLayout<Dim>& layout = f.getLayout();
128 [ + - ]: 24 : const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
129 : 24 : const int nghost = f.getNghost();
130 : :
131 : : //using policy_type = Kokkos::RangePolicy<execution_space>;
132 : 24 : const bool useHashView = hash_array.extent(0) > 0;
133 [ - + - - : 24 : if (useHashView && (iteration_policy.end() > hash_array.extent(0))) {
- + ]
134 [ # # ]: 0 : Inform m("scatter");
135 [ # # # # ]: 0 : m << "Hash array was passed to scatter, but size does not match iteration policy." << endl;
136 [ # # ]: 0 : ippl::Comm->abort();
137 : 0 : }
138 [ + - + - ]: 24 : Kokkos::parallel_for(
139 : : "ParticleAttrib::scatter", iteration_policy,
140 [ + - + - : 1968 : KOKKOS_CLASS_LAMBDA(const size_t idx) {
+ - + - -
- - - - -
- - - - ]
141 : : // map index to possible hash_map
142 [ - + - + : 1920 : size_t mapped_idx = useHashView ? hash_array(idx) : idx;
- + - + -
+ - + - +
- + - + -
+ - + -
+ ][ # # ]
143 : :
144 : : // find nearest grid point
145 [ + - + - : 1920 : vector_type l = (pp(mapped_idx) - origin) * invdx + 0.5;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ][ # # #
# # # # #
# # ][ # #
# # # # #
# ]
146 [ + - + - : 1920 : Vector<int, Field::dim> index = l;
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ # # ]
147 [ + - + - : 1920 : Vector<PositionType, Field::dim> whi = l - index;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
[ # # # # ]
[ # # ]
148 [ + - + - : 1920 : Vector<PositionType, Field::dim> wlo = 1.0 - whi;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
[ # # # # ]
[ # # ]
149 : :
150 [ + - + - : 1920 : Vector<size_t, Field::dim> args = index - lDom.first() + nghost;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ # #
# # # # #
# ][ # # #
# # # ]
151 : :
152 : : // scatter
153 : 1920 : const value_type& val = dview_m(mapped_idx);
154 [ + - + - : 1920 : detail::scatterToField(std::make_index_sequence<1 << Field::dim>{}, view, wlo, whi,
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ # # ]
155 : : args, val);
156 : 1920 : });
157 [ + - ]: 24 : IpplTimings::stopTimer(scatterTimer);
158 : :
159 [ + - + - : 24 : static IpplTimings::TimerRef accumulateHaloTimer = IpplTimings::getTimer("accumulateHalo");
+ - - - ]
160 [ + - ]: 24 : IpplTimings::startTimer(accumulateHaloTimer);
161 [ + - ]: 24 : f.accumulateHalo();
162 [ + - ]: 24 : IpplTimings::stopTimer(accumulateHaloTimer);
163 : 24 : }
164 : :
165 : : template <typename T, class... Properties>
166 : : template <typename Field, typename P2>
167 : 12 : void ParticleAttrib<T, Properties...>::gather(
168 : : Field& f, const ParticleAttrib<Vector<P2, Field::dim>, Properties...>& pp,
169 : : const bool addToAttribute) {
170 : 12 : constexpr unsigned Dim = Field::dim;
171 : : using PositionType = typename Field::Mesh_t::value_type;
172 : :
173 [ + - + - : 12 : static IpplTimings::TimerRef fillHaloTimer = IpplTimings::getTimer("fillHalo");
+ - - - ]
174 [ + - ]: 12 : IpplTimings::startTimer(fillHaloTimer);
175 [ + - ]: 12 : f.fillHalo();
176 [ + - ]: 12 : IpplTimings::stopTimer(fillHaloTimer);
177 : :
178 [ + - + - : 12 : static IpplTimings::TimerRef gatherTimer = IpplTimings::getTimer("gather");
+ - - - ]
179 [ + - ]: 12 : IpplTimings::startTimer(gatherTimer);
180 [ + - ]: 12 : const typename Field::view_type view = f.getView();
181 : :
182 : : using mesh_type = typename Field::Mesh_t;
183 : 12 : const mesh_type& mesh = f.get_mesh();
184 : :
185 : : using vector_type = typename mesh_type::vector_type;
186 : :
187 : 12 : const vector_type& dx = mesh.getMeshSpacing();
188 : 12 : const vector_type& origin = mesh.getOrigin();
189 [ + - + - ]: 12 : const vector_type invdx = 1.0 / dx;
[ # # ]
190 : :
191 [ + - ]: 12 : const FieldLayout<Dim>& layout = f.getLayout();
192 [ + - ]: 12 : const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
193 : 12 : const int nghost = f.getNghost();
194 : :
195 : : using policy_type = Kokkos::RangePolicy<execution_space>;
196 [ + - + - ]: 12 : Kokkos::parallel_for(
197 : 12 : "ParticleAttrib::gather", policy_type(0, *(this->localNum_mp)),
198 [ + - + - : 408 : KOKKOS_CLASS_LAMBDA(const size_t idx) {
+ - + - -
- - - - -
- - - - ]
199 : : // find nearest grid point
200 [ + - + - : 384 : vector_type l = (pp(idx) - origin) * invdx + 0.5;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ][ # # #
# # # # #
# # ][ # #
# # # # #
# ]
201 [ + - + - : 384 : Vector<int, Field::dim> index = l;
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ # # ]
202 [ + - + - : 384 : Vector<PositionType, Field::dim> whi = l - index;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
[ # # # # ]
[ # # ]
203 [ + - + - : 384 : Vector<PositionType, Field::dim> wlo = 1.0 - whi;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
[ # # # # ]
[ # # ]
204 : :
205 [ + - + - : 384 : Vector<size_t, Field::dim> args = index - lDom.first() + nghost;
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - ][ # #
# # # # #
# ][ # # #
# # # ]
206 : :
207 : : // gather
208 : 0 : value_type gathered = detail::gatherFromField(std::make_index_sequence<1 << Field::dim>{},
209 [ + - + - : 384 : view, wlo, whi, args);
+ - + - +
- + - + -
+ - + - +
- + - +
- ][ # # ]
210 [ - + - + : 384 : if (addToAttribute) {
- + - + -
+ - + - +
- + - + -
+ - + -
+ ][ # # ]
211 : 0 : dview_m(idx) += gathered;
212 : : } else {
213 : 768 : dview_m(idx) = gathered;
214 : : }
215 : 384 : });
216 [ + - ]: 12 : IpplTimings::stopTimer(gatherTimer);
217 : 12 : }
218 : :
219 : : /*
220 : : * Non-class function
221 : : *
222 : : */
223 : :
224 : : /**
225 : : * @brief Non-class interface for scattering particle attribute data onto a field.
226 : : *
227 : : * This overload preserves legacy functionality by providing a default iteration policy.
228 : : * It calls the member scatter() with a default Kokkos::RangePolicy.
229 : : *
230 : : * @note The default behaviour is to scatter all particles without any custom index mapping.
231 : : *
232 : : * @tparam Attrib1 The type of the particle attribute.
233 : : * @tparam Field The type of the field.
234 : : * @tparam Attrib2 The type of the particle position attribute.
235 : : * @tparam policy_type (Default: `Kokkos::RangePolicy<typename Field::execution_space>`)
236 : : * @param attrib The particle attribute to scatter.
237 : : * @param f The field onto which the data is scattered.
238 : : * @param pp The ParticleAttrib representing particle positions.
239 : : */
240 : : template <typename Attrib1, typename Field, typename Attrib2,
241 : : typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
242 : 24 : inline void scatter(const Attrib1& attrib, Field& f, const Attrib2& pp) {
243 [ + - + - : 24 : attrib.scatter(f, pp, policy_type(0, attrib.getParticleCount()));
+ - ]
244 : 24 : }
245 : :
246 : : /**
247 : : * @brief Non-class interface for scattering with a custom iteration policy and optional index array.
248 : : *
249 : : * This overload allows the caller to specify a custom `Kokkos::range_policy` and an optional
250 : : * `ippl::hash_type` array. It forwards the parameters to the member scatter() function.
251 : : *
252 : : * @note See ParticleAttrib::scatter() for more information on the custom iteration functionality.
253 : : *
254 : : * @tparam Attrib1 The type of the particle attribute.
255 : : * @tparam Field The type of the field.
256 : : * @tparam Attrib2 The type of the particle position attribute.
257 : : * @tparam policy_type (Default: `Kokkos::RangePolicy<typename Field::execution_space>`)
258 : : * @param attrib The particle attribute to scatter.
259 : : * @param f The field onto which the data is scattered.
260 : : * @param pp The ParticleAttrib representing particle positions.
261 : : * @param iteration_policy A custom `Kokkos::range_policy` defining the iteration range.
262 : : * @param hash_array An optional `ippl::hash_type` array for index mapping.
263 : : */
264 : : template <typename Attrib1, typename Field, typename Attrib2,
265 : : typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
266 : : inline void scatter(const Attrib1& attrib, Field& f, const Attrib2& pp,
267 : : policy_type iteration_policy, typename Attrib1::hash_type hash_array = {}) {
268 : : attrib.scatter(f, pp, iteration_policy, hash_array);
269 : : }
270 : :
271 : : /**
272 : : * @brief Non-class interface for gathering field data into a particle attribute.
273 : : *
274 : : * This interface calls the member ParticleAttrib::gather() function with the provided
275 : : * parameters and preserving legacy behavior by assigning `addToAttribute` a default value.
276 : : *
277 : : * @note See ParticleAttrib::gather() for more information on the behavior of `addToAttribute`.
278 : : *
279 : : * @tparam Attrib1 The type of the particle attribute.
280 : : * @tparam Field The type of the field.
281 : : * @tparam Attrib2 The type of the particle position attribute.
282 : : * @param attrib The particle attribute to gather data into.
283 : : * @param f The field from which data is gathered.
284 : : * @param pp The ParticleAttrib representing particle positions.
285 : : * @param addToAttribute If true, the gathered field value is added to the current attribute value;
286 : : * otherwise, the attribute value is overwritten.
287 : : */
288 : : template <typename Attrib1, typename Field, typename Attrib2>
289 : 12 : inline void gather(Attrib1& attrib, Field& f, const Attrib2& pp,
290 : : const bool addToAttribute = false) {
291 : 12 : attrib.gather(f, pp, addToAttribute);
292 : 12 : }
293 : :
294 : : #define DefineParticleReduction(fun, name, op, MPI_Op) \
295 : : template <typename T, class... Properties> \
296 : : T ParticleAttrib<T, Properties...>::name() { \
297 : : T temp = 0.0; \
298 : : using policy_type = Kokkos::RangePolicy<execution_space>; \
299 : : Kokkos::parallel_reduce( \
300 : : "fun", policy_type(0, *(this->localNum_mp)), \
301 : : KOKKOS_CLASS_LAMBDA(const size_t i, T& valL) { \
302 : : T myVal = dview_m(i); \
303 : : op; \
304 : : }, \
305 : : Kokkos::fun<T>(temp)); \
306 : : T globaltemp = 0.0; \
307 : : Comm->allreduce(temp, globaltemp, 1, MPI_Op<T>()); \
308 : : return globaltemp; \
309 : : }
310 : :
311 [ + - + - : 432 : DefineParticleReduction(Sum, sum, valL += myVal, std::plus)
+ - + - +
- + - ]
312 : : DefineParticleReduction(Max, max, if (myVal > valL) valL = myVal, std::greater)
313 : : DefineParticleReduction(Min, min, if (myVal < valL) valL = myVal, std::less)
314 : : DefineParticleReduction(Prod, prod, valL *= myVal, std::multiplies)
315 : : } // namespace ippl
|