capytaine 2.3__cp312-cp312-win_amd64.whl → 2.3.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.
capytaine/__about__.py CHANGED
@@ -5,7 +5,7 @@ __all__ = ["__title__", "__description__", "__version__", "__author__", "__uri__
5
5
  __title__ = "capytaine"
6
6
  __description__ = """Python BEM solver for linear potential flow, based on Nemoh"""
7
7
 
8
- __version__ = "2.3"
8
+ __version__ = "2.3.1"
9
9
 
10
10
  __author__ = "Matthieu Ancellin"
11
11
  __uri__ = "https://github.com/capytaine/capytaine"
capytaine/__init__.py CHANGED
@@ -3,14 +3,14 @@
3
3
 
4
4
 
5
5
  # start delvewheel patch
6
- def _delvewheel_patch_1_10_1():
6
+ def _delvewheel_patch_1_11_2():
7
7
  import os
8
8
  if os.path.isdir(libs_dir := os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, 'capytaine.libs'))):
9
9
  os.add_dll_directory(libs_dir)
10
10
 
11
11
 
12
- _delvewheel_patch_1_10_1()
13
- del _delvewheel_patch_1_10_1
12
+ _delvewheel_patch_1_11_2()
13
+ del _delvewheel_patch_1_11_2
14
14
  # end delvewheel patch
15
15
 
