예제 #1
0
def integrate_GH_pts(list_GH_pts):
    num_beams = len(list_GH_pts)

    list_variables = list_GH_pts[0].values.keys()

    integrated_variables = {}
    for k in list_variables:
        integrated_variables[k] = [float('nan')]
        for i in list_GH_pts:
            integrated_variables[k] = utilities.nansum_arr(
                integrated_variables[k], i.values[k] * i.GH_weight)

    # Get index of central beam
    idx_0 = int(num_beams / 2)

    # Sum the mask of all beams to get overall mask
    mask = np.zeros(
        num_beams,
    )  # This mask serves to tell if the measured point is ok, or below topo or above COSMO domain
    for i, p in enumerate(list_GH_pts):
        mask = utilities.sum_arr(mask, p.mask)  # Get mask of every Beam
    mask /= float(
        num_beams
    )  # Larger than 1 means that every Beam is below TOPO, smaller than 0 that at least one Beam is above COSMO domain
    mask[np.logical_and(mask >= 0, mask < 1)] = 0

    heights_radar = list_GH_pts[idx_0].heights_profile
    distances_radar = list_GH_pts[idx_0].dist_profile
    lats = list_GH_pts[idx_0].lats_profile
    lons = list_GH_pts[idx_0].lons_profile

    integrated_beam = Beam(integrated_variables, mask, lats, lons,
                           distances_radar, heights_radar)
    return integrated_beam
예제 #2
0
def get_doppler_velocity(list_beams, lut_sz=0):
    ###########################################################################
    # Get setup
    global doppler_scheme
    global microphysics_scheme

    doppler_scheme = cfg.CONFIG['doppler']['scheme']
    microphysics_scheme = cfg.CONFIG['microphysics']['scheme']

    # Check if necessary variables for turbulence scheme are present
    if doppler_scheme == 4 and 'EDR' in list_beams.keys():
        add_turb = True
    else:
        add_turb = False
        if doppler_scheme == 4:
            print(
                'No eddy dissipitation rate variable found in COSMO file, could not use doppler_scheme == 4, using doppler_scheme == 3 instead'
            )

# Get dimensions
    num_beams = len(list_beams)  # Number of beams
    idx_0 = int(num_beams / 2)  # Index of central beam
    len_beams = max([len(l.dist_profile) for l in list_beams])  # Beam length

    if microphysics_scheme == 1:
        hydrom_types = ['R', 'S', 'G']  # Rain, snow and graupel
    elif microphysics_scheme == 2:
        hydrom_types = ['R', 'S', 'G', 'H']  # Add hail

    # Create dic of hydrometeors
    list_hydrom = {}
    for h in hydrom_types:
        list_hydrom[h] = hydrometeors.create_hydrometeor(
            h, microphysics_scheme)

    ###########################################################################
    # Get radial wind and doppler spectrum (if scheme == 1 or 2)
    if doppler_scheme == 1 or doppler_scheme == 2:

        rvel_avg = np.zeros(len_beams, ) * float(
            'nan')  # average radial velocity
        sum_weights = np.zeros(len_beams, )  # mask of GH weights

        for beam in list_beams:
            if doppler_scheme == 1:  # Weighting by PSD only
                v_hydro = get_v_hydro_unweighted(beam, list_hydrom)

            elif doppler_scheme == 2:  # Weighting by RCS and PSD
                v_hydro = get_v_hydro_weighted(beam, list_hydrom, lut_sz)

            # Get radial velocity knowing hydrometeor fall speed and U,V,W from model
            theta = beam.elev_profile * DEG2RAD
            phi = beam.GH_pt[0] * DEG2RAD

            proj_wind = proj_vel(beam.values['U'], beam.values['V'],
                                 beam.values['W'], v_hydro, theta, phi)

            # Get mask of valid values
            sum_weights = utilities.sum_arr(
                sum_weights, ~np.isnan(proj_wind) * beam.GH_weight)

            # Average radial velocity for all sub-beams
            rvel_avg = utilities.nansum_arr(rvel_avg,
                                            (proj_wind) * beam.GH_weight)

        # We need to divide by the total weights of valid beams at every bin
        rvel_avg /= sum_weights

    elif doppler_scheme == 3:
        rvel_avg = np.zeros(len_beams, )
        doppler_spectrum = np.zeros((len_beams, len(constants.VARRAY)))
        for beam in list_beams:
            beam_spectrum = get_doppler_spectrum(
                beam, list_hydrom,
                lut_sz) * beam.GH_weight  # Multiply by GH weight
            if add_turb:  # Spectrum spread caused by turbulence
                turb_std = get_turb_std(constants.RANGE_RADAR,
                                        beam.values['EDR'])
                beam_spectrum = turb_spectrum_spread(beam_spectrum, turb_std)
            doppler_spectrum += beam_spectrum
        try:
            rvel_avg = np.sum(np.tile(constants.VARRAY,
                                      (len_beams, 1)) * doppler_spectrum,
                              axis=1) / np.sum(doppler_spectrum, axis=1)
        except:
            rvel_avg *= float('nan')

    ###########################################################################
    # Get mask
    # This mask serves to tell if the measured point is ok, or below topo or above COSMO domain
    mask = np.zeros(len_beams, )

    for i, beam in enumerate(list_beams):
        mask = utilities.sum_arr(mask, beam.mask)  # Get mask of every Beam
    mask /= num_beams  # Larger than 1 means that every Beam is below TOPO, smaller than 0 that at least one Beam is above COSMO domain
    mask[np.logical_and(mask >= 0, mask < 1)] = 0

    # Finally get vectors of distances, height and lat/lon at the central beam
    idx_0 = int(len(list_beams) / 2)
    heights_radar = list_beams[idx_0].heights_profile
    distances_radar = list_beams[idx_0].dist_profile
    lats = list_beams[idx_0].lats_profile
    lons = list_beams[idx_0].lons_profile

    if doppler_scheme == 3:
        dic_vars = {'RVEL': rvel_avg, 'DSPECTRUM': doppler_spectrum}
    else:
        # No doppler spectrum is computed
        dic_vars = {'RVEL': rvel_avg}

    beam_doppler = Beam(dic_vars, mask, lats, lons, distances_radar,
                        heights_radar)
    return beam_doppler
