openfoam/applications/test/minMax1/Test-minMax1.C
Mark Olesen ba153df8db 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.
2023-01-23 14:52:29 +01:00

297 lines
7.9 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Test minMax
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "Time.H"
#include "BitOps.H"
#include "HashOps.H"
#include "ListOps.H"
#include "scalarField.H"
#include "complexField.H"
#include "MinMax.H"
#include "dimensionedScalar.H"
using namespace Foam;
template<class T>
Ostream& printInfo(const MinMax<T>& range)
{
Info<< range << " good=" << range.good() << " span=" << range.span();
return Info;
}
template<class T>
void testUniformField(const T& val)
{
constexpr label N = 10;
// Field<T> fld(N, val);
List<T> fld(N, val);
Info<< "field: " << fld << nl
<< "min/max: " << minMaxMag(fld) << nl;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Main program:
int main(int argc, char *argv[])
{
argList::noCheckProcessorDirectories();
#include "setRootCase.H"
Info<< "Test min/max " << nl;
Info<<"Construct null: ";
printInfo(MinMax<scalar>()) << nl;
Info<<"Construct single value : ";
printInfo(MinMax<scalar>(15)) << nl;
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;
Info<<"A 0-1 scalar range : ";
printInfo(scalarMinMax::zero_one()) << nl;
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);
scalarMinMax range2(40, 50);
Info<< range1 << " + " << range2 << " = " << (range1 + range2) <<nl;
}
{
Info<<"Dimensioned range : "
<< dimensioned<scalarMinMax>("velrange", dimVelocity, {1, 20})
<< nl;
dimensioned<scalarMinMax> range1("a", dimVelocity, {10, 20});
dimensioned<scalarMinMax> range2("b", dimVelocity, {40, 50});
Info<<"Dimensioned range : " << (range1 + range2) << endl;
}
Info<<"Centre value for (10 250) = "
<< scalarMinMax(10, 250).centre() << nl;
{
Info<<"compare - similar definition as per std::string compare" << nl;
string str1("abc");
Info<< "For string=" << str1 << nl
<< " compare(\"aaa\") = " << str1.compare("aaa") << nl
<< " compare(\"abz\") = " << str1.compare("abz") << nl;
MinMax<scalar> range(10, 20);
Info<< "For range=" << range << nl
<< " compare(5) = " << range.compare(5) << nl
<< " compare(15) = " << range.compare(15) << nl
<< " compare(25) = " << range.compare(25) << nl;
Info<< "Binary comparisons" << nl;
Info<< "(5 < range) = " << (5 < range) << nl
<< "(25 > range) = " << (25 >= range) << nl
<< "(12 <= range) = " << (12 <= range) << nl
<< "(12 >= range) = " << (12 >= range) << nl;
}
scalarField values1
(
List<scalar>({3, 10, -11, 85, 300})
);
values1 *= (Pstream::myProcNo()+1);
Pout<<"min-max of " << flatOutput(values1) << " = "
<< minMax(values1) << endl;
// Construct from values
MinMax<scalar> minmax1(values1);
printInfo(minmax1) << nl;
// Reset and add values
minmax1.clear();
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;
vectorField values1v
(
ListOps::create<vector>
(
values1,
[](const scalar s) { return vector(s, 2*s, -2*s); }
)
);
Info<< "gMinMax: " << gMinMax(values1v) << nl;
Info<< "gMinMaxMag: " << gMinMaxMag(values1v) << nl;
{
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
<< "values : " << flatOutput(values1) << nl;
Info<< "Subset mask: "
<< ListOps::create<bool, scalar>(values1, limiter)
<< nl;
Info<< "Subset = " << subsetList(values1, limiter) << nl;
Info<< "Subset = "
<< IndirectList<scalar>::subset_if(values1, limiter) << nl;
Info<< nl << "test clip() with limiter: " << limiter << nl;
for (const scalar& val : values1)
{
Info<< "clipped : " << val << " = "
<< clip(val, limiter)
<< " or " << clip(val, limiter)
<< " or " << clipper(val) << nl;
}
Info<< nl << "test clip(Field) with limiter: " << limiter << nl;
Info<< "clipped : " << clip(values1, limiter) << nl;
scalarField values2(values1);
Info<< nl << "inplace clip" << nl;
Info<< "before " << flatOutput(values2) << nl;
// Too much clutter
// for (scalar& val : values2)
// {
// clampEqOp<scalar>{limiter}(val);
// }
for (scalar& val : values2)
{
val = clipper(val);
}
Info<< "after: " << flatOutput(values2) << nl;
Info<< nl << "For list: " << flatOutput(values1) << nl
<< " minMax : " << minMax(values1) << nl
<< " minMaxMag : " << minMaxMag(values1)
<< " = " << mag(minMaxMag(vector(1, 2, 3)))
<< nl;
}
// Hashed values and reduction
{
HashTable<scalarMinMax> hashed;
hashed.insert("zero", scalarMinMax(Zero));
hashed("null");
hashed("U") += values1;
Pout<< "hashed: " << hashed << nl;
Pstream::mapCombineReduce(hashed, plusEqOp<scalarMinMax>());
Info<< "reduced: " << hashed << nl;
// Prune invalid
hashed.filterValues(emptyOp<scalarMinMax>(), true);
Info<< "filtered: " << hashed << nl;
}
// Min/max of uniform fields
{
testUniformField<scalar>(100);
// testUniformField<complex>(complex(100, 0));
}
Info<< "\nEnd\n" << nl;
return 0;
}
// ************************************************************************* //