Skip to content

Commit

Permalink
Add function to combine multiple petro realizations using facies real…
Browse files Browse the repository at this point in the history
…ization

Add function to import and export field parameters to and from ERTBOX grid.
Added documentation for update_petro_real and the export and import functions.
Add test for update_petro_real.py
  • Loading branch information
oddvarlia committed Jan 2, 2025
1 parent 39c3f3f commit aa0cbc4
Show file tree
Hide file tree
Showing 5 changed files with 1,334 additions and 0 deletions.
111 changes: 111 additions & 0 deletions docs/export_and_import_fields.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
rms.export_and_import_field_parameters
=======================================

The export and import scripts desctibed below supports a workflow where
both facies and petrophysical properties are updated as field parameters in ERT.
The implemented functions in the module *fmu.tools.rms.update_petro_real* are::

export_initial_field_parameters
import_updated_field_parameters

Both the export and import function the same set of petrophysical variables in the
same workflow. Therefore, they both read this information from a configuration file
in YAML format that is also shared with the function *generate_petro_jobs*.

Export petrophysical parameters as field parameters to be used in ERT FIELD keyword
-------------------------------------------------------------------------------------

Example of use of the export function

.. code-block:: python
from fmu.tools.rms.update_petro_real import export_initial_field_parameters
from fmu.tools.rms.generate_petro_jobs_for_field_update import read_specification_file
DEBUG_PRINT=True
CONFIG_FILE_NAME_VALYSAR = "../input/config/field_update/generate_petro_jobs_valysar.yml"
CONFIG_FILE_NAME_THERYS = "../input/config/field_update/generate_petro_jobs_therys.yml"
CONFIG_FILE_NAME_VOLON = "../input/config/field_update/generate_petro_jobs_volon.yml"
ERTBOX_GRID = "ERTBOX"
def export_fields():
spec_dict = read_specification_file(CONFIG_FILE_NAME_VALYSAR)
used_petro_dict = spec_dict["used_petro_var"]
export_initial_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Valysar",
debug_print= DEBUG_PRINT)
spec_dict = read_specification_file(CONFIG_FILE_NAME_THERYS)
used_petro_dict = spec_dict["used_petro_var"]
export_initial_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Therys",
debug_print= DEBUG_PRINT)
spec_dict = read_specification_file(CONFIG_FILE_NAME_VOLON)
used_petro_dict = spec_dict["used_petro_var"]
export_initial_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Volon",
debug_print= DEBUG_PRINT)
if __name__ == "__main__":
export_fields()
Import petrophysical parameters used as field parameters to be used in ERT FIELD keyword
------------------------------------------------------------------------------------------

Example of use of the import function

.. code-block:: python
from fmu.tools.rms.update_petro_real import import_updated_field_parameters
from fmu.tools.rms.generate_petro_jobs_for_field_update import read_specification_file
DEBUG_PRINT = False
CONFIG_FILE_NAME_VALYSAR = "../input/config/field_update/generate_petro_jobs_valysar.yml"
CONFIG_FILE_NAME_THERYS = "../input/config/field_update/generate_petro_jobs_therys.yml"
CONFIG_FILE_NAME_VOLON = "../input/config/field_update/generate_petro_jobs_volon.yml"
ERTBOX_GRID = "ERTBOX"
def import_fields():
spec_dict = read_specification_file(CONFIG_FILE_NAME_VALYSAR)
used_petro_dict = spec_dict["used_petro_var"]
import_updated_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Valysar",
debug_print=DEBUG_PRINT)
spec_dict = read_specification_file(CONFIG_FILE_NAME_THERYS)
used_petro_dict = spec_dict["used_petro_var"]
import_updated_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Therys",
debug_print=DEBUG_PRINT)
spec_dict = read_specification_file(CONFIG_FILE_NAME_VOLON)
used_petro_dict = spec_dict["used_petro_var"]
import_updated_field_parameters(
project,
used_petro_dict,
grid_model_name=ERTBOX_GRID,
zone_name_for_single_zone_grid="Volon",
debug_print=DEBUG_PRINT)
if __name__ == "__main__":
import_fields()
2 changes: 2 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Contents:
rename_rms_scripts
rms_import_localmodule
generate_bw_per_facies
update_petro_real
export_and_import_fields
utilities
rmsvolumetrics2csv
ensembles
Expand Down
185 changes: 185 additions & 0 deletions docs/update_petro_real.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
rms.update_petro_real
=======================

When running FMU project where field parameters for both facies and
petrophysical properties are updated in ERT simultaneously,
some adjustments are needed in the RMS project to support this type
of workflow. It is necessary to have one petrosim job per facies.

The module *update_petro_real* will combine values from realization
of a petrophysical property for individual facies into one common
petrophysical realization by using the facies realization as filter.

Example describing the workflow
--------------------------------

The zone Valysar has four different facies::

Floodplain
Channel
Crevasse
Coal

A petrophysical realization is made for PHIT and KLOGH for each of the three
first facies with property names::

Floodplain_PHIT
Floodplain_KLOGH
Channel_PHIT
Channel_KLOGH
Crevasse_PHIT
Crevasse_KLOGH

Neither PHIT nor KLOGH are updated as field parameters for facies
Coal since they have constant (not spatially varying) values and
may even have 0 specified uncertainty.
The variables VSH and VPHYL are chosen not to be used as field parameters
in ERT in assisted histroy matching and therefore not included here,
but still used in the RMS workflow with the prior values.

