1 /*--------------------------------*- C++ -*----------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
28 Converts a Fluent mesh to OpenFOAM format
29 including multiple region and region boundary handling.
31 \*---------------------------------------------------------------------------*/
37 /* ------------------------------------------------------------------------- *\
38 ------ local definitions
39 \* ------------------------------------------------------------------------- */
43 #include "IStringStream.H"
45 #include "emptyPolyPatch.H"
46 #include "wallPolyPatch.H"
47 #include "symmetryPolyPatch.H"
48 #include "cellShape.H"
51 #include "meshTools.H"
54 #include "readHexLabel.H"
55 #include "cellShapeRecognition.H"
56 #include "repatchPolyTopoChanger.H"
59 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
63 const scalar convertToMeters = 1.0;
65 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
68 label dimensionOfGrid = 0;
75 SLList<label> pointGroupZoneID;
76 SLList<label> pointGroupStartIndex;
77 SLList<label> pointGroupEndIndex;
82 labelList neighbour(0);
83 SLList<label> faceGroupZoneID;
84 SLList<label> faceGroupStartIndex;
85 SLList<label> faceGroupEndIndex;
87 labelList fluentCellModelID(0);
88 SLList<label> cellGroupZoneID;
89 SLList<label> cellGroupStartIndex;
90 SLList<label> cellGroupEndIndex;
91 SLList<label> cellGroupType;
93 // number of zones adjusted at run-time if necessary
94 label maxZoneID = 100;
95 label zoneIDBuffer = 10;
97 wordList patchTypeIDs(maxZoneID);
98 wordList patchNameIDs(maxZoneID);
100 // Dummy yywrap to keep yylex happy at compile time.
101 // It is called by yylex but is not used as the mechanism to change file.
103 #if YY_FLEX_SUBMINOR_VERSION < 34
104 extern "C" int yywrap()
106 int yyFlexLexer::yywrap()
116 some_space {one_space}+
118 spaceNl ({space}|\n|\r)*
124 hexDigit [[:xdigit:]]
132 schemeSpecialInitial [!$%&*/:<=>?~_^#.]
133 schemeSpecialSubsequent [.+-]
134 schemeSymbol (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
137 identifier {alpha}({alpha}|{digit})*
139 label [1-9]{decDigit}*
143 word ({alpha}|{digit}|{dotColonDash})*
145 exponent_part [eE][-+]?{digit}+
146 fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
148 double ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
154 labelListElement {space}{zeroLabel}
155 hexLabelListElement {space}{hexLabel}
156 scalarListElement {space}{double}
157 schemeSymbolListElement {space}{schemeSymbol}
158 labelList ({labelListElement}+{space})
159 hexLabelList ({hexLabelListElement}+{space})
160 scalarList ({scalarListElement}+{space})
161 schemeSymbolList ({schemeSymbolListElement}+{space})
164 text ({space}({word}*{space})*)
166 dateDDMMYYYY ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
167 dateDDMonYYYY ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
168 time ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
170 versionNumber ({digit}|".")*
172 comment {spaceNl}"(0"{space}
173 header {spaceNl}"(1"{space}
174 dimension {spaceNl}"(2"{space}
175 point {spaceNl}"(10"{space}
176 fluentFace {spaceNl}"(13"{space}
177 cell {spaceNl}"(12"{space}
178 zoneVariant1 {spaceNl}"(39"{space}
179 zoneVariant2 {spaceNl}"(45"{space}
181 unknownPeriodicFace {spaceNl}"(17"{space}
182 periodicFace {spaceNl}"(18"{space}
183 cellTree {spaceNl}"(58"{space}
184 faceTree {spaceNl}"(59"{space}
185 faceParents {spaceNl}"(61"{space}
187 endOfSection {space}")"{space}
191 /* ------------------------------------------------------------------------- *\
192 ----- Exclusive start states -----
193 \* ------------------------------------------------------------------------- */
198 %x embeddedCommentState
203 %x readNumberOfPoints
204 %x readPointGroupData
234 %x embeddedUnknownBlock
239 label pointGroupNumberOfComponents = 3;
240 label pointI = 0; // index used for reading points
243 label faceGroupElementType = -1;
247 label cellGroupElementType = -1;
252 /* ------------------------------------------------------------------------- *\
253 ------ Start Lexing ------
254 \* ------------------------------------------------------------------------- */
256 /* ------ Reading control header ------ */
259 yy_push_state(readComment);
263 <readComment>{quote}{text}{quote} {
267 <readComment>{spaceNl}{endOfSection} {
275 <readHeader>{quote}{text}{quote} {
276 Info<< "Reading header: " << YYText() << endl;
281 BEGIN(readDimension);
284 <readDimension>{space}{label}{space} {
285 IStringStream dimOfGridStream(YYText());
287 dimensionOfGrid = readLabel(dimOfGridStream);
289 Info<< "Dimension of grid: " << dimensionOfGrid << endl;
294 BEGIN(readPointHeader);
297 <readPointHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
298 BEGIN(readNumberOfPoints);
301 <readNumberOfPoints>{space}{hexLabel}{space}{labelList} {
303 IStringStream numberOfPointsStream(YYText());
305 nPoints = readHexLabel(numberOfPointsStream);
307 Info<< "Number of points: " << nPoints << endl;
309 // set the size of the points list
310 points.setSize(nPoints);
312 // meaningless type skipped
313 readLabel(numberOfPointsStream);
315 // this dimension of grid may be checked against global dimension
316 if (numberOfPointsStream)
318 // check dimension of grid
319 readLabel(numberOfPointsStream);
327 <readPointHeader>{spaceNl}{lbrac} {
328 BEGIN(readPointGroupData);
331 <readPointGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
332 IStringStream pointGroupDataStream(YYText());
334 // read point zone-ID, start and end-label
335 // the indices will be used for checking later.
336 pointGroupZoneID.append(readHexLabel(pointGroupDataStream));
338 pointGroupStartIndex.append(readHexLabel(pointGroupDataStream));
340 pointGroupEndIndex.append(readHexLabel(pointGroupDataStream));
342 // point group type skipped
343 readHexLabel(pointGroupDataStream);
345 // In FOAM, indices start from zero - adjust
346 pointI = pointGroupStartIndex.last() - 1;
348 // reset number of components to default
349 pointGroupNumberOfComponents = 3;
351 // read number of components in the vector
352 if (pointGroupDataStream)
354 pointGroupNumberOfComponents = readLabel(pointGroupDataStream);
358 <readNumberOfPoints,readPointGroupData>{endOfSection} {
359 BEGIN(readPointData);
362 <readPointData>{spaceNl}{lbrac} {
364 Info<< "Reading points" << endl;
366 if (pointGroupNumberOfComponents == 2)
368 yy_push_state(readPoints2D);
372 yy_push_state(readPoints3D);
376 <readPoints2D>{spaceNl}{scalarList} {
378 IStringStream vertexXyzStream(YYText());
380 // Note: coordinates must be read one at the time.
381 scalar x = readScalar(vertexXyzStream);
382 scalar y = readScalar(vertexXyzStream);
384 points[pointI] = point(x, y, 0);
388 <readPoints3D>{spaceNl}{scalarList} {
390 IStringStream vertexXyzStream(YYText());
392 // Note: coordinates must be read one at the time.
393 scalar x = readScalar(vertexXyzStream);
394 scalar y = readScalar(vertexXyzStream);
395 scalar z = readScalar(vertexXyzStream);
397 points[pointI] = convertToMeters*point(x, y, z);
401 <readPoints2D,readPoints3D>{spaceNl}{endOfSection} {
403 // check read of points
404 if (pointI != pointGroupEndIndex.last())
406 Info<< "problem with reading points: "
407 << "start index: " << pointGroupStartIndex.last()
408 << " end index: " << pointGroupEndIndex.last()
409 << " last points read: " << pointI << endl;
417 BEGIN(readFaceHeader);
420 <readFaceHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
421 BEGIN(readNumberOfFaces);
424 <readNumberOfFaces>{space}{hexLabel}{space}{labelListElement}+ {
426 IStringStream numberOfFacesStream(YYText());
428 nFaces = readHexLabel(numberOfFacesStream);
430 Info<< "number of faces: " << nFaces << endl;
432 faces.setSize(nFaces);
433 owner.setSize(nFaces);
434 neighbour.setSize(nFaces);
436 // Meaningless type and element type not read
439 <readFaceHeader>{spaceNl}{lbrac} {
440 BEGIN(readFaceGroupData);
443 <readFaceGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
445 IStringStream faceGroupDataStream(YYText());
447 // read fluentFace zone-ID, start and end-label
448 faceGroupZoneID.append(readHexLabel(faceGroupDataStream));
450 // the indices will be used for checking later.
451 faceGroupStartIndex.append(readHexLabel(faceGroupDataStream));
453 faceGroupEndIndex.append(readHexLabel(faceGroupDataStream));
456 readHexLabel(faceGroupDataStream);
458 faceGroupElementType = readHexLabel(faceGroupDataStream);
460 // In FOAM, indices start from zero - adjust
461 faceI = faceGroupStartIndex.last() - 1;
464 <readNumberOfFaces,readFaceGroupData>{spaceNl}{endOfSection} {
468 <readFaceData>{spaceNl}{lbrac} {
470 if (faceGroupElementType == 0)
472 Info<< "Reading mixed faces" << endl;
473 yy_push_state(readFacesMixed);
477 Info<< "Reading uniform faces" << endl;
478 yy_push_state(readFacesUniform);
482 <readFacesMixed>{spaceNl}{hexLabelList} {
484 IStringStream mixedFaceStream(YYText());
486 face& curFaceLabels = faces[faceI];
488 // set size of label list
489 curFaceLabels.setSize(readLabel(mixedFaceStream));
491 forAll(curFaceLabels, i)
493 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
496 // read neighbour and owner. Neighbour comes first
497 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
498 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
502 <readFacesUniform>{spaceNl}{hexLabelList} {
504 IStringStream mixedFaceStream(YYText());
506 face& curFaceLabels = faces[faceI];
508 // set size of label list. This is OK because in Fluent the type
509 // for edge is 2, for triangle is 3 and for quad is 4
510 curFaceLabels.setSize(faceGroupElementType);
512 forAll(curFaceLabels, i)
514 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
517 // read neighbour and owner. Neighbour comes first
518 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
519 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
523 <readFacesMixed,readFacesUniform>{spaceNl}{endOfSection} {
525 // check read of fluentFaces
526 if (faceI != faceGroupEndIndex.last())
528 Info<< "problem with reading fluentFaces: "
529 << "start index: " << faceGroupStartIndex.last()
530 << " end index: " << faceGroupEndIndex.last()
531 << " last fluentFaces read: " << faceI << endl;
539 BEGIN(readCellHeader);
542 <readCellHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
543 BEGIN(readNumberOfCells);
546 <readNumberOfCells>{space}{hexLabel}{space}{labelListElement}+ {
548 IStringStream numberOfCellsStream(YYText());
550 nCells = readHexLabel(numberOfCellsStream);
552 Info<< "Number of cells: " << nCells << endl;
554 fluentCellModelID.setSize(nCells);
556 // Meaningless type and element type not read
559 <readCellHeader>{spaceNl}{lbrac} {
560 BEGIN(readCellGroupData);
563 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
564 // Warning. This entry must be above the next one because of the lexing
565 // rules. It is introduced to deal with the problem of reading
566 // non-standard cell definition from Tgrid, which misses the type label.
568 Info<< "Tgrid syntax problem: " << YYText() << endl;
569 IStringStream cellGroupDataStream(YYText());
571 // read cell zone-ID, start and end-label
572 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
574 // the indices will be used for checking later.
575 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
577 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
579 cellGroupType.append(readHexLabel(cellGroupDataStream));
581 Info<< "cellGroupZoneID:" << cellGroupZoneID.last()
583 Info<< "cellGroupStartIndex:" << cellGroupStartIndex.last()
585 Info<< "cellGroupEndIndex:" << cellGroupEndIndex.last()
587 Info<< "cellGroupType:" << cellGroupType.last()
591 // Note. Potentially skip cell set if type is zero.
592 // This entry does not exist in Tgrid files.
593 if (dimensionOfGrid == 2)
595 // Tgrid creating triangles
596 cellGroupElementType = 1;
600 cellGroupElementType = 2;
603 // In FOAM, indices start from zero - adjust
604 celli = cellGroupStartIndex.last() - 1;
606 if (cellGroupElementType != 0)
608 label lastIndex = cellGroupEndIndex.last();
610 for (; celli < lastIndex; celli++)
612 fluentCellModelID[celli] = cellGroupElementType;
617 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
618 // Warning. See above
620 Info<< "Other readCellGroupData: " << YYText() << endl;
623 IStringStream cellGroupDataStream(YYText());
625 // read cell zone-ID, start and end-label
626 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
628 // the indices will be used for checking later.
629 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
631 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
633 cellGroupType.append(readHexLabel(cellGroupDataStream));
635 // Note. Potentially skip cell set if type is zero.
637 cellGroupElementType = readHexLabel(cellGroupDataStream);
639 // In FOAM, indices start from zero - adjust
640 celli = cellGroupStartIndex.last() - 1;
642 if (cellGroupElementType != 0)
644 Info<< "Reading uniform cells" << endl;
645 label lastIndex = cellGroupEndIndex.last();
647 for (; celli < lastIndex; celli++)
649 fluentCellModelID[celli] = cellGroupElementType;
654 <readNumberOfCells,readCellGroupData>{endOfSection} {
658 <readCellData>{spaceNl}{lbrac} {
659 Info<< "Reading mixed cells" << endl;
660 yy_push_state(readCellsMixed);
663 <readCellsMixed>{spaceNl}{labelList} {
665 IStringStream fluentCellModelIDStream(YYText());
668 while (fluentCellModelIDStream.read(celliD))
670 fluentCellModelID[celli] = celliD;
675 <readCellsMixed>{spaceNl}{endOfSection} {
677 // check read of cells
678 if (celli != cellGroupEndIndex.last())
680 Info<< "problem with reading cells: "
681 << "start index: " << cellGroupStartIndex.last()
682 << " end index: " << cellGroupEndIndex.last()
683 << " last cells read: " << celli << endl;
692 BEGIN(readZoneHeader);
696 BEGIN(readZoneHeader);
699 <readZoneHeader>{spaceNl}{lbrac} {
700 BEGIN(readZoneGroupData);
703 <readZoneGroupData>{space}{label}{space}{word}{space}{word} {
705 IStringStream zoneDataStream(YYText());
707 // cell zone-ID not in hexadecimal!!! Inconsistency
708 label zoneID(readLabel(zoneDataStream));
710 if (zoneID > maxZoneID - 1)
712 // resize the container
713 maxZoneID = zoneID + zoneIDBuffer;
715 patchTypeIDs.setSize(maxZoneID);
716 patchNameIDs.setSize(maxZoneID);
719 zoneDataStream >> patchTypeIDs[zoneID];
720 zoneDataStream >> patchNameIDs[zoneID];
722 Info<< "Read zone1:" << zoneID
723 << " name:" << patchNameIDs[zoneID]
724 << " patchTypeID:" << patchTypeIDs[zoneID]
728 <readZoneGroupData>{space}{label}{space}{word}{space}{word}{space}{label} {
729 // Fluent manual inconsistency, version 6.1.22
730 IStringStream zoneDataStream(YYText());
732 // cell zone-ID not in hexadecimal!!! Inconsistency
733 label zoneID(readLabel(zoneDataStream));
735 if (zoneID > maxZoneID - 1)
737 // resize the container
738 maxZoneID = zoneID + zoneIDBuffer;
740 patchTypeIDs.setSize(maxZoneID);
741 patchNameIDs.setSize(maxZoneID);
744 zoneDataStream >> patchTypeIDs[zoneID];
745 zoneDataStream >> patchNameIDs[zoneID];
747 Info<< "Read zone2:" << zoneID
748 << " name:" << patchNameIDs[zoneID]
749 << " patchTypeID:" << patchTypeIDs[zoneID]
753 <readZoneGroupData>{endOfSection} {
757 <readZoneData>{spaceNl}{lbrac} {
758 Info<< "Reading zone data" << endl;
759 yy_push_state(readZoneBlock);
762 <readZoneBlock>{spaceNl}{schemeSymbolList} {
765 <readZoneBlock>{lbrac} {
766 Info<< "Found unknown block in zone:" << YYText() << endl;
767 yy_push_state(unknownBlock);
770 <readZoneBlock>{endOfSection} {
776 /* ------ Reading end of section and others ------ */
778 <readHeader,readDimension,readPointData,readFaceData,readCellData,readZoneData>{spaceNl}{endOfSection} {
782 /* ------ Reading unknown type or non-standard comment ------ */
786 Info<< "Found unknown block:" << YYText() << endl;
787 yy_push_state(unknownBlock);
790 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbol} {
793 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{lbrac} {
794 Info<< "Embedded blocks in comment or unknown:" << YYText() << endl;
795 yy_push_state(embeddedUnknownBlock);
799 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{endOfSection} {
800 Info<< "Found end of section in unknown:" << YYText() << endl;
804 <unknownBlock,embeddedUnknownBlock>{spaceNl}{labelList} {
807 <unknownBlock,embeddedUnknownBlock>{spaceNl}{hexLabelList} {
810 <unknownBlock,embeddedUnknownBlock>{spaceNl}{scalarList} {
813 <unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbolList} {
816 <unknownBlock,embeddedUnknownBlock>{spaceNl}{text} {
820 /* ------ Ignore remaining space and \n s. Any other characters are errors. */
822 <readPoints2D,readPoints3D>.|\n {
823 Info<< "ERROR! Do not understand characters: " << YYText() << endl;
828 /* ------ On EOF return to previous file, if none exists terminate. ------ */
836 #include "fileName.H"
839 // Find label of face.
840 label findFace(const primitiveMesh& mesh, const face& f)
842 // Get faces using zeroth vertex of face.
843 const labelList& pFaces = mesh.pointFaces()[f[0] ];
847 label faceI = pFaces[i];
849 if (f == mesh.faces()[faceI])
855 // Didn't find face. Do what?
856 FatalErrorIn("findFace(const primitiveMesh&, const face&)")
857 << "Problem : cannot find a single face in the mesh which uses"
858 << " vertices " << f << exit(FatalError);
864 int main(int argc, char *argv[])
866 argList::noParallel();
867 argList::validArgs.append("Fluent mesh file");
872 "geometry scaling factor - default is 1"
874 argList::addBoolOption
877 "write cell zones and patches as sets"
879 argList::addBoolOption
882 "write cell zones as zones"
885 argList args(argc, argv);
892 const scalar scaleFactor = args.optionLookupOrDefault("scale", 1.0);
894 const bool writeSets = args.optionFound("writeSets");
895 const bool writeZones = args.optionFound("writeZones");
897 # include "createTime.H"
899 const fileName fluentFile = args[1];
900 std::ifstream fluentStream(fluentFile.c_str());
904 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
906 << ": file " << fluentFile << " not found"
910 yyFlexLexer lexer(&fluentStream);
911 while (lexer.yylex() != 0)
914 Info<< "\n\nFINISHED LEXING\n\n\n";
915 // Lookup table giving number of vertices given a fluent cell type ID
916 // Currently not used.
917 // label fluentModelNVertices[7] = {-1, 3, 4, 4, 8, 5, 6};
919 // Lookup table giving number of vertices given a fluent cell type ID
920 label fluentModelNFaces[7] = {-1, 3, 4, 4, 6, 5, 5};
922 // Make a list of cell faces to be filled in for owner and neighbour
924 labelListList cellFaces(nCells);
926 labelList nFacesInCell(nCells, 0);
928 forAll(cellFaces, celli)
930 cellFaces[celli].setSize(fluentModelNFaces[fluentCellModelID[celli] ]);
933 // fill in owner and neighbour
937 if (owner[faceI] > -1)
939 label curCell = owner[faceI];
940 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
942 nFacesInCell[curCell]++;
946 forAll(neighbour, faceI)
948 if (neighbour[faceI] > -1)
950 label curCell = neighbour[faceI];
951 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
953 nFacesInCell[curCell]++;
957 // Construct shapes from face lists
958 cellShapeList cellShapes(nCells);
960 // Extrude 2-D mesh into 3-D
962 Info<< "dimension of grid: " << dimensionOfGrid << endl;
963 faceList frontAndBackFaces;
965 if (dimensionOfGrid == 2)
967 const scalar extrusionFactor = 0.01;
969 boundBox box(max(points), min(points));
971 const scalar zOffset = extrusionFactor*box.mag();
973 // two-dimensional grid. Extrude in z-direction
974 Info<< "Grid is 2-D. Extruding in z-direction by: "
975 << 2*zOffset << endl;
977 pointField oldPoints = points;
979 const label pointOffset = oldPoints.size();
981 points.setSize(2*pointOffset);
983 label nNewPoints = 0;
985 // Note: In order for the owner-neighbour rules to be right, the
986 // points given by Fluent need to represent the FRONT plane of the
987 // geometry. Therefore, the extrusion will be in -z direction
989 forAll(oldPoints, pointI)
991 points[nNewPoints] = oldPoints[pointI];
993 points[nNewPoints].z() = zOffset;
998 forAll(oldPoints, pointI)
1000 points[nNewPoints] = oldPoints[pointI];
1002 points[nNewPoints].z() = -zOffset;
1007 // 2-D shape recognition
1008 Info<< "Creating shapes for 2-D cells"<< endl;
1010 // Set the number of empty faces
1011 frontAndBackFaces.setSize(2*nCells);
1013 forAll(fluentCellModelID, celli)
1015 switch (fluentCellModelID[celli])
1022 extrudedTriangleCellShape
1041 extrudedQuadCellShape
1057 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1058 << "unrecognised 2-D cell shape: "
1059 << fluentCellModelID[celli]
1060 << abort(FatalError);
1066 forAll(faces, faceI)
1069 if (faces[faceI].size() != 2)
1071 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1072 << "fluentMeshToFoam: a 2-D face defined with "
1073 << faces[faceI].size() << " points." << endl;
1076 labelList& newFace = faces[faceI];
1080 newFace[2] = newFace[1] + pointOffset;
1082 newFace[3] = newFace[0] + pointOffset;
1085 // Create new cells from 2-D shapes
1089 // 3-D shape recognition
1090 Info<< "Creating shapes for 3-D cells"<< endl;
1091 forAll(fluentCellModelID, celli)
1095 fluentCellModelID[celli] == 2 // tet
1096 || fluentCellModelID[celli] == 4 // hex
1097 || fluentCellModelID[celli] == 5 // pyramid
1098 || fluentCellModelID[celli] == 6 // prism
1111 fluentCellModelID[celli]
1117 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1118 << "unrecognised 3-D cell shape: "
1119 << fluentCellModelID[celli]
1120 << abort(FatalError);
1125 // boundary faces are oriented such that the owner is zero and the face
1126 // area vector points into the domain. Turn them round before making patches
1127 // for Foam compatibility
1129 forAll(faces, faceI)
1131 if (owner[faceI] == -1)
1134 labelList oldFace = faces[faceI];
1136 forAllReverse(oldFace, i)
1138 faces[faceI][oldFace.size() - i - 1] =
1145 //make patchless mesh before analysing boundaries
1147 faceListList patches(0);
1148 wordList patchNames(0);
1149 wordList patchTypes(0);
1150 word defaultFacesName = "defaultFaces";
1151 word defaultFacesType = emptyPolyPatch::typeName;
1152 wordList patchPhysicalTypes(0);
1156 points *= scaleFactor;
1158 Info<< "Building patch-less mesh..." << flush;
1164 polyMesh::defaultRegion,
1178 //dont write mesh yet, otherwise preservePatchTypes will be broken
1179 //and zones wont be written
1180 //checkmesh done after patch addition as well
1181 Info<< "done." << endl;
1184 Info<< endl << "Building boundary and internal patches." << endl;
1185 //adding patches after mesh construction allows topological checks
1186 //on whether a patch is internal or external, something fluent
1187 //doesnt seem to mind
1189 // Make boundary patches
1191 SLList<label>::iterator faceGroupZoneIDIter = faceGroupZoneID.begin();
1192 SLList<label>::iterator faceGroupStartIndexIter =
1193 faceGroupStartIndex.begin();
1194 SLList<label>::iterator faceGroupEndIndexIter = faceGroupEndIndex.begin();
1196 // Note. Not all groups of faces will be boundary patches.
1197 // Take care on construction
1199 //2D needs extra space for frontAndBack faces
1200 if (dimensionOfGrid == 2)
1202 patches.setSize(faceGroupZoneID.size()+1);
1203 patchNames.setSize(faceGroupZoneID.size()+1);
1204 patchTypes.setSize(faceGroupZoneID.size()+1);
1205 patchPhysicalTypes.setSize(faceGroupZoneID.size()+1);
1209 patches.setSize(faceGroupZoneID.size());
1210 patchNames.setSize(faceGroupZoneID.size());
1211 patchTypes.setSize(faceGroupZoneID.size());
1212 patchPhysicalTypes.setSize(faceGroupZoneID.size());
1217 //colate information for all patches (internal and external)
1221 faceGroupZoneIDIter != faceGroupZoneID.end()
1222 && faceGroupStartIndexIter != faceGroupStartIndex.end()
1223 && faceGroupEndIndexIter != faceGroupEndIndex.end();
1224 ++faceGroupZoneIDIter,
1225 ++faceGroupStartIndexIter,
1226 ++faceGroupEndIndexIter
1229 // get face type and name
1230 const word& curPatchType = patchTypeIDs[faceGroupZoneIDIter()];
1232 const word& curPatchName = patchNameIDs[faceGroupZoneIDIter()];
1234 Info<< "Creating patch " << nPatches
1235 << " for zone: " << faceGroupZoneIDIter()
1236 << " start: " << faceGroupStartIndexIter()
1237 << " end: " << faceGroupEndIndexIter()
1238 << " type: " << curPatchType << " name: " << curPatchName << endl;
1240 // make patch labels
1241 label faceLabel = faceGroupStartIndexIter() - 1;
1243 faceList patchFaces(faceGroupEndIndexIter() - faceLabel);
1245 forAll(patchFaces, faceI)
1249 faces[faceLabel].size() == 3
1250 || faces[faceLabel].size() == 4
1253 patchFaces[faceI] = face(faces[faceLabel]);
1258 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1259 << "unrecognised face shape with "
1260 << patchFaces[faceI].size() << " vertices"
1261 << abort(FatalError);
1265 //inlets and outlets
1268 curPatchType == "pressure"
1269 || curPatchType == "pressure-inlet"
1270 || curPatchType == "inlet-vent"
1271 || curPatchType == "intake-fan"
1272 || curPatchType == "pressure-outlet"
1273 || curPatchType == "exhaust-fan"
1274 || curPatchType == "outlet-vent"
1275 || curPatchType == "pressure-far-field"
1276 || curPatchType == "velocity-inlet"
1277 || curPatchType == "mass-flow-inlet"
1278 || curPatchType == "outflow"
1281 patches[nPatches] = patchFaces;
1282 patchTypes[nPatches] = polyPatch::typeName;
1283 patchNames[nPatches] = curPatchName;
1287 else if (curPatchType == "wall" ) //wall boundaries
1289 patches[nPatches] = patchFaces;
1290 patchTypes[nPatches] = wallPolyPatch::typeName;
1291 patchNames[nPatches] = curPatchName;
1297 curPatchType == "symmetry"
1298 || curPatchType == "axis"
1301 patches[nPatches] = patchFaces;
1302 patchTypes[nPatches] = symmetryPolyPatch::typeName;
1303 patchNames[nPatches] = curPatchName;
1309 curPatchType == "interior"
1310 || curPatchType == "interface"
1311 || curPatchType == "internal"
1312 || curPatchType == "solid"
1313 || curPatchType == "fan"
1314 || curPatchType == "radiator"
1315 || curPatchType == "porous-jump"
1316 ) //interior boundaries - will not be added as patches
1318 patches[nPatches] = patchFaces;
1319 patchTypes[nPatches] = "internal";
1320 patchNames[nPatches] = curPatchName;
1327 ) //unnamed face regions default to interior patches
1329 Info<< "Patch " << faceGroupZoneIDIter()
1330 << ": Faces are defined but "
1331 << "not created as a zone." << endl
1332 << "Null specification is only valid for internal faces."
1335 patches[nPatches] = patchFaces;
1336 patchTypes[nPatches] = "internal";
1337 patchNames[nPatches] = curPatchName;
1341 else //unknown face regions are not handled
1343 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1344 << "fluent patch type " << curPatchType << " not recognised."
1345 << abort(FatalError);
1349 //add front and back boundaries for 2D meshes
1350 if (dimensionOfGrid == 2)
1352 Info<< "Creating patch for front and back planes" << endl << endl;
1354 patches[nPatches] = frontAndBackFaces;
1355 patchTypes[nPatches] = emptyPolyPatch::typeName;
1356 patchNames[nPatches] = "frontAndBackPlanes";
1361 //Now have all patch information,
1362 //check whether each patch is internal or external
1363 //and add boundaries to mesh
1364 //also write face sets of all patches
1365 patches.setSize(nPatches);
1366 patchTypes.setSize(nPatches);
1367 patchNames.setSize(nPatches);
1371 const polyBoundaryMesh& oPatches = pShapeMesh.boundaryMesh();
1373 DynamicList<polyPatch*> newPatches(nPatches);
1375 // For every boundary face the old patch.
1376 labelList facePatchID(pShapeMesh.nFaces()-pShapeMesh.nInternalFaces(), -1);
1377 label cMeshFace = pShapeMesh.nInternalFaces();
1378 label nBoundaries = 0;
1381 forAll(patches, patchI)
1383 const faceList& bFaces = patches[patchI];
1385 label sz = bFaces.size();
1386 labelList meshFaces(sz,-1);
1389 //make face set and write (seperate from rest for clarity)
1390 //internal and external Fluent boundaries
1392 faceSet pFaceSet(pShapeMesh, patchNames[patchI], sz);
1396 const face& f = bFaces[j];
1397 label cMeshFace = findFace(pShapeMesh, f);
1398 meshFaces[j] = cMeshFace;
1399 pFaceSet.insert(cMeshFace);
1403 Info<< "Writing patch " << patchNames[patchI]
1404 << " of size " << sz << " to faceSet." << endl;
1410 //check if patch is internal
1411 //also check internal/external-ness of first patch face
1412 //internal faces cannot become foam boundaries
1413 //if a face is defined as internal but is actually external
1414 //it will be put in a default wall boundary
1415 //internal boundaries are simply ignored
1419 patchTypes[patchI] != "internal"
1420 && !pShapeMesh.isInternalFace(meshFaces[0])
1423 //first face is external and has valid non-internal type
1425 //check all faces for externalness just to be sure
1426 //and mark patch number to global list
1427 forAll(meshFaces, i)
1429 label faceI = meshFaces[i];
1431 if (pShapeMesh.isInternalFace(faceI))
1433 FatalErrorIn(args.executable())
1434 << "Face " << faceI << " on new patch "
1435 << patchNames[patchI]
1436 << " is not an external face of the mesh." << endl
1437 << exit(FatalError);
1440 if (facePatchID[faceI - pShapeMesh.nInternalFaces()]!= -1)
1442 FatalErrorIn(args.executable())
1443 << "Face " << faceI << " on new patch "
1444 << patchNames[patchI]
1445 << " has already been marked for repatching to"
1447 << facePatchID[faceI - pShapeMesh.nInternalFaces()]
1448 << exit(FatalError);
1450 facePatchID[faceI - pShapeMesh.nInternalFaces()] = nBoundaries;
1453 //add to boundary patch
1455 Info<< "Adding new patch " << patchNames[patchI]
1456 << " of type " << patchTypes[patchI]
1457 << " as patch " << nBoundaries << endl;
1459 // Add patch to new patch list
1477 Info<< "Patch " << patchNames[patchI]
1478 << " is internal to the mesh "
1479 << " and is not being added to the boundary."
1485 // Check for any remaining boundary faces
1486 // and add them to a default wall patch
1487 // this routine should generally not be invoked
1489 DynamicList<label> defaultBoundaryFaces(facePatchID.size());
1490 forAll(facePatchID, idI)
1492 if (facePatchID[idI] == -1)
1494 defaultBoundaryFaces.append(idI);
1495 facePatchID[idI] = nBoundaries;
1498 defaultBoundaryFaces.shrink();
1500 if (defaultBoundaryFaces.size())
1502 Warning << " fluent mesh has " << defaultBoundaryFaces.size()
1503 << " undefined boundary faces." << endl
1504 << " Adding undefined faces to new patch `default_wall`"
1507 // Add patch to new patch list
1513 wallPolyPatch::typeName,
1515 defaultBoundaryFaces.size(),
1522 cMeshFace += defaultBoundaryFaces.size();
1526 newPatches.shrink();
1528 // Use facePatchIDs map to reorder boundary faces into compact regions
1530 repatchPolyTopoChanger repatcher(pShapeMesh);
1532 // Add new list of patches
1533 repatcher.changePatches(newPatches);
1536 forAll(facePatchID, idI)
1538 label faceI = idI + pShapeMesh.nInternalFaces();
1540 repatcher.changePatchID(faceI, facePatchID[idI]);
1542 repatcher.repatch();
1545 // Set the precision of the points data to 10
1546 IOstream::defaultPrecision(10);
1550 // will write out cell zones and internal faces for those zones
1551 // note: zone boundary faces are not added to face zones
1552 // the names of boundaries bordering on cell zones are written to
1553 // a list containing the boundary name and cellzone it borders on
1554 // interior boundaries are handled via faceSets
1555 // cell zones will only be written if there is more than one
1557 if (writeZones && cellGroupZoneID.size() > 1)
1559 Info<< "Adding Zones" << endl;
1560 List<pointZone*> pz(0);
1562 label nrCellZones = cellGroupZoneID.size();
1563 List<cellZone*> cz(nrCellZones);
1565 // Make face zones for cell zones
1566 List<faceZone*> fz(nrCellZones);
1568 // List of patch names and the cellZone(s) they border
1569 // this is just an info file to make MRF easier to setup
1570 List<DynamicList<word> > boundaryZones
1572 pShapeMesh.boundaryMesh().size()
1575 const polyBoundaryMesh& bPatches = pShapeMesh.boundaryMesh();
1576 forAll(bPatches, pI)
1578 boundaryZones[pI].append(bPatches[pI].name());
1582 SLList<label>::iterator cg = cellGroupZoneID.begin();
1583 SLList<label>::iterator start = cellGroupStartIndex.begin();
1584 SLList<label>::iterator end = cellGroupEndIndex.begin();
1586 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1588 const word& name = patchNameIDs[cg()];
1589 const word& type = patchTypeIDs[cg()];
1591 Info<< "Writing cell zone: " << name
1592 << " of type " << type << " starting at " << start() - 1
1593 << " ending at " << end() - 1 << " to cellSet." << endl;
1595 labelList cls(end() - start() + 1);
1597 // Mark zone cells, used for finding faces
1598 boolList zoneCell(pShapeMesh.nCells(), false);
1600 // shift cell indizes by 1
1602 for (label celli = (start() - 1); celli < end(); celli++)
1605 zoneCell[celli] = true;
1609 cz[cnt] = new cellZone
1614 pShapeMesh.cellZones()
1617 DynamicList<label> zoneFaces(pShapeMesh.nFaces());
1618 forAll(pShapeMesh.faceNeighbour(), faceI)
1620 label nei = pShapeMesh.faceNeighbour()[faceI];
1621 label own = pShapeMesh.faceOwner()[faceI];
1624 if (zoneCell[nei] && zoneCell[own])
1626 zoneFaces.append(faceI);
1632 fz[cnt] = new faceZone
1636 boolList(zoneFaces.size(), false),
1638 pShapeMesh.faceZones()
1641 // Add cell zones to patch zone list
1642 forAll(bPatches, pI)
1644 const labelList& faceCells = bPatches[pI].faceCells();
1645 forAll(faceCells, fcI)
1647 if (zoneCell[faceCells[fcI] ])
1649 boundaryZones[pI].append(name);
1658 pShapeMesh.addZones(pz, fz, cz);
1660 forAll(bPatches, pI)
1662 boundaryZones[pI].shrink();
1667 runTime.path()/runTime.constant()
1668 /"polyMesh"/"boundaryAdjacentCellZones"
1671 OFstream boundaryCellZonesFile(bczf);
1672 forAll(boundaryZones, bzI)
1674 forAll(boundaryZones[bzI], bzII)
1676 boundaryCellZonesFile << boundaryZones[bzI][bzII] << " ";
1679 boundaryCellZonesFile << endl;
1683 Info<< endl << "Writing mesh..." << flush;
1685 Info<< " to " << pShapeMesh.instance()/pShapeMesh.meshDir()
1688 pShapeMesh.setInstance(pShapeMesh.instance());
1690 Info<< "done." << endl << endl;
1692 // Write cellSets for Fluent regions
1693 // allows easy post-processing
1694 // set and zone functionality will be integrated some time
1695 // soon negating the need for double output
1698 if (cellGroupZoneID.size() > 1)
1700 Info<< "Writing cell sets" << endl;
1702 SLList<label>::iterator cg = cellGroupZoneID.begin();
1703 SLList<label>::iterator start = cellGroupStartIndex.begin();
1704 SLList<label>::iterator end = cellGroupEndIndex.begin();
1706 // Note: cellGroupXXX are all Fluent indices (starting at 1)
1707 // so offset before using.
1709 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1711 const word& name=patchNameIDs[cg()];
1712 const word& type=patchTypeIDs[cg()];
1714 Info<< "Writing cell set: " << name
1715 << " of type " << type << " starting at " << start() - 1
1716 << " ending at " << end() - 1 << " to cellSet." << endl;
1718 cellSet internal(pShapeMesh, name, end() - start());
1720 // shift cell indizes by 1
1721 for (label celli = start() - 1; celli <= end() - 1; celli++)
1723 internal.insert(celli);
1731 Info<< "Only one cell group: no set written\n";
1735 Info<< "\nEnd\n" << endl;
1740 /* ------------------------------------------------------------------------- *\
1741 ------ End of fluentMeshToFoam.L
1742 \* ------------------------------------------------------------------------- */