def test_hPa2Pa(self):
     """Convert pressure from hPa to Pa"""
     self.assertEqual(metutils.convert(0, "hPa", "Pa"), 0.0)
     self.assertEqual(metutils.convert(1, "hPa", "Pa"), 100.0)
     self.assertEqual(metutils.convert(10, "hPa", "Pa"), 1000.0)
     self.assertEqual(metutils.convert(15, "hPa", "Pa"), 1500.0)
     self.assertEqual(metutils.convert(600, "hPa", "Pa"), 60000.0)
 def test_mps2kmphr(self):
     """Convert from m/s to km/h"""
     self.assertEqual(metutils.convert(0, "mps", "kph"), 0.)
     self.assertEqual(metutils.convert(1, "mps", "kph"), 3.6)
     self.assertEqual(metutils.convert(5, "mps", "kph"), 18.)
     self.assertEqual(metutils.convert(15, "mps", "kph"), 54.)
     self.assertEqual(metutils.convert(100, "mps", "kph"), 360.)
Exemple #3
0
 def test_mps2kmphr(self):
     """Convert from m/s to km/h"""
     self.assertEqual(metutils.convert(0, "mps", "kph"), 0.)
     self.assertEqual(metutils.convert(1, "mps", "kph"), 3.6)
     self.assertEqual(metutils.convert(5, "mps", "kph"), 18.)
     self.assertEqual(metutils.convert(15, "mps", "kph"), 54.)
     self.assertEqual(metutils.convert(100, "mps", "kph"), 360.)
Exemple #4
0
 def test_kgmetre2hPa(self):
     """Convert from Pa to hPa"""
     self.assertEqual(metutils.convert(0, "Pa", "hPa"), 0.0)
     self.assertEqual(metutils.convert(1, "Pa", "hPa"), 0.01)
     self.assertEqual(metutils.convert(100, "Pa", "hPa"), 1.0)
     self.assertEqual(metutils.convert(200, "Pa", "hPa"), 2.0)
     self.assertEqual(metutils.convert(600, "Pa", "hPa"), 6.0)
Exemple #5
0
 def test_hPa2Pa(self):
     """Convert pressure from hPa to Pa"""
     self.assertEqual(metutils.convert(0, "hPa", "Pa"), 0.0)
     self.assertEqual(metutils.convert(1, "hPa", "Pa"), 100.0)
     self.assertEqual(metutils.convert(10, "hPa", "Pa"), 1000.0)
     self.assertEqual(metutils.convert(15, "hPa", "Pa"), 1500.0)
     self.assertEqual(metutils.convert(600, "hPa", "Pa"), 60000.0)
 def test_kgmetre2hPa(self):
     """Convert from Pa to hPa"""
     self.assertEqual(metutils.convert(0, "Pa", "hPa"), 0.0)
     self.assertEqual(metutils.convert(1, "Pa", "hPa"), 0.01)
     self.assertEqual(metutils.convert(100, "Pa", "hPa"), 1.0)
     self.assertEqual(metutils.convert(200, "Pa", "hPa"), 2.0)
     self.assertEqual(metutils.convert(600, "Pa", "hPa"), 6.0)
Exemple #7
0
    def pressureProfile(self, i, R):
        """
        Calculate the pressure profile at time `i` at the radiuses `R`
        around the tropical cyclone.


        :type  i: int
        :param i: the time.

        :type  R: :class:`numpy.ndarray`
        :param R: the radiuses around the tropical cyclone.
        """
        from PressureInterface.pressureProfile import PrsProfile as PressureProfile

        p = PressureProfile(R,
                            convert(self.track.EnvPressure[i], 'hPa', 'Pa'),
                            convert(self.track.CentralPressure[i], 'hPa',
                                    'Pa'),
                            self.track.rMax[i],
                            self.track.Latitude[i],
                            self.track.Longitude[i],
                            self.beta,
                            beta1=self.beta1,
                            beta2=self.beta2)
        try:
            pressure = getattr(p, self.profileType)
        except AttributeError:
            msg = '%s not implemented in pressureProfile' % self.profileType
            log.exception(msg)
        return pressure()
Exemple #8
0
def vmax(pCentre, pEnv, type="holland", beta=1.3, rho=1.15):
    """
    Calculate the maximum wind speed from the pressure difference.

    :param float pc: central pressure (Pa)
    :param float pe: environmental pressure (Pa)
    :param str type: which Vmax relation to use (Willoughby & Rahn,
                     Holland or Atkinson & Holliday)
    :param float beta: Holland's (1980) beta parameter. Only used for the
                       Holland estimation (type=holland)
    :param float rho: air density (default=1.15 kg/m^3)
    :return: maximum wind speed. For types 1 & 2, this is a
             gradient level wind. The relation used in type 3
             (Atkinson & Holliday) was determined using surface
             wind observations so should be used with caution at
             the gradient level.
    :raises ValueError: if environmental pressure is lower than central pressure

    Note: The pressure should ideally be passed in units of Pa, but the
    function will accept hPa and automatically convert to Pa.

    """
    # Convert from hPa to Pa if necessary:
    if pCentre < 10000:
        pCentre = metutils.convert(pCentre, "hPa", "Pa")

    if pEnv < 10000:
        pEnv = metutils.convert(pEnv, "hPa", "Pa")

    if pEnv < pCentre:
        raise ValueError, "Error in vmax - Environmental pressure is less than central pressure. Check values and/or order of input arguments"

    dP = pEnv - pCentre

    if type == "willoughby":
        # Default: Most advanced estimation technique:
        # Willoughby & Rahn (2004), Parametric Representation of the
        # Primary Hurricane Vortex. Part I: Observations and
        # Evaluation of the Holland (1980) Model.
        # Mon. Wea. Rev., 132, 3033-3048
        vMax = 0.6252 * sqrt(dP)
    elif type == "holland":
        # Holland (1980), An Analytic Model of the Wind and Pressure
        # Profiles in Hurricanes. Mon. Wea. Rev, 108, 1212-1218
        # Density of air is assumed to be 1.15 kg/m^3.
        # beta is assumed to be 1.3. Other values can be specified.
        # Gradient level wind (assumed maximum).
        vMax = sqrt(beta * dP / (exp(1) * rho))
    elif type == "atkinson":
        # Atkinson and Holliday (1977), Tropical Cyclone Minimum Sea
        # Level Pressure / Maximum Sustained Wind Relationship for
        # the Western North Pacific. Mon. Wea. Rev., 105, 421-427
        # Maximum 10m, 1-minute wind speed. Uses pEnv as 1010 hPa
        vMax = 3.04 * power(1010 - metutils.convert(pCentre, "Pa", "hPa"),
                            0.644)
    else:
        raise NotImplementedError, "Vmax type " + type + " not implemented"
    return vMax
