Ejemplo n.º 1
0
def ms_sums(diameter, beta, depol, multiple_scatter_parameters, ms_obj):
    '''  ms_sums(diameter,beta,depol,multiple_scatter_parameters,ms_obj):

             diameter = particle diameter profile or profiles
             beta     = extinction or backscatter cross section profile or profiles
             depol    = depolarization profile or profiles
             returns:
             ms_obj   = summed profiles
               "       .diameter_ice
               "       .diameter_water
               "       .beta_ice
               "       .beta_water
               "       .n_samples_ice
               "       .n_samples_water  '''
    is_ice = np.zeros_like(beta)
    is_water = np.zeros_like(beta)
    is_ice[depol >= multiple_scatter_parameters['h2o_depol_threshold']] = 1.0
    is_water[depol < multiple_scatter_parameters['h2o_depol_threshold']] = 1.0

    #diameter_ice = diameter * is_ice
    #diameter_water = diameter * is_water
    beta_ice = beta * is_ice
    beta_water = beta * is_water

    #compute diameter * beta for ice and water components
    if not diameter == None:
        diameter_ice = diameter * beta * is_ice
        diameter_water = diameter * beta * is_water
    #if diameter is not supplied from lidar-radar retrieval get it from constants in multiple_scatter_parameters
    else:
        diameter_ice = hau.Z_Array(
            np.ones_like(beta) *
            multiple_scatter_parameters['mode_diameter_ice'] * beta * is_ice)
        diameter_water = hau.Z_Array(
            np.ones_like(beta) *
            multiple_scatter_parameters['mode_diameter_water'] * beta *
            is_water)

    if ms_obj == None:
        ms_obj = hau.Time_Z_Group()
        setattr(ms_obj, 'beta_ice', hau.Z_Array(nansum(beta_ice, 0)))
        setattr(ms_obj, 'beta_water', hau.Z_Array(nansum(beta_water, 0)))
        setattr(ms_obj, 'diameter_ice', hau.Z_Array(nansum(diameter_ice, 0)))
        setattr(ms_obj, 'diameter_water',
                hau.Z_Array(nansum(diameter_water, 0)))
        setattr(ms_obj, 'n_samples_ice',
                hau.Z_Array(sum(~np.isnan(beta_ice) * is_ice, 0)))
        setattr(ms_obj, 'n_samples_water',
                hau.Z_Array(sum(~np.isnan(beta_water) * is_water, 0)))
    else:
        ms_obj.beta_ice += nansum(beta_ice, 0)
        ms_obj.beta_water += nansum(beta_water, 0)
        ms_obj.diameter_ice += nansum(diameter_ice, 0)
        ms_obj.diameter_water += nansum(diameter_water, 0)
        ms_obj.n_samples_ice += sum(~np.isnan(beta) * is_ice, 0)
        ms_obj.n_samples_water += sum(~np.isnan(beta) * is_water, 0)

    return ms_obj
Ejemplo n.º 2
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.º 3
0
    def preYield(self, x, attrs, found):
        if not hasattr(x, 'altitudes') or not hasattr(
                x, 'times') or x.times.size == 0:
            return False
        altmask = x.altitudes < 90000
        for n, v in vars(x).items():
            #print n,v
            if n.startswith('_'):
                continue
            v = v[altmask]
            if n == 'altitudes':
                setattr(x, '_altitudevarname', n)
                setattr(x, n, hau.Z_Array(v).copy())
                continue
            if n in ('latitude', 'longitude', 'times'):
                if v.size > 0:
                    setattr(x, n, v[0])
                continue
            setattr(x, n, hau.Z_Array(
                v.astype('double')))  #.reshape([1]+list(v.shape))))
        x.temps += 273.15
        if not hasattr(x, 'dew_points') and hasattr(x, 'relative_humidity'):
            setattr(
                x, 'dew_points',
                hau.Z_Array(self.su.cal_dew_point(x.relative_humidity,
                                                  x.temps)))
        else:
            x.dew_points += 273.15
        if not hasattr(x, 'frost_points') and hasattr(x, 'dew_points'):
            setattr(x, 'frost_points',
                    hau.Z_Array(self.su.cal_frost_point(x.dew_points)))
        else:
            x.frost_points += 273.15

        x.sounding_type = 'arm'
        x.sounding_id = attrs['zeb_platform']
        x.station_id = attrs['site_id']
        x.top = max(x.altitudes)
        x.bot = min(x.altitudes)

        #print vars(x)
        #if x.times.size<=0:
        #    return False
        x.sample_latitude = x.latitude
        x.sample_longitude = x.longitude
        x.sample_time = x.times
        return True
Ejemplo n.º 4
0
def Rayleigh_cross_section(wavelength, pressures, temps, altitudes):
    """
       Rayleigh_lidar_return(wavelength,,pressures,temperatures,altitudes):
       compute Rayleigh scattering cross section
       see R Holz thesis for this equation giving the Rayleigh scattering cross section.
       beta=3.78e-6*press/temp at a wavelength of 532 nm
       then rescale to actual wavelength
    """

    nalts = altitudes.shape[0]
    beta_r = hau.Z_Array(np.zeros(nalts))

    #Rayleigh scatteromg cross section at 532 nm
    beta_r[:nalts] = 3.78e-6 * pressures[:nalts] / temps[:nalts]

    #Rayleigh scattering  cross section
    beta_r = hau.Z_Array(beta_r * (532.0 / wavelength)**4)

    return beta_r
