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/plot.py ADDED
@@ -0,0 +1,569 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib.animation import FuncAnimation
4
+ from wawi.wave import dispersion_relation_scalar as get_kappa
5
+ from scipy.ndimage import rotate, shift
6
+ from matplotlib import transforms
7
+ from scipy.interpolate import RectBivariateSpline, interp1d
8
+
9
+
10
+ def plot_ads(ad_dict, v, terms='stiffness', num=None, test_v=dict(), test_ad=dict(), zasso_type=False, ranges=None):
11
+ # v: v or K
12
+ if terms is 'stiffness':
13
+ terms = [['P4', 'P6', 'P3'], ['H6', 'H4', 'H3'], ['A6', 'A4', 'A3']]
14
+ elif terms is 'damping':
15
+ terms = [['P1', 'P5', 'P2'], ['H5', 'H1', 'H2'], ['A5', 'A1', 'A2']]
16
+
17
+ # Create exponent defs for K_normalized plotting
18
+ K_exp = dict()
19
+ stiffness_terms = ['P4', 'P6', 'P3', 'H6', 'H4', 'H3', 'A6', 'A4', 'A3']
20
+ damping_terms = ['P1', 'P5', 'P2', 'H5', 'H1', 'H2', 'A5', 'A1', 'A2']
21
+ K_exp.update(zip(stiffness_terms, [1]*len(stiffness_terms)))
22
+ K_exp.update(zip(damping_terms, [2]*len(damping_terms)))
23
+
24
+ K_label_add = dict()
25
+ K_label_add.update(zip(stiffness_terms, ['$K$']*len(stiffness_terms)))
26
+ K_label_add.update(zip(damping_terms, ['$K^2$']*len(damping_terms)))
27
+
28
+ fig, ax = plt.subplots(nrows=len(terms[0]), ncols=len(terms), num=num, sharex=True)
29
+
30
+ for row_ix, row in enumerate(terms):
31
+ for col_ix, term in enumerate(row):
32
+ axi = ax[row_ix, col_ix]
33
+
34
+ if term in ad_dict:
35
+ if ranges is not None and term in ranges:
36
+ ad_valid = ad_dict[term](v)*1
37
+
38
+ v_min, v_max = ranges[term]
39
+
40
+ ad_valid[v<v_min] = ad_dict[term](v_min)
41
+ ad_valid[v>v_max] = ad_dict[term](v_max)
42
+ else:
43
+ ad_valid = ad_dict[term](v)
44
+
45
+ axi.plot(v, ad_valid, label='Fit')
46
+
47
+ label = zasso_type*K_label_add[term]+('$' + term[0] + '_' + term[1] + '^*' + '$')
48
+ axi.set_ylabel(label)
49
+ axi.grid('on')
50
+
51
+ if term in test_v:
52
+ if zasso_type:
53
+ vK = 1/test_v[term]
54
+ factor = vK**K_exp[term]
55
+ else:
56
+ vK = test_v[term]
57
+ factor = 1.0
58
+
59
+ axi.plot(vK, test_ad[term]*factor, '.k', label='Test')
60
+
61
+ for col_ix in range(len(terms)):
62
+ if zasso_type:
63
+ ax[-1, col_ix].set_xlabel('$K$')
64
+ else:
65
+ ax[-1, col_ix].set_xlabel('$V/(B\cdot \omega)$')
66
+
67
+ fig.tight_layout()
68
+ return fig, ax
69
+
70
+ def save_plot(pl, path, w=None, h=None):
71
+ ws = pl.window_size
72
+ if w is not None and h is None:
73
+ w = int(np.round(w))
74
+ h = int(np.round(ws[1] * w/ws[0]))
75
+ elif h is not None and w is None:
76
+ h = int(np.round(h))
77
+ w = int(np.round(ws[0] * h/ws[1]))
78
+ elif h is None and w is None:
79
+ w,h = ws
80
+ else:
81
+ w = int(np.round(w))
82
+ h = int(np.round(h))
83
+
84
+ pl.screenshot(path, window_size=[w,h], return_img=False)
85
+
86
+ def plot_dir_and_crests(theta0, Tp, arrow_length=100, origin=np.array([0,0]),
87
+ ax=None, n_repeats=2, crest_length=1000,
88
+ alpha_crests=0.2, arrow_options={}):
89
+ arr_opts = {'head_width': 4, 'width':2, 'edgecolor':'none'}
90
+ arr_opts.update(**arrow_options)
91
+
92
+ if ax is None:
93
+ ax = plt.gca()
94
+
95
+ # Plot wave angle and crests
96
+ v = np.array([np.cos(theta0*np.pi/180), np.sin(theta0*np.pi/180)])
97
+ v_norm = np.array([-np.sin(theta0*np.pi/180), np.cos(theta0*np.pi/180)])
98
+ wave_length = 2*np.pi/get_kappa(2*np.pi/Tp, U=0.0)
99
+
100
+ plt.arrow(origin[0],origin[1], arrow_length*v[0], arrow_length*v[1], **arr_opts)
101
+ plt.text(origin[0], origin[1], f'$\\theta_0$ = {theta0}$^o$\n $T_p$={Tp} s\n $\lambda=${wave_length:.0f} m')
102
+
103
+ dv = v*wave_length
104
+ for n in range(n_repeats):
105
+ p1 = origin-v_norm*crest_length/2
106
+ p2 = origin+v_norm*crest_length/2
107
+ pts = np.vstack([p1,p2])
108
+
109
+ ax.plot(pts[:,0], pts[:,1], alpha=alpha_crests, color='black', zorder=0)
110
+ origin = origin + dv
111
+
112
+ return ax
113
+
114
+ def rotate_image_about_pivot(Z, x, y, angle, x0=0, y0=0):
115
+ xc = np.mean(x)
116
+ yc = np.mean(y)
117
+
118
+ pixel_x = interp1d(x, np.arange(len(x)), fill_value='extrapolate')
119
+ pixel_y = interp1d(y, np.arange(len(y)), fill_value='extrapolate')
120
+
121
+ ds_x = pixel_x(x0) - pixel_x(xc) # sample shift x
122
+ ds_y = pixel_y(y0) - pixel_y(yc) # sample shift y
123
+ ds = np.array([ds_x, ds_y])*0
124
+
125
+ T = np.array([[np.cos(angle*np.pi/180), np.sin(angle*np.pi/180)],
126
+ [-np.sin(angle*np.pi/180), np.cos(angle*np.pi/180)]])
127
+
128
+ ds_rot = T @ ds
129
+
130
+ return shift(rotate(shift(Z, ds[::-1]), angle), -ds_rot[::-1])
131
+
132
+ def combine_eta(eta_fine, eta_course, x_fine, y_fine, x_course, y_course, x=None, y=None):
133
+ dx_fine = x_fine[1]-x_fine[0]
134
+ dy_fine = y_fine[1]-y_fine[0]
135
+
136
+ if x is None:
137
+ x = np.arange(np.min(x_course), np.max(x_course), dx_fine)
138
+
139
+ if y is None:
140
+ y = np.arange(np.min(y_course), np.max(y_course), dy_fine)
141
+
142
+ eta_course_i = RectBivariateSpline(y_course,x_course,eta_course)
143
+ eta_fine_i = RectBivariateSpline(y_fine,x_fine,eta_fine)
144
+
145
+ eta_combined = eta_course_i(y,x)
146
+ sel = np.ix_(
147
+ (y >= np.min(y_fine)) & (y <= np.max(y_fine)),
148
+ (x >= np.min(x_fine)) & (x <= np.max(x_fine)))
149
+
150
+ eta_combined[sel] = eta_fine_i(y[(y >= np.min(y_fine)) & (y <= np.max(y_fine))],
151
+ x[(x >= np.min(x_fine)) & (x <= np.max(x_fine))])
152
+
153
+ return eta_combined, x, y
154
+
155
+
156
+ def animate_surface(eta, x, y, t, filename=None, fps=None,
157
+ speed_ratio=1.0, figsize=None, writer='ffmpeg',
158
+ ax=None, surface=None):
159
+
160
+
161
+ if surface is None:
162
+ if ax is None:
163
+ fig, ax = plt.subplots(figsize=figsize)
164
+ else:
165
+ fig = fig.get_figure()
166
+ surface, __ = plot_surface(eta[:,:,0], x, y, ax=ax, colorbar=False, labels=False)
167
+ else:
168
+ fig = surface.get_figure()
169
+ ax = fig.axes[0]
170
+
171
+ def animate(i):
172
+ surface.set_data(eta[:,:,i])
173
+ return surface,
174
+
175
+ frames = np.arange(len(t))
176
+ dt = t[1]-t[0]
177
+ fs = 1/dt
178
+
179
+ if filename is None:
180
+ repeat = True
181
+ else:
182
+ repeat = False
183
+
184
+ if fps is None:
185
+ fps = fs*speed_ratio
186
+
187
+ interval = 1/fps*1000
188
+
189
+ anim = FuncAnimation(fig, animate,
190
+ frames=frames, interval=interval, blit=True, repeat=repeat)
191
+
192
+ if filename is not None:
193
+ anim.save(filename, writer=writer, fps=fps)
194
+ else:
195
+ plt.show()
196
+
197
+ def xy_to_latlon(latlon0, coors, rot=0):
198
+ import cartopy.crs as ccrs, cartopy.geodesic as cgds
199
+ dist = np.linalg.norm(coors, axis=1)
200
+ azi = np.arctan2(coors[:,0], coors[:,1])*180/np.pi - rot # atan2(x,y) to get azimuth (relative to N-vector)
201
+ geodesic = cgds.Geodesic()
202
+
203
+ return np.vstack(geodesic.direct(np.tile(latlon0, [len(dist), 1]), azi, dist))[:,:2]
204
+
205
+
206
+ def plot_surface_in_map(eta, x, y, eta_geo0, extent,
207
+ eta_scatter=None,
208
+ wms_url='https://openwms.statkart.no/skwms1/wms.terrengmodell?request=GetCapabilities&service=WMS',
209
+ wms_layers=['relieff'], ax=None,
210
+ cm='Blues_r', colorbar=True, figsize=None, eta_rot=0, labels=False):
211
+
212
+ import cartopy.crs as ccrs, cartopy.geodesic as cgds
213
+
214
+ proj = 'Mercator'
215
+ proj = getattr(ccrs, proj)()
216
+
217
+
218
+ if ax is None:
219
+ ax = plt.axes(projection=proj)
220
+
221
+
222
+ # Plot scatter
223
+ if eta_scatter is None:
224
+ scatter = None
225
+ else:
226
+ eta_scatter = xy_to_latlon(eta_geo0, eta_scatter, rot=eta_rot)
227
+ scatter = ax.scatter(eta_scatter[:,0], eta_scatter[:,1], c='black', s=6, transform=ccrs.PlateCarree())
228
+
229
+ # Plot eta
230
+ if eta is not None:
231
+ eta_max = np.max(np.abs(eta))
232
+ corners = np.array([[np.min(x), np.min(y)],
233
+ [np.min(x), np.max(y)],
234
+ [np.max(x), np.max(y)],
235
+ [np.max(x), np.min(y)]])
236
+
237
+ corners_latlon = xy_to_latlon(eta_geo0, corners, rot=eta_rot)
238
+
239
+ extent_merc = np.vstack(proj.transform_points(ccrs.PlateCarree(), np.array([extent[0], extent[2]]), np.array([extent[1], extent[3]])))[:,:2]
240
+ extent_merc = [np.min(extent_merc[:,0]), np.max(extent_merc[:,0]),
241
+ np.min(extent_merc[:,1]), np.max(extent_merc[:,1])]
242
+
243
+ ax.imshow(np.zeros([2,2]), cmap=cm, origin='lower', interpolation='none',
244
+ vmin=-eta_max, vmax=eta_max, extent=extent_merc)
245
+
246
+ corners_latlon_new = np.vstack(proj.transform_points(ccrs.PlateCarree(), *corners_latlon.T))[:,:2]
247
+ eta_extent_new = [np.min(corners_latlon_new[:,0]), np.max(corners_latlon_new[:,0]),
248
+ np.min(corners_latlon_new[:,1]), np.max(corners_latlon_new[:,1])]
249
+
250
+ eta_rotated = rotate(eta, -eta_rot)
251
+
252
+ surface = ax.imshow(eta_rotated, cmap=cm, origin='lower',
253
+ interpolation='none', extent=eta_extent_new,
254
+ vmin=-eta_max, vmax=eta_max)
255
+
256
+ if colorbar:
257
+ plt.colorbar(surface)
258
+
259
+ else:
260
+ surface = None
261
+ if labels:
262
+ ax.gridlines(color='lightgrey', linestyle='-', draw_labels=True)
263
+
264
+ ax.add_wms(wms_url, layers=wms_layers, extent=extent)
265
+ ax.set_extent(extent)
266
+
267
+ return ax, scatter, surface
268
+
269
+
270
+ def plot_surface(eta, x, y, ax=None,
271
+ cm='Blues_r', colorbar=True,
272
+ labels=True, figsize=None, interpolation='none'):
273
+
274
+ if ax is None:
275
+ fig, ax = plt.subplots(figsize=figsize)
276
+
277
+ dx = (x[1]-x[0])/2.
278
+ dy = (y[1]-y[0])/2.
279
+ extent = [x[0]-dx, x[-1]+dx, y[0]-dy, y[-1]+dy]
280
+
281
+ eta_max = np.max(np.abs(eta))
282
+ surface_plot = ax.imshow(eta, cmap=cm, extent=extent, origin='lower', vmin=-eta_max, vmax=eta_max, interpolation=interpolation)
283
+
284
+ if labels:
285
+ ax.set_xlabel('x [m]')
286
+ ax.set_ylabel('y [m]')
287
+ else:
288
+ ax.set_xticks([])
289
+ ax.set_yticks([])
290
+
291
+ if colorbar:
292
+ cb = plt.colorbar(surface_plot)
293
+
294
+ return surface_plot, ax
295
+
296
+
297
+ def set_axes_equal(ax: plt.Axes):
298
+ import matplotlib.pyplot as plt
299
+ """Set 3D plot axes to equal scale.
300
+
301
+ Make axes of 3D plot have equal scale so that spheres appear as
302
+ spheres and cubes as cubes. Required since `ax.axis('equal')`
303
+ and `ax.set_aspect('equal')` don't work on 3D.
304
+ """
305
+ limits = np.array([
306
+ ax.get_xlim3d(),
307
+ ax.get_ylim3d(),
308
+ ax.get_zlim3d(),
309
+ ])
310
+ origin = np.mean(limits, axis=1)
311
+ radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0]))
312
+ _set_axes_radius(ax, origin, radius)
313
+
314
+ def _set_axes_radius(ax, origin, radius):
315
+ x, y, z = origin
316
+ ax.set_xlim3d([x - radius, x + radius])
317
+ ax.set_ylim3d([y - radius, y + radius])
318
+ ax.set_zlim3d([z - radius, z + radius])
319
+
320
+ def equal_3d(ax=plt.gca()):
321
+ x_lims = np.array(ax.get_xlim())
322
+ y_lims = np.array(ax.get_ylim())
323
+ z_lims = np.array(ax.get_zlim())
324
+
325
+ x_range = np.diff(x_lims)
326
+ y_range = np.diff(y_lims)
327
+ z_range = np.diff(z_lims)
328
+
329
+ max_range = np.max([x_range,y_range,z_range])/2
330
+
331
+ ax.set_xlim(np.mean(x_lims) - max_range, np.mean(x_lims) + max_range)
332
+ ax.set_ylim(np.mean(y_lims) - max_range, np.mean(y_lims) + max_range)
333
+ ax.set_zlim(np.mean(z_lims) - max_range, np.mean(z_lims) + max_range)
334
+ # ax.set_aspect(1)
335
+
336
+ return ax
337
+
338
+ def plot_transformation_mats(x,y,z,T,figno=None, ax=None, scaling='auto'):
339
+
340
+ if ax==None:
341
+ fig = plt.figure(figno)
342
+ ax = fig.add_subplot(111, projection='3d')
343
+
344
+ ax.scatter(x,y,z,'.k')
345
+
346
+ if scaling=='auto':
347
+ xr = max(x)-min(x)
348
+ yr = max(y)-min(y)
349
+ zr = max(z)-min(z)
350
+ r = np.sqrt(xr**2+yr**2+zr**2)
351
+ scaling = 0.005*r
352
+
353
+ compcolors = ['tab:red', 'tab:blue', 'tab:green']
354
+ h = [None]*3
355
+ for ix, Ti in enumerate(T):
356
+ xi = x[ix]
357
+ yi = y[ix]
358
+ zi = z[ix]
359
+
360
+ for comp in range(0,3):
361
+ xunit = [xi, xi+Ti[comp,0]*scaling]
362
+ yunit = [yi, yi+Ti[comp,1]*scaling]
363
+ zunit = [zi, zi+Ti[comp,2]*scaling]
364
+
365
+ h[comp] = plt.plot(xs=xunit,ys=yunit,zs=zunit, color=compcolors[comp])[0]
366
+
367
+ plt.legend(h,['x', 'y', 'z'])
368
+ ax.set_xlabel('x')
369
+ ax.set_ylabel('y')
370
+ ax.set_zlabel('z')
371
+
372
+ equal_3d(ax)
373
+ return ax,h
374
+
375
+
376
+ def plot_elements(element_matrix, node_matrix, chosen_nodes_ix=[], disp=None, node_labels=False, element_labels=False, plot_nodes=True, plot_elements=True, ax=None, fig=None, element_settings={}, node_settings={}, node_label_settings={}, chosen_node_settings={}, disp_settings={}, element_label_settings={}, three_d=True):
377
+ e_dict = {'color': 'LimeGreen', 'alpha': 1}
378
+ e_dict.update(**element_settings)
379
+
380
+ n_dict = {'color':'Black', 'linestyle':'', 'marker':'.', 'markersize':4, 'alpha':0.8}
381
+ n_dict.update(**node_settings)
382
+
383
+ n_chosen_dict = {'color':'GreenYellow', 'linestyle':'', 'marker':'o', 'markersize':8, 'alpha':1, 'markeredgecolor':'dimgray'}
384
+ n_chosen_dict.update(**chosen_node_settings)
385
+
386
+ disp_dict = {'color':'IndianRed', 'alpha':1}
387
+ disp_dict.update(**disp_settings)
388
+
389
+ l_nodes_dict = {'color':'Black', 'fontsize': 8, 'fontweight':'normal'}
390
+ l_nodes_dict.update(**node_label_settings)
391
+
392
+ l_elements_dict = {'color':'LimeGreen', 'fontsize': 8, 'fontweight':'bold', 'style':'italic'}
393
+ l_elements_dict.update(**element_label_settings)
394
+
395
+ if ax is None and fig is None:
396
+ fig = plt.figure()
397
+
398
+ if ax == None and three_d:
399
+ ax = fig.gca(projection='3d')
400
+ elif ax == None:
401
+ ax = fig.gca()
402
+ elif three_d:
403
+ 1
404
+ # ax.set(projection='3d') #mangler funksjonalitet her...
405
+
406
+ element_handles = [None]*len(element_matrix[:,0])
407
+
408
+ if plot_elements:
409
+ for element_ix, __ in enumerate(element_matrix[:,0]):
410
+ node1 = element_matrix[element_ix, 1]
411
+ node2 = element_matrix[element_ix, 2]
412
+ nodeix1 = np.where(node_matrix[:,0]==node1)[0]
413
+ nodeix2 = np.where(node_matrix[:,0]==node2)[0]
414
+ x01 = node_matrix[nodeix1,1:4]
415
+ x02 = node_matrix[nodeix2,1:4]
416
+ x0 = np.vstack([x01,x02])
417
+
418
+ if three_d:
419
+ element_handles[element_ix] = ax.plot(xs=x0[:,0], ys=x0[:,1], zs=x0[:,2], **e_dict)
420
+ else:
421
+ element_handles[element_ix] = ax.plot(x0[:,0], x0[:,1], **e_dict)
422
+
423
+ if element_labels:
424
+ xmean = np.mean(x0, axis=0)
425
+ if three_d:
426
+ ax.text(xmean[0],xmean[1],xmean[2],'%i' % element_matrix[element_ix,0], **l_elements_dict)
427
+ else:
428
+ ax.text(xmean[0],xmean[1],s='%i' % element_matrix[element_ix,0], **l_elements_dict)
429
+
430
+ if disp is not None:
431
+ disp_node1 = disp[nodeix1[0]*6:(nodeix1[0]*6+6)]
432
+ disp_node2 = disp[nodeix2[0]*6:(nodeix2[0]*6+6)]
433
+ x1 = x01+disp_node1[0:3]
434
+ x2 = x02+disp_node2[0:3]
435
+ x = np.vstack([x1,x2])
436
+
437
+ if three_d:
438
+ ax.plot(xs=x[:,0], ys=x[:,1], zs=x[:,2], **disp_dict)
439
+ else:
440
+ ax.plot(x[:,0], x[:,1], **disp_dict)
441
+
442
+ if plot_nodes:
443
+ if three_d:
444
+ ax.plot(xs=node_matrix[:, 1], ys=node_matrix[:, 2], zs=node_matrix[:, 3], **n_dict)
445
+ else:
446
+ ax.plot(node_matrix[:, 1], node_matrix[:, 2], **n_dict)
447
+
448
+ if chosen_nodes_ix != []:
449
+ if three_d:
450
+ ax.plot(xs=node_matrix[chosen_nodes_ix, 1], ys=node_matrix[chosen_nodes_ix, 2], zs=node_matrix[chosen_nodes_ix, 3], **n_chosen_dict)
451
+ else:
452
+ ax.plot(node_matrix[chosen_nodes_ix, 1], node_matrix[chosen_nodes_ix, 2], **n_chosen_dict)
453
+
454
+ if node_labels:
455
+ if three_d:
456
+ for node_ix in range(0, np.shape(node_matrix)[0]):
457
+ ax.text(node_matrix[node_ix, 1], node_matrix[node_ix, 2], node_matrix[node_ix, 3], '%i' % node_matrix[node_ix, 0], **l_nodes_dict)
458
+ else:
459
+ for node_ix in range(0, np.shape(node_matrix)[0]):
460
+ ax.text(node_matrix[node_ix, 1], node_matrix[node_ix, 2], '%i' % node_matrix[node_ix, 0], **l_nodes_dict)
461
+
462
+ if three_d:
463
+ equal_3d(ax)
464
+ else:
465
+ ax.set_aspect('equal', adjustable='box')
466
+
467
+ ax.grid('off')
468
+ return ax, element_handles
469
+
470
+
471
+ def plot_2d(S2d, x1, x2, ax=None, levels=80, discrete=False, **kwargs):
472
+ if ax is None:
473
+ ax = plt.gca()
474
+
475
+ X, Y = np.meshgrid(x1, x2)
476
+ if discrete:
477
+ contour = ax.pcolormesh(x1,x2,S2d, **kwargs)
478
+ else:
479
+ contour = ax.contourf(X, Y, S2d.T, levels=levels, **kwargs)
480
+ return contour
481
+
482
+
483
+ def plot_S2d(S, omega, theta, D=None, omega_range=None, theta_range=None):
484
+
485
+ if theta_range is None:
486
+ theta_range = [np.min(theta), np.max(theta)]
487
+
488
+ if omega_range is None:
489
+ omega_range = [0, np.max(omega)]
490
+
491
+ X, Y = np.meshgrid(omega, theta)
492
+
493
+ if D is None:
494
+ SD = S*1
495
+ else:
496
+ SD = S[:,np.newaxis] @ D[np.newaxis,:]
497
+
498
+ SD[np.isnan(SD)] = 0
499
+
500
+ plt.figure(2).clf()
501
+ fig = plt.figure(num=2, constrained_layout=True)
502
+
503
+ if D is not None:
504
+ widths = [2, 0.7]
505
+ heights = [0.7, 2.0, 0.7]
506
+ spec = fig.add_gridspec(ncols=2, nrows=3, width_ratios=widths,
507
+ height_ratios=heights, wspace=.1, hspace=.1)
508
+ else:
509
+ widths = [2]
510
+ heights = [2.0, 0.7]
511
+ spec = fig.add_gridspec(ncols=1, nrows=2, width_ratios=widths,
512
+ height_ratios=heights, wspace=.1, hspace=.1)
513
+
514
+ if D is not None:
515
+ ax = [None]*3
516
+ ax[0] = fig.add_subplot(spec[1,0]) # SD
517
+ ax[1] = fig.add_subplot(spec[0,0]) # S
518
+ ax[2] = fig.add_subplot(spec[1,1]) # D
519
+ ax[1].set_yticklabels('')
520
+ ax[2].set_xticklabels('')
521
+ ax[2].set_yticklabels('')
522
+ cbar_ax = fig.add_subplot(spec[2,0])
523
+ else:
524
+ ax = [fig.add_subplot(spec[0,0])]
525
+ cbar_ax = fig.add_subplot(spec[1,0])
526
+
527
+ cbar_ax.axis('off')
528
+
529
+ # Contour plot
530
+ contour = ax[0].contourf(X, Y, SD.T)
531
+ ax[0].set_ylim(theta_range)
532
+ ax[0].set_xlim(omega_range)
533
+ ax[0].set_ylabel(r'$\theta$ [rad]')
534
+ ax[0].set_xlabel(r'$\omega$ [rad/s]')
535
+
536
+ if D is not None:
537
+ # S line plot
538
+ ax[1].plot(omega, S)
539
+ ax[1].set_ylim(bottom=0)
540
+ ax[1].set_xlim(omega_range)
541
+ ax[1].set_xticklabels('')
542
+ ax[1].set_yticks([])
543
+
544
+ # D line plot
545
+
546
+ ax[2].plot(D, theta)
547
+ ax[2].set_ylim(theta_range)
548
+ ax[2].set_xlim(left=0)
549
+ ax[2].set_xticks([])
550
+
551
+ # cbar_ax.axis('off')
552
+ fig.colorbar(contour, ax=cbar_ax, orientation="horizontal", aspect=25, shrink=1.0)
553
+
554
+ ax[0].spines['top'].set_visible(False)
555
+ ax[0].spines['right'].set_visible(False)
556
+
557
+ if D is not None:
558
+ ax[1].spines['top'].set_visible(False)
559
+ ax[1].spines['right'].set_visible(False)
560
+ ax[1].set_ylabel(r'$S_\eta(\omega)$')
561
+
562
+ ax[2].spines['bottom'].set_visible(False)
563
+ ax[2].spines['right'].set_visible(False)
564
+ ax[2].set_xlabel(r'$D(\theta)$',rotation=-90)
565
+ ax[2].xaxis.set_label_position('top')
566
+
567
+ fig.subplots_adjust(top=0.97, bottom=0.08, left=0.16, right=0.97)
568
+
569
+ return fig
wawi/prob.py ADDED
@@ -0,0 +1,9 @@
1
+ import numpy as np
2
+
3
+ def gumbel_log(umax):
4
+ umax_ordered = np.sort(umax)[::-1]
5
+ N_stat = len(umax)
6
+ F = 1-np.arange(1, N_stat+1)/(N_stat+1)
7
+ loglogF = -np.log(-np.log(F))
8
+
9
+ return umax_ordered, loglogF
wawi/random.py ADDED
@@ -0,0 +1,38 @@
1
+ import numpy as np
2
+
3
+ def zero_crossing_period(S, omega):
4
+ return 2*np.pi*np.sqrt(np.trapz(S, x=omega)/np.trapz(omega**2*S, x=omega))
5
+
6
+ def stoch_mom(S, omega, n=0):
7
+ return np.trapz(S*omega**n, x=omega)
8
+
9
+ def m0(S, omega):
10
+ return stoch_mom(S, omega, n=0)
11
+
12
+ def m2(S, omega):
13
+ return stoch_mom(S, omega, n=2)
14
+
15
+ def v0_from_spectrum(S, omega):
16
+ return 1/(2*np.pi) * np.sqrt(m2(S, omega)/m0(S, omega))
17
+
18
+ def v0(m0,m2):
19
+ return 1/(2*np.pi) * np.sqrt(m2/m0)
20
+
21
+ def peakfactor(T, v0):
22
+ c = np.sqrt(2*np.log(v0*T))
23
+ kp = c + np.euler_gamma/c
24
+ return kp
25
+
26
+ def expmax(T, v0, std):
27
+ return peakfactor(T,v0)*std
28
+
29
+ def expmax_from_spectrum(S, omega, T):
30
+ m0_val = m0(S, omega)
31
+ std = np.sqrt(m0_val)
32
+
33
+ v0_val = v0(m0_val, m2(S, omega))
34
+
35
+ return expmax(T, v0_val, std)
36
+
37
+ def peakfactor_from_spectrum(S, omega, T):
38
+ return peakfactor(T, v0(S, omega))
wawi/signal.py ADDED
@@ -0,0 +1,45 @@
1
+ from .wave import jonswap
2
+ import numpy as np
3
+ from scipy.optimize import curve_fit
4
+
5
+ def fit_jonswap(S, w, sigma=[0.07, 0.09], initial_values=None):
6
+ if initial_values is None:
7
+ initial_values = {}
8
+
9
+ Hs0 = np.sqrt(np.trapz(S, w))*4
10
+
11
+ p0 = {'Hs': Hs0, 'Tp': 1, 'gamma': 1} #standard values of curve_fit are 1
12
+ p0.update(**initial_values)
13
+
14
+ if w[0]==0:
15
+ w = w[1:]
16
+ S = S[1:]
17
+
18
+ fun = lambda om, Hs, Tp, gamma: jonswap(Hs, Tp, gamma, sigma=sigma)(om)
19
+ popt,__ = curve_fit(fun, w, S)
20
+ out = dict(Hs=popt[0], Tp=popt[1], gamma=popt[2], p0=[p0['Hs'], p0['Tp'], p0['gamma']])
21
+
22
+ return out
23
+
24
+ def onesided_to_twosided(omega, S, axis=-1):
25
+ S2 = 0.5*np.concatenate([np.flip(S, axis=axis), S], axis=axis)
26
+ omega2 = np.hstack([np.flip(-omega), omega])
27
+
28
+ return omega2, S2
29
+
30
+
31
+ def twosided_to_onesided(omega, S):
32
+ n_samples = len(omega)
33
+ return omega[:n_samples//2], S[:,:,:n_samples//2]
34
+
35
+
36
+ def ramp_up(Nramp, Ntot):
37
+ t_scale = np.ones(Ntot)
38
+ t_scale[:Nramp] = np.linspace(0, 1, Nramp)
39
+ return t_scale
40
+
41
+ def ramp_up_t(t, t0):
42
+ Nramp = np.sum(t<t0)
43
+ Ntot = len(t)
44
+
45
+ return ramp_up(Nramp, Ntot)