capytaine 2.3__cp38-cp38-macosx_13_0_x86_64.whl → 2.3.1__cp38-cp38-macosx_13_0_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.
Binary file
Binary file
Binary file
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"
@@ -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):
@@ -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,5 +1,5 @@
1
1
  capytaine/__init__.py,sha256=ffYPfnzVMU03arvItDaf5VoDa68KEGP4J9aE1MQlmQg,1822
2
- capytaine/__about__.py,sha256=di-zISnbYXwp9FpVIxlF_mgV6Ind8W8YBuMiy82ypCA,413
2
+ capytaine/__about__.py,sha256=14fwPZt3SRhKmIUSRPB6gpUnkNBLGgZLmq6_R2Xvy_k,415
3
3
  capytaine/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  capytaine/ui/rich.py,sha256=ZfMHUpCSVztNseIGpN2I69ts_Aw_HJ5RnZc0f73av5Q,233
5
5
  capytaine/ui/cli.py,sha256=o3MH2OCHXFww1kb2zM9R3qs4jjfkCeeZFRAgnFnb2NE,797
@@ -9,7 +9,7 @@ capytaine/ui/vtk/animation.py,sha256=FYH-YAu0LY2zr7fTl36aOSkM8z74_gxQRKOJFhUSluo
9
9
  capytaine/ui/vtk/helpers.py,sha256=sOK_a679a7n9ozhcEZY3IhTWmPyctoLkFwKTyzDHrm8,2640
10
10
  capytaine/ui/vtk/body_viewer.py,sha256=gGIla-gADWiYuiNdS2io-0whpO6AaH8A8KkEmqX4OSY,1032
11
11
  capytaine/green_functions/__init__.py,sha256=527Pd0SIqwR64-d4sT-_jyE89XU-PLgFL0et96ChAIo,107
12
- capytaine/green_functions/delhommeau.py,sha256=Z3lXv4MP1MPPJKmyISMVDqTQIpEHdroAl-OUjYJVE2w,23357
12
+ capytaine/green_functions/delhommeau.py,sha256=y9nkyVKj9ES0nL2jDLdx_5ejQ5nbMSKV0qYUnPnfTNg,23550
13
13
  capytaine/green_functions/hams.py,sha256=yxT0ysNFxsm4VbRtywHnhtWnHrxkU8q6_DL8eEwZPTs,8252
14
14
  capytaine/green_functions/abstract_green_function.py,sha256=6_YjjTKbYNgteWw4FWKQQI9nfpPzEETQxD3WOWFqosw,2834
15
15
  capytaine/green_functions/FinGreen3D/test_program.f90,sha256=BlQv3O0z0tYXejz261S8l7x5H01wHAdn9-YfsRurW1w,926
@@ -20,15 +20,15 @@ capytaine/green_functions/FinGreen3D/FinGreen3D.f90,sha256=tBsSc6BfQJpaFQ6j6tEYW
20
20
  capytaine/green_functions/FinGreen3D/.gitignore,sha256=GBMUBl3y8v2vkgsai1MR2qIWotZImgatpbScxRTYlBc,7
21
21
  capytaine/green_functions/LiangWuNoblesse/test_program.f90,sha256=cettkRXfJDmhigo7oUACjU3qCNFLJVDU0vI6Og4UFs8,494
22
22
  capytaine/green_functions/LiangWuNoblesse/LICENSE,sha256=IMF9i4xIpgCADf0U-V1cuf9HBmqWQd3qtI3FSuyW4zE,26526
23
- capytaine/green_functions/LiangWuNoblesse/Makefile,sha256=S0zjKvMQ9z2nWHEKNe-ES32LWyNI1_ogcJ6s9qVFEho,413
23
+ capytaine/green_functions/LiangWuNoblesse/Makefile,sha256=txvf2ppXhnT9OPDcE8zQcEq5jQcQ3B_A0ge1vdR6huA,411
24
24
  capytaine/green_functions/LiangWuNoblesse/README.md,sha256=0pQbZxIAWTc-9eQ2Qb62SfM5Eh3dNx0bPSznuOCx8xU,102
