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 static 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))
147 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
148 static 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(VDIM == 2 || !(eval_flags & QI::DETERMINANTS),
"");
172 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
173 "'geom' must be given (non-null) only when evaluating physical" 175 const auto B =
Reshape(maps.B.Read(), NQ, ND);
176 const auto G =
Reshape(maps.G.Read(), NQ, 2, ND);
177 const auto J =
Reshape(geom ? geom->J.Read() :
nullptr, NQ, 2, 2, NE);
178 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
180 Reshape(q_val.Write(), NQ, VDIM, NE):
181 Reshape(q_val.Write(), VDIM, NQ, NE);
183 Reshape(q_der.Write(), NQ, VDIM, 2, NE):
184 Reshape(q_der.Write(), VDIM, 2, NQ, NE);
185 auto det =
Reshape(q_det.Write(), NQ, NE);
188 const int ND = T_ND ? T_ND : nd;
189 const int NQ = T_NQ ? T_NQ : nq;
190 const int VDIM = T_VDIM ? T_VDIM : vdim;
191 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
192 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
193 MFEM_SHARED
double s_E[max_VDIM*max_ND];
194 MFEM_FOREACH_THREAD(d, x, ND)
196 for (
int c = 0; c < VDIM; c++)
198 s_E[c+d*VDIM] = E(d,c,e);
203 MFEM_FOREACH_THREAD(q, x, NQ)
205 if (eval_flags & QI::VALUES)
208 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
209 for (
int d = 0; d < ND; ++d)
211 const double b = B(q,d);
212 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
214 for (
int c = 0; c < VDIM; c++)
220 if ((eval_flags & QI::DERIVATIVES) ||
221 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
222 (eval_flags & QI::DETERMINANTS))
225 double D[QI::MAX_VDIM2D*2];
226 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
227 for (
int d = 0; d < ND; ++d)
229 const double wx = G(q,0,d);
230 const double wy = G(q,1,d);
231 for (
int c = 0; c < VDIM; c++)
233 double s_e = s_E[c+d*VDIM];
234 D[c+VDIM*0] += s_e * wx;
235 D[c+VDIM*1] += s_e * wy;
238 if (eval_flags & QI::DERIVATIVES)
240 for (
int c = 0; c < VDIM; c++)
244 der(c,0,q,e) = D[c+VDIM*0];
245 der(c,1,q,e) = D[c+VDIM*1];
249 der(q,c,0,e) = D[c+VDIM*0];
250 der(q,c,1,e) = D[c+VDIM*1];
254 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
256 double Jloc[4], Jinv[4];
257 Jloc[0] = J(q,0,0,e);
258 Jloc[1] = J(q,1,0,e);
259 Jloc[2] = J(q,0,1,e);
260 Jloc[3] = J(q,1,1,e);
261 kernels::CalcInverse<2>(Jloc, Jinv);
262 for (
int c = 0; c < VDIM; c++)
264 const double u = D[c+VDIM*0];
265 const double v = D[c+VDIM*1];
266 const double JiU = Jinv[0]*
u + Jinv[1]*v;
267 const double JiV = Jinv[2]*
u + Jinv[3]*v;
280 if (VDIM == 2 && (eval_flags & QI::DETERMINANTS))
284 det(q,e) = kernels::Det<2>(D);
295 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
296 static void Eval3D(
const int NE,
299 const GeometricFactors *geom,
300 const DofToQuad &maps,
305 const int eval_flags)
307 using QI = QuadratureInterpolator;
309 const int nd = maps.ndof;
310 const int nq = maps.nqpt;
311 const int ND = T_ND ? T_ND : nd;
312 const int NQ = T_NQ ? T_NQ : nq;
313 const int NMAX = NQ > ND ? NQ : ND;
314 const int VDIM = T_VDIM ? T_VDIM : vdim;
316 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3,
"");
317 MFEM_VERIFY(ND <= QI::MAX_ND3D,
"");
318 MFEM_VERIFY(NQ <= QI::MAX_NQ3D,
"");
319 MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS),
"");
320 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
321 "'geom' must be given (non-null) only when evaluating physical" 323 const auto B =
Reshape(maps.B.Read(), NQ, ND);
324 const auto G =
Reshape(maps.G.Read(), NQ, 3, ND);
325 const auto J =
Reshape(geom ? geom->J.Read() :
nullptr, NQ, 3, 3, NE);
326 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
328 Reshape(q_val.Write(), NQ, VDIM, NE):
329 Reshape(q_val.Write(), VDIM, NQ, NE);
331 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
332 Reshape(q_der.Write(), VDIM, 3, NQ, NE);
333 auto det =
Reshape(q_det.Write(), NQ, NE);
336 const int ND = T_ND ? T_ND : nd;
337 const int NQ = T_NQ ? T_NQ : nq;
338 const int VDIM = T_VDIM ? T_VDIM : vdim;
339 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
340 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
341 MFEM_SHARED
double s_E[max_VDIM*max_ND];
342 MFEM_FOREACH_THREAD(d, x, ND)
344 for (
int c = 0; c < VDIM; c++)
346 s_E[c+d*VDIM] = E(d,c,e);
351 MFEM_FOREACH_THREAD(q, x, NQ)
353 if (eval_flags & QI::VALUES)
356 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
357 for (
int d = 0; d < ND; ++d)
359 const double b = B(q,d);
360 for (
int c = 0; c < VDIM; c++) { ed[c] +=
b*s_E[c+d*VDIM]; }
362 for (
int c = 0; c < VDIM; c++)
368 if ((eval_flags & QI::DERIVATIVES) ||
369 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
370 (eval_flags & QI::DETERMINANTS))
373 double D[QI::MAX_VDIM3D*3];
374 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
375 for (
int d = 0; d < ND; ++d)
377 const double wx = G(q,0,d);
378 const double wy = G(q,1,d);
379 const double wz = G(q,2,d);
380 for (
int c = 0; c < VDIM; c++)
382 double s_e = s_E[c+d*VDIM];
383 D[c+VDIM*0] += s_e * wx;
384 D[c+VDIM*1] += s_e * wy;
385 D[c+VDIM*2] += s_e * wz;
388 if (eval_flags & QI::DERIVATIVES)
390 for (
int c = 0; c < VDIM; c++)
394 der(c,0,q,e) = D[c+VDIM*0];
395 der(c,1,q,e) = D[c+VDIM*1];
396 der(c,2,q,e) = D[c+VDIM*2];
400 der(q,c,0,e) = D[c+VDIM*0];
401 der(q,c,1,e) = D[c+VDIM*1];
402 der(q,c,2,e) = D[c+VDIM*2];
406 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
408 double Jloc[9], Jinv[9];
409 for (
int col = 0; col < 3; col++)
411 for (
int row = 0; row < 3; row++)
413 Jloc[row+3*col] = J(q,row,col,e);
416 kernels::CalcInverse<3>(Jloc, Jinv);
417 for (
int c = 0; c < VDIM; c++)
419 const double u = D[c+VDIM*0];
420 const double v = D[c+VDIM*1];
421 const double w = D[c+VDIM*2];
422 const double JiU = Jinv[0]*
u + Jinv[1]*v + Jinv[2]*w;
423 const double JiV = Jinv[3]*
u + Jinv[4]*v + Jinv[5]*w;
424 const double JiW = Jinv[6]*
u + Jinv[7]*v + Jinv[8]*w;
439 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
443 det(q,e) = kernels::Det<3>(D);
460 using namespace internal::quadrature_interpolator;
463 if (ne == 0) {
return; }
466 const bool use_tensor_eval =
483 "mixed meshes are not supported");
492 TensorValues<QVectorLayout::byNODES>(ne, vdim, maps, e_vec, q_val);
496 TensorDerivatives<QVectorLayout::byNODES>(
497 ne, vdim, maps, e_vec, q_der);
501 TensorPhysDerivatives<QVectorLayout::byNODES>(
502 ne, vdim, maps, *geom, e_vec, q_der);
510 TensorValues<QVectorLayout::byVDIM>(ne, vdim, maps, e_vec, q_val);
514 TensorDerivatives<QVectorLayout::byVDIM>(
515 ne, vdim, maps, e_vec, q_der);
519 TensorPhysDerivatives<QVectorLayout::byVDIM>(
520 ne, vdim, maps, *geom, e_vec, q_der);
525 TensorDeterminants(ne, vdim, maps, e_vec, q_det,
d_buffer);
530 const int nd = maps.
ndof;
531 const int nq = maps.
nqpt;
534 void (*mult)(
const int NE,
543 const int eval_flags) = NULL;
556 case 101: mult = &Eval2D<1,1,1>;
break;
557 case 104: mult = &Eval2D<1,1,4>;
break;
559 case 404: mult = &Eval2D<1,4,4>;
break;
560 case 409: mult = &Eval2D<1,4,9>;
break;
562 case 909: mult = &Eval2D<1,9,9>;
break;
563 case 916: mult = &Eval2D<1,9,16>;
break;
565 case 1616: mult = &Eval2D<1,16,16>;
break;
566 case 1625: mult = &Eval2D<1,16,25>;
break;
567 case 1636: mult = &Eval2D<1,16,36>;
break;
569 case 2525: mult = &Eval2D<1,25,25>;
break;
570 case 2536: mult = &Eval2D<1,25,36>;
break;
571 case 2549: mult = &Eval2D<1,25,49>;
break;
572 case 2564: mult = &Eval2D<1,25,64>;
break;
574 if (nq >= 100 || !mult)
576 mult = &Eval2D<1,0,0>;
581 switch (1000*nd + nq)
584 case 1001: mult = &Eval3D<1,1,1>;
break;
585 case 1008: mult = &Eval3D<1,1,8>;
break;
587 case 8008: mult = &Eval3D<1,8,8>;
break;
588 case 8027: mult = &Eval3D<1,8,27>;
break;
590 case 27027: mult = &Eval3D<1,27,27>;
break;
591 case 27064: mult = &Eval3D<1,27,64>;
break;
593 case 64064: mult = &Eval3D<1,64,64>;
break;
594 case 64125: mult = &Eval3D<1,64,125>;
break;
595 case 64216: mult = &Eval3D<1,64,216>;
break;
597 case 125125: mult = &Eval3D<1,125,125>;
break;
598 case 125216: mult = &Eval3D<1,125,216>;
break;
600 if (nq >= 1000 || !mult)
602 mult = &Eval3D<1,0,0>;
606 else if (vdim == 3 &&
dim == 2)
611 case 101: mult = &Eval2D<3,1,1>;
break;
612 case 104: mult = &Eval2D<3,1,4>;
break;
614 case 404: mult = &Eval2D<3,4,4>;
break;
615 case 409: mult = &Eval2D<3,4,9>;
break;
617 case 904: mult = &Eval2D<3,9,4>;
break;
618 case 909: mult = &Eval2D<3,9,9>;
break;
619 case 916: mult = &Eval2D<3,9,16>;
break;
620 case 925: mult = &Eval2D<3,9,25>;
break;
622 case 1616: mult = &Eval2D<3,16,16>;
break;
623 case 1625: mult = &Eval2D<3,16,25>;
break;
624 case 1636: mult = &Eval2D<3,16,36>;
break;
626 case 2525: mult = &Eval2D<3,25,25>;
break;
627 case 2536: mult = &Eval2D<3,25,36>;
break;
628 case 2549: mult = &Eval2D<3,25,49>;
break;
629 case 2564: mult = &Eval2D<3,25,64>;
break;
630 default: mult = &Eval2D<3,0,0>;
633 else if (vdim ==
dim)
640 case 404: mult = &Eval2D<2,4,4>;
break;
641 case 409: mult = &Eval2D<2,4,9>;
break;
643 case 909: mult = &Eval2D<2,9,9>;
break;
644 case 916: mult = &Eval2D<2,9,16>;
break;
646 case 1616: mult = &Eval2D<2,16,16>;
break;
647 case 1625: mult = &Eval2D<2,16,25>;
break;
648 case 1636: mult = &Eval2D<2,16,36>;
break;
650 case 2525: mult = &Eval2D<2,25,25>;
break;
651 case 2536: mult = &Eval2D<2,25,36>;
break;
652 case 2549: mult = &Eval2D<2,25,49>;
break;
653 case 2564: mult = &Eval2D<2,25,64>;
break;
655 if (nq >= 100 || !mult) { mult = &Eval2D<2,0,0>; }
659 switch (1000*nd + nq)
662 case 8008: mult = &Eval3D<3,8,8>;
break;
663 case 8027: mult = &Eval3D<3,8,27>;
break;
665 case 27027: mult = &Eval3D<3,27,27>;
break;
666 case 27064: mult = &Eval3D<3,27,64>;
break;
667 case 27125: mult = &Eval3D<3,27,125>;
break;
669 case 64064: mult = &Eval3D<3,64,64>;
break;
670 case 64125: mult = &Eval3D<3,64,125>;
break;
671 case 64216: mult = &Eval3D<3,64,216>;
break;
673 case 125125: mult = &Eval3D<3,125,125>;
break;
674 case 125216: mult = &Eval3D<3,125,216>;
break;
676 if (nq >= 1000 || !mult) { mult = &Eval3D<3,0,0>; }
681 mult(ne,vdim,
q_layout,geom,maps,e_vec,q_val,q_der,q_det,eval_flags);
683 else { MFEM_ABORT(
"case not supported yet"); }
692 MFEM_CONTRACT_VAR(eval_flags);
693 MFEM_CONTRACT_VAR(q_val);
694 MFEM_CONTRACT_VAR(q_der);
695 MFEM_CONTRACT_VAR(e_vec);
696 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.
void forall_2D(int N, int X, int Y, lambda &&body)
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.
int Dimension() const
Dimension of the reference space used within the elements.
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.
void forall(int N, lambda &&body)
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
Dimension of the physical space containing the mesh.
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.