MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_convection_kernels.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#ifndef MFEM_BILININTEG_CONVECTION_KERNELS_HPP
13#define MFEM_BILININTEG_CONVECTION_KERNELS_HPP
14
16#include "../bilininteg.hpp"
17#include "../gridfunc.hpp"
18#include "../qfunction.hpp"
20
21/// \cond DO_NOT_DOCUMENT
22namespace mfem
23{
24
25// PA Convection Apply 2D kernel
26template <int T_D1D = 0, int T_Q1D = 0>
27void PAConvectionApply2D(const int ne, const Array<real_t> &b,
28 const Array<real_t> &g, const Array<real_t> &bt,
29 const Array<real_t> &gt, const Vector &op_,
30 const Vector &x_, Vector &y_, const int d1d = 0,
31 const int q1d = 0)
32{
33 const int NE = ne;
34 const int D1D = T_D1D ? T_D1D : d1d;
35 const int Q1D = T_Q1D ? T_Q1D : q1d;
36 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
37 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
38 auto B = Reshape(b.Read(), Q1D, D1D);
39 auto G = Reshape(g.Read(), Q1D, D1D);
40 auto Bt = Reshape(bt.Read(), D1D, Q1D);
41 auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
42 auto x = Reshape(x_.Read(), D1D, D1D, NE);
43 auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
44 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
45 {
46 const int D1D = T_D1D ? T_D1D : d1d;
47 const int Q1D = T_Q1D ? T_Q1D : q1d;
48 // the following variables are evaluated at compile time
49 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
50 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
51
52 real_t u[max_D1D][max_D1D];
53 for (int dy = 0; dy < D1D; ++dy)
54 {
55 for (int dx = 0; dx < D1D; ++dx)
56 {
57 u[dy][dx] = x(dx,dy,e);
58 }
59 }
60 real_t Bu[max_D1D][max_Q1D];
61 real_t Gu[max_D1D][max_Q1D];
62 for (int dy = 0; dy < D1D; ++dy)
63 {
64 for (int qx = 0; qx < Q1D; ++qx)
65 {
66 Bu[dy][qx] = 0.0;
67 Gu[dy][qx] = 0.0;
68 for (int dx = 0; dx < D1D; ++dx)
69 {
70 const real_t bx = B(qx,dx);
71 const real_t gx = G(qx,dx);
72 const real_t x = u[dy][dx];
73 Bu[dy][qx] += bx * x;
74 Gu[dy][qx] += gx * x;
75 }
76 }
77 }
78 real_t GBu[max_Q1D][max_Q1D];
79 real_t BGu[max_Q1D][max_Q1D];
80 for (int qx = 0; qx < Q1D; ++qx)
81 {
82 for (int qy = 0; qy < Q1D; ++qy)
83 {
84 GBu[qy][qx] = 0.0;
85 BGu[qy][qx] = 0.0;
86 for (int dy = 0; dy < D1D; ++dy)
87 {
88 const real_t bx = B(qy,dy);
89 const real_t gx = G(qy,dy);
90 GBu[qy][qx] += gx * Bu[dy][qx];
91 BGu[qy][qx] += bx * Gu[dy][qx];
92 }
93 }
94 }
95 // Calculate Dxy, xDy in plane
96 real_t DGu[max_Q1D][max_Q1D];
97 for (int qy = 0; qy < Q1D; ++qy)
98 {
99 for (int qx = 0; qx < Q1D; ++qx)
100 {
101 const real_t O1 = op(qx,qy,0,e);
102 const real_t O2 = op(qx,qy,1,e);
103
104 const real_t gradX = BGu[qy][qx];
105 const real_t gradY = GBu[qy][qx];
106
107 DGu[qy][qx] = (O1 * gradX) + (O2 * gradY);
108 }
109 }
110 real_t BDGu[max_D1D][max_Q1D];
111 for (int qx = 0; qx < Q1D; ++qx)
112 {
113 for (int dy = 0; dy < D1D; ++dy)
114 {
115 BDGu[dy][qx] = 0.0;
116 for (int qy = 0; qy < Q1D; ++qy)
117 {
118 const real_t w = Bt(dy,qy);
119 BDGu[dy][qx] += w * DGu[qy][qx];
120 }
121 }
122 }
123 for (int dx = 0; dx < D1D; ++dx)
124 {
125 for (int dy = 0; dy < D1D; ++dy)
126 {
127 real_t BBDGu = 0.0;
128 for (int qx = 0; qx < Q1D; ++qx)
129 {
130 const real_t w = Bt(dx,qx);
131 BBDGu += w * BDGu[dy][qx];
132 }
133 y(dx,dy,e) += BBDGu;
134 }
135 }
136 });
137}
138
139// Optimized PA Convection Apply 2D kernel
140template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
141void SmemPAConvectionApply2D(const int ne, const Array<real_t> &b,
142 const Array<real_t> &g, const Array<real_t> &bt,
143 const Array<real_t> &gt, const Vector &op_,
144 const Vector &x_, Vector &y_, const int d1d = 0,
145 const int q1d = 0)
146{
147 const int NE = ne;
148 const int D1D = T_D1D ? T_D1D : d1d;
149 const int Q1D = T_Q1D ? T_Q1D : q1d;
150 constexpr int NBZ = T_NBZ ? T_NBZ : 1;
151 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
152 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
153 auto B = Reshape(b.Read(), Q1D, D1D);
154 auto G = Reshape(g.Read(), Q1D, D1D);
155 auto Bt = Reshape(bt.Read(), D1D, Q1D);
156 auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
157 auto x = Reshape(x_.Read(), D1D, D1D, NE);
158 auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
159 mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
160 {
161 const int tidz = MFEM_THREAD_ID(z);
162 const int D1D = T_D1D ? T_D1D : d1d;
163 const int Q1D = T_Q1D ? T_Q1D : q1d;
164 // the following variables are evaluated at compile time
165 constexpr int NBZ = T_NBZ ? T_NBZ : 1;
166 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
167 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
168 // constexpr int MDQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
169 MFEM_SHARED real_t u[NBZ][max_D1D][max_D1D];
170 MFEM_FOREACH_THREAD(dy,y,D1D)
171 {
172 MFEM_FOREACH_THREAD(dx,x,D1D)
173 {
174 // e is really equal to e+tidz
175 u[tidz][dy][dx] = x(dx,dy,e);
176 }
177 }
178 MFEM_SYNC_THREAD;
179 MFEM_SHARED real_t Bu[NBZ][max_D1D][max_Q1D];
180 MFEM_SHARED real_t Gu[NBZ][max_D1D][max_Q1D];
181 MFEM_FOREACH_THREAD(dy,y,D1D)
182 {
183 MFEM_FOREACH_THREAD(qx,x,Q1D)
184 {
185 Bu[tidz][dy][qx] = 0.0;
186 Gu[tidz][dy][qx] = 0.0;
187 for (int dx = 0; dx < D1D; ++dx)
188 {
189 const real_t bx = B(qx,dx);
190 const real_t gx = G(qx,dx);
191 const real_t x = u[tidz][dy][dx];
192 Bu[tidz][dy][qx] += bx * x;
193 Gu[tidz][dy][qx] += gx * x;
194 }
195 }
196 }
197 MFEM_SYNC_THREAD;
198 MFEM_SHARED real_t GBu[NBZ][max_Q1D][max_Q1D];
199 MFEM_SHARED real_t BGu[NBZ][max_Q1D][max_Q1D];
200 MFEM_FOREACH_THREAD(qx,x,Q1D)
201 {
202 MFEM_FOREACH_THREAD(qy,y,Q1D)
203 {
204 GBu[tidz][qy][qx] = 0.0;
205 BGu[tidz][qy][qx] = 0.0;
206 for (int dy = 0; dy < D1D; ++dy)
207 {
208 const real_t bx = B(qy,dy);
209 const real_t gx = G(qy,dy);
210 GBu[tidz][qy][qx] += gx * Bu[tidz][dy][qx];
211 BGu[tidz][qy][qx] += bx * Gu[tidz][dy][qx];
212 }
213 }
214 }
215 MFEM_SYNC_THREAD;
216 // Calculate Dxy, xDy in plane
217 MFEM_SHARED real_t DGu[NBZ][max_Q1D][max_Q1D];
218 MFEM_FOREACH_THREAD(qy,y,Q1D)
219 {
220 MFEM_FOREACH_THREAD(qx,x,Q1D)
221 {
222 const real_t O1 = op(qx,qy,0,e);
223 const real_t O2 = op(qx,qy,1,e);
224
225 const real_t gradX = BGu[tidz][qy][qx];
226 const real_t gradY = GBu[tidz][qy][qx];
227
228 DGu[tidz][qy][qx] = (O1 * gradX) + (O2 * gradY);
229 }
230 }
231 MFEM_SYNC_THREAD;
232 MFEM_SHARED real_t BDGu[NBZ][max_D1D][max_Q1D];
233 MFEM_FOREACH_THREAD(qx,x,Q1D)
234 {
235 MFEM_FOREACH_THREAD(dy,y,D1D)
236 {
237 BDGu[tidz][dy][qx] = 0.0;
238 for (int qy = 0; qy < Q1D; ++qy)
239 {
240 const real_t w = Bt(dy,qy);
241 BDGu[tidz][dy][qx] += w * DGu[tidz][qy][qx];
242 }
243 }
244 }
245 MFEM_SYNC_THREAD;
246 MFEM_FOREACH_THREAD(dx,x,D1D)
247 {
248 MFEM_FOREACH_THREAD(dy,y,D1D)
249 {
250 real_t BBDGu = 0.0;
251 for (int qx = 0; qx < Q1D; ++qx)
252 {
253 const real_t w = Bt(dx,qx);
254 BBDGu += w * BDGu[tidz][dy][qx];
255 }
256 y(dx,dy,e) += BBDGu;
257 }
258 }
259 });
260}
261
262// PA Convection Apply 3D kernel
263template <int T_D1D = 0, int T_Q1D = 0>
264void PAConvectionApply3D(const int ne, const Array<real_t> &b,
265 const Array<real_t> &g, const Array<real_t> &bt,
266 const Array<real_t> &gt, const Vector &op_,
267 const Vector &x_, Vector &y_, const int d1d = 0,
268 const int q1d = 0)
269{
270 const int NE = ne;
271 const int D1D = T_D1D ? T_D1D : d1d;
272 const int Q1D = T_Q1D ? T_Q1D : q1d;
273 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
274 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
275 auto B = Reshape(b.Read(), Q1D, D1D);
276 auto G = Reshape(g.Read(), Q1D, D1D);
277 auto Bt = Reshape(bt.Read(), D1D, Q1D);
278 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
279 auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
280 auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
281 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
282 {
283 const int D1D = T_D1D ? T_D1D : d1d;
284 const int Q1D = T_Q1D ? T_Q1D : q1d;
285 // the following variables are evaluated at compile time
286 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
287 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
288
289 real_t u[max_D1D][max_D1D][max_D1D];
290 for (int dz = 0; dz < D1D; ++dz)
291 {
292 for (int dy = 0; dy < D1D; ++dy)
293 {
294 for (int dx = 0; dx < D1D; ++dx)
295 {
296 u[dz][dy][dx] = x(dx,dy,dz,e);
297 }
298 }
299 }
300 real_t Bu[max_D1D][max_D1D][max_Q1D];
301 real_t Gu[max_D1D][max_D1D][max_Q1D];
302 for (int dz = 0; dz < D1D; ++dz)
303 {
304 for (int dy = 0; dy < D1D; ++dy)
305 {
306 for (int qx = 0; qx < Q1D; ++qx)
307 {
308 Bu[dz][dy][qx] = 0.0;
309 Gu[dz][dy][qx] = 0.0;
310 for (int dx = 0; dx < D1D; ++dx)
311 {
312 const real_t bx = B(qx,dx);
313 const real_t gx = G(qx,dx);
314 const real_t x = u[dz][dy][dx];
315 Bu[dz][dy][qx] += bx * x;
316 Gu[dz][dy][qx] += gx * x;
317 }
318 }
319 }
320 }
321 real_t BBu[max_D1D][max_Q1D][max_Q1D];
322 real_t GBu[max_D1D][max_Q1D][max_Q1D];
323 real_t BGu[max_D1D][max_Q1D][max_Q1D];
324 for (int dz = 0; dz < D1D; ++dz)
325 {
326 for (int qx = 0; qx < Q1D; ++qx)
327 {
328 for (int qy = 0; qy < Q1D; ++qy)
329 {
330 BBu[dz][qy][qx] = 0.0;
331 GBu[dz][qy][qx] = 0.0;
332 BGu[dz][qy][qx] = 0.0;
333 for (int dy = 0; dy < D1D; ++dy)
334 {
335 const real_t bx = B(qy,dy);
336 const real_t gx = G(qy,dy);
337 BBu[dz][qy][qx] += bx * Bu[dz][dy][qx];
338 GBu[dz][qy][qx] += gx * Bu[dz][dy][qx];
339 BGu[dz][qy][qx] += bx * Gu[dz][dy][qx];
340 }
341 }
342 }
343 }
344 real_t GBBu[max_Q1D][max_Q1D][max_Q1D];
345 real_t BGBu[max_Q1D][max_Q1D][max_Q1D];
346 real_t BBGu[max_Q1D][max_Q1D][max_Q1D];
347 for (int qx = 0; qx < Q1D; ++qx)
348 {
349 for (int qy = 0; qy < Q1D; ++qy)
350 {
351 for (int qz = 0; qz < Q1D; ++qz)
352 {
353 GBBu[qz][qy][qx] = 0.0;
354 BGBu[qz][qy][qx] = 0.0;
355 BBGu[qz][qy][qx] = 0.0;
356 for (int dz = 0; dz < D1D; ++dz)
357 {
358 const real_t bx = B(qz,dz);
359 const real_t gx = G(qz,dz);
360 GBBu[qz][qy][qx] += gx * BBu[dz][qy][qx];
361 BGBu[qz][qy][qx] += bx * GBu[dz][qy][qx];
362 BBGu[qz][qy][qx] += bx * BGu[dz][qy][qx];
363 }
364 }
365 }
366 }
367 // Calculate Dxy, xDy in plane
368 real_t DGu[max_Q1D][max_Q1D][max_Q1D];
369 for (int qz = 0; qz < Q1D; ++qz)
370 {
371 for (int qy = 0; qy < Q1D; ++qy)
372 {
373 for (int qx = 0; qx < Q1D; ++qx)
374 {
375 const real_t O1 = op(qx,qy,qz,0,e);
376 const real_t O2 = op(qx,qy,qz,1,e);
377 const real_t O3 = op(qx,qy,qz,2,e);
378
379 const real_t gradX = BBGu[qz][qy][qx];
380 const real_t gradY = BGBu[qz][qy][qx];
381 const real_t gradZ = GBBu[qz][qy][qx];
382
383 DGu[qz][qy][qx] = (O1 * gradX) + (O2 * gradY) + (O3 * gradZ);
384 }
385 }
386 }
387 real_t BDGu[max_D1D][max_Q1D][max_Q1D];
388 for (int qx = 0; qx < Q1D; ++qx)
389 {
390 for (int qy = 0; qy < Q1D; ++qy)
391 {
392 for (int dz = 0; dz < D1D; ++dz)
393 {
394 BDGu[dz][qy][qx] = 0.0;
395 for (int qz = 0; qz < Q1D; ++qz)
396 {
397 const real_t w = Bt(dz,qz);
398 BDGu[dz][qy][qx] += w * DGu[qz][qy][qx];
399 }
400 }
401 }
402 }
403 real_t BBDGu[max_D1D][max_D1D][max_Q1D];
404 for (int dz = 0; dz < D1D; ++dz)
405 {
406 for (int qx = 0; qx < Q1D; ++qx)
407 {
408 for (int dy = 0; dy < D1D; ++dy)
409 {
410 BBDGu[dz][dy][qx] = 0.0;
411 for (int qy = 0; qy < Q1D; ++qy)
412 {
413 const real_t w = Bt(dy,qy);
414 BBDGu[dz][dy][qx] += w * BDGu[dz][qy][qx];
415 }
416 }
417 }
418 }
419 for (int dz = 0; dz < D1D; ++dz)
420 {
421 for (int dy = 0; dy < D1D; ++dy)
422 {
423 for (int dx = 0; dx < D1D; ++dx)
424 {
425 real_t BBBDGu = 0.0;
426 for (int qx = 0; qx < Q1D; ++qx)
427 {
428 const real_t w = Bt(dx,qx);
429 BBBDGu += w * BBDGu[dz][dy][qx];
430 }
431 y(dx,dy,dz,e) += BBBDGu;
432 }
433 }
434 }
435 });
436}
437
438// Optimized PA Convection Apply 3D kernel
439template <int T_D1D = 0, int T_Q1D = 0>
440void SmemPAConvectionApply3D(const int ne, const Array<real_t> &b,
441 const Array<real_t> &g, const Array<real_t> &bt,
442 const Array<real_t> &gt, const Vector &op_,
443 const Vector &x_, Vector &y_, const int d1d = 0,
444 const int q1d = 0)
445{
446 const int NE = ne;
447 const int D1D = T_D1D ? T_D1D : d1d;
448 const int Q1D = T_Q1D ? T_Q1D : q1d;
449 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
450 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
451 auto B = Reshape(b.Read(), Q1D, D1D);
452 auto G = Reshape(g.Read(), Q1D, D1D);
453 auto Bt = Reshape(bt.Read(), D1D, Q1D);
454 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
455 auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
456 auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
457 mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
458 {
459 const int D1D = T_D1D ? T_D1D : d1d;
460 const int Q1D = T_Q1D ? T_Q1D : q1d;
461 // the following variables are evaluated at compile time
462 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
463 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
464 constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
465 MFEM_SHARED real_t sm0[max_DQ*max_DQ*max_DQ];
466 MFEM_SHARED real_t sm1[max_DQ*max_DQ*max_DQ];
467 MFEM_SHARED real_t sm2[max_DQ*max_DQ*max_DQ];
468 MFEM_SHARED real_t sm3[max_DQ*max_DQ*max_DQ];
469 MFEM_SHARED real_t sm4[max_DQ*max_DQ*max_DQ];
470 MFEM_SHARED real_t sm5[max_DQ*max_DQ*max_DQ];
471
472 real_t (*u)[max_D1D][max_D1D] = (real_t (*)[max_D1D][max_D1D]) sm0;
473 MFEM_FOREACH_THREAD(dz,z,D1D)
474 {
475 MFEM_FOREACH_THREAD(dy,y,D1D)
476 {
477 MFEM_FOREACH_THREAD(dx,x,D1D)
478 {
479 u[dz][dy][dx] = x(dx,dy,dz,e);
480 }
481 }
482 }
483 MFEM_SYNC_THREAD;
484 real_t (*Bu)[max_D1D][max_Q1D] = (real_t (*)[max_D1D][max_Q1D])sm1;
485 real_t (*Gu)[max_D1D][max_Q1D] = (real_t (*)[max_D1D][max_Q1D])sm2;
486 MFEM_FOREACH_THREAD(dz,z,D1D)
487 {
488 MFEM_FOREACH_THREAD(dy,y,D1D)
489 {
490 MFEM_FOREACH_THREAD(qx,x,Q1D)
491 {
492 real_t Bu_ = 0.0;
493 real_t Gu_ = 0.0;
494 for (int dx = 0; dx < D1D; ++dx)
495 {
496 const real_t bx = B(qx,dx);
497 const real_t gx = G(qx,dx);
498 const real_t x = u[dz][dy][dx];
499 Bu_ += bx * x;
500 Gu_ += gx * x;
501 }
502 Bu[dz][dy][qx] = Bu_;
503 Gu[dz][dy][qx] = Gu_;
504 }
505 }
506 }
507 MFEM_SYNC_THREAD;
508 real_t (*BBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm3;
509 real_t (*GBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm4;
510 real_t (*BGu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm5;
511 MFEM_FOREACH_THREAD(dz,z,D1D)
512 {
513 MFEM_FOREACH_THREAD(qx,x,Q1D)
514 {
515 MFEM_FOREACH_THREAD(qy,y,Q1D)
516 {
517 real_t BBu_ = 0.0;
518 real_t GBu_ = 0.0;
519 real_t BGu_ = 0.0;
520 for (int dy = 0; dy < D1D; ++dy)
521 {
522 const real_t bx = B(qy,dy);
523 const real_t gx = G(qy,dy);
524 BBu_ += bx * Bu[dz][dy][qx];
525 GBu_ += gx * Bu[dz][dy][qx];
526 BGu_ += bx * Gu[dz][dy][qx];
527 }
528 BBu[dz][qy][qx] = BBu_;
529 GBu[dz][qy][qx] = GBu_;
530 BGu[dz][qy][qx] = BGu_;
531 }
532 }
533 }
534 MFEM_SYNC_THREAD;
535 real_t (*GBBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm0;
536 real_t (*BGBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm1;
537 real_t (*BBGu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm2;
538 MFEM_FOREACH_THREAD(qx,x,Q1D)
539 {
540 MFEM_FOREACH_THREAD(qy,y,Q1D)
541 {
542 MFEM_FOREACH_THREAD(qz,z,Q1D)
543 {
544 real_t GBBu_ = 0.0;
545 real_t BGBu_ = 0.0;
546 real_t BBGu_ = 0.0;
547 for (int dz = 0; dz < D1D; ++dz)
548 {
549 const real_t bx = B(qz,dz);
550 const real_t gx = G(qz,dz);
551 GBBu_ += gx * BBu[dz][qy][qx];
552 BGBu_ += bx * GBu[dz][qy][qx];
553 BBGu_ += bx * BGu[dz][qy][qx];
554 }
555 GBBu[qz][qy][qx] = GBBu_;
556 BGBu[qz][qy][qx] = BGBu_;
557 BBGu[qz][qy][qx] = BBGu_;
558 }
559 }
560 }
561 MFEM_SYNC_THREAD;
562 real_t (*DGu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm3;
563 MFEM_FOREACH_THREAD(qz,z,Q1D)
564 {
565 MFEM_FOREACH_THREAD(qy,y,Q1D)
566 {
567 MFEM_FOREACH_THREAD(qx,x,Q1D)
568 {
569 const real_t O1 = op(qx,qy,qz,0,e);
570 const real_t O2 = op(qx,qy,qz,1,e);
571 const real_t O3 = op(qx,qy,qz,2,e);
572
573 const real_t gradX = BBGu[qz][qy][qx];
574 const real_t gradY = BGBu[qz][qy][qx];
575 const real_t gradZ = GBBu[qz][qy][qx];
576
577 DGu[qz][qy][qx] = (O1 * gradX) + (O2 * gradY) + (O3 * gradZ);
578 }
579 }
580 }
581 MFEM_SYNC_THREAD;
582 real_t (*BDGu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm4;
583 MFEM_FOREACH_THREAD(qx,x,Q1D)
584 {
585 MFEM_FOREACH_THREAD(qy,y,Q1D)
586 {
587 MFEM_FOREACH_THREAD(dz,z,D1D)
588 {
589 real_t BDGu_ = 0.0;
590 for (int qz = 0; qz < Q1D; ++qz)
591 {
592 const real_t w = Bt(dz,qz);
593 BDGu_ += w * DGu[qz][qy][qx];
594 }
595 BDGu[dz][qy][qx] = BDGu_;
596 }
597 }
598 }
599 MFEM_SYNC_THREAD;
600 real_t (*BBDGu)[max_D1D][max_Q1D] = (real_t (*)[max_D1D][max_Q1D])sm5;
601 MFEM_FOREACH_THREAD(dz,z,D1D)
602 {
603 MFEM_FOREACH_THREAD(qx,x,Q1D)
604 {
605 MFEM_FOREACH_THREAD(dy,y,D1D)
606 {
607 real_t BBDGu_ = 0.0;
608 for (int qy = 0; qy < Q1D; ++qy)
609 {
610 const real_t w = Bt(dy,qy);
611 BBDGu_ += w * BDGu[dz][qy][qx];
612 }
613 BBDGu[dz][dy][qx] = BBDGu_;
614 }
615 }
616 }
617 MFEM_SYNC_THREAD;
618 MFEM_FOREACH_THREAD(dz,z,D1D)
619 {
620 MFEM_FOREACH_THREAD(dy,y,D1D)
621 {
622 MFEM_FOREACH_THREAD(dx,x,D1D)
623 {
624 real_t BBBDGu = 0.0;
625 for (int qx = 0; qx < Q1D; ++qx)
626 {
627 const real_t w = Bt(dx,qx);
628 BBBDGu += w * BBDGu[dz][dy][qx];
629 }
630 y(dx,dy,dz,e) += BBBDGu;
631 }
632 }
633 }
634 });
635}
636
637// PA Convection Apply 2D kernel
638template <int T_D1D = 0, int T_Q1D = 0>
639void PAConvectionApplyT2D(const int ne, const Array<real_t> &b,
640 const Array<real_t> &g, const Array<real_t> &bt,
641 const Array<real_t> &gt, const Vector &op_,
642 const Vector &x_, Vector &y_, const int d1d = 0,
643 const int q1d = 0)
644{
645 const int NE = ne;
646 const int D1D = T_D1D ? T_D1D : d1d;
647 const int Q1D = T_Q1D ? T_Q1D : q1d;
648 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
649 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
650 auto B = Reshape(b.Read(), Q1D, D1D);
651 auto Bt = Reshape(bt.Read(), D1D, Q1D);
652 auto Gt = Reshape(gt.Read(), D1D, Q1D);
653 auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
654 auto x = Reshape(x_.Read(), D1D, D1D, NE);
655 auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
656 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
657 {
658 const int D1D = T_D1D ? T_D1D : d1d;
659 const int Q1D = T_Q1D ? T_Q1D : q1d;
660 // the following variables are evaluated at compile time
661 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
662 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
663
664 real_t u[max_D1D][max_D1D];
665 for (int dy = 0; dy < D1D; ++dy)
666 {
667 for (int dx = 0; dx < D1D; ++dx)
668 {
669 u[dy][dx] = x(dx,dy,e);
670 }
671 }
672 real_t Bu[max_D1D][max_Q1D];
673 for (int dy = 0; dy < D1D; ++dy)
674 {
675 for (int qx = 0; qx < Q1D; ++qx)
676 {
677 Bu[dy][qx] = 0.0;
678 for (int dx = 0; dx < D1D; ++dx)
679 {
680 const real_t bx = B(qx,dx);
681 const real_t x = u[dy][dx];
682 Bu[dy][qx] += bx * x;
683 }
684 }
685 }
686 real_t BBu[max_Q1D][max_Q1D];
687 for (int qx = 0; qx < Q1D; ++qx)
688 {
689 for (int qy = 0; qy < Q1D; ++qy)
690 {
691 BBu[qy][qx] = 0.0;
692 for (int dy = 0; dy < D1D; ++dy)
693 {
694 const real_t bx = B(qy,dy);
695 BBu[qy][qx] += bx * Bu[dy][qx];
696 }
697 }
698 }
699 // Calculate Dxy, xDy in plane
700 real_t DBu[max_Q1D][max_Q1D][2];
701 for (int qy = 0; qy < Q1D; ++qy)
702 {
703 for (int qx = 0; qx < Q1D; ++qx)
704 {
705 const real_t O1 = op(qx,qy,0,e);
706 const real_t O2 = op(qx,qy,1,e);
707
708 const real_t X = BBu[qy][qx];
709
710 DBu[qy][qx][0] = O1 * X;
711 DBu[qy][qx][1] = O2 * X;
712 }
713 }
714 real_t GDBu[max_D1D][max_Q1D][2];
715 for (int qx = 0; qx < Q1D; ++qx)
716 {
717 for (int dy = 0; dy < D1D; ++dy)
718 {
719 GDBu[dy][qx][0] = 0.0;
720 GDBu[dy][qx][1] = 0.0;
721 for (int qy = 0; qy < Q1D; ++qy)
722 {
723 const real_t by = Bt(dy,qy);
724 const real_t gy = Gt(dy,qy);
725 GDBu[dy][qx][0] += by * DBu[qy][qx][0];
726 GDBu[dy][qx][1] += gy * DBu[qy][qx][1];
727 }
728 }
729 }
730 for (int dx = 0; dx < D1D; ++dx)
731 {
732 for (int dy = 0; dy < D1D; ++dy)
733 {
734 real_t res = 0.0;
735 for (int qx = 0; qx < Q1D; ++qx)
736 {
737 const real_t bx = Bt(dx,qx);
738 const real_t gx = Gt(dx,qx);
739 res += gx * GDBu[dy][qx][0] + bx * GDBu[dy][qx][1];
740 }
741 y(dx,dy,e) += res;
742 }
743 }
744 });
745}
746
747// Optimized PA Convection Apply 2D kernel
748template <int T_D1D = 0, int T_Q1D = 0, int T_NBZ = 0>
749void SmemPAConvectionApplyT2D(const int ne, const Array<real_t> &b,
750 const Array<real_t> &g, const Array<real_t> &bt,
751 const Array<real_t> &gt, const Vector &op_,
752 const Vector &x_, Vector &y_, const int d1d = 0,
753 const int q1d = 0)
754{
755 const int NE = ne;
756 const int D1D = T_D1D ? T_D1D : d1d;
757 const int Q1D = T_Q1D ? T_Q1D : q1d;
758 constexpr int NBZ = T_NBZ ? T_NBZ : 1;
759 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
760 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
761 auto B = Reshape(b.Read(), Q1D, D1D);
762 auto Bt = Reshape(bt.Read(), D1D, Q1D);
763 auto Gt = Reshape(gt.Read(), D1D, Q1D);
764 auto op = Reshape(op_.Read(), Q1D, Q1D, 2, NE);
765 auto x = Reshape(x_.Read(), D1D, D1D, NE);
766 auto y = Reshape(y_.ReadWrite(), D1D, D1D, NE);
767 mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
768 {
769 const int tidz = MFEM_THREAD_ID(z);
770 const int D1D = T_D1D ? T_D1D : d1d;
771 const int Q1D = T_Q1D ? T_Q1D : q1d;
772 // the following variables are evaluated at compile time
773 constexpr int NBZ = T_NBZ ? T_NBZ : 1;
774 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
775 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
776 MFEM_SHARED real_t u[NBZ][max_D1D][max_D1D];
777 MFEM_FOREACH_THREAD(dy,y,D1D)
778 {
779 MFEM_FOREACH_THREAD(dx,x,D1D)
780 {
781 // e is really equal to e+tidz
782 u[tidz][dy][dx] = x(dx,dy,e);
783 }
784 }
785 MFEM_SYNC_THREAD;
786 MFEM_SHARED real_t Bu[NBZ][max_D1D][max_Q1D];
787 MFEM_FOREACH_THREAD(dy,y,D1D)
788 {
789 MFEM_FOREACH_THREAD(qx,x,Q1D)
790 {
791 Bu[tidz][dy][qx] = 0.0;
792 for (int dx = 0; dx < D1D; ++dx)
793 {
794 const real_t bx = B(qx,dx);
795 const real_t x = u[tidz][dy][dx];
796 Bu[tidz][dy][qx] += bx * x;
797 }
798 }
799 }
800 MFEM_SYNC_THREAD;
801 MFEM_SHARED real_t BBu[NBZ][max_Q1D][max_Q1D];
802 MFEM_FOREACH_THREAD(qx,x,Q1D)
803 {
804 MFEM_FOREACH_THREAD(qy,y,Q1D)
805 {
806 BBu[tidz][qy][qx] = 0.0;
807 for (int dy = 0; dy < D1D; ++dy)
808 {
809 const real_t bx = B(qy,dy);
810 BBu[tidz][qy][qx] += bx * Bu[tidz][dy][qx];
811 }
812 }
813 }
814 MFEM_SYNC_THREAD;
815 // Calculate Dxy, xDy in plane
816 MFEM_SHARED real_t DBu[NBZ][max_Q1D][max_Q1D][2];
817 MFEM_FOREACH_THREAD(qy,y,Q1D)
818 {
819 MFEM_FOREACH_THREAD(qx,x,Q1D)
820 {
821 const real_t O1 = op(qx,qy,0,e);
822 const real_t O2 = op(qx,qy,1,e);
823
824 const real_t X = BBu[tidz][qy][qx];
825
826 DBu[tidz][qy][qx][0] = O1 * X;
827 DBu[tidz][qy][qx][1] = O2 * X;
828 }
829 }
830 MFEM_SYNC_THREAD;
831 MFEM_SHARED real_t GDBu[NBZ][max_D1D][max_Q1D][2];
832 MFEM_FOREACH_THREAD(qx,x,Q1D)
833 {
834 MFEM_FOREACH_THREAD(dy,y,D1D)
835 {
836 GDBu[tidz][dy][qx][0] = 0.0;
837 GDBu[tidz][dy][qx][1] = 0.0;
838 for (int qy = 0; qy < Q1D; ++qy)
839 {
840 const real_t by = Bt(dy,qy);
841 const real_t gy = Gt(dy,qy);
842 GDBu[tidz][dy][qx][0] += by * DBu[tidz][qy][qx][0];
843 GDBu[tidz][dy][qx][1] += gy * DBu[tidz][qy][qx][1];
844 }
845 }
846 }
847 MFEM_SYNC_THREAD;
848 MFEM_FOREACH_THREAD(dx,x,D1D)
849 {
850 MFEM_FOREACH_THREAD(dy,y,D1D)
851 {
852 real_t res = 0.0;
853 for (int qx = 0; qx < Q1D; ++qx)
854 {
855 const real_t bx = Bt(dx,qx);
856 const real_t gx = Gt(dx,qx);
857 res += gx * GDBu[tidz][dy][qx][0] + bx * GDBu[tidz][dy][qx][1];
858 }
859 y(dx,dy,e) += res;
860 }
861 }
862 });
863}
864
865// PA Convection Apply 3D kernel
866template <int T_D1D = 0, int T_Q1D = 0>
867void PAConvectionApplyT3D(const int ne, const Array<real_t> &b,
868 const Array<real_t> &g, const Array<real_t> &bt,
869 const Array<real_t> &gt, const Vector &op_,
870 const Vector &x_, Vector &y_, const int d1d = 0,
871 const int q1d = 0)
872{
873 const int NE = ne;
874 const int D1D = T_D1D ? T_D1D : d1d;
875 const int Q1D = T_Q1D ? T_Q1D : q1d;
876 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
877 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
878 auto B = Reshape(b.Read(), Q1D, D1D);
879 auto Bt = Reshape(bt.Read(), D1D, Q1D);
880 auto Gt = Reshape(gt.Read(), D1D, Q1D);
881 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
882 auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
883 auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
884 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
885 {
886 const int D1D = T_D1D ? T_D1D : d1d;
887 const int Q1D = T_Q1D ? T_Q1D : q1d;
888 // the following variables are evaluated at compile time
889 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
890 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
891
892 real_t u[max_D1D][max_D1D][max_D1D];
893 for (int dz = 0; dz < D1D; ++dz)
894 {
895 for (int dy = 0; dy < D1D; ++dy)
896 {
897 for (int dx = 0; dx < D1D; ++dx)
898 {
899 u[dz][dy][dx] = x(dx,dy,dz,e);
900 }
901 }
902 }
903 real_t Bu[max_D1D][max_D1D][max_Q1D];
904 for (int dz = 0; dz < D1D; ++dz)
905 {
906 for (int dy = 0; dy < D1D; ++dy)
907 {
908 for (int qx = 0; qx < Q1D; ++qx)
909 {
910 Bu[dz][dy][qx] = 0.0;
911 for (int dx = 0; dx < D1D; ++dx)
912 {
913 const real_t bx = B(qx,dx);
914 const real_t x = u[dz][dy][dx];
915 Bu[dz][dy][qx] += bx * x;
916 }
917 }
918 }
919 }
920 real_t BBu[max_D1D][max_Q1D][max_Q1D];
921 for (int dz = 0; dz < D1D; ++dz)
922 {
923 for (int qx = 0; qx < Q1D; ++qx)
924 {
925 for (int qy = 0; qy < Q1D; ++qy)
926 {
927 BBu[dz][qy][qx] = 0.0;
928 for (int dy = 0; dy < D1D; ++dy)
929 {
930 const real_t bx = B(qy,dy);
931 BBu[dz][qy][qx] += bx * Bu[dz][dy][qx];
932 }
933 }
934 }
935 }
936 real_t BBBu[max_Q1D][max_Q1D][max_Q1D];
937 for (int qx = 0; qx < Q1D; ++qx)
938 {
939 for (int qy = 0; qy < Q1D; ++qy)
940 {
941 for (int qz = 0; qz < Q1D; ++qz)
942 {
943 BBBu[qz][qy][qx] = 0.0;
944 for (int dz = 0; dz < D1D; ++dz)
945 {
946 const real_t bx = B(qz,dz);
947 BBBu[qz][qy][qx] += bx * BBu[dz][qy][qx];
948 }
949 }
950 }
951 }
952 // Calculate Dxy, xDy in plane
953 real_t DBu[max_Q1D][max_Q1D][max_Q1D][3];
954 for (int qz = 0; qz < Q1D; ++qz)
955 {
956 for (int qy = 0; qy < Q1D; ++qy)
957 {
958 for (int qx = 0; qx < Q1D; ++qx)
959 {
960 const real_t O1 = op(qx,qy,qz,0,e);
961 const real_t O2 = op(qx,qy,qz,1,e);
962 const real_t O3 = op(qx,qy,qz,2,e);
963
964 const real_t X = BBBu[qz][qy][qx];
965
966 DBu[qz][qy][qx][0] = O1 * X;
967 DBu[qz][qy][qx][1] = O2 * X;
968 DBu[qz][qy][qx][2] = O3 * X;
969 }
970 }
971 }
972 real_t GDBu[max_D1D][max_Q1D][max_Q1D][3];
973 for (int qx = 0; qx < Q1D; ++qx)
974 {
975 for (int qy = 0; qy < Q1D; ++qy)
976 {
977 for (int dz = 0; dz < D1D; ++dz)
978 {
979 GDBu[dz][qy][qx][0] = 0.0;
980 GDBu[dz][qy][qx][1] = 0.0;
981 GDBu[dz][qy][qx][2] = 0.0;
982 for (int qz = 0; qz < Q1D; ++qz)
983 {
984 const real_t bz = Bt(dz,qz);
985 const real_t gz = Gt(dz,qz);
986 GDBu[dz][qy][qx][0] += bz * DBu[qz][qy][qx][0];
987 GDBu[dz][qy][qx][1] += bz * DBu[qz][qy][qx][1];
988 GDBu[dz][qy][qx][2] += gz * DBu[qz][qy][qx][2];
989 }
990 }
991 }
992 }
993 real_t GGDBu[max_D1D][max_D1D][max_Q1D][3];
994 for (int dz = 0; dz < D1D; ++dz)
995 {
996 for (int qx = 0; qx < Q1D; ++qx)
997 {
998 for (int dy = 0; dy < D1D; ++dy)
999 {
1000 GGDBu[dz][dy][qx][0] = 0.0;
1001 GGDBu[dz][dy][qx][1] = 0.0;
1002 GGDBu[dz][dy][qx][2] = 0.0;
1003 for (int qy = 0; qy < Q1D; ++qy)
1004 {
1005 const real_t by = Bt(dy,qy);
1006 const real_t gy = Gt(dy,qy);
1007 GGDBu[dz][dy][qx][0] += by * GDBu[dz][qy][qx][0];
1008 GGDBu[dz][dy][qx][1] += gy * GDBu[dz][qy][qx][1];
1009 GGDBu[dz][dy][qx][2] += by * GDBu[dz][qy][qx][2];
1010 }
1011 }
1012 }
1013 }
1014 for (int dz = 0; dz < D1D; ++dz)
1015 {
1016 for (int dy = 0; dy < D1D; ++dy)
1017 {
1018 for (int dx = 0; dx < D1D; ++dx)
1019 {
1020 real_t res = 0.0;
1021 for (int qx = 0; qx < Q1D; ++qx)
1022 {
1023 const real_t bx = Bt(dx,qx);
1024 const real_t gx = Gt(dx,qx);
1025 res += gx * GGDBu[dz][dy][qx][0];
1026 res += bx * GGDBu[dz][dy][qx][1];
1027 res += bx * GGDBu[dz][dy][qx][2];
1028 }
1029 y(dx,dy,dz,e) += res;
1030 }
1031 }
1032 }
1033 });
1034}
1035
1036// Optimized PA Convection Apply 3D kernel
1037template <int T_D1D = 0, int T_Q1D = 0>
1038void SmemPAConvectionApplyT3D(const int ne, const Array<real_t> &b,
1039 const Array<real_t> &g, const Array<real_t> &bt,
1040 const Array<real_t> &gt, const Vector &op_,
1041 const Vector &x_, Vector &y_, const int d1d = 0,
1042 const int q1d = 0)
1043{
1044 const int NE = ne;
1045 const int D1D = T_D1D ? T_D1D : d1d;
1046 const int Q1D = T_Q1D ? T_Q1D : q1d;
1047 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
1048 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
1049 auto B = Reshape(b.Read(), Q1D, D1D);
1050 auto Bt = Reshape(bt.Read(), D1D, Q1D);
1051 auto Gt = Reshape(gt.Read(), D1D, Q1D);
1052 auto op = Reshape(op_.Read(), Q1D, Q1D, Q1D, 3, NE);
1053 auto x = Reshape(x_.Read(), D1D, D1D, D1D, NE);
1054 auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
1055 mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
1056 {
1057 const int D1D = T_D1D ? T_D1D : d1d;
1058 const int Q1D = T_Q1D ? T_Q1D : q1d;
1059 // the following variables are evaluated at compile time
1060 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
1061 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
1062 constexpr int max_DQ = (max_Q1D > max_D1D) ? max_Q1D : max_D1D;
1063 MFEM_SHARED real_t sm0[3*max_DQ*max_DQ*max_DQ];
1064 MFEM_SHARED real_t sm1[3*max_DQ*max_DQ*max_DQ];
1065
1066 real_t (*u)[max_D1D][max_D1D] = (real_t (*)[max_D1D][max_D1D]) sm0;
1067 MFEM_FOREACH_THREAD(dz,z,D1D)
1068 {
1069 MFEM_FOREACH_THREAD(dy,y,D1D)
1070 {
1071 MFEM_FOREACH_THREAD(dx,x,D1D)
1072 {
1073 u[dz][dy][dx] = x(dx,dy,dz,e);
1074 }
1075 }
1076 }
1077 MFEM_SYNC_THREAD;
1078 real_t (*Bu)[max_D1D][max_Q1D] = (real_t (*)[max_D1D][max_Q1D])sm1;
1079 MFEM_FOREACH_THREAD(dz,z,D1D)
1080 {
1081 MFEM_FOREACH_THREAD(dy,y,D1D)
1082 {
1083 MFEM_FOREACH_THREAD(qx,x,Q1D)
1084 {
1085 real_t Bu_ = 0.0;
1086 for (int dx = 0; dx < D1D; ++dx)
1087 {
1088 const real_t bx = B(qx,dx);
1089 const real_t x = u[dz][dy][dx];
1090 Bu_ += bx * x;
1091 }
1092 Bu[dz][dy][qx] = Bu_;
1093 }
1094 }
1095 }
1096 MFEM_SYNC_THREAD;
1097 real_t (*BBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm0;
1098 MFEM_FOREACH_THREAD(dz,z,D1D)
1099 {
1100 MFEM_FOREACH_THREAD(qx,x,Q1D)
1101 {
1102 MFEM_FOREACH_THREAD(qy,y,Q1D)
1103 {
1104 real_t BBu_ = 0.0;
1105 for (int dy = 0; dy < D1D; ++dy)
1106 {
1107 const real_t bx = B(qy,dy);
1108 BBu_ += bx * Bu[dz][dy][qx];
1109 }
1110 BBu[dz][qy][qx] = BBu_;
1111 }
1112 }
1113 }
1114 MFEM_SYNC_THREAD;
1115 real_t (*BBBu)[max_Q1D][max_Q1D] = (real_t (*)[max_Q1D][max_Q1D])sm1;
1116 MFEM_FOREACH_THREAD(qx,x,Q1D)
1117 {
1118 MFEM_FOREACH_THREAD(qy,y,Q1D)
1119 {
1120 MFEM_FOREACH_THREAD(qz,z,Q1D)
1121 {
1122 real_t BBBu_ = 0.0;
1123 for (int dz = 0; dz < D1D; ++dz)
1124 {
1125 const real_t bx = B(qz,dz);
1126 BBBu_ += bx * BBu[dz][qy][qx];
1127 }
1128 BBBu[qz][qy][qx] = BBBu_;
1129 }
1130 }
1131 }
1132 MFEM_SYNC_THREAD;
1133 real_t (*DBu)[max_Q1D][max_Q1D][3] = (real_t (*)[max_Q1D][max_Q1D][3])sm0;
1134 MFEM_FOREACH_THREAD(qz,z,Q1D)
1135 {
1136 MFEM_FOREACH_THREAD(qy,y,Q1D)
1137 {
1138 MFEM_FOREACH_THREAD(qx,x,Q1D)
1139 {
1140 const real_t O1 = op(qx,qy,qz,0,e);
1141 const real_t O2 = op(qx,qy,qz,1,e);
1142 const real_t O3 = op(qx,qy,qz,2,e);
1143
1144 const real_t X = BBBu[qz][qy][qx];
1145
1146 DBu[qz][qy][qx][0] = O1 * X;
1147 DBu[qz][qy][qx][1] = O2 * X;
1148 DBu[qz][qy][qx][2] = O3 * X;
1149 }
1150 }
1151 }
1152 MFEM_SYNC_THREAD;
1153 real_t (*GDBu)[max_Q1D][max_Q1D][3] = (real_t (*)[max_Q1D][max_Q1D][3])sm1;
1154 MFEM_FOREACH_THREAD(qx,x,Q1D)
1155 {
1156 MFEM_FOREACH_THREAD(qy,y,Q1D)
1157 {
1158 MFEM_FOREACH_THREAD(dz,z,D1D)
1159 {
1160 real_t GDBu0 = 0.0;
1161 real_t GDBu1 = 0.0;
1162 real_t GDBu2 = 0.0;
1163 for (int qz = 0; qz < Q1D; ++qz)
1164 {
1165 const real_t bz = Bt(dz,qz);
1166 const real_t gz = Gt(dz,qz);
1167 GDBu0 += bz * DBu[qz][qy][qx][0];
1168 GDBu1 += bz * DBu[qz][qy][qx][1];
1169 GDBu2 += gz * DBu[qz][qy][qx][2];
1170 }
1171 GDBu[dz][qy][qx][0] = GDBu0;
1172 GDBu[dz][qy][qx][1] = GDBu1;
1173 GDBu[dz][qy][qx][2] = GDBu2;
1174 }
1175 }
1176 }
1177 MFEM_SYNC_THREAD;
1178 real_t (*GGDBu)[max_D1D][max_Q1D][3] = (real_t (*)[max_D1D][max_Q1D][3])sm0;
1179 MFEM_FOREACH_THREAD(dz,z,D1D)
1180 {
1181 MFEM_FOREACH_THREAD(qx,x,Q1D)
1182 {
1183 MFEM_FOREACH_THREAD(dy,y,D1D)
1184 {
1185 real_t GGDBu0 = 0.0;
1186 real_t GGDBu1 = 0.0;
1187 real_t GGDBu2 = 0.0;
1188 for (int qy = 0; qy < Q1D; ++qy)
1189 {
1190 const real_t by = Bt(dy,qy);
1191 const real_t gy = Gt(dy,qy);
1192 GGDBu0 += by * GDBu[dz][qy][qx][0];
1193 GGDBu1 += gy * GDBu[dz][qy][qx][1];
1194 GGDBu2 += by * GDBu[dz][qy][qx][2];
1195 }
1196 GGDBu[dz][dy][qx][0] = GGDBu0;
1197 GGDBu[dz][dy][qx][1] = GGDBu1;
1198 GGDBu[dz][dy][qx][2] = GGDBu2;
1199 }
1200 }
1201 }
1202 MFEM_SYNC_THREAD;
1203 MFEM_FOREACH_THREAD(dz,z,D1D)
1204 {
1205 MFEM_FOREACH_THREAD(dy,y,D1D)
1206 {
1207 MFEM_FOREACH_THREAD(dx,x,D1D)
1208 {
1209 real_t res = 0.0;
1210 for (int qx = 0; qx < Q1D; ++qx)
1211 {
1212 const real_t bx = Bt(dx,qx);
1213 const real_t gx = Gt(dx,qx);
1214 res += gx * GGDBu[dz][dy][qx][0];
1215 res += bx * GGDBu[dz][dy][qx][1];
1216 res += bx * GGDBu[dz][dy][qx][2];
1217 }
1218 y(dx,dy,dz,e) += res;
1219 }
1220 }
1221 }
1222 });
1223}
1224
1225namespace convection
1226{
1227constexpr int ipow(int x, int p) { return p == 0 ? 1 : x*ipow(x, p-1); }
1228constexpr int D(int D1D) { return (11 - D1D) / 2; }
1229constexpr int NBZ(int D1D)
1230{
1231 return ipow(2, D(D1D) >= 0 ? D(D1D) : 0);
1232}
1233}
1234
1235template <int DIM, int T_D1D, int T_Q1D>
1237ConvectionIntegrator::ApplyPAKernels::Kernel()
1238{
1239 if constexpr (DIM == 2)
1240 {
1241 constexpr int T_NBZ = convection::NBZ(T_D1D);
1242 return SmemPAConvectionApply2D<T_D1D, T_Q1D, T_NBZ>;
1243 }
1244 else if constexpr (DIM == 3)
1245 {
1246 return SmemPAConvectionApply3D<T_D1D, T_Q1D>;
1247 }
1248 MFEM_ABORT("");
1249}
1250
1251template <int DIM, int T_D1D, int T_Q1D>
1253ConvectionIntegrator::ApplyPATKernels::Kernel()
1254{
1255 if constexpr (DIM == 2)
1256 {
1257 constexpr int T_NBZ = convection::NBZ(T_D1D);
1258 return SmemPAConvectionApplyT2D<T_D1D, T_Q1D, T_NBZ>;
1259 }
1260 else if constexpr (DIM == 3)
1261 {
1262 return SmemPAConvectionApplyT3D<T_D1D, T_Q1D>;
1263 }
1264 MFEM_ABORT("");
1265}
1266} // namespace mfem
1267/// \endcond DO_NOT_DOCUMENT
1268#endif
void(*)(const int, const Array< real_t > &, const Array< real_t > &, const Array< real_t > &, const Array< real_t > &, const Vector &, const Vector &, Vector &, const int, const int) ApplyKernelType
arguments: NE, B, G, Bt, Gt, pa_data, x, y, D1D, Q1D
real_t b
Definition lissajous.cpp:42
constexpr int DIM
mfem::real_t real_t
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
void forall_2D_batch(int N, int X, int Y, int BZ, lambda &&body)
Definition forall.hpp:1232
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
Definition forall.hpp:1244
float real_t
Definition config.hpp:46
void forall(int N, lambda &&body)
Definition forall.hpp:1134
real_t p(const Vector &x, real_t t)
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138