Skip to content

Commit 62041a4

Browse files
committed
Add get_simbox_params
1 parent 82dab87 commit 62041a4

6 files changed

Lines changed: 291 additions & 0 deletions

File tree

docs/get_rms_simbox.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
rms.get_rms_simbox
2+
============================
3+
4+
The function extract the information from a geomodel grid necessary to
5+
create a box grid representing the RMS simulation box. The purpose is to save the necessary
6+
information to either create a box grid with same resolution, size, location and orientation
7+
as the a xy-regular geogrid. This information can be used in ERT to calculate cell center points
8+
for field parameters where (x,y) coordinates is relevant for the field parameter like in
9+
distance-based localization.
10+
11+
Example of use
12+
----------------
13+
14+
The function is called from a python job in RMS and use the rmsapi to get the information.
15+
16+
Example from Drogon where a small yaml file is written for each of the three zones.
17+
Here zone_index is counted from 0 from top of a (multizone-) geogrid.
18+
Drogon has only single zone grids, therefore zone_index = 0 for all three grids.
19+
20+
.. code-block:: python
21+
22+
from fmu.tools.rms.get_rms_simbox_params import get_simbox_param, write_simbox
23+
24+
if __name__ == "__main__":
25+
grid_model_names = ["Geogrid_Valysar", "Geogrid_Therys", "Geogrid_Volon"]
26+
for grid_model_name in grid_model_names:
27+
filename = "simbox_" + grid_model_name + ".yml"
28+
zone_index = 0
29+
simbox = get_simbox_param(project, grid_model_name, zone_index)
30+
write_simbox(filename, simbox)

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Contents:
2121
update_petro_real
2222
export_and_import_fields
2323
copy_rms_param_to_ertbox_grid
24+
get_rms_simbox
2425
utilities
2526
rmsvolumetrics2csv
2627
ensembles
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""
2+
Extract simbox information necessary to be able to both create a box grid
3+
with the simbox size, resolution and orientation and as input to calculate
4+
cell center position of each grid cell in simbox grid. Note, only that depth
5+
of the simbox is irrelevant where this is meant to be used in distance-based
6+
localization and therefore
7+
not saved.
8+
"""
9+
# NOTE: A bug in RMS14.2.2 cause the origin to be wrong.
10+
# But RMS15.0.1.0 and newer works.
11+
12+
from typing import Any
13+
14+
import yaml
15+
16+
17+
def get_simbox_param(project: Any, grid_model_name: str, zone_index: int) -> dict:
18+
if grid_model_name in project.grid_models:
19+
grid_model = project.grid_models[grid_model_name]
20+
grid3D = grid_model.get_grid()
21+
cell_increments = grid3D.simbox.cell_increments
22+
simbox_indexer = grid3D.simbox_indexer
23+
ijk_handedness = simbox_indexer.ijk_handedness
24+
zonation = simbox_indexer.zonation
25+
layer_range = list(zonation[zone_index][0])
26+
nlayers = len(layer_range)
27+
dimensions = simbox_indexer.dimensions
28+
zone_name = grid3D.zone_names[zone_index]
29+
simbox = {
30+
"name": str(zone_name),
31+
"origin": [float(grid3D.origin[0]), float(grid3D.origin[1])],
32+
"rotation": float(grid3D.rotation),
33+
}
34+
simbox["size"] = [
35+
float(cell_increments["x_increment"] * dimensions[0]),
36+
float(cell_increments["y_increment"] * dimensions[1]),
37+
float(cell_increments["z_increments"][zone_index] * nlayers),
38+
]
39+
simbox["dimensions"] = [
40+
int(dimensions[0]),
41+
int(dimensions[1]),
42+
int(nlayers),
43+
]
44+
simbox["handedness"] = str(ijk_handedness)
45+
return simbox
46+
raise ValueError(f"Unknown grid model {grid_model_name}")
47+
48+
49+
def write_simbox(filename: str, simbox: dict) -> None:
50+
simbox_data_yml = yaml.dump(simbox, default_flow_style=False, sort_keys=False)
51+
print(f"Write file: {filename}")
52+
with open(filename, "w") as file:
53+
file.write(simbox_data_yml)
54+
file.write("\n")
55+
print(
56+
"NOTE: If the RMS simulation box data written is to be used to\n"
57+
" define ERTBOX parameters for use in ERT update of field parameters\n"
58+
" remember that geomodel zones with top or base conform gridding\n"
59+
" may need more grid layers if the grid vary from realization to\n"
60+
" realization. For zones in geogrid with proportional gridding,\n"
61+
" it is ok to use the data from RMS simulation box as data for ERTBOX\n"
62+
" for the zone in ERT."
63+
)
64+
65+
66+
# if __name__ == "__main__":
67+
# grid_model_names = ["Geogrid_Valysar", "Geogrid_Therys", "Geogrid_Volon"]
68+
# for grid_model_name in grid_model_names:
69+
# filename = "tmp_simbox_" + grid_model_name + ".yml"
70+
# zone_index = 0
71+
# simbox = get_simbox_param(project, grid_model_name, zone_index)
72+
# write_simbox(filename, simbox)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: ZoneA
2+
origin:
3+
- 10000.0
4+
- 20000.0
5+
rotation: 0.0
6+
size:
7+
- 2500.0
8+
- 3500.0
9+
- 50.0
10+
dimensions:
11+
- 50
12+
- 70
13+
- 10
14+
handedness: left
15+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: ZoneB
2+
origin:
3+
- 10000.0
4+
- 20000.0
5+
rotation: 0.0
6+
size:
7+
- 2500.0
8+
- 3500.0
9+
- 175.0
10+
dimensions:
11+
- 50
12+
- 70
13+
- 35
14+
handedness: left
15+
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import contextlib
2+
import filecmp
3+
import shutil
4+
from os.path import isdir
5+
from pathlib import Path
6+
from typing import Any
7+
8+
import pytest
9+
10+
with contextlib.suppress(ImportError):
11+
import rmsapi
12+
13+
import xtgeo
14+
15+
from fmu.tools.rms.get_rms_simbox_params import get_simbox_param, write_simbox
16+
17+
# ======================================================================================
18+
# settings to create RMS project!
19+
20+
REMOVE_RMS_PROJECT_AFTER_TEST = False
21+
22+
TMPD = Path("TMP")
23+
TMPD.mkdir(parents=True, exist_ok=True)
24+
25+
26+
PROJNAME = "tmp_project_get_rms_simbox_params.rmsxxx"
27+
PRJ = str(TMPD / PROJNAME)
28+
RESULTDIR = TMPD / "rms_simbox"
29+
RESULTDIR.mkdir(parents=True, exist_ok=True)
30+
REFERENCE_DIR = Path("tests/rms/rms_simbox")
31+
32+
NX = 50
33+
NY = 70
34+
NZ_ZONEA = 10
35+
NZ_ZONEB = 35
36+
XINC = 50.0
37+
YINC = 50.0
38+
ZINC = 5.0
39+
ORIGIN = (10000.0, 20000.0, 2000.0)
40+
ROTATION = 50.0
41+
ZONEA = "ZoneA"
42+
ZONEB = "ZoneB"
43+
44+
45+
ZONEA_NUMBER = 1
46+
ZONEB_NUMBER = 2
47+
48+
49+
GRID_MODEL_NAME = "Geogrid"
50+
OUTPUT_FILE_PREFIX = "simbox"
51+
OUTPUT_REF_FILE_PREFIX = "ref_simbox"
52+
53+
54+
@pytest.mark.skipunlessroxar
55+
@pytest.mark.parametrize(
56+
"rotation, flip, zone_index_list",
57+
[
58+
(
59+
0.0,
60+
1,
61+
[0, 1],
62+
),
63+
],
64+
)
65+
def test_get_rms_simbox_params(
66+
rotation: float, flip: int, zone_index_list: list[int]
67+
) -> None:
68+
"""Create a tmp RMS project for testing, populate with basic data."""
69+
project = create_project()
70+
71+
create_grids(project, rotation, flip)
72+
for zone_index in zone_index_list:
73+
simbox_output_file_name = Path(RESULTDIR) / Path(
74+
OUTPUT_FILE_PREFIX
75+
+ "_angle"
76+
+ str(int(rotation))
77+
+ "_zone"
78+
+ str(zone_index)
79+
+ ".txt"
80+
)
81+
simbox_dict = get_simbox_param(project, GRID_MODEL_NAME, zone_index)
82+
write_simbox(simbox_output_file_name, simbox_dict)
83+
84+
# Verify that original is equal to the new params
85+
reference_filename = Path(REFERENCE_DIR) / Path(
86+
OUTPUT_REF_FILE_PREFIX
87+
+ "_angle"
88+
+ str(int(rotation))
89+
+ "_zone"
90+
+ str(zone_index)
91+
+ ".txt"
92+
)
93+
compare_results_with_reference(simbox_output_file_name, reference_filename)
94+
95+
project.close()
96+
97+
if REMOVE_RMS_PROJECT_AFTER_TEST:
98+
print("\n******* Teardown RMS project!\n")
99+
if isdir(PRJ):
100+
print("Remove existing project!")
101+
shutil.rmtree(PRJ)
102+
if isdir(RESULTDIR):
103+
print("Remove temporary files")
104+
shutil.rmtree(RESULTDIR)
105+
106+
107+
def create_project():
108+
"""Create a tmp RMS project for testing, populate with basic data."""
109+
110+
prj1 = str(PRJ)
111+
112+
print("\n******** Setup RMS project!\n")
113+
if isdir(prj1):
114+
print("Remove existing project! (1)")
115+
shutil.rmtree(prj1)
116+
117+
project = rmsapi.Project.create()
118+
119+
rox = xtgeo.RoxUtils(project)
120+
print("rmsapi version is", rox.roxversion)
121+
print("RMS version is", rox.rmsversion(rox.roxversion))
122+
assert "1." in rox.roxversion
123+
124+
project.save_as(prj1)
125+
return project
126+
127+
128+
def create_grids(project: Any, rotation: float, flip: int = 1):
129+
nx = NX
130+
ny = NY
131+
nz_zoneA = NZ_ZONEA
132+
nz_zoneB = NZ_ZONEB
133+
nz = nz_zoneA + nz_zoneB
134+
dimension = (nx, ny, nz)
135+
increment = (XINC, YINC, ZINC)
136+
origin = ORIGIN
137+
138+
subgrid_dict = {
139+
ZONEA: nz_zoneA,
140+
ZONEB: nz_zoneB,
141+
}
142+
geogrid = xtgeo.create_box_grid(
143+
dimension,
144+
origin=origin,
145+
increment=increment,
146+
rotation=rotation,
147+
flip=flip,
148+
)
149+
geogrid.set_subgrids(subgrid_dict)
150+
geogrid.to_roxar(project, GRID_MODEL_NAME)
151+
152+
153+
def compare_results_with_reference(filename, reference_filename):
154+
# Compare with reference
155+
check = filecmp.cmp(filename, reference_filename)
156+
if check:
157+
print("Check OK for multi zone grid")
158+
assert check

0 commit comments

Comments
 (0)