Example #1
0
def ecwmf_surface_pressure(input_path, lonlat, time):
    """
    Retrieve a pixel value from the ECWMF Surface Pressure
    collection.
    Scales the result by 100 before returning.
    """
    product = DatasetName.SURFACE_PRESSURE.value.lower()
    search = pjoin(input_path, DatasetName.ECMWF_PATH_FMT.value)
    files = glob.glob(search.format(product=product, year=time.year))
    data = None
    required_ymd = datetime.datetime(time.year, time.month, time.day)
    for f in files:
        url = urlparse(f, scheme='file').geturl()
        ymd = splitext(basename(f))[0].split('_')[1]
        ancillary_ymd = datetime.datetime.strptime(ymd, '%Y-%m-%d')
        if ancillary_ymd == required_ymd:
            data = get_pixel(f, lonlat) / 100.0

            metadata = {
                'data_source': 'ECWMF Surface Pressure',
                'url': url,
                'query_date': time
            }

            # ancillary metadata tracking
            md = extract_ancillary_metadata(f)
            for key in md:
                metadata[key] = md[key]

            return data, metadata

    if data is None:
        raise AncillaryError("No ECWMF Surface Pressure data")
Example #2
0
def get_elevation_data(lonlat, pathname):
    """
    Get elevation data for a scene.

    :param lon_lat:
        The latitude, longitude of the scene center.
    :type lon_lat:
        float (2-tuple)

    :pathname:
        The pathname of the DEM with a ':' to seperate the
        dataset name.
    :type dem_dir:
        str
    """
    fname, dname = pathname.split(":")

    try:
        data, md_uuid = get_pixel(fname, dname, lonlat)
        data = data * 0.001  # scale to correct units
    except ValueError:
        raise AncillaryError("No Elevation data")

    metadata = {
        "id": numpy.array([md_uuid], VLEN_STRING),
    }

    return data, metadata
Example #3
0
def ecwmf_water_vapour(input_path, lonlat, time):
    """
    Retrieve a pixel value from the ECWMF Total Column Water Vapour
    collection.
    """
    product = DatasetName.WATER_VAPOUR.value.lower()
    search = pjoin(input_path, DatasetName.ECMWF_PATH_FMT.value)
    files = glob.glob(search.format(product=product, year=time.year))
    data = None
    required_ymd = datetime.datetime(time.year, time.month, time.day)
    for f in files:
        url = urlparse(f, scheme='file').geturl()
        ymd = splitext(basename(f))[0].split('_')[1]
        ancillary_ymd = datetime.datetime.strptime(ymd, '%Y-%m-%d')
        if ancillary_ymd == required_ymd:
            data = get_pixel(f, lonlat)

            metadata = {
                'data_source': 'ECWMF Total Column Water Vapour',
                'url': url,
                'query_date': time
            }

            # ancillary metadata tracking
            md = extract_ancillary_metadata(f)
            for key in md:
                metadata[key] = md[key]

            return data, metadata

    if data is None:
        raise AncillaryError("No ECWMF Total Column Water Vapour data")
Example #4
0
def get_elevation_data(lonlat, dem_path):
    """
    Get elevation data for a scene.

    :param lon_lat:
        The latitude, longitude of the scene center.
    :type lon_lat:
        float (2-tuple)

    :dem_dir:
        The directory in which the DEM can be found.
    :type dem_dir:
        str
    """
    datafile = pjoin(dem_path, "DEM_one_deg.tif")
    url = urlparse(datafile, scheme='file').geturl()

    try:
        data = get_pixel(datafile, lonlat) * 0.001  # scale to correct units
    except IndexError:
        raise AncillaryError("No Elevation data")

    metadata = {'data_source': 'Elevation', 'url': url}

    # ancillary metadata tracking
    md = extract_ancillary_metadata(datafile)
    for key in md:
        metadata[key] = md[key]

    return data, metadata
