functionObjects: surfaceFieldValue, volFieldValue: Various improvements

A number of changes have been made to the surfaceFieldValue and
volFieldValue function objects to improve their usability and
performance, and to extend them so that similar duplicate functionality
elsewhere in OpenFOAM can be removed.

Weighted operations have been removed. Weighting for averages and sums
is now triggered simply by the existence of the "weightField" or
"weightFields" entry. Multiple weight fields are now supported in both
functions.

The distinction between oriented and non-oriented fields has been
removed from surfaceFieldValue. There is now just a single list of
fields which are operated on. Instead of oriented fields, an
"orientedSum" operation has been added, which should be used for
flowRate calculations and other similar operations on fluxes.

Operations minMag and maxMag have been added to both functions, to
calculate the minimum and maximum field magnitudes respectively. The min
and max operations are performed component-wise, as was the case
previously.

In volFieldValue, minMag and maxMag (and min and mag operations when
applied to scalar fields) will report the location, cell and processor
of the maximum or minimum value. There is also a "writeLocation" option
which if set will write this location information into the output file.
The fieldMinMax function has been made obsolete by this change, and has
therefore been removed.

surfaceFieldValue now operates in parallel without accumulating the
entire surface on the master processor for calculation of the operation.
Collecting the entire surface on the master processor is now only done
if the surface itself is to be written out.
This commit is contained in:
Will Bainbridge
2021-07-08 10:51:34 +01:00
parent e00316c7be
commit 056cc20f34
28 changed files with 781 additions and 1302 deletions

View File

@ -8,8 +8,7 @@
#includeEtc "caseDicts/postProcessing/surfaceFieldValue/faceZone.cfg" #includeEtc "caseDicts/postProcessing/surfaceFieldValue/faceZone.cfg"
fields (); fields (phi);
orientedFields (phi); operation orientedSum;
operation sum;
// ************************************************************************* // // ************************************************************************* //

View File

@ -1,17 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
-------------------------------------------------------------------------------
Description
Writes out the maximum face value for one or more fields.
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/faceMinMax.cfg"
fields (U p);
// ************************************************************************* //

View File

@ -1,17 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
-------------------------------------------------------------------------------
Description
Writes out the minimum face value for one or more fields.
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/faceMin.cfg"
fields (U p);
// ************************************************************************* //

View File

@ -1,12 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/faceMinMax.cfg"
operation min;
// ************************************************************************* //

View File

@ -1,20 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
type surfaceFieldValue;
libs ("libfieldFunctionObjects.so");
writeControl timeStep;
writeInterval 1;
writeFields false;
regionType all;
operation max;
// ************************************************************************* //

View File

@ -1,17 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
type fieldMinMax;
libs ("libfieldFunctionObjects.so");
writeControl timeStep;
writeInterval 1;
mode magnitude;
// ************************************************************************* //

View File

@ -1,18 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
-------------------------------------------------------------------------------
Description
Writes out the minimum and maximum values, by component for non-scalar
fields, and the locations where they occur.
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/minMaxComponents.cfg"
fields (U p);
// ************************************************************************* //

View File

@ -1,12 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/fieldMinMax.cfg"
mode component;
// ************************************************************************* //

View File

@ -1,18 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Version: dev
\\/ M anipulation |
-------------------------------------------------------------------------------
Description
Writes out the minimum and maximum values, by magnitude for non-scalar
fields, and the locations where they occur.
\*---------------------------------------------------------------------------*/
#includeEtc "caseDicts/postProcessing/minMax/fieldMinMax.cfg"
fields (U p);
// ************************************************************************* //

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) 2016-2020 OpenFOAM Foundation \\ / A nd | Copyright (C) 2016-2021 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -55,15 +55,7 @@ Description
#includeFunc mag(p) #includeFunc mag(p)
\endverbatim \endverbatim
Other dictionary entries may also be specified using named arguments, for Other dictionary entries may also be specified using named arguments.
example the \c name of the \c faceZone in the \c flowRateFaceZone \c
functionObject configuration set and the \c orientedFields entry which
defaults to \c phi may also be overridden as required, e.g.
\verbatim
#includeFunc flowRateFaceZone(name=fZone1)
#includeFunc flowRateFaceZone(orientedFields=(phiAlpha),name=fZone1)
\endverbatim
See also See also
Foam::functionObjectList Foam::functionObjectList

View File

@ -3,7 +3,6 @@ fieldAverage/fieldAverageItem/fieldAverageItem.C
fieldAverage/fieldAverageItem/fieldAverageItemIO.C fieldAverage/fieldAverageItem/fieldAverageItemIO.C
fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
fieldMinMax/fieldMinMax.C
fieldValues/fieldValue/fieldValue.C fieldValues/fieldValue/fieldValue.C
fieldValues/fieldValue/fieldValueNew.C fieldValues/fieldValue/fieldValueNew.C

View File

