예제 #1
0
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))
예제 #2
0
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()
예제 #3
0
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.")
예제 #4
0
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)
예제 #5
0
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)
예제 #6
0
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()
예제 #7
0
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))