diff --git a/Allwclean b/Allwclean
index 1f55d569..3284d8aa 100755
--- a/Allwclean
+++ b/Allwclean
@@ -19,6 +19,7 @@ wclean ./src/dfCanteraMixture
wclean ./src/dfMeshTools
wclean ./applications/utilities/flameSpeed
wclean ./applications/utilities/dfAutoPatch
+wclean ./applications/utilities/dfFluent3DMeshToFoam
wclean ./applications/solvers/dfSprayFoam
wclean ./applications/solvers/df0DFoam
wclean ./applications/solvers/dfLowMachFoam
diff --git a/Allwmake b/Allwmake
index 74136b06..dab0a5ca 100755
--- a/Allwmake
+++ b/Allwmake
@@ -30,3 +30,4 @@ wmake applications/solvers/dfSteadyFoam
wmake applications/utilities/flameSpeed
wmake applications/utilities/dfAutoPatch
+wmake applications/utilities/dfFluent3DMeshToFoam
diff --git a/applications/utilities/dfFluent3DMeshToFoam/Make/files b/applications/utilities/dfFluent3DMeshToFoam/Make/files
new file mode 100644
index 00000000..24de36d2
--- /dev/null
+++ b/applications/utilities/dfFluent3DMeshToFoam/Make/files
@@ -0,0 +1,3 @@
+fluent3DMeshToFoam.L
+
+EXE = $(DF_APPBIN)/dfFluent3DMeshToFoam
diff --git a/applications/utilities/dfFluent3DMeshToFoam/Make/options b/applications/utilities/dfFluent3DMeshToFoam/Make/options
new file mode 100644
index 00000000..70c838b7
--- /dev/null
+++ b/applications/utilities/dfFluent3DMeshToFoam/Make/options
@@ -0,0 +1,7 @@
+EXE_INC = \
+ -I$(LIB_SRC)/meshTools/lnInclude \
+ -I$(LIB_SRC)/dynamicMesh/lnInclude
+
+EXE_LIBS = \
+ -lmeshTools \
+ -ldynamicMesh
diff --git a/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.C b/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.C
new file mode 100644
index 00000000..d99f8f58
--- /dev/null
+++ b/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.C
@@ -0,0 +1,30 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Copyright (C) 2018 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+Application
+ fluent3DMeshToFoam
+
+Description
+ Converts a Fluent mesh to OpenFOAM format.
+
+\*---------------------------------------------------------------------------*/
diff --git a/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.L b/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.L
new file mode 100644
index 00000000..86353d51
--- /dev/null
+++ b/applications/utilities/dfFluent3DMeshToFoam/fluent3DMeshToFoam.L
@@ -0,0 +1,1446 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration | Website: https://openfoam.org
+ \\ / A nd | Copyright (C) 2011-2019 OpenFOAM Foundation
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenFOAM. If not, see .
+
+\*---------------------------------------------------------------------------*/
+
+%{
+#undef yyFlexLexer
+
+ /* ------------------------------------------------------------------------ *\
+ ------ local definitions
+ \* ------------------------------------------------------------------------ */
+
+#include "cyclicPolyPatch.H"
+#include "argList.H"
+#include "Time.H"
+#include "polyMesh.H"
+#include "polyTopoChange.H"
+#include "polyMeshZipUpCells.H"
+#include "wallPolyPatch.H"
+#include "symmetryPolyPatch.H"
+#include "oldCyclicPolyPatch.H"
+#include "Swap.H"
+#include "IFstream.H"
+#include "readHexLabel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Line number
+label lineNo = 1;
+
+// Scale factor used to scale points (optional command line argument)
+scalar scaleFactor = 1.0;
+
+label dimensionOfGrid = 0;
+label nPoints = 0;
+label nFaces = 0;
+label nCells = 0;
+
+bool hangingNodes = false;
+
+pointField points(0);
+faceList faces(0);
+labelList owner(0);
+labelList neighbour(0);
+
+// Group type and name
+Map groupType(100);
+Map groupName(100);
+
+// Point groups
+DynamicList pointGroupZoneID;
+DynamicList pointGroupStartIndex;
+DynamicList pointGroupEndIndex;
+
+// Face groups
+DynamicList faceGroupZoneID;
+DynamicList faceGroupStartIndex;
+DynamicList faceGroupEndIndex;
+
+// Cell groups
+DynamicList cellGroupZoneID;
+DynamicList cellGroupStartIndex;
+DynamicList cellGroupEndIndex;
+DynamicList cellGroupType;
+
+// Special parsing of (incorrect) Cubit files
+bool cubitFile = false;
+
+
+void uniquify(word& name, HashSet& patchNames)
+{
+ if (!patchNames.found(name))
+ {
+ patchNames.insert(name);
+ }
+ else
+ {
+ Info<< " name " << name << " already used";
+
+ label i = 1;
+ word baseName = name;
+
+ do
+ {
+ name = baseName + "_" + Foam::name(i++);
+ } while (patchNames.found(name));
+
+ Info<< ", changing to " << name << endl;
+ }
+}
+
+
+// Dummy yywrap to keep yylex happy at compile time.
+// It is called by yylex but is not used as the mechanism to change file.
+// See <>
+#if YY_FLEX_MINOR_VERSION < 6 && YY_FLEX_SUBMINOR_VERSION < 34
+extern "C" int yywrap()
+#else
+int yyFlexLexer::yywrap()
+#endif
+{
+ return 1;
+}
+
+%}
+
+one_space [ \t\f]
+space {one_space}*
+some_space {one_space}+
+
+alpha [_[:alpha:]]
+digit [[:digit:]]
+decDigit [[:digit:]]
+octalDigit [0-7]
+hexDigit [[:xdigit:]]
+
+lbrac "("
+rbrac ")"
+quote \"
+dash "-"
+dotColonDash [.:-]
+commaPipe [,\|]
+
+schemeSpecialInitial [!$%&*/\\:<=>?~_^#.@']
+schemeSpecialSubsequent [.+-]
+schemeSymbol (({some_space}|{alpha}|{quote}|{schemeSpecialInitial})({alpha}|{quote}|{digit}|{schemeSpecialInitial}|{schemeSpecialSubsequent})*)
+
+
+identifier {alpha}({alpha}|{digit})*
+integer {decDigit}+
+label [1-9]{decDigit}*
+hexLabel {hexDigit}+
+zeroLabel {digit}*
+signedInteger [-+]?{integer}
+word ({alpha}|{digit}|{dotColonDash})*
+wordBraces ({word}|{lbrac}|{rbrac})*
+wordBracesExtras ({word}|{lbrac}|{rbrac}|{commaPipe})*
+
+exponent_part [eE][-+]?{digit}+
+fractional_constant [-+]?(({digit}*"."{digit}+)|({digit}+".")|({digit}))
+
+double ((({fractional_constant}{exponent_part}?)|({digit}+{exponent_part}))|0)
+
+x {double}
+y {double}
+z {double}
+scalar {double}
+labelListElement {space}{zeroLabel}
+hexLabelListElement {space}{hexLabel}
+scalarListElement {space}{double}
+schemeSymbolListElement {space}{schemeSymbol}
+labelList ({labelListElement}+{space})
+hexLabelList ({hexLabelListElement}+{space})
+scalarList ({scalarListElement}+{space})
+schemeSymbolList ({schemeSymbolListElement}+{space})
+
+starStar ("**")
+text ({space}({word}*{space})*)
+textBraces ({space}({wordBraces}*{space})*)
+textExtras ({space}({word}*{commaPipe}{space})*)
+textBracesExtras ({space}({wordBracesExtras}*{space})*)
+anythingInBlock ([^)]*)
+
+dateDDMMYYYY ({digit}{digit}"/"{digit}{digit}"/"{digit}{digit}{digit}{digit})
+dateDDMonYYYY ((({digit}{digit}{space})|({digit}{space})){alpha}*{space}{digit}{digit}{digit}{digit})
+time ({digit}{digit}":"{digit}{digit}":"{digit}{digit})
+
+versionNumber ({digit}|".")*
+
+header {space}"(1"{space}
+dimension {space}"(2"{space}
+points {space}"(10"{space}
+faces {space}"(13"{space}
+cells {space}"(12"{space}
+zoneVariant1 {space}"(39"{space}
+zoneVariant2 {space}"(45"{space}
+faceTree {space}"(59"{space}
+
+comment "0"{space}
+unknownPeriodicFace "17"{space}
+periodicFace "18"{space}
+cellTree "58"{space}
+faceParents "61"{space}
+ignoreBlocks ("4"|"37"|"38"|"40"|"41"|"60"|"64"){space}
+
+redundantBlock {space}({comment}|{unknownPeriodicFace}|{periodicFace}|{cellTree}|{faceParents}|{ignoreBlocks}){space}
+
+endOfSection {space}")"{space}
+
+
+
+ /* ------------------------------------------------------------------------ *\
+ ----- Exclusive start states -----
+ \* ------------------------------------------------------------------------ */
+
+%option stack
+
+%x readHeader
+%x readDimension
+%x readPoint
+%x readPointHeader
+%x readNumberOfPoints
+%x readPointGroupData
+%x readPointData
+%x readScalarList
+%x fluentFace
+%x readFaceHeader
+%x readNumberOfFaces
+%x readFaceGroupData
+%x readFaceData
+%x readFacesMixed
+%x readFacesUniform
+%x cell
+%x readCellHeader
+%x readNumberOfCells
+%x readCellGroupData
+%x readCellData
+%x readCellsUniform
+%x zone
+%x readZoneHeader
+%x readZoneGroupData
+%x readZoneData
+%x readZoneBlock
+
+%x ignoreBlock
+%x ignoreEmbeddedBlock
+%%
+
+%{
+ // End of read character pointer returned by strtol and strtod
+ char* endPtr;
+
+ // Point data
+ label pointGroupNumberOfComponents = 3;
+ label pointi = 0; // index used for reading points
+ label cmpt = 0; // component index used for reading points
+
+ // Face data
+ label faceGroupElementType = -1;
+ label facei = 0; // index used for reading faces
+%}
+
+
+ /* ------------------------------------------------------------------------ *\
+ ------ Start Lexing ------
+ \* ------------------------------------------------------------------------ */
+
+ /* ------ Reading control header ------ */
+
+{header} {
+ BEGIN(readHeader);
+ }
+
+{quote}{textBracesExtras}{quote} {
+ Info<< "Reading header: " << YYText() << endl;
+ }
+
+{dimension} {
+ BEGIN(readDimension);
+ }
+
+{space}{label}{space} {
+ dimensionOfGrid = atoi(YYText());
+ Info<< "Dimension of grid: " << dimensionOfGrid << endl;
+ }
+
+
+{points} {
+ BEGIN(readPointHeader);
+ }
+
+{space}{lbrac}{space}"0"{space}"1"{space} {
+ BEGIN(readNumberOfPoints);
+ }
+
+{hexLabel}{space}{labelList} {
+ nPoints = strtol(YYText(), &endPtr, 16);
+ Info<< "Number of points: " << nPoints << endl;
+ points.setSize(nPoints);
+
+ // Ignore rest of stream
+ }
+
+{space}{lbrac} {
+ BEGIN(readPointGroupData);
+ }
+
+{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{labelList} {
+ // Read point zone-ID, start and end-label
+ // the indices will be used for checking later.
+ pointGroupZoneID.append(strtol(YYText(), &endPtr, 16));
+
+ // In FOAM, indices start from zero - adjust
+ pointGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ pointGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ // point group type skipped
+ (void)strtol(endPtr, &endPtr, 16);
+
+ pointi = pointGroupStartIndex.last();
+
+ // reset number of components to default
+ pointGroupNumberOfComponents = 3;
+
+ // read number of components in the vector
+ if (endPtr < &(YYText()[YYLeng()-1]))
+ {
+ pointGroupNumberOfComponents = strtol(endPtr, &endPtr, 16);
+ }
+
+ Info<< "PointGroup: "
+ << pointGroupZoneID.last()
+ << " start: "
+ << pointGroupStartIndex.last()
+ << " end: "
+ << pointGroupEndIndex.last() << flush;
+ }
+
+{endOfSection} {
+ BEGIN(readPointData);
+ }
+
+{space}{lbrac}{space} {
+ Info<< ". Reading points..." << flush;
+ cmpt = 0;
+ yy_push_state(readScalarList);
+ }
+
+{signedInteger}{space} {
+ points[pointi][cmpt++] = scaleFactor*atol(YYText());
+
+ if (cmpt == pointGroupNumberOfComponents)
+ {
+ if (pointGroupNumberOfComponents == 2)
+ {
+ points[pointi].z() = 0.0;
+ }
+
+ cmpt = 0;
+ pointi++;
+ }
+ }
+
+{scalar}{space} {
+ points[pointi][cmpt++] = scaleFactor*atof(YYText());
+
+ if (cmpt == pointGroupNumberOfComponents)
+ {
+ if (pointGroupNumberOfComponents == 2)
+ {
+ points[pointi].z() = 0.0;
+ }
+
+ cmpt = 0;
+ pointi++;
+ }
+ }
+
+{endOfSection} {
+ Info<< "done." << endl;
+
+ // check read of points
+ if (pointi != pointGroupEndIndex.last()+1)
+ {
+ Warning
+ << "Problem with reading points: " << nl
+ << " start index: "
+ << pointGroupStartIndex.last()
+ << " end index: "
+ << pointGroupEndIndex.last()
+ << " last points read: " << pointi << nl
+ << " on line " << lineNo << endl;
+ }
+
+ yy_pop_state();
+ }
+
+{faces} {
+ BEGIN(readFaceHeader);
+ }
+
+{space}{lbrac}{space}"0"{space}"1"{space} {
+ BEGIN(readNumberOfFaces);
+ }
+
+{space}{hexLabel}{space}{labelListElement}+ {
+ nFaces = strtol(YYText(), &endPtr, 16);
+
+ Info<< "Number of faces: " << nFaces << endl;
+
+ faces.setSize(nFaces);
+ owner.setSize(nFaces);
+ neighbour.setSize(nFaces);
+
+ // Type and element type not read
+ }
+
+{space}{lbrac} {
+ BEGIN(readFaceGroupData);
+ }
+
+{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{hexLabelListElement}+ {
+ // read fluentFace zone-ID, start and end-label
+ faceGroupZoneID.append(strtol(YYText(), &endPtr, 16));
+
+ // In FOAM, indices start from zero - adjust
+ faceGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ faceGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ // face group type
+ (void)strtol(endPtr, &endPtr, 16);
+
+ faceGroupElementType = strtol(endPtr, &endPtr, 16);
+
+ facei = faceGroupStartIndex.last();
+
+ Info<< "FaceGroup: "
+ << faceGroupZoneID.last()
+ << " start: "
+ << faceGroupStartIndex.last()
+ << " end: "
+ << faceGroupEndIndex.last() << flush;
+ }
+
+{space}{endOfSection} {
+ BEGIN(readFaceData);
+ }
+
+{space}{lbrac} {
+ if (faceGroupElementType == 0 || faceGroupElementType > 4)
+ {
+ Info<< ". Reading mixed faces..." << flush;
+ yy_push_state(readFacesMixed);
+ }
+ else
+ {
+ Info<< ". Reading uniform faces..." << flush;
+ yy_push_state(readFacesUniform);
+ }
+ }
+
+{space}{hexLabelList} {
+ face& curFaceLabels = faces[facei];
+
+ // set size of label list
+ curFaceLabels.setSize(strtol(YYText(), &endPtr, 16));
+
+ forAll(curFaceLabels, i)
+ {
+ curFaceLabels[i] = strtol(endPtr, &endPtr, 16) - 1;
+ }
+
+ // read neighbour and owner. Neighbour comes first
+ neighbour[facei] = strtol(endPtr, &endPtr, 16) - 1;
+ owner[facei] = strtol(endPtr, &endPtr, 16) - 1;
+ facei++;
+ }
+
+{space}{hexLabelList} {
+ face& curFaceLabels = faces[facei];
+
+ // Set size of label list.
+ curFaceLabels.setSize(faceGroupElementType);
+
+ curFaceLabels[0] = strtol(YYText(), &endPtr, 16) - 1;
+
+ for (int i=1; i{space}{endOfSection} {
+ Info<< "done." << endl;
+
+ // check read of fluentFaces
+ if (facei != faceGroupEndIndex.last()+1)
+ {
+ Warning
+ << "Problem with reading fluentFaces: " << nl
+ << " start index: "
+ << faceGroupStartIndex.last()
+ << " end index: "
+ << faceGroupEndIndex.last()
+ << " last fluentFaces read: " << facei << nl
+ << " on line " << lineNo << endl;
+ }
+
+ yy_pop_state();
+ }
+
+
+{cells} {
+ BEGIN(readCellHeader);
+ }
+
+{space}{lbrac}{space}"0"{space}"1"{space} {
+ BEGIN(readNumberOfCells);
+ }
+
+{space}{hexLabel}{space}{labelListElement}+ {
+ nCells = strtol(YYText(), &endPtr, 16);
+ Info<< "Number of cells: " << nCells << endl;
+ }
+
+{space}{lbrac} {
+ BEGIN(readCellGroupData);
+ }
+
+{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
+ // Warning. This entry must be above the next one because of the lexing
+ // rules. It is introduced to deal with the problem of reading
+ // non-standard cell definition from Tgrid, which misses the type label.
+
+ Warning
+ << "Tgrid syntax problem: " << YYText() << nl
+ << " on line " << lineNo << endl;
+
+ // read cell zone-ID, start and end-label
+ cellGroupZoneID.append(strtol(YYText(), &endPtr, 16));
+
+ // the indices will be used for checking later.
+ cellGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ cellGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ cellGroupType.append(strtol(endPtr, &endPtr, 16));
+
+ Info<< "CellGroup: "
+ << cellGroupZoneID.last()
+ << " start: "
+ << cellGroupStartIndex.last()
+ << " end: "
+ << cellGroupEndIndex.last()
+ << " type: "
+ << cellGroupType.last()
+ << endl;
+ }
+
+{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel}{space}{hexLabel} {
+ // Warning. See above
+
+ // read cell zone-ID, start and end-label
+ cellGroupZoneID.append(strtol(YYText(), &endPtr, 16));
+
+ // the indices will be used for checking later.
+ cellGroupStartIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ cellGroupEndIndex.append(strtol(endPtr, &endPtr, 16) - 1);
+
+ cellGroupType.append(strtol(endPtr, &endPtr, 16));
+
+ // Note. Potentially skip cell set if type is zero.
+ (void)strtol(endPtr, &endPtr, 16);
+
+ Info<< "CellGroup: "
+ << cellGroupZoneID.last()
+ << " start: "
+ << cellGroupStartIndex.last()
+ << " end: "
+ << cellGroupEndIndex.last()
+ << " type: "
+ << cellGroupType.last()
+ << endl;
+ }
+
+{endOfSection} {
+ BEGIN(readCellData);
+ }
+
+{space}{lbrac} {
+ // Quickly scan to the end of the cell data block and discard
+ int c;
+ while ((c = yyinput()) != 0 && c != ')')
+ {}
+ }
+
+{faceTree} {
+ // There are hanging nodes in the mesh so make sure it gets zipped-up
+ hangingNodes = true;
+ yy_push_state(ignoreBlock);
+ }
+
+{zoneVariant1} {
+ BEGIN(readZoneHeader);
+ }
+
+{zoneVariant2} {
+ BEGIN(readZoneHeader);
+ }
+
+{space}{lbrac} {
+ BEGIN(readZoneGroupData);
+ }
+
+{space}{hexLabel}{space}{word}{space}{word}{space}{label}? {
+ IStringStream zoneDataStream(YYText());
+
+ // cell zone-ID not in hexadecimal!!! Inconsistency
+ label zoneID = -1;
+
+ if (cubitFile)
+ {
+ zoneID = readHexLabel(zoneDataStream);
+ }
+ else
+ {
+ zoneID = readLabel(zoneDataStream);
+ }
+
+ groupType.insert(zoneID, word(zoneDataStream));
+ groupName.insert(zoneID, word(zoneDataStream));
+
+ Info<< "Zone: " << zoneID
+ << " name: " << groupName[zoneID]
+ << " type: " << groupType[zoneID] << flush;
+ }
+
+{endOfSection} {
+ BEGIN(readZoneData);
+ }
+
+{space}{lbrac} {
+ Info<< ". Reading zone data..." << flush;
+ yy_push_state(readZoneBlock);
+ }
+
+{space}{schemeSymbolList} {
+ }
+
+{lbrac} {
+ // Warning
+ // << "Found unknown block in zone: " << YYText() << nl
+ // << " on line " << lineNo << endl;
+ yy_push_state(ignoreBlock);
+ }
+
+{endOfSection} {
+ Info<< "done." << endl;
+ yy_pop_state();
+ }
+
+
+
+ /* ------ Reading end of section and others ------ */
+
+{space}{endOfSection} {
+ BEGIN(INITIAL);
+ }
+
+ /* ------ Reading unknown type or non-standard comment ------ */
+
+{lbrac}{label} {
+ Warning
+ << "Found unknown block of type: "
+ << Foam::string(YYText())(1, YYLeng()-1) << nl
+ << " on line " << lineNo << endl;
+
+ yy_push_state(ignoreBlock);
+ }
+
+{lbrac}{redundantBlock} {
+ yy_push_state(ignoreBlock);
+ }
+
+{lbrac}{alpha}[^ \t\n\r\f()]* {
+ // Handles scheme-style blocks with alphabetic names, e.g. (cad/adv-options ...)
+ yy_push_state(ignoreBlock);
+ }
+
+{space}{quote}{text}{quote} {
+ }
+
+{space}{schemeSymbol} {
+ }
+
+{space}{lbrac} {
+ yy_push_state(ignoreEmbeddedBlock);
+
+ }
+
+"[" {
+ // Handle Scheme-style square bracket blocks
+ yy_push_state(ignoreEmbeddedBlock);
+ }
+
+"]" {
+ yy_pop_state();
+ }
+
+{space}{endOfSection} {
+ yy_pop_state();
+ }
+
+{space}{labelList} {
+ }
+
+{space}{hexLabelList} {
+ }
+
+{space}{scalarList} {
+ }
+
+{space}{schemeSymbolList} {
+ }
+
+{space}{text} {
+ }
+
+{space}{textExtras} {
+ }
+
+ /* ------ Count newlines. ------ */
+
+<*>\n {
+ lineNo++;
+ }
+
+
+ /* ------ Ignore remaining space. ------ */
+
+<*>{some_space}|\r {
+ }
+
+
+ /* ------ Any other characters are errors. ------ */
+
+<*>. {
+ // This is a catch all.
+ FatalErrorInFunction
+ << "Do not understand characters: " << YYText() << nl
+ << " on line " << lineNo
+ << exit(FatalError);
+ }
+
+
+ /* ------ On EOF return to previous file, if none exists terminate. ------ */
+
+<> {
+ yyterminate();
+ }
+%%
+
+int main(int argc, char *argv[])
+{
+ argList::noParallel();
+ argList::validArgs.append("Fluent mesh file");
+ argList::addOption
+ (
+ "scale",
+ "factor",
+ "geometry scaling factor - default is 1"
+ );
+ argList::addOption
+ (
+ "ignoreCellGroups",
+ "names",
+ "specify cell groups to ignore"
+ );
+ argList::addOption
+ (
+ "ignoreFaceGroups",
+ "names",
+ "specify face groups to ignore"
+ );
+
+ argList::addBoolOption
+ (
+ "cubit",
+ "special parsing of (incorrect) cubit files"
+ );
+
+ argList args(argc, argv);
+
+ if (!args.check())
+ {
+ FatalError.exit();
+ }
+
+ args.optionReadIfPresent("scale", scaleFactor);
+
+ wordHashSet ignoreCellGroups;
+ wordHashSet ignoreFaceGroups;
+
+ args.optionReadIfPresent("ignoreCellGroups", ignoreCellGroups);
+ args.optionReadIfPresent("ignoreFaceGroups", ignoreFaceGroups);
+
+ cubitFile = args.options().found("cubit");
+
+ if (cubitFile)
+ {
+ Info<< nl
+ << "Assuming Cubit generated file"
+ << " (incorrect face orientation; hexadecimal zoneIDs)."
+ << nl << endl;
+ }
+
+
+ #include "createTime.H"
+
+ const fileName fluentFile = args[1];
+ IFstream fluentStream(fluentFile);
+
+ if (!fluentStream)
+ {
+ FatalErrorInFunction
+ << ": file " << fluentFile << " not found"
+ << exit(FatalError);
+ }
+
+ yyFlexLexer lexer(&fluentStream.stdStream());
+
+ while (lexer.yylex() != 0)
+ {}
+
+ Info<< "\nFINISHED LEXING\n\n";
+
+ if (dimensionOfGrid != 3)
+ {
+ FatalErrorInFunction
+ << "Mesh is not 3D, dimension of grid: " << dimensionOfGrid
+ << exit(FatalError);
+ }
+
+ pointGroupZoneID.shrink();
+ pointGroupStartIndex.shrink();
+ pointGroupEndIndex.shrink();
+
+ faceGroupZoneID.shrink();
+ faceGroupStartIndex.shrink();
+ faceGroupEndIndex.shrink();
+
+ cellGroupZoneID.shrink();
+ cellGroupStartIndex.shrink();
+ cellGroupEndIndex.shrink();
+ cellGroupType.shrink();
+
+
+ // Pre-filtering: flip "owner" boundary or wrong oriented internal
+ // faces and move to neighbour
+
+ boolList fm(faces.size(), false);
+ forAll(faces, facei)
+ {
+ if
+ (
+ owner[facei] == -1
+ || (neighbour[facei] != -1 && owner[facei] > neighbour[facei])
+ )
+ {
+ fm[facei] = true;
+ if (!cubitFile)
+ {
+ faces[facei].flip();
+ }
+ Swap(owner[facei], neighbour[facei]);
+ }
+ }
+
+
+ // Foam type for Fluent type
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ HashTable fluentToFoamType;
+
+ fluentToFoamType.insert("pressure", polyPatch::typeName);
+ fluentToFoamType.insert("pressure-inlet", polyPatch::typeName);
+ fluentToFoamType.insert("inlet-vent", polyPatch::typeName);
+ fluentToFoamType.insert("intake-fan", polyPatch::typeName);
+ fluentToFoamType.insert("pressure-outlet", polyPatch::typeName);
+ fluentToFoamType.insert("exhaust-fan", polyPatch::typeName);
+ fluentToFoamType.insert("outlet-vent", polyPatch::typeName);
+ fluentToFoamType.insert("pressure-far-field", polyPatch::typeName);
+ fluentToFoamType.insert("velocity-inlet", polyPatch::typeName);
+ fluentToFoamType.insert("mass-flow-inlet", polyPatch::typeName);
+ fluentToFoamType.insert("outflow", polyPatch::typeName);
+
+ fluentToFoamType.insert("wall" , wallPolyPatch::typeName);
+
+ fluentToFoamType.insert("symmetry", symmetryPolyPatch::typeName);
+ fluentToFoamType.insert("axis", symmetryPolyPatch::typeName);
+
+ fluentToFoamType.insert("interior", polyPatch::typeName);
+ fluentToFoamType.insert("interface", polyPatch::typeName);
+ fluentToFoamType.insert("internal", polyPatch::typeName);
+ fluentToFoamType.insert("solid", polyPatch::typeName);
+ fluentToFoamType.insert("fan", oldCyclicPolyPatch::typeName);
+ fluentToFoamType.insert("radiator", polyPatch::typeName);
+ fluentToFoamType.insert("porous-jump", polyPatch::typeName);
+
+ //- Periodic halves map directly into split cyclics. The problem is the
+ // initial matching since we require knowledge of the transformation.
+ // It is ok if the periodics are already ordered. We should read the
+ // periodic shadow faces section (section 18) to give use the ordering
+ // For now just disable.
+ // fluentToFoamType.insert("periodic", cyclicPolyPatch::typeName);
+
+
+ // Foam patch type for Fluent zone type
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ HashSet fluentGroupToFoamPatch;
+ fluentGroupToFoamPatch.insert("wall");
+ fluentGroupToFoamPatch.insert("fan");
+
+
+ // Create initial empty polyMesh
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ polyMesh mesh
+ (
+ IOobject
+ (
+ polyMesh::defaultRegion,
+ runTime.constant(),
+ runTime
+ ),
+ pointField(),
+ faceList(),
+ labelList(),
+ labelList()
+ );
+
+
+ // Check the cell groups for zones ignoring those in ignoreCellGroups
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ label nCellZones = 0;
+ labelList cellZoneIDs(cellGroupZoneID.size());
+
+ forAll(cellGroupZoneID, cgi)
+ {
+ if (!ignoreCellGroups.found(groupName[cellGroupZoneID[cgi] ]))
+ {
+ cellZoneIDs[nCellZones++] = cgi;
+ }
+ }
+
+ cellZoneIDs.setSize(nCellZones);
+
+
+ // Check the face groups for boundary patches, baffles and faceZones
+ // ignoring the interior zones in ignoreCellGroups
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ DynamicList patchIDs(faceGroupZoneID.size());
+ DynamicList faceZoneIDs(faceGroupZoneID.size());
+
+ forAll(faceGroupZoneID, fgi)
+ {
+ label zoneID = faceGroupZoneID[fgi];
+ label start = faceGroupStartIndex[fgi];
+
+ if (groupType.found(zoneID))
+ {
+ const word& type = groupType[zoneID];
+
+ // Check the first element of neighbour for boundary group
+ if (neighbour[start] == -1 || fluentGroupToFoamPatch.found(type))
+ {
+ patchIDs.append(fgi);
+ }
+ else
+ {
+ if (!ignoreFaceGroups.found(groupName[faceGroupZoneID[fgi] ]))
+ {
+ faceZoneIDs.append(fgi);
+ }
+ }
+ }
+ else if (hangingNodes)
+ {
+ label end = faceGroupEndIndex[fgi];
+
+ Info<< "Unknown FaceGroup " << zoneID
+ << " assumed to be parent faces of refinement "
+ "patterns and ignored."
+ << endl;
+
+ // Set the owner of these faces to -1 so that they do not get
+ // added to the mesh
+ for (label facei = start; facei <= end; facei++)
+ {
+ owner[facei] = -1;
+ }
+ }
+ else
+ {
+ if (neighbour[start] == -1)
+ {
+ // Boundary face in unknown group. Create a patch for it.
+ groupType.insert(zoneID, "unknown");
+ groupName.insert(zoneID, "FaceGroup" + Foam::name(zoneID));
+ patchIDs.append(fgi);
+ Info<< "Created patch " << fgi << " for unknown FaceGroup "
+ << zoneID << '.' << endl;
+ }
+ else
+ {
+ WarningInFunction
+ << "Unknown FaceGroup " << zoneID << " not in a zone"
+ << endl;
+ }
+ }
+ }
+
+ patchIDs.shrink();
+ faceZoneIDs.shrink();
+
+
+ // Add empty patches
+ // ~~~~~~~~~~~~~~~~~
+
+ List newPatches(patchIDs.size());
+ HashSet patchNames;
+
+ forAll(patchIDs, patchi)
+ {
+ label zoneID = faceGroupZoneID[patchIDs[patchi] ];
+ word name = groupName[zoneID];
+ const word& type = groupType[zoneID];
+
+ Info<< "Creating patch " << patchi
+ << " for zone: " << zoneID
+ << " name: " << name
+ << " type: " << type
+ << endl;
+
+ uniquify(name, patchNames);
+
+ HashTable::const_iterator iter = fluentToFoamType.find(type);
+
+ if (iter != fluentToFoamType.end())
+ {
+ // See if we have a periodic and can derive the other side.
+ word neighbPatchName;
+ if (iter() == cyclicPolyPatch::typeName)
+ {
+ // Periodic
+ size_t n = name.rfind("-SIDE-1");
+
+ if (n != string::npos)
+ {
+ neighbPatchName = name.substr(0, n) + "-SIDE-2";
+ }
+ else
+ {
+ n = name.rfind("-SIDE-2");
+ if (n != string::npos)
+ {
+ neighbPatchName = name.substr(0, n) + "-SIDE-1";
+ }
+ }
+ }
+
+ if (neighbPatchName.size())
+ {
+ Info<< "Adding cyclicPolyPatch for Fluent zone " << name
+ << " with neighbour patch " << neighbPatchName
+ << endl;
+
+ newPatches[patchi] = new cyclicPolyPatch
+ (
+ name,
+ 0,
+ 0,
+ patchi,
+ mesh.boundaryMesh(),
+ neighbPatchName,
+ cyclicPolyPatch::NOORDERING,
+ Zero,
+ Zero,
+ Zero
+ );
+ }
+ else
+ {
+ newPatches[patchi] = polyPatch::New
+ (
+ iter(),
+ name,
+ 0,
+ 0,
+ patchi,
+ mesh.boundaryMesh()
+ ).ptr();
+ }
+ }
+ else
+ {
+ Info<< "Adding polyPatch for unknown Fluent type " << type
+ << endl;
+
+ newPatches[patchi] = new polyPatch
+ (
+ name,
+ 0,
+ 0,
+ patchi,
+ mesh.boundaryMesh(),
+ polyPatch::typeName
+ );
+ }
+ }
+ mesh.addPatches(newPatches);
+
+
+ // Add empty zones
+ // ~~~~~~~~~~~~~~~
+
+ // Cell zones
+ mesh.cellZones().setSize(cellZoneIDs.size());
+ HashSet cellZoneNames;
+
+ forAll(cellZoneIDs, cellZonei)
+ {
+ label zoneID = cellGroupZoneID[cellZoneIDs[cellZonei] ];
+ word name = groupName[zoneID];
+ const word& type = groupType[zoneID];
+
+ Info<< "Creating cellZone " << cellZonei
+ << " name: " << name
+ << " type: " << type
+ << endl;
+
+ uniquify(name, cellZoneNames);
+
+ mesh.cellZones().set
+ (
+ cellZonei,
+ new cellZone
+ (
+ name,
+ labelList(0),
+ cellZonei,
+ mesh.cellZones()
+ )
+ );
+ }
+
+ // Face zones
+ mesh.faceZones().setSize(faceZoneIDs.size());
+ HashSet faceZoneNames;
+
+ forAll(faceZoneIDs, faceZonei)
+ {
+ label zoneID = faceGroupZoneID[faceZoneIDs[faceZonei] ];
+ word name = groupName[zoneID];
+ const word& type = groupType[zoneID];
+
+ Info<< "Creating faceZone " << faceZonei
+ << " name: " << name
+ << " type: " << type
+ << endl;
+
+ uniquify(name, faceZoneNames);
+
+ mesh.faceZones().set
+ (
+ faceZonei,
+ new faceZone
+ (
+ name,
+ labelList(0),
+ boolList(0),
+ faceZonei,
+ mesh.faceZones()
+ )
+ );
+ }
+
+
+ // Modify mesh for points/cells/faces
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ // Mesh-change container
+ polyTopoChange meshMod(mesh, false);
+
+ // Add all points
+ forAll(points, pointi)
+ {
+ meshMod.addPoint(points[pointi], pointi, -1, true);
+ }
+ points.setSize(0);
+
+ // Add all cells
+ for (label celli = 0; celli < nCells; celli++)
+ {
+ meshMod.addCell
+ (
+ -1, // masterPointID
+ -1, // masterEdgeID
+ -1, // masterFaceID
+ celli, // masterCellID
+ -1 // zoneID
+ );
+ }
+
+ // Modify cells to be in zones as required
+ forAll(cellZoneIDs, cellZonei)
+ {
+ label cgi = cellZoneIDs[cellZonei];
+
+ for
+ (
+ label celli = cellGroupStartIndex[cgi];
+ celli <= cellGroupEndIndex[cgi];
+ celli++
+ )
+ {
+ meshMod.modifyCell(celli, cellZonei);
+ }
+ }
+
+
+ bool doneWarning = false;
+
+ // Add faceZone faces
+ forAll(faceZoneIDs, faceZonei)
+ {
+ label fgi = faceZoneIDs[faceZonei];
+ label start = faceGroupStartIndex[fgi];
+ label end = faceGroupEndIndex[fgi];
+ label zoneID = faceGroupZoneID[fgi];
+
+ Info<< "faceZone from Fluent indices: " << start
+ << " to: " << end
+ << " type: " << groupType[zoneID]
+ << endl;
+
+ for (label facei = start; facei <= end; facei++)
+ {
+ if (owner[facei] >= nCells || neighbour[facei] >= nCells)
+ {
+ if (!doneWarning)
+ {
+ WarningInFunction
+ << "Ignoring internal face " << facei
+ << " on FaceZone " << zoneID
+ << " since owner " << owner[facei] << " or neighbour "
+ << neighbour[facei] << " outside range of cells 0.."
+ << nCells-1 << endl
+ << " Suppressing future warnings." << endl;
+ doneWarning = true;
+ }
+ }
+ else
+ {
+ meshMod.addFace
+ (
+ faces[facei],
+ owner[facei],
+ neighbour[facei],
+ -1, // masterPointID
+ -1, // masterEdgeID
+ facei, // masterFace
+ false, // flipFaceFlux
+ -1, // patchID
+ faceZonei, // zoneID
+ fm[facei] // zoneFlip
+ );
+ }
+
+ // Mark face as being done
+ owner[facei] = -1;
+ }
+ }
+
+ // Add patch faces
+ forAll(patchIDs, patchi)
+ {
+ label fgi = patchIDs[patchi];
+ label start = faceGroupStartIndex[fgi];
+ label end = faceGroupEndIndex[fgi];
+ label zoneID = faceGroupZoneID[fgi];
+
+ Info<< "patch " << patchi << " from Fluent indices: " << start
+ << " to: " << end
+ << " type: " << groupType[zoneID]
+ << endl;
+
+ for (label facei = start; facei <= end; facei++)
+ {
+ if (owner[facei] >= nCells || neighbour[facei] >= nCells)
+ {
+ if (!doneWarning)
+ {
+ WarningInFunction
+ << "Ignoring patch face " << facei
+ << " on FaceZone " << zoneID
+ << " since owner " << owner[facei] << " or neighbour "
+ << neighbour[facei] << " outside range of cells 0.."
+ << nCells-1 << endl
+ << " Suppressing future warnings." << endl;
+ doneWarning = true;
+ }
+ }
+ else
+ {
+ meshMod.addFace
+ (
+ faces[facei],
+ owner[facei],
+ -1,
+ -1, // masterPointID
+ -1, // masterEdgeID
+ facei, // masterFace
+ false, // flipFaceFlux
+ patchi, // patchID
+ -1, // zoneID
+ false // zoneFlip
+ );
+
+ // For baffles create the opposite face
+ if (neighbour[start] != -1)
+ {
+ meshMod.addFace
+ (
+ faces[facei].reverseFace(),
+ neighbour[facei],
+ -1,
+ -1, // masterPointID
+ -1, // masterEdgeID
+ facei, // masterFace
+ false, // flipFaceFlux
+ patchi, // patchID
+ -1, // zoneID
+ false // zoneFlip
+ );
+ }
+ }
+ // Mark face as being done
+ owner[facei] = -1;
+ }
+ }
+
+ // Add remaining internal faces
+ forAll(owner, facei)
+ {
+ if (owner[facei] != -1)
+ {
+ // Check the face being added as an internal face actually is one
+ if (neighbour[facei] == -1)
+ {
+ FatalErrorInFunction
+ << "Attempt of add internal face " << facei
+ << " which is a boundary face"
+ << exit(FatalError);
+ }
+
+ if (owner[facei] >= nCells || neighbour[facei] >= nCells)
+ {
+ if (!doneWarning)
+ {
+ WarningInFunction
+ << "Ignoring internal face " << facei
+ << " since owner " << owner[facei] << " or neighbour "
+ << neighbour[facei] << " outside range of cells 0.."
+ << nCells-1 << endl
+ << " Suppressing future warnings." << endl;
+ doneWarning = true;
+ }
+ }
+ else
+ {
+ meshMod.addFace
+ (
+ faces[facei],
+ owner[facei],
+ neighbour[facei],
+ -1, // masterPointID
+ -1, // masterEdgeID
+ facei, // masterFace
+ false, // flipFaceFlux
+ -1, // patchID
+ -1, // zoneID
+ false // zoneFlip
+ );
+ }
+ }
+ }
+
+ // Reclaim storage
+ faces.setSize(0);
+ owner.setSize(0);
+ neighbour.setSize(0);
+
+
+ // Modify mesh
+ // ~~~~~~~~~~~
+
+ autoPtr map = meshMod.changeMesh(mesh, false);
+
+ // Zip-up the mesh if it contained hanging nodes
+ if (hangingNodes)
+ {
+ Info<< "Zipping mesh to remove hanging nodes" << endl;
+ polyMeshZipUpCells(mesh);
+ }
+
+ mesh.setInstance(runTime.constant());
+
+ // Set the precision of the points data to 10
+ IOstream::defaultPrecision(max(10u, IOstream::defaultPrecision()));
+
+ Info<< nl << "Writing mesh to " << mesh.objectPath() << endl;
+ mesh.write();
+
+
+ Info<< "\nEnd\n" << endl;
+ return 0;
+}
+
+
+ /* ------------------------------------------------------------------------ *\
+ ------ End of fluentMeshToFoam.L
+ \* ------------------------------------------------------------------------ */