12#ifndef MFEM_BILININTEG_MASS_KERNELS_HPP
13#define MFEM_BILININTEG_MASS_KERNELS_HPP
33inline void PAMassAssembleDiagonal1D(
const int NE,
const Array<real_t> &
b,
34 const Vector &d, Vector &y,
const int D1D,
37 auto B =
Reshape(
b.Read(), Q1D, D1D);
38 auto D =
Reshape(d.Read(), Q1D, NE);
39 auto Y =
Reshape(y.ReadWrite(), D1D, NE);
42 for (
int dx = 0; dx < D1D; ++dx)
44 for (
int qx = 0; qx < Q1D; ++qx)
46 Y(dx, e) += B(qx, dx) * B(qx, dx) * D(qx, e);
52template <
bool ACCUMULATE = true>
53MFEM_HOST_DEVICE
inline
54void PAMassApply1D_Element(
const int e,
74 for (
int dx = 0; dx < D1D; ++dx)
80 real_t XQ[DofQuadLimits::MAX_Q1D];
81 for (
int qx = 0; qx < Q1D; ++qx)
85 for (
int dx = 0; dx < D1D; ++dx)
88 for (
int qx = 0; qx < Q1D; ++qx)
93 for (
int qx = 0; qx < Q1D; ++qx)
95 const double q = XQ[qx]*D(qx,e);
96 for (
int dx = 0; dx < D1D; ++dx)
98 Y(dx,e) += Bt(dx,qx) * q;
104inline void PAMassApply1D(
const int NE,
const Array<real_t> &b_,
105 const Array<real_t> &bt_,
const Vector &d_,
106 const Vector &x_, Vector &y_,
const int d1d = 0,
112 const auto B = b_.Read();
113 const auto Bt = bt_.Read();
114 const auto D = d_.Read();
115 const auto X = x_.Read();
116 auto Y = y_.ReadWrite();
120 internal::PAMassApply1D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
125template<
int T_D1D = 0,
int T_Q1D = 0>
126inline void PAMassAssembleDiagonal2D(
const int NE,
127 const Array<real_t> &
b,
133 const int D1D = T_D1D ? T_D1D : d1d;
134 const int Q1D = T_Q1D ? T_Q1D : q1d;
137 auto B =
Reshape(
b.Read(), Q1D, D1D);
138 auto D =
Reshape(d.Read(), Q1D, Q1D, NE);
139 auto Y =
Reshape(y.ReadWrite(), D1D, D1D, NE);
142 const int D1D = T_D1D ? T_D1D : d1d;
143 const int Q1D = T_Q1D ? T_Q1D : q1d;
144 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
145 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
147 for (
int qx = 0; qx < Q1D; ++qx)
149 for (
int dy = 0; dy < D1D; ++dy)
152 for (
int qy = 0; qy < Q1D; ++qy)
154 QD[qx][dy] += B(qy, dy) * B(qy, dy) * D(qx, qy, e);
158 for (
int dy = 0; dy < D1D; ++dy)
160 for (
int dx = 0; dx < D1D; ++dx)
162 for (
int qx = 0; qx < Q1D; ++qx)
164 Y(dx,dy,e) += B(qx, dx) * B(qx, dx) * QD[qx][dy];
173constexpr int ipow(
int x,
int p) {
return p == 0 ? 1 : x*ipow(x,
p-1); }
174constexpr int D(
int D1D) {
return (11 - D1D) / 2; }
175constexpr int NBZ(
int D1D)
177 return ipow(2, D(D1D) >= 0 ? D(D1D) : 0);
179constexpr int NBZ3D(
int MDQ)
181 return MDQ > 0 ? std::min<int>(
182 (128 + MDQ * MDQ * MDQ - 1) / (MDQ * MDQ * MDQ), 64)
188template<
int T_D1D = 0,
int T_Q1D = 0>
189inline void SmemPAMassAssembleDiagonal2D(
const int NE,
190 const Array<real_t> &b_,
196 static constexpr int T_NBZ = mass::NBZ(T_D1D);
197 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
198 const int D1D = T_D1D ? T_D1D : d1d;
199 const int Q1D = T_Q1D ? T_Q1D : q1d;
202 MFEM_VERIFY(D1D <= max_d1d,
"");
203 MFEM_VERIFY(Q1D <= max_q1d,
"");
204 auto b =
Reshape(b_.Read(), Q1D, D1D);
205 auto D =
Reshape(d_.Read(), Q1D, Q1D, NE);
206 auto Y =
Reshape(y_.ReadWrite(), D1D, D1D, NE);
209 const int tidz = MFEM_THREAD_ID(z);
210 const int D1D = T_D1D ? T_D1D : d1d;
211 const int Q1D = T_Q1D ? T_Q1D : q1d;
212 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
213 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
214 MFEM_SHARED
real_t B[MQ1][MD1];
215 MFEM_SHARED
real_t QDZ[NBZ][MQ1][MD1];
219 MFEM_FOREACH_THREAD(d,y,D1D)
221 MFEM_FOREACH_THREAD(q,x,Q1D)
228 MFEM_FOREACH_THREAD(qx,x,Q1D)
230 MFEM_FOREACH_THREAD(dy,y,D1D)
233 for (
int qy = 0; qy < Q1D; ++qy)
235 QD[qx][dy] += B[qy][dy] * B[qy][dy] * D(qx, qy, e);
240 MFEM_FOREACH_THREAD(dy,y,D1D)
242 MFEM_FOREACH_THREAD(dx,x,D1D)
244 for (
int qx = 0; qx < Q1D; ++qx)
247 Y(dx,dy,e) += B[qx][dx] * B[qx][dx] * QD[qx][dy];
255template<
int T_D1D = 0,
int T_Q1D = 0>
256inline void PAMassAssembleDiagonal3D(
const int NE,
257 const Array<real_t> &
b,
263 const int D1D = T_D1D ? T_D1D : d1d;
264 const int Q1D = T_Q1D ? T_Q1D : q1d;
267 auto B =
Reshape(
b.Read(), Q1D, D1D);
268 auto D =
Reshape(d.Read(), Q1D, Q1D, Q1D, NE);
269 auto Y =
Reshape(y.ReadWrite(), D1D, D1D, D1D, NE);
272 const int D1D = T_D1D ? T_D1D : d1d;
273 const int Q1D = T_Q1D ? T_Q1D : q1d;
274 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
275 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
276 real_t QQD[MQ1][MQ1][MD1];
277 real_t QDD[MQ1][MD1][MD1];
278 for (
int qx = 0; qx < Q1D; ++qx)
280 for (
int qy = 0; qy < Q1D; ++qy)
282 for (
int dz = 0; dz < D1D; ++dz)
284 QQD[qx][qy][dz] = 0.0;
285 for (
int qz = 0; qz < Q1D; ++qz)
287 QQD[qx][qy][dz] += B(qz, dz) * B(qz, dz) * D(qx, qy, qz, e);
292 for (
int qx = 0; qx < Q1D; ++qx)
294 for (
int dz = 0; dz < D1D; ++dz)
296 for (
int dy = 0; dy < D1D; ++dy)
298 QDD[qx][dy][dz] = 0.0;
299 for (
int qy = 0; qy < Q1D; ++qy)
301 QDD[qx][dy][dz] += B(qy, dy) * B(qy, dy) * QQD[qx][qy][dz];
306 for (
int dz = 0; dz < D1D; ++dz)
308 for (
int dy = 0; dy < D1D; ++dy)
310 for (
int dx = 0; dx < D1D; ++dx)
313 for (
int qx = 0; qx < Q1D; ++qx)
315 t += B(qx, dx) * B(qx, dx) * QDD[qx][dy][dz];
317 Y(dx, dy, dz, e) += t;
325template<
int T_D1D = 0,
int T_Q1D = 0>
326inline void SmemPAMassAssembleDiagonal3D(
const int NE,
327 const Array<real_t> &b_,
333 const int D1D = T_D1D ? T_D1D : d1d;
334 const int Q1D = T_Q1D ? T_Q1D : q1d;
337 MFEM_VERIFY(D1D <= max_d1d,
"");
338 MFEM_VERIFY(Q1D <= max_q1d,
"");
339 auto b =
Reshape(b_.Read(), Q1D, D1D);
340 auto D =
Reshape(d_.Read(), Q1D, Q1D, Q1D, NE);
341 auto Y =
Reshape(y_.ReadWrite(), D1D, D1D, D1D, NE);
344 const int tidz = MFEM_THREAD_ID(z);
345 const int D1D = T_D1D ? T_D1D : d1d;
346 const int Q1D = T_Q1D ? T_Q1D : q1d;
347 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
348 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
349 MFEM_SHARED
real_t B[MQ1][MD1];
350 MFEM_SHARED
real_t QQD[MQ1][MQ1][MD1];
351 MFEM_SHARED
real_t QDD[MQ1][MD1][MD1];
354 MFEM_FOREACH_THREAD(d,y,D1D)
356 MFEM_FOREACH_THREAD(q,x,Q1D)
363 MFEM_FOREACH_THREAD(qx,x,Q1D)
365 MFEM_FOREACH_THREAD(qy,y,Q1D)
367 MFEM_FOREACH_THREAD(dz,z,D1D)
369 QQD[qx][qy][dz] = 0.0;
370 for (
int qz = 0; qz < Q1D; ++qz)
372 QQD[qx][qy][dz] += B[qz][dz] * B[qz][dz] * D(qx, qy, qz, e);
378 MFEM_FOREACH_THREAD(qx,x,Q1D)
380 MFEM_FOREACH_THREAD(dz,z,D1D)
382 MFEM_FOREACH_THREAD(dy,y,D1D)
384 QDD[qx][dy][dz] = 0.0;
385 for (
int qy = 0; qy < Q1D; ++qy)
387 QDD[qx][dy][dz] += B[qy][dy] * B[qy][dy] * QQD[qx][qy][dz];
393 MFEM_FOREACH_THREAD(dz,z,D1D)
395 MFEM_FOREACH_THREAD(dy,y,D1D)
397 MFEM_FOREACH_THREAD(dx,x,D1D)
400 for (
int qx = 0; qx < Q1D; ++qx)
402 t += B[qx][dx] * B[qx][dx] * QDD[qx][dy][dz];
404 Y(dx, dy, dz, e) += t;
413void OccaPAMassApply2D(
const int D1D,
416 const Array<real_t> &B,
417 const Array<real_t> &Bt,
423void OccaPAMassApply3D(
const int D1D,
426 const Array<real_t> &B,
427 const Array<real_t> &Bt,
433template <
bool ACCUMULATE = true>
434MFEM_HOST_DEVICE
inline
435void PAMassApply2D_Element(
const int e,
455 for (
int dy = 0; dy < D1D; ++dy)
457 for (
int dx = 0; dx < D1D; ++dx)
464 constexpr int max_D1D = DofQuadLimits::MAX_D1D;
465 constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
466 real_t sol_xy[max_Q1D][max_Q1D];
467 for (
int qy = 0; qy < Q1D; ++qy)
469 for (
int qx = 0; qx < Q1D; ++qx)
471 sol_xy[qy][qx] = 0.0;
474 for (
int dy = 0; dy < D1D; ++dy)
477 for (
int qy = 0; qy < Q1D; ++qy)
481 for (
int dx = 0; dx < D1D; ++dx)
483 const real_t s = X(dx,dy,e);
484 for (
int qx = 0; qx < Q1D; ++qx)
486 sol_x[qx] += B(qx,dx)* s;
489 for (
int qy = 0; qy < Q1D; ++qy)
491 const real_t d2q = B(qy,dy);
492 for (
int qx = 0; qx < Q1D; ++qx)
494 sol_xy[qy][qx] += d2q * sol_x[qx];
498 for (
int qy = 0; qy < Q1D; ++qy)
500 for (
int qx = 0; qx < Q1D; ++qx)
502 sol_xy[qy][qx] *= D(qx,qy,e);
505 for (
int qy = 0; qy < Q1D; ++qy)
508 for (
int dx = 0; dx < D1D; ++dx)
512 for (
int qx = 0; qx < Q1D; ++qx)
514 const real_t s = sol_xy[qy][qx];
515 for (
int dx = 0; dx < D1D; ++dx)
517 sol_x[dx] += Bt(dx,qx) * s;
520 for (
int dy = 0; dy < D1D; ++dy)
522 const real_t q2d = Bt(dy,qy);
523 for (
int dx = 0; dx < D1D; ++dx)
525 Y(dx,dy,e) += q2d * sol_x[dx];
531template<
int T_D1D,
int T_Q1D,
int T_NBZ,
bool ACCUMULATE = true>
532MFEM_HOST_DEVICE
inline
533void SmemPAMassApply2D_Element(
const int e,
542 const int D1D = T_D1D ? T_D1D : d1d;
543 const int Q1D = T_Q1D ? T_Q1D : q1d;
544 constexpr int NBZ = T_NBZ ? T_NBZ : 1;
546 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
547 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
548 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
555 const int tidz = MFEM_THREAD_ID(z);
557 MFEM_SHARED
real_t BBt[MQ1*MD1];
560 MFEM_SHARED
real_t sm0[NBZ][MDQ*MDQ];
561 MFEM_SHARED
real_t sm1[NBZ][MDQ*MDQ];
568 MFEM_FOREACH_THREAD(dy,y,D1D)
570 MFEM_FOREACH_THREAD(dx,x,D1D)
572 X[dy][dx] = x(dx,dy,e);
577 MFEM_FOREACH_THREAD(dy,y,D1D)
579 MFEM_FOREACH_THREAD(q,x,Q1D)
586 MFEM_FOREACH_THREAD(dy,y,D1D)
588 MFEM_FOREACH_THREAD(qx,x,Q1D)
591 for (
int dx = 0; dx < D1D; ++dx)
593 dq += X[dy][dx] * B[qx][dx];
599 MFEM_FOREACH_THREAD(qy,y,Q1D)
601 MFEM_FOREACH_THREAD(qx,x,Q1D)
604 for (
int dy = 0; dy < D1D; ++dy)
606 qq += DQ[dy][qx] * B[qy][dy];
608 QQ[qy][qx] = qq * D(qx, qy, e);
614 MFEM_FOREACH_THREAD(dy,y,D1D)
616 MFEM_FOREACH_THREAD(q,x,Q1D)
623 MFEM_FOREACH_THREAD(qy,y,Q1D)
625 MFEM_FOREACH_THREAD(dx,x,D1D)
628 for (
int qx = 0; qx < Q1D; ++qx)
630 dq += QQ[qy][qx] * Bt[dx][qx];
636 MFEM_FOREACH_THREAD(dy,y,D1D)
638 MFEM_FOREACH_THREAD(dx,x,D1D)
641 for (
int qy = 0; qy < Q1D; ++qy)
643 dd += (QD[qy][dx] * Bt[dy][qy]);
657template <
bool ACCUMULATE = true>
658MFEM_HOST_DEVICE
inline
659void PAMassApply3D_Element(
const int e,
673 auto D = DeviceTensor<4,const real_t>(d_, Q1D, Q1D, Q1D, NE);
674 auto X = DeviceTensor<4,const real_t>(x_, D1D, D1D, D1D, NE);
675 auto Y = DeviceTensor<4,real_t>(y_, D1D, D1D, D1D, NE);
679 for (
int dz = 0; dz < D1D; ++dz)
681 for (
int dy = 0; dy < D1D; ++dy)
683 for (
int dx = 0; dx < D1D; ++dx)
685 Y(dx, dy, dz, e) = 0.0;
691 constexpr int max_D1D = DofQuadLimits::MAX_D1D;
692 constexpr int max_Q1D = DofQuadLimits::MAX_Q1D;
693 real_t sol_xyz[max_Q1D][max_Q1D][max_Q1D];
694 for (
int qz = 0; qz < Q1D; ++qz)
696 for (
int qy = 0; qy < Q1D; ++qy)
698 for (
int qx = 0; qx < Q1D; ++qx)
700 sol_xyz[qz][qy][qx] = 0.0;
704 for (
int dz = 0; dz < D1D; ++dz)
706 real_t sol_xy[max_Q1D][max_Q1D];
707 for (
int qy = 0; qy < Q1D; ++qy)
709 for (
int qx = 0; qx < Q1D; ++qx)
711 sol_xy[qy][qx] = 0.0;
714 for (
int dy = 0; dy < D1D; ++dy)
717 for (
int qx = 0; qx < Q1D; ++qx)
721 for (
int dx = 0; dx < D1D; ++dx)
723 const real_t s = X(dx,dy,dz,e);
724 for (
int qx = 0; qx < Q1D; ++qx)
726 sol_x[qx] += B(qx,dx) * s;
729 for (
int qy = 0; qy < Q1D; ++qy)
731 const real_t wy = B(qy,dy);
732 for (
int qx = 0; qx < Q1D; ++qx)
734 sol_xy[qy][qx] += wy * sol_x[qx];
738 for (
int qz = 0; qz < Q1D; ++qz)
740 const real_t wz = B(qz,dz);
741 for (
int qy = 0; qy < Q1D; ++qy)
743 for (
int qx = 0; qx < Q1D; ++qx)
745 sol_xyz[qz][qy][qx] += wz * sol_xy[qy][qx];
750 for (
int qz = 0; qz < Q1D; ++qz)
752 for (
int qy = 0; qy < Q1D; ++qy)
754 for (
int qx = 0; qx < Q1D; ++qx)
756 sol_xyz[qz][qy][qx] *= D(qx,qy,qz,e);
760 for (
int qz = 0; qz < Q1D; ++qz)
762 real_t sol_xy[max_D1D][max_D1D];
763 for (
int dy = 0; dy < D1D; ++dy)
765 for (
int dx = 0; dx < D1D; ++dx)
770 for (
int qy = 0; qy < Q1D; ++qy)
773 for (
int dx = 0; dx < D1D; ++dx)
777 for (
int qx = 0; qx < Q1D; ++qx)
779 const real_t s = sol_xyz[qz][qy][qx];
780 for (
int dx = 0; dx < D1D; ++dx)
782 sol_x[dx] += Bt(dx,qx) * s;
785 for (
int dy = 0; dy < D1D; ++dy)
787 const real_t wy = Bt(dy,qy);
788 for (
int dx = 0; dx < D1D; ++dx)
790 sol_xy[dy][dx] += wy * sol_x[dx];
794 for (
int dz = 0; dz < D1D; ++dz)
796 const real_t wz = Bt(dz,qz);
797 for (
int dy = 0; dy < D1D; ++dy)
799 for (
int dx = 0; dx < D1D; ++dx)
801 Y(dx,dy,dz,e) += wz * sol_xy[dy][dx];
808template <
int T_D1D,
int T_Q1D,
int TBATCH,
bool ACCUMULATE = true>
809MFEM_HOST_DEVICE
inline void
810SmemPAMassApply3D_Element(
const int e,
const int NE,
const real_t *b_,
812 int d1d = 0,
int q1d = 0)
814 static_assert(TBATCH > 0,
"TBATCH must be positive");
815#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
816 constexpr int tbatch = TBATCH;
817 const int tidz = MFEM_THREAD_ID(z);
820 constexpr int tbatch = 1;
821 constexpr int tidz = 0;
823 const int D1D = T_D1D ? T_D1D : d1d;
824 const int Q1D = T_Q1D ? T_Q1D : q1d;
825 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
826 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
827 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
830 auto d = DeviceTensor<4,const real_t>(d_, Q1D, Q1D, Q1D, NE);
831 auto x = DeviceTensor<4,const real_t>(x_, D1D, D1D, D1D, NE);
832 auto y = DeviceTensor<4,real_t>(y_, D1D, D1D, D1D, NE);
834 MFEM_SHARED
real_t sDQ[MQ1*MD1];
837 MFEM_SHARED
real_t sm0[tbatch][MDQ*MDQ*MDQ];
838 MFEM_SHARED
real_t sm1[tbatch][MDQ*MDQ*MDQ];
839 real_t (*X)[MD1][MD1] = (
real_t (*)[MD1][MD1]) (sm0+tidz);
840 real_t (*DDQ)[MD1][MQ1] = (
real_t (*)[MD1][MQ1]) (sm1+tidz);
841 real_t (*DQQ)[MQ1][MQ1] = (
real_t (*)[MQ1][MQ1]) (sm0+tidz);
842 real_t (*QQQ)[MQ1][MQ1] = (
real_t (*)[MQ1][MQ1]) (sm1+tidz);
843 real_t (*QQD)[MQ1][MD1] = (
real_t (*)[MQ1][MD1]) (sm0+tidz);
844 real_t (*QDD)[MD1][MD1] = (
real_t (*)[MD1][MD1]) (sm1+tidz);
845 MFEM_FOREACH_THREAD(dy, y, D1D)
847 MFEM_FOREACH_THREAD(dx, x, D1D)
850 for (
int dz = 0; dz < D1D; ++dz)
852 X[dz][dy][dx] = x(dx, dy, dz, e);
855 MFEM_FOREACH_THREAD(dx, x, Q1D) { B[dx][dy] =
b(dx, dy); }
859 MFEM_FOREACH_THREAD(dy, y, D1D)
861 MFEM_FOREACH_THREAD(dx, x, Q1D) { B[dx][dy] =
b(dx, dy); }
865 MFEM_FOREACH_THREAD(dy, y, D1D)
867 MFEM_FOREACH_THREAD(qx, x, Q1D)
871 for (
int dz = 0; dz < D1D; dz++)
876 for (
int dx = 0; dx < D1D; ++dx)
879 for (
int dz = 0; dz < D1D; ++dz)
881 u[dz] += X[dz][dy][dx] * B[qx][dx];
885 for (
int dz = 0; dz < D1D; ++dz)
887 DDQ[dz][dy][qx] =
u[dz];
892 MFEM_FOREACH_THREAD(qy, y, Q1D)
894 MFEM_FOREACH_THREAD(qx, x, Q1D)
898 for (
int dz = 0; dz < D1D; dz++)
903 for (
int dy = 0; dy < D1D; ++dy)
906 for (
int dz = 0; dz < D1D; dz++)
908 u[dz] += DDQ[dz][dy][qx] * B[qy][dy];
912 for (
int dz = 0; dz < D1D; dz++)
914 DQQ[dz][qy][qx] =
u[dz];
919 MFEM_FOREACH_THREAD(qy, y, Q1D)
921 MFEM_FOREACH_THREAD(qx, x, Q1D)
925 for (
int qz = 0; qz < Q1D; qz++)
930 for (
int dz = 0; dz < D1D; ++dz)
933 for (
int qz = 0; qz < Q1D; qz++)
935 u[qz] += DQQ[dz][qy][qx] * B[qz][dz];
939 for (
int qz = 0; qz < Q1D; qz++)
941 QQQ[qz][qy][qx] =
u[qz] * d(qx, qy, qz, e);
948 MFEM_FOREACH_THREAD(di, y, D1D)
950 MFEM_FOREACH_THREAD(q, x, Q1D) { Bt[di][q] =
b(q, di); }
954 MFEM_FOREACH_THREAD(qy, y, Q1D)
956 MFEM_FOREACH_THREAD(dx, x, D1D)
960 for (
int qz = 0; qz < Q1D; ++qz)
965 for (
int qx = 0; qx < Q1D; ++qx)
968 for (
int qz = 0; qz < Q1D; ++qz)
970 u[qz] += QQQ[qz][qy][qx] * Bt[dx][qx];
974 for (
int qz = 0; qz < Q1D; ++qz)
976 QQD[qz][qy][dx] =
u[qz];
981 MFEM_FOREACH_THREAD(dy, y, D1D)
983 MFEM_FOREACH_THREAD(dx, x, D1D)
987 for (
int qz = 0; qz < Q1D; ++qz)
992 for (
int qy = 0; qy < Q1D; ++qy)
995 for (
int qz = 0; qz < Q1D; ++qz)
997 u[qz] += QQD[qz][qy][dx] * Bt[dy][qy];
1001 for (
int qz = 0; qz < Q1D; ++qz)
1003 QDD[qz][dy][dx] =
u[qz];
1008 MFEM_FOREACH_THREAD(dy, y, D1D)
1010 MFEM_FOREACH_THREAD(dx, x, D1D)
1014 for (
int dz = 0; dz < D1D; ++dz)
1019 for (
int qz = 0; qz < Q1D; ++qz)
1022 for (
int dz = 0; dz < D1D; ++dz)
1024 u[dz] += QDD[qz][dy][dx] * Bt[dz][qz];
1028 for (
int dz = 0; dz < D1D; ++dz)
1032 y(dx, dy, dz, e) +=
u[dz];
1036 y(dx, dy, dz, e) =
u[dz];
1045template<
int T_D1D = 0,
int T_Q1D = 0>
1046inline void PAMassApply2D(
const int NE,
1047 const Array<real_t> &b_,
1048 const Array<real_t> &bt_,
1055 MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D,
"");
1056 MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D,
"");
1058 const auto B = b_.Read();
1059 const auto Bt = bt_.Read();
1060 const auto D = d_.Read();
1061 const auto X = x_.Read();
1062 auto Y = y_.ReadWrite();
1066 internal::PAMassApply2D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
1071template<
int T_D1D = 0,
int T_Q1D = 0>
1072inline void SmemPAMassApply2D(
const int NE,
1073 const Array<real_t> &b_,
1074 const Array<real_t> &bt_,
1081 MFEM_CONTRACT_VAR(bt_);
1082 static constexpr int T_NBZ = mass::NBZ(T_D1D);
1083 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
1084 const int D1D = T_D1D ? T_D1D : d1d;
1085 const int Q1D = T_Q1D ? T_Q1D : q1d;
1088 MFEM_VERIFY(D1D <= max_d1d,
"");
1089 MFEM_VERIFY(Q1D <= max_q1d,
"");
1090 const auto b = b_.Read();
1091 const auto D = d_.Read();
1092 const auto x = x_.Read();
1093 auto Y = y_.ReadWrite();
1096 internal::SmemPAMassApply2D_Element<T_D1D,T_Q1D,T_NBZ>(
1097 e, NE,
b, D, x, Y, d1d, q1d);
1102template<
int T_D1D = 0,
int T_Q1D = 0>
1103inline void PAMassApply3D(
const int NE,
1104 const Array<real_t> &b_,
1105 const Array<real_t> &bt_,
1112 MFEM_VERIFY(T_D1D ? T_D1D : d1d <= DeviceDofQuadLimits::Get().MAX_D1D,
"");
1113 MFEM_VERIFY(T_Q1D ? T_Q1D : q1d <= DeviceDofQuadLimits::Get().MAX_Q1D,
"");
1115 const auto B = b_.Read();
1116 const auto Bt = bt_.Read();
1117 const auto D = d_.Read();
1118 const auto X = x_.Read();
1119 auto Y = y_.ReadWrite();
1123 internal::PAMassApply3D_Element(e, NE, B, Bt, D, X, Y, d1d, q1d);
1128template<
int T_D1D = 0,
int T_Q1D = 0,
int TBATCH=1>
1129inline void SmemPAMassApply3D(
const int NE,
1130 const Array<real_t> &b_,
1131 const Array<real_t> &bt_,
1138 static_assert(T_D1D > 0,
"T_D1D must be positive");
1139 static_assert(T_Q1D > 0,
"T_Q1D must be positive");
1140 static_assert(TBATCH > 0,
"TBATCH must be positive");
1141 MFEM_CONTRACT_VAR(bt_);
1142 const int D1D = T_D1D ? T_D1D : d1d;
1143 const int Q1D = T_Q1D ? T_Q1D : q1d;
1146 MFEM_VERIFY(D1D <= max_d1d,
"");
1147 MFEM_VERIFY(Q1D <= max_q1d,
"");
1148 const auto b = b_.Read();
1149 const auto d = d_.Read();
1150 const auto x = x_.Read();
1151 auto y = y_.ReadWrite();
1153 [=] MFEM_HOST_DEVICE(
int e)
1155 internal::SmemPAMassApply3D_Element<T_D1D, T_Q1D, TBATCH>(e, NE,
b, d, x,
1160template<
int T_D1D = 0,
int T_Q1D = 0>
1161inline void EAMassAssemble1D(
const int NE,
1162 const Array<real_t> &basis,
1163 const Vector &padata,
1169 const int D1D = T_D1D ? T_D1D : d1d;
1170 const int Q1D = T_Q1D ? T_Q1D : q1d;
1173 const auto B =
Reshape(basis.Read(), Q1D, D1D);
1174 const auto D =
Reshape(padata.Read(), Q1D, NE);
1175 auto M =
Reshape(
add ? eadata.ReadWrite() : eadata.
Write(), D1D, D1D, NE);
1178 const int D1D = T_D1D ? T_D1D : d1d;
1179 const int Q1D = T_Q1D ? T_Q1D : q1d;
1180 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
1181 MFEM_FOREACH_THREAD(i1,x,D1D)
1184 for (
int q = 0; q < Q1D; q++) { r_Bi[q] = B(q,i1); }
1185 MFEM_FOREACH_THREAD(j1,y,D1D)
1188 for (
int q = 0; q < Q1D; q++) { r_Bj[q] = B(q,j1); }
1191 for (
int k1 = 0; k1 < Q1D; ++k1)
1193 val += r_Bi[k1] * r_Bj[k1] * D(k1, e);
1197 M(i1, j1, e) += val;
1208template<
int T_D1D = 0,
int T_Q1D = 0>
1209inline void EAMassAssemble2D(
const int NE,
1210 const Array<real_t> &basis,
1211 const Vector &padata,
1217 const int D1D = T_D1D ? T_D1D : d1d;
1218 const int Q1D = T_Q1D ? T_Q1D : q1d;
1221 auto B =
Reshape(basis.Read(), Q1D, D1D);
1222 auto D =
Reshape(padata.Read(), Q1D, Q1D, NE);
1223 auto M =
Reshape(
add ? eadata.ReadWrite() : eadata.
Write(), D1D, D1D, D1D, D1D,
1227 const int D1D = T_D1D ? T_D1D : d1d;
1228 const int Q1D = T_Q1D ? T_Q1D : q1d;
1229 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
1230 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
1232 for (
int d = 0; d < D1D; d++)
1234 for (
int q = 0; q < Q1D; q++)
1239 MFEM_SHARED
real_t s_D[MQ1][MQ1];
1240 MFEM_FOREACH_THREAD(k1,x,Q1D)
1242 MFEM_FOREACH_THREAD(k2,y,Q1D)
1244 s_D[k1][k2] = D(k1,k2,e);
1248 MFEM_FOREACH_THREAD(i1,x,D1D)
1250 MFEM_FOREACH_THREAD(i2,y,D1D)
1252 for (
int j1 = 0; j1 < D1D; ++j1)
1254 for (
int j2 = 0; j2 < D1D; ++j2)
1257 for (
int k1 = 0; k1 < Q1D; ++k1)
1259 for (
int k2 = 0; k2 < Q1D; ++k2)
1261 val += r_B[k1][i1] * r_B[k1][j1]
1262 * r_B[k2][i2] * r_B[k2][j2]
1268 M(i1, i2, j1, j2, e) += val;
1272 M(i1, i2, j1, j2, e) = val;
1281template<
int T_D1D = 0,
int T_Q1D = 0>
1282inline void EAMassAssemble3D(
const int NE,
1283 const Array<real_t> &basis,
1284 const Vector &padata,
1290 const int D1D = T_D1D ? T_D1D : d1d;
1291 const int Q1D = T_Q1D ? T_Q1D : q1d;
1294 auto B =
Reshape(basis.Read(), Q1D, D1D);
1295 auto D =
Reshape(padata.Read(), Q1D, Q1D, Q1D, NE);
1296 auto M =
Reshape(
add ? eadata.ReadWrite() : eadata.
Write(), D1D, D1D, D1D, D1D,
1300 const int D1D = T_D1D ? T_D1D : d1d;
1301 const int Q1D = T_Q1D ? T_Q1D : q1d;
1302 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
1303 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
1304 constexpr int DQ = T_D1D * T_Q1D;
1308 constexpr bool USE_REG = DQ != 0 && DQ <= 12;
1309 constexpr int MD1r = USE_REG ? MD1 : 1;
1310 constexpr int MQ1r = USE_REG ? MQ1 : 1;
1311 constexpr int MD1s = USE_REG ? 1 : MD1;
1312 constexpr int MQ1s = USE_REG ? 1 : MQ1;
1314 MFEM_SHARED
real_t s_B[MQ1s][MD1s];
1316 real_t (*l_B)[MD1] =
nullptr;
1319 for (
int d = 0; d < D1D; d++)
1321 for (
int q = 0; q < Q1D; q++)
1326 l_B = (
real_t (*)[MD1])r_B;
1330 if (MFEM_THREAD_ID(z) == 0)
1332 MFEM_FOREACH_THREAD(d,x,D1D)
1334 MFEM_FOREACH_THREAD(q,y,Q1D)
1340 l_B = (
real_t (*)[MD1])s_B;
1343 MFEM_SHARED
real_t s_D[MQ1][MQ1][MQ1];
1344 MFEM_FOREACH_THREAD(k1,x,Q1D)
1346 MFEM_FOREACH_THREAD(k2,y,Q1D)
1348 MFEM_FOREACH_THREAD(k3,z,Q1D)
1350 s_D[k1][k2][k3] = D(k1,k2,k3,e);
1355 MFEM_FOREACH_THREAD(i1,x,D1D)
1357 MFEM_FOREACH_THREAD(i2,y,D1D)
1359 MFEM_FOREACH_THREAD(i3,z,D1D)
1361 for (
int j1 = 0; j1 < D1D; ++j1)
1363 for (
int j2 = 0; j2 < D1D; ++j2)
1365 for (
int j3 = 0; j3 < D1D; ++j3)
1368 for (
int k1 = 0; k1 < Q1D; ++k1)
1370 for (
int k2 = 0; k2 < Q1D; ++k2)
1372 for (
int k3 = 0; k3 < Q1D; ++k3)
1374 val += l_B[k1][i1] * l_B[k1][j1]
1375 * l_B[k2][i2] * l_B[k2][j2]
1376 * l_B[k3][i3] * l_B[k3][j3]
1383 M(i1, i2, i3, j1, j2, j3, e) += val;
1387 M(i1, i2, i3, j1, j2, j3, e) = val;
1406template<
int DIM,
int D1D,
int Q1D>
1407ApplyKernelType MassIntegrator::ApplyPAKernels::Kernel()
1409 if constexpr (
DIM == 1) {
return internal::PAMassApply1D; }
1410 else if constexpr (
DIM == 2) {
return internal::SmemPAMassApply2D<D1D, Q1D>; }
1411 else if constexpr (
DIM == 3)
1413 constexpr int MDQ = D1D >= Q1D ? D1D : Q1D;
1415 if constexpr (MDQ > 0)
1417 return internal::SmemPAMassApply3D<D1D, Q1D,
1418 internal::mass::NBZ3D(MDQ)>;
1421 else { MFEM_ABORT(
""); }
1425inline ApplyKernelType MassIntegrator::ApplyPAKernels::Fallback(
1428 if (
dim == 1) {
return internal::PAMassApply1D; }
1429 else if (
dim == 2) {
return internal::PAMassApply2D; }
1430 else if (
dim == 3) {
return internal::PAMassApply3D; }
1431 else { MFEM_ABORT(
""); }
1435template<
int DIM,
int D1D,
int Q1D>
1436DiagonalKernelType MassIntegrator::DiagonalPAKernels::Kernel()
1438 if constexpr (
DIM == 1) {
return internal::PAMassAssembleDiagonal1D; }
1439 else if constexpr (
DIM == 2) {
return internal::SmemPAMassAssembleDiagonal2D<D1D, Q1D>; }
1440 else if constexpr (
DIM == 3) {
return internal::SmemPAMassAssembleDiagonal3D<D1D, Q1D>; }
1441 else { MFEM_ABORT(
""); }
1445inline DiagonalKernelType MassIntegrator::DiagonalPAKernels::Fallback(
1448 if (
dim == 1) {
return internal::PAMassAssembleDiagonal1D; }
1449 else if (
dim == 2) {
return internal::PAMassAssembleDiagonal2D; }
1450 else if (
dim == 3) {
return internal::PAMassAssembleDiagonal3D; }
1451 else { MFEM_ABORT(
""); }
void(*)(const int, const Array< real_t > &, const Array< real_t > &, const Vector &, const Vector &, Vector &, const int, const int) ApplyKernelType
void(*)(const int, const Array< real_t > &, const Vector &, Vector &, const int, const int) DiagonalKernelType
DeviceTensor< 3, real_t > DeviceCube
real_t u(const Vector &xvec)
DeviceTensor< 3, const real_t > ConstDeviceCube
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
void add(const Vector &v1, const Vector &v2, Vector &v)
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_batch(int N, int X, int Y, int BZ, lambda &&body)
void forall_2D(int N, int X, int Y, lambda &&body)
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
DeviceTensor< 2, const real_t > ConstDeviceMatrix
void forall(int N, lambda &&body)
DeviceTensor< 2, real_t > DeviceMatrix
real_t p(const Vector &x, real_t t)
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
int MAX_D1D
Maximum number of 1D nodal points.
int MAX_Q1D
Maximum number of 1D quadrature points.