25
25
  capytaine/green_functions/LiangWuNoblesse/.gitignore,sha256=GBMUBl3y8v2vkgsai1MR2qIWotZImgatpbScxRTYlBc,7
26
26
  capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90,sha256=BYaVrslAbglcI-7-kOz7qH3AQKLY4rvCmXaa7zfDCaM,22552
27
- capytaine/green_functions/libs/Delhommeau_float64.cpython-38-darwin.so,sha256=20MVKC6HB72LdbrEUE0ok0SGQGUBsTCIcTJLgMswOsc,465904
28
- capytaine/green_functions/libs/Delhommeau_float32.cpython-38-darwin.so,sha256=1XYJ6lO6Kr5TzB5huYLPYWZXYwdEESju1gFzurSFRNU,412800
27
+ capytaine/green_functions/libs/Delhommeau_float64.cpython-38-darwin.so,sha256=ig5Ftsg-9km_wABbmDelvFjrZ4sBq73LA5f5-pce4NI,465904
28
+ capytaine/green_functions/libs/Delhommeau_float32.cpython-38-darwin.so,sha256=UXpvw50jmadyl7QIQW4t5-xgqxsQFvQab2RISqUMuZg,412800
29
29
  capytaine/green_functions/libs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  capytaine/bodies/dofs.py,sha256=M5nWTeVJxmxKl2BowOnrE3plv1rrqDHNb76D_qHroS8,598
31
- capytaine/bodies/bodies.py,sha256=w_2kx-8Hm9qDWI9Zl-RsQQQ9RHAqAZ0lldxSseL4OFw,52243
31
+ capytaine/bodies/bodies.py,sha256=KOBeLwpXDBQhZAjLePqXMQf8LcAl2TdOtYS_4rzIjMs,52708
32
32
  capytaine/bodies/__init__.py,sha256=wIYFs14NAWqaHLQWvDGUEZTBWp_kdthKkbOlXHup6LA,157
33
33
  capytaine/bodies/predefined/rectangles.py,sha256=PtNK7_RUjRIi1oJNlsBhOosC3Ib2cXX1SnW9llTmD44,4500
34
34
  capytaine/bodies/predefined/spheres.py,sha256=8lHMqCQBQneN8EqTSXQanumt6j5TeR70CR4ckrnDfo4,2598
@@ -36,17 +36,17 @@ capytaine/bodies/predefined/__init__.py,sha256=IA1y5XDGmyzNDpgQvz8kjyGajBCYoClAn
36
36
  capytaine/bodies/predefined/cylinders.py,sha256=Zfp3ecpKD72dfzv5Dd2y87EvDBBRsOJPq6GR6B76r5Y,5596
37
37
  capytaine/tools/lru_cache.py,sha256=ssPo7sZMMe15GIxPiQ7rA0GrjwYWsE66x3A-d-4FQTI,1709
38
38
  capytaine/tools/cache_on_disk.py,sha256=Cj2J5pNKw9PbIvxUn53swSmuGJoMibZzIvB5Skt52ig,912
39
- capytaine/tools/timer.py,sha256=3-PXNn6lMfbPP6z0HNCE9YcnIdrepzMHFd_CZ1F4aiM,1464
39
+ capytaine/tools/timer.py,sha256=0kEIvYFnwa0F4ayecxLl_VtiCrVL-8i9_NrAKrlSVmo,1520
40
40
  capytaine/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  capytaine/tools/deprecation_handling.py,sha256=_QFNrkreLerm3-LzRZ3l6B_O249PM-fCCAXMsHA7kIU,809
42
42
  capytaine/tools/optional_imports.py,sha256=HNjtvNZGxsw-eYmr4ejq001KhLevrvqq7ASAqTOw8W8,860
43
- capytaine/tools/symbolic_multiplication.py,sha256=Ef7oJftyAyw7kbPl5F4xD3YGDTWQFVNrdYCBii5e9po,4425
43
+ capytaine/tools/symbolic_multiplication.py,sha256=DCmVlUwGtyUBU7VZZ0xxNnIjNSC0rQbgSuHRnlFQ8VU,4842
44
44
  capytaine/tools/lists_of_points.py,sha256=6DyL9kr8jbkvB2IuCq288eSd4Xq6pwa8wiQCYZm9M1Q,1828
