python4oceanographers

Turning ripples into waves

Snell-Descartes Law

(Updating my Waves and Tides laboratory lecture on Snell-Descartes Law. This post was written in Portuguese.)

Altura e direção de onda usando a lei de snell e batimetria realística

Região do estudo

Utilizaremos a lei de snell-descartes para estudar o ângulo de refração e a altura de ondas na praia de Santos. Podemos observar tais transformações na imagem retirar do Google-Earth abaixo. Mas notem que teremos também os efeitos da difração e interferência de ondas oriundas da ilha ao lado. Adicionalmente, nosso modelo não resolve os efeitos não-lineares!!!

In [2]:
from IPython.display import Image
Image('./data/perfis.png', retina=True)
Out[2]:

Esse bloco apenas lê os dados da planilha do Excel dos alunos, converte a batimetria para metros, e inverte o sinal (o modelo usa com "h" positivo).

In [3]:
from pandas import read_excel

xls = -1e-2 * read_excel('./data/batimetria.xlsx', sheetname='Plan1', skiprows=1, index_col=0, parse_cols=(0, 1, 4, 7))
xls.index.name = 'Distance [m]'
xls.columns = ['T1', 'T2', 'T3']
xls
Out[3]:
T1 T2 T3
Distance [m]
0 -0.00 -0.00 -0.00
6 0.08 0.06 0.11
12 0.12 0.20 0.14
18 0.14 0.23 0.17
24 0.15 0.25 0.23
30 0.22 0.29 0.28
36 0.27 0.31 0.33
42 0.29 0.42 0.49
48 0.36 0.49 0.51
54 0.40 0.51 0.60
60 0.44 0.62 0.67
66 0.47 0.70 0.81
72 0.56 0.78 0.92
78 0.58 0.82 1.00
84 0.65 0.90 1.06
90 0.70 0.98 1.10
96 0.72 1.00 1.12
102 0.77 1.02 1.19
108 0.80 1.07 1.25
114 0.82 1.15 1.32
120 0.85 1.22 NaN
126 0.85 1.30 NaN
132 0.80 1.35 NaN

Observe como o perfil T1 tem um gradiente mais suave que os T2 e T3.

In [4]:
ax = xls.plot()
ax.invert_yaxis()
_ = ax.set_ylabel('Depth [m]')

O modelo

In [5]:
import numpy as np
import numpy.ma as ma

# Constantes.
g = 9.81
twopi = 2 * np.pi
    
# Relação de dispersão (Resolvida pelo método de Newton-Raphson).
def dispersion_relationship(T, h, Ho, thetao):
    T, h, Ho, thetao = np.broadcast_arrays(T, h, Ho, thetao)
    omega = twopi / T
    Lo = (g * T ** 2) / twopi
    # Começa pela relação de dispersão de águas profundas.
    k = omega / np.sqrt(g)
    # Vamos aproximando por incrementos de "f".
    f = g * k * np.tanh(k * h) - omega ** 2
    while np.abs(f.max()) > 1e-7:
        dfdk = (g * k * h * (1 / (np.cosh(k * h))) ** 2 + g * np.tanh(k * h))
        k = k - f / dfdk
        f = g * k * np.tanh(k * h) - omega ** 2

    # Com o número de onda resolvido podemos calcular:
    L = twopi / k
    C = omega / k
    Co = Lo / T
    G = 2 * k * h / np.sinh(2 * k * h)
    
    # Aqui é basicamente a lei de Snell e o shoaling.
    theta = np.rad2deg(np.arcsin(C / Co * np.sin(np.deg2rad(thetao))))
    Kr = np.sqrt(np.cos(np.deg2rad(thetao)) / np.cos(np.deg2rad(theta)))
    Ks = np.sqrt(1 / (1 + G) / np.tanh(k * h))
    H = Ho * Ks * Kr
    # Retorna Altura de onda e ângulo.
    return map(ma.asanyarray, (theta, H))

Rodando o modelo

No modelo temos que entrar com,

  • T: Período de onda típico;
  • h: Batimetria que vocês mediram;
  • Ho: Altura de onda inicial;
  • thetao: Angulo de incidência das ondas.
In [6]:
T = 5.  # Segundos.
h = np.fliplr(np.flipud(xls.values)[3:,:])  # Começa no mais fundo até a costa.
Ho = 0.1  # Metros.
thetao = 45  # Graus.

rows, cols = h.shape

theta, H = [], []
for row in range(rows):
    thetao, Ho = dispersion_relationship(T=T, h=h[row, :], Ho=Ho, thetao=thetao)
    H.append(Ho)
    theta.append(thetao)
    
H = np.array(H)
theta = np.array(theta)

Plotando os resultados

In [7]:
import matplotlib.pyplot as plt

cmap = plt.cm.BrBG
x = np.arange(3)
y = xls.index.values[:-3]

fig, (ax0, ax1, ax2) = plt.subplots(ncols=3, sharex=True, sharey=True, figsize=(12, 4))
cs0 = ax0.pcolorfast(x, y, h, cmap=cmap)
fig.colorbar(cs0, ax=ax0, extend='both')
ax0.set_title('Batimetria [m]')
ax0.set_xlabel('Perfil [sem unidade]')

cs1 = ax1.pcolorfast(x, y, H, vmax=1., vmin=0.1, cmap=cmap)
fig.colorbar(cs1, ax=ax1, extend='both')
ax1.set_ylabel(u'Distância [m]')
ax1.set_title('Altura de onda [m]')

cs2 = ax2.pcolorfast(x, y, theta, vmax=20, vmin=0, cmap=cmap)
fig.colorbar(cs2, ax=ax2, extend='both')
_ = ax2.set_title(u'Ângulo [graus]')
In [8]:
HTML(html)
Out[8]:

This post was written as an IPython notebook. It is available for download or as a static html.

Creative Commons License
python4oceanographers by Filipe Fernandes is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://ocefpaf.github.io/.

Comments