Ejemplo n.º 5
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
    def convert(self, profile, posframe):
        sounding = hau.Time_Z_Group()
        if 'cache' in self.name:
            sounding.sounding_type = 'virtual'
            sounding.sounding_id = 'Cached Forecast'
            sounding.station_id = 'Cached Forecast'
        elif 'virtual' in self.name:
            sounding.sounding_type = 'virtual'
            sounding.sounding_id = 'NWP Virt'
            sounding.station_id = 'NWP Virt'
        else:
            sounding.sounding_type = 'model'
            sounding.sounding_id = 'Static GRIB'
            sounding.station_id = 'Static GRIB'
        sounding.latitude = profile['lat'][0]
        sounding.longitude = profile['lon'][0]
        sounding.times = datetime(1970, 1, 1, 0, 0, 0) + timedelta(
            seconds=profile['base_time']) + timedelta(
                seconds=profile['time_offset'][0])
        if posframe is None:
            sounding.sample_latitude = sounding.latitude
            sounding.sample_longitude = sounding.longitude
            sounding.sample_time = sounding.times
        else:
            sounding.sample_latitude = posframe['latitude']
            sounding.sample_longitude = posframe['longitude']
            sounding.sample_time = posframe['start']
        minlen = profile['alt'].size
        for k, v in profile.items():
            if hasattr(v, 'shape'):
                if profile['alt'].size != v.size:
                    print 'WARNING SOUNDING ATTRIBUTE ' + k + ' has a length', v.size, 'while alts are', profile[
                        'alt'].size
                    profile[k] = v[:profile['alt'].size]
                    if minlen > v.size:
                        minlen = v.size
        if minlen < profile['alt'].size:
            print "TRIMMING TO SHORTENED SOUNDING ATTRIBUTE of length", minlen
            for k, v in profile.items():
                if hasattr(v, 'shape'):
                    profile[k] = v[:minlen]

        sounding.top = numpy.max(profile['alt'])
        sounding.bot = numpy.min(profile['alt'])
        sounding.altitudes = hau.Z_Array(profile['alt'])
        if 'tkel' in profile:
            sounding.temps = hau.Z_Array(profile['tkel'])
        else:
            sounding.temps = hau.Z_Array(profile['tdry']) + 273.15
        sounding.pressures = hau.Z_Array(profile['pres'])
        sounding.dew_points = hau.Z_Array(
            self.su.cal_dew_point(hau.Z_Array(profile['rh']), sounding.temps))
        sounding.frost_points = hau.Z_Array(
            self.su.cal_frost_point(sounding.dew_points))
        return sounding
Ejemplo n.º 7
0
def lidar_return(beta_r, beta_e_trans, beta_e_rec, altitudes):
    """
       lidar_return(beta_r,beta_e_trans,beta_e_rec,altitudes
       beta_r       = backscatter cross section profile(1/(m sr)
       beta_e_trans = extinction cross section at transmit wavelength (1/m)
       beta_e_rec   = extinction cross section at receive wavelength (1/m)
       altitudes    = vector of altitudes at which to make calculations (m)
       atten_bs     = attenuated backscatter cross_section_profile (1/m)
       
    """

    delta_r = np.zeros_like(altitudes)
    delta_r[:-1] = altitudes[1:] - altitudes[:-1]

    #optical depths on tranmit and receive paths
    od_trans = np.cumsum(beta_e_trans * delta_r)
    od_rec = np.cumsum(beta_e_rec * delta_r)
    atten_bs = hau.Z_Array(beta_r * exp(-od_trans - od_rec))

    return atten_bs
Ejemplo n.º 8
0
def compute_i2a_mol_ratio(profiles,Cxx,corr_adjusts,process_defaults):
    """compute_i2a_mol_ratio(i2a,mol,process_defaults):
       compute ratio of argon broadened i2 filtered profile to normal
       i2 filtered profile
       i2a = corrected argon broadened profile
       mol = normal i2 filtered profile
       process_defaults = processing instructions from process_control.json"""


    i2a = profiles.molecular_i2a_counts[0,:].copy()
    i2a = i2a * corr_adjusts['i2a_ratio']
    mol = profiles.molecular_counts[0,:].copy()
    
    
    if process_defaults.enabled('i2a_mol_ratio'):
        #compute filter length in bins
        window = np.int(np.float(process_defaults.get_value('i2a_mol_ratio','filter_window')\
                 /(profiles.msl_altitudes[2]-profiles.msl_altitudes[1])))
        print 'applying 3-order savitzky_golay filter before computing i2a/i2 ratio',
        print ' window = ',window * (
              profiles.msl_altitudes[2]-profiles.msl_altitudes[1]), ' meters'
        #window must be odd number
        if window == 2*(window/2):
            window = window +1
    
        if window >=5:
            i2a=sg.savitzky_golay(i2a,window,3)
            mol=sg.savitzky_golay(mol,window,3)
        else:
            print 'Window too short---no filtering applied to i2a_mol_ratio'
   
    i2a_mol_ratio = (i2a 
         - Cxx.Cam_i2a*corr_adjusts['Cam_corr']
         * profiles.combined_hi_counts[0,:])\
         /(mol - Cxx.Cam*corr_adjusts['Cam_corr'] 
         * profiles.combined_hi_counts[0,:])
    i2a_mol_ratio = hau.Z_Array(i2a_mol_ratio[np.newaxis,:])
   
    return i2a_mol_ratio
