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 VDIM = T_VDIM ? T_VDIM : vdim;
68 MFEM_VERIFY(VDIM == 2 || !(eval_flags &
DETERMINANTS),
"");
77 const int ND = T_ND ? T_ND : nd;
78 const int NQ = T_NQ ? T_NQ : nq;
79 const int VDIM = T_VDIM ? T_VDIM : vdim;
80 constexpr
int max_ND = T_ND ? T_ND :
MAX_ND2D;
81 constexpr
int max_VDIM = T_VDIM ? T_VDIM :
MAX_VDIM2D;
82 double s_E[max_VDIM*max_ND];
83 for (
int d = 0; d < ND; d++)
85 for (
int c = 0; c < VDIM; c++)
87 s_E[c+d*VDIM] = E(d,c,e);
90 for (
int q = 0; q < NQ; ++q)
95 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
96 for (
int d = 0; d < ND; ++d)
98 const double b = B(q,d);
99 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
101 for (
int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
103 if ((eval_flags &
DERIVATIVES) || (eval_flags & DETERMINANTS))
107 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
108 for (
int d = 0; d < ND; ++d)
110 const double wx = G(q,0,d);
111 const double wy = G(q,1,d);
112 for (
int c = 0; c < VDIM; c++)
114 double s_e = s_E[c+d*VDIM];
115 D[c+VDIM*0] += s_e * wx;
116 D[c+VDIM*1] += s_e * wy;
119 if (eval_flags & DERIVATIVES)
121 for (
int c = 0; c < VDIM; c++)
123 der(q,c,0,e) = D[c+VDIM*0];
124 der(q,c,1,e) = D[c+VDIM*1];
127 if (VDIM == 2 && (eval_flags & DETERMINANTS))
131 det(q,e) = kernels::Det<2>(D);
138 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
147 const int eval_flags)
149 const int nd = maps.
ndof;
150 const int nq = maps.
nqpt;
151 const int ND = T_ND ? T_ND : nd;
152 const int NQ = T_NQ ? T_NQ : nq;
153 const int VDIM = T_VDIM ? T_VDIM : vdim;
156 MFEM_VERIFY(VDIM == 3 || !(eval_flags &
DETERMINANTS),
"");
165 const int ND = T_ND ? T_ND : nd;
166 const int NQ = T_NQ ? T_NQ : nq;
167 const int VDIM = T_VDIM ? T_VDIM : vdim;
168 constexpr
int max_ND = T_ND ? T_ND :
MAX_ND3D;
169 constexpr
int max_VDIM = T_VDIM ? T_VDIM :
MAX_VDIM3D;
170 double s_E[max_VDIM*max_ND];
171 for (
int d = 0; d < ND; d++)
173 for (
int c = 0; c < VDIM; c++)
175 s_E[c+d*VDIM] = E(d,c,e);
178 for (
int q = 0; q < NQ; ++q)
183 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
184 for (
int d = 0; d < ND; ++d)
186 const double b = B(q,d);
187 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
189 for (
int c = 0; c < VDIM; c++) { val(q,c,e) = ed[c]; }
191 if ((eval_flags &
DERIVATIVES) || (eval_flags & DETERMINANTS))
195 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
196 for (
int d = 0; d < ND; ++d)
198 const double wx = G(q,0,d);
199 const double wy = G(q,1,d);
200 const double wz = G(q,2,d);
201 for (
int c = 0; c < VDIM; c++)
203 double s_e = s_E[c+d*VDIM];
204 D[c+VDIM*0] += s_e * wx;
205 D[c+VDIM*1] += s_e * wy;
206 D[c+VDIM*2] += s_e * wz;
209 if (eval_flags & DERIVATIVES)
211 for (
int c = 0; c < VDIM; c++)
213 der(q,c,0,e) = D[c+VDIM*0];
214 der(q,c,1,e) = D[c+VDIM*1];
215 der(q,c,2,e) = D[c+VDIM*2];
218 if (VDIM == 3 && (eval_flags & DETERMINANTS))
222 det(q,e) = kernels::Det<3>(D);
230 const Vector &e_vec,
unsigned eval_flags,
239 MFEM_ABORT(
"evaluation of determinants with 'byVDIM' output layout"
240 " is not implemented yet!");
247 if (ne == 0) {
return; }
254 const int nd = maps.
ndof;
255 const int nq = maps.
nqpt;
264 const int eval_flags) = NULL;
272 case 101: eval_func = &Eval2D<1,1,1>;
break;
273 case 104: eval_func = &Eval2D<1,1,4>;
break;
275 case 404: eval_func = &Eval2D<1,4,4>;
break;
276 case 409: eval_func = &Eval2D<1,4,9>;
break;
278 case 909: eval_func = &Eval2D<1,9,9>;
break;
279 case 916: eval_func = &Eval2D<1,9,16>;
break;
281 case 1616: eval_func = &Eval2D<1,16,16>;
break;
282 case 1625: eval_func = &Eval2D<1,16,25>;
break;
283 case 1636: eval_func = &Eval2D<1,16,36>;
break;
285 case 2525: eval_func = &Eval2D<1,25,25>;
break;
286 case 2536: eval_func = &Eval2D<1,25,36>;
break;
287 case 2549: eval_func = &Eval2D<1,25,49>;
break;
288 case 2564: eval_func = &Eval2D<1,25,64>;
break;
290 if (nq >= 100 || !eval_func)
292 eval_func = &Eval2D<1>;
297 switch (1000*nd + nq)
300 case 1001: eval_func = &Eval3D<1,1,1>;
break;
301 case 1008: eval_func = &Eval3D<1,1,8>;
break;
303 case 8008: eval_func = &Eval3D<1,8,8>;
break;
304 case 8027: eval_func = &Eval3D<1,8,27>;
break;
306 case 27027: eval_func = &Eval3D<1,27,27>;
break;
307 case 27064: eval_func = &Eval3D<1,27,64>;
break;
309 case 64064: eval_func = &Eval3D<1,64,64>;
break;
310 case 64125: eval_func = &Eval3D<1,64,125>;
break;
311 case 64216: eval_func = &Eval3D<1,64,216>;
break;
313 case 125125: eval_func = &Eval3D<1,125,125>;
break;
314 case 125216: eval_func = &Eval3D<1,125,216>;
break;
316 if (nq >= 1000 || !eval_func)
318 eval_func = &Eval3D<1>;
322 else if (vdim == dim)
329 case 404: eval_func = &Eval2D<2,4,4>;
break;
330 case 409: eval_func = &Eval2D<2,4,9>;
break;
332 case 909: eval_func = &Eval2D<2,9,9>;
break;
333 case 916: eval_func = &Eval2D<2,9,16>;
break;
335 case 1616: eval_func = &Eval2D<2,16,16>;
break;
336 case 1625: eval_func = &Eval2D<2,16,25>;
break;
337 case 1636: eval_func = &Eval2D<2,16,36>;
break;
339 case 2525: eval_func = &Eval2D<2,25,25>;
break;
340 case 2536: eval_func = &Eval2D<2,25,36>;
break;
341 case 2549: eval_func = &Eval2D<2,25,49>;
break;
342 case 2564: eval_func = &Eval2D<2,25,64>;
break;
344 if (nq >= 100 || !eval_func)
346 eval_func = &Eval2D<2>;
351 switch (1000*nd + nq)
354 case 8008: eval_func = &Eval3D<3,8,8>;
break;
355 case 8027: eval_func = &Eval3D<3,8,27>;
break;
357 case 27027: eval_func = &Eval3D<3,27,27>;
break;
358 case 27064: eval_func = &Eval3D<3,27,64>;
break;
360 case 64064: eval_func = &Eval3D<3,64,64>;
break;
361 case 64125: eval_func = &Eval3D<3,64,125>;
break;
362 case 64216: eval_func = &Eval3D<3,64,216>;
break;
364 case 125125: eval_func = &Eval3D<3,125,125>;
break;
365 case 125216: eval_func = &Eval3D<3,125,216>;
break;
367 if (nq >= 1000 || !eval_func)
369 eval_func = &Eval3D<3>;
375 eval_func(ne, vdim, maps, e_vec, q_val, q_der, q_det, eval_flags);
379 MFEM_ABORT(
"case not supported yet");
384 unsigned eval_flags,
const Vector &q_val,
const Vector &q_der,
387 MFEM_ABORT(
"this method is not implemented yet");
391 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
392 static void D2QValues2D(
const int NE,
400 const int D1D = T_D1D ? T_D1D : d1d;
401 const int Q1D = T_Q1D ? T_Q1D : q1d;
402 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
403 const int VDIM = T_VDIM ? T_VDIM : vdim;
409 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
411 const int D1D = T_D1D ? T_D1D : d1d;
412 const int Q1D = T_Q1D ? T_Q1D : q1d;
413 const int VDIM = T_VDIM ? T_VDIM : vdim;
414 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
415 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
416 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
417 const int zid = MFEM_THREAD_ID(z);
418 MFEM_SHARED
double B[MQ1][MD1];
420 MFEM_SHARED
double DDz[NBZ][MD1*MD1];
421 double (*DD)[MD1] = (double (*)[MD1])(DDz + zid);
423 MFEM_SHARED
double DQz[NBZ][MD1*MQ1];
424 double (*DQ)[MQ1] = (double (*)[MQ1])(DQz + zid);
428 MFEM_FOREACH_THREAD(d,y,D1D)
430 MFEM_FOREACH_THREAD(q,x,Q1D)
438 for (
int c = 0; c < VDIM; c++)
440 MFEM_FOREACH_THREAD(dy,y,D1D)
442 MFEM_FOREACH_THREAD(dx,x,D1D)
444 DD[dy][dx] = x(dx,dy,c,e);
448 MFEM_FOREACH_THREAD(dy,y,D1D)
450 MFEM_FOREACH_THREAD(qx,x,Q1D)
453 for (
int dx = 0; dx < D1D; ++dx)
455 dq += B[qx][dx] * DD[dy][dx];
461 MFEM_FOREACH_THREAD(qy,y,Q1D)
463 MFEM_FOREACH_THREAD(qx,x,Q1D)
466 for (
int dy = 0; dy < D1D; ++dy)
468 qq += DQ[dy][qx] * B[qy][dy];
478 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
479 int MAX_D = 0,
int MAX_Q = 0>
480 static void D2QValues3D(
const int NE,
481 const Array<double> &b_,
488 const int D1D = T_D1D ? T_D1D : d1d;
489 const int Q1D = T_Q1D ? T_Q1D : q1d;
490 const int VDIM = T_VDIM ? T_VDIM : vdim;
492 auto b =
Reshape(b_.Read(), Q1D, D1D);
493 auto x =
Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
494 auto y =
Reshape(y_.Write(), VDIM, Q1D, Q1D, Q1D, NE);
496 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
498 const int D1D = T_D1D ? T_D1D : d1d;
499 const int Q1D = T_Q1D ? T_Q1D : q1d;
500 const int VDIM = T_VDIM ? T_VDIM : vdim;
501 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
502 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
503 constexpr
int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
504 const int tidz = MFEM_THREAD_ID(z);
505 MFEM_SHARED
double B[MQ1][MD1];
506 MFEM_SHARED
double sm0[MDQ*MDQ*MDQ];
507 MFEM_SHARED
double sm1[MDQ*MDQ*MDQ];
508 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) sm0;
509 double (*DDQ)[MD1][MQ1] = (double (*)[MD1][MQ1]) sm1;
510 double (*DQQ)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) sm0;
514 MFEM_FOREACH_THREAD(d,y,D1D)
516 MFEM_FOREACH_THREAD(q,x,Q1D)
524 for (
int c = 0; c < VDIM; c++)
526 MFEM_FOREACH_THREAD(dz,z,D1D)
528 MFEM_FOREACH_THREAD(dy,y,D1D)
530 MFEM_FOREACH_THREAD(dx,x,D1D)
532 X[dz][dy][dx] = x(dx,dy,dz,c,e);
537 MFEM_FOREACH_THREAD(dz,z,D1D)
539 MFEM_FOREACH_THREAD(dy,y,D1D)
541 MFEM_FOREACH_THREAD(qx,x,Q1D)
544 for (
int dx = 0; dx < D1D; ++dx)
546 u += B[qx][dx] * X[dz][dy][dx];
553 MFEM_FOREACH_THREAD(dz,z,D1D)
555 MFEM_FOREACH_THREAD(qy,y,Q1D)
557 MFEM_FOREACH_THREAD(qx,x,Q1D)
560 for (
int dy = 0; dy < D1D; ++dy)
562 u += DDQ[dz][dy][qx] * B[qy][dy];
569 MFEM_FOREACH_THREAD(qz,z,Q1D)
571 MFEM_FOREACH_THREAD(qy,y,Q1D)
573 MFEM_FOREACH_THREAD(qx,x,Q1D)
576 for (
int dz = 0; dz < D1D; ++dz)
578 u += DQQ[dz][qy][qx] * B[qz][dz];
589 static void D2QValues(
const FiniteElementSpace &fes,
590 const DofToQuad *maps,
594 const int dim = fes.GetMesh()->Dimension();
595 const int vdim = fes.GetVDim();
596 const int NE = fes.GetNE();
597 const int D1D = maps->ndof;
598 const int Q1D = maps->nqpt;
599 const int id = (vdim<<8) | (D1D<<4) | Q1D;
605 case 0x124:
return D2QValues2D<1,2,4,8>(NE, maps->B, e_vec, q_val);
606 case 0x136:
return D2QValues2D<1,3,6,4>(NE, maps->B, e_vec, q_val);
607 case 0x148:
return D2QValues2D<1,4,8,2>(NE, maps->B, e_vec, q_val);
608 case 0x224:
return D2QValues2D<2,2,4,8>(NE, maps->B, e_vec, q_val);
609 case 0x236:
return D2QValues2D<2,3,6,4>(NE, maps->B, e_vec, q_val);
610 case 0x248:
return D2QValues2D<2,4,8,2>(NE, maps->B, e_vec, q_val);
614 <<
" are not supported!");
615 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
616 <<
MAX_Q1D <<
" 1D points are not supported!");
617 D2QValues2D(NE, maps->B, e_vec, q_val, vdim, D1D, Q1D);
626 case 0x124:
return D2QValues3D<1,2,4>(NE, maps->B, e_vec, q_val);
627 case 0x136:
return D2QValues3D<1,3,6>(NE, maps->B, e_vec, q_val);
628 case 0x148:
return D2QValues3D<1,4,8>(NE, maps->B, e_vec, q_val);
629 case 0x324:
return D2QValues3D<3,2,4>(NE, maps->B, e_vec, q_val);
630 case 0x336:
return D2QValues3D<3,3,6>(NE, maps->B, e_vec, q_val);
631 case 0x348:
return D2QValues3D<3,4,8>(NE, maps->B, e_vec, q_val);
634 constexpr
int MD = 8;
635 constexpr
int MQ = 8;
636 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
637 <<
" are not supported!");
638 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
639 <<
" 1D points are not supported!");
640 D2QValues3D<0,0,0,MD,MQ>(NE, maps->B, e_vec, q_val, vdim, D1D, Q1D);
645 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
646 MFEM_ABORT(
"Unknown kernel");
663 D2QValues(*
fespace, &d2q, e_vec, q_val);
666 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
667 static void D2QGrad2D(
const int NE,
676 const int D1D = T_D1D ? T_D1D : d1d;
677 const int Q1D = T_Q1D ? T_Q1D : q1d;
678 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
679 const int VDIM = T_VDIM ? T_VDIM : vdim;
682 auto g =
Reshape(g_, Q1D, D1D);
683 auto x =
Reshape(x_, D1D, D1D, VDIM, NE);
684 auto y =
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
686 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
688 const int D1D = T_D1D ? T_D1D : d1d;
689 const int Q1D = T_Q1D ? T_Q1D : q1d;
690 const int VDIM = T_VDIM ? T_VDIM : vdim;
691 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
692 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
693 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
694 const int tidz = MFEM_THREAD_ID(z);
695 MFEM_SHARED
double B[MQ1][MD1];
696 MFEM_SHARED
double G[MQ1][MD1];
698 MFEM_SHARED
double Xz[NBZ][MD1][MD1];
699 double (*X)[MD1] = (double (*)[MD1])(Xz + tidz);
701 MFEM_SHARED
double GD[2][NBZ][MD1][MQ1];
702 double (*DQ0)[MQ1] = (double (*)[MQ1])(GD[0] + tidz);
703 double (*DQ1)[MQ1] = (double (*)[MQ1])(GD[1] + tidz);
707 MFEM_FOREACH_THREAD(d,y,D1D)
709 MFEM_FOREACH_THREAD(q,x,Q1D)
718 for (
int c = 0; c < VDIM; ++c)
720 MFEM_FOREACH_THREAD(dx,x,D1D)
722 MFEM_FOREACH_THREAD(dy,y,D1D)
724 X[dx][dy] = x(dx,dy,c,e);
728 MFEM_FOREACH_THREAD(dy,y,D1D)
730 MFEM_FOREACH_THREAD(qx,x,Q1D)
734 for (
int dx = 0; dx < D1D; ++dx)
736 const double input = X[dx][dy];
737 u += B[qx][dx] * input;
738 v += G[qx][dx] * input;
745 MFEM_FOREACH_THREAD(qy,y,Q1D)
747 MFEM_FOREACH_THREAD(qx,x,Q1D)
751 for (
int dy = 0; dy < D1D; ++dy)
753 u += DQ1[dy][qx] * B[qy][dy];
754 v += DQ0[dy][qx] * G[qy][dy];
765 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
766 int MAX_D = 0,
int MAX_Q = 0>
767 static void D2QGrad3D(
const int NE,
776 const int D1D = T_D1D ? T_D1D : d1d;
777 const int Q1D = T_Q1D ? T_Q1D : q1d;
778 const int VDIM = T_VDIM ? T_VDIM : vdim;
781 auto g =
Reshape(g_, Q1D, D1D);
782 auto x =
Reshape(x_, D1D, D1D, D1D, VDIM, NE);
783 auto y =
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
785 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
787 const int D1D = T_D1D ? T_D1D : d1d;
788 const int Q1D = T_Q1D ? T_Q1D : q1d;
789 const int VDIM = T_VDIM ? T_VDIM : vdim;
790 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
791 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
792 const int tidz = MFEM_THREAD_ID(z);
793 MFEM_SHARED
double B[MQ1][MD1];
794 MFEM_SHARED
double G[MQ1][MD1];
796 MFEM_SHARED
double sm0[3][MQ1*MQ1*MQ1];
797 MFEM_SHARED
double sm1[3][MQ1*MQ1*MQ1];
798 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
799 double (*DDQ0)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+0);
800 double (*DDQ1)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+1);
801 double (*DQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+0);
802 double (*DQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+1);
803 double (*DQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+2);
807 MFEM_FOREACH_THREAD(d,y,D1D)
809 MFEM_FOREACH_THREAD(q,x,Q1D)
818 for (
int c = 0; c < VDIM; ++c)
820 MFEM_FOREACH_THREAD(dx,x,D1D)
822 MFEM_FOREACH_THREAD(dy,y,D1D)
824 MFEM_FOREACH_THREAD(dz,z,D1D)
826 X[dx][dy][dz] = x(dx,dy,dz,c,e);
832 MFEM_FOREACH_THREAD(dz,z,D1D)
834 MFEM_FOREACH_THREAD(dy,y,D1D)
836 MFEM_FOREACH_THREAD(qx,x,Q1D)
840 for (
int dx = 0; dx < D1D; ++dx)
842 const double coords = X[dx][dy][dz];
843 u += coords * B[qx][dx];
844 v += coords * G[qx][dx];
846 DDQ0[dz][dy][qx] = u;
847 DDQ1[dz][dy][qx] = v;
852 MFEM_FOREACH_THREAD(dz,z,D1D)
854 MFEM_FOREACH_THREAD(qy,y,Q1D)
856 MFEM_FOREACH_THREAD(qx,x,Q1D)
861 for (
int dy = 0; dy < D1D; ++dy)
863 u += DDQ1[dz][dy][qx] * B[qy][dy];
864 v += DDQ0[dz][dy][qx] * G[qy][dy];
865 w += DDQ0[dz][dy][qx] * B[qy][dy];
867 DQQ0[dz][qy][qx] = u;
868 DQQ1[dz][qy][qx] = v;
869 DQQ2[dz][qy][qx] = w;
874 MFEM_FOREACH_THREAD(qz,z,Q1D)
876 MFEM_FOREACH_THREAD(qy,y,Q1D)
878 MFEM_FOREACH_THREAD(qx,x,Q1D)
883 for (
int dz = 0; dz < D1D; ++dz)
885 u += DQQ0[dz][qy][qx] * B[qz][dz];
886 v += DQQ1[dz][qy][qx] * B[qz][dz];
887 w += DQQ2[dz][qy][qx] * G[qz][dz];
889 y(c,0,qx,qy,qz,e) = u;
890 y(c,1,qx,qy,qz,e) = v;
891 y(c,2,qx,qy,qz,e) = w;
900 static void D2QGrad(
const FiniteElementSpace &fes,
901 const DofToQuad *maps,
905 const int dim = fes.GetMesh()->Dimension();
906 const int vdim = fes.GetVDim();
907 const int NE = fes.GetNE();
908 const int D1D = maps->ndof;
909 const int Q1D = maps->nqpt;
910 const int id = (vdim<<8) | (D1D<<4) | Q1D;
911 const double *B = maps->B.Read();
912 const double *G = maps->G.Read();
913 const double *X = e_vec.Read();
914 double *Y = q_der.Write();
919 case 0x134:
return D2QGrad2D<1,3,4,8>(NE, B, G, X, Y);
920 case 0x146:
return D2QGrad2D<1,4,6,4>(NE, B, G, X, Y);
921 case 0x158:
return D2QGrad2D<1,5,8,2>(NE, B, G, X, Y);
922 case 0x234:
return D2QGrad2D<2,3,4,8>(NE, B, G, X, Y);
923 case 0x246:
return D2QGrad2D<2,4,6,4>(NE, B, G, X, Y);
924 case 0x258:
return D2QGrad2D<2,5,8,2>(NE, B, G, X, Y);
928 <<
" are not supported!");
929 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
930 <<
MAX_Q1D <<
" 1D points are not supported!");
931 D2QGrad2D(NE, B, G, X, Y, vdim, D1D, Q1D);
940 case 0x134:
return D2QGrad3D<1,3,4>(NE, B, G, X, Y);
941 case 0x146:
return D2QGrad3D<1,4,6>(NE, B, G, X, Y);
942 case 0x158:
return D2QGrad3D<1,5,8>(NE, B, G, X, Y);
943 case 0x334:
return D2QGrad3D<3,3,4>(NE, B, G, X, Y);
944 case 0x346:
return D2QGrad3D<3,4,6>(NE, B, G, X, Y);
945 case 0x358:
return D2QGrad3D<3,5,8>(NE, B, G, X, Y);
948 constexpr
int MD = 8;
949 constexpr
int MQ = 8;
950 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
951 <<
" are not supported!");
952 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
953 <<
" 1D points are not supported!");
954 D2QGrad3D<0,0,0,MD,MQ>(NE, B, G, X, Y, vdim, D1D, Q1D);
959 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
960 MFEM_ABORT(
"Unknown kernel");
963 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
int T_NBZ = 0>
964 static void D2QPhysGrad2D(
const int NE,
974 const int D1D = T_D1D ? T_D1D : d1d;
975 const int Q1D = T_Q1D ? T_Q1D : q1d;
976 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
977 const int VDIM = T_VDIM ? T_VDIM : vdim;
980 auto g =
Reshape(g_, Q1D, D1D);
981 auto j =
Reshape(j_, Q1D, Q1D, 2, 2, NE);
982 auto x =
Reshape(x_, D1D, D1D, VDIM, NE);
983 auto y =
Reshape(y_, VDIM, 2, Q1D, Q1D, NE);
985 MFEM_FORALL_2D(e, NE, Q1D, Q1D, NBZ,
987 const int D1D = T_D1D ? T_D1D : d1d;
988 const int Q1D = T_Q1D ? T_Q1D : q1d;
989 const int VDIM = T_VDIM ? T_VDIM : vdim;
990 constexpr
int NBZ = T_NBZ ? T_NBZ : 1;
991 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
992 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
993 const int tidz = MFEM_THREAD_ID(z);
994 MFEM_SHARED
double B[MQ1][MD1];
995 MFEM_SHARED
double G[MQ1][MD1];
997 MFEM_SHARED
double Xz[NBZ][MD1][MD1];
998 double (*X)[MD1] = (double (*)[MD1])(Xz + tidz);
1000 MFEM_SHARED
double GD[2][NBZ][MD1][MQ1];
1001 double (*DQ0)[MQ1] = (double (*)[MQ1])(GD[0] + tidz);
1002 double (*DQ1)[MQ1] = (double (*)[MQ1])(GD[1] + tidz);
1006 MFEM_FOREACH_THREAD(d,y,D1D)
1008 MFEM_FOREACH_THREAD(q,x,Q1D)
1017 for (
int c = 0; c < VDIM; ++c)
1019 MFEM_FOREACH_THREAD(dx,x,D1D)
1021 MFEM_FOREACH_THREAD(dy,y,D1D)
1023 X[dx][dy] = x(dx,dy,c,e);
1027 MFEM_FOREACH_THREAD(dy,y,D1D)
1029 MFEM_FOREACH_THREAD(qx,x,Q1D)
1033 for (
int dx = 0; dx < D1D; ++dx)
1035 const double input = X[dx][dy];
1036 u += B[qx][dx] * input;
1037 v += G[qx][dx] * input;
1045 MFEM_FOREACH_THREAD(qy,y,Q1D)
1047 MFEM_FOREACH_THREAD(qx,x,Q1D)
1051 for (
int dy = 0; dy < D1D; ++dy)
1053 u += DQ1[dy][qx] * B[qy][dy];
1054 v += DQ0[dy][qx] * G[qy][dy];
1056 double Jloc[4], Jinv[4];
1057 Jloc[0] = j(qx,qy,0,0,e);
1058 Jloc[1] = j(qx,qy,1,0,e);
1059 Jloc[2] = j(qx,qy,0,1,e);
1060 Jloc[3] = j(qx,qy,1,1,e);
1061 kernels::CalcInverse<2>(Jloc, Jinv);
1062 y(c,0,qx,qy,e) = Jinv[0]*u + Jinv[1]*v;
1063 y(c,1,qx,qy,e) = Jinv[2]*u + Jinv[3]*v;
1071 template<
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
1072 int MAX_D = 0,
int MAX_Q = 0>
1073 static void D2QPhysGrad3D(
const int NE,
1083 const int D1D = T_D1D ? T_D1D : d1d;
1084 const int Q1D = T_Q1D ? T_Q1D : q1d;
1085 const int VDIM = T_VDIM ? T_VDIM : vdim;
1088 auto g =
Reshape(g_, Q1D, D1D);
1089 auto j =
Reshape(j_, Q1D, Q1D, Q1D, 3, 3, NE);
1090 auto x =
Reshape(x_, D1D, D1D, D1D, VDIM, NE);
1091 auto y =
Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
1093 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
1095 const int D1D = T_D1D ? T_D1D : d1d;
1096 const int Q1D = T_Q1D ? T_Q1D : q1d;
1097 const int VDIM = T_VDIM ? T_VDIM : vdim;
1098 constexpr
int MQ1 = T_Q1D ? T_Q1D : MAX_Q;
1099 constexpr
int MD1 = T_D1D ? T_D1D : MAX_D;
1100 const int tidz = MFEM_THREAD_ID(z);
1101 MFEM_SHARED
double B[MQ1][MD1];
1102 MFEM_SHARED
double G[MQ1][MD1];
1104 MFEM_SHARED
double sm0[3][MQ1*MQ1*MQ1];
1105 MFEM_SHARED
double sm1[3][MQ1*MQ1*MQ1];
1106 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
1107 double (*DDQ0)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+0);
1108 double (*DDQ1)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+1);
1109 double (*DQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+0);
1110 double (*DQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+1);
1111 double (*DQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+2);
1115 MFEM_FOREACH_THREAD(d,y,D1D)
1117 MFEM_FOREACH_THREAD(q,x,Q1D)
1126 for (
int c = 0; c < VDIM; ++c)
1128 MFEM_FOREACH_THREAD(dx,x,D1D)
1130 MFEM_FOREACH_THREAD(dy,y,D1D)
1132 MFEM_FOREACH_THREAD(dz,z,D1D)
1135 X[dx][dy][dz] = x(dx,dy,dz,c,e);
1141 MFEM_FOREACH_THREAD(dz,z,D1D)
1143 MFEM_FOREACH_THREAD(dy,y,D1D)
1145 MFEM_FOREACH_THREAD(qx,x,Q1D)
1149 for (
int dx = 0; dx < D1D; ++dx)
1151 const double coords = X[dx][dy][dz];
1152 u += coords * B[qx][dx];
1153 v += coords * G[qx][dx];
1155 DDQ0[dz][dy][qx] = u;
1156 DDQ1[dz][dy][qx] = v;
1161 MFEM_FOREACH_THREAD(dz,z,D1D)
1163 MFEM_FOREACH_THREAD(qy,y,Q1D)
1165 MFEM_FOREACH_THREAD(qx,x,Q1D)
1170 for (
int dy = 0; dy < D1D; ++dy)
1172 u += DDQ1[dz][dy][qx] * B[qy][dy];
1173 v += DDQ0[dz][dy][qx] * G[qy][dy];
1174 w += DDQ0[dz][dy][qx] * B[qy][dy];
1176 DQQ0[dz][qy][qx] = u;
1177 DQQ1[dz][qy][qx] = v;
1178 DQQ2[dz][qy][qx] = w;
1183 MFEM_FOREACH_THREAD(qz,z,Q1D)
1185 MFEM_FOREACH_THREAD(qy,y,Q1D)
1187 MFEM_FOREACH_THREAD(qx,x,Q1D)
1192 for (
int dz = 0; dz < D1D; ++dz)
1194 u += DQQ0[dz][qy][qx] * B[qz][dz];
1195 v += DQQ1[dz][qy][qx] * B[qz][dz];
1196 w += DQQ2[dz][qy][qx] * G[qz][dz];
1198 double Jloc[9], Jinv[9];
1199 for (
int col = 0; col < 3; col++)
1201 for (
int row = 0; row < 3; row++)
1203 Jloc[row+3*col] = j(qx,qy,qz,row,col,e);
1206 kernels::CalcInverse<3>(Jloc, Jinv);
1207 y(c,0,qx,qy,qz,e) = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
1208 y(c,1,qx,qy,qz,e) = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
1209 y(c,2,qx,qy,qz,e) = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
1219 static void D2QPhysGrad(
const FiniteElementSpace &fes,
1220 const GeometricFactors *
geom,
1221 const DofToQuad *maps,
1222 const Vector &e_vec,
1225 const int dim = fes.GetMesh()->Dimension();
1226 const int vdim = fes.GetVDim();
1227 const int NE = fes.GetNE();
1228 const int D1D = maps->ndof;
1229 const int Q1D = maps->nqpt;
1230 const int id = (vdim<<8) | (D1D<<4) | Q1D;
1231 const double *B = maps->B.Read();
1232 const double *G = maps->G.Read();
1233 const double *J = geom->J.Read();
1234 const double *X = e_vec.Read();
1235 double *Y = q_der.Write();
1240 case 0x134:
return D2QPhysGrad2D<1,3,4,8>(NE, B, G, J, X, Y);
1241 case 0x146:
return D2QPhysGrad2D<1,4,6,4>(NE, B, G, J, X, Y);
1242 case 0x158:
return D2QPhysGrad2D<1,5,8,2>(NE, B, G, J, X, Y);
1243 case 0x234:
return D2QPhysGrad2D<2,3,4,8>(NE, B, G, J, X, Y);
1244 case 0x246:
return D2QPhysGrad2D<2,4,6,4>(NE, B, G, J, X, Y);
1245 case 0x258:
return D2QPhysGrad2D<2,5,8,2>(NE, B, G, J, X, Y);
1249 <<
" are not supported!");
1250 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"Quadrature rules with more than "
1251 <<
MAX_Q1D <<
" 1D points are not supported!");
1252 D2QPhysGrad2D(NE, B, G, J, X, Y, vdim, D1D, Q1D);
1261 case 0x134:
return D2QPhysGrad3D<1,3,4>(NE, B, G, J, X, Y);
1262 case 0x146:
return D2QPhysGrad3D<1,4,6>(NE, B, G, J, X, Y);
1263 case 0x158:
return D2QPhysGrad3D<1,5,8>(NE, B, G, J, X, Y);
1264 case 0x334:
return D2QPhysGrad3D<3,3,4>(NE, B, G, J, X, Y);
1265 case 0x346:
return D2QPhysGrad3D<3,4,6>(NE, B, G, J, X, Y);
1266 case 0x358:
return D2QPhysGrad3D<3,5,8>(NE, B, G, J, X, Y);
1269 constexpr
int MD = 8;
1270 constexpr
int MQ = 8;
1271 MFEM_VERIFY(D1D <= MD,
"Orders higher than " << MD-1
1272 <<
" are not supported!");
1273 MFEM_VERIFY(Q1D <= MQ,
"Quadrature rules with more than " << MQ
1274 <<
" 1D points are not supported!");
1275 D2QPhysGrad3D<0,0,0,MD,MQ>(NE, B, G, J, X, Y, vdim, D1D, Q1D);
1280 mfem::out <<
"Unknown kernel 0x" << std::hex <<
id << std::endl;
1281 MFEM_ABORT(
"Unknown kernel");
1299 D2QGrad(*
fespace, &d2q, e_vec, q_der);
1307 MFEM_ABORT(
"evaluation of physical derivatives with 'byNODES' output"
1308 " layout is not implemented yet!");
1314 if (mesh->
GetNE() == 0) {
return; }
1321 D2QPhysGrad(*
fespace, geom, &d2q, e_vec, q_der);
Abstract class for 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
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 associated with i'th element.
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.