Skip to content

Commit 3f30482

Browse files
committed
Add tutorial on ensemble verification
1 parent b5b59b1 commit 3f30482

File tree

2 files changed

+171
-2
lines changed

2 files changed

+171
-2
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
#!/bin/env python
2+
"""
3+
Ensemble verification
4+
=====================
5+
6+
This tutorial shows how to compute and plot an extrapolation nowcast using
7+
Finnish radar data.
8+
9+
"""
10+
11+
from pylab import *
12+
from datetime import datetime
13+
from pprint import pprint
14+
from pysteps import io, nowcasts, rcparams, verification
15+
from pysteps.motion.lucaskanade import dense_lucaskanade
16+
from pysteps.postprocessing import ensemblestats
17+
from pysteps.utils import conversion, dimension, transformation
18+
from pysteps.visualization import plot_precip_field
19+
20+
# Set nowcast parameters
21+
n_ens_members = 20
22+
n_leadtimes = 6
23+
seed = 24
24+
25+
###############################################################################
26+
# Read precipitation field
27+
# ------------------------
28+
#
29+
# First thing, the sequence of Swiss radar composites is imported, converted and
30+
# transformed into units of dBR.
31+
32+
date = datetime.strptime("201607112100", "%Y%m%d%H%M")
33+
data_source = "mch"
34+
35+
# Load data source config
36+
root_path = rcparams.data_sources[data_source]["root_path"]
37+
path_fmt = rcparams.data_sources[data_source]["path_fmt"]
38+
fn_pattern = rcparams.data_sources[data_source]["fn_pattern"]
39+
fn_ext = rcparams.data_sources[data_source]["fn_ext"]
40+
importer_name = rcparams.data_sources[data_source]["importer"]
41+
importer_kwargs = rcparams.data_sources[data_source]["importer_kwargs"]
42+
timestep = rcparams.data_sources[data_source]["timestep"]
43+
44+
# Find the radar files in the archive
45+
fns = io.find_by_date(
46+
date, root_path, path_fmt, fn_pattern, fn_ext, timestep, num_prev_files=2
47+
)
48+
49+
# Read the data from the archive
50+
importer = io.get_method(importer_name, "importer")
51+
R, _, metadata = io.read_timeseries(fns, importer, **importer_kwargs)
52+
53+
# Convert to rain rate
54+
R, metadata = conversion.to_rainrate(R, metadata)
55+
56+
# Upscale data to 2 km to limit memory usage
57+
R, metadata = dimension.aggregate_fields_space(R, metadata, 2000)
58+
59+
# Plot the rainfall field
60+
plot_precip_field(R[-1, :, :], geodata=metadata)
61+
62+
# Log-transform the data to unit of dBR, set the threshold to 0.1 mm/h,
63+
# set the fill value to -15 dBR
64+
R, metadata = transformation.dB_transform(R, metadata, threshold=0.1, zerovalue=-15.0)
65+
66+
# Set missing values with the fill value
67+
R[~np.isfinite(R)] = -15.0
68+
69+
# Nicely print the metadata
70+
pprint(metadata)
71+
72+
###############################################################################
73+
# Forecast
74+
# --------
75+
#
76+
# We use the STEPS approach to produce a ensemble nowcast of precipitation fields.
77+
78+
# Estimate the motion field
79+
V = dense_lucaskanade(R)
80+
81+
# The STEPES nowcast
82+
nowcast_method = nowcasts.get_method("steps")
83+
R_f = nowcast_method(
84+
R[-3:, :, :],
85+
V,
86+
n_leadtimes,
87+
n_ens_members,
88+
n_cascade_levels=6,
89+
R_thr=-10.0,
90+
kmperpixel=2.0,
91+
timestep=timestep,
92+
decomp_method="fft",
93+
bandpass_filter_method="gaussian",
94+
noise_method="nonparametric",
95+
vel_pert_method="bps",
96+
mask_method="incremental",
97+
seed=seed,
98+
)
99+
100+
# Back-transform to rain rates
101+
R_f = transformation.dB_transform(R_f, threshold=-10.0, inverse=True)[0]
102+
103+
# Plot some of the realizations
104+
fig = figure()
105+
for i in range(4):
106+
ax = fig.add_subplot(221 + i)
107+
ax.set_title("Member %02d" % i)
108+
plot_precip_field(R_f[i, -1, :, :], geodata=metadata, colorbar=False, axis="off")
109+
tight_layout()
110+
111+
###############################################################################
112+
# Verification
113+
# ------------
114+
#
115+
# Pysteps includes a number of verification metrics to help users to analyze
116+
# the general characteristics of the nowcasts in terms of consistency and
117+
# quality (or goodness).
118+
# Here, we will verify our probabilistic forecasts using the ROC curve,
119+
# reliability diagrams, and rank histograms, as implemented in the verification
120+
# module of pysteps.
121+
122+
# Find the files containing the verifying observations
123+
fns = io.archive.find_by_date(
124+
date,
125+
root_path,
126+
path_fmt,
127+
fn_pattern,
128+
fn_ext,
129+
timestep,
130+
0,
131+
num_next_files=n_leadtimes,
132+
)
133+
134+
# Read the observations
135+
R_o, _, metadata_o = io.read_timeseries(fns, importer, **importer_kwargs)
136+
137+
# Convert to mm/h
138+
R_o, metadata_o = conversion.to_rainrate(R_o, metadata_o)
139+
140+
# Upscale data to 2 km
141+
R_o, metadata_o = dimension.aggregate_fields_space(R_o, metadata_o, 2000)
142+
143+
# Compute the verification for the last lead time
144+
145+
# compute the exceedance probability of 0.1 mm/h from the ensemble
146+
P_f = ensemblestats.excprob(R_f[:, -1, :, :], 0.1, ignore_nan=True)
147+
148+
# compute and plot the ROC curve
149+
roc = verification.ROC_curve_init(0.1, n_prob_thrs=10)
150+
verification.ROC_curve_accum(roc, P_f, R_o[-1, :, :])
151+
fig = figure()
152+
verification.plot_ROC(roc, ax=fig.gca(), opt_prob_thr=True)
153+
title("ROC curve (+ %i min)" % (n_leadtimes * timestep))
154+
155+
# compute and plot the reliability diagram
156+
reldiag = verification.reldiag_init(0.1)
157+
verification.reldiag_accum(reldiag, P_f, R_o[-1, :, :])
158+
fig = figure()
159+
verification.plot_reldiag(reldiag, ax=fig.gca())
160+
title("Reliability diagram (+ %i min)" % (n_leadtimes * timestep))
161+
162+
# compute and plot the rank histogram
163+
rankhist = verification.rankhist_init(R_f.shape[0], 0.1)
164+
verification.rankhist_accum(rankhist, R_f[:, -1, :, :], R_o[-1, :, :])
165+
fig = figure()
166+
verification.plot_rankhist(rankhist, ax=fig.gca())
167+
title("Rank histogram (+ %i min)" % (n_leadtimes * timestep))
168+
169+
# sphinx_gallery_thumbnail_number = 5

examples/plot_steps_nowcast.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from pysteps.visualization import plot_precip_field
1919

2020
# Set nowcast parameters
21-
n_ens_members = 12
21+
n_ens_members = 20
2222
n_leadtimes = 6
2323
seed = 24
2424

@@ -160,7 +160,7 @@
160160
# the ensemble size. In this sense, the S-PROG forecast can be seen as
161161
# the mean of an ensemble of infinite size.
162162

163-
# Plot the first two realizations
163+
# Plot some of the realizations
164164
fig = figure()
165165
for i in range(4):
166166
ax = fig.add_subplot(221 + i)

0 commit comments

Comments
 (0)