From 0aecb25024dee5d12bd4a7e6d6a059736fae7a4f Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Thu, 20 Feb 2025 13:54:40 +0100 Subject: [PATCH] ENH: update MinMax to accept multiple values for add() - now also provide its own member data (previously inherited from Tuple2) to provide better isolation from future changes --- applications/test/minMax1/Test-minMax1.cxx | 15 ++- applications/test/minMax2/Make/files | 2 +- .../{Test-minMax2.C => Test-minMax2.cxx} | 0 .../primitives/ranges/MinMax/MinMax.H | 87 +++++++++----- .../primitives/ranges/MinMax/MinMaxI.H | 108 ++++++++++-------- .../primitives/ranges/MinMax/MinMaxOps.H | 38 ++---- .../binModels/uniformBin/uniformBin.C | 8 +- 7 files changed, 147 insertions(+), 111 deletions(-) rename applications/test/minMax2/{Test-minMax2.C => Test-minMax2.cxx} (100%) diff --git a/applications/test/minMax1/Test-minMax1.cxx b/applications/test/minMax1/Test-minMax1.cxx index 327ca27dc6..d30b4ed18d 100644 --- a/applications/test/minMax1/Test-minMax1.cxx +++ b/applications/test/minMax1/Test-minMax1.cxx @@ -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 minmax1(values1); diff --git a/applications/test/minMax2/Make/files b/applications/test/minMax2/Make/files index 08cdfd9751..2aae0fe309 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/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H b/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H index abe625765d..7d07427bd4 100644 --- a/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H +++ b/src/OpenFOAM/primitives/ranges/MinMax/MinMax.H @@ -110,9 +110,15 @@ typedef MinMax scalarMinMax; //!< A scalar min/max range template class MinMax -: - public Tuple2 { + // 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& range); - //- Copy construct from components + //- Implicit construct from min/max limits inline MinMax(const Pair& range); + //- Implicit construct from min/max limits + inline MinMax(const Tuple2& 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& add(const UList& vals); + //- Include two or more values into the range. + // All values must be similar types + template + inline MinMax& add(const T& val0, const T& val1, Args&&... values); + // Member Operators @@ -264,19 +275,19 @@ public: inline MinMax& operator+=(const UList& vals); //- Multiply range by scalar factor - inline MinMax& operator*=(const scalar& s); + inline MinMax& operator*=(scalar s); //- Divide range by scalar factor - inline MinMax& operator/=(const scalar& s); + inline MinMax& 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); } }; @@ -299,6 +310,30 @@ word name(const MinMax& range) return '(' + Foam::name(range.min()) + ',' + Foam::name(range.max()) + ')'; } +// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // + +//- Read min/max range as (min max) tuple from Istream +template +inline Istream& operator>>(Istream& is, MinMax& 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 +inline Ostream& operator<<(Ostream& os, const MinMax& 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 444c685320..61b274a8e0 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 Foam::MinMax::zero_one() template inline Foam::MinMax::MinMax() : - Tuple2(pTraits::max, pTraits::min) + // An inverted range + min_(pTraits::max), + max_(pTraits::min) {} template inline Foam::MinMax::MinMax(const T& minVal, const T& maxVal) : - Tuple2(minVal, maxVal) + min_(minVal), + max_(maxVal) {} template inline Foam::MinMax::MinMax(const std::pair& range) : - Tuple2(range.first, range.second) + min_(range.first), + max_(range.second) {} template inline Foam::MinMax::MinMax(const Pair& range) : - Tuple2(range.first(), range.second()) + min_(range.first()), + max_(range.second()) {} template -inline Foam::MinMax::MinMax(const Foam::zero) +inline Foam::MinMax::MinMax(const Tuple2& range) : - Tuple2(pTraits::zero, pTraits::zero) + min_(range.first()), + max_(range.second()) {} template -inline Foam::MinMax::MinMax(const Foam::zero_one) +inline Foam::MinMax::MinMax(Foam::zero) : - Tuple2(pTraits::zero, pTraits::one) + min_(pTraits::zero), + max_(pTraits::zero) +{} + + +template +inline Foam::MinMax::MinMax(Foam::zero_one) +: + min_(pTraits::zero), + max_(pTraits::one) {} template inline Foam::MinMax::MinMax(const T& val) : - Tuple2(val, val) + min_(val), + max_(val) {} @@ -110,34 +126,6 @@ inline Foam::MinMax::MinMax(const UList& vals) // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -template -inline const T& Foam::MinMax::min() const noexcept -{ - return this->first(); -} - - -template -inline T& Foam::MinMax::min() noexcept -{ - return this->first(); -} - - -template -inline const T& Foam::MinMax::max() const noexcept -{ - return this->second(); -} - - -template -inline T& Foam::MinMax::max() noexcept -{ - return this->second(); -} - - template inline T Foam::MinMax::centre() const { @@ -156,7 +144,7 @@ inline T Foam::MinMax::span() const template inline Foam::scalar Foam::MinMax::mag() const { - return ::Foam::mag(span()); + return (empty() ? scalar(0) : ::Foam::mag(max() - min())); } @@ -171,31 +159,32 @@ inline bool Foam::MinMax::empty() const template inline bool Foam::MinMax::good() const { - return !empty(); + return !(max() < min()); } template inline void Foam::MinMax::reset() { - min() = pTraits::max; - max() = pTraits::min; + // An inverted range + min_ = pTraits::max; + max_ = pTraits::min; } template inline void Foam::MinMax::reset(const T& val) { - min() = val; - max() = val; + min_ = val; + max_ = val; } template inline void Foam::MinMax::reset(const T& minVal, const T& maxVal) { - min() = minVal; - max() = maxVal; + min_ = minVal; + max_ = maxVal; } @@ -246,6 +235,7 @@ inline T Foam::MinMax::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::clamp(const T& val) const template inline Foam::MinMax& Foam::MinMax::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& Foam::MinMax::add(const MinMax& other) template inline Foam::MinMax& Foam::MinMax::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& Foam::MinMax::add(const UList& vals) } +template +template +inline Foam::MinMax& Foam::MinMax::add +( + const T& val0, + const T& val1, + Args&&... values +) +{ + add(val0); + add(val1); + + // Add multiple values via fold expression + ((*this += std::forward(values)), ...); + + return *this; +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template @@ -325,6 +336,7 @@ inline bool Foam::MinMax::operator()(const T& val) const template inline Foam::MinMax& Foam::MinMax::operator&=(const MinMax& 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& Foam::MinMax::operator+=(const UList& vals) template -inline Foam::MinMax& Foam::MinMax::operator*=(const scalar& s) +inline Foam::MinMax& Foam::MinMax::operator*=(scalar s) { min() *= s; max() *= s; @@ -363,7 +375,7 @@ inline Foam::MinMax& Foam::MinMax::operator*=(const scalar& s) template -inline Foam::MinMax& Foam::MinMax::operator/=(const scalar& s) +inline Foam::MinMax& Foam::MinMax::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 70ea46674b..71e3632bfc 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 @@ -156,7 +156,7 @@ inline scalarMinMax minMaxMag(const UList& vals) scalarMinMax result; for (const T& val : vals) { - result += Foam::mag(val); + result.add(Foam::mag(val)); } return result; @@ -174,38 +174,20 @@ inline scalarMinMax minMaxMag(const MinMax& range) } -//- Combine the magitude of two values to create a min/max range. -//- Order is unimportant. -template -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 +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 -inline scalarMinMax minMaxMag(const MinMax& x, const MinMax& 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 inline scalarMinMax minMaxMag(const MinMax& x, const MinMax& 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())); } @@ -309,7 +291,7 @@ inline MinMax operator+(const MinMax& x, const MinMax& y) //- Multiply range by scalar factor template -inline MinMax operator*(const MinMax& x, const scalar& s) +inline MinMax operator*(const MinMax& x, scalar s) { return MinMax(x.min()*s, x.max()*s); } @@ -317,7 +299,7 @@ inline MinMax operator*(const MinMax& x, const scalar& s) //- Divide range by scalar factor template -inline MinMax operator/(const MinMax& x, const scalar& s) +inline MinMax operator/(const MinMax& x, scalar s) { return MinMax(x.min()/s, x.max()/s); } diff --git a/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C b/src/functionObjects/field/binField/binModels/uniformBin/uniformBin.C index dc122d4236..65f9a19643 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 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 limits(pts); - - geomLimits.add(limits.min()); - geomLimits.add(limits.max()); + geomLimits.add(limits.min(), limits.max()); } // Globally consistent