Ejemplo n.º 1
0
    def fetchFromWeb(self, soundingDate, stationId):
        """
        Load University of Wyoming sound data from the uwyo website

        .. _datetime:`https://docs.python.org/2/library/datetime.html`

        Parameters
        ----------

        soundingDate : str or datetime_
            Date of the selected sounding to download. The date could be a datetime_ object
            or an string. The string should have the following format: "%Y%m%d:%H"

        stationId : str
            Station ID

        """
        # Inspired in pymeteo.uwyo.py , fetch_from_web

        if isinstance(soundingDate, string_types):
            soundingDate = datetime.strptime(soundingDate, "%Y%m%d:%H")

        base_url = "http://weather.uwyo.edu/cgi-bin/sounding"

        payload = {
            "TYPE": r"TEXT:LIST",
            "YEAR": soundingDate.strftime("%Y"),
            "MONTH": soundingDate.strftime("%m"),
            "FROM": soundingDate.strftime("%d%H"),
            "TO": soundingDate.strftime("%d%H"),
            "STNM": stationId,
        }

        myresponse = requests.get(base_url, params=payload)

        if "Can't get" in myresponse.text:
            raise fatalError(
                "Error retrieving sounding from UW web page.",
                "Observations not present for that station or that date",
                "Check the date and the station name",
                "Selected Station ID:%s" % stationId,
                "Selected Date:%s" % soundingDate.strftime("%Y%m%d:%H"),
            )
        else:
            parsedResponse = UW_HTMLParser()
            parsedResponse.feed(myresponse.text)

            with NamedTemporaryFile(mode="w") as tempFile:
                tempFile.write("\n".join(parsedResponse.soundingData))
                self.fetchFromTxtFile(tempFile.name)
Ejemplo n.º 2
0
    def getCleanSounding(self):
        """  
        Clean the sounding, when Temperature or pressure has a missing values,
        removing that pressure level.
        
        It returns the pressure in Pa and temperatures in Celsius
        """

        pressure = self['pressure']
        temperature = self['temperature']

        dewPointTemperature = self['dewPointTemperature']
        dewPointTemperature[getmaskarray(
            dewPointTemperature)] = self.missingValue

        if pressure.units is not None:
            if pressure.units.lower() == 'hpa':
                hPa = True
            elif pressure.units.lower() == 'pa':
                hPa = False
            else:
                raise fatalError(
                    "Error getting clean sounding plot",
                    "Pressure units not supported:%s" % pressure.units,
                    "Supported: hPa or Pa ")
        else:
            hPa = True

        if temperature.units is not None:

            if dewPointTemperature.units is not None:
                if temperature.units.lower(
                ) != dewPointTemperature.units.lower():
                    raise fatalError(
                        "Error getting clean sounding plot",
                        "Temperature units: %s" % temperature.units,
                        "Dew Point Temp: %s" % dewPointTemperature.units)

            if temperature.units.lower() == 'c':
                celsius = True
            elif temperature.units.lower() == 'k':
                celsius = False
            else:
                raise fatalError(
                    "Error getting clean sounding plot",
                    "Temperature units not supported:%s" % temperature.units,
                    "Supported: C or K ")
        else:
            celsius = True

        mask = ~mask_or(
            getmaskarray(pressure), getmaskarray(temperature), shrink=False)

        if hPa:
            _pressure = pressure.data[mask]
        else:
            _pressure = pressure.data[mask] / 100

        if celsius:
            _temperature = temperature.data[mask]
            _dewPointTemperature = masked_values(
                dewPointTemperature.data[mask], self.missingValue)

        else:
            _temperature = temperature.data[mask] - 273.15
            _dewPointTemperature = masked_values(
                dewPointTemperature.data[mask], self.missingValue) - 273.15

        return (_pressure, _temperature, _dewPointTemperature)