Ejemplo n.º 9
0
    def updateProfiles(self,profiles,mean,hsrl_constants,calframe={},qc_mask=None):
        try:
            hsrl_Cxx = calframe.pop('rs_Cxx',None)
            hsrl_cal = calframe.pop('rs_cal',None)
            hsrl_sounding = calframe.pop('sounding',None)

            pc=self.hsrl_process_control if hsrl_Cxx is not None else None
            if not hasattr(mean,'msl_altitudes') and hasattr(mean,'molecular_counts'):
                mean=copy.copy(mean)
                setattr(mean,'msl_altitudes',hau.Z_Array(np.arange(0,mean.molecular_counts.shape[1])*hsrl_constants['binwidth']*3e8/2))
            if pc is not None:
                sel_telescope_dir = pc.get_value('averaged_profiles','telescope_pointing') 
            else:
                sel_telescope_dir='all'
            profiles=self.mr.generate_ave_profiles(
                mean,
                qc_mask,
                hsrl_Cxx,hsrl_constants,
                pc,sel_telescope_dir,self.hsrl_corr_adjusts,old_profiles=profiles)
            #compute temperatures if data is available
            if hasattr(profiles,'molecular_i2a_counts') and hasattr(hsrl_Cxx,'Cam_i2a'):
                profiles.i2a_mol_ratio = self.iat.compute_i2a_mol_ratio(
                               profiles
                              ,hsrl_Cxx
                              ,self.hsrl_corr_adjusts
                              ,pc) 
                profiles.i2a_temperatures=self.iat.compute_temperature_from_i2a(
                    self.hsrl_instrument,profiles.i2a_mol_ratio
                    ,hsrl_cal.i2a_temp_table,hsrl_sounding.pressures,self.hsrl_corr_adjusts)
                profiles.i2a_temperatures[profiles.msl_altitudes <= hsrl_constants['lidar_altitude']+200] = np.nan
            if self.multistream:#this is safe only if we are top level
                self.setProvidesUsing(profiles)
        except Exception as e:
            print 'Exception occurred in profiles ',e
            traceback.print_exc()
            raise
            #do nothing
        return profiles
    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.º 11
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
Ejemplo n.º 12
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.º 13
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
Ejemplo n.º 14
0
    def search(self, start_time_datetime=None, end_time_datetime=None,reverse_padding=None,timeres_timedelta=None,min_alt_m=None,max_alt_m=None,\
        altres_m=None,window_width_timedelta=None,forimage=None,inclusive=False,timesource=None,allow_nans=False,*args, **kwargs):
        """
        :param start_time_datetime: start time (optional)
        :type start_time_datetime: datetime.datetime
        :param end_time_datetime: end time (optional) if unspecified, will continue to return frames thru now, unending
        :type end_time_datetime: datetime.datetime
        :param reverse_padding: (optional)in the case of reading up to the current time, this timedelta is always subtracted from the current time to get the most recent moment to read
        :type reverse_padding: datetime.timedelta
        :param timeres_timedelta: (optional) time resolution, or None to optimized for images
        :type timeres_timedelta: datetime.timedelta
        :param min_alt_m: minimum altitude in meters
        :param max_alt_m: maximum altitude in meters
        :param altres_m: (optional) altitude resolution
        :param window_width_timedelta:   used with start or end time (not both) to determine preferred return width. if unspecified, will imply the other unspecified, or from now if neither
        :type window_width_timedelta: datetime.timedelta
        :param corr_adjusts: correction adjustments. if unspecified, will use default   
        :param block_when_out_of_data: (optional) if unspecified or True, will block for 'timeres_timedelta' until trying for more frames. if False, yield None until more data is available
        :param forimage: (optional) if provided, is a dict(x=##,y=##) containing preferred x and y pixel count for an image. if no resolutions are provided, these are used to create an optimal one. if not provided, lacking resolutions are native
        :param inclusive: if true, will expand window to ensure including any data that intersects the requested times
        """
        if len(args):
            print 'Unused dpl_radar.search args = ',args
        if len(kwargs):
            print "Unused dpl_radar.search kwargs = ",kwargs

        # altitude configuration notes: min and max alt are required. resolution is optional, in which case the process_control will determine pixel count, and thus resolution

        # time configuration notes: there are many modes to this operation, and two layers
        #   calibration layer: possible parameters are start, end, and window width. (implemented by dpl_calibration.parse_timewindow(), which will return in all cases start and width, and end if will terminate)
        #      specification groups possible: start+end, start+window,start,end+window,window (in order of priority)
        #      start and end specify the range of calibrations to stream
        #      if only one is specified, window is used to roll forward or back the one specified to make the other
        #         if window is not specified, it goes from start to now (defining the window)
        #      if neither are specified, start is set to now-window
        #      if end is not specified, it keeps rolling forward without termination. if it is, it WILL go to that point (even in future) and terminate
        #         if start and window are specified, and start+window is past now, start will be ignored
        #   processing layer:
        #      extra parameter of maxtimeslice specifies the largest volume of actual data to be returned (may be violated if no data is available, and filler piles up)
        #         if it is not specified, natural flow is not interrupted for the sake of data volume
        #      here, it only cares if timeres is not specified.  If it is not specified, it will follows the same steps as calibration to find the preferred window size, and use process_control to determine pixel count, and resolution

        prms={}
        if reverse_padding!=None:
            prms['now']=datetime.utcnow()-reverse_padding
        d=parse_timewindow(start_time_datetime,end_time_datetime,window_width_timedelta,**prms)

        if forimage!=None:
            if not isinstance(forimage,dict):
                import lg_base.core.canvas_info as ci
                forimage=ci.load_canvas_info()['canvas_pixels']
            if altres_m==None:
                if min_alt_m==None:
                    min_alt_m=0
                if max_alt_m==None:
                    max_alt_m=30
                altres_m=(max_alt_m-min_alt_m)/forimage['y']
            if timeres_timedelta==None:
                timeres_timedelta=timedelta(seconds=d['windowwidth'].total_seconds()/forimage['x'])
        from lg_dpl_toolbox.filters import time_frame,resample_altitude

        def extralibparms():#scope abuse
            if 'merge' in self.instrument:
                return dict()
            return dict(firstaltitude=min_alt_m-altpad,lastaltitude=max_alt_m+altpad)

        altpad=(2*altres_m) if altres_m!=None else 0
        ramannar=self.lib(start=d['starttime'],end=d['endtime'],**extralibparms())
        #FIXME too constant, and hardcoded
        if timeres_timedelta!=None and ramannar.ramanNativeTimeResolution>timeres_timedelta:
            #dropping time resolution to 'pure native'
            timeres_timedelta=None

        if inclusive:
            #remake with padding
            padAmount=(2*timeres_timedelta) if timeres_timedelta!=None else None
            if padAmount is None or padAmount<(2*ramannar.ramanNativeTimeResolution):
                padAmount=2*ramannar.ramanNativeTimeResolution
            if d['starttime']:
                d['starttime']-=padAmount
            if d['endtime']:
                d['endtime']+=padAmount
            altpad=(2*altres_m) if altres_m!=None else 50
            ramannar=self.lib(start=d['starttime'],end=d['endtime'],**extralibparms())
        elif timeres_timedelta:#just pad the input data. don't mess with the mean narrator below
            ramannar=self.lib(start=d['starttime']-timeres_timedelta,end=d['endtime']+timeres_timedelta,**extralibparms())


        #ramannar=self.rf.RadarPrefilter(ramannar)
        if timesource is not None:
            ramannar=time_frame.MeanNarrator(ramannar,timesource=timesource,allow_nans=allow_nans)
        elif timeres_timedelta is not None:
            ramannar=time_frame.MeanNarrator(ramannar,basetime=d['starttime'],timeres=timeres_timedelta,endtime=d['endtime'],allow_nans=allow_nans)
        if 'merge' not in self.instrument and altres_m is not None:
            requested_altitudes=hau.Z_Array(np.arange(min_alt_m,max_alt_m+altres_m*0.1,altres_m))
            ramannar=resample_altitude.ResampleXd(ramannar,'altitudes',requested_altitudes,left=np.NaN,right=np.NaN)

        return ramannar