Example #5
0
def get_water_vapour(acquisition, water_vapour_dict, scale_factor=0.1):
    """
    Retrieve the water vapour value for an `acquisition` and the
    path for the water vapour ancillary data.
    """
    dt = acquisition.acquisition_datetime
    geobox = acquisition.gridded_geo_box()

    year = dt.strftime('%Y')
    filename = "pr_wtr.eatm.{year}.tif".format(year=year)

    if 'user' in water_vapour_dict:
        metadata = {'data_source': 'User defined value'}
        return water_vapour_dict['user'], metadata
    else:
        water_vapour_path = water_vapour_dict['pathname']

    datafile = pjoin(water_vapour_path, filename)
    url = urlparse(datafile, scheme='file').geturl()

    # calculate the water vapour band number based on the datetime

    doy = dt.timetuple().tm_yday
    hour = dt.timetuple().tm_hour
    band = (int(doy) - 1) * 4 + int((hour + 3) / 6)

    # Check for boundary condition: 1 Jan, 0-3 hours
    if band == 0 and doy == 1:
        band = 1

    # Get the number of bands
    with rasterio.open(datafile) as src:
        n_bands = src.count

    # Enable NBAR Near Real Time (NRT) processing
    if band > (n_bands + 1):
        rasterdoy = (((n_bands) - (int((hour + 3) / 6))) / 4) + 1
        if (doy - rasterdoy) < 7:
            band = (int(rasterdoy) - 1) * 4 + int((hour + 3) / 6)

    try:
        data = get_pixel(datafile, geobox.centre_lonlat, band=band)
    except IndexError:
        raise AncillaryError("No Water Vapour data")

    data = data * scale_factor

    metadata = {'data_source': 'Water Vapour', 'url': url, 'query_date': dt}

    # ancillary metadata tracking
    md = extract_ancillary_metadata(datafile)
    for key in md:
        metadata[key] = md[key]

    return data, metadata
Example #6
0
def get_ozone_data(ozone_fname, lonlat, time):
    """
    Get ozone data for a scene. `lonlat` should be the (x,y) for the centre
    the scene.
    """
    dname = time.strftime("%b").lower()

    try:
        data, md_uuid = get_pixel(ozone_fname, dname, lonlat)
    except ValueError:
        raise AncillaryError("No Ozone data")

    metadata = {
        "id": numpy.array([md_uuid], VLEN_STRING),
        "tier": OzoneTier.DEFINITIVE.name,
    }

    return data, metadata
Example #7
0
def ecwmf_geo_potential(input_path, lonlat, time):
    """
    Retrieve a pixel value from the ECWMF Geo-Potential collection
    across 37 height pressure levels, for a given longitude,
    latitude and time.

    Converts to geo-potential height in KM, and reverses the order of
    the elements (1000 -> 1 mb, rather than 1 -> 1000 mb) before
    returning.
    """
    product = DatasetName.GEOPOTENTIAL.value.lower()
    search = pjoin(input_path, DatasetName.ECMWF_PATH_FMT.value)
    files = glob.glob(search.format(product=product, year=time.year))
    data = None
    required_ymd = datetime.datetime(time.year, time.month, time.day)
    for f in files:
        url = urlparse(f, scheme='file').geturl()
        ymd = splitext(basename(f))[0].split('_')[1]
        ancillary_ymd = datetime.datetime.strptime(ymd, '%Y-%m-%d')
        if ancillary_ymd == required_ymd:
            bands = list(range(1, 38))
            data = get_pixel(f, lonlat, bands)[::-1]
            scaled_data = data / 9.80665 / 1000.0

            metadata = {
                'data_source': 'ECWMF Geo-Potential',
                'url': url,
                'query_date': time
            }

            # ancillary metadata tracking
            md = extract_ancillary_metadata(f)
            for key in md:
                metadata[key] = md[key]

            # internal file metadata (and reverse the ordering)
            df = read_metadata_tags(f, bands).iloc[::-1]
            df.insert(0, 'GeoPotential', data)
            df.insert(1, 'GeoPotential_Height', scaled_data)

            return df, md

    if data is None:
        raise AncillaryError("No ECWMF Geo-Potential profile data")
Example #8
0
def ecwmf_relative_humidity(input_path, lonlat, time):
    """
    Retrieve a pixel value from the ECWMF Relative Humidity collection
    across 37 height pressure levels, for a given longitude,
    latitude and time.

    Reverses the order of elements
    (1000 -> 1 mb, rather than 1 -> 1000 mb) before returning.
    """
    product = DatasetName.RELATIVE_HUMIDITY.value.lower()
    search = pjoin(input_path, DatasetName.ECMWF_PATH_FMT.value)
    files = glob.glob(search.format(product=product, year=time.year))
    data = None
    required_ymd = datetime.datetime(time.year, time.month, time.day)
    for f in files:
        url = urlparse(f, scheme='file').geturl()
        ymd = splitext(basename(f))[0].split('_')[1]
        ancillary_ymd = datetime.datetime.strptime(ymd, '%Y-%m-%d')
        if ancillary_ymd == required_ymd:
            bands = list(range(1, 38))
            data = get_pixel(f, lonlat, bands)[::-1]

            metadata = {
                'data_source': 'ECWMF Relative Humidity',
                'url': url,
                'query_date': time
            }

            # file level metadata
            md = extract_ancillary_metadata(f)
            for key in md:
                metadata[key] = md[key]

            # internal file metadata (and reverse the ordering)
            df = read_metadata_tags(f, bands).iloc[::-1]
            df.insert(0, 'Relative_Humidity', data)

            return df, metadata

    if data is None:
        raise AncillaryError("No ECWMF Relative Humidity profile data")
