IPPL API Reference
Independent Parallel Particle Layer C++ API
Loading...
Searching...
No Matches
ParticleAttrib.hpp
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
22namespace ippl {
23
24 template <typename T, class... Properties>
25 void ParticleAttrib<T, Properties...>::create(size_type n, bool non_destructive) {
26 size_type required = *(this->localNum_mp) + n;
27 if (this->size() < required) {
28 int overalloc = Comm->getDefaultOverallocation();
29 if (non_destructive) {
30 // Kokkos::resize preserves existing entries when growing.
31 this->resize(required * overalloc);
32 } else {
33 // Kokkos::realloc is destructive (free + alloc, no copy).
34 this->realloc(required * overalloc);
35 }
36 }
37 }
38
39 template <typename T, class... Properties>
41 int overalloc = Comm->getDefaultOverallocation();
42 this->realloc(n * overalloc);
43 }
44
45 template <typename T, class... Properties>
46 void ParticleAttrib<T, Properties...>::destroy(const hash_type& deleteIndex,
47 const hash_type& keepIndex,
48 size_type invalidCount) {
49 // Replace all invalid particles in the valid region with valid
50 // particles in the invalid region
51 auto dview = dview_m;
52 using policy_type = Kokkos::RangePolicy<execution_space>;
53 Kokkos::parallel_for(
54 "ParticleAttrib::destroy()", policy_type(0, invalidCount),
55 KOKKOS_LAMBDA(const size_t i) {
56 dview(deleteIndex(i)) = dview(keepIndex(i));
57 });
58 }
59
60 template <typename T, class... Properties>
61 void ParticleAttrib<T, Properties...>::pack(const hash_type& hash) {
62 auto size = hash.extent(0);
63 if (buf_m.extent(0) < size) {
64 int overalloc = Comm->getDefaultOverallocation();
65 Kokkos::realloc(buf_m, size * overalloc);
66 }
67
68 auto buf = buf_m;
69 auto dview = dview_m;
70 using policy_type = Kokkos::RangePolicy<execution_space>;
71 Kokkos::parallel_for(
72 "ParticleAttrib::pack()", policy_type(0, size),
73 KOKKOS_LAMBDA(const size_t i) { buf(i) = dview(hash(i)); });
74 Kokkos::fence();
75 }
76
77 template <typename T, class... Properties>
78 void ParticleAttrib<T, Properties...>::unpack(size_type nrecvs) {
79 auto size = dview_m.extent(0);
80 size_type required = *(this->localNum_mp) + nrecvs;
81 if (size < required) {
82 int overalloc = Comm->getDefaultOverallocation();
83 this->resize(required * overalloc);
84 }
85
86 size_type count = *(this->localNum_mp);
87 auto buf = buf_m;
88 auto dview = dview_m;
89 using policy_type = Kokkos::RangePolicy<execution_space>;
90 Kokkos::parallel_for(
91 "ParticleAttrib::unpack()", policy_type(0, nrecvs),
92 KOKKOS_LAMBDA(const size_t i) { dview(count + i) = buf(i); });
93 Kokkos::fence();
94 }
95
96 template <typename T, class... Properties>
97 // KOKKOS_INLINE_FUNCTION
99 auto dview = dview_m;
100 using policy_type = Kokkos::RangePolicy<execution_space>;
101 Kokkos::parallel_for(
102 "ParticleAttrib::operator=()", policy_type(0, *(this->localNum_mp)),
103 KOKKOS_LAMBDA(const size_t i) { dview(i) = x; });
104 return *this;
105 }
106
107 template <typename T, class... Properties>
108 template <typename E, size_t N>
109 // KOKKOS_INLINE_FUNCTION
111 detail::Expression<E, N> const& expr) {
112 using capture_type = detail::CapturedExpression<E, N>;
113 capture_type expr_ = reinterpret_cast<const capture_type&>(expr);
114
115 auto dview = dview_m;
116 using policy_type = Kokkos::RangePolicy<execution_space>;
117 Kokkos::parallel_for(
118 "ParticleAttrib::operator=()", policy_type(0, *(this->localNum_mp)),
119 KOKKOS_LAMBDA(const size_t i) { dview(i) = expr_(i); });
120 return *this;
121 }
122
123 template <typename T, class... Properties>
124 template <typename Field, class PT, typename policy_type>
126 Field& f, const ParticleAttrib<Vector<PT, Field::dim>, Properties...>& pp,
127 policy_type iteration_policy, hash_type hash_array) const {
128 constexpr unsigned Dim = Field::dim;
129 using PositionType = typename Field::Mesh_t::value_type;
130
131 static IpplTimings::TimerRef scatterTimer = IpplTimings::getTimer("scatter");
132 IpplTimings::startTimer(scatterTimer);
133 using view_type = typename Field::view_type;
134 view_type view = f.getView();
135
136 using mesh_type = typename Field::Mesh_t;
137 const mesh_type& mesh = f.get_mesh();
138
139 using vector_type = typename mesh_type::vector_type;
140 using value_type = typename ParticleAttrib<T, Properties...>::value_type;
141
142 const vector_type& dx = mesh.getMeshSpacing();
143 const vector_type& origin = mesh.getOrigin();
144 const vector_type invdx = 1.0 / dx;
145
146 const FieldLayout<Dim>& layout = f.getLayout();
147 const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
148 const int nghost = f.getNghost();
149
150 //using policy_type = Kokkos::RangePolicy<execution_space>;
151 const bool useHashView = hash_array.extent(0) > 0;
152 if (useHashView && (iteration_policy.end() > hash_array.extent(0))) {
153 Inform m("scatter");
154 m << "Hash array was passed to scatter, but size does not match iteration policy." << endl;
155 ippl::Comm->abort();
156 }
157 auto dview = dview_m;
158 auto ppview = pp.getView();
159 Kokkos::parallel_for(
160 "ParticleAttrib::scatter", iteration_policy,
161 KOKKOS_LAMBDA(const size_t idx) {
162 // map index to possible hash_map
163 size_t mapped_idx = useHashView ? hash_array(idx) : idx;
164
165 // find nearest grid point
166 vector_type l = (ppview(mapped_idx) - origin) * invdx + 0.5;
167 Vector<int, Field::dim> index = l;
168 Vector<PositionType, Field::dim> whi = l - index;
169 Vector<PositionType, Field::dim> wlo = 1.0 - whi;
170
171 Vector<size_t, Field::dim> args = index - lDom.first() + nghost;
172
173 // scatter
174 const value_type& val = dview(mapped_idx);
175 detail::scatterToField(std::make_index_sequence<1 << Field::dim>{}, view, wlo, whi,
176 args, val);
177 });
178 IpplTimings::stopTimer(scatterTimer);
179
180 static IpplTimings::TimerRef accumulateHaloTimer = IpplTimings::getTimer("accumulateHalo");
181 IpplTimings::startTimer(accumulateHaloTimer);
182 f.accumulateHalo();
183 IpplTimings::stopTimer(accumulateHaloTimer);
184 }
185
186 template <typename T, class... Properties>
187 template <typename Field, typename P2>
189 Field& f, const ParticleAttrib<Vector<P2, Field::dim>, Properties...>& pp,
190 const bool addToAttribute) {
191 constexpr unsigned Dim = Field::dim;
192 using PositionType = typename Field::Mesh_t::value_type;
193
194 static IpplTimings::TimerRef fillHaloTimer = IpplTimings::getTimer("fillHalo");
195 IpplTimings::startTimer(fillHaloTimer);
196 f.fillHalo();
197 IpplTimings::stopTimer(fillHaloTimer);
198
199 static IpplTimings::TimerRef gatherTimer = IpplTimings::getTimer("gather");
200 IpplTimings::startTimer(gatherTimer);
201 const typename Field::view_type view = f.getView();
202
203 using mesh_type = typename Field::Mesh_t;
204 const mesh_type& mesh = f.get_mesh();
205
206 using vector_type = typename mesh_type::vector_type;
207
208 const vector_type& dx = mesh.getMeshSpacing();
209 const vector_type& origin = mesh.getOrigin();
210 const vector_type invdx = 1.0 / dx;
211
212 const FieldLayout<Dim>& layout = f.getLayout();
213 const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
214 const int nghost = f.getNghost();
215
216 auto dview = dview_m;
217 auto ppview = pp.getView();
218 using policy_type = Kokkos::RangePolicy<execution_space>;
219 Kokkos::parallel_for(
220 "ParticleAttrib::gather", policy_type(0, *(this->localNum_mp)),
221 KOKKOS_LAMBDA(const size_t idx) {
222 // find nearest grid point
223 vector_type l = (ppview(idx) - origin) * invdx + 0.5;
224 Vector<int, Field::dim> index = l;
225 Vector<PositionType, Field::dim> whi = l - index;
226 Vector<PositionType, Field::dim> wlo = 1.0 - whi;
228 Vector<size_t, Field::dim> args = index - lDom.first() + nghost;
229
230 // gather
231 value_type gathered = detail::gatherFromField(std::make_index_sequence<1 << Field::dim>{},
232 view, wlo, whi, args);
233 if (addToAttribute) {
234 dview(idx) += gathered;
235 } else {
236 dview(idx) = gathered;
237 }
238 });
239 IpplTimings::stopTimer(gatherTimer);
240 }
241
242 template <typename T, class... Properties>
244 const hash_type& permutation) {
245
246 const auto view = this->getView();
247 const auto size = this->getParticleCount();
248
249 view_type temp("copy", size);
250
251 using policy_type = Kokkos::RangePolicy<execution_space>;
252 Kokkos::parallel_for(
253 "Copy to temp", policy_type(0, size),
254 KOKKOS_LAMBDA(const size_type& i) { temp(permutation(i)) = view(i); });
255
256 Kokkos::fence();
257
258 Kokkos::deep_copy(Kokkos::subview(view, Kokkos::make_pair<size_type, size_type>(0, size)), temp);
259 }
260
261 template<typename T, class... Properties>
263 const hash_type &indices) {
264 auto copySize = indices.size();
265 create(copySize);
266
267 auto view = this->getView();
268 const auto size = this->getParticleCount();
269
270 using policy_type = Kokkos::RangePolicy<execution_space>;
271 Kokkos::parallel_for(
272 "Copy to temp", policy_type(0, copySize),
273 KOKKOS_LAMBDA(const size_type &i) {
274 view(size + i) = view(i);
275 });
276
277 Kokkos::fence();
278 }
279
280 /*
281 * Non-class function
282 *
283 */
284
301 template <typename Attrib1, typename Field, typename Attrib2,
302 typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
303 inline void scatter(const Attrib1& attrib, Field& f, const Attrib2& pp) {
304 attrib.scatter(f, pp, policy_type(0, attrib.getParticleCount()));
305 }
306
325 template <typename Attrib1, typename Field, typename Attrib2,
326 typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
327 inline void scatter(const Attrib1& attrib, Field& f, const Attrib2& pp,
328 policy_type iteration_policy, typename Attrib1::hash_type hash_array = {}) {
329 attrib.scatter(f, pp, iteration_policy, hash_array);
330 }
331
349 template <typename Attrib1, typename Field, typename Attrib2>
350 inline void gather(Attrib1& attrib, Field& f, const Attrib2& pp,
351 const bool addToAttribute = false) {
352 attrib.gather(f, pp, addToAttribute);
353 }
354
355#define DefineParticleReduction(fun, name, op, MPI_Op) \
356 template <typename T, class... Properties> \
357 T ParticleAttrib<T, Properties...>::name() { \
358 T temp = 0.0; \
359 auto dview = dview_m; \
360 using policy_type = Kokkos::RangePolicy<execution_space>; \
361 Kokkos::parallel_reduce( \
362 "fun", policy_type(0, *(this->localNum_mp)), \
363 KOKKOS_LAMBDA(const size_t i, T& valL) { \
364 T myVal = dview(i); \
365 op; \
366 }, \
367 Kokkos::fun<T>(temp)); \
368 T globaltemp = 0.0; \
369 Comm->allreduce(temp, globaltemp, 1, MPI_Op<T>()); \
370 return globaltemp; \
371 }
372
373 DefineParticleReduction(Sum, sum, valL += myVal, std::plus)
374 DefineParticleReduction(Max, max, if (myVal > valL) valL = myVal, std::greater)
375 DefineParticleReduction(Min, min, if (myVal < valL) valL = myVal, std::less)
376 DefineParticleReduction(Prod, prod, valL *= myVal, std::multiplies)
377} // namespace ippl
Definition Inform.h:40
Definition FieldLayout.h:166
Definition Field.h:18
Definition NDIndex.h:21
Definition ParticleAttrib.h:33
void destroy(const hash_type &deleteIndex, const hash_type &keepIndex, size_type invalidCount) override
Definition ParticleAttrib.hpp:46
void internalCopy(const hash_type &indices) override
Copy and create values of given indices.
Definition ParticleAttrib.hpp:262
void scatter(Field &f, const ParticleAttrib< Vector< P2, Field::dim >, Properties... > &pp, policy_type iteration_policy, hash_type hash_array={}) const
Scatter particle attribute data onto a field.
void gather(Field &f, const ParticleAttrib< Vector< P2, Field::dim >, Properties... > &pp, const bool addToAttribute=false)
Gather field data into the particle attribute.
Definition ParticleAttrib.hpp:188
void applyPermutation(const hash_type &permutation) override
Sort the attribute according to a permutation.
Definition ParticleAttrib.hpp:243
ParticleAttrib< T, Properties... > & operator=(T x)
Definition ParticleAttrib.hpp:98
Definition Vector.h:23
Definition Archive.h:20
void gather(Attrib1 &attrib, Field &f, const Attrib2 &pp, const bool addToAttribute=false)
Non-class interface for gathering field data into a particle attribute.
Definition ParticleAttrib.hpp:350
void scatter(const Attrib1 &attrib, Field &f, const Attrib2 &pp)
Non-class interface for scattering particle attribute data onto a field.
Definition ParticleAttrib.hpp:303
Definition IpplExpressions.h:44
Definition IpplExpressions.h:26