Exemple #9
0
def vmax(pCentre, pEnv, type="holland", beta=1.3, rho=1.15):
    """
    Calculate the maximum wind speed from the pressure difference.

    :param float pc: central pressure (Pa)
    :param float pe: environmental pressure (Pa)
    :param str type: which Vmax relation to use (Willoughby & Rahn,
                     Holland or Atkinson & Holliday)
    :param float beta: Holland's (1980) beta parameter. Only used for the
                       Holland estimation (type=holland)
    :param float rho: air density (default=1.15 kg/m^3)
    :return: maximum wind speed. For types 1 & 2, this is a
             gradient level wind. The relation used in type 3
             (Atkinson & Holliday) was determined using surface
             wind observations so should be used with caution at
             the gradient level.
    :raises ValueError: if environmental pressure is lower than central pressure
    
    Note: The pressure should ideally be passed in units of Pa, but the
    function will accept hPa and automatically convert to Pa.
    
    """
    # Convert from hPa to Pa if necessary:
    if pCentre < 10000:
        pCentre = metutils.convert(pCentre, "hPa", "Pa")

    if pEnv < 10000:
        pEnv = metutils.convert(pEnv, "hPa", "Pa")

    if pEnv < pCentre:
        raise ValueError, "Error in vmax - Environmental pressure is less than central pressure. Check values and/or order of input arguments"

    dP = pEnv - pCentre

    if type == "willoughby":
        # Default: Most advanced estimation technique:
        # Willoughby & Rahn (2004), Parametric Representation of the
        # Primary Hurricane Vortex. Part I: Observations and
        # Evaluation of the Holland (1980) Model.
        # Mon. Wea. Rev., 132, 3033-3048
        vMax = 0.6252*sqrt(dP)
    elif type == "holland":
        # Holland (1980), An Analytic Model of the Wind and Pressure
        # Profiles in Hurricanes. Mon. Wea. Rev, 108, 1212-1218
        # Density of air is assumed to be 1.15 kg/m^3.
        # beta is assumed to be 1.3. Other values can be specified.
        # Gradient level wind (assumed maximum).
        vMax = sqrt(beta*dP/(exp(1)*rho))
    elif type == "atkinson":
        # Atkinson and Holliday (1977), Tropical Cyclone Minimum Sea
        # Level Pressure / Maximum Sustained Wind Relationship for
        # the Western North Pacific. Mon. Wea. Rev., 105, 421-427
        # Maximum 10m, 1-minute wind speed. Uses pEnv as 1010 hPa
        vMax = 3.04*power(1010 - metutils.convert(pCentre,"Pa","hPa"), 0.644)
    else:
        raise NotImplementedError, "Vmax type " + type + " not implemented"
    return vMax
Exemple #10
0
 def test_deg2km(self):
     """Convert distance in degrees to distance in km"""
     self.assertEqual(metutils.convert(0, "deg", "km"), 0)
     self.assertAlmostEqual(metutils.convert(1, "deg", "km"),
                            (1 / (360 / (2 * pi * 6367))), 3)
     self.assertAlmostEqual(metutils.convert(2, "deg", "km"),
                            (2 / (360 / (2 * pi * 6367))), 3)
     self.assertAlmostEqual(metutils.convert(10, "deg", "km"),
                            (10 / (360 / (2 * pi * 6367))), 3)
Exemple #11
0
 def test_km2deg(self):
     """Convert distance in km to distance in degrees"""
     self.assertEqual(metutils.convert(0, "km", "deg"), 0)
     self.assertAlmostEqual(metutils.convert(1, "km", "deg"),
                            360 / (2 * pi * 6367), 3)
     self.assertAlmostEqual(metutils.convert(2, "km", "deg"),
                            720 / (2 * pi * 6367), 3)
     self.assertAlmostEqual(metutils.convert(10, "km", "deg"),
                            3600 / (2 * pi * 6367), 3)
Exemple #12
0
    def plotMap(self):
        """Plot return period wind speed maps"""

        lon, lat, years, inputData = self.loadFile(self.inputFile, 'wspd')
        if lon.min() > 180.:
            lon = lon - 360.

        [xgrid, ygrid] = np.meshgrid(lon, lat)
        dmask = inputData.mask
        inputData = metutils.convert(inputData, 'mps', self.plotUnits.units)
        inputData = ma.array(inputData, mask=dmask)
        map_kwargs = dict(llcrnrlon=xgrid.min(),
                          llcrnrlat=ygrid.min(),
                          urcrnrlon=xgrid.max(),
                          urcrnrlat=ygrid.max(),
                          projection='merc',
                          resolution='i')

        for i, year in enumerate(years):
            log.debug("Plotting %d-year return period hazard map", year)
            title = '%d-Year ARI Cyclonic Wind Hazard' % (year)
            imageFilename = '%d_yrRP_hazard_map.png' % (year)
            filename = pjoin(self.plotPath, imageFilename)
            cbarlab = "Wind speed (%s)"%self.plotUnits.units
            levels = self.plotUnits.levels
            if self.smooth:
                dx = np.mean(np.diff(xgrid))
                data = smooth(inputData[i, :, :], int(1/dx))
            else:
                data = inputData[i, :, :]

            saveHazardMap(data, xgrid, ygrid, title, levels,
                          cbarlab, map_kwargs, filename)

            self.progressbar.update((i + 1) / float(len(years)), 0.0, 0.9)
Exemple #13
0
    def plotMap(self):
        """Plot return period wind speed maps"""

        lon, lat, years, inputData = self.loadFile(self.inputFile, 'wspd')
        if lon.min() > 180.:
            lon = lon - 360.

        [xgrid, ygrid] = np.meshgrid(lon, lat)
        inputData = metutils.convert(inputData, 'mps', self.plotUnits.units)

        map_kwargs = dict(llcrnrlon=xgrid.min(),
                          llcrnrlat=ygrid.min(),
                          urcrnrlon=xgrid.max(),
                          urcrnrlat=ygrid.max(),
                          projection='merc',
                          resolution='i')

        for i, year in enumerate(years):
            log.debug("Plotting %d-year return period hazard map"%(year))
            title = '%d-Year Return Period Cyclonic Wind Hazard' % (year)
            imageFilename = '%d_yrRP_hazard_map.png' % (year)
            filename = pjoin(self.plotPath, imageFilename)
            cbarlab = "Wind speed (%s)"%self.plotUnits.units
            levels = self.plotUnits.levels
            saveHazardMap(inputData[i, :, :], xgrid, ygrid, title, levels,
                          cbarlab, map_kwargs, filename)

            self.progressbar.update((i + 1) / float(len(years)), 0.0, 0.9)
Exemple #14
0
 def cP(self):
     """
     Current pressure.
     """
     cP = self.profile.cP
     if cP < 10000:
         cP = metutils.convert(cP, "hPa", "Pa")
     return cP
Exemple #15
0
 def eP(self):
     """
     Environment pressure.
     """
     eP = self.profile.eP
     if eP < 10000:
         eP = metutils.convert(eP, "hPa", "Pa")
     return eP
Exemple #16
0
 def eP(self):
     """
     Environment pressure.
     """
     eP = self.profile.eP
     if eP < 10000:
         eP = metutils.convert(eP, 'hPa', 'Pa')
     return eP
Exemple #17
0
 def __init__(self, lat, lon, eP, cP, rMax):
     beta = 1.881093 - 0.010917 * np.abs(lat) -\
            0.005567 * metutils.convert(rMax, "m", "nm")
     if beta < 0.8:
         beta = 0.8
     if beta > 2.2:
         beta = 2.2
     HollandWindProfile.__init__(self, lat, lon, eP, cP, rMax, beta)
Exemple #18
0
 def cP(self):
     """
     Current pressure.
     """
     cP = self.profile.cP
     if cP < 10000:
         cP = metutils.convert(cP, 'hPa', 'Pa')
     return cP
Exemple #19
0
    def __init__(self, lat, lon, eP, cP, rMax, windSpeedModel):
        self.rho = 1.15  # density of air
        self.lat = lat
        self.lon = lon
        self.eP = eP
        self.cP = cP
        self.rMax = rMax
        self.speed = windSpeedModel(self)
        self.f = metutils.coriolis(lat)
        self.vMax_ = None

        if eP < 10000.:
            self.eP = metutils.convert(eP, 'hPa', 'Pa')
        else:
            self.eP = eP

        if cP < 10000.:
            self.cP = metutils.convert(cP, 'hPa', 'Pa')
        else:
            self.cP = cP
