WarpX
Loading...
Searching...
No Matches
WarpXComm_K.H
Go to the documentation of this file.
1/* Copyright 2019 Axel Huebl, Weiqun Zhang
2 *
3 * This file is part of WarpX.
4 *
5 * License: BSD-3-Clause-LBNL
6 */
7#ifndef WARPX_COMM_K_H_
8#define WARPX_COMM_K_H_
9
10#include <AMReX.H>
11#include <AMReX_FArrayBox.H>
12
28void warpx_interp (int j, int k, int l,
29 amrex::Array4<amrex::Real > const& arr_aux,
31 amrex::Array4<amrex::Real const> const& arr_coarse,
32 const amrex::IntVect& arr_stag,
33 const amrex::IntVect& rr)
34{
35 using namespace amrex;
36
37 // Pad arr_coarse with zeros beyond ghost cells for out-of-bound accesses
38 const auto arr_coarse_zeropad = [arr_coarse] (const int jj, const int kk, const int ll) noexcept
39 {
40 return arr_coarse.contains(jj,kk,ll) ? arr_coarse(jj,kk,ll) : 0.0_rt;
41 };
42
43 // NOTE Indices (j,k,l) in the following refer to (z,-,-) in 1D, (x,z,-) in 2D, and (x,y,z) in 3D
44
45 // Refinement ratio
46 const int rj = rr[0];
47 const int rk = (AMREX_SPACEDIM > 1) ? rr[1] : 1;
48 const int rl = (AMREX_SPACEDIM > 2) ? rr[2] : 1;
49
50 // Staggering (0: cell-centered; 1: nodal)
51 // Unused dimensions are considered nodal.
52 const int sj = arr_stag[0];
53 const int sk = (AMREX_SPACEDIM > 1) ? arr_stag[1] : 1;
54 const int sl = (AMREX_SPACEDIM > 2) ? arr_stag[2] : 1;
55
56 // Number of points used for interpolation from coarse grid to fine grid
57 const int nj = 2;
58 const int nk = (AMREX_SPACEDIM > 1) ? 2 : 1;
59 const int nl = (AMREX_SPACEDIM > 2) ? 2 : 1;
60
61 const int jc = (sj == 0) ? amrex::coarsen(j - rj/2, rj) : amrex::coarsen(j, rj);
62 const int kc = (sk == 0) ? amrex::coarsen(k - rk/2, rk) : amrex::coarsen(k, rk);
63 const int lc = (sl == 0) ? amrex::coarsen(l - rl/2, rl) : amrex::coarsen(l, rl);
64
65 // Interpolate from coarse grid to fine grid using 2 points
66 // with weights depending on the distance, for both nodal and cell-centered grids
67 const amrex::Real hj = (sj == 0) ? 0.5_rt : 0._rt;
68 const amrex::Real hk = (sk == 0) ? 0.5_rt : 0._rt;
69 const amrex::Real hl = (sl == 0) ? 0.5_rt : 0._rt;
70
71 amrex::Real res = 0.0_rt;
72
73 for (int jj = 0; jj < nj; jj++) {
74 for (int kk = 0; kk < nk; kk++) {
75 for (int ll = 0; ll < nl; ll++) {
76 const amrex::Real wj = (rj - amrex::Math::abs(j + hj - (jc + jj + hj) * rj)) / static_cast<amrex::Real>(rj);
77 const amrex::Real wk = (rk - amrex::Math::abs(k + hk - (kc + kk + hk) * rk)) / static_cast<amrex::Real>(rk);
78 const amrex::Real wl = (rl - amrex::Math::abs(l + hl - (lc + ll + hl) * rl)) / static_cast<amrex::Real>(rl);
79 res += wj * wk * wl * arr_coarse_zeropad(jc+jj,kc+kk,lc+ll);
80 }
81 }
82 }
83 arr_aux(j,k,l) = arr_fine(j,k,l) + res;
84}
85
104void warpx_interp (int j, int k, int l,
105 amrex::Array4<amrex::Real > const& arr_aux,
106 amrex::Array4<amrex::Real const> const& arr_fine,
107 amrex::Array4<amrex::Real const> const& arr_coarse,
109 const amrex::IntVect& arr_fine_stag,
110 const amrex::IntVect& arr_coarse_stag,
111 const amrex::IntVect& rr)
112{
113 using namespace amrex;
114
115 // Pad input arrays with zeros beyond ghost cells
116 // for out-of-bound accesses due to large-stencil operations
117 const auto arr_fine_zeropad = [arr_fine] (const int jj, const int kk, const int ll) noexcept
118 {
119 return arr_fine.contains(jj,kk,ll) ? arr_fine(jj,kk,ll) : 0.0_rt;
120 };
121 const auto arr_coarse_zeropad = [arr_coarse] (const int jj, const int kk, const int ll) noexcept
122 {
123 return arr_coarse.contains(jj,kk,ll) ? arr_coarse(jj,kk,ll) : 0.0_rt;
124 };
125 const auto arr_tmp_zeropad = [arr_tmp] (const int jj, const int kk, const int ll) noexcept
126 {
127 return arr_tmp.contains(jj,kk,ll) ? arr_tmp(jj,kk,ll) : 0.0_rt;
128 };
129
130 // NOTE Indices (j,k,l) in the following refer to:
131 // - (z,-,-) in 1D
132 // - (x,z,-) in 2D
133 // - (r,z,-) in RZ
134 // - (x,y,z) in 3D
135
136 // Refinement ratio
137 const int rj = rr[0];
138 const int rk = (AMREX_SPACEDIM > 1) ? rr[1] : 1;
139 const int rl = (AMREX_SPACEDIM > 2) ? rr[2] : 1;
140
141 // Staggering of fine array (0: cell-centered; 1: nodal)
142 // Unused dimensions are considered nodal.
143 const int sj_fp = arr_fine_stag[0];
144 const int sk_fp = (AMREX_SPACEDIM > 1) ? arr_fine_stag[1] : 1;
145 const int sl_fp = (AMREX_SPACEDIM > 2) ? arr_fine_stag[2] : 1;
146
147 // Staggering of coarse array (0: cell-centered; 1: nodal)
148 // Unused dimensions are considered nodal.
149 const int sj_cp = arr_coarse_stag[0];
150 const int sk_cp = (AMREX_SPACEDIM > 1) ? arr_coarse_stag[1] : 1;
151 const int sl_cp = (AMREX_SPACEDIM > 2) ? arr_coarse_stag[2] : 1;
152
153 // Number of points used for interpolation from coarse grid to fine grid
154 int nj;
155 int nk;
156 int nl;
157
158 int jc = amrex::coarsen(j, rj);
159 int kc = amrex::coarsen(k, rk);
160 int lc = amrex::coarsen(l, rl);
161
162 amrex::Real tmp = 0.0_rt;
163 amrex::Real fine = 0.0_rt;
164 amrex::Real coarse = 0.0_rt;
165
166 // 1) Interpolation from coarse nodal to fine nodal
167
168 nj = 2;
169 nk = (AMREX_SPACEDIM > 1) ? 2 : 1;
170 nl = (AMREX_SPACEDIM > 2) ? 2 : 1;
171
172 for (int jj = 0; jj < nj; jj++) {
173 for (int kk = 0; kk < nk; kk++) {
174 for (int ll = 0; ll < nl; ll++) {
175 auto c = arr_tmp_zeropad(jc+jj,kc+kk,lc+ll);
176 c *= (rj - amrex::Math::abs(j - (jc + jj) * rj)) / static_cast<amrex::Real>(rj);
177#if (AMREX_SPACEDIM > 1)
178 c *= (rk - amrex::Math::abs(k - (kc + kk) * rk)) / static_cast<amrex::Real>(rk);
179#if (AMREX_SPACEDIM > 2)
180 c *= (rl - amrex::Math::abs(l - (lc + ll) * rl)) / static_cast<amrex::Real>(rl);
181#endif
182#endif
183 tmp += c;
184 }
185 }
186 }
187
188 // 2) Interpolation from coarse staggered to fine nodal
189
190 nj = 2;
191 nk = (AMREX_SPACEDIM > 1) ? 2 : 1;
192 nl = (AMREX_SPACEDIM > 2) ? 2 : 1;
193
194 const int jn = (sj_cp == 1) ? j : j - rj / 2;
195 const int kn = (sk_cp == 1) ? k : k - rk / 2;
196 const int ln = (sl_cp == 1) ? l : l - rl / 2;
197
198 jc = amrex::coarsen(jn, rj);
199 kc = amrex::coarsen(kn, rk);
200 lc = amrex::coarsen(ln, rl);
201
202 for (int jj = 0; jj < nj; jj++) {
203 for (int kk = 0; kk < nk; kk++) {
204 for (int ll = 0; ll < nl; ll++) {
205 auto c = arr_coarse_zeropad(jc+jj,kc+kk,lc+ll);
206 c *= (rj - amrex::Math::abs(jn - (jc + jj) * rj)) / static_cast<amrex::Real>(rj);
207#if (AMREX_SPACEDIM > 1)
208 c *= (rk - amrex::Math::abs(kn - (kc + kk) * rk)) / static_cast<amrex::Real>(rk);
209#if (AMREX_SPACEDIM > 2)
210 c *= (rl - amrex::Math::abs(ln - (lc + ll) * rl)) / static_cast<amrex::Real>(rl);
211#endif
212#endif
213 coarse += c;
214 }
215 }
216 }
217
218 // 3) Interpolation from fine staggered to fine nodal
219
220 nj = (sj_fp == 0) ? 2 : 1;
221 nk = (sk_fp == 0) ? 2 : 1;
222 nl = (sl_fp == 0) ? 2 : 1;
223
224 const int jm = (sj_fp == 0) ? j-1 : j;
225 const int km = (sk_fp == 0) ? k-1 : k;
226 const int lm = (sl_fp == 0) ? l-1 : l;
227
228 for (int jj = 0; jj < nj; jj++) {
229 for (int kk = 0; kk < nk; kk++) {
230 for (int ll = 0; ll < nl; ll++) {
231 fine += arr_fine_zeropad(jm+jj,km+kk,lm+ll);
232 }
233 }
234 }
235 fine = fine/static_cast<amrex::Real>(nj*nk*nl);
236
237 // Final result
238 arr_aux(j,k,l) = tmp + (fine - coarse);
239}
240
255void warpx_interp (int j, int k, int l,
256 amrex::Array4<amrex::Real > const& arr_aux,
257 amrex::Array4<amrex::Real const> const& arr_fine,
258 const amrex::IntVect& arr_fine_stag)
259{
260 using namespace amrex;
261
262 // Pad input arrays with zeros beyond ghost cells
263 // for out-of-bound accesses due to large-stencil operations
264 const auto arr_fine_zeropad = [arr_fine] (const int jj, const int kk, const int ll) noexcept
265 {
266 return arr_fine.contains(jj,kk,ll) ? arr_fine(jj,kk,ll) : 0.0_rt;
267 };
268
269 // NOTE Indices (j,k,l) in the following refer to:
270 // - (z,-,-) in 1D
271 // - (r,-,-) in RCYLINDER and RSPHERE
272 // - (x,z,-) in 2D
273 // - (r,z,-) in RZ
274 // - (x,y,z) in 3D
275
276 // Staggering of fine array (0: cell-centered; 1: nodal)
277 // Unused dimensions are considered nodal.
278 const int sj_fp = arr_fine_stag[0];
279 const int sk_fp = (AMREX_SPACEDIM > 1) ? arr_fine_stag[1] : 1;
280 const int sl_fp = (AMREX_SPACEDIM > 2) ? arr_fine_stag[2] : 1;
281
282 // Number of points used for interpolation from coarse grid to fine grid
283 int nj;
284 int nk;
285 int nl;
286
287 amrex::Real fine = 0.0_rt;
288
289 // 3) Interpolation from fine staggered to fine nodal
290
291 nj = (sj_fp == 0) ? 2 : 1;
292 nk = (sk_fp == 0) ? 2 : 1;
293 nl = (sl_fp == 0) ? 2 : 1;
294
295 int const jm = (sj_fp == 0) ? j-1 : j;
296 int const km = (sk_fp == 0) ? k-1 : k;
297 int const lm = (sl_fp == 0) ? l-1 : l;
298
299 for (int jj = 0; jj < nj; jj++) {
300 for (int kk = 0; kk < nk; kk++) {
301 for (int ll = 0; ll < nl; ll++) {
302 fine += arr_fine_zeropad(jm+jj,km+kk,lm+ll);
303 }
304 }
305 }
306 fine = fine/static_cast<amrex::Real>(nj*nk*nl);
307
308 // Final result
309 arr_aux(j,k,l) = fine;
310}
311
332void warpx_interp (const int j,
333 const int k,
334 const int l,
335 amrex::Array4<amrex::Real > const& dst_arr,
337 const amrex::IntVect& dst_stag,
338 const amrex::IntVect& src_stag,
339 [[maybe_unused]] const int nox = 2,
340 [[maybe_unused]] const int noy = 2,
341 [[maybe_unused]] const int noz = 2,
342 [[maybe_unused]] amrex::Real const* stencil_coeffs_x = nullptr,
343 [[maybe_unused]] amrex::Real const* stencil_coeffs_y = nullptr,
344 [[maybe_unused]] amrex::Real const* stencil_coeffs_z = nullptr)
345{
346 using namespace amrex;
347
348 // Pad input array with zeros beyond ghost cells
349 // for out-of-bound accesses due to large-stencil operations
350 const auto src_arr_zeropad = [src_arr] (const int jj, const int kk, const int ll) noexcept
351 {
352 return src_arr.contains(jj,kk,ll) ? src_arr(jj,kk,ll) : 0.0_rt;
353 };
354
355 // Avoid compiler warnings
356 amrex::ignore_unused(nox, noy, stencil_coeffs_x, stencil_coeffs_y);
357
358 // If dst_nodal = true , we are centering from a staggered grid to a nodal grid
359 // If dst_nodal = false, we are centering from a nodal grid to a staggered grid
360 const bool dst_nodal = (dst_stag == amrex::IntVect::TheNodeVector());
361
362 // See 1D examples below to understand the meaning of this integer shift
363 const int shift = (dst_nodal) ? 0 : 1;
364
365 // Staggering (s = 0 if cell-centered, s = 1 if nodal)
366 // Unused dimensions are considered nodal.
367 const int sj = (dst_nodal) ? src_stag[0] : dst_stag[0];
368 const int sk = (AMREX_SPACEDIM > 1) ? ((dst_nodal) ? src_stag[1] : dst_stag[1]) : 1;
369 const int sl = (AMREX_SPACEDIM > 2) ? ((dst_nodal) ? src_stag[2] : dst_stag[2]) : 1;
370
371 // Interpolate along j,k,l only if source MultiFab is staggered along j,k,l
372 const bool interp_j = (sj == 0);
373 const bool interp_k = (sk == 0);
374 const bool interp_l = (sl == 0);
375
376 const int noj = AMREX_D_PICK(noz, nox, nox);
377 const int nok = AMREX_D_PICK(0 , noz, noy);
378 const int nol = AMREX_D_PICK(0 , 0 , noz);
379
380 // Additional normalization factor
381 const amrex::Real wj = (interp_j) ? 0.5_rt : 1.0_rt;
382 const amrex::Real wk = (interp_k) ? 0.5_rt : 1.0_rt;
383 const amrex::Real wl = (interp_l) ? 0.5_rt : 1.0_rt;
384
385 // Min and max for interpolation loop
386 const int jmin = (interp_j) ? j - noj/2 + shift : j;
387 const int jmax = (interp_j) ? j + noj/2 + shift - 1 : j;
388 const int kmin = (interp_k) ? k - nok/2 + shift : k;
389 const int kmax = (interp_k) ? k + nok/2 + shift - 1 : k;
390 const int lmin = (interp_l) ? l - nol/2 + shift : l;
391 const int lmax = (interp_l) ? l + nol/2 + shift - 1 : l;
392
393 // Number of interpolation points
394 const int nj = jmax - jmin;
395 const int nk = kmax - kmin;
396 const int nl = lmax - lmin;
397
398 // Example of 1D centering from nodal grid to nodal grid (simple copy):
399 //
400 // j
401 // --o-----o-----o-- result(j) = f(j)
402 // --o-----o-----o--
403 // j-1 j j+1
404 //
405 // Example of 1D linear centering from staggered grid to nodal grid:
406 //
407 // j
408 // --o-----o-----o-- result(j) = (f(j-1) + f(j)) / 2
409 // -----x-----x-----
410 // j-1 j
411 //
412 // Example of 1D linear centering from nodal grid to staggered grid:
413 // (note the shift of +1 in the indices with respect to the case above, see variable "shift")
414 //
415 // j
416 // --x-----x-----x-- result(j) = (f(j) + f(j+1)) / 2
417 // -----o-----o-----
418 // j j+1
419 //
420 // Example of 1D finite-order centering from staggered grid to nodal grid:
421 //
422 // j
423 // --o-----o-----o-----o-----o-----o-----o-- result(j) = c_0 * (f(j-1) + f(j) ) / 2
424 // -----x-----x-----x-----x-----x-----x----- + c_1 * (f(j-2) + f(j+1)) / 2
425 // j-3 j-2 j-1 j j+1 j+2 + c_2 * (f(j-3) + f(j+2)) / 2
426 // c_2 c_1 c_0 c_0 c_1 c_2 + ...
427 //
428 // Example of 1D finite-order centering from nodal grid to staggered grid:
429 // (note the shift of +1 in the indices with respect to the case above, see variable "shift")
430 //
431 // j
432 // --x-----x-----x-----x-----x-----x-----x-- result(j) = c_0 * (f(j) + f(j+1)) / 2
433 // -----o-----o-----o-----o-----o-----o----- + c_1 * (f(j-1) + f(j+2)) / 2
434 // j-2 j-1 j j+1 j+2 j+3 + c_2 * (f(j-2) + f(j+3)) / 2
435 // c_2 c_1 c_0 c_0 c_1 c_2 + ...
436
437 amrex::Real res = 0.0_rt;
438
439 amrex::Real const* scj = AMREX_D_PICK(stencil_coeffs_z, stencil_coeffs_x, stencil_coeffs_x);
440 amrex::Real const* sck = AMREX_D_PICK(nullptr , stencil_coeffs_z, stencil_coeffs_y);
441 amrex::Real const* scl = AMREX_D_PICK(nullptr , nullptr , stencil_coeffs_z);
442
443 for (int ll = 0; ll <= nl; ll++)
444 {
445 const amrex::Real cl = (interp_l)? scl[ll] : 1.0_rt;
446 for (int kk = 0; kk <= nk; kk++)
447 {
448 const amrex::Real ck = (interp_k)? sck[kk] : 1.0_rt;
449 for (int jj = 0; jj <= nj; jj++)
450 {
451 const amrex::Real cj = (interp_j)? scj[jj] : 1.0_rt;
452
453 res += cj * ck * cl * src_arr_zeropad(jmin+jj,kmin+kk,lmin+ll);
454 }
455 }
456 }
457
458 dst_arr(j,k,l) = wj * wk * wl * res;
459}
460
461#endif
#define AMREX_FORCE_INLINE
#define AMREX_GPU_DEVICE
Array4< Real > fine
#define AMREX_D_PICK(a, b, c)
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void warpx_interp(int j, int k, int l, amrex::Array4< amrex::Real > const &arr_aux, amrex::Array4< amrex::Real const > const &arr_fine, amrex::Array4< amrex::Real const > const &arr_coarse, const amrex::IntVect &arr_stag, const amrex::IntVect &rr)
Interpolation function called within WarpX::UpdateAuxilaryDataSameType with electromagnetic solver to...
Definition WarpXComm_K.H:28
__host__ static __device__ constexpr IntVectND< dim > TheNodeVector() noexcept
__host__ __device__ void ignore_unused(const Ts &...)
__host__ __device__ BoxND< dim > coarsen(const BoxND< dim > &b, int ref_ratio) noexcept
__host__ __device__ BoxND< dim > shift(const BoxND< dim > &b, int dir, int nzones) noexcept
IntVectND< 3 > IntVect
__host__ __device__ bool contains(int i, int j, int k) const noexcept