The original realizations created for PHIT and KLOGH are conditioned
to facies. In a workflow where we want to use both facies by applying
the Adaptive PluriGaussian Simulation method (APS) and PHIT and KLOG
for some selected facies as field parameters to be updated by ERT,
we will need the separate PHIT and KLOGH realizations for the selected
facies.

The steps will be:

* Use original petrophysical job to create initial version of a realization of
PHIT, KLOGH, VSH and VPHYL.
* Use separate petrophysical jobs to create separate version of realizations of
Floodplain_PHIT, Floodplain_KLOGH and so on.
* Use the script *update_petro_real* to copy the values for PHIT and KLOGH from
the individual realizations per facies into the initial version of PHIT and KLOG
by overwriting the values in the original version. In this process,
the facies realization is used as a filter to select which grid cell values
to get from the individual PHIT and KLOGH parameters that belongs to the
various facies.

When running ERT iteration 0 which creates the initial ensemble, this looks a bit unnecessary,
since the initial PHIT and KLOGH already has taken facies into account. But, when running
ERT iteration larger than 0 (after ERT has updated the fields Floodplain_PHIT,
Floodplain_KLOGH and so on), then updated versions of the field parameters are imported
and updated version of facies realization is used to update the PHIT and KLOGH parameters
from the imported field parameters (Floodplain_PHIT, Floodplain_KLOGH ...).

Also for iteration 0, to ensure consistency the same procedure
(copy from the field parameters Floodplain_PHIT, Floodplain_KLOG,..) is
applied since this ensure consistent handling of the realizations.

Example of RMS python job running this module to combine the field parameters
-------------------------------------------------------------------------------

The python job below will call the *update_petro_real* function that does the
combination of the field parameters into one petrophysical realization.
This job depends on a small config file ( the same config file that is used by the
function *generate_petro_jobs* from fmu.tools.rms module). Here the python job gets
the grid name and which of the petrophysical properties for which facies
to be updated as field parameters in ERT. The script also depends on the facies table
(which facies code and name belongs together).
This can be fetched from the *global_variables.yml* file as shown in the example below.

An alternative is to add a key *USED_PETRO_FIELDS* in global_master_config.yml
and get the petro parameters per facies per zone from this keyword instead.

.. code-block:: python
from fmu.tools.rms.update_petro_real import update_petro_real
from fmu.config import utilities as ut
DEBUG_PRINT = False
# Choose either to use config file or input from global variable file
USE_CONFIG_FILES = True
CFG = ut.yaml_load("../../fmuconfig/output/global_variables.yml")["global"]
FACIES_ZONE = CFG["FACIES_ZONE"]
# Used if alternative 1 with config file is used
CONFIG_FILES = {
"Valysar": "../input/config/field_update/generate_petro_jobs_valysar.yml",
"Therys": "../input/config/field_update/generate_petro_jobs_therys.yml",
"Volon": "../input/config/field_update/generate_petro_jobs_volon.yml",
}
# Used if alternative 2 without config file is used
# In this case the global master config must be updated
# to define the dictionary with used petro fields per zone per facies
USED_PETRO_FIELDS = CFG["USED_PETRO_FIELDS"]
GRID_NAMES = {
"Valysar": "Geogrid_Valysar",
"Therys": "Geogrid_Therys",
"Volon": "Geogrid_Volon",
}
FACIES_REAL_NAMES = {
"Valysar": "FACIES",
"Therys": "FACIES",
"Volon": "FACIES",
}
# For multi zone grids also zone_param_name and zone_code_names must be specified
# Example:
# ZONE_PARAM_NAME = "Zone"
# ZONE_CODE_NAMES = {
# 1: "Valysar,
# 2: "Therys",
# 3: "Volon",
# }
if __name__ == "__main__":
# Drogon uses 3 different grids and single zone grids
if USE_CONFIG_FILES:
# Alternative 1 using config file common with generate_petro_jobs
for zone_name in ["Valysar", "Therys", "Volon"]:
facies_code_names = FACIES_ZONE[zone_name]
config_file = CONFIG_FILES[zone_name]
update_petro_real(
project,
facies_code_names,
zone_name_for_single_zone_grid=zone_name,
config_file=config_file,
debug_print=DEBUG_PRINT)
else:
# Alternative 2 specify input using global_variables file
for zone_name in ["Valysar", "Therys", "Volon"]:
facies_code_names = FACIES_ZONE[zone_name]
grid_name = GRID_NAMES[zone_name]
facies_real_name = FACIES_REAL_NAMES[zone_name]
used_petro_per_facies=USED_PETRO_FIELDS
update_petro_real(
project,
facies_code_names,
grid_name=grid_name,
facies_real_name=facies_real_name,
used_petro_dict=used_petro_per_facies,
zone_name_for_single_zone_grid=zone_name,
debug_print=DEBUG_PRINT)
The *global_master_config.yml* file can include a keyword for *USED_PETRO_FIELDS*

.. code-block:: yaml
USED_PETRO_FIELDS:
Valysar:
Floodplain: [ PHIT, KLOGH ]
Channel: [ PHIT, KLOGH ]
Crevasse: [ PHIT, KLOGH ]
Therys:
Offshore: [ PHIT, KLOGH ]
Lowershoreface: [ PHIT, KLOGH ]
Uppershoreface: [ PHIT, KLOGH ]
Volon:
Floodplain: [ PHIT, KLOGH ]
Channel: [ PHIT, KLOGH ]
and optionally also for multizone grid:

.. code-block:: yaml
ZONE_CODE_NAMES:
1: Valysar
2: Therys
3: Volon
Loading

0 comments on commit aa0cbc4

Please sign in to comment.