ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
interpolation.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010-2022 The ESPResSo project
3 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010
4 * Max-Planck-Institute for Polymer Research, Theory Group
5 *
6 * This file is part of ESPResSo.
7 *
8 * ESPResSo is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * ESPResSo is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
24#include <config/config.hpp>
25
26#include <utils/index.hpp>
28
29#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
30#include <Kokkos_Core.hpp>
31#endif
32
33#include <algorithm>
34#include <cassert>
35#include <cstddef>
36#include <iterator>
37#include <span>
38#include <tuple>
39#include <utility>
40#include <vector>
41
42/**
43 * @brief Interpolation weights for one point.
44 *
45 * Interpolation weights and grid offset for one point.
46 *
47 * @tparam cao Interpolation order.
48 */
49template <int cao> struct InterpolationWeights {
50 /** Linear index of the corner of the interpolation cube. */
51 int ind;
52 /** Weights for the directions */
54};
55
56template <int cao> struct InterpolationWeightsView {
57 /** Linear index of the corner of the interpolation cube. */
58 int ind;
59 /** Weights for the directions */
60 std::span<double const, cao> w_x, w_y, w_z;
61};
62
63/**
64 * @brief Cache for interpolation weights.
65 *
66 * This is a storage container for interpolation weights of
67 * type InterpolationWeights.
68 */
70 int m_cao = 0;
71 /** Charge fractions for mesh assignment. */
72#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
74 std::vector<double> ca_frac_spillover;
75#else
76 std::vector<double> ca_frac;
77#endif
78 /** index of first mesh point for charge assignment. */
79#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
81 std::vector<int> ca_fmp_spillover;
82#else
83 std::vector<int> ca_fmp;
84#endif
85
86public:
87#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
89 : ca_frac("p3m_interpolation_cache::ca_frac", 0, 0),
90 ca_fmp("p3m_interpolation_cache::ca_fmp", 0, 0) {}
91#endif
92
93 /**
94 * @brief Number of points in the cache.
95 * @return Number of points currently in the cache.
96 */
97 auto size() const {
98#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
99 return ca_fmp.size() + ca_fmp_spillover.size();
100#else
101 return ca_fmp.size();
102#endif
103 }
104
105 /**
106 * @brief Charge assignment order the weights are for.
107 * @return The charge assignment order.
108 */
109 auto cao() const { return m_cao; }
110
111 /**
112 * @brief Fill cache with zero-initialized data.
113 * Meant for the parallel weight interpolation calculation.
114 * @param size Number of elements.
115 */
116 void zfill(std::size_t size) {
117 auto const size_frac = size * static_cast<std::size_t>(m_cao * 3);
118#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
119 if (ca_fmp.size() != size or ca_frac.size() != size_frac) {
120 Kokkos::realloc(Kokkos::WithoutInitializing, ca_fmp, size);
121 Kokkos::realloc(Kokkos::WithoutInitializing, ca_frac, size_frac);
122 }
123 assert(ca_frac_spillover.empty());
124 assert(ca_fmp_spillover.empty());
125 // data must be contiguous in memory
126 assert(size == 0 or
127 (std::distance(&ca_fmp(0), &ca_fmp(size - 1)) == size - 1));
128#else
129 assert(ca_frac.empty());
130 assert(ca_fmp.empty());
131 ca_fmp.resize(size);
132 ca_frac.resize(size_frac);
133#endif
134 }
135
136 /**
137 * @brief Push back weights for one point.
138 *
139 * @tparam cao Interpolation order has to match the order
140 * set at last call to @ref p3m_interpolation_cache::reset.
141 * @param weights Interpolation weights to store.
142 */
143 template <int cao> void store(InterpolationWeights<cao> const &weights) {
144 assert(cao == m_cao);
145
146#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
147 ca_fmp_spillover.emplace_back(weights.ind);
148 auto it = std::back_inserter(ca_frac_spillover);
149 std::ranges::copy(weights.w_x, it);
150 std::ranges::copy(weights.w_y, it);
151 std::ranges::copy(weights.w_z, it);
152#else
153 ca_fmp.emplace_back(weights.ind);
154 auto it = std::back_inserter(ca_frac);
155 std::ranges::copy(weights.w_x, it);
156 std::ranges::copy(weights.w_y, it);
157 std::ranges::copy(weights.w_z, it);
158#endif
159 }
160
161 /**
162 * @brief Insert weights for one point.
163 *
164 * @tparam cao Interpolation order has to match the order
165 * set at last call to @ref p3m_interpolation_cache::reset.
166 * @param p_index Particle index.
167 * @param weights Interpolation weights to store.
168 */
169 template <int cao>
170 void store_at(std::size_t p_index, InterpolationWeights<cao> const &weights) {
171 assert(cao == m_cao);
172 assert(p_index < ca_fmp.size());
173
174 auto copy_weights = [](InterpolationWeights<cao> const &src, auto dst) {
175 std::copy_n(src.w_x.data(), cao, dst);
176 std::advance(dst, cao);
177 std::copy_n(src.w_y.data(), cao, dst);
178 std::advance(dst, cao);
179 std::copy_n(src.w_z.data(), cao, dst);
180 };
181
182#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
183 ca_fmp(p_index) = weights.ind;
184#else
185 ca_fmp[p_index] = weights.ind;
186#endif
187 auto const offset = p_index * static_cast<std::size_t>(cao * 3);
188 copy_weights(weights, ca_frac.data() + offset);
189 }
190
191 /**
192 * @brief Load entry from the cache.
193 *
194 * This loads an entry at an index from the cache,
195 * the entries are indexed by the order they were stored.
196 *
197 * @tparam cao Interpolation order has to match the order
198 * set at last call to @ref p3m_interpolation_cache::reset.
199 * @param p_index Index of the entry to load.
200 * @return Interpolation weights.
201 */
202 template <int cao>
204 assert(cao == m_cao);
205 assert(p_index < size());
206
207 int index = -1;
208 double const *ptr = nullptr;
209#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
210 if (p_index >= ca_fmp.size()) {
211 p_index -= ca_fmp.size();
212 index = ca_fmp_spillover[p_index];
213 auto const offset = p_index * static_cast<std::size_t>(cao * 3);
214 ptr = std::as_const(ca_frac_spillover).data() + offset;
215 } else {
216 index = ca_fmp(p_index);
217 auto const offset = p_index * static_cast<std::size_t>(cao * 3);
218 ptr = std::as_const(ca_frac).data() + offset;
219 }
220#else
221 index = ca_fmp[p_index];
222 auto const offset = p_index * static_cast<std::size_t>(cao * 3);
223 ptr = std::as_const(ca_frac).data() + offset;
224#endif
225 std::span<double const, cao> w_x(ptr, cao);
226 std::advance(ptr, cao);
227 std::span<double const, cao> w_y(ptr, cao);
228 std::advance(ptr, cao);
229 std::span<double const, cao> w_z(ptr, cao);
230 return {index, w_x, w_y, w_z};
231 }
232
233 /**
234 * @brief Reset the cache.
235 *
236 * @param cao Interpolation order.
237 */
238 void reset(int cao) {
239 m_cao = cao;
240#ifdef ESPRESSO_SHARED_MEMORY_PARALLELISM
241 Kokkos::realloc(Kokkos::WithoutInitializing, ca_fmp, 0ul);
242 Kokkos::realloc(Kokkos::WithoutInitializing, ca_frac, 0ul);
243 ca_frac_spillover.clear();
244 ca_fmp_spillover.clear();
245#else
246 ca_frac.clear();
247 ca_fmp.clear();
248#endif
249 }
250};
251
252/**
253 * @brief Calculate the P-th order interpolation weights.
254 *
255 * As described in from @cite hockney88a 5-189 (or 8-61).
256 * The weights are also tabulated in @cite deserno98a @cite deserno98b.
257 */
258template <int cao, Utils::MemoryOrder memory_order>
261 const Utils::Vector3d &ai,
262 P3MLocalMesh const &local_mesh) {
263 /** position shift for calc. of first assignment mesh point. */
264 auto const pos_shift = std::floor((cao - 1) / 2.0) - (cao % 2) / 2.0;
265
266 /* distance to nearest mesh point */
268
269 /* nearest mesh point */
271
272 for (unsigned int d = 0; d < 3; d++) {
273 /* particle position in mesh coordinates */
274 auto const pos = ((position[d] - local_mesh.ld_pos[d]) * ai[d]) - pos_shift;
275
276 nmp[d] = static_cast<int>(pos);
277
278 /* distance to nearest mesh point */
279 dist[d] = (pos - nmp[d]) - 0.5;
280 }
281
283
284 /* 3d-array index of nearest mesh point */
285 ret.ind = Utils::get_linear_index<memory_order>(nmp, local_mesh.dim);
286
287 assert((nmp + Utils::Vector3i::broadcast(cao)) <= local_mesh.dim);
288 for (int i = 0; i < cao; i++) {
289 using Utils::bspline;
290
291 ret.w_x[i] = bspline<cao>(i, dist[0]);
292 ret.w_y[i] = bspline<cao>(i, dist[1]);
293 ret.w_z[i] = bspline<cao>(i, dist[2]);
294 }
295
296 return ret;
297}
298
299/**
300 * @brief P3M grid interpolation.
301 *
302 * This runs an kernel for every interpolation point
303 * in a set of interpolation weights with the linear
304 * grid index and the weight of the point as arguments.
305 *
306 * @param local_mesh Mesh info.
307 * @param weights Set of weights
308 * @param kernel The kernel to run.
309 */
310template <int cao, template <int> class WeightsStorage, class Kernel>
311void p3m_interpolate(P3MLocalMesh const &local_mesh,
312 WeightsStorage<cao> const &weights, Kernel kernel) {
313 auto q_ind = weights.ind;
314 for (int i0 = 0; i0 < cao; i0++) {
315 auto const w_x = weights.w_x[i0];
316 for (int i1 = 0; i1 < cao; i1++) {
317 auto const w_xy = w_x * weights.w_y[i1];
318 for (int i2 = 0; i2 < cao; i2++) {
319 auto const w_xyz = w_xy * weights.w_z[i2];
320 kernel(q_ind, w_xyz);
321 q_ind++;
322 }
323 q_ind += local_mesh.q_2_off;
324 }
325 q_ind += local_mesh.q_21_off;
326 }
327}
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value) noexcept
Create a vector that has all entries set to the same value.
Definition Vector.hpp:132
Cache for interpolation weights.
void zfill(std::size_t size)
Fill cache with zero-initialized data.
void store(InterpolationWeights< cao > const &weights)
Push back weights for one point.
void store_at(std::size_t p_index, InterpolationWeights< cao > const &weights)
Insert weights for one point.
auto cao() const
Charge assignment order the weights are for.
void reset(int cao)
Reset the cache.
InterpolationWeightsView< cao > load(std::size_t p_index) const
Load entry from the cache.
auto size() const
Number of points in the cache.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
InterpolationWeights< cao > p3m_calculate_interpolation_weights(const Utils::Vector3d &position, const Utils::Vector3d &ai, P3MLocalMesh const &local_mesh)
Calculate the P-th order interpolation weights.
void p3m_interpolate(P3MLocalMesh const &local_mesh, WeightsStorage< cao > const &weights, Kernel kernel)
P3M grid interpolation.
DEVICE_QUALIFIER auto bspline(int i, T x) -> T requires((order > 0) and(order<=7))
Formula of the B-spline.
Definition bspline.hpp:43
int ind
Linear index of the corner of the interpolation cube.
std::span< double const, cao > w_z
std::span< double const, cao > w_x
Weights for the directions.
std::span< double const, cao > w_y
Interpolation weights for one point.
Utils::Array< double, cao > w_y
Utils::Array< double, cao > w_x
Weights for the directions.
int ind
Linear index of the corner of the interpolation cube.
Utils::Array< double, cao > w_z
Properties of the local mesh.
Utils::Vector3i dim
dimension (size) of local mesh including halo layers.
int q_2_off
offset between mesh lines of the last dimension
Utils::Vector3d ld_pos
position of the first local mesh point.
int q_21_off
offset between mesh lines of the two last dimensions