@ -1,169 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ 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/>.
\*---------------------------------------------------------------------------*/
#include "fieldMinMax.H"
#include "fieldTypes.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(fieldMinMax, 0);
addToRunTimeSelectionTable(functionObject, fieldMinMax, dictionary);
}
}
template<>
const char* Foam::NamedEnum
<
Foam::functionObjects::fieldMinMax::modeType,
2
>::names[] = {"magnitude", "component"};
const Foam::NamedEnum
<
Foam::functionObjects::fieldMinMax::modeType,
2
> Foam::functionObjects::fieldMinMax::modeTypeNames_;
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::functionObjects::fieldMinMax::writeFileHeader(const label i)
{
OFstream& file = this->file();
writeHeader(file, "Field minima and maxima");
writeCommented(file, "Time");
if (location_)
{
writeTabbed(file, "field");
writeTabbed(file, "min");
writeTabbed(file, "location(min)");
if (Pstream::parRun())
{
writeTabbed(file, "processor");
}
writeTabbed(file, "max");
writeTabbed(file, "location(max)");
if (Pstream::parRun())
{
writeTabbed(file, "processor");
}
}
else
{
forAll(fieldSet_, fieldi)
{
writeTabbed(file, "min(" + fieldSet_[fieldi] + ')');
writeTabbed(file, "max(" + fieldSet_[fieldi] + ')');
}
}
file<< endl;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::fieldMinMax::fieldMinMax
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
fvMeshFunctionObject(name, runTime, dict),
logFiles(obr_, name),
location_(true),
mode_(modeType::mag),
fieldSet_()
{
read(dict);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::fieldMinMax::~fieldMinMax()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::fieldMinMax::read(const dictionary& dict)
{
fvMeshFunctionObject::read(dict);
location_ = dict.lookupOrDefault<Switch>("location", true);
mode_ = modeTypeNames_[dict.lookupOrDefault<word>("mode", "magnitude")];
dict.lookup("fields") >> fieldSet_;
resetName(typeName);
return true;
}
bool Foam::functionObjects::fieldMinMax::execute()
{
return true;
}
bool Foam::functionObjects::fieldMinMax::write()
{
logFiles::write();
if (Pstream::master() && !location_) writeTime(file());
Log << type() << " " << name() << " write:" << nl;
forAll(fieldSet_, fieldi)
{
calcMinMaxFields<scalar>(fieldSet_[fieldi], modeType::cmpt);
calcMinMaxFields<vector>(fieldSet_[fieldi], mode_);
calcMinMaxFields<sphericalTensor>(fieldSet_[fieldi], mode_);
calcMinMaxFields<symmTensor>(fieldSet_[fieldi], mode_);
calcMinMaxFields<tensor>(fieldSet_[fieldi], mode_);
}
if (Pstream::master() && !location_) file() << endl;
Log << endl;
return true;
}
// ************************************************************************* //

View File

@ -1,209 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2020 OpenFOAM Foundation
\\/ 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::functionObjects::fieldMinMax
Description
Calculates the value and location of scalar minimum and maximum for a list
of user-specified fields.
For variables with a rank greater than zero, either the min/max of a
component value or the magnitude is reported. When operating in parallel,
the processor owning the value is also given.
Example of function object specification:
\verbatim
fieldMinMax1
{
type fieldMinMax;
libs ("libfieldFunctionObjects.so");
...
log yes;
location yes;
mode magnitude;
fields
(
U
p
);
}
\endverbatim
Usage
\table
Property | Description | Required | Default value
type | type name: fieldMinMax | yes |
log | write min/max data to standard output | no | no
location | write location of the min/max value | no | yes
mode | calculation mode: magnitude or component | no | magnitude
\endtable
Output data is written to the file \<timeDir\>/fieldMinMax.dat
See also
Foam::functionObjects::fvMeshFunctionObject
Foam::functionObjects::logFiles
SourceFiles
fieldMinMax.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_fieldMinMax_H
#define functionObjects_fieldMinMax_H
#include "fvMeshFunctionObject.H"
#include "logFiles.H"
#include "vector.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class fieldMinMax Declaration
\*---------------------------------------------------------------------------*/
class fieldMinMax
:
public fvMeshFunctionObject,
public logFiles
{
public:
enum class modeType
{
mag,
cmpt
};
protected:
// Protected data
//- Mode type names
static const NamedEnum<modeType, 2> modeTypeNames_;
//- Switch to write location of min/max values
Switch location_;
//- Mode for min/max - only applicable for ranks > 0
modeType mode_;
//- Fields to assess min/max
wordList fieldSet_;
// Protected Member Functions
//- Helper function to write the output
template<class Type>
void output
(
const word& fieldName,
const word& outputName,
const label minCell,
const label maxCell,
const vector& minC,
const vector& maxC,
const label minProci,
const label maxProci,
const Type& minValue,
const Type& maxValue
);
//- Calculate the field min/max
template<class Type>
void calcMinMaxFields
(
const word& fieldName,
const modeType& mode
);
//- Output file header information
virtual void writeFileHeader(const label i);
public:
//- Runtime type information
TypeName("fieldMinMax");
// Constructors
//- Construct from Time and dictionary
fieldMinMax
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- Disallow default bitwise copy construction
fieldMinMax(const fieldMinMax&) = delete;
//- Destructor
virtual ~fieldMinMax();
// Member Functions
//- Read the field min/max data
virtual bool read(const dictionary&);
//- Execute, currently does nothing
virtual bool execute();
//- Write the fieldMinMax
virtual bool write();
// Member Operators
//- Disallow default bitwise assignment
void operator=(const fieldMinMax&) = delete;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "fieldMinMaxTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,305 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
\\/ 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/>.
\*---------------------------------------------------------------------------*/
#include "fieldMinMax.H"
#include "volFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
void Foam::functionObjects::fieldMinMax::output
(
const word& fieldName,
const word& outputName,
const label minCell,
const label maxCell,
const vector& minC,
const vector& maxC,
const label minProci,
const label maxProci,
const Type& minValue,
const Type& maxValue
)
{
OFstream& file = this->file();
if (location_)
{
writeTime(file());
writeTabbed(file, fieldName);
file<< tab << minValue
<< tab << minC;
if (Pstream::parRun())
{
file<< tab << minProci;
}
file<< tab << maxValue
<< tab << maxC;
if (Pstream::parRun())
{
file<< tab << maxProci;
}
file<< endl;
Log << " min(" << outputName << ") = " << minValue
<< " in cell " << minCell
<< " at location " << minC;
if (Pstream::parRun())
{
Log << " on processor " << minProci;
}
Log << nl << " max(" << outputName << ") = " << maxValue
<< " in cell " << maxCell
<< " at location " << maxC;
if (Pstream::parRun())
{
Log << " on processor " << maxProci;
}
}
else
{
file<< tab << minValue << tab << maxValue;
Log << " min/max(" << outputName << ") = "
<< minValue << ' ' << maxValue;
}
Log << endl;
}
template<class Type>
void Foam::functionObjects::fieldMinMax::calcMinMaxFields
(
const word& fieldName,
const modeType& mode
)
{
typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
if (obr_.foundObject<fieldType>(fieldName))
{
const label proci = Pstream::myProcNo();
const fieldType& field = obr_.lookupObject<fieldType>(fieldName);
const volVectorField::Boundary& CfBoundary =
mesh_.C().boundaryField();
switch (mode)
{
case modeType::mag:
{
const volScalarField magField(mag(field));
const volScalarField::Boundary& magFieldBoundary =
magField.boundaryField();
scalarList minVs(Pstream::nProcs());
labelList minCells(Pstream::nProcs());
List<vector> minCs(Pstream::nProcs());
label minProci = findMin(magField);
minVs[proci] = magField[minProci];
minCells[proci] = minProci;
minCs[proci] = mesh_.C()[minProci];
scalarList maxVs(Pstream::nProcs());
labelList maxCells(Pstream::nProcs());
List<vector> maxCs(Pstream::nProcs());
label maxProci = findMax(magField);
maxVs[proci] = magField[maxProci];
maxCells[proci] = maxProci;
maxCs[proci] = mesh_.C()[maxProci];
forAll(magFieldBoundary, patchi)
{
const scalarField& mfp = magFieldBoundary[patchi];
if (mfp.size())
{
const vectorField& Cfp = CfBoundary[patchi];
const labelList& faceCells =
magFieldBoundary[patchi].patch().faceCells();
label minPI = findMin(mfp);
if (mfp[minPI] < minVs[proci])
{
minVs[proci] = mfp[minPI];
minCells[proci] = faceCells[minPI];
minCs[proci] = Cfp[minPI];
}
label maxPI = findMax(mfp);
if (mfp[maxPI] > maxVs[proci])
{
maxVs[proci] = mfp[maxPI];
maxCells[proci] = faceCells[maxPI];
maxCs[proci] = Cfp[maxPI];
}
}
}
Pstream::gatherList(minVs);
Pstream::gatherList(minCells);
Pstream::gatherList(minCs);
Pstream::gatherList(maxVs);
Pstream::gatherList(maxCells);
Pstream::gatherList(maxCs);
if (Pstream::master())
{
const label minI = findMin(minVs);
const scalar minValue = minVs[minI];
const label minCell = minCells[minI];
const vector& minC = minCs[minI];
const label maxI = findMax(maxVs);
const scalar maxValue = maxVs[maxI];
const label maxCell = maxCells[maxI];
const vector& maxC = maxCs[maxI];
output
(
fieldName,
word("mag(" + fieldName + ")"),
minCell,
maxCell,
minC,
maxC,
minI,
maxI,
minValue,
maxValue
);
}
break;
}
case modeType::cmpt:
{
const typename fieldType::Boundary&
fieldBoundary = field.boundaryField();
List<Type> minVs(Pstream::nProcs());
labelList minCells(Pstream::nProcs());
List<vector> minCs(Pstream::nProcs());
label minProci = findMin(field);
minVs[proci] = field[minProci];
minCells[proci] = minProci;
minCs[proci] = mesh_.C()[minProci];
List<Type> maxVs(Pstream::nProcs());
labelList maxCells(Pstream::nProcs());
List<vector> maxCs(Pstream::nProcs());
label maxProci = findMax(field);
maxVs[proci] = field[maxProci];
maxCells[proci] = maxProci;
maxCs[proci] = mesh_.C()[maxProci];
forAll(fieldBoundary, patchi)
{
const Field<Type>& fp = fieldBoundary[patchi];
if (fp.size())
{
const vectorField& Cfp = CfBoundary[patchi];
const labelList& faceCells =
fieldBoundary[patchi].patch().faceCells();
label minPI = findMin(fp);
if (fp[minPI] < minVs[proci])
{
minVs[proci] = fp[minPI];
minCells[proci] = faceCells[minPI];
minCs[proci] = Cfp[minPI];
}
label maxPI = findMax(fp);
if (fp[maxPI] > maxVs[proci])
{
maxVs[proci] = fp[maxPI];
maxCells[proci] = faceCells[maxPI];
maxCs[proci] = Cfp[maxPI];
}
}
}
Pstream::gatherList(minVs);
Pstream::gatherList(minCells);
Pstream::gatherList(minCs);
Pstream::gatherList(maxVs);
Pstream::gatherList(maxCells);
Pstream::gatherList(maxCs);
if (Pstream::master())
{
label minI = findMin(minVs);
Type minValue = minVs[minI];
const label minCell = minCells[minI];
const vector& minC = minCs[minI];
label maxI = findMax(maxVs);
Type maxValue = maxVs[maxI];
const label maxCell = maxCells[maxI];
const vector& maxC = maxCs[maxI];
output
(
fieldName,
fieldName,
minCell,
maxCell,
minC,
maxC,
minI,
maxI,
minValue,
maxValue
);
}
break;
}
default:
{
FatalErrorInFunction
<< "Unknown min/max mode: " << modeTypeNames_[mode_]
<< exit(FatalError);
}
}
}
}
// ************************************************************************* //

View File

@ -63,23 +63,22 @@ template<>
const char* Foam::NamedEnum const char* Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::surfaceFieldValue::operationType, Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
17 16
>::names[] = >::names[] =
{ {
"none", "none",
"sum", "sum",
"weightedSum",
"sumMag", "sumMag",
"sumDirection", "sumDirection",
"sumDirectionBalance", "sumDirectionBalance",
"orientedSum",
"average", "average",
"weightedAverage",
"areaAverage", "areaAverage",
"weightedAreaAverage",
"areaIntegrate", "areaIntegrate",
"weightedAreaIntegrate",
"min", "min",
"max", "max",
"minMag",
"maxMag",
"CoV", "CoV",
"areaNormalAverage", "areaNormalAverage",
"areaNormalIntegrate" "areaNormalIntegrate"
@ -94,7 +93,7 @@ const Foam::NamedEnum
const Foam::NamedEnum const Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::surfaceFieldValue::operationType, Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
17 16
> Foam::functionObjects::fieldValues::surfaceFieldValue::operationTypeNames_; > Foam::functionObjects::fieldValues::surfaceFieldValue::operationTypeNames_;
@ -366,7 +365,7 @@ combineSurfaceGeometry
pointField& points pointField& points
) const ) const
{ {
if (surfacePtr_.valid()) if (regionType_ == regionTypes::sampledSurface)
{ {
const sampledSurface& s = surfacePtr_(); const sampledSurface& s = surfacePtr_();
@ -402,18 +401,14 @@ combineSurfaceGeometry
Foam::scalar Foam::scalar
Foam::functionObjects::fieldValues::surfaceFieldValue::totalArea() const Foam::functionObjects::fieldValues::surfaceFieldValue::totalArea() const
{ {
scalar totalArea; if (regionType_ == regionTypes::sampledSurface)
if (surfacePtr_.valid())
{ {
totalArea = gSum(surfacePtr_().magSf()); return gSum(surfacePtr_().magSf());
} }
else else
{ {
totalArea = gSum(filterField(mesh_.magSf(), false)); return gSum(filterField(mesh_.magSf()));
} }
return totalArea;
} }
@ -462,7 +457,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
<< " Region has no faces" << exit(FatalError); << " Region has no faces" << exit(FatalError);
} }
if (surfacePtr_.valid()) if (regionType_ == regionTypes::sampledSurface)
{ {
surfacePtr_().update(); surfacePtr_().update();
} }
@ -475,42 +470,18 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
<< " total area = " << totalArea_ << " total area = " << totalArea_
<< nl; << nl;
if (dict.readIfPresent("orientedWeightField", weightFieldName_)) if (dict.readIfPresent("weightFields", weightFieldNames_))
{ {
Info<< " orientedWeightField = " << weightFieldName_ << nl; Info<< name() << " " << operationTypeNames_[operation_]
orientWeightField_ = true; << " weight fields " << weightFieldNames_;
if (regionType_ == regionTypes::sampledSurface)
{
FatalIOErrorInFunction(dict)
<< "Cannot use orientedWeightField for a sampledSurface"
<< exit(FatalIOError);
}
if (dict.found("weightField"))
{
FatalIOErrorInFunction(dict)
<< "Either provide weightField or orientedWeightField"
<< exit(FatalIOError);
}
} }
else if (dict.readIfPresent("weightField", weightFieldName_)) else if (dict.found("weightField"))
{ {
Info<< " weightField = " << weightFieldName_ << nl; weightFieldNames_.setSize(1);
dict.lookup("weightField") >> weightFieldNames_[0];
if (regionType_ == regionTypes::sampledSurface) Info<< name() << " " << operationTypeNames_[operation_]
{ << " weight field " << weightFieldNames_[0];
FatalIOErrorInFunction(dict)
<< "Cannot use weightField for a sampledSurface"
<< exit(FatalIOError);
}
}
List<word> orientedFields;
if (dict.readIfPresent("orientedFields", orientedFields))
{
orientedFieldsStart_ = fields_.size();
fields_.append(orientedFields);
} }
if (dict.readIfPresent("scaleFactor", scaleFactor_)) if (dict.readIfPresent("scaleFactor", scaleFactor_))
@ -567,8 +538,9 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
( (
const Field<scalar>& values, const Field<scalar>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
scalar& result scalar& result
) const ) const
{ {
@ -576,21 +548,28 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
{ {
case operationType::sumDirection: case operationType::sumDirection:
{ {
vector n(dict_.lookup("direction")); const vector n(dict_.lookup("direction"));
result = sum(pos0(values*(Sf & n))*mag(values)); result = gSum(weights*pos0(values*(Sf & n))*mag(values));
return true; return true;
} }
case operationType::sumDirectionBalance: case operationType::sumDirectionBalance:
{ {
vector n(dict_.lookup("direction")); const 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)); result = gSum(weights*(pos0(nv)*mag(values) - neg(nv)*mag(values)));
return true; return true;
} }
default: default:
{ {
// Fall through to same-type operations // Fall through to same-type operations
return processValuesTypeType(values, Sf, weightField, result); return processValuesTypeType
(
values,
signs,
weights,
Sf,
result
);
} }
} }
} }
@ -599,8 +578,9 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
( (
const Field<vector>& values, const Field<vector>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
scalar& result scalar& result
) const ) const
{ {
@ -608,12 +588,12 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
{ {
case operationType::areaNormalAverage: case operationType::areaNormalAverage:
{ {
result = sum(values & Sf)/sum(mag(Sf)); result = gSum(weights*values & Sf)/gSum(mag(weights*Sf));
return true; return true;
} }
case operationType::areaNormalIntegrate: case operationType::areaNormalIntegrate:
{ {
result = sum(values & Sf); result = gSum(weights*values & Sf);
return true; return true;
} }
default: default:
@ -627,8 +607,9 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
( (
const Field<vector>& values, const Field<vector>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
vector& result vector& result
) const ) const
{ {
@ -636,24 +617,29 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
{ {
case operationType::sumDirection: case operationType::sumDirection:
{ {
vector n(dict_.lookup("direction")); const vector n = normalised(dict_.lookup<vector>("direction"));
n /= mag(n) + rootVSmall;
const scalarField nv(n & values); const scalarField nv(n & values);
result = sum(pos0(nv)*n*(nv)); result = gSum(weights*pos0(nv)*n*(nv));
return true; return true;
} }
case operationType::sumDirectionBalance: case operationType::sumDirectionBalance:
{ {
vector n(dict_.lookup("direction")); const vector n = normalised(dict_.lookup<vector>("direction"));
n /= mag(n) + rootVSmall;
const scalarField nv(n & values); const scalarField nv(n & values);
result = sum(pos0(nv)*n*(nv)); result = gSum(weights*pos0(nv)*n*(nv));
return true; return true;
} }
default: default:
{ {
// Fall through to same-type operations // Fall through to same-type operations
return processValuesTypeType(values, Sf, weightField, result); return processValuesTypeType
(
values,
signs,
weights,
Sf,
result
);
} }
} }
} }
@ -672,10 +658,8 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
surfaceWriterPtr_(nullptr), surfaceWriterPtr_(nullptr),
regionType_(regionTypeNames_.read(dict.lookup("regionType"))), regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
operation_(operationTypeNames_.read(dict.lookup("operation"))), operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldName_("none"), weightFieldNames_(),
orientWeightField_(false), scaleFactor_(1),
orientedFieldsStart_(labelMax),
scaleFactor_(1.0),
writeArea_(dict.lookupOrDefault("writeArea", false)), writeArea_(dict.lookupOrDefault("writeArea", false)),
nFaces_(0), nFaces_(0),
faceId_(), faceId_(),
@ -696,10 +680,8 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
surfaceWriterPtr_(nullptr), surfaceWriterPtr_(nullptr),
regionType_(regionTypeNames_.read(dict.lookup("regionType"))), regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
operation_(operationTypeNames_.read(dict.lookup("operation"))), operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldName_("none"), weightFieldNames_(),
orientWeightField_(false), scaleFactor_(1),
orientedFieldsStart_(labelMax),
scaleFactor_(1.0),
writeArea_(dict.lookupOrDefault("writeArea", false)), writeArea_(dict.lookupOrDefault("writeArea", false)),
nFaces_(0), nFaces_(0),
faceId_(), faceId_(),
@ -737,7 +719,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
fieldValue::write(); fieldValue::write();
} }
if (surfacePtr_.valid()) if (regionType_ == regionTypes::sampledSurface)
{ {
surfacePtr_().update(); surfacePtr_().update();
} }
@ -758,12 +740,12 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
} }
// Write the surface geometry // Write the surface geometry
if (surfaceWriterPtr_.valid()) if (writeFields_)
{ {
faceList faces; faceList faces;
pointField points; pointField points;
if (surfacePtr_.valid()) if (regionType_ == regionTypes::sampledSurface)
{ {
combineSurfaceGeometry(faces, points); combineSurfaceGeometry(faces, points);
} }
@ -784,21 +766,24 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
} }
} }
// Construct weight field. Note: zero size means weight = 1 // Construct the sign and weight fields and the surface normals
scalarField weightField; const scalarField signs
if (weightFieldName_ != "none") (
regionType_ == regionTypes::sampledSurface
? scalarField(surfacePtr_().Sf().size(), 1)
: List<scalar>(faceSign_)
);
scalarField weights(signs.size(), 1);
forAll(weightFieldNames_, i)
{ {
weightField = weights *= getFieldValues<scalar>(weightFieldNames_[i]);
getFieldValues<scalar>
(
weightFieldName_,
true,
orientWeightField_
);
} }
const vectorField Sf
// Combine onto master (
combineFields(weightField); regionType_ == regionTypes::sampledSurface
? surfacePtr_().Sf()
: (signs*filterField(mesh_.Sf()))()
);
// Process the fields // Process the fields
forAll(fields_, i) forAll(fields_, i)
@ -806,12 +791,18 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
const word& fieldName = fields_[i]; const word& fieldName = fields_[i];
bool ok = false; bool ok = false;
bool orient = i >= orientedFieldsStart_; #define writeValuesFieldType(fieldType, none) \
ok = ok || writeValues<scalar>(fieldName, weightField, orient); ok = \
ok = ok || writeValues<vector>(fieldName, weightField, orient); ok \
ok = ok || writeValues<sphericalTensor>(fieldName, weightField, orient); || writeValues<fieldType> \
ok = ok || writeValues<symmTensor>(fieldName, weightField, orient); ( \
ok = ok || writeValues<tensor>(fieldName, weightField, orient); fieldName, \
signs, \
weights, \
Sf \
);
FOR_ALL_FIELD_TYPES(writeValuesFieldType);
#undef writeValuesFieldType
if (!ok) if (!ok)
{ {

View File

@ -32,7 +32,7 @@ Description
averages and integrations. averages and integrations.
For example, to calculate the volumetric or mass flux across a patch, For example, to calculate the volumetric or mass flux across a patch,
apply the 'sum' operator to the flux field (typically \c phi) apply the 'orientedSum' operator to the flux field (typically \c phi)
Examples of function object specification: Examples of function object specification:
\verbatim \verbatim
@ -96,10 +96,9 @@ Usage
name | name of face regionType if required | no | name | name of face regionType if required | no |
operation | operation to perform | yes | operation | operation to perform | yes |
weightField | name of field to apply weighting | no | weightField | name of field to apply weighting | no |
orientedWeightField | name of oriented field to apply weighting | no | weightFields | Names of fields to apply weighting | no |
scaleFactor | scale factor | no | 1 scaleFactor | scale factor | no | 1
fields | list of fields to operate on | yes | fields | list of fields to operate on | yes |
orientedFields | list of oriented fields to operate on | no |
\endtable \endtable
Where \c regionType is defined by Where \c regionType is defined by
@ -113,41 +112,38 @@ Usage
\plaintable \plaintable
none | no operation none | no operation
sum | sum sum | sum
weightedSum | weighted sum
sumMag | sum of component magnitudes sumMag | sum of component magnitudes
sumDirection | sum values which are positive in given direction sumDirection | sum values which are positive in given direction
sumDirectionBalance | sum of balance of values in given direction sumDirectionBalance | sum of balance of values in given direction
orientedSum | sum with face orientations
average | ensemble average average | ensemble average
weightedAverage | weighted average
areaAverage | area weighted average areaAverage | area weighted average
weightedAreaAverage | weighted area average
areaIntegrate | area integral areaIntegrate | area integral
weightedAreaIntegrate | weighted area integral
min | minimum min | minimum
max | maximum max | maximum
minMag | minimum magnitude
maxMag | maximum magnitude
CoV | coefficient of variation: standard deviation/mean CoV | coefficient of variation: standard deviation/mean
areaNormalAverage| area weighted average in face normal direction areaNormalAverage | area weighted average in face normal direction
areaNormalIntegrate | area weighted integral in face normal directon areaNormalIntegrate | area weighted integral in face normal direction
\endplaintable \endplaintable
Note Note
- The values reported by the areaNormalAverage and areaNormalIntegrate - Faces on empty patches get ignored.
operations are written as the first component of a field with the same - The `oriented' operations will flip the sign of the field so that all the
rank as the input field. normals point in a consistent direction. This is only of relevance when
- faces on empty patches get ignored summing mesh-oriented fields, such as the flux, on faceZones.
- if the field is a volField the \c faceZone can only consist of boundary - If the field is a volField then a \c faceZone can only consist of
boundary faces, because only these faces have a value associated with
them. No cell-to-face interpolation is performed.
- If the field is a surfaceField then the region cannot be a \c
sampledSurface
- If a sampledSurface has interpolation set to false then the surface
face values will be taken directly from the cell that contains the
surface face centre
- If a \c sampledSurface has interpolation set to true then the field
will be interpolated to the vertices, then averaged onto the surface
faces faces
- the `oriented' entries relate to mesh-oriented fields, such as the
flux, phi. These fields will be oriented according to the face normals.
- using \c sampledSurface:
- not available for surface fields
- if interpolate=true they use \c interpolationCellPoint
otherwise they use cell values
- each triangle in \c sampledSurface is logically only in one cell
so interpolation will be wrong when triangles are larger than
cells. This can only happen for sampling on a \c triSurfaceMesh
- take care when using isoSurfaces - these might have duplicate
triangles and so integration might be wrong
See also See also
Foam::fieldValues Foam::fieldValues
@ -208,25 +204,24 @@ public:
{ {
none, none,
sum, sum,
weightedSum,
sumMag, sumMag,
sumDirection, sumDirection,
sumDirectionBalance, sumDirectionBalance,
orientedSum,
average, average,
weightedAverage,
areaAverage, areaAverage,
weightedAreaAverage,
areaIntegrate, areaIntegrate,
weightedAreaIntegrate,
min, min,
max, max,
minMag,
maxMag,
CoV, CoV,
areaNormalAverage, areaNormalAverage,
areaNormalIntegrate areaNormalIntegrate
}; };
//- Operation type names //- Operation type names
static const NamedEnum<operationType, 17> operationTypeNames_; static const NamedEnum<operationType, 16> operationTypeNames_;
private: private:
@ -273,14 +268,8 @@ protected:
//- Operation to apply to values //- Operation to apply to values
operationType operation_; operationType operation_;
//- Weight field name - optional //- Weight field names - optional
word weightFieldName_; wordList weightFieldNames_;
//- Flag to indicate if flipMap should be applied to the weight field
bool orientWeightField_;
//- Start index of fields that require application of flipMap
label orientedFieldsStart_;
//- Scale factor - optional //- Scale factor - optional
scalar scaleFactor_; scalar scaleFactor_;
@ -325,12 +314,7 @@ protected:
//- Return field values by looking up field name //- Return field values by looking up field name
template<class Type> template<class Type>
tmp<Field<Type>> getFieldValues tmp<Field<Type>> getFieldValues(const word& fieldName) const;
(
const word& fieldName,
const bool mustGet = false,
const bool applyOrientation = false
) const;
//- Apply the operation to the values, and return true if successful. //- Apply the operation to the values, and return true if successful.
// Does nothing unless overloaded below. // Does nothing unless overloaded below.
@ -338,8 +322,9 @@ protected:
bool processValues bool processValues
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
ResultType& result ResultType& result
) const; ) const;
@ -349,19 +334,32 @@ protected:
bool processValues bool processValues
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
Type& result Type& result
) const; ) const;
//- Apply Type -> scalar operation to the values
template<class Type>
bool processValues
(
const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf,
scalar& result
) const;
//- Apply scalar -> scalar operation to the values. Tries to apply //- Apply scalar -> scalar operation to the values. Tries to apply
// scalar -> scalar specific operations, otherwise calls // scalar -> scalar specific operations, otherwise calls
// processValuesTypeType. // processValuesTypeType.
bool processValues bool processValues
( (
const Field<scalar>& values, const Field<scalar>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
scalar& result scalar& result
) const; ) const;
@ -369,8 +367,9 @@ protected:
bool processValues bool processValues
( (
const Field<vector>& values, const Field<vector>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
scalar& result scalar& result
) const; ) const;
@ -380,8 +379,9 @@ protected:
bool processValues bool processValues
( (
const Field<vector>& values, const Field<vector>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
vector& result vector& result
) const; ) const;
@ -390,8 +390,9 @@ protected:
bool processValuesTypeType bool processValuesTypeType
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
Type& result Type& result
) const; ) const;
@ -450,8 +451,9 @@ public:
bool writeValues bool writeValues
( (
const word& fieldName, const word& fieldName,
const scalarField& weightField, const scalarField& signs,
const bool orient const scalarField& weights,
const vectorField& Sf
); );
//- Templated helper function to output field values //- Templated helper function to output field values
@ -459,8 +461,9 @@ public:
bool writeValues bool writeValues
( (
const word& fieldName, const word& fieldName,
const scalarField& weightField,
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf const vectorField& Sf
); );
@ -468,16 +471,14 @@ public:
template<class Type> template<class Type>
tmp<Field<Type>> filterField tmp<Field<Type>> filterField
( (
const GeometricField<Type, fvsPatchField, surfaceMesh>& field, const GeometricField<Type, fvsPatchField, surfaceMesh>& field
const bool applyOrientation
) const; ) const;
//- Filter a volume field according to faceIds //- Filter a volume field according to faceIds
template<class Type> template<class Type>
tmp<Field<Type>> filterField tmp<Field<Type>> filterField
( (
const GeometricField<Type, fvPatchField, volMesh>& field, const GeometricField<Type, fvPatchField, volMesh>& field
const bool applyOrientation
) const; ) const;
//- Read from dictionary //- Read from dictionary