Ejemplo n.º 15
0
    def preYield(self,x,attrs,found):
        if not hasattr(x,'heights') or not hasattr(x,'times') or x.times.size==0:
            return False
        
        if 'merge' in self.ramanType:
            basealt=0 #don't correct yet for merge
        elif hasattr(x,'alt'):#platform height from sealevel
            basealt=x.alt
        elif "altitude [m AMSL]" in attrs:
            basealt=float(attrs["altitude [m AMSL]"])
            setattr(x,'alt',basealt)
            print 'Got an altitude from attributes', basealt,x.alt,self.ramanType
        else:
            raise RuntimeError("Can't find MSL altitude")
        dualmerge=hasattr(x,'heights') and hasattr(x,'heights_low')
        if dualmerge:
            print 'merging low into high'
            #print 'high =',x.heights
            #print 'low  =',x.heights_low
            mergemap=[]
            merged=[0,0]
            hlowcount=x.heights_low.size
            for lidx,alt in enumerate(x.heights_low):
                idxs=np.where(x.heights==alt)[0]
                if idxs.size==0:
                    #print 'height_low',alt,'at offset',lidx,'not in high'
                    #raise RuntimeError('missing alt')
                    mergemap.append(None)
                    merged[1]=merged[1]+1
                else:
                    if idxs.size>1:
                        print 'heigh_low',alt,'has',len(idxs),'matches'
                    #print 'merging in alt',alt,'from low',lidx,'to high',idxs,'(len',idxs.size,')'
                    mergemap.append(int(idxs.ravel()[0]))
                    merged[0]=merged[0]+1
            if merged[1]>0:
                print 'Successfully merged =',merged[0],'   unmerged and dropped =',merged[1]
            delattr(x,'heights_low')

        for n,v in vars(x).items():
            #print n,v
            if n.startswith('_'):
                continue
            #v=v[altmask]
            fd = found[n] if n in found else {}
            self.fixValue(v,fd,attrs,'missing_value',np.NAN)
            self.fixValue(v,fd,attrs,'missing-data',np.NAN)
            self.fixValue(v,fd,attrs,'nan_value',np.NAN)
            units = '' if 'units' not in fd else fd['units']
            if '/' in units:
                sp=units.split('/')
                numer=sp[0]
                denom=sp[1]
            else:
                numer=units
                denom='1'
            if 'km' in denom:# THIS DOES ASSUME ANY KM/M conversions don't stick, and have to be redone here
                v/=1000.0
            if 'km' in numer:
                v*=1000.0
            if 'depol' in n and 'counts' not in n and 'uncert' not in n and (len(units)<2 or units=="unitless") :
                v*=100.0
            if n=='heights' and 'merge' not in self.ramanType:
                setattr(x,'_altitudevarname','altitudes')
                setattr(x,"altitudes",hau.Z_Array(v+basealt))
                continue
            if (n.endswith('_low') or '_low_' in n) and len(v.shape)>1 and v.shape[1]==hlowcount and dualmerge:
                tmp=v
                hname=n.replace('_low','_high')
                if not hasattr(x,hname):
                    hname=n.replace('_low','')
                if not hasattr(x,hname):
                    print "Can't find high equivalent to "+n
                v=getattr(x,hname).copy()
                def subslice(chunk=None):
                    ret=[slice(None),slice(chunk)]
                    for x in range(2,len(v.shape)):
                        ret.append(slice(None))
                    return tuple(ret)
                v[subslice()]=np.NAN
                for si,i in enumerate(mergemap):
                    if i is not None:
                        v[subslice(i)]=tmp[subslice(si)]
                setattr(x,n,v)
        dt=x.times.copy()
        dt.summode="sum"
        setattr(x,'width',dt)
        setattr(x,'start',x.times.copy())
        if dt.size>1:
            for i in range(dt.size-1):
                dt[i]=(x.times[i+1]-x.times[i]).total_seconds()
            dt[-1]=dt[-2]
            for i,dtv in enumerate(dt):
                x.start[i]-=timedelta(seconds=dtv/2.0)
        return True