Exemple #20
0
    def localWindField(self, i):
        """
        Calculate the local wind field at time `i` around the
        tropical cyclone.

        :type  i: int
        :param i: the time.
        """
        lat = self.track.Latitude[i]
        lon = self.track.Longitude[i]
        beta = self.track.beta[i]
        eP = convert(self.track.EnvPressure[i], 'hPa', 'Pa')
        cP = convert(self.track.CentralPressure[i], 'hPa', 'Pa')
        rMax = self.track.rMax[i]*1000
        vFm = convert(self.track.Speed[i], 'kph', 'mps')
        thetaFm = bearing2theta(self.track.Bearing[i] * np.pi/180.)
        thetaMax = self.thetaMax
        beta = self.track.beta[i]

        #FIXME: temporary way to do this
        cls = windmodels.profile(self.profileType)
        params = windmodels.profileParams(self.profileType)
        values = [getattr(self, p) for p in params if hasattr(self, p)]
        profile = cls(lat, lon, eP, cP, rMax, beta, *values)

        R, theta = self.polarGridAroundEye(i)

        P = self.pressureProfile(i, R)

        #FIXME: temporary way to do this
        cls = windmodels.field(self.windFieldType)
        params = windmodels.fieldParams(self.windFieldType)
        values = [getattr(self, p) for p in params if hasattr(self, p)]
        windfield = cls(profile, *values)

        Ux, Vy = windfield.field(R * 1000, theta, vFm, thetaFm,  thetaMax)

        log.debug("UU: {0}, VV: {1}".format(Ux.max(), Vy.max()))

        return (Ux, Vy, P)
Exemple #21
0
def pDiff(vMax, pEnv, vMaxType="holland", beta=1.3, rho=1.15):
    """
    Inverse functions to calculate central pressure from vMax
    Assumes vMax is given in metres/second.
    Returns pCentre in Pa.

    """
    if pEnv < 10000:
        pEnv = metutils.convert(pEnv, "hPa", "Pa")

    if vMaxType == "willoughby":
        dP = (vMax / 0.6252)**2
    elif vMaxType == "holland":
        dP = rho * exp(1) * (vMax**2) / beta
    elif vMaxType == "atkinson":
        dP = (vMax / 3.04)**(1 / 0.644)
        dP = metutils.convert(dP, "hPa", "Pa")
    else:
        raise NotImplementedError("Vmax type " + vMaxType + " not implemented")

    pCentre = pEnv - dP
    return pCentre
Exemple #22
0
def calculateWindField(lon, lat, pEnv, pCentre, rMax, vFm, thetaFm, beta,
                       profileType='powell', windFieldType='kepert'):

    pCentre = metutils.convert(pCentre, 'hPa', 'Pa')
    pEnv = metutils.convert(pEnv, 'hPa', 'Pa')
    vFm = metutils.convert(vFm, 'kmh', 'mps')
    thetaFm = bearing2theta(np.pi * thetaFm / 180.)
    thetaMax = 70.
    rmax = metutils.convert(rMax, 'km', 'm')
    cls = windmodels.profile(profileType)
    if profileType=="holland":
        profile = cls(lat, lon, pEnv, pCentre, rmax, beta)
    else:
        profile = cls(lat, lon, pEnv, pCentre, rmax)
    R, theta = polarGridAroundEye(lon, lat, 5.)
    gradV = profile.velocity(R*1000)
    cls = windmodels.field(windFieldType)
    windfield = cls(profile)
    Ux, Vy = windfield.field(R*1000, theta, vFm, thetaFm, thetaMax)

    surfV = np.sqrt(Ux*Ux+Vy*Vy)*1.268 # Gust conversion factor
    return gradV, surfV
Exemple #23
0
def pDiff(vMax, pEnv, vMaxType="holland", beta=1.3, rho=1.15):
    """
    Inverse functions to calculate central pressure from vMax
    Assumes vMax is given in metres/second.
    Returns pCentre in Pa.
    """
    if pEnv < 10000:
        pEnv = metutils.convert(pEnv, "hPa", "Pa")

    if vMaxType == "willoughby":
        dP = (vMax/0.6252)**2
    elif vMaxType == "holland":
        dP = rho*exp(1)*(vMax**2)/beta
    elif vMaxType == "atkinson":
        dP = (vMax/3.04)**(1/0.644)
        dP = metutils.convert(dP, "hPa", "Pa")
    else:
        raise NotImplementedError, \
              "Vmax type " + vMaxType + " not implemented"

    pCentre = pEnv - dP
    return pCentre
Exemple #24
0
def plotPressurefield(xGrid, yGrid, pressure, title='Cyclone pressure field',
                    xlabel='Longitude', ylabel='Latitude',
                    infostring='', fileName=None):
    """
    Plot the wind field for a given grid.
    xGrid, yGrid and speed are arrays of the same size. (xGrid and yGrid
    are typically generated by [xGrid,yGrid] = meshgrid(lon,lat))
    """
    pMin = pressure.min()
    if pMin > 8000.:
        pressure = metutils.convert(pressure, 'Pa', 'hPa')
    pylab.clf()
    dl = 5.
    llLon = min(xGrid[0, :])
    urLon = max(xGrid[0, :])
    llLat = min(yGrid[:, 0])
    urLat = max(yGrid[:, 0])
    meridians = np.arange(dl*floor(llLon/dl), dl*ceil(urLon/dl), dl)
    parallels = np.arange(dl*floor(llLat/dl), dl*ceil(urLat/dl), dl)
    levels = np.arange(900, 1020, 5)

    m = Basemap(projection='cyl',
                resolution='i',
                llcrnrlon=llLon,
                urcrnrlon=urLon,
                llcrnrlat=llLat,
                urcrnrlat=urLat)

    m.contourf(xGrid, yGrid, pressure, levels)
    #m.plot(cLon, cLat, 'k.-', markersize=2)

    pylab.colorbar()
    pylab.title(title)

    m.drawcoastlines()
    m.drawparallels(parallels, labels=[1, 0, 0, 1], fontsize=9)
    m.drawmeridians(meridians, labels=[1, 0, 0, 1], fontsize=9)
    """
    if cfgPlot['Basemap.fill_continents']:
        m.fillcontinents()
    """

    pylab.grid(True)

    if fileName is not None:
        pylab.savefig(fileName)
Exemple #25
0
    def minimumDistance(self, points):
        """
        Calculate the minimum distance between a track and a
        collection of :class:`shapely.geometry.Point` points. Assumes
        the points and the :attr:`Longitude` and :attr:`Latitude`
        attributes share the same coordinate system (presumed to be
        geographic coordinates).

        :param points: sequence of :class:`shapely.geometry.Point` objects.

        :returns: :class:`numpy.ndarray` of minimum distances between
                  the set of points and the line features (in km).
        """
        coords = [(x, y) for x, y in zip(self.Longitude, self.Latitude)]

        if len(coords) == 1:
            point_feature = Point(self.Longitude, self.Latitude)
            distances = [point_feature.distance(point) for point in points]
        else:
            line_feature = LineString(coords)
            distances = [line_feature.distance(point) for point in points]

        return convert(distances, 'deg', 'km')
Exemple #26
0
from Utilities.metutils import convert

from timeseries import TimeSeriesFigure, saveFigure

DATEFORMAT = "%Y-%m-%d %H:%M"
INPUT_COLS = ('Time', 'Longitude', 'Latitude',
              'Speed', 'UU', 'VV', 'Bearing',
              'Pressure')

