meshRW 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- meshRW/__init__.py +1 -0
- meshRW/configMESH.py +22 -0
- meshRW/dbmsh.py +172 -0
- meshRW/dbvtk.py +261 -0
- meshRW/fileio.py +141 -0
- meshRW/msh.py +549 -0
- meshRW/msh2.py +280 -0
- meshRW/tests/__init__.py +0 -0
- meshRW/tests/test_data/debug.h5 +0 -0
- meshRW/tests/test_data/mesh2Dref.msh +22613 -0
- meshRW/tests/test_data/mesh3Dref.msh +732323 -0
- meshRW/tests/test_msh.py +275 -0
- meshRW/tests/test_vtk.py +205 -0
- meshRW/various.py +43 -0
- meshRW/vtk.py +423 -0
- meshRW/vtk2.py +249 -0
- meshRW/writerClass.py +212 -0
- meshrw-1.0.0.dist-info/METADATA +184 -0
- meshrw-1.0.0.dist-info/RECORD +21 -0
- meshrw-1.0.0.dist-info/WHEEL +4 -0
- meshrw-1.0.0.dist-info/licenses/LICENSE +21 -0
meshRW/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.0.0'
|
meshRW/configMESH.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file contains the default
|
|
3
|
+
declaration of the keywords
|
|
4
|
+
used to declare/manipulate a mesh in Python
|
|
5
|
+
----
|
|
6
|
+
Luc Laurent - luc.laurent@lecnam.net -- 2021
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
DFLT_MESH = 'connectivity'
|
|
10
|
+
DFLT_TYPE_ELEM = 'type'
|
|
11
|
+
DFLT_PHYS_GRP = 'physgrp'
|
|
12
|
+
DFLT_FIELD_DATA = 'data'
|
|
13
|
+
DFLT_FIELD_TYPE = 'type'
|
|
14
|
+
DFLT_FIELD_TYPE_NODAL = 'nodal'
|
|
15
|
+
DFLT_FIELD_TYPE_ELEMENT = 'elemental'
|
|
16
|
+
DFLT_FIELD_TYPE_NODAL_SCALAR = 'nodal_scalar'
|
|
17
|
+
DFLT_FIELD_TYPE_ELEMENT_SCALAR = 'elemental_scalar'
|
|
18
|
+
DFLT_FIELD_DIM = 'dim'
|
|
19
|
+
DFLT_FIELD_NAME = 'name'
|
|
20
|
+
DFLT_FIELD_STEPS = 'steps'
|
|
21
|
+
DFLT_FIELD_NBSTEPS = 'nbsteps'
|
|
22
|
+
DFLT_FIELD_NUMENTITIES = 'numentities'
|
meshRW/dbmsh.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
""" "
|
|
2
|
+
This file includes the definition
|
|
3
|
+
and tools to manipulate MSH format
|
|
4
|
+
Documentation available here:
|
|
5
|
+
https://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
|
|
6
|
+
----
|
|
7
|
+
Luc Laurent - luc.laurent@lecnam.net -- 2021
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from loguru import logger as Logger
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def loadElementDict():
|
|
15
|
+
"""
|
|
16
|
+
dictionary from element (string) to msh element number
|
|
17
|
+
"""
|
|
18
|
+
elementDict = {
|
|
19
|
+
# 2-nodes line
|
|
20
|
+
'LIN2': {'code': 1, 'nodes': 2, 'dim': 1},
|
|
21
|
+
# 3-nodes second order line
|
|
22
|
+
'LIN3': {'code': 8, 'nodes': 3, 'dim': 1},
|
|
23
|
+
# 4-nodes third order line
|
|
24
|
+
'LIN4': None,
|
|
25
|
+
# 3-nodes triangle
|
|
26
|
+
'TRI3': {'code': 2, 'nodes': 3, 'dim': 2},
|
|
27
|
+
# 6-nodes second order triangle (3 vertices, 3 on edges)
|
|
28
|
+
'TRI6': {'code': 9, 'nodes': 6, 'dim': 2},
|
|
29
|
+
# 9-nodes cubic order triangle (3 vertices, 3 on edges and 3 inside)
|
|
30
|
+
'TRI9': None,
|
|
31
|
+
# 10-nodes higher order triangle (3 vertices, 6 on edges and 1 inside)
|
|
32
|
+
'TRI10': None,
|
|
33
|
+
# 12-nodes higher order triangle (3 vertices and 9 on edges)
|
|
34
|
+
'TRI12': None,
|
|
35
|
+
# 15-nodes higher order triangle (3 vertices, 9 on edges and 3 inside)
|
|
36
|
+
'TRI15': None,
|
|
37
|
+
# 4-nodes quadrangle
|
|
38
|
+
'QUA4': {'code': 3, 'nodes': 4, 'dim': 2},
|
|
39
|
+
# 8-nodes second order quadrangle (4 vertices and 4 on edges)
|
|
40
|
+
'QUA8': {'code': 16, 'nodes': 8, 'dim': 2},
|
|
41
|
+
# 9-nodes higher order quadrangle (4 vertices, 4 on edges and 1 inside)
|
|
42
|
+
'QUA9': {'code': 10, 'nodes': 9, 'dim': 2},
|
|
43
|
+
# 4-nodes tetrahedron
|
|
44
|
+
'TET4': {'code': 4, 'nodes': 4, 'dim': 3},
|
|
45
|
+
# 10-nodes second order tetrahedron (4 vertices and 6 on edges)
|
|
46
|
+
'TET10': {'code': 11, 'nodes': 10, 'dim': 3},
|
|
47
|
+
# 8-nodes hexahedron
|
|
48
|
+
'HEX8': {'code': 5, 'nodes': 8, 'dim': 3},
|
|
49
|
+
# 20-nodes second order hexahedron (8 vertices and 12 on edges)
|
|
50
|
+
'HEX20': {'code': 17, 'nodes': 20, 'dim': 3},
|
|
51
|
+
# 27-nodes higher order hexahedron
|
|
52
|
+
# (8 vertices, 12 on edges, 6 on faces and 1 inside)
|
|
53
|
+
'HEX27': {'code': 12, 'nodes': 27, 'dim': 3},
|
|
54
|
+
# 6-nodes prism
|
|
55
|
+
'PRI6': {'code': 6, 'nodes': 6, 'dim': 3},
|
|
56
|
+
# 15-nodes second order prism (6 vertices and 9 on edges)
|
|
57
|
+
'PRI15': {'code': 18, 'nodes': 15, 'dim': 3},
|
|
58
|
+
# 18-nodes higher order prism (6 vertices, 9 on edges and 3 on faces)
|
|
59
|
+
'PRI18': {'code': 13, 'nodes': 18, 'dim': 3},
|
|
60
|
+
# 5-node pyramid
|
|
61
|
+
'PYR5': {'code': 7, 'nodes': 5, 'dim': 3},
|
|
62
|
+
# 13-nodes second order pyramid (5 edges and 8 on edges)
|
|
63
|
+
'PYR13': {'code': 19, 'nodes': 13, 'dim': 3},
|
|
64
|
+
# 14-nodes higher order pyramid (5 edges, 8 on edges and 1 inside)
|
|
65
|
+
'PYR14': {'code': 14, 'nodes': 14, 'dim': 3},
|
|
66
|
+
# 1-node point
|
|
67
|
+
'NOD1': {'code': 15, 'nodes': 1, 'dim': 0},
|
|
68
|
+
}
|
|
69
|
+
return elementDict
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def getMSHElemType(txtEltype):
|
|
73
|
+
"""
|
|
74
|
+
Get the element type defined as in gmsh (refer to gmsh documentation for numbering) from text declaration
|
|
75
|
+
syntax:
|
|
76
|
+
getMshElemType(txtEltype)
|
|
77
|
+
|
|
78
|
+
input:
|
|
79
|
+
txtEltype: element declared using string (if number is used the function will return it)
|
|
80
|
+
output:
|
|
81
|
+
element type defined as gmsh number
|
|
82
|
+
"""
|
|
83
|
+
elementDict = loadElementDict()
|
|
84
|
+
|
|
85
|
+
# depending on the type of txtEltype
|
|
86
|
+
# - if int: return txtEltype
|
|
87
|
+
# - else get the number from the dictionary
|
|
88
|
+
if isinstance(txtEltype, int):
|
|
89
|
+
elementNum = txtEltype
|
|
90
|
+
else:
|
|
91
|
+
elementNum = elementDict[txtEltype.upper()].get('code', None)
|
|
92
|
+
# show error if the type is not available
|
|
93
|
+
if not elementNum:
|
|
94
|
+
Logger.error(f'Element type {txtEltype} not implemented')
|
|
95
|
+
return elementNum
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def getElemTypeFromMSH(elementNum):
|
|
99
|
+
"""
|
|
100
|
+
Get the element type from id (integer) defined in gmsh (refer to gmsh documentation for numbering)
|
|
101
|
+
syntax:
|
|
102
|
+
getElemTypeFromMSH(elementNum)
|
|
103
|
+
|
|
104
|
+
input:
|
|
105
|
+
elementNum: integer used in gmsh to declare element
|
|
106
|
+
output:
|
|
107
|
+
global name of the element
|
|
108
|
+
"""
|
|
109
|
+
# load the dictionary
|
|
110
|
+
elementDict = loadElementDict()
|
|
111
|
+
globalName = None
|
|
112
|
+
# get the name of the element using the integer iD along the dictionary
|
|
113
|
+
for k, v in elementDict.items():
|
|
114
|
+
if v:
|
|
115
|
+
if v.get('code', None) == elementNum:
|
|
116
|
+
globalName = k
|
|
117
|
+
break
|
|
118
|
+
# if the name of the element if not available show error
|
|
119
|
+
if globalName is None:
|
|
120
|
+
Logger.error(f'Element type not found with id {elementNum}')
|
|
121
|
+
return globalName
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def getNumberNodes(txtElemtype):
|
|
125
|
+
"""
|
|
126
|
+
Get the number of nodes for a specific element type type (declare as string)
|
|
127
|
+
syntax:
|
|
128
|
+
getNumberNodes(txtElemtype)
|
|
129
|
+
|
|
130
|
+
input:
|
|
131
|
+
txtElemtype: element declared using string (if number is used the function wil return it)
|
|
132
|
+
output:
|
|
133
|
+
number of nodes for txtEltype
|
|
134
|
+
"""
|
|
135
|
+
# load the dictionary
|
|
136
|
+
elementDict = loadElementDict()
|
|
137
|
+
nbNodes = 0
|
|
138
|
+
# check if the type of element exists
|
|
139
|
+
if txtElemtype in elementDict.keys():
|
|
140
|
+
# get the number of nodes for the type of element
|
|
141
|
+
if elementDict[txtElemtype]:
|
|
142
|
+
nbNodes = elementDict[txtElemtype].get('nodes', None)
|
|
143
|
+
else:
|
|
144
|
+
# show error message if the type of element does not exist
|
|
145
|
+
Logger.error(f'Element type {txtElemtype} not defined')
|
|
146
|
+
return nbNodes
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def getNumberNodesFromNum(elementNum):
|
|
150
|
+
"""
|
|
151
|
+
Get the number of nodfs for a specific element type type (declare as string)
|
|
152
|
+
syntax:
|
|
153
|
+
getNumberNodesFromNum(elementNum)
|
|
154
|
+
|
|
155
|
+
input:
|
|
156
|
+
elementNum: integer used in gmsh to declare element
|
|
157
|
+
output:
|
|
158
|
+
number of nodes for txtEltype
|
|
159
|
+
"""
|
|
160
|
+
return getNumberNodes(getElemTypeFromMSH(elementNum))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# DEFAULT VALUES
|
|
164
|
+
ALLOWED_EXTENSIONS = ['.msh', '.msh.bz2', '.msh.gz']
|
|
165
|
+
|
|
166
|
+
# Keywords MSH
|
|
167
|
+
DFLT_FILE_OPEN_CLOSE = {'open': '$MeshFormat', 'close': '$EndMeshFormat'}
|
|
168
|
+
DFLT_FILE_VERSION = '2.2 0 8'
|
|
169
|
+
DFLT_NODES_OPEN_CLOSE = {'open': '$Nodes', 'close': '$EndNodes'}
|
|
170
|
+
DFLT_ELEMS_OPEN_CLOSE = {'open': '$Elements', 'close': '$EndElements'}
|
|
171
|
+
DFLT_FIELDS_NODES_OPEN_CLOSE = {'open': '$NodeData', 'close': '$EndNodeData'}
|
|
172
|
+
DFLT_FIELDS_ELEMS_OPEN_CLOSE = {'open': '$ElementData', 'close': '$EndElementData'}
|
meshRW/dbvtk.py
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
""" "
|
|
2
|
+
This file includes the definition and tools to manipulate MSH format
|
|
3
|
+
Documentation available here: https://gmsh.info/doc/texinfo/gmsh.html#MSH-file-format
|
|
4
|
+
----
|
|
5
|
+
Luc Laurent - luc.laurent@lecnam.net -- 2021
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import vtk
|
|
10
|
+
from loguru import logger as Logger
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def loadElementDict():
|
|
14
|
+
"""
|
|
15
|
+
dictionary from element (string) to VTK number
|
|
16
|
+
"""
|
|
17
|
+
elementDict = {
|
|
18
|
+
# 2-nodes line
|
|
19
|
+
'LIN2': {'code': 3, 'nodes': 2, 'dim': 1, 'vtkobj': vtk.vtkLine()},
|
|
20
|
+
# 3-nodes second order line
|
|
21
|
+
'LIN3': {'code': 21, 'nodes': 3, 'dim': 1, 'vtkobj': vtk.vtkQuadraticEdge()},
|
|
22
|
+
# 4-nodes third order line
|
|
23
|
+
'LIN4': None,
|
|
24
|
+
# 3-nodes triangle
|
|
25
|
+
'TRI3': {'code': 5, 'nodes': 3, 'dim': 2, 'vtkobj': vtk.vtkTriangle()},
|
|
26
|
+
# 6-nodes second order triangle (3 vertices, 3 on edges)
|
|
27
|
+
'TRI6': {'code': 22, 'nodes': 6, 'dim': 2, 'vtkobj': vtk.vtkQuadraticTriangle()},
|
|
28
|
+
# 9-nodes cubic order triangle (3 vertices, 3 on edges and 3 inside)
|
|
29
|
+
'TRI9': None,
|
|
30
|
+
# 10-nodes higher order triangle (3 vertices, 6 on edges and 1 inside)
|
|
31
|
+
'TRI10': None,
|
|
32
|
+
# 12-nodes higher order triangle (3 vertices and 9 on edges)
|
|
33
|
+
'TRI12': None,
|
|
34
|
+
# 15-nodes higher order triangle (3 vertices, 9 on edges and 3 inside)
|
|
35
|
+
'TRI15': None,
|
|
36
|
+
# 4-nodes quadrangle
|
|
37
|
+
'QUA4': {'code': 9, 'nodes': 4, 'dim': 2, 'vtkobj': vtk.vtkQuad()},
|
|
38
|
+
# 8-nodes second order quadrangle (4 vertices and 4 on edges)
|
|
39
|
+
'QUA8': {'code': 23, 'nodes': 8, 'dim': 2, 'vtkobj': vtk.vtkQuadraticQuad()},
|
|
40
|
+
# 9-nodes higher order quadrangle (4 vertices, 4 on edges and 1 inside)
|
|
41
|
+
'QUA9': None,
|
|
42
|
+
# 4-nodes tetrahedron
|
|
43
|
+
'TET4': {'code': 10, 'nodes': 4, 'dim': 3, 'vtkobj': vtk.vtkTetra()},
|
|
44
|
+
# 10-nodes second order tetrahedron (4 vertices and 6 on edges)
|
|
45
|
+
'TET10': {'code': 24, 'nodes': 10, 'dim': 3, 'vtkobj': vtk.vtkQuadraticTetra()},
|
|
46
|
+
# 8-nodes hexahedron
|
|
47
|
+
'HEX8': {'code': 12, 'nodes': 8, 'dim': 3, 'vtkobj': vtk.vtkHexahedron()},
|
|
48
|
+
# 20-nodes second order hexahedron (8 vertices and 12 on edges)
|
|
49
|
+
'HEX20': {'code': 25, 'nodes': 20, 'dim': 3, 'vtkobj': vtk.vtkQuadraticHexahedron()},
|
|
50
|
+
# 27-nodes higher order hexahedron (8 vertices,
|
|
51
|
+
# 12 on edges, 6 on faces and 1 inside)
|
|
52
|
+
'HEX27': None,
|
|
53
|
+
# 6-nodes prism
|
|
54
|
+
'PRI6': {'code': 13, 'nodes': 6, 'dim': 3, 'vtkobj': vtk.vtkWedge()},
|
|
55
|
+
# 15-nodes second order prism (6 vertices and 9 on edges)
|
|
56
|
+
'PRI15': None,
|
|
57
|
+
# 18-nodes higher order prism (6 vertices, 9 on edges and 3 on faces)
|
|
58
|
+
'PRI18': None,
|
|
59
|
+
# 5-node pyramid
|
|
60
|
+
'PYR5': {'code': 14, 'nodes': 5, 'dim': 3, 'vtkobj': vtk.vtkPyramid()},
|
|
61
|
+
# 13-nodes second order pyramid (5 edges and 8 on edges)
|
|
62
|
+
'PYR13': None,
|
|
63
|
+
# 14-nodes higher order pyramid (5 edges, 8 on edges and 1 inside)
|
|
64
|
+
'PYR14': None,
|
|
65
|
+
# 1-node point
|
|
66
|
+
'NOD1': {'code': 1, 'nodes': 1, 'dim': 0, 'vtkobj': vtk.vtkVertex()},
|
|
67
|
+
#
|
|
68
|
+
# many nodes
|
|
69
|
+
'NODN': {'code': 2, 'nodes': -1, 'dim': 0, 'vtkobj': vtk.vtkPolyVertex()},
|
|
70
|
+
# many lines (poly-lines)
|
|
71
|
+
'LINEN': {'code': 4, 'nodes': -1, 'dim': 1, 'vtkobj': vtk.vtkPolyLine()},
|
|
72
|
+
# many stripped triangles
|
|
73
|
+
'TRIN': {'code': 6, 'nodes': -1, 'dim': 2, 'vtkobj': vtk.vtkTriangleStrip()},
|
|
74
|
+
# polygons
|
|
75
|
+
'POLY': {'code': 7, 'nodes': -1, 'dim': 2, 'vtkobj': vtk.vtkPolygon()},
|
|
76
|
+
# pixel
|
|
77
|
+
'PIXEL': {'code': 8, 'nodes': -1, 'dim': 2, 'vtkobj': vtk.vtkPixel()},
|
|
78
|
+
# voxel
|
|
79
|
+
'VOXEL': {'code': 11, 'nodes': -1, 'dim': 3, 'vtkobj': vtk.vtkVoxel()},
|
|
80
|
+
}
|
|
81
|
+
return elementDict
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def getVTKtoElem():
|
|
85
|
+
"""
|
|
86
|
+
dictionary from VTK element to name of element (string)
|
|
87
|
+
"""
|
|
88
|
+
VTKtoElem = {
|
|
89
|
+
'VTK_VERTEX': 'NOD1',
|
|
90
|
+
'VTK_LINE': 'LIN2',
|
|
91
|
+
'VTK_TRIANGLE': 'TRI3',
|
|
92
|
+
'VTK_QUAD': 'QUAD4',
|
|
93
|
+
'VTK_TETRA': 'TET4',
|
|
94
|
+
'VTK_HEXAHEDRON': 'HEX8',
|
|
95
|
+
'VTK_WEDGE': 'PRI6',
|
|
96
|
+
'VTK_PYRAMID': 'PYR5',
|
|
97
|
+
'VTK_QUADRATIC_EDGE': 'LIN3',
|
|
98
|
+
'VTK_QUADRATIC_TRIANGLE': 'TRI6',
|
|
99
|
+
'VTK_QUADRATIC_QUAD': 'QUA8',
|
|
100
|
+
'VTK_QUADRATIC_TETRA': 'TET10',
|
|
101
|
+
'VTK_QUADRATIC_HEXAHEDRON': 'HEX20',
|
|
102
|
+
#
|
|
103
|
+
'VTK_POLY_VERTEX': 'NODN',
|
|
104
|
+
'VTK_POLY_LINE': 'LINEN',
|
|
105
|
+
'VTK_TRIANGLE_STRIP': 'TRIN',
|
|
106
|
+
'VTK_POLYGON': 'POLY',
|
|
107
|
+
'VTK_PIXEL': 'PIXEL',
|
|
108
|
+
'VTK_VOXEL': 'VOXEL',
|
|
109
|
+
}
|
|
110
|
+
return VTKtoElem
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def getVTKObj(txtEltype):
|
|
114
|
+
"""
|
|
115
|
+
Get the vtk class from libvtk from text declaration
|
|
116
|
+
syntax:
|
|
117
|
+
getVTKEObjType(txtEltype)
|
|
118
|
+
|
|
119
|
+
input:
|
|
120
|
+
txtEltype: element declared using VTK string (if number is used the function wil return it)
|
|
121
|
+
output:
|
|
122
|
+
vtk class for the requested element
|
|
123
|
+
number of nodes on element
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
VTKtoElem = getVTKtoElem()
|
|
127
|
+
elementDict = loadElementDict()
|
|
128
|
+
|
|
129
|
+
# depending on the type of txtEltype
|
|
130
|
+
numPerElement = -1
|
|
131
|
+
if txtEltype.upper() in VTKtoElem.keys():
|
|
132
|
+
txtEltype = VTKtoElem[txtEltype]
|
|
133
|
+
vtkobj = elementDict[txtEltype.upper()].get('vtkobj', None)
|
|
134
|
+
numPerElement = getNumberNodes(txtEltype.upper())
|
|
135
|
+
if not vtkobj:
|
|
136
|
+
Logger.error(f'Element type {txtEltype} not implemented')
|
|
137
|
+
return vtkobj, numPerElement
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def getVTKElemType(txtEltype):
|
|
141
|
+
"""
|
|
142
|
+
Get the element type defined as in vtk (refer to VTK documentation for numbering) from text declaration
|
|
143
|
+
syntax:
|
|
144
|
+
getVTKElemType(txtEltype)
|
|
145
|
+
|
|
146
|
+
input:
|
|
147
|
+
txtEltype: element declared using VTK string (if number is used the function wil return it)
|
|
148
|
+
output:
|
|
149
|
+
element type defined as VTK number
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
VTKtoElem = getVTKtoElem()
|
|
153
|
+
elementDict = loadElementDict()
|
|
154
|
+
|
|
155
|
+
# depending on the type of txtEltype
|
|
156
|
+
numPerElement = -1
|
|
157
|
+
if isinstance(txtEltype, int):
|
|
158
|
+
elementNum = txtEltype
|
|
159
|
+
else:
|
|
160
|
+
if txtEltype.upper() in VTKtoElem.keys():
|
|
161
|
+
txtEltype = VTKtoElem[txtEltype]
|
|
162
|
+
elementNum = elementDict[txtEltype.upper()].get('code', None)
|
|
163
|
+
numPerElement = getNumberNodes(txtEltype.upper())
|
|
164
|
+
if not elementNum:
|
|
165
|
+
Logger.error(f'Element type {txtEltype} not implemented')
|
|
166
|
+
return elementNum, numPerElement
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def getElemTypeFromVTK(elementNum):
|
|
170
|
+
"""
|
|
171
|
+
Get the element type from id (integer) defined in gmsh (refer to gmsh documentation for numbering)
|
|
172
|
+
syntax:
|
|
173
|
+
getElemTypeFromVTK(elementNum)
|
|
174
|
+
|
|
175
|
+
input:
|
|
176
|
+
elementNum: integer used in gmsh to declare element
|
|
177
|
+
output:
|
|
178
|
+
global name of the element
|
|
179
|
+
"""
|
|
180
|
+
# load the dictionary
|
|
181
|
+
elementDict = loadElementDict()
|
|
182
|
+
globalName = None
|
|
183
|
+
# get the name of the element using the integer iD along the dictionary
|
|
184
|
+
for k, v in elementDict.items():
|
|
185
|
+
if v:
|
|
186
|
+
if v.get('code', None) == elementNum:
|
|
187
|
+
globalName = k
|
|
188
|
+
break
|
|
189
|
+
# if the name of the element if not available show error
|
|
190
|
+
if globalName is None:
|
|
191
|
+
Logger.error(f'Element type not found with id {elementNum}')
|
|
192
|
+
return globalName
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def getNumberNodes(txtElemtype):
|
|
196
|
+
"""
|
|
197
|
+
Get the number of nodes for a specific element type type (declare as string)
|
|
198
|
+
syntax:
|
|
199
|
+
getNumberNodes(txtElemtype)
|
|
200
|
+
|
|
201
|
+
input:
|
|
202
|
+
txtElemtype: element declared using string (if number is used the function wil return it)
|
|
203
|
+
output:
|
|
204
|
+
number of nodes for txtEltype
|
|
205
|
+
"""
|
|
206
|
+
|
|
207
|
+
elementDict = loadElementDict()
|
|
208
|
+
# check if the type of element exists
|
|
209
|
+
if txtElemtype in elementDict.keys():
|
|
210
|
+
# get the number of nodes for the type of element
|
|
211
|
+
if elementDict[txtElemtype]:
|
|
212
|
+
nbNodes = elementDict[txtElemtype].get('nodes', None)
|
|
213
|
+
else:
|
|
214
|
+
# show error message if the type of element does not exist
|
|
215
|
+
Logger.error(f'Element type {txtElemtype} not defined')
|
|
216
|
+
return nbNodes
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def getNumberNodesFromNum(elementNum):
|
|
220
|
+
"""
|
|
221
|
+
Get the number of nodfs for a specific element type type (declare as string)
|
|
222
|
+
syntax:
|
|
223
|
+
getNumberNodesFromNum(elementNum)
|
|
224
|
+
|
|
225
|
+
input:
|
|
226
|
+
elementNum: integer used in gmsh to declare element
|
|
227
|
+
output:
|
|
228
|
+
number of nodes for txtEltype
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
return getNumberNodes(getElemTypeFromVTK(elementNum))
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# DEFAULT VALUES
|
|
235
|
+
ALLOWED_EXTENSIONS = [
|
|
236
|
+
'.vtk',
|
|
237
|
+
'.vtk.bz2',
|
|
238
|
+
'.vtk.gz',
|
|
239
|
+
'.vtu',
|
|
240
|
+
'.vtu.bz2',
|
|
241
|
+
'.vtu.gz',
|
|
242
|
+
]
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# Keywords MSH
|
|
246
|
+
DFLT_HEADER_VERSION = '# vtk DataFile Version 2.0'
|
|
247
|
+
DFLT_TYPE_ASCII = 'ASCII'
|
|
248
|
+
DFLT_FILE_VERSION = '2.2 0 8'
|
|
249
|
+
DFLT_TYPE_MESH = 'DATASET UNSTRUCTURED_GRID'
|
|
250
|
+
DFLT_NODES = 'POINTS'
|
|
251
|
+
DFLT_NODES_DATA = 'POINT_DATA'
|
|
252
|
+
DFLT_DOUBLE = 'double'
|
|
253
|
+
DFLT_FLOAT = 'float'
|
|
254
|
+
DFLT_INT = 'int'
|
|
255
|
+
DFLT_ELEMS = 'CELLS'
|
|
256
|
+
DFLT_ELEMS_TYPE = 'CELL_TYPES'
|
|
257
|
+
DFLT_ELEMS_DATA = 'CELL_DATA'
|
|
258
|
+
DFLT_FIELD = 'FIELD'
|
|
259
|
+
DFLT_SCALARS = 'SCALARS'
|
|
260
|
+
DFLT_TABLE = 'LOOKUP_TABLE'
|
|
261
|
+
DFLT_TABLE_DEFAULT = 'default'
|
meshRW/fileio.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This file includes the definition and tools to manipulate files
|
|
3
|
+
----
|
|
4
|
+
Luc Laurent - luc.laurent@lecnam.net -- 2021
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import time
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from loguru import logger as Logger
|
|
11
|
+
|
|
12
|
+
from . import various
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class fileHandler:
|
|
16
|
+
def __init__(self, filename=None, append=None, right='w', gz=False, bz2=False, safeMode=False):
|
|
17
|
+
"""
|
|
18
|
+
create the class
|
|
19
|
+
arguments:
|
|
20
|
+
- filename: name of the file to open
|
|
21
|
+
- append: append to existing file (override 'right')
|
|
22
|
+
- right: specific right when open the file ('r','a','w'...)
|
|
23
|
+
- gz: on the fly compress file with gunzip
|
|
24
|
+
- bz2: on the fly compress file with bunzip2
|
|
25
|
+
- safeMode: avoid overwritten
|
|
26
|
+
"""
|
|
27
|
+
self.filename = None
|
|
28
|
+
self.dirname = None
|
|
29
|
+
self.fhandle = None
|
|
30
|
+
self.right = right
|
|
31
|
+
self.append = None
|
|
32
|
+
self.compress = None
|
|
33
|
+
self.startTime = 0
|
|
34
|
+
#
|
|
35
|
+
self.fixRight(append=append, right=right)
|
|
36
|
+
|
|
37
|
+
# check arguments
|
|
38
|
+
checkOk = True
|
|
39
|
+
if not filename:
|
|
40
|
+
checkOk = False
|
|
41
|
+
Logger.error('Filename argument missing')
|
|
42
|
+
if not right and not append:
|
|
43
|
+
checkOk = False
|
|
44
|
+
Logger.error('Right(s) not provided')
|
|
45
|
+
# load the filename
|
|
46
|
+
self.getFilename(Path(filename), gz, bz2)
|
|
47
|
+
# open the file
|
|
48
|
+
self.open(safeMode)
|
|
49
|
+
|
|
50
|
+
def getFilename(self, filename, gz=None, bz2=None):
|
|
51
|
+
"""
|
|
52
|
+
Load the right filename
|
|
53
|
+
"""
|
|
54
|
+
self.compress = None
|
|
55
|
+
# check extension for compression
|
|
56
|
+
if filename.suffix == '.gz':
|
|
57
|
+
self.compress = 'gz'
|
|
58
|
+
elif filename.suffix == '.bz2':
|
|
59
|
+
self.compress = 'bz2'
|
|
60
|
+
elif gz:
|
|
61
|
+
filename.with_suffix(filename.suffix + '.gz')
|
|
62
|
+
self.compress = 'gz'
|
|
63
|
+
elif bz2:
|
|
64
|
+
filename.with_suffix(filename.suffix + '.bz2')
|
|
65
|
+
self.compress = 'bz2'
|
|
66
|
+
# extract information about filename
|
|
67
|
+
self.basename = filename.name
|
|
68
|
+
self.dirname = filename.absolute().parent
|
|
69
|
+
self.filename = filename
|
|
70
|
+
|
|
71
|
+
def open(self, safeMode=False):
|
|
72
|
+
"""
|
|
73
|
+
Open the file w/- or W/o safe mode (avoid overwrite existing file
|
|
74
|
+
"""
|
|
75
|
+
# adapt the rights (in case of the file does not exist)
|
|
76
|
+
if self.append and self.filename.exists():
|
|
77
|
+
Logger.warning(f'{self.basename} does not exist! Unable to append')
|
|
78
|
+
self.fixRight(append=False)
|
|
79
|
+
if not safeMode and self.filename.exists() and not self.append and 'w' in self.right:
|
|
80
|
+
Logger.warning(f'{self.basename} already exists! It will be overwritten')
|
|
81
|
+
if safeMode and self.filename.exists() and not self.append and 'w' in self.right:
|
|
82
|
+
Logger.warning(f'{self.basename} already exists! Not overwrite it')
|
|
83
|
+
else:
|
|
84
|
+
#
|
|
85
|
+
Logger.debug(f'Open {self.basename} in {self.dirname} with right {self.right}')
|
|
86
|
+
# open file
|
|
87
|
+
if self.compress == 'gz':
|
|
88
|
+
Logger.debug('Use GZ lib')
|
|
89
|
+
import gzip
|
|
90
|
+
|
|
91
|
+
self.fhandle = gzip.open(self.filename, self.right)
|
|
92
|
+
elif self.compress == 'bz2':
|
|
93
|
+
Logger.debug('Use BZ2 lib')
|
|
94
|
+
import bz2
|
|
95
|
+
|
|
96
|
+
self.fhandle = bz2.open(self.filename, self.right)
|
|
97
|
+
else:
|
|
98
|
+
self.fhandle = open(self.filename, self.right)
|
|
99
|
+
# store timestamp at opening
|
|
100
|
+
self.startTime = time.perf_counter()
|
|
101
|
+
return self.fhandle
|
|
102
|
+
|
|
103
|
+
def close(self):
|
|
104
|
+
"""
|
|
105
|
+
Close openned file
|
|
106
|
+
"""
|
|
107
|
+
if self.fhandle:
|
|
108
|
+
self.fhandle.close()
|
|
109
|
+
self.fhandle = None
|
|
110
|
+
Logger.info(
|
|
111
|
+
f'Close file {self.basename} with elapsed time {time.perf_counter()-self.startTime:g}s - size {various.convert_size(self.filename.stat().st_size)}'
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
def getHandler(self):
|
|
115
|
+
"""
|
|
116
|
+
get the file handler
|
|
117
|
+
"""
|
|
118
|
+
return self.fhandle
|
|
119
|
+
|
|
120
|
+
def write(self, txt):
|
|
121
|
+
"""
|
|
122
|
+
write in the file using handle
|
|
123
|
+
"""
|
|
124
|
+
return self.fhandle.write(txt)
|
|
125
|
+
|
|
126
|
+
def fixRight(self, append=None, right=None):
|
|
127
|
+
"""
|
|
128
|
+
Fix issue on right to write file
|
|
129
|
+
"""
|
|
130
|
+
if append is not None:
|
|
131
|
+
self.append = append
|
|
132
|
+
if append:
|
|
133
|
+
self.right = 'a'
|
|
134
|
+
else:
|
|
135
|
+
self.right = 'w'
|
|
136
|
+
else:
|
|
137
|
+
self.right = right
|
|
138
|
+
if right[0] == 'w':
|
|
139
|
+
self.append = False
|
|
140
|
+
elif right[0] == 'a':
|
|
141
|
+
self.append = True
|