MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_dgdiffusion_kernels.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#ifndef MFEM_BILININTEG_DGDIFFUSION_KERNELS_HPP
13#define MFEM_BILININTEG_DGDIFFUSION_KERNELS_HPP
14
18#include "../gridfunc.hpp"
19#include "../qfunction.hpp"
20
21/// \cond DO_NOT_DOCUMENT
22namespace mfem
23{
24
25namespace internal
26{
27
28template <int T_D1D = 0, int T_Q1D = 0>
29void PADGDiffusionApply2D(const int NF, const Array<real_t> &b,
30 const Array<real_t> &bt, const Array<real_t> &g,
31 const Array<real_t> &gt, const real_t sigma,
32 const Vector &pa_data, const Vector &x_,
33 const Vector &dxdn_, Vector &y_, Vector &dydn_,
34 const int d1d = 0, const int q1d = 0)
35{
36 const int D1D = T_D1D ? T_D1D : d1d;
37 const int Q1D = T_Q1D ? T_Q1D : q1d;
38 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
39 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
40
41 auto B_ = Reshape(b.Read(), Q1D, D1D);
42 auto G_ = Reshape(g.Read(), Q1D, D1D);
43
44 auto pa =
45 Reshape(pa_data.Read(), 6, Q1D, NF); // (q, 1/h, J00, J01, J10, J11)
46
47 auto x = Reshape(x_.Read(), D1D, 2, NF);
48 auto y = Reshape(y_.ReadWrite(), D1D, 2, NF);
49 auto dxdn = Reshape(dxdn_.Read(), D1D, 2, NF);
50 auto dydn = Reshape(dydn_.ReadWrite(), D1D, 2, NF);
51
52 const int NBX = std::max(D1D, Q1D);
53
54 mfem::forall_2D(NF, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
55 {
56 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
57 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
58
59 MFEM_SHARED real_t u0[max_D1D];
60 MFEM_SHARED real_t u1[max_D1D];
61 MFEM_SHARED real_t du0[max_D1D];
62 MFEM_SHARED real_t du1[max_D1D];
63
64 MFEM_SHARED real_t Bu0[max_Q1D];
65 MFEM_SHARED real_t Bu1[max_Q1D];
66 MFEM_SHARED real_t Bdu0[max_Q1D];
67 MFEM_SHARED real_t Bdu1[max_Q1D];
68
69 MFEM_SHARED real_t r[max_Q1D];
70
71 MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
72 DeviceMatrix B(BG, Q1D, D1D);
73 DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
74
75 if (MFEM_THREAD_ID(y) == 0)
76 {
77 MFEM_FOREACH_THREAD(p, x, Q1D)
78 {
79 for (int d = 0; d < D1D; ++d)
80 {
81 B(p, d) = B_(p, d);
82 G(p, d) = G_(p, d);
83 }
84 }
85 }
86 MFEM_SYNC_THREAD;
87
88 // copy edge values to u0, u1 and copy edge normals to du0, du1
89 MFEM_FOREACH_THREAD(side, y, 2)
90 {
91 real_t *u = (side == 0) ? u0 : u1;
92 real_t *du = (side == 0) ? du0 : du1;
93 MFEM_FOREACH_THREAD(d, x, D1D)
94 {
95 u[d] = x(d, side, f);
96 du[d] = dxdn(d, side, f);
97 }
98 }
99 MFEM_SYNC_THREAD;
100
101 // eval @ quad points
102 MFEM_FOREACH_THREAD(side, y, 2)
103 {
104 real_t *u = (side == 0) ? u0 : u1;
105 real_t *du = (side == 0) ? du0 : du1;
106 real_t *Bu = (side == 0) ? Bu0 : Bu1;
107 real_t *Bdu = (side == 0) ? Bdu0 : Bdu1;
108
109 MFEM_FOREACH_THREAD(p, x, Q1D)
110 {
111 const real_t Je_side[] = {pa(2 + 2 * side, p, f),
112 pa(2 + 2 * side + 1, p, f)
113 };
114
115 Bu[p] = 0.0;
116 Bdu[p] = 0.0;
117
118 for (int d = 0; d < D1D; ++d)
119 {
120 const real_t b = B(p, d);
121 const real_t g = G(p, d);
122
123 Bu[p] += b * u[d];
124 Bdu[p] += Je_side[0] * b * du[d] + Je_side[1] * g * u[d];
125 }
126 }
127 }
128 MFEM_SYNC_THREAD;
129
130 // term - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >:
131 if (MFEM_THREAD_ID(y) == 0)
132 {
133 MFEM_FOREACH_THREAD(p, x, Q1D)
134 {
135 const real_t q = pa(0, p, f);
136 const real_t hi = pa(1, p, f);
137 const real_t jump = Bu0[p] - Bu1[p];
138 const real_t avg = Bdu0[p] + Bdu1[p]; // = {Q du/dn} * w * det(J)
139 r[p] = -avg + hi * q * jump;
140 }
141 }
142 MFEM_SYNC_THREAD;
143
144 MFEM_FOREACH_THREAD(d, x, D1D)
145 {
146 real_t Br = 0.0;
147
148 for (int p = 0; p < Q1D; ++p)
149 {
150 Br += B(p, d) * r[p];
151 }
152
153 u0[d] = Br; // overwrite u0, u1
154 u1[d] = -Br;
155 } // for d
156 MFEM_SYNC_THREAD;
157
158 MFEM_FOREACH_THREAD(side, y, 2)
159 {
160 real_t *du = (side == 0) ? du0 : du1;
161 MFEM_FOREACH_THREAD(d, x, D1D) { du[d] = 0.0; }
162 }
163 MFEM_SYNC_THREAD;
164
165 // term sigma * < [u], {Q dv/dn} >
166 MFEM_FOREACH_THREAD(side, y, 2)
167 {
168 real_t *const du = (side == 0) ? du0 : du1;
169 real_t *const u = (side == 0) ? u0 : u1;
170
171 MFEM_FOREACH_THREAD(d, x, D1D)
172 {
173 for (int p = 0; p < Q1D; ++p)
174 {
175 const real_t Je[] = {pa(2 + 2 * side, p, f),
176 pa(2 + 2 * side + 1, p, f)
177 };
178 const real_t jump = Bu0[p] - Bu1[p];
179 const real_t r_p = Je[0] * jump; // normal
180 const real_t w_p = Je[1] * jump; // tangential
181 du[d] += sigma * B(p, d) * r_p;
182 u[d] += sigma * G(p, d) * w_p;
183 }
184 }
185 }
186 MFEM_SYNC_THREAD;
187
188 MFEM_FOREACH_THREAD(side, y, 2)
189 {
190 real_t *u = (side == 0) ? u0 : u1;
191 real_t *du = (side == 0) ? du0 : du1;
192 MFEM_FOREACH_THREAD(d, x, D1D)
193 {
194 y(d, side, f) += u[d];
195 dydn(d, side, f) += du[d];
196 }
197 }
198 }); // mfem::forall
199}
200
201template <int T_D1D = 0, int T_Q1D = 0>
202void PADGDiffusionApply3D(const int NF, const Array<real_t> &b,
203 const Array<real_t> &bt, const Array<real_t> &g,
204 const Array<real_t> &gt, const real_t sigma,
205 const Vector &pa_data, const Vector &x_,
206 const Vector &dxdn_, Vector &y_, Vector &dydn_,
207 const int d1d = 0, const int q1d = 0)
208{
209 const int D1D = T_D1D ? T_D1D : d1d;
210 const int Q1D = T_Q1D ? T_Q1D : q1d;
211 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
212 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
213
214 auto B_ = Reshape(b.Read(), Q1D, D1D);
215 auto G_ = Reshape(g.Read(), Q1D, D1D);
216
217 // (J0[0], J0[1], J0[2], J1[0], J1[1], J1[2], q/h)
218 auto pa = Reshape(pa_data.Read(), 7, Q1D, Q1D, NF);
219
220 auto x = Reshape(x_.Read(), D1D, D1D, 2, NF);
221 auto y = Reshape(y_.ReadWrite(), D1D, D1D, 2, NF);
222 auto dxdn = Reshape(dxdn_.Read(), D1D, D1D, 2, NF);
223 auto dydn = Reshape(dydn_.ReadWrite(), D1D, D1D, 2, NF);
224
225 const int NBX = std::max(D1D, Q1D);
226
227 mfem::forall_3D(NF, NBX, NBX, 2, [=] MFEM_HOST_DEVICE(int f) -> void
228 {
229 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
230 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
231
232 MFEM_SHARED real_t u0[max_Q1D][max_Q1D];
233 MFEM_SHARED real_t u1[max_Q1D][max_Q1D];
234
235 MFEM_SHARED real_t du0[max_Q1D][max_Q1D];
236 MFEM_SHARED real_t du1[max_Q1D][max_Q1D];
237
238 MFEM_SHARED real_t Gu0[max_Q1D][max_Q1D];
239 MFEM_SHARED real_t Gu1[max_Q1D][max_Q1D];
240
241 MFEM_SHARED real_t Bu0[max_Q1D][max_Q1D];
242 MFEM_SHARED real_t Bu1[max_Q1D][max_Q1D];
243
244 MFEM_SHARED real_t Bdu0[max_Q1D][max_Q1D];
245 MFEM_SHARED real_t Bdu1[max_Q1D][max_Q1D];
246
247 MFEM_SHARED real_t kappa_Qh[max_Q1D][max_Q1D];
248
249 MFEM_SHARED real_t nJe[2][max_Q1D][max_Q1D][3];
250 MFEM_SHARED real_t BG[2 * max_D1D * max_Q1D];
251
252 // some buffers are reused multiple times, but for clarity have new names:
253 real_t(*Bj0)[max_Q1D] = Bu0;
254 real_t(*Bj1)[max_Q1D] = Bu1;
255 real_t(*Bjn0)[max_Q1D] = Bdu0;
256 real_t(*Bjn1)[max_Q1D] = Bdu1;
257 real_t(*Gj0)[max_Q1D] = Gu0;
258 real_t(*Gj1)[max_Q1D] = Gu1;
259
260 DeviceMatrix B(BG, Q1D, D1D);
261 DeviceMatrix G(BG + D1D * Q1D, Q1D, D1D);
262
263 // copy face values to u0, u1 and copy normals to du0, du1
264 MFEM_FOREACH_THREAD(side, z, 2)
265 {
266 real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
267 real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
268
269 MFEM_FOREACH_THREAD(d2, x, D1D)
270 {
271 MFEM_FOREACH_THREAD(d1, y, D1D)
272 {
273 u[d2][d1] = x(d1, d2, side,
274 f); // copy transposed for better memory access
275 du[d2][d1] = dxdn(d1, d2, side, f);
276 }
277 }
278
279 MFEM_FOREACH_THREAD(p1, x, Q1D)
280 {
281 MFEM_FOREACH_THREAD(p2, y, Q1D)
282 {
283 for (int l = 0; l < 3; ++l)
284 {
285 nJe[side][p2][p1][l] = pa(3 * side + l, p1, p2, f);
286 }
287
288 if (side == 0)
289 {
290 kappa_Qh[p2][p1] = pa(6, p1, p2, f);
291 }
292 }
293 }
294
295 if (side == 0)
296 {
297 MFEM_FOREACH_THREAD(p, x, Q1D)
298 {
299 MFEM_FOREACH_THREAD(d, y, D1D)
300 {
301 B(p, d) = B_(p, d);
302 G(p, d) = G_(p, d);
303 }
304 }
305 }
306 }
307 MFEM_SYNC_THREAD;
308
309 // eval u and normal derivative @ quad points
310 MFEM_FOREACH_THREAD(side, z, 2)
311 {
312 real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
313 real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
314 real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
315 real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
316 real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
317
318 MFEM_FOREACH_THREAD(p1, x, Q1D)
319 {
320 MFEM_FOREACH_THREAD(d2, y, D1D)
321 {
322 real_t bu = 0.0;
323 real_t bdu = 0.0;
324 real_t gu = 0.0;
325
326 for (int d1 = 0; d1 < D1D; ++d1)
327 {
328 const real_t b = B(p1, d1);
329 const real_t g = G(p1, d1);
330
331 bu += b * u[d2][d1];
332 bdu += b * du[d2][d1];
333 gu += g * u[d2][d1];
334 }
335
336 Bu[p1][d2] = bu;
337 Bdu[p1][d2] = bdu;
338 Gu[p1][d2] = gu;
339 }
340 }
341 }
342 MFEM_SYNC_THREAD;
343
344 MFEM_FOREACH_THREAD(side, z, 2)
345 {
346 real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
347 real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
348 real_t(*Bu)[max_Q1D] = (side == 0) ? Bu0 : Bu1;
349 real_t(*Gu)[max_Q1D] = (side == 0) ? Gu0 : Gu1;
350 real_t(*Bdu)[max_Q1D] = (side == 0) ? Bdu0 : Bdu1;
351
352 MFEM_FOREACH_THREAD(p2, x, Q1D)
353 {
354 MFEM_FOREACH_THREAD(p1, y, Q1D)
355 {
356 const real_t *Je = nJe[side][p2][p1];
357
358 real_t bbu = 0.0;
359 real_t bgu = 0.0;
360 real_t gbu = 0.0;
361 real_t bbdu = 0.0;
362
363 for (int d2 = 0; d2 < D1D; ++d2)
364 {
365 const real_t b = B(p2, d2);
366 const real_t g = G(p2, d2);
367 bbu += b * Bu[p1][d2];
368 gbu += g * Bu[p1][d2];
369 bgu += b * Gu[p1][d2];
370 bbdu += b * Bdu[p1][d2];
371 }
372
373 u[p2][p1] = bbu;
374 // du <- Q du/dn * w * det(J)
375 du[p2][p1] = Je[0] * bbdu + Je[1] * bgu + Je[2] * gbu;
376 }
377 }
378 }
379 MFEM_SYNC_THREAD;
380
381 MFEM_FOREACH_THREAD(side, z, 2)
382 {
383 real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
384 real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
385 real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
386
387 MFEM_FOREACH_THREAD(d1, x, D1D)
388 {
389 MFEM_FOREACH_THREAD(p2, y, Q1D)
390 {
391 real_t bj = 0.0;
392 real_t bjn = 0.0;
393 real_t gj = 0.0;
394 real_t br = 0.0;
395
396 for (int p1 = 0; p1 < Q1D; ++p1)
397 {
398 const real_t b = B(p1, d1);
399 const real_t g = G(p1, d1);
400
401 const real_t *Je = nJe[side][p2][p1];
402
403 const real_t jump = u0[p2][p1] - u1[p2][p1];
404 const real_t avg = du0[p2][p1] + du1[p2][p1];
405
406 // r = - < {Q du/dn}, [v] > + kappa * < {Q/h} [u], [v] >
407 const real_t r = -avg + kappa_Qh[p2][p1] * jump;
408
409 // bj, gj, bjn contribute to sigma term
410 bj += b * Je[0] * jump;
411 gj += g * Je[1] * jump;
412 bjn += b * Je[2] * jump;
413
414 br += b * r;
415 }
416
417 Bj[d1][p2] = sigma * bj;
418 Bjn[d1][p2] = sigma * bjn;
419
420 // group br and gj together since we will multiply them both by B
421 // and then sum
422 const real_t sgn = (side == 0) ? 1.0 : -1.0;
423 Gj[d1][p2] = sgn * br + sigma * gj;
424 }
425 }
426 }
427 MFEM_SYNC_THREAD;
428
429 MFEM_FOREACH_THREAD(side, z, 2)
430 {
431 real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
432 real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
433 real_t(*Bj)[max_Q1D] = (side == 0) ? Bj0 : Bj1;
434 real_t(*Bjn)[max_Q1D] = (side == 0) ? Bjn0 : Bjn1;
435 real_t(*Gj)[max_Q1D] = (side == 0) ? Gj0 : Gj1;
436
437 MFEM_FOREACH_THREAD(d2, x, D1D)
438 {
439 MFEM_FOREACH_THREAD(d1, y, D1D)
440 {
441 real_t bbj = 0.0;
442 real_t gbj = 0.0;
443 real_t bgj = 0.0;
444
445 for (int p2 = 0; p2 < Q1D; ++p2)
446 {
447 const real_t b = B(p2, d2);
448 const real_t g = G(p2, d2);
449
450 bbj += b * Bj[d1][p2];
451 bgj += b * Gj[d1][p2];
452 gbj += g * Bjn[d1][p2];
453 }
454
455 du[d2][d1] = bbj;
456 u[d2][d1] = bgj + gbj;
457 }
458 }
459 }
460 MFEM_SYNC_THREAD;
461
462 // map back to y and dydn
463 MFEM_FOREACH_THREAD(side, z, 2)
464 {
465 const real_t(*u)[max_Q1D] = (side == 0) ? u0 : u1;
466 const real_t(*du)[max_Q1D] = (side == 0) ? du0 : du1;
467
468 MFEM_FOREACH_THREAD(d2, x, D1D)
469 {
470 MFEM_FOREACH_THREAD(d1, y, D1D)
471 {
472 y(d1, d2, side, f) += u[d2][d1];
473 dydn(d1, d2, side, f) += du[d2][d1];
474 }
475 }
476 }
477 });
478}
479
480} // namespace internal
481
482template <int DIM, int D1D, int Q1D>
484DGDiffusionIntegrator::ApplyPAKernels::Kernel()
485{
486 if constexpr (DIM == 2)
487 {
488 return internal::PADGDiffusionApply2D<D1D, Q1D>;
489 }
490 else if constexpr (DIM == 3)
491 {
492 return internal::PADGDiffusionApply3D<D1D, Q1D>;
493 }
494 MFEM_ABORT("");
495}
496} // namespace mfem
497/// \endcond DO_NOT_DOCUMENT
498#endif
void(*)(const int, const Array< real_t > &, const Array< real_t > &, const Array< real_t > &, const Array< real_t > &, const real_t, const Vector &, const Vector &_, const Vector &, Vector &, Vector &, const int, const int) ApplyKernelType
real_t sigma(const Vector &x)
Definition maxwell.cpp:91
real_t b
Definition lissajous.cpp:42
constexpr int DIM
mfem::real_t real_t
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(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
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
DeviceTensor< 2, real_t > DeviceMatrix
Definition dtensor.hpp:150
real_t p(const Vector &x, real_t t)
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138