예제 #1
0
def report_servo_distances2(servo_agent, processed, area_graphs):
    r = Report()
    nmap = processed['nmap']
    y_goal = processed['y_goal']
    figparams = dict(figsize=(6, 6))
    px = []
    py = []
    distances = []
    for i in range(nmap.npoints()):
        obs = nmap.get_observations_at(i)
        # d = np.linalg.norm(obs - y_goal)
        d = servo_agent.get_distance(obs, y_goal)
        p = nmap.get_R2_point_at_index(i)
        px.append(p[0])
        py.append(p[1])
        distances.append(d)
    
    px = np.array(px)
    py = np.array(py)
    
    mx = np.linspace(px.min(), px.max(), 75)
    my = np.linspace(py.min(), py.max(), 75)
    XI, YI = np.meshgrid(mx, my)
    
    from scipy.interpolate import Rbf
    rbf = Rbf(px, py, distances, epsilon=0.05)
    ZI = rbf(XI, YI)

    D = np.zeros(shape=XI.shape)
    for i, j in itertools.product(range(len(mx)), range(len(my))):
        D[i, j] = np.min(np.hypot(mx[j] - px, my[i] - py))  # not a bug
    outside = D > 0.12

    ZI[outside] = np.nan
    ZI = masked_invalid(ZI)
    
    f = r.figure()
    with f.plot('rbfs', **figparams) as pylab:
        pylab.gca().set_rasterized(True) 
        from matplotlib import cm
        pylab.pcolormesh(XI, YI, ZI, cmap=cm.jet)  # @UndefinedVariable
        pylab.scatter(px, py, 20, distances, cmap=cm.jet)  # @UndefinedVariable
        pylab.colorbar()
        plot_style_servo_field_xy(pylab, area_graphs=area_graphs)
        

    with f.plot('interpolation', **figparams) as pylab:
        pylab.gca().set_rasterized(True) 
        cmap = cm.jet  # @UndefinedVariable
        cmap.set_bad('w', 0.)
#         pylab.pcolormesh(XI, YI, ZI, cmap=cm.jet)  # @UndefinedVariable
        # bug with pcolormesh: black background
        pylab.pcolormesh(XI, YI, ZI, cmap=cmap, shading='gouraud')  # @UndefinedVariable
        plot_style_servo_field_xy(pylab, area_graphs=area_graphs)
        
    return r
예제 #2
0
    def addField(self,
                 fieldName,
                 fieldValue,
                 longName=None,
                 units=None,
                 **kwargs):
        """
        Add a field to the sounding
        
        .. _ndarray: http://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.htm
        
        Parameters
        ----------
        
        fieldName : str
            Name of the field to be added. It supports abbreviations 
            (see :py:attr:`abbreviations`)
        
        fieldValue : any
            Corresponding field value. If the field value is an ndarray_  then
            it will be converted to a :py:class:`~SkewTplus.sounding.soundingArray` with the corresponding 
            metadata.
            
        longName : str, optional
            Long name of the field
            
        units : str , optional
            units of the field
        
        missingValue : float, optional
            Value for missing data. Occurrences of this value will be masked.
            The default missingValue can be change with :py:meth:`setMissingValue` 
       
        """

        missingValue = kwargs.pop('missingValue', self.missingValue)

        fieldName = self._getFieldName(fieldName)

        if isinstance(fieldValue, ndarray):

            _fieldValue = masked_invalid(fieldValue)
            _fieldValue = masked_values(_fieldValue, missingValue)
            _fieldValue.harden_mask()
            self._soundingData[fieldName] = soundingArray(
                _fieldValue,
                longName=longName,
                units=units,
                missingValue=missingValue)

        else:
            self._soundingData[fieldName] = fieldValue
예제 #3
0
def virtualTemp3(T, Td, p):
    """Virtual Temperature, but using vapor mixing ratio instead the vapor pressure

    Parameters
    ---------    
    T: float
        Temperature in Celsius degrees
    
    Td: float
        Dew Point Temperature un Celsius Degrees
    
    p: float
        Atmospheric pressure (Pa)

    Returns
    -------
    Virtual temperature : float32
        In Celsius degrees
    """

    T = masked_invalid(T)
    Td = masked_where(numpy.array(Td) < -degCtoK, Td)
    Td = masked_invalid(Td)
    _vaporMixingRatio = vaporMixingRatio(VaporPressure(Td), p)

    T.filled(-99999)
    #print(_vaporMixingRatio)
    Tc = (T + degCtoK)
    factor = (1. +
              (_vaporMixingRatio.data / Epsilon)) / (1. +
                                                     _vaporMixingRatio.data)

    _virtualTemp = (Tc * factor) - degCtoK

    noTDMask = getmaskarray(_vaporMixingRatio)
    _virtualTemp.data[noTDMask] = T[noTDMask]
    _virtualTemp.mask = getmask(T)

    return _virtualTemp