예제 #3
0
def get_profiles_GH(dic_variables,
                    azimuth,
                    elevation,
                    radar_range=0,
                    N=0,
                    list_refraction=0):

    list_variables = dic_variables.values()
    keys = dic_variables.keys()

    # Get options
    bandwidth_3dB = cfg.CONFIG['radar']['3dB_beamwidth']
    integration_scheme = cfg.CONFIG['integration']['scheme']
    refraction_method = cfg.CONFIG['refraction']['scheme']

    list_variables = dic_variables.values()
    keys = dic_variables.keys()

    # Calculate quadrature weights
    if integration_scheme == 1:  # Classical single gaussian scheme
        nh_GH = int(cfg.CONFIG['integration']['nh_GH'])
        nv_GH = int(cfg.CONFIG['integration']['nv_GH'])

        # Get GH points and weights
        sigma = bandwidth_3dB / (2 * np.sqrt(2 * np.log(2)))

        pts_hor, weights_hor = np.polynomial.hermite.hermgauss(nh_GH)
        pts_hor = pts_hor * sigma

        pts_ver, weights_ver = np.polynomial.hermite.hermgauss(nv_GH)
        pts_ver = pts_ver * sigma

        weights = np.outer(weights_hor * sigma, weights_ver * sigma)
        weights *= np.abs(np.cos(pts_ver))

        sum_weights = np.sum(weights.ravel())

        beam_broadening = nh_GH > 1 or nv_GH > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    elif integration_scheme == 2:  # Improved multi-gaussian scheme
        nr_GH = int(cfg.CONFIG['integration']['nr_GH'])
        na_GL = int(cfg.CONFIG['integration']['na_GL'])

        antenna_params = cfg.CONFIG['integration']['antenna_params']

        pts_ang, w_ang = np.polynomial.legendre.leggauss(na_GL)
        pts_rad, w_rad = np.polynomial.hermite.hermgauss(nr_GH)

        a_dB = antenna_params[:, 0]
        mu = antenna_params[:, 1]
        sigma = antenna_params[:, 2]

        list_pts = []
        weights = []
        sum_weights = 0

        for i in range(nr_GH):
            for j in range(len(sigma)):
                for k in range(na_GL):
                    r = mu[j] + np.sqrt(2) * sigma[j] * pts_rad[i]
                    theta = np.pi * pts_ang[k] + np.pi
                    weight = np.pi * w_ang[k] * w_rad[i] * 10**(
                        0.1 * a_dB[j]) * np.sqrt(2) * sigma[j] * abs(
                            r)  # Laplacian
                    weight *= np.cos(r * np.sin(theta))
                    weights.append(weight)

                    sum_weights += weight

                    list_pts.append([
                        r * np.cos(theta) + azimuth,
                        r * np.sin(theta) + elevation
                    ])

    elif integration_scheme == 3:  # Gauss-Legendre with real-antenna weighting
        nh_GH = int(cfg.CONFIG['integration']['nh_GH'])
        nv_GH = int(cfg.CONFIG['integration']['nv_GH'])

        antenna = np.genfromtxt(cfg.CONFIG['integration']['antenna_diagram'],
                                delimiter=',')

        angles = antenna[:, 0]
        power_sq = (10**(0.1 * antenna[:, 1]))**2
        bounds = np.max(angles)

        pts_hor, weights_hor = np.polynomial.legendre.leggauss(nh_GH)
        pts_hor = pts_hor * bounds

        pts_ver, weights_ver = np.polynomial.legendre.leggauss(nv_GH)
        pts_ver = pts_ver * bounds

        power_sq_pts = (utilities.vector_1d_to_polar(angles, power_sq, pts_hor,
                                                     pts_ver).T)
        weights = power_sq_pts * np.outer(weights_hor, weights_ver)
        weights *= np.abs(np.cos(pts_ver))
        weights *= 2 * bounds

        sum_weights = np.sum(weights.ravel())
        beam_broadening = nh_GH > 1 or nv_GH > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)


