1 /*--------------------------------*- C++ -*----------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 Converts a Fluent mesh to FOAM format
29 including multiple region and region boundary handling.
31 \*---------------------------------------------------------------------------*/
37 /* ------------------------------------------------------------------------- *\
38 ------ local definitions
39 \* ------------------------------------------------------------------------- */
42 #include "objectRegistry.H"
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"
55 #include "wordIOList.H"
57 #include "readHexLabel.H"
58 #include "cellShapeRecognition.H"
59 #include "repatchPolyTopoChanger.H"
62 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
66 const scalar convertToMeters = 1.0;
68 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
71 label dimensionOfGrid = 0;
78 SLList<label> pointGroupZoneID;
79 SLList<label> pointGroupStartIndex;
80 SLList<label> pointGroupEndIndex;
85 labelList neighbour(0);
86 SLList<label> faceGroupZoneID;
87 SLList<label> faceGroupStartIndex;
88 SLList<label> faceGroupEndIndex;
90 labelList fluentCellModelID(0);
91 SLList<label> cellGroupZoneID;
92 SLList<label> cellGroupStartIndex;
93 SLList<label> cellGroupEndIndex;
94 SLList<label> cellGroupType;
96 // number of zones adjusted at run-time if necessary
97 label maxZoneID = 100;
98 label zoneIDBuffer = 10;
100 wordList patchTypeIDs(maxZoneID);
101 wordList patchNameIDs(maxZoneID);
103 // Dummy yywrap to keep yylex happy at compile time.
104 // It is called by yylex but is not used as the mechanism to change file.
106 #if YY_FLEX_MINOR_VERSION < 6 && YY_FLEX_SUBMINOR_VERSION < 34
107 extern "C" int yywrap()
109 int yyFlexLexer::yywrap()
119 some_space {one_space}+
121 spaceNl ({space}|\n|\r)*
127 hexDigit [[:xdigit:]]
135 schemeSpecialInitial [!$%&*/\\:<=>?~_^#.@']
136 schemeSpecialSubsequent [.+-]
137 schemeSymbol (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
140 identifier {alpha}({alpha}|{digit})*
142 label [1-9]{decDigit}*
145 signedInteger [-+]?{integer}
146 word ({alpha}|{digit}|{dotColonDash})*
148 exponent_part [eE][-+]?{digit}+
149 fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
151 double ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
157 labelListElement {space}{zeroLabel}
158 hexLabelListElement {space}{hexLabel}
159 scalarListElement {space}{double}
160 schemeSymbolListElement {space}{schemeSymbol}
161 labelList ({labelListElement}+{space})
162 hexLabelList ({hexLabelListElement}+{space})
163 scalarList ({scalarListElement}+{space})
164 schemeSymbolList ({schemeSymbolListElement}+{space})
167 text ({space}({word}*{space})*)
169 dateDDMMYYYY ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
170 dateDDMonYYYY ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
171 time ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
173 versionNumber ({digit}|".")*
175 comment {spaceNl}"(0"{space}
176 header {spaceNl}"(1"{space}
177 dimension {spaceNl}"(2"{space}
178 point {spaceNl}"(10"{space}
179 fluentFace {spaceNl}"(13"{space}
180 cell {spaceNl}"(12"{space}
181 zoneVariant1 {spaceNl}"(39"{space}
182 zoneVariant2 {spaceNl}"(45"{space}
184 unknownPeriodicFace {spaceNl}"(17"{space}
185 periodicFace {spaceNl}"(18"{space}
186 cellTree {spaceNl}"(58"{space}
187 faceTree {spaceNl}"(59"{space}
188 faceParents {spaceNl}"(61"{space}
190 endOfSection {space}")"{space}
194 /* ------------------------------------------------------------------------- *\
195 ----- Exclusive start states -----
196 \* ------------------------------------------------------------------------- */
201 %x embeddedCommentState
206 %x readNumberOfPoints
207 %x readPointGroupData
237 %x embeddedUnknownBlock
242 label pointGroupNumberOfComponents = 3;
243 label pointI = 0; // index used for reading points
246 label faceGroupElementType = -1;
250 label cellGroupElementType = -1;
255 /* ------------------------------------------------------------------------ *\
256 ------ Start Lexing ------
257 \* ------------------------------------------------------------------------ */
259 /* ------ Reading control header ------ */
262 yy_push_state(readComment);
266 <readComment>{quote}{text}{quote} {
270 <readComment>{spaceNl}{endOfSection} {
278 <readHeader>{quote}{text}{quote} {
279 Info<< "Reading header: " << YYText() << endl;
284 BEGIN(readDimension);
287 <readDimension>{space}{label}{space} {
288 IStringStream dimOfGridStream(YYText());
290 dimensionOfGrid = readLabel(dimOfGridStream);
292 Info<< "Dimension of grid: " << dimensionOfGrid << endl;
297 BEGIN(readPointHeader);
300 <readPointHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
301 BEGIN(readNumberOfPoints);
304 <readNumberOfPoints>{space}{hexLabel}{space}{labelList} {
306 IStringStream numberOfPointsStream(YYText());
308 nPoints = readHexLabel(numberOfPointsStream);
310 Info<< "Number of points: " << nPoints << endl;
312 // set the size of the points list
313 points.setSize(nPoints);
315 // meaningless type skipped
316 readLabel(numberOfPointsStream);
318 // this dimension of grid may be checked against global dimension
319 if (numberOfPointsStream)
321 // check dimension of grid
322 readLabel(numberOfPointsStream);
330 <readPointHeader>{spaceNl}{lbrac} {
331 BEGIN(readPointGroupData);
334 <readPointGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
335 IStringStream pointGroupDataStream(YYText());
337 // read point zone-ID, start and end-label
338 // the indices will be used for checking later.
339 pointGroupZoneID.append(readHexLabel(pointGroupDataStream));
341 pointGroupStartIndex.append(readHexLabel(pointGroupDataStream));
343 pointGroupEndIndex.append(readHexLabel(pointGroupDataStream));
345 // point group type skipped
346 readHexLabel(pointGroupDataStream);
348 // In FOAM, indices start from zero - adjust
349 pointI = pointGroupStartIndex.last() - 1;
351 // reset number of components to default
352 pointGroupNumberOfComponents = 3;
354 // read number of components in the vector
355 if (pointGroupDataStream)
357 pointGroupNumberOfComponents = readLabel(pointGroupDataStream);
361 <readNumberOfPoints,readPointGroupData>{endOfSection} {
362 BEGIN(readPointData);
365 <readPointData>{spaceNl}{lbrac} {
367 Info<< "Reading points" << endl;
369 if (pointGroupNumberOfComponents == 2)
371 yy_push_state(readPoints2D);
375 yy_push_state(readPoints3D);
379 <readPoints2D>{spaceNl}{scalarList} {
381 IStringStream vertexXyzStream(YYText());
383 // Note: coordinates must be read one at the time.
384 scalar x = readScalar(vertexXyzStream);
385 scalar y = readScalar(vertexXyzStream);
387 points[pointI] = point(x, y, 0);
391 <readPoints3D>{spaceNl}{scalarList} {
393 IStringStream vertexXyzStream(YYText());
395 // Note: coordinates must be read one at the time.
396 scalar x = readScalar(vertexXyzStream);
397 scalar y = readScalar(vertexXyzStream);
398 scalar z = readScalar(vertexXyzStream);
400 points[pointI] = convertToMeters*point(x, y, z);
404 <readPoints2D,readPoints3D>{spaceNl}{endOfSection} {
406 // check read of points
407 if (pointI != pointGroupEndIndex.last())
409 Info<< "problem with reading points: "
410 << "start index: " << pointGroupStartIndex.last()
411 << " end index: " << pointGroupEndIndex.last()
412 << " last points read: " << pointI << endl;
420 BEGIN(readFaceHeader);
423 <readFaceHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
424 BEGIN(readNumberOfFaces);
427 <readNumberOfFaces>{space}{hexLabel}{space}{labelListElement}+ {
429 IStringStream numberOfFacesStream(YYText());
431 nFaces = readHexLabel(numberOfFacesStream);
433 Info<< "number of faces: " << nFaces << endl;
435 faces.setSize(nFaces);
436 owner.setSize(nFaces);
437 neighbour.setSize(nFaces);
439 // Meaningless type and element type not read
442 <readFaceHeader>{spaceNl}{lbrac} {
443 BEGIN(readFaceGroupData);
446 <readFaceGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
448 IStringStream faceGroupDataStream(YYText());
450 // read fluentFace zone-ID, start and end-label
451 faceGroupZoneID.append(readHexLabel(faceGroupDataStream));
453 // the indices will be used for checking later.
454 faceGroupStartIndex.append(readHexLabel(faceGroupDataStream));
456 faceGroupEndIndex.append(readHexLabel(faceGroupDataStream));
459 readHexLabel(faceGroupDataStream);
461 faceGroupElementType = readHexLabel(faceGroupDataStream);
463 // In FOAM, indices start from zero - adjust
464 faceI = faceGroupStartIndex.last() - 1;
467 <readNumberOfFaces,readFaceGroupData>{spaceNl}{endOfSection} {
471 <readFaceData>{spaceNl}{lbrac} {
473 if (faceGroupElementType == 0)
475 Info<< "Reading mixed faces" << endl;
476 yy_push_state(readFacesMixed);
480 Info<< "Reading uniform faces" << endl;
481 yy_push_state(readFacesUniform);
485 <readFacesMixed>{spaceNl}{hexLabelList} {
487 IStringStream mixedFaceStream(YYText());
489 face& curFaceLabels = faces[faceI];
491 // set size of label list
492 curFaceLabels.setSize(readLabel(mixedFaceStream));
494 forAll (curFaceLabels, i)
496 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
499 // read neighbour and owner. Neighbour comes first
500 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
501 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
505 <readFacesUniform>{spaceNl}{hexLabelList} {
507 IStringStream mixedFaceStream(YYText());
509 face& curFaceLabels = faces[faceI];
511 // set size of label list. This is OK because in Fluent the type
512 // for edge is 2, for triangle is 3 and for quad is 4
513 curFaceLabels.setSize(faceGroupElementType);
515 forAll (curFaceLabels, i)
517 curFaceLabels[i] = readHexLabel(mixedFaceStream) - 1;
520 // read neighbour and owner. Neighbour comes first
521 neighbour[faceI] = readHexLabel(mixedFaceStream) - 1;
522 owner[faceI] = readHexLabel(mixedFaceStream) - 1;
526 <readFacesMixed,readFacesUniform>{spaceNl}{endOfSection} {
528 // check read of fluentFaces
529 if (faceI != faceGroupEndIndex.last())
531 Info<< "problem with reading fluentFaces: "
532 << "start index: " << faceGroupStartIndex.last()
533 << " end index: " << faceGroupEndIndex.last()
534 << " last fluentFaces read: " << faceI << endl;
542 BEGIN(readCellHeader);
545 <readCellHeader>{spaceNl}{lbrac}{space}"0"{space}"1"{space} {
546 BEGIN(readNumberOfCells);
549 <readNumberOfCells>{space}{hexLabel}{space}{labelListElement}+ {
551 IStringStream numberOfCellsStream(YYText());
553 nCells = readHexLabel(numberOfCellsStream);
555 Info<< "Number of cells: " << nCells << endl;
557 fluentCellModelID.setSize(nCells);
559 // Meaningless type and element type not read
562 <readCellHeader>{spaceNl}{lbrac} {
563 BEGIN(readCellGroupData);
566 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
567 // Warning. This entry must be above the next one because of the lexing
568 // rules. It is introduced to deal with the problem of reading
569 // non-standard cell definition from Tgrid, which misses the type label.
571 Info<< "Tgrid syntax problem: " << YYText() << endl;
572 IStringStream cellGroupDataStream(YYText());
574 // read cell zone-ID, start and end-label
575 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
577 // the indices will be used for checking later.
578 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
580 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
582 cellGroupType.append(readHexLabel(cellGroupDataStream));
584 Info<< "cellGroupZoneID:" << cellGroupZoneID.last()
586 Info<< "cellGroupStartIndex:" << cellGroupStartIndex.last()
588 Info<< "cellGroupEndIndex:" << cellGroupEndIndex.last()
590 Info<< "cellGroupType:" << cellGroupType.last()
594 // Note. Potentially skip cell set if type is zero.
595 // This entry does not exist in Tgrid files.
596 if (dimensionOfGrid == 2)
598 // Tgrid creating triangles
599 cellGroupElementType = 1;
603 cellGroupElementType = 2;
606 // In FOAM, indices start from zero - adjust
607 celli = cellGroupStartIndex.last() - 1;
609 if (cellGroupElementType != 0)
611 label lastIndex = cellGroupEndIndex.last();
613 for (; celli < lastIndex; celli++)
615 fluentCellModelID[celli] = cellGroupElementType;
620 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
621 // Warning. See above
623 Info<< "Other readCellGroupData: " << YYText() << endl;
626 IStringStream cellGroupDataStream(YYText());
628 // read cell zone-ID, start and end-label
629 cellGroupZoneID.append(readHexLabel(cellGroupDataStream));
631 // the indices will be used for checking later.
632 cellGroupStartIndex.append(readHexLabel(cellGroupDataStream));
634 cellGroupEndIndex.append(readHexLabel(cellGroupDataStream));
636 cellGroupType.append(readHexLabel(cellGroupDataStream));
638 // Note. Potentially skip cell set if type is zero.
640 cellGroupElementType = readHexLabel(cellGroupDataStream);
642 // In FOAM, indices start from zero - adjust
643 celli = cellGroupStartIndex.last() - 1;
645 if (cellGroupElementType != 0)
647 Info<< "Reading uniform cells" << endl;
648 label lastIndex = cellGroupEndIndex.last();
650 for (; celli < lastIndex; celli++)
652 fluentCellModelID[celli] = cellGroupElementType;
657 <readNumberOfCells,readCellGroupData>{endOfSection} {
661 <readCellData>{spaceNl}{lbrac} {
662 Info<< "Reading mixed cells" << endl;
663 yy_push_state(readCellsMixed);
666 <readCellsMixed>{spaceNl}{labelList} {
668 IStringStream fluentCellModelIDStream(YYText());
671 while (fluentCellModelIDStream.read(celliD))
673 fluentCellModelID[celli] = celliD;
678 <readCellsMixed>{spaceNl}{endOfSection} {
680 // check read of cells
681 if (celli != cellGroupEndIndex.last())
683 Info<< "problem with reading cells: "
684 << "start index: " << cellGroupStartIndex.last()
685 << " end index: " << cellGroupEndIndex.last()
686 << " last cells read: " << celli << endl;
695 BEGIN(readZoneHeader);
699 BEGIN(readZoneHeader);
702 <readZoneHeader>{spaceNl}{lbrac} {
703 BEGIN(readZoneGroupData);
706 <readZoneGroupData>{space}{label}{space}{word}{space}{word} {
708 IStringStream zoneDataStream(YYText());
710 // cell zone-ID not in hexadecimal!!! Inconsistency
711 label zoneID(readLabel(zoneDataStream));
713 if (zoneID > maxZoneID - 1)
715 // resize the container
716 maxZoneID = zoneID + zoneIDBuffer;
718 patchTypeIDs.setSize(maxZoneID);
719 patchNameIDs.setSize(maxZoneID);
722 zoneDataStream >> patchTypeIDs[zoneID];
723 zoneDataStream >> patchNameIDs[zoneID];
725 Info<< "Read zone1:" << zoneID
726 << " name:" << patchNameIDs[zoneID]
727 << " patchTypeID:" << patchTypeIDs[zoneID]
731 <readZoneGroupData>{space}{label}{space}{word}{space}{word}{space}{label} {
732 // Fluent manual inconsistency, version 6.1.22
733 IStringStream zoneDataStream(YYText());
735 // cell zone-ID not in hexadecimal!!! Inconsistency
736 label zoneID(readLabel(zoneDataStream));
738 if (zoneID > maxZoneID - 1)
740 // resize the container
741 maxZoneID = zoneID + zoneIDBuffer;
743 patchTypeIDs.setSize(maxZoneID);
744 patchNameIDs.setSize(maxZoneID);
747 zoneDataStream >> patchTypeIDs[zoneID];
748 zoneDataStream >> patchNameIDs[zoneID];
750 Info<< "Read zone2:" << zoneID
751 << " name:" << patchNameIDs[zoneID]
752 << " patchTypeID:" << patchTypeIDs[zoneID]
756 <readZoneGroupData>{endOfSection} {
760 <readZoneData>{spaceNl}{lbrac} {
761 Info<< "Reading zone data" << endl;
762 yy_push_state(readZoneBlock);
765 <readZoneBlock>{spaceNl}{schemeSymbolList} {
768 <readZoneBlock>{lbrac} {
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 yy_push_state(unknownBlock);
791 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbol} {
794 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{lbrac} {
795 yy_push_state(embeddedUnknownBlock);
799 <readComment,unknownBlock,embeddedUnknownBlock>{spaceNl}{endOfSection} {
803 <unknownBlock,embeddedUnknownBlock>{spaceNl}{labelList} {
806 <unknownBlock,embeddedUnknownBlock>{spaceNl}{hexLabelList} {
809 <unknownBlock,embeddedUnknownBlock>{spaceNl}{scalarList} {
812 <unknownBlock,embeddedUnknownBlock>{spaceNl}{schemeSymbolList} {
815 <unknownBlock,embeddedUnknownBlock>{spaceNl}{text} {
819 /* ------ Ignore remaining space and \n s. Any other characters are errors. */
821 <readPoints2D,readPoints3D>.|\n {
822 Info<< "ERROR! Do not understand characters: " << YYText() << endl;
827 /* ------ On EOF return to previous file, if none exists terminate. ------ */
835 #include "fileName.H"
838 // Find label of face.
839 label findFace(const primitiveMesh& mesh, const face& f)
841 // Get faces using zeroth vertex of face.
842 const labelList& pFaces = mesh.pointFaces()[f[0] ];
846 label faceI = pFaces[i];
848 if (f == mesh.faces()[faceI])
854 // Didn't find face. Do what?
855 FatalErrorIn("findFace(const primitiveMesh&, const face&)")
856 << "Problem : cannot find a single face in the mesh which uses"
857 << " vertices " << f << exit(FatalError);
863 int main(int argc, char *argv[])
865 argList::noParallel();
866 argList::validArgs.append("Fluent mesh file");
867 argList::validOptions.insert("scale", "scale factor");
868 argList::validOptions.insert("writeSets", "");
869 argList::validOptions.insert("writeZones", "");
871 argList args(argc, argv);
878 scalar scaleFactor = 1.0;
879 args.optionReadIfPresent("scale", scaleFactor);
881 bool writeSets = args.optionFound("writeSets");
882 bool writeZones = args.optionFound("writeZones");
884 # include "createTime.H"
886 fileName fluentFile(args.additionalArgs()[0]);
887 std::ifstream fluentStream(fluentFile.c_str());
891 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
893 << ": file " << fluentFile << " not found"
897 //HR 22.11.09: These global variables do not get initialised.
898 // Debug-version fails!
899 patchTypeIDs.setSize(maxZoneID);
900 patchNameIDs.setSize(maxZoneID);
902 yyFlexLexer lexer(&fluentStream);
903 while (lexer.yylex() != 0)
906 Info<< "\n\nFINISHED LEXING\n\n\n";
907 // Lookup table giving number of vertices given a fluent cell type ID
908 // Currently not used.
909 // label fluentModelNVertices[7] = {-1, 3, 4, 4, 8, 5, 6};
911 // Lookup table giving number of vertices given a fluent cell type ID
912 label fluentModelNFaces[7] = {-1, 3, 4, 4, 6, 5, 5};
914 // Make a list of cell faces to be filled in for owner and neighbour
916 labelListList cellFaces(nCells);
918 labelList nFacesInCell(nCells, 0);
920 forAll (cellFaces, celli)
922 cellFaces[celli].setSize(fluentModelNFaces[fluentCellModelID[celli] ]);
925 // fill in owner and neighbour
927 forAll (owner, faceI)
929 if (owner[faceI] > -1)
931 label curCell = owner[faceI];
933 if (nFacesInCell[curCell] >= cellFaces[curCell].size())
935 FatalErrorIn(args.executable())
936 << "Trying to add " << nFacesInCell[curCell] + 1
937 << "th face to a cell with " << cellFaces[curCell].size()
938 << " faces. Face index: " << faceI
939 << " Current faces: " << cellFaces[curCell]
940 << abort(FatalError);
943 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
945 nFacesInCell[curCell]++;
949 forAll (neighbour, faceI)
951 if (neighbour[faceI] > -1)
953 label curCell = neighbour[faceI];
955 if (nFacesInCell[curCell] >= cellFaces[curCell].size())
957 FatalErrorIn(args.executable())
958 << "Trying to add " << nFacesInCell[curCell] + 1
959 << "th face to a cell with " << cellFaces[curCell].size()
960 << " faces. Face index: " << faceI
961 << " Current faces: " << cellFaces[curCell]
962 << abort(FatalError);
965 cellFaces[curCell][nFacesInCell[curCell] ] = faceI;
967 nFacesInCell[curCell]++;
971 // Construct shapes from face lists
972 cellShapeList cellShapes(nCells);
974 // Extrude 2-D mesh into 3-D
976 Info<< "dimension of grid: " << dimensionOfGrid << endl;
977 faceList frontAndBackFaces;
979 if (dimensionOfGrid == 2)
981 const scalar extrusionFactor = 0.01;
983 boundBox box(max(points), min(points));
985 const scalar zOffset = extrusionFactor*box.mag();
987 // two-dimensional grid. Extrude in z-direction
988 Info<< "Grid is 2-D. Extruding in z-direction by: "
989 << 2*zOffset << endl;
991 pointField oldPoints = points;
993 const label pointOffset = oldPoints.size();
995 points.setSize(2*pointOffset);
997 label nNewPoints = 0;
999 // Note: In order for the owner-neighbour rules to be right, the
1000 // points given by Fluent need to represent the FRONT plane of the
1001 // geometry. Therefore, the extrusion will be in -z direction
1003 forAll (oldPoints, pointI)
1005 points[nNewPoints] = oldPoints[pointI];
1007 points[nNewPoints].z() = zOffset;
1012 forAll (oldPoints, pointI)
1014 points[nNewPoints] = oldPoints[pointI];
1016 points[nNewPoints].z() = -zOffset;
1021 // 2-D shape recognition
1022 Info<< "Creating shapes for 2-D cells"<< endl;
1024 // Set the number of empty faces
1025 frontAndBackFaces.setSize(2*nCells);
1027 forAll (fluentCellModelID, celli)
1029 switch (fluentCellModelID[celli])
1036 extrudedTriangleCellShape
1055 extrudedQuadCellShape
1071 FatalErrorIn(args.executable())
1072 << "unrecognised 2-D cell shape: "
1073 << fluentCellModelID[celli]
1074 << abort(FatalError);
1080 forAll (faces, faceI)
1083 if (faces[faceI].size() != 2)
1085 FatalErrorIn(args.executable())
1086 << "fluentMeshToFoam: a 2-D face defined with "
1087 << faces[faceI].size() << " points." << endl;
1090 labelList& newFace = faces[faceI];
1094 newFace[2] = newFace[1] + pointOffset;
1096 newFace[3] = newFace[0] + pointOffset;
1099 // Create new cells from 2-D shapes
1103 // 3-D shape recognition
1104 Info<< "Creating shapes for 3-D cells"<< endl;
1105 forAll (fluentCellModelID, celli)
1109 fluentCellModelID[celli] == 2 // tet
1110 || fluentCellModelID[celli] == 4 // hex
1111 || fluentCellModelID[celli] == 5 // pyramid
1112 || fluentCellModelID[celli] == 6 // prism
1125 fluentCellModelID[celli]
1131 FatalErrorIn(args.executable())
1132 << "unrecognised 3-D cell shape: "
1133 << fluentCellModelID[celli]
1134 << abort(FatalError);
1139 // boundary faces are oriented such that the owner is zero and the face
1140 // area vector points into the domain. Turn them round before making patches
1141 // for Foam compatibility
1143 forAll (faces, faceI)
1145 if (owner[faceI] == -1)
1148 labelList oldFace = faces[faceI];
1150 forAllReverse(oldFace, i)
1152 faces[faceI][oldFace.size() - i - 1] =
1159 //make patchless mesh before analysing boundaries
1161 faceListList patches(0);
1162 wordList patchNames(0);
1163 wordList patchTypes(0);
1164 word defaultFacesName = "defaultFaces";
1165 word defaultFacesType = emptyPolyPatch::typeName;
1166 wordList patchPhysicalTypes(0);
1170 points *= scaleFactor;
1172 Info<< "Building patch-less mesh..." << flush;
1178 polyMesh::defaultRegion,
1192 //dont write mesh yet, otherwise preservePatchTypes will be broken
1193 //and zones wont be written
1194 //checkmesh done after patch addition as well
1195 Info<< "done." << endl;
1198 Info<< endl << "Building boundary and internal patches." << endl;
1199 //adding patches after mesh construction allows topological checks
1200 //on whether a patch is internal or external, something fluent
1201 //doesnt seem to mind
1203 // Make boundary patches
1205 SLList<label>::iterator faceGroupZoneIDIter = faceGroupZoneID.begin();
1206 SLList<label>::iterator faceGroupStartIndexIter =
1207 faceGroupStartIndex.begin();
1208 SLList<label>::iterator faceGroupEndIndexIter = faceGroupEndIndex.begin();
1210 // Note. Not all groups of faces will be boundary patches.
1211 // Take care on construction
1213 //2D needs extra space for frontAndBack faces
1214 if (dimensionOfGrid == 2)
1216 patches.setSize(faceGroupZoneID.size()+1);
1217 patchNames.setSize(faceGroupZoneID.size()+1);
1218 patchTypes.setSize(faceGroupZoneID.size()+1);
1219 patchPhysicalTypes.setSize(faceGroupZoneID.size()+1);
1223 patches.setSize(faceGroupZoneID.size());
1224 patchNames.setSize(faceGroupZoneID.size());
1225 patchTypes.setSize(faceGroupZoneID.size());
1226 patchPhysicalTypes.setSize(faceGroupZoneID.size());
1231 // Colate information for all patches (internal and external)
1233 // Create a file listing patch type for each zone
1235 label maxZoneID = 0;
1239 SLList<label>::iterator fgzIDIter = faceGroupZoneID.begin();
1240 fgzIDIter != faceGroupZoneID.end();
1244 maxZoneID = max(maxZoneID, fgzIDIter());
1247 Info << "maxZoneID: " << maxZoneID << endl;
1248 wordIOList zoneToPatchName
1254 pShapeMesh.meshSubDir,
1259 wordList(maxZoneID + 1, "unknown")
1266 faceGroupZoneIDIter != faceGroupZoneID.end()
1267 && faceGroupStartIndexIter != faceGroupStartIndex.end()
1268 && faceGroupEndIndexIter != faceGroupEndIndex.end();
1269 ++faceGroupZoneIDIter,
1270 ++faceGroupStartIndexIter,
1271 ++faceGroupEndIndexIter
1274 // Get face type and name
1275 const word& curPatchType = patchTypeIDs[faceGroupZoneIDIter()];
1277 const word& curPatchName = patchNameIDs[faceGroupZoneIDIter()];
1279 Info<< "Creating patch " << nPatches
1280 << " for zone: " << faceGroupZoneIDIter()
1281 << " start: " << faceGroupStartIndexIter()
1282 << " end: " << faceGroupEndIndexIter()
1283 << " type: " << curPatchType << " name: " << curPatchName << endl;
1285 // Record zone index
1286 zoneToPatchName[faceGroupZoneIDIter()] = curPatchName;
1288 // Make patch labels
1289 label faceLabel = faceGroupStartIndexIter() - 1;
1291 faceList patchFaces(faceGroupEndIndexIter() - faceLabel);
1293 forAll (patchFaces, faceI)
1297 faces[faceLabel].size() == 3
1298 || faces[faceLabel].size() == 4
1301 patchFaces[faceI] = face(faces[faceLabel]);
1306 FatalErrorIn("fluentToFoam::main(int argc, char *argv[])")
1307 << "unrecognised face shape with "
1308 << patchFaces[faceI].size() << " vertices"
1309 << abort(FatalError);
1313 // Inlets and outlets
1316 curPatchType == "pressure"
1317 || curPatchType == "pressure-inlet"
1318 || curPatchType == "inlet-vent"
1319 || curPatchType == "intake-fan"
1320 || curPatchType == "pressure-outlet"
1321 || curPatchType == "exhaust-fan"
1322 || curPatchType == "outlet-vent"
1323 || curPatchType == "pressure-far-field"
1324 || curPatchType == "velocity-inlet"
1325 || curPatchType == "mass-flow-inlet"
1326 || curPatchType == "outflow"
1327 || curPatchType == "interface"
1328 || curPatchType == "periodic"
1329 || curPatchType == "shadow"
1332 patches[nPatches] = patchFaces;
1333 patchTypes[nPatches] = polyPatch::typeName;
1334 patchNames[nPatches] = curPatchName;
1338 else if (curPatchType == "wall" ) //wall boundaries
1340 patches[nPatches] = patchFaces;
1341 patchTypes[nPatches] = wallPolyPatch::typeName;
1342 patchNames[nPatches] = curPatchName;
1348 curPatchType == "symmetry"
1349 || curPatchType == "axis"
1352 patches[nPatches] = patchFaces;
1353 patchTypes[nPatches] = symmetryPolyPatch::typeName;
1354 patchNames[nPatches] = curPatchName;
1360 curPatchType == "interior"
1361 || curPatchType == "interface"
1362 || curPatchType == "internal"
1363 || curPatchType == "solid"
1364 || curPatchType == "fan"
1365 || curPatchType == "radiator"
1366 || curPatchType == "porous-jump"
1367 ) //interior boundaries - will not be added as patches
1369 patches[nPatches] = patchFaces;
1370 patchTypes[nPatches] = "internal";
1371 patchNames[nPatches] = curPatchName;
1378 ) // Unnamed face regions default to interior patches
1380 Info<< "Patch " << faceGroupZoneIDIter()
1381 << ": Faces are defined but "
1382 << "not created as a zone." << endl
1383 << "Null specification is only valid for internal faces."
1386 patches[nPatches] = patchFaces;
1387 patchTypes[nPatches] = "internal";
1388 patchNames[nPatches] = curPatchName;
1392 else //unknown face regions are not handled
1394 FatalErrorIn(args.executable())
1395 << "fluent patch type " << curPatchType << " not recognised."
1396 << abort(FatalError);
1400 //add front and back boundaries for 2D meshes
1401 if (dimensionOfGrid == 2)
1403 Info<< "Creating patch for front and back planes" << endl << endl;
1405 patches[nPatches] = frontAndBackFaces;
1406 patchTypes[nPatches] = emptyPolyPatch::typeName;
1407 patchNames[nPatches] = "frontAndBackPlanes";
1412 //Now have all patch information,
1413 //check whether each patch is internal or external
1414 //and add boundaries to mesh
1415 //also write face sets of all patches
1416 patches.setSize(nPatches);
1417 patchTypes.setSize(nPatches);
1418 patchNames.setSize(nPatches);
1422 const polyBoundaryMesh& oPatches = pShapeMesh.boundaryMesh();
1424 DynamicList<polyPatch*> newPatches(nPatches);
1426 // For every boundary face the old patch.
1427 labelList facePatchID(pShapeMesh.nFaces()-pShapeMesh.nInternalFaces(), -1);
1428 label cMeshFace = pShapeMesh.nInternalFaces();
1429 label nBoundaries = 0;
1432 forAll(patches, patchI)
1434 const faceList& bFaces = patches[patchI];
1436 label sz = bFaces.size();
1437 labelList meshFaces(sz,-1);
1440 //make face set and write (seperate from rest for clarity)
1441 //internal and external Fluent boundaries
1443 faceSet pFaceSet(pShapeMesh, patchNames[patchI], sz);
1447 const face& f = bFaces[j];
1448 label cMeshFace = findFace(pShapeMesh, f);
1449 meshFaces[j] = cMeshFace;
1450 pFaceSet.insert(cMeshFace);
1454 Info<< "Writing patch " << patchNames[patchI]
1455 << " of size " << sz << " to faceSet." << endl;
1461 //check if patch is internal
1462 //also check internal/external-ness of first patch face
1463 //internal faces cannot become foam boundaries
1464 //if a face is defined as internal but is actually external
1465 //it will be put in a default wall boundary
1466 //internal boundaries are simply ignored
1470 patchTypes[patchI] != "internal"
1471 && !pShapeMesh.isInternalFace(meshFaces[0])
1474 // First face is external and has valid non-internal type
1476 //check all faces for externalness just to be sure
1477 //and mark patch number to global list
1478 forAll(meshFaces, i)
1480 label faceI = meshFaces[i];
1482 if (pShapeMesh.isInternalFace(faceI))
1484 FatalErrorIn(args.executable())
1485 << "Face " << faceI << " on new patch "
1486 << patchNames[patchI]
1487 << " is not an external face of the mesh." << endl
1488 << exit(FatalError);
1491 if(facePatchID[faceI - pShapeMesh.nInternalFaces()]!= -1)
1493 FatalErrorIn(args.executable())
1494 << "Face " << faceI << " on new patch "
1495 << patchNames[patchI]
1496 << " has already been marked for repatching to"
1498 << facePatchID[faceI - pShapeMesh.nInternalFaces()]
1499 << exit(FatalError);
1501 facePatchID[faceI - pShapeMesh.nInternalFaces()] = nBoundaries;
1504 // Add to boundary patch
1506 Info<< "Adding new patch " << patchNames[patchI]
1507 << " of type " << patchTypes[patchI]
1508 << " as patch " << nBoundaries << endl;
1510 // Add patch to new patch list
1528 Info<< "Patch " << patchNames[patchI]
1529 << " is internal to the mesh "
1530 << " and is not being added to the boundary."
1536 // Check for any remaining boundary faces
1537 // and add them to a default wall patch
1538 // this routine should generally not be invoked
1540 DynamicList<label> defaultBoundaryFaces(facePatchID.size());
1541 forAll (facePatchID, idI)
1543 if(facePatchID[idI] == -1)
1545 defaultBoundaryFaces.append(idI);
1546 facePatchID[idI] = nBoundaries;
1549 defaultBoundaryFaces.shrink();
1551 if (defaultBoundaryFaces.size() != 0)
1553 Warning << " fluent mesh has " << defaultBoundaryFaces.size()
1554 << " undefined boundary faces." << endl
1555 << " Adding undefined faces to new patch `default_wall`"
1558 // Add patch to new patch list
1564 wallPolyPatch::typeName,
1566 defaultBoundaryFaces.size(),
1573 cMeshFace += defaultBoundaryFaces.size();
1577 newPatches.shrink();
1579 // Use facePatchIDs map to reorder boundary faces into compact regions
1581 repatchPolyTopoChanger repatcher(pShapeMesh);
1583 // Add new list of patches
1584 repatcher.changePatches(newPatches);
1587 forAll(facePatchID, idI)
1589 label faceI = idI + pShapeMesh.nInternalFaces();
1591 repatcher.changePatchID(faceI, facePatchID[idI]);
1593 repatcher.repatch();
1599 polyMesh::defaultRegion,
1607 // Set the precision of the points data to 10
1608 IOstream::defaultPrecision(10);
1612 // will write out cell zones and internal faces for those zones
1613 // note: zone boundary faces are not added to face zones
1614 // the names of boundaries bordering on cell zones are written to
1615 // a list containing the boundary name and cellzone it borders on
1616 // interior boundaries are handled via faceSets
1617 // cell zones will only be written if there is more than one
1619 if (writeZones && cellGroupZoneID.size() > 1)
1621 Info<< "Adding Zones" << endl;
1622 List<pointZone*> pz(0);
1624 label nrCellZones = cellGroupZoneID.size();
1625 List<cellZone*> cz(nrCellZones);
1627 // Make face zones for cell zones
1628 List<faceZone*> fz(nrCellZones);
1630 // List of patch names and the cellZone(s) they border
1631 // this is just an info file to make MRF easier to setup
1632 List<DynamicList<word> > boundaryZones
1634 pShapeMesh.boundaryMesh().size()
1637 const polyBoundaryMesh& bPatches = pShapeMesh.boundaryMesh();
1638 forAll(bPatches, pI)
1640 boundaryZones[pI].append(bPatches[pI].name());
1644 SLList<label>::iterator cg = cellGroupZoneID.begin();
1645 SLList<label>::iterator start = cellGroupStartIndex.begin();
1646 SLList<label>::iterator end = cellGroupEndIndex.begin();
1648 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1650 const word& name = patchNameIDs[cg()];
1651 const word& type = patchTypeIDs[cg()];
1653 Info<< "Writing cell zone: " << name
1654 << " of type " << type << " starting at " << start() - 1
1655 << " ending at " << end() - 1 << " to cellSet." << endl;
1657 labelList cls(end() - start() + 1);
1659 // Mark zone cells, used for finding faces
1660 boolList zoneCell(pShapeMesh.nCells(), false);
1662 // Shift cell indices by 1
1664 for (label celli = (start() - 1); celli < end(); celli++)
1667 zoneCell[celli] = true;
1671 cz[cnt] = new cellZone
1676 pShapeMesh.cellZones()
1679 DynamicList<label> zoneFaces(pShapeMesh.nFaces());
1680 forAll (pShapeMesh.faceNeighbour(), faceI)
1682 label nei = pShapeMesh.faceNeighbour()[faceI];
1683 label own = pShapeMesh.faceOwner()[faceI];
1686 if(zoneCell[nei] && zoneCell[own])
1688 zoneFaces.append(faceI);
1694 fz[cnt] = new faceZone
1698 boolList(zoneFaces.size(), false),
1700 pShapeMesh.faceZones()
1703 // Add cell zones to patch zone list
1704 forAll (bPatches, pI)
1706 const labelList& faceCells = bPatches[pI].faceCells();
1707 forAll(faceCells, fcI)
1709 if(zoneCell[faceCells[fcI] ])
1711 boundaryZones[pI].append(name);
1720 pShapeMesh.addZones(pz, fz, cz);
1722 forAll(bPatches, pI)
1724 boundaryZones[pI].shrink();
1729 runTime.path()/runTime.constant()
1730 /"polyMesh"/"boundaryAdjacentCellZones"
1733 OFstream boundaryCellZonesFile(bczf);
1734 forAll (boundaryZones, bzI)
1736 forAll(boundaryZones[bzI], bzII)
1738 boundaryCellZonesFile << boundaryZones[bzI][bzII] << " ";
1741 boundaryCellZonesFile << endl;
1745 Info<< endl << "Writing mesh..." << flush;
1747 Info<< " to " << pShapeMesh.instance()/pShapeMesh.meshDir()
1750 pShapeMesh.setInstance(pShapeMesh.instance());
1753 // Write zone to patch name
1754 zoneToPatchName.write();
1755 Info<< "done." << endl << endl;
1757 // Write cellSets for Fluent regions
1758 // allows easy post-processing
1759 // set and zone functionality will be integrated some time
1760 // soon negating the need for double output
1763 if (cellGroupZoneID.size() > 1)
1765 Info<< "Writing cell sets" << endl;
1767 SLList<label>::iterator cg = cellGroupZoneID.begin();
1768 SLList<label>::iterator start = cellGroupStartIndex.begin();
1769 SLList<label>::iterator end = cellGroupEndIndex.begin();
1771 // Note: cellGroupXXX are all Fluent indices (starting at 1)
1772 // so offset before using.
1774 for (; cg != cellGroupZoneID.end(); ++cg, ++start, ++end)
1776 const word& name = patchNameIDs[cg()];
1777 const word& type = patchTypeIDs[cg()];
1779 Info<< "Writing cell set: " << name
1780 << " of type " << type << " starting at " << start() - 1
1781 << " ending at " << end() - 1 << " to cellSet." << endl;
1783 cellSet internal(pShapeMesh, name, end() - start());
1785 // shift cell indizes by 1
1786 for (label celli = start() - 1; celli <= end() - 1; celli++)
1788 internal.insert(celli);
1796 Info<< "Only one cell group: no set written\n";
1800 Info<< "\nEnd\n" << endl;
1805 /* --------------------------------------------------------------------------*\
1806 ------ End of fluentMeshToFoam.L
1807 \* --------------------------------------------------------------------------*/