12 #include "../general/forall.hpp"
24 static void PAVectorDiffusionSetup2D(
const int Q1D,
26 const Array<double> &w,
31 const int NQ = Q1D*Q1D;
34 auto J =
Reshape(j.Read(), NQ, 2, 2, NE);
35 auto y =
Reshape(op.Write(), NQ, 3, NE);
39 for (
int q = 0; q < NQ; ++q)
41 const double J11 = J(q,0,0,e);
42 const double J21 = J(q,1,0,e);
43 const double J12 = J(q,0,1,e);
44 const double J22 = J(q,1,1,e);
45 const double c_detJ = W[q] * COEFF / ((J11*J22)-(J21*J12));
46 y(q,0,e) = c_detJ * (J12*J12 + J22*J22);
47 y(q,1,e) = -c_detJ * (J12*J11 + J22*J21);
48 y(q,2,e) = c_detJ * (J11*J11 + J21*J21);
54 static void PAVectorDiffusionSetup3D(
const int Q1D,
56 const Array<double> &w,
61 const int NQ = Q1D*Q1D*Q1D;
63 auto J =
Reshape(j.Read(), NQ, 3, 3, NE);
64 auto y =
Reshape(op.Write(), NQ, 6, NE);
67 for (
int q = 0; q < NQ; ++q)
69 const double J11 = J(q,0,0,e);
70 const double J21 = J(q,1,0,e);
71 const double J31 = J(q,2,0,e);
72 const double J12 = J(q,0,1,e);
73 const double J22 = J(q,1,1,e);
74 const double J32 = J(q,2,1,e);
75 const double J13 = J(q,0,2,e);
76 const double J23 = J(q,1,2,e);
77 const double J33 = J(q,2,2,e);
78 const double detJ = J11 * (J22 * J33 - J32 * J23) -
79 J21 * (J12 * J33 - J32 * J13) +
80 J31 * (J12 * J23 - J22 * J13);
81 const double c_detJ = W[q] * COEFF / detJ;
83 const double A11 = (J22 * J33) - (J23 * J32);
84 const double A12 = (J32 * J13) - (J12 * J33);
85 const double A13 = (J12 * J23) - (J22 * J13);
86 const double A21 = (J31 * J23) - (J21 * J33);
87 const double A22 = (J11 * J33) - (J13 * J31);
88 const double A23 = (J21 * J13) - (J11 * J23);
89 const double A31 = (J21 * J32) - (J31 * J22);
90 const double A32 = (J31 * J12) - (J11 * J32);
91 const double A33 = (J11 * J22) - (J12 * J21);
93 y(q,0,e) = c_detJ * (A11*A11 + A12*A12 + A13*A13);
94 y(q,1,e) = c_detJ * (A11*A21 + A12*A22 + A13*A23);
95 y(q,2,e) = c_detJ * (A11*A31 + A12*A32 + A13*A33);
96 y(q,3,e) = c_detJ * (A21*A21 + A22*A22 + A23*A23);
97 y(q,4,e) = c_detJ * (A21*A31 + A22*A32 + A23*A33);
98 y(q,5,e) = c_detJ * (A31*A31 + A32*A32 + A33*A33);
103 static void PAVectorDiffusionSetup(
const int dim,
107 const Array<double> &W,
112 if (!(dim == 2 || dim == 3))
114 MFEM_ABORT(
"Dimension not supported.");
118 PAVectorDiffusionSetup2D(Q1D, NE, W, J, COEFF, op);
122 PAVectorDiffusionSetup3D(Q1D, NE, W, J, COEFF, op);
132 = IntRule ? IntRule : &DiffusionIntegrator::GetRule(el, el);
133 const int dims = el.
GetDim();
134 const int symmDims = (dims * (dims + 1)) / 2;
142 pa_data.SetSize(symmDims * nq * ne, Device::GetDeviceMemoryType());
147 MFEM_VERIFY(cQ != NULL,
"only ConstantCoefficient is supported!");
150 PAVectorDiffusionSetup(dim, dofs1D, quad1D, ne, ir->
GetWeights(),
geom->J,
155 template<
int T_D1D = 0,
int T_Q1D = 0>
static
156 void PAVectorDiffusionApply2D(
const int NE,
167 const int D1D = T_D1D ? T_D1D : d1d;
168 const int Q1D = T_Q1D ? T_Q1D : q1d;
169 constexpr
int VDIM = 2;
170 MFEM_VERIFY(D1D <=
MAX_D1D,
"");
171 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
181 const int D1D = T_D1D ? T_D1D : d1d;
182 const int Q1D = T_Q1D ? T_Q1D : q1d;
184 constexpr
int max_D1D = T_D1D ? T_D1D :
MAX_D1D;
185 constexpr
int max_Q1D = T_Q1D ? T_Q1D :
MAX_Q1D;
187 for (
int c = 0; c < VDIM; ++ c)
189 double grad[max_Q1D][max_Q1D][2];
190 for (
int qy = 0; qy < Q1D; ++qy)
192 for (
int qx = 0; qx < Q1D; ++qx)
194 grad[qy][qx][0] = 0.0;
195 grad[qy][qx][1] = 0.0;
198 for (
int dy = 0; dy < D1D; ++dy)
200 double gradX[max_Q1D][2];
201 for (
int qx = 0; qx < Q1D; ++qx)
206 for (
int dx = 0; dx < D1D; ++dx)
208 const double s = x(dx,dy,c,e);
209 for (
int qx = 0; qx < Q1D; ++qx)
211 gradX[qx][0] += s * B(qx,dx);
212 gradX[qx][1] += s * G(qx,dx);
215 for (
int qy = 0; qy < Q1D; ++qy)
217 const double wy = B(qy,dy);
218 const double wDy = G(qy,dy);
219 for (
int qx = 0; qx < Q1D; ++qx)
221 grad[qy][qx][0] += gradX[qx][1] * wy;
222 grad[qy][qx][1] += gradX[qx][0] * wDy;
227 for (
int qy = 0; qy < Q1D; ++qy)
229 for (
int qx = 0; qx < Q1D; ++qx)
231 const int q = qx + qy * Q1D;
233 const double O11 = op(q,0,e);
234 const double O12 = op(q,1,e);
235 const double O22 = op(q,2,e);
237 const double gradX = grad[qy][qx][0];
238 const double gradY = grad[qy][qx][1];
240 grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
241 grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
244 for (
int qy = 0; qy < Q1D; ++qy)
246 double gradX[max_D1D][2];
247 for (
int dx = 0; dx < D1D; ++dx)
252 for (
int qx = 0; qx < Q1D; ++qx)
254 const double gX = grad[qy][qx][0];
255 const double gY = grad[qy][qx][1];
256 for (
int dx = 0; dx < D1D; ++dx)
258 const double wx = Bt(dx,qx);
259 const double wDx = Gt(dx,qx);
260 gradX[dx][0] += gX * wDx;
261 gradX[dx][1] += gY * wx;
264 for (
int dy = 0; dy < D1D; ++dy)
266 const double wy = Bt(dy,qy);
267 const double wDy = Gt(dy,qy);
268 for (
int dx = 0; dx < D1D; ++dx)
270 y(dx,dy,c,e) += ((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
279 template<
const int T_D1D = 0,
280 const int T_Q1D = 0>
static
281 void PAVectorDiffusionApply3D(
const int NE,
282 const Array<double> &b,
283 const Array<double> &g,
284 const Array<double> &bt,
285 const Array<double> >,
289 int d1d = 0,
int q1d = 0)
291 const int D1D = T_D1D ? T_D1D : d1d;
292 const int Q1D = T_Q1D ? T_Q1D : q1d;
293 constexpr
int VDIM = 3;
294 MFEM_VERIFY(D1D <=
MAX_D1D,
"");
295 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
296 auto B =
Reshape(b.Read(), Q1D, D1D);
297 auto G =
Reshape(g.Read(), Q1D, D1D);
298 auto Bt =
Reshape(bt.Read(), D1D, Q1D);
299 auto Gt =
Reshape(gt.Read(), D1D, Q1D);
300 auto op =
Reshape(_op.Read(), Q1D*Q1D*Q1D, 6, NE);
301 auto x =
Reshape(_x.Read(), D1D, D1D, D1D, VDIM, NE);
302 auto y =
Reshape(_y.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
305 const int D1D = T_D1D ? T_D1D : d1d;
306 const int Q1D = T_Q1D ? T_Q1D : q1d;
307 constexpr
int max_D1D = T_D1D ? T_D1D :
MAX_D1D;
308 constexpr
int max_Q1D = T_Q1D ? T_Q1D :
MAX_Q1D;
309 for (
int c = 0; c < VDIM; ++ c)
311 double grad[max_Q1D][max_Q1D][max_Q1D][3];
312 for (
int qz = 0; qz < Q1D; ++qz)
314 for (
int qy = 0; qy < Q1D; ++qy)
316 for (
int qx = 0; qx < Q1D; ++qx)
318 grad[qz][qy][qx][0] = 0.0;
319 grad[qz][qy][qx][1] = 0.0;
320 grad[qz][qy][qx][2] = 0.0;
324 for (
int dz = 0; dz < D1D; ++dz)
326 double gradXY[max_Q1D][max_Q1D][3];
327 for (
int qy = 0; qy < Q1D; ++qy)
329 for (
int qx = 0; qx < Q1D; ++qx)
331 gradXY[qy][qx][0] = 0.0;
332 gradXY[qy][qx][1] = 0.0;
333 gradXY[qy][qx][2] = 0.0;
336 for (
int dy = 0; dy < D1D; ++dy)
338 double gradX[max_Q1D][2];
339 for (
int qx = 0; qx < Q1D; ++qx)
344 for (
int dx = 0; dx < D1D; ++dx)
346 const double s = x(dx,dy,dz,c,e);
347 for (
int qx = 0; qx < Q1D; ++qx)
349 gradX[qx][0] += s * B(qx,dx);
350 gradX[qx][1] += s * G(qx,dx);
353 for (
int qy = 0; qy < Q1D; ++qy)
355 const double wy = B(qy,dy);
356 const double wDy = G(qy,dy);
357 for (
int qx = 0; qx < Q1D; ++qx)
359 const double wx = gradX[qx][0];
360 const double wDx = gradX[qx][1];
361 gradXY[qy][qx][0] += wDx * wy;
362 gradXY[qy][qx][1] += wx * wDy;
363 gradXY[qy][qx][2] += wx * wy;
367 for (
int qz = 0; qz < Q1D; ++qz)
369 const double wz = B(qz,dz);
370 const double wDz = G(qz,dz);
371 for (
int qy = 0; qy < Q1D; ++qy)
373 for (
int qx = 0; qx < Q1D; ++qx)
375 grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
376 grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
377 grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
383 for (
int qz = 0; qz < Q1D; ++qz)
385 for (
int qy = 0; qy < Q1D; ++qy)
387 for (
int qx = 0; qx < Q1D; ++qx)
389 const int q = qx + (qy + qz * Q1D) * Q1D;
390 const double O11 = op(q,0,e);
391 const double O12 = op(q,1,e);
392 const double O13 = op(q,2,e);
393 const double O22 = op(q,3,e);
394 const double O23 = op(q,4,e);
395 const double O33 = op(q,5,e);
396 const double gradX = grad[qz][qy][qx][0];
397 const double gradY = grad[qz][qy][qx][1];
398 const double gradZ = grad[qz][qy][qx][2];
399 grad[qz][qy][qx][0] = (O11*gradX)+(O12*gradY)+(O13*gradZ);
400 grad[qz][qy][qx][1] = (O12*gradX)+(O22*gradY)+(O23*gradZ);
401 grad[qz][qy][qx][2] = (O13*gradX)+(O23*gradY)+(O33*gradZ);
405 for (
int qz = 0; qz < Q1D; ++qz)
407 double gradXY[max_D1D][max_D1D][3];
408 for (
int dy = 0; dy < D1D; ++dy)
410 for (
int dx = 0; dx < D1D; ++dx)
412 gradXY[dy][dx][0] = 0;
413 gradXY[dy][dx][1] = 0;
414 gradXY[dy][dx][2] = 0;
417 for (
int qy = 0; qy < Q1D; ++qy)
419 double gradX[max_D1D][3];
420 for (
int dx = 0; dx < D1D; ++dx)
426 for (
int qx = 0; qx < Q1D; ++qx)
428 const double gX = grad[qz][qy][qx][0];
429 const double gY = grad[qz][qy][qx][1];
430 const double gZ = grad[qz][qy][qx][2];
431 for (
int dx = 0; dx < D1D; ++dx)
433 const double wx = Bt(dx,qx);
434 const double wDx = Gt(dx,qx);
435 gradX[dx][0] += gX * wDx;
436 gradX[dx][1] += gY * wx;
437 gradX[dx][2] += gZ * wx;
440 for (
int dy = 0; dy < D1D; ++dy)
442 const double wy = Bt(dy,qy);
443 const double wDy = Gt(dy,qy);
444 for (
int dx = 0; dx < D1D; ++dx)
446 gradXY[dy][dx][0] += gradX[dx][0] * wy;
447 gradXY[dy][dx][1] += gradX[dx][1] * wDy;
448 gradXY[dy][dx][2] += gradX[dx][2] * wy;
452 for (
int dz = 0; dz < D1D; ++dz)
454 const double wz = Bt(dz,qz);
455 const double wDz = Gt(dz,qz);
456 for (
int dy = 0; dy < D1D; ++dy)
458 for (
int dx = 0; dx < D1D; ++dx)
461 ((gradXY[dy][dx][0] * wz) +
462 (gradXY[dy][dx][1] * wz) +
463 (gradXY[dy][dx][2] * wDz));
472 static void PAVectorDiffusionApply(
const int dim,
476 const Array<double> &B,
477 const Array<double> &G,
478 const Array<double> &Bt,
479 const Array<double> &Gt,
486 return PAVectorDiffusionApply2D(NE,B,G,Bt,Gt,op,x,y,D1D,Q1D);
490 return PAVectorDiffusionApply3D(NE,B,G,Bt,Gt,op,x,y,D1D,Q1D);
492 MFEM_ABORT(
"Unknown kernel.");
496 void VectorDiffusionIntegrator::AddMultPA(
const Vector &x,
Vector &y)
const
498 PAVectorDiffusionApply(dim, dofs1D, quad1D, ne,
499 maps->B, maps->G, maps->Bt, maps->Gt,
503 template<
int T_D1D = 0,
int T_Q1D = 0>
504 static void PAVectorDiffusionDiagonal2D(
const int NE,
512 const int D1D = T_D1D ? T_D1D : d1d;
513 const int Q1D = T_Q1D ? T_Q1D : q1d;
514 MFEM_VERIFY(D1D <=
MAX_D1D,
"");
515 MFEM_VERIFY(Q1D <=
MAX_Q1D,
"");
524 const int D1D = T_D1D ? T_D1D : d1d;
525 const int Q1D = T_Q1D ? T_Q1D : q1d;
526 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
527 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
529 double QD0[MQ1][MD1];
530 double QD1[MQ1][MD1];
531 double QD2[MQ1][MD1];
532 for (
int qx = 0; qx < Q1D; ++qx)
534 for (
int dy = 0; dy < D1D; ++dy)
539 for (
int qy = 0; qy < Q1D; ++qy)
541 const int q = qx + qy * Q1D;
542 const double D0 = D(q,0,e);
543 const double D1 = D(q,1,e);
544 const double D2 = D(q,2,e);
545 QD0[qx][dy] += B(qy, dy) * B(qy, dy) * D0;
546 QD1[qx][dy] += B(qy, dy) * G(qy, dy) * D1;
547 QD2[qx][dy] += G(qy, dy) * G(qy, dy) * D2;
551 for (
int dy = 0; dy < D1D; ++dy)
553 for (
int dx = 0; dx < D1D; ++dx)
556 for (
int qx = 0; qx < Q1D; ++qx)
558 temp += G(qx, dx) * G(qx, dx) * QD0[qx][dy];
559 temp += G(qx, dx) * B(qx, dx) * QD1[qx][dy];
560 temp += B(qx, dx) * G(qx, dx) * QD1[qx][dy];
561 temp += B(qx, dx) * B(qx, dx) * QD2[qx][dy];
563 Y(dx,dy,0,e) += temp;
564 Y(dx,dy,1,e) += temp;
570 template<
int T_D1D = 0,
int T_Q1D = 0>
571 static void PAVectorDiffusionDiagonal3D(
const int NE,
572 const Array<double> &b,
573 const Array<double> &g,
579 constexpr
int DIM = 3;
580 const int D1D = T_D1D ? T_D1D : d1d;
581 const int Q1D = T_Q1D ? T_Q1D : q1d;
582 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
583 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
584 MFEM_VERIFY(D1D <= MD1,
"");
585 MFEM_VERIFY(Q1D <= MQ1,
"");
586 auto B =
Reshape(b.Read(), Q1D, D1D);
587 auto G =
Reshape(g.Read(), Q1D, D1D);
588 auto Q =
Reshape(d.Read(), Q1D*Q1D*Q1D, 6, NE);
589 auto Y =
Reshape(y.ReadWrite(), D1D, D1D, D1D, 3, NE);
592 const int D1D = T_D1D ? T_D1D : d1d;
593 const int Q1D = T_Q1D ? T_Q1D : q1d;
594 constexpr
int MD1 = T_D1D ? T_D1D :
MAX_D1D;
595 constexpr
int MQ1 = T_Q1D ? T_Q1D :
MAX_Q1D;
596 double QQD[MQ1][MQ1][MD1];
597 double QDD[MQ1][MD1][MD1];
598 for (
int i = 0; i < DIM; ++i)
600 for (
int j = 0; j < DIM; ++j)
603 for (
int qx = 0; qx < Q1D; ++qx)
605 for (
int qy = 0; qy < Q1D; ++qy)
607 for (
int dz = 0; dz < D1D; ++dz)
609 QQD[qx][qy][dz] = 0.0;
610 for (
int qz = 0; qz < Q1D; ++qz)
612 const int q = qx + (qy + qz * Q1D) * Q1D;
613 const int k = j >= i ?
614 3 - (3-i)*(2-i)/2 + j:
615 3 - (3-j)*(2-j)/2 + i;
616 const double O = Q(q,k,e);
617 const double Bz = B(qz,dz);
618 const double Gz = G(qz,dz);
619 const double L = i==2 ? Gz : Bz;
620 const double R = j==2 ? Gz : Bz;
621 QQD[qx][qy][dz] += L * O * R;
627 for (
int qx = 0; qx < Q1D; ++qx)
629 for (
int dz = 0; dz < D1D; ++dz)
631 for (
int dy = 0; dy < D1D; ++dy)
633 QDD[qx][dy][dz] = 0.0;
634 for (
int qy = 0; qy < Q1D; ++qy)
636 const double By = B(qy,dy);
637 const double Gy = G(qy,dy);
638 const double L = i==1 ? Gy : By;
639 const double R = j==1 ? Gy : By;
640 QDD[qx][dy][dz] += L * QQD[qx][qy][dz] * R;
646 for (
int dz = 0; dz < D1D; ++dz)
648 for (
int dy = 0; dy < D1D; ++dy)
650 for (
int dx = 0; dx < D1D; ++dx)
653 for (
int qx = 0; qx < Q1D; ++qx)
655 const double Bx = B(qx,dx);
656 const double Gx = G(qx,dx);
657 const double L = i==0 ? Gx : Bx;
658 const double R = j==0 ? Gx : Bx;
659 temp += L * QDD[qx][dy][dz] * R;
661 Y(dx, dy, dz, 0, e) += temp;
662 Y(dx, dy, dz, 1, e) += temp;
663 Y(dx, dy, dz, 2, e) += temp;
672 static void PAVectorDiffusionAssembleDiagonal(
const int dim,
676 const Array<double> &B,
677 const Array<double> &G,
683 return PAVectorDiffusionDiagonal2D(NE, B, G, op, y, D1D, Q1D);
687 return PAVectorDiffusionDiagonal3D(NE, B, G, op, y, D1D, Q1D);
689 MFEM_ABORT(
"Dimension not implemented.");
692 void VectorDiffusionIntegrator::AssembleDiagonalPA(
Vector &diag)
694 PAVectorDiffusionAssembleDiagonal(dim,
int GetNPoints() const
Returns the number of the points in the integration rule.
Abstract class for Finite Elements.
int GetDim() const
Returns the reference space dimension for the finite element.
Class for an integration rule - an Array of IntegrationPoint.
Subclass constant coefficient.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
const Array< double > & GetWeights() const
Return the quadrature weights in a contiguous array.
DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims...dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
int GetNE() const
Returns number of elements in the mesh.
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags)
Return the mesh geometric factors corresponding to the given integration rule.
double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Mesh * GetMesh() const
Returns the mesh.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement associated with i'th element.