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 =
390 const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
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);
416 if (eval_flags & PHYSICAL_DERIVATIVES)
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);
434 if (eval_flags & PHYSICAL_DERIVATIVES)
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;
449 const int dim = maps.FE->GetDim();
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");
Abstract class for all finite elements.
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 IntegrationRule & GetElementIntRule(int idx) const
Get the IntegrationRule associated with mesh element idx.
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
const FiniteElementSpace * fespace
Not owned.
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
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...
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 void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
int GetNE() const
Returns number of elements in the mesh.
Vector J
Jacobians of the element transformations at all quadrature points.
QVectorLayout q_layout
Output Q-vector layout.
Mesh * GetMesh() const
Returns the mesh.
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.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
int GetVDim() const
Returns vector dimension.
Vector d_buffer
Auxiliary device buffer.
int SpaceDimension() const
QuadratureInterpolator(const FiniteElementSpace &fes, const IntegrationRule &ir)
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
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...
Structure representing the matrices/tensors needed to evaluate (in reference space) the values...
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 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.
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
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...
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)
void Values(const Vector &e_vec, Vector &q_val) const
Interpolate the values of the E-vector e_vec at quadrature points.
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
void MultTranspose(unsigned eval_flags, const Vector &q_val, const Vector &q_der, Vector &e_vec) const
Perform the transpose operation of Mult(). (TODO)
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.