예제 #4
0
def virtualTemp4(T, p):
    """Virtual Temperature, but using vapor mixing ratio instead the vapor pressure

    Parameters
    ---------    
    T: float
        Temperature in Celsius degrees
    
    Td: float
        Dew Point Temperature un Celsius Degrees
    
    p: float
        Atmospheric pressure (Pa)

    Returns
    -------
    Virtual temperature : float32
        In Celsius degrees
    """
    T = masked_invalid(T)
    _vaporMixingRatio = vaporMixingRatio(VaporPressure(T), p)

    return ((T + degCtoK) * (1. + (_vaporMixingRatio / Epsilon)) /
            (1. + _vaporMixingRatio)) - degCtoK
예제 #5
0
    def fetchFromTxtFile(self, filePath, headerLength=6):
        """
        Reads the raw profile data from a University of Wyoming sounding file.
        
        Notes
        -----
        1. Data can be downloaded from http://weather.uwyo.edu/upperair/sounding.html
        2. The input file has to conform *Exactly* to the University of 
           Wyoming file format. 
        3. The diagnostics at the end of the file are ignored.        
           
        """

        # Now this class uses Numpy's genfromtxt function to read the TXT files,
        # Idea taken from pymeteo.uwyo.py , fetch_from_file method

        def isValidValue(valueString):
            # True if the string can be converted to float
            try:
                _ = float(valueString)
                value = True
            except ValueError:
                value = False
            return value

        with open(filePath, 'r') as fileHandler:
            lines = fileHandler.readlines()

            # New: handle whitespace at top of file if present
            offset = 0
            while not lines[0].strip():
                print(lines[0])
                lines.pop(0)
                offset += 1

            # Handle the file header
            # First line for WRF profiles differs from the UWYO soundings
            header = lines[0]
            if header[:5] == '00000':
                # WRF profile
                self.addField('StationNumber', '00000')
                self.addField('Longitude', float(header.split()[5].strip(",")))
                self.addField('Latitude', float(header.split()[6]))
                self.addField('SoundingDate', header.split()[-1])
            else:
                self.addField('StationNumber', header[:5])
                dstr = (' ').join(header.split()[-4:])
                soundingDate = datetime.strptime(dstr, "%HZ %d %b %Y")
                self.addField('SoundingDate',
                              soundingDate.strftime("%Y-%m-%d_%H:%M:%S"))

            fieldsNames = lines[headerLength - 3].split()
            filedsUnits = lines[headerLength - 2].split()

            arePressureValues = [isValidValue(_line[0:7]) for _line in lines]

            fieldsData = numpy.genfromtxt(
                filePath,
                unpack=True,
                skip_header=headerLength + offset,
                max_rows=numpy.argwhere(arePressureValues).max() -
                headerLength + 1,
                delimiter=7,
                usemask=True,
                missing_values=self.missingValue)

        for fieldName, fieldValues, units in zip(fieldsNames, fieldsData,
                                                 filedsUnits):
            # Set mask for missing data

            fieldValues = masked_invalid(fieldValues)

            fieldValues.harden_mask()

            self.addField(fieldName,
                          fieldValues,
                          units=units,
                          missingValue=self.missingValue,
                          longName=_txtSoundingLongNames[fieldName.lower()])
