[1]:
# flake8: noqa

Routine verification measures for radar-based precipitation estimates#

[2]:
import wradlib
import os
import numpy as np
import matplotlib.pyplot as pl
import warnings

warnings.filterwarnings("ignore")
try:
    get_ipython().run_line_magic("matplotlib inline")
except:
    pl.ion()
/home/runner/micromamba-root/envs/wradlib-tests/lib/python3.11/site-packages/tqdm/auto.py:22: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

Extract bin values from a polar radar data set at rain gage locations#

Read polar data set#

[3]:
filename = wradlib.util.get_wradlib_data_file("misc/polar_R_tur.gz")
data = np.loadtxt(filename)

Define site coordinates (lon/lat) and polar coordinate system#

[4]:
r = np.arange(1, 129)
az = np.linspace(0, 360, 361)[0:-1]
sitecoords = (9.7839, 48.5861)

Make up two rain gauge locations (say we want to work in Gaus Krueger zone 3)#

[5]:
# Define the projection via epsg-code
proj = wradlib.georef.epsg_to_osr(31467)
# Coordinates of the rain gages in Gauss-Krueger 3 coordinates
x, y = np.array([3557880, 3557890]), np.array([5383379, 5383375])

Now extract the radar values at those bins that are closest to our rain gauges#

For this purppose, we use the PolarNeighbours class from wraldib’s verify module. Here, we extract the 9 nearest bins…

[6]:
polarneighbs = wradlib.verify.PolarNeighbours(r, az, sitecoords, proj, x, y, nnear=9)
radar_at_gages = polarneighbs.extract(data)
print("Radar values at rain gauge #1: %r" % radar_at_gages[0].tolist())
print("Radar values at rain gauge #2: %r" % radar_at_gages[1].tolist())
Radar values at rain gauge #1: [0.01, 0.02, 0.01, 0.01, 0.02, 0.05, 0.01, 0.01, 0.01]
Radar values at rain gauge #2: [0.2, 0.06, 0.15, 0.69, 0.06, 0.26, 0.05, 0.99, 0.32]

Retrieve the bin coordinates (all of them or those at the rain gauges)#

[7]:
binx, biny = polarneighbs.get_bincoords()
binx_nn, biny_nn = polarneighbs.get_bincoords_at_points()

Plot the entire radar domain and zoom into the surrounding of the rain gauge locations#

[8]:
fig = pl.figure(figsize=(12, 12))
ax = fig.add_subplot(121)
ax.plot(binx, biny, "r+")
ax.plot(binx_nn, biny_nn, "b+", markersize=10)
ax.plot(x, y, "bo")
ax.axis("tight")
ax.set_aspect("equal")
pl.title("Full view")
ax = fig.add_subplot(122)
ax.plot(binx, biny, "r+")
ax.plot(binx_nn, biny_nn, "b+", markersize=10)
ax.plot(x, y, "bo")
pl.xlim(binx_nn.min() - 5, binx_nn.max() + 5)
pl.ylim(biny_nn.min() - 7, biny_nn.max() + 8)
ax.set_aspect("equal")
txt = pl.title("Zoom into rain gauge locations")
pl.tight_layout()
../../_images/notebooks_verification_wradlib_verify_example_16_0.png

Create a verification report#

In this example, we make up a true Kdp profile and verify our reconstructed Kdp.

Create synthetic data and reconstruct KDP#

[9]:
# Synthetic truth
dr = 0.5
r = np.arange(0, 100, dr)
kdp_true = np.sin(0.3 * r)
kdp_true[kdp_true < 0] = 0.0
phidp_true = np.cumsum(kdp_true) * 2 * dr
# Synthetic observation of PhiDP with a random noise and gaps
np.random.seed(1319622840)
phidp_raw = phidp_true + np.random.uniform(-2, 2, len(phidp_true))
gaps = np.random.uniform(0, len(r), 20).astype("int")
phidp_raw[gaps] = np.nan

# linearly interpolate nan
nans = np.isnan(phidp_raw)
phidp_ipol = phidp_raw.copy()
phidp_ipol[nans] = np.interp(r[nans], r[~nans], phidp_raw[~nans])

# Reconstruct PhiDP and KDP
phidp_rawre, kdp_rawre = wradlib.dp.process_raw_phidp_vulpiani(phidp_raw, dr=dr)
phidp_ipre, kdp_ipre = wradlib.dp.process_raw_phidp_vulpiani(phidp_ipol, dr=dr)

# Plot results
fig = pl.figure(figsize=(12, 8))
ax = fig.add_subplot(211)
pl.plot(kdp_true, "g-", label="True KDP")
pl.plot(kdp_rawre, "r-", label="Reconstructed Raw KDP")
pl.plot(kdp_ipre, "b-", label="Reconstructed Ipol KDP")
pl.grid()
lg = pl.legend()

ax = fig.add_subplot(212)
pl.plot(r, phidp_true, "b--", label="True PhiDP")
pl.plot(r, np.ma.masked_invalid(phidp_raw), "b-", label="Raw PhiDP")
pl.plot(r, phidp_rawre, "r-", label="Reconstructed Raw PhiDP")
pl.plot(r, phidp_ipre, "g-", label="Reconstructed Ipol PhiDP")
pl.grid()
lg = pl.legend(loc="lower right")
txt = pl.xlabel("Range (km)")
../../_images/notebooks_verification_wradlib_verify_example_19_0.png

Create verification report#

[10]:
metrics_raw = wradlib.verify.ErrorMetrics(kdp_true, kdp_rawre)
metrics_raw.pprint()
metrics_ip = wradlib.verify.ErrorMetrics(kdp_true, kdp_ipre)
metrics_ip.pprint()

pl.subplots_adjust(wspace=0.5)
ax = pl.subplot(121, aspect=1.0)
ax.plot(metrics_raw.obs, metrics_raw.est, "bo")
ax.plot([-1, 2], [-1, 2], "k--")
pl.xlim(-0.3, 1.1)
pl.ylim(-0.3, 1.1)
xlabel = ax.set_xlabel("True KDP (deg/km)")
ylabel = ax.set_ylabel("Reconstructed Raw KDP (deg/km)")
ax = pl.subplot(122, aspect=1.0)
ax.plot(metrics_ip.obs, metrics_ip.est, "bo")
ax.plot([-1, 2], [-1, 2], "k--")
pl.xlim(-0.3, 1.1)
pl.ylim(-0.3, 1.1)
xlabel = ax.set_xlabel("True KDP (deg/km)")
ylabel = ax.set_ylabel("Reconstructed Ipol KDP (deg/km)")
{'corr': 0.95,
 'mas': 0.1,
 'meanerr': -0.0,
 'mse': 0.01,
 'nash': 0.93,
 'pbias': -0.0,
 'r2': 0.9,
 'ratio': nan,
 'rmse': 0.1,
 'spearman': 0.92,
 'sse': 2.96}
{'corr': 0.95,
 'mas': 0.1,
 'meanerr': -0.01,
 'mse': 0.01,
 'nash': 0.93,
 'pbias': -3.0,
 'r2': 0.91,
 'ratio': nan,
 'rmse': 0.1,
 'spearman': 0.92,
 'sse': 2.91}
../../_images/notebooks_verification_wradlib_verify_example_21_1.png