Exemplo n.º 1
0
    def set_countries(self, countries=[], reg=[], ref_year=2000, path=None):
        """Model countries using values at reference year. If GDP or income
        group not available for that year, consider the value of the closest
        available year.

        Parameters:
            countries (list): list of country names ISO3
            ref_year (int, optional): reference year. Default: 2016
            path (string): path to exposure dataset (ISIMIP)
        """
        gdp2a_list = []
        tag = Tag()

        if path is None:
            LOGGER.error('No path for exposure data set')
            raise NameError

        if not Path(path).is_file():
            LOGGER.error('Invalid path %s', path)
            raise NameError
        try:

            if not countries:
                if reg:
                    natISO = region2isos(reg)
                    countries = np.array(natISO)
                else:
                    LOGGER.error('set_countries requires countries or reg')
                    raise ValueError

            for cntr_ind in range(len(countries)):
                gdp2a_list.append(
                    self._set_one_country(countries[cntr_ind], ref_year, path))
                tag.description += ("{} GDP2Asset \n").\
                    format(countries[cntr_ind])
        except KeyError:
            LOGGER.error(
                'Exposure countries: %s or reg %s could not be set, check ISO3 or'
                ' reference year %s', countries, reg, ref_year)
            raise

        tag.description += 'GDP2Asset ' + str(self.ref_year)
        Exposures.__init__(self,
                           data=Exposures.concat(gdp2a_list).gdf,
                           ref_year=ref_year,
                           tag=tag,
                           value_unit='USD')

        # set meta
        res = 0.0416666

        rows, cols, ras_trans = pts_to_raster_meta(
            (self.gdf.longitude.min(), self.gdf.latitude.min(),
             self.gdf.longitude.max(), self.gdf.latitude.max()), res)
        self.meta = {
            'width': cols,
            'height': rows,
            'crs': self.crs,
            'transform': ras_trans
        }
def _interp_one_poly(poly, res):
    """
    Disaggregate a single polygon to points

    Parameters
    ----------
    poly : shapely Polygon
        Polygon
    res : float
        Resolution (same units as gdf crs)

    Returns
    -------
    shapely multipoint
        Grid of points rasterizing the polygon

    """

    if poly.is_empty:
        return shgeom.MultiPoint([])

    height, width, trafo = u_coord.pts_to_raster_meta(poly.bounds, (res, res))
    x_grid, y_grid = u_coord.raster_to_meshgrid(trafo, width, height)
    in_geom = sh.vectorized.contains(poly, x_grid, y_grid)

    if sum(in_geom.flatten()) > 1:
        return shgeom.MultiPoint(list(zip(x_grid[in_geom], y_grid[in_geom])))

    LOGGER.warning(
        'Polygon smaller than resolution. Setting a representative point.')
    return shgeom.MultiPoint([poly.representative_point()])
Exemplo n.º 3
0
    def set_countries(self, countries, ref_year=2016, res_km=None, from_hr=None,
                      admin_file='admin_0_countries', **kwargs):
        """ Model countries using values at reference year. If GDP or income
        group not available for that year, consider the value of the closest
        available year.

        Parameters:
            countries (list or dict): list of country names (admin0 or subunits)
                or dict with key = admin0 name and value = [admin1 names]
            ref_year (int, optional): reference year. Default: 2016
            res_km (float, optional): approx resolution in km. Default:
                nightlights resolution.
            from_hr (bool, optional): force to use higher resolution image,
                independently of its year of acquisition.
            admin_file (str): file name, admin_0_countries or admin_0_map_subunits
            kwargs (optional): 'gdp' and 'inc_grp' dictionaries with keys the
                country ISO_alpha3 code. 'poly_val' polynomial transformation
                [1,x,x^2,...] to apply to nightlight (DEF_POLY_VAL used if not
                provided). If provided, these are used.
        """
        admin_key_dict = {'admin_0_countries': ['ADMIN', 'ADM0_A3'],
                          'admin_0_map_subunits': ['SUBUNIT', 'SU_A3']}

        shp_file = shapereader.natural_earth(resolution='10m',
                                             category='cultural',
                                             name=admin_file)
        shp_file = shapereader.Reader(shp_file)

        cntry_info, cntry_admin1 = country_iso_geom(countries, shp_file,
                                                    admin_key_dict[admin_file])
        fill_econ_indicators(ref_year, cntry_info, shp_file, **kwargs)

        nightlight, coord_nl, fn_nl, res_fact, res_km = get_nightlight(
            ref_year, cntry_info, res_km, from_hr)

        tag = Tag()
        bkmrbl_list = []

        for cntry_iso, cntry_val in cntry_info.items():

            bkmrbl_list.append(
                self._set_one_country(cntry_val, nightlight, coord_nl, res_fact, res_km,
                                      cntry_admin1[cntry_iso], **kwargs))
            tag.description += ("{} {:d} GDP: {:.3e} income group: {:d} \n").\
                format(cntry_val[1], cntry_val[3], cntry_val[4], cntry_val[5])

        Exposures.__init__(self, gpd.GeoDataFrame(
            pd.concat(bkmrbl_list, ignore_index=True)), crs=DEF_CRS)

        # set metadata
        self.ref_year = ref_year
        self.tag = tag
        self.tag.file_name = fn_nl
        self.value_unit = 'USD'
        rows, cols, ras_trans = pts_to_raster_meta(
            (self.longitude.min(), self.latitude.min(),
             self.longitude.max(), self.latitude.max()),
            (coord_nl[0, 1], -coord_nl[0, 1]))
        self.meta = {'width': cols, 'height': rows, 'crs': self.crs, 'transform': ras_trans}
