# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE.txt', which is part of this source code package.
#
""" Gmsh file reader (gmsh mesh files)
"""
from Muscat.IO.IOFactory import RegisterReaderClass
from typing import Optional, Dict, List
import numpy as np
from Muscat.Helpers.Logger import Debug, Info, Warning
import Muscat.Containers.ElementsDescription as ED
from Muscat.Containers.Mesh import Mesh
from Muscat.IO.ReaderBase import ReaderBase
from Muscat.Types import MuscatIndex
from Muscat.IO.GmshTools import gmshNumber, PermutationGmshToMuscat
[docs]def ReadGmsh(fileName: str = "", string:str = "", out=None, **kwargs) -> Mesh:
"""Function API for reading a gmsh file
Parameters
----------
fileName : str, optional
name of the file to be read, by default None
string : str, optional
data to be read as a string instead of a file, by default None
out : Mesh, optional
output unstructured mesh object containing reading result, by default None
Returns
-------
Mesh
output unstructured mesh object containing reading result
"""
reader = GmshReader()
reader.SetFileName(fileName)
reader.SetStringToRead(string)
if "readGeoTags" in kwargs:
reader.readGeoTags = kwargs["readGeoTags"]
kwargs.pop("readGeoTags")
if "readPhyTags" in kwargs:
reader.readPhyTags = kwargs["readPhyTags"]
kwargs.pop("readPhyTags")
return reader.Read(fileName=fileName, string=string, out=out, **kwargs)
[docs]class GmshReader(ReaderBase):
"""Class to read Gmsh files into a Mesh
Parameters
----------
readGeoTags : Bool
option to activate/deactivate the reading of the Geometrical tags of the files
readPhyTags : Bool
option to activate/deactivate the reading of the Physical tags of the files
"""
def __init__(self) -> None:
super().__init__()
self.readGeoTags = True
self.readPhyTags = True
self.commentHeader = "%"
self.readFormat = 'r'
[docs] def Read(self, fileName: Optional[str] = None, string: Optional[str] = None, out: Optional[Mesh] = None) -> Mesh:
"""Function that performs the reading of a gmsh mesh file
Parameters
----------
fileName : str, optional
name of the file to be read, by default None
string : str, optional
data to be read as a string instead of a file, by default None
out : Mesh, optional
output unstructured mesh object containing reading result, by default None
Returns
-------
Mesh
output unstructured mesh object containing reading result
"""
if fileName is not None:
self.SetFileName(fileName)
if string is not None:
self.SetStringToRead(string)
self.StartReading()
if out is None:
res = Mesh()
else:
res = out
fileToInternalId: Dict[str, MuscatIndex] = {}
tagsNames: List[str] = []
while (True):
l = self.ReadCleanLine()
if not l:
break
if l.find("$MeshFormat") > -1:
while (True):
line = self.ReadCleanLine()
l = line.strip('\n').lstrip().rstrip()
if len(l) == 0:
continue
if l.find("$EndMeshFormat") > -1:
break
continue
if l.find("$Nodes") > -1:
l = self.ReadCleanLine()
nbNodes = int(l.split()[0])
#print("Reading "+str(nbNodes)+ " Nodes")
res.nodes = np.empty((nbNodes, 3))
res.originalIDNodes = np.empty((nbNodes,), dtype=MuscatIndex)
cpt = 0
while (True):
line = self.ReadCleanLine()
l = line.strip('\n').lstrip().rstrip()
if len(l) == 0:
continue
if l.find("$EndNodes") > -1:
break
s = l.split()
if cpt == nbNodes:
raise (Exception("More points than the number of point in the header (fix your file!!!)")) # pragma: no cover
fileToInternalId[s[0]] = cpt
res.originalIDNodes[cpt] = int(s[0])
res.nodes[cpt, :] = list(map(float, s[1:]))
cpt += 1
continue
if l.find("$PhysicalNames") > -1:
l = self.ReadCleanLine()
numberOfTags = int(l)
if l.find("$EndPhysicalNames") > -1:
continue
while (numberOfTags > 0):
numberOfTags -= 1
l = self.ReadCleanLine()
if l.find("$EndPhysicalNames") > -1:
break
l = l.split()
dimensionality = int(l[0])
tagNumber = l[1]
tagName = l[2].strip('"').strip("'")
tagsNames.append((dimensionality, tagNumber, tagName))
line = self.ReadCleanLine()
if line.find("$EndPhysicalNames") == -1:
print("Expecting $EndPhysicalNames Keyword in the file (corrupted file??")
continue
if l.find("$Elements") > -1:
line = self.ReadCleanLine()
l = line.strip('\n').lstrip().rstrip()
nbElements = int(l.split()[0])
allTags: Dict[str, Dict[str, MuscatIndex]] = {}
cpt: MuscatIndex = 0
while (True):
l = self.ReadCleanLine()
if l.find("$EndElements") > -1:
if nbElements != cpt: # pragma: no cover
print("File problem!! number of elements read not equal to the total number of elements")
print(nbElements)
print(cpt)
break
s = l.split()
oid = int(s[0])
gmshElemType = s[1]
nameType = gmshNumber[gmshElemType]
nTags = int(s[2])
conn = [fileToInternalId[x] for x in s[nTags+3:]]
if nameType in PermutationGmshToMuscat:
conn = [conn[x] for x in PermutationGmshToMuscat[nameType]]
elements = res.elements.GetElementsOfType(nameType)
elNumber = elements.AddNewElement(conn, oid)-1
tags = allTags.setdefault(nameType, {})
if nTags >= 0 and self.readPhyTags:
tags.setdefault("PhyTag"+s[3], []).append(elNumber)
if nTags >= 1 and self.readGeoTags:
tags.setdefault("GeoTag"+s[4], []).append(elNumber)
for n in range(2, nTags):
tags.setdefault("ExtraTag"+str(n-2), []).append(elNumber)
cpt += 1
for nameType, tags in allTags.items():
elements = res.elements.GetElementsOfType(nameType)
for name, ids in tags.items():
elements.tags.CreateTag(name).SetIds(ids)
del allTags
continue
Warning("ignoring line : " + l)
# convert to 2D if needed
if np.linalg.norm(res.nodes[:, 2]) == 0:
from Muscat.Containers.MeshModificationTools import LowerNodesDimension
res = LowerNodesDimension(res)
# apply tags names
for dim, number, newName in tagsNames:
for name, data in res.elements.items():
if ED.dimensionality[name] != dim:
continue
Info("changing tag form '" + str("PhyTag"+number) + "' to '" + str(newName)+"'")
data.tags.RenameTag("PhyTag"+number, newName, noError=True)
self.EndReading()
res.PrepareForOutput()
return res
RegisterReaderClass(".msh", GmshReader)
[docs]def CheckIntegrity():
__testString = u"""
$MeshFormat
2.2 0 8
$EndMeshFormat
$PhysicalNames
3
0 223 "1D"
0 227 "2D"
0 230 "3D"
$EndPhysicalNames
$Nodes
23
1 30 0 0
2 30 0 75
3 30 -2.5 0
4 0.0 0.0 0.0
5 1.0 0.0 0.0
6 1.0 1.0 0.0
7 0.0 1.0 0.0
8 0.0 0.0 1.0
9 1.0 0.0 1.0
10 1.0 1.0 1.0
11 0.0 1.0 1.0
12 0.5 0.0 0.0
13 1.0 0.5 0.0
14 0.5 1.0 0.0
15 0.0 0.5 0.0
16 0.5 0.0 1.0
17 1.0 0.5 1.0
18 0.5 1.0 1.0
19 0.0 0.5 1.0
20 0.0 0.0 0.5
21 1.0 0.0 0.5
22 1.0 1.0 0.5
23 0.0 1.0 0.5
$EndNodes
$Elements
3
1 15 2 223 1 2
2 15 3 227 2 3 1
3 17 3 230 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
$EndElements
this is a comment
"""
res = ReadGmsh(string=__testString)
print("----")
print(res.nodes)
print(res.originalIDNodes)
print(res.GetElementsOfType(ED.ElementType.Bar_2).connectivity)
print(res.GetElementsOfType(ED.ElementType.Hexahedron_20).connectivity)
from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory
newFileName = TemporaryDirectory().GetTempPath()+"mshFile"
open(newFileName, 'w').write(__testString)
res = ReadGmsh(fileName=newFileName)
print(res)
return 'ok'
if __name__ == '__main__':
print(CheckIntegrity()) # pragma: no cover