12 #include "../general/forall.hpp"
73 static void PAGradientSetup2D(
const int Q1D,
75 const Array<double> &w,
80 const int NQ = Q1D*Q1D;
82 auto J =
Reshape(j.Read(), NQ, 2, 2, NE);
83 auto y =
Reshape(op.Write(), NQ, 2, 2, NE);
87 for (
int q = 0; q < NQ; ++q)
89 const double J11 = J(q,0,0,e);
90 const double J12 = J(q,0,1,e);
91 const double J21 = J(q,1,0,e);
92 const double J22 = J(q,1,1,e);
94 y(q,0,0,e) = W[q] * COEFF * J22;
95 y(q,0,1,e) = W[q] * COEFF * -J12;
96 y(q,1,0,e) = W[q] * COEFF * -J21;
97 y(q,1,1,e) = W[q] * COEFF * J11;
103 static void PAGradientSetup3D(
const int Q1D,
105 const Array<double> &w,
110 const int NQ = Q1D*Q1D*Q1D;
112 auto J =
Reshape(j.Read(), NQ, 3, 3, NE);
113 auto y =
Reshape(op.Write(), NQ, 3, 3, NE);
116 for (
int q = 0; q < NQ; ++q)
118 const double J11 = J(q,0,0,e);
119 const double J21 = J(q,1,0,e);
120 const double J31 = J(q,2,0,e);
121 const double J12 = J(q,0,1,e);
122 const double J22 = J(q,1,1,e);
123 const double J32 = J(q,2,1,e);
124 const double J13 = J(q,0,2,e);
125 const double J23 = J(q,1,2,e);
126 const double J33 = J(q,2,2,e);
127 const double cw = W[q] * COEFF;
129 const double A11 = (J22 * J33) - (J23 * J32);
130 const double A12 = (J32 * J13) - (J12 * J33);
131 const double A13 = (J12 * J23) - (J22 * J13);
132 const double A21 = (J31 * J23) - (J21 * J33);
133 const double A22 = (J11 * J33) - (J13 * J31);
134 const double A23 = (J21 * J13) - (J11 * J23);
135 const double A31 = (J21 * J32) - (J31 * J22);
136 const double A32 = (J31 * J12) - (J11 * J32);
137 const double A33 = (J11 * J22) - (J12 * J21);
139 y(q,0,0,e) = cw * A11;
140 y(q,0,1,e) = cw * A12;
141 y(q,0,2,e) = cw * A13;
142 y(q,1,0,e) = cw * A21;
143 y(q,1,1,e) = cw * A22;
144 y(q,1,2,e) = cw * A23;
145 y(q,2,0,e) = cw * A31;
146 y(q,2,1,e) = cw * A32;
147 y(q,2,2,e) = cw * A33;
152 static void PAGradientSetup(
const int dim,
157 const Array<double> &W,
162 if (dim == 1) { MFEM_ABORT(
"dim==1 not supported in PAGradientSetup"); }
165 PAGradientSetup2D(Q1D, NE, W, J, COEFF, op);
169 PAGradientSetup3D(Q1D, NE, W, J, COEFF, op);
177 MFEM_ASSERT(trial_fes.
GetOrdering() == Ordering::byNODES,
178 "PA Only supports Ordering::byNODES!");
183 const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
185 const int dims = trial_fe.
GetDim();
186 const int dimsToStore = dims * dims;
188 dim = mesh->Dimension();
189 ne = trial_fes.
GetNE();
190 geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
191 trial_maps = &trial_fe.
GetDofToQuad(*ir, DofToQuad::TENSOR);
192 trial_dofs1D = trial_maps->
ndof;
193 quad1D = trial_maps->nqpt;
194 test_maps = &test_fe.
GetDofToQuad(*ir, DofToQuad::TENSOR);
195 test_dofs1D = test_maps->
ndof;
196 MFEM_ASSERT(quad1D == test_maps->nqpt,
197 "PA requires test and trial space to have same number of quadrature points!");
203 MFEM_VERIFY(cQ != NULL,
"only ConstantCoefficient is supported!");
206 PAGradientSetup(dim, trial_dofs1D, test_dofs1D, quad1D,
211 template<
int T_TR_D1D = 0,
int T_TE_D1D = 0,
int T_Q1D = 0>
212 static void PAGradientApply2D(
const int NE,
219 const int tr_d1d = 0,
220 const int te_d1d = 0,
223 const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
224 const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
225 const int Q1D = T_Q1D ? T_Q1D : q1d;
226 MFEM_VERIFY(TR_D1D <=
MAX_D1D,
"");
227 MFEM_VERIFY(TE_D1D <=
MAX_D1D,
"");
228 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
237 const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
238 const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
239 const int Q1D = T_Q1D ? T_Q1D : q1d;
242 constexpr
int max_TE_D1D = T_TE_D1D ? T_TE_D1D :
MAX_D1D;
243 constexpr
int max_Q1D = T_Q1D ? T_Q1D :
MAX_Q1D;
245 double grad[max_Q1D][max_Q1D][VDIM];
246 for (
int qy = 0; qy < Q1D; ++qy)
248 for (
int qx = 0; qx < Q1D; ++qx)
250 grad[qy][qx][0] = 0.0;
251 grad[qy][qx][1] = 0.0;
254 for (
int dy = 0; dy < TR_D1D; ++dy)
256 double gradX[max_Q1D][VDIM];
257 for (
int qx = 0; qx < Q1D; ++qx)
262 for (
int dx = 0; dx < TR_D1D; ++dx)
264 const double s = x(dx,dy,e);
265 for (
int qx = 0; qx < Q1D; ++qx)
267 gradX[qx][0] += s * G(qx,dx);
268 gradX[qx][1] += s * B(qx,dx);
271 for (
int qy = 0; qy < Q1D; ++qy)
273 const double wy = B(qy,dy);
274 const double wDy = G(qy,dy);
275 for (
int qx = 0; qx < Q1D; ++qx)
277 grad[qy][qx][0] += gradX[qx][0] * wy;
278 grad[qy][qx][1] += gradX[qx][1] * wDy;
283 for (
int qy = 0; qy < Q1D; ++qy)
285 for (
int qx = 0; qx < Q1D; ++qx)
287 const int q = qx + qy * Q1D;
288 const double gradX = grad[qy][qx][0];
289 const double gradY = grad[qy][qx][1];
291 grad[qy][qx][0] = gradX*op(q,0,0,e) + gradY*op(q,1,0,e);
292 grad[qy][qx][1] = gradX*op(q,0,1,e) + gradY*op(q,1,1,e);
296 for (
int qy = 0; qy < Q1D; ++qy)
298 double opX[max_TE_D1D][VDIM];
299 for (
int dx = 0; dx < TE_D1D; ++dx)
303 for (
int qx = 0; qx < Q1D; ++qx)
305 opX[dx][0] += Bt(dx,qx)*grad[qy][qx][0];
306 opX[dx][1] += Bt(dx,qx)*grad[qy][qx][1];
309 for (
int dy = 0; dy < TE_D1D; ++dy)
311 for (
int dx = 0; dx < TE_D1D; ++dx)
313 y(dx,dy,0,e) += Bt(dy,qy)*opX[dx][0];
314 y(dx,dy,1,e) += Bt(dy,qy)*opX[dx][1];
324 template<
int T_TR_D1D = 0,
int T_TE_D1D = 0,
int T_Q1D = 0>
325 static void PAGradientApplyTranspose2D(
const int NE,
326 const Array<double> &bt,
327 const Array<double> >,
328 const Array<double> &b,
332 const int tr_d1d = 0,
333 const int te_d1d = 0,
337 MFEM_ASSERT(
false,
"GradientPAApplyTranspose 3D not implemented.");
341 template<const
int T_TR_D1D = 0, const
int T_TE_D1D = 0, const
int T_Q1D = 0>
342 static void PAGradientApply3D(
const int NE,
343 const Array<double> &b,
344 const Array<double> &g,
345 const Array<double> &bt,
353 const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
354 const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
355 const int Q1D = T_Q1D ? T_Q1D : q1d;
356 MFEM_VERIFY(TR_D1D <=
MAX_D1D,
"");
357 MFEM_VERIFY(TE_D1D <=
MAX_D1D,
"");
358 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
359 auto B =
Reshape(b.Read(), Q1D, TR_D1D);
360 auto G =
Reshape(g.Read(), Q1D, TR_D1D);
361 auto Bt =
Reshape(bt.Read(), TE_D1D, Q1D);
362 auto op =
Reshape(_op.Read(), Q1D*Q1D*Q1D, 3,3, NE);
363 auto x =
Reshape(_x.Read(), TR_D1D, TR_D1D, TR_D1D, NE);
364 auto y =
Reshape(_y.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, 3, NE);
367 const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
368 const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
369 const int Q1D = T_Q1D ? T_Q1D : q1d;
372 constexpr
int max_TE_D1D = T_TE_D1D ? T_TE_D1D :
MAX_D1D;
373 constexpr
int max_Q1D = T_Q1D ? T_Q1D :
MAX_Q1D;
375 double grad[max_Q1D][max_Q1D][max_Q1D][VDIM];
376 for (
int qz = 0; qz < Q1D; ++qz)
378 for (
int qy = 0; qy < Q1D; ++qy)
380 for (
int qx = 0; qx < Q1D; ++qx)
382 grad[qz][qy][qx][0] = 0.0;
383 grad[qz][qy][qx][1] = 0.0;
384 grad[qz][qy][qx][2] = 0.0;
388 for (
int dz = 0; dz < TR_D1D; ++dz)
390 double gradXY[max_Q1D][max_Q1D][3];
391 for (
int qy = 0; qy < Q1D; ++qy)
393 for (
int qx = 0; qx < Q1D; ++qx)
395 gradXY[qy][qx][0] = 0.0;
396 gradXY[qy][qx][1] = 0.0;
397 gradXY[qy][qx][2] = 0.0;
400 for (
int dy = 0; dy < TR_D1D; ++dy)
402 double gradX[max_Q1D][2];
403 for (
int qx = 0; qx < Q1D; ++qx)
408 for (
int dx = 0; dx < TR_D1D; ++dx)
410 const double s = x(dx,dy,dz,e);
411 for (
int qx = 0; qx < Q1D; ++qx)
413 gradX[qx][0] += s * B(qx,dx);
414 gradX[qx][1] += s * G(qx,dx);
417 for (
int qy = 0; qy < Q1D; ++qy)
419 const double wy = B(qy,dy);
420 const double wDy = G(qy,dy);
421 for (
int qx = 0; qx < Q1D; ++qx)
423 const double wx = gradX[qx][0];
424 const double wDx = gradX[qx][1];
425 gradXY[qy][qx][0] += wDx * wy;
426 gradXY[qy][qx][1] += wx * wDy;
427 gradXY[qy][qx][2] += wx * wy;
431 for (
int qz = 0; qz < Q1D; ++qz)
433 const double wz = B(qz,dz);
434 const double wDz = G(qz,dz);
435 for (
int qy = 0; qy < Q1D; ++qy)
437 for (
int qx = 0; qx < Q1D; ++qx)
439 grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
440 grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
441 grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
447 for (
int qz = 0; qz < Q1D; ++qz)
449 for (
int qy = 0; qy < Q1D; ++qy)
451 for (
int qx = 0; qx < Q1D; ++qx)
453 const int q = qx + (qy + qz * Q1D) * Q1D;
454 const double gradX = grad[qz][qy][qx][0];
455 const double gradY = grad[qz][qy][qx][1];
456 const double gradZ = grad[qz][qy][qx][2];
458 grad[qz][qy][qx][0] = gradX*op(q,0,0,e) + gradY*op(q,1,0,e) + gradZ*op(q,2,0,e);
459 grad[qz][qy][qx][1] = gradX*op(q,0,1,e) + gradY*op(q,1,1,e) + gradZ*op(q,2,1,e);
460 grad[qz][qy][qx][2] = gradX*op(q,0,2,e) + gradY*op(q,1,2,e) + gradZ*op(q,2,2,e);
465 for (
int qz = 0; qz < Q1D; ++qz)
467 double opXY[max_TE_D1D][max_TE_D1D][VDIM];
468 for (
int dy = 0; dy < TE_D1D; ++dy)
470 for (
int dx = 0; dx < TE_D1D; ++dx)
472 opXY[dy][dx][0] = 0.0;
473 opXY[dy][dx][1] = 0.0;
474 opXY[dy][dx][2] = 0.0;
477 for (
int qy = 0; qy < Q1D; ++qy)
479 double opX[max_TE_D1D][VDIM];
480 for (
int dx = 0; dx < TE_D1D; ++dx)
485 for (
int qx = 0; qx < Q1D; ++qx)
487 opX[dx][0] += Bt(dx,qx)*grad[qz][qy][qx][0];
488 opX[dx][1] += Bt(dx,qx)*grad[qz][qy][qx][1];
489 opX[dx][2] += Bt(dx,qx)*grad[qz][qy][qx][2];
492 for (
int dy = 0; dy < TE_D1D; ++dy)
494 for (
int dx = 0; dx < TE_D1D; ++dx)
496 opXY[dy][dx][0] += Bt(dy,qy)*opX[dx][0];
497 opXY[dy][dx][1] += Bt(dy,qy)*opX[dx][1];
498 opXY[dy][dx][2] += Bt(dy,qy)*opX[dx][2];
502 for (
int dz = 0; dz < TE_D1D; ++dz)
504 for (
int dy = 0; dy < TE_D1D; ++dy)
506 for (
int dx = 0; dx < TE_D1D; ++dx)
508 y(dx,dy,dz,0,e) += Bt(dz,qz)*opXY[dy][dx][0];
509 y(dx,dy,dz,1,e) += Bt(dz,qz)*opXY[dy][dx][1];
510 y(dx,dy,dz,2,e) += Bt(dz,qz)*opXY[dy][dx][2];
520 template<const
int T_TR_D1D = 0, const
int T_TE_D1D = 0, const
int T_Q1D = 0>
521 static void PAGradientApplyTranspose3D(
const int NE,
522 const Array<double> &bt,
523 const Array<double> >,
524 const Array<double> &b,
532 MFEM_ASSERT(
false,
"Gradient PA Apply Transpose 3D not implemented.");
536 template<const
int T_TR_D1D = 0, const
int T_TE_D1D = 0, const
int T_Q1D = 0>
537 static void SmemPAGradientApply3D(
const int NE,
538 const Array<double> &b_,
539 const Array<double> &g_,
540 const Array<double> &bt_,
544 const int tr_d1d = 0,
545 const int te_d1d = 0,
548 const int TR_D1D = T_TR_D1D ? T_TR_D1D : tr_d1d;
549 const int TE_D1D = T_TE_D1D ? T_TE_D1D : te_d1d;
550 const int Q1D = T_Q1D ? T_Q1D : q1d;
552 MFEM_VERIFY(TR_D1D <=
MAX_D1D,
"");
553 MFEM_VERIFY(TE_D1D <=
MAX_D1D,
"");
554 MFEM_VERIFY(TR_D1D <= Q1D,
"");
555 MFEM_VERIFY(TE_D1D <= Q1D,
"");
556 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
558 auto b =
Reshape(b_.Read(), Q1D, TR_D1D);
559 auto g =
Reshape(g_.Read(), Q1D, TR_D1D);
560 auto bt =
Reshape(bt_.Read(), TE_D1D, Q1D);
561 auto D =
Reshape(d_.Read(), Q1D*Q1D*Q1D, 3, 3, NE);
562 auto x =
Reshape(x_.Read(), TR_D1D, TR_D1D, TR_D1D, NE);
563 auto y =
Reshape(y_.ReadWrite(), TE_D1D, TE_D1D, TE_D1D, 3, NE);
565 MFEM_FORALL_3D(e, NE, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D, (Q1D>8)?8:Q1D,
567 const int tidz = MFEM_THREAD_ID(z);
568 const int D1DR = T_TR_D1D ? T_TR_D1D : tr_d1d;
569 const int D1DE = T_TE_D1D ? T_TE_D1D : te_d1d;
570 const int Q1D = T_Q1D ? T_Q1D : q1d;
571 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
572 constexpr
int MD1R = T_TR_D1D ? T_TR_D1D :
MAX_D1D;
573 constexpr
int MD1E = T_TE_D1D ? T_TE_D1D :
MAX_D1D;
574 constexpr
int MD1 = MD1E > MD1R ? MD1E : MD1R;
575 constexpr
int MDQ = MQ1 > MD1 ? MQ1 : MD1;
576 MFEM_SHARED
double sBG[2][MQ1*MD1];
577 double (*B)[MD1] = (double (*)[MD1]) (sBG+0);
578 double (*G)[MD1] = (double (*)[MD1]) (sBG+1);
579 double (*Bt)[MQ1] = (double (*)[MQ1]) (sBG+0);
580 MFEM_SHARED
double sm0[3][MDQ*MDQ*MDQ];
581 MFEM_SHARED
double sm1[3][MDQ*MDQ*MDQ];
582 double (*X)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
583 double (*DDQ0)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+0);
584 double (*DDQ1)[MD1][MQ1] = (double (*)[MD1][MQ1]) (sm0+1);
586 double (*DQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+0);
587 double (*DQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+1);
588 double (*DQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm1+2);
590 double (*QQQ0)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm0+0);
591 double (*QQQ1)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm0+1);
592 double (*QQQ2)[MQ1][MQ1] = (double (*)[MQ1][MQ1]) (sm0+2);
594 double (*QQD0)[MQ1][MD1] = (double (*)[MQ1][MD1]) (sm1+0);
595 double (*QQD1)[MQ1][MD1] = (double (*)[MQ1][MD1]) (sm1+1);
596 double (*QQD2)[MQ1][MD1] = (double (*)[MQ1][MD1]) (sm1+2);
598 double (*QDD0)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+0);
599 double (*QDD1)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+1);
600 double (*QDD2)[MD1][MD1] = (double (*)[MD1][MD1]) (sm0+2);
601 MFEM_FOREACH_THREAD(dz,z,D1DR)
603 MFEM_FOREACH_THREAD(dy,y,D1DR)
605 MFEM_FOREACH_THREAD(dx,x,D1DR)
607 X[dz][dy][dx] = x(dx,dy,dz,e);
613 MFEM_FOREACH_THREAD(d,y,D1DR)
615 MFEM_FOREACH_THREAD(q,x,Q1D)
623 MFEM_FOREACH_THREAD(dz,z,D1DR)
625 MFEM_FOREACH_THREAD(dy,y,D1DR)
627 MFEM_FOREACH_THREAD(qx,x,Q1D)
631 for (
int dx = 0; dx < D1DR; ++dx)
633 const double coord = X[dz][dy][dx];
634 u += coord * B[qx][dx];
635 v += coord * G[qx][dx];
637 DDQ0[dz][dy][qx] = u;
638 DDQ1[dz][dy][qx] = v;
643 MFEM_FOREACH_THREAD(dz,z,D1DR)
645 MFEM_FOREACH_THREAD(qy,y,Q1D)
647 MFEM_FOREACH_THREAD(qx,x,Q1D)
652 for (
int dy = 0; dy < D1DR; ++dy)
654 u += DDQ1[dz][dy][qx] * B[qy][dy];
655 v += DDQ0[dz][dy][qx] * G[qy][dy];
656 w += DDQ0[dz][dy][qx] * B[qy][dy];
658 DQQ0[dz][qy][qx] = u;
659 DQQ1[dz][qy][qx] = v;
660 DQQ2[dz][qy][qx] = w;
665 MFEM_FOREACH_THREAD(qz,z,Q1D)
667 MFEM_FOREACH_THREAD(qy,y,Q1D)
669 MFEM_FOREACH_THREAD(qx,x,Q1D)
674 for (
int dz = 0; dz < D1DR; ++dz)
676 u += DQQ0[dz][qy][qx] * B[qz][dz];
677 v += DQQ1[dz][qy][qx] * B[qz][dz];
678 w += DQQ2[dz][qy][qx] * G[qz][dz];
680 QQQ0[qz][qy][qx] = u;
681 QQQ1[qz][qy][qx] = v;
682 QQQ2[qz][qy][qx] = w;
687 MFEM_FOREACH_THREAD(qz,z,Q1D)
689 MFEM_FOREACH_THREAD(qy,y,Q1D)
691 MFEM_FOREACH_THREAD(qx,x,Q1D)
693 const int q = qx + (qy + qz * Q1D) * Q1D;
694 const double gX = QQQ0[qz][qy][qx];
695 const double gY = QQQ1[qz][qy][qx];
696 const double gZ = QQQ2[qz][qy][qx];
697 QQQ0[qz][qy][qx] = (D(q,0,0,e)*gX) + (D(q,1,0,e)*gY) + (D(q,2,0,e)*gZ);
698 QQQ1[qz][qy][qx] = (D(q,0,1,e)*gX) + (D(q,1,1,e)*gY) + (D(q,2,1,e)*gZ);
699 QQQ2[qz][qy][qx] = (D(q,0,2,e)*gX) + (D(q,1,2,e)*gY) + (D(q,2,2,e)*gZ);
706 MFEM_FOREACH_THREAD(d,y,D1DE)
708 MFEM_FOREACH_THREAD(q,x,Q1D)
715 MFEM_FOREACH_THREAD(qz,z,Q1D)
717 MFEM_FOREACH_THREAD(qy,y,Q1D)
719 MFEM_FOREACH_THREAD(dx,x,D1DE)
724 for (
int qx = 0; qx < Q1D; ++qx)
726 u += QQQ0[qz][qy][qx] * Bt[dx][qx];
727 v += QQQ1[qz][qy][qx] * Bt[dx][qx];
728 w += QQQ2[qz][qy][qx] * Bt[dx][qx];
730 QQD0[qz][qy][dx] = u;
731 QQD1[qz][qy][dx] = v;
732 QQD2[qz][qy][dx] = w;
737 MFEM_FOREACH_THREAD(qz,z,Q1D)
739 MFEM_FOREACH_THREAD(dy,y,D1DE)
741 MFEM_FOREACH_THREAD(dx,x,D1DE)
746 for (
int qy = 0; qy < Q1D; ++qy)
748 u += QQD0[qz][qy][dx] * Bt[dy][qy];
749 v += QQD1[qz][qy][dx] * Bt[dy][qy];
750 w += QQD2[qz][qy][dx] * Bt[dy][qy];
752 QDD0[qz][dy][dx] = u;
753 QDD1[qz][dy][dx] = v;
754 QDD2[qz][dy][dx] = w;
759 MFEM_FOREACH_THREAD(dz,z,D1DE)
761 MFEM_FOREACH_THREAD(dy,y,D1DE)
763 MFEM_FOREACH_THREAD(dx,x,D1DE)
768 for (
int qz = 0; qz < Q1D; ++qz)
770 u += QDD0[qz][dy][dx] * Bt[dz][qz];
771 v += QDD1[qz][dy][dx] * Bt[dz][qz];
772 w += QDD2[qz][dy][dx] * Bt[dz][qz];
774 y(dx,dy,dz,0,e) += u;
775 y(dx,dy,dz,1,e) += v;
776 y(dx,dy,dz,2,e) += w;
783 static void PAGradientApply(
const int dim,
788 const Array<double> &B,
789 const Array<double> &G,
790 const Array<double> &Bt,
794 bool transpose=
false)
799 return PAGradientApply2D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
803 return PAGradientApply3D(NE,B,G,Bt,op,x,y,TR_D1D,TE_D1D,Q1D);
805 MFEM_ABORT(
"Unknown kernel.");
811 PAGradientApply(dim, trial_dofs1D, test_dofs1D, quad1D, ne,
812 trial_maps->B, trial_maps->G, test_maps->Bt, pa_data, x, y,
817 void GradientIntegrator::AddMultTransposePA(
const Vector &x,
Vector &y)
const
819 MFEM_ABORT(
"PA Gradient AddMultTransposePA not implemented.");
int GetNPoints() const
Returns the number of the points in the integration rule.
Abstract class for all finite elements.
Ordering::Type GetOrdering() const
Return the ordering method.
int GetDim() const
Returns the reference space dimension for the finite element.
void trans(const Vector &u, Vector &x)
Class for an integration rule - an Array of IntegrationPoint.
A coefficient that is constant across space and time.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
const Array< double > & GetWeights() const
Return the quadrature weights in a contiguous array.
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.
double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Mesh * GetMesh() const
Returns the mesh.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
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...
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...