Exemplo n.º 4
0
def _fraction_on_land(centroids, topo_path):
    """Determine fraction of each centroid cell that is on land.

    Typically, the resolution of the provided DEM data set is much higher than the resolution
    of the centroids so that the centroid cells might be partly above and partly below sea level.
    This function computes for each centroid cell the fraction of its area that is on land.

    Parameters
    ----------
    centroids : Centroids
        Centroids to consider
    topo_path : str
        Path to a raster file containing gridded elevation data.

    Returns
    -------
    fractions : ndarray of shape (ncentroids,)
        For each centroid, the fraction of it's cell area that is on land according to the DEM.
    """
    bounds = np.array(centroids.total_bounds)
    shape = [0, 0]
    if centroids.meta:
        shape = centroids.shape
        cen_trans = centroids.meta['transform']
    else:
        shape[0], shape[1], cen_trans = u_coord.pts_to_raster_meta(
            bounds, min(u_coord.get_resolution(centroids.lat, centroids.lon)))

    read_raster_buffer = 0.5 * max(np.abs(cen_trans[0]), np.abs(cen_trans[4]))
    bounds += read_raster_buffer * np.array([-1., -1., 1., 1.])
    on_land, dem_trans = u_coord.read_raster_bounds(topo_path, bounds)
    on_land = (on_land > 0).astype(np.float64)

    with rasterio.open(topo_path, 'r') as src:
        dem_crs = src.crs
        dem_nodata = src.nodata

    fractions = np.zeros(shape, dtype=np.float64)
    rasterio.warp.reproject(source=on_land,
                            destination=fractions,
                            src_transform=dem_trans,
                            src_crs=dem_crs,
                            dst_transform=cen_trans,
                            dst_crs=centroids.crs,
                            resampling=rasterio.warp.Resampling.average,
                            src_nodata=dem_nodata,
                            dst_nodata=0.0)

    if not centroids.meta:
        x_i = ((centroids.lon - cen_trans[2]) / cen_trans[0]).astype(int)
        y_i = ((centroids.lat - cen_trans[5]) / cen_trans[4]).astype(int)
        fractions = fractions[y_i, x_i]

    return fractions.reshape(-1)
Exemplo n.º 5
0
 def test_pts_to_raster_irreg_pass(self):
     """ Test pts_to_raster_meta with irregular points """
     xmin, ymin, xmax, ymax = -124.19473, 32.81908, -114.4632, 42.020759999999996  # bounds of points == centers pixels
     points_bounds = (xmin, ymin, xmax, ymax)
     res = 0.013498920086393088
     rows, cols, ras_trans = pts_to_raster_meta(points_bounds, res)
     self.assertEqual(ras_trans[0], res)
     self.assertEqual(ras_trans[4], -res)
     self.assertEqual(ras_trans[1], 0.0)
     self.assertEqual(ras_trans[3], 0.0)
     self.assertEqual(ras_trans[2], xmin - res / 2)
     self.assertEqual(ras_trans[5], ymax + res / 2)
     self.assertTrue(ymin >= ymax + res / 2 - rows * res)
     self.assertTrue(xmax <= xmin - res / 2 + cols * res)
