Source code for wavespectra.input.funwave_new
"""Read Funwave WK_NEW_DATA2D Wave Maker files"""
from xarray.backends import BackendEntrypoint
import numpy as np
import xarray as xr
from wavespectra import SpecArray
from wavespectra.input import read_ascii_or_binary
from wavespectra.core.attributes import attrs, set_spec_attributes
[docs]
def read_funwave_new(filename_or_obj):
"""Read Spectra in Funwave WK_NEW_DATA2D wavemaker format.
Args:
- filename_or_obj (str, filelike): Funwave WaveCompFile to read.
Returns:
- dset (SpecDataset): spectra dataset object read from funwave file.
Note:
- Format description: https://fengyanshi.github.io/build/html/wavemaker_coherence.html.
- The file describes individual wave components, the gridded spectrum is
reconstructed by summing component energies :math:`a^2/2` falling in each
frequency-direction bin defined by the unique frequencies and directions.
- Directions converted from Cartesian (0E, CCW, to) to wavespectra (0N, CW, from).
- A 1D :math:`E(f)` spectrum is returned if all directions are equal.
- Phases are ignored if present.
"""
data = read_ascii_or_binary(filename_or_obj, mode="r")
# Remove any empty rows
data = [row for row in data if row != "\n"]
# Number of wave components
nc = int(data.pop(0).split()[0])
# Tp
tp = float(data.pop(0).split()[0])
# Wave component blocks
values = [float(row.split()[0]) for row in data]
freq = np.array(values[:nc])
dir = np.array(values[nc : 2 * nc])
amp = np.array(values[2 * nc : 3 * nc])
# Bin component energies onto the spectral grid
freqs = np.unique(freq)
dirs = np.unique(dir)
ifreq = np.searchsorted(freqs, freq)
idir = np.searchsorted(dirs, dir)
energy = np.zeros((freqs.size, dirs.size))
np.add.at(energy, (ifreq, idir), amp**2 / 2)
if dirs.size == 1:
coords = {attrs.FREQNAME: freqs}
dims = (attrs.FREQNAME,)
energy = energy.squeeze(axis=1)
else:
# Convert dir from cartesian to wavespectra convention
dirs = (270 - dirs) % 360
# Turn zero dir into 360 for continuity
i0 = np.where(dirs == 0)[0]
if i0.size > 0:
dirs[i0] = 360.0
coords = {attrs.FREQNAME: freqs, attrs.DIRNAME: dirs}
dims = (attrs.FREQNAME, attrs.DIRNAME)
darr = xr.DataArray(data=energy, coords=coords, dims=dims)
# Energy density spectrum
darr = darr / (darr.spec.df * darr.spec.dd)
# Define output dataset
dset = darr.to_dataset(name=attrs.SPECNAME)
if dirs.size > 1:
dset = dset.sortby(attrs.DIRNAME)
dset["tp"] = tp
set_spec_attributes(dset)
return dset
class FunwaveNewBackendEntrypoint(BackendEntrypoint):
"""Funwave WK_NEW_DATA2D backend engine."""
def open_dataset(
self,
filename_or_obj,
*,
drop_variables=None,
):
return read_funwave_new(filename_or_obj)
def guess_can_open(self, filename_or_obj):
return False
description = (
"Open Funwave WK_NEW_DATA2D ASCII wave component files as a wavespectra "
"dataset."
)
url = "https://github.com/wavespectra/wavespectra"