___________________
New Features
------------
* New ``track`` partitioning method replacing ``ptm1_track``, tracking wave systems
in time from partitions produced by any of the ``ptm1``, ``ptm2``, ``ptm3`` or
``hp01`` methods (``method`` argument, default ``"ptm1"``). Wind-sea matching
thresholds are applied to the leading wind sea partitions of each method (both wind
seas in ``ptm2``) and swell thresholds to the remaining ones; ``ptm3`` partitions
are unclassified so they are all matched with swell thresholds and wind inputs are
not required.
* The partition tracker now evaluates the time step for each pair of consecutive
spectra, so records with gaps or irregular sampling use matching thresholds
consistent with the actual time elapsed.
* Candidate partition pairs are now matched globally in ascending order of their
distance in frequency-direction space, making the tracking independent of
partition ordering.
* New ``systems`` option in the ``track`` method to remap the tracked partitions
onto a ``wave_system`` dimension in place of ``part``, so each tracked wave system
occupies its own index and carries values along the entire time axis, null where
the system does not exist. Systems spanning fewer time steps than ``min_duration``
can be excluded. The remapping is lazy on dask datasets and is also available as
the standalone ``wave_systems`` function.
* Rewritten ``hp01`` partitioning method implementing the swell combining criteria of
`Hanson and Phillips (2001) <https://journals.ametsoc.org/view/journals/atot/18/2/1520-0426_2001_018_0277_aaoosd_2_0_co_2.xml>`_
and `Hanson et al. (2009) <https://journals.ametsoc.org/view/journals/atot/26/8/2009jtecho650_1.xml>`_
from scratch. Swell partitions belonging to the same wave system are combined based
on the saddle point between adjacent partitions (``zeta``), the separation between
partition peaks relative to their spectral spread (``kappa``, renamed from ``k``)
and the angle between partition mean directions (``angle_max``). The criteria are
evaluated on an adjacency graph of the watershed partitions with statistics
recomputed after every merge and the strongest candidate pairs combined first, so
results are independent of partition ordering; spectral variance is conserved
throughout. Small partitions are merged onto their most connected neighbours based
on the ``hs_min`` threshold or the optional Hanson and Phillips (2001) noise floor
(``noise_a``, ``noise_b``). The method supports prescribing an exact number of
output partitions, with extra swells either combined or dropped.
* Support ``swells=None`` (``parts=None`` in ``ptm3``) in all watershed partitioning
methods, sizing the output ``part`` dimension from the largest number of partitions
detected across all spectra by an extra counting pass over the data.
* New ``awac``, ``datawell`` and ``obscape`` engines for ``xr.open_dataset``,
completing the xarray backend registration of all wavespectra readers.
* Binary wheels published for CPython 3.9-3.13 on Linux (x86_64, aarch64), macOS
(x86_64, arm64) and Windows (amd64), so installing wavespectra no longer requires a
C compiler.
Breaking Changes
----------------
* The ``ptm1_track`` method has been replaced by ``track`` (use ``method="ptm1"``
for the previous behaviour). The output variables have been renamed for clarity:
``part_id`` is now ``track_id`` and ``npart_id`` is now ``ntracks``.
* ``match_consecutive_partitions`` now takes per-partition threshold arrays and
``np_track_partitions`` / ``track_partitions`` take an ``nsea`` argument defining
the number of leading wind sea partitions; times must be strictly increasing and
``wspd`` is only required when ``nsea > 0``.
* The experimental ``wstype`` argument of ``hp01`` and the associated
``np_hp01_wseabins`` and ``np_hp01_wseafrac_wseabins`` variants have been removed;
the wind sea is now always defined by the wind-sea fraction criterion as in
``ptm1``. The ``k`` argument of ``hp01`` has been renamed ``kappa`` and the
internals of the ``hanson_and_phillips_2001`` module have been rewritten, removing
the previous helper functions. These changes are confined to the ``hp01`` method,
which was previously documented as under development.
Bug Fixes
---------
* Fix ``DatawellBackendEntrypoint`` passing an unsupported ``filetype`` argument to
``read_datawell``, which made ``xr.open_dataset(..., engine="datawell")`` unusable.
* Fix silent corruption of watershed partitions for spectra that are not C-contiguous
in memory, e.g. datasets stored with dims ``(..., dir, freq)``. The ``specpart`` C
extension wrapper now converts any input dtype and memory layout at the boundary,
matching the behaviour of the f2py wrapper around the pre-v4 Fortran code. Reported
by `daniel-caichac-DHI`_
(`GH142 <https://github.com/wavespectra/wavespectra/issues/142>`_,
`PR160 <https://github.com/wavespectra/wavespectra/pull/160>`_).
* Fix intermittent deadlock when writing dask-backed spectra to netCDF in ``to_ww3``
and ``to_netcdf`` by forcing the single-threaded dask scheduler during the write,
avoiding cross-thread contention on the netCDF4/HDF5 global lock.
* Fix ``as_site`` argument silently ignored when reading ERA5 spectra through the
xarray backend entrypoint (``xr.open_dataset(..., engine="era5", as_site=True)``).
* Fix wrong default upper direction bound ``dmax`` in the ``bbox`` partition method.
Internal Changes
----------------
* Rewrite the ``specpart`` C extension without global state, making it reentrant and
thread-safe under dask's threaded scheduler; release the GIL during computation,
validate inputs, raise proper Python exceptions instead of exiting, and fix a memory
leak. The rewritten kernel is verified to produce partition maps bit-identical to
the pre-v4 Fortran implementation over 1420 comparison cases (see
``wavespectra/partition/specpart/ANALYSIS.md``).
* Run ruff linting and coverage reporting in CI; add pip caching and a per-test
timeout so hanging tests fail fast with a traceback; remove the unused tox and
flake8 configurations.
* Clean up lint findings across the source and test suite; restore disabled test
assertions (HP01 Hs conservation, ``peak_directional_spread``) and fix
Pierson-Moskowitz test tolerances that previously asserted nothing.
* Documentation fixes: correct JONSWAP ``sigma_a``/``sigma_b`` values in the Zieger
reconstruction page, fix broken imports in the reconstruction examples, remove the
orphaned library page and enable ``sphinx.ext.napoleon`` so Google-style docstrings
render properly in the API reference.
* Report reader import failures with ``warnings.warn`` instead of printing to stdout,
including the module name and the original error; new parity tests ensure every
reader module keeps a top-level ``read_*`` function, a registered xarray engine and
a backend signature consistent with its reader.
* Reconcile the reader listings in the API documentation with the available readers
(add missing ``read_awac``, ``read_datawell``, ``read_obscape`` and
``read_wavespectra`` entries, remove a duplicate).
.. _`daniel-caichac-DHI`: https://github.com/daniel-caichac-DHI