Exemplo n.º 6
0
    def set_raster_from_pnt_bounds(self, points_bounds, res, crs=DEF_CRS):
        """ Set raster metadata (meta attribute) from points border data.
        Raster border = point_border + res/2

        Parameters:
            points_bounds (tuple): points' lon_min, lat_min, lon_max, lat_max
            res (float): desired resolution in same units as points_bounds
            crs (dict() or rasterio.crs.CRS, optional): CRS. Default: DEF_CRS
        """
        self.__init__()
        rows, cols, ras_trans = pts_to_raster_meta(points_bounds, res)
        self.set_raster_from_pix_bounds(ras_trans[5], ras_trans[2],
                                        ras_trans[4], ras_trans[0], rows, cols,
                                        crs)
Exemplo n.º 7
0
 def test_vector_to_raster_pass(self):
     """ Test vector_to_raster """
     xmin, ymin, xmax, ymax = -60, -5, -50, 10  # bounds of points == centers pixels
     points_bounds = (xmin, ymin, xmax, ymax)
     res = 0.5
     rows, cols, ras_trans = pts_to_raster_meta(points_bounds, res)
     self.assertEqual(xmin - res / 2 + res * cols, xmax + res / 2)
     self.assertEqual(ymax + res / 2 - res * rows, ymin - res / 2)
     self.assertEqual(ras_trans[0], res)
     self.assertEqual(ras_trans[4], -res)
     self.assertEqual(ras_trans[1], 0.0)
     self.assertEqual(ras_trans[3], 0.0)
     self.assertEqual(ras_trans[2], xmin - res / 2)
     self.assertEqual(ras_trans[5], ymax + res / 2)
     self.assertTrue(ymin >= ymax + res / 2 - rows * res)
     self.assertTrue(xmax <= xmin - res / 2 + cols * res)
Exemplo n.º 8
0
    def set_lat_lon_to_meta(self, min_resol=1.0e-8):
        """Compute meta from lat and lon values.

        Parameters:
            min_resol (float, optional): minimum centroids resolution to use
                in the raster. Default: 1.0e-8.
        """
        res = get_resolution(self.lon, self.lat, min_resol=min_resol)
        rows, cols, ras_trans = pts_to_raster_meta(self.total_bounds, res)
        LOGGER.debug('Resolution points: %s', str(res))
        self.meta = {
            'width': cols,
            'height': rows,
            'crs': self.crs,
            'transform': ras_trans,
        }
Exemplo n.º 9
0
    def set_raster_from_pnt_bounds(self, points_bounds, res, crs=DEF_CRS):
        """Set raster metadata (meta attribute) from points border data.
        Raster border = point_border + res/2

        Parameters:
            points_bounds (tuple): points' lon_min, lat_min, lon_max, lat_max
            res (float): desired resolution in same units as points_bounds
            crs (dict() or rasterio.crs.CRS, optional): CRS. Default: DEF_CRS
        """
        self.__init__()
        rows, cols, ras_trans = pts_to_raster_meta(points_bounds, (res, -res))
        self.meta = {
            'width': cols,
            'height': rows,
            'crs': crs,
            'transform': ras_trans,
        }
Exemplo n.º 10
0
    def set_lat_lon_to_meta(self, min_resol=1.0e-8):
        """ Compute meta from lat and lon values. To match the existing lat
        and lon, lat and lon need to start from the upper left corner!!

        Parameter:
            min_resol (float, optional): minimum centroids resolution to use
                in the raster. Default: 1.0e-8.
        """
        self.meta = dict()
        res = min(get_resolution(self.lat, self.lon, min_resol))
        rows, cols, ras_trans = pts_to_raster_meta(self.total_bounds, res)
        LOGGER.debug('Resolution points: %s', str(res))
        self.meta = {
            'width': cols,
            'height': rows,
            'crs': self.crs,
            'transform': ras_trans
        }
