Ejemplo n.º 1
0
 def process(self):
     isMmcr = (self.framestream.radarType == 'MMCR'
               )  #FIXME better way to discover the division
     isKazr = (self.framestream.radarType.startswith('KAZR')
               )  #FIXME better way to discover the division
     isMwacr = ('WACR' in self.framestream.radarType
                )  #FIXME better way to discover the division
     for f in self.framestream:
         f = copy.copy(f)
         if hasattr(f, 'heights'):
             #    f._altitudevarname='heights'
             f.heights = hau.Z_Array(f.heights, dtype=numpy.float64)
         if hasattr(f, 'Reflectivity'):
             f.Reflectivity = hau.TZ_Array(f.Reflectivity,
                                           dtype=numpy.float64)
             if isMmcr:
                 f.Reflectivity /= 100.0
             setattr(
                 f, 'Backscatter',
                 hau.TZ_Array(
                     self.reflectivityToBackscatterCrossSection(
                         f.Reflectivity)))
         if hasattr(f, 'SpectralWidth'):
             f.SpectralWidth = hau.TZ_Array(f.SpectralWidth,
                                            dtype=numpy.float64)
             if isMmcr:
                 f.SpectralWidth /= 1000.0
         if hasattr(f, 'MeanDopplerVelocity'):
             f.MeanDopplerVelocity = hau.TZ_Array(f.MeanDopplerVelocity,
                                                  dtype=numpy.float64)
             if isMmcr:
                 f.MeanDopplerVelocity /= 1000.0
             if isKazr or isMwacr:
                 f.MeanDopplerVelocity *= -1.0
         yield f
Ejemplo n.º 2
0
 def process(self):
     fr = None
     flags = None
     olda = None
     qasource = tf.TimeTrickle(self.qasource, 'time')
     altitudes = hau.Z_Array(self.qaparser.altitudeAxis)
     for f in self.timealtsource:
         #FIXME include angles
         if not isinstance(f, dict):
             f = vars(f)
         t = f[self.timename]
         a = self.constantAltitude
         if fr is None or ((not qasource.atEnd) and t >= qasource.nextTime
                           ):  #if need an update to the qa record
             #print 'Getting qa source for time',t
             fr = qasource(t)
             flags = None
         if 'range_flags' in fr and fr[
                 'range_flags'] is not None:  #if there is a range dependence, and a potentially non-constant altitude
             if self.altname is not None and self.altname in f:
                 a = f[self.altname]
             if a is None:
                 raise RuntimeError(
                     'Need platform altitude to merge in range-dependant qa Flags'
                 )
             if olda is None or a != olda:
                 flags = None
                 olda = a
         if flags is None:  #was cleared either because new flags from the qa file, or new altitude from the stream
             if 'range_flags' in fr and fr['range_flags'] is not None:
                 flags = self.qaparser.mergeVectors(fr['flags'],
                                                    fr['range_flags'], a)
             else:
                 flags = fr['flags']
             flags = self.qaparser.translateToEnumeration(flags)
             flags = hau.TZ_Array(flags.reshape([1] + list(flags.shape)),
                                  dtype='int32',
                                  summode='and')
         ret = hau.Time_Z_Group(timevarname='times', altname='altitudes')
         setattr(ret, 'times', hau.T_Array([t]))
         setattr(ret, 'delta_t', hau.T_Array([f['width'].total_seconds()]))
         setattr(ret, 'altitudes', copy.copy(altitudes))
         setattr(ret, 'start', f['start'])
         setattr(ret, 'width', f['width'])
         if self.splitFields:
             for f, idx in self.qaparser.flagbits.items():
                 setattr(
                     ret, 'qa_' + f,
                     hau.TZ_Array((flags / (10**idx)) % 10,
                                  dtype='int32',
                                  summode='and'))
         else:
             setattr(ret, 'qaflags', flags)
         yield ret
Ejemplo n.º 3
0
 def process(self):
     for f in self.framestream:
         if hasattr(f, 'Backscatter'):
             f = copy.copy(f)
             setattr(
                 f, 'Reflectivity',
                 hau.TZ_Array(
                     self.backscatterCrossSectionToReflectivity(
                         f.Backscatter)))
         yield f
Ejemplo n.º 4
0
def radar_masking(rs_radar, processing_defaults, instrument):
    """radar_masking(rs_radar,processing_defaults)
       rs_radar = structure generated by radar processing stream
       processing_defaults = config info from 'radar_processing_defaults.json'
       qc_radar_mask, bit[0] = longical and of all other bits
       qc_radar_mask, bit[1] = cleared if radar refectivity fall below SNR threshhold
       """

    assert (rs_radar != None)
    if not hasattr(rs_radar, 'Backscatter'):
        return rs_radar

    threshhold = processing_defaults.get_value('radar_SNR_mask', 'threshhold')
    #radar mask ok when sig_to_noise greater than threshhold in dB
    rs_radar = copy.copy(rs_radar)
    #fix me this has been changed to a single bit because the interpolator is
    #not aware of summode
    rs_radar.qc_radar_mask = \
        hau.TZ_Array(np.ones(rs_radar.Backscatter.shape),summode='or',dtype='uint16')
    #rs_radar.qc_radar_mask[:,:]=65535
    #mask = np.ones_like(rs_radar.Backscatter)
    #mask[rs_radar.SignalToNoiseRatio < threshhold] = 0
    #mask = ~(3*mask.astype('uint16'))
    #rs_radar.qc_radar_mask &= mask

    rs_radar.qc_radar_mask[rs_radar.SignalToNoiseRatio < threshhold] = 0
    rs_radar.qc_radar_mask[np.isnan(rs_radar.SignalToNoiseRatio)] = 0

    print
    print 'instrument', instrument

    if (instrument == 'magkazrge' or 'magmwacr') \
                and processing_defaults.enabled('ship_motion_correction'):
        temp = rs_radar.MeanDopplerVelocity.copy()
        temp[rs_radar.qc_radar_mask == 0] = np.NaN
        rs_radar.vertically_averaged_doppler = hau.T_Array(nanmean(temp, 1))

    return rs_radar
Ejemplo n.º 5
0
    def __call__(self,rs_inv,rs_particle,calvals):#update to process,and return a completed frame
        rs_multiple_scattering=hau.Time_Z_Group(rs_inv.times.copy(),timevarname='times',altname='msl_altitudes')

        N1 = 2  
        N2 = self.multiple_scatter_parameters['highest_order']
        
        start_alt = self.multiple_scatter_parameters['lowest_altitude']
        
        p180_water = self.multiple_scatter_parameters['p180_water']
        p180_ice   = self.multiple_scatter_parameters['p180_ice']
        h2o_depol_threshold = self.multiple_scatter_parameters['h2o_depol_threshold']
       

        p180_ice = self.multiple_scatter_parameters['p180_ice']
        p180_water = self.multiple_scatter_parameters['p180_water']
        second_wavelength =self.multiple_scatter_parameters['second_wavelength']

        wavelength = calvals['wavelength']*1e-9

        #assert(rs_particle!=None or self.multiple_scatter_parameters['particle_info_source'] == 'constant')

       
        
        if 1:   #self.multiple_scatter_parameters['processing_mode'] == '1d':
            if self.multiple_scatter_parameters['particle_info_source'] == 'constant':
                #in this case the mode diameter will be reset to ice or water values from multiple_scattering.json file
                #depending on h2o_depol_threshold
                mode_diameter = None
            else:
                #use lidar-radar retrieved particle sizes
                #print 'particle'
                #print dir(rs_particle)
                mode_diameter = rs_particle.mode_diameter.copy()

            #accumulates sums for 1-d average multiple scatter profile
            self.ms_obj = msu.ms_sums(mode_diameter,rs_inv.beta_a_backscat
                         ,rs_inv.linear_depol,self.multiple_scatter_parameters,self.ms_obj)

            self.ms_obj.beta_water[self.ms_obj.beta_water < 0] = 0.0
            self.ms_obj.beta_ice[self.ms_obj.beta_ice < 0] = 0.0
            
            beta_total = self.ms_obj.beta_water +self.ms_obj.beta_ice
            
            total_samples = self.ms_obj.n_samples_water +self.ms_obj.n_samples_ice
            
            #when no ice or water data points are present averages must be zero
            #compute weighted averages of beta, diameter when ice and water are present
            #ms_obj.beta_water and ms_obj.beta_ice have the sum of beta_backscatter for ice and water
            #self.ms_obj.n_samples_water[self.ms_obj.n_samples_water == 0] = np.infty
            #self.ms_obj.n_samples_ice[self.ms_obj.n_samples_ice == 0] = np.infty
            
            
            #compute ave beta_extinction profile from sum beta_backscat profiles
            extinction_profile = (self.ms_obj.beta_water/p180_water + self.ms_obj.beta_ice/p180_ice)/total_samples
            diameter = (self.ms_obj.diameter_ice + self.ms_obj.diameter_water)/beta_total
            
          
            #convert altitudes into range
            ranges = rs_inv.msl_altitudes.copy()
            zenith_angle = np.abs(calvals['telescope_roll_angle_offset'])*np.pi/180.0
            ranges = ranges/np.cos(zenith_angle)
            start_range = start_alt/np.cos(zenith_angle)
            end_range = rs_inv.msl_altitudes[-1]/np.cos(zenith_angle)
            if start_range >= end_range:
               raise RuntimeError(' start altitude'+str(np.int(start_range))+ ' is above highest data point')
            
            ms_ratios_profile = msu.msinteg(N1,N2,start_range \
                     ,end_range,self.multiple_scatter_parameters['step_size'], extinction_profile, diameter 
                     ,ranges,wavelength,self.multiple_scatter_parameters,calvals) 

            rs_multiple_scattering.ranges = ms_ratios_profile[:,0]
            rs_multiple_scattering.ms_ratios_profile = ms_ratios_profile
            rs_multiple_scattering.extinction_profile = hau.Z_Array(extinction_profile[np.newaxis,:])   
            rs_multiple_scattering.weighted_diameter = hau.Z_Array(diameter[np.newaxis,:])
            rs_multiple_scattering.msl_altitudes = rs_inv.msl_altitudes.copy()
            rs_multiple_scattering.wavelength = wavelength

            #compute multiple scattering for a second wavelength if it is provided
            #assume no change is extinction cross section
            if second_wavelength:
                 ms_ratios_profile_2 = msu.msinteg(N1,N2,start_range \
                     ,end_range,self.multiple_scatter_parameters['step_size'], extinction_profile, diameter 
                     ,ranges,second_wavelength,self.multiple_scatter_parameters,calvals) 

                 rs_multiple_scattering.ms_ratios_profile_2 = ms_ratios_profile_2
                 rs_multiple_scattering.second_wavelength = second_wavelength
           
        if self.multiple_scatter_parameters['processing_mode'] == '2d': #do multiple scatter calculation for all profiles in frame
            print 'begining 2d multiple scatter processing'
            #estimate extinction based on backscatter phase function 
            beta = rs_inv.beta_a_backscat.copy()
            beta = beta/p180_water
            beta[rs_inv.linear_depol>self.multiple_scatter_parameters['h2o_depol_threshold']] \
                 = beta[rs_inv.linear_depol>self.multiple_scatter_parameters['h2o_depol_threshold']]*p180_water/p180_ice
            beta[beta < 0]=0.0
            if self.multiple_scatter_parameters['particle_info_source'] == 'constant':
                mode_diameter = np.ones_like(rs_inv.beta_a_backscat) \
                                * self.multiple_scatter_parameters['mode_diameter_water']
                mode_diameter[rs_inv.linear_depol > self.multiple_scatter_parameters['h2o_depol_threshold']] \
                           = self.multiple_scatter_parameters['mode_diameter_ice']

        
            #convert altitudes into ranges
            ranges = rs_inv.msl_altitudes.copy()
            zenith_angle = np.abs(calvals['telescope_roll_angle_offset'])*np.pi/180.0
            ranges = ranges/np.cos(zenith_angle)
            start_range = start_alt/np.cos(zenith_angle)
            end_range = rs_inv.msl_altitudes[-1]/np.cos(zenith_angle)
            
            for i in range(rs_inv.beta_a_backscat.shape[0]):
                print 'Computing multiple scattering for ' ,rs_inv.times[i]
                if self.multiple_scatter_parameters['particle_info_source'] == 'constant':
                    ratios = msu.msinteg(N1,N2,start_range \
                         ,end_range,self.multiple_scatter_parameters['step_size'],beta[i,:],mode_diameter[i,:] 
                         ,ranges,wavelength,self.multiple_scatter_parameters,calvals)
                else: #get mode diameter from lidar_radar measured values
                   ratios = msu.msinteg(N1,N2,start_range \
                         ,end_range,wavelength,self.multiple_scatter_parameters['step_size']
                         ,beta[i,:],rs_particle.mode_diameter[i,:] 
                         ,ranges,self.multiple_scatter_parameters,calvals)
                   
                #load values into output array 
                if not hasattr(rs_multiple_scattering,'ms_ratio_total'):
                    rs_multiple_scattering.ms_ratio_total = np.zeros((beta.shape[0],ratios.shape[0]))
                
                rs_multiple_scattering.ms_ratio_total[i,:] =nansum(ratios[:,2:],1)
               
                rs_multiple_scattering.msl_altitudes = rs_inv.msl_altitudes.copy()
            rs_multiple_scattering.ms_ratio_total =hau.TZ_Array(rs_multiple_scattering.ms_ratio_total)
                
       
        
        #rs_multiple_scattering.start_altitude = start_alt
       
        return rs_multiple_scattering
