1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 Reads .msh file as written by Gmsh.
28 Needs surface elements on mesh to be present and aligned with outside faces
29 of the mesh. I.e. if the mesh is hexes, the outside faces need to be quads
31 Note: There is something seriously wrong with the ordering written in the
32 .msh file. Normal operation is to check the ordering and invert prisms
33 and hexes if found to be wrong way round.
34 Use the -keepOrientation to keep the raw information.
36 Note: The code now uses the element (cell,face) physical region id number
37 to create cell zones and faces zones (similar to
38 fluentMeshWithInternalFaces).
40 A use of the cell zone information, is for field initialization with the
41 "setFields" utility. see the classes: topoSetSource, zoneToCell.
42 \*---------------------------------------------------------------------------*/
49 #include "cellModeller.H"
50 #include "repatchPolyTopoChanger.H"
56 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
58 // Element type numbers
59 static label MSHTRI = 2;
60 static label MSHQUAD = 3;
61 static label MSHTET = 4;
62 static label MSHPYR = 7;
63 static label MSHPRISM = 6;
64 static label MSHHEX = 5;
67 // Skips till end of section. Returns false if end of file.
68 bool skipSection(IFstream& inFile)
80 while (line.size() < 4 || line.substr(0, 4) != "$End");
88 const Map<label>& mshToFoam,
92 forAll(labels, labelI)
94 labels[labelI] = mshToFoam[labels[labelI]];
99 // Find face in pp which uses all vertices in meshF (in mesh point labels)
100 label findFace(const primitivePatch& pp, const labelList& meshF)
102 const Map<label>& meshPointMap = pp.meshPointMap();
104 // meshF[0] in pp labels.
105 if (!meshPointMap.found(meshF[0]))
107 Warning<< "Not using gmsh face " << meshF
108 << " since zero vertex is not on boundary of polyMesh" << endl;
112 // Find faces using first point
113 const labelList& pFaces = pp.pointFaces()[meshPointMap[meshF[0]]];
115 // Go through all these faces and check if there is one which uses all of
116 // meshF vertices (in any order ;-)
119 label faceI = pFaces[i];
121 const face& f = pp[faceI];
123 // Count uses of vertices of meshF for f
128 if (findIndex(meshF, f[fp]) != -1)
134 if (nMatched == meshF.size())
144 // Same but find internal face. Expensive addressing.
145 label findInternalFace(const primitiveMesh& mesh, const labelList& meshF)
147 const labelList& pFaces = mesh.pointFaces()[meshF[0]];
151 label faceI = pFaces[i];
153 const face& f = mesh.faces()[faceI];
155 // Count uses of vertices of meshF for f
160 if (findIndex(meshF, f[fp]) != -1)
166 if (nMatched == meshF.size())
175 // Determine whether cell is inside-out by checking for any wrong-oriented
177 bool correctOrientation(const pointField& points, const cellShape& shape)
179 // Get centre of shape.
180 point cc(shape.centre(points));
182 // Get outwards pointing faces.
183 faceList faces(shape.faces());
187 const face& f = faces[i];
189 vector n(f.normal(points));
191 // Check if vector from any point on face to cc points outwards
192 if (((points[f[0]] - cc) & n) < 0)
194 // Incorrectly oriented
207 Map<label>& physToZone,
209 labelList& zoneToPhys,
210 List<DynamicList<label> >& zoneCells
213 Map<label>::const_iterator zoneFnd = physToZone.find(regPhys);
215 if (zoneFnd == physToZone.end())
217 // New region. Allocate zone for it.
218 label zoneI = zoneCells.size();
219 zoneCells.setSize(zoneI+1);
220 zoneToPhys.setSize(zoneI+1);
222 Info<< "Mapping region " << regPhys << " to Foam cellZone "
224 physToZone.insert(regPhys, zoneI);
226 zoneToPhys[zoneI] = regPhys;
227 zoneCells[zoneI].append(cellI);
231 // Existing zone for region
232 zoneCells[zoneFnd()].append(cellI);
237 // Reads points and map
238 void readPoints(IFstream& inFile, pointField& points, Map<label>& mshToFoam)
240 Info<< "Starting to read points at line " << inFile.lineNumber() << endl;
243 inFile.getLine(line);
244 IStringStream lineStr(line);
249 Info<< "Vertices to be read:" << nVerts << endl;
251 points.setSize(nVerts);
252 mshToFoam.resize(2*nVerts);
254 for (label pointI = 0; pointI < nVerts; pointI++)
257 scalar xVal, yVal, zVal;
260 inFile.getLine(line);
261 IStringStream lineStr(line);
263 lineStr >> mshLabel >> xVal >> yVal >> zVal;
265 point& pt = points[pointI];
271 mshToFoam.insert(mshLabel, pointI);
274 Info<< "Vertices read:" << mshToFoam.size() << endl;
276 inFile.getLine(line);
277 IStringStream tagStr(line);
280 if (tag != "$ENDNOD" && tag != "$EndNodes")
282 FatalErrorIn("readPoints(..)")
283 << "Did not find $ENDNOD tag on line "
284 << inFile.lineNumber() << exit(FatalError);
290 // Reads physical names
291 void readPhysNames(IFstream& inFile, Map<word>& physicalNames)
293 Info<< "Starting to read physical names at line " << inFile.lineNumber()
297 inFile.getLine(line);
298 IStringStream lineStr(line);
303 Info<< "Physical names:" << nNames << endl;
305 physicalNames.resize(nNames);
307 for (label i = 0; i < nNames; i++)
313 inFile.getLine(line);
314 IStringStream lineStr(line);
316 lineStr >> regionI >> regionName;
318 Info<< " " << regionI << '\t' << string::validate<word>(regionName)
321 physicalNames.insert(regionI, string::validate<word>(regionName));
324 inFile.getLine(line);
325 IStringStream tagStr(line);
328 if (tag != "$EndPhysicalNames")
330 FatalErrorIn("readPhysicalNames(..)")
331 << "Did not find $EndPhysicalNames tag on line "
332 << inFile.lineNumber() << exit(FatalError);
338 // Reads cells and patch faces
341 const bool version2Format,
342 const bool keepOrientation,
343 const pointField& points,
344 const Map<label>& mshToFoam,
346 cellShapeList& cells,
348 labelList& patchToPhys,
349 List<DynamicList<face> >& patchFaces,
351 labelList& zoneToPhys,
352 List<DynamicList<label> >& zoneCells
355 Info<< "Starting to read cells at line " << inFile.lineNumber() << endl;
357 const cellModel& hex = *(cellModeller::lookup("hex"));
358 const cellModel& prism = *(cellModeller::lookup("prism"));
359 const cellModel& pyr = *(cellModeller::lookup("pyr"));
360 const cellModel& tet = *(cellModeller::lookup("tet"));
364 labelList tetPoints(4);
365 labelList pyrPoints(5);
366 labelList prismPoints(6);
367 labelList hexPoints(8);
371 inFile.getLine(line);
372 IStringStream lineStr(line);
377 Info<< "Cells to be read:" << nElems << endl << endl;
380 // Storage for all cells. Too big. Shrink later
381 cells.setSize(nElems);
390 // From gmsh physical region to Foam patch
391 Map<label> physToPatch;
393 // From gmsh physical region to Foam cellZone
394 Map<label> physToZone;
397 for (label elemI = 0; elemI < nElems; elemI++)
400 inFile.getLine(line);
401 IStringStream lineStr(line);
403 label elmNumber, elmType, regPhys;
407 lineStr >> elmNumber >> elmType;
412 label regElem, partition;
416 lineStr >> regPhys >> regElem >> partition;
421 for (label i = 0; i < nTags; i++)
430 label regElem, nNodes;
431 lineStr >> elmNumber >> elmType >> regPhys >> regElem >> nNodes;
434 // regPhys on surface elements is region number.
436 if (elmType == MSHTRI)
438 lineStr >> triPoints[0] >> triPoints[1] >> triPoints[2];
440 renumber(mshToFoam, triPoints);
442 Map<label>::iterator regFnd = physToPatch.find(regPhys);
445 if (regFnd == physToPatch.end())
447 // New region. Allocate patch for it.
448 patchI = patchFaces.size();
450 patchFaces.setSize(patchI + 1);
451 patchToPhys.setSize(patchI + 1);
453 Info<< "Mapping region " << regPhys << " to Foam patch "
455 physToPatch.insert(regPhys, patchI);
456 patchToPhys[patchI] = regPhys;
460 // Existing patch for region
464 // Add triangle to correct patchFaces.
465 patchFaces[patchI].append(triPoints);
467 else if (elmType == MSHQUAD)
470 >> quadPoints[0] >> quadPoints[1] >> quadPoints[2]
473 renumber(mshToFoam, quadPoints);
475 Map<label>::iterator regFnd = physToPatch.find(regPhys);
478 if (regFnd == physToPatch.end())
480 // New region. Allocate patch for it.
481 patchI = patchFaces.size();
483 patchFaces.setSize(patchI + 1);
484 patchToPhys.setSize(patchI + 1);
486 Info<< "Mapping region " << regPhys << " to Foam patch "
488 physToPatch.insert(regPhys, patchI);
489 patchToPhys[patchI] = regPhys;
493 // Existing patch for region
497 // Add quad to correct patchFaces.
498 patchFaces[patchI].append(quadPoints);
500 else if (elmType == MSHTET)
512 >> tetPoints[0] >> tetPoints[1] >> tetPoints[2]
515 renumber(mshToFoam, tetPoints);
517 cells[cellI++] = cellShape(tet, tetPoints);
521 else if (elmType == MSHPYR)
533 >> pyrPoints[0] >> pyrPoints[1] >> pyrPoints[2]
534 >> pyrPoints[3] >> pyrPoints[4];
536 renumber(mshToFoam, pyrPoints);
538 cells[cellI++] = cellShape(pyr, pyrPoints);
542 else if (elmType == MSHPRISM)
554 >> prismPoints[0] >> prismPoints[1] >> prismPoints[2]
555 >> prismPoints[3] >> prismPoints[4] >> prismPoints[5];
557 renumber(mshToFoam, prismPoints);
559 cells[cellI] = cellShape(prism, prismPoints);
561 const cellShape& cell = cells[cellI];
563 if (!keepOrientation && !correctOrientation(points, cell))
565 Info<< "Inverting prism " << cellI << endl;
567 prismPoints[0] = cell[0];
568 prismPoints[1] = cell[2];
569 prismPoints[2] = cell[1];
570 prismPoints[3] = cell[3];
571 prismPoints[4] = cell[4];
572 prismPoints[5] = cell[5];
574 cells[cellI] = cellShape(prism, prismPoints);
581 else if (elmType == MSHHEX)
593 >> hexPoints[0] >> hexPoints[1]
594 >> hexPoints[2] >> hexPoints[3]
595 >> hexPoints[4] >> hexPoints[5]
596 >> hexPoints[6] >> hexPoints[7];
598 renumber(mshToFoam, hexPoints);
600 cells[cellI] = cellShape(hex, hexPoints);
602 const cellShape& cell = cells[cellI];
604 if (!keepOrientation && !correctOrientation(points, cell))
606 Info<< "Inverting hex " << cellI << endl;
608 hexPoints[0] = cell[4];
609 hexPoints[1] = cell[5];
610 hexPoints[2] = cell[6];
611 hexPoints[3] = cell[7];
612 hexPoints[4] = cell[0];
613 hexPoints[5] = cell[1];
614 hexPoints[6] = cell[2];
615 hexPoints[7] = cell[3];
617 cells[cellI] = cellShape(hex, hexPoints);
626 Info<< "Unhandled element " << elmType << " at line "
627 << inFile.lineNumber() << endl;
632 inFile.getLine(line);
633 IStringStream tagStr(line);
636 if (tag != "$ENDELM" && tag != "$EndElements")
638 FatalErrorIn("readCells(..)")
639 << "Did not find $ENDELM tag on line "
640 << inFile.lineNumber() << exit(FatalError);
644 cells.setSize(cellI);
646 forAll(patchFaces, patchI)
648 patchFaces[patchI].shrink();
652 Info<< "Cells:" << endl
653 << " total:" << cells.size() << endl
654 << " hex :" << nHex << endl
655 << " prism:" << nPrism << endl
656 << " pyr :" << nPyr << endl
657 << " tet :" << nTet << endl
660 if (cells.size() == 0)
662 FatalErrorIn("readCells(..)")
663 << "No cells read from file " << inFile.name() << nl
664 << "Does your file specify any 3D elements (hex=" << MSHHEX
665 << ", prism=" << MSHPRISM << ", pyramid=" << MSHPYR
666 << ", tet=" << MSHTET << ")?" << nl
667 << "Perhaps you have not exported the 3D elements?"
671 Info<< "CellZones:" << nl
672 << "Zone\tSize" << endl;
674 forAll(zoneCells, zoneI)
676 zoneCells[zoneI].shrink();
678 const labelList& zCells = zoneCells[zoneI];
682 Info<< " " << zoneI << '\t' << zCells.size() << endl;
691 int main(int argc, char *argv[])
693 argList::noParallel();
694 argList::validArgs.append(".msh file");
695 argList::validOptions.insert("keepOrientation", "");
697 # include "setRootCase.H"
698 # include "createTime.H"
700 fileName mshName(args.additionalArgs()[0]);
702 bool keepOrientation = args.optionFound("keepOrientation");
704 // Storage for points
706 Map<label> mshToFoam;
708 // Storage for all cells.
711 // Map from patch to gmsh physical region
712 labelList patchToPhys;
713 // Storage for patch faces.
714 List<DynamicList<face> > patchFaces(0);
716 // Map from cellZone to gmsh physical region
717 labelList zoneToPhys;
718 // Storage for cell zones.
719 List<DynamicList<label> > zoneCells(0);
721 // Name per physical region
722 Map<word> physicalNames;
724 // Version 1 or 2 format
725 bool version2Format = false;
728 IFstream inFile(mshName);
730 while (inFile.good())
733 inFile.getLine(line);
734 IStringStream lineStr(line);
738 if (tag == "$MeshFormat")
740 Info<< "Found $MeshFormat tag; assuming version 2 file format."
742 version2Format = true;
744 if (!skipSection(inFile))
749 else if (tag == "$PhysicalNames")
751 readPhysNames(inFile, physicalNames);
753 else if (tag == "$NOD" || tag == "$Nodes")
755 readPoints(inFile, points, mshToFoam);
757 else if (tag == "$ELM" || tag == "$Elements")
775 Info<< "Skipping tag " << tag << " at line "
776 << inFile.lineNumber()
779 if (!skipSection(inFile))
787 label nValidCellZones = 0;
789 forAll(zoneCells, zoneI)
791 if (zoneCells[zoneI].size())
798 // Problem is that the orientation of the patchFaces does not have to
799 // be consistent with the outwards orientation of the mesh faces. So
800 // we have to construct the mesh in two stages:
801 // 1. define mesh with all boundary faces in one patch
802 // 2. use the read patchFaces to find the corresponding boundary face
806 // Create correct number of patches
807 // (but without any faces in it)
808 faceListList boundaryFaces(patchFaces.size());
810 wordList boundaryPatchNames(boundaryFaces.size());
812 forAll(boundaryPatchNames, patchI)
814 label physReg = patchToPhys[patchI];
816 Map<word>::const_iterator iter = physicalNames.find(physReg);
818 if (iter != physicalNames.end())
820 boundaryPatchNames[patchI] = iter();
824 boundaryPatchNames[patchI] = word("patch") + name(patchI);
826 Info<< "Patch " << patchI << " gets name "
827 << boundaryPatchNames[patchI] << endl;
831 wordList boundaryPatchTypes(boundaryFaces.size(), polyPatch::typeName);
832 word defaultFacesName = "defaultFaces";
833 word defaultFacesType = polyPatch::typeName;
834 wordList boundaryPatchPhysicalTypes
836 boundaryFaces.size(),
844 polyMesh::defaultRegion,
855 boundaryPatchPhysicalTypes
858 repatchPolyTopoChanger repatcher(mesh);
860 // Now use the patchFaces to patch up the outside faces of the mesh.
862 // Get the patch for all the outside faces (= default patch added as last)
863 const polyPatch& pp = mesh.boundaryMesh()[mesh.boundaryMesh().size()-1];
865 // Storage for faceZones.
866 List<DynamicList<label> > zoneFaces(patchFaces.size());
869 // Go through all the patchFaces and find corresponding face in pp.
870 forAll(patchFaces, patchI)
872 const DynamicList<face>& pFaces = patchFaces[patchI];
874 Info<< "Finding faces of patch " << patchI << endl;
878 const face& f = pFaces[i];
880 // Find face in pp using all vertices of f.
881 label patchFaceI = findFace(pp, f);
883 if (patchFaceI != -1)
885 label meshFaceI = pp.start() + patchFaceI;
887 repatcher.changePatchID(meshFaceI, patchI);
891 // Maybe internal face? If so add to faceZone with same index
892 // - might be useful.
893 label meshFaceI = findInternalFace(mesh, f);
897 zoneFaces[patchI].append(meshFaceI);
901 WarningIn(args.executable())
902 << "Could not match gmsh face " << f
903 << " to any of the interior or exterior faces"
904 << " that share the same 0th point" << endl;
912 label nValidFaceZones = 0;
914 Info<< "FaceZones:" << nl
915 << "Zone\tSize" << endl;
917 forAll(zoneFaces, zoneI)
919 zoneFaces[zoneI].shrink();
921 const labelList& zFaces = zoneFaces[zoneI];
927 Info<< " " << zoneI << '\t' << zFaces.size() << endl;
933 //Get polyMesh to write to constant
934 runTime.setTime(instant(runTime.constant()), 0);
941 // Construct and add the zones. Note that cell ordering does not change
942 // because of repatch() and neither does internal faces so we can
943 // use the zoneCells/zoneFaces as is.
945 if (nValidCellZones > 0)
947 cz.setSize(nValidCellZones);
951 forAll(zoneCells, zoneI)
953 if (zoneCells[zoneI].size())
955 label physReg = zoneToPhys[zoneI];
957 Map<word>::const_iterator iter = physicalNames.find(physReg);
959 word zoneName = "cellZone_" + name(zoneI);
960 if (iter != physicalNames.end())
965 Info<< "Writing zone " << zoneI << " to cellZone "
966 << zoneName << " and cellSet"
969 cellSet cset(mesh, zoneName, zoneCells[zoneI]);
972 cz[nValidCellZones] = new cellZone
984 if (nValidFaceZones > 0)
986 fz.setSize(nValidFaceZones);
990 forAll(zoneFaces, zoneI)
992 if (zoneFaces[zoneI].size())
994 label physReg = zoneToPhys[zoneI];
996 Map<word>::const_iterator iter = physicalNames.find(physReg);
998 word zoneName = "faceZone_" + name(zoneI);
999 if (iter != physicalNames.end())
1004 Info<< "Writing zone " << zoneI << " to faceZone "
1005 << zoneName << " and faceSet"
1008 faceSet fset(mesh, zoneName, zoneFaces[zoneI]);
1011 fz[nValidFaceZones] = new faceZone
1015 boolList(zoneFaces[zoneI].size(), true),
1024 if (cz.size() || fz.size())
1026 mesh.addZones(List<pointZone*>(0), fz, cz);
1031 Info<< "End\n" << endl;
1037 // ************************************************************************* //