View File

@ -62,42 +62,29 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
( (
const word& fieldName, const word& fieldName
const bool mustGet,
const bool applyOrientation
) const ) const
{ {
typedef GeometricField<Type, fvsPatchField, surfaceMesh> sf;
typedef GeometricField<Type, fvPatchField, volMesh> vf; typedef GeometricField<Type, fvPatchField, volMesh> vf;
typedef GeometricField<Type, fvsPatchField, surfaceMesh> sf;
if if (regionType_ == regionTypes::sampledSurface)
(
regionType_ != regionTypes::sampledSurface
&& obr_.foundObject<sf>(fieldName)
)
{ {
return filterField(obr_.lookupObject<sf>(fieldName), applyOrientation); if (obr_.foundObject<vf>(fieldName))
}
else if (obr_.foundObject<vf>(fieldName))
{
const vf& fld = obr_.lookupObject<vf>(fieldName);
if (surfacePtr_.valid())
{ {
const vf& fld = obr_.lookupObject<vf>(fieldName);
if (surfacePtr_().interpolate()) if (surfacePtr_().interpolate())
{ {
// Interpolate the field to the surface points
const interpolationCellPoint<Type> interp(fld); const interpolationCellPoint<Type> interp(fld);
tmp<Field<Type>> tintFld(surfacePtr_().interpolate(interp)); tmp<Field<Type>> tintFld(surfacePtr_().interpolate(interp));
const Field<Type>& intFld = tintFld(); const Field<Type>& intFld = tintFld();
// Average // Average the interpolated field onto the surface faces
const faceList& faces = surfacePtr_().faces(); const faceList& faces = surfacePtr_().faces();
tmp<Field<Type>> tavg tmp<Field<Type>> tavg(new Field<Type>(faces.size(), Zero));
(
new Field<Type>(faces.size(), Zero)
);
Field<Type>& avg = tavg.ref(); Field<Type>& avg = tavg.ref();
forAll(faces, facei) forAll(faces, facei)
{ {
const face& f = faces[facei]; const face& f = faces[facei];
@ -115,20 +102,34 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
return surfacePtr_().sample(fld); return surfacePtr_().sample(fld);
} }
} }
else else if (obr_.foundObject<sf>(fieldName))
{ {
return filterField(fld, applyOrientation); FatalErrorInFunction
<< "Surface field " << fieldName
<< " cannot be sampled onto surface " << surfacePtr_().name()
<< ". Only vol fields can be sampled onto surfaces."
<< abort(FatalError);
}
}
else
{
if (obr_.foundObject<vf>(fieldName))
{
const vf& fld = obr_.lookupObject<vf>(fieldName);
return filterField(fld);
}
else if (obr_.foundObject<sf>(fieldName))
{
const sf& fld = obr_.lookupObject<sf>(fieldName);
return filterField(fld);
} }
} }
if (mustGet) FatalErrorInFunction
{ << "Field " << fieldName << " not found in database"
FatalErrorInFunction << abort(FatalError);
<< "Field " << fieldName << " not found in database"
<< abort(FatalError);
}
return tmp<Field<Type>>(new Field<Type>(0)); return tmp<Field<Type>>(nullptr);
} }
@ -136,8 +137,9 @@ template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
ResultType& result ResultType& result
) const ) const
{ {
@ -149,12 +151,43 @@ template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
Type& result Type& result
) const ) const
{ {
return processValuesTypeType(values, Sf, weightField, result); return processValuesTypeType(values, signs, weights, Sf, result);
}
template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::processValues
(
const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf,
scalar& result
) const
{
switch (operation_)
{
case operationType::minMag:
{
result = gMin(mag(values));
return true;
}
case operationType::maxMag:
{
result = gMax(mag(values));
return true;
}
default:
{
return false;
}
}
} }
@ -163,8 +196,9 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::
processValuesTypeType processValuesTypeType
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf, const vectorField& Sf,
const scalarField& weightField,
Type& result Type& result
) const ) const
{ {
@ -172,104 +206,55 @@ processValuesTypeType
{ {
case operationType::sum: case operationType::sum:
{ {
result = sum(values); result = gSum(weights*values);
return true;
}
case operationType::weightedSum:
{
if (weightField.size())
{
result = sum(weightField*values);
}
else
{
result = sum(values);
}
return true; return true;
} }
case operationType::sumMag: case operationType::sumMag:
{ {
result = sum(cmptMag(values)); result = gSum(weights*cmptMag(values));
return true;
}
case operationType::orientedSum:
{
result = gSum(signs*weights*values);
return true; return true;
} }
case operationType::average: case operationType::average:
{ {
result = sum(values)/values.size(); result =
return true; gSum(weights*values)
} /stabilise(gSum(weights), vSmall);
case operationType::weightedAverage:
{
if (weightField.size())
{
result =
sum(weightField*values)
/stabilise(sum(weightField), vSmall);
}
else
{
result = sum(values)/values.size();
}
return true; return true;
} }
case operationType::areaAverage: case operationType::areaAverage:
{ {
const scalarField magSf(mag(Sf)); const scalarField magSf(mag(Sf));
result =
result = sum(magSf*values)/sum(magSf); gSum(weights*magSf*values)
return true; /stabilise(gSum(weights*magSf), vSmall);
}
case operationType::weightedAreaAverage:
{
const scalarField magSf(mag(Sf));
if (weightField.size())
{
result =
sum(weightField*magSf*values)
/stabilise(sum(magSf*weightField), vSmall);
}
else
{
result = sum(magSf*values)/sum(magSf);
}
return true; return true;
} }
case operationType::areaIntegrate: case operationType::areaIntegrate:
{ {
const scalarField magSf(mag(Sf)); const scalarField magSf(mag(Sf));
result = gSum(weights*magSf*values);
result = sum(magSf*values);
return true;
}
case operationType::weightedAreaIntegrate:
{
const scalarField magSf(mag(Sf));
if (weightField.size())
{
result = sum(weightField*magSf*values);
}
else
{
result = sum(magSf*values);
}
return true; return true;
} }
case operationType::min: case operationType::min:
{ {
result = min(values); result = gMin(values);
return true; return true;
} }
case operationType::max: case operationType::max:
{ {
result = max(values); result = gMax(values);
return true; return true;
} }
case operationType::CoV: case operationType::CoV:
{ {
const scalarField magSf(mag(Sf)); const scalarField magSf(mag(Sf));
Type meanValue = sum(values*magSf)/sum(magSf); Type meanValue = gSum(values*magSf)/gSum(magSf);
const label nComp = pTraits<Type>::nComponents; const label nComp = pTraits<Type>::nComponents;
@ -279,7 +264,7 @@ processValuesTypeType
scalar mean = component(meanValue, d); scalar mean = component(meanValue, d);
scalar& res = setComponent(result, d); scalar& res = setComponent(result, d);
res = sqrt(sum(magSf*sqr(vals - mean))/sum(magSf))/mean; res = sqrt(gSum(magSf*sqr(vals - mean))/gSum(magSf))/mean;
} }
return true; return true;
@ -302,39 +287,25 @@ template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
( (
const word& fieldName, const word& fieldName,
const scalarField& weightField, const scalarField& signs,
const bool orient const scalarField& weights,
const vectorField& Sf
) )
{ {
const bool ok = validField<Type>(fieldName); const bool ok = validField<Type>(fieldName);
if (ok) if (ok)
{ {
Field<Type> values(getFieldValues<Type>(fieldName, true, orient)); // Get the values
Field<Type> values(getFieldValues<Type>(fieldName));
vectorField Sf;
if (surfacePtr_.valid())
{
// Get oriented Sf
Sf = surfacePtr_().Sf();
}
else
{
// Get oriented Sf
Sf = filterField(mesh_.Sf(), true);
}
// Combine onto master
combineFields(values);
combineFields(Sf);
// Write raw values on surface if specified // Write raw values on surface if specified
if (surfaceWriterPtr_.valid()) if (writeFields_)
{ {
faceList faces; faceList faces;
pointField points; pointField points;
if (surfacePtr_.valid()) if (regionType_ == regionTypes::sampledSurface)
{ {
combineSurfaceGeometry(faces, points); combineSurfaceGeometry(faces, points);
} }
@ -343,6 +314,9 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
combineMeshGeometry(faces, points); combineMeshGeometry(faces, points);
} }
Field<Type> writeValues(weights*values);
combineFields(writeValues);
if (Pstream::master()) if (Pstream::master())
{ {
surfaceWriterPtr_->write surfaceWriterPtr_->write
@ -352,39 +326,41 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
points, points,
faces, faces,
fieldName, fieldName,
values, writeValues,
false false
); );
} }
} }
// Do the operation
if (operation_ != operationType::none) if (operation_ != operationType::none)
{ {
// Apply scale factor // Apply scale factor
values *= scaleFactor_; values *= scaleFactor_;
if (Pstream::master()) bool ok = false;
#define writeValuesFieldType(fieldType, none) \
ok = \
ok \
|| writeValues<Type, fieldType> \
( \
fieldName, \
values, \
signs, \
weights, \
Sf \
);
FOR_ALL_FIELD_TYPES(writeValuesFieldType);
#undef writeValuesFieldType
if (!ok)
{ {
if FatalErrorInFunction
( << "Operation " << operationTypeNames_[operation_]
!writeValues<Type, scalar> << " not available for values of type "
(fieldName, weightField, values, Sf) << pTraits<Type>::typeName
&& !writeValues<Type, vector> << exit(FatalError);
(fieldName, weightField, values, Sf)
&& !writeValues<Type, sphericalTensor>
(fieldName, weightField, values, Sf)
&& !writeValues<Type, symmTensor>
(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);
}
} }
} }
} }
@ -397,23 +373,27 @@ template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
( (
const word& fieldName, const word& fieldName,
const scalarField& weightField,
const Field<Type>& values, const Field<Type>& values,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf const vectorField& Sf
) )
{ {
ResultType result; ResultType result;
if (processValues(values, Sf, weightField, result)) if (processValues(values, signs, weights, Sf, result))
{ {
// Add to result dictionary, over-writing any previous entry // Add to result dictionary, over-writing any previous entry
resultDict_.add(fieldName, result, true); resultDict_.add(fieldName, result, true);
file() << tab << result; if (Pstream::master())
{
file() << tab << result;
Log << " " << operationTypeNames_[operation_] Log << " " << operationTypeNames_[operation_]
<< "(" << regionName_ << ") of " << fieldName << "(" << regionName_ << ") of " << fieldName
<< " = " << result << endl; << " = " << result << endl;
}
return true; return true;
} }
@ -426,8 +406,7 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::surfaceFieldValue::filterField Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
( (
const GeometricField<Type, fvPatchField, volMesh>& field, const GeometricField<Type, fvPatchField, volMesh>& field
const bool applyOrientation
) const ) const
{ {
tmp<Field<Type>> tvalues(new Field<Type>(faceId_.size())); tmp<Field<Type>> tvalues(new Field<Type>(faceId_.size()));
@ -435,8 +414,9 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
forAll(values, i) forAll(values, i)
{ {
label facei = faceId_[i]; const label facei = faceId_[i];
label patchi = facePatchId_[i]; const label patchi = facePatchId_[i];
if (patchi >= 0) if (patchi >= 0)
{ {
values[i] = field.boundaryField()[patchi][facei]; values[i] = field.boundaryField()[patchi][facei];
@ -452,14 +432,6 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
} }
} }
if (applyOrientation)
{
forAll(values, i)
{
values[i] *= faceSign_[i];
}
}
return tvalues; return tvalues;
} }
@ -468,8 +440,7 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::surfaceFieldValue::filterField Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
( (
const GeometricField<Type, fvsPatchField, surfaceMesh>& field, const GeometricField<Type, fvsPatchField, surfaceMesh>& field
const bool applyOrientation
) const ) const
{ {
tmp<Field<Type>> tvalues(new Field<Type>(faceId_.size())); tmp<Field<Type>> tvalues(new Field<Type>(faceId_.size()));
@ -477,8 +448,9 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
forAll(values, i) forAll(values, i)
{ {
label facei = faceId_[i]; const label facei = faceId_[i];
label patchi = facePatchId_[i]; const label patchi = facePatchId_[i];
if (patchi >= 0) if (patchi >= 0)
{ {
values[i] = field.boundaryField()[patchi][facei]; values[i] = field.boundaryField()[patchi][facei];
@ -489,14 +461,6 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::filterField
} }
} }
if (applyOrientation)
{
forAll(values, i)
{
values[i] *= faceSign_[i];
}
}
return tvalues; return tvalues;
} }

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
@ -48,28 +48,26 @@ const char*
Foam::NamedEnum Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::volFieldValue::operationType, Foam::functionObjects::fieldValues::volFieldValue::operationType,
13 11
>::names[] = >::names[] =
{ {
"none", "none",
"sum", "sum",
"weightedSum",
"sumMag", "sumMag",
"average", "average",
"weightedAverage",
"volAverage", "volAverage",
"weightedVolAverage",
"volIntegrate", "volIntegrate",
"weightedVolIntegrate",
"min", "min",
"max", "max",
"minMag",
"maxMag",
"CoV" "CoV"
}; };
const Foam::NamedEnum const Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::volFieldValue::operationType, Foam::functionObjects::fieldValues::volFieldValue::operationType,
13 11
> Foam::functionObjects::fieldValues::volFieldValue::operationTypeNames_; > Foam::functionObjects::fieldValues::volFieldValue::operationTypeNames_;
@ -80,6 +78,8 @@ void Foam::functionObjects::fieldValues::volFieldValue::initialise
const dictionary& dict const dictionary& dict
) )
{ {
dict.readIfPresent<Switch>("writeLocation", writeLocation_);
if (dict.readIfPresent("weightFields", weightFieldNames_)) if (dict.readIfPresent("weightFields", weightFieldNames_))
{ {
Info<< name() << " " << operationTypeNames_[operation_] Info<< name() << " " << operationTypeNames_[operation_]
@ -94,10 +94,57 @@ void Foam::functionObjects::fieldValues::volFieldValue::initialise
<< " weight field " << weightFieldNames_[0]; << " weight field " << weightFieldNames_[0];
} }
if (dict.readIfPresent("scaleFactor", scaleFactor_))
{
Info<< " scale factor = " << scaleFactor_ << nl;
}
Info<< nl << endl; Info<< nl << endl;
} }
template<class Type>
void Foam::functionObjects::fieldValues::volFieldValue::
writeFileHeaderLocation()
{
switch (operation_)
{
case operationType::minMag:
case operationType::maxMag:
file() << tab << "location" << tab << "cell";
if (Pstream::parRun())
{
file() << tab << "processor";
}
break;
default:
break;
}
}
template<>
void Foam::functionObjects::fieldValues::volFieldValue::
writeFileHeaderLocation<Foam::scalar>()
{
switch (operation_)
{
case operationType::min:
case operationType::max:
case operationType::minMag:
case operationType::maxMag:
file() << tab << "location" << tab << "cell";
if (Pstream::parRun())
{
file() << tab << "processor";
}
break;
default:
break;
}
}
void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader
( (
const label i const label i
@ -117,12 +164,54 @@ void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader
} }
file() << fields_[fieldi] << ")"; file() << fields_[fieldi] << ")";
if (writeLocation_)
{
#define writeFileHeaderLocationFieldType(fieldType, none) \
if (validField<fieldType>(fields_[fieldi])) \
{ \
writeFileHeaderLocation<fieldType>(); \
}
FOR_ALL_FIELD_TYPES(writeFileHeaderLocationFieldType)
#undef writeHeaderLocationFieldType
}
} }
file() << endl; file() << endl;
} }
bool Foam::functionObjects::fieldValues::volFieldValue::processValues
(
const Field<scalar>& values,
const scalarField& weights,
const scalarField& V,
Result<scalar>& result
) const
{
switch (operation_)
{
case operationType::min:
case operationType::minMag:
{
opMag(values, result, lessOp<scalar>());
return true;
}
case operationType::max:
case operationType::maxMag:
{
opMag(values, result, greaterOp<scalar>());
return true;
}
default:
{
// Fall through to same-type operations
return processValuesTypeType(values, weights, V, result);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::fieldValues::volFieldValue::volFieldValue Foam::functionObjects::fieldValues::volFieldValue::volFieldValue
@ -134,7 +223,9 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue
: :
fieldValue(name, runTime, dict, typeName), fieldValue(name, runTime, dict, typeName),
volRegion(fieldValue::mesh_, dict), volRegion(fieldValue::mesh_, dict),
operation_(operationTypeNames_.read(dict.lookup("operation"))) writeLocation_(false),
operation_(operationTypeNames_.read(dict.lookup("operation"))),
scaleFactor_(1)
{ {
read(dict); read(dict);
} }
@ -149,7 +240,9 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue
: :
fieldValue(name, obr, dict, typeName), fieldValue(name, obr, dict, typeName),
volRegion(fieldValue::mesh_, dict), volRegion(fieldValue::mesh_, dict),
operation_(operationTypeNames_.read(dict.lookup("operation"))) writeLocation_(false),
operation_(operationTypeNames_.read(dict.lookup("operation"))),
scaleFactor_(1)
{ {
read(dict); read(dict);
} }
@ -186,24 +279,37 @@ bool Foam::functionObjects::fieldValues::volFieldValue::write()
writeTime(file()); writeTime(file());
} }
// Construct the weight field and the volumes
scalarField weights
(
isNull(cellIDs()) ? fieldValue::mesh_.nCells() : cellIDs().size(),
1
);
forAll(weightFieldNames_, i)
{
weights *= getFieldValues<scalar>(weightFieldNames_[i]);
}
const scalarField V(filterField(fieldValue::mesh_.V()));
forAll(fields_, i) forAll(fields_, i)
{ {
const word& fieldName = fields_[i]; const word& fieldName = fields_[i];
bool processed = false; bool ok = false;
#define processType(fieldType, none) \ #define writeValuesFieldType(fieldType, none) \
processed = processed || writeValues<fieldType>(fieldName); ok = ok || writeValues<fieldType>(fieldName, weights, V);
FOR_ALL_FIELD_TYPES(processType) FOR_ALL_FIELD_TYPES(writeValuesFieldType)
#undef writeValuesFieldType
if (!processed) if (!ok)
{ {
cannotFindObject(fieldName); cannotFindObject(fieldName);
} }
} }
if (Pstream::master()) if (operation_ != operationType::none && Pstream::master())
{ {
file()<< endl; file() << endl;
} }
Log << endl; Log << endl;

View File

@ -61,6 +61,7 @@ Usage
type | Type name: volFieldValue | yes | type | Type name: volFieldValue | yes |
log | Write data to standard output | no | no log | Write data to standard output | no | no
writeFields | Write the region field values | yes | writeFields | Write the region field values | yes |
writeLocation| Write the location (if available) | no | no
regionType | volRegion type: see below | yes | regionType | volRegion type: see below | yes |
name | Name of volRegion if required | no | name | Name of volRegion if required | no |
operation | Operation to perform | yes | operation | Operation to perform | yes |
@ -79,16 +80,14 @@ Usage
\plaintable \plaintable
none | No operation none | No operation
sum | Sum sum | Sum
weightedSum | Weighted sum
sumMag | Sum of component magnitudes sumMag | Sum of component magnitudes
average | Ensemble average average | Ensemble average
weightedAverage | Weighted average
volAverage | Volume weighted average volAverage | Volume weighted average
weightedVolAverage | Weighted volume average
volIntegrate | Volume integral volIntegrate | Volume integral
weightedVolIntegrate | Weighted volume integral
min | Minimum min | Minimum
max | Maximum max | Maximum
minMag | Minimum magnitude
maxMag | Maximum magnitude
CoV | Coefficient of variation: standard deviation/mean CoV | Coefficient of variation: standard deviation/mean
\endplaintable \endplaintable
@ -136,33 +135,44 @@ public:
{ {
none, none,
sum, sum,
weightedSum,
sumMag, sumMag,
average, average,
weightedAverage,
volAverage, volAverage,
weightedVolAverage,
volIntegrate, volIntegrate,
weightedVolIntegrate,
min, min,
max, max,
minMag,
maxMag,
CoV CoV
}; };
//- Operation type names //- Operation type names
static const NamedEnum<operationType, 13> operationTypeNames_; static const NamedEnum<operationType, 11> operationTypeNames_;
// Public classes
//- Forward declare the result structure
template<class Type>
struct Result;
protected: protected:
// Protected data // Protected data
//- Write the location if available for this operation - optional
Switch writeLocation_;
//- Operation to apply to values //- Operation to apply to values
operationType operation_; operationType operation_;
//- Weight field names - only used for weighted modes //- Weight field names
wordList weightFieldNames_; wordList weightFieldNames_;
//- Scale factor - optional
scalar scaleFactor_;
// Protected Member Functions // Protected Member Functions
@ -175,21 +185,74 @@ protected:
//- Insert field values into values list //- Insert field values into values list
template<class Type> template<class Type>
tmp<Field<Type>> setFieldValues tmp<Field<Type>> getFieldValues(const word& fieldName) const;
(
const word& fieldName,
const bool mustGet = false
) const;
//- Apply the 'operation' to the values //- Apply a comparison operation (min/max) to the field magnitude,
template<class Type> // returning the limiting value, its index and processor index
Type processValues template<class Type, class Op>
void opMag
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& V, Result<scalar>& result,
const scalarField& weightField const Op& op
) const; ) const;
//- Apply the operation to the values, and return true if successful.
// Does nothing unless overloaded below.
template<class Type, class ResultType>
bool processValues
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<ResultType>& result
) const;
//- Apply Type -> Type operation to the values. Calls
// processValuesTypeType.
template<class Type>
bool processValues
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<Type>& result
) const;
//- Apply Type -> scalar operation to the values
template<class Type>
bool processValues
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<scalar>& result
) const;
//- Apply scalar -> scalar operation to the values. Calls
// processValuesTypeType.
bool processValues
(
const Field<scalar>& values,
const scalarField& weights,
const scalarField& V,
Result<scalar>& result
) const;
//- Apply a Type -> Type operation to the values
template<class Type>
bool processValuesTypeType
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<Type>& result
) const;
//- Output file header location information for a given type
template<class Type>
void writeFileHeaderLocation();
//- Output file header information //- Output file header information
virtual void writeFileHeader(const label i); virtual void writeFileHeader(const label i);
@ -227,7 +290,22 @@ public:
//- Templated helper function to output field values //- Templated helper function to output field values
template<class Type> template<class Type>
bool writeValues(const word& fieldName); bool writeValues
(
const word& fieldName,
const scalarField& weights,
const scalarField& V
);
//- Templated helper function to output field values
template<class Type, class ResultType>
bool writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalarField& weights,
const scalarField& V
);
//- Filter a field according to cellIds //- Filter a field according to cellIds
template<class Type> template<class Type>
@ -241,6 +319,46 @@ public:
}; };
template<>
void volFieldValue::writeFileHeaderLocation<scalar>();
/*---------------------------------------------------------------------------*\
Class volFieldValue::Result Declaration
\*---------------------------------------------------------------------------*/
template<class Type>
struct volFieldValue::Result
{
Type value;
label celli;
label proci;
point cc;
};
template<class Type>
inline Istream& operator>>
(
Istream& is,
volFieldValue::Result<Type>& result
)
{
return is >> result.value >> result.celli >> result.proci >> result.cc;
}
template<class Type>
inline Ostream& operator<<
(
Ostream& os,
const volFieldValue::Result<Type>& result
)
{
return os << result.value << result.celli << result.proci << result.cc;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // 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-2020 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2021 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -47,10 +47,9 @@ bool Foam::functionObjects::fieldValues::volFieldValue::validField
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::volFieldValue::setFieldValues Foam::functionObjects::fieldValues::volFieldValue::getFieldValues
( (
const word& fieldName, const word& fieldName
const bool mustGet
) const ) const
{ {
typedef GeometricField<Type, fvPatchField, volMesh> vf; typedef GeometricField<Type, fvPatchField, volMesh> vf;
@ -60,83 +59,149 @@ Foam::functionObjects::fieldValues::volFieldValue::setFieldValues
return filterField(obr_.lookupObject<vf>(fieldName)); return filterField(obr_.lookupObject<vf>(fieldName));
} }
if (mustGet) FatalErrorInFunction
<< "Field " << fieldName << " not found in database"
<< abort(FatalError);
return tmp<Field<Type>>(nullptr);
}
template<class Type, class Op>
void Foam::functionObjects::fieldValues::volFieldValue::opMag
(
const Field<Type>& values,
Result<scalar>& result,
const Op& op
) const
{
const scalarField magValues(mag(values));
label i = 0;
forAll(magValues, j)
{ {
FatalErrorInFunction if (op(magValues[j], magValues[i]))
<< "Field " << fieldName << " not found in database" {
<< abort(FatalError); i = j;
}
} }
return tmp<Field<Type>>(new Field<Type>(0.0)); result.value = magValues[i];
result.celli = isNull(cellIDs()) ? i : cellIDs()[i];
result.proci = Pstream::parRun() ? Pstream::myProcNo() : -1;
result.cc = fieldValue::mesh_.C()[result.celli];
reduce
(
result,
[&op](const Result<scalar>& a, const Result<scalar>& b)
{
return op(a.value, b.value) ? a : b;
}
);
}
template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::volFieldValue::processValues
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<ResultType>& result
) const
{
return false;
} }
template<class Type> template<class Type>
Type Foam::functionObjects::fieldValues::volFieldValue::processValues bool Foam::functionObjects::fieldValues::volFieldValue::processValues
( (
const Field<Type>& values, const Field<Type>& values,
const scalarField& weights,
const scalarField& V, const scalarField& V,
const scalarField& weightField Result<Type>& result
) const
{
return processValuesTypeType(values, weights, V, result);
}
template<class Type>
bool Foam::functionObjects::fieldValues::volFieldValue::processValues
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<scalar>& result
) const
{
switch (operation_)
{
case operationType::minMag:
{
opMag(values, result, lessOp<scalar>());
return true;
}
case operationType::maxMag:
{
opMag(values, result, greaterOp<scalar>());
return true;
}
default:
{
return false;
}
}
}
template<class Type>
bool Foam::functionObjects::fieldValues::volFieldValue::processValuesTypeType
(
const Field<Type>& values,
const scalarField& weights,
const scalarField& V,
Result<Type>& result
) const ) const
{ {
Type result = Zero;
switch (operation_) switch (operation_)
{ {
case operationType::sum: case operationType::sum:
{ {
result = gSum(values); result.value = gSum(weights*values);
break; return true;
}
case operationType::weightedSum:
{
result = gSum(weightField*values);
break;
} }
case operationType::sumMag: case operationType::sumMag:
{ {
result = gSum(cmptMag(values)); result.value = gSum(cmptMag(values));
break; return true;
} }
case operationType::average: case operationType::average:
{ {
result = gSum(values)/nCells(); result.value = gSum(weights*values)/max(gSum(weights), vSmall);
break; return true;
}
case operationType::weightedAverage:
{
result = gSum(weightField*values)/max(gSum(weightField), vSmall);
break;
} }
case operationType::volAverage: case operationType::volAverage:
{ {
result = gSum(V*values)/this->V(); result.value = gSum(weights*V*values)/max(gSum(weights*V), vSmall);
break; return true;
}
case operationType::weightedVolAverage:
{
result =
gSum(weightField*V*values)/max(gSum(weightField*V), vSmall);
break;
} }
case operationType::volIntegrate: case operationType::volIntegrate:
{ {
result = gSum(V*values); result.value = gSum(weights*V*values);
break; return true;
}
case operationType::weightedVolIntegrate:
{
result = gSum(weightField*V*values);
break;
} }
case operationType::min: case operationType::min:
{ {
result = gMin(values); result.value = gMin(values);
break; return true;
} }
case operationType::max: case operationType::max:
{ {
result = gMax(values); result.value = gMax(values);
break; return true;
} }
case operationType::CoV: case operationType::CoV:
{ {
@ -148,18 +213,22 @@ Type Foam::functionObjects::fieldValues::volFieldValue::processValues
{ {
scalarField vals(values.component(d)); scalarField vals(values.component(d));
scalar mean = component(meanValue, d); scalar mean = component(meanValue, d);
scalar& res = setComponent(result, d); scalar& res = setComponent(result.value, d);
res = sqrt(gSum(V*sqr(vals - mean))/this->V())/mean; res = sqrt(gSum(V*sqr(vals - mean))/this->V())/mean;
} }
break; return true;
} }
case operationType::none: case operationType::none:
{} {
return true;
}
default:
{
return false;
}
} }
return result;
} }
@ -168,36 +237,19 @@ Type Foam::functionObjects::fieldValues::volFieldValue::processValues
template<class Type> template<class Type>
bool Foam::functionObjects::fieldValues::volFieldValue::writeValues bool Foam::functionObjects::fieldValues::volFieldValue::writeValues
( (
const word& fieldName const word& fieldName,
const scalarField& weights,
const scalarField& V
) )
{ {
const bool ok = validField<Type>(fieldName); const bool ok = validField<Type>(fieldName);
if (ok) if (ok)
{ {
Field<Type> values(setFieldValues<Type>(fieldName)); // Get the values
scalarField V(filterField(fieldValue::mesh_.V())); Field<Type> values(getFieldValues<Type>(fieldName));
scalarField weightField(values.size(), 1.0);
forAll(weightFieldNames_, i)
{
weightField *= setFieldValues<scalar>(weightFieldNames_[i], true);
}
Type result = processValues(values, V, weightField);
if (Pstream::master())
{
// Add to result dictionary, over-writing any previous entry
resultDict_.add(fieldName, result, true);
file()<< tab << result;
Log << " " << operationTypeNames_[operation_]
<< "(" << volRegion::regionName_ << ") of " << fieldName
<< " = " << result << endl;
}
// Write raw values if specified
if (writeFields_) if (writeFields_)
{ {
IOField<Type> IOField<Type>
@ -211,15 +263,98 @@ bool Foam::functionObjects::fieldValues::volFieldValue::writeValues
IOobject::NO_READ, IOobject::NO_READ,
IOobject::NO_WRITE IOobject::NO_WRITE
), ),
(weightField*values).ref() (weights*values).ref()
).write(); ).write();
} }
// Do the operation
if (operation_ != operationType::none)
{
// Apply scale factor
values *= scaleFactor_;
bool ok = false;
#define writeValuesFieldType(fieldType, none) \
ok = \
ok \
|| writeValues<Type, fieldType> \
( \
fieldName, \
values, \
weights, \
V \
);
FOR_ALL_FIELD_TYPES(writeValuesFieldType);
#undef writeValuesFieldType
if (!ok)
{
FatalErrorInFunction
<< "Operation " << operationTypeNames_[operation_]
<< " not available for values of type "
<< pTraits<Type>::typeName
<< exit(FatalError);
}
}
} }
return ok; return ok;
} }
template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::volFieldValue::writeValues
(
const word& fieldName,
const Field<Type>& values,
const scalarField& weights,
const scalarField& V
)
{
Result<ResultType> result({Zero, -1, -1, point::uniform(NaN)});
if (processValues(values, weights, V, result))
{
// Add to result dictionary, over-writing any previous entry
resultDict_.add(fieldName, result.value, true);
if (Pstream::master())
{
file() << tab << result.value;
Log << " " << operationTypeNames_[operation_]
<< "(" << volRegion::regionName_ << ") of " << fieldName
<< " = " << result.value;
if (result.celli != -1)
{
Log << " at location " << result.cc;
if (writeLocation_) file() << tab << result.cc;
}
if (result.celli != -1)
{
Log << " in cell " << result.celli;
if (writeLocation_) file() << tab << result.celli;
}
if (result.proci != -1)
{
Log << " on processor " << result.proci;
if (writeLocation_) file() << tab << result.proci;
}
Log << endl;
}
return true;
}
return false;
}
template<class Type> template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::functionObjects::fieldValues::volFieldValue::filterField Foam::functionObjects::fieldValues::volFieldValue::filterField