def process_mass_dimension_particle(rs_inv, rs_radar, particle_parameters,
                                    lambda_radar, entire_frame):
    """
            generate and return the particle measurements based on a given hsrl inverted data, radar (and its lambda), and particle parameters dictionary
            """

    ParticleParameters = namedtuple('ParticleParameters',
                                    ','.join(particle_parameters.keys()))
    pparm = ParticleParameters(
        **particle_parameters
    )  #pparm is a structure of the particle parameters, instead of a dictionary 'particle_parameters'

    #create timez group and add heights
    rs_particle = hau.Time_Z_Group(rs_inv.times.copy(),
                                   timevarname='times',
                                   altname='heights')
    setattr(rs_particle, 'heights', rs_inv.msl_altitudes.copy())

    #remove points where lidar signal is noise dominated by setting to
    #very small value.
    clipped_beta_a_back = rs_inv.beta_a_backscat.copy()
    if hasattr(rs_inv, 'std_beta_a_backscat'):
        clipped_beta_a_back[clipped_beta_a_back < (
            2 * rs_inv.std_beta_a_backscat)] = -np.inf
    else:
        print 'No std_beta_a_backscat statistics to filter particle measurements'
    clipped_beta_a_back[np.logical_not(np.isfinite(
        rs_inv.beta_a_backscat))] = -np.inf
    used_beta_a = None
    if hasattr(rs_inv, 'beta_a'):
        used_beta_a = rs_inv.beta_a.copy()
        #mask beta_a?

    rs_particle.effective_diameter_prime,used_beta_a = \
        lred.lidar_radar_eff_diameter_prime(
           beta_a_backscat=clipped_beta_a_back
          ,radar_backscat=rs_radar.Backscatter
          ,depol=rs_inv.linear_depol
          ,h2o_depol_threshold=particle_parameters['h2o_depol_threshold']
          ,beta_a=used_beta_a
          ,p180_ice=particle_parameters['p180_ice']
          ,lambda_radar=lambda_radar)

    rs_particle.effective_diameter,rs_particle.num_particles,rs_particle.LWC,rs_particle.mean_diameter=\
         lred.d_eff_from_d_eff_prime(
             rs_particle.effective_diameter_prime
             ,clipped_beta_a_back
             ,rs_inv.linear_depol
             ,used_beta_a
             ,pparm)

    #rs_particle.hsrl_radar_rain_rate = 3600 * 10* .0001 * rs_particle.LWC * rs_radar.MeanDopplerVelocity
    #convert to mks units LWC kg/m^3, Doppler m/s, rain_rate m/s
    rs_particle.hsrl_radar_rain_rate = 0.001 * rs_particle.LWC * rs_radar.MeanDopplerVelocity

    #retype all these fields to a proper TZ_Array
    for f in [
            'hsrl_radar_rain_rate', 'effective_diameter_prime',
            'effective_diameter', 'num_particles', 'LWC', 'mean_diameter'
    ]:
        if hasattr(rs_particle, f):
            setattr(rs_particle, f, hau.TZ_Array(getattr(rs_particle, f)))

    return rs_particle
    def __call__(self, _mean, t_filter_order, correct_below_range, min_fit_alt,
                 z_norm_interval, enable_z_fit):
        """
    def func(x,a):
        #fourth order polynomial with last value = 1 and df/dx of last value = 0
        #return a[0] + a[1] * x + a[2] * x**2 + a[3] * x**3 + a[4] * x**4
        #val = a[0] + a[1] * x**2 + a[2] * x**3 + a[3] * x**4
        #val = val -(2*a[1]*x[-1] + 3*a[2]*x[-1]**2 + 4*a[3]*x[-1]**3) * x
        val = a[0] * x**2 + a[1] * x**3 + a[2] * x**4
        # linear term from df/dx = 0 at x[-1]
        b = -(2*a[0]*x[-1] + 3*a[1]*x[-1]**2 + 4*a[2]*x[-1]**3)
        # constant term from x[-1] = 1
        a = 1.0 - (b*x[-1] + a[0]*x[-1]**2 + a[1]*x[-1]**3 + a[2]*x[-1]**4)
        #full quadratic
        val = a + b*x + val
        return val


    def func2(x,a):
        #fourth order polynomial with last value = 1 and df/dx of first and last value = 0
        #return a[0] + a[1] * x + a[2] * x**2 + a[3] * x**3 + a[4] * x**4
        val = a[0] * x**3 + a[1] * x**4
        #second order term from df/dx = 0 at first and last points
        c = -(3 * a[0] * (x[-1]**2 - x[0]**2) + 4 * a[1] * (x[-1]**3 - x[0]**3))\
                        /(2 * (x[-1] - x[0]))
        # linear term from df/dx = 0 at x[-1]
        b = -(2* c *x[-1] + 3*a[0]*x[-1]**2 + 4*a[1]*x[-1]**3)
        # constant term from x[-1] = 1
        a = 1.0 - (b*x[-1] + c * x[-1]**2 + a[0]*x[-1]**3 + a[1]*x[-1]**4)
        val = a + b*x + c*x**2 + val
        return val
    """
        def func3(x, a):
            #fifth order polynomial with last value = 1 and df/dx of first and last value = 0
            #return a[0] + a[1] * x + a[2] * x**2 + a[3] * x**3 + a[4] * x**4 + a[5] * x**5
            val = a[0] * x**3 + a[1] * x**4 + a[2] * x**5
            #second order term from df/dx = 0 at first and last points
            c = -(3*a[0]*(x[-1]**2 - x[0]**2) + 4*a[1]*(x[-1]**3 - x[0]**3) +5*a[2]*(x[-1]**4-x[0]**4))\
                            /(2*(x[-1] - x[0]))
            # linear term from df/dx = 0 at x[-1]
            b = -(2 * c * x[-1] + 3 * a[0] * x[-1]**2 + 4 * a[1] * x[-1]**3 +
                  5 * a[2] * x[-1]**4)
            # constant term from x[-1] = 1
            a = 1.0 - (b * x[-1] + c * x[-1]**2 + a[0] * x[-1]**3 +
                       a[1] * x[-1]**4 + a[2] * x[-1]**5)
            val = a + b * x + c * x**2 + val
            return val

        def residuals(p, x, y):
            res = y - func3(x, p)
            return res

        s_time = datetime.utcnow()
        mean = listMerge(_mean)

        ntimes = mean.times.size
        useindex = 0
        if self.priorTime is None:
            self.priorTime = mean.times[0] - timedelta(seconds=10)
        while useindex < (ntimes -
                          1) and self.priorTime >= mean.times[useindex]:
            useindex = useindex + 1
        self.priorTime = mean.times[useindex]

        r_mean = copy.deepcopy(_mean[useindex])

        print 'wfov window ', r_mean.times[0], r_mean.times[-1], ntimes
        if not hasattr(mean, 'raw_molecular_counts') or not hasattr(
                mean, 'raw_molecular_wfov_counts') or not hasattr(
                    mean, 'msl_altitudes'):
            print
            print 'WARNING: Missing value for wfov calculation. skipped'
            print "hasattr(r_inv,'raw_molecular_wfov_counts') = ", hasattr(
                mean, 'raw_molecular_wfov_counts')
            print "hasattr(r_inv,'msl_altitudes') = ", hasattr(
                mean, 'msl_altitudes')
            return r_mean

        if not hasattr(r_mean, 'raw_molecular_wfov_counts') or not hasattr(
                r_mean, 'msl_altitudes'):
            return r_mean

        if not hasattr(r_mean, 'calibration_wfov_mol_ratio'):
            print 'CALIBRATION WFOV mol ratio missing!'
            return r_mean

        if r_mean.msl_altitudes[-1] < (correct_below_range + z_norm_interval +
                                       r_mean.lidar_altitude):
            print 'WARNING--max altitude two low for wfov correction--no corr applied'
            print '         wfov cor requires max alt >', (
                correct_below_range + z_norm_interval + r_mean.lidar_altitude)
            return r_mean

        data_len = len(mean.raw_molecular_counts[0, :])
        msl_altitudes = mean.msl_altitudes

        #distance between altitude bins
        adz = hau.Z_Array(np.zeros(msl_altitudes.shape))
        adz[1:] = msl_altitudes[1:] - msl_altitudes[:-1]
        adz[0] = adz[1]

        t_window_pts = ntimes
        ones_array = np.ones_like(mean.raw_molecular_counts)
        molecular_wfov_counts = (mean.raw_molecular_wfov_counts -
                                 mean.m_wfov_dark_counts * ones_array)
        molecular_counts = (mean.raw_molecular_counts -
                            mean.mol_dark_counts * ones_array)

        if 0:

            import matplotlib.pylab as plt
            plt.figure(1111)
            plt.plot(msl_altitudes, np.nanmean(molecular_counts,
                                               0), 'c', msl_altitudes,
                     46 * (np.nanmean(molecular_wfov_counts, 0)), 'r')
            ax = plt.gca()
            ax.set_yscale('log')
        #filter in time
        t_pts = np.arange(len(molecular_counts[:, 0]))
        fit_time = datetime.utcnow()

        top_norm_bin = len(msl_altitudes[msl_altitudes <= correct_below_range +
                                         z_norm_interval])
        top_bin = len(msl_altitudes[msl_altitudes <= correct_below_range])
        bot_bin = len(msl_altitudes[msl_altitudes <= min_fit_alt])

        if t_filter_order <> 1:
            pc = np.polyfit(t_pts, molecular_counts, t_filter_order)
            filtered_molecular_counts = np.polyval(pc, useindex)
            pcw = np.polyfit(t_pts, molecular_wfov_counts, t_filter_order)
            filtered_molecular_wfov_counts = np.polyval(pcw, useindex)
            pcw = np.polyfit(t_pts, mean.raw_molecular_wfov_counts,
                             t_filter_order)
            filtered_raw_molecular_wfov_counts = np.polyval(pcw, useindex)
        else:  # simplified computation when fit is linear
            filtered_molecular_counts = np.nanmean(
                molecular_counts[:, :top_norm_bin], 0)
            filtered_molecular_wfov_counts = np.nanmean(
                molecular_wfov_counts[:, :top_norm_bin], 0)
            filtered_raw_molecular_wfov_counts = np.nanmean(
                mean.raw_molecular_wfov_counts[:, :top_norm_bin], 0)

        wfov_mol_ratio = filtered_molecular_wfov_counts / filtered_molecular_counts

        #wfov_mol_ratio is now ratioed to the value measured with the geometric correction
        wfov_mol_ratio /= mean.calibration_wfov_mol_ratio[:top_norm_bin]
        if 0:
            import matplotlib.pylab as plt
            plt.figure(6666)
            plt.plot(np.arange(top_norm_bin),wfov_mol_ratio,'b'\
                     ,np.arange(top_norm_bin),wfov_mol_ratio[:top_norm_bin],'r')

        # add functional code here.
        #   'inv' is a normal 2-D frame of data (read only)
        #   'r_inv' is the 1-D frame to be returned.
        #   'useindex' is the time index of the 'r_inv' frame within 'inv'

        #normalize wfov_correction by mean value between top_bin and 1.5 km above top_bin

        wfov_mol_ratio /= np.nanmean(wfov_mol_ratio[top_bin:top_norm_bin])
        #wfov_mol_ratio /= wfov_mol_ratio[top_bin]

        if 0:
            import matplotlib.pylab as plt
            plt.figure(6667)
            plt.plot(msl_altitudes[:top_norm_bin],wfov_mol_ratio,'g'\
                     ,msl_altitudes[:top_norm_bin],wfov_mol_ratio[:top_norm_bin],'r')
            plt.grid(True)

        #bin_vec = np.arange(len(wfov_mol_ratio))
        #smoothed_wfov_mol_ratio = np.ones_like(wfov_mol_ratio)
        bin_vec = np.arange(top_norm_bin)
        smoothed_wfov_mol_ratio = np.ones(len(msl_altitudes))
        if enable_z_fit == "spline":
            #wfov fit with spline
            #forces correction factor to 1.0 and slope to zero at top of layer
            #weights = np.sqrt(filtered_molecular_wfov_counts[bot_bin:top_bin])
            weights = filtered_molecular_wfov_counts[bot_bin:top_bin] \
                      / np.sqrt(filtered_raw_molecular_wfov_counts[bot_bin:top_bin])
            temp = wfov_mol_ratio[bot_bin:top_bin].copy()
            weights = weights[np.isnan(temp) == 0]
            bins = bin_vec[bot_bin:top_bin].copy()
            bins = bins[np.isnan(temp) == 0]
            temp = temp[np.isnan(temp) == 0]

            #force correction factor to 1.0 and slope = 0.0 at top of corrected layer
            temp[-2:] = 1.0
            weights[-2:] = 1000.0

            npts = bins.shape[0] - 1 - 2
            s = 0.05 * (npts - np.sqrt(2 * npts))
            tck = splrep(bins, temp, w=weights, s=s)
            smoothed_wfov_mol_ratio[bot_bin:top_bin] = splev(
                bin_vec[bot_bin:top_bin], tck)
        elif enable_z_fit == "polynomial":  #smooth over ranges bot_bin to top_bin if enabled
            # 'wfov correction using polynomial fit'
            temp = wfov_mol_ratio[bot_bin:top_bin].copy()
            temp[np.isnan(temp)] = 0
            p = leastsq(residuals
                    ,x0=np.array([-1.0e-5,0.0000,0.0])
                    ,args=(bin_vec[bot_bin:top_bin] \
                    ,temp))

            #use fitted values between min_fit_alt and fit_below_alt
            smoothed_wfov_mol_ratio[bot_bin:top_bin] = func3(
                bin_vec[bot_bin:top_bin], p[0])

        else:  #no smoothing
            # 'wfov correction with no range smoothing'
            smoothed_wfov_mol_ratio[:top_bin] = wfov_mol_ratio[:top_bin]

        #make value constant below bot_bin
        smoothed_wfov_mol_ratio[:bot_bin] = smoothed_wfov_mol_ratio[bot_bin]

        #smallestval=nanmin(smoothed_wfov_mol_ratio[smoothed_wfov_mol_ratio>0.0])
        #smoothed_wfov_mol_ratio[np.logical_not(smoothed_wfov_mol_ratio>0.0)]=smallestval

        if 0:  #plot fit as function of altitude
            import matplotlib.pylab as plt
            plt.figure(6668)
            plt.plot(msl_altitudes[:top_bin], wfov_mol_ratio[:top_bin], 'c',
                     msl_altitudes[bot_bin:top_bin],
                     smoothed_wfov_mol_ratio[bot_bin:top_bin], 'r',
                     msl_altitudes[top_bin:],
                     smoothed_wfov_mol_ratio[top_bin:], 'g')
            plt.grid(True)
            plt.xlabel('Range (m)')
            plt.ylabel('Correction')
            ax = plt.gca()
            ax.set_ylim(0.7, 1.1)
            ax.set_xlim(0, 8000)

            #plt.show()
        r_mean.filtered_wfov_mol_ratio = hau.TZ_Array(
            np.ones(r_mean.raw_molecular_counts.shape))

        #no correction for NaN points
        smoothed_wfov_mol_ratio[np.isnan(smoothed_wfov_mol_ratio)] = 1.0
        #limit size of correction
        smoothed_wfov_mol_ratio[smoothed_wfov_mol_ratio < 0.5] = 0.5

        r_mean.filtered_wfov_mol_ratio[0, :] = smoothed_wfov_mol_ratio

        r_mean.wfov_extinction_corr = hau.TZ_Array(
            np.zeros(r_mean.raw_molecular_counts.shape))
        r_mean.wfov_extinction_corr[
            0, 1:top_bin - 1] = smoothed_wfov_mol_ratio[
                2:top_bin] - smoothed_wfov_mol_ratio[:top_bin - 2]
        r_mean.wfov_extinction_corr[0,1:top_bin-1] = -0.25 * r_mean.wfov_extinction_corr[0,1:top_bin-1] \
                                               /(smoothed_wfov_mol_ratio[1:top_bin-1] * adz[1:top_bin-1])

        # make wfov geo correction to mean counts.
        for chan in vars(r_mean).keys():
            if not chan.endswith('_counts'):
                continue
            applyFilter = True
            for badPart in ['dark', 'raw_', 'var_', 'wfov']:
                if badPart in chan:
                    applyFilter = False
                    break
            if not applyFilter:
                continue
            if hasattr(r_mean, chan):
                setattr(
                    r_mean, chan,
                    (getattr(r_mean, chan) * r_mean.filtered_wfov_mol_ratio))

        return r_mean
