PstreamGlobals.C
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) 2013-2015 OpenFOAM Foundation
9  Copyright (C) 2023-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 \*---------------------------------------------------------------------------*/
28 
29 #include "PstreamGlobals.H"
30 
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 
36 
39 
41 Foam::PstreamGlobals::MPIdataTypes_(MPI_DATATYPE_NULL);
42 
45 
46 
47 // * * * * * * * * * * * * * * * Communicators * * * * * * * * * * * * * * * //
48 
49 void Foam::PstreamGlobals::initCommunicator(const label index)
50 {
51  if (FOAM_UNLIKELY(index < 0 || index > MPICommunicators_.size()))
52  {
54  << "PstreamGlobals out of sync with UPstream data. Problem."
56  }
57  else if (index == MPICommunicators_.size())
58  {
59  // Extend storage with null values
61  MPICommunicators_.emplace_back(MPI_COMM_NULL);
62  }
63  else
64  {
65  // Init with null values
66  pendingMPIFree_[index] = false;
67  MPICommunicators_[index] = MPI_COMM_NULL;
68  }
69 }
70 
71 
72 // * * * * * * * * * * * * * * * * Data Types * * * * * * * * * * * * * * * //
73 
75 {
76  static_assert
77  (
78  PstreamGlobals::DataTypeCountLookupTable::max_size()
79  == (int(UPstream::dataTypes::DataTypes_end)+1),
80  "Data count lookup table size != number of dataTypes enumerations"
81  );
82  static_assert
83  (
84  PstreamGlobals::DataTypeLookupTable::max_size()
85  == (int(UPstream::dataTypes::DataTypes_end)+1),
86  "Lookup table size != number of dataTypes enumerations"
87  );
88 
89  // From enumeration to MPI datatype for fundamental types
90  // (count is always 1)
91  #undef defineType
92  #define defineType(Idx, BaseType) \
93  { \
94  dataTypesCount_[int(UPstream::dataTypes::Idx)] = 1; \
95  MPIdataTypes_[int(UPstream::dataTypes::Idx)] = BaseType; \
96  }
97 
98  // Fundamental Types [10]:
99  defineType(type_byte, MPI_BYTE);
100  defineType(type_int16, MPI_INT16_T);
101  defineType(type_int32, MPI_INT32_T);
102  defineType(type_int64, MPI_INT64_T);
103  defineType(type_uint16, MPI_UINT16_T);
104  defineType(type_uint32, MPI_UINT32_T);
105  defineType(type_uint64, MPI_UINT64_T);
106  defineType(type_float, MPI_FLOAT);
107  defineType(type_double, MPI_DOUBLE);
108  defineType(type_long_double, MPI_LONG_DOUBLE);
109 
110  #undef defineType
111 
112  // User-define types
113  #undef defineUserType
114  #define defineUserType(Idx, Count, BaseType, Name) \
115  { \
116  dataTypesCount_[int(UPstream::dataTypes::Idx)] = Count; \
117  auto& dt = MPIdataTypes_[int(UPstream::dataTypes::Idx)]; \
118  MPI_Type_contiguous(Count, BaseType, &dt); \
119  MPI_Type_set_name(dt, Name); \
120  MPI_Type_commit(&dt); \
121  }
122 
123  // User Types [6]:
124  defineUserType(type_3float, 3, MPI_FLOAT, "float[3]");
125  defineUserType(type_3double, 3, MPI_DOUBLE, "double[3]");
126  defineUserType(type_6float, 6, MPI_FLOAT, "float[6]");
127  defineUserType(type_6double, 6, MPI_DOUBLE, "double[6]");
128  defineUserType(type_9float, 9, MPI_FLOAT, "float[9]");
129  defineUserType(type_9double, 9, MPI_DOUBLE, "double[9]");
130 
131  #undef defineUserType
132 }
133 
134 
136 {
137  // User types only
138  auto first =
139  (
140  MPIdataTypes_.begin() + int(UPstream::dataTypes::User_begin)
141  );
142  const auto last =
143  (
144  MPIdataTypes_.begin() + int(UPstream::dataTypes::User_end)
145  );
146 
147  for (; first != last; ++first)
148  {
149  if (MPI_DATATYPE_NULL != *first)
150  {
151  MPI_Type_free(&(*first));
152  }
153  }
154 }
155 
156 
157 // Debugging
159 {
160  // Check all types, not just user types
161  auto first =
162  (
164  );
165  const auto last =
166  (
167  MPIdataTypes_.begin() + int(UPstream::dataTypes::DataTypes_end)
168  );
169 
170  for (; (first != last); ++first)
171  {
172  if (MPI_DATATYPE_NULL == *first)
173  {
174  return false;
175  }
176  }
177 
178  return true;
179 }
180 
181 
182 // Debugging
184 {
185  int rank = -1;
186  if
187  (
188  (MPI_SUCCESS != MPI_Comm_rank(MPI_COMM_WORLD, &rank))
189  || (rank != 0)
190  )
191  {
192  return;
193  }
194 
195  const auto print = [&](auto firstIndex, auto lastIndex)
196  {
197  auto first =
198  (
199  PstreamGlobals::MPIdataTypes_.begin() + int(firstIndex)
200  );
201  const auto last =
202  (
203  PstreamGlobals::MPIdataTypes_.begin() + int(lastIndex)
204  );
205 
206  for (; (first != last); ++first)
207  {
208  std::cerr
209  << " name = "
210  << PstreamGlobals::dataType_name(*first) << '\n';
211  }
212  };
213 
214  if (all)
215  {
216  std::cerr << "enumerated data types:\n";
217  print
218  (
219  UPstream::dataTypes::Basic_begin,
220  UPstream::dataTypes::Basic_end
221  );
222  }
223  else
224  {
225  // User types only.
226  std::cerr << "enumerated user-defined data types:\n";
227  }
228  print
229  (
230  UPstream::dataTypes::User_begin,
231  UPstream::dataTypes::User_end
232  );
233 }
234 
235 
236 std::string Foam::PstreamGlobals::dataType_name(MPI_Datatype datatype)
237 {
238  if (MPI_DATATYPE_NULL == datatype)
239  {
240  return std::string("(null)");
241  }
242 
243  char buf[MPI_MAX_OBJECT_NAME];
244  int len;
245 
246  if (MPI_SUCCESS == MPI_Type_get_name(datatype, buf, &len))
247  {
248  if (len > 0)
249  {
250  return std::string(buf, len);
251  }
252  else
253  {
254  return std::string("(anon)");
255  }
256  }
258  return std::string("???");
259 }
260 
261 
262 // * * * * * * * * * * * * * * * * Op Codes * * * * * * * * * * * * * * * * //
263 
265 {
266  static_assert
267  (
268  PstreamGlobals::OpCodesLookupTable::max_size()
269  == (int(UPstream::opCodes::OpCodes_end)+1),
270  "Lookup table size != number of opCodes enumerations"
271  );
272 
273  // From enumeration to MPI datatype
274  #undef defineCode
275  #define defineCode(Idx, CodeType) \
276  MPIopCodes_[int(UPstream::opCodes::Idx)] = CodeType;
277 
278  defineCode(op_min, MPI_MIN);
279  defineCode(op_max, MPI_MAX);
280  defineCode(op_sum, MPI_SUM);
281  defineCode(op_prod, MPI_PROD);
282 
283  // TBD: still need to sort out if they are MPI_C_BOOL or MPI_CXX_BOOL
284  // ...
285  defineCode(op_bool_and, MPI_LAND);
286  defineCode(op_bool_or, MPI_LOR);
287  defineCode(op_bool_xor, MPI_LXOR);
288 
289  defineCode(op_bit_and, MPI_BAND);
290  defineCode(op_bit_or, MPI_BOR);
291  defineCode(op_bit_xor, MPI_BXOR);
292 
293  // Do not include MPI_MINLOC, MPI_MAXLOC since they are tied to
294  // float_int, double_int and larger or other types
295 
296  // window-only
297  defineCode(op_replace, MPI_REPLACE);
298  defineCode(op_no_op, MPI_NO_OP);
299 
300  #undef defineCode
301 }
302 
303 
305 {}
306 
307 
309 {
310  auto first = MPIopCodes_.begin();
311  const auto last =
312  (
313  MPIopCodes_.begin() + int(UPstream::opCodes::OpCodes_end)
314  );
315 
316  for (; (first != last); ++first)
317  {
318  if (MPI_OP_NULL == *first)
319  {
320  return false;
321  }
322  }
323 
324  return true;
325 }
326 
327 
328 // ************************************************************************* //
#define defineCode(Idx, CodeType)
DynamicList< MPI_Request > outstandingRequests_
Outstanding non-blocking operations.
void deinitOpCodes()
Free any user-defined op codes.
A 1D vector of objects of type <T> with a fixed length <N>.
Definition: HashTable.H:107
iterator begin() noexcept
Return an iterator to begin traversing the FixedList.
Definition: FixedListI.H:473
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
Ostream & print(Ostream &os, UIntType value, char off='0', char on='1')
Print 0/1 bits in the (unsigned) integral type.
Definition: BitOps.H:323
DynamicList< MPI_Comm > MPICommunicators_
void initDataTypes()
Create mapping into MPIdataTypes_ and define user data types.
bool checkOpCodes()
Debugging only: check if op code mappings are non-null.
DynamicList< bool > pendingMPIFree_
#define defineType(Idx, BaseType)
void initOpCodes()
Create mapping into MPIopCodes_.
#define defineUserType(Idx, Count, BaseType, Name)
T & emplace_back(Args &&... args)
Construct an element at the end of the list, return reference to the new list element.
Definition: DynamicListI.H:541
#define FOAM_UNLIKELY(cond)
Definition: stdFoam.H:64
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void initCommunicator(const label index)
Initialize bookkeeping for MPI communicator index.
void printDataTypes(bool all=false)
Debugging only: print data type names (all or just user-defined)
void deinitDataTypes()
Free any user data types.
DataTypeCountLookupTable dataTypesCount_
Fundamental count for each valid UPstream::dataTypes entry Indexed by UPstream::dataTypes enum...
bool checkDataTypes()
Debugging only: check if data type mappings are non-null.
bool all(const UList< bool > &bools)
True if all entries are &#39;true&#39; or if the set is empty.
Definition: BitOps.H:83
::Foam::direction rank(const expressions::valueTypeCode) noexcept
The vector-space rank associated with given valueTypeCode.
Definition: exprTraits.C:70
OpCodesLookupTable MPIopCodes_
MPI operation types, indexed by UPstream::opCodes enum.
DataTypeLookupTable MPIdataTypes_
MPI data types corresponding to fundamental and OpenFOAM types. Indexed by UPstream::dataTypes enum...
std::string dataType_name(MPI_Datatype datatype)
Return MPI internal name for specified MPI_Datatype.