Exemplo n.º 1
0
def _calculate_vri(l_path, target_vri_path):
    """Calculate VRI as li_array / qb_sum.

    Parameters:
        l_path (str): path to L raster.
        target_vri_path (str): path to output Vri raster.

    Returns:
        None.

    """
    qb_sum = 0.0
    qb_valid_count = 0
    l_nodata = pygeoprocessing.get_raster_info(l_path)['nodata'][0]

    for _, block in pygeoprocessing.iterblocks((l_path, 1)):
        valid_mask = block != l_nodata
        qb_sum += numpy.sum(block[valid_mask])
        qb_valid_count += numpy.count_nonzero(valid_mask)
    li_nodata = pygeoprocessing.get_raster_info(l_path)['nodata'][0]

    def vri_op(li_array):
        """Calculate vri index [Eq 10]."""
        result = numpy.empty_like(li_array)
        result[:] = li_nodata
        if qb_sum > 0:
            valid_mask = li_array != li_nodata
            result[valid_mask] = li_array[valid_mask] / qb_sum
        return result

    pygeoprocessing.raster_calculator([(l_path, 1)], vri_op, target_vri_path,
                                      gdal.GDT_Float32, li_nodata)
Exemplo n.º 2
0
def add_elk_to_large_land_mammals():
    """Add the elk raster to the sum of other large land mammals."""
    extract_folder = "E:/Datasets/AK_GAP_Analysis/Other_Subsistence_Spp/Unzip"
    with tempfile.TemporaryDirectory(dir=extract_folder) as temp_spp_dir:
        raster_list = [
            "E:/Datasets/AK_GAP_Analysis/Other_Subsistence_Spp/Processed/Large_Land_mammals.tif",
            "E:/Datasets/AK_GAP_Analysis/Other_Subsistence_Spp/Processed/Elk_AHMG.tif"
        ]
        input_nodata = pygeoprocessing.get_raster_info(
            raster_list[0])['nodata'][0]
        pixel_size = pygeoprocessing.get_raster_info(
            raster_list[0])['pixel_size']
        for raster_path in raster_list:
            test_nodata = pygeoprocessing.get_raster_info(
                raster_path)['nodata'][0]
            if test_nodata != input_nodata:
                reclassify_nodata(raster_path, input_nodata)

        aligned_path_list = [
            os.path.join(temp_spp_dir, os.path.basename(f))
            for f in raster_list
        ]
        pygeoprocessing.align_and_resize_raster_stack(
            raster_list, aligned_path_list, ['near'] * len(raster_list),
            pixel_size, 'union')

        destination_path = "E:/Datasets/AK_GAP_Analysis/Other_Subsistence_Spp/Processed/Large_Land_Mammals_with_Elk.tif"
        raster_list_sum(aligned_path_list,
                        input_nodata,
                        destination_path,
                        _TARGET_NODATA,
                        _TARGET_DATATYPE,
                        nodata_remove=True)
def threshold_by_raster(base_raster_path, threshold_raster_path,
                        target_raster_path):
    """If base <= threshold, then 1, otherwise 0."""
    base_raster_info = pygeoprocessing.get_raster_info(base_raster_path)
    threshold_raster_info = pygeoprocessing.get_raster_info(
        threshold_raster_path)
    target_nodata = 255

    align_id = (
        f'{os.path.splitext(os.path.basename(base_raster_path))[0]}_'
        f'{os.path.splitext(os.path.basename(threshold_raster_path))[0]}')

    # align rasters
    align_raster_path_list = [
        os.path.join(
            CHURN_DIR, f'aligned_{align_id}_'
            f'{os.path.basename(os.path.splitext(path)[0])}.tif')
        for path in [base_raster_path, threshold_raster_path]
    ]

    pygeoprocessing.align_and_resize_raster_stack(
        [base_raster_path, threshold_raster_path], align_raster_path_list,
        ['near'] * 2, base_raster_info['pixel_size'], 'intersection')

    pygeoprocessing.raster_calculator(
        [(align_raster_path_list[0], 1), (align_raster_path_list[1], 1),
         (base_raster_info['nodata'][0], 'raw'),
         (threshold_raster_info['nodata'][0], 'raw'), (target_nodata, 'raw')],
        threshold_array_op, target_raster_path, gdal.GDT_Byte, target_nodata)
def resample_raster_preserving_sum(input_raster, match_raster,
                                   intermediate_raster, output_raster):
    rasterArray = gdal_array.LoadFile(input_raster)
    # Replace ndv (-3.4028230607370965e+38) by 0 and sum population
    raster_info = pygeoprocessing.get_raster_info(input_raster)
    ndv = raster_info['nodata'][0]
    rasterArray[rasterArray == ndv] = 0
    total_pop = rasterArray.sum()
    print('Sum of pixels: ' + str(total_pop / 1e9) + ' bio')

    # Resample population "bilinear"
    hb.spatial_utils.align_dataset_to_match(input_raster,
                                            match_raster,
                                            intermediate_raster,
                                            resample_method='bilinear')

    rasterArray = gdal_array.LoadFile(intermediate_raster)
    # Replace ndv by 0 and sum population
    raster_info = pygeoprocessing.get_raster_info(intermediate_raster)
    ndv = raster_info['nodata'][0]
    rasterArray[rasterArray == ndv] = 0
    total_new_fake_pop = rasterArray.sum()

    # Write output Raster = intermediate raster * total_pop/total_new_fake_pop
    print('Writing raster at ' + output_raster)
    outputArray = rasterArray * (total_pop / total_new_fake_pop)
    hb.save_array_as_geotiff(outputArray,
                             output_raster,
                             geotiff_uri_to_match=match_raster)
