1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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
661 Info<< "CellZones:" << nl
662 << "Zone\tSize" << endl;
664 forAll(zoneCells, zoneI)
666 zoneCells[zoneI].shrink();
668 const labelList& zCells = zoneCells[zoneI];
670 if (zCells.size() > 0)
672 Info<< " " << zoneI << '\t' << zCells.size() << endl;
681 int main(int argc, char *argv[])
683 argList::noParallel();
684 argList::validArgs.append(".msh file");
685 argList::validOptions.insert("keepOrientation", "");
687 # include "setRootCase.H"
688 # include "createTime.H"
690 fileName mshName(args.additionalArgs()[0]);
692 bool keepOrientation = args.options().found("keepOrientation");
694 // Storage for points
696 Map<label> mshToFoam;
698 // Storage for all cells.
701 // Map from patch to gmsh physical region
702 labelList patchToPhys;
703 // Storage for patch faces.
704 List<DynamicList<face> > patchFaces(0);
706 // Map from cellZone to gmsh physical region
707 labelList zoneToPhys;
708 // Storage for cell zones.
709 List<DynamicList<label> > zoneCells(0);
711 // Name per physical region
712 Map<word> physicalNames;
714 // Version 1 or 2 format
715 bool version2Format = false;
718 IFstream inFile(mshName);
720 while (inFile.good())
723 inFile.getLine(line);
724 IStringStream lineStr(line);
728 if (tag == "$MeshFormat")
730 Info<< "Found $MeshFormat tag; assuming version 2 file format."
732 version2Format = true;
734 if (!skipSection(inFile))
739 else if (tag == "$PhysicalNames")
741 readPhysNames(inFile, physicalNames);
743 else if (tag == "$NOD" || tag == "$Nodes")
745 readPoints(inFile, points, mshToFoam);
747 else if (tag == "$ELM" || tag == "$Elements")
765 Info<< "Skipping tag " << tag << " at line "
766 << inFile.lineNumber()
769 if (!skipSection(inFile))
777 label nValidCellZones = 0;
779 forAll(zoneCells, zoneI)
781 if (zoneCells[zoneI].size() > 0)
788 // Problem is that the orientation of the patchFaces does not have to
789 // be consistent with the outwards orientation of the mesh faces. So
790 // we have to construct the mesh in two stages:
791 // 1. define mesh with all boundary faces in one patch
792 // 2. use the read patchFaces to find the corresponding boundary face
796 // Create correct number of patches
797 // (but without any faces in it)
798 faceListList boundaryFaces(patchFaces.size());
800 wordList boundaryPatchNames(boundaryFaces.size());
802 forAll(boundaryPatchNames, patchI)
804 label physReg = patchToPhys[patchI];
806 Map<word>::const_iterator iter = physicalNames.find(physReg);
808 if (iter != physicalNames.end())
810 boundaryPatchNames[patchI] = iter();
814 boundaryPatchNames[patchI] = word("patch") + name(patchI);
816 Info<< "Patch " << patchI << " gets name "
817 << boundaryPatchNames[patchI] << endl;
821 wordList boundaryPatchTypes(boundaryFaces.size(), polyPatch::typeName);
822 word defaultFacesName = "defaultFaces";
823 word defaultFacesType = polyPatch::typeName;
824 wordList boundaryPatchPhysicalTypes
826 boundaryFaces.size(),
834 polyMesh::defaultRegion,
845 boundaryPatchPhysicalTypes
848 repatchPolyTopoChanger repatcher(mesh);
850 // Now use the patchFaces to patch up the outside faces of the mesh.
852 // Get the patch for all the outside faces (= default patch added as last)
853 const polyPatch& pp = mesh.boundaryMesh()[mesh.boundaryMesh().size()-1];
855 // Storage for faceZones.
856 List<DynamicList<label> > zoneFaces(patchFaces.size());
859 // Go through all the patchFaces and find corresponding face in pp.
860 forAll(patchFaces, patchI)
862 const DynamicList<face>& pFaces = patchFaces[patchI];
864 Info<< "Finding faces of patch " << patchI << endl;
868 const face& f = pFaces[i];
870 // Find face in pp using all vertices of f.
871 label patchFaceI = findFace(pp, f);
873 if (patchFaceI != -1)
875 label meshFaceI = pp.start() + patchFaceI;
877 repatcher.changePatchID(meshFaceI, patchI);
881 // Maybe internal face? If so add to faceZone with same index
882 // - might be useful.
883 label meshFaceI = findInternalFace(mesh, f);
887 zoneFaces[patchI].append(meshFaceI);
891 WarningIn(args.executable())
892 << "Could not match gmsh face " << f
893 << " to any of the interior or exterior faces"
894 << " that share the same 0th point" << endl;
902 label nValidFaceZones = 0;
904 Info<< "FaceZones:" << nl
905 << "Zone\tSize" << endl;
907 forAll(zoneFaces, zoneI)
909 zoneFaces[zoneI].shrink();
911 const labelList& zFaces = zoneFaces[zoneI];
913 if (zFaces.size() > 0)
917 Info<< " " << zoneI << '\t' << zFaces.size() << endl;
923 //Get polyMesh to write to constant
924 runTime.setTime(instant(runTime.constant()), 0);
931 // Construct and add the zones. Note that cell ordering does not change
932 // because of repatch() and neither does internal faces so we can
933 // use the zoneCells/zoneFaces as is.
935 if (nValidCellZones > 0)
937 cz.setSize(nValidCellZones);
941 forAll(zoneCells, zoneI)
943 if (zoneCells[zoneI].size() > 0)
945 label physReg = zoneToPhys[zoneI];
947 Map<word>::const_iterator iter = physicalNames.find(physReg);
949 word zoneName = "cellZone_" + name(zoneI);
950 if (iter != physicalNames.end())
955 Info<< "Writing zone " << zoneI << " to cellZone "
956 << zoneName << " and cellSet"
959 cellSet cset(mesh, zoneName, zoneCells[zoneI]);
962 cz[nValidCellZones] = new cellZone
974 if (nValidFaceZones > 0)
976 fz.setSize(nValidFaceZones);
980 forAll(zoneFaces, zoneI)
982 if (zoneFaces[zoneI].size() > 0)
984 label physReg = zoneToPhys[zoneI];
986 Map<word>::const_iterator iter = physicalNames.find(physReg);
988 word zoneName = "faceZone_" + name(zoneI);
989 if (iter != physicalNames.end())
994 Info<< "Writing zone " << zoneI << " to faceZone "
995 << zoneName << " and faceSet"
998 faceSet fset(mesh, zoneName, zoneFaces[zoneI]);
1001 fz[nValidFaceZones] = new faceZone
1005 boolList(zoneFaces[zoneI].size(), true),
1014 if (cz.size() > 0 || fz.size() > 0)
1016 mesh.addZones(List<pointZone*>(0), fz, cz);
1021 Info<< "End\n" << endl;
1027 // ************************************************************************* //