From 9437e8d068c158cf6d6130c23624957185568be0 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 5 Mar 2025 11:36:00 +0100 Subject: [PATCH 01/15] ENH: simplify operator calls for error, messageStream - use move semantics for string parameters and reuse more code --- src/OpenFOAM/db/error/IOerror.C | 6 +- src/OpenFOAM/db/error/error.C | 42 ++++----- src/OpenFOAM/db/error/error.H | 33 +++---- src/OpenFOAM/db/error/messageStream.C | 125 ++++++++++++++++---------- src/OpenFOAM/db/error/messageStream.H | 40 ++++----- 5 files changed, 133 insertions(+), 113 deletions(-) diff --git a/src/OpenFOAM/db/error/IOerror.C b/src/OpenFOAM/db/error/IOerror.C index 23029959ffc..b245976499b 100644 --- a/src/OpenFOAM/db/error/IOerror.C +++ b/src/OpenFOAM/db/error/IOerror.C @@ -69,7 +69,7 @@ Foam::OSstream& Foam::IOerror::operator() const char* functionName, const char* sourceFileName, const int sourceFileLineNumber, - const string& ioFileName, + string ioFileName, const label ioStartLineNumber, const label ioEndLineNumber ) @@ -81,7 +81,7 @@ Foam::OSstream& Foam::IOerror::operator() sourceFileLineNumber ); - ioFileName_ = ioFileName; + ioFileName_ = std::move(ioFileName); ioStartLineNumber_ = ioStartLineNumber; ioEndLineNumber_ = ioEndLineNumber; @@ -296,7 +296,7 @@ void Foam::IOerror::write(Ostream& os, const bool withTitle) const } - const label lineNo = sourceFileLineNumber(); + const auto lineNo = sourceFileLineNumber(); if (messageStream::level >= 2 && lineNo && !functionName().empty()) { diff --git a/src/OpenFOAM/db/error/error.C b/src/OpenFOAM/db/error/error.C index 22b81ca642f..f127e5f8aa3 100644 --- a/src/OpenFOAM/db/error/error.C +++ b/src/OpenFOAM/db/error/error.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2015-2023 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -57,7 +57,7 @@ Foam::error::handlerNames // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // -bool Foam::error::master(const label communicator) +bool Foam::error::master(const int communicator) { // Trap negative value for comm as 'default'. This avoids direct use // of UPstream::worldComm which may have not yet been initialised @@ -177,12 +177,20 @@ Foam::error::~error() noexcept Foam::OSstream& Foam::error::operator() ( - const string& functionName + string functionName, + const char* sourceFileName, + const int sourceFileLineNumber ) { - functionName_ = functionName; + functionName_ = std::move(functionName); sourceFileName_.clear(); - sourceFileLineNumber_ = -1; + + if (sourceFileName) // nullptr check + { + sourceFileName_.assign(sourceFileName); + } + + sourceFileLineNumber_ = sourceFileLineNumber; return this->stream(); } @@ -198,14 +206,12 @@ Foam::OSstream& Foam::error::operator() functionName_.clear(); sourceFileName_.clear(); - if (functionName) + if (functionName) // nullptr check { - // With nullptr protection functionName_.assign(functionName); } - if (sourceFileName) + if (sourceFileName) // nullptr check { - // With nullptr protection sourceFileName_.assign(sourceFileName); } sourceFileLineNumber_ = sourceFileLineNumber; @@ -214,22 +220,6 @@ Foam::OSstream& Foam::error::operator() } -Foam::OSstream& Foam::error::operator() -( - const string& functionName, - const char* sourceFileName, - const int sourceFileLineNumber -) -{ - return operator() - ( - functionName.c_str(), - sourceFileName, - sourceFileLineNumber - ); -} - - Foam::error::operator Foam::dictionary() const { dictionary errDict; @@ -401,7 +391,7 @@ void Foam::error::write(Ostream& os, const bool withTitle) const os << message().c_str(); - const label lineNo = sourceFileLineNumber(); + const auto lineNo = sourceFileLineNumber(); if (messageStream::level >= 2 && lineNo && !functionName().empty()) { diff --git a/src/OpenFOAM/db/error/error.H b/src/OpenFOAM/db/error/error.H index 22832dd8e4a..59d7128fd93 100644 --- a/src/OpenFOAM/db/error/error.H +++ b/src/OpenFOAM/db/error/error.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2024 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -89,7 +89,7 @@ protected: string functionName_; string sourceFileName_; - label sourceFileLineNumber_; + int sourceFileLineNumber_; bool throwing_; std::unique_ptr<OStringStream> messageStreamPtr_; @@ -143,7 +143,7 @@ public: // // \param communicator is the numbered MPI communicator. // By default it uses UPstream::worldComm - static bool master(const label communicator = -1); + static bool master(const int communicator = -1); //- Test if an age warning should be emitted. // \param version is the old version (YYMM) for determining the @@ -180,7 +180,7 @@ public: } //- The currently defined source-file line number for output messages - label sourceFileLineNumber() const noexcept + int sourceFileLineNumber() const noexcept { return sourceFileLineNumber_; } @@ -218,29 +218,24 @@ public: return this->stream(); } - //- Define basic print message + //- Define basic print message with originating function name, + //- optionally with 'source file, line number' // \return OSstream for further operations OSstream& operator() ( - const string& functionName + string functionName, + const char* sourceFileName = nullptr, + const int sourceFileLineNumber = -1 ); - //- Define basic print message + //- Define basic print message with originating function name, + //- optionally with 'source file, line number' // \return OSstream for further operations OSstream& operator() ( const char* functionName, - const char* sourceFileName, - const int sourceFileLineNumber = 0 - ); - - //- Define basic print message - // \return OSstream for further operations - OSstream& operator() - ( - const string& functionName, - const char* sourceFileName, - const int sourceFileLineNumber = 0 + const char* sourceFileName = nullptr, + const int sourceFileLineNumber = -1 ); @@ -361,7 +356,7 @@ public: const char* functionName, const char* sourceFileName, const int sourceFileLineNumber, - const string& ioFileName, + string ioFileName, const label ioStartLineNumber = -1, const label ioEndLineNumber = -1 ); diff --git a/src/OpenFOAM/db/error/messageStream.C b/src/OpenFOAM/db/error/messageStream.C index 04a3e907bdc..62e26d30d21 100644 --- a/src/OpenFOAM/db/error/messageStream.C +++ b/src/OpenFOAM/db/error/messageStream.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2017-2024 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -49,21 +49,15 @@ int Foam::infoDetailLevel(1); Foam::messageStream::messageStream ( - const char* title, errorSeverity severity, int maxErrors, bool use_stderr ) : - title_(), severity_(severity), maxErrors_(maxErrors), errorCount_(0) { - if (title) - { - title_ = title; - } if (use_stderr) { severity_ |= errorSeverity::USE_STDERR; @@ -71,12 +65,40 @@ Foam::messageStream::messageStream } +Foam::messageStream::messageStream +( + const char* title, + errorSeverity severity, + int maxErrors, + bool use_stderr +) +: + messageStream(severity, maxErrors, use_stderr) +{ + if (title) + { + title_ = title; + } +} + + +Foam::messageStream::messageStream +( + string title, + errorSeverity severity, + int maxErrors, + bool use_stderr +) +: + messageStream(severity, maxErrors, use_stderr) +{ + title_ = std::move(title); +} + + Foam::messageStream::messageStream(const dictionary& dict) : - title_(dict.get<string>("title")), - severity_(errorSeverity::FATAL), - maxErrors_(0), - errorCount_(0) + messageStream(dict.get<string>("title"), errorSeverity::FATAL) {} @@ -153,7 +175,7 @@ Foam::OSstream& Foam::messageStream::stream } -Foam::OSstream& Foam::messageStream::masterStream(const label communicator) +Foam::OSstream& Foam::messageStream::masterStream(const int communicator) { if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm) { @@ -178,23 +200,6 @@ std::ostream& Foam::messageStream::stdStream() // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // -Foam::OSstream& Foam::messageStream::operator() -( - const std::string& functionName -) -{ - OSstream& os = this->stream(); - - if (!functionName.empty()) - { - os << nl - << " From " << functionName.c_str() << nl; - } - - return os; -} - - Foam::OSstream& Foam::messageStream::deprecated ( const int afterVersion, @@ -239,10 +244,15 @@ Foam::OSstream& Foam::messageStream::deprecated { os << " From " << functionName << nl; } - if (sourceFileName) + if (sourceFileName) // nullptr check { - os << " in file " << sourceFileName - << " at line " << sourceFileLineNumber << nl; + os << " in file " << sourceFileName; + + if (sourceFileLineNumber >= 0) + { + os << " at line " << sourceFileLineNumber; + } + os << nl; } } os << " "; @@ -253,18 +263,29 @@ Foam::OSstream& Foam::messageStream::deprecated Foam::OSstream& Foam::messageStream::operator() ( - const char* functionName, + const std::string& functionName, const char* sourceFileName, const int sourceFileLineNumber ) { OSstream& os = this->stream(); - os << nl - << " From " << functionName << nl - << " in file " << sourceFileName - << " at line " << sourceFileLineNumber << nl - << " "; + if (!functionName.empty()) + { + os << nl + << " From " << functionName.c_str() << nl; + } + + if (sourceFileName) // nullptr check + { + os << " in file " << sourceFileName; + + if (sourceFileLineNumber >= 0) + { + os << " at line " << sourceFileLineNumber; + } + os << nl << " "; + } return os; } @@ -272,17 +293,31 @@ Foam::OSstream& Foam::messageStream::operator() Foam::OSstream& Foam::messageStream::operator() ( - const std::string& functionName, + const char* functionName, const char* sourceFileName, const int sourceFileLineNumber ) { - return operator() - ( - functionName.c_str(), - sourceFileName, - sourceFileLineNumber - ); + OSstream& os = this->stream(); + + if (functionName) // nullptr check + { + os << nl + << " From " << functionName << nl; + } + + if (sourceFileName) // nullptr check + { + os << " in file " << sourceFileName; + + if (sourceFileLineNumber >= 0) + { + os << " at line " << sourceFileLineNumber; + } + os << nl << " "; + } + + return os; } diff --git a/src/OpenFOAM/db/error/messageStream.H b/src/OpenFOAM/db/error/messageStream.H index e22d8d0abec..6fe86394e94 100644 --- a/src/OpenFOAM/db/error/messageStream.H +++ b/src/OpenFOAM/db/error/messageStream.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2024 OpenCFD Ltd. + Copyright (C) 2016-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -130,6 +130,14 @@ public: // Constructors + //- Construct untitled with given characteristics + explicit messageStream + ( + errorSeverity severity, + int maxErrors = 0, + bool use_stderr = false + ); + //- Construct from components messageStream ( @@ -142,14 +150,11 @@ public: //- Construct from components messageStream ( - const std::string& title, + string title, errorSeverity severity, int maxErrors = 0, bool use_stderr = false - ) - : - messageStream(title.c_str(), severity, maxErrors, use_stderr) - {} + ); //- Construct from dictionary as Fatal, extracting 'title'. @@ -191,7 +196,7 @@ public: //- Return OSstream for output operations on the master process only, //- Snull on other processes. - OSstream& masterStream(const label communicator); + OSstream& masterStream(const int communicator); //- Return std::ostream for output operations. std::ostream& stdStream(); @@ -220,28 +225,23 @@ public: return this->stream(); } - //- Report 'From function-name' - // \return OSstream for further operations - OSstream& operator() - ( - const std::string& functionName - ); - - //- Report 'From function-name, source file, line number' + //- Report 'From function-name', + //- optionally with 'source file, line number' // \return OSstream for further operations OSstream& operator() ( - const char* functionName, - const char* sourceFileName, + const std::string& functionName, + const char* sourceFileName = nullptr, const int sourceFileLineNumber = 0 ); - //- Report 'From function-name, source file, line number' + //- Report 'From function-name', + //- optionally with 'source file, line number' // \return OSstream for further operations OSstream& operator() ( - const std::string& functionName, - const char* sourceFileName, + const char* functionName, + const char* sourceFileName = nullptr, const int sourceFileLineNumber = 0 ); -- GitLab From cf9fa16788ec9530183534a12c1697410158035e Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Thu, 27 Feb 2025 08:35:05 +0100 Subject: [PATCH 02/15] COMP: add pTraits for int16/uint16 types (simplifies messages) --- src/OpenFOAM/primitives/Scalar/scalarImpl.H | 15 +---- src/OpenFOAM/primitives/bools/bool/bool.H | 5 +- src/OpenFOAM/primitives/chars/char/char.H | 5 +- src/OpenFOAM/primitives/complex/complex.H | 5 +- src/OpenFOAM/primitives/ints/int16/int16.C | 15 ++++- src/OpenFOAM/primitives/ints/int16/int16.H | 63 +++++++++++++++++++- src/OpenFOAM/primitives/ints/int32/int32.C | 4 +- src/OpenFOAM/primitives/ints/int32/int32.H | 5 +- src/OpenFOAM/primitives/ints/int64/int64.C | 4 +- src/OpenFOAM/primitives/ints/int64/int64.H | 5 +- src/OpenFOAM/primitives/ints/int8/int8.H | 5 +- src/OpenFOAM/primitives/ints/uint16/uint16.C | 15 ++++- src/OpenFOAM/primitives/ints/uint16/uint16.H | 63 +++++++++++++++++++- src/OpenFOAM/primitives/ints/uint32/uint32.C | 2 +- src/OpenFOAM/primitives/ints/uint32/uint32.H | 5 +- src/OpenFOAM/primitives/ints/uint64/uint64.C | 2 +- src/OpenFOAM/primitives/ints/uint64/uint64.H | 5 +- src/OpenFOAM/primitives/ints/uint8/uint8.H | 15 +---- 18 files changed, 172 insertions(+), 66 deletions(-) diff --git a/src/OpenFOAM/primitives/Scalar/scalarImpl.H b/src/OpenFOAM/primitives/Scalar/scalarImpl.H index 2517aa0aef3..0d1564dde56 100644 --- a/src/OpenFOAM/primitives/Scalar/scalarImpl.H +++ b/src/OpenFOAM/primitives/Scalar/scalarImpl.H @@ -116,10 +116,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(Scalar val) noexcept - : - p_(val) - {} + explicit pTraits(Scalar val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); @@ -128,16 +125,10 @@ public: // Member Functions //- Return the value - operator Scalar() const noexcept - { - return p_; - } + operator Scalar() const noexcept { return p_; } //- Access the value - operator Scalar&() noexcept - { - return p_; - } + operator Scalar&() noexcept { return p_; } }; diff --git a/src/OpenFOAM/primitives/bools/bool/bool.H b/src/OpenFOAM/primitives/bools/bool/bool.H index 0e791d0404b..090fae41375 100644 --- a/src/OpenFOAM/primitives/bools/bool/bool.H +++ b/src/OpenFOAM/primitives/bools/bool/bool.H @@ -102,10 +102,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(bool val) noexcept - : - p_(val) - {} + explicit pTraits(bool val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/chars/char/char.H b/src/OpenFOAM/primitives/chars/char/char.H index 959e0f075c3..25ecd83f388 100644 --- a/src/OpenFOAM/primitives/chars/char/char.H +++ b/src/OpenFOAM/primitives/chars/char/char.H @@ -94,10 +94,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(char val) noexcept - : - p_(val) - {} + explicit pTraits(char val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/complex/complex.H b/src/OpenFOAM/primitives/complex/complex.H index 7749aae7adf..b04f76b4afb 100644 --- a/src/OpenFOAM/primitives/complex/complex.H +++ b/src/OpenFOAM/primitives/complex/complex.H @@ -288,10 +288,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(const complex& val) noexcept - : - p_(val) - {} + explicit pTraits(const complex& val) noexcept : p_(val) {} //- Read construct from Istream diff --git a/src/OpenFOAM/primitives/ints/int16/int16.C b/src/OpenFOAM/primitives/ints/int16/int16.C index 27a16f57f64..1fc4b094288 100644 --- a/src/OpenFOAM/primitives/ints/int16/int16.C +++ b/src/OpenFOAM/primitives/ints/int16/int16.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +29,19 @@ License #include "int32.H" #include "IOstreams.H" +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const char* const Foam::pTraits<int16_t>::typeName = "int16"; +const char* const Foam::pTraits<int16_t>::componentNames[] = { "" }; + +const int16_t Foam::pTraits<int16_t>::zero = 0; +const int16_t Foam::pTraits<int16_t>::one = 1; +const int16_t Foam::pTraits<int16_t>::min = INT16_MIN; +const int16_t Foam::pTraits<int16_t>::max = INT16_MAX; +const int16_t Foam::pTraits<int16_t>::rootMin = INT16_MIN; +const int16_t Foam::pTraits<int16_t>::rootMax = INT16_MAX; + + // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // Foam::Istream& Foam::operator>>(Istream& is, int16_t& val) diff --git a/src/OpenFOAM/primitives/ints/int16/int16.H b/src/OpenFOAM/primitives/ints/int16/int16.H index 21587e88e6b..44f6fc96c5a 100644 --- a/src/OpenFOAM/primitives/ints/int16/int16.H +++ b/src/OpenFOAM/primitives/ints/int16/int16.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -73,6 +73,67 @@ Istream& operator>>(Istream& is, int16_t& val); Ostream& operator<<(Ostream& os, const int16_t val); +/*---------------------------------------------------------------------------*\ + Specialization pTraits<int16_t> +\*---------------------------------------------------------------------------*/ + +//- Template specialization for pTraits<int16_t> +template<> +class pTraits<int16_t> +{ + int16_t p_; + +public: + + // Typedefs + + //- Component type + typedef int16_t cmptType; + + + // Member Constants + + //- Dimensionality of space + static constexpr direction dim = 3; + + //- Rank of int16_t is 0 + static constexpr direction rank = 0; + + //- Number of components in int16_t is 1 + static constexpr direction nComponents = 1; + + + // Static Data Members + + static const char* const typeName; + static const char* const componentNames[]; + static const int16_t zero; + static const int16_t one; + static const int16_t min; + static const int16_t max; + static const int16_t rootMax; + static const int16_t rootMin; + + + // Constructors + + //- Copy construct from primitive + explicit pTraits(int16_t val) noexcept : p_(val) {} + + //- Read construct from Istream + explicit pTraits(Istream& is); + + + // Member Functions + + //- Return the value + operator int16_t() const noexcept { return p_; } + + //- Access the value + operator int16_t&() noexcept { return p_; } +}; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/OpenFOAM/primitives/ints/int32/int32.C b/src/OpenFOAM/primitives/ints/int32/int32.C index c1606ab63eb..ccfe8eebbc1 100644 --- a/src/OpenFOAM/primitives/ints/int32/int32.C +++ b/src/OpenFOAM/primitives/ints/int32/int32.C @@ -36,8 +36,8 @@ const int32_t Foam::pTraits<int32_t>::zero = 0; const int32_t Foam::pTraits<int32_t>::one = 1; const int32_t Foam::pTraits<int32_t>::min = INT32_MIN; const int32_t Foam::pTraits<int32_t>::max = INT32_MAX; -const int32_t Foam::pTraits<int32_t>::rootMin = pTraits<int32_t>::min; -const int32_t Foam::pTraits<int32_t>::rootMax = pTraits<int32_t>::max; +const int32_t Foam::pTraits<int32_t>::rootMin = INT32_MIN; +const int32_t Foam::pTraits<int32_t>::rootMax = INT32_MAX; // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/primitives/ints/int32/int32.H b/src/OpenFOAM/primitives/ints/int32/int32.H index bd97eae76b2..39d75b155bc 100644 --- a/src/OpenFOAM/primitives/ints/int32/int32.H +++ b/src/OpenFOAM/primitives/ints/int32/int32.H @@ -181,10 +181,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(int32_t val) noexcept - : - p_(val) - {} + explicit pTraits(int32_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/ints/int64/int64.C b/src/OpenFOAM/primitives/ints/int64/int64.C index 30ad0534e2a..051a8a7e5f8 100644 --- a/src/OpenFOAM/primitives/ints/int64/int64.C +++ b/src/OpenFOAM/primitives/ints/int64/int64.C @@ -36,8 +36,8 @@ const int64_t Foam::pTraits<int64_t>::zero = 0; const int64_t Foam::pTraits<int64_t>::one = 1; const int64_t Foam::pTraits<int64_t>::min = INT64_MIN; const int64_t Foam::pTraits<int64_t>::max = INT64_MAX; -const int64_t Foam::pTraits<int64_t>::rootMin = pTraits<int64_t>::min; -const int64_t Foam::pTraits<int64_t>::rootMax = pTraits<int64_t>::max; +const int64_t Foam::pTraits<int64_t>::rootMin = INT64_MIN; +const int64_t Foam::pTraits<int64_t>::rootMax = INT64_MAX; // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/primitives/ints/int64/int64.H b/src/OpenFOAM/primitives/ints/int64/int64.H index 49766d26212..e88716e14aa 100644 --- a/src/OpenFOAM/primitives/ints/int64/int64.H +++ b/src/OpenFOAM/primitives/ints/int64/int64.H @@ -180,10 +180,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(int64_t val) noexcept - : - p_(val) - {} + explicit pTraits(int64_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/ints/int8/int8.H b/src/OpenFOAM/primitives/ints/int8/int8.H index 734b5323a95..91ca4a678c6 100644 --- a/src/OpenFOAM/primitives/ints/int8/int8.H +++ b/src/OpenFOAM/primitives/ints/int8/int8.H @@ -124,10 +124,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(int8_t val) noexcept - : - p_(val) - {} + explicit pTraits(int8_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/ints/uint16/uint16.C b/src/OpenFOAM/primitives/ints/uint16/uint16.C index 1b4516ae495..91d1acbc392 100644 --- a/src/OpenFOAM/primitives/ints/uint16/uint16.C +++ b/src/OpenFOAM/primitives/ints/uint16/uint16.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +29,19 @@ License #include "int32.H" #include "IOstreams.H" +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const char* const Foam::pTraits<uint16_t>::typeName = "uint16"; +const char* const Foam::pTraits<uint16_t>::componentNames[] = { "" }; + +const uint16_t Foam::pTraits<uint16_t>::zero = 0; +const uint16_t Foam::pTraits<uint16_t>::one = 1; +const uint16_t Foam::pTraits<uint16_t>::min = 0; +const uint16_t Foam::pTraits<uint16_t>::max = UINT16_MAX; +const uint16_t Foam::pTraits<uint16_t>::rootMin = 0; +const uint16_t Foam::pTraits<uint16_t>::rootMax = UINT16_MAX; + + // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // Foam::Istream& Foam::operator>>(Istream& is, uint16_t& val) diff --git a/src/OpenFOAM/primitives/ints/uint16/uint16.H b/src/OpenFOAM/primitives/ints/uint16/uint16.H index 14b9b249fd1..4ab782dd6c2 100644 --- a/src/OpenFOAM/primitives/ints/uint16/uint16.H +++ b/src/OpenFOAM/primitives/ints/uint16/uint16.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -74,6 +74,67 @@ Istream& operator>>(Istream& is, uint16_t& val); Ostream& operator<<(Ostream& os, const uint16_t val); +/*---------------------------------------------------------------------------*\ + Specialization pTraits<uint16_t> +\*---------------------------------------------------------------------------*/ + +//- Template specialization for pTraits<uint16_t> +template<> +class pTraits<uint16_t> +{ + uint16_t p_; + +public: + + // Typedefs + + //- Component type + typedef uint16_t cmptType; + + + // Member Constants + + //- Dimensionality of space + static constexpr direction dim = 3; + + //- Rank of uint16_t is 0 + static constexpr direction rank = 0; + + //- Number of components in uint16_t is 1 + static constexpr direction nComponents = 1; + + + // Static Data Members + + static const char* const typeName; + static const char* const componentNames[]; + static const uint16_t zero; + static const uint16_t one; + static const uint16_t min; + static const uint16_t max; + static const uint16_t rootMax; + static const uint16_t rootMin; + + + // Constructors + + //- Copy construct from primitive + explicit pTraits(uint16_t val) noexcept : p_(val) {} + + //- Read construct from Istream + explicit pTraits(Istream& is); + + + // Member Functions + + //- Return the value + operator uint16_t() const noexcept { return p_; } + + //- Access the value + operator uint16_t&() noexcept { return p_; } +}; + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace Foam diff --git a/src/OpenFOAM/primitives/ints/uint32/uint32.C b/src/OpenFOAM/primitives/ints/uint32/uint32.C index aa728626e01..9c179acadbd 100644 --- a/src/OpenFOAM/primitives/ints/uint32/uint32.C +++ b/src/OpenFOAM/primitives/ints/uint32/uint32.C @@ -37,7 +37,7 @@ const uint32_t Foam::pTraits<uint32_t>::one = 1; const uint32_t Foam::pTraits<uint32_t>::min = 0; const uint32_t Foam::pTraits<uint32_t>::max = UINT32_MAX; const uint32_t Foam::pTraits<uint32_t>::rootMin = 0; -const uint32_t Foam::pTraits<uint32_t>::rootMax = pTraits<uint32_t>::max; +const uint32_t Foam::pTraits<uint32_t>::rootMax = UINT32_MAX; // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/primitives/ints/uint32/uint32.H b/src/OpenFOAM/primitives/ints/uint32/uint32.H index ba0e7e58872..7d2f1e01e99 100644 --- a/src/OpenFOAM/primitives/ints/uint32/uint32.H +++ b/src/OpenFOAM/primitives/ints/uint32/uint32.H @@ -162,10 +162,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(uint32_t val) noexcept - : - p_(val) - {} + explicit pTraits(uint32_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/ints/uint64/uint64.C b/src/OpenFOAM/primitives/ints/uint64/uint64.C index ab626962348..bf5dbb4ecbf 100644 --- a/src/OpenFOAM/primitives/ints/uint64/uint64.C +++ b/src/OpenFOAM/primitives/ints/uint64/uint64.C @@ -37,7 +37,7 @@ const uint64_t Foam::pTraits<uint64_t>::one = 1; const uint64_t Foam::pTraits<uint64_t>::min = 0; const uint64_t Foam::pTraits<uint64_t>::max = UINT64_MAX; const uint64_t Foam::pTraits<uint64_t>::rootMin = 0; -const uint64_t Foam::pTraits<uint64_t>::rootMax = pTraits<uint64_t>::max; +const uint64_t Foam::pTraits<uint64_t>::rootMax = UINT64_MAX; // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/primitives/ints/uint64/uint64.H b/src/OpenFOAM/primitives/ints/uint64/uint64.H index 98e6346d6b6..3c352e4148b 100644 --- a/src/OpenFOAM/primitives/ints/uint64/uint64.H +++ b/src/OpenFOAM/primitives/ints/uint64/uint64.H @@ -170,10 +170,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(uint64_t val) noexcept - : - p_(val) - {} + explicit pTraits(uint64_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); diff --git a/src/OpenFOAM/primitives/ints/uint8/uint8.H b/src/OpenFOAM/primitives/ints/uint8/uint8.H index b17d19f7293..4fc6c28f366 100644 --- a/src/OpenFOAM/primitives/ints/uint8/uint8.H +++ b/src/OpenFOAM/primitives/ints/uint8/uint8.H @@ -123,10 +123,7 @@ public: // Constructors //- Copy construct from primitive - explicit pTraits(uint8_t val) noexcept - : - p_(val) - {} + explicit pTraits(uint8_t val) noexcept : p_(val) {} //- Read construct from Istream explicit pTraits(Istream& is); @@ -135,16 +132,10 @@ public: // Member Functions //- Return the value - operator uint8_t() const noexcept - { - return p_; - } + operator uint8_t() const noexcept { return p_; } //- Access the value - operator uint8_t&() noexcept - { - return p_; - } + operator uint8_t&() noexcept { return p_; } }; -- GitLab From d64682a7af9cdaa897b0a275710f4ed5fa762d06 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 4 Mar 2025 13:30:20 +0100 Subject: [PATCH 03/15] ENH: expand VectorSpaceOps to include copy_n/fill_n methods - similar to what std::copy_n and std::fill_n would do, except with templated loops. This allows compile-time transcribing with loop unrolling. For example, vector vec1 = ..., vec2 = ...; FixedList<scalar, 6> values; VectorSpaceOps<3>::copy_n(vec1.begin(), values.begin()); VectorSpaceOps<3>::copy_n(vec2.begin(), values.begin(3)) // do something with all of these values STYLE: make start index of VectorSpaceOps optional ENH: add clamped begin(int) versions to FixedList as per UList --- applications/test/vector/Make/files | 2 +- .../vector/{Test-vector.C => Test-vector.cxx} | 51 ++++++++- applications/test/vectorTools/Make/files | 2 +- ...est-vectorTools.C => Test-vectorTools.cxx} | 0 .../containers/Lists/FixedList/FixedList.H | 12 +++ .../containers/Lists/FixedList/FixedListI.H | 24 +++++ .../primitives/VectorSpace/VectorSpace.H | 42 ++++---- .../primitives/VectorSpace/VectorSpaceI.H | 80 ++------------ .../primitives/VectorSpace/VectorSpaceOps.H | 102 ++++++++++++++---- 9 files changed, 197 insertions(+), 118 deletions(-) rename applications/test/vector/{Test-vector.C => Test-vector.cxx} (84%) rename applications/test/vectorTools/{Test-vectorTools.C => Test-vectorTools.cxx} (100%) diff --git a/applications/test/vector/Make/files b/applications/test/vector/Make/files index 62f06825eae..68db4be0f7b 100644 --- a/applications/test/vector/Make/files +++ b/applications/test/vector/Make/files @@ -1,3 +1,3 @@ -Test-vector.C +Test-vector.cxx EXE = $(FOAM_USER_APPBIN)/Test-vector diff --git a/applications/test/vector/Test-vector.C b/applications/test/vector/Test-vector.cxx similarity index 84% rename from applications/test/vector/Test-vector.C rename to applications/test/vector/Test-vector.cxx index 582f8bf5049..cc2ad57d36e 100644 --- a/applications/test/vector/Test-vector.C +++ b/applications/test/vector/Test-vector.cxx @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2023 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,7 +32,10 @@ Description \*---------------------------------------------------------------------------*/ #include "vectorField.H" +#include "boolVector.H" +#include "labelVector.H" #include "IOstreams.H" +#include "FixedList.H" #include "Random.H" #include <algorithm> #include <random> @@ -125,6 +128,42 @@ void testNormalise(Field<Type>& fld) } +// Transcribe vectorspace information into a FixedList +template<class Type> +void testTranscribe(Type& input) +{ + if constexpr + ( + is_vectorspace_v<Type> + && std::is_floating_point_v<typename pTraits_cmptType<Type>::type> + ) + { + constexpr auto nCmpts = pTraits_nComponents<Type>::value; + using cmpt = typename pTraits_cmptType<Type>::type; + + FixedList<cmpt, nCmpts+1> values; + values.back() = 100; // some additional data + + VectorSpaceOps<nCmpts>::copy_n(input.cdata(), values.data()); + + Info<< "Transcribed " << input << " => " << values << nl; + + for (auto& val : values) + { + val *= -1; + } + + VectorSpaceOps<nCmpts>::copy_n(values.cdata(), input.data()); + Info<< " copied back (-1) as " << input + << " from " << values << nl; + } + else + { + Info<< "Did not transcribe " << input << nl; + } +} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Main program: @@ -240,6 +279,16 @@ int main(int argc, char *argv[]) testNormalise(vfld2); } + Info<< nl + << "Test transcribing components" << nl; + { + vector vec1(1.1, 2.2, 3.3); + testTranscribe(vec1); + + labelVector vec2(10, 20, 30); + testTranscribe(vec2); + } + Info<< "\nEnd\n" << nl; return 0; diff --git a/applications/test/vectorTools/Make/files b/applications/test/vectorTools/Make/files index 0b30b98f8f3..6c1e81deb86 100644 --- a/applications/test/vectorTools/Make/files +++ b/applications/test/vectorTools/Make/files @@ -1,3 +1,3 @@ -Test-vectorTools.C +Test-vectorTools.cxx EXE = $(FOAM_USER_APPBIN)/Test-vectorTools diff --git a/applications/test/vectorTools/Test-vectorTools.C b/applications/test/vectorTools/Test-vectorTools.cxx similarity index 100% rename from applications/test/vectorTools/Test-vectorTools.C rename to applications/test/vectorTools/Test-vectorTools.cxx diff --git a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H index 5344e5b3642..8a6abaa91f0 100644 --- a/src/OpenFOAM/containers/Lists/FixedList/FixedList.H +++ b/src/OpenFOAM/containers/Lists/FixedList/FixedList.H @@ -384,6 +384,10 @@ public: //- Return an iterator to end traversing the FixedList inline iterator end() noexcept; + //- Return iterator at offset i from begin, + //- clamped to [0,N] range + inline iterator begin(const int i) noexcept; + // Random access iterator (const) @@ -399,6 +403,14 @@ public: //- Return const_iterator to end traversing the constant FixedList inline const_iterator end() const noexcept; + //- Return const_iterator at offset i from begin, + //- clamped to [0,N] range + inline const_iterator cbegin(const int i) const noexcept; + + //- Return const_iterator at offset i from begin, + //- clamped to [0,N] range + inline const_iterator begin(const int i) const noexcept; + // Reverse iterator (non-const) diff --git a/src/OpenFOAM/containers/Lists/FixedList/FixedListI.H b/src/OpenFOAM/containers/Lists/FixedList/FixedListI.H index 7d590c37994..61fe38572fb 100644 --- a/src/OpenFOAM/containers/Lists/FixedList/FixedListI.H +++ b/src/OpenFOAM/containers/Lists/FixedList/FixedListI.H @@ -499,6 +499,30 @@ Foam::FixedList<T, N>::cbegin() const noexcept } +template<class T, unsigned N> +inline typename Foam::FixedList<T, N>::iterator +Foam::FixedList<T, N>::begin(const int i) noexcept +{ + return (v_ + (i < 0 ? 0 : int(N) < i ? int(N) : i)); +} + + +template<class T, unsigned N> +inline typename Foam::FixedList<T, N>::const_iterator +Foam::FixedList<T, N>::begin(const int i) const noexcept +{ + return (v_ + (i < 0 ? 0 : int(N) < i ? int(N) : i)); +} + + +template<class T, unsigned N> +inline typename Foam::FixedList<T, N>::const_iterator +Foam::FixedList<T, N>::cbegin(const int i) const noexcept +{ + return (v_ + (i < 0 ? 0 : int(N) < i ? int(N) : i)); +} + + template<class T, unsigned N> inline typename Foam::FixedList<T, N>::iterator Foam::FixedList<T, N>::end() noexcept diff --git a/src/OpenFOAM/primitives/VectorSpace/VectorSpace.H b/src/OpenFOAM/primitives/VectorSpace/VectorSpace.H index 048f49bb407..c3f7163c4b7 100644 --- a/src/OpenFOAM/primitives/VectorSpace/VectorSpace.H +++ b/src/OpenFOAM/primitives/VectorSpace/VectorSpace.H @@ -158,7 +158,7 @@ public: // Constructors //- Construct initialized to zero - inline VectorSpace(const Foam::zero); + inline VectorSpace(Foam::zero); //- Copy construct inline VectorSpace(const VectorSpace<Form, Cmpt, Ncmpts>& vs); @@ -174,10 +174,7 @@ public: // Member Functions //- The number of elements in the VectorSpace = Ncmpts. - static constexpr direction size() noexcept - { - return Ncmpts; - } + static constexpr direction size() noexcept { return Ncmpts; } inline const Cmpt& component(const direction) const; inline Cmpt& component(const direction); @@ -186,10 +183,10 @@ public: inline void replace(const direction, const Cmpt&); //- Return const pointer to the first data element - inline const Cmpt* cdata() const noexcept; + const Cmpt* cdata() const noexcept { return v_; } //- Return pointer to the first data element - inline Cmpt* data() noexcept; + Cmpt* data() noexcept { return v_; } //- Assign all components to given value inline void fill(const Cmpt& s); @@ -210,7 +207,7 @@ public: inline void operator+=(const VectorSpace<Form, Cmpt, Ncmpts>&); inline void operator-=(const VectorSpace<Form, Cmpt, Ncmpts>&); - inline void operator=(const Foam::zero); + inline void operator=(Foam::zero); inline void operator*=(const scalar); inline void operator/=(const scalar); @@ -224,28 +221,25 @@ public: typedef const Cmpt* const_iterator; - // Random access iterator (non-const) - - //- Return an iterator to begin of VectorSpace - inline iterator begin() noexcept; - - //- Return an iterator to end of VectorSpace - inline iterator end() noexcept; + // Random access iterators (const and non-const) + //- Return an iterator (pointer) to begin of VectorSpace + iterator begin() noexcept { return v_; } - // Random access iterator (const) + //- Return const_iterator (const pointer) to begin of VectorSpace + const_iterator begin() const noexcept { return v_; } - //- Return const_iterator to begin of VectorSpace - inline const_iterator cbegin() const noexcept; + //- Return const_iterator (const pointer) to begin of VectorSpace + const_iterator cbegin() const noexcept { return v_; } - //- Return const_iterator to end of VectorSpace - inline const_iterator cend() const noexcept; + //- Return an iterator (pointer) to end of VectorSpace + iterator end() noexcept { return (v_ + Ncmpts); } - //- Return const_iterator to begin of VectorSpace - inline const_iterator begin() const noexcept; + //- Return const_iterator (const pointer) to end of VectorSpace + const_iterator end() const noexcept { return (v_ + Ncmpts); } - //- Return const_iterator to end of VectorSpace - inline const_iterator end() const noexcept; + //- Return const_iterator (const pointer) to end of VectorSpace + const_iterator cend() const noexcept { return (v_ + Ncmpts); } // IOstream Operators diff --git a/src/OpenFOAM/primitives/VectorSpace/VectorSpaceI.H b/src/OpenFOAM/primitives/VectorSpace/VectorSpaceI.H index 7f8bbd46dc1..772baa7d4fc 100644 --- a/src/OpenFOAM/primitives/VectorSpace/VectorSpaceI.H +++ b/src/OpenFOAM/primitives/VectorSpace/VectorSpaceI.H @@ -35,9 +35,9 @@ License // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template<class Form, class Cmpt, Foam::direction Ncmpts> -inline Foam::VectorSpace<Form, Cmpt, Ncmpts>::VectorSpace(const Foam::zero) +inline Foam::VectorSpace<Form, Cmpt, Ncmpts>::VectorSpace(Foam::zero) { - VectorSpaceOps<Ncmpts,0>::eqOpS(*this, Zero, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::fill_n(this->begin(), Cmpt(Foam::zero{})); } @@ -47,7 +47,7 @@ inline Foam::VectorSpace<Form, Cmpt, Ncmpts>::VectorSpace const VectorSpace<Form, Cmpt, Ncmpts>& vs ) { - VectorSpaceOps<Ncmpts,0>::eqOp(*this, vs, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::copy_n(vs.cbegin(), this->begin()); } @@ -58,7 +58,7 @@ inline Foam::VectorSpace<Form, Cmpt, Ncmpts>::VectorSpace const VectorSpace<Form2, Cmpt2, Ncmpts>& vs ) { - VectorSpaceOps<Ncmpts,0>::eqOp(*this, vs, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::copy_n(vs.cbegin(), this->begin()); } @@ -163,7 +163,7 @@ inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::replace template<class Form, class Cmpt, Foam::direction Ncmpts> inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::fill(const Cmpt& s) { - VectorSpaceOps<Ncmpts,0>::eqOpS(*this, s, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::fill_n(this->begin(), s); } @@ -171,7 +171,7 @@ template<class Form, class Cmpt, Foam::direction Ncmpts> inline Form Foam::VectorSpace<Form, Cmpt, Ncmpts>::uniform(const Cmpt& s) { Form v; - VectorSpaceOps<Ncmpts,0>::eqOpS(v, s, eqOp<Cmpt>()); + v.fill(s); return v; } @@ -186,68 +186,6 @@ Foam::VectorSpace<Form, Cmpt, Ncmpts>::block() const } -// * * * * * * * * * * * * * * * * Iterator * * * * * * * * * * * * * * * * // - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::data() noexcept -{ - return v_; -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline const Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::cdata() const noexcept -{ - return v_; -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::begin() noexcept -{ - return v_; -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::end() noexcept -{ - return (v_ + Ncmpts); -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline const Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::cbegin() -const noexcept -{ - return v_; -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline const Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::cend() -const noexcept -{ - return (v_ + Ncmpts); -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline const Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::begin() -const noexcept -{ - return v_; -} - - -template<class Form, class Cmpt, Foam::direction Ncmpts> -inline const Cmpt* Foam::VectorSpace<Form, Cmpt, Ncmpts>::end() -const noexcept -{ - return (v_ + Ncmpts); -} - - // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template<class Form, class Cmpt, Foam::direction Ncmpts> @@ -346,7 +284,7 @@ inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::operator= const VectorSpace<Form, Cmpt, Ncmpts>& vs ) { - VectorSpaceOps<Ncmpts,0>::eqOp(*this, vs, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::copy_n(vs.cbegin(), this->begin()); } @@ -371,9 +309,9 @@ inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::operator-= template<class Form, class Cmpt, Foam::direction Ncmpts> -inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::operator=(const Foam::zero) +inline void Foam::VectorSpace<Form, Cmpt, Ncmpts>::operator=(Foam::zero) { - VectorSpaceOps<Ncmpts,0>::eqOpS(*this, 0, eqOp<Cmpt>()); + VectorSpaceOps<Ncmpts>::fill_n(this->begin(), Cmpt(Foam::zero{})); } diff --git a/src/OpenFOAM/primitives/VectorSpace/VectorSpaceOps.H b/src/OpenFOAM/primitives/VectorSpace/VectorSpaceOps.H index c608971b265..bc1e7366880 100644 --- a/src/OpenFOAM/primitives/VectorSpace/VectorSpaceOps.H +++ b/src/OpenFOAM/primitives/VectorSpace/VectorSpaceOps.H @@ -43,9 +43,40 @@ namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // //- Recursive execution. Terminating at \<N\>, starting at index \<I\> -template<direction N, direction I> +template<direction N, direction I=0> struct VectorSpaceOps { + //- Somewhat equivalent to std::copy_n() but with templated loops. + // \param [in] input indexable input data + // \param [out] result indexable output data + template<class Input, class Output> + static inline void copy_n(Input input, Output result) + { + // if constexpr (I < N) + { + result[I] = input[I]; + VectorSpaceOps<N, I+1>::copy_n(input, result); + } + } + + //- Somewhat equivalent to std::fill_n() but with templated loops + // \param [out] result indexable output data + // \param val the value to assign for each entry + template<class Output, class T> + static inline void fill_n(Output result, const T& val) + { + // if constexpr (I < N) + { + result[I] = val; + VectorSpaceOps<N, I+1>::fill_n(result, val); + } + } + + //- Apply the binary assignment operation to each vector-space + //- component. + // \param [in,out] vs vector-space (indexed) data + // \param s scalar/component data (non-indexed) + // \param eo binary combine/assign operation template<class V, class S, class EqOp> static inline void eqOpS(V& vs, const S& s, EqOp eo) { @@ -56,6 +87,10 @@ struct VectorSpaceOps } } + //- Apply the inplace binary reduction operation. + // \param [in,out] s scalar or component data (non-indexed) + // \param [in] vs input vector-space (indexed) data + // \param eo binary combine/assign operation template<class S, class V, class EqOp> static inline void SeqOp(S& s, const V& vs, EqOp eo) { @@ -66,6 +101,10 @@ struct VectorSpaceOps } } + //- Apply the inplace binary assignment operation to the components. + // \param [in,out] vs1 vector-space (indexed) data + // \param [in] vs2 second vector-space (indexed) data + // \param eo binary combine/assign operation template<class V1, class V2, class EqOp> static inline void eqOp(V1& vs1, const V2& vs2, EqOp eo) { @@ -76,34 +115,51 @@ struct VectorSpaceOps } } - - template<class V, class V1, class S, class Op> - static inline void opVS(V& vs, const V1& vs1, const S& s, Op o) + //- Apply the binary operation between vector-space and scalar data + //- and assign the result. + // \param [out] vs vector-space (indexed) data + // \param [in] vs1 vector-space (indexed) data operand + // \param [in] s scalar operand + // \param bop binary operation + template<class V, class V1, class S, class BinaryOp> + static inline void opVS(V& vs, const V1& vs1, const S& s, BinaryOp bop) { // if constexpr (I < N) { - vs.v_[I] = o(vs1.v_[I], s); - VectorSpaceOps<N, I+1>::opVS(vs, vs1, s, o); + vs.v_[I] = bop(vs1.v_[I], s); + VectorSpaceOps<N, I+1>::opVS(vs, vs1, s, bop); } } - template<class V, class S, class V1, class Op> - static inline void opSV(V& vs, const S& s, const V1& vs1, Op o) + //- Apply the binary operation between scalar and vector-space data + //- and assign the result. + // \param [out] vs vector-space (indexed) data + // \param [in] s scalar operand + // \param [in] vs1 vector-space (indexed) data operand + // \param bop binary operation + template<class V, class S, class V1, class BinaryOp> + static inline void opSV(V& vs, const S& s, const V1& vs1, BinaryOp bop) { // if constexpr (I < N) { - vs.v_[I] = o(s, vs1.v_[I]); - VectorSpaceOps<N, I+1>::opSV(vs, s, vs1, o); + vs.v_[I] = bop(s, vs1.v_[I]); + VectorSpaceOps<N, I+1>::opSV(vs, s, vs1, bop); } } - template<class V, class V1, class Op> - static inline void op(V& vs, const V1& vs1, const V1& vs2, Op o) + //- Apply the binary operation between two vector-space data + //- and assign the result. + // \param [out] vs vector-space (indexed) data + // \param [in] vs1 vector-space (indexed) data operand + // \param [in] vs2 vector-space (indexed) data operand + // \param bop binary operation + template<class V, class V1, class BinaryOp> + static inline void op(V& vs, const V1& vs1, const V1& vs2, BinaryOp bop) { // if constexpr (I < N) { - vs.v_[I] = o(vs1.v_[I], vs2.v_[I]); - VectorSpaceOps<N, I+1>::op(vs, vs1, vs2, o); + vs.v_[I] = bop(vs1.v_[I], vs2.v_[I]); + VectorSpaceOps<N, I+1>::op(vs, vs1, vs2, bop); } } }; @@ -115,6 +171,12 @@ struct VectorSpaceOps template<direction N> struct VectorSpaceOps<N, N> { + template<class Input, class Output> + static inline void copy_n(Input, Output) {} + + template<class Output, class T> + static inline void fill_n(Output, const T&) {} + template<class V, class S, class EqOp> static inline void eqOpS(V&, const S&, EqOp) {} @@ -124,14 +186,14 @@ struct VectorSpaceOps<N, N> template<class V1, class V2, class EqOp> static inline void eqOp(V1&, const V2&, EqOp) {} - template<class V, class V1, class S, class Op> - static inline void opVS(V& vs, const V1&, const S&, Op) {} + template<class V, class V1, class S, class BinaryOp> + static inline void opVS(V&, const V1&, const S&, BinaryOp) {} - template<class V, class S, class V1, class Op> - static inline void opSV(V& vs, const S&, const V1&, Op) {} + template<class V, class S, class V1, class BinaryOp> + static inline void opSV(V&, const S&, const V1&, BinaryOp) {} - template<class V, class V1, class Op> - static inline void op(V& vs, const V1&, const V1&, Op) {} + template<class V, class V1, class BinaryOp> + static inline void op(V&, const V1&, const V1&, BinaryOp) {} }; -- GitLab From be30598e3d80babbda8462f3e6d022e7ae52060c Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Mon, 3 Mar 2025 11:13:07 +0100 Subject: [PATCH 04/15] ENH: add UPstream::localNode_parentProcs() method - returns the (start/size) range of the commLocalNode ranks in terms of the (const) world communicator processors. This allows mapping back into lists defined in terms of the world ranks. --- .../test/nodeTopology/Test-nodeTopology.cxx | 7 ++++ src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C | 32 +++++++++++++++++++ src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 7 ++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/applications/test/nodeTopology/Test-nodeTopology.cxx b/applications/test/nodeTopology/Test-nodeTopology.cxx index 9909d51d4f5..58b3d56cde5 100644 --- a/applications/test/nodeTopology/Test-nodeTopology.cxx +++ b/applications/test/nodeTopology/Test-nodeTopology.cxx @@ -115,6 +115,13 @@ int main(int argc, char *argv[]) ); + if (UPstream::parRun()) + { + const auto& procs = UPstream::localNode_parentProcs(); + Perr<< "local processors: [" << procs.min() + << ".." << procs.max() << ']' << endl; + } + // Generate the graph if (UPstream::master(UPstream::worldComm)) { diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C index 4ba0e1f4abb..d3b8e489e3b 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C @@ -791,6 +791,38 @@ const Foam::List<int>& Foam::UPstream::interNode_offsets() } +const Foam::UPstream::rangeType& Foam::UPstream::localNode_parentProcs() +{ + static UPstream::rangeType singleton; + + if (singleton.empty()) + { + // The inter-node offsets [in const world comm] also include a + // startup guard + const auto& offsets = UPstream::interNode_offsets(); + + const auto nodei = + Foam::findLower + ( + offsets, + // My place within const world comm + UPstream::myProcNo(constWorldComm_)+1 + ); + + if (nodei >= 0) + { + singleton.reset + ( + offsets[nodei], + offsets[nodei+1] - offsets[nodei] + ); + } + } + + return singleton; +} + + // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // bool Foam::UPstream::parRun_(false); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index d0e23c298cc..a18d46128e2 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -1232,6 +1232,9 @@ public: //- Processor offsets corresponding to the inter-node communicator static const List<int>& interNode_offsets(); + //- The range (start/size) of the commLocalNode ranks in terms of the + //- (const) world communicator processors. + static const rangeType& localNode_parentProcs(); //- Linear communication schedule (special case) for given communicator static const commsStructList& linearCommunication(int communicator); @@ -1240,8 +1243,8 @@ public: static const commsStructList& treeCommunication(int communicator); //- Communication schedule for all-to-master (proc 0) as - //- linear/tree/none with switching based on UPstream::nProcsSimpleSum - //- and the is_parallel() state and the optional \c linear parameter. + //- linear/tree/none with switching based on UPstream::nProcsSimpleSum, + //- the is_parallel() state and the optional \c linear parameter. static const commsStructList& whichCommunication ( const int communicator, -- GitLab From d4b52807424474998409393aa40f4f09e28e4d96 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 26 Feb 2025 11:50:14 +0100 Subject: [PATCH 05/15] ENH: cleanup broadcast streams - remove unused/unusable broadcast stream constructors/methods - provide OPBstream::sends() and IPBstream::recvs() methods, refactored from Pstream::broadcasts. These will always use serializations, even for contiguous content. - additional methods to support special handling of zero-sized lists. For example, if (UPstream::master(comm)) { if (list.empty()) OPBstream::send(Foam::zero, comm); else OPBstream::send(list, comm); } else { IPBstream is(comm); if (is.remaining()) { is >> list; } else { list.clear(); } } This avoids serialization of an empty list and the resulting double broadcast (size + content), using instead a single broadcast (size). STYLE: more consistency in communicator types (int vs label) --- .../db/IOstreams/Pstreams/IPBstreams.C | 65 ++------- src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H | 53 ++++---- .../db/IOstreams/Pstreams/OPBstreams.C | 68 ++-------- src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H | 56 ++++---- src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H | 11 +- .../IOstreams/Pstreams/PstreamBroadcast.txx | 125 +++++++++++------- .../db/IOstreams/Pstreams/UIPstream.H | 34 +---- .../db/IOstreams/Pstreams/UIPstreamBase.C | 12 ++ .../db/IOstreams/Pstreams/UOPstream.H | 32 ++--- src/Pstream/dummy/UIPBstreamRead.C | 17 +-- src/Pstream/dummy/UOPBstreamWrite.C | 15 +-- src/Pstream/mpi/PstreamGlobals.H | 19 +++ src/Pstream/mpi/UIPBstreamRead.C | 85 ++++-------- src/Pstream/mpi/UOPBstreamWrite.C | 66 +++------ 14 files changed, 253 insertions(+), 405 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/IPBstreams.C b/src/OpenFOAM/db/IOstreams/Pstreams/IPBstreams.C index 54b1305f27e..43fcb428d73 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/IPBstreams.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/IPBstreams.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2024 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,24 +33,21 @@ License Foam::UIPBstream::UIPBstream ( - const UPstream::commsTypes commsType, - const int rootProcNo, DynamicList<char>& receiveBuf, label& receiveBufPosition, - const int tag, - const label comm, + const int communicator, const bool clearAtEnd, IOstreamOption::streamFormat fmt ) : UIPstreamBase ( - commsType, // irrelevant - rootProcNo, // normally UPstream::masterNo() + UPstream::commsTypes::scheduled, // irrelevant + UPstream::masterNo(), // irrelevant receiveBuf, receiveBufPosition, - tag, // irrelevant - comm, + UPstream::msgType(), // irrelevant + communicator, clearAtEnd, fmt ) @@ -61,64 +58,20 @@ Foam::UIPBstream::UIPBstream Foam::IPBstream::IPBstream ( - const UPstream::commsTypes commsType, - const int rootProcNo, - const label bufSize, - const int tag, - const label comm, + const int communicator, IOstreamOption::streamFormat fmt ) : - Pstream(commsType, bufSize), + Pstream(UPstream::commsTypes::scheduled), // type is irrelevant UIPBstream ( - commsType, // irrelevant - rootProcNo, // normally UPstream::masterNo() Pstream::transferBuf_, UIPstreamBase::storedRecvBufPos_, // Internal only - tag, // irrelevant - comm, + communicator, false, // Do not clear Pstream::transferBuf_ if at end fmt ) {} -Foam::IPBstream::IPBstream -( - const int rootProcNo, - const label comm, - IOstreamOption::streamFormat fmt -) -: - IPBstream - ( - UPstream::commsTypes::scheduled, // irrelevant - rootProcNo, - label(0), // bufSize - UPstream::msgType(), // irrelevant - comm, - fmt - ) -{} - - -Foam::IPBstream::IPBstream -( - const label comm, - IOstreamOption::streamFormat fmt -) -: - IPBstream - ( - UPstream::commsTypes::scheduled, // irrelevant - UPstream::masterNo(), // rootProcNo - label(0), // bufSize - UPstream::msgType(), // irrelevant - comm, - fmt - ) -{} - - // ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H index e1304da8851..472353a2cdd 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation - Copyright (C) 2021-2024 OpenCFD Ltd. + Copyright (C) 2021-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -116,31 +116,11 @@ public: // Constructors - //- Construct for broadcast root, optional buffer size, read format - IPBstream - ( - const UPstream::commsTypes, //!< ignored - const int rootProcNo, //!< normally UPstream::masterNo() - const label bufSize = 0, - const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY - ); - - //- Construct for broadcast root and communicator, - //- with optional read format - IPBstream - ( - const int rootProcNo, //!< normally UPstream::masterNo() - const label comm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY - ); - //- Construct with optional communicator and read format. //- Uses UPstream::masterNo() root explicit IPBstream ( - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -154,12 +134,33 @@ public: static void recv ( Type& value, - const label comm = UPstream::worldComm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY + const int communicator = UPstream::worldComm ) { - IPBstream is(comm, fmt); - is >> value; + IPBstream is(communicator); + { + is >> value; + } + } + + //- Receive (from broadcast) a buffer and deserialize + //- multiple items. + //- Uses \c operator>> for de-serialization + template<class Type, class... Args> + static void recvs + ( + const int communicator, + Type& value, + Args&&... values + ) + { + IPBstream is(communicator); + { + Detail::inputLoop(is, value, std::forward<Args>(values)...); + // Depending on compiler support: + // Unpack via fold expression + // (((is >> value) >> std::forward<Args>(values)), ...); + } } }; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/OPBstreams.C b/src/OpenFOAM/db/IOstreams/Pstreams/OPBstreams.C index b68dc927a70..c5aed9a4252 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/OPBstreams.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/OPBstreams.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2024 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,22 +33,19 @@ License Foam::UOPBstream::UOPBstream ( - const UPstream::commsTypes commsType, - const int rootProcNo, DynamicList<char>& sendBuf, - const int tag, - const label comm, + const int communicator, const bool sendAtDestruct, IOstreamOption::streamFormat fmt ) : UOPstreamBase ( - commsType, // irrelevant - rootProcNo, // normally UPstream::masterNo() + UPstream::commsTypes::scheduled, // irrelevant + UPstream::masterNo(), // irrelevant sendBuf, - tag, // irrelevant - comm, + UPstream::msgType(), // irrelevant + communicator, sendAtDestruct, fmt ) @@ -57,65 +54,21 @@ Foam::UOPBstream::UOPBstream Foam::OPBstream::OPBstream ( - const UPstream::commsTypes commsType, - const int rootProcNo, - const label bufSize, - const int tag, - const label comm, + const int communicator, IOstreamOption::streamFormat fmt ) : - Pstream(commsType, bufSize), + Pstream(UPstream::commsTypes::scheduled), // type is irrelevant UOPBstream ( - commsType, // irrelevant - rootProcNo, // normally UPstream::masterNo() Pstream::transferBuf_, - tag, // irrelevant - comm, + communicator, true, // sendAtDestruct fmt ) {} -Foam::OPBstream::OPBstream -( - const int rootProcNo, - const label comm, - IOstreamOption::streamFormat fmt -) -: - OPBstream - ( - UPstream::commsTypes::scheduled, // irrelevant - rootProcNo, - label(0), // bufSize - UPstream::msgType(), // irrelevant - comm, - fmt - ) -{} - - -Foam::OPBstream::OPBstream -( - const label comm, - IOstreamOption::streamFormat fmt -) -: - OPBstream - ( - UPstream::commsTypes::scheduled, // irrelevant - UPstream::masterNo(), // rootProcNo - label(0), // bufSize - UPstream::msgType(), // irrelevant - comm, - fmt - ) -{} - - // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // Foam::UOPBstream::~UOPBstream() @@ -125,8 +78,7 @@ Foam::UOPBstream::~UOPBstream() if (!bufferIPCsend()) { FatalErrorInFunction - << "Failed broadcast message of size " - << sendBuf_.size() << " root: " << toProcNo_ + << "Failed broadcast message of size " << sendBuf_.size() << Foam::abort(FatalError); } } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H index 1b4414a4604..dcdcbda7977 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation - Copyright (C) 2021-2024 OpenCFD Ltd. + Copyright (C) 2021-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -133,49 +133,51 @@ public: // Constructors - //- Construct for broadcast root, optional buffer size, write format - OPBstream - ( - const UPstream::commsTypes, //!< ignored - const int rootProcNo, //!< normally UPstream::masterNo() - const label bufSize = 0, - const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY - ); - - //- Construct for broadcast root and communicator, - //- with optional write format - OPBstream - ( - const int rootProcNo, //!< normally UPstream::masterNo() - const label comm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY - ); - //- Construct with optional communicator and write format. - //- Uses UPstream::masterNo() root explicit OPBstream ( - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); // Static Functions + //- Use all send methods from base + using UOPBstream::send; + //- Serialize a value and broadcast (root == UPstream::masterNo()). //- Uses \c operator<< for serialization template<class Type> static void send ( const Type& value, - const label comm = UPstream::worldComm, - IOstreamOption::streamFormat fmt = IOstreamOption::BINARY + const int communicator = UPstream::worldComm ) { - OPBstream os(comm, fmt); - os << value; + OPBstream os(communicator); + { + os << value; + } + } + + //- Serialize multiple items and broadcast the buffer + //- Uses \c operator<< for serialization + template<class Type, class... Args> + static void sends + ( + const int communicator, + Type& value, + Args&&... values + ) + { + OPBstream os(communicator); + { + Detail::outputLoop(os, value, std::forward<Args>(values)...); + // Depending on compiler support: + // Pack via fold expression + // (((os << value) << std::forward<Args>(values)), ...); + } } }; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index 0e26a4a3998..84d97ee64fe 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -104,13 +104,18 @@ public: static void broadcast ( Type& value, - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Broadcast multiple items to all communicator ranks. //- Does nothing in \b non-parallel. template<class Type, class... Args> - static void broadcasts(const label comm, Type& arg1, Args&&... args); + static void broadcasts + ( + const int communicator, + Type& value, + Args&&... values + ); //- Broadcast list content (contiguous or non-contiguous) to all //- communicator ranks. Does nothing in \b non-parallel. @@ -120,7 +125,7 @@ public: static void broadcastList ( ListType& list, - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx index 90c427ab506..1e9bd139316 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx @@ -25,109 +25,136 @@ License \*---------------------------------------------------------------------------*/ -#include "OPstream.H" #include "IPstream.H" -#include "contiguous.H" +#include "OPstream.H" // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // template<class Type> -void Foam::Pstream::broadcast(Type& value, const label comm) +void Foam::Pstream::broadcast +( + Type& value, + const int communicator +) { - if constexpr (is_contiguous_v<Type>) + if (!UPstream::is_parallel(communicator)) + { + return; + } + else if constexpr (is_contiguous_v<Type>) { // Note: contains parallel guard internally UPstream::broadcast ( reinterpret_cast<char*>(&value), sizeof(Type), - comm + communicator ); } - else if (UPstream::is_parallel(comm)) + else { - if (UPstream::master(comm)) + if (UPstream::master(communicator)) { - OPBstream os(comm); - os << value; + OPBstream::send(value, communicator); } - else // UPstream::is_subrank(comm) + else { - IPBstream is(comm); - is >> value; + IPBstream::recv(value, communicator); } } } template<class Type, class... Args> -void Foam::Pstream::broadcasts(const label comm, Type& arg1, Args&&... args) +void Foam::Pstream::broadcasts +( + const int communicator, + Type& value, + Args&&... values +) { - if (UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) + { + return; + } + else { - if (UPstream::master(comm)) + if (UPstream::master(communicator)) { - OPBstream os(comm); - Detail::outputLoop(os, arg1, std::forward<Args>(args)...); + OPBstream::sends + ( + communicator, + value, + std::forward<Args>(values)... + ); } - else // UPstream::is_subrank(comm) + else { - IPBstream is(comm); - Detail::inputLoop(is, arg1, std::forward<Args>(args)...); + IPBstream::recvs + ( + communicator, + value, + std::forward<Args>(values)... + ); } } } template<class ListType> -void Foam::Pstream::broadcastList(ListType& list, const label comm) +void Foam::Pstream::broadcastList +( + ListType& list, + const int communicator +) { - if constexpr (is_contiguous_v<typename ListType::value_type>) + if (!UPstream::is_parallel(communicator)) + { + return; + } + else if constexpr (is_contiguous_v<typename ListType::value_type>) { // List data are contiguous // 1. broadcast the size // 2. resize for receiver list // 3. broadcast contiguous contents - if (UPstream::is_parallel(comm)) + label len(list.size()); + + UPstream::broadcast + ( + reinterpret_cast<char*>(&len), + sizeof(label), + communicator + ); + + if (UPstream::is_subrank(communicator)) { - label len(list.size()); + list.resize_nocopy(len); + } + if (len) + { UPstream::broadcast ( - reinterpret_cast<char*>(&len), - sizeof(label), - comm + list.data_bytes(), + list.size_bytes(), + communicator ); - - if (UPstream::is_subrank(comm)) - { - list.resize_nocopy(len); - } - - if (len) - { - UPstream::broadcast - ( - list.data_bytes(), - list.size_bytes(), - comm - ); - } } } - else if (UPstream::is_parallel(comm)) + else { // List data are non-contiguous - serialize/de-serialize - if (UPstream::master(comm)) + if (UPstream::master(communicator)) { - OPBstream os(comm); + OPBstream os(communicator); os << list; } - else // UPstream::is_subrank(comm) + else { - IPBstream is(comm); + IPBstream is(communicator); is >> list; } } @@ -148,11 +175,11 @@ template<class Type> Type returnBroadcast ( const Type& value, - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { Type work(value); - Pstream::broadcast(work, comm); + Pstream::broadcast(work, communicator); return work; } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H index eb2deb9a87d..dbce6dc0109 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2013 OpenFOAM Foundation - Copyright (C) 2017-2024 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -165,6 +165,9 @@ public: return std::ios_base::fmtflags(0); } + //- The number of characters remaining in the get buffer + label remaining() const noexcept; + // Read Functions @@ -447,17 +450,13 @@ public: // Constructors - //- Construct given process index to read from using the given - //- attached receive buffer, optional communication characteristics - //- and IO format + //- Construct using the given attached receive buffer, + // optional communication characteristics and IO format UIPBstream ( - const UPstream::commsTypes, //!< irrelevant - const int rootProcNo, //!< normally UPstream::masterNo() DynamicList<char>& receiveBuf, label& receiveBufPosition, - const int tag = UPstream::msgType(), //!< irrelevant - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool clearAtEnd = false, //!< destroy receiveBuf if at end IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -465,25 +464,6 @@ public: //- Destructor virtual ~UIPBstream() = default; - - - // Member Functions - - //- Use all read methods from base - using UIPstreamBase::read; - - - // Static Functions - - //- Wrapped version of UPstream::broadcast - // \return the message size (bytes read). May change in the future - static std::streamsize read - ( - const int rootProcNo, //!< normally UPstream::masterNo() - char* buf, - const std::streamsize bufSize, - const label comm = UPstream::worldComm - ); }; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C index cfbb3241646..9ea930111f2 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C @@ -548,6 +548,18 @@ bool Foam::UIPstreamBase::beginRawRead() /// return recvBufPos_; /// } +Foam::label Foam::UIPstreamBase::remaining() const noexcept +{ + if (messageSize_ && (recvBufPos_ < recvBuf_.size())) + { + return (recvBuf_.size() - recvBufPos_); + } + else + { + return 0; + } +} + void Foam::UIPstreamBase::rewind() { diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H index e96a05d8754..34c49685119 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2017-2024 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -481,16 +481,12 @@ public: // Constructors - //- Construct given process index to write to using the given - //- attached send buffer, optional communication characteristics - //- and IO format - UOPBstream + //- Construct with attached send buffer, + //- optional communication characteristics and IO format + explicit UOPBstream ( - const UPstream::commsTypes, //!< irrelevant - const int toProcNo, //!< normally UPstream::masterNo() DynamicList<char>& sendBuf, - const int tag = UPstream::msgType(), //!< irrelevant - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool sendAtDestruct = true, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -502,21 +498,9 @@ public: // Member Functions - //- Use all write methods from base - using UOPstreamBase::write; - - - // Static Functions - - //- Wrapped version of UPstream::broadcast with const-cast - // \return True on success - static bool write - ( - const int rootProcNo, //!< normally UPstream::masterNo() - const char* buf, - const std::streamsize bufSize, - const label comm = UPstream::worldComm - ); + //- Broadcast a zero value (buffer) size that can be matched + //- by the UIPBstream constructor. + static void send(Foam::zero, const int communicator); }; diff --git a/src/Pstream/dummy/UIPBstreamRead.C b/src/Pstream/dummy/UIPBstreamRead.C index 31e0f0743fa..2a30bd5cbb0 100644 --- a/src/Pstream/dummy/UIPBstreamRead.C +++ b/src/Pstream/dummy/UIPBstreamRead.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2024 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -35,19 +35,4 @@ void Foam::UIPBstream::bufferIPCrecv() } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -std::streamsize Foam::UIPBstream::read -( - const int rootProcNo, - char* buf, - const std::streamsize bufSize, - const label comm -) -{ - NotImplemented; - return 0; -} - - // ************************************************************************* // diff --git a/src/Pstream/dummy/UOPBstreamWrite.C b/src/Pstream/dummy/UOPBstreamWrite.C index 72c702f0343..794791fc614 100644 --- a/src/Pstream/dummy/UOPBstreamWrite.C +++ b/src/Pstream/dummy/UOPBstreamWrite.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,17 +38,8 @@ bool Foam::UOPBstream::bufferIPCsend() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::UOPBstream::write -( - const int rootProcNo, - const char* buf, - const std::streamsize bufSize, - const label comm -) -{ - NotImplemented; - return false; -} +void Foam::UOPBstream::send(Foam::zero, const int communicator) +{} // ************************************************************************* // diff --git a/src/Pstream/mpi/PstreamGlobals.H b/src/Pstream/mpi/PstreamGlobals.H index bf46434ad78..dd7930209d6 100644 --- a/src/Pstream/mpi/PstreamGlobals.H +++ b/src/Pstream/mpi/PstreamGlobals.H @@ -203,6 +203,25 @@ inline void push_request } +// * * * * * * * * * * * * * * Convenience Methods * * * * * * * * * * * * * // + +//- Broadcast a single int64 value. +// +// Ensures consistent data types. Used within the following: +// - UIPBstream::bufferIPCrecv() +// - UOPBstream::bufferIPCsend() +// - UOPBstream::send(Foam::zero, ...) + +inline bool broadcast_int64(int64_t& value, int comm) +{ + return + ( + MPI_SUCCESS + == MPI_Bcast(&value, 1, MPI_INT64_T, 0, MPICommunicators_[comm]) + ); +} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace PstreamGlobals diff --git a/src/Pstream/mpi/UIPBstreamRead.C b/src/Pstream/mpi/UIPBstreamRead.C index 5080583396c..22b5fa48111 100644 --- a/src/Pstream/mpi/UIPBstreamRead.C +++ b/src/Pstream/mpi/UIPBstreamRead.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2024 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,8 +26,8 @@ License \*---------------------------------------------------------------------------*/ #include "UIPstream.H" -#include "PstreamGlobals.H" #include "IOstreams.H" +#include "PstreamGlobals.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // @@ -37,33 +37,32 @@ void Foam::UIPBstream::bufferIPCrecv() // 1. for the data size // 2. for the data itself - // Expected message size, similar to MPI_Probe - // Same type must be expected in UOPBstream::bufferIPCsend() - std::streamsize bufSize(0); - // Broadcast #1 - data size - if - ( - !UPstream::broadcast - ( - reinterpret_cast<char*>(&bufSize), - sizeof(std::streamsize), - comm_, - fromProcNo_ //< is actually rootProcNo - ) - ) + // Same data type must be used in UOPBstream::bufferIPCsend() + + int64_t count(0); + if (!PstreamGlobals::broadcast_int64(count, comm_)) { FatalErrorInFunction - << "MPI_Bcast failure receiving buffer size" << nl + << "Broadcast failure receiving buffer size" << nl + << " comm:" << comm_ << nl << Foam::abort(FatalError); } - if (UPstream::debug) + // This is not actually possible - sender uses List::size() + // + // if (FOAM_UNLIKELY(count > int64_t(UList<char>::max_size()))) + // { + // FatalErrorInFunction + // << "Broadcast list size larger than UList<char>::max_size()" + // << Foam::abort(FatalError); + // } + + if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UOPBstream IPC read buffer :" - << " root:" << fromProcNo_ + Perr<< "UIPBstream IPC read buffer :" << " comm:" << comm_ - << " probed size:" << label(bufSize) + << " probed size:" << label(count) << " wanted size:" << recvBuf_.capacity() << Foam::endl; } @@ -71,33 +70,32 @@ void Foam::UIPBstream::bufferIPCrecv() // Set buffer size, avoiding any copying and resize doubling etc. recvBuf_.clear(); - if (recvBuf_.capacity() < label(bufSize)) + if (recvBuf_.capacity() < label(count)) { - recvBuf_.setCapacity_nocopy(label(bufSize)); + recvBuf_.setCapacity_nocopy(label(count)); } - recvBuf_.resize_nocopy(label(bufSize)); + recvBuf_.resize_nocopy(label(count)); // This is the only real information we can trust - messageSize_ = label(bufSize); + messageSize_ = label(count); // Broadcast #2 - data content // - skip if there is no data to receive if ( - (bufSize > 0) + (count > 0) // ie, not empty && !UPstream::broadcast ( recvBuf_.data(), - recvBuf_.size(), // same as bufSize - comm_, - fromProcNo_ //< is actually rootProcNo + recvBuf_.size(), // same as count + comm_ ) ) { FatalErrorInFunction - << "MPI_Bcast failure receiving buffer data:" - << recvBuf_.size() << nl + << "Broadcast failure receiving buffer data:" + << recvBuf_.size() << " comm:" << comm_ << nl << Foam::abort(FatalError); } @@ -108,29 +106,4 @@ void Foam::UIPBstream::bufferIPCrecv() } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -std::streamsize Foam::UIPBstream::read -( - const int rootProcNo, - char* buf, - const std::streamsize bufSize, - const label comm -) -{ - if - ( - !UPstream::broadcast(buf, bufSize, comm, rootProcNo) - ) - { - FatalErrorInFunction - << "MPI_Bcast failure receiving data:" << label(bufSize) << nl - << Foam::abort(FatalError); - return 0; - } - - return bufSize; -} - - // ************************************************************************* // diff --git a/src/Pstream/mpi/UOPBstreamWrite.C b/src/Pstream/mpi/UOPBstreamWrite.C index f4c9412fca4..6a9348e8806 100644 --- a/src/Pstream/mpi/UOPBstreamWrite.C +++ b/src/Pstream/mpi/UOPBstreamWrite.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -39,55 +39,35 @@ bool Foam::UOPBstream::bufferIPCsend() PstreamGlobals::checkCommunicator(comm_, toProcNo_); - // Same type must be expected in UIPBstream::bufferIPCrecv() - std::streamsize bufSize(sendBuf_.size()); - - // TODO: some corrective action - #if 0 - if (bufSize > std::streamsize(INT_MAX)) - { - Perr<< "UOPBstream::write() :" - << " exceeds INT_MAX bytes" << Foam::endl; - error::printStack(Perr); - } - #endif - // Broadcast #1 - data size - if - ( - !UPstream::broadcast - ( - reinterpret_cast<char*>(&bufSize), - sizeof(std::streamsize), - comm_, - toProcNo_ //< is actually rootProcNo - ) - ) + // Same data type must be used in UIPBstream::bufferIPCrecv() + + int64_t count(sendBuf_.size()); + if (!PstreamGlobals::broadcast_int64(count, comm_)) { FatalErrorInFunction - << "MPI_Bcast failure sending buffer size:" << bufSize << nl + << "Broadcast failure sending buffer size:" + << label(count) << " comm:" << comm_ << nl << Foam::abort(FatalError); return false; } - // Broadcast #2 - data content // - skip if there is no data to send if ( - (bufSize > 0) + (count > 0) // ie, not empty && !UPstream::broadcast ( sendBuf_.data(), - sendBuf_.size(), // same as bufSize - comm_, - toProcNo_ //< is actually rootProcNo + sendBuf_.size(), // same as count + comm_ ) ) { FatalErrorInFunction - << "MPI_Bcast failure sending buffer data:" - << sendBuf_.size() << nl + << "Broadcast failure sending buffer data:" + << sendBuf_.size() << " comm:" << comm_ << nl << Foam::abort(FatalError); return false; } @@ -98,26 +78,10 @@ bool Foam::UOPBstream::bufferIPCsend() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::UOPBstream::write -( - const int rootProcNo, - const char* buf, - const std::streamsize bufSize, - const label comm -) +void Foam::UOPBstream::send(Foam::zero, const int communicator) { - if - ( - !UPstream::broadcast(const_cast<char*>(buf), bufSize, comm, rootProcNo) - ) - { - FatalErrorInFunction - << "MPI_Bcast failure sending buffer data:" << label(bufSize) << nl - << Foam::abort(FatalError); - return false; - } - - return true; + int64_t count(0); + PstreamGlobals::broadcast_int64(count, communicator); } -- GitLab From 8c395357f39e4a070bbbf51a6d5897484d640599 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 26 Feb 2025 11:50:14 +0100 Subject: [PATCH 06/15] STYLE: more consistency in communicator types (int vs label) --- .../test/globalIndex3/Test-globalIndex3.cxx | 2 +- src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H | 11 +++-- .../db/IOstreams/Pstreams/IPstreams.C | 14 +++---- src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H | 15 ++++--- .../db/IOstreams/Pstreams/OPstreams.C | 12 +++--- src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H | 18 +++++---- .../db/IOstreams/Pstreams/PstreamBuffers.C | 6 +-- .../db/IOstreams/Pstreams/PstreamBuffers.H | 37 +++++------------ .../db/IOstreams/Pstreams/UIPstream.H | 26 ++++++------ .../db/IOstreams/Pstreams/UIPstreamBase.C | 4 +- .../db/IOstreams/Pstreams/UOPstream.H | 18 ++++----- .../db/IOstreams/Pstreams/UOPstreamBase.C | 4 +- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C | 15 ++++--- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 40 +++++++++---------- .../db/IOstreams/Pstreams/UPstreamWindow.H | 5 +++ src/Pstream/dummy/UIPstreamRead.C | 4 +- src/Pstream/dummy/UOPstreamWrite.C | 4 +- src/Pstream/dummy/UPstreamCommunicator.C | 10 ++++- src/Pstream/dummy/UPstreamWindow.C | 6 +++ src/Pstream/mpi/UIPstreamRead.C | 6 +-- src/Pstream/mpi/UOPstreamWrite.C | 4 +- src/Pstream/mpi/UPstreamCommunicator.C | 27 ++++++++++++- src/Pstream/mpi/UPstreamWindow.C | 25 ++++++++++++ 23 files changed, 181 insertions(+), 132 deletions(-) diff --git a/applications/test/globalIndex3/Test-globalIndex3.cxx b/applications/test/globalIndex3/Test-globalIndex3.cxx index 19a72499d32..d6ae4a658e5 100644 --- a/applications/test/globalIndex3/Test-globalIndex3.cxx +++ b/applications/test/globalIndex3/Test-globalIndex3.cxx @@ -508,7 +508,7 @@ int main(int argc, char *argv[]) #include "setRootCase.H" - const bool useLocalComms = UPstream::usingNodeComms(); + const bool useLocalComms = UPstream::usingNodeComms(UPstream::worldComm); bool useWindow = args.found("window"); bool useBuiltin = args.found("builtin"); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H index 472353a2cdd..056d3dd0fba 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/IPstream.H @@ -61,14 +61,13 @@ public: // Constructors //- Construct given process index to read from - //- and optional buffer size, read format IPstream ( const UPstream::commsTypes commsType, const int fromProcNo, - const label bufSize = 0, + const int bufferSize = 0, //!< optional buffer size const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -83,7 +82,7 @@ public: Type& value, const int fromProcNo, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ) { @@ -91,9 +90,9 @@ public: ( UPstream::commsTypes::scheduled, // ie, MPI_Recv() fromProcNo, - 0, // bufSize + 0, // bufferSize tag, - comm, + communicator, fmt ); is >> value; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/IPstreams.C b/src/OpenFOAM/db/IOstreams/Pstreams/IPstreams.C index 340f0a2f990..667970803bc 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/IPstreams.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/IPstreams.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,7 +38,7 @@ Foam::UIPstream::UIPstream DynamicList<char>& receiveBuf, label& receiveBufPosition, const int tag, - const label comm, + const int communicator, const bool clearAtEnd, IOstreamOption::streamFormat fmt ) @@ -50,7 +50,7 @@ Foam::UIPstream::UIPstream receiveBuf, receiveBufPosition, tag, - comm, + communicator, clearAtEnd, fmt ) @@ -105,13 +105,13 @@ Foam::IPstream::IPstream ( const UPstream::commsTypes commsType, const int fromProcNo, - const label bufSize, + const int bufferSize, const int tag, - const label comm, + const int communicator, IOstreamOption::streamFormat fmt ) : - Pstream(commsType, bufSize), + Pstream(commsType, bufferSize), UIPstream ( commsType, @@ -119,7 +119,7 @@ Foam::IPstream::IPstream Pstream::transferBuf_, UIPstreamBase::storedRecvBufPos_, // Internal only tag, - comm, + communicator, false, // Do not clear Pstream::transferBuf_ if at end fmt ) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H index dcdcbda7977..8513b4fbf12 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/OPstream.H @@ -61,14 +61,13 @@ public: // Constructors //- Construct for given process index to send to - //- and optional buffer size, write format OPstream ( const UPstream::commsTypes commsType, const int toProcNo, - const label bufSize = 0, + const int bufferSize = 0, //!< optional buffer size const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -81,15 +80,15 @@ public: static void send ( const Type& value, - //! blocking or scheduled only! + //! buffered or scheduled only! const UPstream::commsTypes commsType, const int toProcNo, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ) { - OPstream os(commsType, toProcNo, 0, tag, comm, fmt); + OPstream os(commsType, toProcNo, 0, tag, communicator, fmt); os << value; } @@ -101,7 +100,7 @@ public: const Type& value, const int toProcNo, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ) { @@ -111,7 +110,7 @@ public: UPstream::commsTypes::scheduled, // ie, MPI_Send() toProcNo, tag, - comm, + communicator, fmt ); } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/OPstreams.C b/src/OpenFOAM/db/IOstreams/Pstreams/OPstreams.C index fc8312f6749..281bc01a687 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/OPstreams.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/OPstreams.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011 OpenFOAM Foundation - Copyright (C) 2022-2024 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -37,7 +37,7 @@ Foam::UOPstream::UOPstream const int toProcNo, DynamicList<char>& sendBuf, const int tag, - const label comm, + const int comm, const bool sendAtDestruct, IOstreamOption::streamFormat fmt ) @@ -66,20 +66,20 @@ Foam::OPstream::OPstream ( const UPstream::commsTypes commsType, const int toProcNo, - const label bufSize, + const int bufferSize, const int tag, - const label comm, + const int communicator, IOstreamOption::streamFormat fmt ) : - Pstream(commsType, bufSize), + Pstream(commsType, bufferSize), UOPstream ( commsType, toProcNo, Pstream::transferBuf_, tag, - comm, + communicator, true, // sendAtDestruct fmt ) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index 84d97ee64fe..ef8acb773b1 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -75,18 +75,20 @@ public: // Constructors - //- Construct for given communication type, with optional buffer size - explicit Pstream - ( - const UPstream::commsTypes commsType, - const label bufSize = 0 - ) + //- Construct for communication type with empty buffer + explicit Pstream(const UPstream::commsTypes commsType) noexcept + : + UPstream(commsType) + {} + + //- Construct for communication type with given buffer size + Pstream(const UPstream::commsTypes commsType, int bufferSize) : UPstream(commsType) { - if (bufSize > 0) + if (bufferSize > 0) { - transferBuf_.setCapacity(bufSize + 2*sizeof(scalar) + 1); + transferBuf_.setCapacity(bufferSize + 2*sizeof(scalar) + 1); } } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.C b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.C index 391c094beac..5332f3cf895 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2021-2023 OpenCFD Ltd. + Copyright (C) 2021-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -300,7 +300,7 @@ Foam::PstreamBuffers::PstreamBuffers ( UPstream::commsTypes commsType, int tag, - label communicator, + int communicator, IOstreamOption::streamFormat fmt ) : @@ -313,7 +313,7 @@ Foam::PstreamBuffers::PstreamBuffers nProcs_(UPstream::nProcs(comm_)), sendBuffers_(nProcs_), recvBuffers_(nProcs_), - recvPositions_(nProcs_, Zero) + recvPositions_(nProcs_, Foam::zero{}) { DebugPoutInFunction << "tag:" << tag_ diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.H b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.H index 97cb68fe9ac..d80607d3799 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBuffers.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2021-2023 OpenCFD Ltd. + Copyright (C) 2021-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -182,10 +182,10 @@ class PstreamBuffers const int tag_; //- Communicator - const label comm_; + const int comm_; //- Number of ranks associated with PstreamBuffers (at construction) - const label nProcs_; + const int nProcs_; // Buffer storage @@ -266,7 +266,7 @@ public: ( UPstream::commsTypes commsType = UPstream::commsTypes::nonBlocking, int tag = UPstream::msgType(), - label communicator = UPstream::worldComm, + int communicator = UPstream::worldComm, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -274,7 +274,7 @@ public: //- (default: nonBlocking), message tag, IO format (default: binary) explicit PstreamBuffers ( - label communicator, + int communicator, UPstream::commsTypes commsType = UPstream::commsTypes::nonBlocking, int tag = UPstream::msgType(), IOstreamOption::streamFormat fmt = IOstreamOption::BINARY @@ -287,7 +287,7 @@ public: //- (default: nonBlocking), IO format (default: binary) PstreamBuffers ( - label communicator, + int communicator, int tag, UPstream::commsTypes commsType = UPstream::commsTypes::nonBlocking, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY @@ -306,34 +306,19 @@ public: // Attributes //- The associated buffer format (ascii | binary) - IOstreamOption::streamFormat format() const noexcept - { - return format_; - } + IOstreamOption::streamFormat format() const noexcept { return format_; } //- The communications type of the stream - UPstream::commsTypes commsType() const noexcept - { - return commsType_; - } + UPstream::commsTypes commsType() const noexcept { return commsType_; } //- The transfer message tag - int tag() const noexcept - { - return tag_; - } + int tag() const noexcept { return tag_; } //- The communicator index - label comm() const noexcept - { - return comm_; - } + int comm() const noexcept { return comm_; } //- Number of ranks associated with PstreamBuffers - label nProcs() const noexcept - { - return nProcs_; - } + int nProcs() const noexcept { return nProcs_; } // Sizing diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H index dbce6dc0109..33b40e8a22b 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H @@ -124,7 +124,7 @@ protected: DynamicList<char>& receiveBuf, label& receiveBufPosition, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool clearAtEnd = false, // destroy receiveBuf if at end IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -252,7 +252,7 @@ public: DynamicList<char>& receiveBuf, label& receiveBufPosition, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool clearAtEnd = false, // destroy receiveBuf if at end IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -292,7 +292,7 @@ public: char* buf, const std::streamsize bufSize, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr ); @@ -307,7 +307,7 @@ public: char* buf, const std::streamsize bufSize, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { return UIPstream::read @@ -317,7 +317,7 @@ public: buf, bufSize, tag, - comm, + communicator, &req ); } @@ -332,7 +332,7 @@ public: const int fromProcNo, UList<Type>& buffer, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr ) @@ -344,7 +344,7 @@ public: buffer.data_bytes(), buffer.size_bytes(), tag, - comm, + communicator, req ); } @@ -359,7 +359,7 @@ public: const int fromProcNo, SubList<Type> buffer, // passed by shallow copy const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr ) @@ -371,7 +371,7 @@ public: buffer.data_bytes(), buffer.size_bytes(), tag, - comm, + communicator, req ); } @@ -387,7 +387,7 @@ public: const int fromProcNo, UList<Type>& buffer, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { return UIPstream::read @@ -397,7 +397,7 @@ public: buffer.data_bytes(), buffer.size_bytes(), tag, - comm, + communicator, &req ); } @@ -413,7 +413,7 @@ public: const int fromProcNo, SubList<Type> buffer, // passed by shallow copy const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { return UIPstream::read @@ -423,7 +423,7 @@ public: buffer.data_bytes(), buffer.size_bytes(), tag, - comm, + communicator, &req ); } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C index 9ea930111f2..c9444e67353 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstreamBase.C @@ -167,7 +167,7 @@ Foam::UIPstreamBase::UIPstreamBase DynamicList<char>& receiveBuf, label& receiveBufPosition, const int tag, - const label comm, + const int communicator, const bool clearAtEnd, IOstreamOption::streamFormat fmt ) @@ -176,7 +176,7 @@ Foam::UIPstreamBase::UIPstreamBase Istream(fmt), fromProcNo_(fromProcNo), tag_(tag), - comm_(comm), + comm_(communicator), messageSize_(0), storedRecvBufPos_(0), clearAtEnd_(clearAtEnd), diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H index 34c49685119..d1550c4d9c5 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H @@ -121,7 +121,7 @@ protected: const int toProcNo, DynamicList<char>& sendBuf, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool sendAtDestruct = true, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -325,7 +325,7 @@ public: const int toProcNo, DynamicList<char>& sendBuf, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const bool sendAtDestruct = true, IOstreamOption::streamFormat fmt = IOstreamOption::BINARY ); @@ -367,7 +367,7 @@ public: const char* buf, const std::streamsize bufSize, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr, const UPstream::sendModes sendMode = UPstream::sendModes::normal @@ -383,7 +383,7 @@ public: const char* buf, const std::streamsize bufSize, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const UPstream::sendModes sendMode = UPstream::sendModes::normal ) { @@ -394,7 +394,7 @@ public: buf, bufSize, tag, - comm, + communicator, &req, sendMode ); @@ -410,7 +410,7 @@ public: const int toProcNo, const UList<Type>& buffer, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr, const UPstream::sendModes sendMode = UPstream::sendModes::normal @@ -423,7 +423,7 @@ public: buffer.cdata_bytes(), buffer.size_bytes(), tag, - comm, + communicator, req, sendMode ); @@ -440,7 +440,7 @@ public: const int toProcNo, const UList<Type>& buffer, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, const UPstream::sendModes sendMode = UPstream::sendModes::normal ) { @@ -451,7 +451,7 @@ public: buffer.cdata_bytes(), buffer.size_bytes(), tag, - comm, + communicator, &req, sendMode ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstreamBase.C b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstreamBase.C index e07c5320e8f..cc665f0cb64 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstreamBase.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstreamBase.C @@ -146,7 +146,7 @@ Foam::UOPstreamBase::UOPstreamBase const int toProcNo, DynamicList<char>& sendBuf, const int tag, - const label comm, + const int communicator, const bool sendAtDestruct, IOstreamOption::streamFormat fmt ) @@ -155,7 +155,7 @@ Foam::UOPstreamBase::UOPstreamBase Ostream(fmt), toProcNo_(toProcNo), tag_(tag), - comm_(comm), + comm_(communicator), sendAtDestruct_(sendAtDestruct), sendBuf_(sendBuf) { diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C index d3b8e489e3b..2c1d72b143a 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C @@ -112,7 +112,7 @@ void Foam::UPstream::printTopoControl(Ostream& os) // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -void Foam::UPstream::setParRun(const label nProcs, const bool haveThreads) +void Foam::UPstream::setParRun(const int nProcs, const bool haveThreads) { parRun_ = (nProcs > 0); haveThreads_ = haveThreads; @@ -725,7 +725,7 @@ void Foam::UPstream::printCommTree } -bool Foam::UPstream::usingNodeComms(const label communicator) +bool Foam::UPstream::usingNodeComms(const int communicator) { // Starting point must be "real" world-communicator // ("real" means without any local trickery with worldComm) @@ -849,10 +849,10 @@ Foam::DynamicList<Foam::UPstream::commsStructList> Foam::UPstream::treeCommunication_(16); -Foam::label Foam::UPstream::constWorldComm_(0); -Foam::label Foam::UPstream::numNodes_(1); -Foam::label Foam::UPstream::commInterNode_(-1); -Foam::label Foam::UPstream::commLocalNode_(-1); +int Foam::UPstream::constWorldComm_(0); +int Foam::UPstream::commInterNode_(-1); +int Foam::UPstream::commLocalNode_(-1); +int Foam::UPstream::numNodes_(1); Foam::label Foam::UPstream::worldComm(0); // Initially same as constWorldComm_ Foam::label Foam::UPstream::warnComm(-1); @@ -860,7 +860,7 @@ Foam::label Foam::UPstream::warnComm(-1); // Predefine world and self communicator slots. // These are overwritten in parallel mode (by UPstream::setParRun()) -const Foam::label nPredefinedComm = []() +const int nPredefinedComm = []() { // 0: COMM_WORLD : commGlobal(), constWorldComm_, worldComm (void) Foam::UPstream::newCommunicator(-1, Foam::labelRange(1), false); @@ -894,7 +894,6 @@ registerOptSwitch Foam::UPstream::nodeCommsMin_ ); - int Foam::UPstream::topologyControl_ ( Foam::debug::optimisationSwitch("topoControl", 0) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index a18d46128e2..3ce948183f4 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -389,18 +389,18 @@ private: //- Index to the world-communicator as defined at startup //- (after any multi-world definitions). //- Is unaffected by any later changes to worldComm. - static label constWorldComm_; - - //- The number of shared/host nodes in the (const) world communicator. - static label numNodes_; + static int constWorldComm_; //- Index to the inter-node communicator (between nodes), //- defined based on constWorldComm_ - static label commInterNode_; + static int commInterNode_; //- Index to the intra-host communicator (within a node), //- defined based on constWorldComm_ - static label commLocalNode_; + static int commLocalNode_; + + //- The number of shared/host nodes in the (const) world communicator. + static int numNodes_; //- Names of all worlds static wordList allWorlds_; @@ -433,7 +433,7 @@ private: // Private Member Functions //- Set data for parallel running - static void setParRun(const label nProcs, const bool haveThreads); + static void setParRun(const int nProcs, const bool haveThreads); //- Initialise entries for new communicator. // @@ -557,16 +557,16 @@ public: //- Communicator for all ranks, irrespective of any local worlds. // This value \em never changes during a simulation. - static constexpr label commGlobal() noexcept { return 0; } + static constexpr int commGlobal() noexcept { return 0; } //- Communicator within the current rank only // This value \em never changes during a simulation. - static constexpr label commSelf() noexcept { return 1; } + static constexpr int commSelf() noexcept { return 1; } //- Communicator for all ranks (respecting any local worlds). // This value \em never changes after startup. Unlike the commWorld() // which can be temporarily overriden. - static label commConstWorld() noexcept { return constWorldComm_; } + static int commConstWorld() noexcept { return constWorldComm_; } //- Communicator for all ranks (respecting any local worlds) static label commWorld() noexcept { return worldComm; } @@ -601,13 +601,13 @@ public: // Host Communicators //- Communicator between nodes/hosts (respects any local worlds) - static label commInterNode() noexcept + static int commInterNode() noexcept { return (parRun_ ? commInterNode_ : constWorldComm_); } //- Communicator within the node/host (respects any local worlds) - static label commLocalNode() noexcept + static int commLocalNode() noexcept { return (parRun_ ? commLocalNode_ : constWorldComm_); } @@ -626,7 +626,7 @@ public: //- it is running in parallel, the starting point is the //- world-communicator and it is not an odd corner case //- (ie, all processes on one node, all processes on different nodes) - static bool usingNodeComms(const label communicator = worldComm); + static bool usingNodeComms(const int communicator); // Constructors @@ -1168,19 +1168,16 @@ public: } //- The number of shared/host nodes in the (const) world communicator. - static label numNodes() noexcept - { - return numNodes_; - } + static int numNodes() noexcept { return numNodes_; } //- The parent communicator - static label parent(const label communicator) + static label parent(int communicator) { return parentComm_(communicator); } //- The list of ranks within a given communicator - static List<int>& procID(const label communicator) + static List<int>& procID(int communicator) { return procIDs_[communicator]; } @@ -1694,7 +1691,7 @@ public: // UPstream::Communicator::lookup(UPstream::commWorld()) // ) // \endcode - static Communicator lookup(const label comm); + static Communicator lookup(const int comm); // Member Functions @@ -1713,6 +1710,9 @@ public: //- Reset to default constructed value (MPI_COMM_NULL) void reset() noexcept; + + //- The number of ranks associated with the communicator + int size() const; }; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamWindow.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamWindow.H index aa3ef233f87..54ce90aecc9 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamWindow.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamWindow.H @@ -137,6 +137,11 @@ public: //- Reset to default constructed value (MPI_WIN_NULL) void reset() noexcept; + + //- The number of ranks associated with the window group. + // The same as querying the original communicator, assuming the + // communicator is available within the current code scope. + int size() const; }; diff --git a/src/Pstream/dummy/UIPstreamRead.C b/src/Pstream/dummy/UIPstreamRead.C index c8b7286fdf6..7c82adb7f3f 100644 --- a/src/Pstream/dummy/UIPstreamRead.C +++ b/src/Pstream/dummy/UIPstreamRead.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2021-2024 OpenCFD Ltd. + Copyright (C) 2021-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -45,7 +45,7 @@ std::streamsize Foam::UIPstream::read char* buf, const std::streamsize bufSize, const int tag, - const label communicator, + const int communicator, UPstream::Request* req ) { diff --git a/src/Pstream/dummy/UOPstreamWrite.C b/src/Pstream/dummy/UOPstreamWrite.C index 24078ca9244..dfd4be78afe 100644 --- a/src/Pstream/dummy/UOPstreamWrite.C +++ b/src/Pstream/dummy/UOPstreamWrite.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -46,7 +46,7 @@ bool Foam::UOPstream::write const char* buf, const std::streamsize bufSize, const int tag, - const label communicator, + const int communicator, UPstream::Request* req, const UPstream::sendModes sendMode ) diff --git a/src/Pstream/dummy/UPstreamCommunicator.C b/src/Pstream/dummy/UPstreamCommunicator.C index e7c713f85c5..29055a6da2d 100644 --- a/src/Pstream/dummy/UPstreamCommunicator.C +++ b/src/Pstream/dummy/UPstreamCommunicator.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2024 OpenCFD Ltd. + Copyright (C) 2024-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,7 +38,7 @@ Foam::UPstream::Communicator::Communicator() noexcept // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // Foam::UPstream::Communicator -Foam::UPstream::Communicator::lookup(const label comm) +Foam::UPstream::Communicator::lookup(const int comm) { return UPstream::Communicator(nullptr); } @@ -56,4 +56,10 @@ void Foam::UPstream::Communicator::reset() noexcept {} +int Foam::UPstream::Communicator::size() const +{ + return 0; +} + + // ************************************************************************* // diff --git a/src/Pstream/dummy/UPstreamWindow.C b/src/Pstream/dummy/UPstreamWindow.C index 4c8e5b79061..9af10b6e911 100644 --- a/src/Pstream/dummy/UPstreamWindow.C +++ b/src/Pstream/dummy/UPstreamWindow.C @@ -47,4 +47,10 @@ void Foam::UPstream::Window::reset() noexcept {} +int Foam::UPstream::Window::size() const +{ + return 0; +} + + // ************************************************************************* // diff --git a/src/Pstream/mpi/UIPstreamRead.C b/src/Pstream/mpi/UIPstreamRead.C index 4f94257e712..4f5fe7e2a78 100644 --- a/src/Pstream/mpi/UIPstreamRead.C +++ b/src/Pstream/mpi/UIPstreamRead.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2019-2024 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -47,7 +47,7 @@ static std::streamsize UPstream_mpi_receive const std::streamsize bufSize, const int fromProcNo, const int tag, - const Foam::label communicator, + const int communicator, Foam::UPstream::Request* req ) { @@ -344,7 +344,7 @@ std::streamsize Foam::UIPstream::read char* buf, const std::streamsize bufSize, const int tag, - const label communicator, + const int communicator, UPstream::Request* req ) { diff --git a/src/Pstream/mpi/UOPstreamWrite.C b/src/Pstream/mpi/UOPstreamWrite.C index d2e1da2ec65..8ebb2375464 100644 --- a/src/Pstream/mpi/UOPstreamWrite.C +++ b/src/Pstream/mpi/UOPstreamWrite.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -55,7 +55,7 @@ bool Foam::UOPstream::write const char* buf, const std::streamsize bufSize, const int tag, - const label communicator, + const int communicator, UPstream::Request* req, const UPstream::sendModes sendMode ) diff --git a/src/Pstream/mpi/UPstreamCommunicator.C b/src/Pstream/mpi/UPstreamCommunicator.C index 9040f2f0dc2..adff0a7ea30 100644 --- a/src/Pstream/mpi/UPstreamCommunicator.C +++ b/src/Pstream/mpi/UPstreamCommunicator.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2024 OpenCFD Ltd. + Copyright (C) 2024-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -39,7 +39,7 @@ Foam::UPstream::Communicator::Communicator() noexcept // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // Foam::UPstream::Communicator -Foam::UPstream::Communicator::lookup(const label comm) +Foam::UPstream::Communicator::lookup(const int comm) { if (comm < 0 || comm >= PstreamGlobals::MPICommunicators_.size()) { @@ -70,4 +70,27 @@ void Foam::UPstream::Communicator::reset() noexcept } +int Foam::UPstream::Communicator::size() const +{ + int val = 0; + + MPI_Comm comm = PstreamUtils::Cast::to_mpi(*this); + + if (MPI_COMM_SELF == comm) + { + return 1; + } + else if + ( + (MPI_COMM_NULL == comm) + || (MPI_SUCCESS != MPI_Comm_size(comm, &val)) + ) + { + val = 0; + } + + return val; +} + + // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstreamWindow.C b/src/Pstream/mpi/UPstreamWindow.C index 8bcce43014d..0657c86096a 100644 --- a/src/Pstream/mpi/UPstreamWindow.C +++ b/src/Pstream/mpi/UPstreamWindow.C @@ -50,4 +50,29 @@ void Foam::UPstream::Window::reset() noexcept } +int Foam::UPstream::Window::size() const +{ + int val = 0; + + MPI_Win win = PstreamUtils::Cast::to_mpi(*this); + MPI_Group group; + + // Get num of ranks from the group information + if + ( + (MPI_WIN_NULL != win) + && (MPI_SUCCESS == MPI_Win_get_group(win, &group)) + ) + { + if (MPI_SUCCESS != MPI_Group_size(group, &val)) + { + val = 0; + } + MPI_Group_free(&group); + } + + return val; +} + + // ************************************************************************* // -- GitLab From 7ac83f22c72f8cb81955157e610156e0a6485e2a Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 26 Feb 2025 15:47:39 +0100 Subject: [PATCH 07/15] ENH: refine the dataTypes handling - now distinguish between basic MPI types and user-defined types. The new front-facing trait UPstream_basic_dataType unwinds components and other types, but only for MPI fundamental types (including any aliases) - additional helper to combine a test for binary operator validity and basic data type validity, which better expresses intent: template<class BinaryOp, class T> UPstream_data_opType; - relax bit-wise operators to also accept signed integrals and 'void' generic --- .../00-machine-sizes/Test-machine-sizes.cpp | 90 +-- .../UPstreamTraits/Test-UPstreamTraits.cxx | 345 +++++++++--- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 68 ++- .../db/IOstreams/Pstreams/UPstreamTraits.H | 533 +++++++++++++----- src/Pstream/mpi/PstreamGlobals.C | 42 +- src/Pstream/mpi/PstreamGlobals.H | 14 +- 6 files changed, 792 insertions(+), 300 deletions(-) diff --git a/applications/test/00-machine-sizes/Test-machine-sizes.cpp b/applications/test/00-machine-sizes/Test-machine-sizes.cpp index 917782dfde1..e66fa7e57c3 100644 --- a/applications/test/00-machine-sizes/Test-machine-sizes.cpp +++ b/applications/test/00-machine-sizes/Test-machine-sizes.cpp @@ -51,17 +51,20 @@ Description //- Mapping of some fundamental and aggregate types to MPI data types enum class dataTypes : int { - // Builtin Types [8]: - DataTypes_begin, //!< Begin builtin types (internal use) - type_byte = DataTypes_begin, // also for char, unsigned char + // Fundamental Types [10]: + Basic_begin, + type_byte = Basic_begin, + type_int16, type_int32, type_int64, + type_uint16, type_uint32, type_uint64, type_float, type_double, type_long_double, - invalid + invalid, + Basic_end = invalid }; @@ -69,20 +72,19 @@ enum class dataTypes : int // Partial copy from UPstreamTraits.H -//- A supported UPstream data type (intrinsic or user-defined) +//- UPstream data type corresponding to an intrinsic (MPI) type template<class T> -struct UPstream_base_dataType : std::false_type +struct UPstream_mpi_dataType : std::false_type { static constexpr auto datatype_id = dataTypes::invalid; }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Specializations of the above, -// each to match the elements of UPstream::dataTypes +// Specializations to match elements of UPstream::dataTypes #undef defineUPstreamDataTraits #define defineUPstreamDataTraits(TypeId, Type) \ - template<> struct UPstream_base_dataType<Type> : std::true_type \ + template<> struct UPstream_mpi_dataType<Type> : std::true_type \ { \ static constexpr auto datatype_id = dataTypes::TypeId; \ }; @@ -90,8 +92,10 @@ struct UPstream_base_dataType : std::false_type defineUPstreamDataTraits(type_byte, char); defineUPstreamDataTraits(type_byte, unsigned char); +defineUPstreamDataTraits(type_int16, int16_t); defineUPstreamDataTraits(type_int32, int32_t); defineUPstreamDataTraits(type_int64, int64_t); +defineUPstreamDataTraits(type_uint16, uint16_t); defineUPstreamDataTraits(type_uint32, uint32_t); defineUPstreamDataTraits(type_uint64, uint64_t); defineUPstreamDataTraits(type_float, float); @@ -109,8 +113,8 @@ struct UPstream_alias_dataType : std::bool_constant < - // Base type (no alias needed) - UPstream_base_dataType<std::remove_cv_t<T>>::value || + // Basic MPI type + UPstream_mpi_dataType<std::remove_cv_t<T>>::value || ( // Or some int 32/64 type to re-map std::is_integral_v<T> @@ -118,15 +122,11 @@ struct UPstream_alias_dataType ) > { - // Is it using the base type? (no alias needed) - static constexpr bool is_base = - UPstream_base_dataType<std::remove_cv_t<T>>::value; - using base = std::conditional_t < - UPstream_base_dataType<std::remove_cv_t<T>>::value, // is_base - std::remove_cv_t<T>, - std::conditional_t + UPstream_mpi_dataType<std::remove_cv_t<T>>::value, + std::remove_cv_t<T>, // <- using mpi type (no alias) + std::conditional_t // <- using alias < ( std::is_integral_v<T> @@ -138,12 +138,32 @@ struct UPstream_alias_dataType 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 // Fallback value (assuming it is contiguous) + char // Fallback is a byte (eg, arbitrary contiguous data) > >; static constexpr auto datatype_id = - UPstream_base_dataType<base>::datatype_id; + UPstream_mpi_dataType<base>::datatype_id; +}; + + +// Handle int8_t/uint8_t as aliases since 'signed char' etc may be +// ambiguous + +//- Map \c int8_t to UPstream::dataTypes::type_byte +template<> +struct UPstream_alias_dataType<int8_t> : std::true_type +{ + using base = char; + static constexpr auto datatype_id = dataTypes::type_byte; +}; + +//- Map \c uint8_t to UPstream::dataTypes::type_byte +template<> +struct UPstream_alias_dataType<uint8_t> : std::true_type +{ + using base = unsigned char; + static constexpr auto datatype_id = dataTypes::type_byte; }; @@ -172,26 +192,31 @@ void print(const char* name, bool showLimits = true) } // A declared or deduced MPI type, or aliased - std::cout - << " is_mpi=" << UPstream_base_dataType<T>::value - << " (" << int(UPstream_base_dataType<T>::datatype_id) << ")"; + if constexpr (UPstream_mpi_dataType<T>::value) + { + std::cout + << " is_mpi=(" + << int(UPstream_mpi_dataType<T>::datatype_id) << ')'; + } + else + { + std::cout << " is_mpi=(null)"; + } - if (UPstream_alias_dataType<T>::value) + // Any aliases? + if constexpr (UPstream_alias_dataType<T>::value) { - if (UPstream_alias_dataType<T>::is_base) + if constexpr (UPstream_mpi_dataType<T>::value) { - std::cout<< " is_base"; + std::cout << " alias=base"; } else { - std::cout<< " is_alias (" - << int(UPstream_alias_dataType<T>::datatype_id) << ")"; + std::cout + << " alias=(" + << int(UPstream_alias_dataType<T>::datatype_id) << ')'; } } - else - { - std::cout<< " no_alias"; - } std::cout<< '\n'; } @@ -217,6 +242,7 @@ int main(int argc, char *argv[]) std::cout << '\n'; print<char>("char"); + print<signed char>("signed char"); print<unsigned char>("unsigned char"); print<short>("short"); print<int>("int"); diff --git a/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx b/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx index 9c747c61fa7..d8cb032749d 100644 --- a/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx +++ b/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx @@ -37,35 +37,40 @@ Description #include "vector.H" #include "tensor.H" #include "uLabel.H" +#include "MinMax.H" #include "Switch.H" #include "IOstreams.H" #include "UPstream.H" +#include <functional> #include <type_traits> -using namespace Foam; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Just for debugging -const List<std::string> dataType_names -({ - "byte", - "int32", - "int64", - "uint32", - "uint64", - "float", - "double", - "long_double", +namespace Foam +{ + +// Add in some extras from functional + +//- Map std::plus to \c UPstream::opCodes::op_sum +template<> +struct UPstream_opType<std::plus<void>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_sum; +}; + + +//- Map 'signed char' to UPstream::dataTypes::type_byte +// Caution with: may be identical to int8_t mapping!! +#if 0 +template<> +struct UPstream_alias_dataType<signed char> : std::true_type +{ + using base = char; + static constexpr auto datatype_id = UPstream::dataTypes::type_byte; +}; +#endif - "float(2)", - "double(2)", - "float(3)", - "double(3)", - "float(6)", - "double(6)", - "float(9)", - "double(9)" -}); //- Test for pTraits typeName member : default is false template<class T, class = void> @@ -82,24 +87,93 @@ struct check_has_typeName std::true_type {}; +} // End namespace Foam -// Possible future change... -// //- A supported UPstream data type (intrinsic or user-defined) -// template<> -// struct UPstream_base_dataType<complex> : std::true_type -// { -// static constexpr auto datatype_id = []() -// { -// if constexpr (sizeof(complex) == 2*sizeof(float)) -// return UPstream::dataTypes::type_2float; -// else -// return UPstream::dataTypes::type_2double; -// }(); -// }; +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -template<class T> -void printTypeName(const bool showSize = false) +// Just for debugging +static const Foam::List<std::string> dataType_names +({ + "byte", + "int16", + "int32", + "int64", + "uint16", + "uint32", + "uint64", + "float", + "double", + "long_double", + + "float[3]", + "double[3]", + "float[6]", + "double[6]", + "float[9]", + "double[9]" +}); + +// Just for debugging +static const Foam::List<std::string> opType_names +({ + "op_min", + "op_max", + "op_sum", + "op_prod", + "op_bool_and", + "op_bool_or", + "op_bool_xor", + "op_bit_and", + "op_bit_or", + "op_bit_xor", + "op_replace", + "op_no_op" +}); + + +using namespace Foam; + +void printDataTypeId(UPstream::dataTypes datatype_id) +{ + if (datatype_id != UPstream::dataTypes::invalid) + { + const int index = int(datatype_id); + if (index < dataType_names.size()) + { + Info<< dataType_names[index]; + } + else + { + Info<< '(' << index << ')'; + } + } +} + + +void printOpCodeId(UPstream::opCodes opcode_id) +{ + if (opcode_id != UPstream::opCodes::invalid) + { + const int index = int(opcode_id); + if (index < opType_names.size()) + { + Info<< ':' << opType_names[index].c_str(); + } + else + { + Info<< '(' << index << ')'; + } + } + else + { + Info<< "(null)"; + } +} + + +template<class T, bool showSize = false> +void printTypeName() { // Both float and double have pTraits typeName = "scalar"! if constexpr (std::is_same_v<float, std::remove_cv_t<T>>) @@ -118,12 +192,13 @@ void printTypeName(const bool showSize = false) { Info<< typeid(T).name(); } - if (showSize) + if constexpr (showSize) { Info<< " (" << sizeof(T) << " bytes)"; } } + template<class Type, bool UseTypeName = true> void printPstreamTraits(const std::string_view name = std::string_view()) { @@ -133,55 +208,111 @@ void printPstreamTraits(const std::string_view name = std::string_view()) { Info<< name << ' '; } + if constexpr (UseTypeName) { - printTypeName<Type>(true); + printTypeName<Type, true>(); } else { - Info<< typeid(Type).name(); - Info<< " (" << sizeof(Type) << " bytes)"; + Info<< typeid(Type).name() << " (" << sizeof(Type) << " bytes)"; + } + + { + using cmpt = typename Foam::pTraits_cmptType<Type>::type; + + if constexpr (!std::is_same_v<Type, cmpt>) + { + Info<< ", cmpt:"; + + if constexpr (UseTypeName) + { + printTypeName<cmpt, true>(); + } + else + { + Info<< typeid(cmpt).name() << " (" << sizeof(cmpt) << " bytes)"; + } + } } - Info<< ", cmpt:"; - printTypeName<typename Foam::pTraits_cmptType<Type>::type>(true); Info<< nl << " is_contiguous:" - << is_contiguous<Type>::value - << ", is base:" - << UPstream_base_dataType<Type>::value - << ", is cmpt:" - << UPstream_dataType<Type>::value << nl; - - Info<< "is base:" - << UPstream_base_dataType<Type>::value - << " (type:" << int(UPstream_base_dataType<Type>::datatype_id) - << ") is alias:" << UPstream_alias_dataType<Type>::value - << " (type:" << int(UPstream_alias_dataType<Type>::datatype_id) - << ")" << nl; + << is_contiguous<Type>::value; + if constexpr (UPstream_mpi_dataType<Type>::value) + { + Info<< ", is_mpi=(" + << int(UPstream_mpi_dataType<Type>::datatype_id) << ')'; + } + else + { + std::cout << ", is_mpi=(null)"; + } + if constexpr (UPstream_user_dataType<Type>::value) + { + Info<< ", is_user=(" + << int(UPstream_user_dataType<Type>::datatype_id) << ')'; + } + else + { + std::cout << ", is_user=(null)"; + } + if constexpr (UPstream_any_dataType<Type>::value) + { + Info<< ", is_any=(" + << int(UPstream_any_dataType<Type>::datatype_id) << ')'; + } + else + { + std::cout << ", is_any=(null)"; + } + // Any aliases? + if constexpr + ( + UPstream_alias_dataType<Type>::value + && !UPstream_mpi_dataType<Type>::value + ) { - int index = int(UPstream_base_dataType<Type>::datatype_id); - Info<< "datatype: " << index; + Info<< ", alias=(" + << int(UPstream_alias_dataType<Type>::datatype_id) << ')'; + } - if (index < dataType_names.size()) - { - Info<< ' ' << dataType_names[index]; - } - Info<< nl; + Info<< " base-type:" << int(UPstream_basic_dataType<Type>::datatype_id) + << " data-type:" << int(UPstream_dataType<Type>::datatype_id) + << nl; + + if constexpr (UPstream_basic_dataType<Type>::value) + { + Info<< " base-type="; + printDataTypeId(UPstream_basic_dataType<Type>::datatype_id); + } + else if constexpr (UPstream_dataType<Type>::value) + { + Info<< " data-type="; + printDataTypeId(UPstream_dataType<Type>::datatype_id); } { // Use element or component type (or byte-wise) for data type using base = typename UPstream_dataType<Type>::base; - constexpr auto datatype = UPstream_dataType<Type>::datatype_id; - Info<< "datatype => "; - printTypeName<base>(); - Info<< " (" << sizeof(Type)/sizeof(base) << " elems)" << nl - << "datatype: " << static_cast<int>(datatype) << nl; + Info<< " : "; + if constexpr (UseTypeName) + { + printTypeName<base, true>(); + } + else + { + Info<< typeid(base).name() << " (" << sizeof(base) << " bytes)"; + } + + Info<< " cmpt-type="; + printDataTypeId(UPstream_dataType<Type>::datatype_id); + Info<< " count=" << UPstream_dataType<Type>::size(1); + Info<< nl; } } @@ -190,15 +321,44 @@ template<class BinaryOp> void printOpCodeTraits(BinaryOp bop, std::string_view name) { Info<< "op: " << name << ' '; - if constexpr (UPstream_opType<BinaryOp>::value) - { - Info<< "supported"; - } - else + + printOpCodeId(UPstream_opType<BinaryOp>::opcode_id); + Info<< nl; +} + + +template<class DataType, class BinaryOp> +void printOpCodeTraits(BinaryOp bop, std::string_view name) +{ + Info<< "op: " << name << ' '; + + printOpCodeId(UPstream_opType<BinaryOp>::opcode_id); + + if constexpr (!std::is_void_v<DataType>) { - Info<< "unknown"; + if constexpr (UPstream_basic_dataType<DataType>::value) + { + Info<< " [supported type]"; + } + else + { + Info<< " [disabled]"; + } } - Info<< ": " << int(UPstream_opType<BinaryOp>::opcode_id) << nl; + Info<< nl; +} + + +template<class DataType, class BinaryOp> +void print_data_opType(BinaryOp bop, std::string_view name) +{ + Info<< "op: " << name << ' '; + + printOpCodeId(UPstream_data_opType<BinaryOp, DataType>::opcode_id); + + const bool ok = UPstream_data_opType<BinaryOp, DataType>::value; + + Info<< " okay=" << ok << nl; } @@ -210,6 +370,16 @@ int main() printPstreamTraits<bool>(); printPstreamTraits<label>(); + printPstreamTraits<char, false>("<char>"); + printPstreamTraits<signed char, false>("<signed char>"); + printPstreamTraits<unsigned char, false>("<unsigned char>"); + + printPstreamTraits<int8_t, false>("<int8_t>"); + printPstreamTraits<uint8_t, false>("<uint8_t>"); + + printPstreamTraits<int16_t, false>("<int16_t>"); + printPstreamTraits<uint16_t, false>("<uint16_t>"); + printPstreamTraits<int>("<int>"); printPstreamTraits<long>("<long>"); printPstreamTraits<unsigned>("<unsigned>"); @@ -258,6 +428,35 @@ int main() printOpCodeTraits(bitAndOp<unsigned>{}, "bitAnd<unsigned>"); printOpCodeTraits(bitOrOp<unsigned>{}, "bitOr<unsigned>"); + printOpCodeTraits<vector>(sumOp<vector>{}, "sum"); + printOpCodeTraits(sumOp<scalarMinMax>{}, "sum"); + + printOpCodeTraits(std::plus<>{}, "sum"); + printOpCodeTraits<bool>(std::plus<>{}, "sum"); + printOpCodeTraits<vector>(std::plus<>{}, "sum"); + + + // Expect success + Info<< nl << "expect success" << nl; + print_data_opType<vector>(maxOp<scalar>(), "maxOp(scalar)"); + print_data_opType<unsigned>(bitOrOp<unsigned>(), "bitOrOp(unsigned)"); + print_data_opType<uint8_t>(bitOrOp<uint8_t>(), "bitOrOp(uint8_t)"); + print_data_opType<uint16_t>(bitOrOp<uint16_t>(), "bitOrOp(uint16_t)"); + + // Even allow signed integrals + print_data_opType<int>(bitOrOp<int>(), "bitOrOp(int)"); + print_data_opType<int8_t>(bitOrOp<int8_t>(), "bitOrOp(int8_t)"); + + // Failure - supported op, unsupported data type. + Info<< nl << "expect failure" << nl; + print_data_opType<bool>(maxOp<scalar>(), "maxOp(scalar, bool)"); + print_data_opType<bool>(bitOrOp<unsigned>(), "bitOrOp(unsigned, bool)"); + + // False positives. Failure - supported op, unsupported data type. + Info<< nl << "false positives" << nl; + print_data_opType<void>(maxOp<bool>(), "maxOp(bool, void)"); + print_data_opType<float>(bitOrOp<unsigned>(), "bitOrOp(unsigned, float)"); + Info<< nl << "End\n" << endl; return 0; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index 3ce948183f4..208ce835060 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -91,52 +91,54 @@ public: }; //- Mapping of some fundamental and aggregate types to MPI data types - enum class dataTypes : int + enum class dataTypes : char { // NOTE: changes here require adjustment in // PstreamGlobals, UPstreamTraits - // Builtin Types [8]: - DataTypes_begin, //!< (internal use) begin all data types - type_byte = DataTypes_begin, //!< byte, char, unsigned char, ... + // Fundamental Types [10]: + Basic_begin, //!< (internal use) begin marker [basic/all types] + type_byte = Basic_begin, //!< byte, char, unsigned char, ... + type_int16, type_int32, type_int64, + type_uint16, type_uint32, type_uint64, type_float, type_double, type_long_double, - //! (internal use) end of builtin data types marker - BuiltinTypes_end, UserTypes_begin = BuiltinTypes_end, - //!< (internal use) begin of user data types marker + //! (internal use) end marker [basic types] + Basic_end, User_begin = Basic_end, + //!< (internal use) begin marker [user types] // User Types [6]: - type_3float = UserTypes_begin, //!< 3*float (eg, floatVector) + type_3float = User_begin, //!< 3*float (eg, floatVector) type_3double, //!< 3*double (eg, doubleVector) type_6float, //!< 6*float (eg, floatSymmTensor, complex vector) type_6double, //!< 6*double (eg, doubleSymmTensor, complex vector) type_9float, //!< 9*float (eg, floatTensor) type_9double, //!< 9*double (eg, doubleTensor) - // Internal markers + // Internal markers [1] invalid, //!< invalid type (NULL) - //! (internal use) end of user data types marker - UserTypes_end = invalid, DataTypes_end = invalid - //!< (internal use) end of all data types marker + //! (internal use) end marker [user types] + User_end = invalid, DataTypes_end = invalid + //!< (internal use) end marker [all types] }; //- Mapping of some MPI op codes. // Currently excluding min/max location until they are needed - enum class opCodes : int + enum class opCodes : char { // NOTE: changes here require adjustment in // PstreamGlobals, UPstreamTraits - ReduceOps_begin, //!< (internal use) begin reduce/window + Basic_begin, //!< (internal use) begin marker [reduce/window types] // Reduce or window operations [10] - op_min = ReduceOps_begin, //!< min(x,y) + op_min = Basic_begin, //!< min(x,y) op_max, //!< max(x,y) op_sum, //!< (x + y) op_prod, //!< (x * y) @@ -147,19 +149,30 @@ public: op_bit_or, //!< Bit-wise \c or for (unsigned) integral types op_bit_xor, //!< Bit-wise \c xor for (unsigned) integral types - //! (internal use) end of reduce-ops marker - ReduceOps_end, WindowOps_begin = ReduceOps_end, - //!< (internal use) begin end of window-ops marker + //! (internal use) end marker [reduce types] + Basic_end, Extra_begin = Basic_end, + //!< (internal use) begin marker [window types] // Window-only operations [2] - op_replace = WindowOps_begin, //!< Replace (window only) + op_replace = Extra_begin, //!< Replace (window only) op_no_op, //!< No-op (window only) - // Internal markers + // Internal markers [1] invalid, //!< invalid op (NULL) - //! (internal use) end of window-ops marker - WindowOps_end = invalid, OpCodes_end = invalid - //!< (internal use) end of all ops marker + //! (internal use) end marker [window types] + Extra_end = invalid, OpCodes_end = invalid + //!< (internal use) end marker [all types] + }; + + //- Some bit masks corresponding to topology controls + // These selectively enable topology-aware handling + enum class topoControls : int + { + broadcast = 1, //!< broadcast [MPI] + reduce = 2, //!< reduce/all-reduce [MPI] + gather = 16, //!< gather (reduction) [manual algorithm] + mapGather = 32, //!< mapGather (reduction) [manual algorithm] + gatherList = 64, //!< gatherList/scatterList [manual algorithm] }; @@ -509,13 +522,14 @@ public: // >= 3 : when there are more than N nodes static int nodeCommsMin_; - //- Selection of topology-aware routines + //- Selection of topology-aware routines as a bitmask combination + //- of the topoControls enumerations static int topologyControl_; - //- Test for selection of given topology-aware routine (bitmask) - static bool usingTopoControl(int routine = 0) noexcept + //- Test for selection of given topology-aware routine + static bool usingTopoControl(UPstream::topoControls ctrl) noexcept { - return static_cast<bool>(topologyControl_ & routine); + return static_cast<bool>(topologyControl_ & int(ctrl)); } //- Should compact transfer be used in which floats replace doubles diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamTraits.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamTraits.H index 224300002d4..ec0d3ad8631 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamTraits.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamTraits.H @@ -26,28 +26,50 @@ License Description A set of traits associated with UPstream communication - - UPstream_dataType trait: - This wrapper is unwinds the type to check against base/alias, but also - checks if it is a component aggregate of a supported UPstream data type. - This will be that main entry point for usage. + \par Front-facing traits - - UPstream_opType trait: - Provides a mapping of OpenFOAM ops to their MPI equivalent. + - \c UPstream_basic_dataType trait :<br> + The main entry point for reduction operations + (requires fundamental types).<br> + Checks against fundamental/aliased (excludes user-defined), + or is a component-wise aggregate of the same. + + - \c UPstream_dataType trait :<br> + The main entry point for transmission (broadcast, send/recv, ...).<br> + Checks against fundamental/aliased/user-defined, + or is a component-wise aggregate of the same. + + - \c UPstream_opType trait :<br> + Mapping of OpenFOAM ops to their MPI equivalent. The \c opcode_id is the corresponding internal representation. -Note - Additional helper traits: + - \c UPstream_data_opType trait :<br> + Combination of UPstream_opType and UPstream_basic_dataType. + . + + \par Additional helper traits (not normally used directly): - - UPstream_base_dataType trait: - Tests true/false if the specified data type has an internal - MPI equivalent. The \c datatype_id is the corresponding - internal enumeration. Even if this tests as false, it will - always return \c type_byte as the fallback for general contiguous data + - \c UPstream_mpi_dataType trait :<br> + Tests true and provides valid \c datatype_id for MPI fundamental + data types. This trait will should not normally be used directly: + use UPstream_alias_dataType for 'low-level' purposes (see below). - - UPstream_alias_dataType trait: - Provides mapping for <int/long/long long,...> to the fundamental + - \c UPstream_user_dataType trait :<br> + Tests true and provides valid \c datatype_id for user-defined + data types. + + - \c UPstream_alias_dataType trait :<br> + Use this in preference to UPstream_mpi_dataType.<br> + A pass-through to UPstream_mpi_dataType, but provides additional + mappings for <int/long/long long,...> to the fundamental 32/64 bit integrals, since <int/long/long long,...> may not otherwise - directly map on all systems. + map directly on all systems. + + - \c UPstream_any_dataType trait :<br> + Used as a building block for uniform aggregate types.<br> + Combines UPstream_user_dataType and UPstream_alias_dataType into a + single trait. + . \*---------------------------------------------------------------------------*/ @@ -88,130 +110,37 @@ template<class T> class Tensor; // template<class T> struct bitXorOp; //! \cond +template<class T> struct UPstream_basic_dataType; template<class T> struct UPstream_dataType; -template<class T> struct UPstream_opType; //! \endcond // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Base traits - -//- A supported UPstream (MPI) reduce/window operation type -template<class T> -struct UPstream_opType : std::false_type -{ - static constexpr auto opcode_id = UPstream::opCodes::invalid; -}; - - -//- A supported UPstream data type (intrinsic or user-defined) +//- UPstream data type corresponding to a fundamental (MPI) type template<class T> -struct UPstream_base_dataType : std::false_type +struct UPstream_mpi_dataType : std::false_type { static constexpr auto datatype_id = UPstream::dataTypes::invalid; }; - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Trait specializations (op-codes) - -//- Map minOp\<T\> to \c UPstream::opCodes::op_min -template<class T> -struct UPstream_opType<Foam::minOp<T>> : std::true_type -{ - static constexpr auto opcode_id = UPstream::opCodes::op_min; -}; - -//- Map maxOp\<T\> to \c UPstream::opCodes::op_max -template<class T> -struct UPstream_opType<Foam::maxOp<T>> : std::true_type +//- Disallow \c void +template<> struct UPstream_mpi_dataType<void> : std::false_type { - static constexpr auto opcode_id = UPstream::opCodes::op_max; -}; - -//- Map sumOp\<T\> to \c UPstream::opCodes::op_sum -template<class T> -struct UPstream_opType<Foam::sumOp<T>> : std::true_type -{ - static constexpr auto opcode_id = UPstream::opCodes::op_sum; -}; - -//- Map plusOp\<T\> to \c UPstream::opCodes::op_sum -//- as a recognized alternative to sumOp\<T\> -template<class T> -struct UPstream_opType<Foam::plusOp<T>> : std::true_type -{ - static constexpr auto opcode_id = UPstream::opCodes::op_sum; -}; - -//- Map multiplyOp\<T\> to \c UPstream::opCodes::op_prod -template<class T> -struct UPstream_opType<Foam::multiplyOp<T>> : std::true_type -{ - static constexpr auto opcode_id = UPstream::opCodes::op_prod; -}; - -// NOTE (2025-02): -// currently no mappings provided for -// (op_bool_and, op_bool_or, op_bool_xor) until the calling semantics -// have been properly defined - - -// These are only viable for unsigned integral types, -// probably not for signed integral types. -// Be extra restrictive for now - -//- Map bitAndOp\<T\> to \c UPstream::opCodes::op_bit_and -//- (for unsigned integrals) -template<class T> -struct UPstream_opType<Foam::bitAndOp<T>> -: - // ie, std::unsigned_integral<T> concept - std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>> -{ - static constexpr auto opcode_id = []() constexpr noexcept - { - if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) - return UPstream::opCodes::op_bit_and; - else - return UPstream::opCodes::invalid; - }(); + static constexpr auto datatype_id = UPstream::dataTypes::invalid; }; -//- Map bitOrOp\<T\> to \c UPstream::opCodes::op_bit_or -//- (for unsigned integrals) +//- UPstream data type corresponding to user-defined type template<class T> -struct UPstream_opType<Foam::bitOrOp<T>> -: - // ie, std::unsigned_integral<T> concept - std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>> +struct UPstream_user_dataType : std::false_type { - static constexpr auto opcode_id = []() constexpr noexcept - { - if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) - return UPstream::opCodes::op_bit_or; - else - return UPstream::opCodes::invalid; - }(); + static constexpr auto datatype_id = UPstream::dataTypes::invalid; }; -//- Map bitXorOp\<T\> to \c UPstream::opCodes::op_bit_xor -//- (for unsigned integrals) -template<class T> -struct UPstream_opType<Foam::bitXorOp<T>> -: - // ie, std::unsigned_integral<T> concept - std::bool_constant<std::is_integral_v<T> && !std::is_signed_v<T>> +//- Disallow \c void +template<> struct UPstream_user_dataType<void> : std::false_type { - static constexpr auto opcode_id = []() constexpr noexcept - { - if constexpr (std::is_integral_v<T> && !std::is_signed_v<T>) - return UPstream::opCodes::op_bit_xor; - else - return UPstream::opCodes::invalid; - }(); + static constexpr auto datatype_id = UPstream::dataTypes::invalid; }; @@ -219,36 +148,59 @@ struct UPstream_opType<Foam::bitXorOp<T>> // Trait specializations (data types) -// Specializations to match elements of UPstream::dataTypes +// Specializations to match elements of UPstream::dataTypes. + #undef defineUPstreamDataTraits #define defineUPstreamDataTraits(TypeId, Type) \ \ /*! \brief Map \c Type to UPstream::dataTypes::TypeId */ \ - template<> struct UPstream_base_dataType<Type> : std::true_type \ + template<> struct UPstream_mpi_dataType<Type> : std::true_type \ { \ static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \ }; \ /*! \brief Map \c const \c Type to \c UPstream::dataTypes::TypeId */ \ - template<> struct UPstream_base_dataType<const Type> : std::true_type \ + template<> struct UPstream_mpi_dataType<const Type> : std::true_type \ { \ static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \ }; - -// Intrinsic Types [8]: +// Fundamental Types [10]: // Note: uses 'int32_t,int64_t,...' instead of 'int,long,...' to minimize -// the possibility of duplicates types. +// the possibility of duplicate types. However, 'int8_t,uint8_t' are treated +// as aliases (char,unsigned char) to avoid possible compilation issues. +// // OpenFOAM defines Foam::label as either int32_t,int64_t (not int,long) too. defineUPstreamDataTraits(type_byte, char); defineUPstreamDataTraits(type_byte, unsigned char); +defineUPstreamDataTraits(type_int16, int16_t); defineUPstreamDataTraits(type_int32, int32_t); defineUPstreamDataTraits(type_int64, int64_t); +defineUPstreamDataTraits(type_uint16, uint16_t); defineUPstreamDataTraits(type_uint32, uint32_t); defineUPstreamDataTraits(type_uint64, uint64_t); defineUPstreamDataTraits(type_float, float); defineUPstreamDataTraits(type_double, double); defineUPstreamDataTraits(type_long_double, long double); +#undef defineUPstreamDataTraits + +// ------------------------------------------------------------------------- // + +#undef defineUPstreamDataTraits +#define defineUPstreamDataTraits(TypeId, Type) \ + \ + /*! \brief Map \c Type to UPstream::dataTypes::TypeId */ \ + template<> struct UPstream_user_dataType<Type> : std::true_type \ + { \ + static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \ + }; \ + /*! \brief Map \c const \c Type to \c UPstream::dataTypes::TypeId */ \ + template<> struct UPstream_user_dataType<const Type> : std::true_type \ + { \ + static constexpr auto datatype_id = UPstream::dataTypes::TypeId; \ + }; + + // User Types [6]: defineUPstreamDataTraits(type_3float, Vector<float>); defineUPstreamDataTraits(type_3double, Vector<double>); @@ -264,14 +216,17 @@ defineUPstreamDataTraits(type_9double, Tensor<double>); //- Explicit handling of data type aliases. This is necessary since //- different systems map things like 'unsigned long' differently but we -//- restrict ourselves to int32/int64 types +//- restrict ourselves to int32/int64 types. +// +// Note that this trait serves as the single pass-through point when needing +// to reference UPstream_mpi_dataType elsewhere template<class T> struct UPstream_alias_dataType : std::bool_constant < - // Base type (no alias needed) - UPstream_base_dataType<std::remove_cv_t<T>>::value || + // Basic MPI type + UPstream_mpi_dataType<std::remove_cv_t<T>>::value || ( // Or some int 32/64 type to re-map std::is_integral_v<T> @@ -279,14 +234,10 @@ struct UPstream_alias_dataType ) > { - // Is it using the base type? (no alias needed) - static constexpr bool is_base = - UPstream_base_dataType<std::remove_cv_t<T>>::value; - using base = std::conditional_t < - UPstream_base_dataType<std::remove_cv_t<T>>::value, - std::remove_cv_t<T>, // <- using base + UPstream_mpi_dataType<std::remove_cv_t<T>>::value, + std::remove_cv_t<T>, // <- using mpi type (no alias) std::conditional_t // <- using alias < ( @@ -304,66 +255,342 @@ struct UPstream_alias_dataType >; static constexpr auto datatype_id = - UPstream_base_dataType<base>::datatype_id; + UPstream_mpi_dataType<base>::datatype_id; +}; + + +// Handle int8_t/uint8_t as aliases since 'signed char' etc may be +// ambiguous + +//- Map \c int8_t to UPstream::dataTypes::type_byte +template<> +struct UPstream_alias_dataType<int8_t> : std::true_type +{ + using base = char; + static constexpr auto datatype_id = UPstream::dataTypes::type_byte; +}; + +//- Map \c uint8_t to UPstream::dataTypes::type_byte +template<> +struct UPstream_alias_dataType<uint8_t> : std::true_type +{ + using base = unsigned char; + static constexpr auto datatype_id = UPstream::dataTypes::type_byte; +}; + +// ------------------------------------------------------------------------- // + +//- UPstream data type (fundamental or user-defined), +//- after resolving any aliases +template<class T> +struct UPstream_any_dataType +: + std::bool_constant + < + UPstream_user_dataType<std::remove_cv_t<T>>::value + || UPstream_alias_dataType<T>::value + > +{ + using base = std::conditional_t + < + UPstream_user_dataType<std::remove_cv_t<T>>::value, + std::remove_cv_t<T>, + typename UPstream_alias_dataType<T>::base + >; + + //- The corresponding UPstream::dataTypes enumeration + static constexpr auto datatype_id = []() constexpr noexcept + { + if constexpr (UPstream_user_dataType<std::remove_cv_t<T>>::value) + { + // A user-defined type + return UPstream_user_dataType<std::remove_cv_t<T>>::datatype_id; + } + else if constexpr (UPstream_alias_dataType<T>::value) + { + // Fundamental type or alias to a fundamental type + return UPstream_alias_dataType<T>::datatype_id; + } + else + { + return UPstream::dataTypes::invalid; + } + }(); }; // ------------------------------------------------------------------------- // -//- A supported UPstream data type (fundamental or user-defined) -//- or a component aggregate of a supported UPstream data type. +//- UPstream fundamental/aliased (excludes user-defined) data type +//- or a component aggregate of the same. // -// Is true for the following conditions: +// True for the following conditions: // - The \c Type is directly supported // - The \c cmptType (eg, from VectorSpace) exists and is directly supported // - Fallback to byte-wise representation (ie, for contiguous) // . template<class T> -struct UPstream_dataType +struct UPstream_basic_dataType : std::bool_constant < + // non-aggregate type UPstream_alias_dataType<T>::value + // aggregate type || UPstream_alias_dataType<typename pTraits_cmptType<T>::type>::value > { - // Is it using the base type? (ie, not using components) - static constexpr bool is_base = UPstream_alias_dataType<T>::value; - //- The underlying data type (if supported) or byte using base = std::conditional_t < UPstream_alias_dataType<T>::value, - typename UPstream_alias_dataType<T>::base, // <- using base + typename UPstream_alias_dataType<T>::base, // <- non-aggregate typename UPstream_alias_dataType - <typename pTraits_cmptType<T>::type>::base // <- using components + <typename pTraits_cmptType<T>::type>::base // <- aggregate >; //- The corresponding UPstream::dataTypes enumeration static constexpr auto datatype_id = - UPstream_base_dataType<base>::datatype_id; + UPstream_alias_dataType<base>::datatype_id; //- The size in terms of the number of underlying data elements - static std::streamsize size(std::streamsize count) noexcept + static std::streamsize size(std::streamsize n) noexcept { if constexpr (UPstream_alias_dataType<T>::value) { - // using base: no multiplier - return count; + // non-aggregate: no multiplier + return n; } else { - // using components: with multiplier - return count*(sizeof(T)/sizeof(base)); + // aggregate: with multiplier + return n*(sizeof(T)/sizeof(base)); } } }; +//- Disallow \c void +template<> struct UPstream_basic_dataType<void> : UPstream_mpi_dataType<void> +{ + using base = void; + static std::streamsize size(std::streamsize n) noexcept { return n; } +}; + + +// ------------------------------------------------------------------------- // + +//- UPstream fundamental/aliased/user-defined data type +//- or a component aggregate of the same. +// +// True for the following conditions: +// - The \c Type is directly supported +// - The \c cmptType (eg, from VectorSpace) exists and is directly supported +// - Fallback to byte-wise representation (ie, for contiguous) +// . +template<class T> +struct UPstream_dataType +: + std::bool_constant + < + UPstream_any_dataType<T>::value + || UPstream_any_dataType<typename pTraits_cmptType<T>::type>::value + > +{ + //- The underlying data type (if supported) or byte + using base = std::conditional_t + < + UPstream_any_dataType<T>::value, + typename UPstream_any_dataType<T>::base, // <- non-aggregate + typename UPstream_any_dataType + <typename pTraits_cmptType<T>::type>::base // <- aggregate + >; + + //- The corresponding UPstream::dataTypes enumeration + static constexpr auto datatype_id = + UPstream_any_dataType<base>::datatype_id; + + //- The size in terms of the number of base data elements + static std::streamsize size(std::streamsize n) noexcept + { + if constexpr (UPstream_any_dataType<T>::value) + { + // non-aggregate: no multiplier + return n; + } + else + { + // aggregate: with multiplier + return n*(sizeof(T)/sizeof(base)); + } + } +}; + +//- Disallow \c void +template<> struct UPstream_dataType<void> : UPstream_basic_dataType<void> {}; + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace Foam +// Reduction op-codes + +//- A supported UPstream (MPI) reduce/window operation type +template<class BinaryOp> +struct UPstream_opType : std::false_type +{ + static constexpr auto opcode_id = UPstream::opCodes::invalid; +}; + +//- Disallow \c void +template<> struct UPstream_opType<void> : std::false_type +{ + static constexpr auto opcode_id = UPstream::opCodes::invalid; +}; + +//- Map minOp\<T\> to \c UPstream::opCodes::op_min +template<class T> +struct UPstream_opType<Foam::minOp<T>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_min; +}; + +//- Map maxOp\<T\> to \c UPstream::opCodes::op_max +template<class T> +struct UPstream_opType<Foam::maxOp<T>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_max; +}; + +//- Map sumOp\<T\> to \c UPstream::opCodes::op_sum +template<class T> +struct UPstream_opType<Foam::sumOp<T>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_sum; +}; + +//- Map plusOp\<T\> (same as sumOp\<T\>) to \c UPstream::opCodes::op_sum +template<class T> +struct UPstream_opType<Foam::plusOp<T>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_sum; +}; + +//- Map multiplyOp\<T\> to \c UPstream::opCodes::op_prod +template<class T> +struct UPstream_opType<Foam::multiplyOp<T>> : std::true_type +{ + static constexpr auto opcode_id = UPstream::opCodes::op_prod; +}; + +// NOTE (2025-02): +// currently no mappings provided for +// (op_bool_and, op_bool_or, op_bool_xor) until the calling semantics +// have been properly defined + + +// These are only viable for unsigned integral types, +// probably not for signed integral types. +// Be extra restrictive for now + +//- Map bitAndOp\<T\> to \c UPstream::opCodes::op_bit_and +//- for integrals (signed or unsigned), but also allow void as "generic" +template<class T> +struct UPstream_opType<Foam::bitAndOp<T>> +: + std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>> +{ + static constexpr auto opcode_id = []() constexpr noexcept + { + if constexpr (std::is_integral_v<T> || std::is_void_v<T>) + return UPstream::opCodes::op_bit_and; + else + return UPstream::opCodes::invalid; + }(); +}; + +//- Map bitOrOp\<T\> to \c UPstream::opCodes::op_bit_or +//- for integrals (signed or unsigned), but also allow void as "generic" +template<class T> +struct UPstream_opType<Foam::bitOrOp<T>> +: + std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>> +{ + static constexpr auto opcode_id = []() constexpr noexcept + { + if constexpr (std::is_integral_v<T> || std::is_void_v<T>) + return UPstream::opCodes::op_bit_or; + else + return UPstream::opCodes::invalid; + }(); +}; +//- Map bitXorOp\<T\> to \c UPstream::opCodes::op_bit_xor +//- for integrals (signed or unsigned), but also allow void as "generic" +template<class T> +struct UPstream_opType<Foam::bitXorOp<T>> +: + std::bool_constant<std::is_integral_v<T> || std::is_void_v<T>> +{ + static constexpr auto opcode_id = []() constexpr noexcept + { + if constexpr (std::is_integral_v<T> || std::is_void_v<T>) + return UPstream::opCodes::op_bit_xor; + else + return UPstream::opCodes::invalid; + }(); +}; + + +//- Combined query of opType and the underlying basic data type +// This handling may be simplified in the future... +template<class BinaryOp, class T> +struct UPstream_data_opType +: + std::bool_constant + < + UPstream_opType<BinaryOp>::value + && UPstream_basic_dataType<T>::value + > +{ + static constexpr auto opcode_id = []() constexpr noexcept + { + if constexpr + ( + UPstream_opType<BinaryOp>::value + && UPstream_basic_dataType<T>::value + ) + return UPstream_opType<BinaryOp>::opcode_id; + else + return UPstream::opCodes::invalid; + }(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Convenience Functions (FUTURE?) + +// inline bool is_UPstream_mpi_dataTypeCode(UPstream::dataTypes id) noexcept +// { +// return +// ( +// int(id) >= int(UPstream::opCodes::Basic_begin) +// && int(id) < int(UPstream::opCodes::Basic_end) +// ); +// } +// +// inline bool is_UPstream_reduceOpCode(UPstream::opCodes id) noexcept +// { +// return +// ( +// int(id) >= int(UPstream::opCodes::Basic_begin) +// && int(id) < int(UPstream::opCodes::Basic_end) +// ); +// } + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/Pstream/mpi/PstreamGlobals.C b/src/Pstream/mpi/PstreamGlobals.C index b7aa206aea7..20a6868c723 100644 --- a/src/Pstream/mpi/PstreamGlobals.C +++ b/src/Pstream/mpi/PstreamGlobals.C @@ -34,6 +34,9 @@ Foam::DynamicList<bool> Foam::PstreamGlobals::pendingMPIFree_; Foam::DynamicList<MPI_Comm> Foam::PstreamGlobals::MPICommunicators_; Foam::DynamicList<MPI_Request> Foam::PstreamGlobals::outstandingRequests_; +Foam::PstreamGlobals::DataTypeCountLookupTable +Foam::PstreamGlobals::dataTypesCount_(1); + Foam::PstreamGlobals::DataTypeLookupTable Foam::PstreamGlobals::MPIdataTypes_(MPI_DATATYPE_NULL); @@ -70,6 +73,12 @@ void Foam::PstreamGlobals::initCommunicator(const label index) void Foam::PstreamGlobals::initDataTypes() { + static_assert + ( + PstreamGlobals::DataTypeCountLookupTable::max_size() + == (int(UPstream::dataTypes::DataTypes_end)+1), + "Data count lookup table size != number of dataTypes enumerations" + ); static_assert ( PstreamGlobals::DataTypeLookupTable::max_size() @@ -77,15 +86,21 @@ void Foam::PstreamGlobals::initDataTypes() "Lookup table size != number of dataTypes enumerations" ); - // From enumeration to MPI datatype + // From enumeration to MPI datatype for fundamental types + // (count is always 1) #undef defineType - #define defineType(Idx, BaseType) \ - MPIdataTypes_[int(UPstream::dataTypes::Idx)] = BaseType; + #define defineType(Idx, BaseType) \ + { \ + dataTypesCount_[int(UPstream::dataTypes::Idx)] = 1; \ + MPIdataTypes_[int(UPstream::dataTypes::Idx)] = BaseType; \ + } - // Intrinsic Types [8]: + // Fundamental Types [10]: defineType(type_byte, MPI_BYTE); + defineType(type_int16, MPI_INT16_T); defineType(type_int32, MPI_INT32_T); defineType(type_int64, MPI_INT64_T); + defineType(type_uint16, MPI_UINT16_T); defineType(type_uint32, MPI_UINT32_T); defineType(type_uint64, MPI_UINT64_T); defineType(type_float, MPI_FLOAT); @@ -98,6 +113,7 @@ void Foam::PstreamGlobals::initDataTypes() #undef defineUserType #define defineUserType(Idx, Count, BaseType, Name) \ { \ + dataTypesCount_[int(UPstream::dataTypes::Idx)] = Count; \ auto& dt = MPIdataTypes_[int(UPstream::dataTypes::Idx)]; \ MPI_Type_contiguous(Count, BaseType, &dt); \ MPI_Type_set_name(dt, Name); \ @@ -121,11 +137,11 @@ void Foam::PstreamGlobals::deinitDataTypes() // User types only auto first = ( - MPIdataTypes_.begin() + int(UPstream::dataTypes::UserTypes_begin) + MPIdataTypes_.begin() + int(UPstream::dataTypes::User_begin) ); const auto last = ( - MPIdataTypes_.begin() + int(UPstream::dataTypes::UserTypes_end) + MPIdataTypes_.begin() + int(UPstream::dataTypes::User_end) ); for (; first != last; ++first) @@ -200,20 +216,20 @@ void Foam::PstreamGlobals::printDataTypes(bool all) std::cerr << "enumerated data types:\n"; print ( - UPstream::dataTypes::DataTypes_begin, - UPstream::dataTypes::DataTypes_end + UPstream::dataTypes::Basic_begin, + UPstream::dataTypes::Basic_end ); } else { // User types only. std::cerr << "enumerated user-defined data types:\n"; - print - ( - UPstream::dataTypes::UserTypes_begin, - UPstream::dataTypes::UserTypes_end - ); } + print + ( + UPstream::dataTypes::User_begin, + UPstream::dataTypes::User_end + ); } diff --git a/src/Pstream/mpi/PstreamGlobals.H b/src/Pstream/mpi/PstreamGlobals.H index dd7930209d6..e895883992f 100644 --- a/src/Pstream/mpi/PstreamGlobals.H +++ b/src/Pstream/mpi/PstreamGlobals.H @@ -63,18 +63,28 @@ extern DynamicList<MPI_Comm> MPICommunicators_; //- Outstanding non-blocking operations. extern DynamicList<MPI_Request> outstandingRequests_; -typedef Foam::FixedList<MPI_Datatype, 15> DataTypeLookupTable; +// The fundamental count for each UPstream::dataTypes entry +typedef Foam::FixedList<int, 17> DataTypeCountLookupTable; -//- MPI data types corresponding to some fundamental and OpenFOAM types. +//- Fundamental count for each valid UPstream::dataTypes entry +//- Indexed by UPstream::dataTypes enum +extern DataTypeCountLookupTable dataTypesCount_; + +// For UPstream::dataTypes lookup, includes space for last 'invalid' entry +typedef Foam::FixedList<MPI_Datatype, 17> DataTypeLookupTable; + +//- MPI data types corresponding to fundamental and OpenFOAM types. //- Indexed by UPstream::dataTypes enum extern DataTypeLookupTable MPIdataTypes_; +// For UPstream::opCodes lookup, includes space for last 'invalid' entry typedef Foam::FixedList<MPI_Op, 13> OpCodesLookupTable; //- MPI operation types, indexed by UPstream::opCodes enum extern OpCodesLookupTable MPIopCodes_; + // * * * * * * * * * * * * * * * Communicators * * * * * * * * * * * * * * * // //- Initialize bookkeeping for MPI communicator index -- GitLab From 151f4df5464e14b389f0b7341704fdc3ffbc76d8 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Fri, 28 Feb 2025 09:24:40 +0100 Subject: [PATCH 08/15] ENH: add opaque data types to UPstream bridge code - permits more flexible handling at the caller level --- .../IOstreams/Pstreams/PstreamBroadcast.txx | 3 +- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 174 +++++++++++++ src/Pstream/dummy/UIPstreamRead.C | 19 ++ src/Pstream/dummy/UOPstreamWrite.C | 20 ++ src/Pstream/dummy/UPstreamBroadcast.C | 17 +- src/Pstream/dummy/UPstreamGatherScatter.C | 70 +++++- src/Pstream/dummy/UPstreamReduce.C | 30 ++- src/Pstream/mpi/UIPBstreamRead.C | 3 +- src/Pstream/mpi/UIPstreamRead.C | 178 ++++++++------ src/Pstream/mpi/UOPBstreamWrite.C | 3 +- src/Pstream/mpi/UOPstreamWrite.C | 108 +++++--- src/Pstream/mpi/UPstream.C | 4 +- src/Pstream/mpi/UPstreamBroadcast.C | 87 ++++--- src/Pstream/mpi/UPstreamGatherScatter.C | 231 +++++++++++++++++- src/Pstream/mpi/UPstreamReduce.C | 179 +++++++++++++- src/Pstream/mpi/UPstreamWrapping.txx | 23 +- 16 files changed, 992 insertions(+), 157 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx index 1e9bd139316..23193de0dd3 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx @@ -121,10 +121,11 @@ void Foam::Pstream::broadcastList label len(list.size()); - UPstream::broadcast + UPstream::mpi_broadcast ( reinterpret_cast<char*>(&len), sizeof(label), + UPstream::dataTypes::type_byte, communicator ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index 208ce835060..2373facaa8b 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -502,6 +502,180 @@ private: static void freeCommunicatorComponents(const label index); +protected: + + // Protected Member Functions + + // Static Functions + + //- Broadcast buffer contents from rank=0 to all ranks. + //- The sizes must match on all processes. + // For \b non-parallel : do nothing. + // + // \note The method uses a \c void pointer and the required data type + // (as per MPI). This means it should almost never be called directly + // but always via a compile-time checked caller. + // \return True on success + static bool mpi_broadcast + ( + void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int communicator + ); + + //- In-place reduction of \c values with result on rank 0. + // Includes internal parallel guard and checks on data types, opcode. + // + // \note The method uses a \c void pointer and the required data type + // (as per MPI). This means it should almost never be called directly + // but always via a compile-time checked caller. + static void mpi_reduce + ( + void* values, + int count, + const UPstream::dataTypes dataTypeId, + const UPstream::opCodes opCodeId, + const int communicator, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- In-place reduction of \c values with same result on all ranks. + // Includes internal parallel guard and checks on data types, opcode. + // + // \note The method uses a \c void pointer and the required data type + // (as per MPI). This means it should almost never be called directly + // but always via a compile-time checked caller. + static void mpi_allreduce + ( + void* values, + int count, + const UPstream::dataTypes dataTypeId, + const UPstream::opCodes opCodeId, + const int communicator, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- Send buffer contents of specified data type to given processor. + // + // \note The method uses a \c void pointer and the required data type + // (as per MPI). This means it should almost never be called directly + // but always via a compile-time checked caller. + // \return True on success (or Fatal) + static bool mpi_send + ( + const UPstream::commsTypes commsType, + const void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int toProcNo, + const int tag, // eg, UPstream::msgType() + const int communicator, // eg, UPstream::worldComm + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr, + //! optional send mode (normal | sync) + const UPstream::sendModes sendMode = UPstream::sendModes::normal + ); + + //- Receive buffer contents of specified data type from given processor. + // + // \note The method uses a \c void pointer and the required data type + // (as per MPI). This means it should almost never be called directly + // but always via a compile-time checked caller. + // The commsType will be ignored if UPstream::Request is specified. + // + // \return number of elements read. May change in the future + static std::streamsize mpi_receive + ( + const UPstream::commsTypes commsType, + void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int fromProcNo, + const int tag, // eg, UPstream::msgType() + const int communicator, // eg, UPstream::worldComm + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- Receive identically-sized (contiguous) data from all ranks + // Includes internal parallel guard. + // For non-parallel, does not copy any data. + // If needed, this must be done by the caller. + static void mpi_gather + ( + //! On rank: individual value to send (or nullptr for inplace) + const void* sendData, + //! Master: receive buffer with all values + //! Or for in-place send/recv when sendData is nullptr + void* recvData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const UPstream::dataTypes dataTypeId, + const int communicator, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- Send identically-sized (contiguous) data to all ranks + // Includes internal parallel guard. + static void mpi_scatter + ( + //! On master: send buffer with all values (nullptr for inplace) + const void* sendData, + //! On rank: individual value to receive + //! Or for in-place send/recv when sendData is nullptr + void* recvData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const UPstream::dataTypes dataTypeId, + const int communicator, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- Gather/scatter identically-sized data + // Send data from proc slot, receive into all slots + static void mpi_allgather + ( + //! On all ranks: the base of the data locations + void* allData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const UPstream::dataTypes dataTypeId, + const int communicator, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr + ); + + //- Receive variable length data from all ranks. + //- (caution: known to scale poorly) + static void mpi_gatherv + ( + const void* sendData, + int sendCount, //!< Ignored on master if recvCount[0] == 0 + void* recvData, //!< Ignored on non-root rank + const UList<int>& recvCounts, //!< Ignored on non-root rank + const UList<int>& recvOffsets, //!< Ignored on non-root rank + const UPstream::dataTypes dataTypeId, + const int communicator + ); + + //- Send variable length data to all ranks + //- (caution: known to scale poorly) + static void mpi_scatterv + ( + const void* sendData, //!< Ignored on non-root rank + const UList<int>& sendCounts, //!< Ignored on non-root rank + const UList<int>& sendOffsets, //!< Ignored on non-root rank + void* recvData, + int recvCount, + const UPstream::dataTypes dataTypeId, + const int communicator + ); + public: //- Declare name of the class and its debug switch diff --git a/src/Pstream/dummy/UIPstreamRead.C b/src/Pstream/dummy/UIPstreamRead.C index 7c82adb7f3f..359b602e3ff 100644 --- a/src/Pstream/dummy/UIPstreamRead.C +++ b/src/Pstream/dummy/UIPstreamRead.C @@ -28,6 +28,25 @@ License #include "UIPstream.H" +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // + +std::streamsize Foam::UPstream::mpi_receive +( + const UPstream::commsTypes commsType, + void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int fromProcNo, + const int tag, + const int communicator, + UPstream::Request* req +) +{ + NotImplemented; + return 0; +} + + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::UIPstream::bufferIPCrecv() diff --git a/src/Pstream/dummy/UOPstreamWrite.C b/src/Pstream/dummy/UOPstreamWrite.C index dfd4be78afe..ccbafad4062 100644 --- a/src/Pstream/dummy/UOPstreamWrite.C +++ b/src/Pstream/dummy/UOPstreamWrite.C @@ -37,6 +37,26 @@ bool Foam::UOPstream::bufferIPCsend() } +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // + +bool Foam::UPstream::mpi_send +( + const UPstream::commsTypes commsType, + const void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int toProcNo, + const int tag, + const int communicator, + UPstream::Request* req, + const UPstream::sendModes sendMode +) +{ + NotImplemented; + return false; +} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::UOPstream::write diff --git a/src/Pstream/dummy/UPstreamBroadcast.C b/src/Pstream/dummy/UPstreamBroadcast.C index 079512f255e..ae2825a51b9 100644 --- a/src/Pstream/dummy/UPstreamBroadcast.C +++ b/src/Pstream/dummy/UPstreamBroadcast.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,6 +27,21 @@ License #include "UPstream.H" +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // + +bool Foam::UPstream::mpi_broadcast +( + void* buf, + std::streamsize count, + const UPstream::dataTypes dataTypeId, + const int communicator +) +{ + // Treat like serial + return true; +} + + // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::UPstream::broadcast diff --git a/src/Pstream/dummy/UPstreamGatherScatter.C b/src/Pstream/dummy/UPstreamGatherScatter.C index 9034fc75f39..346b3e1768c 100644 --- a/src/Pstream/dummy/UPstreamGatherScatter.C +++ b/src/Pstream/dummy/UPstreamGatherScatter.C @@ -26,7 +26,75 @@ License \*---------------------------------------------------------------------------*/ #include "UPstream.H" -#include <cstring> // memmove + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_gather +( + const void* sendData, + void* recvData, + int count, + const UPstream::dataTypes dataTypeId, + + const int communicator, + UPstream::Request* req +) +{} + + +void Foam::UPstream::mpi_scatter +( + const void* sendData, + void* recvData, + int count, + const UPstream::dataTypes dataTypeId, + + const int communicator, + UPstream::Request* req +) +{} + + +void Foam::UPstream::mpi_allgather +( + void* allData, + int count, + const UPstream::dataTypes dataTypeId, + + const int communicator, + UPstream::Request* req +) +{} + + +void Foam::UPstream::mpi_gatherv +( + const void* sendData, + int sendCount, + void* recvData, + const UList<int>& recvCounts, + const UList<int>& recvOffsets, + + const UPstream::dataTypes dataTypeId, + const int communicator +) +{} + + +void Foam::UPstream::mpi_scatterv +( + const void* sendData, + const UList<int>& sendCounts, + const UList<int>& sendOffsets, + + void* recvData, + int recvCount, + + const UPstream::dataTypes dataTypeId, + const int communicator +) +{} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/Pstream/dummy/UPstreamReduce.C b/src/Pstream/dummy/UPstreamReduce.C index 9572d0e52d1..1a6affb0478 100644 --- a/src/Pstream/dummy/UPstreamReduce.C +++ b/src/Pstream/dummy/UPstreamReduce.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -28,7 +28,7 @@ License #include "Pstream.H" #include "PstreamReduceOps.H" -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // Special reductions for bool @@ -58,6 +58,32 @@ void Foam::reduce {} +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // + +void Foam::UPstream::mpi_reduce +( + void* values, + int count, + const UPstream::dataTypes dataTypeId, + const UPstream::opCodes opCodeId, + const int communicator, + UPstream::Request* req +) +{} + + +void Foam::UPstream::mpi_allreduce +( + void* values, + int count, + const UPstream::dataTypes dataTypeId, + const UPstream::opCodes opCodeId, + const int communicator, + UPstream::Request* req +) +{} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Common reductions diff --git a/src/Pstream/mpi/UIPBstreamRead.C b/src/Pstream/mpi/UIPBstreamRead.C index 22b5fa48111..93db0ff80f9 100644 --- a/src/Pstream/mpi/UIPBstreamRead.C +++ b/src/Pstream/mpi/UIPBstreamRead.C @@ -85,10 +85,11 @@ void Foam::UIPBstream::bufferIPCrecv() if ( (count > 0) // ie, not empty - && !UPstream::broadcast + && !UPstream::mpi_broadcast ( recvBuf_.data(), recvBuf_.size(), // same as count + UPstream::dataTypes::type_byte, comm_ ) ) diff --git a/src/Pstream/mpi/UIPstreamRead.C b/src/Pstream/mpi/UIPstreamRead.C index 4f5fe7e2a78..f3a367a4be0 100644 --- a/src/Pstream/mpi/UIPstreamRead.C +++ b/src/Pstream/mpi/UIPstreamRead.C @@ -35,41 +35,47 @@ License // - as of 2023-06 appears to be broken with INTELMPI + PMI-2 (slurm) // and perhaps other places so currently avoid -#undef Pstream_use_MPI_Get_count - -// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // // General blocking/non-blocking MPI receive -static std::streamsize UPstream_mpi_receive +std::streamsize Foam::UPstream::mpi_receive ( - const Foam::UPstream::commsTypes commsType, - char* buf, - const std::streamsize bufSize, + const UPstream::commsTypes commsType, + void* buf, // Type checking done by caller + std::streamsize count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller const int fromProcNo, const int tag, const int communicator, - Foam::UPstream::Request* req + UPstream::Request* req ) { - using namespace Foam; + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); PstreamGlobals::reset_request(req); + // Could check if nonBlocking and request are consistently specified... + + // TODO: some corrective action, at least when not nonBlocking #if 0 // No warnings here, just on the sender side. - if (bufSize > std::streamsize(INT_MAX)) + if (count > std::streamsize(INT_MAX)) { - Perr<< "UIPstream::read() : from rank " << fromProcNo - << " exceeds INT_MAX bytes" << Foam::endl; + Perr<< "[mpi_recv] from rank " << fromProcNo + << " exceeds INT_MAX values of " + << PstreamGlobals::dataType_name(datatype) + << Foam::endl; + error::printStack(Perr); } #endif if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { - Perr<< "UIPstream::read : starting read from:" << fromProcNo - << " size:" << label(bufSize) + Perr<< "[mpi_recv] : starting recv from:" << fromProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " comm:" << communicator << " commsType:" << UPstream::commsTypeNames[commsType] << " warnComm:" << UPstream::warnComm @@ -78,8 +84,9 @@ static std::streamsize UPstream_mpi_receive } else if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UIPstream::read : starting read from:" << fromProcNo - << " size:" << label(bufSize) + Perr<< "[mpi_recv] : starting recv from:" << fromProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " comm:" << communicator << " commsType:" << UPstream::commsTypeNames[commsType] << Foam::endl; @@ -103,68 +110,75 @@ static std::streamsize UPstream_mpi_receive returnCode = MPI_Recv ( buf, - bufSize, - MPI_BYTE, + count, + datatype, fromProcNo, tag, PstreamGlobals::MPICommunicators_[communicator], - &status + &status ); } profilingPstream::addGatherTime(); - if (returnCode != MPI_SUCCESS) + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) { FatalErrorInFunction - << "MPI_Recv cannot receive incoming message" + << "[mpi_recv] : cannot receive message from:" + << fromProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << Foam::abort(FatalError); return 0; } else if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UIPstream::read : finished recv from:" + Perr<< "[mpi_recv] : finished recv from:" << fromProcNo - << " size:" << label(bufSize) << " tag:" << tag + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << Foam::endl; } - // Check size of message read - #ifdef Pstream_use_MPI_Get_count - int count(0); - MPI_Get_count(&status, MPI_BYTE, &count); - #else - MPI_Count count(0); - MPI_Get_elements_x(&status, MPI_BYTE, &count); - #endif + // Check size of message read (number of basic elements) + MPI_Count num_recv(0); + MPI_Get_elements_x(&status, datatype, &num_recv); // Errors - if (count == MPI_UNDEFINED || int64_t(count) < 0) + if (FOAM_UNLIKELY(num_recv == MPI_UNDEFINED || int64_t(num_recv) < 0)) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " - "returned undefined or negative value" + << "[mpi_recv] : receive from:" << fromProcNo + << " type:" << int(dataTypeId) + << " received count is undefined or negative value" << Foam::abort(FatalError); } - else if (int64_t(count) > int64_t(UList<char>::max_size())) + else + { + // From number of basic elements to number of 'datatype' + num_recv /= PstreamGlobals::dataTypesCount_[int(dataTypeId)]; + } + + if (FOAM_UNLIKELY(int64_t(num_recv) > int64_t(UList<char>::max_size()))) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " - "count is larger than UList<char>::max_size() bytes" + << "[mpi_recv] : receive from:" << fromProcNo + << " type:" << int(dataTypeId) + << " received count is larger than UList<T>::max_size()" << Foam::abort(FatalError); } - - - if (bufSize < std::streamsize(count)) + else if (FOAM_UNLIKELY(count < std::streamsize(num_recv))) { FatalErrorInFunction - << "buffer (" << label(bufSize) - << ") not large enough for incoming message (" - << label(count) << ')' + << "[mpi_recv] : receive from:" << fromProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) + << " buffer is too small for incoming message (" + << label(num_recv) << ')' << Foam::abort(FatalError); } - return std::streamsize(count); + return std::streamsize(num_recv); } else if (commsType == UPstream::commsTypes::nonBlocking) { @@ -174,19 +188,22 @@ static std::streamsize UPstream_mpi_receive returnCode = MPI_Irecv ( buf, - bufSize, - MPI_BYTE, + count, + datatype, fromProcNo, tag, PstreamGlobals::MPICommunicators_[communicator], - &request + &request ); } - if (returnCode != MPI_SUCCESS) + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) { FatalErrorInFunction - << "MPI_Irecv cannot start non-blocking receive" + << "[mpi_recv] : cannot start non-blocking receive from:" + << fromProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << Foam::abort(FatalError); return 0; @@ -198,16 +215,17 @@ static std::streamsize UPstream_mpi_receive if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UIPstream::read : started non-blocking recv from:" + Perr<< "[mpi_recv] : started non-blocking recv from:" << fromProcNo - << " size:" << label(bufSize) << " tag:" << tag + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " request:" << (req ? label(-1) : PstreamGlobals::outstandingRequests_.size()) << Foam::endl; } // Assume the message will be completely received. - return bufSize; + return count; } FatalErrorInFunction @@ -264,63 +282,64 @@ void Foam::UIPstream::bufferIPCrecv() profilingPstream::addProbeTime(); - - #ifdef Pstream_use_MPI_Get_count - int count(0); - MPI_Get_count(&status, MPI_BYTE, &count); - #else - MPI_Count count(0); - MPI_Get_elements_x(&status, MPI_BYTE, &count); - #endif + // Buffer of characters (bytes) + MPI_Count num_recv(0); + MPI_Get_elements_x(&status, MPI_BYTE, &num_recv); // Errors - if (count == MPI_UNDEFINED || int64_t(count) < 0) + if (FOAM_UNLIKELY(num_recv == MPI_UNDEFINED || int64_t(num_recv) < 0)) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " - "returned undefined or negative value" + << "UIPstream IPC read buffer from:" << fromProcNo_ + << " received count is undefined or negative value" << Foam::abort(FatalError); } - else if (int64_t(count) > int64_t(UList<char>::max_size())) + + // Count is already in basic elements, no need to scale the result + + if (FOAM_UNLIKELY(int64_t(num_recv) > int64_t(UList<char>::max_size()))) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " - "count is larger than UList<char>::max_size() bytes" + << "UIPstream IPC read buffer from:" << fromProcNo_ + << " received count is larger than UList<T>::max_size()" << Foam::abort(FatalError); } if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UIPstream::UIPstream : probed size:" - << label(count) << Foam::endl; + Perr<< "UIPstream::bufferIPCrecv : probed size:" + << label(num_recv) << Foam::endl; } - recvBuf_.resize(label(count)); - messageSize_ = label(count); + recvBuf_.resize(label(num_recv)); + messageSize_ = label(num_recv); } - std::streamsize count = UPstream_mpi_receive + std::streamsize count = UPstream::mpi_receive ( commsType(), - recvBuf_.data(), - messageSize_, // The expected size + recvBuf_.data(), // buffer + messageSize_, // expected size + UPstream::dataTypes::type_byte, // MPI_BYTE fromProcNo_, tag_, comm_, nullptr // UPstream::Request ); - if (count < 0) + // Errors + if (FOAM_UNLIKELY(count < 0)) { FatalErrorInFunction - << "MPI_recv() with negative size??" + << "UIPstream IPC read buffer from:" << fromProcNo_ + << " with negative size?" << Foam::abort(FatalError); } - else if (int64_t(count) > int64_t(UList<char>::max_size())) + else if (FOAM_UNLIKELY(int64_t(count) > int64_t(UList<char>::max_size()))) { FatalErrorInFunction - << "MPI_recv() larger than " - "UList<char>::max_size() bytes" + << "UIPstream IPC read buffer from:" << fromProcNo_ + << " received size is larger than UList<T>::max_size()" << Foam::abort(FatalError); } @@ -348,11 +367,12 @@ std::streamsize Foam::UIPstream::read UPstream::Request* req ) { - return UPstream_mpi_receive + return UPstream::mpi_receive ( commsType, buf, bufSize, + UPstream::dataTypes::type_byte, fromProcNo, tag, communicator, diff --git a/src/Pstream/mpi/UOPBstreamWrite.C b/src/Pstream/mpi/UOPBstreamWrite.C index 6a9348e8806..90c96ab3a2d 100644 --- a/src/Pstream/mpi/UOPBstreamWrite.C +++ b/src/Pstream/mpi/UOPBstreamWrite.C @@ -57,10 +57,11 @@ bool Foam::UOPBstream::bufferIPCsend() if ( (count > 0) // ie, not empty - && !UPstream::broadcast + && !UPstream::mpi_broadcast ( sendBuf_.data(), sendBuf_.size(), // same as count + UPstream::dataTypes::type_byte, comm_ ) ) diff --git a/src/Pstream/mpi/UOPstreamWrite.C b/src/Pstream/mpi/UOPstreamWrite.C index 8ebb2375464..e4aabbb2dea 100644 --- a/src/Pstream/mpi/UOPstreamWrite.C +++ b/src/Pstream/mpi/UOPstreamWrite.C @@ -46,36 +46,47 @@ bool Foam::UOPstream::bufferIPCsend() } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // -bool Foam::UOPstream::write +// General blocking/non-blocking MPI send +bool Foam::UPstream::mpi_send ( const UPstream::commsTypes commsType, + const void* buf, // Type checking done by caller + std::streamsize count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller const int toProcNo, - const char* buf, - const std::streamsize bufSize, const int tag, const int communicator, UPstream::Request* req, const UPstream::sendModes sendMode ) { + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + PstreamGlobals::reset_request(req); + // Could check if nonBlocking and request are consistently specified... + + // TODO: some corrective action, at least when not nonBlocking #if 0 - if (bufSize > std::streamsize(INT_MAX)) + if (count > std::streamsize(INT_MAX)) { - Perr<< "UOPstream::write() : to rank " << toProcNo - << " exceeds INT_MAX bytes" << Foam::endl; + Perr<< "[mpi_send] : to rank " << toProcNo + << " type:" << int(dataTypeId) + << " exceeds INT_MAX values" + << Foam::endl; + error::printStack(Perr); } #endif if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { - Perr<< "UOPstream::write : starting write to:" << toProcNo - << " size:" << label(bufSize) + Perr<< "[mpi_send] : starting send to:" << toProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " comm:" << communicator << " commType:" << UPstream::commsTypeNames[commsType] << " warnComm:" << UPstream::warnComm @@ -84,8 +95,9 @@ bool Foam::UOPstream::write } else if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UOPstream::write : starting write to:" << toProcNo - << " size:" << label(bufSize) + Perr<< "[mpi_send] : starting send to:" << toProcNo + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " comm:" << communicator << " commType:" << UPstream::commsTypeNames[commsType] << Foam::endl; @@ -101,9 +113,9 @@ bool Foam::UOPstream::write { returnCode = MPI_Bsend ( - const_cast<char*>(buf), - bufSize, - MPI_BYTE, + buf, + count, + datatype, toProcNo, tag, PstreamGlobals::MPICommunicators_[communicator] @@ -114,9 +126,9 @@ bool Foam::UOPstream::write if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UOPstream::write : finished buffered send to:" + Perr<< "[mpi_send] : finished buffered send to:" << toProcNo - << " size:" << label(bufSize) << " tag:" << tag + << " count:" << label(count) << " tag:" << tag << Foam::endl; } } @@ -126,9 +138,9 @@ bool Foam::UOPstream::write { returnCode = MPI_Ssend ( - const_cast<char*>(buf), - bufSize, - MPI_BYTE, + buf, + count, + datatype, toProcNo, tag, PstreamGlobals::MPICommunicators_[communicator] @@ -138,9 +150,9 @@ bool Foam::UOPstream::write { returnCode = MPI_Send ( - const_cast<char*>(buf), - bufSize, - MPI_BYTE, + buf, + count, + datatype, toProcNo, tag, PstreamGlobals::MPICommunicators_[communicator] @@ -152,9 +164,10 @@ bool Foam::UOPstream::write if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UOPstream::write : finished send to:" + Perr<< "[mpi_send] : finished send to:" << toProcNo - << " size:" << label(bufSize) << " tag:" << tag + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << Foam::endl; } } @@ -166,9 +179,9 @@ bool Foam::UOPstream::write { returnCode = MPI_Issend ( - const_cast<char*>(buf), - bufSize, - MPI_BYTE, + buf, + count, + datatype, toProcNo, tag, PstreamGlobals::MPICommunicators_[communicator], @@ -179,9 +192,9 @@ bool Foam::UOPstream::write { returnCode = MPI_Isend ( - const_cast<char*>(buf), - bufSize, - MPI_BYTE, + buf, + count, + datatype, toProcNo, tag, PstreamGlobals::MPICommunicators_[communicator], @@ -191,9 +204,10 @@ bool Foam::UOPstream::write if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UOPstream::write : started non-blocking send to:" + Perr<< "[mpi_send] : started non-blocking send to:" << toProcNo - << " size:" << label(bufSize) << " tag:" << tag + << " type:" << int(dataTypeId) + << " count:" << label(count) << " tag:" << tag << " request:" << (req ? label(-1) : PstreamGlobals::outstandingRequests_.size()) << Foam::endl; @@ -207,10 +221,40 @@ bool Foam::UOPstream::write FatalErrorInFunction << "Unsupported communications type " << int(commsType) << Foam::abort(FatalError); + return false; } return (returnCode == MPI_SUCCESS); } +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::UOPstream::write +( + const UPstream::commsTypes commsType, + const int toProcNo, + const char* buf, + const std::streamsize bufSize, + const int tag, + const int communicator, + UPstream::Request* req, + const UPstream::sendModes sendMode +) +{ + return UPstream::mpi_send + ( + commsType, + buf, + bufSize, + UPstream::dataTypes::type_byte, + toProcNo, + tag, + communicator, + req, + sendMode + ); +} + + // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstream.C b/src/Pstream/mpi/UPstream.C index a3bfe3ab429..1b051b072fb 100644 --- a/src/Pstream/mpi/UPstream.C +++ b/src/Pstream/mpi/UPstream.C @@ -1253,14 +1253,14 @@ Foam::UPstream::probeMessage MPI_Get_elements_x(&status, MPI_BYTE, &num_recv); // Errors - if (num_recv == MPI_UNDEFINED || int64_t(num_recv) < 0) + if (FOAM_UNLIKELY(num_recv == MPI_UNDEFINED || int64_t(num_recv) < 0)) { FatalErrorInFunction << "MPI_Get_elements_x() : " "returned undefined or negative value" << Foam::abort(FatalError); } - else if (int64_t(num_recv) > int64_t(INT_MAX)) + else if (FOAM_UNLIKELY(int64_t(num_recv) > int64_t(INT_MAX))) { FatalErrorInFunction << "MPI_Get_elements_x() : " diff --git a/src/Pstream/mpi/UPstreamBroadcast.C b/src/Pstream/mpi/UPstreamBroadcast.C index 1b3669d3a41..686fb230ad4 100644 --- a/src/Pstream/mpi/UPstreamBroadcast.C +++ b/src/Pstream/mpi/UPstreamBroadcast.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,51 +29,62 @@ License #include "PstreamGlobals.H" #include "profilingPstream.H" -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // -bool Foam::UPstream::broadcast +bool Foam::UPstream::mpi_broadcast ( - char* buf, - const std::streamsize bufSize, - const label comm, - const int rootProcNo + void* buf, // Type checking done by caller + std::streamsize count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + const int communicator // Index into MPICommunicators_ ) { - if (!UPstream::is_parallel(comm)) + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if (!count || !UPstream::is_parallel(communicator)) { // Nothing to do - ignore return true; } - //Needed? PstreamGlobals::checkCommunicator(comm, rootProcNo); + //Needed? PstreamGlobals::checkCommunicator(communicator, 0); - if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(comm))) + // Without MPI_Bcast_c() + if (FOAM_UNLIKELY(count > std::streamsize(INT_MAX))) { - Perr<< "UPstream::broadcast : root:" << rootProcNo - << " comm:" << comm - << " size:" << label(bufSize) - << " warnComm:" << UPstream::warnComm - << Foam::endl; - error::printStack(Perr); + FatalErrorInFunction + << "Broadcast size " << label(count) + << " exceeds INT_MAX bytes" << Foam::endl + << Foam::abort(FatalError); + return false; } - else if (FOAM_UNLIKELY(UPstream::debug)) + + if (FOAM_UNLIKELY(UPstream::debug)) { - Perr<< "UPstream::broadcast : root:" << rootProcNo - << " comm:" << comm - << " size:" << label(bufSize) + Perr<< "[mpi_broadcast] :" + << " type:" << int(dataTypeId) + << " count:" << label(count) + << " comm:" << communicator << Foam::endl; } + int returnCode = MPI_SUCCESS; + profilingPstream::beginTiming(); - const int returnCode = MPI_Bcast - ( - buf, - bufSize, - MPI_BYTE, - rootProcNo, - PstreamGlobals::MPICommunicators_[comm] - ); + { + // Regular broadcast + // OR: PstreamDetail::broadcast0(buf, count, datatype, communicator); + + returnCode = MPI_Bcast + ( + buf, + count, + datatype, + 0, // (root rank) == UPstream::masterNo() + PstreamGlobals::MPICommunicators_[communicator] + ); + } profilingPstream::addBroadcastTime(); @@ -81,4 +92,24 @@ bool Foam::UPstream::broadcast } +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::UPstream::broadcast +( + char* buf, + const std::streamsize count, + const label communicator, + const int rootProcNo +) +{ + return UPstream::mpi_broadcast + ( + buf, + count, + UPstream::dataTypes::type_byte, + communicator + ); +} + + // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstreamGatherScatter.C b/src/Pstream/mpi/UPstreamGatherScatter.C index 36cac86dd42..39470d5488f 100644 --- a/src/Pstream/mpi/UPstreamGatherScatter.C +++ b/src/Pstream/mpi/UPstreamGatherScatter.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -26,9 +26,236 @@ License \*---------------------------------------------------------------------------*/ #include "Pstream.H" +#include "PstreamGlobals.H" #include "UPstreamWrapping.H" -#include <cinttypes> +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +static inline bool is_basic_dataType(Foam::UPstream::dataTypes id) noexcept +{ + return + ( + int(id) >= int(Foam::UPstream::dataTypes::Basic_begin) + && int(id) < int(Foam::UPstream::dataTypes::Basic_end) + ); +} + +namespace +{ + +using namespace Foam; + +// Local function to print some error information +inline void printErrorNonIntrinsic +( + const char* context, + UPstream::dataTypes dataTypeId +) +{ + FatalError + << "Bad input for " << context << ": likely a programming problem\n" + << " Non-intrinsic data (" << int(dataTypeId) << ")\n" + << Foam::endl; +} + +} // End anonymous namespace + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_gather +( + const void* sendData, // Type checking done by caller + void* recvData, // Type checking done by caller + int count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + + const int communicator, // Index into MPICommunicators_ + UPstream::Request* req +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if (FOAM_UNLIKELY(UPstream::debug)) + { + Perr<< "[mpi_gather] : " + << " type:" << int(dataTypeId) << " count:" << count + << " comm:" << communicator + << Foam::endl; + } + + { + // Regular gather + + PstreamDetail::gather + ( + sendData, + recvData, + count, + datatype, + communicator, + req + ); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_scatter +( + const void* sendData, // Type checking done by caller + void* recvData, // Type checking done by caller + int count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + + const int communicator, // Index into MPICommunicators_ + UPstream::Request* req +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if (FOAM_UNLIKELY(UPstream::debug)) + { + Perr<< "[mpi_scatter] : " + << " type:" << int(dataTypeId) << " count:" << count + << " comm:" << communicator + << Foam::endl; + } + + { + // Regular scatter + + PstreamDetail::scatter + ( + sendData, + recvData, + count, + datatype, + communicator, + req + ); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_allgather +( + void* allData, // Type checking done by caller + int count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + + const int communicator, // Index into MPICommunicators_ + UPstream::Request* req +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if (FOAM_UNLIKELY(UPstream::debug)) + { + Perr<< "[mpi_allgather] : " + << " type:" << int(dataTypeId) << " count:" << count + << " comm:" << communicator + << Foam::endl; + } + + { + // Regular all gather + + PstreamDetail::allGather + ( + allData, + count, + datatype, + communicator, + req + ); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_gatherv +( + const void* sendData, + int sendCount, + void* recvData, + const UList<int>& recvCounts, + const UList<int>& recvOffsets, + + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + const int communicator +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if + ( + FOAM_UNLIKELY + ( + !is_basic_dataType(dataTypeId) + ) + ) + { + FatalErrorInFunction; + printErrorNonIntrinsic("MPI_Gatherv()", dataTypeId); + FatalError << Foam::abort(FatalError); + } + + { + PstreamDetail::gatherv + ( + sendData, sendCount, + recvData, recvCounts, recvOffsets, + datatype, communicator + ); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +void Foam::UPstream::mpi_scatterv +( + const void* sendData, + const UList<int>& sendCounts, + const UList<int>& sendOffsets, + + void* recvData, + int recvCount, + + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + const int communicator +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + + if + ( + FOAM_UNLIKELY + ( + !is_basic_dataType(dataTypeId) + ) + ) + { + FatalErrorInFunction; + printErrorNonIntrinsic("MPI_Scatterv()", dataTypeId); + FatalError << Foam::abort(FatalError); + } + + { + PstreamDetail::scatterv + ( + sendData, sendCounts, sendOffsets, + recvData, recvCount, + datatype, communicator + ); + } +} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/Pstream/mpi/UPstreamReduce.C b/src/Pstream/mpi/UPstreamReduce.C index d9e96a89ceb..e388bbb75b2 100644 --- a/src/Pstream/mpi/UPstreamReduce.C +++ b/src/Pstream/mpi/UPstreamReduce.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2022-2023 OpenCFD Ltd. + Copyright (C) 2022-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -31,7 +31,7 @@ License #include <cinttypes> -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // Special reductions for bool @@ -71,6 +71,181 @@ void Foam::reduce } +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +static inline bool is_basic_dataType(Foam::UPstream::dataTypes id) noexcept +{ + return + ( + int(id) >= int(Foam::UPstream::dataTypes::Basic_begin) + && int(id) < int(Foam::UPstream::dataTypes::Basic_end) + ); +} + +static inline bool is_reduce_opCode(Foam::UPstream::opCodes id) noexcept +{ + return + ( + int(id) >= int(Foam::UPstream::opCodes::Basic_begin) + && int(id) < int(Foam::UPstream::opCodes::Basic_end) + ); +} + + +namespace +{ + +using namespace Foam; + +// Local function to print some error information +void printErrorMessage +( + const void* values, + const UPstream::dataTypes datatype_id, + const UPstream::opCodes opcode_id +) +{ + FatalError + << "Bad input for reduce(): likely a programming problem\n"; + + if (!is_basic_dataType(datatype_id)) + { + FatalError<< " Non-basic data tyoe (" << int(datatype_id) << ")\n"; + } + + if (!is_reduce_opCode(opcode_id)) + { + FatalError<< " Invalid reduce op (" << int(opcode_id) << ")\n"; + } + + if (values == nullptr) + { + FatalError<< " nullptr for values\n"; + } + FatalError<< Foam::endl; +} + +} // End anonymous namespace + + +// * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // + +void Foam::UPstream::mpi_reduce +( + void* values, // Type checking done by caller + int count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + const UPstream::opCodes opCodeId, // Proper code passed by caller + const int communicator, // Index into MPICommunicators_ + UPstream::Request* req +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + MPI_Op optype = PstreamGlobals::getOpCode(opCodeId); + + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing to do - ignore + return; + } + if + ( + FOAM_UNLIKELY + ( + !is_basic_dataType(dataTypeId) + || !is_reduce_opCode(opCodeId) + || (values == nullptr) + ) + ) + { + FatalErrorInFunction; + printErrorMessage(values, dataTypeId, opCodeId); + FatalError << Foam::abort(FatalError); + } + + if (FOAM_UNLIKELY(UPstream::debug)) + { + Perr<< "[mpi_reduce] : " + << " op:" << int(opCodeId) + << " type:" << int(dataTypeId) << " count:" << count + << " comm:" << communicator + << Foam::endl; + } + + { + // Regular reduce + + PstreamDetail::reduce0 + ( + values, + count, + datatype, + optype, + communicator, + req + ); + } +} + + +void Foam::UPstream::mpi_allreduce +( + void* values, // Type checking done by caller + int count, + const UPstream::dataTypes dataTypeId, // Proper type passed by caller + const UPstream::opCodes opCodeId, // Proper code passed by caller + const int communicator, // Index into MPICommunicators_ + UPstream::Request* req +) +{ + MPI_Datatype datatype = PstreamGlobals::getDataType(dataTypeId); + MPI_Op optype = PstreamGlobals::getOpCode(opCodeId); + + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing to do - ignore + return; + } + if + ( + FOAM_UNLIKELY + ( + !is_basic_dataType(dataTypeId) + || !is_reduce_opCode(opCodeId) + || (values == nullptr) + ) + ) + { + FatalErrorInFunction; + printErrorMessage(values, dataTypeId, opCodeId); + FatalError << Foam::abort(FatalError); + } + + if (FOAM_UNLIKELY(UPstream::debug)) + { + Perr<< "[mpi_allreduce] : " + << " op:" << int(opCodeId) + << " type:" << int(dataTypeId) << " count:" << count + << " comm:" << communicator + << Foam::endl; + } + + { + // Regular allReduce + + PstreamDetail::allReduce + ( + values, + count, + datatype, + optype, + communicator, + req + ); + } +} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Common reductions diff --git a/src/Pstream/mpi/UPstreamWrapping.txx b/src/Pstream/mpi/UPstreamWrapping.txx index 057c0e6025f..ac9ce01792e 100644 --- a/src/Pstream/mpi/UPstreamWrapping.txx +++ b/src/Pstream/mpi/UPstreamWrapping.txx @@ -997,7 +997,7 @@ void Foam::PstreamDetail::gather const bool immediate = (req); - if (!UPstream::is_rank(communicator) || !count) + if (!count || !UPstream::is_rank(communicator)) { return; } @@ -1115,7 +1115,7 @@ void Foam::PstreamDetail::scatter const bool immediate = (req); - if (!UPstream::is_rank(communicator) || !count) + if (!count || !UPstream::is_rank(communicator)) { return; } @@ -1243,9 +1243,14 @@ void Foam::PstreamDetail::gatherv } else if (!UPstream::is_parallel(communicator)) { - // recvCounts[0] may be invalid - use sendCount instead - if (sendData && recvData) + if constexpr (std::is_void_v<Type>) { + // Cannot copy data here since we don't know the number of bytes + // - must be done by the caller. + } + else if (sendData && recvData) + { + // recvCounts[0] may be invalid - use sendCount instead std::memmove(recvData, sendData, sendCount*sizeof(Type)); } return; @@ -1385,7 +1390,15 @@ void Foam::PstreamDetail::scatterv } else if (!UPstream::is_parallel(communicator)) { - std::memmove(recvData, sendData, recvCount*sizeof(Type)); + if constexpr (std::is_void_v<Type>) + { + // Cannot copy data here since we don't know the number of bytes + // - must be done by the caller. + } + else if (sendData && recvData) + { + std::memmove(recvData, sendData, recvCount*sizeof(Type)); + } return; } -- GitLab From f0b844eb47d247bdc6b45dc7b7befa2fb392319f Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Fri, 28 Feb 2025 10:41:10 +0100 Subject: [PATCH 09/15] ENH: generalize MPI broadcast to basic and user-defined MPI types - simplify and rationalize some of the broadcast methods for more code reuse. The bottom level UPstream::broadcast is now always to/from "root=0". This was previously passed as a default parameter, but never used anything other than '0' in the code. Fixing it as '0' makes it consistent with the 'top-down' logical for node-based broadcast. --- .../test/globalIndex3/Test-globalIndex3.cxx | 4 +- src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H | 9 +++ .../IOstreams/Pstreams/PstreamBroadcast.txx | 73 +++++++++++++++---- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 14 ++-- .../db/IOstreams/Pstreams/UPstream.txx | 38 ++++++++++ .../parallel/globalIndex/globalIndex.C | 7 +- src/Pstream/dummy/UPstreamBroadcast.C | 15 ---- src/Pstream/mpi/UPstreamBroadcast.C | 20 ----- 8 files changed, 115 insertions(+), 65 deletions(-) diff --git a/applications/test/globalIndex3/Test-globalIndex3.cxx b/applications/test/globalIndex3/Test-globalIndex3.cxx index d6ae4a658e5..19beee62390 100644 --- a/applications/test/globalIndex3/Test-globalIndex3.cxx +++ b/applications/test/globalIndex3/Test-globalIndex3.cxx @@ -345,8 +345,8 @@ static void reportOffsets(const globalIndex& gi) UPstream::broadcast ( - allOffsets.data_bytes(), - allOffsets.size_bytes(), + allOffsets.data(), + allOffsets.size(), interNodeComm ); } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index ef8acb773b1..1563a8da480 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -109,6 +109,15 @@ public: const int communicator = UPstream::worldComm ); + //- Broadcast fixed-list content (contiguous or non-contiguous) to all + //- communicator ranks. Does nothing in \b non-parallel. + template<class Type, unsigned N> + static void broadcast + ( + FixedList<Type, N>& list, + const int communicator = UPstream::worldComm + ); + //- Broadcast multiple items to all communicator ranks. //- Does nothing in \b non-parallel. template<class Type, class... Args> diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx index 23193de0dd3..447d2685447 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamBroadcast.txx @@ -43,7 +43,6 @@ void Foam::Pstream::broadcast } else if constexpr (is_contiguous_v<Type>) { - // Note: contains parallel guard internally UPstream::broadcast ( reinterpret_cast<char*>(&value), @@ -65,6 +64,37 @@ void Foam::Pstream::broadcast } +template<class Type, unsigned N> +void Foam::Pstream::broadcast +( + FixedList<Type, N>& list, + const int communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + return; + } + else if constexpr (is_contiguous_v<Type>) + { + // Size is known and identical on all ranks + UPstream::broadcast(list.data(), list.size(), communicator); + } + else + { + // Non-contiguous content - serialize it + if (UPstream::master(communicator)) + { + OPBstream::send(list, communicator); + } + else + { + IPBstream::recv(list, communicator); + } + } +} + + template<class Type, class... Args> void Foam::Pstream::broadcasts ( @@ -77,8 +107,15 @@ void Foam::Pstream::broadcasts { return; } + else if constexpr (!sizeof...(values) && is_contiguous_v<Type>) + { + // A single-value and contiguous + UPstream::broadcast(&value, 1, communicator); + } else { + // Non-contiguous data, or multiple data - needs serialization + if (UPstream::master(communicator)) { OPBstream::sends @@ -129,19 +166,10 @@ void Foam::Pstream::broadcastList communicator ); - if (UPstream::is_subrank(communicator)) - { - list.resize_nocopy(len); - } - if (len) { - UPstream::broadcast - ( - list.data_bytes(), - list.size_bytes(), - communicator - ); + // Only broadcast non-empty content + UPstream::broadcast(list.data(), list.size(), communicator); } } else @@ -150,13 +178,28 @@ void Foam::Pstream::broadcastList if (UPstream::master(communicator)) { - OPBstream os(communicator); - os << list; + if (list.empty()) + { + // Do not serialize if empty. + // Just broadcast zero-size in a form that IPBstream can expect + OPBstream::send(Foam::zero{}, communicator); + } + else + { + OPBstream::send(list, communicator); + } } else { IPBstream is(communicator); - is >> list; + if (is.remaining() > 0) // Received a non-empty buffer + { + is >> list; + } + else + { + list.clear(); + } } } } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index 2373facaa8b..40643472e2f 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -1720,16 +1720,16 @@ public: // Broadcast Functions - //- Broadcast buffer contents to all processes in given communicator. - //- The sizes must match on all processes. + //- Broadcast buffer contents (contiguous types), from rank=0 + //- to all ranks. The sizes must match on all processes. // For \b non-parallel : do nothing. // \return True on success - static bool broadcast + template<class Type> + inline static bool broadcast ( - char* buf, - const std::streamsize bufSize, - const label communicator, - const int rootProcNo = masterNo() + Type* buffer, + std::streamsize count, + const int communicator ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx index 844b203446d..076b6c0e54c 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx @@ -27,6 +27,44 @@ License // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +template<class Type> +bool Foam::UPstream::broadcast +( + Type* buffer, + std::streamsize count, + const int communicator +) +{ + // Likely no reason to check for nullptr + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do - ignore + return true; + } + else if constexpr (!is_contiguous_v<Type>) + { + // Also report parameters to silence compiler warnings about unused + FatalErrorInFunction + << "Invalid for non-contiguous data types." + << " buffer:" << (buffer != nullptr) + << " count:" << count + << Foam::abort(FatalError); + return false; + } + else + { + // Use element or component type (or byte-wise) for data type + return UPstream::mpi_broadcast + ( + buffer, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + communicator + ); + } +} + + template<class T> Foam::List<T> Foam::UPstream::allGatherValues ( diff --git a/src/OpenFOAM/parallel/globalIndex/globalIndex.C b/src/OpenFOAM/parallel/globalIndex/globalIndex.C index 95f64b161c6..12113485a4f 100644 --- a/src/OpenFOAM/parallel/globalIndex/globalIndex.C +++ b/src/OpenFOAM/parallel/globalIndex/globalIndex.C @@ -319,12 +319,7 @@ bool Foam::globalIndex::splitNodeOffsets allOffsets.resize_nocopy(numProc+1); } - UPstream::broadcast - ( - allOffsets.data_bytes(), - allOffsets.size_bytes(), - interNodeComm - ); + UPstream::broadcast(allOffsets.data(), allOffsets.size(), interNodeComm); if (FOAM_UNLIKELY(allOffsets.empty())) diff --git a/src/Pstream/dummy/UPstreamBroadcast.C b/src/Pstream/dummy/UPstreamBroadcast.C index ae2825a51b9..0e87b5b50bc 100644 --- a/src/Pstream/dummy/UPstreamBroadcast.C +++ b/src/Pstream/dummy/UPstreamBroadcast.C @@ -42,19 +42,4 @@ bool Foam::UPstream::mpi_broadcast } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -bool Foam::UPstream::broadcast -( - char* buf, - const std::streamsize bufSize, - const label comm, - const int rootProcNo -) -{ - // Nothing to do - ignore - return true; -} - - // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstreamBroadcast.C b/src/Pstream/mpi/UPstreamBroadcast.C index 686fb230ad4..91f4b1abfc6 100644 --- a/src/Pstream/mpi/UPstreamBroadcast.C +++ b/src/Pstream/mpi/UPstreamBroadcast.C @@ -92,24 +92,4 @@ bool Foam::UPstream::mpi_broadcast } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -bool Foam::UPstream::broadcast -( - char* buf, - const std::streamsize count, - const label communicator, - const int rootProcNo -) -{ - return UPstream::mpi_broadcast - ( - buf, - count, - UPstream::dataTypes::type_byte, - communicator - ); -} - - // ************************************************************************* // -- GitLab From c7fc9d4ddcf28db5867bc0b2695362b8344776f9 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 25 Feb 2025 19:26:23 +0100 Subject: [PATCH 10/15] ENH: extend MPI send/recv types - support send/recv of basic types (int32, float, double, ...) in addition to common OpenFOAM vectorspace types (floatVector, doubleVector, ...) This permits sending NUM items of the given types instead of sending NUM sizeof() bytes. For a vector (as double): 1 item instead of 24 items (3*8 bytes). For a tensor (as double): 1 item instead of 72 items (9*8 bytes). --- .../db/IOstreams/Pstreams/UIPstream.H | 111 +++------- .../db/IOstreams/Pstreams/UIPstream.txx | 187 ++++++++++++++++ .../db/IOstreams/Pstreams/UOPstream.H | 102 +++++---- .../db/IOstreams/Pstreams/UOPstream.txx | 200 ++++++++++++++++++ src/Pstream/dummy/UIPstreamRead.C | 18 -- src/Pstream/dummy/UOPstreamWrite.C | 19 -- src/Pstream/mpi/UIPstreamRead.C | 27 --- src/Pstream/mpi/UOPstreamWrite.C | 29 --- 8 files changed, 461 insertions(+), 232 deletions(-) create mode 100644 src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.txx create mode 100644 src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.txx diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H index 33b40e8a22b..42ecd8f1d6c 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.H @@ -33,6 +33,7 @@ Description Not to be used directly, thus contructors are protected. SourceFiles + UIPstream.txx UIPstreamBase.C \*---------------------------------------------------------------------------*/ @@ -283,48 +284,36 @@ public: // Static Functions - //- Read buffer contents from given processor. - // \return the message size (bytes read). May change in the future + //- Receive buffer contents (contiguous types) from given processor. + // \return the message size (elements read). May change in the future + template<class Type> static std::streamsize read ( const UPstream::commsTypes commsType, const int fromProcNo, - char* buf, - const std::streamsize bufSize, + Type* buffer, + std::streamsize count, const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr ); - //- Read buffer contents (non-blocking) from given processor. - // \return the message size (bytes read). May change in the future + //- Read buffer contents (non-blocking) from given processor + // \return number of elements read. May change in the future + template<class Type> inline static std::streamsize read ( //! [out] request information UPstream::Request& req, const int fromProcNo, - char* buf, - const std::streamsize bufSize, + Type* buffer, + std::streamsize count, const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm - ) - { - return UIPstream::read - ( - UPstream::commsTypes::nonBlocking, - fromProcNo, - buf, - bufSize, - tag, - communicator, - &req - ); - } + ); - //- Read into UList storage from given processor. - // Only valid for contiguous data types. - // \return the message size (bytes read). May change in the future + //- Receive into UList storage from given processor. template<class Type> inline static std::streamsize read ( @@ -335,23 +324,9 @@ public: const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr - ) - { - return UIPstream::read - ( - commsType, - fromProcNo, - buffer.data_bytes(), - buffer.size_bytes(), - tag, - communicator, - req - ); - } + ); - //- Read into SubList storage from given processor. - // Only valid for contiguous data types. - // \return the message size (bytes read). May change in the future + //- Receive into SubList storage from given processor. template<class Type> inline static std::streamsize read ( @@ -362,23 +337,9 @@ public: const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr - ) - { - return UIPstream::read - ( - commsType, - fromProcNo, - buffer.data_bytes(), - buffer.size_bytes(), - tag, - communicator, - req - ); - } + ); - //- Read into UList storage (non-blocking) from given processor. - // Only valid for contiguous data types. - // \return the message size (bytes read). May change in the future + //- Receive into UList storage (non-blocking) from given processor. template<class Type> inline static std::streamsize read ( @@ -388,23 +349,9 @@ public: UList<Type>& buffer, const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm - ) - { - return UIPstream::read - ( - UPstream::commsTypes::nonBlocking, - fromProcNo, - buffer.data_bytes(), - buffer.size_bytes(), - tag, - communicator, - &req - ); - } + ); - //- Read into SubList storage (non-blocking) from given processor. - // Only valid for contiguous data types. - // \return the message size (bytes read). May change in the future + //- Receive into SubList storage (non-blocking) from given processor. template<class Type> inline static std::streamsize read ( @@ -414,19 +361,7 @@ public: SubList<Type> buffer, // passed by shallow copy const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm - ) - { - return UIPstream::read - ( - UPstream::commsTypes::nonBlocking, - fromProcNo, - buffer.data_bytes(), - buffer.size_bytes(), - tag, - communicator, - &req - ); - } + ); }; @@ -473,6 +408,12 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#ifdef NoRepository + #include "UIPstream.txx" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + #endif // ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.txx new file mode 100644 index 00000000000..4ee2044924e --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UIPstream.txx @@ -0,0 +1,187 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2025 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +template<class Type> +std::streamsize Foam::UIPstream::read +( + const UPstream::commsTypes commsType, + const int fromProcNo, + Type* buffer, + std::streamsize count, + const int tag, + const int communicator, + [[maybe_unused]] UPstream::Request* req +) +{ + if constexpr (!is_contiguous_v<Type>) + { + // Report parameters to silence compiler warnings about unused + FatalErrorInFunction + << "Invalid for non-contiguous data types. " + << int(commsType) << ':' << fromProcNo + << ':' << (buffer != nullptr) + << ':' << count + << ':' << tag + << ':' << communicator + << Foam::abort(FatalError); + return 0; + } + else + { + // Use element or component type (or byte-wise) for data type + return UPstream::mpi_receive + ( + commsType, + buffer, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + fromProcNo, + tag, + communicator, + req + ); + } +} + + +template<class Type> +std::streamsize Foam::UIPstream::read +( + UPstream::Request& req, + const int fromProcNo, + Type* buffer, + std::streamsize count, + const int tag, + const int communicator +) +{ + return UIPstream::read + ( + UPstream::commsTypes::nonBlocking, + fromProcNo, + buffer, + count, + tag, + communicator, + &req + ); +} + + +template<class Type> +std::streamsize Foam::UIPstream::read +( + const UPstream::commsTypes commsType, + const int fromProcNo, + UList<Type>& buffer, + const int tag, + const int communicator, + UPstream::Request* req +) +{ + return UIPstream::read + ( + commsType, + fromProcNo, + buffer.data(), buffer.size(), + tag, + communicator, + req + ); +} + + +template<class Type> +std::streamsize Foam::UIPstream::read +( + const UPstream::commsTypes commsType, + const int fromProcNo, + SubList<Type> buffer, + const int tag, + const int communicator, + UPstream::Request* req +) +{ + return UIPstream::read + ( + commsType, + fromProcNo, + buffer.data(), buffer.size(), + tag, + communicator, + req + ); +} + + +template<class Type> +std::streamsize Foam::UIPstream::read +( + UPstream::Request& req, + const int fromProcNo, + UList<Type>& buffer, + const int tag, + const int communicator +) +{ + return UIPstream::read + ( + UPstream::commsTypes::nonBlocking, + fromProcNo, + buffer.data(), buffer.size(), + tag, + communicator, + &req + ); +} + + +template<class Type> +std::streamsize Foam::UIPstream::read +( + UPstream::Request& req, + const int fromProcNo, + SubList<Type> buffer, + const int tag, + const int communicator +) +{ + return UIPstream::read + ( + UPstream::commsTypes::nonBlocking, + fromProcNo, + buffer.data(), buffer.size(), + tag, + communicator, + &req + ); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H index d1550c4d9c5..0dc65315f18 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.H @@ -33,6 +33,7 @@ Description Not to be used directly, thus contructors are protected. SourceFiles + UOPstream.txx UOPstreamBase.C \*---------------------------------------------------------------------------*/ @@ -358,51 +359,39 @@ public: // Static Functions - //- Write buffer contents to given processor + //- Write buffer contents (contiguous types only) to given processor // \return True on success + template<class Type> static bool write ( const UPstream::commsTypes commsType, const int toProcNo, - const char* buf, - const std::streamsize bufSize, + const Type* buffer, + std::streamsize count, const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm, //! [out] request information (for non-blocking) UPstream::Request* req = nullptr, + //! optional send mode (normal | sync) const UPstream::sendModes sendMode = UPstream::sendModes::normal ); - //- Write buffer contents (non-blocking) to given processor + //- Write buffer contents (contiguous types only) to given processor // \return True on success + template<class Type> inline static bool write ( //! [out] request information UPstream::Request& req, const int toProcNo, - const char* buf, - const std::streamsize bufSize, + const Type* buffer, + std::streamsize count, const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm, const UPstream::sendModes sendMode = UPstream::sendModes::normal - ) - { - return UOPstream::write - ( - UPstream::commsTypes::nonBlocking, - toProcNo, - buf, - bufSize, - tag, - communicator, - &req, - sendMode - ); - } + ); - //- Write UList contents to given processor. - // Only valid for contiguous data types. - // \return True on success + //- Send UList contiguous contents to given processor. template<class Type> inline static bool write ( @@ -414,24 +403,23 @@ public: //! [out] request information (for non-blocking) UPstream::Request* req = nullptr, const UPstream::sendModes sendMode = UPstream::sendModes::normal - ) - { - return UOPstream::write - ( - commsType, - toProcNo, - buffer.cdata_bytes(), - buffer.size_bytes(), - tag, - communicator, - req, - sendMode - ); - } + ); - //- Write UList contents (non-blocking) to given processor. - // Only valid for contiguous data types. - // \return True on success + //- Send SubList contiguous contents to given processor. + template<class Type> + inline static bool write + ( + const UPstream::commsTypes commsType, + const int toProcNo, + const SubList<Type> buffer, // passed by shallow copy + const int tag = UPstream::msgType(), + const int communicator = UPstream::worldComm, + //! [out] request information (for non-blocking) + UPstream::Request* req = nullptr, + const UPstream::sendModes sendMode = UPstream::sendModes::normal + ); + + //- Send UList contiguous contents (non-blocking) to given processor. template<class Type> inline static bool write ( @@ -442,20 +430,20 @@ public: const int tag = UPstream::msgType(), const int communicator = UPstream::worldComm, const UPstream::sendModes sendMode = UPstream::sendModes::normal - ) - { - return UOPstream::write - ( - UPstream::commsTypes::nonBlocking, - toProcNo, - buffer.cdata_bytes(), - buffer.size_bytes(), - tag, - communicator, - &req, - sendMode - ); - } + ); + + //- Send SubList contiguous contents (non-blocking) to given processor. + template<class Type> + inline static bool write + ( + //! [out] request information + UPstream::Request& req, + const int toProcNo, + const SubList<Type> buffer, // passed by shallow copy + const int tag = UPstream::msgType(), + const int communicator = UPstream::worldComm, + const UPstream::sendModes sendMode = UPstream::sendModes::normal + ); }; @@ -510,6 +498,12 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#ifdef NoRepository + #include "UOPstream.txx" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + #endif // ************************************************************************* // diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.txx new file mode 100644 index 00000000000..940dfc5a166 --- /dev/null +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UOPstream.txx @@ -0,0 +1,200 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2025 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +template<class Type> +bool Foam::UOPstream::write +( + const UPstream::commsTypes commsType, + const int toProcNo, + const Type* buffer, + std::streamsize count, + const int tag, + const int communicator, + [[maybe_unused]] UPstream::Request* req, + const UPstream::sendModes sendMode +) +{ + if constexpr (!is_contiguous_v<Type>) + { + // Report parameters to silence compiler warnings about unused + FatalErrorInFunction + << "Invalid for non-contiguous data types. " + << int(commsType) << ':' << int(sendMode) + << ':' << toProcNo + << ':' << (buffer != nullptr) + << ':' << count + << ':' << tag + << ':' << communicator + << Foam::abort(FatalError); + return false; + } + else + { + // Use element or component type (or byte-wise) for data type + return UPstream::mpi_send + ( + commsType, + buffer, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + toProcNo, + tag, + communicator, + req, + sendMode + ); + } +} + + +template<class Type> +bool Foam::UOPstream::write +( + UPstream::Request& req, + const int toProcNo, + const Type* buffer, + std::streamsize count, + const int tag, + const int communicator, + const UPstream::sendModes sendMode +) +{ + return UOPstream::write + ( + UPstream::commsTypes::nonBlocking, + toProcNo, + buffer, + count, + tag, + communicator, + &req, + sendMode + ); +} + + +template<class Type> +bool Foam::UOPstream::write +( + const UPstream::commsTypes commsType, + const int toProcNo, + const UList<Type>& buffer, + const int tag, + const int communicator, + UPstream::Request* req, + const UPstream::sendModes sendMode +) +{ + return UOPstream::write + ( + commsType, + toProcNo, + buffer.cdata(), buffer.size(), + tag, + communicator, + req, + sendMode + ); +} + + +template<class Type> +bool Foam::UOPstream::write +( + const UPstream::commsTypes commsType, + const int toProcNo, + const SubList<Type> buffer, + const int tag, + const int communicator, + UPstream::Request* req, + const UPstream::sendModes sendMode +) +{ + return UOPstream::write + ( + commsType, + toProcNo, + buffer.cdata(), buffer.size(), + tag, + communicator, + req, + sendMode + ); +} + + +template<class Type> +bool Foam::UOPstream::write +( + UPstream::Request& req, + const int toProcNo, + const UList<Type>& buffer, + const int tag, + const int communicator, + const UPstream::sendModes sendMode +) +{ + return UOPstream::write + ( + UPstream::commsTypes::nonBlocking, + toProcNo, + buffer.cdata(), buffer.size(), + tag, + communicator, + &req, + sendMode + ); +} + + +template<class Type> +bool Foam::UOPstream::write +( + UPstream::Request& req, + const int toProcNo, + const SubList<Type> buffer, + const int tag, + const int communicator, + const UPstream::sendModes sendMode +) +{ + return UOPstream::write + ( + UPstream::commsTypes::nonBlocking, + toProcNo, + buffer.cdata(), buffer.size(), + tag, + communicator, + &req, + sendMode + ); +} + + +// ************************************************************************* // diff --git a/src/Pstream/dummy/UIPstreamRead.C b/src/Pstream/dummy/UIPstreamRead.C index 359b602e3ff..396a7a204b7 100644 --- a/src/Pstream/dummy/UIPstreamRead.C +++ b/src/Pstream/dummy/UIPstreamRead.C @@ -55,22 +55,4 @@ void Foam::UIPstream::bufferIPCrecv() } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -std::streamsize Foam::UIPstream::read -( - const UPstream::commsTypes commsType, - const int fromProcNo, - char* buf, - const std::streamsize bufSize, - const int tag, - const int communicator, - UPstream::Request* req -) -{ - NotImplemented; - return 0; -} - - // ************************************************************************* // diff --git a/src/Pstream/dummy/UOPstreamWrite.C b/src/Pstream/dummy/UOPstreamWrite.C index ccbafad4062..b6f2a61f6db 100644 --- a/src/Pstream/dummy/UOPstreamWrite.C +++ b/src/Pstream/dummy/UOPstreamWrite.C @@ -57,23 +57,4 @@ bool Foam::UPstream::mpi_send } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -bool Foam::UOPstream::write -( - const UPstream::commsTypes commsType, - const int toProcNo, - const char* buf, - const std::streamsize bufSize, - const int tag, - const int communicator, - UPstream::Request* req, - const UPstream::sendModes sendMode -) -{ - NotImplemented; - return false; -} - - // ************************************************************************* // diff --git a/src/Pstream/mpi/UIPstreamRead.C b/src/Pstream/mpi/UIPstreamRead.C index f3a367a4be0..050995e952b 100644 --- a/src/Pstream/mpi/UIPstreamRead.C +++ b/src/Pstream/mpi/UIPstreamRead.C @@ -354,31 +354,4 @@ void Foam::UIPstream::bufferIPCrecv() } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -std::streamsize Foam::UIPstream::read -( - const UPstream::commsTypes commsType, - const int fromProcNo, - char* buf, - const std::streamsize bufSize, - const int tag, - const int communicator, - UPstream::Request* req -) -{ - return UPstream::mpi_receive - ( - commsType, - buf, - bufSize, - UPstream::dataTypes::type_byte, - fromProcNo, - tag, - communicator, - req - ); -} - - // ************************************************************************* // diff --git a/src/Pstream/mpi/UOPstreamWrite.C b/src/Pstream/mpi/UOPstreamWrite.C index e4aabbb2dea..dca49157c27 100644 --- a/src/Pstream/mpi/UOPstreamWrite.C +++ b/src/Pstream/mpi/UOPstreamWrite.C @@ -228,33 +228,4 @@ bool Foam::UPstream::mpi_send } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -bool Foam::UOPstream::write -( - const UPstream::commsTypes commsType, - const int toProcNo, - const char* buf, - const std::streamsize bufSize, - const int tag, - const int communicator, - UPstream::Request* req, - const UPstream::sendModes sendMode -) -{ - return UPstream::mpi_send - ( - commsType, - buf, - bufSize, - UPstream::dataTypes::type_byte, - toProcNo, - tag, - communicator, - req, - sendMode - ); -} - - // ************************************************************************* // -- GitLab From 20b6aeb4dd3be6454a1cf47e57336aed079f9253 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 25 Feb 2025 19:26:28 +0100 Subject: [PATCH 11/15] ENH: generalize reduce/all-reduce to include MPI types - for known data types (and component aggregates), and intrisic reduction operation can now use UPstream::mpiReduce(), UPstream::mpiAllReduce(). This change permits more operations to use MPI calls directly. eg, reduce(vec, sumOp<vector>); now calls mpiAllReduce(..., op_sum) instead of point-to-point, followed by a broadcast. Similarly, when called as a simple reduction (not all-reduce) Pstream::gather(vec, sumOp<vector>); now calls mpiReduce(..., op_sum) instead of point-to-point - extend use of MPI calls to list-wise reductions as well - extend sumReduce() to bundle/unbundle vector-space types, which lowers overall communication. Before: 1) send/recv + binary op through a communication tree 2) broadcast 3) all-reduce of the count Now: 1) pack into a local bundle 2) all-reduce 3) unpack the bundle --- src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H | 86 ++-- .../db/IOstreams/Pstreams/PstreamGather.txx | 93 ++-- .../IOstreams/Pstreams/PstreamGatherList.txx | 6 +- .../db/IOstreams/Pstreams/PstreamReduceOps.H | 439 ++++++++---------- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 47 +- .../db/IOstreams/Pstreams/UPstream.txx | 104 ++++- .../fields/Fields/Field/FieldFunctions.C | 2 +- src/OpenFOAM/meshes/lduMesh/lduMesh.H | 13 +- .../meshes/lduMesh/lduMeshTemplates.C | 44 +- src/Pstream/dummy/UPstreamReduce.C | 164 +------ src/Pstream/mpi/UPstreamReduce.C | 238 +--------- 11 files changed, 463 insertions(+), 773 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index 1563a8da480..91329be13da 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -150,7 +150,7 @@ public: const UPstream::commsStructList& comms, //!< Communication order //! [in,out] T& value, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ); @@ -166,9 +166,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 T& value, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Gather individual values into list locations. @@ -180,7 +180,7 @@ public: static List<T> listGatherValues ( const T& localValue, - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! Only used for non-contiguous types const int tag = UPstream::msgType() ); @@ -194,7 +194,7 @@ public: static T listScatterValues ( const UList<T>& allValues, - const label comm = UPstream::worldComm, + const int communicator = UPstream::worldComm, //! Only used for non-contiguous types const int tag = UPstream::msgType() ); @@ -208,9 +208,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 T& value, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Reduce inplace (cf. MPI Allreduce) @@ -221,9 +221,9 @@ public: ( //! [in,out] the result is consistent on all ranks T& value, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Same as Pstream::combineReduce @@ -232,12 +232,12 @@ public: ( //! [in,out] the result is consistent on all ranks T& value, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { - Pstream::combineReduce(value, cop, tag, comm); + Pstream::combineReduce(value, cop, tag, communicator); } @@ -251,7 +251,7 @@ public: const UPstream::commsStructList& comms, //!< Communication order //! [in,out] UList<T>& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ); @@ -266,9 +266,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 UList<T>& values, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Forwards to Pstream::listGather with an \em in-place \c cop @@ -277,9 +277,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 UList<T>& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Reduce list elements (list must be equal size on all ranks), @@ -292,9 +292,9 @@ public: ( //! [in,out] the result is consistent on all ranks UList<T>& values, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Forwards to Pstream::listReduce with an \em in-place \c cop @@ -303,9 +303,9 @@ public: ( //! [in,out] the result is consistent on all ranks UList<T>& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Same as Pstream::listCombineReduce @@ -314,12 +314,12 @@ public: ( //! [in,out] the result is consistent on all ranks UList<T>& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { - Pstream::listCombineReduce(values, cop, tag, comm); + Pstream::listCombineReduce(values, cop, tag, communicator); } @@ -332,7 +332,7 @@ public: ( const UPstream::commsStructList& comms, //!< Communication order Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ); @@ -347,9 +347,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Forwards to Pstream::mapGather with an \em in-place \c cop @@ -358,9 +358,9 @@ public: ( //! [in,out] the result is only reliable on rank=0 Container& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Reduce inplace (cf. MPI Allreduce) @@ -374,9 +374,9 @@ public: ( //! [in,out] the result is consistent on all ranks Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Forwards to Pstream::mapReduce with an \em in-place \c cop @@ -385,9 +385,9 @@ public: ( //! [in,out] the result is consistent on all ranks Container& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Same as Pstream::mapCombineReduce @@ -396,12 +396,12 @@ public: ( //! [in,out] the result is consistent on all ranks Container& values, - const CombineOp& cop, + CombineOp cop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { - Pstream::mapCombineReduce(values, cop, tag, comm); + Pstream::mapCombineReduce(values, cop, tag, communicator); } @@ -439,7 +439,7 @@ public: //! [in,out] UList<T>& values, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); //- Gather data, but keep individual values separate. @@ -452,7 +452,7 @@ public: //! [in,out] UList<T>& values, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); @@ -465,7 +465,7 @@ public: //! [in,out] UList<T>& values, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ); @@ -656,7 +656,7 @@ public: ( T& value, const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm + const int comm = UPstream::worldComm ) { Pstream::broadcast(value, comm); @@ -669,7 +669,7 @@ public: ( T& value, const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm + const int comm = UPstream::worldComm ) { Pstream::broadcast(value, comm); @@ -682,7 +682,7 @@ public: ( List<T>& value, const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm + const int comm = UPstream::worldComm ) { Pstream::broadcast(value, comm); @@ -695,7 +695,7 @@ public: ( Container& values, const int tag = UPstream::msgType(), //!< ignored - const label comm = UPstream::worldComm + const int comm = UPstream::worldComm ) { Pstream::broadcast(values, comm); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx index 8aa66bb7951..3b5e34c9739 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx @@ -53,7 +53,7 @@ void Foam::Pstream::gather_algorithm ( const UPstream::commsStructList& comms, // Communication order T& value, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ) @@ -151,9 +151,9 @@ template<class T, class BinaryOp, bool InplaceMode> void Foam::Pstream::gather ( T& value, - const BinaryOp& bop, - const int tag, - const label communicator + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag, + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -161,6 +161,17 @@ void Foam::Pstream::gather // Nothing to do return; } + else if constexpr (!InplaceMode && UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiReduce + ( + &value, + 1, + UPstream_opType<BinaryOp>::opcode_id, + communicator + ); + } else { // Communication order @@ -182,9 +193,9 @@ template<class T, class CombineOp> void Foam::Pstream::combineGather ( T& value, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { // In-place binary operation @@ -196,9 +207,9 @@ template<class T, class CombineOp> void Foam::Pstream::combineReduce ( T& value, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { if (UPstream::is_parallel(comm)) @@ -219,7 +230,7 @@ void Foam::Pstream::listGather_algorithm ( const UPstream::commsStructList& comms, // Communication order UList<T>& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ) @@ -330,9 +341,9 @@ template<class T, class BinaryOp, bool InplaceMode> void Foam::Pstream::listGather ( UList<T>& values, - const BinaryOp& bop, - const int tag, - const label communicator + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag, + const int communicator ) { if (!UPstream::is_parallel(communicator) || values.empty()) @@ -340,6 +351,17 @@ void Foam::Pstream::listGather // Nothing to do return; } + else if constexpr (!InplaceMode && UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiReduce + ( + values.data(), + values.size(), // Same length on all ranks + UPstream_opType<BinaryOp>::opcode_id, + communicator + ); + } else if (values.size() == 1) { // Single value - optimized version @@ -372,15 +394,26 @@ template<class T, class BinaryOp, bool InplaceMode> void Foam::Pstream::listReduce ( UList<T>& values, - const BinaryOp& bop, - const int tag, - const label comm + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag, + const int comm ) { if (!UPstream::is_parallel(comm) || values.empty()) { // Nothing to do } + else if constexpr (!InplaceMode && UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiAllReduce + ( + values.data(), + values.size(), // Same length on all ranks + UPstream_opType<BinaryOp>::opcode_id, + comm + ); + } else if (values.size() == 1) { // Single value - optimized version @@ -400,9 +433,9 @@ template<class T, class CombineOp> void Foam::Pstream::listCombineGather ( UList<T>& values, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { // In-place binary operation @@ -414,9 +447,9 @@ template<class T, class CombineOp> void Foam::Pstream::listCombineReduce ( UList<T>& values, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { // In-place binary operation @@ -433,7 +466,7 @@ void Foam::Pstream::mapGather_algorithm ( const UPstream::commsStructList& comms, // Communication order Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, const int communicator ) @@ -519,9 +552,9 @@ template<class Container, class BinaryOp, bool InplaceMode> void Foam::Pstream::mapGather ( Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -550,9 +583,9 @@ template<class Container, class BinaryOp, bool InplaceMode> void Foam::Pstream::mapReduce ( Container& values, - const BinaryOp& bop, + BinaryOp bop, const int tag, - const label comm + const int comm ) { Pstream::mapGather<Container, BinaryOp, InplaceMode> @@ -567,9 +600,9 @@ template<class Container, class CombineOp> void Foam::Pstream::mapCombineGather ( Container& values, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { // In-place binary operation @@ -584,9 +617,9 @@ template<class Container, class CombineOp> void Foam::Pstream::mapCombineReduce ( Container& values, - const CombineOp& cop, + CombineOp cop, const int tag, - const label comm + const int comm ) { // In-place binary operation @@ -605,7 +638,7 @@ template<class T> Foam::List<T> Foam::Pstream::listGatherValues ( const T& localValue, - const label communicator, + const int communicator, [[maybe_unused]] const int tag ) { @@ -658,7 +691,7 @@ template<class T> T Foam::Pstream::listScatterValues ( const UList<T>& allValues, - const label communicator, + const int communicator, [[maybe_unused]] const int tag ) { diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx index a77c13bda68..085a8778333 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx @@ -415,7 +415,7 @@ void Foam::Pstream::gatherList ( UList<T>& values, [[maybe_unused]] const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -457,7 +457,7 @@ void Foam::Pstream::scatterList ( UList<T>& values, [[maybe_unused]] const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -491,7 +491,7 @@ void Foam::Pstream::allGatherList ( UList<T>& values, [[maybe_unused]] const int tag, - const label comm + const int comm ) { if (!UPstream::is_parallel(comm)) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H index 93a1e4b8e4b..c13757d3c30 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2024 OpenCFD Ltd. + Copyright (C) 2016-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -38,6 +38,7 @@ Description #include "Pstream.H" #include "FixedList.H" #include "ops.H" +#include "VectorSpaceOps.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -46,74 +47,160 @@ namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Single value: mpiAllReduce or manual + //- Reduce inplace (cf. MPI Allreduce) -//- using linear/tree communication schedule template<class T, class BinaryOp> void reduce ( T& value, - const BinaryOp& bop, - const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag = UPstream::msgType(), + const int communicator = UPstream::worldComm ) { - if (UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else if constexpr (UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiAllReduce + ( + &value, + 1, + UPstream_opType<BinaryOp>::opcode_id, + communicator + ); + } + else { - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm) { - Perr<< "** reducing:" << value << " with comm:" << comm << endl; + Perr<< "** reducing:" << value << " comm:" << communicator << endl; error::printStack(Perr); } - Pstream::gather(value, bop, tag, comm); - Pstream::broadcast(value, comm); + Pstream::gather(value, bop, tag, communicator); + Pstream::broadcast(value, communicator); } } +// Multiple values: mpiAllReduce only! + //- Reduce inplace (cf. MPI Allreduce) //- multiple values (same size on all ranks!) template<class T, class BinaryOp> void reduce ( T values[], - const int size, - const BinaryOp&, - const int tag, - const label comm + const int count, + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag, + const int communicator = UPstream::worldComm +) +{ + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else if constexpr (UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiAllReduce + ( + values, + count, + UPstream_opType<BinaryOp>::opcode_id, + communicator + ); + } + else + { + // static_assert(false, "unsupported data type"); + static_assert + ( + stdFoam::dependent_false_v<T>, + "only for specific, contiguous, known data types" + ); + } +} + + +//- Reduce multiple values +// Multiple values: mpiAllReduce only! +template<class T, unsigned N, class BinaryOp> +inline void reduce +( + FixedList<T, N>& values, + BinaryOp bop, + const int tag = UPstream::msgType(), + const int communicator = UPstream::worldComm ) { - NotImplemented; + reduce(values.data(), int(values.size()), bop, tag, communicator); } + //- Non-blocking reduce inplace (cf. MPI Iallreduce) -//- single value. Sets request. +//- multiple values. Sets request. template<class T, class BinaryOp> void reduce ( - T& Value, - const BinaryOp&, - const int tag, - const label comm, + T values[], + int count, + [[maybe_unused]] BinaryOp bop, + [[maybe_unused]] const int tag, + const int communicator, UPstream::Request& req ) { - NotImplemented; + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else if constexpr (UPstream_data_opType<BinaryOp, T>::value) + { + // Valid opcode and (directly/indirectly) uses basic dataType + UPstream::mpiAllReduce + ( + values, + count, + UPstream_opType<BinaryOp>::opcode_id, + communicator, + req + ); + } + else + { + // static_assert(false, "unsupported data type"); + static_assert + ( + stdFoam::dependent_false_v<T>, + "only for specific, contiguous, known data types" + ); + } } + //- Non-blocking reduce inplace (cf. MPI Iallreduce) -//- of multiple values (same size on all ranks!). Sets request. +//- single value. Sets request. template<class T, class BinaryOp> void reduce ( - T values[], - const int size, - const BinaryOp&, + T& value, + BinaryOp bop, const int tag, - const label comm, + const int communicator, UPstream::Request& req ) { - NotImplemented; + // single value + reduce(&value, 1, tag, communicator, req); } @@ -125,245 +212,97 @@ void reduce void reduce ( bool& value, - const andOp<bool>&, - const int tag = UPstream::msgType(), /*!< (ignored) */ - const label comm = UPstream::worldComm + Foam::andOp<bool>, + [[maybe_unused]] const int tag = UPstream::msgType(), /*!< (ignored) */ + const int communicator = UPstream::worldComm ); +// UPstream::reduceAnd(value, communicator); + //- Logical (or) inplace reduction. Uses UPstream::reduceOr void reduce ( bool& value, - const orOp<bool>&, - const int tag = UPstream::msgType(), /*!< (ignored) */ - const label comm = UPstream::worldComm + Foam::orOp<bool>, + [[maybe_unused]] const int tag = UPstream::msgType(), /*!< (ignored) */ + const int communicator = UPstream::worldComm ); - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Common reductions - -#undef Pstream_CommonReductions -#define Pstream_CommonReductions(Native) \ - \ -/*! \brief Reduce (min) multiple Native values (same size on all ranks!) */ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const minOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); \ - \ -/*! \brief Reduce (min) single Native value */ \ -void reduce \ -( \ - Native& value, \ - const minOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); \ - \ -/*! \brief Reduce (min) multiple Native values */ \ -template<unsigned N> \ -inline void reduce \ -( \ - FixedList<Native, N>& values, \ - const minOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -) \ -{ \ - reduce(values.data(), int(values.size()), minOp<Native>(), tag, comm); \ -} \ - \ -/*! \brief Reduce (max) multiple Native values (same size on all ranks!) */ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const maxOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm \ -); \ - \ -/*! \brief Reduce (max) single Native value */ \ -void reduce \ -( \ - Native& value, \ - const maxOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); \ - \ -/*! \brief Reduce (max) multiple Native values */ \ -template<unsigned N> \ -inline void reduce \ -( \ - FixedList<Native, N>& values, \ - const maxOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -) \ -{ \ - reduce(values.data(), int(values.size()), maxOp<Native>(), tag, comm); \ -} \ - \ -/*! \brief Reduce (sum) multiple Native values (same size on all ranks!) */ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm \ -); \ - \ -/*! \brief Reduce (sum) single Native value */ \ -void reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); \ - \ -/*! \brief Reduce (sum) multiple Native values */ \ -template<unsigned N> \ -inline void reduce \ -( \ - FixedList<Native, N>& values, \ - const sumOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -) \ -{ \ - reduce(values.data(), int(values.size()), sumOp<Native>(), tag, comm); \ -} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Floating-point reductions - -#undef Pstream_FloatReductions -#define Pstream_FloatReductions(Native) \ - \ -Pstream_CommonReductions(Native); \ - \ -/*! \brief Non-blocking reduce (sum) multiple Native values. Sets request */ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm, \ - UPstream::Request& req /*!< [out] request information */ \ -); \ - \ -/*! \brief Non-blocking reduce (sum) single Native value. Sets request */ \ -void reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm, \ - UPstream::Request& req /*!< [out] request information */ \ -); - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Bitwise reductions - -#undef Pstream_BitwiseReductions -#define Pstream_BitwiseReductions(Native) \ - \ -/*! \brief Reduce (bit-or) multiple Native values (same size on all ranks!)*/ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const bitOrOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); \ - \ -/*! \brief Reduce (bit-or) single Native value */ \ -void reduce \ -( \ - Native& value, \ - const bitOrOp<Native>&, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -Pstream_CommonReductions(int32_t); -Pstream_CommonReductions(int64_t); -Pstream_CommonReductions(uint32_t); -Pstream_CommonReductions(uint64_t); - -Pstream_FloatReductions(float); -Pstream_FloatReductions(double); - -Pstream_BitwiseReductions(unsigned char); -Pstream_BitwiseReductions(unsigned int); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#undef Pstream_CommonReductions -#undef Pstream_FloatReductions -#undef Pstream_BitwiseReductions +// UPstream::reduceOr(value, communicator); // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // //- Reduce inplace (cf. MPI Allreduce) //- the sum of both value and count (for averaging) -template<class T> +template<class T, class IntType = int> void sumReduce ( T& value, - label& count, - const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + IntType& count, + [[maybe_unused]] const int tag = UPstream::msgType(), + const int communicator = UPstream::worldComm ) { - if (UPstream::is_parallel(comm)) + static_assert(std::is_arithmetic_v<IntType>, "Counter not arithmetic"); + + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else if constexpr (std::is_floating_point_v<T>) + { + // Bundle value and count together + T work[2]; + work[0] = value; + work[1] = static_cast<T>(count); + + UPstream::mpiAllReduce + ( + work, + 2, + UPstream::opCodes::op_sum, + communicator + ); + + // Unbundle + value = work[0]; + count = static_cast<IntType>(work[1]); + } + else if constexpr + ( + is_vectorspace_v<T> + && std::is_floating_point_v<typename pTraits_cmptType<T>::type> + ) { - Foam::reduce(value, sumOp<T>(), tag, comm); - Foam::reduce(count, sumOp<label>(), tag, comm); + constexpr auto nCmpts = pTraits_nComponents<T>::value; + using cmpt = typename pTraits_cmptType<T>::type; + + // Bundle all components and count together + cmpt work[nCmpts+1]; + VectorSpaceOps<nCmpts>::copy_n(value.begin(), work); + work[nCmpts] = static_cast<cmpt>(count); + + UPstream::mpiAllReduce + ( + work, + nCmpts+1, + UPstream::opCodes::op_sum, + communicator + ); + + // Unbundle + VectorSpaceOps<nCmpts>::copy_n(work, value.begin()); + count = static_cast<IntType>(work[nCmpts]); + } + else + { + Foam::reduce(value, sumOp<T>(), tag, communicator); + Foam::reduce(count, sumOp<IntType>(), tag, communicator); } } -// Floating-point sum-reduce - -#undef Pstream_SumReduce -#define Pstream_SumReduce(Native) \ - \ -/*! \brief Sum of both Native value and count (for averaging) */ \ -void sumReduce \ -( \ - Native& value, \ - label& count, \ - const int tag = UPstream::msgType(), /*!< (ignored) */ \ - const label comm = UPstream::worldComm \ -); - - -Pstream_SumReduce(float); -Pstream_SumReduce(double); - -#undef Pstream_SumReduce - - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Convenience wrappers - defined after all specialisations are known @@ -374,13 +313,13 @@ template<class T, class BinaryOp> T returnReduce ( const T& value, - const BinaryOp& bop, + BinaryOp bop, const int tag = UPstream::msgType(), - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { T work(value); - Foam::reduce(work, bop, tag, comm); + Foam::reduce(work, bop, tag, communicator); return work; } @@ -390,11 +329,11 @@ T returnReduce inline bool returnReduceAnd ( const bool value, - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { bool work(value); - UPstream::reduceAnd(work, comm); + UPstream::reduceAnd(work, communicator); return work; } @@ -404,11 +343,11 @@ inline bool returnReduceAnd inline bool returnReduceOr ( const bool value, - const label comm = UPstream::worldComm + const int communicator = UPstream::worldComm ) { bool work(value); - UPstream::reduceOr(work, comm); + UPstream::reduceOr(work, communicator); return work; } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index 40643472e2f..2f6bdb85e49 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -1690,7 +1690,7 @@ public: static List<T> allGatherValues ( const T& localValue, - const label communicator = worldComm + const int communicator = UPstream::worldComm ); //- Gather individual values into list locations. @@ -1702,7 +1702,7 @@ public: static List<T> listGatherValues ( const T& localValue, - const label communicator = worldComm + const int communicator = UPstream::worldComm ); //- Scatter individual values from list locations. @@ -1714,7 +1714,7 @@ public: static T listScatterValues ( const UList<T>& allValues, - const label communicator = worldComm + const int communicator = UPstream::worldComm ); @@ -1733,6 +1733,43 @@ public: ); + // Reductions + + //- MPI_Reduce (blocking) for known operators + // For \b non-parallel : do nothing. + template<class T> + static void mpiReduce + ( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator + ); + + //- MPI_Allreduce (blocking) for known operators + // For \b non-parallel : do nothing. + template<class T> + static void mpiAllReduce + ( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator + ); + + //- MPI_Iallreduce (non-blocking) for known operators + // For \b non-parallel : do nothing. + template<class T> + static void mpiAllReduce + ( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator, + UPstream::Request& req + ); + + // Logical reductions //- Logical (and) reduction (MPI_AllReduce) @@ -1740,7 +1777,7 @@ public: static void reduceAnd ( bool& value, - const label communicator = worldComm + const int communicator = worldComm ); //- Logical (or) reduction (MPI_AllReduce) @@ -1748,7 +1785,7 @@ public: static void reduceOr ( bool& value, - const label communicator = worldComm + const int communicator = worldComm ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx index 076b6c0e54c..9aa479d8175 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx @@ -69,7 +69,7 @@ template<class T> Foam::List<T> Foam::UPstream::allGatherValues ( const T& localValue, - const label comm + const int comm ) { if constexpr (!is_contiguous_v<T>) @@ -101,11 +101,13 @@ Foam::List<T> Foam::UPstream::allGatherValues } +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + template<class T> Foam::List<T> Foam::UPstream::listGatherValues ( const T& localValue, - const label comm + const int comm ) { if constexpr (!is_contiguous_v<T>) @@ -149,7 +151,7 @@ template<class T> T Foam::UPstream::listScatterValues ( const UList<T>& allValues, - const label comm + const int comm ) { if constexpr (!is_contiguous_v<T>) @@ -197,4 +199,100 @@ T Foam::UPstream::listScatterValues } +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class T> +void Foam::UPstream::mpiReduce +( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator +) +{ + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Use element or component type (or byte-wise) for data type + // Restricted to basic data types + UPstream::mpi_reduce + ( + values, // The data or cmpt pointer + UPstream_basic_dataType<T>::size(count), + UPstream_basic_dataType<T>::datatype_id, + opCodeId, + communicator + ); + } +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class T> +void Foam::UPstream::mpiAllReduce +( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator +) +{ + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Use element or component type (or byte-wise) for data type + // Restricted to basic data types + UPstream::mpi_allreduce + ( + values, // The data or cmpt pointer + UPstream_basic_dataType<T>::size(count), + UPstream_basic_dataType<T>::datatype_id, + opCodeId, + communicator + ); + } +} + + +template<class T> +void Foam::UPstream::mpiAllReduce +( + T values[], + int count, + const UPstream::opCodes opCodeId, + const int communicator, + UPstream::Request& req +) +{ + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Use element or component type (or byte-wise) for data type + // Restricted to basic data types + UPstream::mpi_allreduce + ( + values, // The data or cmpt pointer + UPstream_basic_dataType<T>::size(count), + UPstream_basic_dataType<T>::datatype_id, + opCodeId, + communicator, + &req + ); + } +} + + // ************************************************************************* // diff --git a/src/OpenFOAM/fields/Fields/Field/FieldFunctions.C b/src/OpenFOAM/fields/Fields/Field/FieldFunctions.C index 583c4439710..b9053f08627 100644 --- a/src/OpenFOAM/fields/Fields/Field/FieldFunctions.C +++ b/src/OpenFOAM/fields/Fields/Field/FieldFunctions.C @@ -652,7 +652,7 @@ Type gAverage { label n = f1.size(); Type s = sum(f1); - sumReduce(s, n, UPstream::msgType(), comm); + Foam::sumReduce(s, n, UPstream::msgType(), comm); if (n > 0) { diff --git a/src/OpenFOAM/meshes/lduMesh/lduMesh.H b/src/OpenFOAM/meshes/lduMesh/lduMesh.H index 493bbcaabc2..9c7e3045795 100644 --- a/src/OpenFOAM/meshes/lduMesh/lduMesh.H +++ b/src/OpenFOAM/meshes/lduMesh/lduMesh.H @@ -91,11 +91,10 @@ public: //- Helper: reduce with current communicator template<class T, class BinaryOp> - void reduce - ( - T& Value, - const BinaryOp& bop - ) const; + void reduce(T& val, BinaryOp bop) const + { + Foam::reduce(val, bop, UPstream::msgType(), comm()); + } // Info @@ -117,10 +116,6 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#ifdef NoRepository - #include "lduMeshTemplates.C" -#endif - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif diff --git a/src/OpenFOAM/meshes/lduMesh/lduMeshTemplates.C b/src/OpenFOAM/meshes/lduMesh/lduMeshTemplates.C index b44e7454173..7cec1b4541d 100644 --- a/src/OpenFOAM/meshes/lduMesh/lduMeshTemplates.C +++ b/src/OpenFOAM/meshes/lduMesh/lduMeshTemplates.C @@ -1,43 +1 @@ -/*---------------------------------------------------------------------------*\ - ========= | - \\ / F ield | OpenFOAM: The Open Source CFD Toolbox - \\ / O peration | - \\ / A nd | www.openfoam.com - \\/ M anipulation | -------------------------------------------------------------------------------- - Copyright (C) 2013 OpenFOAM Foundation -------------------------------------------------------------------------------- -License - This file is part of OpenFOAM. - - OpenFOAM is free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - OpenFOAM is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for more details. - - You should have received a copy of the GNU General Public License - along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. - -\*---------------------------------------------------------------------------*/ - -#include "lduMesh.H" - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -template<class T, class BinaryOp> -void Foam::lduMesh::reduce -( - T& Value, - const BinaryOp& bop -) const -{ - Foam::reduce(Value, bop, Pstream::msgType(), comm()); -} - - -// ************************************************************************* // +#warning File removed - left for old dependency check only diff --git a/src/Pstream/dummy/UPstreamReduce.C b/src/Pstream/dummy/UPstreamReduce.C index 1a6affb0478..610b06e3579 100644 --- a/src/Pstream/dummy/UPstreamReduce.C +++ b/src/Pstream/dummy/UPstreamReduce.C @@ -32,28 +32,28 @@ License // Special reductions for bool -void Foam::UPstream::reduceAnd(bool& value, const label comm) +void Foam::UPstream::reduceAnd(bool& value, const int communicator) {} -void Foam::UPstream::reduceOr(bool& value, const label comm) +void Foam::UPstream::reduceOr(bool& value, const int communicator) {} void Foam::reduce ( bool& value, - const andOp<bool>&, + Foam::andOp<bool>, const int tag, - const label comm + const int communicator ) {} void Foam::reduce ( bool& value, - const orOp<bool>&, + Foam::orOp<bool>, const int tag, - const label comm + const int communicator ) {} @@ -84,156 +84,4 @@ void Foam::UPstream::mpi_allreduce {} -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Common reductions - -#undef Pstream_CommonReductions -#define Pstream_CommonReductions(Native) \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const minOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const maxOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const minOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const maxOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Floating-point reductions - -#undef Pstream_FloatReductions -#define Pstream_FloatReductions(Native) \ - \ -Pstream_CommonReductions(Native); \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm, \ - UPstream::Request& req \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm, \ - UPstream::Request& req \ -) \ -{} \ - \ -void Foam::sumReduce \ -( \ - Native& value, \ - label& count, \ - const int tag, \ - const label comm \ -) \ -{} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Bitwise reductions - -#undef Pstream_BitwiseReductions -#define Pstream_BitwiseReductions(Native) \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const bitOrOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const bitOrOp<Native>&, \ - const int tag, \ - const label comm \ -) \ -{} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -Pstream_CommonReductions(int32_t); -Pstream_CommonReductions(int64_t); -Pstream_CommonReductions(uint32_t); -Pstream_CommonReductions(uint64_t); - -Pstream_FloatReductions(float); -Pstream_FloatReductions(double); - -Pstream_BitwiseReductions(unsigned char); -Pstream_BitwiseReductions(unsigned int); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#undef Pstream_CommonReductions -#undef Pstream_FloatReductions -#undef Pstream_BitwiseReductions - - // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstreamReduce.C b/src/Pstream/mpi/UPstreamReduce.C index e388bbb75b2..991b72aac41 100644 --- a/src/Pstream/mpi/UPstreamReduce.C +++ b/src/Pstream/mpi/UPstreamReduce.C @@ -35,42 +35,41 @@ License // Special reductions for bool -void Foam::UPstream::reduceAnd(bool& value, const label comm) +void Foam::UPstream::reduceAnd(bool& value, const int communicator) { - PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LAND, comm); + PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LAND, communicator); } -void Foam::UPstream::reduceOr(bool& value, const label comm) +void Foam::UPstream::reduceOr(bool& value, const int communicator) { - PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LOR, comm); + PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LOR, communicator); } void Foam::reduce ( bool& value, - const andOp<bool>&, + Foam::andOp<bool>, const int tag, /* (unused) */ - const label comm + const int communicator ) { - PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LAND, comm); + UPstream::reduceAnd(value, communicator); } void Foam::reduce ( bool& value, - const orOp<bool>&, + Foam::orOp<bool>, const int tag, /* (unused) */ - const label comm + const int communicator ) { - PstreamDetail::allReduce(&value, 1, MPI_C_BOOL, MPI_LOR, comm); + UPstream::reduceOr(value, communicator); } - // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // static inline bool is_basic_dataType(Foam::UPstream::dataTypes id) noexcept @@ -246,221 +245,4 @@ void Foam::UPstream::mpi_allreduce } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Common reductions - -#undef Pstream_CommonReductions -#define Pstream_CommonReductions(Native, TaggedType) \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const minOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_MIN, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const maxOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_MAX, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_SUM, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const minOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_MIN, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const maxOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_MAX, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_SUM, comm \ - ); \ -} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Floating-point reductions - -#undef Pstream_FloatReductions -#define Pstream_FloatReductions(Native, TaggedType) \ - \ -Pstream_CommonReductions(Native, TaggedType); \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm, \ - UPstream::Request& req \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_SUM, comm, &req \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm, \ - UPstream::Request& req \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_SUM, comm, &req \ - ); \ -} \ - \ -void Foam::sumReduce \ -( \ - Native& value, \ - label& count, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - if (UPstream::is_parallel(comm)) \ - { \ - Native values[2]; \ - values[0] = static_cast<Native>(count); \ - values[1] = value; \ - \ - PstreamDetail::allReduce<Native> \ - ( \ - values, 2, TaggedType, MPI_SUM, comm \ - ); \ - \ - count = static_cast<label>(values[0]); \ - value = values[1]; \ - } \ -} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -// Bitwise reductions - -#undef Pstream_BitwiseReductions -#define Pstream_BitwiseReductions(Native, TaggedType) \ - \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const bitOrOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_BOR, comm \ - ); \ -} \ - \ -void Foam::reduce \ -( \ - Native& value, \ - const bitOrOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_BOR, comm \ - ); \ -} \ - -\ -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -Pstream_CommonReductions(int32_t, MPI_INT32_T); -Pstream_CommonReductions(int64_t, MPI_INT64_T); -Pstream_CommonReductions(uint32_t, MPI_UINT32_T); -Pstream_CommonReductions(uint64_t, MPI_UINT64_T); - -Pstream_FloatReductions(float, MPI_FLOAT); -Pstream_FloatReductions(double, MPI_DOUBLE); - -Pstream_BitwiseReductions(unsigned char, MPI_UNSIGNED_CHAR); -Pstream_BitwiseReductions(unsigned int, MPI_UNSIGNED); - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#undef Pstream_CommonReductions -#undef Pstream_FloatReductions -#undef Pstream_BitwiseReductions - - // ************************************************************************* // -- GitLab From 3bf139909833c819717ed36e812b138f34dbc6de Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 25 Feb 2025 19:26:31 +0100 Subject: [PATCH 12/15] ENH: generalize mpiGather/mpiScatter/mpiAllGather - include MPI and component aggregates --- .../IOstreams/Pstreams/PstreamGatherList.txx | 37 +-- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 78 +++--- .../db/IOstreams/Pstreams/UPstream.txx | 253 +++++++++++++----- .../global/profiling/profilingPstream.C | 12 +- src/Pstream/dummy/UPstreamGatherScatter.C | 41 +-- src/Pstream/mpi/UPstreamGatherScatter.C | 46 ---- 6 files changed, 248 insertions(+), 219 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx index 085a8778333..5a3de56ad5d 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx @@ -433,14 +433,8 @@ void Foam::Pstream::gatherList << Foam::abort(FatalError); } - // In-place gather for contiguous types - UPstream::mpiGather - ( - nullptr, - values.data_bytes(), - sizeof(T), - communicator - ); + // In-place gather for contiguous types - one element per rank + UPstream::mpiGather(nullptr, values.data(), 1, communicator); } else { @@ -467,14 +461,8 @@ void Foam::Pstream::scatterList } else if constexpr (is_contiguous_v<T>) { - // In-place scatter for contiguous types - UPstream::mpiScatter - ( - nullptr, - values.data_bytes(), - sizeof(T), - communicator - ); + // In-place scatter for contiguous types - one element per rank + UPstream::mpiScatter(nullptr, values.data(), 1, communicator); } else { @@ -491,33 +479,34 @@ void Foam::Pstream::allGatherList ( UList<T>& values, [[maybe_unused]] const int tag, - const int comm + const int communicator ) { - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { // Nothing to do return; } else if constexpr (is_contiguous_v<T>) { - if (FOAM_UNLIKELY(values.size() < UPstream::nProcs(comm))) + if (FOAM_UNLIKELY(values.size() < UPstream::nProcs(communicator))) { FatalErrorInFunction << "List of values is too small:" << values.size() - << " vs numProcs:" << UPstream::nProcs(comm) << nl + << " vs numProcs:" << UPstream::nProcs(communicator) << nl << Foam::abort(FatalError); } - UPstream::mpiAllGather(values.data_bytes(), sizeof(T), comm); + // Allgather for contiguous types - one element per rank + UPstream::mpiAllGather(values.data(), 1, communicator); } else { // Communication order - const auto& commOrder = UPstream::whichCommunication(comm); + const auto& commOrder = UPstream::whichCommunication(communicator); - Pstream::gatherList_algorithm(commOrder, values, tag, comm); - Pstream::scatterList_algorithm(commOrder, values, tag, comm); + Pstream::gatherList_algorithm(commOrder, values, tag, communicator); + Pstream::scatterList_algorithm(commOrder, values, tag, communicator); } } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index 2f6bdb85e49..b80eba3f343 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -1579,46 +1579,50 @@ public: // Low-level gather/scatter routines + //- Receive identically-sized (contiguous) data from all ranks + template<class Type> + static void mpiGather + ( + //! On rank: individual value to send (or nullptr for inplace) + const Type* sendData, + //! Master: receive buffer with all values + //! Or for in-place send/recv when sendData is nullptr + Type* recvData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const int communicator = UPstream::worldComm + ); + + //- Send identically-sized (contiguous) data to all ranks + template<class Type> + static void mpiScatter + ( + //! On master: send buffer with all values (nullptr for inplace) + const Type* sendData, + //! On rank: individual value to receive + //! Or for in-place send/recv when sendData is nullptr + Type* recvData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const int communicator = UPstream::worldComm + ); + + //- Gather/scatter identically-sized data + // Send data from proc slot, receive into all slots + template<class Type> + static void mpiAllGather + ( + //! On all ranks: the base of the data locations + Type* allData, + //! Number of send/recv data per rank. Globally consistent! + int count, + const int communicator = UPstream::worldComm + ); + + #undef Pstream_CommonRoutines #define Pstream_CommonRoutines(Type) \ \ - /*! \brief Receive identically-sized \c Type data from all ranks */ \ - static void mpiGather \ - ( \ - /*! On rank: individual value to send (or nullptr for inplace) */ \ - const Type* sendData, \ - /*! Master: receive buffer with all values */ \ - /*! Or for in-place send/recv when sendData is nullptr */ \ - Type* recvData, \ - /*! Number of send/recv data per rank. Globally consistent! */ \ - int count, \ - const label communicator = worldComm \ - ); \ - \ - /*! \brief Send identically-sized \c Type data to all ranks */ \ - static void mpiScatter \ - ( \ - /*! Master: send buffer with all values (nullptr for inplace) */ \ - const Type* sendData, \ - /*! On rank: individual value to receive */ \ - /*! Or for in-place send/recv when sendData is nullptr */ \ - Type* recvData, \ - /*! Number of send/recv data per rank. Globally consistent! */ \ - int count, \ - const label communicator = worldComm \ - ); \ - \ - /*! \brief Gather/scatter identically-sized \c Type data */ \ - /*! Send data from proc slot, receive into all slots */ \ - static void mpiAllGather \ - ( \ - /*! On all ranks: the base of the data locations */ \ - Type* allData, \ - /*! Number of send/recv data per rank. Globally consistent! */ \ - int count, \ - const label communicator = worldComm \ - ); \ - \ /*! \brief Receive variable length \c Type data from all ranks */ \ static void mpiGatherv \ ( \ diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx index 9aa479d8175..58aae735e90 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx @@ -65,39 +65,159 @@ bool Foam::UPstream::broadcast } -template<class T> -Foam::List<T> Foam::UPstream::allGatherValues +template<class Type> +void Foam::UPstream::mpiGather ( - const T& localValue, - const int comm + const Type* sendData, + Type* recvData, + int count, + const int communicator ) { - if constexpr (!is_contiguous_v<T>) + if (!count || !UPstream::is_rank(communicator)) + { + // Nothing to do + return; + } + else if constexpr (!is_contiguous_v<Type>) { FatalErrorInFunction - << "Cannot all-gather values for non-contiguous types" - " - consider Pstream variant instead" << endl + << "Invalid for non-contiguous data types" << Foam::abort(FatalError); } + else if (!UPstream::is_parallel(communicator)) + { + // Perform any fallback copying here, while we still know the Type + if (sendData && recvData && (sendData != recvData)) + { + std::memmove(recvData, sendData, count*sizeof(Type)); + } + } + else + { + // Use element or component type (or byte-wise) for data type + UPstream::mpi_gather + ( + sendData, // The data or cmpt pointer + recvData, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + communicator + ); + } +} - List<T> allValues; - if (UPstream::is_parallel(comm)) +template<class Type> +void Foam::UPstream::mpiScatter +( + const Type* sendData, + Type* recvData, + int count, + const int communicator +) +{ + if (!count || !UPstream::is_rank(communicator)) { - allValues.resize(UPstream::nProcs(comm)); - allValues[UPstream::myProcNo(comm)] = localValue; + // Nothing to do + return; + } + else if constexpr (!is_contiguous_v<Type>) + { + FatalErrorInFunction + << "Invalid for non-contiguous data types" + << Foam::abort(FatalError); + } + else if (!UPstream::is_parallel(communicator)) + { + // Perform any fallback copying here, while we still know the Type + if (sendData && recvData && (sendData != recvData)) + { + std::memmove(recvData, sendData, count*sizeof(Type)); + } + } + else + { + // Use element or component type (or byte-wise) for data type + UPstream::mpi_scatter + ( + sendData, // The data or cmpt pointer + recvData, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + communicator + ); + } +} - UPstream::mpiAllGather(allValues.data_bytes(), sizeof(T), comm); + +template<class Type> +void Foam::UPstream::mpiAllGather +( + Type* allData, + int count, + const int communicator +) +{ + if (!count || !UPstream::is_parallel(communicator)) + { + // Nothing sensible to do + return; + } + else if constexpr (!is_contiguous_v<Type>) + { + FatalErrorInFunction + << "Invalid for non-contiguous data types" + << Foam::abort(FatalError); } else + { + // Use element or component type (or byte-wise) for data type + UPstream::mpi_allgather + ( + allData, // The data or cmpt pointer + UPstream_dataType<Type>::size(count), + UPstream_dataType<Type>::datatype_id, + communicator + ); + } +} + + +template<class T> +Foam::List<T> Foam::UPstream::allGatherValues +( + const T& localValue, + const int communicator +) +{ + if (!UPstream::is_parallel(communicator)) { // non-parallel: return own value // TBD: only when UPstream::is_rank(comm) as well? - allValues.resize(1); + List<T> allValues(1); allValues[0] = localValue; + return allValues; + } + else if constexpr (!is_contiguous_v<T>) + { + FatalErrorInFunction + << "Cannot all-gather values for non-contiguous types" + << " - consider Pstream variant instead" << endl + << Foam::abort(FatalError); + return List<T>(); } + else + { + // Standard gather with direct MPI communication + List<T> allValues; - return allValues; + allValues.resize(UPstream::nProcs(communicator)); + allValues[UPstream::myProcNo(communicator)] = localValue; + + UPstream::mpiAllGather(allValues.data(), 1, communicator); + return allValues; + } } @@ -107,43 +227,38 @@ template<class T> Foam::List<T> Foam::UPstream::listGatherValues ( const T& localValue, - const int comm + const int communicator ) { - if constexpr (!is_contiguous_v<T>) + if (!UPstream::is_parallel(communicator)) + { + // non-parallel: return own value + // TBD: only when UPstream::is_rank(communicator) as well? + List<T> allValues(1); + allValues[0] = localValue; + return allValues; + } + else if constexpr (!is_contiguous_v<T>) { FatalErrorInFunction << "Cannot gather values for non-contiguous types" " - consider Pstream variant instead" << endl << Foam::abort(FatalError); + return List<T>(); } - - List<T> allValues; - - if (UPstream::is_parallel(comm)) + else { - if (UPstream::master(comm)) + // Local sizes are identical, can use MPI_Gather + List<T> allValues; + + if (UPstream::master(communicator)) { - allValues.resize(UPstream::nProcs(comm)); + allValues.resize(UPstream::nProcs(communicator)); } - UPstream::mpiGather - ( - reinterpret_cast<const char*>(&localValue), - allValues.data_bytes(), - sizeof(T), // The send/recv size per rank - comm - ); + UPstream::mpiGather(&localValue, allValues.data(), 1, communicator); + return allValues; } - else - { - // non-parallel: return own value - // TBD: only when UPstream::is_rank(comm) as well? - allValues.resize(1); - allValues[0] = localValue; - } - - return allValues; } @@ -151,51 +266,55 @@ template<class T> T Foam::UPstream::listScatterValues ( const UList<T>& allValues, - const int comm + const int communicator ) { - if constexpr (!is_contiguous_v<T>) + if (!UPstream::is_parallel(communicator)) + { + // non-parallel: return own value + // TBD: only when UPstream::is_rank(communicator) as well? + + if (!allValues.empty()) + { + return allValues[0]; + } + + return T{}; // Fallback value + } + else if constexpr (!is_contiguous_v<T>) { FatalErrorInFunction - << "Cannot scatter values for non-contiguous types" + << "Cannot scatter non-contiguous values" " - consider Pstream variant instead" << endl << Foam::abort(FatalError); - } - - T localValue{}; - if (UPstream::is_parallel(comm)) + return T{}; // Fallback value + } + else { - const label numProc = UPstream::nProcs(comm); + // Local sizes are identical, can use MPI_Scatter - if (UPstream::master(comm) && allValues.size() < numProc) + const label nProcs = UPstream::nProcs(communicator); + + if + ( + FOAM_UNLIKELY + ( + UPstream::master(communicator) + && allValues.size() < nProcs + ) + ) { FatalErrorInFunction << "Attempting to send " << allValues.size() - << " values to " << numProc << " processors" << endl + << " values to " << nProcs << " processors" << endl << Foam::abort(FatalError); } - UPstream::mpiScatter - ( - allValues.cdata_bytes(), - reinterpret_cast<char*>(&localValue), - sizeof(T), // The send/recv size per rank - comm - ); + T localValue{}; + UPstream::mpiScatter(allValues.cdata(), &localValue, 1, communicator); + return localValue; } - else - { - // non-parallel: return first value - // TBD: only when UPstream::is_rank(comm) as well? - - if (!allValues.empty()) - { - return allValues[0]; - } - } - - return localValue; } diff --git a/src/OpenFOAM/global/profiling/profilingPstream.C b/src/OpenFOAM/global/profiling/profilingPstream.C index e7ad9050e0c..9189cd86ff4 100644 --- a/src/OpenFOAM/global/profiling/profilingPstream.C +++ b/src/OpenFOAM/global/profiling/profilingPstream.C @@ -228,9 +228,9 @@ void Foam::profilingPstream::report(const int reportLevel) UPstream::mpiGather ( - procValues.cdata_bytes(), // Send - allTimes.data_bytes(), // Recv - procValues.size_bytes(), // Num send/recv data per rank + procValues.cdata(), // Send + allTimes.data(), // Recv + procValues.size(), // Num send/recv data per rank UPstream::commWorld() ); } @@ -247,9 +247,9 @@ void Foam::profilingPstream::report(const int reportLevel) UPstream::mpiGather ( - procValues.cdata_bytes(), // Send - allCounts.data_bytes(), // Recv - procValues.size_bytes(), // Num send/recv data per rank + procValues.cdata(), // Send + allCounts.data(), // Recv + procValues.size(), // Num send/recv data per rank UPstream::commWorld() ); } diff --git a/src/Pstream/dummy/UPstreamGatherScatter.C b/src/Pstream/dummy/UPstreamGatherScatter.C index 346b3e1768c..e5f4fcbe842 100644 --- a/src/Pstream/dummy/UPstreamGatherScatter.C +++ b/src/Pstream/dummy/UPstreamGatherScatter.C @@ -67,6 +67,8 @@ void Foam::UPstream::mpi_allgather {} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + void Foam::UPstream::mpi_gatherv ( const void* sendData, @@ -101,45 +103,6 @@ void Foam::UPstream::mpi_scatterv #undef Pstream_CommonRoutines #define Pstream_CommonRoutines(Type) \ \ -void Foam::UPstream::mpiGather \ -( \ - const Type* sendData, \ - Type* recvData, \ - int count, \ - const label comm \ -) \ -{ \ - if (sendData && recvData) \ - { \ - std::memmove(recvData, sendData, count*sizeof(Type)); \ - } \ -} \ - \ - \ -void Foam::UPstream::mpiScatter \ -( \ - const Type* sendData, \ - Type* recvData, \ - int count, \ - const label comm \ -) \ -{ \ - if (sendData && recvData) \ - { \ - std::memmove(recvData, sendData, count*sizeof(Type)); \ - } \ -} \ - \ - \ -void Foam::UPstream::mpiAllGather \ -( \ - Type* allData, \ - int count, \ - const label comm \ -) \ -{} \ - \ - \ void Foam::UPstream::mpiGatherv \ ( \ const Type* sendData, \ diff --git a/src/Pstream/mpi/UPstreamGatherScatter.C b/src/Pstream/mpi/UPstreamGatherScatter.C index 39470d5488f..0a39fd71d6e 100644 --- a/src/Pstream/mpi/UPstreamGatherScatter.C +++ b/src/Pstream/mpi/UPstreamGatherScatter.C @@ -262,52 +262,6 @@ void Foam::UPstream::mpi_scatterv #undef Pstream_CommonRoutines #define Pstream_CommonRoutines(Native, TaggedType) \ \ -void Foam::UPstream::mpiGather \ -( \ - const Native* sendData, \ - Native* recvData, \ - int count, \ - const label comm \ -) \ -{ \ - PstreamDetail::gather \ - ( \ - sendData, recvData, count, \ - TaggedType, comm \ - ); \ -} \ - \ - \ -void Foam::UPstream::mpiScatter \ -( \ - const Native* sendData, \ - Native* recvData, \ - int count, \ - const label comm \ -) \ -{ \ - PstreamDetail::scatter \ - ( \ - sendData, recvData, count, \ - TaggedType, comm \ - ); \ -} \ - \ - \ -void Foam::UPstream::mpiAllGather \ -( \ - Native* allData, \ - int count, \ - const label comm \ -) \ -{ \ - PstreamDetail::allGather \ - ( \ - allData, count, \ - TaggedType, comm \ - ); \ -} \ - \ void Foam::UPstream::mpiGatherv \ ( \ const Native* sendData, \ -- GitLab From 5d9f8e9a9d69c2f42ec39adfac41f09aa62bf0cc Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Wed, 26 Feb 2025 17:39:23 +0100 Subject: [PATCH 13/15] ENH: remove gatherv/scatterv direct coding - includes intrinsic MPI types, but no component aggregates since we barely wish to use gatherv/scatterv (slow!) in the first place and it makes no sense to recalculate the list of counts for component aggregates which we will never use. --- src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H | 118 ++++++++---------- .../db/IOstreams/Pstreams/UPstream.txx | 101 +++++++++++++++ src/Pstream/dummy/UPstreamGatherScatter.C | 46 ------- src/Pstream/mpi/UPstreamGatherScatter.C | 55 -------- 4 files changed, 155 insertions(+), 165 deletions(-) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index b80eba3f343..8caf255853f 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -1619,71 +1619,29 @@ public: const int communicator = UPstream::worldComm ); + //- Receive variable length data from all ranks + template<class Type> + static void mpiGatherv + ( + const Type* sendData, + int sendCount, //!< Ignored on master if recvCount[0] == 0 + Type* recvData, //!< Ignored on non-root rank + const UList<int>& recvCounts, //!< Ignored on non-root rank + const UList<int>& recvOffsets, //!< Ignored on non-root rank + const int communicator = UPstream::worldComm + ); - #undef Pstream_CommonRoutines - #define Pstream_CommonRoutines(Type) \ - \ - /*! \brief Receive variable length \c Type data from all ranks */ \ - static void mpiGatherv \ - ( \ - const Type* sendData, \ - int sendCount, /*!< Ignored on master if recvCount[0] == 0 */ \ - Type* recvData, /*!< Ignored on non-root rank */ \ - const UList<int>& recvCounts, /*!< Ignored on non-root rank */ \ - const UList<int>& recvOffsets, /*!< Ignored on non-root rank */ \ - const label communicator = worldComm \ - ); \ - \ - /*! \brief Send variable length \c Type data to all ranks */ \ - static void mpiScatterv \ - ( \ - const Type* sendData, /*!< Ignored on non-root rank */ \ - const UList<int>& sendCounts, /*!< Ignored on non-root rank */ \ - const UList<int>& sendOffsets, /*!< Ignored on non-root rank */ \ - Type* recvData, \ - int recvCount, \ - const label communicator = worldComm \ - ); \ - \ - /*! \deprecated(2025-02) prefer mpiGatherv */ \ - FOAM_DEPRECATED_FOR(2025-02, "mpiGatherv()") \ - inline static void gather \ - ( \ - const Type* send, \ - int count, \ - Type* recv, \ - const UList<int>& counts, \ - const UList<int>& offsets, \ - const label comm = worldComm \ - ) \ - { \ - UPstream::mpiGatherv(send, count, recv, counts, offsets, comm); \ - } \ - \ - /*! \deprecated(2025-02) prefer mpiScatterv */ \ - FOAM_DEPRECATED_FOR(2025-02, "mpiScatterv()") \ - inline static void scatter \ - ( \ - const Type* send, \ - const UList<int>& counts, \ - const UList<int>& offsets, \ - Type* recv, \ - int count, \ - const label comm = worldComm \ - ) \ - { \ - UPstream::mpiScatterv(send, counts, offsets, recv, count, comm); \ - } - - Pstream_CommonRoutines(char); - Pstream_CommonRoutines(int32_t); - Pstream_CommonRoutines(int64_t); - Pstream_CommonRoutines(uint32_t); - Pstream_CommonRoutines(uint64_t); - Pstream_CommonRoutines(float); - Pstream_CommonRoutines(double); - - #undef Pstream_CommonRoutines + //- Send variable length data to all ranks + template<class Type> + static void mpiScatterv + ( + const Type* sendData, //!< Ignored on non-root rank + const UList<int>& sendCounts, //!< Ignored on non-root rank + const UList<int>& sendOffsets, //!< Ignored on non-root rank + Type* recvData, + int recvCount, + const int communicator = UPstream::worldComm + ); // Gather single, contiguous value(s) @@ -1832,6 +1790,38 @@ public: // Should normally be restricted to a particular starting request. FOAM_DEPRECATED_FOR(2023-01, "waitRequests(int) method") static void waitRequests() { waitRequests(0); } + + //- \deprecated(2025-02) prefer mpiGatherv + template<class Type> + FOAM_DEPRECATED_FOR(2025-02, "mpiGatherv()") + static void gather + ( + const Type* send, + int count, + Type* recv, + const UList<int>& counts, + const UList<int>& offsets, + const int comm = UPstream::worldComm + ) + { + UPstream::mpiGatherv(send, count, recv, counts, offsets, comm); + } + + //- \deprecated(2025-02) prefer mpiScatterv + template<class Type> + FOAM_DEPRECATED_FOR(2025-02, "mpiScatterv()") + static void scatter + ( + const Type* send, + const UList<int>& counts, + const UList<int>& offsets, + Type* recv, + int count, + const int comm = UPstream::worldComm + ) + { + UPstream::mpiScatterv(send, counts, offsets, recv, count, comm); + } }; diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx index 58aae735e90..1e529ac018e 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.txx @@ -318,6 +318,107 @@ T Foam::UPstream::listScatterValues } +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +template<class Type> +void Foam::UPstream::mpiGatherv +( + const Type* sendData, + int sendCount, + Type* recvData, + const UList<int>& recvCounts, + const UList<int>& recvOffsets, + const int communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + if constexpr (is_contiguous_v<Type>) + { + if (sendData && recvData) + { + // recvCounts[0] may be invalid - use sendCount instead + std::memmove(recvData, sendData, sendCount*sizeof(Type)); + } + } + // Nothing further to do + } + else if constexpr (UPstream_basic_dataType<Type>::value) + { + // Restrict to basic (or aliased) MPI types to avoid recalculating + // the list of counts/offsets. + + UPstream::mpi_gatherv + ( + sendData, + sendCount, + recvData, + recvCounts, + recvOffsets, + + UPstream_basic_dataType<Type>::datatype_id, + communicator + ); + } + else + { + static_assert + ( + stdFoam::dependent_false_v<Type>, "Only basic MPI data types" + ); + } +} + + +template<class Type> +void Foam::UPstream::mpiScatterv +( + const Type* sendData, + const UList<int>& sendCounts, + const UList<int>& sendOffsets, + Type* recvData, + int recvCount, + const int communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + if constexpr (is_contiguous_v<Type>) + { + if (sendData && recvData) + { + std::memmove(recvData, sendData, recvCount*sizeof(Type)); + } + } + // Nothing further to do + } + else if constexpr (UPstream_basic_dataType<Type>::value) + { + // Restrict to basic (or aliased) MPI types to avoid recalculating + // the list of counts/offsets. + + UPstream::mpi_scatterv + ( + sendData, + sendCounts, + sendOffsets, + recvData, + recvCount, + + UPstream_basic_dataType<Type>::datatype_id, + communicator + ); + } + else + { + static_assert + ( + stdFoam::dependent_false_v<Type>, "Only basic MPI data types" + ); + } +} + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template<class T> diff --git a/src/Pstream/dummy/UPstreamGatherScatter.C b/src/Pstream/dummy/UPstreamGatherScatter.C index e5f4fcbe842..4d4e3992ef5 100644 --- a/src/Pstream/dummy/UPstreamGatherScatter.C +++ b/src/Pstream/dummy/UPstreamGatherScatter.C @@ -98,50 +98,4 @@ void Foam::UPstream::mpi_scatterv {} -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#undef Pstream_CommonRoutines -#define Pstream_CommonRoutines(Type) \ - \ -void Foam::UPstream::mpiGatherv \ -( \ - const Type* sendData, \ - int sendCount, \ - \ - Type* recvData, \ - const UList<int>& recvCounts, \ - const UList<int>& recvOffsets, \ - const label comm \ -) \ -{ \ - /* recvCounts[0] may be invalid - use sendCount instead */ \ - std::memmove(recvData, sendData, sendCount*sizeof(Type)); \ -} \ - \ -void Foam::UPstream::mpiScatterv \ -( \ - const Type* sendData, \ - const UList<int>& sendCounts, \ - const UList<int>& sendOffsets, \ - \ - Type* recvData, \ - int recvCount, \ - const label comm \ -) \ -{ \ - std::memmove(recvData, sendData, recvCount*sizeof(Type)); \ -} - - -//TDB: Pstream_CommonRoutines(bool); -Pstream_CommonRoutines(char); -Pstream_CommonRoutines(int32_t); -Pstream_CommonRoutines(int64_t); -Pstream_CommonRoutines(uint32_t); -Pstream_CommonRoutines(uint64_t); -Pstream_CommonRoutines(float); -Pstream_CommonRoutines(double); - -#undef Pstream_CommonRoutines - // ************************************************************************* // diff --git a/src/Pstream/mpi/UPstreamGatherScatter.C b/src/Pstream/mpi/UPstreamGatherScatter.C index 0a39fd71d6e..561a1d41c98 100644 --- a/src/Pstream/mpi/UPstreamGatherScatter.C +++ b/src/Pstream/mpi/UPstreamGatherScatter.C @@ -257,59 +257,4 @@ void Foam::UPstream::mpi_scatterv } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#undef Pstream_CommonRoutines -#define Pstream_CommonRoutines(Native, TaggedType) \ - \ -void Foam::UPstream::mpiGatherv \ -( \ - const Native* sendData, \ - int sendCount, \ - \ - Native* recvData, \ - const UList<int>& recvCounts, \ - const UList<int>& recvOffsets, \ - const label comm \ -) \ -{ \ - PstreamDetail::gatherv \ - ( \ - sendData, sendCount, \ - recvData, recvCounts, recvOffsets, \ - TaggedType, comm \ - ); \ -} \ - \ -void Foam::UPstream::mpiScatterv \ -( \ - const Native* sendData, \ - const UList<int>& sendCounts, \ - const UList<int>& sendOffsets, \ - \ - Native* recvData, \ - int recvCount, \ - const label comm \ -) \ -{ \ - PstreamDetail::scatterv \ - ( \ - sendData, sendCounts, sendOffsets, \ - recvData, recvCount, \ - TaggedType, comm \ - ); \ -} - - -//TDB: Pstream_CommonRoutines(bool, MPI_C_BOOL); -Pstream_CommonRoutines(char, MPI_BYTE); -Pstream_CommonRoutines(int32_t, MPI_INT32_T); -Pstream_CommonRoutines(int64_t, MPI_INT64_T); -Pstream_CommonRoutines(uint32_t, MPI_UINT32_T); -Pstream_CommonRoutines(uint64_t, MPI_UINT64_T); -Pstream_CommonRoutines(float, MPI_FLOAT); -Pstream_CommonRoutines(double, MPI_DOUBLE); - -#undef Pstream_CommonRoutines - // ************************************************************************* // -- GitLab From 20b2f4631525e4935430046bf88812418e7a7876 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Tue, 25 Feb 2025 19:26:40 +0100 Subject: [PATCH 14/15] STYLE: prefer listReduce() to using listCombineReduce() when possible - potentially allows access into the builtin MPI operations --- .../extrudeToRegionMesh/extrudeToRegionMesh.C | 4 ++-- .../splitMeshRegions/splitMeshRegions.C | 2 +- .../lagrangian/particleTracks/particleTracks.C | 2 +- .../postChannel/channelIndexTemplates.C | 2 +- .../raySearchEngine/raySearchEngine.C | 9 ++++++--- .../utilities/preProcessing/setFields/setFields.C | 2 +- .../pointSmoothing/hexMeshSmootherMotionSolver.C | 2 +- .../polyTopoChange/hexRef8/hexRef8.C | 4 ++-- .../fvMesh/fvMeshSubset/fvMeshSubset.C | 2 +- src/functionObjects/field/Curle/Curle.C | 2 +- .../field/columnAverage/columnAverageTemplates.C | 6 +++--- .../extractEulerianParticles.C | 4 ++-- .../histogramModels/equalBinWidth/equalBinWidth.C | 4 ++-- .../unequalBinWidth/unequalBinWidth.C | 4 ++-- .../forces/propellerInfo/propellerInfo.C | 2 +- .../ParticleZoneInfo/ParticleZoneInfo.C | 2 +- .../CellZoneInjection/CellZoneInjection.C | 4 ++-- .../LocalInteraction/LocalInteraction.C | 10 +++++----- .../RecycleInteraction/RecycleInteraction.C | 8 ++++---- .../StandardWallInteraction.C | 8 ++++---- .../movement/lumpedPointMovement.C | 8 ++++---- .../snappyHexMesh/meshRefinement/meshRefinement.C | 4 ++-- .../meshRefinement/meshRefinementBaffles.C | 8 ++++---- .../snappyHexMeshDriver/snappyRefineDriver.C | 8 ++++---- .../planeToFaceZone/planeToFaceZone.C | 8 ++++---- .../adjoint/optimisation/updateMethod/MMA/MMA.C | 2 +- .../NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C | 4 ++-- .../cellVolumeWeightCellCellStencil.C | 6 +++--- .../inverseDistanceCellCellStencil.C | 6 +++--- .../trackingInverseDistanceCellCellStencil.C | 4 ++-- src/overset/regionsToCell/findRefCells.C | 4 ++-- .../multiLevelDecomp/multiLevelDecomp.C | 10 +++------- .../singleLayerRegion/singleLayerRegion.C | 4 ++-- src/sampling/sampledSet/cloud/cloudSet.C | 6 +++--- .../distanceSurface/distanceSurfaceFilter.C | 14 +++++++------- src/sampling/surface/isoSurface/isoSurfacePoint.C | 4 ++-- .../solarLoad/faceReflecting/faceReflecting.C | 4 ++-- .../radiationModels/viewFactor/viewFactor.C | 8 ++++---- 38 files changed, 97 insertions(+), 98 deletions(-) diff --git a/applications/utilities/mesh/generation/extrude/extrudeToRegionMesh/extrudeToRegionMesh.C b/applications/utilities/mesh/generation/extrude/extrudeToRegionMesh/extrudeToRegionMesh.C index cf15e2f1a51..d1fb66a6056 100644 --- a/applications/utilities/mesh/generation/extrude/extrudeToRegionMesh/extrudeToRegionMesh.C +++ b/applications/utilities/mesh/generation/extrude/extrudeToRegionMesh/extrudeToRegionMesh.C @@ -661,8 +661,8 @@ void countExtrudePatches } // Synchronise decision. Actual numbers are not important, just make // sure that they're > 0 on all processors. - Pstream::listCombineReduce(zoneSidePatch, plusEqOp<label>()); - Pstream::listCombineReduce(zoneZonePatch, plusEqOp<label>()); + Pstream::listReduce(zoneSidePatch, sumOp<label>()); + Pstream::listReduce(zoneZonePatch, sumOp<label>()); } diff --git a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C index 64c0b0ef341..ae9d91f0b19 100644 --- a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C +++ b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C @@ -1081,7 +1081,7 @@ label findCorrespondingRegion } } - Pstream::listCombineReduce(cellsInZone, plusEqOp<label>()); + Pstream::listReduce(cellsInZone, sumOp<label>()); // Pick region with largest overlap of zoneI label regionI = findMax(cellsInZone); diff --git a/applications/utilities/postProcessing/lagrangian/particleTracks/particleTracks.C b/applications/utilities/postProcessing/lagrangian/particleTracks/particleTracks.C index 754109e162e..2202574ad88 100644 --- a/applications/utilities/postProcessing/lagrangian/particleTracks/particleTracks.C +++ b/applications/utilities/postProcessing/lagrangian/particleTracks/particleTracks.C @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) const label maxNProcs = returnReduce(maxIds.size(), maxOp<label>()); maxIds.resize(maxNProcs, -1); - Pstream::listCombineReduce(maxIds, maxEqOp<label>()); + Pstream::listReduce(maxIds, maxOp<label>()); // From ids to count const labelList numIds = maxIds + 1; diff --git a/applications/utilities/postProcessing/miscellaneous/postChannel/channelIndexTemplates.C b/applications/utilities/postProcessing/miscellaneous/postChannel/channelIndexTemplates.C index e0ca2042b62..5668bcc3cb9 100644 --- a/applications/utilities/postProcessing/miscellaneous/postChannel/channelIndexTemplates.C +++ b/applications/utilities/postProcessing/miscellaneous/postChannel/channelIndexTemplates.C @@ -40,7 +40,7 @@ Foam::Field<T> Foam::channelIndex::regionSum(const Field<T>& cellField) const } // Global sum - Pstream::listCombineReduce(regionField, plusEqOp<T>()); + Pstream::listReduce(regionField, sumOp<T>()); return regionField; } diff --git a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C index f1a37bbc5f3..4f2699517d7 100644 --- a/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C +++ b/applications/utilities/preProcessing/createViewFactors/viewFactorModels/raySearchEngine/raySearchEngine/raySearchEngine.C @@ -229,7 +229,7 @@ void Foam::VF::raySearchEngine::createAgglomeration(const IOobject& io) Pstream::allGatherList(allSf_); Pstream::allGatherList(allAgg_); - Pstream::listCombineGather(patchAreas_, plusEqOp<scalar>()); + Pstream::listGather(patchAreas_, sumOp<scalar>()); Pstream::broadcast(patchAreas_); globalNumbering_ = globalIndex(nCoarseFace_); @@ -262,8 +262,11 @@ void Foam::VF::raySearchEngine::createGeometry() Pstream::allGatherList(allCf_); Pstream::allGatherList(allSf_); - Pstream::listCombineGather(patchAreas_, plusEqOp<scalar>()); - Pstream::broadcast(patchAreas_); + // Pstream::listCombineGather(patchAreas_, plusEqOp<scalar>()); + // Pstream::broadcast(patchAreas_); + + // Basic type and op_sum, so can use listReduce (ie, mpiAllReduce) + Pstream::listReduce(patchAreas_, sumOp<scalar>()); globalNumbering_ = globalIndex(nFace_); } diff --git a/applications/utilities/preProcessing/setFields/setFields.C b/applications/utilities/preProcessing/setFields/setFields.C index 276b36c2f3d..44778b680ae 100644 --- a/applications/utilities/preProcessing/setFields/setFields.C +++ b/applications/utilities/preProcessing/setFields/setFields.C @@ -407,7 +407,7 @@ bool setFaceFieldType } } - Pstream::listCombineReduce(nChanged, plusEqOp<label>()); + Pstream::listReduce(nChanged, sumOp<label>()); auto& fieldBf = field.boundaryFieldRef(); diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C index d8964afef6d..2b28c6e06d2 100644 --- a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C @@ -464,7 +464,7 @@ Foam::labelList Foam::hexMeshSmootherMotionSolver::countZeroOrPos } } - Pstream::listCombineReduce(n, plusEqOp<label>()); + Pstream::listReduce(n, sumOp<label>()); return n; } diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C b/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C index 73501db8cf9..380bc508032 100644 --- a/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C +++ b/src/dynamicMesh/polyTopoChange/polyTopoChange/hexRef8/hexRef8.C @@ -440,7 +440,7 @@ Foam::scalar Foam::hexRef8::getLevel0EdgeLength() const // Get the minimum per level over all processors. Note minimum so if // cells are not cubic we use the smallest edge side. - Pstream::listCombineReduce(typEdgeLenSqr, minEqOp<scalar>()); + Pstream::listReduce(typEdgeLenSqr, minOp<scalar>()); if (debug) { @@ -474,7 +474,7 @@ Foam::scalar Foam::hexRef8::getLevel0EdgeLength() const } } - Pstream::listCombineReduce(maxEdgeLenSqr, maxEqOp<scalar>()); + Pstream::listReduce(maxEdgeLenSqr, maxOp<scalar>()); if (debug) { diff --git a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C index 839d102a171..2c5e8ec4197 100644 --- a/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C +++ b/src/finiteVolume/fvMesh/fvMeshSubset/fvMeshSubset.C @@ -1108,7 +1108,7 @@ void Foam::fvMeshSubset::reset // Get patch sizes (up to nextPatchID). // Note that up to nextPatchID the globalPatchMap is an identity so // no need to index through that. - Pstream::listCombineReduce(globalPatchSizes, plusEqOp<label>()); + Pstream::listReduce(globalPatchSizes, sumOp<label>()); // Now all processors have all the patchnames. // Decide: if all processors have the same patch names and size is zero diff --git a/src/functionObjects/field/Curle/Curle.C b/src/functionObjects/field/Curle/Curle.C index 6b53be07234..0ee78d92003 100644 --- a/src/functionObjects/field/Curle/Curle.C +++ b/src/functionObjects/field/Curle/Curle.C @@ -222,7 +222,7 @@ bool Foam::functionObjects::Curle::execute() pDash /= 4*mathematical::pi; - Pstream::listCombineReduce(pDash, plusEqOp<scalar>()); + Pstream::listReduce(pDash, sumOp<scalar>()); if (surfaceWriterPtr_) { diff --git a/src/functionObjects/field/columnAverage/columnAverageTemplates.C b/src/functionObjects/field/columnAverage/columnAverageTemplates.C index 2bba02a3dc3..aa7cc893e9b 100644 --- a/src/functionObjects/field/columnAverage/columnAverageTemplates.C +++ b/src/functionObjects/field/columnAverage/columnAverageTemplates.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2024 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -88,8 +88,8 @@ bool Foam::functionObjects::columnAverage::columnAverageField } // Global sum - Pstream::listCombineReduce(regionField, plusEqOp<Type>()); - Pstream::listCombineReduce(regionCount, plusEqOp<label>()); + Pstream::listReduce(regionField, sumOp<Type>()); + Pstream::listReduce(regionCount, sumOp<label>()); forAll(regionField, regioni) { diff --git a/src/functionObjects/field/extractEulerianParticles/extractEulerianParticles/extractEulerianParticles.C b/src/functionObjects/field/extractEulerianParticles/extractEulerianParticles/extractEulerianParticles.C index c8e2c76cb50..bba3209e639 100644 --- a/src/functionObjects/field/extractEulerianParticles/extractEulerianParticles/extractEulerianParticles.C +++ b/src/functionObjects/field/extractEulerianParticles/extractEulerianParticles/extractEulerianParticles.C @@ -329,7 +329,7 @@ void Foam::functionObjects::extractEulerianParticles::calculateAddressing // Create map from new regions to slots in particles list // - filter through new-to-new addressing to identify new particles - Pstream::listCombineReduce(newToNewRegion, maxEqOp<label>()); + Pstream::listReduce(newToNewRegion, maxOp<label>()); label nParticle = -1; labelHashSet newRegions; @@ -348,7 +348,7 @@ void Foam::functionObjects::extractEulerianParticles::calculateAddressing // Accumulate old region data or create a new particle if there is no // mapping from the old-to-new region - Pstream::listCombineReduce(oldToNewRegion, maxEqOp<label>()); + Pstream::listReduce(oldToNewRegion, maxOp<label>()); List<eulerianParticle> newParticles(newRegionToParticleMap.size()); forAll(oldToNewRegion, oldRegioni) diff --git a/src/functionObjects/field/histogram/histogramModels/equalBinWidth/equalBinWidth.C b/src/functionObjects/field/histogram/histogramModels/equalBinWidth/equalBinWidth.C index 790e6213c54..e8d40cb54e4 100644 --- a/src/functionObjects/field/histogram/histogramModels/equalBinWidth/equalBinWidth.C +++ b/src/functionObjects/field/histogram/histogramModels/equalBinWidth/equalBinWidth.C @@ -155,8 +155,8 @@ bool Foam::histogramModels::equalBinWidth::write(const bool log) dataCount[bini]++; } } - Pstream::listCombineGather(dataNormalised, plusEqOp<scalar>()); - Pstream::listCombineGather(dataCount, plusEqOp<label>()); + Pstream::listGather(dataNormalised, sumOp<scalar>()); + Pstream::listGather(dataCount, sumOp<label>()); // Write histogram data diff --git a/src/functionObjects/field/histogram/histogramModels/unequalBinWidth/unequalBinWidth.C b/src/functionObjects/field/histogram/histogramModels/unequalBinWidth/unequalBinWidth.C index 658c54bd135..aec3f84f0b1 100644 --- a/src/functionObjects/field/histogram/histogramModels/unequalBinWidth/unequalBinWidth.C +++ b/src/functionObjects/field/histogram/histogramModels/unequalBinWidth/unequalBinWidth.C @@ -129,8 +129,8 @@ bool Foam::histogramModels::unequalBinWidth::write(const bool log) } } } - Pstream::listCombineGather(dataNormalised, plusEqOp<scalar>()); - Pstream::listCombineGather(dataCount, plusEqOp<label>()); + Pstream::listGather(dataNormalised, sumOp<scalar>()); + Pstream::listGather(dataCount, sumOp<label>()); // Write histogram data diff --git a/src/functionObjects/forces/propellerInfo/propellerInfo.C b/src/functionObjects/forces/propellerInfo/propellerInfo.C index b080d929a36..18a47b728a0 100644 --- a/src/functionObjects/forces/propellerInfo/propellerInfo.C +++ b/src/functionObjects/forces/propellerInfo/propellerInfo.C @@ -791,7 +791,7 @@ Foam::tmp<Foam::Field<Type>> Foam::functionObjects::propellerInfo::interpolate } } - Pstream::listCombineReduce(field, maxEqOp<Type>()); + Pstream::listReduce(field, maxOp<Type>()); return tfield; } diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleZoneInfo/ParticleZoneInfo.C b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleZoneInfo/ParticleZoneInfo.C index 522e94c35bc..dcd6e8effec 100644 --- a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleZoneInfo/ParticleZoneInfo.C +++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleZoneInfo/ParticleZoneInfo.C @@ -365,7 +365,7 @@ void Foam::ParticleZoneInfo<CloudType>::write() { // Find number of particles per proc labelList allMaxIDs(maxIDs_); - Pstream::listCombineReduce(allMaxIDs, maxEqOp<label>()); + Pstream::listReduce(allMaxIDs, maxOp<label>()); // Combine into single list label n = returnReduce(data_.size(), sumOp<label>()); diff --git a/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/CellZoneInjection/CellZoneInjection.C b/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/CellZoneInjection/CellZoneInjection.C index 5ee1a9e6ff7..5e2ed632cc9 100644 --- a/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/CellZoneInjection/CellZoneInjection.C +++ b/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/CellZoneInjection/CellZoneInjection.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2023 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -121,7 +121,7 @@ void Foam::CellZoneInjection<CloudType>::setPositions globalPositions.range(myProci) ) = positions; - Pstream::listCombineReduce(allPositions, minEqOp<point>()); + Pstream::listReduce(allPositions, minOp<point>()); // Gather local cell tet and tet-point Ids, but leave non-local ids set -1 SubList<label> diff --git a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/LocalInteraction/LocalInteraction.C b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/LocalInteraction/LocalInteraction.C index 440103171a7..5a52be2cb19 100644 --- a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/LocalInteraction/LocalInteraction.C +++ b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/LocalInteraction/LocalInteraction.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2020 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -372,28 +372,28 @@ void Foam::LocalInteraction<CloudType>::info() labelListList npe(nEscape_); forAll(npe, i) { - Pstream::listCombineGather(npe[i], plusEqOp<label>()); + Pstream::listGather(npe[i], sumOp<label>()); npe[i] = npe[i] + npe0[i]; } scalarListList mpe(massEscape_); forAll(mpe, i) { - Pstream::listCombineGather(mpe[i], plusEqOp<scalar>()); + Pstream::listGather(mpe[i], sumOp<scalar>()); mpe[i] = mpe[i] + mpe0[i]; } labelListList nps(nStick_); forAll(nps, i) { - Pstream::listCombineGather(nps[i], plusEqOp<label>()); + Pstream::listGather(nps[i], sumOp<label>()); nps[i] = nps[i] + nps0[i]; } scalarListList mps(massStick_); forAll(nps, i) { - Pstream::listCombineGather(mps[i], plusEqOp<scalar>()); + Pstream::listGather(mps[i], sumOp<scalar>()); mps[i] = mps[i] + mps0[i]; } diff --git a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/RecycleInteraction/RecycleInteraction.C b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/RecycleInteraction/RecycleInteraction.C index 78501a00a22..e185e16034a 100644 --- a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/RecycleInteraction/RecycleInteraction.C +++ b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/RecycleInteraction/RecycleInteraction.C @@ -379,28 +379,28 @@ void Foam::RecycleInteraction<CloudType>::info() forAll(npr, i) { - Pstream::listCombineGather(npr[i], plusEqOp<label>()); + Pstream::listGather(npr[i], sumOp<label>()); npr[i] = npr[i] + npr0[i]; } scalarListList mpr(massRemoved_); forAll(mpr, i) { - Pstream::listCombineGather(mpr[i], plusEqOp<scalar>()); + Pstream::listGather(mpr[i], sumOp<scalar>()); mpr[i] = mpr[i] + mpr0[i]; } labelListList npi(nInjected_); forAll(npi, i) { - Pstream::listCombineGather(npi[i], plusEqOp<label>()); + Pstream::listGather(npi[i], sumOp<label>()); npi[i] = npi[i] + npi0[i]; } scalarListList mpi(massInjected_); forAll(mpi, i) { - Pstream::listCombineGather(mpi[i], plusEqOp<scalar>()); + Pstream::listGather(mpi[i], sumOp<scalar>()); mpi[i] = mpi[i] + mpi0[i]; } diff --git a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/StandardWallInteraction/StandardWallInteraction.C b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/StandardWallInteraction/StandardWallInteraction.C index 5f9f1033a7e..00ca30c613c 100644 --- a/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/StandardWallInteraction/StandardWallInteraction.C +++ b/src/lagrangian/intermediate/submodels/Kinematic/PatchInteractionModel/StandardWallInteraction/StandardWallInteraction.C @@ -285,28 +285,28 @@ void Foam::StandardWallInteraction<CloudType>::info() forAll(npe, i) { - Pstream::listCombineGather(npe[i], plusEqOp<label>()); + Pstream::listGather(npe[i], sumOp<label>()); npe[i] = npe[i] + npe0[i]; } scalarListList mpe(massEscape_); forAll(mpe, i) { - Pstream::listCombineGather(mpe[i], plusEqOp<scalar>()); + Pstream::listGather(mpe[i], sumOp<scalar>()); mpe[i] = mpe[i] + mpe0[i]; } labelListList nps(nStick_); forAll(nps, i) { - Pstream::listCombineGather(nps[i], plusEqOp<label>()); + Pstream::listGather(nps[i], sumOp<label>()); nps[i] = nps[i] + nps0[i]; } scalarListList mps(massStick_); forAll(nps, i) { - Pstream::listCombineGather(mps[i], plusEqOp<scalar>()); + Pstream::listGather(mps[i], sumOp<scalar>()); mps[i] = mps[i] + mps0[i]; } diff --git a/src/lumpedPointMotion/movement/lumpedPointMovement.C b/src/lumpedPointMotion/movement/lumpedPointMovement.C index 524e2be769f..f31f4dc907e 100644 --- a/src/lumpedPointMotion/movement/lumpedPointMovement.C +++ b/src/lumpedPointMotion/movement/lumpedPointMovement.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2016-2024 OpenCFD Ltd. + Copyright (C) 2016-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -878,7 +878,7 @@ Foam::List<Foam::scalar> Foam::lumpedPointMovement::areas } } - Pstream::listCombineReduce(zoneAreas, plusEqOp<scalar>()); + Pstream::listReduce(zoneAreas, sumOp<scalar>()); return zoneAreas; } @@ -1006,8 +1006,8 @@ bool Foam::lumpedPointMovement::forcesAndMoments Info<<"No pressure field" << endl; } - Pstream::listCombineReduce(forces, plusEqOp<vector>()); - Pstream::listCombineReduce(moments, plusEqOp<vector>()); + Pstream::listReduce(forces, sumOp<vector>()); + Pstream::listReduce(moments, sumOp<vector>()); return true; } diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C index ed4e8cc9679..5e3bafccad8 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinement.C @@ -2050,7 +2050,7 @@ Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance labelList nProcCells(distributor.countCells(distribution)); Pout<< "Wanted distribution:" << nProcCells << endl; - Pstream::listCombineReduce(nProcCells, plusEqOp<label>()); + Pstream::listReduce(nProcCells, sumOp<label>()); Pout<< "Wanted resulting decomposition:" << endl; forAll(nProcCells, proci) @@ -3611,7 +3611,7 @@ const nCells[cellLevel[celli]]++; } - Pstream::listCombineGather(nCells, plusEqOp<label>()); + Pstream::listGather(nCells, sumOp<label>()); /// Pstream::broadcast(nCells); if (Pstream::master()) diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C index 3afa51b1e37..2c92d2f0591 100644 --- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C +++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementBaffles.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2014 OpenFOAM Foundation - Copyright (C) 2015-2024 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -867,7 +867,7 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::createZoneBaffles if (nTotalBaffles > 0) { - Pstream::listCombineReduce(nBaffles, plusEqOp<label>()); + Pstream::listReduce(nBaffles, sumOp<label>()); Info<< nl << setf(ios_base::left) @@ -2001,7 +2001,7 @@ void Foam::meshRefinement::findCellZoneTopo // - region numbers are identical on all processors // - keepRegion is identical ,, // - cellZones are identical ,, - Pstream::listCombineReduce(regionToCellZone, maxEqOp<label>()); + Pstream::listReduce(regionToCellZone, maxOp<label>()); // Find the region containing the keepPoint @@ -2051,7 +2051,7 @@ void Foam::meshRefinement::findCellZoneTopo // - cellZones are identical ,, // This done at top of loop to account for geometric matching // not being synchronised. - Pstream::listCombineReduce(regionToCellZone, maxEqOp<label>()); + Pstream::listReduce(regionToCellZone, maxOp<label>()); bool changed = false; diff --git a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C index bdb55c6faf1..6381b3733c6 100644 --- a/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C +++ b/src/mesh/snappyHexMesh/snappyHexMeshDriver/snappyRefineDriver.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2015 OpenFOAM Foundation - Copyright (C) 2015-2024 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -3403,9 +3403,9 @@ void Foam::snappyRefineDriver::deleteSmallRegions nCellsPerRegion[regioni]++; nCellsPerZone[zonei]++; } - Pstream::listCombineReduce(nCellsPerRegion, plusEqOp<label>()); - Pstream::listCombineReduce(regionToZone, maxEqOp<label>()); - Pstream::listCombineReduce(nCellsPerZone, plusEqOp<label>()); + Pstream::listReduce(nCellsPerRegion, sumOp<label>()); + Pstream::listReduce(regionToZone, maxOp<label>()); + Pstream::listReduce(nCellsPerZone, sumOp<label>()); // Mark small regions. Note that all processors have the same information diff --git a/src/meshTools/topoSet/faceZoneSources/planeToFaceZone/planeToFaceZone.C b/src/meshTools/topoSet/faceZoneSources/planeToFaceZone/planeToFaceZone.C index 273cbfd8acc..e9132b3e5ae 100644 --- a/src/meshTools/topoSet/faceZoneSources/planeToFaceZone/planeToFaceZone.C +++ b/src/meshTools/topoSet/faceZoneSources/planeToFaceZone/planeToFaceZone.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2020 OpenFOAM Foundation - Copyright (C) 2020-2022 OpenCFD Ltd. + Copyright (C) 2020-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -258,7 +258,7 @@ void Foam::planeToFaceZone::combine(faceZoneSet& fzSet, const bool add) const { ++ regionNFaces[regioni]; } - Pstream::listCombineReduce(regionNFaces, plusEqOp<label>()); + Pstream::listReduce(regionNFaces, sumOp<label>()); Info<< " Found " << nRegions << " contiguous regions with " << regionNFaces << " faces" << endl; @@ -281,8 +281,8 @@ void Foam::planeToFaceZone::combine(faceZoneSet& fzSet, const bool add) const regionWeights[regioni] += w; regionCentres[regioni] += w*c; } - Pstream::listCombineGather(regionWeights, plusEqOp<scalar>()); - Pstream::listCombineGather(regionCentres, plusEqOp<point>()); + Pstream::listGather(regionWeights, sumOp<scalar>()); + Pstream::listGather(regionCentres, sumOp<point>()); if (Pstream::master()) { diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/MMA/MMA.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/MMA/MMA.C index 4c29943d2d3..2777f8d4257 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/MMA/MMA.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/MMA/MMA.C @@ -597,7 +597,7 @@ void Foam::MMA::computeNewtonDirection() if (globalSum_) { reduce(lhs, sumOp<scalarSquareMatrix>()); - Pstream::listCombineAllGather(rhs, plusEqOp<scalar>()); + Pstream::listReduce(rhs, sumOp<scalar>()); } // Add remaining parts from deltaLamdaYTilda and the deltaZ eqn diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C index e467948c4a6..052396e975a 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C @@ -1181,7 +1181,7 @@ Foam::vectorField Foam::NURBS3DVolume::computeControlPointSensitivities } // Sum contributions from all processors - Pstream::listCombineReduce(controlPointDerivs, plusEqOp<vector>()); + Pstream::listReduce(controlPointDerivs, sumOp<vector>()); return controlPointDerivs; } @@ -1266,7 +1266,7 @@ Foam::vectorField Foam::NURBS3DVolume::computeControlPointSensitivities } } // Sum contributions from all processors - Pstream::listCombineReduce(controlPointDerivs, plusEqOp<vector>()); + Pstream::listReduce(controlPointDerivs, sumOp<vector>()); return controlPointDerivs; } diff --git a/src/overset/cellCellStencil/cellVolumeWeight/cellVolumeWeightCellCellStencil.C b/src/overset/cellCellStencil/cellVolumeWeight/cellVolumeWeightCellCellStencil.C index fd04966eff9..602d31b0752 100644 --- a/src/overset/cellCellStencil/cellVolumeWeight/cellVolumeWeightCellCellStencil.C +++ b/src/overset/cellCellStencil/cellVolumeWeight/cellVolumeWeightCellCellStencil.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2014-2023 OpenCFD Ltd. + Copyright (C) 2014-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -227,7 +227,7 @@ void Foam::cellCellStencils::cellVolumeWeight::findHoles { // Synchronise region status on processors // (could instead swap status through processor patches) - Pstream::listCombineReduce(regionType, maxEqOp<label>()); + Pstream::listReduce(regionType, maxOp<label>()); // Communicate region status through interpolative cells labelList cellRegionType(labelUIndList(regionType, cellRegion)); @@ -602,7 +602,7 @@ bool Foam::cellCellStencils::cellVolumeWeight::update() { nCellsPerZone[zoneID[cellI]]++; } - Pstream::listCombineReduce(nCellsPerZone, plusEqOp<label>()); + Pstream::listReduce(nCellsPerZone, sumOp<label>()); Info<< typeName << " : detected " << nZones << " mesh regions" << nl << endl; diff --git a/src/overset/cellCellStencil/inverseDistance/inverseDistanceCellCellStencil.C b/src/overset/cellCellStencil/inverseDistance/inverseDistanceCellCellStencil.C index f606f5bdd44..c09703ec547 100644 --- a/src/overset/cellCellStencil/inverseDistance/inverseDistanceCellCellStencil.C +++ b/src/overset/cellCellStencil/inverseDistance/inverseDistanceCellCellStencil.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2023 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -1107,7 +1107,7 @@ void Foam::cellCellStencils::inverseDistance::findHoles { // Synchronise region status on processors // (could instead swap status through processor patches) - Pstream::listCombineReduce(regionType, maxEqOp<label>()); + Pstream::listReduce(regionType, maxOp<label>()); DebugInfo<< FUNCTION_NAME << " : Gathered region type" << endl; @@ -1801,7 +1801,7 @@ bool Foam::cellCellStencils::inverseDistance::update() { nCellsPerZone[zoneID[cellI]]++; } - Pstream::listCombineReduce(nCellsPerZone, plusEqOp<label>()); + Pstream::listReduce(nCellsPerZone, sumOp<label>()); const boundBox& allBb = mesh_.bounds(); diff --git a/src/overset/cellCellStencil/trackingInverseDistance/trackingInverseDistanceCellCellStencil.C b/src/overset/cellCellStencil/trackingInverseDistance/trackingInverseDistanceCellCellStencil.C index 73d421c58f5..07f3c254362 100644 --- a/src/overset/cellCellStencil/trackingInverseDistance/trackingInverseDistanceCellCellStencil.C +++ b/src/overset/cellCellStencil/trackingInverseDistance/trackingInverseDistanceCellCellStencil.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2017-2023 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -519,7 +519,7 @@ Foam::cellCellStencils::trackingInverseDistance::trackingInverseDistance { nCellsPerZone[zoneID[celli]]++; } - Pstream::listCombineReduce(nCellsPerZone, plusEqOp<label>()); + Pstream::listReduce(nCellsPerZone, sumOp<label>()); meshParts_.setSize(nZones); forAll(meshParts_, zonei) diff --git a/src/overset/regionsToCell/findRefCells.C b/src/overset/regionsToCell/findRefCells.C index 0704f355ba0..fc5f942847b 100644 --- a/src/overset/regionsToCell/findRefCells.C +++ b/src/overset/regionsToCell/findRefCells.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016,2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -188,7 +188,7 @@ void Foam::setRefCells } } - Pstream::listCombineReduce(hasRef, plusEqOp<label>()); + Pstream::listReduce(hasRef, sumOp<label>()); forAll(hasRef, regionI) { diff --git a/src/parallel/decompose/decompositionMethods/multiLevelDecomp/multiLevelDecomp.C b/src/parallel/decompose/decompositionMethods/multiLevelDecomp/multiLevelDecomp.C index b91df7c6d69..f1fa4f415cb 100644 --- a/src/parallel/decompose/decompositionMethods/multiLevelDecomp/multiLevelDecomp.C +++ b/src/parallel/decompose/decompositionMethods/multiLevelDecomp/multiLevelDecomp.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2017-2024 OpenCFD Ltd. + Copyright (C) 2017-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -420,8 +420,8 @@ void Foam::multiLevelDecomp::decompose ); label nPoints = returnReduce(domainPoints.size(), sumOp<label>()); + Pstream::listReduce(nOutsideConnections, sumOp<label>()); - Pstream::listCombineReduce(nOutsideConnections, plusEqOp<label>()); label nPatches = 0; label nFaces = 0; for (const label nConnect : nOutsideConnections) @@ -528,11 +528,7 @@ void Foam::multiLevelDecomp::decompose } reduce(nPoints, sumOp<label>()); - Pstream::listCombineReduce - ( - nOutsideConnections, - plusEqOp<label>() - ); + Pstream::listReduce(nOutsideConnections, sumOp<label>()); label nPatches = 0; label nFaces = 0; diff --git a/src/regionModels/regionModel/singleLayerRegion/singleLayerRegion.C b/src/regionModels/regionModel/singleLayerRegion/singleLayerRegion.C index 94f65984004..207d1c0a486 100644 --- a/src/regionModels/regionModel/singleLayerRegion/singleLayerRegion.C +++ b/src/regionModels/regionModel/singleLayerRegion/singleLayerRegion.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2020 OpenCFD Ltd. + Copyright (C) 2020-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -144,7 +144,7 @@ void Foam::regionModels::singleLayerRegion::initialise() } } - Pstream::listCombineReduce(passivePatchIDs_, maxEqOp<label>()); + Pstream::listReduce(passivePatchIDs_, maxOp<label>()); magSf.field() = 0.5*(magSf + passiveMagSf); magSf.correctBoundaryConditions(); diff --git a/src/sampling/sampledSet/cloud/cloudSet.C b/src/sampling/sampledSet/cloud/cloudSet.C index 42045d473ce..3447facc9b8 100644 --- a/src/sampling/sampledSet/cloud/cloudSet.C +++ b/src/sampling/sampledSet/cloud/cloudSet.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016 OpenCFD Ltd. + Copyright (C) 2016-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -84,8 +84,8 @@ void Foam::cloudSet::calcSamples minFoundProc[i] = foundProc[i]; } } - Pstream::listCombineReduce(minFoundProc, minEqOp<label>()); - Pstream::listCombineReduce(maxFoundProc, maxEqOp<label>()); + Pstream::listReduce(minFoundProc, minOp<label>()); + Pstream::listReduce(maxFoundProc, maxOp<label>()); DynamicField<point> missingPoints(sampleCoords_.size()); diff --git a/src/sampling/surface/distanceSurface/distanceSurfaceFilter.C b/src/sampling/surface/distanceSurface/distanceSurfaceFilter.C index 58d3892748a..739a802f4ee 100644 --- a/src/sampling/surface/distanceSurface/distanceSurfaceFilter.C +++ b/src/sampling/surface/distanceSurface/distanceSurfaceFilter.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2020-2022 OpenCFD Ltd. + Copyright (C) 2020-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -142,8 +142,8 @@ void Foam::distanceSurface::filterKeepLargestRegion } } - // Sum totals from all processors - Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>()); + // Sum totals from all processors (onto the master) + Pstream::listGather(nCutsPerRegion, sumOp<label>()); // Define which regions to keep @@ -242,8 +242,8 @@ void Foam::distanceSurface::filterKeepNearestRegions } } - // Sum totals from all processors - Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>()); + // Sum totals from all processors (onto the master) + Pstream::listGather(nCutsPerRegion, sumOp<label>()); // Get nearest Pstream::listCombineGather(nearest, minFirstEqOp<scalar>()); @@ -355,8 +355,8 @@ void Foam::distanceSurface::filterRegionProximity areaRegion[regioni] += (faceArea); } - Pstream::listCombineGather(distRegion, plusEqOp<scalar>()); - Pstream::listCombineGather(areaRegion, plusEqOp<scalar>()); + Pstream::listGather(distRegion, sumOp<scalar>()); + Pstream::listGather(areaRegion, sumOp<scalar>()); if (Pstream::master()) { diff --git a/src/sampling/surface/isoSurface/isoSurfacePoint.C b/src/sampling/surface/isoSurface/isoSurfacePoint.C index 020a0465a2b..b450c9b0f51 100644 --- a/src/sampling/surface/isoSurface/isoSurfacePoint.C +++ b/src/sampling/surface/isoSurface/isoSurfacePoint.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation - Copyright (C) 2015-2024 OpenCFD Ltd. + Copyright (C) 2015-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -256,7 +256,7 @@ void Foam::isoSurfacePoint::syncUnseparatedPoints } // Globally consistent - Pstream::listCombineReduce(sharedPts, minEqOp<point>()); + Pstream::listReduce(sharedPts, minOp<point>()); // Now we will all have the same information. Merge it back with // my local information. diff --git a/src/thermophysicalModels/radiation/radiationModels/solarLoad/faceReflecting/faceReflecting.C b/src/thermophysicalModels/radiation/radiationModels/solarLoad/faceReflecting/faceReflecting.C index 32fa503e548..53236148ec1 100644 --- a/src/thermophysicalModels/radiation/radiationModels/solarLoad/faceReflecting/faceReflecting.C +++ b/src/thermophysicalModels/radiation/radiationModels/solarLoad/faceReflecting/faceReflecting.C @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2022 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -327,7 +327,7 @@ void Foam::faceReflecting::calculate() // Distribute ray indexes to all proc's // Make sure all the processors have the same information - Pstream::listCombineReduce(refDisDirsIndex, maxEqOp<label>()); + Pstream::listReduce(refDisDirsIndex, maxOp<label>()); Pstream::mapCombineReduce(refFacesDirIndex, minEqOp<label>()); const scalar maxBounding = diff --git a/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C b/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C index d434b37a90f..79267e4c80c 100644 --- a/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C +++ b/src/thermophysicalModels/radiation/radiationModels/viewFactor/viewFactor.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2016-2022 OpenCFD Ltd. + Copyright (C) 2016-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -969,9 +969,9 @@ void Foam::radiation::viewFactor::calculate() qrExt[compactGlobalIds[i]] = compactCoarseHo[i]; } - Pstream::listCombineReduce(T4, maxEqOp<scalar>()); - Pstream::listCombineReduce(E, maxEqOp<scalar>()); - Pstream::listCombineReduce(qrExt, maxEqOp<scalar>()); + Pstream::listReduce(T4, maxOp<scalar>()); + Pstream::listReduce(E, maxOp<scalar>()); + Pstream::listReduce(qrExt, maxOp<scalar>()); if (Pstream::master()) { -- GitLab From 28818c73f926487a3d7d916b756eb7654d1f5e19 Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Thu, 6 Mar 2025 11:45:28 +0100 Subject: [PATCH 15/15] COMP: workaround for broken in-place reduce INTEL-MPI (#3331) - since that particular vendor version of MPI_Reduce() does not work with MPI_IN_PLACE, create a local copy of the data to pass into the routine. --- src/Pstream/mpi/UPstreamReduce.C | 39 +++++++++++++++++++++ src/Pstream/mpi/UPstreamWrapping.H | 3 +- src/Pstream/mpi/UPstreamWrapping.txx | 51 ++++++++++------------------ 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/Pstream/mpi/UPstreamReduce.C b/src/Pstream/mpi/UPstreamReduce.C index 991b72aac41..3ade1de388e 100644 --- a/src/Pstream/mpi/UPstreamReduce.C +++ b/src/Pstream/mpi/UPstreamReduce.C @@ -129,6 +129,15 @@ void printErrorMessage // * * * * * * * * * * Protected Static Member Functions * * * * * * * * * * // +// The intel-mpi version of MPI_Reduce() does not accept IN_PLACE +// operations (issue #3331) +// Assume the same may be true for ms-mpi +#if defined(I_MPI_VERSION) || defined(MSMPI_VER) +#define Foam_broken_vendor_INPLACE_REDUCE +#else +#undef Foam_broken_vendor_INPLACE_REDUCE +#endif + void Foam::UPstream::mpi_reduce ( void* values, // Type checking done by caller @@ -171,11 +180,41 @@ void Foam::UPstream::mpi_reduce << Foam::endl; } + // Workaround for broken in-place handling. + // Use a local buffer to send the data from. + + #ifdef Foam_broken_vendor_INPLACE_REDUCE + static std::unique_ptr<char[]> work; + static int work_len(0); + + const int num_bytes = [=](int n) + { + int size = 1; + MPI_Type_size(datatype, &size); + return (size * n); + }(count); + + if (work_len < num_bytes) + { + // Min length to avoid many initial re-allocations + work_len = std::max(256, num_bytes); + work.reset(); + work = std::make_unique<char[]>(work_len); + } + void* sendData = work.get(); + + std::memcpy(sendData, values, num_bytes); + #else + void* sendData(nullptr); + #endif + + { // Regular reduce PstreamDetail::reduce0 ( + sendData, values, count, datatype, diff --git a/src/Pstream/mpi/UPstreamWrapping.H b/src/Pstream/mpi/UPstreamWrapping.H index b98c99f314f..2587d840dc2 100644 --- a/src/Pstream/mpi/UPstreamWrapping.H +++ b/src/Pstream/mpi/UPstreamWrapping.H @@ -62,6 +62,7 @@ bool broadcast0 template<class Type> void reduce0 ( + const Type* sendData, // Use nullptr for in-place operation Type* values, int count, MPI_Datatype datatype, @@ -70,7 +71,7 @@ void reduce0 UPstream::Request* req = nullptr // Non-null for non-blocking ); -// MPI_Allreduce or MPI_Iallreduce +// MPI_Allreduce or MPI_Iallreduce : in-place operation template<class Type> void allReduce ( diff --git a/src/Pstream/mpi/UPstreamWrapping.txx b/src/Pstream/mpi/UPstreamWrapping.txx index ac9ce01792e..fdcc5d22183 100644 --- a/src/Pstream/mpi/UPstreamWrapping.txx +++ b/src/Pstream/mpi/UPstreamWrapping.txx @@ -74,6 +74,7 @@ bool Foam::PstreamDetail::broadcast0 template<class Type> void Foam::PstreamDetail::reduce0 ( + const Type* sendData, Type* values, int count, MPI_Datatype datatype, @@ -92,6 +93,13 @@ void Foam::PstreamDetail::reduce0 return; } + const void* send_buffer = sendData; + if (sendData == nullptr || (sendData == values)) + { + // Appears to be an in-place request + send_buffer = MPI_IN_PLACE; + } + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) @@ -102,22 +110,12 @@ void Foam::PstreamDetail::reduce0 { Perr<< "** MPI_Reduce (blocking):"; } - if constexpr (std::is_void_v<Type>) - { - Perr<< count << " values"; - } - else + if (sendData == nullptr || (sendData == values)) { - if (count == 1) - { - Perr<< (*values); - } - else - { - Perr<< UList<Type>(values, count); - } + Perr<< " [inplace]"; } - Perr<< " with comm:" << communicator + Perr<< " count:" << count + << " comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); } @@ -135,7 +133,7 @@ void Foam::PstreamDetail::reduce0 returnCode = MPI_Ireduce ( - MPI_IN_PLACE, // recv is also send + send_buffer, values, count, datatype, @@ -156,7 +154,7 @@ void Foam::PstreamDetail::reduce0 returnCode = MPI_Reduce ( - MPI_IN_PLACE, // recv is also send + send_buffer, values, count, datatype, @@ -174,24 +172,9 @@ void Foam::PstreamDetail::reduce0 FatalErrorInFunction<< "MPI Reduce "; if (immediate) FatalError<< "(non-blocking) "; - FatalError<< "failed for "; - - if constexpr (std::is_void_v<Type>) - { - FatalError<< count << " values"; - } - else - { - if (count == 1) - { - FatalError<< (*values); - } - else - { - FatalError<< UList<Type>(values, count); - } - } - FatalError<< Foam::abort(FatalError); + FatalError + << "failed for count:" << count + << Foam::abort(FatalError); } } -- GitLab