def _interp_one_poly_m(poly, res, orig_crs):
    """
    Disaggregate a single polygon to points for resolution given in meters.
    Transforms coordinates into an adequate projected equal-area crs for this.

    Parameters
    ----------
    poly : shapely Polygon
        Polygon
    res : float
        Resolution in meters
    orig_crs: pyproj.CRS
        CRS of the polygon

    Returns
    -------
    shapely multipoint
        Grid of points rasterizing the polygon

    """

    if poly.is_empty:
        return shgeom.MultiPoint([])

    m_crs = _get_equalarea_proj(poly)
    poly_m = reproject_poly(poly, orig_crs, m_crs)

    height, width, trafo = u_coord.pts_to_raster_meta(poly_m.bounds,
                                                      (res, res))
    x_grid, y_grid = u_coord.raster_to_meshgrid(trafo, width, height)

    in_geom = sh.vectorized.contains(poly_m, x_grid, y_grid)
    if sum(in_geom.flatten()) > 1:
        x_poly, y_poly = reproject_grid(x_grid[in_geom], y_grid[in_geom],
                                        m_crs, orig_crs)
        return shgeom.MultiPoint(list(zip(x_poly, y_poly)))

    LOGGER.warning(
        'Polygon smaller than resolution. Setting a representative point.')
    return shgeom.MultiPoint([poly.representative_point()])
Exemplo n.º 12
0
    def test_calc_grid_impact_polys(self):
        """Test impact on grid for polygons"""
        import climada.util.coordinates as u_coord
        res = 0.1
        (_, _, xmax, ymax) = EXP_POLY.gdf.geometry.bounds.max()
        (xmin, ymin, _, _) = EXP_POLY.gdf.geometry.bounds.min()
        bounds = (xmin, ymin, xmax, ymax)
        height, width, trafo = u_coord.pts_to_raster_meta(bounds, (res, res))
        x_grid, y_grid = u_coord.raster_to_meshgrid(trafo, width, height)

        imp_g = u_lp.calc_grid_impact(exp=EXP_POLY,
                                      impf_set=IMPF_SET,
                                      haz=HAZ,
                                      grid=(x_grid, y_grid),
                                      disagg_met=u_lp.DisaggMethod.DIV,
                                      disagg_val=None,
                                      agg_met=u_lp.AggMethod.SUM)
        aai_agg = 2319608.54202
        eai_exp = np.array([
            17230.22051525, 10974.85453081, 14423.77523209, 77906.29609785,
            22490.08925927, 147937.83580832, 132329.78961234, 375082.82348148,
            514527.07490518, 460185.19291995, 265875.77587879, 280644.81378238
        ])
        check_impact(self, imp_g, HAZ, EXP_POLY, aai_agg, eai_exp)