Exemplo n.º 5
0
def _msa_calculation(msa_f_path, msa_lu_path, msa_i_path, msa_path,
                     msa_nodata):
    """Calculate the MSA which is the product of the sub MSAs.

    Args:
        msa_f_path (str): path to the msa_f raster.
        msa_lu_path (str): path to the msa_lu raster.
        msa_i_path (str): path to the msa_i raster.
        msa_path (str): path to the output MSA raster.
        msa_nodata (int/float): the output nodata value.

    Returns:
        Nothing
    """
    msa_f_nodata = pygeoprocessing.get_raster_info(msa_f_path)['nodata'][0]
    msa_lu_nodata = pygeoprocessing.get_raster_info(msa_lu_path)['nodata'][0]
    msa_i_nodata = pygeoprocessing.get_raster_info(msa_i_path)['nodata'][0]
    nodata_array = [msa_f_nodata, msa_lu_nodata, msa_i_nodata]

    def msa_op(msa_f, msa_lu, msa_i):
        """Calculate the MSA which is the product of the sub MSAs."""
        result = numpy.full_like(msa_f, msa_nodata, dtype=numpy.float32)
        valid_mask = numpy.ones(msa_f.shape, dtype=bool)
        for msa_array, nodata_val in zip([msa_f, msa_lu, msa_i], nodata_array):
            if nodata_val is not None:
                valid_mask &= ~numpy.isclose(msa_array, nodata_val)
        result[valid_mask] = (msa_f[valid_mask] * msa_lu[valid_mask] *
                              msa_i[valid_mask])
        return result

    pygeoprocessing.raster_calculator([(msa_f_path, 1), (msa_lu_path, 1),
                                       (msa_i_path, 1)], msa_op, msa_path,
                                      gdal.GDT_Float32, msa_nodata)
def diff_valid(a_raster_path, b_raster_path, target_diff_raster_path):
    """Calculate a-b.

    Args:
        a_raster_path (str): path to arbitrary raster
        b_raster_path (str): path to raster that is the same size as a
        target_diff_raster_path (str): result of a-b where both a and b are
            not nodata.

    Returns:
        None.
    """
    a_info = pygeoprocessing.get_raster_info(a_raster_path)
    b_info = pygeoprocessing.get_raster_info(b_raster_path)

    def valid_diff_op(a_array, b_array):
        """Calc a-b."""
        result = numpy.empty_like(a_array)
        result[:] = a_info['nodata'][0]
        valid_mask = (~numpy.isclose(a_array, a_info['nodata'][0])
                      & ~numpy.isclose(b_array, b_info['nodata'][0]))
        result[valid_mask] = a_array[valid_mask] - b_array[valid_mask]
        return result

    pygeoprocessing.raster_calculator([(a_raster_path, 1), (b_raster_path, 1)],
                                      valid_diff_op, target_diff_raster_path,
                                      a_info['datatype'], a_info['nodata'][0])
Exemplo n.º 7
0
def _calculate_d_up(
        w_bar_path, s_bar_path, flow_accumulation_path, out_d_up_path):
    """Calculate w_bar * s_bar * sqrt(flow accumulation * cell area)."""
    cell_area = pygeoprocessing.get_raster_info(
        w_bar_path)['mean_pixel_size'] ** 2
    flow_accumulation_nodata = pygeoprocessing.get_raster_info(
        flow_accumulation_path)['nodata'][0]

    def d_up_op(w_bar, s_bar, flow_accumulation):
        """Calculate the d_up index.

        w_bar * s_bar * sqrt(upstream area)

        """
        valid_mask = (
            (w_bar != _TARGET_NODATA) & (s_bar != _TARGET_NODATA) &
            (flow_accumulation != flow_accumulation_nodata))
        d_up_array = numpy.empty(valid_mask.shape)
        d_up_array[:] = _TARGET_NODATA
        d_up_array[valid_mask] = (
            w_bar[valid_mask] * s_bar[valid_mask] * numpy.sqrt(
                flow_accumulation[valid_mask] * cell_area))
        return d_up_array

    pygeoprocessing.raster_calculator(
        [(path, 1) for path in [
            w_bar_path, s_bar_path, flow_accumulation_path]], d_up_op,
        out_d_up_path, gdal.GDT_Float32, _TARGET_NODATA)
Exemplo n.º 8
0
def _calculate_d_up_bare(
        s_bar_path, flow_accumulation_path, out_d_up_bare_path):
    """Calculate s_bar * sqrt(flow accumulation * cell area)."""
    cell_area = pygeoprocessing.get_raster_info(
        s_bar_path)['mean_pixel_size'] ** 2
    flow_accumulation_nodata = pygeoprocessing.get_raster_info(
        flow_accumulation_path)['nodata'][0]

    def d_up_op(s_bar, flow_accumulation):
        """Calculate the bare d_up index.

        s_bar * sqrt(upstream area)

        """
        valid_mask = (
            (flow_accumulation != flow_accumulation_nodata) &
            (s_bar != _TARGET_NODATA))
        d_up_array = numpy.empty(valid_mask.shape, dtype=numpy.float32)
        d_up_array[:] = _TARGET_NODATA
        d_up_array[valid_mask] = (
            numpy.sqrt(flow_accumulation[valid_mask] * cell_area) *
            s_bar[valid_mask])
        return d_up_array

    pygeoprocessing.raster_calculator(
        [(s_bar_path, 1), (flow_accumulation_path, 1)], d_up_op,
        out_d_up_bare_path, gdal.GDT_Float32, _TARGET_NODATA)