#
#    elif integration_scheme == 3.5: # Gauss-Legendre with real-antenna weighting
#        nh_GH = int(cfg.CONFIG['integration']['nh_GH'])
#        nv_GH = int(cfg.CONFIG['integration']['nv_GH'])
#
#        antenna = np.genfromtxt(cfg.CONFIG['integration']['antenna_diagram'],delimiter=',')
#
#        angles =  antenna[:,0]
#        power_sq =  (10**(0.1*antenna[:,1]))**2
#        bounds = np.max(angles)
#
#        pts_hor=np.linspace(-bounds,bounds,nh_GH)
#
#        pts_ver=np.linspace(-bounds,bounds,nv_GH)
#
#        power_sq_pts = (utilities.vector_1d_to_polar(angles,power_sq,pts_hor,pts_ver).T)
#        weights = power_sq_pts
#        weights *= np.abs(np.cos(pts_ver))
#        weights *= 2*bounds
#
#        sum_weights = np.sum(weights.ravel())
#        beam_broadening=nh_GH>1 or nv_GH>1 # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    elif integration_scheme == 4:  # Real antenna, for testing only

        data = pickle.load(
            open('/storage/cosmo_pol/tests/real_antenna_ss.p', 'rb'))
        angles = data['angles']
        power_squ = (data['data'].T)**2

        pts_hor = angles
        pts_ver = angles

        #        threshold = -np.Inf
        beam_broadening = True  # In this scheme we always consider several beams

        weights = power_squ * np.abs(np.cos(pts_ver))
        sum_weights = np.sum(weights)

    elif integration_scheme == 5:  # Discrete Gautschi quadrature
        nh_GA = int(cfg.CONFIG['integration']['nh_GH'])
        nv_GA = int(cfg.CONFIG['integration']['nv_GH'])

        antenna = np.genfromtxt(cfg.CONFIG['integration']['antenna_diagram'],
                                delimiter=',')

        angles = antenna[:, 0]
        power_sq = (10**(0.1 * antenna[:, 1]))**2
        bounds = np.max(angles)

        antenna_fit = interp.interp1d(angles, power_sq, fill_value=0)
        antenna_fit_weighted = interp.interp1d(
            angles,
            power_sq * np.cos(np.abs(np.deg2rad(angles))),
            fill_value=0)

        pts_hor, weights_hor = quadrature.get_points_and_weights(
            antenna_fit, -bounds, bounds, nh_GA)
        pts_ver, weights_ver = quadrature.get_points_and_weights(
            antenna_fit_weighted, -bounds, bounds, nv_GA)

        weights = np.outer(weights_hor, weights_ver)
        sum_weights = np.sum(weights.ravel())

        beam_broadening = nh_GA > 1 or nv_GA > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    elif integration_scheme == 6:  # Sparse Gauss-Hermite
        nh_GH = int(cfg.CONFIG['integration']['nh_GH'])
        nv_GH = int(cfg.CONFIG['integration']['nv_GH'])
        # Get GH points and weights
        sigma = bandwidth_3dB / (2 * np.sqrt(2 * np.log(2)))

        grid = SparseGrids.SparseGrid(dim=2,
                                      qrule=SparseGrids.GQN,
                                      k=int(
                                          cfg.CONFIG['integration']['nh_GH']),
                                      sym=True)

        XF, W = grid.sparseGrid()
        W = np.squeeze(W)
        XF *= sigma

        weights = W
        weights *= np.abs(np.cos(XF[:, 1])) * sigma

        pts_hor = XF[:, 0] + azimuth
        pts_ver = XF[:, 1] + elevation
        list_pts = [pt for pt in zip(pts_hor, pts_ver)]

        sum_weights = np.sum(weights)

        beam_broadening = nh_GH > 1 or nv_GH > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    # Keep only weights above threshold
    if integration_scheme != 6:
        weights_sort = np.sort(np.array(weights).ravel())[::-1]  # Desc. order

        weights_cumsum = np.cumsum(weights_sort / sum_weights)
        weights_cumsum[-1] = 1.  # Avoid floating precision issues
        idx_above = np.where(
            weights_cumsum >= cfg.CONFIG['integration']['weight_threshold']
        )[0][0]

        threshold = weights_sort[idx_above]
        sum_weights = np.sum(weights_sort[weights_sort >= threshold])
    else:
        threshold = -np.inf

    # Get beams
    list_beams = []
    # create vector of bin positions
    rranges = np.arange(cfg.CONFIG['radar']['radial_resolution'] / 2,
                        cfg.CONFIG['radar']['range'],
                        cfg.CONFIG['radar']['radial_resolution'])

    if integration_scheme not in [2, 6]:  # Only regular grids!

        if list_refraction == 0:  # Calculate refraction for vertical GH points
            list_refraction = []

            # Get coordinates of virtual radar
            radar_pos = cfg.CONFIG['radar']['coords']

            for pt in pts_ver:
                if cfg.CONFIG['radar']['type'] == 'GPM':
                    S, H, E = atm_refraction.get_GPM_refraction(pt + elevation)
                else:
                    S, H, E = atm_refraction.get_radar_refraction(
                        rranges, pt + elevation, radar_pos, refraction_method,
                        N)
                list_refraction.append((S, H, E))

        for i in range(len(pts_hor)):
            for j in range(len(pts_ver)):
                if weights[i, j] >= threshold or not beam_broadening:

                    # GH coordinates
                    pt = [pts_hor[i] + azimuth, pts_ver[j] + elevation]
                    weight = weights[i, j] / sum_weights
                    # Interpolate beam
                    lats, lons, b = get_radar_beam_trilin(
                        list_variables, pts_hor[i] + azimuth,
                        list_refraction[j][0], list_refraction[j][1])

                    # Create dictionary of beams
                    dic_beams = {}
                    for k, bi in enumerate(
                            b):  # Loop on interpolated variables
                        if k == 0:  # Do this only for the first variable (same mask for all variables)
                            mask_beam = np.zeros((len(bi)))
                            mask_beam[
                                bi ==
                                -9999] = -1  # Means that the interpolated point is above COSMO domain
                            mask_beam[np.isnan(
                                bi
                            )] = 1  # Means that the interpolated point is below COSMO terrain
                        bi[mask_beam != 0] = float(
                            'nan')  # Assign NaN to all missing data
                        dic_beams[keys[k]] = bi  # Create dictionary
                    list_beams.append(
                        Beam(dic_beams, mask_beam, lats, lons,
                             list_refraction[j][0], list_refraction[j][1],
                             list_refraction[j][2], pt, weight))

    else:
        # create vector of bin positions
        # Get coordinates of virtual radar

        radar_pos = cfg.CONFIG['radar']['coords']

        for i in range(len(list_pts)):
            if weights[i] >= threshold:

                if cfg.CONFIG['radar']['type'] == 'GPM':
                    S, H, E = atm_refraction.get_GPM_refraction(list_pts[i][1])
                else:
                    S, H, E = atm_refraction.get_radar_refraction(
                        rranges, list_pts[i][1], radar_pos, refraction_method,
                        N)

                lats, lons, b = get_radar_beam_trilin(list_variables,
                                                      list_pts[i][0], S, H)
                # Create dictionary of beams
                dic_beams = {}
                for k, bi in enumerate(b):  # Loop on interpolated variables
                    if k == 0:  # Do this only for the first variable (same mask for all variables)
                        mask_beam = np.zeros((len(bi)))
                        mask_beam[
                            bi ==
                            -9999] = -1  # Means that the interpolated point is above COSMO domain
                        mask_beam[np.isnan(
                            bi
                        )] = 1  # NaN means that the interpolated point is below COSMO terrain
                    bi[mask_beam != 0] = float(
                        'nan')  # Assign NaN to all missing data
                    dic_beams[keys[k]] = bi  # Create dictionary
                list_beams.append(
                    Beam(dic_beams, mask_beam, lats, lons, S, H, E,
                         list_pts[i], weights[i] / sum_weights))

    return list_beams
