Source code for BasicTools.IO.GmshReader

# -*- 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)

"""
import numpy as np
from typing import Optional, Dict, List

import BasicTools.Containers.ElementNames as EN
from BasicTools.Containers.UnstructuredMesh  import UnstructuredMesh
from BasicTools.IO.ReaderBase import ReaderBase
from BasicTools.NumpyDefs import PBasicIndexType
from BasicTools.IO.GmshTools import gmshNumber,PermutationGmshToBasicTools

[docs]def ReadGmsh(fileName: Optional[str]=None, string: Optional[str]=None, out=None, **kwargs) -> UnstructuredMesh: """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 : UnstructuredMesh, optional output unstructured mesh object containing reading result, by default None Returns ------- UnstructuredMesh 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 UnstructuredMesh 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.commentChar= "%" self.readFormat = 'r'
[docs] def Read(self, fileName: Optional[str]=None, string: Optional[str]=None, out: Optional[UnstructuredMesh]=None) -> UnstructuredMesh: """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 : UnstructuredMesh, optional output unstructured mesh object containing reading result, by default None Returns ------- UnstructuredMesh 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 = UnstructuredMesh() else: res = out fileToInternalId: Dict[str,PBasicIndexType] = {} 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=PBasicIndexType) 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,PBasicIndexType]] = {} cpt: PBasicIndexType =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 PermutationGmshToBasicTools: conn = [conn[x] for x in PermutationGmshToBasicTools[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 print("ignoring line : " + l ) ## convert to 2D if needed if np.linalg.norm(res.nodes[:,2]) == 0: from BasicTools.Containers.UnstructuredMeshModificationTools import LowerNodesDimension res = LowerNodesDimension(res) ## apply tags names for dim,number,newName in tagsNames: for name,data in res.elements.items(): if EN.dimension[name] != dim : continue self.PrintVerbose("changing tag form '" + str("PhyTag"+number) + "' to '" + str(newName)+"'") data.tags.RenameTag("PhyTag"+number,newName,noError=True) self.EndReading() res.PrepareForOutput() return res
from BasicTools.IO.IOFactory import RegisterReaderClass 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('bar2').connectivity) print(res.GetElementsOfType('hex20').connectivity) from BasicTools.Helpers.Tests import TestTempDir newFileName = TestTempDir().GetTempPath()+"mshFile" open(newFileName,'w').write(__testString) res = ReadGmsh(fileName=newFileName) print(res) return 'ok'
if __name__ == '__main__': print(CheckIntegrity())# pragma: no cover