surfaceFieldValue: Ouput as correct primitive type

If the surfaceFieldValue function object is used to compute an
area-normal average or integral of a vector quantity, the result will
now be correctly written out as a scalar.

Previously surfaceFieldValue was limited to writing the same type as the
input field. A vector area-normal average or integral therefore had to
be written out as a vector. This was done by setting the x component to
the result, and the y and z components to zero. This was considered to
be counter-intuitive.
This commit is contained in:
Will Bainbridge
2021-01-08 13:08:28 +00:00
parent 476bce93ce
commit 34cbcd444d
3 changed files with 210 additions and 131 deletions

View File

@ -564,13 +564,12 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
} }
template<> bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
Foam::scalar Foam::functionObjects::fieldValues::surfaceFieldValue::
processValues
( (
const Field<scalar>& values, const Field<scalar>& values,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField const scalarField& weightField,
scalar& result
) const ) const
{ {
switch (operation_) switch (operation_)
@ -578,31 +577,59 @@ processValues
case operationType::sumDirection: case operationType::sumDirection:
{ {
vector n(dict_.lookup("direction")); vector n(dict_.lookup("direction"));
return sum(pos0(values*(Sf & n))*mag(values)); result = sum(pos0(values*(Sf & n))*mag(values));
return true;
} }
case operationType::sumDirectionBalance: case operationType::sumDirectionBalance:
{ {
vector n(dict_.lookup("direction")); vector n(dict_.lookup("direction"));
const scalarField nv(values*(Sf & n)); const scalarField nv(values*(Sf & n));
result = sum(pos0(nv)*mag(values) - neg(nv)*mag(values));
return sum(pos0(nv)*mag(values) - neg(nv)*mag(values)); return true;
} }
default: default:
{ {
// Fall through to other operations // Fall through to same-type operations
return processSameTypeValues(values, Sf, weightField); return processValuesTypeType(values, Sf, weightField, result);
} }
} }
} }
template<> bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
Foam::vector Foam::functionObjects::fieldValues::surfaceFieldValue::
processValues
( (
const Field<vector>& values, const Field<vector>& values,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField const scalarField& weightField,
scalar& result
) const
{
switch (operation_)
{
case operationType::areaNormalAverage:
{
result = sum(values & Sf)/sum(mag(Sf));
return true;
}
case operationType::areaNormalIntegrate:
{
result = sum(values & Sf);
return true;
}
default:
{
return false;
}
}
}
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
(
const Field<vector>& values,
const vectorField& Sf,
const scalarField& weightField,
vector& result
) const ) const
{ {
switch (operation_) switch (operation_)
@ -612,31 +639,21 @@ processValues
vector n(dict_.lookup("direction")); vector n(dict_.lookup("direction"));
n /= mag(n) + rootVSmall; n /= mag(n) + rootVSmall;
const scalarField nv(n & values); const scalarField nv(n & values);
result = sum(pos0(nv)*n*(nv));
return sum(pos0(nv)*n*(nv)); return true;
} }
case operationType::sumDirectionBalance: case operationType::sumDirectionBalance:
{ {
vector n(dict_.lookup("direction")); vector n(dict_.lookup("direction"));
n /= mag(n) + rootVSmall; n /= mag(n) + rootVSmall;
const scalarField nv(n & values); const scalarField nv(n & values);
result = sum(pos0(nv)*n*(nv));
return sum(pos0(nv)*n*(nv)); return true;
}
case operationType::areaNormalAverage:
{
scalar result = sum(values & Sf)/sum(mag(Sf));
return vector(result, 0.0, 0.0);
}
case operationType::areaNormalIntegrate:
{
scalar result = sum(values & Sf);
return vector(result, 0.0, 0.0);
} }
default: default:
{ {
// Fall through to other operations // Fall through to same-type operations
return processSameTypeValues(values, Sf, weightField); return processValuesTypeType(values, Sf, weightField, result);
} }
} }
} }
@ -792,8 +809,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
bool orient = i >= orientedFieldsStart_; bool orient = i >= orientedFieldsStart_;
ok = ok || writeValues<scalar>(fieldName, weightField, orient); ok = ok || writeValues<scalar>(fieldName, weightField, orient);
ok = ok || writeValues<vector>(fieldName, weightField, orient); ok = ok || writeValues<vector>(fieldName, weightField, orient);
ok = ok ok = ok || writeValues<sphericalTensor>(fieldName, weightField, orient);
|| writeValues<sphericalTensor>(fieldName, weightField, orient);
ok = ok || writeValues<symmTensor>(fieldName, weightField, orient); ok = ok || writeValues<symmTensor>(fieldName, weightField, orient);
ok = ok || writeValues<tensor>(fieldName, weightField, orient); ok = ok || writeValues<tensor>(fieldName, weightField, orient);

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -332,24 +332,67 @@ protected:
const bool applyOrientation = false const bool applyOrientation = false
) const; ) const;
//- Apply the 'operation' to the values. Operation has to //- Apply the operation to the values, and return true if successful.
// preserve Type. // Does nothing unless overloaded below.
template<class Type> template<class Type, class ResultType>
Type processSameTypeValues bool processValues
( (
const Field<Type>& values, const Field<Type>& values,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField const scalarField& weightField,
ResultType& result
) const; ) const;
//- Apply the 'operation' to the values. Wrapper around //- Apply Type -> Type operation to the values. Calls
// processSameTypeValues. See also template specialisation below. // processValuesTypeType.
template<class Type> template<class Type>
Type processValues bool processValues
( (
const Field<Type>& values, const Field<Type>& values,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField const scalarField& weightField,
Type& result
) const;
//- Apply scalar -> scalar operation to the values. Tries to apply
// scalar -> scalar specific operations, otherwise calls
// processValuesTypeType.
bool processValues
(
const Field<scalar>& values,
const vectorField& Sf,
const scalarField& weightField,
scalar& result
) const;
//- Apply vector -> vector operation to the values.
bool processValues
(
const Field<vector>& values,
const vectorField& Sf,
const scalarField& weightField,
scalar& result
) const;
//- Apply vector -> vector operation to the values. Tries to apply
// vector -> vector specific operations, otherwise calls
// processValuesTypeType.
bool processValues
(
const Field<vector>& values,
const vectorField& Sf,
const scalarField& weightField,
vector& result
) const;
//- Apply a Type -> Type operation to the values
template<class Type>
bool processValuesTypeType
(
const Field<Type>& values,
const vectorField& Sf,
const scalarField& weightField,
Type& result
) const; ) const;
//- Output file header information //- Output file header information
@ -411,6 +454,16 @@ public:
const bool orient const bool orient
); );
//- Templated helper function to output field values
template<class Type, class ResultType>
bool writeValues
(
const word& fieldName,
const scalarField& weightField,
const Field<Type>& values,
const vectorField& Sf
);
//- Filter a surface field according to faceIds //- Filter a surface field according to faceIds
template<class Type> template<class Type>
tmp<Field<Type>> filterField tmp<Field<Type>> filterField
@ -435,26 +488,6 @@ public:
}; };
//- Specialisation for scalar
template<>
scalar surfaceFieldValue::processValues
(
const Field<scalar>& values,
const vectorField& Sf,
const scalarField& weightField
) const;
//- Specialisation for vector
template<>
vector surfaceFieldValue::processValues
(
const Field<vector>& values,
const vectorField& Sf,
const scalarField& weightField
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace fieldValues } // End namespace fieldValues

