capytaine 3.0.0a1__cp312-cp312-macosx_15_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.
- capytaine/.dylibs/libgcc_s.1.1.dylib +0 -0
- capytaine/.dylibs/libgfortran.5.dylib +0 -0
- capytaine/.dylibs/libquadmath.0.dylib +0 -0
- capytaine/__about__.py +21 -0
- capytaine/__init__.py +32 -0
- capytaine/bem/__init__.py +0 -0
- capytaine/bem/airy_waves.py +111 -0
- capytaine/bem/engines.py +321 -0
- capytaine/bem/problems_and_results.py +601 -0
- capytaine/bem/solver.py +718 -0
- capytaine/bodies/__init__.py +4 -0
- capytaine/bodies/bodies.py +630 -0
- capytaine/bodies/dofs.py +146 -0
- capytaine/bodies/hydrostatics.py +540 -0
- capytaine/bodies/multibodies.py +216 -0
- capytaine/green_functions/Delhommeau_float32.cpython-312-darwin.so +0 -0
- capytaine/green_functions/Delhommeau_float64.cpython-312-darwin.so +0 -0
- capytaine/green_functions/__init__.py +2 -0
- capytaine/green_functions/abstract_green_function.py +64 -0
- capytaine/green_functions/delhommeau.py +522 -0
- capytaine/green_functions/hams.py +210 -0
- capytaine/io/__init__.py +0 -0
- capytaine/io/bemio.py +153 -0
- capytaine/io/legacy.py +228 -0
- capytaine/io/wamit.py +479 -0
- capytaine/io/xarray.py +673 -0
- capytaine/meshes/__init__.py +2 -0
- capytaine/meshes/abstract_meshes.py +375 -0
- capytaine/meshes/clean.py +302 -0
- capytaine/meshes/clip.py +347 -0
- capytaine/meshes/export.py +89 -0
- capytaine/meshes/geometry.py +259 -0
- capytaine/meshes/io.py +433 -0
- capytaine/meshes/meshes.py +826 -0
- capytaine/meshes/predefined/__init__.py +6 -0
- capytaine/meshes/predefined/cylinders.py +280 -0
- capytaine/meshes/predefined/rectangles.py +202 -0
- capytaine/meshes/predefined/spheres.py +55 -0
- capytaine/meshes/quality.py +159 -0
- capytaine/meshes/surface_integrals.py +82 -0
- capytaine/meshes/symmetric_meshes.py +641 -0
- capytaine/meshes/visualization.py +353 -0
- capytaine/post_pro/__init__.py +6 -0
- capytaine/post_pro/free_surfaces.py +85 -0
- capytaine/post_pro/impedance.py +92 -0
- capytaine/post_pro/kochin.py +54 -0
- capytaine/post_pro/rao.py +60 -0
- capytaine/tools/__init__.py +0 -0
- capytaine/tools/block_circulant_matrices.py +275 -0
- capytaine/tools/cache_on_disk.py +26 -0
- capytaine/tools/deprecation_handling.py +18 -0
- capytaine/tools/lists_of_points.py +52 -0
- capytaine/tools/memory_monitor.py +45 -0
- capytaine/tools/optional_imports.py +27 -0
- capytaine/tools/prony_decomposition.py +150 -0
- capytaine/tools/symbolic_multiplication.py +161 -0
- capytaine/tools/timer.py +90 -0
- capytaine/ui/__init__.py +0 -0
- capytaine/ui/cli.py +28 -0
- capytaine/ui/rich.py +5 -0
- capytaine-3.0.0a1.dist-info/LICENSE +674 -0
- capytaine-3.0.0a1.dist-info/METADATA +755 -0
- capytaine-3.0.0a1.dist-info/RECORD +65 -0
- capytaine-3.0.0a1.dist-info/WHEEL +6 -0
- capytaine-3.0.0a1.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""This module is used for the handling of zero and infinite frequencies.
|
|
2
|
+
In this cases, the magnitudes that the solver has to manipulate are in the form of ω times a non-zero term.
|
|
3
|
+
Instead of evaluating this multiplication as zero of infinity, we keep it symbolic using the class defined here.
|
|
4
|
+
|
|
5
|
+
The frequency can be provided to the solver as something like
|
|
6
|
+
`SymbolicMultiplication("0", 1.0)` (that is zero) and the solver will return an
|
|
7
|
+
output of the form `SymbolicMultiplication("0", np.array(...))`
|
|
8
|
+
(that is also actually zero, except we may be intested in the non-zero array).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import numpy as np
|
|
12
|
+
from functools import wraps, total_ordering
|
|
13
|
+
|
|
14
|
+
class SymbolicMultiplication:
|
|
15
|
+
def __init__(self, symbol, value=1.0):
|
|
16
|
+
self.symbol = symbol
|
|
17
|
+
self.value = value
|
|
18
|
+
if hasattr(value, "shape"):
|
|
19
|
+
self.shape = value.shape # When wrapping Numpy arrays
|
|
20
|
+
|
|
21
|
+
def __format__(self, format_spec):
|
|
22
|
+
return f"{self.symbol}×{self.value.__format__(format_spec)}"
|
|
23
|
+
|
|
24
|
+
__array_priority__ = 1.0
|
|
25
|
+
|
|
26
|
+
def __array_function__(self, func, types, *args, **kwargs):
|
|
27
|
+
actual_args = args[0] # args = (actual_args, kwargs) for some reason
|
|
28
|
+
if func in {np.real, np.imag, np.sum} and len(actual_args) == 1 and len(kwargs) == 0:
|
|
29
|
+
return SymbolicMultiplication(self.symbol, func(self.value))
|
|
30
|
+
elif (
|
|
31
|
+
func in {np.einsum} and
|
|
32
|
+
len([a for a in actual_args if isinstance(a, SymbolicMultiplication)]) == 1 and
|
|
33
|
+
"out" not in kwargs
|
|
34
|
+
):
|
|
35
|
+
# Einsum with one of the array being wrapped in SymbolicMultiplication
|
|
36
|
+
unwrapped = [a.value if isinstance(a, SymbolicMultiplication) else a for a in actual_args]
|
|
37
|
+
return SymbolicMultiplication(self.symbol, func(*unwrapped, **kwargs))
|
|
38
|
+
else:
|
|
39
|
+
return NotImplemented
|
|
40
|
+
|
|
41
|
+
def astype(self, proper_type):
|
|
42
|
+
return SymbolicMultiplication(self.symbol, proper_type(self.value))
|
|
43
|
+
|
|
44
|
+
def __str__(self):
|
|
45
|
+
return f"{self.symbol}×{self.value}"
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
return f"SymbolicMultiplication(\"{self.symbol}\", {repr(self.value)})"
|
|
49
|
+
|
|
50
|
+
def __add__(self, x):
|
|
51
|
+
return self._concretize() + x
|
|
52
|
+
|
|
53
|
+
def __radd__(self, x):
|
|
54
|
+
return x + self._concretize()
|
|
55
|
+
|
|
56
|
+
def __neg__(self):
|
|
57
|
+
return SymbolicMultiplication(self.symbol, -self.value)
|
|
58
|
+
|
|
59
|
+
def __mul__(self, x):
|
|
60
|
+
return SymbolicMultiplication(self.symbol, self.value * x)
|
|
61
|
+
|
|
62
|
+
def __rmul__(self, x):
|
|
63
|
+
return SymbolicMultiplication(self.symbol, x * self.value)
|
|
64
|
+
|
|
65
|
+
def __pow__(self, n):
|
|
66
|
+
if n == 2:
|
|
67
|
+
return self * self
|
|
68
|
+
else:
|
|
69
|
+
raise NotImplementedError
|
|
70
|
+
|
|
71
|
+
def __truediv__(self, x):
|
|
72
|
+
if hasattr(x, 'symbol') and self.symbol == x.symbol:
|
|
73
|
+
return self.value / x.value
|
|
74
|
+
else:
|
|
75
|
+
return SymbolicMultiplication(self.symbol, self.value / x)
|
|
76
|
+
|
|
77
|
+
def __rtruediv__(self, x):
|
|
78
|
+
if hasattr(x, 'symbol') and self.symbol == x.symbol:
|
|
79
|
+
return x.value / self.value
|
|
80
|
+
elif self.symbol == "0":
|
|
81
|
+
return SymbolicMultiplication("∞", x/self.value)
|
|
82
|
+
elif self.symbol == "∞":
|
|
83
|
+
return SymbolicMultiplication("0", x/self.value)
|
|
84
|
+
else:
|
|
85
|
+
raise NotImplementedError
|
|
86
|
+
|
|
87
|
+
def __matmul__(self, x):
|
|
88
|
+
return SymbolicMultiplication(self.symbol, self.value @ x)
|
|
89
|
+
|
|
90
|
+
def __rmatmul__(self, x):
|
|
91
|
+
return SymbolicMultiplication(self.symbol, x @ self.value)
|
|
92
|
+
|
|
93
|
+
def __getitem__(self, item):
|
|
94
|
+
return SymbolicMultiplication(self.symbol, self.value[item])
|
|
95
|
+
|
|
96
|
+
def __setitem__(self, item, val):
|
|
97
|
+
if isinstance(val, SymbolicMultiplication) and self.symbol == val.symbol:
|
|
98
|
+
self.value.__setitem__(item, val.value)
|
|
99
|
+
else:
|
|
100
|
+
raise NotImplementedError
|
|
101
|
+
|
|
102
|
+
def __lt__(self, x):
|
|
103
|
+
return self._concretize() < x
|
|
104
|
+
|
|
105
|
+
def __le__(self, x):
|
|
106
|
+
return self._concretize() <= x
|
|
107
|
+
|
|
108
|
+
def __eq__(self, x):
|
|
109
|
+
return self._concretize() == x
|
|
110
|
+
|
|
111
|
+
def __ge__(self, x):
|
|
112
|
+
return self._concretize() >= x
|
|
113
|
+
|
|
114
|
+
def __gt__(self, x):
|
|
115
|
+
return self._concretize() > x
|
|
116
|
+
|
|
117
|
+
def __hash__(self):
|
|
118
|
+
return hash((self.symbol, self.value))
|
|
119
|
+
|
|
120
|
+
def _concretize(self):
|
|
121
|
+
if isinstance(self.value, np.ndarray):
|
|
122
|
+
if self.symbol == "0":
|
|
123
|
+
return np.zeros_like(self.value)
|
|
124
|
+
elif self.symbol == "∞":
|
|
125
|
+
return np.full_like(self.value, np.inf)
|
|
126
|
+
else:
|
|
127
|
+
return float(self)
|
|
128
|
+
|
|
129
|
+
def __float__(self):
|
|
130
|
+
if self.symbol == "0":
|
|
131
|
+
return 0.0 * float(self.value)
|
|
132
|
+
elif self.symbol == "∞":
|
|
133
|
+
return np.inf * float(self.value)
|
|
134
|
+
else:
|
|
135
|
+
raise NotImplementedError
|
|
136
|
+
|
|
137
|
+
def reshape(self, *args):
|
|
138
|
+
return SymbolicMultiplication(self.symbol, self.value.reshape(*args))
|
|
139
|
+
|
|
140
|
+
def sum(self, *args, **kwargs):
|
|
141
|
+
return SymbolicMultiplication(self.symbol, self.value.sum(*args, **kwargs))
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def T(self):
|
|
145
|
+
return SymbolicMultiplication(self.symbol, self.value.T)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def supporting_symbolic_multiplication(f):
|
|
149
|
+
"""
|
|
150
|
+
When this decorator is applied to a function, this function can now take
|
|
151
|
+
as input a `SymbolicMultiplication` object. The function is applied on the
|
|
152
|
+
`value` part of the `SymbolicMultiplication` without modifying the
|
|
153
|
+
`symbol`.
|
|
154
|
+
"""
|
|
155
|
+
@wraps(f)
|
|
156
|
+
def wrapped_f(a, x):
|
|
157
|
+
if hasattr(x, 'symbol'):
|
|
158
|
+
return SymbolicMultiplication(x.symbol, f(a, x.value))
|
|
159
|
+
else:
|
|
160
|
+
return f(a, x)
|
|
161
|
+
return wrapped_f
|
capytaine/tools/timer.py
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""A simple timer class used to measure the time spent in various parts of the BEM solver."""
|
|
2
|
+
|
|
3
|
+
from functools import wraps
|
|
4
|
+
import time
|
|
5
|
+
import contextlib
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
class Timer:
|
|
10
|
+
"""A timer class that can be used as context manager or as decorator using `wraps_function` method.
|
|
11
|
+
Several timing measurement can be nested.
|
|
12
|
+
|
|
13
|
+
Attributes
|
|
14
|
+
----------
|
|
15
|
+
timings: List[Dict]]
|
|
16
|
+
List of records of each timing measurement.
|
|
17
|
+
The record is a dict with a 'timing' key and any number of other metadata keys.
|
|
18
|
+
default_tags: Optional[Dict]
|
|
19
|
+
Tags added to all the timing measurements.
|
|
20
|
+
_start_times: List[float]
|
|
21
|
+
Start times of the ongoing timing measurements.
|
|
22
|
+
|
|
23
|
+
Example
|
|
24
|
+
-------
|
|
25
|
+
::
|
|
26
|
+
from time import sleep # For testing
|
|
27
|
+
|
|
28
|
+
timer = Timer()
|
|
29
|
+
|
|
30
|
+
with timer(tag="run 1"):
|
|
31
|
+
sleep(1.0)
|
|
32
|
+
|
|
33
|
+
print(timer.total) # 1.0...
|
|
34
|
+
|
|
35
|
+
@timer.wraps_function(tag="run function")
|
|
36
|
+
def my_function():
|
|
37
|
+
sleep(0.5)
|
|
38
|
+
|
|
39
|
+
my_function()
|
|
40
|
+
print(timer.total) # 1.5...
|
|
41
|
+
my_function()
|
|
42
|
+
print(timer.total) # 2.0...
|
|
43
|
+
|
|
44
|
+
with timer(tag="outer"):
|
|
45
|
+
sleep(0.3)
|
|
46
|
+
with timer(tag="inner"):
|
|
47
|
+
sleep(0.3)
|
|
48
|
+
sleep(0.3)
|
|
49
|
+
"""
|
|
50
|
+
def __init__(self, *, default_tags=None):
|
|
51
|
+
self.timings = []
|
|
52
|
+
if default_tags is None:
|
|
53
|
+
default_tags = {}
|
|
54
|
+
self.default_tags = default_tags
|
|
55
|
+
self._start_times = [] # Starting time of ongoing sub-timers
|
|
56
|
+
|
|
57
|
+
def __repr__(self):
|
|
58
|
+
return f"Timer({self.timings})"
|
|
59
|
+
|
|
60
|
+
def add_data_from_other_timer(self, other, **supplementary_tags):
|
|
61
|
+
self.timings.extend([{**t, **supplementary_tags} for t in other.timings])
|
|
62
|
+
|
|
63
|
+
@contextlib.contextmanager
|
|
64
|
+
def __call__(self, **tags):
|
|
65
|
+
self._start_times.append(time.perf_counter())
|
|
66
|
+
try:
|
|
67
|
+
yield
|
|
68
|
+
finally:
|
|
69
|
+
timing = time.perf_counter() - self._start_times.pop()
|
|
70
|
+
self.timings.append({'timing': timing, **tags, **self.default_tags})
|
|
71
|
+
|
|
72
|
+
def wraps_function(self, **tags):
|
|
73
|
+
def wrapper(f):
|
|
74
|
+
@wraps(f)
|
|
75
|
+
def wrapped_f(*args, **kwargs):
|
|
76
|
+
with self(**tags):
|
|
77
|
+
out = f(*args, **kwargs)
|
|
78
|
+
return out
|
|
79
|
+
return wrapped_f
|
|
80
|
+
return wrapper
|
|
81
|
+
|
|
82
|
+
def as_dataframe(self):
|
|
83
|
+
if len(self.timings) == 0:
|
|
84
|
+
return pd.DataFrame([{'timing': 0.0}])
|
|
85
|
+
else:
|
|
86
|
+
return pd.DataFrame(self.timings)
|
|
87
|
+
|
|
88
|
+
@property
|
|
89
|
+
def total(self):
|
|
90
|
+
return self.as_dataframe()['timing'].sum()
|
capytaine/ui/__init__.py
ADDED
|
File without changes
|
capytaine/ui/cli.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
"""Experimental command-line interface for Capytaine."""
|
|
4
|
+
# Copyright (C) 2017-2023 Matthieu Ancellin
|
|
5
|
+
# See LICENSE file at <https://github.com/capytaine/capytaine>
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
|
|
9
|
+
import capytaine as cpt
|
|
10
|
+
from capytaine.io.legacy import run_cal_file
|
|
11
|
+
|
|
12
|
+
cpt.set_logging()
|
|
13
|
+
|
|
14
|
+
parser = argparse.ArgumentParser(description="Command-line interface for Capytaine taking Nemoh.cal files as input and returning Tecplots files.")
|
|
15
|
+
parser.add_argument('paramfiles',
|
|
16
|
+
default=['./Nemoh.cal'],
|
|
17
|
+
nargs='*',
|
|
18
|
+
help='path of parameters files (default: ./Nemoh.cal)')
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main():
|
|
22
|
+
args = parser.parse_args()
|
|
23
|
+
for paramfile in args.paramfiles:
|
|
24
|
+
run_cal_file(paramfile)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == '__main__':
|
|
28
|
+
main()
|