Ejemplo n.º 16
0
def msinteg(N1, N2, firstR, lastR, inc, beta, mode_dia, ranges, wavelength,
            multiple_scattering_parameters, calvals):
    """
       msinteg(N1,N2,firstR,lastR,inc,beta,mode_dia 
             ,ranges,multiple_scattering_parameters,calvals,wavelength)
       N1         = highest order of scattering to compute.
       N2         = lowest order of scattering to compute.
       firstR     = begining of the range interval to compute (meters),
                    optical depth below firstR does not contribute to computed result.
       lastR      = end of the range interval to compute (meters).
       inc        = number of range indices between ms computations (normally inc=1).
       beta       = column vector with scattering cross sections (1/m), 
       mode_dia   = column vector with mode diameter at each range (m)
                    if supplied as single value it will be expanded to a column vector.
       ranges     = column vector containing the ranges at which beta_c, beta_R, and
                    mode_dia are specified. Answers will be returned at these points. 
                    ranges must be equally spaced. Ranges must be supplied in meters,
       wavelength = lidar wavelength (m)             
       multiple_scatter_parameters['particle_info_source'] == 'measured' | 'constant'
                                  ['p180_water'] 
                                  ['p180_ice'] 
                                  ['h2o_depol_threshold']  water when depol < threshold
                                  ['alpha_water'] 
                                  ['alpha_ice']
                                  ['g_water'] 
                                  ['g_ice'] 
                                  where: N(D) ~ D^alpha * exp(-alpha/g *(D/mode_dia)^g)
       calvals =  dictionary of calibration constants for particular hsrl
       

       #old doc header
       function ms=msinteg(id,N1,N2,firstR,lastR,inc,beta_c,r_particle...
             ,ranges,wavelength,FOVT,d_beam,FOVR,d_rec,P180,P18_2,P18_n);


       Python only version of mutliple scatter code-uses ms_int.py a recursive
       integration routine. The mode diameter of the gamma distribution is used to
       compute the square of the Gaussian diffraction peak width.
      
       
       See 'http://lidar.ssec.wisc.edu/mscat/derivations' for details. 
 
       id         = integer used in output file name,usually the starting shot number.
       N1         = highest order of scattering to compute.
       N2         = lowest order of scattering to compute.
       firstR     = begining of the range interval to compute (meters),
                    optical depth below firstR does not contribute to computed result.
       lastR      = end of the range interval to compute (meters).
       inc        = number of range indices between ms computations (normally inc=1).
       ranges     = column vector containing the ranges at which beta_c, beta_R, and
                    mode_dia are specified. Answers will be returned at these points. 
                    ranges must be equally spaced. Ranges must be supplied in meters, 
       beta       = column vector with scattering cross sections (1/m), 
       mode_dia   = column vector with mode diameter at each range (m)
                    if supplied as single value it will be expanded to a column vector.
       alpha,gam  = gamma size parameters, N(D)=D^alpha *exp(-b*D^gam)      
       lambda     = wavelength (m)
       FOVT       = laser divergence in radians.
       d_beam     = 1/e full with of the laser beam at telecope exit
       FOVR       = reciever fov in radians.
       d_rec      = diameter of receiving mirror (m)
       P180       = backscatter phase function for single scattering.
       P18_2      = backscatter phase function for second order scattering
       P18_n      = backscatter phase function for all higher orders of scattering.
       beta_source is a string which will be appended to field name of results.
       it is expected to indicate the algorithm used to compute the extinction
       cross section profile used in the calculations.

    """

    #convert angles to half angles--inputs in form of full angle divergence
    #and program in terms of half angles.

    FOVR = calvals['telescope_fov'] / 2.0
    FOVT = calvals['laser_beam_divergence'] / 2.0
    r_beam = calvals['1/e_laser_beam_width'] / 2.0
    r_rec = calvals['telescope_diameter'] / 2.0
    #wavelength = calvals['wavelength']*1e-9
    alpha = multiple_scattering_parameters['alpha_water']
    gam = multiple_scattering_parameters['g_water']

    nranges = ranges.shape[0]

    #find index of first and last range involved in this computation
    first_pt = 1
    for i in range(nranges):
        if ranges[i] <= firstR:
            first_pt = i
        if ranges[i] <= lastR:
            last_pt = i

    #convert mode diameter to diffraction peak width squared
    #area weighted diameter-squared from mode diameter of gamma distribution
    ave_D_squared = mode_dia**2 * (gam / alpha)**2 * ss.gamma(
        (alpha + 3) / gam) / ss.gamma((alpha + 1) / gam)
    #theta_s = (4*wavelength^2/(pi^2 *<D^2>)
    theta_sq = (2 * wavelength / np.pi)**2 / ave_D_squared

    #if mode_dia is provided as a single value expand into array
    #if not isinstance(mode_dia,hau.Z_Array):
    #    if not isinstance(mode_dia,np.ndarray):
    #        theta_sq = theta_sq * np.ones_like(ranges)

    nranges = len(ranges)
    beta_c = beta.copy()
    dr = ranges[1] - ranges[0]

    # cloud optical depth
    tau_c = np.zeros_like(ranges)
    beta_c[np.isnan(beta_c)] = 0.0
    tau_c[first_pt:last_pt] = np.cumsum(beta_c[first_pt:last_pt])-beta_c[first_pt]/2.0 \
                               -beta_c[first_pt:last_pt]/2.0
    tau_c = tau_c * dr

    #sum of Rayleigh and cloud optical depth
    tau_t = np.cumsum(beta_c[first_pt:last_pt])-beta_c[first_pt]/2.0 \
            -beta_c[first_pt:last_pt]/2.0
    tau_t = tau_t * dr

    tbeta = np.transpose(beta_c)
    #time0=cputime;
    #ms = np.zeros((ranges.shape[0],N2-N1+3))
    #compute for subset of ranges if inc > 1
    #inc =3
    indices = range(first_pt, last_pt, inc)
    ms = np.zeros((len(indices), N2 + 1))
    ms[:, 0] = ranges[indices]
    s_time = datetime.utcnow()
    for n_th in range(N1, N2 + 1):
        j = 0
        for i in indices:
            divlR2 = (FOVT * ranges[i] + r_beam)**2
            fovR2 = (FOVR * ranges[i] + r_rec)**2
            ms[j,n_th] = ms_int(n_th,ranges \
                           ,first_pt,i, tbeta,theta_sq,divlR2,fovR2)
            ms[j, n_th] = tau_c[i]**(n_th - 1) / ss.gamma(n_th) - ms[j, n_th]
            #print 'Range=%g N=%g tau=%g,ms=%g' %(ranges[i],n_th,tau_c[i]**(n_th-1)/ss.gamma(n_th),ms[j,n_th])

            j = j + 1
    #interpolate back to input resolution
    #ms_ratios_profile[number_of_range_bins,number_of_orders_of_scattering + 1]
    ms_ratios_profile = np.zeros((beta.shape[0], N2 + 1))
    ms_ratios_profile[first_pt:last_pt, 0] = ranges[first_pt:last_pt]
    for i in range(2, N2 + 1):
        ms_ratios_profile[first_pt:last_pt,
                          i] = np.interp(ranges[first_pt:last_pt],
                                         ranges[indices], ms[:, i])
    ms_ratios_profile = hau.Z_Array(ms_ratios_profile)
    print 'time for multiple scatter cal = ', datetime.utcnow() - s_time
    return ms_ratios_profile
