Exemple #1
0
 def test_bin_altitude(self):
     altitude = georef.bin_altitude(np.arange(10., 101., 10.)
                                    * 1000., 2., 0, 6370040.)
     altref = np.array([354.87448647, 721.50702113, 1099.8960815,
                        1490.04009656, 1891.93744678, 2305.58646416,
                        2730.98543223, 3168.13258613, 3617.02611263,
                        4077.66415017])
     np.testing.assert_allclose(altref, altitude)
Exemple #2
0
 def test_bin_altitude(self):
     altitude = georef.bin_altitude(np.arange(10., 101., 10.)
                                    * 1000., 2., 0, 6370040.)
     altref = np.array([354.87448647, 721.50702113, 1099.8960815,
                        1490.04009656, 1891.93744678, 2305.58646416,
                        2730.98543223, 3168.13258613, 3617.02611263,
                        4077.66415017])
     np.testing.assert_allclose(altref, altitude)
Exemple #3
0
 def test_site_distance(self):
     altitude = georef.bin_altitude(np.arange(10., 101., 10.) * 1000., 2.,
                                    0, 6370040.)
     distance = georef.site_distance(np.arange(10., 101., 10.) * 1000., 2.,
                                     altitude, 6370040.)
     distref = np.array([9993.49302358, 19986.13717891, 29977.90491409,
                         39968.76869178, 49958.70098959, 59947.6743006,
                         69935.66113377, 79922.63401441, 89908.5654846,
                         99893.4281037])
     np.testing.assert_allclose(distref, distance)
Exemple #4
0
 def test_site_distance(self):
     altitude = georef.bin_altitude(np.arange(10., 101., 10.) * 1000., 2.,
                                    0, 6370040.)
     distance = georef.site_distance(np.arange(10., 101., 10.) * 1000., 2.,
                                     altitude, 6370040.)
     distref = np.array([9993.49302358, 19986.13717891, 29977.90491409,
                         39968.76869178, 49958.70098959, 59947.6743006,
                         69935.66113377, 79922.63401441, 89908.5654846,
                         99893.4281037])
     np.testing.assert_allclose(distref, distance)
Exemple #5
0
def blindspots(center, gridcoords, minelev, maxelev, maxrange):
    """Masks blind regions of the radar, marked on a 3-D grid

    The radar is blind below the radar, above the radar and beyond the range.
    The function returns three boolean arrays which indicate whether (1) the
    grid node is below the radar, (2) the grid node is above the radar,
    (3) the grid node is beyond the maximum range.

    Parameters
    ---------
    center : tuple
        radar location
    gridcoords : :class:`numpy:numpy.ndarray`
        array of 3-D coordinates with shape (num voxels, 3)
    minelev : float
        The minimum elevation angle of the volume (degree)
    maxelev : float
        The maximum elevation angle of the volume (degree)
    maxrange : float
        maximum range (same unit as gridcoords)

    Returns
    -------
    output : tuple of three Boolean arrays each of length (num grid points)

    """
    # distances of 3-D grid nodes from radar site (center)
    dist_from_rad = np.sqrt(((gridcoords - center) ** 2).sum(axis=-1))
    # below the radar
    below = gridcoords[:, 2] < (georef.bin_altitude(dist_from_rad, minelev, 0,
                                                    re=6371000) +
                                center[:, 2])
    # above the radar
    above = gridcoords[:, 2] > (georef.bin_altitude(dist_from_rad, maxelev, 0,
                                                    re=6371000) +
                                center[:, 2])
    # out of range
    out_of_range = dist_from_rad > maxrange
    return below, above, out_of_range
