From a4dc9966eda70f06933c541d08d9ef0bfbf3b6a2 Mon Sep 17 00:00:00 2001 From: Andrew Heather <> Date: Fri, 7 Dec 2018 17:24:13 +0000 Subject: [PATCH] ENH: Added new AMIWeights function object Reports the min|max|average AMI weights to text file and optionally writes VTK surfaces of the sum of the weights, and mask field for ACMI patches. Example usage: AMIWeights { type AMIWeights; libs ("libfieldFunctionObjects.so"); writeControl writeTime; writeFields yes; } --- .../postProcessing/fields/AMIWeights | 20 + .../field/AMIWeights/AMIWeights.C | 396 ++++++++++++++++++ .../field/AMIWeights/AMIWeights.H | 163 +++++++ src/functionObjects/field/Make/files | 2 + .../RAS/propeller/system/AMIWeights | 17 + .../RAS/propeller/system/controlDict | 1 + 6 files changed, 599 insertions(+) create mode 100644 etc/caseDicts/postProcessing/fields/AMIWeights create mode 100644 src/functionObjects/field/AMIWeights/AMIWeights.C create mode 100644 src/functionObjects/field/AMIWeights/AMIWeights.H create mode 100644 tutorials/incompressible/pimpleFoam/RAS/propeller/system/AMIWeights diff --git a/etc/caseDicts/postProcessing/fields/AMIWeights b/etc/caseDicts/postProcessing/fields/AMIWeights new file mode 100644 index 00000000000..3bbda0fcc5d --- /dev/null +++ b/etc/caseDicts/postProcessing/fields/AMIWeights @@ -0,0 +1,20 @@ +/*--------------------------------*- C++ -*----------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | Version: v1806 + \\ / A nd | Web: www.OpenFOAM.com + \\/ M anipulation | +------------------------------------------------------------------------------- +Description + Calculates and writes the second largest eigenvalue of the sum of the + square of the symmetrical and anti-symmetrical parts of the velocity + gradient tensor. + +\*---------------------------------------------------------------------------*/ + +type AMIWeights; +libs ("libfieldFunctionObjects.so"); +writeFields yes; +writeControl writeTime; + +// ************************************************************************* // diff --git a/src/functionObjects/field/AMIWeights/AMIWeights.C b/src/functionObjects/field/AMIWeights/AMIWeights.C new file mode 100644 index 00000000000..4f0952442cb --- /dev/null +++ b/src/functionObjects/field/AMIWeights/AMIWeights.C @@ -0,0 +1,396 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "AMIWeights.H" +#include "fvMesh.H" +#include "vtkSurfaceWriter.H" +#include "PatchTools.H" +#include "cyclicACMIPolyPatch.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + defineTypeNameAndDebug(AMIWeights, 0); + addToRunTimeSelectionTable(functionObject, AMIWeights, dictionary); +} +} + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::functionObjects::AMIWeights::writeFileHeader(Ostream& os) +{ + writeHeader(os, "AMI"); + + writeCommented(os, "Time"); + forAll(patchIDs_, patchi) + { + writeTabbed(os, "Patch"); + writeTabbed(os, "nbr_patch"); + + if (Pstream::parRun()) + { + writeTabbed(os, "distributed"); + } + + writeTabbed(os, "src_min_weight"); + writeTabbed(os, "src_max_weight"); + writeTabbed(os, "src_average_weight"); + writeTabbed(os, "src_min_neighbours"); + writeTabbed(os, "src_max_neighbours"); + writeTabbed(os, "src_average_neighbours"); + writeTabbed(os, "tgt_min_weight"); + writeTabbed(os, "tgt_max_weight"); + writeTabbed(os, "tgt_average_weight"); + writeTabbed(os, "tgt_min_neighbours"); + writeTabbed(os, "tgt_max_neighbours"); + writeTabbed(os, "tgt_average_neighbours"); + } + + os << endl; +} + + +void Foam::functionObjects::AMIWeights::reportPatch +( + const cyclicAMIPolyPatch& pp +) +{ + const word& nbrPatchName = pp.neighbPatchName(); + + const Switch distributed = pp.AMI().singlePatchProc() == -1; + + const scalarField& srcWeightsSum = pp.AMI().srcWeightsSum(); + const scalar srcMinWeight = gMin(srcWeightsSum); + const scalar srcMaxWeight = gMax(srcWeightsSum); + const scalar srcAveWeight = gAverage(srcWeightsSum); + + const labelListList& srcAddress = pp.AMI().srcAddress(); + label srcMinNbr = labelMax; + label srcMaxNbr = labelMin; + scalar srcAveNbr = 0; + for (const labelList& srcFace : srcAddress) + { + const label n = srcFace.size(); + srcAveNbr += n; + srcMinNbr = min(srcMinNbr, n); + srcMaxNbr = max(srcMaxNbr, n); + } + + reduce(srcMinNbr, minOp<label>()); + reduce(srcMaxNbr, maxOp<label>()); + + srcAveNbr = + returnReduce(srcAveNbr, sumOp<scalar>()) + /(returnReduce(srcAddress.size(), sumOp<scalar>()) + ROOTVSMALL); + + const scalarField& tgtWeightsSum = pp.AMI().tgtWeightsSum(); + const scalar tgtMinWeight = gMin(tgtWeightsSum); + const scalar tgtMaxWeight = gMax(tgtWeightsSum); + const scalar tgtAveWeight = gAverage(tgtWeightsSum); + + const labelListList& tgtAddress = pp.AMI().tgtAddress(); + label tgtMinNbr = labelMax; + label tgtMaxNbr = labelMin; + scalar tgtAveNbr = 0; + for (const labelList& tgtFace : tgtAddress) + { + const label n = tgtFace.size(); + tgtAveNbr += n; + tgtMinNbr = min(tgtMinNbr, n); + tgtMaxNbr = max(tgtMaxNbr, n); + } + + reduce(tgtMinNbr, minOp<label>()); + reduce(tgtMaxNbr, maxOp<label>()); + + tgtAveNbr = + returnReduce(tgtAveNbr, sumOp<scalar>()) + /(returnReduce(tgtAddress.size(), sumOp<scalar>()) + ROOTVSMALL); + + file() + << mesh_.time().timeName() << tab + << pp.name() << tab + << nbrPatchName << tab; + + + if (Pstream::parRun()) + { + file() << distributed << tab; + } + + file() + << srcMinWeight << tab + << srcMaxWeight << tab + << srcAveWeight << tab + << srcMinNbr << tab + << srcMaxNbr << tab + << srcAveNbr << tab + << tgtMinWeight << tab + << tgtMaxWeight << tab + << tgtAveWeight << tab + << tgtMinNbr << tab + << tgtMaxNbr << tab + << tgtAveNbr << tab + << endl; + + Log << " Patches: " << nl + << " Source: " << pp.name() << nl + << " Target: " << nbrPatchName << nl; + + if (Pstream::parRun()) + { + Log << " Parallel distributed: " << distributed << nl; + } + + Log << nl; + + const label w = IOstream::defaultPrecision() + 8; + + Log << " | " << setw(w) << pp.name() + << " | " << setw(w) << nbrPatchName << " | " << nl + << " min(weight) | " << setw(w) << srcMinWeight + << " | " << setw(w) << tgtMinWeight << " | " << nl + << " max(weight) | " << setw(w) << srcMaxWeight + << " | " << setw(w) << tgtMaxWeight << " | " << nl + << " ave(weight) | " << setw(w) << srcAveWeight + << " | " << setw(w) << tgtAveWeight << " | " << nl + << " min(address) | " << setw(w) << srcMinNbr + << " | " << setw(w) << tgtMinNbr << " | " << nl + << " max(address) | " << setw(w) << srcMaxNbr + << " | " << setw(w) << tgtMaxNbr << " | " << nl + << " ave(address) | " << setw(w) << srcAveNbr + << " | " << setw(w) << tgtAveNbr << " | " << nl + << endl; + + setResult(pp.name() + ":src", pp.name()); + setResult(pp.name() + ":tgt", nbrPatchName); + setResult(pp.name() + ":src:min(weight)", srcMinWeight); + setResult(pp.name() + ":src:max(weight)", srcMaxWeight); + setResult(pp.name() + ":src:ave(weight)", srcAveWeight); + setResult(pp.name() + ":src:min(address)", srcMinNbr); + setResult(pp.name() + ":src:max(address)", srcMaxNbr); + setResult(pp.name() + ":src:ave(address)", srcAveNbr); + setResult(pp.name() + ":tgt:min(weight)", tgtMinWeight); + setResult(pp.name() + ":tgt:max(weight)", tgtMaxWeight); + setResult(pp.name() + ":tgt:ave(weight)", tgtAveWeight); + setResult(pp.name() + ":tgt:min(address)", tgtMinNbr); + setResult(pp.name() + ":tgt:max(address)", tgtMaxNbr); + setResult(pp.name() + ":tgt:ave(address)", tgtAveNbr); +} + + +void Foam::functionObjects::AMIWeights::writeWeightField +( + const cyclicAMIPolyPatch& cpp, + const scalarField& weightSum, + const word& side +) const +{ + vtkSurfaceWriter writer; + + // Collect geometry + labelList pointToGlobal; + labelList uniqueMeshPointLabels; + autoPtr<globalIndex> globalPoints; + autoPtr<globalIndex> globalFaces; + faceList mergedFaces; + pointField mergedPoints; + Foam::PatchTools::gatherAndMerge + ( + mesh_, + cpp.localFaces(), + cpp.meshPoints(), + cpp.meshPointMap(), + + pointToGlobal, + uniqueMeshPointLabels, + globalPoints, + globalFaces, + + mergedFaces, + mergedPoints + ); + + // Collect field + scalarField mergedWeights; + globalFaces().gather + ( + UPstream::worldComm, + ListOps::create<label> + ( + UPstream::procID(UPstream::worldComm), + labelOp<int>() // int -> label + ), + weightSum, + mergedWeights + ); + + if (Pstream::master()) + { + writer.write + ( + baseTimeDir(), + cpp.name() + "_" + side, + meshedSurfRef(mergedPoints, mergedFaces), + "weightsSum", + mergedWeights, + false + ); + } + + if (isA<cyclicACMIPolyPatch>(cpp)) + { + const cyclicACMIPolyPatch& pp = refCast<const cyclicACMIPolyPatch>(cpp); + scalarField mergedMask; + globalFaces().gather + ( + UPstream::worldComm, + ListOps::create<label> + ( + UPstream::procID(UPstream::worldComm), + labelOp<int>() // int -> label + ), + pp.mask(), + mergedMask + ); + + if (Pstream::master()) + { + writer.write + ( + baseTimeDir(), + cpp.name() + "_" + side, + meshedSurfRef(mergedPoints, mergedFaces), + "mask", + mergedMask, + false + ); + } + } +} + + +void Foam::functionObjects::AMIWeights::writeWeightFields +( + const cyclicAMIPolyPatch& cpp +) const +{ + if (cpp.owner()) + { + writeWeightField(cpp, cpp.AMI().srcWeightsSum(), "src"); + writeWeightField(cpp.neighbPatch(), cpp.AMI().tgtWeightsSum(), "tgt"); + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::AMIWeights::AMIWeights +( + const word& name, + const Time& runTime, + const dictionary& dict +) +: + fvMeshFunctionObject(name, runTime, dict), + writeFile(mesh_, name, typeName, dict), + writeFields_(false), + patchIDs_() +{ + read(dict); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::functionObjects::AMIWeights::read(const dictionary& dict) +{ + if (fvMeshFunctionObject::read(dict) && writeFile::read(dict)) + { + const polyBoundaryMesh& pbm = mesh_.boundaryMesh(); + + patchIDs_.clear(); + labelHashSet ids; + forAll(pbm, patchi) + { + if (isA<cyclicAMIPolyPatch>(pbm[patchi])) + { + const auto& ami = + static_cast<const cyclicAMIPolyPatch&>(pbm[patchi]); + + if (ami.owner()) + { + ids.insert(patchi); + } + } + } + + patchIDs_ = ids.sortedToc(); + + writeFileHeader(file()); + + writeFields_ = dict.get<bool>("writeFields"); + + return true; + } + + return false; +} + + +bool Foam::functionObjects::AMIWeights::execute() +{ + return true; +} + + +bool Foam::functionObjects::AMIWeights::write() +{ + Log << type() << " " << name() << " write:" << nl; + + const polyBoundaryMesh& pbm = mesh_.boundaryMesh(); + for (const label patchi : patchIDs_) + { + const polyPatch& pp = pbm[patchi]; + const auto& cpp = static_cast<const cyclicAMIPolyPatch&>(pp); + + reportPatch(cpp); + + if (writeFields_) + { + writeWeightFields(cpp); + } + } + + + return true; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/field/AMIWeights/AMIWeights.H b/src/functionObjects/field/AMIWeights/AMIWeights.H new file mode 100644 index 00000000000..bebbd0dcc78 --- /dev/null +++ b/src/functionObjects/field/AMIWeights/AMIWeights.H @@ -0,0 +1,163 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::functionObjects::AMIWeights + +Group + grpFieldFunctionObjects + +Description + +Usage + Example of function object specification: + \verbatim + AMIWeights1 + { + type AMIWeights; + libs ("libfieldFunctionObjects.so"); + writeFields yes; + } + \endverbatim + + Where the entries comprise: + \table + Property | Description | Required | Default value + type | type name: AMIWeights | yes | + writeFields | write weights as VTK fields | yes | + \endtable + + Output data is written to the file \<timeDir\>/AMIWeights.dat + +See also + Foam::functionObjects::fvMeshFunctionObject + Foam::functionObjects::writeFile + +SourceFiles + AMIWeights.C + AMIWeightsTemplates.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_AMIWeights_H +#define functionObjects_AMIWeights_H + +#include "fvMeshFunctionObject.H" +#include "writeFile.H" +#include "cyclicAMIPolyPatch.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + +/*---------------------------------------------------------------------------*\ + Class AMIWeights Declaration +\*---------------------------------------------------------------------------*/ + +class AMIWeights +: + public fvMeshFunctionObject, + public writeFile +{ +protected: + + // Protected data + + //- Flag to write AMI fields (as VTK files) + bool writeFields_; + + //- List of AMI patch IDs + labelList patchIDs_; + + + // Protected Member Functions + + //- Output file header information + virtual void writeFileHeader(Ostream& os); + + //- Helper function to report patch information + virtual void reportPatch(const cyclicAMIPolyPatch& pp); + + void writeWeightField + ( + const cyclicAMIPolyPatch& cpp, + const scalarField& weightSum, + const word& side + ) const; + + void writeWeightFields(const cyclicAMIPolyPatch& cpp) const; + + //- No copy construct + AMIWeights(const AMIWeights&) = delete; + + //- No copy assignment + void operator=(const AMIWeights&) = delete; + + +public: + + //- Runtime type information + TypeName("AMIWeights"); + + + // Constructors + + //- Construct from Time and dictionary + AMIWeights + ( + const word& name, + const Time& runTime, + const dictionary& dict + ); + + + //- Destructor + virtual ~AMIWeights() = default; + + + // Member Functions + + //- Read the field min/max data + virtual bool read(const dictionary&); + + //- Execute, currently does nothing + virtual bool execute(); + + //- Write the AMIWeights + virtual bool write(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files index d5aa38ee3dd..fbbac57cb6d 100644 --- a/src/functionObjects/field/Make/files +++ b/src/functionObjects/field/Make/files @@ -1,3 +1,5 @@ +AMIWeights/AMIWeights.C + fieldAverage/fieldAverage.C fieldAverage/fieldAverageItem/fieldAverageItem.C fieldAverage/fieldAverageItem/fieldAverageItemIO.C diff --git a/tutorials/incompressible/pimpleFoam/RAS/propeller/system/AMIWeights b/tutorials/incompressible/pimpleFoam/RAS/propeller/system/AMIWeights new file mode 100644 index 00000000000..10a3a902c03 --- /dev/null +++ b/tutorials/incompressible/pimpleFoam/RAS/propeller/system/AMIWeights @@ -0,0 +1,17 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1806 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +AMIWeights +{ + type AMIWeights; + libs ("libfieldFunctionObjects.so"); + writeControl writeTime; + writeFields no; +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/pimpleFoam/RAS/propeller/system/controlDict b/tutorials/incompressible/pimpleFoam/RAS/propeller/system/controlDict index 92a90406da2..507be631bb1 100644 --- a/tutorials/incompressible/pimpleFoam/RAS/propeller/system/controlDict +++ b/tutorials/incompressible/pimpleFoam/RAS/propeller/system/controlDict @@ -57,6 +57,7 @@ functions #includeFunc Q #include "surfaces" #include "forces" + #include "AMIWeights" } // ************************************************************************* // -- GitLab