Ejemplo n.º 17
0
    def process(self):
        #calsource=time_frame.TimeTrickle(self.cals,timename='chunk_start_time',endtimename='chunk_end_time')
        rif = self.rif
        pickle = self.pickle
        lasttime = None
        calsource = time_frame.TimeTrickle(self.cals,
                                           timename='chunk_start_time',
                                           endtimename='chunk_end_time')
        for f in self.datasource:
            orig = f
            if self.sourcename is not None:
                if isinstance(f, dict) and self.sourcename in f:
                    f = f[self.sourcename]
                elif hasattr(f, self.sourcename):
                    f = getattr(f, self.sourcename)
                else:
                    print "No Raman Ranged to process. can't find subframe " + self.sourcename
                    continue
            if f is None or f.times.size == 0:
                print "No Raman Ranged to process. Raman Merge is empty"
                continue
            print "Raman Merge to Ranged running"
            lasttime = f.times[0]
            caldictionary = calsource(lasttime)
            pname = ('frame', 'cal frame')
            p1 = []
            p1.append(pickle.dumps(f))
            p1.append(pickle.dumps(caldictionary))
            ret = rif.process_ranged_raman(caldictionary['rs_constants'], f,
                                           self.raman_process_control,
                                           caldictionary['rs_cal'],
                                           self.raman_corr_adjusts)
            p2 = []
            p2.append(pickle.dumps(f))
            p2.append(pickle.dumps(caldictionary))
            for i in range(len(p1)):
                if p1[i] != p2[i]:
                    print 'Detected modification of ' + pname[i] + '. FAIL'
                    raise RuntimeError('Modification of Raman Ranged ' +
                                       pname[i])

            hau.verifyAllNew(ramancal=caldictionary,
                             ramanmerge=f,
                             ramanrange=ret)

            if ret is None:
                print "Raman Range is none"
                import time
                time.sleep(5)
            elif hasattr(f, 'alt'):  #platform height from sealevel
                setattr(ret, '_altitudevarname', 'altitudes')
                setattr(ret, "altitudes", hau.Z_Array(f.heights + f.alt))

            if self.destination is not None:
                if isinstance(orig, dict):
                    orig[self.destination] = ret
                else:
                    setattr(orig, self.destination, ret)
                yield orig
            else:
                yield ret
