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)
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])
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)
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)
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])
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)
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)
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)
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])