15 #include "../general/forall.hpp" 16 #include "../linalg/dtensor.hpp" 17 #include "../linalg/kernels.hpp" 34 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
35 "Only scalar finite elements are supported");
50 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
51 "Only scalar finite elements are supported");
57 namespace quadrature_interpolator
64 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
65 static void Eval2D(
const int NE,
78 const int nd = maps.
ndof;
79 const int nq = maps.
nqpt;
80 const int ND = T_ND ? T_ND : nd;
81 const int NQ = T_NQ ? T_NQ : nq;
82 const int NMAX = NQ > ND ? NQ : ND;
83 const int VDIM = T_VDIM ? T_VDIM : vdim;
86 MFEM_VERIFY(ND <= QI::MAX_ND2D,
"");
87 MFEM_VERIFY(NQ <= QI::MAX_NQ2D,
"");
88 MFEM_VERIFY(VDIM == 2 || !(eval_flags & QI::DETERMINANTS),
"");
89 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
90 "'geom' must be given (non-null) only when evaluating physical" 94 const auto J =
Reshape(geom ? geom->
J.
Read() :
nullptr, NQ, 2, 2, NE);
103 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
105 const int ND = T_ND ? T_ND : nd;
106 const int NQ = T_NQ ? T_NQ : nq;
107 const int VDIM = T_VDIM ? T_VDIM : vdim;
108 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
109 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
110 MFEM_SHARED
double s_E[max_VDIM*max_ND];
111 MFEM_FOREACH_THREAD(d, x, ND)
113 for (
int c = 0; c < VDIM; c++)
115 s_E[c+d*VDIM] = E(d,c,e);
120 MFEM_FOREACH_THREAD(q, x, NQ)
122 if (eval_flags & QI::VALUES)
125 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
126 for (
int d = 0; d < ND; ++d)
128 const double b = B(q,d);
129 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
131 for (
int c = 0; c < VDIM; c++)
137 if ((eval_flags & QI::DERIVATIVES) ||
138 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
139 (eval_flags & QI::DETERMINANTS))
142 double D[QI::MAX_VDIM2D*2];
143 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
144 for (
int d = 0; d < ND; ++d)
146 const double wx = G(q,0,d);
147 const double wy = G(q,1,d);
148 for (
int c = 0; c < VDIM; c++)
150 double s_e = s_E[c+d*VDIM];
151 D[c+VDIM*0] += s_e * wx;
152 D[c+VDIM*1] += s_e * wy;
155 if (eval_flags & QI::DERIVATIVES)
157 for (
int c = 0; c < VDIM; c++)
161 der(c,0,q,e) = D[c+VDIM*0];
162 der(c,1,q,e) = D[c+VDIM*1];
166 der(q,c,0,e) = D[c+VDIM*0];
167 der(q,c,1,e) = D[c+VDIM*1];
171 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
173 double Jloc[4], Jinv[4];
174 Jloc[0] = J(q,0,0,e);
175 Jloc[1] = J(q,1,0,e);
176 Jloc[2] = J(q,0,1,e);
177 Jloc[3] = J(q,1,1,e);
178 kernels::CalcInverse<2>(Jloc, Jinv);
179 for (
int c = 0; c < VDIM; c++)
181 const double u = D[c+VDIM*0];
182 const double v = D[c+VDIM*1];
183 const double JiU = Jinv[0]*
u + Jinv[1]*v;
184 const double JiV = Jinv[2]*
u + Jinv[3]*v;
197 if (VDIM == 2 && (eval_flags & QI::DETERMINANTS))
201 det(q,e) = kernels::Det<2>(D);
212 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
213 static void Eval3D(
const int NE,
216 const GeometricFactors *geom,
217 const DofToQuad &maps,
222 const int eval_flags)
224 using QI = QuadratureInterpolator;
226 const int nd = maps.ndof;
227 const int nq = maps.nqpt;
228 const int ND = T_ND ? T_ND : nd;
229 const int NQ = T_NQ ? T_NQ : nq;
230 const int NMAX = NQ > ND ? NQ : ND;
231 const int VDIM = T_VDIM ? T_VDIM : vdim;
233 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3,
"");
234 MFEM_VERIFY(ND <= QI::MAX_ND3D,
"");
235 MFEM_VERIFY(NQ <= QI::MAX_NQ3D,
"");
236 MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS),
"");
237 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
238 "'geom' must be given (non-null) only when evaluating physical" 240 const auto B =
Reshape(maps.B.Read(), NQ, ND);
241 const auto G =
Reshape(maps.G.Read(), NQ, 3, ND);
242 const auto J =
Reshape(geom ? geom->J.Read() :
nullptr, NQ, 3, 3, NE);
243 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
245 Reshape(q_val.Write(), NQ, VDIM, NE):
246 Reshape(q_val.Write(), VDIM, NQ, NE);
248 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
249 Reshape(q_der.Write(), VDIM, 3, NQ, NE);
250 auto det =
Reshape(q_det.Write(), NQ, NE);
251 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
253 const int ND = T_ND ? T_ND : nd;
254 const int NQ = T_NQ ? T_NQ : nq;
255 const int VDIM = T_VDIM ? T_VDIM : vdim;
256 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
257 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
258 MFEM_SHARED
double s_E[max_VDIM*max_ND];
259 MFEM_FOREACH_THREAD(d, x, ND)
261 for (
int c = 0; c < VDIM; c++)
263 s_E[c+d*VDIM] = E(d,c,e);
268 MFEM_FOREACH_THREAD(q, x, NQ)
270 if (eval_flags & QI::VALUES)
273 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
274 for (
int d = 0; d < ND; ++d)
276 const double b = B(q,d);
277 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
279 for (
int c = 0; c < VDIM; c++)
285 if ((eval_flags & QI::DERIVATIVES) ||
286 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
287 (eval_flags & QI::DETERMINANTS))
290 double D[QI::MAX_VDIM3D*3];
291 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
292 for (
int d = 0; d < ND; ++d)
294 const double wx = G(q,0,d);
295 const double wy = G(q,1,d);
296 const double wz = G(q,2,d);
297 for (
int c = 0; c < VDIM; c++)
299 double s_e = s_E[c+d*VDIM];
300 D[c+VDIM*0] += s_e * wx;
301 D[c+VDIM*1] += s_e * wy;
302 D[c+VDIM*2] += s_e * wz;
305 if (eval_flags & QI::DERIVATIVES)
307 for (
int c = 0; c < VDIM; c++)
311 der(c,0,q,e) = D[c+VDIM*0];
312 der(c,1,q,e) = D[c+VDIM*1];
313 der(c,2,q,e) = D[c+VDIM*2];
317 der(q,c,0,e) = D[c+VDIM*0];
318 der(q,c,1,e) = D[c+VDIM*1];
319 der(q,c,2,e) = D[c+VDIM*2];
323 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
325 double Jloc[9], Jinv[9];
326 for (
int col = 0; col < 3; col++)
328 for (
int row = 0; row < 3; row++)
330 Jloc[row+3*col] = J(q,row,col,e);
333 kernels::CalcInverse<3>(Jloc, Jinv);
334 for (
int c = 0; c < VDIM; c++)
336 const double u = D[c+VDIM*0];
337 const double v = D[c+VDIM*1];
338 const double w = D[c+VDIM*2];
339 const double JiU = Jinv[0]*
u + Jinv[1]*v + Jinv[2]*w;
340 const double JiV = Jinv[3]*
u + Jinv[4]*v + Jinv[5]*w;
341 const double JiW = Jinv[6]*
u + Jinv[7]*v + Jinv[8]*w;
356 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
360 det(q,e) = kernels::Det<3>(D);
377 using namespace internal::quadrature_interpolator;
380 if (ne == 0) {
return; }
383 const bool use_tensor_eval =
400 "mixed meshes are not supported");
409 TensorValues<QVectorLayout::byNODES>(ne, vdim, maps, e_vec, q_val);
413 TensorDerivatives<QVectorLayout::byNODES>(
414 ne, vdim, maps, e_vec, q_der);
418 TensorPhysDerivatives<QVectorLayout::byNODES>(
419 ne, vdim, maps, *geom, e_vec, q_der);
427 TensorValues<QVectorLayout::byVDIM>(ne, vdim, maps, e_vec, q_val);
431 TensorDerivatives<QVectorLayout::byVDIM>(
432 ne, vdim, maps, e_vec, q_der);
436 TensorPhysDerivatives<QVectorLayout::byVDIM>(
437 ne, vdim, maps, *geom, e_vec, q_der);
442 TensorDeterminants(ne, vdim, maps, e_vec, q_det,
d_buffer);
447 const int nd = maps.
ndof;
448 const int nq = maps.
nqpt;
451 void (*mult)(
const int NE,
460 const int eval_flags) = NULL;
468 case 101: mult = &Eval2D<1,1,1>;
break;
469 case 104: mult = &Eval2D<1,1,4>;
break;
471 case 404: mult = &Eval2D<1,4,4>;
break;
472 case 409: mult = &Eval2D<1,4,9>;
break;
474 case 909: mult = &Eval2D<1,9,9>;
break;
475 case 916: mult = &Eval2D<1,9,16>;
break;
477 case 1616: mult = &Eval2D<1,16,16>;
break;
478 case 1625: mult = &Eval2D<1,16,25>;
break;
479 case 1636: mult = &Eval2D<1,16,36>;
break;
481 case 2525: mult = &Eval2D<1,25,25>;
break;
482 case 2536: mult = &Eval2D<1,25,36>;
break;
483 case 2549: mult = &Eval2D<1,25,49>;
break;
484 case 2564: mult = &Eval2D<1,25,64>;
break;
486 if (nq >= 100 || !mult)
488 mult = &Eval2D<1,0,0>;
493 switch (1000*nd + nq)
496 case 1001: mult = &Eval3D<1,1,1>;
break;
497 case 1008: mult = &Eval3D<1,1,8>;
break;
499 case 8008: mult = &Eval3D<1,8,8>;
break;
500 case 8027: mult = &Eval3D<1,8,27>;
break;
502 case 27027: mult = &Eval3D<1,27,27>;
break;
503 case 27064: mult = &Eval3D<1,27,64>;
break;
505 case 64064: mult = &Eval3D<1,64,64>;
break;
506 case 64125: mult = &Eval3D<1,64,125>;
break;
507 case 64216: mult = &Eval3D<1,64,216>;
break;
509 case 125125: mult = &Eval3D<1,125,125>;
break;
510 case 125216: mult = &Eval3D<1,125,216>;
break;
512 if (nq >= 1000 || !mult)
514 mult = &Eval3D<1,0,0>;
518 else if (vdim == 3 &&
dim == 2)
523 case 101: mult = &Eval2D<3,1,1>;
break;
524 case 104: mult = &Eval2D<3,1,4>;
break;
526 case 404: mult = &Eval2D<3,4,4>;
break;
527 case 409: mult = &Eval2D<3,4,9>;
break;
529 case 904: mult = &Eval2D<3,9,4>;
break;
530 case 909: mult = &Eval2D<3,9,9>;
break;
531 case 916: mult = &Eval2D<3,9,16>;
break;
532 case 925: mult = &Eval2D<3,9,25>;
break;
534 case 1616: mult = &Eval2D<3,16,16>;
break;
535 case 1625: mult = &Eval2D<3,16,25>;
break;
536 case 1636: mult = &Eval2D<3,16,36>;
break;
538 case 2525: mult = &Eval2D<3,25,25>;
break;
539 case 2536: mult = &Eval2D<3,25,36>;
break;
540 case 2549: mult = &Eval2D<3,25,49>;
break;
541 case 2564: mult = &Eval2D<3,25,64>;
break;
542 default: mult = &Eval2D<3,0,0>;
545 else if (vdim ==
dim)
552 case 404: mult = &Eval2D<2,4,4>;
break;
553 case 409: mult = &Eval2D<2,4,9>;
break;
555 case 909: mult = &Eval2D<2,9,9>;
break;
556 case 916: mult = &Eval2D<2,9,16>;
break;
558 case 1616: mult = &Eval2D<2,16,16>;
break;
559 case 1625: mult = &Eval2D<2,16,25>;
break;
560 case 1636: mult = &Eval2D<2,16,36>;
break;
562 case 2525: mult = &Eval2D<2,25,25>;
break;
563 case 2536: mult = &Eval2D<2,25,36>;
break;
564 case 2549: mult = &Eval2D<2,25,49>;
break;
565 case 2564: mult = &Eval2D<2,25,64>;
break;
567 if (nq >= 100 || !mult) { mult = &Eval2D<2,0,0>; }
571 switch (1000*nd + nq)
574 case 8008: mult = &Eval3D<3,8,8>;
break;
575 case 8027: mult = &Eval3D<3,8,27>;
break;
577 case 27027: mult = &Eval3D<3,27,27>;
break;
578 case 27064: mult = &Eval3D<3,27,64>;
break;
579 case 27125: mult = &Eval3D<3,27,125>;
break;
581 case 64064: mult = &Eval3D<3,64,64>;
break;
582 case 64125: mult = &Eval3D<3,64,125>;
break;
583 case 64216: mult = &Eval3D<3,64,216>;
break;
585 case 125125: mult = &Eval3D<3,125,125>;
break;
586 case 125216: mult = &Eval3D<3,125,216>;
break;
588 if (nq >= 1000 || !mult) { mult = &Eval3D<3,0,0>; }
593 mult(ne,vdim,
q_layout,geom,maps,e_vec,q_val,q_der,q_det,eval_flags);
595 else { MFEM_ABORT(
"case not supported yet"); }
604 MFEM_CONTRACT_VAR(eval_flags);
605 MFEM_CONTRACT_VAR(q_val);
606 MFEM_CONTRACT_VAR(q_der);
607 MFEM_CONTRACT_VAR(e_vec);
608 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).
Abstract class for all finite elements.
const class FiniteElement * FE
The FiniteElement that created and owns this object.
Class for an integration rule - an Array of IntegrationPoint.
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
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.
const FiniteElementSpace * fespace
Not owned.
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
const IntegrationRule & GetElementIntRule(int idx) const
Get the IntegrationRule associated with mesh element idx.
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
Evaluate the physical derivatives.
Evaluate the derivatives at quadrature points.
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
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...
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...
Vector J
Jacobians of the element transformations at all quadrature points.
QVectorLayout q_layout
Output Q-vector layout.
virtual double * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
const IntegrationRule * IntRule
Not owned.
Mode mode
Describes the contents of the B, Bt, G, and Gt arrays, see Mode.
bool use_tensor_products
Tensor product evaluation mode.
int GetNE() const
Returns number of elements in the mesh.
Vector d_buffer
Auxiliary device buffer.
int GetVDim() const
Returns vector dimension.
QuadratureInterpolator(const FiniteElementSpace &fes, const IntegrationRule &ir)
Mesh * GetMesh() const
Returns the mesh.
int GetDim() const
Returns the reference space dimension for the finite element.
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
void Values(const Vector &e_vec, Vector &q_val) const
Interpolate the values of the E-vector e_vec at quadrature points.
Structure representing the matrices/tensors needed to evaluate (in reference space) the values...
void MultTranspose(unsigned eval_flags, const Vector &q_val, const Vector &q_der, Vector &e_vec) const
Perform the transpose operation of Mult(). (TODO)
int SpaceDimension() const
Array< double > B
Basis functions evaluated at quadrature points.
Assuming the derivative at quadrature points form a matrix, this flag can be used to compute and stor...
QVectorLayout
Type describing possible layouts for Q-vectors.
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
Full multidimensional representation which does not use tensor product structure. The ordering of the...
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...
void Mult(const Vector &e_vec, unsigned eval_flags, Vector &q_val, Vector &q_der, Vector &q_det) const
Interpolate the E-vector e_vec to quadrature points.
Array< double > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
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...
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
Class representing the storage layout of a QuadratureFunction.
double u(const Vector &xvec)
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
VDIM x NQPT x NE (values) / VDIM x DIM x NQPT x NE (grads)
Evaluate the values at quadrature points.
const QuadratureSpace * qspace
Not owned.