View File

@ -2,7 +2,7 @@
========= | ========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org \\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -132,22 +132,48 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
} }
template<class Type> template<class Type, class ResultType>
Type Foam::functionObjects::fieldValues::surfaceFieldValue:: bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
processSameTypeValues
( (
const Field<Type>& values, const Field<Type>& values,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField const scalarField& weightField,
ResultType& result
) const
{
return false;
}
template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
(
const Field<Type>& values,
const vectorField& Sf,
const scalarField& weightField,
Type& result
) const
{
return processValuesTypeType(values, Sf, weightField, result);
}
template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::
processValuesTypeType
(
const Field<Type>& values,
const vectorField& Sf,
const scalarField& weightField,
Type& result
) const ) const
{ {
Type result = Zero;
switch (operation_) switch (operation_)
{ {
case operationType::sum: case operationType::sum:
{ {
result = sum(values); result = sum(values);
break; return true;
} }
case operationType::weightedSum: case operationType::weightedSum:
{ {
@ -159,39 +185,17 @@ processSameTypeValues
{ {
result = sum(values); result = sum(values);
} }
break; return true;
} }
case operationType::sumMag: case operationType::sumMag:
{ {
result = sum(cmptMag(values)); result = sum(cmptMag(values));
break; return true;
}
case operationType::sumDirection:
{
FatalErrorInFunction
<< "Operation " << operationTypeNames_[operation_]
<< " not available for values of type "
<< pTraits<Type>::typeName
<< exit(FatalError);
result = Zero;
break;
}
case operationType::sumDirectionBalance:
{
FatalErrorInFunction
<< "Operation " << operationTypeNames_[operation_]
<< " not available for values of type "
<< pTraits<Type>::typeName
<< exit(FatalError);
result = Zero;
break;
} }
case operationType::average: case operationType::average:
{ {
result = sum(values)/values.size(); result = sum(values)/values.size();
break; return true;
} }
case operationType::weightedAverage: case operationType::weightedAverage:
{ {
@ -205,14 +209,14 @@ processSameTypeValues
{ {
result = sum(values)/values.size(); result = sum(values)/values.size();
} }
break; return true;
} }
case operationType::areaAverage: case operationType::areaAverage:
{ {
const scalarField magSf(mag(Sf)); const scalarField magSf(mag(Sf));
result = sum(magSf*values)/sum(magSf); result = sum(magSf*values)/sum(magSf);
break; return true;
} }
case operationType::weightedAreaAverage: case operationType::weightedAreaAverage:
{ {
@ -228,14 +232,14 @@ processSameTypeValues
{ {
result = sum(magSf*values)/sum(magSf); result = sum(magSf*values)/sum(magSf);
} }
break; return true;
} }
case operationType::areaIntegrate: case operationType::areaIntegrate:
{ {
const scalarField magSf(mag(Sf)); const scalarField magSf(mag(Sf));
result = sum(magSf*values); result = sum(magSf*values);
break; return true;
} }
case operationType::weightedAreaIntegrate: case operationType::weightedAreaIntegrate:
{ {
@ -249,17 +253,17 @@ processSameTypeValues
{ {
result = sum(magSf*values); result = sum(magSf*values);
} }
break; return true;
} }
case operationType::min: case operationType::min:
{ {
result = min(values); result = min(values);
break; return true;
} }
case operationType::max: case operationType::max:
{ {
result = max(values); result = max(values);
break; return true;
} }
case operationType::CoV: case operationType::CoV:
{ {
@ -278,33 +282,20 @@ processSameTypeValues
res = sqrt(sum(magSf*sqr(vals - mean))/sum(magSf))/mean; res = sqrt(sum(magSf*sqr(vals - mean))/sum(magSf))/mean;
} }
break; return true;
} }
case operationType::areaNormalAverage:
{}
case operationType::areaNormalIntegrate:
{}
case operationType::none: case operationType::none:
{} {
return true;
}
default:
{
return false;
}
} }
return result;
} }
template<class Type>
Type Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
(
const Field<Type>& values,
const vectorField& Sf,
const scalarField& weightField
) const
{
return processSameTypeValues(values, Sf, weightField);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> template<class Type>
@ -374,16 +365,26 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
if (Pstream::master()) if (Pstream::master())
{ {
Type result = processValues(values, Sf, weightField); if
(
// Add to result dictionary, over-writing any previous entry !writeValues<Type, scalar>
resultDict_.add(fieldName, result, true); (fieldName, weightField, values, Sf)
&& !writeValues<Type, vector>
file() << tab << result; (fieldName, weightField, values, Sf)
&& !writeValues<Type, sphericalTensor>
Log << " " << operationTypeNames_[operation_] (fieldName, weightField, values, Sf)
<< "(" << regionName_ << ") of " << fieldName && !writeValues<Type, symmTensor>
<< " = " << result << endl; (fieldName, weightField, values, Sf)
&& !writeValues<Type, tensor>
(fieldName, weightField, values, Sf)
)
{
FatalErrorInFunction
<< "Operation " << operationTypeNames_[operation_]
<< " not available for values of type "
<< pTraits<Type>::typeName
<< exit(FatalError);
}
} }
} }
} }
@ -392,6 +393,35 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
} }
template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
(
const word& fieldName,
const scalarField& weightField,
const Field<Type>& values,
const vectorField& Sf
)
{
ResultType result;
if (processValues(values, Sf, weightField, result))
{
// Add to result dictionary, over-writing any previous entry
resultDict_.add(fieldName, result, true);
file() << tab << result;
Log << " " << operationTypeNames_[operation_]
<< "(" << regionName_ << ") of " << fieldName
<< " = " << result << endl;
return true;
}
return false;
}
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::surfaceFieldValue::filterField Foam::functionObjects::fieldValues::surfaceFieldValue::filterField