capytaine 2.3.1__cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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.
Files changed (93) hide show
  1. capytaine/__about__.py +16 -0
  2. capytaine/__init__.py +36 -0
  3. capytaine/bem/__init__.py +0 -0
  4. capytaine/bem/airy_waves.py +111 -0
  5. capytaine/bem/engines.py +441 -0
  6. capytaine/bem/problems_and_results.py +600 -0
  7. capytaine/bem/solver.py +594 -0
  8. capytaine/bodies/__init__.py +4 -0
  9. capytaine/bodies/bodies.py +1221 -0
  10. capytaine/bodies/dofs.py +19 -0
  11. capytaine/bodies/predefined/__init__.py +6 -0
  12. capytaine/bodies/predefined/cylinders.py +151 -0
  13. capytaine/bodies/predefined/rectangles.py +111 -0
  14. capytaine/bodies/predefined/spheres.py +70 -0
  15. capytaine/green_functions/FinGreen3D/.gitignore +1 -0
  16. capytaine/green_functions/FinGreen3D/FinGreen3D.f90 +3589 -0
  17. capytaine/green_functions/FinGreen3D/LICENSE +165 -0
  18. capytaine/green_functions/FinGreen3D/Makefile +16 -0
  19. capytaine/green_functions/FinGreen3D/README.md +24 -0
  20. capytaine/green_functions/FinGreen3D/test_program.f90 +39 -0
  21. capytaine/green_functions/LiangWuNoblesse/.gitignore +1 -0
  22. capytaine/green_functions/LiangWuNoblesse/LICENSE +504 -0
  23. capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90 +751 -0
  24. capytaine/green_functions/LiangWuNoblesse/Makefile +16 -0
  25. capytaine/green_functions/LiangWuNoblesse/README.md +2 -0
  26. capytaine/green_functions/LiangWuNoblesse/test_program.f90 +28 -0
  27. capytaine/green_functions/__init__.py +2 -0
  28. capytaine/green_functions/abstract_green_function.py +64 -0
  29. capytaine/green_functions/delhommeau.py +507 -0
  30. capytaine/green_functions/hams.py +204 -0
  31. capytaine/green_functions/libs/Delhommeau_float32.cpython-38-x86_64-linux-gnu.so +0 -0
  32. capytaine/green_functions/libs/Delhommeau_float64.cpython-38-x86_64-linux-gnu.so +0 -0
  33. capytaine/green_functions/libs/__init__.py +0 -0
  34. capytaine/io/__init__.py +0 -0
  35. capytaine/io/bemio.py +153 -0
  36. capytaine/io/legacy.py +328 -0
  37. capytaine/io/mesh_loaders.py +1086 -0
  38. capytaine/io/mesh_writers.py +692 -0
  39. capytaine/io/meshio.py +38 -0
  40. capytaine/io/wamit.py +479 -0
  41. capytaine/io/xarray.py +668 -0
  42. capytaine/matrices/__init__.py +16 -0
  43. capytaine/matrices/block.py +592 -0
  44. capytaine/matrices/block_toeplitz.py +325 -0
  45. capytaine/matrices/builders.py +89 -0
  46. capytaine/matrices/linear_solvers.py +232 -0
  47. capytaine/matrices/low_rank.py +395 -0
  48. capytaine/meshes/__init__.py +6 -0
  49. capytaine/meshes/clipper.py +465 -0
  50. capytaine/meshes/collections.py +342 -0
  51. capytaine/meshes/geometry.py +409 -0
  52. capytaine/meshes/mesh_like_protocol.py +37 -0
  53. capytaine/meshes/meshes.py +890 -0
  54. capytaine/meshes/predefined/__init__.py +6 -0
  55. capytaine/meshes/predefined/cylinders.py +314 -0
  56. capytaine/meshes/predefined/rectangles.py +261 -0
  57. capytaine/meshes/predefined/spheres.py +62 -0
  58. capytaine/meshes/properties.py +276 -0
  59. capytaine/meshes/quadratures.py +80 -0
  60. capytaine/meshes/quality.py +448 -0
  61. capytaine/meshes/surface_integrals.py +63 -0
  62. capytaine/meshes/symmetric.py +462 -0
  63. capytaine/post_pro/__init__.py +6 -0
  64. capytaine/post_pro/free_surfaces.py +88 -0
  65. capytaine/post_pro/impedance.py +92 -0
  66. capytaine/post_pro/kochin.py +54 -0
  67. capytaine/post_pro/rao.py +60 -0
  68. capytaine/tools/__init__.py +0 -0
  69. capytaine/tools/cache_on_disk.py +26 -0
  70. capytaine/tools/deprecation_handling.py +18 -0
  71. capytaine/tools/lists_of_points.py +52 -0
  72. capytaine/tools/lru_cache.py +49 -0
  73. capytaine/tools/optional_imports.py +27 -0
  74. capytaine/tools/prony_decomposition.py +150 -0
  75. capytaine/tools/symbolic_multiplication.py +149 -0
  76. capytaine/tools/timer.py +66 -0
  77. capytaine/ui/__init__.py +0 -0
  78. capytaine/ui/cli.py +28 -0
  79. capytaine/ui/rich.py +5 -0
  80. capytaine/ui/vtk/__init__.py +3 -0
  81. capytaine/ui/vtk/animation.py +329 -0
  82. capytaine/ui/vtk/body_viewer.py +28 -0
  83. capytaine/ui/vtk/helpers.py +82 -0
  84. capytaine/ui/vtk/mesh_viewer.py +461 -0
  85. capytaine-2.3.1.dist-info/LICENSE +674 -0
  86. capytaine-2.3.1.dist-info/METADATA +750 -0
  87. capytaine-2.3.1.dist-info/RECORD +93 -0
  88. capytaine-2.3.1.dist-info/WHEEL +6 -0
  89. capytaine-2.3.1.dist-info/entry_points.txt +3 -0
  90. capytaine.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  91. capytaine.libs/libgomp-e985bcbb.so.1.0.0 +0 -0
  92. capytaine.libs/libmvec-2-583a17db.28.so +0 -0
  93. capytaine.libs/libquadmath-2284e583.so.0.0.0 +0 -0