Exemplo n.º 13
0
    def test_point_exposure_from_polygons_on_grid(self):
        """Test disaggregation of polygons to points on grid"""
        exp_poly = EXP_POLY.copy()
        res = 0.1
        exp_poly.gdf = exp_poly.gdf[exp_poly.gdf['population'] < 400000]
        height, width, trafo = u_coord.pts_to_raster_meta(
            exp_poly.gdf.geometry.bounds, (res, res))
        x_grid, y_grid = u_coord.raster_to_meshgrid(trafo, width, height)

        #to_meters=False, DIV
        exp_pnt = u_lp.exp_geom_to_pnt(exp_poly,
                                       res=0.1,
                                       to_meters=False,
                                       disagg_met=u_lp.DisaggMethod.DIV,
                                       disagg_val=None)
        exp_pnt_grid = u_lp.exp_geom_to_grid(exp_poly, (x_grid, y_grid),
                                             disagg_met=u_lp.DisaggMethod.DIV,
                                             disagg_val=None)
        self.check_unchanged_exp(exp_poly, exp_pnt_grid)
        for col in ['value', 'latitude', 'longitude']:
            np.testing.assert_allclose(exp_pnt.gdf[col], exp_pnt_grid.gdf[col])

        x_grid = np.append(x_grid, x_grid + 10)
        y_grid = np.append(y_grid, y_grid + 10)
        #to_meters=False, DIV
        exp_pnt = u_lp.exp_geom_to_pnt(exp_poly,
                                       res=0.1,
                                       to_meters=False,
                                       disagg_met=u_lp.DisaggMethod.DIV,
                                       disagg_val=None)
        exp_pnt_grid = u_lp.exp_geom_to_grid(exp_poly, (x_grid, y_grid),
                                             disagg_met=u_lp.DisaggMethod.DIV,
                                             disagg_val=None)
        self.check_unchanged_exp(exp_poly, exp_pnt_grid)
        for col in ['value', 'latitude', 'longitude']:
            np.testing.assert_allclose(exp_pnt.gdf[col], exp_pnt_grid.gdf[col])
    def set_ls_hist(self, bbox, input_gdf, res=0.0083333):
        """
        Set historic landslide (ls) raster hazard from historical point records,
        for example as can be retrieved from the NASA COOLR initiative,
        which is the largest global ls repository, for a specific geographic
        extent.
        Points are assigned to the gridcell they fall into, and the whole grid-
        cell hence counts as equally affected.
        Event frequencies from an incomplete dataset are not meaningful and
        hence aren't set by default. probabilistic calculations!
        Use the probabilistic method for this!

        See tutorial for details; the global ls catalog from NASA COOLR can bedownloaded from
        https://maps.nccs.nasa.gov/arcgis/apps/webappviewer/index.html?id=824ea5864ec8423fb985b33ee6bc05b7

        Note
        -----
        The grid which is generated has the same projection as the geodataframe
        with point occurrences. By default, this is EPSG:4326, which is a non-
        projected, geographic CRS. This means, depending on where on the globe
        the analysis is performed, the area per gridcell differs vastly.
        Consider this when setting your resoluton (e.g. at the equator,
        1° ~ 111 km). In turn, one can use projected CRS which preserve angles
        and areas within the reference area for which they are defined. To do
        this, reproject the input_gdf to the desired projection.
        For more on projected & geographic CRS, see
        https://desktop.arcgis.com/en/arcmap/10.3/guide-books/map-projections/about-projected-coordinate-systems.htm

        Parameters:
        ----------
        bbox : tuple
            (minx, miny, maxx, maxy) geographic extent of interest
        input_gdf : str or  or geopandas geodataframe
             path to shapefile (.shp) with ls point data or already laoded gdf
        res : float
            resolution in units of the input_gdf crs of the final grid cells
            which are created. Whith EPSG:4326, this is degrees. Default is
            0.008333.

        Returns:
        --------
            self (Landslide() inst.): instance filled with historic LS hazard
                set for either point hazards or polygons with specified
                surrounding extent.
        """
        if isinstance(input_gdf, gpd.GeoDataFrame):
            LOGGER.info('Using pre-loaded gdf')
            gdf_cropped = input_gdf.copy().cx[bbox[0]:bbox[2], bbox[1]:bbox[3]]
        else:
            LOGGER.info('Reading in gdf from source %s', input_gdf)
            gdf_cropped = gpd.read_file(input_gdf, bbox=bbox)

        LOGGER.info('Generating a raster with resolution %s for box %s', res,
                    bbox)
        if not gdf_cropped.crs:
            gdf_cropped.crs = DEF_CRS
        self.centroids.set_raster_from_pnt_bounds(bbox,
                                                  res,
                                                  crs=gdf_cropped.crs)

        n_ev = len(gdf_cropped)

        # assign lat-lon points of LS events to corresponding grid & flattened
        # grid-index
        grid_height, grid_width, grid_transform = u_coord.pts_to_raster_meta(
            bbox, (res, -res))
        gdf_cropped['flat_ix'] = u_coord.assign_grid_points(
            gdf_cropped.geometry.x, gdf_cropped.geometry.y, grid_width,
            grid_height, grid_transform)
        self.intensity = sparse.csr_matrix(
            (np.ones(n_ev), (np.arange(n_ev), gdf_cropped.flat_ix)),
            shape=(n_ev, self.centroids.size))
        self.fraction = self.intensity.copy()
        self.frequency = self.intensity.copy()

        if hasattr(gdf_cropped, 'ev_date'):
            self.date = pd.to_datetime(gdf_cropped.ev_date, yearfirst=True)
        else:
            LOGGER.info('No event dates set from source')

        if self.date.size > 0:
            self.frequency = np.ones(n_ev) / (
                (self.date.max() - self.date.min()).value / 3.154e+16)
        else:
            LOGGER.warning('no event dates to derive proxy frequency from')

        self.units = ''
        self.event_id = np.arange(n_ev, dtype=int) + 1
        self.orig = np.ones(n_ev, bool)

        self.check()
