Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Development
openfoam
Commits
8a391b79
Commit
8a391b79
authored
Jan 14, 2019
by
Mark Olesen
Browse files
ENH: MinMax class for handling value ranges
parent
a174f13f
Changes
5
Hide whitespace changes
Inline
Side-by-side
applications/test/minMax1/Make/files
0 → 100644
View file @
8a391b79
Test-minMax1.C
EXE = $(FOAM_USER_APPBIN)/Test-minMax1
applications/test/minMax1/Make/options
0 → 100644
View file @
8a391b79
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools
applications/test/minMax1/Test-minMax1.C
0 → 100644
View file @
8a391b79
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "MinMax.H"
#include "dimensionedScalar.H"
using
namespace
Foam
;
template
<
class
T
>
Ostream
&
printInfo
(
const
MinMax
<
T
>&
range
)
{
Info
<<
range
<<
" valid="
<<
range
.
valid
();
return
Info
;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// 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 range : "
;
printInfo
(
MinMax
<
scalar
>
(
1
,
20
))
<<
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
;
{
MinMax
<
scalar
>
limiter
(
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
<<
nl
<<
"test clip() with limiter: "
<<
limiter
<<
nl
;
for
(
const
scalar
&
val
:
values1
)
{
Info
<<
"clipped : "
<<
val
<<
" = "
<<
clip
(
val
,
limiter
)
<<
nl
;
}
Info
<<
nl
<<
"inplace clip"
<<
nl
;
scalarField
values2
(
values1
);
Info
<<
"before: "
<<
flatOutput
(
values2
)
<<
nl
;
Info
<<
"before: "
<<
flatOutput
(
values2
)
<<
nl
;
for
(
scalar
&
val
:
values2
)
{
clipEqOp
<
scalar
>
()(
val
,
limiter
);
}
Info
<<
"after: "
<<
flatOutput
(
values2
)
<<
nl
;
Info
<<
nl
<<
"For list: "
<<
flatOutput
(
values1
)
<<
nl
<<
" minMax : "
<<
minMax
(
values1
)
<<
nl
<<
" minMaxMag : "
<<
minMaxMag
(
values1
)
<<
nl
;
}
// Hashed values and reduction
{
HashTable
<
scalarMinMax
>
hashed
;
hashed
.
insert
(
"zero"
,
scalarMinMax
(
Zero
));
hashed
(
"null"
);
hashed
(
"U"
)
+=
values1
;
Pout
<<
"hashed: "
<<
hashed
<<
nl
;
Pstream
::
mapCombineGather
(
hashed
,
plusEqOp
<
scalarMinMax
>
()
);
Info
<<
"reduced: "
<<
hashed
<<
nl
;
// Prune invalid
hashed
.
filterValues
(
emptyOp
<
scalarMinMax
>
(),
true
);
Info
<<
"filtered: "
<<
hashed
<<
nl
;
}
return
0
;
}
// ************************************************************************* //
src/OpenFOAM/primitives/ranges/MinMax/MinMax.H
0 → 100644
View file @
8a391b79
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::MinMax
Description
A min/max value pair with additional methods.
In addition to conveniently storing values, it can be used for logic
operations or to modify data. A few global functions and functors are
also provided.
Examples of use.
Determine min/max limits from a List of values:
\verbatim
List<scalar> values = ...;
// on construction
MinMax<scalar> range(values);
range.clear();
range += val;
// global minMax() function
Info<< minMax(values) << nl;
\endverbatim
General comparsion operations
\verbatim
scalar val;
if (val < range) ... value is below range min
if (range.contains(val)) ... value within range
if (range.compare(val) > 0) ... value is above range max
if (range(val)) ... value within range - as predicate
\endverbatim
Since the range has a predicate form, it can be used as a filter method.
For example,
\verbatim
Info<< "values in range: " << subsetList(values, range) << nl;
boolList mask = ListOps::create<bool>(values, range);
Info<< "values values in range " << mask << nl;
\endverbatim
One particular advantage offered by MinMax is to clip or limit values
to a particular range. For example,
\verbatim
scalarMinMax range(lower, upper);
scalar val;
val = range.clip(val) .. return clip 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))
\endverbatim
\*---------------------------------------------------------------------------*/
#ifndef MinMax_H
#define MinMax_H
#include "scalar.H"
#include "Pair.H"
#include "Tuple2.H"
#include "ListListOps.H"
#include <type_traits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace
Foam
{
// Forward declarations
template
<
class
T
>
class
MinMax
;
// Common min/max types
typedef
MinMax
<
scalar
>
scalarMinMax
;
/*---------------------------------------------------------------------------*\
Class MinMax Declaration
\*---------------------------------------------------------------------------*/
template
<
class
T
>
class
MinMax
:
public
Tuple2
<
T
,
T
>
{
public:
// Typedefs
//- The value type the MinMax represents
typedef
T
value_type
;
typedef
typename
pTraits
<
T
>::
cmptType
cmptType
;
// Constructors
//- Construct inverted range
inline
MinMax
();
//- Copy construct from components
inline
MinMax
(
const
T
&
minVal
,
const
T
&
maxVal
);
//- Copy construct from components
inline
MinMax
(
const
std
::
pair
<
T
,
T
>&
range
);
//- Copy construct from components
inline
MinMax
(
const
Pair
<
T
>&
range
);
//- Construct with a single initial value
inline
explicit
MinMax
(
const
T
&
val
);
//- Construct from list
inline
explicit
MinMax
(
const
UList
<
T
>&
list
);
// Member Functions
// Access
//- The min value (first)
inline
const
T
&
min
()
const
;
//- The min value (first)
inline
T
&
min
();
//- The max value (second)
inline
const
T
&
max
()
const
;
//- The max value (second)
inline
T
&
max
();
//- The min/max average value
inline
T
centre
()
const
;
//- Range is empty if it is inverted
inline
bool
empty
()
const
;
//- Range is valid if it is not inverted
inline
bool
valid
()
const
;
//- Reset to an invalid, inverted range
inline
void
clear
();
// Testing / Query
//- Intersect (union) with the second range.
// \return True if the resulting intersection is non-empty.
bool
intersect
(
const
MinMax
<
T
>&
b
);
//- Test if the ranges overlap
bool
overlaps
(
const
MinMax
<
T
>&
b
)
const
;
//- Compares the min/max range with the specified value.
// \return
// - 0: value is within the range, or range is invalid
// - -1: range (max) is less than the value
// - +1: range (min) is greater than value
inline
int
compare
(
const
T
&
val
)
const
;
//- True if the value is within the range
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
;
// Manipulate
//- Extend the range to include the other min/max range
inline
MinMax
<
T
>&
add
(
const
MinMax
&
other
);
//- Include the value into the range
inline
MinMax
<
T
>&
add
(
const
T
&
val
);
//- Include the values into the range
inline
MinMax
<
T
>&
add
(
const
UList
<
T
>&
vals
);
// Member Operators
//- Identical to contains(), for use as a predicate.
inline
bool
operator
()(
const
T
&
val
)
const
;
//- Extend min/max range to include other range
// Can be used in a reduction operation.
inline
MinMax
<
T
>&
operator
+=
(
const
MinMax
<
T
>&
b
);
//- Extend min/max range to include value
inline
MinMax
<
T
>&
operator
+=
(
const
T
&
val
);
//- Extend min/max range to include all values
inline
MinMax
<
T
>&
operator
+=
(
const
UList
<
T
>&
vals
);
//- Multiply range by scalar factor
inline
MinMax
<
T
>&
operator
*=
(
const
scalar
&
s
);
//- Divide range by scalar factor
inline
MinMax
<
T
>&
operator
/=
(
const
scalar
&
s
);
};
// Global Functions
//- Min/max range as a string
template
<
class
T
>
word
name
(
const
MinMax
<
T
>&
range
)
{
return
'('
+
Foam
::
name
(
range
.
min
())
+
','
+
Foam
::
name
(
range
.
max
())
+
')'
;
}
//- Return the value after clipping by the min/max limiter
template
<
class
T
>
T
clip
(
const
T
&
val
,
const
MinMax
<
T
>&
range
)
{
return
range
.
clip
(
val
);
}
//- Return the value after clipping by the min/max limiter
template
<
class
T
>
struct
clipOp
{
T
operator
()(
T
&
val
,
const
MinMax
<
T
>&
range
)
const
{
return
range
.
clip
(
val
);
}
};
//- Clip value and assign inplace
template
<
class
T
>
struct
clipEqOp
{
bool
operator
()(
T
&
val
,
const
MinMax
<
T
>&
range
)
const
{
return
range
.
inplaceClip
(
val
);
}
};
//- Extract the min/max range from a list of values
template
<
class
T
>
MinMax
<
T
>
minMax
(
const
UList
<
T
>&
list
)
{
return
MinMax
<
T
>
(
list
);
}
//- Extract the min/max magnitudes from a list of values
template
<
class
T
>
MinMax
<
scalar
>
minMaxMag
(
const
UList
<
T
>&
list
)
{
MinMax
<
scalar
>
result
;
for
(
const
T
&
val
:
list
)
{
result
+=
Foam
::
mag
(
val
);
}
return
result
;
}
// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
//- Combine two ranges
template
<
class
T
>
inline
MinMax
<
T
>
operator
+
(
const
MinMax
<
T
>&
x
,
const
MinMax
<
T
>&
y
)
{
return
MinMax
<
T
>
(
x
).
add
(
y
);
}
//- Multiply range by scalar factor
template
<
class
T
>
inline
MinMax
<
T
>
operator
*
(
const
MinMax
<
T
>&
x
,
const
scalar
&
s
)
{
return
MinMax
<
T
>
(
x
.
min
()
*
s
,
x
.
max
()
*
s
);
}
//- Divide range by scalar factor
template
<
class
T
>
inline
MinMax
<
T
>
operator
/
(
const
MinMax
<
T
>&
x
,
const
scalar
&
s
)
{
return
MinMax
<
T
>
(
x
.
min
()
/
s
,
x
.
max
()
/
s
);
}
// Comparison
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
<
(
const
MinMax
<
T
>&
range
,
const
U
&
val
)
{
return
(
range
.
compare
(
val
)
<
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
<=
(
const
MinMax
<
T
>&
range
,
const
U
&
val
)
{
return
(
range
.
compare
(
val
)
<=
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
>
(
const
MinMax
<
T
>&
range
,
const
U
&
val
)
{
return
(
range
.
compare
(
val
)
>
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
>=
(
const
MinMax
<
T
>&
range
,
const
U
&
val
)
{
return
(
range
.
compare
(
val
)
>=
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
<
(
const
U
&
val
,
const
MinMax
<
T
>&
range
)
{
return
(
range
.
compare
(
val
)
>
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
<=
(
const
U
&
val
,
const
MinMax
<
T
>&
range
)
{
return
(
range
.
compare
(
val
)
>=
0
);
}
template
<
class
T
,
class
U
>
inline
typename
std
::
enable_if
<
std
::
is_convertible
<
U
,
T
>::
value
,
bool
>::
type
operator
>
(
const
U
&
val
,
const
MinMax
<
T
>&
range
)
{