Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Steps blending v1 #255

Merged
merged 63 commits into from
Feb 15, 2022
Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
d6652ea
Implement STEPS blending (#233)
RubenImhoff Jan 14, 2022
b947b6b
First changes to remove xarray dependency
dnerini Jan 14, 2022
46cb9a0
Do not format json with black
dnerini Jan 14, 2022
b6f6ddc
Comment out xarray code
dnerini Jan 14, 2022
b1f99b3
Remove 'legacy' argument
dnerini Jan 14, 2022
8bb3a0a
Fix issues from codacy report - v1
RubenImhoff Jan 14, 2022
52aacab
Fix issues from codacy report - v2
RubenImhoff Jan 14, 2022
dc4ccab
Fix black
dnerini Jan 14, 2022
ae3f4d4
Set minimum python version to 3.7 (#253)
dnerini Jan 15, 2022
3197383
Ignore vscode and macos folders
dnerini Jan 15, 2022
123388a
Change reprojection, test and example script to work without xarray
RubenImhoff Jan 17, 2022
299df11
Merge branch 'master' into blending-v1
dnerini Jan 17, 2022
230737b
Fix test
dnerini Jan 17, 2022
e197371
remove nwp_importers from main pysteps repo (available in separate pl…
RubenImhoff Jan 20, 2022
bd9bc7c
remove nwp_importer tests
RubenImhoff Jan 20, 2022
d3200fe
make reprojection tests independent of nwp importer
RubenImhoff Jan 20, 2022
d32550d
fixes to reprojection
RubenImhoff Jan 20, 2022
022a05a
Remove BoM xarray importer and make BoM importer tests independent of…
RubenImhoff Jan 21, 2022
e95d0c4
Make importer tests xarray independent
RubenImhoff Jan 21, 2022
8928a89
fixes from codacy report
RubenImhoff Jan 21, 2022
20169a6
fix tests and add multiple model tests for linear blending module
RubenImhoff Jan 21, 2022
bc03abc
minor fix for codacy report
RubenImhoff Jan 21, 2022
2dc44fe
add extra linear blending tests
RubenImhoff Jan 21, 2022
fc701e5
add blending interface tests
RubenImhoff Jan 21, 2022
5b989ab
minor fix to io_readers test
RubenImhoff Jan 21, 2022
1c15d60
Remove private methods from docs
dnerini Jan 22, 2022
146c6d5
Install plugins for building examples
dnerini Jan 24, 2022
fdf19e4
Install pysteps-nwp-importers from source
dnerini Jan 24, 2022
b137c52
Fix branch name
dnerini Jan 24, 2022
38dd2b0
Ignore NWP decomposition example for now
dnerini Jan 24, 2022
b80231f
Remove xarray notation
dnerini Jan 24, 2022
9e986d6
update to blending example
RubenImhoff Jan 24, 2022
11b047a
remove os import from blended_forecast example
RubenImhoff Jan 24, 2022
a6f2065
remove test_decomposition from examples
RubenImhoff Jan 24, 2022
5cd752b
Fix black
dnerini Jan 25, 2022
544e4d3
Minor doc fixes
dnerini Jan 25, 2022
b9490c2
Reintroduce nwp sources
dnerini Jan 25, 2022
bdea79b
Updated linear blending example
RubenImhoff Jan 26, 2022
c47e370
Fix enum list in docstrings
dnerini Jan 25, 2022
a3a3244
Do not build pdf
dnerini Jan 26, 2022
6e554f2
fixes to figures sizes in blending examples
RubenImhoff Jan 27, 2022
7a75a4f
Merge branch 'blending-v1' of https://github.com/pySTEPS/pysteps into…
RubenImhoff Jan 27, 2022
77a43e1
update linear blending doc strings
RubenImhoff Jan 27, 2022
f054a78
fixes from codacy report
RubenImhoff Jan 27, 2022
6e069a8
Merge branch 'master' into blending-v1
dnerini Jan 27, 2022
6a9f1d4
Fix table
dnerini Jan 28, 2022
c5f5212
Plot results as columns
dnerini Jan 28, 2022
7e6bb95
Improve docstrings
dnerini Jan 28, 2022
b145ef6
Fix black
dnerini Jan 28, 2022
0d63879
Merge branch 'master' into blending-v1
dnerini Jan 30, 2022
99fa108
Rename (some) variables
dnerini Feb 2, 2022
0c2b621
Merge branch 'master' into blending-v1
dnerini Feb 2, 2022
0d7f302
Make sure NWP correlations are always finite numbers
RubenImhoff Feb 3, 2022
29e960f
Make sure climatological skill is always positive and finite
RubenImhoff Feb 3, 2022
0ba919f
Fix reference in docstrings
dnerini Feb 4, 2022
d7a4306
List rasterio as optional dependency
dnerini Feb 7, 2022
5cad933
Make n_ens_members a mandatory argument
dnerini Feb 11, 2022
19df0d2
Remove default parameters
dnerini Feb 11, 2022
e35c00a
Fix black
dnerini Feb 11, 2022
587ef13
Rename reprojection method
dnerini Feb 11, 2022
642fd75
Add missing test
dnerini Feb 11, 2022
c8e0063
Use micromamba 0.20
dnerini Feb 13, 2022
3a2cac0
add notes about lag-1 and lag-2 parameter regression
RubenImhoff Feb 15, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/test_pysteps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ name: Test pysteps
on:
# Triggers the workflow on push or pull request events to the master branch
push:
branches: [ master ]
branches:
- master
- pysteps-v2
pull_request:
branches: [ master ]
branches:
- master
- pysteps-v2

jobs:
unit_tests:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/psf/black
rev: 21.6b0
rev: 21.7b0
hooks:
- id: black
language_version: python3
1 change: 1 addition & 0 deletions ci/ci_test_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ dependencies:
- PyWavelets
- pandas
- scikit-image
- rasterio
# Test dependencies
- pytest
- pytest-cov
Expand Down
4 changes: 2 additions & 2 deletions doc/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Additional requeriments related to the documentation build only
# Additional requirements related to the documentation build only
sphinx
sphinxcontrib.bibtex
sphinx-book-theme
sphinx_gallery
scikit-image
pandas

git+https://github.com/pySTEPS/pysteps-nwp-importers.git@main#egg=pysteps_nwp_importers
12 changes: 12 additions & 0 deletions doc/source/pysteps_reference/blending.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
================
pysteps.blending
================

Implementation of blending methods for blending (ensemble) nowcasts with Numerical Weather Prediction (NWP) models.

.. automodule:: pysteps.blending.interface
.. automodule:: pysteps.blending.clim
.. automodule:: pysteps.blending.linear_blending
.. automodule:: pysteps.blending.skill_scores
.. automodule:: pysteps.blending.steps
.. automodule:: pysteps.blending.utils
1 change: 1 addition & 0 deletions doc/source/pysteps_reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ available in pysteps.
:caption: API Reference

pysteps
blending
cascade
decorators
extrapolation
Expand Down
1 change: 1 addition & 0 deletions doc/source/pysteps_reference/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ Implementation of miscellaneous utility functions.
.. automodule:: pysteps.utils.spectral
.. automodule:: pysteps.utils.tapering
.. automodule:: pysteps.utils.transformation
.. automodule:: pysteps.utils.reprojection
10 changes: 10 additions & 0 deletions doc/source/references.bib
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@

@TECHREPORT{BPS2004,
AUTHOR = "N. E. Bowler and C. E. Pierce and A. W. Seed",
TITLE = "{STEPS}: A probabilistic precipitation forecasting scheme which merges an extrapolation nowcast with downscaled {NWP}",
INSTITUTION = "UK Met Office",
TYPE = "Forecasting Research Technical Report",
NUMBER = 433,
ADDRESS = "Wallingford, United Kingdom",
YEAR = 2004,
}

@ARTICLE{BPS2006,
AUTHOR = "N. E. Bowler and C. E. Pierce and A. W. Seed",
TITLE = "{STEPS}: A probabilistic precipitation forecasting scheme which merges an extrapolation nowcast with downscaled {NWP}",
Expand Down
4 changes: 3 additions & 1 deletion doc/source/user_guide/install_pysteps.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ Other optional dependencies include:
* `pywavelets <https://pywavelets.readthedocs.io/en/latest/>`_
(for intensity-scale verification)
* `pandas <https://pandas.pydata.org/>`_ and
`scikit-image <https://scikit-image.org/>`_ (for the DATing and LINDA nowcast methods)
`scikit-image <https://scikit-image.org/>`_ (for advanced feature detection methods)
* `rasterio <https://rasterio.readthedocs.io/en/latest/>`_ (for the reprojection module)


**Important**: If you only want to use pysteps, you can continue reading below.
But, if you want to contribute to pysteps or edit the package, you need to install
Expand Down
1 change: 1 addition & 0 deletions environment_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ dependencies:
- cartopy>=0.18
- scikit-image
- pandas
- rasterio
4 changes: 1 addition & 3 deletions examples/anvil_nowcast.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,7 @@
date, root_path, path_fmt, fn_pattern, fn_ext, timestep=5, num_next_files=3
)

refobs_field, quality, metadata = io.read_timeseries(
filenames, importer, **importer_kwargs
)
refobs_field, _, metadata = io.read_timeseries(filenames, importer, **importer_kwargs)

refobs_field, metadata = utils.to_rainrate(refobs_field[-1], metadata)
refobs_field[refobs_field < 0.5] = 0.0
Expand Down
230 changes: 230 additions & 0 deletions examples/blended_forecast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# -*- coding: utf-8 -*-
"""
Blended forecast
====================

This tutorial shows how to construct a blended forecast from an ensemble nowcast
using the STEPS approach and a Numerical Weather Prediction (NWP) rainfall
forecast. The used datasets are from the Bureau of Meteorology, Australia.

"""

import os
from datetime import datetime

import numpy as np
from matplotlib import pyplot as plt

import pysteps
from pysteps import io, rcparams, blending
from pysteps.visualization import plot_precip_field


################################################################################
# Read the radar images and the NWP forecast
# ------------------------------------------
#
# First, we import a sequence of 3 images of 10-minute radar composites
# and the corresponding NWP rainfall forecast that was available at that time.
#
# You need the pysteps-data archive downloaded and the pystepsrc file
# configured with the data_source paths pointing to data folders.
# Additionally, the pysteps-nwp-importers plugin needs to be installed, see
# https://github.com/pySTEPS/pysteps-nwp-importers.

# Selected case
date_radar = datetime.strptime("202010310400", "%Y%m%d%H%M")
# The last NWP forecast was issued at 00:00
date_nwp = datetime.strptime("202010310000", "%Y%m%d%H%M")
radar_data_source = rcparams.data_sources["bom"]
nwp_data_source = rcparams.data_sources["bom_nwp"]

###############################################################################
# Load the data from the archive
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

root_path = radar_data_source["root_path"]
path_fmt = "prcp-c10/66/%Y/%m/%d"
fn_pattern = "66_%Y%m%d_%H%M00.prcp-c10"
fn_ext = radar_data_source["fn_ext"]
importer_name = radar_data_source["importer"]
importer_kwargs = radar_data_source["importer_kwargs"]
timestep = 10.0

# Find the radar files in the archive
fns = io.find_by_date(
date_radar, root_path, path_fmt, fn_pattern, fn_ext, timestep, num_prev_files=2
)

# Read the radar composites
importer = io.get_method(importer_name, "importer")
radar_precip, _, radar_metadata = io.read_timeseries(fns, importer, **importer_kwargs)

# Import the NWP data
filename = os.path.join(
nwp_data_source["root_path"],
datetime.strftime(date_nwp, nwp_data_source["path_fmt"]),
datetime.strftime(date_nwp, nwp_data_source["fn_pattern"])
+ "."
+ nwp_data_source["fn_ext"],
)

nwp_importer = io.get_method("bom_nwp", "importer")
nwp_precip, _, nwp_metadata = nwp_importer(filename)

# Only keep the NWP forecasts from the last radar observation time (2020-10-31 04:00)
# onwards

nwp_precip = nwp_precip[24:43, :, :]


################################################################################
# Pre-processing steps
# --------------------

# Make sure the units are in mm/h
converter = pysteps.utils.get_method("mm/h")
radar_precip, radar_metadata = converter(radar_precip, radar_metadata)
nwp_precip, nwp_metadata = converter(nwp_precip, nwp_metadata)

# Threshold the data
radar_precip[radar_precip < 0.1] = 0.0
nwp_precip[nwp_precip < 0.1] = 0.0

# Plot the radar rainfall field and the first time step of the NWP forecast.
date_str = datetime.strftime(date_radar, "%Y-%m-%d %H:%M")
plt.figure(figsize=(10, 5))
plt.subplot(121)
plot_precip_field(
radar_precip[-1, :, :],
geodata=radar_metadata,
title=f"Radar observation at {date_str}",
)
plt.subplot(122)
plot_precip_field(
nwp_precip[0, :, :], geodata=nwp_metadata, title=f"NWP forecast at {date_str}"
)
plt.tight_layout()
plt.show()

# transform the data to dB
transformer = pysteps.utils.get_method("dB")
radar_precip, radar_metadata = transformer(radar_precip, radar_metadata, threshold=0.1)
nwp_precip, nwp_metadata = transformer(nwp_precip, nwp_metadata, threshold=0.1)

# r_nwp has to be four dimentional (n_models, time, y, x).
# If we only use one model:
if nwp_precip.ndim == 3:
nwp_precip = nwp_precip[None, :]

###############################################################################
# For the initial time step (t=0), the NWP rainfall forecast is not that different
# from the observed radar rainfall, but it misses some of the locations and
# shapes of the observed rainfall fields. Therefore, the NWP rainfall forecast will
# initially get a low weight in the blending process.
#
# Determine the velocity fields
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

oflow_method = pysteps.motion.get_method("lucaskanade")

# First for the radar images
velocity_radar = oflow_method(radar_precip)

# Then for the NWP forecast
velocity_nwp = []
# Loop through the models
for n_model in range(nwp_precip.shape[0]):
# Loop through the timesteps. We need two images to construct a motion
# field, so we can start from timestep 1. Timestep 0 will be the same
# as timestep 1.
_v_nwp_ = []
for t in range(1, nwp_precip.shape[1]):
v_nwp_ = oflow_method(nwp_precip[n_model, t - 1 : t + 1, :])
_v_nwp_.append(v_nwp_)
v_nwp_ = None
# Add the velocity field at time step 1 to time step 0.
_v_nwp_ = np.insert(_v_nwp_, 0, _v_nwp_[0], axis=0)
velocity_nwp.append(_v_nwp_)
velocity_nwp = np.stack(velocity_nwp)


################################################################################
# The blended forecast
# --------------------

precip_forecast = blending.steps.forecast(
precip=radar_precip,
precip_models=nwp_precip,
velocity=velocity_radar,
velocity_models=velocity_nwp,
timesteps=18,
timestep=timestep,
issuetime=date_radar,
n_ens_members=1,
precip_thr=radar_metadata["threshold"],
kmperpixel=radar_metadata["xpixelsize"] / 1000.0,
noise_stddev_adj="auto",
vel_pert_method=None,
)

# Transform the data back into mm/h
precip_forecast, _ = converter(precip_forecast, radar_metadata)
radar_precip, _ = converter(radar_precip, radar_metadata)
nwp_precip, _ = converter(nwp_precip, nwp_metadata)


################################################################################
# Visualize the output
# ~~~~~~~~~~~~~~~~~~~~
#
# The NWP rainfall forecast has a lower weight than the radar-based extrapolation
# forecast at the issue time of the forecast (+0 min). Therefore, the first time
# steps consist mostly of the extrapolation.
# However, near the end of the forecast (+180 min), the NWP share in the blended
# forecast has become more important and the forecast starts to resemble the
# NWP forecast more.

fig = plt.figure(figsize=(5, 12))

leadtimes_min = [30, 60, 90, 120, 150, 180]
n_leadtimes = len(leadtimes_min)
for n, leadtime in enumerate(leadtimes_min):

# Nowcast with blending into NWP
plt.subplot(n_leadtimes, 2, n * 2 + 1)
plot_precip_field(
precip_forecast[0, int(leadtime / timestep) - 1, :, :],
geodata=radar_metadata,
title=f"Nowcast +{leadtime} min",
axis="off",
colorbar=False,
)

# Raw NWP forecast
plt.subplot(n_leadtimes, 2, n * 2 + 2)
plot_precip_field(
nwp_precip[0, int(leadtime / timestep) - 1, :, :],
geodata=nwp_metadata,
title=f"NWP +{leadtime} min",
axis="off",
colorbar=False,
)


################################################################################
# References
# ~~~~~~~~~~
#
# Bowler, N. E., and C. E. Pierce, and A. W. Seed. 2004. "STEPS: A probabilistic
# precipitation forecasting scheme which merges an extrapolation nowcast with
# downscaled NWP." Forecasting Research Technical Report No. 433. Wallingford, UK.
#
# Bowler, N. E., and C. E. Pierce, and A. W. Seed. 2006. "STEPS: A probabilistic
# precipitation forecasting scheme which merges an extrapolation nowcast with
# downscaled NWP." Quarterly Journal of the Royal Meteorological Society 132(16):
# 2127-2155. https://doi.org/10.1256/qj.04.100
#
# Seed, A. W., and C. E. Pierce, and K. Norman. 2013. "Formulation and evaluation
# of a scale decomposition-based stochastic precipitation nowcast scheme." Water
# Resources Research 49(10): 6624-664. https://doi.org/10.1002/wrcr.20536
Loading