예제 #4
0
def get_radar_observables(list_beams, lut_sz):
    ###########################################################################
    # Get setup
    att_corr = cfg.CONFIG['attenuation']['correction']
    hydrom_scheme = cfg.CONFIG['microphysics']['scheme']

    # Get dimensions
    num_beams = len(list_beams)  # Number of beams
    idx_0 = int(num_beams / 2)  # Index of central beam
    len_beams = len(list_beams[idx_0].dist_profile)  # Beam length

    # Initialize

    radial_res = cfg.CONFIG['radar']['radial_resolution']

    if hydrom_scheme == 1:
        hydrom_types = ['R', 'S', 'G']  # Rain, snow and graupel
    elif hydrom_scheme == 2:
        hydrom_types = ['R', 'S', 'G', 'H']  # Add hail

    # Initialize matrices
    sz_integ = np.zeros((len_beams, len(hydrom_types), 12), dtype='float32')
    sz_integ.fill(np.nan)

    ###########################################################################
    for j, h in enumerate(hydrom_types):  # Loop on hydrometeors
        # Create a hydrometeor instance
        scheme = '2mom' if hydrom_scheme == 2 else '1mom'
        hydrom = create_hydrometeor(h, scheme)

        # Get list of diameters for this hydrometeor
        list_D = lut_sz[h].axes[lut_sz[h].axes_names['d']]
        # Diameter bin size
        dD = list_D[1] - list_D[0]

        for i, beam in enumerate(list_beams):  # Loop on subbeams

            # For GPM some sub-beams are longer than the main beam, so we discard
            # the "excess" part
            for k in beam.values.keys():
                beam.values[k] = beam.values[k][0:len_beams]

            valid_data = beam.values['Q' + h + '_v'] > 0

            elev = beam.elev_profile

            # Since lookup tables are defined for angles >0, we have to check
            # if angles are larger than 90°, in that case we take 180-elevation
            # by symmetricity
            elev[elev > 90] = 180 - elev[elev > 90]
            # Also check if angles are smaller than 0, in that case, flip sign
            elev[elev < 0] = -elev[elev < 0]

            T = beam.values['T']
            ''' 
            Part 1: Query of the SZ Lookup table 
            '''
            # Get SZ matrix
            sz = lut_sz[h].lookup_line(e=elev[valid_data], t=T[valid_data])
            ''' 
            Part 2 : Get the PSD of the particles
            '''
            QM = beam.values['Q' + h + '_v']  # Get mass densities
            # 1 Moment case
            if hydrom_scheme == 1:
                if h != 'S':
                    hydrom.set_psd(QM[valid_data])
                else:
                    # For snow N0 is Q and temperature dependent
                    hydrom.set_psd(T[valid_data], QM[valid_data])
            # 2 Moment case
            elif hydrom_scheme == 2:
                QN = beam.values['QN' + h + '_v']  # Get concentrations as well
                hydrom.set_psd(QN[valid_data], QM[valid_data])

            # Compute particle numbers for all diameters
            N = hydrom.get_N(list_D)

            if len(N.shape) == 1:
                N = np.reshape(
                    N,
                    [len(N), 1])  # To be consistent with the einsum dimensions
            ''' 
            Part 3 : Integrate the SZ coefficients
            '''
            sz_psd_integ = np.einsum('ijk,ji->ik', sz, N) * dD

            sz_integ[valid_data,
                     j, :] = nansum_arr(sz_integ[valid_data, j, :],
                                        sz_psd_integ * beam.GH_weight)

    # Finally we integrate for all hydrometeors
    sz_integ = np.nansum(sz_integ, axis=1)
    sz_integ[sz_integ == 0] = np.nan

    # Get radar observables
    ZH, ZV, ZDR, RHOHV, KDP, AH, AV, DELTA_HV = get_pol_from_sz(sz_integ)

    #    print 10*np.log10(ZH)[0]
    #    print(sz_integ[0])
    KDP_m = KDP + DELTA_HV  # Account for differential phase on prop.
    PHIDP = nan_cumsum(2 * KDP_m) * radial_res / 1000.

    if att_corr:
        # AH and AV are in dB so we need to convert them to linear
        ZV *= nan_cumprod(
            10**(-0.1 * AV * (radial_res / 1000.)))  # divide to get dist in km
        ZH *= nan_cumprod(10**(-0.1 * AH * (radial_res / 1000.)))
        #        print(nan_cumprod(10**(-0.1*AH*(radial_res/1000.))))
        ZDR = ZH / ZV

    ###########################################################################

    # Create outputs
    rad_obs = {}
    rad_obs['ZH'] = ZH
    rad_obs['ZDR'] = ZDR
    rad_obs['ZV'] = ZV
    rad_obs['KDP'] = KDP_m
    rad_obs['DELTA_HV'] = DELTA_HV
    rad_obs['PHIDP'] = PHIDP
    rad_obs['RHOHV'] = RHOHV
    rad_obs['AH'] = AH
    rad_obs['AV'] = AV

    # This mask serves to tell if the measured point is ok, or below topo or above COSMO domain
    mask = np.zeros(len_beams, )
    for i, beam in enumerate(list_beams):
        mask = sum_arr(mask, beam.mask[0:len_beams],
                       cst=1)  # Get mask of every Beam

    # Larger than 0 means that at least one Beam is below TOPO, smaller than 0 that at least one Beam is above COSMO domain
    mask /= num_beams
    mask[np.logical_and(
        mask >= 0, mask < 1
    )] = 0  # If at least one beam is above topo, we still consider this gate

    # Finally get vectors of distances, height and lat/lon at the central beam
    heights_radar = list_beams[idx_0].heights_profile
    distances_radar = list_beams[idx_0].dist_profile
    lats = list_beams[idx_0].lats_profile
    lons = list_beams[idx_0].lons_profile

    beam_pol = Beam(rad_obs, mask, lats, lons, distances_radar, heights_radar)

    return beam_pol
