wavespectra 3.18.0__tar.gz → 4.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {wavespectra-3.18.0/wavespectra.egg-info → wavespectra-4.0.0}/PKG-INFO +8 -8
  2. {wavespectra-3.18.0 → wavespectra-4.0.0}/pyproject.toml +39 -8
  3. wavespectra-4.0.0/setup.py +16 -0
  4. wavespectra-4.0.0/tests/test_cli.py +103 -0
  5. wavespectra-4.0.0/tests/test_cookiecutter_template.py +37 -0
  6. wavespectra-4.0.0/tests/test_partition.py +397 -0
  7. {wavespectra-3.18.0 → wavespectra-4.0.0}/tests/test_specarray.py +32 -16
  8. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/__init__.py +11 -7
  9. wavespectra-4.0.0/wavespectra/cli.py +196 -0
  10. wavespectra-4.0.0/wavespectra/construct/__init__.py +190 -0
  11. wavespectra-4.0.0/wavespectra/construct/direction.py +104 -0
  12. wavespectra-4.0.0/wavespectra/construct/frequency.py +210 -0
  13. wavespectra-4.0.0/wavespectra/core/__init__.py +0 -0
  14. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/core/attributes.py +9 -7
  15. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/core/attributes.yml +42 -1
  16. wavespectra-4.0.0/wavespectra/core/fitting.py +140 -0
  17. wavespectra-4.0.0/wavespectra/core/npstats.py +254 -0
  18. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/core/select.py +16 -7
  19. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/core/swan.py +5 -5
  20. wavespectra-4.0.0/wavespectra/core/utils.py +459 -0
  21. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/core/xrstats.py +98 -14
  22. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/dataset.py +6 -5
  23. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/era5.py +23 -1
  24. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/funwave.py +24 -4
  25. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/json.py +20 -0
  26. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/ncswan.py +30 -7
  27. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/ndbc.py +49 -0
  28. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/ndbc_ascii.py +28 -28
  29. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/netcdf.py +36 -1
  30. wavespectra-4.0.0/wavespectra/input/obscape.py +267 -0
  31. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/octopus.py +25 -5
  32. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/spotter.py +27 -0
  33. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/swan.py +29 -2
  34. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/triaxys.py +33 -2
  35. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/wavespectra.py +22 -2
  36. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/ww3.py +27 -3
  37. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/ww3_station.py +21 -0
  38. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/wwm.py +22 -1
  39. wavespectra-4.0.0/wavespectra/input/xwaves.py +67 -0
  40. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/funwave.py +2 -2
  41. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/netcdf.py +3 -1
  42. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/octopus.py +23 -22
  43. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/orcaflex.py +16 -13
  44. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/ww3.py +10 -3
  45. wavespectra-4.0.0/wavespectra/partition/__init__.py +0 -0
  46. wavespectra-4.0.0/wavespectra/partition/hanson_and_phillips_2001.py +295 -0
  47. wavespectra-4.0.0/wavespectra/partition/partition.py +1288 -0
  48. wavespectra-4.0.0/wavespectra/partition/specpart/specpartc.c +475 -0
  49. wavespectra-4.0.0/wavespectra/partition/specpart/specpartc_wrap.c +61 -0
  50. wavespectra-4.0.0/wavespectra/partition/tracking.py +356 -0
  51. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/plot.py +13 -8
  52. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/specarray.py +523 -234
  53. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/specdataset.py +2 -2
  54. {wavespectra-3.18.0 → wavespectra-4.0.0/wavespectra.egg-info}/PKG-INFO +8 -8
  55. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra.egg-info/SOURCES.txt +13 -6
  56. wavespectra-4.0.0/wavespectra.egg-info/entry_points.txt +20 -0
  57. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra.egg-info/requires.txt +5 -6
  58. wavespectra-3.18.0/setup.py +0 -15
  59. wavespectra-3.18.0/tests/test_cookiecutter_template.py +0 -37
  60. wavespectra-3.18.0/wavespectra/cli.py +0 -17
  61. wavespectra-3.18.0/wavespectra/construct/__init__.py +0 -4
  62. wavespectra-3.18.0/wavespectra/construct/helpers.py +0 -101
  63. wavespectra-3.18.0/wavespectra/construct/jonswap.py +0 -50
  64. wavespectra-3.18.0/wavespectra/construct/ochihubble.py +0 -57
  65. wavespectra-3.18.0/wavespectra/core/__init__.py +0 -4
  66. wavespectra-3.18.0/wavespectra/core/npstats.py +0 -147
  67. wavespectra-3.18.0/wavespectra/core/utils.py +0 -283
  68. wavespectra-3.18.0/wavespectra/core/watershed.py +0 -188
  69. wavespectra-3.18.0/wavespectra/specpart/specpart.f90 +0 -499
  70. wavespectra-3.18.0/wavespectra/specpart/specpart.pyf +0 -20
  71. wavespectra-3.18.0/wavespectra.egg-info/entry_points.txt +0 -2
  72. {wavespectra-3.18.0 → wavespectra-4.0.0}/AUTHORS.rst +0 -0
  73. {wavespectra-3.18.0 → wavespectra-4.0.0}/LICENSE.txt +0 -0
  74. {wavespectra-3.18.0 → wavespectra-4.0.0}/README.rst +0 -0
  75. {wavespectra-3.18.0 → wavespectra-4.0.0}/setup.cfg +0 -0
  76. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/input/__init__.py +0 -0
  77. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/__init__.py +0 -0
  78. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/json.py +0 -0
  79. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/swan.py +0 -0
  80. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra/output/ww3.yml +0 -0
  81. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra.egg-info/dependency_links.txt +0 -0
  82. {wavespectra-3.18.0 → wavespectra-4.0.0}/wavespectra.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wavespectra
