IPPL API Reference
Independent Parallel Particle Layer C++ API
Loading...
Searching...
No Matches
FEMInterpolate.hpp
1#ifndef IPPL_FEMINTERPOLATE_H
2#define IPPL_FEMINTERPOLATE_H
3
4
5namespace ippl {
6
14 template <typename T, unsigned Dim>
15 KOKKOS_INLINE_FUNCTION void
17 const Vector<T, Dim>& origin,
18 const Vector<T, Dim>& x,
20 Vector<T, Dim>& xi) {
21
22 for (unsigned d = 0; d < Dim; ++d) {
23 const T s = (x[d] - origin[d]) / hr[d]; // To cell units
24 const size_t e = static_cast<size_t>(Kokkos::floor(s));
25 e_nd[d] = e;
26 xi[d] = s - static_cast<T>(e);
27 }
28 }
29
30
31 template<class View, class IVec, std::size_t... Is>
32 KOKKOS_INLINE_FUNCTION
33 auto view_ptr_impl(View& v, const IVec& I, std::index_sequence<Is...>)
34 -> decltype(&v(I[Is]...)) {
35 return &v(I[Is]...);
36 }
37
38 template<int D, class View, class IVec>
39 KOKKOS_INLINE_FUNCTION
40 auto view_ptr(View& v, const IVec& I)
41 -> decltype(view_ptr_impl(v, I, std::make_index_sequence<D>{})) {
42 return view_ptr_impl(v, I, std::make_index_sequence<D>{});
43 }
44
58 template <typename AttribIn, typename Field, typename PosAttrib, typename Space,
59 typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
60 inline void assemble_rhs_from_particles(const AttribIn& attrib, Field& f,
61 const PosAttrib& pp, const Space& space,
62 policy_type iteration_policy)
63 {
64 constexpr unsigned Dim = Field::dim;
65 using T = typename Field::value_type;
66 using view_type = typename Field::view_type;
67 using mesh_type = typename Field::Mesh_t;
68
69 static IpplTimings::TimerRef t = IpplTimings::getTimer("assemble_rhs_from_particles(P1)");
70
71 IpplTimings::startTimer(t);
72
73 view_type view = f.getView();
74
75 // Mesh / layout (for locating + indexing into the field view)
76 mesh_type& mesh = f.get_mesh();
77
78 const auto hr = mesh.getMeshSpacing();
79 const auto origin = mesh.getOrigin();
80
81 FieldLayout<Dim>& layout = f.getLayout();
82 const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
83 const int nghost = f.getNghost();
84
85 Field lumpedMass(mesh, layout);
86 space.evaluateLumpedMass(lumpedMass);
87
88 view_type view_lumpedmass = lumpedMass.getView();
89
90 // Particle attribute/device views
91 auto d_attr = attrib.getView(); // scalar weight per particle (e.g. charge)
92 auto d_pos = pp.getView(); // positions (Vector<T,Dim>) per particle
93
94 // make device copy of space
95 auto device_space = space.getDeviceMirror();
96
97 Kokkos::parallel_for("assemble_rhs_from_particles_P1", iteration_policy,
98 KOKKOS_LAMBDA(const size_t p) {
99 const Vector<T, Dim> x = d_pos(p);
100 const T val = d_attr(p);
101
104
105 locate_element_nd_and_xi<T, Dim>(hr, origin, x, e_nd, xi);
106
107 // DOFs for this element
108 const auto dofs = device_space.getGlobalDOFIndices(e_nd);
109
110 // Deposit into each vertex/DOF
111 for (size_t a = 0; a < dofs.dim; ++a) {
112 const size_t local = device_space.getLocalDOFIndex(e_nd, dofs[a]);
113 const T w = device_space.evaluateRefElementShapeFunction(local, xi);
114
115 // ND coords (global, vertex-centered)
116 const auto v_nd = device_space.getMeshVertexNDIndex(dofs[a]);
117 Vector<size_t, Dim> I; // indices into view
118
119 for (unsigned d = 0; d < Dim; ++d) {
120 I[d] = static_cast<size_t>(v_nd[d] - lDom[d].first() + nghost);
121 }
122 const T m = apply(view_lumpedmass, I);
123
124 Kokkos::atomic_add(view_ptr<Dim>(view, I), val * w / m);
125 }
126 }
127 );
128
129 static IpplTimings::TimerRef accumulateHaloTimer = IpplTimings::getTimer("accumulateHalo");
130 IpplTimings::startTimer(accumulateHaloTimer);
131 f.accumulateHalo();
132 IpplTimings::stopTimer(accumulateHaloTimer);
133
134 }
135
136 template<class View, class IVec, std::size_t... Is>
137 KOKKOS_INLINE_FUNCTION
138 decltype(auto) view_ref_impl(View& v, const IVec& I, std::index_sequence<Is...>) {
139 return v(I[Is]...);
140 }
141
142 template<int D, class View, class IVec>
143 KOKKOS_INLINE_FUNCTION
144 decltype(auto) view_ref(View& v, const IVec& I) {
145 return view_ref_impl(v, I, std::make_index_sequence<D>{});
146 }
147
161 template <typename AttribOut, typename Field, typename PosAttrib, typename Space,
162 typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
163 inline void interpolate_to_diracs(AttribOut& attrib_out,
164 const Field& coeffs,
165 const PosAttrib& pp,
166 const Space& space,
167 policy_type iteration_policy)
168 {
169 constexpr unsigned Dim = Field::dim;
170 using T = typename AttribOut::value_type;
171 using field_value_type = typename Field::value_type;
172 using view_type = typename Field::view_type;
173 using mesh_type = typename Field::Mesh_t;
174
175 static IpplTimings::TimerRef timer =
176 IpplTimings::getTimer("interpolate_field_to_particles(P1)");
177 IpplTimings::startTimer(timer);
178
179 view_type view = coeffs.getView();
180 const mesh_type& mesh = coeffs.get_mesh();
181
182 const auto hr = mesh.getMeshSpacing();
183 const auto origin = mesh.getOrigin();
184
185 const FieldLayout<Dim>& layout = coeffs.getLayout();
186 const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
187 const int nghost = coeffs.getNghost();
188
189 // Particle device views
190 auto d_pos = pp.getView();
191 auto d_out = attrib_out.getView();
192
193 // make device copy of space
194 auto device_space = space.getDeviceMirror();
195
196 Kokkos::parallel_for("interpolate_to_diracs_P1", iteration_policy,
197 KOKKOS_LAMBDA(const size_t p) {
198
199 const Vector<T, Dim> x = d_pos(p);
200
203 locate_element_nd_and_xi<T, Dim>(hr, origin, x, e_nd, xi);
204
205 const auto dofs = device_space.getGlobalDOFIndices(e_nd);
206
207 field_value_type up = field_value_type(0);
208
209 for (size_t a = 0; a < dofs.dim; ++a) {
210 const size_t local = device_space.getLocalDOFIndex(e_nd, dofs[a]);
211 const field_value_type w = device_space.evaluateRefElementShapeFunction(local, xi);
212
213 const auto v_nd = device_space.getMeshVertexNDIndex(dofs[a]);
215 for (unsigned d = 0; d < Dim; ++d) {
216 I[d] = static_cast<size_t>(v_nd[d] - lDom.first()[d] + nghost);
217 }
218
219 up += view_ref<Dim>(view, I) * w;
220 }
221 d_out(p) = static_cast<T>(up);
222 });
223 }
224
238 template <typename AttribOut, typename Field, typename PosAttrib, typename Space,
239 typename policy_type = Kokkos::RangePolicy<typename Field::execution_space>>
240 inline void interpolate_grad_to_diracs(AttribOut& attrib_out,
241 const Field& coeffs,
242 const PosAttrib& pp,
243 const Space& space,
244 policy_type iteration_policy)
245 {
246 constexpr unsigned Dim = Field::dim;
247 using T = typename Field::value_type;
248 using view_type = typename Field::view_type;
249 using mesh_type = typename Field::Mesh_t;
250
251 static IpplTimings::TimerRef timer =
252 IpplTimings::getTimer("interpolate_field_to_particles(P1)");
253 IpplTimings::startTimer(timer);
254
255 // Compute Inverse Transpose Transformation Jacobian ()
256 const auto firstElementVertexPoints = space.getElementMeshVertexPoints(Vector<size_t, Dim>(0));
257 const Vector<T, Dim> DPhiInvT =
258 space.getInverseTransposeTransformationJacobian(firstElementVertexPoints);
259
260 view_type view = coeffs.getView();
261 const mesh_type& mesh = coeffs.get_mesh();
262
263 const auto hr = mesh.getMeshSpacing();
264 const auto origin = mesh.getOrigin();
265
266 const FieldLayout<Dim>& layout = coeffs.getLayout();
267 const NDIndex<Dim>& lDom = layout.getLocalNDIndex();
268 const int nghost = coeffs.getNghost();
269
270 // Particle device views
271 auto d_pos = pp.getView();
272 auto d_out = attrib_out.getView();
273
274 // make device copy of space
275 auto device_space = space.getDeviceMirror();
276
277 Kokkos::parallel_for("interpolate_to_diracs_P1", iteration_policy,
278 KOKKOS_LAMBDA(const size_t p) {
279
280 const Vector<T, Dim> x = d_pos(p);
281
284 locate_element_nd_and_xi<T, Dim>(hr, origin, x, e_nd, xi);
285
286 const auto dofs = device_space.getGlobalDOFIndices(e_nd);
287
288 Vector<T, Dim> up(0.0);
289
290 for (size_t a = 0; a < dofs.dim; ++a) {
291 const size_t local = device_space.getLocalDOFIndex(e_nd, dofs[a]);
292 Vector<T, Dim> w = device_space.evaluateRefElementShapeFunctionGradient(local, xi);
293 w = DPhiInvT * w;
294
295 const auto v_nd = device_space.getMeshVertexNDIndex(dofs[a]);
297 for (unsigned d = 0; d < Dim; ++d) {
298 I[d] = static_cast<size_t>(v_nd[d] - lDom.first()[d] + nghost);
299 }
300
301 // negative as E = -grad(phi), but in the future this should be
302 // more general (maybe bool to say whether we want negative or positive?)
303 up += -(view_ref<Dim>(view, I) * w);
304 }
305 d_out(p) = up;
306 });
307 }
308
309} // namespace ippl
310#endif
Definition FieldLayout.h:166
Definition NDIndex.h:21
Definition Vector.h:23
Definition Archive.h:20
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
Definition IpplOperations.h:64
void interpolate_grad_to_diracs(AttribOut &attrib_out, const Field &coeffs, const PosAttrib &pp, const Space &space, policy_type iteration_policy)
Interpolate a P1 FEM field gradient to particle positions.
Definition FEMInterpolate.hpp:240
void assemble_rhs_from_particles(const AttribIn &attrib, Field &f, const PosAttrib &pp, const Space &space, policy_type iteration_policy)
Assemble a P1 FEM load vector (RHS) from particle attributes.
Definition FEMInterpolate.hpp:60
void interpolate_to_diracs(AttribOut &attrib_out, const Field &coeffs, const PosAttrib &pp, const Space &space, policy_type iteration_policy)
Interpolate a P1 FEM field to particle positions.
Definition FEMInterpolate.hpp:163
KOKKOS_INLINE_FUNCTION void locate_element_nd_and_xi(const Vector< T, Dim > &hr, const Vector< T, Dim > &origin, const Vector< T, Dim > &x, Vector< size_t, Dim > &e_nd, Vector< T, Dim > &xi)
Mapping from global position to element ND index and reference coordinates (xi ∈ [0,...
Definition FEMInterpolate.hpp:16