Commit 9238c90e authored by Mark OLESEN's avatar Mark OLESEN
Browse files

Merge branch 'feature-surfacefield-value' into 'develop'

Feature surface field value operations

See merge request !141
parents eaebb8ee 6ec186ba
......@@ -69,23 +69,32 @@ const Foam::Enum
>
Foam::functionObjects::fieldValues::surfaceFieldValue::operationTypeNames_
{
// Normal operations
{ operationType::opNone, "none" },
{ operationType::opMin, "min" },
{ operationType::opMax, "max" },
{ operationType::opSum, "sum" },
{ operationType::opWeightedSum, "weightedSum" },
{ operationType::opSumMag, "sumMag" },
{ operationType::opSumDirection, "sumDirection" },
{ operationType::opSumDirectionBalance, "sumDirectionBalance" },
{ operationType::opAverage, "average" },
{ operationType::opWeightedAverage, "weightedAverage" },
{ operationType::opAreaAverage, "areaAverage" },
{ operationType::opWeightedAreaAverage, "weightedAreaAverage" },
{ operationType::opAreaIntegrate, "areaIntegrate" },
{ operationType::opWeightedAreaIntegrate, "weightedAreaIntegrate" },
{ operationType::opMin, "min" },
{ operationType::opMax, "max" },
{ operationType::opCoV, "CoV" },
{ operationType::opAreaNormalAverage, "areaNormalAverage" },
{ operationType::opAreaNormalIntegrate, "areaNormalIntegrate" },
// Using weighting
{ operationType::opWeightedSum, "weightedSum" },
{ operationType::opWeightedAverage, "weightedAverage" },
{ operationType::opWeightedAreaAverage, "weightedAreaAverage" },
{ operationType::opWeightedAreaIntegrate, "weightedAreaIntegrate" },
// Using absolute weighting
{ operationType::opAbsWeightedSum, "absWeightedSum" },
{ operationType::opAbsWeightedAverage, "absWeightedAverage" },
{ operationType::opAbsWeightedAreaAverage, "absWeightedAreaAverage" },
{ operationType::opAbsWeightedAreaIntegrate, "absWeightedAreaIntegrate" },
};
const Foam::Enum
......@@ -244,7 +253,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
{
if (facePatchId_[i] != -1)
{
label patchi = facePatchId_[i];
const label patchi = facePatchId_[i];
globalFacesIs[i] += mesh_.boundaryMesh()[patchi].start();
}
}
......@@ -279,9 +288,8 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
// My own data first
{
const faceList& fcs = allFaces[Pstream::myProcNo()];
forAll(fcs, i)
for (const face& f : fcs)
{
const face& f = fcs[i];
face& newF = faces[nFaces++];
newF.setSize(f.size());
forAll(f, fp)
......@@ -291,9 +299,9 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
}
const pointField& pts = allPoints[Pstream::myProcNo()];
forAll(pts, i)
for (const point& pt : pts)
{
points[nPoints++] = pts[i];
points[nPoints++] = pt;
}
}
......@@ -303,9 +311,8 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
if (proci != Pstream::myProcNo())
{
const faceList& fcs = allFaces[proci];
forAll(fcs, i)
for (const face& f : fcs)
{
const face& f = fcs[i];
face& newF = faces[nFaces++];
newF.setSize(f.size());
forAll(f, fp)
......@@ -315,9 +322,9 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
}
const pointField& pts = allPoints[proci];
forAll(pts, i)
for (const point& pt : pts)
{
points[nPoints++] = pts[i];
points[nPoints++] = pt;
}
}
}
......@@ -343,9 +350,9 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
}
points.transfer(newPoints);
forAll(faces, i)
for (face& f : faces)
{
inplaceRenumber(oldToNew, faces[i]);
inplaceRenumber(oldToNew, f);
}
}
}
......@@ -447,17 +454,19 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::totalArea() const
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
bool Foam::functionObjects::fieldValues::surfaceFieldValue::needsSf() const
bool Foam::functionObjects::fieldValues::surfaceFieldValue::usesSf() const
{
// Many operations use the Sf field
// Only a few operations do not require the Sf field
switch (operation_)
{
case opNone:
case opMin:
case opMax:
case opSum:
case opSumMag:
case opAverage:
case opMin:
case opMax:
case opSumDirection:
case opSumDirectionBalance:
{
return false;
}
......@@ -469,26 +478,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::needsSf() const
}
bool Foam::functionObjects::fieldValues::surfaceFieldValue::needsWeight() const
{
// Only a few operations use weight field
switch (operation_)
{
case opWeightedSum:
case opWeightedAverage:
case opWeightedAreaAverage:
case opWeightedAreaIntegrate:
{
return true;
}
default:
{
return false;
}
}
}
void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
(
const dictionary& dict
......@@ -582,19 +571,32 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
weightFieldName_ = "none";
if (needsWeight())
if (usesWeight())
{
if (dict.readIfPresent("weightField", weightFieldName_))
if (regionType_ == stSampledSurface)
{
if (regionType_ == stSampledSurface)
{
FatalIOErrorInFunction(dict)
<< "Cannot use weightField for sampledSurface"
<< exit(FatalIOError);
}
FatalIOErrorInFunction(dict)
<< "Cannot use weighted operation '"
<< operationTypeNames_[operation_]
<< "' for sampledSurface"
<< exit(FatalIOError);
}
if (dict.readIfPresent("weightField", weightFieldName_))
{
Info<< " weight field = " << weightFieldName_ << nl;
}
else
{
// Suggest possible alternative unweighted operation?
FatalIOErrorInFunction(dict)
<< "The '" << operationTypeNames_[operation_]
<< "' operation is missing a weightField." << nl
<< "Either provide the weightField, "
<< "use weightField 'none' to suppress weighting," << nl
<< "or use a different operation."
<< exit(FatalIOError);
}
}
// Backwards compatibility for v1612+ and older
......@@ -660,10 +662,10 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
os << tab << "Area";
}
forAll(fields_, i)
for (const word& fieldName : fields_)
{
os << tab << operationTypeNames_[operation_]
<< "(" << fields_[i] << ")";
<< "(" << fieldName << ")";
}
os << endl;
......@@ -684,12 +686,12 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
{
case opSumDirection:
{
vector n(dict_.lookup("direction"));
const vector n(dict_.lookup("direction"));
return gSum(pos(values*(Sf & n))*mag(values));
}
case opSumDirectionBalance:
{
vector n(dict_.lookup("direction"));
const vector n(dict_.lookup("direction"));
const scalarField nv(values*(Sf & n));
return gSum(pos(nv)*mag(values) - neg(nv)*mag(values));
......@@ -754,10 +756,17 @@ Foam::tmp<Foam::scalarField>
Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor
(
const Field<scalar>& weightField
)
) const
{
// pass through
return weightField;
if (usesMag())
{
return mag(weightField);
}
else
{
// pass through
return weightField;
}
}
......@@ -767,16 +776,21 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor
(
const Field<scalar>& weightField,
const vectorField& Sf
)
) const
{
// scalar * Area
if (returnReduce(weightField.empty(), andOp<bool>()))
{
// No weight field - revert to unweighted form
return mag(Sf);
}
else if (usesMag())
{
return mag(weightField * mag(Sf));
}
else
{
return weightField * mag(Sf);
return (weightField * mag(Sf));
}
}
......@@ -787,16 +801,21 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::weightingFactor
(
const Field<vector>& weightField,
const vectorField& Sf
)
) const
{
// vector (dot) Area
if (returnReduce(weightField.empty(), andOp<bool>()))
{
// No weight field - revert to unweighted form
return mag(Sf);
}
else if (usesMag())
{
return mag(weightField & Sf);
}
else
{
return weightField & Sf;
return (weightField & Sf);
}
}
......@@ -915,7 +934,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
// Many operations use the Sf field
vectorField Sf;
if (needsSf())
if (usesSf())
{
if (regionType_ == stSurface)
{
......
......@@ -103,22 +103,26 @@ Usage
The \c operation is one of:
\plaintable
none | no operation
min | minimum
max | maximum
sum | sum
weightedSum | weighted sum
sumMag | sum of component magnitudes
sumDirection | sum values which are positive in given direction
sumDirection | sum values that are positive in given direction
sumDirectionBalance | sum of balance of values in given direction
average | ensemble average
weightedAverage | weighted average
areaAverage | area-weighted average
weightedAreaAverage | weighted area average
areaIntegrate | area integral
weightedAreaIntegrate | weighted area integral
min | minimum
max | maximum
CoV | coefficient of variation: standard deviation/mean
areaNormalAverage| area-weighted average in face normal direction
areaNormalIntegrate | area-weighted integral in face normal directon
weightedSum | weighted sum
weightedAverage | weighted average
weightedAreaAverage | weighted area average
weightedAreaIntegrate | weighted area integral
absWeightedSum | sum using absolute weighting
absWeightedAverage | average using absolute weighting
absWeightedAreaAverage | area average using absolute weighting
absWeightedAreaIntegrate | area integral using absolute weighting
\endplaintable
Note
......@@ -190,36 +194,73 @@ public:
//- Region type enumeration
enum regionTypes
{
stFaceZone,
stPatch,
stSurface,
stSampledSurface
stFaceZone, //!< Calculate on a faceZone
stPatch, //!< Calculate on a patch
stSurface, //!< Calculate with fields on a surfMesh
stSampledSurface //!< Sample onto surface and calculate
};
//- Region type names
static const Enum<regionTypes> regionTypeNames_;
//- Bitmask values for operation variants
enum operationVariant
{
typeBase = 0, //!< Base operation
typeWeighted = 0x100, //!< Operation using weighting
typeAbsolute = 0x200, //!< Operation using mag (eg, for weighting)
};
//- Operation type enumeration
enum operationType
{
opNone, //!< None
opSum, //!< Sum
opWeightedSum, //!< Weighted sum
opSumMag, //!< Magnitude of sum
// Normal operations
opNone = 0, //!< No operation
opMin, //!< Minimum value
opMax, //!< Maximum value
opSum, //!< Sum of values
opSumMag, //!< Sum of component magnitudes
opSumDirection, //!< Sum in a given direction
opSumDirectionBalance, //!< Sum in a given direction for multiple
opAverage, //!< Average
opWeightedAverage, //!< Weighted average
//! Sum of balance of values in given direction
opSumDirectionBalance,
opAverage, //!< Ensemble average
opAreaAverage, //!< Area average
opWeightedAreaAverage, //!< Weighted area average
opAreaIntegrate, //!< Area integral
opWeightedAreaIntegrate, //!< Weighted area integral
opMin, //!< Minimum
opMax, //!< Maximum
opCoV, //!< Coefficient of variation
opAreaNormalAverage, //!< Area average in normal direction
opAreaNormalIntegrate //!< Area integral in normal direction
opAreaNormalIntegrate, //!< Area integral in normal direction
// Weighted variants
//! Weighted sum
opWeightedSum = (opSum | typeWeighted),
//! Weighted average
opWeightedAverage = (opAverage | typeWeighted),
//! Weighted area average
opWeightedAreaAverage = (opAreaAverage | typeWeighted),
//! Weighted area integral
opWeightedAreaIntegrate = (opAreaIntegrate | typeWeighted),
// Variants using absolute weighting
//! Sum using abs weighting
opAbsWeightedSum = (opWeightedSum | typeAbsolute),
//! Average using abs weighting
opAbsWeightedAverage = (opWeightedAverage | typeAbsolute),
//! Area average using abs weighting
opAbsWeightedAreaAverage = (opWeightedAreaAverage | typeAbsolute),
//! Area integral using abs weighting
opAbsWeightedAreaIntegrate =
(opWeightedAreaIntegrate | typeAbsolute),
};
//- Operation type names
......@@ -229,8 +270,8 @@ public:
//- Post-operation type enumeration
enum postOperationType
{
postOpNone,
postOpSqrt
postOpNone, //!< No additional operation after calculation
postOpSqrt //!< Perform sqrt after normal operation
};
//- Operation type names
......@@ -325,11 +366,19 @@ protected:
//- Return the local true/false list representing the face flip map
inline const boolList& faceFlip() const;
//- True if the specified operation needs a surface Sf
bool needsSf() const;
//- True if the operation needs a surface Sf
bool usesSf() const;
//- True if the operation variant uses mag
inline bool usesMag() const;
//- True if the specified operation needs a weight-field
bool needsWeight() const;
//- True if the operation variant uses a weight-field
inline bool usesWeight() const;
//- True if operation variant uses a weight-field that is available.
// Checks for availability on any processor.
template<class WeightType>
inline bool canWeight(const Field<WeightType>& weightField) const;
//- Initialise, e.g. face addressing
void initialise(const dictionary& dict);
......@@ -365,6 +414,7 @@ protected:
const Field<WeightType>& weightField
) const;
//- Filter a surface field according to faceIds
template<class Type>
tmp<Field<Type>> filterField
......@@ -379,20 +429,24 @@ protected:
const GeometricField<Type, fvPatchField, volMesh>& field
) const;
//- Weighting factor
//- Weighting factor.
// Possibly applies mag() depending on the operation type.
template<class WeightType>
static tmp<scalarField> weightingFactor
tmp<scalarField> weightingFactor
(
const Field<WeightType>& weightField
);
) const;
//- Weighting factor, weight field with the area
//- Weighting factor, weight field with the area.
// Possibly applies mag() depending on the operation type.
// Reverts to mag(Sf) if the weight field is not available.
template<class WeightType>
static tmp<scalarField> weightingFactor
tmp<scalarField> weightingFactor
(
const Field<WeightType>& weightField,
const vectorField& Sf
);
) const;
//- Templated helper function to output field values
......@@ -489,7 +543,7 @@ template<>
tmp<scalarField> surfaceFieldValue::weightingFactor
(
const Field<scalar>& weightField
);
) const;
//- Specialisation for scalar - scalar * Area
......@@ -498,7 +552,7 @@ tmp<scalarField> surfaceFieldValue::weightingFactor
(
const Field<scalar>& weightField,
const vectorField& Sf
);
) const;
//- Specialisation for vector - vector (dot) Area
......@@ -507,7 +561,7 @@ tmp<scalarField> surfaceFieldValue::weightingFactor
(
const Field<vector>& weightField,
const vectorField& Sf
);
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......
......@@ -23,7 +23,6 @@ License
\*---------------------------------------------------------------------------*/
#include "surfaceFieldValue.H"
#include "Time.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
......@@ -51,6 +50,22 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::faceFlip() const
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool
Foam::functionObjects::fieldValues::surfaceFieldValue::usesMag() const
{
// Operation specifically tagged to use mag
return (operation_ & typeAbsolute);
}
inline bool
Foam::functionObjects::fieldValues::surfaceFieldValue::usesWeight() const
{
// Operation specifically tagged to require a weight field
return (operation_ & typeWeighted);
}
inline const Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypes&
Foam::functionObjects::fieldValues::surfaceFieldValue::regionType() const
{
......
......@@ -33,6 +33,20 @@ License
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class WeightType>
inline bool Foam::functionObjects::fieldValues::surfaceFieldValue::canWeight
(
const Field<WeightType>& weightField
) const
{
return
(
usesWeight()
&& returnReduce(!weightField.empty(), orOp<bool>()) // On some processor
);
}
template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::validField
(
......@@ -142,28 +156,36 @@ processSameTypeValues
{
break;
}
case opSum:
case opMin:
{
result = gMin(values);
break;
}
case opMax:
{
result = gMax(values);
break;
}
case opSumMag:
{
result = gSum(values);
result = gSum(cmptMag(values));
break;
}
case opSum:
case opWeightedSum:
case opAbsWeightedSum: