From ab5c4c92f2398c7a0128662c655f06ce653408b2 Mon Sep 17 00:00:00 2001 From: oddvarlia <77153131+oddvarlia@users.noreply.github.com> Date: Tue, 17 Dec 2024 21:30:44 +0100 Subject: [PATCH] Add script to generate new petro logs from original logs (#264) Added test and testdata Add documentation --- docs/generate_bw_per_facies.rst | 79 ++++++ docs/index.rst | 1 + src/fmu/tools/rms/__init__.py | 4 +- src/fmu/tools/rms/generate_bw_per_facies.py | 100 +++++++ tests/rms/generate_bw_testdata/Wtest_0.txt | 37 +++ tests/rms/generate_bw_testdata/Wtest_1.txt | 37 +++ tests/rms/generate_bw_testdata/Wtest_2.txt | 37 +++ tests/rms/test_generate_bw_per_facies.py | 288 ++++++++++++++++++++ 8 files changed, 582 insertions(+), 1 deletion(-) create mode 100644 docs/generate_bw_per_facies.rst create mode 100644 src/fmu/tools/rms/generate_bw_per_facies.py create mode 100644 tests/rms/generate_bw_testdata/Wtest_0.txt create mode 100644 tests/rms/generate_bw_testdata/Wtest_1.txt create mode 100644 tests/rms/generate_bw_testdata/Wtest_2.txt create mode 100644 tests/rms/test_generate_bw_per_facies.py diff --git a/docs/generate_bw_per_facies.rst b/docs/generate_bw_per_facies.rst new file mode 100644 index 00000000..3bc2f32f --- /dev/null +++ b/docs/generate_bw_per_facies.rst @@ -0,0 +1,79 @@ +rms.create_bw_per_facies +============================ + +The RMS python job to generate new blocked wells with petrophysical +values for one facies per blocked well log is used as part of a workflow +to create petrophysical 3D grid realizations conditioned to only one facies. +This is used in FMU workflows where both facies and petrophysical variables +are used as field parameters in assisted history matching (AHM) with ERT. + +Input + +* Grid name +* Existing blocked well set (containing the original blocked well logs) +* List of original petrophysical blocked well log names to be used to generate new logs +* Facies log name +* Python dictionary with code and facies names per code for relevant facies + +Output + +For each of the specified original petrophysical logs, one new log per facies +for the specified facies is made. The values are copies of the original blocked +well logs except that all values belonging to other facies than the one for the +created log is set to undefined. The new logs will have name of +the form "faciesname_petroname". + +Example of use as RMS python job +--------------------------------- + +.. code-block:: python + + from fmu.tools.rms import create_bw_per_facies + from fmu.config import utilities as ut + DEBUG_PRINT = False + + CFG = ut.yaml_load("../../fmuconfig/output/global_variables.yml")["global"] + FACIES_ZONE = CFG["FACIES_ZONE"] + + GRID_NAMES = { + "Valysar": "Geogrid_Valysar", + "Therys": "Geogrid_Therys", + "Volon": "Geogrid_Volon", + } + + # Blocked well set + BW_NAME = "BW" + + # Original logs to make copy of per facies + ORIGINAL_BW_LOG_NAMES = ["PHIT", "KLOGH"] + + # Facies log in original blocked well set + FACIES_LOG_NAME = "Facies" + + def main(project): + for zone_name, facies_code_names_for_zone in FACIES_ZONE.items(): + # For each of the single zone grids, calculate updated BW set + create_bw_per_facies( + project, + GRID_NAMES[zone_name], + BW_NAME, + ORIGINAL_BW_LOG_NAMES, + FACIES_LOG_NAME, + FACIES_ZONE[zone_name], + debug_print=DEBUG_PRINT) + + if __name__ == "__main__": + main(project) + +The example above will create the following new blocked well logs for +each well based on the original logs "PHIT" and "KLOGH": + +* Floodplain_PHIT +* Floodplain_KLOGH +* Channel_PHIT +* Channel_KLOGH +* Crevasse_PHIT +* Crevasse_KLOGH +* Coal_PHIT +* Coal_KLOGH + diff --git a/docs/index.rst b/docs/index.rst index 22c6a21a..6caa0ff5 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -17,6 +17,7 @@ Contents: create_rft_ertobs rename_rms_scripts rms_import_localmodule + generate_bw_per_facies utilities rmsvolumetrics2csv ensembles diff --git a/src/fmu/tools/rms/__init__.py b/src/fmu/tools/rms/__init__.py index 0f2d6419..89467520 100644 --- a/src/fmu/tools/rms/__init__.py +++ b/src/fmu/tools/rms/__init__.py @@ -1,7 +1,8 @@ """ -Processing of volumetrics from RMS +Initialize modules for use in RMS """ +from .generate_bw_per_facies import create_bw_per_facies from .generate_petro_jobs_for_field_update import ( main as generate_petro_jobs, ) @@ -12,4 +13,5 @@ "rmsvolumetrics_txt2df", "import_localmodule", "generate_petro_jobs", + "create_bw_per_facies", ] diff --git a/src/fmu/tools/rms/generate_bw_per_facies.py b/src/fmu/tools/rms/generate_bw_per_facies.py new file mode 100644 index 00000000..55285293 --- /dev/null +++ b/src/fmu/tools/rms/generate_bw_per_facies.py @@ -0,0 +1,100 @@ +import copy +from typing import Dict, List + +import numpy as np +import xtgeo + + +def create_bw_per_facies( + project, + grid_name: str, + bw_name: str, + original_petro_log_names: List[str], + facies_log_name: str, + facies_code_names: Dict[int, str], + debug_print: bool = False, +) -> None: + """Function to be imported and applied in a RMS python job + to create new petrophysical logs from original logs, + but with one log per facies. + All grid blocks for the blocked wells not belonging to the facies + is set to undefined. + + Purpose: + Create the blocked well logs to be used to condition + petrophysical realizations where all grid cells are + assumed to belong to only one facies. This script will + not modify any of the original logs, only create new logs where only + petrophysical log values for one facies is selected + and all other are set ot undefined. + + Input: + grid model name, + blocked well set name, + list of original log names to use, + facies log name, + facies code with facies name dictionary + + Output: + One new petro log per facies per petro variables in the + input list of original log names. The output will be saved in + the given blocked well set specified in the input. + + """ + + original_log_names = copy.copy(original_petro_log_names) + original_log_names.append(facies_log_name) + bw = xtgeo.blockedwells_from_roxar( + project, grid_name, bw_name, lognames=original_log_names + ) + print(" ") + print(f"Update blocked well set {bw_name} for grid model {grid_name}:") + + for well in bw.wells: + if debug_print: + print(f"Wellname: {well.name}") + + # Update the new logs by only keeping petro variables + # belonging to the current facies + df = well.get_dataframe() + new_log_names = [] + for facies_code, fname in facies_code_names.items(): + filtered_rows = df[facies_log_name] != int(facies_code) + for petro_name in original_petro_log_names: + if petro_name in well.lognames: + new_log_name = fname + "_" + petro_name + well.create_log(new_log_name) + + df[new_log_name] = df[petro_name] + df[new_log_name][filtered_rows] = np.nan + if debug_print: + print(f" Create new log: {new_log_name}") + new_log_names.append(new_log_name) + + well.set_dataframe(df) + if debug_print: + print(f"Well: {well.name}") + print(f"All logs: {well.lognames_all}") + print("Dataframe for facies log and new logs:") + df_updated = well.get_dataframe() + selected_log_names = [] + selected_log_names.append(facies_log_name) + selected_log_names.extend(new_log_names) + print(f"{df_updated[selected_log_names]}") + + print(f"Create new logs for well {well.name}") + if debug_print: + print("-" * 100) + + well.to_roxar( + project, + grid_name, + bw_name, + well.name, + lognames=new_log_names, + update_option="overwrite", + ) + + print("New logs: ") + for name in new_log_names: + print(f" {name}") diff --git a/tests/rms/generate_bw_testdata/Wtest_0.txt b/tests/rms/generate_bw_testdata/Wtest_0.txt new file mode 100644 index 00000000..90787662 --- /dev/null +++ b/tests/rms/generate_bw_testdata/Wtest_0.txt @@ -0,0 +1,37 @@ +1.0 +Unknown +Wtest_0 None None 100.0 +13 +I_INDEX CONT linear +J_INDEX CONT linear +K_INDEX CONT linear +ZONELOG DISC 1 Zone1 2 Zone2 3 Zone3 +PORO CONT linear +PERM CONT linear +FACIES DISC 0 F1 1 F2 2 F3 +F1_PORO CONT linear +F1_PERM CONT linear +F2_PORO CONT linear +F2_PERM CONT linear +F3_PORO CONT linear +F3_PERM CONT linear +125.0000 125.0000 1002.5000 0.0000 0.0000 0.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1007.5000 0.0000 0.0000 1.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1012.5000 0.0000 0.0000 2.0000 1 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +125.0000 125.0000 1017.5000 0.0000 0.0000 3.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1022.5000 0.0000 0.0000 4.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1027.5000 0.0000 0.0000 5.0000 1 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +125.0000 125.0000 1032.5000 0.0000 0.0000 6.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1037.5000 0.0000 0.0000 7.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1042.5000 0.0000 0.0000 8.0000 2 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +125.0000 125.0000 1047.5000 0.0000 0.0000 9.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1052.5000 0.0000 0.0000 10.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1057.5000 0.0000 0.0000 11.0000 2 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +125.0000 125.0000 1062.5000 0.0000 0.0000 12.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1067.5000 0.0000 0.0000 13.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1072.5000 0.0000 0.0000 14.0000 3 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +125.0000 125.0000 1077.5000 0.0000 0.0000 15.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1082.5000 0.0000 0.0000 16.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1087.5000 0.0000 0.0000 17.0000 3 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +125.0000 125.0000 1092.5000 0.0000 0.0000 18.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +125.0000 125.0000 1097.5000 0.0000 0.0000 19.0000 3 0.1125 25.6914 2 -999.0000 -999.0000 -999.0000 -999.0000 0.1125 25.6914 diff --git a/tests/rms/generate_bw_testdata/Wtest_1.txt b/tests/rms/generate_bw_testdata/Wtest_1.txt new file mode 100644 index 00000000..c51e21d8 --- /dev/null +++ b/tests/rms/generate_bw_testdata/Wtest_1.txt @@ -0,0 +1,37 @@ +1.0 +Unknown +Wtest_1 None None 100.0 +13 +I_INDEX CONT linear +J_INDEX CONT linear +K_INDEX CONT linear +ZONELOG DISC 1 Zone1 2 Zone2 3 Zone3 +PORO CONT linear +PERM CONT linear +FACIES DISC 0 F1 1 F2 2 F3 +F1_PORO CONT linear +F1_PERM CONT linear +F2_PORO CONT linear +F2_PERM CONT linear +F3_PORO CONT linear +F3_PERM CONT linear +875.0000 875.0000 1002.5000 3.0000 3.0000 0.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1007.5000 3.0000 3.0000 1.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1012.5000 3.0000 3.0000 2.0000 1 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +875.0000 875.0000 1017.5000 3.0000 3.0000 3.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1022.5000 3.0000 3.0000 4.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1027.5000 3.0000 3.0000 5.0000 1 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +875.0000 875.0000 1032.5000 3.0000 3.0000 6.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1037.5000 3.0000 3.0000 7.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1042.5000 3.0000 3.0000 8.0000 2 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +875.0000 875.0000 1047.5000 3.0000 3.0000 9.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1052.5000 3.0000 3.0000 10.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1057.5000 3.0000 3.0000 11.0000 2 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +875.0000 875.0000 1062.5000 3.0000 3.0000 12.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1067.5000 3.0000 3.0000 13.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1072.5000 3.0000 3.0000 14.0000 3 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +875.0000 875.0000 1077.5000 3.0000 3.0000 15.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1082.5000 3.0000 3.0000 16.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1087.5000 3.0000 3.0000 17.0000 3 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +875.0000 875.0000 1092.5000 3.0000 3.0000 18.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +875.0000 875.0000 1097.5000 3.0000 3.0000 19.0000 3 0.1125 25.6914 2 -999.0000 -999.0000 -999.0000 -999.0000 0.1125 25.6914 diff --git a/tests/rms/generate_bw_testdata/Wtest_2.txt b/tests/rms/generate_bw_testdata/Wtest_2.txt new file mode 100644 index 00000000..66bd38d8 --- /dev/null +++ b/tests/rms/generate_bw_testdata/Wtest_2.txt @@ -0,0 +1,37 @@ +1.0 +Unknown +Wtest_2 None None 100.0 +13 +I_INDEX CONT linear +J_INDEX CONT linear +K_INDEX CONT linear +ZONELOG DISC 1 Zone1 2 Zone2 3 Zone3 +PORO CONT linear +PERM CONT linear +FACIES DISC 0 F1 1 F2 2 F3 +F1_PORO CONT linear +F1_PERM CONT linear +F2_PORO CONT linear +F2_PERM CONT linear +F3_PORO CONT linear +F3_PERM CONT linear +1625.0000 1625.0000 1002.5000 6.0000 6.0000 0.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1007.5000 6.0000 6.0000 1.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1012.5000 6.0000 6.0000 2.0000 1 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +1625.0000 1625.0000 1017.5000 6.0000 6.0000 3.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1022.5000 6.0000 6.0000 4.0000 1 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1027.5000 6.0000 6.0000 5.0000 1 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +1625.0000 1625.0000 1032.5000 6.0000 6.0000 6.0000 1 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1037.5000 6.0000 6.0000 7.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1042.5000 6.0000 6.0000 8.0000 2 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +1625.0000 1625.0000 1047.5000 6.0000 6.0000 9.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1052.5000 6.0000 6.0000 10.0000 2 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1057.5000 6.0000 6.0000 11.0000 2 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +1625.0000 1625.0000 1062.5000 6.0000 6.0000 12.0000 2 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1067.5000 6.0000 6.0000 13.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1072.5000 6.0000 6.0000 14.0000 3 0.1184 37.4939 1 -999.0000 -999.0000 0.1184 37.4939 -999.0000 -999.0000 +1625.0000 1625.0000 1077.5000 6.0000 6.0000 15.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1082.5000 6.0000 6.0000 16.0000 3 0.1816 162.5061 0 0.1816 162.5061 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1087.5000 6.0000 6.0000 17.0000 3 0.1816 162.5061 1 -999.0000 -999.0000 0.1816 162.5061 -999.0000 -999.0000 +1625.0000 1625.0000 1092.5000 6.0000 6.0000 18.0000 3 0.1184 37.4939 0 0.1184 37.4939 -999.0000 -999.0000 -999.0000 -999.0000 +1625.0000 1625.0000 1097.5000 6.0000 6.0000 19.0000 3 0.1125 25.6914 2 -999.0000 -999.0000 -999.0000 -999.0000 0.1125 25.6914 diff --git a/tests/rms/test_generate_bw_per_facies.py b/tests/rms/test_generate_bw_per_facies.py new file mode 100644 index 00000000..f65e4a08 --- /dev/null +++ b/tests/rms/test_generate_bw_per_facies.py @@ -0,0 +1,288 @@ +"""Run tests in RMS using rmsapi to new blocked well logs by using +generate_bw_per_facies. + +Creates a tmp RMS project in given version. + +This requires a ROXAPI license, and to be ran in a "roxenvbash" environment + +""" + +import contextlib +import filecmp +import shutil +from os.path import isdir +from pathlib import Path +from typing import List + +import numpy as np +import pytest +import xtgeo + +with contextlib.suppress(ImportError): + import rmsapi + import rmsapi.jobs + +from fmu.tools.rms.generate_bw_per_facies import create_bw_per_facies + +# ====================================================================================== +# settings to create RMS project! + +REMOVE_RMS_PROJECT_AFTER_TEST = False +DEBUG_PRINT = True +TMPD = Path("TMP") +TMPD.mkdir(parents=True, exist_ok=True) +PROJNAME = "tmp_project_generate_bw_logs.rmsxxx" +PRJ = str(TMPD / PROJNAME) +RESULTDIR = TMPD / "bw" +RESULTDIR.mkdir(parents=True, exist_ok=True) +REFERENCE_DIR = Path("tests/rms/generate_bw_testdata") + +GRIDNAME = "TestGrid" +GRID_DIM = (10, 10, 20) +INCREMENT = (250.0, 250.0, 5.0) +TOP_DEPTH = 1000 +BASE_DEPTH = TOP_DEPTH + GRID_DIM[2] * INCREMENT[2] +EAST = 0.0 +NORTH = 0.0 +ORIGIN = (EAST, NORTH, TOP_DEPTH) + +NWELLS = 3 +WELL_NAME_PREFIX = "Wtest" +NPOINTS = 100 +BLOCKED_WELL_SET = "BWtest" +BLOCKED_WELL_JOB = "BW_job" +ORIGINAL_PETRO_LOGS = ["PORO", "PERM"] +FACIES_LOG = "FACIES" +JOB_TYPE = "Block Wells" +FACIES_CODE_NAMES = { + 0: "F1", + 1: "F2", + 2: "F3", +} +ZONE_CODE_NAMES = { + 1: "Zone1", + 2: "Zone2", + 3: "Zone3", +} + + +def create_grid(project) -> None: + grid = xtgeo.create_box_grid(GRID_DIM, origin=ORIGIN, increment=INCREMENT) + grid.to_roxar(project, GRIDNAME) + + +def create_wells(project) -> List[str]: + well_list = [] + well_names = [] + for i in range(NWELLS): + # well head and name + well_name = f"{WELL_NAME_PREFIX}_{i}" + well_names.append(well_name) + if DEBUG_PRINT: + print(f"Create well: {well_name}") + well = project.wells.create(well_name) + well.rkb = 100 + east = EAST + INCREMENT[0] + 750 * i + north = NORTH + INCREMENT[1] + 750 * i + topdepth = TOP_DEPTH + basedepth = BASE_DEPTH + npoints = NPOINTS + loginc = (basedepth - topdepth) / npoints + well.well_head = (east, north) + + # trajectory + trajectories = well.wellbore.trajectories + drilled_trajectory = trajectories.create("Drilled trajectory") + surveypoints = drilled_trajectory.survey_point_series + array_with_points = surveypoints.generate_survey_points(npoints) + array_with_points[:, 0] = np.arange(topdepth, basedepth, loginc) + array_with_points[:, 3].fill(east) + array_with_points[:, 4].fill(north) + array_with_points[:, 5] = np.arange(topdepth, basedepth, loginc) # TVD + surveypoints.set_survey_points(array_with_points) + + # log curves + log_run = drilled_trajectory.log_runs.create("Log run 1") + measured_depths = np.arange( + topdepth, basedepth, loginc + ) # MD points for log values + log_run.set_measured_depths(measured_depths) + nval = len(measured_depths) + + poro_log_curve = log_run.log_curves.create("PORO") + values = np.zeros(nval, dtype=np.float32) + for i in range(nval): + angle = i * 10 * np.pi / nval + values[i] = 0.05 * np.sin(angle) + 0.15 + poro_log_curve.set_values(values) + + perm_log_curve = log_run.log_curves.create("PERM") + for i in range(nval): + angle = i * 10 * np.pi / nval + values[i] = 99 * np.sin(angle) + 100 + perm_log_curve.set_values(values) + + facies_log_curve = log_run.log_curves.create_discrete("FACIES") + values = np.zeros(nval, dtype=np.int32) + # facies_log_curve.generate_values() + for i in range(nval): + values[i] = ( + i % 3 + ) # (values 0,1 or 2, must be consistent with facies code names) + facies_log_curve.set_values(values) + code_names = FACIES_CODE_NAMES + facies_log_curve.set_code_names(code_names) + + zone_log_curve = log_run.log_curves.create_discrete("ZONELOG") + values = zone_log_curve.generate_values() + for i in range(nval): + if i < (nval / 3): + values[i] = 1 + elif i < (2 * nval / 3): + values[i] = 2 + else: + values[i] = 3 + zone_log_curve.set_values(values) + code_names = ZONE_CODE_NAMES + zone_log_curve.set_code_names(code_names) + + well_list.append(well) + + return well_names + + +def create_bw_job( + owner_strings: List[str], + job_type: str, + job_name: str, + well_names: List[str], + debug_print: bool = False, +): + bw_job = rmsapi.jobs.Job.create(owner=owner_strings, type=job_type, name=job_name) + + params = { + "BlockedWellsName": BLOCKED_WELL_SET, + "Continuous Blocked Log": [ + { + "Name": "PORO", + "Interpolate": True, + "CellLayerAveraging": True, + }, + { + "Name": "PERM", + "Interpolate": True, + "CellLayerAveraging": True, + }, + ], + "Discrete Blocked Log": [ + { + "Name": "FACIES", + "CellLayerAveraging": True, + }, + ], + "Wells": [["Wells", well_name] for well_name in well_names], + "Zone Blocked Log": [ + { + "Name": "ZONELOG", + "CellLayerAveraging": True, + "ZoneLogArray": [1, 2, 3, 4], + } + ], + } + check, err_list, warn_list = bw_job.check(params) + if not check: + print("Error when creating blocked well job:") + for i in range(len(err_list)): + print(f" {err_list[i]}") + print("Warnings when creating blocked well job:") + for i in range(len(warn_list)): + print(f" {warn_list[i]}") + + if debug_print: + print( + f"Create block well job: {job_name} to make blocked well set: " + f"{BLOCKED_WELL_SET}" + ) + print(f"Use the wells: {well_names}") + + bw_job.set_arguments(params) + bw_job.save() + + return bw_job + + +def create_project(): + """Create a tmp RMS project for testing, populate with basic data.""" + + prj1 = str(PRJ) + + print("\n******** Setup RMS project!\n") + if isdir(prj1): + print("Remove existing project! (1)") + shutil.rmtree(prj1) + + project = rmsapi.Project.create() + + rox = xtgeo.RoxUtils(project) + print("rmsapi version is", rox.roxversion) + print("RMS version is", rox.rmsversion(rox.roxversion)) + assert "1." in rox.roxversion + + create_grid(project) + + well_names = create_wells(project) + owner_strings = ["Grid models", GRIDNAME, "Grid"] + bw_job = create_bw_job(owner_strings, "Block Wells", BLOCKED_WELL_JOB, well_names) + bw_job.execute() + project.save_as(prj1) + return project + + +@pytest.mark.skipunlessroxar +def test_generate_bw() -> None: + """Test generate_new blocked well logs""" + + project = create_project() + create_bw_per_facies( + project, + GRIDNAME, + BLOCKED_WELL_SET, + ORIGINAL_PETRO_LOGS, + FACIES_LOG, + FACIES_CODE_NAMES, + debug_print=DEBUG_PRINT, + ) + wellnames = write_bw_to_files(project) + + # Compare text files with blocked well data with reference data + for wellname in wellnames: + filename = wellname + ".txt" + check = filecmp.cmp(TMPD / Path(filename), REFERENCE_DIR / Path(filename)) + if check: + print(f"Check OK for blocked well: {wellname}") + assert check + + if REMOVE_RMS_PROJECT_AFTER_TEST: + print("\n******* Teardown RMS project!\n") + if isdir(PRJ): + print("Remove existing project!") + shutil.rmtree(PRJ) + if isdir(RESULTDIR): + print("Remove temporary files") + shutil.rmtree(RESULTDIR) + + +def write_bw_to_files(project) -> List[str]: + xtgeo_bw = xtgeo.blockedwells_from_roxar( + project, GRIDNAME, BLOCKED_WELL_SET, lognames="all" + ) + wells = xtgeo_bw.wells + wellnames = [] + for well in wells: + well_file_name = TMPD / Path(well.name + ".txt") + wellnames.append(well.name) + if DEBUG_PRINT: + print(f"Write file: {well_file_name}") + print(f"Well logs: {well.lognames}") + well.to_file(well_file_name, fformat="rmswell") + return wellnames