12 #include "../general/forall.hpp"
33 constexpr
static int VDIM = 2;
41 auto op =
Reshape(pa_data.
Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
49 for (
int qy = 0; qy < Q1D; ++qy)
51 for (
int qx = 0; qx < Q1D; ++qx)
53 for (
int c = 0; c < VDIM; ++c)
55 mass[qy][qx][c] = 0.0;
62 for (
int c = 0; c < VDIM; ++c)
64 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
65 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
67 for (
int dy = 0; dy < D1Dy; ++dy)
70 for (
int qx = 0; qx < Q1D; ++qx)
75 for (
int dx = 0; dx < D1Dx; ++dx)
77 const double t = X(dx + (dy * D1Dx) + osc, e);
78 for (
int qx = 0; qx < Q1D; ++qx)
80 massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
84 for (
int qy = 0; qy < Q1D; ++qy)
86 const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
87 for (
int qx = 0; qx < Q1D; ++qx)
89 mass[qy][qx][c] += massX[qx] * wy;
98 for (
int qy = 0; qy < Q1D; ++qy)
100 for (
int qx = 0; qx < Q1D; ++qx)
102 const double O11 = op(qx,qy,0,e);
103 const double O21 = op(qx,qy,1,e);
104 const double O12 = symmetric ? O21 : op(qx,qy,2,e);
105 const double O22 = symmetric ? op(qx,qy,2,e) : op(qx,qy,3,e);
106 const double massX = mass[qy][qx][0];
107 const double massY = mass[qy][qx][1];
108 mass[qy][qx][0] = (O11*massX)+(O12*massY);
109 mass[qy][qx][1] = (O21*massX)+(O22*massY);
113 for (
int qy = 0; qy < Q1D; ++qy)
117 for (
int c = 0; c < VDIM; ++c)
119 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
120 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
123 for (
int dx = 0; dx < D1Dx; ++dx)
127 for (
int qx = 0; qx < Q1D; ++qx)
129 for (
int dx = 0; dx < D1Dx; ++dx)
131 massX[dx] += mass[qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
135 for (
int dy = 0; dy < D1Dy; ++dy)
137 const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
139 for (
int dx = 0; dx < D1Dx; ++dx)
141 Y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
154 const bool symmetric,
160 constexpr
static int VDIM = 2;
165 auto op =
Reshape(pa_data.
Read(), Q1D, Q1D, symmetric ? 3 : 4, NE);
172 for (
int c = 0; c < VDIM; ++c)
174 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
175 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
179 for (
int dy = 0; dy < D1Dy; ++dy)
181 for (
int qx = 0; qx < Q1D; ++qx)
184 for (
int qy = 0; qy < Q1D; ++qy)
186 const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
188 mass[qx] += wy * wy * ((c == 0) ? op(qx,qy,0,e) :
189 op(qx,qy,symmetric ? 2 : 3, e));
193 for (
int dx = 0; dx < D1Dx; ++dx)
195 for (
int qx = 0; qx < Q1D; ++qx)
197 const double wx = ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
198 D(dx + (dy * D1Dx) + osc, e) += mass[qx] * wx * wx;
211 const bool symmetric,
220 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
221 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
222 constexpr static int VDIM = 3;
224 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
225 auto Bc = Reshape(bc.Read(), Q1D, D1D);
226 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
227 auto D = Reshape(diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
233 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
235 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
236 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
237 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
239 const int opc = (c == 0) ? 0 : ((c == 1) ? (symmetric ? 3 : 4) :
240 (symmetric ? 5 : 8));
242 double mass[MAX_Q1D];
244 for (int dz = 0; dz < D1Dz; ++dz)
246 for (int dy = 0; dy < D1Dy; ++dy)
248 for (int qx = 0; qx < Q1D; ++qx)
251 for (int qy = 0; qy < Q1D; ++qy)
253 const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
255 for (int qz = 0; qz < Q1D; ++qz)
257 const double wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
259 mass[qx] += wy * wy * wz * wz * op(qx,qy,qz,opc,e);
264 for (int dx = 0; dx < D1Dx; ++dx)
266 for (int qx = 0; qx < Q1D; ++qx)
268 const double wx = ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
269 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += mass[qx] * wx * wx;
275 osc += D1Dx * D1Dy * D1Dz;
277 }); // end of element loop
280 template<int T_D1D, int T_Q1D>
281 void SmemPAHcurlMassAssembleDiagonal3D(const int D1D,
284 const bool symmetric,
285 const Array<double> &bo,
286 const Array<double> &bc,
287 const Vector &pa_data,
290 MFEM_VERIFY(D1D <= HCURL_MAX_D1D, "Error: D1D > MAX_D1D
");
291 MFEM_VERIFY(Q1D <= HCURL_MAX_Q1D, "Error: Q1D > MAX_Q1D
");
293 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
294 auto Bc = Reshape(bc.Read(), Q1D, D1D);
295 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
296 auto D = Reshape(diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
298 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
300 constexpr int VDIM = 3;
301 constexpr int tD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
302 constexpr int tQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
304 MFEM_SHARED double sBo[tQ1D][tD1D];
305 MFEM_SHARED double sBc[tQ1D][tD1D];
308 MFEM_SHARED double sop[3][tQ1D][tQ1D];
310 MFEM_FOREACH_THREAD(qx,x,Q1D)
312 MFEM_FOREACH_THREAD(qy,y,Q1D)
314 MFEM_FOREACH_THREAD(qz,z,Q1D)
316 op3[0] = op(qx,qy,qz,0,e);
317 op3[1] = op(qx,qy,qz,symmetric ? 3 : 4,e);
318 op3[2] = op(qx,qy,qz,symmetric ? 5 : 8,e);
323 const int tidx = MFEM_THREAD_ID(x);
324 const int tidy = MFEM_THREAD_ID(y);
325 const int tidz = MFEM_THREAD_ID(z);
329 MFEM_FOREACH_THREAD(d,y,D1D)
331 MFEM_FOREACH_THREAD(q,x,Q1D)
344 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
346 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
347 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
348 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
352 for (int qz=0; qz < Q1D; ++qz)
356 for (int i=0; i<3; ++i)
358 sop[i][tidx][tidy] = op3[i];
364 MFEM_FOREACH_THREAD(dz,z,D1Dz)
366 const double wz = ((c == 2) ? sBo[qz][dz] : sBc[qz][dz]);
368 MFEM_FOREACH_THREAD(dy,y,D1Dy)
370 MFEM_FOREACH_THREAD(dx,x,D1Dx)
372 for (int qy = 0; qy < Q1D; ++qy)
374 const double wy = ((c == 1) ? sBo[qy][dy] : sBc[qy][dy]);
376 for (int qx = 0; qx < Q1D; ++qx)
378 const double wx = ((c == 0) ? sBo[qx][dx] : sBc[qx][dx]);
379 dxyz += sop[c][qx][qy] * wx * wx * wy * wy * wz * wz;
389 MFEM_FOREACH_THREAD(dz,z,D1Dz)
391 MFEM_FOREACH_THREAD(dy,y,D1Dy)
393 MFEM_FOREACH_THREAD(dx,x,D1Dx)
395 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += dxyz;
400 osc += D1Dx * D1Dy * D1Dz;
402 }); // end of element loop
405 void PAHcurlMassApply3D(const int D1D,
408 const bool symmetric,
409 const Array<double> &bo,
410 const Array<double> &bc,
411 const Array<double> &bot,
412 const Array<double> &bct,
413 const Vector &pa_data,
417 constexpr static int MAX_D1D = HCURL_MAX_D1D;
418 constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
420 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
421 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
422 constexpr static int VDIM = 3;
424 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
425 auto Bc = Reshape(bc.Read(), Q1D, D1D);
426 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
427 auto Bct = Reshape(bct.Read(), D1D, Q1D);
428 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
429 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
430 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
434 double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
436 for (int qz = 0; qz < Q1D; ++qz)
438 for (int qy = 0; qy < Q1D; ++qy)
440 for (int qx = 0; qx < Q1D; ++qx)
442 for (int c = 0; c < VDIM; ++c)
444 mass[qz][qy][qx][c] = 0.0;
452 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
454 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
455 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
456 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
458 for (int dz = 0; dz < D1Dz; ++dz)
460 double massXY[MAX_Q1D][MAX_Q1D];
461 for (int qy = 0; qy < Q1D; ++qy)
463 for (int qx = 0; qx < Q1D; ++qx)
465 massXY[qy][qx] = 0.0;
469 for (int dy = 0; dy < D1Dy; ++dy)
471 double massX[MAX_Q1D];
472 for (int qx = 0; qx < Q1D; ++qx)
477 for (int dx = 0; dx < D1Dx; ++dx)
479 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
480 for (int qx = 0; qx < Q1D; ++qx)
482 massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
486 for (int qy = 0; qy < Q1D; ++qy)
488 const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
489 for (int qx = 0; qx < Q1D; ++qx)
491 const double wx = massX[qx];
492 massXY[qy][qx] += wx * wy;
497 for (int qz = 0; qz < Q1D; ++qz)
499 const double wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
500 for (int qy = 0; qy < Q1D; ++qy)
502 for (int qx = 0; qx < Q1D; ++qx)
504 mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
510 osc += D1Dx * D1Dy * D1Dz;
511 } // loop (c) over components
514 for (int qz = 0; qz < Q1D; ++qz)
516 for (int qy = 0; qy < Q1D; ++qy)
518 for (int qx = 0; qx < Q1D; ++qx)
520 const double O11 = op(qx,qy,qz,0,e);
521 const double O12 = op(qx,qy,qz,1,e);
522 const double O13 = op(qx,qy,qz,2,e);
523 const double O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
524 const double O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
525 const double O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
526 const double O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
527 const double O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
528 const double O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
529 const double massX = mass[qz][qy][qx][0];
530 const double massY = mass[qz][qy][qx][1];
531 const double massZ = mass[qz][qy][qx][2];
532 mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
533 mass[qz][qy][qx][1] = (O21*massX)+(O22*massY)+(O23*massZ);
534 mass[qz][qy][qx][2] = (O31*massX)+(O32*massY)+(O33*massZ);
539 for (int qz = 0; qz < Q1D; ++qz)
541 double massXY[MAX_D1D][MAX_D1D];
545 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
547 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
548 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
549 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
551 for (int dy = 0; dy < D1Dy; ++dy)
553 for (int dx = 0; dx < D1Dx; ++dx)
555 massXY[dy][dx] = 0.0;
558 for (int qy = 0; qy < Q1D; ++qy)
560 double massX[MAX_D1D];
561 for (int dx = 0; dx < D1Dx; ++dx)
565 for (int qx = 0; qx < Q1D; ++qx)
567 for (int dx = 0; dx < D1Dx; ++dx)
569 massX[dx] += mass[qz][qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
572 for (int dy = 0; dy < D1Dy; ++dy)
574 const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
575 for (int dx = 0; dx < D1Dx; ++dx)
577 massXY[dy][dx] += massX[dx] * wy;
582 for (int dz = 0; dz < D1Dz; ++dz)
584 const double wz = (c == 2) ? Bot(dz,qz) : Bct(dz,qz);
585 for (int dy = 0; dy < D1Dy; ++dy)
587 for (int dx = 0; dx < D1Dx; ++dx)
589 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += massXY[dy][dx] * wz;
594 osc += D1Dx * D1Dy * D1Dz;
597 }); // end of element loop
600 template<int T_D1D, int T_Q1D>
601 void SmemPAHcurlMassApply3D(const int D1D,
604 const bool symmetric,
605 const Array<double> &bo,
606 const Array<double> &bc,
607 const Array<double> &bot,
608 const Array<double> &bct,
609 const Vector &pa_data,
613 MFEM_VERIFY(D1D <= HCURL_MAX_D1D, "Error: D1D > MAX_D1D
");
614 MFEM_VERIFY(Q1D <= HCURL_MAX_Q1D, "Error: Q1D > MAX_Q1D
");
616 const int dataSize = symmetric ? 6 : 9;
618 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
619 auto Bc = Reshape(bc.Read(), Q1D, D1D);
620 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, dataSize, NE);
621 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
622 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
624 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
626 constexpr int VDIM = 3;
627 constexpr int tD1D = T_D1D ? T_D1D : HCURL_MAX_D1D;
628 constexpr int tQ1D = T_Q1D ? T_Q1D : HCURL_MAX_Q1D;
630 MFEM_SHARED double sBo[tQ1D][tD1D];
631 MFEM_SHARED double sBc[tQ1D][tD1D];
634 MFEM_SHARED double sop[9*tQ1D*tQ1D];
635 MFEM_SHARED double mass[tQ1D][tQ1D][3];
637 MFEM_SHARED double sX[tD1D][tD1D][tD1D];
639 MFEM_FOREACH_THREAD(qx,x,Q1D)
641 MFEM_FOREACH_THREAD(qy,y,Q1D)
643 MFEM_FOREACH_THREAD(qz,z,Q1D)
645 for (int i=0; i<dataSize; ++i)
647 op9[i] = op(qx,qy,qz,i,e);
653 const int tidx = MFEM_THREAD_ID(x);
654 const int tidy = MFEM_THREAD_ID(y);
655 const int tidz = MFEM_THREAD_ID(z);
659 MFEM_FOREACH_THREAD(d,y,D1D)
661 MFEM_FOREACH_THREAD(q,x,Q1D)
673 for (int qz=0; qz < Q1D; ++qz)
676 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
678 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
679 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
680 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
682 MFEM_FOREACH_THREAD(dz,z,D1Dz)
684 MFEM_FOREACH_THREAD(dy,y,D1Dy)
686 MFEM_FOREACH_THREAD(dx,x,D1Dx)
688 sX[dz][dy][dx] = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
696 for (int i=0; i<dataSize; ++i)
698 sop[i + (dataSize*tidx) + (dataSize*Q1D*tidy)] = op9[i];
701 MFEM_FOREACH_THREAD(qy,y,Q1D)
703 MFEM_FOREACH_THREAD(qx,x,Q1D)
707 for (int dz = 0; dz < D1Dz; ++dz)
709 const double wz = (c == 2) ? sBo[qz][dz] : sBc[qz][dz];
710 for (int dy = 0; dy < D1Dy; ++dy)
712 const double wy = (c == 1) ? sBo[qy][dy] : sBc[qy][dy];
713 for (int dx = 0; dx < D1Dx; ++dx)
715 const double t = sX[dz][dy][dx];
716 const double wx = (c == 0) ? sBo[qx][dx] : sBc[qx][dx];
717 u += t * wx * wy * wz;
727 osc += D1Dx * D1Dy * D1Dz;
731 MFEM_SYNC_THREAD; // Sync mass[qy][qx][d] and sop
734 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
736 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
737 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
738 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
742 MFEM_FOREACH_THREAD(dz,z,D1Dz)
744 const double wz = (c == 2) ? sBo[qz][dz] : sBc[qz][dz];
746 MFEM_FOREACH_THREAD(dy,y,D1Dy)
748 MFEM_FOREACH_THREAD(dx,x,D1Dx)
750 for (int qy = 0; qy < Q1D; ++qy)
752 const double wy = (c == 1) ? sBo[qy][dy] : sBc[qy][dy];
753 for (int qx = 0; qx < Q1D; ++qx)
755 const int os = (dataSize*qx) + (dataSize*Q1D*qy);
756 const int id1 = os + ((c == 0) ? 0 : ((c == 1) ? (symmetric ? 1 : 3) :
757 (symmetric ? 2 : 6))); // O11, O21, O31
758 const int id2 = os + ((c == 0) ? 1 : ((c == 1) ? (symmetric ? 3 : 4) :
759 (symmetric ? 4 : 7))); // O12, O22, O32
760 const int id3 = os + ((c == 0) ? 2 : ((c == 1) ? (symmetric ? 4 : 5) :
761 (symmetric ? 5 : 8))); // O13, O23, O33
763 const double m_c = (sop[id1] * mass[qy][qx][0]) + (sop[id2] * mass[qy][qx][1]) +
764 (sop[id3] * mass[qy][qx][2]);
766 const double wx = (c == 0) ? sBo[qx][dx] : sBc[qx][dx];
767 dxyz += m_c * wx * wy * wz;
776 MFEM_FOREACH_THREAD(dz,z,D1Dz)
778 MFEM_FOREACH_THREAD(dy,y,D1Dy)
780 MFEM_FOREACH_THREAD(dx,x,D1Dx)
782 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += dxyz;
787 osc += D1Dx * D1Dy * D1Dz;
790 }); // end of element loop
793 // PA H(curl) curl-curl assemble 2D kernel
794 static void PACurlCurlSetup2D(const int Q1D,
796 const Array<double> &w,
801 const int NQ = Q1D*Q1D;
803 auto J = Reshape(j.Read(), NQ, 2, 2, NE);
804 auto C = Reshape(coeff.Read(), NQ, NE);
805 auto y = Reshape(op.Write(), NQ, NE);
808 for (int q = 0; q < NQ; ++q)
810 const double J11 = J(q,0,0,e);
811 const double J21 = J(q,1,0,e);
812 const double J12 = J(q,0,1,e);
813 const double J22 = J(q,1,1,e);
814 const double detJ = (J11*J22)-(J21*J12);
815 y(q,e) = W[q] * C(q,e) / detJ;
820 // PA H(curl) curl-curl assemble 3D kernel
821 static void PACurlCurlSetup3D(const int Q1D,
824 const Array<double> &w,
829 const int NQ = Q1D*Q1D*Q1D;
830 const bool symmetric = (coeffDim != 9);
832 auto J = Reshape(j.Read(), NQ, 3, 3, NE);
833 auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
834 auto y = Reshape(op.Write(), NQ, symmetric ? 6 : 9, NE);
838 for (int q = 0; q < NQ; ++q)
840 const double J11 = J(q,0,0,e);
841 const double J21 = J(q,1,0,e);
842 const double J31 = J(q,2,0,e);
843 const double J12 = J(q,0,1,e);
844 const double J22 = J(q,1,1,e);
845 const double J32 = J(q,2,1,e);
846 const double J13 = J(q,0,2,e);
847 const double J23 = J(q,1,2,e);
848 const double J33 = J(q,2,2,e);
849 const double detJ = J11 * (J22 * J33 - J32 * J23) -
850 /* */ J21 * (J12 * J33 - J32 * J13) +
851 /* */ J31 * (J12 * J23 - J22 * J13);
853 const double c_detJ = W[q] / detJ;
855 if (coeffDim == 6 || coeffDim == 9) // Matrix coefficient version
857 // Set y to the 6 or 9 entries of J^T M J / det
858 const double M11 = C(0, q, e);
859 const double M12 = C(1, q, e);
860 const double M13 = C(2, q, e);
861 const double M21 = (!symmetric) ? C(3, q, e) : M12;
862 const double M22 = (!symmetric) ? C(4, q, e) : C(3, q, e);
863 const double M23 = (!symmetric) ? C(5, q, e) : C(4, q, e);
864 const double M31 = (!symmetric) ? C(6, q, e) : M13;
865 const double M32 = (!symmetric) ? C(7, q, e) : M23;
866 const double M33 = (!symmetric) ? C(8, q, e) : C(5, q, e);
868 // First compute R = MJ
869 const double R11 = M11*J11 + M12*J21 + M13*J31;
870 const double R12 = M11*J12 + M12*J22 + M13*J32;
871 const double R13 = M11*J13 + M12*J23 + M13*J33;
872 const double R21 = M21*J11 + M22*J21 + M23*J31;
873 const double R22 = M21*J12 + M22*J22 + M23*J32;
874 const double R23 = M21*J13 + M22*J23 + M23*J33;
875 const double R31 = M31*J11 + M32*J21 + M33*J31;
876 const double R32 = M31*J12 + M32*J22 + M33*J32;
877 const double R33 = M31*J13 + M32*J23 + M33*J33;
879 // Now set y to J^T R / det
880 y(q,0,e) = c_detJ * (J11*R11 + J21*R21 + J31*R31); // 1,1
881 const double Y12 = c_detJ * (J11*R12 + J21*R22 + J31*R32);
882 y(q,1,e) = Y12; // 1,2
883 y(q,2,e) = c_detJ * (J11*R13 + J21*R23 + J31*R33); // 1,3
885 const double Y21 = c_detJ * (J12*R11 + J22*R21 + J32*R31);
886 const double Y22 = c_detJ * (J12*R12 + J22*R22 + J32*R32);
887 const double Y23 = c_detJ * (J12*R13 + J22*R23 + J32*R33);
889 const double Y33 = c_detJ * (J13*R13 + J23*R23 + J33*R33);
891 y(q,3,e) = symmetric ? Y22 : Y21; // 2,2 or 2,1
892 y(q,4,e) = symmetric ? Y23 : Y22; // 2,3 or 2,2
893 y(q,5,e) = symmetric ? Y33 : Y23; // 3,3 or 2,3
897 y(q,6,e) = c_detJ * (J13*R11 + J23*R21 + J33*R31); // 3,1
898 y(q,7,e) = c_detJ * (J13*R12 + J23*R22 + J33*R32); // 3,2
899 y(q,8,e) = Y33; // 3,3
902 else // Vector or scalar coefficient version
904 // Set y to the 6 entries of J^T D J / det^2
905 const double D1 = C(0, q, e);
906 const double D2 = coeffDim == 3 ? C(1, q, e) : D1;
907 const double D3 = coeffDim == 3 ? C(2, q, e) : D1;
909 y(q,0,e) = c_detJ * (D1*J11*J11 + D2*J21*J21 + D3*J31*J31); // 1,1
910 y(q,1,e) = c_detJ * (D1*J11*J12 + D2*J21*J22 + D3*J31*J32); // 1,2
911 y(q,2,e) = c_detJ * (D1*J11*J13 + D2*J21*J23 + D3*J31*J33); // 1,3
912 y(q,3,e) = c_detJ * (D1*J12*J12 + D2*J22*J22 + D3*J32*J32); // 2,2
913 y(q,4,e) = c_detJ * (D1*J12*J13 + D2*J22*J23 + D3*J32*J33); // 2,3
914 y(q,5,e) = c_detJ * (D1*J13*J13 + D2*J23*J23 + D3*J33*J33); // 3,3
920 void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
922 // Assumes tensor-product elements
923 Mesh *mesh = fes.GetMesh();
924 const FiniteElement *fel = fes.GetFE(0);
926 const VectorTensorFiniteElement *el =
927 dynamic_cast<const VectorTensorFiniteElement*>(fel);
930 const IntegrationRule *ir
931 = IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
932 *mesh->GetElementTransformation(0));
934 const int dims = el->GetDim();
935 MFEM_VERIFY(dims == 2 || dims == 3, "");
937 const int nq = ir->GetNPoints();
938 dim = mesh->Dimension();
939 MFEM_VERIFY(dim == 2 || dim == 3, "");
941 const int dimc = (dim == 3) ? 3 : 1;
944 geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
945 mapsC = &el->GetDofToQuad(*ir, DofToQuad::TENSOR);
946 mapsO = &el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
947 dofs1D = mapsC->ndof;
948 quad1D = mapsC->nqpt;
950 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
952 const int MQsymmDim = SMQ ? (SMQ->GetSize() * (SMQ->GetSize() + 1)) / 2 : 0;
953 const int MQfullDim = MQ ? (MQ->GetHeight() * MQ->GetWidth()) : 0;
954 const int MQdim = MQ ? MQfullDim : MQsymmDim;
955 const int coeffDim = (MQ || SMQ) ? MQdim : (DQ ? DQ->GetVDim() : 1);
957 symmetric = (MQ == NULL);
959 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
960 const int ndata = (dim == 2) ? 1 : (symmetric ? symmDims : MQfullDim);
961 pa_data.SetSize(ndata * nq * ne, Device::GetMemoryType());
963 Vector coeff(coeffDim * ne * nq);
965 auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
966 if (Q || DQ || MQ || SMQ)
968 Vector D(DQ ? coeffDim : 0);
970 DenseSymmetricMatrix SM;
974 MFEM_VERIFY(coeffDim == dimc, "");
979 MFEM_VERIFY(coeffDim == MQdim, "");
980 MFEM_VERIFY(MQ->GetHeight() == dimc && MQ->GetWidth() == dimc, "");
985 MFEM_VERIFY(SMQ->GetSize() == dimc, "");
988 for (int e=0; e<ne; ++e)
990 ElementTransformation *tr = mesh->GetElementTransformation(e);
991 for (int p=0; p<nq; ++p)
995 MQ->Eval(M, *tr, ir->IntPoint(p));
997 for (int i=0; i<dimc; ++i)
998 for (int j=0; j<dimc; ++j)
1000 coeffh(j+(i*dimc), p, e) = M(i,j);
1006 SMQ->Eval(SM, *tr, ir->IntPoint(p));
1009 for (int i=0; i<dimc; ++i)
1010 for (int j=i; j<dimc; ++j, ++cnt)
1012 coeffh(cnt, p, e) = SM(i,j);
1018 DQ->Eval(D, *tr, ir->IntPoint(p));
1019 for (int i=0; i<coeffDim; ++i)
1021 coeffh(i, p, e) = D[i];
1026 coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
1032 if (el->GetDerivType() != mfem::FiniteElement::CURL)
1034 MFEM_ABORT("Unknown kernel.
");
1039 PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J, coeff,
1044 PACurlCurlSetup2D(quad1D, ne, ir->GetWeights(), geom->J, coeff, pa_data);
1048 static void PACurlCurlApply2D(const int D1D,
1051 const Array<double> &bo,
1052 const Array<double> &bot,
1053 const Array<double> &gc,
1054 const Array<double> &gct,
1055 const Vector &pa_data,
1059 constexpr static int VDIM = 2;
1060 constexpr static int MAX_D1D = HCURL_MAX_D1D;
1061 constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
1063 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
1064 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
1065 auto Gc = Reshape(gc.Read(), Q1D, D1D);
1066 auto Gct = Reshape(gct.Read(), D1D, Q1D);
1067 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
1068 auto X = Reshape(x.Read(), 2*(D1D-1)*D1D, NE);
1069 auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
1073 double curl[MAX_Q1D][MAX_Q1D];
1075 // curl[qy][qx] will be computed as du_y/dx - du_x/dy
1077 for (int qy = 0; qy < Q1D; ++qy)
1079 for (int qx = 0; qx < Q1D; ++qx)
1087 for (int c = 0; c < VDIM; ++c) // loop over x, y components
1089 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
1090 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
1092 for (int dy = 0; dy < D1Dy; ++dy)
1094 double gradX[MAX_Q1D];
1095 for (int qx = 0; qx < Q1D; ++qx)
1100 for (int dx = 0; dx < D1Dx; ++dx)
1102 const double t = X(dx + (dy * D1Dx) + osc, e);
1103 for (int qx = 0; qx < Q1D; ++qx)
1105 gradX[qx] += t * ((c == 0) ? Bo(qx,dx) : Gc(qx,dx));
1109 for (int qy = 0; qy < Q1D; ++qy)
1111 const double wy = (c == 0) ? -Gc(qy,dy) : Bo(qy,dy);
1112 for (int qx = 0; qx < Q1D; ++qx)
1114 curl[qy][qx] += gradX[qx] * wy;
1120 } // loop (c) over components
1122 // Apply D operator.
1123 for (int qy = 0; qy < Q1D; ++qy)
1125 for (int qx = 0; qx < Q1D; ++qx)
1127 curl[qy][qx] *= op(qx,qy,e);
1131 for (int qy = 0; qy < Q1D; ++qy)
1135 for (int c = 0; c < VDIM; ++c) // loop over x, y components
1137 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
1138 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
1140 double gradX[MAX_D1D];
1141 for (int dx = 0; dx < D1Dx; ++dx)
1145 for (int qx = 0; qx < Q1D; ++qx)
1147 for (int dx = 0; dx < D1Dx; ++dx)
1149 gradX[dx] += curl[qy][qx] * ((c == 0) ? Bot(dx,qx) : Gct(dx,qx));
1152 for (int dy = 0; dy < D1Dy; ++dy)
1154 const double wy = (c == 0) ? -Gct(dy,qy) : Bot(dy,qy);
1156 for (int dx = 0; dx < D1Dx; ++dx)
1158 Y(dx + (dy * D1Dx) + osc, e) += gradX[dx] * wy;
1165 }); // end of element loop
1168 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
1169 static void PACurlCurlApply3D(const int D1D,
1171 const bool symmetric,
1173 const Array<double> &bo,
1174 const Array<double> &bc,
1175 const Array<double> &bot,
1176 const Array<double> &bct,
1177 const Array<double> &gc,
1178 const Array<double> &gct,
1179 const Vector &pa_data,
1183 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
1184 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
1185 // Using (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
1186 // (\nabla\times u) \cdot (\nabla\times v) = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{\nabla}\times\hat{v}
1187 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1188 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1189 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1191 constexpr static int VDIM = 3;
1193 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
1194 auto Bc = Reshape(bc.Read(), Q1D, D1D);
1195 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
1196 auto Bct = Reshape(bct.Read(), D1D, Q1D);
1197 auto Gc = Reshape(gc.Read(), Q1D, D1D);
1198 auto Gct = Reshape(gct.Read(), D1D, Q1D);
1199 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, (symmetric ? 6 : 9), NE);
1200 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
1201 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
1205 double curl[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
1206 // curl[qz][qy][qx] will be computed as the vector curl at each quadrature point.
1208 for (int qz = 0; qz < Q1D; ++qz)
1210 for (int qy = 0; qy < Q1D; ++qy)
1212 for (int qx = 0; qx < Q1D; ++qx)
1214 for (int c = 0; c < VDIM; ++c)
1216 curl[qz][qy][qx][c] = 0.0;
1222 // We treat x, y, z components separately for optimization specific to each.
1228 const int D1Dz = D1D;
1229 const int D1Dy = D1D;
1230 const int D1Dx = D1D - 1;
1232 for (int dz = 0; dz < D1Dz; ++dz)
1234 double gradXY[MAX_Q1D][MAX_Q1D][2];
1235 for (int qy = 0; qy < Q1D; ++qy)
1237 for (int qx = 0; qx < Q1D; ++qx)
1239 for (int d = 0; d < 2; ++d)
1241 gradXY[qy][qx][d] = 0.0;
1246 for (int dy = 0; dy < D1Dy; ++dy)
1248 double massX[MAX_Q1D];
1249 for (int qx = 0; qx < Q1D; ++qx)
1254 for (int dx = 0; dx < D1Dx; ++dx)
1256 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
1257 for (int qx = 0; qx < Q1D; ++qx)
1259 massX[qx] += t * Bo(qx,dx);
1263 for (int qy = 0; qy < Q1D; ++qy)
1265 const double wy = Bc(qy,dy);
1266 const double wDy = Gc(qy,dy);
1267 for (int qx = 0; qx < Q1D; ++qx)
1269 const double wx = massX[qx];
1270 gradXY[qy][qx][0] += wx * wDy;
1271 gradXY[qy][qx][1] += wx * wy;
1276 for (int qz = 0; qz < Q1D; ++qz)
1278 const double wz = Bc(qz,dz);
1279 const double wDz = Gc(qz,dz);
1280 for (int qy = 0; qy < Q1D; ++qy)
1282 for (int qx = 0; qx < Q1D; ++qx)
1284 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1285 curl[qz][qy][qx][1] += gradXY[qy][qx][1] * wDz; // (u_0)_{x_2}
1286 curl[qz][qy][qx][2] -= gradXY[qy][qx][0] * wz; // -(u_0)_{x_1}
1292 osc += D1Dx * D1Dy * D1Dz;
1297 const int D1Dz = D1D;
1298 const int D1Dy = D1D - 1;
1299 const int D1Dx = D1D;
1301 for (int dz = 0; dz < D1Dz; ++dz)
1303 double gradXY[MAX_Q1D][MAX_Q1D][2];
1304 for (int qy = 0; qy < Q1D; ++qy)
1306 for (int qx = 0; qx < Q1D; ++qx)
1308 for (int d = 0; d < 2; ++d)
1310 gradXY[qy][qx][d] = 0.0;
1315 for (int dx = 0; dx < D1Dx; ++dx)
1317 double massY[MAX_Q1D];
1318 for (int qy = 0; qy < Q1D; ++qy)
1323 for (int dy = 0; dy < D1Dy; ++dy)
1325 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
1326 for (int qy = 0; qy < Q1D; ++qy)
1328 massY[qy] += t * Bo(qy,dy);
1332 for (int qx = 0; qx < Q1D; ++qx)
1334 const double wx = Bc(qx,dx);
1335 const double wDx = Gc(qx,dx);
1336 for (int qy = 0; qy < Q1D; ++qy)
1338 const double wy = massY[qy];
1339 gradXY[qy][qx][0] += wDx * wy;
1340 gradXY[qy][qx][1] += wx * wy;
1345 for (int qz = 0; qz < Q1D; ++qz)
1347 const double wz = Bc(qz,dz);
1348 const double wDz = Gc(qz,dz);
1349 for (int qy = 0; qy < Q1D; ++qy)
1351 for (int qx = 0; qx < Q1D; ++qx)
1353 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1354 curl[qz][qy][qx][0] -= gradXY[qy][qx][1] * wDz; // -(u_1)_{x_2}
1355 curl[qz][qy][qx][2] += gradXY[qy][qx][0] * wz; // (u_1)_{x_0}
1361 osc += D1Dx * D1Dy * D1Dz;
1366 const int D1Dz = D1D - 1;
1367 const int D1Dy = D1D;
1368 const int D1Dx = D1D;
1370 for (int dx = 0; dx < D1Dx; ++dx)
1372 double gradYZ[MAX_Q1D][MAX_Q1D][2];
1373 for (int qz = 0; qz < Q1D; ++qz)
1375 for (int qy = 0; qy < Q1D; ++qy)
1377 for (int d = 0; d < 2; ++d)
1379 gradYZ[qz][qy][d] = 0.0;
1384 for (int dy = 0; dy < D1Dy; ++dy)
1386 double massZ[MAX_Q1D];
1387 for (int qz = 0; qz < Q1D; ++qz)
1392 for (int dz = 0; dz < D1Dz; ++dz)
1394 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
1395 for (int qz = 0; qz < Q1D; ++qz)
1397 massZ[qz] += t * Bo(qz,dz);
1401 for (int qy = 0; qy < Q1D; ++qy)
1403 const double wy = Bc(qy,dy);
1404 const double wDy = Gc(qy,dy);
1405 for (int qz = 0; qz < Q1D; ++qz)
1407 const double wz = massZ[qz];
1408 gradYZ[qz][qy][0] += wz * wy;
1409 gradYZ[qz][qy][1] += wz * wDy;
1414 for (int qx = 0; qx < Q1D; ++qx)
1416 const double wx = Bc(qx,dx);
1417 const double wDx = Gc(qx,dx);
1419 for (int qy = 0; qy < Q1D; ++qy)
1421 for (int qz = 0; qz < Q1D; ++qz)
1423 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1424 curl[qz][qy][qx][0] += gradYZ[qz][qy][1] * wx; // (u_2)_{x_1}
1425 curl[qz][qy][qx][1] -= gradYZ[qz][qy][0] * wDx; // -(u_2)_{x_0}
1432 // Apply D operator.
1433 for (int qz = 0; qz < Q1D; ++qz)
1435 for (int qy = 0; qy < Q1D; ++qy)
1437 for (int qx = 0; qx < Q1D; ++qx)
1439 const double O11 = op(qx,qy,qz,0,e);
1440 const double O12 = op(qx,qy,qz,1,e);
1441 const double O13 = op(qx,qy,qz,2,e);
1442 const double O21 = symmetric ? O12 : op(qx,qy,qz,3,e);
1443 const double O22 = symmetric ? op(qx,qy,qz,3,e) : op(qx,qy,qz,4,e);
1444 const double O23 = symmetric ? op(qx,qy,qz,4,e) : op(qx,qy,qz,5,e);
1445 const double O31 = symmetric ? O13 : op(qx,qy,qz,6,e);
1446 const double O32 = symmetric ? O23 : op(qx,qy,qz,7,e);
1447 const double O33 = symmetric ? op(qx,qy,qz,5,e) : op(qx,qy,qz,8,e);
1449 const double c1 = (O11 * curl[qz][qy][qx][0]) + (O12 * curl[qz][qy][qx][1]) +
1450 (O13 * curl[qz][qy][qx][2]);
1451 const double c2 = (O21 * curl[qz][qy][qx][0]) + (O22 * curl[qz][qy][qx][1]) +
1452 (O23 * curl[qz][qy][qx][2]);
1453 const double c3 = (O31 * curl[qz][qy][qx][0]) + (O32 * curl[qz][qy][qx][1]) +
1454 (O33 * curl[qz][qy][qx][2]);
1456 curl[qz][qy][qx][0] = c1;
1457 curl[qz][qy][qx][1] = c2;
1458 curl[qz][qy][qx][2] = c3;
1466 const int D1Dz = D1D;
1467 const int D1Dy = D1D;
1468 const int D1Dx = D1D - 1;
1470 for (int qz = 0; qz < Q1D; ++qz)
1472 double gradXY12[MAX_D1D][MAX_D1D];
1473 double gradXY21[MAX_D1D][MAX_D1D];
1475 for (int dy = 0; dy < D1Dy; ++dy)
1477 for (int dx = 0; dx < D1Dx; ++dx)
1479 gradXY12[dy][dx] = 0.0;
1480 gradXY21[dy][dx] = 0.0;
1483 for (int qy = 0; qy < Q1D; ++qy)
1485 double massX[MAX_D1D][2];
1486 for (int dx = 0; dx < D1Dx; ++dx)
1488 for (int n = 0; n < 2; ++n)
1493 for (int qx = 0; qx < Q1D; ++qx)
1495 for (int dx = 0; dx < D1Dx; ++dx)
1497 const double wx = Bot(dx,qx);
1499 massX[dx][0] += wx * curl[qz][qy][qx][1];
1500 massX[dx][1] += wx * curl[qz][qy][qx][2];
1503 for (int dy = 0; dy < D1Dy; ++dy)
1505 const double wy = Bct(dy,qy);
1506 const double wDy = Gct(dy,qy);
1508 for (int dx = 0; dx < D1Dx; ++dx)
1510 gradXY21[dy][dx] += massX[dx][0] * wy;
1511 gradXY12[dy][dx] += massX[dx][1] * wDy;
1516 for (int dz = 0; dz < D1Dz; ++dz)
1518 const double wz = Bct(dz,qz);
1519 const double wDz = Gct(dz,qz);
1520 for (int dy = 0; dy < D1Dy; ++dy)
1522 for (int dx = 0; dx < D1Dx; ++dx)
1524 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1525 // (u_0)_{x_2} * (op * curl)_1 - (u_0)_{x_1} * (op * curl)_2
1526 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
1527 e) += (gradXY21[dy][dx] * wDz) - (gradXY12[dy][dx] * wz);
1533 osc += D1Dx * D1Dy * D1Dz;
1538 const int D1Dz = D1D;
1539 const int D1Dy = D1D - 1;
1540 const int D1Dx = D1D;
1542 for (int qz = 0; qz < Q1D; ++qz)
1544 double gradXY02[MAX_D1D][MAX_D1D];
1545 double gradXY20[MAX_D1D][MAX_D1D];
1547 for (int dy = 0; dy < D1Dy; ++dy)
1549 for (int dx = 0; dx < D1Dx; ++dx)
1551 gradXY02[dy][dx] = 0.0;
1552 gradXY20[dy][dx] = 0.0;
1555 for (int qx = 0; qx < Q1D; ++qx)
1557 double massY[MAX_D1D][2];
1558 for (int dy = 0; dy < D1Dy; ++dy)
1563 for (int qy = 0; qy < Q1D; ++qy)
1565 for (int dy = 0; dy < D1Dy; ++dy)
1567 const double wy = Bot(dy,qy);
1569 massY[dy][0] += wy * curl[qz][qy][qx][2];
1570 massY[dy][1] += wy * curl[qz][qy][qx][0];
1573 for (int dx = 0; dx < D1Dx; ++dx)
1575 const double wx = Bct(dx,qx);
1576 const double wDx = Gct(dx,qx);
1578 for (int dy = 0; dy < D1Dy; ++dy)
1580 gradXY02[dy][dx] += massY[dy][0] * wDx;
1581 gradXY20[dy][dx] += massY[dy][1] * wx;
1586 for (int dz = 0; dz < D1Dz; ++dz)
1588 const double wz = Bct(dz,qz);
1589 const double wDz = Gct(dz,qz);
1590 for (int dy = 0; dy < D1Dy; ++dy)
1592 for (int dx = 0; dx < D1Dx; ++dx)
1594 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1595 // -(u_1)_{x_2} * (op * curl)_0 + (u_1)_{x_0} * (op * curl)_2
1596 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
1597 e) += (-gradXY20[dy][dx] * wDz) + (gradXY02[dy][dx] * wz);
1603 osc += D1Dx * D1Dy * D1Dz;
1608 const int D1Dz = D1D - 1;
1609 const int D1Dy = D1D;
1610 const int D1Dx = D1D;
1612 for (int qx = 0; qx < Q1D; ++qx)
1614 double gradYZ01[MAX_D1D][MAX_D1D];
1615 double gradYZ10[MAX_D1D][MAX_D1D];
1617 for (int dy = 0; dy < D1Dy; ++dy)
1619 for (int dz = 0; dz < D1Dz; ++dz)
1621 gradYZ01[dz][dy] = 0.0;
1622 gradYZ10[dz][dy] = 0.0;
1625 for (int qy = 0; qy < Q1D; ++qy)
1627 double massZ[MAX_D1D][2];
1628 for (int dz = 0; dz < D1Dz; ++dz)
1630 for (int n = 0; n < 2; ++n)
1635 for (int qz = 0; qz < Q1D; ++qz)
1637 for (int dz = 0; dz < D1Dz; ++dz)
1639 const double wz = Bot(dz,qz);
1641 massZ[dz][0] += wz * curl[qz][qy][qx][0];
1642 massZ[dz][1] += wz * curl[qz][qy][qx][1];
1645 for (int dy = 0; dy < D1Dy; ++dy)
1647 const double wy = Bct(dy,qy);
1648 const double wDy = Gct(dy,qy);
1650 for (int dz = 0; dz < D1Dz; ++dz)
1652 gradYZ01[dz][dy] += wy * massZ[dz][1];
1653 gradYZ10[dz][dy] += wDy * massZ[dz][0];
1658 for (int dx = 0; dx < D1Dx; ++dx)
1660 const double wx = Bct(dx,qx);
1661 const double wDx = Gct(dx,qx);
1663 for (int dy = 0; dy < D1Dy; ++dy)
1665 for (int dz = 0; dz < D1Dz; ++dz)
1667 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1668 // (u_2)_{x_1} * (op * curl)_0 - (u_2)_{x_0} * (op * curl)_1
1669 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
1670 e) += (gradYZ10[dz][dy] * wx) - (gradYZ01[dz][dy] * wDx);
1676 }); // end of element loop
1679 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
1680 static void SmemPACurlCurlApply3D(const int D1D,
1682 const bool symmetric,
1684 const Array<double> &bo,
1685 const Array<double> &bc,
1686 const Array<double> &bot,
1687 const Array<double> &bct,
1688 const Array<double> &gc,
1689 const Array<double> &gct,
1690 const Vector &pa_data,
1694 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
1695 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
1696 // Using (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
1697 // (\nabla\times u) \cdot (\nabla\times v) = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{\nabla}\times\hat{v}
1698 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1699 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1700 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1702 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
1703 auto Bc = Reshape(bc.Read(), Q1D, D1D);
1704 auto Gc = Reshape(gc.Read(), Q1D, D1D);
1705 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, symmetric ? 6 : 9, NE);
1706 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
1707 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
1709 const int s = symmetric ? 6 : 9;
1711 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
1713 constexpr int VDIM = 3;
1715 MFEM_SHARED double sBo[MAX_D1D][MAX_Q1D];
1716 MFEM_SHARED double sBc[MAX_D1D][MAX_Q1D];
1717 MFEM_SHARED double sGc[MAX_D1D][MAX_Q1D];
1720 MFEM_SHARED double sop[9][MAX_Q1D][MAX_Q1D];
1721 MFEM_SHARED double curl[MAX_Q1D][MAX_Q1D][3];
1723 MFEM_SHARED double sX[MAX_D1D][MAX_D1D][MAX_D1D];
1725 MFEM_FOREACH_THREAD(qx,x,Q1D)
1727 MFEM_FOREACH_THREAD(qy,y,Q1D)
1729 MFEM_FOREACH_THREAD(qz,z,Q1D)
1731 for (int i=0; i<s; ++i)
1733 ope[i] = op(qx,qy,qz,i,e);
1739 const int tidx = MFEM_THREAD_ID(x);
1740 const int tidy = MFEM_THREAD_ID(y);
1741 const int tidz = MFEM_THREAD_ID(z);
1745 MFEM_FOREACH_THREAD(d,y,D1D)
1747 MFEM_FOREACH_THREAD(q,x,Q1D)
1749 sBc[d][q] = Bc(q,d);
1750 sGc[d][q] = Gc(q,d);
1753 sBo[d][q] = Bo(q,d);
1760 for (int qz=0; qz < Q1D; ++qz)
1764 MFEM_FOREACH_THREAD(qy,y,Q1D)
1766 MFEM_FOREACH_THREAD(qx,x,Q1D)
1768 for (int i=0; i<3; ++i)
1770 curl[qy][qx][i] = 0.0;
1777 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
1779 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
1780 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
1781 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
1783 MFEM_FOREACH_THREAD(dz,z,D1Dz)
1785 MFEM_FOREACH_THREAD(dy,y,D1Dy)
1787 MFEM_FOREACH_THREAD(dx,x,D1Dx)
1789 sX[dz][dy][dx] = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
1799 for (int i=0; i<s; ++i)
1801 sop[i][tidx][tidy] = ope[i];
1805 MFEM_FOREACH_THREAD(qy,y,Q1D)
1807 MFEM_FOREACH_THREAD(qx,x,Q1D)
1812 // We treat x, y, z components separately for optimization specific to each.
1813 if (c == 0) // x component
1815 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1817 for (int dz = 0; dz < D1Dz; ++dz)
1819 const double wz = sBc[dz][qz];
1820 const double wDz = sGc[dz][qz];
1822 for (int dy = 0; dy < D1Dy; ++dy)
1824 const double wy = sBc[dy][qy];
1825 const double wDy = sGc[dy][qy];
1827 for (int dx = 0; dx < D1Dx; ++dx)
1829 const double wx = sX[dz][dy][dx] * sBo[dx][qx];
1836 curl[qy][qx][1] += v; // (u_0)_{x_2}
1837 curl[qy][qx][2] -= u; // -(u_0)_{x_1}
1839 else if (c == 1) // y component
1841 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1843 for (int dz = 0; dz < D1Dz; ++dz)
1845 const double wz = sBc[dz][qz];
1846 const double wDz = sGc[dz][qz];
1848 for (int dy = 0; dy < D1Dy; ++dy)
1850 const double wy = sBo[dy][qy];
1852 for (int dx = 0; dx < D1Dx; ++dx)
1854 const double t = sX[dz][dy][dx];
1855 const double wx = t * sBc[dx][qx];
1856 const double wDx = t * sGc[dx][qx];
1864 curl[qy][qx][0] -= v; // -(u_1)_{x_2}
1865 curl[qy][qx][2] += u; // (u_1)_{x_0}
1869 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1871 for (int dz = 0; dz < D1Dz; ++dz)
1873 const double wz = sBo[dz][qz];
1875 for (int dy = 0; dy < D1Dy; ++dy)
1877 const double wy = sBc[dy][qy];
1878 const double wDy = sGc[dy][qy];
1880 for (int dx = 0; dx < D1Dx; ++dx)
1882 const double t = sX[dz][dy][dx];
1883 const double wx = t * sBc[dx][qx];
1884 const double wDx = t * sGc[dx][qx];
1892 curl[qy][qx][0] += v; // (u_2)_{x_1}
1893 curl[qy][qx][1] -= u; // -(u_2)_{x_0}
1899 osc += D1Dx * D1Dy * D1Dz;
1907 MFEM_FOREACH_THREAD(dz,z,D1D)
1909 const double wcz = sBc[dz][qz];
1910 const double wcDz = sGc[dz][qz];
1911 const double wz = (dz < D1D-1) ? sBo[dz][qz] : 0.0;
1913 MFEM_FOREACH_THREAD(dy,y,D1D)
1915 MFEM_FOREACH_THREAD(dx,x,D1D)
1917 for (int qy = 0; qy < Q1D; ++qy)
1919 const double wcy = sBc[dy][qy];
1920 const double wcDy = sGc[dy][qy];
1921 const double wy = (dy < D1D-1) ? sBo[dy][qy] : 0.0;
1923 for (int qx = 0; qx < Q1D; ++qx)
1925 const double O11 = sop[0][qx][qy];
1926 const double O12 = sop[1][qx][qy];
1927 const double O13 = sop[2][qx][qy];
1928 const double O21 = symmetric ? O12 : sop[3][qx][qy];
1929 const double O22 = symmetric ? sop[3][qx][qy] : sop[4][qx][qy];
1930 const double O23 = symmetric ? sop[4][qx][qy] : sop[5][qx][qy];
1931 const double O31 = symmetric ? O13 : sop[6][qx][qy];
1932 const double O32 = symmetric ? O23 : sop[7][qx][qy];
1933 const double O33 = symmetric ? sop[5][qx][qy] : sop[8][qx][qy];
1935 const double c1 = (O11 * curl[qy][qx][0]) + (O12 * curl[qy][qx][1]) +
1936 (O13 * curl[qy][qx][2]);
1937 const double c2 = (O21 * curl[qy][qx][0]) + (O22 * curl[qy][qx][1]) +
1938 (O23 * curl[qy][qx][2]);
1939 const double c3 = (O31 * curl[qy][qx][0]) + (O32 * curl[qy][qx][1]) +
1940 (O33 * curl[qy][qx][2]);
1942 const double wcx = sBc[dx][qx];
1943 const double wDx = sGc[dx][qx];
1947 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
1948 // (u_0)_{x_2} * (op * curl)_1 - (u_0)_{x_1} * (op * curl)_2
1949 const double wx = sBo[dx][qx];
1950 dxyz1 += (wx * c2 * wcy * wcDz) - (wx * c3 * wcDy * wcz);
1953 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
1954 // -(u_1)_{x_2} * (op * curl)_0 + (u_1)_{x_0} * (op * curl)_2
1955 dxyz2 += (-wy * c1 * wcx * wcDz) + (wy * c3 * wDx * wcz);
1957 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
1958 // (u_2)_{x_1} * (op * curl)_0 - (u_2)_{x_0} * (op * curl)_1
1959 dxyz3 += (wcDy * wz * c1 * wcx) - (wcy * wz * c2 * wDx);
1968 MFEM_FOREACH_THREAD(dz,z,D1D)
1970 MFEM_FOREACH_THREAD(dy,y,D1D)
1972 MFEM_FOREACH_THREAD(dx,x,D1D)
1976 Y(dx + ((dy + (dz * D1D)) * (D1D-1)), e) += dxyz1;
1980 Y(dx + ((dy + (dz * (D1D-1))) * D1D) + ((D1D-1)*D1D*D1D), e) += dxyz2;
1984 Y(dx + ((dy + (dz * D1D)) * D1D) + (2*(D1D-1)*D1D*D1D), e) += dxyz3;
1990 }); // end of element loop
1993 void CurlCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
1997 if (Device::Allows(Backend::DEVICE_MASK))
1999 const int ID = (dofs1D << 4) | quad1D;
2002 case 0x23: return SmemPACurlCurlApply3D<2,3>(dofs1D, quad1D, symmetric, ne,
2003 mapsO->B, mapsC->B, mapsO->Bt,
2004 mapsC->Bt, mapsC->G, mapsC->Gt, pa_data, x, y);
2005 case 0x34: return SmemPACurlCurlApply3D<3,4>(dofs1D, quad1D, symmetric, ne,
2006 mapsO->B, mapsC->B, mapsO->Bt,
2007 mapsC->Bt, mapsC->G, mapsC->Gt, pa_data, x, y);
2008 case 0x45: return SmemPACurlCurlApply3D<4,5>(dofs1D, quad1D, symmetric, ne,
2010 mapsC->B, mapsO->Bt,
2011 mapsC->Bt, mapsC->G, mapsC->Gt, pa_data, x, y);
2012 case 0x56: return SmemPACurlCurlApply3D<5,6>(dofs1D, quad1D, symmetric, ne,
2013 mapsO->B, mapsC->B, mapsO->Bt,
2014 mapsC->Bt, mapsC->G, mapsC->Gt, pa_data, x, y);
2015 default: return SmemPACurlCurlApply3D(dofs1D, quad1D, symmetric, ne, mapsO->B,
2016 mapsC->B, mapsO->Bt, mapsC->Bt,
2017 mapsC->G, mapsC->Gt, pa_data, x, y);
2021 PACurlCurlApply3D(dofs1D, quad1D, symmetric, ne, mapsO->B, mapsC->B, mapsO->Bt,
2022 mapsC->Bt, mapsC->G, mapsC->Gt, pa_data, x, y);
2026 PACurlCurlApply2D(dofs1D, quad1D, ne, mapsO->B, mapsO->Bt,
2027 mapsC->G, mapsC->Gt, pa_data, x, y);
2031 MFEM_ABORT("Unsupported dimension!
");
2035 static void PACurlCurlAssembleDiagonal2D(const int D1D,
2038 const Array<double> &bo,
2039 const Array<double> &gc,
2040 const Vector &pa_data,
2043 constexpr static int VDIM = 2;
2044 constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
2046 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
2047 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2048 auto op = Reshape(pa_data.Read(), Q1D, Q1D, NE);
2049 auto D = Reshape(diag.ReadWrite(), 2*(D1D-1)*D1D, NE);
2055 for (int c = 0; c < VDIM; ++c) // loop over x, y components
2057 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
2058 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
2062 for (int dy = 0; dy < D1Dy; ++dy)
2064 for (int qx = 0; qx < Q1D; ++qx)
2067 for (int qy = 0; qy < Q1D; ++qy)
2069 const double wy = (c == 1) ? Bo(qy,dy) : -Gc(qy,dy);
2070 t[qx] += wy * wy * op(qx,qy,e);
2074 for (int dx = 0; dx < D1Dx; ++dx)
2076 for (int qx = 0; qx < Q1D; ++qx)
2078 const double wx = ((c == 0) ? Bo(qx,dx) : Gc(qx,dx));
2079 D(dx + (dy * D1Dx) + osc, e) += t[qx] * wx * wx;
2086 }); // end of element loop
2089 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
2090 static void PACurlCurlAssembleDiagonal3D(const int D1D,
2092 const bool symmetric,
2094 const Array<double> &bo,
2095 const Array<double> &bc,
2096 const Array<double> &go,
2097 const Array<double> &gc,
2098 const Vector &pa_data,
2101 constexpr static int VDIM = 3;
2102 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
2103 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
2105 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
2106 auto Bc = Reshape(bc.Read(), Q1D, D1D);
2107 auto Go = Reshape(go.Read(), Q1D, D1D-1);
2108 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2109 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, (symmetric ? 6 : 9), NE);
2110 auto D = Reshape(diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
2112 const int s = symmetric ? 6 : 9;
2116 const int i21 = symmetric ? i12 : 3;
2117 const int i22 = symmetric ? 3 : 4;
2118 const int i23 = symmetric ? 4 : 5;
2119 const int i31 = symmetric ? i13 : 6;
2120 const int i32 = symmetric ? i23 : 7;
2121 const int i33 = symmetric ? 5 : 8;
2125 // Using (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
2126 // (\nabla\times u) \cdot (\nabla\times u) = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{\nabla}\times\hat{u}
2127 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
2128 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
2129 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
2131 // For each c, we will keep 9 arrays for derivatives multiplied by the 9 entries of the 3x3 matrix (dF^T C dF),
2132 // which may be non-symmetric depending on a possibly non-symmetric matrix coefficient.
2136 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
2138 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
2139 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
2140 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
2142 double zt[MAX_Q1D][MAX_Q1D][MAX_D1D][9][3];
2145 for (int qx = 0; qx < Q1D; ++qx)
2147 for (int qy = 0; qy < Q1D; ++qy)
2149 for (int dz = 0; dz < D1Dz; ++dz)
2151 for (int i=0; i<s; ++i)
2153 for (int d=0; d<3; ++d)
2155 zt[qx][qy][dz][i][d] = 0.0;
2159 for (int qz = 0; qz < Q1D; ++qz)
2161 const double wz = ((c == 2) ? Bo(qz,dz) : Bc(qz,dz));
2162 const double wDz = ((c == 2) ? Go(qz,dz) : Gc(qz,dz));
2164 for (int i=0; i<s; ++i)
2166 zt[qx][qy][dz][i][0] += wz * wz * op(qx,qy,qz,i,e);
2167 zt[qx][qy][dz][i][1] += wDz * wz * op(qx,qy,qz,i,e);
2168 zt[qx][qy][dz][i][2] += wDz * wDz * op(qx,qy,qz,i,e);
2173 } // end of z contraction
2175 double yt[MAX_Q1D][MAX_D1D][MAX_D1D][9][3][3];
2178 for (int qx = 0; qx < Q1D; ++qx)
2180 for (int dz = 0; dz < D1Dz; ++dz)
2182 for (int dy = 0; dy < D1Dy; ++dy)
2184 for (int i=0; i<s; ++i)
2186 for (int d=0; d<3; ++d)
2187 for (int j=0; j<3; ++j)
2189 yt[qx][dy][dz][i][d][j] = 0.0;
2193 for (int qy = 0; qy < Q1D; ++qy)
2195 const double wy = ((c == 1) ? Bo(qy,dy) : Bc(qy,dy));
2196 const double wDy = ((c == 1) ? Go(qy,dy) : Gc(qy,dy));
2198 for (int i=0; i<s; ++i)
2200 for (int d=0; d<3; ++d)
2202 yt[qx][dy][dz][i][d][0] += wy * wy * zt[qx][qy][dz][i][d];
2203 yt[qx][dy][dz][i][d][1] += wDy * wy * zt[qx][qy][dz][i][d];
2204 yt[qx][dy][dz][i][d][2] += wDy * wDy * zt[qx][qy][dz][i][d];
2210 } // end of y contraction
2213 for (int dz = 0; dz < D1Dz; ++dz)
2215 for (int dy = 0; dy < D1Dy; ++dy)
2217 for (int dx = 0; dx < D1Dx; ++dx)
2219 for (int qx = 0; qx < Q1D; ++qx)
2221 const double wx = ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
2222 const double wDx = ((c == 0) ? Go(qx,dx) : Gc(qx,dx));
2224 // Using (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
2225 // (\nabla\times u) \cdot (\nabla\times u) = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{\nabla}\times\hat{u}
2226 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
2227 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
2228 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
2231 const double O11 = op(q,0,e);
2232 const double O12 = op(q,1,e);
2233 const double O13 = op(q,2,e);
2234 const double O22 = op(q,3,e);
2235 const double O23 = op(q,4,e);
2236 const double O33 = op(q,5,e);
2241 // (u_0)_{x_2} (O22 (u_0)_{x_2} - O23 (u_0)_{x_1}) - (u_0)_{x_1} (O32 (u_0)_{x_2} - O33 (u_0)_{x_1})
2242 const double sumy = yt[qx][dy][dz][i22][2][0] - yt[qx][dy][dz][i23][1][1]
2243 - yt[qx][dy][dz][i32][1][1] + yt[qx][dy][dz][i33][0][2];
2245 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += sumy * wx * wx;
2249 // (u_1)_{x_2} (O11 (u_1)_{x_2} - O13 (u_1)_{x_0}) + (u_1)_{x_0} (-O31 (u_1)_{x_2} + O33 (u_1)_{x_0})
2250 const double d = (yt[qx][dy][dz][i11][2][0] * wx * wx)
2251 - ((yt[qx][dy][dz][i13][1][0] + yt[qx][dy][dz][i31][1][0]) * wDx * wx)
2252 + (yt[qx][dy][dz][i33][0][0] * wDx * wDx);
2254 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += d;
2258 // (u_2)_{x_1} (O11 (u_2)_{x_1} - O12 (u_2)_{x_0}) - (u_2)_{x_0} (O21 (u_2)_{x_1} - O22 (u_2)_{x_0})
2259 const double d = (yt[qx][dy][dz][i11][0][2] * wx * wx)
2260 - ((yt[qx][dy][dz][i12][0][1] + yt[qx][dy][dz][i21][0][1]) * wDx * wx)
2261 + (yt[qx][dy][dz][i22][0][0] * wDx * wDx);
2263 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += d;
2268 } // end of x contraction
2270 osc += D1Dx * D1Dy * D1Dz;
2272 }); // end of element loop
2275 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
2276 static void SmemPACurlCurlAssembleDiagonal3D(const int D1D,
2278 const bool symmetric,
2280 const Array<double> &bo,
2281 const Array<double> &bc,
2282 const Array<double> &go,
2283 const Array<double> &gc,
2284 const Vector &pa_data,
2287 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
2288 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
2290 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
2291 auto Bc = Reshape(bc.Read(), Q1D, D1D);
2292 auto Go = Reshape(go.Read(), Q1D, D1D-1);
2293 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2294 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, (symmetric ? 6 : 9), NE);
2295 auto D = Reshape(diag.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
2297 const int s = symmetric ? 6 : 9;
2301 const int i21 = symmetric ? i12 : 3;
2302 const int i22 = symmetric ? 3 : 4;
2303 const int i23 = symmetric ? 4 : 5;
2304 const int i31 = symmetric ? i13 : 6;
2305 const int i32 = symmetric ? i23 : 7;
2306 const int i33 = symmetric ? 5 : 8;
2308 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
2310 // Using (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
2311 // (\nabla\times u) \cdot (\nabla\times u) = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{\nabla}\times\hat{u}
2312 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
2313 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
2314 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
2316 constexpr int VDIM = 3;
2318 MFEM_SHARED double sBo[MAX_Q1D][MAX_D1D];
2319 MFEM_SHARED double sBc[MAX_Q1D][MAX_D1D];
2320 MFEM_SHARED double sGo[MAX_Q1D][MAX_D1D];
2321 MFEM_SHARED double sGc[MAX_Q1D][MAX_D1D];
2324 MFEM_SHARED double sop[9][MAX_Q1D][MAX_Q1D];
2326 MFEM_FOREACH_THREAD(qx,x,Q1D)
2328 MFEM_FOREACH_THREAD(qy,y,Q1D)
2330 MFEM_FOREACH_THREAD(qz,z,Q1D)
2332 for (int i=0; i<s; ++i)
2334 ope[i] = op(qx,qy,qz,i,e);
2340 const int tidx = MFEM_THREAD_ID(x);
2341 const int tidy = MFEM_THREAD_ID(y);
2342 const int tidz = MFEM_THREAD_ID(z);
2346 MFEM_FOREACH_THREAD(d,y,D1D)
2348 MFEM_FOREACH_THREAD(q,x,Q1D)
2350 sBc[q][d] = Bc(q,d);
2351 sGc[q][d] = Gc(q,d);
2354 sBo[q][d] = Bo(q,d);
2355 sGo[q][d] = Go(q,d);
2363 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
2365 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
2366 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
2367 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
2371 for (int qz=0; qz < Q1D; ++qz)
2375 for (int i=0; i<s; ++i)
2377 sop[i][tidx][tidy] = ope[i];
2383 MFEM_FOREACH_THREAD(dz,z,D1Dz)
2385 const double wz = ((c == 2) ? sBo[qz][dz] : sBc[qz][dz]);
2386 const double wDz = ((c == 2) ? sGo[qz][dz] : sGc[qz][dz]);
2388 MFEM_FOREACH_THREAD(dy,y,D1Dy)
2390 MFEM_FOREACH_THREAD(dx,x,D1Dx)
2392 for (int qy = 0; qy < Q1D; ++qy)
2394 const double wy = ((c == 1) ? sBo[qy][dy] : sBc[qy][dy]);
2395 const double wDy = ((c == 1) ? sGo[qy][dy] : sGc[qy][dy]);
2397 for (int qx = 0; qx < Q1D; ++qx)
2399 const double wx = ((c == 0) ? sBo[qx][dx] : sBc[qx][dx]);
2400 const double wDx = ((c == 0) ? sGo[qx][dx] : sGc[qx][dx]);
2404 // (u_0)_{x_2} (O22 (u_0)_{x_2} - O23 (u_0)_{x_1}) - (u_0)_{x_1} (O32 (u_0)_{x_2} - O33 (u_0)_{x_1})
2406 // (u_0)_{x_2} O22 (u_0)_{x_2}
2407 dxyz += sop[i22][qx][qy] * wx * wx * wy * wy * wDz * wDz;
2409 // -(u_0)_{x_2} O23 (u_0)_{x_1} - (u_0)_{x_1} O32 (u_0)_{x_2}
2410 dxyz += -(sop[i23][qx][qy] + sop[i32][qx][qy]) * wx * wx * wDy * wy * wDz * wz;
2412 // (u_0)_{x_1} O33 (u_0)_{x_1}
2413 dxyz += sop[i33][qx][qy] * wx * wx * wDy * wDy * wz * wz;
2417 // (u_1)_{x_2} (O11 (u_1)_{x_2} - O13 (u_1)_{x_0}) + (u_1)_{x_0} (-O31 (u_1)_{x_2} + O33 (u_1)_{x_0})
2419 // (u_1)_{x_2} O11 (u_1)_{x_2}
2420 dxyz += sop[i11][qx][qy] * wx * wx * wy * wy * wDz * wDz;
2422 // -(u_1)_{x_2} O13 (u_1)_{x_0} - (u_1)_{x_0} O31 (u_1)_{x_2}
2423 dxyz += -(sop[i13][qx][qy] + sop[i31][qx][qy]) * wDx * wx * wy * wy * wDz * wz;
2425 // (u_1)_{x_0} O33 (u_1)_{x_0})
2426 dxyz += sop[i33][qx][qy] * wDx * wDx * wy * wy * wz * wz;
2430 // (u_2)_{x_1} (O11 (u_2)_{x_1} - O12 (u_2)_{x_0}) - (u_2)_{x_0} (O21 (u_2)_{x_1} - O22 (u_2)_{x_0})
2432 // (u_2)_{x_1} O11 (u_2)_{x_1}
2433 dxyz += sop[i11][qx][qy] * wx * wx * wDy * wDy * wz * wz;
2435 // -(u_2)_{x_1} O12 (u_2)_{x_0} - (u_2)_{x_0} O21 (u_2)_{x_1}
2436 dxyz += -(sop[i12][qx][qy] + sop[i21][qx][qy]) * wDx * wx * wDy * wy * wz * wz;
2438 // (u_2)_{x_0} O22 (u_2)_{x_0}
2439 dxyz += sop[i22][qx][qy] * wDx * wDx * wy * wy * wz * wz;
2450 MFEM_FOREACH_THREAD(dz,z,D1Dz)
2452 MFEM_FOREACH_THREAD(dy,y,D1Dy)
2454 MFEM_FOREACH_THREAD(dx,x,D1Dx)
2456 D(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += dxyz;
2461 osc += D1Dx * D1Dy * D1Dz;
2463 }); // end of element loop
2466 void CurlCurlIntegrator::AssembleDiagonalPA(Vector& diag)
2470 if (Device::Allows(Backend::DEVICE_MASK))
2472 const int ID = (dofs1D << 4) | quad1D;
2475 case 0x23: return SmemPACurlCurlAssembleDiagonal3D<2,3>(dofs1D, quad1D,
2480 case 0x34: return SmemPACurlCurlAssembleDiagonal3D<3,4>(dofs1D, quad1D,
2485 case 0x45: return SmemPACurlCurlAssembleDiagonal3D<4,5>(dofs1D, quad1D,
2490 case 0x56: return SmemPACurlCurlAssembleDiagonal3D<5,6>(dofs1D, quad1D,
2495 default: return SmemPACurlCurlAssembleDiagonal3D(dofs1D, quad1D, symmetric, ne,
2502 PACurlCurlAssembleDiagonal3D(dofs1D, quad1D, symmetric, ne,
2509 PACurlCurlAssembleDiagonal2D(dofs1D, quad1D, ne,
2510 mapsO->B, mapsC->G, pa_data, diag);
2514 MFEM_ABORT("Unsupported dimension!
");
2518 // Apply to x corresponding to DOF's in H^1 (trial), whose gradients are
2519 // integrated against H(curl) test functions corresponding to y.
2520 void PAHcurlH1Apply3D(const int D1D,
2523 const Array<double> &bc,
2524 const Array<double> &gc,
2525 const Array<double> &bot,
2526 const Array<double> &bct,
2527 const Vector &pa_data,
2531 constexpr static int MAX_D1D = HCURL_MAX_D1D;
2532 constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
2534 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
2535 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
2537 constexpr static int VDIM = 3;
2539 auto Bc = Reshape(bc.Read(), Q1D, D1D);
2540 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2541 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
2542 auto Bct = Reshape(bct.Read(), D1D, Q1D);
2543 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
2544 auto X = Reshape(x.Read(), D1D, D1D, D1D, NE);
2545 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
2549 double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
2551 for (int qz = 0; qz < Q1D; ++qz)
2553 for (int qy = 0; qy < Q1D; ++qy)
2555 for (int qx = 0; qx < Q1D; ++qx)
2557 for (int c = 0; c < VDIM; ++c)
2559 mass[qz][qy][qx][c] = 0.0;
2565 for (int dz = 0; dz < D1D; ++dz)
2567 double gradXY[MAX_Q1D][MAX_Q1D][3];
2568 for (int qy = 0; qy < Q1D; ++qy)
2570 for (int qx = 0; qx < Q1D; ++qx)
2572 gradXY[qy][qx][0] = 0.0;
2573 gradXY[qy][qx][1] = 0.0;
2574 gradXY[qy][qx][2] = 0.0;
2577 for (int dy = 0; dy < D1D; ++dy)
2579 double gradX[MAX_Q1D][2];
2580 for (int qx = 0; qx < Q1D; ++qx)
2585 for (int dx = 0; dx < D1D; ++dx)
2587 const double s = X(dx,dy,dz,e);
2588 for (int qx = 0; qx < Q1D; ++qx)
2590 gradX[qx][0] += s * Bc(qx,dx);
2591 gradX[qx][1] += s * Gc(qx,dx);
2594 for (int qy = 0; qy < Q1D; ++qy)
2596 const double wy = Bc(qy,dy);
2597 const double wDy = Gc(qy,dy);
2598 for (int qx = 0; qx < Q1D; ++qx)
2600 const double wx = gradX[qx][0];
2601 const double wDx = gradX[qx][1];
2602 gradXY[qy][qx][0] += wDx * wy;
2603 gradXY[qy][qx][1] += wx * wDy;
2604 gradXY[qy][qx][2] += wx * wy;
2608 for (int qz = 0; qz < Q1D; ++qz)
2610 const double wz = Bc(qz,dz);
2611 const double wDz = Gc(qz,dz);
2612 for (int qy = 0; qy < Q1D; ++qy)
2614 for (int qx = 0; qx < Q1D; ++qx)
2616 mass[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
2617 mass[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
2618 mass[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
2624 // Apply D operator.
2625 for (int qz = 0; qz < Q1D; ++qz)
2627 for (int qy = 0; qy < Q1D; ++qy)
2629 for (int qx = 0; qx < Q1D; ++qx)
2631 const double O11 = op(qx,qy,qz,0,e);
2632 const double O12 = op(qx,qy,qz,1,e);
2633 const double O13 = op(qx,qy,qz,2,e);
2634 const double O22 = op(qx,qy,qz,3,e);
2635 const double O23 = op(qx,qy,qz,4,e);
2636 const double O33 = op(qx,qy,qz,5,e);
2637 const double massX = mass[qz][qy][qx][0];
2638 const double massY = mass[qz][qy][qx][1];
2639 const double massZ = mass[qz][qy][qx][2];
2640 mass[qz][qy][qx][0] = (O11*massX)+(O12*massY)+(O13*massZ);
2641 mass[qz][qy][qx][1] = (O12*massX)+(O22*massY)+(O23*massZ);
2642 mass[qz][qy][qx][2] = (O13*massX)+(O23*massY)+(O33*massZ);
2647 for (int qz = 0; qz < Q1D; ++qz)
2649 double massXY[MAX_D1D][MAX_D1D];
2653 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
2655 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
2656 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
2657 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
2659 for (int dy = 0; dy < D1Dy; ++dy)
2661 for (int dx = 0; dx < D1Dx; ++dx)
2663 massXY[dy][dx] = 0.0;
2666 for (int qy = 0; qy < Q1D; ++qy)
2668 double massX[MAX_D1D];
2669 for (int dx = 0; dx < D1Dx; ++dx)
2673 for (int qx = 0; qx < Q1D; ++qx)
2675 for (int dx = 0; dx < D1Dx; ++dx)
2677 massX[dx] += mass[qz][qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
2680 for (int dy = 0; dy < D1Dy; ++dy)
2682 const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
2683 for (int dx = 0; dx < D1Dx; ++dx)
2685 massXY[dy][dx] += massX[dx] * wy;
2690 for (int dz = 0; dz < D1Dz; ++dz)
2692 const double wz = (c == 2) ? Bot(dz,qz) : Bct(dz,qz);
2693 for (int dy = 0; dy < D1Dy; ++dy)
2695 for (int dx = 0; dx < D1Dx; ++dx)
2697 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += massXY[dy][dx] * wz;
2702 osc += D1Dx * D1Dy * D1Dz;
2705 }); // end of element loop
2708 // Apply to x corresponding to DOF's in H^1 (trial), whose gradients are
2709 // integrated against H(curl) test functions corresponding to y.
2710 void PAHcurlH1Apply2D(const int D1D,
2713 const Array<double> &bc,
2714 const Array<double> &gc,
2715 const Array<double> &bot,
2716 const Array<double> &bct,
2717 const Vector &pa_data,
2721 constexpr static int VDIM = 2;
2722 constexpr static int MAX_D1D = HCURL_MAX_D1D;
2723 constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
2725 auto Bc = Reshape(bc.Read(), Q1D, D1D);
2726 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2727 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
2728 auto Bct = Reshape(bct.Read(), D1D, Q1D);
2729 auto op = Reshape(pa_data.Read(), Q1D, Q1D, 3, NE);
2730 auto X = Reshape(x.Read(), D1D, D1D, NE);
2731 auto Y = Reshape(y.ReadWrite(), 2*(D1D-1)*D1D, NE);
2735 double mass[MAX_Q1D][MAX_Q1D][VDIM];
2737 for (int qy = 0; qy < Q1D; ++qy)
2739 for (int qx = 0; qx < Q1D; ++qx)
2741 for (int c = 0; c < VDIM; ++c)
2743 mass[qy][qx][c] = 0.0;
2748 for (int dy = 0; dy < D1D; ++dy)
2750 double gradX[MAX_Q1D][2];
2751 for (int qx = 0; qx < Q1D; ++qx)
2756 for (int dx = 0; dx < D1D; ++dx)
2758 const double s = X(dx,dy,e);
2759 for (int qx = 0; qx < Q1D; ++qx)
2761 gradX[qx][0] += s * Bc(qx,dx);
2762 gradX[qx][1] += s * Gc(qx,dx);
2765 for (int qy = 0; qy < Q1D; ++qy)
2767 const double wy = Bc(qy,dy);
2768 const double wDy = Gc(qy,dy);
2769 for (int qx = 0; qx < Q1D; ++qx)
2771 const double wx = gradX[qx][0];
2772 const double wDx = gradX[qx][1];
2773 mass[qy][qx][0] += wDx * wy;
2774 mass[qy][qx][1] += wx * wDy;
2779 // Apply D operator.
2780 for (int qy = 0; qy < Q1D; ++qy)
2782 for (int qx = 0; qx < Q1D; ++qx)
2784 const double O11 = op(qx,qy,0,e);
2785 const double O12 = op(qx,qy,1,e);
2786 const double O22 = op(qx,qy,2,e);
2787 const double massX = mass[qy][qx][0];
2788 const double massY = mass[qy][qx][1];
2789 mass[qy][qx][0] = (O11*massX)+(O12*massY);
2790 mass[qy][qx][1] = (O12*massX)+(O22*massY);
2794 for (int qy = 0; qy < Q1D; ++qy)
2798 for (int c = 0; c < VDIM; ++c) // loop over x, y components
2800 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
2801 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
2803 double massX[MAX_D1D];
2804 for (int dx = 0; dx < D1Dx; ++dx)
2808 for (int qx = 0; qx < Q1D; ++qx)
2810 for (int dx = 0; dx < D1Dx; ++dx)
2812 massX[dx] += mass[qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
2816 for (int dy = 0; dy < D1Dy; ++dy)
2818 const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
2820 for (int dx = 0; dx < D1Dx; ++dx)
2822 Y(dx + (dy * D1Dx) + osc, e) += massX[dx] * wy;
2829 }); // end of element loop
2832 // PA H(curl) Mass Assemble 3D kernel
2833 void PAHcurlL2Setup(const int NQ,
2836 const Array<double> &w,
2841 auto C = Reshape(coeff.Read(), coeffDim, NQ, NE);
2842 auto y = Reshape(op.Write(), coeffDim, NQ, NE);
2846 for (int q = 0; q < NQ; ++q)
2848 for (int c=0; c<coeffDim; ++c)
2850 y(c,q,e) = W[q] * C(c,q,e);
2856 void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
2857 const FiniteElementSpace &test_fes)
2859 // Assumes tensor-product elements, with vector test and trial spaces.
2860 Mesh *mesh = trial_fes.GetMesh();
2861 const FiniteElement *trial_fel = trial_fes.GetFE(0);
2862 const FiniteElement *test_fel = test_fes.GetFE(0);
2864 const VectorTensorFiniteElement *trial_el =
2865 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
2868 const VectorTensorFiniteElement *test_el =
2869 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
2872 const IntegrationRule *ir
2873 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
2874 *mesh->GetElementTransformation(0));
2875 const int dims = trial_el->GetDim();
2876 MFEM_VERIFY(dims == 3, "");
2878 const int nq = ir->GetNPoints();
2879 dim = mesh->Dimension();
2880 MFEM_VERIFY(dim == 3, "");
2882 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
2884 ne = trial_fes.GetNE();
2885 geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
2886 mapsC = &trial_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
2887 mapsO = &trial_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
2888 mapsCtest = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
2889 mapsOtest = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
2890 dofs1D = mapsC->ndof;
2891 quad1D = mapsC->nqpt;
2892 dofs1Dtest = mapsCtest->ndof;
2894 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
2896 testType = test_el->GetDerivType();
2897 trialType = trial_el->GetDerivType();
2899 const int symmDims = (dims * (dims + 1)) / 2; // 1x1: 1, 2x2: 3, 3x3: 6
2900 coeffDim = (DQ ? 3 : 1);
2902 pa_data.SetSize(symmDims * nq * ne, Device::GetMemoryType());
2904 Vector coeff(coeffDim * nq * ne);
2906 auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
2912 MFEM_VERIFY(DQ->GetVDim() == coeffDim, "");
2915 for (int e=0; e<ne; ++e)
2917 ElementTransformation *tr = mesh->GetElementTransformation(e);
2919 for (int p=0; p<nq; ++p)
2923 DQ->Eval(V, *tr, ir->IntPoint(p));
2924 for (int i=0; i<coeffDim; ++i)
2926 coeffh(i, p, e) = V[i];
2931 coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
2937 if (testType == mfem::FiniteElement::CURL &&
2938 trialType == mfem::FiniteElement::CURL && dim == 3)
2940 PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
2942 else if (testType == mfem::FiniteElement::DIV &&
2943 trialType == mfem::FiniteElement::CURL && dim == 3 &&
2944 test_fel->GetOrder() == trial_fel->GetOrder())
2946 PACurlCurlSetup3D(quad1D, coeffDim, ne, ir->GetWeights(), geom->J, coeff,
2951 MFEM_ABORT("Unknown kernel.
");
2955 // Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
2956 // integrated against H(curl) test functions corresponding to y.
2957 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
2958 static void PAHcurlL2Apply3D(const int D1D,
2962 const Array<double> &bo,
2963 const Array<double> &bc,
2964 const Array<double> &bot,
2965 const Array<double> &bct,
2966 const Array<double> &gc,
2967 const Vector &pa_data,
2971 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
2972 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
2973 // Using u = dF^{-T} \hat{u} and (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u} (p. 78 of Monk), we get
2974 // (\nabla\times u) \cdot v = 1/det(dF) \hat{\nabla}\times\hat{u}^T dF^T dF^{-T} \hat{v}
2975 // = 1/det(dF) \hat{\nabla}\times\hat{u}^T \hat{v}
2976 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
2977 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
2978 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
2980 constexpr static int VDIM = 3;
2982 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
2983 auto Bc = Reshape(bc.Read(), Q1D, D1D);
2984 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
2985 auto Bct = Reshape(bct.Read(), D1D, Q1D);
2986 auto Gc = Reshape(gc.Read(), Q1D, D1D);
2987 auto op = Reshape(pa_data.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
2988 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
2989 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
2993 double curl[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
2994 // curl[qz][qy][qx] will be computed as the vector curl at each quadrature point.
2996 for (int qz = 0; qz < Q1D; ++qz)
2998 for (int qy = 0; qy < Q1D; ++qy)
3000 for (int qx = 0; qx < Q1D; ++qx)
3002 for (int c = 0; c < VDIM; ++c)
3004 curl[qz][qy][qx][c] = 0.0;
3010 // We treat x, y, z components separately for optimization specific to each.
3016 const int D1Dz = D1D;
3017 const int D1Dy = D1D;
3018 const int D1Dx = D1D - 1;
3020 for (int dz = 0; dz < D1Dz; ++dz)
3022 double gradXY[MAX_Q1D][MAX_Q1D][2];
3023 for (int qy = 0; qy < Q1D; ++qy)
3025 for (int qx = 0; qx < Q1D; ++qx)
3027 for (int d = 0; d < 2; ++d)
3029 gradXY[qy][qx][d] = 0.0;
3034 for (int dy = 0; dy < D1Dy; ++dy)
3036 double massX[MAX_Q1D];
3037 for (int qx = 0; qx < Q1D; ++qx)
3042 for (int dx = 0; dx < D1Dx; ++dx)
3044 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3045 for (int qx = 0; qx < Q1D; ++qx)
3047 massX[qx] += t * Bo(qx,dx);
3051 for (int qy = 0; qy < Q1D; ++qy)
3053 const double wy = Bc(qy,dy);
3054 const double wDy = Gc(qy,dy);
3055 for (int qx = 0; qx < Q1D; ++qx)
3057 const double wx = massX[qx];
3058 gradXY[qy][qx][0] += wx * wDy;
3059 gradXY[qy][qx][1] += wx * wy;
3064 for (int qz = 0; qz < Q1D; ++qz)
3066 const double wz = Bc(qz,dz);
3067 const double wDz = Gc(qz,dz);
3068 for (int qy = 0; qy < Q1D; ++qy)
3070 for (int qx = 0; qx < Q1D; ++qx)
3072 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
3073 curl[qz][qy][qx][1] += gradXY[qy][qx][1] * wDz; // (u_0)_{x_2}
3074 curl[qz][qy][qx][2] -= gradXY[qy][qx][0] * wz; // -(u_0)_{x_1}
3080 osc += D1Dx * D1Dy * D1Dz;
3085 const int D1Dz = D1D;
3086 const int D1Dy = D1D - 1;
3087 const int D1Dx = D1D;
3089 for (int dz = 0; dz < D1Dz; ++dz)
3091 double gradXY[MAX_Q1D][MAX_Q1D][2];
3092 for (int qy = 0; qy < Q1D; ++qy)
3094 for (int qx = 0; qx < Q1D; ++qx)
3096 for (int d = 0; d < 2; ++d)
3098 gradXY[qy][qx][d] = 0.0;
3103 for (int dx = 0; dx < D1Dx; ++dx)
3105 double massY[MAX_Q1D];
3106 for (int qy = 0; qy < Q1D; ++qy)
3111 for (int dy = 0; dy < D1Dy; ++dy)
3113 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3114 for (int qy = 0; qy < Q1D; ++qy)
3116 massY[qy] += t * Bo(qy,dy);
3120 for (int qx = 0; qx < Q1D; ++qx)
3122 const double wx = Bc(qx,dx);
3123 const double wDx = Gc(qx,dx);
3124 for (int qy = 0; qy < Q1D; ++qy)
3126 const double wy = massY[qy];
3127 gradXY[qy][qx][0] += wDx * wy;
3128 gradXY[qy][qx][1] += wx * wy;
3133 for (int qz = 0; qz < Q1D; ++qz)
3135 const double wz = Bc(qz,dz);
3136 const double wDz = Gc(qz,dz);
3137 for (int qy = 0; qy < Q1D; ++qy)
3139 for (int qx = 0; qx < Q1D; ++qx)
3141 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
3142 curl[qz][qy][qx][0] -= gradXY[qy][qx][1] * wDz; // -(u_1)_{x_2}
3143 curl[qz][qy][qx][2] += gradXY[qy][qx][0] * wz; // (u_1)_{x_0}
3149 osc += D1Dx * D1Dy * D1Dz;
3154 const int D1Dz = D1D - 1;
3155 const int D1Dy = D1D;
3156 const int D1Dx = D1D;
3158 for (int dx = 0; dx < D1Dx; ++dx)
3160 double gradYZ[MAX_Q1D][MAX_Q1D][2];
3161 for (int qz = 0; qz < Q1D; ++qz)
3163 for (int qy = 0; qy < Q1D; ++qy)
3165 for (int d = 0; d < 2; ++d)
3167 gradYZ[qz][qy][d] = 0.0;
3172 for (int dy = 0; dy < D1Dy; ++dy)
3174 double massZ[MAX_Q1D];
3175 for (int qz = 0; qz < Q1D; ++qz)
3180 for (int dz = 0; dz < D1Dz; ++dz)
3182 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3183 for (int qz = 0; qz < Q1D; ++qz)
3185 massZ[qz] += t * Bo(qz,dz);
3189 for (int qy = 0; qy < Q1D; ++qy)
3191 const double wy = Bc(qy,dy);
3192 const double wDy = Gc(qy,dy);
3193 for (int qz = 0; qz < Q1D; ++qz)
3195 const double wz = massZ[qz];
3196 gradYZ[qz][qy][0] += wz * wy;
3197 gradYZ[qz][qy][1] += wz * wDy;
3202 for (int qx = 0; qx < Q1D; ++qx)
3204 const double wx = Bc(qx,dx);
3205 const double wDx = Gc(qx,dx);
3207 for (int qy = 0; qy < Q1D; ++qy)
3209 for (int qz = 0; qz < Q1D; ++qz)
3211 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
3212 curl[qz][qy][qx][0] += gradYZ[qz][qy][1] * wx; // (u_2)_{x_1}
3213 curl[qz][qy][qx][1] -= gradYZ[qz][qy][0] * wDx; // -(u_2)_{x_0}
3220 // Apply D operator.
3221 for (int qz = 0; qz < Q1D; ++qz)
3223 for (int qy = 0; qy < Q1D; ++qy)
3225 for (int qx = 0; qx < Q1D; ++qx)
3227 for (int c = 0; c < VDIM; ++c)
3229 curl[qz][qy][qx][c] *= op(coeffDim == 3 ? c : 0, qx,qy,qz,e);
3235 for (int qz = 0; qz < Q1D; ++qz)
3237 double massXY[MAX_D1D][MAX_D1D];
3241 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
3243 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
3244 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
3245 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
3247 for (int dy = 0; dy < D1Dy; ++dy)
3249 for (int dx = 0; dx < D1Dx; ++dx)
3254 for (int qy = 0; qy < Q1D; ++qy)
3256 double massX[MAX_D1D];
3257 for (int dx = 0; dx < D1Dx; ++dx)
3261 for (int qx = 0; qx < Q1D; ++qx)
3263 for (int dx = 0; dx < D1Dx; ++dx)
3265 massX[dx] += curl[qz][qy][qx][c] * ((c == 0) ? Bot(dx,qx) : Bct(dx,qx));
3269 for (int dy = 0; dy < D1Dy; ++dy)
3271 const double wy = (c == 1) ? Bot(dy,qy) : Bct(dy,qy);
3272 for (int dx = 0; dx < D1Dx; ++dx)
3274 massXY[dy][dx] += massX[dx] * wy;
3279 for (int dz = 0; dz < D1Dz; ++dz)
3281 const double wz = (c == 2) ? Bot(dz,qz) : Bct(dz,qz);
3282 for (int dy = 0; dy < D1Dy; ++dy)
3284 for (int dx = 0; dx < D1Dx; ++dx)
3286 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) += massXY[dy][dx] * wz;
3291 osc += D1Dx * D1Dy * D1Dz;
3294 }); // end of element loop
3297 // Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
3298 // integrated against H(curl) test functions corresponding to y.
3299 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
3300 static void SmemPAHcurlL2Apply3D(const int D1D,
3304 const Array<double> &bo,
3305 const Array<double> &bc,
3306 const Array<double> &gc,
3307 const Vector &pa_data,
3311 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
3312 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
3314 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
3315 auto Bc = Reshape(bc.Read(), Q1D, D1D);
3316 auto Gc = Reshape(gc.Read(), Q1D, D1D);
3317 auto op = Reshape(pa_data.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
3318 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
3319 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
3321 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
3323 constexpr int VDIM = 3;
3324 constexpr int maxCoeffDim = 3;
3326 MFEM_SHARED double sBo[MAX_D1D][MAX_Q1D];
3327 MFEM_SHARED double sBc[MAX_D1D][MAX_Q1D];
3328 MFEM_SHARED double sGc[MAX_D1D][MAX_Q1D];
3330 double opc[maxCoeffDim];
3331 MFEM_SHARED double sop[maxCoeffDim][MAX_Q1D][MAX_Q1D];
3332 MFEM_SHARED double curl[MAX_Q1D][MAX_Q1D][3];
3334 MFEM_SHARED double sX[MAX_D1D][MAX_D1D][MAX_D1D];
3336 MFEM_FOREACH_THREAD(qx,x,Q1D)
3338 MFEM_FOREACH_THREAD(qy,y,Q1D)
3340 MFEM_FOREACH_THREAD(qz,z,Q1D)
3342 for (int i=0; i<coeffDim; ++i)
3344 opc[i] = op(i,qx,qy,qz,e);
3350 const int tidx = MFEM_THREAD_ID(x);
3351 const int tidy = MFEM_THREAD_ID(y);
3352 const int tidz = MFEM_THREAD_ID(z);
3356 MFEM_FOREACH_THREAD(d,y,D1D)
3358 MFEM_FOREACH_THREAD(q,x,Q1D)
3360 sBc[d][q] = Bc(q,d);
3361 sGc[d][q] = Gc(q,d);
3364 sBo[d][q] = Bo(q,d);
3371 for (int qz=0; qz < Q1D; ++qz)
3375 MFEM_FOREACH_THREAD(qy,y,Q1D)
3377 MFEM_FOREACH_THREAD(qx,x,Q1D)
3379 for (int i=0; i<3; ++i)
3381 curl[qy][qx][i] = 0.0;
3388 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
3390 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
3391 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
3392 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
3394 MFEM_FOREACH_THREAD(dz,z,D1Dz)
3396 MFEM_FOREACH_THREAD(dy,y,D1Dy)
3398 MFEM_FOREACH_THREAD(dx,x,D1Dx)
3400 sX[dz][dy][dx] = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3410 for (int i=0; i<coeffDim; ++i)
3412 sop[i][tidx][tidy] = opc[i];
3416 MFEM_FOREACH_THREAD(qy,y,Q1D)
3418 MFEM_FOREACH_THREAD(qx,x,Q1D)
3423 // We treat x, y, z components separately for optimization specific to each.
3424 if (c == 0) // x component
3426 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
3428 for (int dz = 0; dz < D1Dz; ++dz)
3430 const double wz = sBc[dz][qz];
3431 const double wDz = sGc[dz][qz];
3433 for (int dy = 0; dy < D1Dy; ++dy)
3435 const double wy = sBc[dy][qy];
3436 const double wDy = sGc[dy][qy];
3438 for (int dx = 0; dx < D1Dx; ++dx)
3440 const double wx = sX[dz][dy][dx] * sBo[dx][qx];
3447 curl[qy][qx][1] += v; // (u_0)_{x_2}
3448 curl[qy][qx][2] -= u; // -(u_0)_{x_1}
3450 else if (c == 1) // y component
3452 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
3454 for (int dz = 0; dz < D1Dz; ++dz)
3456 const double wz = sBc[dz][qz];
3457 const double wDz = sGc[dz][qz];
3459 for (int dy = 0; dy < D1Dy; ++dy)
3461 const double wy = sBo[dy][qy];
3463 for (int dx = 0; dx < D1Dx; ++dx)
3465 const double t = sX[dz][dy][dx];
3466 const double wx = t * sBc[dx][qx];
3467 const double wDx = t * sGc[dx][qx];
3475 curl[qy][qx][0] -= v; // -(u_1)_{x_2}
3476 curl[qy][qx][2] += u; // (u_1)_{x_0}
3480 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
3482 for (int dz = 0; dz < D1Dz; ++dz)
3484 const double wz = sBo[dz][qz];
3486 for (int dy = 0; dy < D1Dy; ++dy)
3488 const double wy = sBc[dy][qy];
3489 const double wDy = sGc[dy][qy];
3491 for (int dx = 0; dx < D1Dx; ++dx)
3493 const double t = sX[dz][dy][dx];
3494 const double wx = t * sBc[dx][qx];
3495 const double wDx = t * sGc[dx][qx];
3503 curl[qy][qx][0] += v; // (u_2)_{x_1}
3504 curl[qy][qx][1] -= u; // -(u_2)_{x_0}
3510 osc += D1Dx * D1Dy * D1Dz;
3518 MFEM_FOREACH_THREAD(dz,z,D1D)
3520 const double wcz = sBc[dz][qz];
3521 const double wz = (dz < D1D-1) ? sBo[dz][qz] : 0.0;
3523 MFEM_FOREACH_THREAD(dy,y,D1D)
3525 MFEM_FOREACH_THREAD(dx,x,D1D)
3527 for (int qy = 0; qy < Q1D; ++qy)
3529 const double wcy = sBc[dy][qy];
3530 const double wy = (dy < D1D-1) ? sBo[dy][qy] : 0.0;
3532 for (int qx = 0; qx < Q1D; ++qx)
3534 const double O1 = sop[0][qx][qy];
3535 const double O2 = (coeffDim == 3) ? sop[1][qx][qy] : O1;
3536 const double O3 = (coeffDim == 3) ? sop[2][qx][qy] : O1;
3538 const double c1 = O1 * curl[qy][qx][0];
3539 const double c2 = O2 * curl[qy][qx][1];
3540 const double c3 = O3 * curl[qy][qx][2];
3542 const double wcx = sBc[dx][qx];
3546 const double wx = sBo[dx][qx];
3547 dxyz1 += c1 * wx * wcy * wcz;
3550 dxyz2 += c2 * wcx * wy * wcz;
3551 dxyz3 += c3 * wcx * wcy * wz;
3560 MFEM_FOREACH_THREAD(dz,z,D1D)
3562 MFEM_FOREACH_THREAD(dy,y,D1D)
3564 MFEM_FOREACH_THREAD(dx,x,D1D)
3568 Y(dx + ((dy + (dz * D1D)) * (D1D-1)), e) += dxyz1;
3572 Y(dx + ((dy + (dz * (D1D-1))) * D1D) + ((D1D-1)*D1D*D1D), e) += dxyz2;
3576 Y(dx + ((dy + (dz * D1D)) * D1D) + (2*(D1D-1)*D1D*D1D), e) += dxyz3;
3582 }); // end of element loop
3585 // Apply to x corresponding to DOF's in H(curl) (trial), whose curl is
3586 // integrated against H(div) test functions corresponding to y.
3587 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
3588 static void PAHcurlHdivApply3D(const int D1D,
3592 const Array<double> &bo,
3593 const Array<double> &bc,
3594 const Array<double> &bot,
3595 const Array<double> &bct,
3596 const Array<double> &gc,
3597 const Vector &pa_data,
3601 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
3602 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
3603 // Using Piola transformations (\nabla\times u) F = 1/det(dF) dF \hat{\nabla}\times\hat{u}
3604 // for u in H(curl) and w = (1 / det (dF)) dF \hat{w} for w in H(div), we get
3605 // (\nabla\times u) \cdot w = 1/det(dF)^2 \hat{\nabla}\times\hat{u}^T dF^T dF \hat{w}
3606 // If c = 0, \hat{\nabla}\times\hat{u} reduces to [0, (u_0)_{x_2}, -(u_0)_{x_1}]
3607 // If c = 1, \hat{\nabla}\times\hat{u} reduces to [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
3608 // If c = 2, \hat{\nabla}\times\hat{u} reduces to [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
3610 constexpr static int VDIM = 3;
3612 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
3613 auto Bc = Reshape(bc.Read(), Q1D, D1D);
3614 auto Bot = Reshape(bot.Read(), D1Dtest-1, Q1D);
3615 auto Bct = Reshape(bct.Read(), D1Dtest, Q1D);
3616 auto Gc = Reshape(gc.Read(), Q1D, D1D);
3617 auto op = Reshape(pa_data.Read(), Q1D, Q1D, Q1D, 6, NE);
3618 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
3619 auto Y = Reshape(y.ReadWrite(), 3*(D1Dtest-1)*(D1Dtest-1)*D1D, NE);
3623 double curl[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
3624 // curl[qz][qy][qx] will be computed as the vector curl at each quadrature point.
3626 for (int qz = 0; qz < Q1D; ++qz)
3628 for (int qy = 0; qy < Q1D; ++qy)
3630 for (int qx = 0; qx < Q1D; ++qx)
3632 for (int c = 0; c < VDIM; ++c)
3634 curl[qz][qy][qx][c] = 0.0;
3640 // We treat x, y, z components separately for optimization specific to each.
3646 const int D1Dz = D1D;
3647 const int D1Dy = D1D;
3648 const int D1Dx = D1D - 1;
3650 for (int dz = 0; dz < D1Dz; ++dz)
3652 double gradXY[MAX_Q1D][MAX_Q1D][2];
3653 for (int qy = 0; qy < Q1D; ++qy)
3655 for (int qx = 0; qx < Q1D; ++qx)
3657 for (int d = 0; d < 2; ++d)
3659 gradXY[qy][qx][d] = 0.0;
3664 for (int dy = 0; dy < D1Dy; ++dy)
3666 double massX[MAX_Q1D];
3667 for (int qx = 0; qx < Q1D; ++qx)
3672 for (int dx = 0; dx < D1Dx; ++dx)
3674 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3675 for (int qx = 0; qx < Q1D; ++qx)
3677 massX[qx] += t * Bo(qx,dx);
3681 for (int qy = 0; qy < Q1D; ++qy)
3683 const double wy = Bc(qy,dy);
3684 const double wDy = Gc(qy,dy);
3685 for (int qx = 0; qx < Q1D; ++qx)
3687 const double wx = massX[qx];
3688 gradXY[qy][qx][0] += wx * wDy;
3689 gradXY[qy][qx][1] += wx * wy;
3694 for (int qz = 0; qz < Q1D; ++qz)
3696 const double wz = Bc(qz,dz);
3697 const double wDz = Gc(qz,dz);
3698 for (int qy = 0; qy < Q1D; ++qy)
3700 for (int qx = 0; qx < Q1D; ++qx)
3702 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
3703 curl[qz][qy][qx][1] += gradXY[qy][qx][1] * wDz; // (u_0)_{x_2}
3704 curl[qz][qy][qx][2] -= gradXY[qy][qx][0] * wz; // -(u_0)_{x_1}
3710 osc += D1Dx * D1Dy * D1Dz;
3715 const int D1Dz = D1D;
3716 const int D1Dy = D1D - 1;
3717 const int D1Dx = D1D;
3719 for (int dz = 0; dz < D1Dz; ++dz)
3721 double gradXY[MAX_Q1D][MAX_Q1D][2];
3722 for (int qy = 0; qy < Q1D; ++qy)
3724 for (int qx = 0; qx < Q1D; ++qx)
3726 for (int d = 0; d < 2; ++d)
3728 gradXY[qy][qx][d] = 0.0;
3733 for (int dx = 0; dx < D1Dx; ++dx)
3735 double massY[MAX_Q1D];
3736 for (int qy = 0; qy < Q1D; ++qy)
3741 for (int dy = 0; dy < D1Dy; ++dy)
3743 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3744 for (int qy = 0; qy < Q1D; ++qy)
3746 massY[qy] += t * Bo(qy,dy);
3750 for (int qx = 0; qx < Q1D; ++qx)
3752 const double wx = Bc(qx,dx);
3753 const double wDx = Gc(qx,dx);
3754 for (int qy = 0; qy < Q1D; ++qy)
3756 const double wy = massY[qy];
3757 gradXY[qy][qx][0] += wDx * wy;
3758 gradXY[qy][qx][1] += wx * wy;
3763 for (int qz = 0; qz < Q1D; ++qz)
3765 const double wz = Bc(qz,dz);
3766 const double wDz = Gc(qz,dz);
3767 for (int qy = 0; qy < Q1D; ++qy)
3769 for (int qx = 0; qx < Q1D; ++qx)
3771 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
3772 curl[qz][qy][qx][0] -= gradXY[qy][qx][1] * wDz; // -(u_1)_{x_2}
3773 curl[qz][qy][qx][2] += gradXY[qy][qx][0] * wz; // (u_1)_{x_0}
3779 osc += D1Dx * D1Dy * D1Dz;
3784 const int D1Dz = D1D - 1;
3785 const int D1Dy = D1D;
3786 const int D1Dx = D1D;
3788 for (int dx = 0; dx < D1Dx; ++dx)
3790 double gradYZ[MAX_Q1D][MAX_Q1D][2];
3791 for (int qz = 0; qz < Q1D; ++qz)
3793 for (int qy = 0; qy < Q1D; ++qy)
3795 for (int d = 0; d < 2; ++d)
3797 gradYZ[qz][qy][d] = 0.0;
3802 for (int dy = 0; dy < D1Dy; ++dy)
3804 double massZ[MAX_Q1D];
3805 for (int qz = 0; qz < Q1D; ++qz)
3810 for (int dz = 0; dz < D1Dz; ++dz)
3812 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
3813 for (int qz = 0; qz < Q1D; ++qz)
3815 massZ[qz] += t * Bo(qz,dz);
3819 for (int qy = 0; qy < Q1D; ++qy)
3821 const double wy = Bc(qy,dy);
3822 const double wDy = Gc(qy,dy);
3823 for (int qz = 0; qz < Q1D; ++qz)
3825 const double wz = massZ[qz];
3826 gradYZ[qz][qy][0] += wz * wy;
3827 gradYZ[qz][qy][1] += wz * wDy;
3832 for (int qx = 0; qx < Q1D; ++qx)
3834 const double wx = Bc(qx,dx);
3835 const double wDx = Gc(qx,dx);
3837 for (int qy = 0; qy < Q1D; ++qy)
3839 for (int qz = 0; qz < Q1D; ++qz)
3841 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
3842 curl[qz][qy][qx][0] += gradYZ[qz][qy][1] * wx; // (u_2)_{x_1}
3843 curl[qz][qy][qx][1] -= gradYZ[qz][qy][0] * wDx; // -(u_2)_{x_0}
3850 // Apply D operator.
3851 for (int qz = 0; qz < Q1D; ++qz)
3853 for (int qy = 0; qy < Q1D; ++qy)
3855 for (int qx = 0; qx < Q1D; ++qx)
3857 const double O11 = op(qx,qy,qz,0,e);
3858 const double O12 = op(qx,qy,qz,1,e);
3859 const double O13 = op(qx,qy,qz,2,e);
3860 const double O22 = op(qx,qy,qz,3,e);
3861 const double O23 = op(qx,qy,qz,4,e);
3862 const double O33 = op(qx,qy,qz,5,e);
3864 const double c1 = (O11 * curl[qz][qy][qx][0]) + (O12 * curl[qz][qy][qx][1]) +
3865 (O13 * curl[qz][qy][qx][2]);
3866 const double c2 = (O12 * curl[qz][qy][qx][0]) + (O22 * curl[qz][qy][qx][1]) +
3867 (O23 * curl[qz][qy][qx][2]);
3868 const double c3 = (O13 * curl[qz][qy][qx][0]) + (O23 * curl[qz][qy][qx][1]) +
3869 (O33 * curl[qz][qy][qx][2]);
3871 curl[qz][qy][qx][0] = c1;
3872 curl[qz][qy][qx][1] = c2;
3873 curl[qz][qy][qx][2] = c3;
3878 for (int qz = 0; qz < Q1D; ++qz)
3880 double massXY[HCURL_MAX_D1D][HCURL_MAX_D1D]; // Assuming HDIV_MAX_D1D <= HCURL_MAX_D1D
3884 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
3886 const int D1Dz = (c == 2) ? D1Dtest : D1Dtest - 1;
3887 const int D1Dy = (c == 1) ? D1Dtest : D1Dtest - 1;
3888 const int D1Dx = (c == 0) ? D1Dtest : D1Dtest - 1;
3890 for (int dy = 0; dy < D1Dy; ++dy)
3892 for (int dx = 0; dx < D1Dx; ++dx)
3897 for (int qy = 0; qy < Q1D; ++qy)
3899 double massX[HCURL_MAX_D1D];
3900 for (int dx = 0; dx < D1Dx; ++dx)
3904 for (int qx = 0; qx < Q1D; ++qx)
3906 for (int dx = 0; dx < D1Dx; ++dx)
3908 massX[dx] += curl[qz][qy][qx][c] *
3909 ((c == 0) ? Bct(dx,qx) : Bot(dx,qx));
3912 for (int dy = 0; dy < D1Dy; ++dy)
3914 const double wy = (c == 1) ? Bct(dy,qy) : Bot(dy,qy);
3915 for (int dx = 0; dx < D1Dx; ++dx)
3917 massXY[dy][dx] += massX[dx] * wy;
3922 for (int dz = 0; dz < D1Dz; ++dz)
3924 const double wz = (c == 2) ? Bct(dz,qz) : Bot(dz,qz);
3925 for (int dy = 0; dy < D1Dy; ++dy)
3927 for (int dx = 0; dx < D1Dx; ++dx)
3929 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e) +=
3930 massXY[dy][dx] * wz;
3935 osc += D1Dx * D1Dy * D1Dz;
3938 }); // end of element loop
3941 void MixedVectorCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
3943 if (testType == mfem::FiniteElement::CURL &&
3944 trialType == mfem::FiniteElement::CURL && dim == 3)
3946 if (Device::Allows(Backend::DEVICE_MASK))
3948 const int ID = (dofs1D << 4) | quad1D;
3951 case 0x23: return SmemPAHcurlL2Apply3D<2,3>(dofs1D, quad1D, coeffDim, ne,
3953 mapsC->G, pa_data, x, y);
3954 case 0x34: return SmemPAHcurlL2Apply3D<3,4>(dofs1D, quad1D, coeffDim, ne,
3956 mapsC->G, pa_data, x, y);
3957 case 0x45: return SmemPAHcurlL2Apply3D<4,5>(dofs1D, quad1D, coeffDim, ne,
3959 mapsC->G, pa_data, x, y);
3960 case 0x56: return SmemPAHcurlL2Apply3D<5,6>(dofs1D, quad1D, coeffDim, ne,
3962 mapsC->G, pa_data, x, y);
3963 default: return SmemPAHcurlL2Apply3D(dofs1D, quad1D, coeffDim, ne, mapsO->B,
3965 mapsC->G, pa_data, x, y);
3969 PAHcurlL2Apply3D(dofs1D, quad1D, coeffDim, ne, mapsO->B, mapsC->B,
3970 mapsO->Bt, mapsC->Bt, mapsC->G, pa_data, x, y);
3972 else if (testType == mfem::FiniteElement::DIV &&
3973 trialType == mfem::FiniteElement::CURL && dim == 3)
3974 PAHcurlHdivApply3D(dofs1D, dofs1Dtest, quad1D, ne, mapsO->B,
3975 mapsC->B, mapsOtest->Bt, mapsCtest->Bt, mapsC->G,
3979 MFEM_ABORT("Unsupported dimension or
space!
");
3983 void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
3985 const FiniteElementSpace &test_fes)
3987 // Assumes tensor-product elements, with vector test and trial spaces.
3988 Mesh *mesh = trial_fes.GetMesh();
3989 const FiniteElement *trial_fel = trial_fes.GetFE(0);
3990 const FiniteElement *test_fel = test_fes.GetFE(0);
3992 const VectorTensorFiniteElement *trial_el =
3993 dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
3996 const VectorTensorFiniteElement *test_el =
3997 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
4000 const IntegrationRule *ir
4001 = IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
4002 *mesh->GetElementTransformation(0));
4003 const int dims = trial_el->GetDim();
4004 MFEM_VERIFY(dims == 3, "");
4006 const int nq = ir->GetNPoints();
4007 dim = mesh->Dimension();
4008 MFEM_VERIFY(dim == 3, "");
4010 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
4012 ne = trial_fes.GetNE();
4013 geom = mesh->GetGeometricFactors(*ir, GeometricFactors::JACOBIANS);
4014 mapsC = &test_el->GetDofToQuad(*ir, DofToQuad::TENSOR);
4015 mapsO = &test_el->GetDofToQuadOpen(*ir, DofToQuad::TENSOR);
4016 dofs1D = mapsC->ndof;
4017 quad1D = mapsC->nqpt;
4019 MFEM_VERIFY(dofs1D == mapsO->ndof + 1 && quad1D == mapsO->nqpt, "");
4021 coeffDim = DQ ? 3 : 1;
4023 pa_data.SetSize(coeffDim * nq * ne, Device::GetMemoryType());
4025 Vector coeff(coeffDim * nq * ne);
4027 auto coeffh = Reshape(coeff.HostWrite(), coeffDim, nq, ne);
4033 MFEM_VERIFY(DQ->GetVDim() == coeffDim, "");
4036 for (int e=0; e<ne; ++e)
4038 ElementTransformation *tr = mesh->GetElementTransformation(e);
4040 for (int p=0; p<nq; ++p)
4044 DQ->Eval(V, *tr, ir->IntPoint(p));
4045 for (int i=0; i<coeffDim; ++i)
4047 coeffh(i, p, e) = V[i];
4052 coeffh(0, p, e) = Q->Eval(*tr, ir->IntPoint(p));
4058 testType = test_el->GetDerivType();
4059 trialType = trial_el->GetDerivType();
4061 if (trialType == mfem::FiniteElement::CURL && dim == 3)
4063 PAHcurlL2Setup(nq, coeffDim, ne, ir->GetWeights(), coeff, pa_data);
4067 MFEM_ABORT("Unknown kernel.
");
4071 // Apply to x corresponding to DOF's in H(curl) (trial), integrated against curl
4072 // of H(curl) test functions corresponding to y.
4073 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
4074 static void PAHcurlL2Apply3DTranspose(const int D1D,
4078 const Array<double> &bo,
4079 const Array<double> &bc,
4080 const Array<double> &bot,
4081 const Array<double> &bct,
4082 const Array<double> &gct,
4083 const Vector &pa_data,
4087 // See PAHcurlL2Apply3D for comments.
4089 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
4090 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
4092 constexpr static int VDIM = 3;
4094 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
4095 auto Bc = Reshape(bc.Read(), Q1D, D1D);
4096 auto Bot = Reshape(bot.Read(), D1D-1, Q1D);
4097 auto Bct = Reshape(bct.Read(), D1D, Q1D);
4098 auto Gct = Reshape(gct.Read(), D1D, Q1D);
4099 auto op = Reshape(pa_data.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
4100 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
4101 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
4105 double mass[MAX_Q1D][MAX_Q1D][MAX_Q1D][VDIM];
4107 for (int qz = 0; qz < Q1D; ++qz)
4109 for (int qy = 0; qy < Q1D; ++qy)
4111 for (int qx = 0; qx < Q1D; ++qx)
4113 for (int c = 0; c < VDIM; ++c)
4115 mass[qz][qy][qx][c] = 0.0;
4123 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
4125 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
4126 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
4127 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
4129 for (int dz = 0; dz < D1Dz; ++dz)
4131 double massXY[MAX_Q1D][MAX_Q1D];
4132 for (int qy = 0; qy < Q1D; ++qy)
4134 for (int qx = 0; qx < Q1D; ++qx)
4136 massXY[qy][qx] = 0.0;
4140 for (int dy = 0; dy < D1Dy; ++dy)
4142 double massX[MAX_Q1D];
4143 for (int qx = 0; qx < Q1D; ++qx)
4148 for (int dx = 0; dx < D1Dx; ++dx)
4150 const double t = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
4151 for (int qx = 0; qx < Q1D; ++qx)
4153 massX[qx] += t * ((c == 0) ? Bo(qx,dx) : Bc(qx,dx));
4157 for (int qy = 0; qy < Q1D; ++qy)
4159 const double wy = (c == 1) ? Bo(qy,dy) : Bc(qy,dy);
4160 for (int qx = 0; qx < Q1D; ++qx)
4162 const double wx = massX[qx];
4163 massXY[qy][qx] += wx * wy;
4168 for (int qz = 0; qz < Q1D; ++qz)
4170 const double wz = (c == 2) ? Bo(qz,dz) : Bc(qz,dz);
4171 for (int qy = 0; qy < Q1D; ++qy)
4173 for (int qx = 0; qx < Q1D; ++qx)
4175 mass[qz][qy][qx][c] += massXY[qy][qx] * wz;
4181 osc += D1Dx * D1Dy * D1Dz;
4182 } // loop (c) over components
4184 // Apply D operator.
4185 for (int qz = 0; qz < Q1D; ++qz)
4187 for (int qy = 0; qy < Q1D; ++qy)
4189 for (int qx = 0; qx < Q1D; ++qx)
4191 for (int c=0; c<VDIM; ++c)
4193 mass[qz][qy][qx][c] *= op(coeffDim == 3 ? c : 0, qx,qy,qz,e);
4202 const int D1Dz = D1D;
4203 const int D1Dy = D1D;
4204 const int D1Dx = D1D - 1;
4206 for (int qz = 0; qz < Q1D; ++qz)
4208 double gradXY12[MAX_D1D][MAX_D1D];
4209 double gradXY21[MAX_D1D][MAX_D1D];
4211 for (int dy = 0; dy < D1Dy; ++dy)
4213 for (int dx = 0; dx < D1Dx; ++dx)
4215 gradXY12[dy][dx] = 0.0;
4216 gradXY21[dy][dx] = 0.0;
4219 for (int qy = 0; qy < Q1D; ++qy)
4221 double massX[MAX_D1D][2];
4222 for (int dx = 0; dx < D1Dx; ++dx)
4224 for (int n = 0; n < 2; ++n)
4229 for (int qx = 0; qx < Q1D; ++qx)
4231 for (int dx = 0; dx < D1Dx; ++dx)
4233 const double wx = Bot(dx,qx);
4235 massX[dx][0] += wx * mass[qz][qy][qx][1];
4236 massX[dx][1] += wx * mass[qz][qy][qx][2];
4239 for (int dy = 0; dy < D1Dy; ++dy)
4241 const double wy = Bct(dy,qy);
4242 const double wDy = Gct(dy,qy);
4244 for (int dx = 0; dx < D1Dx; ++dx)
4246 gradXY21[dy][dx] += massX[dx][0] * wy;
4247 gradXY12[dy][dx] += massX[dx][1] * wDy;
4252 for (int dz = 0; dz < D1Dz; ++dz)
4254 const double wz = Bct(dz,qz);
4255 const double wDz = Gct(dz,qz);
4256 for (int dy = 0; dy < D1Dy; ++dy)
4258 for (int dx = 0; dx < D1Dx; ++dx)
4260 // \hat{\nabla}\times\hat{u} is [0, (u_0)_{x_2}, -(u_0)_{x_1}]
4261 // (u_0)_{x_2} * (op * curl)_1 - (u_0)_{x_1} * (op * curl)_2
4262 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
4263 e) += (gradXY21[dy][dx] * wDz) - (gradXY12[dy][dx] * wz);
4269 osc += D1Dx * D1Dy * D1Dz;
4274 const int D1Dz = D1D;
4275 const int D1Dy = D1D - 1;
4276 const int D1Dx = D1D;
4278 for (int qz = 0; qz < Q1D; ++qz)
4280 double gradXY02[MAX_D1D][MAX_D1D];
4281 double gradXY20[MAX_D1D][MAX_D1D];
4283 for (int dy = 0; dy < D1Dy; ++dy)
4285 for (int dx = 0; dx < D1Dx; ++dx)
4287 gradXY02[dy][dx] = 0.0;
4288 gradXY20[dy][dx] = 0.0;
4291 for (int qx = 0; qx < Q1D; ++qx)
4293 double massY[MAX_D1D][2];
4294 for (int dy = 0; dy < D1Dy; ++dy)
4299 for (int qy = 0; qy < Q1D; ++qy)
4301 for (int dy = 0; dy < D1Dy; ++dy)
4303 const double wy = Bot(dy,qy);
4305 massY[dy][0] += wy * mass[qz][qy][qx][2];
4306 massY[dy][1] += wy * mass[qz][qy][qx][0];
4309 for (int dx = 0; dx < D1Dx; ++dx)
4311 const double wx = Bct(dx,qx);
4312 const double wDx = Gct(dx,qx);
4314 for (int dy = 0; dy < D1Dy; ++dy)
4316 gradXY02[dy][dx] += massY[dy][0] * wDx;
4317 gradXY20[dy][dx] += massY[dy][1] * wx;
4322 for (int dz = 0; dz < D1Dz; ++dz)
4324 const double wz = Bct(dz,qz);
4325 const double wDz = Gct(dz,qz);
4326 for (int dy = 0; dy < D1Dy; ++dy)
4328 for (int dx = 0; dx < D1Dx; ++dx)
4330 // \hat{\nabla}\times\hat{u} is [-(u_1)_{x_2}, 0, (u_1)_{x_0}]
4331 // -(u_1)_{x_2} * (op * curl)_0 + (u_1)_{x_0} * (op * curl)_2
4332 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
4333 e) += (-gradXY20[dy][dx] * wDz) + (gradXY02[dy][dx] * wz);
4339 osc += D1Dx * D1Dy * D1Dz;
4344 const int D1Dz = D1D - 1;
4345 const int D1Dy = D1D;
4346 const int D1Dx = D1D;
4348 for (int qx = 0; qx < Q1D; ++qx)
4350 double gradYZ01[MAX_D1D][MAX_D1D];
4351 double gradYZ10[MAX_D1D][MAX_D1D];
4353 for (int dy = 0; dy < D1Dy; ++dy)
4355 for (int dz = 0; dz < D1Dz; ++dz)
4357 gradYZ01[dz][dy] = 0.0;
4358 gradYZ10[dz][dy] = 0.0;
4361 for (int qy = 0; qy < Q1D; ++qy)
4363 double massZ[MAX_D1D][2];
4364 for (int dz = 0; dz < D1Dz; ++dz)
4366 for (int n = 0; n < 2; ++n)
4371 for (int qz = 0; qz < Q1D; ++qz)
4373 for (int dz = 0; dz < D1Dz; ++dz)
4375 const double wz = Bot(dz,qz);
4377 massZ[dz][0] += wz * mass[qz][qy][qx][0];
4378 massZ[dz][1] += wz * mass[qz][qy][qx][1];
4381 for (int dy = 0; dy < D1Dy; ++dy)
4383 const double wy = Bct(dy,qy);
4384 const double wDy = Gct(dy,qy);
4386 for (int dz = 0; dz < D1Dz; ++dz)
4388 gradYZ01[dz][dy] += wy * massZ[dz][1];
4389 gradYZ10[dz][dy] += wDy * massZ[dz][0];
4394 for (int dx = 0; dx < D1Dx; ++dx)
4396 const double wx = Bct(dx,qx);
4397 const double wDx = Gct(dx,qx);
4399 for (int dy = 0; dy < D1Dy; ++dy)
4401 for (int dz = 0; dz < D1Dz; ++dz)
4403 // \hat{\nabla}\times\hat{u} is [(u_2)_{x_1}, -(u_2)_{x_0}, 0]
4404 // (u_2)_{x_1} * (op * curl)_0 - (u_2)_{x_0} * (op * curl)_1
4405 Y(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc,
4406 e) += (gradYZ10[dz][dy] * wx) - (gradYZ01[dz][dy] * wDx);
4415 template<int MAX_D1D = HCURL_MAX_D1D, int MAX_Q1D = HCURL_MAX_Q1D>
4416 static void SmemPAHcurlL2Apply3DTranspose(const int D1D,
4420 const Array<double> &bo,
4421 const Array<double> &bc,
4422 const Array<double> &gc,
4423 const Vector &pa_data,
4427 MFEM_VERIFY(D1D <= MAX_D1D, "Error: D1D > MAX_D1D
");
4428 MFEM_VERIFY(Q1D <= MAX_Q1D, "Error: Q1D > MAX_Q1D
");
4430 auto Bo = Reshape(bo.Read(), Q1D, D1D-1);
4431 auto Bc = Reshape(bc.Read(), Q1D, D1D);
4432 auto Gc = Reshape(gc.Read(), Q1D, D1D);
4433 auto op = Reshape(pa_data.Read(), coeffDim, Q1D, Q1D, Q1D, NE);
4434 auto X = Reshape(x.Read(), 3*(D1D-1)*D1D*D1D, NE);
4435 auto Y = Reshape(y.ReadWrite(), 3*(D1D-1)*D1D*D1D, NE);
4437 MFEM_FORALL_3D(e, NE, Q1D, Q1D, Q1D,
4439 constexpr int VDIM = 3;
4440 constexpr int maxCoeffDim = 3;
4442 MFEM_SHARED double sBo[MAX_D1D][MAX_Q1D];
4443 MFEM_SHARED double sBc[MAX_D1D][MAX_Q1D];
4444 MFEM_SHARED double sGc[MAX_D1D][MAX_Q1D];
4446 double opc[maxCoeffDim];
4447 MFEM_SHARED double sop[maxCoeffDim][MAX_Q1D][MAX_Q1D];
4448 MFEM_SHARED double mass[MAX_Q1D][MAX_Q1D][3];
4450 MFEM_SHARED double sX[MAX_D1D][MAX_D1D][MAX_D1D];
4452 MFEM_FOREACH_THREAD(qx,x,Q1D)
4454 MFEM_FOREACH_THREAD(qy,y,Q1D)
4456 MFEM_FOREACH_THREAD(qz,z,Q1D)
4458 for (int i=0; i<coeffDim; ++i)
4460 opc[i] = op(i,qx,qy,qz,e);
4466 const int tidx = MFEM_THREAD_ID(x);
4467 const int tidy = MFEM_THREAD_ID(y);
4468 const int tidz = MFEM_THREAD_ID(z);
4472 MFEM_FOREACH_THREAD(d,y,D1D)
4474 MFEM_FOREACH_THREAD(q,x,Q1D)
4476 sBc[d][q] = Bc(q,d);
4477 sGc[d][q] = Gc(q,d);
4480 sBo[d][q] = Bo(q,d);
4487 for (int qz=0; qz < Q1D; ++qz)
4491 MFEM_FOREACH_THREAD(qy,y,Q1D)
4493 MFEM_FOREACH_THREAD(qx,x,Q1D)
4495 for (int i=0; i<3; ++i)
4497 mass[qy][qx][i] = 0.0;
4504 for (int c = 0; c < VDIM; ++c) // loop over x, y, z components
4506 const int D1Dz = (c == 2) ? D1D - 1 : D1D;
4507 const int D1Dy = (c == 1) ? D1D - 1 : D1D;
4508 const int D1Dx = (c == 0) ? D1D - 1 : D1D;
4510 MFEM_FOREACH_THREAD(dz,z,D1Dz)
4512 MFEM_FOREACH_THREAD(dy,y,D1Dy)
4514 MFEM_FOREACH_THREAD(dx,x,D1Dx)
4516 sX[dz][dy][dx] = X(dx + ((dy + (dz * D1Dy)) * D1Dx) + osc, e);
4526 for (int i=0; i<coeffDim; ++i)
4528 sop[i][tidx][tidy] = opc[i];
4532 MFEM_FOREACH_THREAD(qy,y,Q1D)
4534 MFEM_FOREACH_THREAD(qx,x,Q1D)
4538 for (int dz = 0; dz < D1Dz; ++dz)
4540 const double wz = (c == 2) ? sBo[dz][qz] : sBc[dz][qz];
4542 for (int dy = 0; dy < D1Dy; ++dy)
4544 const double wy = (c == 1) ? sBo[dy][qy] : sBc[dy][qy];
4546 for (int dx = 0; dx < D1Dx; ++dx)
4548 const double wx = sX[dz][dy][dx] * ((c == 0) ? sBo[dx][qx] : sBc[dx][qx]);
4554 mass[qy][qx][c] += u;
4559 osc += D1Dx * D1Dy * D1Dz;
4567 MFEM_FOREACH_THREAD(dz,z,D1D)
4569 const double wcz = sBc[dz][qz];
4570 const double wcDz = sGc[dz][qz];
4571 const double wz = (dz < D1D-1) ? sBo[dz][qz] : 0.0;
4573 MFEM_FOREACH_THREAD(dy,y,D1D)
4575 MFEM_FOREACH_THREAD(dx,x,D1D)
4577 for (int qy = 0; qy < Q1D; ++qy)
4579 const double wcy = sBc[dy][qy];
4580 const double wcDy = sGc[dy][qy];
4581 const double wy = (dy < D1D-1) ? sBo[dy][qy] : 0.0;
4583 for (int qx = 0; qx < Q1D; ++qx)
4585 const double O1 = sop[0][qx][qy];
4586 const double O2 = (coeffDim == 3) ? sop[1][qx][qy] : O1;
4587 const double O3 = (coeffDim == 3) ? sop[2][qx][qy] : O1;
4589 const double c1 = O1 * mass[qy][qx][0];
4590 const double c2 = O2 * mass[qy][qx][1];
4591 const double c3 = O3 * mass[qy][qx][2];
4593 const double wcx = sBc[dx][qx];
4594 const double wDx = sGc[dx][qx];
4598 const double wx = sBo[dx][qx];
4599 dxyz1 += (wx * c2 * wcy * wcDz) - (wx * c3 * wcDy * wcz);
4602 dxyz2 += (-wy * c1 * wcx * wcDz) + (wy * c3 * wDx * wcz);
4604 dxyz3 += (wcDy * wz * c1 * wcx) - (wcy * wz * c2 * wDx);
4613 MFEM_FOREACH_THREAD(dz,z,D1D)
4615 MFEM_FOREACH_THREAD(dy,y,D1D)
4617 MFEM_FOREACH_THREAD(dx,x,D1D)
4621 Y(dx + ((dy + (dz * D1D)) * (D1D-1)), e) += dxyz1;
4625 Y(dx + ((dy + (dz * (D1D-1))) * D1D) + ((D1D-1)*D1D*D1D), e) += dxyz2;
4629 Y(dx + ((dy + (dz * D1D)) * D1D) + (2*(D1D-1)*D1D*D1D), e) += dxyz3;
4635 }); // end of element loop
4638 void MixedVectorWeakCurlIntegrator::AddMultPA(const Vector &x, Vector &y) const
4640 if (testType == mfem::FiniteElement::CURL &&
4641 trialType == mfem::FiniteElement::CURL && dim == 3)
4643 if (Device::Allows(Backend::DEVICE_MASK))
4645 const int ID = (dofs1D << 4) | quad1D;
4648 case 0x23: return SmemPAHcurlL2Apply3DTranspose<2,3>(dofs1D, quad1D, coeffDim,
4649 ne, mapsO->B, mapsC->B,
4650 mapsC->G, pa_data, x, y);
4651 case 0x34: return SmemPAHcurlL2Apply3DTranspose<3,4>(dofs1D, quad1D, coeffDim,
4652 ne, mapsO->B, mapsC->B,
4653 mapsC->G, pa_data, x, y);
4654 case 0x45: return SmemPAHcurlL2Apply3DTranspose<4,5>(dofs1D, quad1D, coeffDim,
4655 ne, mapsO->B, mapsC->B,
4656 mapsC->G, pa_data, x, y);
4657 case 0x56: return SmemPAHcurlL2Apply3DTranspose<5,6>(dofs1D, quad1D, coeffDim,
4658 ne, mapsO->B, mapsC->B,
4659 mapsC->G, pa_data, x, y);
4660 default: return SmemPAHcurlL2Apply3DTranspose(dofs1D, quad1D, coeffDim, ne,
4662 mapsC->G, pa_data, x, y);
4666 PAHcurlL2Apply3DTranspose(dofs1D, quad1D, coeffDim, ne, mapsO->B, mapsC->B,
4667 mapsO->Bt, mapsC->Bt, mapsC->Gt, pa_data, x, y);
4671 MFEM_ABORT("Unsupported dimension or
space!
");
4675 // Apply to x corresponding to DOFs in H^1 (domain) the (topological) gradient
4676 // to get a dof in H(curl) (range). You can think of the range as the "test
" space
4677 // and the domain as the "trial
" space, but there's no integration.
4678 static void PAHcurlApplyGradient2D(const int c_dofs1D,
4681 const Array<double> &B_,
4682 const Array<double> &G_,
4686 auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D);
4687 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
4689 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
4690 auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
4692 constexpr static int MAX_D1D = HCURL_MAX_D1D;
4693 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
4697 double w[MAX_D1D][MAX_D1D];
4700 for (int dx = 0; dx < c_dofs1D; ++dx)
4702 for (int ey = 0; ey < c_dofs1D; ++ey)
4705 for (int dy = 0; dy < c_dofs1D; ++dy)
4707 w[dx][ey] += B(ey, dy) * x(dx, dy, e);
4712 for (int ey = 0; ey < c_dofs1D; ++ey)
4714 for (int ex = 0; ex < o_dofs1D; ++ex)
4717 for (int dx = 0; dx < c_dofs1D; ++dx)
4719 s += G(ex, dx) * w[dx][ey];
4721 const int local_index = ey*o_dofs1D + ex;
4722 y(local_index, e) += s;
4727 for (int dx = 0; dx < c_dofs1D; ++dx)
4729 for (int ey = 0; ey < o_dofs1D; ++ey)
4732 for (int dy = 0; dy < c_dofs1D; ++dy)
4734 w[dx][ey] += G(ey, dy) * x(dx, dy, e);
4739 for (int ey = 0; ey < o_dofs1D; ++ey)
4741 for (int ex = 0; ex < c_dofs1D; ++ex)
4744 for (int dx = 0; dx < c_dofs1D; ++dx)
4746 s += B(ex, dx) * w[dx][ey];
4748 const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex;
4749 y(local_index, e) += s;
4755 // Specialization of PAHcurlApplyGradient2D to the case where B is identity
4756 static void PAHcurlApplyGradient2DBId(const int c_dofs1D,
4759 const Array<double> &G_,
4763 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
4765 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, NE);
4766 auto y = Reshape(y_.ReadWrite(), 2 * c_dofs1D * o_dofs1D, NE);
4768 constexpr static int MAX_D1D = HCURL_MAX_D1D;
4769 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
4773 double w[MAX_D1D][MAX_D1D];
4776 for (int dx = 0; dx < c_dofs1D; ++dx)
4778 for (int ey = 0; ey < c_dofs1D; ++ey)
4781 w[dx][ey] = x(dx, dy, e);
4785 for (int ey = 0; ey < c_dofs1D; ++ey)
4787 for (int ex = 0; ex < o_dofs1D; ++ex)
4790 for (int dx = 0; dx < c_dofs1D; ++dx)
4792 s += G(ex, dx) * w[dx][ey];
4794 const int local_index = ey*o_dofs1D + ex;
4795 y(local_index, e) += s;
4800 for (int dx = 0; dx < c_dofs1D; ++dx)
4802 for (int ey = 0; ey < o_dofs1D; ++ey)
4805 for (int dy = 0; dy < c_dofs1D; ++dy)
4807 w[dx][ey] += G(ey, dy) * x(dx, dy, e);
4812 for (int ey = 0; ey < o_dofs1D; ++ey)
4814 for (int ex = 0; ex < c_dofs1D; ++ex)
4817 const double s = w[dx][ey];
4818 const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex;
4819 y(local_index, e) += s;
4825 static void PAHcurlApplyGradientTranspose2D(
4826 const int c_dofs1D, const int o_dofs1D, const int NE,
4827 const Array<double> &B_, const Array<double> &G_,
4828 const Vector &x_, Vector &y_)
4830 auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D);
4831 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
4833 auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
4834 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
4836 constexpr static int MAX_D1D = HCURL_MAX_D1D;
4837 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
4841 double w[MAX_D1D][MAX_D1D];
4843 // horizontal part (open x, closed y)
4844 for (int dy = 0; dy < c_dofs1D; ++dy)
4846 for (int ex = 0; ex < o_dofs1D; ++ex)
4849 for (int ey = 0; ey < c_dofs1D; ++ey)
4851 const int local_index = ey*o_dofs1D + ex;
4852 w[dy][ex] += B(ey, dy) * x(local_index, e);
4857 for (int dy = 0; dy < c_dofs1D; ++dy)
4859 for (int dx = 0; dx < c_dofs1D; ++dx)
4862 for (int ex = 0; ex < o_dofs1D; ++ex)
4864 s += G(ex, dx) * w[dy][ex];
4870 // vertical part (open y, closed x)
4871 for (int dy = 0; dy < c_dofs1D; ++dy)
4873 for (int ex = 0; ex < c_dofs1D; ++ex)
4876 for (int ey = 0; ey < o_dofs1D; ++ey)
4878 const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex;
4879 w[dy][ex] += G(ey, dy) * x(local_index, e);
4884 for (int dy = 0; dy < c_dofs1D; ++dy)
4886 for (int dx = 0; dx < c_dofs1D; ++dx)
4889 for (int ex = 0; ex < c_dofs1D; ++ex)
4891 s += B(ex, dx) * w[dy][ex];
4899 // Specialization of PAHcurlApplyGradientTranspose2D to the case where
4901 static void PAHcurlApplyGradientTranspose2DBId(
4902 const int c_dofs1D, const int o_dofs1D, const int NE,
4903 const Array<double> &G_,
4904 const Vector &x_, Vector &y_)
4906 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
4908 auto x = Reshape(x_.Read(), 2 * c_dofs1D * o_dofs1D, NE);
4909 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, NE);
4911 constexpr static int MAX_D1D = HCURL_MAX_D1D;
4912 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
4916 double w[MAX_D1D][MAX_D1D];
4918 // horizontal part (open x, closed y)
4919 for (int dy = 0; dy < c_dofs1D; ++dy)
4921 for (int ex = 0; ex < o_dofs1D; ++ex)
4924 const int local_index = ey*o_dofs1D + ex;
4925 w[dy][ex] = x(local_index, e);
4929 for (int dy = 0; dy < c_dofs1D; ++dy)
4931 for (int dx = 0; dx < c_dofs1D; ++dx)
4934 for (int ex = 0; ex < o_dofs1D; ++ex)
4936 s += G(ex, dx) * w[dy][ex];
4942 // vertical part (open y, closed x)
4943 for (int dy = 0; dy < c_dofs1D; ++dy)
4945 for (int ex = 0; ex < c_dofs1D; ++ex)
4948 for (int ey = 0; ey < o_dofs1D; ++ey)
4950 const int local_index = c_dofs1D * o_dofs1D + ey*c_dofs1D + ex;
4951 w[dy][ex] += G(ey, dy) * x(local_index, e);
4956 for (int dy = 0; dy < c_dofs1D; ++dy)
4958 for (int dx = 0; dx < c_dofs1D; ++dx)
4961 const double s = w[dy][ex];
4968 static void PAHcurlApplyGradient3D(const int c_dofs1D,
4971 const Array<double> &B_,
4972 const Array<double> &G_,
4976 auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D);
4977 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
4979 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
4980 auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
4982 constexpr static int MAX_D1D = HCURL_MAX_D1D;
4983 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
4987 double w1[MAX_D1D][MAX_D1D][MAX_D1D];
4988 double w2[MAX_D1D][MAX_D1D][MAX_D1D];
4991 // dofs that point parallel to x-axis (open in x, closed in y, z)
4995 for (int ez = 0; ez < c_dofs1D; ++ez)
4997 for (int dx = 0; dx < c_dofs1D; ++dx)
4999 for (int dy = 0; dy < c_dofs1D; ++dy)
5001 w1[dx][dy][ez] = 0.0;
5002 for (int dz = 0; dz < c_dofs1D; ++dz)
5004 w1[dx][dy][ez] += B(ez, dz) * x(dx, dy, dz, e);
5011 for (int ez = 0; ez < c_dofs1D; ++ez)
5013 for (int ey = 0; ey < c_dofs1D; ++ey)
5015 for (int dx = 0; dx < c_dofs1D; ++dx)
5017 w2[dx][ey][ez] = 0.0;
5018 for (int dy = 0; dy < c_dofs1D; ++dy)
5020 w2[dx][ey][ez] += B(ey, dy) * w1[dx][dy][ez];
5027 for (int ez = 0; ez < c_dofs1D; ++ez)
5029 for (int ey = 0; ey < c_dofs1D; ++ey)
5031 for (int ex = 0; ex < o_dofs1D; ++ex)
5034 for (int dx = 0; dx < c_dofs1D; ++dx)
5036 s += G(ex, dx) * w2[dx][ey][ez];
5038 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
5039 y(local_index, e) += s;
5045 // dofs that point parallel to y-axis (open in y, closed in x, z)
5049 for (int ez = 0; ez < c_dofs1D; ++ez)
5051 for (int dx = 0; dx < c_dofs1D; ++dx)
5053 for (int dy = 0; dy < c_dofs1D; ++dy)
5055 w1[dx][dy][ez] = 0.0;
5056 for (int dz = 0; dz < c_dofs1D; ++dz)
5058 w1[dx][dy][ez] += B(ez, dz) * x(dx, dy, dz, e);
5065 for (int ez = 0; ez < c_dofs1D; ++ez)
5067 for (int ey = 0; ey < o_dofs1D; ++ey)
5069 for (int dx = 0; dx < c_dofs1D; ++dx)
5071 w2[dx][ey][ez] = 0.0;
5072 for (int dy = 0; dy < c_dofs1D; ++dy)
5074 w2[dx][ey][ez] += G(ey, dy) * w1[dx][dy][ez];
5081 for (int ez = 0; ez < c_dofs1D; ++ez)
5083 for (int ey = 0; ey < o_dofs1D; ++ey)
5085 for (int ex = 0; ex < c_dofs1D; ++ex)
5088 for (int dx = 0; dx < c_dofs1D; ++dx)
5090 s += B(ex, dx) * w2[dx][ey][ez];
5092 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
5093 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
5094 y(local_index, e) += s;
5100 // dofs that point parallel to z-axis (open in z, closed in x, y)
5104 for (int ez = 0; ez < o_dofs1D; ++ez)
5106 for (int dx = 0; dx < c_dofs1D; ++dx)
5108 for (int dy = 0; dy < c_dofs1D; ++dy)
5110 w1[dx][dy][ez] = 0.0;
5111 for (int dz = 0; dz < c_dofs1D; ++dz)
5113 w1[dx][dy][ez] += G(ez, dz) * x(dx, dy, dz, e);
5120 for (int ez = 0; ez < o_dofs1D; ++ez)
5122 for (int ey = 0; ey < c_dofs1D; ++ey)
5124 for (int dx = 0; dx < c_dofs1D; ++dx)
5126 w2[dx][ey][ez] = 0.0;
5127 for (int dy = 0; dy < c_dofs1D; ++dy)
5129 w2[dx][ey][ez] += B(ey, dy) * w1[dx][dy][ez];
5136 for (int ez = 0; ez < o_dofs1D; ++ez)
5138 for (int ey = 0; ey < c_dofs1D; ++ey)
5140 for (int ex = 0; ex < c_dofs1D; ++ex)
5143 for (int dx = 0; dx < c_dofs1D; ++dx)
5145 s += B(ex, dx) * w2[dx][ey][ez];
5147 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
5148 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
5149 y(local_index, e) += s;
5156 // Specialization of PAHcurlApplyGradient3D to the case where
5157 static void PAHcurlApplyGradient3DBId(const int c_dofs1D,
5160 const Array<double> &G_,
5164 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
5166 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
5167 auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
5169 constexpr static int MAX_D1D = HCURL_MAX_D1D;
5170 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
5174 double w1[MAX_D1D][MAX_D1D][MAX_D1D];
5175 double w2[MAX_D1D][MAX_D1D][MAX_D1D];
5178 // dofs that point parallel to x-axis (open in x, closed in y, z)
5182 for (int ez = 0; ez < c_dofs1D; ++ez)
5184 for (int dx = 0; dx < c_dofs1D; ++dx)
5186 for (int dy = 0; dy < c_dofs1D; ++dy)
5189 w1[dx][dy][ez] = x(dx, dy, dz, e);
5195 for (int ez = 0; ez < c_dofs1D; ++ez)
5197 for (int ey = 0; ey < c_dofs1D; ++ey)
5199 for (int dx = 0; dx < c_dofs1D; ++dx)
5202 w2[dx][ey][ez] = w1[dx][dy][ez];
5208 for (int ez = 0; ez < c_dofs1D; ++ez)
5210 for (int ey = 0; ey < c_dofs1D; ++ey)
5212 for (int ex = 0; ex < o_dofs1D; ++ex)
5215 for (int dx = 0; dx < c_dofs1D; ++dx)
5217 s += G(ex, dx) * w2[dx][ey][ez];
5219 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
5220 y(local_index, e) += s;
5226 // dofs that point parallel to y-axis (open in y, closed in x, z)
5230 for (int ez = 0; ez < c_dofs1D; ++ez)
5232 for (int dx = 0; dx < c_dofs1D; ++dx)
5234 for (int dy = 0; dy < c_dofs1D; ++dy)
5237 w1[dx][dy][ez] = x(dx, dy, dz, e);
5243 for (int ez = 0; ez < c_dofs1D; ++ez)
5245 for (int ey = 0; ey < o_dofs1D; ++ey)
5247 for (int dx = 0; dx < c_dofs1D; ++dx)
5249 w2[dx][ey][ez] = 0.0;
5250 for (int dy = 0; dy < c_dofs1D; ++dy)
5252 w2[dx][ey][ez] += G(ey, dy) * w1[dx][dy][ez];
5259 for (int ez = 0; ez < c_dofs1D; ++ez)
5261 for (int ey = 0; ey < o_dofs1D; ++ey)
5263 for (int ex = 0; ex < c_dofs1D; ++ex)
5266 const double s = w2[dx][ey][ez];
5267 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
5268 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
5269 y(local_index, e) += s;
5275 // dofs that point parallel to z-axis (open in z, closed in x, y)
5279 for (int ez = 0; ez < o_dofs1D; ++ez)
5281 for (int dx = 0; dx < c_dofs1D; ++dx)
5283 for (int dy = 0; dy < c_dofs1D; ++dy)
5285 w1[dx][dy][ez] = 0.0;
5286 for (int dz = 0; dz < c_dofs1D; ++dz)
5288 w1[dx][dy][ez] += G(ez, dz) * x(dx, dy, dz, e);
5295 for (int ez = 0; ez < o_dofs1D; ++ez)
5297 for (int ey = 0; ey < c_dofs1D; ++ey)
5299 for (int dx = 0; dx < c_dofs1D; ++dx)
5302 w2[dx][ey][ez] = w1[dx][dy][ez];
5308 for (int ez = 0; ez < o_dofs1D; ++ez)
5310 for (int ey = 0; ey < c_dofs1D; ++ey)
5312 for (int ex = 0; ex < c_dofs1D; ++ex)
5315 const double s = w2[dx][ey][ez];
5316 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
5317 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
5318 y(local_index, e) += s;
5325 static void PAHcurlApplyGradientTranspose3D(
5326 const int c_dofs1D, const int o_dofs1D, const int NE,
5327 const Array<double> &B_, const Array<double> &G_,
5328 const Vector &x_, Vector &y_)
5330 auto B = Reshape(B_.Read(), c_dofs1D, c_dofs1D);
5331 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
5333 auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
5334 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
5336 constexpr static int MAX_D1D = HCURL_MAX_D1D;
5337 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
5341 double w1[MAX_D1D][MAX_D1D][MAX_D1D];
5342 double w2[MAX_D1D][MAX_D1D][MAX_D1D];
5344 // dofs that point parallel to x-axis (open in x, closed in y, z)
5348 for (int dz = 0; dz < c_dofs1D; ++dz)
5350 for (int ex = 0; ex < o_dofs1D; ++ex)
5352 for (int ey = 0; ey < c_dofs1D; ++ey)
5354 w1[ex][ey][dz] = 0.0;
5355 for (int ez = 0; ez < c_dofs1D; ++ez)
5357 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
5358 w1[ex][ey][dz] += B(ez, dz) * x(local_index, e);
5365 for (int dz = 0; dz < c_dofs1D; ++dz)
5367 for (int dy = 0; dy < c_dofs1D; ++dy)
5369 for (int ex = 0; ex < o_dofs1D; ++ex)
5371 w2[ex][dy][dz] = 0.0;
5372 for (int ey = 0; ey < c_dofs1D; ++ey)
5374 w2[ex][dy][dz] += B(ey, dy) * w1[ex][ey][dz];
5381 for (int dz = 0; dz < c_dofs1D; ++dz)
5383 for (int dy = 0; dy < c_dofs1D; ++dy)
5385 for (int dx = 0; dx < c_dofs1D; ++dx)
5388 for (int ex = 0; ex < o_dofs1D; ++ex)
5390 s += G(ex, dx) * w2[ex][dy][dz];
5392 y(dx, dy, dz, e) += s;
5398 // dofs that point parallel to y-axis (open in y, closed in x, z)
5402 for (int dz = 0; dz < c_dofs1D; ++dz)
5404 for (int ex = 0; ex < c_dofs1D; ++ex)
5406 for (int ey = 0; ey < o_dofs1D; ++ey)
5408 w1[ex][ey][dz] = 0.0;
5409 for (int ez = 0; ez < c_dofs1D; ++ez)
5411 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
5412 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
5413 w1[ex][ey][dz] += B(ez, dz) * x(local_index, e);
5420 for (int dz = 0; dz < c_dofs1D; ++dz)
5422 for (int dy = 0; dy < c_dofs1D; ++dy)
5424 for (int ex = 0; ex < c_dofs1D; ++ex)
5426 w2[ex][dy][dz] = 0.0;
5427 for (int ey = 0; ey < o_dofs1D; ++ey)
5429 w2[ex][dy][dz] += G(ey, dy) * w1[ex][ey][dz];
5436 for (int dz = 0; dz < c_dofs1D; ++dz)
5438 for (int dy = 0; dy < c_dofs1D; ++dy)
5440 for (int dx = 0; dx < c_dofs1D; ++dx)
5443 for (int ex = 0; ex < c_dofs1D; ++ex)
5445 s += B(ex, dx) * w2[ex][dy][dz];
5447 y(dx, dy, dz, e) += s;
5453 // dofs that point parallel to z-axis (open in z, closed in x, y)
5457 for (int dz = 0; dz < c_dofs1D; ++dz)
5459 for (int ex = 0; ex < c_dofs1D; ++ex)
5461 for (int ey = 0; ey < c_dofs1D; ++ey)
5463 w1[ex][ey][dz] = 0.0;
5464 for (int ez = 0; ez < o_dofs1D; ++ez)
5466 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
5467 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
5468 w1[ex][ey][dz] += G(ez, dz) * x(local_index, e);
5475 for (int dz = 0; dz < c_dofs1D; ++dz)
5477 for (int dy = 0; dy < c_dofs1D; ++dy)
5479 for (int ex = 0; ex < c_dofs1D; ++ex)
5481 w2[ex][dy][dz] = 0.0;
5482 for (int ey = 0; ey < c_dofs1D; ++ey)
5484 w2[ex][dy][dz] += B(ey, dy) * w1[ex][ey][dz];
5491 for (int dz = 0; dz < c_dofs1D; ++dz)
5493 for (int dy = 0; dy < c_dofs1D; ++dy)
5495 for (int dx = 0; dx < c_dofs1D; ++dx)
5498 for (int ex = 0; ex < c_dofs1D; ++ex)
5500 s += B(ex, dx) * w2[ex][dy][dz];
5502 y(dx, dy, dz, e) += s;
5509 // Specialization of PAHcurlApplyGradientTranspose3D to the case where
5510 static void PAHcurlApplyGradientTranspose3DBId(
5511 const int c_dofs1D, const int o_dofs1D, const int NE,
5512 const Array<double> &G_,
5513 const Vector &x_, Vector &y_)
5515 auto G = Reshape(G_.Read(), o_dofs1D, c_dofs1D);
5517 auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
5518 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, NE);
5520 constexpr static int MAX_D1D = HCURL_MAX_D1D;
5521 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
5525 double w1[MAX_D1D][MAX_D1D][MAX_D1D];
5526 double w2[MAX_D1D][MAX_D1D][MAX_D1D];
5528 // dofs that point parallel to x-axis (open in x, closed in y, z)
5532 for (int dz = 0; dz < c_dofs1D; ++dz)
5534 for (int ex = 0; ex < o_dofs1D; ++ex)
5536 for (int ey = 0; ey < c_dofs1D; ++ey)
5539 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
5540 w1[ex][ey][dz] = x(local_index, e);
5546 for (int dz = 0; dz < c_dofs1D; ++dz)
5548 for (int dy = 0; dy < c_dofs1D; ++dy)
5550 for (int ex = 0; ex < o_dofs1D; ++ex)
5553 w2[ex][dy][dz] = w1[ex][ey][dz];
5559 for (int dz = 0; dz < c_dofs1D; ++dz)
5561 for (int dy = 0; dy < c_dofs1D; ++dy)
5563 for (int dx = 0; dx < c_dofs1D; ++dx)
5566 for (int ex = 0; ex < o_dofs1D; ++ex)
5568 s += G(ex, dx) * w2[ex][dy][dz];
5570 y(dx, dy, dz, e) += s;
5576 // dofs that point parallel to y-axis (open in y, closed in x, z)
5580 for (int dz = 0; dz < c_dofs1D; ++dz)
5582 for (int ex = 0; ex < c_dofs1D; ++ex)
5584 for (int ey = 0; ey < o_dofs1D; ++ey)
5587 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
5588 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
5589 w1[ex][ey][dz] = x(local_index, e);
5595 for (int dz = 0; dz < c_dofs1D; ++dz)
5597 for (int dy = 0; dy < c_dofs1D; ++dy)
5599 for (int ex = 0; ex < c_dofs1D; ++ex)
5601 w2[ex][dy][dz] = 0.0;
5602 for (int ey = 0; ey < o_dofs1D; ++ey)
5604 w2[ex][dy][dz] += G(ey, dy) * w1[ex][ey][dz];
5611 for (int dz = 0; dz < c_dofs1D; ++dz)
5613 for (int dy = 0; dy < c_dofs1D; ++dy)
5615 for (int dx = 0; dx < c_dofs1D; ++dx)
5618 double s = w2[ex][dy][dz];
5619 y(dx, dy, dz, e) += s;
5625 // dofs that point parallel to z-axis (open in z, closed in x, y)
5629 for (int dz = 0; dz < c_dofs1D; ++dz)
5631 for (int ex = 0; ex < c_dofs1D; ++ex)
5633 for (int ey = 0; ey < c_dofs1D; ++ey)
5635 w1[ex][ey][dz] = 0.0;
5636 for (int ez = 0; ez < o_dofs1D; ++ez)
5638 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
5639 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
5640 w1[ex][ey][dz] += G(ez, dz) * x(local_index, e);
5647 for (int dz = 0; dz < c_dofs1D; ++dz)
5649 for (int dy = 0; dy < c_dofs1D; ++dy)
5651 for (int ex = 0; ex < c_dofs1D; ++ex)
5654 w2[ex][dy][dz] = w1[ex][ey][dz];
5660 for (int dz = 0; dz < c_dofs1D; ++dz)
5662 for (int dy = 0; dy < c_dofs1D; ++dy)
5664 for (int dx = 0; dx < c_dofs1D; ++dx)
5667 double s = w2[ex][dy][dz];
5668 y(dx, dy, dz, e) += s;
5675 void GradientInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
5676 const FiniteElementSpace &test_fes)
5678 // Assumes tensor-product elements, with a vector test space and H^1 trial space.
5679 Mesh *mesh = trial_fes.GetMesh();
5680 const FiniteElement *trial_fel = trial_fes.GetFE(0);
5681 const FiniteElement *test_fel = test_fes.GetFE(0);
5683 const NodalTensorFiniteElement *trial_el =
5684 dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
5687 const VectorTensorFiniteElement *test_el =
5688 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
5691 const int dims = trial_el->GetDim();
5692 MFEM_VERIFY(dims == 2 || dims == 3, "Bad dimension!
");
5693 dim = mesh->Dimension();
5694 MFEM_VERIFY(dim == 2 || dim == 3, "Bad dimension!
");
5695 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(),
5696 "Orders
do not match!
");
5697 ne = trial_fes.GetNE();
5699 const int order = trial_el->GetOrder();
5700 dofquad_fe = new H1_SegmentElement(order, trial_el->GetBasisType());
5701 mfem::QuadratureFunctions1D qf1d;
5702 mfem::IntegrationRule closed_ir;
5703 closed_ir.SetSize(order + 1);
5704 qf1d.GaussLobatto(order + 1, &closed_ir);
5705 mfem::IntegrationRule open_ir;
5706 open_ir.SetSize(order);
5707 qf1d.GaussLegendre(order, &open_ir);
5709 maps_O_C = &dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR);
5710 o_dofs1D = maps_O_C->nqpt;
5711 if (trial_el->GetBasisType() == BasisType::GaussLobatto)
5714 c_dofs1D = maps_O_C->ndof;
5719 maps_C_C = &dofquad_fe->GetDofToQuad(closed_ir, DofToQuad::TENSOR);
5720 c_dofs1D = maps_C_C->nqpt;
5724 void GradientInterpolator::AddMultPA(const Vector &x, Vector &y) const
5730 PAHcurlApplyGradient3DBId(c_dofs1D, o_dofs1D, ne,
5735 PAHcurlApplyGradient3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
5743 PAHcurlApplyGradient2DBId(c_dofs1D, o_dofs1D, ne,
5748 PAHcurlApplyGradient2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->G,
5754 mfem_error("Bad dimension!
");
5758 void GradientInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const
5764 PAHcurlApplyGradientTranspose3DBId(c_dofs1D, o_dofs1D, ne,
5769 PAHcurlApplyGradientTranspose3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
5777 PAHcurlApplyGradientTranspose2DBId(c_dofs1D, o_dofs1D, ne,
5782 PAHcurlApplyGradientTranspose2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
5788 mfem_error("Bad dimension!
");
5792 static void PAHcurlVecH1IdentityApply3D(const int c_dofs1D,
5795 const Array<double> &Bclosed,
5796 const Array<double> &Bopen,
5797 const Vector &pa_data,
5801 auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D);
5802 auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D);
5804 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, c_dofs1D, 3, NE);
5805 auto y = Reshape(y_.ReadWrite(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
5807 auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
5810 constexpr static int MAX_D1D = HCURL_MAX_D1D;
5811 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
5815 double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
5816 double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
5818 // dofs that point parallel to x-axis (open in x, closed in y, z)
5821 for (int ez = 0; ez < c_dofs1D; ++ez)
5823 for (int dx = 0; dx < c_dofs1D; ++dx)
5825 for (int dy = 0; dy < c_dofs1D; ++dy)
5827 for (int j=0; j<3; ++j)
5829 w1[j][dx][dy][ez] = 0.0;
5830 for (int dz = 0; dz < c_dofs1D; ++dz)
5832 w1[j][dx][dy][ez] += Bc(ez, dz) * x(dx, dy, dz, j, e);
5840 for (int ez = 0; ez < c_dofs1D; ++ez)
5842 for (int ey = 0; ey < c_dofs1D; ++ey)
5844 for (int dx = 0; dx < c_dofs1D; ++dx)
5846 for (int j=0; j<3; ++j)
5848 w2[j][dx][ey][ez] = 0.0;
5849 for (int dy = 0; dy < c_dofs1D; ++dy)
5851 w2[j][dx][ey][ez] += Bc(ey, dy) * w1[j][dx][dy][ez];
5859 for (int ez = 0; ez < c_dofs1D; ++ez)
5861 for (int ey = 0; ey < c_dofs1D; ++ey)
5863 for (int ex = 0; ex < o_dofs1D; ++ex)
5865 for (int j=0; j<3; ++j)
5868 for (int dx = 0; dx < c_dofs1D; ++dx)
5870 s += Bo(ex, dx) * w2[j][dx][ey][ez];
5872 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
5873 y(local_index, e) += s * vk(j, local_index, e);
5879 // dofs that point parallel to y-axis (open in y, closed in x, z)
5882 for (int ez = 0; ez < c_dofs1D; ++ez)
5884 for (int dx = 0; dx < c_dofs1D; ++dx)
5886 for (int dy = 0; dy < c_dofs1D; ++dy)
5888 for (int j=0; j<3; ++j)
5890 w1[j][dx][dy][ez] = 0.0;
5891 for (int dz = 0; dz < c_dofs1D; ++dz)
5893 w1[j][dx][dy][ez] += Bc(ez, dz) * x(dx, dy, dz, j, e);
5901 for (int ez = 0; ez < c_dofs1D; ++ez)
5903 for (int ey = 0; ey < o_dofs1D; ++ey)
5905 for (int dx = 0; dx < c_dofs1D; ++dx)
5907 for (int j=0; j<3; ++j)
5909 w2[j][dx][ey][ez] = 0.0;
5910 for (int dy = 0; dy < c_dofs1D; ++dy)
5912 w2[j][dx][ey][ez] += Bo(ey, dy) * w1[j][dx][dy][ez];
5920 for (int ez = 0; ez < c_dofs1D; ++ez)
5922 for (int ey = 0; ey < o_dofs1D; ++ey)
5924 for (int ex = 0; ex < c_dofs1D; ++ex)
5926 for (int j=0; j<3; ++j)
5929 for (int dx = 0; dx < c_dofs1D; ++dx)
5931 s += Bc(ex, dx) * w2[j][dx][ey][ez];
5933 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
5934 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
5935 y(local_index, e) += s * vk(j, local_index, e);
5941 // dofs that point parallel to z-axis (open in z, closed in x, y)
5944 for (int ez = 0; ez < o_dofs1D; ++ez)
5946 for (int dx = 0; dx < c_dofs1D; ++dx)
5948 for (int dy = 0; dy < c_dofs1D; ++dy)
5950 for (int j=0; j<3; ++j)
5952 w1[j][dx][dy][ez] = 0.0;
5953 for (int dz = 0; dz < c_dofs1D; ++dz)
5955 w1[j][dx][dy][ez] += Bo(ez, dz) * x(dx, dy, dz, j, e);
5963 for (int ez = 0; ez < o_dofs1D; ++ez)
5965 for (int ey = 0; ey < c_dofs1D; ++ey)
5967 for (int dx = 0; dx < c_dofs1D; ++dx)
5969 for (int j=0; j<3; ++j)
5971 w2[j][dx][ey][ez] = 0.0;
5972 for (int dy = 0; dy < c_dofs1D; ++dy)
5974 w2[j][dx][ey][ez] += Bc(ey, dy) * w1[j][dx][dy][ez];
5982 for (int ez = 0; ez < o_dofs1D; ++ez)
5984 for (int ey = 0; ey < c_dofs1D; ++ey)
5986 for (int ex = 0; ex < c_dofs1D; ++ex)
5988 for (int j=0; j<3; ++j)
5991 for (int dx = 0; dx < c_dofs1D; ++dx)
5993 s += Bc(ex, dx) * w2[j][dx][ey][ez];
5995 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
5996 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
5997 y(local_index, e) += s * vk(j, local_index, e);
6005 static void PAHcurlVecH1IdentityApplyTranspose3D(const int c_dofs1D,
6008 const Array<double> &Bclosed,
6009 const Array<double> &Bopen,
6010 const Vector &pa_data,
6014 auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D);
6015 auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D);
6017 auto x = Reshape(x_.Read(), (3 * c_dofs1D * c_dofs1D * o_dofs1D), NE);
6018 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, c_dofs1D, 3, NE);
6020 auto vk = Reshape(pa_data.Read(), 3, (3 * c_dofs1D * c_dofs1D * o_dofs1D),
6023 constexpr static int MAX_D1D = HCURL_MAX_D1D;
6025 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
6029 double w1[3][MAX_D1D][MAX_D1D][MAX_D1D];
6030 double w2[3][MAX_D1D][MAX_D1D][MAX_D1D];
6032 // dofs that point parallel to x-axis (open in x, closed in y, z)
6035 for (int ez = 0; ez < c_dofs1D; ++ez)
6037 for (int ey = 0; ey < c_dofs1D; ++ey)
6039 for (int j=0; j<3; ++j)
6041 for (int dx = 0; dx < c_dofs1D; ++dx)
6043 w2[j][dx][ey][ez] = 0.0;
6045 for (int ex = 0; ex < o_dofs1D; ++ex)
6047 const int local_index = ez*c_dofs1D*o_dofs1D + ey*o_dofs1D + ex;
6048 const double xv = x(local_index, e) * vk(j, local_index, e);
6049 for (int dx = 0; dx < c_dofs1D; ++dx)
6051 w2[j][dx][ey][ez] += xv * Bo(ex, dx);
6059 for (int ez = 0; ez < c_dofs1D; ++ez)
6061 for (int dx = 0; dx < c_dofs1D; ++dx)
6063 for (int dy = 0; dy < c_dofs1D; ++dy)
6065 for (int j=0; j<3; ++j)
6067 w1[j][dx][dy][ez] = 0.0;
6068 for (int ey = 0; ey < c_dofs1D; ++ey)
6070 w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bc(ey, dy);
6078 for (int dx = 0; dx < c_dofs1D; ++dx)
6080 for (int dy = 0; dy < c_dofs1D; ++dy)
6082 for (int dz = 0; dz < c_dofs1D; ++dz)
6084 for (int j=0; j<3; ++j)
6087 for (int ez = 0; ez < c_dofs1D; ++ez)
6089 s += w1[j][dx][dy][ez] * Bc(ez, dz);
6091 y(dx, dy, dz, j, e) += s;
6097 // dofs that point parallel to y-axis (open in y, closed in x, z)
6100 for (int ez = 0; ez < c_dofs1D; ++ez)
6102 for (int ey = 0; ey < o_dofs1D; ++ey)
6104 for (int j=0; j<3; ++j)
6106 for (int dx = 0; dx < c_dofs1D; ++dx)
6108 w2[j][dx][ey][ez] = 0.0;
6110 for (int ex = 0; ex < c_dofs1D; ++ex)
6112 const int local_index = c_dofs1D*c_dofs1D*o_dofs1D +
6113 ez*c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
6114 const double xv = x(local_index, e) * vk(j, local_index, e);
6115 for (int dx = 0; dx < c_dofs1D; ++dx)
6117 w2[j][dx][ey][ez] += xv * Bc(ex, dx);
6125 for (int ez = 0; ez < c_dofs1D; ++ez)
6127 for (int dx = 0; dx < c_dofs1D; ++dx)
6129 for (int dy = 0; dy < c_dofs1D; ++dy)
6131 for (int j=0; j<3; ++j)
6133 w1[j][dx][dy][ez] = 0.0;
6134 for (int ey = 0; ey < o_dofs1D; ++ey)
6136 w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bo(ey, dy);
6144 for (int dx = 0; dx < c_dofs1D; ++dx)
6146 for (int dy = 0; dy < c_dofs1D; ++dy)
6148 for (int dz = 0; dz < c_dofs1D; ++dz)
6150 for (int j=0; j<3; ++j)
6153 for (int ez = 0; ez < c_dofs1D; ++ez)
6155 s += w1[j][dx][dy][ez] * Bc(ez, dz);
6157 y(dx, dy, dz, j, e) += s;
6163 // dofs that point parallel to z-axis (open in z, closed in x, y)
6166 for (int ez = 0; ez < o_dofs1D; ++ez)
6168 for (int ey = 0; ey < c_dofs1D; ++ey)
6170 for (int j=0; j<3; ++j)
6172 for (int dx = 0; dx < c_dofs1D; ++dx)
6174 w2[j][dx][ey][ez] = 0.0;
6176 for (int ex = 0; ex < c_dofs1D; ++ex)
6178 const int local_index = 2*c_dofs1D*c_dofs1D*o_dofs1D +
6179 ez*c_dofs1D*c_dofs1D + ey*c_dofs1D + ex;
6180 const double xv = x(local_index, e) * vk(j, local_index, e);
6181 for (int dx = 0; dx < c_dofs1D; ++dx)
6183 w2[j][dx][ey][ez] += xv * Bc(ex, dx);
6191 for (int ez = 0; ez < o_dofs1D; ++ez)
6193 for (int dx = 0; dx < c_dofs1D; ++dx)
6195 for (int dy = 0; dy < c_dofs1D; ++dy)
6197 for (int j=0; j<3; ++j)
6199 w1[j][dx][dy][ez] = 0.0;
6200 for (int ey = 0; ey < c_dofs1D; ++ey)
6202 w1[j][dx][dy][ez] += w2[j][dx][ey][ez] * Bc(ey, dy);
6210 for (int dx = 0; dx < c_dofs1D; ++dx)
6212 for (int dy = 0; dy < c_dofs1D; ++dy)
6214 for (int dz = 0; dz < c_dofs1D; ++dz)
6216 for (int j=0; j<3; ++j)
6219 for (int ez = 0; ez < o_dofs1D; ++ez)
6221 s += w1[j][dx][dy][ez] * Bo(ez, dz);
6223 y(dx, dy, dz, j, e) += s;
6231 static void PAHcurlVecH1IdentityApply2D(const int c_dofs1D,
6234 const Array<double> &Bclosed,
6235 const Array<double> &Bopen,
6236 const Vector &pa_data,
6240 auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D);
6241 auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D);
6243 auto x = Reshape(x_.Read(), c_dofs1D, c_dofs1D, 2, NE);
6244 auto y = Reshape(y_.ReadWrite(), (2 * c_dofs1D * o_dofs1D), NE);
6246 auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
6248 constexpr static int MAX_D1D = HCURL_MAX_D1D;
6250 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
6254 double w[2][MAX_D1D][MAX_D1D];
6256 // dofs that point parallel to x-axis (open in x, closed in y)
6259 for (int ey = 0; ey < c_dofs1D; ++ey)
6261 for (int dx = 0; dx < c_dofs1D; ++dx)
6263 for (int j=0; j<2; ++j)
6266 for (int dy = 0; dy < c_dofs1D; ++dy)
6268 w[j][dx][ey] += Bc(ey, dy) * x(dx, dy, j, e);
6275 for (int ey = 0; ey < c_dofs1D; ++ey)
6277 for (int ex = 0; ex < o_dofs1D; ++ex)
6279 for (int j=0; j<2; ++j)
6282 for (int dx = 0; dx < c_dofs1D; ++dx)
6284 s += Bo(ex, dx) * w[j][dx][ey];
6286 const int local_index = ey*o_dofs1D + ex;
6287 y(local_index, e) += s * vk(j, local_index, e);
6292 // dofs that point parallel to y-axis (open in y, closed in x)
6295 for (int ey = 0; ey < o_dofs1D; ++ey)
6297 for (int dx = 0; dx < c_dofs1D; ++dx)
6299 for (int j=0; j<2; ++j)
6302 for (int dy = 0; dy < c_dofs1D; ++dy)
6304 w[j][dx][ey] += Bo(ey, dy) * x(dx, dy, j, e);
6311 for (int ey = 0; ey < o_dofs1D; ++ey)
6313 for (int ex = 0; ex < c_dofs1D; ++ex)
6315 for (int j=0; j<2; ++j)
6318 for (int dx = 0; dx < c_dofs1D; ++dx)
6320 s += Bc(ex, dx) * w[j][dx][ey];
6322 const int local_index = c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
6323 y(local_index, e) += s * vk(j, local_index, e);
6330 static void PAHcurlVecH1IdentityApplyTranspose2D(const int c_dofs1D,
6333 const Array<double> &Bclosed,
6334 const Array<double> &Bopen,
6335 const Vector &pa_data,
6339 auto Bc = Reshape(Bclosed.Read(), c_dofs1D, c_dofs1D);
6340 auto Bo = Reshape(Bopen.Read(), o_dofs1D, c_dofs1D);
6342 auto x = Reshape(x_.Read(), (2 * c_dofs1D * o_dofs1D), NE);
6343 auto y = Reshape(y_.ReadWrite(), c_dofs1D, c_dofs1D, 2, NE);
6345 auto vk = Reshape(pa_data.Read(), 2, (2 * c_dofs1D * o_dofs1D), NE);
6347 constexpr static int MAX_D1D = HCURL_MAX_D1D;
6348 //constexpr static int MAX_Q1D = HCURL_MAX_Q1D;
6350 MFEM_VERIFY(c_dofs1D <= MAX_D1D && o_dofs1D <= c_dofs1D, "");
6354 double w[2][MAX_D1D][MAX_D1D];
6356 // dofs that point parallel to x-axis (open in x, closed in y)
6359 for (int ey = 0; ey < c_dofs1D; ++ey)
6361 for (int dx = 0; dx < c_dofs1D; ++dx)
6363 for (int j=0; j<2; ++j) { w[j][dx][ey] = 0.0; }
6365 for (int ex = 0; ex < o_dofs1D; ++ex)
6367 const int local_index = ey*o_dofs1D + ex;
6368 const double xd = x(local_index, e);
6370 for (int dx = 0; dx < c_dofs1D; ++dx)
6372 for (int j=0; j<2; ++j)
6374 w[j][dx][ey] += Bo(ex, dx) * xd * vk(j, local_index, e);
6381 for (int dx = 0; dx < c_dofs1D; ++dx)
6383 for (int dy = 0; dy < c_dofs1D; ++dy)
6385 for (int j=0; j<2; ++j)
6388 for (int ey = 0; ey < c_dofs1D; ++ey)
6390 s += w[j][dx][ey] * Bc(ey, dy);
6392 y(dx, dy, j, e) += s;
6397 // dofs that point parallel to y-axis (open in y, closed in x)
6400 for (int ey = 0; ey < o_dofs1D; ++ey)
6402 for (int dx = 0; dx < c_dofs1D; ++dx)
6404 for (int j=0; j<2; ++j) { w[j][dx][ey] = 0.0; }
6406 for (int ex = 0; ex < c_dofs1D; ++ex)
6408 const int local_index = c_dofs1D*o_dofs1D + ey*c_dofs1D + ex;
6409 const double xd = x(local_index, e);
6410 for (int dx = 0; dx < c_dofs1D; ++dx)
6412 for (int j=0; j<2; ++j)
6414 w[j][dx][ey] += Bc(ex, dx) * xd * vk(j, local_index, e);
6421 for (int dx = 0; dx < c_dofs1D; ++dx)
6423 for (int dy = 0; dy < c_dofs1D; ++dy)
6425 for (int j=0; j<2; ++j)
6428 for (int ey = 0; ey < o_dofs1D; ++ey)
6430 s += w[j][dx][ey] * Bo(ey, dy);
6432 y(dx, dy, j, e) += s;
6439 void IdentityInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
6440 const FiniteElementSpace &test_fes)
6442 // Assumes tensor-product elements, with a vector test space and H^1 trial space.
6443 Mesh *mesh = trial_fes.GetMesh();
6444 const FiniteElement *trial_fel = trial_fes.GetFE(0);
6445 const FiniteElement *test_fel = test_fes.GetFE(0);
6447 const NodalTensorFiniteElement *trial_el =
6448 dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
6451 const VectorTensorFiniteElement *test_el =
6452 dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
6455 const int dims = trial_el->GetDim();
6456 MFEM_VERIFY(dims == 2 || dims == 3, "");
6458 dim = mesh->Dimension();
6459 MFEM_VERIFY(dim == 2 || dim == 3, "");
6461 MFEM_VERIFY(trial_el->GetOrder() == test_el->GetOrder(), "");
6463 ne = trial_fes.GetNE();
6465 const int order = trial_el->GetOrder();
6466 dofquad_fe = new H1_SegmentElement(order);
6467 mfem::QuadratureFunctions1D qf1d;
6468 mfem::IntegrationRule closed_ir;
6469 closed_ir.SetSize(order + 1);
6470 qf1d.GaussLobatto(order + 1, &closed_ir);
6471 mfem::IntegrationRule open_ir;
6472 open_ir.SetSize(order);
6473 qf1d.GaussLegendre(order, &open_ir);
6475 maps_C_C = &dofquad_fe->GetDofToQuad(closed_ir, DofToQuad::TENSOR);
6476 maps_O_C = &dofquad_fe->GetDofToQuad(open_ir, DofToQuad::TENSOR);
6478 o_dofs1D = maps_O_C->nqpt;
6479 c_dofs1D = maps_C_C->nqpt;
6480 MFEM_VERIFY(maps_O_C->ndof == c_dofs1D &&
6481 maps_C_C->ndof == c_dofs1D, "Discrepancy in the number of DOFs
");
6483 const int ndof_test = (dim == 3) ? 3 * c_dofs1D * c_dofs1D * o_dofs1D
6484 : 2 * c_dofs1D * o_dofs1D;
6486 const IntegrationRule & Nodes = test_el->GetNodes();
6488 pa_data.SetSize(dim * ndof_test * ne, Device::GetMemoryType());
6489 auto op = Reshape(pa_data.HostWrite(), dim, ndof_test, ne);
6491 const Array<int> &dofmap = test_el->GetDofMap();
6495 // Note that ND_HexahedronElement uses 6 vectors in tk rather than 3, with
6496 // the last 3 having negative signs. Here the signs are all positive, as
6497 // signs are applied in ElementRestriction.
6499 const double tk[9] = { 1.,0.,0., 0.,1.,0., 0.,0.,1. };
6501 for (int c=0; c<3; ++c)
6503 for (int i=0; i<ndof_test/3; ++i)
6505 const int d = (c*ndof_test/3) + i;
6506 // ND_HexahedronElement sets dof2tk = (dofmap < 0) ? 3+c : c, but here
6507 // no signs should be applied due to ElementRestriction.
6508 const int dof2tk = c;
6509 const int id = (dofmap[d] >= 0) ? dofmap[d] : -1 - dofmap[d];
6511 for (int e=0; e<ne; ++e)
6514 ElementTransformation *tr = mesh->GetElementTransformation(e);
6515 tr->SetIntPoint(&Nodes.IntPoint(id));
6516 tr->Jacobian().Mult(tk + dof2tk*dim, v);
6518 for (int j=0; j<3; ++j)
6528 const double tk[4] = { 1.,0., 0.,1. };
6529 for (int c=0; c<2; ++c)
6531 for (int i=0; i<ndof_test/2; ++i)
6533 const int d = (c*ndof_test/2) + i;
6534 // ND_QuadrilateralElement sets dof2tk = (dofmap < 0) ? 2+c : c, but here
6535 // no signs should be applied due to ElementRestriction.
6536 const int dof2tk = c;
6537 const int id = (dofmap[d] >= 0) ? dofmap[d] : -1 - dofmap[d];
6539 for (int e=0; e<ne; ++e)
6542 ElementTransformation *tr = mesh->GetElementTransformation(e);
6543 tr->SetIntPoint(&Nodes.IntPoint(id));
6544 tr->Jacobian().Mult(tk + dof2tk*dim, v);
6546 for (int j=0; j<2; ++j)
6556 void IdentityInterpolator::AddMultPA(const Vector &x, Vector &y) const
6560 PAHcurlVecH1IdentityApply3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->B,
6565 PAHcurlVecH1IdentityApply2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B, maps_O_C->B,
6570 mfem_error("Bad dimension!
");
6574 void IdentityInterpolator::AddMultTransposePA(const Vector &x, Vector &y) const
6578 PAHcurlVecH1IdentityApplyTranspose3D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
6579 maps_O_C->B, pa_data, x, y);
6583 PAHcurlVecH1IdentityApplyTranspose2D(c_dofs1D, o_dofs1D, ne, maps_C_C->B,
6584 maps_O_C->B, pa_data, x, y);
6588 mfem_error("Bad dimension!
");
6592 template void SmemPAHcurlMassAssembleDiagonal3D<0,0>(const int D1D,
6595 const bool symmetric,
6596 const Array<double> &bo,
6597 const Array<double> &bc,
6598 const Vector &pa_data,
6601 template void SmemPAHcurlMassAssembleDiagonal3D<2,3>(const int D1D,
6604 const bool symmetric,
6605 const Array<double> &bo,
6606 const Array<double> &bc,
6607 const Vector &pa_data,
6610 template void SmemPAHcurlMassAssembleDiagonal3D<3,4>(const int D1D,
6613 const bool symmetric,
6614 const Array<double> &bo,
6615 const Array<double> &bc,
6616 const Vector &pa_data,
6619 template void SmemPAHcurlMassAssembleDiagonal3D<4,5>(const int D1D,
6622 const bool symmetric,
6623 const Array<double> &bo,
6624 const Array<double> &bc,
6625 const Vector &pa_data,
6628 template void SmemPAHcurlMassAssembleDiagonal3D<5,6>(const int D1D,
6631 const bool symmetric,
6632 const Array<double> &bo,
6633 const Array<double> &bc,
6634 const Vector &pa_data,
6637 template void SmemPAHcurlMassApply3D<0,0>(const int D1D,
6640 const bool symmetric,
6641 const Array<double> &bo,
6642 const Array<double> &bc,
6643 const Array<double> &bot,
6644 const Array<double> &bct,
6645 const Vector &pa_data,
6649 template void SmemPAHcurlMassApply3D<2,3>(const int D1D,
6652 const bool symmetric,
6653 const Array<double> &bo,
6654 const Array<double> &bc,
6655 const Array<double> &bot,
6656 const Array<double> &bct,
6657 const Vector &pa_data,
6661 template void SmemPAHcurlMassApply3D<3,4>(const int D1D,
6664 const bool symmetric,
6665 const Array<double> &bo,
6666 const Array<double> &bc,
6667 const Array<double> &bot,
6668 const Array<double> &bct,
6669 const Vector &pa_data,
6673 template void SmemPAHcurlMassApply3D<4,5>(const int D1D,
6676 const bool symmetric,
6677 const Array<double> &bo,
6678 const Array<double> &bc,
6679 const Array<double> &bot,
6680 const Array<double> &bct,
6681 const Vector &pa_data,
6685 template void SmemPAHcurlMassApply3D<5,6>(const int D1D,
6688 const bool symmetric,
6689 const Array<double> &bo,
6690 const Array<double> &bc,
6691 const Array<double> &bot,
6692 const Array<double> &bct,
6693 const Vector &pa_data,
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
void PAHcurlMassAssembleDiagonal2D(const int D1D, const int Q1D, const int NE, const bool symmetric, const Array< double > &bo, const Array< double > &bc, const Vector &pa_data, Vector &diag)
constexpr int HCURL_MAX_D1D
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
void PAHcurlMassAssembleDiagonal3D(const int D1D, const int Q1D, const int NE, const bool symmetric, const Array< double > &bo, const Array< double > &bc, const Vector &pa_data, Vector &diag)
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
void PAHcurlMassApply2D(const int D1D, const int Q1D, const int NE, const bool symmetric, const Array< double > &bo, const Array< double > &bc, const Array< double > &bot, const Array< double > &bct, const Vector &pa_data, const Vector &x, Vector &y)
constexpr int HCURL_MAX_Q1D
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).