3
- Version: 3.18.0
3
+ Version: 4.0.0
4
4
  Summary: Library for ocean wave spectra
5
5
  Author-email: Wavespectra Developers <r.guedes@oceanum.science>
6
6
  Maintainer-email: Rafael Guedes <r.guedes@oceanum.science>, Tom Durrant <t.durrant@oceanum.science>
@@ -41,22 +41,18 @@ Classifier: Programming Language :: Python :: 3.8
41
41
  Classifier: Programming Language :: Python :: 3.9
42
42
  Classifier: Programming Language :: Python :: 3.10
43
43
  Classifier: Programming Language :: Python :: 3.11
44
- Requires-Python: <3.12,>=3.8
44
+ Classifier: Programming Language :: Python :: 3.12
45
+ Requires-Python: >=3.8
45
46
  Description-Content-Type: text/x-rst
46
47
  License-File: LICENSE.txt
47
48
  License-File: AUTHORS.rst
48
49
  Requires-Dist: click
49
- Requires-Dist: cmocean
50
50
  Requires-Dist: dask
51
51
  Requires-Dist: matplotlib
52
- Requires-Dist: numba
53
- Requires-Dist: pandas
54
52
  Requires-Dist: python-dateutil
55
53
  Requires-Dist: pyyaml
56
54
  Requires-Dist: sortedcontainers
57
55
  Requires-Dist: scipy
58
- Requires-Dist: toolz
59
- Requires-Dist: typing_extensions
60
56
  Requires-Dist: xarray
61
57
  Provides-Extra: test
62
58
  Requires-Dist: pytest; extra == "test"
@@ -65,13 +61,17 @@ Requires-Dist: ruff; extra == "test"
65
61
  Provides-Extra: extra
66
62
  Requires-Dist: fsspec; extra == "extra"
67
63
  Requires-Dist: gcsfs; extra == "extra"
64
+ Requires-Dist: h5netcdf; extra == "extra"
68
65
  Requires-Dist: netCDF4; extra == "extra"
69
66
  Requires-Dist: zarr; extra == "extra"
70
- Requires-Dist: h5netcdf; extra == "extra"
71
67
  Provides-Extra: docs
72
68
  Requires-Dist: autodoc; extra == "docs"
69
+ Requires-Dist: cmocean; extra == "docs"
73
70
  Requires-Dist: ipython; extra == "docs"
71
+ Requires-Dist: pickleshare; extra == "docs"
74
72
  Requires-Dist: pydata_sphinx_theme; extra == "docs"
73
+ Requires-Dist: sphinxcontrib-programoutput; extra == "docs"
74
+ Requires-Dist: sphinx-book-theme; extra == "docs"
75
75
  Requires-Dist: sphinx; extra == "docs"
76
76
  Requires-Dist: sphinx-autobuild; extra == "docs"
77
77
  Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
@@ -29,21 +29,17 @@ classifiers = [
29
29
  "Programming Language :: Python :: 3.9",
30
30
  "Programming Language :: Python :: 3.10",
31
31
  "Programming Language :: Python :: 3.11",
32
+ "Programming Language :: Python :: 3.12",
32
33
  ]