@@ -0,0 +1,692 @@
1
+ """Functions to write mesh to 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 time
9
+ import numpy as np
10
+
11
+ from capytaine.tools.optional_imports import import_optional_dependency
12
+
13
+
14
+ def write_mesh(filename, vertices, faces, file_format):
15
+ """Driver function that writes every mesh file file_format known by meshmagick
16
+
17
+ Parameters
18
+ ----------
19
+ filename: str
20
+ name of the mesh file to be written on disk
21
+ vertices: ndarray
22
+ numpy array of the coordinates of the mesh's nodes
23
+ faces: ndarray
24
+ numpy array of the faces' nodes connectivities
25
+ file_format: str
26
+ file_format of the mesh defined in the extension_dict dictionary
27
+ """
28
+
29
+ if file_format not in extension_dict:
30
+ raise IOError('Extension "%s" is not known' % file_format)
31
+
32
+ writer = extension_dict[file_format]
33
+
34
+ writer(filename, vertices, faces)
35
+
36
+
37
+ def write_DAT(filename, vertices, faces):
38
+ """Writes .DAT file format for the DIODORE (PRINCIPA (c)) software.
39
+
40
+ It also displays suggestions for inclusion into the .INP configuration
41
+ file.
42
+
43
+ Parameters
44
+ ----------
45
+ filename: str
46
+ name of the mesh file to be written on disk
47
+ vertices: ndarray
48
+ numpy array of the coordinates of the mesh's nodes
49
+ faces: ndarray
50
+ numpy array of the faces' nodes connectivities
51
+ """
52
+
53
+ root_filename, ext = os.path.splitext(filename)
54
+ filename = root_filename + ext.upper()
55
+ ofile = open(filename, 'w')
56
+
57
+ ofile.write('$\n$ Data for DIODORE input file : {0}\n'.format(root_filename.upper()))
58
+ ofile.write('$ GENERATED BY MESHMAGICK ON {0}\n$\n'.format(time.strftime('%c')))
59
+
60
+ ofile.write('$ NODE\n')
61
+ vertex_block = \
62
+ ''.join(
63
+ (
64
+ '\n'.join(
65
+ ''.join(
66
+ (
67
+ '{:8d}'.format(idx+1),
68
+ ''.join('{:13.5E}'.format(elt) for elt in node)
69
+ )
70
+ ) for (idx, node) in enumerate(vertices)
71
+ ),
72
+
73
+ '\n*RETURN\n'
74
+ )
75
+ )
76
+ ofile.write(vertex_block)
77
+
78
+ quad_block = '$\n$ ELEMENT,TYPE=Q4C000,ELSTRUCTURE={0}'.format(root_filename.upper())
79
+ tri_block = '$\n$ ELEMENT,TYPE=T3C000,ELSTRUCTURE={0}'.format(root_filename.upper())
80
+ nq = 0
81
+ nt = 0
82
+ for (idx, cell) in enumerate(faces+1):
83
+ if cell[0] != cell[-1]:
84
+ # quadrangle
85
+ nq += 1
86
+ quad_block = ''.join(
87
+ (
88
+ quad_block,
89
+ '\n',
90
+ '{:8d}'.format(idx+1),
91
+ ''.join('{:8d}'.format(node_id) for node_id in cell)
92
+ )
93
+ )
94
+
95
+ else:
96
+ # Triangle
97
+ nt += 1
98
+ tri_block = ''.join(
99
+ (
100
+ tri_block,
101
+ '\n',
102
+ '{:8d}'.format(idx+1),
103
+ ''.join('{:8d}'.format(node_id) for node_id in cell[:3])
104
+ )
105
+ )
106
+
107
+ print('-------------------------------------------------')
108
+ print('Suggestion for .inp DIODORE input file :')
109
+ print('')
110
+ print('*NODE,INPUT={0},FRAME=???'.format(root_filename))
111
+
112
+ if nq > 0:
113
+ quad_block = ''.join((quad_block, '\n*RETURN\n'))
114
+ ofile.write(quad_block)
115
+ print('*ELEMENT,TYPE=Q4C000,ELSTRUCTURE={0},INPUT={0}'.format(root_filename))
116
+ if nt > 0:
117
+ tri_block = ''.join((tri_block, '\n*RETURN\n'))
118
+ ofile.write(tri_block)
119
+ print('*ELEMENT,TYPE=T3C000,ELSTRUCTURE={0},INPUT={0}'.format(root_filename))
120
+
121
+ print('')
122
+ print('-------------------------------------------------')
123
+ ofile.close()
124
+
125
+
126
+ def write_HST(filename, vertices, faces):
127
+ """Writes .HST file format for the HYDROSTAR (Bureau Veritas (c)) software.
128
+
129
+ Parameters
130
+ ----------
131
+ filename: str
132
+ name of the mesh file to be written on disk
133
+ vertices: ndarray
134
+ numpy array of the coordinates of the mesh's nodes
135
+ faces: ndarray
136
+ numpy array of the faces' nodes connectivities
137
+ """
138
+ # TODO: allow many bodies
139
+
140
+ ofile = open(filename, 'w')
141
+
142
+ ofile.write(''.join((
143
+ 'PROJECT:\n',
144
+ 'USERS: meshmagick\n\n'
145
+ 'NBODY 1\n'
146
+ 'RHO 1025.0\n'
147
+ 'GRAVITY 9.81\n\n'
148
+ )))
149
+
150
+ coordinates_block = ''.join(( # block
151
+ 'COORDINATES\n',
152
+ '\n'.join( # line
153
+ ''.join(
154
+ (
155
+ '{:10d}'.format(idx+1), # index
156
+ ''.join('{:16.6E}'.format(elt) for elt in node) # node coordinates
157
+ )
158
+ ) for (idx, node) in enumerate(vertices)
159
+ ),
160
+ '\nENDCOORDINATES\n\n'
161
+ ))
162
+
163
+ ofile.write(coordinates_block)
164
+
165
+ cells_coordinates = ''.join(( # block
166
+ 'PANEL TYPE 0\n',
167
+ '\n'.join( # line
168
+ ''.join(
169
+ '{:10d}'.format(node_idx) for node_idx in cell
170
+ ) for cell in faces + 1
171
+ ),
172
+ '\nENDPANEL\n\n'
173
+ ))
174
+
175
+ ofile.write(cells_coordinates)
176
+
177
+ ofile.write('ENDFILE\n')
178
+
179
+ ofile.close()
180
+
181
+
182
+ def write_TEC(filename, vertices, faces):
183
+ """Writes .TEC file format for the TECPLOT (Tecplot (c)) visualisation software.
184
+
185
+ Parameters
186
+ ----------
187
+ filename: str
188
+ name of the mesh file to be written on disk
189
+ vertices: ndarray
190
+ numpy array of the coordinates of the mesh's nodes
191
+ faces: ndarray
192
+ numpy array of the faces' nodes connectivities
193
+ """
194
+
195
+ ofile = open(filename, 'w')
196
+
197
+ nv = vertices.shape[0]
198
+ nf = faces.shape[0]
199
+
200
+ ofile.write('TITLE = \" THIS FILE WAS GENERATED BY MESHMAGICK - FICHIER : {} \" \n'.format(filename))
201
+
202
+ ofile.write('VARIABLES = \"X\",\"Y\",\"Z\" \n')
203
+ ofile.write('ZONE T=\"MESH\" \n')
204
+ ofile.write('N={nv:10d} ,E={nf:10d} , F=FEPOINT, ET=QUADRILATERAL\n'.format(nv=nv, nf=nf))
205
+
206
+ node_block = '\n'.join( # block
207
+ ''.join(
208
+ ''.join('{:16.6E}'.format(elt) for elt in node)
209
+ ) for node in vertices
210
+ ) + '\n'
211
+ ofile.write(node_block)
212
+
213
+ cells_block = '\n'.join( # block
214
+ ''.join(
215
+ ''.join('{:10d}'.format(node_id) for node_id in cell)
216
+ ) for cell in faces + 1
217
+ ) + '\n'
218
+ ofile.write(cells_block)
219
+
220
+ ofile.close()
221
+
222
+ return 1
223
+
224
+
225
+ def write_VTU(filename, vertices, faces):
226
+ """Writes .vtu file format for the paraview (Kitware (c)) visualisation software.
227
+
228
+ It relies on the VTK library for its writer. VTU files use the last XML file format of the VTK library.
229
+
230
+ Parameters
231
+ ----------
232
+ filename: str
233
+ name of the mesh file to be written on disk
234
+ vertices: ndarray
235
+ numpy array of the coordinates of the mesh's nodes
236
+ faces: ndarray
237
+ numpy array of the faces' nodes connectivities
238
+ """
239
+ vtk = import_optional_dependency("vtk")
240
+
241
+ writer = vtk.vtkXMLUnstructuredGridWriter()
242
+ writer.SetDataModeToAscii()
243
+ writer.SetFileName(str(filename))
244
+
245
+ unstructured_grid = _build_vtkUnstructuredGrid(vertices, faces)
246
+ writer.SetInputData(unstructured_grid)
247
+ writer.Write()
248
+
249
+
250
+ def write_VTP(filename, vertices, faces):
251
+ """Writes .vtp file format for the Paraview (Kitware (c)) visualisation software.
252
+
253
+ It relies on the VTK library for its writer. VTP files use the last XML file format of the VTK library and
254
+ correspond to polydata.
255
+
256
+ Parameters
257
+ ----------
258
+ filename: str
259
+ name of the mesh file to be written on disk
260
+ vertices: ndarray
261
+ numpy array of the coordinates of the mesh's nodes
262
+ faces: ndarray
263
+ numpy array of the faces' nodes connectivities
264
+ """
265
+
266
+ vtk = import_optional_dependency("vtk")
267
+
268
+ writer = vtk.vtkXMLPolyDataWriter()
269
+ writer.SetDataModeToAscii()
270
+ writer.SetFileName(str(filename))
271
+
272
+ polydata = _build_vtkPolyData(vertices, faces)
273
+ writer.SetInputData(polydata)
274
+ writer.Write()
275
+
276
+
277
+ def write_VTK(filename, vertices, faces):
278
+ """Writes .vtk file format for the Paraview (Kitware (c)) visualisation software.
279
+
280
+ It relies on the VTK library for its writer. VTK files use the legagy ASCII file format of the VTK library.
281
+
282
+ Parameters
283
+ ----------
284
+ filename: str
285
+ name of the mesh file to be written on disk
286
+ vertices: ndarray
287
+ numpy array of the coordinates of the mesh's nodes
288
+ faces: ndarray
289
+ numpy array of the faces' nodes connectivities
290
+ """
291
+
292
+ nv = vertices.shape[0]
293
+ nf = faces.shape[0]
294
+
295
+ triangle_mask = (faces[:, 0] == faces[:, -1])
296
+ quadrangles_mask = np.invert(triangle_mask)
297
+ nb_triangles = len(np.where(triangle_mask)[0])
298
+ nb_quandrangles = len(np.where(quadrangles_mask)[0])
299
+
300
+ with open(filename, 'w') as f:
301
+
302
+ f.write('# vtk DataFile Version 4.0\n')
303
+ f.write('vtk file generated by meshmagick on %s\n' % time.strftime('%c'))
304
+ f.write('ASCII\n')
305
+ f.write('DATASET POLYDATA\n')
306
+ f.write('POINTS %u float\n' % nv)
307
+
308
+ for vertex in vertices:
309
+ f.write('%f %f %f\n' % (vertex[0], vertex[1], vertex[2]))
310
+
311
+ f.write('POLYGONS %u %u\n' % (nf, 4*nb_triangles+5*nb_quandrangles))
312
+
313
+ for face in faces:
314
+ if face[0] == face[-1]: # Triangle
315
+ f.write('3 %u %u %u\n' % (face[0], face[1], face[2]))
316
+ else: # Quadrangle
317
+ f.write('4 %u %u %u %u\n' % (face[0], face[1], face[2], face[3]))
318
+
319
+
320
+ def _build_vtkUnstructuredGrid(vertices, faces):
321
+ """Internal function that builds a VTK object for manipulation by the VTK library.
322
+
323
+ Parameters
324
+ ----------
325
+ vertices: ndarray
326
+ numpy array of the coordinates of the mesh's nodes
327
+ faces: ndarray
328
+ numpy array of the faces' nodes connectivities
329
+
330
+ Returns
331
+ -------
332
+ vtkObject
333
+ """
334
+
335
+ vtk = import_optional_dependency("vtk")
336
+
337
+ nv = max(np.shape(vertices))
338
+ nf = max(np.shape(faces))
339
+
340
+ vtk_mesh = vtk.vtkUnstructuredGrid()
341
+ vtk_mesh.Allocate(nf, nf)
342
+
343
+ # Building the vtkPoints data structure
344
+ vtk_points = vtk.vtkPoints()
345
+ vtk_points.SetNumberOfPoints(nv)
346
+ for idx, vertex in enumerate(vertices):
347
+ vtk_points.SetPoint(idx, vertex)
348
+
349
+ vtk_mesh.SetPoints(vtk_points) # Storing the points into vtk_mesh
350
+
351
+ # Building the vtkCell data structure
352
+ for cell in faces:
353
+ if cell[-1] in cell[:-1]:
354
+ vtk_cell = vtk.vtkTriangle()
355
+ nc = 3
356
+ else:
357
+ # #print 'quadrangle'
358
+ vtk_cell = vtk.vtkQuad()
359
+ nc = 4
360
+
361
+ for k in range(nc):
362
+ vtk_cell.GetPointIds().SetId(k, cell[k])
363
+
364
+ vtk_mesh.InsertNextCell(vtk_cell.GetCellType(), vtk_cell.GetPointIds())
365
+ return vtk_mesh
366
+
367
+
368
+ def _build_vtkPolyData(vertices, faces):
369
+ """Builds a vtkPolyData object from vertices and faces"""
370
+
371
+ vtk = import_optional_dependency("vtk")
372
+
373
+ # Create a vtkPoints object and store the points in it
374
+ points = vtk.vtkPoints()
375
+ for point in vertices:
376
+ points.InsertNextPoint(point)
377
+
378
+ # Create a vtkCellArray to store faces
379
+ cell_array = vtk.vtkCellArray()
380
+ for face_ids in faces:
381
+ if face_ids[0] == face_ids[-1]:
382
+ # Triangle
383
+ curface = face_ids[:3]
384
+ vtk_face = vtk.vtkTriangle()
385
+ else:
386
+ # Quadrangle
387
+ curface = face_ids[:4]
388
+ vtk_face = vtk.vtkQuad()
389
+
390
+ for idx, id in enumerate(curface):
391
+ vtk_face.GetPointIds().SetId(idx, id)
392
+
393
+ cell_array.InsertNextCell(vtk_face)
394
+
395
+ polydata_mesh = vtk.vtkPolyData()
396
+ polydata_mesh.SetPoints(points)
397
+ polydata_mesh.SetPolys(cell_array)
398
+
399
+ return polydata_mesh
400
+
401
+
402
+ def write_NAT(filename, vertices, faces):
403
+ """Writes .nat file format as defined into the load_NAT function.
404
+
405
+ Parameters
406
+ ----------
407
+ filename: str
408
+ name of the mesh file to be written on disk
409
+ vertices: ndarray
410
+ numpy array of the coordinates of the mesh's nodes
411
+ faces: ndarray
412
+ numpy array of the faces' nodes connectivities
413
+
414
+ See Also
415
+ --------
416
+ load_NAT
417
+ """
418
+
419
+ ofile = open(filename, 'w')
420
+
421
+ nv = max(np.shape(vertices))
422
+ nf = max(np.shape(faces))
423
+
424
+ ofile.write('%6u%6u\n' % (0, 0)) # lire les symmetries dans args...
425
+ ofile.write('%6u%6u\n' % (nv, nf))
426
+ for vertex in vertices:
427
+ ofile.write('%15.6E%15.6E%15.6E\n' % (vertex[0], vertex[1], vertex[2]))
428
+ for cell in faces+1:
429
+ ofile.write('%10u%10u%10u%10u\n' % (cell[0], cell[1], cell[2], cell[3]))
430
+
431
+ ofile.close()
432
+
433
+
434
+ def write_NEM(filename, vertices, faces):
435
+ """Writes mesh files used by the Mesh tool included in Nemoh
436
+
437
+ Parameters
438
+ ----------
439
+ filename : str
440
+ name of the mesh file to be written on disk
441
+ vertices: ndarray
442
+ numpy array of the coordinates of the mesh's nodes
443
+ faces: ndarray
444
+ numpy array of the faces' nodes connectivities
445
+
446
+ Note
447
+ ----
448
+ This file format is different from that used by Nemoh itself. It is only used by the Mesh tool.
449
+ """
450
+ ofile = open(filename, 'w')
451
+
452
+ ofile.write('%u\n' % vertices.shape[0])
453
+ ofile.write('%u\n' % faces.shape[0])
454
+
455
+ for vertex in vertices:
456
+ ofile.write('%15.6f\t%15.6f\t%15.6f\n' % (vertex[0], vertex[1], vertex[2]))
457
+
458
+ for face in faces+1:
459
+ ofile.write('%10u\t%10u\t%10u\t%10u\n' % (face[0], face[1], face[2], face[3]))
460
+
461
+ ofile.close()
462
+
463
+
464
+ def write_GDF(filename, vertices, faces, ulen=100.0, gravity=9.81, isx=0, isy=0):
465
+ """Writes .gdf file format for the WAMIT (Wamit INC. (c)) BEM software.
466
+
467
+ Parameters
468
+ ----------
469
+ filename: str
470
+ name of the mesh file to be written on disk
471
+ vertices: ndarray
472
+ numpy array of the coordinates of the mesh's nodes
473
+ faces: ndarray
474
+ numpy array of the faces' nodes connectivities
475
+ ulen: float, optional
476
+ length scale. The default is 100.0
477
+ gravity: float, optional
478
+ acceleration of gravity. The default is 9.81
479
+ isx: {0, 1}, optional
480
+ symmetry in x-axis. The default is 0
481
+ isy: {0, 1}, optional
482
+ symmetry in y-axis. The default is 0
483
+ """
484
+
485
+ nf = max(np.shape(faces))
486
+
487
+ ofile = open(filename, 'w')
488
+
489
+ ofile.write('GDF file generated by meshmagick on %s\n' % time.strftime('%c'))
490
+
491
+ ofile.write('%16.6f%16.6f\n' % (ulen, gravity))
492
+ ofile.write('%12u%12u\n' % (isx, isy)) # TODO : mettre les symetries en argument
493
+ ofile.write('%12u\n' % nf)
494
+
495
+ for cell in faces:
496
+ for k in range(4):
497
+ cur_vertices = vertices[cell[k], :]
498
+ ofile.write('%16.6E%16.6E%16.6E\n' % (cur_vertices[0], cur_vertices[1], cur_vertices[2]))
499
+
500
+ ofile.close()
501
+
502
+
503
+ def write_MAR(filename, vertices, faces):
504
+ """Writes mesh files to be used with Nemoh BEM software (Ecole Centrale de Nantes)
505
+
506
+ Parameters
507
+ ----------
508
+ filename: str
509
+ name of the mesh file to be written on disk
510
+ vertices: ndarray
511
+ numpy array of the coordinates of the mesh's nodes
512
+ faces: ndarray
513
+ numpy array of the faces' nodes connectivities
514
+ """
515
+
516
+ # TODO: detect symmetry in Oxz plane
517
+
518
+ ofile = open(filename, 'w')
519
+
520
+ ofile.write('{0:6d}{1:6d}\n'.format(2, 0)) # TODO : mettre les symetries en argument
521
+
522
+ for (idx, vertex) in enumerate(vertices):
523
+ ofile.write('{0:6d}{1:16.6f}{2:16.6f}{3:16.6f}\n'.format(idx+1, vertex[0], vertex[1], vertex[2]))
524
+
525
+ ofile.write('{0:6d}{1:6d}{2:6d}{3:6d}{4:6d}\n'.format(0, 0, 0, 0, 0))
526
+
527
+ cell_block = '\n'.join(
528
+ ''.join('{0:10d}'.format(elt) for elt in cell)
529
+ for cell in faces + 1
530
+ ) + '\n'
531
+ ofile.write(cell_block)
532
+ ofile.write('%6u%6u%6u%6u\n' % (0, 0, 0, 0))
533
+
534
+ ofile.close()
535
+
536
+ print('WARNING: if you described only one part of the mesh using symmetry for Nemoh, you may manually modify the ' \
537
+ 'file header accordingly')
538
+
539
+
540
+ def write_RAD(filename, vertices, faces):
541
+ raise NotImplementedError
542
+
543
+
544
+ def write_STL(filename, vertices, faces):
545
+ """Writes .stl file format. It relies on the VTK library for its writer.
546
+
547
+ Parameters
548
+ ----------
549
+ filename: str
550
+ name of the mesh file to be written on disk
551
+ vertices: ndarray
552
+ numpy array of the coordinates of the mesh's nodes
553
+ faces: ndarray
554
+ numpy array of the faces' nodes connectivities
555
+ """
556
+
557
+ # TODO : replace this implementation by using the vtk functionalities
558
+
559
+ # Triangulating quads
560
+ t1 = (0, 1, 2)
561
+ t2 = (0, 2, 3)
562
+
563
+ quads_ids = np.where(faces[:, 0] != faces[:, -1])[0]
564
+
565
+ new_faces = faces[quads_ids].copy()
566
+ new_faces[:, :3] = new_faces[:, t1]
567
+ new_faces[:, -1] = new_faces[:, 0]
568
+
569
+ faces[quads_ids, :3] = faces[:, t2][quads_ids]
570
+ faces[quads_ids, -1] = faces[quads_ids, 0]
571
+
572
+ faces = np.concatenate((faces, new_faces))
573
+
574
+ # Writing file
575
+ ofile = open(filename, 'w')
576
+
577
+ ofile.write('solid meshmagick\n')
578
+
579
+ for face in faces:
580
+ if face[0] != face[3]:
581
+ raise RuntimeError("""Only full triangle meshes are accepted in STL files.
582
+ Please consider using the --triangulate-quadrangles option (-tq) to
583
+ perform a prior triangulation of the mesh""")
584
+
585
+ # Computing normal
586
+ v0 = vertices[face[0], :]
587
+ v1 = vertices[face[1], :]
588
+ v2 = vertices[face[2], :]
589
+
590
+ n = np.cross(v1 - v0, v2 - v0)
591
+ n /= np.linalg.norm(n)
592
+
593
+ block_facet = ''.join([' facet normal ', ''.join('%15.6e' % ni for ni in n) + '\n',
594
+ ' outer loop\n',
595
+ ' vertex', ''.join('%15.6e' % Vi for Vi in v0) + '\n',
596
+ ' vertex', ''.join('%15.6e' % Vi for Vi in v1) + '\n',
597
+ ' vertex', ''.join('%15.6e' % Vi for Vi in v2) + '\n',
598
+ ' endloop\n',
599
+ ' endfacet\n'])
600
+ ofile.write(block_facet)
601
+ ofile.write('endsolid meshmagick\n')
602
+ ofile.close()
603
+
604
+
605
+ def write_INP(filename, vertices, faces):
606
+ raise NotImplementedError('INP writer is not implementer yet')
607
+
608
+
609
+ def write_MSH(filename, vertices, faces):
610
+ raise NotImplementedError('MSH writer is not implemented yet')
611
+
612
+
613
+ def write_MED(filename, vertices, faces):
614
+ raise NotImplementedError('MED writer is not implemented yet')
615
+
616
+
617
+ def write_WRL(filename, vertices, faces):
618
+ raise NotImplementedError('VRML writer is not implemented yet')
619
+
620
+
621
+ def write_PNL(filename, vertices, faces):
622
+ """Write a mesh to a file using HAMS file format.
623
+
624
+ Took some inspiration from "nemohmesh_to_pnl" by Garett Barter
625
+ https://github.com/WISDEM/pyHAMS/blob/d10b51122e92849c63640b34e4fa9d413eb306fd/pyhams/pyhams.py#L11
626
+
627
+ This writer does not support symmetries.
628
+
629
+ Parameters
630
+ ----------
631
+ filename: str
632
+ name of the mesh file to be written on disk
633
+ vertices: ndarray
634
+ numpy array of the coordinates of the mesh's nodes
635
+ faces: ndarray
636
+ numpy array of the faces' nodes connectivities
637
+ """
638
+ with open(filename, 'w') as f:
639
+ f.write(' --------------Hull Mesh File---------------\n')
640
+ f.write('\n')
641
+ f.write(' # Number of Panels, Nodes, X-Symmetry and Y-Symmetry\n')
642
+ f.write(f' {faces.shape[0]} {vertices.shape[0]} 0 0\n')
643
+ f.write('\n')
644
+ f.write(' #Start Definition of Node Coordinates ! node_number x y z\n')
645
+ for i, vertex in enumerate(vertices):
646
+ f.write("{:>5}{:>18.6f}{:>18.6f}{:>18.6f}\n".format(i+1, *vertex))
647
+ f.write(' #End Definition of Node Coordinates\n')
648
+ f.write('\n')
649
+ f.write(' #Start Definition of Node Relations ! panel_number number_of_vertices Vertex1_ID Vertex2_ID Vertex3_ID (Vertex4_ID)\n')
650
+ for i, face in enumerate(faces):
651
+ face = face + 1
652
+ if face[2] == face[3]: # Triangle
653
+ f.write("{:>5}{:>5}{:>10}{:>10}{:>10}\n".format(i+1, 3, *face[:3]))
654
+ else:
655
+ f.write("{:>5}{:>5}{:>10}{:>10}{:>10}{:>10}\n".format(i+1, 4, *face))
656
+ f.write(' #End Definition of Node Relations\n')
657
+ f.write('\n')
658
+ f.write(' --------------End Hull Mesh File---------------\n')
659
+
660
+
661
+ extension_dict = { # keyword, writer
662
+ 'mar': write_MAR,
663
+ 'nemoh': write_MAR,
664
+ 'wamit': write_GDF,
665
+ 'gdf': write_GDF,
666
+ 'diodore-inp': write_INP,
667
+ 'inp': write_INP,
668
+ 'diodore-dat': write_DAT,
669
+ 'hydrostar': write_HST,
670
+ 'hst': write_HST,
671
+ 'natural': write_NAT,
672
+ 'nat': write_NAT,
673
+ 'gmsh': write_MSH,
674
+ 'msh': write_MSH,
675
+ 'rad': write_RAD,
676
+ 'radioss': write_RAD,
677
+ 'stl': write_STL,
678
+ 'vtu': write_VTU,
679
+ 'vtp': write_VTP,
680
+ 'paraview-legacy': write_VTK,
681
+ 'vtk': write_VTK,
682
+ 'tecplot': write_TEC,
683
+ 'tec': write_TEC,
684
+ 'med': write_MED,
685
+ 'salome': write_MED,
686
+ 'vrml': write_WRL,
687
+ 'wrl': write_WRL,
688
+ 'nem': write_NEM,
689
+ 'nemoh_mesh': write_NEM,
690
+ 'pnl': write_PNL,
691
+ 'hams': write_PNL,
692
+ }