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
Exemple #3
0
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
Exemple #4
0
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
Exemple #6
0
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