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()])
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}
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)
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)
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)
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)
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, }
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, }
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()])
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)
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()
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
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