12#ifndef MFEM_LININTEG_DOMAIN_KERNELS_HPP
13#define MFEM_LININTEG_DOMAIN_KERNELS_HPP
24template <
int T_D1D = 0,
int T_Q1D = 0>
25void DLFEvalAssemble1D(
const int vdim,
const int ne,
const int d,
const int q,
26 const int map_type,
const int *markers,
const real_t *
b,
28 const Vector &coeff,
real_t *y)
31 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
32 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
33 MFEM_VERIFY(q <= Q,
"");
34 MFEM_VERIFY(d <= D,
"");
37 const auto F = coeff.Read();
39 const auto DETJ =
Reshape(detj, q, ne);
40 const bool cst = coeff.Size() == vdim;
41 const auto C = cst ?
Reshape(F, vdim, 1, 1) :
Reshape(F, vdim, q, ne);
42 auto Y =
Reshape(y, d, vdim, ne);
51 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
52 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
54 MFEM_SHARED
real_t sBt[Q * D];
56 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
58 for (
int c = 0; c < vdim; ++c)
60 const real_t cst_val = C(c, 0, 0);
61 MFEM_FOREACH_THREAD(dx, x, d)
64 for (
int qx = 0; qx < q; ++qx)
68 const real_t coeff_val = cst ? cst_val : C(c, qx, e);
69 u += weights[qx] * coeff_val * detJ * Bt(dx, qx);
77template <
int T_D1D = 0,
int T_Q1D = 0>
78void DLFEvalAssemble2D(
const int vdim,
const int ne,
const int d,
const int q,
79 const int map_type,
const int *markers,
const real_t *
b,
81 const Vector &coeff,
real_t *y)
84 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
85 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
86 MFEM_VERIFY(q <= Q,
"");
87 MFEM_VERIFY(d <= D,
"");
90 const auto F = coeff.Read();
92 const auto DETJ =
Reshape(detj, q, q, ne);
93 const auto W =
Reshape(weights, q, q);
94 const bool cst = coeff.Size() == vdim;
95 const auto C = cst ?
Reshape(F, vdim, 1, 1, 1) :
Reshape(F, vdim, q, q, ne);
96 auto Y =
Reshape(y, d, d, vdim, ne);
105 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
106 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
108 MFEM_SHARED
real_t sBt[Q * D];
109 MFEM_SHARED
real_t sQQ[Q * Q];
110 MFEM_SHARED
real_t sQD[Q * D];
113 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
118 for (
int c = 0; c < vdim; ++c)
120 const real_t cst_val = C(c, 0, 0, 0);
121 MFEM_FOREACH_THREAD(x, x, q)
123 MFEM_FOREACH_THREAD(y, y, q)
127 const real_t coeff_val = cst ? cst_val : C(c, x, y, e);
128 QQ(y, x) = W(x, y) * coeff_val * detJ;
132 MFEM_FOREACH_THREAD(qy, y, q)
134 MFEM_FOREACH_THREAD(dx, x, d)
137 for (
int qx = 0; qx < q; ++qx)
139 u += QQ(qy, qx) * Bt(dx, qx);
145 MFEM_FOREACH_THREAD(dy, y, d)
147 MFEM_FOREACH_THREAD(dx, x, d)
150 for (
int qy = 0; qy < q; ++qy)
152 u += QD(qy, dx) * Bt(dy, qy);
154 Y(dx, dy, c, e) +=
u;
162template <
int T_D1D = 0,
int T_Q1D = 0>
163void DLFEvalAssemble3D(
const int vdim,
const int ne,
const int d,
const int q,
164 const int map_type,
const int *markers,
const real_t *
b,
166 const Vector &coeff,
real_t *y)
169 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
170 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
171 MFEM_VERIFY(q <= Q,
"");
172 MFEM_VERIFY(d <= D,
"");
175 const auto F = coeff.Read();
177 const auto DETJ =
Reshape(detj, q, q, q, ne);
178 const auto W =
Reshape(weights, q, q, q);
179 const bool cst_coeff = coeff.Size() == vdim;
181 cst_coeff ?
Reshape(F, vdim, 1, 1, 1, 1) :
Reshape(F, vdim, q, q, q, ne);
183 auto Y =
Reshape(y, d, d, d, vdim, ne);
192 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
193 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
194 constexpr int MQD = (Q >= D) ? Q : D;
198 MFEM_SHARED
real_t sBt[Q * D];
200 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
202 MFEM_SHARED
real_t sQQQ[MQD * MQD * MQD];
205 for (
int c = 0; c < vdim; ++c)
207 const real_t cst_val = C(c, 0, 0, 0, 0);
208 MFEM_FOREACH_THREAD(x, x, q)
210 MFEM_FOREACH_THREAD(y, y, q)
212 for (
int z = 0; z < q; ++z)
218 cst_coeff ? cst_val : C(c, x, y, z, e);
219 QQQ(z, y, x) = W(x, y, z) * coeff_val * detJ;
224 MFEM_FOREACH_THREAD(qx, x, q)
226 MFEM_FOREACH_THREAD(qy, y, q)
228 for (
int dz = 0; dz < d; ++dz)
232 for (
int qz = 0; qz < q; ++qz)
234 const real_t ZYX = QQQ(qz, qy, qx);
235 for (
int dz = 0; dz < d; ++dz)
237 u[dz] += ZYX * Bt(dz, qz);
240 for (
int dz = 0; dz < d; ++dz)
242 QQQ(dz, qy, qx) =
u[dz];
247 MFEM_FOREACH_THREAD(dz, y, d)
249 MFEM_FOREACH_THREAD(qx, x, q)
251 for (
int dy = 0; dy < d; ++dy)
255 for (
int qy = 0; qy < q; ++qy)
257 const real_t zYX = QQQ(dz, qy, qx);
258 for (
int dy = 0; dy < d; ++dy)
260 u[dy] += zYX * Bt(dy, qy);
263 for (
int dy = 0; dy < d; ++dy)
265 QQQ(dz, dy, qx) =
u[dy];
270 MFEM_FOREACH_THREAD(dz, y, d)
272 MFEM_FOREACH_THREAD(dy, x, d)
274 for (
int dx = 0; dx < d; ++dx)
278 for (
int qx = 0; qx < q; ++qx)
280 const real_t zyX = QQQ(dz, dy, qx);
281 for (
int dx = 0; dx < d; ++dx)
283 u[dx] += zyX * Bt(dx, qx);
286 for (
int dx = 0; dx < d; ++dx)
288 Y(dx, dy, dz, c, e) +=
u[dx];
297template <
int DIM,
int T_D1D,
int T_Q1D>
299DomainLFIntegrator::AssembleKernels::Kernel()
301 if constexpr (
DIM == 1) {
return DLFEvalAssemble1D<T_D1D, T_Q1D>; }
302 if constexpr (
DIM == 2) {
return DLFEvalAssemble2D<T_D1D, T_Q1D>; }
303 if constexpr (
DIM == 3) {
return DLFEvalAssemble3D<T_D1D, T_Q1D>; }
307template <
int T_D1D = 0,
int T_Q1D = 0>
308void HdivDLFAssemble2D(
const int ne,
const Array<int> &markers,
309 const Vector &jac,
const Array<real_t> &weights,
310 const Array<real_t> &testBO,
const Array<real_t> &testBC,
311 const Vector &coeff, Vector &y,
const int d,
const int q)
314 "Problem size too large.");
316 "Problem size too large.");
317 MFEM_VERIFY(y.Size() == 2 * (d - 1) * d * ne,
"");
319 constexpr int vdim = 2;
320 const auto F = coeff.Read();
321 const auto M = markers.Read();
322 const auto BO =
Reshape(testBO.Read(), q, d-1);
323 const auto BC =
Reshape(testBC.Read(), q, d);
324 const auto J =
Reshape(jac.Read(), q, q, vdim, vdim, ne);
325 const auto W =
Reshape(weights.Read(), q, q);
326 const bool cst = coeff.Size() == vdim;
327 const auto C = cst ?
Reshape(F,vdim,1,1,1) :
Reshape(F,vdim,q,q,ne);
328 auto Y = y.ReadWrite();
332 constexpr int vdim = 2;
333 if (M[e] == 0) {
return; }
335 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
336 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
338 MFEM_SHARED
real_t sBot[Q*D];
339 MFEM_SHARED
real_t sBct[Q*D];
340 MFEM_SHARED
real_t sQQ[vdim*Q*Q];
341 MFEM_SHARED
real_t sQD[vdim*Q*D];
345 kernels::internal::LoadB<D,Q>(d-1, q, BO, sBot);
347 kernels::internal::LoadB<D,Q>(d, q, BC, sBct);
352 MFEM_FOREACH_THREAD(vd,z,vdim)
354 const real_t cst_val_0 = C(0,0,0,0);
355 const real_t cst_val_1 = C(1,0,0,0);
356 MFEM_FOREACH_THREAD(y,y,q)
358 MFEM_FOREACH_THREAD(x,x,q)
360 const real_t J0 = J(x,y,0,vd,e);
361 const real_t J1 = J(x,y,1,vd,e);
362 const real_t C0 = cst ? cst_val_0 : C(0,x,y,e);
363 const real_t C1 = cst ? cst_val_1 : C(1,x,y,e);
364 QQ(x,y,vd) = W(x,y)*(J0*C0 + J1*C1);
369 MFEM_FOREACH_THREAD(vd,z,vdim)
371 const int nx = (vd == 0) ? d : d-1;
373 MFEM_FOREACH_THREAD(qy,y,q)
375 MFEM_FOREACH_THREAD(dx,x,nx)
378 for (
int qx = 0; qx < q; ++qx)
380 qd += QQ(qx,qy,vd) * Btx(dx,qx);
387 MFEM_FOREACH_THREAD(vd,z,vdim)
389 const int nx = (vd == 0) ? d : d-1;
390 const int ny = (vd == 1) ? d : d-1;
392 DeviceTensor<4> Yxy(Y, nx, ny, vdim, ne);
393 MFEM_FOREACH_THREAD(dy,y,ny)
395 MFEM_FOREACH_THREAD(dx,x,nx)
398 for (
int qy = 0; qy < q; ++qy)
400 dd += QD(dx,qy,vd) * Bty(dy,qy);
402 Yxy(dx,dy,vd,e) += dd;
410template <
int T_D1D = 0,
int T_Q1D = 0>
411void HdivDLFAssemble3D(
const int ne,
const Array<int> &markers,
412 const Vector &jac,
const Array<real_t> &weights,
413 const Array<real_t> &testBO,
414 const Array<real_t> &testBC,
const Vector &coeff,
415 Vector &y,
const int d,
const int q)
418 "Problem size too large.");
420 "Problem size too large.");
421 MFEM_VERIFY(y.Size() == 3 * (d - 1) * (d - 1) * d * ne,
"y wrong length");
423 constexpr int vdim = 3;
424 const auto F = coeff.Read();
425 const auto M = markers.Read();
426 const auto BO =
Reshape(testBO.Read(), q, d-1);
427 const auto BC =
Reshape(testBC.Read(), q, d);
428 const auto J =
Reshape(jac.Read(), q, q, q, vdim, vdim, ne);
429 const auto W =
Reshape(weights.Read(), q, q, q);
430 const bool cst = coeff.Size() == vdim;
431 const auto C = cst ?
Reshape(F,vdim,1,1,1,1) :
Reshape(F,vdim,q,q,q,ne);
432 auto Y = y.ReadWrite();
436 constexpr int vdim = 3;
437 if (M[e] == 0) {
return; }
439 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
440 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
442 MFEM_SHARED
real_t sBot[Q*D];
443 MFEM_SHARED
real_t sBct[Q*D];
447 kernels::internal::LoadB<D,Q>(d-1, q, BO, sBot);
449 kernels::internal::LoadB<D,Q>(d, q, BC, sBct);
451 MFEM_SHARED
real_t sm0[vdim*Q*Q*Q];
452 MFEM_SHARED
real_t sm1[vdim*Q*Q*Q];
453 DeviceTensor<4> QQQ(sm1, q, q, q, vdim);
454 DeviceTensor<4> DQQ(sm0, d, q, q, vdim);
455 DeviceTensor<4> DDQ(sm1, d, d, q, vdim);
457 MFEM_FOREACH_THREAD(vd,z,vdim)
459 const real_t cst_val_0 = C(0,0,0,0,0);
460 const real_t cst_val_1 = C(1,0,0,0,0);
461 const real_t cst_val_2 = C(2,0,0,0,0);
462 MFEM_FOREACH_THREAD(y,y,q)
464 MFEM_FOREACH_THREAD(x,x,q)
466 for (
int z = 0; z < q; ++z)
468 const real_t J0 = J(x,y,z,0,vd,e);
469 const real_t J1 = J(x,y,z,1,vd,e);
470 const real_t J2 = J(x,y,z,2,vd,e);
471 const real_t C0 = cst ? cst_val_0 : C(0,x,y,z,e);
472 const real_t C1 = cst ? cst_val_1 : C(1,x,y,z,e);
473 const real_t C2 = cst ? cst_val_2 : C(2,x,y,z,e);
474 QQQ(x,y,z,vd) = W(x,y,z)*(J0*C0 + J1*C1 + J2*C2);
481 MFEM_FOREACH_THREAD(vd,z,vdim)
483 const int nx = (vd == 0) ? d : d-1;
485 MFEM_FOREACH_THREAD(qy,y,q)
487 MFEM_FOREACH_THREAD(dx,x,nx)
491 for (
int qz = 0; qz < q; ++qz) {
u[qz] = 0.0; }
493 for (
int qx = 0; qx < q; ++qx)
496 for (
int qz = 0; qz < q; ++qz)
498 u[qz] += QQQ(qx,qy,qz,vd) * Btx(dx,qx);
502 for (
int qz = 0; qz < q; ++qz) { DQQ(dx,qy,qz,vd) =
u[qz]; }
507 MFEM_FOREACH_THREAD(vd,z,vdim)
509 const int nx = (vd == 0) ? d : d-1;
510 const int ny = (vd == 1) ? d : d-1;
512 MFEM_FOREACH_THREAD(dy,y,ny)
514 MFEM_FOREACH_THREAD(dx,x,nx)
518 for (
int qz = 0; qz < q; ++qz) {
u[qz] = 0.0; }
520 for (
int qy = 0; qy < q; ++qy)
523 for (
int qz = 0; qz < q; ++qz)
525 u[qz] += DQQ(dx,qy,qz,vd) * Bty(dy,qy);
529 for (
int qz = 0; qz < q; ++qz) { DDQ(dx,dy,qz,vd) =
u[qz]; }
534 MFEM_FOREACH_THREAD(vd,z,vdim)
536 const int nx = (vd == 0) ? d : d-1;
537 const int ny = (vd == 1) ? d : d-1;
538 const int nz = (vd == 2) ? d : d-1;
539 DeviceTensor<5> Yxyz(Y, nx, ny, nz, vdim, ne);
541 MFEM_FOREACH_THREAD(dy,y,ny)
543 MFEM_FOREACH_THREAD(dx,x,nx)
547 for (
int dz = 0; dz < nz; ++dz) {
u[dz] = 0.0; }
549 for (
int qz = 0; qz < q; ++qz)
552 for (
int dz = 0; dz < nz; ++dz)
554 u[dz] += DDQ(dx,dy,qz,vd) * Btz(dz,qz);
558 for (
int dz = 0; dz < nz; ++dz) { Yxyz(dx,dy,dz,vd,e) +=
u[dz]; }
579template <
int T_D1D = 0,
int T_Q1D = 0>
580void HcurlDLFAssemble3D(
const int ne,
const Array<int> &markers,
581 const Vector &jac,
const Array<real_t> &weights,
582 const Array<real_t> &testBO,
583 const Array<real_t> &testBC,
const Vector &coeff,
584 Vector &y,
const int d,
const int q)
587 "Problem size too large.");
589 "Problem size too large.");
590 MFEM_VERIFY(y.Size() == 3 * (d - 1) * d * d * ne,
"y wrong length");
592 constexpr int vdim = 3;
593 const auto F = coeff.Read();
594 const auto M = markers.Read();
595 const auto BO =
Reshape(testBO.Read(), q, d-1);
596 const auto BC =
Reshape(testBC.Read(), q, d);
597 const auto J =
Reshape(jac.Read(), q, q, q, vdim, vdim, ne);
598 const auto W =
Reshape(weights.Read(), q, q, q);
599 const bool cst = coeff.Size() == vdim;
600 const auto C = cst ?
Reshape(F,vdim,1,1,1,1) :
Reshape(F,vdim,q,q,q,ne);
601 auto Y = y.ReadWrite();
611 constexpr int vdim = 3;
612 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
613 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
615 MFEM_SHARED
real_t sBot[Q * D];
616 MFEM_SHARED
real_t sBct[Q * D];
620 kernels::internal::LoadB<D, Q>(d - 1, q, BO, sBot);
622 kernels::internal::LoadB<D, Q>(d, q, BC, sBct);
624 MFEM_SHARED
real_t sm0[vdim * Q * Q * Q];
625 MFEM_SHARED
real_t sm1[vdim * Q * Q * Q];
626 DeviceTensor<4> QQQ(sm1, q, q, q, vdim);
627 DeviceTensor<4> DQQ(sm0, d, q, q, vdim);
628 DeviceTensor<4> DDQ(sm1, d, d, q, vdim);
630 const real_t cst_val_0 = C(0, 0, 0, 0, 0);
631 const real_t cst_val_1 = C(1, 0, 0, 0, 0);
632 const real_t cst_val_2 = C(2, 0, 0, 0, 0);
634 MFEM_FOREACH_THREAD(vd, z, vdim)
636 MFEM_FOREACH_THREAD(y, y, q)
638 MFEM_FOREACH_THREAD(x, x, q)
640 for (
int z = 0; z < q; ++z)
643 curr[0] = cst ? cst_val_0 : C(0, x, y, z, e);
644 curr[1] = cst ? cst_val_1 : C(1, x, y, z, e);
645 curr[2] = cst ? cst_val_2 : C(2, x, y, z, e);
647 const real_t J11 = J(x, y, z, 0, 0, e);
648 const real_t J21 = J(x, y, z, 1, 0, e);
649 const real_t J31 = J(x, y, z, 2, 0, e);
650 const real_t J12 = J(x, y, z, 0, 1, e);
651 const real_t J22 = J(x, y, z, 1, 1, e);
652 const real_t J32 = J(x, y, z, 2, 1, e);
653 const real_t J13 = J(x, y, z, 0, 2, e);
654 const real_t J23 = J(x, y, z, 1, 2, e);
655 const real_t J33 = J(x, y, z, 2, 2, e);
657 const real_t A11 = (J22 * J33) - (J23 * J32);
658 const real_t A12 = (J32 * J13) - (J12 * J33);
659 const real_t A13 = (J12 * J23) - (J22 * J13);
660 const real_t A21 = (J31 * J23) - (J21 * J33);
661 const real_t A22 = (J11 * J33) - (J13 * J31);
662 const real_t A23 = (J21 * J13) - (J11 * J23);
663 const real_t A31 = (J21 * J32) - (J31 * J22);
664 const real_t A32 = (J31 * J12) - (J11 * J32);
665 const real_t A33 = (J11 * J22) - (J12 * J21);
666 const real_t A[9] = {A11, A12, A13, A21, A22,
669 QQQ(x, y, z, vd) = W(x, y, z) * (A[vd * vdim] * curr[0] +
670 A[vd * vdim + 1] * curr[1] +
671 A[vd * vdim + 2] * curr[2]);
678 MFEM_FOREACH_THREAD(vd, z, vdim)
680 const int nx = (vd == 0) ? d - 1 : d;
682 MFEM_FOREACH_THREAD(qy, y, q)
684 MFEM_FOREACH_THREAD(dx, x, nx)
688 for (
int qz = 0; qz < q; ++qz)
693 for (
int qx = 0; qx < q; ++qx)
696 for (
int qz = 0; qz < q; ++qz)
698 u[qz] += QQQ(qx, qy, qz, vd) * Btx(dx, qx);
702 for (
int qz = 0; qz < q; ++qz)
704 DQQ(dx, qy, qz, vd) =
u[qz];
710 MFEM_FOREACH_THREAD(vd, z, vdim)
712 const int nx = (vd == 0) ? d - 1 : d;
713 const int ny = (vd == 1) ? d - 1 : d;
715 MFEM_FOREACH_THREAD(dy, y, ny)
717 MFEM_FOREACH_THREAD(dx, x, nx)
721 for (
int qz = 0; qz < q; ++qz)
726 for (
int qy = 0; qy < q; ++qy)
729 for (
int qz = 0; qz < q; ++qz)
731 u[qz] += DQQ(dx, qy, qz, vd) * Bty(dy, qy);
735 for (
int qz = 0; qz < q; ++qz)
737 DDQ(dx, dy, qz, vd) =
u[qz];
743 MFEM_FOREACH_THREAD(vd, z, vdim)
745 const int nx = (vd == 0) ? d - 1 : d;
746 const int ny = (vd == 1) ? d - 1 : d;
747 const int nz = (vd == 2) ? d - 1 : d;
748 DeviceTensor<5> Yxyz(Y, nx, ny, nz, vdim, ne);
750 MFEM_FOREACH_THREAD(dy, y, ny)
752 MFEM_FOREACH_THREAD(dx, x, nx)
756 for (
int dz = 0; dz < nz; ++dz)
761 for (
int qz = 0; qz < q; ++qz)
764 for (
int dz = 0; dz < nz; ++dz)
766 u[dz] += DDQ(dx, dy, qz, vd) * Btz(dz, qz);
770 for (
int dz = 0; dz < nz; ++dz)
772 Yxyz(dx, dy, dz, vd, e) +=
u[dz];
781template <FiniteElement::DerivType TestType,
int DIM,
int TEST_D1D,
int Q1D>
783VectorFEDomainLFIntegrator::AssembleKernels::Kernel()
787 if constexpr (
DIM == 2)
789 return HdivDLFAssemble2D<TEST_D1D, Q1D>;
791 if constexpr (
DIM == 3)
793 return HdivDLFAssemble3D<TEST_D1D, Q1D>;
798 if constexpr (
DIM == 3)
800 return HcurlDLFAssemble3D<TEST_D1D, Q1D>;
void(*)(const int, const int, const int, const int, const int, const int *, const real_t *, const real_t *, const real_t *, const Vector &coeff, real_t *y) AssembleKernelType
args: vdim, ne, d1d, q1d, map_type, markers, B, detJ, W, coeff, y
@ DIV
Implements CalcDivShape methods.
@ CURL
Implements CalcCurlShape methods.
void(*)(const int NE, const Array< int > &markers, const Vector &jac, const Array< real_t > &weights, const Array< real_t > &testBO, const Array< real_t > &testBC, const Vector &coeff, Vector &y, const int testd1d, const int q1d) AssembleKernelType
DeviceTensor< 3, real_t > DeviceCube
real_t u(const Vector &xvec)
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)
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
DeviceTensor< 2, real_t > DeviceMatrix
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.