1 /*--------------------------------*- C++ -*----------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 Converts a Fluent mesh to FOAM format
30 including multiple region and region boundary handling.
32 \*---------------------------------------------------------------------------*/
38 /* ------------------------------------------------------------------------- *\
39 ------ local definitions
40 \* ------------------------------------------------------------------------- */
44 #include "IStringStream.H"
46 #include "emptyPolyPatch.H"
47 #include "wallPolyPatch.H"
48 #include "symmetryPolyPatch.H"
49 #include "preservePatchTypes.H"
50 #include "cellShape.H"
53 #include "meshTools.H"
56 #include "readHexLabel.H"
57 #include "cellShapeRecognition.H"
58 #include "repatchPolyTopoChanger.H"
61 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
65 const scalar convertToMeters = 1.0;
67 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
70 label dimensionOfGrid = 0;
77 SLList<label> pointGroupZoneID;
78 SLList<label> pointGroupStartIndex;
79 SLList<label> pointGroupEndIndex;
84 labelList neighbour(0);
85 SLList<label> faceGroupZoneID;
86 SLList<label> faceGroupStartIndex;
87 SLList<label> faceGroupEndIndex;
89 labelList fluentCellModelID(0);
90 SLList<label> cellGroupZoneID;
91 SLList<label> cellGroupStartIndex;
92 SLList<label> cellGroupEndIndex;
93 SLList<label> cellGroupType;
95 // number of zones adjusted at run-time if necessary
96 label maxZoneID = 100;
97 label zoneIDBuffer = 10;
99 wordList patchTypeIDs(maxZoneID);
100 wordList patchNameIDs(maxZoneID);
102 // Dummy yywrap to keep yylex happy at compile time.
103 // It is called by yylex but is not used as the mechanism to change file.
105 #if YY_FLEX_SUBMINOR_VERSION < 34
106 extern "C" int yywrap()
108 int yyFlexLexer::yywrap()
118 some_space {one_space}+
120 spaceNl ({space}|\n|\r)*
126 hexDigit [[:xdigit:]]
134 schemeSpecialInitial [!$%&*/:<=>?~_^#.]
135 schemeSpecialSubsequent [.+-]
136 schemeSymbol (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
139 identifier {alpha}({alpha}|{digit})*
141 label [1-9]{decDigit}*
145 word ({alpha}|{digit}|{dotColonDash})*
147 exponent_part [eE][-+]?{digit}+
148 fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
150 double ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
156 labelListElement {space}{zeroLabel}
157 hexLabelListElement {space}{hexLabel}
158 scalarListElement {space}{double}
159 schemeSymbolListElement {space}{schemeSymbol}
160 labelList ({labelListElement}+{space})
161 hexLabelList ({hexLabelListElement}+{space})
162 scalarList ({scalarListElement}+{space})
163 schemeSymbolList ({schemeSymbolListElement}+{space})
166 text ({space}({word}*{space})*)
168 dateDDMMYYYY ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
169 dateDDMonYYYY ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
170 time ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
172 versionNumber ({digit}|".")*
174 comment {spaceNl}"(0"{space}
175 header {spaceNl}"(1"{space}
176 dimension {spaceNl}"(2"{space}
177 point {spaceNl}"(10"{space}
178 fluentFace {spaceNl}"(13"{space}
179 cell {spaceNl}"(12"{space}
180 zoneVariant1 {spaceNl}"(39"{space}
181 zoneVariant2 {spaceNl}"(45"{space}
183 unknownPeriodicFace {spaceNl}"(17"{space}
184 periodicFace {spaceNl}"(18"{space}
185 cellTree {spaceNl}"(58"{space}
186 faceTree {spaceNl}"(59"{space}
187 faceParents {spaceNl}"(61"{space}
189 endOfSection {space}")"{space}
193 /* ------------------------------------------------------------------------- *\
194 ----- Exclusive start states -----
195 \* ------------------------------------------------------------------------- */
200 %x embeddedCommentState
205 %x readNumberOfPoints
206 %x readPointGroupData
236 %x embeddedUnknownBlock
241 label pointGroupNumberOfComponents = 3;
242 label pointI = 0; // index used for reading points
245 label faceGroupElementType = -1;
249 label cellGroupElementType = -1;
254 /* ------------------------------------------------------------------------- *\
255 ------ Start Lexing ------
256 \* ------------------------------------------------------------------------- */
258 /* ------ Reading control header ------ */
261 yy_push_state(readComment);
265 <readComment>{quote}{text}{quote} {
269 <readComment>{spaceNl}{endOfSection} {
277 <readHeader>{quote}{text}{quote} {
278 Info<< "Reading header: " << YYText() << endl;
283 BEGIN(readDimension);
286 <readDimension>{space}{label}{space} {
287 IStringStream dimOfGridStream(YYText());
289 dimensionOfGrid = readLabel(dimOfGridStream);
291 Info<< "Dimension of grid: " << dimensionOfGrid << endl;
296 BEGIN(readPointHeader);
299 <readPointHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
300 BEGIN(readNumberOfPoints);
303 <readNumberOfPoints>{space}{hexLabel}{space}{labelList} {
305 IStringStream numberOfPointsStream(YYText());
307 nPoints = readHexLabel(numberOfPointsStream);
309 Info<< "Number of points: " << nPoints << endl;
311 // set the size of the points list
312 points.setSize(nPoints);
314 // meaningless type skipped
315 readLabel(numberOfPointsStream);
317 // this dimension of grid may be checked against global dimension
318 if (numberOfPointsStream)
320 // check dimension of grid
321 readLabel(numberOfPointsStream);
329 <readPointHeader>{spaceNl}{lbrac} {
330 BEGIN(readPointGroupData);
333 <readPointGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
334 IStringStream pointGroupDataStream(YYText());
336 // read point zone-ID, start and end-label
337 // the indices will be used for checking later.
338 pointGroupZoneID.append(readHexLabel(pointGroupDataStream));
340 pointGroupStartIndex.append(readHexLabel(pointGroupDataStream));
342 pointGroupEndIndex.append(readHexLabel(pointGroupDataStream));
344 // point group type skipped
345 readHexLabel(pointGroupDataStream);
347 // In FOAM, indices start from zero - adjust
348 pointI = pointGroupStartIndex.last() - 1;
350 // reset number of components to default
351 pointGroupNumberOfComponents = 3;
353 // read number of components in the vector
354 if (pointGroupDataStream)
356 pointGroupNumberOfComponents = readLabel(pointGroupDataStream);
360 <readNumberOfPoints,readPointGroupData>{endOfSection} {
361 BEGIN(readPointData);
364 <readPointData>{spaceNl}{lbrac} {
366 Info<< "Reading points" << endl;
368 if (pointGroupNumberOfComponents == 2)
370 yy_push_state(readPoints2D);
374 yy_push_state(readPoints3D);
378 <readPoints2D>{spaceNl}{scalarList} {
380 IStringStream vertexXyzStream(YYText());
382 // Note: coordinates must be read one at the time.
383 scalar x = readScalar(vertexXyzStream);
384 scalar y = readScalar(vertexXyzStream);
386 points[pointI] = point(x, y, 0);
390 <readPoints3D>{spaceNl}{scalarList} {
392 IStringStream vertexXyzStream(YYText());
394 // Note: coordinates must be read one at the time.
395 scalar x = readScalar(vertexXyzStream);
396 scalar y = readScalar(vertexXyzStream);
397 scalar z = readScalar(vertexXyzStream);
399 points[pointI] = convertToMeters*point(x, y, z);
403 <readPoints2D,readPoints3D>{spaceNl}{endOfSection} {
405 // check read of points
406 if (pointI != pointGroupEndIndex.last())
408 Info<< "problem with reading points: "
409 << "start index: " << pointGroupStartIndex.last()
410 << " end index: " << pointGroupEndIndex.last()
411 << " last points read: " << pointI << endl;
419 BEGIN(readFaceHeader);
422 <readFaceHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
423 BEGIN(readNumberOfFaces);
426 <readNumberOfFaces>{space}{hexLabel}{space}{labelListElement}+ {
428 IStringStream numberOfFacesStream(YYText());
430 nFaces = readHexLabel(numberOfFacesStream);
432 Info<< "number of faces: " << nFaces << endl;
434 faces.setSize(nFaces);
435 owner.setSize(nFaces);
436 neighbour.setSize(nFaces);
438 // Meaningless type and element type not read
441 <readFaceHeader>{spaceNl}{lbrac} {
442 BEGIN(readFaceGroupData);
445 <readFaceGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
447 IStringStream faceGroupDataStream(YYText());
449 // read fluentFace zone-ID, start and end-label
450 faceGroupZoneID.append(readHexLabel(faceGroupDataStream));
452 // the indices will be used for checking later.
453 faceGroupStartIndex.append(readHexLabel(faceGroupDataStream));
455 faceGroupEndIndex.append(readHexLabel(faceGroupDataStream));
458 readHexLabel(faceGroupDataStream);
460 faceGroupElementType = readHexLabel(faceGroupDataStream);
462 // In FOAM, indices start from zero - adjust
463 faceI = faceGroupStartIndex.last() - 1;
466 <readNumberOfFaces,readFaceGroupData>{spaceNl}{endOfSection} {
470 <readFaceData>{spaceNl}{lbrac} {
472 if (faceGroupElementType == 0)
474 Info<< "Reading mixed faces" << endl;
475 yy_push_state(readFacesMixed);
479 Info<< "Reading uniform faces" << endl;
480 yy_push_state(readFacesUniform);
484 <readFacesMixed>{spaceNl}{hexLabelList} {
486 IStringStream mixedFaceStream(YYText());
488 face& curFaceLabels = faces[faceI];
490 // set size of label list
491 curFaceLabels.setSize(readLabel(mixedFaceStream));
493 forAll (curFaceLabels, i)
495 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
498 // read neighbour and owner. Neighbour comes first
499 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
500 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
504 <readFacesUniform>{spaceNl}{hexLabelList} {
506 IStringStream mixedFaceStream(YYText());
508 face& curFaceLabels = faces[faceI];
510 // set size of label list. This is OK because in Fluent the type
511 // for edge is 2, for triangle is 3 and for quad is 4
512 curFaceLabels.setSize(faceGroupElementType);
514 forAll (curFaceLabels, i)
516 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
519 // read neighbour and owner. Neighbour comes first
520 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
521 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
525 <readFacesMixed,readFacesUniform>{spaceNl}{endOfSection} {
527 // check read of fluentFaces
528 if (faceI != faceGroupEndIndex.last())
530 Info<< "problem with reading fluentFaces: "
531 << "start index: " << faceGroupStartIndex.last()
532 << " end index: " << faceGroupEndIndex.last()
533 << " last fluentFaces read: " << faceI << endl;
541 BEGIN(readCellHeader);
544 <readCellHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
545 BEGIN(readNumberOfCells);
548 <readNumberOfCells>{space}{hexLabel}{space}{labelListElement}+ {
550 IStringStream numberOfCellsStream(YYText());
552 nCells = readHexLabel(numberOfCellsStream);
554 Info<< "Number of cells: " << nCells << endl;
556 fluentCellModelID.setSize(nCells);
558 // Meaningless type and element type not read
561 <readCellHeader>{spaceNl}{lbrac} {
562 BEGIN(readCellGroupData);
565 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
566 // Warning. This entry must be above the next one because of the lexing
567 // rules. It is introduced to deal with the problem of reading
568 // non-standard cell definition from Tgrid, which misses the type label.
570 Info<< "Tgrid syntax problem: " << YYText() << endl;
571 IStringStream cellGroupDataStream(YYText());
573 // read cell zone-ID, start and end-label
574 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
576 // the indices will be used for checking later.
577 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
579 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
581 cellGroupType.append(readHexLabel(cellGroupDataStream));
583 Info<< "cellGroupZoneID:" << cellGroupZoneID.last()
585 Info<< "cellGroupStartIndex:" << cellGroupStartIndex.last()
587 Info<< "cellGroupEndIndex:" << cellGroupEndIndex.last()
589 Info<< "cellGroupType:" << cellGroupType.last()
593 // Note. Potentially skip cell set if type is zero.
594 // This entry does not exist in Tgrid files.
595 if (dimensionOfGrid == 2)
597 // Tgrid creating triangles
598 cellGroupElementType = 1;
602 cellGroupElementType = 2;
605 // In FOAM, indices start from zero - adjust
606 celli = cellGroupStartIndex.last() - 1;
608 if (cellGroupElementType != 0)
610 label lastIndex = cellGroupEndIndex.last();
612 for (; celli < lastIndex; celli++)
614 fluentCellModelID[celli] = cellGroupElementType;
619 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
620 // Warning. See above
622 Info<< "Other readCellGroupData: " << YYText() << endl;
625 IStringStream cellGroupDataStream(YYText());
627 // read cell zone-ID, start and end-label
628 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
630 // the indices will be used for checking later.
631 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
633 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
635 cellGroupType.append(readHexLabel(cellGroupDataStream));
637 // Note. Potentially skip cell set if type is zero.
639 cellGroupElementType = readHexLabel(cellGroupDataStream);
641 // In FOAM, indices start from zero - adjust
642 celli = cellGroupStartIndex.last() - 1;
644 if (cellGroupElementType != 0)
646 Info<< "Reading uniform cells" << endl;
647 label lastIndex = cellGroupEndIndex.last();
649 for (; celli < lastIndex; celli++)
651 fluentCellModelID[celli] = cellGroupElementType;
656 <readNumberOfCells,readCellGroupData>{endOfSection} {
660 <readCellData>{spaceNl}{lbrac} {
661 Info<< "Reading mixed cells" << endl;
662 yy_push_state(readCellsMixed);
665 <readCellsMixed>{spaceNl}{labelList} {
667 IStringStream fluentCellModelIDStream(YYText());
670 while (fluentCellModelIDStream.read(celliD))
672 fluentCellModelID[celli] = celliD;
677 <readCellsMixed>{spaceNl}{endOfSection} {
679 // check read of cells
680 if (celli != cellGroupEndIndex.last())
682 Info<< "problem with reading cells: "
683 << "start index: " << cellGroupStartIndex.last()
684 << " end index: " << cellGroupEndIndex.last()
685 << " last cells read: " << celli << endl;
694 BEGIN(readZoneHeader);
698 BEGIN(readZoneHeader);
701 <readZoneHeader>{spaceNl}{lbrac} {
702 BEGIN(readZoneGroupData);
705 <readZoneGroupData>{space}{label}{space}{word}{space}{word} {
707 IStringStream zoneDataStream(YYText());
709 // cell zone-ID not in hexadecimal!!! Inconsistency
710 label zoneID(readLabel(zoneDataStream));
712 if (zoneID > maxZoneID - 1)
714 // resize the container
715 maxZoneID = zoneID + zoneIDBuffer;
717 patchTypeIDs.setSize(maxZoneID);
718 patchNameIDs.setSize(maxZoneID);
721 zoneDataStream >> patchTypeIDs[zoneID];
722 zoneDataStream >> patchNameIDs[zoneID];
724 Info<< "Read zone1:" << zoneID
725 << " name:" << patchNameIDs[zoneID]
726 << " patchTypeID:" << patchTypeIDs[zoneID]
730 <readZoneGroupData>{space}{label}{space}{word}{space}{word}{space}{label} {
731 // Fluent manual inconsistency, version 6.1.22
732 IStringStream zoneDataStream(YYText());
734 // cell zone-ID not in hexadecimal!!! Inconsistency
735 label zoneID(readLabel(zoneDataStream));
737 if (zoneID > maxZoneID - 1)
739 // resize the container
740 maxZoneID = zoneID + zoneIDBuffer;
742 patchTypeIDs.setSize(maxZoneID);
743 patchNameIDs.setSize(maxZoneID);
746 zoneDataStream >> patchTypeIDs[zoneID];
747 zoneDataStream >> patchNameIDs[zoneID];
749 Info<< "Read zone2:" << zoneID
750 << " name:" << patchNameIDs[zoneID]
751 << " patchTypeID:" << patchTypeIDs[zoneID]
755 <readZoneGroupData>{endOfSection} {
759 <readZoneData>{spaceNl}{lbrac} {
760 Info<< "Reading zone data" << endl;
761 yy_push_state(readZoneBlock);
764 <readZoneBlock>{spaceNl}{schemeSymbolList} {
767 <readZoneBlock>{lbrac} {
768 Info<< "Found unknown block in zone:" << YYText() << endl;
769 yy_push_state(unknownBlock);
772 <readZoneBlock>{endOfSection} {
778 /* ------ Reading end of section and others ------ */
780 <readHeader,readDimension,readPointData,readFaceData,readCellData,readZoneData>{spaceNl}{endOfSection} {
784 /* ------ Reading unknown type or non-standard comment ------ */
788 Info<< "Found unknown block:" << YYText() << endl;
789 yy_push_state(unknownBlock);
792 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbol} {
795 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{lbrac} {
796 Info<< "Embedded blocks in comment or unknown:" << YYText() << endl;
797 yy_push_state(embeddedUnknownBlock);
801 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{endOfSection} {
802 Info<< "Found end of section in unknown:" << YYText() << endl;
806 <unknownBlock,embeddedUnknownBlock>{spaceNl}{labelList} {
809 <unknownBlock,embeddedUnknownBlock>{spaceNl}{hexLabelList} {
812 <unknownBlock,embeddedUnknownBlock>{spaceNl}{scalarList} {
815 <unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbolList} {
818 <unknownBlock,embeddedUnknownBlock>{spaceNl}{text} {
822 /* ------ Ignore remaining space and \n s. Any other characters are errors. */
824 <readPoints2D,readPoints3D>.|\n {
825 Info<< "ERROR! Do not understand characters: " << YYText() << endl;
830 /* ------ On EOF return to previous file, if none exists terminate. ------ */
838 #include "fileName.H"
841 // Find label of face.
842 label findFace(const primitiveMesh& mesh, const face& f)
844 // Get faces using zeroth vertex of face.
845 const labelList& pFaces = mesh.pointFaces()[f[0] ];
849 label faceI = pFaces[i];
851 if (f == mesh.faces()[faceI])
857 // Didn't find face. Do what?
858 FatalErrorIn("findFace(const primitiveMesh&, const face&)")
859 << "Problem : cannot find a single face in the mesh which uses"
860 << " vertices " << f << exit(FatalError);
866 int main(int argc, char *argv[])
868 argList::noParallel();
869 argList::validArgs.append("Fluent mesh file");
870 argList::validOptions.insert("scale", "scale factor");
871 argList::validOptions.insert("writeSets", "");
872 argList::validOptions.insert("writeZones", "");
874 argList args(argc, argv);
881 scalar scaleFactor = 1.0;
882 args.optionReadIfPresent("scale", scaleFactor);
884 bool writeSets = args.optionFound("writeSets");
885 bool writeZones = args.optionFound("writeZones");
887 # include "createTime.H"
889 fileName fluentFile(args.additionalArgs()[0]);
890 std::ifstream fluentStream(fluentFile.c_str());
894 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
896 << ": file " << fluentFile << " not found"
900 yyFlexLexer lexer(&fluentStream);
901 while(lexer.yylex() != 0)
904 Info<< "\n\nFINISHED LEXING\n\n\n";
905 // Lookup table giving number of vertices given a fluent cell type ID
906 // Currently not used.
907 // label fluentModelNVertices[7] = {-1, 3, 4, 4, 8, 5, 6};
909 // Lookup table giving number of vertices given a fluent cell type ID
910 label fluentModelNFaces[7] = {-1, 3, 4, 4, 6, 5, 5};
912 // Make a list of cell faces to be filled in for owner and neighbour
914 labelListList cellFaces(nCells);
916 labelList nFacesInCell(nCells, 0);
918 forAll (cellFaces, celli)
920 cellFaces[celli].setSize(fluentModelNFaces[fluentCellModelID[celli] ]);
923 // fill in owner and neighbour
925 forAll (owner, faceI)
927 if (owner[faceI] > -1)
929 label curCell = owner[faceI];
930 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
932 nFacesInCell[curCell]++;
936 forAll (neighbour, faceI)
938 if (neighbour[faceI] > -1)
940 label curCell = neighbour[faceI];
941 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
943 nFacesInCell[curCell]++;
947 // Construct shapes from face lists
948 cellShapeList cellShapes(nCells);
950 // Extrude 2-D mesh into 3-D
952 Info<< "dimension of grid: " << dimensionOfGrid << endl;
953 faceList frontAndBackFaces;
955 if (dimensionOfGrid == 2)
957 const scalar extrusionFactor = 0.01;
959 boundBox box(max(points), min(points));
961 const scalar zOffset = extrusionFactor*box.mag();
963 // two-dimensional grid. Extrude in z-direction
964 Info<< "Grid is 2-D. Extruding in z-direction by: "
965 << 2*zOffset << endl;
967 pointField oldPoints = points;
969 const label pointOffset = oldPoints.size();
971 points.setSize(2*pointOffset);
973 label nNewPoints = 0;
975 // Note: In order for the owner-neighbour rules to be right, the
976 // points given by Fluent need to represent the FRONT plane of the
977 // geometry. Therefore, the extrusion will be in -z direction
979 forAll (oldPoints, pointI)
981 points[nNewPoints] = oldPoints[pointI];
983 points[nNewPoints].z() = zOffset;
988 forAll (oldPoints, pointI)
990 points[nNewPoints] = oldPoints[pointI];
992 points[nNewPoints].z() = -zOffset;
997 // 2-D shape recognition
998 Info<< "Creating shapes for 2-D cells"<< endl;
1000 // Set the number of empty faces
1001 frontAndBackFaces.setSize(2*nCells);
1003 forAll (fluentCellModelID, celli)
1005 switch (fluentCellModelID[celli])
1012 extrudedTriangleCellShape
1031 extrudedQuadCellShape
1047 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1048 << "unrecognised 2-D cell shape: "
1049 << fluentCellModelID[celli]
1050 << abort(FatalError);
1056 forAll (faces, faceI)
1059 if (faces[faceI].size() != 2)
1061 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1062 << "fluentMeshToFoam: a 2-D face defined with "
1063 << faces[faceI].size() << " points." << endl;
1066 labelList& newFace = faces[faceI];
1070 newFace[2] = newFace[1] + pointOffset;
1072 newFace[3] = newFace[0] + pointOffset;
1075 // Create new cells from 2-D shapes
1079 // 3-D shape recognition
1080 Info<< "Creating shapes for 3-D cells"<< endl;
1081 forAll (fluentCellModelID, celli)
1085 fluentCellModelID[celli] == 2 // tet
1086 || fluentCellModelID[celli] == 4 // hex
1087 || fluentCellModelID[celli] == 5 // pyramid
1088 || fluentCellModelID[celli] == 6 // prism
1101 fluentCellModelID[celli]
1107 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1108 << "unrecognised 3-D cell shape: "
1109 << fluentCellModelID[celli]
1110 << abort(FatalError);
1115 // boundary faces are oriented such that the owner is zero and the face
1116 // area vector points into the domain. Turn them round before making patches
1117 // for Foam compatibility
1119 forAll (faces, faceI)
1121 if (owner[faceI] == -1)
1124 labelList oldFace = faces[faceI];
1126 forAllReverse(oldFace, i)
1128 faces[faceI][oldFace.size() - i - 1] =
1135 //make patchless mesh before analysing boundaries
1137 faceListList patches(0);
1138 wordList patchNames(0);
1139 wordList patchTypes(0);
1140 word defaultFacesName = "defaultFaces";
1141 word defaultFacesType = emptyPolyPatch::typeName;
1142 wordList patchPhysicalTypes(0);
1146 points *= scaleFactor;
1148 Info<< "Building patch-less mesh..." << flush;
1154 polyMesh::defaultRegion,
1168 //dont write mesh yet, otherwise preservePatchTypes will be broken
1169 //and zones wont be written
1170 //checkmesh done after patch addition as well
1171 Info<< "done." << endl;
1174 Info<< endl << "Building boundary and internal patches." << endl;
1175 //adding patches after mesh construction allows topological checks
1176 //on whether a patch is internal or external, something fluent
1177 //doesnt seem to mind
1179 // Make boundary patches
1181 SLList<label>::iterator faceGroupZoneIDIter = faceGroupZoneID.begin();
1182 SLList<label>::iterator faceGroupStartIndexIter =
1183 faceGroupStartIndex.begin();
1184 SLList<label>::iterator faceGroupEndIndexIter = faceGroupEndIndex.begin();
1186 // Note. Not all groups of faces will be boundary patches.
1187 // Take care on construction
1189 //2D needs extra space for frontAndBack faces
1190 if (dimensionOfGrid == 2)
1192 patches.setSize(faceGroupZoneID.size()+1);
1193 patchNames.setSize(faceGroupZoneID.size()+1);
1194 patchTypes.setSize(faceGroupZoneID.size()+1);
1195 patchPhysicalTypes.setSize(faceGroupZoneID.size()+1);
1199 patches.setSize(faceGroupZoneID.size());
1200 patchNames.setSize(faceGroupZoneID.size());
1201 patchTypes.setSize(faceGroupZoneID.size());
1202 patchPhysicalTypes.setSize(faceGroupZoneID.size());
1207 //colate information for all patches (internal and external)
1211 faceGroupZoneIDIter != faceGroupZoneID.end()
1212 && faceGroupStartIndexIter != faceGroupStartIndex.end()
1213 && faceGroupEndIndexIter != faceGroupEndIndex.end();
1214 ++faceGroupZoneIDIter,
1215 ++faceGroupStartIndexIter,
1216 ++faceGroupEndIndexIter
1219 // get face type and name
1220 const word& curPatchType = patchTypeIDs[faceGroupZoneIDIter()];
1222 const word& curPatchName = patchNameIDs[faceGroupZoneIDIter()];
1224 Info<< "Creating patch " << nPatches
1225 << " for zone: " << faceGroupZoneIDIter()
1226 << " start: " << faceGroupStartIndexIter()
1227 << " end: " << faceGroupEndIndexIter()
1228 << " type: " << curPatchType << " name: " << curPatchName << endl;
1230 // make patch labels
1231 label faceLabel = faceGroupStartIndexIter() - 1;
1233 faceList patchFaces(faceGroupEndIndexIter() - faceLabel);
1235 forAll (patchFaces, faceI)
1239 faces[faceLabel].size() == 3
1240 || faces[faceLabel].size() == 4
1243 patchFaces[faceI] = face(faces[faceLabel]);
1248 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1249 << "unrecognised face shape with "
1250 << patchFaces[faceI].size() << " vertices"
1251 << abort(FatalError);
1255 //inlets and outlets
1258 curPatchType == "pressure"
1259 || curPatchType == "pressure-inlet"
1260 || curPatchType == "inlet-vent"
1261 || curPatchType == "intake-fan"
1262 || curPatchType == "pressure-outlet"
1263 || curPatchType == "exhaust-fan"
1264 || curPatchType == "outlet-vent"
1265 || curPatchType == "pressure-far-field"
1266 || curPatchType == "velocity-inlet"
1267 || curPatchType == "mass-flow-inlet"
1268 || curPatchType == "outflow"
1271 patches[nPatches] = patchFaces;
1272 patchTypes[nPatches] = polyPatch::typeName;
1273 patchNames[nPatches] = curPatchName;
1277 else if (curPatchType == "wall" ) //wall boundaries
1279 patches[nPatches] = patchFaces;
1280 patchTypes[nPatches] = wallPolyPatch::typeName;
1281 patchNames[nPatches] = curPatchName;
1287 curPatchType == "symmetry"
1288 || curPatchType == "axis"
1291 patches[nPatches] = patchFaces;
1292 patchTypes[nPatches] = symmetryPolyPatch::typeName;
1293 patchNames[nPatches] = curPatchName;
1299 curPatchType == "interior"
1300 || curPatchType == "interface"
1301 || curPatchType == "internal"
1302 || curPatchType == "solid"
1303 || curPatchType == "fan"
1304 || curPatchType == "radiator"
1305 || curPatchType == "porous-jump"
1306 ) //interior boundaries - will not be added as patches
1308 patches[nPatches] = patchFaces;
1309 patchTypes[nPatches] = "internal";
1310 patchNames[nPatches] = curPatchName;
1317 ) //unnamed face regions default to interior patches
1319 Info<< "Patch " << faceGroupZoneIDIter()
1320 << ": Faces are defined but "
1321 << "not created as a zone." << endl
1322 << "Null specification is only valid for internal faces."
1325 patches[nPatches] = patchFaces;
1326 patchTypes[nPatches] = "internal";
1327 patchNames[nPatches] = curPatchName;
1331 else //unknown face regions are not handled
1333 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1334 << "fluent patch type " << curPatchType << " not recognised."
1335 << abort(FatalError);
1339 //add front and back boundaries for 2D meshes
1340 if (dimensionOfGrid == 2)
1342 Info<< "Creating patch for front and back planes" << endl << endl;
1344 patches[nPatches] = frontAndBackFaces;
1345 patchTypes[nPatches] = emptyPolyPatch::typeName;
1346 patchNames[nPatches] = "frontAndBackPlanes";
1351 //Now have all patch information,
1352 //check whether each patch is internal or external
1353 //and add boundaries to mesh
1354 //also write face sets of all patches
1355 patches.setSize(nPatches);
1356 patchTypes.setSize(nPatches);
1357 patchNames.setSize(nPatches);
1361 const polyBoundaryMesh& oPatches = pShapeMesh.boundaryMesh();
1363 DynamicList<polyPatch*> newPatches(nPatches);
1365 // For every boundary face the old patch.
1366 labelList facePatchID(pShapeMesh.nFaces()-pShapeMesh.nInternalFaces(), -1);
1367 label cMeshFace = pShapeMesh.nInternalFaces();
1368 label nBoundaries = 0;
1371 forAll(patches, patchI)
1373 const faceList& bFaces = patches[patchI];
1375 label sz = bFaces.size();
1376 labelList meshFaces(sz,-1);
1379 //make face set and write (seperate from rest for clarity)
1380 //internal and external Fluent boundaries
1382 faceSet pFaceSet(pShapeMesh, patchNames[patchI], sz);
1386 const face& f = bFaces[j];
1387 label cMeshFace = findFace(pShapeMesh, f);
1388 meshFaces[j] = cMeshFace;
1389 pFaceSet.insert(cMeshFace);
1393 Info<< "Writing patch " << patchNames[patchI]
1394 << " of size " << sz << " to faceSet." << endl;
1400 //check if patch is internal
1401 //also check internal/external-ness of first patch face
1402 //internal faces cannot become foam boundaries
1403 //if a face is defined as internal but is actually external
1404 //it will be put in a default wall boundary
1405 //internal boundaries are simply ignored
1407 if(patchTypes[patchI] != "internal" && !pShapeMesh.isInternalFace(meshFaces[0]))
1409 //first face is external and has valid non-internal type
1411 //check all faces for externalness just to be sure
1412 //and mark patch number to global list
1413 forAll(meshFaces, i)
1415 label faceI = meshFaces[i];
1417 if (pShapeMesh.isInternalFace(faceI))
1419 FatalErrorIn(args.executable())
1420 << "Face " << faceI << " on new patch "
1421 << patchNames[patchI]
1422 << " is not an external face of the mesh." << endl
1423 << exit(FatalError);
1426 if(facePatchID[faceI - pShapeMesh.nInternalFaces()]!= -1)
1428 FatalErrorIn(args.executable())
1429 << "Face " << faceI << " on new patch "
1430 << patchNames[patchI]
1431 << " has already been marked for repatching to"
1433 << facePatchID[faceI - pShapeMesh.nInternalFaces()]
1434 << exit(FatalError);
1436 facePatchID[faceI - pShapeMesh.nInternalFaces()] = nBoundaries;
1439 //add to boundary patch
1441 Info<< "Adding new patch " << patchNames[patchI]
1442 << " of type " << patchTypes[patchI]
1443 << " as patch " << nBoundaries << endl;
1445 // Add patch to new patch list
1463 Info<< "Patch " << patchNames[patchI]
1464 << " is internal to the mesh "
1465 << " and is not being added to the boundary."
1471 // Check for any remaining boundary faces
1472 // and add them to a default wall patch
1473 // this routine should generally not be invoked
1475 DynamicList<label> defaultBoundaryFaces(facePatchID.size());
1476 forAll(facePatchID, idI)
1478 if(facePatchID[idI] == -1)
1480 defaultBoundaryFaces.append(idI);
1481 facePatchID[idI] = nBoundaries;
1484 defaultBoundaryFaces.shrink();
1486 if (defaultBoundaryFaces.size())
1488 Warning << " fluent mesh has " << defaultBoundaryFaces.size()
1489 << " undefined boundary faces." << endl
1490 << " Adding undefined faces to new patch `default_wall`"
1493 // Add patch to new patch list
1499 wallPolyPatch::typeName,
1501 defaultBoundaryFaces.size(),
1508 cMeshFace += defaultBoundaryFaces.size();
1512 newPatches.shrink();
1514 // Use facePatchIDs map to reorder boundary faces into compact regions
1516 repatchPolyTopoChanger repatcher(pShapeMesh);
1518 // Add new list of patches
1519 repatcher.changePatches(newPatches);
1522 forAll(facePatchID, idI)
1524 label faceI = idI + pShapeMesh.nInternalFaces();
1526 repatcher.changePatchID(faceI, facePatchID[idI]);
1528 repatcher.repatch();
1534 polyMesh::defaultRegion,
1542 // Set the precision of the points data to 10
1543 IOstream::defaultPrecision(10);
1547 // will write out cell zones and internal faces for those zones
1548 // note: zone boundary faces are not added to face zones
1549 // the names of boundaries bordering on cell zones are written to
1550 // a list containing the boundary name and cellzone it borders on
1551 // interior boundaries are handled via faceSets
1552 // cell zones will only be written if there is more than one
1554 if (writeZones && cellGroupZoneID.size()>1)
1556 Info<< "Adding Zones" << endl;
1557 List<pointZone*> pz(0);
1559 label nrCellZones = cellGroupZoneID.size();
1560 List<cellZone*> cz(nrCellZones);
1562 // Make face zones for cell zones
1563 List<faceZone*> fz(nrCellZones);
1565 // List of patch names and the cellZone(s) they border
1566 // this is just an info file to make MRF easier to setup
1567 List<DynamicList<word> > boundaryZones
1569 pShapeMesh.boundaryMesh().size()
1572 const polyBoundaryMesh& bPatches = pShapeMesh.boundaryMesh();
1573 forAll(bPatches, pI)
1575 boundaryZones[pI].append(bPatches[pI].name());
1579 SLList<label>::iterator cg = cellGroupZoneID.begin();
1580 SLList<label>::iterator start = cellGroupStartIndex.begin();
1581 SLList<label>::iterator end = cellGroupEndIndex.begin();
1583 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1585 const word& name = patchNameIDs[cg()];
1586 const word& type = patchTypeIDs[cg()];
1588 Info<< "Writing cell zone: " << name
1589 << " of type " << type << " starting at " << start() - 1
1590 << " ending at " << end() - 1 << " to cellSet." << endl;
1592 labelList cls(end() - start() + 1);
1594 // Mark zone cells, used for finding faces
1595 boolList zoneCell(pShapeMesh.nCells(), false);
1597 // shift cell indizes by 1
1599 for (label celli = (start() - 1); celli < end(); celli++)
1602 zoneCell[celli] = true;
1606 cz[cnt] = new cellZone
1611 pShapeMesh.cellZones()
1614 DynamicList<label> zoneFaces(pShapeMesh.nFaces());
1615 forAll(pShapeMesh.faceNeighbour(), faceI)
1617 label nei = pShapeMesh.faceNeighbour()[faceI];
1618 label own = pShapeMesh.faceOwner()[faceI];
1621 if(zoneCell[nei] && zoneCell[own])
1623 zoneFaces.append(faceI);
1629 fz[cnt] = new faceZone
1633 boolList(zoneFaces.size(), false),
1635 pShapeMesh.faceZones()
1638 // Add cell zones to patch zone list
1639 forAll(bPatches, pI)
1641 const labelList& faceCells = bPatches[pI].faceCells();
1642 forAll(faceCells, fcI)
1644 if(zoneCell[faceCells[fcI] ])
1646 boundaryZones[pI].append(name);
1655 pShapeMesh.addZones(pz, fz, cz);
1657 forAll(bPatches, pI)
1659 boundaryZones[pI].shrink();
1664 runTime.path()/runTime.constant()
1665 /"polyMesh"/"boundaryAdjacentCellZones"
1668 OFstream boundaryCellZonesFile(bczf);
1669 forAll(boundaryZones, bzI)
1671 forAll(boundaryZones[bzI], bzII)
1673 boundaryCellZonesFile << boundaryZones[bzI][bzII] << " ";
1676 boundaryCellZonesFile << endl;
1680 Info<< endl << "Writing mesh..." << flush;
1682 Info<< " to " << pShapeMesh.instance()/pShapeMesh.meshDir()
1685 pShapeMesh.setInstance(pShapeMesh.instance());
1687 Info<< "done." << endl << endl;
1689 // Write cellSets for Fluent regions
1690 // allows easy post-processing
1691 // set and zone functionality will be integrated some time
1692 // soon negating the need for double output
1695 if (cellGroupZoneID.size() > 1)
1697 Info<< "Writing cell sets" << endl;
1699 SLList<label>::iterator cg = cellGroupZoneID.begin();
1700 SLList<label>::iterator start = cellGroupStartIndex.begin();
1701 SLList<label>::iterator end = cellGroupEndIndex.begin();
1703 // Note: cellGroupXXX are all Fluent indices (starting at 1)
1704 // so offset before using.
1706 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1708 const word& name=patchNameIDs[cg()];
1709 const word& type=patchTypeIDs[cg()];
1711 Info<< "Writing cell set: " << name
1712 << " of type " << type << " starting at " << start() - 1
1713 << " ending at " << end() - 1 << " to cellSet." << endl;
1715 cellSet internal(pShapeMesh, name, end() - start());
1717 // shift cell indizes by 1
1718 for(label celli=start() - 1; celli<=end() - 1; celli++)
1720 internal.insert(celli);
1728 Info<< "Only one cell group: no set written\n";
1732 Info<< nl << "End" << endl;
1737 /* ------------------------------------------------------------------------- *\
1738 ------ End of fluentMeshToFoam.L
1739 \* ------------------------------------------------------------------------- */