Ejemplo n.º 8
0
def read_raqms_file(instrument, start_time):
    """read raqms file between start and end time

    instrument - e.g. 'gvhsrl'
    start_time -  datetime object    
    
    """

    raqms = hau.Time_Z_Group(altname='model_level_alts')

    filename = find_raqms_filename(instrument, start_time)
    if not filename:
        return None

    nc = Dataset(filename, 'r')
    times = getAll(nc, 'time')
    aircraft_alts = getAll(nc, 'alt')
    pressures = getAll(nc, 'pressure')
    temperatures = getAll(nc, 'temperature')
    model_level_alts = getAll(nc, 'altitude')

    relative_humidity = getAll(nc, 'rh')
    latitude = getAll(nc, 'lat')
    longitude = getAll(nc, 'lon')
    u_vel = getAll(nc, 'uvel')
    v_vel = getAll(nc, 'vvel')
    ext_total = getAll(nc, 'ext_tot')
    ext_dust = getAll(nc, 'ext_dust')
    ext_salt = getAll(nc, 'ext_salt')

    base_time = datetime(start_time.year, start_time.month, start_time.day, 0,
                         0, 0)
    #np.fix(start_time)
    #time=times.astype('float64')

    #convert raqms seconds from start of day to python datetimes
    #times=base_time + time/(3600.0*24.0)
    times = hau.T_Array(
        [base_time + timedelta(seconds=float(x)) for x in times])

    assert (times.size > 0)

    selectedMask = (times > start_time)
    for i, x in enumerate(selectedMask):
        fi = i
        if x:
            if i > 0:
                selectedMask[i - 1] = True
            break
    selectedMask[-1] = True

    selectedTimes = np.arange(times.size)[selectedMask]

    raqms.latitude = hau.T_Array(latitude[selectedTimes])
    raqms.longitude = hau.T_Array(longitude[selectedTimes])
    raqms.pressures = hau.TZ_Array(pressures[selectedTimes, :])
    raqms.temperatures = hau.TZ_Array(temperatures[selectedTimes, :])
    raqms.ext_total = hau.TZ_Array(ext_total[selectedTimes, :])
    raqms.ext_dust = hau.TZ_Array(ext_dust[selectedTimes, :])
    raqms.ext_salt = hau.TZ_Array(ext_salt[selectedTimes, :])
    raqms.relative_humidity = hau.TZ_Array(relative_humidity[selectedTimes, :])
    raqms.u_vel = hau.TZ_Array(u_vel[selectedTimes, :])
    raqms.v_vel = hau.TZ_Array(v_vel[selectedTimes, :])
    raqms.model_level_alts = hau.TZ_Array(model_level_alts[selectedTimes, :] *
                                          1000.0)
    raqms.times = times[selectedTimes]

    return raqms
