MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
integrate.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#pragma once
12
13#include "util.hpp"
14
15namespace mfem::future
16{
17
18template <typename output_t>
19MFEM_HOST_DEVICE
23 const output_t &output,
24 const DofToQuadMap &dtq)
25{
26 [[maybe_unused]] auto B = dtq.B;
27 [[maybe_unused]] auto G = dtq.G;
28
29 // assuming the quadrature point residual has to "play nice with
30 // the test function"
31 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
32 {
33 const auto [num_qp, cdim, num_dof] = B.GetShape();
34 const int vdim = output.vdim > 0 ? output.vdim : cdim ;
35 for (int dof = 0; dof < num_dof; dof++)
36 {
37 for (int vd = 0; vd < vdim; vd++)
38 {
39 real_t acc = 0.0;
40 for (int qp = 0; qp < num_qp; qp++)
41 {
42 acc += B(qp, 0, dof) * f(vd, 0, qp);
43 }
44 y(dof, vd) += acc;
45 }
46 }
47 }
48 else if constexpr (
50 {
51 const auto [num_qp, dim, num_dof] = G.GetShape();
52 const int vdim = output.vdim;
53 for (int dof = 0; dof < num_dof; dof++)
54 {
55 for (int vd = 0; vd < vdim; vd++)
56 {
57 real_t acc = 0.0;
58 for (int d = 0; d < dim; d++)
59 {
60 for (int qp = 0; qp < num_qp; qp++)
61 {
62 acc += G(qp, d, dof) * f(vd, d, qp);
63 }
64 }
65 y(dof, vd) += acc;
66 }
67 }
68 }
69 else if constexpr (is_sum_fop<std::decay_t<output_t>>::value)
70 {
71 // This is the "integral over all quadrature points type" applying
72 // B = 1 s.t. B^T * C \in R^1.
73 const auto [num_qp, unused, unused1] = B.GetShape();
74 auto cc = Reshape(&f(0, 0, 0), num_qp);
75 for (int i = 0; i < num_qp; i++)
76 {
77 y(0, 0) += cc(i);
78 }
79 }
80 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
81 {
82 const auto [num_qp, unused, num_dof] = B.GetShape();
83 const auto vdim = output.vdim;
84 auto cc = Reshape(&f(0, 0, 0), num_qp * vdim);
85 auto yy = Reshape(&y(0, 0), num_qp * vdim);
86 for (int i = 0; i < num_qp * vdim; i++)
87 {
88 yy(i) = cc(i);
89 }
90 }
91 else
92 {
93 MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
94 " for this field descriptor");
95 }
96}
97
98template <typename output_t>
99MFEM_HOST_DEVICE
103 const output_t &output,
104 const DofToQuadMap &dtq,
105 std::array<DeviceTensor<1>, 6> &scratch_mem)
106{
107 [[maybe_unused]] auto B = dtq.B;
108 [[maybe_unused]] auto G = dtq.G;
109
110 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
111 {
112 const auto [q1d, unused, d1d] = B.GetShape();
113 const int vdim = output.vdim;
114 const int test_dim = output.size_on_qp / vdim;
115
116 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d);
117 auto yd = Reshape(&y(0, 0), d1d, vdim);
118
119 for (int vd = 0; vd < vdim; vd++)
120 {
121 MFEM_FOREACH_THREAD(dx, x, d1d)
122 {
123 real_t acc = 0.0;
124 for (int qx = 0; qx < q1d; qx++)
125 {
126 acc += fqp(vd, 0, qx) * B(qx, 0, dx);
127 }
128 yd(dx, vd) = acc;
129 }
130 }
131 MFEM_SYNC_THREAD;
132 }
133 else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
134 {
135 const auto [q1d, unused, d1d] = G.GetShape();
136 const int vdim = output.vdim;
137 const int test_dim = output.size_on_qp / vdim;
138 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d);
139 auto yd = Reshape(&y(0, 0), d1d, vdim);
140
141 for (int vd = 0; vd < vdim; vd++)
142 {
143 MFEM_FOREACH_THREAD(dx, x, d1d)
144 {
145 real_t acc = 0.0;
146 for (int qx = 0; qx < q1d; qx++)
147 {
148 acc += fqp(vd, 0, qx) * G(qx, 0, dx);
149 }
150 yd(dx, vd) = acc;
151 }
152 }
153 MFEM_SYNC_THREAD;
154 }
155 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
156 {
157 const auto [q1d, unused, d1d] = B.GetShape();
158 auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d);
159 auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d);
160
161 for (int sq = 0; sq < output.size_on_qp; sq++)
162 {
163 MFEM_FOREACH_THREAD(qx, x, q1d)
164 {
165 yqp(sq, qx) = fqp(sq, qx);
166 }
167 MFEM_SYNC_THREAD;
168 }
169 }
170 else
171 {
172 MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
173 "for this field descriptor with sum factorization on"
174 " tensor product elements");
175 }
176}
177
178template <typename output_t>
179MFEM_HOST_DEVICE
183 const output_t &output,
184 const DofToQuadMap &dtq,
185 std::array<DeviceTensor<1>, 6> &scratch_mem)
186{
187 [[maybe_unused]] auto B = dtq.B;
188 [[maybe_unused]] auto G = dtq.G;
189
190 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
191 {
192 const auto [q1d, unused, d1d] = B.GetShape();
193 const int vdim = output.vdim;
194 const int test_dim = output.size_on_qp / vdim;
195
196 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d);
197 auto yd = Reshape(&y(0, 0), d1d, d1d, vdim);
198
199 auto s0 = Reshape(&scratch_mem[0](0), q1d, d1d);
200
201 for (int vd = 0; vd < vdim; vd++)
202 {
203 MFEM_FOREACH_THREAD(qy, y, q1d)
204 {
205 MFEM_FOREACH_THREAD(dx, x, d1d)
206 {
207 real_t acc = 0.0;
208 for (int qx = 0; qx < q1d; qx++)
209 {
210 acc += fqp(vd, 0, qx, qy) * B(qx, 0, dx);
211 }
212 s0(qy, dx) = acc;
213 }
214 }
215 MFEM_SYNC_THREAD;
216
217 MFEM_FOREACH_THREAD(dy, y, d1d)
218 {
219 MFEM_FOREACH_THREAD(dx, x, d1d)
220 {
221 real_t acc = 0.0;
222 for (int qy = 0; qy < q1d; qy++)
223 {
224 acc += s0(qy, dx) * B(qy, 0, dy);
225 }
226 yd(dx, dy, vd) += acc;
227 }
228 }
229 MFEM_SYNC_THREAD;
230 }
231 }
232 else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
233 {
234 const auto [q1d, unused, d1d] = G.GetShape();
235 const int vdim = output.vdim;
236 const int test_dim = output.size_on_qp / vdim;
237 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d);
238 auto yd = Reshape(&y(0, 0), d1d, d1d, vdim);
239
240 auto s0 = Reshape(&scratch_mem[0](0), q1d, d1d);
241 auto s1 = Reshape(&scratch_mem[1](0), q1d, d1d);
242
243 for (int vd = 0; vd < vdim; vd++)
244 {
245 MFEM_FOREACH_THREAD(qy, y, q1d)
246 {
247 MFEM_FOREACH_THREAD(dx, x, d1d)
248 {
249 real_t uv[2] = {0.0, 0.0};
250 for (int qx = 0; qx < q1d; qx++)
251 {
252 uv[0] += fqp(vd, 0, qx, qy) * G(qx, 0, dx);
253 uv[1] += fqp(vd, 1, qx, qy) * B(qx, 0, dx);
254 }
255 s0(qy, dx) = uv[0];
256 s1(qy, dx) = uv[1];
257 }
258 }
259 MFEM_SYNC_THREAD;
260
261 MFEM_FOREACH_THREAD(dy, y, d1d)
262 {
263 MFEM_FOREACH_THREAD(dx, x, d1d)
264 {
265 real_t uv[2] = {0.0, 0.0};
266 for (int qy = 0; qy < q1d; qy++)
267 {
268 uv[0] += s0(qy, dx) * B(qy, 0, dy);
269 uv[1] += s1(qy, dx) * G(qy, 0, dy);
270 }
271 yd(dx, dy, vd) += uv[0] + uv[1];
272 }
273 }
274 MFEM_SYNC_THREAD;
275 }
276 }
277 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
278 {
279 const auto [q1d, unused, d1d] = B.GetShape();
280
281 // // TODO: Check if this is the right fix for all cases
282 // auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d);
283 // auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d);
284 // for (int sq = 0; sq < output.size_on_qp; sq++)
285 // {
286 // MFEM_FOREACH_THREAD(qx, x, q1d)
287 // {
288 // yqp(sq, qx) = fqp(sq, qx);
289 // }
290 // MFEM_SYNC_THREAD;
291 // }
292
293 auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d, q1d);
294 auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d, q1d);
295
296 for (int sq = 0; sq < output.size_on_qp; sq++)
297 {
298 MFEM_FOREACH_THREAD(qx, x, q1d)
299 {
300 MFEM_FOREACH_THREAD(qy, y, q1d)
301 {
302 yqp(sq, qx, qy) = fqp(sq, qx, qy);
303 }
304 }
305 MFEM_SYNC_THREAD;
306 }
307 }
308 else
309 {
310 MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
311 " for this field descriptor with sum factorization on"
312 " tensor product elements");
313 }
314}
315
316template <typename output_t>
317MFEM_HOST_DEVICE
321 const output_t &output,
322 const DofToQuadMap &dtq,
323 std::array<DeviceTensor<1>, 6> &scratch_mem)
324{
325 [[maybe_unused]] auto B = dtq.B;
326 [[maybe_unused]] auto G = dtq.G;
327
328 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
329 {
330 const auto [q1d, unused, d1d] = B.GetShape();
331 const int vdim = output.vdim;
332 const int test_dim = output.size_on_qp / vdim;
333
334 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
335 auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
336
337 auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
338 auto s1 = Reshape(&scratch_mem[1](0), q1d, d1d, d1d);
339
340 for (int vd = 0; vd < vdim; vd++)
341 {
342 MFEM_FOREACH_THREAD(qy, y, q1d)
343 {
344 MFEM_FOREACH_THREAD(dx, x, d1d)
345 {
346 MFEM_FOREACH_THREAD(qz, z, q1d)
347 {
348 real_t acc = 0.0;
349 for (int qx = 0; qx < q1d; qx++)
350 {
351 acc += fqp(vd, 0, qx, qy, qz) * B(qx, 0, dx);
352 }
353 s0(qz, qy, dx) = acc;
354 }
355 }
356 }
357 MFEM_SYNC_THREAD;
358
359 MFEM_FOREACH_THREAD(dy, y, d1d)
360 {
361 MFEM_FOREACH_THREAD(dx, x, d1d)
362 {
363 MFEM_FOREACH_THREAD(qz, z, q1d)
364 {
365 real_t acc = 0.0;
366 for (int qy = 0; qy < q1d; qy++)
367 {
368 acc += s0(qz, qy, dx) * B(qy, 0, dy);
369 }
370 s1(qz, dy, dx) = acc;
371 }
372 }
373 }
374 MFEM_SYNC_THREAD;
375
376
377 MFEM_FOREACH_THREAD(dy, y, d1d)
378 {
379 MFEM_FOREACH_THREAD(dx, x, d1d)
380 {
381 MFEM_FOREACH_THREAD(dz, z, d1d)
382 {
383 real_t acc = 0.0;
384 for (int qz = 0; qz < q1d; qz++)
385 {
386 acc += s1(qz, dy, dx) * B(qz, 0, dz);
387 }
388 yd(dx, dy, dz, vd) += acc;
389 }
390 }
391 }
392 MFEM_SYNC_THREAD;
393 }
394 }
395 else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
396 {
397 const auto [q1d, unused, d1d] = G.GetShape();
398 const int vdim = output.vdim;
399 const int test_dim = output.size_on_qp / vdim;
400 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
401 auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
402
403 auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
404 auto s1 = Reshape(&scratch_mem[1](0), q1d, q1d, d1d);
405 auto s2 = Reshape(&scratch_mem[2](0), q1d, q1d, d1d);
406 auto s3 = Reshape(&scratch_mem[3](0), q1d, d1d, d1d);
407 auto s4 = Reshape(&scratch_mem[4](0), q1d, d1d, d1d);
408 auto s5 = Reshape(&scratch_mem[5](0), q1d, d1d, d1d);
409
410 for (int vd = 0; vd < vdim; vd++)
411 {
412 MFEM_FOREACH_THREAD(qz, z, q1d)
413 {
414 MFEM_FOREACH_THREAD(qy, y, q1d)
415 {
416 MFEM_FOREACH_THREAD(dx, x, d1d)
417 {
418 real_t uvw[3] = {0.0, 0.0, 0.0};
419 for (int qx = 0; qx < q1d; qx++)
420 {
421 uvw[0] += fqp(vd, 0, qx, qy, qz) * G(qx, 0, dx);
422 uvw[1] += fqp(vd, 1, qx, qy, qz) * B(qx, 0, dx);
423 uvw[2] += fqp(vd, 2, qx, qy, qz) * B(qx, 0, dx);
424 }
425 s0(qz, qy, dx) = uvw[0];
426 s1(qz, qy, dx) = uvw[1];
427 s2(qz, qy, dx) = uvw[2];
428 }
429 }
430 }
431 MFEM_SYNC_THREAD;
432
433 MFEM_FOREACH_THREAD(qz, z, q1d)
434 {
435 MFEM_FOREACH_THREAD(dy, y, d1d)
436 {
437 MFEM_FOREACH_THREAD(dx, x, d1d)
438 {
439 real_t uvw[3] = {0.0, 0.0, 0.0};
440 for (int qy = 0; qy < q1d; qy++)
441 {
442 uvw[0] += s0(qz, qy, dx) * B(qy, 0, dy);
443 uvw[1] += s1(qz, qy, dx) * G(qy, 0, dy);
444 uvw[2] += s2(qz, qy, dx) * B(qy, 0, dy);
445 }
446 s3(qz, dy, dx) = uvw[0];
447 s4(qz, dy, dx) = uvw[1];
448 s5(qz, dy, dx) = uvw[2];
449 }
450 }
451 }
452 MFEM_SYNC_THREAD;
453
454 MFEM_FOREACH_THREAD(dz, z, d1d)
455 {
456 MFEM_FOREACH_THREAD(dy, y, d1d)
457 {
458 MFEM_FOREACH_THREAD(dx, x, d1d)
459 {
460 real_t uvw[3] = {0.0, 0.0, 0.0};
461 for (int qz = 0; qz < q1d; qz++)
462 {
463 uvw[0] += s3(qz, dy, dx) * B(qz, 0, dz);
464 uvw[1] += s4(qz, dy, dx) * B(qz, 0, dz);
465 uvw[2] += s5(qz, dy, dx) * G(qz, 0, dz);
466 }
467 yd(dx, dy, dz, vd) += uvw[0] + uvw[1] + uvw[2];
468 }
469 }
470 }
471 MFEM_SYNC_THREAD;
472 }
473 }
474 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
475 {
476 const auto [q1d, unused, d1d] = B.GetShape();
477 auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d, q1d, q1d);
478 auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d, q1d, q1d);
479
480 for (int sq = 0; sq < output.size_on_qp; sq++)
481 {
482 MFEM_FOREACH_THREAD(qx, x, q1d)
483 {
484 MFEM_FOREACH_THREAD(qy, y, q1d)
485 {
486 MFEM_FOREACH_THREAD(qz, z, q1d)
487 {
488 yqp(sq, qx, qy, qz) = fqp(sq, qx, qy, qz);
489 }
490 }
491 }
492 MFEM_SYNC_THREAD;
493 }
494 }
495 else
496 {
497 MFEM_ABORT_KERNEL("quadrature data mapping to field is not implemented"
498 " for this field descriptor with sum factorization on"
499 " tensor product elements");
500 }
501}
502
503template <typename output_t>
504MFEM_HOST_DEVICE
508 const output_t &output,
509 const DofToQuadMap &dtq,
510 std::array<DeviceTensor<1>, 6> &scratch_mem,
511 const int &dimension,
512 const bool &use_sum_factorization)
513{
514 if (use_sum_factorization)
515 {
516 if (dimension == 1)
517 {
518 map_quadrature_data_to_fields_tensor_impl_1d(y, f, output, dtq, scratch_mem);
519 }
520 else if (dimension == 2)
521 {
522 map_quadrature_data_to_fields_tensor_impl_2d(y, f, output, dtq, scratch_mem);
523 }
524 else if (dimension == 3)
525 {
526 map_quadrature_data_to_fields_tensor_impl_3d(y, f, output, dtq, scratch_mem);
527 }
528 else { MFEM_ABORT_KERNEL("dimension not supported"); }
529 }
530 else
531 {
532 map_quadrature_data_to_fields_impl(y, f, output, dtq);
533 }
534}
535
536} // namespace mfem::future
A basic generic Tensor class, appropriate for use on the GPU.
Definition dtensor.hpp:84
MFEM_HOST_DEVICE auto & GetShape() const
Returns the shape of the tensor.
Definition dtensor.hpp:131
int dim
Definition ex24.cpp:53
constexpr int dimension
This example only works in 3D. Kernels for 2D are not implemented.
Definition hooke.cpp:45
MFEM_HOST_DEVICE void map_quadrature_data_to_fields_tensor_impl_2d(DeviceTensor< 2, real_t > &y, const DeviceTensor< 3, real_t > &f, const output_t &output, const DofToQuadMap &dtq, std::array< DeviceTensor< 1 >, 6 > &scratch_mem)
MFEM_HOST_DEVICE void map_quadrature_data_to_fields_tensor_impl_1d(DeviceTensor< 2, real_t > &y, const DeviceTensor< 3, real_t > &f, const output_t &output, const DofToQuadMap &dtq, std::array< DeviceTensor< 1 >, 6 > &scratch_mem)
MFEM_HOST_DEVICE void map_quadrature_data_to_fields(DeviceTensor< 2, real_t > &y, const DeviceTensor< 3, real_t > &f, const output_t &output, const DofToQuadMap &dtq, std::array< DeviceTensor< 1 >, 6 > &scratch_mem, const int &dimension, const bool &use_sum_factorization)
MFEM_HOST_DEVICE void map_quadrature_data_to_fields_tensor_impl_3d(DeviceTensor< 2, real_t > &y, const DeviceTensor< 3, real_t > &f, const output_t &output, const DofToQuadMap &dtq, std::array< DeviceTensor< 1 >, 6 > &scratch_mem)
MFEM_HOST_DEVICE void map_quadrature_data_to_fields_impl(DeviceTensor< 2, real_t > &y, const DeviceTensor< 3, real_t > &f, const output_t &output, const DofToQuadMap &dtq)
Definition integrate.hpp:20
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
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
T sq(T x)
DofToQuadMap struct.
Definition util.hpp:1475
DeviceTensor< 3, const real_t > G
Gradient of the basis functions evaluated at quadrature points.
Definition util.hpp:1492
DeviceTensor< 3, const real_t > B
Basis functions evaluated at quadrature points.
Definition util.hpp:1487