Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
robbibt committed Oct 18, 2024
2 parents 4470645 + e4c8a72 commit 7d9a565
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 21 deletions.
15 changes: 15 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ Renamed for consistency with `model_tides` and `pixel_tides`.

Update references to `tidal_tag` to `tag_tides`.

### `tag_tides` now returns an array instead of updating data in-place

The `tag_tides` function now returns an `xarray.DataArray` output containing tide heights, rather than appending tide height data to the original input dataset in-place. This change provides better consistency with `pixel_tides`, which also returns an array of tide heights.

!!! tip "Action required"

Update:
```
ds = tag_tides(ds, ...)
```
To:
```
ds["tide_height"] = tag_tides(ds, ...)
```

### `pixel_tides` only returns a single array

The `pixel_tides` function has been updated to only ever return a single array as an output: a high-resolution tide height array matching the resolution of the input `ds` by default, and a low-resolution tide height array if `resample=False`.
Expand Down
44 changes: 40 additions & 4 deletions docs/notebooks/Case_study_intertidal.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,30 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Mapping the intertidal zone"
"# Mapping the intertidal zone\n",
"\n",
"The intertidal zone (i.e. the land along the coast that is periodically inundated by the tide) support important ecological habitats (e.g. sandy beaches and shores, tidal flats and rocky shores and reefs), and provide many valuable benefits such as storm surge protection, carbon storage and natural resources for recreational and commercial use.\n",
"However, intertidal zones are faced with increasing threats from coastal erosion, land reclamation (e.g. port construction), and sea level rise.\n",
"Accurate mapping data describing the spatial extents of the intertidal zone are essential for managing these environments, and predicting when and where these threats will have the greatest impact. \n",
"However, the intertidal zone is challenging and expensive to map at large scale using intensive manual survey methods - particularly across large coastal regions.\n",
"\n",
"Satellite Earth observation (EO) data is freely available for the entire planet, making satellite imagery a powerful and cost-effective tool for mapping the intertidal zone at regional, national scale or global scale.\n",
"This case study will demonstrate a simple **intertidal mapping workflow that combines free and open Landsat satellite data with tide modelling from `eo-tides`**. \n",
"The workflow includes:\n",
"\n",
"1. Loading a time-series of cloud-free satellite data from the cloud using `odc-stac`\n",
"2. Converting our satellite data to a remote sensing water index (NDWI)\n",
"3. [Modelling tides for each satellite image](../Satellite_data) and inspecting how these observed tides match up to the full local astronomical tide range\n",
"4. Filtering our satellite imagery to low and high tide observations\n",
"5. Combining noisy individual images into clean low and high tide median NDWI composites\n",
"6. Using these composites to extract the extent of the intertidal zone\n",
"\n",
"<div class=\"admonition tip\">\n",
" <p class=\"admonition-title\">More information</p>\n",
" <p>\n",
" For more information about the workflows described below, refer to <a href=\"https://www.sciencedirect.com/science/article/pii/S0034425717301591\">Sagar et al. 2017</a>, <a href=\"https://www.mdpi.com/2072-4292/10/3/480\">Sagar et al. 2018</a>, and <a href=\"https://www.sciencedirect.com/science/article/pii/S0272771418308783\">Bishop-Taylor et al. 2019</a>.\n",
" </p>\n",
"</div>"
]
},
{
Expand Down Expand Up @@ -1046,11 +1069,24 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 19,
"metadata": {},
"outputs": [],
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option WIDTH\n",
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option HEIGHT\n",
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option COUNT\n",
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option DTYPE\n",
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option CRS\n",
"WARNING:rasterio._env:CPLE_NotSupported in driver GTiff does not support creation option TRANSFORM\n"
]
}
],
"source": [
"intertidal.astype(int).odc.write_cog(\"intertidal_map.tif\", overwrite=True);"
"intertidal.astype(\"int16\").odc.write_cog(\"intertidal_map.tif\", overwrite=True);"
]
}
],
Expand Down
34 changes: 22 additions & 12 deletions docs/notebooks/Model_tides.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
"source": [
"# Modelling tides\n",
"\n",
"**This guide demonstrates how to use the [`model_tides`](../../api/#eo_tides.model.model_tides) function from the [`eo_tides.model`](../../api/#eo_tides.model) module to model tide heights at multiple coordinates or timesteps, using one or more ocean tide models.**\n",
"**This guide demonstrates how to use the [`model_tides`](../../api/#eo_tides.model.model_tides) function from the [`eo_tides.model`](../../api/#eo_tides.model) module to model tide heights at multiple coordinates or time steps, using one or more ocean tide models.**\n",
"\n",
"The `model_tides` function supports tide modelling based on a wide range of ocean tide models using a single line of code, parallelising this modelling where possible and returning data in a standardised `pandas.Dataframe` format.\n",
"The `model_tides` function can be used independently of Earth observation (EO) data, e.g. for any application where you need to generate a time series of tide heights.\n",
"However, it also underpins the more complex EO-related functions demonstrated in [Combining tides with satellite data](../Satellite_data)."
"However, it also underpins the more complex EO-related functions demonstrated in [Combining tides with satellite data](../Satellite_data).\n",
"\n",
"<div class=\"admonition tip\">\n",
" <p class=\"admonition-title\">Tip</p>\n",
" <p>\n",
" The <code>model_tides</code> function is based on the <a href=\"https://pytmd.readthedocs.io/en/latest/api_reference/compute.html#pyTMD.compute.tide_elevations\"><code>pyTMD.compute.tide_elevations</code></a> function from the <code>pyTMD</code> tide modelling package that underpins <code>eo-tides</code>, with modifications to support parallel processing and integration with <code>pandas</code> and <code>xarray</code> workflows. We highly recommend exploring the <a href=\"https://pytmd.readthedocs.io/en/latest/getting_started/Overview.html\">more advanced tide modelling functionality available in <code>pyTMD</code></a> for more custom tide modelling applications.\n",
" </p>\n",
"</div>"
]
},
{
Expand Down Expand Up @@ -246,7 +254,7 @@
}
],
"source": [
"tide_df.reset_index([\"x\", \"y\"], drop=True).tide_height.plot();"
"tide_df.droplevel([\"x\", \"y\"]).tide_height.plot();"
]
},
{
Expand All @@ -255,11 +263,13 @@
"source": [
"### Multiple models\n",
"\n",
"By default, `model_tides` will model tides using the EOT20 tide model. \n",
"By default, `model_tides` will model tides using the [`EOT20` tide model](https://www.seanoe.org/data/00683/79489/) – a leading open-source global ocean model with a permissive CC BY 4.0 licence:\n",
"\n",
"> Hart-Davis Michael, Piccioni Gaia, Dettmering Denise, Schwatke Christian, Passaro Marcello, Seitz Florian (2021). EOT20 - A global Empirical Ocean Tide model from multi-mission satellite altimetry. SEANOE. https://doi.org/10.17882/79489\n",
"\n",
"However, we can easily model tides using multiple models by passing a list of models to the `model` parameter.\n",
"`eo-tides` will process these in parallel where possible, and return the data into a single `pandas.DataFrame`.\n",
"\n",
"For example, we can model tides using the EOT20, GOT5.5 and HAMTIDE11 models.\n",
"For example, we can model tides using the `EOT20`, `GOT5.5` and `HAMTIDE11` models:\n",
"\n",
"<div class=\"admonition note\">\n",
" <p class=\"admonition-title\">Note</p>\n",
Expand Down Expand Up @@ -288,7 +298,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 3/3 [00:00<00:00, 20.44it/s]\n"
"100%|██████████| 3/3 [00:00<00:00, 25.49it/s]\n"
]
},
{
Expand Down Expand Up @@ -445,7 +455,7 @@
],
"source": [
"# Print outputs\n",
"tide_df_multiple.reset_index([\"x\", \"y\"], drop=True).plot(legend=True)"
"tide_df_multiple.droplevel([\"x\", \"y\"]).plot(legend=True)"
]
},
{
Expand Down Expand Up @@ -481,7 +491,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 2/2 [00:00<00:00, 17.67it/s]\n"
"100%|██████████| 2/2 [00:00<00:00, 17.42it/s]\n"
]
},
{
Expand Down Expand Up @@ -685,7 +695,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 2/2 [00:00<00:00, 15.74it/s]\n"
"100%|██████████| 2/2 [00:00<00:00, 17.30it/s]\n"
]
},
{
Expand Down Expand Up @@ -785,7 +795,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 6/6 [00:00<00:00, 19.79it/s]\n"
"100%|██████████| 6/6 [00:00<00:00, 49.24it/s]\n"
]
},
{
Expand Down Expand Up @@ -971,7 +981,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 6/6 [00:00<00:00, 21.22it/s]\n"
"100%|██████████| 6/6 [00:00<00:00, 50.29it/s]\n"
]
},
{
Expand Down
6 changes: 3 additions & 3 deletions docs/notebooks/Validating_tides.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@
}
],
"source": [
"gauge_df.reset_index(\"site_code\").sea_level.plot()"
"gauge_df.droplevel(\"site_code\").sea_level.plot()"
]
},
{
Expand Down Expand Up @@ -680,7 +680,7 @@
"name": "stderr",
"output_type": "stream",
"text": [
"100%|██████████| 3/3 [00:00<00:00, 21.59it/s]\n"
"100%|██████████| 3/3 [00:00<00:00, 25.57it/s]\n"
]
},
{
Expand Down Expand Up @@ -840,7 +840,7 @@
"joined_df = gauge_df.join(modelled_df).dropna()\n",
"\n",
"# Plot measured sea levels and modelled data\n",
"joined_df.reset_index([\"site_code\", \"x\", \"y\"])[[\"sea_level\"] + models].plot()"
"joined_df.droplevel([\"site_code\", \"x\", \"y\"])[[\"sea_level\"] + models].plot()"
]
},
{
Expand Down
4 changes: 2 additions & 2 deletions eo_tides/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -562,8 +562,8 @@ def model_tides(
<https://pytmd.readthedocs.io/en/latest/getting_started/Getting-Started.html#directories>
This function is a modification of the `pyTMD` package's
`compute_tidal_elevations` function. For more info:
<https://pytmd.readthedocs.io/en/latest/api_reference/compute_tidal_elevations.html>
`pyTMD.compute.tide_elevations` function. For more info:
<https://pytmd.readthedocs.io/en/latest/api_reference/compute.html#pyTMD.compute.tide_elevations>
Parameters
----------
Expand Down
8 changes: 8 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ def test_model_tides_mode(mode, models, output_format):
assert all(modelled_tides_df.index.get_level_values("x") == np.tile(x, len(models)))
assert all(modelled_tides_df.index.get_level_values("y") == np.tile(y, len(models)))

# Verify correct models exist in column
assert "tide_model" in modelled_tides_df.columns
assert all(modelled_tides_df.tide_model.unique() == models)

if mode == "one-to-many":
if output_format == "wide":
# In "wide" output format, the number of rows should equal
Expand All @@ -243,6 +247,10 @@ def test_model_tides_mode(mode, models, output_format):
assert all(modelled_tides_df.index.get_level_values("x") == np.tile(np.repeat(x, len(times)), len(models)))
assert all(modelled_tides_df.index.get_level_values("y") == np.tile(np.repeat(y, len(times)), len(models)))

# Verify correct models exist in column
assert "tide_model" in modelled_tides_df.columns
assert all(modelled_tides_df.tide_model.unique() == models)


# Test ensemble modelling functionality
def test_model_tides_ensemble():
Expand Down

0 comments on commit 7d9a565

Please sign in to comment.