diff --git a/tests/jobs/localisation/example_case/README b/tests/jobs/localisation/example_case/README new file mode 100644 index 000000000..1c4dcfa8d --- /dev/null +++ b/tests/jobs/localisation/example_case/README @@ -0,0 +1,60 @@ +Directory for test case for non-adaptive localisation (LOCALISATION_JOB) +Main components: +ERT config file: sim_field.ert + +The ERT model depends on: +scripts/sim_fields.py +scripts/common_functions.py + +Example of optional input config scripts to +scripts/init_test_case.py and scripts/sim_fields.py: +example_case.yml +modify_variogram.yml + +ERT keyword input: +GRID: Input grid is made by scripts/init_test_case.py +OBS_CONFIG: Observations are extracted from an upscaled realization made by scripts/init_test_case.py +GEN_DATA : Prediction of observables made by forward model SIM_FIELD which runs scripts/sim_fields.py +FIELD: Prior realizations of field made by forward model SIM_FIELD which runs scripts/sim_fields.py + +Other ERT input files: +time_map.txt +localisation.wf + +Other files: +randomseeds.txt - Not used by ERT, but by sim_fields.py + This file can be generated by scripts/init_test_case.py +UpscaledGrid.EGRID - Not used by ERT, but by scripts/sim_fields.py + This file can be generated by scripts/init_test_case.py + +Typical workflow: +1. Prepare ERT config input by running scripts/init_test_case.py. If run without any arguments, a set of hardcoded + default settings are used. Optionally add one argument (a yml file where the settings for the test case can be modified. + See example of two such yml files: example_case.yml containing all available settings and modify_variogram.yml + where only a few parameters are modified and the rest of the settings are using default values. + Edit the input yml file to change settings. +2. Directories for observations are created automatically according to the default (or modified) settings. +3. Make the directory init_files if not existing. +4. Run the script init_test_case.py located under scripts from the example_case dirctory. + Run it with or without one argument which is a specification of settings. + Default settings are used for settings not specified. The file can be ommited if one want to use the default + settings for all parameters. Example file containing all possible settings is the file example_case.yml +5. If non-default settings are specified and the init_test_case.py is run with an yml file as argument, also the ERT forward + model SIM_FIELD need the same input as the third argument for the script sim_fields.py + The first two arguments are iteration and realisation number. Edit FM_SIM_FIELD and specify wanted settings file (yml file). +5. Activate/not activate localisation in ERT config file (HOOK_WORKFLOW LOAD_WORKFLOW for localisation) +6. Now ready to run ERT. + + + +What the script sim_fields.py do: +1. Get iteration and realisation number from ERT using ERT environment variables _ERT_ITERATION_NUMBER and _ERT_REALIZATION_NUMBER + If running with old komodo version, the script will require iteration and realisation_number as command line input and optionally the yml settings file. +2. If iteration = 0 then + simulate field and export to file to be used in FIELD keyword in ERT config file. + upscale field and optionally export to file for QC purpose + else + import updated field from ERT + upscale field and optionally export file for QC purpose +3. Extract predicted values of observables from upscaled field (values for some selected grid cells related to the upscaled grid) and write GEN_DATA files +4. Optionally write some files for QC purpose. diff --git a/tests/jobs/localisation/example_case/example_case.yml b/tests/jobs/localisation/example_case/example_case.yml new file mode 100644 index 000000000..f0418b998 --- /dev/null +++ b/tests/jobs/localisation/example_case/example_case.yml @@ -0,0 +1,44 @@ +settings: + grid_size: + xsize: 7500.0 + ysize: 12500.0 + zsize: 50.0 + use_eclipse_grid_index_origo: "eclipse" + + field: + name: "FIELDPARAM" + initial_file_name: "init_files/FieldParam.roff" + updated_file_name: "FieldParam.roff" + seed_file: "randomseeds.txt" + variogram: "gaussian" + correlation_range: [5000.0, 3000.0, 2.0] + correlation_azimuth: 45.0 + correlation_dip: 0.0 + trend_use: False + trend_params: [ 1.0, -1.0 ] + trend_relstd: 0.15 + grid_dimension: [150, 250, 1] + grid_file_name: "GRID.EGRID" + + response: + grid_dimension: [15, 25, 1] + upscaled_file_name: "Upscaled.roff" + grid_file_name: "UpscaleGrid.EGRID" + response_function: "average" + gen_data_file_name: "UpscaledField_0.txt" + calculate_all_cells: True + + observation: + directory: "observations" + file_name: "observations.obs" + data_dir: "obs_data" + 3D_param_file_name: "init_files/UpscaledObsField.roff" + rel_error: 0.10 + min_abs_error: 0.01 + selected_grid_cells: + - [5, 10, 1] + - [10, 20, 1] + + optional: + write_upscaled_to_file: True + write_obs_pred_diff_field_file: True diff --git a/tests/jobs/localisation/example_case/init_files/README b/tests/jobs/localisation/example_case/init_files/README new file mode 100644 index 000000000..2abda6e8d --- /dev/null +++ b/tests/jobs/localisation/example_case/init_files/README @@ -0,0 +1,7 @@ +Directory where initial ensemble realisation is saved: +FieldParam.roff - The field parameter +Upscaled.roff - The upscaled field parameter (for QC purpose) +UpscaledObsField.roff - The upscaled field parameter used when + extracting observations (selected grid cells to be used as observables) +UpscaledConditionedCells.roff - A coarse grid parameter with all cells except the cells defined as observable + with a dummy value and the observable grid cells with the values used as observations. diff --git a/tests/jobs/localisation/example_case/localisation.wf b/tests/jobs/localisation/example_case/localisation.wf new file mode 100644 index 000000000..c6477f3d7 --- /dev/null +++ b/tests/jobs/localisation/example_case/localisation.wf @@ -0,0 +1 @@ +LOCALISATION_JOB local_config.yml diff --git a/tests/jobs/localisation/example_case/modify_variogram.yml b/tests/jobs/localisation/example_case/modify_variogram.yml new file mode 100644 index 000000000..144f36523 --- /dev/null +++ b/tests/jobs/localisation/example_case/modify_variogram.yml @@ -0,0 +1,5 @@ +settings: + + field: + variogram: "spherical" + correlation_range: [4000.0, 4000.0, 2.0] diff --git a/tests/jobs/localisation/example_case/scripts/FM_SIM_FIELD b/tests/jobs/localisation/example_case/scripts/FM_SIM_FIELD new file mode 100644 index 000000000..1611d40ff --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/FM_SIM_FIELD @@ -0,0 +1,6 @@ +EXECUTABLE ./sim_fields.py + +ARGLIST + +STDERR sim_fields.stderr +STDOUT sim_fields.stdout diff --git a/tests/jobs/localisation/example_case/scripts/README b/tests/jobs/localisation/example_case/scripts/README new file mode 100644 index 000000000..9c2c35e63 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/README @@ -0,0 +1,13 @@ +Source code scripts: +common_functions.py - Functions used by the two scripts init_test_case.py and sim_fields.py +init_test_case.py - Create grid files, random seed file localisation config file and observation files for the test case +sim_fields.py - This script is run from ERT config file as a FORWARD model. +FM_SIM_FIELD - ERT configuration of forward model SIM_FIELD + using sim_fields.py. + +Scripts used in RMS project to load and visualize the realizations. +These are not needed to run the test and alternatives for visualizing the realizations exists (coviz, webviz?): +import_field_parameters.py +import_field_parameters_local.py +import_upscaled_field_parameters_local.py +import_upscaled_field_parameters.py diff --git a/tests/jobs/localisation/example_case/scripts/__init__.py b/tests/jobs/localisation/example_case/scripts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/jobs/localisation/example_case/scripts/common_functions.py b/tests/jobs/localisation/example_case/scripts/common_functions.py new file mode 100644 index 000000000..45d63bd7b --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/common_functions.py @@ -0,0 +1,507 @@ +""" +Common functions used by the scripts: init_test_case.py and sim_field.py +""" +import copy + +import numpy as np +import yaml + +import xtgeo # isort: skip +import gaussianfft as sim # isort: skip + + +# NOTE: xtgeo MUST be imported BEFORE gaussianfft +# The reason is that xtgeo has functions importing roxar API and +# even though this is not used, the code will crash with core dump +# since Roxar API and gaussianfft both use Boost to wrap C++ code +# into python functions but Roxar API and gaussianfft uses two +# slightly different versions of Boost. +# The gaussianfft module uses version 1.76 which is newer than +# version 1.74 from Roxar API (and indirectly xtgeo) +# which may explain why it works importing gaussianfft after +# xtgeo (and Roxar API module roxar). We don't know exactly the reason +# for the core dump with wrong sequence of the import's, but probably +# it is due to some initialization related to the Boost library and +# Boost version 1.74.0 is not compatible with any initialization done by +# version 1.76. +# +# The message related to Boost and RMS (and then indirectly also xtgeo) +# from Aspentech Support is this: +# "The current version of boost is 1.74.0 and this version has been used +# since RMS 12.1, and is still used in RMS V14.0.1 and V14.1. +# Boost version 1.81.0 will be available in version 14.2 or version 15. +# Thomas also write "Last time I checked, boost did not provide any +# compatibility guarantees, so it's not expected to work if you +# mix two different boost versions in the same process +# by loading python modules into RMS that uses other versions." + +# The current combination of gaussianfft and xtgeo (or RMS Roxar API) +# will work if xtgeo is imported first. But this may change later. +# The plan for gaussianfft is to ensure correct sequence of import by +# importing xtgeo (and when running from RMS, also roxar) in +# gaussianfft before calling any functions from the gaussianfft module. +# In this case it should work for the end user regardless of which sequence +# it is imported. The most robust solution would be to generate gaussianfft +# to use exactly the same. + + +# pylint: disable=missing-function-docstring, too-many-locals, invalid-name +# pylint: disable=bare-except, raise-missing-from +# pylint: disable= redefined-outer-name, too-many-nested-blocks + + +def specify_settings(spec_dict=None, yml_file_name=None): + """ + grid_size - length, width, thickness of a box containing the field + Same size is used for both fine scale grid with + the simulated field and the coarse scale grid + containing upscaled values of the simulated field. + + field - Define the dimension (number of grid cells) for fine scale grid, + name of output files and specification of model parameters for + simulation of gaussian field with option to use linear trend. + Relative standard deviation specify standard deviation of + gaussian residual field relative to the trends span of value + (max trend value - min trend value) + + response - Specify the coarse grid dimensions, name of file and type + of average operation to calculated upscaled values that + are predictions of observations of the same grid cells. + Which cell indices are observed are specified in + observation settings. + + observation - Specify name of files for generated observations + and also which grid cells from coarse grid is used + as observables. + (Cells that have values that are used as observations) + + optional - Specify if some optional files should be + written or not (for QC purpose) + """ + default_settings = { + "grid_size": { + "xsize": 7500.0, + "ysize": 12500.0, + "zsize": 50.0, + "use_eclipse_grid_index_origo": True, + }, + "field": { + "name": "FIELDPARAM", + "initial_file_name": "init_files/FieldParam.roff", + "updated_file_name": "FieldParam.roff", + "seed_file": "randomseeds.txt", + "variogram": "gaussian", + "correlation_range": [5000.0, 3000.0, 2.0], + "correlation_azimuth": 45.0, + "correlation_dip": 0.0, + "trend_use": 0, + "trend_params": [1.0, -1.0], + "trend_relstd": 0.05, + "grid_dimension": [150, 250, 1], + "grid_file_name": "GRID.EGRID", + }, + "response": { + "grid_dimension": [15, 25, 1], + "upscaled_file_name": "Upscaled.roff", + "grid_file_name": "UpscaleGrid.EGRID", + "response_function": "average", + "gen_data_file_name": "UpscaledField_0.txt", + "calculate_all_cells": True, + }, + "observation": { + "directory": "observations", + "file_name": "observations.obs", + "data_dir": "obs_data", + "3D_param_file_name": "init_files/UpscaledObsField.roff", + "rel_error": 0.10, + "min_abs_error": 0.01, + "selected_grid_cells": [ + [5, 10, 1], + [10, 20, 1], + ], + # "selected_grid_cells":[ + # [15, 1, 1], + # [15, 25, 1], + # [ 1, 25, 1], + # [ 1, 1, 1], + # [ 3, 3, 1], + # [ 5, 23, 1], + # [11, 4, 1], + # [ 3, 12, 1], + # [13, 18, 1], + # ], + }, + "optional": { + "write_upscaled_to_file": True, + "write_obs_pred_diff_field_file": True, + }, + } + + settings = copy.deepcopy(default_settings) + if spec_dict is not None: + main_key = "settings" + if main_key not in spec_dict: + raise KeyError(f"Missing main keyword {main_key} in file: {yml_file_name}") + settings_yml_dict = spec_dict[main_key] + valid_keys1 = default_settings.keys() + for key1 in settings_yml_dict.keys(): + if key1 in valid_keys1: + valid_keys2 = default_settings[key1].keys() + for key2 in settings_yml_dict[key1].keys(): + if key2 in valid_keys2: + print( + f"Modifying default setting for keyword '{key2}' " + f"under '{key1}' in file {yml_file_name} " + ) + settings[key1][key2] = settings_yml_dict[key1][key2] + else: + raise KeyError( + f"Unknown keyword '{key2}' specified under keyword '{key1}'" + f" in {yml_file_name}" + ) + else: + raise KeyError( + f"Unknown keyword '{key1}' specified under keyword '{main_key}'" + f" in {yml_file_name}" + ) + return settings + + +# def update_settings(settings_dict, spec_dict, main_key, sub_keys): +# if main_key in spec_dict: +# main_key_dict = spec_dict[main_key] +# print(f"main_key_dict: {main_key_dict}") +# if main_key_dict is not None: +# print(f"sub_keys: {sub_keys}") +# for key in sub_keys: +# if key in main_key_dict: +# print(f"Settings updated for:{main_key} with sub key: {key} ") +# settings_dict[key] = main_key_dict[key] +# return settings_dict + + +def read_test_config(config_file_name): + if config_file_name is None: + spec_dict = None + else: + words = config_file_name.split(".") + if words[-1].upper() not in ["YML", "YAML"]: + raise IOError( + f"Expecting input yaml file as last argument for script {__file__}. " + f"Got the file {config_file_name} " + ) + with open(config_file_name, "r", encoding="utf-8") as yml_file: + spec_dict = yaml.safe_load(yml_file) + + return specify_settings(spec_dict, config_file_name) + + +def generate_field_and_upscale(settings, real_number): + seed_file_name = settings["field"]["seed_file"] + relative_std = settings["field"]["trend_relstd"] + use_trend = settings["field"]["trend_use"] + + start_seed = get_seed(seed_file_name, real_number) + residual_field = simulate_field(settings, start_seed) + if use_trend == 1: + trend_field = trend(settings) + field3D = trend_field + relative_std * residual_field + else: + field3D = residual_field + + # Write field parameter for fine scale grid + field_object = export_field(settings, field3D) + field_values = field_object.values + + # Calculate upscaled values for selected coarse grid cells + upscaled_values = upscaling( + field_values, + settings, + write_field=True, + iteration=0, + ) + return upscaled_values + + +def get_seed(seed_file_name, r_number): + with open(seed_file_name, "r", encoding="utf8") as file: + lines = file.readlines() + try: + seed_value = int(lines[r_number - 1]) + except: # noqa: E722 + raise IOError("Seed value not found for realization {r_number} ") + return seed_value + + +def upscaling(field_values, settings, write_field=True, iteration=0): + response_function_name = settings["response"]["response_function"] + upscaled_file_name = settings["response"]["upscaled_file_name"] + NX, NY, NZ = settings["response"]["grid_dimension"] + calculate_all = settings["response"]["calculate_all_cells"] + + coarse_cell_index_list = settings["observation"]["selected_grid_cells"] + upscaled_values = np.zeros((NX, NY, NZ), dtype=np.float32, order="F") + upscaled_values[:, :, :] = -999 + + if response_function_name == "average": + upscaled_values = upscale_average( + field_values, coarse_cell_index_list, upscaled_values, use_all=calculate_all + ) + + if iteration == 0: + upscaled_file_name = "init_files/" + upscaled_file_name + + if write_field: + write_upscaled_field(upscaled_values, upscaled_file_name) + return upscaled_values + + +def write_upscaled_field( + upscaled_values, upscaled_file_name, selected_cell_index_list=None +): + nx, ny, nz = upscaled_values.shape + field_name = "Upscaled" + + field_object = xtgeo.grid3d.GridProperty( + ncol=nx, + nrow=ny, + nlay=nz, + values=upscaled_values, + discrete=False, + name=field_name, + ) + + print(f"Write upscaled field file: {upscaled_file_name} ") + field_object.to_file(upscaled_file_name, fformat="roff") + if selected_cell_index_list is not None: + selected_upscaled_values = np.zeros((nx, ny, nz), dtype=np.float32, order="F") + selected_upscaled_values[:, :, :] = -1 + for indices in selected_cell_index_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + Kindx = indices[2] - 1 + selected_upscaled_values[Iindx, Jindx, Kindx] = upscaled_values[ + Iindx, Jindx, Kindx + ] + + field_name_selected = field_name + "_conditioned_cells" + file_name_selected = "init_files/" + field_name_selected + ".roff" + cond_field_object = xtgeo.grid3d.GridProperty( + ncol=nx, + nrow=ny, + nlay=nz, + values=selected_upscaled_values, + discrete=False, + name=field_name_selected, + ) + print(f"Write conditioned cell values as field: {file_name_selected}") + cond_field_object.to_file(file_name_selected, fformat="roff") + + return field_object + + +def upscale_average( + field_values, coarse_cell_index_list, upscaled_values, use_all=False +): + """ + Input: field_values (numpy 3D) + coarse_cell_index_list (list of tuples (I,J,K)) + Output: upscaled_values (numpy 3D) initialized outside + but filled in specified (I,J,K) cells. + """ + nx, ny, nz = field_values.shape + NX, NY, NZ = upscaled_values.shape + + print(f"Number of fine scale grid cells: (nx,ny,nz): ({nx},{ny},{nz})") + print(f"Number of coarse scale grid cells: (NX,NY,NZ): ({NX},{NY},{NZ}) ") + mx = int(nx / NX) + my = int(ny / NY) + mz = int(nz / NZ) + print( + "Number of fine scale grid cells per coarse grid cell: " + f"(mx,my,mz): ({mx},{my},{mz}) " + ) + if use_all: + print("Calculate upscaled values for all grid cells") + for Kindx in range(NZ): + for Jindx in range(NY): + for Iindx in range(NX): + istart = mx * Iindx + iend = istart + mx + jstart = my * Jindx + jend = jstart + my + kstart = mz * Kindx + kend = kstart + mz + sum_val = 0.0 + for k in range(kstart, kend): + for j in range(jstart, jend): + for i in range(istart, iend): + sum_val += field_values[i, j, k] + upscaled_values[Iindx, Jindx, Kindx] = sum_val / (mx * my * mz) + + else: + print("Calculate upscaled values for selected grid cells") + for indices in coarse_cell_index_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + Kindx = indices[2] - 1 + istart = mx * Iindx + iend = istart + mx + jstart = my * Jindx + jend = jstart + my + kstart = mz * Kindx + kend = kstart + mz + sum_val = 0.0 + for k in range(kstart, kend): + for j in range(jstart, jend): + for i in range(istart, iend): + sum_val += field_values[i, j, k] + upscaled_values[Iindx, Jindx, Kindx] = sum_val / (mx * my * mz) + + return upscaled_values + + +def write_prediction_gen_data(upscaled_values, settings): + cell_indx_list = settings["observation"]["selected_grid_cells"] + response_file_name = settings["response"]["gen_data_file_name"] + print(f"Write GEN_DATA file with prediction of observations: {response_file_name}") + with open(response_file_name, "w", encoding="utf8") as file: + # NOTE: The sequence of values must be the same as for the observations + for indices in cell_indx_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + Kindx = indices[2] - 1 + value = upscaled_values[Iindx, Jindx, Kindx] + print(f"Prediction of obs for {Iindx+1},{Jindx+1},{Kindx+1}: {value}") + file.write(f"{value}\n") + + +def trend(settings): + """ + Return 3D numpy array with values following a linear trend + scaled to take values between 0 and 1. + """ + nx, ny, nz = settings["field"]["grid_dimension"] + xsize = settings["grid_size"]["xsize"] + ysize = settings["grid_size"]["ysize"] + a, b = settings["field"]["trend_params"] + + x0 = 0.0 + y0 = 0.0 + dx = xsize / nx + dy = ysize / ny + + maxsize = ysize + if xsize > ysize: + maxsize = xsize + + val = np.zeros((nx, ny, nz), dtype=np.float32, order="F") + for i in range(nx): + x = x0 + i * dx + for j in range(ny): + y = y0 + j * dy + for k in range(nz): + val[i, j, k] = a * (x - x0) / maxsize + b * (y - y0) / maxsize + + minval = np.min(val) + maxval = np.max(val) + val_normalized = (val - minval) / (maxval - minval) + return val_normalized + + +def simulate_field(settings, start_seed): + # pylint: disable=no-member, + variogram_name = settings["field"]["variogram"] + corr_ranges = settings["field"]["correlation_range"] + xrange = corr_ranges[0] + yrange = corr_ranges[1] + zrange = corr_ranges[2] + + azimuth = settings["field"]["correlation_azimuth"] + dip = settings["field"]["correlation_dip"] + + nx, ny, nz = settings["field"]["grid_dimension"] + xsize = settings["grid_size"]["xsize"] + ysize = settings["grid_size"]["ysize"] + zsize = settings["grid_size"]["zsize"] + + dx = xsize / nx + dy = ysize / ny + dz = zsize / nz + + print(f"Start seed: {start_seed}") + sim.seed(start_seed) + + variogram = sim.variogram( + variogram_name, + xrange, + perp_range=yrange, + depth_range=zrange, + azimuth=azimuth - 90, + dip=dip, + ) + + print(f"Simulate field with size: nx={nx},ny={ny} ") + field1D = sim.simulate(variogram, nx, dx, ny, dy, nz, dz) + field = field1D.reshape((nx, ny, nz), order="F") + return field + + +def export_field(settings, field3D): + # Export initial ensemble field + nx, ny, nz = settings["field"]["grid_dimension"] + field_name = settings["field"]["name"] + field_file_name = settings["field"]["initial_file_name"] + + field_object = xtgeo.grid3d.GridProperty( + ncol=nx, nrow=ny, nlay=nz, values=field3D, discrete=False, name=field_name + ) + + print(f"Write field file: {field_file_name} ") + field_object.to_file(field_file_name, fformat="roff") + return field_object + + +def read_field_from_file(settings): + input_file_name = settings["field"]["updated_file_name"] + name = settings["field"]["name"] + field_object = xtgeo.gridproperty_from_file( + input_file_name, fformat="roff", name=name + ) + return field_object + + +def read_obs_field_from_file(settings): + input_file_name = settings["observation"]["3D_param_file_name"] + obs_field_object = xtgeo.gridproperty_from_file(input_file_name, fformat="roff") + return obs_field_object + + +def read_upscaled_field_from_file(settings, iteration): + input_file_name = settings["response"]["upscaled_file_name"] + if iteration == 0: + filename = "init_files/" + input_file_name + else: + filename = input_file_name + field_object = xtgeo.gridproperty_from_file(filename, fformat="roff") + return field_object + + +def write_obs_pred_diff_field(upscaled_field_object, observation_field_object): + nx, ny, nz = upscaled_field_object.dimensions + values_diff = upscaled_field_object.values - observation_field_object.values + + diff_object = xtgeo.grid3d.GridProperty( + ncol=nx, + nrow=ny, + nlay=nz, + values=values_diff, + discrete=False, + name="DiffObsPred", + ) + + filename = "DiffObsPred.roff" + print( + f"Write field with difference between observation and prediction: {filename} " + ) + diff_object.to_file(filename, fformat="roff") diff --git a/tests/jobs/localisation/example_case/scripts/import_field_parameters.py b/tests/jobs/localisation/example_case/scripts/import_field_parameters.py new file mode 100644 index 000000000..a00c82244 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/import_field_parameters.py @@ -0,0 +1,103 @@ +""" +Import field parameters into RMS (Must be included as python job +in RMS workflow and edited to fit your scratch directory) +""" +from pathlib import Path + +import xtgeo + +SCRATCH = "/scratch/fmu/olia/sim_field/" +# SCRATCH = "/scratch/fmu/olia/sim_field_local/" +CASE_NAME = "original" +# CASE_NAME = "local" + + +# pylint: disable=undefined-variable, bare-except +PRJ = project # noqa: 821 + +GRID_MODEL_NAME = "GRID" +FIELD_NAMES = [ + "FieldParam", +] + + +def main(): + """ + Import files with initial ensemble and updated fields into RMS project + """ + xtgeo.grid_from_roxar(PRJ, GRID_MODEL_NAME, PRJ.current_realisation) + + path = Path(SCRATCH) + if not path.exists(): + raise IOError(f"File path: {SCRATCH} does not exist. ") + + real = PRJ.current_realisation + print("\n") + print(f"Realization: {real} ") + for name in FIELD_NAMES: + for iteration in [0, 3]: + print(f"Iteration: {iteration}") + if iteration == 0: + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/init_files/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + + try: + property0 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property0.name} from file" + f" {file_name} into {name_with_iter} " + ) + property0.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + elif iteration == 3: + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + + try: + property3 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property3.name} for iteration {iteration} " + f"from file {file_name} into {name_with_iter} " + ) + property3.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + try: + diff_property = property0 + diff_property.values = property3.values - property0.values + name_diff = name + "_" + CASE_NAME + "_diff" + print( + f"Calculate difference between iteration 3 and 0: {name_diff}" + ) + diff_property.to_roxar( + PRJ, GRID_MODEL_NAME, name_diff, realisation=real + ) + except: # noqa: E722 + print(f"Skip difference for realisation: {real} ") + + +if __name__ == "__main__": + main() diff --git a/tests/jobs/localisation/example_case/scripts/import_field_parameters_local.py b/tests/jobs/localisation/example_case/scripts/import_field_parameters_local.py new file mode 100644 index 000000000..72ea1e090 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/import_field_parameters_local.py @@ -0,0 +1,103 @@ +""" +Import field parameters into RMS (Must be included as python job +in RMS workflow and edited to fit your scratch directory) +""" +from pathlib import Path + +import xtgeo + +# SCRATCH = "/scratch/fmu/olia/sim_field/" +SCRATCH = "/scratch/fmu/olia/sim_field_local/" +# CASE_NAME = "original" +CASE_NAME = "local" + + +# pylint: disable=undefined-variable, bare-except +PRJ = project # noqa: 821 + +GRID_MODEL_NAME = "GRID" +FIELD_NAMES = [ + "FieldParam", +] + + +def main(): + """ + Import files with initial ensemble and updated fields into RMS project + """ + xtgeo.grid_from_roxar(PRJ, GRID_MODEL_NAME, PRJ.current_realisation) + + path = Path(SCRATCH) + if not path.exists(): + raise IOError(f"File path: {SCRATCH} does not exist. ") + + real = PRJ.current_realisation + print("\n") + print(f"Realization: {real} ") + for name in FIELD_NAMES: + for iteration in [0, 3]: + print(f"Iteration: {iteration}") + if iteration == 0: + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/init_files/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + + try: + property0 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property0.name} from file" + f" {file_name} into {name_with_iter} " + ) + property0.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + elif iteration == 3: + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + + try: + property3 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property3.name} for iteration {iteration} " + f"from file {file_name} into {name_with_iter} " + ) + property3.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + try: + diff_property = property0 + diff_property.values = property3.values - property0.values + name_diff = name + "_" + CASE_NAME + "_diff" + print( + f"Calculate difference between iteration 3 and 0: {name_diff}" + ) + diff_property.to_roxar( + PRJ, GRID_MODEL_NAME, name_diff, realisation=real + ) + except: # noqa: E722 + print(f"Skip difference for realisation: {real} ") + + +if __name__ == "__main__": + main() diff --git a/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters.py b/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters.py new file mode 100644 index 000000000..207d6c0c5 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters.py @@ -0,0 +1,103 @@ +# Import field parameters +""" +Import upscaled field parameters into RMS (Must be included as python job +in RMS workflow and edited to fit your scratch directory) +""" +from pathlib import Path + +import xtgeo + +# Set scratch file directory for the case and name of case (one short word) +SCRATCH = "/scratch/fmu/olia/sim_field/" +# SCRATCH = "/scratch/fmu/olia/sim_field_local/" +CASE_NAME = "original" +# CASE_NAME = "local" + + +# pylint: disable=undefined-variable, bare-except +PRJ = project # noqa: 821 + +GRID_MODEL_NAME = "UpscaleGrid" +FIELD_NAMES = [ + "Upscaled", +] + + +def main(): + """ + Import files with upscaled initial ensemble and updated fields into RMS + """ + + xtgeo.grid_from_roxar(PRJ, GRID_MODEL_NAME, PRJ.current_realisation) + + path = Path(SCRATCH) + if not path.exists(): + raise IOError(f"File path: {SCRATCH} does not exist. ") + + real = PRJ.current_realisation + print("\n") + print(f"Realization: {real} ") + for name in FIELD_NAMES: + for iteration in [0, 3]: + print(f"Iteration: {iteration}") + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + if iteration == 0: + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/init_files/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + try: + property0 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property0.name} from file " + f"{file_name} into {name_with_iter} " + ) + property0.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + elif iteration == 3: + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + try: + property3 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property3.name} for iteration {iteration} " + f"from file {file_name} into {name_with_iter} " + ) + property3.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + try: + diff_property = property0 + diff_property.values = property3.values - property0.values + name_diff = name + "_" + CASE_NAME + "_diff" + print( + f"Calculate difference between iteration 3 and 0: {name_diff}" + ) + diff_property.to_roxar( + PRJ, GRID_MODEL_NAME, name_diff, realisation=real + ) + except: # noqa: E722 + print(f"Skip difference for realisation: {real} ") + + +if __name__ == "__main__": + main() diff --git a/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters_local.py b/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters_local.py new file mode 100644 index 000000000..b2d0f20a2 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/import_upscaled_field_parameters_local.py @@ -0,0 +1,103 @@ +# Import field parameters +""" +Import upscaled field parameters into RMS (Must be included as python job +in RMS workflow and edited to fit your scratch directory) +""" +from pathlib import Path + +import xtgeo + +# Set scratch file directory for the case and name of case (one short word) +# SCRATCH = "/scratch/fmu/olia/sim_field/" +SCRATCH = "/scratch/fmu/olia/sim_field_local/" +# CASE_NAME = "original" +CASE_NAME = "local" + + +# pylint: disable=undefined-variable, bare-except +PRJ = project # noqa: 821 + +GRID_MODEL_NAME = "UpscaleGrid" +FIELD_NAMES = [ + "Upscaled", +] + + +def main(): + """ + Import files with upscaled initial ensemble and updated fields into RMS + """ + + xtgeo.grid_from_roxar(PRJ, GRID_MODEL_NAME, PRJ.current_realisation) + + path = Path(SCRATCH) + if not path.exists(): + raise IOError(f"File path: {SCRATCH} does not exist. ") + + real = PRJ.current_realisation + print("\n") + print(f"Realization: {real} ") + for name in FIELD_NAMES: + for iteration in [0, 3]: + print(f"Iteration: {iteration}") + name_with_iter = name + "_" + CASE_NAME + "_" + str(iteration) + if iteration == 0: + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/init_files/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + try: + property0 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property0.name} from file " + f"{file_name} into {name_with_iter} " + ) + property0.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + elif iteration == 3: + path = ( + SCRATCH + + "realization-" + + str(real) + + "/iter-" + + str(iteration) + + "/" + ) + file_name = path + name + ".roff" + print(f"File name: {file_name} ") + try: + property3 = xtgeo.gridproperty_from_file(file_name, "roff") + print( + f"Import property {property3.name} for iteration {iteration} " + f"from file {file_name} into {name_with_iter} " + ) + property3.to_roxar( + PRJ, GRID_MODEL_NAME, name_with_iter, realisation=real + ) + except: # noqa: E722 + print(f"Skip realization: {real} for iteration: {iteration} ") + try: + diff_property = property0 + diff_property.values = property3.values - property0.values + name_diff = name + "_" + CASE_NAME + "_diff" + print( + f"Calculate difference between iteration 3 and 0: {name_diff}" + ) + diff_property.to_roxar( + PRJ, GRID_MODEL_NAME, name_diff, realisation=real + ) + except: # noqa: E722 + print(f"Skip difference for realisation: {real} ") + + +if __name__ == "__main__": + main() diff --git a/tests/jobs/localisation/example_case/scripts/init_test_case.py b/tests/jobs/localisation/example_case/scripts/init_test_case.py new file mode 100755 index 000000000..5cd265850 --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/init_test_case.py @@ -0,0 +1,281 @@ +#!/usr/bin/env python +""" +Script initialize the test case by creating the grid files, observation files etc +""" + +import math +import os +import random +import sys + +import xtgeo + +# pylint: disable=import-error + + +# pylint: disable=too-many-arguments,invalid-name,missing-function-docstring +# pylint: disable=too-many-locals,redefined-outer-name + + +def generate_seed_file( + settings, + start_seed: int = 9828862224, + number_of_seeds: int = 1000, +): + # pylint: disable=unused-variable + seed_file_name = settings["field"]["seed_file"] + print(f"Generate random seed file: {seed_file_name}") + random.seed(start_seed) + with open(seed_file_name, "w", encoding="utf8") as file: + for i in range(number_of_seeds): + file.write(f"{random.randint(1, 999999999)}\n") + + +def obs_positions(settings): + NX, NY, _ = settings["response"]["grid_dimension"] + use_eclipse_origo = settings["grid_size"]["use_eclipse_grid_index_origo"] + + xsize = settings["grid_size"]["xsize"] + ysize = settings["grid_size"]["ysize"] + dx = xsize / NX + dy = ysize / NY + cell_indx_list = settings["observation"]["selected_grid_cells"] + if use_eclipse_origo: + print("Grid index origin: Eclipse standard") + else: + print("Grid index origin: RMS standard") + print( + "Observation reference point coordinates is always " + "from origin at lower left corner" + ) + + pos_list = [] + for indices in cell_indx_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + x = (Iindx + 0.5) * dx + if use_eclipse_origo: + y = ysize - (Jindx + 0.5) * dy + else: + y = (Jindx + 0.5) * dy + + pos_list.append((x, y)) + + return pos_list + + +def write_localisation_config( + settings, + config_file_name="local_config.yml", + write_scaling=True, +): + obs_index_list = settings["observation"]["selected_grid_cells"] + field_name = settings["field"]["name"] + corr_ranges = settings["field"]["correlation_range"] + azimuth = settings["field"]["correlation_azimuth"] + space = " " * 2 + space2 = " " * 4 + space3 = " " * 6 + positions = obs_positions(settings) + print(f"Write localisation config file: {config_file_name}") + with open(config_file_name, "w", encoding="utf8") as file: + file.write("log_level: 3\n") + file.write(f"write_scaling_factors: {write_scaling}\n") + file.write("correlations:\n") + for i, indx in enumerate(obs_index_list): + Iindx, Jindx, Kindx = indx + obs_name = f"OBS_{Iindx}_{Jindx}_{Kindx}" + pos = positions[i] + file.write(f"{space}- name: CORR_{i}\n") + file.write(f"{space2}obs_group:\n") + file.write(f'{space3}add: ["{obs_name}"]\n') + file.write(f"{space2}param_group:\n") + file.write(f'{space3}add: ["{field_name}"]\n') + file.write(f"{space2}field_scale:\n") + file.write(f"{space3}method: gaussian_decay\n") + file.write(f"{space3}main_range: {corr_ranges[0]}\n") + file.write(f"{space3}perp_range: {corr_ranges[1]}\n") + file.write(f"{space3}azimuth: {azimuth}\n") + file.write(f"{space3}ref_point: [ {pos[0]}, {pos[1]} ]\n") + + +def write_gen_obs(upscaled_values, settings): + observation_dir = settings["observation"]["directory"] + obs_file_name = settings["observation"]["file_name"] + obs_data_dir = settings["observation"]["data_dir"] + cell_indx_list = settings["observation"]["selected_grid_cells"] + rel_err = settings["observation"]["rel_error"] + min_err = settings["observation"]["min_abs_error"] + if not os.path.exists(observation_dir): + print(f"Create directory: {observation_dir} ") + os.makedirs(observation_dir) + data_dir = observation_dir + "/" + obs_data_dir + if not os.path.exists(data_dir): + print(f"Create directory: {data_dir} ") + os.makedirs(data_dir) + + print(f"Write observation file: {obs_file_name} ") + filename = observation_dir + "/" + obs_file_name + with open(filename, "w", encoding="utf8") as obs_file: + number = 0 + for indices in cell_indx_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + Kindx = indices[2] - 1 + + value = upscaled_values[Iindx, Jindx, Kindx] + value_err = math.fabs(value) * rel_err + value_err = max(value_err, min_err) + + obs_data_relative_file_name = ( + obs_data_dir + + "/obs_" + + str(Iindx + 1) + + "_" + + str(Jindx + 1) + + "_" + + str(Kindx + 1) + + ".txt" + ) + + obs_file.write(f"GENERAL_OBSERVATION OBS_{Iindx+1}_{Jindx+1}_{Kindx+1} ") + obs_file.write("{ ") + obs_file.write( + f"DATA = RESULT_UPSCALED_FIELD ; INDEX_LIST = {number} ; RESTART = 0; " + ) + obs_file.write(f"OBS_FILE = ./{obs_data_relative_file_name} ; ") + obs_file.write(" };\n") + number += 1 + data_file_name = observation_dir + "/" + obs_data_relative_file_name + print(f"Write file: {data_file_name} ") + with open(data_file_name, "w", encoding="utf8") as data_file: + data_file.write(f"{value} {value_err}\n") + + +def create_grid(settings): + grid_file_name = settings["field"]["grid_file_name"] + nx, ny, nz = settings["field"]["grid_dimension"] + xsize = settings["grid_size"]["xsize"] + ysize = settings["grid_size"]["ysize"] + zsize = settings["grid_size"]["zsize"] + if settings["grid_size"]["use_eclipse_grid_index_origo"]: + flip = -1 + x0 = 0.0 + y0 = ysize + z0 = 0.0 + else: + flip = 1 + x0 = 0.0 + y0 = 0.0 + z0 = 0.0 + + dx = xsize / nx + dy = ysize / ny + dz = zsize / nz + + grid_object = xtgeo.create_box_grid( + dimension=(nx, ny, nz), + origin=(x0, y0, z0), + increment=(dx, dy, dz), + rotation=0.0, + flip=flip, + ) + + print(f"Write grid file: {grid_file_name} ") + grid_object.to_file(grid_file_name, fformat="egrid") + return grid_object + + +def create_upscaled_grid(settings): + grid_file_name = settings["response"]["grid_file_name"] + nx, ny, nz = settings["response"]["grid_dimension"] + xsize = settings["grid_size"]["xsize"] + ysize = settings["grid_size"]["ysize"] + zsize = settings["grid_size"]["zsize"] + if settings["grid_size"]["use_eclipse_grid_index_origo"]: + flip = -1 + x0 = 0.0 + y0 = ysize + z0 = 0.0 + else: + flip = 1 + x0 = 0.0 + y0 = 0.0 + z0 = 0.0 + + dx = xsize / nx + dy = ysize / ny + dz = zsize / nz + + grid_object = xtgeo.create_box_grid( + dimension=(nx, ny, nz), + origin=(x0, y0, z0), + increment=(dx, dy, dz), + rotation=0.0, + flip=flip, + ) + + print(f"Write grid file: {grid_file_name} ") + grid_object.to_file(grid_file_name, fformat="egrid") + return grid_object + + +def main(config_file_name): + """ + Initialize seed file, grid files, observation files and localisation config file + """ + # pylint: disable=import-outside-toplevel + from common_functions import ( + generate_field_and_upscale, + read_test_config, + write_upscaled_field, + ) + + # Settings are specified here + settings = read_test_config(config_file_name) + + # Create seed file + generate_seed_file(settings) + + # Create grid for the field parameter + create_grid(settings) + + # Create coarse grid to be used in QC of upscaled field parameter + create_upscaled_grid(settings) + + print("Generate field parameter and upscale this.") + print( + f"The upscaled field {settings['observation']['3D_param_file_name']} " + "is used when extracting observations." + ) + + # Simulate field (with trend) + real_number = 0 + upscaled_values = generate_field_and_upscale(settings, real_number) + + # Create observations by extracting from existing upscaled field + write_gen_obs(upscaled_values, settings) + + # Write upscaled field used as truth realisation + write_upscaled_field( + upscaled_values, + settings["observation"]["3D_param_file_name"], + selected_cell_index_list=settings["observation"]["selected_grid_cells"], + ) + + # Write file for non-adaptive localisation using distance based localisation + write_localisation_config( + settings, + config_file_name="local_config.yml", + write_scaling=True, + ) + + +if __name__ == "__main__": + config_file_name = None + if len(sys.argv) < 2: + print("Use default settings") + else: + config_file_name = sys.argv[1] + print(f"Read modified settings from file: {config_file_name} ") + main(config_file_name) diff --git a/tests/jobs/localisation/example_case/scripts/sim_fields.py b/tests/jobs/localisation/example_case/scripts/sim_fields.py new file mode 100755 index 000000000..8f95f2a9b --- /dev/null +++ b/tests/jobs/localisation/example_case/scripts/sim_fields.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +""" +Script used as forward model in ERT to test localisation. +""" +import os +import sys + +# pylint: disable=import-error, redefined-outer-name +# pylint: disable=missing-function-docstring,invalid-name +from common_functions import ( + generate_field_and_upscale, + read_field_from_file, + read_obs_field_from_file, + read_test_config, + read_upscaled_field_from_file, + upscaling, + write_obs_pred_diff_field, +) + + +def write_prediction_gen_data(upscaled_values, settings): + cell_indx_list = settings["observation"]["selected_grid_cells"] + response_file_name = settings["response"]["gen_data_file_name"] + print(f"Write GEN_DATA file with prediction of observations: {response_file_name}") + with open(response_file_name, "w", encoding="utf8") as file: + # NOTE: The sequence of values must be the same as for the observations + for indices in cell_indx_list: + Iindx = indices[0] - 1 + Jindx = indices[1] - 1 + Kindx = indices[2] - 1 + value = upscaled_values[Iindx, Jindx, Kindx] + print(f"Prediction of obs for {Iindx+1},{Jindx+1},{Kindx+1}: {value}") + file.write(f"{value}\n") + + +def get_iteration_and_real_number(argv): + iter_env_name = "_ERT_ITERATION_NUMBER" + if iter_env_name in os.environ: + iteration = int(os.environ.get(iter_env_name)) + else: + if len(argv) < 3: + raise IOError("Missing command line arguments ") + arg1 = argv[1] + if arg1 is None: + raise IOError( + "Missing iteration number (argv[1]) when running this script manually" + ) + iteration = int(arg1) + print(f"ERT iteration: {iteration}") + + real_env_name = "_ERT_REALIZATION_NUMBER" + if real_env_name in os.environ: + real_number = int(os.environ.get(real_env_name)) + else: + if len(argv) < 3: + raise IOError("Missing command line arguments ") + arg2 = argv[2] + if arg2 is None: + raise IOError( + "Missing real_number (argv[2]) when running this script manually" + ) + real_number = int(arg2) + print(f"ERT realization: {real_number}") + return iteration, real_number + + +def main(config_file_name, iteration, real_number): + # pylint: disable=too-many-arguments + """ + Specify settings for fine grid and model parameters for simulating a + field on fine grid. + Specify settings for coarse grid. + Specify settings for synthetic observations extracted from upscaled + field values from coarse grid. + Simulate a field on fine grid. + Export the fine grid and the field for the fine grid to files to be used by ERT. + Upscale the fine grid field to a coarse grid field which is used as + response variables here. + Option to extract synthetic observations for upscaled field parameters + and generate ERT observation files. + Options to generate a sequence of random seeds to make the simulations repeatable. + + """ + + # NOTE: Both the fine scale grid with simulated field values + # and the coarse grid with upscaled values must have Eclipse grid index origin + + # Settings are specified here + + settings = read_test_config(config_file_name) + + if iteration == 0: + print(f"Generate new field parameter realization:{real_number} ") + # Simulate field (with trend) + upscaled_values = generate_field_and_upscale(settings, real_number) + + else: + print(f"Import updated field parameter realization: {real_number} ") + field_object = read_field_from_file(settings) + field_values = field_object.values + + # Calculate upscaled values for selected coarse grid cells + upscaled_values = upscaling( + field_values, + settings, + write_field=settings["optional"]["write_upscaled_to_file"], + iteration=iteration, + ) + # Write GEN_DATA file + write_prediction_gen_data(upscaled_values, settings) + + # Optional output + if settings["optional"]["write_obs_pred_diff_field_file"]: + obs_field_object = read_obs_field_from_file(settings) + upscaled_field_object = read_upscaled_field_from_file(settings, iteration) + write_obs_pred_diff_field(upscaled_field_object, obs_field_object) + + +if __name__ == "__main__": + iteration, real_number = get_iteration_and_real_number(sys.argv) + config_file_name = None + if len(sys.argv) < 4: + print("Use default settings") + else: + config_file_name = sys.argv[3] + print(f"Read modified settings from file: {config_file_name} ") + + main(config_file_name, iteration, real_number) diff --git a/tests/jobs/localisation/example_case/sim_field.ert b/tests/jobs/localisation/example_case/sim_field.ert new file mode 100644 index 000000000..99302a6d6 --- /dev/null +++ b/tests/jobs/localisation/example_case/sim_field.ert @@ -0,0 +1,55 @@ +DEFINE $USER +DEFINE /scratch/fmu +DEFINE sim_field +DEFINE randomseeds.txt +DEFINE /example_case.yml +INSTALL_JOB SIM_FIELD scripts/FM_SIM_FIELD +----------------------------------------------------- +-- Observations +----------------------------------------------------- + +DEFINE /observations/observations.obs +OBS_CONFIG +TIME_MAP time_map.txt + +JOBNAME sim_fields_ + + +NUM_REALIZATIONS 100 -- Set number of realizations to run +MAX_RUNTIME 18000 -- Set the maximum allowed run time (in seconds) +MIN_REALIZATIONS 1 -- Success criteria +MAX_SUBMIT 1 -- How many times should the queue system retry a simulation. +QUEUE_OPTION LSF MAX_RUNNING 100 -- Choke the number of simultaneous run +QUEUE_OPTION LSF LSF_QUEUE mr -- Assign LSF cluster queue to use + +RUNPATH ///realization-/iter- +RANDOM_SEED 123456 -- ERT seed value + +ENSPATH output//storage -- Storage of internal ert data +UPDATE_LOG_PATH output//update_log -- Info of active and inactive data points +RUNPATH_FILE output//runpath_file -- List of runpaths + +-- LOAD_WORKFLOW localisation.wf LOCALISATION_WORKFLOW +-- HOOK_WORKFLOW LOCALISATION_WORKFLOW PRE_FIRST_UPDATE + +--Result data from forward model-- +GEN_DATA RESULT_UPSCALED_FIELD RESULT_FILE:UpscaledField_%d.txt REPORT_STEPS:0 INPUT_FORMAT:ASCII OUTPUT_FORMAT:ASCII + +----------------------------------------------------- +-- Forward models +----------------------------------------------------- +--Simulate Gaussian field with trend and calculate upscaled values. Observables are upscaled values of selected grid cells. +FORWARD_MODEL MAKE_DIRECTORY(=init_files) +-- Is used to identify iteration number (only relevant for old komodo versions) +FORWARD_MODEL MAKE_DIRECTORY(=) +-- The common seed file +FORWARD_MODEL COPY_FILE(=/, =/) +-- For QC purpose only +FORWARD_MODEL COPY_FILE(=/init_files/UpscaledObsField.roff, =/init_files/UpscaledObsField.roff) + +-- The main forward model simulating gaussian field with trend, and upscale +FORWARD_MODEL SIM_FIELD(=, =) + +GRID /GRID.EGRID -- Necessary for AHM using field parameters + +FIELD FIELDPARAM PARAMETER FieldParam.roff INIT_FILES:init_files/FieldParam.roff MIN:-5.0 MAX:5.0 FORWARD_INIT:True diff --git a/tests/jobs/localisation/example_case/sim_field_local.ert b/tests/jobs/localisation/example_case/sim_field_local.ert new file mode 100644 index 000000000..9e0993793 --- /dev/null +++ b/tests/jobs/localisation/example_case/sim_field_local.ert @@ -0,0 +1,54 @@ +DEFINE $USER +DEFINE /scratch/fmu +DEFINE sim_field_local +DEFINE randomseeds.txt +INSTALL_JOB SIM_FIELD scripts/FM_SIM_FIELD +----------------------------------------------------- +-- Observations +----------------------------------------------------- + +DEFINE /observations/observations.obs +OBS_CONFIG +TIME_MAP time_map.txt + +JOBNAME sim_fields_ + + +NUM_REALIZATIONS 100 -- Set number of realizations to run +MAX_RUNTIME 18000 -- Set the maximum allowed run time (in seconds) +MIN_REALIZATIONS 1 -- Success criteria +MAX_SUBMIT 1 -- How many times should the queue system retry a simulation. +QUEUE_OPTION LSF MAX_RUNNING 100 -- Choke the number of simultaneous run +QUEUE_OPTION LSF LSF_QUEUE mr -- Assign LSF cluster queue to use + +RUNPATH ///realization-/iter- +RANDOM_SEED 123456 -- ERT seed value + +ENSPATH output//storage -- Storage of internal ert data +UPDATE_LOG_PATH output//update_log -- Info of active and inactive data points +RUNPATH_FILE output//runpath_file -- List of runpaths + +LOAD_WORKFLOW localisation.wf LOCALISATION_WORKFLOW +HOOK_WORKFLOW LOCALISATION_WORKFLOW PRE_FIRST_UPDATE + +--Result data from forward model-- +GEN_DATA RESULT_UPSCALED_FIELD RESULT_FILE:UpscaledField_%d.txt REPORT_STEPS:0 INPUT_FORMAT:ASCII OUTPUT_FORMAT:ASCII + +----------------------------------------------------- +-- Forward models +----------------------------------------------------- +--Simulate Gaussian field with trend and calculate upscaled values. Observables are upscaled values of selected grid cells. +FORWARD_MODEL MAKE_DIRECTORY(=init_files) +-- Is used to identify iteration number (only relevant for old komodo versions) +FORWARD_MODEL MAKE_DIRECTORY(=) +-- The common seed file +FORWARD_MODEL COPY_FILE(=/, =/) +-- For QC purpose only +FORWARD_MODEL COPY_FILE(=/init_files/UpscaledObsField.roff, =/init_files/UpscaledObsField.roff) + +-- The main forward model simulating gaussian field with trend, and upscale +FORWARD_MODEL SIM_FIELD(=, =) + +GRID /GRID.EGRID -- Necessary for AHM using field parameters + +FIELD FIELDPARAM PARAMETER FieldParam.roff INIT_FILES:init_files/FieldParam.roff MIN:-5.0 MAX:5.0 FORWARD_INIT:True diff --git a/tests/jobs/localisation/example_case/time_map.txt b/tests/jobs/localisation/example_case/time_map.txt new file mode 100644 index 000000000..9c6b8b808 --- /dev/null +++ b/tests/jobs/localisation/example_case/time_map.txt @@ -0,0 +1 @@ +2000-01-01