Ejemplo n.º 3
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)))
Ejemplo n.º 4
0
def parcelAnalysis(pressure,
                   temperature,
                   dewPointTemperature,
                   hPa=False,
                   celsius=False,
                   maxPressureStep=2.,
                   fullFields=1,
                   method=0,
                   initialLevel=0,
                   useVirtual=1,
                   tolerance=0.1,
                   maxIterations=20,
                   depth=30000):
    """
    Function to perform a parcel analysis
    
    The shape of the input arrays (*pressure*, *temperature* and *dewPointTemperature*) 
    should be equal. 

    By default pressure and temperature are treated as Pascals and Kelvins degrees respectively.
    The working units can be selected by *hPa* and *celsius* keywords.
    The output values will automatically be converted to the selected units.
    
    The dimensions of the arrays should be one of the followings:
    
    * [time,height,latitude or y ,longitude or x] (3D + time)
    * [height,latitude or y ,longitude or x] (3D)
    * [height] 1D)
    
    See :py:func:`_parcelAnalysis1D` for a complete description of input parameters
    and returned values.  
    
    Parameters
    ----------
    
    hPa : bool, optional
        If True, pressure is treated as in hPa instead of Pa.
    
    celsius : bool, optional
        If True, temperature is considered as Celsius instead of Kelvin degrees.     
                          
    Other Parameters
    ----------------
    
    See :py:func:`_parcelAnalysis1D` for a complete description of input parameters.
    
    Returns
    -------
    
    See :py:func:`_parcelAnalysis1D` for a complete description of the returned values.
         
    """

    if ((pressure.shape != temperature.shape)
            or (dewPointTemperature.shape != temperature.shape)):

        raise fatalError(
            "Error computing Parcel Analysis",
            "Input array shape mismatch",
            "pressure.shape = %s" % str(pressure.shape),
            "temperature.shape = %s" % str(temperature.shape),
            "dewPointTemperature.shape = %s" % str(dewPointTemperature.shape),
        )

    if isinstance(dewPointTemperature, masked_array):
        dewPointTemperature.data[dewPointTemperature.mask] = -9999.

    pressure = numpy.asarray(pressure, dtype=numpy.float32)
    temperature = numpy.asarray(temperature, dtype=numpy.float32)
    dewPointTemperature = numpy.asarray(dewPointTemperature,
                                        dtype=numpy.float32)

    if hPa:
        pressureConversionFactor = 100
        pressureUnits = 'hPa'
    else:
        pressureConversionFactor = 1
        pressureUnits = 'Pa'

    if celsius:
        temperatureConversionOffset = degCtoK
        temperatureUnits = 'Celsius'
    else:
        temperatureConversionOffset = 0
        temperatureUnits = 'Kelvin'

    args = (pressure * pressureConversionFactor,
            temperature + temperatureConversionOffset,
            dewPointTemperature + temperatureConversionOffset)
    kwargs = dict(maxPressureStep=maxPressureStep,
                  fullFields=fullFields,
                  method=method,
                  initialLevel=initialLevel,
                  tolerance=tolerance,
                  maxIterations=maxIterations,
                  useVirtual=useVirtual,
                  depth=depth)

    if pressure.ndim == 4:
        myParcelAnalysis = _parcelAnalysis4D(*args, **kwargs)
    elif pressure.ndim == 3:
        myParcelAnalysis = _parcelAnalysis3D(*args, **kwargs)
    elif pressure.ndim == 1:
        myParcelAnalysis = _parcelAnalysis1D(*args, **kwargs)
    else:
        raise fatalError(
            "Error computing Parcel Analysis",
            "Number of array dimensions not supported"
            "Number of array dimensions = %d" % pressure.ndim)

    # Convert the values to the selected units
    for key in myParcelAnalysis:

        if 'temperature' in key:
            myParcelAnalysis[key] -= temperatureConversionOffset

        if 'pressure' in key:
            myParcelAnalysis[key] /= pressureConversionFactor

    myParcelAnalysis['pressureUnits'] = pressureUnits
    myParcelAnalysis['temperatureUnits'] = temperatureUnits

    return myParcelAnalysis