Example of a wind retrieval in a tornado over Sydney#
This shows an example of how to retrieve winds from 4 radars over Sydney.
We use smoothing to decrease the magnitude of the updraft in the region of the mesocyclone. The reduction of noise also helps the solution converge much faster since the cost function is smoother and therefore less susecptible to find a local minimum that is in noise.
The observational constraint is reduced to 0.01 from the usual 1 because we are factoring in many more data points as we are using 4 radars instead of the two in the Darwin example.
This example uses pooch to download the data files.
import pydda
import matplotlib.pyplot as plt
import numpy as np
grid1_path = pydda.tests.get_sample_file("grid1_sydney.nc")
grid2_path = pydda.tests.get_sample_file("grid2_sydney.nc")
grid3_path = pydda.tests.get_sample_file("grid3_sydney.nc")
grid4_path = pydda.tests.get_sample_file("grid4_sydney.nc")
grid1 = pydda.io.read_grid(grid1_path)
grid2 = pydda.io.read_grid(grid2_path)
grid3 = pydda.io.read_grid(grid3_path)
grid4 = pydda.io.read_grid(grid4_path)
# Set initialization and do retrieval
grid1 = pydda.initialization.make_constant_wind_field(grid1, vel_field="VRADH_corr")
new_grids, _ = pydda.retrieval.get_dd_wind_field(
[grid1, grid2, grid3, grid4],
Co=1e-2,
Cm=256.0,
Cx=10,
Cy=10,
Cz=10,
vel_name="VRADH_corr",
refl_field="DBZH",
mask_outside_opt=True,
wind_tol=0.5,
max_iterations=200,
engine="scipy",
)
# Make a neat plot
fig = plt.figure(figsize=(10, 7))
ax = pydda.vis.plot_horiz_xsection_quiver_map(
new_grids,
background_field="DBZH",
level=3,
show_lobes=False,
bg_grid_no=3,
vmin=0,
vmax=60,
quiverkey_len=20.0,
w_vel_contours=[1.0, 3.0, 5.0, 10.0, 20.0],
quiver_spacing_x_km=2.0,
quiver_spacing_y_km=2.0,
quiverkey_loc="top",
colorbar_contour_flag=True,
cmap="ChaseSpectral",
)
ax.set_xticks(np.arange(150.5, 153, 0.1))
ax.set_yticks(np.arange(-36, -32.0, 0.1))
ax.set_xlim([151.0, 151.35])
ax.set_ylim([-34.15, -33.9])
plt.show()
## You are using the Python ARM Radar Toolkit (Py-ART), an open source
## library for working with weather radar data. Py-ART is partly
## supported by the U.S. Department of Energy as part of the Atmospheric
## Radiation Measurement (ARM) Climate Research Facility, an Office of
## Science user facility.
##
## If you use this software to prepare a publication, please cite:
##
## JJ Helmus and SM Collis, JORS 2016, doi: 10.5334/jors.119
<frozen importlib._bootstrap>:283: DeprecationWarning: the load_module() method is deprecated and slated for removal in Python 3.12; use exec_module() instead
/usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/pyart/testing/example_data.py:1: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
import pkg_resources
/usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/pkg_resources/__init__.py:2832: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('google')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages
declare_namespace(pkg)
/usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/pkg_resources/__init__.py:2832: DeprecationWarning: Deprecated call to `pkg_resources.declare_namespace('sphinxcontrib')`.
Implementing implicit namespace packages (as specified in PEP 420) is preferred to `pkg_resources.declare_namespace`. See https://setuptools.pypa.io/en/latest/references/keywords.html#keyword-namespace-packages
declare_namespace(pkg)
/usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/tensorflow_probability/python/__init__.py:57: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
if (distutils.version.LooseVersion(tf.__version__) <
/usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/tensorflow_probability/python/__init__.py:58: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
distutils.version.LooseVersion(required_tensorflow_version)):
Welcome to PyDDA 2.0.1
If you are using PyDDA in your publications, please cite:
Jackson et al. (2020) Journal of Open Research Science
Detecting Jax...
Jax/JaxOpt are not installed on your system, unable to use Jax engine.
Detecting TensorFlow...
TensorFlow detected. Checking for tensorflow-probability...
TensorFlow-probability detected. TensorFlow engine enabled!
False
Calculating weights for radars 0 and 1
Calculating weights for radars 0 and 2
Calculating weights for radars 0 and 3
Calculating weights for radars 1 and 0
Calculating weights for radars 1 and 2
Calculating weights for radars 1 and 3
Calculating weights for radars 2 and 0
Calculating weights for radars 2 and 1
Calculating weights for radars 2 and 3
Calculating weights for radars 3 and 0
Calculating weights for radars 3 and 1
Calculating weights for radars 3 and 2
Calculating weights for models...
Starting solver
rmsVR = 7.242250167336596
Total points: 281276
The max of w_init is 0.0
Total number of model points: 0
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
0|2864.7900| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000
The gradient of the cost functions is 0.1228988818772181
Nfeval | Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel | Jpoint | Max w
10| 117.2266| 23.2756| 0.0000| 0.0000| 0.0000| 0.0000| 0.0000| 18.4482
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
Cell In[1], line 17
15 # Set initialization and do retrieval
16 grid1 = pydda.initialization.make_constant_wind_field(grid1, vel_field="VRADH_corr")
---> 17 new_grids, _ = pydda.retrieval.get_dd_wind_field(
18 [grid1, grid2, grid3, grid4],
19 Co=1e-2,
20 Cm=256.0,
21 Cx=10,
22 Cy=10,
23 Cz=10,
24 vel_name="VRADH_corr",
25 refl_field="DBZH",
26 mask_outside_opt=True,
27 wind_tol=0.5,
28 max_iterations=200,
29 engine="scipy",
30 )
31 # Make a neat plot
32 fig = plt.figure(figsize=(10, 7))
File ~/work/PyDDA/PyDDA/pydda/retrieval/wind_retrieve.py:1474, in get_dd_wind_field(Grids, u_init, v_init, w_init, engine, **kwargs)
1467 w_init = new_grids[0]["w"].values.squeeze()
1469 if (
1470 engine.lower() == "scipy"
1471 or engine.lower() == "jax"
1472 or engine.lower() == "auglag"
1473 ):
-> 1474 return _get_dd_wind_field_scipy(
1475 new_grids, u_init, v_init, w_init, engine, **kwargs
1476 )
1477 elif engine.lower() == "tensorflow":
1478 return _get_dd_wind_field_tensorflow(
1479 new_grids, u_init, v_init, w_init, **kwargs
1480 )
File ~/work/PyDDA/PyDDA/pydda/retrieval/wind_retrieve.py:602, in _get_dd_wind_field_scipy(Grids, u_init, v_init, w_init, engine, points, vel_name, refl_field, u_back, v_back, z_back, frz, Co, Cm, Cx, Cy, Cz, Cb, Cv, Cmod, Cpoint, cvtol, gtol, Jveltol, Ut, Vt, low_pass_filter, mask_outside_opt, weights_obs, weights_model, weights_bg, max_iterations, mask_w_outside_opt, filter_window, filter_order, min_bca, max_bca, upper_bc, model_fields, output_cost_functions, roi, wind_tol, tolerance, const_boundary_cond, max_wind_mag)
600 parameters.print_out = False
601 if engine.lower() == "scipy":
--> 602 winds = fmin_l_bfgs_b(
603 J_function,
604 winds,
605 args=(parameters,),
606 maxiter=max_iterations,
607 pgtol=tolerance,
608 bounds=bounds,
609 fprime=grad_J,
610 disp=0,
611 iprint=-1,
612 callback=_vert_velocity_callback,
613 )
614 else:
616 def loss_and_gradient(x):
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_lbfgsb_py.py:237, in fmin_l_bfgs_b(func, x0, fprime, args, approx_grad, bounds, m, factr, pgtol, epsilon, iprint, maxfun, maxiter, disp, callback, maxls)
225 callback = _wrap_callback(callback)
226 opts = {'disp': disp,
227 'iprint': iprint,
228 'maxcor': m,
(...)
234 'callback': callback,
235 'maxls': maxls}
--> 237 res = _minimize_lbfgsb(fun, x0, args=args, jac=jac, bounds=bounds,
238 **opts)
239 d = {'grad': res['jac'],
240 'task': res['message'],
241 'funcalls': res['nfev'],
242 'nit': res['nit'],
243 'warnflag': res['status']}
244 f = res['fun']
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_lbfgsb_py.py:407, in _minimize_lbfgsb(fun, x0, args, jac, bounds, disp, maxcor, ftol, gtol, eps, maxfun, maxiter, iprint, callback, maxls, finite_diff_rel_step, **unknown_options)
401 task_str = task.tobytes()
402 if task_str.startswith(b'FG'):
403 # The minimization routine wants f and g at the current x.
404 # Note that interruptions due to maxfun are postponed
405 # until the completion of the current minimization iteration.
406 # Overwrite f and g:
--> 407 f, g = func_and_grad(x)
408 elif task_str.startswith(b'NEW_X'):
409 # new iteration
410 n_iterations += 1
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py:297, in ScalarFunction.fun_and_grad(self, x)
295 self._update_x_impl(x)
296 self._update_fun()
--> 297 self._update_grad()
298 return self.f, self.g
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py:267, in ScalarFunction._update_grad(self)
265 def _update_grad(self):
266 if not self.g_updated:
--> 267 self._update_grad_impl()
268 self.g_updated = True
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py:175, in ScalarFunction.__init__.<locals>.update_grad()
174 def update_grad():
--> 175 self.g = grad_wrapped(self.x)
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/scipy/optimize/_differentiable_functions.py:172, in ScalarFunction.__init__.<locals>.grad_wrapped(x)
170 def grad_wrapped(x):
171 self.ngev += 1
--> 172 return np.atleast_1d(grad(np.copy(x), *args))
File ~/work/PyDDA/PyDDA/pydda/cost_functions/cost_functions.py:528, in grad_J(winds, parameters)
513 grad = _cost_functions_numpy.calculate_grad_radial_vel(
514 parameters.vrs,
515 parameters.els,
(...)
524 upper_bc=parameters.upper_bc,
525 )
527 if parameters.Cm > 0:
--> 528 grad += _cost_functions_numpy.calculate_mass_continuity_gradient(
529 winds[0],
530 winds[1],
531 winds[2],
532 parameters.z,
533 parameters.dx,
534 parameters.dy,
535 parameters.dz,
536 coeff=parameters.Cm,
537 upper_bc=parameters.upper_bc,
538 )
540 if parameters.Cx > 0 or parameters.Cy > 0 or parameters.Cz > 0:
541 grad += _cost_functions_numpy.calculate_smoothness_gradient(
542 winds[0],
543 winds[1],
(...)
551 upper_bc=parameters.upper_bc,
552 )
File ~/work/PyDDA/PyDDA/pydda/cost_functions/_cost_functions_numpy.py:465, in calculate_mass_continuity_gradient(u, v, w, z, dx, dy, dz, coeff, anel, upper_bc)
463 grad_u = -np.gradient(div, dx, axis=2) * coeff
464 grad_v = -np.gradient(div, dy, axis=1) * coeff
--> 465 grad_w = -np.gradient(div, dz, axis=0) * coeff
467 # Impermeability condition
468 grad_w[0, :, :] = 0
File <__array_function__ internals>:180, in gradient(*args, **kwargs)
File /usr/share/miniconda3/envs/pydda-docs/lib/python3.10/site-packages/numpy/lib/function_base.py:1256, in gradient(f, axis, edge_order, *varargs)
1254 dx_0 = ax_dx if uniform_spacing else ax_dx[0]
1255 # 1D equivalent -- out[0] = (f[1] - f[0]) / (x[1] - x[0])
-> 1256 out[tuple(slice1)] = (f[tuple(slice2)] - f[tuple(slice3)]) / dx_0
1258 slice1[axis] = -1
1259 slice2[axis] = -1
KeyboardInterrupt: