capytaine 2.3__cp312-cp312-macosx_14_0_arm64.whl → 3.0.0a1__cp312-cp312-macosx_14_0_arm64.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.
- capytaine/.dylibs/libgcc_s.1.1.dylib +0 -0
- capytaine/.dylibs/libgfortran.5.dylib +0 -0
- capytaine/.dylibs/libquadmath.0.dylib +0 -0
- capytaine/__about__.py +7 -2
- capytaine/__init__.py +8 -12
- capytaine/bem/engines.py +234 -354
- capytaine/bem/problems_and_results.py +30 -21
- capytaine/bem/solver.py +205 -81
- capytaine/bodies/bodies.py +279 -862
- capytaine/bodies/dofs.py +136 -9
- capytaine/bodies/hydrostatics.py +540 -0
- capytaine/bodies/multibodies.py +216 -0
- capytaine/green_functions/{libs/Delhommeau_float32.cpython-312-darwin.so → Delhommeau_float32.cpython-312-darwin.so} +0 -0
- capytaine/green_functions/{libs/Delhommeau_float64.cpython-312-darwin.so → Delhommeau_float64.cpython-312-darwin.so} +0 -0
- capytaine/green_functions/abstract_green_function.py +2 -2
- capytaine/green_functions/delhommeau.py +50 -31
- capytaine/green_functions/hams.py +19 -13
- capytaine/io/legacy.py +3 -103
- capytaine/io/xarray.py +15 -10
- capytaine/meshes/__init__.py +2 -6
- capytaine/meshes/abstract_meshes.py +375 -0
- capytaine/meshes/clean.py +302 -0
- capytaine/meshes/clip.py +347 -0
- capytaine/meshes/export.py +89 -0
- capytaine/meshes/geometry.py +244 -394
- capytaine/meshes/io.py +433 -0
- capytaine/meshes/meshes.py +621 -676
- capytaine/meshes/predefined/cylinders.py +22 -56
- capytaine/meshes/predefined/rectangles.py +26 -85
- capytaine/meshes/predefined/spheres.py +4 -11
- capytaine/meshes/quality.py +118 -407
- capytaine/meshes/surface_integrals.py +48 -29
- capytaine/meshes/symmetric_meshes.py +641 -0
- capytaine/meshes/visualization.py +353 -0
- capytaine/post_pro/free_surfaces.py +1 -4
- capytaine/post_pro/kochin.py +10 -10
- capytaine/tools/block_circulant_matrices.py +275 -0
- capytaine/tools/lists_of_points.py +2 -2
- capytaine/tools/memory_monitor.py +45 -0
- capytaine/tools/symbolic_multiplication.py +31 -5
- capytaine/tools/timer.py +68 -42
- {capytaine-2.3.dist-info → capytaine-3.0.0a1.dist-info}/METADATA +8 -14
- capytaine-3.0.0a1.dist-info/RECORD +65 -0
- capytaine-3.0.0a1.dist-info/WHEEL +6 -0
- capytaine/bodies/predefined/__init__.py +0 -6
- capytaine/bodies/predefined/cylinders.py +0 -151
- capytaine/bodies/predefined/rectangles.py +0 -111
- capytaine/bodies/predefined/spheres.py +0 -70
- capytaine/green_functions/FinGreen3D/.gitignore +0 -1
- capytaine/green_functions/FinGreen3D/FinGreen3D.f90 +0 -3589
- capytaine/green_functions/FinGreen3D/LICENSE +0 -165
- capytaine/green_functions/FinGreen3D/Makefile +0 -16
- capytaine/green_functions/FinGreen3D/README.md +0 -24
- capytaine/green_functions/FinGreen3D/test_program.f90 +0 -39
- capytaine/green_functions/LiangWuNoblesse/.gitignore +0 -1
- capytaine/green_functions/LiangWuNoblesse/LICENSE +0 -504
- capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90 +0 -751
- capytaine/green_functions/LiangWuNoblesse/Makefile +0 -18
- capytaine/green_functions/LiangWuNoblesse/README.md +0 -2
- capytaine/green_functions/LiangWuNoblesse/test_program.f90 +0 -28
- capytaine/green_functions/libs/__init__.py +0 -0
- capytaine/io/mesh_loaders.py +0 -1086
- capytaine/io/mesh_writers.py +0 -692
- capytaine/io/meshio.py +0 -38
- capytaine/matrices/__init__.py +0 -16
- capytaine/matrices/block.py +0 -592
- capytaine/matrices/block_toeplitz.py +0 -325
- capytaine/matrices/builders.py +0 -89
- capytaine/matrices/linear_solvers.py +0 -232
- capytaine/matrices/low_rank.py +0 -395
- capytaine/meshes/clipper.py +0 -465
- capytaine/meshes/collections.py +0 -334
- capytaine/meshes/mesh_like_protocol.py +0 -37
- capytaine/meshes/properties.py +0 -276
- capytaine/meshes/quadratures.py +0 -80
- capytaine/meshes/symmetric.py +0 -392
- capytaine/tools/lru_cache.py +0 -49
- capytaine/ui/vtk/__init__.py +0 -3
- capytaine/ui/vtk/animation.py +0 -329
- capytaine/ui/vtk/body_viewer.py +0 -28
- capytaine/ui/vtk/helpers.py +0 -82
- capytaine/ui/vtk/mesh_viewer.py +0 -461
- capytaine-2.3.dist-info/RECORD +0 -92
- capytaine-2.3.dist-info/WHEEL +0 -4
- {capytaine-2.3.dist-info → capytaine-3.0.0a1.dist-info}/LICENSE +0 -0
- {capytaine-2.3.dist-info → capytaine-3.0.0a1.dist-info}/entry_points.txt +0 -0
capytaine/io/mesh_loaders.py
DELETED
|
@@ -1,1086 +0,0 @@
|
|
|
1
|
-
"""Functions to load meshes from different file formats.
|
|
2
|
-
Based on meshmagick <https://github.com/LHEEA/meshmagick> by François Rongère.
|
|
3
|
-
"""
|
|
4
|
-
# Copyright (C) 2017-2019 Matthieu Ancellin, based on the work of François Rongère
|
|
5
|
-
# See LICENSE file at <https://github.com/mancellin/capytaine>
|
|
6
|
-
|
|
7
|
-
import os
|
|
8
|
-
import logging
|
|
9
|
-
import numpy as np
|
|
10
|
-
|
|
11
|
-
from capytaine.meshes.meshes import Mesh
|
|
12
|
-
from capytaine.meshes.symmetric import ReflectionSymmetricMesh
|
|
13
|
-
from capytaine.meshes.geometry import xOz_Plane, yOz_Plane
|
|
14
|
-
from capytaine.tools.optional_imports import import_optional_dependency, silently_import_optional_dependency
|
|
15
|
-
|
|
16
|
-
LOG = logging.getLogger(__name__)
|
|
17
|
-
|
|
18
|
-
real_str = r'[+-]?(?:\d+\.\d*|\d*\.\d+)(?:[Ee][+-]?\d+)?' # Regex for floats
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
def _check_file(filename, name=None):
|
|
22
|
-
if not os.path.isfile(filename):
|
|
23
|
-
raise IOError("file %s not found" % filename)
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def load_mesh(mesh, file_format=None, name=None):
|
|
28
|
-
"""Driver function that loads every mesh file format known by meshmagick.
|
|
29
|
-
Dispatch to one of the other function depending on file_format.
|
|
30
|
-
|
|
31
|
-
Parameters
|
|
32
|
-
----------
|
|
33
|
-
mesh: str or meshio object
|
|
34
|
-
Either the path to the mesh on disk
|
|
35
|
-
or a meshio object to be loaded with the dedicated method
|
|
36
|
-
file_format: str, optional
|
|
37
|
-
format of the mesh defined in the extension_dict dictionary
|
|
38
|
-
name: str, optional
|
|
39
|
-
name for the created mesh object
|
|
40
|
-
|
|
41
|
-
Returns
|
|
42
|
-
-------
|
|
43
|
-
Mesh or SymmetricMesh
|
|
44
|
-
the loaded mesh
|
|
45
|
-
"""
|
|
46
|
-
meshio = silently_import_optional_dependency("meshio")
|
|
47
|
-
if meshio is not None and isinstance(mesh, meshio._mesh.Mesh):
|
|
48
|
-
from capytaine.io.meshio import load_from_meshio
|
|
49
|
-
return load_from_meshio(mesh, name=name)
|
|
50
|
-
|
|
51
|
-
filename = mesh
|
|
52
|
-
|
|
53
|
-
_check_file(filename)
|
|
54
|
-
|
|
55
|
-
if file_format is None:
|
|
56
|
-
_, file_format = os.path.splitext(filename)
|
|
57
|
-
file_format = file_format.strip('.').lower()
|
|
58
|
-
|
|
59
|
-
if file_format not in extension_dict:
|
|
60
|
-
raise IOError('Extension ".%s" is not known' % file_format)
|
|
61
|
-
|
|
62
|
-
loader = extension_dict[file_format]
|
|
63
|
-
|
|
64
|
-
if name is None:
|
|
65
|
-
name = filename
|
|
66
|
-
|
|
67
|
-
return loader(filename, name)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def load_RAD(filename, name=None):
|
|
71
|
-
"""Loads RADIOSS mesh files. This export file format may be chosen in ICEM meshing program.
|
|
72
|
-
|
|
73
|
-
Parameters
|
|
74
|
-
----------
|
|
75
|
-
filename: str
|
|
76
|
-
name of the mesh file on disk
|
|
77
|
-
|
|
78
|
-
Returns
|
|
79
|
-
-------
|
|
80
|
-
Mesh
|
|
81
|
-
the loaded mesh
|
|
82
|
-
|
|
83
|
-
Note
|
|
84
|
-
----
|
|
85
|
-
RAD files have a 1-indexing
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
import re
|
|
89
|
-
_check_file(filename)
|
|
90
|
-
ifile = open(filename, 'r')
|
|
91
|
-
data = ifile.read()
|
|
92
|
-
ifile.close()
|
|
93
|
-
|
|
94
|
-
# node_line = r'\s*\d+(?:\s*' + real_str + '){3}'
|
|
95
|
-
node_line = r'\s*\d+\s*(' + real_str + r')\s*(' + real_str + r')\s*(' + real_str + ')'
|
|
96
|
-
node_section = r'((?:' + node_line + ')+)'
|
|
97
|
-
|
|
98
|
-
elem_line = r'^\s*(?:\d+\s+){6}\d+\s*[\r\n]+'
|
|
99
|
-
elem_section = r'((?:' + elem_line + '){3,})'
|
|
100
|
-
|
|
101
|
-
pattern_node_line = re.compile(node_line, re.MULTILINE)
|
|
102
|
-
# pattern_node_line_group = re.compile(node_line, re.MULTILINE)
|
|
103
|
-
pattern_elem_line = re.compile(elem_line, re.MULTILINE)
|
|
104
|
-
pattern_node_section = re.compile(node_section, re.MULTILINE)
|
|
105
|
-
pattern_elem_section = re.compile(elem_section, re.MULTILINE)
|
|
106
|
-
|
|
107
|
-
vertices = []
|
|
108
|
-
node_section = pattern_node_section.search(data).group(1)
|
|
109
|
-
for node in pattern_node_line.finditer(node_section):
|
|
110
|
-
vertices.append(list(map(float, list(node.groups()))))
|
|
111
|
-
vertices = np.asarray(vertices, dtype=float)
|
|
112
|
-
|
|
113
|
-
faces = []
|
|
114
|
-
elem_section = pattern_elem_section.search(data).group(1)
|
|
115
|
-
for elem in pattern_elem_line.findall(elem_section):
|
|
116
|
-
faces.append(list(map(int, elem.strip().split()[3:])))
|
|
117
|
-
faces = np.asarray(faces, dtype=int) - 1
|
|
118
|
-
|
|
119
|
-
return Mesh(vertices, faces, name)
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
def load_HST(filename, name=None):
|
|
123
|
-
"""Loads HYDROSTAR (Bureau Veritas (c)) mesh files.
|
|
124
|
-
|
|
125
|
-
Parameters
|
|
126
|
-
----------
|
|
127
|
-
filename: str
|
|
128
|
-
name of the mesh file on disk
|
|
129
|
-
|
|
130
|
-
Returns
|
|
131
|
-
-------
|
|
132
|
-
Mesh
|
|
133
|
-
the loaded mesh
|
|
134
|
-
|
|
135
|
-
Note
|
|
136
|
-
----
|
|
137
|
-
HST files have a 1-indexing
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
_check_file(filename)
|
|
141
|
-
|
|
142
|
-
with open(filename, 'r') as f:
|
|
143
|
-
lines = f.readlines()
|
|
144
|
-
|
|
145
|
-
optional_keywords = ['PROJECT', 'SYMMETRY']
|
|
146
|
-
not_implemented_optional_keywords = ['USER', 'REFLENGTH', 'GRAVITY', 'RHO', 'NBBODY']
|
|
147
|
-
|
|
148
|
-
vertices = []
|
|
149
|
-
faces = []
|
|
150
|
-
optional_data = {kw: None for kw in optional_keywords}
|
|
151
|
-
current_context = None
|
|
152
|
-
ignored_lines = []
|
|
153
|
-
|
|
154
|
-
for i_line, line in enumerate(lines):
|
|
155
|
-
line = line.lstrip()
|
|
156
|
-
|
|
157
|
-
if line == '':
|
|
158
|
-
continue
|
|
159
|
-
|
|
160
|
-
elif line.startswith("COORDINATES"):
|
|
161
|
-
current_context = 'vertices'
|
|
162
|
-
|
|
163
|
-
elif current_context == 'vertices' and line.startswith("ENDCOORDINATES"):
|
|
164
|
-
current_context = None
|
|
165
|
-
|
|
166
|
-
elif line.startswith("PANEL"):
|
|
167
|
-
panels_type = int(line[10:])
|
|
168
|
-
current_context = ('panels', panels_type)
|
|
169
|
-
|
|
170
|
-
elif (current_context == ('panels', 0) or current_context == ('panels', 1)) and line.startswith("ENDPANEL"):
|
|
171
|
-
current_context = None
|
|
172
|
-
|
|
173
|
-
elif current_context == 'vertices': # parse vertex coordinates
|
|
174
|
-
numbers = line.split()
|
|
175
|
-
if len(numbers) == 4:
|
|
176
|
-
i_vertex, x, y, z = numbers
|
|
177
|
-
if int(i_vertex) != len(vertices) + 1:
|
|
178
|
-
raise ValueError(
|
|
179
|
-
f"HST mesh reader expected the next vertex to be indexed as {len(vertices)+1}, "
|
|
180
|
-
f"but it was actually indexed as {i_vertex} (line {i_line+1} of {filename}).")
|
|
181
|
-
elif len(numbers) == 3:
|
|
182
|
-
x, y, z = numbers
|
|
183
|
-
vertices.append([x, y, z])
|
|
184
|
-
|
|
185
|
-
elif current_context == ('panels', 0): # parse face definition (no index given)
|
|
186
|
-
numbers = line.split()
|
|
187
|
-
if len(numbers) == 3:
|
|
188
|
-
v1, v2, v3 = numbers
|
|
189
|
-
v4 = v3
|
|
190
|
-
elif len(numbers) == 4:
|
|
191
|
-
v1, v2, v3, v4 = numbers
|
|
192
|
-
faces.append([v1, v2, v3, v4])
|
|
193
|
-
|
|
194
|
-
elif current_context == ('panels', 1): # parse face definition
|
|
195
|
-
numbers = line.split()
|
|
196
|
-
if len(numbers) == 4:
|
|
197
|
-
i_face, v1, v2, v3 = numbers
|
|
198
|
-
v4 = v3
|
|
199
|
-
elif len(numbers) == 5:
|
|
200
|
-
i_face, v1, v2, v3, v4 = numbers
|
|
201
|
-
|
|
202
|
-
if int(i_face) != len(faces) + 1:
|
|
203
|
-
ii = len(faces) + 1
|
|
204
|
-
raise ValueError(f"HST mesh reader expected the next face to be indexed {ii},\n"
|
|
205
|
-
f"but it was actually indexed with {i_face} (line {i_line+1} of file {filename}).")
|
|
206
|
-
faces.append([v1, v2, v3, v4])
|
|
207
|
-
|
|
208
|
-
elif line.startswith("ENDFILE"):
|
|
209
|
-
break
|
|
210
|
-
|
|
211
|
-
else:
|
|
212
|
-
for keyword in optional_data:
|
|
213
|
-
if line.startswith(keyword):
|
|
214
|
-
optional_data[keyword] = line[len(keyword)+1:].lstrip(':').strip()
|
|
215
|
-
break
|
|
216
|
-
else:
|
|
217
|
-
ignored_lines.append((i_line+1, line))
|
|
218
|
-
|
|
219
|
-
if len(ignored_lines) > 0:
|
|
220
|
-
formatted_ignored_lines = ["{: 4} | {}".format(i, line.strip('\n')) for (i, line) in ignored_lines]
|
|
221
|
-
LOG.warning(f"HST mesh reader ignored the following lines from file {filename}:\n" + "\n".join(formatted_ignored_lines))
|
|
222
|
-
|
|
223
|
-
vertices = np.array(vertices, dtype=float)
|
|
224
|
-
faces = np.array(faces, dtype=int) - 1
|
|
225
|
-
|
|
226
|
-
if name is None: name = optional_data['PROJECT']
|
|
227
|
-
|
|
228
|
-
if optional_data['SYMMETRY'] == '1':
|
|
229
|
-
return ReflectionSymmetricMesh(Mesh(vertices, faces, f"half_of_{name}"), xOz_Plane, name)
|
|
230
|
-
elif optional_data['SYMMETRY'] == '2':
|
|
231
|
-
return ReflectionSymmetricMesh(ReflectionSymmetricMesh(Mesh(vertices, faces, f"quarter_of_{name}"), yOz_Plane, f"half_of_{name}"), xOz_Plane, name)
|
|
232
|
-
else:
|
|
233
|
-
return Mesh(vertices, faces, name)
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def load_DAT(filename, name=None):
|
|
237
|
-
"""Not implemented.
|
|
238
|
-
Intended to load .DAT files used in DIODORE (PRINCIPIA (c))
|
|
239
|
-
"""
|
|
240
|
-
_check_file(filename)
|
|
241
|
-
raise NotImplementedError
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def load_INP(filename, name=None):
|
|
245
|
-
"""Loads DIODORE (PRINCIPIA (c)) configuration file format.
|
|
246
|
-
|
|
247
|
-
It parses the .INP file and extracts meshes defined in subsequent .DAT files using the different information
|
|
248
|
-
contained in the .INP file.
|
|
249
|
-
|
|
250
|
-
Parameters
|
|
251
|
-
----------
|
|
252
|
-
filename: str
|
|
253
|
-
name of the mesh file on disk
|
|
254
|
-
|
|
255
|
-
Returns
|
|
256
|
-
-------
|
|
257
|
-
Mesh
|
|
258
|
-
the loaded mesh
|
|
259
|
-
|
|
260
|
-
Note
|
|
261
|
-
----
|
|
262
|
-
INP/DAT files use a 1-indexing
|
|
263
|
-
"""
|
|
264
|
-
_check_file(filename)
|
|
265
|
-
import re
|
|
266
|
-
|
|
267
|
-
with open(filename, 'r') as f:
|
|
268
|
-
text = f.read()
|
|
269
|
-
|
|
270
|
-
# Retrieving frames into a dictionary frames
|
|
271
|
-
pattern_frame_str = r'^\s*\*FRAME,NAME=(.+)[\r\n]+(.*)'
|
|
272
|
-
pattern_frame = re.compile(pattern_frame_str, re.MULTILINE)
|
|
273
|
-
|
|
274
|
-
frames = {}
|
|
275
|
-
for match in pattern_frame.finditer(text):
|
|
276
|
-
frame_name = match.group(1).strip()
|
|
277
|
-
frame_vector = re.split(r'[, ]', match.group(2).strip())
|
|
278
|
-
frames[frame_name] = np.asarray(list(map(float, frame_vector)))
|
|
279
|
-
|
|
280
|
-
# Storing the inp layout into a list of dictionary
|
|
281
|
-
pattern_node_elements = re.compile(r'^\s*\*(NODE|ELEMENT),(.*)', re.MULTILINE)
|
|
282
|
-
layout = []
|
|
283
|
-
mesh_files = {}
|
|
284
|
-
for match in pattern_node_elements.finditer(text):
|
|
285
|
-
field_dict = dict()
|
|
286
|
-
field_dict['type'] = match.group(1)
|
|
287
|
-
if field_dict['type'] == 'NODE':
|
|
288
|
-
field_dict['INCREMENT'] = 'NO'
|
|
289
|
-
opts = match.group(2).split(',')
|
|
290
|
-
for opt in opts:
|
|
291
|
-
key, pair = opt.split('=')
|
|
292
|
-
field_dict[key] = pair.strip()
|
|
293
|
-
|
|
294
|
-
# Retrieving information on mesh files and their usage
|
|
295
|
-
file = field_dict['INPUT']
|
|
296
|
-
if file in mesh_files:
|
|
297
|
-
mesh_files[file][field_dict['type'] + '_CALL_INP'] += 1
|
|
298
|
-
else:
|
|
299
|
-
mesh_files[file] = {}
|
|
300
|
-
mesh_files[file]['NODE_CALL_INP'] = 0
|
|
301
|
-
mesh_files[file]['ELEMENT_CALL_INP'] = 0
|
|
302
|
-
mesh_files[file][field_dict['type'] + '_CALL_INP'] += 1
|
|
303
|
-
|
|
304
|
-
layout.append(field_dict)
|
|
305
|
-
|
|
306
|
-
# RETRIEVING DATA SECTIONS FROM MESHFILES
|
|
307
|
-
# patterns for recognition of sections
|
|
308
|
-
node_line = r'\s*\d+(?:\s+' + real_str + '){3}'
|
|
309
|
-
node_section = r'((?:' + node_line + ')+)'
|
|
310
|
-
elem_line = r'^ +\d+(?: +\d+){3,4}[\r\n]+' # 3 -> triangle, 4 -> quadrangle
|
|
311
|
-
elem_section = r'((?:' + elem_line + ')+)'
|
|
312
|
-
pattern_node_line = re.compile(node_line, re.MULTILINE)
|
|
313
|
-
pattern_elem_line = re.compile(elem_line, re.MULTILINE)
|
|
314
|
-
pattern_node_section = re.compile(node_section, re.MULTILINE)
|
|
315
|
-
pattern_elem_section = re.compile(elem_section, re.MULTILINE)
|
|
316
|
-
|
|
317
|
-
for file in mesh_files:
|
|
318
|
-
try:
|
|
319
|
-
meshfile = open(os.path.join(os.path.dirname(filename), file + '.DAT'), 'r')
|
|
320
|
-
except:
|
|
321
|
-
raise IOError('File {0:s} not found'.format(file + '.DAT'))
|
|
322
|
-
data = meshfile.read()
|
|
323
|
-
meshfile.close()
|
|
324
|
-
|
|
325
|
-
node_section = pattern_node_section.findall(data)
|
|
326
|
-
if len(node_section) > 1:
|
|
327
|
-
raise IOError("""Several NODE sections into a .DAT file is not supported by meshmagick
|
|
328
|
-
as it is considered as bad practice""")
|
|
329
|
-
node_array = []
|
|
330
|
-
idx_array = []
|
|
331
|
-
for node in pattern_node_line.findall(node_section[0]):
|
|
332
|
-
node = node.split()
|
|
333
|
-
|
|
334
|
-
node[0] = int(node[0])
|
|
335
|
-
idx_array.append(node[0])
|
|
336
|
-
node[1:] = list(map(float, node[1:]))
|
|
337
|
-
node_array.append(node[1:])
|
|
338
|
-
|
|
339
|
-
mesh_files[file]['NODE_SECTION'] = node_array
|
|
340
|
-
|
|
341
|
-
# Detecting renumberings to do
|
|
342
|
-
real_idx = 0
|
|
343
|
-
# renumberings = []
|
|
344
|
-
id_new = - np.ones(max(idx_array) + 1, dtype=int)
|
|
345
|
-
# FIXME: cette partie est tres buggee !!!
|
|
346
|
-
for i, idx in enumerate(idx_array):
|
|
347
|
-
id_new[idx] = i+1
|
|
348
|
-
|
|
349
|
-
mesh_files[file]['ELEM_SECTIONS'] = []
|
|
350
|
-
for elem_section in pattern_elem_section.findall(data):
|
|
351
|
-
|
|
352
|
-
elem_array = []
|
|
353
|
-
for elem in pattern_elem_line.findall(elem_section):
|
|
354
|
-
elem = list(map(int, elem.split()))
|
|
355
|
-
# for node in elem[1:]:
|
|
356
|
-
elem = id_new[elem[1:]].tolist()
|
|
357
|
-
if len(elem) == 3: # Case of a triangle, we repeat the first node at the last position
|
|
358
|
-
elem.append(elem[0])
|
|
359
|
-
|
|
360
|
-
elem_array.append(list(map(int, elem)))
|
|
361
|
-
mesh_files[file]['ELEM_SECTIONS'].append(elem_array)
|
|
362
|
-
mesh_files[file]['nb_elem_sections'] = len(mesh_files[file]['ELEM_SECTIONS'])
|
|
363
|
-
|
|
364
|
-
mesh_files[file]['nb_elem_sections_used'] = 0
|
|
365
|
-
|
|
366
|
-
nb_nodes = 0
|
|
367
|
-
nb_elems = 0
|
|
368
|
-
for field in layout:
|
|
369
|
-
file = field['INPUT']
|
|
370
|
-
if field['type'] == 'NODE':
|
|
371
|
-
nodes = np.asarray(mesh_files[file]['NODE_SECTION'], dtype=float)
|
|
372
|
-
# Translation of nodes according to frame option id any
|
|
373
|
-
nodes += frames[field['FRAME']] # TODO: s'assurer que frame est une options obligatoire...
|
|
374
|
-
|
|
375
|
-
if nb_nodes == 0:
|
|
376
|
-
vertices = nodes.copy()
|
|
377
|
-
nb_nodes = vertices.shape[0]
|
|
378
|
-
increment = False
|
|
379
|
-
continue
|
|
380
|
-
|
|
381
|
-
if field['INCREMENT'] == 'NO':
|
|
382
|
-
vertices[idx, :] = nodes.copy()
|
|
383
|
-
increment = False
|
|
384
|
-
else:
|
|
385
|
-
vertices = np.concatenate((vertices, nodes))
|
|
386
|
-
nb_nodes = vertices.shape[0]
|
|
387
|
-
increment = True
|
|
388
|
-
else: # this is an ELEMENT section
|
|
389
|
-
elem_section = np.asarray(mesh_files[file]['ELEM_SECTIONS'][mesh_files[file]['nb_elem_sections_used']],
|
|
390
|
-
dtype=int)
|
|
391
|
-
|
|
392
|
-
mesh_files[file]['nb_elem_sections_used'] += 1
|
|
393
|
-
if mesh_files[file]['nb_elem_sections_used'] == mesh_files[file]['nb_elem_sections']:
|
|
394
|
-
mesh_files[file]['nb_elem_sections_used'] = 0
|
|
395
|
-
|
|
396
|
-
# Updating to new id of nodes
|
|
397
|
-
elems = elem_section
|
|
398
|
-
if increment:
|
|
399
|
-
elems += nb_nodes
|
|
400
|
-
|
|
401
|
-
if nb_elems == 0:
|
|
402
|
-
faces = elems.copy()
|
|
403
|
-
nb_elems = faces.shape[0]
|
|
404
|
-
continue
|
|
405
|
-
else:
|
|
406
|
-
faces = np.concatenate((faces, elems))
|
|
407
|
-
nb_elems = faces.shape[0]
|
|
408
|
-
|
|
409
|
-
return Mesh(vertices, faces-1, name)
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
def load_TEC(filename, name=None):
|
|
413
|
-
"""Loads TECPLOT (Tecplot (c)) mesh files.
|
|
414
|
-
|
|
415
|
-
It relies on the tecplot file reader from the VTK library.
|
|
416
|
-
|
|
417
|
-
Parameters
|
|
418
|
-
----------
|
|
419
|
-
filename: str
|
|
420
|
-
name of the mesh file on disk
|
|
421
|
-
|
|
422
|
-
Returns
|
|
423
|
-
-------
|
|
424
|
-
Mesh
|
|
425
|
-
the loaded mesh
|
|
426
|
-
|
|
427
|
-
Note
|
|
428
|
-
----
|
|
429
|
-
TEC files have a 1-indexing
|
|
430
|
-
"""
|
|
431
|
-
|
|
432
|
-
import re
|
|
433
|
-
|
|
434
|
-
_check_file(filename)
|
|
435
|
-
|
|
436
|
-
data_pattern = re.compile(
|
|
437
|
-
r'ZONE.*\s*N\s*=\s*(\d+)\s*,\s*E=\s*(\d+)\s*,\s*F\s*=\s*FEPOINT\s*,\s*ET\s*=\s*QUADRILATERAL\s+'
|
|
438
|
-
+ r'(^(?:\s*' + real_str + r'){3,})\s+'
|
|
439
|
-
+ r'(^(?:\s*\d+)*)', re.MULTILINE)
|
|
440
|
-
|
|
441
|
-
with open(filename, 'r') as f:
|
|
442
|
-
data = f.read()
|
|
443
|
-
|
|
444
|
-
nv, nf, vertices, faces = data_pattern.search(data).groups()
|
|
445
|
-
nv = int(nv)
|
|
446
|
-
nf = int(nf)
|
|
447
|
-
|
|
448
|
-
vertices = np.asarray(list(map(float, vertices.split())), dtype=float).reshape((nv, -1))[:, :3]
|
|
449
|
-
faces = np.asarray(list(map(int, faces.split())), dtype=int).reshape((nf, 4))-1
|
|
450
|
-
|
|
451
|
-
return Mesh(vertices, faces, name)
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
def load_VTU(filename, name=None):
|
|
455
|
-
"""Loads VTK file format in the new XML format (vtu file extension for unstructured meshes).
|
|
456
|
-
|
|
457
|
-
It relies on the reader from the VTK library.
|
|
458
|
-
|
|
459
|
-
Parameters
|
|
460
|
-
----------
|
|
461
|
-
filename: str
|
|
462
|
-
name of the mesh file on disk
|
|
463
|
-
|
|
464
|
-
Returns
|
|
465
|
-
-------
|
|
466
|
-
Mesh
|
|
467
|
-
the loaded mesh
|
|
468
|
-
|
|
469
|
-
Note
|
|
470
|
-
----
|
|
471
|
-
VTU files have a 0-indexing
|
|
472
|
-
"""
|
|
473
|
-
|
|
474
|
-
_check_file(filename)
|
|
475
|
-
|
|
476
|
-
vtk = import_optional_dependency("vtk")
|
|
477
|
-
|
|
478
|
-
reader = vtk.vtkXMLUnstructuredGridReader()
|
|
479
|
-
reader.SetFileName(str(filename))
|
|
480
|
-
reader.Update()
|
|
481
|
-
vtk_mesh = reader.GetOutput()
|
|
482
|
-
|
|
483
|
-
vertices, faces = _dump_vtk(vtk_mesh)
|
|
484
|
-
return Mesh(vertices, faces, name)
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
def load_VTP(filename, name=None):
|
|
488
|
-
"""Loads VTK file format in the new XML format (vtp file extension for polydata meshes).
|
|
489
|
-
|
|
490
|
-
It relies on the reader from the VTK library.
|
|
491
|
-
|
|
492
|
-
Parameters
|
|
493
|
-
----------
|
|
494
|
-
filename: str
|
|
495
|
-
name of the mesh file on disk
|
|
496
|
-
|
|
497
|
-
Returns
|
|
498
|
-
-------
|
|
499
|
-
Mesh
|
|
500
|
-
the loaded mesh
|
|
501
|
-
|
|
502
|
-
Note
|
|
503
|
-
----
|
|
504
|
-
VTP files have a 0-indexing
|
|
505
|
-
"""
|
|
506
|
-
_check_file(filename)
|
|
507
|
-
|
|
508
|
-
vtk = import_optional_dependency("vtk")
|
|
509
|
-
|
|
510
|
-
reader = vtk.vtkXMLPolyDataReader()
|
|
511
|
-
reader.SetFileName(str(filename))
|
|
512
|
-
reader.Update()
|
|
513
|
-
vtk_mesh = reader.GetOutput()
|
|
514
|
-
|
|
515
|
-
vertices, faces = _dump_vtk(vtk_mesh)
|
|
516
|
-
return Mesh(vertices, faces, name)
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
def load_VTK(filename, name=None):
|
|
520
|
-
"""Loads VTK file format in the legacy format (vtk file extension).
|
|
521
|
-
|
|
522
|
-
It relies on the reader from the VTK library.
|
|
523
|
-
|
|
524
|
-
Parameters
|
|
525
|
-
----------
|
|
526
|
-
filename: str
|
|
527
|
-
name of the mesh file on disk
|
|
528
|
-
|
|
529
|
-
Returns
|
|
530
|
-
-------
|
|
531
|
-
Mesh
|
|
532
|
-
the loaded mesh
|
|
533
|
-
|
|
534
|
-
Note
|
|
535
|
-
----
|
|
536
|
-
VTU files have a 0-indexing
|
|
537
|
-
"""
|
|
538
|
-
_check_file(filename)
|
|
539
|
-
|
|
540
|
-
vtk = import_optional_dependency("vtk")
|
|
541
|
-
|
|
542
|
-
reader = vtk.vtkPolyDataReader()
|
|
543
|
-
reader.SetFileName(str(filename))
|
|
544
|
-
reader.Update()
|
|
545
|
-
vtk_mesh = reader.GetOutput()
|
|
546
|
-
|
|
547
|
-
vertices, faces = _dump_vtk(vtk_mesh)
|
|
548
|
-
return Mesh(vertices, faces, name)
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
def _dump_vtk(vtk_mesh):
|
|
552
|
-
"""Internal driver function that uses the VTK library to read VTK polydata or vtk unstructured grid data structures
|
|
553
|
-
|
|
554
|
-
Returns
|
|
555
|
-
-------
|
|
556
|
-
vertices: ndarray
|
|
557
|
-
numpy array of the coordinates of the mesh's nodes
|
|
558
|
-
faces: ndarray
|
|
559
|
-
numpy array of the faces' nodes connectivities
|
|
560
|
-
"""
|
|
561
|
-
|
|
562
|
-
nv = vtk_mesh.GetNumberOfPoints()
|
|
563
|
-
vertices = np.zeros((nv, 3), dtype=float)
|
|
564
|
-
for k in range(nv):
|
|
565
|
-
vertices[k] = np.array(vtk_mesh.GetPoint(k))
|
|
566
|
-
|
|
567
|
-
nf = vtk_mesh.GetNumberOfCells()
|
|
568
|
-
faces = np.zeros((nf, 4), dtype=int)
|
|
569
|
-
for k in range(nf):
|
|
570
|
-
cell = vtk_mesh.GetCell(k)
|
|
571
|
-
nv_facet = cell.GetNumberOfPoints()
|
|
572
|
-
for l in range(nv_facet):
|
|
573
|
-
faces[k][l] = cell.GetPointId(l)
|
|
574
|
-
if nv_facet == 3:
|
|
575
|
-
faces[k][3] = faces[k][0]
|
|
576
|
-
|
|
577
|
-
return vertices, faces
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
def load_STL(filename, name=None):
|
|
581
|
-
"""Loads STL file format.
|
|
582
|
-
|
|
583
|
-
It relies on the reader from the VTK library. As STL file format maintains a redundant set of vertices for each
|
|
584
|
-
faces of the mesh, it returns a merged list of nodes and connectivity array by using the merge_duplicates function.
|
|
585
|
-
|
|
586
|
-
Parameters
|
|
587
|
-
----------
|
|
588
|
-
filename: str
|
|
589
|
-
name of the mesh file on disk
|
|
590
|
-
|
|
591
|
-
Returns
|
|
592
|
-
-------
|
|
593
|
-
Mesh
|
|
594
|
-
the loaded mesh
|
|
595
|
-
|
|
596
|
-
Note
|
|
597
|
-
----
|
|
598
|
-
STL files have a 0-indexing
|
|
599
|
-
"""
|
|
600
|
-
vtk = import_optional_dependency("vtk")
|
|
601
|
-
|
|
602
|
-
from capytaine.meshes.quality import merge_duplicate_rows
|
|
603
|
-
|
|
604
|
-
_check_file(filename)
|
|
605
|
-
|
|
606
|
-
reader = vtk.vtkSTLReader()
|
|
607
|
-
reader.SetFileName(str(filename))
|
|
608
|
-
reader.Update()
|
|
609
|
-
|
|
610
|
-
data = reader.GetOutputDataObject(0)
|
|
611
|
-
|
|
612
|
-
nv = data.GetNumberOfPoints()
|
|
613
|
-
vertices = np.zeros((nv, 3), dtype=float)
|
|
614
|
-
for k in range(nv):
|
|
615
|
-
vertices[k] = np.array(data.GetPoint(k))
|
|
616
|
-
nf = data.GetNumberOfCells()
|
|
617
|
-
faces = np.zeros((nf, 4), dtype=int)
|
|
618
|
-
for k in range(nf):
|
|
619
|
-
cell = data.GetCell(k)
|
|
620
|
-
if cell is not None:
|
|
621
|
-
for l in range(3):
|
|
622
|
-
faces[k][l] = cell.GetPointId(l)
|
|
623
|
-
faces[k][3] = faces[k][0] # always repeating the first node as stl is triangle only
|
|
624
|
-
|
|
625
|
-
# Merging duplicates nodes
|
|
626
|
-
vertices, new_id = merge_duplicate_rows(vertices)
|
|
627
|
-
faces = new_id[faces]
|
|
628
|
-
|
|
629
|
-
return Mesh(vertices, faces, name)
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
def load_NAT(filename, name=None):
|
|
633
|
-
"""This function loads natural file format for meshes.
|
|
634
|
-
|
|
635
|
-
Parameters
|
|
636
|
-
----------
|
|
637
|
-
filename: str
|
|
638
|
-
name of the mesh file on disk
|
|
639
|
-
|
|
640
|
-
Returns
|
|
641
|
-
-------
|
|
642
|
-
Mesh
|
|
643
|
-
the loaded mesh
|
|
644
|
-
|
|
645
|
-
Notes
|
|
646
|
-
-----
|
|
647
|
-
The file format is as follow::
|
|
648
|
-
|
|
649
|
-
xsym ysym
|
|
650
|
-
n m
|
|
651
|
-
x1 y1 z1
|
|
652
|
-
.
|
|
653
|
-
.
|
|
654
|
-
.
|
|
655
|
-
xn yn zn
|
|
656
|
-
i1 j1 k1 l1
|
|
657
|
-
.
|
|
658
|
-
.
|
|
659
|
-
.
|
|
660
|
-
im jm km lm
|
|
661
|
-
|
|
662
|
-
where :
|
|
663
|
-
n : number of nodes
|
|
664
|
-
m : number of cells
|
|
665
|
-
x1 y1 z1 : cartesian coordinates of node 1
|
|
666
|
-
i1 j1 k1 l1 : counterclock wise Ids of nodes for cell 1
|
|
667
|
-
if cell 1 is a triangle, i1==l1
|
|
668
|
-
|
|
669
|
-
Note
|
|
670
|
-
----
|
|
671
|
-
NAT files have a 1-indexing
|
|
672
|
-
"""
|
|
673
|
-
|
|
674
|
-
_check_file(filename)
|
|
675
|
-
|
|
676
|
-
ifile = open(filename, 'r')
|
|
677
|
-
ifile.readline()
|
|
678
|
-
nv, nf = list(map(int, ifile.readline().split()))
|
|
679
|
-
|
|
680
|
-
vertices = []
|
|
681
|
-
for i in range(nv):
|
|
682
|
-
vertices.append(list(map(float, ifile.readline().split())))
|
|
683
|
-
vertices = np.array(vertices, dtype=float)
|
|
684
|
-
|
|
685
|
-
faces = []
|
|
686
|
-
for i in range(nf):
|
|
687
|
-
faces.append(list(map(int, ifile.readline().split())))
|
|
688
|
-
faces = np.array(faces, dtype=int)
|
|
689
|
-
|
|
690
|
-
ifile.close()
|
|
691
|
-
return Mesh(vertices, faces-1, name)
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
def load_GDF(filename, name=None):
|
|
695
|
-
"""Loads WAMIT (Wamit INC. (c)) GDF mesh files.
|
|
696
|
-
|
|
697
|
-
As GDF file format maintains a redundant set of vertices for each faces of the mesh, it returns a merged list of
|
|
698
|
-
nodes and connectivity array by using the merge_duplicates function.
|
|
699
|
-
|
|
700
|
-
Parameters
|
|
701
|
-
----------
|
|
702
|
-
filename: str
|
|
703
|
-
name of the mesh file on disk
|
|
704
|
-
|
|
705
|
-
Returns
|
|
706
|
-
-------
|
|
707
|
-
Mesh or ReflectionSymmetricMesh
|
|
708
|
-
the loaded mesh
|
|
709
|
-
|
|
710
|
-
Note
|
|
711
|
-
----
|
|
712
|
-
GDF files have a 1-indexing
|
|
713
|
-
"""
|
|
714
|
-
|
|
715
|
-
_check_file(filename)
|
|
716
|
-
|
|
717
|
-
with open(str(filename)) as gdf_file:
|
|
718
|
-
title = gdf_file.readline()
|
|
719
|
-
ulen, grav = map(float, gdf_file.readline().split()[:2])
|
|
720
|
-
isx, isy = map(int, gdf_file.readline().split()[:2])
|
|
721
|
-
npan = int(gdf_file.readline().split()[0])
|
|
722
|
-
faces_vertices = np.genfromtxt(gdf_file)
|
|
723
|
-
|
|
724
|
-
faces_vertices = faces_vertices.reshape(-1, 3)
|
|
725
|
-
vertices, indices = np.unique(faces_vertices, axis=0, return_inverse=True)
|
|
726
|
-
faces = indices.reshape(-1, 4)
|
|
727
|
-
|
|
728
|
-
if faces.shape[0] != npan:
|
|
729
|
-
raise ValueError(
|
|
730
|
-
f"In {filename} npan value: {npan} is not equal to face count: \
|
|
731
|
-
{faces.shape[0]}."
|
|
732
|
-
)
|
|
733
|
-
|
|
734
|
-
if isx == 1 and isy == 1:
|
|
735
|
-
return ReflectionSymmetricMesh(ReflectionSymmetricMesh(Mesh(vertices, faces, f"quarter_of_{name}"), yOz_Plane, f"half_of_{name}"), xOz_Plane, name)
|
|
736
|
-
elif isx == 1:
|
|
737
|
-
return ReflectionSymmetricMesh(Mesh(vertices, faces, f"half_of_{name}"), yOz_Plane, name)
|
|
738
|
-
elif isy == 1:
|
|
739
|
-
return ReflectionSymmetricMesh(Mesh(vertices, faces, f"half_of_{name}"), xOz_Plane, name)
|
|
740
|
-
else:
|
|
741
|
-
return Mesh(vertices, faces, name)
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
def load_MAR(filename, name=None):
|
|
745
|
-
"""Loads Nemoh (Ecole Centrale de Nantes) mesh files.
|
|
746
|
-
|
|
747
|
-
Parameters
|
|
748
|
-
----------
|
|
749
|
-
filename: str
|
|
750
|
-
name of the mesh file on disk
|
|
751
|
-
|
|
752
|
-
Returns
|
|
753
|
-
-------
|
|
754
|
-
Mesh or ReflectionSymmetry
|
|
755
|
-
the loaded mesh
|
|
756
|
-
|
|
757
|
-
Note
|
|
758
|
-
----
|
|
759
|
-
MAR files have a 1-indexing
|
|
760
|
-
"""
|
|
761
|
-
|
|
762
|
-
_check_file(filename)
|
|
763
|
-
|
|
764
|
-
ifile = open(filename, 'r')
|
|
765
|
-
|
|
766
|
-
header = ifile.readline()
|
|
767
|
-
_, symmetric_mesh = header.split()
|
|
768
|
-
|
|
769
|
-
vertices = []
|
|
770
|
-
while 1:
|
|
771
|
-
line = ifile.readline()
|
|
772
|
-
line = line.split()
|
|
773
|
-
if line[0] == '0':
|
|
774
|
-
break
|
|
775
|
-
vertices.append(list(map(float, line[1:])))
|
|
776
|
-
|
|
777
|
-
vertices = np.array(vertices, dtype=float)
|
|
778
|
-
faces = []
|
|
779
|
-
while 1:
|
|
780
|
-
line = ifile.readline()
|
|
781
|
-
line = line.split()
|
|
782
|
-
if line[0] == '0':
|
|
783
|
-
break
|
|
784
|
-
faces.append(list(map(int, line)))
|
|
785
|
-
|
|
786
|
-
faces = np.array(faces, dtype=int)
|
|
787
|
-
|
|
788
|
-
ifile.close()
|
|
789
|
-
|
|
790
|
-
if int(symmetric_mesh) == 1:
|
|
791
|
-
if name is None:
|
|
792
|
-
half_mesh = Mesh(vertices, faces-1)
|
|
793
|
-
return ReflectionSymmetricMesh(half_mesh, plane=xOz_Plane)
|
|
794
|
-
else:
|
|
795
|
-
half_mesh = Mesh(vertices, faces-1, name=f"half_of_{name}")
|
|
796
|
-
return ReflectionSymmetricMesh(half_mesh, plane=xOz_Plane, name=name)
|
|
797
|
-
else:
|
|
798
|
-
return Mesh(vertices, faces-1, name)
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
def load_MSH(filename, name=None):
|
|
802
|
-
"""Loads .MSH mesh files generated by GMSH by C. Geuzaine and J.F. Remacle.
|
|
803
|
-
|
|
804
|
-
Parameters
|
|
805
|
-
----------
|
|
806
|
-
filename: str
|
|
807
|
-
name of the mesh file on disk
|
|
808
|
-
|
|
809
|
-
Returns
|
|
810
|
-
-------
|
|
811
|
-
Mesh
|
|
812
|
-
the loaded mesh
|
|
813
|
-
|
|
814
|
-
Note
|
|
815
|
-
----
|
|
816
|
-
MSH files have a 1-indexing
|
|
817
|
-
"""
|
|
818
|
-
|
|
819
|
-
import re
|
|
820
|
-
|
|
821
|
-
_check_file(filename)
|
|
822
|
-
|
|
823
|
-
try:
|
|
824
|
-
meshio = import_optional_dependency("meshio")
|
|
825
|
-
except:
|
|
826
|
-
with open(filename, 'r') as file:
|
|
827
|
-
data = file.read()
|
|
828
|
-
version = float(re.search(r'\$MeshFormat\n(\d.\d).*\n\$EndMeshFormat', data, re.DOTALL).groups()[0])
|
|
829
|
-
|
|
830
|
-
if 4 <= version < 5:
|
|
831
|
-
message = (
|
|
832
|
-
f"Meshio is required to read MSH file format version 4. "
|
|
833
|
-
f"Use pip or conda to install Meshio."
|
|
834
|
-
)
|
|
835
|
-
raise ImportError(message) from None
|
|
836
|
-
else:
|
|
837
|
-
nb_nodes, nodes_data = re.search(r'\$Nodes\n(\d+)\n(.+)\$EndNodes', data, re.DOTALL).groups()
|
|
838
|
-
nb_elts, elts_data = re.search(r'\$Elements\n(\d+)\n(.+)\$EndElements', data, re.DOTALL).groups()
|
|
839
|
-
|
|
840
|
-
vertices = np.asarray(list(map(float, nodes_data.split())), dtype=float).reshape((-1, 4))[:, 1:]
|
|
841
|
-
vertices = np.ascontiguousarray(vertices)
|
|
842
|
-
faces = []
|
|
843
|
-
|
|
844
|
-
# Triangles
|
|
845
|
-
for tri_elt in re.findall(r'(^\d+\s2(?:\s\d+)+?$)', elts_data, re.MULTILINE):
|
|
846
|
-
tri_elt = list(map(int, tri_elt.split()))
|
|
847
|
-
triangle = tri_elt[-3:]
|
|
848
|
-
triangle.append(triangle[0])
|
|
849
|
-
faces.append(triangle)
|
|
850
|
-
|
|
851
|
-
for quad_elt in re.findall(r'(^\d+\s3(?:\s\d+)+?$)', elts_data, re.MULTILINE):
|
|
852
|
-
quad_elt = list(map(int, quad_elt.split()))
|
|
853
|
-
quadrangle = quad_elt[-4:]
|
|
854
|
-
faces.append(quadrangle)
|
|
855
|
-
|
|
856
|
-
faces = np.asarray(faces, dtype=int) - 1
|
|
857
|
-
|
|
858
|
-
return Mesh(vertices, faces, name)
|
|
859
|
-
|
|
860
|
-
msh_mesh = meshio.read(filename)
|
|
861
|
-
from capytaine.io.meshio import load_from_meshio
|
|
862
|
-
return load_from_meshio(msh_mesh, name)
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
def load_MED(filename, name=None):
|
|
866
|
-
"""Loads MED mesh files generated by SALOME MECA.
|
|
867
|
-
|
|
868
|
-
Parameters
|
|
869
|
-
----------
|
|
870
|
-
filename: str
|
|
871
|
-
name of the mesh file on disk
|
|
872
|
-
|
|
873
|
-
Returns
|
|
874
|
-
-------
|
|
875
|
-
Mesh
|
|
876
|
-
the loaded mesh
|
|
877
|
-
|
|
878
|
-
Note
|
|
879
|
-
----
|
|
880
|
-
MED files have a 1-indexing
|
|
881
|
-
"""
|
|
882
|
-
|
|
883
|
-
try:
|
|
884
|
-
import h5py
|
|
885
|
-
except ImportError:
|
|
886
|
-
raise ImportError('MED file format reader needs h5py module to be installed')
|
|
887
|
-
|
|
888
|
-
_check_file(filename)
|
|
889
|
-
|
|
890
|
-
file = h5py.File(filename)
|
|
891
|
-
|
|
892
|
-
list_of_names = []
|
|
893
|
-
file.visit(list_of_names.append)
|
|
894
|
-
|
|
895
|
-
nb_quadrangles = nb_triangles = 0
|
|
896
|
-
|
|
897
|
-
for item in list_of_names:
|
|
898
|
-
if '/NOE/COO' in item:
|
|
899
|
-
vertices = file[item][:].reshape((3, -1)).T
|
|
900
|
-
nv = vertices.shape[0]
|
|
901
|
-
if '/MAI/TR3/NOD' in item:
|
|
902
|
-
triangles = file[item][:].reshape((3, -1)).T - 1
|
|
903
|
-
nb_triangles = triangles.shape[0]
|
|
904
|
-
if '/MAI/QU4/NOD' in item:
|
|
905
|
-
quadrangles = file[item][:].reshape((4, -1)).T - 1
|
|
906
|
-
nb_quadrangles = quadrangles.shape[0]
|
|
907
|
-
|
|
908
|
-
file.close()
|
|
909
|
-
|
|
910
|
-
if nb_triangles == 0:
|
|
911
|
-
triangles = np.zeros((0, 4), dtype=int)
|
|
912
|
-
else:
|
|
913
|
-
triangles = np.column_stack((triangles, triangles[:, 0]))
|
|
914
|
-
if nb_quadrangles == 0:
|
|
915
|
-
quadrangles = np.zeros((0, 4), dtype=int)
|
|
916
|
-
|
|
917
|
-
faces = np.vstack([triangles, quadrangles])
|
|
918
|
-
|
|
919
|
-
return Mesh(vertices, faces, name=name)
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
def load_WRL(filename, name=None):
|
|
923
|
-
"""Loads VRML 2.0 mesh files.
|
|
924
|
-
|
|
925
|
-
Parameters
|
|
926
|
-
----------
|
|
927
|
-
filename: str
|
|
928
|
-
name of the mesh file on disk
|
|
929
|
-
|
|
930
|
-
Returns
|
|
931
|
-
-------
|
|
932
|
-
Mesh
|
|
933
|
-
the loaded mesh
|
|
934
|
-
"""
|
|
935
|
-
import re
|
|
936
|
-
|
|
937
|
-
vtk = import_optional_dependency("vtk")
|
|
938
|
-
|
|
939
|
-
_check_file(filename)
|
|
940
|
-
|
|
941
|
-
# Checking version
|
|
942
|
-
with open(filename, 'r') as f:
|
|
943
|
-
line = f.readline()
|
|
944
|
-
ver = re.search(r'#VRML\s+V(\d.\d)', line).group(1)
|
|
945
|
-
if not ver == '2.0':
|
|
946
|
-
raise NotImplementedError('VRML loader only supports VRML 2.0 format (version %s given)' % ver)
|
|
947
|
-
|
|
948
|
-
importer = vtk.vtkVRMLImporter()
|
|
949
|
-
importer.SetFileName(str(filename))
|
|
950
|
-
importer.Update()
|
|
951
|
-
|
|
952
|
-
actors = importer.GetRenderer().GetActors()
|
|
953
|
-
actors.InitTraversal()
|
|
954
|
-
dataset = actors.GetNextActor().GetMapper().GetInput()
|
|
955
|
-
|
|
956
|
-
return _dump_vtk(dataset)
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
def load_NEM(filename, name=None):
|
|
960
|
-
"""Loads mesh files that are used by the ``Mesh`` tool included in Nemoh.
|
|
961
|
-
|
|
962
|
-
Parameters
|
|
963
|
-
----------
|
|
964
|
-
filename: str
|
|
965
|
-
name of the mesh file on disk
|
|
966
|
-
|
|
967
|
-
Returns
|
|
968
|
-
-------
|
|
969
|
-
Mesh
|
|
970
|
-
the loaded mesh
|
|
971
|
-
|
|
972
|
-
Note
|
|
973
|
-
----
|
|
974
|
-
This format is different from that is used directly by Nemoh software. It is only dedicated to the Mesh tool.
|
|
975
|
-
"""
|
|
976
|
-
|
|
977
|
-
_check_file(filename)
|
|
978
|
-
|
|
979
|
-
ifile = open(filename, 'r')
|
|
980
|
-
|
|
981
|
-
nv = int(ifile.readline())
|
|
982
|
-
nf = int(ifile.readline())
|
|
983
|
-
|
|
984
|
-
vertices = []
|
|
985
|
-
for ivertex in range(nv):
|
|
986
|
-
vertices.append(list(map(float, ifile.readline().split())))
|
|
987
|
-
vertices = np.asarray(vertices, dtype=float)
|
|
988
|
-
|
|
989
|
-
faces = []
|
|
990
|
-
for iface in range(nf):
|
|
991
|
-
faces.append(list(map(int, ifile.readline().split())))
|
|
992
|
-
faces = np.asarray(faces, dtype=int)
|
|
993
|
-
faces -= 1
|
|
994
|
-
|
|
995
|
-
return Mesh(vertices, faces, name)
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
def load_PNL(filename, name=None):
|
|
999
|
-
"""Load mesh using HAMS file format.
|
|
1000
|
-
|
|
1001
|
-
Parameters
|
|
1002
|
-
----------
|
|
1003
|
-
filename: str
|
|
1004
|
-
name of the mesh file on disk
|
|
1005
|
-
|
|
1006
|
-
Returns
|
|
1007
|
-
-------
|
|
1008
|
-
Mesh or ReflectionSymmetricMesh
|
|
1009
|
-
the loaded mesh
|
|
1010
|
-
"""
|
|
1011
|
-
|
|
1012
|
-
with open(filename, 'r') as f:
|
|
1013
|
-
# Skip 3 title lines
|
|
1014
|
-
f.readline()
|
|
1015
|
-
f.readline()
|
|
1016
|
-
f.readline()
|
|
1017
|
-
# Read header data
|
|
1018
|
-
nb_faces, nb_vertices, x_sym, y_sym = map(int, f.readline().split())
|
|
1019
|
-
# Skip 2 more lines
|
|
1020
|
-
f.readline()
|
|
1021
|
-
f.readline()
|
|
1022
|
-
vertices = np.genfromtxt((f.readline() for _ in range(nb_vertices)), usecols=(1, 2, 3))
|
|
1023
|
-
# Skip 3 more lines
|
|
1024
|
-
f.readline()
|
|
1025
|
-
f.readline()
|
|
1026
|
-
f.readline()
|
|
1027
|
-
faces = np.zeros((nb_faces, 4), dtype=int)
|
|
1028
|
-
for i in range(nb_faces):
|
|
1029
|
-
index, nb_corners, *data = map(int, f.readline().split())
|
|
1030
|
-
assert i+1 == index
|
|
1031
|
-
if nb_corners == 3: # Triangle
|
|
1032
|
-
assert len(data) == 3
|
|
1033
|
-
faces[i, 0:3] = data
|
|
1034
|
-
faces[i, 3] = faces[i, 2] # Convention for triangles in Capytaine: repeat last vertex
|
|
1035
|
-
elif int(nb_corners) == 4: # Quadrangle
|
|
1036
|
-
assert len(data) == 4
|
|
1037
|
-
faces[i, :] = data
|
|
1038
|
-
faces = faces - 1 # Going from Fortran 1-based indices to Numpy 0-based indices
|
|
1039
|
-
|
|
1040
|
-
if x_sym == 1 and y_sym == 0:
|
|
1041
|
-
half_mesh = Mesh(vertices, faces, name=(f"half_of_{name}" if name is not None else None))
|
|
1042
|
-
return ReflectionSymmetricMesh(half_mesh, plane=yOz_Plane, name=name)
|
|
1043
|
-
elif x_sym == 0 and y_sym == 1:
|
|
1044
|
-
half_mesh = Mesh(vertices, faces, name=(f"half_of_{name}" if name is not None else None))
|
|
1045
|
-
return ReflectionSymmetricMesh(half_mesh, plane=xOz_Plane, name=name)
|
|
1046
|
-
elif x_sym == 1 and y_sym == 1:
|
|
1047
|
-
quarter_mesh = Mesh(vertices, faces, name=(f"quarter_of_{name}" if name is not None else None))
|
|
1048
|
-
half_mesh = ReflectionSymmetricMesh(quarter_mesh, plane=xOz_Plane, name=(f"half_of_{name}" if name is not None else None))
|
|
1049
|
-
return ReflectionSymmetricMesh(half_mesh, plane=yOz_Plane, name=name)
|
|
1050
|
-
else:
|
|
1051
|
-
return Mesh(vertices, faces, name)
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
extension_dict = { # keyword, reader
|
|
1055
|
-
'dat': load_MAR,
|
|
1056
|
-
'mar': load_MAR,
|
|
1057
|
-
'nemoh': load_MAR,
|
|
1058
|
-
'wamit': load_GDF,
|
|
1059
|
-
'gdf': load_GDF,
|
|
1060
|
-
'diodore-inp': load_INP,
|
|
1061
|
-
'inp': load_INP,
|
|
1062
|
-
'diodore-dat': load_DAT,
|
|
1063
|
-
'hydrostar': load_HST,
|
|
1064
|
-
'hst': load_HST,
|
|
1065
|
-
'natural': load_NAT,
|
|
1066
|
-
'nat': load_NAT,
|
|
1067
|
-
'gmsh': load_MSH,
|
|
1068
|
-
'msh': load_MSH,
|
|
1069
|
-
'rad': load_RAD,
|
|
1070
|
-
'radioss': load_RAD,
|
|
1071
|
-
'stl': load_STL,
|
|
1072
|
-
'vtu': load_VTU,
|
|
1073
|
-
'vtp': load_VTP,
|
|
1074
|
-
'paraview-legacy': load_VTK,
|
|
1075
|
-
'vtk': load_VTK,
|
|
1076
|
-
'tecplot': load_TEC,
|
|
1077
|
-
'tec': load_TEC,
|
|
1078
|
-
'med': load_MED,
|
|
1079
|
-
'salome': load_MED,
|
|
1080
|
-
'vrml': load_WRL,
|
|
1081
|
-
'wrl': load_WRL,
|
|
1082
|
-
'nem': load_NEM,
|
|
1083
|
-
'nemoh_mesh': load_NEM,
|
|
1084
|
-
'pnl': load_PNL,
|
|
1085
|
-
'hams': load_PNL,
|
|
1086
|
-
}
|