|
| 1 | +#!/bin/env python |
| 2 | +""" |
| 3 | +Extrapolation nowcast |
| 4 | +===================== |
| 5 | +
|
| 6 | +This tutorial shows how to compute and plot an extrapolation nowcast using |
| 7 | +Swiss radar data. |
| 8 | +
|
| 9 | +""" |
| 10 | + |
| 11 | +from pylab import * |
| 12 | +from datetime import datetime |
| 13 | +import numpy as np |
| 14 | +from pprint import pprint |
| 15 | +from pysteps import io, motion, nowcasts, rcparams, verification |
| 16 | +from pysteps.utils import conversion, transformation |
| 17 | +from pysteps.visualization import plot_precip_field, quiver |
| 18 | + |
| 19 | +############################################################################### |
| 20 | +# Read the radar input images |
| 21 | +# --------------------------- |
| 22 | +# |
| 23 | +# First thing, the sequence of radar composites is imported, converted and |
| 24 | +# transformed into units of dBR. |
| 25 | + |
| 26 | +date = datetime.strptime("201705091100", "%Y%m%d%H%M") |
| 27 | +data_source = "fmi" |
| 28 | +n_leadtimes = 12 |
| 29 | + |
| 30 | +# Load data source config |
| 31 | +root_path = rcparams.data_sources[data_source]["root_path"] |
| 32 | +path_fmt = rcparams.data_sources[data_source]["path_fmt"] |
| 33 | +fn_pattern = rcparams.data_sources[data_source]["fn_pattern"] |
| 34 | +fn_ext = rcparams.data_sources[data_source]["fn_ext"] |
| 35 | +importer_name = rcparams.data_sources[data_source]["importer"] |
| 36 | +importer_kwargs = rcparams.data_sources[data_source]["importer_kwargs"] |
| 37 | +timestep = rcparams.data_sources[data_source]["timestep"] |
| 38 | + |
| 39 | +# Find the input files from the archive |
| 40 | +fns = io.archive.find_by_date( |
| 41 | + date, root_path, path_fmt, fn_pattern, fn_ext, timestep, num_prev_files=2 |
| 42 | +) |
| 43 | + |
| 44 | +# Read the radar composites |
| 45 | +importer = io.get_method(importer_name, "importer") |
| 46 | +R, _, metadata = io.read_timeseries(fns, importer, **importer_kwargs) |
| 47 | + |
| 48 | +# Convert to rain rate using the finnish Z-R relationship |
| 49 | +R, metadata = conversion.to_rainrate(R, metadata, 223.0, 1.53) |
| 50 | + |
| 51 | +# Store the last frame for polotting it later later |
| 52 | +R_ = R[-1, :, :].copy() |
| 53 | + |
| 54 | +# Log-transform the data |
| 55 | +R, metadata = transformation.dB_transform(R, metadata, threshold=0.1, zerovalue=-15.0) |
| 56 | + |
| 57 | +# Nicely print the metadata |
| 58 | +pprint(metadata) |
| 59 | + |
| 60 | +############################################################################### |
| 61 | +# Compute the nowcast |
| 62 | +# ------------------- |
| 63 | +# |
| 64 | +# The extrapolation nowcast is based on the estimation of the motion field, |
| 65 | +# which is here performed using a local tacking approach (Lucas-Kanade). |
| 66 | +# The most recent radar rainfall field is then simply advected along this motion |
| 67 | +# field in oder to produce an extrapolation forecast. |
| 68 | + |
| 69 | +# Estimate the motion field with Lucas-Kanade |
| 70 | +oflow_method = motion.get_method("LK") |
| 71 | +V = oflow_method(R[-3:, :, :]) |
| 72 | + |
| 73 | +# Extrapolate the last radar observation |
| 74 | +extrapolate = nowcasts.get_method("extrapolation") |
| 75 | +R[~np.isfinite(R)] = metadata["zerovalue"] |
| 76 | +R_f = extrapolate(R[-1, :, :], V, n_leadtimes) |
| 77 | + |
| 78 | +# Back-transform to rain rate |
| 79 | +R_f = transformation.dB_transform(R_f, threshold=-10.0, inverse=True)[0] |
| 80 | + |
| 81 | +# Plot the motion field |
| 82 | +plot_precip_field(R_, geodata=metadata) |
| 83 | +quiver(V, geodata=metadata) |
| 84 | + |
| 85 | +############################################################################### |
| 86 | +# Verify with FSS |
| 87 | +# --------------- |
| 88 | +# |
| 89 | +# The fractions skill score (FSS) provides an intuitive assessment of the |
| 90 | +# dependency of skill on spatial scale and intensity, which makes it an ideal |
| 91 | +# skill score for high-resolution precipitation forecasts. |
| 92 | + |
| 93 | +# Find observations in the data archive |
| 94 | +fns = io.archive.find_by_date( |
| 95 | + date, |
| 96 | + root_path, |
| 97 | + path_fmt, |
| 98 | + fn_pattern, |
| 99 | + fn_ext, |
| 100 | + timestep, |
| 101 | + num_prev_files=0, |
| 102 | + num_next_files=n_leadtimes, |
| 103 | +) |
| 104 | +# Read the radar composites |
| 105 | +R_o, _, metadata_o = io.read_timeseries(fns, importer, **importer_kwargs) |
| 106 | +R_o, metadata_o = conversion.to_rainrate(R_o, metadata_o, 223.0, 1.53) |
| 107 | + |
| 108 | +# Compute fractions skill score (FSS) for all lead times, a set of scales and 1 mm/h |
| 109 | +fss = verification.get_method("FSS") |
| 110 | +scales = [2, 4, 8, 16, 32, 64, 128, 256, 512] |
| 111 | +threshold = 1.0 |
| 112 | +score = [] |
| 113 | +for i in range(n_leadtimes): |
| 114 | + score_ = [] |
| 115 | + for scale in scales: |
| 116 | + score_.append(fss(R_f[i, :, :], R_o[i + 1, :, :], threshold, scale)) |
| 117 | + score.append(score_) |
| 118 | + |
| 119 | +figure() |
| 120 | +x = np.arange(1, n_leadtimes + 1) * timestep |
| 121 | +plot(x, score) |
| 122 | +legend(scales, title="Scale [km]") |
| 123 | +xlabel("Lead time [min]") |
| 124 | +ylabel("FSS ( > 1.0 mm/h ) ") |
| 125 | +title("Fractions skill score") |
0 commit comments