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