Skip to content

Commit 433f341

Browse files
committed
Update rips module, proto files, and Python examples
1 parent 4b1e16b commit 433f341

File tree

4 files changed

+247
-2
lines changed

4 files changed

+247
-2
lines changed

docs/rips/case.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,3 +1435,56 @@ def export_corner_point_grid(
14351435
return (zcorn, coord, actnum, nx, ny, nz)
14361436
else:
14371437
return ([], [], [], 0, 0, 0)
1438+
1439+
1440+
@add_method(Case)
1441+
def replace_corner_point_grid(
1442+
self,
1443+
nx: int,
1444+
ny: int,
1445+
nz: int,
1446+
coord: List[float],
1447+
zcorn: List[float],
1448+
actnum: List[int],
1449+
):
1450+
"""Replace the current case grid with new corner point grid geometry
1451+
1452+
This method modifies the geometry of an existing case by replacing it with
1453+
new grid parameters. All existing properties will be cleared.
1454+
1455+
Arguments:
1456+
nx(int): Number of cells in x direction
1457+
ny(int): Number of cells in y direction
1458+
nz(int): Number of cells in z direction
1459+
coord(list[float]): Coordinate lines as COORD keyword in Eclipse.
1460+
Each coordinate line is defined by two points (top and bottom).
1461+
Size: (nx+1) * (ny+1) * 2 * 3. Points are ordered as in Eclipse.
1462+
zcorn(list[float]): Corner depths as defined by the Eclipse keyword ZCORN.
1463+
Size: nx * ny * nz * 8
1464+
actnum(list[int]): Active cell info: cells with values > 0 are active.
1465+
Size: nx * ny * nz
1466+
"""
1467+
# Generate unique keys for three arrays
1468+
coord_key = "{}_{}".format(uuid.uuid4(), "coord")
1469+
zcorn_key = "{}_{}".format(uuid.uuid4(), "zcorn")
1470+
actnum_key = "{}_{}".format(uuid.uuid4(), "actnum")
1471+
1472+
# Get project to access key-value store
1473+
project = self.ancestor(rips.project.Project)
1474+
if not project:
1475+
raise RuntimeError("Unable to get project from case")
1476+
1477+
# Store arrays in key-value store
1478+
project.set_key_values(coord_key, coord)
1479+
project.set_key_values(zcorn_key, zcorn)
1480+
project.set_key_values(actnum_key, actnum)
1481+
1482+
# Call internal C++ method to replace the grid
1483+
self.replace_corner_point_grid_internal(
1484+
nx=nx,
1485+
ny=ny,
1486+
nz=nz,
1487+
coord_key=coord_key,
1488+
zcorn_key=zcorn_key,
1489+
actnum_key=actnum_key,
1490+
)

docs/rips/generated/generated_classes.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ def __init__(self, pb2_object: Optional[PdmObject_pb2.PdmObject]=None, channel:
129129
if CornerPointCase.__custom_init__ is not None:
130130
CornerPointCase.__custom_init__(self, pb2_object=pb2_object, channel=channel)
131131

132+
def replace_corner_point_grid_internal(self, nx: int=0, ny: int=0, nz: int=0, coord_key: str="", zcorn_key: str="", actnum_key: str="") -> None:
133+
"""
134+
Replace Corner Point Grid
135+
136+
Arguments:
137+
nx (int):
138+
ny (int):
139+
nz (int):
140+
coord_key (str):
141+
zcorn_key (str):
142+
actnum_key (str):
143+
Returns:
144+
145+
"""
146+
self._call_pdm_method_void("replace_corner_point_grid_internal", nx=nx, ny=ny, nz=nz, coord_key=coord_key, zcorn_key=zcorn_key, actnum_key=actnum_key)
147+
148+
132149
class CurveIntersection(PdmObjectBase):
133150
"""
134151
Attributes:

docs/rips/tests/test_export_corner_point_grid.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,119 @@ def test_export_corner_point_grid_roundtrip(rips_instance, initialize_test):
172172

173173
max_diff = max(diff_x, diff_y, diff_z)
174174
assert max_diff < 1e-3
175+
176+
177+
def test_replace_corner_point_grid_basic(rips_instance, initialize_test):
178+
"""Test the replace_corner_point_grid method by creating a grid and replacing it with a larger one"""
179+
180+
# Create initial grid with 2x2x2 cells
181+
nx_init, ny_init, nz_init = 2, 2, 2
182+
183+
# Generate simple coordinate data for initial grid
184+
coord_init = []
185+
for j in range(ny_init + 1):
186+
for i in range(nx_init + 1):
187+
x = i * 100.0
188+
y = j * 100.0
189+
# Top point
190+
coord_init.extend([x, y, 1000.0])
191+
# Bottom point
192+
coord_init.extend([x, y, 1100.0])
193+
194+
# Generate simple ZCORN data for initial grid
195+
zcorn_init = []
196+
for k in range(nz_init):
197+
for j in range(ny_init):
198+
for i in range(nx_init):
199+
base_depth = 1000.0 + k * 100.0
200+
# 8 corner depths for each cell
201+
zcorn_init.extend(
202+
[
203+
base_depth,
204+
base_depth,
205+
base_depth,
206+
base_depth,
207+
base_depth + 100.0,
208+
base_depth + 100.0,
209+
base_depth + 100.0,
210+
base_depth + 100.0,
211+
]
212+
)
213+
214+
# Generate ACTNUM for initial grid (all cells active)
215+
actnum_init = [1] * (nx_init * ny_init * nz_init)
216+
217+
# Create the initial grid case
218+
case = rips_instance.project.create_corner_point_grid(
219+
"InitialGrid", nx_init, ny_init, nz_init, coord_init, zcorn_init, actnum_init
220+
)
221+
222+
# Verify initial grid dimensions
223+
initial_cell_count = case.cell_count()
224+
assert initial_cell_count.reservoir_cell_count == nx_init * ny_init * nz_init
225+
226+
# Now create replacement grid with more cells (3x3x3)
227+
nx_new, ny_new, nz_new = 3, 3, 3
228+
229+
# Generate coordinate data for new grid
230+
coord_new = []
231+
for j in range(ny_new + 1):
232+
for i in range(nx_new + 1):
233+
x = i * 100.0
234+
y = j * 100.0
235+
# Top point
236+
coord_new.extend([x, y, 1000.0])
237+
# Bottom point
238+
coord_new.extend([x, y, 1200.0])
239+
240+
# Generate ZCORN data for new grid
241+
zcorn_new = []
242+
for k in range(nz_new):
243+
for j in range(ny_new):
244+
for i in range(nx_new):
245+
base_depth = 1000.0 + k * 100.0
246+
# 8 corner depths for each cell
247+
zcorn_new.extend(
248+
[
249+
base_depth,
250+
base_depth,
251+
base_depth,
252+
base_depth,
253+
base_depth + 100.0,
254+
base_depth + 100.0,
255+
base_depth + 100.0,
256+
base_depth + 100.0,
257+
]
258+
)
259+
260+
# Generate ACTNUM for new grid (all cells active)
261+
actnum_new = [1] * (nx_new * ny_new * nz_new)
262+
263+
# Replace the grid geometry
264+
case.replace_corner_point_grid(
265+
nx_new, ny_new, nz_new, coord_new, zcorn_new, actnum_new
266+
)
267+
268+
# Verify that the grid now has the new dimensions
269+
new_cell_count = case.cell_count()
270+
assert new_cell_count.reservoir_cell_count == nx_new * ny_new * nz_new
271+
assert new_cell_count.reservoir_cell_count == 27 # 3x3x3
272+
273+
# Verify the grid has more cells than before
274+
assert new_cell_count.reservoir_cell_count > initial_cell_count.reservoir_cell_count
275+
276+
# Export the replaced grid and verify dimensions
277+
exported_zcorn, exported_coord, exported_actnum, export_nx, export_ny, export_nz = (
278+
case.export_corner_point_grid()
279+
)
280+
281+
# Verify dimensions match
282+
assert export_nx == nx_new
283+
assert export_ny == ny_new
284+
assert export_nz == nz_new
285+
286+
# Verify array sizes
287+
print(exported_actnum)
288+
assert len(exported_actnum) == nx_new * ny_new * nz_new
289+
# All cells should be active
290+
assert sum(1 for x in exported_actnum if x > 0) == len(actnum_new)

docs/rips/tests/test_summary_cases.py

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import contextlib
44
import shutil
55
import tempfile
6+
import pytest
67

78
sys.path.insert(1, os.path.join(sys.path[0], "../../"))
89

@@ -115,8 +116,66 @@ def test_summary_set_values(rips_instance, initialize_test):
115116
current_keyword_count = len(addresses.values)
116117
assert current_keyword_count == original_keyword_count + 1
117118

118-
# invalid value count, check that available addresses are unchanged
119-
summary_case.set_summary_values("FOPT_2", "", [])
119+
# invalid value count should now raise an error (no longer fails silently)
120+
with pytest.raises(Exception) as exc_info:
121+
summary_case.set_summary_values("FOPT_2", "", [])
122+
# Verify error message is informative
123+
assert "size" in str(exc_info.value).lower() or "Expected" in str(exc_info.value)
124+
125+
# Verify addresses are unchanged after failed operation
120126
addresses = summary_case.available_addresses()
121127
current_keyword_count = len(addresses.values)
122128
assert current_keyword_count == original_keyword_count + 1
129+
130+
131+
def test_summary_set_values_with_long_keyword(rips_instance, initialize_test):
132+
"""Test that setting summary values with a keyword exceeding 8 characters fails with an informative error."""
133+
casePath = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
134+
summary_case = rips_instance.project.import_summary_case(casePath)
135+
assert summary_case.id == 1
136+
137+
summary_data = summary_case.summary_vector_values("FOPT")
138+
assert len(summary_data.values) == 60
139+
140+
# This keyword exceeds the 8-character SMSPEC limit
141+
long_keyword = "ROPR_FROM_1_TO_23"
142+
143+
# Currently this fails silently - after fix, it should raise an exception with a clear error message
144+
with pytest.raises(Exception) as exc_info:
145+
summary_case.set_summary_values(long_keyword, "", summary_data.values)
146+
147+
# Check that the error message is informative
148+
error_message = str(exc_info.value)
149+
assert (
150+
"8" in error_message
151+
or "character" in error_message
152+
or "length" in error_message
153+
), f"Error message should mention the 8-character limit, but got: {error_message}"
154+
155+
156+
def test_summary_set_values_with_wrong_size(rips_instance, initialize_test):
157+
"""Test that setting summary values with wrong vector size fails with an informative error."""
158+
casePath = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
159+
summary_case = rips_instance.project.import_summary_case(casePath)
160+
assert summary_case.id == 1
161+
162+
summary_data = summary_case.summary_vector_values("FOPT")
163+
expected_size = len(summary_data.values)
164+
assert expected_size == 60
165+
166+
# Try to set values with wrong size
167+
wrong_size_values = [1.0, 2.0, 3.0] # Only 3 values instead of 60
168+
169+
# Currently this fails silently - after fix, it should raise an exception with a clear error message
170+
with pytest.raises(Exception) as exc_info:
171+
summary_case.set_summary_values("TEST_KW", "", wrong_size_values)
172+
173+
# Check that the error message is informative
174+
error_message = str(exc_info.value)
175+
assert (
176+
"size" in error_message.lower() or "length" in error_message.lower()
177+
), f"Error message should mention size/length mismatch, but got: {error_message}"
178+
assert (
179+
str(expected_size) in error_message
180+
or str(len(wrong_size_values)) in error_message
181+
), f"Error message should mention expected ({expected_size}) or received ({len(wrong_size_values)}) size, but got: {error_message}"

0 commit comments

Comments
 (0)