Python library for ocean wave spectra.
- SpecArray: extends xarray's DataArray with methods to manipulate wave spectra and calculate spectral statistics.
- SpecDataset: wrapper around SpecArray with methods for saving spectra in different formats.
The documentation is hosted on ReadTheDocs at https://wavespectra-metocean.readthedocs.io.
The source code is hosted on GitHub at https://github.com/metocean/wavespectra.
Clone the repository and navigate to its root directory:
git clone https://github.com/metocean/wavespectra.git
cd wavespectraCreate a Python 3.9 environment:
uv venv --python 3.9
source .venv/bin/activateInstall the Fortran compiler required to build spectral partitioning. On Debian or Ubuntu:
sudo apt install gcc gfortranFor a non-editable installation with all optional dependencies:
uv sync --no-editable --all-extrasThe metocean extra installs cfjson from GitHub over HTTPS. To omit that
dependency, install the public optional and test dependencies instead:
uv sync --no-editable --extra extra --extra testRun the tests:
pytestFor an editable installation, first install the legacy build tools:
uv pip install "setuptools<65" wheel "numpy>=1.23.5,<2.0" "pip==22.3.1"
SETUPTOOLS_ENABLE_FEATURES="legacy-editable" .venv/bin/pip install -e ".[extra,test,metocean]" --no-build-isolation --disable-pip-version-checkRun the tests with pytest after an editable installation.
Currently there are some issues with the Fortran version of spectral partitioning in Windows systems. A workaround is described in: #28 (comment)
The two main classes SpecArray and SpecDataset are defined as xarray accessors. The accessors are registered on xarray's DataArray and Dataset respectively as a new namespace called spec.
To use methods in the accessor classes simply import the classes into your code and they will be available to your xarray.Dataset or xarray.DataArray instances through the spec attribute, e.g.
import datetime
import numpy as np
import xarray as xr
from wavespectra.specarray import SpecArray
from wavespectra.specdataset import SpecDataset
coords = {'time': [datetime.datetime(2017,01,n+1) for n in range(2)],
'freq': [0.05,0.1],
'dir': np.arange(0,360,120)}
efth = xr.DataArray(data=np.random.rand(2,2,3),
coords=coords,
dims=('time','freq', 'dir'),
name='efth')
In [1]: efth
Out[1]:
<xarray.DataArray (time: 2, freq: 2, dir: 3)>
array([[[ 0.100607, 0.328229, 0.332708],
[ 0.532 , 0.665938, 0.177731]],
[[ 0.469371, 0.002963, 0.627179],
[ 0.004523, 0.682717, 0.09766 ]]])
Coordinates:
* freq (freq) float64 0.05 0.1
* dir (dir) int64 0 120 240
* time (time) datetime64[ns] 2017-01-01 2017-01-02
In [2]: efth.spec
Out[2]:
<SpecArray (time: 2, freq: 2, dir: 3)>
array([[[ 0.100607, 0.328229, 0.332708],
[ 0.532 , 0.665938, 0.177731]],
[[ 0.469371, 0.002963, 0.627179],
[ 0.004523, 0.682717, 0.09766 ]]])
Coordinates:
* freq (freq) float64 0.05 0.1
* dir (dir) int64 0 120 240
* time (time) datetime64[ns] 2017-01-01 2017-01-02
In [3]: efth.spec.hs()
Out[3]:
<xarray.DataArray 'hs' (time: 2)>
array([ 10.128485, 9.510618])
Coordinates:
* time (time) datetime64[ns] 2017-01-01 2017-01-02
Attributes:
standard_name: sea_surface_wave_significant_height
units: m
SpecDataset provides a wrapper around the methods in SpecArray. For instance, these produce same result:
In [4]: dset = efth.to_dataset(name='efth')
In [5]: tm01 = dset.spec.tm01()
In [6]: tm01.identical(dset.efth.spec.tm01())
Out[6]: True
- wave frequency coordinate in Hz named as freq (required).
- wave direction coordinate in degree (coming from) named as dir (optional for 1D, required for 2D spectra).
- wave energy density data in m2/Hz/degree (2D) or m2/Hz (1D) named as efth
SpecDataset methods require xarray's Dataset to have the following attributes:
- spectra DataArray named as efth, complying with the above specifications
Define and plot spectra history from example SWAN spectra file:
from wavespectra import read_swan
dset = read_swan('/source/wavespectra/tests/sample_files/swanfile.spec')
spec_hist = dset.isel(lat=0, lon=0).sel(freq=slice(0.05,0.2)).spec.oned().T
spec_hist.plot.contourf(levels=10)