Exemplo n.º 9
0
def _calculate_export(surface_load_path, ndr_path, subsurface_load_path,
                      subsurface_ndr_path, target_export_path):
    """Calculate export."""
    load_nodata = pygeoprocessing.get_raster_info(
        surface_load_path)['nodata'][0]
    subsurface_load_nodata = pygeoprocessing.get_raster_info(
        subsurface_load_path)['nodata'][0]
    ndr_nodata = pygeoprocessing.get_raster_info(ndr_path)['nodata'][0]
    sub_ndr_nodata = pygeoprocessing.get_raster_info(
        subsurface_ndr_path)['nodata'][0]

    def _calculate_export_op(modified_load_array, ndr_array,
                             modified_sub_load_array, sub_ndr_array):
        """Combine NDR and subsurface NDR."""
        valid_mask = (
            ~numpy.isclose(modified_load_array, load_nodata)
            & ~numpy.isclose(ndr_array, ndr_nodata)
            & ~numpy.isclose(modified_sub_load_array, subsurface_load_nodata)
            & ~numpy.isclose(sub_ndr_array, sub_ndr_nodata))
        result = numpy.empty(valid_mask.shape, dtype=numpy.float32)
        result[:] = _TARGET_NODATA
        result[valid_mask] = (
            modified_load_array[valid_mask] * ndr_array[valid_mask] +
            modified_sub_load_array[valid_mask] * sub_ndr_array[valid_mask])
        return result

    pygeoprocessing.raster_calculator([(surface_load_path, 1), (ndr_path, 1),
                                       (subsurface_load_path, 1),
                                       (subsurface_ndr_path, 1)],
                                      _calculate_export_op, target_export_path,
                                      gdal.GDT_Float32, _TARGET_NODATA)
Exemplo n.º 10
0
def _calculate_ndr(effective_retention_path, ic_factor_path, k_param,
                   target_ndr_path):
    """Calculate NDR as a function of Equation 4 in the user's guide."""
    ic_factor_raster = gdal.OpenEx(ic_factor_path, gdal.OF_RASTER)
    ic_factor_band = ic_factor_raster.GetRasterBand(1)
    ic_min, ic_max, _, _ = ic_factor_band.GetStatistics(0, 1)
    ic_factor_band = None
    ic_factor_raster = None
    ic_0_param = (ic_min + ic_max) / 2.0
    effective_retention_nodata = pygeoprocessing.get_raster_info(
        effective_retention_path)['nodata'][0]
    ic_nodata = pygeoprocessing.get_raster_info(ic_factor_path)['nodata'][0]

    def _calculate_ndr_op(effective_retention_array, ic_array):
        """Calculate NDR."""
        valid_mask = ((effective_retention_array != effective_retention_nodata)
                      & (ic_array != ic_nodata))
        result = numpy.empty(valid_mask.shape, dtype=numpy.float32)
        result[:] = _TARGET_NODATA
        result[valid_mask] = (
            (1.0 - effective_retention_array[valid_mask]) / (1.0 + numpy.exp(
                (ic_0_param - ic_array[valid_mask]) / k_param)))
        return result

    pygeoprocessing.raster_calculator([(effective_retention_path, 1),
                                       (ic_factor_path, 1)], _calculate_ndr_op,
                                      target_ndr_path, gdal.GDT_Float32,
                                      _TARGET_NODATA)
Exemplo n.º 11
0
def align_predictors(task_graph, lulc_raster_base_path, predictor_list,
                     workspace_dir):
    """Align all the predictors to lulc."""
    lulc_raster_info = pygeoprocessing.get_raster_info(lulc_raster_base_path)
    aligned_dir = os.path.join(workspace_dir, 'aligned')
    os.makedirs(aligned_dir, exist_ok=True)
    aligned_predictor_list = []
    for predictor_raster_path, nodata in predictor_list:
        if nodata is None:
            nodata = pygeoprocessing.get_raster_info(
                predictor_raster_path)['nodata'][0]
        aligned_predictor_raster_path = os.path.join(
            aligned_dir, os.path.basename(predictor_raster_path))
        task_graph.add_task(func=pygeoprocessing.warp_raster,
                            args=(predictor_raster_path,
                                  lulc_raster_info['pixel_size'],
                                  aligned_predictor_raster_path, 'near'),
                            kwargs={
                                'target_bb':
                                lulc_raster_info['bounding_box'],
                                'target_projection_wkt':
                                lulc_raster_info['projection_wkt']
                            },
                            target_path_list=[aligned_predictor_raster_path],
                            task_name=f'align {aligned_predictor_raster_path}')
        aligned_predictor_list.append((aligned_predictor_raster_path, nodata))
    return aligned_predictor_list
