MFEM v4.8.0
Finite element discretization library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
reducers.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_REDUCERS_HPP
13#define MFEM_REDUCERS_HPP
14
15#include "forall.hpp"
16
17#include <climits>
18#include <cmath>
19#include <cstdint>
20#include <limits>
21#include <type_traits>
22
23namespace mfem
24{
25
26/// Pair of values which can be used in device code
27template <class A, class B> struct DevicePair
28{
31};
32
33/// Two pairs for the min/max values and their location indices
34template <class A, class B> struct MinMaxLocScalar
35{
40};
41
42/// @brief a += b
43template <class T> struct SumReducer
44{
45 using value_type = T;
46 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
47 {
48 a += b;
49 }
50
51 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a) { a = T(0); }
52};
53
54/// @brief a *= b
55template <class T> struct MultReducer
56{
57 using value_type = T;
58 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
59 {
60 a *= b;
61 }
62
63 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a) { a = T(1); }
64};
65
66/// @brief a &= b
67template <class T> struct BAndReducer
68{
69 static_assert(std::is_integral<T>::value, "Only works for integral types");
70 using value_type = T;
71 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
72 {
73 a &= b;
74 }
75
76 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
77 {
78 // sets all bits, does not work for floating point types
79 // bitwise operators are not defined for floating point types anyways
80 a = ~T(0);
81 }
82};
83
84/// @brief a |= b
85template <class T> struct BOrReducer
86{
87 static_assert(std::is_integral<T>::value, "Only works for integral types");
88 using value_type = T;
89 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
90 {
91 a |= b;
92 }
93
94 static MFEM_HOST_DEVICE void SetInitialValue(T &a) { a = T(0); }
95};
96
97/// @brief a = min(a,b)
98template <class T> struct MinReducer
99{
100 using value_type = T;
101
102 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
103 {
104 if (b < a)
105 {
106 a = b;
107 }
108 }
109
110 // If we use std::numeric_limits<T>::max() in host-device method, Cuda
111 // complains about calling host-only constexpr functions in device code
112 // without --expt-relaxed-constexpr, so we define the following constant as a
113 // workaround for the Cuda warning.
114 static constexpr T max_val = std::numeric_limits<T>::max();
115
116 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
117 {
118 a = max_val;
119 }
120};
121
122template <> struct MinReducer<float>
123{
124 using value_type = float;
125 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
126 {
127 a = fmin(a, b);
128 }
129
130 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a) { a = HUGE_VALF; }
131};
132
133template <> struct MinReducer<double>
134{
135 using value_type = double;
136 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
137 {
138 a = fmin(a, b);
139 }
140
141 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a) { a = HUGE_VAL; }
142};
143
144/// @brief a = max(a,b)
145template <class T> struct MaxReducer
146{
147 using value_type = T;
148 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
149 {
150 if (a < b)
151 {
152 a = b;
153 }
154 }
155
156 // If we use std::numeric_limits<T>::min() in host-device method, Cuda
157 // complains about calling host-only constexpr functions in device code
158 // without --expt-relaxed-constexpr, so we define the following constant as a
159 // workaround for the Cuda warning.
160 static constexpr T min_val = std::numeric_limits<T>::min();
161
162 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
163 {
164 a = min_val;
165 }
166};
167
168template <> struct MaxReducer<float>
169{
170 using value_type = float;
171 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
172 {
173 a = fmax(a, b);
174 }
175
176 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
177 {
178 a = -HUGE_VALF;
179 }
180};
181
182template <> struct MaxReducer<double>
183{
184 using value_type = double;
185 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
186 {
187 a = fmax(a, b);
188 }
189
190 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a) { a = -HUGE_VAL; }
191};
192
193/// @brief a = minmax(a,b)
194template <class T> struct MinMaxReducer
195{
197 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
198 {
199 if (b.first < a.first)
200 {
201 a.first = b.first;
202 }
203 if (b.second > a.second)
204 {
205 a.second = b.second;
206 }
207 }
208
209 // If we use std::numeric_limits<T>::min() (or max()) in host-device method,
210 // Cuda complains about calling host-only constexpr functions in device code
211 // without --expt-relaxed-constexpr, so we define the following constants as
212 // a workaround for the Cuda warning.
213 static constexpr T min_val = std::numeric_limits<T>::min();
214 static constexpr T max_val = std::numeric_limits<T>::max();
215
216 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
217 {
219 }
220};
221
222template <> struct MinMaxReducer<float>
223{
225 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
226 {
227 a.first = fmin(a.first, b.first);
228 a.second = fmax(a.second, b.second);
229 }
230
231 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
232 {
233 a = value_type{HUGE_VALF, -HUGE_VALF};
234 }
235};
236
237template <> struct MinMaxReducer<double>
238{
240 static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
241 {
242 a.first = fmin(a.first, b.first);
243 a.second = fmax(a.second, b.second);
244 }
245
246 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
247 {
248 a = value_type{HUGE_VAL, -HUGE_VAL};
249 }
250};
251
252/// @brief i = argmin(a[i], a[j])
253///
254/// Note: for ties the returned index can correspond to any min entry, not
255/// necesarily the first one
256template <class T, class I> struct ArgMinReducer
257{
259 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
260 {
261 if (b.first <= a.first)
262 {
263 a = b;
264 }
265 }
266 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
267 {
268 // Cuda complains about calling host-only constexpr functions in device
269 // code without --expt-relaxed-constexpr, wrap into integral_constant to
270 // get around this
271 a = value_type
272 {
273 std::integral_constant<T, std::numeric_limits<T>::max()>::value, I{0}};
274 }
275};
276
277template <class I> struct ArgMinReducer<float, I>
278{
280 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
281 {
282 if (b.first <= a.first)
283 {
284 a = b;
285 }
286 }
287 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
288 {
289 a = value_type{HUGE_VALF, I{0}};
290 }
291};
292
293template <class I> struct ArgMinReducer<double, I>
294{
296 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
297 {
298 if (b.first <= a.first)
299 {
300 a = b;
301 }
302 }
303 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
304 {
305 a = value_type{HUGE_VAL, I{0}};
306 }
307};
308
309/// @brief i = argmax(a[i], a[j])
310///
311/// Note: for ties the returned index can correspond to any min entry, not
312/// necesarily the first one.
313template <class T, class I> struct ArgMaxReducer
314{
316 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
317 {
318 if (a.first <= b.first)
319 {
320 a = b;
321 }
322 }
323 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
324 {
325 // Cuda complains about calling host-only constexpr functions in device
326 // code without --expt-relaxed-constexpr, wrap into integral_constant to
327 // get around this
328 a = value_type
329 {
330 std::integral_constant<T, std::numeric_limits<T>::max()>::value, I{0}};
331 }
332};
333
334template <class I> struct ArgMaxReducer<float, I>
335{
337 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
338 {
339 if (a.first <= b.first)
340 {
341 a = b;
342 }
343 }
344 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
345 {
346 a = value_type{-HUGE_VALF, I{0}};
347 }
348};
349
350template <class I> struct ArgMaxReducer<double, I>
351{
353 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
354 {
355 if (a.first <= b.first)
356 {
357 a = b;
358 }
359 }
360 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
361 {
362 a = value_type{-HUGE_VAL, I{0}};
363 }
364};
365
366template <class T, class I> struct ArgMinMaxReducer
367{
369 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
370 {
371 if (b.min_val <= a.min_val)
372 {
373 a.min_val = b.min_val;
374 a.min_loc = b.min_loc;
375 }
376 if (b.max_val >= a.max_val)
377 {
378 a.max_val = b.max_val;
379 a.max_loc = b.max_loc;
380 }
381 }
382
383 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
384 {
385 // Cuda complains about calling host-only constexpr functions in device
386 // code without --expt-relaxed-constexpr, wrap into integral_constant to
387 // get around this
388 a = value_type
389 {
390 std::integral_constant<T, std::numeric_limits<T>::max()>::value,
391 std::integral_constant<T, std::numeric_limits<T>::min()>::value, I(0),
392 I(0)};
393 }
394};
395
396template <class I> struct ArgMinMaxReducer<float, I>
397{
399 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
400 {
401 if (b.min_val <= a.min_val)
402 {
403 a.min_val = b.min_val;
404 a.min_loc = b.min_loc;
405 }
406 if (b.max_val >= a.max_val)
407 {
408 a.max_val = b.max_val;
409 a.max_loc = b.max_loc;
410 }
411 }
412
413 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
414 {
415 a = value_type{HUGE_VALF, -HUGE_VALF, I(0), I(0)};
416 }
417};
418
419template <class I> struct ArgMinMaxReducer<double, I>
420{
422 static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
423 {
424 if (b.min_val <= a.min_val)
425 {
426 a.min_val = b.min_val;
427 a.min_loc = b.min_loc;
428 }
429 if (b.max_val >= a.max_val)
430 {
431 a.max_val = b.max_val;
432 a.max_loc = b.max_loc;
433 }
434 }
435
436 static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
437 {
438 a = value_type{HUGE_VAL, -HUGE_VAL, I(0), I(0)};
439 }
440};
441
442} // namespace mfem
443
444#endif
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:360
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:353
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:337
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:344
i = argmax(a[i], a[j])
Definition reducers.hpp:314
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:316
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:323
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:422
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:436
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:399
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:413
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:383
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:369
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:296
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:303
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:287
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:280
i = argmin(a[i], a[j])
Definition reducers.hpp:257
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:266
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:259
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:71
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:76
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:89
static MFEM_HOST_DEVICE void SetInitialValue(T &a)
Definition reducers.hpp:94
Pair of values which can be used in device code.
Definition reducers.hpp:28
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:185
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:190
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:171
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:176
a = max(a,b)
Definition reducers.hpp:146
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:148
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:162
static constexpr T min_val
Definition reducers.hpp:160
Two pairs for the min/max values and their location indices.
Definition reducers.hpp:35
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:246
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:240
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:225
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:231
a = minmax(a,b)
Definition reducers.hpp:195
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:197
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:216
static constexpr T max_val
Definition reducers.hpp:214
static constexpr T min_val
Definition reducers.hpp:213
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:136
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:141
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:125
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:130
a = min(a,b)
Definition reducers.hpp:99
static MFEM_HOST_DEVICE void Join(value_type &a, value_type b)
Definition reducers.hpp:102
static constexpr T max_val
Definition reducers.hpp:114
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:116
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:63
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:58
static MFEM_HOST_DEVICE void Join(value_type &a, const value_type &b)
Definition reducers.hpp:46
static MFEM_HOST_DEVICE void SetInitialValue(value_type &a)
Definition reducers.hpp:51