33
- requires-python = ">=3.8,<3.12"
34
+ requires-python = ">=3.8"
34
35
  dependencies = [
35
36
  "click",
36
- "cmocean",
37
37
  "dask",
38
38
  "matplotlib",
39
- "numba",
40
- "pandas",
41
39
  "python-dateutil",
42
40
  "pyyaml",
43
41
  "sortedcontainers",
44
42
  "scipy",
45
- "toolz",
46
- "typing_extensions",
47
43
  "xarray",
48
44
  ]
49
45
  dynamic = ["version"]
@@ -57,19 +53,41 @@ dynamic = ["version"]
57
53
  [project.scripts]
58
54
  wavespectra = "wavespectra.cli:main"
59
55
 
56
+ [project.entry-points."xarray.backends"]
57
+ era5 = "wavespectra.input.era5:ERA5BackendEntrypoint"
58
+ funwave = "wavespectra.input.funwave:FunwaveBackendEntrypoint"
59
+ json = "wavespectra.input.json:JsonBackendEntrypoint"
60
+ ncswan = "wavespectra.input.ncswan:NCSwanBackendEntrypoint"
61
+ ndbc = "wavespectra.input.ndbc:NDBCBackendEntrypoint"
62
+ ndbc_ascii = "wavespectra.input.ndbc_ascii:NDBCASCIIBackendEntrypoint"
63
+ netcdf = "wavespectra.input.netcdf:NetCDFBackendEntrypoint"
64
+ octopus = "wavespectra.input.octopus:OctopusBackendEntrypoint"
65
+ spotter = "wavespectra.input.spotter:SpotterBackendEntrypoint"
66
+ swan = "wavespectra.input.swan:SWANBackendEntrypoint"
67
+ triaxys = "wavespectra.input.triaxys:TRIAXYSBackendEntrypoint"
68
+ wavespectra = "wavespectra.input.wavespectra:WavespectraBackendEntrypoint"
69
+ wwm = "wavespectra.input.wwm:WWMBackendEntrypoint"
70
+ ww3 = "wavespectra.input.ww3:WW3BackendEntrypoint"
71
+ ww3_station = "wavespectra.input.ww3_station:WW3StationBackendEntrypoint"
72
+ xwaves = "wavespectra.input.xwaves:XWavesBackendEntrypoint"
73
+
60
74
  [project.optional-dependencies]
61
75
  test = ["pytest", "tox", "ruff"]
62
76
  extra = [
63
77
  "fsspec",
64
78
  "gcsfs",
79
+ "h5netcdf",
65
80
  "netCDF4",
66
81
  "zarr",
67
- "h5netcdf",
68
82
  ]