Exemplo n.º 15
0
    def set_from_isimip_netcdf(self, input_dir=None, filename=None, hist_mean=None,
                               bbox=None, yearrange=None, cl_model=None, scenario=None,
                               crop=None, irr=None, isimip_version=None,
                               unit=None, fn_str_var=None):

        """Wrapper to fill exposure from NetCDF file from ISIMIP. Requires historical
        mean relative cropyield module as additional input.
        Optional Parameters:
            input_dir (string): path to input data directory
            filename (string): name of the landuse data file to use,
                e.g. "histsoc_landuse-15crops_annual_1861_2005.nc""
            hist_mean (str or array): historic mean crop yield per centroid (or path)
            bbox (list of four floats): bounding box:
                [lon min, lat min, lon max, lat max]
            yearrange (int tuple): year range for exposure set
               e.g., (1990, 2010)
            scenario (string): climate change and socio economic scenario
               e.g., '1860soc', 'histsoc', '2005soc', 'rcp26soc','rcp60soc','2100rcp26soc'
            cl_model (string): abbrev. climate model (only for future projections of lu data)
               e.g., 'gfdl-esm2m', 'hadgem2-es', 'ipsl-cm5a-lr','miroc5'
            crop (string): crop type
               e.g., 'mai', 'ric', 'whe', 'soy'
            irr (string): irrigation type, default: 'combined'
                f.i 'firr' (full irrigation), 'noirr' (no irrigation) or 'combined'= firr+noirr
            isimip_version(str): 'ISIMIP2' (default) or 'ISIMIP3'
            unit (string): unit of the exposure (per year)
                f.i 't/y' (default), 'USD/y', or 'kcal/y'
            fn_str_var (string): FileName STRing depending on VARiable and
                ISIMIP simuation round

        Returns:
            Exposure
        """
        # parameters not provided in method call are set to default values:
        if irr is None:
            irr = 'combined'
        if not bbox:
            bbox = BBOX
        if not input_dir:
            input_dir = INPUT_DIR
        if hist_mean is None:
            hist_mean = HIST_MEAN_PATH
        if not fn_str_var:
            fn_str_var = FN_STR_VAR
        if (not isimip_version) or (isimip_version in ('ISIMIP2a', 'ISIMIP2b')):
            isimip_version = 'ISIMIP2'
        elif isimip_version in ('ISIMIP3a', 'ISIMIP3b'):
            isimip_version = 'ISIMIP3'
        if (not scenario) or (scenario in ('historical', 'hist')):
            scenario = 'histsoc'
        if yearrange is None:
            yearrange = YEARCHUNKS[isimip_version][scenario]['yearrange']
        if not unit:
            unit = 't/y'
        #if not soc: soc=''
        # The filename is set or other variables (cl_model, scenario) are extracted of the
        # specified filename
        if filename is None:
            yearchunk = YEARCHUNKS[isimip_version][scenario]
            # if scenario == 'histsoc' or scenario == '1860soc':
            if scenario in ('histsoc', '1860soc'):
                string = '{}_{}_{}_{}.nc'
                filepath = Path(input_dir, string.format(scenario, fn_str_var,
                                                         yearchunk['startyear'],
                                                         yearchunk['endyear']))
            else:
                string = '{}_{}_{}_{}_{}.nc'
                filepath = Path(input_dir, string.format(scenario, cl_model, fn_str_var,
                                                         yearchunk['startyear'],
                                                         yearchunk['endyear']))
        elif scenario == 'flexible':
            _, _, _, _, _, _, startyear, endyearnc = filename.split('_')
            endyear = endyearnc.split('.')[0]
            yearchunk = dict()
            yearchunk = {'yearrange': (int(startyear), int(endyear)),
                         'startyear': int(startyear), 'endyear': int(endyear)}
            filepath = Path(input_dir, filename)
        else:
            scenario, *_ = filename.split('_')
            yearchunk = YEARCHUNKS[isimip_version][scenario]
            filepath = Path(input_dir, filename)

        # Dataset is opened and data within the bbox extends is extracted
        data_set = xr.open_dataset(filepath, decode_times=False)
        [lonmin, latmin, lonmax, latmax] = bbox
        data = data_set.sel(lon=slice(lonmin, lonmax), lat=slice(latmax, latmin))

        # The latitude and longitude are set; the region_id is determined
        lon, lat = np.meshgrid(data.lon.values, data.lat.values)
        self.gdf['latitude'] = lat.flatten()
        self.gdf['longitude'] = lon.flatten()
        self.gdf['region_id'] = u_coord.get_country_code(self.gdf.latitude, self.gdf.longitude)

        # The indeces of the yearrange to be extracted are determined
        time_idx = (int(yearrange[0] - yearchunk['startyear']),
                             int(yearrange[1] - yearchunk['startyear']))

        # The area covered by a grid cell is calculated depending on the latitude
        # 1 degree = 111.12km (at the equator); resolution data: 0.5 degree;
        # longitudal distance in km = 111.12*0.5*cos(lat);
        # latitudal distance in km = 111.12*0.5;
        # area = longitudal distance * latitudal distance;
        # 1km2 = 100ha
        area = (111.12 * 0.5)**2 * np.cos(np.deg2rad(lat)) * 100

        # The area covered by a crop is calculated as the product of the fraction and
        # the grid cell size
        if irr == 'combined':
            irr_types = ['firr', 'noirr']
        else:
            irr_types = [irr]
        area_crop = dict()
        for irr_var in irr_types:
            area_crop[irr_var] = (
                getattr(
                    data, (CROP_NAME[crop])['input']+'_'+ (IRR_NAME[irr_var])['name']
                )[time_idx[0]:time_idx[1], :, :].mean(dim='time')*area
            ).values
            area_crop[irr_var] = np.nan_to_num(area_crop[irr_var]).flatten()

        # set historic mean, its latitude, and longitude:
        hist_mean_dict = dict()
        # if hist_mean is given as np.ndarray or dict,
        # code assumes it contains hist_mean as returned by relative_cropyield
        # however structured in dictionary as hist_mean_dict, with same
        # bbox extensions as the exposure:
        if isinstance(hist_mean, dict):
            if not ('firr' in hist_mean.keys() or 'noirr' in hist_mean.keys()):
                # as a dict hist_mean, needs to contain key 'firr' or 'noirr';
                # if irr=='combined', both 'firr' and 'noirr' are required.
                LOGGER.error('Invalid hist_mean provided: %s', hist_mean)
                raise ValueError('invalid hist_mean.')
            hist_mean_dict = hist_mean
            lat_mean = self.gdf.latitude.values
        elif isinstance(hist_mean, np.ndarray) or isinstance(hist_mean, list):
            hist_mean_dict[irr_types[0]] = np.array(hist_mean)
            lat_mean = self.gdf.latitude.values
        elif Path(hist_mean).is_dir(): # else if hist_mean is given as path to directory
        # The adequate file from the directory (depending on crop and irrigation) is extracted
        # and the variables hist_mean, lat_mean and lon_mean are set accordingly
            for irr_var in irr_types:
                filename = str(Path(hist_mean, 'hist_mean_%s-%s_%i-%i.hdf5' %(
                    crop, irr_var, yearrange[0], yearrange[1])))
                hist_mean_dict[irr_var] = (h5py.File(filename, 'r'))['mean'][()]
            lat_mean = (h5py.File(filename, 'r'))['lat'][()]
            lon_mean = (h5py.File(filename, 'r'))['lon'][()]
        elif Path(input_dir, hist_mean).is_file(): # file path
        # Hist_mean, lat_mean and lon_mean are extracted from the given file
            if len(irr_types) > 1:
                LOGGER.error("For irr=='combined', hist_mean can not be single file. Aborting.")
                raise ValueError('Wrong combination of parameters irr and hist_mean.')
            hist_mean = h5py.File(str(Path(input_dir, hist_mean)), 'r')
            hist_mean_dict[irr_types[0]] = hist_mean['mean'][()]
            lat_mean = hist_mean['lat'][()]
            lon_mean = hist_mean['lon'][()]
        else:
            LOGGER.error('Invalid hist_mean provided: %s', hist_mean)
            raise ValueError('invalid hist_mean.')

        # The bbox is cut out of the hist_mean data file if needed
        if len(lat_mean) != len(self.gdf.latitude.values):
            idx_mean = np.zeros(len(self.gdf.latitude.values), dtype=int)
            for i in range(len(self.gdf.latitude.values)):
                idx_mean[i] = np.where(
                    (lat_mean == self.gdf.latitude.values[i])
                    & (lon_mean == self.gdf.longitude.values[i])
                )[0][0]
        else:
            idx_mean = np.arange(0, len(lat_mean))

        # The exposure [t/y] is computed per grid cell as the product of the area covered
        # by a crop [ha] and its yield [t/ha/y]
        self.gdf['value'] = np.squeeze(area_crop[irr_types[0]] * \
                                   hist_mean_dict[irr_types[0]][idx_mean])
        self.gdf['value'] = np.nan_to_num(self.gdf.value) # replace NaN by 0.0
        for irr_val in irr_types[1:]: # add other irrigation types if irr=='combined'
            value_tmp = np.squeeze(area_crop[irr_val]*hist_mean_dict[irr_val][idx_mean])
            value_tmp = np.nan_to_num(value_tmp) # replace NaN by 0.0
            self.gdf['value'] += value_tmp
        self.tag = Tag()

        self.tag.description = ("Crop production exposure from ISIMIP " +
                                (CROP_NAME[crop])['print'] + ' ' +
                                irr + ' ' + str(yearrange[0]) + '-' + str(yearrange[-1]))
        self.value_unit = 't/y' # input unit, will be reset below if required by user
        self.crop = crop
        self.ref_year = yearrange
        try:
            rows, cols, ras_trans = pts_to_raster_meta(
                (self.gdf.longitude.min(), self.gdf.latitude.min(),
                 self.gdf.longitude.max(), self.gdf.latitude.max()),
                get_resolution(self.gdf.longitude, self.gdf.latitude))
            self.meta = {
                'width': cols,
                'height': rows,
                'crs': self.crs,
                'transform': ras_trans,
            }
        except ValueError:
            LOGGER.warning('Could not write attribute meta, because exposure'
                           ' has only 1 data point')
            self.meta = {}

        if 'USD' in unit:
            # set_value_to_usd() is called to compute the exposure in USD/y (country specific)
            self.set_value_to_usd(input_dir=input_dir)
        elif 'kcal' in unit:
            # set_value_to_kcal() is called to compute the exposure in kcal/y
            self.set_value_to_kcal()
        self.check()

        return self
