13 #include "qinterp/dispatch.hpp"
14 #include "../general/forall.hpp"
15 #include "../linalg/dtensor.hpp"
16 #include "../linalg/kernels.hpp"
33 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
34 "Only scalar finite elements are supported");
49 MFEM_VERIFY(dynamic_cast<const ScalarFiniteElement*>(fe) != NULL,
50 "Only scalar finite elements are supported");
56 namespace quadrature_interpolator
63 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
64 static void Eval2D(
const int NE,
77 const int nd = maps.
ndof;
78 const int nq = maps.
nqpt;
79 const int ND = T_ND ? T_ND : nd;
80 const int NQ = T_NQ ? T_NQ : nq;
81 const int NMAX = NQ > ND ? NQ : ND;
82 const int VDIM = T_VDIM ? T_VDIM : vdim;
85 MFEM_VERIFY(ND <= QI::MAX_ND2D,
"");
86 MFEM_VERIFY(NQ <= QI::MAX_NQ2D,
"");
87 MFEM_VERIFY(VDIM == 2 || !(eval_flags & QI::DETERMINANTS),
"");
88 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
89 "'geom' must be given (non-null) only when evaluating physical"
93 const auto J =
Reshape(geom ? geom->
J.
Read() :
nullptr, NQ, 2, 2, NE);
102 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
104 const int ND = T_ND ? T_ND : nd;
105 const int NQ = T_NQ ? T_NQ : nq;
106 const int VDIM = T_VDIM ? T_VDIM : vdim;
107 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
108 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
109 MFEM_SHARED
double s_E[max_VDIM*max_ND];
110 MFEM_FOREACH_THREAD(d, x, ND)
112 for (
int c = 0; c < VDIM; c++)
114 s_E[c+d*VDIM] = E(d,c,e);
119 MFEM_FOREACH_THREAD(q, x, NQ)
121 if (eval_flags & QI::VALUES)
124 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
125 for (
int d = 0; d < ND; ++d)
127 const double b = B(q,d);
128 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
130 for (
int c = 0; c < VDIM; c++)
136 if ((eval_flags & QI::DERIVATIVES) ||
137 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
138 (eval_flags & QI::DETERMINANTS))
141 double D[QI::MAX_VDIM2D*2];
142 for (
int i = 0; i < 2*VDIM; i++) { D[i] = 0.0; }
143 for (
int d = 0; d < ND; ++d)
145 const double wx = G(q,0,d);
146 const double wy = G(q,1,d);
147 for (
int c = 0; c < VDIM; c++)
149 double s_e = s_E[c+d*VDIM];
150 D[c+VDIM*0] += s_e * wx;
151 D[c+VDIM*1] += s_e * wy;
154 if (eval_flags & QI::DERIVATIVES)
156 for (
int c = 0; c < VDIM; c++)
160 der(c,0,q,e) = D[c+VDIM*0];
161 der(c,1,q,e) = D[c+VDIM*1];
165 der(q,c,0,e) = D[c+VDIM*0];
166 der(q,c,1,e) = D[c+VDIM*1];
170 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
172 double Jloc[4], Jinv[4];
173 Jloc[0] = J(q,0,0,e);
174 Jloc[1] = J(q,1,0,e);
175 Jloc[2] = J(q,0,1,e);
176 Jloc[3] = J(q,1,1,e);
177 kernels::CalcInverse<2>(Jloc, Jinv);
178 for (
int c = 0; c < VDIM; c++)
180 const double u = D[c+VDIM*0];
181 const double v = D[c+VDIM*1];
182 const double JiU = Jinv[0]*u + Jinv[1]*v;
183 const double JiV = Jinv[2]*u + Jinv[3]*v;
196 if (VDIM == 2 && (eval_flags & QI::DETERMINANTS))
200 det(q,e) = kernels::Det<2>(D);
211 template<const
int T_VDIM, const
int T_ND, const
int T_NQ>
212 static void Eval3D(
const int NE,
215 const GeometricFactors *geom,
216 const DofToQuad &maps,
221 const int eval_flags)
223 using QI = QuadratureInterpolator;
225 const int nd = maps.ndof;
226 const int nq = maps.nqpt;
227 const int ND = T_ND ? T_ND : nd;
228 const int NQ = T_NQ ? T_NQ : nq;
229 const int NMAX = NQ > ND ? NQ : ND;
230 const int VDIM = T_VDIM ? T_VDIM : vdim;
232 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3,
"");
233 MFEM_VERIFY(ND <= QI::MAX_ND3D,
"");
234 MFEM_VERIFY(NQ <= QI::MAX_NQ3D,
"");
235 MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS),
"");
236 MFEM_VERIFY(
bool(geom) ==
bool(eval_flags & QI::PHYSICAL_DERIVATIVES),
237 "'geom' must be given (non-null) only when evaluating physical"
239 const auto B =
Reshape(maps.B.Read(), NQ, ND);
240 const auto G =
Reshape(maps.G.Read(), NQ, 3, ND);
241 const auto J =
Reshape(geom ? geom->J.Read() :
nullptr, NQ, 3, 3, NE);
242 const auto E =
Reshape(e_vec.Read(), ND, VDIM, NE);
244 Reshape(q_val.Write(), NQ, VDIM, NE):
245 Reshape(q_val.Write(), VDIM, NQ, NE);
247 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
248 Reshape(q_der.Write(), VDIM, 3, NQ, NE);
249 auto det =
Reshape(q_det.Write(), NQ, NE);
250 MFEM_FORALL_2D(e, NE, NMAX, 1, 1,
252 const int ND = T_ND ? T_ND : nd;
253 const int NQ = T_NQ ? T_NQ : nq;
254 const int VDIM = T_VDIM ? T_VDIM : vdim;
255 constexpr
int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
256 constexpr
int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
257 MFEM_SHARED
double s_E[max_VDIM*max_ND];
258 MFEM_FOREACH_THREAD(d, x, ND)
260 for (
int c = 0; c < VDIM; c++)
262 s_E[c+d*VDIM] = E(d,c,e);
267 MFEM_FOREACH_THREAD(q, x, NQ)
269 if (eval_flags & QI::VALUES)
272 for (
int c = 0; c < VDIM; c++) { ed[c] = 0.0; }
273 for (
int d = 0; d < ND; ++d)
275 const double b = B(q,d);
276 for (
int c = 0; c < VDIM; c++) { ed[c] += b*s_E[c+d*VDIM]; }
278 for (
int c = 0; c < VDIM; c++)
284 if ((eval_flags & QI::DERIVATIVES) ||
285 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
286 (eval_flags & QI::DETERMINANTS))
289 double D[QI::MAX_VDIM3D*3];
290 for (
int i = 0; i < 3*VDIM; i++) { D[i] = 0.0; }
291 for (
int d = 0; d < ND; ++d)
293 const double wx = G(q,0,d);
294 const double wy = G(q,1,d);
295 const double wz = G(q,2,d);
296 for (
int c = 0; c < VDIM; c++)
298 double s_e = s_E[c+d*VDIM];
299 D[c+VDIM*0] += s_e * wx;
300 D[c+VDIM*1] += s_e * wy;
301 D[c+VDIM*2] += s_e * wz;
304 if (eval_flags & QI::DERIVATIVES)
306 for (
int c = 0; c < VDIM; c++)
310 der(c,0,q,e) = D[c+VDIM*0];
311 der(c,1,q,e) = D[c+VDIM*1];
312 der(c,2,q,e) = D[c+VDIM*2];
316 der(q,c,0,e) = D[c+VDIM*0];
317 der(q,c,1,e) = D[c+VDIM*1];
318 der(q,c,2,e) = D[c+VDIM*2];
322 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
324 double Jloc[9], Jinv[9];
325 for (
int col = 0; col < 3; col++)
327 for (
int row = 0; row < 3; row++)
329 Jloc[row+3*col] = J(q,row,col,e);
332 kernels::CalcInverse<3>(Jloc, Jinv);
333 for (
int c = 0; c < VDIM; c++)
335 const double u = D[c+VDIM*0];
336 const double v = D[c+VDIM*1];
337 const double w = D[c+VDIM*2];
338 const double JiU = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
339 const double JiV = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
340 const double JiW = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
355 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
359 det(q,e) = kernels::Det<3>(D);
376 using namespace internal::quadrature_interpolator;
379 if (ne == 0) {
return; }
382 const bool use_tensor_eval =
389 const DofToQuad &maps = fe->GetDofToQuad(*ir, mode);
399 "mixed meshes are not supported");
408 TensorValues<QVectorLayout::byNODES>(ne, vdim, maps, e_vec, q_val);
412 TensorDerivatives<QVectorLayout::byNODES>(
413 ne, vdim, maps, e_vec, q_der);
415 if (eval_flags & PHYSICAL_DERIVATIVES)
417 TensorPhysDerivatives<QVectorLayout::byNODES>(
418 ne, vdim, maps, *geom, e_vec, q_der);
426 TensorValues<QVectorLayout::byVDIM>(ne, vdim, maps, e_vec, q_val);
430 TensorDerivatives<QVectorLayout::byVDIM>(
431 ne, vdim, maps, e_vec, q_der);
433 if (eval_flags & PHYSICAL_DERIVATIVES)
435 TensorPhysDerivatives<QVectorLayout::byVDIM>(
436 ne, vdim, maps, *geom, e_vec, q_der);
441 TensorDeterminants(ne, vdim, maps, e_vec, q_det,
d_buffer);
446 const int nd = maps.ndof;
447 const int nq = maps.nqpt;
448 const int dim = maps.FE->GetDim();
450 void (*mult)(
const int NE,
459 const int eval_flags) = NULL;
467 case 101: mult = &Eval2D<1,1,1>;
break;
468 case 104: mult = &Eval2D<1,1,4>;
break;
470 case 404: mult = &Eval2D<1,4,4>;
break;
471 case 409: mult = &Eval2D<1,4,9>;
break;
473 case 909: mult = &Eval2D<1,9,9>;
break;
474 case 916: mult = &Eval2D<1,9,16>;
break;
476 case 1616: mult = &Eval2D<1,16,16>;
break;
477 case 1625: mult = &Eval2D<1,16,25>;
break;
478 case 1636: mult = &Eval2D<1,16,36>;
break;
480 case 2525: mult = &Eval2D<1,25,25>;
break;
481 case 2536: mult = &Eval2D<1,25,36>;
break;
482 case 2549: mult = &Eval2D<1,25,49>;
break;
483 case 2564: mult = &Eval2D<1,25,64>;
break;
485 if (nq >= 100 || !mult)
487 mult = &Eval2D<1,0,0>;
492 switch (1000*nd + nq)
495 case 1001: mult = &Eval3D<1,1,1>;
break;
496 case 1008: mult = &Eval3D<1,1,8>;
break;
498 case 8008: mult = &Eval3D<1,8,8>;
break;
499 case 8027: mult = &Eval3D<1,8,27>;
break;
501 case 27027: mult = &Eval3D<1,27,27>;
break;
502 case 27064: mult = &Eval3D<1,27,64>;
break;
504 case 64064: mult = &Eval3D<1,64,64>;
break;
505 case 64125: mult = &Eval3D<1,64,125>;
break;
506 case 64216: mult = &Eval3D<1,64,216>;
break;
508 case 125125: mult = &Eval3D<1,125,125>;
break;
509 case 125216: mult = &Eval3D<1,125,216>;
break;
511 if (nq >= 1000 || !mult)
513 mult = &Eval3D<1,0,0>;
517 else if (vdim == 3 && dim == 2)
522 case 101: mult = &Eval2D<3,1,1>;
break;
523 case 104: mult = &Eval2D<3,1,4>;
break;
525 case 404: mult = &Eval2D<3,4,4>;
break;
526 case 409: mult = &Eval2D<3,4,9>;
break;
528 case 904: mult = &Eval2D<3,9,4>;
break;
529 case 909: mult = &Eval2D<3,9,9>;
break;
530 case 916: mult = &Eval2D<3,9,16>;
break;
531 case 925: mult = &Eval2D<3,9,25>;
break;
533 case 1616: mult = &Eval2D<3,16,16>;
break;
534 case 1625: mult = &Eval2D<3,16,25>;
break;
535 case 1636: mult = &Eval2D<3,16,36>;
break;
537 case 2525: mult = &Eval2D<3,25,25>;
break;
538 case 2536: mult = &Eval2D<3,25,36>;
break;
539 case 2549: mult = &Eval2D<3,25,49>;
break;
540 case 2564: mult = &Eval2D<3,25,64>;
break;
541 default: mult = &Eval2D<3,0,0>;
544 else if (vdim == dim)
551 case 404: mult = &Eval2D<2,4,4>;
break;
552 case 409: mult = &Eval2D<2,4,9>;
break;
554 case 909: mult = &Eval2D<2,9,9>;
break;
555 case 916: mult = &Eval2D<2,9,16>;
break;
557 case 1616: mult = &Eval2D<2,16,16>;
break;
558 case 1625: mult = &Eval2D<2,16,25>;
break;
559 case 1636: mult = &Eval2D<2,16,36>;
break;
561 case 2525: mult = &Eval2D<2,25,25>;
break;
562 case 2536: mult = &Eval2D<2,25,36>;
break;
563 case 2549: mult = &Eval2D<2,25,49>;
break;
564 case 2564: mult = &Eval2D<2,25,64>;
break;
566 if (nq >= 100 || !mult) { mult = &Eval2D<2,0,0>; }
570 switch (1000*nd + nq)
573 case 8008: mult = &Eval3D<3,8,8>;
break;
574 case 8027: mult = &Eval3D<3,8,27>;
break;
576 case 27027: mult = &Eval3D<3,27,27>;
break;
577 case 27064: mult = &Eval3D<3,27,64>;
break;
578 case 27125: mult = &Eval3D<3,27,125>;
break;
580 case 64064: mult = &Eval3D<3,64,64>;
break;
581 case 64125: mult = &Eval3D<3,64,125>;
break;
582 case 64216: mult = &Eval3D<3,64,216>;
break;
584 case 125125: mult = &Eval3D<3,125,125>;
break;
585 case 125216: mult = &Eval3D<3,125,216>;
break;
587 if (nq >= 1000 || !mult) { mult = &Eval3D<3,0,0>; }
592 mult(ne,vdim,q_layout,geom,maps,e_vec,q_val,q_der,q_det,eval_flags);
594 else { MFEM_ABORT(
"case not supported yet"); }
603 MFEM_CONTRACT_VAR(eval_flags);
604 MFEM_CONTRACT_VAR(q_val);
605 MFEM_CONTRACT_VAR(q_der);
606 MFEM_CONTRACT_VAR(e_vec);
607 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)
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
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.
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)
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.