capytaine 2.2.1__cp39-cp39-win_amd64.whl → 2.3__cp39-cp39-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 +1 -1
- capytaine/__init__.py +7 -6
- capytaine/bem/airy_waves.py +7 -2
- capytaine/bem/problems_and_results.py +78 -34
- capytaine/bem/solver.py +127 -39
- capytaine/bodies/bodies.py +30 -10
- capytaine/bodies/predefined/rectangles.py +2 -0
- capytaine/green_functions/FinGreen3D/.gitignore +1 -0
- capytaine/green_functions/FinGreen3D/FinGreen3D.f90 +3589 -0
- capytaine/green_functions/FinGreen3D/LICENSE +165 -0
- capytaine/green_functions/FinGreen3D/Makefile +16 -0
- capytaine/green_functions/FinGreen3D/README.md +24 -0
- capytaine/green_functions/FinGreen3D/test_program.f90 +39 -0
- capytaine/green_functions/LiangWuNoblesse/.gitignore +1 -0
- capytaine/green_functions/LiangWuNoblesse/LICENSE +504 -0
- capytaine/green_functions/LiangWuNoblesse/LiangWuNoblesseWaveTerm.f90 +751 -0
- capytaine/green_functions/LiangWuNoblesse/Makefile +18 -0
- capytaine/green_functions/LiangWuNoblesse/README.md +2 -0
- capytaine/green_functions/LiangWuNoblesse/test_program.f90 +28 -0
- capytaine/green_functions/abstract_green_function.py +55 -3
- capytaine/green_functions/delhommeau.py +186 -115
- capytaine/green_functions/hams.py +204 -0
- capytaine/green_functions/libs/Delhommeau_float32.cp39-win_amd64.dll.a +0 -0
- capytaine/green_functions/libs/Delhommeau_float32.cp39-win_amd64.pyd +0 -0
- capytaine/green_functions/libs/Delhommeau_float64.cp39-win_amd64.dll.a +0 -0
- capytaine/green_functions/libs/Delhommeau_float64.cp39-win_amd64.pyd +0 -0
- capytaine/io/bemio.py +14 -2
- capytaine/io/mesh_loaders.py +1 -1
- capytaine/io/wamit.py +479 -0
- capytaine/io/xarray.py +257 -113
- capytaine/matrices/linear_solvers.py +1 -1
- capytaine/meshes/clipper.py +1 -0
- capytaine/meshes/collections.py +11 -1
- capytaine/meshes/mesh_like_protocol.py +37 -0
- capytaine/meshes/meshes.py +17 -6
- capytaine/meshes/symmetric.py +11 -2
- capytaine/post_pro/kochin.py +4 -4
- capytaine/tools/lists_of_points.py +3 -3
- capytaine/tools/prony_decomposition.py +60 -4
- capytaine/tools/symbolic_multiplication.py +12 -0
- capytaine/tools/timer.py +64 -0
- capytaine-2.3.dist-info/DELVEWHEEL +2 -0
- {capytaine-2.2.1.dist-info → capytaine-2.3.dist-info}/METADATA +9 -2
- {capytaine-2.2.1.dist-info → capytaine-2.3.dist-info}/RECORD +48 -32
- capytaine-2.2.1.dist-info/DELVEWHEEL +0 -2
- {capytaine-2.2.1.dist-info → capytaine-2.3.dist-info}/LICENSE +0 -0
- {capytaine-2.2.1.dist-info → capytaine-2.3.dist-info}/WHEEL +0 -0
- {capytaine-2.2.1.dist-info → capytaine-2.3.dist-info}/entry_points.txt +0 -0
- capytaine.libs/{.load-order-capytaine-2.2.1 → .load-order-capytaine-2.3} +2 -2
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.
|
|
8
|
+
__version__ = "2.3"
|
|
9
9
|
|
|
10
10
|
__author__ = "Matthieu Ancellin"
|
|
11
11
|
__uri__ = "https://github.com/capytaine/capytaine"
|
capytaine/__init__.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
# start delvewheel patch
|
|
6
|
-
def
|
|
6
|
+
def _delvewheel_patch_1_10_1():
|
|
7
7
|
import ctypes
|
|
8
8
|
import os
|
|
9
9
|
import platform
|
|
@@ -14,10 +14,10 @@ def _delvewheel_patch_1_9_0():
|
|
|
14
14
|
if os.path.isdir(libs_dir):
|
|
15
15
|
os.add_dll_directory(libs_dir)
|
|
16
16
|
else:
|
|
17
|
-
load_order_filepath = os.path.join(libs_dir, '.load-order-capytaine-2.
|
|
17
|
+
load_order_filepath = os.path.join(libs_dir, '.load-order-capytaine-2.3')
|
|
18
18
|
if os.path.isfile(load_order_filepath):
|
|
19
19
|
import ctypes.wintypes
|
|
20
|
-
with open(os.path.join(libs_dir, '.load-order-capytaine-2.
|
|
20
|
+
with open(os.path.join(libs_dir, '.load-order-capytaine-2.3')) as file:
|
|
21
21
|
load_order = file.read().split()
|
|
22
22
|
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
|
|
23
23
|
kernel32.LoadLibraryExW.restype = ctypes.wintypes.HMODULE
|
|
@@ -28,8 +28,8 @@ def _delvewheel_patch_1_9_0():
|
|
|
28
28
|
raise OSError('Error loading {}; {}'.format(lib, ctypes.FormatError(ctypes.get_last_error())))
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
del
|
|
31
|
+
_delvewheel_patch_1_10_1()
|
|
32
|
+
del _delvewheel_patch_1_10_1
|
|
33
33
|
# end delvewheel patch
|
|
34
34
|
|
|
35
35
|
from .__about__ import (
|
|
@@ -55,11 +55,12 @@ from capytaine.bem.problems_and_results import RadiationProblem, DiffractionProb
|
|
|
55
55
|
from capytaine.bem.solver import BEMSolver
|
|
56
56
|
from capytaine.bem.engines import BasicMatrixEngine, HierarchicalToeplitzMatrixEngine, HierarchicalPrecondMatrixEngine
|
|
57
57
|
from capytaine.green_functions.delhommeau import Delhommeau, XieDelhommeau
|
|
58
|
+
from capytaine.green_functions.hams import LiangWuNoblesseGF, FinGreen3D, HAMS_GF
|
|
58
59
|
|
|
59
60
|
from capytaine.post_pro.free_surfaces import FreeSurface
|
|
60
61
|
|
|
61
62
|
from capytaine.io.mesh_loaders import load_mesh
|
|
62
|
-
from capytaine.io.xarray import assemble_dataset
|
|
63
|
+
from capytaine.io.xarray import assemble_dataframe, assemble_dataset, assemble_matrices, export_dataset
|
|
63
64
|
|
|
64
65
|
from capytaine.ui.rich import set_logging
|
|
65
66
|
|
capytaine/bem/airy_waves.py
CHANGED
|
@@ -22,6 +22,9 @@ def airy_waves_potential(points, pb):
|
|
|
22
22
|
"""
|
|
23
23
|
points, output_shape = _normalize_points(points)
|
|
24
24
|
|
|
25
|
+
if float(pb.wavenumber) == 0.0 or float(pb.wavenumber) == np.inf:
|
|
26
|
+
return np.nan * np.ones(output_shape)
|
|
27
|
+
|
|
25
28
|
x, y, z = points.T
|
|
26
29
|
k = pb.wavenumber
|
|
27
30
|
h = pb.water_depth
|
|
@@ -54,9 +57,11 @@ def airy_waves_velocity(points, pb):
|
|
|
54
57
|
array of shape (3) or (N x 3)
|
|
55
58
|
the velocity vectors
|
|
56
59
|
"""
|
|
57
|
-
|
|
58
60
|
points, output_shape = _normalize_points(points)
|
|
59
61
|
|
|
62
|
+
if float(pb.wavenumber) == 0.0 or float(pb.wavenumber) == np.inf:
|
|
63
|
+
return np.nan * np.ones((*output_shape, 3))
|
|
64
|
+
|
|
60
65
|
x, y, z = points.T
|
|
61
66
|
k = pb.wavenumber
|
|
62
67
|
h = pb.water_depth
|
|
@@ -79,7 +84,7 @@ def airy_waves_velocity(points, pb):
|
|
|
79
84
|
|
|
80
85
|
|
|
81
86
|
def airy_waves_pressure(points, pb):
|
|
82
|
-
return 1j * pb.omega * pb.rho * airy_waves_potential(points, pb)
|
|
87
|
+
return 1j * float(pb.omega) * pb.rho * airy_waves_potential(points, pb)
|
|
83
88
|
|
|
84
89
|
|
|
85
90
|
def froude_krylov_force(pb):
|
|
@@ -24,8 +24,8 @@ _default_parameters = {'rho': 1000.0, 'g': 9.81, 'omega': 1.0,
|
|
|
24
24
|
class LinearPotentialFlowProblem:
|
|
25
25
|
"""General class of a potential flow problem.
|
|
26
26
|
|
|
27
|
-
At most one of the following
|
|
28
|
-
|
|
27
|
+
At most one of the following parameters must be provided:
|
|
28
|
+
omega, freq, period, wavenumber or wavelength.
|
|
29
29
|
|
|
30
30
|
Parameters
|
|
31
31
|
----------
|
|
@@ -39,6 +39,8 @@ class LinearPotentialFlowProblem:
|
|
|
39
39
|
The position of the sea bottom (deprecated: please prefer setting water_depth)
|
|
40
40
|
omega: float, optional
|
|
41
41
|
The angular frequency of the waves in rad/s
|
|
42
|
+
freq: float, optional
|
|
43
|
+
The frequency of the waves in Hz
|
|
42
44
|
period: float, optional
|
|
43
45
|
The period of the waves in s
|
|
44
46
|
wavenumber: float, optional
|
|
@@ -59,7 +61,7 @@ class LinearPotentialFlowProblem:
|
|
|
59
61
|
body=None,
|
|
60
62
|
free_surface=_default_parameters['free_surface'],
|
|
61
63
|
water_depth=None, sea_bottom=None,
|
|
62
|
-
omega=None, period=None, wavenumber=None, wavelength=None,
|
|
64
|
+
omega=None, freq=None, period=None, wavenumber=None, wavelength=None,
|
|
63
65
|
forward_speed=_default_parameters['forward_speed'],
|
|
64
66
|
rho=_default_parameters['rho'],
|
|
65
67
|
g=_default_parameters['g'],
|
|
@@ -76,14 +78,14 @@ class LinearPotentialFlowProblem:
|
|
|
76
78
|
self.boundary_condition = boundary_condition
|
|
77
79
|
|
|
78
80
|
self.water_depth = _get_water_depth(free_surface, water_depth, sea_bottom, default_water_depth=_default_parameters["water_depth"])
|
|
79
|
-
self.omega, self.period, self.wavenumber, self.wavelength, self.provided_freq_type = \
|
|
80
|
-
self._get_frequencies(omega=omega, period=period, wavenumber=wavenumber, wavelength=wavelength)
|
|
81
|
+
self.omega, self.freq, self.period, self.wavenumber, self.wavelength, self.provided_freq_type = \
|
|
82
|
+
self._get_frequencies(omega=omega, freq=freq, period=period, wavenumber=wavenumber, wavelength=wavelength)
|
|
81
83
|
|
|
82
84
|
self._check_data()
|
|
83
85
|
|
|
84
86
|
if forward_speed != 0.0:
|
|
85
87
|
dopplered_omega = self.omega - self.wavenumber*self.forward_speed*np.cos(self.wave_direction)
|
|
86
|
-
self.encounter_omega, self.encounter_period, self.encounter_wavenumber, self.encounter_wavelength, _ = \
|
|
88
|
+
self.encounter_omega, self.encounter_freq, self.encounter_period, self.encounter_wavenumber, self.encounter_wavelength, _ = \
|
|
87
89
|
self._get_frequencies(omega=abs(dopplered_omega))
|
|
88
90
|
|
|
89
91
|
if dopplered_omega >= 0.0:
|
|
@@ -92,18 +94,19 @@ class LinearPotentialFlowProblem:
|
|
|
92
94
|
self.encounter_wave_direction = self.wave_direction + np.pi
|
|
93
95
|
else:
|
|
94
96
|
self.encounter_omega = self.omega
|
|
97
|
+
self.encounter_freq = self.freq
|
|
95
98
|
self.encounter_period = self.period
|
|
96
99
|
self.encounter_wavenumber = self.wavenumber
|
|
97
100
|
self.encounter_wavelength = self.wavelength
|
|
98
101
|
self.encounter_wave_direction = self.wave_direction
|
|
99
102
|
|
|
100
103
|
|
|
101
|
-
def _get_frequencies(self, *, omega=None, period=None, wavenumber=None, wavelength=None):
|
|
102
|
-
frequency_data = dict(omega=omega, period=period, wavenumber=wavenumber, wavelength=wavelength)
|
|
103
|
-
nb_provided_frequency_data =
|
|
104
|
+
def _get_frequencies(self, *, omega=None, freq=None, period=None, wavenumber=None, wavelength=None):
|
|
105
|
+
frequency_data = dict(omega=omega, freq=freq, period=period, wavenumber=wavenumber, wavelength=wavelength)
|
|
106
|
+
nb_provided_frequency_data = len(frequency_data) - list(frequency_data.values()).count(None)
|
|
104
107
|
|
|
105
108
|
if nb_provided_frequency_data > 1:
|
|
106
|
-
raise ValueError("Settings a problem requires at most one of the following: omega (angular frequency) OR period OR wavenumber OR wavelength.\n"
|
|
109
|
+
raise ValueError("Settings a problem requires at most one of the following: omega (angular frequency) OR freq (in Hz) OR period OR wavenumber OR wavelength.\n"
|
|
107
110
|
"Received {} of them: {}".format(nb_provided_frequency_data, {k: v for k, v in frequency_data.items() if v is not None}))
|
|
108
111
|
|
|
109
112
|
if nb_provided_frequency_data == 0:
|
|
@@ -112,27 +115,35 @@ class LinearPotentialFlowProblem:
|
|
|
112
115
|
else:
|
|
113
116
|
provided_freq_type = [k for (k, v) in frequency_data.items() if v is not None][0]
|
|
114
117
|
|
|
115
|
-
if ((float(frequency_data[provided_freq_type]) == 0.0 and provided_freq_type in {'omega', 'wavenumber'})
|
|
118
|
+
if ((float(frequency_data[provided_freq_type]) == 0.0 and provided_freq_type in {'omega', 'freq', 'wavenumber'})
|
|
116
119
|
or (float(frequency_data[provided_freq_type]) == np.inf and provided_freq_type in {'period', 'wavelength'})):
|
|
117
120
|
omega = SymbolicMultiplication("0")
|
|
121
|
+
freq = SymbolicMultiplication("0")
|
|
118
122
|
wavenumber = SymbolicMultiplication("0")
|
|
119
123
|
period = SymbolicMultiplication("∞")
|
|
120
124
|
wavelength = SymbolicMultiplication("∞")
|
|
121
125
|
elif ((float(frequency_data[provided_freq_type]) == 0.0 and provided_freq_type in {'period', 'wavelength'})
|
|
122
|
-
or (float(frequency_data[provided_freq_type]) == np.inf and provided_freq_type in {'omega', 'wavenumber'})):
|
|
126
|
+
or (float(frequency_data[provided_freq_type]) == np.inf and provided_freq_type in {'omega', 'freq', 'wavenumber'})):
|
|
123
127
|
omega = SymbolicMultiplication("∞")
|
|
128
|
+
freq = SymbolicMultiplication("∞")
|
|
124
129
|
wavenumber = SymbolicMultiplication("∞")
|
|
125
130
|
period = SymbolicMultiplication("0")
|
|
126
131
|
wavelength = SymbolicMultiplication("0")
|
|
127
132
|
else:
|
|
128
133
|
|
|
129
|
-
if provided_freq_type in {'omega', 'period'}:
|
|
134
|
+
if provided_freq_type in {'omega', 'freq', 'period'}:
|
|
130
135
|
if provided_freq_type == 'omega':
|
|
131
136
|
omega = frequency_data['omega']
|
|
132
137
|
period = 2*np.pi/omega
|
|
138
|
+
freq = omega/2/np.pi
|
|
139
|
+
elif provided_freq_type == 'freq':
|
|
140
|
+
freq = frequency_data['freq']
|
|
141
|
+
omega = 2*np.pi*freq
|
|
142
|
+
period = 1/freq
|
|
133
143
|
else: # provided_freq_type is 'period'
|
|
134
144
|
period = frequency_data['period']
|
|
135
145
|
omega = 2*np.pi/period
|
|
146
|
+
freq = 1/period
|
|
136
147
|
|
|
137
148
|
if self.water_depth == np.inf:
|
|
138
149
|
wavenumber = omega**2/self.g
|
|
@@ -150,8 +161,9 @@ class LinearPotentialFlowProblem:
|
|
|
150
161
|
|
|
151
162
|
omega = np.sqrt(self.g*wavenumber*np.tanh(wavenumber*self.water_depth))
|
|
152
163
|
period = 2*np.pi/omega
|
|
164
|
+
freq = 1/period
|
|
153
165
|
|
|
154
|
-
return omega, period, wavenumber, wavelength, provided_freq_type
|
|
166
|
+
return omega, freq, period, wavenumber, wavelength, provided_freq_type
|
|
155
167
|
|
|
156
168
|
def _check_data(self):
|
|
157
169
|
"""Sanity checks on the data."""
|
|
@@ -168,7 +180,6 @@ class LinearPotentialFlowProblem:
|
|
|
168
180
|
"If you were actually giving an angle in radians, use the modulo operator to give a value between -2π and 2π to disable this warning.")
|
|
169
181
|
|
|
170
182
|
if self.free_surface == np.inf and self.water_depth != np.inf:
|
|
171
|
-
|
|
172
183
|
raise NotImplementedError(
|
|
173
184
|
"Problems with a sea bottom but no free surface have not been implemented."
|
|
174
185
|
)
|
|
@@ -177,11 +188,6 @@ class LinearPotentialFlowProblem:
|
|
|
177
188
|
raise ValueError("`water_depth` should be strictly positive (provided water depth: {self.water_depth}).")
|
|
178
189
|
|
|
179
190
|
if float(self.omega) in {0, np.inf}:
|
|
180
|
-
if self.water_depth != np.inf:
|
|
181
|
-
LOG.warning(
|
|
182
|
-
f"Default Green function allows for {self.provided_freq_type}={float(self.__getattribute__(self.provided_freq_type))} only for infinite depth (provided water depth: {self.water_depth})."
|
|
183
|
-
)
|
|
184
|
-
|
|
185
191
|
if self.forward_speed != 0.0:
|
|
186
192
|
raise NotImplementedError(
|
|
187
193
|
f"omega={float(self.omega)} is only implemented without forward speed (provided forward speed: {self.forward_speed})."
|
|
@@ -193,6 +199,8 @@ class LinearPotentialFlowProblem:
|
|
|
193
199
|
or len(self.body.mesh.faces) == 0):
|
|
194
200
|
raise ValueError(f"The mesh of the body {self.body.__short_str__()} is empty.")
|
|
195
201
|
|
|
202
|
+
self.body._check_dofs_shape_consistency()
|
|
203
|
+
|
|
196
204
|
panels_above_fs = self.body.mesh.faces_centers[:, 2] >= self.free_surface + 1e-8
|
|
197
205
|
panels_below_sb = self.body.mesh.faces_centers[:, 2] <= -self.water_depth
|
|
198
206
|
if (any(panels_above_fs) or any(panels_below_sb)):
|
|
@@ -231,8 +239,11 @@ class LinearPotentialFlowProblem:
|
|
|
231
239
|
def _asdict(self):
|
|
232
240
|
return {"body_name": self.body_name,
|
|
233
241
|
"water_depth": self.water_depth,
|
|
242
|
+
"free_surface": self.free_surface,
|
|
234
243
|
"omega": float(self.omega),
|
|
244
|
+
"freq": float(self.freq),
|
|
235
245
|
"encounter_omega": float(self.encounter_omega),
|
|
246
|
+
"encounter_freq": float(self.encounter_freq),
|
|
236
247
|
"period": float(self.period),
|
|
237
248
|
"wavelength": float(self.wavelength),
|
|
238
249
|
"wavenumber": float(self.wavenumber),
|
|
@@ -322,8 +333,11 @@ class LinearPotentialFlowProblem:
|
|
|
322
333
|
# TODO: let the user choose the influenced dofs
|
|
323
334
|
return self.body.dofs if self.body is not None else set()
|
|
324
335
|
|
|
325
|
-
def make_results_container(self):
|
|
326
|
-
return LinearPotentialFlowResult(self)
|
|
336
|
+
def make_results_container(self, *args, **kwargs):
|
|
337
|
+
return LinearPotentialFlowResult(self, *args, **kwargs)
|
|
338
|
+
|
|
339
|
+
def make_failed_results_container(self, *args, **kwargs):
|
|
340
|
+
return FailedLinearPotentialFlowResult(self, *args, **kwargs)
|
|
327
341
|
|
|
328
342
|
|
|
329
343
|
class DiffractionProblem(LinearPotentialFlowProblem):
|
|
@@ -334,19 +348,16 @@ class DiffractionProblem(LinearPotentialFlowProblem):
|
|
|
334
348
|
body=None,
|
|
335
349
|
free_surface=_default_parameters['free_surface'],
|
|
336
350
|
water_depth=None, sea_bottom=None,
|
|
337
|
-
omega=None, period=None, wavenumber=None, wavelength=None,
|
|
351
|
+
omega=None, freq=None, period=None, wavenumber=None, wavelength=None,
|
|
338
352
|
forward_speed=_default_parameters['forward_speed'],
|
|
339
353
|
rho=_default_parameters['rho'],
|
|
340
354
|
g=_default_parameters['g'],
|
|
341
355
|
wave_direction=_default_parameters['wave_direction']):
|
|
342
356
|
|
|
343
357
|
super().__init__(body=body, free_surface=free_surface, water_depth=water_depth, sea_bottom=sea_bottom,
|
|
344
|
-
omega=omega, period=period, wavenumber=wavenumber, wavelength=wavelength, wave_direction=wave_direction,
|
|
358
|
+
omega=omega, freq=freq, period=period, wavenumber=wavenumber, wavelength=wavelength, wave_direction=wave_direction,
|
|
345
359
|
forward_speed=forward_speed, rho=rho, g=g)
|
|
346
360
|
|
|
347
|
-
if float(self.omega) in {0.0, np.inf}:
|
|
348
|
-
raise NotImplementedError("DiffractionProblem does not support zero or infinite frequency.")
|
|
349
|
-
|
|
350
361
|
if self.body is not None:
|
|
351
362
|
|
|
352
363
|
self.boundary_condition = -(
|
|
@@ -371,6 +382,9 @@ class DiffractionProblem(LinearPotentialFlowProblem):
|
|
|
371
382
|
def make_results_container(self, *args, **kwargs):
|
|
372
383
|
return DiffractionResult(self, *args, **kwargs)
|
|
373
384
|
|
|
385
|
+
def make_failed_results_container(self, *args, **kwargs):
|
|
386
|
+
return FailedDiffractionResult(self, *args, **kwargs)
|
|
387
|
+
|
|
374
388
|
|
|
375
389
|
class RadiationProblem(LinearPotentialFlowProblem):
|
|
376
390
|
"""Particular LinearPotentialFlowProblem whose boundary conditions have
|
|
@@ -379,7 +393,7 @@ class RadiationProblem(LinearPotentialFlowProblem):
|
|
|
379
393
|
def __init__(self, *, body=None,
|
|
380
394
|
free_surface=_default_parameters['free_surface'],
|
|
381
395
|
water_depth=None, sea_bottom=None,
|
|
382
|
-
omega=None, period=None, wavenumber=None, wavelength=None,
|
|
396
|
+
omega=None, freq=None, period=None, wavenumber=None, wavelength=None,
|
|
383
397
|
forward_speed=_default_parameters['forward_speed'],
|
|
384
398
|
wave_direction=_default_parameters['wave_direction'],
|
|
385
399
|
rho=_default_parameters['rho'],
|
|
@@ -389,7 +403,7 @@ class RadiationProblem(LinearPotentialFlowProblem):
|
|
|
389
403
|
self.radiating_dof = radiating_dof
|
|
390
404
|
|
|
391
405
|
super().__init__(body=body, free_surface=free_surface, water_depth=water_depth, sea_bottom=sea_bottom,
|
|
392
|
-
omega=omega, period=period, wavenumber=wavenumber, wavelength=wavelength,
|
|
406
|
+
omega=omega, freq=freq, period=period, wavenumber=wavenumber, wavelength=wavelength,
|
|
393
407
|
wave_direction=wave_direction, forward_speed=forward_speed, rho=rho, g=g)
|
|
394
408
|
|
|
395
409
|
if self.body is not None:
|
|
@@ -407,7 +421,11 @@ class RadiationProblem(LinearPotentialFlowProblem):
|
|
|
407
421
|
|
|
408
422
|
dof = self.body.dofs[self.radiating_dof]
|
|
409
423
|
|
|
410
|
-
|
|
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)])
|
|
427
|
+
|
|
428
|
+
self.boundary_condition = -1j * self.encounter_omega * displacement_on_face
|
|
411
429
|
|
|
412
430
|
if self.forward_speed != 0.0:
|
|
413
431
|
if self.radiating_dof.lower() == "pitch":
|
|
@@ -424,8 +442,6 @@ class RadiationProblem(LinearPotentialFlowProblem):
|
|
|
424
442
|
)
|
|
425
443
|
self.boundary_condition += self.forward_speed * ddofdx_dot_n
|
|
426
444
|
|
|
427
|
-
if self.body.lid_mesh is not None:
|
|
428
|
-
self.boundary_condition = np.concatenate([self.boundary_condition, np.zeros(self.body.lid_mesh.nb_faces)])
|
|
429
445
|
|
|
430
446
|
|
|
431
447
|
def _astuple(self):
|
|
@@ -448,6 +464,9 @@ class RadiationProblem(LinearPotentialFlowProblem):
|
|
|
448
464
|
def make_results_container(self, *args, **kwargs):
|
|
449
465
|
return RadiationResult(self, *args, **kwargs)
|
|
450
466
|
|
|
467
|
+
def make_failed_results_container(self, *args, **kwargs):
|
|
468
|
+
return FailedRadiationResult(self, *args, **kwargs)
|
|
469
|
+
|
|
451
470
|
|
|
452
471
|
class LinearPotentialFlowResult:
|
|
453
472
|
|
|
@@ -465,12 +484,14 @@ class LinearPotentialFlowResult:
|
|
|
465
484
|
self.body = self.problem.body
|
|
466
485
|
self.free_surface = self.problem.free_surface
|
|
467
486
|
self.omega = self.problem.omega
|
|
487
|
+
self.freq = self.problem.freq
|
|
468
488
|
self.period = self.problem.period
|
|
469
489
|
self.wavenumber = self.problem.wavenumber
|
|
470
490
|
self.wavelength = self.problem.wavelength
|
|
471
491
|
self.forward_speed = self.problem.forward_speed
|
|
472
492
|
self.wave_direction = self.problem.wave_direction
|
|
473
493
|
self.encounter_omega = self.problem.encounter_omega
|
|
494
|
+
self.encounter_freq = self.problem.encounter_freq
|
|
474
495
|
self.encounter_period = self.problem.encounter_period
|
|
475
496
|
self.encounter_wavenumber = self.problem.encounter_wavenumber
|
|
476
497
|
self.encounter_wavelength = self.problem.encounter_wavelength
|
|
@@ -495,6 +516,13 @@ class LinearPotentialFlowResult:
|
|
|
495
516
|
__rich_repr__ = LinearPotentialFlowProblem.__rich_repr__
|
|
496
517
|
|
|
497
518
|
|
|
519
|
+
class FailedLinearPotentialFlowResult(LinearPotentialFlowResult):
|
|
520
|
+
def __init__(self, problem, exception):
|
|
521
|
+
LinearPotentialFlowResult.__init__(self, problem)
|
|
522
|
+
self.forces = {dof: np.nan + 1j*np.nan for dof in self.influenced_dofs}
|
|
523
|
+
self.exception = exception
|
|
524
|
+
|
|
525
|
+
|
|
498
526
|
class DiffractionResult(LinearPotentialFlowResult):
|
|
499
527
|
|
|
500
528
|
def __init__(self, problem, *args, **kwargs):
|
|
@@ -510,10 +538,18 @@ class DiffractionResult(LinearPotentialFlowResult):
|
|
|
510
538
|
return [dict(**params,
|
|
511
539
|
influenced_dof=dof,
|
|
512
540
|
diffraction_force=self.forces[dof],
|
|
513
|
-
Froude_Krylov_force=FK[dof]
|
|
541
|
+
Froude_Krylov_force=FK[dof],
|
|
542
|
+
kind="DiffractionResult")
|
|
514
543
|
for dof in self.influenced_dofs]
|
|
515
544
|
|
|
516
545
|
|
|
546
|
+
class FailedDiffractionResult(DiffractionResult):
|
|
547
|
+
def __init__(self, problem, exception):
|
|
548
|
+
DiffractionResult.__init__(self, problem)
|
|
549
|
+
self.forces = {dof: np.nan for dof in self.influenced_dofs}
|
|
550
|
+
self.exception = exception
|
|
551
|
+
|
|
552
|
+
|
|
517
553
|
class RadiationResult(LinearPotentialFlowResult):
|
|
518
554
|
|
|
519
555
|
def __init__(self, problem, *args, **kwargs):
|
|
@@ -544,5 +580,13 @@ class RadiationResult(LinearPotentialFlowResult):
|
|
|
544
580
|
return [dict(params,
|
|
545
581
|
influenced_dof=dof,
|
|
546
582
|
added_mass=self.added_mass[dof],
|
|
547
|
-
radiation_damping=self.radiation_damping[dof]
|
|
583
|
+
radiation_damping=self.radiation_damping[dof],
|
|
584
|
+
kind="RadiationResult")
|
|
548
585
|
for dof in self.influenced_dofs]
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
class FailedRadiationResult(RadiationResult):
|
|
589
|
+
def __init__(self, problem, exception):
|
|
590
|
+
RadiationResult.__init__(self, problem)
|
|
591
|
+
self.forces = {dof: np.nan + 1j*np.nan for dof in self.influenced_dofs}
|
|
592
|
+
self.exception = exception
|