eo-tides 0.6.0__tar.gz → 0.6.1__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.
- {eo_tides-0.6.0 → eo_tides-0.6.1}/PKG-INFO +3 -2
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/model.py +5 -4
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/utils.py +16 -14
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides.egg-info/PKG-INFO +3 -2
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides.egg-info/requires.txt +2 -1
- {eo_tides-0.6.0 → eo_tides-0.6.1}/pyproject.toml +3 -2
- {eo_tides-0.6.0 → eo_tides-0.6.1}/tests/test_utils.py +82 -1
- {eo_tides-0.6.0 → eo_tides-0.6.1}/LICENSE +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/README.md +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/__init__.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/eo.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/stats.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides/validation.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides.egg-info/SOURCES.txt +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides.egg-info/dependency_links.txt +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/eo_tides.egg-info/top_level.txt +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/setup.cfg +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/tests/test_eo.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/tests/test_model.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/tests/test_stats.py +0 -0
- {eo_tides-0.6.0 → eo_tides-0.6.1}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: eo-tides
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.1
|
4
4
|
Summary: Tide modelling tools for large-scale satellite earth observation analysis
|
5
5
|
Author: Robbi Bishop-Taylor, Stephen Sagar, Claire Phillips, Vanessa Newey
|
6
6
|
Author-email: Robbi.BishopTaylor@ga.gov.au
|
@@ -32,10 +32,11 @@ Requires-Dist: pandas>=2.2.0
|
|
32
32
|
Requires-Dist: psutil>=5.8.0
|
33
33
|
Requires-Dist: pyogrio>=0.10.0
|
34
34
|
Requires-Dist: pyproj>=3.7.0
|
35
|
-
Requires-Dist: pyTMD
|
35
|
+
Requires-Dist: pyTMD>=2.2.2
|
36
36
|
Requires-Dist: scikit-learn>=1.4.0
|
37
37
|
Requires-Dist: scipy>=1.14.1
|
38
38
|
Requires-Dist: shapely>=2.0.6
|
39
|
+
Requires-Dist: timescale>=0.0.3
|
39
40
|
Requires-Dist: tqdm>=4.55.0
|
40
41
|
Requires-Dist: xarray>=2022.3.0
|
41
42
|
Provides-Extra: notebooks
|
@@ -19,6 +19,7 @@ import numpy as np
|
|
19
19
|
import pandas as pd
|
20
20
|
import pyproj
|
21
21
|
import pyTMD
|
22
|
+
import timescale.time
|
22
23
|
from tqdm import tqdm
|
23
24
|
|
24
25
|
from .utils import DatetimeLike, _set_directory, _standardise_models, _standardise_time, idw
|
@@ -95,7 +96,7 @@ def _model_tides(
|
|
95
96
|
lon, lat = transformer.transform(x.flatten(), y.flatten())
|
96
97
|
|
97
98
|
# Convert datetime
|
98
|
-
|
99
|
+
ts = timescale.time.Timescale().from_datetime(time.flatten())
|
99
100
|
|
100
101
|
try:
|
101
102
|
# Read tidal constants and interpolate to grid points
|
@@ -136,10 +137,10 @@ def _model_tides(
|
|
136
137
|
# Compute delta times based on model
|
137
138
|
if pytmd_model.corrections in ("OTIS", "ATLAS", "TMD3", "netcdf"):
|
138
139
|
# Use delta time at 2000.0 to match TMD outputs
|
139
|
-
deltat = np.zeros_like(
|
140
|
+
deltat = np.zeros_like(ts.tt_ut1)
|
140
141
|
else:
|
141
142
|
# Use interpolated delta times
|
142
|
-
deltat =
|
143
|
+
deltat = ts.tt_ut1
|
143
144
|
|
144
145
|
# In "one-to-many" mode, extracted tidal constituents and timesteps
|
145
146
|
# are repeated/multiplied out to match the number of input points and
|
@@ -149,7 +150,7 @@ def _model_tides(
|
|
149
150
|
points_repeat = len(x) if mode == "one-to-many" else 1
|
150
151
|
time_repeat = len(time) if mode == "one-to-many" else 1
|
151
152
|
t, hc, deltat = (
|
152
|
-
np.tile(
|
153
|
+
np.tile(ts.tide, points_repeat),
|
153
154
|
hc.repeat(time_repeat, axis=0),
|
154
155
|
np.tile(deltat, points_repeat),
|
155
156
|
)
|
@@ -181,9 +181,9 @@ def _clip_model_file(
|
|
181
181
|
"""
|
182
182
|
Clips tide model netCDF datasets to a bounding box.
|
183
183
|
|
184
|
-
If the bounding box crosses 0 degrees longitude (e.g. Greenwich
|
185
|
-
the
|
186
|
-
|
184
|
+
If the bounding box crosses 0 degrees longitude (e.g. Greenwich prime
|
185
|
+
meridian), the dataset will be clipped into two parts and concatenated
|
186
|
+
along the x-dimension to create a continuous result.
|
187
187
|
|
188
188
|
Parameters
|
189
189
|
----------
|
@@ -226,20 +226,22 @@ def _clip_model_file(
|
|
226
226
|
xcoords = nc[xcoord].compute()
|
227
227
|
ycoords = nc[ycoord].compute()
|
228
228
|
|
229
|
-
#
|
230
|
-
|
229
|
+
# Convert longitudes to 0-360 convention
|
230
|
+
left = bbox.left % 360
|
231
|
+
right = bbox.right % 360
|
232
|
+
|
233
|
+
# If left coordinate is smaller than right, bbox does not cross
|
234
|
+
# zero longitude and can be clipped directly
|
235
|
+
if left <= right: # bbox does not cross 0
|
231
236
|
nc_clipped = nc.sel({
|
232
237
|
ydim: (ycoords >= bbox.bottom) & (ycoords <= bbox.top),
|
233
|
-
xdim: (xcoords >=
|
238
|
+
xdim: (xcoords >= left) & (xcoords <= right),
|
234
239
|
})
|
235
240
|
|
236
|
-
# If
|
237
|
-
# separately and then combine into one
|
238
|
-
|
239
|
-
|
240
|
-
left = bbox.left % 360
|
241
|
-
right = bbox.right % 360
|
242
|
-
|
241
|
+
# If left coordinate is larger than right, bbox crosses zero longitude.
|
242
|
+
# If so, extract left and right separately and then combine into one
|
243
|
+
# concatenated dataset
|
244
|
+
elif left > right: # bbox crosses 0
|
243
245
|
# Extract data from left of 0 longitude, and convert lon
|
244
246
|
# coords to -180 to 0 range to enable continuous interpolation
|
245
247
|
# across 0 boundary
|
@@ -357,7 +359,7 @@ def clip_models(
|
|
357
359
|
model_files = model_database[m].get("model_file", [])
|
358
360
|
grid_file = model_database[m].get("grid_file", [])
|
359
361
|
|
360
|
-
# Convert to list
|
362
|
+
# Convert to list of strings and combine
|
361
363
|
model_files = model_files if isinstance(model_files, list) else [model_files]
|
362
364
|
grid_file = grid_file if isinstance(grid_file, list) else [grid_file]
|
363
365
|
all_files = model_files + grid_file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: eo-tides
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.1
|
4
4
|
Summary: Tide modelling tools for large-scale satellite earth observation analysis
|
5
5
|
Author: Robbi Bishop-Taylor, Stephen Sagar, Claire Phillips, Vanessa Newey
|
6
6
|
Author-email: Robbi.BishopTaylor@ga.gov.au
|
@@ -32,10 +32,11 @@ Requires-Dist: pandas>=2.2.0
|
|
32
32
|
Requires-Dist: psutil>=5.8.0
|
33
33
|
Requires-Dist: pyogrio>=0.10.0
|
34
34
|
Requires-Dist: pyproj>=3.7.0
|
35
|
-
Requires-Dist: pyTMD
|
35
|
+
Requires-Dist: pyTMD>=2.2.2
|
36
36
|
Requires-Dist: scikit-learn>=1.4.0
|
37
37
|
Requires-Dist: scipy>=1.14.1
|
38
38
|
Requires-Dist: shapely>=2.0.6
|
39
|
+
Requires-Dist: timescale>=0.0.3
|
39
40
|
Requires-Dist: tqdm>=4.55.0
|
40
41
|
Requires-Dist: xarray>=2022.3.0
|
41
42
|
Provides-Extra: notebooks
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "eo-tides"
|
3
|
-
version = "0.6.
|
3
|
+
version = "0.6.1"
|
4
4
|
description = "Tide modelling tools for large-scale satellite earth observation analysis"
|
5
5
|
authors = [
|
6
6
|
{ name = "Robbi Bishop-Taylor" },
|
@@ -44,10 +44,11 @@ dependencies = [
|
|
44
44
|
"psutil>=5.8.0",
|
45
45
|
"pyogrio>=0.10.0",
|
46
46
|
"pyproj>=3.7.0",
|
47
|
-
"pyTMD
|
47
|
+
"pyTMD>=2.2.2",
|
48
48
|
"scikit-learn>=1.4.0",
|
49
49
|
"scipy>=1.14.1",
|
50
50
|
"shapely>=2.0.6",
|
51
|
+
"timescale>=0.0.3",
|
51
52
|
"tqdm>=4.55.0",
|
52
53
|
"xarray>=2022.3.0",
|
53
54
|
]
|
@@ -3,9 +3,11 @@ import tempfile
|
|
3
3
|
from datetime import datetime
|
4
4
|
|
5
5
|
import numpy as np
|
6
|
+
import odc.geo.geom
|
6
7
|
import pandas as pd
|
7
8
|
import pytest
|
8
9
|
|
10
|
+
from eo_tides.model import model_tides
|
9
11
|
from eo_tides.utils import _standardise_models, _standardise_time, clip_models, idw, list_models
|
10
12
|
|
11
13
|
|
@@ -53,17 +55,96 @@ def test_standardise_models(model, ensemble_models, exp_process, exp_request, ex
|
|
53
55
|
|
54
56
|
|
55
57
|
def test_clip_models():
|
58
|
+
# Set input and output paths
|
59
|
+
in_dir = "tests/data/tide_models"
|
56
60
|
out_dir = pathlib.Path("tests/data/tide_models_clipped")
|
57
61
|
|
62
|
+
# Clip models to bbox
|
58
63
|
clip_models(
|
59
|
-
input_directory=
|
64
|
+
input_directory=in_dir,
|
60
65
|
output_directory=out_dir,
|
61
66
|
bbox=(122.27, -18.07, 122.29, -18.05),
|
62
67
|
)
|
63
68
|
|
69
|
+
# Assert that files were exported for all available models
|
64
70
|
output_files = set([i.stem for i in out_dir.iterdir()])
|
65
71
|
assert output_files == set(["GOT5", "EOT20", "hamtide"])
|
66
72
|
|
73
|
+
# Set modelling location
|
74
|
+
x, y = 122.28, -18.06
|
75
|
+
time = pd.date_range(start="2000-01", end="2001-03", freq="5h")
|
76
|
+
|
77
|
+
# Model using unclipped vs clipped files
|
78
|
+
df_unclipped = model_tides(
|
79
|
+
x=x,
|
80
|
+
y=y,
|
81
|
+
time=time,
|
82
|
+
model="HAMTIDE11",
|
83
|
+
directory=in_dir,
|
84
|
+
crop=False,
|
85
|
+
)
|
86
|
+
df_clipped = model_tides(
|
87
|
+
x=x,
|
88
|
+
y=y,
|
89
|
+
time=time,
|
90
|
+
model="HAMTIDE11",
|
91
|
+
directory=out_dir,
|
92
|
+
crop=False,
|
93
|
+
)
|
94
|
+
|
95
|
+
# Verify both produce the same results
|
96
|
+
assert np.allclose(df_unclipped.tide_height, df_clipped.tide_height)
|
97
|
+
|
98
|
+
|
99
|
+
# Test clipping across multiple global locations using synthetic HAMTIDE11 data
|
100
|
+
@pytest.mark.parametrize(
|
101
|
+
"bbox, name",
|
102
|
+
[
|
103
|
+
((-166, 14, -151, 29), "hawaii"), # entirely W of prime meridian
|
104
|
+
((-13, 49, 6, 60), "uk"), # crossing prime meridian
|
105
|
+
((105.292969, -47.872144, 160.312500, -5.266008), "aus"), # entirely E of prime meridian
|
106
|
+
((-256.640625, 7.013668, -119.794922, 63.391522), "pacific"), # crossing antimeridian
|
107
|
+
],
|
108
|
+
)
|
109
|
+
def test_clip_models_bbox(bbox, name):
|
110
|
+
# Set input and output paths
|
111
|
+
in_dir = "tests/data/tide_models_synthetic/"
|
112
|
+
out_dir = f"tests/data/tide_models_synthetic_{name}/"
|
113
|
+
|
114
|
+
# Clip models to input bbox
|
115
|
+
clip_models(
|
116
|
+
input_directory=in_dir,
|
117
|
+
output_directory=out_dir,
|
118
|
+
bbox=bbox,
|
119
|
+
model="HAMTIDE11",
|
120
|
+
overwrite=True,
|
121
|
+
)
|
122
|
+
|
123
|
+
# Set modelling location based on bbox centroid
|
124
|
+
x, y = odc.geo.geom.BoundingBox(*bbox, crs="EPSG:4326").polygon.centroid.xy
|
125
|
+
time = pd.date_range(start="2000-01", end="2001-03", freq="5h")
|
126
|
+
|
127
|
+
# Model using unclipped vs clipped files
|
128
|
+
df_unclipped = model_tides(
|
129
|
+
x=x,
|
130
|
+
y=y,
|
131
|
+
time=time,
|
132
|
+
model="HAMTIDE11",
|
133
|
+
directory=in_dir,
|
134
|
+
crop=False,
|
135
|
+
)
|
136
|
+
df_clipped = model_tides(
|
137
|
+
x=x,
|
138
|
+
y=y,
|
139
|
+
time=time,
|
140
|
+
model="HAMTIDE11",
|
141
|
+
directory=out_dir,
|
142
|
+
crop=False,
|
143
|
+
)
|
144
|
+
|
145
|
+
# Verify both produce the same results
|
146
|
+
assert np.allclose(df_unclipped.tide_height, df_clipped.tide_height)
|
147
|
+
|
67
148
|
|
68
149
|
@pytest.mark.parametrize(
|
69
150
|
"input_value, expected_output",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|