capytaine 2.1__cp312-cp312-win_amd64.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 (85) hide show
  1. capytaine/__about__.py +16 -0
  2. capytaine/__init__.py +48 -0
  3. capytaine/bem/__init__.py +0 -0
  4. capytaine/bem/airy_waves.py +106 -0
  5. capytaine/bem/engines.py +441 -0
  6. capytaine/bem/problems_and_results.py +540 -0
  7. capytaine/bem/solver.py +463 -0
  8. capytaine/bodies/__init__.py +4 -0
  9. capytaine/bodies/bodies.py +1084 -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 +109 -0
  14. capytaine/bodies/predefined/spheres.py +70 -0
  15. capytaine/green_functions/__init__.py +2 -0
  16. capytaine/green_functions/abstract_green_function.py +12 -0
  17. capytaine/green_functions/delhommeau.py +380 -0
  18. capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.dll.a +0 -0
  19. capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.pyd +0 -0
  20. capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.dll.a +0 -0
  21. capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.pyd +0 -0
  22. capytaine/green_functions/libs/XieDelhommeau_float32.cp312-win_amd64.dll.a +0 -0
  23. capytaine/green_functions/libs/XieDelhommeau_float32.cp312-win_amd64.pyd +0 -0
  24. capytaine/green_functions/libs/XieDelhommeau_float64.cp312-win_amd64.dll.a +0 -0
  25. capytaine/green_functions/libs/XieDelhommeau_float64.cp312-win_amd64.pyd +0 -0
  26. capytaine/green_functions/libs/__init__.py +0 -0
  27. capytaine/io/__init__.py +0 -0
  28. capytaine/io/bemio.py +141 -0
  29. capytaine/io/legacy.py +328 -0
  30. capytaine/io/mesh_loaders.py +1061 -0
  31. capytaine/io/mesh_writers.py +692 -0
  32. capytaine/io/meshio.py +35 -0
  33. capytaine/io/xarray.py +514 -0
  34. capytaine/matrices/__init__.py +16 -0
  35. capytaine/matrices/block.py +590 -0
  36. capytaine/matrices/block_toeplitz.py +325 -0
  37. capytaine/matrices/builders.py +89 -0
  38. capytaine/matrices/linear_solvers.py +233 -0
  39. capytaine/matrices/low_rank.py +393 -0
  40. capytaine/meshes/__init__.py +6 -0
  41. capytaine/meshes/clipper.py +464 -0
  42. capytaine/meshes/collections.py +313 -0
  43. capytaine/meshes/geometry.py +409 -0
  44. capytaine/meshes/meshes.py +746 -0
  45. capytaine/meshes/predefined/__init__.py +6 -0
  46. capytaine/meshes/predefined/cylinders.py +314 -0
  47. capytaine/meshes/predefined/rectangles.py +261 -0
  48. capytaine/meshes/predefined/spheres.py +62 -0
  49. capytaine/meshes/properties.py +199 -0
  50. capytaine/meshes/quadratures.py +80 -0
  51. capytaine/meshes/quality.py +448 -0
  52. capytaine/meshes/surface_integrals.py +63 -0
  53. capytaine/meshes/symmetric.py +383 -0
  54. capytaine/post_pro/__init__.py +6 -0
  55. capytaine/post_pro/free_surfaces.py +88 -0
  56. capytaine/post_pro/impedance.py +92 -0
  57. capytaine/post_pro/kochin.py +54 -0
  58. capytaine/post_pro/rao.py +60 -0
  59. capytaine/tools/__init__.py +0 -0
  60. capytaine/tools/cache_on_disk.py +24 -0
  61. capytaine/tools/deprecation_handling.py +18 -0
  62. capytaine/tools/lists_of_points.py +52 -0
  63. capytaine/tools/lru_cache.py +49 -0
  64. capytaine/tools/optional_imports.py +27 -0
  65. capytaine/tools/prony_decomposition.py +94 -0
  66. capytaine/tools/symbolic_multiplication.py +104 -0
  67. capytaine/ui/__init__.py +0 -0
  68. capytaine/ui/cli.py +28 -0
  69. capytaine/ui/rich.py +5 -0
  70. capytaine/ui/vtk/__init__.py +3 -0
  71. capytaine/ui/vtk/animation.py +329 -0
  72. capytaine/ui/vtk/body_viewer.py +26 -0
  73. capytaine/ui/vtk/helpers.py +82 -0
  74. capytaine/ui/vtk/mesh_viewer.py +461 -0
  75. capytaine-2.1.dist-info/DELVEWHEEL +2 -0
  76. capytaine-2.1.dist-info/LICENSE +674 -0
  77. capytaine-2.1.dist-info/METADATA +756 -0
  78. capytaine-2.1.dist-info/RECORD +85 -0
  79. capytaine-2.1.dist-info/WHEEL +4 -0
  80. capytaine-2.1.dist-info/entry_points.txt +3 -0
  81. capytaine.libs/libgcc_s_seh-1.dll +0 -0
  82. capytaine.libs/libgfortran-5.dll +0 -0
  83. capytaine.libs/libgomp-1.dll +0 -0
  84. capytaine.libs/libquadmath-0.dll +0 -0
  85. capytaine.libs/libwinpthread-1.dll +0 -0
