eo-tides 0.0.21__tar.gz → 0.0.22__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.0.21 → eo_tides-0.0.22}/PKG-INFO +16 -15
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/model.py +5 -1
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/stats.py +75 -21
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides.egg-info/PKG-INFO +16 -15
- eo_tides-0.0.22/eo_tides.egg-info/requires.txt +19 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/pyproject.toml +29 -30
- {eo_tides-0.0.21 → eo_tides-0.0.22}/tests/test_model.py +48 -49
- eo_tides-0.0.21/eo_tides.egg-info/requires.txt +0 -18
- {eo_tides-0.0.21 → eo_tides-0.0.22}/LICENSE +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/README.md +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/__init__.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/eo.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/utils.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides/validation.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides.egg-info/SOURCES.txt +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides.egg-info/dependency_links.txt +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/eo_tides.egg-info/top_level.txt +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/setup.cfg +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/tests/test_eo.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/tests/test_stats.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/tests/test_utils.py +0 -0
- {eo_tides-0.0.21 → eo_tides-0.0.22}/tests/test_validation.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: eo-tides
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.22
|
4
4
|
Summary: Tide modelling tools for large-scale satellite earth observation analysis
|
5
5
|
Author-email: Robbi Bishop-Taylor <Robbi.BishopTaylor@ga.gov.au>
|
6
6
|
Project-URL: Homepage, https://GeoscienceAustralia.github.io/eo-tides/
|
@@ -22,23 +22,24 @@ Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Requires-Python: <4.0,>=3.9
|
23
23
|
Description-Content-Type: text/markdown
|
24
24
|
License-File: LICENSE
|
25
|
-
Requires-Dist: colorama
|
26
|
-
Requires-Dist: geopandas>=
|
27
|
-
Requires-Dist:
|
28
|
-
Requires-Dist:
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
25
|
+
Requires-Dist: colorama>=0.4.3
|
26
|
+
Requires-Dist: geopandas>=0.10.0
|
27
|
+
Requires-Dist: matplotlib>=3.8.0
|
28
|
+
Requires-Dist: numpy>=1.26.0
|
29
|
+
Requires-Dist: odc-geo>=0.4.7
|
30
|
+
Requires-Dist: pandas>=2.2.0
|
31
|
+
Requires-Dist: pyproj>=3.6.1
|
31
32
|
Requires-Dist: pyTMD==2.1.6
|
32
|
-
Requires-Dist: scikit-learn
|
33
|
-
Requires-Dist: scipy
|
34
|
-
Requires-Dist: shapely
|
35
|
-
Requires-Dist: tqdm
|
36
|
-
Requires-Dist: xarray
|
33
|
+
Requires-Dist: scikit-learn>=1.4.0
|
34
|
+
Requires-Dist: scipy>=1.11.2
|
35
|
+
Requires-Dist: shapely>=2.0.6
|
36
|
+
Requires-Dist: tqdm>=4.55.0
|
37
|
+
Requires-Dist: xarray>=2022.3.0
|
37
38
|
Provides-Extra: notebooks
|
38
39
|
Requires-Dist: odc-stac>=0.3.10; extra == "notebooks"
|
39
|
-
Requires-Dist: pystac-client; extra == "notebooks"
|
40
|
-
Requires-Dist: folium; extra == "notebooks"
|
41
|
-
Requires-Dist:
|
40
|
+
Requires-Dist: pystac-client>=0.8.3; extra == "notebooks"
|
41
|
+
Requires-Dist: folium>=0.16.0; extra == "notebooks"
|
42
|
+
Requires-Dist: planetary_computer>=1.0.0; extra == "notebooks"
|
42
43
|
|
43
44
|
# `eo-tides`: Tide modelling tools for large-scale satellite earth observation analysis
|
44
45
|
|
@@ -243,7 +243,7 @@ def _model_tides(
|
|
243
243
|
lon,
|
244
244
|
lat,
|
245
245
|
pytmd_model.model_file,
|
246
|
-
grid=pytmd_model.
|
246
|
+
grid=pytmd_model.file_format,
|
247
247
|
crop=crop,
|
248
248
|
bounds=bounds,
|
249
249
|
method=method,
|
@@ -277,6 +277,10 @@ def _model_tides(
|
|
277
277
|
|
278
278
|
# Delta time (TT - UT1)
|
279
279
|
deltat = timescale.tt_ut1
|
280
|
+
else:
|
281
|
+
raise Exception(
|
282
|
+
f"Unsupported model format ({pytmd_model.format}). This may be due to an incompatible version of `pyTMD`."
|
283
|
+
)
|
280
284
|
|
281
285
|
# Calculate complex phase in radians for Euler's
|
282
286
|
cph = -1j * ph * np.pi / 180.0
|
@@ -26,8 +26,10 @@ def tide_stats(
|
|
26
26
|
tidepost_lon: float | None = None,
|
27
27
|
plain_english: bool = True,
|
28
28
|
plot: bool = True,
|
29
|
+
plot_col: str | None = None,
|
29
30
|
modelled_freq: str = "2h",
|
30
31
|
linear_reg: bool = False,
|
32
|
+
min_max_q: tuple = (0.0, 1.0),
|
31
33
|
round_stats: int = 3,
|
32
34
|
**model_tides_kwargs,
|
33
35
|
) -> pd.Series:
|
@@ -73,6 +75,10 @@ def tide_stats(
|
|
73
75
|
An optional boolean indicating whether to plot how satellite-
|
74
76
|
observed tide heights compare against the full tidal range.
|
75
77
|
Defaults to True.
|
78
|
+
plot_col : str, optional
|
79
|
+
Optional name of a coordinate, dimension or variable in the array
|
80
|
+
that will be used to plot observations with unique symbols.
|
81
|
+
Defaults to None, which will plot all observations as circles.
|
76
82
|
modelled_freq : str, optional
|
77
83
|
An optional string giving the frequency at which to model tides
|
78
84
|
when computing the full modelled tidal range. Defaults to '2h',
|
@@ -84,6 +90,11 @@ def tide_stats(
|
|
84
90
|
increasing trends over time. This may indicate whether your
|
85
91
|
satellite data may produce misleading trends based on uneven
|
86
92
|
sampling of the local tide regime.
|
93
|
+
min_max_q : tuple, optional
|
94
|
+
Quantiles used to calculate max and min observed and modelled
|
95
|
+
astronomical tides. By default `(0.0, 1.0)` which is equivalent
|
96
|
+
to minimum and maximum; to use a softer threshold that is more
|
97
|
+
robust to outliers, use e.g. `(0.1, 0.9)`.
|
87
98
|
round_stats : int, optional
|
88
99
|
The number of decimal places used to round the output statistics.
|
89
100
|
Defaults to 3.
|
@@ -135,6 +146,7 @@ def tide_stats(
|
|
135
146
|
return_tideposts=True,
|
136
147
|
**model_tides_kwargs,
|
137
148
|
)
|
149
|
+
ds_tides = ds_tides.sortby("time")
|
138
150
|
|
139
151
|
# Drop spatial ref for nicer plotting
|
140
152
|
ds_tides = ds_tides.drop_vars("spatial_ref")
|
@@ -160,8 +172,8 @@ def tide_stats(
|
|
160
172
|
# Get coarse statistics on all and observed tidal ranges
|
161
173
|
obs_mean = ds_tides.tide_height.mean().item()
|
162
174
|
all_mean = all_tides_df.tide_height.mean()
|
163
|
-
obs_min, obs_max = ds_tides.tide_height.quantile(
|
164
|
-
all_min, all_max = all_tides_df.tide_height.quantile(
|
175
|
+
obs_min, obs_max = ds_tides.tide_height.quantile(min_max_q).values
|
176
|
+
all_min, all_max = all_tides_df.tide_height.quantile(min_max_q).values
|
165
177
|
|
166
178
|
# Calculate tidal range
|
167
179
|
obs_range = obs_max - obs_min
|
@@ -169,47 +181,89 @@ def tide_stats(
|
|
169
181
|
|
170
182
|
# Calculate Bishop-Taylor et al. 2018 tidal metrics
|
171
183
|
spread = obs_range / all_range
|
172
|
-
|
173
|
-
|
184
|
+
low_tide_offset_m = abs(all_min - obs_min)
|
185
|
+
high_tide_offset_m = abs(all_max - obs_max)
|
186
|
+
low_tide_offset = low_tide_offset_m / all_range
|
187
|
+
high_tide_offset = high_tide_offset_m / all_range
|
188
|
+
|
189
|
+
# Plain text descriptors
|
190
|
+
mean_diff = "higher" if obs_mean > all_mean else "lower"
|
191
|
+
mean_diff_icon = "⬆️" if obs_mean > all_mean else "⬇️"
|
192
|
+
spread_icon = "🟢" if spread >= 0.9 else "🟡" if 0.7 < spread <= 0.9 else "🔴"
|
193
|
+
low_tide_icon = "🟢" if low_tide_offset <= 0.1 else "🟡" if 0.1 <= low_tide_offset < 0.2 else "🔴"
|
194
|
+
high_tide_icon = "🟢" if high_tide_offset <= 0.1 else "🟡" if 0.1 <= high_tide_offset < 0.2 else "🔴"
|
174
195
|
|
175
196
|
# Extract x (time in decimal years) and y (distance) values
|
176
197
|
all_times = all_tides_df.index.get_level_values("time")
|
177
|
-
all_x = all_times.year + ((all_times.dayofyear - 1) / 365) + ((all_times.hour
|
198
|
+
all_x = all_times.year + ((all_times.dayofyear - 1) / 365) + ((all_times.hour) / 24)
|
178
199
|
time_period = all_x.max() - all_x.min()
|
179
200
|
|
180
201
|
# Extract x (time in decimal years) and y (distance) values
|
181
|
-
obs_x = ds_tides.time.dt.year + ((ds_tides.time.dt.dayofyear - 1) / 365) + ((ds_tides.time.dt.hour
|
202
|
+
obs_x = ds_tides.time.dt.year + ((ds_tides.time.dt.dayofyear - 1) / 365) + ((ds_tides.time.dt.hour) / 24)
|
182
203
|
obs_y = ds_tides.tide_height.values.astype(np.float32)
|
183
204
|
|
184
205
|
# Compute linear regression
|
185
206
|
obs_linreg = stats.linregress(x=obs_x, y=obs_y)
|
186
207
|
|
208
|
+
# return obs_linreg
|
209
|
+
|
187
210
|
if plain_english:
|
211
|
+
print(f"\n\n🌊 Modelled astronomical tide range: {all_range:.2f} metres.")
|
212
|
+
print(f"🛰️ Observed tide range: {obs_range:.2f} metres.\n")
|
213
|
+
print(f" {spread_icon} {spread:.0%} of the modelled astronomical tide range was observed at this location.")
|
214
|
+
print(
|
215
|
+
f" {high_tide_icon} The highest {high_tide_offset:.0%} ({high_tide_offset_m:.2f} metres) of the tide range was never observed."
|
216
|
+
)
|
188
217
|
print(
|
189
|
-
f"
|
190
|
-
|
191
|
-
|
192
|
-
|
218
|
+
f" {low_tide_icon} The lowest {low_tide_offset:.0%} ({low_tide_offset_m:.2f} metres) of the tide range was never observed.\n"
|
219
|
+
)
|
220
|
+
print(f"🌊 Mean modelled astronomical tide height: {all_mean:.2f} metres.")
|
221
|
+
print(f"🛰️ Mean observed tide height: {obs_mean:.2f} metres.\n")
|
222
|
+
print(
|
223
|
+
f" {mean_diff_icon} The mean observed tide height was {obs_mean - all_mean:.2f} metres {mean_diff} than the mean modelled astronomical tide height."
|
193
224
|
)
|
194
225
|
|
195
226
|
if linear_reg:
|
196
|
-
if obs_linreg.pvalue > 0.
|
197
|
-
print(
|
227
|
+
if obs_linreg.pvalue > 0.01:
|
228
|
+
print(" ➖ Observed tides showed no significant trends over time.")
|
198
229
|
else:
|
199
|
-
obs_slope_desc = "
|
230
|
+
obs_slope_desc = "decreasing" if obs_linreg.slope < 0 else "increasing"
|
200
231
|
print(
|
201
|
-
f"Observed tides {obs_slope_desc}
|
202
|
-
f"(p={obs_linreg.pvalue:.3f}) over time by "
|
203
|
-
f"{obs_linreg.slope:.03f} m per year (i.e. a "
|
204
|
-
f"~{time_period * obs_linreg.slope:.2f} m "
|
205
|
-
f"{obs_slope_desc} over the ~{time_period:.0f} year period)."
|
232
|
+
f" ⚠️ Observed tides showed a significant {obs_slope_desc} trend over time (p={obs_linreg.pvalue:.3f}, {obs_linreg.slope:.2f} metres per year)"
|
206
233
|
)
|
207
234
|
|
208
235
|
if plot:
|
209
236
|
# Create plot and add all time and observed tide data
|
210
|
-
fig, ax = plt.subplots(figsize=(10,
|
211
|
-
all_tides_df.reset_index(["x", "y"]).tide_height.plot(ax=ax, alpha=0.4)
|
212
|
-
|
237
|
+
fig, ax = plt.subplots(figsize=(10, 6))
|
238
|
+
all_tides_df.reset_index(["x", "y"]).tide_height.plot(ax=ax, alpha=0.4, label="Modelled tides")
|
239
|
+
|
240
|
+
# Look through custom column values if provided
|
241
|
+
if plot_col is not None:
|
242
|
+
# Create a list of marker styles
|
243
|
+
markers = ["o", "^", "s", "D", "v", "<", ">", "p", "*", "h", "H", "+", "x", "d", "|", "_"]
|
244
|
+
for i, value in enumerate(np.unique(ds_tides[plot_col])):
|
245
|
+
ds_tides.where(ds_tides[plot_col] == value, drop=True).tide_height.plot.line(
|
246
|
+
ax=ax,
|
247
|
+
linewidth=0.0,
|
248
|
+
color="black",
|
249
|
+
marker=markers[i % len(markers)],
|
250
|
+
markersize=4,
|
251
|
+
label=value,
|
252
|
+
)
|
253
|
+
# Otherwise, plot all data at once
|
254
|
+
else:
|
255
|
+
ds_tides.tide_height.plot.line(
|
256
|
+
ax=ax, marker="o", linewidth=0.0, color="black", markersize=3.5, label="Satellite observations"
|
257
|
+
)
|
258
|
+
|
259
|
+
ax.legend(loc="upper center", bbox_to_anchor=(0.5, 1.04), ncol=20, borderaxespad=0, frameon=False)
|
260
|
+
|
261
|
+
ax.plot(
|
262
|
+
ds_tides.time.isel(time=[0, -1]),
|
263
|
+
obs_linreg.intercept + obs_linreg.slope * obs_x[[0, -1]],
|
264
|
+
"r",
|
265
|
+
label="fitted line",
|
266
|
+
)
|
213
267
|
|
214
268
|
# Add horizontal lines for spread/offsets
|
215
269
|
ax.axhline(obs_min, color="black", linestyle=":", linewidth=1)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: eo-tides
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.22
|
4
4
|
Summary: Tide modelling tools for large-scale satellite earth observation analysis
|
5
5
|
Author-email: Robbi Bishop-Taylor <Robbi.BishopTaylor@ga.gov.au>
|
6
6
|
Project-URL: Homepage, https://GeoscienceAustralia.github.io/eo-tides/
|
@@ -22,23 +22,24 @@ Classifier: Programming Language :: Python :: 3.12
|
|
22
22
|
Requires-Python: <4.0,>=3.9
|
23
23
|
Description-Content-Type: text/markdown
|
24
24
|
License-File: LICENSE
|
25
|
-
Requires-Dist: colorama
|
26
|
-
Requires-Dist: geopandas>=
|
27
|
-
Requires-Dist:
|
28
|
-
Requires-Dist:
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
25
|
+
Requires-Dist: colorama>=0.4.3
|
26
|
+
Requires-Dist: geopandas>=0.10.0
|
27
|
+
Requires-Dist: matplotlib>=3.8.0
|
28
|
+
Requires-Dist: numpy>=1.26.0
|
29
|
+
Requires-Dist: odc-geo>=0.4.7
|
30
|
+
Requires-Dist: pandas>=2.2.0
|
31
|
+
Requires-Dist: pyproj>=3.6.1
|
31
32
|
Requires-Dist: pyTMD==2.1.6
|
32
|
-
Requires-Dist: scikit-learn
|
33
|
-
Requires-Dist: scipy
|
34
|
-
Requires-Dist: shapely
|
35
|
-
Requires-Dist: tqdm
|
36
|
-
Requires-Dist: xarray
|
33
|
+
Requires-Dist: scikit-learn>=1.4.0
|
34
|
+
Requires-Dist: scipy>=1.11.2
|
35
|
+
Requires-Dist: shapely>=2.0.6
|
36
|
+
Requires-Dist: tqdm>=4.55.0
|
37
|
+
Requires-Dist: xarray>=2022.3.0
|
37
38
|
Provides-Extra: notebooks
|
38
39
|
Requires-Dist: odc-stac>=0.3.10; extra == "notebooks"
|
39
|
-
Requires-Dist: pystac-client; extra == "notebooks"
|
40
|
-
Requires-Dist: folium; extra == "notebooks"
|
41
|
-
Requires-Dist:
|
40
|
+
Requires-Dist: pystac-client>=0.8.3; extra == "notebooks"
|
41
|
+
Requires-Dist: folium>=0.16.0; extra == "notebooks"
|
42
|
+
Requires-Dist: planetary_computer>=1.0.0; extra == "notebooks"
|
42
43
|
|
43
44
|
# `eo-tides`: Tide modelling tools for large-scale satellite earth observation analysis
|
44
45
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
colorama>=0.4.3
|
2
|
+
geopandas>=0.10.0
|
3
|
+
matplotlib>=3.8.0
|
4
|
+
numpy>=1.26.0
|
5
|
+
odc-geo>=0.4.7
|
6
|
+
pandas>=2.2.0
|
7
|
+
pyproj>=3.6.1
|
8
|
+
pyTMD==2.1.6
|
9
|
+
scikit-learn>=1.4.0
|
10
|
+
scipy>=1.11.2
|
11
|
+
shapely>=2.0.6
|
12
|
+
tqdm>=4.55.0
|
13
|
+
xarray>=2022.3.0
|
14
|
+
|
15
|
+
[notebooks]
|
16
|
+
odc-stac>=0.3.10
|
17
|
+
pystac-client>=0.8.3
|
18
|
+
folium>=0.16.0
|
19
|
+
planetary_computer>=1.0.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "eo-tides"
|
3
|
-
version = "0.0.
|
3
|
+
version = "0.0.22"
|
4
4
|
description = "Tide modelling tools for large-scale satellite earth observation analysis"
|
5
5
|
authors = [{ name = "Robbi Bishop-Taylor", email = "Robbi.BishopTaylor@ga.gov.au" }]
|
6
6
|
readme = "README.md"
|
@@ -30,19 +30,19 @@ classifiers = [
|
|
30
30
|
]
|
31
31
|
requires-python = ">=3.9,<4.0"
|
32
32
|
dependencies = [
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
33
|
+
"colorama>=0.4.3",
|
34
|
+
"geopandas>=0.10.0",
|
35
|
+
"matplotlib>=3.8.0",
|
36
|
+
"numpy>=1.26.0",
|
37
|
+
"odc-geo>=0.4.7",
|
38
|
+
"pandas>=2.2.0",
|
39
|
+
"pyproj>=3.6.1",
|
40
|
+
"pyTMD==2.1.6",
|
41
|
+
"scikit-learn>=1.4.0",
|
42
|
+
"scipy>=1.11.2",
|
43
|
+
"shapely>=2.0.6",
|
44
|
+
"tqdm>=4.55.0",
|
45
|
+
"xarray>=2022.3.0",
|
46
46
|
]
|
47
47
|
|
48
48
|
[project.urls]
|
@@ -53,28 +53,27 @@ Documentation = "https://GeoscienceAustralia.github.io/eo-tides/"
|
|
53
53
|
[project.optional-dependencies]
|
54
54
|
notebooks = [
|
55
55
|
"odc-stac>=0.3.10",
|
56
|
-
"pystac-client",
|
57
|
-
"folium",
|
58
|
-
"
|
56
|
+
"pystac-client>=0.8.3",
|
57
|
+
"folium>=0.16.0",
|
58
|
+
"planetary_computer>=1.0.0",
|
59
59
|
]
|
60
60
|
|
61
61
|
[tool.uv]
|
62
62
|
dev-dependencies = [
|
63
|
-
"pytest>=
|
64
|
-
"
|
65
|
-
"pre-commit>=2.20.0",
|
66
|
-
"tox-uv>=1.11.3",
|
63
|
+
"pytest>=6.0.0",
|
64
|
+
"pre-commit>=0.2.0",
|
67
65
|
"deptry>=0.20.0",
|
68
|
-
"mypy>=0.
|
69
|
-
"pytest-cov>=
|
70
|
-
"ruff>=0.
|
71
|
-
"mkdocs>=1.
|
72
|
-
"mkdocs-material>=
|
73
|
-
"mkdocs-jupyter>=0.
|
74
|
-
"mkdocstrings[python]>=0.
|
66
|
+
"mypy>=0.900",
|
67
|
+
"pytest-cov>=0.6",
|
68
|
+
"ruff>=0.0.200",
|
69
|
+
"mkdocs>=1.2",
|
70
|
+
"mkdocs-material>=9.5.0",
|
71
|
+
"mkdocs-jupyter>=0.24.0",
|
72
|
+
"mkdocstrings[python]>=0.20.0",
|
73
|
+
"nbval>=0.10.0",
|
74
|
+
"odc-stac>=0.3.8",
|
75
75
|
"pystac-client>=0.8.3",
|
76
|
-
"
|
77
|
-
"black>=24.8.0",
|
76
|
+
"planetary_computer>=1.0.0",
|
78
77
|
]
|
79
78
|
|
80
79
|
[build-system]
|
@@ -3,8 +3,9 @@ import pathlib
|
|
3
3
|
import numpy as np
|
4
4
|
import pandas as pd
|
5
5
|
import pytest
|
6
|
+
from pyTMD.compute import tide_elevations
|
6
7
|
|
7
|
-
from eo_tides.model import list_models, model_tides
|
8
|
+
from eo_tides.model import _set_directory, list_models, model_tides
|
8
9
|
from eo_tides.validation import eval_metrics
|
9
10
|
|
10
11
|
GAUGE_X = 122.2183
|
@@ -12,94 +13,92 @@ GAUGE_Y = -18.0008
|
|
12
13
|
ENSEMBLE_MODELS = ["EOT20", "HAMTIDE11"] # simplified for tests
|
13
14
|
|
14
15
|
|
15
|
-
@pytest.fixture()
|
16
|
-
def measured_tides_ds():
|
17
|
-
"""
|
18
|
-
Load measured sea level data from the Broome ABSLMP tidal station:
|
19
|
-
http://www.bom.gov.au/oceanography/projects/abslmp/data/data.shtml
|
20
|
-
"""
|
21
|
-
# Metadata for Broome ABSLMP tidal station:
|
22
|
-
# http://www.bom.gov.au/oceanography/projects/abslmp/data/data.shtml
|
23
|
-
ahd_offset = -5.322
|
24
|
-
|
25
|
-
# Load measured tides from ABSLMP tide gauge data
|
26
|
-
measured_tides_df = pd.read_csv(
|
27
|
-
"tests/data/IDO71013_2020.csv",
|
28
|
-
index_col=0,
|
29
|
-
parse_dates=True,
|
30
|
-
na_values=-9999,
|
31
|
-
)[["Sea Level"]]
|
32
|
-
|
33
|
-
# Update index and column names
|
34
|
-
measured_tides_df.index.name = "time"
|
35
|
-
measured_tides_df.columns = ["tide_height"]
|
36
|
-
|
37
|
-
# Apply station AHD offset
|
38
|
-
measured_tides_df += ahd_offset
|
39
|
-
|
40
|
-
# Return as xarray dataset
|
41
|
-
return measured_tides_df.to_xarray()
|
42
|
-
|
43
|
-
|
44
16
|
# Test available tide models
|
45
17
|
def test_list_models():
|
46
18
|
# Using env var
|
47
19
|
available_models, supported_models = list_models()
|
48
|
-
assert available_models == ["EOT20", "HAMTIDE11"]
|
49
|
-
assert len(supported_models) >
|
20
|
+
assert available_models == ["EOT20", "GOT5.5", "HAMTIDE11"]
|
21
|
+
assert len(supported_models) > 3
|
50
22
|
|
51
23
|
# Not printing outputs
|
52
24
|
available_models, supported_models = list_models(show_available=False, show_supported=False)
|
53
|
-
assert available_models == ["EOT20", "HAMTIDE11"]
|
25
|
+
assert available_models == ["EOT20", "GOT5.5", "HAMTIDE11"]
|
54
26
|
|
55
27
|
# Providing a string path
|
56
28
|
available_models, supported_models = list_models(directory="./tests/data/tide_models")
|
57
|
-
assert available_models == ["EOT20", "HAMTIDE11"]
|
29
|
+
assert available_models == ["EOT20", "GOT5.5", "HAMTIDE11"]
|
58
30
|
|
59
31
|
# Providing a pathlib
|
60
32
|
path = pathlib.Path("./tests/data/tide_models")
|
61
33
|
available_models, supported_models = list_models(directory=path)
|
62
|
-
assert available_models == ["EOT20", "HAMTIDE11"]
|
34
|
+
assert available_models == ["EOT20", "GOT5.5", "HAMTIDE11"]
|
63
35
|
|
64
36
|
|
65
37
|
# Run test for multiple input coordinates, CRSs and interpolation methods
|
66
38
|
@pytest.mark.parametrize(
|
67
|
-
"x, y, crs, method",
|
39
|
+
"x, y, crs, method, model",
|
68
40
|
[
|
69
|
-
(GAUGE_X, GAUGE_Y, "EPSG:4326", "bilinear"), # WGS84, bilinear interp
|
70
|
-
(GAUGE_X, GAUGE_Y, "EPSG:4326", "spline"), # WGS84, spline interp
|
41
|
+
(GAUGE_X, GAUGE_Y, "EPSG:4326", "bilinear", "EOT20"), # WGS84, bilinear interp
|
42
|
+
(GAUGE_X, GAUGE_Y, "EPSG:4326", "spline", "EOT20"), # WGS84, spline interp
|
71
43
|
(
|
72
44
|
-1034913,
|
73
45
|
-1961916,
|
74
46
|
"EPSG:3577",
|
75
47
|
"bilinear",
|
48
|
+
"EOT20",
|
76
49
|
), # Australian Albers, bilinear interp
|
50
|
+
(GAUGE_X, GAUGE_Y, "EPSG:4326", "spline", "GOT5.5"),
|
51
|
+
(GAUGE_X, GAUGE_Y, "EPSG:4326", "spline", "HAMTIDE11"),
|
77
52
|
],
|
78
53
|
)
|
79
|
-
def test_model_tides(measured_tides_ds, x, y, crs, method):
|
80
|
-
# Run
|
54
|
+
def test_model_tides(measured_tides_ds, x, y, crs, method, model):
|
55
|
+
# Run modelling for locations and timesteps in tide gauge data
|
81
56
|
modelled_tides_df = model_tides(
|
82
57
|
x=[x],
|
83
58
|
y=[y],
|
84
59
|
time=measured_tides_ds.time,
|
85
60
|
crs=crs,
|
86
61
|
method=method,
|
62
|
+
model=model,
|
87
63
|
)
|
88
64
|
|
89
|
-
# Compare measured and modelled tides
|
90
|
-
val_stats = eval_metrics(x=measured_tides_ds.tide_height, y=modelled_tides_df.tide_height)
|
91
|
-
|
92
65
|
# Test that modelled tides contain correct headings and have same
|
93
66
|
# number of timesteps
|
94
67
|
assert modelled_tides_df.index.names == ["time", "x", "y"]
|
95
68
|
assert modelled_tides_df.columns.tolist() == ["tide_model", "tide_height"]
|
96
69
|
assert len(modelled_tides_df.index) == len(measured_tides_ds.time)
|
97
70
|
|
71
|
+
# Run equivalent pyTMD code
|
72
|
+
pytmd_tides = tide_elevations(
|
73
|
+
x=x,
|
74
|
+
y=y,
|
75
|
+
delta_time=measured_tides_ds.time,
|
76
|
+
DIRECTORY=_set_directory(None),
|
77
|
+
MODEL=model,
|
78
|
+
EPSG=int(crs[-4:]),
|
79
|
+
TIME="datetime",
|
80
|
+
EXTRAPOLATE=True,
|
81
|
+
CUTOFF=np.inf,
|
82
|
+
METHOD=method,
|
83
|
+
)
|
84
|
+
|
85
|
+
# Verify that pyTMD produces same results as `model_tides`
|
86
|
+
assert np.allclose(modelled_tides_df.tide_height.values, pytmd_tides.data)
|
87
|
+
|
88
|
+
# Compare measured and modelled tides
|
89
|
+
val_stats = eval_metrics(x=measured_tides_ds.tide_height, y=modelled_tides_df.tide_height)
|
90
|
+
|
98
91
|
# Test that modelled tides meet expected accuracy
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
92
|
+
if model == "HAMTIDE11":
|
93
|
+
assert val_stats["Correlation"] > 0.99
|
94
|
+
assert val_stats["RMSE"] < 0.34
|
95
|
+
assert val_stats["R-squared"] > 0.98
|
96
|
+
assert abs(val_stats["Bias"]) < 0.20
|
97
|
+
else:
|
98
|
+
assert val_stats["Correlation"] > 0.99
|
99
|
+
assert val_stats["RMSE"] < 0.27
|
100
|
+
assert val_stats["R-squared"] > 0.99
|
101
|
+
assert abs(val_stats["Bias"]) < 0.20
|
103
102
|
|
104
103
|
|
105
104
|
# Run tests for one or multiple models, and long and wide format outputs
|
@@ -108,8 +107,8 @@ def test_model_tides(measured_tides_ds, x, y, crs, method):
|
|
108
107
|
[
|
109
108
|
(["EOT20"], "long"),
|
110
109
|
(["EOT20"], "wide"),
|
111
|
-
(["EOT20", "HAMTIDE11"], "long"),
|
112
|
-
(["EOT20", "HAMTIDE11"], "wide"),
|
110
|
+
(["EOT20", "GOT5.5", "HAMTIDE11"], "long"),
|
111
|
+
(["EOT20", "GOT5.5", "HAMTIDE11"], "wide"),
|
113
112
|
],
|
114
113
|
ids=[
|
115
114
|
"single_model_long",
|
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
|