Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 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/>.
\*---------------------------------------------------------------------------*/
Henry Weller
committed
#include "surfaceFieldValue.H"
#include "fvMesh.H"
#include "cyclicPolyPatch.H"
#include "emptyPolyPatch.H"
#include "sampledSurface.H"
#include "mergePoints.H"
#include "indirectPrimitivePatch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
Henry Weller
committed
namespace functionObjects
{
namespace fieldValues
{
Henry Weller
committed
defineTypeNameAndDebug(surfaceFieldValue, 0);
addToRunTimeSelectionTable(fieldValue, surfaceFieldValue, dictionary);
addToRunTimeSelectionTable(functionObject, surfaceFieldValue, dictionary);
Henry Weller
committed
}
}
Henry Weller
committed
template<>
const char* Foam::NamedEnum
<
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypes,
Henry Weller
committed
3
>::names[] =
{
"faceZone",
"patch",
"sampledSurface"
};
Henry Weller
committed
template<>
const char* Foam::NamedEnum
<
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
Henry Weller
committed
15
>::names[] =
{
"none",
"sum",
"sumMag",
"sumDirection",
"sumDirectionBalance",
"average",
"weightedAverage",
"areaAverage",
"weightedAreaAverage",
"areaIntegrate",
"min",
"max",
"CoV",
"areaNormalAverage",
"areaNormalIntegrate"
};
const Foam::NamedEnum
<
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypes,
Henry Weller
committed
3
Henry Weller
committed
> Foam::functionObjects::fieldValues::surfaceFieldValue::regionTypeNames_;
Henry Weller
committed
const Foam::NamedEnum
<
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::operationType,
Henry Weller
committed
15
Henry Weller
committed
> Foam::functionObjects::fieldValues::surfaceFieldValue::operationTypeNames_;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
label zoneId = mesh_.faceZones().findZoneID(regionName_);
if (zoneId < 0)
{
<< type() << " " << name() << ": "
<< regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
<< " Unknown face zone name: " << regionName_
<< ". Valid face zones are: " << mesh_.faceZones().names()
<< nl << exit(FatalError);
}
const faceZone& fZone = mesh_.faceZones()[zoneId];
DynamicList<label> faceIds(fZone.size());
DynamicList<label> facePatchIds(fZone.size());
DynamicList<label> faceSigns(fZone.size());
forAll(fZone, i)
{
label facei = fZone[i];
label faceId = -1;
label facePatchId = -1;
if (mesh_.isInternalFace(facei))
facePatchId = -1;
}
else
{
facePatchId = mesh_.boundaryMesh().whichPatch(facei);
const polyPatch& pp = mesh_.boundaryMesh()[facePatchId];
if (refCast<const coupledPolyPatch>(pp).owner())
faceId = pp.whichFace(facei);
}
else
{
faceId = -1;
}
}
else if (!isA<emptyPolyPatch>(pp))
{
faceId = facei - pp.start();
}
else
{
faceId = -1;
facePatchId = -1;
}
}
if (faceId >= 0)
{
if (fZone.flipMap()[i])
{
faceIds.append(faceId);
facePatchIds.append(facePatchId);
faceId_.transfer(faceIds);
facePatchId_.transfer(facePatchIds);
faceSign_.transfer(faceSigns);
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
Pout<< "Original face zone size = " << fZone.size()
<< ", new size = " << faceId_.size() << endl;
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
const label patchid = mesh_.boundaryMesh().findPatchID(regionName_);
<< type() << " " << name() << ": "
<< regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
<< " Unknown patch name: " << regionName_
<< ". Valid patch names are: "
<< mesh_.boundaryMesh().names() << nl
<< exit(FatalError);
}
const polyPatch& pp = mesh_.boundaryMesh()[patchid];
label nFaces = pp.size();
if (isA<emptyPolyPatch>(pp))
{
nFaces = 0;
}
faceId_.setSize(nFaces);
facePatchId_.setSize(nFaces);
faceSign_.setSize(nFaces);
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
forAll(faceId_, facei)
faceId_[facei] = facei;
facePatchId_[facei] = patchid;
faceSign_[facei] = 1;
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::sampledSurfaceFaces
Henry Weller
committed
(
const dictionary& dict
)
{
surfacePtr_ = sampledSurface::New
(
name(),
mesh_,
dict.subDict("sampledSurfaceDict")
);
surfacePtr_().update();
nFaces_ = returnReduce(surfacePtr_().faces().size(), sumOp<label>());
}
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
(
faceList& faces,
pointField& points
) const
{
List<faceList> allFaces(Pstream::nProcs());
List<pointField> allPoints(Pstream::nProcs());
labelList globalFacesIs(faceId_);
forAll(globalFacesIs, i)
{
if (facePatchId_[i] != -1)
{
label patchi = facePatchId_[i];
globalFacesIs[i] += mesh_.boundaryMesh()[patchi].start();
}
}
// Add local faces and points to the all* lists
indirectPrimitivePatch pp
(
IndirectList<face>(mesh_.faces(), globalFacesIs),
mesh_.points()
);
allFaces[Pstream::myProcNo()] = pp.localFaces();
allPoints[Pstream::myProcNo()] = pp.localPoints();
Pstream::gatherList(allFaces);
Pstream::gatherList(allPoints);
// Renumber and flatten
label nFaces = 0;
label nPoints = 0;
forAll(allFaces, proci)
{
nFaces += allFaces[proci].size();
nPoints += allPoints[proci].size();
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
}
faces.setSize(nFaces);
points.setSize(nPoints);
nFaces = 0;
nPoints = 0;
// My own data first
{
const faceList& fcs = allFaces[Pstream::myProcNo()];
forAll(fcs, i)
{
const face& f = fcs[i];
face& newF = faces[nFaces++];
newF.setSize(f.size());
forAll(f, fp)
{
newF[fp] = f[fp] + nPoints;
}
}
const pointField& pts = allPoints[Pstream::myProcNo()];
forAll(pts, i)
{
points[nPoints++] = pts[i];
}
}
// Other proc data follows
forAll(allFaces, proci)
{
if (proci != Pstream::myProcNo())
{
const faceList& fcs = allFaces[proci];
forAll(fcs, i)
{
const face& f = fcs[i];
face& newF = faces[nFaces++];
newF.setSize(f.size());
forAll(f, fp)
{
newF[fp] = f[fp] + nPoints;
}
}
const pointField& pts = allPoints[proci];
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
forAll(pts, i)
{
points[nPoints++] = pts[i];
}
}
}
// Merge
labelList oldToNew;
pointField newPoints;
bool hasMerged = mergePoints
(
points,
SMALL,
false,
oldToNew,
newPoints
);
if (hasMerged)
{
if (debug)
{
Pout<< "Merged from " << points.size()
<< " down to " << newPoints.size() << " points" << endl;
}
points.transfer(newPoints);
forAll(faces, i)
{
inplaceRenumber(oldToNew, faces[i]);
}
}
}
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::
combineSurfaceGeometry
(
faceList& faces,
pointField& points
) const
{
if (surfacePtr_.valid())
{
const sampledSurface& s = surfacePtr_();
if (Pstream::parRun())
{
// Dimension as fraction of mesh bounding box
scalar mergeDim = 1e-10*mesh_.bounds().mag();
labelList pointsMap;
PatchTools::gatherAndMerge
(
mergeDim,
primitivePatch
(
SubList<face>(s.faces(), s.faces().size()),
s.points()
),
points,
faces,
pointsMap
);
}
else
{
faces = s.faces();
points = s.points();
}
}
}
Henry Weller
committed
Foam::scalar
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::totalArea() const
Henry
committed
{
scalar totalArea;
if (surfacePtr_.valid())
{
totalArea = gSum(surfacePtr_().magSf());
}
else
{
totalArea = gSum(filterField(mesh_.magSf(), false));
Henry
committed
}
return totalArea;
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::initialise
Henry Weller
committed
(
const dictionary& dict
)
dict.lookup("name") >> regionName_;
Henry Weller
committed
switch (regionType_)
{
case stFaceZone:
{
setFaceZoneFaces();
break;
}
case stPatch:
{
setPatchFaces();
break;
}
case stSampledSurface:
{
sampledSurfaceFaces(dict);
break;
}
<< type() << " " << name() << ": "
<< regionTypeNames_[regionType_] << "(" << regionName_ << "):"
Henry Weller
committed
<< nl << " Unknown region type. Valid region types are:"
<< regionTypeNames_.sortedToc() << nl << exit(FatalError);
if (nFaces_ == 0)
{
Henry Weller
committed
FatalErrorInFunction
<< type() << " " << name() << ": "
<< regionTypeNames_[regionType_] << "(" << regionName_ << "):" << nl
Henry Weller
committed
<< " Region has no faces" << exit(FatalError);
if (surfacePtr_.valid())
{
surfacePtr_().update();
}
totalArea_ = totalArea();
Info<< type() << " " << name() << ":" << nl
<< " total faces = " << nFaces_
<< nl
<< " total area = " << totalArea_
if (dict.readIfPresent("weightField", weightFieldName_))
Info<< " weight field = " << weightFieldName_ << nl;
Henry Weller
committed
if (regionType_ == stSampledSurface)
FatalIOErrorInFunction(dict)
<< "Cannot use weightField for a sampledSurface"
<< exit(FatalIOError);
}
}
if (dict.found("orientedWeightField"))
{
if (weightFieldName_ == "none")
{
dict.lookup("orientedWeightField") >> weightFieldName_;
Info<< " weight field = " << weightFieldName_ << nl;
orientWeightField_ = true;
}
else
{
FatalIOErrorInFunction(dict)
<< "Either weightField or orientedWeightField can be supplied, "
<< "but not both"
<< exit(FatalIOError);
}
}
List<word> orientedFields;
if (dict.readIfPresent("orientedFields", orientedFields))
{
orientedFieldsStart_ = fields_.size();
fields_.append(orientedFields);
if (dict.readIfPresent("scaleFactor", scaleFactor_))
{
Info<< " scale factor = " << scaleFactor_ << nl;
{
const word surfaceFormat(dict.lookup("surfaceFormat"));
surfaceWriterPtr_.reset
(
surfaceWriter::New
(
surfaceFormat,
dict.subOrEmptyDict("formatOptions").
subOrEmptyDict(surfaceFormat)
).ptr()
);
}
Henry Weller
committed
void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
Henry Weller
committed
(
const label i
)
if (operation_ != opNone)
Henry
committed
{
writeCommented(file(), "Region type : ");
file() << regionTypeNames_[regionType_] << " " << regionName_ << endl;
writeCommented(file(), "Faces : ");
file() << nFaces_ << endl;
writeCommented(file(), "Area : ");
file() << totalArea_ << endl;
writeCommented(file(), "Time");
if (writeArea_)
{
file() << tab << "Area";
}
forAll(fields_, fieldi)
{
file()
<< tab << operationTypeNames_[operation_]
<< "(" << fields_[fieldi] << ")";
}
file() << endl;
}
Henry Weller
committed
Foam::scalar Foam::functionObjects::fieldValues::surfaceFieldValue::
processValues
(
const Field<scalar>& values,
const vectorField& Sf,
const scalarField& weightField
) const
{
switch (operation_)
{
case opSumDirection:
{
vector n(dict_.lookup("direction"));
return sum(pos(values*(Sf & n))*mag(values));
}
case opSumDirectionBalance:
{
vector n(dict_.lookup("direction"));
const scalarField nv(values*(Sf & n));
return sum(pos(nv)*mag(values) - neg(nv)*mag(values));
}
default:
{
// Fall through to other operations
return processSameTypeValues(values, Sf, weightField);
}
}
}
Henry Weller
committed
Foam::vector Foam::functionObjects::fieldValues::surfaceFieldValue::
processValues
(
const Field<vector>& values,
const vectorField& Sf,
const scalarField& weightField
) const
{
switch (operation_)
{
case opSumDirection:
{
vector n(dict_.lookup("direction"));
n /= mag(n) + ROOTVSMALL;
const scalarField nv(n & values);
return sum(pos(nv)*n*(nv));
}
case opSumDirectionBalance:
{
vector n(dict_.lookup("direction"));
n /= mag(n) + ROOTVSMALL;
const scalarField nv(n & values);
return sum(pos(nv)*n*(nv));
case opAreaNormalAverage:
{
scalar result = sum(values & Sf)/sum(mag(Sf));
return vector(result, 0.0, 0.0);
}
case opAreaNormalIntegrate:
{
scalar result = sum(values & Sf);
return vector(result, 0.0, 0.0);
}
default:
{
// Fall through to other operations
return processSameTypeValues(values, Sf, weightField);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
fieldValue(name, runTime, dict, typeName),
surfaceWriterPtr_(nullptr),
Henry Weller
committed
regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldName_("none"),
orientWeightField_(false),
orientedFieldsStart_(labelMax),
scaleFactor_(1.0),
writeArea_(dict.lookupOrDefault("writeArea", false)),
nFaces_(0),
faceId_(),
facePatchId_(),
faceSign_()
{
read(dict);
}
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
(
const word& name,
const objectRegistry& obr,
const dictionary& dict
fieldValue(name, obr, dict, typeName),
surfaceWriterPtr_(nullptr),
Henry Weller
committed
regionType_(regionTypeNames_.read(dict.lookup("regionType"))),
operation_(operationTypeNames_.read(dict.lookup("operation"))),
weightFieldName_("none"),
orientWeightField_(false),
orientedFieldsStart_(labelMax),
writeArea_(dict.lookupOrDefault("writeArea", false)),
nFaces_(0),
faceId_(),
facePatchId_(),
faceSign_()
read(dict);
Henry Weller
committed
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Henry Weller
committed
Foam::functionObjects::fieldValues::surfaceFieldValue::~surfaceFieldValue()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Henry Weller
committed
bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
Henry Weller
committed
(
const dictionary& dict
)
Henry Weller
committed
initialise(dict);
return true;
Henry Weller
committed
bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
if (operation_ != opNone)
{
fieldValue::write();
}
Henry Weller
committed
if (surfacePtr_.valid())
Henry Weller
committed
surfacePtr_().update();
}
if (operation_ != opNone && Pstream::master())
Henry Weller
committed
{
writeTime(file());
}
Henry
committed
Henry Weller
committed
if (writeArea_)
{
totalArea_ = totalArea();
if (operation_ != opNone && Pstream::master())
{
Henry Weller
committed
file() << tab << totalArea_;
}
Log << " total area = " << totalArea_ << endl;
Henry Weller
committed
}
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
// Write the surface geometry
if (surfaceWriterPtr_.valid())
{
faceList faces;
pointField points;
if (surfacePtr_.valid())
{
combineSurfaceGeometry(faces, points);
}
else
{
combineMeshGeometry(faces, points);
}
if (Pstream::master())
{
surfaceWriterPtr_->write
(
outputDir(),
regionTypeNames_[regionType_] + ("_" + regionName_),
points,
faces,
false
);
}
}
// Construct weight field. Note: zero size means weight = 1
Henry Weller
committed
scalarField weightField;
if (weightFieldName_ != "none")
{
weightField =
getFieldValues<scalar>
(
weightFieldName_,
true,
orientWeightField_
);
}
Henry Weller
committed
// Combine onto master
combineFields(weightField);
// Process the fields
Henry Weller
committed
forAll(fields_, i)
{
const word& fieldName = fields_[i];
bool ok = false;
Henry Weller
committed
bool orient = i >= orientedFieldsStart_;
ok = ok || writeValues<scalar>(fieldName, weightField, orient);
ok = ok || writeValues<vector>(fieldName, weightField, orient);
ok = ok
|| writeValues<sphericalTensor>(fieldName, weightField, orient);
ok = ok || writeValues<symmTensor>(fieldName, weightField, orient);
ok = ok || writeValues<tensor>(fieldName, weightField, orient);
Henry Weller
committed
if (!ok)
Henry Weller
committed
WarningInFunction
<< "Requested field " << fieldName
<< " not found in database and not processed"
<< endl;
Henry Weller
committed
}
if (operation_ != opNone && Pstream::master())
Henry Weller
committed
{
file() << endl;
Henry Weller
committed
Log << endl;
return true;
}
// ************************************************************************* //