15#ifndef MFEM_QUADINTERP_EVAL
16#define MFEM_QUADINTERP_EVAL
30namespace quadrature_interpolator
33template <QVectorLayout Q_LAYOUT,
bool Integral>
34void ImplValues1D(
const int NE,
const real_t *b_,
const real_t *detJ_,
35 const real_t *x_,
real_t *y_,
const int vdim,
const int d1d,
40 const auto b =
Reshape(b_, q1d, d1d);
41 const auto x =
Reshape(x_, d1d, vdim, NE);
42 const auto detJ =
Reshape(detJ_, q1d, NE);
45 for (
int c = 0; c < vdim; c++)
47 for (
int q = 0; q < q1d; q++)
50 for (
int d = 0; d < d1d; d++)
52 u +=
b(q, d) * x(d, c, e);
54 if constexpr (Integral)
71template <QVectorLayout Q_LAYOUT>
73 const int vdim,
const int d1d,
const int q1d)
75 ImplValues1D<Q_LAYOUT, false>(NE, b_,
nullptr, x_, y_, vdim, d1d, q1d);
79template <
QVectorLayout Q_LAYOUT,
bool Integral,
int T_VDIM = 0,
int T_D1D = 0,
80 int T_Q1D = 0,
int T_NBZ = 1>
81void ImplValues2D(
const int NE,
const real_t *b_,
const real_t *detJ_,
83 const int d1d = 0,
const int q1d = 0)
85 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
87 const int D1D = T_D1D ? T_D1D : d1d;
88 const int Q1D = T_Q1D ? T_Q1D : q1d;
89 const int VDIM = T_VDIM ? T_VDIM : vdim;
91 const auto b =
Reshape(b_, Q1D, D1D);
95 const auto x =
Reshape(x_, D1D, D1D, VDIM, NE);
96 const auto detJ =
Reshape(detJ_, Q1D, Q1D, NE);
98 ?
Reshape(y_, Q1D, Q1D, VDIM, NE)
99 :
Reshape(y_, VDIM, Q1D, Q1D, NE);
100 const int D1D = T_D1D ? T_D1D : d1d;
101 const int Q1D = T_Q1D ? T_Q1D : q1d;
102 const int VDIM = T_VDIM ? T_VDIM : vdim;
103 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
104 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
105 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
106 const int tidz = MFEM_THREAD_ID(z);
108 MFEM_SHARED
real_t sB[MQ1*MD1];
109 MFEM_SHARED
real_t sm0[NBZ][MDQ*MDQ];
110 MFEM_SHARED
real_t sm1[NBZ][MDQ*MDQ];
112 kernels::internal::LoadB<MD1,MQ1>(D1D,Q1D,
b,sB);
119 for (
int c = 0; c < VDIM; c++)
121 MFEM_FOREACH_THREAD(dy,y,D1D)
123 MFEM_FOREACH_THREAD(dx, x, D1D)
125 DD(dx, dy) = x(dx, dy, c, e);
129 kernels::internal::EvalX(D1D,Q1D,B,DD,DQ);
130 kernels::internal::EvalY(D1D,Q1D,B,DQ,QQ);
131 MFEM_FOREACH_THREAD(qy,y,Q1D)
133 MFEM_FOREACH_THREAD(qx,x,Q1D)
136 if constexpr (Integral)
138 u /= detJ(qx, qy, e);
156template <
QVectorLayout Q_LAYOUT,
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0,
159 const int vdim = 0,
const int d1d = 0,
const int q1d = 0)
161 return ImplValues2D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D, T_NBZ>(
162 NE, b_,
nullptr, x_, y_, vdim, d1d, q1d);
166template <
QVectorLayout Q_LAYOUT,
bool Integral,
int T_VDIM = 0,
int T_D1D = 0,
168void ImplValues3D(
const int NE,
const real_t *b_,
const real_t *detJ_,
170 const int d1d = 0,
const int q1d = 0)
172 const int D1D = T_D1D ? T_D1D : d1d;
173 const int Q1D = T_Q1D ? T_Q1D : q1d;
174 const int VDIM = T_VDIM ? T_VDIM : vdim;
176 const auto b =
Reshape(b_, Q1D, D1D);
180 const auto x =
Reshape(x_, D1D, D1D, D1D, VDIM, NE);
181 const auto detJ =
Reshape(detJ_, Q1D, Q1D, Q1D, NE);
183 ?
Reshape(y_, Q1D, Q1D, Q1D, VDIM, NE)
184 :
Reshape(y_, VDIM, Q1D, Q1D, Q1D, NE);
185 const int D1D = T_D1D ? T_D1D : d1d;
186 const int Q1D = T_Q1D ? T_Q1D : q1d;
187 const int VDIM = T_VDIM ? T_VDIM : vdim;
188 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_INTERP_1D;
189 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_INTERP_1D;
190 constexpr int MDQ = (MQ1 > MD1) ? MQ1 : MD1;
192 MFEM_SHARED
real_t sB[MQ1*MD1];
193 MFEM_SHARED
real_t sm0[MDQ*MDQ*MDQ];
194 MFEM_SHARED
real_t sm1[MDQ*MDQ*MDQ];
196 kernels::internal::LoadB<MD1,MQ1>(D1D,Q1D,
b,sB);
204 for (
int c = 0; c < VDIM; c++)
206 MFEM_FOREACH_THREAD(dz, z, D1D)
208 MFEM_FOREACH_THREAD(dy, y, D1D)
210 MFEM_FOREACH_THREAD(dx, x, D1D)
212 DDD(dx, dy, dz) = x(dx, dy, dz, c, e);
217 kernels::internal::EvalX(D1D,Q1D,B,DDD,DDQ);
218 kernels::internal::EvalY(D1D,Q1D,B,DDQ,DQQ);
219 kernels::internal::EvalZ(D1D,Q1D,B,DQQ,QQQ);
220 MFEM_FOREACH_THREAD(qz,z,Q1D)
222 MFEM_FOREACH_THREAD(qy,y,Q1D)
224 MFEM_FOREACH_THREAD(qx,x,Q1D)
227 if constexpr (Integral)
229 u /= detJ(qx, qy, qz, e);
233 y(c, qx, qy, qz, e) =
u;
237 y(qx, qy, qz, c, e) =
u;
248template <QVectorLayout Q_LAYOUT,
int T_VDIM = 0,
int T_D1D = 0,
int T_Q1D = 0>
250 const int vdim = 0,
const int d1d = 0,
const int q1d = 0)
252 return ImplValues3D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D>(
253 NE, b_,
nullptr, x_, y_, vdim, d1d, q1d);
256template <
bool Integral>
257void ImplEval1D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
258 const real_t *detJ,
const GeometricFactors *geom,
259 const DofToQuad &maps,
const Vector &e_vec, Vector &q_val,
260 Vector &q_der, Vector &q_det,
const int eval_flags);
262inline void Eval1D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
263 const GeometricFactors *geom,
const DofToQuad &maps,
264 const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det,
265 const int eval_flags)
267 ImplEval1D<false>(NE, vdim, q_layout,
nullptr, geom, maps, e_vec, q_val,
268 q_der, q_det, eval_flags);
275template <
bool Integral, const
int T_VDIM, const
int T_ND, const
int T_NQ>
276void ImplEval2D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
277 const real_t *detJ_,
const GeometricFactors *geom,
278 const DofToQuad &maps,
const Vector &e_vec, Vector &q_val,
279 Vector &q_der, Vector &q_det,
const int eval_flags)
281 using QI = QuadratureInterpolator;
283 const int nd = maps.ndof;
284 const int nq = maps.nqpt;
285 const int ND = T_ND ? T_ND : nd;
286 const int NQ = T_NQ ? T_NQ : nq;
287 const int NMAX = NQ > ND ? NQ : ND;
288 const int VDIM = T_VDIM ? T_VDIM : vdim;
290 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 2,
"");
291 MFEM_VERIFY(ND <= QI::MAX_ND2D,
"");
292 MFEM_VERIFY(NQ <= QI::MAX_NQ2D,
"");
293 if constexpr(Integral)
295 MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
297 "Integral FE does not support computing derivatives");
299 const auto B =
Reshape(maps.B.Read(), NQ, ND);
300 const auto G =
Reshape(maps.G.Read(), NQ, 2, ND);
301 const auto J =
Reshape(geom ? geom->J.Read() : nullptr, NQ, 2, 2, NE);
302 const auto E_ = e_vec.Read();
304 Reshape(q_val.Write(), NQ, VDIM, NE):
307 Reshape(q_der.Write(), NQ, VDIM, 2, NE):
312 const auto E =
Reshape(E_, ND, VDIM, NE);
313 const auto detJ =
Reshape(detJ_, NQ, NE);
314 const int ND = T_ND ? T_ND : nd;
315 const int NQ = T_NQ ? T_NQ : nq;
316 const int VDIM = T_VDIM ? T_VDIM : vdim;
317 constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND2D;
318 constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM2D;
319 MFEM_SHARED
real_t s_E[max_VDIM*max_ND];
320 MFEM_FOREACH_THREAD(d, x, ND)
322 for (
int c = 0; c < VDIM; c++)
324 s_E[c + d * VDIM] = E(d, c, e);
329 MFEM_FOREACH_THREAD(q, x, NQ)
331 if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
334 for (
int c = 0; c < VDIM; c++)
338 for (
int d = 0; d < ND; ++d)
341 for (
int c = 0; c < VDIM; c++)
343 ed[c] +=
b * s_E[c + d * VDIM];
346 for (
int c = 0; c < VDIM; c++)
348 if constexpr (Integral)
354 val(c, q, e) = ed[c];
358 val(q, c, e) = ed[c];
362 if ((eval_flags & QI::DERIVATIVES) ||
363 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
364 (eval_flags & QI::DETERMINANTS))
367 real_t D[QI::MAX_VDIM2D*2];
368 for (
int i = 0; i < 2*VDIM; i++)
372 for (
int d = 0; d < ND; ++d)
374 const real_t wx = G(q,0,d);
375 const real_t wy = G(q,1,d);
376 for (
int c = 0; c < VDIM; c++)
378 real_t s_e = s_E[c+d*VDIM];
379 D[c+VDIM*0] += s_e * wx;
380 D[c+VDIM*1] += s_e * wy;
383 if (eval_flags & QI::DERIVATIVES)
385 for (
int c = 0; c < VDIM; c++)
389 der(c,0,q,e) = D[c+VDIM*0];
390 der(c,1,q,e) = D[c+VDIM*1];
394 der(q,c,0,e) = D[c+VDIM*0];
395 der(q,c,1,e) = D[c+VDIM*1];
399 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
402 Jloc[0] = J(q,0,0,e);
403 Jloc[1] = J(q,1,0,e);
404 Jloc[2] = J(q,0,1,e);
405 Jloc[3] = J(q,1,1,e);
407 for (
int c = 0; c < VDIM; c++)
410 const real_t v = D[c+VDIM*1];
411 const real_t JiU = Jinv[0]*
u + Jinv[1]*v;
412 const real_t JiV = Jinv[2]*
u + Jinv[3]*v;
425 if (eval_flags & QI::DETERMINANTS)
433 DeviceTensor<2> j(D, 3, 2);
434 const real_t dE = j(0,0)*j(0,0) + j(1,0)*j(1,0) + j(2,0)*j(2,0);
435 const real_t dF = j(0,0)*j(0,1) + j(1,0)*j(1,1) + j(2,0)*j(2,1);
436 const real_t dG = j(0,1)*j(0,1) + j(1,1)*j(1,1) + j(2,1)*j(2,1);
437 det(q,e) = std::sqrt(dE*dG - dF*dF);
449template <const
int T_VDIM, const
int T_ND, const
int T_NQ>
450void Eval2D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
451 const GeometricFactors *geom,
const DofToQuad &maps,
452 const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det,
453 const int eval_flags)
455 ImplEval2D<false, T_VDIM, T_ND, T_NQ>(NE, vdim, q_layout,
nullptr, geom,
456 maps, e_vec, q_val, q_der, q_det,
464template <
bool Integral, const
int T_VDIM, const
int T_ND, const
int T_NQ>
465void ImplEval3D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
466 const real_t *detJ_,
const GeometricFactors *geom,
467 const DofToQuad &maps,
const Vector &e_vec, Vector &q_val,
468 Vector &q_der, Vector &q_det,
const int eval_flags)
470 using QI = QuadratureInterpolator;
472 const int nd = maps.ndof;
473 const int nq = maps.nqpt;
474 const int ND = T_ND ? T_ND : nd;
475 const int NQ = T_NQ ? T_NQ : nq;
476 const int NMAX = NQ > ND ? NQ : ND;
477 const int VDIM = T_VDIM ? T_VDIM : vdim;
479 MFEM_ASSERT(!geom || geom->mesh->SpaceDimension() == 3,
"");
480 MFEM_VERIFY(ND <= QI::MAX_ND3D,
"");
481 MFEM_VERIFY(NQ <= QI::MAX_NQ3D,
"");
482 MFEM_VERIFY(VDIM == 3 || !(eval_flags & QI::DETERMINANTS),
"");
483 if constexpr(Integral)
485 MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
487 "Integral FE does not support computing derivatives");
489 const auto B =
Reshape(maps.B.Read(), NQ, ND);
490 const auto G =
Reshape(maps.G.Read(), NQ, 3, ND);
491 const auto J =
Reshape(geom ? geom->J.Read() : nullptr, NQ, 3, 3, NE);
492 auto E_ = e_vec.Read();
494 Reshape(q_val.Write(), NQ, VDIM, NE):
497 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
502 const auto E =
Reshape(E_, ND, VDIM, NE);
503 const auto detJ =
Reshape(detJ_, NQ, NE);
504 const int ND = T_ND ? T_ND : nd;
505 const int NQ = T_NQ ? T_NQ : nq;
506 const int VDIM = T_VDIM ? T_VDIM : vdim;
507 constexpr int max_ND = T_ND ? T_ND : QI::MAX_ND3D;
508 constexpr int max_VDIM = T_VDIM ? T_VDIM : QI::MAX_VDIM3D;
509 MFEM_SHARED
real_t s_E[max_VDIM*max_ND];
510 MFEM_FOREACH_THREAD(d, x, ND)
512 for (
int c = 0; c < VDIM; c++)
514 s_E[c + d * VDIM] = E(d, c, e);
519 MFEM_FOREACH_THREAD(q, x, NQ)
521 if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
524 for (
int c = 0; c < VDIM; c++)
528 for (
int d = 0; d < ND; ++d)
531 for (
int c = 0; c < VDIM; c++)
533 ed[c] +=
b * s_E[c + d * VDIM];
536 for (
int c = 0; c < VDIM; c++)
538 if constexpr (Integral)
544 val(c, q, e) = ed[c];
548 val(q, c, e) = ed[c];
552 if ((eval_flags & QI::DERIVATIVES) ||
553 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
554 (eval_flags & QI::DETERMINANTS))
557 real_t D[QI::MAX_VDIM3D*3];
558 for (
int i = 0; i < 3*VDIM; i++)
562 for (
int d = 0; d < ND; ++d)
564 const real_t wx = G(q,0,d);
565 const real_t wy = G(q,1,d);
566 const real_t wz = G(q,2,d);
567 for (
int c = 0; c < VDIM; c++)
569 real_t s_e = s_E[c+d*VDIM];
570 D[c+VDIM*0] += s_e * wx;
571 D[c+VDIM*1] += s_e * wy;
572 D[c+VDIM*2] += s_e * wz;
575 if (eval_flags & QI::DERIVATIVES)
577 for (
int c = 0; c < VDIM; c++)
581 der(c,0,q,e) = D[c+VDIM*0];
582 der(c,1,q,e) = D[c+VDIM*1];
583 der(c,2,q,e) = D[c+VDIM*2];
587 der(q,c,0,e) = D[c+VDIM*0];
588 der(q,c,1,e) = D[c+VDIM*1];
589 der(q,c,2,e) = D[c+VDIM*2];
593 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
596 for (
int col = 0; col < 3; col++)
598 for (
int row = 0; row < 3; row++)
600 Jloc[row+3*col] = J(q,row,col,e);
604 for (
int c = 0; c < VDIM; c++)
607 const real_t v = D[c+VDIM*1];
608 const real_t w = D[c+VDIM*2];
609 const real_t JiU = Jinv[0]*
u + Jinv[1]*v + Jinv[2]*w;
610 const real_t JiV = Jinv[3]*
u + Jinv[4]*v + Jinv[5]*w;
611 const real_t JiW = Jinv[6]*
u + Jinv[7]*v + Jinv[8]*w;
626 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
641template <const
int T_VDIM, const
int T_ND, const
int T_NQ>
642void Eval3D(
const int NE,
const int vdim,
const QVectorLayout q_layout,
643 const GeometricFactors *geom,
const DofToQuad &maps,
644 const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det,
645 const int eval_flags)
647 ImplEval3D<false, T_VDIM, T_ND, T_NQ>(NE, vdim, q_layout,
nullptr, geom,
648 maps, e_vec, q_val, q_der, q_det,
658template <
int DIM, QVectorLayout Q_LAYOUT,
int VDIM,
int D1D,
int Q1D,
int NBZ>
660QuadratureInterpolator::IntTensorEvalKernels::Kernel()
662 if constexpr (
DIM == 1) {
return internal::quadrature_interpolator::ImplValues1D<Q_LAYOUT, true>; }
663 else if constexpr (
DIM == 2) {
return internal::quadrature_interpolator::ImplValues2D<Q_LAYOUT, true, VDIM, D1D, Q1D, NBZ>; }
664 else if constexpr (
DIM == 3) {
return internal::quadrature_interpolator::ImplValues3D<Q_LAYOUT, true, VDIM, D1D, Q1D>; }
668template <
int DIM, QVectorLayout Q_LAYOUT,
int VDIM,
int D1D,
int Q1D,
int NBZ>
670QuadratureInterpolator::TensorEvalKernels::Kernel()
672 if constexpr (
DIM == 1) {
return internal::quadrature_interpolator::Values1D<Q_LAYOUT>; }
673 else if constexpr (
DIM == 2) {
return internal::quadrature_interpolator::Values2D<Q_LAYOUT, VDIM, D1D, Q1D, NBZ>; }
674 else if constexpr (
DIM == 3) {
return internal::quadrature_interpolator::Values3D<Q_LAYOUT, VDIM, D1D, Q1D>; }
678template <
int DIM,
int VDIM,
int ND,
int NQ>
680QuadratureInterpolator::IntEvalKernels::Kernel()
682 using namespace internal::quadrature_interpolator;
683 if constexpr (
DIM == 1) {
return ImplEval1D<true>; }
684 else if constexpr (
DIM == 2) {
return ImplEval2D<true,VDIM,ND,NQ>; }
685 else if constexpr (
DIM == 3) {
return ImplEval3D<true,VDIM,ND,NQ>; }
689template <
int DIM,
int VDIM,
int ND,
int NQ>
691QuadratureInterpolator::EvalKernels::Kernel()
693 using namespace internal::quadrature_interpolator;
694 if constexpr (
DIM == 1) {
return Eval1D; }
695 else if constexpr (
DIM == 2) {
return Eval2D<VDIM,ND,NQ>; }
696 else if constexpr (
DIM == 3) {
return Eval3D<VDIM,ND,NQ>; }
@ FULL
Full multidimensional representation which does not use tensor product structure. The ordering of the...
void(*)(const int ne, const real_t *B, const real_t *e_vec, real_t *q_val, const int vdim, const int nd, const int nq) TensorEvalKernelType
void(*)(const int NE, const int vdim, const QVectorLayout q_layout, const GeometricFactors *geom, const DofToQuad &maps, const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det, const int eval_flags) EvalKernelType
void(*)(const int NE, const int vdim, const QVectorLayout q_layout, const real_t *detJ, const GeometricFactors *geom, const DofToQuad &maps, const Vector &e_vec, Vector &q_val, Vector &q_der, Vector &q_det, const int eval_flags) IntEvalKernelType
void(*)(const int ne, const real_t *B, const real_t *detJ, const real_t *e_vec, real_t *q_val, const int vdim, const int nd, const int nq) IntTensorEvalKernelType
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
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.
DeviceTensor< 3, real_t > DeviceCube
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_batch(int N, int X, int Y, int BZ, lambda &&body)
void forall_2D(int N, int X, int Y, lambda &&body)
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
QVectorLayout
Type describing possible layouts for Q-vectors.
DeviceTensor< 2, const real_t > ConstDeviceMatrix
void forall(int N, lambda &&body)
DeviceTensor< 2, real_t > DeviceMatrix