1807 lines
50 KiB
C++
1807 lines
50 KiB
C++
/*--------------------------------*- C++ -*----------------------------------*\
|
|
========= |
|
|
\\ / F ield | foam-extend: Open Source CFD
|
|
\\ / O peration | Version: 3.2
|
|
\\ / A nd | Web: http://www.foam-extend.org
|
|
\\/ M anipulation | For copyright notice see file Copyright
|
|
-------------------------------------------------------------------------------
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
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<label> pointGroupZoneID;
|
|
SLList<label> pointGroupStartIndex;
|
|
SLList<label> pointGroupEndIndex;
|
|
|
|
|
|
faceList faces(0);
|
|
labelList owner(0);
|
|
labelList neighbour(0);
|
|
SLList<label> faceGroupZoneID;
|
|
SLList<label> faceGroupStartIndex;
|
|
SLList<label> faceGroupEndIndex;
|
|
|
|
labelList fluentCellModelID(0);
|
|
SLList<label> cellGroupZoneID;
|
|
SLList<label> cellGroupStartIndex;
|
|
SLList<label> cellGroupEndIndex;
|
|
SLList<label> 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 <<EOF>>
|
|
#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);
|
|
}
|
|
|
|
|
|
<readComment>{quote}{text}{quote} {
|
|
}
|
|
|
|
|
|
<readComment>{spaceNl}{endOfSection} {
|
|
yy_pop_state();
|
|
}
|
|
|
|
{header} {
|
|
BEGIN(readHeader);
|
|
}
|
|
|
|
<readHeader>{quote}{text}{quote} {
|
|
Info<< "Reading header: " << YYText() << endl;
|
|
}
|
|
|
|
|
|
{dimension} {
|
|
BEGIN(readDimension);
|
|
}
|
|
|
|
<readDimension>{space}{label}{space} {
|
|
IStringStream dimOfGridStream(YYText());
|
|
|
|
dimensionOfGrid = readLabel(dimOfGridStream);
|
|
|
|
Info<< "Dimension of grid: " << dimensionOfGrid << endl;
|
|
}
|
|
|
|
|
|
{point} {
|
|
BEGIN(readPointHeader);
|
|
}
|
|
|
|
<readPointHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
|
|
BEGIN(readNumberOfPoints);
|
|
}
|
|
|
|
<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;
|
|
}
|
|
}
|
|
|
|
<readPointHeader>{spaceNl}{lbrac} {
|
|
BEGIN(readPointGroupData);
|
|
}
|
|
|
|
<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);
|
|
}
|
|
}
|
|
|
|
<readNumberOfPoints,readPointGroupData>{endOfSection} {
|
|
BEGIN(readPointData);
|
|
}
|
|
|
|
<readPointData>{spaceNl}{lbrac} {
|
|
|
|
Info<< "Reading points" << endl;
|
|
|
|
if (pointGroupNumberOfComponents == 2)
|
|
{
|
|
yy_push_state(readPoints2D);
|
|
}
|
|
else
|
|
{
|
|
yy_push_state(readPoints3D);
|
|
}
|
|
}
|
|
|
|
<readPoints2D>{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++;
|
|
}
|
|
|
|
<readPoints3D>{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++;
|
|
}
|
|
|
|
<readPoints2D,readPoints3D>{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);
|
|
}
|
|
|
|
<readFaceHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
|
|
BEGIN(readNumberOfFaces);
|
|
}
|
|
|
|
<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
|
|
}
|
|
|
|
<readFaceHeader>{spaceNl}{lbrac} {
|
|
BEGIN(readFaceGroupData);
|
|
}
|
|
|
|
<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;
|
|
}
|
|
|
|
<readNumberOfFaces,readFaceGroupData>{spaceNl}{endOfSection} {
|
|
BEGIN(readFaceData);
|
|
}
|
|
|
|
<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);
|
|
}
|
|
}
|
|
|
|
<readFacesMixed>{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++;
|
|
}
|
|
|
|
<readFacesUniform>{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++;
|
|
}
|
|
|
|
<readFacesMixed,readFacesUniform>{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);
|
|
}
|
|
|
|
<readCellHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
|
|
BEGIN(readNumberOfCells);
|
|
}
|
|
|
|
<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
|
|
}
|
|
|
|
<readCellHeader>{spaceNl}{lbrac} {
|
|
BEGIN(readCellGroupData);
|
|
}
|
|
|
|
<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;
|
|
}
|
|
}
|
|
}
|
|
|
|
<readCellGroupData>{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;
|
|
}
|
|
}
|
|
}
|
|
|
|
<readNumberOfCells,readCellGroupData>{endOfSection} {
|
|
BEGIN(readCellData);
|
|
}
|
|
|
|
<readCellData>{spaceNl}{lbrac} {
|
|
Info<< "Reading mixed cells" << endl;
|
|
yy_push_state(readCellsMixed);
|
|
}
|
|
|
|
<readCellsMixed>{spaceNl}{labelList} {
|
|
|
|
IStringStream fluentCellModelIDStream(YYText());
|
|
|
|
label celliD;
|
|
while (fluentCellModelIDStream.read(celliD))
|
|
{
|
|
fluentCellModelID[celli] = celliD;
|
|
celli++;
|
|
}
|
|
}
|
|
|
|
<readCellsMixed>{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);
|
|
}
|
|
|
|
<readZoneHeader>{spaceNl}{lbrac} {
|
|
BEGIN(readZoneGroupData);
|
|
}
|
|
|
|
<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;
|
|
}
|
|
|
|
<readZoneGroupData>{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;
|
|
}
|
|
|
|
<readZoneGroupData>{endOfSection} {
|
|
BEGIN(readZoneData);
|
|
}
|
|
|
|
<readZoneData>{spaceNl}{lbrac} {
|
|
Info<< "Reading zone data" << endl;
|
|
yy_push_state(readZoneBlock);
|
|
}
|
|
|
|
<readZoneBlock>{spaceNl}{schemeSymbolList} {
|
|
}
|
|
|
|
<readZoneBlock>{lbrac} {
|
|
yy_push_state(unknownBlock);
|
|
}
|
|
|
|
<readZoneBlock>{endOfSection} {
|
|
yy_pop_state();
|
|
}
|
|
|
|
|
|
|
|
/* ------ Reading end of section and others ------ */
|
|
|
|
<readHeader,readDimension,readPointData,readFaceData,readCellData,readZoneData>{spaceNl}{endOfSection} {
|
|
BEGIN(INITIAL);
|
|
}
|
|
|
|
/* ------ Reading unknown type or non-standard comment ------ */
|
|
|
|
|
|
{lbrac}{label} {
|
|
yy_push_state(unknownBlock);
|
|
}
|
|
|
|
<readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbol} {
|
|
}
|
|
|
|
<readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{lbrac} {
|
|
yy_push_state(embeddedUnknownBlock);
|
|
|
|
}
|
|
|
|
<readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{endOfSection} {
|
|
yy_pop_state();
|
|
}
|
|
|
|
<unknownBlock,embeddedUnknownBlock>{spaceNl}{labelList} {
|
|
}
|
|
|
|
<unknownBlock,embeddedUnknownBlock>{spaceNl}{hexLabelList} {
|
|
}
|
|
|
|
<unknownBlock,embeddedUnknownBlock>{spaceNl}{scalarList} {
|
|
}
|
|
|
|
<unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbolList} {
|
|
}
|
|
|
|
<unknownBlock,embeddedUnknownBlock>{spaceNl}{text} {
|
|
}
|
|
|
|
|
|
/* ------ Ignore remaining space and \n s. Any other characters are errors. */
|
|
|
|
<readPoints2D,readPoints3D>.|\n {
|
|
Info<< "ERROR! Do not understand characters: " << YYText() << endl;
|
|
}
|
|
.|\n {}
|
|
|
|
|
|
/* ------ On EOF return to previous file, if none exists terminate. ------ */
|
|
|
|
<<EOF>> {
|
|
yyterminate();
|
|
}
|
|
%%
|
|
|
|
|
|
#include "fileName.H"
|
|
#include <fstream>
|
|
|
|
// 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<label>::iterator faceGroupZoneIDIter = faceGroupZoneID.begin();
|
|
SLList<label>::iterator faceGroupStartIndexIter =
|
|
faceGroupStartIndex.begin();
|
|
SLList<label>::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<label>::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<polyPatch*> 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<label> 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<pointZone*> pz(0);
|
|
|
|
label nrCellZones = cellGroupZoneID.size();
|
|
List<cellZone*> cz(nrCellZones);
|
|
|
|
// Make face zones for cell zones
|
|
List<faceZone*> 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<DynamicList<word> > boundaryZones
|
|
(
|
|
pShapeMesh.boundaryMesh().size()
|
|
);
|
|
|
|
const polyBoundaryMesh& bPatches = pShapeMesh.boundaryMesh();
|
|
forAll(bPatches, pI)
|
|
{
|
|
boundaryZones[pI].append(bPatches[pI].name());
|
|
}
|
|
|
|
label cnt = 0;
|
|
SLList<label>::iterator cg = cellGroupZoneID.begin();
|
|
SLList<label>::iterator start = cellGroupStartIndex.begin();
|
|
SLList<label>::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<label> 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<label>::iterator cg = cellGroupZoneID.begin();
|
|
SLList<label>::iterator start = cellGroupStartIndex.begin();
|
|
SLList<label>::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
|
|
\* --------------------------------------------------------------------------*/
|