45
45
  capytaine/tools/prony_decomposition.py,sha256=Eg8CcedPuLKVUA-wpjwXBJsnXjBGZruHVy4jMU2cCSM,5147
46
- capytaine/bem/solver.py,sha256=KvDzuf4fOnUiklnBMutSWS-IoEd5ST-9BEXkVDdGiD0,28795
46
+ capytaine/bem/solver.py,sha256=j2ZoVGA8x46xQe61s1Dh0zCFVXnTDuehAKa3f3-bZ0o,28790
47
47
  capytaine/bem/engines.py,sha256=YauXkOHKLbrDbzM1qisKiJ1D3LZ0-ALOWIIRNzNchUU,18070
48
48
  capytaine/bem/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
- capytaine/bem/problems_and_results.py,sha256=X5va5A8dMCpXeuhAdDr_OWLYkI_KcerhLq99z-qkS20,27040
49
+ capytaine/bem/problems_and_results.py,sha256=4pdwswnrbp7D1v1xOnBA3aYSCxm5qiaFZDJt_u5BxaA,27430
50
50
  capytaine/bem/airy_waves.py,sha256=GAhX5xNEgjoOo2uEHXfKCxb2TnmbPBCqW6VWfvzJTM8,3498
51
51
  capytaine/io/wamit.py,sha256=dvmthwIZnzOM8L1kq814pilCpQPLeTHvjjgg21hV2po,16028
52
52
  capytaine/io/legacy.py,sha256=lARoaPGjTsUQ4YiLmD8ZYMSCU_UDmnOQx4_JppaCcRc,14730
@@ -55,18 +55,18 @@ capytaine/io/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  capytaine/io/mesh_loaders.py,sha256=NjSWrCR20ozIFu94B7ZveiSS1kzt-IWKoFnkvLHcNXU,31771
56
56
  capytaine/io/meshio.py,sha256=QmuHGJt_a1VDrCpA_OKVWftgHPdZyjNkao38QpGuPT8,1469
57
57
  capytaine/io/mesh_writers.py,sha256=zLHRdzTpbpXyPsf7c09s6Nk2ZXIAQCCfHYIF3vKKDBo,21084
58
- capytaine/io/xarray.py,sha256=LdbWiLAYqN9uz-TaYSqhVfSAKUnFnt2NmbJA4XUoO3Y,26909
59
- capytaine/.dylibs/libgfortran.5.dylib,sha256=vrn9LxAxYhy74BVfINa1ANs4zkvZq3LJR583KM3eBV4,3497360
60
- capytaine/.dylibs/libquadmath.0.dylib,sha256=yKg9ePtGRSTCvOoq-MKeXyL-KwJ5fFc7ber_FvOWU9I,381088
61
- capytaine/.dylibs/libgcc_s.1.1.dylib,sha256=TkxUgIZRQtgSBW5wG3sHiwurvUOrRHsQElu6_LTXlDI,244384
58
+ capytaine/io/xarray.py,sha256=IF-l5O9gGeBTRpcJontvvi11sYfgqwfK7wp1_MAtFHY,27057
59
+ capytaine/.dylibs/libgfortran.5.dylib,sha256=58lGzOQAJ8maiYrLh0oaYocIfJMrLQhHzo0HaPuJp54,3497360
60
+ capytaine/.dylibs/libquadmath.0.dylib,sha256=aU-tHcHpGTPL1MkPenAw_94eJx2POBThXvwMvrIaubE,381088
61
+ capytaine/.dylibs/libgcc_s.1.1.dylib,sha256=8NDI5rBKk_mhvebcgJkLy3WpXbzgBdVPMiqlgN4RrYo,244384
62
62
  capytaine/meshes/clipper.py,sha256=CB38_cmha8q6hnaxKukKQPtB7sXx34fU2HBujF8hD24,18677
63
63
  capytaine/meshes/properties.py,sha256=eJHhTtXzW-aiokuvluqLSfumAGMFZGmI3ZLP-pfVh2I,10790