Exemplo n.º 12
0
def _validate_inputs(lulc_snapshot_list, lulc_lookup_dict):
    """Validate inputs.

    Args:
        lulc_snapshot_list (list): list of snapshot raster filepaths
        lulc_lookup_dict (dict): lookup table information
    """
    LOGGER.info('Validating inputs...')
    lulc_snapshot_list = lulc_snapshot_list
    lulc_lookup_dict = lulc_lookup_dict

    nodata_values = set([pygeoprocessing.get_raster_info(filepath)['nodata'][0]
                         for filepath in lulc_snapshot_list])
    if len(nodata_values) > 1:
        raise ValueError('Provided rasters have different nodata values')

    # assert all raster values in lookup table
    raster_val_set = set(reduce(
        lambda accum_value, x: numpy.unique(
            numpy.append(accum_value, x.next()[1].flat)),
        itertools.chain(pygeoprocessing.iterblocks((snapshot, 1))
                        for snapshot in lulc_snapshot_list),
        numpy.array([])))

    code_set = set(lulc_lookup_dict.iterkeys())
    code_set.add(
        pygeoprocessing.get_raster_info(lulc_snapshot_list[0])['nodata'][0])

    if raster_val_set.difference(code_set):
        msg = "These raster values are not in the lookup table: %s" % \
            raster_val_set.difference(code_set)
        raise ValueError(msg)
Exemplo n.º 13
0
def _warp_and_wgs84_area_scale(base_raster_path, model_raster_path,
                               target_raster_path, interpolation_alg, clip_bb,
                               watershed_vector_path, watershed_fid,
                               working_dir):
    base_raster_info = pygeoprocessing.get_raster_info(base_raster_path)
    model_raster_info = pygeoprocessing.get_raster_info(model_raster_path)
    clipped_base_path = '%s_clip%s' % os.path.splitext(target_raster_path)
    pygeoprocessing.warp_raster(base_raster_path,
                                base_raster_info['pixel_size'],
                                clipped_base_path,
                                'near',
                                target_bb=clip_bb,
                                vector_mask_options={
                                    'mask_vector_path':
                                    watershed_vector_path,
                                    'mask_vector_where_filter':
                                    f'"FID"={watershed_fid}'
                                },
                                working_dir=working_dir)

    lat_min, lat_max = clip_bb[1], clip_bb[3]
    _, n_rows = pygeoprocessing.get_raster_info(
        clipped_base_path)['raster_size']
    m2_area_per_lat = pygeoprocessing.geoprocessing._create_latitude_m2_area_column(
        lat_min, lat_max, n_rows)

    def _mult_op(base_array, base_nodata, scale, datatype):
        """Scale non-nodata by scale."""
        result = base_array.astype(datatype)
        if base_nodata is not None:
            valid_mask = ~numpy.isclose(base_array, base_nodata)
        else:
            valid_mask = numpy.ones(base_array.shape, dtype=bool)
        result[valid_mask] = result[valid_mask] * scale[valid_mask]
        return result

    scaled_raster_path = os.path.join('%s_scaled%s' %
                                      os.path.splitext(clipped_base_path))
    base_pixel_area_m2 = model_raster_info['pixel_size'][0]**2
    # multiply the pixels in the resampled raster by the ratio of
    # the pixel area in the wgs84 units divided by the area of the
    # original pixel
    base_nodata = base_raster_info['nodata'][0]
    pygeoprocessing.raster_calculator(
        [(clipped_base_path, 1),
         (base_nodata, 'raw'), base_pixel_area_m2 / m2_area_per_lat,
         (numpy.float32, 'raw')], _mult_op, scaled_raster_path,
        gdal.GDT_Float32, base_nodata)

    pygeoprocessing.warp_raster(
        scaled_raster_path,
        model_raster_info['pixel_size'],
        target_raster_path,
        'near',
        target_projection_wkt=model_raster_info['projection_wkt'],
        target_bb=model_raster_info['bounding_box'],
        working_dir=working_dir)
    os.remove(clipped_base_path)
    os.remove(scaled_raster_path)
Exemplo n.º 14
0
def calculate_crop_production(lulc_path, yield_path, crop_lucode,
                              pixel_area_ha, target_path):
    """Calculate crop production for a particular crop.

    The resulting production value is:

    - nodata, where either the LULC or yield input has nodata
    - 0, where the LULC does not match the given LULC code
    - yield * pixel area, where the given LULC code exists

    Args:
        lulc_path (str): path to a raster of LULC codes
        yield_path (str): path of a raster of yields for the crop identified
            by ``crop_lucode``, in units per hectare
        crop_lucode (int): LULC code that identifies the crop of interest in
            the ``lulc_path`` raster.
        pixel_area_ha (number): Pixel area in hectares for both input rasters
        target_path (str): Path to write the output crop production raster

    Returns:
        None
    """

    lulc_nodata = pygeoprocessing.get_raster_info(lulc_path)['nodata'][0]
    yield_nodata = pygeoprocessing.get_raster_info(yield_path)['nodata'][0]

    def _crop_production_op(lulc_array, yield_array):
        """Mask in yields that overlap with `crop_lucode`.

        Args:
            lulc_array (numpy.ndarray): landcover raster values
            yield_array (numpy.ndarray): interpolated yield raster values

        Returns:
            numpy.ndarray with float values of yields for the current crop

        """
        result = numpy.full(lulc_array.shape,
                            _NODATA_YIELD,
                            dtype=numpy.float32)

        valid_mask = numpy.full(lulc_array.shape, True)
        if lulc_nodata is not None:
            valid_mask &= ~utils.array_equals_nodata(lulc_array, lulc_nodata)
        if yield_nodata is not None:
            valid_mask &= ~utils.array_equals_nodata(yield_array, yield_nodata)
        result[valid_mask] = 0

        lulc_mask = lulc_array == crop_lucode
        result[valid_mask & lulc_mask] = (yield_array[valid_mask & lulc_mask] *
                                          pixel_area_ha)
        return result

    pygeoprocessing.raster_calculator([(lulc_path, 1), (yield_path, 1)],
                                      _crop_production_op, target_path,
                                      gdal.GDT_Float32, _NODATA_YIELD),
