MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
grad.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_GRAD
16#define MFEM_QUADINTERP_GRAD
17
21#include "../../fem/kernels.hpp"
23
24namespace mfem
25{
26
27namespace internal
28{
29
30namespace quadrature_interpolator
31{
32
33template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
34void Derivatives1D(const int NE, const real_t *b_, const real_t *g_,
35 const real_t *j_, const real_t *x_, real_t *y_,
36 const int sdim, const int vdim, const int d1d, const int q1d)
37{
38 MFEM_CONTRACT_VAR(b_);
39 const int SDIM = GRAD_PHYS ? sdim : 1;
40 const auto g = Reshape(g_, q1d, d1d);
41 const auto j = Reshape(j_, q1d, SDIM, NE);
42 const auto x = Reshape(x_, d1d, vdim, NE);
43 auto y = Q_LAYOUT == QVectorLayout::byNODES ?
44 Reshape(y_, q1d, vdim, SDIM, NE):
45 Reshape(y_, vdim, SDIM, q1d, NE);
46
47 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
48 {
49 for (int c = 0; c < vdim; c++)
50 {
51 for (int q = 0; q < q1d; q++)
52 {
53 real_t du[3] = {0.0, 0.0, 0.0};
54 for (int d = 0; d < d1d; d++)
55 {
56 du[0] += g(q, d) * x(d, c, e);
57 }
58 if (GRAD_PHYS)
59 {
60 if (SDIM == 1) { du[0] /= j(q, 0, e); }
61 else if (SDIM == 2)
62 {
63 const real_t Jloc[2] = {j(q,0,e), j(q,1,e)};
64 real_t Jinv[3];
66 const real_t U = Jinv[0]*du[0];
67 const real_t V = Jinv[1]*du[0];
68 du[0] = U;
69 du[1] = V;
70 }
71 else // SDIM == 3
72 {
73 const real_t Jloc[3] = {j(q,0,e), j(q,1,e), j(q,2,e)};
74 real_t Jinv[3];
76 const real_t U = Jinv[0]*du[0];
77 const real_t V = Jinv[1]*du[0];
78 const real_t W = Jinv[2]*du[0];
79 du[0] = U;
80 du[1] = V;
81 du[2] = W;
82 }
83 }
84 for (int d = 0; d < SDIM; ++d)
85 {
86 if (Q_LAYOUT == QVectorLayout::byVDIM) { y(c, d, q, e) = du[d]; }
87 if (Q_LAYOUT == QVectorLayout::byNODES) { y(q, c, d, e) = du[d]; }
88 }
89 }
90 }
91 });
92}
93
94// Template compute kernel for derivatives in 2D: tensor product version.
95template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int T_VDIM = 0, int T_D1D = 0,
96 int T_Q1D = 0, int T_NBZ = 1>
97void Derivatives2D(const int NE, const real_t *b_, const real_t *g_,
98 const real_t *j_, const real_t *x_, real_t *y_,
99 const int sdim = 2, const int vdim = 0, const int d1d = 0,
100 const int q1d = 0)
101{
102 const int D1D = T_D1D ? T_D1D : d1d;
103 const int Q1D = T_Q1D ? T_Q1D : q1d;
104 const int VDIM = T_VDIM ? T_VDIM : vdim;
105 const int SDIM = GRAD_PHYS ? sdim : 2;
106 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
107
108 const auto b = Reshape(b_, Q1D, D1D);
109 const auto g = Reshape(g_, Q1D, D1D);
110 const auto j = Reshape(j_, Q1D, Q1D, SDIM, 2, NE);
111 const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
112 auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
113 Reshape(y_, Q1D, Q1D, VDIM, SDIM, NE):
114 Reshape(y_, VDIM, SDIM, Q1D, Q1D, NE);
115
116 mfem::forall_2D_batch(NE, Q1D, Q1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
117 {
118 const int D1D = T_D1D ? T_D1D : d1d;
119 const int Q1D = T_Q1D ? T_Q1D : q1d;
120 const int VDIM = T_VDIM ? T_VDIM : vdim;
121 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
122 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
123
124 const int tidz = MFEM_THREAD_ID(z);
125 MFEM_SHARED real_t BG[2][MQ1*MD1];
126 kernels::internal::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
127 DeviceMatrix B(BG[0], D1D, Q1D);
128 DeviceMatrix G(BG[1], D1D, Q1D);
129
130 MFEM_SHARED real_t XY[NBZ][MD1*MD1];
131 DeviceTensor<2> X((real_t*)(XY+tidz), D1D, D1D);
132
133 MFEM_SHARED real_t s_DQ[2][NBZ][MD1*MQ1];
134 DeviceTensor<2> DQ0(s_DQ[0][tidz], D1D, Q1D);
135 DeviceTensor<2> DQ1(s_DQ[1][tidz], D1D, Q1D);
136
137 for (int c = 0; c < VDIM; ++c)
138 {
139 kernels::internal::LoadX<MD1,NBZ>(e,D1D,c,x,XY);
140 MFEM_FOREACH_THREAD(dy,y,D1D)
141 {
142 MFEM_FOREACH_THREAD(qx,x,Q1D)
143 {
144 real_t u = 0.0;
145 real_t v = 0.0;
146 for (int dx = 0; dx < D1D; ++dx)
147 {
148 const real_t input = X(dx,dy);
149 u += input * B(dx,qx);
150 v += input * G(dx,qx);
151 }
152 DQ0(dy,qx) = u;
153 DQ1(dy,qx) = v;
154 }
155 }
156 MFEM_SYNC_THREAD;
157 MFEM_FOREACH_THREAD(qy,y,Q1D)
158 {
159 MFEM_FOREACH_THREAD(qx,x,Q1D)
160 {
161 real_t du[3] = {0.0, 0.0, 0.0};
162 for (int dy = 0; dy < D1D; ++dy)
163 {
164 du[0] += DQ1(dy,qx) * B(dy,qy);
165 du[1] += DQ0(dy,qx) * G(dy,qy);
166 }
167 if (GRAD_PHYS)
168 {
169 if (SDIM == 2)
170 {
171 real_t Jloc[4], Jinv[4];
172 Jloc[0] = j(qx,qy,0,0,e);
173 Jloc[1] = j(qx,qy,1,0,e);
174 Jloc[2] = j(qx,qy,0,1,e);
175 Jloc[3] = j(qx,qy,1,1,e);
176 kernels::CalcInverse<2>(Jloc, Jinv);
177 const real_t U = Jinv[0]*du[0] + Jinv[1]*du[1];
178 const real_t V = Jinv[2]*du[0] + Jinv[3]*du[1];
179 du[0] = U;
180 du[1] = V;
181 }
182 else
183 {
184 real_t Jloc[6], Jinv[6];
185 Jloc[0] = j(qx,qy,0,0,e);
186 Jloc[1] = j(qx,qy,1,0,e);
187 Jloc[2] = j(qx,qy,2,0,e);
188 Jloc[3] = j(qx,qy,0,1,e);
189 Jloc[4] = j(qx,qy,1,1,e);
190 Jloc[5] = j(qx,qy,2,1,e);
192 const real_t U = Jinv[0]*du[0] + Jinv[1]*du[1];
193 const real_t V = Jinv[2]*du[0] + Jinv[3]*du[1];
194 const real_t W = Jinv[4]*du[0] + Jinv[5]*du[1];
195 du[0] = U;
196 du[1] = V;
197 du[2] = W;
198 }
199 }
200 for (int d = 0; d < SDIM; ++d)
201 {
202 if (Q_LAYOUT == QVectorLayout::byVDIM)
203 {
204 y(c,d,qx,qy,e) = du[d];
205 }
206 else // Q_LAYOUT == QVectorLayout::byNODES
207 {
208 y(qx,qy,c,d,e) = du[d];
209 }
210 }
211 }
212 }
213 MFEM_SYNC_THREAD;
214 }
215 });
216}
217
218// Template compute kernel for derivatives in 3D: tensor product version.
219template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int T_VDIM = 0, int T_D1D = 0,
220 int T_Q1D = 0>
221void Derivatives3D(const int NE, const real_t *b_, const real_t *g_,
222 const real_t *j_, const real_t *x_, real_t *y_,
223 const int sdim = 3, const int vdim = 0, const int d1d = 0,
224 const int q1d = 0)
225{
226 const int D1D = T_D1D ? T_D1D : d1d;
227 const int Q1D = T_Q1D ? T_Q1D : q1d;
228 const int VDIM = T_VDIM ? T_VDIM : vdim;
229
230 const auto b = Reshape(b_, Q1D, D1D);
231 const auto g = Reshape(g_, Q1D, D1D);
232 const auto j = Reshape(j_, Q1D, Q1D, Q1D, 3, 3, NE);
233 const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
234 auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
235 Reshape(y_, Q1D, Q1D, Q1D, VDIM, 3, NE):
236 Reshape(y_, VDIM, 3, Q1D, Q1D, Q1D, NE);
237
238 mfem::forall_3D(NE, Q1D, Q1D, Q1D, [=] MFEM_HOST_DEVICE (int e)
239 {
240 const int D1D = T_D1D ? T_D1D : d1d;
241 const int Q1D = T_Q1D ? T_Q1D : q1d;
242 const int VDIM = T_VDIM ? T_VDIM : vdim;
243 constexpr int MQ1 = T_Q1D ? T_Q1D : DofQuadLimits::MAX_INTERP_1D;
244 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_INTERP_1D;
245
246 MFEM_SHARED real_t BG[2][MQ1*MD1];
247 kernels::internal::LoadBG<MD1,MQ1>(D1D,Q1D,b,g,BG);
248 DeviceMatrix B(BG[0], D1D, Q1D);
249 DeviceMatrix G(BG[1], D1D, Q1D);
250
251 constexpr int MDQ = MD1 > MQ1 ? MD1 : MQ1;
252 MFEM_SHARED real_t sm0[3][MD1*MD1*MDQ];
253 MFEM_SHARED real_t sm1[3][MD1*MQ1*MQ1];
254 DeviceTensor<3> X(sm0[2], D1D, D1D, D1D);
255 DeviceTensor<3> DDQ0(sm0[0], D1D, D1D, Q1D);
256 DeviceTensor<3> DDQ1(sm0[1], D1D, D1D, Q1D);
257 DeviceTensor<3> DQQ0(sm1[0], D1D, Q1D, Q1D);
258 DeviceTensor<3> DQQ1(sm1[1], D1D, Q1D, Q1D);
259 DeviceTensor<3> DQQ2(sm1[2], D1D, Q1D, Q1D);
260
261 for (int c = 0; c < VDIM; ++c)
262 {
263 kernels::internal::LoadX(e,D1D,c,x,X);
264 MFEM_FOREACH_THREAD(dz,z,D1D)
265 {
266 MFEM_FOREACH_THREAD(dy,y,D1D)
267 {
268 MFEM_FOREACH_THREAD(qx,x,Q1D)
269 {
270 real_t u = 0.0;
271 real_t v = 0.0;
272 for (int dx = 0; dx < D1D; ++dx)
273 {
274 const real_t input = X(dx,dy,dz);
275 u += input * B(dx,qx);
276 v += input * G(dx,qx);
277 }
278 DDQ0(dz,dy,qx) = u;
279 DDQ1(dz,dy,qx) = v;
280 }
281 }
282 }
283 MFEM_SYNC_THREAD;
284 MFEM_FOREACH_THREAD(dz,z,D1D)
285 {
286 MFEM_FOREACH_THREAD(qy,y,Q1D)
287 {
288 MFEM_FOREACH_THREAD(qx,x,Q1D)
289 {
290 real_t u = 0.0;
291 real_t v = 0.0;
292 real_t w = 0.0;
293 for (int dy = 0; dy < D1D; ++dy)
294 {
295 u += DDQ1(dz,dy,qx) * B(dy,qy);
296 v += DDQ0(dz,dy,qx) * G(dy,qy);
297 w += DDQ0(dz,dy,qx) * B(dy,qy);
298 }
299 DQQ0(dz,qy,qx) = u;
300 DQQ1(dz,qy,qx) = v;
301 DQQ2(dz,qy,qx) = w;
302 }
303 }
304 }
305 MFEM_SYNC_THREAD;
306 MFEM_FOREACH_THREAD(qz,z,Q1D)
307 {
308 MFEM_FOREACH_THREAD(qy,y,Q1D)
309 {
310 MFEM_FOREACH_THREAD(qx,x,Q1D)
311 {
312 real_t u = 0.0;
313 real_t v = 0.0;
314 real_t w = 0.0;
315 for (int dz = 0; dz < D1D; ++dz)
316 {
317 u += DQQ0(dz,qy,qx) * B(dz,qz);
318 v += DQQ1(dz,qy,qx) * B(dz,qz);
319 w += DQQ2(dz,qy,qx) * G(dz,qz);
320 }
321 if (GRAD_PHYS)
322 {
323 real_t Jloc[9], Jinv[9];
324 for (int col = 0; col < 3; col++)
325 {
326 for (int row = 0; row < 3; row++)
327 {
328 Jloc[row+3*col] = j(qx,qy,qz,row,col,e);
329 }
330 }
331 kernels::CalcInverse<3>(Jloc, Jinv);
332 const real_t U = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
333 const real_t V = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
334 const real_t W = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
335 u = U; v = V; w = W;
336 }
337 if (Q_LAYOUT == QVectorLayout::byVDIM)
338 {
339 y(c,0,qx,qy,qz,e) = u;
340 y(c,1,qx,qy,qz,e) = v;
341 y(c,2,qx,qy,qz,e) = w;
342 }
343 if (Q_LAYOUT == QVectorLayout::byNODES)
344 {
345 y(qx,qy,qz,c,0,e) = u;
346 y(qx,qy,qz,c,1,e) = v;
347 y(qx,qy,qz,c,2,e) = w;
348 }
349 }
350 }
351 }
352 MFEM_SYNC_THREAD;
353 }
354 });
355}
356
357template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS>
358void CollocatedDerivatives1D(const int NE, const real_t *g_, const real_t *j_,
359 const real_t *x_, real_t *y_, const int sdim,
360 const int vdim, const int d1d)
361{
362 Derivatives1D<Q_LAYOUT, GRAD_PHYS>(
363 NE, nullptr, g_, j_, x_, y_, sdim, vdim, d1d, d1d);
364}
365
366// Template compute kernel for derivatives in 2D: tensor product version.
367template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int T_VDIM = 0, int T_D1D = 0,
368 int T_NBZ = 1>
369void CollocatedDerivatives2D(const int NE, const real_t *g_, const real_t *j_,
370 const real_t *x_, real_t *y_, const int sdim = 2,
371 const int vdim = 0, const int d1d = 0)
372{
373 const int D1D = T_D1D ? T_D1D : d1d;
374 const int VDIM = T_VDIM ? T_VDIM : vdim;
375 const int SDIM = GRAD_PHYS ? sdim : 2;
376 static constexpr int NBZ = T_NBZ ? T_NBZ : 1;
377
378 const auto g = Reshape(g_, D1D, D1D);
379 const auto j = Reshape(j_, D1D, D1D, SDIM, 2, NE);
380 const auto x = Reshape(x_, D1D, D1D, VDIM, NE);
381 auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
382 Reshape(y_, D1D, D1D, VDIM, SDIM, NE):
383 Reshape(y_, VDIM, SDIM, D1D, D1D, NE);
384
385 mfem::forall_2D_batch(NE, D1D, D1D, NBZ, [=] MFEM_HOST_DEVICE (int e)
386 {
387 const int D1D = T_D1D ? T_D1D : d1d;
388 const int VDIM = T_VDIM ? T_VDIM : vdim;
389 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
390
391 const int tidz = MFEM_THREAD_ID(z);
392
393 MFEM_SHARED real_t XY[NBZ][MD1*MD1];
394 DeviceTensor<2> X((real_t*)(XY+tidz), D1D, D1D);
395
396 for (int c = 0; c < VDIM; ++c)
397 {
398 kernels::internal::LoadX<MD1,NBZ>(e,D1D,c,x,XY);
399 MFEM_FOREACH_THREAD(dy,y,D1D)
400 {
401 MFEM_FOREACH_THREAD(dx,x,D1D)
402 {
403 real_t u = 0.0;
404 real_t v = 0.0;
405 real_t w = 0.0;
406 for (int dxy = 0; dxy < D1D; ++dxy)
407 {
408 u += X(dxy, dy) * g(dx,dxy);
409 v += X(dx, dxy) * g(dy,dxy);
410 }
411
412 if (GRAD_PHYS)
413 {
414 if (SDIM == 2)
415 {
416 real_t Jloc[4], Jinv[4];
417 Jloc[0] = j(dx,dy,0,0,e);
418 Jloc[1] = j(dx,dy,1,0,e);
419 Jloc[2] = j(dx,dy,0,1,e);
420 Jloc[3] = j(dx,dy,1,1,e);
421 kernels::CalcInverse<2>(Jloc, Jinv);
422 const real_t U = Jinv[0]*u + Jinv[1]*v;
423 const real_t V = Jinv[2]*u + Jinv[3]*v;
424 u = U;
425 v = V;
426 }
427 else
428 {
429 real_t Jloc[6], Jinv[6];
430 Jloc[0] = j(dx,dy,0,0,e);
431 Jloc[1] = j(dx,dy,1,0,e);
432 Jloc[2] = j(dx,dy,2,0,e);
433 Jloc[3] = j(dx,dy,0,1,e);
434 Jloc[4] = j(dx,dy,1,1,e);
435 Jloc[5] = j(dx,dy,2,1,e);
437 const real_t U = Jinv[0]*u + Jinv[1]*v;
438 const real_t V = Jinv[2]*u + Jinv[3]*v;
439 const real_t W = Jinv[4]*u + Jinv[5]*v;
440 u = U;
441 v = V;
442 w = W;
443 }
444 }
445
446 if (Q_LAYOUT == QVectorLayout::byVDIM)
447 {
448 y(c,0,dx,dy,e) = u;
449 y(c,1,dx,dy,e) = v;
450 if (SDIM == 3) { y(c,2,dx,dy,e) = w; }
451 }
452 if (Q_LAYOUT == QVectorLayout::byNODES)
453 {
454 y(dx,dy,c,0,e) = u;
455 y(dx,dy,c,1,e) = v;
456 if (SDIM == 3) { y(dx,dy,c,2,e) = w; }
457 }
458 }
459 }
460 MFEM_SYNC_THREAD;
461 }
462 });
463}
464
465// Template compute kernel for derivatives in 3D: tensor product version.
466template <QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int T_VDIM = 0, int T_D1D = 0>
467void CollocatedDerivatives3D(const int NE, const real_t *g_, const real_t *j_,
468 const real_t *x_, real_t *y_, const int sdim = 3,
469 const int vdim = 0, const int d1d = 0)
470{
471 MFEM_VERIFY(sdim == 3, "");
472
473 const int D1D = T_D1D ? T_D1D : d1d;
474 const int VDIM = T_VDIM ? T_VDIM : vdim;
475
476 const auto g = Reshape(g_, D1D, D1D);
477 const auto j = Reshape(j_, D1D, D1D, D1D, 3, 3, NE);
478 const auto x = Reshape(x_, D1D, D1D, D1D, VDIM, NE);
479 auto y = Q_LAYOUT == QVectorLayout:: byNODES ?
480 Reshape(y_, D1D, D1D, D1D, VDIM, 3, NE):
481 Reshape(y_, VDIM, 3, D1D, D1D, D1D, NE);
482
483 mfem::forall_3D(NE, D1D, D1D, D1D, [=] MFEM_HOST_DEVICE (int e)
484 {
485 const int D1D = T_D1D ? T_D1D : d1d;
486 const int VDIM = T_VDIM ? T_VDIM : vdim;
487 constexpr int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_INTERP_1D;
488
489 MFEM_SHARED real_t uvw[MD1*MD1*MD1];
490 DeviceTensor<3> X(uvw, D1D, D1D, D1D);
491
492 for (int c = 0; c < VDIM; ++c)
493 {
494 kernels::internal::LoadX(e,D1D,c,x,X);
495 MFEM_FOREACH_THREAD(dz,z,D1D)
496 {
497 MFEM_FOREACH_THREAD(dy,y,D1D)
498 {
499 MFEM_FOREACH_THREAD(dx,x,D1D)
500 {
501 real_t u = 0.0;
502 real_t v = 0.0;
503 real_t w = 0.0;
504 for (int dxyz = 0; dxyz < D1D; ++dxyz)
505 {
506 u += X(dxyz, dy, dz) * g(dx,dxyz);
507 v += X(dx, dxyz, dz) * g(dy,dxyz);
508 w += X(dx, dy, dxyz) * g(dz,dxyz);
509 }
510
511 if (GRAD_PHYS)
512 {
513 real_t Jloc[9], Jinv[9];
514 for (int col = 0; col < 3; col++)
515 {
516 for (int row = 0; row < 3; row++)
517 {
518 Jloc[row+3*col] = j(dx,dy,dz,row,col,e);
519 }
520 }
521 kernels::CalcInverse<3>(Jloc, Jinv);
522 const real_t U = Jinv[0]*u + Jinv[1]*v + Jinv[2]*w;
523 const real_t V = Jinv[3]*u + Jinv[4]*v + Jinv[5]*w;
524 const real_t W = Jinv[6]*u + Jinv[7]*v + Jinv[8]*w;
525 u = U; v = V; w = W;
526 }
527 if (Q_LAYOUT == QVectorLayout::byVDIM)
528 {
529 y(c,0,dx,dy,dz,e) = u;
530 y(c,1,dx,dy,dz,e) = v;
531 y(c,2,dx,dy,dz,e) = w;
532 }
533 if (Q_LAYOUT == QVectorLayout::byNODES)
534 {
535 y(dx,dy,dz,c,0,e) = u;
536 y(dx,dy,dz,c,1,e) = v;
537 y(dx,dy,dz,c,2,e) = w;
538 }
539
540 }
541 }
542 }
543 MFEM_SYNC_THREAD;
544 }
545 });
546}
547
548} // namespace quadrature_interpolator
549
550} // namespace internal
551
552/// @cond Suppress_Doxygen_warnings
553
554template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
555 int Q1D, int NBZ>
557QuadratureInterpolator::GradKernels::Kernel()
558{
559 if constexpr (DIM == 1) { return internal::quadrature_interpolator::Derivatives1D<Q_LAYOUT, GRAD_PHYS>; }
560 else if constexpr (DIM == 2) { return internal::quadrature_interpolator::Derivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D, NBZ>; }
561 else if constexpr (DIM == 3) { return internal::quadrature_interpolator::Derivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, Q1D>; }
562 MFEM_ABORT("");
563}
564
565template<int DIM, QVectorLayout Q_LAYOUT, bool GRAD_PHYS, int VDIM, int D1D,
566 int NBZ>
568QuadratureInterpolator::CollocatedGradKernels::Kernel()
569{
570 if constexpr (DIM == 1) { return internal::quadrature_interpolator::CollocatedDerivatives1D<Q_LAYOUT, GRAD_PHYS>; }
571 else if constexpr (DIM == 2) { return internal::quadrature_interpolator::CollocatedDerivatives2D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D, NBZ>; }
572 else if constexpr (DIM == 3) { return internal::quadrature_interpolator::CollocatedDerivatives3D<Q_LAYOUT, GRAD_PHYS, VDIM, D1D>; }
573 MFEM_ABORT("");
574}
575
576/// @endcond
577
578} // namespace mfem
579
580#endif
void(*)(const int ne, const real_t *B, const real_t *G, const real_t *J, const real_t *e_vec, real_t *q_der, const int s_dim, const int v_dim, const int nd, const int nq) GradKernelType
void(*)(const int ne, const real_t *G, const real_t *J, const real_t *e_vec, real_t *q_der, const int sdim, const int vdim, const int d1d) CollocatedGradKernelType
real_t b
Definition lissajous.cpp:42
constexpr int SDIM
constexpr int DIM
mfem::real_t real_t
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 void CalcLeftInverse< 2, 1 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1200
MFEM_HOST_DEVICE void CalcLeftInverse< 3, 2 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1217
MFEM_HOST_DEVICE void CalcLeftInverse< 3, 1 >(const real_t *d, real_t *left_inv)
Definition kernels.hpp:1208
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
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_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
void forall(int N, lambda &&body)
Definition forall.hpp:1134
DeviceTensor< 2, real_t > DeviceMatrix
Definition dtensor.hpp:150