Ejemplo n.º 9
0
def select_raqms_profile(soundings,
                         request_time,
                         requested_altitudes,
                         offset=0):
    """selects sounding prior to request_time from soundings -- the sounding
       is returned in a Time_Z_Group as Z_arrays"""

    if soundings is None or soundings.times.size == 0:
        raise RuntimeError, "select_faqms_profile: No soundings for %s " %\
              request_time

    import atmospheric_profiles.soundings.sounding_utilities as su
    sounding = hau.Time_Z_Group()

    sounding.altitudes = hau.Z_Array(requested_altitudes)
    max_alt = requested_altitudes[-1]
    max_bin = len(requested_altitudes)
    index = sum(soundings.times <= request_time) - 1 + offset

    if index < 0 or index >= len(soundings.times):
        return None
    #initialize variables for inclusion in T_Z_Group
    sounding.temps = hau.Z_Array(np.zeros((max_bin)))
    sounding.dew_points = hau.Z_Array(np.zeros(max_bin))
    sounding.frost_points = hau.Z_Array(np.zeros(max_bin))
    sounding.pressures = hau.TZ_Array(np.zeros(max_bin))
    sounding.ext_total = hau.TZ_Array(np.zeros(max_bin))
    sounding.ext_salt = hau.TZ_Array(np.zeros(max_bin))
    sounding.wind_spd = hau.TZ_Array(np.zeros(max_bin))
    sounding.wind_dir = hau.TZ_Array(np.zeros(max_bin))

    #sounding.times is a single time at this point, however it will later be included
    #in a list of all the soundings used in this processing request. In order that it
    #be treated properly it must be defined as a T_Array

    sounding.times = hau.T_Array([soundings.times[index]])
    sounding.latitude = hau.T_Array([soundings.latitude[index]])
    sounding.longitude = hau.T_Array([soundings.longitude[index]])

    #sounding.times=hau.T_Array([soundings.times[index]])

    #interpolate model levels to lidar bin altitudes

    #temp=interpolate.splrep(soundings.model_level_alts[index,-1::-1] \
    #     ,soundings.temperatures[index,-1::-1])
    #sounding.temps=interpolate.splev(sounding.altitudes,temp,der=0)

    temp=interpolate.splrep(soundings.model_level_alts[index,-1::-1] \
                            ,soundings.pressures[index,-1::-1])
    sounding.pressures = interpolate.splev(sounding.altitudes, temp, der=0)



    sounding.temps=np.interp(sounding.altitudes \
                             ,soundings.model_level_alts[index,-1::-1] \
                             ,soundings.temperatures[index,-1::-1])

    #calculate dew point at model levels for selected profile
    dew_pts=su.cal_dew_point(soundings.relative_humidity[index,:] \
                             ,soundings.temperatures[index,:])
    frost_pts = su.cal_frost_point(dew_pts)

    #calculate wind speed and direction from u and v
    u_vel = soundings.u_vel[index, -1::-1]
    v_vel = soundings.v_vel[index, -1::-1]

    wind_spd = np.sqrt(u_vel**2 + v_vel**2)
    wind_dir = np.arctan(v_vel / u_vel) * 180.0 / np.pi

    for i in range(len(u_vel)):
        if (u_vel[i] < 0 and v_vel[i]) < 0:
            wind_dir[i] = 180.0 - wind_dir[i]
        elif (u_vel[i] > 0 and v_vel[i]) > 0:
            wind_dir[i] = 180.0 + wind_dir[i]
        elif u_vel[i] < 0:
            wind_dir[i] = 270.0 - wind_dir[i]
        else:
            wind_dir[i] = np.nan

    #interpolate to lidar bin altitudes
    sounding.frost_points=np.interp(sounding.altitudes \
                                    ,soundings.model_level_alts[index,-1::-1],frost_pts[-1::-1])
    sounding.dew_points=np.interp(sounding.altitudes \
                                  ,soundings.model_level_alts[index,-1::-1],dew_pts[-1::-1])
    sounding.ext_total=np.interp(sounding.altitudes\
                                 ,soundings.model_level_alts[index,-1::-1]\
                                 ,soundings.ext_total[index,-1::-1])
    sounding.ext_salt=np.interp(sounding.altitudes\
                                ,soundings.model_level_alts[index,-1::-1]\
                                ,soundings.ext_salt[index,-1::-1])
    sounding.ext_dust=np.interp(sounding.altitudes\
                                ,soundings.model_level_alts[index,-1::-1]\
                                ,soundings.ext_dust[index,-1::-1])



    sounding.wind_dir = np.interp(sounding.altitudes \
                                  ,soundings.model_level_alts[index,-1::-1],wind_dir)
    sounding.wind_spd = np.interp(sounding.altitudes \
                                  ,soundings.model_level_alts[index,-1::-1],wind_spd)

    sounding.top = sounding.altitudes[-1]
    sounding.bot = sounding.altitudes[0]

    #plt.figure(1)
    #plt.plot(temperatures,altitudes,dew_points,altitudes)

    #plt.figure(2)
    #plt.plot(ext_total,altitudes)
    #plt.show()
    return sounding
Ejemplo n.º 10
0
def compute_optical_depth(Nm,
                          beta_r_backscat,
                          msl_altitudes,
                          processing_defaults,
                          constants,
                          telescope_pointing=None):
    """uses Nm and beta_r_backscat to compute the optical
       depth profile with the optical depth profile set to zero at
       an alititude given by 'mol_norm_alt' which must provided
       in meters.
       returns:
           od = total optical depth
           od_aerosol = aerosol optical depth
           mol_norm_index = bin number at which optical depth is normalized to zero
           mol_ref_aod = estimated optical depth at altitudes[mol_norm_index]"""

    #mol_od_between_lidar_and_norm_alt = 0.0
    mol_norm_alt = processing_defaults.get_value('mol_norm_alt', 'meters')
    mol_norm_index = len(msl_altitudes[msl_altitudes <= mol_norm_alt])
    if processing_defaults.enabled('molecular_smooth'):
        window_offset = np.float(
            processing_defaults.get_value('molecular_smooth',
                                          'window_length')) / 2.0
    else:
        window_offset = 0.0
    if ('installation' not in constants or constants['installation'] == 'ground'
               or constants['installation'] == 'shipborne')\
               and mol_norm_alt < (constants['lidar_altitude']+150.0 + window_offset):
        mol_norm_alt = constants['lidar_altitude'] + 150. + window_offset
        mol_norm_index = len(msl_altitudes[msl_altitudes <= mol_norm_alt])
        lidar_alt_index = len(
            msl_altitudes[msl_altitudes <= constants['lidar_altitude']])

        print 'requested molecular norm altitude too low--  reset at ', mol_norm_alt, ' m'
        processing_defaults.set_value('mol_norm_alt', 'meters', mol_norm_alt)
    od = hau.TZ_Array(np.NaN * np.zeros_like(Nm))
    indices = np.arange(len(msl_altitudes))

    if processing_defaults.enabled('molecular_smooth'):
        window = processing_defaults.get_value('molecular_smooth',
                                               'window_length')
        if mol_norm_alt < constants['lidar_altitude'] + 150 + window / 2.0:
            mol_norm_alt = constants['lidar_altitude'] + 150 + window / 2.0
            mol_norm_index = len(msl_altitudes[msl_altitudes <= mol_norm_alt])
            print ' '
            print 'Warning:******requested mol_normalization_altitude not within acquired data'
            print '      setting normalization altitude = ', msl_altitudes[
                mol_norm_index]
            print ' '
    if mol_norm_index >= len(msl_altitudes):
        mol_norm_index = len(msl_altitudes) - 1
        print ' '
        print 'Warning:******requested normalization altitude higher than requested range'
        print '     setting normalization altitude =', msl_altitudes[
            mol_norm_index]

    if mol_norm_index <= Nm.shape[1]:
        if 0:
            print
            print
            print 'alts', msl_altitudes.shape
            print 'beta_r', beta_r_backscat.shape
            print 'Nm', Nm.shape
            print 'norm_alt', msl_altitudes[mol_norm_index]
            print
            import matplotlib.pylab as plt
            plt.figure(2000)
            plt.plot(
                msl_altitudes,
                np.nanmean(Nm, 0) * beta_r_backscat[mol_norm_index] /
                np.nanmean(Nm[:, mol_norm_index], 0), msl_altitudes,
                beta_r_backscat)
            plt.ylabel('altitude')
            ax = plt.gca()
            ax.set_yscale('log')
            plt.grid(True)

        time_vec = np.ones_like(Nm[:, 0])
        bin_vec = np.ones_like(beta_r_backscat)
        beta_r_array = (time_vec[:, np.newaxis] *
                        beta_r_backscat[np.newaxis, :])
        Nm_norm_array = Nm[:, mol_norm_index]
        Nm_norm_array = Nm_norm_array[:, np.newaxis] * bin_vec[np.newaxis, :]
        prelog_od = Nm[:, :] / (
            beta_r_array * Nm_norm_array) * beta_r_backscat[mol_norm_index]
        prelog_od[np.isnan(prelog_od)] = 0
        prelog_od[prelog_od <= 0.0] = np.NaN
        od = -0.5 * np.log(prelog_od)
        if telescope_pointing is not None:
            tmpod = od
            od = od.copy()
            od[:, :] = np.NAN
            od[telescope_pointing < 0.1, :] = -1.0 * tmpod[
                telescope_pointing < 0.1, :]
            od[telescope_pointing > 0.9, :] = tmpod[
                telescope_pointing > 0.9, :]
        dz = msl_altitudes[1] - msl_altitudes[0]
        mol_od = 8.0 * np.pi * np.cumsum(beta_r_backscat) * dz / 3.0
        mol_od = mol_od - mol_od[mol_norm_index]

        mol_od_array = time_vec[:, np.newaxis] * mol_od[np.newaxis, :]
        od_aerosol = od - mol_od_array
    else:
        od[:, :] = np.NaN
        od_aerosol[:, :] = od.copy()
        print ' '
        print '*******requested od_normalization altitude not within acquired data'
        print ' '

    #compute optical depth below mol_norm_index
    #extrapolate from just above mol_norm_index to estimate unmeasured optical depth
    if dz >= 100:
        n_bins = 1
    else:
        n_bins = int(100.0 / dz + 1)
    norm_alt_range = msl_altitudes[mol_norm_index] - constants['lidar_altitude']
    mol_ref_aod = (od[:, mol_norm_index + n_bins] -
                   od[:, mol_norm_index]) * (norm_alt_range / (dz * n_bins))
    mol_ref_aod -= (mol_od_array[:,mol_norm_index + n_bins] - mol_od_array[:,mol_norm_index])\
                      *norm_alt_range/(dz*n_bins)
    mol_ref_aod = hau.T_Array(mol_ref_aod)
    od = hau.TZ_Array(od)
    od_aerosol = hau.TZ_Array(od_aerosol)
    return (od, od_aerosol, mol_norm_index, mol_ref_aod)