예제 #5
0
def get_profiles(interpolation_mode,
                 dic_variables,
                 azimuth,
                 elevation,
                 radar_range=0,
                 N=0,
                 list_refraction=0):

    list_variables = dic_variables.values()
    keys = dic_variables.keys()

    # Get options
    bandwidth_3dB = config['radar_3dB_beamwidth']

    ###########################################################################
    if interpolation_mode == 'GH':
        nh_GH = int(config['nh_GH'])
        nv_GH = int(config['nv_GH'])

        # Get GH points and weights
        sigma = bandwidth_3dB / (2 * np.sqrt(2 * np.log(2)))

        pts_hor, weights_hor = np.polynomial.hermite.hermgauss(nh_GH)
        pts_hor = pts_hor * np.sqrt(2) * sigma

        pts_ver, weights_ver = np.polynomial.hermite.hermgauss(nv_GH)
        pts_ver = pts_ver * np.sqrt(2) * sigma

        weights = np.outer(weights_hor, weights_ver)

        threshold = np.mean([
            (weights_hor[0] * weights_hor[int(nh_GH / 2)]) / (nv_GH * nh_GH),
            (weights_ver[0] * weights_ver[int(nv_GH / 2)]) / (nv_GH * nh_GH)
        ])
        sum_weights = np.pi

        beam_broadening = nh_GH > 1 and nv_GH > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    ###########################################################################

    if interpolation_mode == 'GH_improved':

        n_rad = 9
        n_ang = 9

        x_leg, w_leg = np.polynomial.legendre.leggauss(n_ang)
        x_her, w_her = np.polynomial.hermite.hermgauss(n_rad)

        #        bw = [5,1.5,1.5,1.8,1.5,1.5,5]
        sigma = [2, 2, 0.68574, 2, 2, 0.39374, 1.21239]
        mu = [-12.86, -7.0931, 0, 0.2948, 8.37059, 10.05448, 13.20]
        a_dB = [-44.219, -37.7577, 0, -24.0645, -42.1912, -41.4037, -44.7814]

        list_pts = []
        sum_weights = 0
        for i in range(n_rad):
            for j in range(len(sigma)):
                for k in range(n_ang):
                    r = mu[j] + np.sqrt(2) * sigma[j] * x_her[i]
                    theta = np.pi * x_leg[k] + np.pi
                    weight = np.pi * w_her[i] * w_leg[k] * 10**(
                        0.1 * a_dB[j]) * np.sqrt(2) * sigma[j] * abs(
                            r)  # Laplacian
                    sum_weights += weight
                    list_pts.append([
                        weight,
                        [
                            r * np.cos(theta) + azimuth,
                            r * np.sin(theta) + elevation
                        ]
                    ])

        beam_broadening = n_rad > 1 or n_ang > 1  # Boolean for beam-broadening (if only one GH point : No beam-broadening)

    ###########################################################################

    elif interpolation_mode == 'Gauss':
        # Get points and weights
        sigma = bandwidth_3dB / (2 * np.sqrt(2 * np.log(2)))

        data = pickle.load(open('real_antenna_s.p', 'rb'))
        angles = data['angles']

        pts_hor = angles
        pts_ver = angles

        threshold = -np.Inf
        beam_broadening = True

        ax, ay = np.meshgrid(angles, angles)
        d = (ax**2 + ay**2)
        weights = 1 / (2 * np.pi * sigma) * np.exp(
            -0.5 * d / sigma**2) * (angles[1] - angles[0])**2

        sum_weights = np.sum(weights)

    ###########################################################################

    elif interpolation_mode == 'Real':

        data = pickle.load(open('real_antenna.p', 'rb'))
        angles = data['angles']

        pts_hor = angles
        pts_ver = angles

        threshold = -np.Inf
        beam_broadening = True

        weights = data['data']
        sum_weights = np.sum(weights)

    ###########################################################################

    elif interpolation_mode == 'Real_s':

        data = pickle.load(open('real_antenna_s.p', 'rb'))
        angles = data['angles']

        pts_hor = angles
        pts_ver = angles

        threshold = -np.Inf
        beam_broadening = True

        weights = data['data']
        sum_weights = np.sum(weights)

    list_beams = []

    if interpolation_mode == 'GH_improved':
        # create vector of bin positions
        bins_ranges = np.arange(config['radar_rres'] / 2,
                                config['radar_range'], config['radar_rres'])
        # Get coordinates of virtual radar
        radar_pos = config['radar_coords']

        refraction_method = '4/3'  # Other methods take too much time if no quadrature scheme is used

        for i in range(len(list_pts)):
            S, H, E = atm_refraction.get_radar_refraction(
                bins_ranges, list_pts[i][1][1], radar_pos, refraction_method,
                N)
            lats, lons, b = get_radar_beam_trilin(list_variables,
                                                  list_pts[i][0], S, H)
            # Create dictionary of beams
            dic_beams = {}
            for k, bi in enumerate(b):  # Loop on interpolated variables
                if k == 0:  # Do this only for the first variable (same mask for all variables)
                    mask_beam = np.zeros((len(bi)))
                    mask_beam[
                        bi ==
                        -9999] = -1  # Means that the interpolated point is above COSMO domain
                    mask_beam[np.isnan(
                        bi
                    )] = 1  # NaN means that the interpolated point is below COSMO terrain
                bi[mask_beam != 0] = float(
                    'nan')  # Assign NaN to all missing data
                dic_beams[keys[k]] = bi  # Create dictionary
            list_beams.append(
                Beam(dic_beams, mask_beam, lats, lons, S, H, E, list_pts[i][1],
                     list_pts[i][0] / sum_weights))
    else:
        print interpolation_mode

        if list_refraction == 0:  # Calculate refraction for vertical GH points
            list_refraction = []

            # create vector of bin positions
            bins_ranges = np.arange(config['radar_rres'] / 2,
                                    config['radar_range'],
                                    config['radar_rres'])
            # Get coordinates of virtual radar
            radar_pos = config['radar_coords']

            refraction_method = '4/3'  # Other methods take too much time if no quadrature scheme is used

            for pt in pts_ver:
                S, H, E = atm_refraction.get_radar_refraction(
                    bins_ranges, pt + elevation, radar_pos, refraction_method,
                    N)
                list_refraction.append((S, H, E))

        for i in range(len(pts_hor)):
            print i
            for j in range(len(pts_ver)):
                if weights[i, j] > threshold or not beam_broadening:

                    # GH coordinates
                    pt = [pts_hor[i] + azimuth, pts_ver[j] + elevation]
                    weight = weights[i, j] / sum_weights
                    # Interpolate beam
                    lats, lons, b = get_radar_beam_trilin(
                        list_variables, pts_hor[i] + azimuth,
                        list_refraction[j][0], list_refraction[j][1])
                    # Create dictionary of beams
                    dic_beams = {}
                    for k, bi in enumerate(
                            b):  # Loop on interpolated variables
                        if k == 0:  # Do this only for the first variable (same mask for all variables)
                            mask_beam = np.zeros((len(bi)))
                            mask_beam[
                                bi ==
                                -9999] = -1  # Means that the interpolated point is above COSMO domain
                            mask_beam[np.isnan(
                                bi
                            )] = 1  # NaN means that the interpolated point is below COSMO terrain
                        bi[mask_beam != 0] = float(
                            'nan')  # Assign NaN to all missing data
                        dic_beams[keys[k]] = bi  # Create dictionary
                    list_beams.append(
                        Beam(dic_beams, mask_beam, lats, lons,
                             list_refraction[j][0], list_refraction[j][1],
                             list_refraction[j][2], pt, weight))
    return list_beams