Ejemplo n.º 18
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.º 19
0
def quick_cal( i2_scan, Cam, Cam_i2a,sounding, wavelength, method_string
               , i2_scan_corr, i2a_scan_corr):
    """quick_cal_stream(i2_scan, Cam, sounding, wavelength, method_string, i2_scan_corr)
       A function which computes hsrl calibration coefficients.
       at the altitudes specified (in meters) within 'alt_vector'
       using a precomputed iodine scan file(i2_scan_file).
       i2_scan(:,:) = input containing i2 scan info
       i2_scan(:,0) = freq (GHz)
       -------(:,1) = combined channel scan
       -------(:,2) = molecular channel scan
       -------(:,3) = theoretical i2 transmission
       -------(:,4) = measured i2/combined
       if bagohsrl with argon buffered i2 cell
       -------(:,5) = molecular i2a/combined
       -------(:,6) = molecular i2a channel scan

       Cam           = aerosol in molecular coefficent
       Cam_i2a       = aerosol in argon-buffered molecular channel (will = None when not present)
       sounding      = return structure from read_sounding_file.py contains temp profile
       wavelength    = laser wavelength (nm)
       method_string = molecular line shape ''maxwellian','tenti_s6','wirtschas'
       i2_scan_corr  = adjustment factor for i2 scan that adjusts
                       i2 molecular channel gain relative to combined channel gain
       i2a_scan_corr = adjustment factor for i2a scan that adjusts
                       i2a molecular channel gain relative to combined channel gain
       rs            = return structure containing calibration coefficents
                       calibration values are returned at altitudes
                       rs_sounding.alititudes[:]
                       
                       1            = particulate in combined channel
                       rs.Cmc[i]    = molecular in combined channel
                       rs.Cmm[i]    = molecular in molecular channel
                       rs.Cam       = particulate in molecular channel
                       rs.beta_r[i] = Rayleigh scattering cross section (1/m)"""

       
    rs = hau.Time_Z_Group()  # calibration structure

    # i2_scan=cal_vec.i2_scan
    i2_scan=i2_scan.copy()

    # if selected use theory*combined as synthetic mol scan
    print method_string
    if method_string.find('i2 theory') >= 0:
        i2_scan[:, 2] = i2_scan[:, 4] * i2_scan[:, 1]
   
    # trim i2 scan to +-4 GHz about line center

    #i2_scan = i2_scan[abs(i2_scan[:, 0]) <= 4, :]

    # rescale i2 molecular component of i2 scan if required
    if i2_scan_corr != 1.0:
        i2_scan[:, 2] = i2_scan[:, 2] * i2_scan_corr
        
    # rescale i2a molecular component of i2 scan if required    
    if i2a_scan_corr != 1.0 and i2_scan.shape[1]>6:
        i2_scan[:, 6] = i2_scan[:, 6] * i2a_scan_corr

    if 0:
       import matplotlib.pylab as plt
       plt.figure(444443)
       plt.plot(i2_scan[:,0],i2_scan[:,1:3],i2_scan[:,0],i2_scan[:,2]/i2_scan[:,1],'k')
       plt.xlabel('freq GHz')
       plt.grid(True)

    # trim i2 scan to +-4 GHz about line center
    i2_scan = i2_scan[abs(i2_scan[:, 0]) <= 4, :]

    if 0:
       
       import matplotlib.pylab as plt
       plt.figure(444444)
       plt.plot(i2_scan[:,0],i2_scan[:,1:3])
       plt.xlabel('freq GHz')
       plt.grid(True)
    
    # compute Rayleigh scattering cross section
    # see R Holz thesis for this equation giving the Rayleigh scatter cross section.
    # beta=3.78e-6*press/temp at a wavelength of 532 nm
    # then rescale to actual wavelength

    nalts = sounding.altitudes.shape[0]
    if not (nalts==sounding.pressures.shape[0] and nalts==sounding.temps.shape[0]):
      print "ERROR: SOMETHIGN BAD ABOUT SOUNDING AT TIME ",sounding.times
      return None
    rs.beta_r = hau.Z_Array(np.zeros( nalts ))
    rs.beta_r[:nalts] = 3.78e-6 * sounding.pressures[:nalts]  / sounding.temps[:nalts]
    rs.beta_r = rs.beta_r * (532.0 / wavelength) ** 4
   
    # spectral width of molecular scattering

    m_bar = 28.97 * 1.65978e-27  # average mass of an air molecule
    sigma_0 = 1 / (wavelength * 1e-9)  # number in 1/meters
    kb = 1.38044e-23  # Boltzmans constant J/(K deg)
    c = 3e8  # speed of light in m/s
    sigma = i2_scan[:, 0] * 1e9 / c  # wavenumber vector

    rs.Cmm     =  hau.Z_Array(np.zeros( nalts ))
    rs.Cmc     =  hau.Z_Array(np.zeros( nalts ))
    sample_altitudes = np.zeros(nalts)   
    #for bagohsrl with argon buffered i2 cell
    if len(i2_scan[0,:]) > 6:   
        rs.Cmm_i2a =  hau.Z_Array(np.zeros( nalts ))
        rs.Cam_i2a =  Cam_i2a
    rs.Cam = Cam 
    
    print 'RBS computed with '+method_string+  ' spectrum'
  
    spectrum_time = datetime.utcnow()        
    
    dz = sounding.altitudes[2]-sounding.altitudes[1]
    delta_i = np.int(np.ceil(300.0/dz))
    nk=int(nalts/delta_i)
    if delta_i>1 and nk<2:# if interpolation is to happen, but not enough to interpolate, force it to the edge
        nk=2
        delta_i=nalts-1
    sample_altitudes = np.zeros(nk)
    rs.msl_altitudes = sounding.altitudes.copy()

    i=0
    k=0
    while k < len(sample_altitudes):
        if not np.isfinite(sounding.temps[i]) or not np.isfinite(sounding.pressures[i]):
          i=i+delta_i
          k=k+1
          continue
        if method_string.find('maxwellian') >= 0:
            norm = m_bar * c ** 2 / (8 * sigma_0 ** 2 * kb
                    * sounding.temps[ i])
            spectrum = np.exp(-norm * sigma ** 2)
        elif method_string.find('tenti_s6') >= 0:
            from tenti_s6 import tenti_s6
            spectrum = tenti_s6(wavelength * 1e-9,sounding.temps[i],
                    sounding.pressures[ i],
                    i2_scan[:, 0] * 1e9)
            
        elif method_string.find('witschas') >= 0:
            spectrum = witschas_spectrum(sounding.temps[i],
                    sounding.pressures[ i], wavelength * 1e-9,
                    i2_scan[:, 0] * 1e9)

        spectrum = spectrum / sum(spectrum)
       
    
        sample_altitudes[k] = sounding.altitudes[i]
        rs.Cmc[ k] = sum(spectrum * i2_scan[:, 1])
        rs.Cmm[ k] = sum(spectrum * i2_scan[:, 2])
        if i2_scan.shape[1]>6:
            rs.Cmm_i2a[ k] = sum(spectrum * i2_scan[:, 6])
        i = i + delta_i
        k = k + 1

    # if Cxx computed at less than full altitude resolution 
    if delta_i >1:
       rs.Cmc = np.interp(sounding.altitudes,sample_altitudes[0:k-1]
                        ,rs.Cmc[0:k-1])
       rs.Cmm = np.interp(sounding.altitudes,sample_altitudes[0:k-1]
                        ,rs.Cmm[0:k-1])
       if hasattr(rs,'Cmm_i2a'):
           rs.Cmm_i2a = np.interp(sounding.altitudes,sample_altitudes[0:k-1]
                        ,rs.Cmm_i2a[0:k-1])
    print method_string, 'computed for ',k-1,' altitudes in '\
          , (datetime.utcnow() - spectrum_time).total_seconds(),' seconds'
    plots = 0
    if plots:
        import matplotlib.pyplot as plt
        plt.figure(600)
        plt.plot(i2_scan[:, 0], spectrum[:])
        fig = plt.grid(True)
        plt.xlabel('Frequency (GHz)')
        plt.ylabel('Intensity')
        # ax=gca()
        # ax.set_yscale('log')

        plt.figure(601)
        plt.plot(rs.Cmm,sounding.altitudes/1000.0,'b'
                 ,rs.Cmm_i2a,sounding.altitudes/1000.0,'r')
        plt.grid(True)
        plt.xlabel('Cmm, Cmm_i2a')
        plt.ylabel('Altitude')
        plt.show()
        
    # add sounding identification to return structure
    rs.sounding_id = sounding.station_id
    rs.sounding_time = sounding.times
  
    return rs
Ejemplo n.º 20
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