View File

@ -61,7 +61,7 @@ functions
writeFields no; writeFields no;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedAverage; operation average;
weightField phi; weightField phi;
fields fields

View File

@ -56,7 +56,7 @@ functions
writeFields no; writeFields no;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedAverage; operation average;
weightField phi; weightField phi;
fields fields
( (

View File

@ -57,7 +57,7 @@ functions
writeFields no; writeFields no;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedAverage; operation average;
weightField phi; weightField phi;
fields fields
( (

View File

@ -82,7 +82,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -94,7 +94,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }
@ -106,7 +106,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -118,7 +118,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }

View File

@ -82,7 +82,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -94,7 +94,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }
@ -106,7 +106,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -118,7 +118,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }

View File

@ -121,7 +121,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -133,7 +133,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }
@ -145,7 +145,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -157,7 +157,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }

View File

@ -121,7 +121,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -133,7 +133,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas2; weightField alphaRhoPhi.gas2;
fields ( h.gas2 ); fields ( h.gas2 );
} }
@ -145,7 +145,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name outlet; name outlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }
@ -157,7 +157,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas; weightField alphaRhoPhi.gas;
fields ( h.gas ); fields ( h.gas );
} }
@ -169,7 +169,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.gas2; weightField alphaRhoPhi.gas2;
fields ( h.gas2 ); fields ( h.gas2 );
} }
@ -181,7 +181,7 @@ functions
writeFields false; writeFields false;
regionType patch; regionType patch;
name inlet; name inlet;
operation weightedSum; operation sum;
weightField alphaRhoPhi.liquid; weightField alphaRhoPhi.liquid;
fields ( h.liquid ); fields ( h.liquid );
} }

View File

@ -52,20 +52,8 @@ maxDeltaT 1e-2;
functions functions
{ {
minMax #includeFunc cellMin(T.steam,T.water,p)
{ #includeFunc cellMax(T.steam,T.water,p)
type fieldMinMax;
functionObjectLibs ("libfieldFunctionObjects.so");
fields
(
T.steam
T.water
p
);
location no;
writeControl timeStep;
writeInterval 1;
}
} }