5. Notebook exercise: Converting a JONSWAP spectrum into a time series#
In this interactive notebook you will try to convert a JONSWAP spectrum into a time series \(\eta(t)\). For this, you will use the MHKiT package.
Click –> Live Code on the top right corner of this screen and then wait until all cells are executed.
!pip install mhkit
import numpy as np
import matplotlib.pyplot as plt
class Cyl:
def __init__(self, x0, z0, R, dth):
thMat = np.arange(0, 360, dth) #deg
cx = x0 + R*np.cos( np.deg2rad(thMat) )
cz = z0 + R*np.sin( np.deg2rad(thMat) )
self.R = R
self.D = 2*R
self.x0 = x0
self.z0 = z0
self.cx = cx
self.cz = cz
self.NodeC = [ [x, z] for x,z in zip (cx, cz) ]
self.nNode = len(self.NodeC)
self.Ele = [ [n1, n2] for n1,n2 in
zip( range(0,self.nNode-1), range(1,self.nNode)) ]
self.Ele.append([self.nNode-1, 0])
self.nEle = len(self.Ele)
self.P = np.zeros(self.nNode)
def plotEle(self):
for iEle in range(0,self.nEle):
n1, n2 = self.Ele[iEle]
n1 = int(round(n1))
n2 = int(round(n2))
plt.plot( [self.NodeC[n1][0], self.NodeC[n2][0]],
[self.NodeC[n1][1], self.NodeC[n2][1]],
lw=3, color='k')
Requirement already satisfied: mhkit in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (0.9.0)
Requirement already satisfied: numpy>=2.0.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2.2.5)
Requirement already satisfied: pandas>=2.2.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2.2.3)
Requirement already satisfied: scipy>=1.14.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (1.15.2)
Requirement already satisfied: xarray>=2024.6.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2025.4.0)
Requirement already satisfied: matplotlib>=3.9.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (3.10.1)
Requirement already satisfied: scikit-learn>=1.5.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (1.6.1)
Requirement already satisfied: h5py>=3.11.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (3.13.0)
Requirement already satisfied: h5pyd>=0.18.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (0.21.0)
Requirement already satisfied: netCDF4>=1.7.1.post1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (1.7.2)
Requirement already satisfied: statsmodels>=0.14.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (0.14.4)
Requirement already satisfied: requests in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2.32.3)
Requirement already satisfied: pecos>=0.3.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (1.0.0)
Requirement already satisfied: fatpack in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (0.7.8)
Requirement already satisfied: NREL-rex>=0.2.63 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (0.3.2)
Requirement already satisfied: pytz in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2025.2)
Requirement already satisfied: beautifulsoup4 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (4.13.4)
Requirement already satisfied: numexpr>=2.10.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (2.10.2)
Requirement already satisfied: lxml in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (5.4.0)
Requirement already satisfied: bottleneck in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from mhkit) (1.4.2)
Requirement already satisfied: requests_unixsocket in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from h5pyd>=0.18.0->mhkit) (0.4.1)
Requirement already satisfied: pyjwt in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from h5pyd>=0.18.0->mhkit) (2.10.1)
Requirement already satisfied: packaging in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from h5pyd>=0.18.0->mhkit) (24.2)
Requirement already satisfied: contourpy>=1.0.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (1.3.2)
Requirement already satisfied: cycler>=0.10 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (4.57.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (1.4.8)
Requirement already satisfied: pillow>=8 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (11.1.0)
Requirement already satisfied: pyparsing>=2.3.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (3.2.3)
Requirement already satisfied: python-dateutil>=2.7 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from matplotlib>=3.9.1->mhkit) (2.9.0.post0)
Requirement already satisfied: cftime in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from netCDF4>=1.7.1.post1->mhkit) (1.6.4)
Requirement already satisfied: certifi in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from netCDF4>=1.7.1.post1->mhkit) (2025.11.12)
Requirement already satisfied: click<9,>=8.1.8 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (8.1.8)
Requirement already satisfied: fsspec<2025,>=2021.09.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (2023.12.2)
Requirement already satisfied: dask<2025,>=2024.8.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (2024.12.1)
Requirement already satisfied: psutil<8,>=7.0.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (7.0.0)
Requirement already satisfied: PyYAML<7,>=6.0.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (6.0.2)
Requirement already satisfied: s3fs<2024,>=2023.6.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (2023.12.2)
Requirement already satisfied: toml<0.11,>=0.10.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from NREL-rex>=0.2.63->mhkit) (0.10.2)
Requirement already satisfied: tzdata>=2022.7 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from pandas>=2.2.2->mhkit) (2025.2)
Requirement already satisfied: jinja2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from pecos>=0.3.0->mhkit) (3.1.6)
Requirement already satisfied: pytest in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from pecos>=0.3.0->mhkit) (8.3.5)
Requirement already satisfied: joblib>=1.2.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from scikit-learn>=1.5.1->mhkit) (1.5.0)
Requirement already satisfied: threadpoolctl>=3.1.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from scikit-learn>=1.5.1->mhkit) (3.6.0)
Requirement already satisfied: patsy>=0.5.6 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from statsmodels>=0.14.2->mhkit) (1.0.1)
Requirement already satisfied: soupsieve>1.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from beautifulsoup4->mhkit) (2.7)
Requirement already satisfied: typing-extensions>=4.0.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from beautifulsoup4->mhkit) (4.13.2)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from requests->mhkit) (3.4.2)
Requirement already satisfied: idna<4,>=2.5 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from requests->mhkit) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from requests->mhkit) (2.4.0)
Requirement already satisfied: cloudpickle>=3.0.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from dask<2025,>=2024.8.0->NREL-rex>=0.2.63->mhkit) (3.1.1)
Requirement already satisfied: partd>=1.4.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from dask<2025,>=2024.8.0->NREL-rex>=0.2.63->mhkit) (1.4.2)
Requirement already satisfied: toolz>=0.10.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from dask<2025,>=2024.8.0->NREL-rex>=0.2.63->mhkit) (1.0.0)
Requirement already satisfied: six>=1.5 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from python-dateutil>=2.7->matplotlib>=3.9.1->mhkit) (1.17.0)
Requirement already satisfied: aiobotocore<3.0.0,>=2.5.4 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (2.22.0)
Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (3.11.18)
Requirement already satisfied: MarkupSafe>=2.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from jinja2->pecos>=0.3.0->mhkit) (3.0.2)
Requirement already satisfied: iniconfig in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from pytest->pecos>=0.3.0->mhkit) (2.1.0)
Requirement already satisfied: pluggy<2,>=1.5 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from pytest->pecos>=0.3.0->mhkit) (1.5.0)
Requirement already satisfied: aioitertools<1.0.0,>=0.5.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (0.12.0)
Requirement already satisfied: botocore<1.37.4,>=1.37.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.37.3)
Requirement already satisfied: jmespath<2.0.0,>=0.7.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.0.1)
Requirement already satisfied: multidict<7.0.0,>=6.0.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (6.4.3)
Requirement already satisfied: wrapt<2.0.0,>=1.10.10 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiobotocore<3.0.0,>=2.5.4->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.17.2)
Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (2.6.1)
Requirement already satisfied: aiosignal>=1.1.2 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.3.2)
Requirement already satisfied: attrs>=17.3.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (25.3.0)
Requirement already satisfied: frozenlist>=1.1.1 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.6.0)
Requirement already satisfied: propcache>=0.2.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (0.3.1)
Requirement already satisfied: yarl<2.0,>=1.17.0 in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->s3fs<2024,>=2023.6.0->NREL-rex>=0.2.63->mhkit) (1.20.0)
Requirement already satisfied: locket in /opt/miniconda3/envs/prob_design_25/lib/python3.12/site-packages (from partd>=1.4.0->dask<2025,>=2024.8.0->NREL-rex>=0.2.63->mhkit) (1.0.0)
5.1. 1. Generate a wave spectrum using MHKiT#
Hint: use the mhkit.wave.resource.jonswap_spectrum() package
def get_spec(w, Tp, Hs):
q = # your code here
return q.to_numpy()/2/ np.pi
Cell In[2], line 2
q = # your code here
^
SyntaxError: invalid syntax
Hm0 = 8.0 # Significant wave height [m]
Tp = 10.0 # Peak period [s]
omega = # your code here
S = # your code here
plt.plot(omega, S)
plt.show()
5.2. 2. Get the amplitude spectrum for the power spectral density function#
Definition of single-sided power spectral density function is given by $\( \sum_f^{f+\Delta f} \frac{1}{2} a_n^2 = S_n(f) \Delta f \quad \)\( PSDF has a unit of \)m^2 \cdot s$
The single-sided amplitude spectrum is given by $\( a_n(f) = \sqrt{2 S_n(f) \Delta f} \)$
Here S.args\(= \omega\) and S.data= Spectral density value
def getAmpSPEC(omega, E, iseed=None):
df = # your code here # Frequency band width
A = # your code here
n_omega = len(omega)
# Seed for random phase
if iseed is not None:
try:
np.random.set_state(iseed)
except (KeyError, TypeError):
np.random.seed(iseed)
ph = np.random.rand(n_omega) * 2 * np.pi - np.pi
return A[2:], omega[2:], ph[2:]
Cell In[7], line 2
df = # your code here # Frequency band width
^
SyntaxError: invalid syntax
A, omega, ph = getAmpSpec(omega, S, iseed=123)
# A, w, ph = getAmpSpec(spec, ns//2+1, iseed=123)
fig, ax = plt.subplots(1,1)
plt.plot(omega, A, color='r')
plt.title('Statistical amplitude spectrum')
plt.xlabel('$\omega$ (rad/s)')
plt.ylabel('$\eta_0$ (m)')
plt.grid('on')
plt.show()
<>:7: SyntaxWarning: invalid escape sequence '\o'
<>:8: SyntaxWarning: invalid escape sequence '\e'
<>:7: SyntaxWarning: invalid escape sequence '\o'
<>:8: SyntaxWarning: invalid escape sequence '\e'
/var/folders/4r/myg3jzhx1yd72kbqs5r4rv2w0000gn/T/ipykernel_66684/782426865.py:7: SyntaxWarning: invalid escape sequence '\o'
plt.xlabel('$\omega$ (rad/s)')
/var/folders/4r/myg3jzhx1yd72kbqs5r4rv2w0000gn/T/ipykernel_66684/782426865.py:8: SyntaxWarning: invalid escape sequence '\e'
plt.ylabel('$\eta_0$ (m)')
/var/folders/4r/myg3jzhx1yd72kbqs5r4rv2w0000gn/T/ipykernel_66684/782426865.py:7: SyntaxWarning: invalid escape sequence '\o'
plt.xlabel('$\omega$ (rad/s)')
/var/folders/4r/myg3jzhx1yd72kbqs5r4rv2w0000gn/T/ipykernel_66684/782426865.py:8: SyntaxWarning: invalid escape sequence '\e'
plt.ylabel('$\eta_0$ (m)')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 A, omega, ph = getAmpSpec(omega, S, iseed=123)
2 # A, w, ph = getAmpSpec(spec, ns//2+1, iseed=123)
4 fig, ax = plt.subplots(1,1)
NameError: name 'getAmpSpec' is not defined
5.3. 3. Calculate the elevation profile#
We use LinearWave2D class from LinearWave package for defining the linear wave and the associated particle velocity, acceleration and pressure fields.
The linear wave theory only calculate the pressure and velocities for \(z<=0\).
In order to calculate the values for \(z>0\) we use
For Pressure: Taylor series expansion, limited to first order
For Velocities: Wheeler stretching link
We initiate LineaerWave object using amplitudes from JONSWAP spectrum and random phase. This will be used for obtaining the elevation, velocity and acceleration time-series for calculating the forces.
We have two classes
LinearWave2D: Class to define wave in shallow waterwv = LinearWave2D(rhoW, g, d, T, H)rhoW: Density of waterg: acceleration due to gravityd: still-water depthT: Wave time-periodH: Wave-height
LinearWaveDeep2D: Class to define wave in deep waterwv = LinearWave2D(rhoW, g, T, H)rhoW: Density of waterg: acceleration due to gravityT: Wave time-periodH: Wave-height
Location in 2D space is defined as (x,z)
The time instant is t
wv.waveElevation(t,x): Wave elevation at a given xwv.pressureTot(t,x,z): Total pressure (static + dynamic pressure)wv.pressureDyn(t,x,z): Dynamic pressurewv.particleVelPoi(t,x,z): Wave particle vel at (x,z) at time-instant twv.particleAccPoi(t,x,z): Wave particle acceleration at (x,z) at time-instant twv.particleVelMax(t,x,z): Maximum of wave particle vel at location (x,z)wv.particleAccMax(t,x,z): Maximum of wave particle acceleration at location (x,z)
Here wv can be an object of LinearWave2D or LinearWaveDeep2D
from LinearWave import LinearWave2D
from LinearWave import LinearWaveDeep2D
# Wave(g, d, T, H, phi=0, x0=0)
d = 187 #m (still-water depth)
rhoW = 1025
g = 9.81
cyl1 = Cyl(10, -20, 5, 0.1)
wvAll = [ LinearWaveDeep2D(rhoW, g, 2*np.pi/wi, 2*Ai, phi, msg=False) for wi,Ai,phi in zip(w,A,ph) ]
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[8], line 1
----> 1 from LinearWave import LinearWave2D
2 from LinearWave import LinearWaveDeep2D
4 # Wave(g, d, T, H, phi=0, x0=0)
ModuleNotFoundError: No module named 'LinearWave'
def spec2ts(wvListIn, x0, z0, t):
nt = len(t)
et_t = np.zeros(nt) # wave elevation time series
vx_t = np.zeros(nt) # horizontal particle velocity time series
vz_t = np.zeros(nt) # vertical particle velocity time series
vm_t = np.zeros(nt) # Velocity magnitude time series
ax_t = np.zeros(nt) # Horizontal particle acceleration time series
az_t = np.zeros(nt) # Vertical particle acceleration time series
for i, ti in enumerate(t):
et_t[i] = sum([wv.waveElevation(ti, x0) for wv in wvListIn])
vel = np.array([wv.particleVelPoi(ti, x0, z0) for wv in wvListIn])
vx_t[i] = np.sum(vel[:, 0])
vz_t[i] = np.sum(vel[:, 1])
vm_t[i] = np.sqrt( vx_t[i]**2 + vz_t[i]**2 )
acc = np.array([wv.particleAccPoi(ti, x0, z0) for wv in wvListIn])
ax_t[i] = np.sum(acc[:, 0])
az_t[i] = np.sum(acc[:, 1])
return et_t, vx_t, vz_t, vm_t, ax_t, az_t
fig, ax = plt.subplots(1,1)
plt.plot(t_t, et_t, color='r')
plt.title('Wave Elevation')
plt.xlabel('t (s)')
plt.ylabel('$\eta$ (m)')
plt.grid('on')
fig, ax = plt.subplots(1,1)
plt.plot(t_t, vx_t, color='r', label='vx')
plt.plot(t_t, vz_t, color='b', label='vz')
plt.plot(t_t, vm_t, color='g', label='vMag')
plt.title('Vel')
plt.xlabel('t (s)')
plt.ylabel('v (m/s)')
plt.grid('on')
plt.legend()
fig, ax = plt.subplots(1,1)
plt.plot(t_t, ax_t, color='r', label='ax')
plt.plot(t_t, az_t, color='b', label='az')
plt.title('Acc')
plt.xlabel('t (s)')
plt.ylabel('$\dot{v}$ (m/s2)')
plt.grid('on')
plt.legend()
plt.show()