예제 #1
0
def get_v_hydro_unweighted(beam, list_hydrom):
    vh_avg = np.zeros(beam.values['T'].shape)
    vh_avg.fill(np.nan)
    n_avg = np.zeros(beam.values['T'].shape)
    n_avg.fill(np.nan)

    for i, h in enumerate(list_hydrom.keys()):
        if cfg.CONFIG['microphysics']['scheme'] == 1:
            if h == 'S':
                list_hydrom['S'].set_psd(beam.values['T'],
                                         beam.values['Q' + h + '_v'])
            else:
                list_hydrom[h].set_psd(beam.values['Q' + h + '_v'])
        elif cfg.CONFIG['microphysics']['scheme'] == 2:
            list_hydrom[h].set_psd(beam.values['QN' + h + '_v'],
                                   beam.values['Q' + h + '_v'])

        # Get fall speed
        vh, n = list_hydrom[h].integrate_V()

        vh_avg = utilities.nansum_arr(vh_avg, vh)
        n_avg = utilities.nansum_arr(n_avg, n)

    v_hydro_unweighted = vh_avg / n_avg  # Average over all hydrometeors

    return v_hydro_unweighted * (beam.values['RHO'] /
                                 beam.values['RHO'][0])**(0.5)
예제 #2
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
예제 #3
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
예제 #4
0
def get_v_hydro_weighted(beam, list_hydrom, lut_sz):
    hydrom_scheme = cfg.CONFIG['microphysics']['scheme']

    vh_avg = np.zeros(beam.values['T'].shape)
    vh_avg.fill(np.nan)
    n_avg = np.zeros(beam.values['T'].shape)
    n_avg.fill(np.nan)

    for i, h in enumerate(list_hydrom.keys()):
        # Get list of diameters for this hydrometeor
        list_D = lut_sz[h].axes[lut_sz[h].axes_names['d']]

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

        # Get all elevations
        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_lut = copy.deepcopy(elev)
        elev_lut[elev_lut > 90] = 180 - elev_lut[elev_lut > 90]
        # Also check if angles are smaller than 0, in that case, flip sign
        elev_lut[elev_lut < 0] = -elev_lut[elev_lut < 0]

        T = beam.values['T']

        # Get SZ matrix
        sz = lut_sz[h].lookup_line(e=elev[valid_data], t=T[valid_data])
        ''' 
        Part 1: Query of the SZ Lookup table  and RCS computation
        '''
        # Get SZ matrix
        sz = lut_sz[h].lookup_line(e=elev_lut[valid_data], t=T[valid_data])
        # get RCS
        rcs = 2 * np.pi * (sz[:, :, 0] - sz[:, :, 1] - sz[:, :, 2] +
                           sz[:, :, 3])
        rcs = rcs.T
        ''' 
        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':
                list_hydrom[h].set_psd(QM[valid_data])
            else:
                # For snow N0 is Q and temperature dependent
                list_hydrom[h].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
            list_hydrom[h].set_psd(QN[valid_data], QM[valid_data])

        N = list_hydrom[h].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
        '''
        # Get fall speed
        v_f = list_hydrom[h].get_V(list_D)
        vh_w = np.trapz(N * v_f[:, np.newaxis] * rcs, axis=0)
        n_w = np.trapz(N * rcs, axis=0)

        vh_avg[valid_data] = utilities.nansum_arr(vh_avg[valid_data], vh_w)
        n_avg[valid_data] = utilities.nansum_arr(n_avg[valid_data], n_w)

    v_hydro_weighted = vh_avg / n_avg  # Average over all hydrometeors

    return v_hydro_weighted * (beam.values['RHO'] /
                               beam.values['RHO'][0])**(0.5)
예제 #5
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
예제 #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