Skip to content

Commit ae06092

Browse files
committed
Add get_simbox_params
1 parent 82dab87 commit ae06092

6 files changed

Lines changed: 287 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: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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+
# TODO: NOTE: A bug in RMS14.2.2 cause the origin to be wrong.
10+
# Have to verify that newer versions of RMS is corrected before the function
11+
# below can be used. The RMS bug is only for rotated grids not for
12+
# rotation = 0. The error in RMS is that origin is set equal to MinX, MinY
13+
# and not the local origin for the rotated coordinate system aligned with
14+
# the rotated grid, typically the lower left corner point of the grid.
15+
16+
from typing import Any
17+
18+
import yaml
19+
20+
21+
def get_simbox_param(project: Any, grid_model_name: str, zone_index: int) -> dict:
22+
if grid_model_name in project.grid_models:
23+
grid_model = project.grid_models[grid_model_name]
24+
grid3D = grid_model.get_grid()
25+
cell_increments = grid3D.simbox.cell_increments
26+
simbox_indexer = grid3D.simbox_indexer
27+
ijk_handedness = simbox_indexer.ijk_handedness
28+
zonation = simbox_indexer.zonation
29+
layer_range = list(zonation[zone_index][0])
30+
nlayers = len(layer_range)
31+
dimensions = simbox_indexer.dimensions
32+
zone_name = grid3D.zone_names[zone_index]
33+
simbox = {
34+
"name": str(zone_name),
35+
"origin": [float(grid3D.origin[0]), float(grid3D.origin[1])],
36+
"rotation": float(grid3D.rotation),
37+
}
38+
simbox["size"] = [
39+
float(cell_increments["x_increment"] * dimensions[0]),
40+
float(cell_increments["y_increment"] * dimensions[1]),
41+
float(cell_increments["z_increments"][zone_index] * nlayers),
42+
]
43+
simbox["dimensions"] = [
44+
int(dimensions[0]),
45+
int(dimensions[1]),
46+
int(nlayers),
47+
]
48+
simbox["handedness"] = str(ijk_handedness)
49+
return simbox
50+
raise ValueError(f"Unknown grid model {grid_model_name}")
51+
52+
53+
def write_simbox(filename: str, simbox: dict) -> None:
54+
simbox_data_yml = yaml.dump(simbox, default_flow_style=False, sort_keys=False)
55+
print(f"Write file: {filename}")
56+
with open(filename, "w") as file:
57+
file.write(simbox_data_yml)
58+
file.write("\n")
59+
60+
61+
# if __name__ == "__main__":
62+
# grid_model_names = ["Geogrid_Valysar", "Geogrid_Therys", "Geogrid_Volon"]
63+
# for grid_model_name in grid_model_names:
64+
# filename = "tmp_simbox_" + grid_model_name + ".yml"
65+
# zone_index = 0
66+
# simbox = get_simbox_param(project, grid_model_name, zone_index)
67+
# 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: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
# TODO Extend with more cases with rotation when RMS bug is fixed
64+
],
65+
)
66+
def test_get_rms_simbox_params(
67+
rotation: float, flip: int, zone_index_list: list[int]
68+
) -> None:
69+
"""Create a tmp RMS project for testing, populate with basic data."""
70+
project = create_project()
71+
72+
create_grids(project, rotation, flip)
73+
for zone_index in zone_index_list:
74+
simbox_output_file_name = Path(RESULTDIR) / Path(
75+
OUTPUT_FILE_PREFIX
76+
+ "_angle"
77+
+ str(int(rotation))
78+
+ "_zone"
79+
+ str(zone_index)
80+
+ ".txt"
81+
)
82+
simbox_dict = get_simbox_param(project, GRID_MODEL_NAME, zone_index)
83+
write_simbox(simbox_output_file_name, simbox_dict)
84+
85+
# Verify that original is equal to the new params
86+
reference_filename = Path(REFERENCE_DIR) / Path(
87+
OUTPUT_REF_FILE_PREFIX
88+
+ "_angle"
89+
+ str(int(rotation))
90+
+ "_zone"
91+
+ str(zone_index)
92+
+ ".txt"
93+
)
94+
compare_results_with_reference(simbox_output_file_name, reference_filename)
95+
96+
project.close()
97+
98+
if REMOVE_RMS_PROJECT_AFTER_TEST:
99+
print("\n******* Teardown RMS project!\n")
100+
if isdir(PRJ):
101+
print("Remove existing project!")
102+
shutil.rmtree(PRJ)
103+
if isdir(RESULTDIR):
104+
print("Remove temporary files")
105+
shutil.rmtree(RESULTDIR)
106+
107+
108+
def create_project():
109+
"""Create a tmp RMS project for testing, populate with basic data."""
110+
111+
prj1 = str(PRJ)
112+
113+
print("\n******** Setup RMS project!\n")
114+
if isdir(prj1):
115+
print("Remove existing project! (1)")
116+
shutil.rmtree(prj1)
117+
118+
project = rmsapi.Project.create()
119+
120+
rox = xtgeo.RoxUtils(project)
121+
print("rmsapi version is", rox.roxversion)
122+
print("RMS version is", rox.rmsversion(rox.roxversion))
123+
assert "1." in rox.roxversion
124+
125+
project.save_as(prj1)
126+
return project
127+
128+
129+
def create_grids(project: Any, rotation: float, flip: int = 1):
130+
nx = NX
131+
ny = NY
132+
nz_zoneA = NZ_ZONEA
133+
nz_zoneB = NZ_ZONEB
134+
nz = nz_zoneA + nz_zoneB
135+
dimension = (nx, ny, nz)
136+
increment = (XINC, YINC, ZINC)
137+
origin = ORIGIN
138+
139+
subgrid_dict = {
140+
ZONEA: nz_zoneA,
141+
ZONEB: nz_zoneB,
142+
}
143+
geogrid = xtgeo.create_box_grid(
144+
dimension,
145+
origin=origin,
146+
increment=increment,
147+
rotation=rotation,
148+
flip=flip,
149+
)
150+
geogrid.set_subgrids(subgrid_dict)
151+
geogrid.to_roxar(project, GRID_MODEL_NAME)
152+
153+
154+
def compare_results_with_reference(filename, reference_filename):
155+
# Compare with reference
156+
check = filecmp.cmp(filename, reference_filename)
157+
if check:
158+
print("Check OK for multi zone grid")
159+
assert check

0 commit comments

Comments
 (0)