def same_coverage(raster_a_path, raster_b_path):
    """Return true if raster a and b have same pixels and bounding box."""
    raster_a_info = pygeoprocessing.get_raster_info(raster_a_path)
    raster_b_info = pygeoprocessing.get_raster_info(raster_b_path)
    if raster_a_info['raster_size'] != raster_b_info['raster_size']:
        return False
    if not numpy.isclose(raster_a_info['bounding_box'],
                         raster_b_info['bounding_box']).all():
        return False
    return True
Exemplo n.º 16
0
def lookup_ratios(lulc_path, soil_group_path, ratio_lookup, sorted_lucodes,
                  output_path):
    """Look up retention/percolation ratios from LULC codes and soil groups.

    Args:
        lulc_array (numpy.ndarray): 2D array of LULC codes
        soil_group_array (numpy.ndarray): 2D array with the same shape as
            ``lulc_array``. Values in {1, 2, 3, 4} corresponding to soil
            groups A, B, C, and D.
        ratio_lookup (numpy.ndarray): 2D array where rows correspond to
            sorted LULC codes and the 4 columns correspond to soil groups
            A, B, C, D in order. Shape: (number of lulc codes, 4).
        sorted_lucodes (list[int]): List of LULC codes sorted from smallest
            to largest. These correspond to the rows of ``ratio_lookup``.
        output_path (str): path to a raster to write out the result. has the
            same shape as the lulc and soil group rasters. Each value is the
            corresponding ratio for that LULC code x soil group pair.

    Returns:
        None
    """
    lulc_nodata = pygeoprocessing.get_raster_info(lulc_path)['nodata'][0]
    soil_group_nodata = pygeoprocessing.get_raster_info(
        soil_group_path)['nodata'][0]
    # insert a column on the left side of the array so that the soil
    # group codes 1-4 line up with their indexes. this is faster than
    # decrementing every value in a large raster.
    ratio_lookup = numpy.insert(ratio_lookup,
                                0,
                                numpy.zeros(ratio_lookup.shape[0]),
                                axis=1)

    def ratio_op(lulc_array, soil_group_array):
        output_ratio_array = numpy.full(lulc_array.shape,
                                        FLOAT_NODATA,
                                        dtype=numpy.float32)
        valid_mask = numpy.full(lulc_array.shape, True)
        if lulc_nodata is not None:
            valid_mask &= ~utils.array_equals_nodata(lulc_array, lulc_nodata)
        if soil_group_nodata is not None:
            valid_mask &= ~utils.array_equals_nodata(soil_group_array,
                                                     soil_group_nodata)
        # the index of each lucode in the sorted lucodes array
        lulc_index = numpy.digitize(lulc_array[valid_mask],
                                    sorted_lucodes,
                                    right=True)
        output_ratio_array[valid_mask] = (
            ratio_lookup[lulc_index, soil_group_array[valid_mask]])
        return output_ratio_array

    pygeoprocessing.raster_calculator([(lulc_path, 1), (soil_group_path, 1)],
                                      ratio_op, output_path, gdal.GDT_Float32,
                                      FLOAT_NODATA)
Exemplo n.º 17
0
def mask_by_nodata(base_raster_path, nodata_mask_raster_path,
                   target_raster_path):
    """Set base to nodata wherever mask is nodata."""
    base_raster_info = pygeoprocessing.get_raster_info(base_raster_path)
    nodata_mask_raster_info = pygeoprocessing.get_raster_info(
        nodata_mask_raster_path)
    pygeoprocessing.raster_calculator(
        [(base_raster_path, 1), (nodata_mask_raster_path, 1),
         (nodata_mask_raster_info['nodata'][0], 'raw'),
         (base_raster_info['nodata'][0], 'raw')], _mask_by_nodata_op,
        target_raster_path, base_raster_info['datatype'],
        base_raster_info['nodata'][0])
