mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
Merge branch 'updated-surface-handling' into 'develop'
Updated surface handling See merge request Development/openfoam!394
This commit is contained in:
@ -47,12 +47,19 @@ Usage
|
|||||||
|
|
||||||
where the entries mean:
|
where the entries mean:
|
||||||
\table
|
\table
|
||||||
Property | Description | Type | Req'd | Dflt
|
Property | Description | Type | Reqd | Dflt
|
||||||
writePrecision | Number of decimal points | label | no | \<system dflt\>
|
writePrecision | Number of decimal points | int | no | \<system dflt\>
|
||||||
writeToFile | Flag to produce text file output | bool | no | true
|
writeToFile | Produce text file output? | bool | no | true
|
||||||
useUserTime | Flag to use user time, e.g. degrees | bool | no | true
|
useUserTime | Use user time (e.g. degrees)? | bool | no | true
|
||||||
|
updateHeader | Update header on mesh changes? | bool | no | true
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
Note
|
||||||
|
The file header is normally updated whenver the mesh points or
|
||||||
|
topology changes. In some cases, the function object is actually
|
||||||
|
unaffected by these changes.
|
||||||
|
Use the \c updateHeader flag to override the default behaviour.
|
||||||
|
|
||||||
See also
|
See also
|
||||||
- Foam::functionObject
|
- Foam::functionObject
|
||||||
- Foam::functionObjects::logFiles
|
- Foam::functionObjects::logFiles
|
||||||
|
|||||||
@ -30,8 +30,9 @@ License
|
|||||||
#include "ListOps.H"
|
#include "ListOps.H"
|
||||||
#include "stringOps.H"
|
#include "stringOps.H"
|
||||||
#include "UIListStream.H"
|
#include "UIListStream.H"
|
||||||
|
#include "cellModel.H"
|
||||||
#undef Foam_readAbaqusSurface
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -319,11 +320,10 @@ Foam::fileFormats::ABAQUSCore::readHelper::readPoints
|
|||||||
const label initialCount = points_.size();
|
const label initialCount = points_.size();
|
||||||
|
|
||||||
char sep; // Comma separator (dummy)
|
char sep; // Comma separator (dummy)
|
||||||
|
string line;
|
||||||
label id;
|
label id;
|
||||||
point p;
|
point p;
|
||||||
|
|
||||||
string line;
|
|
||||||
|
|
||||||
// Read nodes (points) until next "*Section"
|
// Read nodes (points) until next "*Section"
|
||||||
while (is.peek() != '*' && is.peek() != EOF)
|
while (is.peek() != '*' && is.peek() != EOF)
|
||||||
{
|
{
|
||||||
@ -368,10 +368,10 @@ Foam::fileFormats::ABAQUSCore::readHelper::readElements
|
|||||||
const label initialCount = elemTypes_.size();
|
const label initialCount = elemTypes_.size();
|
||||||
|
|
||||||
char sep; // Comma separator (dummy)
|
char sep; // Comma separator (dummy)
|
||||||
label id;
|
|
||||||
labelList elemNodes(nNodes, Zero);
|
|
||||||
|
|
||||||
string line;
|
string line;
|
||||||
|
label id;
|
||||||
|
|
||||||
|
labelList elemNodes(nNodes, Zero);
|
||||||
|
|
||||||
// Read element connectivity until next "*Section"
|
// Read element connectivity until next "*Section"
|
||||||
|
|
||||||
@ -403,6 +403,130 @@ Foam::fileFormats::ABAQUSCore::readHelper::readElements
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::label
|
||||||
|
Foam::fileFormats::ABAQUSCore::readHelper::readSurfaceElements
|
||||||
|
(
|
||||||
|
ISstream& is,
|
||||||
|
const label setId
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Info<< "*Surface" << nl;
|
||||||
|
|
||||||
|
// Models for supported solids (need to face mapping)
|
||||||
|
const cellModel& tet = cellModel::ref(cellModel::TET);
|
||||||
|
const cellModel& prism = cellModel::ref(cellModel::PRISM);
|
||||||
|
const cellModel& hex = cellModel::ref(cellModel::HEX);
|
||||||
|
|
||||||
|
// Face mapping from Abaqus cellModel to OpenFOAM cellModel
|
||||||
|
const auto& abqToFoamFaceMap = abaqusToFoamFaceAddr();
|
||||||
|
|
||||||
|
const label initialCount = elemTypes_.size();
|
||||||
|
|
||||||
|
char sep; // Comma separator (dummy)
|
||||||
|
string line;
|
||||||
|
label id;
|
||||||
|
|
||||||
|
// Read until next "*Section"
|
||||||
|
|
||||||
|
// Parse for elemId, sideId.
|
||||||
|
// Eg, "1235, S1"
|
||||||
|
while (is.peek() != '*' && is.peek() != EOF)
|
||||||
|
{
|
||||||
|
is >> id >> sep;
|
||||||
|
is.getLine(line);
|
||||||
|
|
||||||
|
const word sideName(word::validate(stringOps::upper(line)));
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
sideName.size() != 2
|
||||||
|
|| sideName[0] != 'S'
|
||||||
|
|| !std::isdigit(sideName[1])
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< "Abaqus reader: unsupported surface element side "
|
||||||
|
<< id << ", " << sideName << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const label index = elemIds_.find(id);
|
||||||
|
if (id <= 0 || index < 0)
|
||||||
|
{
|
||||||
|
Info<< "Abaqus reader: unsupported surface element "
|
||||||
|
<< id << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto faceIdIter = abqToFoamFaceMap.cfind(elemTypes_[index]);
|
||||||
|
if (!faceIdIter.found())
|
||||||
|
{
|
||||||
|
Info<< "Abaqus reader: reject non-solid shape: " << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The abaqus element side number (1-based)
|
||||||
|
const label sideNum = (sideName[1] - '0');
|
||||||
|
|
||||||
|
const label foamFaceNum = (*faceIdIter)[sideNum - 1];
|
||||||
|
|
||||||
|
const labelList& connect = connectivity_[index];
|
||||||
|
|
||||||
|
// Nodes for the derived shell element
|
||||||
|
labelList elemNodes;
|
||||||
|
|
||||||
|
switch (elemTypes_[index])
|
||||||
|
{
|
||||||
|
case shapeType::abaqusTet:
|
||||||
|
{
|
||||||
|
elemNodes = labelList(connect, tet.modelFaces()[foamFaceNum]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case shapeType::abaqusPrism:
|
||||||
|
{
|
||||||
|
elemNodes = labelList(connect, prism.modelFaces()[foamFaceNum]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case shapeType::abaqusHex:
|
||||||
|
{
|
||||||
|
elemNodes = labelList(connect, hex.modelFaces()[foamFaceNum]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum shapeType shape = shapeType::abaqusUnknownShape;
|
||||||
|
|
||||||
|
if (elemNodes.size() == 3)
|
||||||
|
{
|
||||||
|
shape = shapeType::abaqusTria;
|
||||||
|
}
|
||||||
|
else if (elemNodes.size() == 4)
|
||||||
|
{
|
||||||
|
shape = shapeType::abaqusQuad;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Cannot happen
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Could not map face side for "
|
||||||
|
<< id << ", " << sideName << nl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synthesize face Id from solid element Id and side Id
|
||||||
|
const label newElemId = ABAQUSCore::encodeSolidId(id, sideNum);
|
||||||
|
|
||||||
|
// Further checks?
|
||||||
|
connectivity_.append(std::move(elemNodes));
|
||||||
|
elemTypes_.append(shape);
|
||||||
|
elemIds_.append(newElemId);
|
||||||
|
elsetIds_.append(setId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (elemTypes_.size() - initialCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::fileFormats::ABAQUSCore::readHelper::read
|
void Foam::fileFormats::ABAQUSCore::readHelper::read
|
||||||
(
|
(
|
||||||
ISstream& is
|
ISstream& is
|
||||||
@ -427,9 +551,11 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
|
|||||||
// Some abaqus files use upper-case or mixed-case for section names,
|
// Some abaqus files use upper-case or mixed-case for section names,
|
||||||
// convert all to upper-case for ease.
|
// convert all to upper-case for ease.
|
||||||
|
|
||||||
string upperLine(stringOps::upper(line));
|
const string upperLine(stringOps::upper(line));
|
||||||
|
|
||||||
|
//
|
||||||
// "*Nodes" section
|
// "*Nodes" section
|
||||||
|
//
|
||||||
if (upperLine.starts_with("*NODE"))
|
if (upperLine.starts_with("*NODE"))
|
||||||
{
|
{
|
||||||
// Ignore "NSET=...", we cannot do anything useful with it
|
// Ignore "NSET=...", we cannot do anything useful with it
|
||||||
@ -446,14 +572,16 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// "*Element" section
|
// "*Element" section
|
||||||
|
//
|
||||||
if (upperLine.starts_with("*ELEMENT,"))
|
if (upperLine.starts_with("*ELEMENT,"))
|
||||||
{
|
{
|
||||||
// Must have "TYPE=..."
|
// Must have "TYPE=..."
|
||||||
auto elemTypeName = getIdentifier("TYPE", line);
|
const string elemTypeName(getIdentifier("TYPE", line));
|
||||||
|
|
||||||
// May have "ELSET=..." on the same line
|
// May have "ELSET=..." on the same line
|
||||||
string elsetName(getIdentifier("ELSET", line));
|
const string elsetName(getIdentifier("ELSET", line));
|
||||||
|
|
||||||
const shapeType shape(getElementType(elemTypeName));
|
const shapeType shape(getElementType(elemTypeName));
|
||||||
|
|
||||||
@ -485,18 +613,42 @@ void Foam::fileFormats::ABAQUSCore::readHelper::read
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// "*Surface" section
|
// "*Surface" section
|
||||||
|
//
|
||||||
if (upperLine.starts_with("*SURFACE,"))
|
if (upperLine.starts_with("*SURFACE,"))
|
||||||
{
|
{
|
||||||
#ifdef Foam_readAbaqusSurface
|
// Require "NAME=..." on the same line
|
||||||
|
const string elsetName(getIdentifier("NAME", line));
|
||||||
|
|
||||||
|
// May have "TYPE=..." on the same line.
|
||||||
|
// If missing, default is ELEMENT.
|
||||||
|
const string surfTypeName(getIdentifier("TYPE", line));
|
||||||
|
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!surfTypeName.empty()
|
||||||
|
&& stringOps::upper(surfTypeName) != "ELEMENT"
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< "Reading abaqus surface type "
|
||||||
|
<< surfTypeName << " is not implemented" << nl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Treat like an element set
|
||||||
|
const label elsetId = addNewElset(elsetName);
|
||||||
|
|
||||||
skipComments(is);
|
skipComments(is);
|
||||||
|
|
||||||
#else
|
nread = readSurfaceElements(is, elsetId);
|
||||||
Info<< "Reading of abaqus surfaces not implemented" << nl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
if (verbose_)
|
||||||
|
{
|
||||||
|
InfoErr
|
||||||
|
<< "Read " << nread << " *SURFACE entries for "
|
||||||
|
<< elsetName << nl;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -623,6 +775,15 @@ void Foam::fileFormats::ABAQUSCore::readHelper::compact_nodes()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::fileFormats::ABAQUSCore::readHelper::renumber_elements_1to0()
|
||||||
|
{
|
||||||
|
for (label& elemId : elemIds_)
|
||||||
|
{
|
||||||
|
renumber0_elemId(elemId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::fileFormats::ABAQUSCore::writePoints
|
void Foam::fileFormats::ABAQUSCore::writePoints
|
||||||
(
|
(
|
||||||
Ostream& os,
|
Ostream& os,
|
||||||
|
|||||||
@ -90,7 +90,6 @@ SourceFiles
|
|||||||
|
|
||||||
namespace Foam
|
namespace Foam
|
||||||
{
|
{
|
||||||
|
|
||||||
namespace fileFormats
|
namespace fileFormats
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -148,11 +147,62 @@ public:
|
|||||||
return (tag & 0x80);
|
return (tag & 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- Is a combined (synthetic) face Id?
|
||||||
|
inline static bool isEncodedSolidId(const label combinedId)
|
||||||
|
{
|
||||||
|
return (combinedId < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Combine solid element Id and side Id into synthetic face Id
|
||||||
|
inline static label encodeSolidId(const label id, const label side)
|
||||||
|
{
|
||||||
|
return -(10 * id + side);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Entangle solid element id from synthetic face Id
|
||||||
|
inline static label decodeSolidElementId(const label combinedId)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(
|
||||||
|
isEncodedSolidId(combinedId)
|
||||||
|
? (-combinedId / 10)
|
||||||
|
: combinedId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Entangle solid side id from synthetic face Id
|
||||||
|
//- Synthesize faceId from solid element Id and sideId
|
||||||
|
inline static label decodeSolidSideNum(const label combinedId)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(
|
||||||
|
isEncodedSolidId(combinedId)
|
||||||
|
? (-combinedId % 10)
|
||||||
|
: 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Protected Member Functions
|
// Protected Member Functions
|
||||||
|
|
||||||
|
//- From 1-based to 0-based
|
||||||
|
inline static void renumber0_elemId(label& elemId)
|
||||||
|
{
|
||||||
|
if (isEncodedSolidId(elemId))
|
||||||
|
{
|
||||||
|
// Eg,
|
||||||
|
// 1-based (solid 4, side 2) is -42
|
||||||
|
// 0-based (solid 3, side 2) is -32
|
||||||
|
elemId += 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--elemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//- Face addressing from ABAQUS faces to OpenFOAM faces.
|
//- Face addressing from ABAQUS faces to OpenFOAM faces.
|
||||||
// For hex, prism, tet primitive shapes.
|
// For hex, prism, tet primitive shapes.
|
||||||
static const Map<labelList>& abaqusToFoamFaceAddr();
|
static const Map<labelList>& abaqusToFoamFaceAddr();
|
||||||
@ -249,12 +299,26 @@ protected:
|
|||||||
const label setId = 0
|
const label setId = 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//- Read elements within an "*Surface" section.
|
||||||
|
// If the shape is known/supported, appends to
|
||||||
|
// connectivity, elemType, elemIds lists.
|
||||||
|
//
|
||||||
|
// \return the number of elements read
|
||||||
|
label readSurfaceElements
|
||||||
|
(
|
||||||
|
ISstream& is,
|
||||||
|
const label setId = 0
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
//- Remove non-shell elements and compact the points
|
//- Remove non-shell elements and compact the points
|
||||||
void purge_solids();
|
void purge_solids();
|
||||||
|
|
||||||
//- Compact unused points and relabel connectivity
|
//- Compact unused points and relabel connectivity
|
||||||
void compact_nodes();
|
void compact_nodes();
|
||||||
|
|
||||||
|
//- Renumber elements from 1-based to 0-based
|
||||||
|
void renumber_elements_1to0();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ License
|
|||||||
#include "coupledPolyPatch.H"
|
#include "coupledPolyPatch.H"
|
||||||
#include "sampledSurface.H"
|
#include "sampledSurface.H"
|
||||||
#include "mergePoints.H"
|
#include "mergePoints.H"
|
||||||
#include "indirectPrimitivePatch.H"
|
#include "uindirectPrimitivePatch.H"
|
||||||
#include "PatchTools.H"
|
#include "PatchTools.H"
|
||||||
#include "addToRunTimeSelectionTable.H"
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
@ -130,115 +130,225 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::obr() const
|
|||||||
|
|
||||||
void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
|
void Foam::functionObjects::fieldValues::surfaceFieldValue::setFaceZoneFaces()
|
||||||
{
|
{
|
||||||
const label zoneId = mesh_.faceZones().findZoneID(regionName_);
|
// Indices for all matches, already sorted
|
||||||
|
const labelList zoneIds
|
||||||
|
(
|
||||||
|
mesh_.faceZones().indices(selectionNames_)
|
||||||
|
);
|
||||||
|
|
||||||
if (zoneId < 0)
|
// Total number of faces selected
|
||||||
|
label numFaces = 0;
|
||||||
|
for (const label zoneId : zoneIds)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
numFaces += mesh_.faceZones()[zoneId].size();
|
||||||
<< 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];
|
if (zoneIds.empty())
|
||||||
|
|
||||||
DynamicList<label> faceIds(fZone.size());
|
|
||||||
DynamicList<label> facePatchIds(fZone.size());
|
|
||||||
DynamicList<bool> faceFlip(fZone.size());
|
|
||||||
|
|
||||||
forAll(fZone, i)
|
|
||||||
{
|
{
|
||||||
const label facei = fZone[i];
|
FatalErrorInFunction
|
||||||
|
<< type() << ' ' << name() << ": "
|
||||||
|
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
||||||
|
<< " No matching face zone(s): "
|
||||||
|
<< flatOutput(selectionNames_) << nl
|
||||||
|
<< " Known face zones: "
|
||||||
|
<< flatOutput(mesh_.faceZones().names()) << nl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
label faceId = -1;
|
// Could also check this
|
||||||
label facePatchId = -1;
|
#if 0
|
||||||
if (mesh_.isInternalFace(facei))
|
if (!returnReduce(bool(numFaces), orOp<bool>()))
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< type() << ' ' << name() << ": "
|
||||||
|
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
||||||
|
<< " The faceZone specification: "
|
||||||
|
<< flatOutput(selectionNames_) << nl
|
||||||
|
<< " resulted in 0 faces" << nl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
faceId_.resize(numFaces);
|
||||||
|
facePatchId_.resize(numFaces);
|
||||||
|
faceFlip_.resize(numFaces);
|
||||||
|
|
||||||
|
numFaces = 0;
|
||||||
|
|
||||||
|
for (const label zoneId : zoneIds)
|
||||||
|
{
|
||||||
|
const faceZone& fZone = mesh_.faceZones()[zoneId];
|
||||||
|
|
||||||
|
forAll(fZone, i)
|
||||||
{
|
{
|
||||||
faceId = facei;
|
const label meshFacei = fZone[i];
|
||||||
facePatchId = -1;
|
const bool isFlip = fZone.flipMap()[i];
|
||||||
}
|
|
||||||
else
|
// Internal faces
|
||||||
{
|
label faceId = meshFacei;
|
||||||
facePatchId = mesh_.boundaryMesh().whichPatch(facei);
|
label facePatchId = -1;
|
||||||
const polyPatch& pp = mesh_.boundaryMesh()[facePatchId];
|
|
||||||
if (isA<coupledPolyPatch>(pp))
|
// Boundary faces
|
||||||
|
if (!mesh_.isInternalFace(meshFacei))
|
||||||
{
|
{
|
||||||
if (refCast<const coupledPolyPatch>(pp).owner())
|
facePatchId = mesh_.boundaryMesh().whichPatch(meshFacei);
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[facePatchId];
|
||||||
|
|
||||||
|
if (isA<coupledPolyPatch>(pp))
|
||||||
{
|
{
|
||||||
faceId = pp.whichFace(facei);
|
if (refCast<const coupledPolyPatch>(pp).owner())
|
||||||
|
{
|
||||||
|
faceId = pp.whichFace(meshFacei);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
faceId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!isA<emptyPolyPatch>(pp))
|
||||||
|
{
|
||||||
|
faceId = meshFacei - pp.start();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
faceId = -1;
|
faceId = -1;
|
||||||
|
facePatchId = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!isA<emptyPolyPatch>(pp))
|
|
||||||
{
|
|
||||||
faceId = facei - pp.start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
faceId = -1;
|
|
||||||
facePatchId = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (faceId >= 0)
|
if (faceId >= 0)
|
||||||
{
|
{
|
||||||
faceIds.append(faceId);
|
faceId_[numFaces] = faceId;
|
||||||
facePatchIds.append(facePatchId);
|
facePatchId_[numFaces] = facePatchId;
|
||||||
faceFlip.append(fZone.flipMap()[i] ? true : false);
|
faceFlip_[numFaces] = isFlip;
|
||||||
|
|
||||||
|
++numFaces;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
faceId_.transfer(faceIds);
|
// Shrink to size used
|
||||||
facePatchId_.transfer(facePatchIds);
|
faceId_.resize(numFaces);
|
||||||
faceFlip_.transfer(faceFlip);
|
facePatchId_.resize(numFaces);
|
||||||
|
faceFlip_.resize(numFaces);
|
||||||
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
|
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
|
||||||
|
|
||||||
if (debug)
|
|
||||||
{
|
|
||||||
Pout<< "Original face zone size = " << fZone.size()
|
|
||||||
<< ", new size = " << faceId_.size() << endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
|
void Foam::functionObjects::fieldValues::surfaceFieldValue::setPatchFaces()
|
||||||
{
|
{
|
||||||
const label patchid = mesh_.boundaryMesh().findPatchID(regionName_);
|
// Patch indices for all matches
|
||||||
|
labelList patchIds;
|
||||||
|
|
||||||
if (patchid < 0)
|
// Total number of faces selected
|
||||||
|
label numFaces = 0;
|
||||||
|
|
||||||
|
labelList selected
|
||||||
|
(
|
||||||
|
mesh_.boundaryMesh().patchSet
|
||||||
|
(
|
||||||
|
selectionNames_,
|
||||||
|
false // warnNotFound - we do that ourselves
|
||||||
|
).sortedToc()
|
||||||
|
);
|
||||||
|
|
||||||
|
DynamicList<label> bad;
|
||||||
|
for (const label patchi : selected)
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
|
||||||
|
|
||||||
|
if (isA<emptyPolyPatch>(pp))
|
||||||
|
{
|
||||||
|
bad.append(patchi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
numFaces += pp.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bad.size())
|
||||||
|
{
|
||||||
|
label nGood = (selected.size() - bad.size());
|
||||||
|
|
||||||
|
auto& os = (nGood > 0 ? WarningInFunction : FatalErrorInFunction);
|
||||||
|
|
||||||
|
os << "Cannot sample an empty patch" << nl;
|
||||||
|
|
||||||
|
for (const label patchi : bad)
|
||||||
|
{
|
||||||
|
os << " "
|
||||||
|
<< mesh_.boundaryMesh()[patchi].name() << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nGood)
|
||||||
|
{
|
||||||
|
os << "No non-empty patches selected" << endl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << "Selected " << nGood << " non-empty patches" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchIds.resize(nGood);
|
||||||
|
nGood = 0;
|
||||||
|
for (const label patchi : selected)
|
||||||
|
{
|
||||||
|
if (!bad.found(patchi))
|
||||||
|
{
|
||||||
|
patchIds[nGood] = patchi;
|
||||||
|
++nGood;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
patchIds = std::move(selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patchIds.empty())
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< type() << " " << name() << ": "
|
<< type() << ' ' << name() << ": "
|
||||||
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
||||||
<< " Unknown patch name: " << regionName_
|
<< " No matching patch name(s): "
|
||||||
<< ". Valid patch names are: "
|
<< flatOutput(selectionNames_) << nl
|
||||||
|
<< " Known patch names:" << nl
|
||||||
<< mesh_.boundaryMesh().names() << nl
|
<< mesh_.boundaryMesh().names() << nl
|
||||||
<< exit(FatalError);
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const polyPatch& pp = mesh_.boundaryMesh()[patchid];
|
// Could also check this
|
||||||
|
#if 0
|
||||||
label nFaces = pp.size();
|
if (!returnReduce(bool(numFaces), orOp<bool>()))
|
||||||
if (isA<emptyPolyPatch>(pp))
|
|
||||||
{
|
{
|
||||||
nFaces = 0;
|
WarningInFunction
|
||||||
|
<< type() << ' ' << name() << ": "
|
||||||
|
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
||||||
|
<< " The patch specification: "
|
||||||
|
<< flatOutput(selectionNames_) << nl
|
||||||
|
<< " resulted in 0 faces" << nl
|
||||||
|
<< exit(FatalError);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
faceId_.setSize(nFaces);
|
faceId_.resize(numFaces);
|
||||||
facePatchId_.setSize(nFaces);
|
facePatchId_.resize(numFaces);
|
||||||
faceFlip_.setSize(nFaces);
|
faceFlip_.resize(numFaces);
|
||||||
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
|
nFaces_ = returnReduce(faceId_.size(), sumOp<label>());
|
||||||
|
|
||||||
forAll(faceId_, facei)
|
numFaces = 0;
|
||||||
|
for (const label patchi : patchIds)
|
||||||
{
|
{
|
||||||
faceId_[facei] = facei;
|
const polyPatch& pp = mesh_.boundaryMesh()[patchi];
|
||||||
facePatchId_[facei] = patchid;
|
const label len = pp.size();
|
||||||
faceFlip_[facei] = false;
|
|
||||||
|
SubList<label>(faceId_, len, numFaces) = identity(len);
|
||||||
|
SubList<label>(facePatchId_, len, numFaces) = patchi;
|
||||||
|
SubList<bool>(faceFlip_, len, numFaces) = false;
|
||||||
|
|
||||||
|
numFaces += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,24 +362,25 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
|
|||||||
List<faceList> allFaces(Pstream::nProcs());
|
List<faceList> allFaces(Pstream::nProcs());
|
||||||
List<pointField> allPoints(Pstream::nProcs());
|
List<pointField> allPoints(Pstream::nProcs());
|
||||||
|
|
||||||
labelList globalFacesIs(faceId_);
|
|
||||||
forAll(globalFacesIs, i)
|
|
||||||
{
|
{
|
||||||
if (facePatchId_[i] != -1)
|
IndirectList<face> selectedFaces(mesh_.faces(), labelList(faceId_));
|
||||||
|
labelList& meshFaceIds = selectedFaces.addressing();
|
||||||
|
|
||||||
|
forAll(meshFaceIds, i)
|
||||||
{
|
{
|
||||||
const label patchi = facePatchId_[i];
|
const label patchi = facePatchId_[i];
|
||||||
globalFacesIs[i] += mesh_.boundaryMesh()[patchi].start();
|
if (patchi != -1)
|
||||||
|
{
|
||||||
|
meshFaceIds[i] += mesh_.boundaryMesh()[patchi].start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add local faces and points to the all* lists
|
// Add local faces and points to the all* lists
|
||||||
indirectPrimitivePatch pp
|
uindirectPrimitivePatch pp(selectedFaces, mesh_.points());
|
||||||
(
|
|
||||||
IndirectList<face>(mesh_.faces(), globalFacesIs),
|
allFaces[Pstream::myProcNo()] = pp.localFaces();
|
||||||
mesh_.points()
|
allPoints[Pstream::myProcNo()] = pp.localPoints();
|
||||||
);
|
}
|
||||||
allFaces[Pstream::myProcNo()] = pp.localFaces();
|
|
||||||
allPoints[Pstream::myProcNo()] = pp.localPoints();
|
|
||||||
|
|
||||||
Pstream::gatherList(allFaces);
|
Pstream::gatherList(allFaces);
|
||||||
Pstream::gatherList(allPoints);
|
Pstream::gatherList(allPoints);
|
||||||
@ -283,53 +394,41 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::combineMeshGeometry
|
|||||||
nPoints += allPoints[proci].size();
|
nPoints += allPoints[proci].size();
|
||||||
}
|
}
|
||||||
|
|
||||||
faces.setSize(nFaces);
|
faces.resize(nFaces);
|
||||||
points.setSize(nPoints);
|
points.resize(nPoints);
|
||||||
|
|
||||||
nFaces = 0;
|
nFaces = 0;
|
||||||
nPoints = 0;
|
nPoints = 0;
|
||||||
|
|
||||||
// My own data first
|
// My data first
|
||||||
{
|
{
|
||||||
const faceList& fcs = allFaces[Pstream::myProcNo()];
|
for (const face& f : allFaces[Pstream::myProcNo()])
|
||||||
for (const face& f : fcs)
|
|
||||||
{
|
{
|
||||||
face& newF = faces[nFaces++];
|
faces[nFaces++] = offsetOp<face>()(f, nPoints);
|
||||||
newF.setSize(f.size());
|
|
||||||
forAll(f, fp)
|
|
||||||
{
|
|
||||||
newF[fp] = f[fp] + nPoints;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointField& pts = allPoints[Pstream::myProcNo()];
|
for (const point& p : allPoints[Pstream::myProcNo()])
|
||||||
for (const point& pt : pts)
|
|
||||||
{
|
{
|
||||||
points[nPoints++] = pt;
|
points[nPoints++] = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other proc data follows
|
// Other proc data follows
|
||||||
forAll(allFaces, proci)
|
forAll(allFaces, proci)
|
||||||
{
|
{
|
||||||
if (proci != Pstream::myProcNo())
|
if (proci == Pstream::myProcNo())
|
||||||
{
|
{
|
||||||
const faceList& fcs = allFaces[proci];
|
continue;
|
||||||
for (const face& f : fcs)
|
}
|
||||||
{
|
|
||||||
face& newF = faces[nFaces++];
|
|
||||||
newF.setSize(f.size());
|
|
||||||
forAll(f, fp)
|
|
||||||
{
|
|
||||||
newF[fp] = f[fp] + nPoints;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const pointField& pts = allPoints[proci];
|
for (const face& f : allFaces[proci])
|
||||||
for (const point& pt : pts)
|
{
|
||||||
{
|
faces[nFaces++] = offsetOp<face>()(f, nPoints);
|
||||||
points[nPoints++] = pt;
|
}
|
||||||
}
|
|
||||||
|
for (const point& p : allPoints[proci])
|
||||||
|
{
|
||||||
|
points[nPoints++] = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,11 +482,7 @@ combineSurfaceGeometry
|
|||||||
PatchTools::gatherAndMerge
|
PatchTools::gatherAndMerge
|
||||||
(
|
(
|
||||||
mergeDim,
|
mergeDim,
|
||||||
primitivePatch
|
primitivePatch(SubList<face>(s.faces()), s.points()),
|
||||||
(
|
|
||||||
SubList<face>(s.faces(), s.faces().size()),
|
|
||||||
s.points()
|
|
||||||
),
|
|
||||||
points,
|
points,
|
||||||
faces,
|
faces,
|
||||||
pointsMap
|
pointsMap
|
||||||
@ -413,11 +508,7 @@ combineSurfaceGeometry
|
|||||||
PatchTools::gatherAndMerge
|
PatchTools::gatherAndMerge
|
||||||
(
|
(
|
||||||
mergeDim,
|
mergeDim,
|
||||||
primitivePatch
|
primitivePatch(SubList<face>(s.faces()), s.points()),
|
||||||
(
|
|
||||||
SubList<face>(s.faces(), s.faces().size()),
|
|
||||||
s.points()
|
|
||||||
),
|
|
||||||
points,
|
points,
|
||||||
faces,
|
faces,
|
||||||
pointsMap
|
pointsMap
|
||||||
@ -522,7 +613,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::update()
|
|||||||
if (nFaces_ == 0)
|
if (nFaces_ == 0)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< type() << " " << name() << ": "
|
<< type() << ' ' << name() << ": "
|
||||||
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
<< regionTypeNames_[regionType_] << '(' << regionName_ << "):" << nl
|
||||||
<< " Region has no faces" << exit(FatalError);
|
<< " Region has no faces" << exit(FatalError);
|
||||||
}
|
}
|
||||||
@ -548,15 +639,20 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
|
|||||||
if (canWriteHeader() && (operation_ != opNone))
|
if (canWriteHeader() && (operation_ != opNone))
|
||||||
{
|
{
|
||||||
writeCommented(os, "Region type : ");
|
writeCommented(os, "Region type : ");
|
||||||
os << regionTypeNames_[regionType_] << " " << regionName_ << endl;
|
os << regionTypeNames_[regionType_] << ' ' << regionName_ << nl;
|
||||||
|
|
||||||
writeHeaderValue(os, "Faces", nFaces_);
|
writeHeaderValue(os, "Faces", nFaces_);
|
||||||
writeHeaderValue(os, "Area", totalArea_);
|
writeHeaderValue(os, "Area", totalArea_);
|
||||||
writeHeaderValue(os, "Scale factor", scaleFactor_);
|
writeHeaderValue(os, "Scale factor", scaleFactor_);
|
||||||
|
|
||||||
if (weightFieldName_ != "none")
|
if (weightFieldNames_.size())
|
||||||
{
|
{
|
||||||
writeHeaderValue(os, "Weight field", weightFieldName_);
|
writeHeaderValue
|
||||||
|
(
|
||||||
|
os,
|
||||||
|
"Weight field",
|
||||||
|
flatOutput(weightFieldNames_, FlatOutput::BareComma{})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCommented(os, "Time");
|
writeCommented(os, "Time");
|
||||||
@ -570,7 +666,7 @@ void Foam::functionObjects::fieldValues::surfaceFieldValue::writeFileHeader
|
|||||||
for (const word& fieldName : fields_)
|
for (const word& fieldName : fields_)
|
||||||
{
|
{
|
||||||
os << tab << operationTypeNames_[operation_]
|
os << tab << operationTypeNames_[operation_]
|
||||||
<< "(" << fieldName << ")";
|
<< '(' << fieldName << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
os << endl;
|
os << endl;
|
||||||
@ -821,9 +917,10 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
|
|||||||
true // Failsafe behaviour
|
true // Failsafe behaviour
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
weightFieldName_("none"),
|
|
||||||
needsUpdate_(true),
|
needsUpdate_(true),
|
||||||
writeArea_(false),
|
writeArea_(false),
|
||||||
|
selectionNames_(),
|
||||||
|
weightFieldNames_(),
|
||||||
totalArea_(0),
|
totalArea_(0),
|
||||||
nFaces_(0),
|
nFaces_(0),
|
||||||
faceId_(),
|
faceId_(),
|
||||||
@ -854,9 +951,10 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::surfaceFieldValue
|
|||||||
true // Failsafe behaviour
|
true // Failsafe behaviour
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
weightFieldName_("none"),
|
|
||||||
needsUpdate_(true),
|
needsUpdate_(true),
|
||||||
writeArea_(false),
|
writeArea_(false),
|
||||||
|
selectionNames_(),
|
||||||
|
weightFieldNames_(),
|
||||||
totalArea_(0),
|
totalArea_(0),
|
||||||
nFaces_(0),
|
nFaces_(0),
|
||||||
faceId_(),
|
faceId_(),
|
||||||
@ -876,18 +974,55 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
|
|||||||
{
|
{
|
||||||
fieldValue::read(dict);
|
fieldValue::read(dict);
|
||||||
|
|
||||||
weightFieldName_ = "none";
|
|
||||||
needsUpdate_ = true;
|
needsUpdate_ = true;
|
||||||
writeArea_ = dict.getOrDefault("writeArea", false);
|
writeArea_ = dict.getOrDefault("writeArea", false);
|
||||||
|
weightFieldNames_.clear();
|
||||||
|
|
||||||
totalArea_ = 0;
|
totalArea_ = 0;
|
||||||
nFaces_ = 0;
|
nFaces_ = 0;
|
||||||
faceId_.clear();
|
faceId_.clear();
|
||||||
facePatchId_.clear();
|
facePatchId_.clear();
|
||||||
faceFlip_.clear();
|
faceFlip_.clear();
|
||||||
sampledPtr_.clear();
|
sampledPtr_.reset(nullptr);
|
||||||
surfaceWriterPtr_.clear();
|
surfaceWriterPtr_.reset(nullptr);
|
||||||
|
|
||||||
|
// Can have "name" (word) and/or "names" (wordRes)
|
||||||
|
//
|
||||||
|
// If "names" exists AND contains a literal (non-regex) that can be used
|
||||||
|
// as a suitable value for "name", the "name" entry becomes optional.
|
||||||
|
|
||||||
|
regionName_.clear();
|
||||||
|
selectionNames_.clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
dict.readIfPresent("names", selectionNames_);
|
||||||
|
|
||||||
|
for (const auto& item : selectionNames_)
|
||||||
|
{
|
||||||
|
if (item.isLiteral())
|
||||||
|
{
|
||||||
|
regionName_ = item;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mandatory if we didn't pick up a value from selectionNames_
|
||||||
|
dict.readEntry
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
regionName_,
|
||||||
|
keyType::LITERAL,
|
||||||
|
regionName_.empty()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure there is always content for selectionNames_
|
||||||
|
if (selectionNames_.empty())
|
||||||
|
{
|
||||||
|
selectionNames_.resize(1);
|
||||||
|
selectionNames_.first() = regionName_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dict.readEntry("name", regionName_);
|
|
||||||
|
|
||||||
// Create sampled surface, but leave 'expired' (ie, no update) since it
|
// Create sampled surface, but leave 'expired' (ie, no update) since it
|
||||||
// may depend on fields or data that do not yet exist
|
// may depend on fields or data that do not yet exist
|
||||||
@ -901,7 +1036,7 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Info<< type() << " " << name() << ":" << nl
|
Info<< type() << ' ' << name() << ':' << nl
|
||||||
<< " operation = ";
|
<< " operation = ";
|
||||||
|
|
||||||
if (postOperation_ != postOpNone)
|
if (postOperation_ != postOpNone)
|
||||||
@ -925,11 +1060,29 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
|
|||||||
<< exit(FatalIOError);
|
<< exit(FatalIOError);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dict.readIfPresent("weightField", weightFieldName_))
|
// Can have "weightFields" or "weightField"
|
||||||
|
|
||||||
|
bool missing = true;
|
||||||
|
if (dict.readIfPresent("weightFields", weightFieldNames_))
|
||||||
{
|
{
|
||||||
Info<< " weight field = " << weightFieldName_ << nl;
|
missing = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
weightFieldNames_.resize(1);
|
||||||
|
|
||||||
|
if (dict.readIfPresent("weightField", weightFieldNames_.first()))
|
||||||
|
{
|
||||||
|
missing = false;
|
||||||
|
if ("none" == weightFieldNames_.first())
|
||||||
|
{
|
||||||
|
// "none" == no weighting
|
||||||
|
weightFieldNames_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing)
|
||||||
{
|
{
|
||||||
// Suggest possible alternative unweighted operation?
|
// Suggest possible alternative unweighted operation?
|
||||||
FatalIOErrorInFunction(dict)
|
FatalIOErrorInFunction(dict)
|
||||||
@ -940,6 +1093,16 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::read
|
|||||||
<< "or use a different operation."
|
<< "or use a different operation."
|
||||||
<< exit(FatalIOError);
|
<< exit(FatalIOError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Info<< " weight field = ";
|
||||||
|
if (weightFieldNames_.empty())
|
||||||
|
{
|
||||||
|
Info<< "none" << nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< flatOutput(weightFieldNames_) << nl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backwards compatibility for v1612 and older
|
// Backwards compatibility for v1612 and older
|
||||||
@ -1048,46 +1211,79 @@ bool Foam::functionObjects::fieldValues::surfaceFieldValue::write()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only a few weight types (scalar, vector)
|
|
||||||
if (weightFieldName_ != "none")
|
// Check availability and type of weight field
|
||||||
|
// Only support a few weight types:
|
||||||
|
// scalar: 0-N fields
|
||||||
|
// vector: 0-1 fields
|
||||||
|
|
||||||
|
// Default is a zero-size scalar weight field (ie, weight = 1)
|
||||||
|
scalarField scalarWeights;
|
||||||
|
vectorField vectorWeights;
|
||||||
|
|
||||||
|
for (const word& weightName : weightFieldNames_)
|
||||||
{
|
{
|
||||||
if (validField<scalar>(weightFieldName_))
|
if (validField<scalar>(weightName))
|
||||||
{
|
{
|
||||||
scalarField weightField
|
tmp<scalarField> tfld = getFieldValues<scalar>(weightName, true);
|
||||||
(
|
|
||||||
getFieldValues<scalar>(weightFieldName_, true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process the fields
|
if (scalarWeights.empty())
|
||||||
writeAll(Sf, weightField, points, faces);
|
{
|
||||||
|
scalarWeights = tfld;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scalarWeights *= tfld;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (validField<vector>(weightFieldName_))
|
else if (validField<vector>(weightName))
|
||||||
{
|
{
|
||||||
vectorField weightField
|
tmp<vectorField> tfld = getFieldValues<vector>(weightName, true);
|
||||||
(
|
|
||||||
getFieldValues<vector>(weightFieldName_, true)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Process the fields
|
if (vectorWeights.empty())
|
||||||
writeAll(Sf, weightField, points, faces);
|
{
|
||||||
|
vectorWeights = tfld;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "weightField " << weightName
|
||||||
|
<< " - only one vector weight field allowed. " << nl
|
||||||
|
<< "weights: " << flatOutput(weightFieldNames_) << nl
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (weightName != "none")
|
||||||
{
|
{
|
||||||
|
// Silently ignore "none", flag everything else as an error
|
||||||
|
|
||||||
|
// TBD: treat missing "rho" like incompressible with rho = 1
|
||||||
|
// and/or provided rhoRef value
|
||||||
|
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "weightField " << weightFieldName_
|
<< "weightField " << weightName
|
||||||
<< " not found or an unsupported type"
|
<< " not found or an unsupported type" << nl
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Process the fields
|
||||||
|
if (vectorWeights.size())
|
||||||
|
{
|
||||||
|
if (scalarWeights.size())
|
||||||
|
{
|
||||||
|
vectorWeights *= scalarWeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeAll(Sf, vectorWeights, points, faces);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Default is a zero-size scalar weight field (ie, weight = 1)
|
writeAll(Sf, scalarWeights, points, faces);
|
||||||
scalarField weightField;
|
|
||||||
|
|
||||||
// Process the fields
|
|
||||||
writeAll(Sf, weightField, points, faces);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (operation_ != opNone)
|
if (operation_ != opNone)
|
||||||
{
|
{
|
||||||
file() << endl;
|
file() << endl;
|
||||||
|
|||||||
@ -31,17 +31,17 @@ Group
|
|||||||
grpFieldFunctionObjects
|
grpFieldFunctionObjects
|
||||||
|
|
||||||
Description
|
Description
|
||||||
Provides a 'face regionType' variant of the \c fieldValues function object.
|
A \c face regionType variant of the \c fieldValues function object.
|
||||||
|
|
||||||
Given a list of user-specified fields and a selection of mesh (or general
|
Given a list of user-specified fields and a selection of mesh (or general
|
||||||
surface) faces, a number of operations can be performed, such as sums,
|
surface) faces, a number of operations can be performed, such as sums,
|
||||||
averages and integrations.
|
averages and integrations.
|
||||||
|
|
||||||
For example, to calculate the volumetric or mass flux across a patch,
|
For example, to calculate the volumetric or mass flux across a patch,
|
||||||
apply the 'sum' operator to the flux field (typically \c phi).
|
apply the \c sum operator to the flux field (typically \c phi).
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
Minimal example by using \c system/controlDict.functions:
|
A minimal example:
|
||||||
\verbatim
|
\verbatim
|
||||||
surfaceFieldValuePatch1
|
surfaceFieldValuePatch1
|
||||||
{
|
{
|
||||||
@ -56,6 +56,8 @@ Usage
|
|||||||
name <patch>;
|
name <patch>;
|
||||||
|
|
||||||
// Optional entries (runtime modifiable)
|
// Optional entries (runtime modifiable)
|
||||||
|
names (<patch-name> <patch-regex>);
|
||||||
|
|
||||||
postOperation none;
|
postOperation none;
|
||||||
weightField alpha1;
|
weightField alpha1;
|
||||||
scaleFactor 1.0;
|
scaleFactor 1.0;
|
||||||
@ -79,8 +81,10 @@ Usage
|
|||||||
name <faceZone>;
|
name <faceZone>;
|
||||||
|
|
||||||
// Optional entries (runtime modifiable)
|
// Optional entries (runtime modifiable)
|
||||||
|
names (<zone-name> <zone-regex>);
|
||||||
|
|
||||||
postOperation none;
|
postOperation none;
|
||||||
weightField alpha1;
|
weightFields (rho U);
|
||||||
scaleFactor 1.0;
|
scaleFactor 1.0;
|
||||||
writeArea false;
|
writeArea false;
|
||||||
surfaceFormat none;
|
surfaceFormat none;
|
||||||
@ -92,15 +96,17 @@ Usage
|
|||||||
|
|
||||||
where the entries mean:
|
where the entries mean:
|
||||||
\table
|
\table
|
||||||
Property | Description | Type | Req'd | Dflt
|
Property | Description | Type | Reqd | Dflt
|
||||||
type | Type name: surfaceFieldValue | word | yes | -
|
type | Type name: surfaceFieldValue | word | yes | -
|
||||||
libs | Library name: fieldFunctionObjects | word | yes | -
|
libs | Libraries: fieldFunctionObjects | wordList | yes | -
|
||||||
fields | Names of operand fields | wordList | yes | -
|
|
||||||
regionType | Face regionType: see below | word | yes | -
|
regionType | Face regionType: see below | word | yes | -
|
||||||
name | Name for regionType | word | yes | -
|
fields | Names of operand fields | wordList | yes | -
|
||||||
|
name | Name of the regionType | word | yes | -
|
||||||
|
names | Extended selection | word/regex list | no | -
|
||||||
operation | Operation type: see below | word | yes | -
|
operation | Operation type: see below | word | yes | -
|
||||||
postOperation | Post-operation type: see below | word | no | none
|
postOperation | Post-operation type: see below | word | no | none
|
||||||
weightField | Name of field to apply weighting | word | no | none
|
weightField | Name of field to apply weighting | word | maybe |
|
||||||
|
weightFields | Names of fields to apply weighting | wordList | maybe |
|
||||||
scaleFactor | Output value scaling factor | scalar | no | 1.0
|
scaleFactor | Output value scaling factor | scalar | no | 1.0
|
||||||
writeArea | Write the surface area | bool | no | false
|
writeArea | Write the surface area | bool | no | false
|
||||||
surfaceFormat | Output value format | word <!--
|
surfaceFormat | Output value format | word <!--
|
||||||
@ -112,9 +118,9 @@ Usage
|
|||||||
|
|
||||||
Options for the \c regionType entry:
|
Options for the \c regionType entry:
|
||||||
\plaintable
|
\plaintable
|
||||||
faceZone | The \b name entry to specify the faceZone
|
faceZone | The \b name entry specifies a faceZone. Supports \b names
|
||||||
patch | The \b name entry to specify the patch
|
patch | The \b name entry specifies a patch. Supports \b names
|
||||||
functionObjectSurface | The \b name entry to specify a polySurface
|
functionObjectSurface | The \b name entry specifies a polySurface
|
||||||
sampledSurface | A \b sampledSurfaceDict sub-dictionary and \b name
|
sampledSurface | A \b sampledSurfaceDict sub-dictionary and \b name
|
||||||
\endplaintable
|
\endplaintable
|
||||||
|
|
||||||
@ -156,12 +162,16 @@ Usage
|
|||||||
Usage by the \c postProcess utility is not available.
|
Usage by the \c postProcess utility is not available.
|
||||||
|
|
||||||
Note
|
Note
|
||||||
|
- Some types (eg, patch or faceZone) support the selection of multiple
|
||||||
|
entries, which can be specified as list of words or regular expressions
|
||||||
|
by \b names entry.<br>
|
||||||
|
If the \b names enty exists \em and contains a literal that can be used
|
||||||
|
as a suitable value for \b name, the \b name entry becomes optional
|
||||||
|
instead of being mandatory.
|
||||||
- The values reported by the \c areaNormalAverage and \c areaNormalIntegrate
|
- The values reported by the \c areaNormalAverage and \c areaNormalIntegrate
|
||||||
operations are written as the first component of a field with the same
|
operations are written as the first component of a field with the same
|
||||||
rank as the input field.
|
rank as the input field.
|
||||||
- Faces on empty patches get ignored.
|
- Faces on empty patches are ignored.
|
||||||
- If the field is a volField the \c faceZone
|
|
||||||
can only consist of boundary faces.
|
|
||||||
- Using \c functionObjectSurface:
|
- Using \c functionObjectSurface:
|
||||||
- The keyword %subRegion should not be used to select surfaces.
|
- The keyword %subRegion should not be used to select surfaces.
|
||||||
Instead specify the regionType 'functionObjectSurface' and provide
|
Instead specify the regionType 'functionObjectSurface' and provide
|
||||||
@ -242,8 +252,8 @@ public:
|
|||||||
//- Region type enumeration
|
//- Region type enumeration
|
||||||
enum regionTypes
|
enum regionTypes
|
||||||
{
|
{
|
||||||
stFaceZone = 0x01, //!< Calculate on a faceZone
|
stFaceZone = 0x01, //!< Calculate with faceZone(s)
|
||||||
stPatch = 0x02, //!< Calculate on a patch
|
stPatch = 0x02, //!< Calculate with patch(es)
|
||||||
stObject = 0x11, //!< Calculate with function object surface
|
stObject = 0x11, //!< Calculate with function object surface
|
||||||
stSampled = 0x12 //!< Sample onto surface and calculate
|
stSampled = 0x12 //!< Sample onto surface and calculate
|
||||||
};
|
};
|
||||||
@ -385,15 +395,18 @@ protected:
|
|||||||
//- Optional post-evaluation operation
|
//- Optional post-evaluation operation
|
||||||
postOperationType postOperation_;
|
postOperationType postOperation_;
|
||||||
|
|
||||||
//- Weight field name - optional
|
|
||||||
word weightFieldName_;
|
|
||||||
|
|
||||||
//- Track if the surface needs an update
|
//- Track if the surface needs an update
|
||||||
bool needsUpdate_;
|
bool needsUpdate_;
|
||||||
|
|
||||||
//- Optionally write the area of the surfaceFieldValue
|
//- Optionally write the area of the surfaceFieldValue
|
||||||
bool writeArea_;
|
bool writeArea_;
|
||||||
|
|
||||||
|
//- Extended selections
|
||||||
|
wordRes selectionNames_;
|
||||||
|
|
||||||
|
//- Weight field name(s) - optional
|
||||||
|
wordList weightFieldNames_;
|
||||||
|
|
||||||
//- Total area of the surfaceFieldValue
|
//- Total area of the surfaceFieldValue
|
||||||
scalar totalArea_;
|
scalar totalArea_;
|
||||||
|
|
||||||
@ -401,17 +414,20 @@ protected:
|
|||||||
label nFaces_;
|
label nFaces_;
|
||||||
|
|
||||||
|
|
||||||
// If operating on mesh faces (faceZone, patch)
|
// If operating on mesh faces (faceZone, patch)
|
||||||
|
|
||||||
//- Local list of face IDs
|
//- Local list of face IDs
|
||||||
labelList faceId_;
|
labelList faceId_;
|
||||||
|
|
||||||
//- Local list of patch ID per face
|
//- Local list of patch ID per face
|
||||||
labelList facePatchId_;
|
labelList facePatchId_;
|
||||||
|
|
||||||
//- List representing the face flip map
|
//- List representing the face flip map
|
||||||
// (false: use as-is, true: negate)
|
// (false: use as-is, true: negate)
|
||||||
boolList faceFlip_;
|
boolList faceFlip_;
|
||||||
|
|
||||||
|
|
||||||
|
// Demand-driven
|
||||||
|
|
||||||
//- The sampledSurface (when operating on sampledSurface)
|
//- The sampledSurface (when operating on sampledSurface)
|
||||||
autoPtr<sampledSurface> sampledPtr_;
|
autoPtr<sampledSurface> sampledPtr_;
|
||||||
|
|||||||
@ -118,7 +118,7 @@ Foam::functionObjects::fieldValues::surfaceFieldValue::getFieldValues
|
|||||||
if (mandatory)
|
if (mandatory)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "Field " << fieldName << " not found in database"
|
<< "Field " << fieldName << " not found in database" << nl
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -135,9 +135,15 @@ void Foam::functionObjects::fieldValues::volFieldValue::writeFileHeader
|
|||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
volRegion::writeFileHeader(*this, os);
|
volRegion::writeFileHeader(*this, os);
|
||||||
if (weightFieldName_ != "none")
|
|
||||||
|
if (weightFieldNames_.size())
|
||||||
{
|
{
|
||||||
writeHeaderValue(os, "Weight field", weightFieldName_);
|
writeHeaderValue
|
||||||
|
(
|
||||||
|
os,
|
||||||
|
"Weight field",
|
||||||
|
flatOutput(weightFieldNames_, FlatOutput::BareComma{})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeCommented(os, "Time");
|
writeCommented(os, "Time");
|
||||||
@ -210,7 +216,7 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue
|
|||||||
true // Failsafe behaviour
|
true // Failsafe behaviour
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
weightFieldName_("none")
|
weightFieldNames_()
|
||||||
{
|
{
|
||||||
read(dict);
|
read(dict);
|
||||||
writeFileHeader(file());
|
writeFileHeader(file());
|
||||||
@ -237,7 +243,7 @@ Foam::functionObjects::fieldValues::volFieldValue::volFieldValue
|
|||||||
true // Failsafe behaviour
|
true // Failsafe behaviour
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
weightFieldName_("none")
|
weightFieldNames_()
|
||||||
{
|
{
|
||||||
read(dict);
|
read(dict);
|
||||||
}
|
}
|
||||||
@ -252,15 +258,33 @@ bool Foam::functionObjects::fieldValues::volFieldValue::read
|
|||||||
{
|
{
|
||||||
fieldValue::read(dict);
|
fieldValue::read(dict);
|
||||||
|
|
||||||
weightFieldName_ = "none";
|
weightFieldNames_.clear();
|
||||||
|
|
||||||
if (usesWeight())
|
if (usesWeight())
|
||||||
{
|
{
|
||||||
if (dict.readIfPresent("weightField", weightFieldName_))
|
// Can have "weightFields" or "weightField"
|
||||||
|
|
||||||
|
bool missing = true;
|
||||||
|
if (dict.readIfPresent("weightFields", weightFieldNames_))
|
||||||
{
|
{
|
||||||
Info<< " weight field = " << weightFieldName_;
|
missing = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
weightFieldNames_.resize(1);
|
||||||
|
|
||||||
|
if (dict.readIfPresent("weightField", weightFieldNames_.first()))
|
||||||
|
{
|
||||||
|
missing = false;
|
||||||
|
if ("none" == weightFieldNames_.first())
|
||||||
|
{
|
||||||
|
// "none" == no weighting
|
||||||
|
weightFieldNames_.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missing)
|
||||||
{
|
{
|
||||||
// Suggest possible alternative unweighted operation?
|
// Suggest possible alternative unweighted operation?
|
||||||
FatalIOErrorInFunction(dict)
|
FatalIOErrorInFunction(dict)
|
||||||
@ -271,6 +295,16 @@ bool Foam::functionObjects::fieldValues::volFieldValue::read
|
|||||||
<< "or use a different operation."
|
<< "or use a different operation."
|
||||||
<< exit(FatalIOError);
|
<< exit(FatalIOError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Info<< " weight field = ";
|
||||||
|
if (weightFieldNames_.empty())
|
||||||
|
{
|
||||||
|
Info<< "none" << nl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Info<< flatOutput(weightFieldNames_) << nl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Info<< nl << endl;
|
Info<< nl << endl;
|
||||||
@ -297,14 +331,45 @@ bool Foam::functionObjects::fieldValues::volFieldValue::write()
|
|||||||
V = filterField(fieldValue::mesh_.V());
|
V = filterField(fieldValue::mesh_.V());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight field - zero-size means weight = 1
|
// Check availability and type of weight field
|
||||||
scalarField weightField;
|
// Only support a few weight types:
|
||||||
if (weightFieldName_ != "none")
|
// scalar: 0-N fields
|
||||||
|
|
||||||
|
// Default is a zero-size scalar weight field (ie, weight = 1)
|
||||||
|
scalarField scalarWeights;
|
||||||
|
|
||||||
|
for (const word& weightName : weightFieldNames_)
|
||||||
{
|
{
|
||||||
weightField = getFieldValues<scalar>(weightFieldName_, true);
|
if (validField<scalar>(weightName))
|
||||||
|
{
|
||||||
|
tmp<scalarField> tfld = getFieldValues<scalar>(weightName, true);
|
||||||
|
|
||||||
|
if (scalarWeights.empty())
|
||||||
|
{
|
||||||
|
scalarWeights = tfld;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scalarWeights *= tfld;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (weightName != "none")
|
||||||
|
{
|
||||||
|
// Silently ignore "none", flag everything else as an error
|
||||||
|
|
||||||
|
// TBD: treat missing "rho" like incompressible with rho = 1
|
||||||
|
// and/or provided rhoRef value
|
||||||
|
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "weightField " << weightName
|
||||||
|
<< " not found or an unsupported type" << nl
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeAll(V, weightField);
|
|
||||||
|
// Process the fields
|
||||||
|
writeAll(V, scalarWeights);
|
||||||
|
|
||||||
if (Pstream::master())
|
if (Pstream::master())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -69,7 +69,8 @@ Usage
|
|||||||
name | Name for regionType | word | yes | -
|
name | Name for regionType | word | yes | -
|
||||||
operation | Operation type: see below | word | yes | -
|
operation | Operation type: see below | word | yes | -
|
||||||
postOperation | Post-operation type: see below | word | no | none
|
postOperation | Post-operation type: see below | word | no | none
|
||||||
weightField | Name of field to apply weighting | word | no | none
|
weightField | Name of field to apply weighting | word | maybe |
|
||||||
|
weightFields | Names of fields to apply weighting | wordList | maybe |
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
The inherited entries are elaborated in:
|
The inherited entries are elaborated in:
|
||||||
@ -214,8 +215,8 @@ protected:
|
|||||||
//- Optional post-evaluation operation
|
//- Optional post-evaluation operation
|
||||||
postOperationType postOperation_;
|
postOperationType postOperation_;
|
||||||
|
|
||||||
//- Weight field name - only used for weighted modes
|
//- Weight field name(s) - optional
|
||||||
word weightFieldName_;
|
wordList weightFieldNames_;
|
||||||
|
|
||||||
|
|
||||||
// Protected Member Functions
|
// Protected Member Functions
|
||||||
@ -233,7 +234,7 @@ protected:
|
|||||||
// Checks for availability on any processor.
|
// Checks for availability on any processor.
|
||||||
inline bool canWeight(const scalarField& weightField) const;
|
inline bool canWeight(const scalarField& weightField) const;
|
||||||
|
|
||||||
//- True if the field name is valid (exists, and a supported type)
|
//- Return true if the field name is valid
|
||||||
template<class Type>
|
template<class Type>
|
||||||
bool validField(const word& fieldName) const;
|
bool validField(const word& fieldName) const;
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ Foam::functionObjects::fieldValues::volFieldValue::getFieldValues
|
|||||||
if (mandatory)
|
if (mandatory)
|
||||||
{
|
{
|
||||||
FatalErrorInFunction
|
FatalErrorInFunction
|
||||||
<< "Field " << fieldName << " not found in database"
|
<< "Field " << fieldName << " not found in database" << nl
|
||||||
<< abort(FatalError);
|
<< abort(FatalError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,6 +35,7 @@ surface/isoSurface/isoSurfaceTopo.C
|
|||||||
surface/thresholdCellFaces/thresholdCellFaces.C
|
surface/thresholdCellFaces/thresholdCellFaces.C
|
||||||
|
|
||||||
sampledSurface/sampledNone/sampledNone.C
|
sampledSurface/sampledNone/sampledNone.C
|
||||||
|
sampledSurface/sampledFaceZone/sampledFaceZone.C
|
||||||
sampledSurface/sampledPatch/sampledPatch.C
|
sampledSurface/sampledPatch/sampledPatch.C
|
||||||
sampledSurface/sampledPatchInternalField/sampledPatchInternalField.C
|
sampledSurface/sampledPatchInternalField/sampledPatchInternalField.C
|
||||||
sampledSurface/sampledPlane/sampledPlane.C
|
sampledSurface/sampledPlane/sampledPlane.C
|
||||||
|
|||||||
402
src/sampling/sampledSurface/sampledFaceZone/sampledFaceZone.C
Normal file
402
src/sampling/sampledSurface/sampledFaceZone/sampledFaceZone.C
Normal file
@ -0,0 +1,402 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 "sampledFaceZone.H"
|
||||||
|
#include "dictionary.H"
|
||||||
|
#include "polyMesh.H"
|
||||||
|
#include "polyPatch.H"
|
||||||
|
#include "volFields.H"
|
||||||
|
#include "surfaceFields.H"
|
||||||
|
#include "volPointInterpolation.H"
|
||||||
|
#include "uindirectPrimitivePatch.H"
|
||||||
|
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(sampledFaceZone, 0);
|
||||||
|
addNamedToRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
sampledSurface,
|
||||||
|
sampledFaceZone,
|
||||||
|
word,
|
||||||
|
faceZone
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::sampledFaceZone::sampledFaceZone
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const polyMesh& mesh,
|
||||||
|
const UList<wordRe>& zoneNames,
|
||||||
|
const bool triangulate
|
||||||
|
)
|
||||||
|
:
|
||||||
|
sampledSurface(name, mesh),
|
||||||
|
selectionNames_(zoneNames),
|
||||||
|
triangulate_(triangulate),
|
||||||
|
needsUpdate_(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::sampledFaceZone::sampledFaceZone
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const polyMesh& mesh,
|
||||||
|
const dictionary& dict
|
||||||
|
)
|
||||||
|
:
|
||||||
|
sampledSurface(name, mesh, dict),
|
||||||
|
selectionNames_(dict.get<wordRes>("zones")),
|
||||||
|
triangulate_(dict.getOrDefault("triangulate", false)),
|
||||||
|
needsUpdate_(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
const Foam::labelList& Foam::sampledFaceZone::zoneIDs() const
|
||||||
|
{
|
||||||
|
if (zoneIds_.empty())
|
||||||
|
{
|
||||||
|
// Zone indices for all matches, already sorted
|
||||||
|
zoneIds_ = mesh().faceZones().indices(selectionNames_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return zoneIds_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::sampledFaceZone::needsUpdate() const
|
||||||
|
{
|
||||||
|
return needsUpdate_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::sampledFaceZone::expire()
|
||||||
|
{
|
||||||
|
// already marked as expired
|
||||||
|
if (needsUpdate_)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampledSurface::clearGeom();
|
||||||
|
Mesh::clear();
|
||||||
|
|
||||||
|
zoneIds_.clear();
|
||||||
|
|
||||||
|
faceId_.clear();
|
||||||
|
facePatchId_.clear();
|
||||||
|
|
||||||
|
needsUpdate_ = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::sampledFaceZone::update()
|
||||||
|
{
|
||||||
|
if (!needsUpdate_)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total number of faces selected
|
||||||
|
label numFaces = 0;
|
||||||
|
for (const label zonei : zoneIDs())
|
||||||
|
{
|
||||||
|
numFaces += mesh().faceZones()[zonei].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zoneIDs().empty())
|
||||||
|
{
|
||||||
|
WarningInFunction
|
||||||
|
<< type() << ' ' << name() << ": "
|
||||||
|
<< " No matching face zone(s): "
|
||||||
|
<< flatOutput(selectionNames_) << nl
|
||||||
|
<< " Known face zones: "
|
||||||
|
<< flatOutput(mesh().faceZones().names()) << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could also check numFaces
|
||||||
|
|
||||||
|
// The mesh face or local patch face and the patch id
|
||||||
|
faceId_.resize(numFaces);
|
||||||
|
facePatchId_.resize(numFaces);
|
||||||
|
|
||||||
|
IndirectList<face> selectedFaces(mesh().faces(), labelList());
|
||||||
|
labelList& meshFaceIds = selectedFaces.addressing();
|
||||||
|
meshFaceIds.resize(numFaces);
|
||||||
|
|
||||||
|
numFaces = 0;
|
||||||
|
|
||||||
|
forAll(zoneIDs(), idx)
|
||||||
|
{
|
||||||
|
const label zonei = zoneIDs()[idx];
|
||||||
|
const faceZone& fZone = mesh().faceZones()[zonei];
|
||||||
|
|
||||||
|
for (const label meshFacei : fZone)
|
||||||
|
{
|
||||||
|
// Internal faces
|
||||||
|
label faceId = meshFacei;
|
||||||
|
label facePatchId = -1;
|
||||||
|
|
||||||
|
// Boundary faces
|
||||||
|
if (!mesh().isInternalFace(meshFacei))
|
||||||
|
{
|
||||||
|
facePatchId = mesh().boundaryMesh().whichPatch(meshFacei);
|
||||||
|
const polyPatch& pp = mesh().boundaryMesh()[facePatchId];
|
||||||
|
|
||||||
|
if (isA<emptyPolyPatch>(pp))
|
||||||
|
{
|
||||||
|
// Do not sample an empty patch
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* procPatch = isA<processorPolyPatch>(pp);
|
||||||
|
if (procPatch && !procPatch->owner())
|
||||||
|
{
|
||||||
|
// Do not sample neighbour-side, retain owner-side only
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* cpp = isA<coupledPolyPatch>(pp);
|
||||||
|
if (cpp)
|
||||||
|
{
|
||||||
|
faceId = (cpp->owner() ? pp.whichFace(meshFacei) : -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
faceId = meshFacei - pp.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faceId >= 0)
|
||||||
|
{
|
||||||
|
faceId_[numFaces] = faceId;
|
||||||
|
facePatchId_[numFaces] = facePatchId;
|
||||||
|
meshFaceIds[numFaces] = meshFacei;
|
||||||
|
++numFaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink to size used
|
||||||
|
faceId_.resize(numFaces);
|
||||||
|
facePatchId_.resize(numFaces);
|
||||||
|
meshFaceIds.resize(numFaces);
|
||||||
|
|
||||||
|
uindirectPrimitivePatch zoneFaces(selectedFaces, mesh().points());
|
||||||
|
|
||||||
|
this->storedPoints() = zoneFaces.localPoints();
|
||||||
|
this->storedFaces() = zoneFaces.localFaces();
|
||||||
|
|
||||||
|
// triangulate - uses remapFaces()
|
||||||
|
if (triangulate_)
|
||||||
|
{
|
||||||
|
Mesh::triangulate();
|
||||||
|
}
|
||||||
|
|
||||||
|
needsUpdate_ = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// remap action on triangulation
|
||||||
|
void Foam::sampledFaceZone::remapFaces(const labelUList& faceMap)
|
||||||
|
{
|
||||||
|
if (!faceMap.empty())
|
||||||
|
{
|
||||||
|
Mesh::remapFaces(faceMap);
|
||||||
|
faceId_ = labelList
|
||||||
|
(
|
||||||
|
labelUIndList(faceId_, faceMap)
|
||||||
|
);
|
||||||
|
facePatchId_ = labelList
|
||||||
|
(
|
||||||
|
labelUIndList(facePatchId_, faceMap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const interpolation<scalar>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::vectorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const interpolation<vector>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::sphericalTensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const interpolation<sphericalTensor>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::symmTensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const interpolation<symmTensor>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::tensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const interpolation<tensor>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sampler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::sampledFaceZone::withSurfaceFields() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const surfaceScalarField& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::vectorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const surfaceVectorField& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::sphericalTensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const surfaceSphericalTensorField& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::symmTensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const surfaceSymmTensorField& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::tensorField> Foam::sampledFaceZone::sample
|
||||||
|
(
|
||||||
|
const surfaceTensorField& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnFaces(sField);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField> Foam::sampledFaceZone::interpolate
|
||||||
|
(
|
||||||
|
const interpolation<scalar>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnPoints(interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::vectorField> Foam::sampledFaceZone::interpolate
|
||||||
|
(
|
||||||
|
const interpolation<vector>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnPoints(interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
|
Foam::tmp<Foam::sphericalTensorField>
|
||||||
|
Foam::sampledFaceZone::interpolate
|
||||||
|
(
|
||||||
|
const interpolation<sphericalTensor>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnPoints(interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::symmTensorField> Foam::sampledFaceZone::interpolate
|
||||||
|
(
|
||||||
|
const interpolation<symmTensor>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnPoints(interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::tensorField> Foam::sampledFaceZone::interpolate
|
||||||
|
(
|
||||||
|
const interpolation<tensor>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return sampleOnPoints(interpolator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::sampledFaceZone::print(Ostream& os) const
|
||||||
|
{
|
||||||
|
os << "faceZone: " << name() << " :"
|
||||||
|
<< " zones: " << flatOutput(selectionNames_)
|
||||||
|
<< " faces:" << faces().size()
|
||||||
|
<< " points:" << points().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
345
src/sampling/sampledSurface/sampledFaceZone/sampledFaceZone.H
Normal file
345
src/sampling/sampledSurface/sampledFaceZone/sampledFaceZone.H
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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::sampledFaceZone
|
||||||
|
|
||||||
|
Description
|
||||||
|
A sampledSurface defined by the cell faces corresponding to a threshold
|
||||||
|
value.
|
||||||
|
|
||||||
|
This is often embedded as part of a sampled surfaces function object.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Example of function object partial specification:
|
||||||
|
\verbatim
|
||||||
|
surfaces
|
||||||
|
(
|
||||||
|
surface1
|
||||||
|
{
|
||||||
|
type faceZones;
|
||||||
|
zones (zone1 "sides.*");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Where the sub-entries comprise:
|
||||||
|
\table
|
||||||
|
Property | Description | Required | Default
|
||||||
|
type | faceZones | yes |
|
||||||
|
zones | zone selection as word/regex list | yes |
|
||||||
|
triangulate | triangulate faces | no | false
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
sampledFaceZone.C
|
||||||
|
sampledFaceZoneTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef sampledFaceZone_H
|
||||||
|
#define sampledFaceZone_H
|
||||||
|
|
||||||
|
#include "sampledSurface.H"
|
||||||
|
#include "MeshedSurfaces.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class sampledFaceZone Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class sampledFaceZone
|
||||||
|
:
|
||||||
|
public meshedSurface,
|
||||||
|
public sampledSurface
|
||||||
|
{
|
||||||
|
//- Mesh storage type
|
||||||
|
typedef meshedSurface Mesh;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Selection (word/regex) of face zones
|
||||||
|
const wordRes selectionNames_;
|
||||||
|
|
||||||
|
//- IDs for selected face zones (sorted)
|
||||||
|
mutable labelList zoneIds_;
|
||||||
|
|
||||||
|
//- Triangulated faces or keep faces as is
|
||||||
|
bool triangulate_;
|
||||||
|
|
||||||
|
//- Track if the surface needs an update
|
||||||
|
mutable bool needsUpdate_;
|
||||||
|
|
||||||
|
//- Local list of face IDs
|
||||||
|
labelList faceId_;
|
||||||
|
|
||||||
|
//- Local list of patch ID per face. Is -1 for internal face
|
||||||
|
labelList facePatchId_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Sample volume/boundary field onto surface faces
|
||||||
|
template<class Type>
|
||||||
|
tmp<Field<Type>> sampleOnFaces
|
||||||
|
(
|
||||||
|
const interpolation<Type>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample surface field onto surface faces
|
||||||
|
template<class Type>
|
||||||
|
tmp<Field<Type>> sampleOnFaces
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvsPatchField, surfaceMesh>& sField
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate volume/boundary field onto surface points
|
||||||
|
template<class Type>
|
||||||
|
tmp<Field<Type>> sampleOnPoints
|
||||||
|
(
|
||||||
|
const interpolation<Type>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
//- Re-map action on triangulation or cleanup
|
||||||
|
virtual void remapFaces(const labelUList& faceMap);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//- The selected face zones (sorted)
|
||||||
|
const labelList& zoneIDs() const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("faceZone");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
sampledFaceZone
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const polyMesh& mesh,
|
||||||
|
const UList<wordRe>& zoneNames,
|
||||||
|
const bool triangulate = false
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Construct from dictionary
|
||||||
|
sampledFaceZone
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const polyMesh& mesh,
|
||||||
|
const dictionary& dict
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~sampledFaceZone() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Does the surface need an update?
|
||||||
|
virtual bool needsUpdate() const;
|
||||||
|
|
||||||
|
//- Mark the surface as needing an update.
|
||||||
|
// May also free up unneeded data.
|
||||||
|
// Return false if surface was already marked as expired.
|
||||||
|
virtual bool expire();
|
||||||
|
|
||||||
|
//- Update the surface as required.
|
||||||
|
// Do nothing (and return false) if no update was needed
|
||||||
|
virtual bool update();
|
||||||
|
|
||||||
|
//- Points of surface
|
||||||
|
virtual const pointField& points() const
|
||||||
|
{
|
||||||
|
return Mesh::points();
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Faces of surface
|
||||||
|
virtual const faceList& faces() const
|
||||||
|
{
|
||||||
|
return Mesh::surfFaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Per-face zone/region information
|
||||||
|
virtual const labelList& zoneIds() const
|
||||||
|
{
|
||||||
|
return labelList::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Face area vectors (normals)
|
||||||
|
virtual const vectorField& Sf() const
|
||||||
|
{
|
||||||
|
return Mesh::Sf();
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Face area magnitudes
|
||||||
|
virtual const scalarField& magSf() const
|
||||||
|
{
|
||||||
|
return Mesh::magSf();
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Face centres
|
||||||
|
virtual const vectorField& Cf() const
|
||||||
|
{
|
||||||
|
return Mesh::Cf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sample
|
||||||
|
|
||||||
|
//- Sample volume field onto surface faces
|
||||||
|
virtual tmp<scalarField> sample
|
||||||
|
(
|
||||||
|
const interpolation<scalar>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample volume field onto surface faces
|
||||||
|
virtual tmp<vectorField> sample
|
||||||
|
(
|
||||||
|
const interpolation<vector>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample volume field onto surface faces
|
||||||
|
virtual tmp<sphericalTensorField> sample
|
||||||
|
(
|
||||||
|
const interpolation<sphericalTensor>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample volume field onto surface faces
|
||||||
|
virtual tmp<symmTensorField> sample
|
||||||
|
(
|
||||||
|
const interpolation<symmTensor>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample volume field onto surface faces
|
||||||
|
virtual tmp<tensorField> sample
|
||||||
|
(
|
||||||
|
const interpolation<tensor>& sampler
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
//- Can it sample surface-fields?
|
||||||
|
virtual bool withSurfaceFields() const;
|
||||||
|
|
||||||
|
|
||||||
|
//- Sample surface field on face zone
|
||||||
|
virtual tmp<scalarField> sample
|
||||||
|
(
|
||||||
|
const surfaceScalarField&
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample surface field on face zone
|
||||||
|
virtual tmp<vectorField> sample
|
||||||
|
(
|
||||||
|
const surfaceVectorField&
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample surface field on face zone
|
||||||
|
virtual tmp<sphericalTensorField> sample
|
||||||
|
(
|
||||||
|
const surfaceSphericalTensorField&
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample surface field on face zone
|
||||||
|
virtual tmp<symmTensorField> sample
|
||||||
|
(
|
||||||
|
const surfaceSymmTensorField&
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Sample surface field on face zone
|
||||||
|
virtual tmp<tensorField> sample
|
||||||
|
(
|
||||||
|
const surfaceTensorField&
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Interpolate
|
||||||
|
|
||||||
|
//- Interpolate volume field onto surface points
|
||||||
|
virtual tmp<scalarField> interpolate
|
||||||
|
(
|
||||||
|
const interpolation<scalar>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate volume field onto surface points
|
||||||
|
virtual tmp<vectorField> interpolate
|
||||||
|
(
|
||||||
|
const interpolation<vector>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate volume field onto surface points
|
||||||
|
virtual tmp<sphericalTensorField> interpolate
|
||||||
|
(
|
||||||
|
const interpolation<sphericalTensor>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate volume field onto surface points
|
||||||
|
virtual tmp<symmTensorField> interpolate
|
||||||
|
(
|
||||||
|
const interpolation<symmTensor>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Interpolate volume field onto surface points
|
||||||
|
virtual tmp<tensorField> interpolate
|
||||||
|
(
|
||||||
|
const interpolation<tensor>& interpolator
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
// Output
|
||||||
|
|
||||||
|
//- Print information
|
||||||
|
virtual void print(Ostream& os) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef NoRepository
|
||||||
|
#include "sampledFaceZoneTemplates.C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 "sampledFaceZone.H"
|
||||||
|
#include "volFieldsFwd.H"
|
||||||
|
#include "pointFields.H"
|
||||||
|
#include "volPointInterpolation.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::Field<Type>>
|
||||||
|
Foam::sampledFaceZone::sampleOnFaces
|
||||||
|
(
|
||||||
|
const interpolation<Type>& sampler
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const auto& vField = sampler.psi();
|
||||||
|
const labelList& own = mesh().faceOwner();
|
||||||
|
const labelList& nei = mesh().faceNeighbour();
|
||||||
|
|
||||||
|
// One value per face
|
||||||
|
auto tvalues = tmp<Field<Type>>::New(faceId_.size());
|
||||||
|
auto& values = tvalues.ref();
|
||||||
|
|
||||||
|
forAll(faceId_, i)
|
||||||
|
{
|
||||||
|
const label facei = faceId_[i];
|
||||||
|
const label patchi = facePatchId_[i];
|
||||||
|
|
||||||
|
if (patchi != -1)
|
||||||
|
{
|
||||||
|
// Boundary face - face id is the patch-local face id
|
||||||
|
values[i] = vField.boundaryField()[patchi][facei];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Internal face
|
||||||
|
values[i] = 0.5*(vField[own[facei]] + vField[nei[facei]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tvalues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::Field<Type>>
|
||||||
|
Foam::sampledFaceZone::sampleOnFaces
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvsPatchField, surfaceMesh>& sField
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// One value per face
|
||||||
|
auto tvalues = tmp<Field<Type>>::New(faceId_.size());
|
||||||
|
auto& values = tvalues.ref();
|
||||||
|
|
||||||
|
forAll(faceId_, i)
|
||||||
|
{
|
||||||
|
const label facei = faceId_[i];
|
||||||
|
const label patchi = facePatchId_[i];
|
||||||
|
|
||||||
|
if (patchi != -1)
|
||||||
|
{
|
||||||
|
// Boundary face - face id is the patch-local face id
|
||||||
|
values[i] = sField.boundaryField()[patchi][facei];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Internal face
|
||||||
|
values[i] = sField[facei];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tvalues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp<Foam::Field<Type>>
|
||||||
|
Foam::sampledFaceZone::sampleOnPoints
|
||||||
|
(
|
||||||
|
const interpolation<Type>& interpolator
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// One value per vertex
|
||||||
|
auto tvalues = tmp<Field<Type>>::New(points().size(), Zero);
|
||||||
|
auto& values = tvalues.ref();
|
||||||
|
|
||||||
|
const labelList& own = mesh().faceOwner();
|
||||||
|
|
||||||
|
bitSet pointDone(points().size());
|
||||||
|
|
||||||
|
forAll(faces(), i)
|
||||||
|
{
|
||||||
|
const face& f = faces()[i];
|
||||||
|
label facei = faceId_[i];
|
||||||
|
const label patchi = facePatchId_[i];
|
||||||
|
|
||||||
|
if (patchi != -1)
|
||||||
|
{
|
||||||
|
// Boundary face. patch-local face id -> mesh face id
|
||||||
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
|
||||||
|
facei += pp.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const label celli = own[facei];
|
||||||
|
|
||||||
|
for (const label pointi : f)
|
||||||
|
{
|
||||||
|
if (pointDone.set(pointi))
|
||||||
|
{
|
||||||
|
values[pointi] = interpolator.interpolate
|
||||||
|
(
|
||||||
|
points()[pointi],
|
||||||
|
celli,
|
||||||
|
facei
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tvalues;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -170,9 +170,9 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
// Does approximation by looking at the face centres only
|
// Does approximation by looking at the face centres only
|
||||||
const pointField& fc = surface_.faceCentres();
|
const pointField& fc = surface_.faceCentres();
|
||||||
|
|
||||||
List<nearInfo> nearest(fc.size(), nearInfo(GREAT, labelMax));
|
List<nearInfo> nearest(fc.size(), nearInfo(Foam::sqr(GREAT), labelMax));
|
||||||
|
|
||||||
if (sampleSource_ == cells)
|
if (sampleSource_ == samplingSource::cells)
|
||||||
{
|
{
|
||||||
// Search for nearest cell
|
// Search for nearest cell
|
||||||
|
|
||||||
@ -181,17 +181,18 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
forAll(fc, facei)
|
forAll(fc, facei)
|
||||||
{
|
{
|
||||||
const point& pt = fc[facei];
|
const point& pt = fc[facei];
|
||||||
|
auto& near = nearest[facei];
|
||||||
|
|
||||||
pointIndexHit info = cellTree.findNearest(pt, sqr(GREAT));
|
pointIndexHit info = cellTree.findNearest(pt, Foam::sqr(GREAT));
|
||||||
|
|
||||||
if (info.hit())
|
if (info.hit())
|
||||||
{
|
{
|
||||||
nearest[facei].first() = magSqr(info.hitPoint()-pt);
|
near.first() = magSqr(info.hitPoint()-pt);
|
||||||
nearest[facei].second() = globalCells.toGlobal(info.index());
|
near.second() = globalCells.toGlobal(info.index());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sampleSource_ == insideCells)
|
else if (sampleSource_ == samplingSource::insideCells)
|
||||||
{
|
{
|
||||||
// Search for cell containing point
|
// Search for cell containing point
|
||||||
|
|
||||||
@ -200,35 +201,37 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
forAll(fc, facei)
|
forAll(fc, facei)
|
||||||
{
|
{
|
||||||
const point& pt = fc[facei];
|
const point& pt = fc[facei];
|
||||||
|
auto& near = nearest[facei];
|
||||||
|
|
||||||
if (cellTree.bb().contains(pt))
|
if (cellTree.bb().contains(pt))
|
||||||
{
|
{
|
||||||
const label index = cellTree.findInside(pt);
|
const label index = cellTree.findInside(pt);
|
||||||
if (index != -1)
|
if (index != -1)
|
||||||
{
|
{
|
||||||
nearest[facei].first() = 0;
|
near.first() = 0;
|
||||||
nearest[facei].second() = globalCells.toGlobal(index);
|
near.second() = globalCells.toGlobal(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // samplingSource::boundaryFaces
|
||||||
{
|
{
|
||||||
// Search for nearest boundaryFace
|
// Search for nearest boundary face
|
||||||
|
// on all non-coupled boundary faces
|
||||||
|
|
||||||
//- Search on all non-coupled boundary faces
|
|
||||||
const auto& bndTree = meshSearcher.nonCoupledBoundaryTree();
|
const auto& bndTree = meshSearcher.nonCoupledBoundaryTree();
|
||||||
|
|
||||||
forAll(fc, facei)
|
forAll(fc, facei)
|
||||||
{
|
{
|
||||||
const point& pt = fc[facei];
|
const point& pt = fc[facei];
|
||||||
|
auto& near = nearest[facei];
|
||||||
|
|
||||||
pointIndexHit info = bndTree.findNearest(pt, sqr(GREAT));
|
pointIndexHit info = bndTree.findNearest(pt, sqr(GREAT));
|
||||||
|
|
||||||
if (info.hit())
|
if (info.hit())
|
||||||
{
|
{
|
||||||
nearest[facei].first() = magSqr(info.hitPoint()-pt);
|
near.first() = magSqr(info.hitPoint()-pt);
|
||||||
nearest[facei].second() =
|
near.second() =
|
||||||
globalCells.toGlobal
|
globalCells.toGlobal
|
||||||
(
|
(
|
||||||
bndTree.shapes().faceLabels()[info.index()]
|
bndTree.shapes().faceLabels()[info.index()]
|
||||||
@ -250,16 +253,26 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
|
|
||||||
forAll(nearest, facei)
|
forAll(nearest, facei)
|
||||||
{
|
{
|
||||||
const label index = nearest[facei].second();
|
const auto& near = nearest[facei];
|
||||||
|
|
||||||
|
const label index = near.second();
|
||||||
|
|
||||||
if (index == labelMax)
|
if (index == labelMax)
|
||||||
{
|
{
|
||||||
// Not found on any processor. How to map?
|
// Not found on any processor, or simply too far.
|
||||||
|
// How to map?
|
||||||
}
|
}
|
||||||
else if (globalCells.isLocal(index))
|
else if (globalCells.isLocal(index))
|
||||||
{
|
{
|
||||||
cellOrFaceLabels[facei] = globalCells.toLocal(index);
|
|
||||||
facesToSubset.set(facei);
|
facesToSubset.set(facei);
|
||||||
|
|
||||||
|
// Mark as special if too far away
|
||||||
|
cellOrFaceLabels[facei] =
|
||||||
|
(
|
||||||
|
(near.first() < maxDistanceSqr_)
|
||||||
|
? globalCells.toLocal(index)
|
||||||
|
: -1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +308,7 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
{
|
{
|
||||||
// With point interpolation
|
// With point interpolation
|
||||||
|
|
||||||
samplePoints_.resize(pointMap.size());
|
samplePoints_ = points();
|
||||||
sampleElements_.resize(pointMap.size(), -1);
|
sampleElements_.resize(pointMap.size(), -1);
|
||||||
|
|
||||||
// Store any face per point (without using pointFaces())
|
// Store any face per point (without using pointFaces())
|
||||||
@ -312,34 +325,27 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (sampleSource_ == cells)
|
if (sampleSource_ == samplingSource::cells)
|
||||||
{
|
{
|
||||||
// samplePoints_ : per surface point a location inside the cell
|
// sampleElements_ : per surface point, the cell
|
||||||
// sampleElements_ : per surface point the cell
|
// samplePoints_ : per surface point, a location inside the cell
|
||||||
|
|
||||||
forAll(points(), pointi)
|
forAll(samplePoints_, pointi)
|
||||||
{
|
{
|
||||||
const point& pt = points()[pointi];
|
// Use _copy_ of point
|
||||||
|
const point pt = samplePoints_[pointi];
|
||||||
|
|
||||||
const label celli = cellOrFaceLabels[pointToFace[pointi]];
|
const label celli = cellOrFaceLabels[pointToFace[pointi]];
|
||||||
|
|
||||||
sampleElements_[pointi] = celli;
|
sampleElements_[pointi] = celli;
|
||||||
|
|
||||||
// Check if point inside cell
|
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
mesh().pointInCell
|
celli >= 0
|
||||||
(
|
&& !mesh().pointInCell(pt, celli, meshSearcher.decompMode())
|
||||||
pt,
|
|
||||||
sampleElements_[pointi],
|
|
||||||
meshSearcher.decompMode()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
samplePoints_[pointi] = pt;
|
// Point not inside cell
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Find nearest point on faces of cell
|
// Find nearest point on faces of cell
|
||||||
|
|
||||||
scalar minDistSqr = VGREAT;
|
scalar minDistSqr = VGREAT;
|
||||||
@ -348,7 +354,12 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
{
|
{
|
||||||
const face& f = mesh().faces()[facei];
|
const face& f = mesh().faces()[facei];
|
||||||
|
|
||||||
pointHit info = f.nearestPoint(pt, mesh().points());
|
pointHit info =
|
||||||
|
f.nearestPoint
|
||||||
|
(
|
||||||
|
pt,
|
||||||
|
mesh().points()
|
||||||
|
);
|
||||||
|
|
||||||
if (info.distance() < minDistSqr)
|
if (info.distance() < minDistSqr)
|
||||||
{
|
{
|
||||||
@ -359,53 +370,56 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sampleSource_ == insideCells)
|
else if (sampleSource_ == samplingSource::insideCells)
|
||||||
{
|
{
|
||||||
// samplePoints_ : per surface point a location inside the cell
|
|
||||||
// sampleElements_ : per surface point the cell
|
// sampleElements_ : per surface point the cell
|
||||||
|
// samplePoints_ : per surface point a location inside the cell
|
||||||
|
|
||||||
forAll(points(), pointi)
|
forAll(samplePoints_, pointi)
|
||||||
{
|
{
|
||||||
const point& pt = points()[pointi];
|
|
||||||
|
|
||||||
const label celli = cellOrFaceLabels[pointToFace[pointi]];
|
const label celli = cellOrFaceLabels[pointToFace[pointi]];
|
||||||
|
|
||||||
sampleElements_[pointi] = celli;
|
sampleElements_[pointi] = celli;
|
||||||
samplePoints_[pointi] = pt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else // samplingSource::boundaryFaces
|
||||||
{
|
{
|
||||||
// samplePoints_ : per surface point a location on the boundary
|
// sampleElements_ : per surface point, the boundary face containing
|
||||||
// sampleElements_ : per surface point the boundary face containing
|
|
||||||
// the location
|
// the location
|
||||||
|
// samplePoints_ : per surface point, a location on the boundary
|
||||||
|
|
||||||
forAll(points(), pointi)
|
forAll(samplePoints_, pointi)
|
||||||
{
|
{
|
||||||
const point& pt = points()[pointi];
|
const point& pt = samplePoints_[pointi];
|
||||||
|
|
||||||
const label facei = cellOrFaceLabels[pointToFace[pointi]];
|
const label facei = cellOrFaceLabels[pointToFace[pointi]];
|
||||||
|
|
||||||
sampleElements_[pointi] = facei;
|
sampleElements_[pointi] = facei;
|
||||||
samplePoints_[pointi] = mesh().faces()[facei].nearestPoint
|
|
||||||
(
|
if (facei >= 0)
|
||||||
pt,
|
{
|
||||||
mesh().points()
|
samplePoints_[pointi] =
|
||||||
).rawPoint();
|
mesh().faces()[facei].nearestPoint
|
||||||
|
(
|
||||||
|
pt,
|
||||||
|
mesh().points()
|
||||||
|
).rawPoint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if sampleSource_ == cells:
|
// if sampleSource_ == cells:
|
||||||
// sampleElements_ : per surface triangle the cell
|
// sampleElements_ : per surface face, the cell
|
||||||
// samplePoints_ : n/a
|
// samplePoints_ : n/a
|
||||||
// if sampleSource_ == insideCells:
|
// if sampleSource_ == insideCells:
|
||||||
// sampleElements_ : -1 or per surface triangle the cell
|
// sampleElements_ : -1 or per surface face, the cell
|
||||||
// samplePoints_ : n/a
|
// samplePoints_ : n/a
|
||||||
// else:
|
// if sampleSource_ == boundaryFaces:
|
||||||
// sampleElements_ : per surface triangle the boundary face
|
// sampleElements_ : per surface face, the boundary face
|
||||||
// samplePoints_ : n/a
|
// samplePoints_ : n/a
|
||||||
|
|
||||||
sampleElements_.transfer(cellOrFaceLabels);
|
sampleElements_.transfer(cellOrFaceLabels);
|
||||||
samplePoints_.clear();
|
samplePoints_.clear();
|
||||||
}
|
}
|
||||||
@ -431,14 +445,14 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
forAll(samplePoints_, pointi)
|
forAll(samplePoints_, pointi)
|
||||||
{
|
{
|
||||||
meshTools::writeOBJ(str, points()[pointi]);
|
meshTools::writeOBJ(str, points()[pointi]);
|
||||||
vertI++;
|
++vertI;
|
||||||
|
|
||||||
meshTools::writeOBJ(str, samplePoints_[pointi]);
|
meshTools::writeOBJ(str, samplePoints_[pointi]);
|
||||||
vertI++;
|
++vertI;
|
||||||
|
|
||||||
label elemi = sampleElements_[pointi];
|
label elemi = sampleElements_[pointi];
|
||||||
meshTools::writeOBJ(str, centres[elemi]);
|
meshTools::writeOBJ(str, centres[elemi]);
|
||||||
vertI++;
|
++vertI;
|
||||||
str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << nl;
|
str << "l " << vertI-2 << ' ' << vertI-1 << ' ' << vertI << nl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,11 +462,11 @@ bool Foam::sampledMeshedSurface::update(const meshSearch& meshSearcher)
|
|||||||
forAll(sampleElements_, triI)
|
forAll(sampleElements_, triI)
|
||||||
{
|
{
|
||||||
meshTools::writeOBJ(str, faceCentres()[triI]);
|
meshTools::writeOBJ(str, faceCentres()[triI]);
|
||||||
vertI++;
|
++vertI;
|
||||||
|
|
||||||
label elemi = sampleElements_[triI];
|
label elemi = sampleElements_[triI];
|
||||||
meshTools::writeOBJ(str, centres[elemi]);
|
meshTools::writeOBJ(str, centres[elemi]);
|
||||||
vertI++;
|
++vertI;
|
||||||
str << "l " << vertI-1 << ' ' << vertI << nl;
|
str << "l " << vertI-1 << ' ' << vertI << nl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,7 +488,7 @@ Foam::sampledMeshedSurface::sampledMeshedSurface
|
|||||||
)
|
)
|
||||||
:
|
:
|
||||||
sampledSurface(name, mesh),
|
sampledSurface(name, mesh),
|
||||||
MeshStorage(),
|
meshedSurface(),
|
||||||
surfaceName_(surfaceName),
|
surfaceName_(surfaceName),
|
||||||
surface_
|
surface_
|
||||||
(
|
(
|
||||||
@ -486,7 +500,9 @@ Foam::sampledMeshedSurface::sampledMeshedSurface
|
|||||||
keepIds_(true),
|
keepIds_(true),
|
||||||
zoneIds_(),
|
zoneIds_(),
|
||||||
sampleElements_(),
|
sampleElements_(),
|
||||||
samplePoints_()
|
samplePoints_(),
|
||||||
|
maxDistanceSqr_(Foam::sqr(GREAT)),
|
||||||
|
defaultValues_()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
@ -498,7 +514,7 @@ Foam::sampledMeshedSurface::sampledMeshedSurface
|
|||||||
)
|
)
|
||||||
:
|
:
|
||||||
sampledSurface(name, mesh, dict),
|
sampledSurface(name, mesh, dict),
|
||||||
MeshStorage(),
|
meshedSurface(),
|
||||||
surfaceName_
|
surfaceName_
|
||||||
(
|
(
|
||||||
meshedSurface::findFile
|
meshedSurface::findFile
|
||||||
@ -517,8 +533,25 @@ Foam::sampledMeshedSurface::sampledMeshedSurface
|
|||||||
keepIds_(dict.getOrDefault("keepIds", true)),
|
keepIds_(dict.getOrDefault("keepIds", true)),
|
||||||
zoneIds_(),
|
zoneIds_(),
|
||||||
sampleElements_(),
|
sampleElements_(),
|
||||||
samplePoints_()
|
samplePoints_(),
|
||||||
|
maxDistanceSqr_(Foam::sqr(GREAT)),
|
||||||
|
defaultValues_(dict.subOrEmptyDict("defaultValue"))
|
||||||
{
|
{
|
||||||
|
if (dict.readIfPresent("maxDistance", maxDistanceSqr_))
|
||||||
|
{
|
||||||
|
// Info<< "Limit to maxDistance " << maxDistanceSqr_ << nl;
|
||||||
|
// if (defaultValues_.empty())
|
||||||
|
// {
|
||||||
|
// Info<< "defaultValues = zero" << nl;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// defaultValues_.writeEntry(Info);
|
||||||
|
// }
|
||||||
|
|
||||||
|
maxDistanceSqr_ = Foam::sqr(maxDistanceSqr_);
|
||||||
|
}
|
||||||
|
|
||||||
wordRes includePatches;
|
wordRes includePatches;
|
||||||
dict.readIfPresent("patches", includePatches);
|
dict.readIfPresent("patches", includePatches);
|
||||||
includePatches.uniq();
|
includePatches.uniq();
|
||||||
@ -596,7 +629,7 @@ bool Foam::sampledMeshedSurface::expire()
|
|||||||
}
|
}
|
||||||
|
|
||||||
sampledSurface::clearGeom();
|
sampledSurface::clearGeom();
|
||||||
MeshStorage::clear();
|
meshedSurface::clear();
|
||||||
zoneIds_.clear();
|
zoneIds_.clear();
|
||||||
|
|
||||||
sampleElements_.clear();
|
sampleElements_.clear();
|
||||||
|
|||||||
@ -35,33 +35,35 @@ Description
|
|||||||
|
|
||||||
- 6 different modes:
|
- 6 different modes:
|
||||||
- source=cells, interpolate=false:
|
- source=cells, interpolate=false:
|
||||||
finds per triangle centre the nearest cell centre and uses its value
|
finds per surface face centre the \em nearest cell centre
|
||||||
- source=cells, interpolate=true
|
and uses its value
|
||||||
finds per triangle centre the nearest cell centre.
|
- source=cells, interpolate=true:
|
||||||
|
finds per surface face centre the \em nearest cell centre.
|
||||||
Per surface point checks if this nearest cell is the one containing
|
Per surface point checks if this nearest cell is the one containing
|
||||||
point; otherwise projects the point onto the nearest point on
|
point; otherwise projects the point onto the nearest point on
|
||||||
the boundary of the cell (to make sure interpolateCellPoint
|
the boundary of the cell (to make sure interpolateCellPoint
|
||||||
gets a valid location)
|
gets a valid location)
|
||||||
|
|
||||||
- source=insideCells, interpolate=false:
|
- source=insideCells, interpolate=false:
|
||||||
finds per triangle centre the cell containing it and uses its value.
|
finds per surface face centre the cell containing it
|
||||||
Trims triangles outside mesh.
|
and uses its value.
|
||||||
- source=insideCells, interpolate=true
|
Trims surface faces outside of the mesh.
|
||||||
|
- source=insideCells, interpolate=true:
|
||||||
Per surface point interpolate cell containing it.
|
Per surface point interpolate cell containing it.
|
||||||
|
|
||||||
- source=boundaryFaces, interpolate=false:
|
- source=boundaryFaces, interpolate=false:
|
||||||
finds per triangle centre the nearest point on the boundary
|
finds per surface face centre the \em nearest point on the boundary
|
||||||
(uncoupled faces only) and uses the value (or 0 if the nearest
|
(uncoupled faces only) and uses the value (or 0 if the nearest
|
||||||
is on an empty boundary)
|
is on an empty boundary)
|
||||||
- source=boundaryFaces, interpolate=true:
|
- source=boundaryFaces, interpolate=true:
|
||||||
finds per triangle centre the nearest point on the boundary
|
finds per surface face centre the \em nearest point on the boundary
|
||||||
(uncoupled faces only).
|
(uncoupled faces only).
|
||||||
Per surface point projects the point onto this boundary face
|
Per surface point projects the point onto this boundary face
|
||||||
(to make sure interpolateCellPoint gets a valid location)
|
(to make sure interpolateCellPoint gets a valid location)
|
||||||
|
|
||||||
- since it finds a nearest per triangle each triangle is guaranteed
|
- since it finds the nearest per surface face, each surface face
|
||||||
to be on one processor only. So after stitching (by sampledSurfaces)
|
is guaranteed to be on one processor only.
|
||||||
the original surface should be complete.
|
So after stitching the original surface should be complete.
|
||||||
|
|
||||||
This is often embedded as part of a sampled surfaces function object.
|
This is often embedded as part of a sampled surfaces function object.
|
||||||
|
|
||||||
@ -75,6 +77,16 @@ Usage
|
|||||||
type meshedSurface;
|
type meshedSurface;
|
||||||
surface something.obj;
|
surface something.obj;
|
||||||
source cells;
|
source cells;
|
||||||
|
|
||||||
|
//- Max sampling distance
|
||||||
|
maxDistance 0.005;
|
||||||
|
|
||||||
|
//- Fallback for missed sampling in 'cells' mode
|
||||||
|
defaultValue
|
||||||
|
{
|
||||||
|
"p.*" 1e5;
|
||||||
|
T 273.15;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
\endverbatim
|
\endverbatim
|
||||||
@ -90,8 +102,11 @@ Usage
|
|||||||
file | Alternative file name | no |
|
file | Alternative file name | no |
|
||||||
fileType | The surface format | no | (extension)
|
fileType | The surface format | no | (extension)
|
||||||
scale | Surface scaling factor | no | 0
|
scale | Surface scaling factor | no | 0
|
||||||
|
maxDistance | Max search distance | no | GREAT
|
||||||
|
defaultValue | Value beyond max distance (dictionary) | no | empty
|
||||||
\endtable
|
\endtable
|
||||||
|
|
||||||
|
|
||||||
SourceFiles
|
SourceFiles
|
||||||
sampledMeshedSurface.C
|
sampledMeshedSurface.C
|
||||||
sampledMeshedSurfaceTemplates.C
|
sampledMeshedSurfaceTemplates.C
|
||||||
@ -102,8 +117,7 @@ SourceFiles
|
|||||||
#define sampledMeshedSurface_H
|
#define sampledMeshedSurface_H
|
||||||
|
|
||||||
#include "sampledSurface.H"
|
#include "sampledSurface.H"
|
||||||
#include "MeshedSurface.H"
|
#include "MeshedSurfaces.H"
|
||||||
#include "MeshedSurfacesFwd.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -123,18 +137,19 @@ class sampledMeshedSurface
|
|||||||
public meshedSurface
|
public meshedSurface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//- Types of sampling regions
|
//- Types of sampling regions
|
||||||
enum samplingSource
|
enum class samplingSource : unsigned char
|
||||||
{
|
{
|
||||||
cells,
|
cells, //!< Use nearest cell value
|
||||||
insideCells,
|
insideCells, //!< Surface face within a cell, or trim
|
||||||
boundaryFaces
|
boundaryFaces //!< Use nearest boundary face values
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
//- Private typedefs for convenience
|
//- The concrete storage type for faces and points
|
||||||
typedef meshedSurface MeshStorage;
|
typedef meshedSurface Mesh;
|
||||||
|
|
||||||
|
|
||||||
// Private Data
|
// Private Data
|
||||||
@ -165,6 +180,12 @@ private:
|
|||||||
//- Local points to sample per point
|
//- Local points to sample per point
|
||||||
pointField samplePoints_;
|
pointField samplePoints_;
|
||||||
|
|
||||||
|
//- Max search distance squared
|
||||||
|
scalar maxDistanceSqr_;
|
||||||
|
|
||||||
|
//- Out-of-range fallback values (when beyond the max search distance)
|
||||||
|
dictionary defaultValues_;
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
@ -239,13 +260,13 @@ public:
|
|||||||
//- Points of surface
|
//- Points of surface
|
||||||
virtual const pointField& points() const
|
virtual const pointField& points() const
|
||||||
{
|
{
|
||||||
return MeshStorage::points();
|
return Mesh::points();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Faces of surface
|
//- Faces of surface
|
||||||
virtual const faceList& faces() const
|
virtual const faceList& faces() const
|
||||||
{
|
{
|
||||||
return MeshStorage::surfFaces();
|
return Mesh::surfFaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Per-face zone/region information
|
//- Per-face zone/region information
|
||||||
@ -257,37 +278,37 @@ public:
|
|||||||
//- Per-face identifier (eg, element Id)
|
//- Per-face identifier (eg, element Id)
|
||||||
virtual const labelList& faceIds() const
|
virtual const labelList& faceIds() const
|
||||||
{
|
{
|
||||||
return MeshStorage::faceIds();
|
return Mesh::faceIds();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Face area vectors
|
//- Face area vectors
|
||||||
virtual const vectorField& Sf() const
|
virtual const vectorField& Sf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::Sf();
|
return Mesh::Sf();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Face area magnitudes
|
//- Face area magnitudes
|
||||||
virtual const scalarField& magSf() const
|
virtual const scalarField& magSf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::magSf();
|
return Mesh::magSf();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Face centres
|
//- Face centres
|
||||||
virtual const vectorField& Cf() const
|
virtual const vectorField& Cf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::Cf();
|
return Mesh::Cf();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- If element ids/order of the original surface are kept
|
//- If element ids/order of the original surface are kept
|
||||||
virtual bool hasFaceIds() const
|
virtual bool hasFaceIds() const
|
||||||
{
|
{
|
||||||
return keepIds_ && !MeshStorage::faceIds().empty();
|
return keepIds_ && !Mesh::faceIds().empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Sampling boundary values instead of cell values
|
//- Sampling boundary values instead of cell values
|
||||||
bool onBoundary() const
|
bool onBoundary() const
|
||||||
{
|
{
|
||||||
return sampleSource_ == boundaryFaces;
|
return sampleSource_ == samplingSource::boundaryFaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,14 @@ Foam::sampledMeshedSurface::sampleOnFaces
|
|||||||
const interpolation<Type>& sampler
|
const interpolation<Type>& sampler
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
|
const Type deflt
|
||||||
|
(
|
||||||
|
defaultValues_.getOrDefault<Type>(sampler.psi().name(), Zero)
|
||||||
|
);
|
||||||
|
|
||||||
const labelList& elements = sampleElements_;
|
const labelList& elements = sampleElements_;
|
||||||
|
|
||||||
|
|
||||||
if (!onBoundary())
|
if (!onBoundary())
|
||||||
{
|
{
|
||||||
// Sample cells
|
// Sample cells
|
||||||
@ -48,7 +54,8 @@ Foam::sampledMeshedSurface::sampleOnFaces
|
|||||||
sampler,
|
sampler,
|
||||||
elements,
|
elements,
|
||||||
faces(),
|
faces(),
|
||||||
points()
|
points(),
|
||||||
|
deflt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,33 +67,33 @@ Foam::sampledMeshedSurface::sampleOnFaces
|
|||||||
auto tvalues = tmp<Field<Type>>::New(elements.size());
|
auto tvalues = tmp<Field<Type>>::New(elements.size());
|
||||||
auto& values = tvalues.ref();
|
auto& values = tvalues.ref();
|
||||||
|
|
||||||
const polyBoundaryMesh& pbm = mesh().boundaryMesh();
|
|
||||||
const label nBnd = mesh().nBoundaryFaces();
|
|
||||||
|
|
||||||
// Create flat boundary field
|
// Create flat boundary field
|
||||||
|
|
||||||
Field<Type> bVals(nBnd, Zero);
|
const polyBoundaryMesh& pbm = mesh().boundaryMesh();
|
||||||
|
|
||||||
|
Field<Type> bVals(mesh().nBoundaryFaces(), Zero);
|
||||||
|
|
||||||
const auto& bField = sampler.psi().boundaryField();
|
const auto& bField = sampler.psi().boundaryField();
|
||||||
|
|
||||||
forAll(bField, patchi)
|
forAll(bField, patchi)
|
||||||
{
|
{
|
||||||
const label bFacei = (pbm[patchi].start() - mesh().nInternalFaces());
|
SubList<Type>(bVals, pbm[patchi].range()) = bField[patchi];
|
||||||
|
|
||||||
SubList<Type>
|
|
||||||
(
|
|
||||||
bVals,
|
|
||||||
bField[patchi].size(),
|
|
||||||
bFacei
|
|
||||||
) = bField[patchi];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sample in flat boundary field
|
// Sample within the flat boundary field
|
||||||
|
|
||||||
forAll(elements, i)
|
forAll(elements, i)
|
||||||
{
|
{
|
||||||
const label bFacei = (elements[i] - mesh().nInternalFaces());
|
const label bFacei = (elements[i] - mesh().nInternalFaces());
|
||||||
values[i] = bVals[bFacei];
|
|
||||||
|
if (bFacei < 0)
|
||||||
|
{
|
||||||
|
values[i] = deflt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values[i] = bVals[bFacei];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tvalues;
|
return tvalues;
|
||||||
@ -100,34 +107,60 @@ Foam::sampledMeshedSurface::sampleOnPoints
|
|||||||
const interpolation<Type>& interpolator
|
const interpolation<Type>& interpolator
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
// One value per vertex
|
const Type deflt
|
||||||
auto tvalues = tmp<Field<Type>>::New(sampleElements_.size());
|
(
|
||||||
|
defaultValues_.getOrDefault<Type>(interpolator.psi().name(), Zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
const labelList& elements = sampleElements_;
|
||||||
|
|
||||||
|
|
||||||
|
// One value per vertex.
|
||||||
|
// - sampleElements_ and samplePoints_ have the identical size
|
||||||
|
auto tvalues = tmp<Field<Type>>::New(elements.size());
|
||||||
auto& values = tvalues.ref();
|
auto& values = tvalues.ref();
|
||||||
|
|
||||||
if (!onBoundary())
|
if (!onBoundary())
|
||||||
{
|
{
|
||||||
// Sample cells
|
// Sample cells
|
||||||
|
|
||||||
forAll(sampleElements_, pointi)
|
forAll(elements, i)
|
||||||
{
|
{
|
||||||
values[pointi] = interpolator.interpolate
|
const label celli = elements[i];
|
||||||
(
|
|
||||||
samplePoints_[pointi],
|
if (celli < 0)
|
||||||
sampleElements_[pointi]
|
{
|
||||||
);
|
values[i] = deflt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
values[i] = interpolator.interpolate
|
||||||
|
(
|
||||||
|
samplePoints_[i],
|
||||||
|
celli
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sample boundary faces
|
||||||
|
//
|
||||||
|
|
||||||
|
forAll(elements, i)
|
||||||
{
|
{
|
||||||
// Sample boundary faces
|
const label facei = elements[i];
|
||||||
|
|
||||||
forAll(samplePoints_, pointi)
|
if (facei < 0)
|
||||||
{
|
{
|
||||||
const label facei = sampleElements_[pointi];
|
values[i] = deflt;
|
||||||
|
}
|
||||||
values[pointi] = interpolator.interpolate
|
else
|
||||||
|
{
|
||||||
|
values[i] = interpolator.interpolate
|
||||||
(
|
(
|
||||||
samplePoints_[pointi],
|
samplePoints_[i],
|
||||||
mesh().faceOwner()[facei],
|
mesh().faceOwner()[facei],
|
||||||
facei
|
facei
|
||||||
);
|
);
|
||||||
|
|||||||
@ -32,6 +32,7 @@ License
|
|||||||
#include "polyPatch.H"
|
#include "polyPatch.H"
|
||||||
#include "volFields.H"
|
#include "volFields.H"
|
||||||
#include "surfaceFields.H"
|
#include "surfaceFields.H"
|
||||||
|
#include "uindirectPrimitivePatch.H"
|
||||||
|
|
||||||
#include "addToRunTimeSelectionTable.H"
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ Foam::sampledPatch::sampledPatch
|
|||||||
)
|
)
|
||||||
:
|
:
|
||||||
sampledSurface(name, mesh),
|
sampledSurface(name, mesh),
|
||||||
patchNames_(patchNames),
|
selectionNames_(patchNames),
|
||||||
triangulate_(triangulate),
|
triangulate_(triangulate),
|
||||||
needsUpdate_(true)
|
needsUpdate_(true)
|
||||||
{}
|
{}
|
||||||
@ -69,7 +70,7 @@ Foam::sampledPatch::sampledPatch
|
|||||||
)
|
)
|
||||||
:
|
:
|
||||||
sampledSurface(name, mesh, dict),
|
sampledSurface(name, mesh, dict),
|
||||||
patchNames_(dict.get<wordRes>("patches")),
|
selectionNames_(dict.get<wordRes>("patches")),
|
||||||
triangulate_(dict.getOrDefault("triangulate", false)),
|
triangulate_(dict.getOrDefault("triangulate", false)),
|
||||||
needsUpdate_(true)
|
needsUpdate_(true)
|
||||||
{}
|
{}
|
||||||
@ -81,8 +82,63 @@ const Foam::labelList& Foam::sampledPatch::patchIDs() const
|
|||||||
{
|
{
|
||||||
if (patchIDs_.empty())
|
if (patchIDs_.empty())
|
||||||
{
|
{
|
||||||
patchIDs_ = mesh().boundaryMesh().patchSet(patchNames_).sortedToc();
|
labelList selected
|
||||||
|
(
|
||||||
|
mesh().boundaryMesh().patchSet(selectionNames_).sortedToc()
|
||||||
|
);
|
||||||
|
|
||||||
|
DynamicList<label> bad;
|
||||||
|
for (const label patchi : selected)
|
||||||
|
{
|
||||||
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
|
||||||
|
if (isA<emptyPolyPatch>(pp))
|
||||||
|
{
|
||||||
|
bad.append(patchi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bad.size())
|
||||||
|
{
|
||||||
|
label nGood = (selected.size() - bad.size());
|
||||||
|
|
||||||
|
auto& os = nGood > 0 ? WarningInFunction : FatalErrorInFunction;
|
||||||
|
|
||||||
|
os << "Cannot sample an empty patch" << nl;
|
||||||
|
|
||||||
|
for (const label patchi : bad)
|
||||||
|
{
|
||||||
|
os << " "
|
||||||
|
<< mesh().boundaryMesh()[patchi].name() << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nGood)
|
||||||
|
{
|
||||||
|
os << "No non-empty patches selected" << endl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << "Selected " << nGood << " non-empty patches" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
patchIDs_.resize(nGood);
|
||||||
|
nGood = 0;
|
||||||
|
for (const label patchi : selected)
|
||||||
|
{
|
||||||
|
if (!bad.found(patchi))
|
||||||
|
{
|
||||||
|
patchIDs_[nGood] = patchi;
|
||||||
|
++nGood;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
patchIDs_ = std::move(selected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return patchIDs_;
|
return patchIDs_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,11 +158,13 @@ bool Foam::sampledPatch::expire()
|
|||||||
}
|
}
|
||||||
|
|
||||||
sampledSurface::clearGeom();
|
sampledSurface::clearGeom();
|
||||||
MeshStorage::clear();
|
Mesh::clear();
|
||||||
|
|
||||||
patchIDs_.clear();
|
patchIDs_.clear();
|
||||||
|
patchStart_.clear();
|
||||||
|
|
||||||
patchIndex_.clear();
|
patchIndex_.clear();
|
||||||
patchFaceLabels_.clear();
|
patchFaceLabels_.clear();
|
||||||
patchStart_.clear();
|
|
||||||
|
|
||||||
needsUpdate_ = true;
|
needsUpdate_ = true;
|
||||||
return true;
|
return true;
|
||||||
@ -120,52 +178,45 @@ bool Foam::sampledPatch::update()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
label sz = 0;
|
// Total number of faces selected
|
||||||
|
label numFaces = 0;
|
||||||
for (const label patchi : patchIDs())
|
for (const label patchi : patchIDs())
|
||||||
{
|
{
|
||||||
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
numFaces += pp.size();
|
||||||
if (isA<emptyPolyPatch>(pp))
|
|
||||||
{
|
|
||||||
FatalErrorInFunction
|
|
||||||
<< "Cannot sample an empty patch. Patch " << pp.name()
|
|
||||||
<< exit(FatalError);
|
|
||||||
}
|
|
||||||
|
|
||||||
sz += pp.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For every face (or triangle) the originating patch and local face in the
|
patchStart_.resize(patchIDs().size());
|
||||||
// patch.
|
|
||||||
patchIndex_.setSize(sz);
|
|
||||||
patchFaceLabels_.setSize(sz);
|
|
||||||
patchStart_.setSize(patchIDs().size());
|
|
||||||
labelList meshFaceLabels(sz);
|
|
||||||
|
|
||||||
sz = 0;
|
// The originating patch and local face in the patch.
|
||||||
|
patchIndex_.resize(numFaces);
|
||||||
|
patchFaceLabels_.resize(numFaces);
|
||||||
|
|
||||||
forAll(patchIDs(), i)
|
IndirectList<face> selectedFaces(mesh().faces(), labelList());
|
||||||
|
labelList& meshFaceIds = selectedFaces.addressing();
|
||||||
|
meshFaceIds.resize(numFaces);
|
||||||
|
|
||||||
|
numFaces = 0;
|
||||||
|
|
||||||
|
forAll(patchIDs(), idx)
|
||||||
{
|
{
|
||||||
const label patchi = patchIDs()[i];
|
const label patchi = patchIDs()[idx];
|
||||||
|
|
||||||
patchStart_[i] = sz;
|
|
||||||
|
|
||||||
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
const label len = pp.size();
|
||||||
|
|
||||||
forAll(pp, j)
|
patchStart_[idx] = numFaces;
|
||||||
{
|
|
||||||
patchIndex_[sz] = i;
|
SubList<label>(patchIndex_, len, numFaces) = idx;
|
||||||
patchFaceLabels_[sz] = j;
|
|
||||||
meshFaceLabels[sz] = pp.start()+j;
|
SubList<label>(patchFaceLabels_, len, numFaces) = identity(len);
|
||||||
++sz;
|
|
||||||
}
|
SubList<label>(meshFaceIds, len, numFaces) = identity(len, pp.start());
|
||||||
|
|
||||||
|
numFaces += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
indirectPrimitivePatch allPatches
|
|
||||||
(
|
uindirectPrimitivePatch allPatches(selectedFaces, mesh().points());
|
||||||
IndirectList<face>(mesh().faces(), meshFaceLabels),
|
|
||||||
mesh().points()
|
|
||||||
);
|
|
||||||
|
|
||||||
this->storedPoints() = allPatches.localPoints();
|
this->storedPoints() = allPatches.localPoints();
|
||||||
this->storedFaces() = allPatches.localFaces();
|
this->storedFaces() = allPatches.localFaces();
|
||||||
@ -177,7 +228,7 @@ bool Foam::sampledPatch::update()
|
|||||||
// too often anyhow.
|
// too often anyhow.
|
||||||
if (triangulate_)
|
if (triangulate_)
|
||||||
{
|
{
|
||||||
MeshStorage::triangulate();
|
Mesh::triangulate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -194,10 +245,9 @@ bool Foam::sampledPatch::update()
|
|||||||
// remap action on triangulation
|
// remap action on triangulation
|
||||||
void Foam::sampledPatch::remapFaces(const labelUList& faceMap)
|
void Foam::sampledPatch::remapFaces(const labelUList& faceMap)
|
||||||
{
|
{
|
||||||
// Recalculate the cells cut
|
|
||||||
if (!faceMap.empty())
|
if (!faceMap.empty())
|
||||||
{
|
{
|
||||||
MeshStorage::remapFaces(faceMap);
|
Mesh::remapFaces(faceMap);
|
||||||
patchFaceLabels_ = labelList
|
patchFaceLabels_ = labelList
|
||||||
(
|
(
|
||||||
labelUIndList(patchFaceLabels_, faceMap)
|
labelUIndList(patchFaceLabels_, faceMap)
|
||||||
@ -207,11 +257,11 @@ void Foam::sampledPatch::remapFaces(const labelUList& faceMap)
|
|||||||
labelUIndList(patchIndex_, faceMap)
|
labelUIndList(patchIndex_, faceMap)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Redo patchStart.
|
// Update patchStart
|
||||||
if (patchIndex_.size() > 0)
|
if (patchIndex_.size())
|
||||||
{
|
{
|
||||||
patchStart_[patchIndex_[0]] = 0;
|
patchStart_[patchIndex_[0]] = 0;
|
||||||
for (label i = 1; i < patchIndex_.size(); i++)
|
for (label i = 1; i < patchIndex_.size(); ++i)
|
||||||
{
|
{
|
||||||
if (patchIndex_[i] != patchIndex_[i-1])
|
if (patchIndex_[i] != patchIndex_[i-1])
|
||||||
{
|
{
|
||||||
@ -367,7 +417,7 @@ Foam::tmp<Foam::tensorField> Foam::sampledPatch::interpolate
|
|||||||
void Foam::sampledPatch::print(Ostream& os) const
|
void Foam::sampledPatch::print(Ostream& os) const
|
||||||
{
|
{
|
||||||
os << "sampledPatch: " << name() << " :"
|
os << "sampledPatch: " << name() << " :"
|
||||||
<< " patches:" << patchNames()
|
<< " patches: " << flatOutput(selectionNames_)
|
||||||
<< " faces:" << faces().size()
|
<< " faces:" << faces().size()
|
||||||
<< " points:" << points().size();
|
<< " points:" << points().size();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2016-2019 OpenCFD Ltd.
|
Copyright (C) 2016-2020 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -62,8 +62,7 @@ SourceFiles
|
|||||||
#define sampledPatch_H
|
#define sampledPatch_H
|
||||||
|
|
||||||
#include "sampledSurface.H"
|
#include "sampledSurface.H"
|
||||||
#include "MeshedSurface.H"
|
#include "MeshedSurfaces.H"
|
||||||
#include "wordRes.H"
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
@ -76,19 +75,19 @@ namespace Foam
|
|||||||
|
|
||||||
class sampledPatch
|
class sampledPatch
|
||||||
:
|
:
|
||||||
public MeshedSurface<face>,
|
public meshedSurface,
|
||||||
public sampledSurface
|
public sampledSurface
|
||||||
{
|
{
|
||||||
//- Private typedefs for convenience
|
//- Mesh storage type
|
||||||
typedef MeshedSurface<face> MeshStorage;
|
typedef meshedSurface Mesh;
|
||||||
|
|
||||||
|
|
||||||
// Private data
|
// Private Data
|
||||||
|
|
||||||
//- Name of patches
|
//- Selection (word/regex) of patches
|
||||||
const wordRes patchNames_;
|
const wordRes selectionNames_;
|
||||||
|
|
||||||
//- Corresponding patchIDs
|
//- The IDs for selected patches. Sorted and no emptyPolyPatch
|
||||||
mutable labelList patchIDs_;
|
mutable labelList patchIDs_;
|
||||||
|
|
||||||
//- Triangulated faces or keep faces as is
|
//- Triangulated faces or keep faces as is
|
||||||
@ -97,15 +96,15 @@ class sampledPatch
|
|||||||
//- Track if the surface needs an update
|
//- Track if the surface needs an update
|
||||||
mutable bool needsUpdate_;
|
mutable bool needsUpdate_;
|
||||||
|
|
||||||
|
//- Start indices (in patchFaceLabels_) of patches
|
||||||
|
labelList patchStart_;
|
||||||
|
|
||||||
//- For every face (or triangle) the originating patch
|
//- For every face (or triangle) the originating patch
|
||||||
labelList patchIndex_;
|
labelList patchIndex_;
|
||||||
|
|
||||||
//- For every face (or triangle) the index in the originating patch
|
//- For every face (or triangle) the index in the originating patch
|
||||||
labelList patchFaceLabels_;
|
labelList patchFaceLabels_;
|
||||||
|
|
||||||
//- Start indices (in patchFaceLabels_) of patches
|
|
||||||
labelList patchStart_;
|
|
||||||
|
|
||||||
|
|
||||||
// Private Member Functions
|
// Private Member Functions
|
||||||
|
|
||||||
@ -137,23 +136,28 @@ class sampledPatch
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
//- The selection (word/regex) of patches
|
||||||
const wordRes& patchNames() const
|
const wordRes& patchNames() const
|
||||||
{
|
{
|
||||||
return patchNames_;
|
return selectionNames_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- The patches selected
|
||||||
const labelList& patchIDs() const;
|
const labelList& patchIDs() const;
|
||||||
|
|
||||||
|
//- The offset into patchIndex, patchFaceLabels
|
||||||
const labelList& patchStart() const
|
const labelList& patchStart() const
|
||||||
{
|
{
|
||||||
return patchStart_;
|
return patchStart_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- For each face, the patch ID
|
||||||
const labelList& patchIndex() const
|
const labelList& patchIndex() const
|
||||||
{
|
{
|
||||||
return patchIndex_;
|
return patchIndex_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//- For each face, the patch local face ID
|
||||||
const labelList& patchFaceLabels() const
|
const labelList& patchFaceLabels() const
|
||||||
{
|
{
|
||||||
return patchFaceLabels_;
|
return patchFaceLabels_;
|
||||||
@ -208,13 +212,13 @@ public:
|
|||||||
//- Points of surface
|
//- Points of surface
|
||||||
virtual const pointField& points() const
|
virtual const pointField& points() const
|
||||||
{
|
{
|
||||||
return MeshStorage::points();
|
return Mesh::points();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Faces of surface
|
//- Faces of surface
|
||||||
virtual const faceList& faces() const
|
virtual const faceList& faces() const
|
||||||
{
|
{
|
||||||
return MeshStorage::surfFaces();
|
return Mesh::surfFaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Per-face zone/region information
|
//- Per-face zone/region information
|
||||||
@ -226,19 +230,19 @@ public:
|
|||||||
//- Face area vectors
|
//- Face area vectors
|
||||||
virtual const vectorField& Sf() const
|
virtual const vectorField& Sf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::Sf();
|
return Mesh::Sf();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Face area magnitudes
|
//- Face area magnitudes
|
||||||
virtual const scalarField& magSf() const
|
virtual const scalarField& magSf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::magSf();
|
return Mesh::magSf();
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Face centres
|
//- Face centres
|
||||||
virtual const vectorField& Cf() const
|
virtual const vectorField& Cf() const
|
||||||
{
|
{
|
||||||
return MeshStorage::Cf();
|
return Mesh::Cf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2018 OpenCFD Ltd.
|
Copyright (C) 2018-2020 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -93,20 +93,21 @@ Foam::sampledPatch::sampleOnPoints
|
|||||||
|
|
||||||
bitSet pointDone(points().size());
|
bitSet pointDone(points().size());
|
||||||
|
|
||||||
forAll(faces(), cutFacei)
|
forAll(faces(), i)
|
||||||
{
|
{
|
||||||
const label patchi = patchIDs_[patchIndex_[cutFacei]];
|
const face& f = faces()[i];
|
||||||
|
const label patchi = patchIDs_[patchIndex_[i]];
|
||||||
|
const label patchFacei = patchFaceLabels_[i];
|
||||||
|
|
||||||
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
const label patchFacei = patchFaceLabels()[cutFacei];
|
|
||||||
const face& f = faces()[cutFacei];
|
const label facei = patchFacei + pp.start();
|
||||||
|
const label celli = own[facei];
|
||||||
|
|
||||||
for (const label pointi : f)
|
for (const label pointi : f)
|
||||||
{
|
{
|
||||||
if (pointDone.set(pointi))
|
if (pointDone.set(pointi))
|
||||||
{
|
{
|
||||||
const label facei = patchFacei + pp.start();
|
|
||||||
const label celli = own[facei];
|
|
||||||
|
|
||||||
values[pointi] = interpolator.interpolate
|
values[pointi] = interpolator.interpolate
|
||||||
(
|
(
|
||||||
points()[pointi],
|
points()[pointi],
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2016-2019 OpenCFD Ltd.
|
Copyright (C) 2016-2020 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -132,14 +132,16 @@ protected:
|
|||||||
|
|
||||||
// Protected Member Functions
|
// Protected Member Functions
|
||||||
|
|
||||||
//- General loop for sampling elements to faces
|
//- General loop for sampling elements to faces.
|
||||||
|
// The defaultValue is used for invalid (negative) elements
|
||||||
template<class Type>
|
template<class Type>
|
||||||
static tmp<Field<Type>> sampleOnFaces
|
static tmp<Field<Type>> sampleOnFaces
|
||||||
(
|
(
|
||||||
const interpolation<Type>& sampler,
|
const interpolation<Type>& sampler,
|
||||||
const labelUList& elements,
|
const labelUList& elements,
|
||||||
const faceList& fcs,
|
const faceList& fcs,
|
||||||
const pointField& pts
|
const pointField& pts,
|
||||||
|
const Type& defaultValue = Type(Zero)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
\\/ M anipulation |
|
\\/ M anipulation |
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||||
Copyright (C) 2018-2019 OpenCFD Ltd.
|
Copyright (C) 2018-2020 OpenCFD Ltd.
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
License
|
License
|
||||||
This file is part of OpenFOAM.
|
This file is part of OpenFOAM.
|
||||||
@ -37,7 +37,8 @@ Foam::sampledSurface::sampleOnFaces
|
|||||||
const interpolation<Type>& sampler,
|
const interpolation<Type>& sampler,
|
||||||
const labelUList& elements,
|
const labelUList& elements,
|
||||||
const faceList& fcs,
|
const faceList& fcs,
|
||||||
const pointField& pts
|
const pointField& pts,
|
||||||
|
const Type& defaultValue
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const label len = elements.size();
|
const label len = elements.size();
|
||||||
@ -57,9 +58,16 @@ Foam::sampledSurface::sampleOnFaces
|
|||||||
for (label i=0; i < len; ++i)
|
for (label i=0; i < len; ++i)
|
||||||
{
|
{
|
||||||
const label celli = elements[i];
|
const label celli = elements[i];
|
||||||
const point pt = fcs[i].centre(pts);
|
if (celli < 0)
|
||||||
|
{
|
||||||
|
values[i] = defaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const point pt = fcs[i].centre(pts);
|
||||||
|
|
||||||
values[i] = sampler.interpolate(pt, celli);
|
values[i] = sampler.interpolate(pt, celli);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tvalues;
|
return tvalues;
|
||||||
|
|||||||
@ -63,6 +63,7 @@ writers = writers
|
|||||||
|
|
||||||
$(writers)/surfaceWriter.C
|
$(writers)/surfaceWriter.C
|
||||||
$(writers)/caching/surfaceWriterCaching.C
|
$(writers)/caching/surfaceWriterCaching.C
|
||||||
|
$(writers)/abaqus/abaqusSurfaceWriter.C
|
||||||
$(writers)/boundaryData/boundaryDataSurfaceWriter.C
|
$(writers)/boundaryData/boundaryDataSurfaceWriter.C
|
||||||
$(writers)/ensight/ensightSurfaceWriter.C
|
$(writers)/ensight/ensightSurfaceWriter.C
|
||||||
$(writers)/foam/foamSurfaceWriter.C
|
$(writers)/foam/foamSurfaceWriter.C
|
||||||
|
|||||||
@ -154,6 +154,7 @@ bool Foam::fileFormats::ABAQUSsurfaceFormat<Face>::read
|
|||||||
// No solids
|
// No solids
|
||||||
reader.purge_solids();
|
reader.purge_solids();
|
||||||
reader.compact_nodes();
|
reader.compact_nodes();
|
||||||
|
reader.renumber_elements_1to0(); // Convert 1-based -> 0-based
|
||||||
|
|
||||||
|
|
||||||
// Convert connectivity to faces
|
// Convert connectivity to faces
|
||||||
|
|||||||
355
src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C
Normal file
355
src/surfMesh/writers/abaqus/abaqusSurfaceWriter.C
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 "abaqusSurfaceWriter.H"
|
||||||
|
#include "ABAQUSCore.H"
|
||||||
|
#include "IOmanip.H"
|
||||||
|
#include "ListOps.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
#include "surfaceWriterMethods.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace surfaceWriters
|
||||||
|
{
|
||||||
|
defineTypeName(abaqusWriter);
|
||||||
|
addToRunTimeSelectionTable(surfaceWriter, abaqusWriter, word);
|
||||||
|
addToRunTimeSelectionTable(surfaceWriter, abaqusWriter, wordDict);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
// Field writing implementation
|
||||||
|
#include "abaqusSurfaceWriterImpl.C"
|
||||||
|
|
||||||
|
// Field writing methods
|
||||||
|
defineSurfaceWriterWriteFields(Foam::surfaceWriters::abaqusWriter);
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Write connectivity as CSV list
|
||||||
|
inline static void writeConnectivity
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const label elemId,
|
||||||
|
const labelUList& elem
|
||||||
|
)
|
||||||
|
{
|
||||||
|
os << " " << elemId;
|
||||||
|
|
||||||
|
for (const label vert : elem)
|
||||||
|
{
|
||||||
|
os << ", " << (vert + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
os << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::surfaceWriters::abaqusWriter::writeFace
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const labelUList& f,
|
||||||
|
const label elemId,
|
||||||
|
const label propId,
|
||||||
|
bool header
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// Only called with 3 or 4 points!
|
||||||
|
|
||||||
|
if (header)
|
||||||
|
{
|
||||||
|
os << "*ELEMENT, TYPE=S" << f.size();
|
||||||
|
|
||||||
|
if (propId >= 0)
|
||||||
|
{
|
||||||
|
os << ", ELSET=_" << propId;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeConnectivity(os, elemId, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::surfaceWriters::abaqusWriter::writeGeometry
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const meshedSurf& surf,
|
||||||
|
labelList& decompOffsets,
|
||||||
|
DynamicList<face>& decompFaces
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const pointField& points = surf.points();
|
||||||
|
const faceList& faces = surf.faces();
|
||||||
|
const labelList& zones = surf.zoneIds();
|
||||||
|
const labelList& elemIds = surf.faceIds();
|
||||||
|
|
||||||
|
// Possible to use faceIds?
|
||||||
|
bool useOrigFaceIds =
|
||||||
|
(
|
||||||
|
elemIds.size() == faces.size()
|
||||||
|
&& !ListOps::found(elemIds, lessOp1<label>(0))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (useOrigFaceIds)
|
||||||
|
{
|
||||||
|
// Not possible with on-the-fly face decomposition
|
||||||
|
for (const auto& f : faces)
|
||||||
|
{
|
||||||
|
if (f.size() > 4)
|
||||||
|
{
|
||||||
|
useOrigFaceIds = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
os << "** Geometry" << nl;
|
||||||
|
|
||||||
|
os << nl
|
||||||
|
<< "**" << nl
|
||||||
|
<< "** Points" << nl
|
||||||
|
<< "**" << nl;
|
||||||
|
|
||||||
|
fileFormats::ABAQUSCore::writePoints(os, points, geometryScale_);
|
||||||
|
|
||||||
|
|
||||||
|
// Write faces, with on-the-fly decomposition (triangulation)
|
||||||
|
decompOffsets.resize(faces.size()+1);
|
||||||
|
decompFaces.clear();
|
||||||
|
|
||||||
|
decompOffsets[0] = 0; // The first offset is always zero
|
||||||
|
|
||||||
|
os << "**" << nl
|
||||||
|
<< "** Faces" << nl
|
||||||
|
<< "**" << nl;
|
||||||
|
|
||||||
|
// Simple tracking for change of element type/set
|
||||||
|
labelPair prevOutput(-1, -1);
|
||||||
|
|
||||||
|
label elemId = 0; // The element-id
|
||||||
|
forAll(faces, facei)
|
||||||
|
{
|
||||||
|
const face& f = faces[facei];
|
||||||
|
|
||||||
|
if (useOrigFaceIds)
|
||||||
|
{
|
||||||
|
// When available and not decomposed
|
||||||
|
elemId = elemIds[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1-offset for PID
|
||||||
|
const label propId = 1 + (facei < zones.size() ? zones[facei] : 0);
|
||||||
|
|
||||||
|
const label n = f.size();
|
||||||
|
|
||||||
|
bool header =
|
||||||
|
(prevOutput.first() != n || prevOutput.second() != propId);
|
||||||
|
|
||||||
|
if (header)
|
||||||
|
{
|
||||||
|
// Update values
|
||||||
|
prevOutput.first() = n;
|
||||||
|
prevOutput.second() = propId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 3 || n == 4)
|
||||||
|
{
|
||||||
|
writeFace(os, f, ++elemId, propId, header);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Decompose into tris
|
||||||
|
prevOutput.first() = 3;
|
||||||
|
|
||||||
|
f.triangles(points, decompFaces);
|
||||||
|
|
||||||
|
for
|
||||||
|
(
|
||||||
|
label decompi = decompOffsets[facei];
|
||||||
|
decompi < decompFaces.size();
|
||||||
|
++decompi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
writeFace
|
||||||
|
(
|
||||||
|
os,
|
||||||
|
decompFaces[decompi],
|
||||||
|
++elemId,
|
||||||
|
propId,
|
||||||
|
header
|
||||||
|
);
|
||||||
|
|
||||||
|
header = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The end offset, which is the next begin offset
|
||||||
|
decompOffsets[facei+1] = decompFaces.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
os << "**" << nl
|
||||||
|
<< "**" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::surfaceWriters::abaqusWriter::abaqusWriter()
|
||||||
|
:
|
||||||
|
surfaceWriter(),
|
||||||
|
geometryScale_(1),
|
||||||
|
fieldScale_(),
|
||||||
|
noGeometry_(false),
|
||||||
|
outputLayout_(outputLayoutType::BY_FIELD)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::surfaceWriters::abaqusWriter::abaqusWriter
|
||||||
|
(
|
||||||
|
const dictionary& options
|
||||||
|
)
|
||||||
|
:
|
||||||
|
surfaceWriter(options),
|
||||||
|
geometryScale_(options.getOrDefault<scalar>("scale", 1)),
|
||||||
|
fieldScale_(options.subOrEmptyDict("fieldScale")),
|
||||||
|
noGeometry_(options.getOrDefault("noGeometry", false)),
|
||||||
|
outputLayout_(outputLayoutType::BY_FIELD)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::surfaceWriters::abaqusWriter::abaqusWriter
|
||||||
|
(
|
||||||
|
const meshedSurf& surf,
|
||||||
|
const fileName& outputPath,
|
||||||
|
bool parallel,
|
||||||
|
const dictionary& options
|
||||||
|
)
|
||||||
|
:
|
||||||
|
abaqusWriter(options)
|
||||||
|
{
|
||||||
|
open(surf, outputPath, parallel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::surfaceWriters::abaqusWriter::abaqusWriter
|
||||||
|
(
|
||||||
|
const pointField& points,
|
||||||
|
const faceList& faces,
|
||||||
|
const fileName& outputPath,
|
||||||
|
bool parallel,
|
||||||
|
const dictionary& options
|
||||||
|
)
|
||||||
|
:
|
||||||
|
abaqusWriter(options)
|
||||||
|
{
|
||||||
|
open(points, faces, outputPath, parallel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::fileName Foam::surfaceWriters::abaqusWriter::write()
|
||||||
|
{
|
||||||
|
checkOpen();
|
||||||
|
|
||||||
|
// Geometry:
|
||||||
|
// 1) rootdir/<TIME>/surfaceName.abq
|
||||||
|
// 2) rootdir/geometry/surfaceName_<TIME>.abq
|
||||||
|
|
||||||
|
fileName outputFile;
|
||||||
|
|
||||||
|
switch (outputLayout_)
|
||||||
|
{
|
||||||
|
case outputLayoutType::BY_TIME:
|
||||||
|
{
|
||||||
|
outputFile = outputPath_;
|
||||||
|
if (useTimeDir() && !timeName().empty())
|
||||||
|
{
|
||||||
|
// Splice in time-directory
|
||||||
|
outputFile =
|
||||||
|
outputPath_.path() / timeName() / outputPath_.name();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case outputLayoutType::BY_FIELD:
|
||||||
|
{
|
||||||
|
outputFile = outputPath_ / "geometry" / outputPath_.name();
|
||||||
|
if (!timeName().empty())
|
||||||
|
{
|
||||||
|
// Append time information to file name
|
||||||
|
outputFile += '_' + timeName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputFile.ext("abq");
|
||||||
|
|
||||||
|
if (verbose_)
|
||||||
|
{
|
||||||
|
Info<< "Writing abaqus geometry to " << outputFile << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const meshedSurf& surf = surface();
|
||||||
|
|
||||||
|
if (Pstream::master() || !parallel_)
|
||||||
|
{
|
||||||
|
if (!isDir(outputFile.path()))
|
||||||
|
{
|
||||||
|
mkDir(outputFile.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
OFstream os(outputFile);
|
||||||
|
|
||||||
|
labelList decompOffsets;
|
||||||
|
DynamicList<face> decompFaces;
|
||||||
|
|
||||||
|
writeGeometry(os, surf, decompOffsets, decompFaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
wroteGeom_ = true;
|
||||||
|
return outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
239
src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H
Normal file
239
src/surfMesh/writers/abaqus/abaqusSurfaceWriter.H
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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::surfaceWriters::abaqusWriter
|
||||||
|
|
||||||
|
Description
|
||||||
|
A surface writer for the ABAQUS file format - both surface mesh and fields
|
||||||
|
|
||||||
|
The formatOptions for abaqus:
|
||||||
|
\table
|
||||||
|
Property | Description | Required | Default
|
||||||
|
scale | output geometry scaling | no | 1
|
||||||
|
fieldScale | output field scaling (dictionary) | no | empty
|
||||||
|
noGeometry | Suppress geometry output (beta feature) | no | false
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
For example,
|
||||||
|
\verbatim
|
||||||
|
formatOptions
|
||||||
|
{
|
||||||
|
abaqus
|
||||||
|
{
|
||||||
|
scale 1000; // [m] -> [mm]
|
||||||
|
fieldScale
|
||||||
|
{
|
||||||
|
"p.*" 0.01; // [Pa] -> [mbar]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
\heading Output file locations
|
||||||
|
|
||||||
|
The \c rootdir normally corresponds to something like
|
||||||
|
\c postProcessing/\<name\>
|
||||||
|
|
||||||
|
\subheading Geometry
|
||||||
|
\verbatim
|
||||||
|
rootdir
|
||||||
|
`-- surfaceName0
|
||||||
|
`-- geometry
|
||||||
|
`-- surfaceName0_<time>.abq
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
\subheading Fields
|
||||||
|
\verbatim
|
||||||
|
rootdir
|
||||||
|
`-- surfaceName0
|
||||||
|
`-- field0
|
||||||
|
| `-- surfaceName0_<time>.{inp}
|
||||||
|
`-- field1
|
||||||
|
`-- surfaceName0_<time>.{inp}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Note
|
||||||
|
Output variable scaling does not apply to integer types such as Ids.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
abaqusSurfaceWriter.C
|
||||||
|
abaqusSurfaceWriterImpl.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef abaqusSurfaceWriter_H
|
||||||
|
#define abaqusSurfaceWriter_H
|
||||||
|
|
||||||
|
#include "surfaceWriter.H"
|
||||||
|
#include "ABAQUSCore.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace surfaceWriters
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class abaqusWriter Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class abaqusWriter
|
||||||
|
:
|
||||||
|
public surfaceWriter
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Output geometry scaling
|
||||||
|
const scalar geometryScale_;
|
||||||
|
|
||||||
|
//- Output field scaling
|
||||||
|
const dictionary fieldScale_;
|
||||||
|
|
||||||
|
//- BETA feature
|
||||||
|
bool noGeometry_;
|
||||||
|
|
||||||
|
//- Output directory layouts
|
||||||
|
enum class outputLayoutType
|
||||||
|
{
|
||||||
|
BY_TIME = 0,
|
||||||
|
BY_FIELD,
|
||||||
|
};
|
||||||
|
|
||||||
|
//- Output directory layout
|
||||||
|
outputLayoutType outputLayout_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Write face element (tri/quad)
|
||||||
|
void writeFace
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const labelUList& f,
|
||||||
|
const label elemId, //!< 1-based Element Id
|
||||||
|
const label propId, //!< 1-based Property Id
|
||||||
|
const bool header = true
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Write the surface mesh geometry, tracking face decomposition
|
||||||
|
//
|
||||||
|
// \param decompOffsets begin/end offsets (size+1) into decompFaces
|
||||||
|
// \param decompFaces Non tri/quad decomposed into triangles
|
||||||
|
void writeGeometry
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const meshedSurf& surf,
|
||||||
|
labelList& decompOffsets,
|
||||||
|
DynamicList<face>& decompFaces
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Write a face-based value
|
||||||
|
template<class Type>
|
||||||
|
Ostream& writeFaceValue
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const Type& value,
|
||||||
|
const label elemId //!< 0-based Element Id
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Templated write operation
|
||||||
|
template<class Type>
|
||||||
|
fileName writeTemplate
|
||||||
|
(
|
||||||
|
const word& fieldName, //!< Name of field
|
||||||
|
const Field<Type>& localValues //!< Local field values to write
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Declare type-name, virtual type (with debug switch)
|
||||||
|
TypeNameNoDebug("abaqus");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Default construct
|
||||||
|
abaqusWriter();
|
||||||
|
|
||||||
|
//- Construct with some output options
|
||||||
|
explicit abaqusWriter(const dictionary& options);
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
abaqusWriter
|
||||||
|
(
|
||||||
|
const meshedSurf& surf,
|
||||||
|
const fileName& outputPath,
|
||||||
|
bool parallel = Pstream::parRun(),
|
||||||
|
const dictionary& options = dictionary()
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
abaqusWriter
|
||||||
|
(
|
||||||
|
const pointField& points,
|
||||||
|
const faceList& faces,
|
||||||
|
const fileName& outputPath,
|
||||||
|
bool parallel = Pstream::parRun(),
|
||||||
|
const dictionary& options = dictionary()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~abaqusWriter() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Format uses faceIds as part of its output
|
||||||
|
virtual bool usesFaceIds() const // override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Write surface geometry to file.
|
||||||
|
virtual fileName write(); // override
|
||||||
|
|
||||||
|
declareSurfaceWriterWriteMethod(label);
|
||||||
|
declareSurfaceWriterWriteMethod(scalar);
|
||||||
|
declareSurfaceWriterWriteMethod(vector);
|
||||||
|
declareSurfaceWriterWriteMethod(sphericalTensor);
|
||||||
|
declareSurfaceWriterWriteMethod(symmTensor);
|
||||||
|
declareSurfaceWriterWriteMethod(tensor);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace surfaceWriters
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
308
src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C
Normal file
308
src/surfMesh/writers/abaqus/abaqusSurfaceWriterImpl.C
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2020 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 "OFstream.H"
|
||||||
|
#include "IOmanip.H"
|
||||||
|
#include "OSspecific.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::Ostream& Foam::surfaceWriters::abaqusWriter::writeFaceValue
|
||||||
|
(
|
||||||
|
Ostream& os,
|
||||||
|
const Type& value,
|
||||||
|
const label elemId
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (fileFormats::ABAQUSCore::isEncodedSolidId(elemId))
|
||||||
|
{
|
||||||
|
const label solidId =
|
||||||
|
fileFormats::ABAQUSCore::decodeSolidElementId(elemId);
|
||||||
|
|
||||||
|
const label sideNum =
|
||||||
|
fileFormats::ABAQUSCore::decodeSolidSideNum(elemId);
|
||||||
|
|
||||||
|
// Element-id: 0-based to 1-based
|
||||||
|
// Side-id: always 1-based
|
||||||
|
os << (solidId + 1) << ", P" << sideNum;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Element-id: 0-based to 1-based
|
||||||
|
os << (elemId + 1) << ", P";
|
||||||
|
}
|
||||||
|
|
||||||
|
os << ", ";
|
||||||
|
if (pTraits<Type>::nComponents == 1)
|
||||||
|
{
|
||||||
|
os << value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
os << mag(value);
|
||||||
|
}
|
||||||
|
os << nl;
|
||||||
|
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::fileName Foam::surfaceWriters::abaqusWriter::writeTemplate
|
||||||
|
(
|
||||||
|
const word& fieldName,
|
||||||
|
const Field<Type>& localValues
|
||||||
|
)
|
||||||
|
{
|
||||||
|
checkOpen();
|
||||||
|
|
||||||
|
// Field:
|
||||||
|
// 1) rootdir/<TIME>/<field>_surfaceName.inp
|
||||||
|
// 2) rootdir/<field>/surfaceName_<TIME>.inp
|
||||||
|
|
||||||
|
fileName outputFile;
|
||||||
|
|
||||||
|
switch (outputLayout_)
|
||||||
|
{
|
||||||
|
case outputLayoutType::BY_TIME:
|
||||||
|
{
|
||||||
|
outputFile = outputPath_;
|
||||||
|
if (useTimeDir() && !timeName().empty())
|
||||||
|
{
|
||||||
|
// Splice in time-directory
|
||||||
|
outputFile =
|
||||||
|
outputPath_.path() / timeName() / outputPath_.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append <field>_surfaceName
|
||||||
|
outputFile /= fieldName + '_' + outputPath_.name();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case outputLayoutType::BY_FIELD:
|
||||||
|
{
|
||||||
|
outputFile = outputPath_ / fieldName / outputPath_.name();
|
||||||
|
if (!timeName().empty())
|
||||||
|
{
|
||||||
|
// Append time information to file name
|
||||||
|
outputFile += '_' + timeName();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputFile.ext("inp");
|
||||||
|
|
||||||
|
|
||||||
|
// Output scaling for the variable, but not for integer types.
|
||||||
|
// could also solve with clever templating
|
||||||
|
|
||||||
|
const scalar varScale =
|
||||||
|
(
|
||||||
|
std::is_integral<Type>::value
|
||||||
|
? scalar(1)
|
||||||
|
: fieldScale_.getOrDefault<scalar>(fieldName, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (verbose_)
|
||||||
|
{
|
||||||
|
Info<< "Writing field " << fieldName;
|
||||||
|
if (!equal(varScale, 1))
|
||||||
|
{
|
||||||
|
Info<< " (scaling " << varScale << ')';
|
||||||
|
}
|
||||||
|
Info<< " to " << outputFile << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Implicit geometry merge()
|
||||||
|
tmp<Field<Type>> tfield = mergeField(localValues) * varScale;
|
||||||
|
|
||||||
|
const meshedSurf& surf = surface();
|
||||||
|
|
||||||
|
if (Pstream::master() || !parallel_)
|
||||||
|
{
|
||||||
|
const auto& values = tfield();
|
||||||
|
|
||||||
|
if (!isDir(outputFile.path()))
|
||||||
|
{
|
||||||
|
mkDir(outputFile.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
// const scalar timeValue(0);
|
||||||
|
|
||||||
|
|
||||||
|
// Additional bookkeeping for decomposing non tri/quad
|
||||||
|
labelList decompOffsets;
|
||||||
|
DynamicList<face> decompFaces;
|
||||||
|
|
||||||
|
|
||||||
|
OFstream os(outputFile);
|
||||||
|
|
||||||
|
if (noGeometry_ || wroteGeom_)
|
||||||
|
{
|
||||||
|
// Geometry already written (or suppressed)
|
||||||
|
// - still need decomposition information
|
||||||
|
|
||||||
|
fileFormats::ABAQUSCore::faceDecomposition
|
||||||
|
(
|
||||||
|
surf.points(),
|
||||||
|
surf.faces(),
|
||||||
|
decompOffsets,
|
||||||
|
decompFaces
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write geometry (separate file)
|
||||||
|
|
||||||
|
OFstream osGeom(outputFile.lessExt().ext("abq"));
|
||||||
|
writeGeometry(osGeom, surf, decompOffsets, decompFaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write field
|
||||||
|
// *DLOAD
|
||||||
|
// Element-based: // elemId, P, 1000
|
||||||
|
// Surface-based: // elemId, P4, 1000
|
||||||
|
|
||||||
|
os << "**" << nl
|
||||||
|
<< "** field = " << fieldName << nl
|
||||||
|
<< "** type = " << pTraits<Type>::typeName << nl;
|
||||||
|
|
||||||
|
if (useTimeDir() && !timeName().empty())
|
||||||
|
{
|
||||||
|
os << "** time = " << timeName() << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
os << "**" << nl
|
||||||
|
<< "*DLOAD" << nl;
|
||||||
|
|
||||||
|
|
||||||
|
// Regular (undecomposed) faces
|
||||||
|
const faceList& faces = surf.faces();
|
||||||
|
const labelList& elemIds = surf.faceIds();
|
||||||
|
|
||||||
|
// Possible to use faceIds?
|
||||||
|
const bool useOrigFaceIds =
|
||||||
|
(
|
||||||
|
elemIds.size() == faces.size()
|
||||||
|
&& decompFaces.empty()
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
label elemId = 0;
|
||||||
|
|
||||||
|
if (this->isPointData())
|
||||||
|
{
|
||||||
|
forAll(faces, facei)
|
||||||
|
{
|
||||||
|
if (useOrigFaceIds)
|
||||||
|
{
|
||||||
|
// When available and not decomposed
|
||||||
|
elemId = elemIds[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
const label beginElemId = elemId;
|
||||||
|
|
||||||
|
// Any face decomposition
|
||||||
|
for
|
||||||
|
(
|
||||||
|
label decompi = decompOffsets[facei];
|
||||||
|
decompi < decompOffsets[facei+1];
|
||||||
|
++decompi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const face& f = decompFaces[decompi];
|
||||||
|
|
||||||
|
Type v = Zero;
|
||||||
|
for (const label verti : f)
|
||||||
|
{
|
||||||
|
v += values[verti];
|
||||||
|
}
|
||||||
|
v /= f.size();
|
||||||
|
|
||||||
|
writeFaceValue(os, v, elemId); // 0-based
|
||||||
|
++elemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Face not decomposed
|
||||||
|
if (beginElemId == elemId)
|
||||||
|
{
|
||||||
|
const face& f = faces[facei];
|
||||||
|
|
||||||
|
Type v = Zero;
|
||||||
|
for (const label verti : f)
|
||||||
|
{
|
||||||
|
v += values[verti];
|
||||||
|
}
|
||||||
|
v /= f.size();
|
||||||
|
|
||||||
|
writeFaceValue(os, v, elemId); // 0-based
|
||||||
|
++elemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto valIter = values.cbegin();
|
||||||
|
|
||||||
|
forAll(faces, facei)
|
||||||
|
{
|
||||||
|
if (useOrigFaceIds)
|
||||||
|
{
|
||||||
|
// When available and not decomposed
|
||||||
|
elemId = elemIds[facei];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type v(*valIter);
|
||||||
|
++valIter;
|
||||||
|
|
||||||
|
label nValues =
|
||||||
|
max
|
||||||
|
(
|
||||||
|
label(1),
|
||||||
|
(decompOffsets[facei+1] - decompOffsets[facei])
|
||||||
|
);
|
||||||
|
|
||||||
|
while (nValues--)
|
||||||
|
{
|
||||||
|
writeFaceValue(os, v, elemId); // 0-based
|
||||||
|
++elemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
os << "**" << nl
|
||||||
|
<< "**" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
wroteGeom_ = true;
|
||||||
|
return outputFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -121,6 +121,44 @@ sampled
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sample and write for meshed surfaces
|
||||||
|
sampleMesh
|
||||||
|
{
|
||||||
|
type surfaces;
|
||||||
|
libs (sampling);
|
||||||
|
log true;
|
||||||
|
|
||||||
|
writeControl writeTime;
|
||||||
|
writeInterval 1;
|
||||||
|
|
||||||
|
surfaceFormat vtk;
|
||||||
|
|
||||||
|
fields (p rho U T);
|
||||||
|
|
||||||
|
surfaces
|
||||||
|
{
|
||||||
|
// Oversized sampling - for general testing
|
||||||
|
meshed_sample
|
||||||
|
{
|
||||||
|
type meshedSurface;
|
||||||
|
surface oversized_sample.obj;
|
||||||
|
source cells;
|
||||||
|
maxDistance 0.0025;
|
||||||
|
defaultValue
|
||||||
|
{
|
||||||
|
T 273;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meshed_interpolate
|
||||||
|
{
|
||||||
|
$meshed_sample;
|
||||||
|
interpolate true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// * * * * * * * * * * * * * * * Calculations * * * * * * * * * * * * * * * //
|
// * * * * * * * * * * * * * * * Calculations * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
massflow
|
massflow
|
||||||
@ -144,6 +182,7 @@ areaAverage
|
|||||||
|
|
||||||
operation weightedAreaAverage;
|
operation weightedAreaAverage;
|
||||||
weightField rhoU;
|
weightField rhoU;
|
||||||
|
weightFields ( rho U none ); // 2012 and later
|
||||||
fields ( p pTotal );
|
fields ( p pTotal );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +195,7 @@ areaIntegrate
|
|||||||
|
|
||||||
operation weightedAreaIntegrate;
|
operation weightedAreaIntegrate;
|
||||||
weightField rhoU;
|
weightField rhoU;
|
||||||
|
weightFields ( rho U ); // 2012 and later
|
||||||
fields ( T );
|
fields ( T );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,8 +16,9 @@ runApplication subsetMesh c0 -patch walls -overwrite
|
|||||||
runApplication splitMeshRegions -cellZones -overwrite
|
runApplication splitMeshRegions -cellZones -overwrite
|
||||||
|
|
||||||
# create register face and cell zones
|
# create register face and cell zones
|
||||||
rm log.topoSet
|
rm -f log.topoSet.register
|
||||||
runApplication topoSet -region cabin -dict system/topoSetDictRegister
|
runApplication -s register \
|
||||||
|
topoSet -region cabin -dict system/topoSetDictRegister
|
||||||
|
|
||||||
# set the initial fields
|
# set the initial fields
|
||||||
restore0Dir
|
restore0Dir
|
||||||
|
|||||||
@ -16,8 +16,9 @@ runApplication subsetMesh c0 -patch walls -overwrite
|
|||||||
runApplication splitMeshRegions -cellZones -overwrite
|
runApplication splitMeshRegions -cellZones -overwrite
|
||||||
|
|
||||||
# create register face and cell zones
|
# create register face and cell zones
|
||||||
rm log.topoSet
|
rm -f log.topoSet.register
|
||||||
runApplication topoSet -region cabin -dict system/topoSetDictRegister
|
runApplication -o -s register \
|
||||||
|
topoSet -region cabin -dict system/topoSetDictRegister
|
||||||
|
|
||||||
# set the initial fields
|
# set the initial fields
|
||||||
restore0Dir
|
restore0Dir
|
||||||
|
|||||||
@ -83,6 +83,27 @@ functions
|
|||||||
( 60 "<system>/solverControls.60")
|
( 60 "<system>/solverControls.60")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify values for sampling multiple faceZones
|
||||||
|
inletFaces
|
||||||
|
{
|
||||||
|
type surfaces;
|
||||||
|
libs (sampling);
|
||||||
|
writeControl onEnd;
|
||||||
|
region cabin;
|
||||||
|
surfaceFormat vtk;
|
||||||
|
fields (H2O U);
|
||||||
|
|
||||||
|
surfaces
|
||||||
|
{
|
||||||
|
inletFaces
|
||||||
|
{
|
||||||
|
type faceZone;
|
||||||
|
zones (inletFaces f1Zone);
|
||||||
|
interpolate false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -44,6 +44,28 @@ actions
|
|||||||
type cellSet;
|
type cellSet;
|
||||||
action invert;
|
action invert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
name f0tmp;
|
||||||
|
type faceSet;
|
||||||
|
action new;
|
||||||
|
source patchToFace;
|
||||||
|
patch inlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
name inletFaces;
|
||||||
|
type faceZoneSet;
|
||||||
|
action new;
|
||||||
|
source setToFaceZone;
|
||||||
|
faceSet f0tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
name f0tmp;
|
||||||
|
type faceSet;
|
||||||
|
action remove;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -3,15 +3,12 @@ cd "${0%/*}" || exit # Run from this directory
|
|||||||
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
|
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
# create mesh
|
|
||||||
runApplication blockMesh
|
|
||||||
|
|
||||||
restore0Dir
|
restore0Dir
|
||||||
|
|
||||||
# initialise with potentialFoam solution
|
runApplication blockMesh
|
||||||
|
|
||||||
runApplication potentialFoam
|
runApplication potentialFoam
|
||||||
|
|
||||||
# run the solver
|
|
||||||
runApplication $(getApplication)
|
runApplication $(getApplication)
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
|
|||||||
16
tutorials/lagrangian/reactingParcelFoam/verticalChannel/Allrun-parallel
Executable file
16
tutorials/lagrangian/reactingParcelFoam/verticalChannel/Allrun-parallel
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd "${0%/*}" || exit # Run from this directory
|
||||||
|
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
restore0Dir
|
||||||
|
|
||||||
|
runApplication blockMesh
|
||||||
|
|
||||||
|
runApplication potentialFoam
|
||||||
|
|
||||||
|
runApplication decomposePar
|
||||||
|
|
||||||
|
runParallel $(getApplication)
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
@ -53,7 +53,27 @@ maxDeltaT 1e-03;
|
|||||||
|
|
||||||
functions
|
functions
|
||||||
{
|
{
|
||||||
surfaceFieldValue1
|
avgInlets
|
||||||
|
{
|
||||||
|
type surfaceFieldValue;
|
||||||
|
libs (fieldFunctionObjects);
|
||||||
|
enabled yes;
|
||||||
|
writeControl writeTime;
|
||||||
|
log yes;
|
||||||
|
writeFields off;
|
||||||
|
surfaceFormat vtk;
|
||||||
|
regionType patch;
|
||||||
|
// name inlet;
|
||||||
|
names (inlet "inlet.*");
|
||||||
|
operation weightedAverage;
|
||||||
|
weightField phi;
|
||||||
|
fields
|
||||||
|
(
|
||||||
|
T
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
avgOutlets
|
||||||
{
|
{
|
||||||
type surfaceFieldValue;
|
type surfaceFieldValue;
|
||||||
libs (fieldFunctionObjects);
|
libs (fieldFunctionObjects);
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*--------------------------------*- C++ -*----------------------------------*\
|
||||||
|
| ========= | |
|
||||||
|
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||||
|
| \\ / O peration | Version: v2006 |
|
||||||
|
| \\ / A nd | Website: www.openfoam.com |
|
||||||
|
| \\/ M anipulation | |
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
FoamFile
|
||||||
|
{
|
||||||
|
version 2.0;
|
||||||
|
format ascii;
|
||||||
|
class dictionary;
|
||||||
|
object decomposeParDict;
|
||||||
|
}
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
numberOfSubdomains 4;
|
||||||
|
|
||||||
|
method scotch;
|
||||||
|
|
||||||
|
coeffs
|
||||||
|
{
|
||||||
|
n (2 2 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
distributed no;
|
||||||
|
|
||||||
|
roots ( );
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -48,7 +48,7 @@ runTimeModifiable yes;
|
|||||||
|
|
||||||
functions
|
functions
|
||||||
{
|
{
|
||||||
surfaceFieldValue1
|
avgOutlets
|
||||||
{
|
{
|
||||||
type surfaceFieldValue;
|
type surfaceFieldValue;
|
||||||
libs (fieldFunctionObjects);
|
libs (fieldFunctionObjects);
|
||||||
|
|||||||
Reference in New Issue
Block a user