39template<
int T_D1D = 0,
int T_Q1D = 0>
40inline void PADiffusionApplyTriangle(
const int NE,
42 const Array<int> &lex_map_,
47 const Array<real_t> &ga1_,
48 const Array<real_t> &ga2_,
49 const Array<real_t> &,
50 const Array<real_t> &ga1t_,
51 const Array<real_t> &ga2t_,
52 const Array<real_t> &,
59 const int D1D = T_D1D ? T_D1D : d1d;
60 const int Q1D = T_Q1D ? T_Q1D : q1d;
61 const int BASIS_DIM = D1D * (D1D+1) / 2;
62 const int p2 = (D1D-1) * (D1D-1);
67 const auto lex_map = lex_map_.Read();
72 const auto D =
Reshape(d_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
73 const auto X =
Reshape(x_.Read(), BASIS_DIM, NE);
74 auto Y =
Reshape(y_.ReadWrite(), BASIS_DIM, NE);
78 const int D1D = T_D1D ? T_D1D : d1d;
79 const int Q1D = T_Q1D ? T_Q1D : q1d;
81 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D_SIMPLEX;
82 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D_SIMPLEX;
84 real_t cin[2 * (max_D1D-1) * (max_D1D-1)];
85 real_t C1[2 * (max_D1D-1) * max_Q1D];
86 real_t C2[2 * max_Q1D * max_Q1D];
87 real_t fin[2 * max_Q1D * max_Q1D];
88 real_t F1[2 * (max_D1D-1) * max_Q1D];
89 real_t F2[2 * (max_D1D-1) * (max_D1D-1)];
91 for (
int a1 = 0; a1 < D1D-1; ++a1)
93 for (
int a2 = 0; a2 < D1D-1-a1; ++a2)
95 const int q = 2*(a2 + (D1D-1)*a1);
101 for (
int i2 = 0; i2 < Q1D; ++i2)
103 const int q = 2*(i2 + Q1D*a1);
110 for (
int i1 = 0; i1 < Q1D; ++i1)
112 for (
int i2 = 0; i2 < Q1D; ++i2)
114 const int q = 2*(i2 + Q1D*i1);
128 for (
int a1 = 0; a1 < D1D-1; ++a1)
130 for (
int a2 = 0; a2 < D1D-a1-1; ++a2)
133 int idx = lex_map[a2 + D1D*(a1+1)];
134 const int a1a2 = 2*(a1 + (D1D-1)*a2);
135 cin[a1a2] += X(idx, e);
142 idx = lex_map[a2 + D1D*a1];
143 cin[a1a2] -= X(idx, e);
150 idx = lex_map[(a2+1) + D1D*a1];
151 cin[1 + a1a2] += X(idx, e);
154 idx = lex_map[a2 + D1D*a1];
155 cin[1 + a1a2] -= X(idx, e);
161 for (
int i2 = 0; i2 < Q1D; i2++)
163 for (
int a1 = 0; a1 < D1D-1; a1++)
165 const int a1i2 = 2*(i2 + Q1D*a1);
166 for (
int a2 = 0; a2 < D1D-a1-1; a2++)
168 const int a1a2 = 2*(a1 + (D1D-1)*a2);
169 const real_t Gai = Ga2t(i2, a1, a2);
170 C1[a1i2] += cin[a1a2] * Gai;
171 C1[1 + a1i2] += cin[1 + a1a2] * Gai;
180 for (
int i1 = 0; i1 < Q1D; i1++)
182 for (
int a1 = 0; a1 < D1D-1; a1++)
184 const real_t Gai = Ga1t(i1, a1);
185 for (
int i2 = 0; i2 < Q1D; i2++)
187 const int i1i2 = 2*(i2 + Q1D*i1);
188 const int a1i2 = 2*(i2 + Q1D*a1);
189 C2[i1i2] += C1[a1i2] * Gai;
190 C2[1 + i1i2] += C1[1 + a1i2] * Gai;
199 for (
int i1 = 0; i1 < Q1D; ++i1)
201 for (
int i2 = 0; i2 < Q1D; ++i2)
203 const real_t O11 = D(i1, i2, 0, e);
204 const real_t O21 = D(i1, i2, 1, e);
205 const real_t O12 = symmetric ? O21 : D(i1, i2, 2, e);
206 const real_t O22 = symmetric ? D(i1, i2, 2, e) : D(i1, i2, 3, e);
208 const int i1i2 = 2*(i2 + Q1D*i1);
209 fin[i1i2] = O11 * C2[i1i2] + O12 * C2[1 + i1i2];
210 fin[1 + i1i2] = O21 * C2[i1i2] + O22 * C2[1 + i1i2];
215 for (
int i1 = 0; i1 < Q1D; i1++)
217 for (
int a1 = 0; a1 < D1D-1; a1++)
219 const real_t Gai = Ga1(a1, i1);
220 for (
int i2 = 0; i2 < Q1D; i2++)
222 const int i1i2 = 2*(i2 + Q1D*i1);
223 const int a1i2 = 2*(i2 + Q1D*a1);
224 F1[a1i2] += fin[i1i2] * Gai;
225 F1[1 + a1i2] += fin[1 + i1i2] * Gai;
231 for (
int i2 = 0; i2 < Q1D; i2++)
233 for (
int a1 = 0; a1 < D1D-1; a1++)
235 const int a1i2 = 2*(i2 + Q1D*a1);
236 for (
int a2 = 0; a2 < D1D-a1-1; a2++)
238 const int a1a2 = 2*(a2 + (D1D-1)*a1);
239 const real_t Gai = Ga2(a2, a1, i2);
240 F2[a1a2] += F1[a1i2] * Gai;
241 F2[1 + a1a2] += F1[1 + a1i2] * Gai;
250 for (
int a1 = 0; a1 < D1D-1; ++a1)
252 for (
int a2 = 0; a2 < D1D-a1-1; ++a2)
255 int idx = lex_map[a2 + D1D*(a1+1)];
256 const int a2a1 = 2*(a2 + (D1D-1)*a1);
257 Y(idx,e) += p2 * F2[a2a1];
260 idx = lex_map[(a2+1) + D1D*a1];
261 Y(idx,e) += p2 * F2[1 + a2a1];
264 idx = lex_map[a2 + D1D*a1];
265 Y(idx,e) -= p2 * (F2[a2a1] + F2[1 + a2a1]);
271template<
int T_D1D = 0,
int T_Q1D = 0>
272inline void SmemPADiffusionApplyTriangle(
const int NE,
273 const bool symmetric,
274 const Array<int> &lex_map_,
279 const Array<real_t> &ga1_,
280 const Array<real_t> &ga2_,
281 const Array<real_t> &,
282 const Array<real_t> &ga1t_,
283 const Array<real_t> &ga2t_,
284 const Array<real_t> &,
291 const int D1D = T_D1D ? T_D1D : d1d;
292 const int Q1D = T_Q1D ? T_Q1D : q1d;
293 const int BASIS_DIM = D1D * (D1D+1) / 2;
294 const int p2 = (D1D-1) * (D1D-1);
299 const auto map = DeviceTensor<2,const int>(lex_map_.Read(), D1D, D1D);
304 const auto D =
Reshape(d_.Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
305 const auto x =
Reshape(x_.Read(), BASIS_DIM, NE);
306 auto Y =
Reshape(y_.ReadWrite(), BASIS_DIM, NE);
308 const int T1D = (Q1D > D1D) ? Q1D : D1D;
309 constexpr int T_T1D = (T_Q1D > T_D1D) ? T_Q1D : T_D1D;
313 const int tidz = MFEM_THREAD_ID(z);
314 const int D1D = T_D1D ? T_D1D : d1d;
315 const int Q1D = T_Q1D ? T_Q1D : q1d;
317 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D_SIMPLEX;
318 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D_SIMPLEX;
319 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
320 constexpr int BASIS_DIM = MD1 * (MD1+1) / 2;
322 MFEM_SHARED
real_t sBG[2][MQ1*MD1*MD1];
323 auto Ga1 = (
real_t (*)[MD1]) (sBG+0);
324 auto Ga2 = (
real_t (*)[MD1][MD1]) (sBG+1);
325 auto Ga1t = (
real_t (*)[MQ1]) (sBG+0);
326 auto Ga2t = (
real_t (*)[MD1][MQ1]) (sBG+1);
327 MFEM_SHARED
real_t Xz[BASIS_DIM];
328 MFEM_SHARED
real_t GD[2][MDQ][MDQ];
329 MFEM_SHARED
real_t GQ[2][MDQ][MDQ];
330 auto X = (
real_t (*))(Xz + tidz);
331 auto DQ0 = (
real_t (*)[MD1])(GD[0]);
332 auto DQ1 = (
real_t (*)[MD1])(GD[1]);
333 auto QQ0 = (
real_t (*)[MQ1])(GQ[0]);
334 auto QQ1 = (
real_t (*)[MQ1])(GQ[1]);
335 auto QD0 = (
real_t (*)[MQ1])(GD[0]);
336 auto QD1 = (
real_t (*)[MQ1])(GD[1]);
337 MFEM_SHARED
int s_lex[MD1*MD1];
338 auto lex_map = (int (*)[MD1])(s_lex);
341 MFEM_FOREACH_THREAD_DIRECT(a1,y,D1D)
343 MFEM_FOREACH_THREAD_DIRECT(a2,x,D1D-a1)
345 const int idx = map(a2,a1);
346 lex_map[a1][a2] = idx;
351 MFEM_FOREACH_THREAD_DIRECT(a1,y,D1D-1)
353 MFEM_FOREACH_THREAD_DIRECT(i1,x,Q1D)
355 Ga1[i1][a1] = ga1(a1,i1);
356 for (
int a2 = 0; a2 < D1D-a1-1; a2++)
358 Ga2[i1][a1][a2] = ga2(a2,a1,i1);
364 MFEM_FOREACH_THREAD_DIRECT(i2,y,Q1D)
366 MFEM_FOREACH_THREAD_DIRECT(a1,x,D1D-1)
368 real_t uu = 0.0, vv = 0.0;
369 for (
int a2 = 0; a2 < D1D-a1-1; ++a2)
373 int idx = lex_map[a1+1][a2];
377 idx = lex_map[a1][a2];
381 idx = lex_map[a1][a2+1];
385 idx = lex_map[a1][a2];
388 const real_t Gai = Ga2[i2][a1][a2];
398 MFEM_FOREACH_THREAD_DIRECT(i1,y,Q1D)
400 MFEM_FOREACH_THREAD_DIRECT(i2,x,Q1D)
403 for (
int a1 = 0; a1 < D1D-1; a1++)
405 const real_t Gai = Ga1[i1][a1];
406 u += DQ0[i2][a1] * Gai;
407 v += DQ1[i2][a1] * Gai;
414 MFEM_FOREACH_THREAD_DIRECT(i1,y,Q1D)
416 MFEM_FOREACH_THREAD_DIRECT(i2,x,Q1D)
418 const real_t O11 = D(i1, i2, 0, e);
419 const real_t O21 = D(i1, i2, 1, e);
420 const real_t O12 = symmetric ? O21 : D(i1, i2, 2, e);
421 const real_t O22 = symmetric ? D(i1, i2, 2, e) : D(i1, i2, 3, e);
422 const real_t gX = QQ0[i1][i2];
423 const real_t gY = QQ1[i1][i2];
425 QQ0[i1][i2] = (O11 * gX) + (O12 * gY);
426 QQ1[i1][i2] = (O21 * gX) + (O22 * gY);
430 MFEM_FOREACH_THREAD_DIRECT(a1,y,D1D-1)
432 MFEM_FOREACH_THREAD_DIRECT(i1,x,Q1D)
434 Ga1t[a1][i1] = ga1t(i1,a1);
435 for (
int a2 = 0; a2 < D1D-a1-1; a2++)
437 Ga2t[a2][a1][i1] = ga2t(i1,a1,a2);
443 MFEM_FOREACH_THREAD_DIRECT(i2,y,Q1D)
445 MFEM_FOREACH_THREAD_DIRECT(a1,x,D1D-1)
448 for (
int i1 = 0; i1 < Q1D; i1++)
450 u += QQ0[i1][i2] * Ga1t[a1][i1];
451 v += QQ1[i1][i2] * Ga1t[a1][i1];
459 MFEM_FOREACH_THREAD_DIRECT(a1,y,D1D-1)
461 MFEM_FOREACH_THREAD_DIRECT(a2,x,D1D-a1-1)
464 for (
int i2 = 0; i2 < Q1D; i2++)
466 u += QD0[a1][i2] * Ga2t[a2][a1][i2];
467 v += QD1[a1][i2] * Ga2t[a2][a1][i2];
470 int idx = lex_map[a1+1][a2];
474 idx = lex_map[a1][a2+1];
478 idx = lex_map[a1][a2];
479 Y(idx,e) -= p2 * (
u + v);
496template<
int T_D1D = 0,
int T_Q1D = 0>
497inline void PADiffusionApplyTetrahedron(
const int NE,
498 const bool symmetric,
499 const Array<int> &lex_map_,
500 const Array<int> &forward_map2d_,
501 const Array<int> &inverse_map2d_,
503 const Array<int> &inverse_map3d_,
504 const Array<real_t> &ga1_,
505 const Array<real_t> &ga2_,
506 const Array<real_t> &,
507 const Array<real_t> &ga1t_,
508 const Array<real_t> &ga2t_,
509 const Array<real_t> &ga3t_,
516 const int D1D = T_D1D ? T_D1D : d1d;
517 const int Q1D = T_Q1D ? T_Q1D : q1d;
518 const int BASIS_DIM3D = D1D * (D1D+1) * (D1D+2) / 6;
519 const int BASIS_DIM2D_DIFF = (D1D-1) * D1D / 2;
520 const int BASIS_DIM3D_DIFF = (D1D-1) * D1D * (D1D+1) / 6;
521 const int p2 = (D1D-1) * (D1D-1);
526 const auto lex_map = lex_map_.Read();
527 const auto forward_map2d = forward_map2d_.Read();
528 const auto inverse_map2d = inverse_map2d_.Read();
529 const auto inverse_map3d = inverse_map3d_.Read();
535 const auto D =
Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
536 const auto X =
Reshape(x_.Read(), BASIS_DIM3D, NE);
537 auto Y =
Reshape(y_.ReadWrite(), BASIS_DIM3D, NE);
542 const int D1D = T_D1D ? T_D1D : d1d;
543 const int Q1D = T_Q1D ? T_Q1D : q1d;
545 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D_SIMPLEX;
546 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D_SIMPLEX;
548 constexpr int basis_dim2d = (int) 3 * (max_D1D-1) * (max_D1D) / 2;
549 real_t C1[(int) 3 * basis_dim2d * max_Q1D];
550 real_t C2[3 * (max_D1D-1) * max_Q1D * max_Q1D];
551 real_t C3[3 * max_Q1D * max_Q1D * max_Q1D];
552 real_t F1[3 * (max_D1D-1) * max_Q1D * max_Q1D];
553 real_t F2[(int) 3 * basis_dim2d * max_Q1D];
555 for (
int i3 = 0; i3 < Q1D; i3++)
557 for (
int i2 = 0; i2 < Q1D; i2++)
559 for (
int i1 = 0; i1 < Q1D; i1++)
561 const int q = 3*(i1 + Q1D*(i2 + Q1D*i3));
566 for (
int a1 = 0; a1 < D1D-1; a1++)
568 const int q = 3*(a1 + (D1D-1)*(i2 + Q1D*i3));
578 for (
int a = 0;
a < BASIS_DIM2D_DIFF;
a++)
580 const int q = 3*(
a + BASIS_DIM2D_DIFF*i3);
592 for (
int a = 0;
a < BASIS_DIM3D_DIFF;
a++)
594 const int a1 = inverse_map3d[3*
a];
595 const int a2 = inverse_map3d[1 + 3*
a];
596 const int a3 = inverse_map3d[2 + 3*
a];
597 const int a_2d = forward_map2d[a2 + (D1D-1)*a1];
600 real_t u = 0.0, v = 0.0, w = 0.0;
602 int idx = lex_map[a3 + D1D*(a2 + D1D*a1)];
612 idx = lex_map[a3+1 + D1D*(a2 + D1D*a1)];
617 idx = lex_map[a3 + D1D*(a2+1 + D1D*a1)];
621 idx = lex_map[a3 + D1D*(a2 + D1D*(a1 + 1))];
624 for (
int i3 = 0; i3 < Q1D; i3++)
626 const int a1a2i3 = 3*(i3 + Q1D*a_2d);
629 C1[a1a2i3] +=
u * Gai;
630 C1[1 + a1a2i3] += v * Gai;
631 C1[2 + a1a2i3] += w * Gai;
637 for (
int a = 0;
a < BASIS_DIM2D_DIFF;
a++)
639 const int a1 = inverse_map2d[2*
a];
640 for (
int i3 = 0; i3 < Q1D; i3++)
642 const int a1a2i3 = 3*(i3 + Q1D*
a);
643 const real_t C1x = C1[a1a2i3];
644 const real_t C1y = C1[1 + a1a2i3];
645 const real_t C1z = C1[2 + a1a2i3];
646 for (
int i2 = 0; i2 < Q1D; i2++)
650 const int a1i2i3 = 3*(i2 + Q1D*(i3 + Q1D*a1));
651 C2[a1i2i3] += C1x * Gai;
652 C2[1 + a1i2i3] += C1y * Gai;
653 C2[2 + a1i2i3] += C1z * Gai;
658 for (
int a1 = 0; a1 < D1D-1; a1++)
660 for (
int i3 = 0; i3 < Q1D; i3++)
662 for (
int i2 = 0; i2 < Q1D; i2++)
664 const int a1i2i3 = 3*(i2 + Q1D*(i3 + Q1D*a1));
665 const real_t C2x = C2[a1i2i3];
666 const real_t C2y = C2[1 + a1i2i3];
667 const real_t C2z = C2[2 + a1i2i3];
668 for (
int i1 = 0; i1 < Q1D; i1++)
670 const real_t Gai = Ga1t(i1,a1);
671 const int i1i2i3 = 3*(i1 + Q1D*(i2 + Q1D*i3));
672 C3[i1i2i3] += C2x * Gai;
673 C3[1 + i1i2i3] += C2y * Gai;
674 C3[2 + i1i2i3] += C2z * Gai;
681 for (
int i3 = 0; i3 < Q1D; i3++)
683 for (
int i2 = 0; i2 < Q1D; i2++)
685 for (
int i1 = 0; i1 < Q1D; i1++)
687 const real_t O11 = D(i1,i2,i3,0,e);
688 const real_t O12 = D(i1,i2,i3,1,e);
689 const real_t O13 = D(i1,i2,i3,2,e);
690 const real_t O21 = symmetric ? O12 : D(i1,i2,i3,3,e);
691 const real_t O22 = symmetric ? D(i1,i2,i3,3,e) : D(i1,i2,i3,4,e);
692 const real_t O23 = symmetric ? D(i1,i2,i3,4,e) : D(i1,i2,i3,5,e);
693 const real_t O31 = symmetric ? O13 : D(i1,i2,i3,6,e);
694 const real_t O32 = symmetric ? O23 : D(i1,i2,i3,7,e);
695 const real_t O33 = symmetric ? D(i1,i2,i3,5,e) : D(i1,i2,i3,8,e);
697 const int i1i2i3 = 3*(i1 + Q1D*(i2 + Q1D*i3));
699 real_t gY = C3[1 + i1i2i3];
700 real_t gZ = C3[2 + i1i2i3];
702 const real_t fin1 = O11 * gX + O12 * gY + O13 * gZ;
703 const real_t fin2 = O21 * gX + O22 * gY + O23 * gZ;
704 const real_t fin3 = O31 * gX + O32 * gY + O33 * gZ;
705 for (
int a1 = 0; a1 < D1D-1; a1++)
707 const real_t Gai = Ga1(a1,i1);
708 const int a1i2i3 = 3*(a1 + (D1D-1)*(i2 + Q1D*i3));
709 F1[a1i2i3] += fin1 * Gai;
710 F1[1 + a1i2i3] += fin2 * Gai;
711 F1[2 + a1i2i3] += fin3 * Gai;
718 for (
int i3 = 0; i3 < Q1D; i3++)
720 for (
int i2 = 0; i2 < Q1D; i2++)
722 for (
int a = 0;
a < BASIS_DIM2D_DIFF;
a++)
724 const int a1 = inverse_map2d[2*
a];
727 const int a1a2i3 = 3*(
a + BASIS_DIM2D_DIFF*i3);
728 const int a1i2i3 = 3*(a1 + (D1D-1)*(i2 + Q1D*i3));
729 F2[a1a2i3] += F1[a1i2i3] * Gai;
730 F2[1 + a1a2i3] += F1[1 + a1i2i3] * Gai;
731 F2[2 + a1a2i3] += F1[2 + a1i2i3] * Gai;
736 for (
int a = 0;
a < BASIS_DIM3D_DIFF;
a++)
738 const int a1 = inverse_map3d[3*
a];
739 const int a2 = inverse_map3d[1 + 3*
a];
740 const int a3 = inverse_map3d[2 + 3*
a];
741 const int a_2d = forward_map2d[a2 + (D1D-1)*a1];
743 real_t u = 0.0, v = 0.0, w = 0.0;
745 for (
int i3 = 0; i3 < Q1D; i3++)
749 const int a1a2i3 = 3*(a_2d + BASIS_DIM2D_DIFF*i3);
750 u += F2[a1a2i3] * Gai;
751 v += F2[1 + a1a2i3] * Gai;
752 w += F2[2 + a1a2i3] * Gai;
756 int idx = lex_map[a3 + D1D*(a2 + D1D*a1)];
757 Y(idx,e) -= p2 * (
u + v + w);
760 idx = lex_map[a3 + D1D*(a2 + D1D*(a1+1))];
764 idx = lex_map[a3 + D1D*(a2+1 + D1D*a1)];
768 idx = lex_map[a3+1 + D1D*(a2 + D1D*a1)];
775template<
int T_D1D = 0,
int T_Q1D = 0>
776inline void SmemPADiffusionApplyTetrahedron(
const int NE,
777 const bool symmetric,
778 const Array<int> &lex_map_,
779 const Array<int> &forward_map2d_,
780 const Array<int> &inverse_map2d_,
781 const Array<int> &forward_map3d_,
783 const Array<real_t> &ga1_,
784 const Array<real_t> &ga2_,
785 const Array<real_t> &ga3_,
786 const Array<real_t> &ga1t_,
787 const Array<real_t> &ga2t_,
788 const Array<real_t> &ga3t_,
795 const int D1D = T_D1D ? T_D1D : d1d;
796 const int Q1D = T_Q1D ? T_Q1D : q1d;
797 const int BASIS_DIM3D = D1D * (D1D+1) * (D1D+2) / 6;
798 const int BASIS_DIM2D_DIFF = (D1D-1) * D1D / 2;
799 const int BASIS_DIM3D_DIFF = (D1D-1) * D1D * (D1D+1) / 6;
800 const int p2 = (D1D-1) * (D1D-1);
804 MFEM_VERIFY(D1D <= MD1,
"");
805 MFEM_VERIFY(Q1D <= MQ1,
"");
807 const auto forward_map3d__ =
808 DeviceTensor<3,const int>(forward_map3d_.Read(), D1D-1, D1D-1, D1D-1);
809 const auto forward_map2d__ =
810 DeviceTensor<2,const int>(forward_map2d_.Read(), D1D-1, D1D-1);
811 const auto inverse_map2d__ =
812 DeviceTensor<2,const int>(inverse_map2d_.Read(), 2, BASIS_DIM2D_DIFF);
813 const auto lex_map__ =
814 DeviceTensor<3,const int>(lex_map_.Read(), D1D, D1D, D1D);
822 const auto d =
Reshape(d_.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
823 const auto x =
Reshape(x_.Read(), BASIS_DIM3D, NE);
824 auto y =
Reshape(y_.ReadWrite(), BASIS_DIM3D, NE);
826 const int T1D = (Q1D > D1D) ? Q1D : D1D;
827 constexpr int T_T1D = (T_Q1D > T_D1D) ? T_Q1D : T_D1D;
830 [=] MFEM_HOST_DEVICE (
int e)
832 const int D1D = T_D1D ? T_D1D : d1d;
833 const int Q1D = T_Q1D ? T_Q1D : q1d;
835 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D_SIMPLEX;
836 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D_SIMPLEX;
837 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
838 constexpr int BASIS_DIM2D_DIFF = (MD1 > 1) ? (MD1-1) * MD1 / 2 : 1;
839 constexpr int BASIS_DIM3D_DIFF = (MD1 > 1) ? (MD1-1) * MD1 * (MD1 + 1) / 6 : 1;
841 MFEM_SHARED
real_t sBG3[BASIS_DIM3D_DIFF*MQ1];
842 MFEM_SHARED
real_t sBG2[BASIS_DIM2D_DIFF*MQ1];
843 MFEM_SHARED
real_t sBG1[MD1*MQ1];
844 auto Ga1 = (
real_t (*)[MD1]) sBG1;
845 auto Ga2 = (
real_t (*)[BASIS_DIM2D_DIFF]) sBG2;
846 auto Ga3 = (
real_t (*)[BASIS_DIM3D_DIFF]) sBG3;
847 auto Ga1t = (
real_t (*)[MQ1]) sBG1;
848 auto Ga2t = (
real_t (*)[MQ1]) sBG2;
849 auto Ga3t = (
real_t (*)[MQ1]) sBG3;
850 MFEM_SHARED
real_t sm0[3][MDQ*MDQ*MDQ];
851 MFEM_SHARED
real_t sm1[3][MDQ*MDQ*MDQ];
852 auto X = (
real_t (*)) (sm0+0);
853 auto DDQ0 = (
real_t (*)[MQ1]) (sm1+0);
854 auto DDQ1 = (
real_t (*)[MQ1]) (sm1+1);
855 auto DDQ2 = (
real_t (*)[MQ1]) (sm1+2);
856 auto DQQ0 = (
real_t (*)[MQ1][MQ1]) (sm0+0);
857 auto DQQ1 = (
real_t (*)[MQ1][MQ1]) (sm0+1);
858 auto DQQ2 = (
real_t (*)[MQ1][MQ1]) (sm0+2);
859 auto QQQ0 = (
real_t (*)[MQ1][MQ1]) (sm1+0);
860 auto QQQ1 = (
real_t (*)[MQ1][MQ1]) (sm1+1);
861 auto QQQ2 = (
real_t (*)[MQ1][MQ1]) (sm1+2);
862 auto QQD0 = (
real_t (*)[MQ1][MQ1]) (sm0+0);
863 auto QQD1 = (
real_t (*)[MQ1][MQ1]) (sm0+1);
864 auto QQD2 = (
real_t (*)[MQ1][MQ1]) (sm0+2);
865 auto QDD0 = (
real_t (*)[MQ1]) (sm1+0);
866 auto QDD1 = (
real_t (*)[MQ1]) (sm1+1);
867 auto QDD2 = (
real_t (*)[MQ1]) (sm1+2);
868 MFEM_SHARED
int s3D[MD1*MD1*MD1];
869 MFEM_SHARED
int s3D_lex[MD1*MD1*MD1];
870 MFEM_SHARED
int s2D[MD1*MD1];
871 auto forward_map3d = (int (*)[MD1][MD1]) s3D;
872 auto forward_map2d = (int (*)[MD1]) s2D;
873 auto lex_map = (int (*)[MD1][MD1]) s3D_lex;
874 MFEM_SHARED
int s2D_inv[BASIS_DIM2D_DIFF*2];
875 auto inverse_map2d = (int (*)[2]) s2D_inv;
877 MFEM_FOREACH_THREAD_DIRECT(i3a1,y,Q1D*D1D)
879 const int i3 = (int) i3a1 / D1D;
880 const int a1 = i3a1 % D1D;
883 Ga1[i3][a1] = ga1(a1,i3);
885 MFEM_FOREACH_THREAD_DIRECT(a2,x,D1D-a1)
887 if (a1 < D1D-1 && a2 < D1D-a1-1)
889 const int a_2d = forward_map2d__(a2, a1);
890 forward_map2d[a1][a2] = a_2d;
891 inverse_map2d[a_2d][0] = inverse_map2d__(0,a_2d);
892 inverse_map2d[a_2d][1] = inverse_map2d__(1,a_2d);
893 Ga2[i3][a_2d] = ga2(a_2d,i3);
896 for (
int a3 = 0; a3 < D1D-a1-a2; a3++)
898 if (a1 < D1D-1 && a2 < D1D-a1-1 && a3 < D1D-a1-a2-1)
900 const int a = forward_map3d__(a3, a2, a1);
901 forward_map3d[a1][a2][a3] =
a;
902 Ga3[i3][
a] = ga3(
a,i3);
904 const int idx = lex_map__(a3, a2, a1);
905 lex_map[a1][a2][a3] = idx;
911 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
913 const int a1 = inverse_map2d[a_2d][0];
914 const int a2 = inverse_map2d[a_2d][1];
915 MFEM_FOREACH_THREAD_DIRECT(i3,x,Q1D)
917 real_t uu = 0.0, vv = 0.0, ww = 0.0;
919 for (
int a3 = 0; a3 < D1D-a1-a2-1; a3++)
921 const int a = forward_map3d[a1][a2][a3];
922 real_t u = 0.0, v = 0.0, w = 0.0;
924 int idx = lex_map[a1][a2][a3];
929 idx = lex_map[a1][a2][a3+1];
932 idx = lex_map[a1][a2+1][a3];
935 idx = lex_map[a1+1][a2][a3];
949 MFEM_FOREACH_THREAD_DIRECT(a1i2,y,Q1D*(D1D-1))
951 const int a1 = (int) a1i2 / Q1D;
952 const int i2 = a1i2 % Q1D;
953 MFEM_FOREACH_THREAD_DIRECT(i3,x,Q1D)
955 real_t u = 0.0, v = 0.0, w = 0.0;
957 for (
int a2 = 0; a2 < D1D-a1-1; a2++)
959 const int a_2d = forward_map2d[a1][a2];
960 u += DDQ0[a_2d][i3] * Ga2[i2][a_2d];
961 v += DDQ1[a_2d][i3] * Ga2[i2][a_2d];
962 w += DDQ2[a_2d][i3] * Ga2[i2][a_2d];
964 DQQ0[a1][i2][i3] =
u;
965 DQQ1[a1][i2][i3] = v;
966 DQQ2[a1][i2][i3] = w;
970 MFEM_FOREACH_THREAD_DIRECT(i1i2,y,Q1D*Q1D)
972 const int i2 = i1i2 % Q1D;
973 const int i1 = (int) i1i2 / Q1D;
974 MFEM_FOREACH_THREAD_DIRECT(i3,x,Q1D)
976 real_t u = 0.0, v = 0.0, w = 0.0;
978 for (
int a1 = 0; a1 < D1D-1; a1++)
980 u += DQQ0[a1][i2][i3] * Ga1[i1][a1];
981 v += DQQ1[a1][i2][i3] * Ga1[i1][a1];
982 w += DQQ2[a1][i2][i3] * Ga1[i1][a1];
984 const real_t O11 = d(i1,i2,i3,0,e);
985 const real_t O12 = d(i1,i2,i3,1,e);
986 const real_t O13 = d(i1,i2,i3,2,e);
987 const real_t O21 = symmetric ? O12 : d(i1,i2,i3,3,e);
988 const real_t O22 = symmetric ? d(i1,i2,i3,3,e) : d(i1,i2,i3,4,e);
989 const real_t O23 = symmetric ? d(i1,i2,i3,4,e) : d(i1,i2,i3,5,e);
990 const real_t O31 = symmetric ? O13 : d(i1,i2,i3,6,e);
991 const real_t O32 = symmetric ? O23 : d(i1,i2,i3,7,e);
992 const real_t O33 = symmetric ? d(i1,i2,i3,5,e) : d(i1,i2,i3,8,e);
996 QQQ0[i1][i2][i3] = O11 * gX + O12 * gY + O13 * gZ;
997 QQQ1[i1][i2][i3] = O21 * gX + O22 * gY + O23 * gZ;
998 QQQ2[i1][i2][i3] = O31 * gX + O32 * gY + O33 * gZ;
1002 MFEM_FOREACH_THREAD_DIRECT(a1i1,y,Q1D*(D1D-1))
1004 const int i1 = a1i1 % Q1D;
1005 const int a1 = (int) a1i1 / Q1D;
1006 Ga1t[a1][i1] = ga1t(i1,a1);
1007 MFEM_FOREACH_THREAD_DIRECT(a2,x,D1D-a1-1)
1009 const int a_2d = forward_map2d[a1][a2];
1010 Ga2t[a_2d][i1] = ga2t(i1,a_2d);
1012 for (
int a3 = 0; a3 < D1D-a1-a2-1; a3++)
1014 const int a = forward_map3d[a1][a2][a3];
1015 Ga3t[
a][i1] = ga3t(i1,
a);
1020 MFEM_FOREACH_THREAD_DIRECT(i2i3,y,Q1D*Q1D)
1022 const int i3 = i2i3 % Q1D;
1023 const int i2 = (int) i2i3 / Q1D;
1024 MFEM_FOREACH_THREAD_DIRECT(a1,x,D1D-1)
1026 real_t u = 0.0, v = 0.0, w = 0.0;
1028 for (
int i1 = 0; i1 < Q1D; i1++)
1030 u += QQQ0[i1][i2][i3] * Ga1t[a1][i1];
1031 v += QQQ1[i1][i2][i3] * Ga1t[a1][i1];
1032 w += QQQ2[i1][i2][i3] * Ga1t[a1][i1];
1034 QQD0[a1][i2][i3] =
u;
1035 QQD1[a1][i2][i3] = v;
1036 QQD2[a1][i2][i3] = w;
1040 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1042 const int a1 = inverse_map2d[a_2d][0];
1043 MFEM_FOREACH_THREAD_DIRECT(i3,x,Q1D)
1045 real_t u = 0.0, v = 0.0, w = 0.0;
1047 for (
int i2 = 0; i2 < Q1D; i2++)
1049 u += QQD0[a1][i2][i3] * Ga2t[a_2d][i2];
1050 v += QQD1[a1][i2][i3] * Ga2t[a_2d][i2];
1051 w += QQD2[a1][i2][i3] * Ga2t[a_2d][i2];
1061 auto uvw = (
real_t (*)[BASIS_DIM2D_DIFF][MD1]) sm0;
1062 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1064 const int a1 = inverse_map2d[a_2d][0];
1065 const int a2 = inverse_map2d[a_2d][1];
1066 MFEM_FOREACH_THREAD_DIRECT(a3,x,D1D-a1-a2-1)
1068 real_t u = 0.0, v = 0.0, w = 0.0;
1069 const int a = forward_map3d[a1][a2][a3];
1071 for (
int i3 = 0; i3 < Q1D; i3++)
1073 u += QDD0[a_2d][i3] * Ga3t[
a][i3];
1074 v += QDD1[a_2d][i3] * Ga3t[
a][i3];
1075 w += QDD2[a_2d][i3] * Ga3t[
a][i3];
1077 uvw[0][a_2d][a3] =
u;
1078 uvw[1][a_2d][a3] = v;
1079 uvw[2][a_2d][a3] = w;
1084 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1086 const int a1 = inverse_map2d[a_2d][0];
1087 const int a2 = inverse_map2d[a_2d][1];
1088 MFEM_FOREACH_THREAD_DIRECT(a3,x,D1D-a1-a2-1)
1090 const real_t u = uvw[0][a_2d][a3];
1091 const real_t v = uvw[1][a_2d][a3];
1092 const real_t w = uvw[2][a_2d][a3];
1093 const int idx = lex_map[a1][a2][a3];
1094 y(idx,e) -= p2 * (
u + v + w);
1099 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1101 const int a1 = inverse_map2d[a_2d][0];
1102 const int a2 = inverse_map2d[a_2d][1];
1103 MFEM_FOREACH_THREAD_DIRECT(a3,x,D1D-a1-a2-1)
1105 const real_t u = uvw[0][a_2d][a3];
1106 const int idx = lex_map[a1+1][a2][a3];
1112 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1114 const int a1 = inverse_map2d[a_2d][0];
1115 const int a2 = inverse_map2d[a_2d][1];
1116 MFEM_FOREACH_THREAD_DIRECT(a3,x,D1D-a1-a2-1)
1118 const real_t v = uvw[1][a_2d][a3];
1119 const int idx = lex_map[a1][a2+1][a3];
1125 MFEM_FOREACH_THREAD_DIRECT(a_2d,y,BASIS_DIM2D_DIFF)
1127 const int a1 = inverse_map2d[a_2d][0];
1128 const int a2 = inverse_map2d[a_2d][1];
1129 MFEM_FOREACH_THREAD_DIRECT(a3,x,D1D-a1-a2-1)
1131 const real_t w = uvw[2][a_2d][a3];
1132 const int idx = lex_map[a1][a2][a3+1];
1140template<
int DIM,
int D1D,
int Q1D>
1142DiffusionIntegrator::ApplySimplexPAKernels::Kernel()
1144 if constexpr (
DIM == 2)
1146 return internal::SmemPADiffusionApplyTriangle<D1D, Q1D>;
1148 else if constexpr (
DIM == 3)
1150 return internal::SmemPADiffusionApplyTetrahedron<D1D, Q1D>;
1152 else { MFEM_ABORT(
""); }
1157DiffusionIntegrator::ApplySimplexPAKernels::Fallback(
int dim,
int,
int)
1161 return internal::PADiffusionApplyTriangle;
1165 return internal::PADiffusionApplyTetrahedron;
1167 else { MFEM_ABORT(
""); }
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
real_t u(const Vector &xvec)
DeviceTensor< 3, const real_t > ConstDeviceCube
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
void forall_2D(int N, int X, int Y, lambda &&body)
DeviceTensor< 2, const real_t > ConstDeviceMatrix
void forall(int N, lambda &&body)
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
int MAX_D1D_SIMPLEX
Maximum number of 1D nodal points for simplices.
int MAX_Q1D_SIMPLEX
Maximum number of 1D quadrature points for simplices.