Example #9
0
def ecwmf_elevation(datafile, lonlat):
    """
    Retrieve a pixel from the ECWMF invariant geo-potential
    dataset.
    Converts to Geo-Potential height in KM.
    2 metres is added to the result before returning.
    """
    try:
        data = get_pixel(datafile, lonlat) / 9.80665 / 1000.0 + 0.002
    except IndexError:
        raise AncillaryError("No Invariant Geo-Potential data")

    url = urlparse(datafile, scheme='file').geturl()

    metadata = {'data_source': 'ECWMF Invariant Geo-Potential', 'url': url}

    # ancillary metadata tracking
    md = extract_ancillary_metadata(datafile)
    for key in md:
        metadata[key] = md[key]

    return data, metadata
Example #10
0
def get_ozone_data(ozone_path, lonlat, time):
    """
    Get ozone data for a scene. `lonlat` should be the (x,y) for the centre
    the scene.
    """
    filename = time.strftime('%b').lower() + '.tif'
    datafile = pjoin(ozone_path, filename)
    url = urlparse(datafile, scheme='file').geturl()

    try:
        data = get_pixel(datafile, lonlat)
    except IndexError:
        raise AncillaryError("No Ozone data")

    metadata = {'data_source': 'Ozone', 'url': url, 'query_date': time}

    # ancillary metadata tracking
    md = extract_ancillary_metadata(datafile)
    for key in md:
        metadata[key] = md[key]

    return data, metadata
Example #11
0
def get_water_vapour(acquisition,
                     water_vapour_dict,
                     scale_factor=0.1,
                     tolerance=1):
    """
    Retrieve the water vapour value for an `acquisition` and the
    path for the water vapour ancillary data.
    """
    dt = acquisition.acquisition_datetime
    geobox = acquisition.gridded_geo_box()

    year = dt.strftime("%Y")
    hour = dt.timetuple().tm_hour
    filename = "pr_wtr.eatm.{year}.h5".format(year=year)

    if "user" in water_vapour_dict:
        metadata = {
            "id": numpy.array([], VLEN_STRING),
            "tier": WaterVapourTier.USER.name
        }
        return water_vapour_dict["user"], metadata

    water_vapour_path = water_vapour_dict["pathname"]

    datafile = pjoin(water_vapour_path, filename)

    if os.path.isfile(datafile):

        with h5py.File(datafile, "r") as fid:
            index = read_h5_table(fid, "INDEX")

        # set the tolerance in days to search back in time
        max_tolerance = -datetime.timedelta(days=tolerance)

        # only look for observations that have occured in the past
        time_delta = index.timestamp - dt
        result = time_delta[(time_delta < datetime.timedelta())
                            & (time_delta > max_tolerance)]

    if not os.path.isfile(datafile) or result.shape[0] == 0:
        if "fallback_dataset" not in water_vapour_dict:
            raise AncillaryError("No actual or fallback water vapour data.")

        tier = WaterVapourTier.FALLBACK_DATASET
        month = dt.strftime("%B-%d").upper()

        # closest previous observation
        # i.e. observations are at 0000, 0600, 1200, 1800
        # and an acquisition hour of 1700 will use the 1200 observation
        observations = numpy.array([0, 6, 12, 18])
        hr = observations[numpy.argmin(numpy.abs(hour - observations))]
        dataset_name = "AVERAGE/{}/{:02d}00".format(month, hr)
        datafile = water_vapour_dict["fallback_dataset"]
    else:
        tier = WaterVapourTier.DEFINITIVE
        # get the index of the closest water vapour observation
        # which would be the maximum timedelta
        # as we're only dealing with negative timedelta's here
        idx = result.idxmax()
        record = index.iloc[idx]
        dataset_name = record.dataset_name

    try:
        data, md_uuid = get_pixel(datafile, dataset_name, geobox.centre_lonlat)
    except ValueError:
        # h5py raises a ValueError not an IndexError for out of bounds
        raise AncillaryError("No Water Vapour data")

    # the metadata from the original file says (Kg/m^2)
    # so multiply by 0.1 to get (g/cm^2)
    data = data * scale_factor
    metadata = {"id": numpy.array([md_uuid], VLEN_STRING), "tier": tier.name}

    return data, metadata