예제 #1
0
def create_gain_year_count_merge(tile_id, pattern, sensit_type, no_upload):

    uu.print_log(
        "Merging loss, gain, no change, and loss/gain pixels into single raster for {}"
        .format(tile_id))

    # start time
    start = datetime.datetime.now()

    # The four rasters from above that are to be merged
    no_change_gain_years = '{}_growth_years_no_change.tif'.format(tile_id)
    loss_only_gain_years = '{}_growth_years_loss_only.tif'.format(tile_id)
    gain_only_gain_years = '{}_growth_years_gain_only.tif'.format(tile_id)
    loss_and_gain_gain_years = '{}_growth_years_loss_and_gain.tif'.format(
        tile_id)

    # Names of the output tiles
    gain_year_count_merged = '{0}_{1}.tif'.format(tile_id, pattern)

    # Opens no change gain year count tile. This should exist for all tiles.
    with rasterio.open(no_change_gain_years) as no_change_gain_years_src:

        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = no_change_gain_years_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = no_change_gain_years_src.block_windows(1)

        # Updates kwargs for the output dataset
        kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

        uu.print_log(
            "   No change tile exists for {} by default".format(tile_id))

        # Opens the other gain year count tiles. They may not exist for all other tiles.
        try:
            loss_only_gain_years_src = rasterio.open(loss_only_gain_years)
            uu.print_log("   Loss only tile found for {}".format(tile_id))
        except:
            uu.print_log("   No loss only tile found for {}".format(tile_id))

        try:
            gain_only_gain_years_src = rasterio.open(gain_only_gain_years)
            uu.print_log("   Gain only tile found for {}".format(tile_id))
        except:
            uu.print_log("   No gain only tile found for {}".format(tile_id))

        try:
            loss_and_gain_gain_years_src = rasterio.open(
                loss_and_gain_gain_years)
            uu.print_log("   Loss and gain tile found for {}".format(tile_id))
        except:
            uu.print_log(
                "   No loss and gain tile found for {}".format(tile_id))

        # Opens the output tile, giving it the arguments of the input tiles
        gain_year_count_merged_dst = rasterio.open(gain_year_count_merged, 'w',
                                                   **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(gain_year_count_merged_dst, sensit_type)
        gain_year_count_merged_dst.update_tags(units='years')
        gain_year_count_merged_dst.update_tags(min_possible_value='0')
        gain_year_count_merged_dst.update_tags(
            max_possible_value=cn.loss_years)
        gain_year_count_merged_dst.update_tags(
            source=
            'Gain years are assigned based on the combination of Hansen loss and gain in each pixel. There are four combinations: neither loss nor gain, loss only, gain only, loss and gain.'
        )
        gain_year_count_merged_dst.update_tags(extent='Full model extent')

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            no_change_gain_years_window = no_change_gain_years_src.read(
                1, window=window)

            try:
                loss_only_gain_years_window = loss_only_gain_years_src.read(
                    1, window=window)
            except:
                loss_only_gain_years_window = np.zeros(
                    (window.height, window.width), dtype='uint8')

            try:
                gain_only_gain_years_window = gain_only_gain_years_src.read(
                    1, window=window)
            except:
                gain_only_gain_years_window = np.zeros(
                    (window.height, window.width), dtype='uint8')

            try:
                loss_and_gain_gain_years_window = loss_and_gain_gain_years_src.read(
                    1, window=window)
            except:
                loss_and_gain_gain_years_window = np.zeros(
                    (window.height, window.width), dtype='uint8')


            gain_year_count_merged_window = loss_only_gain_years_window + gain_only_gain_years_window + \
                                            no_change_gain_years_window + loss_and_gain_gain_years_window

            gain_year_count_merged_dst.write_band(
                1, gain_year_count_merged_window, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, pattern, no_upload)
예제 #2
0
def annual_gain_rate(tile_id, sensit_type, gain_table_dict, stdev_table_dict,
                     output_pattern_list, no_upload):

    # Converts the forest age category decision tree output values to the three age categories--
    # 10000: primary forest; 20000: secondary forest > 20 years; 30000: secondary forest <= 20 years
    # These are five digits so they can easily be added to the four digits of the continent-ecozone code to make unique codes
    # for each continent-ecozone-age combination.
    # The key in the dictionary is the forest age category decision tree endpoints.
    age_dict = {0: 0, 1: 10000, 2: 20000, 3: 30000}

    uu.print_log("Processing:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the forest age category and continent-ecozone tiles
    age_cat = uu.sensit_tile_rename(sensit_type, tile_id,
                                    cn.pattern_age_cat_IPCC)
    cont_eco = uu.sensit_tile_rename(sensit_type, tile_id,
                                     cn.pattern_cont_eco_processed)

    # Names of the output natural forest gain rate tiles (above and belowground)
    AGB_IPCC_default_gain_rate = '{0}_{1}.tif'.format(tile_id,
                                                      output_pattern_list[0])
    BGB_IPCC_default_gain_rate = '{0}_{1}.tif'.format(tile_id,
                                                      output_pattern_list[1])
    AGB_IPCC_default_gain_stdev = '{0}_{1}.tif'.format(tile_id,
                                                       output_pattern_list[2])

    uu.print_log(
        "  Creating IPCC default biomass gain rates and standard deviation for {}"
        .format(tile_id))

    # Opens the input tiles if they exist. kips tile if either input doesn't exist.
    try:
        age_cat_src = rasterio.open(age_cat)
        uu.print_log("   Age category tile found for {}".format(tile_id))
    except:
        return uu.print_log(
            "   No age category tile found for {}. Skipping tile.".format(
                tile_id))

    try:
        cont_eco_src = rasterio.open(cont_eco)
        uu.print_log("   Continent-ecozone tile found for {}".format(tile_id))
    except:
        return uu.print_log(
            "   No continent-ecozone tile found for {}. Skipping tile.".format(
                tile_id))

    # Grabs metadata about the continent ecozone tile, like its location/projection/cellsize
    kwargs = cont_eco_src.meta

    # Grabs the windows of the tile (stripes) to iterate over the entire tif without running out of memory
    windows = cont_eco_src.block_windows(1)

    # Updates kwargs for the output dataset.
    # Need to update data type to float 32 so that it can handle fractional gain rates
    kwargs.update(driver='GTiff',
                  count=1,
                  compress='lzw',
                  nodata=0,
                  dtype='float32')

    # The output files, aboveground and belowground biomass gain rates
    dst_above = rasterio.open(AGB_IPCC_default_gain_rate, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_above, sensit_type)
    dst_above.update_tags(
        units='megagrams aboveground biomass (AGB or dry matter)/ha/yr')
    dst_above.update_tags(
        source='IPCC Guidelines 2019 refinement, forest section, Table 4.9')
    dst_above.update_tags(
        extent=
        'Full model extent, even though these rates will not be used over the full model extent'
    )

    dst_below = rasterio.open(BGB_IPCC_default_gain_rate, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_below, sensit_type)
    dst_below.update_tags(
        units='megagrams belowground biomass (AGB or dry matter)/ha/yr')
    dst_below.update_tags(
        source='IPCC Guidelines 2019 refinement, forest section, Table 4.9')
    dst_below.update_tags(
        extent=
        'Full model extent, even though these rates will not be used over the full model extent'
    )

    dst_stdev_above = rasterio.open(AGB_IPCC_default_gain_stdev, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_stdev_above, sensit_type)
    dst_stdev_above.update_tags(
        units=
        'standard deviation, in terms of megagrams aboveground biomass (AGB or dry matter)/ha/yr'
    )
    dst_stdev_above.update_tags(
        source='IPCC Guidelines 2019 refinement, forest section, Table 4.9')
    dst_stdev_above.update_tags(
        extent=
        'Full model extent, even though these standard deviations will not be used over the full model extent'
    )

    # Iterates across the windows (1 pixel strips) of the input tiles
    for idx, window in windows:

        # Creates a processing window for each input raster
        try:
            cont_eco_window = cont_eco_src.read(1, window=window)
        except:
            cont_eco_window = np.zeros((window.height, window.width),
                                       dtype='uint8')

        try:
            age_cat_window = age_cat_src.read(1, window=window)
        except:
            age_cat_window = np.zeros((window.height, window.width),
                                      dtype='uint8')

        # Recodes the input forest age category array with 10 different decision tree end values into the 3 actual age categories
        age_recode = np.vectorize(age_dict.get)(age_cat_window)

        # Adds the age category codes to the continent-ecozone codes to create an array of unique continent-ecozone-age codes
        cont_eco_age = cont_eco_window + age_recode

        ## Aboveground removal factors
        # Converts the continent-ecozone array to float so that the values can be replaced with fractional gain rates
        gain_rate_AGB = cont_eco_age.astype('float32')

        # Applies the dictionary of continent-ecozone-age gain rates to the continent-ecozone-age array to
        # get annual gain rates (metric tons aboveground biomass/yr) for each pixel
        for key, value in gain_table_dict.items():
            gain_rate_AGB[gain_rate_AGB == key] = value

        # Writes the output window to the output file
        dst_above.write_band(1, gain_rate_AGB, window=window)

        ## Belowground removal factors
        # Calculates belowground annual removal rates
        gain_rate_BGB = gain_rate_AGB * cn.below_to_above_non_mang

        # Writes the output window to the output file
        dst_below.write_band(1, gain_rate_BGB, window=window)

        ## Aboveground removal factor standard deviation
        # Converts the continent-ecozone array to float so that the values can be replaced with fractional standard deviations
        gain_stdev_AGB = cont_eco_age.astype('float32')

        # Applies the dictionary of continent-ecozone-age gain rate standard deviations to the continent-ecozone-age array to
        # get annual gain rate standard deviations (metric tons aboveground biomass/yr) for each pixel
        for key, value in stdev_table_dict.items():
            gain_stdev_AGB[gain_stdev_AGB == key] = value

        # Writes the output window to the output file
        dst_stdev_above.write_band(1, gain_stdev_AGB, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, output_pattern_list[0], no_upload)
def hansen_burnyear(tile_id, no_upload):

    # Start time
    start = datetime.datetime.now()

    uu.print_log("Processing", tile_id)

    # The tiles that are used. out_tile_no_tag is the output before metadata tags are added. out_tile is the output
    # once metadata tags have been added.
    out_tile_no_tag = '{0}_{1}_no_tag.tif'.format(tile_id,
                                                  cn.pattern_burn_year)
    out_tile = '{0}_{1}.tif'.format(tile_id, cn.pattern_burn_year)
    loss = '{0}.tif'.format(tile_id)

    # Does not continue processing tile if no loss (because there will not be any output)
    if not os.path.exists(loss):
        uu.print_log("No loss tile for", tile_id)
        return
    else:
        uu.print_log("Loss tile exists for", tile_id)

    # Downloads the burned area tiles for each year
    include = 'ba_*_{}.tif'.format(tile_id)
    burn_tiles_dir = 'burn_tiles'
    if not os.path.exists(burn_tiles_dir):
        os.mkdir(burn_tiles_dir)
    cmd = [
        'aws', 's3', 'cp', cn.burn_year_warped_to_Hansen_dir, burn_tiles_dir,
        '--recursive', '--exclude', "*", '--include', include
    ]
    uu.log_subprocess_output_full(cmd)

    # For each year tile, converts to array and stacks them
    array_list = []
    ba_tifs = glob.glob(burn_tiles_dir + '/*{}*'.format(tile_id))

    # Skips the tile if it has no burned area data for any year
    uu.print_log("There are {0} tiles to stack for {1}".format(
        len(ba_tifs), tile_id))
    if len(ba_tifs) == 0:
        uu.print_log(
            "Skipping {} because there are no tiles to stack".format(tile_id))
        return

    # NOTE: All of this could pretty easily be done in rasterio. However, Sam's use of GDAL for this still works fine,
    # so I've left it using GDAL.

    for ba_tif in ba_tifs:
        uu.print_log("Creating array with {}".format(ba_tif))
        array = utilities.raster_to_array(ba_tif)
        array_list.append(array)

    # Stacks arrays from each year
    uu.print_log("Stacking arrays for", tile_id)
    stacked_year_array = utilities.stack_arrays(array_list)

    # Converts Hansen tile to array
    uu.print_log("Creating loss year array for", tile_id)
    loss_array = utilities.raster_to_array(loss)

    # Determines what year to assign burned area
    lossarray_min1 = np.subtract(loss_array, 1)

    stack_con = (stacked_year_array >= lossarray_min1) & (stacked_year_array <=
                                                          loss_array)
    stack_con2 = stack_con * stacked_year_array
    lossyear_burn_array = stack_con2.max(0)

    utilities.array_to_raster_simple(lossyear_burn_array, out_tile_no_tag,
                                     loss)

    # Only copies to s3 if the tile has data
    uu.print_log("Checking if {} contains any data...".format(tile_id))
    empty = uu.check_for_data(out_tile_no_tag)

    # Checks output for data. There could be burned area but none of it coincides with tree cover loss,
    # so this is the final check for whether there is any data.
    if empty:
        uu.print_log("  No data found. Not copying {}.".format(tile_id))

        # Without this, the untagged version is counted and eventually copied to s3 if it has data in it
        os.remove(out_tile_no_tag)

        return

    else:
        uu.print_log(
            "  Data found in {}. Adding metadata tags...".format(tile_id))

        ### Thomas suggested these on 8/19/2020 but they didn't work. The first one wrote the tags but erased all the
        ### data in the tiles (everything became 0 according to gdalinfo). The second one had some other error.
        # with rasterio.open(out_tile_no_tag, 'r') as src:
        #
        #     profile = src.profile
        #
        # with rasterio.open(out_tile_no_tag, 'w', **profile) as dst:
        #
        #     dst.update_tags(units='year (2001, 2002, 2003...)',
        #                     source='MODIS collection 6 burned area',
        #                     extent='global')
        #
        # with rasterio.open(out_tile_no_tag, 'w+') as src:
        #
        #     dst.update_tags(units='year (2001, 2002, 2003...)',
        #                     source='MODIS collection 6 burned area',
        #                     extent='global')

        # All of the below is to add metadata tags to the output burn year masks.
        # For some reason, just doing what's at https://rasterio.readthedocs.io/en/latest/topics/tags.html
        # results in the data getting removed.
        # I found it necessary to copy the desired output and read its windows into a new copy of the file, to which the
        # metadata tags are added. I'm sure there's an easier way to do this but I couldn't figure out how.
        # I know it's very convoluted but I really couldn't figure out how to add the tags without erasing the data.

        copyfile(out_tile_no_tag, out_tile)

        with rasterio.open(out_tile_no_tag) as out_tile_no_tag_src:

            # Grabs metadata about the tif, like its location/projection/cellsize
            kwargs = out_tile_no_tag_src.meta  #### Use profile instead

            # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
            windows = out_tile_no_tag_src.block_windows(1)

            # Updates kwargs for the output dataset
            kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

            out_tile_tagged = rasterio.open(out_tile, 'w', **kwargs)

            # Adds metadata tags to the output raster
            uu.add_rasterio_tags(out_tile_tagged, 'std')
            out_tile_tagged.update_tags(units='year (2001, 2002, 2003...)')
            out_tile_tagged.update_tags(
                source=
                'MODIS collection 6 burned area, https://modis-fire.umd.edu/files/MODIS_C6_BA_User_Guide_1.3.pdf'
            )
            out_tile_tagged.update_tags(extent='global')

            # Iterates across the windows (1 pixel strips) of the input tile
            for idx, window in windows:
                in_window = out_tile_no_tag_src.read(1, window=window)

                # Writes the output window to the output
                out_tile_tagged.write_band(1, in_window, window=window)

        # Without this, the untagged version is counted and eventually copied to s3 if it has data in it
        os.remove(out_tile_no_tag)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, cn.pattern_burn_year, no_upload)
def create_supplementary_outputs(tile_id, input_pattern, output_patterns,
                                 sensit_type):

    # start time
    start = datetime.datetime.now()

    # Extracts the tile id, tile type, and bounding box for the tile
    tile_id = uu.get_tile_id(tile_id)

    # Names of inputs
    focal_tile = '{0}_{1}.tif'.format(tile_id, input_pattern)
    pixel_area = '{0}_{1}.tif'.format(cn.pattern_pixel_area, tile_id)
    tcd = '{0}_{1}.tif'.format(cn.pattern_tcd, tile_id)
    gain = '{0}_{1}.tif'.format(cn.pattern_gain, tile_id)
    mangrove = '{0}_{1}.tif'.format(tile_id, cn.pattern_mangrove_biomass_2000)

    # Names of outputs.
    # Requires that output patterns be listed in main script in the correct order for here
    # (currently, per pixel full extent, per hectare forest extent, per pixel forest extent).
    per_pixel_full_extent = '{0}_{1}.tif'.format(tile_id, output_patterns[0])
    per_hectare_forest_extent = '{0}_{1}.tif'.format(tile_id,
                                                     output_patterns[1])
    per_pixel_forest_extent = '{0}_{1}.tif'.format(tile_id, output_patterns[2])

    # Opens input tiles for rasterio
    in_src = rasterio.open(focal_tile)
    # Grabs metadata about the tif, like its location/projection/cellsize
    kwargs = in_src.meta
    # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
    windows = in_src.block_windows(1)

    pixel_area_src = rasterio.open(pixel_area)
    tcd_src = rasterio.open(tcd)
    gain_src = rasterio.open(gain)

    try:
        mangrove_src = rasterio.open(mangrove)
        uu.print_log("    Mangrove tile found for {}".format(tile_id))
    except:
        uu.print_log("    No mangrove tile found for {}".format(tile_id))

    uu.print_log("  Creating outputs for {}...".format(focal_tile))

    kwargs.update(driver='GTiff',
                  count=1,
                  compress='lzw',
                  nodata=0,
                  dtype='float32')

    # Opens output tiles, giving them the arguments of the input tiles
    per_pixel_full_extent_dst = rasterio.open(per_pixel_full_extent, 'w',
                                              **kwargs)
    per_hectare_forest_extent_dst = rasterio.open(per_hectare_forest_extent,
                                                  'w', **kwargs)
    per_pixel_forest_extent_dst = rasterio.open(per_pixel_forest_extent, 'w',
                                                **kwargs)

    # Adds metadata tags to the output rasters

    uu.add_rasterio_tags(per_pixel_full_extent_dst, sensit_type)
    per_pixel_full_extent_dst.update_tags(
        units='Mg CO2e/pixel over model duration (2001-20{})'.format(
            cn.loss_years))
    per_pixel_full_extent_dst.update_tags(
        source='per hectare full model extent tile')
    per_pixel_full_extent_dst.update_tags(
        extent=
        'Full model extent: ((TCD2000>0 AND WHRC AGB2000>0) OR Hansen gain=1 OR mangrove AGB2000>0) NOT IN pre-2000 plantations'
    )

    uu.add_rasterio_tags(per_hectare_forest_extent_dst, sensit_type)
    per_hectare_forest_extent_dst.update_tags(
        units='Mg CO2e/hectare over model duration (2001-20{})'.format(
            cn.loss_years))
    per_hectare_forest_extent_dst.update_tags(
        source='per hectare full model extent tile')
    per_hectare_forest_extent_dst.update_tags(
        extent=
        'Forest extent: ((TCD2000>30 AND WHRC AGB2000>0) OR Hansen gain=1 OR mangrove AGB2000>0) NOT IN pre-2000 plantations'
    )

    uu.add_rasterio_tags(per_pixel_forest_extent_dst, sensit_type)
    per_pixel_forest_extent_dst.update_tags(
        units='Mg CO2e/pixel over model duration (2001-20{})'.format(
            cn.loss_years))
    per_pixel_forest_extent_dst.update_tags(
        source='per hectare forest model extent tile')
    per_pixel_forest_extent_dst.update_tags(
        extent=
        'Forest extent: ((TCD2000>30 AND WHRC AGB2000>0) OR Hansen gain=1 OR mangrove AGB2000>0) NOT IN pre-2000 plantations'
    )

    if "net_flux" in focal_tile:
        per_pixel_full_extent_dst.update_tags(
            scale=
            'Negative values are net sinks. Positive values are net sources.')
        per_hectare_forest_extent_dst.update_tags(
            scale=
            'Negative values are net sinks. Positive values are net sources.')
        per_pixel_forest_extent_dst.update_tags(
            scale=
            'Negative values are net sinks. Positive values are net sources.')

    # Iterates across the windows of the input tiles
    for idx, window in windows:

        # Creates windows for each input tile
        in_window = in_src.read(1, window=window)
        pixel_area_window = pixel_area_src.read(1, window=window)
        tcd_window = tcd_src.read(1, window=window)
        gain_window = gain_src.read(1, window=window)

        try:
            mangrove_window = mangrove_src.read(1, window=window)
        except:
            mangrove_window = np.zeros((window.height, window.width),
                                       dtype='uint8')

        # Output window for per pixel full extent raster
        dst_window_per_pixel_full_extent = in_window * pixel_area_window / cn.m2_per_ha

        # Output window for per hectare forest extent raster
        # QCed this line before publication and then again afterwards in response to question from Lena Schulte-Uebbing at Wageningen Uni.
        dst_window_per_hectare_forest_extent = np.where(
            (tcd_window > cn.canopy_threshold) | (gain_window == 1) |
            (mangrove_window != 0), in_window, 0)

        # Output window for per pixel forest extent raster
        dst_window_per_pixel_forest_extent = dst_window_per_hectare_forest_extent * pixel_area_window / cn.m2_per_ha

        # Writes arrays to output raster
        per_pixel_full_extent_dst.write_band(1,
                                             dst_window_per_pixel_full_extent,
                                             window=window)
        per_hectare_forest_extent_dst.write_band(
            1, dst_window_per_hectare_forest_extent, window=window)
        per_pixel_forest_extent_dst.write_band(
            1, dst_window_per_pixel_forest_extent, window=window)

    uu.print_log("  Output tiles created for {}...".format(tile_id))

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, output_patterns[0])
예제 #5
0
def net_calc(tile_id, pattern, sensit_type):

    uu.print_log("Calculating net flux for", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the gain and emissions tiles
    removals_in = uu.sensit_tile_rename(sensit_type, tile_id, cn.pattern_cumul_gain_AGCO2_BGCO2_all_types)
    emissions_in = uu.sensit_tile_rename(sensit_type, tile_id, cn.pattern_gross_emis_all_gases_all_drivers_biomass_soil)

    # Output net emissions file
    net_flux = '{0}_{1}.tif'.format(tile_id, pattern)

    try:
        removals_src = rasterio.open(removals_in)
        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = removals_src.meta
        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = removals_src.block_windows(1)
        uu.print_log("   Gross removals tile {} found".format(removals_in))
    except:
        uu.print_log("   No gross removals tile {} found".format(removals_in))

    try:
        emissions_src = rasterio.open(emissions_in)
        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = emissions_src.meta
        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = emissions_src.block_windows(1)
        uu.print_log("   Gross emissions tile {} found".format(emissions_in))
    except:
        uu.print_log("   No gross emissions tile {} found".format(emissions_in))

    # Skips the tile if there is neither a gross emissions nor a gross removals tile.
    # This should only occur for biomass_swap sensitivity analysis, which gets its net flux tile list from
    # the JPL tile list (some tiles of which have neither emissions nor removals), rather than the union of
    # emissions and removals tiles.
    try:
        kwargs.update(
            driver='GTiff',
            count=1,
            compress='lzw',
            nodata=0,
            dtype='float32'
        )
    except:
        uu.print_log("No gross emissions or gross removals for {}. Skipping tile.".format(tile_id))
        return

    # Opens the output tile, giving it the arguments of the input tiles
    net_flux_dst = rasterio.open(net_flux, 'w', **kwargs)

    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(net_flux_dst, sensit_type)
    net_flux_dst.update_tags(
        units='Mg CO2e/ha over model duration (2001-20{})'.format(cn.loss_years))
    net_flux_dst.update_tags(
        source='Gross emissions - gross removals')
    net_flux_dst.update_tags(
        extent='Model extent')
    net_flux_dst.update_tags(
        scale='Negative values are net sinks. Positive values are net sources.')

    # Iterates across the windows (1 pixel strips) of the input tile
    for idx, window in windows:

        # Creates windows for each input tile
        try:
            removals_window = removals_src.read(1, window=window).astype('float32')
        except:
            removals_window = np.zeros((window.height, window.width)).astype('float32')
        try:
            emissions_window = emissions_src.read(1, window=window).astype('float32')
        except:
            emissions_window = np.zeros((window.height, window.width)).astype('float32')

        # Subtracts gain that from loss
        dst_data = emissions_window - removals_window

        net_flux_dst.write_band(1, dst_data, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, pattern)
예제 #6
0
def model_extent(tile_id, pattern, sensit_type):

    # I don't know why, but this needs to be here and not just in mp_model_extent
    os.chdir(cn.docker_base_dir)

    uu.print_log("Delineating model extent:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the input tiles
    mangrove = '{0}_{1}.tif'.format(tile_id, cn.pattern_mangrove_biomass_2000)
    gain = '{0}_{1}.tif'.format(cn.pattern_gain, tile_id)
    pre_2000_plantations = '{0}_{1}.tif'.format(tile_id,
                                                cn.pattern_plant_pre_2000)

    # Tree cover tile name depends on the sensitivity analysis.
    # PRODES extent 2000 stands in for Hansen TCD
    if sensit_type == 'legal_Amazon_loss':
        tcd = '{0}_{1}.tif'.format(
            tile_id, cn.pattern_Brazil_forest_extent_2000_processed)
        uu.print_log(
            "Using PRODES extent 2000 tile {0} for {1} sensitivity analysis".
            format(tile_id, sensit_type))
    else:
        tcd = '{0}_{1}.tif'.format(cn.pattern_tcd, tile_id)
        uu.print_log("Using Hansen tcd tile {0} for {1} model run".format(
            tile_id, sensit_type))

    # Biomass tile name depends on the sensitivity analysis
    if sensit_type == 'biomass_swap':
        biomass = '{0}_{1}.tif'.format(tile_id,
                                       cn.pattern_JPL_unmasked_processed)
        uu.print_log(
            "Using JPL biomass tile {0} for {1} sensitivity analysis".format(
                tile_id, sensit_type))
    else:
        biomass = '{0}_{1}.tif'.format(tile_id,
                                       cn.pattern_WHRC_biomass_2000_unmasked)
        uu.print_log("Using WHRC biomass tile {0} for {1} model run".format(
            tile_id, sensit_type))

    out_tile = '{0}_{1}.tif'.format(tile_id, pattern)

    # Opens biomass tile
    with rasterio.open(tcd) as tcd_src:

        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = tcd_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = tcd_src.block_windows(1)

        # Updates kwargs for the output dataset
        kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

        # Checks whether each input tile exists
        try:
            mangroves_src = rasterio.open(mangrove)
            uu.print_log("  Mangrove tile found for {}".format(tile_id))
        except:
            uu.print_log("  No mangrove tile found for {}".format(tile_id))

        try:
            gain_src = rasterio.open(gain)
            uu.print_log("  Gain tile found for {}".format(tile_id))
        except:
            uu.print_log("  No gain tile found for {}".format(tile_id))

        try:
            biomass_src = rasterio.open(biomass)
            uu.print_log("  Biomass tile found for {}".format(tile_id))
        except:
            uu.print_log("  No biomass tile found for {}".format(tile_id))

        try:
            pre_2000_plantations_src = rasterio.open(pre_2000_plantations)
            uu.print_log(
                "  Pre-2000 plantation tile found for {}".format(tile_id))
        except:
            uu.print_log(
                "  No pre-2000 plantation tile found for {}".format(tile_id))

        # Opens the output tile, giving it the metadata of the input tiles
        dst = rasterio.open(out_tile, 'w', **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(dst, sensit_type)
        dst.update_tags(
            units='unitless. 1 = in model extent. 0 = not in model extent')
        if sensit_type == 'biomass_swap':
            dst.update_tags(
                source=
                'Pixels with ((Hansen 2000 tree cover AND NASA JPL AGB2000) OR Hansen gain OR mangrove biomass 2000) NOT pre-2000 plantations'
            )
        else:
            dst.update_tags(
                source=
                'Pixels with ((Hansen 2000 tree cover AND WHRC AGB2000) OR Hansen gain OR mangrove biomass 2000) NOT pre-2000 plantations'
            )
        dst.update_tags(
            extent=
            'Full model extent. This defines which pixels are included in the model.'
        )

        uu.print_log("  Creating model extent for {}".format(tile_id))

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            # Tries to create a window (array) for each input tile.
            # If the tile does exist, it creates an array of the values in the window
            # If the tile does not exist, it creates an array of 0s.
            try:
                mangrove_window = mangroves_src.read(
                    1, window=window).astype('uint8')
            except:
                mangrove_window = np.zeros((window.height, window.width),
                                           dtype=int)
            try:
                gain_window = gain_src.read(1, window=window)
            except:
                gain_window = np.zeros((window.height, window.width),
                                       dtype=int)
            try:
                biomass_window = biomass_src.read(1, window=window)
            except:
                biomass_window = np.zeros((window.height, window.width),
                                          dtype=int)
            try:
                tcd_window = tcd_src.read(1, window=window)
            except:
                tcd_window = np.zeros((window.height, window.width), dtype=int)
            try:
                pre_2000_plantations_window = pre_2000_plantations_src.read(
                    1, window=window)
            except:
                pre_2000_plantations_window = np.zeros(
                    (window.height, window.width), dtype=int)

            # Array of pixels that have both biomass and tree cover density
            tcd_with_biomass_window = np.where(
                (biomass_window > 0) & (tcd_window > 0), 1, 0)

            # For all moel types except legal_Amazon_loss sensitivity analysis
            if sensit_type != 'legal_Amazon_loss':

                # Array of pixels with (biomass AND tcd) OR mangrove biomass OR Hansen gain
                forest_extent = np.where(
                    (tcd_with_biomass_window == 1) | (mangrove_window > 1) |
                    (gain_window == 1), 1, 0)

                # extent now WITHOUT pre-2000 plantations
                forest_extent = np.where(
                    (forest_extent == 1) & (pre_2000_plantations_window == 0),
                    1, 0).astype('uint8')

            # For legal_Amazon_loss sensitivity analysis
            else:
                # Array of pixels with (biomass AND tcd) OR mangrove biomass.
                # Does not include mangrove or Hansen gain pixels that are outside PRODES 2000 forest extent
                forest_extent = tcd_with_biomass_window.astype('uint8')

            # Writes the output window to the output
            dst.write_band(1, forest_extent, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, pattern)
예제 #7
0
def annual_gain_rate(tile_id, sensit_type, output_pattern_list,
                     gain_above_dict, gain_below_dict, stdev_dict):

    uu.print_log("Processing:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # This is only needed for testing, when a list of tiles might include ones without mangroves.
    # When the full model is being run, only tiles with mangroves are included.
    mangrove_biomass_tile_list = uu.tile_list_s3(cn.mangrove_biomass_2000_dir)
    if tile_id not in mangrove_biomass_tile_list:
        uu.print_log(
            "{} does not contain mangroves. Skipping tile.".format(tile_id))
        return

    # Name of the input files
    mangrove_biomass = uu.sensit_tile_rename(sensit_type, tile_id,
                                             cn.pattern_mangrove_biomass_2000)
    cont_eco = uu.sensit_tile_rename(sensit_type, tile_id,
                                     cn.pattern_cont_eco_processed)

    # Names of the output aboveground and belowground mangrove gain rate tiles
    AGB_gain_rate = '{0}_{1}.tif'.format(tile_id, output_pattern_list[0])
    BGB_gain_rate = '{0}_{1}.tif'.format(tile_id, output_pattern_list[1])
    AGB_gain_stdev = '{0}_{1}.tif'.format(tile_id, output_pattern_list[2])

    uu.print_log(
        "  Reading input files and creating aboveground and belowground biomass gain rates for {}"
        .format(tile_id))

    cont_eco_src = rasterio.open(cont_eco)
    mangrove_AGB_src = rasterio.open(mangrove_biomass)

    # Grabs metadata about the tif, like its location/projection/cellsize
    kwargs = cont_eco_src.meta

    # Grabs the windows of the tile (stripes) to iterate over the entire tif without running out of memory
    windows = cont_eco_src.block_windows(1)

    # Updates kwargs for the output dataset.
    # Need to update data type to float 32 so that it can handle fractional gain rates
    kwargs.update(driver='GTiff',
                  count=1,
                  compress='lzw',
                  nodata=0,
                  dtype='float32')

    dst_above = rasterio.open(AGB_gain_rate, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_above, sensit_type)
    dst_above.update_tags(
        units='megagrams aboveground biomass (AGB or dry matter)/ha/yr')
    dst_above.update_tags(
        source='IPCC Guidelines, 2013 Coastal Wetlands Supplement, Table 4.4')
    dst_above.update_tags(
        extent=
        'Simard et al. 2018, based on Giri et al. 2011 (Global Ecol. Biogeogr.) mangrove extent'
    )

    dst_below = rasterio.open(BGB_gain_rate, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_below, sensit_type)
    dst_below.update_tags(
        units='megagrams belowground biomass (BGB or dry matter)/ha/yr')
    dst_below.update_tags(
        source='IPCC Guidelines, 2013 Coastal Wetlands Supplement, Table 4.4')
    dst_below.update_tags(
        extent=
        'Simard et al. 2018, based on Giri et al. 2011 (Global Ecol. Biogeogr.) mangrove extent'
    )

    dst_stdev_above = rasterio.open(AGB_gain_stdev, 'w', **kwargs)
    # Adds metadata tags to the output raster
    uu.add_rasterio_tags(dst_stdev_above, sensit_type)
    dst_stdev_above.update_tags(
        units=
        'standard deviation, in terms of megagrams aboveground biomass (AGB or dry matter)/ha/yr'
    )
    dst_stdev_above.update_tags(
        source='IPCC Guidelines, 2013 Coastal Wetlands Supplement, Table 4.4')
    dst_stdev_above.update_tags(
        extent=
        'Simard et al. 2018, based on Giri et al. 2011 (Global Ecol. Biogeogr.) mangrove extent'
    )

    # Iterates across the windows (1 pixel strips) of the input tile
    for idx, window in windows:

        # Creates windows for each input raster
        cont_eco = cont_eco_src.read(1, window=window)
        mangrove_AGB = mangrove_AGB_src.read(1, window=window)

        # Converts the continent-ecozone array to float so that the values can be replaced with fractional gain rates.
        # Creates two copies: one for aboveground gain and one for belowground gain.
        # Creating only one copy of the cont_eco raster made it so that belowground gain rates weren't being
        # written correctly for some reason.
        cont_eco_above = cont_eco.astype('float32')
        cont_eco_below = cont_eco.astype('float32')
        cont_eco_stdev = cont_eco.astype('float32')

        # Reclassifies mangrove biomass to 1 or 0 to make a mask of mangrove pixels.
        # Ultimately, only these pixels (ones with mangrove biomass) will get values.
        mangrove_AGB[mangrove_AGB > 0] = 1

        # Applies the dictionary of continent-ecozone aboveground gain rates to the continent-ecozone array to
        # get annual aboveground gain rates (metric tons aboveground biomass/yr) for each pixel
        for key, value in gain_above_dict.items():
            cont_eco_above[cont_eco_above == key] = value

        # Masks out pixels without mangroves, leaving gain rates in only pixels with mangroves
        dst_above_data = cont_eco_above * mangrove_AGB

        # Writes the output window to the output
        dst_above.write_band(1, dst_above_data, window=window)

        # Same as above but for belowground gain rates
        for key, value in gain_below_dict.items():
            cont_eco_below[cont_eco_below == key] = value

        dst_below_data = cont_eco_below * mangrove_AGB

        dst_below.write_band(1, dst_below_data, window=window)

        # Applies the dictionary of continent-ecozone aboveground gain rate standard deviations to the continent-ecozone array to
        # get annual aboveground gain rate standard deviations (metric tons aboveground biomass/yr) for each pixel
        for key, value in stdev_dict.items():
            cont_eco_stdev[cont_eco_stdev == key] = value

        # Masks out pixels without mangroves, leaving gain rates in only pixels with mangroves
        dst_stdev = cont_eco_stdev * mangrove_AGB

        # Writes the output window to the output
        dst_stdev_above.write_band(1, dst_stdev, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, output_pattern_list[0])
예제 #8
0
def create_peat_mask_tiles(tile_id):

    # Start time
    start = datetime.datetime.now()

    uu.print_log("Getting bounding coordinates for tile", tile_id)
    xmin, ymin, xmax, ymax = uu.coords(tile_id)
    uu.print_log("  ymax:", ymax, "; ymin:", ymin, "; xmax", xmax, "; xmin:",
                 xmin)

    out_tile_no_tag = '{0}_{1}_no_tag.tif'.format(tile_id,
                                                  cn.pattern_peat_mask)
    out_tile = '{0}_{1}.tif'.format(tile_id, cn.pattern_peat_mask)

    # If the tile is outside the band covered by the CIFOR peat raster, SoilGrids250m is used
    if ymax > 40 or ymax < -60:

        uu.print_log(
            "{} is outside CIFOR band. Using SoilGrids250m organic soil mask..."
            .format(tile_id))

        out_intermediate = '{0}_intermediate.tif'.format(
            tile_id, cn.pattern_peat_mask)

        # Cuts the SoilGrids250m global raster to the focal tile
        uu.warp_to_Hansen('most_likely_soil_class.vrt', out_intermediate, xmin,
                          ymin, xmax, ymax, 'Byte')

        # Removes all non-histosol sub-groups from the SoilGrids raster.
        # Ideally, this would be done once on the entire SoilGrids raster in the main function but I didn't think of that.
        # Code 14 is the histosol subgroup in SoilGrids250 (https://files.isric.org/soilgrids/latest/data/wrb/MostProbable.qml).
        calc = '--calc=(A==14)'
        peat_mask_out_filearg = '--outfile={}'.format(out_tile_no_tag)
        cmd = [
            'gdal_calc.py', '-A', out_intermediate, calc,
            peat_mask_out_filearg, '--NoDataValue=0', '--overwrite', '--co',
            'COMPRESS=LZW', '--type=Byte', '--quiet'
        ]
        uu.log_subprocess_output_full(cmd)

        uu.print_log("{} created.".format(tile_id))

    # If the tile is inside the band covered by CIFOR, CIFOR is used (and Jukka in the tiles where it occurs).
    # For some reason, the CIFOR raster has a color scheme that makes it symbolized from 0 to 255. This carries
    # over to the output file but that seems like a problem with the output symbology, not the values.
    # gdalinfo shows that the min and max values are 1, as they should be, and it visualizes correctly in ArcMap.
    else:

        uu.print_log(
            "{} is inside CIFOR band. Using CIFOR/Jukka combination...".format(
                tile_id))

        # Combines CIFOR and Jukka (if it occurs there)
        cmd = [
            'gdalwarp', '-t_srs', 'EPSG:4326', '-co', 'COMPRESS=LZW', '-tr',
            '{}'.format(cn.Hansen_res), '{}'.format(cn.Hansen_res), '-tap',
            '-te',
            str(xmin),
            str(ymin),
            str(xmax),
            str(ymax), '-dstnodata', '0', '-overwrite',
            '{}'.format(cn.cifor_peat_file), 'jukka_peat.tif', out_tile_no_tag
        ]
        uu.log_subprocess_output_full(cmd)

        uu.print_log("{} created.".format(tile_id))

    # All of the below is to add metadata tags to the output peat masks.
    # For some reason, just doing what's at https://rasterio.readthedocs.io/en/latest/topics/tags.html
    # results in the data getting removed.
    # I found it necessary to copy the peat mask and read its windows into a new copy of the file, to which the
    # metadata tags are added. I'm sure there's an easier way to do this but I couldn't figure out how.
    # I know it's very convoluted but I really couldn't figure out how to add the tags without erasing the data.
    # To make it even stranger, adding the tags before the gdal processing seemed to work fine for the non-tropical
    # (SoilGrids) tiles but not for the tropical (CIFOR/Jukka) tiles (i.e. data didn't disappear in the non-tropical
    # tiles if I added the tags before the GDAL steps but the tropical data did disappear).

    copyfile(out_tile_no_tag, out_tile)

    uu.print_log("Adding metadata tags to", tile_id)
    # Opens the output tile, only so that metadata tags can be added
    # Based on https://rasterio.readthedocs.io/en/latest/topics/tags.html
    with rasterio.open(out_tile_no_tag) as out_tile_no_tag_src:

        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = out_tile_no_tag_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = out_tile_no_tag_src.block_windows(1)

        # Updates kwargs for the output dataset
        kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

        out_tile_tagged = rasterio.open(out_tile, 'w', **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(out_tile_tagged, 'std')
        out_tile_tagged.update_tags(key='1 = peat. 0 = not peat.')
        out_tile_tagged.update_tags(
            source=
            'Jukka for IDN and MYS; CIFOR for rest of tropics; SoilGrids250 (May 2020) most likely histosol for outside tropics'
        )
        out_tile_tagged.update_tags(extent='Full extent of input datasets')

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            peat_mask_window = out_tile_no_tag_src.read(1, window=window)

            # Writes the output window to the output
            out_tile_tagged.write_band(1, peat_mask_window, window=window)

    # Otherwise, the untagged version is counted and eventually copied to s3 if it has data in it
    os.remove(out_tile_no_tag)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, cn.pattern_peat_mask)
예제 #9
0
def sign_change(std_aggreg_flux, sensit_aggreg_flux, sensit_type):

    # start time
    start = datetime.datetime.now()

    # Date for the output raster name
    date = datetime.datetime.now()
    date_formatted = date.strftime("%Y_%m_%d")

    # Opens the standard net flux output in rasterio
    with rasterio.open(std_aggreg_flux) as std_src:

        kwargs = std_src.meta

        windows = std_src.block_windows(1)

        # Opens the sensitivity analysis net flux output in rasterio
        sensit_src = rasterio.open(sensit_aggreg_flux)

        # Creates the sign change raster
        dst = rasterio.open(
            '{0}_{1}_{2}.tif'.format(cn.pattern_aggreg_sensit_sign_change,
                                     sensit_type, date_formatted), 'w',
            **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(dst, sensit_type)
        dst.update_tags(
            key=
            '1=stays net source. 2=stays net sink. 3=changes from net source to net sink. 4=changes from net sink to net source.'
        )
        dst.update_tags(
            source=
            'Comparison of net flux at 0.04x0.04 degrees from standard model to net flux from {} sensitivity analysis'
            .format(sensit_type))
        dst.update_tags(extent='Global')

        # Iterates through the windows in the standard net flux output
        for idx, window in windows:

            std_window = std_src.read(1, window=window)
            sensit_window = sensit_src.read(1, window=window)

            # Defaults the sign change output raster to 0
            dst_data = np.zeros((window.height, window.width), dtype='Float32')

            # Assigns the output value based on the signs (source, sink) of the standard and sensitivity analysis.
            # No option has both windows equaling 0 because that results in the NoData values getting assigned whatever
            # output corresponds to that
            # (e.g., if dst_data[np.where((sensit_window >= 0) & (std_window >= 0))] = 1, NoData values (0s) would become 1s.
            dst_data[np.where((sensit_window > 0)
                              & (std_window >= 0))] = 1  # stays net source
            dst_data[np.where((sensit_window < 0)
                              & (std_window < 0))] = 2  # stays net sink
            dst_data[np.where((sensit_window >= 0) & (
                std_window < 0))] = 3  # changes from sink to source
            dst_data[np.where((sensit_window < 0) & (
                std_window >= 0))] = 4  # changes from source to sink

            dst.write_band(1, dst_data, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, 'global', sensit_aggreg_flux)
def forest_age_category(tile_id, gain_table_dict, pattern, sensit_type, no_upload):

    uu.print_log("Assigning forest age categories:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Gets the bounding coordinates of each tile. Needed to determine if the tile is in the tropics (within 30 deg of the equator)
    xmin, ymin, xmax, ymax = uu.coords(tile_id)

    # Default value is that the tile is not in the tropics
    tropics = 0

    # Criteria for assigning a tile to the tropics
    if (ymax > -30) & (ymax <= 30) :

        tropics = 1

    uu.print_log("  Tile {} in tropics:".format(tile_id), tropics)

    # Names of the input tiles
    gain = '{0}_{1}.tif'.format(cn.pattern_gain, tile_id)
    model_extent = uu.sensit_tile_rename(sensit_type, tile_id, cn.pattern_model_extent)
    ifl_primary = uu.sensit_tile_rename(sensit_type, tile_id, cn.pattern_ifl_primary)
    cont_eco = uu.sensit_tile_rename(sensit_type, tile_id, cn.pattern_cont_eco_processed)

    # Biomass tile name depends on the sensitivity analysis
    if sensit_type == 'biomass_swap':
        biomass = '{0}_{1}.tif'.format(tile_id, cn.pattern_JPL_unmasked_processed)
        uu.print_log("Using JPL biomass tile for {} sensitivity analysis".format(sensit_type))
    else:
        biomass = '{0}_{1}.tif'.format(tile_id, cn.pattern_WHRC_biomass_2000_unmasked)
        uu.print_log("Using WHRC biomass tile for {} sensitivity analysis".format(sensit_type))

    if sensit_type == 'legal_Amazon_loss':
        loss = '{0}_{1}.tif'.format(tile_id, cn.pattern_Brazil_annual_loss_processed)
        uu.print_log("Using PRODES loss tile {0} for {1} sensitivity analysis".format(tile_id, sensit_type))
    elif sensit_type == 'Mekong_loss':
        loss = '{0}_{1}.tif'.format(tile_id, cn.pattern_Mekong_loss_processed)
    else:
        loss = '{0}_{1}.tif'.format(cn.pattern_loss, tile_id)
        uu.print_log("Using Hansen loss tile {0} for {1} model run".format(tile_id, sensit_type))

    uu.print_log("  Assigning age categories")

    # Opens biomass tile
    with rasterio.open(model_extent) as model_extent_src:

        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = model_extent_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = model_extent_src.block_windows(1)

        # Opens the input tiles if they exist
        try:
            cont_eco_src = rasterio.open(cont_eco)
            uu.print_log("   Continent-ecozone tile found for {}".format(tile_id))
        except:
            uu.print_log("   No continent-ecozone tile found for {}".format(tile_id))

        try:
            gain_src = rasterio.open(gain)
            uu.print_log("   Gain tile found for {}".format(tile_id))
        except:
            uu.print_log("   No gain tile found for {}".format(tile_id))

        try:
            biomass_src = rasterio.open(biomass)
            uu.print_log("   Biomass tile found for {}".format(tile_id))
        except:
            uu.print_log("   No biomass tile found for {}".format(tile_id))

        try:
            loss_src = rasterio.open(loss)
            uu.print_log("   Loss tile found for {}".format(tile_id))
        except:
            uu.print_log("   No loss tile found for {}".format(tile_id))

        try:
            ifl_primary_src = rasterio.open(ifl_primary)
            uu.print_log("   IFL-primary forest tile found for {}".format(tile_id))
        except:
            uu.print_log("   No IFL-primary forest tile found for {}".format(tile_id))

        # Updates kwargs for the output dataset
        kwargs.update(
            driver='GTiff',
            count=1,
            compress='lzw',
            nodata=0
        )

        # Opens the output tile, giving it the arguments of the input tiles
        dst = rasterio.open('{0}_{1}.tif'.format(tile_id, pattern), 'w', **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(dst, sensit_type)
        dst.update_tags(
            key='1: young (<20 year) secondary forest; 2: old (>20 year) secondary forest; 3: primary forest or IFL')
        dst.update_tags(
            source='Decision tree that uses Hansen gain and loss, IFL/primary forest extent, and aboveground biomass to assign an age category')
        dst.update_tags(
            extent='Full model extent, even though these age categories will not be used over the full model extent. They apply to just the rates from IPCC defaults.')


        uu.print_log("    Assigning IPCC age categories for", tile_id)

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            # Creates windows for each input raster. Only model_extent_src is guaranteed to exist
            model_extent_window = model_extent_src.read(1, window=window)

            try:
                loss_window = loss_src.read(1, window=window)
            except:
                loss_window = np.zeros((window.height, window.width), dtype='uint8')

            try:
                gain_window = gain_src.read(1, window=window)
            except:
                gain_window = np.zeros((window.height, window.width), dtype='uint8')

            try:
                cont_eco_window = cont_eco_src.read(1, window=window)
            except:
                cont_eco_window = np.zeros((window.height, window.width), dtype='uint8')

            try:
                biomass_window = biomass_src.read(1, window=window)
            except:
                biomass_window = np.zeros((window.height, window.width), dtype='float32')

            try:
                ifl_primary_window = ifl_primary_src.read(1, window=window)
            except:
                ifl_primary_window = np.zeros((window.height, window.width), dtype='uint8')

            # Creates a numpy array that has the <=20 year secondary forest growth rate x 20
            # based on the continent-ecozone code of each pixel (the dictionary).
            # This is used to assign pixels to the correct age category.
            gain_20_years = np.vectorize(gain_table_dict.get)(cont_eco_window)*20

            # Create a 0s array for the output
            dst_data = np.zeros((window.height, window.width), dtype='uint8')

            # Logic tree for assigning age categories begins here
            # Code 1 = young (<20 years) secondary forest, code 2 = old (>20 year) secondary forest, code 3 = primary forest
            # model_extent_window ensures that there is both biomass and tree cover in 2000 OR mangroves OR tree cover gain
            # WITHOUT pre-2000 plantations

            # For every model version except legal_Amazon_loss sensitivity analysis, which has its own rules about age assignment

            if sensit_type != 'legal_Amazon_loss':
                # No change pixels- no loss or gain
                if tropics == 0:

                    dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window == 0))] = 2

                if tropics == 1:

                    dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window == 0) & (ifl_primary_window != 1))] = 2
                    dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window == 0) & (ifl_primary_window == 1))] = 3

                # Loss-only pixels
                dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window > 0) & (ifl_primary_window != 1) & (biomass_window <= gain_20_years))] = 1
                dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window > 0) & (ifl_primary_window != 1) & (biomass_window > gain_20_years))] = 2
                dst_data[np.where((model_extent_window > 0) & (gain_window == 0) & (loss_window > 0) & (ifl_primary_window ==1))] = 3

                # Gain-only pixels
                # If there is gain, the pixel doesn't need biomass or canopy cover. It just needs to be outside of plantations and mangroves.
                # The role of model_extent_window here is to exclude the pre-2000 plantations.
                dst_data[np.where((model_extent_window > 0) & (gain_window == 1) & (loss_window == 0))] = 1

                # Pixels with loss and gain
                # If there is gain with loss, the pixel doesn't need biomass or canopy cover. It just needs to be outside of plantations and mangroves.
                # The role of model_extent_window here is to exclude the pre-2000 plantations.
                dst_data[np.where((model_extent_window > 0) & (gain_window == 1) & (loss_window > (cn.gain_years)))] = 1
                dst_data[np.where((model_extent_window > 0) & (gain_window == 1) & (loss_window > 0) & (loss_window <= (cn.gain_years/2)))] = 1
                dst_data[np.where((model_extent_window > 0) & (gain_window == 1) & (loss_window > (cn.gain_years/2)) & (loss_window <= cn.gain_years))] = 1

            # For legal_Amazon_loss sensitivity analysis
            else:

                # Non-loss pixels (could have gain or not. Assuming that if within PRODES extent in 2000, there can't be
                # gain, so it's a faulty detection. Thus, gain-only pixels are ignored and become part of no change.)
                dst_data[np.where((model_extent_window == 1) & (loss_window == 0))] = 3  # primary forest

                # Loss-only pixels
                dst_data[np.where((model_extent_window == 1) & (loss_window > 0) & (gain_window == 0))] = 3  # primary forest

                # Loss-and-gain pixels
                dst_data[np.where((model_extent_window == 1) & (loss_window > 0) & (gain_window == 1))] = 2  # young secondary forest


            # Writes the output window to the output
            dst.write_band(1, dst_data, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, pattern, no_upload)
