eo-tides 0.0.22__tar.gz → 0.1.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eo-tides
3
- Version: 0.0.22
3
+ Version: 0.1.0
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/
@@ -37,6 +37,7 @@ Requires-Dist: tqdm>=4.55.0
37
37
  Requires-Dist: xarray>=2022.3.0
38
38
  Provides-Extra: notebooks
39
39
  Requires-Dist: odc-stac>=0.3.10; extra == "notebooks"
40
+ Requires-Dist: odc-geo[tiff,warp]>=0.4.7; extra == "notebooks"
40
41
  Requires-Dist: pystac-client>=0.8.3; extra == "notebooks"
41
42
  Requires-Dist: folium>=0.16.0; extra == "notebooks"
42
43
  Requires-Dist: planetary_computer>=1.0.0; extra == "notebooks"
@@ -47,7 +48,7 @@ Requires-Dist: planetary_computer>=1.0.0; extra == "notebooks"
47
48
 
48
49
  [![Release](https://img.shields.io/github/v/release/GeoscienceAustralia/eo-tides)](https://pypi.org/project/eo-tides/)
49
50
  [![Build status](https://img.shields.io/github/actions/workflow/status/GeoscienceAustralia/eo-tides/main.yml?branch=main)](https://github.com/GeoscienceAustralia/eo-tides/actions/workflows/main.yml?query=branch%3Amain)
50
- ![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2FGeoscienceAustralia%2Feo-tides%2Frefs%2Fheads%2Fmain%2Fpyproject.toml)
51
+ ![Python Version from PEP 621 TOML](https://img.shields.io/pypi/pyversions/eo-tides)
51
52
  [![codecov](https://codecov.io/gh/GeoscienceAustralia/eo-tides/branch/main/graph/badge.svg)](https://codecov.io/gh/GeoscienceAustralia/eo-tides)
52
53
  [![License](https://img.shields.io/github/license/GeoscienceAustralia/eo-tides)](https://img.shields.io/github/license/GeoscienceAustralia/eo-tides)
53
54
 
@@ -70,9 +71,9 @@ These tools can be applied to petabytes of freely available satellite data (e.g.
70
71
  - 🌊 Model tides from multiple global ocean tide models in parallel, and return tide heights in standardised `pandas.DataFrame` format for further analysis
71
72
  - 🛰️ "Tag" satellite data with tide height and stage based on the exact moment of image acquisition
72
73
  - 🌐 Model tides for every individual satellite pixel, producing three-dimensional "tide height" `xarray`-format datacubes that can be integrated with satellite data
73
- <!-- - 🎯 Combine multiple tide models into a single locally-optimised "ensemble" model informed by satellite altimetry and satellite-observed patterns of tidal inundation -->
74
74
  - 📈 Calculate statistics describing local tide dynamics, as well as biases caused by interactions between tidal processes and satellite orbits
75
75
  - 🛠️ Validate modelled tides using measured sea levels from coastal tide gauges (e.g. [GESLA Global Extreme Sea Level Analysis](https://gesla.org/))
76
+ <!-- - 🎯 Combine multiple tide models into a single locally-optimised "ensemble" model informed by satellite altimetry and satellite-observed patterns of tidal inundation -->
76
77
 
77
78
  ## Supported tide models
78
79
 
@@ -86,6 +87,14 @@ These tools can be applied to petabytes of freely available satellite data (e.g.
86
87
 
87
88
  For instructions on how to set up these models for use in `eo-tides`, refer to [Setting up tide models](setup.md).
88
89
 
90
+ ## Installing and setting up `eo-tides`
91
+
92
+ To get started with `eo-tides`, follow the [Installation](https://geoscienceaustralia.github.io/eo-tides/install/) and [Setting up tide models](https://geoscienceaustralia.github.io/eo-tides/setup/) guides.
93
+
94
+ ## Jupyter Notebooks code examples
95
+
96
+ Interactive Jupyter Notebook usage examples and more complex coastal EO case studies can be found in the [`docs/notebooks/`](https://github.com/GeoscienceAustralia/eo-tides/tree/main/docs/notebooks) directory, or [rendered in the documentation here](https://geoscienceaustralia.github.io/eo-tides/notebooks/Model_tides/).
97
+
89
98
  ## Citing `eo-tides`
90
99
 
91
100
  To cite `eo-tides` in your work, please use the following citation:
@@ -93,3 +102,8 @@ To cite `eo-tides` in your work, please use the following citation:
93
102
  ```
94
103
  Bishop-Taylor, R., Sagar, S., Phillips, C., & Newey, V. (2024). eo-tides: Tide modelling tools for large-scale satellite earth observation analysis. https://github.com/GeoscienceAustralia/eo-tides
95
104
  ```
105
+
106
+ ## Acknowledgements
107
+
108
+ For a full list of acknowledgements, refer to [Citations and Credits](https://geoscienceaustralia.github.io/eo-tides/credits/).
109
+ This repository was initialised using the [`cookiecutter-uv`](https://github.com/fpgmaas/cookiecutter-uv) package.
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Release](https://img.shields.io/github/v/release/GeoscienceAustralia/eo-tides)](https://pypi.org/project/eo-tides/)
6
6
  [![Build status](https://img.shields.io/github/actions/workflow/status/GeoscienceAustralia/eo-tides/main.yml?branch=main)](https://github.com/GeoscienceAustralia/eo-tides/actions/workflows/main.yml?query=branch%3Amain)
7
- ![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2FGeoscienceAustralia%2Feo-tides%2Frefs%2Fheads%2Fmain%2Fpyproject.toml)
7
+ ![Python Version from PEP 621 TOML](https://img.shields.io/pypi/pyversions/eo-tides)
8
8
  [![codecov](https://codecov.io/gh/GeoscienceAustralia/eo-tides/branch/main/graph/badge.svg)](https://codecov.io/gh/GeoscienceAustralia/eo-tides)
9
9
  [![License](https://img.shields.io/github/license/GeoscienceAustralia/eo-tides)](https://img.shields.io/github/license/GeoscienceAustralia/eo-tides)
10
10
 
@@ -27,9 +27,9 @@ These tools can be applied to petabytes of freely available satellite data (e.g.
27
27
  - 🌊 Model tides from multiple global ocean tide models in parallel, and return tide heights in standardised `pandas.DataFrame` format for further analysis
28
28
  - 🛰️ "Tag" satellite data with tide height and stage based on the exact moment of image acquisition
29
29
  - 🌐 Model tides for every individual satellite pixel, producing three-dimensional "tide height" `xarray`-format datacubes that can be integrated with satellite data
30
- <!-- - 🎯 Combine multiple tide models into a single locally-optimised "ensemble" model informed by satellite altimetry and satellite-observed patterns of tidal inundation -->
31
30
  - 📈 Calculate statistics describing local tide dynamics, as well as biases caused by interactions between tidal processes and satellite orbits
32
31
  - 🛠️ Validate modelled tides using measured sea levels from coastal tide gauges (e.g. [GESLA Global Extreme Sea Level Analysis](https://gesla.org/))
32
+ <!-- - 🎯 Combine multiple tide models into a single locally-optimised "ensemble" model informed by satellite altimetry and satellite-observed patterns of tidal inundation -->
33
33
 
34
34
  ## Supported tide models
35
35
 
@@ -43,6 +43,14 @@ These tools can be applied to petabytes of freely available satellite data (e.g.
43
43
 
44
44
  For instructions on how to set up these models for use in `eo-tides`, refer to [Setting up tide models](setup.md).
45
45
 
46
+ ## Installing and setting up `eo-tides`
47
+
48
+ To get started with `eo-tides`, follow the [Installation](https://geoscienceaustralia.github.io/eo-tides/install/) and [Setting up tide models](https://geoscienceaustralia.github.io/eo-tides/setup/) guides.
49
+
50
+ ## Jupyter Notebooks code examples
51
+
52
+ Interactive Jupyter Notebook usage examples and more complex coastal EO case studies can be found in the [`docs/notebooks/`](https://github.com/GeoscienceAustralia/eo-tides/tree/main/docs/notebooks) directory, or [rendered in the documentation here](https://geoscienceaustralia.github.io/eo-tides/notebooks/Model_tides/).
53
+
46
54
  ## Citing `eo-tides`
47
55
 
48
56
  To cite `eo-tides` in your work, please use the following citation:
@@ -50,3 +58,8 @@ To cite `eo-tides` in your work, please use the following citation:
50
58
  ```
51
59
  Bishop-Taylor, R., Sagar, S., Phillips, C., & Newey, V. (2024). eo-tides: Tide modelling tools for large-scale satellite earth observation analysis. https://github.com/GeoscienceAustralia/eo-tides
52
60
  ```
61
+
62
+ ## Acknowledgements
63
+
64
+ For a full list of acknowledgements, refer to [Citations and Credits](https://geoscienceaustralia.github.io/eo-tides/credits/).
65
+ This repository was initialised using the [`cookiecutter-uv`](https://github.com/fpgmaas/cookiecutter-uv) package.
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import os
5
+ import warnings
5
6
  from typing import TYPE_CHECKING
6
7
 
7
8
  import odc.geo.xr
@@ -93,19 +94,17 @@ def _pixel_tides_resample(
93
94
 
94
95
 
95
96
  def tag_tides(
96
- ds: xr.Dataset,
97
+ ds: xr.Dataset | xr.DataArray,
97
98
  model: str | list[str] = "EOT20",
98
99
  directory: str | os.PathLike | None = None,
99
100
  tidepost_lat: float | None = None,
100
101
  tidepost_lon: float | None = None,
101
- ebb_flow: bool = False,
102
- swap_dims: bool = False,
103
102
  **model_tides_kwargs,
104
- ) -> xr.Dataset:
103
+ ) -> xr.DataArray:
105
104
  """
106
105
  Model tide heights for every timestep in a multi-dimensional
107
- dataset, and add them as a new `tide_height` (and optionally,
108
- `ebb_flow`) variable that "tags" each observation with tide data.
106
+ dataset, and return a new `tide_height` array that can
107
+ be used to "tag" each observation with tide data.
109
108
 
110
109
  The function models tides at the centroid of the dataset
111
110
  by default, but a custom tidal modelling location can
@@ -123,7 +122,7 @@ def tag_tides(
123
122
 
124
123
  Parameters
125
124
  ----------
126
- ds : xarray.Dataset
125
+ ds : xarray.Dataset or xarray.DataArray
127
126
  A multi-dimensional dataset (e.g. "x", "y", "time") to
128
127
  tag with tide heights. This dataset must contain a "time"
129
128
  dimension.
@@ -143,16 +142,6 @@ def tag_tides(
143
142
  Optional coordinates used to model tides. The default is None,
144
143
  which uses the centroid of the dataset as the tide modelling
145
144
  location.
146
- ebb_flow : bool, optional
147
- An optional boolean indicating whether to compute if the
148
- tide phase was ebbing (falling) or flowing (rising) for each
149
- observation. The default is False; if set to True, a new
150
- "ebb_flow" variable will be added to the dataset with each
151
- observation labelled with "Ebb" or "Flow".
152
- swap_dims : bool, optional
153
- An optional boolean indicating whether to swap the `time`
154
- dimension in the original `ds` to the new "tide_height"
155
- variable. Defaults to False.
156
145
  **model_tides_kwargs :
157
146
  Optional parameters passed to the `eo_tides.model.model_tides`
158
147
  function. Important parameters include `cutoff` (used to
@@ -174,8 +163,6 @@ def tag_tides(
174
163
 
175
164
  # Standardise model into a list for easy handling. and verify only one
176
165
  model = [model] if isinstance(model, str) else model
177
- if (len(model) > 1) & swap_dims:
178
- raise ValueError("Can only swap dimensions when a single tide model is passed to `model`.")
179
166
 
180
167
  # If custom tide modelling locations are not provided, use the
181
168
  # dataset centroid
@@ -208,48 +195,38 @@ def tag_tides(
208
195
  f"`tidepost_lat` and `tidepost_lon` parameters."
209
196
  )
210
197
 
211
- # Optionally calculate the tide phase for each observation
212
- if ebb_flow:
213
- # Model tides for a time 15 minutes prior to each previously
214
- # modelled satellite acquisition time. This allows us to compare
215
- # tide heights to see if they are rising or falling.
216
- print("Modelling tidal phase (e.g. ebb or flow)")
217
- tide_pre_df = model_tides(
218
- x=lon, # type: ignore
219
- y=lat, # type: ignore
220
- time=(ds.time - pd.Timedelta("15 min")),
221
- model=model,
222
- directory=directory,
223
- crs="EPSG:4326",
224
- **model_tides_kwargs,
225
- )
226
-
227
- # Compare tides computed for each timestep. If the previous tide
228
- # was higher than the current tide, the tide is 'ebbing'. If the
229
- # previous tide was lower, the tide is 'flowing'
230
- tide_df["ebb_flow"] = (tide_df.tide_height < tide_pre_df.tide_height.values).replace({
231
- True: "Ebb",
232
- False: "Flow",
233
- })
198
+ # # Optionally calculate the tide phase for each observation
199
+ # if ebb_flow:
200
+ # # Model tides for a time 15 minutes prior to each previously
201
+ # # modelled satellite acquisition time. This allows us to compare
202
+ # # tide heights to see if they are rising or falling.
203
+ # print("Modelling tidal phase (e.g. ebb or flow)")
204
+ # tide_pre_df = model_tides(
205
+ # x=lon, # type: ignore
206
+ # y=lat, # type: ignore
207
+ # time=(ds.time - pd.Timedelta("15 min")),
208
+ # model=model,
209
+ # directory=directory,
210
+ # crs="EPSG:4326",
211
+ # **model_tides_kwargs,
212
+ # )
213
+
214
+ # # Compare tides computed for each timestep. If the previous tide
215
+ # # was higher than the current tide, the tide is 'ebbing'. If the
216
+ # # previous tide was lower, the tide is 'flowing'
217
+ # tide_df["ebb_flow"] = (tide_df.tide_height < tide_pre_df.tide_height.values).replace({
218
+ # True: "Ebb",
219
+ # False: "Flow",
220
+ # })
234
221
 
235
222
  # Convert to xarray format
236
- tide_xr = tide_df.reset_index().set_index(["time", "tide_model"]).drop(["x", "y"], axis=1).to_xarray()
223
+ tide_xr = tide_df.reset_index().set_index(["time", "tide_model"]).drop(["x", "y"], axis=1).tide_height.to_xarray()
237
224
 
238
225
  # If only one tidal model exists, squeeze out "tide_model" dim
239
226
  if len(tide_xr.tide_model) == 1:
240
- tide_xr = tide_xr.squeeze("tide_model", drop=True)
241
-
242
- # Add each array into original dataset
243
- for var in tide_xr.data_vars:
244
- ds[var] = tide_xr[var]
245
-
246
- # Swap dimensions and sort by tide height
247
- if swap_dims:
248
- ds = ds.swap_dims({"time": "tide_height"})
249
- ds = ds.sortby("tide_height")
250
- ds = ds.drop_vars("time")
227
+ tide_xr = tide_xr.squeeze("tide_model")
251
228
 
252
- return ds
229
+ return tide_xr
253
230
 
254
231
 
255
232
  def pixel_tides(
@@ -493,8 +470,10 @@ def pixel_tides(
493
470
  # Set dtype to dtype of the input data as quantile always returns
494
471
  # float64 (memory intensive)
495
472
  if calculate_quantiles is not None:
496
- print("Computing tide quantiles")
497
- tides_lowres = tides_lowres.quantile(q=calculate_quantiles, dim="time").astype(tides_lowres.dtype)
473
+ with warnings.catch_warnings():
474
+ warnings.simplefilter("ignore")
475
+ print("Computing tide quantiles")
476
+ tides_lowres = tides_lowres.quantile(q=calculate_quantiles, dim="time").astype(tides_lowres.dtype)
498
477
 
499
478
  # If only one tidal model exists, squeeze out "tide_model" dim
500
479
  if len(tides_lowres.tide_model) == 1:
@@ -3,8 +3,10 @@ from __future__ import annotations
3
3
 
4
4
  import os
5
5
  import pathlib
6
+ import textwrap
6
7
  import warnings
7
8
  from concurrent.futures import ProcessPoolExecutor
9
+ from concurrent.futures.process import BrokenProcessPool
8
10
  from functools import partial
9
11
  from typing import TYPE_CHECKING
10
12
 
@@ -130,7 +132,7 @@ def list_models(
130
132
  # Mark available models with a green tick
131
133
  status = "✅"
132
134
  print(f"{status:^{status_width}}│ {m:<{name_width}} │ {expected_paths[m]:<{path_width}}")
133
- except:
135
+ except FileNotFoundError:
134
136
  if show_supported:
135
137
  # Mark unavailable models with a red cross
136
138
  status = "❌"
@@ -147,16 +149,19 @@ def list_models(
147
149
 
148
150
  # Raise error or warning if no models are available
149
151
  if not available_models:
150
- warning_text = (
151
- f"No valid tide models are available in `{directory}`. "
152
- "Are you sure you have provided the correct `directory` path, "
153
- "or set the `EO_TIDES_TIDE_MODELS` environment variable "
154
- "to point to the location of your tide model directory?"
155
- )
152
+ warning_msg = textwrap.dedent(
153
+ f"""
154
+ No valid tide models are available in `{directory}`.
155
+ Are you sure you have provided the correct `directory` path, or set the
156
+ `EO_TIDES_TIDE_MODELS` environment variable to point to the location of your
157
+ tide model directory?
158
+ """
159
+ ).strip()
160
+
156
161
  if raise_error:
157
- raise Exception(warning_text)
162
+ raise Exception(warning_msg)
158
163
  else:
159
- warnings.warn(warning_text, UserWarning)
164
+ warnings.warn(warning_msg, UserWarning)
160
165
 
161
166
  # Return list of available and supported models
162
167
  return available_models, supported_models
@@ -199,88 +204,101 @@ def _model_tides(
199
204
  lat.max() + buffer,
200
205
  ]
201
206
 
202
- # Read tidal constants and interpolate to grid points
203
- if pytmd_model.format in ("OTIS", "ATLAS-compact", "TMD3"):
204
- amp, ph, D, c = pyTMD.io.OTIS.extract_constants(
205
- lon,
206
- lat,
207
- pytmd_model.grid_file,
208
- pytmd_model.model_file,
209
- pytmd_model.projection,
210
- type=pytmd_model.type,
211
- grid=pytmd_model.file_format,
212
- crop=crop,
213
- bounds=bounds,
214
- method=method,
215
- extrapolate=extrapolate,
216
- cutoff=cutoff,
217
- )
207
+ try:
208
+ # Read tidal constants and interpolate to grid points
209
+ if pytmd_model.format in ("OTIS", "ATLAS-compact", "TMD3"):
210
+ amp, ph, D, c = pyTMD.io.OTIS.extract_constants(
211
+ lon,
212
+ lat,
213
+ pytmd_model.grid_file,
214
+ pytmd_model.model_file,
215
+ pytmd_model.projection,
216
+ type=pytmd_model.type,
217
+ grid=pytmd_model.file_format,
218
+ crop=crop,
219
+ bounds=bounds,
220
+ method=method,
221
+ extrapolate=extrapolate,
222
+ cutoff=cutoff,
223
+ )
218
224
 
219
- # Use delta time at 2000.0 to match TMD outputs
220
- deltat = np.zeros((len(timescale)), dtype=np.float64)
221
-
222
- elif pytmd_model.format in ("ATLAS-netcdf",):
223
- amp, ph, D, c = pyTMD.io.ATLAS.extract_constants(
224
- lon,
225
- lat,
226
- pytmd_model.grid_file,
227
- pytmd_model.model_file,
228
- type=pytmd_model.type,
229
- crop=crop,
230
- bounds=bounds,
231
- method=method,
232
- extrapolate=extrapolate,
233
- cutoff=cutoff,
234
- scale=pytmd_model.scale,
235
- compressed=pytmd_model.compressed,
236
- )
225
+ # Use delta time at 2000.0 to match TMD outputs
226
+ deltat = np.zeros((len(timescale)), dtype=np.float64)
227
+
228
+ elif pytmd_model.format in ("ATLAS-netcdf",):
229
+ amp, ph, D, c = pyTMD.io.ATLAS.extract_constants(
230
+ lon,
231
+ lat,
232
+ pytmd_model.grid_file,
233
+ pytmd_model.model_file,
234
+ type=pytmd_model.type,
235
+ crop=crop,
236
+ bounds=bounds,
237
+ method=method,
238
+ extrapolate=extrapolate,
239
+ cutoff=cutoff,
240
+ scale=pytmd_model.scale,
241
+ compressed=pytmd_model.compressed,
242
+ )
237
243
 
238
- # Use delta time at 2000.0 to match TMD outputs
239
- deltat = np.zeros((len(timescale)), dtype=np.float64)
240
-
241
- elif pytmd_model.format in ("GOT-ascii", "GOT-netcdf"):
242
- amp, ph, c = pyTMD.io.GOT.extract_constants(
243
- lon,
244
- lat,
245
- pytmd_model.model_file,
246
- grid=pytmd_model.file_format,
247
- crop=crop,
248
- bounds=bounds,
249
- method=method,
250
- extrapolate=extrapolate,
251
- cutoff=cutoff,
252
- scale=pytmd_model.scale,
253
- compressed=pytmd_model.compressed,
254
- )
244
+ # Use delta time at 2000.0 to match TMD outputs
245
+ deltat = np.zeros((len(timescale)), dtype=np.float64)
246
+
247
+ elif pytmd_model.format in ("GOT-ascii", "GOT-netcdf"):
248
+ amp, ph, c = pyTMD.io.GOT.extract_constants(
249
+ lon,
250
+ lat,
251
+ pytmd_model.model_file,
252
+ grid=pytmd_model.file_format,
253
+ crop=crop,
254
+ bounds=bounds,
255
+ method=method,
256
+ extrapolate=extrapolate,
257
+ cutoff=cutoff,
258
+ scale=pytmd_model.scale,
259
+ compressed=pytmd_model.compressed,
260
+ )
255
261
 
256
- # Delta time (TT - UT1)
257
- deltat = timescale.tt_ut1
258
-
259
- elif pytmd_model.format in ("FES-ascii", "FES-netcdf"):
260
- amp, ph = pyTMD.io.FES.extract_constants(
261
- lon,
262
- lat,
263
- pytmd_model.model_file,
264
- type=pytmd_model.type,
265
- version=pytmd_model.version,
266
- crop=crop,
267
- bounds=bounds,
268
- method=method,
269
- extrapolate=extrapolate,
270
- cutoff=cutoff,
271
- scale=pytmd_model.scale,
272
- compressed=pytmd_model.compressed,
273
- )
262
+ # Delta time (TT - UT1)
263
+ deltat = timescale.tt_ut1
264
+
265
+ elif pytmd_model.format in ("FES-ascii", "FES-netcdf"):
266
+ amp, ph = pyTMD.io.FES.extract_constants(
267
+ lon,
268
+ lat,
269
+ pytmd_model.model_file,
270
+ type=pytmd_model.type,
271
+ version=pytmd_model.version,
272
+ crop=crop,
273
+ bounds=bounds,
274
+ method=method,
275
+ extrapolate=extrapolate,
276
+ cutoff=cutoff,
277
+ scale=pytmd_model.scale,
278
+ compressed=pytmd_model.compressed,
279
+ )
274
280
 
275
- # Available model constituents
276
- c = pytmd_model.constituents
281
+ # Available model constituents
282
+ c = pytmd_model.constituents
277
283
 
278
- # Delta time (TT - UT1)
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
- )
284
+ # Delta time (TT - UT1)
285
+ deltat = timescale.tt_ut1
286
+ else:
287
+ raise Exception(
288
+ f"Unsupported model format ({pytmd_model.format}). This may be due to an incompatible version of `pyTMD`."
289
+ )
290
+
291
+ # Raise error if constituent files no not cover analysis extent
292
+ except IndexError:
293
+ error_msg = textwrap.dedent(
294
+ f"""
295
+ The {model} tide model constituent files do not cover the requested analysis extent.
296
+ This can occur if you are using clipped model files to improve run times.
297
+ Consider using model files that cover your entire analysis area, or set `crop=False`
298
+ to reduce the extent of tide model constituent files that is loaded.
299
+ """
300
+ ).strip()
301
+ raise Exception(error_msg)
284
302
 
285
303
  # Calculate complex phase in radians for Euler's
286
304
  cph = -1j * ph * np.pi / 180.0
@@ -550,8 +568,8 @@ def model_tides(
550
568
  <https://pytmd.readthedocs.io/en/latest/getting_started/Getting-Started.html#directories>
551
569
 
552
570
  This function is a modification of the `pyTMD` package's
553
- `compute_tidal_elevations` function. For more info:
554
- <https://pytmd.readthedocs.io/en/latest/api_reference/compute_tidal_elevations.html>
571
+ `pyTMD.compute.tide_elevations` function. For more info:
572
+ <https://pytmd.readthedocs.io/en/latest/api_reference/compute.html#pyTMD.compute.tide_elevations>
555
573
 
556
574
  Parameters
557
575
  ----------
@@ -787,12 +805,19 @@ def model_tides(
787
805
  )
788
806
 
789
807
  # Apply func in parallel, iterating through each input param
790
- model_outputs = list(
791
- tqdm(
792
- executor.map(iter_func, model_iters, x_iters, y_iters, time_iters),
793
- total=len(model_iters),
794
- ),
795
- )
808
+ try:
809
+ model_outputs = list(
810
+ tqdm(
811
+ executor.map(iter_func, model_iters, x_iters, y_iters, time_iters),
812
+ total=len(model_iters),
813
+ ),
814
+ )
815
+ except BrokenProcessPool:
816
+ error_msg = (
817
+ "Parallelised tide modelling failed, likely to to an out-of-memory error. "
818
+ "Try reducing the size of your analysis, or set `parallel=False`."
819
+ )
820
+ raise RuntimeError(error_msg)
796
821
 
797
822
  # Model tides in series if parallelisation is off
798
823
  else: