wawi 0.0.1__py3-none-any.whl → 0.0.5__py3-none-any.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.
- wawi/__init__.py +8 -4
- wawi/fe.py +134 -0
- wawi/general.py +468 -0
- wawi/identification.py +66 -0
- wawi/io.py +719 -0
- wawi/modal.py +608 -0
- wawi/plot.py +569 -0
- wawi/prob.py +9 -0
- wawi/random.py +38 -0
- wawi/signal.py +45 -0
- wawi/structural.py +278 -0
- wawi/time_domain.py +126 -0
- wawi/tools.py +7 -0
- wawi/wave.py +491 -0
- wawi/wind.py +1109 -0
- wawi/wind_code.py +14 -0
- {wawi-0.0.1.dist-info → wawi-0.0.5.dist-info}/METADATA +7 -6
- wawi-0.0.5.dist-info/RECORD +21 -0
- wawi-0.0.1.dist-info/RECORD +0 -6
- {wawi-0.0.1.dist-info → wawi-0.0.5.dist-info}/LICENSE +0 -0
- {wawi-0.0.1.dist-info → wawi-0.0.5.dist-info}/WHEEL +0 -0
- {wawi-0.0.1.dist-info → wawi-0.0.5.dist-info}/top_level.txt +0 -0
wawi/wave.py
ADDED
@@ -0,0 +1,491 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from math import atan2
|
3
|
+
from scipy.interpolate import interp1d
|
4
|
+
from scipy.special import jv
|
5
|
+
from .general import wrap_to_pi, uniquetol, zero_pad_upsample, get_omega_upsampled
|
6
|
+
from .tools import print_progress as pp
|
7
|
+
from inspect import isfunction
|
8
|
+
from scipy.special import jv, gamma
|
9
|
+
from scipy.optimize import fsolve
|
10
|
+
from wawi.general import eval_fun_or_scalar
|
11
|
+
|
12
|
+
def linear_drag_damping(drag_coefficient, std_udot, area=1.0, rho=1020.0, as_matrix=True):
|
13
|
+
damping = 0.5*rho*area*drag_coefficient*np.sqrt(8/np.pi)*std_udot
|
14
|
+
|
15
|
+
if as_matrix == True and (len(damping)==3 or len(damping)==6):
|
16
|
+
damping = np.diag(damping)
|
17
|
+
|
18
|
+
return damping
|
19
|
+
|
20
|
+
def stochastic_linearize(C_quad, std_udot):
|
21
|
+
# Input C_quad is assumed matrix form, std_udot is assumed matrix
|
22
|
+
|
23
|
+
if np.ndim(std_udot)==1:
|
24
|
+
std_udot = np.diag(std_udot)
|
25
|
+
|
26
|
+
return C_quad*np.sqrt(8/np.pi)*std_udot
|
27
|
+
|
28
|
+
def harmonic_linearize(C_quad, udot):
|
29
|
+
if np.ndim(udot)==2:
|
30
|
+
udot = np.diag(np.diag(udot))
|
31
|
+
else:
|
32
|
+
udot = np.diag(udot)
|
33
|
+
|
34
|
+
C_quad = np.diag(np.diag(C_quad))
|
35
|
+
return 8/(3*np.pi)*C_quad*np.abs(udot)
|
36
|
+
|
37
|
+
|
38
|
+
def get_coh_fourier(omega, dx, dy, D, theta0, theta_shift=0.0, depth=np.inf,
|
39
|
+
k_max=10, input_is_kappa=False):
|
40
|
+
'''
|
41
|
+
theta_shift is used to translate D, such
|
42
|
+
that non-centered are allowed. Docs to come.
|
43
|
+
'''
|
44
|
+
|
45
|
+
L = np.sqrt(dx**2+dy**2)
|
46
|
+
phi = np.arctan2(dy, dx)
|
47
|
+
beta = theta0 - phi
|
48
|
+
|
49
|
+
if input_is_kappa:
|
50
|
+
kappa = omega*1
|
51
|
+
else:
|
52
|
+
kappa = dispersion_relation(omega, h=depth)[:, np.newaxis]
|
53
|
+
|
54
|
+
# Establish from Fourier coefficients
|
55
|
+
k = np.arange(-k_max, k_max+1)[np.newaxis, :]
|
56
|
+
theta = np.linspace(-np.pi, np.pi, k_max*2+1) #ensures odd number of fft coeff.
|
57
|
+
|
58
|
+
c = np.fft.ifft(D(theta + theta0-theta_shift))
|
59
|
+
c = np.hstack([c[-k_max:], c[:k_max+1]])[np.newaxis, :]
|
60
|
+
|
61
|
+
coh = 2*np.pi*np.sum(
|
62
|
+
np.tile(c*1j**k*np.exp(-1j*k*beta), [len(kappa), 1])
|
63
|
+
* jv(k, kappa*L), axis=1)
|
64
|
+
|
65
|
+
return coh
|
66
|
+
|
67
|
+
def get_coh_cos2s(omega, dx, dy, s, theta0, k_max=10, depth=np.inf,
|
68
|
+
input_is_kappa=False):
|
69
|
+
if input_is_kappa:
|
70
|
+
kappa = omega*1
|
71
|
+
else:
|
72
|
+
kappa = dispersion_relation(omega, h=depth)[:, np.newaxis]
|
73
|
+
|
74
|
+
L = np.sqrt(dx**2 + dy**2)
|
75
|
+
phi = np.arctan2(dy, dx)
|
76
|
+
beta = theta0 - phi
|
77
|
+
|
78
|
+
k = np.arange(-k_max, k_max+1)[np.newaxis, :]
|
79
|
+
c = 1/(2*np.pi) * gamma(s+1)**2/(gamma(s-k+1)*gamma(s+k+1))
|
80
|
+
coh = 2*np.pi * np.sum(np.tile(c*1j**k*np.exp(-1j*k*beta),
|
81
|
+
[len(kappa), 1]) * jv(k, kappa*L), axis=1)
|
82
|
+
|
83
|
+
return coh
|
84
|
+
|
85
|
+
def get_coh(omega, dx, dy, D1, D2=None, depth=np.inf, n_theta=40,
|
86
|
+
theta_shift=0.0, input_is_kappa=False, twodimensional=False,
|
87
|
+
include_D=True):
|
88
|
+
|
89
|
+
if D2 is None: #assumes the same as D1
|
90
|
+
D2 = D1
|
91
|
+
|
92
|
+
if input_is_kappa:
|
93
|
+
kappa = omega*1
|
94
|
+
else:
|
95
|
+
kappa = dispersion_relation(omega, h=depth)
|
96
|
+
|
97
|
+
theta = np.linspace(-np.pi, np.pi, n_theta)
|
98
|
+
|
99
|
+
if include_D:
|
100
|
+
D_eval = np.sqrt(D1(theta)*D2(theta))
|
101
|
+
else:
|
102
|
+
D_eval = 1.0
|
103
|
+
|
104
|
+
coh2d = D_eval*np.exp(-1j*kappa[:, np.newaxis] @ ((np.cos(theta+theta_shift)*dx + np.sin(theta+theta_shift)*dy))[np.newaxis, :])
|
105
|
+
|
106
|
+
if twodimensional:
|
107
|
+
return coh2d, theta
|
108
|
+
else:
|
109
|
+
coh = np.trapz(coh2d, x=theta, axis=1)
|
110
|
+
|
111
|
+
return coh
|
112
|
+
|
113
|
+
|
114
|
+
def xsim(x, y, S, D, omega, fs=None, theta=None, n_theta=40, grid_mode=True, print_progress=True,
|
115
|
+
time_history=False, phase=None, return_phases=False, theta_shift=0.0):
|
116
|
+
|
117
|
+
if fs is None:
|
118
|
+
fs = np.max(omega)/2/np.pi
|
119
|
+
|
120
|
+
if theta is None:
|
121
|
+
theta = np.linspace(-np.pi, np.pi, n_theta)
|
122
|
+
|
123
|
+
|
124
|
+
if not isfunction(S):
|
125
|
+
Sfun = lambda x, y: S
|
126
|
+
else:
|
127
|
+
Sfun = S
|
128
|
+
|
129
|
+
if not isfunction(D):
|
130
|
+
Dfun = lambda x, y: D
|
131
|
+
else:
|
132
|
+
Dfun = D
|
133
|
+
|
134
|
+
if grid_mode:
|
135
|
+
xx,yy = np.meshgrid(x,y)
|
136
|
+
xvec = x*1
|
137
|
+
yvec = y*1
|
138
|
+
x = xx.flatten()
|
139
|
+
y = yy.flatten()
|
140
|
+
|
141
|
+
domega = omega[1] - omega[0]
|
142
|
+
|
143
|
+
if len(theta)>1:
|
144
|
+
dtheta = theta[1] - theta[0]
|
145
|
+
else:
|
146
|
+
dtheta = 1.0
|
147
|
+
|
148
|
+
omegai = get_omega_upsampled(omega, fs*2*np.pi)
|
149
|
+
kappa = omega**2 / 9.81 #assume deep-water waves - can be generalized later (different depths at different positions possible also)
|
150
|
+
|
151
|
+
# Create kappa grid
|
152
|
+
# Attempt to fix function theta_shift (non centered dirdist definitions with theta0 as function)
|
153
|
+
# kappax = lambda x,y: kappa[:, np.newaxis] @ np.cos(theta+eval_fun_or_scalar(theta_shift,x,y))[np.newaxis, :]
|
154
|
+
# kappay = lambda x,y: kappa[:, np.newaxis] @ np.sin(theta+eval_fun_or_scalar(theta_shift,x,y))[np.newaxis, :]
|
155
|
+
|
156
|
+
kappax = kappa[:, np.newaxis] @ np.cos(theta+theta_shift)[np.newaxis, :]
|
157
|
+
kappay = kappa[:, np.newaxis] @ np.sin(theta+theta_shift)[np.newaxis, :]
|
158
|
+
|
159
|
+
n_freqs = len(omega)
|
160
|
+
n_freqs_i = len(omegai)
|
161
|
+
n_angles = len(theta)
|
162
|
+
|
163
|
+
if phase is None:
|
164
|
+
phase = np.exp(1j*np.random.rand(n_freqs, n_angles)*2*np.pi)
|
165
|
+
|
166
|
+
if time_history:
|
167
|
+
eta = np.zeros([n_freqs_i, len(x)])
|
168
|
+
selection = np.arange(n_freqs_i)
|
169
|
+
n_t = n_freqs_i*1
|
170
|
+
else:
|
171
|
+
eta = np.zeros([1, len(x)])
|
172
|
+
selection = np.array(0)
|
173
|
+
n_t = 1
|
174
|
+
|
175
|
+
for ix in range(len(x)):
|
176
|
+
Sthis = Sfun(x[ix], y[ix])(omega)[:, np.newaxis]
|
177
|
+
Dthis = Dfun(x[ix], y[ix])(theta)[np.newaxis, :]
|
178
|
+
|
179
|
+
B0 = np.sqrt(2 * Sthis * Dthis * domega * dtheta)
|
180
|
+
Bkr = B0*np.exp(-1j*(kappax*x[ix] + kappay*y[ix])) * phase
|
181
|
+
if Bkr.shape[1]>1:
|
182
|
+
Bkr_sum = np.trapz(Bkr, axis=1)
|
183
|
+
else:
|
184
|
+
Bkr_sum = Bkr[:,0]
|
185
|
+
|
186
|
+
Bkr_sum = zero_pad_upsample(Bkr_sum, omega, fs*2*np.pi)
|
187
|
+
|
188
|
+
eta[:, ix] = np.fft.fftshift(len(omegai) * np.real(np.fft.ifft(Bkr_sum)))[selection]
|
189
|
+
|
190
|
+
if print_progress:
|
191
|
+
pp(ix+1, len(x), postfix=f' | x={x[ix]:.1f}m, y={y[ix]:.1f}m ')
|
192
|
+
|
193
|
+
t = np.linspace(0, 2*np.pi/domega, n_freqs_i)[selection].T
|
194
|
+
|
195
|
+
if grid_mode:
|
196
|
+
if time_history:
|
197
|
+
eta = np.swapaxes(eta, 0, 1) # after swap: gridcombos x time
|
198
|
+
eta = np.reshape(eta, [len(yvec), len(xvec), -1])
|
199
|
+
else:
|
200
|
+
eta = np.reshape(eta, [len(yvec), len(xvec)])
|
201
|
+
|
202
|
+
# Return
|
203
|
+
if return_phases:
|
204
|
+
return eta, t, phase
|
205
|
+
else:
|
206
|
+
return eta, t
|
207
|
+
|
208
|
+
|
209
|
+
def swh_from_gamma_alpha_Tp(gamma, alpha, Tp, g=9.81):
|
210
|
+
wp = 2*np.pi/Tp
|
211
|
+
|
212
|
+
Hs = (1.555 + 0.2596*gamma - 0.02231*gamma**2 + 0.01142*gamma**3)*g*np.sqrt(alpha)/wp**2
|
213
|
+
return Hs
|
214
|
+
|
215
|
+
def sigma_from_sigma_range(sigma, wp):
|
216
|
+
return lambda w: (sigma[0]+(sigma[1]-sigma[0])*(w>wp))
|
217
|
+
|
218
|
+
def peak_enhancement(gamma, Tp, sigma, normalize=True):
|
219
|
+
wp = 2*np.pi/Tp
|
220
|
+
sigma = sigma_from_sigma_range(sigma, wp)
|
221
|
+
if normalize:
|
222
|
+
A_gamma = (1 - 0.287*np.log(gamma))
|
223
|
+
return lambda w: gamma**np.exp(-(w-wp)**2/(2*sigma(w)**2*wp**2)) * A_gamma
|
224
|
+
else:
|
225
|
+
return lambda w: gamma**np.exp(-(w-wp)**2/(2*sigma(w)**2*wp**2))
|
226
|
+
|
227
|
+
|
228
|
+
def pm2(Hs, Tp, unit='Hz'):
|
229
|
+
fp = 1/Tp
|
230
|
+
A = 5*Hs**2*fp**4/(16)
|
231
|
+
B = 5*fp**4/4
|
232
|
+
|
233
|
+
if unit == 'Hz':
|
234
|
+
return lambda f: A/f**5*np.exp(-B/f**4)
|
235
|
+
elif unit == 'rad/s':
|
236
|
+
return lambda w: A/(w/2/np.pi)**5*np.exp(-B/(w/2/np.pi)**4)/2/np.pi
|
237
|
+
|
238
|
+
|
239
|
+
def jonswap(Hs, Tp, gamma, g=9.81, sigma=[0.07, 0.09]):
|
240
|
+
return lambda w: pm2(Hs, Tp, unit='rad/s')(w)*peak_enhancement(gamma, Tp, sigma, normalize=True)(w)
|
241
|
+
|
242
|
+
def jonswap_numerical(Hs, Tp, gamma, omega, g=9.81, sigma=[0.07, 0.09]):
|
243
|
+
|
244
|
+
if omega[0] == 0:
|
245
|
+
omega[0] = 1
|
246
|
+
first_is_zero = True
|
247
|
+
else:
|
248
|
+
first_is_zero = False
|
249
|
+
|
250
|
+
S = jonswap(Hs, Tp, gamma, g=g, sigma=sigma)(omega)
|
251
|
+
|
252
|
+
if first_is_zero:
|
253
|
+
S[0] = 0.0
|
254
|
+
omega[0] = 0.0
|
255
|
+
|
256
|
+
return S
|
257
|
+
|
258
|
+
|
259
|
+
def jonswap_dnv(Hs, Tp, gamma, sigma=[0.07, 0.09]):
|
260
|
+
A = 1-0.287*np.log(gamma)
|
261
|
+
wp = 2*np.pi/Tp
|
262
|
+
|
263
|
+
sigma = sigma_from_sigma_range(sigma, wp)
|
264
|
+
S = lambda omega: A*5.0/16.0*Hs**2*wp**4/(omega**5)*np.exp(-5/4*(omega/wp)**(-4))*gamma**(np.exp(-0.5*((omega-wp)/sigma(omega)/wp)**2))
|
265
|
+
|
266
|
+
return S
|
267
|
+
|
268
|
+
|
269
|
+
def dirdist_decimal_inv(s, theta0=0, theta=None):
|
270
|
+
if s>170:
|
271
|
+
raise ValueError("Spreading exponent s cannot exceed 170. Please adjust!")
|
272
|
+
C = gamma(s+1)/(2*np.sqrt(np.pi)*gamma(s+0.5))
|
273
|
+
D = lambda theta: C*(np.abs(np.cos((theta+theta0)/2)))**(2*s)
|
274
|
+
|
275
|
+
if theta!=None:
|
276
|
+
D = D(theta)
|
277
|
+
|
278
|
+
return D
|
279
|
+
|
280
|
+
def dirdist_decimal(s, theta0=0, theta=None):
|
281
|
+
if s>170:
|
282
|
+
raise ValueError("Spreading exponent s cannot exceed 170. Please adjust!")
|
283
|
+
|
284
|
+
C = gamma(s+1)/(2*np.sqrt(np.pi)*gamma(s+0.5))
|
285
|
+
D = lambda theta: C*(np.abs(np.cos((theta-theta0)/2)))**(2*s)
|
286
|
+
|
287
|
+
if theta!=None:
|
288
|
+
D = D(theta)
|
289
|
+
|
290
|
+
return D
|
291
|
+
|
292
|
+
def dirdist(s, theta0=0, theta=None):
|
293
|
+
if s>170:
|
294
|
+
raise ValueError("Spreading exponent s cannot exceed 170. Please adjust!")
|
295
|
+
C = gamma(s+1)/(2*np.sqrt(np.pi)*gamma(s+0.5))
|
296
|
+
D = lambda theta: C*(np.cos((theta-theta0)/2))**(2*s)
|
297
|
+
|
298
|
+
if theta!=None:
|
299
|
+
D = D(theta)
|
300
|
+
|
301
|
+
return D
|
302
|
+
|
303
|
+
def dirdist_robust(s, theta0=0, dtheta=1e-4, theta=None):
|
304
|
+
theta_num = np.unique(np.hstack([np.arange(-np.pi, np.pi+dtheta, dtheta), wrap_to_pi(theta0)]))
|
305
|
+
val = np.cos((theta_num-theta0)/2)**(2*s)
|
306
|
+
scaling = 1/np.trapz(val, theta_num)
|
307
|
+
|
308
|
+
def D(theta):
|
309
|
+
return interp1d(theta_num, val*scaling)(wrap_to_pi(theta))
|
310
|
+
|
311
|
+
if theta!=None:
|
312
|
+
D = D(theta)
|
313
|
+
|
314
|
+
return D
|
315
|
+
|
316
|
+
|
317
|
+
|
318
|
+
def waveaction_fft(pontoons, omega, n_fourier=20, max_coherence_length=np.inf, print_progress=True):
|
319
|
+
n_pontoons = len(pontoons)
|
320
|
+
n_dofs = n_pontoons*6
|
321
|
+
|
322
|
+
n_theta = n_fourier*2
|
323
|
+
|
324
|
+
theta = np.linspace(-np.pi, np.pi-2*np.pi/n_theta, n_theta)
|
325
|
+
S = np.zeros([n_dofs, n_dofs, len(omega)]).astype('complex')
|
326
|
+
|
327
|
+
for i, pontoon_i in enumerate(pontoons):
|
328
|
+
fi,__,__ = pontoon_i.evaluate_Q(omega, n_fourier*2)
|
329
|
+
xi,yi = pontoon_i.node.coordinates[:2]
|
330
|
+
|
331
|
+
for j, pontoon_j in enumerate(pontoons):
|
332
|
+
xj,yj = pontoon_j.node.coordinates[:2]
|
333
|
+
dx = xj-xi
|
334
|
+
dy = yj-yi
|
335
|
+
|
336
|
+
l = np.sqrt(dx**2+dy**2)
|
337
|
+
|
338
|
+
if l<max_coherence_length:
|
339
|
+
beta = atan2(dy,dx)
|
340
|
+
fj,__,__ = pontoon_j.evaluate_Q(omega, n_fourier*2)
|
341
|
+
|
342
|
+
depth = (pontoon_i.depth+pontoon_j.depth)/2
|
343
|
+
kappa = np.array([dispersion_relation(omega_k, h=depth) for omega_k in omega])
|
344
|
+
|
345
|
+
coh_2d = np.sqrt((pontoon_i.S(omega) * pontoon_j.S(omega))[:, np.newaxis] @ (pontoon_i.D(theta-pontoon_i.theta0) * pontoon_j.D(theta-pontoon_j.theta0))[np.newaxis, :])
|
346
|
+
|
347
|
+
for dof_i in range(6):
|
348
|
+
for dof_j in range(6):
|
349
|
+
integrand = fi[dof_i,:] * fj[dof_j,:].conj() * coh_2d.T
|
350
|
+
c = np.fft.fft(integrand)
|
351
|
+
I = np.stack([np.exp(1j*n*beta)*1j**n*2*np.pi*jv(n, kappa*l) for n in range(-n_fourier, n_fourier)], axis=1)
|
352
|
+
|
353
|
+
S[i*6+dof_i, j*6+dof_j, :] = np.sum(I*c)
|
354
|
+
|
355
|
+
if print_progress:
|
356
|
+
pp(i*n_pontoons+j, n_pontoons**2)
|
357
|
+
|
358
|
+
return S
|
359
|
+
|
360
|
+
|
361
|
+
def waveaction(pontoon_group, omega, max_rel_error=1e-3, print_progress=True):
|
362
|
+
n_pontoons = len(pontoon_group.pontoons)
|
363
|
+
n_freqs = len(omega)
|
364
|
+
n_dofs = n_pontoons*6
|
365
|
+
|
366
|
+
if omega[0]==0:
|
367
|
+
omega = omega[1::]
|
368
|
+
first_is_zero = True
|
369
|
+
n_freqs = n_freqs-1
|
370
|
+
else:
|
371
|
+
first_is_zero = False
|
372
|
+
|
373
|
+
kappa = [None]*n_pontoons
|
374
|
+
for pontoon_ix, pontoon in enumerate(pontoon_group.pontoons):
|
375
|
+
kappa[pontoon_ix] = dispersion_relation(omega, pontoon.depth)
|
376
|
+
|
377
|
+
Sqq = np.zeros([n_dofs, n_dofs, n_freqs]).astype('complex')
|
378
|
+
|
379
|
+
for k, omega_k in enumerate(omega):
|
380
|
+
if print_progress:
|
381
|
+
pp(k+1, n_freqs)
|
382
|
+
|
383
|
+
theta_int = pontoon_group.get_theta_int(omega_k)
|
384
|
+
dtheta = theta_int[2]-theta_int[1]
|
385
|
+
|
386
|
+
n_theta = len(theta_int)
|
387
|
+
Z = np.zeros([n_dofs, n_theta]).astype('complex')
|
388
|
+
|
389
|
+
for pontoon_index, pontoon in enumerate(pontoon_group.pontoons):
|
390
|
+
if pontoon.D.__code__.co_argcount==2: # count number of inputs
|
391
|
+
D = pontoon.D(theta_int, omega_k)
|
392
|
+
else:
|
393
|
+
D = pontoon.D(theta_int)
|
394
|
+
|
395
|
+
# Shift current theta axis
|
396
|
+
theta_pontoon = wrap_to_pi(pontoon.pontoon_type.theta + pontoon.rotation - pontoon.theta0)
|
397
|
+
theta_pontoon, sort_ix = uniquetol(theta_pontoon, 1e-10)
|
398
|
+
|
399
|
+
# Interpolate hydrodynamic transfer function
|
400
|
+
Q_int = interp1d(theta_pontoon, pontoon.get_local_Q(omega_k)[:, sort_ix], fill_value=0, kind='quadratic', bounds_error=False)(theta_int)
|
401
|
+
|
402
|
+
coh = np.exp(1j*kappa[pontoon_index][k] * (pontoon.node.x*np.cos(theta_int + pontoon.theta0) + pontoon.node.y*np.sin(theta_int + pontoon.theta0)))
|
403
|
+
Z[pontoon_index*6:pontoon_index*6+6, :] = np.sqrt(pontoon.S(omega_k)) * Q_int * np.tile(np.sqrt(D), [6, 1]) * np.tile(coh, [6, 1])
|
404
|
+
|
405
|
+
# first and last point in trapezoidal integration has 1/2 as factor, others have 1
|
406
|
+
Z[:, 0] = np.sqrt(0.5)*Z[:, 0]
|
407
|
+
Z[:, -1] = np.sqrt(0.5)*Z[:, -1]
|
408
|
+
|
409
|
+
Sqq[:, :, k] = dtheta * pontoon_group.get_tmat().T @ (Z @ Z.conj().T) @ pontoon_group.get_tmat() # verified to match for loop over angles and trapz integration.
|
410
|
+
|
411
|
+
|
412
|
+
if first_is_zero==True:
|
413
|
+
Sqq = np.insert(Sqq, 0, Sqq[:,:,0]*0, axis=2)
|
414
|
+
|
415
|
+
|
416
|
+
return Sqq
|
417
|
+
|
418
|
+
|
419
|
+
def dispersion_relation_scalar(w, h=np.inf, g=9.81, U=0.0):
|
420
|
+
if h==np.inf:
|
421
|
+
f = lambda k: g*k - (w-k*U)**2
|
422
|
+
else:
|
423
|
+
f = lambda k: g*k*np.tanh(k*h) - (w-k*U)**2
|
424
|
+
|
425
|
+
k0 = w**2/g # deep-water, zero-current wave number
|
426
|
+
|
427
|
+
k = fsolve(f, x0=k0)[0]
|
428
|
+
|
429
|
+
return k
|
430
|
+
|
431
|
+
def dispersion_relation_scalar_legacy(w, h=np.inf, g=9.81):
|
432
|
+
if h != np.inf:
|
433
|
+
a = h*w**2/g
|
434
|
+
|
435
|
+
# Initial guesses are provided by small value and large value approximations of x
|
436
|
+
x = a*0
|
437
|
+
x[a<=3/4] = np.sqrt((3-np.sqrt(9-12*a[a<=3/4]))/2)
|
438
|
+
x[a>3/4] = a[a>3/4]
|
439
|
+
|
440
|
+
for i in range(0,100):
|
441
|
+
x = (a+(x**2)*(1-(np.tanh(x))**2))/(np.tanh(x)+x*(1-(np.tanh(x))**2))
|
442
|
+
# The convergence criterion is chosen such that the wave numbers produce frequencies that don't deviate more than 1e-6*sqrt(g/h) from w.
|
443
|
+
if np.max(abs(np.sqrt(x*np.tanh(x))-np.sqrt(a))) < 1e-6:
|
444
|
+
break
|
445
|
+
|
446
|
+
k = x/h
|
447
|
+
else:
|
448
|
+
return w**2/g
|
449
|
+
|
450
|
+
def dispersion_relation(w, h=np.inf, g=9.81):
|
451
|
+
zero_ix = np.where(w==0)
|
452
|
+
w = w[w!=0]
|
453
|
+
|
454
|
+
if h != np.Inf:
|
455
|
+
a = h*w**2/g
|
456
|
+
|
457
|
+
# Initial guesses are provided by small value and large value approximations of x
|
458
|
+
x = a*0
|
459
|
+
x[a<=3/4] = np.sqrt((3-np.sqrt(9-12*a[a<=3/4]))/2)
|
460
|
+
x[a>3/4] = a[a>3/4]
|
461
|
+
|
462
|
+
for i in range(0,100):
|
463
|
+
x = (a+(x**2)*(1-(np.tanh(x))**2))/(np.tanh(x)+x*(1-(np.tanh(x))**2))
|
464
|
+
# The convergence criterion is chosen such that the wave numbers produce frequencies that don't deviate more than 1e-6*sqrt(g/h) from w.
|
465
|
+
if np.max(abs(np.sqrt(x*np.tanh(x))-np.sqrt(a))) < 1e-6:
|
466
|
+
break
|
467
|
+
|
468
|
+
k = x/h
|
469
|
+
else:
|
470
|
+
k = w**2/g
|
471
|
+
|
472
|
+
k = np.insert(k, zero_ix[0], 0)
|
473
|
+
|
474
|
+
return k
|
475
|
+
|
476
|
+
|
477
|
+
def maxincrement(dl, kmax, a, b, max_relative_error):
|
478
|
+
g = 9.81
|
479
|
+
thetamax = np.pi/2
|
480
|
+
K = abs(1j*kmax*(-(1/2)*np.pi)*dl*(-(1/2)*np.pi)*(np.cos(thetamax))*(-(1/2)*np.pi)*(np.exp(-1j*kmax*dl*np.cos(thetamax)))*(-(1/2)*np.pi)-kmax*(-(1/2)*np.pi)**2*dl*(-(1/2)*np.pi)**2*(np.sin(thetamax))*(-(1/2)*np.pi)**2*(np.exp(-1j*kmax*dl*np.cos(thetamax)))*(-(1/2)*np.pi))
|
481
|
+
|
482
|
+
max_val = abs(np.exp(-1j*dl))
|
483
|
+
max_error = max_val*max_relative_error
|
484
|
+
N = np.sqrt((K*(b-a)**3)/(12*max_error))
|
485
|
+
|
486
|
+
increment=(b-a)/N
|
487
|
+
|
488
|
+
if dl==0:
|
489
|
+
increment=b-a
|
490
|
+
|
491
|
+
return increment
|