Source code for pydda.cost_functions.cost_functions

import numpy as np
import pyart
import scipy.ndimage.filters


[docs]def J_function(winds, vrs, azs, els, wts, u_back, v_back, u_model, v_model, w_model, Co, Cm, Cx, Cy, Cz, Cb, Cv, Cmod, Ut, Vt, grid_shape, dx, dy, dz, z, rmsVr, weights, bg_weights, model_weights, upper_bc, print_out=False): """ Calculates the total cost function. This typically does not need to be called directly as get_dd_wind_field is a wrapper around this function and grad_J. In order to add more terms to the cost function, modify this function and grad_J. Parameters ---------- winds: 1-D float array The wind field, flattened to 1-D for f_min. The total size of the array will be a 1D array of 3*nx*ny*nz elements. vrs: List of 3D float arrays List of radial velocities from each radar. All arrays in list must have the same dimensions. azs: List of 3D float arrays List of azimuths from each radar. All arrays in list must have the same dimensions. els: List of 3D float arrays List of elevations from each radar. All arrays in list must have the same dimensions. wts: List of 3D float arrays Float array containing fall speeds from radar. All arrays in list must have the same dimensions. u_back: 1D float array (number of vertical levels): Background u wind. This takes in a 1D float array of length nz, with each element corresponding to the u component of the wind at a given vertical level from the sounding. v_back: 1D float array (number of vertical levels): Background v wind. This takes in a 1D float array of length nz, with each element corresponding to the v component of the wind at a given vertical level from the sounding. u_model: list of 3D float arrays U from each model integrated into the retrieval. The U from each model is given as a list of array of the same dimensions, with the U from the model interpolated on to the radar analysis grid. v_model: list of 3D float arrays V from each model integrated into the retrieval. The V from each model is given as a list of array of the same dimensions, with the V from the model interpolated on to the radar analysis grid. w_model: W from each model integrated into the retrieval. The W from each model is given as a list of array of the same dimensions, with the W from the model interpolated on to the radar analysis grid. Co: float Weighting coefficient for data constraint. Cm: float Weighting coefficient for mass continuity constraint. Cx: float Smoothing coefficient for x-direction Cy: float Smoothing coefficient for y-direction Cz: float Smoothing coefficient for z-direction Cb: float Coefficient for sounding constraint Cv: float Weight for cost function related to vertical vorticity equation. Cmod: float Coefficient for model constraint Ut: float Prescribed storm motion. This is only needed if Cv is not zero. Vt: float Prescribed storm motion. This is only needed if Cv is not zero. grid_shape: Shape of wind grid dx: Spacing of grid in x direction dy: Spacing of grid in y direction dz: Spacing of grid in z direction z: Grid vertical levels in m rmsVr: float The sum of squares of velocity/num_points. Use for normalization of data weighting coefficient weights: n_radars by z_bins by y_bins by x_bins float array Data weights for each pair of radars. This is usually automatically determined by get_dd_wind_field. bg_weights: z_bins by y_bins by x_bins float array Data weights for sounding constraint. model_weights: n_models by z_bins by y_bins by x_bins float array Data weights for each model. upper_bc: bool True to enforce w=0 at top of domain (impermeability condition), False to not enforce impermeability at top of domain print_out: bool Set to True to print out the value of the cost function. Returns ------- J: float The value of the cost function """ winds = np.reshape(winds, (3, grid_shape[0], grid_shape[1], grid_shape[2])) Jvel = calculate_radial_vel_cost_function( vrs, azs, els, winds[0], winds[1], winds[2], wts, rmsVr=rmsVr, weights=weights, coeff=Co) if(Cm > 0): Jmass = calculate_mass_continuity( winds[0], winds[1], winds[2], z, dx, dy, dz, coeff=Cm) else: Jmass = 0 if(Cx > 0 or Cy > 0 or Cz > 0): Jsmooth = calculate_smoothness_cost( winds[0], winds[1], winds[2], Cx=Cx, Cy=Cy, Cz=Cz) else: Jsmooth = 0 if(Cb > 0): Jbackground = calculate_background_cost( winds[0], winds[1], winds[2], bg_weights, u_back, v_back, Cb) else: Jbackground = 0 if(Cv > 0): Jvorticity = calculate_vertical_vorticity_cost( winds[0], winds[1], winds[2], dx, dy, dz, Ut, Vt, coeff=Cv) else: Jvorticity = 0 if(Cmod > 0): Jmod = calculate_model_cost( winds[0], winds[1], winds[2], model_weights, u_model, v_model, w_model, coeff=Cmod) else: Jmod = 0 if(print_out is True): print(('| Jvel | Jmass | Jsmooth | Jbg | Jvort | Jmodel ' + '| Max w ')) print(('|' + "{:9.4f}".format(Jvel) + '|' + "{:9.4f}".format(Jmass) + '|' + "{:9.4f}".format(Jsmooth) + '|' + "{:9.4f}".format(Jbackground) + '|' + "{:9.4f}".format(Jvorticity) + '|' + "{:9.4f}".format(Jmod) + '|' + "{:9.4f}".format(np.abs(winds[2]).max()))) return Jvel + Jmass + Jsmooth + Jbackground + Jvorticity + Jmod
[docs]def grad_J(winds, vrs, azs, els, wts, u_back, v_back, u_model, v_model, w_model, Co, Cm, Cx, Cy, Cz, Cb, Cv, Cmod, Ut, Vt, grid_shape, dx, dy, dz, z, rmsVr, weights, bg_weights, model_weights, upper_bc, print_out=False): """ Calculates the gradient of the cost function. This typically does not need to be called directly as get_dd_wind_field is a wrapper around this function and J_function. In order to add more terms to the cost function, modify this function and grad_J. Parameters ---------- winds: 1-D float array The wind field, flattened to 1-D for f_min vrs: List of float arrays List of radial velocities from each radar azs: List of float arrays List of azimuths from each radar els: List of float arrays List of elevations from each radar wts: List of float arrays Float array containing fall speed from radar. u_back: 1D float array (number of vertical levels): Background u wind v_back: 1D float array (number of vertical levels): Background u wind u_model: list of 3D float arrays U from each model integrated into the retrieval v_model: list of 3D float arrays V from each model integrated into the retrieval w_model: W from each model integrated into the retrieval Co: float Weighting coefficient for data constraint. Cm: float Weighting coefficient for mass continuity constraint. Cx: float Smoothing coefficient for x-direction Cy: float Smoothing coefficient for y-direction Cz: float Smoothing coefficient for z-direction Cb: float Coefficient for sounding constraint Cv: float Weight for cost function related to vertical vorticity equation. Cmod: float Coefficient for model constraint Ut: float Prescribed storm motion. This is only needed if Cv is not zero. Vt: float Prescribed storm motion. This is only needed if Cv is not zero. grid_shape: Shape of wind grid dx: Spacing of grid in x direction dy: Spacing of grid in y direction dz: Spacing of grid in z direction z: Grid vertical levels in m rmsVr: float The sum of squares of velocity/num_points. Use for normalization of data weighting coefficient weights: n_radars by z_bins by y_bins x x_bins float array Data weights for each pair of radars bg_weights: z_bins by y_bins x x_bins float array Data weights for sounding constraint model_weights: n_models by z_bins by y_bins by x_bins float array Data weights for each model. upper_bc: bool True to enforce w=0 at top of domain (impermeability condition), False to not enforce impermeability at top of domain Returns ------- grad: 1D float array Gradient vector of cost function """ winds = np.reshape(winds, (3, grid_shape[0], grid_shape[1], grid_shape[2])) grad = calculate_grad_radial_vel( vrs, els, azs, winds[0], winds[1], winds[2], wts, weights, rmsVr, coeff=Co, upper_bc=upper_bc) if(Cm > 0): grad += calculate_mass_continuity_gradient( winds[0], winds[1], winds[2], z, dx, dy, dz, coeff=Cm, upper_bc=upper_bc) if(Cx > 0 or Cy > 0 or Cz > 0): grad += calculate_smoothness_gradient( winds[0], winds[1], winds[2], Cx=Cx, Cy=Cy, Cz=Cz, upper_bc=upper_bc) if(Cb > 0): grad += calculate_background_gradient( winds[0], winds[1], winds[2], bg_weights, u_back, v_back, Cb, upper_bc=upper_bc) if(Cv > 0): grad += calculate_vertical_vorticity_gradient( winds[0], winds[1], winds[2], dx, dy, dz, Ut, Vt, coeff=Cv) if(Cmod > 0): grad += calculate_model_gradient( winds[0], winds[1], winds[2], model_weights, u_model, v_model, w_model, coeff=Cmod) if(print_out is True): print('Norm of gradient: ' + str(np.linalg.norm(grad, np.inf))) return grad
[docs]def calculate_radial_vel_cost_function(vrs, azs, els, u, v, w, wts, rmsVr, weights, coeff=1.0): """ Calculates the cost function due to difference of the wind field from radar radial velocities. For more information on this cost function, see Potvin et al. (2012) and Shapiro et al. (2009). All arrays in the given lists must have the same dimensions and represent the same spatial coordinates. Parameters ---------- vrs: List of float arrays List of radial velocities from each radar els: List of float arrays List of elevations from each radar azs: List of float arrays List of azimuths from each radar u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field wts: List of float arrays Float array containing fall speed from radar. rmsVr: float The sum of squares of velocity/num_points. Use for normalization of data weighting coefficient weights: n_radars x_bins x y_bins float array Data weights for each pair of radars coeff: float Constant for cost function Returns ------- J_o: float Observational cost function References ----------- Potvin, C.K., A. Shapiro, and M. Xue, 2012: Impact of a Vertical Vorticity Constraint in Variational Dual-Doppler Wind Analysis: Tests with Real and Simulated Supercell Data. J. Atmos. Oceanic Technol., 29, 32–49, https://doi.org/10.1175/JTECH-D-11-00019.1 Shapiro, A., C.K. Potvin, and J. Gao, 2009: Use of a Vertical Vorticity Equation in Variational Dual-Doppler Wind Analysis. J. Atmos. Oceanic Technol., 26, 2089–2106, https://doi.org/10.1175/2009JTECHA1256.1 """ J_o = 0 lambda_o = coeff / (rmsVr * rmsVr) for i in range(len(vrs)): v_ar = (np.cos(els[i])*np.sin(azs[i])*u + np.cos(els[i])*np.cos(azs[i])*v + np.sin(els[i])*(w - np.abs(wts[i]))) the_weight = weights[i] the_weight[els[i].mask] = 0 the_weight[azs[i].mask] = 0 the_weight[vrs[i].mask] = 0 the_weight[wts[i].mask] = 0 J_o += lambda_o*np.sum(np.square(vrs[i] - v_ar)*the_weight) return J_o
[docs]def calculate_grad_radial_vel(vrs, els, azs, u, v, w, wts, weights, rmsVr, coeff=1.0, upper_bc=True): """ Calculates the gradient of the cost function due to difference of wind field from radar radial velocities. All arrays in the given lists must have the same dimensions and represent the same spatial coordinates. Parameters ---------- vrs: List of float arrays List of radial velocities from each radar els: List of float arrays List of elevations from each radar azs: List of azimuths List of azimuths from each radar u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field coeff: float Constant for cost function dudt: float Background storm motion dvdt: float Background storm motion vel_name: str Background velocity field name weights: n_radars x_bins x y_bins float array Data weights for each pair of radars Returns ------- y: 1-D float array Gradient vector of observational cost function More information ---------------- The gradient is calculated by taking the functional derivative of the cost function. For more information on functional derivatives, see the Euler-Lagrange Equation: https://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation """ # Use zero for all masked values since we don't want to add them into # the cost function p_x1 = np.zeros(vrs[0].shape) p_y1 = np.zeros(vrs[0].shape) p_z1 = np.zeros(vrs[0].shape) lambda_o = coeff / (rmsVr * rmsVr) for i in range(len(vrs)): v_ar = (np.cos(els[i])*np.sin(azs[i])*u + np.cos(els[i])*np.cos(azs[i])*v + np.sin(els[i])*(w - np.abs(wts[i]))) x_grad = (2*(v_ar - vrs[i]) * np.cos(els[i]) * np.sin(azs[i]) * weights[i]) * lambda_o y_grad = (2*(v_ar - vrs[i]) * np.cos(els[i]) * np.cos(azs[i]) * weights[i]) * lambda_o z_grad = (2*(v_ar - vrs[i]) * np.sin(els[i]) * weights[i]) * lambda_o x_grad[els[i].mask] = 0 y_grad[els[i].mask] = 0 z_grad[els[i].mask] = 0 x_grad[azs[i].mask] = 0 y_grad[azs[i].mask] = 0 z_grad[azs[i].mask] = 0 x_grad[els[i].mask] = 0 x_grad[azs[i].mask] = 0 x_grad[vrs[i].mask] = 0 x_grad[wts[i].mask] = 0 y_grad[els[i].mask] = 0 y_grad[azs[i].mask] = 0 y_grad[vrs[i].mask] = 0 y_grad[wts[i].mask] = 0 z_grad[els[i].mask] = 0 z_grad[azs[i].mask] = 0 z_grad[vrs[i].mask] = 0 z_grad[wts[i].mask] = 0 p_x1 += x_grad p_y1 += y_grad p_z1 += z_grad # Impermeability condition p_z1[0, :, :] = 0 if(upper_bc is True): p_z1[-1, :, :] = 0 y = np.stack((p_x1, p_y1, p_z1), axis=0) return y.flatten()
[docs]def calculate_smoothness_cost(u, v, w, Cx=1e-5, Cy=1e-5, Cz=1e-5): """ Calculates the smoothness cost function by taking the Laplacian of the wind field. All arrays in the given lists must have the same dimensions and represent the same spatial coordinates. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field Cx: float Constant controlling smoothness in x-direction Cy: float Constant controlling smoothness in y-direction Cz: float Constant controlling smoothness in z-direction Returns ------- Js: float value of smoothness cost function """ du = np.zeros(w.shape) dv = np.zeros(w.shape) dw = np.zeros(w.shape) scipy.ndimage.filters.laplace(u, du, mode='wrap') scipy.ndimage.filters.laplace(v, dv, mode='wrap') scipy.ndimage.filters.laplace(w, dw, mode='wrap') return np.sum(Cx*du**2 + Cy*dv**2 + Cz*dw**2)
[docs]def calculate_smoothness_gradient(u, v, w, Cx=1e-5, Cy=1e-5, Cz=1e-5, upper_bc=True): """ Calculates the gradient of the smoothness cost function by taking the Laplacian of the Laplacian of the wind field. All arrays in the given lists must have the same dimensions and represent the same spatial coordinates. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field Cx: float Constant controlling smoothness in x-direction Cy: float Constant controlling smoothness in y-direction Cz: float Constant controlling smoothness in z-direction Returns ------- y: float array value of gradient of smoothness cost function """ du = np.zeros(w.shape) dv = np.zeros(w.shape) dw = np.zeros(w.shape) grad_u = np.zeros(w.shape) grad_v = np.zeros(w.shape) grad_w = np.zeros(w.shape) scipy.ndimage.filters.laplace(u, du, mode='wrap') scipy.ndimage.filters.laplace(v, dv, mode='wrap') scipy.ndimage.filters.laplace(w, dw, mode='wrap') scipy.ndimage.filters.laplace(du, grad_u, mode='wrap') scipy.ndimage.filters.laplace(dv, grad_v, mode='wrap') scipy.ndimage.filters.laplace(dw, grad_w, mode='wrap') # Impermeability condition grad_w[0, :, :] = 0 if(upper_bc is True): grad_w[-1, :, :] = 0 y = np.stack([grad_u*Cx*2, grad_v*Cy*2, grad_w*Cz*2], axis=0) return y.flatten()
[docs]def calculate_mass_continuity(u, v, w, z, dx, dy, dz, coeff=1500.0, anel=1): """ Calculates the mass continuity cost function by taking the divergence of the wind field. All arrays in the given lists must have the same dimensions and represent the same spatial coordinates. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field dx: float Grid spacing in x direction. dy: float Grid spacing in y direction. dz: float Grid spacing in z direction. z: Float array (1D) 1D Float array with heights of grid coeff: float Constant controlling contribution of mass continuity to cost function anel: int = 1 use anelastic approximation, 0=don't Returns ------- J: float value of mass continuity cost function """ dudx = np.gradient(u, dx, axis=2) dvdy = np.gradient(v, dy, axis=1) dwdz = np.gradient(w, dz, axis=0) if(anel == 1): rho = np.exp(-z/10000.0) drho_dz = np.gradient(rho, dz, axis=0) anel_term = w/rho*drho_dz else: anel_term = np.zeros(w.shape) return coeff*np.sum(np.square(dudx + dvdy + dwdz + anel_term))/2.0
[docs]def calculate_mass_continuity_gradient(u, v, w, z, dx, dy, dz, coeff=1500.0, anel=1, upper_bc=True): """ Calculates the gradient of mass continuity cost function. This is done by taking the negative gradient of the divergence of the wind field. All grids must have the same grid specification. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field z: Float array (1D) 1D Float array with heights of grid dx: float Grid spacing in x direction. dy: float Grid spacing in y direction. dz: float Grid spacing in z direction. coeff: float Constant controlling contribution of mass continuity to cost function anel: int = 1 use anelastic approximation, 0=don't Returns ------- y: float array value of gradient of mass continuity cost function """ dudx = np.gradient(u, dx, axis=2) dvdy = np.gradient(v, dy, axis=1) dwdz = np.gradient(w, dz, axis=0) if(anel == 1): rho = np.exp(-z/10000.0) drho_dz = np.gradient(rho, dz, axis=0) anel_term = w/rho*drho_dz else: anel_term = 0 div2 = dudx + dvdy + dwdz + anel_term grad_u = -np.gradient(div2, dx, axis=2)*coeff grad_v = -np.gradient(div2, dy, axis=1)*coeff grad_w = -np.gradient(div2, dz, axis=0)*coeff # Impermeability condition grad_w[0, :, :] = 0 if(upper_bc is True): grad_w[-1, :, :] = 0 y = np.stack([grad_u, grad_v, grad_w], axis=0) return y.flatten()
[docs]def calculate_fall_speed(grid, refl_field=None, frz=4500.0): """ Estimates fall speed based on reflectivity. Uses methodology of Mike Biggerstaff and Dan Betten Parameters ---------- Grid: Py-ART Grid Py-ART Grid containing reflectivity to calculate fall speed from refl_field: str String containing name of reflectivity field. None will automatically determine the name. frz: float Height of freezing level in m Returns ------- 3D float array: Float array of terminal velocities """ # Parse names of velocity field if refl_field is None: refl_field = pyart.config.get_field_name('reflectivity') refl = grid.fields[refl_field]['data'] grid_z = grid.point_z['data'] term_vel = np.zeros(refl.shape) A = np.zeros(refl.shape) B = np.zeros(refl.shape) rho = np.exp(-grid_z/10000.0) A[np.logical_and(grid_z < frz, refl < 55)] = -2.6 B[np.logical_and(grid_z < frz, refl < 55)] = 0.0107 A[np.logical_and(grid_z < frz, np.logical_and(refl >= 55, refl < 60))] = -2.5 B[np.logical_and(grid_z < frz, np.logical_and(refl >= 55, refl < 60))] = 0.013 A[np.logical_and(grid_z < frz, refl > 60)] = -3.95 B[np.logical_and(grid_z < frz, refl > 60)] = 0.0148 A[np.logical_and(grid_z >= frz, refl < 33)] = -0.817 B[np.logical_and(grid_z >= frz, refl < 33)] = 0.0063 A[np.logical_and(grid_z >= frz, np.logical_and(refl >= 33, refl < 49))] = -2.5 B[np.logical_and(grid_z >= frz, np.logical_and(refl >= 33, refl < 49))] = 0.013 A[np.logical_and(grid_z >= frz, refl > 49)] = -3.95 B[np.logical_and(grid_z >= frz, refl > 49)] = 0.0148 fallspeed = A*np.power(10, refl*B)*np.power(1.2/rho, 0.4) del A, B, rho return fallspeed
[docs]def calculate_background_cost(u, v, w, weights, u_back, v_back, Cb=0.01): """ Calculates the background cost function. The background cost function is simply the sum of the squared differences between the wind field and the background wind field multiplied by the weighting coefficient. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field weights: Float array Weights for each point to consider into cost function u_back: 1D float array Zonal winds vs height from sounding w_back: 1D float array Meridional winds vs height from sounding Cb: float Weight of background constraint to total cost function Returns ------- cost: float value of background cost function """ the_shape = u.shape cost = 0 for i in range(the_shape[0]): cost += (Cb*np.sum(np.square(u[i]-u_back[i])*(weights[i]) + np.square(v[i]-v_back[i])*(weights[i]))) return cost
[docs]def calculate_background_gradient(u, v, w, weights, u_back, v_back, Cb=0.01): """ Calculates the gradient of the background cost function. For each u, v this is given as 2*coefficent*(analysis wind - background wind). Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field weights: Float array Weights for each point to consider into cost function u_back: 1D float array Zonal winds vs height from sounding w_back: 1D float array Meridional winds vs height from sounding Cb: float Weight of background constraint to total cost function Returns ------- y: float array value of gradient of background cost function """ the_shape = u.shape u_grad = np.zeros(the_shape) v_grad = np.zeros(the_shape) w_grad = np.zeros(the_shape) for i in range(the_shape[0]): u_grad[i] = Cb*2*(u[i]-u_back[i])*(weights[i]) v_grad[i] = Cb*2*(v[i]-v_back[i])*(weights[i]) y = np.stack([u_grad, v_grad, w_grad], axis=0) return y.flatten()
[docs]def calculate_vertical_vorticity_cost(u, v, w, dx, dy, dz, Ut, Vt, coeff=1e-5): """ Calculates the cost function due to deviance from vertical vorticity equation. For more information of the vertical vorticity cost function, see Potvin et al. (2012) and Shapiro et al. (2009). Parameters ---------- u: 3D array Float array with u component of wind field v: 3D array Float array with v component of wind field w: 3D array Float array with w component of wind field dx: float array Spacing in x grid dy: float array Spacing in y grid dz: float array Spacing in z grid coeff: float Weighting coefficient Ut: float U component of storm motion Vt: float V component of storm motion Returns ------- Jv: float Value of vertical vorticity cost function. References ---------- Potvin, C.K., A. Shapiro, and M. Xue, 2012: Impact of a Vertical Vorticity Constraint in Variational Dual-Doppler Wind Analysis: Tests with Real and Simulated Supercell Data. J. Atmos. Oceanic Technol., 29, 32–49, https://doi.org/10.1175/JTECH-D-11-00019.1 Shapiro, A., C.K. Potvin, and J. Gao, 2009: Use of a Vertical Vorticity Equation in Variational Dual-Doppler Wind Analysis. J. Atmos. Oceanic Technol., 26, 2089–2106, https://doi.org/10.1175/2009JTECHA1256.1 """ dvdz = np.gradient(v, dz, axis=0) dudz = np.gradient(u, dz, axis=0) dwdz = np.gradient(w, dx, axis=2) dvdx = np.gradient(v, dx, axis=2) dwdy = np.gradient(w, dy, axis=1) dwdx = np.gradient(w, dx, axis=2) dudx = np.gradient(u, dx, axis=2) dvdy = np.gradient(v, dy, axis=2) dudy = np.gradient(u, dy, axis=1) zeta = dvdx - dudy dzeta_dx = np.gradient(zeta, dx, axis=2) dzeta_dy = np.gradient(zeta, dy, axis=1) dzeta_dz = np.gradient(zeta, dz, axis=0) jv_array = ((u - Ut) * dzeta_dx + (v - Vt) * dzeta_dy + w * dzeta_dz + (dvdz * dwdx - dudz * dwdy) + zeta * (dudx + dvdy)) return np.sum(coeff*jv_array**2)
[docs]def calculate_vertical_vorticity_gradient(u, v, w, dx, dy, dz, Ut, Vt, coeff=1e-5): """ Calculates the gradient of the cost function due to deviance from vertical vorticity equation. This is done by taking the functional deriviative of the vertical vorticity cost function. Parameters ---------- u: 3D array Float array with u component of wind field v: 3D array Float array with v component of wind field w: 3D array Float array with w component of wind field dx: float array Spacing in x grid dy: float array Spacing in y grid dz: float array Spacing in z grid Ut: float U component of storm motion Vt: float V component of storm motion coeff: float Weighting coefficient Returns ------- Jv: 1D float array Value of the gradient of the vertical vorticity cost function. References ---------- Potvin, C.K., A. Shapiro, and M. Xue, 2012: Impact of a Vertical Vorticity Constraint in Variational Dual-Doppler Wind Analysis: Tests with Real and Simulated Supercell Data. J. Atmos. Oceanic Technol., 29, 32–49, https://doi.org/10.1175/JTECH-D-11-00019.1 Shapiro, A., C.K. Potvin, and J. Gao, 2009: Use of a Vertical Vorticity Equation in Variational Dual-Doppler Wind Analysis. J. Atmos. Oceanic Technol., 26, 2089–2106, https://doi.org/10.1175/2009JTECHA1256.1 """ # First derivatives dvdz = np.gradient(v, dz, axis=0) dudz = np.gradient(u, dz, axis=0) dwdy = np.gradient(w, dy, axis=1) dudx = np.gradient(u, dx, axis=2) dvdy = np.gradient(v, dy, axis=2) dwdx = np.gradient(w, dx, axis=2) dvdx = np.gradient(v, dx, axis=2) dwdx = np.gradient(w, dx, axis=2) dudz = np.gradient(u, dz, axis=0) dudy = np.gradient(u, dy, axis=1) zeta = dvdx - dudy dzeta_dx = np.gradient(zeta, dx, axis=2) dzeta_dy = np.gradient(zeta, dy, axis=1) dzeta_dz = np.gradient(zeta, dz, axis=0) # Second deriviatives dwdydz = np.gradient(dwdy, dz, axis=0) dwdxdz = np.gradient(dwdx, dz, axis=0) dudzdy = np.gradient(dudz, dy, axis=1) dvdxdy = np.gradient(dvdx, dy, axis=1) dudx2 = np.gradient(dudx, dx, axis=2) dudxdy = np.gradient(dudx, dy, axis=1) dudxdz = np.gradient(dudx, dz, axis=0) dudy2 = np.gradient(dudx, dy, axis=1) dzeta_dt = ((u - Ut)*dzeta_dx + (v - Vt)*dzeta_dy + w*dzeta_dz + (dvdz*dwdx - dudz*dwdy) + zeta*(dudx + dvdy)) # Now we intialize our gradient value u_grad = np.zeros(u.shape) v_grad = np.zeros(v.shape) w_grad = np.zeros(w.shape) # Vorticity Advection u_grad += dzeta_dx + (Ut - u)*dudxdy + (Vt - v)*dudxdy v_grad += dzeta_dy + (Vt - v)*dvdxdy + (Ut - u)*dvdxdy w_grad += dzeta_dz # Tilting term u_grad += dwdydz v_grad += dwdxdz w_grad += dudzdy - dudxdz # Stretching term u_grad += -dudxdy + dudy2 - dzeta_dx u_grad += -dudx2 + dudxdy - dzeta_dy # Multiply by 2*dzeta_dt according to chain rule u_grad = u_grad*2*dzeta_dt*coeff v_grad = v_grad*2*dzeta_dt*coeff w_grad = w_grad*2*dzeta_dt*coeff y = np.stack([u_grad, v_grad, w_grad], axis=0) return y.flatten()
[docs]def calculate_model_cost(u, v, w, weights, u_model, v_model, w_model, coeff=1.0): """ Calculates the cost function for the model constraint. This is calculated simply as the sum of squares of the differences between the model wind field and the analysis wind field. Vertical velocities are not factored into this cost function as there is typically a high amount of uncertainty in model derived vertical velocities. Parameters ---------- u: 3D array Float array with u component of wind field v: 3D array Float array with v component of wind field w: 3D array Float array with w component of wind field weights: list of 3D arrays Float array showing how much each point from model weighs into constraint. u_model: list of 3D arrays Float array with u component of wind field from model v_model: list of 3D arrays Float array with v component of wind field from model w_model: list of 3D arrays Float array with w component of wind field from model coeff: float Weighting coefficient Returns ------- Jv: float Value of model cost function """ cost = 0 for i in range(len(u_model)): cost += (coeff*np.sum(np.square(u-u_model[i])*weights[i] + np.square(v-v_model[i])*weights[i])) return cost
[docs]def calculate_model_gradient(u, v, w, weights, u_model, v_model, w_model, coeff=1.0): """ Calculates the cost function for the model constraint. This is calculated simply as twice the differences between the model wind field and the analysis wind field for each u, v. Vertical velocities are not factored into this cost function as there is typically a high amount of uncertainty in model derived vertical velocities. Therefore, the gradient for all of the w's will be 0. Parameters ---------- u: Float array Float array with u component of wind field v: Float array Float array with v component of wind field w: Float array Float array with w component of wind field weights: list of 3D float arrays Weights for each point to consider into cost function u_model: list of 3D float arrays Zonal wind field from model v_model: list of 3D float arrays Meridional wind field from model w_model: list of 3D float arrays Vetical wind field from model coeff: float Weight of background constraint to total cost function Returns ------- y: float array value of gradient of background cost function """ the_shape = u.shape u_grad = np.zeros(the_shape) v_grad = np.zeros(the_shape) w_grad = np.zeros(the_shape) for i in range(len(u_model)): u_grad += coeff*2*(u-u_model[i])*weights[i] v_grad += coeff*2*(v-v_model[i])*weights[i] y = np.stack([u_grad, v_grad, w_grad], axis=0) return y.flatten()