Ejemplo n.º 11
0
def geometry_correction(apply_to,
                        rs,
                        rs_cal,
                        nbins,
                        s_bin,
                        apply_geo_corr=None):
    """geometry_correction(selected_vars,rs,rs_cal,nalts,s_bin,wfov_mol_ratio=Noneapply_geo_corr=None)
       apply_to       = apply geo correction to these variables
       rs             = structure containing channel counts
       rs_cal         = structure containing geo_corr data
       nbins          = number of altitude bins to process
       s_bin          = range bin containing laser pulse
       wfov_mol_ratio = ratio of molecular_wfov_counts to molecular counts (optional correction)
       apply_geo_corr = 
       """

    for field in apply_to:
        if hasattr(rs, field):
            ones_array = np.ones(getattr(rs, field).shape)
            break
    if apply_geo_corr is None or apply_geo_corr > 0:
        geocorr = rs_cal.geo.geo_correction[:nbins -
                                            s_bin] * ones_array[:, s_bin:nbins]
    elif apply_geo_corr == 0:
        #r-squared correction
        geocorr = (rs_cal.geo.data[:(nbins - s_bin), 0]**2 *
                   ones_array[:, s_bin:nbins]) / 1e6
    else:
        #no correction applied
        return rs

    if hasattr(rs,'telescope_pointing') and hasattr(rs_cal,'ngeo') \
               and (rs.telescope_pointing<0.1).any():
        mask = (rs.telescope_pointing < 0.1)
        indices = arange(ones_array.shape[0])
        indices = indices[mask]
        geocorr[indices,:] = rs_cal.ngeo.data[:nalts - s_bin, 1]\
                    * ones_array[indices, s_bin:nalts]
    for field in apply_to:
        if hasattr(rs, field):
            temp = getattr(rs, field)
            #print 'field_________________________',field
            if 0:  #field == 'nitrogen_counts_low':
                import matplotlib.pylab as plt
                bin_vec = np.arange(temp.shape[1])
                plt.figure(77777)
                plt.plot(bin_vec, temp[0, :], 'b',
                         s_bin + np.arange(nbins - s_bin), geocorr[0, :], 'g')
            temp[:, s_bin:nbins] *= geocorr
            if 0:  #field == 'nitrogen_counts_low':
                plt.plot(bin_vec, np.nanmean(temp, 0), 'r')

            setattr(rs, field, temp)

    #add geo_corr to rs and offset by s_bin to align with range scale of data buffers
    geo_corr = np.zeros(ones_array.shape[1])
    geo_corr[s_bin:nbins] = rs_cal.geo.data[:nbins - s_bin, 1].copy()
    rs.geo_corr = hau.Z_Array(geo_corr)

    #make full resolution geo_corr array with sbin offset to match data arrays
    rs.geo_corr_array = hau.TZ_Array(np.zeros(ones_array.shape))
    rs.geo_corr_array[:, s_bin:nbins] = geocorr
    return rs
Ejemplo n.º 12
0
    def profile(self, request_time, request_lat, request_long, offset=0):
        """returns a profile of temperature,pressure, dew_point, frost point at 
        time, lat, and long extracted from the sounding_archive. If request_lat and
        request_long are empty they are ignored
        request_time = python datetime for reqested sounding
        request_lat  = requested latitude for sounding--ignored if []
        request_lon  = requested longitude for sounding--ignored if []"""

        if self.soundings == None:
            return None

        print 'sounding_type= ', self.sounding_type, request_time
        if self.sounding_type == 'NOAA raob':
            temp_sounding = hau.Time_Z_Group()

            #find correct sounding profile out of archive file
            sounding = hau.selectByTime(self.soundings,
                                        request_time,
                                        offset=offset)
            if sounding is None:
                return None

            sounding.sounding_type = self.sounding_type
            sounding.sounding_id = sounding.station_id
            sounding.latitude = sounding.stalat
            sounding.longitude = sounding.stalong
            sounding.frost_points = cal_frost_point(sounding.dew_points)

            temp_sounding.type = self.sounding_type
            temp_sounding.times = sounding.times
            temp_sounding.altitudes = hau.Z_Array(sounding.altitudes)
            temp_sounding.temps = hau.TZ_Array(sounding.temps[np.newaxis, :])
            temp_sounding.pressures = hau.TZ_Array(
                sounding.pressures[np.newaxis, :])
            temp_sounding.dew_pts = hau.TZ_Array(
                sounding.dew_points[np.newaxis, :])
            temp_sounding.frost_pts = hau.TZ_Array(
                sounding.frost_points[np.newaxis, :])
            temp_sounding.wind_dir = hau.TZ_Array(
                sounding.wind_dir[np.newaxis, :])
            temp_sounding.wind_spd = hau.TZ_Array(
                sounding.wind_spd[np.newaxis, :])
            temp_sounding.wind_spd = hau.TZ_Array(
                sounding.wind_spd[np.newaxis, :])
            temp_sounding.station_id = sounding.station_id
            temp_sounding.top = sounding.top

            sounding.times = sounding.times[0]
            #sounding.expire_time=sounding.expire_time[0]

        elif self.sounding_type == "time curtain" \
                  and self.sounding_id == "raqms":

            temp_sounding = hau.Time_Z_Group()
            sounding = raqms.select_raqms_profile(self.soundings,request_time \
                       ,self.requested_altitudes,offset=offset)
            #                      ,self.max_alt,self.alt_res)
            if sounding == None:
                return None
            sounding.station_id = self.sounding_id

            temp_sounding.type = self.sounding_type
            temp_sounding.times = sounding.times
            temp_sounding.latitude = hau.T_Array(sounding.latitude)
            temp_sounding.longitude = hau.T_Array(sounding.longitude)
            temp_sounding.altitudes = hau.Z_Array(sounding.altitudes)
            temp_sounding.temps = hau.TZ_Array(sounding.temps[np.newaxis, :])
            temp_sounding.pressures = hau.TZ_Array(
                sounding.pressures[np.newaxis, :])
            temp_sounding.dew_pts = hau.TZ_Array(
                sounding.dew_points[np.newaxis, :])
            temp_sounding.frost_pts = hau.TZ_Array(
                sounding.frost_points[np.newaxis, :])
            temp_sounding.wind_dir = hau.TZ_Array(
                sounding.wind_dir[np.newaxis, :])
            temp_sounding.wind_spd = hau.TZ_Array(
                sounding.wind_spd[np.newaxis, :])
            temp_sounding.ext_total = hau.TZ_Array(
                sounding.ext_total[np.newaxis, :])
            temp_sounding.ext_salt = hau.TZ_Array(
                sounding.ext_salt[np.newaxis, :])
            temp_sounding.ext_dust = hau.TZ_Array(
                sounding.ext_dust[np.newaxis, :])
            temp_sounding.wind_spd = hau.TZ_Array(
                sounding.wind_spd[np.newaxis, :])
            temp_sounding.station_id = sounding.station_id
            temp_sounding.top = sounding.top

            sounding.times = sounding.times[0]

            #set up time to read in new sounding (in datetime)
            #sounding.expire_time = sounding.times+timedelta(seconds=5*60)
            #expire time can not be less then request time--raqms file must be missing soundings
            #set expire_time 5 minutes after request time
            #if sounding.expire_time <= request_time:
            #    print "****Warning----missing raqms sounding at ",request_time
            #    print "               using sounding from ",sounding.times
            #    sounding.expire_time = request_time + timedelta(seconds=5*60)

        #remove any negative pressure values
        temp_sounding.pressures[temp_sounding.pressures < 0] = 0.0
        #remove NaN's from pressure and temperature values
        temp_sounding.pressures[np.isnan(temp_sounding.pressures)] = 0.0
        temp_sounding.temps[np.isnan(temp_sounding.temps)] = 1.0
        return sounding