@@ -0,0 +1,199 @@
1
+ """Helper functions to compute some properties of the mesh.
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 numpy as np
8
+
9
+
10
+ def compute_faces_properties(mesh):
11
+ """Compute the faces properties of the mesh"""
12
+
13
+ # faces_areas, faces_normals, faces_centers = mm.get_all_faces_properties(mesh._vertices, mesh._faces)
14
+ nf = mesh.nb_faces
15
+
16
+ # triangle_mask = _faces[:, 0] == _faces[:, -1]
17
+ # nb_triangles = np.sum(triangle_mask)
18
+ # quads_mask = np.invert(triangle_mask)
19
+ # nb_quads = nf - nb_triangles
20
+
21
+ faces_areas = np.zeros(nf, dtype=float)
22
+ faces_normals = np.zeros((nf, 3), dtype=float)
23
+ faces_centers = np.zeros((nf, 3), dtype=float)
24
+
25
+ # Collectively dealing with triangles
26
+ # triangles = _faces[triangle_mask]
27
+ triangles_id = mesh.triangles_ids
28
+ triangles = mesh._faces[triangles_id]
29
+
30
+ triangles_normals = np.cross(mesh._vertices[triangles[:, 1]] - mesh._vertices[triangles[:, 0]],
31
+ mesh._vertices[triangles[:, 2]] - mesh._vertices[triangles[:, 0]])
32
+ triangles_normals_norm = np.linalg.norm(triangles_normals, axis=1)
33
+
34
+ degenerate_triangle = np.abs(triangles_normals_norm) < 1e-12
35
+ triangles_id = triangles_id[~degenerate_triangle]
36
+ triangles_normals = triangles_normals[~degenerate_triangle, :]
37
+ triangles_normals_norm = triangles_normals_norm[~degenerate_triangle]
38
+ triangles = triangles[~degenerate_triangle, :]
39
+ # Now, continue the computations without the degenerate triangles
40
+
41
+ faces_normals[triangles_id] = triangles_normals / triangles_normals_norm[:, np.newaxis]
42
+ faces_areas[triangles_id] = triangles_normals_norm / 2.
43
+ faces_centers[triangles_id] = np.sum(mesh._vertices[triangles[:, :3]], axis=1) / 3.
44
+
45
+ # Collectively dealing with quads
46
+ quads_id = mesh.quadrangles_ids
47
+ quads = mesh._faces[quads_id]
48
+ # quads = _faces[quads_mask]
49
+
50
+ quads_normals = np.cross(mesh._vertices[quads[:, 2]] - mesh._vertices[quads[:, 0]],
51
+ mesh._vertices[quads[:, 3]] - mesh._vertices[quads[:, 1]])
52
+
53
+ quads_normals_norm = np.linalg.norm(quads_normals, axis=1)
54
+
55
+ degenerate_quad = np.abs(quads_normals_norm) < 1e-12
56
+ quads_id = quads_id[~degenerate_quad]
57
+ quads_normals = quads_normals[~degenerate_quad]
58
+ quads_normals_norm = quads_normals_norm[~degenerate_quad]
59
+ quads = quads[~degenerate_quad, :]
60
+ # Now, continue the computations without the degenerate quads
61
+
62
+ faces_normals[quads_id] = quads_normals / quads_normals_norm[:, np.newaxis]
63
+
64
+ a1 = np.linalg.norm(np.cross(mesh._vertices[quads[:, 1]] - mesh._vertices[quads[:, 0]],
65
+ mesh._vertices[quads[:, 2]] - mesh._vertices[quads[:, 0]]), axis=1) * 0.5
66
+ a2 = np.linalg.norm(np.cross(mesh._vertices[quads[:, 3]] - mesh._vertices[quads[:, 0]],
67
+ mesh._vertices[quads[:, 2]] - mesh._vertices[quads[:, 0]]), axis=1) * 0.5
68
+ faces_areas[quads_id] = a1 + a2
69
+
70
+ c1 = np.sum(mesh._vertices[quads[:, :3]], axis=1) / 3.
71
+ c2 = (np.sum(mesh._vertices[quads[:, 2:4]], axis=1) + mesh._vertices[quads[:, 0]]) / 3.
72
+
73
+ faces_centers[quads_id] = (np.array(([a1, ] * 3)).T * c1 + np.array(([a2, ] * 3)).T * c2)
74
+ faces_centers[quads_id] /= np.array(([faces_areas[quads_id], ] * 3)).T
75
+
76
+ faces_radiuses = compute_radiuses(mesh, faces_centers)
77
+
78
+ return {'faces_areas': faces_areas,
79
+ 'faces_normals': faces_normals,
80
+ 'faces_centers': faces_centers,
81
+ 'faces_radiuses': faces_radiuses,
82
+ }
83
+
84
+
85
+ def compute_radiuses(mesh, faces_centers):
86
+ """Compute the radiuses of the faces of the mesh.
87
+
88
+ The radius is defined here as the maximal distance between the center
89
+ of mass of a cell and one of its points."""
90
+
91
+ # Coordinates of all the vertices grouped by face
92
+ faces_vertices = mesh.vertices[mesh.faces, :]
93
+ # faces_vertices.shape == (nb_faces, 4, 3)
94
+
95
+ # Reorder the axes for array broadcasting below
96
+ faces_vertices = np.moveaxis(faces_vertices, 0, 1)
97
+ # faces_vertices.shape == (4, nb_faces, 3)
98
+
99
+ # Get all the vectors between the center of faces and their vertices.
100
+ radial_vector = faces_centers - faces_vertices
101
+ # radial_vector.shape == (4, nb_faces, 3)
102
+
103
+ # Keep the maximum length
104
+ faces_radiuses = np.max(np.linalg.norm(radial_vector, axis=2), axis=0)
105
+ # faces_radiuses.shape = (nb_faces)
106
+
107
+ return faces_radiuses
108
+
109
+
110
+ def compute_connectivity(mesh):
111
+ """Compute the connectivities of the mesh.
112
+
113
+ It concerns further connectivity than simple faces/vertices connectivities. It computes the vertices / vertices, vertices / faces and faces / faces connectivities.
114
+
115
+ Note
116
+ ----
117
+ * Note that if the mesh is not conformal, the algorithm may not perform correctly
118
+
119
+ TODO: The computation of boundaries should be in the future computed with help of VTK
120
+ """
121
+
122
+ nv = mesh.nb_vertices
123
+ nf = mesh.nb_faces
124
+
125
+ mesh_closed = True
126
+
127
+ # Building connectivities
128
+
129
+ # Establishing v_v and v_f connectivities
130
+ v_v = dict([(i, set()) for i in range(nv)])
131
+ v_f = dict([(i, set()) for i in range(nv)])
132
+ for (iface, face) in enumerate(mesh._faces):
133
+ if face[0] == face[-1]:
134
+ face_w = face[:3]
135
+ else:
136
+ face_w = face
137
+ for (index, iV) in enumerate(face_w):
138
+ v_f[iV].add(iface)
139
+ v_v[face_w[index - 1]].add(iV)
140
+ v_v[iV].add(face_w[index - 1])
141
+
142
+ # Connectivity f_f
143
+ boundary_edges = dict()
144
+
145
+ f_f = dict([(i, set()) for i in range(nf)])
146
+ for ivertex in range(nv):
147
+ set1 = v_f[ivertex]
148
+ for iadj_v in v_v[ivertex]:
149
+ set2 = v_f[iadj_v]
150
+ intersection = list(set1 & set2)
151
+ if len(intersection) == 2:
152
+ f_f[intersection[0]].add(intersection[1])
153
+ f_f[intersection[1]].add(intersection[0])
154
+
155
+ elif len(intersection) == 1:
156
+ boundary_face = mesh._faces[intersection[0]]
157
+
158
+ if boundary_face[0] == boundary_face[-1]:
159
+ boundary_face = boundary_face[:3]
160
+ ids = np.where((boundary_face == ivertex) + (boundary_face == iadj_v))[0]
161
+
162
+ if ids[1] != ids[0]+1:
163
+ i_v_orig, i_v_target = boundary_face[ids]
164
+ else:
165
+ i_v_target, i_v_orig = boundary_face[ids]
166
+
167
+ boundary_edges[i_v_orig] = i_v_target
168
+ else:
169
+ raise RuntimeError('Unexpected error while computing mesh connectivities')
170
+
171
+ # Computing boundaries
172
+ boundaries = list()
173
+ # TODO: calculer des boundaries fermees et ouvertes (closed_boundaries et open_boundaries) et mettre dans dict
174
+ while True:
175
+ try:
176
+ boundary = list()
177
+ i_v0_init, i_v1 = boundary_edges.popitem()
178
+ boundary.append(i_v0_init)
179
+ boundary.append(i_v1)
180
+ i_v0 = i_v1
181
+
182
+ while True:
183
+ try:
184
+ i_v1 = boundary_edges.pop(i_v0)
185
+ boundary.append(i_v1)
186
+ i_v0 = i_v1
187
+ except KeyError:
188
+ if boundary[0] != boundary[-1]:
189
+ print('Boundary is not closed !!!')
190
+ else:
191
+ boundaries.append(boundary)
192
+ break
193
+ except KeyError:
194
+ break
195
+
196
+ return {'v_v': v_v,
197
+ 'v_f': v_f,
198
+ 'f_f': f_f,
199
+ 'boundaries': boundaries}
@@ -0,0 +1,80 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from capytaine.tools.optional_imports import silently_import_optional_dependency
6
+
7
+ LOG = logging.getLogger(__name__)
8
+
9
+ # The builtin methods are stored as a list of 2D-points in [-1, 1]² and a list
10
+ # of corresponding weights. The 2D points will be remapped to the actual shape
11
+ # of the faces. They are only defined for quadrilaterals. They also work for
12
+ # triangles (although they might be subobtimal).
13
+
14
+ builtin_methods = {
15
+ "First order": (np.array([(0.0, 0.0)]), np.array([1.0])),
16
+ "Gauss-Legendre 2": (
17
+ np.array([(+1/np.sqrt(3), +1/np.sqrt(3)),
18
+ (+1/np.sqrt(3), -1/np.sqrt(3)),
19
+ (-1/np.sqrt(3), +1/np.sqrt(3)),
20
+ (-1/np.sqrt(3), -1/np.sqrt(3))]),
21
+ np.array([1/4, 1/4, 1/4, 1/4])
22
+ )
23
+ }
24
+
25
+
26
+ def compute_quadrature_on_faces(faces, method):
27
+ """
28
+ Compute the quadrature points and weight for numerical integration over the faces.
29
+
30
+ Parameters
31
+ ----------
32
+ faces: array of shape (nb_faces, 4, 3)
33
+ The 3D-coordinates of each of the 4 corners of each face.
34
+ method: string or quadpy object
35
+ The method used to compute the quadrature scheme
36
+
37
+ Returns
38
+ -------
39
+ points: array of shape (nb_faces, nb_quad_points, 3)
40
+ The 3D-coordinates of each of the quadrature points (their number depends on the method) of each face.
41
+ weights: array of shape (nb_faces, nb_quad_points)
42
+ Weights associated to each of the quadrature points.
43
+ """
44
+
45
+ if method in builtin_methods:
46
+ LOG.debug("Quadrature method found in builtin methods.")
47
+ local_points, local_weights = builtin_methods[method]
48
+
49
+ elif ((quadpy := silently_import_optional_dependency("quadpy")) is not None
50
+ and isinstance(method, quadpy.c2._helpers.C2Scheme)):
51
+ LOG.debug("Quadrature method is a Quadpy scheme: %s", method.name)
52
+ local_points = method.points.T
53
+ local_weights = method.weights
54
+
55
+ else:
56
+ raise ValueError(f"Unrecognized quadrature scheme: {method}.\n"
57
+ f"Consider using one of the following: {set(builtin_methods.keys())}")
58
+
59
+ nb_faces = faces.shape[0]
60
+ nb_quad_points = len(local_weights)
61
+ points = np.empty((nb_faces, nb_quad_points, 3))
62
+ weights = np.empty((nb_faces, nb_quad_points))
63
+
64
+ for i_face in range(nb_faces):
65
+ for k_quad in range(nb_quad_points):
66
+ xk, yk = local_points[k_quad, :]
67
+ points[i_face, k_quad, :] = (
68
+ (1+xk)*(1+yk) * faces[i_face, 0, :]
69
+ + (1+xk)*(1-yk) * faces[i_face, 1, :]
70
+ + (1-xk)*(1-yk) * faces[i_face, 2, :]
71
+ + (1-xk)*(1+yk) * faces[i_face, 3, :]
72
+ )/4
73
+ dxidx = ((1+yk)*faces[i_face, 0, :] + (1-yk)*faces[i_face, 1, :]
74
+ - (1-yk)*faces[i_face, 2, :] - (1+yk)*faces[i_face, 3, :])/4
75
+ dxidy = ((1+xk)*faces[i_face, 0, :] - (1+xk)*faces[i_face, 1, :]
76
+ - (1-xk)*faces[i_face, 2, :] + (1-xk)*faces[i_face, 3, :])/4
77
+ detJ = np.linalg.norm(np.cross(dxidx, dxidy))
78
+ weights[i_face, k_quad] = local_weights[k_quad] * 4 * detJ
79
+
80
+ return points, weights