surfaceFieldValue: Added the ability to specify multiple patches

The 'select' control can now take the value 'patches' in which case a
'patches' control will be used to specify a list of patches, rather than
just a single patch. The 'patches' and 'patch' controls now also both
support wildcards.
This commit is contained in:
Will Bainbridge
2024-08-04 14:02:16 +01:00
parent bb6f2ab003
commit 74a1c352b2
4 changed files with 247 additions and 308 deletions

View File

@ -55,11 +55,12 @@ template<>
const char* Foam::NamedEnum const char* Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypes, Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypes,
3 4
>::names[] = >::names[] =
{ {
"faceZone", "faceZone",
"patch", "patch",
"patches",
"sampledSurface" "sampledSurface"
}; };
@ -89,7 +90,7 @@ const char* Foam::NamedEnum
const Foam::NamedEnum const Foam::NamedEnum
< <
Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypes, Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypes,
3 4
> Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypeNames; > Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypeNames;
const Foam::NamedEnum const Foam::NamedEnum
@ -101,21 +102,26 @@ const Foam::NamedEnum
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces() void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces
(
const word& zoneName
)
{ {
label zoneId = mesh_.faceZones().findIndex(selectionName_); const label zoneId = mesh_.faceZones().findIndex(zoneName);
if (zoneId < 0) if (zoneId < 0)
{ {
FatalErrorInFunction FatalErrorInFunction
<< type() << " " << name() << ": " << type() << " " << name() << ": "
<< selectionTypeNames[selectionType_] << selectionTypeNames[selectionType_]
<< "(" << selectionName_ << "):" << nl << "(" << zoneName << "):" << nl
<< " Unknown face zone name: " << selectionName_ << " Unknown face zone name: " << zoneName
<< ". Valid face zones are: " << mesh_.faceZones().toc() << ". Valid face zones are: " << mesh_.faceZones().toc()
<< nl << exit(FatalError); << nl << exit(FatalError);
} }
selectionName_ = zoneName;
// Ensure addressing is built on all processes // Ensure addressing is built on all processes
mesh_.polyBFacePatches(); mesh_.polyBFacePatches();
mesh_.polyBFacePatchFaces(); mesh_.polyBFacePatchFaces();
@ -172,44 +178,45 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
} }
void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces() void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchesFaces
(
const labelList& patchis
)
{ {
const label patchId = mesh_.boundaryMesh().findIndex(selectionName_); selectionName_.clear();
if (patchId < 0) faceId_.clear();
{ facePatchId_.clear();
FatalErrorInFunction faceSign_.clear();
<< type() << " " << name() << ": "
<< selectionTypeNames[selectionType_] forAll(patchis, i)
<< "(" << selectionName_ << "):" << nl
<< " Unknown patch name: " << selectionName_
<< ". Valid patch names are: "
<< mesh_.boundaryMesh().names() << nl
<< exit(FatalError);
}
const fvPatch& fvp = mesh_.boundary()[patchId];
faceId_ = identityMap(fvp.size());
facePatchId_ = labelList(fvp.size(), patchId);
faceSign_ = labelList(fvp.size(), 1);
// If we have selected a cyclic, also include any associated processor
// cyclic faces
forAll(mesh_.boundary(), patchi)
{ {
const label patchi = patchis[i];
const fvPatch& fvp = mesh_.boundary()[patchi]; const fvPatch& fvp = mesh_.boundary()[patchi];
if selectionName_.append((i ? " " : "") + fvp.name());
(
isA<processorCyclicFvPatch>(fvp) faceId_.append(identityMap(fvp.size()));
&& refCast<const processorCyclicFvPatch>(fvp).referPatchIndex() facePatchId_.append(labelList(fvp.size(), patchi));
== patchId faceSign_.append(labelList(fvp.size(), 1));
)
// If we have selected a cyclic, also include any associated processor
// cyclic faces
forAll(mesh_.boundary(), pcPatchj)
{ {
faceId_.append(identityMap(fvp.size())); const fvPatch& pcFvp = mesh_.boundary()[pcPatchj];
facePatchId_.append(labelList(fvp.size(), patchi));
faceSign_.append(labelList(fvp.size(), 1)); if
(
isA<processorCyclicFvPatch>(pcFvp)
&& refCast<const processorCyclicFvPatch>(pcFvp).referPatchIndex()
== patchi
)
{
faceId_.append(identityMap(pcFvp.size()));
facePatchId_.append(labelList(pcFvp.size(), pcPatchj));
faceSign_.append(labelList(pcFvp.size(), 1));
}
} }
} }
@ -217,18 +224,61 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
} }
void Foam::functionObjects::fieldValues::surfaceFieldValue::sampledSurfaceFaces void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchesFaces
(
const wordReList& patchNames
)
{
labelList patchis;
forAll(patchNames, i)
{
const labelList patchiis =
mesh_.boundaryMesh().findIndices(patchNames[i]);
if (patchiis.empty())
{
FatalErrorInFunction
<< type() << " " << this->name() << ": "
<< selectionTypeNames[selectionType_]
<< "(" << patchNames[i] << "):" << nl
<< " Unknown patch name: " << patchNames[i]
<< ". Valid patch names are: "
<< mesh_.boundaryMesh().names() << nl
<< exit(FatalError);
}
patchis.append(patchiis);
}
setPatchesFaces(patchis);
}
void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces
(
const wordRe& patchName
)
{
setPatchesFaces(wordReList(1, patchName));
selectionName_ =
patchName.isPattern() ? '"' + patchName + '"' : string(patchName);
}
void
Foam::functionObjects::fieldValues::surfaceFieldValue::setSampledSurfaceFaces
( (
const dictionary& dict const dictionary& dict
) )
{ {
surfacePtr_ = sampledSurface::New surfacePtr_ = sampledSurface::New(name(), mesh_, dict);
(
name(),
mesh_,
dict.subDict("sampledSurfaceDict")
);
surfacePtr_().update(); surfacePtr_().update();
selectionName_ = surfacePtr_().name();
nFaces_ = returnReduce(surfacePtr_().faces().size(), sumOp<label>()); nFaces_ = returnReduce(surfacePtr_().faces().size(), sumOp<label>());
} }
@ -419,21 +469,28 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
{ {
case selectionTypes::faceZone: case selectionTypes::faceZone:
{ {
dict.lookupBackwardsCompatible({"faceZone", "name"}) setFaceZoneFaces
>> selectionName_; (
setFaceZoneFaces(); dict.lookupBackwardsCompatible<word>({"faceZone", "name"})
);
break; break;
} }
case selectionTypes::patch: case selectionTypes::patch:
{ {
dict.lookupBackwardsCompatible({"patch", "name"}) >> selectionName_; setPatchFaces
setPatchFaces(); (
dict.lookupBackwardsCompatible<wordRe>({"patch", "name"})
);
break;
}
case selectionTypes::patches:
{
setPatchesFaces(dict.lookup<wordReList>("patches"));
break; break;
} }
case selectionTypes::sampledSurface: case selectionTypes::sampledSurface:
{ {
sampledSurfaceFaces(dict); setSampledSurfaceFaces(dict.subDict("sampledSurfaceDict"));
selectionName_ = surfacePtr_().name();
break; break;
} }
default: default:
@ -441,7 +498,6 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
FatalErrorInFunction FatalErrorInFunction
<< type() << " " << name() << ": " << type() << " " << name() << ": "
<< selectionTypeNames[selectionType_] << selectionTypeNames[selectionType_]
<< "(" << selectionName_ << "):" << nl
<< " Unknown selection type. Valid selection types are:" << " Unknown selection type. Valid selection types are:"
<< selectionTypeNames.sortedToc() << nl << exit(FatalError); << selectionTypeNames.sortedToc() << nl << exit(FatalError);
} }
@ -452,7 +508,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
FatalErrorInFunction FatalErrorInFunction
<< type() << " " << name() << ": " << type() << " " << name() << ": "
<< selectionTypeNames[selectionType_] << selectionTypeNames[selectionType_]
<< "(" << selectionName_ << "):" << nl << "(" << selectionName_.c_str() << "):" << nl
<< " selection has no faces" << exit(FatalError); << " selection has no faces" << exit(FatalError);
} }
@ -509,10 +565,10 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
{ {
if (operation_ != operationType::none) if (operation_ != operationType::none)
{ {
writeCommented(file(), "Selection type : "); writeCommented(file(), "Selection : ");
file() file()
<< selectionTypeNames[selectionType_] << " " << selectionTypeNames[selectionType_] << "("
<< selectionName_ << endl; << selectionName_.c_str() << ")" << endl;
writeCommented(file(), "Faces : "); writeCommented(file(), "Faces : ");
file() << nFaces_ << endl; file() << nFaces_ << endl;
writeCommented(file(), "Area : "); writeCommented(file(), "Area : ");
@ -612,7 +668,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
dict.lookupBackwardsCompatible({"select", "regionType"}) dict.lookupBackwardsCompatible({"select", "regionType"})
) )
), ),
selectionName_(word::null), selectionName_(string::null),
operation_(operationTypeNames_.read(dict.lookup("operation"))), operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldNames_(), weightFieldNames_(),
scaleFactor_(1), scaleFactor_(1),
@ -642,7 +698,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
dict.lookupBackwardsCompatible({"select", "regionType"}) dict.lookupBackwardsCompatible({"select", "regionType"})
) )
), ),
selectionName_(word::null), selectionName_(string::null),
operation_(operationTypeNames_.read(dict.lookup("operation"))), operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldNames_(), weightFieldNames_(),
scaleFactor_(1), scaleFactor_(1),
@ -721,33 +777,6 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
Log << " total area = " << totalArea_ << endl; Log << " total area = " << totalArea_ << endl;
} }
// Write the surface geometry
if (writeFields_)
{
faceList faces;
pointField points;
if (selectionType_ == selectionTypes::sampledSurface)
{
combineSurfaceGeometry(faces, points);
}
else
{
combineMeshGeometry(faces, points);
}
if (Pstream::master())
{
surfaceWriterPtr_->write
(
outputDir(),
selectionTypeNames[selectionType_] + ("_" + selectionName_),
points,
faces
);
}
}
// Construct the sign and weight fields and the surface normals // Construct the sign and weight fields and the surface normals
const scalarField signs const scalarField signs
( (
@ -767,14 +796,49 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
: (signs*filterField(mesh_.Sf()))() : (signs*filterField(mesh_.Sf()))()
); );
// Process the fields // Create storage for the values
#define DeclareValues(fieldType, nullArg) \
PtrList<Field<fieldType>> fieldType##Values(fields_.size());
FOR_ALL_FIELD_TYPES(DeclareValues);
#undef DeclareValues
// Process the fields in turn. Get the values and store if necessary.
// Compute the operation and write into the file and the log.
forAll(fields_, i) forAll(fields_, i)
{ {
const word& fieldName = fields_[i]; const word& fieldName = fields_[i];
bool ok = false; bool ok = false;
#define writeValuesFieldType(fieldType, none) \ #define writeValuesFieldType(fieldType, none) \
ok = ok || writeValues<fieldType>(fieldName, signs, weights, Sf); { \
const bool typeOk = validField<fieldType>(fieldName); \
\
if (typeOk) \
{ \
tmp<Field<fieldType>> values = \
getFieldValues<fieldType>(fieldName); \
\
writeValues<fieldType> \
( \
fieldName, \
values(), \
signs, \
weights, \
Sf \
); \
\
if (writeFields_) \
{ \
fieldType##Values.set \
( \
i, \
getFieldValues<fieldType>(fieldName).ptr() \
); \
} \
} \
\
ok = ok || typeOk; \
}
FOR_ALL_FIELD_TYPES(writeValuesFieldType); FOR_ALL_FIELD_TYPES(writeValuesFieldType);
#undef writeValuesFieldType #undef writeValuesFieldType
@ -784,13 +848,53 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
} }
} }
// Finalise // Finalise the file and the log
if (anyFields && operation_ != operationType::none && Pstream::master()) if (anyFields && operation_ != operationType::none && Pstream::master())
{ {
file() << endl; file() << endl;
} }
Log << endl; Log << endl;
// Write a surface file with the values if specified
if (writeFields_)
{
faceList faces;
pointField points;
if (selectionType_ == selectionTypes::sampledSurface)
{
combineSurfaceGeometry(faces, points);
}
else
{
combineMeshGeometry(faces, points);
}
if (Pstream::master())
{
surfaceWriterPtr_->write
(
baseFileDir()/name()/time_.name(),
word(selectionTypeNames[selectionType_])
+ "("
+ (
selectionType_ == selectionTypes::patches
? selectionName_.replace(" ", ",").c_str()
: selectionName_
)
+ ")",
points,
faces,
fields_,
false
#define ValuesParameter(fieldType, nullArg) \
, fieldType##Values
FOR_ALL_FIELD_TYPES(ValuesParameter)
#undef ValuesParameter
);
}
}
return true; return true;
} }

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-2023 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -191,11 +191,12 @@ public:
{ {
faceZone, faceZone,
patch, patch,
patches,
sampledSurface sampledSurface
}; };
//- Selection type names //- Selection type names
static const NamedEnum<selectionTypes, 3> selectionTypeNames; static const NamedEnum<selectionTypes, 4> selectionTypeNames;
//- Operation type enumeration //- Operation type enumeration
@ -226,13 +227,19 @@ private:
// Private Member Functions // Private Member Functions
//- Set faces to evaluate based on a face zone //- Set faces to evaluate based on a face zone
void setFaceZoneFaces(); void setFaceZoneFaces(const word&);
//- Set faces to evaluate based on a patch //- Set faces to evaluate based on a list of patch indices
void setPatchFaces(); void setPatchesFaces(const labelList&);
//- Set faces to evaluate based on a list of patch names
void setPatchesFaces(const wordReList&);
//- Set faces to evaluate based on a patch name
void setPatchFaces(const wordRe&);
//- Set faces according to sampledSurface //- Set faces according to sampledSurface
void sampledSurfaceFaces(const dictionary&); void setSampledSurfaceFaces(const dictionary&);
//- Combine mesh faces and points from multiple processors //- Combine mesh faces and points from multiple processors
void combineMeshGeometry void combineMeshGeometry
@ -266,7 +273,7 @@ protected:
selectionTypes selectionType_; selectionTypes selectionType_;
//- Name of face selection (patch, faceZone, etc.) //- Name of face selection (patch, faceZone, etc.)
word selectionName_; string selectionName_;
//- Operation to apply to values //- Operation to apply to values
operationType operation_; operationType operation_;
@ -424,37 +431,9 @@ public:
// Public Member Functions // Public Member Functions
//- Return the selection type
inline const selectionTypes& selectionType() const;
//- Return the selection name
inline const word& selectionName() const;
//- Return the local list of face IDs
inline const labelList& faceId() const;
//- Return the local list of patch ID per face
inline const labelList& facePatch() const;
//- Return the list of +1/-1 representing face flip map
inline const labelList& faceSign() const;
//- Return the output directory
inline fileName outputDir() const;
//- Templated helper function to output field values //- Templated helper function to output field values
template<class Type> template<class Type>
bool writeValues void writeValues
(
const word& fieldName,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf
);
//- Templated helper function to output field values
template<class Type, class ResultType>
bool writeValues
( (
const word& fieldName, const word& fieldName,
const Field<Type>& values, const Field<Type>& values,
@ -505,10 +484,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "surfaceFieldValueI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository #ifdef NoRepository
#include "surfaceFieldValueTemplates.C" #include "surfaceFieldValueTemplates.C"
#endif #endif

View File

@ -1,74 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 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 "surfaceFieldValue.H"
#include "Time.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline
const Foam::functionObjects::fieldValues::surfaceFieldValue::selectionTypes&
Foam::functionObjects::fieldValues::surfaceFieldValue::selectionType() const
{
return selectionType_;
}
inline const Foam::word&
Foam::functionObjects::fieldValues::surfaceFieldValue::selectionName() const
{
return selectionName_;
}
inline const Foam::labelList&
Foam::functionObjects::fieldValues::surfaceFieldValue::faceId() const
{
return faceId_;
}
inline const Foam::labelList&
Foam::functionObjects::fieldValues::surfaceFieldValue::facePatch() const
{
return facePatchId_;
}
inline const Foam::labelList&
Foam::functionObjects::fieldValues::surfaceFieldValue::faceSign() const
{
return faceSign_;
}
inline Foam::fileName
Foam::functionObjects::fieldValues::surfaceFieldValue::outputDir() const
{
return baseFileDir()/name()/"surface"/time_.name();
}
// ************************************************************************* //

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-2023 OpenFOAM Foundation \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
@ -282,95 +282,7 @@ processValuesTypeType
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type> template<class Type>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues void Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
(
const word& fieldName,
const scalarField& signs,
const scalarField& weights,
const vectorField& Sf
)
{
const bool ok = validField<Type>(fieldName);
if (ok)
{
// Get the values
Field<Type> values(getFieldValues<Type>(fieldName));
// Write raw values on surface if specified
if (writeFields_)
{
faceList faces;
pointField points;
if (selectionType_ == selectionTypes::sampledSurface)
{
combineSurfaceGeometry(faces, points);
}
else
{
combineMeshGeometry(faces, points);
}
Field<Type> writeValues(weights*values);
combineFields(writeValues);
if (Pstream::master())
{
surfaceWriterPtr_->write
(
outputDir(),
fieldName
+ '_' + selectionTypeNames[selectionType_]
+ '_' + selectionName_,
points,
faces,
false,
fieldName,
writeValues
);
}
}
// 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, \
signs, \
weights, \
Sf \
);
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;
}
template<class Type, class ResultType>
bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
( (
const word& fieldName, const word& fieldName,
const Field<Type>& values, const Field<Type>& values,
@ -379,26 +291,48 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::writeValues
const vectorField& Sf const vectorField& Sf
) )
{ {
ResultType result; // Do the operation
if (operation_ != operationType::none)
if (processValues(values, signs, weights, Sf, result))
{ {
// Add to result dictionary, over-writing any previous entry bool ok = false;
resultDict_.add(fieldName, result, true);
if (Pstream::master()) #define writeValuesFieldType(fieldType, none) \
{ { \
file() << tab << result; fieldType result; \
\
Log << " " << operationTypeNames_[operation_] const bool typeOk = \
<< "(" << selectionName_ << ") of " << fieldName processValues(values, signs, weights, Sf, result); \
<< " = " << result << endl; \
if (typeOk) \
{ \
/* Add to result dictionary, over-writing any previous entry */\
resultDict_.add(fieldName, result, true); \
\
/* Write into the file and the log */ \
if (Pstream::master()) \
{ \
file() << tab << result; \
\
Log << " " << operationTypeNames_[operation_] \
<< "(" << selectionName_ << ") of " << fieldName \
<< " = " << result << endl; \
} \
} \
\
ok = ok || typeOk; \
} }
FOR_ALL_FIELD_TYPES(writeValuesFieldType);
#undef writeValuesFieldType
return true; if (!ok)
{
FatalErrorInFunction
<< "Operation " << operationTypeNames_[operation_]
<< " not available for values of type "
<< pTraits<Type>::typeName
<< exit(FatalError);
}
} }
return false;
} }