Exemplo n.º 16
0
def _surge_decay(inten_surge, centroids, dem_product, set_fraction, min_resol, \
                 add_sea_level_rise):
    """ Substract DEM height and decay factor from initial surge height and
    computes corresponding fraction matrix.

    Parameter:
        inten_surge (sparse.csr_matrix): initial surge height in m
        centroids (Centroids): centroids, either raster or points
        dem_product (str): DEM to use: 'SRTM1' (30m) or 'SRTM3' (90m)
        set_fraction (bool, optional): set fraction matrix different to ones.
            Default: True
        min_resol (float, optional): minimum points centroids resolution to
            use when interpolating DEM data. Used in get_resolution method.
            If get_resolution(centroids.lat, centroids.lon) gives a too low
            number, set this parameter to the right centroids resolution.
            Default: 1.0e-8.
        add_sea_level_rise (float): sea level rise in meters to be added to surge

    Returns:
        inten_surge (sparse.csr_matrix), fract_surge (sparse.csr_matrix)
    """
    import elevation

    inland_decay = _calc_inland_decay(centroids)

    # substract event by event to avoid to densificate all the matrix
    inten_surge = _substract_sparse_surge(inten_surge, centroids.elevation, \
                                          inland_decay, add_sea_level_rise)

    # if set_fraction: fraction is fraction of centroids of DEM on land in
    # given centroids cell. Else fraction is ones where intensity.
    if set_fraction:
        bounds = np.array(centroids.total_bounds)
        if centroids.meta:
            shape = centroids.shape
            ras_trans = centroids.meta['transform']
        else:
            shape = [0, 0]
            shape[0], shape[1], ras_trans = pts_to_raster_meta(bounds, \
                min(get_resolution(centroids.lat, centroids.lon, min_resol)))
        bounds += np.array([-.05, -.05, .05, .05])
        elevation.clip(bounds,
                       output=TMP_ELEVATION_FILE,
                       product=dem_product,
                       max_download_tiles=MAX_DEM_TILES_DOWN)
        fract_surge = np.zeros(shape)
        with rasterio.open(TMP_ELEVATION_FILE, 'r') as src:
            on_land = src.read(1)
            on_land[on_land > 0] = 1  # 1 land
            on_land[on_land <= 0] = 0  # 0 water
            on_land[on_land == src.nodata] = 0  # 0 nodata
            reproject(source=on_land,
                      destination=fract_surge,
                      src_transform=src.transform,
                      src_crs=src.crs,
                      dst_transform=ras_trans,
                      dst_crs=centroids.crs,
                      resampling=Resampling.average,
                      src_nodata=src.nodata,
                      dst_nodata=src.nodata)
        if centroids.meta:
            fract_surge = csr_matrix(fract_surge.flatten())
            fract_surge = csr_matrix(np.ones([inten_surge.shape[0], 1
                                              ])) * fract_surge
        else:
            x_i = ((centroids.lon - ras_trans[2]) / ras_trans[0]).astype(int)
            y_i = ((centroids.lat - ras_trans[5]) / ras_trans[4]).astype(int)
            fract_surge = csr_matrix(fract_surge[y_i, x_i])
    else:
        fract_surge = inten_surge.copy()
        fract_surge.data.fill(1)

    return inten_surge, fract_surge