ENH: improved handling for clamping
- proper component-wise clamping for MinMax clamp(). - construct clampOp from components - propagate clamp() method from GeometricField to FieldField and Field - clamp_min() and clamp_max() for one-sided clamping, as explicit alternative to min/max free functions which can be less intuitive and often involve additional field copies. - top-level checks to skip applying invalid min/max ranges and bypass the internal checks of MinMax::clamp() etc.
This commit is contained in:
parent
3888bfa17f
commit
ba153df8db
@ -110,8 +110,7 @@ unsigned checkDimensions
|
||||
|
||||
try
|
||||
{
|
||||
// min(a, b);
|
||||
clip(a, b);
|
||||
min(a, b);
|
||||
dimsOk = true;
|
||||
}
|
||||
catch (const Foam::error& err)
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -83,6 +83,9 @@ int main(int argc, char *argv[])
|
||||
Info<<"Construct zero : ";
|
||||
printInfo(MinMax<scalar>(Zero)) << nl;
|
||||
|
||||
Info<<"Construct zero_one : ";
|
||||
printInfo(MinMax<scalar>(zero_one{})) << nl;
|
||||
|
||||
Info<<"Construct range : ";
|
||||
printInfo(MinMax<scalar>(1, 20)) << nl;
|
||||
|
||||
@ -92,6 +95,26 @@ int main(int argc, char *argv[])
|
||||
Info<<"A 0-1 vector range : ";
|
||||
printInfo(MinMax<vector>::zero_one()) << nl;
|
||||
|
||||
{
|
||||
vector a(0, 1, 20);
|
||||
vector b(2, 1, 0);
|
||||
vector c(4, 10, 12);
|
||||
|
||||
Info<< "vectors:"
|
||||
<< " a = " << a
|
||||
<< " b = " << b
|
||||
<< " c = " << c << nl;
|
||||
|
||||
Info<< "min max = " << min(max(a, b), c) << nl;
|
||||
Info<< "range clamp= " << MinMax<vector>(b, c).clamp(a) << nl;
|
||||
Info<< "clamp = " << clamp(a, b, c) << nl;
|
||||
|
||||
Info<< "clamp 0/1 = " << clamp(a, vector::zero, vector::one) << nl;
|
||||
}
|
||||
|
||||
// Scalar promotion
|
||||
Info<< "clamp (scalar) = " << clamp(15.0, -1, 1) << nl;
|
||||
|
||||
|
||||
{
|
||||
scalarMinMax range1(10, 20);
|
||||
@ -180,6 +203,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
{
|
||||
MinMax<scalar> limiter(10, 200);
|
||||
clampOp<scalar> clipper(limiter);
|
||||
// clampOp<scalar> clipper(zero_one{});
|
||||
// clampOp<scalar> clipper(10, 200);
|
||||
|
||||
Info<< nl
|
||||
<< "Test clipping limiter: " << limiter << nl
|
||||
@ -196,7 +222,10 @@ int main(int argc, char *argv[])
|
||||
Info<< nl << "test clip() with limiter: " << limiter << nl;
|
||||
for (const scalar& val : values1)
|
||||
{
|
||||
Info<< "clipped : " << val << " = " << clip(val, limiter) << nl;
|
||||
Info<< "clipped : " << val << " = "
|
||||
<< clip(val, limiter)
|
||||
<< " or " << clip(val, limiter)
|
||||
<< " or " << clipper(val) << nl;
|
||||
}
|
||||
|
||||
Info<< nl << "test clip(Field) with limiter: " << limiter << nl;
|
||||
@ -208,9 +237,15 @@ int main(int argc, char *argv[])
|
||||
|
||||
Info<< "before " << flatOutput(values2) << nl;
|
||||
|
||||
// Too much clutter
|
||||
// for (scalar& val : values2)
|
||||
// {
|
||||
// clampEqOp<scalar>{limiter}(val);
|
||||
// }
|
||||
|
||||
for (scalar& val : values2)
|
||||
{
|
||||
clipEqOp<scalar>()(val, limiter);
|
||||
val = clipper(val);
|
||||
}
|
||||
|
||||
Info<< "after: " << flatOutput(values2) << nl;
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -24,7 +24,7 @@ License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Description
|
||||
Test minMax
|
||||
Test-minMax2
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -37,6 +37,7 @@ Description
|
||||
#include "MinMax.H"
|
||||
#include "dimensionedScalar.H"
|
||||
#include "dimensionedMinMax.H"
|
||||
#include "Random.H"
|
||||
|
||||
using namespace Foam;
|
||||
|
||||
@ -78,7 +79,6 @@ int main(int argc, char *argv[])
|
||||
|
||||
Info<< "Test min/max " << nl;
|
||||
|
||||
|
||||
{
|
||||
scalarMinMax range1(10, 20);
|
||||
scalarMinMax range2(40, 50);
|
||||
@ -140,7 +140,34 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
scalarField someField(25);
|
||||
|
||||
Random rnd(4567);
|
||||
for (scalar& val : someField)
|
||||
{
|
||||
val = rnd.position(-0.2, 1.2);
|
||||
}
|
||||
|
||||
Info<< nl
|
||||
<< "field: " << flatOutput(someField) << nl;
|
||||
Info<< "clamp01: "
|
||||
<< flatOutput(clamp(someField, scalarMinMax(zero_one{}))()) << nl;
|
||||
|
||||
Info<< "clamp01: "
|
||||
<< clamp(tmp<scalarField>(someField), scalarMinMax(zero_one{}))<< nl;
|
||||
|
||||
scalarField result(10);
|
||||
clamp(result, someField, scalarMinMax(zero_one{}));
|
||||
|
||||
Info<< "result: " << result << nl;
|
||||
|
||||
someField.clamp(zero_one{});
|
||||
|
||||
Info<< "inplace: " << someField << nl;
|
||||
}
|
||||
|
||||
Info<< nl << "\nDone\n" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1279,7 +1279,7 @@ void write_scalarField
|
||||
continue;
|
||||
}
|
||||
|
||||
os << limits.clip(fld(cellIdx)) << nl;
|
||||
os << limits.clamp(fld(cellIdx)) << nl;
|
||||
}
|
||||
|
||||
os << token::END_LIST << token::END_STATEMENT << nl;
|
||||
|
@ -58,12 +58,11 @@ namespace Foam
|
||||
{
|
||||
|
||||
// Read porosity, change to blockage. Clamp values [0-1] silently
|
||||
static const scalarMinMax limits01(scalarMinMax::zero_one());
|
||||
|
||||
// Volume porosity -> blockage
|
||||
inline scalar getPorosity(const dictionary& dict)
|
||||
{
|
||||
return 1 - limits01.clip(dict.getOrDefault<scalar>("porosity", 0));
|
||||
return 1 - clamp(dict.getOrDefault<scalar>("porosity", 0), 0, 1);
|
||||
}
|
||||
|
||||
// Direction porosities -> blockage
|
||||
@ -75,7 +74,7 @@ inline vector getPorosities(const dictionary& dict)
|
||||
{
|
||||
for (scalar& val : blockage)
|
||||
{
|
||||
val = 1 - limits01.clip(val);
|
||||
val = 1 - clamp(val, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,36 +253,38 @@ bool Foam::dimensionSet::operator/=(const dimensionSet& ds)
|
||||
|
||||
// * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::dimensionSet Foam::min(const dimensionSet& ds1, const dimensionSet& ds2)
|
||||
Foam::dimensionSet Foam::min(const dimensionSet& a, const dimensionSet& b)
|
||||
{
|
||||
if (dimensionSet::checking())
|
||||
{
|
||||
checkDims("min(a, b)", ds1, ds2);
|
||||
checkDims("min(a, b)", a, b);
|
||||
}
|
||||
|
||||
return ds1;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Foam::dimensionSet Foam::max(const dimensionSet& ds1, const dimensionSet& ds2)
|
||||
Foam::dimensionSet Foam::max(const dimensionSet& a, const dimensionSet& b)
|
||||
{
|
||||
if (dimensionSet::checking())
|
||||
{
|
||||
checkDims("max(a, b)", ds1, ds2);
|
||||
checkDims("max(a, b)", a, b);
|
||||
}
|
||||
|
||||
return ds1;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Foam::dimensionSet Foam::clip(const dimensionSet& ds1, const dimensionSet& ds2)
|
||||
Foam::dimensionSet Foam::clamp(const dimensionSet& a, const dimensionSet& range)
|
||||
{
|
||||
if (dimensionSet::checking())
|
||||
// In may cases the min/max range will be created from raw values
|
||||
// (no dimension) so accept those without error
|
||||
if (dimensionSet::checking() && !range.dimensionless())
|
||||
{
|
||||
checkDims("clip(a, b)", ds1, ds2);
|
||||
checkDims("clamp(a, b)", a, range);
|
||||
}
|
||||
|
||||
return ds1;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2017-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2017-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -354,9 +354,9 @@ Ostream& operator<<(Ostream& os, const dimensionSet& ds);
|
||||
|
||||
// Global Functions
|
||||
|
||||
dimensionSet min(const dimensionSet& ds1, const dimensionSet& ds2);
|
||||
dimensionSet max(const dimensionSet& ds1, const dimensionSet& ds2);
|
||||
dimensionSet clip(const dimensionSet& ds1, const dimensionSet& ds2);
|
||||
dimensionSet min(const dimensionSet& a, const dimensionSet& b);
|
||||
dimensionSet max(const dimensionSet& a, const dimensionSet& b);
|
||||
dimensionSet clamp(const dimensionSet& a, const dimensionSet& range);
|
||||
|
||||
dimensionSet cmptMultiply(const dimensionSet& ds1, const dimensionSet& ds2);
|
||||
dimensionSet cmptDivide(const dimensionSet& ds1, const dimensionSet& ds2);
|
||||
|
@ -421,6 +421,8 @@ public:
|
||||
const tmp<DimensionedField<cmptType, GeoMesh>>& tdf
|
||||
);
|
||||
|
||||
// Inherits clamp, clamp_min, clamp_max (without dimensions) from Field
|
||||
|
||||
//- Return the field transpose (only defined for second rank tensors)
|
||||
tmp<DimensionedField<Type, GeoMesh>> T() const;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2019-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -282,6 +282,65 @@ void FieldField<Field, Type>::replace
|
||||
}
|
||||
|
||||
|
||||
template<template<class> class Field, class Type>
|
||||
void FieldField<Field, Type>::clamp
|
||||
(
|
||||
const Type& lower,
|
||||
const Type& upper
|
||||
)
|
||||
{
|
||||
if (lower < upper)
|
||||
{
|
||||
for (auto& ff : *this)
|
||||
{
|
||||
ff.clamp(lower, upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<template<class> class Field, class Type>
|
||||
void FieldField<Field, Type>::clamp
|
||||
(
|
||||
const MinMax<Type>& range
|
||||
)
|
||||
{
|
||||
if (range.min() < range.max())
|
||||
{
|
||||
for (auto& ff : *this)
|
||||
{
|
||||
ff.clamp(range.min(), range.max());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<template<class> class Field, class Type>
|
||||
void FieldField<Field, Type>::clamp_min
|
||||
(
|
||||
const Type& lower
|
||||
)
|
||||
{
|
||||
for (auto& ff : *this)
|
||||
{
|
||||
ff.clamp_min(lower);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<template<class> class Field, class Type>
|
||||
void FieldField<Field, Type>::clamp_max
|
||||
(
|
||||
const Type& upper
|
||||
)
|
||||
{
|
||||
for (auto& ff : *this)
|
||||
{
|
||||
ff.clamp_max(upper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<template<class> class Field, class Type>
|
||||
tmp<FieldField<Field, Type>> FieldField<Field, Type>::T() const
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2022 OpenCFD Ltd.
|
||||
Copyright (C) 2022-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -149,6 +149,20 @@ public:
|
||||
//- Replace a component field of the field
|
||||
void replace(const direction, const cmptType&);
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const Type& lower, const Type& upper);
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const MinMax<Type>& range);
|
||||
|
||||
//- Impose lower (floor) clamp on the field values (in-place)
|
||||
void clamp_min(const Type& lower);
|
||||
|
||||
//- Impose upper (ceiling) clamp on the field values (in-place)
|
||||
void clamp_max(const Type& upper);
|
||||
|
||||
//- Return the field transpose (only defined for second rank tensors)
|
||||
tmp<FieldField<Field, Type>> T() const;
|
||||
|
||||
|
@ -673,7 +673,7 @@ BINARY_TYPE_FUNCTION(Type, Type, Type, min)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptMultiply)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptDivide)
|
||||
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip)
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clamp)
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * Global operators * * * * * * * * * * * * * */
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2019 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -287,7 +287,7 @@ BINARY_TYPE_FUNCTION(Type, Type, Type, min)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptMultiply)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptDivide)
|
||||
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip)
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clamp)
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * Global operators * * * * * * * * * * * * * */
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -625,6 +625,50 @@ void Foam::Field<Type>::replace
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::Field<Type>::clamp(const Type& lower, const Type& upper)
|
||||
{
|
||||
// Use free functions min(), max() to impose component-wise clamping
|
||||
if (lower < upper)
|
||||
{
|
||||
// std::for_each
|
||||
for (auto& val : *this)
|
||||
{
|
||||
val = min(max(val, lower), upper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
void Foam::Field<Type>::clamp(const MinMax<Type>& range)
|
||||
{
|
||||
clamp(range.min(), range.max());
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
void Foam::Field<Type>::clamp_min(const Type& lower)
|
||||
{
|
||||
// Use free function max() [sic] to impose component-wise clamp_min
|
||||
// std::for_each
|
||||
for (auto& val : *this)
|
||||
{
|
||||
val = max(val, lower);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
void Foam::Field<Type>::clamp_max(const Type& upper)
|
||||
{
|
||||
// Use free function min() [sic] to impose component-wise clamp_max
|
||||
// std::for_each
|
||||
for (auto& val : *this)
|
||||
{
|
||||
val = min(val, upper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
template<class VSForm>
|
||||
VSForm Foam::Field<Type>::block(const label start) const
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -415,6 +415,20 @@ public:
|
||||
//- Replace a component field of the field
|
||||
void replace(const direction, const cmptType&);
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const Type& lower, const Type& upper);
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const MinMax<Type>& range);
|
||||
|
||||
//- Impose lower (floor) clamp on the field values (in-place)
|
||||
void clamp_min(const Type& lower);
|
||||
|
||||
//- Impose upper (ceiling) clamp on the field values (in-place)
|
||||
void clamp_max(const Type& upper);
|
||||
|
||||
template<class VSForm>
|
||||
VSForm block(const label start) const;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2019 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -656,6 +656,64 @@ TMP_UNARY_FUNCTION(Type, gAverage)
|
||||
|
||||
#undef TMP_UNARY_FUNCTION
|
||||
|
||||
template<class Type>
|
||||
void clamp
|
||||
(
|
||||
Field<Type>& result,
|
||||
const UList<Type>& f1,
|
||||
const MinMax<Type>& range
|
||||
)
|
||||
{
|
||||
if (result.cdata() == f1.cdata())
|
||||
{
|
||||
// Apply in-place
|
||||
result.clamp(range);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (range.good())
|
||||
{
|
||||
std::transform
|
||||
(
|
||||
f1.cbegin(),
|
||||
f1.cbegin(result.size()),
|
||||
result.begin(),
|
||||
clampOp<Type>(range)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No clamping
|
||||
std::copy(f1.cbegin(), f1.cbegin(result.size()), result.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
tmp<Field<Type>> clamp
|
||||
(
|
||||
const UList<Type>& f1,
|
||||
const MinMax<Type>& range
|
||||
)
|
||||
{
|
||||
auto tres = tmp<Field<Type>>::New(f1.size());
|
||||
clamp(tres.ref(), f1, range);
|
||||
return tres;
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
tmp<Field<Type>> clamp
|
||||
(
|
||||
const tmp<Field<Type>>& tf1,
|
||||
const MinMax<Type>& range
|
||||
)
|
||||
{
|
||||
auto tres = reuseTmp<Type, Type>::New(tf1);
|
||||
clamp(tres.ref(), tf1(), range);
|
||||
tf1.clear();
|
||||
return tres;
|
||||
}
|
||||
|
||||
|
||||
BINARY_FUNCTION(Type, Type, Type, max)
|
||||
BINARY_FUNCTION(Type, Type, Type, min)
|
||||
@ -667,10 +725,10 @@ BINARY_TYPE_FUNCTION(Type, Type, Type, min)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptMultiply)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptDivide)
|
||||
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip)
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip) // Same as clamp
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * Global operators * * * * * * * * * * * * * */
|
||||
/* * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * */
|
||||
|
||||
UNARY_OPERATOR(Type, Type, -, negate)
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2019 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -313,10 +313,11 @@ BINARY_TYPE_FUNCTION(Type, Type, Type, min)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptMultiply)
|
||||
BINARY_TYPE_FUNCTION(Type, Type, Type, cmptDivide)
|
||||
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip)
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clamp)
|
||||
BINARY_TYPE_FUNCTION_FS(Type, Type, MinMax<Type>, clip) // Same as clamp
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Global operators * * * * * * * * * * * * * //
|
||||
// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
|
||||
|
||||
UNARY_OPERATOR(Type, Type, -, negate)
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -1250,60 +1250,88 @@ void Foam::GeometricField<Type, PatchField, GeoMesh>::replace
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::min
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp
|
||||
(
|
||||
const dimensioned<Type>& dt
|
||||
const Type& lower,
|
||||
const Type& upper
|
||||
)
|
||||
{
|
||||
Foam::min(primitiveFieldRef(), primitiveField(), dt.value());
|
||||
Foam::min(boundaryFieldRef(), boundaryField(), dt.value());
|
||||
primitiveFieldRef().clamp(lower, upper);
|
||||
boundaryFieldRef().clamp(lower, upper);
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::max
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp
|
||||
(
|
||||
const dimensioned<Type>& dt
|
||||
const MinMax<Type>& range
|
||||
)
|
||||
{
|
||||
Foam::max(primitiveFieldRef(), primitiveField(), dt.value());
|
||||
Foam::max(boundaryFieldRef(), boundaryField(), dt.value());
|
||||
primitiveFieldRef().clamp(range.min(), range.max());
|
||||
boundaryFieldRef().clamp(range.min(), range.max());
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clip
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp
|
||||
(
|
||||
const dimensioned<Type>& lower,
|
||||
const dimensioned<Type>& upper
|
||||
)
|
||||
{
|
||||
this->clamp(lower.value(), upper.value());
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp
|
||||
(
|
||||
const dimensioned<MinMax<Type>>& range
|
||||
)
|
||||
{
|
||||
Foam::clip(primitiveFieldRef(), primitiveField(), range.value());
|
||||
Foam::clip(boundaryFieldRef(), boundaryField(), range.value());
|
||||
this->clamp(range.value());
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clip
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp_min
|
||||
(
|
||||
const dimensioned<Type>& minVal,
|
||||
const dimensioned<Type>& maxVal
|
||||
const Type& lower
|
||||
)
|
||||
{
|
||||
MinMax<Type> range(minVal.value(), maxVal.value());
|
||||
|
||||
Foam::clip(primitiveFieldRef(), primitiveField(), range);
|
||||
Foam::clip(boundaryFieldRef(), boundaryField(), range);
|
||||
primitiveFieldRef().clamp_min(lower);
|
||||
boundaryFieldRef().clamp_min(lower);
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::maxMin
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp_max
|
||||
(
|
||||
const dimensioned<Type>& minVal,
|
||||
const dimensioned<Type>& maxVal
|
||||
const Type& upper
|
||||
)
|
||||
{
|
||||
this->clip(minVal, maxVal);
|
||||
primitiveFieldRef().clamp_max(upper);
|
||||
boundaryFieldRef().clamp_max(upper);
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp_min
|
||||
(
|
||||
const dimensioned<Type>& lower
|
||||
)
|
||||
{
|
||||
this->clamp_min(lower.value());
|
||||
}
|
||||
|
||||
|
||||
template<class Type, template<class> class PatchField, class GeoMesh>
|
||||
void Foam::GeometricField<Type, PatchField, GeoMesh>::clamp_max
|
||||
(
|
||||
const dimensioned<Type>& upper
|
||||
)
|
||||
{
|
||||
this->clamp_max(upper.value());
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2017 OpenFOAM Foundation
|
||||
Copyright (C) 2015-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2015-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -134,7 +134,6 @@ private:
|
||||
//- Read the field - create the field dictionary on-the-fly
|
||||
void readFields();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
@ -630,32 +629,39 @@ public:
|
||||
const dimensioned<cmptType>& ds
|
||||
);
|
||||
|
||||
//- Use the minimum of the field and specified value
|
||||
// This sets the \em ceiling on the field values
|
||||
void min(const dimensioned<Type>& dt);
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const Type& lower, const Type& upper);
|
||||
|
||||
//- Use the maximum of the field and specified value
|
||||
// This sets the \em floor on the field values
|
||||
void max(const dimensioned<Type>& dt);
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range.
|
||||
void clamp(const MinMax<Type>& range);
|
||||
|
||||
//- Clip the field to be bounded within the specified range
|
||||
void clip(const dimensioned<MinMax<Type>>& range);
|
||||
|
||||
//- Clip the field to be bounded within the specified range
|
||||
void clip
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range. No dimension checking.
|
||||
void clamp
|
||||
(
|
||||
const dimensioned<Type>& minVal,
|
||||
const dimensioned<Type>& maxVal
|
||||
const dimensioned<Type>& lower,
|
||||
const dimensioned<Type>& upper
|
||||
);
|
||||
|
||||
//- Deprecated(2019-01) identical to clip()
|
||||
// \deprecated(2019-01) identical to clip()
|
||||
FOAM_DEPRECATED_FOR(2019-01, "clip() method")
|
||||
void maxMin
|
||||
(
|
||||
const dimensioned<Type>& minVal,
|
||||
const dimensioned<Type>& maxVal
|
||||
);
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// A no-op for an invalid range. No dimension checking.
|
||||
void clamp(const dimensioned<MinMax<Type>>& range);
|
||||
|
||||
//- Impose lower (floor) clamp on the field values (in-place)
|
||||
void clamp_min(const Type& lower);
|
||||
|
||||
//- Impose upper (ceiling) clamp on the field values (in-place)
|
||||
void clamp_max(const Type& upper);
|
||||
|
||||
//- Impose lower (floor) clamp on the field values (in-place)
|
||||
// No dimension checking
|
||||
void clamp_min(const dimensioned<Type>& lower);
|
||||
|
||||
//- Impose upper (ceiling) clamp on the field values (in-place)
|
||||
// No dimension checking
|
||||
void clamp_max(const dimensioned<Type>& upper);
|
||||
|
||||
|
||||
// Member Operators
|
||||
@ -691,7 +697,7 @@ public:
|
||||
void operator/=(const dimensioned<scalar>&);
|
||||
|
||||
|
||||
// Ostream operators
|
||||
// Ostream Operators
|
||||
|
||||
friend Ostream& operator<< <Type, PatchField, GeoMesh>
|
||||
(
|
||||
@ -704,6 +710,41 @@ public:
|
||||
Ostream&,
|
||||
const tmp<GeometricField<Type, PatchField, GeoMesh>>&
|
||||
);
|
||||
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// \deprecated(2023-01) prefer clamp() naming
|
||||
void clip(const dimensioned<MinMax<Type>>& range)
|
||||
{
|
||||
this->clamp(range);
|
||||
}
|
||||
|
||||
//- Clamp field values (in-place) to the specified range.
|
||||
// \deprecated(2023-01) prefer clamp() naming
|
||||
void clip(const dimensioned<Type>& lo, const dimensioned<Type>& hi)
|
||||
{
|
||||
this->clamp(lo.value(), hi.value());
|
||||
}
|
||||
|
||||
//- Use minimum of the field and specified value. ie, clamp_max().
|
||||
// This sets the \em ceiling on the field values
|
||||
// \deprecated(2023-01) prefer clamp_max()
|
||||
void min(const dimensioned<Type>& upper) { this->clamp_max(upper); }
|
||||
|
||||
//- Use maximum of the field and specified value. ie, clamp_min().
|
||||
// This sets the \em floor on the field values
|
||||
// \deprecated(2023-01) prefer clamp_min()
|
||||
void max(const dimensioned<Type>& lower) { this->clamp_min(lower); }
|
||||
|
||||
//- Deprecated(2019-01) identical to clamp()
|
||||
// \deprecated(2019-01) identical to clamp()
|
||||
FOAM_DEPRECATED_FOR(2019-01, "clamp() method")
|
||||
void maxMin(const dimensioned<Type>& lo, const dimensioned<Type>& hi)
|
||||
{
|
||||
return this->clamp(lo.value(), hi.value());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -294,6 +294,13 @@ inline bool notEqual(const Scalar a, const Scalar b)
|
||||
}
|
||||
|
||||
|
||||
// Fast implementation, and with scalar promotion of upper/lower limits
|
||||
inline Scalar clamp(const Scalar& val, const Scalar& lower, const Scalar& upper)
|
||||
{
|
||||
return (val < lower) ? lower : (upper < val) ? upper : val;
|
||||
}
|
||||
|
||||
|
||||
inline Scalar limit(const Scalar s1, const Scalar s2)
|
||||
{
|
||||
return (mag(s1) < mag(s2)) ? s1: 0.0;
|
||||
|
@ -141,6 +141,15 @@ inline bool equal(const T& a, const T& b)
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
//- Return value clamped between upper and lower limits.
|
||||
// Unlike the std::clamp, which selects between references, this version
|
||||
// wraps the min/max free functions for component-wise clamping
|
||||
template<class T>
|
||||
inline T clamp(const T& val, const T& lower, const T& upper)
|
||||
{
|
||||
return min(max(val, lower), upper);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Struct labelOp Declaration
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -67,30 +67,16 @@ Description
|
||||
Info<< "values values in range " << mask << nl;
|
||||
\endverbatim
|
||||
|
||||
One particular advantage offered by MinMax is to clip or limit values
|
||||
One advantage offered by MinMax is to clamp or limit values
|
||||
to a particular range. For example,
|
||||
\verbatim
|
||||
scalarMinMax range(lower, upper);
|
||||
|
||||
scalar val;
|
||||
val = range.clip(val) .. return clip values
|
||||
val = range.clamp(val) .. return clamped values
|
||||
|
||||
// vs.
|
||||
val = min(max(value, lower, upper))
|
||||
\endverbatim
|
||||
|
||||
Or when working on lists, the values can be limited in a single pass
|
||||
of the data without intermediate memory allocation.
|
||||
\verbatim
|
||||
scalarField values = ...;
|
||||
|
||||
for (scalar& val : values)
|
||||
{
|
||||
range.inplaceClip(val);
|
||||
}
|
||||
|
||||
// vs.
|
||||
values = min(max(values, lower, upper))
|
||||
val = min(max(value, lower), upper)
|
||||
\endverbatim
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
@ -112,6 +98,7 @@ namespace Foam
|
||||
// Forward Declarations
|
||||
template<class T> class MinMax;
|
||||
class zero;
|
||||
class zero_one;
|
||||
|
||||
// Common min/max types
|
||||
typedef MinMax<label> labelMinMax; //!< A label min/max range
|
||||
@ -155,6 +142,9 @@ public:
|
||||
//- Construct with a single zero value
|
||||
inline explicit MinMax(const Foam::zero);
|
||||
|
||||
//- Implicit construct from zero_one as 0-1 range (pTraits zero, one)
|
||||
inline MinMax(const Foam::zero_one);
|
||||
|
||||
//- Construct with a single initial value
|
||||
inline explicit MinMax(const T& val);
|
||||
|
||||
@ -239,14 +229,9 @@ public:
|
||||
//- True if the value is within the range (inclusive check)
|
||||
inline bool contains(const T& val) const;
|
||||
|
||||
//- If out of range, return the respective min/max limits, otherwise
|
||||
//- return the value itself.
|
||||
// If the range is invalid, always return the value.
|
||||
inline const T& clip(const T& val) const;
|
||||
|
||||
//- Inplace clip value by the min/max limits
|
||||
// \return True if clipping was applied.
|
||||
inline bool inplaceClip(T& val) const;
|
||||
//- Return value clamped component-wise.
|
||||
// If the range is invalid, just returns the value.
|
||||
inline T clamp(const T& val) const;
|
||||
|
||||
|
||||
// Manipulate
|
||||
@ -284,6 +269,15 @@ public:
|
||||
|
||||
//- Divide range by scalar factor
|
||||
inline MinMax<T>& operator/=(const scalar& s);
|
||||
|
||||
|
||||
// Housekeeping
|
||||
|
||||
//- 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); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2019-2022 OpenCFD Ltd.
|
||||
Copyright (C) 2019-2023 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -44,7 +44,7 @@ inline Foam::MinMax<T> Foam::MinMax<T>::le(const T& maxVal)
|
||||
template<class T>
|
||||
inline Foam::MinMax<T> Foam::MinMax<T>::zero_one()
|
||||
{
|
||||
return MinMax<T>(pTraits<T>::zero, pTraits<T>::one);
|
||||
return MinMax<T>(Foam::zero_one{});
|
||||
}
|
||||
|
||||
|
||||
@ -85,6 +85,13 @@ inline Foam::MinMax<T>::MinMax(const Foam::zero)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::MinMax<T>::MinMax(const Foam::zero_one)
|
||||
:
|
||||
Tuple2<T,T>(pTraits<T>::zero, pTraits<T>::one)
|
||||
{}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::MinMax<T>::MinMax(const T& val)
|
||||
:
|
||||
@ -235,45 +242,17 @@ inline bool Foam::MinMax<T>::contains(const T& val) const
|
||||
|
||||
|
||||
template<class T>
|
||||
inline const T& Foam::MinMax<T>::clip(const T& val) const
|
||||
inline T Foam::MinMax<T>::clamp(const T& val) const
|
||||
{
|
||||
if (good())
|
||||
{
|
||||
if (val < min())
|
||||
{
|
||||
return min();
|
||||
}
|
||||
else if (max() < val)
|
||||
{
|
||||
return max();
|
||||
}
|
||||
return Foam::min(Foam::max(val, min()), max());
|
||||
}
|
||||
|
||||
return val; // Pass-through
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline bool Foam::MinMax<T>::inplaceClip(T& val) const
|
||||
{
|
||||
if (good())
|
||||
{
|
||||
if (val < min())
|
||||
{
|
||||
val = min();
|
||||
return true;
|
||||
}
|
||||
else if (max() < val)
|
||||
{
|
||||
val = max();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // No change
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline Foam::MinMax<T>& Foam::MinMax<T>::add(const MinMax& other)
|
||||
{
|
||||
|
@ -54,35 +54,60 @@ inline scalar mag(const MinMax<T>& range)
|
||||
}
|
||||
|
||||
|
||||
//- Return the value after clipping by the min/max limiter
|
||||
//- Return the value after clamping by the min/max limiter
|
||||
template<class T>
|
||||
inline T clip(const T& val, const MinMax<T>& range)
|
||||
{
|
||||
return range.clip(val);
|
||||
return range.clamp(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//- Return the value after clipping by the min/max limiter
|
||||
//- Unary function for applying component-wise clamping
|
||||
template<class T>
|
||||
struct clipOp
|
||||
struct clampOp
|
||||
{
|
||||
T operator()(T& val, const MinMax<T>& range) const
|
||||
const T lower;
|
||||
const T upper;
|
||||
|
||||
//- Construct from min/max limits. No validity checks
|
||||
clampOp(const T& min, const T& max)
|
||||
:
|
||||
lower(min),
|
||||
upper(max)
|
||||
{}
|
||||
|
||||
//- Construct from min/max range. No validity checks
|
||||
clampOp(const MinMax<T>& range)
|
||||
:
|
||||
lower(range.min()),
|
||||
upper(range.max())
|
||||
{}
|
||||
|
||||
//- Construct as 0-1 min/max range
|
||||
clampOp(const Foam::zero_one)
|
||||
:
|
||||
clampOp(MinMax<T>(Foam::zero_one{}))
|
||||
{}
|
||||
|
||||
T operator()(const T& val) const
|
||||
{
|
||||
return range.clip(val);
|
||||
return min(max(val, lower), upper);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//- Clip value and assign inplace
|
||||
template<class T>
|
||||
struct clipEqOp
|
||||
{
|
||||
bool operator()(T& val, const MinMax<T>& range) const
|
||||
{
|
||||
return range.inplaceClip(val);
|
||||
}
|
||||
};
|
||||
/// Not really needed
|
||||
/// //- Unary function for applying component-wise clamping (inplace)
|
||||
/// template<class T>
|
||||
/// struct clampEqOp : public clampOp<T>
|
||||
/// {
|
||||
/// using clampOp<T>::clampOp;
|
||||
///
|
||||
/// void operator()(T& val) const
|
||||
/// {
|
||||
/// val = clampOp<T>::operator()(val);
|
||||
/// }
|
||||
/// };
|
||||
|
||||
|
||||
//- Extract the min/max range from a list of values.
|
||||
@ -156,14 +181,14 @@ struct minMaxEqOp
|
||||
};
|
||||
|
||||
|
||||
//- The magnitude of an initial single value.
|
||||
//- The magnitude of a single value.
|
||||
inline scalarMinMax minMaxMag(const scalar val)
|
||||
{
|
||||
return scalarMinMax(Foam::mag(val));
|
||||
}
|
||||
|
||||
|
||||
//- The magnitude of from an initial VectorSpace.
|
||||
//- The magnitude of a VectorSpace.
|
||||
template<class Form, class Cmpt, direction nCmpt>
|
||||
inline scalarMinMax minMaxMag(const VectorSpace<Form,Cmpt,nCmpt>& vs)
|
||||
{
|
||||
|
@ -257,7 +257,7 @@ void Foam::lumpedPointMovement::readDict(const dictionary& dict)
|
||||
}
|
||||
|
||||
relax_ = dict.getOrDefault<scalar>("relax", 1);
|
||||
scalarMinMax::zero_one().inplaceClip(relax_);
|
||||
relax_ = clamp(relax_, 0, 1);
|
||||
|
||||
forcesDict_.merge(dict.subOrEmptyDict("forces"));
|
||||
|
||||
|
@ -73,7 +73,7 @@ Foam::pointIndexHit Foam::searchableDisk::findNearest
|
||||
v.normalise();
|
||||
|
||||
// Clip to inner/outer radius
|
||||
info.setPoint(origin() + radialLimits_.clip(magV)*v);
|
||||
info.setPoint(origin() + radialLimits_.clamp(magV)*v);
|
||||
|
||||
if (info.point().distSqr(sample) < nearestDistSqr)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user