INPUT_FMTS = ('object', 'f', 'f', 'f', 'f', 'f', 'f', 'f')
INPUT_TITLES = ("Time", "Longitude", "Latitude", "Wind speed", "Eastward wind", 
                "Northward wind", "Wind direction", "Sea level pressure")
INPUT_UNIT = ('%Y-%m-%d %H:%M', 'degrees', 'degrees', 'm/s', 'm/s', 'm/s','degrees', 'Pa')
INPUT_CNVT = {
    0: lambda s: datetime.strptime(s.strip(), INPUT_UNIT[0]),
    7: lambda s: convert(float(s.strip() or 0), INPUT_UNIT[7], 'hPa')
}

def loadTimeseriesData(datafile):
    try:
        return np.loadtxt(datafile,
                          comments = "#",
                          delimiter = ',',
                          dtype = {
                            'names': INPUT_COLS,
                            'formats': INPUT_FMTS},
                            converters = INPUT_CNVT)
    except ValueError:
        return np.empty(0, dtype={
                        'names': INPUT_COLS,
                        'formats': INPUT_FMTS})
Exemple #27
0
    "Latitude",
    "Speed",
    "Bearing",
    "CentralPressure",
    "EnvPressure",
    "rMax",
)

TRACKFILE_UNIT = ("", "%Y-%m-%d %H:%M:%S", "hr", "degree", "degree", "kph", "degrees", "hPa", "hPa", "km")

TRACKFILE_FMTS = ("i", datetime, "f", "f", "f", "f", "f", "f", "f", "f")

TRACKFILE_CNVT = {
    0: lambda s: int(float(s.strip() or 0)),
    1: lambda s: datetime.strptime(s.strip(), TRACKFILE_UNIT[1]),
    5: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[5], "mps"),
    6: lambda s: bearing2theta(float(s.strip() or 0) * np.pi / 180.0),
    7: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[7], "Pa"),
    8: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[8], "Pa"),
}


def readTrackData(trackfile):
    """
    Read a track .csv file into a numpy.ndarray.

    The track format and converters are specified with the global variables

        TRACKFILE_COLS -- The column names
        TRACKFILE_FMTS -- The entry formats
        TRACKFILE_CNVT -- The column converters
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())

TRACKFILE_COLS = ('CycloneNumber', 'Datetime', 'TimeElapsed', 'Longitude',
                  'Latitude', 'Speed', 'Bearing', 'CentralPressure',
                  'EnvPressure', 'rMax')

TRACKFILE_UNIT = ('', '%Y-%m-%d %H:%M:%S', 'hr', 'degree', 'degree', 'kph', 'degrees',
                  'hPa', 'hPa', 'km')

TRACKFILE_FMTS = ('i', datetime, 'f', 'f', 'f', 'f', 'f', 'f', 'f', 'f')

TRACKFILE_CNVT = {
    0: lambda s: int(float(s.strip() or 0)),
    1: lambda s: datetime.strptime(s.strip(), TRACKFILE_UNIT[1]),
    5: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[5], 'mps'),
    6: lambda s: bearing2theta(float(s.strip() or 0) * np.pi / 180.),
    7: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[7], 'hPa'),
    8: lambda s: convert(float(s.strip() or 0), TRACKFILE_UNIT[8], 'hPa'),
}

def readTrackData(trackfile):
    """
    Read a track .csv file into a numpy.ndarray.

    The track format and converters are specified with the global variables

        TRACKFILE_COLS -- The column names
        TRACKFILE_FMTS -- The entry formats
        TRACKFILE_CNVT -- The column converters
Exemple #29
0
 def maximum(self):
     cP = metutils.convert(self.cP, "Pa", "hPa")
     return 3.04 * pow(1010.0 - cP, 0.644)
Exemple #30
0
 def test_m2km(self):
     """Convert distance in m to distance in km"""
     self.assertEqual(metutils.convert(0, "m", "km"), 0)
     self.assertAlmostEqual(metutils.convert(1000., "m", "km"), 1.)
     self.assertAlmostEqual(metutils.convert(10000., "m", "km"), 10.)
Exemple #31
0
    def plotHazardCurves(self, inputFile, plotPath):
        """
        Plot the hazard values stored in hazardFile, at the stns
        stored in stnFile.
        """

        log.info(("Plotting return period curves for locations within the "
                  "model domain"))
        # Open data file
        try:
            ncobj = nctools.ncLoadFile(inputFile)
            lon = nctools.ncGetDims(ncobj, 'lon')
            lat = nctools.ncGetDims(ncobj, 'lat')
            years = nctools.ncGetDims(ncobj, 'ari')
        except (IOError, RuntimeError, KeyError):
            log.critical("Cannot load input file: %s"%inputFile)
            raise

        placeNames, placeID, placeLats, placeLons, locations = self.getLocations()

        for name, plat, plon, pID in zip(placeNames, placeLats, placeLons, placeID):
            pID = int(pID)

            log.debug("Plotting return period curve for %s"%name)
            i = find_index(lon, plon)
            j = find_index(lat, plat)

            xlabel = 'Average recurrence interval (years)'
            ylabel = 'Wind speed (%s)'%self.plotUnits.label
            title = "Return period wind speeds at " + name + ", \n(%5.1f,%5.1f)"%(plon, plat)

            name.replace(' ', '')
            log.debug("Working on {0}".format(name))
            filename = pjoin(plotPath, 'ARI_curve_%s.%s'%(pID, "png"))
            log.debug("Saving hazard curve for %s to %s"%(name, filename))
            wspd = ncobj.variables['wspd'][:, j, i]

            recs = database.queries.locationRecords(self.db, pID)
            data = np.zeros(int(self.numsimulations * 365.25))
            if len(recs) > 0:
                data[-len(recs):] = recs['wspd']

            allevents = np.sort(data)
            log.debug("allevents length = {0}".format(len(allevents)))

            placeWspd = metutils.convert(wspd, 'mps',
                                         self.plotUnits.units)
            if np.all(placeWspd.mask):
                log.debug("All values for {0} are null".format(name))
                continue

            if self.ciBounds:
                wspdLower = ncobj.variables['wspdlower'][:, j, i]
                wspdUpper = ncobj.variables['wspdupper'][:, j, i]
                placeWspdLower = metutils.convert(wspdLower, 'mps',
                                                  self.plotUnits.units)
                placeWspdUpper = metutils.convert(wspdUpper, 'mps',
                                                  self.plotUnits.units)
            else:
                placeWspdUpper = np.zeros(len(placeWspd))
                placeWspdLower = np.zeros(len(placeWspd))

            saveHazardCurve(years, allevents, placeWspd, placeWspdUpper, placeWspdLower,
                            xlabel, ylabel, title, filename, self.fit)

        ncobj.close()
Exemple #32
0
 def maximum(self):
     cP = metutils.convert(self.cP, 'Pa', 'hPa')
     return 3.04 * pow(1010.0 - cP, 0.644)
Exemple #33
0
 def test_km2deg(self):
     """Convert distance in km to distance in degrees"""
     self.assertEqual(metutils.convert(0, "km", "deg"), 0)
     self.assertAlmostEqual(metutils.convert(1, "km", "deg"), 360/(2*pi*6367), 3)
     self.assertAlmostEqual(metutils.convert(2, "km", "deg"), 720/(2*pi*6367), 3)
     self.assertAlmostEqual(metutils.convert(10, "km", "deg"), 3600/(2*pi*6367), 3)
 def test_celcius2F(self):
     """Convert temperatures in Celcius to Farenheit"""
     self.assertEqual(metutils.convert(0, "C", "F"), 32.0)
     self.assertAlmostEqual(metutils.convert(37.78, "C", "F"), 100, 2)
     self.assertAlmostEqual(metutils.convert(-40, "C", "F"), -40, 2)
