# -*- coding: utf-8 -*- """ Functions for calculating/estimating drop size distributions from radar data. Contacts -------- Brenda Dolan (dolan@atmos.colostate.edu) Timothy Lang (tjlangco@gmail.com) References ---------- Bringi et al. (2004; JTECH) - Alternate S-band retrieval Bringi et al. (2009; JTECH) - C-band retrieval Bringi et al. (2013; AMS Radar Conf) - S-band retrieval """ from __future__ import absolute_import from __future__ import division import numpy as np from warnings import warn from .csu_liquid_ice_mass import linearize from .common import _check_for_array DEFAULT_MU = 3.0 def calc_dsd(dz=None, zdr=None, kdp=None, band='S', method='2013'): """This is the primary function to use, it calls everything else""" # Initialize, check for all vars, check for scalars if dz is None or kdp is None or zdr is None: warnings.warn('No dz, zdr, or kdp provided, failing ...') return dz, zdr, kdp, len_flag = _check_for_array(dz, zdr, kdp) # Get DSD based on wavelength if band == 'S': if method == '2013': d0, Nw, mu = calc_dsd_sband_bringi_2013(dz, zdr) else: d0, Nw, mu = calc_dsd_sband_bringi_2004(dz, zdr, kdp) elif band == 'C': d0, Nw, mu = calc_dsd_cband_bringi_2009(dz, zdr) else: warn('Unknown or unsupported wavelength band, try C or S') return if not len_flag: return d0[0], Nw[0], mu[0] else: return d0, Nw, mu def power_law(var, a=1.0, b=1.0): """Generic power law equation""" return a * var**b ###################################################### # Bringi et al. 2009 retrievals # Could make the following a class, but prefer to keep # easy independent access to sub-functions ###################################################### def calc_dsd_cband_bringi_2009(dz, zdr): """ Retrieves d0, Nw, and mu following the methodology of Bringi et al. (2009) Works for C-band """ d0 = 0.0 * dz Nw = 0.0 * dz dz_lin = linearize(dz) meth1 = np.logical_and(zdr >= -0.5, zdr <= 1.25) d0[meth1] = d0_low_zdr(zdr[meth1]) meth2 = zdr > 1.25 d0[meth2] = d0_high_zdr(zdr[meth2]) Nw = dz_lin / power_law(d0, 0.056, 7.319) mu = 0.0 * dz + DEFAULT_MU return d0, Nw, mu def d0_low_zdr(zdr, a=0.0203, b=-0.1488, c=0.2209, d=0.5571, e=0.801): return power_law(zdr, a, 4) + power_law(zdr, b, 3) + \ power_law(zdr, c, 2) + power_law(zdr, d) + e def d0_high_zdr(zdr, a=0.0355, b=-0.3021, c=1.0556, d=0.6844): return power_law(zdr, a, 3) + power_law(zdr, b, 2) + power_law(zdr, c) + d ###################################################### # Bringi et al. 2013 retrievals # Leverages Bringi et al. (2009) function design ###################################################### def calc_dsd_sband_bringi_2013(dz, zdr): """ Retrieves d0, Nw, and mu following the methodology of Bringi et al. (2013) Works for S-band """ d0 = 0.0 * dz Nw = 0.0 * dz dz_lin = linearize(dz) meth1 = zdr < 1 d0[meth1] = d0_low_zdr(zdr[meth1], a=0.0424, b=-0.4571, c=0.6125, d=0.457, e=0.8808) meth2 = zdr >= 1 d0[meth2] = d0_high_zdr(zdr[meth2], a=0.0536, b=-0.1971, c=0.6261, d=1.0815) Nw = 19.76 * dz_lin / power_law(d0, b=7.46) mu = 0.0 * dz + DEFAULT_MU return d0, Nw, mu ###################################################### # Bringi et al. 2004 retrievals # Could make the following a class, but prefer to keep # easy independent access to sub-functions ###################################################### def calc_dsd_sband_bringi_2004(dz, zdr, kdp): """ Retrieves d0, Nw, and mu following the methodology of Bringi et al. (2004) Works for S-band """ d0 = 0.0 * dz Nw = 0.0 * dz mu = 0.0 * dz zeta = linearize(zdr) dz_lin = linearize(dz) beta = calc_beta(dz_lin, kdp, zeta) # Break down DSD calculations by methods meth1a = np.logical_and(dz >= 35, zdr >= 0.2) meth1 = np.logical_and(meth1a, kdp >= 0.3) d0[meth1], Nw[meth1], mu[meth1] = dsd_sband_method1( dz_lin[meth1], kdp[meth1], zeta[meth1], beta[meth1]) meth2 = np.logical_and(kdp < 0.3, zdr >= 0.5) d0[meth2], Nw[meth2], mu[meth2] = dsd_sband_method2( dz_lin[meth2], kdp[meth2], zdr[meth2]) meth3a = np.logical_and(zdr >= 0.2, zdr < 0.5) meth3 = np.logical_and(meth3a, kdp < 0.3) d0[meth3], Nw[meth3], mu[meth3] = dsd_sband_method3( dz_lin[meth3], kdp[meth3], zdr[meth3], zeta[meth3]) meth4a = np.logical_and(zdr >= -0.5, zdr < 0.2) meth4 = np.logical_and(meth4a, kdp < 0.3) d0[meth4], Nw[meth4], mu[meth4] = dsd_sband_method4(dz_lin[meth4], zeta[meth4]) return d0, Nw, mu def calc_beta(dz, kdp, zeta, a=2.08, b=-0.365, c=0.38, d=0.965): """Bringi et al. (2004) Eq. A.1""" return a * (dz**b) * (kdp**c) * (zeta**d) def calc_d0_sband_method1(dz, zeta, beta, a=0.56, b=0.064, c=0.024, d=-1.42): """Bringi et al. (2004) Eqs. A.2-A.5 """ c1 = power_law(beta, c, d) return d0_from_dz_zeta(dz, zeta, a=a, b=b, c=c1) def calc_logNw_sband_method1(dz, zeta, beta, a=3.29, b=0.058, c=-0.023, d=-1.389): """Bringi et al. (2004) Eqs. A.6-A.9 """ return a * (dz**b) * (zeta**(power_law(beta, c, d))) def calc_mu_sband_method1(d0, zeta, beta, a1=203.0, a2=1.89, b1=2.23, b2=0.0388, c1=3.16, c2=-0.0463, d1=0.374, d2=-0.355): """Bringi et al. (2004) Eqs. A.10-A.14 """ a = power_law(beta, a1, a2) b = power_law(beta, b1, b2) c = power_law(beta, c1, c2) d = power_law(beta, d1, d2) return a * ((d0**b) / (zeta-1.0)) - power_law(zeta, c, d) def calc_d0_sband_method3(dz, zdr, zeta, a=1.81, b=0.486, c=0.6096, d=0.0516, e=3.111): """Bringi et al. (2004) Eq. A.18""" part1 = ((zdr-0.2)/3.0) * power_law(zdr, a, b) part2 = ((0.5-zdr)/3.0) * d0_from_dz_zeta(dz, zeta) return part1 + part2 def calc_Nw_mult_methods(dz, d0): """Bringi et al. (2004) Eqs. A.17, A.19, A.21 """ return 21.0 * dz / power_law(d0, b=7.3529) def d0_from_dz_zeta(dz, zeta, a=0.6096, b=0.0516, c=3.111): """Bringi et al. (2004) Eq. A.20""" return a * dz**b * zeta**c def dsd_sband_method1(dz, kdp, zeta, beta): """Bringi et al. (2004) Eqs. A.1-A.14 """ d0 = calc_d0_sband_method1(dz, zeta, beta) logNw = calc_logNw_sband_method1(dz, zeta, beta) mu = calc_mu_sband_method1(d0, zeta, beta) return d0, 10.0**logNw, mu def dsd_sband_method2(dz, kdp, zdr): """Bringi et al. (2004) Eqs. A.15-A.17 """ d0 = power_law(zdr, 1.81, 0.486) Nw = calc_Nw_mult_methods(dz, d0) mu = 0.0 * dz + DEFAULT_MU return d0, Nw, mu def dsd_sband_method3(dz, kdp, zdr, zeta): """Bringi et al. (2004) Eqs. A.18-A.19 """ d0 = calc_d0_sband_method3(dz, zdr, zeta) Nw = calc_Nw_mult_methods(dz, d0) mu = 0.0 * dz + DEFAULT_MU return d0, Nw, mu def dsd_sband_method4(dz, zeta): """Bringi et al. (2004) Eqs. A.20-A.21 """ d0 = d0_from_dz_zeta(dz, zeta) Nw = calc_Nw_mult_methods(dz, d0) mu = 0.0 * dz + DEFAULT_MU return d0, Nw, mu ######################################################