예제 #11
0
def annual_gain_rate_AGC_BGC_all_forest_types(tile_id, output_pattern_list,
                                              sensit_type, no_upload):

    uu.print_log("Mapping removal rate source and AGB and BGB removal rates:",
                 tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the input tiles
    # Removal factors
    model_extent = uu.sensit_tile_rename(sensit_type, tile_id,
                                         cn.pattern_model_extent)
    mangrove_AGB = '{0}_{1}.tif'.format(tile_id,
                                        cn.pattern_annual_gain_AGB_mangrove)
    mangrove_BGB = '{0}_{1}.tif'.format(tile_id,
                                        cn.pattern_annual_gain_BGB_mangrove)
    europe_AGC_BGC = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_annual_gain_AGC_BGC_natrl_forest_Europe)
    plantations_AGC_BGC = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_annual_gain_AGC_BGC_planted_forest_unmasked)
    us_AGC_BGC = uu.sensit_tile_rename(
        sensit_type, tile_id, cn.pattern_annual_gain_AGC_BGC_natrl_forest_US)
    young_AGC = uu.sensit_tile_rename(
        sensit_type, tile_id, cn.pattern_annual_gain_AGC_natrl_forest_young)
    age_category = uu.sensit_tile_rename(sensit_type, tile_id,
                                         cn.pattern_age_cat_IPCC)
    ipcc_AGB_default = uu.sensit_tile_rename(
        sensit_type, tile_id, cn.pattern_annual_gain_AGB_IPCC_defaults)

    # Removal factor standard deviations
    mangrove_AGB_stdev = '{0}_{1}.tif'.format(
        tile_id, cn.pattern_stdev_annual_gain_AGB_mangrove)
    europe_AGC_BGC_stdev = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_stdev_annual_gain_AGC_BGC_natrl_forest_Europe)
    plantations_AGC_BGC_stdev = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_stdev_annual_gain_AGC_BGC_planted_forest_unmasked)
    us_AGC_BGC_stdev = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_stdev_annual_gain_AGC_BGC_natrl_forest_US)
    young_AGC_stdev = uu.sensit_tile_rename(
        sensit_type, tile_id,
        cn.pattern_stdev_annual_gain_AGC_natrl_forest_young)
    ipcc_AGB_default_stdev = uu.sensit_tile_rename(
        sensit_type, tile_id, cn.pattern_stdev_annual_gain_AGB_IPCC_defaults)

    # Names of the output tiles
    removal_forest_type = '{0}_{1}.tif'.format(tile_id, output_pattern_list[0])
    annual_gain_AGC_all_forest_types = '{0}_{1}.tif'.format(
        tile_id, output_pattern_list[1])
    annual_gain_BGC_all_forest_types = '{0}_{1}.tif'.format(
        tile_id, output_pattern_list[2])
    annual_gain_AGC_BGC_all_forest_types = '{0}_{1}.tif'.format(
        tile_id, output_pattern_list[3]
    )  # Not used further in the model. Created just for reference.
    stdev_annual_gain_AGC_all_forest_types = '{0}_{1}.tif'.format(
        tile_id, output_pattern_list[4])

    # Opens biomass tile
    with rasterio.open(model_extent) as model_extent_src:

        # Grabs metadata about the tif, like its location/projection/cellsize
        kwargs = model_extent_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = model_extent_src.block_windows(1)

        # Updates kwargs for the output dataset
        kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

        # Checks whether there are mangrove or planted forest tiles. If so, they are opened.
        try:
            mangrove_AGB_src = rasterio.open(mangrove_AGB)
            mangrove_BGB_src = rasterio.open(mangrove_BGB)
            mangrove_AGB_stdev_src = rasterio.open(mangrove_AGB_stdev)
            uu.print_log(
                "    Mangrove tiles (AGB and BGB) for {}".format(tile_id))
        except:
            uu.print_log("    No mangrove tile for {}".format(tile_id))

        try:
            europe_AGC_BGC_src = rasterio.open(europe_AGC_BGC)
            europe_AGC_BGC_stdev_src = rasterio.open(europe_AGC_BGC_stdev)
            uu.print_log(
                "    Europe removal factor tile for {}".format(tile_id))
        except:
            uu.print_log(
                "    No Europe removal factor tile for {}".format(tile_id))

        try:
            plantations_AGC_BGC_src = rasterio.open(plantations_AGC_BGC)
            plantations_AGC_BGC_stdev_src = rasterio.open(
                plantations_AGC_BGC_stdev)
            uu.print_log("    Planted forest tile for {}".format(tile_id))
        except:
            uu.print_log("    No planted forest tile for {}".format(tile_id))

        try:
            us_AGC_BGC_src = rasterio.open(us_AGC_BGC)
            us_AGC_BGC_stdev_src = rasterio.open(us_AGC_BGC_stdev)
            uu.print_log("    US removal factor tile for {}".format(tile_id))
        except:
            uu.print_log(
                "    No US removal factor tile for {}".format(tile_id))

        try:
            young_AGC_src = rasterio.open(young_AGC)
            young_AGC_stdev_src = rasterio.open(young_AGC_stdev)
            uu.print_log(
                "    Young forest removal factor tile for {}".format(tile_id))
        except:
            uu.print_log(
                "    No young forest removal factor tile for {}".format(
                    tile_id))

        try:
            age_category_src = rasterio.open(age_category)
            uu.print_log("    Age category tile for {}".format(tile_id))
        except:
            uu.print_log("    No age category tile for {}".format(tile_id))

        try:
            ipcc_AGB_default_src = rasterio.open(ipcc_AGB_default)
            ipcc_AGB_default_stdev_src = rasterio.open(ipcc_AGB_default_stdev)
            uu.print_log(
                "    IPCC default removal rate tile for {}".format(tile_id))
        except:
            uu.print_log(
                "    No IPCC default removal rate tile for {}".format(tile_id))

        # Opens the output tile, giving it the arguments of the input tiles
        removal_forest_type_dst = rasterio.open(removal_forest_type, 'w',
                                                **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(removal_forest_type_dst, sensit_type)
        removal_forest_type_dst.update_tags(
            key=
            '6: mangroves. 5: European-specific rates. 4: planted forests. 3: US-specific rates. 2: young (<20 year) secondary forests. 1: old (>20 year) secondary forests and primary forests. Priority goes to the highest number.'
        )
        removal_forest_type_dst.update_tags(
            source=
            'Mangroves: IPCC wetlands supplement. Europe: Liz Goldman. Planted forests: Spatial Database of Planted Forests. USA: US FIA, via Rich Birdsey. Young natural forests: Cook-Patton et al. 2020. Old natural forests: IPCC Forests table 4.9'
        )
        removal_forest_type_dst.update_tags(extent='Full model extent')

        # Updates kwargs for the removal rate outputs-- just need to change datatype
        kwargs.update(dtype='float32')

        annual_gain_AGC_all_forest_types_dst = rasterio.open(
            annual_gain_AGC_all_forest_types, 'w', **kwargs)
        annual_gain_BGC_all_forest_types_dst = rasterio.open(
            annual_gain_BGC_all_forest_types, 'w', **kwargs)
        annual_gain_AGC_BGC_all_forest_types_dst = rasterio.open(
            annual_gain_AGC_BGC_all_forest_types, 'w', **kwargs)
        stdev_annual_gain_AGC_all_forest_types_dst = rasterio.open(
            stdev_annual_gain_AGC_all_forest_types, 'w', **kwargs)

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(annual_gain_AGC_all_forest_types_dst, sensit_type)
        annual_gain_AGC_all_forest_types_dst.update_tags(
            units='megagrams aboveground carbon/ha/yr')
        annual_gain_AGC_all_forest_types_dst.update_tags(
            source=
            'Mangroves: IPCC wetlands supplement Table 4.4. Europe: Liz Goldman. Planted forests: Spatial Database of Planted Forests. USA: US FIA, via Rich Birdsey. Young natural forests: Cook-Patton et al. 2020. Old natural forests: IPCC Forests table 4.9'
        )
        annual_gain_AGC_all_forest_types_dst.update_tags(
            extent='Full model extent')

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(annual_gain_BGC_all_forest_types_dst, sensit_type)
        annual_gain_BGC_all_forest_types_dst.update_tags(
            units='megagrams belowground carbon/ha/yr')
        annual_gain_BGC_all_forest_types_dst.update_tags(
            source=
            'Mangroves: IPCC wetlands supplement Table 4.4. Europe: Liz Goldman. Planted forests: Spatial Database of Planted Forests. USA: US FIA, via Rich Birdsey. Young natural forests: Cook-Patton et al. 2020. Old natural forests: IPCC Forests table 4.9'
        )
        annual_gain_BGC_all_forest_types_dst.update_tags(
            extent='Full model extent')

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(annual_gain_AGC_BGC_all_forest_types_dst,
                             sensit_type)
        annual_gain_AGC_BGC_all_forest_types_dst.update_tags(
            units='megagrams aboveground + belowground carbon/ha/yr')
        annual_gain_AGC_BGC_all_forest_types_dst.update_tags(
            source=
            'Mangroves: IPCC wetlands supplement Table 4.4. Europe: Liz Goldman. Planted forests: Spatial Database of Planted Forests. USA: US FIA, via Rich Birdsey. Young natural forests: Cook-Patton et al. 2020. Old natural forests: IPCC Forests table 4.9'
        )
        annual_gain_AGC_BGC_all_forest_types_dst.update_tags(
            extent='Full model extent')

        # Adds metadata tags to the output raster
        uu.add_rasterio_tags(stdev_annual_gain_AGC_all_forest_types_dst,
                             sensit_type)
        stdev_annual_gain_AGC_all_forest_types_dst.update_tags(
            units=
            'standard deviation for removal factor, in terms of megagrams aboveground carbon/ha/yr'
        )
        stdev_annual_gain_AGC_all_forest_types_dst.update_tags(
            source=
            'Mangroves: IPCC wetlands supplement Table 4.4. Europe: Liz Goldman. Planted forests: Spatial Database of Planted Forests. USA: US FIA, via Rich Birdsey. Young natural forests: Cook-Patton et al. 2020. Old natural forests: IPCC Forests table 4.9'
        )
        stdev_annual_gain_AGC_all_forest_types_dst.update_tags(
            extent='Full model extent')

        uu.print_log(
            "  Creating removal model forest type tile, AGC removal factor tile, BGC removal factor tile, and AGC removal factor standard deviation tile for {}"
            .format(tile_id))

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            model_extent_window = model_extent_src.read(1, window=window)

            # Output rasters' windows
            removal_forest_type_window = np.zeros(
                (window.height, window.width), dtype='uint8')
            annual_gain_AGC_all_forest_types_window = np.zeros(
                (window.height, window.width), dtype='float32')
            annual_gain_BGC_all_forest_types_window = np.zeros(
                (window.height, window.width), dtype='float32')
            stdev_annual_gain_AGC_all_forest_types_window = np.zeros(
                (window.height, window.width), dtype='float32')

            try:
                age_category_window = age_category_src.read(1, window=window)
            except:
                age_category_window = np.zeros((window.height, window.width),
                                               dtype='uint8')

            # Lowest priority
            try:
                ipcc_AGB_default_rate_window = ipcc_AGB_default_src.read(
                    1, window=window)
                ipcc_AGB_default_stdev_window = ipcc_AGB_default_stdev_src.read(
                    1, window=window)
                # In no_primary_gain, the AGB_default_rate_window = 0, so primary forest pixels would not be
                # assigned a removal forest type and therefore get exclude from the model later.
                # That is incorrect, so using model_extent as the criterion instead allows the primary forest pixels
                # that don't have rates under this sensitivity analysis to still be included in the model.
                # Unfortunately, model_extent is slightly different from the IPCC rate extent (no IPCC rates where
                # there is no ecozone information), but this is a very small difference and not worth worrying about.
                if sensit_type == 'no_primary_gain':
                    removal_forest_type_window = np.where(
                        model_extent_window != 0, cn.old_natural_rank,
                        removal_forest_type_window).astype('uint8')
                else:
                    removal_forest_type_window = np.where(
                        ipcc_AGB_default_rate_window != 0, cn.old_natural_rank,
                        removal_forest_type_window).astype('uint8')
                annual_gain_AGC_all_forest_types_window = np.where(
                    ipcc_AGB_default_rate_window != 0,
                    ipcc_AGB_default_rate_window *
                    cn.biomass_to_c_non_mangrove,
                    annual_gain_AGC_all_forest_types_window).astype('float32')
                annual_gain_BGC_all_forest_types_window = np.where(
                    ipcc_AGB_default_rate_window != 0,
                    ipcc_AGB_default_rate_window *
                    cn.biomass_to_c_non_mangrove * cn.below_to_above_non_mang,
                    annual_gain_BGC_all_forest_types_window).astype('float32')
                stdev_annual_gain_AGC_all_forest_types_window = np.where(
                    ipcc_AGB_default_stdev_window != 0,
                    ipcc_AGB_default_stdev_window *
                    cn.biomass_to_c_non_mangrove,
                    stdev_annual_gain_AGC_all_forest_types_window).astype(
                        'float32')
            except:
                pass

            try:  # young_AGC_rate_window uses > because of the weird NaN in the tiles. If != is used, the young rate NaN overwrites the IPCC arrays
                young_AGC_rate_window = young_AGC_src.read(1, window=window)
                young_AGC_stdev_window = young_AGC_stdev_src.read(
                    1, window=window)
                # Using the > with the NaN results in non-fatal "RuntimeWarning: invalid value encountered in greater".
                # This isn't actually a problem, so the "with" statement suppresses it, per https://stackoverflow.com/a/58026329/10839927
                with np.errstate(invalid='ignore'):
                    removal_forest_type_window = np.where(
                        (young_AGC_rate_window > 0) &
                        (age_category_window == 1), cn.young_natural_rank,
                        removal_forest_type_window).astype('uint8')
                    annual_gain_AGC_all_forest_types_window = np.where(
                        (young_AGC_rate_window > 0) &
                        (age_category_window == 1), young_AGC_rate_window,
                        annual_gain_AGC_all_forest_types_window).astype(
                            'float32')
                    annual_gain_BGC_all_forest_types_window = np.where(
                        (young_AGC_rate_window > 0) &
                        (age_category_window == 1),
                        young_AGC_rate_window * cn.below_to_above_non_mang,
                        annual_gain_BGC_all_forest_types_window).astype(
                            'float32')
                    stdev_annual_gain_AGC_all_forest_types_window = np.where(
                        (young_AGC_stdev_window > 0) &
                        (age_category_window == 1), young_AGC_stdev_window,
                        stdev_annual_gain_AGC_all_forest_types_window).astype(
                            'float32')

            except:
                pass

            if sensit_type != 'US_removals':
                try:
                    us_AGC_BGC_rate_window = us_AGC_BGC_src.read(1,
                                                                 window=window)
                    us_AGC_BGC_stdev_window = us_AGC_BGC_stdev_src.read(
                        1, window=window)
                    removal_forest_type_window = np.where(
                        us_AGC_BGC_rate_window != 0, cn.US_rank,
                        removal_forest_type_window).astype('uint8')
                    annual_gain_AGC_all_forest_types_window = np.where(
                        us_AGC_BGC_rate_window != 0, us_AGC_BGC_rate_window /
                        (1 + cn.below_to_above_non_mang),
                        annual_gain_AGC_all_forest_types_window).astype(
                            'float32')
                    annual_gain_BGC_all_forest_types_window = np.where(
                        us_AGC_BGC_rate_window != 0, (us_AGC_BGC_rate_window) -
                        (us_AGC_BGC_rate_window /
                         (1 + cn.below_to_above_non_mang)),
                        annual_gain_BGC_all_forest_types_window).astype(
                            'float32')
                    stdev_annual_gain_AGC_all_forest_types_window = np.where(
                        us_AGC_BGC_stdev_window != 0, us_AGC_BGC_stdev_window /
                        (1 + cn.below_to_above_non_mang),
                        stdev_annual_gain_AGC_all_forest_types_window).astype(
                            'float32')
                except:
                    pass

            try:
                plantations_AGC_BGC_rate_window = plantations_AGC_BGC_src.read(
                    1, window=window)
                plantations_AGC_BGC_stdev_window = plantations_AGC_BGC_stdev_src.read(
                    1, window=window)
                removal_forest_type_window = np.where(
                    plantations_AGC_BGC_rate_window != 0,
                    cn.planted_forest_rank,
                    removal_forest_type_window).astype('uint8')
                annual_gain_AGC_all_forest_types_window = np.where(
                    plantations_AGC_BGC_rate_window != 0,
                    plantations_AGC_BGC_rate_window /
                    (1 + cn.below_to_above_non_mang),
                    annual_gain_AGC_all_forest_types_window).astype('float32')
                annual_gain_BGC_all_forest_types_window = np.where(
                    plantations_AGC_BGC_rate_window != 0,
                    (plantations_AGC_BGC_rate_window) -
                    (plantations_AGC_BGC_rate_window /
                     (1 + cn.below_to_above_non_mang)),
                    annual_gain_BGC_all_forest_types_window).astype('float32')
                stdev_annual_gain_AGC_all_forest_types_window = np.where(
                    plantations_AGC_BGC_stdev_window != 0,
                    plantations_AGC_BGC_stdev_window /
                    (1 + cn.below_to_above_non_mang),
                    stdev_annual_gain_AGC_all_forest_types_window).astype(
                        'float32')
            except:
                pass

            try:
                europe_AGC_BGC_rate_window = europe_AGC_BGC_src.read(
                    1, window=window)
                europe_AGC_BGC_stdev_window = europe_AGC_BGC_stdev_src.read(
                    1, window=window)
                removal_forest_type_window = np.where(
                    europe_AGC_BGC_rate_window != 0, cn.europe_rank,
                    removal_forest_type_window).astype('uint8')
                annual_gain_AGC_all_forest_types_window = np.where(
                    europe_AGC_BGC_rate_window != 0,
                    europe_AGC_BGC_rate_window /
                    (1 + cn.below_to_above_non_mang),
                    annual_gain_AGC_all_forest_types_window).astype('float32')
                annual_gain_BGC_all_forest_types_window = np.where(
                    europe_AGC_BGC_rate_window != 0,
                    (europe_AGC_BGC_rate_window) -
                    (europe_AGC_BGC_rate_window /
                     (1 + cn.below_to_above_non_mang)),
                    annual_gain_BGC_all_forest_types_window).astype('float32')
                # NOTE: Nancy Harris thought that the European removal standard deviations were 2x too large,
                # per email on 8/30/2020. Thus, simplest fix is to leave original tiles 2x too large and
                # correct them only where composited with other stdev sources.
                stdev_annual_gain_AGC_all_forest_types_window = np.where(
                    europe_AGC_BGC_stdev_window != 0,
                    (europe_AGC_BGC_stdev_window / 2) /
                    (1 + cn.below_to_above_non_mang),
                    stdev_annual_gain_AGC_all_forest_types_window).astype(
                        'float32')
            except:
                pass

            # Highest priority
            try:
                mangroves_AGB_rate_window = mangrove_AGB_src.read(
                    1, window=window)
                mangroves_BGB_rate_window = mangrove_BGB_src.read(
                    1, window=window)
                mangroves_AGB_stdev_window = mangrove_AGB_stdev_src.read(
                    1, window=window)
                removal_forest_type_window = np.where(
                    mangroves_AGB_rate_window != 0, cn.mangrove_rank,
                    removal_forest_type_window).astype('uint8')
                annual_gain_AGC_all_forest_types_window = np.where(
                    mangroves_AGB_rate_window != 0,
                    mangroves_AGB_rate_window * cn.biomass_to_c_mangrove,
                    annual_gain_AGC_all_forest_types_window).astype('float32')
                annual_gain_BGC_all_forest_types_window = np.where(
                    mangroves_BGB_rate_window != 0,
                    mangroves_BGB_rate_window * cn.biomass_to_c_mangrove,
                    annual_gain_BGC_all_forest_types_window).astype('float32')
                stdev_annual_gain_AGC_all_forest_types_window = np.where(
                    mangroves_AGB_stdev_window != 0,
                    mangroves_AGB_stdev_window * cn.biomass_to_c_mangrove,
                    stdev_annual_gain_AGC_all_forest_types_window).astype(
                        'float32')
            except:
                pass

            # Masks outputs to model output extent
            removal_forest_type_window = np.where(model_extent_window == 1,
                                                  removal_forest_type_window,
                                                  0)
            annual_gain_AGC_all_forest_types_window = np.where(
                model_extent_window == 1,
                annual_gain_AGC_all_forest_types_window, 0)
            annual_gain_BGC_all_forest_types_window = np.where(
                model_extent_window == 1,
                annual_gain_BGC_all_forest_types_window, 0)
            annual_gain_AGC_BGC_all_forest_types_window = annual_gain_AGC_all_forest_types_window + annual_gain_BGC_all_forest_types_window
            stdev_annual_gain_AGC_all_forest_types_window = np.where(
                model_extent_window == 1,
                stdev_annual_gain_AGC_all_forest_types_window, 0)

            # Writes the outputs window to the output files
            removal_forest_type_dst.write_band(1,
                                               removal_forest_type_window,
                                               window=window)
            annual_gain_AGC_all_forest_types_dst.write_band(
                1, annual_gain_AGC_all_forest_types_window, window=window)
            annual_gain_BGC_all_forest_types_dst.write_band(
                1, annual_gain_BGC_all_forest_types_window, window=window)
            annual_gain_AGC_BGC_all_forest_types_dst.write_band(
                1, annual_gain_AGC_BGC_all_forest_types_window, window=window)
            stdev_annual_gain_AGC_all_forest_types_dst.write_band(
                1,
                stdev_annual_gain_AGC_all_forest_types_window,
                window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, cn.pattern_removal_forest_type,
                         no_upload)
예제 #12
0
def gross_removals_all_forest_types(tile_id, output_pattern_list, sensit_type):

    uu.print_log("Calculating cumulative CO2 removals:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the input tiles, modified according to sensitivity analysis
    gain_rate_AGC = uu.sensit_tile_rename(sensit_type, tile_id,
                                          cn.pattern_annual_gain_AGC_all_types)
    gain_rate_BGC = uu.sensit_tile_rename(sensit_type, tile_id,
                                          cn.pattern_annual_gain_BGC_all_types)
    gain_year_count = uu.sensit_tile_rename(sensit_type, tile_id,
                                            cn.pattern_gain_year_count)

    # Names of the output removal tiles
    cumulative_gain_AGCO2 = '{0}_{1}.tif'.format(tile_id,
                                                 output_pattern_list[0])
    cumulative_gain_BGCO2 = '{0}_{1}.tif'.format(tile_id,
                                                 output_pattern_list[1])
    cumulative_gain_AGCO2_BGCO2 = '{0}_{1}.tif'.format(tile_id,
                                                       output_pattern_list[2])

    # Opens the input tiles
    gain_rate_AGC_src = rasterio.open(gain_rate_AGC)
    gain_rate_BGC_src = rasterio.open(gain_rate_BGC)
    gain_year_count_src = rasterio.open(gain_year_count)

    # Grabs metadata for an input tile
    kwargs = gain_rate_AGC_src.meta

    # Grabs the windows of the tile (stripes) to iterate over the entire tif without running out of memory
    windows = gain_rate_AGC_src.block_windows(1)

    # Updates kwargs for the output dataset.
    kwargs.update(driver='GTiff', count=1, compress='lzw', nodata=0)

    # The output files: aboveground gross removals, belowground gross removals, above+belowground gross removals. Adds metadata tags
    cumulative_gain_AGCO2_dst = rasterio.open(cumulative_gain_AGCO2, 'w',
                                              **kwargs)
    uu.add_rasterio_tags(cumulative_gain_AGCO2_dst, sensit_type)
    cumulative_gain_AGCO2_dst.update_tags(
        units='megagrams aboveground CO2/ha over entire model period')
    cumulative_gain_AGCO2_dst.update_tags(
        source='annual removal factors and gain year count')
    cumulative_gain_AGCO2_dst.update_tags(extent='Full model extent')

    cumulative_gain_BGCO2_dst = rasterio.open(cumulative_gain_BGCO2, 'w',
                                              **kwargs)
    uu.add_rasterio_tags(cumulative_gain_BGCO2_dst, sensit_type)
    cumulative_gain_BGCO2_dst.update_tags(
        units='megagrams belowground CO2/ha over entire model period')
    cumulative_gain_BGCO2_dst.update_tags(
        source='annual removal factors and gain year count')
    cumulative_gain_BGCO2_dst.update_tags(extent='Full model extent')

    cumulative_gain_AGCO2_BGCO2_dst = rasterio.open(
        cumulative_gain_AGCO2_BGCO2, 'w', **kwargs)
    cumulative_gain_AGCO2_BGCO2_dst.update_tags(
        units=
        'megagrams aboveground+belowground CO2/ha over entire model period')
    cumulative_gain_AGCO2_BGCO2_dst.update_tags(
        source='annual removal factors and gain year count')
    cumulative_gain_AGCO2_BGCO2_dst.update_tags(extent='Full model extent')

    # Iterates across the windows (1 pixel strips) of the input tiles
    for idx, window in windows:

        # Creates a processing window for each input raster
        gain_rate_AGC_window = gain_rate_AGC_src.read(1, window=window)
        gain_rate_BGC_window = gain_rate_BGC_src.read(1, window=window)
        gain_year_count_window = gain_year_count_src.read(1, window=window)

        # Converts the annual removal rate into gross removals
        cumulative_gain_AGCO2_window = gain_rate_AGC_window * gain_year_count_window * cn.c_to_co2
        cumulative_gain_BGCO2_window = gain_rate_BGC_window * gain_year_count_window * cn.c_to_co2
        cumulative_gain_AGCO2_BGCO2_window = cumulative_gain_AGCO2_window + cumulative_gain_BGCO2_window

        # Writes the output windows to the output files
        cumulative_gain_AGCO2_dst.write_band(1,
                                             cumulative_gain_AGCO2_window,
                                             window=window)
        cumulative_gain_BGCO2_dst.write_band(1,
                                             cumulative_gain_BGCO2_window,
                                             window=window)
        cumulative_gain_AGCO2_BGCO2_dst.write_band(
            1, cumulative_gain_AGCO2_BGCO2_window, window=window)

    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, output_pattern_list[0])
def US_removal_rate_calc(tile_id, gain_table_group_region_age_dict, gain_table_group_region_dict,
                         stdev_table_group_region_age_dict, stdev_table_group_region_dict, output_pattern_list):

    uu.print_log("Assigning US removal rates and removal rate standard deviations:", tile_id)

    # Start time
    start = datetime.datetime.now()

    # Names of the input tiles
    gain = '{0}_{1}.tif'.format(cn.pattern_gain, tile_id)
    US_age_cat = '{0}_{1}.tif'.format(tile_id, cn.pattern_age_cat_natrl_forest_US)
    US_forest_group = '{0}_{1}.tif'.format(tile_id, cn.pattern_FIA_forest_group_processed)
    US_region = '{0}_{1}.tif'.format(tile_id, cn.pattern_FIA_regions_processed)

    # Opens age category raster and uses it as a template for the metadata output raster
    with rasterio.open(US_age_cat) as US_age_cat_src:

        # Grabs metadata about the tif, like its location/projection/cell size
        kwargs = US_age_cat_src.meta

        # Grabs the windows of the tile (stripes) so we can iterate over the entire tif without running out of memory
        windows = US_age_cat_src.block_windows(1)

        # Opens other necessary tiles
        gain_src = rasterio.open(gain)
        US_forest_group_src = rasterio.open(US_forest_group)
        US_region_src = rasterio.open(US_region)

        # Updates kwargs for the output dataset. Changes the datatype from int to float32.
        kwargs.update(
            driver='GTiff',
            count=1,
            compress='lzw',
            nodata=0,
            dtype='float32'
        )

        # Opens the output tile (aboveground + belowground), giving it the modified metadata of the age category tile
        agc_bgc_rate_dst = rasterio.open('{0}_{1}.tif'.format(tile_id, output_pattern_list[0]), 'w', **kwargs)
        agc_bgc_stdev_dst = rasterio.open('{0}_{1}.tif'.format(tile_id, output_pattern_list[1]), 'w', **kwargs)

        # Adds metadata tags to the output rasters
        uu.add_rasterio_tags(agc_bgc_rate_dst, 'std')
        agc_bgc_rate_dst.update_tags(
            units='megagrams aboveground+belowground carbon/ha/yr')
        agc_bgc_rate_dst.update_tags(
            source='US Forest Service FIA database, queried by Rich Birdsey, and consolidated by Nancy Harris')
        agc_bgc_rate_dst.update_tags(
            extent='Continental USA. Applies to pixels for which an FIA region, FIA forest group, and Pan et al. forest age category are available or interpolated.')

        uu.add_rasterio_tags(agc_bgc_stdev_dst, 'std')
        agc_bgc_stdev_dst.update_tags(
            units='standard deviation of removal factor, in megagrams aboveground+belowground carbon/ha/yr')
        agc_bgc_stdev_dst.update_tags(
            source='US Forest Service FIA database, queried by Rich Birdsey, and reorganized by Nancy Harris')
        agc_bgc_stdev_dst.update_tags(
            extent='Continental USA. Applies to pixels for which an FIA region, FIA forest group, and Pan et al. forest age category are available or interpolated.')

        # Iterates across the windows (1 pixel strips) of the input tile
        for idx, window in windows:

            # Creates window for each input raster
            gain_window = gain_src.read(1, window=window)
            US_age_cat_window = US_age_cat_src.read(1, window=window).astype('float32')
            US_forest_group_window = US_forest_group_src.read(1, window=window).astype('float32')
            US_region_window = US_region_src.read(1, window=window).astype('float32')


            ### For removal factors

            # Creates empty windows (arrays) that will store gain rates. There are separate arrays for
            # no Hansen gain pixels and for Hansen gain pixels. These are later combined.
            # Pixels without and with Hansen gain are treated separately because gain pixels automatically get the youngest
            # removal rate, regardless of their age category.
            agc_bgc_without_gain_pixel_window = np.zeros((window.height, window.width), dtype='float32')
            agc_bgc_with_gain_pixel_window = np.zeros((window.height, window.width), dtype='float32')

            # Performs the same operation on the three rasters as is done on the values in the table in order to
            # make the codes (dictionary key) match. Then, combines the three rasters. These values now match the key values in the spreadsheet.
            group_region_age_combined_window = (US_age_cat_window * 10000 + US_forest_group_window * 100 + US_region_window)


            # Masks the combined age-group-region raster to the three input tiles (age category, forest group, FIA region).
            # Excludes all Hansen gain pixels.
            group_region_age_combined_window = np.ma.masked_where(US_age_cat_window == 0, group_region_age_combined_window).filled(0).astype('uint16')
            group_region_age_combined_window = np.ma.masked_where(US_forest_group_window == 0, group_region_age_combined_window).filled(0)
            group_region_age_combined_window = np.ma.masked_where(US_region_window == 0, group_region_age_combined_window).filled(0)
            group_region_age_combined_window = np.ma.masked_where(gain_window != 0, group_region_age_combined_window).filled(0)

            # Applies the dictionary of group-region-age gain rates to the group-region-age numpy array to
            # get annual gain rates (Mg AGC+BGC/ha/yr) for each non-Hansen gain pixel
            for key, value in gain_table_group_region_age_dict.items():
                agc_bgc_without_gain_pixel_window[group_region_age_combined_window == key] = value


            # This is for pixels with Hansen gain, so it assumes the age category is young and therefore only
            # includes region and forest group.
            # Performs the same operation on the two rasters as is done on the values in the table in order to
            # make the codes (dictionary key) match. Then, combines the two rasters. These values now match the key values in the spreadsheet.
            group_region_combined_window = (US_forest_group_window * 100 + US_region_window)

            # Masks the combined age-group-region raster to the three input tiles (age category, forest group, FIA region).
            # It masks to age category simply to limit the output to pixels that had some age category input.
            # The real age category masking comes when the array is masked to only where Hansen gain occurs.
            group_region_combined_window = np.ma.masked_where(US_age_cat_window == 0, group_region_combined_window).filled(0).astype('uint16')
            group_region_combined_window = np.ma.masked_where(US_forest_group_window == 0, group_region_combined_window).filled(0)
            group_region_combined_window = np.ma.masked_where(US_region_window == 0, group_region_combined_window).filled(0)
            group_region_combined_window = np.ma.masked_where(gain_window == 0, group_region_combined_window).filled(0)

            # Applies the dictionary of group-region gain rates to the group-region numpy array to
            # get annual gain rates (Mg AGC+BGC/ha/yr) for each pixel that doesn't have Hansen gain
            for key, value in gain_table_group_region_dict.items():
                agc_bgc_with_gain_pixel_window[group_region_combined_window == key] = value

            # Pixels with Hansen gain fill in the pixels that don't have Hansen gain. Each pixel has a value in
            # one or neither of these arrays but not both of these arrays
            agc_bgc_rate_window = agc_bgc_without_gain_pixel_window + agc_bgc_with_gain_pixel_window

            # Writes the output to raster
            agc_bgc_rate_dst.write_band(1, agc_bgc_rate_window, window=window)


            ### For removal factor standard deviation

            # Creates empty windows (arrays) that will store stdev. There are separate arrays for
            # no Hansen gain pixels and for Hansen gain pixels. These are later combined.
            # Pixels without and with Hansen gain are treated separately because gain pixels automatically get the youngest
            # removal rate stdev, regardless of their age category.
            stdev_agc_bgc_without_gain_pixel_window = np.zeros((window.height, window.width), dtype='float32')
            stdev_agc_bgc_with_gain_pixel_window = np.zeros((window.height, window.width), dtype='float32')

            # Applies the dictionary of group-region-age gain rates to the group-region-age numpy array to
            # get annual gain rates (Mg AGC+BGC/ha/yr) for each non-Hansen gain pixel
            for key, value in stdev_table_group_region_age_dict.items():
                stdev_agc_bgc_without_gain_pixel_window[group_region_age_combined_window == key] = value

            # Applies the dictionary of group-region gain rates to the group-region numpy array to
            # get annual gain rates (Mg AGC+BGC/ha/yr) for each pixel that doesn't have Hansen gain
            for key, value in stdev_table_group_region_dict.items():
                stdev_agc_bgc_with_gain_pixel_window[group_region_combined_window == key] = value

            # Pixels with Hansen gain fill in the pixels that don't have Hansen gain. Each pixel has a value in
            # one or neither of these arrays but not both of these arrays
            stdev_agc_bgc_window = stdev_agc_bgc_without_gain_pixel_window + stdev_agc_bgc_with_gain_pixel_window

            # Writes the output to raster
            agc_bgc_stdev_dst.write_band(1, stdev_agc_bgc_window, window=window)


    # Prints information about the tile that was just processed
    uu.end_of_fx_summary(start, tile_id, output_pattern_list[0])