Exemple #6
0
def maximum_intensity_projection(data,
                                 r=None,
                                 az=None,
                                 angle=None,
                                 elev=None,
                                 autoext=True):
    """Computes the maximum intensity projection along an arbitrary cut \
    through the ppi from polar data.

    Parameters
    ----------
    data : :class:`numpy:numpy.ndarray`
        Array containing polar data (azimuth, range)
    r : :class:`numpy:numpy.ndarray`
        Array containing range data
    az : array
        Array containing azimuth data
    angle : float
        angle of slice, Defaults to 0. Should be between 0 and 180.
        0. means horizontal slice, 90. means vertical slice
    elev : float
        elevation angle of scan, Defaults to 0.
    autoext : True | False
        This routine uses numpy.digitize to bin the data.
        As this function needs bounds, we create one set of coordinates more
        than would usually be provided by `r` and `az`.

    Returns
    -------
    xs : :class:`numpy:numpy.ndarray`
        meshgrid x array
    ys : :class:`numpy:numpy.ndarray`
        meshgrid y array
    mip : :class:`numpy:numpy.ndarray`
        Array containing the maximum intensity projection (range, range*2)
    """

    from wradlib.georef import bin_altitude as bin_altitude

    # this may seem odd at first, but d1 and d2 are also used in several
    # plotting functions and thus it may be easier to compare the functions
    d1 = r
    d2 = az

    # providing 'reasonable defaults', based on the data's shape
    if d1 is None:
        d1 = np.arange(data.shape[1], dtype=np.float)
    if d2 is None:
        d2 = np.arange(data.shape[0], dtype=np.float)

    if angle is None:
        angle = 0.0

    if elev is None:
        elev = 0.0

    if autoext:
        # the ranges need to go 'one bin further', assuming some regularity
        # we extend by the distance between the preceding bins.
        x = np.append(d1, d1[-1] + (d1[-1] - d1[-2]))
        # the angular dimension is supposed to be cyclic, so we just add the
        # first element
        y = np.append(d2, d2[0])
    else:
        # no autoext basically is only useful, if the user supplied the correct
        # dimensions himself.
        x = d1
        y = d2

    # roll data array to specified azimuth, assuming equidistant azimuth angles
    ind = (d2 >= angle).nonzero()[0][0]
    data = np.roll(data, ind, axis=0)

    # build cartesian range array, add delta to last element to compensate for
    # open bound (np.digitize)
    dc = np.linspace(-np.max(d1), np.max(d1) + 0.0001, num=d1.shape[0] * 2 + 1)

    # get height values from polar data and build cartesian height array
    # add delta to last element to compensate for open bound (np.digitize)
    hp = np.zeros((y.shape[0], x.shape[0]))
    hc = bin_altitude(x, elev, 0, re=6370040.)
    hp[:] = hc
    hc[-1] += 0.0001

    # create meshgrid for polar data
    xx, yy = np.meshgrid(x, y)

    # create meshgrid for cartesian slices
    xs, ys = np.meshgrid(dc, hc)
    # xs, ys = np.meshgrid(dc,x)

    # convert polar coordinates to cartesian
    xxx = xx * np.cos(np.radians(90. - yy))
    # yyy = xx * np.sin(np.radians(90.-yy))

    # digitize coordinates according to cartesian range array
    range_dig1 = np.digitize(xxx.ravel(), dc)
    range_dig1.shape = xxx.shape

    # digitize heights according polar height array
    height_dig1 = np.digitize(hp.ravel(), hc)
    # reshape accordingly
    height_dig1.shape = hp.shape

    # what am I doing here?!
    range_dig1 = range_dig1[0:-1, 0:-1]
    height_dig1 = height_dig1[0:-1, 0:-1]

    # create height and range masks
    height_mask = [(height_dig1 == i).ravel().nonzero()[0]
                   for i in range(1, len(hc))]
    range_mask = [(range_dig1 == i).ravel().nonzero()[0]
                  for i in range(1, len(dc))]

    # create mip output array, set outval to inf
    mip = np.zeros((d1.shape[0], 2 * d1.shape[0]))
    mip[:] = np.inf

    # fill mip array,
    # in some cases there are no values found in the specified range and height
    # then we fill in nans and interpolate afterwards
    for i in range(0, len(range_mask)):
        mask1 = range_mask[i]
        found = False
        for j in range(0, len(height_mask)):
            mask2 = np.intersect1d(mask1, height_mask[j])
            # this is to catch the ValueError from the max() routine when
            # calculating on empty array
            try:
                mip[j, i] = data.ravel()[mask2].max()
                if not found:
                    found = True
            except ValueError:
                if found:
                    mip[j, i] = np.nan

    # interpolate nans inside image, do not touch outvals
    good = ~np.isnan(mip)
    xp = good.ravel().nonzero()[0]
    fp = mip[~np.isnan(mip)]
    x = np.isnan(mip).ravel().nonzero()[0]
    mip[np.isnan(mip)] = np.interp(x, xp, fp)

    # reset outval to nan
    mip[mip == np.inf] = np.nan

    return xs, ys, mip
