# -*- 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 Writer (gmesh mesh files)
"""
from itertools import combinations
import numpy as np
import BasicTools.Containers.ElementNames as EN
from BasicTools.Containers.MeshBase import Tag as Tag
from BasicTools.IO.WriterBase import WriterBase as WriterBase
from BasicTools.NumpyDefs import PBasicFloatType, PBasicIndexType
from BasicTools.IO.GmshTools import gmshName,PermutationGmshToBasicTools
PermutationBasicToolsToGmsh = {key:np.argsort(value) for key, value in PermutationGmshToBasicTools.items() }
[docs]class OverlappingTagException(Exception):
pass
[docs]def WriteMeshToGmsh(filename, mesh, useOriginalId = False, tagMapping = None):
"""Function API for writing data into a gmsh file
Parameters
----------
fileName : str
name of the file to be written
mesh : UnstructuredMesh
the mesh to be written
useOriginalId : bool, optional
If True, Original Id for the number of nodes and elements are used
(the user is responsible of the consistency of this data), by default False
tagMapping : dict, optional
tags of geometric objects defined in the mesh, by default None
"""
OW = GmshWriter()
if tagMapping is not None:
OW.tagMapping=tagMapping
OW.Open(filename)
OW.Write(mesh, useOriginalId = useOriginalId)
OW.Close()
[docs]class GmshWriter(WriterBase):
"""Class to writes a gmsh file on disk
"""
def __init__(self):
super(GmshWriter,self).__init__()
self.SetBinary(False)
self.canHandleBinaryChange = False
self.tagMapping=dict()
self.userRequiredTags=[]
def __str__(self):
res = 'GmshWriter : \n'
res += ' FileName : '+str(self.fileName)+'\n'
return res
[docs] def SetFileName(self, fileName):
"""Sets the fileName parameter of the class
Parameters
----------
string : str
fileName to set
"""
self.fileName = fileName
[docs] def Write(self,meshObject,useOriginalId=False,PointFieldsNames=None,PointFields=None,CellFieldsNames=None,CellFields=None):
"""Function to writes a gmsh file on disk
Parameters
----------
meshObject : UnstructuredMesh
support of the data to be written
useOriginalId : bool, optional
If True original ids of vertices and elements, by default False
PointFieldsNames : _type_, optional
Not Used, by default None
PointFields : _type_, optional
Not Used, by default None
CellFieldsNames : _type_, optional
Not Used, by default None
CellFields : _type_, optional
Not Used, by default None
Raises
------
OverlappingTagException
when at least 2 tags are overlapping
"""
self.filePointer.write("$MeshFormat\n")
self.filePointer.write("2.2 0 8\n")
self.filePointer.write("$EndMeshFormat\n")
self.filePointer.write("$Nodes\n")
numberofpoints = meshObject.GetNumberOfNodes()
self.filePointer.write(f"{numberofpoints}\n")
posn = meshObject.GetPosOfNodes()
if useOriginalId:
for n in range(numberofpoints):
self.filePointer.write("{} ".format(int(meshObject.originalIDNodes[n])))
posn[np.newaxis,n,:].tofile(self.filePointer, sep=" ")
self.filePointer.write("\n")
else:
for n in range(numberofpoints):
self.filePointer.write(f"{n+1} ")
posn[np.newaxis,n,:].tofile(self.filePointer, sep=" ")
self.filePointer.write("\n")
self.filePointer.write("$EndNodes\n")
self.filePointer.write("$Elements\n")
self.filePointer.write(f"{meshObject.GetNumberOfElements()}\n")
cpt = 1
celltags = meshObject.GetNamesOfElemTags()
elements = meshObject.elements
if self.tagMapping:
self.userRequiredTags=self.tagMapping.keys()
minTagVal=max(self.tagMapping.values())+1
notMappedTagNames=sorted(list(set(celltags)-set(self.tagMapping.keys())))
notMappedTagsValue=np.arange(minTagVal,minTagVal+len(notMappedTagNames),dtype=int)
notMappedTagsMapping=dict(zip(notMappedTagNames, notMappedTagsValue))
self.tagMapping={**notMappedTagsMapping,**self.tagMapping}
# tagcounter = 2
#for tagname in celtags:
for elementContainer in elements:
elemtype = gmshName[elementContainer]
#try:
data = meshObject.elements[elementContainer]
phyGeoTags=np.ones(data.GetNumberOfElements(), PBasicIndexType)
elemIdsInTags={tagName:data.tags[tagName].GetIds() for tagName in self.userRequiredTags if tagName in data.tags}
if elemIdsInTags.keys():
tagPairs=list(combinations(elemIdsInTags.keys(), 2))
for tag1,tag2 in tagPairs:
idsTag1,idsTag2=elemIdsInTags[tag1],elemIdsInTags[tag2]
commonIds=np.intersect1d(idsTag1,idsTag2)
if commonIds.size > 0:
print("Common element ids for pair "+str(tag1)+","+str(tag2)+" are: ",str(commonIds))
raise OverlappingTagException("At least 2 tags are overlapping, cannot be handled properly naturally in .msh 2.2 format")
for tagName in self.tagMapping.keys():
if tagName in data.tags:
elemIds = data.tags[tagName].GetIds()
phyGeoTags[elemIds] = self.tagMapping[tagName]
if useOriginalId:
for i in range(data.GetNumberOfElements() ):
self.filePointer.write(f"{data.originalIds[i]} {elemtype} 2 {phyGeoTags[i]} {phyGeoTags[i]} ")
self.filePointer.write(" ".join([str(meshObject.originalIDNodes[x]) for x in data.connectivity[i,:].ravel()]))
cpt += 1
self.filePointer.write("\n")
else:
#for connectivity in meshObject.elements[elementContainer].connectivity[meshObject.elements[elementContainer].tags[tagname].id-1]:
for i in range(data.GetNumberOfElements() ):
connectivity = data.connectivity[i,:]
if elementContainer in PermutationBasicToolsToGmsh:
connectivity = [connectivity[x] for x in PermutationBasicToolsToGmsh[elementContainer]]
self.filePointer.write(f"{cpt} {elemtype} 2 {phyGeoTags[i]} {phyGeoTags[i]} ")
self.filePointer.write(" ".join([str(x+1) for x in connectivity]))
cpt += 1
self.filePointer.write("\n")
#except KeyError:
# continue
#tagcounter += 1
self.filePointer.write("$EndElements\n")
from BasicTools.IO.IOFactory import RegisterWriterClass
RegisterWriterClass(".msh",GmshWriter)
[docs]def CheckIntegrity():
totest = [
CheckIntegrity_SeparatedTags,
CheckIntegrity_OriginalIdsForTags,
CheckIntegrity_OverlappingTags
]
for test in totest:
res = test()
if res.lower() != "ok" :
return res
return "OK"
if __name__ == '__main__':
print(CheckIntegrity())# pragma: no cover