Cholla 3.0.1-dev
Cholla - Massively parallel hydro on GPUs
Loading...
Searching...
No Matches
HenryPeriodic.hpp
1#pragma once
2
3#include <mpi.h>
4
5#include <algorithm>
6
7#include "../../utils/gpu.hpp"
8
13{
14 public:
27 HenryPeriodic(const int n[3], const double lo[3], const double hi[3], const int m[3], const int id[3]);
28
30
34 size_t bytes() const { return bytes_; }
35
60 template <typename F>
61 void filter(const size_t bytes, double *const before, double *const after, const F f) const;
62
63 private:
64 int idi_, idj_, idk_;
65 int mi_, mj_, mk_;
66 int nh_;
68 int ni_, nj_, nk_;
69 int mp_, mq_;
70 int idp_, idq_;
71 MPI_Comm commI_, commJ_,
72 commK_;
73 int dh_, di_, dj_, dk_;
74 int dhq_, dip_, djp_,
75 djq_;
76 size_t bytes_;
77 cufftHandle c2ci_, c2cj_, c2rk_,
78 r2ck_;
79#ifndef MPI_GPU
80 double *ha_, *hb_;
81#endif
82};
83
84#if defined(__HIP__) || defined(__CUDACC__)
85
86template <typename F>
87void HenryPeriodic::filter(const size_t bytes, double *const before, double *const after, const F f) const
88{
89 // Make sure arguments have enough space
90 assert(bytes >= bytes_);
91
92 double *const a = after;
93 double *const b = before;
94 cufftDoubleComplex *const ac = reinterpret_cast<cufftDoubleComplex *>(a);
95 cufftDoubleComplex *const bc = reinterpret_cast<cufftDoubleComplex *>(b);
96
97 // Local copies of member variables for lambda capture
98
99 const int di = di_, dj = dj_, dk = dk_;
100 const int dhq = dhq_, dip = dip_, djp = djp_, djq = djq_;
101 const int idi = idi_, idj = idj_, idk = idk_;
102 const int idp = idp_, idq = idq_;
103 const int mi = mi_, mj = mj_, mk = mk_;
104 const int mp = mp_, mq = mq_;
105 const int nh = nh_, ni = ni_, nj = nj_, nk = nk_;
106
107 // Indices and sizes for pencil redistributions
108
109 const int idip = idi * mp + idp;
110 const int idjq = idj * mq + idq;
111 const int mip = mi * mp;
112 const int mjq = mj * mq;
113
114 // Reorder 3D block into sub-pencils
115
116 gpuFor(
117 mp, mq, dip, djq, dk, GPU_LAMBDA(const int p, const int q, const int i, const int j, const int k) {
118 const int ii = p * dip + i;
119 const int jj = q * djq + j;
120 const int ia = k + dk * (j + djq * (i + dip * (q + mq * p)));
121 const int ib = k + dk * (jj + dj * ii);
122 a[ia] = b[ib];
123 });
124
125 // Redistribute into Z pencils
126
127 const int countK = dip * djq * dk;
128 #ifndef MPI_GPU
129 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
130 MPI_Alltoall(ha_, countK, MPI_DOUBLE, hb_, countK, MPI_DOUBLE, commK_);
131 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
132 #else
133 GPU_Error_Check(cudaDeviceSynchronize());
134 MPI_Alltoall(a, countK, MPI_DOUBLE, b, countK, MPI_DOUBLE, commK_);
135 #endif
136
137 // Make Z pencils contiguous in Z
138 {
139 const int iLo = idi * di + idp * dip;
140 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
141 const int jLo = idj * dj + idq * djq;
142 const int jHi = std::min({jLo + djq, (idj + 1) * dj, nj});
143 gpuFor(
144 iHi - iLo, jHi - jLo, mk, dk, GPU_LAMBDA(const int i, const int j, const int pq, const int k) {
145 const int kk = pq * dk + k;
146 if (kk < nk) {
147 const int ia = kk + nk * (j + djq * i);
148 const int ib = k + dk * (j + djq * (i + dip * pq));
149 a[ia] = b[ib];
150 }
151 });
152 }
153
154 // Real-to-complex FFT in Z
155 GPU_Error_Check(cufftExecD2Z(r2ck_, a, bc));
156
157 // Rearrange for Y redistribution
158 {
159 const int iLo = idi * di + idp * dip;
160 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
161 const int jLo = idj_ * dj_ + idq * djq;
162 const int jHi = std::min({jLo + djq, (idj + 1) * dj, nj});
163 gpuFor(
164 mjq, iHi - iLo, jHi - jLo, dhq, GPU_LAMBDA(const int q, const int i, const int j, const int k) {
165 const int kk = q * dhq + k;
166 if (kk < nh) {
167 const int ia = k + dhq * (j + djq * (i + dip * q));
168 const int ib = kk + nh * (j + djq * i);
169 ac[ia] = bc[ib];
170 }
171 });
172 }
173
174 // Redistribute for Y pencils
175 const int countJ = 2 * dip * djq * dhq;
176 #ifndef MPI_GPU
177 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
178 MPI_Alltoall(ha_, countJ, MPI_DOUBLE, hb_, countJ, MPI_DOUBLE, commJ_);
179 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
180 #else
181 GPU_Error_Check(cudaDeviceSynchronize());
182 MPI_Alltoall(a, countJ, MPI_DOUBLE, b, countJ, MPI_DOUBLE, commJ_);
183 #endif
184
185 // Make Y pencils contiguous in Y
186 {
187 const int iLo = idi * di + idp * dip;
188 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
189 const int kLo = idjq * dhq;
190 const int kHi = std::min(kLo + dhq, nh);
191 gpuFor(
192 kHi - kLo, iHi - iLo, mj, mq, djq, GPU_LAMBDA(const int k, const int i, const int r, const int q, const int j) {
193 const int rdj = r * dj;
194 const int jj = rdj + q * djq + j;
195 if ((jj < nj) && (jj < rdj + dj)) {
196 const int ia = jj + nj * (i + dip * k);
197 const int ib = k + dhq * (j + djq * (i + dip * (q + mq * r)));
198 ac[ia] = bc[ib];
199 }
200 });
201 }
202
203 // Forward FFT in Y
204 GPU_Error_Check(cufftExecZ2Z(c2cj_, ac, bc, CUFFT_FORWARD));
205
206 // Rearrange for X redistribution
207 {
208 const int iLo = idi * di + idp * dip;
209 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
210 const int kLo = idjq * dhq;
211 const int kHi = std::min(kLo + dhq, nh);
212 gpuFor(
213 mip, kHi - kLo, iHi - iLo, djp, GPU_LAMBDA(const int p, const int k, const int i, const int j) {
214 const int jj = p * djp + j;
215 if (jj < nj) {
216 const int ia = j + djp * (i + dip * (k + dhq * p));
217 const int ib = jj + nj * (i + dip * k);
218 ac[ia] = bc[ib];
219 }
220 });
221 }
222
223 // Redistribute for X pencils
224 const int countI = 2 * dip * djp * dhq;
225 #ifndef MPI_GPU
226 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
227 MPI_Alltoall(ha_, countI, MPI_DOUBLE, hb_, countI, MPI_DOUBLE, commI_);
228 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
229 #else
230 GPU_Error_Check(cudaDeviceSynchronize());
231 MPI_Alltoall(a, countI, MPI_DOUBLE, b, countI, MPI_DOUBLE, commI_);
232 #endif
233
234 // Make X pencils contiguous in X
235 {
236 const int jLo = idip * djp;
237 const int jHi = std::min(jLo + djp, nj);
238 const int kLo = idjq * dhq;
239 const int kHi = std::min(kLo + dhq, nh);
240 gpuFor(
241 jHi - jLo, kHi - kLo, mi, mp, dip, GPU_LAMBDA(const int j, const int k, const int r, const int p, const int i) {
242 const int rdi = r * di;
243 const int ii = rdi + p * dip + i;
244 if ((ii < ni) && (ii < rdi + di)) {
245 const int ia = ii + ni * (k + dhq * j);
246 const int ib = j + djp * (i + dip * (k + dhq * (p + mp * r)));
247 ac[ia] = bc[ib];
248 }
249 });
250 }
251
252 // Forward FFT in X
253 GPU_Error_Check(cufftExecZ2Z(c2ci_, ac, bc, CUFFT_FORWARD));
254
255 // Apply filter in frequency space distributed in X pencils
256
257 const int jLo = idip * djp;
258 const int jHi = std::min(jLo + djp, nj);
259 const int kLo = idjq * dhq;
260 const int kHi = std::min(kLo + dhq, nh);
261
262 gpuFor(
263 jHi - jLo, kHi - kLo, ni, GPU_LAMBDA(const int j0, const int k0, const int i) {
264 const int j = jLo + j0;
265 const int k = kLo + k0;
266 const int iab = i + ni * (k0 + dhq * j0);
267 ac[iab] = f(i, j, k, bc[iab]);
268 });
269
270 // Backward FFT in X
271 GPU_Error_Check(cufftExecZ2Z(c2ci_, ac, bc, CUFFT_INVERSE));
272
273 // Rearrange for Y redistribution
274 {
275 const int jLo = idip * djp;
276 const int jHi = std::min(jLo + djp, nj);
277 const int kLo = idjq * dhq;
278 const int kHi = std::min(kLo + dhq, nh);
279 gpuFor(
280 mi, mp, jHi - jLo, kHi - kLo, dip, GPU_LAMBDA(const int r, const int p, const int j, const int k, const int i) {
281 const int rdi = r * di;
282 const int ii = rdi + p * dip + i;
283 if ((ii < ni) && (ii < rdi + di)) {
284 const int ia = i + dip * (k + dhq * (j + djp * (p + mp * r)));
285 const int ib = ii + ni * (k + dhq * j);
286 ac[ia] = bc[ib];
287 }
288 });
289 }
290
291 // Redistribute for Y pencils
292 #ifndef MPI_GPU
293 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
294 MPI_Alltoall(ha_, countI, MPI_DOUBLE, hb_, countI, MPI_DOUBLE, commI_);
295 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
296 #else
297 GPU_Error_Check(cudaDeviceSynchronize());
298 MPI_Alltoall(a, countI, MPI_DOUBLE, b, countI, MPI_DOUBLE, commI_);
299 #endif
300
301 // Make Y pencils contiguous in Y
302 {
303 const int iLo = idi * di + idp * dip;
304 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
305 const int kLo = idjq * dhq;
306 const int kHi = std::min(kLo + dhq, nh);
307 gpuFor(
308 kHi - kLo, iHi - iLo, mip, djp, GPU_LAMBDA(const int k, const int i, const int p, const int j) {
309 const int jj = p * djp + j;
310 if (jj < nj) {
311 const int ia = jj + nj * (i + dip * k);
312 const int ib = i + dip * (k + dhq * (j + djp * p));
313 ac[ia] = bc[ib];
314 }
315 });
316 }
317
318 // Backward FFT in Y
319 GPU_Error_Check(cufftExecZ2Z(c2cj_, ac, bc, CUFFT_INVERSE));
320
321 // Rearrange for Z redistribution
322 {
323 const int iLo = idi * di + idp * dip;
324 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
325 const int kLo = idjq * dhq;
326 const int kHi = std::min(kLo + dhq, nh);
327 gpuFor(
328 mj, mq, kHi - kLo, iHi - iLo, djq, GPU_LAMBDA(const int r, const int q, const int k, const int i, const int j) {
329 const int rdj = r * dj;
330 const int jj = rdj + q * djq + j;
331 if ((jj < nj) && (jj < rdj + dj)) {
332 const int ia = j + djq * (i + dip * (k + dhq * (q + mq * r)));
333 const int ib = jj + nj * (i + dip * k);
334 ac[ia] = bc[ib];
335 }
336 });
337 }
338
339 // Redistribute in Z pencils
340 #ifndef MPI_GPU
341 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
342 MPI_Alltoall(ha_, countJ, MPI_DOUBLE, hb_, countJ, MPI_DOUBLE, commJ_);
343 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
344 #else
345 GPU_Error_Check(cudaDeviceSynchronize());
346 MPI_Alltoall(a, countJ, MPI_DOUBLE, b, countJ, MPI_DOUBLE, commJ_);
347 #endif
348
349 // Make Z pencils contiguous in Z
350 {
351 const int iLo = idi * di + idp * dip;
352 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
353 const int jLo = idj * dj + idq * djq;
354 const int jHi = std::min({jLo + djq, (idj + 1) * dj, nj});
355 gpuFor(
356 iHi - iLo, jHi - jLo, mjq, dhq, GPU_LAMBDA(const int i, const int j, const int q, const int k) {
357 const int kk = q * dhq + k;
358 if (kk < nh) {
359 const int ia = kk + nh * (j + djq * i);
360 const int ib = j + djq * (i + dip * (k + dhq * q));
361 ac[ia] = bc[ib];
362 }
363 });
364 }
365
366 // Complex-to-real FFT in Z
367 GPU_Error_Check(cufftExecZ2D(c2rk_, ac, b));
368
369 // Rearrange for 3D-block redistribution
370 {
371 const int iLo = idi * di + idp * dip;
372 const int iHi = std::min({iLo + dip, (idi + 1) * di, ni});
373 const int jLo = idj * dj + idq * djq;
374 const int jHi = std::min({jLo + djq, (idj + 1) * dj, nj});
375 gpuFor(
376 mk, iHi - iLo, jHi - jLo, dk, GPU_LAMBDA(const int pq, const int i, const int j, const int k) {
377 const int kk = pq * dk + k;
378 if (kk < nk) {
379 const int ia = k + dk * (j + djq * (i + dip * pq));
380 const int ib = kk + nk * (j + djq * i);
381 a[ia] = b[ib];
382 }
383 });
384 }
385
386 // Redistribute for 3D blocks
387 #ifndef MPI_GPU
388 GPU_Error_Check(cudaMemcpy(ha_, a, bytes, cudaMemcpyDeviceToHost));
389 MPI_Alltoall(ha_, countK, MPI_DOUBLE, hb_, countK, MPI_DOUBLE, commK_);
390 GPU_Error_Check(cudaMemcpy(b, hb_, bytes, cudaMemcpyHostToDevice));
391 #else
392 GPU_Error_Check(cudaDeviceSynchronize());
393 MPI_Alltoall(a, countK, MPI_DOUBLE, b, countK, MPI_DOUBLE, commK_);
394 #endif
395
396 // Rearrange into 3D blocks and apply FFT normalization
397 {
398 const double divN = 1.0 / (double(ni) * double(nj) * double(nk));
399 const int kLo = idk * dk;
400 const int kHi = std::min(kLo + dk, nk);
401 gpuFor(
402 mp, dip, mq, djq, kHi - kLo, GPU_LAMBDA(const int p, const int i, const int q, const int j, const int k) {
403 const int ii = p * dip + i;
404 const int jj = q * djq + j;
405 if ((ii < di) && (jj < dj)) {
406 const int ia = k + dk * (jj + dj * ii);
407 const int ib = k + dk * (j + djq * (i + dip * (q + mq * p)));
408 a[ia] = divN * b[ib];
409 }
410 });
411 }
412}
413
414#endif
Generic distributed-memory 3D FFT filter.
Definition HenryPeriodic.hpp:13
HenryPeriodic(const int n[3], const double lo[3], const double hi[3], const int m[3], const int id[3])
size_t bytes() const
Definition HenryPeriodic.hpp:34
void filter(const size_t bytes, double *const before, double *const after, const F f) const