예제 #6
0
    def __init__(self, inputData=None, fileFormat=None, stationId=None):
        """
        Sounding Initialization
        
        It supports 4 types of initialization:
            
        * From a University of Wyoming txt file
        * From a University of Wyoming Website
        * Form an ARM sounding Netcdf file
        * From a dictionary with the field names, field values pairs
        
        All the field are added trough the :py:meth:`addField` method.
        The fields names support abbreviations when they are set or get.
        But internally the field names stored are not abbreviated.
        See :py:attr:`SkewT.sounding.abbreviations`.
        
        If the fileFormat keyword is not specified, it is assumed that 
        the input data correspond to a filePath and it will try determine the
        format automatically.
        
        .. _datetime:`https://docs.python.org/2/library/datetime.html`
        
        Parameters
        ----------
        
        inputData : str, datetime_ or dict
            If inputData is a dictionary, the sounding fields are taken from the
            dictionary (field names, field values pairs).
            
            If fileFormat is "web", then the inputData is considered the date of the sounding.
            See :py:meth:fetchFromWeb for date input format.
            Otherwise, if inputData is an string, it is considered a file path.
            If fileFormat is None (default) the initialization will
            try to automatically detect the file format.
        
            If inputData is None, the create instance correspond to an empty sounding. 
            
        
        fileFormat : str
            File format. Supported values:
            * 'txt', "wrf", "uw or "wyoming" : University of Wyoming
            * "netcdf", "arm" : ARM netcdf soundings
            * 'web' : University of Wyoming website
        
        stationId : str
            Station ID. Used only when "web" is selected as format. See :py:meth:fetchFromWeb
            for more details.
            
        """

        self._soundingData = dict()
        self.missingValue = -9999.

        self.addField('StationNumber', '(No Number)')
        self.addField('SoundingDate', '(No Date)')

        if inputData is not None:

            if fileFormat == "web":
                self.fetchFromWeb(inputData, stationId)
            else:

                if isinstance(inputData, str):
                    # A file path was given

                    if not isfile(inputData):
                        raise fatalError("The file does not exists: %s\n" %
                                         (inputData))

                    if fileFormat is None:
                        # Try automatic detection of file format
                        try:
                            self.fetchFromARMFile(inputData)
                        except OSError:
                            # If it is not a NETCDF , try TXT
                            self.fetchFromTxtFile(inputData)

                    else:
                        # If the argument is an string assume that is
                        # in the university of wyoming format
                        if fileFormat.lower() in ('txt', "wrf", "uw",
                                                  "wyoming"):
                            self.fetchFromTxtFile(inputData)
                        elif fileFormat.lower() in ('netcdf', 'arm'):
                            self.fetchFromARMFile(inputData)
                        else:
                            raise fatalError(
                                "Error loading Sounding",
                                "Selected format not supported:%s" %
                                fileFormat, "Accepted formats:%s" % str(
                                    ('txt', "wrf", "uw", "wyoming", "netcdf")))

                elif isinstance(inputData, dict):
                    for fieldName, fieldValue in inputData.items():

                        if isinstance(fieldValue, ndarray):
                            dataValues = masked_invalid(fieldValue)
                            dataValues = masked_values(fieldValue,
                                                       self.missingValue)
                            dataValues.harden_mask()
                            self.addField(fieldName, fieldValue)
                        else:
                            self.addField(fieldName, fieldValue)

                else:
                    raise fatalError(
                        "Input Data not supported",
                        "type(inputData)=%s" % str(type(inputData)))
