/*--------------------------------*- C++ -*----------------------------------*\
========= |
\\ / F ield | foam-extend: Open Source CFD
\\ / O peration |
\\ / A nd | For copyright notice see file Copyright
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of foam-extend.
foam-extend 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.
foam-extend 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 foam-extend. If not, see .
Application
fluentMeshToFoam
Description
Converts a Fluent mesh to FOAM format
including multiple region and region boundary handling.
\*---------------------------------------------------------------------------*/
%{
#undef yyFlexLexer
/* ------------------------------------------------------------------------- *\
------ local definitions
\* ------------------------------------------------------------------------- */
#include "argList.H"
#include "objectRegistry.H"
#include "Time.H"
#include "IStringStream.H"
#include "polyMesh.H"
#include "emptyPolyPatch.H"
#include "wallPolyPatch.H"
#include "symmetryPolyPatch.H"
#include "preservePatchTypes.H"
#include "cellShape.H"
#include "faceSet.H"
#include "cellSet.H"
#include "meshTools.H"
#include "OFstream.H"
#include "wordIOList.H"
#include "readHexLabel.H"
#include "cellShapeRecognition.H"
#include "repatchPolyTopoChanger.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
using namespace Foam;
const scalar convertToMeters = 1.0;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
label dimensionOfGrid = 0;
label nPoints = 0;
label nFaces = 0;
label nCells = 0;
pointField points(0);
SLList pointGroupZoneID;
SLList pointGroupStartIndex;
SLList pointGroupEndIndex;
faceList faces(0);
labelList owner(0);
labelList neighbour(0);
SLList faceGroupZoneID;
SLList faceGroupStartIndex;
SLList faceGroupEndIndex;
labelList fluentCellModelID(0);
SLList cellGroupZoneID;
SLList cellGroupStartIndex;
SLList cellGroupEndIndex;
SLList cellGroupType;
// number of zones adjusted at run-time if necessary
label maxZoneID = 100;
label zoneIDBuffer = 10;
wordList patchTypeIDs(maxZoneID);
wordList patchNameIDs(maxZoneID);
// Dummy yywrap to keep yylex happy at compile time.
// It is called by yylex but is not used as the mechanism to change file.
// See <>
#if YY_FLEX_SUBMINOR_VERSION < 34
extern "C" int yywrap()
#else
int yyFlexLexer::yywrap()
#endif
{
return 1;
}
%}
one_space [ \t\f]
space {one_space}*
some_space {one_space}+
cspace ","{space}
spaceNl ({space}|\n|\r)*
alpha [_[:alpha:]]
digit [[:digit:]]
decDigit [[:digit:]]
octalDigit [0-7]
hexDigit [[:xdigit:]]
lbrac "("
rbrac ")"
quote \"
dash "-"
dotColonDash [.:-]
schemeSpecialInitial [!$%&*/\\:<=>?~_^#.@']
schemeSpecialSubsequent [.+-]
schemeSymbol (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
identifier {alpha}({alpha}|{digit})*
integer {decDigit}+
label [1-9]{decDigit}*
hexLabel {hexDigit}+
zeroLabel {digit}*
signedInteger [-+]?{integer}
word ({alpha}|{digit}|{dotColonDash})*
exponent_part [eE][-+]?{digit}+
fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
double ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
x {double}
y {double}
z {double}
scalar {double}
labelListElement {space}{zeroLabel}
hexLabelListElement {space}{hexLabel}
scalarListElement {space}{double}
schemeSymbolListElement {space}{schemeSymbol}
labelList ({labelListElement}+{space})
hexLabelList ({hexLabelListElement}+{space})
scalarList ({scalarListElement}+{space})
schemeSymbolList ({schemeSymbolListElement}+{space})
starStar ("**")
text ({space}({word}*{space})*)
dateDDMMYYYY ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
dateDDMonYYYY ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
time ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
versionNumber ({digit}|".")*
comment {spaceNl}"(0"{space}
header {spaceNl}"(1"{space}
dimension {spaceNl}"(2"{space}
point {spaceNl}"(10"{space}
fluentFace {spaceNl}"(13"{space}
cell {spaceNl}"(12"{space}
zoneVariant1 {spaceNl}"(39"{space}
zoneVariant2 {spaceNl}"(45"{space}
unknownPeriodicFace {spaceNl}"(17"{space}
periodicFace {spaceNl}"(18"{space}
cellTree {spaceNl}"(58"{space}
faceTree {spaceNl}"(59"{space}
faceParents {spaceNl}"(61"{space}
endOfSection {space}")"{space}
/* ------------------------------------------------------------------------- *\
----- Exclusive start states -----
\* ------------------------------------------------------------------------- */
%option stack
%x readComment
%x embeddedCommentState
%x readHeader
%x readDimension
%x readPoint
%x readPointHeader
%x readNumberOfPoints
%x readPointGroupData
%x readPointData
%x readPoints2D
%x readPoints3D
%x fluentFace
%x readFaceHeader
%x readNumberOfFaces
%x readFaceGroupData
%x readFaceData
%x readFacesMixed
%x readFacesUniform
%x cell
%x readCellHeader
%x readNumberOfCells
%x readCellGroupData
%x readCellData
%x readCellsMixed
%x readCellsUniform
%x zone
%x readZoneHeader
%x readZoneGroupData
%x readZoneData
%x readZoneBlock
%x periodicFace
%x cellTree
%x faceTree
%x faceParents
%x unknownBlock
%x embeddedUnknownBlock
%%
%{
// Point data
label pointGroupNumberOfComponents = 3;
label pointI = 0; // index used for reading points
// Face data
label faceGroupElementType = -1;
label faceI = 0;
// Cell data
label cellGroupElementType = -1;
label celli = 0;
%}
/* ------------------------------------------------------------------------ *\
------ Start Lexing ------
\* ------------------------------------------------------------------------ */
/* ------ Reading control header ------ */
{comment} {
yy_push_state(readComment);
}
{quote}{text}{quote} {
}
{spaceNl}{endOfSection} {
yy_pop_state();
}
{header} {
BEGIN(readHeader);
}
{quote}{text}{quote} {
Info<< "Reading header: " << YYText() << endl;
}
{dimension} {
BEGIN(readDimension);
}
{space}{label}{space} {
IStringStream dimOfGridStream(YYText());
dimensionOfGrid = readLabel(dimOfGridStream);
Info<< "Dimension of grid: " << dimensionOfGrid << endl;
}
{point} {
BEGIN(readPointHeader);
}
{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
BEGIN(readNumberOfPoints);
}
{space}{hexLabel}{space}{labelList} {
IStringStream numberOfPointsStream(YYText());
nPoints = readHexLabel(numberOfPointsStream);
Info<< "Number of points: " << nPoints << endl;
// set the size of the points list
points.setSize(nPoints);
// meaningless type skipped
readLabel(numberOfPointsStream);
// this dimension of grid may be checked against global dimension
if (numberOfPointsStream)
{
// check dimension of grid
readLabel(numberOfPointsStream);
}
else
{
Info<< endl;
}
}
{spaceNl}{lbrac} {
BEGIN(readPointGroupData);
}
{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
IStringStream pointGroupDataStream(YYText());
// read point zone-ID, start and end-label
// the indices will be used for checking later.
pointGroupZoneID.append(readHexLabel(pointGroupDataStream));
pointGroupStartIndex.append(readHexLabel(pointGroupDataStream));
pointGroupEndIndex.append(readHexLabel(pointGroupDataStream));
// point group type skipped
readHexLabel(pointGroupDataStream);
// In FOAM, indices start from zero - adjust
pointI = pointGroupStartIndex.last() - 1;
// reset number of components to default
pointGroupNumberOfComponents = 3;
// read number of components in the vector
if (pointGroupDataStream)
{
pointGroupNumberOfComponents = readLabel(pointGroupDataStream);
}
}
{endOfSection} {
BEGIN(readPointData);
}
{spaceNl}{lbrac} {
Info<< "Reading points" << endl;
if (pointGroupNumberOfComponents == 2)
{
yy_push_state(readPoints2D);
}
else
{
yy_push_state(readPoints3D);
}
}
{spaceNl}{scalarList} {
IStringStream vertexXyzStream(YYText());
// Note: coordinates must be read one at the time.
scalar x = readScalar(vertexXyzStream);
scalar y = readScalar(vertexXyzStream);
points[pointI] = point(x, y, 0);
pointI++;
}
{spaceNl}{scalarList} {
IStringStream vertexXyzStream(YYText());
// Note: coordinates must be read one at the time.
scalar x = readScalar(vertexXyzStream);
scalar y = readScalar(vertexXyzStream);
scalar z = readScalar(vertexXyzStream);
points[pointI] = convertToMeters*point(x, y, z);
pointI++;
}
{spaceNl}{endOfSection} {
// check read of points
if (pointI != pointGroupEndIndex.last())
{
Info<< "problem with reading points: "
<< "start index: " << pointGroupStartIndex.last()
<< " end index: " << pointGroupEndIndex.last()
<< " last points read: " << pointI << endl;
}
yy_pop_state();
}
{fluentFace} {
BEGIN(readFaceHeader);
}
{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
BEGIN(readNumberOfFaces);
}
{space}{hexLabel}{space}{labelListElement}+ {
IStringStream numberOfFacesStream(YYText());
nFaces = readHexLabel(numberOfFacesStream);
Info<< "number of faces: " << nFaces << endl;
faces.setSize(nFaces);
owner.setSize(nFaces);
neighbour.setSize(nFaces);
// Meaningless type and element type not read
}
{spaceNl}{lbrac} {
BEGIN(readFaceGroupData);
}
{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
IStringStream faceGroupDataStream(YYText());
// read fluentFace zone-ID, start and end-label
faceGroupZoneID.append(readHexLabel(faceGroupDataStream));
// the indices will be used for checking later.
faceGroupStartIndex.append(readHexLabel(faceGroupDataStream));
faceGroupEndIndex.append(readHexLabel(faceGroupDataStream));
// face group type
readHexLabel(faceGroupDataStream);
faceGroupElementType = readHexLabel(faceGroupDataStream);
// In FOAM, indices start from zero - adjust
faceI = faceGroupStartIndex.last() - 1;
}
{spaceNl}{endOfSection} {
BEGIN(readFaceData);
}
{spaceNl}{lbrac} {
if (faceGroupElementType == 0)
{
Info<< "Reading mixed faces" << endl;
yy_push_state(readFacesMixed);
}
else
{
Info<< "Reading uniform faces" << endl;
yy_push_state(readFacesUniform);
}
}
{spaceNl}{hexLabelList} {
IStringStream mixedFaceStream(YYText());
face& curFaceLabels = faces[faceI];
// set size of label list
curFaceLabels.setSize(readLabel(mixedFaceStream));
forAll (curFaceLabels, i)
{
curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
}
// read neighbour and owner. Neighbour comes first
neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
owner[faceI] = readHexLabel(mixedFaceStream) - 1;
faceI++;
}
{spaceNl}{hexLabelList} {
IStringStream mixedFaceStream(YYText());
face& curFaceLabels = faces[faceI];
// set size of label list. This is OK because in Fluent the type
// for edge is 2, for triangle is 3 and for quad is 4
curFaceLabels.setSize(faceGroupElementType);
forAll (curFaceLabels, i)
{
curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
}
// read neighbour and owner. Neighbour comes first
neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
owner[faceI] = readHexLabel(mixedFaceStream) - 1;
faceI++;
}
{spaceNl}{endOfSection} {
// check read of fluentFaces
if (faceI != faceGroupEndIndex.last())
{
Info<< "problem with reading fluentFaces: "
<< "start index: " << faceGroupStartIndex.last()
<< " end index: " << faceGroupEndIndex.last()
<< " last fluentFaces read: " << faceI << endl;
}
yy_pop_state();
}
{cell} {
BEGIN(readCellHeader);
}
{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
BEGIN(readNumberOfCells);
}
{space}{hexLabel}{space}{labelListElement}+ {
IStringStream numberOfCellsStream(YYText());
nCells = readHexLabel(numberOfCellsStream);
Info<< "Number of cells: " << nCells << endl;
fluentCellModelID.setSize(nCells);
// Meaningless type and element type not read
}
{spaceNl}{lbrac} {
BEGIN(readCellGroupData);
}
{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
// Warning. This entry must be above the next one because of the lexing
// rules. It is introduced to deal with the problem of reading
// non-standard cell definition from Tgrid, which misses the type label.
Info<< "Tgrid syntax problem: " << YYText() << endl;
IStringStream cellGroupDataStream(YYText());
// read cell zone-ID, start and end-label
cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
// the indices will be used for checking later.
cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
cellGroupType.append(readHexLabel(cellGroupDataStream));
Info<< "cellGroupZoneID:" << cellGroupZoneID.last()
<< endl;
Info<< "cellGroupStartIndex:" << cellGroupStartIndex.last()
<< endl;
Info<< "cellGroupEndIndex:" << cellGroupEndIndex.last()
<< endl;
Info<< "cellGroupType:" << cellGroupType.last()
<< endl;
// Note. Potentially skip cell set if type is zero.
// This entry does not exist in Tgrid files.
if (dimensionOfGrid == 2)
{
// Tgrid creating triangles
cellGroupElementType = 1;
}
else
{
cellGroupElementType = 2;
}
// In FOAM, indices start from zero - adjust
celli = cellGroupStartIndex.last() - 1;
if (cellGroupElementType != 0)
{
label lastIndex = cellGroupEndIndex.last();
for (; celli < lastIndex; celli++)
{
fluentCellModelID[celli] = cellGroupElementType;
}
}
}
{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
// Warning. See above
Info<< "Other readCellGroupData: " << YYText() << endl;
IStringStream cellGroupDataStream(YYText());
// read cell zone-ID, start and end-label
cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
// the indices will be used for checking later.
cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
cellGroupType.append(readHexLabel(cellGroupDataStream));
// Note. Potentially skip cell set if type is zero.
cellGroupElementType = readHexLabel(cellGroupDataStream);
// In FOAM, indices start from zero - adjust
celli = cellGroupStartIndex.last() - 1;
if (cellGroupElementType != 0)
{
Info<< "Reading uniform cells" << endl;
label lastIndex = cellGroupEndIndex.last();
for (; celli < lastIndex; celli++)
{
fluentCellModelID[celli] = cellGroupElementType;
}
}
}
{endOfSection} {
BEGIN(readCellData);
}
{spaceNl}{lbrac} {
Info<< "Reading mixed cells" << endl;
yy_push_state(readCellsMixed);
}
{spaceNl}{labelList} {
IStringStream fluentCellModelIDStream(YYText());
label celliD;
while (fluentCellModelIDStream.read(celliD))
{
fluentCellModelID[celli] = celliD;
celli++;
}
}
{spaceNl}{endOfSection} {
// check read of cells
if (celli != cellGroupEndIndex.last())
{
Info<< "problem with reading cells: "
<< "start index: " << cellGroupStartIndex.last()
<< " end index: " << cellGroupEndIndex.last()
<< " last cells read: " << celli << endl;
}
yy_pop_state();
}
{zoneVariant1} {
BEGIN(readZoneHeader);
}
{zoneVariant2} {
BEGIN(readZoneHeader);
}
{spaceNl}{lbrac} {
BEGIN(readZoneGroupData);
}
{space}{label}{space}{word}{space}{word} {
IStringStream zoneDataStream(YYText());
// cell zone-ID not in hexadecimal!!! Inconsistency
label zoneID(readLabel(zoneDataStream));
if (zoneID > maxZoneID - 1)
{
// resize the container
maxZoneID = zoneID + zoneIDBuffer;
patchTypeIDs.setSize(maxZoneID);
patchNameIDs.setSize(maxZoneID);
}
zoneDataStream >> patchTypeIDs[zoneID];
zoneDataStream >> patchNameIDs[zoneID];
Info<< "Read zone1:" << zoneID
<< " name:" << patchNameIDs[zoneID]
<< " patchTypeID:" << patchTypeIDs[zoneID]
<< endl;
}
{space}{label}{space}{word}{space}{word}{space}{label} {
// Fluent manual inconsistency, version 6.1.22
IStringStream zoneDataStream(YYText());
// cell zone-ID not in hexadecimal!!! Inconsistency
label zoneID(readLabel(zoneDataStream));
if (zoneID > maxZoneID - 1)
{
// resize the container
maxZoneID = zoneID + zoneIDBuffer;
patchTypeIDs.setSize(maxZoneID);
patchNameIDs.setSize(maxZoneID);
}
zoneDataStream >> patchTypeIDs[zoneID];
zoneDataStream >> patchNameIDs[zoneID];
Info<< "Read zone2:" << zoneID
<< " name:" << patchNameIDs[zoneID]
<< " patchTypeID:" << patchTypeIDs[zoneID]
<< endl;
}
{endOfSection} {
BEGIN(readZoneData);
}
{spaceNl}{lbrac} {
Info<< "Reading zone data" << endl;
yy_push_state(readZoneBlock);
}
{spaceNl}{schemeSymbolList} {
}
{lbrac} {
yy_push_state(unknownBlock);
}
{endOfSection} {
yy_pop_state();
}
/* ------ Reading end of section and others ------ */
{spaceNl}{endOfSection} {
BEGIN(INITIAL);
}
/* ------ Reading unknown type or non-standard comment ------ */
{lbrac}{label} {
yy_push_state(unknownBlock);
}
{spaceNl}{schemeSymbol} {
}
{spaceNl}{lbrac} {
yy_push_state(embeddedUnknownBlock);
}
{spaceNl}{endOfSection} {
yy_pop_state();
}
{spaceNl}{labelList} {
}
{spaceNl}{hexLabelList} {
}
{spaceNl}{scalarList} {
}
{spaceNl}{schemeSymbolList} {
}
{spaceNl}{text} {
}
/* ------ Ignore remaining space and \n s. Any other characters are errors. */
.|\n {
Info<< "ERROR! Do not understand characters: " << YYText() << endl;
}
.|\n {}
/* ------ On EOF return to previous file, if none exists terminate. ------ */
<> {
yyterminate();
}
%%
#include "fileName.H"
#include
// Find label of face.
label findFace(const primitiveMesh& mesh, const face& f)
{
// Get faces using zeroth vertex of face.
const labelList& pFaces = mesh.pointFaces()[f[0] ];
forAll(pFaces, i)
{
label faceI = pFaces[i];
if (f == mesh.faces()[faceI])
{
return faceI;
}
}
// Didn't find face. Do what?
FatalErrorIn("findFace(const primitiveMesh&, const face&)")
<< "Problem : cannot find a single face in the mesh which uses"
<< " vertices " << f << exit(FatalError);
return -1;
}
int main(int argc, char *argv[])
{
argList::noParallel();
argList::validArgs.append("Fluent mesh file");
argList::validOptions.insert("scale", "scale factor");
argList::validOptions.insert("writeSets", "");
argList::validOptions.insert("writeZones", "");
argList args(argc, argv);
if (!args.check())
{
FatalError.exit();
}
scalar scaleFactor = 1.0;
args.optionReadIfPresent("scale", scaleFactor);
bool writeSets = args.optionFound("writeSets");
bool writeZones = args.optionFound("writeZones");
# include "createTime.H"
fileName fluentFile(args.additionalArgs()[0]);
std::ifstream fluentStream(fluentFile.c_str());
if (!fluentStream)
{
FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
<< args.executable()
<< ": file " << fluentFile << " not found"
<< exit(FatalError);
}
//HR 22.11.09: These global variables do not get initialised.
// Debug-version fails!
patchTypeIDs.setSize(maxZoneID);
patchNameIDs.setSize(maxZoneID);
yyFlexLexer lexer(&fluentStream);
while (lexer.yylex() != 0)
{}
Info<< "\n\nFINISHED LEXING\n\n\n";
// Lookup table giving number of vertices given a fluent cell type ID
// Currently not used.
// label fluentModelNVertices[7] = {-1, 3, 4, 4, 8, 5, 6};
// Lookup table giving number of vertices given a fluent cell type ID
label fluentModelNFaces[7] = {-1, 3, 4, 4, 6, 5, 5};
// Make a list of cell faces to be filled in for owner and neighbour
labelListList cellFaces(nCells);
labelList nFacesInCell(nCells, 0);
forAll (cellFaces, celli)
{
cellFaces[celli].setSize(fluentModelNFaces[fluentCellModelID[celli] ]);
}
// fill in owner and neighbour
forAll (owner, faceI)
{
if (owner[faceI] > -1)
{
label curCell = owner[faceI];
if (nFacesInCell[curCell] >= cellFaces[curCell].size())
{
FatalErrorIn(args.executable())
<< "Trying to add " << nFacesInCell[curCell] + 1
<< "th face to a cell with " << cellFaces[curCell].size()
<< " faces. Face index: " << faceI
<< " Current faces: " << cellFaces[curCell]
<< abort(FatalError);
}
cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
nFacesInCell[curCell]++;
}
}
forAll (neighbour, faceI)
{
if (neighbour[faceI] > -1)
{
label curCell = neighbour[faceI];
if (nFacesInCell[curCell] >= cellFaces[curCell].size())
{
FatalErrorIn(args.executable())
<< "Trying to add " << nFacesInCell[curCell] + 1
<< "th face to a cell with " << cellFaces[curCell].size()
<< " faces. Face index: " << faceI
<< " Current faces: " << cellFaces[curCell]
<< abort(FatalError);
}
cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
nFacesInCell[curCell]++;
}
}
// Construct shapes from face lists
cellShapeList cellShapes(nCells);
// Extrude 2-D mesh into 3-D
Info<< "dimension of grid: " << dimensionOfGrid << endl;
faceList frontAndBackFaces;
if (dimensionOfGrid == 2)
{
const scalar extrusionFactor = 0.01;
boundBox box(max(points), min(points));
const scalar zOffset = extrusionFactor*box.mag();
// two-dimensional grid. Extrude in z-direction
Info<< "Grid is 2-D. Extruding in z-direction by: "
<< 2*zOffset << endl;
pointField oldPoints = points;
const label pointOffset = oldPoints.size();
points.setSize(2*pointOffset);
label nNewPoints = 0;
// Note: In order for the owner-neighbour rules to be right, the
// points given by Fluent need to represent the FRONT plane of the
// geometry. Therefore, the extrusion will be in -z direction
forAll (oldPoints, pointI)
{
points[nNewPoints] = oldPoints[pointI];
points[nNewPoints].z() = zOffset;
nNewPoints++;
}
forAll (oldPoints, pointI)
{
points[nNewPoints] = oldPoints[pointI];
points[nNewPoints].z() = -zOffset;
nNewPoints++;
}
// 2-D shape recognition
Info<< "Creating shapes for 2-D cells"<< endl;
// Set the number of empty faces
frontAndBackFaces.setSize(2*nCells);
forAll (fluentCellModelID, celli)
{
switch (fluentCellModelID[celli])
{
case 1:
{
cellShapes[celli] =
cellShape
(
extrudedTriangleCellShape
(
celli,
cellFaces[celli],
faces,
owner,
neighbour,
pointOffset,
frontAndBackFaces
)
);
}
break;
case 3:
{
cellShapes[celli] =
cellShape
(
extrudedQuadCellShape
(
celli,
cellFaces[celli],
faces,
owner,
neighbour,
pointOffset,
frontAndBackFaces
)
);
}
break;
default:
{
FatalErrorIn(args.executable())
<< "unrecognised 2-D cell shape: "
<< fluentCellModelID[celli]
<< abort(FatalError);
}
}
}
// Create new faces
forAll (faces, faceI)
{
if (faces[faceI].size() != 2)
{
FatalErrorIn(args.executable())
<< "fluentMeshToFoam: a 2-D face defined with "
<< faces[faceI].size() << " points." << endl;
}
labelList& newFace = faces[faceI];
newFace.setSize(4);
newFace[2] = newFace[1] + pointOffset;
newFace[3] = newFace[0] + pointOffset;
}
// Create new cells from 2-D shapes
}
else
{
// 3-D shape recognition
Info<< "Creating shapes for 3-D cells"<< endl;
forAll (fluentCellModelID, celli)
{
if
(
fluentCellModelID[celli] == 2 // tet
|| fluentCellModelID[celli] == 4 // hex
|| fluentCellModelID[celli] == 5 // pyramid
|| fluentCellModelID[celli] == 6 // prism
)
{
cellShapes[celli] =
cellShape
(
create3DCellShape
(
celli,
cellFaces[celli],
faces,
owner,
neighbour,
fluentCellModelID[celli]
)
);
}
else
{
FatalErrorIn(args.executable())
<< "unrecognised 3-D cell shape: "
<< fluentCellModelID[celli]
<< abort(FatalError);
}
}
}
// boundary faces are oriented such that the owner is zero and the face
// area vector points into the domain. Turn them round before making patches
// for Foam compatibility
forAll (faces, faceI)
{
if (owner[faceI] == -1)
{
// reverse face
labelList oldFace = faces[faceI];
forAllReverse(oldFace, i)
{
faces[faceI][oldFace.size() - i - 1] =
oldFace[i];
}
}
}
//make patchless mesh before analysing boundaries
faceListList patches(0);
wordList patchNames(0);
wordList patchTypes(0);
word defaultFacesName = "defaultFaces";
word defaultFacesType = emptyPolyPatch::typeName;
wordList patchPhysicalTypes(0);
// Scale the points
points *= scaleFactor;
Info<< "Building patch-less mesh..." << flush;
polyMesh pShapeMesh
(
IOobject
(
polyMesh::defaultRegion,
runTime.constant(),
runTime
),
xferMove(points),
cellShapes,
patches,
patchNames,
patchTypes,
defaultFacesName,
defaultFacesType,
patchPhysicalTypes
);
//dont write mesh yet, otherwise preservePatchTypes will be broken
//and zones wont be written
//checkmesh done after patch addition as well
Info<< "done." << endl;
Info<< endl << "Building boundary and internal patches." << endl;
//adding patches after mesh construction allows topological checks
//on whether a patch is internal or external, something fluent
//doesnt seem to mind
// Make boundary patches
SLList::iterator faceGroupZoneIDIter = faceGroupZoneID.begin();
SLList::iterator faceGroupStartIndexIter =
faceGroupStartIndex.begin();
SLList::iterator faceGroupEndIndexIter = faceGroupEndIndex.begin();
// Note. Not all groups of faces will be boundary patches.
// Take care on construction
//2D needs extra space for frontAndBack faces
if (dimensionOfGrid == 2)
{
patches.setSize(faceGroupZoneID.size()+1);
patchNames.setSize(faceGroupZoneID.size()+1);
patchTypes.setSize(faceGroupZoneID.size()+1);
patchPhysicalTypes.setSize(faceGroupZoneID.size()+1);
}
else
{
patches.setSize(faceGroupZoneID.size());
patchNames.setSize(faceGroupZoneID.size());
patchTypes.setSize(faceGroupZoneID.size());
patchPhysicalTypes.setSize(faceGroupZoneID.size());
}
label nPatches = 0;
// Colate information for all patches (internal and external)
// Create a file listing patch type for each zone
label maxZoneID = 0;
for
(
SLList::iterator fgzIDIter = faceGroupZoneID.begin();
fgzIDIter != faceGroupZoneID.end();
++fgzIDIter
)
{
maxZoneID = max(maxZoneID, fgzIDIter());
}
Info << "maxZoneID: " << maxZoneID << endl;
wordIOList zoneToPatchName
(
IOobject
(
"zoneToPatchName",
runTime.constant(),
pShapeMesh.meshSubDir,
pShapeMesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
wordList(maxZoneID + 1, "unknown")
);
for
(
;
faceGroupZoneIDIter != faceGroupZoneID.end()
&& faceGroupStartIndexIter != faceGroupStartIndex.end()
&& faceGroupEndIndexIter != faceGroupEndIndex.end();
++faceGroupZoneIDIter,
++faceGroupStartIndexIter,
++faceGroupEndIndexIter
)
{
// Get face type and name
const word& curPatchType = patchTypeIDs[faceGroupZoneIDIter()];
const word& curPatchName = patchNameIDs[faceGroupZoneIDIter()];
Info<< "Creating patch " << nPatches
<< " for zone: " << faceGroupZoneIDIter()
<< " start: " << faceGroupStartIndexIter()
<< " end: " << faceGroupEndIndexIter()
<< " type: " << curPatchType << " name: " << curPatchName << endl;
// Record zone index
zoneToPatchName[faceGroupZoneIDIter()] = curPatchName;
// Make patch labels
label faceLabel = faceGroupStartIndexIter() - 1;
faceList patchFaces(faceGroupEndIndexIter() - faceLabel);
forAll (patchFaces, faceI)
{
if
(
faces[faceLabel].size() == 3
|| faces[faceLabel].size() == 4
)
{
patchFaces[faceI] = face(faces[faceLabel]);
faceLabel++;
}
else
{
FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
<< "unrecognised face shape with "
<< patchFaces[faceI].size() << " vertices"
<< abort(FatalError);
}
}
// Inlets and outlets
if
(
curPatchType == "pressure"
|| curPatchType == "pressure-inlet"
|| curPatchType == "inlet-vent"
|| curPatchType == "intake-fan"
|| curPatchType == "pressure-outlet"
|| curPatchType == "exhaust-fan"
|| curPatchType == "outlet-vent"
|| curPatchType == "pressure-far-field"
|| curPatchType == "velocity-inlet"
|| curPatchType == "mass-flow-inlet"
|| curPatchType == "outflow"
|| curPatchType == "interface"
|| curPatchType == "periodic"
|| curPatchType == "shadow"
)
{
patches[nPatches] = patchFaces;
patchTypes[nPatches] = polyPatch::typeName;
patchNames[nPatches] = curPatchName;
nPatches++;
}
else if (curPatchType == "wall" ) //wall boundaries
{
patches[nPatches] = patchFaces;
patchTypes[nPatches] = wallPolyPatch::typeName;
patchNames[nPatches] = curPatchName;
nPatches++;
}
else if
(
curPatchType == "symmetry"
|| curPatchType == "axis"
) //symmetry planes
{
patches[nPatches] = patchFaces;
patchTypes[nPatches] = symmetryPolyPatch::typeName;
patchNames[nPatches] = curPatchName;
nPatches++;
}
else if
(
curPatchType == "interior"
|| curPatchType == "interface"
|| curPatchType == "internal"
|| curPatchType == "solid"
|| curPatchType == "fan"
|| curPatchType == "radiator"
|| curPatchType == "porous-jump"
) //interior boundaries - will not be added as patches
{
patches[nPatches] = patchFaces;
patchTypes[nPatches] = "internal";
patchNames[nPatches] = curPatchName;
nPatches++;
}
else if
(
curPatchType == ""
) // Unnamed face regions default to interior patches
{
Info<< "Patch " << faceGroupZoneIDIter()
<< ": Faces are defined but "
<< "not created as a zone." << endl
<< "Null specification is only valid for internal faces."
<< endl;
patches[nPatches] = patchFaces;
patchTypes[nPatches] = "internal";
patchNames[nPatches] = curPatchName;
nPatches++;
}
else //unknown face regions are not handled
{
FatalErrorIn(args.executable())
<< "fluent patch type " << curPatchType << " not recognised."
<< abort(FatalError);
}
}
//add front and back boundaries for 2D meshes
if (dimensionOfGrid == 2)
{
Info<< "Creating patch for front and back planes" << endl << endl;
patches[nPatches] = frontAndBackFaces;
patchTypes[nPatches] = emptyPolyPatch::typeName;
patchNames[nPatches] = "frontAndBackPlanes";
nPatches++;
}
//Now have all patch information,
//check whether each patch is internal or external
//and add boundaries to mesh
//also write face sets of all patches
patches.setSize(nPatches);
patchTypes.setSize(nPatches);
patchNames.setSize(nPatches);
//old polyBoundary
const polyBoundaryMesh& oPatches = pShapeMesh.boundaryMesh();
// new patches.
DynamicList newPatches(nPatches);
// For every boundary face the old patch.
labelList facePatchID(pShapeMesh.nFaces()-pShapeMesh.nInternalFaces(), -1);
label cMeshFace = pShapeMesh.nInternalFaces();
label nBoundaries = 0;
forAll(patches, patchI)
{
const faceList& bFaces = patches[patchI];
label sz = bFaces.size();
labelList meshFaces(sz,-1);
//make face set and write (seperate from rest for clarity)
//internal and external Fluent boundaries
{
faceSet pFaceSet(pShapeMesh, patchNames[patchI], sz);
forAll (bFaces, j)
{
const face& f = bFaces[j];
label cMeshFace = findFace(pShapeMesh, f);
meshFaces[j] = cMeshFace;
pFaceSet.insert(cMeshFace);
}
if (writeSets)
{
Info<< "Writing patch " << patchNames[patchI]
<< " of size " << sz << " to faceSet." << endl;
pFaceSet.write();
}
}
//check if patch is internal
//also check internal/external-ness of first patch face
//internal faces cannot become foam boundaries
//if a face is defined as internal but is actually external
//it will be put in a default wall boundary
//internal boundaries are simply ignored
if
(
patchTypes[patchI] != "internal"
&& !pShapeMesh.isInternalFace(meshFaces[0])
)
{
// First face is external and has valid non-internal type
//check all faces for externalness just to be sure
//and mark patch number to global list
forAll(meshFaces, i)
{
label faceI = meshFaces[i];
if (pShapeMesh.isInternalFace(faceI))
{
FatalErrorIn(args.executable())
<< "Face " << faceI << " on new patch "
<< patchNames[patchI]
<< " is not an external face of the mesh." << endl
<< exit(FatalError);
}
if(facePatchID[faceI - pShapeMesh.nInternalFaces()]!= -1)
{
FatalErrorIn(args.executable())
<< "Face " << faceI << " on new patch "
<< patchNames[patchI]
<< " has already been marked for repatching to"
<< " patch "
<< facePatchID[faceI - pShapeMesh.nInternalFaces()]
<< exit(FatalError);
}
facePatchID[faceI - pShapeMesh.nInternalFaces()] = nBoundaries;
}
// Add to boundary patch
Info<< "Adding new patch " << patchNames[patchI]
<< " of type " << patchTypes[patchI]
<< " as patch " << nBoundaries << endl;
// Add patch to new patch list
newPatches.append
(
polyPatch::New
(
patchTypes[patchI],
patchNames[patchI],
sz,
cMeshFace,
nBoundaries,
oPatches
).ptr()
);
nBoundaries++;
cMeshFace += sz;
}
else
{
Info<< "Patch " << patchNames[patchI]
<< " is internal to the mesh "
<< " and is not being added to the boundary."
<< endl;
}
}
// Check for any remaining boundary faces
// and add them to a default wall patch
// this routine should generally not be invoked
{
DynamicList defaultBoundaryFaces(facePatchID.size());
forAll (facePatchID, idI)
{
if(facePatchID[idI] == -1)
{
defaultBoundaryFaces.append(idI);
facePatchID[idI] = nBoundaries;
}
}
defaultBoundaryFaces.shrink();
if (defaultBoundaryFaces.size() != 0)
{
Warning << " fluent mesh has " << defaultBoundaryFaces.size()
<< " undefined boundary faces." << endl
<< " Adding undefined faces to new patch `default_wall`"
<< endl;
// Add patch to new patch list
newPatches.append
(
polyPatch::New
(
wallPolyPatch::typeName,
"default_wall",
defaultBoundaryFaces.size(),
cMeshFace,
nBoundaries,
oPatches
).ptr()
);
nBoundaries++;
cMeshFace += defaultBoundaryFaces.size();
}
}
newPatches.shrink();
// Use facePatchIDs map to reorder boundary faces into compact regions
repatchPolyTopoChanger repatcher(pShapeMesh);
// Add new list of patches
repatcher.changePatches(newPatches);
// Change patch ids
forAll(facePatchID, idI)
{
label faceI = idI + pShapeMesh.nInternalFaces();
repatcher.changePatchID(faceI, facePatchID[idI]);
}
repatcher.repatch();
preservePatchTypes
(
runTime,
runTime.constant(),
polyMesh::defaultRegion,
patchNames,
patchTypes,
defaultFacesName,
defaultFacesType,
patchPhysicalTypes
);
// Set the precision of the points data to 10
IOstream::defaultPrecision(10);
// Zones
// will write out cell zones and internal faces for those zones
// note: zone boundary faces are not added to face zones
// the names of boundaries bordering on cell zones are written to
// a list containing the boundary name and cellzone it borders on
// interior boundaries are handled via faceSets
// cell zones will only be written if there is more than one
if (writeZones && cellGroupZoneID.size()>1)
{
Info<< "Adding Zones" << endl;
List pz(0);
label nrCellZones = cellGroupZoneID.size();
List cz(nrCellZones);
// Make face zones for cell zones
List fz(nrCellZones);
// List of patch names and the cellZone(s) they border
// this is just an info file to make MRF easier to setup
List > boundaryZones
(
pShapeMesh.boundaryMesh().size()
);
const polyBoundaryMesh& bPatches = pShapeMesh.boundaryMesh();
forAll(bPatches, pI)
{
boundaryZones[pI].append(bPatches[pI].name());
}
label cnt = 0;
SLList::iterator cg = cellGroupZoneID.begin();
SLList::iterator start = cellGroupStartIndex.begin();
SLList::iterator end = cellGroupEndIndex.begin();
for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
{
const word& name = patchNameIDs[cg()];
const word& type = patchTypeIDs[cg()];
Info<< "Writing cell zone: " << name
<< " of type " << type << " starting at " << start() - 1
<< " ending at " << end() - 1 << " to cellSet." << endl;
labelList cls(end() - start() + 1);
// Mark zone cells, used for finding faces
boolList zoneCell(pShapeMesh.nCells(), false);
// Shift cell indices by 1
label nr = 0;
for (label celli = (start() - 1); celli < end(); celli++)
{
cls[nr] = celli;
zoneCell[celli] = true;
nr++;
}
cz[cnt] = new cellZone
(
name,
cls,
cnt,
pShapeMesh.cellZones()
);
DynamicList zoneFaces(pShapeMesh.nFaces());
forAll (pShapeMesh.faceNeighbour(), faceI)
{
label nei = pShapeMesh.faceNeighbour()[faceI];
label own = pShapeMesh.faceOwner()[faceI];
if(nei != -1)
{
if(zoneCell[nei] && zoneCell[own])
{
zoneFaces.append(faceI);
}
}
}
zoneFaces.shrink();
fz[cnt] = new faceZone
(
name,
zoneFaces,
boolList(zoneFaces.size(), false),
cnt,
pShapeMesh.faceZones()
);
// Add cell zones to patch zone list
forAll (bPatches, pI)
{
const labelList& faceCells = bPatches[pI].faceCells();
forAll(faceCells, fcI)
{
if(zoneCell[faceCells[fcI] ])
{
boundaryZones[pI].append(name);
break;
}
}
}
cnt++;
}
pShapeMesh.addZones(pz, fz, cz);
forAll(bPatches, pI)
{
boundaryZones[pI].shrink();
}
fileName bczf
(
runTime.path()/runTime.constant()
/"polyMesh"/"boundaryAdjacentCellZones"
);
OFstream boundaryCellZonesFile(bczf);
forAll (boundaryZones, bzI)
{
forAll(boundaryZones[bzI], bzII)
{
boundaryCellZonesFile << boundaryZones[bzI][bzII] << " ";
}
boundaryCellZonesFile << endl;
}
}
Info<< endl << "Writing mesh..." << flush;
Info<< " to " << pShapeMesh.instance()/pShapeMesh.meshDir()
<< " " << flush;
pShapeMesh.setInstance(pShapeMesh.instance());
pShapeMesh.write();
// Write zone to patch name
zoneToPatchName.write();
Info<< "done." << endl << endl;
// Write cellSets for Fluent regions
// allows easy post-processing
// set and zone functionality will be integrated some time
// soon negating the need for double output
if (writeSets)
{
if (cellGroupZoneID.size() > 1)
{
Info<< "Writing cell sets" << endl;
SLList::iterator cg = cellGroupZoneID.begin();
SLList::iterator start = cellGroupStartIndex.begin();
SLList::iterator end = cellGroupEndIndex.begin();
// Note: cellGroupXXX are all Fluent indices (starting at 1)
// so offset before using.
for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
{
const word& name = patchNameIDs[cg()];
const word& type = patchTypeIDs[cg()];
Info<< "Writing cell set: " << name
<< " of type " << type << " starting at " << start() - 1
<< " ending at " << end() - 1 << " to cellSet." << endl;
cellSet internal(pShapeMesh, name, end() - start());
// shift cell indizes by 1
for (label celli = start() - 1; celli <= end() - 1; celli++)
{
internal.insert(celli);
}
internal.write();
}
}
else
{
Info<< "Only one cell group: no set written\n";
}
}
Info<< "\nEnd\n" << endl;
return 0;
}
/* --------------------------------------------------------------------------*\
------ End of fluentMeshToFoam.L
\* --------------------------------------------------------------------------*/