Ejemplo n.º 13
0
def read_sounding_file(instrument, sounding_type, id, start_time,
                       requested_altitudes):
    """ read_sounding_file([instrument,sounding_type,id,start_time,alt_res,max_alt)   
     returns arrays rs.temps(sounding#, rs.dew_points(sounding#,alt_index),
     rs.wdir(sounding#,alt_index), rs.wspd(sounding#,alt_index) along with several
     scalers with sounding info instrument (e.g. 'ahsrl','gvhsrl','mf2hsrl','nshsrl')
     sounding_type may be radiosonde station id, model identifier, or other instrument
     sounding_type (e.g. 'NOAA','ARM',.......
     sounding id (for sounding_type=NOAA, this a 3-letter e.g. 'MSN')
     start_time first time for which the sounding is needed, provided as matplot time
     requested_altitudes is a vector of altitudes at which sounding values are requested (m) 
     returns temp_sounding(object) with all soundings from the current file after the starting time
     returns the last time at which this sounding can be used as rs.expire_time"""

    import lg_dpl_toolbox.core.archival as hru

    if sounding_type[:].find('NOAA raob') >= 0:
        rs = hau.Time_Z_Group()

        time_struct = start_time
        dir_path = hru.get_path_to_data(instrument, start_time)
        filename = dir_path + '/' + '%4i' % time_struct.year + '/' \
            + '%02i' % time_struct.month + '/sondes.' + id[:] + '.nc'
        print 'sounding file--', filename
        if not os.path.exists(filename):
            return None
            #raise RuntimeError, 'sounding file %s does not exist' \
            #    % filename
        nc = Dataset(filename, 'r')
        times = getAll(nc, 'synTime')

        # combine mandatory and sig height measurements

        heights = np.hstack((getAll(nc, 'htMan'), getAll(nc, 'htSigT')))

        epoch = datetime(1970, 1, 1, 0, 0, 0)
        t_mask = times < 1e36
        for i in range(len(times)):
            t_mask[i] = times[i] < 1e36 and any(heights[i, :] < 1e36)

        times = times[t_mask]

        times = [epoch + timedelta(seconds=soff) for soff in times[:]]

        # select times, one prior to start time --> last profile in file

        #indices = np.arange(len(times))
        #start_index = max(indices[times <= start_time])
        #rs.times = zeros(len(times) - start_index)
        rs.times = np.zeros(len(times))
        #rs.times = times[start_index:]
        #         rs.times = hau.T_Array( rs.times )
        rs.times = times[:]

        wmosta = getAll(nc, 'wmoStat')  # wmo station number
        stalong = getAll(nc, 'staLon')
        stalat = getAll(nc, 'staLat')

        # combine mandatory and sig height measurements

        temps = np.hstack((getAll(nc, 'tpMan'), getAll(nc, 'tpSigT')))
        pressures = np.hstack((getAll(nc, 'prMan'), getAll(nc, 'prSigT')))
        dew_points = np.hstack((getAll(nc, 'tdMan'), getAll(nc, 'tdSigT')))
        wind_dir = np.hstack((getAll(nc, 'wdMan'), getAll(nc, 'wdSigT')))
        wind_spd = np.hstack((getAll(nc, 'wsMan'), getAll(nc, 'wsSigT')))
        heights = heights[t_mask, :]
        temps = temps[t_mask, :]
        pressures = pressures[t_mask, :]
        dew_points = dew_points[t_mask, :]
        wind_dir = wind_dir[t_mask, :]
        wind_spd = wind_spd[t_mask, :]

        [n_soundings, n_heights] = temps.shape

        # defined standard atmosphere climatology for use above highest reported level
        # climate=temp_sounding()

        climate = hau.Time_Z_Group()
        climate.altitudes = np.zeros((n_soundings, 9))
        climate.temps = np.zeros((n_soundings, 9))
        climate.pressures = np.zeros((n_soundings, 9))
        climate.dew_pt = np.zeros((n_soundings, 9))
        climate.wind_spd = np.zeros((n_soundings, 9))
        climate.wind_dir = np.zeros((n_soundings, 9))

        # find the highest valid point in each sounding

        rs.top = np.zeros((n_soundings, ))
        rs.bot = np.zeros((n_soundings, ))

        # climate.altitudes[0,:]=array([10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000])

        for i in range(n_soundings):
            mask = heights[i, :] <= 50000
            if np.any(mask == True):
                rs.top[i] = max(heights[i, mask])
                rs.bot[i] = min(heights[i, temps[i, :] != 99999])
            else:
                rs.top[i] = 0.0
                rs.bot[i] = 0.0

            rs.top = hau.T_Array(rs.top)
            rs.bot = hau.T_Array(rs.bot)
            climate.altitudes[i, :] = np.array([
                10000,
                15000,
                20000,
                25000,
                30000,
                35000,
                40000,
                45000,
                50000,
            ])
            climate.temps[i, :] = np.array([
                223.1,
                216,
                216,
                221,
                226,
                237,
                251,
                265,
                270,
            ])
            climate.pressures[i, :] = np.array([
                264.3,
                120.45,
                54.75,
                25.11,
                11.71,
                5.58,
                2.77,
                1.43,
                0.759,
            ])
            climate.dew_pt[i, :] = np.NaN

            # don't use climatology lower than 2km above highest valid measurement

            climate.altitudes[climate.altitudes <= rs.top[i] + 2000] = \
                9e36
            climate.temps[climate.altitudes <= rs.top[i] + 2000] = 9e36
            climate.pressures[climate.altitudes <= rs.top[i] + 2000] = \
                9e36

    # stack the climatology on top of the observations

        heights = np.hstack((heights, climate.altitudes))
        temps = np.hstack((temps, climate.temps))
        pressures = np.hstack((pressures, climate.pressures))
        dew_points = np.hstack((dew_points, climate.dew_pt))
        wind_dir = np.hstack((wind_dir, climate.wind_dir))
        wind_spd = np.hstack((wind_spd, climate.wind_spd))
        #print heights.shape
        heights_unsorted = heights.copy()
        temps_unsorted = temps.copy()
        pressures_unsorted = pressures.copy()
        dew_points_unsorted = dew_points.copy()
        wind_dir_unsorted = wind_dir.copy()
        wind_spd_unsorted = wind_spd.copy()

        for i in range(heights_unsorted.shape[0]):
            indices = np.argsort(heights_unsorted[i, :])
            heights[i, :] = heights_unsorted[i, indices]
            temps[i, :] = temps_unsorted[i, indices]
            pressures[i, :] = pressures_unsorted[i, indices]
            dew_points[i, :] = dew_points_unsorted[i, indices]
            wind_dir[i, :] = wind_dir_unsorted[i, indices]
            wind_spd[i, :] = wind_spd_unsorted[i, indices]

    # sort combined file by height and select times of interest
        if 0:
            indices = heights.argsort(axis=1)
            index_a = np.transpose(
                np.transpose(np.ones(heights.shape, dtype=int)) *
                np.arange(heights.shape[0]))
            heights = heights[index_a, indices]
            temps = temps[index_a, indices]
            pressures = pressures[index_a, indices]
            dew_points = dew_points[index_a, indices]
            wind_dir = wind_dir[index_a, indices]
            wind_spd = wind_spd[index_a, indices]

        pressures[heights > 1e5] = np.NaN
        temps[heights > 1e5] = np.NaN
        dew_points[heights > 1e5] = np.NaN

        # interpolate to altitude resolution requested
        # and remove missing data points

        max_alt = requested_altitudes[-1]
        max_bin = requested_altitudes.shape[0]
        alts = requested_altitudes

        n_soundings = len(rs.times)
        #max_bin = round(max_alt / float(alt_res)) + 1

        # create sounding arrays as hau class items

        rs.altitudes = hau.TZ_Array(np.zeros((n_soundings, max_bin)))
        rs.temps = hau.TZ_Array(np.zeros((n_soundings, max_bin)))
        rs.dew_points = hau.TZ_Array(np.zeros((n_soundings, max_bin)))
        rs.pressures = hau.TZ_Array(np.zeros((n_soundings, max_bin)))
        rs.wind_spd = hau.TZ_Array(np.zeros((n_soundings, max_bin)))
        rs.wind_dir = hau.TZ_Array(np.zeros((n_soundings, max_bin)))

        #rs.times =hau.T_Array(np.zeros(n_soundings))
        rs.times = hau.T_Array(times)
        #rs.expire_time =hau.T_Array(np.zeros(n_soundings))
        rs.stalat = hau.T_Array(np.zeros(n_soundings))
        rs.stalong = hau.T_Array(np.zeros(n_soundings))
        rs.wmosta = hau.T_Array(np.zeros(n_soundings))

        rs.stalat[:] = stalat[0]
        rs.stalong[:] = stalong[0]
        rs.wmosta[:] = wmosta[0]
        rs.station_id = id

        # interpolate to lidar altitude scale

        for i in range(n_soundings):

            rs.altitudes[i, :] = alts
            k = i

            rs.temps[i, :] = np.interp(alts, heights[k, temps[k, :] != 99999],
                                       temps[k, temps[k, :] != 99999])

            rs.dew_points[i, :] = np.interp(
                alts, heights[k, dew_points[k, :] != 99999],
                dew_points[k, dew_points[k, :] != 99999])

            #now using spline fit to pressures
            #should use hydrostatic equation to interpolate

            press1 = pressures[k, pressures[k, :] != 99999]
            h1 = heights[k, pressures[k, :] != 99999]
            temp = interpolate.splrep(h1[~np.isnan(press1)],
                                      press1[~np.isnan(press1)])
            rs.pressures[i, :] = interpolate.splev(alts, temp, der=0)

            rs.wind_spd[i, :] = np.interp(alts,
                                          heights[k, wind_spd[k, :] != 99999],
                                          wind_spd[k, wind_spd[k, :] != 99999])
            rs.wind_dir[i, :] = np.interp(alts,
                                          heights[k, wind_dir[k, :] != 99999],
                                          wind_dir[k, wind_dir[k, :] != 99999])
            #if i < n_soundings - 1:
            #    #rs.expire_time[i] = (rs.times[i] + rs.times[i + 1])
            #    rs.expire_time = rs.times[i] + timedelta(seconds=(rs.times[i+1] - rs.times[i]).total_seconds() / 2.0) + timedelta(seconds=60*30)  # add 1/2 hour to point to next sounding
            #else:
            #    #rs.expire_time[i] = rs.times[i] + 0.25 + 1 / 48.0  # new sonde profile expected in 6 1/2 hrs
            #    rs.expire_time = rs.times[i] + timedelta(days=0.25, seconds= 30*60)  # new sonde profile expected in 6 1/2 hrs

    # convert dew point depression to dew point temp

        rs.dew_points = rs.temps - rs.dew_points

        plots = 0  # FIXME
        if plots == 1:
            import matplotlib.pylab as plt
            plt.figure(801)

            plt.plot(temps[0, :], heights[0, :] / 1000, 'r', dew_points[0, :],
                     heights[0, :] / 1000)
            fig = plt.grid(True)
            plt.xlabel('deg-K ')
            plt.ylabel('Altitude MSL (km)')
            plt.title('Temperature, dew point')

            plt.figure(802)
            #set_printoptions(threshold=np.NaN)

            plt.plot(rs.temps[0, :], rs.altitudes[0, :] / 1000, 'r',
                     rs.dew_points[0, :], rs.altitudes[0, :] / 1000)
            fig = plt.grid(True)
            plt.xlabel('deg-K ')
            plt.ylabel('Altitude MSL (km)')
            plt.title('Temperature, dew point')

            plt.figure(803)
            plt.plot(pressures[0, :], heights[0, :] / 1000, 'r')
            fig = plt.grid(True)
            ax = plt.gca()
            #ax.set_xscale('log')
            plt.xlabel('deg-K ')
            plt.ylabel('Altitude MSL (km)')
            plt.title('Pressures')

            plt.figure(804)
            bin_vec = range(len(heights[0, :]))
            heights[heights > 1000] = np.NaN
            plt.plot(heights[0, :] / 1000, bin_vec, 'r')
            fig = plt.grid(True)
            ax = plt.gca()
            #ax.set_xscale('log')
            plt.xlabel('altitudes')
            plt.ylabel('bins')
            plt.title('Heights')

            plt.show()
            raise RuntimeError('deliberate abort')
    else:
        print ' '
        print 'ERROR**************unknown sounding source************'
        print ' '
        rs = []
    return rs
Ejemplo n.º 14
0
 def applyCorrection(self, rs_mean):
     rs_mean.cross_pol_counts = hau.TZ_Array(self.virtual_cross_counts)
     rs_mean.combined_counts = hau.TZ_Array(self.virtual_total_counts)
     rs_mean.molecular_counts = hau.TZ_Array(self.virtual_mol_counts)
     # insert other computed variables here
     rs_mean.f11 = hau.TZ_Array(self.f11)
     rs_mean.f12 = hau.TZ_Array(self.f12)
     rs_mean.f13 = hau.TZ_Array(self.f13)
     rs_mean.f14 = hau.TZ_Array(self.f14)
     rs_mean.f22 = hau.TZ_Array(self.f22)
     rs_mean.f23 = hau.TZ_Array(self.f23)
     rs_mean.f24 = hau.TZ_Array(self.f24)
     rs_mean.f33 = hau.TZ_Array(self.f33)
     rs_mean.f34 = hau.TZ_Array(self.f34)
     rs_mean.f44 = hau.TZ_Array(self.f44)
