Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/oceanography/wave_dynamics.tex
51 views
unlisted
1
\documentclass[a4paper, 11pt]{article}
2
\usepackage[utf8]{inputenc}
3
\usepackage[T1]{fontenc}
4
\usepackage{amsmath, amssymb}
5
\usepackage{graphicx}
6
\usepackage{booktabs}
7
\usepackage{siunitx}
8
\usepackage[makestderr]{pythontex}
9
10
\title{Ocean Wave Dynamics: Dispersion, Spectra, and Coastal Processes}
11
\author{Physical Oceanography Templates}
12
\date{\today}
13
14
\begin{document}
15
\maketitle
16
17
\section{Introduction}
18
Ocean surface waves transport energy across vast distances and undergo transformations as they approach coastlines. This template covers wave dispersion relations, spectral representations, shoaling, and refraction processes.
19
20
\section{Mathematical Framework}
21
22
\subsection{Linear Wave Theory}
23
The surface elevation for a monochromatic wave:
24
\begin{equation}
25
\eta(x, t) = a \cos(kx - \omega t)
26
\end{equation}
27
28
\subsection{Dispersion Relation}
29
Deep water waves satisfy:
30
\begin{equation}
31
\omega^2 = gk \tanh(kh)
32
\end{equation}
33
In deep water ($kh \gg 1$): $\omega^2 = gk$, giving phase speed $c = \sqrt{g/k}$.
34
35
In shallow water ($kh \ll 1$): $\omega^2 = gk^2h$, giving $c = \sqrt{gh}$.
36
37
\subsection{Group Velocity}
38
Energy propagates at the group velocity:
39
\begin{equation}
40
c_g = \frac{\partial \omega}{\partial k} = \frac{c}{2}\left(1 + \frac{2kh}{\sinh(2kh)}\right)
41
\end{equation}
42
43
\subsection{Pierson-Moskowitz Spectrum}
44
Fully developed sea spectrum:
45
\begin{equation}
46
S(\omega) = \frac{\alpha g^2}{\omega^5} \exp\left[-\beta\left(\frac{\omega_0}{\omega}\right)^4\right]
47
\end{equation}
48
where $\alpha = 8.1 \times 10^{-3}$, $\beta = 0.74$, and $\omega_0 = g/U_{19.5}$.
49
50
\subsection{JONSWAP Spectrum}
51
Fetch-limited spectrum with peak enhancement:
52
\begin{equation}
53
S_J(\omega) = S_{PM}(\omega) \cdot \gamma^{\exp\left[-\frac{(\omega - \omega_p)^2}{2\sigma^2\omega_p^2}\right]}
54
\end{equation}
55
56
\subsection{Shoaling and Refraction}
57
Wave height transformation during shoaling:
58
\begin{equation}
59
\frac{H}{H_0} = \sqrt{\frac{c_{g0}}{c_g}} = K_s
60
\end{equation}
61
62
Snell's law for wave refraction:
63
\begin{equation}
64
\frac{\sin\theta}{c} = \frac{\sin\theta_0}{c_0}
65
\end{equation}
66
67
\section{Environment Setup}
68
69
\begin{pycode}
70
import numpy as np
71
import matplotlib.pyplot as plt
72
from scipy.optimize import fsolve
73
74
plt.rc('text', usetex=True)
75
plt.rc('font', family='serif')
76
np.random.seed(42)
77
78
def save_plot(filename, caption=""):
79
plt.savefig(filename, bbox_inches='tight', dpi=150)
80
print(r'\begin{figure}[htbp]')
81
print(r'\centering')
82
print(r'\includegraphics[width=0.9\textwidth]{' + filename + '}')
83
if caption:
84
print(r'\caption{' + caption + '}')
85
print(r'\end{figure}')
86
plt.close()
87
88
# Physical constants
89
g = 9.81 # Gravity (m/s^2)
90
\end{pycode}
91
92
\section{Dispersion Relation Analysis}
93
94
\begin{pycode}
95
def dispersion(omega, h):
96
"""Solve dispersion relation for wavenumber k"""
97
def equation(k):
98
return omega**2 - g * k * np.tanh(k * h)
99
100
k_deep = omega**2 / g # Deep water approximation
101
k = fsolve(equation, k_deep)[0]
102
return k
103
104
def phase_speed(k, h):
105
"""Phase speed from wavenumber and depth"""
106
return np.sqrt(g / k * np.tanh(k * h))
107
108
def group_speed(k, h):
109
"""Group velocity"""
110
c = phase_speed(k, h)
111
n = 0.5 * (1 + 2*k*h / np.sinh(2*k*h))
112
return n * c
113
114
# Calculate dispersion for various periods
115
periods = np.array([4, 6, 8, 10, 12, 15, 20]) # seconds
116
omega_vals = 2 * np.pi / periods
117
depths = np.linspace(5, 500, 100) # meters
118
119
# Store results
120
wavelengths = np.zeros((len(periods), len(depths)))
121
phase_speeds = np.zeros((len(periods), len(depths)))
122
group_speeds = np.zeros((len(periods), len(depths)))
123
124
for i, omega in enumerate(omega_vals):
125
for j, h in enumerate(depths):
126
k = dispersion(omega, h)
127
wavelengths[i, j] = 2 * np.pi / k
128
phase_speeds[i, j] = phase_speed(k, h)
129
group_speeds[i, j] = group_speed(k, h)
130
131
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
132
133
# Plot 1: Wavelength vs depth
134
for i, T in enumerate(periods):
135
axes[0, 0].plot(depths, wavelengths[i, :], label=f'T={T}s')
136
axes[0, 0].set_xlabel('Water Depth (m)')
137
axes[0, 0].set_ylabel('Wavelength (m)')
138
axes[0, 0].set_title('Wavelength vs Depth')
139
axes[0, 0].legend(fontsize=8)
140
axes[0, 0].grid(True, alpha=0.3)
141
axes[0, 0].set_xscale('log')
142
143
# Plot 2: Phase speed vs depth
144
for i, T in enumerate(periods):
145
axes[0, 1].plot(depths, phase_speeds[i, :], label=f'T={T}s')
146
# Deep water limit
147
axes[0, 1].axhline(y=np.sqrt(g * wavelengths[-1, -1] / (2*np.pi)),
148
color='k', linestyle='--', alpha=0.5)
149
axes[0, 1].set_xlabel('Water Depth (m)')
150
axes[0, 1].set_ylabel('Phase Speed (m/s)')
151
axes[0, 1].set_title('Phase Speed vs Depth')
152
axes[0, 1].legend(fontsize=8)
153
axes[0, 1].grid(True, alpha=0.3)
154
axes[0, 1].set_xscale('log')
155
156
# Plot 3: Group speed / Phase speed ratio
157
for i, T in enumerate(periods):
158
ratio = group_speeds[i, :] / phase_speeds[i, :]
159
axes[1, 0].plot(depths, ratio, label=f'T={T}s')
160
axes[1, 0].axhline(y=0.5, color='k', linestyle='--', alpha=0.5, label='Deep water')
161
axes[1, 0].axhline(y=1.0, color='k', linestyle=':', alpha=0.5, label='Shallow water')
162
axes[1, 0].set_xlabel('Water Depth (m)')
163
axes[1, 0].set_ylabel('$c_g / c$')
164
axes[1, 0].set_title('Group Speed / Phase Speed Ratio')
165
axes[1, 0].legend(fontsize=8)
166
axes[1, 0].grid(True, alpha=0.3)
167
axes[1, 0].set_xscale('log')
168
169
# Plot 4: Relative depth parameter kh
170
for i, T in enumerate(periods):
171
k = 2 * np.pi / wavelengths[i, :]
172
kh = k * depths
173
axes[1, 1].plot(depths, kh, label=f'T={T}s')
174
axes[1, 1].axhline(y=np.pi, color='k', linestyle='--', alpha=0.5, label='Deep water limit')
175
axes[1, 1].axhline(y=0.3, color='k', linestyle=':', alpha=0.5, label='Shallow water limit')
176
axes[1, 1].set_xlabel('Water Depth (m)')
177
axes[1, 1].set_ylabel('kh')
178
axes[1, 1].set_title('Relative Depth Parameter')
179
axes[1, 1].legend(fontsize=8)
180
axes[1, 1].grid(True, alpha=0.3)
181
axes[1, 1].set_xscale('log')
182
axes[1, 1].set_yscale('log')
183
184
plt.tight_layout()
185
save_plot('dispersion_relations.pdf', 'Wave dispersion characteristics')
186
\end{pycode}
187
188
\section{Wave Spectra}
189
190
\begin{pycode}
191
def pierson_moskowitz(omega, U):
192
"""Pierson-Moskowitz spectrum"""
193
alpha = 8.1e-3
194
beta = 0.74
195
omega_0 = g / U
196
S = (alpha * g**2 / omega**5) * np.exp(-beta * (omega_0 / omega)**4)
197
return S
198
199
def jonswap(omega, U, fetch, gamma=3.3):
200
"""JONSWAP spectrum"""
201
# Peak frequency
202
omega_p = 22 * (g**2 / (U * fetch))**0.333
203
204
# PM base spectrum
205
alpha = 0.076 * (U**2 / (fetch * g))**0.22
206
S_pm = (alpha * g**2 / omega**5) * np.exp(-1.25 * (omega_p / omega)**4)
207
208
# Peak enhancement
209
sigma = np.where(omega <= omega_p, 0.07, 0.09)
210
r = np.exp(-(omega - omega_p)**2 / (2 * sigma**2 * omega_p**2))
211
S_j = S_pm * gamma**r
212
213
return S_j, omega_p
214
215
# Wave conditions
216
U = 15 # Wind speed (m/s)
217
fetch_values = [100e3, 300e3, 1000e3] # Fetch distances (m)
218
219
omega = np.linspace(0.2, 2.5, 200) # Frequency range (rad/s)
220
221
# Calculate spectra
222
S_pm = pierson_moskowitz(omega, U)
223
224
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
225
226
# Plot 1: Pierson-Moskowitz spectrum
227
axes[0, 0].plot(omega, S_pm, 'b-', linewidth=2)
228
axes[0, 0].fill_between(omega, 0, S_pm, alpha=0.3)
229
axes[0, 0].set_xlabel('$\\omega$ (rad/s)')
230
axes[0, 0].set_ylabel('$S(\\omega)$ (m$^2$s/rad)')
231
axes[0, 0].set_title(f'Pierson-Moskowitz Spectrum (U={U} m/s)')
232
axes[0, 0].grid(True, alpha=0.3)
233
234
# Plot 2: JONSWAP spectra for different fetches
235
colors = ['blue', 'green', 'red']
236
for i, fetch in enumerate(fetch_values):
237
S_j, omega_p = jonswap(omega, U, fetch)
238
label = f'Fetch = {fetch/1e3:.0f} km'
239
axes[0, 1].plot(omega, S_j, color=colors[i], linewidth=2, label=label)
240
241
axes[0, 1].set_xlabel('$\\omega$ (rad/s)')
242
axes[0, 1].set_ylabel('$S(\\omega)$ (m$^2$s/rad)')
243
axes[0, 1].set_title('JONSWAP Spectra')
244
axes[0, 1].legend()
245
axes[0, 1].grid(True, alpha=0.3)
246
247
# Plot 3: Significant wave height vs fetch
248
fetches = np.linspace(50e3, 1000e3, 50)
249
Hs_values = []
250
Tp_values = []
251
252
for fetch in fetches:
253
S_j, omega_p = jonswap(omega, U, fetch)
254
# Significant wave height: Hs = 4 * sqrt(m0)
255
m0 = np.trapz(S_j, omega)
256
Hs = 4 * np.sqrt(m0)
257
Tp = 2 * np.pi / omega_p
258
Hs_values.append(Hs)
259
Tp_values.append(Tp)
260
261
axes[1, 0].plot(fetches/1e3, Hs_values, 'b-', linewidth=2)
262
axes[1, 0].set_xlabel('Fetch (km)')
263
axes[1, 0].set_ylabel('$H_s$ (m)')
264
axes[1, 0].set_title(f'Significant Wave Height Growth (U={U} m/s)')
265
axes[1, 0].grid(True, alpha=0.3)
266
267
# Plot 4: Peak period vs fetch
268
axes[1, 1].plot(fetches/1e3, Tp_values, 'r-', linewidth=2)
269
axes[1, 1].set_xlabel('Fetch (km)')
270
axes[1, 1].set_ylabel('$T_p$ (s)')
271
axes[1, 1].set_title('Peak Period Growth')
272
axes[1, 1].grid(True, alpha=0.3)
273
274
plt.tight_layout()
275
save_plot('wave_spectra.pdf', 'Ocean wave spectra and wave growth')
276
277
# Store for later use
278
final_Hs = Hs_values[-1]
279
final_Tp = Tp_values[-1]
280
\end{pycode}
281
282
\section{Random Sea Surface Simulation}
283
284
\begin{pycode}
285
# Generate random sea surface from spectrum
286
def generate_sea_surface(S, omega, x, t):
287
"""Generate sea surface elevation from spectrum"""
288
domega = omega[1] - omega[0]
289
amplitudes = np.sqrt(2 * S * domega)
290
phases = np.random.uniform(0, 2*np.pi, len(omega))
291
292
eta = np.zeros_like(x)
293
for i, om in enumerate(omega):
294
k = om**2 / g # Deep water
295
eta += amplitudes[i] * np.cos(k * x - om * t + phases[i])
296
297
return eta
298
299
# Generate surface
300
x = np.linspace(0, 1000, 500) # 1 km domain
301
t_values = [0, 5, 10, 15] # Time snapshots
302
303
# Use JONSWAP spectrum
304
S_j, omega_p = jonswap(omega, U, 300e3)
305
306
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
307
308
# Plot 1-4: Sea surface at different times
309
for idx, t in enumerate(t_values):
310
ax = axes[idx // 2, idx % 2]
311
eta = generate_sea_surface(S_j, omega, x, t)
312
ax.plot(x, eta, 'b-', linewidth=1)
313
ax.fill_between(x, 0, eta, where=(eta > 0), alpha=0.3, color='blue')
314
ax.fill_between(x, eta, 0, where=(eta < 0), alpha=0.3, color='blue')
315
ax.axhline(y=0, color='k', linestyle='-', linewidth=0.5)
316
ax.set_xlabel('x (m)')
317
ax.set_ylabel('$\\eta$ (m)')
318
ax.set_title(f't = {t} s')
319
ax.set_ylim(-5, 5)
320
ax.grid(True, alpha=0.3)
321
322
plt.tight_layout()
323
save_plot('sea_surface.pdf', 'Random sea surface time evolution')
324
\end{pycode}
325
326
\section{Wave Shoaling and Refraction}
327
328
\begin{pycode}
329
# Shoaling transformation
330
h_deep = 100 # Deep water depth
331
h_shallow = np.linspace(100, 2, 100)
332
333
T = 10 # Wave period
334
omega_wave = 2 * np.pi / T
335
k_deep = omega_wave**2 / g
336
L_deep = 2 * np.pi / k_deep
337
H_deep = 2 # Deep water wave height (m)
338
339
# Calculate shoaling coefficient
340
Ks_values = []
341
k_values = []
342
c_values = []
343
cg_values = []
344
345
for h in h_shallow:
346
k = dispersion(omega_wave, h)
347
c = phase_speed(k, h)
348
cg = group_speed(k, h)
349
cg_deep = group_speed(k_deep, h_deep)
350
351
Ks = np.sqrt(cg_deep / cg)
352
Ks_values.append(Ks)
353
k_values.append(k)
354
c_values.append(c)
355
cg_values.append(cg)
356
357
Ks_values = np.array(Ks_values)
358
H_shoaled = H_deep * Ks_values
359
360
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
361
362
# Plot 1: Shoaling coefficient
363
axes[0, 0].plot(h_shallow, Ks_values, 'b-', linewidth=2)
364
axes[0, 0].set_xlabel('Water Depth (m)')
365
axes[0, 0].set_ylabel('$K_s$')
366
axes[0, 0].set_title('Shoaling Coefficient')
367
axes[0, 0].grid(True, alpha=0.3)
368
axes[0, 0].invert_xaxis()
369
370
# Plot 2: Wave height transformation
371
axes[0, 1].plot(h_shallow, H_shoaled, 'r-', linewidth=2)
372
axes[0, 1].axhline(y=H_deep, color='k', linestyle='--', label=f'$H_0$ = {H_deep} m')
373
axes[0, 1].set_xlabel('Water Depth (m)')
374
axes[0, 1].set_ylabel('Wave Height (m)')
375
axes[0, 1].set_title('Wave Height During Shoaling')
376
axes[0, 1].legend()
377
axes[0, 1].grid(True, alpha=0.3)
378
axes[0, 1].invert_xaxis()
379
380
# Plot 3: Wave refraction
381
# Beach with varying depth
382
nx, ny = 100, 50
383
x_beach = np.linspace(0, 2000, nx)
384
y_beach = np.linspace(-500, 500, ny)
385
X_beach, Y_beach = np.meshgrid(x_beach, y_beach)
386
387
# Depth decreases toward shore (linear beach)
388
h_beach = 50 - 0.025 * X_beach
389
h_beach = np.maximum(h_beach, 0.5)
390
391
# Calculate wave crests (refraction)
392
# Waves approaching at angle
393
theta_deep = np.radians(30) # 30 degree approach angle
394
395
# Calculate local angle using Snell's law
396
c_deep = np.sqrt(g * h_beach.max())
397
c_local = np.sqrt(g * h_beach * np.tanh(k_deep * h_beach) / k_deep)
398
theta_local = np.arcsin(np.clip(c_local / c_deep * np.sin(theta_deep), -1, 1))
399
400
# Wave crest positions
401
im = axes[1, 0].contourf(X_beach, Y_beach, h_beach, levels=20, cmap='Blues_r')
402
axes[1, 0].contour(X_beach, Y_beach, h_beach, levels=10, colors='white', linewidths=0.5)
403
axes[1, 0].set_xlabel('Distance offshore (m)')
404
axes[1, 0].set_ylabel('Alongshore (m)')
405
axes[1, 0].set_title('Bathymetry')
406
plt.colorbar(im, ax=axes[1, 0], label='Depth (m)')
407
408
# Plot 4: Refraction diagram
409
# Draw wave rays
410
for y0 in np.linspace(-400, 400, 9):
411
ray_x = [0]
412
ray_y = [y0]
413
x_curr = 0
414
y_curr = y0
415
theta_curr = theta_deep
416
ds = 20 # Step size
417
418
while x_curr < 1900:
419
# Get local depth
420
j = int(np.clip(x_curr / x_beach[-1] * (nx-1), 0, nx-1))
421
h_local = 50 - 0.025 * x_curr
422
h_local = max(h_local, 0.5)
423
424
# Local phase speed
425
c_loc = np.sqrt(g * h_local * np.tanh(k_deep * h_local) / k_deep)
426
427
# Update angle (Snell's law)
428
sin_theta = c_loc / c_deep * np.sin(theta_deep)
429
if abs(sin_theta) <= 1:
430
theta_curr = np.arcsin(sin_theta)
431
else:
432
break
433
434
# Step forward
435
x_curr += ds * np.cos(theta_curr)
436
y_curr += ds * np.sin(theta_curr)
437
ray_x.append(x_curr)
438
ray_y.append(y_curr)
439
440
axes[1, 1].plot(ray_x, ray_y, 'b-', linewidth=0.8, alpha=0.7)
441
442
axes[1, 1].contour(X_beach, Y_beach, h_beach, levels=[5, 10, 20, 30, 40],
443
colors='gray', linewidths=0.5)
444
axes[1, 1].set_xlabel('Distance offshore (m)')
445
axes[1, 1].set_ylabel('Alongshore (m)')
446
axes[1, 1].set_title(f'Wave Refraction (approach angle = {np.degrees(theta_deep):.0f}$^\\circ$)')
447
axes[1, 1].set_xlim(0, 2000)
448
axes[1, 1].set_ylim(-500, 500)
449
450
plt.tight_layout()
451
save_plot('shoaling_refraction.pdf', 'Wave shoaling and refraction')
452
453
max_Hs_shoaled = np.max(H_shoaled)
454
\end{pycode}
455
456
\section{Breaking Wave Criterion}
457
458
\begin{pycode}
459
# Wave breaking analysis
460
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
461
462
# McCowan breaking criterion: H/h = 0.78
463
# Miche breaking criterion: H/L = 0.142 tanh(kh)
464
465
depths_break = np.linspace(1, 20, 100)
466
467
# Maximum wave height before breaking
468
Hb_mccowan = 0.78 * depths_break
469
470
# Breaking wave height for different periods
471
for T_break in [6, 8, 10, 12]:
472
omega_b = 2 * np.pi / T_break
473
Hb_miche = []
474
for h in depths_break:
475
k = dispersion(omega_b, h)
476
L = 2 * np.pi / k
477
H_max = 0.142 * L * np.tanh(k * h)
478
Hb_miche.append(H_max)
479
axes[0].plot(depths_break, Hb_miche, label=f'T={T_break}s')
480
481
axes[0].plot(depths_break, Hb_mccowan, 'k--', linewidth=2, label='McCowan')
482
axes[0].set_xlabel('Water Depth (m)')
483
axes[0].set_ylabel('Breaking Wave Height (m)')
484
axes[0].set_title('Breaking Wave Height Limits')
485
axes[0].legend()
486
axes[0].grid(True, alpha=0.3)
487
488
# Breaker type parameter
489
# Surf similarity parameter: xi = tan(beta) / sqrt(H/L)
490
slopes = np.linspace(0.01, 0.15, 100)
491
H_break = 2 # m
492
L_break = 100 # m (approx for T=8s)
493
494
xi = slopes / np.sqrt(H_break / L_break)
495
496
axes[1].plot(slopes, xi, 'b-', linewidth=2)
497
axes[1].axhline(y=0.5, color='r', linestyle='--', label='Spilling (< 0.5)')
498
axes[1].axhline(y=3.3, color='g', linestyle='--', label='Surging (> 3.3)')
499
axes[1].fill_between(slopes, 0.5, 3.3, alpha=0.2, color='yellow', label='Plunging')
500
axes[1].set_xlabel('Beach Slope')
501
axes[1].set_ylabel('Surf Similarity $\\xi$')
502
axes[1].set_title('Breaker Type Classification')
503
axes[1].legend()
504
axes[1].grid(True, alpha=0.3)
505
506
plt.tight_layout()
507
save_plot('wave_breaking.pdf', 'Wave breaking criteria and breaker types')
508
\end{pycode}
509
510
\section{Results Summary}
511
512
\subsection{Wave Properties}
513
\begin{pycode}
514
print(r'\begin{table}[htbp]')
515
print(r'\centering')
516
print(r'\caption{Wave characteristics for T=10s}')
517
print(r'\begin{tabular}{lcc}')
518
print(r'\toprule')
519
print(r'Property & Deep Water & Shallow (10m) \\')
520
print(r'\midrule')
521
522
# Deep water values
523
L_d = g * 10**2 / (2 * np.pi)
524
c_d = g * 10 / (2 * np.pi)
525
cg_d = c_d / 2
526
527
# Shallow water values (h=10m)
528
k_s = dispersion(omega_wave, 10)
529
L_s = 2 * np.pi / k_s
530
c_s = phase_speed(k_s, 10)
531
cg_s = group_speed(k_s, 10)
532
533
print(f"Wavelength (m) & {L_d:.1f} & {L_s:.1f} \\\\")
534
print(f"Phase speed (m/s) & {c_d:.1f} & {c_s:.1f} \\\\")
535
print(f"Group speed (m/s) & {cg_d:.1f} & {cg_s:.1f} \\\\")
536
print(r'\bottomrule')
537
print(r'\end{tabular}')
538
print(r'\end{table}')
539
\end{pycode}
540
541
\subsection{Spectral Parameters}
542
\begin{pycode}
543
print(r'\begin{table}[htbp]')
544
print(r'\centering')
545
print(r'\caption{Wave spectrum characteristics}')
546
print(r'\begin{tabular}{lr}')
547
print(r'\toprule')
548
print(r'Parameter & Value \\')
549
print(r'\midrule')
550
print(f"Wind speed & {U} m/s \\\\")
551
print(f"Significant wave height & {final_Hs:.2f} m \\\\")
552
print(f"Peak period & {final_Tp:.1f} s \\\\")
553
print(f"Maximum fetch & {fetches[-1]/1e3:.0f} km \\\\")
554
print(r'\bottomrule')
555
print(r'\end{tabular}')
556
print(r'\end{table}')
557
\end{pycode}
558
559
\subsection{Coastal Transformation}
560
\begin{pycode}
561
print(r'\begin{table}[htbp]')
562
print(r'\centering')
563
print(r'\caption{Wave transformation during shoaling}')
564
print(r'\begin{tabular}{lr}')
565
print(r'\toprule')
566
print(r'Parameter & Value \\')
567
print(r'\midrule')
568
print(f"Deep water height & {H_deep:.1f} m \\\\")
569
print(f"Maximum shoaled height & {max_Hs_shoaled:.2f} m \\\\")
570
print(f"Maximum shoaling coefficient & {np.max(Ks_values):.2f} \\\\")
571
print(f"Refraction angle (deep) & {np.degrees(theta_deep):.0f}$^\\circ$ \\\\")
572
print(r'\bottomrule')
573
print(r'\end{tabular}')
574
print(r'\end{table}')
575
\end{pycode}
576
577
\subsection{Physical Summary}
578
\begin{itemize}
579
\item Deep water wavelength (T=10s): \py{f"{L_d:.1f}"} m
580
\item JONSWAP $H_s$: \py{f"{final_Hs:.2f}"} m
581
\item Maximum shoaling coefficient: \py{f"{np.max(Ks_values):.2f}"}
582
\item Approach angle: \py{f"{np.degrees(theta_deep):.0f}"} degrees
583
\end{itemize}
584
585
\section{Conclusion}
586
This template demonstrates fundamental ocean wave dynamics. The dispersion relation governs how wave properties vary with depth, transitioning from deep to shallow water behavior. Spectral representations (Pierson-Moskowitz, JONSWAP) describe the energy distribution in random seas and wave growth with fetch. Shoaling causes wave height to increase as waves approach shore, while refraction bends wave crests to align with depth contours. These processes are essential for coastal engineering and understanding surf zone dynamics.
587
588
\end{document}
589
590