def mosaic_base_into_target(base_raster_path, target_raster_path,
                            target_token_complete_path):
    """Copy valid parts of base to target w/r/t correct georeference.

    Parameters:
        base_raster_path (str): a raster with the same cell size,
            coordinate system, and nodata as `target_raster_path`.
        target_raster_path (str): a raster that already exists on disk that
            after this call will contain the non-nodata parts of
            `base_raster_path` that geographically overlap with the target.
        target_token_complete_path (str): this file is created if the
            mosaic to target is successful. Useful for taskgraph task
            scheduling.

    Returns:
        None.

    """
    target_raster = gdal.OpenEx(target_raster_path,
                                gdal.OF_RASTER | gdal.GA_Update)
    target_band = target_raster.GetRasterBand(1)
    target_raster_info = pygeoprocessing.get_raster_info(target_raster_path)
    target_nodata = target_raster_info['nodata'][0]
    base_raster_info = pygeoprocessing.get_raster_info(base_raster_path)
    target_gt = target_raster_info['geotransform']
    base_gt = base_raster_info['geotransform']

    target_x_off = int((base_gt[0] - target_gt[0]) / target_gt[1])
    target_y_off = int((base_gt[3] - target_gt[3]) / target_gt[5])

    for offset_dict, band_data in pygeoprocessing.iterblocks(
        (base_raster_path, 1)):
        target_block = target_band.ReadAsArray(
            xoff=offset_dict['xoff'] + target_x_off,
            yoff=offset_dict['yoff'] + target_y_off,
            win_xsize=offset_dict['win_xsize'],
            win_ysize=offset_dict['win_ysize'])
        valid_mask = numpy.isclose(target_block, target_nodata)
        target_block[valid_mask] = band_data[valid_mask]
        target_band.WriteArray(target_block,
                               xoff=offset_dict['xoff'] + target_x_off,
                               yoff=offset_dict['yoff'] + target_y_off)
    target_band.FlushCache()
    target_band = None
    target_raster = None

    with open(target_token_complete_path, 'w') as token_file:
        token_file.write('complete!')
Exemplo n.º 19
0
def max_value_per_pixel(raster_list, target_path):
    """Identify, for each pixel, the maximum value across a list of rasters.

    The maximum value is calculated only for pixels with valid data across each
    raster in `raster_list`.  All rasters in `raster_list` must share nodata
    value.

    Args:
        raster_list (list): a list of paths to rasters containing the same
            quantity over the same area
        target_path (string): path where the result should be stored

    Side effects:
        creates a raster at `target_path` containing the maximum value for each
            pixel across the rasters in `raster_list`

    """
    def max_op(*raster_list):
        """Find the maximum value per pixel across rasters."""
        invalid_mask = numpy.any(numpy.isclose(numpy.array(raster_list),
                                               input_nodata),
                                 axis=0)
        max_val = numpy.amax(raster_list, axis=0)
        max_val[invalid_mask] = input_nodata
        return max_val

    input_nodata = pygeoprocessing.get_raster_info(raster_list[0])['nodata'][0]
    pygeoprocessing.raster_calculator([(path, 1) for path in raster_list],
                                      max_op, target_path, gdal.GDT_Float32,
                                      input_nodata)
Exemplo n.º 20
0
def _sum_valuation_rasters(dem_path, valuation_filepaths, target_path):
    """Sum up all valuation rasters.

    Args:
        dem_path (string): A path to the DEM. Must perfectly overlap all of
            the rasters in ``valuation_filepaths``.
        valuation_filepaths (list of strings): A list of paths to individual
            valuation rasters. All rasters in this list must overlap
            perfectly.
        target_path (string): The path on disk where the output raster will be
            written. If a file exists at this path, it will be overwritten.

    Returns:
        ``None``

    """
    dem_nodata = pygeoprocessing.get_raster_info(dem_path)['nodata'][0]

    def _sum_rasters(dem, *valuation_rasters):
        valid_dem_pixels = ~utils.array_equals_nodata(dem, dem_nodata)
        raster_sum = numpy.empty(dem.shape, dtype=numpy.float64)
        raster_sum[:] = _VALUATION_NODATA
        raster_sum[valid_dem_pixels] = 0

        for valuation_matrix in valuation_rasters:
            valid_pixels = (
                ~utils.array_equals_nodata(valuation_matrix, _VALUATION_NODATA)
                & valid_dem_pixels)
            raster_sum[valid_pixels] += valuation_matrix[valid_pixels]
        return raster_sum

    pygeoprocessing.raster_calculator(
        [(dem_path, 1)] + [(path, 1) for path in valuation_filepaths],
        _sum_rasters, target_path, gdal.GDT_Float64, _VALUATION_NODATA,
        raster_driver_creation_tuple=FLOAT_GTIFF_CREATION_OPTIONS)
def mask_raster_by_array(raster_path_band,
                         mask_array,
                         target_raster_path,
                         invert=False):
    """Mask the given raster path/band by a set of integers.

    Parameters:
        raster_path_band (tuple): a raster path/band indicating the band to
            apply the mask operation.
        mask_array (list/numpy.ndarray): a sequence of integers that will be
            used to set a mask.
        target_raster_path (str): path to output raster which will have 1s
            where the original raster band had a value found in `mask_array`,
            0 if not found, and nodata if originally nodata.
        invert (bool): if true makes a mask of all values in raster band that
            are *not* in `mask_array`.

    Returns:
        None.

    """
    raster_info = pygeoprocessing.get_raster_info(raster_path_band[0])
    pygeoprocessing.raster_calculator([
        raster_path_band,
        (raster_info['nodata'][raster_path_band[1] - 1], 'raw'),
        (numpy.array(mask_array), 'raw'), (2, 'raw'), (invert, 'raw')
    ], _mask_raster_op, target_raster_path, gdal.GDT_Byte, 2)