Ejemplo n.º 15
0
def process_spheroid_particle(rs_inv,
                              rs_radar,
                              particle_parameters,
                              lambda_radar,
                              entire_frame,
                              sounding=None,
                              size_dist=None):
    """
            process_spheroid_particle(rs_inv,rs_radar,particle_parameters,lambda_radar,entire_frame,
                              sounding=None,p180_water=None,size_dist=None):
            generate and return the particle measurements based on a given hsrl inverted data,
            radar (and its lambda), and particle parameters dictionary
            """

    #create timez group and add heights
    rs_particle = hau.Time_Z_Group(rs_inv.times.copy(),
                                   timevarname='times',
                                   altname='heights')
    setattr(rs_particle, 'heights', rs_inv.msl_altitudes.copy())
    setattr(rs_particle, 'delta_t', rs_inv.delta_t.copy())

    #remove points where lidar signal is noise dominated by setting to
    #very small value.
    #clipped_beta_a_back=rs_inv.beta_a_backscat.copy()
    #if 0: #if hasattr(rs_inv,'std_beta_a_backscat'):
    #    clipped_beta_a_back[clipped_beta_a_back<(2*rs_inv.std_beta_a_backscat)]=-np.inf
    #else:
    #    print 'No std_beta_a_backscat statistics to filter particle measurements'
    #clipped_beta_a_back[np.logical_not(np.isfinite(rs_inv.beta_a_backscat))]=-np.inf;

    rs_particle.q_backscatter = np.NaN * np.zeros_like(rs_inv.beta_a_backscat)
    rs_particle.phase = np.zeros_like(rs_inv.beta_a_backscat)
    rs_particle.phase[
        rs_inv.linear_depol > particle_parameters['h2o_depol_threshold']] = 1
    rs_particle.phase[np.isnan(rs_inv.beta_a_backscat)] = np.NaN

    #set aspect ratio parameter for ice filled bins
    rs_particle.zeta = np.ones(rs_inv.beta_a_backscat.shape)
    rs_particle.zeta[rs_inv.linear_depol > particle_parameters['h2o_depol_threshold']] \
                  = particle_parameters['zeta']

    print 'Extinction cross section for particle size calculations derived from ' \
                ,particle_parameters['ext_source']
    print 'Extinction due nonprecipitating aerosols = '\
                ,particle_parameters['background_aerosol_bs'],'1/(m sr)'

    #store the mask field with the particle info
    rs_particle.qc_mask = rs_inv.qc_mask.copy()

    clipped_beta_a_backscat = rs_inv.beta_a_backscat.copy()
    copy_radar_backscatter = rs_radar.Backscatter.copy()
    #clipped_beta_a_backscat = copy_beta_a.copy()
    clipped_beta_a_backscat = clipped_beta_a_backscat \
              - particle_parameters['background_aerosol_bs']
    clipped_beta_a_backscat[clipped_beta_a_backscat < 0] = np.NaN

    #create an empty mode_diameter array
    rs_particle.mode_diameter = np.zeros_like(rs_inv.beta_a_backscat)

    #create an empty array for extinction--used only for particle calculations
    #bs_ratio_to_dmode will return extinction cross section in clipped_beta_a
    clipped_beta_a = np.NaN * np.zeros_like(rs_inv.beta_a_backscat)

    #water
    #compute mode diameter, extinction cross section, and backscatter efficeincy
    #from radar and lidar backscatter cross sections using mie theory and assumed
    #size distribution to predict mode diameter and q_backscatter for points
    #identified as water.
    if particle_parameters['radar_model'] == "Mie":
        rs_particle.mode_diameter, clipped_beta_a, rs_particle.q_backscatter\
                  ,rs_particle.dstar \
              = size_dist.dmode_from_radar_lidar_mie(copy_radar_backscatter\
                  ,clipped_beta_a_backscat)

    else:
        #use only Rayliegh approx solution--particle_parameter['radar_model']=="Rayleigh"
        #mode diameter is computed for all points assuming everything is water
        #subsequent calculation will replace ice phase points.
        if particle_parameters['ext_source'] == 'ext':
            clipped_beta_a = rs_inv.extinction_aerosol.copy()
        elif particle_parameters['ext_source'] == 'bs/p180':
            clipped_beta_a = clipped_beta_a_backscat / particle_parameters[
                'p180_water']
        else:
            print 'particle_parameters=', particle_parameters[
                'ext_source'], ' not supported'
            print 'in spheroid_particle_processing'
            print j
        clipped_beta_a[np.isnan(clipped_beta_a_backscat)] = np.NaN
        phase = np.zeros_like(rs_inv.beta_a_backscat)
        zeta = np.ones_like(rs_inv.beta_a_backscat)

        rs_particle.mode_diameter = size_dist.dmode_from_lidar_radar_rayleigh(
            rs_particle.mode_diameter, clipped_beta_a, copy_radar_backscatter,
            zeta, phase)

    #ice
    #compute extinction cross section for ice points using backscatter phase function
    clipped_beta_a[rs_particle.phase==1] = \
        clipped_beta_a_backscat[rs_particle.phase==1]/particle_parameters['p180_ice']
    zeta = np.zeros_like(clipped_beta_a)
    zeta[rs_particle.phase == 1] = particle_parameters['zeta']

    #derive mode_diameter directly from radar backscatter and lidar extinction
    #cross sections for parts of image populated by ice
    rs_particle.mode_diameter[rs_particle.phase==1] = size_dist.dmode_from_lidar_radar_rayleigh(\
        rs_particle.mode_diameter[rs_particle.phase==1] \
        ,clipped_beta_a[rs_particle.phase==1],copy_radar_backscatter[rs_particle.phase==1]\
        ,zeta[rs_particle.phase==1],rs_particle.phase[rs_particle.phase==1])

    #creates effective_diameter_prime array from mode diameter
    rs_particle.effective_diameter_prime = \
      size_dist.deff_prime(rs_particle.mode_diameter,rs_particle.phase,zeta)

    rs_particle.effective_diameter = size_dist.eff_diameter(\
                          rs_particle.mode_diameter,rs_particle.phase)

    rs_particle.mean_diameter = size_dist.mean_diameter(\
                          rs_particle.mode_diameter,rs_particle.phase)

    #compute liquid water content for bins with phase == 0
    #bins with phase > 0 will return with NaN's
    if particle_parameters['radar_model'] == "Mie":
        rs_particle.LWC = su.liquid_water_content_mie(
            rs_particle.effective_diameter, clipped_beta_a,
            rs_particle.q_backscatter)
        rs_particle.p180_extinction = rs_inv.beta_a_backscat / rs_particle.q_backscatter

    else:
        if particle_parameters['ext_source'] == 'bs/p180':
            rs_particle.extinction_aerosol = rs_inv.beta_a_backscat / particle_parameters[
                'p180_water']
            clipped_beta_a = rs_particle.extinction_aerosol.copy()
        else:
            clipped_beta_a = rs_inv.extinction_aerosol.copy()
        clipped_beta_a[np.isnan(clipped_beta_a_backscat)] = np.NaN
        rs_particle.LWC = np.NaN * np.zeros_like(
            rs_particle.effective_diameter)
        su.liquid_water_content_ext_approx(rs_particle.LWC,
                                           rs_particle.effective_diameter,
                                           clipped_beta_a, rs_particle.phase)
        rs_particle.p180_extinction = rs_inv.beta_a_backscat / particle_parameters[
            'p180_water']

    rs_particle.extinction_aerosol = rs_inv.extinction_aerosol.copy()
    #compute ice water water content for bins with phase > 0 (kg/m^3)
    #return in LWC array bins with phase > 0
    su.ice_water_content(rs_particle.LWC, rs_particle.effective_diameter,
                         clipped_beta_a, rs_particle.phase)

    if hasattr(rs_radar, 'vertically_averaged_doppler'):
        rs_radar.raw_MeanDopplerVelocity = rs_radar.MeanDopplerVelocity.copy()
        motion_correction = np.transpose(rs_radar.vertically_averaged_doppler\
                            *np.transpose(np.ones_like(rs_radar.MeanDopplerVelocity)))
        rs_radar.MeanDopplerVelocity -= motion_correction

    if sounding != None:
        s_time = datetime.utcnow()

        rs_particle.rw_fall_velocity,rs_particle.mw_fall_velocity \
             ,rs_particle.model_spectral_width,rs_particle.nw_fall_velocity\
             = su.weighted_fall_velocity(
             rs_particle.mode_diameter
            ,particle_parameters
            ,rs_particle.zeta
            ,sounding.temps
            ,sounding.pressures
            ,rs_particle.phase,size_dist)
        print 'time for fall_velocity = ', datetime.utcnow() - s_time

    # compute precip rate (m/s) #rain_rate = 1/density
    # (m^3/kg) * LWC (kg/m^3) * fall_velocity (m/s) #using
    # Doppler velocity rs_particle.hsrl_radar_dv_precip_rate =
    # 0.001 * rs_particle.LWC * rs_radar.MeanDopplerVelocity

    #using raw Doppler to give precip rate in m/s
    rs_particle.hsrl_radar_dv_precip_rate = 0.001 * rs_particle.LWC * rs_radar.MeanDopplerVelocity
    #remove points with Doppler folding
    rs_particle.hsrl_radar_dv_precip_rate[
        rs_radar.MeanDopplerVelocity < -2.0] = np.NaN

    if sounding != None:
        #using modeled mass weighted velocity and dividing by the density of water,
        #                              1000 kg/m^3, to give precip_rate in m/s
        rs_particle.hsrl_radar_precip_rate = 0.001 * rs_particle.LWC * rs_particle.mw_fall_velocity

    #retype all these fields to a proper TZ_Array
    #for f in ['effective_diameter_prime']:
    for f in vars(rs_particle).keys():
        v = getattr(rs_particle, f)
        if isinstance(v, hau.Z_Array):
            continue  #properly typed. continue
        elif isinstance(v, np.ndarray):
            if len(v.shape) == 2:
                setattr(rs_particle, f, hau.TZ_Array(v))
            elif len(v.shape) == 1:
                print '1 Dimensional Variable ' + f + ' will be changed to a T_Array. FIXME!!!!'
                setattr(rs_particle, f, hau.T_Array(v))
            else:
                raise RuntimeError(
                    "I don't know what to type particle array " + f +
                    " with dimensions " + repr(v.shape))
        else:
            pass  #not an array type. should be safe to ignore
    """
            #compute fitting error of computed radar weighted fall velocity
            #to measured Doppler veleocity.
            temp = rs_radar.Backscatter.copy()
            temp[np.isnan(rs_radar.Backscatter)]=0.0
            temp[rs_inv.msl_altitudes>400]=0.0
            fitting_error = np.sqrt(nanmean((rs_particle.rw_fall_velocity[temp >1e-9] \
                                  -  rs_radar.MeanDopplerVelocity[temp >1e-9])**2))
            print
            print rs_radar.times[0],'  --->  ' ,rs_radar.times[-1]
            print 'fitting_error (m/s)= ',fitting_error
            print
            """

    'rs_particle--spher'
    print dir(rs_particle)
    return rs_particle