Exemple #7
0
def maximum_intensity_projection(data, r=None, az=None, angle=None,
                                 elev=None, autoext=True):
    """Computes the maximum intensity projection along an arbitrary cut \
    through the ppi from polar data.

    Parameters
    ----------
    data : :class:`numpy:numpy.ndarray`
        Array containing polar data (azimuth, range)
    r : :class:`numpy:numpy.ndarray`
        Array containing range data
    az : array
        Array containing azimuth data
    angle : float
        angle of slice, Defaults to 0. Should be between 0 and 180.
        0. means horizontal slice, 90. means vertical slice
    elev : float
        elevation angle of scan, Defaults to 0.
    autoext : True | False
        This routine uses numpy.digitize to bin the data.
        As this function needs bounds, we create one set of coordinates more
        than would usually be provided by `r` and `az`.

    Returns
    -------
    xs : :class:`numpy:numpy.ndarray`
        meshgrid x array
    ys : :class:`numpy:numpy.ndarray`
        meshgrid y array
    mip : :class:`numpy:numpy.ndarray`
        Array containing the maximum intensity projection (range, range*2)
    """

    from wradlib.georef import bin_altitude as bin_altitude

    # this may seem odd at first, but d1 and d2 are also used in several
    # plotting functions and thus it may be easier to compare the functions
    d1 = r
    d2 = az

    # providing 'reasonable defaults', based on the data's shape
    if d1 is None:
        d1 = np.arange(data.shape[1], dtype=np.float)
    if d2 is None:
        d2 = np.arange(data.shape[0], dtype=np.float)

    if angle is None:
        angle = 0.0

    if elev is None:
        elev = 0.0

    if autoext:
        # the ranges need to go 'one bin further', assuming some regularity
        # we extend by the distance between the preceding bins.
        x = np.append(d1, d1[-1] + (d1[-1] - d1[-2]))
        # the angular dimension is supposed to be cyclic, so we just add the
        # first element
        y = np.append(d2, d2[0])
    else:
        # no autoext basically is only useful, if the user supplied the correct
        # dimensions himself.
        x = d1
        y = d2

    # roll data array to specified azimuth, assuming equidistant azimuth angles
    ind = (d2 >= angle).nonzero()[0][0]
    data = np.roll(data, ind, axis=0)

    # build cartesian range array, add delta to last element to compensate for
    # open bound (np.digitize)
    dc = np.linspace(-np.max(d1), np.max(d1) + 0.0001, num=d1.shape[0] * 2 + 1)

    # get height values from polar data and build cartesian height array
    # add delta to last element to compensate for open bound (np.digitize)
    hp = np.zeros((y.shape[0], x.shape[0]))
    hc = bin_altitude(x, elev, 0, re=6370040.)
    hp[:] = hc
    hc[-1] += 0.0001

    # create meshgrid for polar data
    xx, yy = np.meshgrid(x, y)

    # create meshgrid for cartesian slices
    xs, ys = np.meshgrid(dc, hc)
    # xs, ys = np.meshgrid(dc,x)

    # convert polar coordinates to cartesian
    xxx = xx * np.cos(np.radians(90. - yy))
    # yyy = xx * np.sin(np.radians(90.-yy))

    # digitize coordinates according to cartesian range array
    range_dig1 = np.digitize(xxx.ravel(), dc)
    range_dig1.shape = xxx.shape

    # digitize heights according polar height array
    height_dig1 = np.digitize(hp.ravel(), hc)
    # reshape accordingly
    height_dig1.shape = hp.shape

    # what am I doing here?!
    range_dig1 = range_dig1[0:-1, 0:-1]
    height_dig1 = height_dig1[0:-1, 0:-1]

    # create height and range masks
    height_mask = [(height_dig1 == i).ravel().nonzero()[0]
                   for i in range(1, len(hc))]
    range_mask = [(range_dig1 == i).ravel().nonzero()[0]
                  for i in range(1, len(dc))]

    # create mip output array, set outval to inf
    mip = np.zeros((d1.shape[0], 2 * d1.shape[0]))
    mip[:] = np.inf

    # fill mip array,
    # in some cases there are no values found in the specified range and height
    # then we fill in nans and interpolate afterwards
    for i in range(0, len(range_mask)):
        mask1 = range_mask[i]
        found = False
        for j in range(0, len(height_mask)):
            mask2 = np.intersect1d(mask1, height_mask[j])
            # this is to catch the ValueError from the max() routine when
            # calculating on empty array
            try:
                mip[j, i] = data.ravel()[mask2].max()
                if not found:
                    found = True
            except ValueError:
                if found:
                    mip[j, i] = np.nan

    # interpolate nans inside image, do not touch outvals
    good = ~np.isnan(mip)
    xp = good.ravel().nonzero()[0]
    fp = mip[~np.isnan(mip)]
    x = np.isnan(mip).ravel().nonzero()[0]
    mip[np.isnan(mip)] = np.interp(x, xp, fp)

    # reset outval to nan
    mip[mip == np.inf] = np.nan

    return xs, ys, mip