eo-tides 0.3.0__py3-none-any.whl → 0.4.0__py3-none-any.whl

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/utils.py CHANGED
@@ -6,6 +6,7 @@ import os
6
6
  import pathlib
7
7
  import textwrap
8
8
  import warnings
9
+ from collections import Counter
9
10
  from typing import List, Union
10
11
 
11
12
  import numpy as np
@@ -23,6 +24,14 @@ from tqdm import tqdm
23
24
  DatetimeLike = Union[np.ndarray, pd.DatetimeIndex, pd.Timestamp, datetime.datetime, str, List[str]]
24
25
 
25
26
 
27
+ def _get_duplicates(array):
28
+ """
29
+ Return any duplicates in a list or array.
30
+ """
31
+ c = Counter(array)
32
+ return [k for k in c if c[k] > 1]
33
+
34
+
26
35
  def _set_directory(
27
36
  directory: str | os.PathLike | None = None,
28
37
  ) -> os.PathLike:
@@ -68,6 +77,99 @@ def _standardise_time(
68
77
  return np.atleast_1d(time)
69
78
 
70
79
 
80
+ def _standardise_models(
81
+ model: str | list[str],
82
+ directory: str | os.PathLike,
83
+ ensemble_models: list[str] | None = None,
84
+ ) -> tuple[list[str], list[str], list[str] | None]:
85
+ """
86
+ Take an input model name or list of names, and return a list
87
+ of models to process, requested models, and ensemble models,
88
+ as required by the `model_tides` function.
89
+
90
+ Handles two special values passed to `model`: "all", which
91
+ will model tides for all models available in `directory`, and
92
+ "ensemble", which will model tides for all models in a list
93
+ of custom ensemble models.
94
+ """
95
+
96
+ # Turn inputs into arrays for consistent handling
97
+ models_requested = list(np.atleast_1d(model))
98
+
99
+ # Raise error if list contains duplications
100
+ duplicates = _get_duplicates(models_requested)
101
+ if len(duplicates) > 0:
102
+ raise ValueError(f"The model parameter contains duplicate values: {duplicates}")
103
+
104
+ # Get full list of supported models from pyTMD database
105
+ available_models, valid_models = list_models(
106
+ directory, show_available=False, show_supported=False, raise_error=True
107
+ )
108
+ custom_options = ["ensemble", "all"]
109
+
110
+ # Error if any models are not supported
111
+ if not all(m in valid_models + custom_options for m in models_requested):
112
+ error_text = (
113
+ f"One or more of the requested models are not valid:\n"
114
+ f"{models_requested}\n\n"
115
+ "The following models are supported:\n"
116
+ f"{valid_models}"
117
+ )
118
+ raise ValueError(error_text)
119
+
120
+ # Error if any models are not available in `directory`
121
+ if not all(m in available_models + custom_options for m in models_requested):
122
+ error_text = (
123
+ f"One or more of the requested models are valid, but not available in `{directory}`:\n"
124
+ f"{models_requested}\n\n"
125
+ f"The following models are available in `{directory}`:\n"
126
+ f"{available_models}"
127
+ )
128
+ raise ValueError(error_text)
129
+
130
+ # If "all" models are requested, update requested list to include available models
131
+ if "all" in models_requested:
132
+ models_requested = available_models + [m for m in models_requested if m != "all"]
133
+
134
+ # If "ensemble" modeling is requested, use custom list of ensemble models
135
+ if "ensemble" in models_requested:
136
+ print("Running ensemble tide modelling")
137
+ ensemble_models = (
138
+ ensemble_models
139
+ if ensemble_models is not None
140
+ else [
141
+ "EOT20",
142
+ "FES2012",
143
+ "FES2014_extrapolated",
144
+ "FES2022_extrapolated",
145
+ "GOT4.10",
146
+ "GOT5.6_extrapolated",
147
+ "TPXO10-atlas-v2-nc",
148
+ "TPXO8-atlas-nc",
149
+ "TPXO9-atlas-v5-nc",
150
+ ]
151
+ )
152
+
153
+ # Error if any ensemble models are not available in `directory`
154
+ if not all(m in available_models for m in ensemble_models):
155
+ error_text = (
156
+ f"One or more of the requested ensemble models are not available in `{directory}`:\n"
157
+ f"{ensemble_models}\n\n"
158
+ f"The following models are available in `{directory}`:\n"
159
+ f"{available_models}"
160
+ )
161
+ raise ValueError(error_text)
162
+
163
+ # Return set of all ensemble plus any other requested models
164
+ models_to_process = sorted(list(set(ensemble_models + [m for m in models_requested if m != "ensemble"])))
165
+
166
+ # Otherwise, models to process are the same as those requested
167
+ else:
168
+ models_to_process = models_requested
169
+
170
+ return models_to_process, models_requested, ensemble_models
171
+
172
+
71
173
  def _clip_model_file(
72
174
  nc: xr.Dataset,
73
175
  bbox: BoundingBox,
@@ -178,7 +280,7 @@ def clip_models(
178
280
  output_directory: str | os.PathLike,
179
281
  bbox: tuple[float, float, float, float],
180
282
  model: list | None = None,
181
- buffer: float = 1,
283
+ buffer: float = 5,
182
284
  overwrite: bool = False,
183
285
  ):
184
286
  """
@@ -211,7 +313,7 @@ def clip_models(
211
313
  in the input directly.
212
314
  buffer : float, optional
213
315
  Buffer distance (in degrees) added to the bounding box to provide
214
- sufficient data on edges of study area. Defaults to 1 degree.
316
+ sufficient data on edges of study area. Defaults to 5 degrees.
215
317
  overwrite : bool, optional
216
318
  If True, overwrite existing files in the output directory.
217
319
  Defaults to False.
@@ -393,7 +495,14 @@ def list_models(
393
495
  expected_paths = {}
394
496
  for m in supported_models:
395
497
  model_file = model_database[m]["model_file"]
396
- model_file = model_file[0] if isinstance(model_file, list) else model_file
498
+
499
+ # Handle GOT5.6 differently to ensure we test for presence of GOT5.6 constituents
500
+ if m in ("GOT5.6", "GOT5.6_extrapolated"):
501
+ model_file = [file for file in model_file if "GOT5.6" in file][0]
502
+ else:
503
+ model_file = model_file[0] if isinstance(model_file, list) else model_file
504
+
505
+ # Add path to dict
397
506
  expected_paths[m] = str(directory / pathlib.Path(model_file).expanduser().parent)
398
507
 
399
508
  # Define column widths
eo_tides/validation.py CHANGED
@@ -5,6 +5,7 @@ from numbers import Number
5
5
 
6
6
  import geopandas as gpd
7
7
  import pandas as pd
8
+ import tqdm
8
9
  from odc.geo.geom import BoundingBox
9
10
  from pandas.tseries.offsets import MonthBegin, MonthEnd, YearBegin, YearEnd
10
11
  from scipy import stats
@@ -152,21 +153,24 @@ def _load_gauge_metadata(metadata_path):
152
153
 
153
154
 
154
155
  def _load_gesla_dataset(site, path, na_value):
155
- with warnings.catch_warnings():
156
- warnings.simplefilter("ignore", FutureWarning)
157
- gesla_df = (
158
- pd.read_csv(
159
- path,
160
- skiprows=41,
161
- names=["date", "time", "sea_level", "qc_flag", "use_flag"],
162
- sep=r"\s+", # sep="\s+",
163
- parse_dates=[[0, 1]],
164
- index_col=0,
165
- na_values=na_value,
166
- )
167
- .rename_axis("time")
168
- .assign(site_code=site)
156
+ # Read dataset
157
+ gesla_df = pd.read_csv(
158
+ path,
159
+ skiprows=41,
160
+ names=["date", "time", "sea_level", "qc_flag", "use_flag"],
161
+ sep=r"\s+",
162
+ na_values=na_value,
163
+ )
164
+
165
+ # Combine two date fields
166
+ gesla_df = (
167
+ gesla_df.assign(
168
+ time=pd.to_datetime(gesla_df["date"] + " " + gesla_df["time"]),
169
+ site_code=site,
169
170
  )
171
+ .drop(columns=["date"])
172
+ .set_index("time")
173
+ )
170
174
 
171
175
  return gesla_df
172
176
 
@@ -301,13 +305,11 @@ def load_gauge_gesla(
301
305
  paths_na = metadata_df.loc[site_code, ["file_name", "null_value"]]
302
306
 
303
307
  # Load and combine into a single dataframe
304
- data_df = (
305
- pd.concat([_load_gesla_dataset(s, p, na_value=na) for s, p, na in paths_na.itertuples()])
306
- .sort_index()
307
- .loc[slice(start_time, end_time)]
308
- .reset_index()
309
- .set_index("site_code")
310
- )
308
+ gauge_list = [
309
+ _load_gesla_dataset(s, p, na_value=na)
310
+ for s, p, na in tqdm.tqdm(paths_na.itertuples(), total=len(paths_na), desc="Loading GESLA gauges")
311
+ ]
312
+ data_df = pd.concat(gauge_list).sort_index().loc[slice(start_time, end_time)].reset_index().set_index("site_code")
311
313
 
312
314
  # Optionally filter by use flag column
313
315
  if filter_use_flag:
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eo-tides
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Tide modelling tools for large-scale satellite earth observation analysis
5
- Author: Stephen Sagar, Claire Phillips, Vanessa Newey
6
- Author-email: Robbi Bishop-Taylor <Robbi.BishopTaylor@ga.gov.au>
5
+ Author: Robbi Bishop-Taylor, Stephen Sagar, Claire Phillips, Vanessa Newey
6
+ Author-email: Robbi.BishopTaylor@ga.gov.au
7
7
  Project-URL: Homepage, https://GeoscienceAustralia.github.io/eo-tides/
8
8
  Project-URL: Repository, https://github.com/GeoscienceAustralia/eo-tides
9
9
  Project-URL: Documentation, https://GeoscienceAustralia.github.io/eo-tides/
@@ -24,26 +24,27 @@ Classifier: Programming Language :: Python :: 3.13
24
24
  Requires-Python: <4.0,>=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
- Requires-Dist: colorama >=0.4.3
28
- Requires-Dist: geopandas >=0.10.0
29
- Requires-Dist: matplotlib >=3.8.0
30
- Requires-Dist: numpy >=1.26.0
31
- Requires-Dist: odc-geo >=0.4.7
32
- Requires-Dist: pandas >=2.2.0
33
- Requires-Dist: psutil >=5.8.0
34
- Requires-Dist: pyproj >=3.6.1
35
- Requires-Dist: pyTMD ==2.1.8
36
- Requires-Dist: scikit-learn >=1.4.0
37
- Requires-Dist: scipy >=1.11.2
38
- Requires-Dist: shapely >=2.0.6
39
- Requires-Dist: tqdm >=4.55.0
40
- Requires-Dist: xarray >=2022.3.0
27
+ Requires-Dist: colorama>=0.4.3
28
+ Requires-Dist: geopandas>=0.10.0
29
+ Requires-Dist: matplotlib>=3.8.0
30
+ Requires-Dist: numpy>=1.26.0
31
+ Requires-Dist: odc-geo>=0.4.7
32
+ Requires-Dist: pandas>=2.2.0
33
+ Requires-Dist: psutil>=5.8.0
34
+ Requires-Dist: pyogrio>=0.7.0
35
+ Requires-Dist: pyproj>=3.6.1
36
+ Requires-Dist: pyTMD==2.2.0
37
+ Requires-Dist: scikit-learn>=1.4.0
38
+ Requires-Dist: scipy>=1.11.2
39
+ Requires-Dist: shapely>=2.0.6
40
+ Requires-Dist: tqdm>=4.55.0
41
+ Requires-Dist: xarray>=2022.3.0
41
42
  Provides-Extra: notebooks
42
- Requires-Dist: odc-stac >=0.3.10 ; extra == 'notebooks'
43
- Requires-Dist: odc-geo[tiff,warp] >=0.4.7 ; extra == 'notebooks'
44
- Requires-Dist: pystac-client >=0.8.3 ; extra == 'notebooks'
45
- Requires-Dist: folium >=0.16.0 ; extra == 'notebooks'
46
- Requires-Dist: planetary-computer >=1.0.0 ; extra == 'notebooks'
43
+ Requires-Dist: odc-stac>=0.3.10; extra == "notebooks"
44
+ Requires-Dist: odc-geo[tiff,warp]>=0.4.7; extra == "notebooks"
45
+ Requires-Dist: pystac-client>=0.8.3; extra == "notebooks"
46
+ Requires-Dist: folium>=0.16.0; extra == "notebooks"
47
+ Requires-Dist: planetary_computer>=1.0.0; extra == "notebooks"
47
48
 
48
49
  # `eo-tides`: Tide modelling tools for large-scale satellite earth observation analysis
49
50
 
@@ -0,0 +1,11 @@
1
+ eo_tides/__init__.py,sha256=pGvVlxMKiYjm_273G-oYcOgVuPra7uEdNZv0oN1i69c,1693
2
+ eo_tides/eo.py,sha256=d4zFs_uhuTekJDDqiX7oIzvS1iP6nEr0rG2Yy4xbsEU,22746
3
+ eo_tides/model.py,sha256=X_nuYkBbzq3cLgJc0dUknlL6w_90O9rz_2BOqX5uxsg,34585
4
+ eo_tides/stats.py,sha256=-nL6Ay6TvA5GSdnglHoLMu5JZf6-YjQKERBGLjAZs34,22993
5
+ eo_tides/utils.py,sha256=9xJ1q-b-TVHg5zFyLy6AT_srrPQDvmFdWJmlGSPaJF0,26563
6
+ eo_tides/validation.py,sha256=KP8WLT5z7KLFjQ9oDla7VJOyLQAK4SVbcz2ySAbsbwI,11882
7
+ eo_tides-0.4.0.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
8
+ eo_tides-0.4.0.dist-info/METADATA,sha256=cqO3zJGPj-l5Xzi-cfPtkd7pzUUTt5ENVvCRM16HXFQ,8045
9
+ eo_tides-0.4.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
10
+ eo_tides-0.4.0.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
11
+ eo_tides-0.4.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- eo_tides/__init__.py,sha256=rn6slQP0bAhqM9cL2W8omiEM8f0b7libt6WsQ5DvYTE,1655
2
- eo_tides/eo.py,sha256=Vc_AHqT0_IDqdwbOpNcONjHhiCtbCe8Osk2gvzUeNmU,22377
3
- eo_tides/model.py,sha256=T0IFvSiXjiTvlY-Vi7-jneHPfaCLt95pmcRd8CZxOjE,34478
4
- eo_tides/stats.py,sha256=lchWWJ5gBDuZWvaD8TF-12Xlo2qCWiNI2IcgAaKWy2U,22668
5
- eo_tides/utils.py,sha256=tqXAkLk_Dm8s3yuXPxBBkHW3PZ42ayV8VCQjNw3wDZw,22433
6
- eo_tides/validation.py,sha256=UREsc0yWRO4x0PJXvyoIx8gYiBZiRSim4z6TmAz_VDM,11857
7
- eo_tides-0.3.0.dist-info/LICENSE,sha256=owxWsXViCL2J6Ks3XYhot7t4Y93nstmXAT95Zf030Cc,11350
8
- eo_tides-0.3.0.dist-info/METADATA,sha256=lajVK9XoAA2fJqA9R3HHYJ7iUJFMtmxh3U07uGTs4_4,8040
9
- eo_tides-0.3.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
10
- eo_tides-0.3.0.dist-info/top_level.txt,sha256=lXZDUUM1DlLdKWHRn8zdmtW8Rx-eQOIWVvt0b8VGiyQ,9
11
- eo_tides-0.3.0.dist-info/RECORD,,