69
83
  docs = [
70
84
  "autodoc",
85
+ "cmocean",
71
86
  "ipython",
87
+ "pickleshare",
72
88
  "pydata_sphinx_theme",
89
+ "sphinxcontrib-programoutput",
90
+ "sphinx-book-theme",
73
91
  "sphinx",
74
92
  "sphinx-autobuild",
75
93
  "sphinx-autodoc-typehints",
@@ -79,11 +97,14 @@ docs = [
79
97
  [tool.setuptools.package-data]
80
98
  "wavespectra.core" = ["*.yml"]
81
99
  "wavespectra.output" = ["*.yml"]
82
- "wavespectra.specpart" = ["specpart.f90", "specpart.pyf"]
100
+ "wavespectra.specpartc" = ["specpartc.c", "specpartc.h", "specpartc_wrap.c"]
83
101
 
84
102
  [tool.setuptools.dynamic]
85
103
  version = {attr = "wavespectra.__version__"}
86
104
 
105
+ [tool.ruff]
106
+ line-length = 88
107
+
87
108
  [tool.ruff.extend-per-file-ignores]
88
109
  "wavespectra/__init__.py" = ["F401"]
89
110
  "wavespectra/specdataset.py" = ["F401"]
@@ -95,6 +116,16 @@ version = {attr = "wavespectra.__version__"}
95
116
  "wavespectra/input/spotter.py" = ["F401"]
96
117
  "wavespectra/input/dataset.py" = ["F401"]
97
118
  "wavespectra/input/swan.py" = ["F401"]
119
+ "wavespectra/construct.py" = ["F401"]
120
+ "wavespectra/directional.py" = ["F401"]
121
+ "wavespectra/fit/pierson_moskowitz.py" = ["F401"]
122
+ "wavespectra/fit/tma.py" = ["F401"]
123
+ "wavespectra/input/funwave.py" = ["F401"]
124
+ "wavespectra/input/ndbc.py" = ["F401"]
125
+ "wavespectra/input/ndbc_ascii.py" = ["F401"]
126
+ "wavespectra/input/octopus.py" = ["F401"]
127
+ "wavespectra/input/wavespectra.py" = ["F401"]
128
+ "wavespectra/input/xwaves.py" = ["F401"]
98
129
 
99
130
  [tool.tox]
100
131
  legacy_tox_ini = """
@@ -0,0 +1,16 @@
1
+ from setuptools import setup, Extension
2
+ from numpy import get_include as get_numpy_include
3
+
4
+ setup(
5
+ name="wavespectra",
6
+ ext_modules=[
7
+ Extension(
8
+ name="wavespectra.partition.specpartc",
9
+ sources=[
10
+ "wavespectra/partition/specpart/specpartc_wrap.c",
11
+ "wavespectra/partition/specpart/specpartc.c",
12
+ ],
13
+ include_dirs=[get_numpy_include()],
14
+ )
15
+ ],
16
+ )
@@ -0,0 +1,103 @@
1
+ """Test model wrapper."""
2
+ from pathlib import Path
3
+ import pytest
4
+ import xarray as xr
5
+ from click.testing import CliRunner
6
+
7
+ from wavespectra import cli
8
+
9
+
10
+ DATADIR = Path(__file__).parent / "sample_files"
11
+ INFILE = str(DATADIR / "ww3file.nc")
12
+ ENGINE = "ww3"
13
+
14
+
15
+ @pytest.fixture(scope="module")
16
+ def runner():
17
+ instance = CliRunner()
18
+ yield instance
19
+
20
+
21
+ def test_main(runner):
22
+ result = runner.invoke(cli.main)
23
+ assert result.exit_code == 0
24
+ assert "main" in result.output
25
+
26
+
27
+ def test_main_convert(runner):
28
+ result = runner.invoke(cli.main, "convert")
29
+ assert result.exit_code == 0
30
+ assert "convert" in result.output
31
+
32
+
33
+ def test_main_convert_format(runner, tmpdir):
34
+ OUTFILE = str(tmpdir / "outspec.nc")
35
+
36
+ result = runner.invoke(
37
+ cli.main, ["convert", "format", INFILE, ENGINE, OUTFILE, "swan"]
38
+ )
39
+ assert result.exit_code == 0
40
+
41
+ xr.open_dataset(OUTFILE, engine="swan")
42
+
43
+
44
+ def test_main_convert_stats(runner, tmpdir):
45
+ OUTFILE = str(tmpdir / "outstats.nc")
46
+
47
+ result = runner.invoke(
48
+ cli.main, ["convert", "stats", INFILE, ENGINE, OUTFILE, "-p", "hs", "-p", "tp"]
49
+ )
50
+ assert result.exit_code == 0
51
+
52
+ dset = xr.open_dataset(OUTFILE)
53
+ assert "hs" in dset.data_vars and "tp" in dset.data_vars
54
+
55
+
56
+ def test_main_reconstruct(runner):
57
+ result = runner.invoke(cli.main, "reconstruct")
58
+ assert result.exit_code == 0
59
+ assert "reconstruct" in result.output
60
+
61
+
62
+ def test_main_reconstruct_spectra(runner, tmpdir):
63
+ OUTFILE = str(tmpdir / "outspec.nc")
64
+
65
+ result = runner.invoke(
66
+ cli.main, ["reconstruct", "spectra", INFILE, ENGINE, OUTFILE]
67
+ )
68
+ assert result.exit_code == 0
69
+
70
+ result = runner.invoke(cli.main, ["reconstruct", "spectra", INFILE, ENGINE, INFILE])
71
+ assert isinstance(result.exception, ValueError)
72
+
73
+ result = runner.invoke(
74
+ cli.main,
75
+ [
76
+ "reconstruct",
77
+ "spectra",
78
+ INFILE,
79
+ ENGINE,
80
+ OUTFILE,
81
+ "-p",
82
+ "3",
83
+ "-d",
84
+ "cartwright,cartwright,cartwright",
85
+ ],
86
+ )
87
+ assert result.exit_code == 0
88
+
89
+ result = runner.invoke(
90
+ cli.main,
91
+ [
92
+ "reconstruct",
93
+ "spectra",
94
+ INFILE,
95
+ ENGINE,
96
+ OUTFILE,
97
+ "-p",
98
+ "3",
99
+ "-f",
100
+ "jonswap,jonswap,jonswap",
101
+ ],
102
+ )
103
+ assert result.exit_code == 0
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """Tests for `wavespectra` package."""
5
+
6
+ import pytest
7
+
8
+ from click.testing import CliRunner
9
+
10
+ from wavespectra import cli
11
+
12
+
13
+ # @pytest.fixture
14
+ # def response():
15
+ # """Sample pytest fixture.
16
+
17
+ # See more at: http://doc.pytest.org/en/latest/fixture.html
18
+ # """
19
+ # # import requests
20
+ # # return requests.get('https://github.com/audreyr/cookiecutter-pypackage')
21
+
22
+
23
+ # def test_content(response):
24
+ # """Sample pytest test function with the pytest fixture as an argument."""
25
+ # # from bs4 import BeautifulSoup
26
+ # # assert 'GitHub' in BeautifulSoup(response.content).title.string
27
+
28
+
29
+ # def test_command_line_interface():
30
+ # """Test the CLI."""
31
+ # runner = CliRunner()
32
+ # result = runner.invoke(cli.main)
33
+ # assert result.exit_code == 0
34
+ # assert "wavespectra.cli.main" in result.output
35
+ # help_result = runner.invoke(cli.main, ["--help"])
36
+ # assert help_result.exit_code == 0
37
+ # assert "--help Show this message and exit." in help_result.output
@@ -0,0 +1,397 @@
1
+ import pytest
2
+ from pathlib import Path
3
+ import numpy as np
4
+ import xarray as xr
5
+
6
+ from wavespectra import read_ww3
7
+ from wavespectra.partition.partition import (
8
+ Partition,
9
+ np_ptm1,
10
+ np_ptm2,
11
+ np_ptm3,
12
+ np_hp01,
13
+ )
14
+ from wavespectra.core.utils import waveage
15
+ from wavespectra.core import npstats
16
+ from wavespectra.partition.tracking import track_partitions
17
+
18
+
19
+ HERE = Path(__file__).parent
20
+
21
+
22
+ class BasePTM:
23
+ def setup_class(self):
24
+ self.dset = read_ww3(HERE / "sample_files/ww3file.nc")
25
+ self.efth = self.dset.isel(time=0, site=0).efth.values
26
+ self.freq = self.dset.freq.values
27
+ self.dir = self.dset.dir.values
28
+ self.pt = Partition(self.dset)
29
+
30
+ @property
31
+ def hs_full(self):
32
+ return npstats.hs(self.efth, self.freq, self.dir)
33
+
34
+ @property
35
+ def hs_from_partitions(self):
36
+ hs_partitions = [npstats.hs(efth, self.freq, self.dir) for efth in self.out]
37
+ return np.sqrt(np.sum(np.power(hs_partitions, 2)))
38
+
39
+
40
+ class TestPTM1(BasePTM):
41
+ def setup_class(self):
42
+ super().setup_class(self)
43
+ self.wspd = self.dset.isel(time=0, site=0).wspd.values
44
+ self.wdir = self.dset.isel(time=0, site=0).wdir.values
45
+ self.dpt = self.dset.isel(time=0, site=0).dpt.values
46
+ self.agefac = 1.7
47
+ self.wscut = 0.3333
48
+ self.swells = 3
49
+
50
+ def _exec(self, **kwargs):
51
+ out = np_ptm1(
52
+ spectrum=self.efth,
53
+ spectrum_smooth=self.efth,
54
+ freq=self.freq,
55
+ dir=self.dir,
56
+ wspd=self.wspd,
57
+ wdir=self.wdir,
58
+ dpt=self.dpt,
59
+ agefac=kwargs.get("agefac", self.agefac),
60
+ wscut=kwargs.get("wscut", self.wscut),
61
+ swells=kwargs.get("swells", self.swells),
62
+ )
63
+ return out
64
+
65
+ def test_defaults(self):
66
+ self.out = self._exec()
67
+ assert self.out.shape[0] == self.swells + 1
68
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
69
+
70
+ def test_request_all_partitions(self):
71
+ self.out = self._exec(swells=None)
72
+ assert self.out.shape[0] == 3
73
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
74
+
75
+ def test_request_less_partitions(self):
76
+ swells = 2
77
+ self.out = self._exec(swells=swells)
78
+ assert self.hs_from_partitions < self.hs_full
79
+ assert len(self.out) == swells + 1
80
+
81
+ def test_partition_class(self):
82
+ swells = 2
83
+ self.out = self._exec(swells=swells)
84
+ dspart = self.pt.ptm1(
85
+ wspd=self.dset.wspd,
86
+ wdir=self.dset.wdir,
87
+ dpt=self.dset.dpt,
88
+ swells=swells,
89
+ )
90
+ hs_dspart = np.sqrt(np.sum(dspart.isel(time=0, site=0).spec.hs().values ** 2))
91
+ assert hs_dspart == pytest.approx(self.hs_from_partitions, rel=1e-2)
92
+
93
+ def test_smoothing(self):
94
+ swells = 2
95
+ ds_nosmoothing = self.pt.ptm1(
96
+ wspd=self.dset.wspd,
97
+ wdir=self.dset.wdir,
98
+ dpt=self.dset.dpt,
99
+ swells=swells,
100
+ )
101
+ ds_smoothing = self.pt.ptm1(
102
+ wspd=self.dset.wspd,
103
+ wdir=self.dset.wdir,
104
+ dpt=self.dset.dpt,
105
+ swells=swells,
106
+ smooth=True,
107
+ )
108
+ assert not ds_nosmoothing.spec.hs().equals(ds_smoothing.spec.hs())
109
+
110
+
111
+ class TestPTM2(BasePTM):
112
+ def setup_class(self):
113
+ super().setup_class(self)
114
+ self.wspd = self.dset.isel(time=0, site=0).wspd.values
115
+ self.wdir = self.dset.isel(time=0, site=0).wdir.values
116
+ self.dpt = self.dset.isel(time=0, site=0).dpt.values
117
+ self.agefac = 1.7
118
+ self.wscut = 0.3333
119
+ self.swells = 3
120
+
121
+ def _exec(self, **kwargs):
122
+ out = np_ptm2(
123
+ spectrum=self.efth,
124
+ spectrum_smooth=self.efth,
125
+ freq=self.freq,
126
+ dir=self.dir,
127
+ wspd=self.wspd,
128
+ wdir=self.wdir,
129
+ dpt=self.dpt,
130
+ agefac=kwargs.get("agefac", self.agefac),
131
+ wscut=kwargs.get("wscut", self.wscut),
132
+ swells=kwargs.get("swells", self.swells),
133
+ )
134
+ return out
135
+
136
+ def test_defaults(self):
137
+ self.out = self._exec()
138
+ assert self.out.shape[0] == self.swells + 2
139
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
140
+
141
+ def test_request_all_partitions(self):
142
+ self.out = self._exec(swells=None)
143
+ assert self.out.shape[0] == 4
144
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
145
+
146
+ def test_request_less_partitions(self):
147
+ swells = 2
148
+ self.out = self._exec(swells=swells)
149
+ assert self.hs_from_partitions < self.hs_full
150
+ assert len(self.out) == swells + 2
151
+
152
+ def test_less_partitions_combined(self):
153
+ swells = 2
154
+ self.out = self._exec(swells=swells)
155
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
156
+ assert len(self.out) == swells + 2
157
+
158
+ def test_partition_class(self):
159
+ swells = 2
160
+ combine = False
161
+ self.out = self._exec(swells=swells)
162
+ dspart = self.pt.ptm2(
163
+ wspd=self.dset.wspd,
164
+ wdir=self.dset.wdir,
165
+ dpt=self.dset.dpt,
166
+ swells=swells,
167
+ )
168
+ hs_dspart = np.sqrt(np.sum(dspart.isel(time=0, site=0).spec.hs().values ** 2))
169
+ assert hs_dspart == pytest.approx(self.hs_from_partitions, rel=1e-2)
170
+
171
+ def test_smoothing(self):
172
+ swells = 2
173
+ ds_nosmoothing = self.pt.ptm1(
174
+ wspd=self.dset.wspd,
175
+ wdir=self.dset.wdir,
176
+ dpt=self.dset.dpt,
177
+ swells=swells,
178
+ )
179
+ ds_smoothing = self.pt.ptm1(
180
+ wspd=self.dset.wspd,
181
+ wdir=self.dset.wdir,
182
+ dpt=self.dset.dpt,
183
+ swells=swells,
184
+ smooth=True,
185
+ )
186
+ assert not ds_nosmoothing.spec.hs().equals(ds_smoothing.spec.hs())
187
+
188
+
189
+ class TestPTM3(BasePTM):
190
+ def _exec(self, parts):
191
+ out = np_ptm3(
192
+ spectrum=self.dset.efth.isel(time=0, site=0).values,
193
+ spectrum_smooth=self.dset.efth.isel(time=0, site=0).values,
194
+ freq=self.dset.freq.values,
195
+ dir=self.dset.dir.values,
196
+ parts=parts,
197
+ )
198
+ return out
199
+
200
+ def test_request_all_partitions(self):
201
+ self.out = self._exec(parts=None)
202
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
203
+
204
+ def test_request_less_partitions(self):
205
+ parts = 2
206
+ self.out = self._exec(parts=parts)
207
+ assert self.hs_from_partitions < self.hs_full
208
+ assert len(self.out) == parts
209
+
210
+ def test_more_partitions(self):
211
+ parts = 5
212
+ self.out = self._exec(parts=parts)
213
+ assert self.hs_full == pytest.approx(self.hs_from_partitions)
214
+ assert len(self.out) == parts
215
+ assert self.out[3:4].sum() == 0
216
+
217
+ def test_partition_class(self):
218
+ parts = 2
219
+ self.out = self._exec(parts=parts)
220
+ dspart = self.pt.ptm3(parts=parts, smooth=False)
221
+ hs_dspart = np.sqrt(np.sum(dspart.isel(time=0, site=0).spec.hs().values ** 2))
222
+ assert hs_dspart == pytest.approx(self.hs_from_partitions)
223
+
224
+ def test_partition_class_smoothing(self):
225
+ parts = 3
226
+ ds_nosmoothing = self.pt.ptm3(parts=parts)
227
+ ds_smoothing = self.pt.ptm3(parts=parts, smooth=True)
228
+ assert not ds_nosmoothing.spec.hs().equals(ds_smoothing.spec.hs())
229
+
230
+
231
+ class TestPTM4(BasePTM):
232
+ def test_agefac(self):
233
+ ds_agefac15 = self.pt.ptm4(
234
+ wspd=self.dset.wspd, wdir=self.dset.wdir, dpt=self.dset.dpt, agefac=1.5
235
+ )
236
+ ds_agefac17 = self.pt.ptm4(
237
+ wspd=self.dset.wspd,
238
+ wdir=self.dset.wdir,
239
+ dpt=self.dset.dpt,
240
+ )
241
+ sea_agefac15 = ds_agefac15.isel(part=0).spec.hs()
242
+ sea_agefac17 = ds_agefac17.isel(part=0).spec.hs()
243
+ assert np.all((sea_agefac17.values - sea_agefac15.values) > 0)
244
+
245
+
246
+ class TestPTM5(BasePTM):
247
+ def test_default(self):
248
+ fcut = 0.1
249
+ ds = self.pt.ptm5(fcut=0.1)
250
+ assert fcut in ds.freq
251
+ assert ds.isel(part=0).sel(freq=slice(None, fcut - 0.001)).spec.hs().max() == 0
252
+ assert ds.isel(part=1).sel(freq=slice(fcut + 0.001, None)).spec.hs().max() == 0
253
+
254
+ def test_not_interpolate(self):
255
+ fcut = 0.1
256
+ ds = self.pt.ptm5(fcut=0.1, interpolate=False)
257
+ assert fcut not in ds.freq
258
+
259
+
260
+ class TestHP01(BasePTM):
261
+ def setup_class(self):
262
+ super().setup_class(self)
263
+ self.agefac = 1.7
264
+ self.wscut = 0.3333
265
+ self.swells = 3
266
+ wspd = self.dset.wspd.isel(time=0, site=0)
267
+ wdir = self.dset.wdir.isel(time=0, site=0)
268
+ dpt = self.dset.dpt.isel(time=0, site=0)
269
+ self.windseamask = waveage(
270
+ self.dset.freq, self.dset.dir, wspd, wdir, dpt, self.agefac
271
+ )
272
+
273
+ def _exec(self, **kwargs):
274
+ out = np_hp01(
275
+ spectrum=self.efth,
276
+ spectrum_smooth=self.efth,
277
+ windseamask=self.windseamask,
278
+ freq=self.freq,
279
+ dir=self.dir,
280
+ wscut=kwargs.get("wscut", self.wscut),
281
+ swells=kwargs.get("swells", self.swells),
282
+ )
283
+ return out
284
+
285
+ def test_defaults(self):
286
+ self.out = self._exec()
287
+ # assert self.out.shape[0] == self.swells + 1
288
+ # assert self.hs_full == pytest.approx(self.hs_from_partitions)
289
+
290
+ # def test_request_all_partitions(self):
291
+ # self.out = self._exec(swells=None)
292
+ # assert self.out.shape[0] == 3
293
+ # assert self.hs_full == pytest.approx(self.hs_from_partitions)
294
+
295
+ # def test_request_less_partitions(self):
296
+ # swells = 2
297
+ # self.out = self._exec(swells=swells)
298
+ # assert self.hs_from_partitions < self.hs_full
299
+ # assert len(self.out) == swells + 1
300
+
301
+ def test_partition_class(self):
302
+ swells = 2
303
+ self.out = self._exec(swells=swells)
304
+ dspart = self.pt.hp01(
305
+ wspd=self.dset.wspd,
306
+ wdir=self.dset.wdir,
307
+ dpt=self.dset.dpt,
308
+ agefac=self.agefac,
309
+ swells=swells,
310
+ )
311
+ hs_dspart = np.sqrt(np.sum(dspart.isel(time=0, site=0).spec.hs().values ** 2))
312
+ # assert hs_dspart == pytest.approx(self.hs_from_partitions, rel=1e-2)
313
+
314
+ # def test_smoothing(self):
315
+ # swells = 2
316
+ # ds_nosmoothing = self.pt.ptm1(
317
+ # wspd=self.dset.wspd,
318
+ # wdir=self.dset.wdir,
319
+ # dpt=self.dset.dpt,
320
+ # swells=swells,
321
+ # )
322
+ # ds_smoothing = self.pt.ptm1(
323
+ # wspd=self.dset.wspd,
324
+ # wdir=self.dset.wdir,
325
+ # dpt=self.dset.dpt,
326
+ # swells=swells,
327
+ # smooth=True,
328
+ # )
329
+ # assert not ds_nosmoothing.spec.hs().equals(ds_smoothing.spec.hs())
330
+
331
+ # def test_compare_legacy(self):
332
+ # kwargs = {"agefac": self.agefac, "wscut": self.wscut, "swells": self.swells}
333
+ # old = self.dset.spec.partition_deprecated(
334
+ # wsp_darr=self.dset.wspd,
335
+ # wdir_darr=self.dset.wdir,
336
+ # dep_darr=self.dset.dpt,
337
+ # **kwargs,
338
+ # )
339
+ # new = self.pt.ptm1(
340
+ # wspd=self.dset.wspd, wdir=self.dset.wdir, dpt=self.dset.dpt, **kwargs,
341
+ # )
342
+ # assert np.array_equal(old.spec.hs().values, new.spec.hs().values)
343
+
344
+
345
+ class TestBbox(BasePTM):
346
+ def test_default(self):
347
+ bboxes = [
348
+ dict(fmin=0.1, fmax=0.2, dmin=None, dmax=None),
349
+ dict(fmin=0.2, fmax=0.3, dmin=None, dmax=None),
350
+ ]
351
+ ds = self.pt.bbox(bboxes=bboxes)
352
+ assert ds.part.size == 3
353
+
354
+ def test_ignore_dlimits(self):
355
+ bboxes = [dict(fmin=0.1, fmax=0.2), dict(fmin=0.2, fmax=0.3)]
356
+ ds = self.pt.bbox(bboxes=bboxes)
357
+ assert ds.part.size == 3
358
+
359
+ def test_overlap(self):
360
+ bboxes = [
361
+ dict(fmin=0.1, fmax=0.2, dmin=None, dmax=None),
362
+ dict(fmin=0.15, fmax=0.3, dmin=None, dmax=None),
363
+ ]
364
+ with pytest.raises(ValueError):
365
+ ds = self.pt.bbox(bboxes=bboxes)
366
+
367
+ def test_freq_increasing(self):
368
+ bboxes = [dict(fmin=0.2, fmax=0.1, dmin=None, dmax=None)]
369
+ with pytest.raises(ValueError):
370
+ ds = self.pt.bbox(bboxes=bboxes)
371
+
372
+
373
+ class TestPartitionAndTrack(BasePTM):
374
+ def setup_class(self):
375
+ super().setup_class(self)
376
+
377
+ def test_partition_class(self):
378
+ swells = 2
379
+ dspart = self.pt.ptm1(
380
+ wspd=self.dset.wspd,
381
+ wdir=self.dset.wdir,
382
+ dpt=self.dset.dpt,
383
+ swells=swells,
384
+ )
385
+ stats = dspart.spec.stats(["fp", "dpm"]).load()
386
+ part_ids = track_partitions(stats, wspd=self.dset.wspd)
387
+
388
+ def test_class(self):
389
+ swells = 2
390
+ dspart = self.pt.ptm1_track(
391
+ wspd=self.dset.wspd,
392
+ wdir=self.dset.wdir,
393
+ dpt=self.dset.dpt,
394
+ swells=swells,
395
+ )
396
+ assert "part_id" in dspart
397
+ assert "npart_id" in dspart