functionObjects: Added patchCutLayerAverage
This function object writes graphs of patch face values, area-averaged in
planes perpendicular to a given direction. It adaptively grades the
distribution of graph points to match the resolution of the mesh.
Example of function object specification:
patchCutLayerAverage1
{
type patchCutLayerAverage;
libs ("libpatchCutLayerAverageFunctionObject.so");
writeControl writeTime;
writeInterval 1;
patch lowerWall;
direction (1 0 0);
nPoints 100;
interpolate no;
fields (p U);
axis x;
setFormat raw;
}
A packaged function object is also included, which permits the following
syntax to be used, either with #includeFunc in the system/controlDict,
or with the -func option to foamPostProcess:
graphPatchCutLayerAverage
(
funcName=aerofoilLowerPressure,
patch=aerofoilLower,
direction=(0.15 -0.016 0),
nPoints=100,
p
)
This commit is contained in:
@ -0,0 +1,37 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Version: dev
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Description
|
||||||
|
Writes graphs of patch face values, area-averaged in planes perpendicular
|
||||||
|
to a given direction. It adaptively grades the distribution of graph points
|
||||||
|
to match the resolution of the mesh.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
patch <patchName>; // Patch on which to average values
|
||||||
|
|
||||||
|
direction <direction>; // Direction along which to graph
|
||||||
|
|
||||||
|
nPoints <nPoints>; // Number of points in the graph
|
||||||
|
|
||||||
|
interpolate no; // Whether or not to do linear interpolation
|
||||||
|
// between the plot points. Generates a smoother,
|
||||||
|
// higher order result. Loses the ability to
|
||||||
|
// visualise and reason about the layer
|
||||||
|
// thicknesses.
|
||||||
|
|
||||||
|
axis default; // The independent variable of the graph. Can be
|
||||||
|
// "x", "y", "z", "xyz" (all coordinates written
|
||||||
|
// out), "distance" (plane distance from the
|
||||||
|
// origin), or "default" (both coordinates and
|
||||||
|
// distance written out).
|
||||||
|
|
||||||
|
fields (<fieldNames>);
|
||||||
|
|
||||||
|
#includeEtc "caseDicts/postProcessing/graphs/graphPatchCutLayerAverage.cfg"
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Version: dev
|
||||||
|
\\/ M anipulation |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
type patchCutLayerAverage;
|
||||||
|
libs ("libfieldFunctionObjects.so");
|
||||||
|
|
||||||
|
writeControl writeTime;
|
||||||
|
writeInterval 1;
|
||||||
|
|
||||||
|
setFormat raw;
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -83,5 +83,6 @@ cylindrical/cylindricalFunctionObject.C
|
|||||||
uniform/uniform.C
|
uniform/uniform.C
|
||||||
|
|
||||||
layerAverage/layerAverage.C
|
layerAverage/layerAverage.C
|
||||||
|
patchCutLayerAverage/patchCutLayerAverage.C
|
||||||
|
|
||||||
LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects
|
LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects
|
||||||
|
|||||||
@ -0,0 +1,823 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 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 "patchCutLayerAverage.H"
|
||||||
|
#include "cutPolyIntegral.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
#include "volFields.H"
|
||||||
|
#include "writeFile.H"
|
||||||
|
#include "polyTopoChangeMap.H"
|
||||||
|
#include "polyMeshMap.H"
|
||||||
|
#include "polyDistributionMap.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace functionObjects
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(patchCutLayerAverage, 0);
|
||||||
|
addToRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
functionObject,
|
||||||
|
patchCutLayerAverage,
|
||||||
|
dictionary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::List<Foam::functionObjects::patchCutLayerAverage::weight>
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::calcNonInterpolatingWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[patchName_];
|
||||||
|
const faceList& faces = pp.localFaces();
|
||||||
|
const vectorField::subField& faceAreas = pp.faceAreas();
|
||||||
|
const vectorField& faceNormals = pp.faceNormals();
|
||||||
|
const pointField& points = pp.localPoints();
|
||||||
|
|
||||||
|
// One-value for every point. Needed for the cutPoly routines.
|
||||||
|
const scalarField pointOnes(points.size(), scalar(1));
|
||||||
|
|
||||||
|
// Generate weights for each face in turn
|
||||||
|
DynamicList<weight> dynWeights(faces.size()*2);
|
||||||
|
label layeri = 0;
|
||||||
|
forAll(faceMinOrder, i)
|
||||||
|
{
|
||||||
|
const label facei = faceMinOrder[i];
|
||||||
|
|
||||||
|
const scalar a = faceAreas[facei] & faceNormals[facei];
|
||||||
|
|
||||||
|
// Find the next relevant layer
|
||||||
|
while (faceMinXs[facei] > plotXs[layeri + 1])
|
||||||
|
{
|
||||||
|
layeri ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all relevant layer intervals
|
||||||
|
label layerj = layeri;
|
||||||
|
while (faceMaxXs[facei] > plotXs[layerj])
|
||||||
|
{
|
||||||
|
const scalar x0 = plotXs[layerj], x1 = plotXs[layerj + 1];
|
||||||
|
|
||||||
|
// Add a new weight
|
||||||
|
dynWeights.append({facei, layerj, a});
|
||||||
|
|
||||||
|
// Left interval
|
||||||
|
if (faceMinXs[facei] < x0)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
scalar(1),
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, x0),
|
||||||
|
points,
|
||||||
|
pointOnes,
|
||||||
|
pointXs,
|
||||||
|
x0,
|
||||||
|
true
|
||||||
|
).first() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right interval
|
||||||
|
if (faceMaxXs[facei] > x1)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
scalar(1),
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, x1),
|
||||||
|
points,
|
||||||
|
pointOnes,
|
||||||
|
pointXs,
|
||||||
|
x1,
|
||||||
|
false
|
||||||
|
).first() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
layerj ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer to non-dynamic storage
|
||||||
|
List<weight> weights;
|
||||||
|
weights.transfer(dynWeights);
|
||||||
|
|
||||||
|
// Normalise, if requested
|
||||||
|
if (normalise)
|
||||||
|
{
|
||||||
|
scalarField layerWeightSums(nLayers_, scalar(0));
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
layerWeightSums[weights[weighti].layeri] += weights[weighti].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pstream::listCombineGather(layerWeightSums, plusEqOp<scalar>());
|
||||||
|
Pstream::listCombineScatter(layerWeightSums);
|
||||||
|
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
weights[weighti].value /=
|
||||||
|
(layerWeightSums[weights[weighti].layeri] + vSmall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weights;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::functionObjects::patchCutLayerAverage::weight>
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::calcInterpolatingWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[patchName_];
|
||||||
|
const faceList& faces = pp.localFaces();
|
||||||
|
const vectorField::subField& faceAreas = pp.faceAreas();
|
||||||
|
const vectorField& faceNormals = pp.faceNormals();
|
||||||
|
const pointField& points = pp.localPoints();
|
||||||
|
|
||||||
|
// Values of the (piecewise linear) interpolation basis function. Different
|
||||||
|
// for every interval. Is constantly being set on a sub-set of the
|
||||||
|
// currently relevant points in the loop below.
|
||||||
|
scalarField pointFs(points.size(), scalar(0));
|
||||||
|
|
||||||
|
// Generate weights for each face in turn
|
||||||
|
DynamicList<weight> dynWeights(faces.size()*2);
|
||||||
|
label layeri = 0;
|
||||||
|
forAll(faceMinOrder, i)
|
||||||
|
{
|
||||||
|
const label facei = faceMinOrder[i];
|
||||||
|
|
||||||
|
const scalar a = faceAreas[facei] & faceNormals[facei];
|
||||||
|
|
||||||
|
// Find the next relevant plot point
|
||||||
|
while (faceMinXs[facei] > plotXs[layeri + 1])
|
||||||
|
{
|
||||||
|
layeri ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all relevant plot points
|
||||||
|
label layerj = layeri;
|
||||||
|
while (layerj == 0 || faceMaxXs[facei] > plotXs[layerj - 1])
|
||||||
|
{
|
||||||
|
const scalar xLeft = layerj > 0 ? plotXs[layerj - 1] : NaN;
|
||||||
|
const scalar xMid = plotXs[layerj];
|
||||||
|
const scalar xRight =
|
||||||
|
layerj < nLayers_ - 1 ? plotXs[layerj + 1] : NaN;
|
||||||
|
|
||||||
|
// Add a new weight
|
||||||
|
dynWeights.append({facei, layerj, 0});
|
||||||
|
|
||||||
|
// Left interval
|
||||||
|
if (layerj > 0 && faceMinXs[facei] < xMid)
|
||||||
|
{
|
||||||
|
forAll(faces[facei], facePointi)
|
||||||
|
{
|
||||||
|
const label pointi = faces[facei][facePointi];
|
||||||
|
pointFs[pointi] =
|
||||||
|
(pointXs[pointi] - xLeft)/(xMid - xLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalar f = faces[facei].average(points, pointFs);
|
||||||
|
|
||||||
|
// Add the whole face's contribution
|
||||||
|
dynWeights.last().value += f*a;
|
||||||
|
|
||||||
|
// Cut off anything before the left point
|
||||||
|
if (faceMinXs[facei] < xLeft)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
f,
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, xLeft),
|
||||||
|
points,
|
||||||
|
pointFs,
|
||||||
|
pointXs,
|
||||||
|
xLeft,
|
||||||
|
true
|
||||||
|
).second() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cut off anything after the middle point
|
||||||
|
if (faceMaxXs[facei] > xMid)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
f,
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, xMid),
|
||||||
|
points,
|
||||||
|
pointFs,
|
||||||
|
pointXs,
|
||||||
|
xMid,
|
||||||
|
false
|
||||||
|
).second() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right interval
|
||||||
|
if (layerj < nLayers_ - 1 && faceMaxXs[facei] > xMid)
|
||||||
|
{
|
||||||
|
forAll(faces[facei], facePointi)
|
||||||
|
{
|
||||||
|
const label pointi = faces[facei][facePointi];
|
||||||
|
pointFs[pointi] =
|
||||||
|
(xRight - pointXs[pointi])/(xRight - xMid);
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalar f = faces[facei].average(points, pointFs);
|
||||||
|
|
||||||
|
// Add the whole face's contribution
|
||||||
|
dynWeights.last().value += f*a;
|
||||||
|
|
||||||
|
// Cut off anything before the middle point
|
||||||
|
if (faceMinXs[facei] < xMid)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
f,
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, xMid),
|
||||||
|
points,
|
||||||
|
pointFs,
|
||||||
|
pointXs,
|
||||||
|
xMid,
|
||||||
|
true
|
||||||
|
).second() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cut off anything after the right point
|
||||||
|
if (faceMaxXs[facei] > xRight)
|
||||||
|
{
|
||||||
|
dynWeights.last().value -=
|
||||||
|
cutPoly::faceCutAreaIntegral
|
||||||
|
(
|
||||||
|
faces[facei],
|
||||||
|
faceAreas[facei],
|
||||||
|
f,
|
||||||
|
cutPoly::faceCuts(faces[facei], pointXs, xRight),
|
||||||
|
points,
|
||||||
|
pointFs,
|
||||||
|
pointXs,
|
||||||
|
xRight,
|
||||||
|
false
|
||||||
|
).second() & faceNormals[facei];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layerj ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer to non-dynamic storage
|
||||||
|
List<weight> weights;
|
||||||
|
weights.transfer(dynWeights);
|
||||||
|
|
||||||
|
// Normalise, if requested. Otherwise, double the weight values on the ends
|
||||||
|
// to account for the fact that these points only have half a basis function
|
||||||
|
// contributing to their sums.
|
||||||
|
if (normalise)
|
||||||
|
{
|
||||||
|
scalarField layerWeightSums(nLayers_, scalar(0));
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
layerWeightSums[weights[weighti].layeri] += weights[weighti].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pstream::listCombineGather(layerWeightSums, plusEqOp<scalar>());
|
||||||
|
Pstream::listCombineScatter(layerWeightSums);
|
||||||
|
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
weights[weighti].value /=
|
||||||
|
(layerWeightSums[weights[weighti].layeri] + vSmall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
weights[weighti].layeri == 0
|
||||||
|
|| weights[weighti].layeri == nLayers_ - 1
|
||||||
|
)
|
||||||
|
{
|
||||||
|
weights[weighti].value *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return weights;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::List<Foam::functionObjects::patchCutLayerAverage::weight>
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::calcWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
interpolate_
|
||||||
|
? calcInterpolatingWeights
|
||||||
|
(
|
||||||
|
pointXs,
|
||||||
|
faceMinXs,
|
||||||
|
faceMaxXs,
|
||||||
|
faceMinOrder,
|
||||||
|
plotXs,
|
||||||
|
normalise
|
||||||
|
)
|
||||||
|
: calcNonInterpolatingWeights
|
||||||
|
(
|
||||||
|
pointXs,
|
||||||
|
faceMinXs,
|
||||||
|
faceMaxXs,
|
||||||
|
faceMinOrder,
|
||||||
|
plotXs,
|
||||||
|
normalise
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
inline Foam::tmp<Foam::Field<Type>>
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::applyWeights
|
||||||
|
(
|
||||||
|
const List<weight>& weights,
|
||||||
|
const Field<Type>& faceValues
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
tmp<Field<Type>> tLayerValues(new Field<Type>(nLayers_, Zero));
|
||||||
|
|
||||||
|
forAll(weights, weighti)
|
||||||
|
{
|
||||||
|
tLayerValues.ref()[weights[weighti].layeri] +=
|
||||||
|
weights[weighti].value*faceValues[weights[weighti].facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
Pstream::listCombineGather(tLayerValues.ref(), plusEqOp<Type>());
|
||||||
|
Pstream::listCombineScatter(tLayerValues.ref());
|
||||||
|
|
||||||
|
return tLayerValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::patchCutLayerAverage::initialise()
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[patchName_];
|
||||||
|
const faceList& faces = pp.localFaces();
|
||||||
|
const pointField& points = pp.localPoints();
|
||||||
|
|
||||||
|
// If interpolating, then the layers and the plot points are coincident. If
|
||||||
|
// not interpolating, then the layers lie in between the plot points, so
|
||||||
|
// there is one more point than there are layers.
|
||||||
|
const label nPlot = interpolate_ ? nLayers_ : nLayers_ + 1;
|
||||||
|
|
||||||
|
// Calculate point coordinates
|
||||||
|
const scalarField pointXs(points & direction_);
|
||||||
|
|
||||||
|
// Determine face min and max coordinates
|
||||||
|
scalarField faceMinXs(faces.size(), vGreat);
|
||||||
|
scalarField faceMaxXs(faces.size(), -vGreat);
|
||||||
|
forAll(faces, facei)
|
||||||
|
{
|
||||||
|
forAll(faces[facei], facePointi)
|
||||||
|
{
|
||||||
|
const label pointi = faces[facei][facePointi];
|
||||||
|
faceMinXs[facei] = min(faceMinXs[facei], pointXs[pointi]);
|
||||||
|
faceMaxXs[facei] = max(faceMaxXs[facei], pointXs[pointi]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create orderings of the faces based on their min and max coordinates
|
||||||
|
labelList faceMinOrder(faces.size());
|
||||||
|
sortedOrder(faceMinXs, faceMinOrder);
|
||||||
|
|
||||||
|
// Assume equal spacing to begin with
|
||||||
|
const scalar xMin = gMin(pointXs), xMax = gMax(pointXs);
|
||||||
|
scalarField plotXs
|
||||||
|
(
|
||||||
|
(xMin + scalarList(identity(nPlot))/(nPlot - 1)*(xMax - xMin))
|
||||||
|
);
|
||||||
|
|
||||||
|
// Names and fields for debug output of the counts, to observe the effect
|
||||||
|
// of iterative improvement of the spacing
|
||||||
|
wordList fieldNames;
|
||||||
|
#define DeclareTypeFieldValues(Type, nullArg) \
|
||||||
|
PtrList<Field<Type>> Type##FieldValues;
|
||||||
|
FOR_ALL_FIELD_TYPES(DeclareTypeFieldValues);
|
||||||
|
#undef DeclareTypeFieldValues
|
||||||
|
|
||||||
|
// Iteratively optimise the spacing between the plot points to achieve an
|
||||||
|
// approximately equal number of data points in each interval
|
||||||
|
for (label iteri = 0; iteri < nOptimiseIter_ + debug; ++ iteri)
|
||||||
|
{
|
||||||
|
// Determine the count of faces that contribute to each layer
|
||||||
|
const List<weight> weights =
|
||||||
|
calcWeights
|
||||||
|
(
|
||||||
|
pointXs,
|
||||||
|
faceMinXs,
|
||||||
|
faceMaxXs,
|
||||||
|
faceMinOrder,
|
||||||
|
plotXs,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
const scalarField layerCounts
|
||||||
|
(
|
||||||
|
applyWeights(weights, (1/pp.magFaceAreas())())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
const label nFields0 = (2 + !interpolate_)*iteri;
|
||||||
|
const label nFields = (2 + !interpolate_)*(iteri + 1);
|
||||||
|
|
||||||
|
fieldNames.resize(nFields);
|
||||||
|
#define ResizeTypeFieldValues(Type, nullArg) \
|
||||||
|
Type##FieldValues.resize(nFields);
|
||||||
|
FOR_ALL_FIELD_TYPES(ResizeTypeFieldValues);
|
||||||
|
#undef ResizeTypeFieldValues
|
||||||
|
|
||||||
|
if (!interpolate_)
|
||||||
|
{
|
||||||
|
const SubField<scalar> distance0s(plotXs, nLayers_);
|
||||||
|
const SubField<scalar> distance1s(plotXs, nLayers_, 1);
|
||||||
|
|
||||||
|
fieldNames[nFields0] = "distance-" + Foam::name(iteri);
|
||||||
|
scalarFieldValues.set(nFields0, (distance0s + distance1s)/2);
|
||||||
|
|
||||||
|
fieldNames[nFields0 + 1] = "thickness-" + Foam::name(iteri);
|
||||||
|
scalarFieldValues.set(nFields0 + 1, distance1s - distance0s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fieldNames[nFields0] = "distance-" + Foam::name(iteri);
|
||||||
|
scalarFieldValues.set(nFields0, new scalarField(plotXs));
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldNames[nFields - 1] = "count-" + Foam::name(iteri);
|
||||||
|
scalarFieldValues.set(nFields - 1, new scalarField(layerCounts));
|
||||||
|
|
||||||
|
if (iteri == nOptimiseIter_) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do a cumulative sum of the layer counts across all plot points
|
||||||
|
scalarField plotSumCounts(nPlot, 0);
|
||||||
|
for (label ploti = 0; ploti < nPlot - 1; ++ ploti)
|
||||||
|
{
|
||||||
|
plotSumCounts[ploti + 1] =
|
||||||
|
plotSumCounts[ploti]
|
||||||
|
+ (
|
||||||
|
interpolate_
|
||||||
|
? (layerCounts[ploti + 1] + layerCounts[ploti])/2
|
||||||
|
: layerCounts[ploti]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the desired count in each interval
|
||||||
|
const scalar plotDeltaCount = plotSumCounts.last()/(nPlot - 1);
|
||||||
|
|
||||||
|
// Compute the new spacing between the points
|
||||||
|
scalarField plot0Xs(plotXs);
|
||||||
|
plotXs = -vGreat;
|
||||||
|
plotXs.first() = xMin;
|
||||||
|
label ploti = 1;
|
||||||
|
for (label ploti0 = 0; ploti0 < nPlot - 1; ++ ploti0)
|
||||||
|
{
|
||||||
|
while (plotSumCounts[ploti0 + 1] > ploti*plotDeltaCount)
|
||||||
|
{
|
||||||
|
const scalar f =
|
||||||
|
(ploti*plotDeltaCount - plotSumCounts[ploti0])
|
||||||
|
/(plotSumCounts[ploti0 + 1] - plotSumCounts[ploti0]);
|
||||||
|
|
||||||
|
plotXs[ploti] = (1 - f)*plot0Xs[ploti0] + f*plot0Xs[ploti0 + 1];
|
||||||
|
|
||||||
|
ploti ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plotXs.last() = xMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
mkDir(outputPath());
|
||||||
|
|
||||||
|
formatter_->write
|
||||||
|
(
|
||||||
|
outputPath(),
|
||||||
|
typeName + "_count",
|
||||||
|
coordSet(labelList(nLayers_, 1)),
|
||||||
|
fieldNames
|
||||||
|
#define TypeFieldValuesParameter(Type, nullArg) \
|
||||||
|
, Type##FieldValues
|
||||||
|
FOR_ALL_FIELD_TYPES(TypeFieldValuesParameter)
|
||||||
|
#undef TypeFieldValuesParameter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, calculate the actual normalised interpolation weights
|
||||||
|
weights_ =
|
||||||
|
calcWeights
|
||||||
|
(
|
||||||
|
pointXs,
|
||||||
|
faceMinXs,
|
||||||
|
faceMaxXs,
|
||||||
|
faceMinOrder,
|
||||||
|
plotXs,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculate plot coordinates and widths
|
||||||
|
if (interpolate_)
|
||||||
|
{
|
||||||
|
layerDistances_ = plotXs;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const SubField<scalar> distance0s(plotXs, nLayers_);
|
||||||
|
const SubField<scalar> distance1s(plotXs, nLayers_, 1);
|
||||||
|
layerDistances_ = (distance0s + distance1s)/2;
|
||||||
|
layerThicknesses_.reset((distance1s - distance0s).ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the plot positions
|
||||||
|
layerPositions_ = applyWeights(weights_, pointField(pp.faceCentres()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::fileName Foam::functionObjects::patchCutLayerAverage::outputPath() const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
mesh_.time().globalPath()
|
||||||
|
/writeFile::outputPrefix
|
||||||
|
/(mesh_.name() != polyMesh::defaultRegion ? mesh_.name() : word())
|
||||||
|
/name()
|
||||||
|
/mesh_.time().name();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::patchCutLayerAverage
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const Time& runTime,
|
||||||
|
const dictionary& dict
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fvMeshFunctionObject(name, runTime, dict)
|
||||||
|
{
|
||||||
|
read(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::functionObjects::patchCutLayerAverage::~patchCutLayerAverage()
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
bool Foam::functionObjects::patchCutLayerAverage::read(const dictionary& dict)
|
||||||
|
{
|
||||||
|
patchName_ = dict.lookup<word>("patch");
|
||||||
|
direction_ = normalised(dict.lookup<vector>("direction"));
|
||||||
|
nLayers_ = dict.lookup<label>("nPoints");
|
||||||
|
|
||||||
|
interpolate_ = dict.lookupOrDefault<bool>("interpolate", false);
|
||||||
|
|
||||||
|
fields_ = dict.lookup<wordList>("fields");
|
||||||
|
|
||||||
|
axis_ =
|
||||||
|
coordSet::axisTypeNames_
|
||||||
|
[
|
||||||
|
dict.lookupOrDefault<word>
|
||||||
|
(
|
||||||
|
"axis",
|
||||||
|
coordSet::axisTypeNames_[coordSet::axisType::DEFAULT]
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
formatter_ = setWriter::New(dict.lookup("setFormat"), dict);
|
||||||
|
|
||||||
|
nOptimiseIter_ = dict.lookupOrDefault("nOptimiseIter", 2);
|
||||||
|
|
||||||
|
initialise();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::wordList Foam::functionObjects::patchCutLayerAverage::fields() const
|
||||||
|
{
|
||||||
|
return fields_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::patchCutLayerAverage::execute()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::patchCutLayerAverage::write()
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[patchName_];
|
||||||
|
|
||||||
|
const bool writeThickness =
|
||||||
|
!interpolate_
|
||||||
|
&& (
|
||||||
|
axis_ == coordSet::axisType::DEFAULT
|
||||||
|
|| axis_ == coordSet::axisType::DISTANCE
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create list of field names
|
||||||
|
wordList fieldNames;
|
||||||
|
if (writeThickness)
|
||||||
|
{
|
||||||
|
fieldNames.append("thickness");
|
||||||
|
}
|
||||||
|
forAll(fields_, fieldi)
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
false
|
||||||
|
#define FoundTypeField(Type, nullArg) \
|
||||||
|
|| foundObject<VolField<Type>>(fields_[fieldi])
|
||||||
|
FOR_ALL_FIELD_TYPES(FoundTypeField)
|
||||||
|
#undef FoundTypeField
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fieldNames.append(fields_[fieldi]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cannotFindObject(fields_[fieldi]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the field values
|
||||||
|
#define DeclareTypeFieldValues(Type, nullArg) \
|
||||||
|
PtrList<Field<Type>> Type##FieldValues(fieldNames.size());
|
||||||
|
FOR_ALL_FIELD_TYPES(DeclareTypeFieldValues);
|
||||||
|
#undef DeclareTypeFieldValues
|
||||||
|
if (writeThickness)
|
||||||
|
{
|
||||||
|
scalarFieldValues.set(0, new scalarField(layerThicknesses_));
|
||||||
|
}
|
||||||
|
for (label fieldi = writeThickness; fieldi < fieldNames.size(); ++ fieldi)
|
||||||
|
{
|
||||||
|
#define CollapseTypeFields(Type, nullArg) \
|
||||||
|
if (mesh_.foundObject<VolField<Type>>(fieldNames[fieldi])) \
|
||||||
|
{ \
|
||||||
|
const VolField<Type>& field = \
|
||||||
|
mesh_.lookupObject<VolField<Type>>(fieldNames[fieldi]); \
|
||||||
|
\
|
||||||
|
Type##FieldValues.set \
|
||||||
|
( \
|
||||||
|
fieldi, \
|
||||||
|
applyWeights(weights_, field.boundaryField()[pp.index()]) \
|
||||||
|
); \
|
||||||
|
}
|
||||||
|
FOR_ALL_FIELD_TYPES(CollapseTypeFields);
|
||||||
|
#undef CollapseTypeFields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write
|
||||||
|
if (Pstream::master() && layerPositions_.size())
|
||||||
|
{
|
||||||
|
mkDir(outputPath());
|
||||||
|
|
||||||
|
formatter_->write
|
||||||
|
(
|
||||||
|
outputPath(),
|
||||||
|
typeName,
|
||||||
|
coordSet
|
||||||
|
(
|
||||||
|
identity(layerPositions_.size()),
|
||||||
|
word::null,
|
||||||
|
layerPositions_,
|
||||||
|
coordSet::axisTypeNames_[coordSet::axisType::DISTANCE],
|
||||||
|
layerDistances_,
|
||||||
|
coordSet::axisTypeNames_[axis_]
|
||||||
|
),
|
||||||
|
fieldNames
|
||||||
|
#define TypeFieldValuesParameter(Type, nullArg) , Type##FieldValues
|
||||||
|
FOR_ALL_FIELD_TYPES(TypeFieldValuesParameter)
|
||||||
|
#undef TypeFieldValuesParameter
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::patchCutLayerAverage::movePoints
|
||||||
|
(
|
||||||
|
const polyMesh& mesh
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (&mesh == &mesh_)
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::patchCutLayerAverage::topoChange
|
||||||
|
(
|
||||||
|
const polyTopoChangeMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (&map.mesh() == &mesh_)
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::patchCutLayerAverage::mapMesh
|
||||||
|
(
|
||||||
|
const polyMeshMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (&map.mesh() == &mesh_)
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::functionObjects::patchCutLayerAverage::distribute
|
||||||
|
(
|
||||||
|
const polyDistributionMap& map
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (&map.mesh() == &mesh_)
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,258 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration | Website: https://openfoam.org
|
||||||
|
\\ / A nd | Copyright (C) 2022 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::patchCutLayerAverage
|
||||||
|
|
||||||
|
Description
|
||||||
|
This function object writes graphs of patch face values, area-averaged in
|
||||||
|
planes perpendicular to a given direction. It adaptively grades the
|
||||||
|
distribution of graph points to match the resolution of the mesh.
|
||||||
|
|
||||||
|
Example of function object specification:
|
||||||
|
\verbatim
|
||||||
|
patchCutLayerAverage1
|
||||||
|
{
|
||||||
|
type patchCutLayerAverage;
|
||||||
|
libs ("libpatchCutLayerAverageFunctionObject.so");
|
||||||
|
|
||||||
|
writeControl writeTime;
|
||||||
|
writeInterval 1;
|
||||||
|
|
||||||
|
patch lowerWall;
|
||||||
|
direction (1 0 0);
|
||||||
|
nPoints 100;
|
||||||
|
interpolate no;
|
||||||
|
|
||||||
|
fields (p U);
|
||||||
|
|
||||||
|
axis x;
|
||||||
|
setFormat raw;
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Usage
|
||||||
|
\table
|
||||||
|
Property | Description | Required | Default value
|
||||||
|
type | type name: patchCutLayerAverage | yes |
|
||||||
|
patch | Name of the patch | yes |
|
||||||
|
direction | Axis along which to plot | yes |
|
||||||
|
nPoints | Number of points in the plot | yes |
|
||||||
|
interpolate | Do linear interpolation | no | false
|
||||||
|
fields | Fields to plot values of | yes |
|
||||||
|
axis | Component of the position to plot against | yes |
|
||||||
|
setFormat | Format of the output file | yes |
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
patchCutLayerAverage.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef patchCutLayerAverage_H
|
||||||
|
#define patchCutLayerAverage_H
|
||||||
|
|
||||||
|
#include "fvMeshFunctionObject.H"
|
||||||
|
#include "vector.H"
|
||||||
|
#include "setWriter.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
class polyPatch;
|
||||||
|
|
||||||
|
namespace functionObjects
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class patchCutLayerAverage Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class patchCutLayerAverage
|
||||||
|
:
|
||||||
|
public fvMeshFunctionObject
|
||||||
|
{
|
||||||
|
// Private Structures
|
||||||
|
|
||||||
|
//- Weight for a given face and layer
|
||||||
|
struct weight
|
||||||
|
{
|
||||||
|
label facei, layeri;
|
||||||
|
scalar value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Name of the patch
|
||||||
|
word patchName_;
|
||||||
|
|
||||||
|
//- Direction along which to plot
|
||||||
|
vector direction_;
|
||||||
|
|
||||||
|
//- Number of layers
|
||||||
|
label nLayers_;
|
||||||
|
|
||||||
|
//- Whether or not to interpolate
|
||||||
|
bool interpolate_;
|
||||||
|
|
||||||
|
//- Fields to plot
|
||||||
|
wordList fields_;
|
||||||
|
|
||||||
|
//- The direction over which to plot the results
|
||||||
|
coordSet::axisType axis_;
|
||||||
|
|
||||||
|
//- File writer
|
||||||
|
autoPtr<setWriter> formatter_;
|
||||||
|
|
||||||
|
//- Number of optimisation iterations. Default is 2.
|
||||||
|
label nOptimiseIter_;
|
||||||
|
|
||||||
|
//- Weights
|
||||||
|
List<weight> weights_;
|
||||||
|
|
||||||
|
//- Layer distances. The distance of the layers' cut-planes to the
|
||||||
|
// origin, in the direction of the given vector. If interpolate is
|
||||||
|
// false, then the distance is taken to the middle of the layer.
|
||||||
|
scalarField layerDistances_;
|
||||||
|
|
||||||
|
//- Layer thicknesses. If interpolate is false, then this is the
|
||||||
|
// thickness of the layer that the plot point represents.
|
||||||
|
autoPtr<scalarField> layerThicknesses_;
|
||||||
|
|
||||||
|
//- Layer positions. The average position of the layer.
|
||||||
|
pointField layerPositions_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member functions
|
||||||
|
|
||||||
|
//- Calculate non-interpolating weights with which to construct plot
|
||||||
|
// values
|
||||||
|
List<weight> calcNonInterpolatingWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise = true
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Calculate interpolating weights with which to construct plot values
|
||||||
|
List<weight> calcInterpolatingWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise = true
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Calculate weights with which to construct plot values
|
||||||
|
List<weight> calcWeights
|
||||||
|
(
|
||||||
|
const scalarField& pointXs,
|
||||||
|
const scalarField& faceMinXs,
|
||||||
|
const scalarField& faceMaxXs,
|
||||||
|
const labelList& faceMinOrder,
|
||||||
|
const scalarField& plotXs,
|
||||||
|
const bool normalise = true
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Construct plot values from face values given a set of weights
|
||||||
|
template<class Type>
|
||||||
|
inline tmp<Field<Type>> applyWeights
|
||||||
|
(
|
||||||
|
const List<weight>& weights,
|
||||||
|
const Field<Type>& faceValues
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Initialise the cached weights
|
||||||
|
void initialise();
|
||||||
|
|
||||||
|
//- Return the output path
|
||||||
|
fileName outputPath() const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("patchCutLayerAverage");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from Time and dictionary
|
||||||
|
patchCutLayerAverage
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const Time& runTime,
|
||||||
|
const dictionary& dict
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~patchCutLayerAverage();
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Read the patchCutLayerAverage data
|
||||||
|
virtual bool read(const dictionary&);
|
||||||
|
|
||||||
|
//- Return the list of fields required
|
||||||
|
virtual wordList fields() const;
|
||||||
|
|
||||||
|
//- Execute, currently does nothing
|
||||||
|
virtual bool execute();
|
||||||
|
|
||||||
|
//- Write the patchCutLayerAverage
|
||||||
|
virtual bool write();
|
||||||
|
|
||||||
|
//- Update for mesh point-motion
|
||||||
|
virtual void movePoints(const polyMesh&);
|
||||||
|
|
||||||
|
//- Update topology using the given map
|
||||||
|
virtual void topoChange(const polyTopoChangeMap&);
|
||||||
|
|
||||||
|
//- Update from another mesh using the given map
|
||||||
|
virtual void mapMesh(const polyMeshMap&);
|
||||||
|
|
||||||
|
//- Redistribute or update using the given distribution map
|
||||||
|
virtual void distribute(const polyDistributionMap&);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace functionObjects
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -220,13 +220,30 @@ boundary
|
|||||||
(27 28 57 56)
|
(27 28 57 56)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hydrofoil
|
hydrofoilTip
|
||||||
{
|
{
|
||||||
type wall;
|
type wall;
|
||||||
|
inGroups (hydrofoil);
|
||||||
faces
|
faces
|
||||||
(
|
(
|
||||||
(12 13 42 41)
|
(12 13 42 41)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
hydrofoilLower
|
||||||
|
{
|
||||||
|
type wall;
|
||||||
|
inGroups (hydrofoil);
|
||||||
|
faces
|
||||||
|
(
|
||||||
(12 16 45 41)
|
(12 16 45 41)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
hydrofoilUpper
|
||||||
|
{
|
||||||
|
type wall;
|
||||||
|
inGroups (hydrofoil);
|
||||||
|
faces
|
||||||
|
(
|
||||||
(13 16 45 42)
|
(13 16 45 42)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,9 +54,50 @@ maxDeltaT 1e-4;
|
|||||||
functions
|
functions
|
||||||
{
|
{
|
||||||
#includeFunc yPlus(phase=liquid)
|
#includeFunc yPlus(phase=liquid)
|
||||||
#includeFunc cellMin(funcName=min, alpha.liquid, alpha.gas, p, p_rgh, U.liquid, U.gas, T.gas, T.liquid)
|
|
||||||
#includeFunc cellMax(funcName=max, alpha.liquid, alpha.gas, p, p_rgh, U.liquid, U.gas, T.gas, T.liquid)
|
#includeFunc cellMin
|
||||||
#includeFunc hydrofoilPressure
|
(
|
||||||
|
funcName=min,
|
||||||
|
alpha.liquid,
|
||||||
|
alpha.gas,
|
||||||
|
p,
|
||||||
|
p_rgh,
|
||||||
|
U.liquid,
|
||||||
|
U.gas,
|
||||||
|
T.gas,
|
||||||
|
T.liquid
|
||||||
|
)
|
||||||
|
|
||||||
|
#includeFunc cellMax
|
||||||
|
(
|
||||||
|
funcName=max,
|
||||||
|
alpha.liquid,
|
||||||
|
alpha.gas,
|
||||||
|
p,
|
||||||
|
p_rgh,
|
||||||
|
U.liquid,
|
||||||
|
U.gas,
|
||||||
|
T.gas,
|
||||||
|
T.liquid
|
||||||
|
)
|
||||||
|
|
||||||
|
#includeFunc graphPatchCutLayerAverage
|
||||||
|
(
|
||||||
|
funcName=hydrofoilLowerPressure,
|
||||||
|
patch=hydrofoilLower,
|
||||||
|
direction=(0.15 -0.016 0),
|
||||||
|
nPoints=100,
|
||||||
|
p
|
||||||
|
)
|
||||||
|
|
||||||
|
#includeFunc graphPatchCutLayerAverage
|
||||||
|
(
|
||||||
|
funcName=hydrofoilUpperPressure,
|
||||||
|
patch=hydrofoilUpper,
|
||||||
|
direction=(0.15 -0.016 0),
|
||||||
|
nPoints=100,
|
||||||
|
p
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,149 +0,0 @@
|
|||||||
/*--------------------------------*- C++ -*----------------------------------*\
|
|
||||||
========= |
|
|
||||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
||||||
\\ / O peration | Website: https://openfoam.org
|
|
||||||
\\ / A nd | Version: dev
|
|
||||||
\\/ M anipulation |
|
|
||||||
\*---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
type sets;
|
|
||||||
libs ("libsampling.so");
|
|
||||||
|
|
||||||
writeControl writeTime;
|
|
||||||
|
|
||||||
interpolationScheme cellPoint;
|
|
||||||
|
|
||||||
setFormat raw;
|
|
||||||
|
|
||||||
fields (p);
|
|
||||||
|
|
||||||
axis xyz;
|
|
||||||
|
|
||||||
sets
|
|
||||||
(
|
|
||||||
lower
|
|
||||||
{
|
|
||||||
type boundaryPoints;
|
|
||||||
axis xyz;
|
|
||||||
points
|
|
||||||
(
|
|
||||||
(0 0 0)
|
|
||||||
(0.003 -0.0003 0)
|
|
||||||
(0.006 -0.0006 0)
|
|
||||||
(0.009 -0.0009 0)
|
|
||||||
(0.012 -0.0012 0)
|
|
||||||
(0.015 -0.0015 0)
|
|
||||||
(0.018 -0.0018 0)
|
|
||||||
(0.021 -0.0021 0)
|
|
||||||
(0.024 -0.0024 0)
|
|
||||||
(0.027 -0.0027 0)
|
|
||||||
(0.03 -0.003 0)
|
|
||||||
(0.033 -0.0033 0)
|
|
||||||
(0.036 -0.0036 0)
|
|
||||||
(0.039 -0.0039 0)
|
|
||||||
(0.042 -0.0042 0)
|
|
||||||
(0.045 -0.0045 0)
|
|
||||||
(0.048 -0.0048 0)
|
|
||||||
(0.051 -0.0051 0)
|
|
||||||
(0.054 -0.0054 0)
|
|
||||||
(0.057 -0.0057 0)
|
|
||||||
(0.06 -0.006 0)
|
|
||||||
(0.063 -0.0063 0)
|
|
||||||
(0.066 -0.0066 0)
|
|
||||||
(0.069 -0.0069 0)
|
|
||||||
(0.072 -0.0072 0)
|
|
||||||
(0.075 -0.0075 0)
|
|
||||||
(0.078 -0.0078 0)
|
|
||||||
(0.081 -0.0081 0)
|
|
||||||
(0.084 -0.0084 0)
|
|
||||||
(0.087 -0.0087 0)
|
|
||||||
(0.09 -0.009 0)
|
|
||||||
(0.093 -0.0093 0)
|
|
||||||
(0.096 -0.0096 0)
|
|
||||||
(0.099 -0.0099 0)
|
|
||||||
(0.102 -0.0102 0)
|
|
||||||
(0.105 -0.0105 0)
|
|
||||||
(0.108 -0.0108 0)
|
|
||||||
(0.111 -0.0111 0)
|
|
||||||
(0.114 -0.0114 0)
|
|
||||||
(0.117 -0.0117 0)
|
|
||||||
(0.12 -0.012 0)
|
|
||||||
(0.123 -0.0123 0)
|
|
||||||
(0.126 -0.0126 0)
|
|
||||||
(0.129 -0.0129 0)
|
|
||||||
(0.132 -0.0132 0)
|
|
||||||
(0.135 -0.0135 0)
|
|
||||||
(0.138 -0.0138 0)
|
|
||||||
(0.141 -0.0141 0)
|
|
||||||
(0.144 -0.0144 0)
|
|
||||||
(0.147 -0.0147 0)
|
|
||||||
(0.15 -0.015 0)
|
|
||||||
);
|
|
||||||
patches (hydrofoil);
|
|
||||||
maxDistance 1;
|
|
||||||
}
|
|
||||||
upper
|
|
||||||
{
|
|
||||||
type boundaryPoints;
|
|
||||||
axis xyz;
|
|
||||||
points
|
|
||||||
(
|
|
||||||
(0 0.015 0)
|
|
||||||
(0.003 0.0147 0)
|
|
||||||
(0.006 0.0144 0)
|
|
||||||
(0.009 0.0141 0)
|
|
||||||
(0.012 0.0138 0)
|
|
||||||
(0.015 0.0135 0)
|
|
||||||
(0.018 0.0132 0)
|
|
||||||
(0.021 0.0129 0)
|
|
||||||
(0.024 0.0126 0)
|
|
||||||
(0.027 0.0123 0)
|
|
||||||
(0.03 0.012 0)
|
|
||||||
(0.033 0.0117 0)
|
|
||||||
(0.036 0.0114 0)
|
|
||||||
(0.039 0.0111 0)
|
|
||||||
(0.042 0.0108 0)
|
|
||||||
(0.045 0.0105 0)
|
|
||||||
(0.048 0.0102 0)
|
|
||||||
(0.051 0.0099 0)
|
|
||||||
(0.054 0.0096 0)
|
|
||||||
(0.057 0.0093 0)
|
|
||||||
(0.06 0.009 0)
|
|
||||||
(0.063 0.0087 0)
|
|
||||||
(0.066 0.0084 0)
|
|
||||||
(0.069 0.0081 0)
|
|
||||||
(0.072 0.0078 0)
|
|
||||||
(0.075 0.0075 0)
|
|
||||||
(0.078 0.0072 0)
|
|
||||||
(0.081 0.0069 0)
|
|
||||||
(0.084 0.0066 0)
|
|
||||||
(0.087 0.0063 0)
|
|
||||||
(0.09 0.006 0)
|
|
||||||
(0.093 0.0057 0)
|
|
||||||
(0.096 0.0054 0)
|
|
||||||
(0.099 0.0051 0)
|
|
||||||
(0.102 0.0048 0)
|
|
||||||
(0.105 0.0045 0)
|
|
||||||
(0.108 0.0042 0)
|
|
||||||
(0.111 0.0039 0)
|
|
||||||
(0.114 0.0036 0)
|
|
||||||
(0.117 0.0033 0)
|
|
||||||
(0.12 0.003 0)
|
|
||||||
(0.123 0.0027 0)
|
|
||||||
(0.126 0.0024 0)
|
|
||||||
(0.129 0.0021 0)
|
|
||||||
(0.132 0.0018 0)
|
|
||||||
(0.135 0.0015 0)
|
|
||||||
(0.138 0.0012 0)
|
|
||||||
(0.141 0.0009 0)
|
|
||||||
(0.144 0.0006 0)
|
|
||||||
(0.147 0.0003 0)
|
|
||||||
(0.15 0 0)
|
|
||||||
);
|
|
||||||
patches (hydrofoil);
|
|
||||||
maxDistance 1;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
|
||||||
@ -6,8 +6,8 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
lowerFile=postProcessing/hydrofoilPressure/$(foamListTimes -latestTime)/lower.xy
|
lowerFile=postProcessing/hydrofoilLowerPressure/$(foamListTimes -latestTime)/patchCutLayerAverage.xy
|
||||||
upperFile=postProcessing/hydrofoilPressure/$(foamListTimes -latestTime)/upper.xy
|
upperFile=postProcessing/hydrofoilUpperPressure/$(foamListTimes -latestTime)/patchCutLayerAverage.xy
|
||||||
|
|
||||||
gnuplot<<EOF
|
gnuplot<<EOF
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ rhoInf = 998.4
|
|||||||
set xlabel 'x/L'
|
set xlabel 'x/L'
|
||||||
set ylabel 'Cp'
|
set ylabel 'Cp'
|
||||||
plot [0:1] \
|
plot [0:1] \
|
||||||
'$lowerFile' u (\$1/0.15):(2*(\$4-pInf)/(rhoInf*UInf*UInf)) w l lt 1 t 'Simulation Lower', \
|
'$lowerFile' u (\$2/0.15):(2*(\$6-pInf)/(rhoInf*UInf*UInf)) w l lt 1 t 'Simulation Lower', \
|
||||||
'$upperFile' u (\$1/0.15):(2*(\$4-pInf)/(rhoInf*UInf*UInf)) w l lt 2 t 'Simulation Upper', \
|
'$upperFile' u (\$2/0.15):(2*(\$6-pInf)/(rhoInf*UInf*UInf)) w l lt 2 t 'Simulation Upper', \
|
||||||
'\$experiment' u 1:2 w p lt rgb "black" pt 4 t 'Experiment'
|
'\$experiment' u 1:2 w p lt rgb "black" pt 4 t 'Experiment'
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
Reference in New Issue
Block a user