wawi 0.0.1__py3-none-any.whl → 0.0.5__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
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)