diff --git a/src/subscript/field_statistics/field_statistics.py b/src/subscript/field_statistics/field_statistics.py index 5cd26bcc9..2463adf02 100644 --- a/src/subscript/field_statistics/field_statistics.py +++ b/src/subscript/field_statistics/field_statistics.py @@ -352,6 +352,14 @@ def field_stat(args): if rms_load_script: generate_script(rms_load_script, ert_config_path, result_path, config_file) + calc_temporary_field_stats( + field_stat, + ens_path, + result_path, + ert_config_path, + ertbox_size, + ) + logger.info( "Finished running workflow to calculate statistics " "for ensemble of field parameters" @@ -790,13 +798,13 @@ def write_mean_stdev_nactive( param_name=param_name, ) - logger.info(f"Write parameter: {name_mean}") + logger.info(f" Write parameter: {name_mean}") xtgeo_ertbox_mean.to_file(result_mean_file_path, fformat="roff") - logger.info(f"Write parameter: {name_stdev}") + logger.info(f" Write parameter: {name_stdev}") xtgeo_ertbox_stdev.to_file(result_stdev_file_path, fformat="roff") - logger.info(f"Write parameter: {name_nactive}") + logger.info(f" Write parameter: {name_nactive}") xtgeo_ertbox_ncount_active.to_file(result_nactive_file_path, fformat="roff") @@ -852,7 +860,7 @@ def ertbox_to_geogrid_statistics( zone_conformity, initialize_geogrid_property_param_values=init_geogrid_param, ) - logger.info(f"Update geogrid parameter: {xtgeo_prop_geogrid_stat.name}") + logger.info(f" Update geogrid parameter: {xtgeo_prop_geogrid_stat.name}") xtgeo_prop_geogrid_stat.to_file(geogrid_stat_file_name, fformat="roff") @@ -892,7 +900,7 @@ def write_fraction_nactive( values=ertbox_fraction, ) - logger.info(f"Write parameter: {name_fraction}") + logger.info(f" Write parameter: {name_fraction}") xtgeo_ertbox_fraction.to_file(ertbox_result_fraction_file_path, fformat="roff") if ncount_active_values is not None: @@ -904,7 +912,7 @@ def write_fraction_nactive( values=ncount_active_values, ) - logger.info(f"Write parameter: {name_nactive}") + logger.info(f" Write parameter: {name_nactive}") xtgeo_ertbox_ncount_active.to_file( ertbox_result_nactive_file_path, fformat="roff" ) @@ -1001,6 +1009,30 @@ def get_specifications(input_dict, ertbox_size, ert_config_path): check_used_params(zone_names_used, param_name_dict, disc_param_name_dict) + temporary_ertbox_field = None + init_path = None + param_list = None + key = "temporary_ertbox_fields" + if key in input_dict: + temporary_ertbox_field = input_dict[key] + + key = "initial_relative_path" + if key in temporary_ertbox_field: + init_path = temporary_ertbox_field[key] + else: + raise KeyError( + f"Missing keyword: {key} " + "specifying relative path for initial temporary fields." + ) + key = "parameter_names" + if key in temporary_ertbox_field: + param_list = temporary_ertbox_field[key] + else: + raise KeyError( + f"Missing keyword: {key} " + "specifying list of temporary field parameter names." + ) + return ( ertbox_size, nreal, @@ -1011,6 +1043,8 @@ def get_specifications(input_dict, ertbox_size, ert_config_path): use_population_stdev, param_name_dict, disc_param_name_dict, + init_path, + param_list, ) @@ -1142,6 +1176,8 @@ def calc_stats( use_population_stdev, param_name_dict, disc_param_name_dict, + _, + _, ) = get_specifications(input_dict, ertbox_size, ert_config_path) ensemble_path = ens_path @@ -1156,7 +1192,7 @@ def calc_stats( if zone_name not in param_name_dict: continue for param_name in param_name_dict[zone_name]: - logger.info(f"Property: {param_name}") + logger.info(f" Property: {param_name}") all_values = np.ma.masked_all( (ertbox_size[0], ertbox_size[1], ertbox_size[2], nreal), dtype=np.float32, @@ -1235,7 +1271,7 @@ def calc_stats( if zone_name not in disc_param_name_dict: continue for param_name in disc_param_name_dict[zone_name]: - logger.info(f"Property: {param_name}") + logger.info(f" Property: {param_name}") all_values = np.ma.masked_all( (ertbox_size[0], ertbox_size[1], ertbox_size[2], nreal), dtype=np.int32, @@ -1291,17 +1327,19 @@ def calc_stats( sum_total_active = np.ma.sum(sum_active) / nreal sum_total_code = np.ma.sum(number_of_cells) / nreal fraction = sum_total_code / sum_total_active - txt1 = f"Average number of active cells: {sum_total_active}" + txt1 = ( + f" Average number of active cells: {sum_total_active}" + ) logger.info(txt1) txt2 = ( - f"Average number of cells with facies " + f" Average number of cells with facies " f"{facies_name} is {sum_total_code}" ) logger.info(txt2) txt3 = ( - "Average estimated facies probability for facies " + " Average estimated facies probability for facies " f"{facies_name}: {fraction}" ) logger.info(txt3) @@ -1338,7 +1376,7 @@ def calc_stats( zone_code_names, copy_to_geogrid_realization=copy_to_geogrid_realization, ) - txt4 = f"Sum facies volume fraction: {sum_fraction}" + txt4 = f" Sum facies volume fraction: {sum_fraction}" logger.info(txt4) else: txt = ( @@ -1349,6 +1387,112 @@ def calc_stats( logger.info(txt) +def calc_temporary_field_stats( + input_dict, + ens_path, + result_path, + ert_config_path, + ertbox_size, +): + ( + ertbox_size, + nreal, + iter_list, + _, + _, + _, + use_population_stdev, + _, + _, + init_path, + param_list, + ) = get_specifications(input_dict, ertbox_size, ert_config_path) + + # Check if any need to continue to calculation + if not init_path or not param_list: + return + + # Import realizations of temporary field parameters + for param_name in param_list: + for iteration in iter_list: + param_filename = param_name + ".roff" + if iteration == 0: + full_param_filename = init_path + "/" + param_filename + elif iteration == iter_list[-1]: + full_param_filename = param_filename + logger.info(f"Property: {param_name}") + all_values = np.ma.masked_all( + (ertbox_size[0], ertbox_size[1], ertbox_size[2], nreal), + dtype=np.float32, + ) + + number_of_skipped = 0 + for real_number in range(nreal): + filepath = ( + ens_path + / Path( + "realization-" + str(real_number) + "/iter-" + str(iteration) + ) + / Path(full_param_filename) + ) + print(f"File: {filepath} ") + if not filepath.exists(): + txt = f" Skip non-existing realization: {real_number}" + logger.info(txt) + number_of_skipped += 1 + continue + property = xtgeo.gridproperty_from_file(filepath, fformat="roff") + values = property.values + all_values[:, :, :, real_number] = values + + # Calculate statistics + calc_mean = False + calc_stdev = False + mean_values_masked = None + stdev_values_masked = None + if number_of_skipped < nreal: + # Mean value + mean_values_masked = all_values.mean(axis=3) + calc_mean = True + if number_of_skipped < (nreal - 1): + # Std deviation + if use_population_stdev: + stdev_values_masked = all_values.std(axis=3, ddof=0) + else: + stdev_values_masked = all_values.std(axis=3, ddof=1) + calc_stdev = True + + # Write results to result directory + # Fill masked values with 0 + if calc_mean: + ertbox_mean_values = mean_values_masked.filled(fill_value=0.0) + name_mean = "mean_" + param_name + result_mean_file_path = result_path / Path(name_mean + ".roff") + xtgeo_ertbox_mean = xtgeo.GridProperty( + ncol=ertbox_size[0], + nrow=ertbox_size[1], + nlay=ertbox_size[2], + name=name_mean, + values=ertbox_mean_values, + ) + logger.info(f" Write parameter: {name_mean}") + xtgeo_ertbox_mean.to_file(result_mean_file_path, fformat="roff") + + if calc_stdev: + ertbox_stdev_values = stdev_values_masked.filled(fill_value=0.0) + name_stdev = "stdev_" + param_name + result_stdev_file_path = result_path / Path(name_stdev + ".roff") + xtgeo_ertbox_stdev = xtgeo.GridProperty( + ncol=ertbox_size[0], + nrow=ertbox_size[1], + nlay=ertbox_size[2], + name=name_stdev, + values=ertbox_stdev_values, + ) + logger.info(f" Write parameter: {name_stdev}") + xtgeo_ertbox_stdev.to_file(result_stdev_file_path, fformat="roff") + + def generate_script( rms_load_script, ert_config_path, result_path, field_stat_config_file ): @@ -1360,6 +1504,11 @@ def generate_script( import yaml import fmu.config.utilities as utils +# Edit this label to fit your case +LABEL = "drogon" + +# -------- Usually no need to edit the code below to fit your case ---------- + PRJ = project GRIDNAME = "ERTBOX" @@ -1374,8 +1523,6 @@ def generate_script( RESULT_PATH = Path("{result_path}") -LABEL = "drogon" - def read_field_stat_config(config_file_name): print(f"Read file: {{config_file_name}}") with open(config_file_name, encoding="utf-8") as yml_file: diff --git a/tests/test_field_statistics.py b/tests/test_field_statistics.py index 1b3426219..0b9a5b4cf 100644 --- a/tests/test_field_statistics.py +++ b/tests/test_field_statistics.py @@ -863,6 +863,8 @@ def test_get_specification( use_population_stdev, param_name_dict, disc_param_name_dict, + _, + _, ) = get_specifications(input_dict, ertbox_size, ert_config_path) assert ertbox_size == reference_dict["ertbox_size"] assert zone_names == reference_dict["use_zones"]