Ejemplo n.º 16
0
def hsrl_inversion(r_msl, rs_Cxx, rs_constants,corr_adjusts,process_defaults):
    """hsrl_inversion(range_processed_returns,calibration_structure
    ,system_constants)
    
    Invert hsrl raw count data into separate molecular and particulate profiles
    and compute backcatter cross-section and depolarization from the profiles
    returned structure rs always returns:
       times               = times of records
       delta_t             = time seperation between records
       msl_altitudes       = bin altitudes in meters   
       seeded shots        = total number of seeded laser shots in profile
       beta_r_backscat     = Rayleigh scattering cross section from sounding
       Na                  = number of aerosol photon counts
       Nm                  = total number of  molecular counts(including i2a if present)
       Nm_i2               = number of molecular counts in i2 channel
       Na                  = number of particulate counts
       Ncp                 = Ncp photon counts
       linear_depol        = fractional particulate depolarization
       beta_a_backscat     = particulate aerosol backscatter cross-section
       beta_a_backscat_par = par polarization component of backscat cross-section
       beta_a_backscat_perp= perp polarization component of backscat cross-section
       integrated_backscat = cumsum of backscatter cross section in altitude
       
    if i2a channel exists the following are added to rs:
       Nm_i2a = number of molecular photons derived from i2a channel    
       Nm     =  rs.Nm_2i + rs.Nm_i2a
       Ncp_i2a
       beta_a_backscat_par_i2a/Nm
       beta_a_backscat_perp_i2a
       
    if these exist in input file they are added to rs:
       telescope_pointing
       GPS_MSL_Alt
       circular_depol
    """

    rs = hau.Time_Z_Group(like=r_msl)
    # r_msl.molecular_counts is  hau.TZ_Array (2D)
    nalts = r_msl.molecular_counts.shape[1]
    if  rs_Cxx.beta_r.shape[0] < nalts:
        print 'hsrl_inversion(): size too small on calibration arrays : rs_Cxx.beta_r = %d vs nalts = %d. padding cal with last value' % \
            (rs_Cxx.beta_r.shape[0], nalts)
        #assert(rs_Cxx.beta_r.shape[0] != nalts)
        os=rs_Cxx.beta_r.shape[0]
        for k,v in vars(rs_Cxx).items():
          if hasattr(v,'size') and v.size==os:
            ns=list(v.shape)
            ns[0]=nalts
            tmp=np.zeros(ns,dtype=v.dtype)
            tmp[:]=v[-1]
            tmp[:os]=v
            setattr(rs_Cxx,k,tmp)
    elif rs_Cxx.beta_r.shape[0] > nalts:
        print 'WARNING hsrl_inversion(): size larger on calibration arrays. may be an error : rs_Cxx.beta_r = %d vs nalts = %d' % \
            (rs_Cxx.beta_r.shape[0], nalts)
    rs.times = r_msl.times.copy()
    rs.delta_t = r_msl.delta_t.copy()
    rs.msl_altitudes = r_msl.msl_altitudes.copy()
    rs.seeded_shots=r_msl.seeded_shots.copy()
    if hasattr(r_msl,'telescope_pointing'):
        rs.telescope_pointing=r_msl.telescope_pointing.copy()

    # Rayleigh backscatter cross section profile
    rs.beta_r_backscat =  hau.Z_Array(np.zeros(nalts))
    rs.beta_r_backscat[:nalts] = rs_Cxx.beta_r[:nalts] * 3.0 / (8.0 * np.pi)
    #for normal i2 channel
    kk = 1.0 / (rs_Cxx.Cmm[:nalts] - rs_Cxx.Cmc[:nalts] * rs_Cxx.Cam)
    rs.Na =  hau.TZ_Array( kk[:nalts] * (rs_Cxx.Cmm[:nalts] * r_msl.combined_counts\
               - rs_Cxx.Cmc[ : nalts] * r_msl.molecular_counts) )
    rs.Nm =  hau.TZ_Array( kk[:nalts] * (r_msl.molecular_counts \
               - rs_Cxx.Cam * r_msl.combined_counts) )
    rs.Nm_i2 = rs.Nm.copy()
    
    #if data includes an i2a channel we generation a seperate inversion--bagohsrl only
    #systems with i2a channel record linear depolarization
    if hasattr(r_msl,'molecular_i2a_counts') and hasattr(rs_Cxx,'Cmm_i2a'):
       
            kk = 1.0 / (rs_Cxx.Cmm_i2a[:nalts] - rs_Cxx.Cmc[:nalts] * rs_Cxx.Cam_i2a)
            rs.Na_i2a = hau.TZ_Array( kk[:nalts] * (rs_Cxx.Cmm_i2a[:nalts]
                 * r_msl.combined_counts - rs_Cxx.Cmc[ : nalts] * r_msl.molecular_i2a_counts) )
            rs.Nm_i2a =  hau.TZ_Array( kk[:nalts] * (r_msl.molecular_i2a_counts \
                    - rs_Cxx.Cam_i2a * r_msl.combined_counts) )
            rs.Nm = (rs.Nm_i2 + rs.Nm_i2a)/2.0

            #bagohsrl is only hsrl with i2a channel--it measures linear depolarization
            rs.Ncp = rs_constants['combined_to_cross_pol_gain_ratio'] \
                    * (r_msl.cross_pol_counts
                    - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']
                    * r_msl.combined_counts) - rs.Nm_i2 * 0.0035 / (1.0 - 0.0035)
            rs.Ncp_i2a = rs_constants['combined_to_cross_pol_gain_ratio'] \
                    * (r_msl.cross_pol_counts
                    - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']
                    * r_msl.combined_counts) - rs.Nm_i2a * 0.0035 / (1.0 - 0.0035)
           
            if not rs_constants.has_key('no_depol_channel') or rs_constants['no_depol_channel']==0 :   
                rs.linear_depol_i2a = rs.Ncp_i2a / rs.Na_i2a
                #compute the linear depolarization as the average of normal and i2a values
                #note these two componets should be almost identical
                rs.linear_depol = (rs.Ncp + rs.Ncp_i2a)/(rs.Na_i2a + rs.Na)
            
                #when backscatter is small linear_depol can become indeterminate--bound values
                rs.linear_depol[rs.linear_depol < 0.0] = 0.0
                rs.linear_depol[rs.linear_depol > 0.6] = 0.6
            else:
                rs.linear_depol = np.zeros_like(rs.Nm)
                rs.linear_depol_i2a = np.zeros_like(rs.Nm)
                
            rs.beta_a_backscat_perp_i2a=rs.Na_i2a/rs.Nm_i2a \
                            *rs.linear_depol_i2a*rs.beta_r_backscat
            rs.beta_a_backscat_perp = rs.Na/rs.Nm_i2 \
                            *rs.linear_depol * rs.beta_r_backscat
            
            rs.beta_a_backscat_par_i2a = rs.Na_i2a / rs.Nm_i2a * rs.beta_r_backscat
            rs.beta_a_backscat_par = rs.Na / rs.Nm_i2 * rs.beta_r_backscat

            rs.beta_a_backscat = 0.5 *(rs.beta_a_backscat_par +rs.beta_a_backscat_perp \
                       + rs.beta_a_backscat_par_i2a + rs.beta_a_backscat_perp_i2a)

            if rs_constants.has_key('no_i2_channel') and rs_constants['no_i2_channel']==1:
                print
                print 'WARNING--I2 channel is not being used in calculations'
                print "calvals has 'no_i2_channel'== 1"
                print
                rs.linear_depol = rs.Ncp_i2a / rs.Na_i2a 
                rs.beta_a_backscat = rs.beta_a_backscat_par_i2a + rs.beta_a_backscat_perp_i2a 
            
            if not process_defaults.enabled('depolarization_is_aerosol_only'):    
                #user wants bulk depolarization aerosol combined with molecular
                #recompute depolarization
                print 'computing bulk depolarization--aerosol and molecular combined'
                rs.linear_depol = rs_constants['combined_to_cross_pol_gain_ratio'] \
                    * (r_msl.cross_pol_counts\
                    - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']\
                    * r_msl.combined_counts) / r_msl.combined_counts
            #compute circular polarization from linear--good only for vertical pointing systems.    
            rs.circular_depol = 2 * rs.linear_depol / (1 - rs.linear_depol)
            
    elif hasattr(rs_Cxx,'Cmm_i2a') or rs_constants.has_key('polarization_is_linear') \
                and rs_constants['polarization_is_linear']==1:
       if hasattr(rs_Cxx,'Cmm_i2a'):
            print
            print 'hsrl_inversion(): WARNING  i2a counts found, but no calibration'
            print 'computing without i2a channel'
            print
       rs.Ncp = rs_constants['combined_to_cross_pol_gain_ratio'] \
               * (r_msl.cross_pol_counts
               - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']
               * r_msl.combined_counts) - rs.Nm_i2 * 0.0035 / (1.0 - 0.0035)
       rs.linear_depol = rs.Ncp/rs.Na
            
            #when backscatter is small linear_depol can become indeterminate--bound values
       rs.linear_depol[rs.linear_depol < 0.0] = 0.0
       rs.linear_depol[rs.linear_depol > 0.6] = 0.6

       if not process_defaults.enabled('depolarization_is_aerosol_only'):    
                #user wants bulk depolarization aerosol combined with molecular
                #recompute depolarization 
                rs.linear_depol = rs_constants['combined_to_cross_pol_gain_ratio'] \
                    * (r_msl.cross_pol_counts\
                    - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']\
                    * r_msl.combined_counts) / r_msl.combined_counts


       #compute circular from linear--good only for vertical pointing system
       rs.circular_depol = 2*rs.linear_depol /(1 - rs.linear_depol)
       
       rs.beta_a_backscat_perp = rs.Na/rs.Nm_i2 \
                            *rs.linear_depol * rs.beta_r_backscat
       rs.beta_a_backscat_par = rs.Na / rs.Nm * rs.beta_r_backscat
       rs.beta_a_backscat = rs.beta_a_backscat_par +rs.beta_a_backscat_perp
    else: #instrument with no i2a channel and measures circular polarization
        rs.Ncp = rs_constants['combined_to_cross_pol_gain_ratio'] \
                * (r_msl.cross_pol_counts\
                - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']\
                * r_msl.combined_counts) - rs.Nm_i2 * 0.0074 / (1.0 - 0.0074)
        rs.circular_depol = rs.Ncp / rs.Na

        #when Na becomes small, circular_depol may become indeterminate
        # (and don't fault on Nans)
        #rs.circular_depol = np.nan_to_num(rs.circular_depol)
        rs.circular_depol[rs.circular_depol < 0.0] = 0.0
        rs.circular_depol[rs.circular_depol > 3.0] = 3.0

        rs.beta_a_backscat_perp=rs.Na/rs.Nm_i2*rs.circular_depol*rs.beta_r_backscat
        rs.beta_a_backscat_par = rs.Na / rs.Nm_i2 * rs.beta_r_backscat
        rs.beta_a_backscat = rs.beta_a_backscat_par + rs.beta_a_backscat_perp
    
        if not process_defaults.enabled('depolarization_is_aerosol_only'): 
           #user wants bulk depolarization containing both aerosol and molecular
           print 'computing bulk depolarization--air and aerosol together'
           rs.circular_depol = rs_constants['combined_to_cross_pol_gain_ratio'] \
                    * (r_msl.cross_pol_counts\
                    - rs_constants['polarization_cross_talk']*corr_adjusts['pol_x_talk']\
                    * r_msl.combined_counts) / r_msl.combined_counts
        rs.linear_depol = rs.circular_depol / (2
                    + rs.circular_depol)
    #compute integrated backscatter cross section
    rs.integrated_backscat = rs.beta_a_backscat.copy()
    rs.integrated_backscat[np.isnan(rs.integrated_backscat)] = 0.0
    da=rs.msl_altitudes.copy()
    da[:-1]=da[1:]-da[:-1]
    da[-1]=da[-2]
    tda=hau.TZ_Array(np.transpose(da[:,np.newaxis]*np.ones((1,rs.times.size))))
    rs.integrated_backscat = np.cumsum(rs.integrated_backscat,1) \
                 *tda               

    if hasattr(r_msl,'GPS_MSL_Alt'):
        rs.GPS_MSL_Alt = r_msl.GPS_MSL_Alt

    if hasattr(r_msl,'combined_1064_counts'):
        rs.combined_1064_counts = r_msl.combined_1064_counts\
                              * rs_constants['IR_combined_hi_gain_ratio']

    if hasattr(r_msl,'wfov_extinction_corr'):
        #transf wfov_extinction correction to output structure
        rs.wfov_extinction_corr = r_msl.wfov_extinction_corr
  
    return rs