64
- capytaine/meshes/symmetric.py,sha256=kK6eELnByoZZmkpziiJ_EJsOFc89MMQqAIG810V5VoI,15697
65
- capytaine/meshes/mesh_like_protocol.py,sha256=9D0PiJHPThc-eezgtJ2FBhxkw50d2sMIHLowA7LVUew,1029
64
+ capytaine/meshes/symmetric.py,sha256=CHBusSwTufKiGYOqVrUurQojYqlLsSWqxB-Z2kjVEYE,18239
65
+ capytaine/meshes/mesh_like_protocol.py,sha256=BxFLfJsHZFobyN5L0siuPRPq0DFpJbGsQw1yuFN06GQ,1042
66
66
  capytaine/meshes/surface_integrals.py,sha256=ihxbuiSsgep4rbrBQlq2q_2p_uDXDkRPyz0S6OVofc8,2263
67
67
  capytaine/meshes/__init__.py,sha256=5-AE32KOmOcq_F09uZanLafy7SzOe0-Cl6PaDbbOLMQ,361
68
- capytaine/meshes/meshes.py,sha256=GgxXIeVDxrZJ1G9CQqPgGpNToXWs4MJ9z_A_wSZGHrk,32284
69
- capytaine/meshes/collections.py,sha256=KAnGlw5VQZtAlKj15O_8jw0WUlrYmKiFgUkFVN8HYn8,11089
68
+ capytaine/meshes/meshes.py,sha256=_b0DtxR_UDmV0UOuB3bZ47ClGkIKJynTWESJxiIsbio,32625
69
+ capytaine/meshes/collections.py,sha256=uTXQovnoPsKZfl3HqUveHc94SyscyfELILikRuAcpG0,11403
70
70
  capytaine/meshes/geometry.py,sha256=ffeHvFzke3sXHzGexivRmSBQIOCk-pCMoveQF4eYyGM,14107
71
71
  capytaine/meshes/quality.py,sha256=OTZvqyDSJGKIHfFWwn-QROH1Je4PjgFxbwp3Ce-nzzI,14383
72
72
  capytaine/meshes/quadratures.py,sha256=eT5tsfonBJEDkrCnoUJbEPLX34I1rCkgzD_E6XhDu-E,3227
@@ -85,8 +85,8 @@ capytaine/matrices/linear_solvers.py,sha256=_5R-CR7eJ07Z3GcOd1YiX2bRyukuXQnHE0Dg
85
85
  capytaine/matrices/block_toeplitz.py,sha256=yL4GFPghfdVZTKtden0RKVDhpiBZz3D1oZ-pAVjDBjg,12930
86
86
  capytaine/matrices/__init__.py,sha256=_b868RYRI8ANHHf2PUVI-2_c0RdBfRDHLvJW5Uq1qys,704
87
87
  capytaine/matrices/block.py,sha256=9Gv800-regvNmD62-h9MvbW7vtPb4N-_3o8Y8HPnxgc,25486
88
- capytaine-2.3.dist-info/RECORD,,
89
- capytaine-2.3.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
90
- capytaine-2.3.dist-info/WHEEL,sha256=GvSWRiUfFrukiVvOyV_xTozA93yOU6whvfgQHhrp_b0,92
91
- capytaine-2.3.dist-info/entry_points.txt,sha256=R72-je8lc6ELm8ftt7lJ7f1aalnQs5BWYrGDBMexHII,53
92
- capytaine-2.3.dist-info/METADATA,sha256=NSFNwYHZoOfMqn7if-xXY-r9qOLAGrlbUSG8qtlahy8,45516
88
+ capytaine-2.3.1.dist-info/RECORD,,
89
+ capytaine-2.3.1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
90
+ capytaine-2.3.1.dist-info/WHEEL,sha256=GvSWRiUfFrukiVvOyV_xTozA93yOU6whvfgQHhrp_b0,92
91
+ capytaine-2.3.1.dist-info/entry_points.txt,sha256=R72-je8lc6ELm8ftt7lJ7f1aalnQs5BWYrGDBMexHII,53
92
+ capytaine-2.3.1.dist-info/METADATA,sha256=ftEZnZzzOAlQ85oSpm66yuOls3Sh6ypK-bEYP3EcKME,45072