def extract_by_geometry(geometries, bounds, prescreen=False): """Calculate the area of overlap between geometries and NatureScape dataset. Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ bounds : list-like of [xmin, ymin, xmax, ymax] prescreen : bool (default False) if True, prescreen using lower resolution mask to determine if there is overlap with this dataset Returns ------- dict or None (if does not overlap Nature's Network dataset) """ if prescreen: # prescreen to make sure data are present with rasterio.open(ns_mask_filename) as src: if not detect_data(src, geometries, bounds): return None results = {} # create mask and window with rasterio.open(ns_filename) as src: try: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False) except ValueError: return None # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES results["shape_mask"] = (( (~shape_mask).sum() * cellsize).round(ACRES_PRECISION).astype( "float32").round(ACRES_PRECISION).astype("float32")) # Nothing in shape mask, return None if results["shape_mask"] == 0: return None max_value = INPUTS["app"]["values"][-1]["value"] counts = extract_count_in_geometry(ns_filename, shape_mask, window, np.arange(max_value + 1), boundless=True) # there is no overlap if counts.max() == 0: return None results["app"] = (counts * cellsize).round(ACRES_PRECISION).astype("float32") return results
def extract_by_geometry(geometries, bounds): """Calculate the area of overlap between geometries and urbanization for each decade from 2020 to 2100. This is only applicable to inland (non-marine) areas. NOTE: urbanization is on a 60m grid Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ bounds : list-like of [xmin, ymin, xmax, ymax] Returns ------- dict keys are mask, <decade>, ... values are the total acres of urbanization for each decade """ # prescreen to make sure data are present with rasterio.open(src_dir / "urban_mask.tif") as src: if not detect_data(src, geometries, bounds): return None results = {} # create mask and window with rasterio.open(src_dir / "urban_2020.tif") as src: try: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False ) except ValueError: return None # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES results["shape_mask"] = ( ((~shape_mask).sum() * cellsize).round(ACRES_PRECISION).astype("float32") ) if results["shape_mask"] == 0: return None # values are probability of urbanization per timestep * 1000 (uint16) # NOTE: index 0 = not predicted to urbanize # index 1 = already urban, so given a probability of 1 # actual probabilities start at 0.025 probabilities = ( np.array( [ 0, 1000, 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950, 975, 1000, ] ) / 1000 ) bins = np.arange(0, len(probabilities)) for year in URBAN_YEARS: filename = src_dir / f"urban_{year}.tif" counts = extract_count_in_geometry( filename, shape_mask, window, bins, boundless=True ) if year == 2020: # extract area already urban (in index 1) results["urban"] = ( (counts[1] * cellsize).round(ACRES_PRECISION).astype("float32") ) # total urbanization is sum of pixel counts * probability results[year] = ( ((counts * probabilities).sum() * cellsize) .round(ACRES_PRECISION) .astype("float32") ) return results
def extract_by_geometry(geometries, bounds, prescreen=False, marine=False): """Calculate the area of overlap between geometries and South Atlantic Conservation Blueprint dataset. Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ bounds : list-like of [xmin, ymin, xmax, ymax] prescreen : bool (default False) if True, prescreen using lower resolution mask to determine if there is overlap with this dataset marine : bool (default False) True for marine lease blocks, False otherwise. Returns ------- dict or None (if does not overlap) """ if prescreen: # prescreen to make sure data are present with rasterio.open(sa_mask_filename) as src: if not detect_data(src, geometries, bounds): return None results = {} # create mask and window with rasterio.open(sa_filename) as src: try: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False) except ValueError: return None # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES results["shape_mask"] = (( (~shape_mask).sum() * cellsize).round(ACRES_PRECISION).astype( "float32").round(ACRES_PRECISION).astype("float32")) # Nothing in shape mask, return None if results["shape_mask"] == 0: return None max_value = INPUTS["sa"]["values"][-1]["value"] counts = extract_count_in_geometry(sa_filename, shape_mask, window, np.arange(max_value + 1), boundless=True) # there is no overlap if counts.max() == 0: return None results["sa"] = (counts * cellsize).round(ACRES_PRECISION).astype("float32") if marine: # marine areas only have marine indicators indicators = [ i for i in INDICATORS if i["id"].startswith("sa:marine_") ] indicators = detect_indicators(geometries, indicators) else: # include all indicators that are present in area indicators = detect_indicators(geometries, INDICATORS) for indicator in indicators: id = indicator["id"] filename = src_dir / indicator["filename"] values = [e["value"] for e in indicator["values"]] bins = np.arange(0, max(values) + 1) counts = extract_count_in_geometry(filename, shape_mask, window, bins, boundless=True) # Some indicators exclude 0 values, their counts need to be zeroed out here min_value = min(values) if min_value > 0: counts[range(0, min_value)] = 0 results[id] = (counts * cellsize).round(ACRES_PRECISION).astype("float32") return results
def extract_by_geometry(geometries, bounds): """Calculate the area of overlap between geometries and each level of SLR between 0 (currently inundated) and 6 meters. Values are cumulative; the total area inundated is added to each higher level of SLR This is only applicable to inland (non-marine) areas that are near the coast. NOTE: SLR is in a VRT with a cell size derived from the underlying rasters. Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ Should be limited to features that intersect with bounds of SLR datasets bounds : list-like of [xmin, ymin, xmax, ymax] Returns ------- dict keys are mask, <decade>, ... values are the area of incremental (not total!) sea level rise by foot """ results = {} # create mask and window with rasterio.open(vrt_filename) as src: try: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False ) except ValueError: return None # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES data = src.read(1, window=window, boundless=True) nodata = src.nodatavals[0] mask = (data == nodata) | shape_mask data = np.where(mask, nodata, data) results["shape_mask"] = ( ((~shape_mask).sum() * cellsize).round(ACRES_PRECISION).astype("float32") ) if results["shape_mask"] == 0: return None bins = np.arange(7) counts = extract_count_in_geometry( vrt_filename, shape_mask, window, bins=bins, boundless=True ) # accumulate values for bin in bins[1:]: counts[bin] = counts[bin] + counts[bin - 1] acres = (counts * cellsize).round(ACRES_PRECISION).astype("float32") results.update({i: a for i, a in enumerate(acres)}) return results
def extract_by_geometry(geometries, bounds, marine=False, zonal_means=False): """Calculate the area of overlap between geometries and Blueprint, corridors, and indicators. NOTE: Blueprint, indicators, and corridors are on the same 30m grid. Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ bounds : list-like of [xmin, ymin, xmax, ymax] marine : bool (default False) if True will use only marine indicators zonal_means : bool (default False) if True, will calculate zonal means for continuous indicators Returns ------- dict or None (if does not overlap) """ results = {"counts": {}, "means": {}} # create mask and window with rasterio.open(blueprint_filename) as src: try: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False ) except ValueError: return None # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES # DEBUG: # write_raster( # f"/tmp/shape_mask.tif", # (~shape_mask).astype("uint8"), # transform, # crs=src.crs, # nodata=0, # ) results["counts"]["shape_mask"] = ( ((~shape_mask).sum() * cellsize) .round(ACRES_PRECISION) .astype("float32") .round(ACRES_PRECISION) .astype("float32") ) # Nothing in shape mask, return None # NOTE: this does not detect that area is completely outside SA area if results["counts"]["shape_mask"] == 0: return None blueprint_counts = extract_count_in_geometry( blueprint_filename, shape_mask, window, np.arange(len(BLUEPRINT)), boundless=True, ) results["counts"]["blueprint"] = ( (blueprint_counts * cellsize).round(ACRES_PRECISION).astype("float32") ) blueprint_total = blueprint_counts.sum() corridor_counts = extract_count_in_geometry( corridors_filename, shape_mask, window, np.arange(len(CORRIDORS)), boundless=True, ) results["counts"]["corridors"] = ( (corridor_counts * cellsize).round(ACRES_PRECISION).astype("float32") ) if marine: # marine areas only have marine indicators indicators = [i for i in INDICATORS if i["id"].startswith("marine_")] indicators = detect_indicators(geometries, indicators) else: # include all indicators that are present in area indicators = detect_indicators(geometries, INDICATORS) for indicator in indicators: id = indicator["id"] filename = indicators_dir / indicator["filename"] values = [e["value"] for e in indicator["values"]] bins = np.arange(0, max(values) + 1) counts = extract_count_in_geometry( filename, shape_mask, window, bins, boundless=True ) # Some indicators exclude 0 values, their counts need to be zeroed out here min_value = min(values) if min_value > 0: counts[range(0, min_value)] = 0 results["counts"][id] = ( (counts * cellsize).round(ACRES_PRECISION).astype("float32") ) if zonal_means and indicator.get("continuous"): continuous_filename = continuous_indicator_dir / indicator[ "filename" ].replace("_Binned", "") mean = extract_zonal_mean( continuous_filename, shape_mask, window, boundless=True ) if mean is not None: results["means"][id] = mean return results
def extract_by_geometry(geometries, bounds): """Calculate the area of overlap between geometries and Blueprint grids. NOTE: Blueprint and inputs are on the same grid Parameters ---------- geometries : list-like of geometry objects that provide __geo_interface__ bounds : list-like of [xmin, ymin, xmax, ymax] Returns ------- dict or None (if does not overlap Blueprint data) {"shape_mask": <shape_mask_area>, "blueprint": [...], ...} """ # prescreen to make sure data are present with rasterio.open(bp_inputs_mask_filename) as src: if not detect_data(src, geometries, bounds): return None results = {} # create mask and window with rasterio.open(blueprint_filename) as src: shape_mask, transform, window = boundless_raster_geometry_mask( src, geometries, bounds, all_touched=False) # square meters to acres cellsize = src.res[0] * src.res[1] * M2_ACRES # DEBUG: # print( # f"Memory of shape mask: {shape_mask.size * shape_mask.itemsize / (1024 * 1024):0.2f} MB", # shape_mask.dtype, # ) results = { "shape_mask": (((~shape_mask).sum() * cellsize).round(ACRES_PRECISION).astype( "float32").round(ACRES_PRECISION).astype("float32")) } # Nothing in shape mask, return None if results["shape_mask"] == 0: return None blueprint_counts = extract_count_in_geometry( blueprint_filename, shape_mask, window, np.arange(len(BLUEPRINT)), boundless=True, ) results["blueprint"] = (( blueprint_counts * cellsize).round(ACRES_PRECISION).astype("float32")) bp_input_counts = extract_count_in_geometry( bp_inputs_filename, shape_mask, window, bins=range(0, len(INPUT_AREA_VALUES)), boundless=True, ) results["inputs"] = ((bp_input_counts * cellsize).round(ACRES_PRECISION).astype("float32")) return results