예제 #7
0
    def addProfile(self,
                   pressure,
                   temperature,
                   dewPointTemperature,
                   hPa=True,
                   celsius=True,
                   method=0,
                   initialLevel=0,
                   parcel=True,
                   label=None,
                   diagnostics=False,
                   markers=True,
                   useVirtual=True,
                   **kwargs):
        """
        Add a profile to the Skew-T axis
        
        .. _`matplotlib.legend`: http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.legend
        
        .. _ndarray: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html
        
        .. _MaskedArray: https://docs.scipy.org/doc/numpy/reference/maskedarray.html
        
        The input data can  be ndarray_ or MaskedArray_.
        If MaskedArray_ are used, the pressure levels with masked or invalid entries 
        in the pressure and temperature arrays are removed. 
        Masked values in the dewPointTemperature are not plotted.
        
        Parameters
        ----------
        
        pressure : ndarray_ or MaskedArray_
            Pressure levels of the sounding
        
        temperature : ndarray_ or MaskedArray_
            Temperature profile at pressure levels
        
        dewPointTemperature : : ndarray_ or MaskedArray_
            Dew point temperature at pressure levels
        
        
        hPa: bool, optional
            If is True, the pressure levels are in hPa. Otherwise Pascals is
            assumed
            
        celsius : bool, optional
            If is True, the temperatures units correspond to celsius degrees.
            Otherwise Kelvin degrees units are assumed
            
        parcel : bool, optional
            If True, the parcel analysis is carried out.
            
        method : int, optional
            Parcel analysis method used. Supported:
        
            * Most Unstable  : method=0
            * Single Parcel: method=1
            * Mixed Layer  : method=2 (Not supported yet)

        initialLevel : int, optional
            Initial level (index) used to compute the parcel analysis.
            Levels below this value are ignored.
            
            For the Single Parcel analysis, this level correspond to the parcel used.
            By default, the initial level is 0 (surface).
            
            For the Most Unstable method, this value is ignored.
        label : str, optional
            Label assigned to the profile lines. If None, no label is used.
            When a line is labeled, the legend is added automatically to the plot.
            use keyword **loc** to control the position.
        diagnostics : bool, optional
            If True a text box is added to the upper right corner with some diagnostics
            from the parcel analysis.
        
        markers: bool, optional
            If True, the LCL, LFC and EL are marked in the plot with markers.
            
        useVirtual : bool, optional
            If True, in the parcel analysis, CAPE and CIN are computed used
            the virtual temperature. The temperatures plotted in the SkewT diagram
            will correspond to virtual temperature instead of temperature. 
            If False, virtual temperatures corrections are neglected and the
            original temperature is plotted.
            
        Other Parameters
        ----------------
        
        loc : str
            Legend location. See `matplotlib.legend`_ for more details.
            
        kwargs : extra
            The remaining extra keyword arguments are passed to the plot function
            when plotting the temperature profiles.
        """

        mask = numpy.zeros_like(pressure, dtype=bool)

        if isinstance(pressure, masked_array):
            pressure[pressure.mask] = numpy.nan
            mask = logical_or(mask, getmaskarray(pressure))
        if isinstance(temperature, masked_array):
            temperature[temperature.mask] = numpy.nan
            mask = logical_or(mask, getmaskarray(temperature))
        if isinstance(dewPointTemperature, masked_array):
            dewPointMask = getmaskarray(dewPointTemperature)
            dewPointTemperature.data[dewPointMask] = numpy.nan
            dewPointTemperature = numpy.asarray(dewPointTemperature.data,
                                                dtype=numpy.float32)

        pressure = masked_invalid(pressure[~mask])
        temperature = masked_invalid(temperature[~mask])
        dewPointTemperature = masked_invalid(dewPointTemperature[~mask])

        # Convert temperatures and pressure to hPa
        if not hPa:
            pressure /= 100

        if not celsius:
            temperature -= degCtoK
            dewPointTemperature -= degCtoK

        if parcel:

            parcelAnalysisResult = parcelAnalysis(pressure,
                                                  temperature,
                                                  dewPointTemperature,
                                                  hPa=True,
                                                  celsius=True,
                                                  useVirtual=1,
                                                  initialLevel=initialLevel,
                                                  method=method)

            initialLevel = parcelAnalysisResult['initialLevel']
            initialTemperature = temperature[initialLevel]

            pressureAtLCL = parcelAnalysisResult['pressureAtLCL']
            temperatureAtLCL = parcelAnalysisResult['temperatureAtLCL']

            pressureAtLFC = parcelAnalysisResult['pressureAtLFC']
            temperatureAtLFC = parcelAnalysisResult['temperatureAtLFC']

            pressureAtEL = parcelAnalysisResult['pressureAtEL']
            temperatureAtEL = parcelAnalysisResult['temperatureAtEL']

            parcelTemperature = liftParcel(initialTemperature,
                                           pressure,
                                           pressureAtLCL,
                                           initialLevel=initialLevel,
                                           hPa=True,
                                           celsius=True)

            # Add LCL
            belowLCL = numpy.where(pressure > pressureAtLCL, True, False)
            newParcelTemperature = numpy.concatenate(
                (parcelTemperature[belowLCL], [temperatureAtLCL],
                 parcelTemperature[~belowLCL]))
            newPressure = numpy.concatenate(
                (pressure[belowLCL], [pressureAtLCL], pressure[~belowLCL]))

            # Add EL
            belowEL = numpy.where(newPressure > pressureAtEL, True, False)
            newParcelTemperature = numpy.concatenate(
                (newParcelTemperature[belowEL], [temperatureAtEL],
                 newParcelTemperature[~belowEL]))
            newPressure = numpy.concatenate(
                (newPressure[belowEL], [pressureAtEL], newPressure[~belowEL]))

            belowLFC = numpy.where(newPressure > pressureAtLFC, True, False)
            newParcelTemperature = numpy.concatenate(
                (newParcelTemperature[belowLFC], [temperatureAtLFC],
                 newParcelTemperature[~belowLFC]))
            newPressure = numpy.concatenate(
                (newPressure[belowLFC], [pressureAtLFC],
                 newPressure[~belowLFC]))

            newTemperature = numpy.interp(newPressure, pressure[::-1],
                                          temperature[::-1])
            newParcelTemperature = masked_invalid(newParcelTemperature)
            if useVirtual:
                newDewPointTemperature = numpy.interp(
                    newPressure, pressure[::-1], dewPointTemperature[::-1])
                newTemperature = virtualTemp3(newTemperature,
                                              newDewPointTemperature,
                                              newPressure * 100)

                belowLCL = (newPressure >= pressureAtLCL)

                newParcelTemperature[belowLCL] = virtualTemp3(
                    newParcelTemperature[belowLCL],
                    dewPointTemperature[initialLevel],
                    newPressure[belowLCL] * 100)
                aboveLCL = (newPressure < pressureAtLCL)

                newParcelTemperature[aboveLCL] = virtualTemp4(
                    newParcelTemperature[aboveLCL],
                    newPressure[aboveLCL] * 100)

        else:
            newTemperature = temperature
            newPressure = pressure

        kwargs['zorder'] = kwargs.pop('zorder', 5)
        kwargs['linewidth'] = kwargs.pop('linewidth', 2.0)
        kwargs['linestyle'] = kwargs.pop('linestyle', '-')
        loc = kwargs.pop('loc', 'best')

        temperatureLine, = self.plot(newTemperature, newPressure, 'r',
                                     **kwargs)

        self.plot(dewPointTemperature, pressure, 'b', **kwargs)

        if label is not None:
            self.linesHandlers.append(temperatureLine)
            self.linesLabels.append(label)
            self.legend(self.linesHandlers, self.linesLabels, loc=loc)

        if parcel:
            self.plot(newParcelTemperature, newPressure, 'k', **kwargs)

            if parcelAnalysisResult['CAPE'] > 0:
                # Positive Buoyancy
                cond1 = (newPressure <= pressureAtLFC) * (newPressure >=
                                                          pressureAtEL)

                self.fill_betweenx(newPressure, newParcelTemperature, newTemperature, where=cond1, \
                                   color="#ff0009", alpha=0.4, zorder=10)

                # Negative Buoyancy

                validMask = ~getmaskarray(masked_invalid(newParcelTemperature))

                cond2 = ((newParcelTemperature[validMask] <=
                          newTemperature[validMask]) *
                         (newPressure[validMask] >= pressureAtLFC))

                self.fill_betweenx(newPressure[validMask], newParcelTemperature[validMask],
                                   newTemperature[validMask], where=cond2, \
                                   color="#045cff", alpha=0.4, zorder=10)

            if markers:
                if useVirtual:
                    temperatureAtLCL = virtualTemp4(temperatureAtLCL,
                                                    pressureAtLCL * 100)
                    temperatureAtLFC = virtualTemp4(temperatureAtLFC,
                                                    pressureAtLFC * 100)
                    temperatureAtEL = virtualTemp4(temperatureAtEL,
                                                   pressureAtEL * 100)

                self.plot(temperatureAtLCL,
                          pressureAtLCL,
                          ls='',
                          marker='o',
                          color='r')
                self.plot(temperatureAtLFC,
                          pressureAtLFC,
                          ls='',
                          marker='o',
                          color='g')
                self.plot(temperatureAtEL,
                          pressureAtEL,
                          ls='',
                          marker='o',
                          color='k')

            if diagnostics:
                # Add text to sounding
                dtext = "Diagnostics:\n"
                # dtext ="Parcel: %s\n"%ptype.upper()

                # dtext+="P  :%6.1fhPa\n"%startp
                # dtext+="T :  %4.1fC\n"%startt
                # dtext+="Td :  %4.1fC\n"%startdp
                dtext += "-------------\n"
                dtext += "P_par:%6.1fhPa\n" % (pressure[initialLevel])
                dtext += "P_LCL:%6.1fhPa\n" % (
                    parcelAnalysisResult['pressureAtLCL'])
                dtext += "T_LCL:%4.1fC\n" % (
                    parcelAnalysisResult['temperatureAtLCL'])
                dtext += "P_LFC:%6.1fhPa\n" % (
                    parcelAnalysisResult['pressureAtLFC'])
                dtext += "T_LFC:%4.1fC\n" % (
                    parcelAnalysisResult['temperatureAtLFC'])
                dtext += "P_EL:%6.1fhPa\n" % (
                    parcelAnalysisResult['pressureAtEL'])
                dtext += "T_EL:%4.1fC\n" % (
                    parcelAnalysisResult['temperatureAtEL'])
                dtext += "CAPE:%.1f\n" % parcelAnalysisResult['CAPE']
                dtext += "CIN: %.1fJ" % parcelAnalysisResult['CIN']

                axesBox = self.get_position().get_points()

                self.figure.text(axesBox[1, 0],
                                 axesBox[1, 1],
                                 dtext,
                                 fontname="monospace",
                                 backgroundcolor='white',
                                 zorder=10,
                                 verticalalignment='top',
                                 horizontalalignment='right',
                                 multialignment="left")