13 #include "../general/forall.hpp"
14 #include "../linalg/dtensor.hpp"
15 #include "../linalg/kernels.hpp"
31 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
32 "Only scalar finite elements are supported");
46 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
47 "Only scalar finite elements are supported");
50 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
61 const int nd = maps.
ndof;
62 const int nq = maps.
nqpt;
63 const int ND = T_ND ? T_ND : nd;
64 const int NQ = T_NQ ? T_NQ : nq;
65 const int NMAX = NQ > ND ? NQ : ND;
66 const int VDIM = T_VDIM ? T_VDIM : vdim;
69 MFEM_VERIFY(VDIM == 2 || !(eval_flags &
DETERMINANTS),
"");
76 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
78 const int ND = T_ND ? T_ND : nd;
79 const int NQ = T_NQ ? T_NQ : nq;
80 const int VDIM = T_VDIM ? T_VDIM : vdim;
81 constexpr
int max_ND = T_ND ? T_ND :
MAX_ND2D;
82 constexpr
int max_VDIM = T_VDIM ? T_VDIM :
MAX_VDIM2D;
83 MFEM_SHARED
double s_E[max_VDIM*max_ND];
84 MFEM_FOREACH_THREAD(d, x, ND)
86 for (
int c = 0; c < VDIM; c++)
88 s_E[c+d*VDIM] = E(d,c,e);
93 MFEM_FOREACH_THREAD(q, x, NQ)
98 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
99 for (
int d = 0; d < ND; ++d)
101 const double b = B(q,d);
102 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
104 for (
int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
106 if ((eval_flags &
DERIVATIVES) || (eval_flags & DETERMINANTS))
110 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
111 for (
int d = 0; d < ND; ++d)
113 const double wx = G(q,0,d);
114 const double wy = G(q,1,d);
115 for (
int c = 0; c < VDIM; c++)
117 double s_e = s_E[c+d*VDIM];
118 D[c+VDIM*0] += s_e * wx;
119 D[c+VDIM*1] += s_e * wy;
122 if (eval_flags & DERIVATIVES)
124 for (
int c = 0; c < VDIM; c++)
126 der(q,c,0,e) = D[c+VDIM*0];
127 der(q,c,1,e) = D[c+VDIM*1];
130 if (VDIM == 2 && (eval_flags & DETERMINANTS))
134 det(q,e) = kernels::Det<2>(D);
141 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
150 const int eval_flags)
152 const int nd = maps.
ndof;
153 const int nq = maps.
nqpt;
154 const int ND = T_ND ? T_ND : nd;
155 const int NQ = T_NQ ? T_NQ : nq;
156 const int NMAX = NQ > ND ? NQ : ND;
157 const int VDIM = T_VDIM ? T_VDIM : vdim;
160 MFEM_VERIFY(VDIM == 3 || !(eval_flags &
DETERMINANTS),
"");
167 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
169 const int ND = T_ND ? T_ND : nd;
170 const int NQ = T_NQ ? T_NQ : nq;
171 const int VDIM = T_VDIM ? T_VDIM : vdim;
172 constexpr
int max_ND = T_ND ? T_ND :
MAX_ND3D;
173 constexpr
int max_VDIM = T_VDIM ? T_VDIM :
MAX_VDIM3D;
174 MFEM_SHARED
double s_E[max_VDIM*max_ND];
175 MFEM_FOREACH_THREAD(d, x, ND)
177 for (
int c = 0; c < VDIM; c++)
179 s_E[c+d*VDIM] = E(d,c,e);
184 MFEM_FOREACH_THREAD(q, x, NQ)
189 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
190 for (
int d = 0; d < ND; ++d)
192 const double b = B(q,d);
193 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
195 for (
int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
197 if ((eval_flags &
DERIVATIVES) || (eval_flags & DETERMINANTS))
201 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
202 for (
int d = 0; d < ND; ++d)
204 const double wx = G(q,0,d);
205 const double wy = G(q,1,d);
206 const double wz = G(q,2,d);
207 for (
int c = 0; c < VDIM; c++)
209 double s_e = s_E[c+d*VDIM];
210 D[c+VDIM*0] += s_e * wx;
211 D[c+VDIM*1] += s_e * wy;
212 D[c+VDIM*2] += s_e * wz;
215 if (eval_flags & DERIVATIVES)
217 for (
int c = 0; c < VDIM; c++)
219 der(q,c,0,e) = D[c+VDIM*0];
220 der(q,c,1,e) = D[c+VDIM*1];
221 der(q,c,2,e) = D[c+VDIM*2];
224 if (VDIM == 3 && (eval_flags & DETERMINANTS))
228 det(q,e) = kernels::Det<3>(D);
236 const Vector &e_vec,
unsigned eval_flags,
245 MFEM_ABORT(
"evaluation of determinants with 'byVDIM' output layout"
246 " is not implemented yet!");
253 if (ne == 0) {
return; }
260 const int nd = maps.
ndof;
261 const int nq = maps.
nqpt;
270 const int eval_flags) = NULL;
278 case 101: eval_func = &Eval2D<1,1,1>;
break;
279 case 104: eval_func = &Eval2D<1,1,4>;
break;
281 case 404: eval_func = &Eval2D<1,4,4>;
break;
282 case 409: eval_func = &Eval2D<1,4,9>;
break;
284 case 909: eval_func = &Eval2D<1,9,9>;
break;
285 case 916: eval_func = &Eval2D<1,9,16>;
break;
287 case 1616: eval_func = &Eval2D<1,16,16>;
break;
288 case 1625: eval_func = &Eval2D<1,16,25>;
break;
289 case 1636: eval_func = &Eval2D<1,16,36>;
break;
291 case 2525: eval_func = &Eval2D<1,25,25>;
break;
292 case 2536: eval_func = &Eval2D<1,25,36>;
break;
293 case 2549: eval_func = &Eval2D<1,25,49>;
break;
294 case 2564: eval_func = &Eval2D<1,25,64>;
break;
296 if (nq >= 100 || !eval_func)
298 eval_func = &Eval2D<1>;
303 switch (1000*nd + nq)
306 case 1001: eval_func = &Eval3D<1,1,1>;
break;
307 case 1008: eval_func = &Eval3D<1,1,8>;
break;
309 case 8008: eval_func = &Eval3D<1,8,8>;
break;
310 case 8027: eval_func = &Eval3D<1,8,27>;
break;
312 case 27027: eval_func = &Eval3D<1,27,27>;
break;
313 case 27064: eval_func = &Eval3D<1,27,64>;
break;
315 case 64064: eval_func = &Eval3D<1,64,64>;
break;
316 case 64125: eval_func = &Eval3D<1,64,125>;
break;
317 case 64216: eval_func = &Eval3D<1,64,216>;
break;
319 case 125125: eval_func = &Eval3D<1,125,125>;
break;
320 case 125216: eval_func = &Eval3D<1,125,216>;
break;
322 if (nq >= 1000 || !eval_func)
324 eval_func = &Eval3D<1>;
328 else if (vdim == 3 && dim == 2)
333 case 101: eval_func = &Eval2D<3,1,1>;
break;
334 case 104: eval_func = &Eval2D<3,1,4>;
break;
336 case 404: eval_func = &Eval2D<3,4,4>;
break;
337 case 409: eval_func = &Eval2D<3,4,9>;
break;
339 case 904: eval_func = &Eval2D<3,9,4>;
break;
340 case 909: eval_func = &Eval2D<3,9,9>;
break;
341 case 916: eval_func = &Eval2D<3,9,16>;
break;
342 case 925: eval_func = &Eval2D<3,9,25>;
break;
344 case 1616: eval_func = &Eval2D<3,16,16>;
break;
345 case 1625: eval_func = &Eval2D<3,16,25>;
break;
346 case 1636: eval_func = &Eval2D<3,16,36>;
break;
348 case 2525: eval_func = &Eval2D<3,25,25>;
break;
349 case 2536: eval_func = &Eval2D<3,25,36>;
break;
350 case 2549: eval_func = &Eval2D<3,25,49>;
break;
351 case 2564: eval_func = &Eval2D<3,25,64>;
break;
352 default: eval_func = &Eval2D<3>;
355 else if (vdim == dim)
362 case 404: eval_func = &Eval2D<2,4,4>;
break;
363 case 409: eval_func = &Eval2D<2,4,9>;
break;
365 case 909: eval_func = &Eval2D<2,9,9>;
break;
366 case 916: eval_func = &Eval2D<2,9,16>;
break;
368 case 1616: eval_func = &Eval2D<2,16,16>;
break;
369 case 1625: eval_func = &Eval2D<2,16,25>;
break;
370 case 1636: eval_func = &Eval2D<2,16,36>;
break;
372 case 2525: eval_func = &Eval2D<2,25,25>;
break;
373 case 2536: eval_func = &Eval2D<2,25,36>;
break;
374 case 2549: eval_func = &Eval2D<2,25,49>;
break;
375 case 2564: eval_func = &Eval2D<2,25,64>;
break;
377 if (nq >= 100 || !eval_func)
379 eval_func = &Eval2D<2>;
384 switch (1000*nd + nq)
387 case 8008: eval_func = &Eval3D<3,8,8>;
break;
388 case 8027: eval_func = &Eval3D<3,8,27>;
break;
390 case 27027: eval_func = &Eval3D<3,27,27>;
break;
391 case 27064: eval_func = &Eval3D<3,27,64>;
break;
393 case 64064: eval_func = &Eval3D<3,64,64>;
break;
394 case 64125: eval_func = &Eval3D<3,64,125>;
break;
395 case 64216: eval_func = &Eval3D<3,64,216>;
break;
397 case 125125: eval_func = &Eval3D<3,125,125>;
break;
398 case 125216: eval_func = &Eval3D<3,125,216>;
break;
400 if (nq >= 1000 || !eval_func)
402 eval_func = &Eval3D<3>;
408 eval_func(ne, vdim, maps, e_vec, q_val, q_der, q_det, eval_flags);
412 MFEM_ABORT(
"case not supported yet");
417 unsigned eval_flags,
const Vector &q_val,
const Vector &q_der,
420 MFEM_ABORT(
"this method is not implemented yet");
424 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
425 static void D2QValues2D(
const int NE,
433 const int D1D = T_D1D ? T_D1D : d1d;
434 const int Q1D = T_Q1D ? T_Q1D : q1d;
435 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
436 const int VDIM = T_VDIM ? T_VDIM : vdim;
442 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
444 const int D1D = T_D1D ? T_D1D : d1d;
445 const int Q1D = T_Q1D ? T_Q1D : q1d;
446 const int VDIM = T_VDIM ? T_VDIM : vdim;
447 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
448 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
449 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
450 const int zid = MFEM_THREAD_ID(z);
451 MFEM_SHARED
double B[MQ1][MD1];
453 MFEM_SHARED
double DDz[NBZ][MD1*MD1];
454 double (*DD)[MD1] = (double (*)[MD1])(DDz + zid);
456 MFEM_SHARED
double DQz[NBZ][MD1*MQ1];
457 double (*DQ)[MQ1] = (double (*)[MQ1])(DQz + zid);
461 MFEM_FOREACH_THREAD(d,y,D1D)
463 MFEM_FOREACH_THREAD(q,x,Q1D)
471 for (
int c = 0; c < VDIM; c++)
473 MFEM_FOREACH_THREAD(dy,y,D1D)
475 MFEM_FOREACH_THREAD(dx,x,D1D)
477 DD[dy][dx] = x(dx,dy,c,e);
481 MFEM_FOREACH_THREAD(dy,y,D1D)
483 MFEM_FOREACH_THREAD(qx,x,Q1D)
486 for (
int dx = 0; dx < D1D; ++dx)
488 dq += B[qx][dx] * DD[dy][dx];
494 MFEM_FOREACH_THREAD(qy,y,Q1D)
496 MFEM_FOREACH_THREAD(qx,x,Q1D)
499 for (
int dy = 0; dy < D1D; ++dy)
501 qq += DQ[dy][qx] * B[qy][dy];
511 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
512 int MAX_D = 0,
int MAX_Q = 0>
513 static void D2QValues3D(
const int NE,
514 const Array<double> &b_,
521 const int D1D = T_D1D ? T_D1D : d1d;
522 const int Q1D = T_Q1D ? T_Q1D : q1d;
523 const int VDIM = T_VDIM ? T_VDIM : vdim;
525 auto b =
Reshape(b_.Read(), Q1D, D1D);
526 auto x =
Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
527 auto y =
Reshape(y_.Write(), VDIM, Q1D, Q1D, Q1D, NE);
529 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
531 const int D1D = T_D1D ? T_D1D : d1d;
532 const int Q1D = T_Q1D ? T_Q1D : q1d;
533 const int VDIM = T_VDIM ? T_VDIM : vdim;
534 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
535 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
536 constexpr
int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
537 const int tidz = MFEM_THREAD_ID(z);
538 MFEM_SHARED
double B[MQ1][MD1];
539 MFEM_SHARED
double sm0[MDQ*MDQ*MDQ];
540 MFEM_SHARED
double sm1[MDQ*MDQ*MDQ];
541 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) sm0;
542 double (*DDQ)[MD1][MQ1] = (double (*)[MD1][MQ1]) sm1;
543 double (*DQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm0;
547 MFEM_FOREACH_THREAD(d,y,D1D)
549 MFEM_FOREACH_THREAD(q,x,Q1D)
557 for (
int c = 0; c < VDIM; c++)
559 MFEM_FOREACH_THREAD(dz,z,D1D)
561 MFEM_FOREACH_THREAD(dy,y,D1D)
563 MFEM_FOREACH_THREAD(dx,x,D1D)
565 X[dz][dy][dx] = x(dx,dy,dz,c,e);
570 MFEM_FOREACH_THREAD(dz,z,D1D)
572 MFEM_FOREACH_THREAD(dy,y,D1D)
574 MFEM_FOREACH_THREAD(qx,x,Q1D)
577 for (
int dx = 0; dx < D1D; ++dx)
579 u += B[qx][dx] * X[dz][dy][dx];
586 MFEM_FOREACH_THREAD(dz,z,D1D)
588 MFEM_FOREACH_THREAD(qy,y,Q1D)
590 MFEM_FOREACH_THREAD(qx,x,Q1D)
593 for (
int dy = 0; dy < D1D; ++dy)
595 u += DDQ[dz][dy][qx] * B[qy][dy];
602 MFEM_FOREACH_THREAD(qz,z,Q1D)
604 MFEM_FOREACH_THREAD(qy,y,Q1D)
606 MFEM_FOREACH_THREAD(qx,x,Q1D)
609 for (
int dz = 0; dz < D1D; ++dz)
611 u += DQQ[dz][qy][qx] * B[qz][dz];
622 static void D2QValues(
const FiniteElementSpace &fes,
623 const DofToQuad *maps,
627 const int dim = fes.GetMesh()->Dimension();
628 const int vdim = fes.GetVDim();
629 const int NE = fes.GetNE();
630 const int D1D = maps->ndof;
631 const int Q1D = maps->nqpt;
632 const int id = (vdim<<8) | (D1D<<4) | Q1D;
638 case 0x124:
return D2QValues2D<1,2,4,8>(NE, maps->B, e_vec, q_val);
639 case 0x136:
return D2QValues2D<1,3,6,4>(NE, maps->B, e_vec, q_val);
640 case 0x148:
return D2QValues2D<1,4,8,2>(NE, maps->B, e_vec, q_val);
641 case 0x224:
return D2QValues2D<2,2,4,8>(NE, maps->B, e_vec, q_val);
642 case 0x236:
return D2QValues2D<2,3,6,4>(NE, maps->B, e_vec, q_val);
643 case 0x248:
return D2QValues2D<2,4,8,2>(NE, maps->B, e_vec, q_val);
647 <<
" are not supported!");
648 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
649 <<
MAX_Q1D <<
" 1D points are not supported!");
650 D2QValues2D(NE, maps->B, e_vec, q_val, vdim, D1D, Q1D);
659 case 0x124:
return D2QValues3D<1,2,4>(NE, maps->B, e_vec, q_val);
660 case 0x136:
return D2QValues3D<1,3,6>(NE, maps->B, e_vec, q_val);
661 case 0x148:
return D2QValues3D<1,4,8>(NE, maps->B, e_vec, q_val);
662 case 0x324:
return D2QValues3D<3,2,4>(NE, maps->B, e_vec, q_val);
663 case 0x336:
return D2QValues3D<3,3,6>(NE, maps->B, e_vec, q_val);
664 case 0x348:
return D2QValues3D<3,4,8>(NE, maps->B, e_vec, q_val);
667 constexpr
int MD = 8;
668 constexpr
int MQ = 8;
669 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
670 <<
" are not supported!");
671 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
672 <<
" 1D points are not supported!");
673 D2QValues3D<0,0,0,MD,MQ>(NE, maps->B, e_vec, q_val, vdim, D1D, Q1D);
678 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
679 MFEM_ABORT(
"Unknown kernel");
696 D2QValues(*
fespace, &d2q, e_vec, q_val);
699 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
700 static void D2QGrad2D(
const int NE,
709 const int D1D = T_D1D ? T_D1D : d1d;
710 const int Q1D = T_Q1D ? T_Q1D : q1d;
711 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
712 const int VDIM = T_VDIM ? T_VDIM : vdim;
715 auto g =
Reshape(g_, Q1D, D1D);
716 auto x =
Reshape(x_, D1D, D1D, VDIM, NE);
717 auto y =
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
719 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
721 const int D1D = T_D1D ? T_D1D : d1d;
722 const int Q1D = T_Q1D ? T_Q1D : q1d;
723 const int VDIM = T_VDIM ? T_VDIM : vdim;
724 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
725 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
726 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
727 const int tidz = MFEM_THREAD_ID(z);
728 MFEM_SHARED
double B[MQ1][MD1];
729 MFEM_SHARED
double G[MQ1][MD1];
731 MFEM_SHARED
double Xz[NBZ][MD1][MD1];
732 double (*X)[MD1] = (double (*)[MD1])(Xz + tidz);
734 MFEM_SHARED
double GD[2][NBZ][MD1][MQ1];
735 double (*DQ0)[MQ1] = (double (*)[MQ1])(GD[0] + tidz);
736 double (*DQ1)[MQ1] = (double (*)[MQ1])(GD[1] + tidz);
740 MFEM_FOREACH_THREAD(d,y,D1D)
742 MFEM_FOREACH_THREAD(q,x,Q1D)
751 for (
int c = 0; c < VDIM; ++c)
753 MFEM_FOREACH_THREAD(dx,x,D1D)
755 MFEM_FOREACH_THREAD(dy,y,D1D)
757 X[dx][dy] = x(dx,dy,c,e);
761 MFEM_FOREACH_THREAD(dy,y,D1D)
763 MFEM_FOREACH_THREAD(qx,x,Q1D)
767 for (
int dx = 0; dx < D1D; ++dx)
769 const double input = X[dx][dy];
770 u += B[qx][dx] * input;
771 v += G[qx][dx] * input;
778 MFEM_FOREACH_THREAD(qy,y,Q1D)
780 MFEM_FOREACH_THREAD(qx,x,Q1D)
784 for (
int dy = 0; dy < D1D; ++dy)
786 u += DQ1[dy][qx] * B[qy][dy];
787 v += DQ0[dy][qx] * G[qy][dy];
798 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
799 int MAX_D = 0,
int MAX_Q = 0>
800 static void D2QGrad3D(
const int NE,
809 const int D1D = T_D1D ? T_D1D : d1d;
810 const int Q1D = T_Q1D ? T_Q1D : q1d;
811 const int VDIM = T_VDIM ? T_VDIM : vdim;
814 auto g =
Reshape(g_, Q1D, D1D);
815 auto x =
Reshape(x_, D1D, D1D, D1D, VDIM, NE);
816 auto y =
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
818 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
820 const int D1D = T_D1D ? T_D1D : d1d;
821 const int Q1D = T_Q1D ? T_Q1D : q1d;
822 const int VDIM = T_VDIM ? T_VDIM : vdim;
823 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
824 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
825 const int tidz = MFEM_THREAD_ID(z);
826 MFEM_SHARED
double B[MQ1][MD1];
827 MFEM_SHARED
double G[MQ1][MD1];
829 MFEM_SHARED
double sm0[3][MQ1*MQ1*MQ1];
830 MFEM_SHARED
double sm1[3][MQ1*MQ1*MQ1];
831 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
832 double (*DDQ0)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+0);
833 double (*DDQ1)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+1);
834 double (*DQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+0);
835 double (*DQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+1);
836 double (*DQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+2);
840 MFEM_FOREACH_THREAD(d,y,D1D)
842 MFEM_FOREACH_THREAD(q,x,Q1D)
851 for (
int c = 0; c < VDIM; ++c)
853 MFEM_FOREACH_THREAD(dx,x,D1D)
855 MFEM_FOREACH_THREAD(dy,y,D1D)
857 MFEM_FOREACH_THREAD(dz,z,D1D)
859 X[dx][dy][dz] = x(dx,dy,dz,c,e);
865 MFEM_FOREACH_THREAD(dz,z,D1D)
867 MFEM_FOREACH_THREAD(dy,y,D1D)
869 MFEM_FOREACH_THREAD(qx,x,Q1D)
873 for (
int dx = 0; dx < D1D; ++dx)
875 const double coords = X[dx][dy][dz];
876 u += coords * B[qx][dx];
877 v += coords * G[qx][dx];
879 DDQ0[dz][dy][qx] = u;
880 DDQ1[dz][dy][qx] = v;
885 MFEM_FOREACH_THREAD(dz,z,D1D)
887 MFEM_FOREACH_THREAD(qy,y,Q1D)
889 MFEM_FOREACH_THREAD(qx,x,Q1D)
894 for (
int dy = 0; dy < D1D; ++dy)
896 u += DDQ1[dz][dy][qx] * B[qy][dy];
897 v += DDQ0[dz][dy][qx] * G[qy][dy];
898 w += DDQ0[dz][dy][qx] * B[qy][dy];
900 DQQ0[dz][qy][qx] = u;
901 DQQ1[dz][qy][qx] = v;
902 DQQ2[dz][qy][qx] = w;
907 MFEM_FOREACH_THREAD(qz,z,Q1D)
909 MFEM_FOREACH_THREAD(qy,y,Q1D)
911 MFEM_FOREACH_THREAD(qx,x,Q1D)
916 for (
int dz = 0; dz < D1D; ++dz)
918 u += DQQ0[dz][qy][qx] * B[qz][dz];
919 v += DQQ1[dz][qy][qx] * B[qz][dz];
920 w += DQQ2[dz][qy][qx] * G[qz][dz];
922 y(c,0,qx,qy,qz,e) = u;
923 y(c,1,qx,qy,qz,e) = v;
924 y(c,2,qx,qy,qz,e) = w;
933 static void D2QGrad(
const FiniteElementSpace &fes,
934 const DofToQuad *maps,
938 const int dim = fes.GetMesh()->Dimension();
939 const int vdim = fes.GetVDim();
940 const int NE = fes.GetNE();
941 const int D1D = maps->ndof;
942 const int Q1D = maps->nqpt;
943 const int id = (vdim<<8) | (D1D<<4) | Q1D;
944 const double *B = maps->B.Read();
945 const double *G = maps->G.Read();
946 const double *X = e_vec.Read();
947 double *Y = q_der.Write();
952 case 0x134:
return D2QGrad2D<1,3,4,8>(NE, B, G, X, Y);
953 case 0x146:
return D2QGrad2D<1,4,6,4>(NE, B, G, X, Y);
954 case 0x158:
return D2QGrad2D<1,5,8,2>(NE, B, G, X, Y);
955 case 0x234:
return D2QGrad2D<2,3,4,8>(NE, B, G, X, Y);
956 case 0x246:
return D2QGrad2D<2,4,6,4>(NE, B, G, X, Y);
957 case 0x258:
return D2QGrad2D<2,5,8,2>(NE, B, G, X, Y);
961 <<
" are not supported!");
962 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
963 <<
MAX_Q1D <<
" 1D points are not supported!");
964 D2QGrad2D(NE, B, G, X, Y, vdim, D1D, Q1D);
973 case 0x134:
return D2QGrad3D<1,3,4>(NE, B, G, X, Y);
974 case 0x146:
return D2QGrad3D<1,4,6>(NE, B, G, X, Y);
975 case 0x158:
return D2QGrad3D<1,5,8>(NE, B, G, X, Y);
976 case 0x334:
return D2QGrad3D<3,3,4>(NE, B, G, X, Y);
977 case 0x346:
return D2QGrad3D<3,4,6>(NE, B, G, X, Y);
978 case 0x358:
return D2QGrad3D<3,5,8>(NE, B, G, X, Y);
981 constexpr
int MD = 8;
982 constexpr
int MQ = 8;
983 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
984 <<
" are not supported!");
985 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
986 <<
" 1D points are not supported!");
987 D2QGrad3D<0,0,0,MD,MQ>(NE, B, G, X, Y, vdim, D1D, Q1D);
992 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
993 MFEM_ABORT(
"Unknown kernel");
996 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
997 static void D2QPhysGrad2D(
const int NE,
1007 const int D1D = T_D1D ? T_D1D : d1d;
1008 const int Q1D = T_Q1D ? T_Q1D : q1d;
1009 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
1010 const int VDIM = T_VDIM ? T_VDIM : vdim;
1013 auto g =
Reshape(g_, Q1D, D1D);
1014 auto j =
Reshape(j_, Q1D, Q1D, 2, 2, NE);
1015 auto x =
Reshape(x_, D1D, D1D, VDIM, NE);
1016 auto y =
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
1018 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
1020 const int D1D = T_D1D ? T_D1D : d1d;
1021 const int Q1D = T_Q1D ? T_Q1D : q1d;
1022 const int VDIM = T_VDIM ? T_VDIM : vdim;
1023 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
1024 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
1025 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
1026 const int tidz = MFEM_THREAD_ID(z);
1027 MFEM_SHARED
double B[MQ1][MD1];
1028 MFEM_SHARED
double G[MQ1][MD1];
1030 MFEM_SHARED
double Xz[NBZ][MD1][MD1];
1031 double (*X)[MD1] = (double (*)[MD1])(Xz + tidz);
1033 MFEM_SHARED
double GD[2][NBZ][MD1][MQ1];
1034 double (*DQ0)[MQ1] = (double (*)[MQ1])(GD[0] + tidz);
1035 double (*DQ1)[MQ1] = (double (*)[MQ1])(GD[1] + tidz);
1039 MFEM_FOREACH_THREAD(d,y,D1D)
1041 MFEM_FOREACH_THREAD(q,x,Q1D)
1050 for (
int c = 0; c < VDIM; ++c)
1052 MFEM_FOREACH_THREAD(dx,x,D1D)
1054 MFEM_FOREACH_THREAD(dy,y,D1D)
1056 X[dx][dy] = x(dx,dy,c,e);
1060 MFEM_FOREACH_THREAD(dy,y,D1D)
1062 MFEM_FOREACH_THREAD(qx,x,Q1D)
1066 for (
int dx = 0; dx < D1D; ++dx)
1068 const double input = X[dx][dy];
1069 u += B[qx][dx] * input;
1070 v += G[qx][dx] * input;
1078 MFEM_FOREACH_THREAD(qy,y,Q1D)
1080 MFEM_FOREACH_THREAD(qx,x,Q1D)
1084 for (
int dy = 0; dy < D1D; ++dy)
1086 u += DQ1[dy][qx] * B[qy][dy];
1087 v += DQ0[dy][qx] * G[qy][dy];
1089 double Jloc[4], Jinv[4];
1090 Jloc[0] = j(qx,qy,0,0,e);
1091 Jloc[1] = j(qx,qy,1,0,e);
1092 Jloc[2] = j(qx,qy,0,1,e);
1093 Jloc[3] = j(qx,qy,1,1,e);
1094 kernels::CalcInverse<2>(Jloc, Jinv);
1095 y(c,0,qx,qy,e) = Jinv[0]*u + Jinv[1]*v;
1096 y(c,1,qx,qy,e) = Jinv[2]*u + Jinv[3]*v;
1104 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
1105 int MAX_D = 0,
int MAX_Q = 0>
1106 static void D2QPhysGrad3D(
const int NE,
1116 const int D1D = T_D1D ? T_D1D : d1d;
1117 const int Q1D = T_Q1D ? T_Q1D : q1d;
1118 const int VDIM = T_VDIM ? T_VDIM : vdim;
1121 auto g =
Reshape(g_, Q1D, D1D);
1122 auto j =
Reshape(j_, Q1D, Q1D, Q1D, 3, 3, NE);
1123 auto x =
Reshape(x_, D1D, D1D, D1D, VDIM, NE);
1124 auto y =
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
1126 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
1128 const int D1D = T_D1D ? T_D1D : d1d;
1129 const int Q1D = T_Q1D ? T_Q1D : q1d;
1130 const int VDIM = T_VDIM ? T_VDIM : vdim;
1131 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
1132 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
1133 const int tidz = MFEM_THREAD_ID(z);
1134 MFEM_SHARED
double B[MQ1][MD1];
1135 MFEM_SHARED
double G[MQ1][MD1];
1137 MFEM_SHARED
double sm0[3][MQ1*MQ1*MQ1];
1138 MFEM_SHARED
double sm1[3][MQ1*MQ1*MQ1];
1139 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
1140 double (*DDQ0)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+0);
1141 double (*DDQ1)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+1);
1142 double (*DQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+0);
1143 double (*DQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+1);
1144 double (*DQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+2);
1148 MFEM_FOREACH_THREAD(d,y,D1D)
1150 MFEM_FOREACH_THREAD(q,x,Q1D)
1159 for (
int c = 0; c < VDIM; ++c)
1161 MFEM_FOREACH_THREAD(dx,x,D1D)
1163 MFEM_FOREACH_THREAD(dy,y,D1D)
1165 MFEM_FOREACH_THREAD(dz,z,D1D)
1168 X[dx][dy][dz] = x(dx,dy,dz,c,e);
1174 MFEM_FOREACH_THREAD(dz,z,D1D)
1176 MFEM_FOREACH_THREAD(dy,y,D1D)
1178 MFEM_FOREACH_THREAD(qx,x,Q1D)
1182 for (
int dx = 0; dx < D1D; ++dx)
1184 const double coords = X[dx][dy][dz];
1185 u += coords * B[qx][dx];
1186 v += coords * G[qx][dx];
1188 DDQ0[dz][dy][qx] = u;
1189 DDQ1[dz][dy][qx] = v;
1194 MFEM_FOREACH_THREAD(dz,z,D1D)
1196 MFEM_FOREACH_THREAD(qy,y,Q1D)
1198 MFEM_FOREACH_THREAD(qx,x,Q1D)
1203 for (
int dy = 0; dy < D1D; ++dy)
1205 u += DDQ1[dz][dy][qx] * B[qy][dy];
1206 v += DDQ0[dz][dy][qx] * G[qy][dy];
1207 w += DDQ0[dz][dy][qx] * B[qy][dy];
1209 DQQ0[dz][qy][qx] = u;
1210 DQQ1[dz][qy][qx] = v;
1211 DQQ2[dz][qy][qx] = w;
1216 MFEM_FOREACH_THREAD(qz,z,Q1D)
1218 MFEM_FOREACH_THREAD(qy,y,Q1D)
1220 MFEM_FOREACH_THREAD(qx,x,Q1D)
1225 for (
int dz = 0; dz < D1D; ++dz)
1227 u += DQQ0[dz][qy][qx] * B[qz][dz];
1228 v += DQQ1[dz][qy][qx] * B[qz][dz];
1229 w += DQQ2[dz][qy][qx] * G[qz][dz];
1231 double Jloc[9], Jinv[9];
1232 for (
int col = 0; col < 3; col++)
1234 for (
int row = 0; row < 3; row++)
1236 Jloc[row+3*col] = j(qx,qy,qz,row,col,e);
1239 kernels::CalcInverse<3>(Jloc, Jinv);
1240 y(c,0,qx,qy,qz,e) = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
1241 y(c,1,qx,qy,qz,e) = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
1242 y(c,2,qx,qy,qz,e) = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
1252 static void D2QPhysGrad(
const FiniteElementSpace &fes,
1253 const GeometricFactors *
geom,
1254 const DofToQuad *maps,
1255 const Vector &e_vec,
1258 const int dim = fes.GetMesh()->Dimension();
1259 const int vdim = fes.GetVDim();
1260 const int NE = fes.GetNE();
1261 const int D1D = maps->ndof;
1262 const int Q1D = maps->nqpt;
1263 const int id = (vdim<<8) | (D1D<<4) | Q1D;
1264 const double *B = maps->B.Read();
1265 const double *G = maps->G.Read();
1266 const double *J = geom->J.Read();
1267 const double *X = e_vec.Read();
1268 double *Y = q_der.Write();
1273 case 0x134:
return D2QPhysGrad2D<1,3,4,8>(NE, B, G, J, X, Y);
1274 case 0x146:
return D2QPhysGrad2D<1,4,6,4>(NE, B, G, J, X, Y);
1275 case 0x158:
return D2QPhysGrad2D<1,5,8,2>(NE, B, G, J, X, Y);
1276 case 0x234:
return D2QPhysGrad2D<2,3,4,8>(NE, B, G, J, X, Y);
1277 case 0x246:
return D2QPhysGrad2D<2,4,6,4>(NE, B, G, J, X, Y);
1278 case 0x258:
return D2QPhysGrad2D<2,5,8,2>(NE, B, G, J, X, Y);
1282 <<
" are not supported!");
1283 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
1284 <<
MAX_Q1D <<
" 1D points are not supported!");
1285 D2QPhysGrad2D(NE, B, G, J, X, Y, vdim, D1D, Q1D);
1294 case 0x134:
return D2QPhysGrad3D<1,3,4>(NE, B, G, J, X, Y);
1295 case 0x146:
return D2QPhysGrad3D<1,4,6>(NE, B, G, J, X, Y);
1296 case 0x158:
return D2QPhysGrad3D<1,5,8>(NE, B, G, J, X, Y);
1297 case 0x334:
return D2QPhysGrad3D<3,3,4>(NE, B, G, J, X, Y);
1298 case 0x346:
return D2QPhysGrad3D<3,4,6>(NE, B, G, J, X, Y);
1299 case 0x358:
return D2QPhysGrad3D<3,5,8>(NE, B, G, J, X, Y);
1302 constexpr
int MD = 8;
1303 constexpr
int MQ = 8;
1304 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
1305 <<
" are not supported!");
1306 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
1307 <<
" 1D points are not supported!");
1308 D2QPhysGrad3D<0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
1313 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
1314 MFEM_ABORT(
"Unknown kernel");
1332 D2QGrad(*
fespace, &d2q, e_vec, q_der);
1340 MFEM_ABORT(
"evaluation of physical derivatives with 'byNODES' output"
1341 " layout is not implemented yet!");
1347 if (mesh->
GetNE() == 0) {
return; }
1354 D2QPhysGrad(*
fespace, geom, &d2q, e_vec, q_der);
Abstract class for all finite elements.
Class for an integration rule - an Array of IntegrationPoint.
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
const IntegrationRule & GetElementIntRule(int idx) const
Get the IntegrationRule associated with mesh element idx.
static const int MAX_ND2D
const FiniteElementSpace * fespace
Not owned.
static const int MAX_NQ3D
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
int GetNE() const
Returns number of elements.
Evaluate the derivatives at quadrature points.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
static const int MAX_ND3D
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
int GetNE() const
Returns number of elements in the mesh.
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags)
Return the mesh geometric factors corresponding to the given integration rule.
QVectorLayout q_layout
Output Q-vector layout.
Mesh * GetMesh() const
Returns the mesh.
const IntegrationRule * IntRule
Not owned.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
int GetVDim() const
Returns vector dimension.
static const int MAX_VDIM2D
QuadratureInterpolator(const FiniteElementSpace &fes, const IntegrationRule &ir)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const
Interpolate the derivatives in physical space of the E-vector e_vec at quadrature points...
static void Eval2D(const int NE, const int vdim, const DofToQuad &maps, const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det, const int eval_flags)
Template compute kernel for 2D.
Structure representing the matrices/tensors needed to evaluate (in reference space) the values...
Array< double > B
Basis functions evaluated at quadrature points.
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
static void Eval3D(const int NE, const int vdim, const DofToQuad &maps, const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det, const int eval_flags)
Template compute kernel for 3D.
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
Full multidimensional representation which does not use tensor product structure. The ordering of the...
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
static const int MAX_VDIM3D
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det) const
Interpolate the E-vector e_vec to quadrature points.
Array< double > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
void Derivatives(const Vector &e_vec, Vector &q_der) const
Interpolate the derivatives of the E-vector e_vec at quadrature points.
static const int MAX_NQ2D
Class representing the storage layout of a QuadratureFunction.
void Values(const Vector &e_vec, Vector &q_val) const
Interpolate the values of the E-vector e_vec at quadrature points.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void MultTranspose(unsigned eval_flags, const Vector &q_val, const Vector &q_der, Vector &e_vec) const
Perform the transpose operation of Mult(). (TODO)
Evaluate the values at quadrature points.
const QuadratureSpace * qspace
Not owned.