Forward compatibility: flex
[foam-extend-3.2.git] / applications / utilities / mesh / conversion / fluent3DMeshToElmer / fluent3DMeshToElmer.L
blob8853db39596994d0290f864837c2a0cba07ad4b9
1 /*--------------------------------*- C++ -*----------------------------------*\
2   =========                 |
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 -------------------------------------------------------------------------------
8 License
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/>.
24 Application
25     fluent3DMeshToFoam
27 Description
28     Converts a Fluent mesh to FOAM format.
30 \*---------------------------------------------------------------------------*/
33 #undef yyFlexLexer
35  /* ------------------------------------------------------------------------ *\
36    ------ local definitions
37  \* ------------------------------------------------------------------------ */
39 #include "argList.H"
40 #include "objectRegistry.H"
41 #include "foamTime.H"
42 #include "polyMesh.H"
43 #include "directTopoChange.H"
44 #include "polyMeshZipUpCells.H"
45 #include "wallPolyPatch.H"
46 #include "symmetryPolyPatch.H"
47 #include "cyclicPolyPatch.H"
48 #include "Swap.H"
49 #include "IFstream.H"
50 #include "wordIOList.H"
51 #include "readHexLabel.H"
52 #include "ElmerMeshWriter.H"
54 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
56 using namespace Foam;
58 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
60 // Line number
61 label lineNo = 1;
63 // Scale factor used to scale points (optional command line argument)
64 scalar scaleFactor = 1.0;
66 label dimensionOfGrid = 0;
67 label nPoints = 0;
68 label nFaces = 0;
69 label nCells = 0;
71 bool hangingNodes = false;
73 pointField points(0);
74 faceList faces(0);
75 labelList owner(0);
76 labelList neighbour(0);
78 // Group type and name
79 Map<word> groupType(100);
80 Map<word> groupName(100);
82 // Point groups
83 DynamicList<label> pointGroupZoneID;
84 DynamicList<label> pointGroupStartIndex;
85 DynamicList<label> pointGroupEndIndex;
87 // Face groups
88 DynamicList<label> faceGroupZoneID;
89 DynamicList<label> faceGroupStartIndex;
90 DynamicList<label> faceGroupEndIndex;
92 // Cell groups
93 DynamicList<label> cellGroupZoneID;
94 DynamicList<label> cellGroupStartIndex;
95 DynamicList<label> cellGroupEndIndex;
96 DynamicList<label> cellGroupType;
98 // Special parsing of (incorrect) Cubit files
99 bool cubitFile = false;
102 void uniquify(word& name, HashSet<word>& patchNames)
104     if (!patchNames.found(name))
105     {
106         patchNames.insert(name);
107     }
108     else
109     {
110         Info<< "    name " << name << " already used";
112         label i = 1;
113         word baseName = name;
115         do
116         {
117             name = baseName + "_" + Foam::name(i++);
118         } while (patchNames.found(name));
120         Info<< ", changing to " << name << endl;
121     }
125 // Dummy yywrap to keep yylex happy at compile time.
126 // It is called by yylex but is not used as the mechanism to change file.
127 // See <<EOF>>
128 #if YY_FLEX_MINOR_VERSION < 6 && YY_FLEX_SUBMINOR_VERSION < 34
129 extern "C" int yywrap()
130 #else
131 int yyFlexLexer::yywrap()
132 #endif
134     return 1;
139 one_space                  [ \t\f]
140 space                      {one_space}*
141 some_space                 {one_space}+
142 cspace                     ","{space}
144 alpha                      [_[:alpha:]]
145 digit                      [[:digit:]]
146 decDigit                   [[:digit:]]
147 octalDigit                 [0-7]
148 hexDigit                   [[:xdigit:]]
150 lbrac                      "("
151 rbrac                      ")"
152 quote                      \"
153 dash                       "-"
154 dotColonDash               [.:-]
156 schemeSpecialInitial       [!$%&*/\\:<=>?~_^#.@']
157 schemeSpecialSubsequent    [.+-]
158 schemeSymbol               (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
161 identifier                 {alpha}({alpha}|{digit})*
162 integer                    {decDigit}+
163 label                      [1-9]{decDigit}*
164 hexLabel                   {hexDigit}+
165 zeroLabel                  {digit}*
166 signedInteger              [-+]?{integer}
167 word                       ({alpha}|{digit}|{dotColonDash})*
169 exponent_part              [eE][-+]?{digit}+
170 fractional_constant        [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
172 double                     ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
174 x                          {double}
175 y                          {double}
176 z                          {double}
177 scalar                     {double}
178 labelListElement           {space}{zeroLabel}
179 hexLabelListElement        {space}{hexLabel}
180 scalarListElement          {space}{double}
181 schemeSymbolListElement    {space}{schemeSymbol}
182 labelList                  ({labelListElement}+{space})
183 hexLabelList               ({hexLabelListElement}+{space})
184 scalarList                 ({scalarListElement}+{space})
185 schemeSymbolList           ({schemeSymbolListElement}+{space})
187 starStar                   ("**")
188 text                       ({space}({word}*{space})*)
189 anythingInBlock            ([^)]*)
190 gridgenComment             (({space}|{cspace})({word}*{space})*)
192 dateDDMMYYYY               ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
193 dateDDMonYYYY              ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
194 time                       ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
196 versionNumber              ({digit}|".")*
198 header                     {space}"(1"{space}
199 dimension                  {space}"(2"{space}
200 points                     {space}"(10"{space}
201 faces                      {space}"(13"{space}
202 cells                      {space}"(12"{space}
203 zoneVariant1               {space}"(39"{space}
204 zoneVariant2               {space}"(45"{space}
205 faceTree                   {space}"(59"{space}
207 comment                    "0"{space}
208 unknownPeriodicFace        "17"{space}
209 periodicFace               "18"{space}
210 cellTree                   "58"{space}
211 faceParents                "61"{space}
212 ignoreBlocks               ("4"|"37"|"38"|"40"|"41"|"60"|"64"){space}
214 redundantBlock             {space}({comment}|{unknownPeriodicFace}|{periodicFace}|{cellTree}|{faceParents}|{ignoreBlocks}){space}
216 endOfSection               {space}")"{space}
220  /* ------------------------------------------------------------------------ *\
221                       -----  Exclusive start states -----
222  \* ------------------------------------------------------------------------ */
224 %option stack
226 %x readHeader
227 %x readDimension
228 %x readPoint
229 %x readPointHeader
230 %x readNumberOfPoints
231 %x readPointGroupData
232 %x readPointData
233 %x readScalarList
234 %x fluentFace
235 %x readFaceHeader
236 %x readNumberOfFaces
237 %x readFaceGroupData
238 %x readFaceData
239 %x readFacesMixed
240 %x readFacesUniform
241 %x cell
242 %x readCellHeader
243 %x readNumberOfCells
244 %x readCellGroupData
245 %x readCellData
246 %x readCellsUniform
247 %x zone
248 %x readZoneHeader
249 %x readZoneGroupData
250 %x readZoneData
251 %x readZoneBlock
253 %x ignoreBlock
254 %x ignoreEmbeddedBlock
258     // End of read character pointer returned by strtol and strtod
259     char* endPtr;
261     // Point data
262     label pointGroupNumberOfComponents = 3;
263     label pointi = 0; // index used for reading points
264     label cmpt = 0;   // component index used for reading points
266     // Face data
267     label faceGroupElementType = -1;
268     label facei = 0;  // index used for reading faces
272  /* ------------------------------------------------------------------------ *\
273                             ------ Start Lexing ------
274  \* ------------------------------------------------------------------------ */
276  /*                      ------ Reading control header ------                */
278 {header} {
279         BEGIN(readHeader);
280     }
282 <readHeader>{anythingInBlock} {
283         Info<< "Header: " << YYText() << endl;
284     }
287 {dimension} {
288         BEGIN(readDimension);
289     }
291 <readDimension>{space}{label}{space} {
292         dimensionOfGrid = atoi(YYText());
293         Info<< "Dimension of grid: " << dimensionOfGrid << endl;
294     }
297 {points} {
298         BEGIN(readPointHeader);
299     }
301 <readPointHeader>{space}{lbrac}{space}"0"{space}"1"{space} {
302         BEGIN(readNumberOfPoints);
303     }
305 <readNumberOfPoints>{hexLabel}{space}{labelList} {
306         nPoints = strtol(YYText(), &endPtr, 16);
307         Info<< "Number of points: " << nPoints << endl;
308         points.setSize(nPoints);
310         // Ignore rest of stream
311     }
313 <readPointHeader>{space}{lbrac} {
314         BEGIN(readPointGroupData);
315     }
317 <readPointGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
318         // Read point zone-ID, start and end-label
319         // the indices will be used for checking later.
320         pointGroupZoneID.append(strtol(YYText(), &endPtr, 16));
322         // In FOAM, indices start from zero - adjust
323         pointGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
325         pointGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
327         // point group type skipped
328         strtol(endPtr, &endPtr, 16);
330         pointi = pointGroupStartIndex[pointGroupStartIndex.size()-1];
332         // reset number of components to default
333         pointGroupNumberOfComponents = 3;
335         // read number of components in the vector
336         if (endPtr < &(YYText()[YYLeng()-1]))
337         {
338             pointGroupNumberOfComponents = strtol(endPtr, &endPtr, 16);
339         }
341         Info<< "PointGroup: "
342             << pointGroupZoneID[pointGroupZoneID.size()-1]
343             << " start: "
344             << pointGroupStartIndex[pointGroupStartIndex.size()-1]
345             << " end: "
346             << pointGroupEndIndex[pointGroupEndIndex.size()-1]
347             << " nComponents: " << pointGroupNumberOfComponents << flush;
348     }
350 <readNumberOfPoints,readPointGroupData>{endOfSection} {
351         BEGIN(readPointData);
352     }
354 <readPointData>{space}{lbrac}{space} {
355         Info<< ".  Reading points..." << flush;
356         cmpt = 0;
357         yy_push_state(readScalarList);
358     }
360 <readScalarList>{signedInteger}{space} {
361         points[pointi][cmpt++] = scaleFactor*atol(YYText());
363         if (cmpt == pointGroupNumberOfComponents)
364         {
365             if (pointGroupNumberOfComponents == 2)
366             {
367                 points[pointi].z() = 0.0;
368             }
370             cmpt = 0;
371             pointi++;
372         }
373     }
375 <readScalarList>{scalar}{space} {
376         points[pointi][cmpt++] = scaleFactor*atof(YYText());
378         if (cmpt == pointGroupNumberOfComponents)
379         {
380             if (pointGroupNumberOfComponents == 2)
381             {
382                 points[pointi].z() = 0.0;
383             }
385             cmpt = 0;
386             pointi++;
387         }
388     }
390 <readScalarList>{endOfSection} {
391         Info<< "done." << endl;
393         // check read of points
394         if (pointi != pointGroupEndIndex[pointGroupEndIndex.size()-1]+1)
395         {
396             Warning
397                 << "Problem with reading points: " << nl
398                 << "    start index: "
399                 << pointGroupStartIndex[pointGroupStartIndex.size()-1]
400                 << " end index: "
401                 << pointGroupEndIndex[pointGroupEndIndex.size()-1]
402                 << " last points read: " << pointi << nl
403                 << "    on line " << lineNo << endl;
404         }
406         yy_pop_state();
407     }
409 {faces} {
410         BEGIN(readFaceHeader);
411     }
413 <readFaceHeader>{space}{lbrac}{space}"0"{space}"1"{space} {
414         BEGIN(readNumberOfFaces);
415     }
417 <readNumberOfFaces>{space}{hexLabel}{space}{labelListElement}+ {
418         nFaces = strtol(YYText(), &endPtr, 16);
420         Info<< "Number of faces: " << nFaces << endl;
422         faces.setSize(nFaces);
423         owner.setSize(nFaces);
424         neighbour.setSize(nFaces);
426         // Type and element type not read
427     }
429 <readFaceHeader>{space}{lbrac} {
430         BEGIN(readFaceGroupData);
431     }
433 <readFaceGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
434         // read fluentFace zone-ID, start and end-label
435         faceGroupZoneID.append(strtol(YYText(), &endPtr, 16));
437         // In FOAM, indices start from zero - adjust
438         faceGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
440         faceGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
442         // face group type
443         strtol(endPtr, &endPtr, 16);
445         faceGroupElementType = strtol(endPtr, &endPtr, 16);
447         facei = faceGroupStartIndex[faceGroupStartIndex.size()-1];
449         Info<< "FaceGroup: "
450             << faceGroupZoneID[faceGroupZoneID.size()-1]
451             << " start: "
452             << faceGroupStartIndex[faceGroupStartIndex.size()-1]
453             << " end: "
454             << faceGroupEndIndex[faceGroupEndIndex.size()-1] << flush;
455     }
457 <readNumberOfFaces,readFaceGroupData>{space}{endOfSection} {
458         BEGIN(readFaceData);
459     }
461 <readFaceData>{space}{lbrac} {
462         if (faceGroupElementType == 0 || faceGroupElementType > 4)
463         {
464             Info<< ".  Reading mixed faces..." << flush;
465             yy_push_state(readFacesMixed);
466         }
467         else
468         {
469             Info<< ".  Reading uniform faces..." << flush;
470             yy_push_state(readFacesUniform);
471         }
472     }
474 <readFacesMixed>{space}{hexLabelList} {
475         face& curFaceLabels = faces[facei];
477         // set size of label list
478         curFaceLabels.setSize(strtol(YYText(), &endPtr, 16));
480         forAll (curFaceLabels, i)
481         {
482             curFaceLabels[i] = strtol(endPtr, &endPtr, 16) - 1;
483         }
485         // read neighbour and owner. Neighbour comes first
486         neighbour[facei] = strtol(endPtr, &endPtr, 16) - 1;
487         owner[facei] = strtol(endPtr, &endPtr, 16) - 1;
488         facei++;
489     }
491 <readFacesUniform>{space}{hexLabelList} {
492         face& curFaceLabels = faces[facei];
494         // Set size of label list.
495         curFaceLabels.setSize(faceGroupElementType);
497         curFaceLabels[0] = strtol(YYText(), &endPtr, 16) - 1;
499         for (int i=1; i<faceGroupElementType; i++)
500         {
501             curFaceLabels[i] = strtol(endPtr, &endPtr, 16) - 1;
502         }
504         // read neighbour and owner. Neighbour comes first
505         neighbour[facei] = strtol(endPtr, &endPtr, 16) - 1;
506         owner[facei] = strtol(endPtr, &endPtr, 16) - 1;
507         facei++;
508     }
510 <readFacesMixed,readFacesUniform>{space}{endOfSection} {
511         Info<< "done." << endl;
513         // check read of fluentFaces
514         if (facei != faceGroupEndIndex[faceGroupEndIndex.size()-1]+1)
515         {
516             Warning
517                 << "Problem with reading fluentFaces: " << nl
518                 << "    start index: "
519                 << faceGroupStartIndex[faceGroupStartIndex.size()-1]
520                 << " end index: "
521                 << faceGroupEndIndex[faceGroupEndIndex.size()-1]
522                 << " last fluentFaces read: " << facei << nl
523                 << "    on line " << lineNo << endl;
524         }
526         yy_pop_state();
527     }
530 {cells} {
531         BEGIN(readCellHeader);
532     }
534 <readCellHeader>{space}{lbrac}{space}"0"{space}"1"{space} {
535         BEGIN(readNumberOfCells);
536     }
538 <readNumberOfCells>{space}{hexLabel}{space}{labelListElement}+ {
539         nCells = strtol(YYText(), &endPtr, 16);
540         Info<< "Number of cells: " << nCells << endl;
541     }
543 <readCellHeader>{space}{lbrac} {
544         BEGIN(readCellGroupData);
545     }
547 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
548         // Warning. This entry must be above the next one because of the lexing
549         // rules. It is introduced to deal with the problem of reading
550         // non-standard cell definition from Tgrid, which misses the type label.
552         Warning
553             << "Tgrid syntax problem: " << YYText() << nl
554             << "    on line " << lineNo << endl;
556         // read cell zone-ID, start and end-label
557         cellGroupZoneID.append(strtol(YYText(), &endPtr, 16));
559         // the indices will be used for checking later.
560         cellGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
562         cellGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
564         cellGroupType.append(strtol(endPtr, &endPtr, 16));
566         Info<< "CellGroup: "
567             << cellGroupZoneID[cellGroupZoneID.size()-1]
568             << " start: "
569             << cellGroupStartIndex[cellGroupStartIndex.size()-1]
570             << " end: "
571             << cellGroupEndIndex[cellGroupEndIndex.size()-1]
572             << " type: "
573             << cellGroupType[cellGroupType.size()-1]
574             << endl;
575     }
577 <readCellGroupData>{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
578         // Warning. See above
580         // read cell zone-ID, start and end-label
581         cellGroupZoneID.append(strtol(YYText(), &endPtr, 16));
583         // the indices will be used for checking later.
584         cellGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
586         cellGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
588         cellGroupType.append(strtol(endPtr, &endPtr, 16));
590         // Note. Potentially skip cell set if type is zero.
591         strtol(endPtr, &endPtr, 16);
593         Info<< "CellGroup: "
594             << cellGroupZoneID[cellGroupZoneID.size()-1]
595             << " start: "
596             << cellGroupStartIndex[cellGroupStartIndex.size()-1]
597             << " end: "
598             << cellGroupEndIndex[cellGroupEndIndex.size()-1]
599             << " type: "
600             << cellGroupType[cellGroupType.size()-1]
601             << endl;
602     }
604 <readNumberOfCells,readCellGroupData>{endOfSection} {
605         BEGIN(readCellData);
606     }
608 <readCellData>{space}{lbrac} {
609         // Quickly scan to the end of the cell data block and discard
610         register int c;
611         while ((c = yyinput()) != 0 && c != ')')
612         {}
613     }
615 {faceTree} {
616         // There are hanging nodes in the mesh so make sure it gets zipped-up
617         hangingNodes = true;
618         yy_push_state(ignoreBlock);
619     }
621 {zoneVariant1} {
622         BEGIN(readZoneHeader);
623     }
625 {zoneVariant2} {
626         BEGIN(readZoneHeader);
627     }
629 <readZoneHeader>{space}{lbrac} {
630         BEGIN(readZoneGroupData);
631     }
633 <readZoneGroupData>{space}{hexLabel}{space}{word}{space}{word}{space}{label}? {
634         IStringStream zoneDataStream(YYText());
636         // cell zone-ID not in hexadecimal!!! Inconsistency
637         label zoneID = -1;
639         if (cubitFile)
640         {
641             zoneID = readHexLabel(zoneDataStream);
642         }
643         else
644         {
645             zoneID = readLabel(zoneDataStream);
646         }
648         groupType.insert(zoneID, word(zoneDataStream));
649         groupName.insert(zoneID, word(zoneDataStream));
651         Info<< "Zone: " << zoneID
652             << " name: " << groupName[zoneID]
653             << " type: " << groupType[zoneID] << flush;
654     }
656 <readZoneGroupData>{endOfSection} {
657         BEGIN(readZoneData);
658     }
660 <readZoneData>{space}{lbrac} {
661         Info<< ".  Reading zone data..." << flush;
662         yy_push_state(readZoneBlock);
663     }
665 <readZoneBlock>{space}{schemeSymbolList} {
666     }
668 <readZoneBlock>{lbrac} {
669         //Warning
670         //    << "Found unknown block in zone: " << YYText() << nl
671         //    << "    on line " << lineNo << endl;
672         yy_push_state(ignoreBlock);
673     }
675 <readZoneBlock>{endOfSection} {
676         Info<< "done." << endl;
677         yy_pop_state();
678     }
682  /*             ------ Reading end of section and others ------              */
684 <readHeader,readDimension,readPointData,readFaceData,readCellData,readZoneData>{space}{endOfSection} {
685         BEGIN(INITIAL);
686     }
688  /*    ------ Reading unknown type or non-standard comment ------            */
690 {lbrac}{label} {
691         Warning
692             << "Found unknown block of type: "
693             << Foam::string(YYText())(1, YYLeng()-1) << nl
694             << "    on line " << lineNo << endl;
696         yy_push_state(ignoreBlock);
697     }
699 {lbrac}{redundantBlock} {
700         yy_push_state(ignoreBlock);
701     }
703 <ignoreBlock,ignoreEmbeddedBlock>{space}{quote}{text}{quote} {
704     }
706 <ignoreBlock,ignoreEmbeddedBlock>{space}{schemeSymbol} {
707     }
709 <ignoreBlock,ignoreEmbeddedBlock>{space}{lbrac} {
710         yy_push_state(ignoreEmbeddedBlock);
712     }
714 <ignoreBlock,ignoreEmbeddedBlock>{space}{endOfSection} {
715         yy_pop_state();
716     }
718 <ignoreBlock,ignoreEmbeddedBlock>{space}{labelList} {
719     }
721 <ignoreBlock,ignoreEmbeddedBlock>{space}{hexLabelList} {
722     }
724 <ignoreBlock,ignoreEmbeddedBlock>{space}{scalarList} {
725     }
727 <ignoreBlock,ignoreEmbeddedBlock>{space}{schemeSymbolList} {
728     }
730 <ignoreBlock,ignoreEmbeddedBlock>{space}{text} {
731     }
733 <ignoreBlock,ignoreEmbeddedBlock>{gridgenComment} {
734     }
737  /* ------              Count newlines.                              ------  */
739 <*>\n {
740         lineNo++;
741     }
744  /* ------              Ignore remaining space.                      ------  */
746 <*>{some_space}|\r {
747     }
750  /* ------              Any other characters are errors.              ------ */
752 <*>. {
753         // This is a catch all.
754         FatalErrorIn("fluentMeshToFoam::lexer")
755             << "Do not understand characters: " << YYText() << nl
756             << "    on line " << lineNo
757             << exit(FatalError);
758     }
761  /*  ------ On EOF return to previous file, if none exists terminate. ------ */
763 <<EOF>> {
764             yyterminate();
765     }
768 int main(int argc, char *argv[])
770     argList::noParallel();
771     argList::validArgs.append("Fluent mesh file");
772     argList::validOptions.insert("scale", "scale factor");
773     argList::validOptions.insert("ignoreCellGroups", "cell group names");
774     argList::validOptions.insert("ignoreFaceGroups", "face group names");
775     argList::validOptions.insert("cubit", "");
776     argList::validOptions.insert("exclude", "pattern");
778     argList args(argc, argv);
780     if (!args.check())
781     {
782         FatalError.exit();
783     }
785     args.optionReadIfPresent("scale", scaleFactor);
787     HashSet<word> ignoreCellGroups;
788     if (args.optionFound("ignoreCellGroups"))
789     {
790         args.optionLookup("ignoreCellGroups")() >> ignoreCellGroups;
791     }
793     HashSet<word> ignoreFaceGroups;
794     if (args.optionFound("ignoreFaceGroups"))
795     {
796         args.optionLookup("ignoreFaceGroups")() >> ignoreFaceGroups;
797     }
799     cubitFile = args.options().found("cubit");
801     if (cubitFile)
802     {
803         Info<< nl
804             << "Assuming Cubit generated file"
805             << " (incorrect face orientation; hexadecimal zoneIDs)."
806             << nl << endl;
807     }
809     Foam::Info<< "Create time\n" << Foam::endl;
811     Foam::Time runTime(args.rootPath(),args.caseName());
813     fileName fluentFile(args.additionalArgs()[0]);
814     IFstream fluentStream(fluentFile);
816     if (!fluentStream)
817     {
818         FatalErrorIn(args.executable())
819             << ": file " << fluentFile << " not found"
820             << exit(FatalError);
821     }
823     yyFlexLexer lexer(&fluentStream.stdStream());
825     while(lexer.yylex() != 0)
826     {}
828     Info<< "\nFINISHED LEXING\n\n";
830     if (dimensionOfGrid != 3)
831     {
832         FatalErrorIn(args.executable())
833             << "Mesh is not 3D, dimension of grid: " << dimensionOfGrid
834             << exit(FatalError);
835     }
837     pointGroupZoneID.shrink();
838     pointGroupStartIndex.shrink();
839     pointGroupEndIndex.shrink();
841     faceGroupZoneID.shrink();
842     faceGroupStartIndex.shrink();
843     faceGroupEndIndex.shrink();
845     cellGroupZoneID.shrink();
846     cellGroupStartIndex.shrink();
847     cellGroupEndIndex.shrink();
848     cellGroupType.shrink();
851     // Pre-filtering: flip "owner" boundary or wrong oriented internal
852     // faces and move to neighbour
854     boolList fm(faces.size(), false);
855     forAll (faces, facei)
856     {
857         if
858         (
859             owner[facei] == -1
860          || (neighbour[facei] != -1 && owner[facei] > neighbour[facei])
861         )
862         {
863             fm[facei] = true;
864             if (!cubitFile)
865             {
866                 faces[facei] = faces[facei].reverseFace();
867             }
868             Swap(owner[facei], neighbour[facei]);
869         }
870     }
873     // Foam type for Fluent type
874     // ~~~~~~~~~~~~~~~~~~~~~~~~~
876     HashTable<word> fluentToFoamType;
878     fluentToFoamType.insert("pressure", polyPatch::typeName);
879     fluentToFoamType.insert("pressure-inlet", polyPatch::typeName);
880     fluentToFoamType.insert("inlet-vent", polyPatch::typeName);
881     fluentToFoamType.insert("intake-fan", polyPatch::typeName);
882     fluentToFoamType.insert("pressure-outlet", polyPatch::typeName);
883     fluentToFoamType.insert("exhaust-fan", polyPatch::typeName);
884     fluentToFoamType.insert("outlet-vent", polyPatch::typeName);
885     fluentToFoamType.insert("pressure-far-field", polyPatch::typeName);
886     fluentToFoamType.insert("velocity-inlet", polyPatch::typeName);
887     fluentToFoamType.insert("mass-flow-inlet", polyPatch::typeName);
888     fluentToFoamType.insert("outflow", polyPatch::typeName);
890     fluentToFoamType.insert("wall" , wallPolyPatch::typeName);
892     fluentToFoamType.insert("symmetry",  symmetryPolyPatch::typeName);
893     fluentToFoamType.insert("axis",  symmetryPolyPatch::typeName);
895     fluentToFoamType.insert("interior", polyPatch::typeName);
896     fluentToFoamType.insert("interface", polyPatch::typeName);
897     fluentToFoamType.insert("internal", polyPatch::typeName);
898     fluentToFoamType.insert("solid", polyPatch::typeName);
899     fluentToFoamType.insert("fan", cyclicPolyPatch::typeName);
900     fluentToFoamType.insert("radiator", polyPatch::typeName);
901     fluentToFoamType.insert("porous-jump", polyPatch::typeName);
904     // Foam patch type for Fluent zone type
905     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
907     HashSet<word> fluentGroupToFoamPatch;
908     fluentGroupToFoamPatch.insert("wall");
909     fluentGroupToFoamPatch.insert("fan");
912     // Create intial empty polyMesh
913     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
915     polyMesh mesh
916     (
917         IOobject
918         (
919             polyMesh::defaultRegion,
920             runTime.constant(),
921             runTime
922         ),
923         xferCopy(pointField()),
924         xferCopy(faceList()),
925         xferCopy(labelList()),
926         xferCopy(labelList())
927     );
930     // Check the cell groups for zones ignoring those in ignoreCellGroups
931     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
932     label nCellZones = 0;
933     labelList cellZoneIDs(cellGroupZoneID.size());
935     forAll(cellGroupZoneID, cgi)
936     {
937         if (!ignoreCellGroups.found(groupName[cellGroupZoneID[cgi] ]))
938         {
939             cellZoneIDs[nCellZones++] = cgi;
940         }
941     }
943     cellZoneIDs.setSize(nCellZones);
946     // Check the face groups for boundary patches, baffles and faceZones
947     // ignoring the interior zones in ignoreCellGroups
948     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
949     DynamicList<label> patchIDs(faceGroupZoneID.size());
950     DynamicList<label> faceZoneIDs(faceGroupZoneID.size());
952     forAll(faceGroupZoneID, fgi)
953     {
954         label zoneID = faceGroupZoneID[fgi];
955         label start = faceGroupStartIndex[fgi];
957         if (groupType.found(zoneID))
958         {
959             const word& type = groupType[zoneID];
961             // Check the first element of neighbour for boundary group
962             if (neighbour[start] == -1 || fluentGroupToFoamPatch.found(type))
963             {
964                 patchIDs.append(fgi);
965             }
966             else
967             {
968                 if (!ignoreFaceGroups.found(groupName[faceGroupZoneID[fgi] ]))
969                 {
970                     faceZoneIDs.append(fgi);
971                 }
972             }
973         }
974         else if (hangingNodes)
975         {
976             label end = faceGroupEndIndex[fgi];
978             Info<< "Unknown FaceGroup " << zoneID
979                 << " assumed to be parent faces of refinement "
980                    "patterns and ignored."
981                 << endl;
983             // Set the owner of these faces to -1 so that they do not get
984             // added to the mesh
985             for(label facei = start; facei <= end; facei++)
986             {
987                 owner[facei] = -1;
988             }
989         }
990         else
991         {
992             if (neighbour[start] == -1)
993             {
994                 // Boundary face in unknown group. Create a patch for it.
995                 groupType.insert(zoneID, "unknown");
996                 groupName.insert(zoneID, "FaceGroup" + Foam::name(zoneID));
997                 patchIDs.append(fgi);
998                 Info<< "Created patch " << fgi << " for unknown FaceGroup "
999                     << zoneID << '.' << endl;
1000             }
1001             else
1002             {
1003                 WarningIn(args.executable())
1004                     << "Unknown FaceGroup " << zoneID << " not in a zone"
1005                     << endl;
1006             }
1007         }
1008     }
1010     patchIDs.shrink();
1011     faceZoneIDs.shrink();
1014     // Add empty patches
1015     // ~~~~~~~~~~~~~~~~~
1017     List<polyPatch*> newPatches(patchIDs.size());
1018     HashSet<word> patchNames;
1020     wordIOList zoneToPatchName
1021     (
1022         IOobject
1023         (
1024             "zoneToPatchName",
1025             runTime.constant(),
1026             mesh.meshSubDir,
1027             mesh,
1028             IOobject::NO_READ,
1029             IOobject::NO_WRITE
1030         ),
1031         wordList(max(faceGroupZoneID) + 1, "unknown")
1032     );
1034     forAll(patchIDs, patchi)
1035     {
1036         label zoneID = faceGroupZoneID[patchIDs[patchi] ];
1037         word name = groupName[zoneID];
1038         const word& type = groupType[zoneID];
1040         Info<< "Creating patch " << patchi
1041             << " for zone: " << zoneID
1042             << " name: " << name
1043             << " type: " << type
1044             << endl;
1046         zoneToPatchName[zoneID] = name;
1048         uniquify(name, patchNames);
1050         HashTable<word>::const_iterator iter = fluentToFoamType.find(type);
1052         if (iter != fluentToFoamType.end())
1053         {
1054             newPatches[patchi] = polyPatch::New
1055             (
1056                 iter(),
1057                 name,
1058                 0,
1059                 0,
1060                 patchi,
1061                 mesh.boundaryMesh()
1062             ).ptr();
1063         }
1064         else
1065         {
1066             Info<< "Adding polyPatch for unknown Fluent type " << type
1067                 << endl;
1069             newPatches[patchi] = new polyPatch
1070             (
1071                 name,
1072                 0,
1073                 0,
1074                 patchi,
1075                 mesh.boundaryMesh()
1076             );
1077         }
1078     }
1079     mesh.addPatches(newPatches);
1082     // Add empty zones
1083     // ~~~~~~~~~~~~~~~
1085     // Cell zones
1086     mesh.cellZones().setSize(cellZoneIDs.size());
1087     HashSet<word> cellZoneNames;
1089     forAll(cellZoneIDs, cellZonei)
1090     {
1091         label zoneID = cellGroupZoneID[cellZoneIDs[cellZonei] ];
1092         word name = groupName[zoneID];
1093         const word& type = groupType[zoneID];
1095         Info<< "Creating cellZone " << cellZonei
1096             << " name: " << name
1097             << " type: " << type
1098             << endl;
1100         uniquify(name, cellZoneNames);
1102         mesh.cellZones().set
1103         (
1104             cellZonei,
1105             new cellZone
1106             (
1107                 name,
1108                 labelList(0),
1109                 cellZonei,
1110                 mesh.cellZones()
1111             )
1112         );
1113     }
1115     // Face zones
1116     mesh.faceZones().setSize(faceZoneIDs.size());
1117     HashSet<word> faceZoneNames;
1119     forAll(faceZoneIDs, faceZonei)
1120     {
1121         label zoneID = faceGroupZoneID[faceZoneIDs[faceZonei] ];
1122         word name = groupName[zoneID];
1123         const word& type = groupType[zoneID];
1125         Info<< "Creating faceZone " << faceZonei
1126             << " name: " << name
1127             << " type: " << type
1128             << endl;
1130         uniquify(name, faceZoneNames);
1132         mesh.faceZones().set
1133         (
1134             faceZonei,
1135             new faceZone
1136             (
1137                 name,
1138                 labelList(0),
1139                 boolList(0),
1140                 faceZonei,
1141                 mesh.faceZones()
1142             )
1143         );
1144     }
1147     // Modify mesh for points/cells/faces
1148     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1150     // Mesh-change container
1151     directTopoChange meshMod(mesh, false);
1153     // Add all points
1154     forAll(points, pointi)
1155     {
1156         meshMod.addPoint(points[pointi], pointi, -1, true);
1157     }
1158     points.setSize(0);
1160     // Add all cells
1161     for (label celli = 0; celli < nCells; celli++)
1162     {
1163         meshMod.addCell
1164         (
1165             -1,         // masterPointID
1166             -1,         // masterEdgeID
1167             -1,         // masterFaceID
1168             celli,      // masterCellID
1169             -1          // zoneID
1170         );
1171     }
1173     // Modify cells to be in zones as required
1174     forAll(cellZoneIDs, cellZonei)
1175     {
1176         label cgi = cellZoneIDs[cellZonei];
1178         for
1179         (
1180             label celli = cellGroupStartIndex[cgi];
1181             celli <= cellGroupEndIndex[cgi];
1182             celli++
1183         )
1184         {
1185             meshMod.modifyCell(celli, cellZonei);
1186         }
1187     }
1190     bool doneWarning = false;
1192     // Add faceZone faces
1193     forAll(faceZoneIDs, faceZonei)
1194     {
1195         label fgi = faceZoneIDs[faceZonei];
1196         label start = faceGroupStartIndex[fgi];
1197         label end = faceGroupEndIndex[fgi];
1198         label zoneID = faceGroupZoneID[fgi];
1200         Info<< "faceZone from Fluent indices: " << start
1201             << " to: " << end
1202             << " type: " << groupType[zoneID]
1203             << endl;
1205         for (label facei = start; facei <= end; facei++)
1206         {
1207             if (owner[facei] >= nCells || neighbour[facei] >= nCells)
1208             {
1209                 if (!doneWarning)
1210                 {
1211                     WarningIn(args.executable())
1212                         << "Ignoring internal face " << facei
1213                         << " on FaceZone " << zoneID
1214                         << " since owner " << owner[facei] << " or neighbour "
1215                         << neighbour[facei] << " outside range of cells 0.."
1216                         << nCells-1 << endl
1217                         << "    Suppressing future warnings." << endl;
1218                     doneWarning = true;
1219                 }
1220             }
1221             else
1222             {
1223                 meshMod.addFace
1224                 (
1225                     faces[facei],
1226                     owner[facei],
1227                     neighbour[facei],
1228                     -1,                 // masterPointID
1229                     -1,                 // masterEdgeID
1230                     facei,              // masterFace
1231                     false,              // flipFaceFlux
1232                     -1,                 // patchID
1233                     faceZonei,          // zoneID
1234                     false               // zoneFlip
1235                 );
1236             }
1238             // Mark face as being done
1239             owner[facei] = -1;
1240         }
1241     }
1243     // Add patch faces
1244     forAll(patchIDs, patchi)
1245     {
1246         label fgi = patchIDs[patchi];
1247         label start = faceGroupStartIndex[fgi];
1248         label end = faceGroupEndIndex[fgi];
1249         label zoneID = faceGroupZoneID[fgi];
1251         Info<< "patch " << patchi << " from Fluent indices: " << start
1252             << " to: " << end
1253             << " type: " << groupType[zoneID]
1254             << endl;
1256         for (label facei = start; facei <= end; facei++)
1257         {
1258             if (owner[facei] >= nCells || neighbour[facei] >= nCells)
1259             {
1260                 if (!doneWarning)
1261                 {
1262                     WarningIn(args.executable())
1263                         << "Ignoring patch face " << facei
1264                         << " on FaceZone " << zoneID
1265                         << " since owner " << owner[facei] << " or neighbour "
1266                         << neighbour[facei] << " outside range of cells 0.."
1267                         << nCells-1 << endl
1268                         << "    Suppressing future warnings." << endl;
1269                     doneWarning = true;
1270                 }
1271             }
1272             else
1273             {
1274                 meshMod.addFace
1275                 (
1276                     faces[facei],
1277                     owner[facei],
1278                     -1,
1279                     -1,                 // masterPointID
1280                     -1,                 // masterEdgeID
1281                     facei,              // masterFace
1282                     false,              // flipFaceFlux
1283                     patchi,             // patchID
1284                     -1,                 // zoneID
1285                     false               // zoneFlip
1286                 );
1288                 // For baffles create the opposite face
1289                 if (neighbour[start] != -1)
1290                 {
1291                     meshMod.addFace
1292                     (
1293                         faces[facei].reverseFace(),
1294                         neighbour[facei],
1295                         -1,
1296                         -1,                 // masterPointID
1297                         -1,                 // masterEdgeID
1298                         facei,              // masterFace
1299                         false,              // flipFaceFlux
1300                         patchi,             // patchID
1301                         -1,                 // zoneID
1302                         false               // zoneFlip
1303                     );
1304                 }
1305             }
1306             // Mark face as being done
1307             owner[facei] = -1;
1308         }
1309     }
1311     // Add remaining internal faces
1312     forAll(owner, facei)
1313     {
1314         if (owner[facei] != -1)
1315         {
1316             // Check the face being added as an internal face actually is one
1317             if (neighbour[facei] == -1)
1318             {
1319                 FatalErrorIn(args.executable())
1320                     << "Attempt of add internal face " << facei
1321                     << " which is a boundary face"
1322                     << exit(FatalError);
1323             }
1325             if (owner[facei] >= nCells || neighbour[facei] >= nCells)
1326             {
1327                 if (!doneWarning)
1328                 {
1329                     WarningIn(args.executable())
1330                         << "Ignoring internal face " << facei
1331                         << " since owner " << owner[facei] << " or neighbour "
1332                         << neighbour[facei] << " outside range of cells 0.."
1333                         << nCells-1 << endl
1334                         << "    Suppressing future warnings." << endl;
1335                     doneWarning = true;
1336                 }
1337             }
1338             else
1339             {
1340                 meshMod.addFace
1341                 (
1342                     faces[facei],
1343                     owner[facei],
1344                     neighbour[facei],
1345                     -1,                 //masterPointID
1346                     -1,                 //masterEdgeID
1347                     facei,              //masterFace
1348                     false,              //flipFaceFlux
1349                     -1,                 //patchID
1350                     -1,                 //zoneID
1351                     false               //zoneFlip
1352                 );
1353             }
1354         }
1355     }
1357     // Reclaim storage
1358     faces.setSize(0);
1359     owner.setSize(0);
1360     neighbour.setSize(0);
1363     // Modify mesh
1364     // ~~~~~~~~~~~
1366     autoPtr<mapPolyMesh> map = meshMod.changeMesh(mesh, false);
1368     // Zip-up the mesh if it contained hanging nodes
1369     if (hangingNodes)
1370     {
1371         Info<< "Zipping mesh to remove hanging nodes" << endl;
1372         polyMeshZipUpCells(mesh);
1373     }
1375     mesh.setInstance(runTime.constant());
1377     wordRe excludePattern;
1378     args.optionReadIfPresent("exclude", excludePattern);
1379     Info<<"Exclude pattern: \"" << excludePattern << "\"." <<endl;
1380     excludePattern.compile(wordRe::DETECT_NOCASE);
1382     Info<< nl << "Writing Elmer mesh ..." << endl;
1383     meshWriters::Elmer writer(mesh, excludePattern, scaleFactor);
1384     writer.write("elmerMesh");
1385     Info<< nl << "End" << endl;
1387     return 0;
1391  /* ------------------------------------------------------------------------ *\
1392     ------ End of fluentMeshToFoam.L
1393  \* ------------------------------------------------------------------------ */