Exemple #35
0
from timeseries import TimeSeriesFigure, saveFigure

DATEFORMAT = "%Y-%m-%d %H:%M"
INPUT_COLS = ('Station', 'Time', 'Longitude', 'Latitude',
              'Speed', 'UU', 'VV', 'Bearing',
              'Pressure')

INPUT_FMTS = ('|S16', 'object', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8')
INPUT_TITLES = ("Station", "Time", "Longitude", "Latitude", "Wind speed",
                "Eastward wind", "Northward wind", "Wind direction",
                "Sea level pressure")
INPUT_UNIT = ('', '%Y-%m-%d %H:%M', 'degrees', 'degrees', 'm/s',
                'm/s', 'm/s','degrees', 'Pa')
INPUT_CNVT = {
    1: lambda s: datetime.strptime(s.strip(), INPUT_UNIT[1]),
    8: lambda s: convert(float(s.strip() or 0), INPUT_UNIT[8], 'hPa')
    }

def loadTimeseriesData(datafile):
    logging.debug("Loading timeseries data from {0}".format(datafile))
    try:
        return np.genfromtxt(datafile, dtype=INPUT_FMTS, names=INPUT_COLS,
                             comments='#', delimiter=',', skip_header=1,
                             converters=INPUT_CNVT)
    except ValueError:
        logging.warn("Timeseries data file is empty - returning empty array")
        return np.empty(0, dtype={
                        'names': INPUT_COLS,
                        'formats': INPUT_FMTS})

def plotTimeseries(inputPath, outputPath, locID=None):
Exemple #36
0
 def maximum(self):
     cP = metutils.convert(self.cP, 'Pa', 'hPa')
     return 3.04 * pow(1010.0 - cP, 0.644)
 def test_farenheit2C(self):
     """Convert temperatures in Farenheit to Celcius"""
     self.assertEqual(metutils.convert(32, "F", "C"), 0.0)
     self.assertAlmostEqual(metutils.convert(100, "F", "C"), 37.78, 2)
     self.assertAlmostEqual(metutils.convert(-40, "F", "C"), -40, 2)
Exemple #38
0
    def regionalExtremes(self, gridLimit, timeStepCallback=None):
        """
        Calculate the maximum potential wind gust and minimum
        pressure over the region throughout the life of the
        tropical cyclone.


        :type  gridLimit: :class:`dict`
        :param gridLimit: the domain where the tracks will be considered.
                          The :class:`dict` should contain the keys
                          :attr:`xMin`, :attr:`xMax`, :attr:`yMin` and
                          :attr:`yMax`. The *y* variable bounds the
                          latitude and the *x* variable bounds the longitude.

        :type  timeStepCallback: function
        :param timeStepCallback: the function to be called on each time step.
        """
        if len(self.track.data) > 0:
            envPressure = convert(self.track.EnvPressure[0], 'hPa', 'Pa')
        else:
            envPressure = np.NaN

        # Get the limits of the region
        xMin = gridLimit['xMin']
        xMax = gridLimit['xMax']
        yMin = gridLimit['yMin']
        yMax = gridLimit['yMax']

        # Setup a 'millidegree' integer grid for the region
        gridMargin = int(100. * self.margin)
        gridStep = int(100. * self.resolution)

        minLat = int(100. * yMin) - gridMargin
        maxLat = int(100. * yMax) + gridMargin
        minLon = int(100. * xMin) - gridMargin
        maxLon = int(100. * xMax) + gridMargin

        latGrid = np.arange(minLat, maxLat + gridStep, gridStep, dtype=int)
        lonGrid = np.arange(minLon, maxLon + gridStep, gridStep, dtype=int)

        [cGridX, cGridY] = np.meshgrid(lonGrid, latGrid)

        # Initialise the region
        UU = np.zeros_like(cGridX, dtype='f')
        VV = np.zeros_like(cGridY, dtype='f')
        bearing = np.zeros_like(cGridX, dtype='f')
        gust = np.zeros_like(cGridX, dtype='f')
        pressure = np.ones_like(cGridX, dtype='f') * envPressure

        lonCDegree = np.array(100. * self.track.Longitude, dtype=int)
        latCDegree = np.array(100. * self.track.Latitude, dtype=int)

        # We only consider the times when the TC track falls in the region
        timesInRegion = np.where((xMin <= self.track.Longitude)
                                 & (self.track.Longitude <= xMax)
                                 & (yMin <= self.track.Latitude)
                                 & (self.track.Latitude <= yMax))[0]

        nsteps = len(self.track.TimeElapsed)

        for i in tqdm.tqdm(timesInRegion, disable=None):
            log.debug(("Calculating wind field at timestep "
                       "{0} of {1}".format(i, nsteps)))
            # Map the local grid to the regional grid
            # Set up max/min over the whole domain
            jmin, jmax = 0, int(
                (maxLat - minLat + 2. * gridMargin) / gridStep) + 1
            imin, imax = 0, int(
                (maxLon - minLon + 2. * gridMargin) / gridStep) + 1

            # If domain is set in gridLimit in config, use only those
            # limits instead
            if self.domain == 'bounded':

                jmin = int((latCDegree[i] - minLat - gridMargin) / gridStep)
                jmax = int(
                    (latCDegree[i] - minLat + gridMargin) / gridStep) + 1
                imin = int((lonCDegree[i] - minLon - gridMargin) / gridStep)
                imax = int(
                    (lonCDegree[i] - minLon + gridMargin) / gridStep) + 1

            # Calculate the local wind speeds and pressure at time i
            Ux, Vy, P = self.localWindField(i)

            # Calculate the local wind gust and bearing
            Ux *= self.gustFactor
            Vy *= self.gustFactor

            localGust = np.sqrt(Ux**2 + Vy**2)
            localBearing = ((np.arctan2(-Ux, -Vy)) * 180. / np.pi)

            # Handover this time step to a callback if required
            if timeStepCallback is not None:
                timeStepCallback(self.track.Datetime[i], localGust, Ux, Vy, P,
                                 lonGrid[imin:imax] / 100.,
                                 latGrid[jmin:jmax] / 100.)

            # Retain when there is a new maximum gust
            mask = localGust > gust[jmin:jmax, imin:imax]

            gust[jmin:jmax, imin:imax] = np.where(mask, localGust,
                                                  gust[jmin:jmax, imin:imax])
            bearing[jmin:jmax,
                    imin:imax] = np.where(mask, localBearing,
                                          bearing[jmin:jmax, imin:imax])
            UU[jmin:jmax, imin:imax] = np.where(mask, Ux, UU[jmin:jmax,
                                                             imin:imax])
            VV[jmin:jmax, imin:imax] = np.where(mask, Vy, VV[jmin:jmax,
                                                             imin:imax])

            # Retain the lowest pressure
            pressure[jmin:jmax,
                     imin:imax] = np.where(P < pressure[jmin:jmax, imin:imax],
                                           P, pressure[jmin:jmax, imin:imax])

        return gust, bearing, UU, VV, pressure, lonGrid / 100., latGrid / 100.
Exemple #39
0
 def test_farenheit2C(self):
     """Convert temperatures in Farenheit to Celcius"""
     self.assertEqual(metutils.convert(32, "F", "C"), 0.0)
     self.assertAlmostEqual(metutils.convert(100, "F", "C"), 37.78, 2)
     self.assertAlmostEqual(metutils.convert(-40, "F", "C"), -40, 2) 
Exemple #40
0
# Define format for TCRM output track files:
ISO_FORMAT = "%Y-%m-%d %H:%M:%S"
TCRM_COLS = ('CycloneNumber', 'Datetime', 'TimeElapsed', 'Longitude',
             'Latitude', 'Speed', 'Bearing', 'CentralPressure', 'EnvPressure',
             'rMax')

TCRM_UNIT = ('', '', 'hr', 'degree', 'degree', 'kph', 'degrees', 'hPa', 'hPa',
             'km')

TCRM_FMTS = ('i', 'object', 'f', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8', 'f8')

TCRM_CNVT = {
    0: lambda s: int(float(s.strip() or 0)),
    1: lambda s: datetime.strptime(s.strip(), ISO_FORMAT),
    5: lambda s: convert(float(s.strip() or 0), TCRM_UNIT[5], 'mps'),
    6: lambda s: bearing2theta(float(s.strip() or 0) * np.pi / 180.),
    7: lambda s: convert(float(s.strip() or 0), TCRM_UNIT[7], 'Pa'),
    8: lambda s: convert(float(s.strip() or 0), TCRM_UNIT[8], 'Pa'),
}

TRACK_DT_ERR = "Track data does not have required \
attributes to convert to datetime object"

TRACK_EMPTY_GROUP = """No track groups in this netcdf file: {0}"""


def ncReadTrackData(trackfile):
    """
    Read a netcdf-format track file into a collection of
    :class:`Track` objects. The returned :class:`Track` objects *must*
Exemple #41
0
 def test_m2nm(self):
     self.assertEqual(metutils.convert(0, "m", "nm"), 0)
     self.assertAlmostEqual(metutils.convert(1000., "m", "nm"), 0.539957)
Exemple #42
0
 def test_celcius2F(self):
     """Convert temperatures in Celcius to Farenheit"""
     self.assertEqual(metutils.convert(0, "C", "F"), 32.0)
     self.assertAlmostEqual(metutils.convert(37.78, "C", "F"), 100, 2)
     self.assertAlmostEqual(metutils.convert(-40, "C", "F"), -40, 2)
Exemple #43
0
 def test_deg2km(self):
     """Convert distance in degrees to distance in km"""
     self.assertEqual(metutils.convert(0, "deg", "km"), 0)
     self.assertAlmostEqual(metutils.convert(1, "deg", "km"), (1/(360/(2*pi*6367))), 3)
     self.assertAlmostEqual(metutils.convert(2, "deg", "km"), (2/(360/(2*pi*6367))), 3)
     self.assertAlmostEqual(metutils.convert(10, "deg", "km"), (10/(360/(2*pi*6367))), 3)
    def plotHazardCurves(self, inputFile, plotPath):
        """
        Plot the hazard values stored in hazardFile, at the stns
        stored in stnFile.
        """

        log.info(("Plotting return period curves for locations within the "
                  "model domain"))
        # Open data file
        try:
            ncobj = nctools.ncLoadFile(inputFile)
            lon = nctools.ncGetDims(ncobj, 'lon')
            lat = nctools.ncGetDims(ncobj, 'lat')
            years = nctools.ncGetDims(ncobj, 'years')
        except (IOError, RuntimeError, KeyError):
            log.critical("Cannot load input file: %s"%inputFile)
            raise

        # Load data
        #wspd = nctools.ncGetData(ncobj, 'wspd')
        #try:
        #    wLower = nctools.ncGetData(ncobj, 'wspdlower')
        #    wUpper = nctools.ncGetData(ncobj, 'wspdupper')
        ciBounds = True
        #except KeyError:
        #    ciBounds = False
        #ncobj.close()

        minLon = min(lon)
        maxLon = max(lon)
        minLat = min(lat)
        maxLat = max(lat)

        # Use the same maximum value for all localities to simplify
        # intercomparisons:
        #defaultMax = np.ceil(metutils.convert(100.0, 'mps',
        #                                      self.plotUnits.units)/10.0)*10.0

        placeNames, parentCountries, placeLats, placeLons = \
            self.getLocations(minLon, maxLon, minLat, maxLat)

        for name, plat, plon, country in zip(placeNames, placeLats,
                                             placeLons, parentCountries):

            log.debug("Plotting return period curve for %s"%name)
            i = find_index(lon, plon)
            j = find_index(lat, plat)

            xlabel = 'Average recurrence interval (years)'
            ylabel = 'Wind speed (%s)'%self.plotUnits.label
            title = "Return period wind speeds at " + name + ", " \
                            + country + "\n(%5.1f,%5.1f)"%(plon, plat)

            name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
            name.replace(' ', '')
            filename = pjoin(plotPath, 'ARI_curve_%s.%s'%(name, "png"))
            log.debug("Saving hazard curve for %s to %s"%(name, filename))
            wspd = ncobj.variables['wspd'][:, j, i]
            

            placeWspd = metutils.convert(wspd, 'mps',
                                         self.plotUnits.units)
            if np.all(placeWspd.mask):
                log.debug("All values for {0} are null".format(name))
                continue

            if ciBounds:
                wspdLower = ncobj.variables['wspdlower'][:, j, i]
                wspdUpper = ncobj.variables['wspdupper'][:, j, i]
                placeWspdLower = metutils.convert(wspdLower, 'mps',
                                                  self.plotUnits.units)
                placeWspdUpper = metutils.convert(wspdUpper, 'mps',
                                                  self.plotUnits.units)

            saveHazardCurve(years, placeWspd, placeWspdUpper, placeWspdLower,
                            xlabel, ylabel, title, filename)

        ncobj.close()
Exemple #45
0
 def test_km2m(self):
     """Convert distance in km to distance in m"""
     self.assertEqual(metutils.convert(0, "km", "m"), 0)
     self.assertAlmostEqual(metutils.convert(1, "km", "m"), 1000)
Exemple #46
0
    def plotHazardCurves(self, inputFile, plotPath):
        """
        Plot the hazard values stored in hazardFile, at the stns
        stored in stnFile.
        """

        log.info(("Plotting return period curves for locations within the "
                  "model domain"))
        # Open data file
        try:
            ncobj = nctools.ncLoadFile(inputFile)
            lon = nctools.ncGetDims(ncobj, 'lon')
            lat = nctools.ncGetDims(ncobj, 'lat')
            years = nctools.ncGetDims(ncobj, 'years')
        except (IOError, RuntimeError, KeyError):
            log.critical("Cannot load input file: %s"%inputFile)
            raise

        # Load data
        wspd = nctools.ncGetData(ncobj, 'wspd')
        try:
            wLower  = nctools.ncGetData(ncobj, 'wspdlower')
            wUpper = nctools.ncGetData(ncobj, 'wspdupper')
            ciBounds = True
        except KeyError:
            ciBounds = False
        ncobj.close()

        minLon = min(lon)
        maxLon = max(lon)
        minLat = min(lat)
        maxLat = max(lat)

        # Use the same maximum value for all localities to simplify
        # intercomparisons:
        defaultMax = np.ceil(metutils.convert(100.0, 'mps',
                                              self.plotUnits.units)/10.0)*10.0
        
        placeNames, parentCountries, placeLats, placeLons = \
            self.getLocations(minLon, maxLon, minLat, maxLat)
        
        for name, plat, plon, country in zip(placeNames, placeLats,
                                             placeLons, parentCountries):

            log.debug("Plotting return period curve for %s"%name)
            i = find_index(lon, plon)
            j = find_index(lat, plat)

            xlabel = 'Average recurrence interval (years)'
            ylabel = 'Wind speed (%s)'%self.plotUnits.label
            title = "Return period wind speeds at " + name + ", " \
                            + country + "\n(%5.1f,%5.1f)"%(plon, plat)

            name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
            name.replace(' ', '')
            filename = pjoin(plotPath, 'ARI_curve_%s.%s'%(name,"png"))
            log.debug("Saving hazard curve for %s to %s"%(name, filename))
            placeWspd = metutils.convert(wspd[:, j, i], 'mps',
                                         self.plotUnits.units)
            maxWspd = placeWspd.max()
            if ciBounds:
                placeWspdLower = metutils.convert(wLower[:,j,i], 'mps',
                                                  self.plotUnits.units)
                placeWspdUpper  = metutils.convert(wUpper[:,j,i], 'mps',
                                                   self.plotUnits.units)
                
            saveHazardCurve(years, placeWspd, placeWspdUpper, placeWspdLower,
                            xlabel, ylabel, title, filename)
Exemple #47
0
    def processData(self, restrictToWindfieldDomain=False):
        """
        Process raw data into ASCII files that can be read by the main
        components of the system

        :param bool restrictToWindfieldDomain: if True, only process data
            within the wind field domain, otherwise, process data from
            across the track generation domain.

        """
        config = ConfigParser()
        config.read(self.configFile)

        self.logger.info("Running {0}".format(flModuleName()))

        if config.has_option('DataProcess', 'InputFile'):
            inputFile = config.get('DataProcess', 'InputFile')

        if config.has_option('DataProcess', 'Source'):
            source = config.get('DataProcess', 'Source')
            self.logger.info('Loading %s dataset', source)
            fn = config.get(source, 'filename')
            path = config.get(source, 'path')
            inputFile = pjoin(path, fn)

        # If input file has no path information, default to tcrm input folder
        if len(os.path.dirname(inputFile)) == 0:
            inputFile = pjoin(self.tcrm_input_dir, inputFile)

        self.logger.info("Processing {0}".format(inputFile))

        self.source = config.get('DataProcess', 'Source')

        inputData = colReadCSV(self.configFile, inputFile, self.source)

        inputSpeedUnits = config.get(self.source, 'SpeedUnits')
        inputPressureUnits = config.get(self.source, 'PressureUnits')
        inputLengthUnits = config.get(self.source, 'LengthUnits')
        startSeason = config.getint('DataProcess', 'StartSeason')

        indicator = loadData.getInitialPositions(inputData)
        lat = np.array(inputData['lat'], 'd')
        lon = np.mod(np.array(inputData['lon'], 'd'), 360)

        if restrictToWindfieldDomain:
            # Filter the input arrays to only retain the tracks that
            # pass through the windfield domain.
            CD = CalcTrackDomain(self.configFile)
            self.domain = CD.calcDomainFromTracks(indicator, lon, lat)
            domainIndex = self.extractTracks(indicator, lon, lat)
            inputData = inputData[domainIndex]
            indicator = indicator[domainIndex]
            lon = lon[domainIndex]
            lat = lat[domainIndex]

        if self.progressbar is not None:
            self.progressbar.update(0.125)

        # Sort date/time information
        try:
            dt = np.empty(indicator.size, 'f')
            dt[1:] = np.diff(inputData['age'])
        except (ValueError, KeyError):

            try:
                self.logger.info(("Filtering input data by season:"
                                  "season > {0}".format(startSeason)))
                # Find indicies that satisfy minimum season filter
                idx = np.where(inputData['season'] >= startSeason)[0]
                # Filter records:
                inputData = inputData[idx]
                indicator = indicator[idx]
                lon = lon[idx]
                lat = lat[idx]
            except (ValueError, KeyError):
                pass

            year, month, day, hour, minute, datetimes \
                = loadData.parseDates(inputData, indicator)

            # Time between observations:
            dt = loadData.getTimeDelta(year, month, day, hour, minute)

            # Calculate julian days:
            jdays = loadData.julianDays(year, month, day, hour, minute)

        delta_lon = np.diff(lon)
        delta_lat = np.diff(lat)

        # Split into separate tracks if large jump occurs (delta_lon >
        # 15 degrees or delta_lat > 5 degrees) This avoids two tracks
        # being accidentally combined when seasons and track numbers
        # match but basins are different as occurs in the IBTrACS
        # dataset.  This problem can also be prevented if the
        # 'tcserialno' column is specified.
        indicator[np.where(delta_lon > 15)[0] + 1] = 1
        indicator[np.where(delta_lat > 5)[0] + 1] = 1

        # Save information required for frequency auto-calculation
        try:
            origin_seasonOrYear = np.array(inputData['season'],
                                           'i').compress(indicator)
            header = 'Season'
        except (ValueError, KeyError):
            origin_seasonOrYear = year.compress(indicator)
            header = 'Year'

        flSaveFile(self.origin_year,
                   np.transpose(origin_seasonOrYear),
                   header,
                   ',',
                   fmt='%d')

        pressure = np.array(inputData['pressure'], 'd')
        novalue_index = np.where(pressure == sys.maxint)
        pressure = metutils.convert(pressure, inputPressureUnits, "hPa")
        pressure[novalue_index] = sys.maxint

        # Convert any non-physical central pressure values to maximum integer
        # This is required because IBTrACS has a mix of missing value codes
        # (i.e. -999, 0, 9999) in the same global dataset.
        pressure = np.where((pressure < 600) | (pressure > 1100), sys.maxint,
                            pressure)

        if self.progressbar is not None:
            self.progressbar.update(0.25)

        try:
            vmax = np.array(inputData['vmax'], 'd')
        except (ValueError, KeyError):
            self.logger.warning("No max wind speed data")
            vmax = np.empty(indicator.size, 'f')
        else:
            novalue_index = np.where(vmax == sys.maxint)
            vmax = metutils.convert(vmax, inputSpeedUnits, "mps")
            vmax[novalue_index] = sys.maxint

        assert lat.size == indicator.size
        assert lon.size == indicator.size
        assert pressure.size == indicator.size
        #assert vmax.size == indicator.size

        try:
            rmax = np.array(inputData['rmax'])
            novalue_index = np.where(rmax == sys.maxint)
            rmax = metutils.convert(rmax, inputLengthUnits, "km")
            rmax[novalue_index] = sys.maxint

            self._rmax(rmax, indicator)
            self._rmaxRate(rmax, dt, indicator)
        except (ValueError, KeyError):
            self.logger.warning("No rmax data available")

        if self.ncflag:
            self.data['index'] = indicator

        # ieast : parameter used in latLon2Azi
        # FIXME: should be a config setting describing the input data.
        ieast = 1

        # Determine the index of initial cyclone observations, excluding
        # those cyclones that have only one observation. This is used
        # for calculating initial bearing and speed
        indicator2 = np.where(indicator > 0, 1, 0)
        initIndex = np.concatenate(
            [np.where(np.diff(indicator2) == -1, 1, 0), [0]])

        # Calculate the bearing and distance (km) of every two
        # consecutive records using ll2azi
        bear_, dist_ = maputils.latLon2Azi(lat, lon, ieast, azimuth=0)
        assert bear_.size == indicator.size - 1
        assert dist_.size == indicator.size - 1
        bear = np.empty(indicator.size, 'f')
        bear[1:] = bear_
        dist = np.empty(indicator.size, 'f')
        dist[1:] = dist_

        self._lonLat(lon, lat, indicator, initIndex)
        self._bearing(bear, indicator, initIndex)
        self._bearingRate(bear, dt, indicator)
        if self.progressbar is not None:
            self.progressbar.update(0.375)
        self._speed(dist, dt, indicator, initIndex)
        self._speedRate(dist, dt, indicator)
        self._pressure(pressure, indicator)
        self._pressureRate(pressure, dt, indicator)
        self._windSpeed(vmax)

        try:
            self._frequency(year, indicator)
            self._juliandays(jdays, indicator, year)
        except (ValueError, KeyError):
            pass

        self.logger.info("Completed {0}".format(flModuleName()))
        if self.progressbar is not None:
            self.progressbar.update(0.5)
Exemple #48
0
    def processData(self, restrictToWindfieldDomain=False):
        """
        Process raw data into ASCII files that can be read by the main
        components of the system

        :param bool restrictToWindfieldDomain: if True, only process data
            within the wind field domain, otherwise, process data from
            across the track generation domain.
            
        """
        config = ConfigParser()
        config.read(self.configFile)

        self.logger.info("Running %s" % flModuleName())

        if config.has_option('DataProcess', 'InputFile'):
            inputFile = config.get('DataProcess', 'InputFile')

        if config.has_option('DataProcess', 'Source'):
            source = config.get('DataProcess', 'Source')
            self.logger.info('Loading %s dataset', source)
            fn = config.get(source, 'filename')
            path = config.get(source, 'path')
            inputFile = pjoin(path, fn)

        # If input file has no path information, default to tcrm input folder
        if len(os.path.dirname(inputFile)) == 0:
            inputFile = pjoin(self.tcrm_input_dir, inputFile)

        self.logger.info("Processing %s" % inputFile)

        self.source = config.get('DataProcess', 'Source')

        inputData = colReadCSV(self.configFile, inputFile, self.source)

        inputSpeedUnits = config.get(self.source, 'SpeedUnits')
        inputPressureUnits = config.get(self.source, 'PressureUnits')
        inputLengthUnits = config.get(self.source, 'LengthUnits')
        startSeason = config.getint('DataProcess', 'StartSeason')

        indicator = loadData.getInitialPositions(inputData)
        lat = np.array(inputData['lat'], 'd')
        lon = np.mod(np.array(inputData['lon'], 'd'), 360)

        if restrictToWindfieldDomain:
            # Filter the input arrays to only retain the tracks that
            # pass through the windfield domain.
            CD = CalcTrackDomain(self.configFile)
            self.domain = CD.calcDomainFromTracks(indicator, lon, lat)
            domainIndex = self.extractTracks(indicator, lon, lat)
            inputData = inputData[domainIndex]
            indicator = indicator[domainIndex]
            lon = lon[domainIndex]
            lat = lat[domainIndex]

        if self.progressbar is not None:
            self.progressbar.update(0.125)

        # Sort date/time information
        try:
            dt = np.empty(indicator.size, 'f')
            dt[1:] = np.diff(inputData['age'])
        except (ValueError, KeyError):

            try:
                self.logger.info("Filtering input data by season: season > %d"%startSeason)
                # Find indicies that satisfy minimum season filter
                idx = np.where(inputData['season'] >= startSeason)[0]
                # Filter records:
                inputData = inputData[idx]
                indicator = indicator[idx]
                lon = lon[idx]
                lat = lat[idx]
            except (ValueError, KeyError):
                pass

            year, month, day, hour, minute, datetimes \
                = loadData.parseDates(inputData, indicator)

            # Time between observations:
            dt = loadData.getTimeDelta(year, month, day, hour, minute)

            # Calculate julian days:
            jdays = loadData.julianDays(year, month, day, hour, minute)

        delta_lon = np.diff(lon)
        delta_lat = np.diff(lat)

        # Split into separate tracks if large jump occurs (delta_lon >
        # 15 degrees or delta_lat > 5 degrees) This avoids two tracks
        # being accidentally combined when seasons and track numbers
        # match but basins are different as occurs in the IBTrACS
        # dataset.  This problem can also be prevented if the
        # 'tcserialno' column is specified.
        indicator[np.where(delta_lon > 15)[0] + 1] = 1
        indicator[np.where(delta_lat > 5)[0] + 1] = 1

        # Save information required for frequency auto-calculation
        try:
            origin_seasonOrYear = np.array(
                inputData['season'], 'i').compress(indicator)
            header = 'Season'
        except (ValueError, KeyError):
            origin_seasonOrYear = year.compress(indicator)
            header = 'Year'

        flSaveFile(self.origin_year, np.transpose(origin_seasonOrYear),
                   header, ',', fmt='%d')

        pressure = np.array(inputData['pressure'], 'd')
        novalue_index = np.where(pressure == sys.maxint)
        pressure = metutils.convert(pressure, inputPressureUnits, "hPa")
        pressure[novalue_index] = sys.maxint

        # Convert any non-physical central pressure values to maximum integer
        # This is required because IBTrACS has a mix of missing value codes
        # (i.e. -999, 0, 9999) in the same global dataset.
        pressure = np.where((pressure < 600) | (pressure > 1100),
                            sys.maxint, pressure)

        if self.progressbar is not None:
            self.progressbar.update(0.25)

        try:
            vmax = np.array(inputData['vmax'], 'd')
        except (ValueError, KeyError):
            self.logger.warning("No max wind speed data")
            vmax = np.empty(indicator.size, 'f')
        else:
            novalue_index = np.where(vmax == sys.maxint)
            vmax = metutils.convert(vmax, inputSpeedUnits, "mps")
            vmax[novalue_index] = sys.maxint

        assert lat.size == indicator.size
        assert lon.size == indicator.size
        assert pressure.size == indicator.size
        #assert vmax.size == indicator.size

        try:
            rmax = np.array(inputData['rmax'])
            novalue_index = np.where(rmax == sys.maxint)
            rmax = metutils.convert(rmax, inputLengthUnits, "km")
            rmax[novalue_index] = sys.maxint

            self._rmax(rmax, indicator)
            self._rmaxRate(rmax, dt, indicator)
        except (ValueError, KeyError):
            self.logger.warning("No rmax data available")

        if self.ncflag:
            self.data['index'] = indicator

        # ieast : parameter used in latLon2Azi
        # FIXME: should be a config setting describing the input data.
        ieast = 1

        # Determine the index of initial cyclone observations, excluding
        # those cyclones that have only one observation. This is used
        # for calculating initial bearing and speed
        indicator2 = np.where(indicator > 0, 1, 0)
        initIndex = np.concatenate([np.where(np.diff(indicator2) ==
                                             -1, 1, 0), [0]])

        # Calculate the bearing and distance (km) of every two
        # consecutive records using ll2azi
        bear_, dist_ = maputils.latLon2Azi(lat, lon, ieast, azimuth=0)
        assert bear_.size == indicator.size - 1
        assert dist_.size == indicator.size - 1
        bear = np.empty(indicator.size, 'f')
        bear[1:] = bear_
        dist = np.empty(indicator.size, 'f')
        dist[1:] = dist_

        self._lonLat(lon, lat, indicator, initIndex)
        self._bearing(bear, indicator, initIndex)
        self._bearingRate(bear, dt, indicator)
        if self.progressbar is not None:
            self.progressbar.update(0.375)
        self._speed(dist, dt, indicator, initIndex)
        self._speedRate(dist, dt, indicator)
        self._pressure(pressure, indicator)
        self._pressureRate(pressure, dt, indicator)
        self._windSpeed(vmax)

        try:
            self._frequency(year, indicator)
            self._juliandays(jdays, indicator, year)
        except (ValueError, KeyError):
            pass

        self.logger.info("Completed %s" % flModuleName())
        if self.progressbar is not None:
            self.progressbar.update(0.5)