diff --git a/applications/test/minMax1/Make/files b/applications/test/minMax1/Make/files index 3b5fddb9fcf5eea27ab938e708a9cd79929fd3de..eb933b6ea46055ad86002e0bb33770d86535cbf9 100644 --- a/applications/test/minMax1/Make/files +++ b/applications/test/minMax1/Make/files @@ -1,3 +1,3 @@ -Test-minMax1.C +Test-minMax1.cxx EXE = $(FOAM_USER_APPBIN)/Test-minMax1 diff --git a/applications/test/minMax1/Test-minMax1.C b/applications/test/minMax1/Test-minMax1.cxx similarity index 95% rename from applications/test/minMax1/Test-minMax1.C rename to applications/test/minMax1/Test-minMax1.cxx index 86ff65d720a9eb996c8b1eefd7fab8cd9b1df10f..d30b4ed18d7a6c893f3daa28a3aad5b0ce750d7e 100644 --- a/applications/test/minMax1/Test-minMax1.C +++ b/applications/test/minMax1/Test-minMax1.cxx @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -170,8 +170,19 @@ int main(int argc, char *argv[]) values1 *= (Pstream::myProcNo()+1); - Pout<<"min-max of " << flatOutput(values1) << " = " - << minMax(values1) << endl; + { + auto limits = minMax(values1); + + Pout<<"min-max of " << flatOutput(values1) << " = " + << limits << endl; + + // add in some more values + limits.add(-100, 10, 1000, 500, 800); + + limits.add(-120, 1200); + + Pout<<"with more values: " << limits << endl; + } // Construct from values MinMax<scalar> minmax1(values1); @@ -182,10 +193,7 @@ int main(int argc, char *argv[]) minmax1 += values1; Pout<<"range: " << minmax1 << endl; - - Info<< "Reduced: "<< returnReduce(minmax1, plusOp<scalarMinMax>()) << nl; - Info<< "Reduced: "<< returnReduce(minmax1, minMaxOp<scalar>()) << nl; // Info<< "gMinMax: "<< gMinMax(values1v) << nl; diff --git a/applications/test/minMax2/Make/files b/applications/test/minMax2/Make/files index 08cdfd97514bd555731dd9e5766c232048513a33..2aae0fe3099f814b5cb5364ea45446253e0e6dee 100644 --- a/applications/test/minMax2/Make/files +++ b/applications/test/minMax2/Make/files @@ -1,3 +1,3 @@ -Test-minMax2.C +Test-minMax2.cxx EXE = $(FOAM_USER_APPBIN)/Test-minMax2 diff --git a/applications/test/minMax2/Test-minMax2.C b/applications/test/minMax2/Test-minMax2.cxx similarity index 100% rename from applications/test/minMax2/Test-minMax2.C rename to applications/test/minMax2/Test-minMax2.cxx diff --git a/applications/test/parallel-comm2/Test-parallel-comm2.C b/applications/test/parallel-comm2/Test-parallel-comm2.C index b5f01bc5040092da6300440cf7d7f8498d2bff3f..8ed7684fc2d8e5c090fe228468c66282560d717f 100644 --- a/applications/test/parallel-comm2/Test-parallel-comm2.C +++ b/applications/test/parallel-comm2/Test-parallel-comm2.C @@ -85,7 +85,8 @@ int main(int argc, char *argv[]) if (UPstream::parRun() && optPrintTree) { - Info<< "comms: " << UPstream::whichCommunication() << endl; + Info<< "comms: " + << UPstream::whichCommunication(UPstream::worldComm) << nl; UPstream::printCommTree(UPstream::commWorld()); } diff --git a/applications/utilities/mesh/manipulation/checkMesh/checkTools.C b/applications/utilities/mesh/manipulation/checkMesh/checkTools.C index e13ef311335bb73138839d1c738b109f76beb8d0..8b6b0d3195db0367d053a012062de1a328355240 100644 --- a/applications/utilities/mesh/manipulation/checkMesh/checkTools.C +++ b/applications/utilities/mesh/manipulation/checkMesh/checkTools.C @@ -123,7 +123,7 @@ void Foam::printMeshStats(const polyMesh& mesh, const bool allTopology) { // Number of global patches and min-max range of total patches Info<< mesh.boundaryMesh().nNonProcessor() << ' ' - << returnReduce(labelMinMax(nPatches), minMaxOp<label>()) << nl; + << returnReduce(labelMinMax(nPatches), sumOp<labelMinMax>{}) << nl; } else { diff --git a/applications/utilities/preProcessing/PDR/pdrFields/PDRutilsOverlap.C b/applications/utilities/preProcessing/PDR/pdrFields/PDRutilsOverlap.C index e2874cdc9e4ad61182ca45b39e02daefb28d0ed4..1c27f536cfe2538b17e4f9ec83527679a6962581 100644 --- a/applications/utilities/preProcessing/PDR/pdrFields/PDRutilsOverlap.C +++ b/applications/utilities/preProcessing/PDR/pdrFields/PDRutilsOverlap.C @@ -124,8 +124,8 @@ void Foam::PDRutils::one_d_overlap } // Ensure search is within the (point) bounds - xmin = grid.clip(xmin); - xmax = grid.clip(xmax); + xmin = grid.clamp(xmin); + xmax = grid.clamp(xmax); // The begin/end of the obstacle *cmin = grid.findCell(xmin); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H index 0f7a17e3a3397808256cc427f76bcdf956da9810..0e26a4a3998035568ee44bcccf2001a3d87244b8 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/Pstream.H @@ -126,6 +126,19 @@ public: // Gather/scatter : single value + //- Implementation: gather (reduce) single element data onto + //- UPstream::masterNo() + template<class T, class BinaryOp, bool InplaceMode> + static void gather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + T& value, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) data, applying \c bop to combine \c value //- from different processors. The basis for Foam::reduce(). // A no-op for non-parallel. @@ -208,12 +221,25 @@ public: const label comm = UPstream::worldComm ) { - Pstream::listCombineReduce(value, cop, tag, comm); + Pstream::combineReduce(value, cop, tag, comm); } // Gather/combine variants working on entire List + //- Implementation: gather (reduce) list element data onto + //- UPstream::masterNo() + template<class T, class BinaryOp, bool InplaceMode> + static void listGather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + //! [in,out] + UList<T>& values, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) list elements, //- applying \c bop to each list element // @@ -240,27 +266,27 @@ public: const label comm = UPstream::worldComm ); - //- Gather (reduce) list elements, - //- applying \c bop to combine each list element. + //- Reduce list elements (list must be equal size on all ranks), + //- applying \c bop to each list element. // // \tparam InplaceMode indicates that the binary operator // modifies values in-place, not using assignment template<class T, class BinaryOp, bool InplaceMode=false> - static void listGatherReduce + static void listReduce ( //! [in,out] the result is consistent on all ranks - List<T>& values, + UList<T>& values, const BinaryOp& bop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm ); - //- Forwards to Pstream::listGatherReduce with an \em in-place \c cop + //- Forwards to Pstream::listReduce with an \em in-place \c cop template<class T, class CombineOp> static void listCombineReduce ( //! [in,out] the result is consistent on all ranks - List<T>& values, + UList<T>& values, const CombineOp& cop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm @@ -271,7 +297,7 @@ public: static void listCombineAllGather ( //! [in,out] the result is consistent on all ranks - List<T>& values, + UList<T>& values, const CombineOp& cop, const int tag = UPstream::msgType(), const label comm = UPstream::worldComm @@ -283,6 +309,18 @@ public: // Gather/combine variants working on Map/HashTable containers + //- Implementation: gather (reduce) Map/HashTable containers onto + //- UPstream::masterNo() + template<class Container, class BinaryOp, bool InplaceMode> + static void mapGather_algorithm + ( + const UPstream::commsStructList& comms, //!< Communication order + Container& values, + const BinaryOp& bop, + const int tag, + const int communicator + ); + //- Gather (reduce) Map/HashTable containers, //- applying \c bop to combine entries from different processors. // @@ -316,7 +354,7 @@ public: // // Wraps mapCombineGather/broadcast (may change in the future). template<class Container, class BinaryOp, bool InplaceMode=false> - static void mapGatherReduce + static void mapReduce ( //! [in,out] the result is consistent on all ranks Container& values, @@ -325,7 +363,7 @@ public: const label comm = UPstream::worldComm ); - //- Forwards to Pstream::mapGatherReduce with an \em in-place \c cop + //- Forwards to Pstream::mapReduce with an \em in-place \c cop template<class Container, class CombineOp> static void mapCombineReduce ( @@ -351,37 +389,33 @@ public: } -private: - - // Private implementations + // Gather/scatter keeping the individual processor data separate. + // The values is a List of size UPstream::nProcs() where + // values[UPstream::myProcNo()] is the data for the current processor. - //- Gather data, but keep individual values separate. + //- Implementation: gather data, keeping individual values separate. + //- Output is only valid (consistent) on UPstream::masterNo() template<class T> - static void gatherList_tree_algorithm + static void gatherList_algorithm ( + const UPstream::commsStructList& comms, //!< Communication order //! [in,out] UList<T>& values, const int tag, - const label communicator + const int communicator ); - //- Inverse of gatherList_tree_algorithm + //- Implementation: inverse of gatherList_algorithm template<class T> - static void scatterList_tree_algorithm + static void scatterList_algorithm ( + const UPstream::commsStructList& comms, //!< Communication order //! [in,out] UList<T>& values, const int tag, - const label communicator + const int communicator ); - -public: - - // Gather/scatter keeping the individual processor data separate. - // The values is a List of size UPstream::nProcs() where - // values[UPstream::myProcNo()] is the data for the current processor. - //- Gather data, but keep individual values separate. template<class T> static void gatherList diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx index 154aee8fb9865be7393aaec5cc04455f087f9f83..8aa66bb79511697ac7c33eb7c1422539e328782a 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGather.txx @@ -49,12 +49,13 @@ Note // Single value variants template<class T, class BinaryOp, bool InplaceMode> -void Foam::Pstream::gather +void Foam::Pstream::gather_algorithm ( + const UPstream::commsStructList& comms, // Communication order T& value, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -64,12 +65,12 @@ void Foam::Pstream::gather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); + // Receive from my downstairs neighbours for (const auto proci : below) { @@ -146,6 +147,37 @@ void Foam::Pstream::gather } +template<class T, class BinaryOp, bool InplaceMode> +void Foam::Pstream::gather +( + T& value, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::gather_algorithm<T, BinaryOp, InplaceMode> + ( + commOrder, + value, + bop, + tag, + communicator + ); + } +} + + template<class T, class CombineOp> void Foam::Pstream::combineGather ( @@ -183,12 +215,13 @@ void Foam::Pstream::combineReduce // List variants template<class T, class BinaryOp, bool InplaceMode> -void Foam::Pstream::listGather +void Foam::Pstream::listGather_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList<T>& values, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator) || values.empty()) @@ -198,10 +231,9 @@ void Foam::Pstream::listGather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); // Same length on all ranks @@ -295,17 +327,70 @@ void Foam::Pstream::listGather template<class T, class BinaryOp, bool InplaceMode> -void Foam::Pstream::listGatherReduce +void Foam::Pstream::listGather +( + UList<T>& values, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator) || values.empty()) + { + // Nothing to do + return; + } + else if (values.size() == 1) + { + // Single value - optimized version + Pstream::gather<T, BinaryOp, InplaceMode> + ( + values[0], + bop, + tag, + communicator + ); + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::listGather_algorithm<T, BinaryOp, InplaceMode> + ( + commOrder, + values, + bop, + tag, + communicator + ); + } +} + + +template<class T, class BinaryOp, bool InplaceMode> +void Foam::Pstream::listReduce ( - List<T>& values, + UList<T>& values, const BinaryOp& bop, const int tag, const label comm ) { - Pstream::listGather<T, BinaryOp, InplaceMode>(values, bop, tag, comm); - if (!values.empty()) + if (!UPstream::is_parallel(comm) || values.empty()) { + // Nothing to do + } + else if (values.size() == 1) + { + // Single value - optimized version + Pstream::gather<T, BinaryOp, InplaceMode>(values[0], bop, tag, comm); + Pstream::broadcast(values[0], comm); + } + else + { + // Multiple values + Pstream::listGather<T, BinaryOp, InplaceMode>(values, bop, tag, comm); Pstream::broadcast(values, comm); } } @@ -328,14 +413,14 @@ void Foam::Pstream::listCombineGather template<class T, class CombineOp> void Foam::Pstream::listCombineReduce ( - List<T>& values, + UList<T>& values, const CombineOp& cop, const int tag, const label comm ) { // In-place binary operation - Pstream::listGatherReduce<T, CombineOp, true>(values, cop, tag, comm); + Pstream::listReduce<T, CombineOp, true>(values, cop, tag, comm); } @@ -344,12 +429,13 @@ void Foam::Pstream::listCombineReduce // Map variants template<class Container, class BinaryOp, bool InplaceMode> -void Foam::Pstream::mapGather +void Foam::Pstream::mapGather_algorithm ( + const UPstream::commsStructList& comms, // Communication order Container& values, const BinaryOp& bop, const int tag, - const label communicator + const int communicator ) { if (!UPstream::is_parallel(communicator)) @@ -359,12 +445,12 @@ void Foam::Pstream::mapGather } else { - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? - const auto& myComm = comms[UPstream::myProcNo(communicator)]; + const label myProci = UPstream::myProcNo(communicator); + const auto& myComm = comms[myProci]; const auto& below = myComm.below(); + // Receive from my downstairs neighbours for (const auto proci : below) { @@ -430,7 +516,38 @@ void Foam::Pstream::mapGather template<class Container, class BinaryOp, bool InplaceMode> -void Foam::Pstream::mapGatherReduce +void Foam::Pstream::mapGather +( + Container& values, + const BinaryOp& bop, + const int tag, + const label communicator +) +{ + if (!UPstream::is_parallel(communicator)) + { + // Nothing to do + return; + } + else + { + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::mapGather_algorithm<Container, BinaryOp, InplaceMode> + ( + commOrder, + values, + bop, + tag, + communicator + ); + } +} + + +template<class Container, class BinaryOp, bool InplaceMode> +void Foam::Pstream::mapReduce ( Container& values, const BinaryOp& bop, @@ -473,7 +590,7 @@ void Foam::Pstream::mapCombineReduce ) { // In-place binary operation - Pstream::mapGatherReduce<Container, CombineOp, true> + Pstream::mapReduce<Container, CombineOp, true> ( values, cop, tag, comm ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx index 082e1688007df5ce70ef8a230cc806186abd4919..a77c13bda68ccfe9094c9f66a320e5d81595750a 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamGatherList.txx @@ -43,11 +43,12 @@ Description // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template<class T> -void Foam::Pstream::gatherList_tree_algorithm +void Foam::Pstream::gatherList_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList<T>& values, const int tag, - const label communicator + const int communicator ) { if (FOAM_UNLIKELY(!UPstream::is_parallel(communicator))) @@ -65,11 +66,8 @@ void Foam::Pstream::gatherList_tree_algorithm << Foam::abort(FatalError); } - const label myProci = UPstream::myProcNo(communicator); - - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? + const label myProci = UPstream::myProcNo(communicator); const auto& myComm = comms[myProci]; @@ -253,11 +251,12 @@ void Foam::Pstream::gatherList_tree_algorithm template<class T> -void Foam::Pstream::scatterList_tree_algorithm +void Foam::Pstream::scatterList_algorithm ( + const UPstream::commsStructList& comms, // Communication order UList<T>& values, const int tag, - const label communicator + const int communicator ) { if (FOAM_UNLIKELY(!UPstream::is_parallel(communicator))) @@ -279,11 +278,8 @@ void Foam::Pstream::scatterList_tree_algorithm << Foam::abort(FatalError); } - const label myProci = UPstream::myProcNo(communicator); - - // Communication order - const auto& comms = UPstream::whichCommunication(communicator); // if (comms.empty()) return; // extra safety? + const label myProci = UPstream::myProcNo(communicator); const auto& myComm = comms[myProci]; @@ -448,7 +444,10 @@ void Foam::Pstream::gatherList } else { - Pstream::gatherList_tree_algorithm(values, tag, communicator); + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::gatherList_algorithm(commOrder, values, tag, communicator); } } @@ -479,7 +478,10 @@ void Foam::Pstream::scatterList } else { - Pstream::scatterList_tree_algorithm(values, tag, communicator); + // Communication order + const auto& commOrder = UPstream::whichCommunication(communicator); + + Pstream::scatterList_algorithm(commOrder, values, tag, communicator); } } @@ -511,8 +513,11 @@ void Foam::Pstream::allGatherList } else { - Pstream::gatherList(values, tag, comm); - Pstream::scatterList(values, tag, comm); + // Communication order + const auto& commOrder = UPstream::whichCommunication(comm); + + Pstream::gatherList_algorithm(commOrder, values, tag, comm); + Pstream::scatterList_algorithm(commOrder, values, tag, comm); } } diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H index 8bd8b474cf824afac7b4a68a2a55d14a301baec7..93a1e4b8e4b1743028728482606f6aca55df2f0c 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/PstreamReduceOps.H @@ -100,21 +100,6 @@ void reduce NotImplemented; } -//- Non-blocking reduce inplace (cf. MPI Iallreduce) -//- single value. Sets request. -template<class T, class BinaryOp> -void reduce -( - T& Value, - const BinaryOp&, - const int tag, - const label comm, - label& request -) -{ - NotImplemented; -} - //- Non-blocking reduce inplace (cf. MPI Iallreduce) //- of multiple values (same size on all ranks!). Sets request. template<class T, class BinaryOp> @@ -131,22 +116,6 @@ void reduce NotImplemented; } -//- Non-blocking reduce inplace (cf. MPI Iallreduce) -//- of multiple values (same size on all ranks!). Sets request. -template<class T, class BinaryOp> -void reduce -( - T values[], - const int size, - const BinaryOp&, - const int tag, - const label comm, - label& request -) -{ - NotImplemented; -} - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -295,18 +264,6 @@ void reduce \ UPstream::Request& req /*!< [out] request information */ \ ); \ \ -/*! \brief Non-blocking reduce (sum) multiple Native values. Sets request */ \ -/*! \deprecated prefer version with UPstream::Request */ \ -void reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm, \ - label& requestID \ -); \ - \ /*! \brief Non-blocking reduce (sum) single Native value. Sets request */ \ void reduce \ ( \ @@ -315,17 +272,6 @@ void reduce \ const int tag, /*!< (ignored) */ \ const label comm, \ UPstream::Request& req /*!< [out] request information */ \ -); \ - \ -/*! \brief Non-blocking reduce (sum) single Native value. Sets request */ \ -/*! \deprecated prefer version with UPstream::Request */ \ -void reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, /*!< (ignored) */ \ - const label comm, \ - label& requestID \ ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C index cd2e1d3c84e4f1eeab4351cca128010a0a68d0f5..4ba0e1f4abb38b3cc00b858507629a7428eb36d9 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.C @@ -58,6 +58,58 @@ Foam::UPstream::commsTypeNames }); +// * * * * * * * * * * * * * Controls Information * * * * * * * * * * * * * // + +void Foam::UPstream::printNodeCommsControl(Ostream& os) +{ + if (UPstream::nodeCommsControl_ > 0) + { + if (UPstream::usingNodeComms(UPstream::worldComm)) + { + os << "on ["; + } + else + { + os << "off ["; + } + if (UPstream::nodeCommsMin_ > 2) + { + os << "min=" << UPstream::nodeCommsMin_ << ","; + } + os << "type="; + + // 1: split by hostname [default] + // 2: split by shared + // >=4: (debug/manual) split with given number per node + if (UPstream::nodeCommsControl_ >= 4) + { + os << UPstream::nodeCommsControl_; + } + else if (UPstream::nodeCommsControl_ == 2) + { + os << "shared"; + } + else + { + os << "host"; + } + os << "]"; + } + else + { + os << "disabled"; + } + os << " (" << UPstream::nProcs(UPstream::worldComm) << " ranks, " + << UPstream::numNodes() << " nodes)"; +} + + +void Foam::UPstream::printTopoControl(Ostream& os) +{ + os << "none"; +} + + // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::UPstream::setParRun(const label nProcs, const bool haveThreads) @@ -187,6 +239,10 @@ Foam::label Foam::UPstream::getAvailableCommIndex(const label parentIndex) treeCommunication_.emplace_back(index); } + // Set the communication pattern + linearCommunication_[index].linear(true); + treeCommunication_[index].linear(false); + return index; } @@ -617,32 +673,50 @@ Foam::label Foam::UPstream::procNo const Foam::UPstream::commsStructList& -Foam::UPstream::linearCommunication(const label communicator) +Foam::UPstream::linearCommunication(int communicator) { + // linear = true + if (linearCommunication_[communicator].empty()) { - linearCommunication_[communicator].init(communicator); + linearCommunication_[communicator].init(communicator, true); } + // Probably not needed + // else + // { + // linearCommunication_[communicator].linear(true); + // } return linearCommunication_[communicator]; } const Foam::UPstream::commsStructList& -Foam::UPstream::treeCommunication(const label communicator) +Foam::UPstream::treeCommunication(int communicator) { + // linear = false + if (treeCommunication_[communicator].empty()) { - treeCommunication_[communicator].init(communicator); + treeCommunication_[communicator].init(communicator, false); } + // Probably not needed + // else + // { + // treeCommunication_[communicator].linear(false); + // } return treeCommunication_[communicator]; } -void Foam::UPstream::printCommTree(int communicator) +void Foam::UPstream::printCommTree +( + int communicator, + bool linear +) { - const auto& comms = UPstream::whichCommunication(communicator); + const auto& comms = UPstream::whichCommunication(communicator, linear); if (UPstream::master(communicator)) { @@ -789,6 +863,17 @@ registerOptSwitch ); +int Foam::UPstream::topologyControl_ +( + Foam::debug::optimisationSwitch("topoControl", 0) +); +registerOptSwitch +( + "topoControl", + int, + Foam::UPstream::topologyControl_ +); + bool Foam::UPstream::floatTransfer ( Foam::debug::optimisationSwitch("floatTransfer", 0) diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H index a49db6dd8a1d845dfc9d368d648313e9eded3c93..e9ff4fc3710f635eac09cbde093e011ed05bda0f 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstream.H @@ -179,7 +179,14 @@ public: //- Reset to default constructed state void reset(); - //- Reset (automatic linear/tree selection), + //- Reset to linear (flat) communication + void reset_linear + ( + const int myProci, + const int numProcs + ); + + //- Reset to tree selection (linear when very small), //- possibly with communicator-specific adjustments void reset ( @@ -205,6 +212,9 @@ public: //- The communicator index int comm_; + //- Linear (flat) communication instead of tree communication + bool flat_; + //- The communication tree List<commsStruct> tree_; @@ -213,10 +223,18 @@ public: // Constructors //- Construct empty with invalid communicator - commsStructList() noexcept : comm_(-1) {} + commsStructList() noexcept + : + comm_(-1), + flat_(false) + {} //- Construct empty with given communicator - explicit commsStructList(int comm) noexcept : comm_(comm) {} + explicit commsStructList(int comm, bool flat=false) noexcept + : + comm_(comm), + flat_(flat) + {} // Static Functions @@ -233,6 +251,13 @@ public: //- The communicator internal index int comm() const noexcept { return comm_; } + //- Linear (flat) communication instead of tree communication + bool linear() const noexcept { return flat_; } + + //- Change communication type (linear vs tree communication). + //- Resets existing structure. + void linear(bool on); + //- Clear the list void clear() { return tree_.clear(); } @@ -245,9 +270,17 @@ public: //- Reset communicator index, fill tree with empty entries void init(int communicator); + //- Reset communicator index, fill tree with empty entries. + //- Specify flat vs tree communication. + void init(int communicator, bool flat); + //- Reset communicator index, clear tree entries void reset(int communicator); + //- Reset communicator index, clear tree entries. + //- Specify flat vs tree communication. + void reset(int communicator, bool flat); + //- Get existing or create (demand-driven) entry const UPstream::commsStruct& get(int proci) const; @@ -404,6 +437,15 @@ public: // >= 3 : when there are more than N nodes static int nodeCommsMin_; + //- Selection of topology-aware routines + static int topologyControl_; + + //- Test for selection of given topology-aware routine (bitmask) + static bool usingTopoControl(int routine = 0) noexcept + { + return static_cast<bool>(topologyControl_ & routine); + } + //- Should compact transfer be used in which floats replace doubles //- reducing the bandwidth requirement at the expense of some loss //- in accuracy @@ -481,7 +523,7 @@ public: static label nComms() noexcept { return parentComm_.size(); } //- Debugging: print the communication tree - static void printCommTree(const label communicator); + static void printCommTree(int communicator, bool linear = false); // Host Communicators @@ -757,6 +799,15 @@ public: ); + // Information + + //- Report the node-communication settings + static void printNodeCommsControl(Ostream& os); + + //- Report the topology routines settings + static void printTopoControl(Ostream& os); + + // Requests (non-blocking comms). // Pending requests are usually handled as an internal (global) list, // since this simplifies the overall tracking and provides a convenient @@ -771,8 +822,9 @@ public: // A no-op for out-of-range values. static void resetRequests(const label n); - //- Transfer the (wrapped) MPI request to the internal global list. - // A no-op for non-parallel. No special treatment for null requests. + //- Transfer the (wrapped) MPI request to the internal global list + //- and invalidate the parameter (ignores null requests) + // A no-op for non-parallel, static void addRequest(UPstream::Request& req); //- Non-blocking comms: cancel and free outstanding request. @@ -784,7 +836,7 @@ public: //- Non-blocking comms: cancel and free outstanding request. //- Corresponds to MPI_Cancel() + MPI_Request_free() - // A no-op if parRun() == false + // A no-op for non-parallel static void cancelRequest(UPstream::Request& req); //- Non-blocking comms: cancel and free outstanding requests. @@ -1081,38 +1133,34 @@ public: static const List<int>& interNode_offsets(); - //- Communication schedule for linear all-to-master (proc 0) - static const commsStructList& linearCommunication - ( - const label communicator = worldComm - ); + //- Linear communication schedule (special case) for given communicator + static const commsStructList& linearCommunication(int communicator); - //- Communication schedule for tree all-to-master (proc 0) - static const commsStructList& treeCommunication - ( - const label communicator = worldComm - ); + //- Tree communication schedule (standard case) for given communicator + 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 is_parallel() state and the optional \c linear parameter. static const commsStructList& whichCommunication ( - const label communicator = worldComm + const int communicator, + //! optionally select linear schedule only + bool linear = false ) { const label np ( parRun_ && is_rank(communicator) // cf. is_parallel() ? nProcs(communicator) - : 0 + : label(0) ); return ( np <= 1 ? commsStructList::null() - : (np <= 2 || np < UPstream::nProcsSimpleSum) + : (linear || np < UPstream::nProcsSimpleSum) ? linearCommunication(communicator) : treeCommunication(communicator) ); diff --git a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamCommsStruct.C b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamCommsStruct.C index e55eff05ed8b53bcfd0a4a3b219a617c31288c3a..ffd542c7d87fa605a91e2240b064259443c3eff7 100644 --- a/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamCommsStruct.C +++ b/src/OpenFOAM/db/IOstreams/Pstreams/UPstreamCommsStruct.C @@ -338,59 +338,61 @@ void Foam::UPstream::commsStruct::reset() } -void Foam::UPstream::commsStruct::reset +void Foam::UPstream::commsStruct::reset_linear ( const int myProci, - const int numProcs, - const int communicator + const int numProcs ) { reset(); // Linear (flat) communication pattern - if - ( - // Trivially small domains - (numProcs <= 2 || numProcs < UPstream::nProcsSimpleSum) - - // local-node: assume that the local communication is low-latency - || ( - UPstream::commLocalNode() == communicator - && UPstream::commLocalNode() > UPstream::commConstWorld() - ) - // inter-node: presumably relatively few nodes and/or - // higher latency with larger messages being sent - || ( - UPstream::commInterNode() == communicator - && UPstream::commInterNode() > UPstream::commConstWorld() - ) - ) + int above(-1); + List<int> below; + + if (myProci == 0) + { + below.resize(numProcs-1); + std::iota(below.begin(), below.end(), 1); + } + else { - // Linear communication pattern - int above(-1); - List<int> below; + above = 0; + } - if (myProci == 0) - { - below.resize(numProcs-1); - std::iota(below.begin(), below.end(), 1); - } - else - { - above = 0; - } + *this = UPstream::commsStruct(numProcs, myProci, above, below, below); +} - *this = UPstream::commsStruct(numProcs, myProci, above, below, below); + +void Foam::UPstream::commsStruct::reset +( + const int myProci, + const int numProcs, + const int communicator +) +{ + // Trivially small domains + if (numProcs <= 2) + { + reset_linear(myProci, numProcs); return; } + reset(); + int above(-1); DynamicList<int> below; DynamicList<int> allBelow; + if (UPstream::usingNodeComms(communicator)) + { + // Additional treatment... + } + + // Simple tree communication pattern - int above = simpleTree + above = simpleTree ( myProci, numProcs, @@ -420,6 +422,38 @@ Foam::UPstream::commsStructList::null() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +void Foam::UPstream::commsStructList::linear(bool on) +{ + if (flat_ != on) + { + // Current size + const auto len = tree_.size(); + + flat_ = on; + tree_.clear(); + if (len > 0) + { + tree_.resize(len); + } + } +} + + +void Foam::UPstream::commsStructList::reset(int communicator) +{ + comm_ = communicator; + tree_.clear(); +} + + +void Foam::UPstream::commsStructList::reset(int communicator, bool flat) +{ + comm_ = communicator; + tree_.clear(); + flat_ = flat; +} + + void Foam::UPstream::commsStructList::init(int communicator) { comm_ = communicator; @@ -431,10 +465,10 @@ void Foam::UPstream::commsStructList::init(int communicator) } -void Foam::UPstream::commsStructList::reset(int communicator) +void Foam::UPstream::commsStructList::init(int communicator, bool flat) { - comm_ = communicator; - tree_.clear(); + init(communicator); + flat_ = flat; } @@ -454,8 +488,17 @@ Foam::UPstream::commsStructList::get(int proci) const if (entry.nProcs() != numProcs) { // Create/update - const_cast<UPstream::commsStruct&>(entry) - .reset(proci, numProcs, comm_); + + if (flat_) + { + const_cast<UPstream::commsStruct&>(entry) + .reset_linear(proci, numProcs); + } + else + { + const_cast<UPstream::commsStruct&>(entry) + .reset(proci, numProcs, comm_); + } } return entry; diff --git a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.C b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.C index 621b49200fcfd8100357655aa22349ec77849441..362c5a355e6b6616afef5a7b5c050eeae184ed90 100644 --- a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.C +++ b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -275,24 +275,26 @@ cmptAv(const tmp<DimensionedField<Type, GeoMesh>>& tf1) template<class Type, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const DimensionedField<Type, GeoMesh>& f1 \ + const DimensionedField<Type, GeoMesh>& f1, \ + const label comm \ ) \ { \ return dimensioned<ReturnType> \ ( \ #Func "(" + f1.name() + ')', \ f1.dimensions(), \ - gFunc(f1.field()) \ + gFunc(f1.field(), comm) \ ); \ } \ \ template<class Type, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<DimensionedField<Type, GeoMesh>>& tf1 \ + const tmp<DimensionedField<Type, GeoMesh>>& tf1, \ + const label comm \ ) \ { \ - dimensioned<ReturnType> res = Func(tf1()); \ + dimensioned<ReturnType> res = Func(tf1(), comm); \ tf1.clear(); \ return res; \ } diff --git a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.H b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.H index e444690399fac3410dc621720d2eb134460e6c34..32ce17fcf04d5609f954ec0eedeaaca4e8c2438c 100644 --- a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.H +++ b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/DimensionedFieldFunctions.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -107,12 +107,14 @@ cmptAv(const tmp<DimensionedField<Type, GeoMesh>>& tf1); template<class Type, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const DimensionedField<Type, GeoMesh>& f1 \ + const DimensionedField<Type, GeoMesh>& f1, \ + const label comm = UPstream::worldComm \ ); \ template<class Type, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<DimensionedField<Type, GeoMesh>>& tf1 \ + const tmp<DimensionedField<Type, GeoMesh>>& tf1, \ + const label comm = UPstream::worldComm \ ); UNARY_REDUCTION_FUNCTION(Type, max, gMax) diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C index 2ec59ff2d74d319d99e8c85d94afd55cd79e48d0..f3037d7e1be31b60ee4715220221038a212c8051 100644 --- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.C +++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.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. @@ -1132,10 +1132,11 @@ Foam::word Foam::GeometricField<Type, PatchField, GeoMesh>::select template<class Type, template<class> class PatchField, class GeoMesh> void Foam::GeometricField<Type, PatchField, GeoMesh>::writeMinMax ( - Ostream& os + Ostream& os, + label comm ) const { - MinMax<Type> range = Foam::minMax(*this).value(); + MinMax<Type> range = Foam::minMax(*this, comm).value(); os << "min/max(" << this->name() << ") = " << range.min() << ", " << range.max() << endl; diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.H b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.H index 8cb500f580c66c083ae5201e21e4cb0f533f9a21..5ff69df5cab49a8c63d6823a0d030bf04ecf81a2 100644 --- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.H +++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricField.H @@ -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. @@ -906,8 +906,9 @@ public: //- otherwise the standard parameters by returning the field name word select(bool final) const; - //- Helper function to write the min and max to an Ostream - void writeMinMax(Ostream& os) const; + //- Helper function to write the min and max to an Ostream. + // Uses the specified communicator for reductions + void writeMinMax(Ostream& os, label comm = UPstream::worldComm) const; // Member Function *this Operators @@ -1037,6 +1038,7 @@ public: //- Clamp field values (in-place) to the specified range. // \deprecated(2023-01) prefer clamp_range() naming + FOAM_DEPRECATED_FOR(2023-01, "clamp_range() method") void clip(const dimensioned<MinMax<Type>>& range) { this->clamp_range(range); @@ -1044,6 +1046,7 @@ public: //- Clamp field values (in-place) to the specified range. // \deprecated(2023-01) prefer clamp_range() naming + FOAM_DEPRECATED_FOR(2023-01, "clamp_range() method") void clip(const dimensioned<Type>& lo, const dimensioned<Type>& hi) { this->clamp_range(lo.value(), hi.value()); @@ -1076,13 +1079,12 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #include "GeometricFieldI.H" +#include "GeometricFieldFunctions.H" #ifdef NoRepository #include "GeometricField.C" #endif -#include "GeometricFieldFunctions.H" - // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.C b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.C index 40ab6e76461d52de79295cd90207546a3569a65b..506942bb9157849e5681b6aaa1bea207f9643b6c 100644 --- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.C +++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2018-2023 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -429,7 +429,8 @@ cmptAv(const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1) template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const GeometricField<Type, PatchField, GeoMesh>& f1 \ + const GeometricField<Type, PatchField, GeoMesh>& f1, \ + const label comm \ ) \ { \ return dimensioned<ReturnType> \ @@ -443,7 +444,9 @@ dimensioned<ReturnType> Func \ Foam::Func(f1.primitiveField()), \ Foam::Func(f1.boundaryField()) \ ), \ - BinaryOp<ReturnType>() \ + BinaryOp<ReturnType>(), \ + UPstream::msgType(), \ + comm \ ) \ ); \ } \ @@ -451,52 +454,52 @@ dimensioned<ReturnType> Func \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1 \ + const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1, \ + const label comm \ ) \ { \ - dimensioned<ReturnType> res = Func(tf1()); \ + dimensioned<ReturnType> res = Func(tf1(), comm); \ tf1.clear(); \ return res; \ } + UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, maxOp) UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, minOp) -UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(MinMax<Type>, minMax, minMaxOp) -UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(scalarMinMax, minMaxMag, minMaxMagOp) +UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(MinMax<Type>, minMax, plusOp) +UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(scalarMinMax, minMaxMag, plusOp) #undef UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY -#define UNARY_REDUCTION_FUNCTION(ReturnType, Func, gFunc) \ +// Forward to DimensionedField directly (same name) +#define UNARY_REDUCTION_FUNCTION(ReturnType, Func) \ \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const GeometricField<Type, PatchField, GeoMesh>& f1 \ + const GeometricField<Type, PatchField, GeoMesh>& f1, \ + const label comm \ ) \ { \ - return dimensioned<ReturnType> \ - ( \ - #Func "(" + f1.name() + ')', \ - f1.dimensions(), \ - gFunc(f1.primitiveField()) \ - ); \ + return Func(f1.internalField(), comm); \ } \ \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1 \ + const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1, \ + const label comm \ ) \ { \ - dimensioned<ReturnType> res = Func(tf1()); \ + auto result = Func(tf1(), comm); \ tf1.clear(); \ - return res; \ + return result; \ } -UNARY_REDUCTION_FUNCTION(Type, sum, gSum) -UNARY_REDUCTION_FUNCTION(Type, average, gAverage) -UNARY_REDUCTION_FUNCTION(typename typeOfMag<Type>::type, sumMag, gSumMag) +UNARY_REDUCTION_FUNCTION(Type, sum) +UNARY_REDUCTION_FUNCTION(Type, average) +UNARY_REDUCTION_FUNCTION(typename typeOfMag<Type>::type, sumMag) #undef UNARY_REDUCTION_FUNCTION diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.H b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.H index 65863a90c0280f81e0ed8bfb7c80c35105a0122d..5aab42aae0e15aab843e0b3ee1f08128d541bf01 100644 --- a/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.H +++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/GeometricFieldFunctions.H @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation - Copyright (C) 2018-2023 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -225,40 +225,45 @@ cmptAv(const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1); template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const GeometricField<Type, PatchField, GeoMesh>& f1 \ + const GeometricField<Type, PatchField, GeoMesh>& f1, \ + const label comm = UPstream::worldComm \ ); \ \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1 \ + const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1, \ + const label comm = UPstream::worldComm \ ); UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, max, maxOp) UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(Type, min, minOp) -UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(MinMax<Type>, minMax, minMaxOp) -UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(scalarMinMax, minMaxMag, minMaxMagOp) +UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(MinMax<Type>, minMax, plusOp) +UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY(scalarMinMax, minMaxMag, plusOp) #undef UNARY_REDUCTION_FUNCTION_WITH_BOUNDARY -#define UNARY_REDUCTION_FUNCTION(ReturnType, Func, gFunc) \ +#define UNARY_REDUCTION_FUNCTION(ReturnType, Func) \ \ +/*! \brief Forwards to Func on internalField */ \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const GeometricField<Type, PatchField, GeoMesh>& f1 \ + const GeometricField<Type, PatchField, GeoMesh>& f1, \ + const label comm = UPstream::worldComm \ ); \ \ template<class Type, template<class> class PatchField, class GeoMesh> \ dimensioned<ReturnType> Func \ ( \ - const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1 \ + const tmp<GeometricField<Type, PatchField, GeoMesh>>& tf1, \ + const label comm = UPstream::worldComm \ ); -UNARY_REDUCTION_FUNCTION(Type, sum, gSum) -UNARY_REDUCTION_FUNCTION(Type, average, gAverage) -UNARY_REDUCTION_FUNCTION(typename typeOfMag<Type>::type, sumMag, gSumMag) +UNARY_REDUCTION_FUNCTION(Type, sum) +UNARY_REDUCTION_FUNCTION(Type, average) +UNARY_REDUCTION_FUNCTION(typename typeOfMag<Type>::type, sumMag) #undef UNARY_REDUCTION_FUNCTION diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C index 99bee6f6fd1a87665209d88886063a93b4377f2d..d04c26860aa200608448048a8fb655c5abac7266 100644 --- a/src/OpenFOAM/global/argList/argList.C +++ b/src/OpenFOAM/global/argList/argList.C @@ -2094,21 +2094,17 @@ void Foam::argList::parse } } - Info<< "Pstream initialized with:" << nl - << " node communication : "; - if (UPstream::nodeCommsControl_ > 0) + Info<< "Pstream initialized with:" << nl; { - Info<< Switch::name(UPstream::usingNodeComms()) - << " [min=" << UPstream::nodeCommsMin_ - << ", type=" << UPstream::nodeCommsControl_ - << "]"; + Info<< " node communication : "; + UPstream::printNodeCommsControl(Info); + Info<< nl; } - else { - Info<< "disabled"; + Info<< " topology controls : "; + UPstream::printTopoControl(Info); + Info<< nl; } - Info<< " (" << UPstream::nProcs() << " ranks, " - << UPstream::numNodes() << " nodes)" << nl; if (UPstream::floatTransfer) { @@ -2128,7 +2124,7 @@ void Foam::argList::parse const auto& commsType = UPstream::commsTypeNames[UPstream::defaultCommsType]; - Info<< " nonBlockingExchange: " + Info<< " consensus exchange : " << UPstream::nProcsNonblockingExchange << " (tuning: " << UPstream::tuning_NBX_ << ')' << nl << " exchange algorithm : " diff --git a/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H b/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H index 377cb6d3e6bb4b32722efd243d97867ef6b25d79..7d07427bd4bcbc8be8a743481a62a31e3e10d39a 100644 --- a/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H +++ b/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -110,9 +110,15 @@ typedef MinMax<scalar> scalarMinMax; //!< A scalar min/max range template<class T> class MinMax -: - public Tuple2<T,T> { + // Private Data + + //- Min value + T min_; + + //- Max value + T max_; + public: // Typedefs @@ -126,23 +132,26 @@ public: // Constructors - //- Construct inverted range + //- Default construct: an inverted range inline MinMax(); - //- Copy construct from components + //- Construct from min/max limits inline MinMax(const T& minVal, const T& maxVal); - //- Copy construct from components + //- Implicit construct from min/max limits inline MinMax(const std::pair<T,T>& range); - //- Copy construct from components + //- Implicit construct from min/max limits inline MinMax(const Pair<T>& range); + //- Implicit construct from min/max limits + inline MinMax(const Tuple2<T,T>& range); + //- Construct with a single zero value - inline explicit MinMax(const Foam::zero); + inline explicit MinMax(Foam::zero); //- Implicit construct from zero_one as 0-1 range (pTraits zero, one) - inline MinMax(const Foam::zero_one); + inline MinMax(Foam::zero_one); //- Construct with a single initial value inline explicit MinMax(const T& val); @@ -167,25 +176,25 @@ public: // Access - //- The min value (first) - inline const T& min() const noexcept; + //- The min value + const T& min() const noexcept { return min_; } - //- The min value (first) - inline T& min() noexcept; + //- The min value + T& min() noexcept { return min_; } - //- The max value (second) - inline const T& max() const noexcept; + //- The max value + const T& max() const noexcept { return max_; } - //- The max value (second) - inline T& max() noexcept; + //- The max value + T& max() noexcept { return max_; } //- The min/max average value inline T centre() const; - //- The min to max span. Zero if the range is invalid. + //- The min to max span. Zero for invalid range. inline T span() const; - //- The magnitude of the min to max span. Zero if the range is invalid. + //- The magnitude of the min to max span. Zero for invalid range. inline scalar mag() const; //- Range is empty if it is inverted @@ -194,9 +203,6 @@ public: //- Range is non-inverted inline bool good() const; - //- Range is non-inverted - bool valid() const { return good(); } - //- Reset to an inverted (invalid) range inline void reset(); @@ -244,6 +250,11 @@ public: //- Include the values into the range inline MinMax<T>& add(const UList<T>& vals); + //- Include two or more values into the range. + // All values must be similar types + template<class... Args> + inline MinMax<T>& add(const T& val0, const T& val1, Args&&... values); + // Member Operators @@ -264,23 +275,33 @@ public: inline MinMax<T>& operator+=(const UList<T>& vals); //- Multiply range by scalar factor - inline MinMax<T>& operator*=(const scalar& s); + inline MinMax<T>& operator*=(scalar s); //- Divide range by scalar factor - inline MinMax<T>& operator/=(const scalar& s); + inline MinMax<T>& operator/=(scalar s); // Housekeeping + //- Range is non-inverted. Same as good (2022-10) + bool valid() const { return good(); } + //- Old method name. Same as clamp (2023-01) T clip(const T& val) const { return this->clamp(val); } - - //- Old method (2023-01) - void inplaceClip(T& val) const { val = this->clamp(val); } }; -// Global Functions +// * * * * * * * * * * * * * * * * * Traits * * * * * * * * * * * * * * * * // + +//- Declare MinMax as non-contiguous (similar to Tuple2). +// Output remains separate (even in binary) and, since the defined +// \c operator+ is somewhat non-standard, also avoid false matching with +// any MPI intrinsic operation. +template<class T> +struct is_contiguous<MinMax<T>> : std::false_type {}; + + +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // //- Min/max range as a string template<class T> @@ -289,6 +310,30 @@ word name(const MinMax<T>& range) return '(' + Foam::name(range.min()) + ',' + Foam::name(range.max()) + ')'; } +// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // + +//- Read min/max range as (min max) tuple from Istream +template<class T> +inline Istream& operator>>(Istream& is, MinMax<T>& range) +{ + is.readBegin("min.max"); + is >> range.min() >> range.max(); + is.readEnd("min.max"); + + is.check(FUNCTION_NAME); + return is; +} + +//- Write min/max range as (min max) tuple to Ostream +template<class T> +inline Ostream& operator<<(Ostream& os, const MinMax<T>& range) +{ + os << token::BEGIN_LIST + << range.min() << token::SPACE << range.max() + << token::END_LIST; + return os; +} + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/primitives/ranges/MinMax/MinMaxI.H b/src/OpenFOAM/primitives/ranges/MinMax/MinMaxI.H index 444c6853204893e2e96b635cf8cb33d7ec317dc4..61b274a8e0e97dc90929c5291b553c2368e4ccba 100644 --- a/src/OpenFOAM/primitives/ranges/MinMax/MinMaxI.H +++ b/src/OpenFOAM/primitives/ranges/MinMax/MinMaxI.H @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2019-2023 OpenCFD Ltd. + Copyright (C) 2019-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -53,49 +53,65 @@ inline Foam::MinMax<T> Foam::MinMax<T>::zero_one() template<class T> inline Foam::MinMax<T>::MinMax() : - Tuple2<T,T>(pTraits<T>::max, pTraits<T>::min) + // An inverted range + min_(pTraits<T>::max), + max_(pTraits<T>::min) {} template<class T> inline Foam::MinMax<T>::MinMax(const T& minVal, const T& maxVal) : - Tuple2<T,T>(minVal, maxVal) + min_(minVal), + max_(maxVal) {} template<class T> inline Foam::MinMax<T>::MinMax(const std::pair<T,T>& range) : - Tuple2<T,T>(range.first, range.second) + min_(range.first), + max_(range.second) {} template<class T> inline Foam::MinMax<T>::MinMax(const Pair<T>& range) : - Tuple2<T,T>(range.first(), range.second()) + min_(range.first()), + max_(range.second()) {} template<class T> -inline Foam::MinMax<T>::MinMax(const Foam::zero) +inline Foam::MinMax<T>::MinMax(const Tuple2<T,T>& range) : - Tuple2<T,T>(pTraits<T>::zero, pTraits<T>::zero) + min_(range.first()), + max_(range.second()) {} template<class T> -inline Foam::MinMax<T>::MinMax(const Foam::zero_one) +inline Foam::MinMax<T>::MinMax(Foam::zero) : - Tuple2<T,T>(pTraits<T>::zero, pTraits<T>::one) + min_(pTraits<T>::zero), + max_(pTraits<T>::zero) +{} + + +template<class T> +inline Foam::MinMax<T>::MinMax(Foam::zero_one) +: + min_(pTraits<T>::zero), + max_(pTraits<T>::one) {} template<class T> inline Foam::MinMax<T>::MinMax(const T& val) : - Tuple2<T,T>(val, val) + min_(val), + max_(val) {} @@ -110,34 +126,6 @@ inline Foam::MinMax<T>::MinMax(const UList<T>& vals) // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template<class T> -inline const T& Foam::MinMax<T>::min() const noexcept -{ - return this->first(); -} - - -template<class T> -inline T& Foam::MinMax<T>::min() noexcept -{ - return this->first(); -} - - -template<class T> -inline const T& Foam::MinMax<T>::max() const noexcept -{ - return this->second(); -} - - -template<class T> -inline T& Foam::MinMax<T>::max() noexcept -{ - return this->second(); -} - - template<class T> inline T Foam::MinMax<T>::centre() const { @@ -156,7 +144,7 @@ inline T Foam::MinMax<T>::span() const template<class T> inline Foam::scalar Foam::MinMax<T>::mag() const { - return ::Foam::mag(span()); + return (empty() ? scalar(0) : ::Foam::mag(max() - min())); } @@ -171,31 +159,32 @@ inline bool Foam::MinMax<T>::empty() const template<class T> inline bool Foam::MinMax<T>::good() const { - return !empty(); + return !(max() < min()); } template<class T> inline void Foam::MinMax<T>::reset() { - min() = pTraits<T>::max; - max() = pTraits<T>::min; + // An inverted range + min_ = pTraits<T>::max; + max_ = pTraits<T>::min; } template<class T> inline void Foam::MinMax<T>::reset(const T& val) { - min() = val; - max() = val; + min_ = val; + max_ = val; } template<class T> inline void Foam::MinMax<T>::reset(const T& minVal, const T& maxVal) { - min() = minVal; - max() = maxVal; + min_ = minVal; + max_ = maxVal; } @@ -246,6 +235,7 @@ inline T Foam::MinMax<T>::clamp(const T& val) const { if (good()) { + // Uses Foam::min/Foam::max for component-wise handling return Foam::min(Foam::max(val, min()), max()); } @@ -256,6 +246,7 @@ inline T Foam::MinMax<T>::clamp(const T& val) const template<class T> inline Foam::MinMax<T>& Foam::MinMax<T>::add(const MinMax& other) { + // Uses Foam::min/Foam::max for component-wise handling min() = Foam::min(min(), other.min()); max() = Foam::max(max(), other.max()); return *this; @@ -265,6 +256,7 @@ inline Foam::MinMax<T>& Foam::MinMax<T>::add(const MinMax& other) template<class T> inline Foam::MinMax<T>& Foam::MinMax<T>::add(const T& val) { + // Uses Foam::min/Foam::max for component-wise handling min() = Foam::min(min(), val); max() = Foam::max(max(), val); return *this; @@ -282,6 +274,25 @@ inline Foam::MinMax<T>& Foam::MinMax<T>::add(const UList<T>& vals) } +template<class T> +template<class... Args> +inline Foam::MinMax<T>& Foam::MinMax<T>::add +( + const T& val0, + const T& val1, + Args&&... values +) +{ + add(val0); + add(val1); + + // Add multiple values via fold expression + ((*this += std::forward<Args>(values)), ...); + + return *this; +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template<class T> @@ -325,6 +336,7 @@ inline bool Foam::MinMax<T>::operator()(const T& val) const template<class T> inline Foam::MinMax<T>& Foam::MinMax<T>::operator&=(const MinMax<T>& b) { + // Uses Foam::min/Foam::max for component-wise handling min() = ::Foam::max(min(), b.min()); max() = ::Foam::min(max(), b.max()); @@ -354,7 +366,7 @@ inline Foam::MinMax<T>& Foam::MinMax<T>::operator+=(const UList<T>& vals) template<class T> -inline Foam::MinMax<T>& Foam::MinMax<T>::operator*=(const scalar& s) +inline Foam::MinMax<T>& Foam::MinMax<T>::operator*=(scalar s) { min() *= s; max() *= s; @@ -363,7 +375,7 @@ inline Foam::MinMax<T>& Foam::MinMax<T>::operator*=(const scalar& s) template<class T> -inline Foam::MinMax<T>& Foam::MinMax<T>::operator/=(const scalar& s) +inline Foam::MinMax<T>& Foam::MinMax<T>::operator/=(scalar s) { min() /= s; max() /= s; diff --git a/src/OpenFOAM/primitives/ranges/MinMax/MinMaxOps.H b/src/OpenFOAM/primitives/ranges/MinMax/MinMaxOps.H index 5bad8452ec13ea97f6649347f4a9827afee6e6ff..71e3632bfc63866ac62794d69fcb601b80c23632 100644 --- a/src/OpenFOAM/primitives/ranges/MinMax/MinMaxOps.H +++ b/src/OpenFOAM/primitives/ranges/MinMax/MinMaxOps.H @@ -44,7 +44,7 @@ Description namespace Foam { -// Global Functions +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // //- The mag() function for min/max range template<class T> @@ -134,53 +134,6 @@ inline MinMax<T> minMax(const MinMax<T>& x, const MinMax<T>& y) } -//- Combine values and/or MinMax ranges -template<class T> -struct minMaxOp -{ - MinMax<T> operator()(const T& x, const T& y) const - { - return MinMax<T>(x).add(y); - } - - MinMax<T> operator()(const MinMax<T>& x, const T& y) const - { - return MinMax<T>(x).add(y); - } - - MinMax<T> operator()(const T& x, const MinMax<T>& y) const - { - return MinMax<T>(y).add(x); - } - - MinMax<T> operator()(const MinMax<T>& x, const MinMax<T>& y) const - { - return MinMax<T>(x).add(y); // Same as (x + y) - } -}; - - -//- Combine assignment for MinMax range -template<class T> -struct minMaxEqOp -{ - MinMax<T>& operator()(MinMax<T>& x, const T& y) const - { - return x.add(y); - } - - MinMax<T>& operator()(MinMax<T>& x, const UList<T>& y) const - { - return x.add(y); - } - - MinMax<T>& operator()(MinMax<T>& x, const MinMax<T>& y) const - { - return x.add(y); - } -}; - - //- The magnitude of a single value. inline scalarMinMax minMaxMag(const scalar val) { @@ -203,7 +156,7 @@ inline scalarMinMax minMaxMag(const UList<T>& vals) scalarMinMax result; for (const T& val : vals) { - result += Foam::mag(val); + result.add(Foam::mag(val)); } return result; @@ -221,92 +174,109 @@ inline scalarMinMax minMaxMag(const MinMax<T>& range) } -//- Combine the magitude of two values to create a min/max range. -//- Order is unimportant. -template<class T> -inline scalarMinMax minMaxMag(const T& x, const T& y) +//- Combine the magitude of two values (similar or dissimilar types) +//- to create a min/max range. Order is unimportant. +template<class T1, class T2> +inline scalarMinMax minMaxMag(const T1& x, const T2& y) { return minMaxMag(x).add(Foam::mag(y)); } -//- Scalar combine two MinMax ranges of same type -template<class T> -inline scalarMinMax minMaxMag(const MinMax<T>& x, const MinMax<T>& y) -{ - return - ( - minMaxMag(x) - .add(Foam::mag(y.min())) - .add(Foam::mag(y.max())) - ); -} - - -//- Scalar combine two MinMax ranges of dissimilar types +//- Scalar combine two MinMax ranges (same or dissimilar types) template<class T1, class T2> inline scalarMinMax minMaxMag(const MinMax<T1>& x, const MinMax<T2>& y) { - return - ( - minMaxMag(x) - .add(Foam::mag(y.min())) - .add(Foam::mag(y.max())) - ); + return minMaxMag(x).add(Foam::mag(y.min()), Foam::mag(y.max())); } -//- Scalar combine the magitude of a value. -template<class T> -struct minMaxMagOp -{ - scalarMinMax operator()(const scalarMinMax& x, const T& y) const - { - return minMaxMag(x).add(Foam::mag(y)); - } - - template<class T1, class T2> - scalarMinMax operator()(const MinMax<T1>& x, const MinMax<T2>& y) const - { - return minMaxMag(x, y); - } -}; - - -//- Combine assignment for MinMax range -template<class T> -struct minMaxMagEqOp -{ - scalarMinMax& operator()(scalarMinMax& x, const T& y) const - { - x = minMaxMag(x); - return x.add(Foam::mag(y)); - } - - scalarMinMax& operator()(scalarMinMax& x, const MinMax<T>& y) const - { - x = minMaxMag(x); - - return - ( - x - .add(Foam::mag(y.min())) - .add(Foam::mag(y.max())) - ); - } - - scalarMinMax& operator()(scalarMinMax& x, const UList<T>& y) const - { - x = minMaxMag(x); - - for (const T& val : y) - { - x.add(Foam::mag(val)); - } - - return x; - } -}; +// Mark as unused (2025-02) +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// //- Combine values and/or MinMax ranges +// template<class T> +// struct minMaxOp +// { +// MinMax<T> operator()(const T& x, const T& y) const +// { +// return MinMax<T>(x).add(y); +// } +// +// MinMax<T> operator()(const MinMax<T>& x, const T& y) const +// { +// return MinMax<T>(x).add(y); +// } +// +// MinMax<T> operator()(const T& x, const MinMax<T>& y) const +// { +// return MinMax<T>(y).add(x); +// } +// }; +// +// +// //- Combine assignment for MinMax range +// template<class T> +// struct minMaxEqOp +// { +// MinMax<T>& operator()(MinMax<T>& x, const T& y) const +// { +// return x.add(y); +// } +// +// MinMax<T>& operator()(MinMax<T>& x, const UList<T>& y) const +// { +// return x.add(y); +// } +// }; +// +// +// //- Scalar combine the magitude of a value. +// template<class T> +// struct minMaxMagOp +// { +// scalarMinMax operator()(const scalarMinMax& x, const T& y) const +// { +// return minMaxMag(x).add(Foam::mag(y)); +// } +// +// template<class T1, class T2> +// scalarMinMax operator()(const MinMax<T1>& x, const MinMax<T2>& y) const +// { +// return minMaxMag(x).add(Foam::mag(y.min()), Foam::mag(y.max())); +// } +// }; +// +// +// //- Combine assignment for MinMax range +// template<class T> +// struct minMaxMagEqOp +// { +// scalarMinMax& operator()(scalarMinMax& x, const T& y) const +// { +// x = minMaxMag(x); +// return x.add(Foam::mag(y)); +// } +// +// scalarMinMax& operator()(scalarMinMax& x, const MinMax<T>& y) const +// { +// x = minMaxMag(x); +// +// return x.add(Foam::mag(y.min()), Foam::mag(y.max())); +// } +// +// scalarMinMax& operator()(scalarMinMax& x, const UList<T>& y) const +// { +// x = minMaxMag(x); +// +// for (const T& val : y) +// { +// x.add(Foam::mag(val)); +// } +// +// return x; +// } +// }; // * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * // @@ -321,7 +291,7 @@ inline MinMax<T> operator+(const MinMax<T>& x, const MinMax<T>& y) //- Multiply range by scalar factor template<class T> -inline MinMax<T> operator*(const MinMax<T>& x, const scalar& s) +inline MinMax<T> operator*(const MinMax<T>& x, scalar s) { return MinMax<T>(x.min()*s, x.max()*s); } @@ -329,7 +299,7 @@ inline MinMax<T> operator*(const MinMax<T>& x, const scalar& s) //- Divide range by scalar factor template<class T> -inline MinMax<T> operator/(const MinMax<T>& x, const scalar& s) +inline MinMax<T> operator/(const MinMax<T>& x, scalar s) { return MinMax<T>(x.min()/s, x.max()/s); } diff --git a/src/Pstream/dummy/UPstreamReduce.C b/src/Pstream/dummy/UPstreamReduce.C index a23eee4dfd87799ed1212bab67fa6fa3020305a3..9572d0e52d19ac24a88308aaff3cfaa8e0e7fbd5 100644 --- a/src/Pstream/dummy/UPstreamReduce.C +++ b/src/Pstream/dummy/UPstreamReduce.C @@ -141,18 +141,6 @@ void Foam::reduce \ const label comm, \ UPstream::Request& req \ ) \ -{} \ - \ -/* Deprecated: prefer version with UPstream::Request */ \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm, \ - label& requestID \ -) \ {} \ \ void Foam::reduce \ @@ -163,17 +151,6 @@ void Foam::reduce \ const label comm, \ UPstream::Request& req \ ) \ -{} \ - \ -/* Deprecated: prefer version with UPstream::Request */ \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, \ - const label comm, \ - label& requestID \ -) \ {} \ \ void Foam::sumReduce \ diff --git a/src/Pstream/mpi/PstreamGlobals.H b/src/Pstream/mpi/PstreamGlobals.H index 48753956dbe44e773d32f7b648def8bf2744d034..2ccb245e3388439885e5250181b91a0ef028a17f 100644 --- a/src/Pstream/mpi/PstreamGlobals.H +++ b/src/Pstream/mpi/PstreamGlobals.H @@ -82,50 +82,40 @@ inline void checkCommunicator(int comm, int rank) } } +//- True if warn communicator is active and not equal to given communicator +inline bool warnCommunicator(int comm) noexcept +{ + return (UPstream::warnComm >= 0 && comm != UPstream::warnComm); +} + // * * * * * * * * * * * * * * * * Requests * * * * * * * * * * * * * * * * // -//- Reset UPstream::Request to null and/or the index of the outstanding -//- request to -1. -// Does not affect the stack of outstanding requests. -inline void reset_request -( - UPstream::Request* requestPtr, - label* requestIdx = nullptr -) +//- Reset UPstream::Request to MPI_REQUEST_NULL +// Does not affect the stack of outstanding requests +inline void reset_request(UPstream::Request* req) noexcept { - if (requestPtr) *requestPtr = UPstream::Request(MPI_REQUEST_NULL); - if (requestIdx) *requestIdx = -1; + if (req) *req = UPstream::Request(MPI_REQUEST_NULL); } //- Transcribe MPI_Request to UPstream::Request //- (does not affect the stack of outstanding requests) //- or else push onto list of outstanding requests -//- and (optionally) record its location inline void push_request ( MPI_Request request, - UPstream::Request* requestPtr = nullptr, - label* requestIdx = nullptr + UPstream::Request* req = nullptr ) { - if (requestPtr) + if (req) { // Transcribe as UPstream::Request - *requestPtr = UPstream::Request(request); - - // Not on stack of outstanding requests - if (requestIdx) *requestIdx = -1; + *req = UPstream::Request(request); } else { - if (requestIdx) - { - // Its index into outstanding requests - *requestIdx = PstreamGlobals::outstandingRequests_.size(); - } - + // Push onto list of requests PstreamGlobals::outstandingRequests_.push_back(request); } } diff --git a/src/Pstream/mpi/UIPstreamRead.C b/src/Pstream/mpi/UIPstreamRead.C index bec4a2e87f6cbd72c0e593d25ceff5174ed733d5..4f94257e712752c2351c2389772fb258e89fd919 100644 --- a/src/Pstream/mpi/UIPstreamRead.C +++ b/src/Pstream/mpi/UIPstreamRead.C @@ -66,7 +66,7 @@ static std::streamsize UPstream_mpi_receive } #endif - if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { Perr<< "UIPstream::read : starting read from:" << fromProcNo << " size:" << label(bufSize) @@ -76,7 +76,7 @@ static std::streamsize UPstream_mpi_receive << Foam::endl; error::printStack(Perr); } - else if (UPstream::debug) + else if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UIPstream::read : starting read from:" << fromProcNo << " size:" << label(bufSize) @@ -121,7 +121,7 @@ static std::streamsize UPstream_mpi_receive << Foam::abort(FatalError); return 0; } - else if (UPstream::debug) + else if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UIPstream::read : finished recv from:" << fromProcNo @@ -196,7 +196,7 @@ static std::streamsize UPstream_mpi_receive profilingPstream::addRequestTime(); - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UIPstream::read : started non-blocking recv from:" << fromProcNo @@ -223,7 +223,7 @@ static std::streamsize UPstream_mpi_receive void Foam::UIPstream::bufferIPCrecv() { // Called by constructor - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UIPstream IPC read buffer :" << " from:" << fromProcNo_ @@ -289,7 +289,7 @@ void Foam::UIPstream::bufferIPCrecv() << Foam::abort(FatalError); } - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UIPstream::UIPstream : probed size:" << label(count) << Foam::endl; diff --git a/src/Pstream/mpi/UOPstreamWrite.C b/src/Pstream/mpi/UOPstreamWrite.C index a8f4f04385f8dc3439f3ea2d06d161dbf02a91fd..d2e1da2ec65f255d3d215793843e079a6f015829 100644 --- a/src/Pstream/mpi/UOPstreamWrite.C +++ b/src/Pstream/mpi/UOPstreamWrite.C @@ -72,7 +72,7 @@ bool Foam::UOPstream::write } #endif - if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { Perr<< "UOPstream::write : starting write to:" << toProcNo << " size:" << label(bufSize) @@ -82,7 +82,7 @@ bool Foam::UOPstream::write << Foam::endl; error::printStack(Perr); } - else if (UPstream::debug) + else if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UOPstream::write : starting write to:" << toProcNo << " size:" << label(bufSize) @@ -112,7 +112,7 @@ bool Foam::UOPstream::write // Assume these are from scatters ... profilingPstream::addScatterTime(); - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UOPstream::write : finished buffered send to:" << toProcNo @@ -150,7 +150,7 @@ bool Foam::UOPstream::write // Assume these are from scatters ... profilingPstream::addScatterTime(); - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UOPstream::write : finished send to:" << toProcNo @@ -189,7 +189,7 @@ bool Foam::UOPstream::write ); } - if (UPstream::debug) + if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UOPstream::write : started non-blocking send to:" << toProcNo diff --git a/src/Pstream/mpi/UPstream.C b/src/Pstream/mpi/UPstream.C index 91391c8442d246a6664ed7394f95132960fa744a..82659a6b070d29f8a5acf4c22303eea4f3febaa3 100644 --- a/src/Pstream/mpi/UPstream.C +++ b/src/Pstream/mpi/UPstream.C @@ -39,8 +39,6 @@ License #include <numeric> #include <string> -#undef Pstream_use_MPI_Get_count - // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // The min value and default for MPI buffer length @@ -1178,33 +1176,28 @@ Foam::UPstream::probeMessage // Unlikely to be used with large amounts of data, // but use MPI_Get_elements_x() instead of MPI_Count() anyhow - #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 + MPI_Count num_recv(0); + MPI_Get_elements_x(&status, MPI_BYTE, &num_recv); // Errors - if (count == MPI_UNDEFINED || int64_t(count) < 0) + if (num_recv == MPI_UNDEFINED || int64_t(num_recv) < 0) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " + << "MPI_Get_elements_x() : " "returned undefined or negative value" << Foam::abort(FatalError); } - else if (int64_t(count) > int64_t(INT_MAX)) + else if (int64_t(num_recv) > int64_t(INT_MAX)) { FatalErrorInFunction - << "MPI_Get_count() or MPI_Get_elements_x() : " - "count is larger than INI_MAX bytes" + << "MPI_Get_elements_x() : " + "count is larger than INT_MAX bytes" << Foam::abort(FatalError); } result.first = status.MPI_SOURCE; - result.second = int64_t(count); + result.second = int64_t(num_recv); } return result; diff --git a/src/Pstream/mpi/UPstreamBroadcast.C b/src/Pstream/mpi/UPstreamBroadcast.C index dcf9ca8ed9dc4567e7c311a6d04e06754b3f04a7..1b3669d3a4121c95a28b332d5ebd6d1e307e8aec 100644 --- a/src/Pstream/mpi/UPstreamBroadcast.C +++ b/src/Pstream/mpi/UPstreamBroadcast.C @@ -47,7 +47,7 @@ bool Foam::UPstream::broadcast //Needed? PstreamGlobals::checkCommunicator(comm, rootProcNo); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(comm))) { Perr<< "UPstream::broadcast : root:" << rootProcNo << " comm:" << comm @@ -56,7 +56,7 @@ bool Foam::UPstream::broadcast << Foam::endl; error::printStack(Perr); } - else if (UPstream::debug) + else if (FOAM_UNLIKELY(UPstream::debug)) { Perr<< "UPstream::broadcast : root:" << rootProcNo << " comm:" << comm diff --git a/src/Pstream/mpi/UPstreamReduce.C b/src/Pstream/mpi/UPstreamReduce.C index d21a4e9a5b06baa1ee43e5a6618a7b6b2ee4d304..d9e96a89ceb13cd211c858a34345ed50bf0cd092 100644 --- a/src/Pstream/mpi/UPstreamReduce.C +++ b/src/Pstream/mpi/UPstreamReduce.C @@ -187,24 +187,7 @@ void Foam::reduce \ { \ PstreamDetail::allReduce<Native> \ ( \ - values, size, TaggedType, MPI_SUM, comm, &req, nullptr \ - ); \ -} \ - \ -/* Deprecated: prefer version with UPstream::Request */ \ -void Foam::reduce \ -( \ - Native values[], \ - const int size, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm, \ - label& requestID \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - values, size, TaggedType, MPI_SUM, comm, nullptr, &requestID \ + values, size, TaggedType, MPI_SUM, comm, &req \ ); \ } \ \ @@ -219,23 +202,7 @@ void Foam::reduce \ { \ PstreamDetail::allReduce<Native> \ ( \ - &value, 1, TaggedType, MPI_SUM, comm, &req, nullptr \ - ); \ -} \ - \ -/* Deprecated: prefer version with UPstream::Request */ \ -void Foam::reduce \ -( \ - Native& value, \ - const sumOp<Native>&, \ - const int tag, /* (unused) */ \ - const label comm, \ - label& requestID \ -) \ -{ \ - PstreamDetail::allReduce<Native> \ - ( \ - &value, 1, TaggedType, MPI_SUM, comm, nullptr, &requestID \ + &value, 1, TaggedType, MPI_SUM, comm, &req \ ); \ } \ \ diff --git a/src/Pstream/mpi/UPstreamRequest.C b/src/Pstream/mpi/UPstreamRequest.C index 3ac8b8ff8ab436803bd8e409284f8b6e79c192ff..afbad051d6c3a3aca1acb2a7c6ec77e19662c702 100644 --- a/src/Pstream/mpi/UPstreamRequest.C +++ b/src/Pstream/mpi/UPstreamRequest.C @@ -6,7 +6,7 @@ \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011 OpenFOAM Foundation - Copyright (C) 2023 OpenCFD Ltd. + Copyright (C) 2023-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -65,7 +65,7 @@ void Foam::UPstream::Request::reset() noexcept // << PstreamGlobals::outstandingRequests_.size() // << ')' << endl; // -// return UPstream::Communicator(MPI_REQUEST_NULL); +// return UPstream::Request(MPI_REQUEST_NULL); // } // // return UPstream::Request(PstreamGlobals::outstandingRequests_[req]); @@ -97,11 +97,13 @@ void Foam::UPstream::addRequest(UPstream::Request& req) return; } - // Transcribe as a MPI_Request - PstreamGlobals::outstandingRequests_.push_back - ( - PstreamUtils::Cast::to_mpi(req) - ); + { + MPI_Request request = PstreamUtils::Cast::to_mpi(req); + if (MPI_REQUEST_NULL != request) + { + PstreamGlobals::outstandingRequests_.push_back(request); + } + } // Invalidate parameter req = UPstream::Request(MPI_REQUEST_NULL); diff --git a/src/Pstream/mpi/UPstreamWrapping.H b/src/Pstream/mpi/UPstreamWrapping.H index a76a2664b3a6f8df392c238201a968def1fd830a..b98c99f314f2c2a521016c7f4117be46df886f42 100644 --- a/src/Pstream/mpi/UPstreamWrapping.H +++ b/src/Pstream/mpi/UPstreamWrapping.H @@ -48,13 +48,14 @@ namespace PstreamDetail { // MPI_Bcast, using root=0 +// No fail/abort handling template<class Type> -void broadcast0 +bool broadcast0 ( Type* values, int count, MPI_Datatype datatype, - const label comm + const int communicator ); // MPI_Reduce, using root=0 @@ -65,7 +66,8 @@ void reduce0 int count, MPI_Datatype datatype, MPI_Op optype, - const label comm + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); // MPI_Allreduce or MPI_Iallreduce @@ -76,9 +78,8 @@ void allReduce int count, MPI_Datatype datatype, MPI_Op optype, - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -89,9 +90,8 @@ void allToAll const UList<Type>& sendData, UList<Type>& recvData, MPI_Datatype datatype, - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -108,9 +108,8 @@ void allToAllv const UList<int>& recvOffsets, MPI_Datatype datatype, - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -122,7 +121,7 @@ void allToAllConsensus UList<Type>& recvData, MPI_Datatype datatype, const int tag, // Message tag - const label comm // Communicator + const int communicator // Communicator ); @@ -134,7 +133,7 @@ void allToAllConsensus Map<Type>& recvData, MPI_Datatype datatype, const int tag, // Message tag - const label comm // Communicator + const int communicator // Communicator ); @@ -147,9 +146,8 @@ void gather Type* recvData, // On master: recv buffer. Ignored elsewhere int count, // Per rank send/recv count. Globally consistent! MPI_Datatype datatype, // The send/recv data type - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -162,9 +160,8 @@ void scatter Type* recvData, // Local recv value int count, // Per rank send/recv count. Globally consistent! MPI_Datatype datatype, // The send/recv data type - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -180,9 +177,8 @@ void gatherv const UList<int>& recvOffsets, // Ignored on non-root rank MPI_Datatype datatype, // The send/recv data type - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -198,9 +194,8 @@ void scatterv int recvCount, MPI_Datatype datatype, // The send/recv data type - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); @@ -212,9 +207,8 @@ void allGather int count, // The send/recv count per element MPI_Datatype datatype, // The send/recv data type - const label comm, // Communicator - UPstream::Request* req = nullptr, // Non-null for non-blocking - label* requestID = nullptr // (alternative to UPstream::Request) + const int communicator, // Communicator + UPstream::Request* req = nullptr // Non-null for non-blocking ); diff --git a/src/Pstream/mpi/UPstreamWrapping.txx b/src/Pstream/mpi/UPstreamWrapping.txx index cce0e9cdcb8c210ca9f27759cc872ed48c03aa1d..057c0e6025fe25709699ddcb0d42194fc75cc018 100644 --- a/src/Pstream/mpi/UPstreamWrapping.txx +++ b/src/Pstream/mpi/UPstreamWrapping.txx @@ -35,32 +35,39 @@ License // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // template<class Type> -void Foam::PstreamDetail::broadcast0 +bool Foam::PstreamDetail::broadcast0 ( Type* values, int count, MPI_Datatype datatype, - const label comm + const int communicator ) { - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { - return; + return true; } + + int returnCode(MPI_SUCCESS); + profilingPstream::beginTiming(); - // const int returnCode = - MPI_Bcast - ( - values, - count, - datatype, - 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ); + { + returnCode = + MPI_Bcast + ( + values, + count, + datatype, + 0, // (root rank) == UPstream::masterNo() + PstreamGlobals::MPICommunicators_[communicator] + ); + } profilingPstream::addBroadcastTime(); + + return (returnCode == MPI_SUCCESS); } @@ -71,45 +78,121 @@ void Foam::PstreamDetail::reduce0 int count, MPI_Datatype datatype, MPI_Op optype, - const label comm + const int communicator, + + UPstream::Request* req ) { - if (!UPstream::is_parallel(comm)) + PstreamGlobals::reset_request(req); + + const bool immediate = (req); + + if (!UPstream::is_parallel(communicator)) { return; } - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { - Perr<< "** MPI_Reduce (blocking):"; - if (count == 1) + if (immediate) + { + Perr<< "** MPI_Ireduce (non-blocking):"; + } + else { - Perr<< (*values); + Perr<< "** MPI_Reduce (blocking):"; + } + if constexpr (std::is_void_v<Type>) + { + Perr<< count << " values"; } else { - Perr<< UList<Type>(values, count); + if (count == 1) + { + Perr<< (*values); + } + else + { + Perr<< UList<Type>(values, count); + } } - Perr<< " with comm:" << comm + Perr<< " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); } - profilingPstream::beginTiming(); - // const int returnCode = - MPI_Reduce - ( - MPI_IN_PLACE, // recv is also send - values, - count, - datatype, - optype, - 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ); - - profilingPstream::addReduceTime(); + int returnCode(MPI_ERR_UNKNOWN); + +#if defined(MPI_VERSION) && (MPI_VERSION >= 3) + if (immediate) + { + // MPI-3 : eg, openmpi-1.7 (2013) and later + profilingPstream::beginTiming(); + MPI_Request request; + + returnCode = + MPI_Ireduce + ( + MPI_IN_PLACE, // recv is also send + values, + count, + datatype, + optype, + 0, // (root rank) == UPstream::masterNo() + PstreamGlobals::MPICommunicators_[communicator], + &request + ); + + PstreamGlobals::push_request(request, req); + profilingPstream::addRequestTime(); + } + else +#endif + { + profilingPstream::beginTiming(); + + returnCode = + MPI_Reduce + ( + MPI_IN_PLACE, // recv is also send + values, + count, + datatype, + optype, + 0, // (root rank) == UPstream::masterNo() + PstreamGlobals::MPICommunicators_[communicator] + ); + + profilingPstream::addReduceTime(); + } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + 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); + } } @@ -120,22 +203,21 @@ void Foam::PstreamDetail::allReduce int count, MPI_Datatype datatype, MPI_Op optype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { return; } - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -145,20 +227,29 @@ void Foam::PstreamDetail::allReduce { Perr<< "** MPI_Allreduce (blocking):"; } - if (count == 1) + if constexpr (std::is_void_v<Type>) { - Perr<< (*values); + Perr<< count << " values"; } else { - Perr<< UList<Type>(values, count); + if (count == 1) + { + Perr<< (*values); + } + else + { + Perr<< UList<Type>(values, count); + } } - Perr<< " with comm:" << comm + Perr<< " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -166,8 +257,7 @@ void Foam::PstreamDetail::allReduce profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Iallreduce ( MPI_IN_PLACE, // recv is also send @@ -175,19 +265,11 @@ void Foam::PstreamDetail::allReduce count, datatype, optype, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Iallreduce failed for " - << UList<Type>(values, count) - << Foam::abort(FatalError); - } - + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -195,8 +277,7 @@ void Foam::PstreamDetail::allReduce { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Allreduce ( MPI_IN_PLACE, // recv is also send @@ -204,18 +285,36 @@ void Foam::PstreamDetail::allReduce count, datatype, optype, - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Allreduce failed for " - << UList<Type>(values, count) - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addReduceTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction<< "MPI Allreduce "; + 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); + } } @@ -225,24 +324,25 @@ void Foam::PstreamDetail::allToAll const UList<Type>& sendData, UList<Type>& recvData, MPI_Datatype datatype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + static_assert(!std::is_void_v<Type>, "Does not handle void types"); + + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; } - const label numProc = UPstream::nProcs(comm); + const label numProc = UPstream::nProcs(communicator); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -254,7 +354,7 @@ void Foam::PstreamDetail::allToAll } Perr<< " numProc:" << numProc << " sendData:" << sendData.size() - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -272,13 +372,15 @@ void Foam::PstreamDetail::allToAll << Foam::abort(FatalError); } - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { recvData.deepCopy(sendData); return; } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -286,8 +388,7 @@ void Foam::PstreamDetail::allToAll profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Ialltoall ( // NOTE: const_cast is a temporary hack for @@ -298,18 +399,11 @@ void Foam::PstreamDetail::allToAll recvData.data(), 1, // one element per rank datatype, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Ialltoall [comm: " << comm << "] failed." - << " For " << sendData - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -317,8 +411,7 @@ void Foam::PstreamDetail::allToAll { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Alltoall ( // NOTE: const_cast is a temporary hack for @@ -329,18 +422,23 @@ void Foam::PstreamDetail::allToAll recvData.data(), 1, // one element per rank datatype, - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Alltoall [comm: " << comm << "] failed." - << " For " << sendData - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addAllToAllTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction<< "MPI Alltoall "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed for " + << sendData << endl + << Foam::abort(FatalError); + } } @@ -356,24 +454,25 @@ void Foam::PstreamDetail::allToAllv const UList<int>& recvOffsets, MPI_Datatype datatype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + static_assert(!std::is_void_v<Type>, "Does not handle void types"); + + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; } - const label np = UPstream::nProcs(comm); + const label np = UPstream::nProcs(communicator); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -385,7 +484,7 @@ void Foam::PstreamDetail::allToAllv } Perr<< " sendCounts:" << sendCounts << " sendOffsets:" << sendOffsets - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -406,9 +505,9 @@ void Foam::PstreamDetail::allToAllv << Foam::abort(FatalError); } - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { - if (recvCounts[0] != sendCounts[0]) + if (FOAM_UNLIKELY(recvCounts[0] != sendCounts[0])) { FatalErrorInFunction << "Bytes to send " << sendCounts[0] @@ -426,6 +525,8 @@ void Foam::PstreamDetail::allToAllv } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -433,8 +534,7 @@ void Foam::PstreamDetail::allToAllv profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Ialltoallv ( const_cast<Type*>(sendData), @@ -445,19 +545,11 @@ void Foam::PstreamDetail::allToAllv const_cast<int*>(recvCounts.cdata()), const_cast<int*>(recvOffsets.cdata()), datatype, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Ialltoallv [comm: " << comm << "] failed." - << " For sendCounts " << sendCounts - << " recvCounts " << recvCounts - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -465,8 +557,7 @@ void Foam::PstreamDetail::allToAllv { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Alltoallv ( const_cast<Type*>(sendData), @@ -477,20 +568,24 @@ void Foam::PstreamDetail::allToAllv const_cast<int*>(recvCounts.cdata()), const_cast<int*>(recvOffsets.cdata()), datatype, - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Alltoallv [comm: " << comm << "] failed." - << " For sendCounts " << sendCounts - << " recvCounts " << recvCounts - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addAllToAllTime(); } + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction<< "MPI Alltoallv "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed for " + << " For sendCounts " << sendCounts + << " recvCounts " << recvCounts << endl + << Foam::abort(FatalError); + } } @@ -501,25 +596,27 @@ void Foam::PstreamDetail::allToAllConsensus UList<Type>& recvData, MPI_Datatype datatype, const int tag, - const label comm + const int communicator ) { + static_assert(!std::is_void_v<Type>, "Does not handle void types"); + const bool initialBarrier = (UPstream::tuning_NBX_ > 0); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; // Process not in communicator } - const label myProci = UPstream::myProcNo(comm); - const label numProc = UPstream::nProcs(comm); + const label myProci = UPstream::myProcNo(communicator); + const label numProc = UPstream::nProcs(communicator); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { Perr<< "** non-blocking consensus Alltoall (list):"; Perr<< " numProc:" << numProc << " sendData:" << sendData.size() - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -538,7 +635,7 @@ void Foam::PstreamDetail::allToAllConsensus const Type zeroValue = pTraits<Type>::zero; recvData = zeroValue; - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { // Non-parallel : deep copy recvData.deepCopy(sendData); @@ -578,7 +675,7 @@ void Foam::PstreamDetail::allToAllConsensus // caused elsewhere if (initialBarrier) { - MPI_Barrier(PstreamGlobals::MPICommunicators_[comm]); + MPI_Barrier(PstreamGlobals::MPICommunicators_[communicator]); } DynamicList<MPI_Request> sendRequests(sendData.size()); @@ -601,7 +698,7 @@ void Foam::PstreamDetail::allToAllConsensus datatype, proci, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &sendRequests.emplace_back() ); } @@ -623,7 +720,7 @@ void Foam::PstreamDetail::allToAllConsensus ( MPI_ANY_SOURCE, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &flag, &status ); @@ -637,7 +734,7 @@ void Foam::PstreamDetail::allToAllConsensus int count(0); MPI_Get_count(&status, datatype, &count); - if (count != 1) + if (FOAM_UNLIKELY(count != 1)) { FatalErrorInFunction << "Incorrect message size from proc=" << proci @@ -654,7 +751,7 @@ void Foam::PstreamDetail::allToAllConsensus datatype, proci, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], MPI_STATUS_IGNORE ); } @@ -684,7 +781,7 @@ void Foam::PstreamDetail::allToAllConsensus { MPI_Ibarrier ( - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &barrierRequest ); barrier_active = true; @@ -703,25 +800,27 @@ void Foam::PstreamDetail::allToAllConsensus Map<Type>& recvBufs, MPI_Datatype datatype, const int tag, - const label comm + const int communicator ) { + static_assert(!std::is_void_v<Type>, "Does not handle void types"); + const bool initialBarrier = (UPstream::tuning_NBX_ > 0); - const label myProci = UPstream::myProcNo(comm); - const label numProc = UPstream::nProcs(comm); + const label myProci = UPstream::myProcNo(communicator); + const label numProc = UPstream::nProcs(communicator); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; } - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { Perr<< "** non-blocking consensus Alltoall (map):"; Perr<< " numProc:" << numProc << " sendData:" << sendBufs.size() - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -740,7 +839,7 @@ void Foam::PstreamDetail::allToAllConsensus } } - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { // Nothing left to do return; @@ -762,7 +861,7 @@ void Foam::PstreamDetail::allToAllConsensus // caused elsewhere if (initialBarrier) { - MPI_Barrier(PstreamGlobals::MPICommunicators_[comm]); + MPI_Barrier(PstreamGlobals::MPICommunicators_[communicator]); } @@ -784,7 +883,7 @@ void Foam::PstreamDetail::allToAllConsensus datatype, proci, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &sendRequests.emplace_back() ); } @@ -806,7 +905,7 @@ void Foam::PstreamDetail::allToAllConsensus ( MPI_ANY_SOURCE, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &flag, &status ); @@ -820,7 +919,7 @@ void Foam::PstreamDetail::allToAllConsensus int count(0); MPI_Get_count(&status, datatype, &count); - if (count != 1) + if (FOAM_UNLIKELY(count != 1)) { FatalErrorInFunction << "Incorrect message size from proc=" << proci @@ -839,7 +938,7 @@ void Foam::PstreamDetail::allToAllConsensus datatype, proci, tag, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], MPI_STATUS_IGNORE ); } @@ -869,7 +968,7 @@ void Foam::PstreamDetail::allToAllConsensus { MPI_Ibarrier ( - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &barrierRequest ); barrier_active = true; @@ -890,31 +989,33 @@ void Foam::PstreamDetail::gather int count, MPI_Datatype datatype, - const label comm, - UPstream::Request* req, - label* requestID + const int communicator, + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm) || !count) + if (!UPstream::is_rank(communicator) || !count) { return; } - else if (!UPstream::is_parallel(comm)) + else if (!UPstream::is_parallel(communicator)) { - 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) { std::memmove(recvData, sendData, count*sizeof(Type)); } return; } - const label numProc = UPstream::nProcs(comm); - - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -924,13 +1025,13 @@ void Foam::PstreamDetail::gather { Perr<< "** MPI_Gather (blocking):"; } - if (sendData == nullptr) + if (sendData == nullptr || (sendData == recvData)) { Perr<< " [inplace]"; } - Perr<< " numProc:" << numProc + Perr<< " numProc:" << UPstream::nProcs(communicator) << " count:" << count - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -943,6 +1044,9 @@ void Foam::PstreamDetail::gather send_buffer = MPI_IN_PLACE; } + + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -950,25 +1054,17 @@ void Foam::PstreamDetail::gather profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Igather ( send_buffer, count, datatype, recvData, count, datatype, 0, // root: UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Igather [comm: " << comm << "] failed." - << " count:" << count << nl - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -976,25 +1072,29 @@ void Foam::PstreamDetail::gather { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Gather ( send_buffer, count, datatype, recvData, count, datatype, 0, // root: UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Gather [comm: " << comm << "] failed." - << " count:" << count << nl - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addGatherTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction << "MPI Gather "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed." + << " count:" << count << nl + << Foam::abort(FatalError); + } } @@ -1007,31 +1107,33 @@ void Foam::PstreamDetail::scatter int count, MPI_Datatype datatype, - const label comm, - UPstream::Request* req, - label* requestID + const int communicator, + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm) || !count) + if (!UPstream::is_rank(communicator) || !count) { return; } - else if (!UPstream::is_parallel(comm)) + else if (!UPstream::is_parallel(communicator)) { - 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) { std::memmove(recvData, sendData, count*sizeof(Type)); } return; } - const label numProc = UPstream::nProcs(comm); - - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -1041,13 +1143,13 @@ void Foam::PstreamDetail::scatter { Perr<< "** MPI_Scatter (blocking):"; } - if (sendData == nullptr) + if (sendData == nullptr || (sendData == recvData)) { Perr<< " [inplace]"; } - Perr<< " numProc:" << numProc + Perr<< " numProc:" << UPstream::nProcs(communicator) << " count:" << count - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -1061,6 +1163,9 @@ void Foam::PstreamDetail::scatter send_buffer = MPI_IN_PLACE; } + + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -1068,25 +1173,17 @@ void Foam::PstreamDetail::scatter profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Iscatter ( send_buffer, count, datatype, recvData, count, datatype, 0, // root: UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Iscatter [comm: " << comm << "] failed." - << " count:" << count << nl - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -1094,25 +1191,29 @@ void Foam::PstreamDetail::scatter { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Scatter ( send_buffer, count, datatype, recvData, count, datatype, 0, // root: UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Scatter [comm: " << comm << "] failed." - << " count:" << count << nl - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addScatterTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction << "MPI Scatter "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed." + << " count:" << count << nl + << Foam::abort(FatalError); + } } @@ -1127,21 +1228,20 @@ void Foam::PstreamDetail::gatherv const UList<int>& recvOffsets, MPI_Datatype datatype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; } - else if (!UPstream::is_parallel(comm)) + else if (!UPstream::is_parallel(communicator)) { // recvCounts[0] may be invalid - use sendCount instead if (sendData && recvData) @@ -1151,9 +1251,9 @@ void Foam::PstreamDetail::gatherv return; } - const label np = UPstream::nProcs(comm); + const label np = UPstream::nProcs(communicator); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -1166,7 +1266,7 @@ void Foam::PstreamDetail::gatherv Perr<< " np:" << np << " recvCounts:" << recvCounts << " recvOffsets:" << recvOffsets - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -1174,7 +1274,7 @@ void Foam::PstreamDetail::gatherv if ( - UPstream::master(comm) + UPstream::master(communicator) && (recvCounts.size() != np || recvOffsets.size() < np) ) { @@ -1189,12 +1289,14 @@ void Foam::PstreamDetail::gatherv } // Ensure send/recv consistency on master - if (UPstream::master(comm) && !recvCounts[0]) + if (UPstream::master(communicator) && !recvCounts[0]) { sendCount = 0; } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -1202,8 +1304,7 @@ void Foam::PstreamDetail::gatherv profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Igatherv ( const_cast<Type*>(sendData), @@ -1214,19 +1315,11 @@ void Foam::PstreamDetail::gatherv const_cast<int*>(recvOffsets.cdata()), datatype, 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Igatherv failed [comm: " << comm << ']' - << " sendCount " << sendCount - << " recvCounts " << recvCounts - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -1234,8 +1327,7 @@ void Foam::PstreamDetail::gatherv { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Gatherv ( const_cast<Type*>(sendData), @@ -1246,19 +1338,24 @@ void Foam::PstreamDetail::gatherv const_cast<int*>(recvOffsets.cdata()), datatype, 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Gatherv failed [comm: " << comm << ']' - << " sendCount " << sendCount - << " recvCounts " << recvCounts - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addGatherTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction << "MPI Gatherv "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed." + << " sendCount " << sendCount + << " recvCounts " << recvCounts + << Foam::abort(FatalError); + } } @@ -1273,29 +1370,28 @@ void Foam::PstreamDetail::scatterv int recvCount, MPI_Datatype datatype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_rank(comm)) + if (!UPstream::is_rank(communicator)) { return; } - else if (!UPstream::is_parallel(comm)) + else if (!UPstream::is_parallel(communicator)) { std::memmove(recvData, sendData, recvCount*sizeof(Type)); return; } - const label np = UPstream::nProcs(comm); + const label np = UPstream::nProcs(communicator); - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -1308,7 +1404,7 @@ void Foam::PstreamDetail::scatterv Perr<< " np:" << np << " sendCounts:" << sendCounts << " sendOffsets:" << sendOffsets - << " with comm:" << comm + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); @@ -1316,7 +1412,7 @@ void Foam::PstreamDetail::scatterv if ( - UPstream::master(comm) + UPstream::master(communicator) && (sendCounts.size() != np || sendOffsets.size() < np) ) { @@ -1331,6 +1427,8 @@ void Foam::PstreamDetail::scatterv } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -1338,8 +1436,7 @@ void Foam::PstreamDetail::scatterv profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Iscatterv ( const_cast<Type*>(sendData), @@ -1350,19 +1447,11 @@ void Foam::PstreamDetail::scatterv recvCount, datatype, 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Iscatterv [comm: " << comm << "] failed." - << " sendCounts " << sendCounts - << " sendOffsets " << sendOffsets - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -1370,8 +1459,7 @@ void Foam::PstreamDetail::scatterv { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Scatterv ( const_cast<Type*>(sendData), @@ -1382,19 +1470,24 @@ void Foam::PstreamDetail::scatterv recvCount, datatype, 0, // (root rank) == UPstream::masterNo() - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Scatterv [comm: " << comm << "] failed." - << " sendCounts " << sendCounts - << " sendOffsets " << sendOffsets - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); profilingPstream::addScatterTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction << "MPI Scatterv "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed." + << " sendCounts " << sendCounts + << " sendOffsets " << sendOffsets + << Foam::abort(FatalError); + } } @@ -1405,23 +1498,22 @@ void Foam::PstreamDetail::allGather int count, MPI_Datatype datatype, - const label comm, + const int communicator, - UPstream::Request* req, - label* requestID + UPstream::Request* req ) { - PstreamGlobals::reset_request(req, requestID); + PstreamGlobals::reset_request(req); - const bool immediate = (req || requestID); + const bool immediate = (req); - if (!UPstream::is_parallel(comm)) + if (!UPstream::is_parallel(communicator)) { // Nothing to do - ignore return; } - if (UPstream::warnComm >= 0 && comm != UPstream::warnComm) + if (FOAM_UNLIKELY(PstreamGlobals::warnCommunicator(communicator))) { if (immediate) { @@ -1431,14 +1523,16 @@ void Foam::PstreamDetail::allGather { Perr<< "** MPI_Allgather (blocking):"; } - Perr<< " numProc:" << UPstream::nProcs(comm) - << " with comm:" << comm + Perr<< " numProc:" << UPstream::nProcs(communicator) + << " with comm:" << communicator << " warnComm:" << UPstream::warnComm << endl; error::printStack(Perr); } + int returnCode(MPI_ERR_UNKNOWN); + #if defined(MPI_VERSION) && (MPI_VERSION >= 3) if (immediate) { @@ -1446,23 +1540,16 @@ void Foam::PstreamDetail::allGather profilingPstream::beginTiming(); MPI_Request request; - if - ( + returnCode = MPI_Iallgather ( MPI_IN_PLACE, count, datatype, allData, count, datatype, - PstreamGlobals::MPICommunicators_[comm], + PstreamGlobals::MPICommunicators_[communicator], &request - ) - ) - { - FatalErrorInFunction - << "MPI_Iallgather [comm: " << comm << "] failed." - << Foam::abort(FatalError); - } + ); - PstreamGlobals::push_request(request, req, requestID); + PstreamGlobals::push_request(request, req); profilingPstream::addRequestTime(); } else @@ -1470,24 +1557,28 @@ void Foam::PstreamDetail::allGather { profilingPstream::beginTiming(); - if - ( + returnCode = MPI_Allgather ( MPI_IN_PLACE, count, datatype, allData, count, datatype, - PstreamGlobals::MPICommunicators_[comm] - ) - ) - { - FatalErrorInFunction - << "MPI_Allgather [comm: " << comm << "] failed." - << Foam::abort(FatalError); - } + PstreamGlobals::MPICommunicators_[communicator] + ); // Is actually gather/scatter but we can't split it apart profilingPstream::addGatherTime(); } + + // Error handling + if (FOAM_UNLIKELY(returnCode != MPI_SUCCESS)) + { + FatalErrorInFunction << "MPI Allgather "; + if (immediate) FatalError<< "(non-blocking) "; + + FatalError + << "[comm: " << communicator << "] failed." + << Foam::abort(FatalError); + } } diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C index 0d3ff48e361e96e950c5e8b80e23b1cd80defa1d..43f81ddfec8299b59a3cfa36f767e2a24b969ee6 100644 --- a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementPointSmoothingMotionSolver.C @@ -199,7 +199,7 @@ bool Foam::displacementPointSmoothingMotionSolver::relax() ); // Synchronise completion - reduce(complete, andOp<bool>()); + UPstream::reduceAnd(complete); } // Check for convergence @@ -222,7 +222,7 @@ bool Foam::displacementPointSmoothingMotionSolver::relax() } // Syncronise convergence - reduce(converged, andOp<bool>()); + UPstream::reduceAnd(converged); //if (converged) //{ diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C index 804c10214f278fbd0d4a9bba9127f1e6cc8d311b..2538bc654e3c07956bae18a48ce5689768d8dabc 100644 --- a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/displacementSmartPointSmoothingMotionSolver.C @@ -245,7 +245,7 @@ bool Foam::displacementSmartPointSmoothingMotionSolver::relax() ); // Synchronise completion - reduce(complete, andOp<bool>()); + UPstream::reduceAnd(complete); } // Check for convergence @@ -266,7 +266,7 @@ bool Foam::displacementSmartPointSmoothingMotionSolver::relax() } // Syncronise convergence - reduce(converged, andOp<bool>()); + UPstream::reduceAnd(converged); //if (converged) //{ diff --git a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C index f8b250f690f7b1e964f4fd991d7cbe4b52725287..d8964afef6d473e5f2c29f484b4173baebb4c1d1 100644 --- a/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C +++ b/src/dynamicMesh/motionSolvers/displacement/pointSmoothing/hexMeshSmootherMotionSolver.C @@ -405,7 +405,7 @@ bool Foam::hexMeshSmootherMotionSolver::relax // Synchronise convergence - reduce(complete, andOp<bool>()); + UPstream::reduceAnd(complete); // Synchronise relaxation levels syncTools::syncPointList diff --git a/src/finiteArea/faMesh/faMeshTools/faMeshToolsChecks.C b/src/finiteArea/faMesh/faMeshTools/faMeshToolsChecks.C index 7664356be9330945c1042d35d85c21238b48ff79..e166a0bdd25256b438c669867ea08abb597cd3fc 100644 --- a/src/finiteArea/faMesh/faMeshTools/faMeshToolsChecks.C +++ b/src/finiteArea/faMesh/faMeshTools/faMeshToolsChecks.C @@ -161,14 +161,14 @@ void Foam::faMeshTools::printMeshChecks scalarMinMax limit(minMax(mesh.magLe().primitiveField())); // Include processor boundaries into 'internal' edges - if (Pstream::parRun()) + if (UPstream::parRun()) { for (label patchi = nNonProcessor; patchi < nPatches; ++patchi) { limit.add(minMax(mesh.magLe().boundaryField()[patchi])); } - reduce(limit, minMaxOp<scalar>()); + reduce(limit, plusOp<scalarMinMax>{}); } Info<< "Edge length (internal):" << nl @@ -181,9 +181,9 @@ void Foam::faMeshTools::printMeshChecks limit.add(minMax(mesh.magLe().boundaryField()[patchi])); } - if (Pstream::parRun()) + if (UPstream::parRun()) { - reduce(limit, minMaxOp<scalar>()); + reduce(limit, plusOp<scalarMinMax>{}); } Info<< "Edge length:" << nl diff --git a/src/finiteVolume/cfdTools/general/pressureControl/pressureControl.C b/src/finiteVolume/cfdTools/general/pressureControl/pressureControl.C index 2e5de81abaf9e6adedde6e90e62675bd73f86eb6..559628a101167440d6ac8948513564220317dd09 100644 --- a/src/finiteVolume/cfdTools/general/pressureControl/pressureControl.C +++ b/src/finiteVolume/cfdTools/general/pressureControl/pressureControl.C @@ -87,7 +87,7 @@ Foam::pressureControl::pressureControl } } - reduce(rhoLimits, andOp<bool>()); + UPstream::reduceAnd(rhoLimits); if (rhoLimits) { reduce(pMax, maxOp<scalar>()); diff --git a/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/turbulentDFSEMInletFvPatchVectorField.C b/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/turbulentDFSEMInletFvPatchVectorField.C index f7e7ac5a0b7b0bb83be91bfab5283a2fc9c950a5..a59ecba23f6d26ac699546bed51c9b9cfad9925b 100644 --- a/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/turbulentDFSEMInletFvPatchVectorField.C +++ b/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/turbulentDFSEMInletFvPatchVectorField.C @@ -372,7 +372,7 @@ void Foam::turbulentDFSEMInletFvPatchVectorField::initialiseEddies() } // else eddy on remote processor - reduce(search, andOp<bool>()); + UPstream::reduceAnd(search); } diff --git a/src/functionObjects/field/binField/binModels/singleDirectionUniformBin/singleDirectionUniformBin.C b/src/functionObjects/field/binField/binModels/singleDirectionUniformBin/singleDirectionUniformBin.C index 4d66960b97fa465e2bf69cfdf41b9d7fc884ee86..6b39e51995b38b6669212e39af342199b748cbf5 100644 --- a/src/functionObjects/field/binField/binModels/singleDirectionUniformBin/singleDirectionUniformBin.C +++ b/src/functionObjects/field/binField/binModels/singleDirectionUniformBin/singleDirectionUniformBin.C @@ -75,7 +75,7 @@ void Foam::binModels::singleDirectionUniformBin::initialise() } // Globally consistent - reduce(geomLimits, minMaxOp<scalar>()); + reduce(geomLimits, sumOp<scalarMinMax>()); if (!geomLimits.good()) { diff --git a/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C b/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C index dc122d42362b10886545eee7a0afc53ae94c2bc1..65f9a19643f2e383ac32a6b8a705d89748fce4db 100644 --- a/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C +++ b/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C @@ -58,9 +58,7 @@ void Foam::binModels::uniformBin::initialise() ); MinMax<vector> limits(pts); - - geomLimits.add(limits.min()); - geomLimits.add(limits.max()); + geomLimits.add(limits.min(), limits.max()); } for (const label zonei : cellZoneIDs_) @@ -72,9 +70,7 @@ void Foam::binModels::uniformBin::initialise() ); MinMax<vector> limits(pts); - - geomLimits.add(limits.min()); - geomLimits.add(limits.max()); + geomLimits.add(limits.min(), limits.max()); } // Globally consistent diff --git a/src/mesh/blockMesh/PDRblockMesh/PDRblock.H b/src/mesh/blockMesh/PDRblockMesh/PDRblock.H index d0302b075b5515156a05cd3ebfe27a6f346486dd..22bc331633933fdd01b9b0da2bd72e7da7a1ec1e 100644 --- a/src/mesh/blockMesh/PDRblockMesh/PDRblock.H +++ b/src/mesh/blockMesh/PDRblockMesh/PDRblock.H @@ -175,10 +175,12 @@ public: // within bounds, but not aligned with a grid point. label findIndex(const scalar p, const scalar tol) const; - //- If out of range, return the respective min/max limits, - //- otherwise return the value itself. + //- Return value clamped to min/max limits. // If the range is invalid, always return the value. - inline const scalar& clip(const scalar& val) const; + inline const scalar& clamp(const scalar& val) const; + + //- Return value clamped to min/max limits. + const scalar& clip(const scalar& val) const { return clamp(val); } }; diff --git a/src/mesh/blockMesh/PDRblockMesh/PDRblockI.H b/src/mesh/blockMesh/PDRblockMesh/PDRblockI.H index 8e34c6ddd4db0ab0df6a5779774a11a37afaf6a6..7999f86d29bab6d819d9ed9f0a3f48ecf4783264 100644 --- a/src/mesh/blockMesh/PDRblockMesh/PDRblockI.H +++ b/src/mesh/blockMesh/PDRblockMesh/PDRblockI.H @@ -124,7 +124,7 @@ inline Foam::scalar Foam::PDRblock::location::C(const label i) const inline const Foam::scalar& -Foam::PDRblock::location::clip(const scalar& val) const +Foam::PDRblock::location::clamp(const scalar& val) const { if (scalarList::size()) { diff --git a/src/meshTools/AMIInterpolation/GAMG/interfaces/cyclicAMIGAMGInterface/cyclicAMIGAMGInterface.C b/src/meshTools/AMIInterpolation/GAMG/interfaces/cyclicAMIGAMGInterface/cyclicAMIGAMGInterface.C index 69dd64b6380598167798e0f864d9c65f84646aed..f2a2d0ebe4dc5a98961697ccc93d5e73351e84e9 100644 --- a/src/meshTools/AMIInterpolation/GAMG/interfaces/cyclicAMIGAMGInterface/cyclicAMIGAMGInterface.C +++ b/src/meshTools/AMIInterpolation/GAMG/interfaces/cyclicAMIGAMGInterface/cyclicAMIGAMGInterface.C @@ -180,8 +180,7 @@ Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface const auto& AMI = amiPtr_(); if (debug & 2) { - const auto oldWarnComm = UPstream::warnComm; - UPstream::warnComm = AMI.comm(); + const auto oldWarnComm = UPstream::commWarn(AMI.comm()); const label myRank = UPstream::myProcNo(AMI.comm()); Pout<< "At level:" << fineLevelIndex @@ -297,7 +296,7 @@ Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface } Pout<< "DONE agglomerating at level:" << fineLevelIndex << endl; - UPstream::warnComm = oldWarnComm; + UPstream::commWarn(oldWarnComm); } } } @@ -820,8 +819,7 @@ Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface { const auto& AMI = amiPtr_(); - const auto oldWarnComm = UPstream::warnComm; - UPstream::warnComm = AMI.comm(); + const auto oldWarnComm = UPstream::commWarn(AMI.comm()); const label myRank = UPstream::myProcNo(AMI.comm()); Pout<< "PROCAGGLOMERATED :" @@ -930,7 +928,7 @@ Foam::cyclicAMIGAMGInterface::cyclicAMIGAMGInterface } } Pout<< "DONE PROCAGGLOMERATED" << endl; - UPstream::warnComm = oldWarnComm; + UPstream::commWarn(oldWarnComm); } } } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/nullSpace/nullSpace.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/nullSpace/nullSpace.C index 82a4207ab008d1d6555d487c06be57977a290cce..6348b76a62b5ac43ef00d1fa7c6fbab4a0497481 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/nullSpace/nullSpace.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/nullSpace/nullSpace.C @@ -1030,7 +1030,7 @@ Foam::nullSpace::nullSpace } if (globalSum_) { - reduce(existsNonBoundVar, orOp<bool>()); + UPstream::reduceOr(existsNonBoundVar); } if (!existsNonBoundVar) { 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 3ad91b1aafbc632b66f93c9f2a6dbddeefe13426..e467948c4a63f46a6787106ec709e87da6861590 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C @@ -476,7 +476,7 @@ void Foam::NURBS3DVolume::confineInertControlPoints() break; } } - reduce(foundParamPt, orOp<bool>()); + UPstream::reduceOr(foundParamPt); if (!foundParamPt) { activeControlPoints_[cpI] = false; diff --git a/src/overset/cellCellStencil/cellCellStencil/cellCellStencil.C b/src/overset/cellCellStencil/cellCellStencil/cellCellStencil.C index ff12dadc36e4fc0aff8aee2e5c17eaa9c949dbc3..f5f3522932dfc8f02c3237b89d3579a7e8141ad4 100644 --- a/src/overset/cellCellStencil/cellCellStencil/cellCellStencil.C +++ b/src/overset/cellCellStencil/cellCellStencil/cellCellStencil.C @@ -498,7 +498,7 @@ void Foam::cellCellStencil::walkFront bitSet isFrontWork(isFront); label nCurrLayer = currLayer; - while (nCurrLayer > 1 && returnReduce(isFrontWork.any(), orOp<bool>())) + while (nCurrLayer > 1 && returnReduceOr(isFrontWork.any())) { bitSet newIsFront(mesh_.nFaces()); forAll(isFrontWork, facei) @@ -575,7 +575,7 @@ void Foam::cellCellStencil::walkFront scalarField allWeightWork(allCellTypes.size(), Zero); bitSet nHoles(allCellTypes.size()); - while (returnReduce(isFront.any(), orOp<bool>())) + while (returnReduceOr(isFront.any())) { // Interpolate cells on front bitSet newIsFront(mesh_.nFaces());