35 "Only scalar finite elements are supported");
51 "Only scalar finite elements are supported");
57namespace quadrature_interpolator
64static void Eval1D(
const int NE,
77 const int nd = maps.
ndof;
78 const int nq = maps.
nqpt;
81 MFEM_VERIFY(vdim == 1 || !(eval_flags & QI::DETERMINANTS),
"");
82 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
83 "'geom' must be given (non-null) only when evaluating physical"
87 const auto J =
Reshape(geom ? geom->
J.
Read() : nullptr, nq, NE);
98 for (
int q = 0; q < nq; ++q)
100 if (eval_flags & QI::VALUES)
102 for (
int c = 0; c < vdim; c++)
105 for (
int d = 0; d < nd; ++d)
107 q_val += B(q,d)*E(d,c,e);
113 if ((eval_flags & QI::DERIVATIVES) ||
114 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
115 (eval_flags & QI::DETERMINANTS))
117 for (
int c = 0; c < vdim; c++)
120 for (
int d = 0; d < nd; ++d)
122 q_d += G(q,d)*E(d,c,e);
124 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
128 if (eval_flags & QI::DERIVATIVES || eval_flags & QI::PHYSICAL_DERIVATIVES)
133 if (vdim == 1 && (eval_flags & QI::DETERMINANTS))
147template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
148static void Eval2D(
const int NE,
151 const GeometricFactors *geom,
152 const DofToQuad &maps,
157 const int eval_flags)
159 using QI = QuadratureInterpolator;
161 const int nd = maps.ndof;
162 const int nq = maps.nqpt;
163 const int ND = T_ND ? T_ND : nd;
164 const int NQ = T_NQ ? T_NQ : nq;
165 const int NMAX = NQ > ND ? NQ : ND;
166 const int VDIM = T_VDIM ? T_VDIM : vdim;
168 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 2,
"");
169 MFEM_VERIFY(ND <= QI::MAX_ND2D,
"");
170 MFEM_VERIFY(NQ <= QI::MAX_NQ2D,
"");
171 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
172 "'geom' must be given (non-null) only when evaluating physical"
174 const auto B =
Reshape(maps.B.Read(), NQ, ND);
175 const auto G =
Reshape(maps.G.Read(), NQ, 2, ND);
176 const auto J =
Reshape(geom ? geom->J.Read() : nullptr, NQ, 2, 2, NE);
177 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
179 Reshape(q_val.Write(), NQ, VDIM, NE):
182 Reshape(q_der.Write(), NQ, VDIM, 2, NE):
184 auto det =
Reshape(q_det.Write(), NQ, NE);
187 const int ND = T_ND ? T_ND : nd;
188 const int NQ = T_NQ ? T_NQ : nq;
189 const int VDIM = T_VDIM ? T_VDIM : vdim;
190 constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
191 constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
192 MFEM_SHARED
real_t s_E[max_VDIM*max_ND];
193 MFEM_FOREACH_THREAD(d, x, ND)
195 for (
int c = 0; c < VDIM; c++)
197 s_E[c+d*VDIM] = E(d,c,e);
202 MFEM_FOREACH_THREAD(q, x, NQ)
204 if (eval_flags & QI::VALUES)
207 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
208 for (
int d = 0; d < ND; ++d)
211 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
213 for (
int c = 0; c < VDIM; c++)
219 if ((eval_flags & QI::DERIVATIVES) ||
220 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
221 (eval_flags & QI::DETERMINANTS))
224 real_t D[QI::MAX_VDIM2D*2];
225 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
226 for (
int d = 0; d < ND; ++d)
228 const real_t wx = G(q,0,d);
229 const real_t wy = G(q,1,d);
230 for (
int c = 0; c < VDIM; c++)
232 real_t s_e = s_E[c+d*VDIM];
233 D[c+VDIM*0] += s_e * wx;
234 D[c+VDIM*1] += s_e * wy;
237 if (eval_flags & QI::DERIVATIVES)
239 for (
int c = 0; c < VDIM; c++)
243 der(c,0,q,e) = D[c+VDIM*0];
244 der(c,1,q,e) = D[c+VDIM*1];
248 der(q,c,0,e) = D[c+VDIM*0];
249 der(q,c,1,e) = D[c+VDIM*1];
253 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
256 Jloc[0] = J(q,0,0,e);
257 Jloc[1] = J(q,1,0,e);
258 Jloc[2] = J(q,0,1,e);
259 Jloc[3] = J(q,1,1,e);
261 for (
int c = 0; c < VDIM; c++)
264 const real_t v = D[c+VDIM*1];
265 const real_t JiU = Jinv[0]*
u + Jinv[1]*v;
266 const real_t JiV = Jinv[2]*
u + Jinv[3]*v;
279 if (eval_flags & QI::DETERMINANTS)
284 DeviceTensor<2> j(D, 3, 2);
285 const double E = j(0,0)*j(0,0) + j(1,0)*j(1,0) + j(2,0)*j(2,0);
286 const double F = j(0,0)*j(0,1) + j(1,0)*j(1,1) + j(2,0)*j(2,1);
287 const double G = j(0,1)*j(0,1) + j(1,1)*j(1,1) + j(2,1)*j(2,1);
288 det(q,e) = sqrt(E*G - F*F);
300template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
301static void Eval3D(
const int NE,
304 const GeometricFactors *geom,
305 const DofToQuad &maps,
310 const int eval_flags)
312 using QI = QuadratureInterpolator;
314 const int nd = maps.ndof;
315 const int nq = maps.nqpt;
316 const int ND = T_ND ? T_ND : nd;
317 const int NQ = T_NQ ? T_NQ : nq;
318 const int NMAX = NQ > ND ? NQ : ND;
319 const int VDIM = T_VDIM ? T_VDIM : vdim;
321 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3,
"");
322 MFEM_VERIFY(ND <= QI::MAX_ND3D,
"");
323 MFEM_VERIFY(NQ <= QI::MAX_NQ3D,
"");
324 MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS),
"");
325 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
326 "'geom' must be given (non-null) only when evaluating physical"
328 const auto B =
Reshape(maps.B.Read(), NQ, ND);
329 const auto G =
Reshape(maps.G.Read(), NQ, 3, ND);
330 const auto J =
Reshape(geom ? geom->J.Read() : nullptr, NQ, 3, 3, NE);
331 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
333 Reshape(q_val.Write(), NQ, VDIM, NE):
336 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
338 auto det =
Reshape(q_det.Write(), NQ, NE);
341 const int ND = T_ND ? T_ND : nd;
342 const int NQ = T_NQ ? T_NQ : nq;
343 const int VDIM = T_VDIM ? T_VDIM : vdim;
344 constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
345 constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
346 MFEM_SHARED
real_t s_E[max_VDIM*max_ND];
347 MFEM_FOREACH_THREAD(d, x, ND)
349 for (
int c = 0; c < VDIM; c++)
351 s_E[c+d*VDIM] = E(d,c,e);
356 MFEM_FOREACH_THREAD(q, x, NQ)
358 if (eval_flags & QI::VALUES)
361 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
362 for (
int d = 0; d < ND; ++d)
365 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
367 for (
int c = 0; c < VDIM; c++)
373 if ((eval_flags & QI::DERIVATIVES) ||
374 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
375 (eval_flags & QI::DETERMINANTS))
378 real_t D[QI::MAX_VDIM3D*3];
379 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
380 for (
int d = 0; d < ND; ++d)
382 const real_t wx = G(q,0,d);
383 const real_t wy = G(q,1,d);
384 const real_t wz = G(q,2,d);
385 for (
int c = 0; c < VDIM; c++)
387 real_t s_e = s_E[c+d*VDIM];
388 D[c+VDIM*0] += s_e * wx;
389 D[c+VDIM*1] += s_e * wy;
390 D[c+VDIM*2] += s_e * wz;
393 if (eval_flags & QI::DERIVATIVES)
395 for (
int c = 0; c < VDIM; c++)
399 der(c,0,q,e) = D[c+VDIM*0];
400 der(c,1,q,e) = D[c+VDIM*1];
401 der(c,2,q,e) = D[c+VDIM*2];
405 der(q,c,0,e) = D[c+VDIM*0];
406 der(q,c,1,e) = D[c+VDIM*1];
407 der(q,c,2,e) = D[c+VDIM*2];
411 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
414 for (
int col = 0; col < 3; col++)
416 for (
int row = 0; row < 3; row++)
418 Jloc[row+3*col] = J(q,row,col,e);
422 for (
int c = 0; c < VDIM; c++)
425 const real_t v = D[c+VDIM*1];
426 const real_t w = D[c+VDIM*2];
427 const real_t JiU = Jinv[0]*
u + Jinv[1]*v + Jinv[2]*w;
428 const real_t JiV = Jinv[3]*
u + Jinv[4]*v + Jinv[5]*w;
429 const real_t JiW = Jinv[6]*
u + Jinv[7]*v + Jinv[8]*w;
444 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
465 using namespace internal::quadrature_interpolator;
468 if (ne == 0) {
return; }
471 const bool use_tensor_eval =
488 (
dim == 2 && vdim == 3),
"Invalid dimensions for determinants.");
491 "mixed meshes are not supported");
500 TensorValues<QVectorLayout::byNODES>(ne, vdim, maps, e_vec, q_val);
504 TensorDerivatives<QVectorLayout::byNODES>(
505 ne, vdim, maps, e_vec, q_der);
509 TensorPhysDerivatives<QVectorLayout::byNODES>(
510 ne, vdim, maps, *geom, e_vec, q_der);
518 TensorValues<QVectorLayout::byVDIM>(ne, vdim, maps, e_vec, q_val);
522 TensorDerivatives<QVectorLayout::byVDIM>(
523 ne, vdim, maps, e_vec, q_der);
527 TensorPhysDerivatives<QVectorLayout::byVDIM>(
528 ne, vdim, maps, *geom, e_vec, q_der);
533 TensorDeterminants(ne, vdim, maps, e_vec, q_det,
d_buffer);
538 const int nd = maps.
ndof;
539 const int nq = maps.
nqpt;
541 void (*mult)(
const int NE,
550 const int eval_flags) = NULL;
563 case 101: mult = &Eval2D<1,1,1>;
break;
564 case 104: mult = &Eval2D<1,1,4>;
break;
566 case 404: mult = &Eval2D<1,4,4>;
break;
567 case 409: mult = &Eval2D<1,4,9>;
break;
569 case 909: mult = &Eval2D<1,9,9>;
break;
570 case 916: mult = &Eval2D<1,9,16>;
break;
572 case 1616: mult = &Eval2D<1,16,16>;
break;
573 case 1625: mult = &Eval2D<1,16,25>;
break;
574 case 1636: mult = &Eval2D<1,16,36>;
break;
576 case 2525: mult = &Eval2D<1,25,25>;
break;
577 case 2536: mult = &Eval2D<1,25,36>;
break;
578 case 2549: mult = &Eval2D<1,25,49>;
break;
579 case 2564: mult = &Eval2D<1,25,64>;
break;
581 if (nq >= 100 || !mult)
583 mult = &Eval2D<1,0,0>;
588 switch (1000*nd + nq)
591 case 1001: mult = &Eval3D<1,1,1>;
break;
592 case 1008: mult = &Eval3D<1,1,8>;
break;
594 case 8008: mult = &Eval3D<1,8,8>;
break;
595 case 8027: mult = &Eval3D<1,8,27>;
break;
597 case 27027: mult = &Eval3D<1,27,27>;
break;
598 case 27064: mult = &Eval3D<1,27,64>;
break;
600 case 64064: mult = &Eval3D<1,64,64>;
break;
601 case 64125: mult = &Eval3D<1,64,125>;
break;
602 case 64216: mult = &Eval3D<1,64,216>;
break;
604 case 125125: mult = &Eval3D<1,125,125>;
break;
605 case 125216: mult = &Eval3D<1,125,216>;
break;
607 if (nq >= 1000 || !mult)
609 mult = &Eval3D<1,0,0>;
613 else if (vdim == 3 &&
dim == 2)
618 case 101: mult = &Eval2D<3,1,1>;
break;
619 case 104: mult = &Eval2D<3,1,4>;
break;
621 case 404: mult = &Eval2D<3,4,4>;
break;
622 case 409: mult = &Eval2D<3,4,9>;
break;
624 case 904: mult = &Eval2D<3,9,4>;
break;
625 case 909: mult = &Eval2D<3,9,9>;
break;
626 case 916: mult = &Eval2D<3,9,16>;
break;
627 case 925: mult = &Eval2D<3,9,25>;
break;
629 case 1616: mult = &Eval2D<3,16,16>;
break;
630 case 1625: mult = &Eval2D<3,16,25>;
break;
631 case 1636: mult = &Eval2D<3,16,36>;
break;
633 case 2525: mult = &Eval2D<3,25,25>;
break;
634 case 2536: mult = &Eval2D<3,25,36>;
break;
635 case 2549: mult = &Eval2D<3,25,49>;
break;
636 case 2564: mult = &Eval2D<3,25,64>;
break;
637 default: mult = &Eval2D<3,0,0>;
640 else if (vdim ==
dim)
647 case 404: mult = &Eval2D<2,4,4>;
break;
648 case 409: mult = &Eval2D<2,4,9>;
break;
650 case 909: mult = &Eval2D<2,9,9>;
break;
651 case 916: mult = &Eval2D<2,9,16>;
break;
653 case 1616: mult = &Eval2D<2,16,16>;
break;
654 case 1625: mult = &Eval2D<2,16,25>;
break;
655 case 1636: mult = &Eval2D<2,16,36>;
break;
657 case 2525: mult = &Eval2D<2,25,25>;
break;
658 case 2536: mult = &Eval2D<2,25,36>;
break;
659 case 2549: mult = &Eval2D<2,25,49>;
break;
660 case 2564: mult = &Eval2D<2,25,64>;
break;
662 if (nq >= 100 || !mult) { mult = &Eval2D<2,0,0>; }
666 switch (1000*nd + nq)
669 case 8008: mult = &Eval3D<3,8,8>;
break;
670 case 8027: mult = &Eval3D<3,8,27>;
break;
672 case 27027: mult = &Eval3D<3,27,27>;
break;
673 case 27064: mult = &Eval3D<3,27,64>;
break;
674 case 27125: mult = &Eval3D<3,27,125>;
break;
676 case 64064: mult = &Eval3D<3,64,64>;
break;
677 case 64125: mult = &Eval3D<3,64,125>;
break;
678 case 64216: mult = &Eval3D<3,64,216>;
break;
680 case 125125: mult = &Eval3D<3,125,125>;
break;
681 case 125216: mult = &Eval3D<3,125,216>;
break;
683 if (nq >= 1000 || !mult) { mult = &Eval3D<3,0,0>; }
688 mult(ne,vdim,
q_layout,geom,maps,e_vec,q_val,q_der,q_det,eval_flags);
690 else { MFEM_ABORT(
"case not supported yet"); }
699 MFEM_CONTRACT_VAR(eval_flags);
700 MFEM_CONTRACT_VAR(q_val);
701 MFEM_CONTRACT_VAR(q_der);
702 MFEM_CONTRACT_VAR(e_vec);
703 MFEM_ABORT(
"this method is not implemented yet");
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Structure representing the matrices/tensors needed to evaluate (in reference space) the values,...
Mode mode
Describes the contents of the B, Bt, G, and Gt arrays, see Mode.
Array< real_t > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
@ FULL
Full multidimensional representation which does not use tensor product structure. The ordering of the...
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Array< real_t > B
Basis functions evaluated at quadrature points.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
const class FiniteElement * FE
The FiniteElement that created and owns this object.
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int GetNE() const
Returns number of elements in the mesh.
Mesh * GetMesh() const
Returns the mesh.
int GetVDim() const
Returns vector dimension.
Abstract class for all finite elements.
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
int GetDim() const
Returns the reference space dimension for the finite element.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Vector J
Jacobians of the element transformations at all quadrature points.
Class for an integration rule - an Array of IntegrationPoint.
int Dimension() const
Dimension of the reference space used within the elements.
int SpaceDimension() const
Dimension of the physical space containing the mesh.
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
bool use_tensor_products
Tensor product evaluation mode.
@ VALUES
Evaluate the values at quadrature points.
@ DERIVATIVES
Evaluate the derivatives at quadrature points.
@ PHYSICAL_DERIVATIVES
Evaluate the physical derivatives.
@ DETERMINANTS
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
QuadratureInterpolator(const FiniteElementSpace &fes, const IntegrationRule &ir)
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det) const
Interpolate the E-vector e_vec to quadrature points.
void Determinants(const Vector &e_vec, Vector &q_det) const
Compute the determinants of the derivatives (with respect to reference coordinates) of the E-vector e...
void MultTranspose(unsigned eval_flags, const Vector &q_val, const Vector &q_der, Vector &e_vec) const
Perform the transpose operation of Mult(). (TODO)
void Values(const Vector &e_vec, Vector &q_val) const
Interpolate the values of the E-vector e_vec at quadrature points.
void Derivatives(const Vector &e_vec, Vector &q_der) const
Interpolate the derivatives (with respect to reference coordinates) of the E-vector e_vec at quadratu...
QVectorLayout q_layout
Output Q-vector layout.
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const
Interpolate the derivatives in physical space of the E-vector e_vec at quadrature points.
const IntegrationRule * IntRule
Not owned.
Vector d_buffer
Auxiliary device buffer.
const FiniteElementSpace * fespace
Not owned.
const QuadratureSpace * qspace
Not owned.
Class representing the storage layout of a QuadratureFunction.
const IntegrationRule & GetElementIntRule(int idx) const
Get the IntegrationRule associated with mesh element idx.
Class for finite elements with basis functions that return scalar values.
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
MFEM_HOST_DEVICE void CalcInverse(const T *data, T *inv_data)
Return the inverse of a matrix with given size and data into the matrix with data inv_data.
MFEM_HOST_DEVICE T Det(const T *data)
Compute the determinant of a square matrix of size dim with given data.
real_t u(const Vector &xvec)
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
void forall_2D(int N, int X, int Y, lambda &&body)
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
QVectorLayout
Type describing possible layouts for Q-vectors.
@ byNODES
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
@ byVDIM
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
void forall(int N, lambda &&body)