MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
bilininteg_vecdiffusion_kernels.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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_VECDIFFUSION_KERNELS_HPP
13#define MFEM_BILININTEG_VECDIFFUSION_KERNELS_HPP
14
16#include "../bilininteg.hpp"
18#include "../gridfunc.hpp"
19#include "../qfunction.hpp"
20
21/// \cond DO_NOT_DOCUMENT
22namespace mfem::internal
23{
24
25// PA Diffusion Apply 2D kernel
26template <int T_D1D = 0, int T_Q1D = 0, int T_VDIM = 0>
27static void
28PAVectorDiffusionApply2D(const int NE, const Array<real_t> &b,
29 const Array<real_t> &g, const Array<real_t> &bt,
30 const Array<real_t> &gt, const Vector &d_,
31 const Vector &x_, Vector &y_, const int d1d = 0,
32 const int q1d = 0, const int vdim = 0)
33{
34 const int D1D = T_D1D ? T_D1D : d1d;
35 const int Q1D = T_Q1D ? T_Q1D : q1d;
36 const int VDIM = T_VDIM ? T_VDIM : vdim;
37 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
38 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
39 auto B = Reshape(b.Read(), Q1D, D1D);
40 auto G = Reshape(g.Read(), Q1D, D1D);
41 auto Bt = Reshape(bt.Read(), D1D, Q1D);
42 auto Gt = Reshape(gt.Read(), D1D, Q1D);
43 auto D = Reshape(d_.Read(), Q1D * Q1D, 3, NE);
44 auto x = Reshape(x_.Read(), D1D, D1D, VDIM, NE);
45 auto y = Reshape(y_.ReadWrite(), D1D, D1D, VDIM, NE);
46 mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
47 {
48 const int D1D = T_D1D ? T_D1D : d1d;
49 const int Q1D = T_Q1D ? T_Q1D : q1d;
50 const int VDIM = T_VDIM ? T_VDIM : vdim;
51 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
52 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
53
54 real_t grad[max_Q1D][max_Q1D][2];
55 for (int c = 0; c < VDIM; c++)
56 {
57 for (int qy = 0; qy < Q1D; ++qy)
58 {
59 for (int qx = 0; qx < Q1D; ++qx)
60 {
61 grad[qy][qx][0] = 0.0;
62 grad[qy][qx][1] = 0.0;
63 }
64 }
65 for (int dy = 0; dy < D1D; ++dy)
66 {
67 real_t gradX[max_Q1D][2];
68 for (int qx = 0; qx < Q1D; ++qx)
69 {
70 gradX[qx][0] = 0.0;
71 gradX[qx][1] = 0.0;
72 }
73 for (int dx = 0; dx < D1D; ++dx)
74 {
75 const real_t s = x(dx, dy, c, e);
76 for (int qx = 0; qx < Q1D; ++qx)
77 {
78 gradX[qx][0] += s * B(qx, dx);
79 gradX[qx][1] += s * G(qx, dx);
80 }
81 }
82 for (int qy = 0; qy < Q1D; ++qy)
83 {
84 const real_t wy = B(qy, dy);
85 const real_t wDy = G(qy, dy);
86 for (int qx = 0; qx < Q1D; ++qx)
87 {
88 grad[qy][qx][0] += gradX[qx][1] * wy;
89 grad[qy][qx][1] += gradX[qx][0] * wDy;
90 }
91 }
92 }
93 // Calculate Dxy, xDy in plane
94 for (int qy = 0; qy < Q1D; ++qy)
95 {
96 for (int qx = 0; qx < Q1D; ++qx)
97 {
98 const int q = qx + qy * Q1D;
99 const real_t O11 = D(q, 0, e);
100 const real_t O12 = D(q, 1, e);
101 const real_t O22 = D(q, 2, e);
102 const real_t gradX = grad[qy][qx][0];
103 const real_t gradY = grad[qy][qx][1];
104 grad[qy][qx][0] = (O11 * gradX) + (O12 * gradY);
105 grad[qy][qx][1] = (O12 * gradX) + (O22 * gradY);
106 }
107 }
108 for (int qy = 0; qy < Q1D; ++qy)
109 {
110 real_t gradX[max_D1D][2];
111 for (int dx = 0; dx < D1D; ++dx)
112 {
113 gradX[dx][0] = 0.0;
114 gradX[dx][1] = 0.0;
115 }
116 for (int qx = 0; qx < Q1D; ++qx)
117 {
118 const real_t gX = grad[qy][qx][0];
119 const real_t gY = grad[qy][qx][1];
120 for (int dx = 0; dx < D1D; ++dx)
121 {
122 const real_t wx = Bt(dx, qx);
123 const real_t wDx = Gt(dx, qx);
124 gradX[dx][0] += gX * wDx;
125 gradX[dx][1] += gY * wx;
126 }
127 }
128 for (int dy = 0; dy < D1D; ++dy)
129 {
130 const real_t wy = Bt(dy, qy);
131 const real_t wDy = Gt(dy, qy);
132 for (int dx = 0; dx < D1D; ++dx)
133 {
134 y(dx, dy, c, e) +=
135 ((gradX[dx][0] * wy) + (gradX[dx][1] * wDy));
136 }
137 }
138 }
139 }
140 });
141}
142
143// PA Diffusion Apply 3D kernel
144template <const int T_D1D = 0, const int T_Q1D = 0>
145static void
146PAVectorDiffusionApply3D(const int NE, const Array<real_t> &b,
147 const Array<real_t> &g, const Array<real_t> &bt,
148 const Array<real_t> &gt, const Vector &op_,
149 const Vector &x_, Vector &y_, const int d1d = 0,
150 const int q1d = 0, const int sdim = 0)
151{
152 const int D1D = T_D1D ? T_D1D : d1d;
153 const int Q1D = T_Q1D ? T_Q1D : q1d;
154 constexpr int VDIM = 3;
155 MFEM_VERIFY(D1D <= DeviceDofQuadLimits::Get().MAX_D1D, "");
156 MFEM_VERIFY(Q1D <= DeviceDofQuadLimits::Get().MAX_Q1D, "");
157 auto B = Reshape(b.Read(), Q1D, D1D);
158 auto G = Reshape(g.Read(), Q1D, D1D);
159 auto Bt = Reshape(bt.Read(), D1D, Q1D);
160 auto Gt = Reshape(gt.Read(), D1D, Q1D);
161 auto op = Reshape(op_.Read(), Q1D * Q1D * Q1D, 6, NE);
162 auto x = Reshape(x_.Read(), D1D, D1D, D1D, VDIM, NE);
163 auto y = Reshape(y_.ReadWrite(), D1D, D1D, D1D, VDIM, NE);
164 mfem::forall(NE, [=] MFEM_HOST_DEVICE(int e)
165 {
166 const int D1D = T_D1D ? T_D1D : d1d;
167 const int Q1D = T_Q1D ? T_Q1D : q1d;
168 constexpr int max_D1D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
169 constexpr int max_Q1D = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
170 for (int c = 0; c < VDIM; ++c)
171 {
172 real_t grad[max_Q1D][max_Q1D][max_Q1D][3];
173 for (int qz = 0; qz < Q1D; ++qz)
174 {
175 for (int qy = 0; qy < Q1D; ++qy)
176 {
177 for (int qx = 0; qx < Q1D; ++qx)
178 {
179 grad[qz][qy][qx][0] = 0.0;
180 grad[qz][qy][qx][1] = 0.0;
181 grad[qz][qy][qx][2] = 0.0;
182 }
183 }
184 }
185 for (int dz = 0; dz < D1D; ++dz)
186 {
187 real_t gradXY[max_Q1D][max_Q1D][3];
188 for (int qy = 0; qy < Q1D; ++qy)
189 {
190 for (int qx = 0; qx < Q1D; ++qx)
191 {
192 gradXY[qy][qx][0] = 0.0;
193 gradXY[qy][qx][1] = 0.0;
194 gradXY[qy][qx][2] = 0.0;
195 }
196 }
197 for (int dy = 0; dy < D1D; ++dy)
198 {
199 real_t gradX[max_Q1D][2];
200 for (int qx = 0; qx < Q1D; ++qx)
201 {
202 gradX[qx][0] = 0.0;
203 gradX[qx][1] = 0.0;
204 }
205 for (int dx = 0; dx < D1D; ++dx)
206 {
207 const real_t s = x(dx, dy, dz, c, e);
208 for (int qx = 0; qx < Q1D; ++qx)
209 {
210 gradX[qx][0] += s * B(qx, dx);
211 gradX[qx][1] += s * G(qx, dx);
212 }
213 }
214 for (int qy = 0; qy < Q1D; ++qy)
215 {
216 const real_t wy = B(qy, dy);
217 const real_t wDy = G(qy, dy);
218 for (int qx = 0; qx < Q1D; ++qx)
219 {
220 const real_t wx = gradX[qx][0];
221 const real_t wDx = gradX[qx][1];
222 gradXY[qy][qx][0] += wDx * wy;
223 gradXY[qy][qx][1] += wx * wDy;
224 gradXY[qy][qx][2] += wx * wy;
225 }
226 }
227 }
228 for (int qz = 0; qz < Q1D; ++qz)
229 {
230 const real_t wz = B(qz, dz);
231 const real_t wDz = G(qz, dz);
232 for (int qy = 0; qy < Q1D; ++qy)
233 {
234 for (int qx = 0; qx < Q1D; ++qx)
235 {
236 grad[qz][qy][qx][0] += gradXY[qy][qx][0] * wz;
237 grad[qz][qy][qx][1] += gradXY[qy][qx][1] * wz;
238 grad[qz][qy][qx][2] += gradXY[qy][qx][2] * wDz;
239 }
240 }
241 }
242 }
243 // Calculate Dxyz, xDyz, xyDz in plane
244 for (int qz = 0; qz < Q1D; ++qz)
245 {
246 for (int qy = 0; qy < Q1D; ++qy)
247 {
248 for (int qx = 0; qx < Q1D; ++qx)
249 {
250 const int q = qx + (qy + qz * Q1D) * Q1D;
251 const real_t O11 = op(q, 0, e);
252 const real_t O12 = op(q, 1, e);
253 const real_t O13 = op(q, 2, e);
254 const real_t O22 = op(q, 3, e);
255 const real_t O23 = op(q, 4, e);
256 const real_t O33 = op(q, 5, e);
257 const real_t gradX = grad[qz][qy][qx][0];
258 const real_t gradY = grad[qz][qy][qx][1];
259 const real_t gradZ = grad[qz][qy][qx][2];
260 grad[qz][qy][qx][0] =
261 (O11 * gradX) + (O12 * gradY) + (O13 * gradZ);
262 grad[qz][qy][qx][1] =
263 (O12 * gradX) + (O22 * gradY) + (O23 * gradZ);
264 grad[qz][qy][qx][2] =
265 (O13 * gradX) + (O23 * gradY) + (O33 * gradZ);
266 }
267 }
268 }
269 for (int qz = 0; qz < Q1D; ++qz)
270 {
271 real_t gradXY[max_D1D][max_D1D][3];
272 for (int dy = 0; dy < D1D; ++dy)
273 {
274 for (int dx = 0; dx < D1D; ++dx)
275 {
276 gradXY[dy][dx][0] = 0;
277 gradXY[dy][dx][1] = 0;
278 gradXY[dy][dx][2] = 0;
279 }
280 }
281 for (int qy = 0; qy < Q1D; ++qy)
282 {
283 real_t gradX[max_D1D][3];
284 for (int dx = 0; dx < D1D; ++dx)
285 {
286 gradX[dx][0] = 0;
287 gradX[dx][1] = 0;
288 gradX[dx][2] = 0;
289 }
290 for (int qx = 0; qx < Q1D; ++qx)
291 {
292 const real_t gX = grad[qz][qy][qx][0];
293 const real_t gY = grad[qz][qy][qx][1];
294 const real_t gZ = grad[qz][qy][qx][2];
295 for (int dx = 0; dx < D1D; ++dx)
296 {
297 const real_t wx = Bt(dx, qx);
298 const real_t wDx = Gt(dx, qx);
299 gradX[dx][0] += gX * wDx;
300 gradX[dx][1] += gY * wx;
301 gradX[dx][2] += gZ * wx;
302 }
303 }
304 for (int dy = 0; dy < D1D; ++dy)
305 {
306 const real_t wy = Bt(dy, qy);
307 const real_t wDy = Gt(dy, qy);
308 for (int dx = 0; dx < D1D; ++dx)
309 {
310 gradXY[dy][dx][0] += gradX[dx][0] * wy;
311 gradXY[dy][dx][1] += gradX[dx][1] * wDy;
312 gradXY[dy][dx][2] += gradX[dx][2] * wy;
313 }
314 }
315 }
316 for (int dz = 0; dz < D1D; ++dz)
317 {
318 const real_t wz = Bt(dz, qz);
319 const real_t wDz = Gt(dz, qz);
320 for (int dy = 0; dy < D1D; ++dy)
321 {
322 for (int dx = 0; dx < D1D; ++dx)
323 {
324 y(dx, dy, dz, c, e) +=
325 ((gradXY[dy][dx][0] * wz) + (gradXY[dy][dx][1] * wz) +
326 (gradXY[dy][dx][2] * wDz));
327 }
328 }
329 }
330 }
331 }
332 });
333}
334} // namespace mfem::internal
335
336/// \endcond DO_NOT_DOCUMENT
337
338#endif // MFEM_BILININTEG_VECDIFFUSION_KERNELS_HPP
real_t b
Definition lissajous.cpp:42
mfem::real_t real_t
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(int N, lambda &&body)
Definition forall.hpp:839
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:128