def depolarization(zdr, rho): """Compute the depolarization ration. Compute the depolarization ration using differential reflectivity :math:`Z_{DR}` and crosscorrelation coefficient :math:`Rho_{HV}` of a radar sweep (:cite:`Kilambi2018`, :cite:`Melnikov2013`, :cite:`Ryzhkov2017`). Parameters ---------- zdr : float or :class:`numpy:numpy.ndarray` differential reflectivity rho : float or :class:`numpy:numpy.ndarray` crosscorrelation coefficient Returns ------ depolarization : :class:`numpy:numpy.ndarray` array of depolarization ratios with the same shape as input data, numpy broadcasting rules apply """ zdr = trafo.idecibel(np.asanyarray(zdr)) m = 2 * np.asanyarray(rho) * zdr**0.5 return trafo.decibel((1 + zdr - m) / (1 + zdr + m))
def _z_to_r_enhanced_mdfilt(z, mode='mirror'): """multidimensional version assuming the two last dimensions represent a 2-D image Uses :func:`scipy:scipy.ndimage.filters.generic_filter` to reduce the number of for-loops even more. """ # get the shape of the input # dimy = z.shape[-2] # dimx = z.shape[-1] # calculate the decibel values from the input db = trafo.decibel(z) # set up our output arrays r = np.zeros(z.shape) size = list(z.shape) size[-2:] = [3, 3] size[:-2] = [1] * len(size[:-2]) size = tuple(size) si = filters.generic_filter(db, z_to_r_esifilter, size=size, mode=mode) gt44 = db > 44. r[gt44] = z_to_r(z[gt44], a=77, b=1.9) si[gt44] = -1. # the same is true for values between 36.5 and 44 dBZ bt3644 = (db >= 36.5) & (db <= 44.) r[bt3644] = z_to_r(z[bt3644], a=200, b=1.6) si[bt3644] = -2. si1 = (si >= 0.) si2 = si1 & (si < 3.5) si3 = si1 & ~si2 & (si <= 7.5) si4 = si > 7.5 r[si2] = z_to_r(z[si2], a=125, b=1.4) r[si3] = z_to_r(z[si3], a=200, b=1.6) r[si4] = z_to_r(z[si4], a=320, b=1.4) return r, si
def z_to_r_enhanced(z, polar=True, shower=True): """Calculates rainrates from radar reflectivities using the enhanced \ three-part Z-R-relationship used by the DWD (as of 2009) To be used with polar representations so that one dimension is cyclical. i.e. z should be of shape (nazimuths, nbins) --> the first dimension is the cyclical one. For DWD DX-Data z's shape is (360,128). Neighborhood-means are taken only for available data via fast convolution sums. Refer to the RADOLAN final report or the RADOLAN System handbook for details on the calculations. Basically, for low reflectivities an index called the shower index is calculated as the mean of the differences along both axis in a neighborhood of 3x3 pixels. This means: +------+-----------------+ | | x-direction --> | +------+-----+-----+-----+ | | y | 1 | 2 | 3 | | | l +-----+-----+-----+ | | d | 4 | 5 | 6 | | | i +-----+-----+-----+ | | r | 7 | 8 | 9 | +------+-----+-----+-----+ If 5 is the pixel in question, it's shower index is calculated as: .. math:: ( &|1-2| + |2-3| + |4-5| + |5-6| + |7-8| + |8-9| + \\\\ &|1-4| + |4-7| + |2-5| + |5-8| + |3-6| + |6-9| ) / 12. then, the upper line of the sum would be diffx (DIFFerences in X-direction), the lower line would be diffy (DIFFerences in Y-direction) in the code below. Parameters ---------- z : :class:`numpy:numpy.ndarray` Corresponds to reflectivity Z in mm**6/m**3 ND-array, at least 2D polar : bool defaults to to True (polar data), False for cartesian data. shower : bool output shower index, defaults to True Returns ------- r : :class:`numpy:numpy.ndarray` r - array of shape z.shape - calculated rain rates si : :class:`numpy:numpy.ndarray` si - array of shape z.shape - calculated shower index for control purposes. May be omitted in later versions """ z = np.asanyarray(z, dtype=np.float64) shape = z.shape z = z.reshape((-1,) + shape[-2:]) if polar: z0 = np.concatenate([z[:, -1:, :], z, z[:, 0:1, :]], axis=-2) x_ymin, x_ymax = 2, -2 y_ymin, y_ymax = 1, -1 x_xmin, x_xmax = None, None y_xmin, y_xmax = 1, -1 else: z0 = z.copy() x_ymin, x_ymax = 1, -1 y_ymin, y_ymax = None, None x_xmin, x_xmax = None, None y_xmin, y_xmax = 1, -1 z0 = trafo.decibel(z0) # create shower index using differences and convolution sum diffx = np.abs(np.diff(z0, n=1, axis=-1)) diffy = np.abs(np.diff(z0, n=1, axis=-2)) xkernel = np.ones((1, 3, 2)) ykernel = np.ones((1, 2, 3)) resx = signal.convolve(diffx, xkernel, mode="full", method="direct")[ :, x_ymin:x_ymax, x_xmin:x_xmax ] resy = signal.convolve(diffy, ykernel, mode="full", method="direct")[ :, y_ymin:y_ymax, y_xmin:y_xmax ] si = resx + resy # edge cases divide by 7, everything else divide by 12 if polar: si[:, :, 0] /= 7.0 si[:, :, -1] /= 7.0 si[:, :, 1:-1] /= 12.0 else: si[:, 1:-1, 1:-1] /= 12.0 si[:, :, 0] /= 7 si[:, :, -1] /= 7.0 si[:, 0, :] /= 7 si[:, -1, :] /= 7.0 rr = np.zeros(z.shape) z0_ = z0[:, y_ymin:y_ymax, :] # get masks gt44 = z0_ > 44 bt3644 = (z0_ >= 36.5) & (z0_ <= 44.0) si[bt3644] = -1.0 si[gt44] = -1.0 mn75h = (si > 7.5) & (si < 36.5) mn35 = (si > -1) & (si < 3.5) mn75l = (si >= 3.5) & (si <= 7.5) # calculate rainrates according DWD rr[mn75l] = z_to_r(z[mn75l], a=200.0, b=1.6) rr[mn75h] = z_to_r(z[mn75h], a=320.0, b=1.4) rr[mn35] = z_to_r(z[mn35], a=125.0, b=1.4) rr[gt44] = z_to_r(z[gt44], a=77.0, b=1.9) rr[bt3644] = z_to_r(z[bt3644], a=200.0, b=1.6) rr.shape = shape si.shape = shape if shower: return rr, si else: return rr
ranges = r polargrid = np.meshgrid(ranges, azimuths) lon, lat, alt = wradlib.georef.polar2lonlatalt_n(polargrid[0], polargrid[1], elevation, radar_location) gk3 = wradlib.georef.epsg_to_osr(31467) x, y = wradlib.georef.reproject(lon, lat, projection_target=gk3) xgrid, ygrid = wradlib.georef.reproject(dpr_lon[latstart:latend], dpr_lat[latstart:latend], projection_target=gk3) grid_xy = np.vstack((xgrid.ravel(), ygrid.ravel())).transpose() xy=np.concatenate([x.ravel()[:,None],y.ravel()[:,None]], axis=1) gridded = wradlib.comp.togrid(xy, grid_xy, ranges[-1], np.array([x.mean(), y.mean()]), R.ravel(), ipoli[0],nnearest=40,p=2) gridded = np.ma.masked_invalid(gridded).reshape(xgrid.shape) gridded = decibel(gridded) R = decibel(R) # ON RADOLAN GRID proj_stereo = wrl.georef.create_osr("dwd-radolan") proj_wgs = osr.SpatialReference() proj_wgs.ImportFromEPSG(4326) box_x, box_y = wradlib.georef.reproject(lon, lat, projection_target=proj_stereo , projection_source=proj_wgs) gpm_x, gpm_y = wradlib.georef.reproject(dpr_lon[latstart:latend], dpr_lat[latstart:latend], projection_target=proj_stereo , projection_source=proj_wgs) #Todo IM PLOT VERWENDEN !!!!!!! # Plot # ----
############################################## INTERLOLATION RX #mask2 = ~np.isnan(rwdata2) result2 = wrl.ipol.interpolate(xy, grid_gpm_xy, rwdata2.reshape(900 * 900, 1), wrl.ipol.Idw, nnearest=8) result2 = np.ma.masked_invalid(result2) rrr2 = result2.reshape(gpm_x.shape) rrr2 = decibel(rrr2) rwdata2 = decibel(rwdata2) ## Interpolation of the binary Grid res_bin = wrl.ipol.interpolate(xy, grid_gpm_xy, rn.reshape(900 * 900, 1), wrl.ipol.Idw, nnearest=25) res_bin = res_bin.reshape(gpm_x.shape) res_bin[res_bin != 0] = 1 # Randkorrektur rand_y_unten = -4658.6447242655722 rand_y_oben = -3759.6447242655722
xy = np.vstack((x.ravel(), y.ravel())).transpose() mask = ~np.isnan(rwdata) result = wrl.ipol.interpolate(xy, grid_gpm_xy, rwdata.reshape(900 * 900, 1), wrl.ipol.Idw, nnearest=4) result = np.ma.masked_invalid(result) rrr = result.reshape(gpm_x.shape) rrr = decibel(rrr) rwdata = decibel(rwdata) ## Interpolation of the binary Grid ## ------------------------------ res_bin = wrl.ipol.interpolate(xy, grid_gpm_xy, rn.reshape(900 * 900, 1), wrl.ipol.Idw, nnearest=4) res_bin = res_bin.reshape(gpm_x.shape) res_bin[res_bin != 0] = 1 # Randkorrektur rand_y_unten = -4658.6447242655722
def test_decibel(self): self.assertTrue(np.allclose(trafo.decibel(self.lin), self.dec))
grid_xy = np.vstack((dpr_lon.ravel(), dpr_lat.ravel())).transpose() xy = np.concatenate([lon.ravel()[:, None], lat.ravel()[:, None]], axis=1) gridded = wradlib.comp.togrid(xy, grid_xy, ranges[-1], np.array([lon.mean(), lat.mean()]), R.ravel(), ipoli[0], nnearest=40, p=2) gridded = np.ma.masked_invalid(gridded).reshape(dpr_lon.shape) gridded[np.where(rr > radius)] = np.nan R = decibel(R) gridded = decibel(gridded) fig = plt.figure(figsize=(14, 12)) fig.suptitle('BoXPol vs DPR ' + ZP + ' Rho_th: ' + str(rho_th)) ################### ax1 = fig.add_subplot(221, aspect='auto') plt.pcolormesh(dpr_lon, dpr_lat, np.ma.masked_invalid(pp), vmin=0, vmax=40, cmap=my_cmap()) plt.colorbar()
gk3 = wradlib.georef.epsg_to_osr(31467) grid_gpm_xy = np.vstack((gpm_x.ravel(), gpm_y.ravel())).transpose() xy = np.vstack((x.ravel(), y.ravel())).transpose() mask = ~np.isnan(rwdata) result = wrl.ipol.interpolate(xy, grid_gpm_xy, rwdata.reshape(900*900,1), wrl.ipol.Idw, nnearest=4) result = np.ma.masked_invalid(result) rrr = result.reshape(gpm_x.shape) rrr = decibel(rrr) rwdata = decibel(rwdata) ## Interpolation of the binary Grid ## ------------------------------ res_bin = wrl.ipol.interpolate(xy, grid_gpm_xy, rn.reshape(900*900,1), wrl.ipol.Idw, nnearest=4) res_bin = res_bin.reshape(gpm_x.shape) res_bin[res_bin!=0]= 1 # Randkorrektur rand_y_unten = -4658.6447242655722 rand_y_oben = -3759.6447242655722 rand_x_rechts = 375.5378330781441
def test_decibel(self): assert np.allclose(trafo.decibel(self.lin), self.dec)
result = np.ma.masked_invalid(result) rrr = result.reshape(gpm_x.shape) ############################################## INTERLOLATION RX #mask2 = ~np.isnan(rwdata2) result2 = wrl.ipol.interpolate(xy, grid_gpm_xy, rwdata2.reshape(900*900,1), wrl.ipol.Idw, nnearest=8) result2 = np.ma.masked_invalid(result2) rrr2 = result2.reshape(gpm_x.shape) rrr2 = decibel(rrr2) rwdata2 = decibel(rwdata2) ## Interpolation of the binary Grid res_bin = wrl.ipol.interpolate(xy, grid_gpm_xy, rn.reshape(900*900,1), wrl.ipol.Idw, nnearest=25) res_bin = res_bin.reshape(gpm_x.shape) res_bin[res_bin != 0] = 1 # Randkorrektur rand_y_unten = -4658.6447242655722 rand_y_oben = -3759.6447242655722 rand_x_rechts = 375.5378330781441
def _z_to_r_enhanced(z): """Calculates rainrates from radar reflectivities using the enhanced \ three-part Z-R-relationship used by the DWD (as of 2009). This function does the actual calculations without any padding. Neighborhood-means are taken only for available data, reducing the number of elements used near the edges of the array. Refer to the RADOLAN final report or the RADOLAN System handbook for details on the calculations. Basically, for low reflectivities an index called the shower index is calculated as the mean of the differences along both axis in a neighborhood of 3x3 pixels. This means: x-direction --> y | +---+---+---+ | | | 1 | 2 | 3 | d v +---+---+---+ i | 4 | 5 | 6 | r +---+---+---+ e | 7 | 8 | 9 | c +---+---+---+ t i if 5 is the pixel in question, its shower index is calculated as o ( |1-2| + |2-3| + |4-5| + |5-6| + |7-8| + |8-9| + n + |1-4| + |4-7| + |2-5| + |5-8| + |3-6| + |6-9| ) / 12. then, the upper line of the sum would be diffx (DIFFerences in X-direction), the lower line would be diffy (DIFFerences in Y-direction) in the code below. """ # get the shape of the input dimy = z.shape[0] dimx = z.shape[1] # calculate the decibel values from the input db = trafo.decibel(z) # set up our output arrays r = np.zeros(z.shape) si = np.zeros(z.shape) # calculate difference fields in x and y direction # mainly for performance reasons, so that we can use numpy's efficient # array operations and avoid calculating a difference more than once diffx = np.abs(db[:, :-1] - db[:, 1:]) diffy = np.abs(db[:-1, :] - db[1:, :]) # if the reflectivity is larger than 44dBZ, then there is no need to # calculate the shower index gt44 = np.where(db > 44.) r[gt44] = z_to_r(z[gt44], a=77., b=1.9) # the same is true for values between 36.5 and 44 dBZ bt3644 = np.where(np.logical_and(db >= 36.5, db <= 44.)) r[bt3644] = z_to_r(z[bt3644], a=200., b=1.6) # now iterate over the array and look for the remaining values # TODO : this could be a starting point for further optimization, if we # iterated only over the remaining pixels instead of all for i in range(dimy): for j in range(dimx): # if the reflectivity is too high, we coped with it already # so we can skip that one if db[i, j] >= 36.5: # just set the shower index to some impossible value so that # we know that there was no calculation done here si[i, j] = -1 # continue with the next iteration continue else: # calculate the bounds of the region where we have to consider # the respective difference xmin = max(0, j - 1) xmax = min(dimx, j + 1) ymin = max(0, i - 1) ymax = min(dimy, i + 1) # in fact python is quite forgiving with upper indices # ours might go one index too far, so don't try to port this # to another programming language straigt away! diffxcut = diffx[ymin:ymax + 1, xmin:xmax] diffycut = diffy[ymin:ymax, xmin:xmax + 1] # calculate the mean for the current pixel mn = (np.sum(diffxcut) + np.sum(diffycut)) / \ (diffxcut.size + diffycut.size) # apply the three different Z/R relations if mn < 3.5: r[i, j] = z_to_r(z[i, j], a=125., b=1.4) elif mn <= 7.5: r[i, j] = z_to_r(z[i, j], a=200., b=1.6) else: r[i, j] = z_to_r(z[i, j], a=320., b=1.4) # save the shower index si[i, j] = mn # return the results return r, si
def _z_to_r_enhanced_mdcorr(z, xmode='reflect', ymode='wrap'): """multidimensional version assuming the two last dimensions represent a 2-D image Uses :func:`scipy:scipy.ndimage.filters.correlate` to reduce the number of for-loops even more. """ # get the shape of the input # dimy = z.shape[-2] # dimx = z.shape[-1] # calculate the decibel values from the input db = trafo.decibel(z) # calculate the shower differences by 1-d correlation with a differencing # kernel db_diffx = np.abs( filters.correlate1d(db, [1, -1], axis=-1, mode=xmode, origin=-1)) db_diffy = np.abs( filters.correlate1d(db, [1, -1], axis=-2, mode=ymode, origin=-1)) diffxmode = 'wrap' if xmode == 'wrap' else 'constant' diffymode = 'wrap' if ymode == 'wrap' else 'constant' diffx_sum1 = filters.correlate1d(db_diffx, [1, 1, 1], axis=-2, mode=diffymode) diffxsum = filters.correlate1d(diffx_sum1, [1, 1, 0], axis=-1, mode=diffxmode) diffy_sum1 = filters.correlate1d(db_diffy, [1, 1, 1], axis=-1, mode=diffxmode) diffysum = filters.correlate1d(diffy_sum1, [1, 1, 0], axis=-2, mode=diffymode) divider = np.ones(db.shape) * 12. if xmode != 'wrap': divider[..., [0, -1]] = np.rint( (divider[..., [0, -1]] + 1) / 1.618) - 1 if ymode != 'wrap': divider[..., [0, -1], :] = np.rint( (divider[..., [0, -1], :] + 1) / 1.618) - 1 # the shower index is the sum of the x- and y-differences si = (diffxsum + diffysum) / divider # set up our rainfall output array r = np.zeros(z.shape) gt44 = db > 44. r[gt44] = z_to_r(z[gt44], a=77, b=1.9) si[gt44] = -1. # the same is true for values between 36.5 and 44 dBZ bt3644 = (db >= 36.5) & (db <= 44.) r[bt3644] = z_to_r(z[bt3644], a=200, b=1.6) si[bt3644] = -2. si1 = (si >= 0.) si2 = si1 & (si < 3.5) si3 = si1 & ~si2 & (si <= 7.5) si4 = si > 7.5 r[si2] = z_to_r(z[si2], a=125, b=1.4) r[si3] = z_to_r(z[si3], a=200, b=1.6) r[si4] = z_to_r(z[si4], a=320, b=1.4) return r, si