MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
eval.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12// Internal header, included only by .cpp files.
13// Template function implementations.
14
15#ifndef MFEM_QUADINTERP_EVAL
16#define MFEM_QUADINTERP_EVAL
17
22#include "../kernels.hpp"
23
24namespace mfem
25{
26
27namespace internal
28{
29
30namespace quadrature_interpolator
31{
32
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,
36 const int q1d)
37{
38 mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
39 {
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);
43 auto y = Q_LAYOUT == QVectorLayout::byNODES ? Reshape(y_, q1d, vdim, NE)
44 : Reshape(y_, vdim, q1d, NE);
45 for (int c = 0; c < vdim; c++)
46 {
47 for (int q = 0; q < q1d; q++)
48 {
49 real_t u = 0.0;
50 for (int d = 0; d < d1d; d++)
51 {
52 u += b(q, d) * x(d, c, e);
53 }
54 if constexpr (Integral)
55 {
56 u /= detJ(q, e);
57 }
58 if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
59 {
60 y(c, q, e) = u;
61 }
62 if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
63 {
64 y(q, c, e) = u;
65 }
66 }
67 }
68 });
69}
70
71template <QVectorLayout Q_LAYOUT>
72void Values1D(const int NE, const real_t *b_, const real_t *x_, real_t *y_,
73 const int vdim, const int d1d, const int q1d)
74{
75 ImplValues1D<Q_LAYOUT, false>(NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
76}
77
78// Template compute kernel for Values in 2D: tensor product version.
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_,
82 const real_t *x_, real_t *y_, const int vdim = 0,
83 const int d1d = 0, const int q1d = 0)
84{
85 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
86
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;
90
91 const auto b = Reshape(b_, Q1D, D1D);
92
93 mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE(int e)
94 {
95 const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
96 const auto detJ = Reshape(detJ_, Q1D, Q1D, NE);
97 auto y = Q_LAYOUT == QVectorLayout::byNODES
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);
107
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];
111
112 kernels::internal::LoadB<MD1,MQ1>(D1D,Q1D,b,sB);
113
114 ConstDeviceMatrix B(sB, D1D,Q1D);
115 DeviceMatrix DD(sm0[tidz], MD1, MD1);
116 DeviceMatrix DQ(sm1[tidz], MD1, MQ1);
117 DeviceMatrix QQ(sm0[tidz], MQ1, MQ1);
118
119 for (int c = 0; c < VDIM; c++)
120 {
121 MFEM_FOREACH_THREAD(dy,y,D1D)
122 {
123 MFEM_FOREACH_THREAD(dx, x, D1D)
124 {
125 DD(dx, dy) = x(dx, dy, c, e);
126 }
127 }
128 MFEM_SYNC_THREAD;
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)
132 {
133 MFEM_FOREACH_THREAD(qx,x,Q1D)
134 {
135 real_t u = QQ(qx, qy);
136 if constexpr (Integral)
137 {
138 u /= detJ(qx, qy, e);
139 }
140 if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
141 {
142 y(c, qx, qy, e) = u;
143 }
144 if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
145 {
146 y(qx, qy, c, e) = u;
147 }
148 }
149 }
150 MFEM_SYNC_THREAD;
151 }
152 });
153}
154
155// Template compute kernel for Values in 2D: tensor product version.
156template <QVectorLayout Q_LAYOUT, int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0,
157 int T_NBZ = 1>
158void Values2D(const int NE, const real_t *b_, const real_t *x_, real_t *y_,
159 const int vdim = 0, const int d1d = 0, const int q1d = 0)
160{
161 return ImplValues2D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D, T_NBZ>(
162 NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
163}
164
165// Template compute kernel for Values in 3D: tensor product version.
166template <QVectorLayout Q_LAYOUT, bool Integral, int T_VDIM = 0, int T_D1D = 0,
167 int T_Q1D = 0>
168void ImplValues3D(const int NE, const real_t *b_, const real_t *detJ_,
169 const real_t *x_, real_t *y_, const int vdim = 0,
170 const int d1d = 0, const int q1d = 0)
171{
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;
175
176 const auto b = Reshape(b_, Q1D, D1D);
177
178 mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE(int e)
179 {
180 const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
181 const auto detJ = Reshape(detJ_, Q1D, Q1D, Q1D, NE);
182 auto y = Q_LAYOUT == QVectorLayout::byNODES
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;
191
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];
195
196 kernels::internal::LoadB<MD1,MQ1>(D1D,Q1D,b,sB);
197
198 ConstDeviceMatrix B(sB, D1D,Q1D);
199 DeviceCube DDD(sm0, MD1,MD1,MD1);
200 DeviceCube DDQ(sm1, MD1,MD1,MQ1);
201 DeviceCube DQQ(sm0, MD1,MQ1,MQ1);
202 DeviceCube QQQ(sm1, MQ1,MQ1,MQ1);
203
204 for (int c = 0; c < VDIM; c++)
205 {
206 MFEM_FOREACH_THREAD(dz, z, D1D)
207 {
208 MFEM_FOREACH_THREAD(dy, y, D1D)
209 {
210 MFEM_FOREACH_THREAD(dx, x, D1D)
211 {
212 DDD(dx, dy, dz) = x(dx, dy, dz, c, e);
213 }
214 }
215 }
216 MFEM_SYNC_THREAD;
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)
221 {
222 MFEM_FOREACH_THREAD(qy,y,Q1D)
223 {
224 MFEM_FOREACH_THREAD(qx,x,Q1D)
225 {
226 real_t u = QQQ(qz,qy,qx);
227 if constexpr (Integral)
228 {
229 u /= detJ(qx, qy, qz, e);
230 }
231 if constexpr (Q_LAYOUT == QVectorLayout::byVDIM)
232 {
233 y(c, qx, qy, qz, e) = u;
234 }
235 if constexpr (Q_LAYOUT == QVectorLayout::byNODES)
236 {
237 y(qx, qy, qz, c, e) = u;
238 }
239 }
240 }
241 }
242 MFEM_SYNC_THREAD;
243 }
244 });
245}
246
247// Template compute kernel for Values in 3D: tensor product version.
248template <QVectorLayout Q_LAYOUT, int T_VDIM = 0, int T_D1D = 0, int T_Q1D = 0>
249void Values3D(const int NE, const real_t *b_, const real_t *x_, real_t *y_,
250 const int vdim = 0, const int d1d = 0, const int q1d = 0)
251{
252 return ImplValues3D<Q_LAYOUT, false, T_VDIM, T_D1D, T_Q1D>(
253 NE, b_, nullptr, x_, y_, vdim, d1d, q1d);
254}
255
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);
261
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)
266{
267 ImplEval1D<false>(NE, vdim, q_layout, nullptr, geom, maps, e_vec, q_val,
268 q_der, q_det, eval_flags);
269}
270
271// Template compute kernel for 2D quadrature interpolation:
272// * non-tensor product version,
273// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
274// * assumes 'maps.mode == FULL'.
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)
280{
281 using QI = QuadratureInterpolator;
282
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;
289 MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
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)
294 {
295 MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
296 QI::DETERMINANTS)),
297 "Integral FE does not support computing derivatives");
298 }
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();
303 auto val = q_layout == QVectorLayout::byNODES ?
304 Reshape(q_val.Write(), NQ, VDIM, NE):
305 Reshape(q_val.Write(), VDIM, NQ, NE);
306 auto der = q_layout == QVectorLayout::byNODES ?
307 Reshape(q_der.Write(), NQ, VDIM, 2, NE):
308 Reshape(q_der.Write(), VDIM, 2, NQ, NE);
309 auto det = Reshape(q_det.Write(), NQ, NE);
310 mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE(int e)
311 {
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)
321 {
322 for (int c = 0; c < VDIM; c++)
323 {
324 s_E[c + d * VDIM] = E(d, c, e);
325 }
326 }
327 MFEM_SYNC_THREAD;
328
329 MFEM_FOREACH_THREAD(q, x, NQ)
330 {
331 if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
332 {
333 real_t ed[max_VDIM];
334 for (int c = 0; c < VDIM; c++)
335 {
336 ed[c] = 0.0;
337 }
338 for (int d = 0; d < ND; ++d)
339 {
340 const real_t b = B(q,d);
341 for (int c = 0; c < VDIM; c++)
342 {
343 ed[c] += b * s_E[c + d * VDIM];
344 }
345 }
346 for (int c = 0; c < VDIM; c++)
347 {
348 if constexpr (Integral)
349 {
350 ed[c] /= detJ(q, e);
351 }
352 if (q_layout == QVectorLayout::byVDIM)
353 {
354 val(c, q, e) = ed[c];
355 }
356 if (q_layout == QVectorLayout::byNODES)
357 {
358 val(q, c, e) = ed[c];
359 }
360 }
361 }
362 if ((eval_flags & QI::DERIVATIVES) ||
363 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
364 (eval_flags & QI::DETERMINANTS))
365 {
366 // use MAX_VDIM2D to avoid "subscript out of range" warnings
367 real_t D[QI::MAX_VDIM2D*2];
368 for (int i = 0; i < 2*VDIM; i++)
369 {
370 D[i] = 0.0;
371 }
372 for (int d = 0; d < ND; ++d)
373 {
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++)
377 {
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;
381 }
382 }
383 if (eval_flags & QI::DERIVATIVES)
384 {
385 for (int c = 0; c < VDIM; c++)
386 {
387 if (q_layout == QVectorLayout::byVDIM)
388 {
389 der(c,0,q,e) = D[c+VDIM*0];
390 der(c,1,q,e) = D[c+VDIM*1];
391 }
392 if (q_layout == QVectorLayout::byNODES)
393 {
394 der(q,c,0,e) = D[c+VDIM*0];
395 der(q,c,1,e) = D[c+VDIM*1];
396 }
397 }
398 }
399 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
400 {
401 real_t Jloc[4], Jinv[4];
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);
406 kernels::CalcInverse<2>(Jloc, Jinv);
407 for (int c = 0; c < VDIM; c++)
408 {
409 const real_t u = D[c+VDIM*0];
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;
413 if (q_layout == QVectorLayout::byVDIM)
414 {
415 der(c,0,q,e) = JiU;
416 der(c,1,q,e) = JiV;
417 }
418 if (q_layout == QVectorLayout::byNODES)
419 {
420 der(q,c,0,e) = JiU;
421 der(q,c,1,e) = JiV;
422 }
423 }
424 }
425 if (eval_flags & QI::DETERMINANTS)
426 {
427 if (VDIM == 2)
428 {
429 det(q, e) = kernels::Det<2>(D);
430 }
431 else
432 {
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);
438 }
439 }
440 }
441 }
442 });
443}
444
445// Template compute kernel for 2D quadrature interpolation:
446// * non-tensor product version,
447// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
448// * assumes 'maps.mode == FULL'.
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)
454{
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,
457 eval_flags);
458}
459
460// Template compute kernel for 3D quadrature interpolation:
461// * non-tensor product version,
462// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
463// * assumes 'maps.mode == FULL'.
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)
469{
470 using QI = QuadratureInterpolator;
471
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;
478 MFEM_ASSERT(maps.mode == DofToQuad::FULL, "internal error");
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)
484 {
485 MFEM_VERIFY(!(eval_flags & (QI::DERIVATIVES | QI::PHYSICAL_DERIVATIVES |
486 QI::DETERMINANTS)),
487 "Integral FE does not support computing derivatives");
488 }
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();
493 auto val = q_layout == QVectorLayout::byNODES ?
494 Reshape(q_val.Write(), NQ, VDIM, NE):
495 Reshape(q_val.Write(), VDIM, NQ, NE);
496 auto der = q_layout == QVectorLayout::byNODES ?
497 Reshape(q_der.Write(), NQ, VDIM, 3, NE):
498 Reshape(q_der.Write(), VDIM, 3, NQ, NE);
499 auto det = Reshape(q_det.Write(), NQ, NE);
500 mfem::forall_2D(NE, NMAX, 1, [=] MFEM_HOST_DEVICE(int e)
501 {
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)
511 {
512 for (int c = 0; c < VDIM; c++)
513 {
514 s_E[c + d * VDIM] = E(d, c, e);
515 }
516 }
517 MFEM_SYNC_THREAD;
518
519 MFEM_FOREACH_THREAD(q, x, NQ)
520 {
521 if (eval_flags & (QI::VALUES | QI::PHYSICAL_VALUES))
522 {
523 real_t ed[max_VDIM];
524 for (int c = 0; c < VDIM; c++)
525 {
526 ed[c] = 0.0;
527 }
528 for (int d = 0; d < ND; ++d)
529 {
530 const real_t b = B(q,d);
531 for (int c = 0; c < VDIM; c++)
532 {
533 ed[c] += b * s_E[c + d * VDIM];
534 }
535 }
536 for (int c = 0; c < VDIM; c++)
537 {
538 if constexpr (Integral)
539 {
540 ed[c] /= detJ(q, e);
541 }
542 if (q_layout == QVectorLayout::byVDIM)
543 {
544 val(c, q, e) = ed[c];
545 }
546 if (q_layout == QVectorLayout::byNODES)
547 {
548 val(q, c, e) = ed[c];
549 }
550 }
551 }
552 if ((eval_flags & QI::DERIVATIVES) ||
553 (eval_flags & QI::PHYSICAL_DERIVATIVES) ||
554 (eval_flags & QI::DETERMINANTS))
555 {
556 // use MAX_VDIM3D to avoid "subscript out of range" warnings
557 real_t D[QI::MAX_VDIM3D*3];
558 for (int i = 0; i < 3*VDIM; i++)
559 {
560 D[i] = 0.0;
561 }
562 for (int d = 0; d < ND; ++d)
563 {
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++)
568 {
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;
573 }
574 }
575 if (eval_flags & QI::DERIVATIVES)
576 {
577 for (int c = 0; c < VDIM; c++)
578 {
579 if (q_layout == QVectorLayout::byVDIM)
580 {
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];
584 }
585 if (q_layout == QVectorLayout::byNODES)
586 {
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];
590 }
591 }
592 }
593 if (eval_flags & QI::PHYSICAL_DERIVATIVES)
594 {
595 real_t Jloc[9], Jinv[9];
596 for (int col = 0; col < 3; col++)
597 {
598 for (int row = 0; row < 3; row++)
599 {
600 Jloc[row+3*col] = J(q,row,col,e);
601 }
602 }
603 kernels::CalcInverse<3>(Jloc, Jinv);
604 for (int c = 0; c < VDIM; c++)
605 {
606 const real_t u = D[c+VDIM*0];
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;
612 if (q_layout == QVectorLayout::byVDIM)
613 {
614 der(c,0,q,e) = JiU;
615 der(c,1,q,e) = JiV;
616 der(c,2,q,e) = JiW;
617 }
618 if (q_layout == QVectorLayout::byNODES)
619 {
620 der(q,c,0,e) = JiU;
621 der(q,c,1,e) = JiV;
622 der(q,c,2,e) = JiW;
623 }
624 }
625 }
626 if (VDIM == 3 && (eval_flags & QI::DETERMINANTS))
627 {
628 // The check (VDIM == 3) should eliminate this block when VDIM is
629 // known at compile time and (VDIM != 3).
630 det(q,e) = kernels::Det<3>(D);
631 }
632 }
633 }
634 });
635}
636
637// Template compute kernel for 3D quadrature interpolation:
638// * non-tensor product version,
639// * assumes 'e_vec' is using ElementDofOrdering::NATIVE,
640// * assumes 'maps.mode == FULL'.
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)
646{
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,
649 eval_flags);
650}
651
652} // namespace quadrature_interpolator
653
654} // namespace internal
655
656/// @cond Suppress_Doxygen_warnings
657
658template <int DIM, QVectorLayout Q_LAYOUT, int VDIM, int D1D, int Q1D, int NBZ>
660QuadratureInterpolator::IntTensorEvalKernels::Kernel()
661{
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>; }
665 MFEM_ABORT("");
666}
667
668template <int DIM, QVectorLayout Q_LAYOUT, int VDIM, int D1D, int Q1D, int NBZ>
670QuadratureInterpolator::TensorEvalKernels::Kernel()
671{
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>; }
675 MFEM_ABORT("");
676}
677
678template <int DIM, int VDIM, int ND, int NQ>
680QuadratureInterpolator::IntEvalKernels::Kernel()
681{
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>; }
686 MFEM_ABORT("");
687}
688
689template <int DIM, int VDIM, int ND, int NQ>
691QuadratureInterpolator::EvalKernels::Kernel()
692{
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>; }
697 MFEM_ABORT("");
698}
699
700/// @endcond
701
702} // namespace mfem
703
704#endif
@ FULL
Full multidimensional representation which does not use tensor product structure. The ordering of the...
Definition fe_base.hpp:158
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
real_t b
Definition lissajous.cpp:42
constexpr int DIM
mfem::real_t real_t
MFEM_HOST_DEVICE T det(const tensor< T, 1, 1 > &A)
Returns the determinant of a matrix.
Definition tensor.hpp:1406
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.
Definition kernels.hpp:306
MFEM_HOST_DEVICE T Det(const T *data)
Compute the determinant of a square matrix of size dim with given data.
Definition kernels.hpp:297
DeviceTensor< 3, real_t > DeviceCube
Definition dtensor.hpp:153
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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,...
Definition device.hpp:386
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
void forall_2D_batch(int N, int X, int Y, int BZ, lambda &&body)
Definition forall.hpp:1232
void forall_2D(int N, int X, int Y, lambda &&body)
Definition forall.hpp:1220
void forall_3D(int N, int X, int Y, int Z, lambda &&body)
Definition forall.hpp:1244
QVectorLayout
Type describing possible layouts for Q-vectors.
Definition fespace.hpp:33
DeviceTensor< 2, const real_t > ConstDeviceMatrix
Definition dtensor.hpp:151
void forall(int N, lambda &&body)
Definition forall.hpp:1134
DeviceTensor< 2, real_t > DeviceMatrix
Definition dtensor.hpp:150