PstreamReduceOps.H
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2016-2025 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 InNamespace
28  Foam
29 
30 Description
31  Inter-processor communication reduction functions.
32 
33 \*---------------------------------------------------------------------------*/
34 
35 #ifndef Foam_PstreamReduceOps_H
36 #define Foam_PstreamReduceOps_H
37 
38 #include "Pstream.H"
39 #include "FixedList.H"
40 #include "ops.H"
41 #include "VectorSpaceOps.H"
42 
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47 
48 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 
50 // Single value: mpiAllReduce or manual
51 
52 //- Reduce inplace (cf. MPI Allreduce)
53 template<class T, class BinaryOp>
54 void reduce
55 (
56  T& value,
57  [[maybe_unused]] BinaryOp bop,
58  [[maybe_unused]] const int tag = UPstream::msgType(),
59  const int communicator = UPstream::worldComm
60 )
61 {
62  if (!UPstream::is_parallel(communicator))
63  {
64  // Nothing to do
65  return;
66  }
68  {
69  // Valid opcode and (directly/indirectly) uses basic dataType
71  (
72  &value,
73  1,
75  communicator
76  );
77  }
78  else
79  {
80  if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm)
81  {
82  Perr<< "** reducing:" << value << " comm:" << communicator << endl;
84  }
85  Pstream::gather(value, bop, tag, communicator);
86  Pstream::broadcast(value, communicator);
87  }
88 }
89 
90 
91 // Multiple values: mpiAllReduce only!
92 
93 //- Reduce inplace (cf. MPI Allreduce)
94 //- multiple values (same size on all ranks!)
95 template<class T, class BinaryOp>
96 void reduce
97 (
98  T values[],
99  const int count,
100  [[maybe_unused]] BinaryOp bop,
101  [[maybe_unused]] const int tag,
102  const int communicator = UPstream::worldComm
103 )
104 {
105  if (!UPstream::is_parallel(communicator))
106  {
107  // Nothing to do
108  return;
109  }
110  else if constexpr (UPstream_data_opType<BinaryOp, T>::value)
111  {
112  // Valid opcode and (directly/indirectly) uses basic dataType
114  (
115  values,
116  count,
118  communicator
119  );
120  }
121  else
122  {
123  // static_assert(false, "unsupported data type");
124  static_assert
125  (
126  stdFoam::dependent_false_v<T>,
127  "only for specific, contiguous, known data types"
128  );
129  }
130 }
131 
132 
133 //- Reduce multiple values
134 // Multiple values: mpiAllReduce only!
135 template<class T, unsigned N, class BinaryOp>
136 inline void reduce
137 (
139  BinaryOp bop,
140  const int tag = UPstream::msgType(),
141  const int communicator = UPstream::worldComm
142 )
143 {
144  reduce(values.data(), int(values.size()), bop, tag, communicator);
145 }
146 
147 
148 //- Non-blocking reduce inplace (cf. MPI Iallreduce)
149 //- multiple values. Sets request.
150 template<class T, class BinaryOp>
151 void reduce
152 (
153  T values[],
154  int count,
155  [[maybe_unused]] BinaryOp bop,
156  [[maybe_unused]] const int tag,
157  const int communicator,
158  UPstream::Request& req
159 )
160 {
161  if (!UPstream::is_parallel(communicator))
162  {
163  // Nothing to do
164  return;
165  }
166  else if constexpr (UPstream_data_opType<BinaryOp, T>::value)
167  {
168  // Valid opcode and (directly/indirectly) uses basic dataType
170  (
171  values,
172  count,
174  communicator,
175  req
176  );
177  }
178  else
179  {
180  // static_assert(false, "unsupported data type");
181  static_assert
182  (
183  stdFoam::dependent_false_v<T>,
184  "only for specific, contiguous, known data types"
185  );
186  }
187 }
188 
189 
190 //- Non-blocking reduce inplace (cf. MPI Iallreduce)
191 //- single value. Sets request.
192 template<class T, class BinaryOp>
193 void reduce
194 (
195  T& value,
196  BinaryOp bop,
197  const int tag,
198  const int communicator,
200 )
201 {
202  // single value
203  reduce(&value, 1, tag, communicator, req);
204 }
205 
206 
207 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
208 
209 // Special reductions for bool
210 
211 //- Logical (and) inplace reduction. Uses UPstream::reduceAnd
212 void reduce
213 (
214  bool& value,
216  [[maybe_unused]] const int tag = UPstream::msgType(),
217  const int communicator = UPstream::worldComm
218 );
219 // UPstream::reduceAnd(value, communicator);
220 
221 
222 //- Logical (or) inplace reduction. Uses UPstream::reduceOr
223 void reduce
224 (
225  bool& value,
227  [[maybe_unused]] const int tag = UPstream::msgType(),
228  const int communicator = UPstream::worldComm
229 );
230 // UPstream::reduceOr(value, communicator);
231 
232 
233 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
234 
235 //- Reduce inplace (cf. MPI Allreduce)
236 //- the sum of value and counter (eg, for averaging)
237 // \note the summed counter value may lose some precision if components
238 // of the main value are narrower. This is usually not the case.
239 template<class T, class CountType = int>
240 void sumReduce
241 (
243  T& value,
245  CountType& count,
246  [[maybe_unused]] const int tag = UPstream::msgType(),
247  const int communicator = UPstream::worldComm
248 )
249 {
250  static_assert(std::is_arithmetic_v<CountType>, "Counter not arithmetic");
251 
252  if (!UPstream::is_parallel(communicator))
253  {
254  // Nothing to do
255  return;
256  }
257  else if constexpr (std::is_floating_point_v<T>)
258  {
259  // Bundle value and count together
260  T work[2];
261  work[0] = value;
262  work[1] = static_cast<T>(count);
263 
265  (
266  work,
267  2,
269  communicator
270  );
271 
272  // Unbundle
273  value = work[0];
274  count = static_cast<CountType>(work[1]);
275  }
276  else if constexpr
277  (
278  is_vectorspace_v<T>
279  && std::is_floating_point_v<typename pTraits_cmptType<T>::type>
280  )
281  {
282  constexpr auto nCmpts = pTraits_nComponents<T>::value;
283  using cmpt = typename pTraits_cmptType<T>::type;
284 
285  // Bundle all components and count together
286  cmpt work[nCmpts+1];
287  VectorSpaceOps<nCmpts>::copy_n(value.begin(), work);
288  work[nCmpts] = static_cast<cmpt>(count);
289 
291  (
292  work,
293  nCmpts+1,
295  communicator
296  );
297 
298  // Unbundle
299  VectorSpaceOps<nCmpts>::copy_n(work, value.begin());
300  count = static_cast<CountType>(work[nCmpts]);
301  }
302  else
303  {
304  Foam::reduce(value, sumOp<T>(), tag, communicator);
305  Foam::reduce(count, sumOp<CountType>(), tag, communicator);
306  }
307 }
308 
309 
310 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
311 
312 // Convenience wrappers - defined after all specialisations are known
313 
314 //- Perform reduction on a copy, using specified binary operation
315 // \return the resulting value
316 template<class T, class BinaryOp>
318 (
319  const T& value,
320  BinaryOp bop,
321  const int tag = UPstream::msgType(),
322  const int communicator = UPstream::worldComm
323 )
324 {
325  T work(value);
326  Foam::reduce(work, bop, tag, communicator);
327  return work;
328 }
329 
330 
331 //- Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd
332 // \return the resulting value
333 inline bool returnReduceAnd
334 (
335  const bool value,
336  const int communicator = UPstream::worldComm
337 )
338 {
339  bool work(value);
340  UPstream::reduceAnd(work, communicator);
341  return work;
342 }
343 
344 
345 //- Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr
346 // \return the resulting value
347 inline bool returnReduceOr
348 (
349  const bool value,
350  const int communicator = UPstream::worldComm
351 )
352 {
353  bool work(value);
354  UPstream::reduceOr(work, communicator);
355  return work;
356 }
357 
358 
359 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
360 
361 } // End namespace Foam
362 
363 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
364 
365 #endif
366 
367 // ************************************************************************* //
prefixOSstream Perr
OSstream wrapped stderr (std::cerr) with parallel prefix.
Combined query of opType and the underlying basic data type.
A 1D vector of objects of type <T> with a fixed length <N>.
Definition: HashTable.H:107
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
Various functors for unary and binary operations. Can be used for parallel combine-reduce operations ...
static void copy_n(Input input, Output result)
Somewhat equivalent to std::copy_n() but with templated loops.
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1787
static void broadcast(Type &value, const int communicator=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:987
A supported UPstream (MPI) reduce/window operation type.
void reduce(T &value, [[maybe_unused]] BinaryOp bop, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce)
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
An opaque wrapper for MPI_Request with a vendor-independent representation without any <mpi...
Definition: UPstream.H:2599
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
T returnReduce(const T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
static bool is_parallel(const label communicator=worldComm)
True if parallel algorithm or exchange is required.
Definition: UPstream.H:1648
static label warnComm
Debugging: warn for use of any communicator differing from warnComm.
Definition: UPstream.H:992
bool returnReduceOr(const bool value, const int communicator=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
static void reduceAnd(bool &value, const int communicator=worldComm)
Logical (and) reduction (MPI_AllReduce)
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
void sumReduce(T &value, CountType &count, [[maybe_unused]] const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) the sum of value and counter (eg, for averaging) ...
static void printStack(Ostream &os, int size=-1)
Helper function to print a stack, with optional upper limit.
static void gather(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Gather (reduce) data, applying bop to combine value from different processors. The basis for Foam::re...
static void reduceOr(bool &value, const int communicator=worldComm)
Logical (or) reduction (MPI_AllReduce)
Namespace for OpenFOAM.
static void mpiAllReduce(T values[], int count, const UPstream::opCodes opCodeId, const int communicator)
MPI_Allreduce (blocking) for known operators.