def run_inundation(args): rem = args[0] catchments = args[1] magnitude_flows_csv = args[2] huc = args[3] hydroTable = args[4] output_extent_grid = args[5] output_depth_grid = args[6] ahps_site = args[7] magnitude = args[8] log_file = args[9] try: inundate(rem,catchments,catchment_poly,hydroTable,magnitude_flows_csv,mask_type,hucs=hucs,hucs_layerName=hucs_layerName, subset_hucs=huc,num_workers=1,aggregate=False,inundation_raster=output_extent_grid,inundation_polygon=None, depths=output_depth_grid,out_raster_profile=None,out_vector_profile=None,quiet=True ) except: # Log errors and their tracebacks f = open(log_file, 'a+') f.write(f"{output_extent_grid} - inundation error: {traceback.format_exc()}\n") f.close() #Inundation.py appends the huc code to the supplied output_extent_grid. #Modify output_extent_grid to match inundation.py saved filename. #Search for this file, if it didn't create, send message to log file. base_file_path,extension = os.path.splitext(output_extent_grid) saved_extent_grid_filename = "{}_{}{}".format(base_file_path,huc,extension) if not os.path.exists(saved_extent_grid_filename): with open(log_file, 'a+') as f: f.write('FAILURE_huc_{}:{}:{} map failed to create\n'.format(huc,ahps_site,magnitude))
def run_alpha_test(fim_run_dir, branch_name, test_id, mask_type, return_interval, compare_to_previous=False, run_structure_stats=False, run_levee_stats=False, archive_results=False): # Construct paths to development test results if not existent. if archive_results: branch_test_case_dir_parent = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'previous_versions', branch_name) else: branch_test_case_dir_parent = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'development_versions', branch_name) # Delete the entire directory if it already exists. if os.path.exists(branch_test_case_dir_parent): shutil.rmtree(branch_test_case_dir_parent) print("Running the alpha test for test_id: " + test_id + ", " + branch_name + "...") stats_modes_list = ['total_area'] if run_structure_stats: stats_modes_list.append('structures') if run_levee_stats: stats_modes_list.append('levees') fim_run_parent = os.path.join(os.environ['outputDataDir'], fim_run_dir) assert os.path.exists(fim_run_parent), "Cannot locate " + fim_run_parent # Create paths to fim_run outputs for use in inundate(). rem = os.path.join(fim_run_parent, 'rem_zeroed_masked.tif') catchments = os.path.join(fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes.tif') catchment_poly = os.path.join(fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') current_huc = test_id.split('_')[0] hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), 'WBDHU8' hydro_table = os.path.join(fim_run_parent, 'hydroTable.csv') # Create list of shapefile paths to use as exclusion areas. zones_dir = os.path.join(TEST_CASES_DIR, 'other', 'zones') exclusion_mask_dict = {'levees': {'path': os.path.join(zones_dir, 'leveed_areas_conus.shp'), 'buffer': None }, 'waterbodies': {'path': os.path.join(zones_dir, 'nwm_v2_reservoirs.shp'), 'buffer': None, } } # # Crosswalk feature_ids to hydroids. # hydro_table_data = pd.read_csv(hydro_table, header=0) # ht_feature_id_list = list(hydro_table_data.feature_id) # ht_hydro_id_list = list(hydro_table_data.HydroID) # lake_id_list = list(hydro_table_data.LakeID) # # # Get list of feature_ids_to_mask. # feature_ids_to_mask = [] # for f in range(0, len(lake_id_list)): # if lake_id_list[f] != -999: # lake_feature_id = ht_feature_id_list[f] # if lake_feature_id not in feature_ids_to_mask: # feature_ids_to_mask.append(lake_feature_id) # Remove duplicates and create list of hydro_ids to use as waterbody mask. # reduced_ht_feature_id_list, reduced_ht_hydro_id_list, hydro_ids_to_mask = [], [], [] # # for i in range(0, len(ht_hydro_id_list)): # if ht_hydro_id_list[i] not in reduced_ht_hydro_id_list: # reduced_ht_hydro_id_list.append(ht_hydro_id_list[i]) # reduced_ht_feature_id_list.append(ht_feature_id_list[i]) # for i in range(0, len(reduced_ht_feature_id_list)): # ht_feature_id = reduced_ht_feature_id_list[i] # ht_hydro_id = reduced_ht_hydro_id_list[i] # if ht_feature_id in feature_ids_to_mask: # hydro_ids_to_mask.append(ht_hydro_id) # Check if return interval is list of return intervals or single value. return_interval_list = return_interval if type(return_interval_list) != list: return_interval_list = [return_interval_list] for return_interval in return_interval_list: # Construct path to validation raster and forecast file. benchmark_category = test_id.split('_')[1] benchmark_raster_path = os.path.join(TEST_CASES_DIR, 'validation_data_' + benchmark_category, current_huc, return_interval, benchmark_category + '_huc_' + current_huc + '_depth_' + return_interval + '.tif') if not os.path.exists(benchmark_raster_path): # Skip loop instance if the benchmark raster doesn't exist. continue branch_test_case_dir = os.path.join(branch_test_case_dir_parent, return_interval) os.makedirs(branch_test_case_dir) # Define paths to inundation_raster and forecast file. inundation_raster = os.path.join(branch_test_case_dir, 'inundation_extent.tif') forecast = os.path.join(TEST_CASES_DIR, 'validation_data_' + benchmark_category, current_huc, return_interval, benchmark_category + '_huc_' + current_huc + '_flows_' + return_interval + '.csv') # Run inundate. print("-----> Running inundate() to produce modeled inundation extent for the " + return_interval + " return period...") inundate( rem,catchments,catchment_poly,hydro_table,forecast,mask_type,hucs=hucs,hucs_layerName=hucs_layerName, subset_hucs=current_huc,num_workers=1,aggregate=False,inundation_raster=inundation_raster,inundation_polygon=None, depths=None,out_raster_profile=None,out_vector_profile=None,quiet=True ) print("-----> Inundation mapping complete.") predicted_raster_path = os.path.join(os.path.split(inundation_raster)[0], os.path.split(inundation_raster)[1].replace('.tif', '_' + current_huc + '.tif')) # The inundate adds the huc to the name so I account for that here. # Define outputs for agreement_raster, stats_json, and stats_csv. agreement_raster, stats_json, stats_csv = os.path.join(branch_test_case_dir, 'total_area_agreement.tif'), os.path.join(branch_test_case_dir, 'stats.json'), os.path.join(branch_test_case_dir, 'stats.csv') test_version_dictionary = compute_contingency_stats_from_rasters(predicted_raster_path, benchmark_raster_path, agreement_raster, stats_csv=stats_csv, stats_json=stats_json, mask_values=[], stats_modes_list=stats_modes_list, test_id=test_id, exclusion_mask_dict=exclusion_mask_dict ) print(" ") print("Evaluation complete. All metrics for " + test_id + ", " + branch_name + ", " + return_interval + " are available at " + CYAN_BOLD + branch_test_case_dir + ENDC) print(" ") if compare_to_previous: text_block = [] # Compare to previous stats files that are available. archive_to_check = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'previous_versions') for stats_mode in stats_modes_list: archive_dictionary = profile_test_case_archive(archive_to_check, return_interval, stats_mode) if archive_dictionary == {}: break # Create header for section. header = [stats_mode] for previous_version, paths in archive_dictionary.items(): header.append(previous_version) header.append(branch_name) text_block.append(header) # Loop through stats in PRINTWORTHY_STATS for left. for stat in PRINTWORTHY_STATS: stat_line = [stat] for previous_version, paths in archive_dictionary.items(): # Load stats for previous version. previous_version_stats_json_path = paths['stats_json'] previous_version_stats_dict = json.load(open(previous_version_stats_json_path)) # Append stat for the version to state_line. stat_line.append(previous_version_stats_dict[stat]) # Append stat for the current version to stat_line. stat_line.append(test_version_dictionary[stats_mode][stat]) text_block.append(stat_line) text_block.append([" "]) regression_report_csv = os.path.join(branch_test_case_dir, 'stats_summary.csv') with open(regression_report_csv, 'w', newline='') as csvfile: csv_writer = csv.writer(csvfile) csv_writer.writerows(text_block) print() print("--------------------------------------------------------------------------------------------------") stats_mode = stats_modes_list[0] try: last_version_index = text_block[0].index('dev_latest') except ValueError: try: last_version_index = text_block[0].index('fim_2_3_3') except ValueError: try: last_version_index = text_block[0].index('fim_1_0_0') except ValueError: print(TRED_BOLD + "Warning: " + ENDC + "Cannot compare " + branch_name + " to a previous version because no authoritative versions were found in previous_versions directory. Future version of run_test_case may allow for comparisons between dev branches.") print() continue current_version_index = text_block[0].index(branch_name) for line in text_block: first_item = line[0] if first_item in stats_modes_list: if first_item != stats_mode: # Update the stats_mode and print a separator. print() print() print("--------------------------------------------------------------------------------------------------") print() stats_mode = first_item print(CYAN_BOLD + current_huc + ": " + return_interval.upper(), ENDC) print(CYAN_BOLD + stats_mode.upper().replace('_', ' ') + " METRICS" + ENDC) print() color = WHITE_BOLD metric_name = ' '.center(len(max(PRINTWORTHY_STATS, key=len))) percent_change_header = '% CHG' difference_header = 'DIFF' current_version_header = line[current_version_index].upper() last_version_header = line[last_version_index].upper() # Print Header. print(color + metric_name + " " + percent_change_header.center((7)) + " " + difference_header.center((15)) + " " + current_version_header.center(18) + " " + last_version_header.center(18), ENDC) # Format and print stat row. elif first_item in PRINTWORTHY_STATS: stat_name = first_item.upper().center(len(max(PRINTWORTHY_STATS, key=len))).replace('_', ' ') current_version = round((line[current_version_index]), 3) last_version = round((line[last_version_index]) + 0.000, 3) difference = round(current_version - last_version, 3) if difference > 0: symbol = '+' if first_item in GO_UP_STATS: color = TGREEN_BOLD elif first_item in GO_DOWN_STATS: color = TRED_BOLD else: color = TWHITE if difference < 0: symbol = '-' if first_item in GO_UP_STATS: color = TRED_BOLD elif first_item in GO_DOWN_STATS: color = TGREEN_BOLD else: color = TWHITE if difference == 0 : symbol, color = '+', TGREEN percent_change = round((difference / last_version)*100,2) print(WHITE_BOLD + stat_name + ENDC + " " + color + (symbol + " {:5.2f}".format(abs(percent_change)) + " %").rjust(len(percent_change_header)), ENDC + " " + color + ("{:12.3f}".format((difference))).rjust(len(difference_header)), ENDC + " " + "{:15.3f}".format(current_version).rjust(len(current_version_header)) + " " + "{:15.3f}".format(last_version).rjust(len(last_version_header)) + " ") print() print() print() print("--------------------------------------------------------------------------------------------------") print()
def run_recurr_test(fim_run_dir, branch_name, huc_id, magnitude, mask_type='huc', output_dir=None): # Construct paths to development test results if not existent. huc_id_dir_parent = os.path.join(INUN_REVIEW_DIR, huc_id) if not os.path.exists(huc_id_dir_parent): os.mkdir(huc_id_dir_parent) if output_dir == None: branch_test_case_dir_parent = os.path.join(INUN_REVIEW_DIR, huc_id, branch_name) else: branch_test_case_dir_parent = os.path.join(output_dir, huc_id, branch_name) # Delete the entire directory if it already exists. if os.path.exists(branch_test_case_dir_parent): shutil.rmtree(branch_test_case_dir_parent) print("Running the NWM recurrence intervals for huc_id: " + huc_id + ", " + branch_name + "...") fim_run_parent = os.path.join(fim_run_dir) assert os.path.exists(fim_run_parent), "Cannot locate " + fim_run_parent # Create paths to fim_run outputs for use in inundate(). if "previous_fim" in fim_run_parent and "fim_2" in fim_run_parent: rem = os.path.join(fim_run_parent, 'rem_clipped_zeroed_masked.tif') catchments = os.path.join( fim_run_parent, 'gw_catchments_reaches_clipped_addedAttributes.tif') else: rem = os.path.join(fim_run_parent, 'rem_zeroed_masked.tif') catchments = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes.tif') if mask_type == 'huc': catchment_poly = '' else: catchment_poly = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') hydro_table = os.path.join(fim_run_parent, 'hydroTable.csv') # Map necessary inputs for inundation(). hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), 'WBDHU8' #benchmark_category = huc_id.split('_')[1] current_huc = huc_id.split('_')[ 0] # Break off HUC ID and assign to variable. if not os.path.exists(branch_test_case_dir_parent): os.mkdir(branch_test_case_dir_parent) # Check if magnitude is list of magnitudes or single value. magnitude_list = magnitude if type(magnitude_list) != list: magnitude_list = [magnitude_list] for magnitude in magnitude_list: # Construct path to validation raster and forecast file. branch_test_case_dir = os.path.join(branch_test_case_dir_parent, magnitude) os.makedirs(branch_test_case_dir) # Make output directory for branch. # Define paths to inundation_raster and forecast file. inundation_raster = os.path.join(branch_test_case_dir, branch_name + '_inund_extent.tif') forecast = os.path.join(INUN_REVIEW_DIR, 'nwm_recurr_flow_data', 'recurr_' + magnitude + '_cms.csv') # Run inundate. print( "-----> Running inundate() to produce modeled inundation extent for the " + magnitude + " magnitude...") inundate(rem, catchments, catchment_poly, hydro_table, forecast, mask_type, hucs=hucs, hucs_layerName=hucs_layerName, subset_hucs=current_huc, num_workers=1, aggregate=False, inundation_raster=inundation_raster, inundation_polygon=None, depths=None, out_raster_profile=None, out_vector_profile=None, quiet=True) print("-----> Inundation mapping complete.")
def run_alpha_test(fim_run_dir, version, test_id, magnitude, compare_to_previous=False, archive_results=False, mask_type='huc', inclusion_area='', inclusion_area_buffer=0, light_run=False, overwrite=True): benchmark_category = test_id.split('_')[1] # Parse benchmark_category from test_id. current_huc = test_id.split('_')[0] # Break off HUC ID and assign to variable. # Construct paths to development test results if not existent. if archive_results: version_test_case_dir_parent = os.path.join(TEST_CASES_DIR, benchmark_category + '_test_cases', test_id, 'official_versions', version) else: version_test_case_dir_parent = os.path.join(TEST_CASES_DIR, benchmark_category + '_test_cases', test_id, 'testing_versions', version) # Delete the entire directory if it already exists. if os.path.exists(version_test_case_dir_parent): if overwrite == True: shutil.rmtree(version_test_case_dir_parent) else: print("Metrics for ({version}: {test_id}) already exist. Use overwrite flag (-o) to overwrite metrics.".format(version=version, test_id=test_id)) return os.mkdir(version_test_case_dir_parent) print("Running the alpha test for test_id: " + test_id + ", " + version + "...") stats_modes_list = ['total_area'] fim_run_parent = os.path.join(os.environ['outputDataDir'], fim_run_dir) assert os.path.exists(fim_run_parent), "Cannot locate " + fim_run_parent # Create paths to fim_run outputs for use in inundate(). rem = os.path.join(fim_run_parent, 'rem_zeroed_masked.tif') if not os.path.exists(rem): rem = os.path.join(fim_run_parent, 'rem_clipped_zeroed_masked.tif') catchments = os.path.join(fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes.tif') if not os.path.exists(catchments): catchments = os.path.join(fim_run_parent, 'gw_catchments_reaches_clipped_addedAttributes.tif') if mask_type == 'huc': catchment_poly = '' else: catchment_poly = os.path.join(fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') hydro_table = os.path.join(fim_run_parent, 'hydroTable.csv') # Map necessary inputs for inundation(). hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), 'WBDHU8' # Create list of shapefile paths to use as exclusion areas. zones_dir = os.path.join(TEST_CASES_DIR, 'other', 'zones') mask_dict = {'levees': {'path': os.path.join(zones_dir, 'leveed_areas_conus.shp'), 'buffer': None, 'operation': 'exclude' }, 'waterbodies': {'path': os.path.join(zones_dir, 'nwm_v2_reservoirs.shp'), 'buffer': None, 'operation': 'exclude', }, } if inclusion_area != '': inclusion_area_name = os.path.split(inclusion_area)[1].split('.')[0] # Get layer name mask_dict.update({inclusion_area_name: {'path': inclusion_area, 'buffer': int(inclusion_area_buffer), 'operation': 'include'}}) # Append the concatenated inclusion_area_name and buffer. if inclusion_area_buffer == None: inclusion_area_buffer = 0 stats_modes_list.append(inclusion_area_name + '_b' + str(inclusion_area_buffer) + 'm') # Check if magnitude is list of magnitudes or single value. magnitude_list = magnitude if type(magnitude_list) != list: magnitude_list = [magnitude_list] # Get path to validation_data_{benchmark} directory and huc_dir. validation_data_path = os.path.join(TEST_CASES_DIR, benchmark_category + '_test_cases', 'validation_data_' + benchmark_category) for magnitude in magnitude_list: version_test_case_dir = os.path.join(version_test_case_dir_parent, magnitude) if not os.path.exists(version_test_case_dir): os.mkdir(version_test_case_dir) # Construct path to validation raster and forecast file. if benchmark_category in AHPS_BENCHMARK_CATEGORIES: benchmark_raster_path_list, forecast_list = [], [] lid_dir_list = os.listdir(os.path.join(validation_data_path, current_huc)) lid_list, inundation_raster_list, domain_file_list = [], [], [] for lid in lid_dir_list: lid_dir = os.path.join(validation_data_path, current_huc, lid) benchmark_lid_raster_path = os.path.join(lid_dir, magnitude, 'ahps_' + lid + '_huc_' + current_huc + '_extent_' + magnitude + '.tif') # Only compare if the benchmark data exist. if os.path.exists(benchmark_lid_raster_path): benchmark_raster_path_list.append(benchmark_lid_raster_path) # TEMP forecast_list.append(os.path.join(lid_dir, magnitude, 'ahps_' + lid + '_huc_' + current_huc + '_flows_' + magnitude + '.csv')) # TEMP lid_list.append(lid) inundation_raster_list.append(os.path.join(version_test_case_dir, lid + '_inundation_extent.tif')) domain_file_list.append(os.path.join(lid_dir, lid + '_domain.shp')) else: benchmark_raster_file = os.path.join(TEST_CASES_DIR, benchmark_category + '_test_cases', 'validation_data_' + benchmark_category, current_huc, magnitude, benchmark_category + '_huc_' + current_huc + '_extent_' + magnitude + '.tif') benchmark_raster_path_list = [benchmark_raster_file] forecast_path = os.path.join(TEST_CASES_DIR, benchmark_category + '_test_cases', 'validation_data_' + benchmark_category, current_huc, magnitude, benchmark_category + '_huc_' + current_huc + '_flows_' + magnitude + '.csv') forecast_list = [forecast_path] inundation_raster_list = [os.path.join(version_test_case_dir, 'inundation_extent.tif')] for index in range(0, len(benchmark_raster_path_list)): benchmark_raster_path = benchmark_raster_path_list[index] forecast = forecast_list[index] inundation_raster = inundation_raster_list[index] # Only need to define ahps_lid and ahps_extent_file for AHPS_BENCHMARK_CATEGORIES. if benchmark_category in AHPS_BENCHMARK_CATEGORIES: ahps_lid = lid_list[index] ahps_domain_file = domain_file_list[index] mask_dict.update({ahps_lid: {'path': ahps_domain_file, 'buffer': None, 'operation': 'include'} }) if not os.path.exists(benchmark_raster_path) or not os.path.exists(ahps_domain_file) or not os.path.exists(forecast): # Skip loop instance if the benchmark raster doesn't exist. continue else: # If not in AHPS_BENCHMARK_CATEGORIES. if not os.path.exists(benchmark_raster_path) or not os.path.exists(forecast): # Skip loop instance if the benchmark raster doesn't exist. continue # Run inundate. # print("-----> Running inundate() to produce modeled inundation extent for the " + magnitude + " magnitude...") try: inundate_test = inundate( rem,catchments,catchment_poly,hydro_table,forecast,mask_type,hucs=hucs,hucs_layerName=hucs_layerName, subset_hucs=current_huc,num_workers=1,aggregate=False,inundation_raster=inundation_raster,inundation_polygon=None, depths=None,out_raster_profile=None,out_vector_profile=None,quiet=True ) if inundate_test == 0: # print("-----> Inundation mapping complete.") predicted_raster_path = os.path.join(os.path.split(inundation_raster)[0], os.path.split(inundation_raster)[1].replace('.tif', '_' + current_huc + '.tif')) # The inundate adds the huc to the name so I account for that here. # Define outputs for agreement_raster, stats_json, and stats_csv. if benchmark_category in AHPS_BENCHMARK_CATEGORIES: agreement_raster, stats_json, stats_csv = os.path.join(version_test_case_dir, lid + 'total_area_agreement.tif'), os.path.join(version_test_case_dir, 'stats.json'), os.path.join(version_test_case_dir, 'stats.csv') else: agreement_raster, stats_json, stats_csv = os.path.join(version_test_case_dir, 'total_area_agreement.tif'), os.path.join(version_test_case_dir, 'stats.json'), os.path.join(version_test_case_dir, 'stats.csv') compute_contingency_stats_from_rasters(predicted_raster_path, benchmark_raster_path, agreement_raster, stats_csv=stats_csv, stats_json=stats_json, mask_values=[], stats_modes_list=stats_modes_list, test_id=test_id, mask_dict=mask_dict, ) if benchmark_category in AHPS_BENCHMARK_CATEGORIES: del mask_dict[ahps_lid] print(" ") print("Evaluation metrics for " + test_id + ", " + version + ", " + magnitude + " are available at " + CYAN_BOLD + version_test_case_dir + ENDC) print(" ") elif inundate_test == 1: pass print (f"No matching feature IDs between forecast and hydrotable for magnitude: {magnitude}") #return except Exception as e: print(e) if benchmark_category in AHPS_BENCHMARK_CATEGORIES: # -- Delete temp files -- # # List all files in the output directory. output_file_list = os.listdir(version_test_case_dir) for output_file in output_file_list: if "total_area" in output_file: full_output_file_path = os.path.join(version_test_case_dir, output_file) os.remove(full_output_file_path)
def run_inundation(args): """ This script is basically a wrapper for the inundate function and is designed for multiprocessing. Args: args (list): [fim_run_dir (str), huc (str), magnitude (str), magnitude_output_dir (str), config (str)] """ fim_run_dir = args[0] huc = args[1] magnitude = args[2] magnitude_output_dir = args[3] config = args[4] # Define file paths for use in inundate(). fim_run_parent = os.path.join(fim_run_dir, huc) rem = os.path.join(fim_run_parent, 'rem_zeroed_masked.tif') catchments = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes.tif') mask_type = 'huc' catchment_poly = '' hydro_table = os.path.join(fim_run_parent, 'hydroTable.csv') catchment_poly = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') inundation_raster = os.path.join( magnitude_output_dir, magnitude + '_' + config + '_inund_extent.tif') depth_raster = os.path.join(magnitude_output_dir, magnitude + '_' + config + '_inund_depth.tif') forecast = os.path.join(INUN_REVIEW_DIR, 'nwm_recurr_flow_data', 'recurr_' + magnitude + '_cms.csv') hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), 'WBDHU8' # Run inundate() once for depth and once for extent. if not os.path.exists(depth_raster): print("Running the NWM recurrence intervals for HUC: " + huc + ", " + magnitude + "...") inundate(rem, catchments, catchment_poly, hydro_table, forecast, mask_type, hucs=hucs, hucs_layerName=hucs_layerName, subset_hucs=huc, num_workers=1, aggregate=False, inundation_raster=None, inundation_polygon=None, depths=depth_raster, out_raster_profile=None, out_vector_profile=None, quiet=True) if not os.path.exists(inundation_raster): inundate(rem, catchments, catchment_poly, hydro_table, forecast, mask_type, hucs=hucs, hucs_layerName=hucs_layerName, subset_hucs=huc, num_workers=1, aggregate=False, inundation_raster=inundation_raster, inundation_polygon=None, depths=None, out_raster_profile=None, out_vector_profile=None, quiet=True)
def run_alpha_test(fim_run_dir, branch_name, test_id, magnitude, compare_to_previous=False, archive_results=False, mask_type='huc', inclusion_area='', inclusion_area_buffer=0, light_run=False): # Construct paths to development test results if not existent. if archive_results: branch_test_case_dir_parent = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'previous_versions', branch_name) else: branch_test_case_dir_parent = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'development_versions', branch_name) # Delete the entire directory if it already exists. if os.path.exists(branch_test_case_dir_parent): shutil.rmtree(branch_test_case_dir_parent) print("Running the alpha test for test_id: " + test_id + ", " + branch_name + "...") stats_modes_list = ['total_area'] fim_run_parent = os.path.join(os.environ['outputDataDir'], fim_run_dir) assert os.path.exists(fim_run_parent), "Cannot locate " + fim_run_parent # Create paths to fim_run outputs for use in inundate(). rem = os.path.join(fim_run_parent, 'rem_zeroed_masked.tif') catchments = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes.tif') if mask_type == 'huc': catchment_poly = '' else: catchment_poly = os.path.join( fim_run_parent, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') hydro_table = os.path.join(fim_run_parent, 'hydroTable.csv') # Map necessary inputs for inundation(). hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), 'WBDHU8' benchmark_category = test_id.split('_')[1] current_huc = test_id.split('_')[ 0] # Break off HUC ID and assign to variable. # Create list of shapefile paths to use as exclusion areas. zones_dir = os.path.join(TEST_CASES_DIR, 'other', 'zones') mask_dict = { 'levees': { 'path': os.path.join(zones_dir, 'leveed_areas_conus.shp'), 'buffer': None, 'operation': 'exclude' }, 'waterbodies': { 'path': os.path.join(zones_dir, 'nwm_v2_reservoirs.shp'), 'buffer': None, 'operation': 'exclude', }, } if not os.path.exists(branch_test_case_dir_parent): os.mkdir(branch_test_case_dir_parent) # If the test_id is AHPS, then identify possible inclusion zones in the HUC. if benchmark_category == 'ahps': ahps_inclusion_zones_dir = os.path.join(branch_test_case_dir_parent, 'ahps_domains') print(ahps_inclusion_zones_dir) if not os.path.exists(ahps_inclusion_zones_dir): os.mkdir(ahps_inclusion_zones_dir) ahps_domain_shapefile = os.path.join(TEST_CASES_DIR, 'other', 'zones', 'ahps_domains.shp') # Open shapefile, determine the polys in the huc, create a different shapefile for each poly--name according to AHPS. ahps_domain_obj = gpd.read_file(ahps_domain_shapefile) ahps_domain_gdf = gpd.GeoDataFrame(ahps_domain_obj) # Loop through entries and compare against the huc4_list to get available HUCs within the geopackage domain. for index, row in ahps_domain_gdf.iterrows(): huc8_code = row['huc8_code'] ahps = row['ahps_code'] if huc8_code == current_huc: ahps_domain_subset = ahps_domain_obj[ahps_domain_obj.ahps_code == ahps] #.query("ahps_code=='{ahps_code}'".format(ahps_code=ahps_code)) ahps_domain_subset_output = os.path.join( ahps_inclusion_zones_dir, ahps + '.shp') ahps_domain_subset.to_file(ahps_domain_subset_output, driver='ESRI Shapefile') mask_dict.update({ ahps: { 'path': ahps_domain_subset_output, 'buffer': None, 'operation': 'include' } }) if inclusion_area != '': inclusion_area_name = os.path.split(inclusion_area)[1].split('.')[ 0] # Get layer name mask_dict.update({ inclusion_area_name: { 'path': inclusion_area, 'buffer': int(inclusion_area_buffer), 'operation': 'include' } }) # Append the concatenated inclusion_area_name and buffer. if inclusion_area_buffer == None: inclusion_area_buffer = 0 stats_modes_list.append(inclusion_area_name + '_b' + str(inclusion_area_buffer) + 'm') # Check if magnitude is list of magnitudes or single value. magnitude_list = magnitude if type(magnitude_list) != list: magnitude_list = [magnitude_list] for magnitude in magnitude_list: # Construct path to validation raster and forecast file. benchmark_raster_path = os.path.join( TEST_CASES_DIR, 'validation_data_' + benchmark_category, current_huc, magnitude, benchmark_category + '_huc_' + current_huc + '_depth_' + magnitude + '.tif') if not os.path.exists( benchmark_raster_path ): # Skip loop instance if the benchmark raster doesn't exist. continue branch_test_case_dir = os.path.join(branch_test_case_dir_parent, magnitude) os.makedirs(branch_test_case_dir) # Make output directory for branch. # Define paths to inundation_raster and forecast file. inundation_raster = os.path.join(branch_test_case_dir, 'inundation_extent.tif') forecast = os.path.join( TEST_CASES_DIR, 'validation_data_' + benchmark_category, current_huc, magnitude, benchmark_category + '_huc_' + current_huc + '_flows_' + magnitude + '.csv') # Run inundate. print( "-----> Running inundate() to produce modeled inundation extent for the " + magnitude + " magnitude...") inundate(rem, catchments, catchment_poly, hydro_table, forecast, mask_type, hucs=hucs, hucs_layerName=hucs_layerName, subset_hucs=current_huc, num_workers=1, aggregate=False, inundation_raster=inundation_raster, inundation_polygon=None, depths=None, out_raster_profile=None, out_vector_profile=None, quiet=True) print("-----> Inundation mapping complete.") predicted_raster_path = os.path.join( os.path.split(inundation_raster)[0], os.path.split(inundation_raster)[1].replace( '.tif', '_' + current_huc + '.tif') ) # The inundate adds the huc to the name so I account for that here. # Define outputs for agreement_raster, stats_json, and stats_csv. agreement_raster, stats_json, stats_csv = os.path.join( branch_test_case_dir, 'total_area_agreement.tif'), os.path.join( branch_test_case_dir, 'stats.json'), os.path.join(branch_test_case_dir, 'stats.csv') test_version_dictionary = compute_contingency_stats_from_rasters( predicted_raster_path, benchmark_raster_path, agreement_raster, stats_csv=stats_csv, stats_json=stats_json, mask_values=[], stats_modes_list=stats_modes_list, test_id=test_id, mask_dict=mask_dict, ) print(" ") print("Evaluation complete. All metrics for " + test_id + ", " + branch_name + ", " + magnitude + " are available at " + CYAN_BOLD + branch_test_case_dir + ENDC) print(" ") if compare_to_previous: text_block = [] # Compare to previous stats files that are available. archive_to_check = os.path.join(TEST_CASES_DIR, test_id, 'performance_archive', 'previous_versions') for stats_mode in stats_modes_list: archive_dictionary = profile_test_case_archive( archive_to_check, magnitude, stats_mode) if archive_dictionary == {}: break # Create header for section. header = [stats_mode] for previous_version, paths in archive_dictionary.items(): header.append(previous_version) header.append(branch_name) text_block.append(header) # Loop through stats in PRINTWORTHY_STATS for left. for stat in PRINTWORTHY_STATS: stat_line = [stat] for previous_version, paths in archive_dictionary.items(): # Load stats for previous version. previous_version_stats_json_path = paths['stats_json'] if os.path.exists(previous_version_stats_json_path): previous_version_stats_dict = json.load( open(previous_version_stats_json_path)) # Append stat for the version to state_line. stat_line.append(previous_version_stats_dict[stat]) # Append stat for the current version to stat_line. stat_line.append(test_version_dictionary[stats_mode][stat]) text_block.append(stat_line) text_block.append([" "]) regression_report_csv = os.path.join(branch_test_case_dir, 'stats_summary.csv') with open(regression_report_csv, 'w', newline='') as csvfile: csv_writer = csv.writer(csvfile) csv_writer.writerows(text_block) print() print( "--------------------------------------------------------------------------------------------------" ) stats_mode = stats_modes_list[0] try: last_version_index = text_block[0].index('dev_latest') except ValueError: try: last_version_index = text_block[0].index('fim_2_3_3') except ValueError: try: last_version_index = text_block[0].index('fim_1_0_0') except ValueError: print( TRED_BOLD + "Warning: " + ENDC + "Cannot compare " + branch_name + " to a previous version because no authoritative versions were found in previous_versions directory. Future version of run_test_case may allow for comparisons between dev branches." ) print() continue for line in text_block: first_item = line[0] if first_item in stats_modes_list: current_version_index = line.index(branch_name) if first_item != stats_mode: # Update the stats_mode and print a separator. print() print() print( "--------------------------------------------------------------------------------------------------" ) print() stats_mode = first_item print(CYAN_BOLD + current_huc + ": " + magnitude.upper(), ENDC) print(CYAN_BOLD + stats_mode.upper().replace('_', ' ') + " METRICS" + ENDC) print() color = WHITE_BOLD metric_name = ' '.center( len(max(PRINTWORTHY_STATS, key=len))) percent_change_header = '% CHG' difference_header = 'DIFF' current_version_header = line[current_version_index].upper( ) last_version_header = line[last_version_index].upper() # Print Header. print( color + metric_name + " " + percent_change_header.center( (7)) + " " + difference_header.center((15)) + " " + current_version_header.center(18) + " " + last_version_header.center(18), ENDC) # Format and print stat row. elif first_item in PRINTWORTHY_STATS: stat_name = first_item.upper().center( len(max(PRINTWORTHY_STATS, key=len))).replace('_', ' ') current_version = round((line[current_version_index]), 3) last_version = round((line[last_version_index]) + 0.000, 3) difference = round(current_version - last_version, 3) if difference > 0: symbol = '+' if first_item in GO_UP_STATS: color = TGREEN_BOLD elif first_item in GO_DOWN_STATS: color = TRED_BOLD else: color = TWHITE if difference < 0: symbol = '-' if first_item in GO_UP_STATS: color = TRED_BOLD elif first_item in GO_DOWN_STATS: color = TGREEN_BOLD else: color = TWHITE if difference == 0: symbol, color = '+', TGREEN percent_change = round((difference / last_version) * 100, 2) print( WHITE_BOLD + stat_name + ENDC + " " + color + (symbol + " {:5.2f}".format(abs(percent_change)) + " %").rjust(len(percent_change_header)), ENDC + " " + color + ("{:12.3f}".format( (difference))).rjust(len(difference_header)), ENDC + " " + "{:15.3f}".format(current_version).rjust( len(current_version_header)) + " " + "{:15.3f}".format(last_version).rjust( len(last_version_header)) + " ") print() print() print() print( "--------------------------------------------------------------------------------------------------" ) print()
def run_recurr_test(fim_run_dir, branch_name, huc_id, input_flow_csv, mask_type='huc'): # Construct paths to development test results if not existent. huc_id_dir_parent = os.path.join(TEST_CASES_DIR, huc_id) if not os.path.exists(huc_id_dir_parent): os.mkdir(huc_id_dir_parent) branch_test_case_dir_parent = os.path.join(TEST_CASES_DIR, huc_id, branch_name) # Delete the entire directory if it already exists. if os.path.exists(branch_test_case_dir_parent): shutil.rmtree(branch_test_case_dir_parent) print("Running the NWM recurrence intervals for HUC: " + huc_id + ", " + branch_name + "...") assert os.path.exists(fim_run_dir), "Cannot locate " + fim_run_dir # Create paths to fim_run outputs for use in inundate(). if "previous_fim" in fim_run_dir and "fim_2" in fim_run_dir: rem = os.path.join(fim_run_dir, 'rem_clipped_zeroed_masked.tif') catchments = os.path.join( fim_run_dir, 'gw_catchments_reaches_clipped_addedAttributes.tif') if not os.path.isfile(rem): print('Can not find REM file: ' + str(rem)) if not os.path.isfile(catchments): print('Can not find catchments file: ' + str(catchments)) else: rem = os.path.join(fim_run_dir, 'rem_zeroed_masked.tif') catchments = os.path.join( fim_run_dir, 'gw_catchments_reaches_filtered_addedAttributes.tif') if not os.path.isfile(rem): print('Can not find REM file: ' + str(rem)) if not os.path.isfile(catchments): print('Can not find catchments file: ' + str(catchments)) if mask_type == 'huc': catchment_poly = '' print( 'Not using the catchment polygon input layer -- FIM version < 3??') else: catchment_poly = os.path.join( fim_run_dir, 'gw_catchments_reaches_filtered_addedAttributes_crosswalked.gpkg') if not os.path.isfile(catchment_poly): print('Can not find catchments polygon file: ' + str(catchments)) hydro_table = os.path.join(fim_run_dir, 'hydroTable.csv') if not os.path.isfile(hydro_table): print('Can not find hydro_table file: ' + str(hydro_table)) #benchmark_category = huc_id.split('_')[1] current_huc = huc_id.split('_')[ 0] # Break off HUC ID and assign to variable. wbd_huc = 'WBDHU' + str( len(huc_id)) # check if the input huc is 2,4,6,8 etc # Map necessary inputs for inundation(). hucs, hucs_layerName = os.path.join(INPUTS_DIR, 'wbd', 'WBD_National.gpkg'), wbd_huc if not os.path.exists(branch_test_case_dir_parent): os.mkdir(branch_test_case_dir_parent) #branch_test_case_dir = os.path.join(branch_test_case_dir_parent) #os.makedirs(branch_test_case_dir) # Make output directory for branch. # Define paths to inundation_raster and forecast file. inundation_raster = os.path.join(branch_test_case_dir_parent, branch_name + '_inund_extent.tif') forecast = os.path.join(TEST_CASES_DIR, "_input_flow_files", input_flow_csv) if not os.path.isfile(forecast): print('Can not find input flow file: ' + str(forecast)) # Copy forecast flow file into the outputs directory to all viewer to reference the flows used to create inundation_raster shutil.copyfile(forecast, os.path.join(branch_test_case_dir_parent, input_flow_csv)) # Run inundate. print( "-----> Running inundate() to produce modeled inundation extent for the " + input_flow_csv) inundate(rem, catchments, catchment_poly, hydro_table, forecast, mask_type, hucs=hucs, hucs_layerName=hucs_layerName, subset_hucs=current_huc, num_workers=1, aggregate=False, inundation_raster=inundation_raster, inundation_polygon=None, depths=None, out_raster_profile=None, out_vector_profile=None, quiet=False) print("-----> Inundation mapping complete.") if not os.path.isfile(inundation_raster): print('Warning!! Inundation Raster not produced: ' + str(inundation_raster))