MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
lininteg_domain_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_LININTEG_DOMAIN_KERNELS_HPP
13#define MFEM_LININTEG_DOMAIN_KERNELS_HPP
14
15#include "../../fem/kernels.hpp"
17#include "../fem.hpp"
18
19/// \cond DO_NOT_DOCUMENT
20
21namespace mfem
22{
23
24template <int T_D1D = 0, int T_Q1D = 0>
25void DLFEvalAssemble1D(const int vdim, const int ne, const int d, const int q,
26 const int map_type, const int *markers, const real_t *b,
27 const real_t *detj, const real_t *weights,
28 const Vector &coeff, real_t *y)
29{
30 {
31 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
32 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
33 MFEM_VERIFY(q <= Q, "");
34 MFEM_VERIFY(d <= D, "");
35 }
36
37 const auto F = coeff.Read();
38 const auto B = Reshape(b, q, d);
39 const auto DETJ = Reshape(detj, q, ne);
40 const bool cst = coeff.Size() == vdim;
41 const auto C = cst ? Reshape(F, vdim, 1, 1) : Reshape(F, vdim, q, ne);
42 auto Y = Reshape(y, d, vdim, ne);
43
44 mfem::forall_2D(ne, d, 1, [=] MFEM_HOST_DEVICE(int e)
45 {
46 if (markers[e] == 0)
47 {
48 return;
49 } // ignore
50
51 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
52 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
53
54 MFEM_SHARED real_t sBt[Q * D];
55 const DeviceMatrix Bt(sBt, d, q);
56 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
57
58 for (int c = 0; c < vdim; ++c)
59 {
60 const real_t cst_val = C(c, 0, 0);
61 MFEM_FOREACH_THREAD(dx, x, d)
62 {
63 real_t u = 0;
64 for (int qx = 0; qx < q; ++qx)
65 {
66 const real_t detJ =
67 (map_type == FiniteElement::VALUE) ? DETJ(qx, e) : 1.0;
68 const real_t coeff_val = cst ? cst_val : C(c, qx, e);
69 u += weights[qx] * coeff_val * detJ * Bt(dx, qx);
70 }
71 Y(dx, c, e) += u;
72 }
73 }
74 });
75}
76
77template <int T_D1D = 0, int T_Q1D = 0>
78void DLFEvalAssemble2D(const int vdim, const int ne, const int d, const int q,
79 const int map_type, const int *markers, const real_t *b,
80 const real_t *detj, const real_t *weights,
81 const Vector &coeff, real_t *y)
82{
83 {
84 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
85 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
86 MFEM_VERIFY(q <= Q, "");
87 MFEM_VERIFY(d <= D, "");
88 }
89
90 const auto F = coeff.Read();
91 const auto B = Reshape(b, q, d);
92 const auto DETJ = Reshape(detj, q, q, ne);
93 const auto W = Reshape(weights, q, q);
94 const bool cst = coeff.Size() == vdim;
95 const auto C = cst ? Reshape(F, vdim, 1, 1, 1) : Reshape(F, vdim, q, q, ne);
96 auto Y = Reshape(y, d, d, vdim, ne);
97
98 mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
99 {
100 if (markers[e] == 0)
101 {
102 return;
103 } // ignore
104
105 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
106 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
107
108 MFEM_SHARED real_t sBt[Q * D];
109 MFEM_SHARED real_t sQQ[Q * Q];
110 MFEM_SHARED real_t sQD[Q * D];
111
112 const DeviceMatrix Bt(sBt, d, q);
113 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
114
115 const DeviceMatrix QQ(sQQ, q, q);
116 const DeviceMatrix QD(sQD, q, d);
117
118 for (int c = 0; c < vdim; ++c)
119 {
120 const real_t cst_val = C(c, 0, 0, 0);
121 MFEM_FOREACH_THREAD(x, x, q)
122 {
123 MFEM_FOREACH_THREAD(y, y, q)
124 {
125 const real_t detJ =
126 (map_type == FiniteElement::VALUE) ? DETJ(x, y, e) : 1.0;
127 const real_t coeff_val = cst ? cst_val : C(c, x, y, e);
128 QQ(y, x) = W(x, y) * coeff_val * detJ;
129 }
130 }
131 MFEM_SYNC_THREAD;
132 MFEM_FOREACH_THREAD(qy, y, q)
133 {
134 MFEM_FOREACH_THREAD(dx, x, d)
135 {
136 real_t u = 0.0;
137 for (int qx = 0; qx < q; ++qx)
138 {
139 u += QQ(qy, qx) * Bt(dx, qx);
140 }
141 QD(qy, dx) = u;
142 }
143 }
144 MFEM_SYNC_THREAD;
145 MFEM_FOREACH_THREAD(dy, y, d)
146 {
147 MFEM_FOREACH_THREAD(dx, x, d)
148 {
149 real_t u = 0.0;
150 for (int qy = 0; qy < q; ++qy)
151 {
152 u += QD(qy, dx) * Bt(dy, qy);
153 }
154 Y(dx, dy, c, e) += u;
155 }
156 }
157 MFEM_SYNC_THREAD;
158 }
159 });
160}
161
162template <int T_D1D = 0, int T_Q1D = 0>
163void DLFEvalAssemble3D(const int vdim, const int ne, const int d, const int q,
164 const int map_type, const int *markers, const real_t *b,
165 const real_t *detj, const real_t *weights,
166 const Vector &coeff, real_t *y)
167{
168 {
169 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
170 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
171 MFEM_VERIFY(q <= Q, "");
172 MFEM_VERIFY(d <= D, "");
173 }
174
175 const auto F = coeff.Read();
176 const auto B = Reshape(b, q, d);
177 const auto DETJ = Reshape(detj, q, q, q, ne);
178 const auto W = Reshape(weights, q, q, q);
179 const bool cst_coeff = coeff.Size() == vdim;
180 const auto C =
181 cst_coeff ? Reshape(F, vdim, 1, 1, 1, 1) : Reshape(F, vdim, q, q, q, ne);
182
183 auto Y = Reshape(y, d, d, d, vdim, ne);
184
185 mfem::forall_2D(ne, q, q, [=] MFEM_HOST_DEVICE(int e)
186 {
187 if (markers[e] == 0)
188 {
189 return;
190 } // ignore
191
192 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::MAX_Q1D;
193 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
194 constexpr int MQD = (Q >= D) ? Q : D;
195
196 real_t u[D];
197
198 MFEM_SHARED real_t sBt[Q * D];
199 const DeviceMatrix Bt(sBt, d, q);
200 kernels::internal::LoadB<D, Q>(d, q, B, sBt);
201
202 MFEM_SHARED real_t sQQQ[MQD * MQD * MQD];
203 const DeviceCube QQQ(sQQQ, MQD, MQD, MQD);
204
205 for (int c = 0; c < vdim; ++c)
206 {
207 const real_t cst_val = C(c, 0, 0, 0, 0);
208 MFEM_FOREACH_THREAD(x, x, q)
209 {
210 MFEM_FOREACH_THREAD(y, y, q)
211 {
212 for (int z = 0; z < q; ++z)
213 {
214 const real_t detJ = (map_type == FiniteElement::VALUE)
215 ? DETJ(x, y, z, e)
216 : 1.0;
217 const real_t coeff_val =
218 cst_coeff ? cst_val : C(c, x, y, z, e);
219 QQQ(z, y, x) = W(x, y, z) * coeff_val * detJ;
220 }
221 }
222 }
223 MFEM_SYNC_THREAD;
224 MFEM_FOREACH_THREAD(qx, x, q)
225 {
226 MFEM_FOREACH_THREAD(qy, y, q)
227 {
228 for (int dz = 0; dz < d; ++dz)
229 {
230 u[dz] = 0.0;
231 }
232 for (int qz = 0; qz < q; ++qz)
233 {
234 const real_t ZYX = QQQ(qz, qy, qx);
235 for (int dz = 0; dz < d; ++dz)
236 {
237 u[dz] += ZYX * Bt(dz, qz);
238 }
239 }
240 for (int dz = 0; dz < d; ++dz)
241 {
242 QQQ(dz, qy, qx) = u[dz];
243 }
244 }
245 }
246 MFEM_SYNC_THREAD;
247 MFEM_FOREACH_THREAD(dz, y, d)
248 {
249 MFEM_FOREACH_THREAD(qx, x, q)
250 {
251 for (int dy = 0; dy < d; ++dy)
252 {
253 u[dy] = 0.0;
254 }
255 for (int qy = 0; qy < q; ++qy)
256 {
257 const real_t zYX = QQQ(dz, qy, qx);
258 for (int dy = 0; dy < d; ++dy)
259 {
260 u[dy] += zYX * Bt(dy, qy);
261 }
262 }
263 for (int dy = 0; dy < d; ++dy)
264 {
265 QQQ(dz, dy, qx) = u[dy];
266 }
267 }
268 }
269 MFEM_SYNC_THREAD;
270 MFEM_FOREACH_THREAD(dz, y, d)
271 {
272 MFEM_FOREACH_THREAD(dy, x, d)
273 {
274 for (int dx = 0; dx < d; ++dx)
275 {
276 u[dx] = 0.0;
277 }
278 for (int qx = 0; qx < q; ++qx)
279 {
280 const real_t zyX = QQQ(dz, dy, qx);
281 for (int dx = 0; dx < d; ++dx)
282 {
283 u[dx] += zyX * Bt(dx, qx);
284 }
285 }
286 for (int dx = 0; dx < d; ++dx)
287 {
288 Y(dx, dy, dz, c, e) += u[dx];
289 }
290 }
291 }
292 MFEM_SYNC_THREAD;
293 }
294 });
295}
296
297template <int DIM, int T_D1D, int T_Q1D>
299DomainLFIntegrator::AssembleKernels::Kernel()
300{
301 if constexpr (DIM == 1) { return DLFEvalAssemble1D<T_D1D, T_Q1D>; }
302 if constexpr (DIM == 2) { return DLFEvalAssemble2D<T_D1D, T_Q1D>; }
303 if constexpr (DIM == 3) { return DLFEvalAssemble3D<T_D1D, T_Q1D>; }
304 MFEM_ABORT("");
305}
306
307template <int T_D1D = 0, int T_Q1D = 0>
308void HdivDLFAssemble2D(const int ne, const Array<int> &markers,
309 const Vector &jac, const Array<real_t> &weights,
310 const Array<real_t> &testBO, const Array<real_t> &testBC,
311 const Vector &coeff, Vector &y, const int d, const int q)
312{
313 MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
314 "Problem size too large.");
315 MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
316 "Problem size too large.");
317 MFEM_VERIFY(y.Size() == 2 * (d - 1) * d * ne, "");
318
319 constexpr int vdim = 2;
320 const auto F = coeff.Read();
321 const auto M = markers.Read();
322 const auto BO = Reshape(testBO.Read(), q, d-1);
323 const auto BC = Reshape(testBC.Read(), q, d);
324 const auto J = Reshape(jac.Read(), q, q, vdim, vdim, ne);
325 const auto W = Reshape(weights.Read(), q, q);
326 const bool cst = coeff.Size() == vdim;
327 const auto C = cst ? Reshape(F,vdim,1,1,1) : Reshape(F,vdim,q,q,ne);
328 auto Y = y.ReadWrite();
329
330 mfem::forall_3D(ne, q, q, vdim, [=] MFEM_HOST_DEVICE (int e)
331 {
332 constexpr int vdim = 2;
333 if (M[e] == 0) { return; } // ignore
334
335 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
336 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
337
338 MFEM_SHARED real_t sBot[Q*D];
339 MFEM_SHARED real_t sBct[Q*D];
340 MFEM_SHARED real_t sQQ[vdim*Q*Q];
341 MFEM_SHARED real_t sQD[vdim*Q*D];
342
343 // Bo and Bc into shared memory
344 const DeviceMatrix Bot(sBot, d-1, q);
345 kernels::internal::LoadB<D,Q>(d-1, q, BO, sBot);
346 const DeviceMatrix Bct(sBct, d, q);
347 kernels::internal::LoadB<D,Q>(d, q, BC, sBct);
348
349 const DeviceCube QQ(sQQ, q, q, vdim);
350 const DeviceCube QD(sQD, q, d, vdim);
351
352 MFEM_FOREACH_THREAD(vd,z,vdim)
353 {
354 const real_t cst_val_0 = C(0,0,0,0);
355 const real_t cst_val_1 = C(1,0,0,0);
356 MFEM_FOREACH_THREAD(y,y,q)
357 {
358 MFEM_FOREACH_THREAD(x,x,q)
359 {
360 const real_t J0 = J(x,y,0,vd,e);
361 const real_t J1 = J(x,y,1,vd,e);
362 const real_t C0 = cst ? cst_val_0 : C(0,x,y,e);
363 const real_t C1 = cst ? cst_val_1 : C(1,x,y,e);
364 QQ(x,y,vd) = W(x,y)*(J0*C0 + J1*C1);
365 }
366 }
367 }
368 MFEM_SYNC_THREAD;
369 MFEM_FOREACH_THREAD(vd,z,vdim)
370 {
371 const int nx = (vd == 0) ? d : d-1;
372 DeviceMatrix Btx = (vd == 0) ? Bct : Bot;
373 MFEM_FOREACH_THREAD(qy,y,q)
374 {
375 MFEM_FOREACH_THREAD(dx,x,nx)
376 {
377 real_t qd = 0.0;
378 for (int qx = 0; qx < q; ++qx)
379 {
380 qd += QQ(qx,qy,vd) * Btx(dx,qx);
381 }
382 QD(dx,qy,vd) = qd;
383 }
384 }
385 }
386 MFEM_SYNC_THREAD;
387 MFEM_FOREACH_THREAD(vd,z,vdim)
388 {
389 const int nx = (vd == 0) ? d : d-1;
390 const int ny = (vd == 1) ? d : d-1;
391 DeviceMatrix Bty = (vd == 1) ? Bct : Bot;
392 DeviceTensor<4> Yxy(Y, nx, ny, vdim, ne);
393 MFEM_FOREACH_THREAD(dy,y,ny)
394 {
395 MFEM_FOREACH_THREAD(dx,x,nx)
396 {
397 real_t dd = 0.0;
398 for (int qy = 0; qy < q; ++qy)
399 {
400 dd += QD(dx,qy,vd) * Bty(dy,qy);
401 }
402 Yxy(dx,dy,vd,e) += dd;
403 }
404 }
405 }
406 MFEM_SYNC_THREAD;
407 });
408}
409
410template <int T_D1D = 0, int T_Q1D = 0>
411void HdivDLFAssemble3D(const int ne, const Array<int> &markers,
412 const Vector &jac, const Array<real_t> &weights,
413 const Array<real_t> &testBO,
414 const Array<real_t> &testBC, const Vector &coeff,
415 Vector &y, const int d, const int q)
416{
417 MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HDIV_MAX_D1D,
418 "Problem size too large.");
419 MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HDIV_MAX_Q1D,
420 "Problem size too large.");
421 MFEM_VERIFY(y.Size() == 3 * (d - 1) * (d - 1) * d * ne, "y wrong length");
422
423 constexpr int vdim = 3;
424 const auto F = coeff.Read();
425 const auto M = markers.Read();
426 const auto BO = Reshape(testBO.Read(), q, d-1);
427 const auto BC = Reshape(testBC.Read(), q, d);
428 const auto J = Reshape(jac.Read(), q, q, q, vdim, vdim, ne);
429 const auto W = Reshape(weights.Read(), q, q, q);
430 const bool cst = coeff.Size() == vdim;
431 const auto C = cst ? Reshape(F,vdim,1,1,1,1) : Reshape(F,vdim,q,q,q,ne);
432 auto Y = y.ReadWrite();
433
434 mfem::forall_3D(ne, q, q, vdim, [=] MFEM_HOST_DEVICE (int e)
435 {
436 constexpr int vdim = 3;
437 if (M[e] == 0) { return; } // ignore
438
439 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HDIV_MAX_Q1D;
440 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HDIV_MAX_D1D;
441
442 MFEM_SHARED real_t sBot[Q*D];
443 MFEM_SHARED real_t sBct[Q*D];
444
445 // Bo and Bc into shared memory
446 const DeviceMatrix Bot(sBot, d-1, q);
447 kernels::internal::LoadB<D,Q>(d-1, q, BO, sBot);
448 const DeviceMatrix Bct(sBct, d, q);
449 kernels::internal::LoadB<D,Q>(d, q, BC, sBct);
450
451 MFEM_SHARED real_t sm0[vdim*Q*Q*Q];
452 MFEM_SHARED real_t sm1[vdim*Q*Q*Q];
453 DeviceTensor<4> QQQ(sm1, q, q, q, vdim);
454 DeviceTensor<4> DQQ(sm0, d, q, q, vdim);
455 DeviceTensor<4> DDQ(sm1, d, d, q, vdim);
456
457 MFEM_FOREACH_THREAD(vd,z,vdim)
458 {
459 const real_t cst_val_0 = C(0,0,0,0,0);
460 const real_t cst_val_1 = C(1,0,0,0,0);
461 const real_t cst_val_2 = C(2,0,0,0,0);
462 MFEM_FOREACH_THREAD(y,y,q)
463 {
464 MFEM_FOREACH_THREAD(x,x,q)
465 {
466 for (int z = 0; z < q; ++z)
467 {
468 const real_t J0 = J(x,y,z,0,vd,e);
469 const real_t J1 = J(x,y,z,1,vd,e);
470 const real_t J2 = J(x,y,z,2,vd,e);
471 const real_t C0 = cst ? cst_val_0 : C(0,x,y,z,e);
472 const real_t C1 = cst ? cst_val_1 : C(1,x,y,z,e);
473 const real_t C2 = cst ? cst_val_2 : C(2,x,y,z,e);
474 QQQ(x,y,z,vd) = W(x,y,z)*(J0*C0 + J1*C1 + J2*C2);
475 }
476 }
477 }
478 }
479 MFEM_SYNC_THREAD;
480 // Apply Bt operator
481 MFEM_FOREACH_THREAD(vd,z,vdim)
482 {
483 const int nx = (vd == 0) ? d : d-1;
484 DeviceMatrix Btx = (vd == 0) ? Bct : Bot;
485 MFEM_FOREACH_THREAD(qy,y,q)
486 {
487 MFEM_FOREACH_THREAD(dx,x,nx)
488 {
489 real_t u[Q];
490 MFEM_UNROLL(Q)
491 for (int qz = 0; qz < q; ++qz) { u[qz] = 0.0; }
492 MFEM_UNROLL(Q)
493 for (int qx = 0; qx < q; ++qx)
494 {
495 MFEM_UNROLL(Q)
496 for (int qz = 0; qz < q; ++qz)
497 {
498 u[qz] += QQQ(qx,qy,qz,vd) * Btx(dx,qx);
499 }
500 }
501 MFEM_UNROLL(Q)
502 for (int qz = 0; qz < q; ++qz) { DQQ(dx,qy,qz,vd) = u[qz]; }
503 }
504 }
505 }
506 MFEM_SYNC_THREAD;
507 MFEM_FOREACH_THREAD(vd,z,vdim)
508 {
509 const int nx = (vd == 0) ? d : d-1;
510 const int ny = (vd == 1) ? d : d-1;
511 DeviceMatrix Bty = (vd == 1) ? Bct : Bot;
512 MFEM_FOREACH_THREAD(dy,y,ny)
513 {
514 MFEM_FOREACH_THREAD(dx,x,nx)
515 {
516 real_t u[Q];
517 MFEM_UNROLL(Q)
518 for (int qz = 0; qz < q; ++qz) { u[qz] = 0.0; }
519 MFEM_UNROLL(Q)
520 for (int qy = 0; qy < q; ++qy)
521 {
522 MFEM_UNROLL(Q)
523 for (int qz = 0; qz < q; ++qz)
524 {
525 u[qz] += DQQ(dx,qy,qz,vd) * Bty(dy,qy);
526 }
527 }
528 MFEM_UNROLL(Q)
529 for (int qz = 0; qz < q; ++qz) { DDQ(dx,dy,qz,vd) = u[qz]; }
530 }
531 }
532 }
533 MFEM_SYNC_THREAD;
534 MFEM_FOREACH_THREAD(vd,z,vdim)
535 {
536 const int nx = (vd == 0) ? d : d-1;
537 const int ny = (vd == 1) ? d : d-1;
538 const int nz = (vd == 2) ? d : d-1;
539 DeviceTensor<5> Yxyz(Y, nx, ny, nz, vdim, ne);
540 DeviceMatrix Btz = (vd == 2) ? Bct : Bot;
541 MFEM_FOREACH_THREAD(dy,y,ny)
542 {
543 MFEM_FOREACH_THREAD(dx,x,nx)
544 {
545 real_t u[D];
546 MFEM_UNROLL(D)
547 for (int dz = 0; dz < nz; ++dz) { u[dz] = 0.0; }
548 MFEM_UNROLL(Q)
549 for (int qz = 0; qz < q; ++qz)
550 {
551 MFEM_UNROLL(D)
552 for (int dz = 0; dz < nz; ++dz)
553 {
554 u[dz] += DDQ(dx,dy,qz,vd) * Btz(dz,qz);
555 }
556 }
557 MFEM_UNROLL(D)
558 for (int dz = 0; dz < nz; ++dz) { Yxyz(dx,dy,dz,vd,e) += u[dz]; }
559 }
560 }
561 }
562 MFEM_SYNC_THREAD;
563 });
564}
565
566/// @param ne number of elements
567/// @param markers array where entry markers[e] == 0 to skip assembly over
568/// element e element
569/// @param jac Spatial Jacobians evaluated at all quadrature points
570/// @param weights 1D quadrature weights
571/// @param testBO 1D open basis test functions
572/// @param testBC 1D closed basis test functions
573/// @param coeff coefficient values evaluated at quadrature points, possibly
574/// compressed.
575/// @param d number of 1D closed dofs
576/// @param q number of 1D quadrature points
577/// @tparam T_D1D maximum number of dofs along any direction, or 0
578/// @tparam T_Q1D maximum number of quadrature points along any direction, or 0
579template <int T_D1D = 0, int T_Q1D = 0>
580void HcurlDLFAssemble3D(const int ne, const Array<int> &markers,
581 const Vector &jac, const Array<real_t> &weights,
582 const Array<real_t> &testBO,
583 const Array<real_t> &testBC, const Vector &coeff,
584 Vector &y, const int d, const int q)
585{
586 MFEM_VERIFY(T_D1D || d <= DeviceDofQuadLimits::Get().HCURL_MAX_D1D,
587 "Problem size too large.");
588 MFEM_VERIFY(T_Q1D || q <= DeviceDofQuadLimits::Get().HCURL_MAX_Q1D,
589 "Problem size too large.");
590 MFEM_VERIFY(y.Size() == 3 * (d - 1) * d * d * ne, "y wrong length");
591
592 constexpr int vdim = 3;
593 const auto F = coeff.Read();
594 const auto M = markers.Read();
595 const auto BO = Reshape(testBO.Read(), q, d-1);
596 const auto BC = Reshape(testBC.Read(), q, d);
597 const auto J = Reshape(jac.Read(), q, q, q, vdim, vdim, ne);
598 const auto W = Reshape(weights.Read(), q, q, q);
599 const bool cst = coeff.Size() == vdim;
600 const auto C = cst ? Reshape(F,vdim,1,1,1,1) : Reshape(F,vdim,q,q,q,ne);
601 auto Y = y.ReadWrite();
602
603 mfem::forall_3D(ne, q, q, vdim, [=] MFEM_HOST_DEVICE(int e)
604 {
605 if (M[e] == 0)
606 {
607 // ignore
608 return;
609 }
610
611 constexpr int vdim = 3;
612 constexpr int Q = T_Q1D ? T_Q1D : DofQuadLimits::HCURL_MAX_Q1D;
613 constexpr int D = T_D1D ? T_D1D : DofQuadLimits::HCURL_MAX_D1D;
614
615 MFEM_SHARED real_t sBot[Q * D];
616 MFEM_SHARED real_t sBct[Q * D];
617
618 // Bo and Bc into shared memory
619 const DeviceMatrix Bot(sBot, d - 1, q);
620 kernels::internal::LoadB<D, Q>(d - 1, q, BO, sBot);
621 const DeviceMatrix Bct(sBct, d, q);
622 kernels::internal::LoadB<D, Q>(d, q, BC, sBct);
623
624 MFEM_SHARED real_t sm0[vdim * Q * Q * Q];
625 MFEM_SHARED real_t sm1[vdim * Q * Q * Q];
626 DeviceTensor<4> QQQ(sm1, q, q, q, vdim);
627 DeviceTensor<4> DQQ(sm0, d, q, q, vdim);
628 DeviceTensor<4> DDQ(sm1, d, d, q, vdim);
629
630 const real_t cst_val_0 = C(0, 0, 0, 0, 0);
631 const real_t cst_val_1 = C(1, 0, 0, 0, 0);
632 const real_t cst_val_2 = C(2, 0, 0, 0, 0);
633
634 MFEM_FOREACH_THREAD(vd, z, vdim)
635 {
636 MFEM_FOREACH_THREAD(y, y, q)
637 {
638 MFEM_FOREACH_THREAD(x, x, q)
639 {
640 for (int z = 0; z < q; ++z)
641 {
642 real_t curr[3];
643 curr[0] = cst ? cst_val_0 : C(0, x, y, z, e);
644 curr[1] = cst ? cst_val_1 : C(1, x, y, z, e);
645 curr[2] = cst ? cst_val_2 : C(2, x, y, z, e);
646
647 const real_t J11 = J(x, y, z, 0, 0, e);
648 const real_t J21 = J(x, y, z, 1, 0, e);
649 const real_t J31 = J(x, y, z, 2, 0, e);
650 const real_t J12 = J(x, y, z, 0, 1, e);
651 const real_t J22 = J(x, y, z, 1, 1, e);
652 const real_t J32 = J(x, y, z, 2, 1, e);
653 const real_t J13 = J(x, y, z, 0, 2, e);
654 const real_t J23 = J(x, y, z, 1, 2, e);
655 const real_t J33 = J(x, y, z, 2, 2, e);
656 // adj(J)
657 const real_t A11 = (J22 * J33) - (J23 * J32);
658 const real_t A12 = (J32 * J13) - (J12 * J33);
659 const real_t A13 = (J12 * J23) - (J22 * J13);
660 const real_t A21 = (J31 * J23) - (J21 * J33);
661 const real_t A22 = (J11 * J33) - (J13 * J31);
662 const real_t A23 = (J21 * J13) - (J11 * J23);
663 const real_t A31 = (J21 * J32) - (J31 * J22);
664 const real_t A32 = (J31 * J12) - (J11 * J32);
665 const real_t A33 = (J11 * J22) - (J12 * J21);
666 const real_t A[9] = {A11, A12, A13, A21, A22,
667 A23, A31, A32, A33
668 };
669 QQQ(x, y, z, vd) = W(x, y, z) * (A[vd * vdim] * curr[0] +
670 A[vd * vdim + 1] * curr[1] +
671 A[vd * vdim + 2] * curr[2]);
672 }
673 }
674 }
675 }
676 MFEM_SYNC_THREAD;
677 // Apply Bt operator
678 MFEM_FOREACH_THREAD(vd, z, vdim)
679 {
680 const int nx = (vd == 0) ? d - 1 : d;
681 DeviceMatrix Btx = (vd == 0) ? Bot : Bct;
682 MFEM_FOREACH_THREAD(qy, y, q)
683 {
684 MFEM_FOREACH_THREAD(dx, x, nx)
685 {
686 real_t u[Q];
687 MFEM_UNROLL(Q)
688 for (int qz = 0; qz < q; ++qz)
689 {
690 u[qz] = 0.0;
691 }
692 MFEM_UNROLL(Q)
693 for (int qx = 0; qx < q; ++qx)
694 {
695 MFEM_UNROLL(Q)
696 for (int qz = 0; qz < q; ++qz)
697 {
698 u[qz] += QQQ(qx, qy, qz, vd) * Btx(dx, qx);
699 }
700 }
701 MFEM_UNROLL(Q)
702 for (int qz = 0; qz < q; ++qz)
703 {
704 DQQ(dx, qy, qz, vd) = u[qz];
705 }
706 }
707 }
708 }
709 MFEM_SYNC_THREAD;
710 MFEM_FOREACH_THREAD(vd, z, vdim)
711 {
712 const int nx = (vd == 0) ? d - 1 : d;
713 const int ny = (vd == 1) ? d - 1 : d;
714 DeviceMatrix Bty = (vd == 1) ? Bot : Bct;
715 MFEM_FOREACH_THREAD(dy, y, ny)
716 {
717 MFEM_FOREACH_THREAD(dx, x, nx)
718 {
719 real_t u[Q];
720 MFEM_UNROLL(Q)
721 for (int qz = 0; qz < q; ++qz)
722 {
723 u[qz] = 0.0;
724 }
725 MFEM_UNROLL(Q)
726 for (int qy = 0; qy < q; ++qy)
727 {
728 MFEM_UNROLL(Q)
729 for (int qz = 0; qz < q; ++qz)
730 {
731 u[qz] += DQQ(dx, qy, qz, vd) * Bty(dy, qy);
732 }
733 }
734 MFEM_UNROLL(Q)
735 for (int qz = 0; qz < q; ++qz)
736 {
737 DDQ(dx, dy, qz, vd) = u[qz];
738 }
739 }
740 }
741 }
742 MFEM_SYNC_THREAD;
743 MFEM_FOREACH_THREAD(vd, z, vdim)
744 {
745 const int nx = (vd == 0) ? d - 1 : d;
746 const int ny = (vd == 1) ? d - 1 : d;
747 const int nz = (vd == 2) ? d - 1 : d;
748 DeviceTensor<5> Yxyz(Y, nx, ny, nz, vdim, ne);
749 DeviceMatrix Btz = (vd == 2) ? Bot : Bct;
750 MFEM_FOREACH_THREAD(dy, y, ny)
751 {
752 MFEM_FOREACH_THREAD(dx, x, nx)
753 {
754 real_t u[D];
755 MFEM_UNROLL(D)
756 for (int dz = 0; dz < nz; ++dz)
757 {
758 u[dz] = 0.0;
759 }
760 MFEM_UNROLL(Q)
761 for (int qz = 0; qz < q; ++qz)
762 {
763 MFEM_UNROLL(D)
764 for (int dz = 0; dz < nz; ++dz)
765 {
766 u[dz] += DDQ(dx, dy, qz, vd) * Btz(dz, qz);
767 }
768 }
769 MFEM_UNROLL(D)
770 for (int dz = 0; dz < nz; ++dz)
771 {
772 Yxyz(dx, dy, dz, vd, e) += u[dz];
773 }
774 }
775 }
776 }
777 MFEM_SYNC_THREAD;
778 });
779}
780
781template <FiniteElement::DerivType TestType, int DIM, int TEST_D1D, int Q1D>
783VectorFEDomainLFIntegrator::AssembleKernels::Kernel()
784{
785 if constexpr (TestType == FiniteElement::DIV)
786 {
787 if constexpr (DIM == 2)
788 {
789 return HdivDLFAssemble2D<TEST_D1D, Q1D>;
790 }
791 if constexpr (DIM == 3)
792 {
793 return HdivDLFAssemble3D<TEST_D1D, Q1D>;
794 }
795 }
796 if constexpr (TestType == FiniteElement::CURL)
797 {
798 if constexpr (DIM == 3)
799 {
800 return HcurlDLFAssemble3D<TEST_D1D, Q1D>;
801 }
802 }
803 MFEM_ABORT("");
804}
805
806/// \endcond DO_NOT_DOCUMENT
807
808} // namespace mfem
809
810#endif // MFEM_LININTEG_DOMAIN_KERNELS_HPP
void(*)(const int, const int, const int, const int, const int, const int *, const real_t *, const real_t *, const real_t *, const Vector &coeff, real_t *y) AssembleKernelType
args: vdim, ne, d1d, q1d, map_type, markers, B, detJ, W, coeff, y
Definition lininteg.hpp:141
@ DIV
Implements CalcDivShape methods.
Definition fe_base.hpp:366
@ CURL
Implements CalcCurlShape methods.
Definition fe_base.hpp:367
void(*)(const int NE, const Array< int > &markers, const Vector &jac, const Array< real_t > &weights, const Array< real_t > &testBO, const Array< real_t > &testBC, const Vector &coeff, Vector &y, const int testd1d, const int q1d) AssembleKernelType
Definition lininteg.hpp:403
real_t b
Definition lissajous.cpp:42
constexpr int DIM
mfem::real_t real_t
DeviceTensor< 3, real_t > DeviceCube
Definition dtensor.hpp:153
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
DeviceTensor< 2, real_t > DeviceMatrix
Definition dtensor.hpp:150
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138