Exemplo n.º 22
0
    def test_flow_dir_mfd_plateau(self):
        """PGP.routing: MFD on a plateau."""
        dem_path = os.path.join(self.workspace_dir, 'dem.tif')
        # this makes a flat raster
        n = 100
        dem_array = numpy.zeros((n, n))
        dem_nodata = -1
        dem_array[2, :] = 1e-12
        dem_array[n // 2, :] = 1e-12
        dem_array[3 * n // 4, :] = 1e-12

        _array_to_raster(dem_array, dem_nodata, dem_path)

        target_flow_dir_path = os.path.join(self.workspace_dir, 'flow_dir.tif')

        pygeoprocessing.routing.flow_dir_mfd((dem_path, 1),
                                             target_flow_dir_path,
                                             working_dir=self.workspace_dir)

        flow_dir_nodata = pygeoprocessing.get_raster_info(
            target_flow_dir_path)['nodata'][0]

        flow_dir_array = pygeoprocessing.raster_to_numpy_array(
            target_flow_dir_path)

        self.assertTrue(
            not numpy.isclose(flow_dir_array[1:-1, 1:-1],
                              flow_dir_nodata).any(),
            'all flow directions should be defined')
def compress_to(task_graph, base_raster_path, resample_method, target_path):
    gtiff_driver = gdal.GetDriverByName('GTiff')
    base_raster = gdal.OpenEx(base_raster_path, gdal.OF_RASTER)
    LOGGER.info('compress %s to %s' % (base_raster_path, target_path))
    compressed_raster = gtiff_driver.CreateCopy(
        target_path,
        base_raster,
        options=('TILED=YES', 'BIGTIFF=YES', 'COMPRESS=LZW', 'BLOCKXSIZE=256',
                 'BLOCKYSIZE=256'))

    min_dimension = min(
        pygeoprocessing.get_raster_info(target_path)['raster_size'])
    LOGGER.info(f"min min_dimension {min_dimension}")

    overview_levels = []
    current_level = 2
    while True:
        if min_dimension // current_level == 0:
            break
        overview_levels.append(current_level)
        current_level *= 2
    LOGGER.info(f'level list: {overview_levels}')
    compressed_raster.BuildOverviews(
        resample_method,
        overview_levels,
        callback=_make_logger_callback(
            f'build overview for {os.path.basename(target_path)} '
            '%.2f%% complete'))
Exemplo n.º 24
0
def _get_land_cover_transitions(raster_t1_uri, raster_t2_uri):
    """Get land cover transition.

    Args:
        raster_t1_uri (str): filepath to first raster
        raster_t2_uri (str): filepath to second raster

    Returns:
        transition_set (set): a set of all types of transitions
    """
    transition_nodata = pygeoprocessing.get_raster_info(
        raster_t1_uri)['nodata'][0]
    transition_set = set()

    for d, a1 in pygeoprocessing.iterblocks((raster_t1_uri, 1)):
        a2 = read_from_raster(raster_t2_uri, d)
        transition_list = zip(a1.flatten(), a2.flatten())
        transition_set = transition_set.union(set(transition_list))

    # Remove transitions to or from cells with NODATA values
    # There may be times when the user's nodata may not match NODATA_INT
    expected_nodata_values = set([NODATA_INT, transition_nodata])
    s = copy.copy(transition_set)
    for i in s:
        for nodata_value in expected_nodata_values:
            if nodata_value in i:
                transition_set.remove(i)

    return transition_set
def mask_ranges(
        base_raster_path, mask_value_list, inverse, target_raster_path):
    """Mask all values in the given inclusive range to 1, the rest to 0.

    Args:
        base_raster_path (str): path to an integer raster
        mask_value_list (list): lits of integer codes to set output to 1 or 0
            if it is ccontained in the list.
        inverse (bool): if true the inverse of the `mask_value_list` is used
            so that values not in the list are set to 1 and those within are
            set to 0.
        target_raster_path (str): path to output mask, will contain 1 or 0
            whether the base had a pixel value contained in the
            `mask_value_list` while accounting for `inverse`.

    Returns:
        None.

    """
    base_nodata = pygeoprocessing.get_raster_info(
        base_raster_path)['nodata'][0]
    pygeoprocessing.raster_calculator(
        [(base_raster_path, 1), (base_nodata, 'raw'),
         (mask_value_list, 'raw'), (inverse, 'raw'),
         (MASK_NODATA, 'raw')], _mask_vals_op,
        target_raster_path, gdal.GDT_Byte, MASK_NODATA)
Exemplo n.º 26
0
def validate(args, limit_to=None):
    """Validate args to ensure they conform to ``execute``'s contract.

    Args:
        args (dict): dictionary of key(str)/value pairs where keys and
            values are specified in ``execute`` docstring.
        limit_to (str): (optional) if not None indicates that validation
            should only occur on the args[limit_to] value. The intent that
            individual key validation could be significantly less expensive
            than validating the entire ``args`` dictionary.

    Returns:
        list of ([invalid key_a, invalid key_b, ...], 'warning/error message')
            tuples. Where an entry indicates that the invalid keys caused
            the error message in the second part of the tuple. This should
            be an empty list if validation succeeds.
    """
    validation_warnings = validation.validate(args, ARGS_SPEC['args'])

    invalid_keys = validation.get_invalid_keys(validation_warnings)
    sufficient_keys = validation.get_sufficient_keys(args)

    if ('dem_band_index' not in invalid_keys
            and 'dem_band_index' in sufficient_keys
            and 'dem_path' not in invalid_keys
            and 'dem_path' in sufficient_keys):
        raster_info = pygeoprocessing.get_raster_info(args['dem_path'])
        if int(args['dem_band_index']) > raster_info['n_bands']:
            validation_warnings.append(
                (['dem_band_index'],
                 'Must be between 1 and %s' % raster_info['n_bands']))

    return validation_warnings
def compress_to(base_raster_path, resample_method, target_path):
    """Compress base to target using resample method for overviews."""
    gtiff_driver = gdal.GetDriverByName('GTiff')
    base_raster = gdal.OpenEx(base_raster_path, gdal.OF_RASTER)
    LOGGER.info('compress %s to %s' % (base_raster_path, target_path))
    gtiff_driver.CreateCopy(target_path,
                            base_raster,
                            options=('TILED=YES', 'BIGTIFF=YES',
                                     'COMPRESS=LZW', 'BLOCKXSIZE=256',
                                     'BLOCKYSIZE=256'))
    base_raster = None
    min_dimension = min(
        pygeoprocessing.get_raster_info(target_path)['raster_size'])
    LOGGER.info("min min_dimension %s" % min_dimension)
    raster_copy = gdal.OpenEx(target_path, gdal.OF_RASTER)

    overview_levels = []
    current_level = 2
    while True:
        if min_dimension // current_level == 0:
            break
        overview_levels.append(current_level)
        current_level *= 2
    LOGGER.info('level list: %s' % overview_levels)
    gdal.SetConfigOption('COMPRESS_OVERVIEW', 'LZW')
    raster_copy.BuildOverviews(
        resample_method,
        overview_levels,
        callback=_make_logger_callback('build overview for ' +
                                       os.path.basename(target_path) +
                                       '%.2f%% complete'))
Exemplo n.º 28
0
def _generate_carbon_map(lulc_path, carbon_pool_by_type,
                         out_carbon_stock_path):
    """Generate carbon stock raster by mapping LULC values to carbon pools.

    Args:
        lulc_path (string): landcover raster with integer pixels.
        out_carbon_stock_path (string): path to output raster that will have
            pixels with carbon storage values in them with units of Mg*C
        carbon_pool_by_type (dict): a dictionary that maps landcover values
            to carbon storage densities per area (Mg C/Ha).

    Returns:
        None.
    """
    lulc_info = pygeoprocessing.get_raster_info(lulc_path)
    pixel_area = abs(numpy.prod(lulc_info['pixel_size']))
    carbon_stock_by_type = dict([
        (lulcid, stock * pixel_area / 10**4)
        for lulcid, stock in carbon_pool_by_type.items()
    ])

    reclass_error_details = {
        'raster_name': 'LULC',
        'column_name': 'lucode',
        'table_name': 'Carbon Pools'
    }
    utils.reclassify_raster((lulc_path, 1), carbon_stock_by_type,
                            out_carbon_stock_path, gdal.GDT_Float32,
                            _CARBON_NODATA, reclass_error_details)
Exemplo n.º 29
0
def reclassify_nodata(target_path, new_nodata_value):
    """Reclassify the nodata value of a raster to a new value.
    Convert all areas of nodata in the target raster to the new nodata
    value, which must be an integer.
    
    Parameters:
        target_path (string): path to target raster
        new_nodata_value (integer): new value to set as nodata
    Side effects:
        modifies the raster indicated by `target_path`
    
    Returns:
        None
    """
    def reclassify_op(target_raster):
        reclassified_raster = numpy.copy(target_raster)
        reclassify_mask = (target_raster == previous_nodata_value)
        reclassified_raster[reclassify_mask] = new_nodata_value
        return reclassified_raster

    fd, temp_path = tempfile.mkstemp()
    shutil.copyfile(target_path, temp_path)
    previous_raster_info = pygeoprocessing.get_raster_info(target_path)
    previous_nodata_value = previous_raster_info['nodata'][0]
    datatype = previous_raster_info['datatype']

    pygeoprocessing.raster_calculator([(temp_path, 1)], reclassify_op,
                                      target_path, datatype, new_nodata_value)

    # clean up
    os.close(fd)
    os.remove(temp_path)
Exemplo n.º 30
0
def _calculate_si_raster(cn_path, stream_path, si_path):
    """Calculate the S factor of the quickflow equation [1].

    Parameters:
        cn_path (string): path to curve number raster
        stream_path (string): path to a stream raster (0, 1)
        si_path (string): path to output s_i raster

    Returns:
        None
    """
    si_nodata = -1
    cn_nodata = pygeoprocessing.get_raster_info(cn_path)['nodata'][0]

    def si_op(ci_factor, stream_mask):
        """Calculate si factor."""
        valid_mask = (ci_factor != cn_nodata) & (ci_factor > 0)
        si_array = numpy.empty(ci_factor.shape)
        si_array[:] = si_nodata
        # multiply by the stream mask != 1 so we get 0s on the stream and
        # unaffected results everywhere else
        si_array[valid_mask] = (
            (1000.0 / ci_factor[valid_mask] - 10) * (
                stream_mask[valid_mask] != 1))
        return si_array

    pygeoprocessing.raster_calculator(
        [(cn_path, 1), (stream_path, 1)], si_op, si_path, gdal.GDT_Float32,
        si_nodata)