예제 #6
0
def get_radar_observables(list_beams, lut):
    ###########################################################################
    # Get setup
    att_corr = cfg.CONFIG['attenuation']['correction']
    hydrom_scheme = cfg.CONFIG['microphysics']['scheme']

    # Get dimensions
    num_beams = len(list_beams)
    idx_0 = int(num_beams / 2)
    len_beams = len(list_beams[idx_0].dist_profile)

    # Initialize
    if att_corr:  # Compute radar bins range
        radial_res = cfg.CONFIG['radar']['radial_resolution']

    if hydrom_scheme == 1:
        hydrom_types = ['R', 'S', 'G']  # Rain, snow and graupel
    elif hydrom_scheme == 2:
        hydrom_types = ['R', 'S', 'G', 'H']  # Add hail

    rad_obs_integrated = {}
    rad_obs = {}

    for o in LIST_OBSERVABLES:
        rad_obs_integrated[o] = np.zeros(
            (len_beams, len(hydrom_types))) * float('nan')
        rad_obs[o] = np.zeros(
            (len_beams, len(hydrom_types), num_beams)) * float('nan')

    ###########################################################################
    for j, h in enumerate(hydrom_types):  # Loop on hydrometeors
        sum_weights = np.zeros((len_beams, ))
        for i, beam in enumerate(list_beams[0:]):  # Loop on subbeams

            elev = beam.elev_profile

            # Since lookup tables are defined for angles >0, we have to check
            # if angles are larger than 90°, in that case we take 180-elevation
            # by symmetricity
            elev[elev > 90] = 180 - elev[elev > 90]
            # Also check if angles are smaller than 0, in that case, flip sign
            elev[elev < 0] = -elev[elev < 0]

            T = beam.values['T']

            QM = np.log10(beam.values['Q' + h +
                                      '_v'])  # Get log mass densities
            if hydrom_scheme == 2:  # Get log number densities as well
                QN = np.log10(beam.values['QN' + h + '_v'])

                lut_pts = np.column_stack((elev, T)).T

            elif hydrom_scheme == 1:
                lut_pts = np.column_stack((elev, T, QM)).T

            # Get polarimetric variables from lookup-table
            ZH_prof = lut[h]['ZH'].lookup_pts(lut_pts)
            ZDR_prof = lut[h]['ZDR'].lookup_pts(lut_pts)
            KDP_prof = lut[h]['KDP'].lookup_pts(
                lut_pts) + lut[h]['DELTAHV'].lookup_pts(lut_pts)
            RHOHV_prof = lut[h]['RHOHV'].lookup_pts(lut_pts)

            #            DELTAHV_prof=lut[h]['DELTAHV'].lookup_pts(lut_pts)
            #            PHIDP_prof=nan_cumsum(KDP_prof+DELTAHV_prof)*cfg.CONFIG['radar']['radial_resolution']/1000

            ZV_prof = ZH_prof / ZDR_prof  # Use ZDR and ZH to get ZV

            # Note that Z2=Z1-a*r in dB gives Z2_l = Z1_l * (1/a_l)**r in linear
            if att_corr:
                # AH and AV are in dB so we need to convert them to linear
                Av_prof = lut[h]['AV'].lookup_pts(lut_pts)
                ZV_prof = ZH_prof / ZDR_prof
                ZV_prof *= nan_cumprod(
                    10**(-Av_prof / 10. *
                         (radial_res / 1000.)))  # divide to get dist in km
                Ah_prof = lut[h]['AH'].lookup_pts(lut_pts)  # convert to linear
                ZH_prof *= nan_cumprod(10**(-Ah_prof / 10. *
                                            (radial_res / 1000.)))
                ZDR_prof = ZH_prof / ZV_prof

            # Add contributions from this subbeam
            rad_obs_integrated['ZH'][:, j] = nansum_arr(
                rad_obs_integrated['ZH'][:, j], ZH_prof * beam.GH_weight)
            rad_obs_integrated['ZV'][:, j] = nansum_arr(
                rad_obs_integrated['ZV'][:, j], ZV_prof * beam.GH_weight)
            rad_obs_integrated['KDP'][:, j] = nansum_arr(
                rad_obs_integrated['KDP'][:, j],
                KDP_prof * np.sqrt(beam.GH_weight))
            rad_obs_integrated['RHOHV'][:, j] = nansum_arr(
                rad_obs_integrated['RHOHV'][:, j],
                RHOHV_prof**np.sqrt(beam.GH_weight))

            rad_obs['ZH'][:, j, i] = ZH_prof
            rad_obs['ZV'][:, j, i] = ZV_prof
            rad_obs['KDP'][:, j, i] = KDP_prof
            rad_obs['RHOHV'][:, j, i] = RHOHV_prof

            sum_weights = sum_arr(sum_weights,
                                  ~np.isnan(QM) * np.sqrt(beam.GH_weight))
            sum_weights_sqrt = sum_arr(np.sqrt(sum_weights),
                                       ~np.isnan(QM) * np.sqrt(beam.GH_weight))

        # Rhohv and Kdp are divided by the total received power
        rad_obs_integrated['KDP'][:, j] = divide_by_power(
            rad_obs_integrated['KDP'][:, j], sum_weights_sqrt)

        rad_obs_integrated['RHOHV'][:, j] = divide_by_power(
            rad_obs_integrated['RHOHV'][:, j], sum_weights_sqrt)

        # If weight = 0, this will get infinite

    ###########################################################################

    # This mask serves to tell if the measured point is ok, or below topo or above COSMO domain
    mask = np.zeros(len_beams, )
    for i, beam in enumerate(list_beams):
        mask = sum_arr(mask, beam.mask)  # Get mask of every Beam

    # Larger than 1 means that every Beam is below TOPO, smaller than 0 that at least one Beam is above COSMO domain
    mask /= num_beams
    mask[np.logical_and(mask >= 0, mask < 1)] = 0

    rad_obs_integrated = combine(rad_obs_integrated)
    rad_obs = combine(rad_obs)

    # Add standard deviation to output
    for var in rad_obs.keys():
        rad_obs_integrated['std_' + var] = np.nanstd(rad_obs[var], axis=1)

    # Finally get vectors of distances, height and lat/lon at the central beam
    idx_0 = int(len(list_beams) / 2)
    heights_radar = list_beams[idx_0].heights_profile
    distances_radar = list_beams[idx_0].dist_profile
    lats = list_beams[idx_0].lats_profile
    lons = list_beams[idx_0].lons_profile

    beam_pol = Beam(rad_obs_integrated, mask, lats, lons, distances_radar,
                    heights_radar)

    return beam_pol