MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
integrate.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#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("quadrature data mapping to field is not implemented for"
94 " 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("quadrature data mapping to field is not implemented for"
173 " this field descriptor with sum factorization on tensor product elements");
174 }
175}
176
177template <typename output_t>
178MFEM_HOST_DEVICE
182 const output_t &output,
183 const DofToQuadMap &dtq,
184 std::array<DeviceTensor<1>, 6> &scratch_mem)
185{
186 [[maybe_unused]] auto B = dtq.B;
187 [[maybe_unused]] auto G = dtq.G;
188
189 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
190 {
191 const auto [q1d, unused, d1d] = B.GetShape();
192 const int vdim = output.vdim;
193 const int test_dim = output.size_on_qp / vdim;
194
195 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d);
196 auto yd = Reshape(&y(0, 0), d1d, d1d, vdim);
197
198 auto s0 = Reshape(&scratch_mem[0](0), q1d, d1d);
199
200 for (int vd = 0; vd < vdim; vd++)
201 {
202 MFEM_FOREACH_THREAD(qy, y, q1d)
203 {
204 MFEM_FOREACH_THREAD(dx, x, d1d)
205 {
206 real_t acc = 0.0;
207 for (int qx = 0; qx < q1d; qx++)
208 {
209 acc += fqp(vd, 0, qx, qy) * B(qx, 0, dx);
210 }
211 s0(qy, dx) = acc;
212 }
213 }
214 MFEM_SYNC_THREAD;
215
216 MFEM_FOREACH_THREAD(dy, y, d1d)
217 {
218 MFEM_FOREACH_THREAD(dx, x, d1d)
219 {
220 real_t acc = 0.0;
221 for (int qy = 0; qy < q1d; qy++)
222 {
223 acc += s0(qy, dx) * B(qy, 0, dy);
224 }
225 yd(dx, dy, vd) += acc;
226 }
227 }
228 MFEM_SYNC_THREAD;
229 }
230 }
231 else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
232 {
233 const auto [q1d, unused, d1d] = G.GetShape();
234 const int vdim = output.vdim;
235 const int test_dim = output.size_on_qp / vdim;
236 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d);
237 auto yd = Reshape(&y(0, 0), d1d, d1d, vdim);
238
239 auto s0 = Reshape(&scratch_mem[0](0), q1d, d1d);
240 auto s1 = Reshape(&scratch_mem[1](0), q1d, d1d);
241
242 for (int vd = 0; vd < vdim; vd++)
243 {
244 MFEM_FOREACH_THREAD(qy, y, q1d)
245 {
246 MFEM_FOREACH_THREAD(dx, x, d1d)
247 {
248 real_t uv[2] = {0.0, 0.0};
249 for (int qx = 0; qx < q1d; qx++)
250 {
251 uv[0] += fqp(vd, 0, qx, qy) * G(qx, 0, dx);
252 uv[1] += fqp(vd, 1, qx, qy) * B(qx, 0, dx);
253 }
254 s0(qy, dx) = uv[0];
255 s1(qy, dx) = uv[1];
256 }
257 }
258 MFEM_SYNC_THREAD;
259
260 MFEM_FOREACH_THREAD(dy, y, d1d)
261 {
262 MFEM_FOREACH_THREAD(dx, x, d1d)
263 {
264 real_t uv[2] = {0.0, 0.0};
265 for (int qy = 0; qy < q1d; qy++)
266 {
267 uv[0] += s0(qy, dx) * B(qy, 0, dy);
268 uv[1] += s1(qy, dx) * G(qy, 0, dy);
269 }
270 yd(dx, dy, vd) += uv[0] + uv[1];
271 }
272 }
273 MFEM_SYNC_THREAD;
274 }
275 }
276 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
277 {
278 const auto [q1d, unused, d1d] = B.GetShape();
279
280 // // TODO: Check if this is the right fix for all cases
281 // auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d);
282 // auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d);
283 // for (int sq = 0; sq < output.size_on_qp; sq++)
284 // {
285 // MFEM_FOREACH_THREAD(qx, x, q1d)
286 // {
287 // yqp(sq, qx) = fqp(sq, qx);
288 // }
289 // MFEM_SYNC_THREAD;
290 // }
291
292 auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d, q1d);
293 auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d, q1d);
294
295 for (int sq = 0; sq < output.size_on_qp; sq++)
296 {
297 MFEM_FOREACH_THREAD(qx, x, q1d)
298 {
299 MFEM_FOREACH_THREAD(qy, y, q1d)
300 {
301 yqp(sq, qx, qy) = fqp(sq, qx, qy);
302 }
303 }
304 MFEM_SYNC_THREAD;
305 }
306 }
307 else
308 {
309 MFEM_ABORT("quadrature data mapping to field is not implemented for"
310 " this field descriptor with sum factorization on tensor product elements");
311 }
312}
313
314template <typename output_t>
315MFEM_HOST_DEVICE
319 const output_t &output,
320 const DofToQuadMap &dtq,
321 std::array<DeviceTensor<1>, 6> &scratch_mem)
322{
323 [[maybe_unused]] auto B = dtq.B;
324 [[maybe_unused]] auto G = dtq.G;
325
326 if constexpr (is_value_fop<std::decay_t<output_t>>::value)
327 {
328 const auto [q1d, unused, d1d] = B.GetShape();
329 const int vdim = output.vdim;
330 const int test_dim = output.size_on_qp / vdim;
331
332 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
333 auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
334
335 auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
336 auto s1 = Reshape(&scratch_mem[1](0), q1d, d1d, d1d);
337
338 for (int vd = 0; vd < vdim; vd++)
339 {
340 MFEM_FOREACH_THREAD(qy, y, q1d)
341 {
342 MFEM_FOREACH_THREAD(dx, x, d1d)
343 {
344 MFEM_FOREACH_THREAD(qz, z, q1d)
345 {
346 real_t acc = 0.0;
347 for (int qx = 0; qx < q1d; qx++)
348 {
349 acc += fqp(vd, 0, qx, qy, qz) * B(qx, 0, dx);
350 }
351 s0(qz, qy, dx) = acc;
352 }
353 }
354 }
355 MFEM_SYNC_THREAD;
356
357 MFEM_FOREACH_THREAD(dy, y, d1d)
358 {
359 MFEM_FOREACH_THREAD(dx, x, d1d)
360 {
361 MFEM_FOREACH_THREAD(qz, z, q1d)
362 {
363 real_t acc = 0.0;
364 for (int qy = 0; qy < q1d; qy++)
365 {
366 acc += s0(qz, qy, dx) * B(qy, 0, dy);
367 }
368 s1(qz, dy, dx) = acc;
369 }
370 }
371 }
372 MFEM_SYNC_THREAD;
373
374
375 MFEM_FOREACH_THREAD(dy, y, d1d)
376 {
377 MFEM_FOREACH_THREAD(dx, x, d1d)
378 {
379 MFEM_FOREACH_THREAD(dz, z, d1d)
380 {
381 real_t acc = 0.0;
382 for (int qz = 0; qz < q1d; qz++)
383 {
384 acc += s1(qz, dy, dx) * B(qz, 0, dz);
385 }
386 yd(dx, dy, dz, vd) += acc;
387 }
388 }
389 }
390 MFEM_SYNC_THREAD;
391 }
392 }
393 else if constexpr (is_gradient_fop<std::decay_t<output_t>>::value)
394 {
395 const auto [q1d, unused, d1d] = G.GetShape();
396 const int vdim = output.vdim;
397 const int test_dim = output.size_on_qp / vdim;
398 auto fqp = Reshape(&f(0, 0, 0), vdim, test_dim, q1d, q1d, q1d);
399 auto yd = Reshape(&y(0, 0), d1d, d1d, d1d, vdim);
400
401 auto s0 = Reshape(&scratch_mem[0](0), q1d, q1d, d1d);
402 auto s1 = Reshape(&scratch_mem[1](0), q1d, q1d, d1d);
403 auto s2 = Reshape(&scratch_mem[2](0), q1d, q1d, d1d);
404 auto s3 = Reshape(&scratch_mem[3](0), q1d, d1d, d1d);
405 auto s4 = Reshape(&scratch_mem[4](0), q1d, d1d, d1d);
406 auto s5 = Reshape(&scratch_mem[5](0), q1d, d1d, d1d);
407
408 for (int vd = 0; vd < vdim; vd++)
409 {
410 MFEM_FOREACH_THREAD(qz, z, q1d)
411 {
412 MFEM_FOREACH_THREAD(qy, y, q1d)
413 {
414 MFEM_FOREACH_THREAD(dx, x, d1d)
415 {
416 real_t uvw[3] = {0.0, 0.0, 0.0};
417 for (int qx = 0; qx < q1d; qx++)
418 {
419 uvw[0] += fqp(vd, 0, qx, qy, qz) * G(qx, 0, dx);
420 uvw[1] += fqp(vd, 1, qx, qy, qz) * B(qx, 0, dx);
421 uvw[2] += fqp(vd, 2, qx, qy, qz) * B(qx, 0, dx);
422 }
423 s0(qz, qy, dx) = uvw[0];
424 s1(qz, qy, dx) = uvw[1];
425 s2(qz, qy, dx) = uvw[2];
426 }
427 }
428 }
429 MFEM_SYNC_THREAD;
430
431 MFEM_FOREACH_THREAD(qz, z, q1d)
432 {
433 MFEM_FOREACH_THREAD(dy, y, d1d)
434 {
435 MFEM_FOREACH_THREAD(dx, x, d1d)
436 {
437 real_t uvw[3] = {0.0, 0.0, 0.0};
438 for (int qy = 0; qy < q1d; qy++)
439 {
440 uvw[0] += s0(qz, qy, dx) * B(qy, 0, dy);
441 uvw[1] += s1(qz, qy, dx) * G(qy, 0, dy);
442 uvw[2] += s2(qz, qy, dx) * B(qy, 0, dy);
443 }
444 s3(qz, dy, dx) = uvw[0];
445 s4(qz, dy, dx) = uvw[1];
446 s5(qz, dy, dx) = uvw[2];
447 }
448 }
449 }
450 MFEM_SYNC_THREAD;
451
452 MFEM_FOREACH_THREAD(dz, z, d1d)
453 {
454 MFEM_FOREACH_THREAD(dy, y, d1d)
455 {
456 MFEM_FOREACH_THREAD(dx, x, d1d)
457 {
458 real_t uvw[3] = {0.0, 0.0, 0.0};
459 for (int qz = 0; qz < q1d; qz++)
460 {
461 uvw[0] += s3(qz, dy, dx) * B(qz, 0, dz);
462 uvw[1] += s4(qz, dy, dx) * B(qz, 0, dz);
463 uvw[2] += s5(qz, dy, dx) * G(qz, 0, dz);
464 }
465 yd(dx, dy, dz, vd) += uvw[0] + uvw[1] + uvw[2];
466 }
467 }
468 }
469 MFEM_SYNC_THREAD;
470 }
471 }
472 else if constexpr (is_identity_fop<std::decay_t<output_t>>::value)
473 {
474 const auto [q1d, unused, d1d] = B.GetShape();
475 auto fqp = Reshape(&f(0, 0, 0), output.size_on_qp, q1d, q1d, q1d);
476 auto yqp = Reshape(&y(0, 0), output.size_on_qp, q1d, q1d, q1d);
477
478 for (int sq = 0; sq < output.size_on_qp; sq++)
479 {
480 MFEM_FOREACH_THREAD(qx, x, q1d)
481 {
482 MFEM_FOREACH_THREAD(qy, y, q1d)
483 {
484 MFEM_FOREACH_THREAD(qz, z, q1d)
485 {
486 yqp(sq, qx, qy, qz) = fqp(sq, qx, qy, qz);
487 }
488 }
489 }
490 MFEM_SYNC_THREAD;
491 }
492 }
493 else
494 {
495 MFEM_ABORT("quadrature data mapping to field is not implemented for"
496 " this field descriptor with sum factorization on tensor product elements");
497 }
498}
499
500template <typename output_t>
501MFEM_HOST_DEVICE
505 const output_t &output,
506 const DofToQuadMap &dtq,
507 std::array<DeviceTensor<1>, 6> &scratch_mem,
508 const int &dimension,
509 const bool &use_sum_factorization)
510{
511 if (use_sum_factorization)
512 {
513 if (dimension == 1)
514 {
515 map_quadrature_data_to_fields_tensor_impl_1d(y, f, output, dtq, scratch_mem);
516 }
517 else if (dimension == 2)
518 {
519 map_quadrature_data_to_fields_tensor_impl_2d(y, f, output, dtq, scratch_mem);
520 }
521 else if (dimension == 3)
522 {
523 map_quadrature_data_to_fields_tensor_impl_3d(y, f, output, dtq, scratch_mem);
524 }
525 else { MFEM_ABORT_KERNEL("dimension not supported"); }
526 }
527 else
528 {
529 map_quadrature_data_to_fields_impl(y, f, output, dtq);
530 }
531}
532
533} // 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:1518
DeviceTensor< 3, const real_t > G
Gradient of the basis functions evaluated at quadrature points.
Definition util.hpp:1535
DeviceTensor< 3, const real_t > B
Basis functions evaluated at quadrature points.
Definition util.hpp:1530