-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGMSH2Jive.py
320 lines (252 loc) · 10.4 KB
/
GMSH2Jive.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# Python script to convert GMSH files to JIVE format
import sys
import gmsh
import os.path
import numpy as np
import argparse
from itemset import ItemSet
from indexdict import IndexDict
from node import Node
from element import Element
def parseGMSH( args ):
fname = args.file
meshRank = args.meshRank
# Create a element map for GMSH types
# (elemID -> nnodes)
elTypeToNNodes = {}
elTypeToNNodes[1] = 2 # Line2
elTypeToNNodes[2] = 3 # Triangle3
elTypeToNNodes[3] = 4 # Quad4
elTypeToNNodes[8] = 3 # Line3
elTypeToNNodes[9] = 6 # Triangle6
# Initialize a database to store mesh data
globdat = {}
globdat["nGroups"] = {} # node groups
globdat["eGroups"] = {} # element groups
# Create empty item sets to store nodes and elements
nodeset = ItemSet()
elemset = ItemSet()
# Create an empty dictionary to store the element groups
eGroups = IndexDict()
# All set, now initialize GMSH with no terminal output
gmsh.initialize()
gmsh.option.set_number('General.Terminal', 0)
# Open the mesh file in gmsh (all versions should work!)
gmsh.open(fname)
# If .geo file is provided, generate and save the mesh
ext = os.path.splitext(fname)[1]
ffname = os.path.splitext(fname)[0]
if ext == ".geo":
print(" -- Reading a mesh file: " + fname )
try:
gmsh.model.geo.synchronize()
gmsh.model.mesh.generate(meshRank)
gmsh.write(ffname +".msh")
gmsh.open(ffname +".msh")
print(" -- Created a mesh file: "
+ ffname + ".msh")
except Exception as e:
raise e
# Extract all nodes in the mesh
nodes = gmsh.model.mesh.getNodes(dim=-1,tag=-1)
# Add nodes to node set
for i in range(len(nodes[0])):
nodeset.addItem( idx=nodes[0][i],
item=Node(nodes[1][3*i:3*i+meshRank]) )
# Get all entities associated with the gmsh model
entities = gmsh.model.getEntities()
# Sort entities such that higher 'dim' are ahead
sorted_entities = sorted(entities, key=lambda x: (x[0], x[1]), reverse=True)
# Element index
elemIdx = 0
# Loop over the entities
for (dim,tag) in sorted_entities:
# Extract physical groups, if present
phyGroups = gmsh.model.getPhysicalGroupsForEntity(dim,\
tag)
# Extract physical names, if phyGroups are found
if phyGroups is []:
phyNames = []
else:
try:
phyNames = gmsh.model.getPhysicalName(dim,\
phyGroups)
except Exception as e:
#print(e)
phyNames = gmsh.model.getPhysicalName(dim,\
phyGroups[0])
# Extract elements for this entity
elems = gmsh.model.mesh.getElements(dim=dim,tag=tag)
# Extract number of nodes for the element type
nNodes = elTypeToNNodes[elems[0][0]]
# Add elements to elem set
for i in range(len(elems[1][0])):
elemIdx += 1
elemset.addItem( idx=elemIdx,
item=Element(elems[2][0][nNodes*i:\
nNodes*i+nNodes],
gmshType=elems[0][0]) )
# If there are physical names, create an element
# group and add element indices to it
if phyNames:
eGroups.append( key=str(phyNames),
value=int(elemIdx) )
# Otherwise, create an element group based on the tag
# and add element indices to it
else:
eGroups.append( key="elemTag"+str(tag),
value=int(elemIdx) )
eGroups.append( key="elems"+str(dim)+"D",
value=int(elemIdx) )
# Store all info in globdat
globdat["nSet"] = nodeset
globdat["eSet"] = elemset
globdat["eGroups"] = eGroups
globdat["eGroups"]['all'] = globdat["eSet"].getAllIndices()
# Create special node groups
for name, ielems in globdat["eGroups"].items():
nodes = []
for ielem in ielems:
for inode in globdat["eSet"].getItem(ielem).getNodes():
nodes.append(inode)
nodes = np.unique(np.array(nodes,dtype=int))
globdat["nGroups"][name] = nodes
gmsh.finalize()
print(" -- Parsed the mesh file: " + ffname + ".msh")
print(" -- Nodes: " + str(nodeset.size()) )
print(" -- Elems: " + str(elemset.size()) )
print(" -- 1D: " + str(len(eGroups["elems1D"])) )
print(" -- 2D: " + str(len(eGroups["elems2D"])) )
if meshRank == 3:
print(" -- 3D: " + str(len(eGroups["elems_3D"])) )
return globdat
def printJiveMesh( args, globdat):
fname = args.file
# Create a element map for GMSH types
# (elemID -> jive node ordering)
elTypeToNodeOrd = {}
elTypeToNodeOrd[1] = np.array([0,1]) # Line2
elTypeToNodeOrd[2] = np.array([0,1,2]) # Triangle3
elTypeToNodeOrd[3] = np.array([0,1,2,3]) # Quad4
elTypeToNodeOrd[8] = np.array([0,2,1]) # Line3
elTypeToNodeOrd[9] = np.array([0,3,1,4,2,5]) # Triangle6
ffname = os.path.splitext(fname)[0]
with open(ffname+'.mesh', 'w') as fout:
# Print nodes
fout.write("<Nodes>\n")
for i in sorted(globdat["nSet"].getAllIndices()):
coords = globdat["nSet"].getItem(i).getCoords()
fout.write(f"{i} {coords[0]} {coords[1]}; \n")
fout.write("</Nodes>\n\n\n")
# Print elements
fout.write("<Elements>\n")
for i in sorted(globdat["eSet"].getAllIndices()):
enodes = globdat["eSet"].getItem(i).getNodes()
perm = elTypeToNodeOrd[globdat["eSet"].getItem(i).getGMSHType()]
fout.write(f"{i} "+" ".join(map(str,enodes[perm]))+";\n")
fout.write("</Elements>\n\n\n")
# Print node groups
# Loop over all node groups
for name, inodes in globdat["nGroups"].items():
fout.write("<NodeGroup name="+ name +"Nodes>\n{")
for inode in inodes:
fout.write( str(inode) +",")
fout.write("}\n</NodeGroup>\n\n")
# Print node groups
# Loop over all node groups
for name, ielems in globdat["eGroups"].items():
fout.write("<ElementGroup name="+ name +"Elems>\n{")
for ielem in ielems:
fout.write( str(ielem) +",")
fout.write("}\n</ElementGroup>\n\n")
return True
def printJiveIPNodes( args, globdat ):
fname = args.file
dim = args.meshRank
# Dummy IP nodes are printed only for domain elements
# not face elements (one can change this construct!)
# Create a element map for GMSH types
# (elemID -> jive node ordering)
elTypes = {}
elTypes[2] = np.array([2,3,9,10,16])
elTypes[3] = np.array([4,5,6,7,11,12,13,14,17,18,19])
nodeID = max(globdat["nSet"].getAllIndices())
ipnodeset = ItemSet()
ipGroups = IndexDict() # ip node groups
# hard-coded for now!
excluded_list = ["all","elems_1D","elems_2D","elems_3D"]
# Loop over all element groups
# (one IP node per element is assumed!)
for name, ielems in globdat["eGroups"].items():
if name not in excluded_list:
elType = globdat["eSet"].getItem(ielems[0]).getGMSHType()
if dim == 2 and elType in elTypes[dim]:
# Create dummy nodes
for i in range(len(ielems)):
nodeID += 1
ipnodeset.addItem( idx=nodeID,
item=Node( np.array([0.0, 0.0]) ) )
ipGroups.append( key=str(name),
value=int(nodeID) )
# Print them to a file
if len(ipGroups) > 0:
ffname = os.path.splitext(fname)[0]
with open(ffname+'.ipnodes', 'w') as fout:
# Print nodes
fout.write("<Nodes>\n")
for i in ipnodeset.getAllIndices():
coords = ipnodeset.getItem(i).getCoords()
fout.write(f"{int(i)} {coords[0]} {coords[1]}; \n")
fout.write("</Nodes>\n\n\n")
# Print node groups
# Loop over all node groups
for name, inodes in ipGroups.items():
fout.write("<NodeGroup name="+ name +"IPNodes>\n{")
for inode in inodes:
fout.write( str(inode) +",")
fout.write("}\n</NodeGroup>\n\n")
return True
def main():
# Create a parser
parser = argparse.ArgumentParser(description="Command line options")
# Add arguments
parser.add_argument("--file", type=str, \
help="filename with extension", \
default = None)
parser.add_argument("--meshRank", type=int, \
help="mesh dimension (1,2,3)", \
default = 2)
parser.add_argument("--sortElems", type=bool, \
help="sort elements reverse dimension-wise", \
default = True)
parser.add_argument("--ip", type=bool, \
help="print dummy IP nodes to file", \
default = False)
# Parse the arguments
args = parser.parse_args()
# Get filename and check for a valid extension
fname = args.file
ext = os.path.splitext(fname)[1]
if ext != ".msh" and ext != ".geo":
raise Exception("Illegal file format!" +
"Only GMSH files with extension .msh or .geo are supported! ")
# Parse GMSH mesh
globdat = parseGMSH( args )
# Print Jive mesh
status = printJiveMesh( args, globdat )
# Check print status
if status:
print(" -- Printed Jive mesh file ")
else:
print(" -- GMSH to Jive mesh conversion: FAILED!")
# Print Jive ip nodes
if args.ip:
status = printJiveIPNodes( args, globdat )
# Check print status
if status:
print(" -- Printed Dummy IP nodes to file ")
print(" -- Use MergeDummyNodes.py to merge with the mesh file ")
else:
print(" -- Dummy IP nodes to file: FAILED!")
if __name__ == "__main__":
main()