UPstreamTraits.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) 2025 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 Description
27  A set of traits associated with UPstream communication
28 
29  \par Front-facing traits
30 
31  - \c UPstream_basic_dataType trait :<br>
32  The main entry point for reduction operations
33  (requires fundamental types).<br>
34  Checks against fundamental/aliased (excludes user-defined),
35  or is a component-wise aggregate of the same.
36 
37  - \c UPstream_dataType trait :<br>
38  The main entry point for transmission (broadcast, send/recv, ...).<br>
39  Checks against fundamental/aliased/user-defined,
40  or is a component-wise aggregate of the same.
41 
42  - \c UPstream_opType trait :<br>
43  Mapping of OpenFOAM ops to their MPI equivalent.
44  The \c opcode_id is the corresponding internal representation.
45 
46  - \c UPstream_data_opType trait :<br>
47  Combination of UPstream_opType and UPstream_basic_dataType.
48  .
49 
50  \par Additional helper traits (not normally used directly):
51 
52  - \c UPstream_mpi_dataType trait :<br>
53  Tests true and provides valid \c datatype_id for MPI fundamental
54  data types. This trait will should not normally be used directly:
55  use UPstream_alias_dataType for 'low-level' purposes (see below).
56 
57  - \c UPstream_user_dataType trait :<br>
58  Tests true and provides valid \c datatype_id for user-defined
59  data types.
60 
61  - \c UPstream_alias_dataType trait :<br>
62  Use this in preference to UPstream_mpi_dataType.<br>
63  A pass-through to UPstream_mpi_dataType, but provides additional
64  mappings for <int/long/long long,...> to the fundamental
65  32/64 bit integrals, since <int/long/long long,...> may not otherwise
66  map directly on all systems.
67 
68  - \c UPstream_any_dataType trait :<br>
69  Used as a building block for uniform aggregate types.<br>
70  Combines UPstream_user_dataType and UPstream_alias_dataType into a
71  single trait.
72  .
73 
74 \*---------------------------------------------------------------------------*/
75 
76 #ifndef Foam_UPstreamTraits_H
77 #define Foam_UPstreamTraits_H
78 
79 #include "UPstream.H"
80 #include <cstdint>
81 #include <ios> // For streamsize
82 #include <type_traits>
83 
84 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
85 
86 namespace Foam
87 {
88 
89 // Forward Declarations
90 
91 // Some vector-space types
92 // -----------------------
94 template<class T> class Vector;
95 template<class T> class SymmTensor;
96 template<class T> class Tensor;
98 
99 // -------------------------
100 // Some binary operators (as per ops.H), but since ListOps.H is included
101 // by UPstream.H, don't need to forward declare
102 // -------------------------
103 // template<class T> struct minOp;
104 // template<class T> struct maxOp;
105 // template<class T> struct plusOp;
106 // template<class T> struct sumOp;
107 // template<class T> struct multiplyOp;
108 // template<class T> struct bitAndOp;
109 // template<class T> struct bitOrOp;
110 // template<class T> struct bitXorOp;
111 
113 template<class T> struct UPstream_basic_dataType;
114 template<class T> struct UPstream_dataType;
116 
117 
118 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
119 
120 //- UPstream data type corresponding to a fundamental (MPI) type
121 template<class T>
122 struct UPstream_mpi_dataType : std::false_type
123 {
124  static constexpr auto datatype_id = UPstream::dataTypes::invalid;
125 };
127 //- Disallow \c void
128 template<> struct UPstream_mpi_dataType<void> : std::false_type
129 {
130  static constexpr auto datatype_id = UPstream::dataTypes::invalid;
131 };
132 
133 //- UPstream data type corresponding to user-defined type
134 template<class T>
135 struct UPstream_user_dataType : std::false_type
136 {
137  static constexpr auto datatype_id = UPstream::dataTypes::invalid;
138 };
139 
140 //- Disallow \c void
141 template<> struct UPstream_user_dataType<void> : std::false_type
142 {
143  static constexpr auto datatype_id = UPstream::dataTypes::invalid;
144 };
146 
147 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
148 
149 // Trait specializations (data types)
150 
151 // Specializations to match elements of UPstream::dataTypes.
152 
153 #undef defineUPstreamDataTraits
154 #define defineUPstreamDataTraits(TypeId, Type) \
155  \
156  \
157  template<> struct UPstream_mpi_dataType<Type> : std::true_type \
158  { \
159  static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
160  }; \
161  \
162  template<> struct UPstream_mpi_dataType<const Type> : std::true_type \
163  { \
164  static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
165  };
166 
167 // Fundamental Types [10]:
168 // Note: uses 'int32_t,int64_t,...' instead of 'int,long,...' to minimize
169 // the possibility of duplicate types. However, 'int8_t,uint8_t' are treated
170 // as aliases (char,unsigned char) to avoid possible compilation issues.
171 //
172 // OpenFOAM defines Foam::label as either int32_t,int64_t (not int,long) too.
173 defineUPstreamDataTraits(type_byte, char);
174 defineUPstreamDataTraits(type_byte, unsigned char);
175 defineUPstreamDataTraits(type_int16, int16_t);
176 defineUPstreamDataTraits(type_int32, int32_t);
177 defineUPstreamDataTraits(type_int64, int64_t);
178 defineUPstreamDataTraits(type_uint16, uint16_t);
179 defineUPstreamDataTraits(type_uint32, uint32_t);
180 defineUPstreamDataTraits(type_uint64, uint64_t);
181 defineUPstreamDataTraits(type_float, float);
182 defineUPstreamDataTraits(type_double, double);
183 defineUPstreamDataTraits(type_long_double, long double);
185 #undef defineUPstreamDataTraits
186 
187 // ------------------------------------------------------------------------- //
188 
189 #undef defineUPstreamDataTraits
190 #define defineUPstreamDataTraits(TypeId, Type) \
191  \
192  \
193  template<> struct UPstream_user_dataType<Type> : std::true_type \
194  { \
195  static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
196  }; \
197  \
198  template<> struct UPstream_user_dataType<const Type> : std::true_type \
199  { \
200  static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \
201  };
202 
203 
204 // User Types [6]:
205 defineUPstreamDataTraits(type_3float, Vector<float>);
206 defineUPstreamDataTraits(type_3double, Vector<double>);
212 #undef defineUPstreamDataTraits
213 
214 
215 // ------------------------------------------------------------------------- //
216 
217 //- Explicit handling of data type aliases. This is necessary since
218 //- different systems map things like 'unsigned long' differently but we
219 //- restrict ourselves to int32/int64 types.
220 //
221 // Note that this trait serves as the single pass-through point when needing
222 // to reference UPstream_mpi_dataType elsewhere
223 template<class T>
225 :
226  std::bool_constant
227  <
228  // Basic MPI type
229  UPstream_mpi_dataType<std::remove_cv_t<T>>::value ||
230  (
231  // Or some int 32/64 type to re-map
232  std::is_integral_v<T>
233  && (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
234  )
235  >
236 {
237  using base = std::conditional_t
238  <
240  std::remove_cv_t<T>, // <- using mpi type (no alias)
241  std::conditional_t // <- using alias
242  <
243  (
244  std::is_integral_v<T>
245  && (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t))
246  ),
247  std::conditional_t
248  <
249  (sizeof(T) == sizeof(int32_t)),
250  std::conditional_t<std::is_signed_v<T>, int32_t, uint32_t>,
251  std::conditional_t<std::is_signed_v<T>, int64_t, uint64_t>
252  >,
253  char // Fallback is a byte (eg, arbitrary contiguous data)
254  >
255  >;
256 
257  static constexpr auto datatype_id =
259 };
261 
262 // Handle int8_t/uint8_t as aliases since 'signed char' etc may be
263 // ambiguous
264 
265 //- Map \c int8_t to UPstream::dataTypes::type_byte
266 template<>
267 struct UPstream_alias_dataType<int8_t> : std::true_type
268 {
269  using base = char;
270  static constexpr auto datatype_id = UPstream::dataTypes::type_byte;
271 };
272 
273 //- Map \c uint8_t to UPstream::dataTypes::type_byte
274 template<>
275 struct UPstream_alias_dataType<uint8_t> : std::true_type
276 {
277  using base = unsigned char;
278  static constexpr auto datatype_id = UPstream::dataTypes::type_byte;
279 };
280 
281 // ------------------------------------------------------------------------- //
282 
283 //- UPstream data type (fundamental or user-defined),
284 //- after resolving any aliases
285 template<class T>
287 :
288  std::bool_constant
289  <
290  UPstream_user_dataType<std::remove_cv_t<T>>::value
291  || UPstream_alias_dataType<T>::value
292  >
293 {
294  using base = std::conditional_t
295  <
297  std::remove_cv_t<T>,
299  >;
300 
301  //- The corresponding UPstream::dataTypes enumeration
302  static constexpr auto datatype_id = []() constexpr noexcept
303  {
304  if constexpr (UPstream_user_dataType<std::remove_cv_t<T>>::value)
305  {
306  // A user-defined type
308  }
309  else if constexpr (UPstream_alias_dataType<T>::value)
310  {
311  // Fundamental type or alias to a fundamental type
313  }
314  else
315  {
317  }
318  }();
319 };
320 
321 
322 // ------------------------------------------------------------------------- //
323 
324 //- UPstream fundamental/aliased (excludes user-defined) data type
325 //- or a component aggregate of the same.
326 //
327 // True for the following conditions:
328 // - The \c Type is directly supported
329 // - The \c cmptType (eg, from VectorSpace) exists and is directly supported
330 // - Fallback to byte-wise representation (ie, for contiguous)
331 // .
332 template<class T>
333 struct UPstream_basic_dataType
334 :
335  std::bool_constant
336  <
337  // non-aggregate type
338  UPstream_alias_dataType<T>::value
339  // aggregate type
340  || UPstream_alias_dataType<typename pTraits_cmptType<T>::type>::value
341  >
342 {
343  //- The underlying data type (if supported) or byte
344  using base = std::conditional_t
345  <
346  UPstream_alias_dataType<T>::value,
347  typename UPstream_alias_dataType<T>::base, // <- non-aggregate
348  typename UPstream_alias_dataType
349  <typename pTraits_cmptType<T>::type>::base // <- aggregate
350  >;
351 
352  //- The corresponding UPstream::dataTypes enumeration
353  static constexpr auto datatype_id =
355 
356  //- The size in terms of the number of underlying data elements
357  static constexpr std::streamsize size(std::streamsize n) noexcept
358  {
359  if constexpr (UPstream_alias_dataType<T>::value)
360  {
361  // non-aggregate: no multiplier
362  return n;
363  }
364  else
365  {
366  // aggregate: with multiplier
367  return n*(sizeof(T)/sizeof(base));
368  }
369  }
370 };
371 
372 //- Disallow \c void
373 template<> struct UPstream_basic_dataType<void> : UPstream_mpi_dataType<void>
374 {
375  using base = void;
376  static constexpr std::streamsize size(std::streamsize n) noexcept
377  {
378  return n;
379  }
380 };
381 
382 
383 // ------------------------------------------------------------------------- //
384 
385 //- UPstream fundamental/aliased/user-defined data type
386 //- or a component aggregate of the same.
387 //
388 // True for the following conditions:
389 // - The \c Type is directly supported
390 // - The \c cmptType (eg, from VectorSpace) exists and is directly supported
391 // - Fallback to byte-wise representation (ie, for contiguous)
392 // .
393 template<class T>
394 struct UPstream_dataType
395 :
396  std::bool_constant
397  <
398  UPstream_any_dataType<T>::value
399  || UPstream_any_dataType<typename pTraits_cmptType<T>::type>::value
400  >
401 {
402  //- The underlying data type (if supported) or byte
403  using base = std::conditional_t
404  <
406  typename UPstream_any_dataType<T>::base, // <- non-aggregate
407  typename UPstream_any_dataType
408  <typename pTraits_cmptType<T>::type>::base // <- aggregate
409  >;
410 
411  //- The corresponding UPstream::dataTypes enumeration
412  static constexpr auto datatype_id =
414 
415  //- The size in terms of the number of base data elements
416  static constexpr std::streamsize size(std::streamsize n) noexcept
417  {
418  if constexpr (UPstream_any_dataType<T>::value)
419  {
420  // non-aggregate: no multiplier
421  return n;
422  }
423  else
424  {
425  // aggregate: with multiplier
426  return n*(sizeof(T)/sizeof(base));
427  }
428  }
429 };
430 
431 //- Disallow \c void
432 template<> struct UPstream_dataType<void> : UPstream_basic_dataType<void> {};
433 
434 
435 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
436 
437 // Reduction op-codes
439 //- A supported UPstream (MPI) reduce/window operation type
440 template<class BinaryOp>
441 struct UPstream_opType : std::false_type
442 {
443  static constexpr auto opcode_id = UPstream::opCodes::invalid;
444 };
445 
446 //- Disallow \c void
447 template<> struct UPstream_opType<void> : std::false_type
448 {
449  static constexpr auto opcode_id = UPstream::opCodes::invalid;
450 };
451 
452 //- Map minOp<T> to \c UPstream::opCodes::op_min
453 template<class T>
454 struct UPstream_opType<Foam::minOp<T>> : std::true_type
455 {
456  static constexpr auto opcode_id = UPstream::opCodes::op_min;
457 };
458 
459 //- Map maxOp<T> to \c UPstream::opCodes::op_max
460 template<class T>
461 struct UPstream_opType<Foam::maxOp<T>> : std::true_type
462 {
463  static constexpr auto opcode_id = UPstream::opCodes::op_max;
464 };
465 
466 //- Map sumOp<T> to \c UPstream::opCodes::op_sum
467 template<class T>
468 struct UPstream_opType<Foam::sumOp<T>> : std::true_type
469 {
470  static constexpr auto opcode_id = UPstream::opCodes::op_sum;
471 };
472 
473 //- Map plusOp<T> (same as sumOp<T>) to \c UPstream::opCodes::op_sum
474 template<class T>
475 struct UPstream_opType<Foam::plusOp<T>> : std::true_type
476 {
477  static constexpr auto opcode_id = UPstream::opCodes::op_sum;
478 };
479 
480 //- Map multiplyOp<T> to \c UPstream::opCodes::op_prod
481 template<class T>
482 struct UPstream_opType<Foam::multiplyOp<T>> : std::true_type
483 {
484  static constexpr auto opcode_id = UPstream::opCodes::op_prod;
485 };
487 // NOTE (2025-02):
488 // currently no mappings provided for
489 // (op_bool_and, op_bool_or, op_bool_xor) until the calling semantics
490 // have been properly defined
491 
492 
493 // These are only viable for unsigned integral types,
494 // probably not for signed integral types.
495 // Be extra restrictive for now
496 
497 //- Map bitAndOp<T> to \c UPstream::opCodes::op_bit_and
498 //- for integrals (signed or unsigned), but also allow void as "generic"
499 template<class T>
500 struct UPstream_opType<Foam::bitAndOp<T>>
501 :
502  std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>>
503 {
504  static constexpr auto opcode_id = []() constexpr noexcept
505  {
506  if constexpr (std::is_integral_v<T> || std::is_void_v<T>)
508  else
510  }();
511 };
512 
513 //- Map bitOrOp<T> to \c UPstream::opCodes::op_bit_or
514 //- for integrals (signed or unsigned), but also allow void as "generic"
515 template<class T>
516 struct UPstream_opType<Foam::bitOrOp<T>>
517 :
518  std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>>
519 {
520  static constexpr auto opcode_id = []() constexpr noexcept
521  {
522  if constexpr (std::is_integral_v<T> || std::is_void_v<T>)
524  else
526  }();
527 };
528 
529 //- Map bitXorOp<T> to \c UPstream::opCodes::op_bit_xor
530 //- for integrals (signed or unsigned), but also allow void as "generic"
531 template<class T>
532 struct UPstream_opType<Foam::bitXorOp<T>>
533 :
534  std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>>
535 {
536  static constexpr auto opcode_id = []() constexpr noexcept
537  {
538  if constexpr (std::is_integral_v<T> || std::is_void_v<T>)
540  else
542  }();
543 };
544 
545 
546 //- Combined query of opType and the underlying basic data type
547 // This handling may be simplified in the future...
548 template<class BinaryOp, class T>
550 :
551  std::bool_constant
552  <
553  UPstream_opType<BinaryOp>::value
554  && UPstream_basic_dataType<T>::value
555  >
556 {
557  static constexpr auto opcode_id = []() constexpr noexcept
558  {
559  if constexpr
560  (
563  )
565  else
567  }();
568 };
570 
571 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
572 
573 // Convenience Functions (FUTURE?)
574 
575 // inline bool is_UPstream_mpi_dataTypeCode(UPstream::dataTypes id) noexcept
576 // {
577 // return
578 // (
579 // int(id) >= int(UPstream::opCodes::Basic_begin)
580 // && int(id) < int(UPstream::opCodes::Basic_end)
581 // );
582 // }
583 //
584 // inline bool is_UPstream_reduceOpCode(UPstream::opCodes id) noexcept
585 // {
586 // return
587 // (
588 // int(id) >= int(UPstream::opCodes::Basic_begin)
589 // && int(id) < int(UPstream::opCodes::Basic_end)
590 // );
591 // }
592 
593 
594 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
595 
596 } // End namespace Foam
597 
598 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
599 
600 #endif
601 
602 // ************************************************************************* //
UPstream fundamental/aliased (excludes user-defined) data type or a component aggregate of the same...
static constexpr auto datatype_id
The corresponding UPstream::dataTypes enumeration.
Explicit handling of data type aliases. This is necessary since different systems map things like &#39;un...
static constexpr std::streamsize size(std::streamsize n) noexcept
The size in terms of the number of base data elements.
A templated (3 x 3) symmetric tensor of objects of <T>, effectively containing 6 elements, derived from VectorSpace.
Definition: foamVtkCore.H:63
Combined query of opType and the underlying basic data type.
static constexpr auto datatype_id
The corresponding UPstream::dataTypes enumeration.
Bit-wise xor for (unsigned) integral types.
UPstream data type (fundamental or user-defined), after resolving any aliases.
static constexpr auto datatype_id
std::conditional_t< UPstream_alias_dataType< T >::value, typename UPstream_alias_dataType< T >::base, typename UPstream_alias_dataType< typename pTraits_cmptType< T >::type >::base > base
The underlying data type (if supported) or byte.
static constexpr auto datatype_id
UPstream data type corresponding to user-defined type.
A supported UPstream (MPI) reduce/window operation type.
static constexpr auto datatype_id
The corresponding UPstream::dataTypes enumeration.
byte, char, unsigned char, ...
static constexpr auto datatype_id
std::conditional_t< UPstream_any_dataType< T >::value, typename UPstream_any_dataType< T >::base, typename UPstream_any_dataType< typename pTraits_cmptType< T >::type >::base > base
The underlying data type (if supported) or byte.
static constexpr auto opcode_id
static constexpr auto opcode_id
const direction noexcept
Definition: scalarImpl.H:265
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
static constexpr std::streamsize size(std::streamsize n) noexcept
The size in terms of the number of underlying data elements.
std::conditional_t< UPstream_mpi_dataType< std::remove_cv_t< T > >::value, std::remove_cv_t< T >, std::conditional_t<(std::is_integral_v< T > &&(sizeof(T)==sizeof(int32_t)||sizeof(T)==sizeof(int64_t))), std::conditional_t<(sizeof(T)==sizeof(int32_t)), std::conditional_t< std::is_signed_v< T >, int32_t, uint32_t >, std::conditional_t< std::is_signed_v< T >, int64_t, uint64_t > >, char > > base
Bit-wise or for (unsigned) integral types.
UPstream data type corresponding to a fundamental (MPI) type.
std::conditional_t< UPstream_user_dataType< std::remove_cv_t< T > >::value, std::remove_cv_t< T >, typename UPstream_alias_dataType< T >::base > base
label n
A templated (3 x 3) tensor of objects of <T> derived from MatrixSpace.
Definition: SVD.H:44
#define defineUPstreamDataTraits(TypeId, Type)
Namespace for OpenFOAM.
Bit-wise and for (unsigned) integral types.