16
16
  from .__about__ import (
@@ -360,16 +360,18 @@ class DiffractionProblem(LinearPotentialFlowProblem):
360
360
 
361
361
  if self.body is not None:
362
362
 
363
- self.boundary_condition = -(
363
+ self.boundary_condition = np.zeros(
364
+ shape=(self.body.mesh_including_lid.nb_faces,),
365
+ dtype=np.complex128
366
+ )
367
+
368
+ self.boundary_condition[self.body.hull_mask] = -(
364
369
  airy_waves_velocity(self.body.mesh.faces_centers, self)
365
370
  * self.body.mesh.faces_normals
366
371
  ).sum(axis=1)
367
372
  # Note that even with forward speed, this is computed based on the
368
373
  # frequency and not the encounter frequency.
369
374
 
370
- if self.body.lid_mesh is not None:
371
- self.boundary_condition = np.concatenate([self.boundary_condition, np.zeros(self.body.lid_mesh.nb_faces)])
372
-
373
375
  if len(self.body.dofs) == 0:
374
376
  LOG.warning(f"The body {self.body.name} used in diffraction problem has no dofs!")
375
377
 
@@ -421,11 +423,16 @@ class RadiationProblem(LinearPotentialFlowProblem):
421
423
 
422
424
  dof = self.body.dofs[self.radiating_dof]
423
425
 
424
- displacement_on_face = np.sum(dof * self.body.mesh.faces_normals, axis=1) # This is a dot product on each face
425
- if self.body.lid_mesh is not None:
426
- displacement_on_face = np.concatenate([displacement_on_face, np.zeros(self.body.lid_mesh.nb_faces)])
426
+ self.boundary_condition = self.encounter_omega * np.zeros(
427
+ shape=(self.body.mesh_including_lid.nb_faces,),
428
+ dtype=np.complex128
429
+ )
430
+ # The multiplication by encounter_omega is just a programming trick to ensure that boundary_condition
431
+ # is implemented with the correct type (for zero and infinite frequencies), it does not affect the value.
432
+ # Below the value is update on the hull. It remains zero on the lid.
427
433
 
428
- self.boundary_condition = -1j * self.encounter_omega * displacement_on_face
434
+ displacement_on_face = np.sum(dof * self.body.mesh.faces_normals, axis=1) # This is a dot product on each face
435
+ self.boundary_condition[self.body.hull_mask] = -1j * self.encounter_omega * displacement_on_face
429
436
 
430
437
  if self.forward_speed != 0.0:
431
438
  if self.radiating_dof.lower() == "pitch":
@@ -440,7 +447,8 @@ class RadiationProblem(LinearPotentialFlowProblem):
440
447
  "Only radiating dofs with name in {'Surge', 'Sway', 'Heave', 'Roll', 'Pitch', 'Yaw'} are supported.\n"
441
448
  f"Got instead `radiating_dof={self.radiating_dof}`"
442
449
  )
443
- self.boundary_condition += self.forward_speed * ddofdx_dot_n
450
+
451
+ self.boundary_condition[self.body.hull_mask] += self.forward_speed * ddofdx_dot_n
444
452
 
445
453
 
446
454
 
capytaine/bem/solver.py CHANGED
@@ -183,7 +183,7 @@ class BEMSolver:
183
183
  nabla_phi = self._compute_potential_gradient(problem.body.mesh_including_lid, result)
184
184
  pressure += problem.rho * problem.forward_speed * nabla_phi[:, 0]
185
185
 
186
- pressure_on_hull = pressure[:problem.body.mesh.nb_faces] # Discards pressure on lid if any
186
+ pressure_on_hull = pressure[problem.body.hull_mask] # Discards pressure on lid if any
187
187
  forces = problem.body.integrate_pressure(pressure_on_hull)
188
188
 
189
189
  if not keep_details:
@@ -114,10 +114,21 @@ class FloatingBody(ClippableMixin, Abstract3DObject):
114
114
  else:
115
115
  self.dofs = dofs
116
116
 
117
+ self._evaluate_full_mesh()
118
+
117
119
  LOG.info(f"New floating body: {self.__str__()}.")
118
120
 
119
121
  self._check_dofs_shape_consistency()
120
122
 
123
+ def _evaluate_full_mesh(self):
124
+ """Merge the mesh and lid_mesh, while keeping track of where each panel came from."""
125
+ if self.lid_mesh is None:
126
+ self.mesh_including_lid = self.mesh
127
+ self.hull_mask = np.full((self.mesh.nb_faces,), True)
128
+ else:
129
+ self.mesh_including_lid, masks = self.mesh.join_meshes(self.lid_mesh, return_masks=True)
130
+ self.hull_mask = masks[0]
131
+
121
132
  @staticmethod
122
133
  def from_meshio(mesh, name=None) -> 'FloatingBody':
123
134
  """Create a FloatingBody from a meshio mesh object.
@@ -138,13 +149,6 @@ class FloatingBody(ClippableMixin, Abstract3DObject):
138
149
  """Arbitrary order. The point is to sort together the problems involving the same body."""
139
150
  return self.name < other.name
140
151
 
141
- @cached_property
142
- def mesh_including_lid(self):
143
- if self.lid_mesh is not None:
144
- return self.mesh.join_meshes(self.lid_mesh)
145
- else:
146
- return self.mesh
147
-
148
152
  ##########
149
153
  # Dofs #
150
154
  ##########
@@ -570,7 +574,7 @@ class FloatingBody(ClippableMixin, Abstract3DObject):
570
574
  )
571
575
  for radiating_dof_name in self.dofs
572
576
  for influenced_dof_name in self.dofs
573
- ])
577
+ ], compat='no_conflicts', join="outer")
574
578
 
575
579
  # Reorder dofs
576
580
  K = hs_set.hydrostatic_stiffness.sel(influenced_dof=list(self.dofs.keys()), radiating_dof=list(self.dofs.keys()))
@@ -660,7 +664,7 @@ class FloatingBody(ClippableMixin, Abstract3DObject):
660
664
  'radiating_dof': body_dof_names},
661
665
  name="inertia_matrix")
662
666
 
663
- total_mass_xr = xr.merge([rigid_inertia_matrix_xr, other_dofs_inertia_matrix_xr], compat="override").inertia_matrix
667
+ total_mass_xr = xr.merge([rigid_inertia_matrix_xr, other_dofs_inertia_matrix_xr], compat="override", join="outer").inertia_matrix
664
668
 
665
669
  non_rigid_dofs = set(body_dof_names) - set(rigid_dof_names)
666
670
 
@@ -980,6 +984,7 @@ respective inertia coefficients are assigned as NaN.")
980
984
  self.mesh.mirror(plane)
981
985
  if self.lid_mesh is not None:
982
986
  self.lid_mesh.mirror(plane)
987
+ self._evaluate_full_mesh()
983
988
  for dof in self.dofs:
984
989
  self.dofs[dof] -= 2 * np.outer(np.dot(self.dofs[dof], plane.normal), plane.normal)
985
990
  for point_attr in ('geometric_center', 'rotation_center', 'center_of_mass'):
@@ -994,6 +999,7 @@ respective inertia coefficients are assigned as NaN.")
994
999
  self.mesh.translate(vector, *args, **kwargs)
995
1000
  if self.lid_mesh is not None:
996
1001
  self.lid_mesh.translate(vector, *args, **kwargs)
1002
+ self._evaluate_full_mesh()
997
1003
  for point_attr in ('geometric_center', 'rotation_center', 'center_of_mass'):
998
1004
  if point_attr in self.__dict__ and self.__dict__[point_attr] is not None:
999
1005
  self.__dict__[point_attr] = np.array(self.__dict__[point_attr]) + vector
@@ -1004,6 +1010,7 @@ respective inertia coefficients are assigned as NaN.")
1004
1010
  self.mesh.rotate(axis, angle)
1005
1011
  if self.lid_mesh is not None:
1006
1012
  self.lid_mesh.rotate(axis, angle)
1013
+ self._evaluate_full_mesh()
1007
1014
  for point_attr in ('geometric_center', 'rotation_center', 'center_of_mass'):
1008
1015
  if point_attr in self.__dict__ and self.__dict__[point_attr] is not None:
1009
1016
  self.__dict__[point_attr] = axis.rotate_points([self.__dict__[point_attr]], angle)[0, :]
@@ -1023,6 +1030,7 @@ respective inertia coefficients are assigned as NaN.")
1023
1030
  if self.lid_mesh.nb_faces == 0:
1024
1031
  LOG.warning("Lid mesh %s is empty after clipping. The lid mesh is removed.", self.lid_mesh)
1025
1032
  self.lid_mesh = None
1033
+ self._evaluate_full_mesh()
1026
1034
 
1027
1035
  # Clip dofs
1028
1036
  ids = self.mesh._clipping_data['faces_ids']
@@ -14,5 +14,3 @@ $(BUILD_DIR)/LiangWuNoblesseWaveTerm.o: LiangWuNoblesseWaveTerm.f90
14
14
  clean:
15
15
  rm -rf $(BUILD_DIR)
16
16
  .PHONY: run_test clean
17
-
18
-
@@ -215,21 +215,25 @@ class Delhommeau(AbstractGreenFunction):
215
215
  filepath = os.path.join(tabulation_cache_dir, filename)
216
216
 
217
217
  if os.path.exists(filepath):
218
- LOG.info("Loading tabulation from %s", filepath)
219
- loaded_arrays = np.load(filepath)
220
- self.tabulated_r_range = loaded_arrays["r_range"]
221
- self.tabulated_z_range = loaded_arrays["z_range"]
222
- self.tabulated_integrals = loaded_arrays["values"]
223
-
224
- else:
225
- self._create_tabulation(tabulation_nr, tabulation_rmax,
226
- tabulation_nz, tabulation_zmin,
227
- tabulation_nb_integration_points)
228
- LOG.debug("Saving tabulation in %s", filepath)
229
- np.savez_compressed(
230
- filepath, r_range=self.tabulated_r_range, z_range=self.tabulated_z_range,
231
- values=self.tabulated_integrals
232
- )
218
+ try:
219
+ LOG.info("Loading tabulation from %s", filepath)
220
+ loaded_arrays = np.load(filepath)
221
+ self.tabulated_r_range = loaded_arrays["r_range"]
222
+ self.tabulated_z_range = loaded_arrays["z_range"]
223
+ self.tabulated_integrals = loaded_arrays["values"]
224
+ return filename
225
+ except (EOFError, FileNotFoundError, KeyError, ValueError):
226
+ LOG.warning("Error loading tabulation from %s", filepath)
227
+
228
+ self._create_tabulation(tabulation_nr, tabulation_rmax,
229
+ tabulation_nz, tabulation_zmin,
230
+ tabulation_nb_integration_points)
231
+ LOG.debug("Saving tabulation in %s", filepath)
232
+ np.savez_compressed(
233
+ filepath, r_range=self.tabulated_r_range, z_range=self.tabulated_z_range,
234
+ values=self.tabulated_integrals
235
+ )
236
+ return filename
233
237
 
234
238
  def _create_tabulation(self, tabulation_nr, tabulation_rmax,
235
239
  tabulation_nz, tabulation_zmin,
capytaine/io/xarray.py CHANGED
@@ -257,7 +257,7 @@ def hydrostatics_dataset(bodies: Sequence[FloatingBody]) -> xr.Dataset:
257
257
  if len(bodies_properties) > 0:
258
258
  bodies_properties = xr.concat(bodies_properties.values(), pd.Index(bodies_properties.keys(), name='body_name'))
259
259
  bodies_properties = _squeeze_dimensions(bodies_properties, dimensions=['body_name'])
260
- dataset = xr.merge([dataset, {body_property: bodies_properties}])
260
+ dataset = xr.merge([dataset, {body_property: bodies_properties}], compat="no_conflicts", join="outer")
261
261
  return dataset
262
262
 
263
263
 
@@ -416,7 +416,7 @@ def assemble_dataset(results,
416
416
  variables=['added_mass', 'radiation_damping'],
417
417
  dimensions=[main_freq_type, 'radiating_dof', 'influenced_dof'],
418
418
  optional_dims=optional_dims + ['wave_direction'])
419
- dataset = xr.merge([dataset, radiation_cases])
419
+ dataset = xr.merge([dataset, radiation_cases], compat="no_conflicts", join="outer")
420
420
 
421
421
  # DIFFRACTION RESULTS
422
422
  if "DiffractionResult" in kinds_of_results:
@@ -425,7 +425,7 @@ def assemble_dataset(results,
425
425
  variables=['diffraction_force', 'Froude_Krylov_force'],
426
426
  dimensions=[main_freq_type, 'wave_direction', 'influenced_dof'],
427
427
  optional_dims=optional_dims)
428
- dataset = xr.merge([dataset, diffraction_cases])
428
+ dataset = xr.merge([dataset, diffraction_cases], compat="no_conflicts", join="outer")
429
429
  dataset['excitation_force'] = dataset['Froude_Krylov_force'] + dataset['diffraction_force']
430
430
 
431
431
  # OTHER FREQUENCIES TYPES
@@ -519,7 +519,7 @@ def assemble_dataset(results,
519
519
  LOG.warning('Bemio data import being used, hydrostatics=True is ignored.')
520
520
  else:
521
521
  bodies = list({result.body for result in results})
522
- dataset = xr.merge([dataset, hydrostatics_dataset(bodies)])
522
+ dataset = xr.merge([dataset, hydrostatics_dataset(bodies)], compat="no_conflicts", join="outer")
523
523
 
524
524
  for var in set(dataset) | set(dataset.coords):
525
525
  if var in VARIABLES_ATTRIBUTES:
@@ -223,8 +223,16 @@ class CollectionOfMeshes(ClippableMixin, SurfaceIntegralsMixin, Abstract3DObject
223
223
  # Transformation #
224
224
  ##################
225
225
 
226
- def join_meshes(*meshes, name=None):
227
- return CollectionOfMeshes(meshes, name=name)
226
+ def join_meshes(*meshes, name=None, return_masks=False):
227
+ coll = CollectionOfMeshes(meshes, name=name)
228
+ if return_masks:
229
+ masks = []
230
+ for i_mesh in range(len(meshes)):
231
+ mask = np.full((coll.nb_faces,), False)
232
+ mask[coll.indices_of_mesh(i_mesh)] = True
233
+ masks.append(mask)
234
+ return coll, masks
235
+ return coll
228
236
 
229
237
  def __add__(self, mesh_to_add):
230
238
  return self.join_meshes(mesh_to_add)
@@ -30,7 +30,7 @@ class MeshLike(Protocol):
30
30
  def extract_faces(self, faces_id):
31
31
  ...
32
32
 
33
- def join_meshes(*meshes):
33
+ def join_meshes(*meshes, return_mask):
34
34
  ...
35
35
 
36
36
  def with_normal_vector_going_down(self, **kwargs):
@@ -644,9 +644,18 @@ class Mesh(ClippableMixin, SurfaceIntegralsMixin, Abstract3DObject):
644
644
  # Combine meshes #
645
645
  ####################
646
646
 
647
- def join_meshes(*meshes, name=None):
647
+ def join_meshes(*meshes, name=None, return_masks=False):
648
648
  from capytaine.meshes.collections import CollectionOfMeshes
649
- return CollectionOfMeshes(meshes, name=name).merged()
649
+ coll = CollectionOfMeshes(meshes, name=name)
650
+ if return_masks:
651
+ masks = []
652
+ for i_mesh in range(len(meshes)):
653
+ mask = np.full((coll.nb_faces,), False)
654
+ mask[coll.indices_of_mesh(i_mesh)] = True
655
+ masks.append(mask)
656
+ return coll.merged(), masks
657
+ else:
658
+ return coll.merged()
650
659
 
651
660
  def __add__(self, mesh_to_add) -> 'Mesh':
652
661
  return self.join_meshes(mesh_to_add)
@@ -84,13 +84,27 @@ class ReflectionSymmetricMesh(SymmetricMesh):
84
84
  def __deepcopy__(self, *args):
85
85
  return ReflectionSymmetricMesh(self.half.copy(), self.plane, name=self.name)
86
86
 
87
- def join_meshes(*meshes, name=None):
87
+ def join_meshes(*meshes, name=None, return_masks=False):
88
88
  assert all(isinstance(mesh, ReflectionSymmetricMesh) for mesh in meshes), \
89
89
  "Only meshes with the same symmetry can be joined together."
90
90
  assert all(meshes[0].plane == mesh.plane for mesh in meshes), \
91
91
  "Only reflection symmetric meshes with the same reflection plane can be joined together."
92
- half_mesh = meshes[0].half.join_meshes(*(mesh.half for mesh in meshes[1:]), name=f"half_of_{name}" if name is not None else None)
93
- return ReflectionSymmetricMesh(half_mesh, plane=meshes[0].plane, name=name)
92
+ if not return_masks:
93
+ name = name=f"half_of_{name}" if name is not None else None
94
+ half_mesh = meshes[0].half.join_meshes(
95
+ *(mesh.half for mesh in meshes[1:]),
96
+ name=name, return_masks=False
97
+ )
98
+ return ReflectionSymmetricMesh(half_mesh, plane=meshes[0].plane, name=name)
99
+ else:
100
+ name = name=f"half_of_{name}" if name is not None else None
101
+ half_mesh, half_masks = meshes[0].half.join_meshes(
102
+ *(mesh.half for mesh in meshes[1:]),
103
+ name=name, return_masks=True
104
+ )
105
+ masks = [np.concatenate([half_mask, half_mask]) for half_mask in half_masks]
106
+ joined = ReflectionSymmetricMesh(half_mesh, plane=meshes[0].plane, name=name)
107
+ return joined, masks
94
108
 
95
109
  @inplace_transformation
96
110
  def translate(self, vector):
@@ -203,15 +217,43 @@ class TranslationalSymmetricMesh(SymmetricMesh):
203
217
  CollectionOfMeshes.mirror(self, plane)
204
218
  return self
205
219
 
206
- def join_meshes(*meshes, name=None):
220
+ def join_meshes(*meshes, name=None, return_masks=False):
207
221
  assert all(isinstance(mesh, TranslationalSymmetricMesh) for mesh in meshes), \
208
222
  "Only meshes with the same symmetry can be joined together."
209
223
  assert all(np.allclose(meshes[0].translation, mesh.translation) for mesh in meshes), \
210
224
  "Only translation symmetric meshes with the same translation vector can be joined together."
211
225
  assert all(len(meshes[0]) == len(mesh) for mesh in meshes), \
212
226
  "Only symmetric meshes with the same number of elements can be joined together."
213
- mesh_strip = CollectionOfMeshes([mesh.first_slice for mesh in meshes], name=f"strip_of_{name}" if name is not None else None)
214
- return TranslationalSymmetricMesh(mesh_strip, translation=meshes[0].translation, nb_repetitions=len(meshes[0]) - 1, name=name)
227
+ if not return_masks:
228
+ strip_name = f"strip_of_{name}" if name is not None else None
229
+ mesh_strip = meshes[0].first_slice.join_meshes(
230
+ *(mesh.first_slice for mesh in meshes[1:]),
231
+ name=strip_name,
232
+ return_masks=False
233
+ )
234
+ return TranslationalSymmetricMesh(
235
+ mesh_strip,
236
+ translation=meshes[0].translation,
237
+ nb_repetitions=len(meshes[0]) - 1,
238
+ name=name
239
+ )
240
+ else:
241
+ strip_name = f"strip_of_{name}" if name is not None else None
242
+ mesh_strip, strip_masks = meshes[0].first_slice.join_meshes(
243
+ *(mesh.first_slice for mesh in meshes[1:]),
244
+ name=strip_name,
245
+ return_masks=True
246
+ )
247
+ joined = TranslationalSymmetricMesh(
248
+ mesh_strip,
249
+ translation=meshes[0].translation,
250
+ nb_repetitions=len(meshes[0]) - 1,
251
+ name=name
252
+ )
253
+ masks = [np.concatenate([
254
+ strip_mask for _ in range(len(meshes[0]))
255
+ ]) for strip_mask in strip_masks]
256
+ return joined, masks
215
257
 
216
258
 
217
259
  def build_regular_array_of_meshes(base_mesh, distance, nb_bodies):
@@ -363,15 +405,43 @@ class AxialSymmetricMesh(SymmetricMesh):
363
405
  def __deepcopy__(self, *args):
364
406
  return AxialSymmetricMesh(self.first_slice.copy(), axis=self.axis.copy(), nb_repetitions=len(self) - 1, name=self.name)
365
407
 
366
- def join_meshes(*meshes, name=None):
408
+ def join_meshes(*meshes, name=None, return_masks=False):
367
409
  assert all(isinstance(mesh, AxialSymmetricMesh) for mesh in meshes), \
368
410
  "Only meshes with the same symmetry can be joined together."
369
411
  assert all(meshes[0].axis == mesh.axis for mesh in meshes), \
370
412
  "Only axisymmetric meshes with the same symmetry axis can be joined together."
371
413
  assert all(len(meshes[0]) == len(mesh) for mesh in meshes), \
372
414
  "Only axisymmetric meshes with the same number of elements can be joined together."
373
- mesh_slice = CollectionOfMeshes([mesh.first_slice for mesh in meshes], name=f"slice_of_{name}" if name is not None else None)
374
- return AxialSymmetricMesh(mesh_slice, axis=meshes[0].axis, nb_repetitions=len(meshes[0]) - 1, name=name)
415
+ if not return_masks:
416
+ slice_name = f"slice_of_{name}" if name is not None else None
417
+ mesh_slice = meshes[0].first_slice.join_meshes(
418
+ *(mesh.first_slice for mesh in meshes[1:]),
419
+ name=slice_name,
420
+ return_masks=False
421
+ )
422
+ return AxialSymmetricMesh(
423
+ mesh_slice,
424
+ axis=meshes[0].axis,
425
+ nb_repetitions=len(meshes[0]) - 1,
426
+ name=name
427
+ )
428
+ else:
429
+ slice_name = f"slice_of_{name}" if name is not None else None
430
+ mesh_slice, slice_masks = meshes[0].first_slice.join_meshes(
431
+ *(mesh.first_slice for mesh in meshes[1:]),
432
+ name=slice_name,
433
+ return_masks=True
434
+ )
435
+ joined = AxialSymmetricMesh(
436
+ mesh_slice,
437
+ axis=meshes[0].axis,
438
+ nb_repetitions=len(meshes[0]) - 1,
439
+ name=name
440
+ )
441
+ masks = [np.concatenate([
442
+ slice_mask for _ in range(len(meshes[0]))
443
+ ]) for slice_mask in slice_masks]
444
+ return joined, masks
375
445
 
376
446
  @inplace_transformation
377
447
  def translate(self, vector):
@@ -11,7 +11,6 @@ output of the form `SymbolicMultiplication("0", np.array(...))`
11
11
  import numpy as np
12
12
  from functools import wraps, total_ordering
13
13
 
14
- @total_ordering
15
14
  class SymbolicMultiplication:
16
15
  def __init__(self, symbol, value=1.0):
17
16
  self.symbol = symbol
@@ -82,11 +81,26 @@ class SymbolicMultiplication:
82
81
  def __getitem__(self, item):
83
82
  return SymbolicMultiplication(self.symbol, self.value[item])
84
83
 
85
- def __eq__(self, x):
86
- return float(self) == x
84
+ def __setitem__(self, item, val):
85
+ if isinstance(val, SymbolicMultiplication) and self.symbol == val.symbol:
86
+ self.value.__setitem__(item, val.value)
87
+ else:
88
+ raise NotImplementedError
87
89
 
88
90
  def __lt__(self, x):
89
- return float(self) < x
91
+ return self._concretize() < x
92
+
93
+ def __le__(self, x):
94
+ return self._concretize() <= x
95
+
96
+ def __eq__(self, x):
97
+ return self._concretize() == x
98
+
99
+ def __ge__(self, x):
100
+ return self._concretize() >= x
101
+
102
+ def __gt__(self, x):
103
+ return self._concretize() > x
90
104
 
91
105
  def __hash__(self):
92
106
  return hash((self.symbol, self.value))
capytaine/tools/timer.py CHANGED
@@ -8,22 +8,24 @@ class Timer:
8
8
 
9
9
  Example
10
10
  -------
11
- timer = Timer()
12
- with timer:
13
- sleep(1.0)
11
+ ::
14
12
 
15
- print(timer.total) # 1.0...
13
+ timer = Timer()
14
+ with timer:
15
+ sleep(1.0)
16
16
 
17
- @timer.wraps_function
18
- def my_function():
19
- sleep(0.5)
17
+ print(timer.total) # 1.0...
20
18
 
21
- my_function()
22
- print(timer.total) # 1.5...
23
- my_function()
24
- print(timer.total) # 2.0...
19
+ @timer.wraps_function
20
+ def my_function():
21
+ sleep(0.5)
25
22
 
26
- print(timer.timings) # [1.0, 0.5, 0.5]
23
+ my_function()
24
+ print(timer.total) # 1.5...
25
+ my_function()
26
+ print(timer.total) # 2.0...
27
+
28
+ print(timer.timings) # [1.0, 0.5, 0.5]
27
29
  """
28
30
 
29
31
  def __init__(self, timings=None):
@@ -0,0 +1,2 @@
1
+ Version: 1.11.2
2
+ Arguments: ['C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-f4_ko6cf\\cp312-win_amd64\\build\\venv\\Scripts\\delvewheel', 'repair', '-w', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-f4_ko6cf\\cp312-win_amd64\\repaired_wheel', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-f4_ko6cf\\cp312-win_amd64\\built_wheel\\capytaine-2.3.1-cp312-cp312-win_amd64.whl', '--no-mangle-all']
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: capytaine
3
- Version: 2.3
3
+ Version: 2.3.1
4
4
  Summary: Python BEM solver for linear potential flow, based on Nemoh
5
5
  Author-Email: Matthieu Ancellin <matthieu.ancellin@mews-labs.com>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -689,7 +689,7 @@ Requires-Python: >=3.8
689
689
  Requires-Dist: numpy>=1.20; python_version >= "3.9"
690
690
  Requires-Dist: numpy>=1.24; python_version == "3.8"
691
691
  Requires-Dist: scipy
692
- Requires-Dist: pandas>=1.3
692
+ Requires-Dist: pandas<3,>=1.3
693
693
  Requires-Dist: xarray
694
694
  Requires-Dist: rich
695
695
  Provides-Extra: optional
@@ -698,17 +698,6 @@ Requires-Dist: joblib>=1.3; extra == "optional"
698
698
  Requires-Dist: meshio; extra == "optional"
699
699
  Requires-Dist: netcdf4; extra == "optional"
700
700
  Requires-Dist: vtk; extra == "optional"
701
- Provides-Extra: more-optional
702
- Requires-Dist: pygmsh; extra == "more-optional"
703
- Requires-Dist: gmsh; extra == "more-optional"
704
- Provides-Extra: test
705
- Requires-Dist: pytest; extra == "test"
706
- Requires-Dist: capytaine[optional]; extra == "test"
707
- Provides-Extra: docs
708
- Requires-Dist: sphinx; extra == "docs"
709
- Requires-Dist: sphinx-toolbox; extra == "docs"
710
- Requires-Dist: sphinxcontrib-proof; extra == "docs"
711
- Requires-Dist: sphinxcontrib-mermaid; extra == "docs"
712
701
  Description-Content-Type: text/markdown
713
702
 
714
703
  # Capytaine: a linear potential flow BEM solver with Python.
@@ -1,11 +1,11 @@
1
- capytaine/__about__.py,sha256=LRZ6r4hFLAiFQOnekKww3qXw0AwGCtRHyfduv0eZKcc,429
2
- capytaine/__init__.py,sha256=BHnatA7zRAuTQpRuNgHp9cx0WwXmHV1qkT9ev98eUzk,2184
1
+ capytaine/__about__.py,sha256=OCkVmS8l1azFK-SbX6-WSZiZEozXQVZyU5MkvgrZiq0,431
2
+ capytaine/__init__.py,sha256=zj_J7weaxC7WkSUov6RcQftY-JLZUu9iaZ5cdWBibGk,2184
3
3
  capytaine/bem/airy_waves.py,sha256=vap1Qmdo-m1lZ-WLj_5TJY2v3_bNJNtJ_04OkJX83fA,3609
4
4
  capytaine/bem/engines.py,sha256=8ShZTaYTYUKSQwt_sHwWH8BfBlt1G0RkDM3mSfuyeE4,18511
5
- capytaine/bem/problems_and_results.py,sha256=j3xdiKZ77fvTMQ8l_JyArTPtcZ284IX1dxgciVbuDZg,27632
6
- capytaine/bem/solver.py,sha256=e1oHAC8c6paOMpeClg34zA3II90Ao_Rzdx-uHIozr1E,29389
5
+ capytaine/bem/problems_and_results.py,sha256=_DirKZ-Wo6-Bs99Q9YuOB6W77eH1CaEzu7HiRli3-Ok,28030
6
+ capytaine/bem/solver.py,sha256=ha4psz3_B2s2RPNG3F0LQ4nEhdtaY__7Pf3SCxLgFak,29384
7
7
  capytaine/bem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- capytaine/bodies/bodies.py,sha256=kTPL3cyk47erZXaVAi9Z1Oqfz0Cfv_GjS9vZO0KqplI,53456
8
+ capytaine/bodies/bodies.py,sha256=Nm8pJ7qC6EWJWr0MgCCZ10N2Jox_u7P_WM8n4uy3igM,53929
9
9
  capytaine/bodies/dofs.py,sha256=CCGNYqilJE6eppyKxiF_712Vc5iCkbbbrRFCZwvKLdY,617
10
10
  capytaine/bodies/__init__.py,sha256=1157LRyNMo7TFZOMvlsC7NPPSMflsZVPfMxeLyNUQkU,161
11
11
  capytaine/bodies/predefined/cylinders.py,sha256=1F9aLXp5ZzUcdo0_xncIliNIK3KAIFMc2XspjfWPh-k,5747
@@ -13,7 +13,7 @@ capytaine/bodies/predefined/rectangles.py,sha256=4iHUNJO_5oX8Xfhj2zTg4mIbOu7Myab
13
13
  capytaine/bodies/predefined/spheres.py,sha256=vHCuB9wq7Fkgx62tYSSpxqo8mgNna49nAQ_bS4GcfAI,2668
14
14
  capytaine/bodies/predefined/__init__.py,sha256=oXMF4lq-wIWO5IWtUt4ZywVAGIi926zYTUz2j_iogT4,344
15
15
  capytaine/green_functions/abstract_green_function.py,sha256=PjV2qANb71JEK1YI1GPCF4_2UmBZLN7YCKllvMP6ELY,2898
16
- capytaine/green_functions/delhommeau.py,sha256=CwLaP2r-qaEZeAr0LaLJL7Hdt4cCGLF_QITsQ27jjcA,23860
16
+ capytaine/green_functions/delhommeau.py,sha256=OhVs6LujvB3ohvhxXCPdr91byDP7mU75XYGoVpTjdwE,24057
17
17
  capytaine/green_functions/hams.py,sha256=MS04A6ucbxk7tqGcgrihthbz1Uj4jpL1B4LvdN0C-jc,8456
18
18
  capytaine/green_functions/__init__.py,sha256=Rvl4Xv0MbD9NOpcnYkiSpeD097l_SQX8C5r-9CvdIZs,109
19
19
  capytaine/green_functions/FinGreen3D/.gitignore,sha256=IxYDvaMqbeEuzSKLq9nRgJIH2AtjPp-ugUuPMhlNirE,8
@@ -25,13 +25,13 @@ capytaine/green_functions/FinGreen3D/test_program.f90,sha256=JYDnew3326C_hCZISpW
25
25
  capytaine/green_functions/LiangWuNoblesse/.gitignore,sha256=IxYDvaMqbeEuzSKLq9nRgJIH2AtjPp-ugUuPMhlNirE,8
26
26
  capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90,sha256=BYaVrslAbglcI-7-kOz7qH3AQKLY4rvCmXaa7zfDCaM,22552
27
27
  capytaine/green_functions/LiangWuNoblesse/LICENSE,sha256=f_4ZVFh8d9-6HPjrmy6nQ2cfpuY_nnovJYEZ1C4U7v4,27030
28
- capytaine/green_functions/LiangWuNoblesse/Makefile,sha256=25uL3q1VNE9ladcJf9CWMHJ1j2nm8klpKQ-uFEUWctQ,431
28
+ capytaine/green_functions/LiangWuNoblesse/Makefile,sha256=tnPiOa2ZWD5db2cb9fJA8sqB1tcAtLN4UiV7ElPFpOQ,427
29
29
  capytaine/green_functions/LiangWuNoblesse/README.md,sha256=mrO9uR0UcNbDOXRjNwahU7AIto-DXHXmNiA5gJ1jKpk,104
30
30
  capytaine/green_functions/LiangWuNoblesse/test_program.f90,sha256=xBkCHsS17Mik7IKgTKRTZNz4EwQcPgnJM1WSmopEWqQ,522
31
- capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.dll.a,sha256=r4wFk6iDdip4yxlHygfmJqe6p0guEyOaQlgwjTOI0eo,1886
32
- capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.pyd,sha256=zIjB4QCK0bYLHphVVU8SPimtJ2qSowmtj2abcG-DYHc,424875
33
- capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.dll.a,sha256=42MxooO3YY0nvXEcAegQec1jbTU71E5tnqWgOcTXg1g,1886
34
- capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.pyd,sha256=Wxprjr_sm1_CQIhJiS-17wYlEsDVgiaQgq5W6I1KDEU,483290
31
+ capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.dll.a,sha256=V9sEqHh7XTVEOlflKiG_0n8ehCcUyox9bCUXxWrU89w,1886
32
+ capytaine/green_functions/libs/Delhommeau_float32.cp312-win_amd64.pyd,sha256=2LgPWI_EDaRGUETyJDZiN8yWmJdRaZKL-2rMP2jT2F8,424875
33
+ capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.dll.a,sha256=kFZZDMyRRLLoB3Vl7TvYpzrJkDXrUdUilcLox2etZ0o,1886
34
+ capytaine/green_functions/libs/Delhommeau_float64.cp312-win_amd64.pyd,sha256=G2CdpA96yg4S-4TFEevcpFTMFxxUSceqzXBes8CmS4w,483290
35
35
  capytaine/green_functions/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  capytaine/io/bemio.py,sha256=_UKSNaI-uuT3ICSEpBRSHhWqN3cFjuBab2t-EJLRtxU,7487
37
37
  capytaine/io/legacy.py,sha256=YwVxJKzofVyTshOcb84wr1l0Q2W4USeJNKau5PSBx5o,15058
@@ -39,7 +39,7 @@ capytaine/io/meshio.py,sha256=bu575xBYbl_7VOUwJz7cvtEPe1twYud2hZDWlbX3jjg,1507
39
39
  capytaine/io/mesh_loaders.py,sha256=5Zb33dgfEZ2B-3SzbMML__N8yGfpbXDDgwuh6Fd561M,32857
40
40
  capytaine/io/mesh_writers.py,sha256=pk88khE-8uXFJj1jmy80C6-saVn8-B7GohSmCWtco9k,21776
41
41
  capytaine/io/wamit.py,sha256=ZCYQBPa2vBWLadtZP9Gkvrq_GpYdhxs4ekPLFDHTHRQ,16507
42
- capytaine/io/xarray.py,sha256=g0wNvPqvfP6ZqPscKmqDCmyafBdZg5HapXsfEMa67MA,27577
42
+ capytaine/io/xarray.py,sha256=9vXThds5aWpfdwBsbXJyXe7-pC-ghmNUYkHlhJGKq_U,27725
43
43
  capytaine/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
44
  capytaine/matrices/block.py,sha256=Kqsyx1NkFyvwGuNB5Ws-UW5tcMa6pAYDfs6BfiVO0Tw,26078
45
45
  capytaine/matrices/block_toeplitz.py,sha256=2G6Hg3cY6nhAsGPpz84utaXKPd0rALdRtGH9MQyd7LQ,13255
@@ -48,15 +48,15 @@ capytaine/matrices/linear_solvers.py,sha256=yobnf7afu7a5Sgby9z8ZcHAjSRlQxVQj7a4Q
48
48
  capytaine/matrices/low_rank.py,sha256=ftWVq35dP-9fNZcqMU6FOXyQcrg_3-0u3ba7g1oW0Oo,16391
49
49
  capytaine/matrices/__init__.py,sha256=BYCiuVbu4sp3Z6mdbK5uTphUTalvaLhHX1aPLljlsRA,720
50
50
  capytaine/meshes/clipper.py,sha256=3C1vxe6mlAYdv0uvtvc3ZA_Lb43ks7UZmDZ1mE9ImRc,19142
51
- capytaine/meshes/collections.py,sha256=8El0zPaUIWbGu_hoqo_CNIv_rbuLfO77AaxNmTr3R7c,11423
51
+ capytaine/meshes/collections.py,sha256=qD_guE5cTAQKvF6wBbtVyyatVa3wwWvf8mJI2qVFThA,11745
52
52
  capytaine/meshes/geometry.py,sha256=QSowVTd4dva0pe4osfFZj0giaL-7Dj-T3wdVZ4k-Clg,14516
53
- capytaine/meshes/meshes.py,sha256=-avX1RpGhCp2rLyNtuC7kSBSivjpaguV_K_9x4LfUN8,33165
54
- capytaine/meshes/mesh_like_protocol.py,sha256=ACIwdvJO_qK6wwvbXUT8s5EoHAIUWWJNoBpDrR_3WCY,1066
53
+ capytaine/meshes/meshes.py,sha256=irSdVC2cG68d-DcM56cFN3BmX4-k-4hcpCqTj7kO9aw,33515
54
+ capytaine/meshes/mesh_like_protocol.py,sha256=QdL4uYjfq4-DckrJfE_8PiEhTUAjilJwtW1IeaDKBGg,1079
55
55
  capytaine/meshes/properties.py,sha256=zNnQCTAMReiJDMguU9pPwca_Zj_NDTTRqT-uVgABI0E,11066
56
56
  capytaine/meshes/quadratures.py,sha256=j6waiQlEoRfzUsnTL2dQg9Ynq5WYkwZT7vV8KOCwN4E,3307
57
57
  capytaine/meshes/quality.py,sha256=YVS294DJCTEyB9qGXEP56h9yqxjWIl6hg8P0QI2msIo,14831
58
58
  capytaine/meshes/surface_integrals.py,sha256=7s_LOtyz2I1SFFsUE1YMoeSR-02MsocRb8AJS6hTEjc,2326
59
- capytaine/meshes/symmetric.py,sha256=_yQ8iRiCooFtvH6ryoOUYv0nIbutYiz5atU2rD8USIM,16089
59
+ capytaine/meshes/symmetric.py,sha256=fFN0Pv8BxixSJRatl7KJBSE2RN7i8GAFugvRyQ79vUM,18701
60
60
  capytaine/meshes/__init__.py,sha256=FKeQT_I3TAb9iHNqJi0qf9HPo_O001P4fXhZQZ8Oj50,367
61
61
  capytaine/meshes/predefined/cylinders.py,sha256=r2UC8uMb60QyyUBaMEvCEkJ9EmazZvDnO-p0GsS2Us8,15160
62
62
  capytaine/meshes/predefined/rectangles.py,sha256=wX0vtY8YLMmJ3UZk2oi7q5eKakDnULCXxMhO1KC8eC8,12555
@@ -73,8 +73,8 @@ capytaine/tools/lists_of_points.py,sha256=OOCZkFBsPZj25KGYAvX2BhVLNnxbR-1lT3BSoE
73
73
  capytaine/tools/lru_cache.py,sha256=OH1J6XhXyKQGKfDhngBne_D_C2Jub3g92Y5JWWcN4ik,1758
74
74
  capytaine/tools/optional_imports.py,sha256=L2_6h1My2jjl7GHL0_hmHsjOE8hRWFrs0eiq_OIDTH8,887
75
75
  capytaine/tools/prony_decomposition.py,sha256=_iqHEhop8oBREz0zY35WXV-UkPw1QHbQhP6L_BrtCQM,5297
76
- capytaine/tools/symbolic_multiplication.py,sha256=MQLsbAfQcWEn7YgcSNRhBmHMRRXY_8wA9Okt4IGaDmI,4560
77
- capytaine/tools/timer.py,sha256=Ch47sRiDcOF-EcVrdM7Eyv4Lch2wqf2eQpIXNgHENMY,1528
76
+ capytaine/tools/symbolic_multiplication.py,sha256=Aloloo9KEaPaQgmqUEFcYcTHQqy_gQSZHQsMJAMR5LA,4991
77
+ capytaine/tools/timer.py,sha256=VOte4SjqgvjUGiwhi3YalifFclZe2X_6VLvuecKofD4,1586
78
78
  capytaine/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
79
79
  capytaine/ui/cli.py,sha256=DLgsJdmMASM70BqN7bbNQxBkiHKReJDJqgf4E9mr_yk,825
80
80
  capytaine/ui/rich.py,sha256=kxI4CVa4ycJBloEHvLpLqrEArkLT4wAdcPKhbEw2hcY,238
@@ -84,12 +84,12 @@ capytaine/ui/vtk/body_viewer.py,sha256=1WGMjHBRhyGkCFxgvJKs_dY-eL2YCCKhqqehKgIww
84
84
  capytaine/ui/vtk/helpers.py,sha256=V1_DeB6svtTlzdNzdcL7-GGj5QvCW6wpVzhXVmpVlwI,2722
85
85
  capytaine/ui/vtk/mesh_viewer.py,sha256=V6ReLbsArkVAZRX6QZdqHhyo1dStT2ql8T2AzpP8HbA,15211
86
86
  capytaine/ui/vtk/__init__.py,sha256=mtXE0si8Fc8QGneQIQNdGPPzhRLNwi4bPMUmQ9Vs1io,164
87
- capytaine-2.3.dist-info/DELVEWHEEL,sha256=wLqEmWBECLItOZ_kx9BJQv6mBGXyIiOFTVa8M6AbvU0,419
88
- capytaine-2.3.dist-info/entry_points.txt,sha256=R72-je8lc6ELm8ftt7lJ7f1aalnQs5BWYrGDBMexHII,53
89
- capytaine-2.3.dist-info/LICENSE,sha256=Czg9WmPaZE9ijZnDOXbqZIftiaqlnwsyV5kt6sEXHms,35821
90
- capytaine-2.3.dist-info/METADATA,sha256=NSFNwYHZoOfMqn7if-xXY-r9qOLAGrlbUSG8qtlahy8,45516
91
- capytaine-2.3.dist-info/RECORD,,
92
- capytaine-2.3.dist-info/WHEEL,sha256=50PeAbplA6PkI0hYOYoeacB9US1R6EguyfOnsccH0WU,85
87
+ capytaine-2.3.1.dist-info/DELVEWHEEL,sha256=BIx_Bwuob1wkJAAid4pQ5MgSYbgcHYpURgKHT2fXRCE,421
88
+ capytaine-2.3.1.dist-info/entry_points.txt,sha256=R72-je8lc6ELm8ftt7lJ7f1aalnQs5BWYrGDBMexHII,53
89
+ capytaine-2.3.1.dist-info/LICENSE,sha256=Czg9WmPaZE9ijZnDOXbqZIftiaqlnwsyV5kt6sEXHms,35821
90
+ capytaine-2.3.1.dist-info/METADATA,sha256=ftEZnZzzOAlQ85oSpm66yuOls3Sh6ypK-bEYP3EcKME,45072
91
+ capytaine-2.3.1.dist-info/RECORD,,
92
+ capytaine-2.3.1.dist-info/WHEEL,sha256=50PeAbplA6PkI0hYOYoeacB9US1R6EguyfOnsccH0WU,85
93
93
  capytaine.libs/libgcc_s_seh-1.dll,sha256=q2m46g2pAq7jvn1d0qbVW6WqyOpxQ6KtnAdh5r3gCxY,111616
94
94
  capytaine.libs/libgfortran-5.dll,sha256=wLLASxjhj_hbogJghmWeKSyi6w4L9h8xR04-iS1Ejq4,3118080
95
95
  capytaine.libs/libgomp-1.dll,sha256=yCJD_z8GQ7Hi7iXgwG2hkjFAOqf-KeE45YnavaKCpf8,280576
@@ -1,2 +0,0 @@
1
- Version: 1.10.1
2
- Arguments: ['C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-9rerwt60\\cp312-win_amd64\\build\\venv\\Scripts\\delvewheel', 'repair', '-w', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-9rerwt60\\cp312-win_amd64\\repaired_wheel', 'C:\\Users\\runneradmin\\AppData\\Local\\Temp\\cibw-run-9rerwt60\\cp312-win_amd64\\built_wheel\\capytaine-2.3-cp312-cp312-win_amd64.whl', '--no-mangle-all']