Case And Grid Operations
This page shows Python examples from the case_and_grid_operations folder.
Add Combined Data Filter
add_combined_data_filter.py
1#######################################################
2#
3# Adds two case-level "Data Filters" combined filters
4# that AND-combine a PERMX property filter with a K-slice
5# range filter (K = 5..10):
6# 1) one with an explicit name (preserved verbatim).
7# 2) one with no name supplied, so the combined
8# filter's display name is auto-derived from its
9# children and updates when their names/bounds
10# change.
11#
12# Then shows how to mutate the PERMX lower bound after
13# creation and confirms the auto-derived combined filter
14# tracks the change while the named one stays put.
15#
16# Assumes a case is already loaded in the running
17# ResInsight instance.
18#
19#######################################################
20
21import rips
22
23resinsight = rips.Instance.find()
24
25cases = resinsight.project.cases()
26assert cases, "No case loaded in ResInsight. Open a case before running this script."
27case = cases[0]
28
29data_filters = case.data_filter_collection()
30
31
32def _build_children(combined):
33 """Add a PERMX property filter and a K=5..10 range filter to `combined`."""
34 permx = combined.add_property_filter(
35 result_variable="PERMX",
36 result_type="STATIC_NATIVE",
37 )
38 permx.lower_bound = 100.0
39 permx.upper_bound = 20000.0
40 permx.update()
41
42 combined.add_range_filter(
43 name="K=5..10",
44 start_k=5,
45 cell_count_k=6,
46 )
47 return permx
48
49
50# 1) Combined filter with a user-supplied name. The name is preserved verbatim
51# even when its children change.
52named_combined = data_filters.add_combined_filter(
53 name="My PERMX-and-K filter",
54 combine_mode="AND",
55)
56named_permx = _build_children(named_combined)
57
58# 2) Combined filter with no name. The display name is auto-derived from its
59# children and updates when child names change.
60auto_combined = data_filters.add_combined_filter(combine_mode="AND")
61auto_permx = _build_children(auto_combined)
62
63
64def _print_state(label):
65 print(f"--- {label} ---")
66 # Re-read the collection so names reflect the current project tree.
67 for c in data_filters.filters():
68 print(f" {c.name}")
69 for child in c.filters():
70 print(f" - {child.name}")
71
72
73_print_state("Initial state")
74
75# Mutate the PERMX lower bound on both.
76named_permx.lower_bound = 250.0
77named_permx.update()
78
79auto_permx.lower_bound = 250.0
80auto_permx.update()
81
82_print_state("After lower_bound 100 -> 250")
Add Perforation Filter
add_perforation_filter.py
1#######################################################
2#
3# Demonstrates associating a case-level cell filter
4# with one or more perforation intervals on a well path.
5#
6# The combined filter is created at case level (under
7# "Data Filters") and shared between two perforation
8# intervals via add_filter(). The filter is stored as a
9# typed reference, so two perforations can point to the
10# same filter without duplicating its configuration.
11#
12# This is metadata only at the moment — completion
13# export is not yet wired to consume the perforation's
14# cell filter.
15#
16# Assumes a case is already loaded in the running
17# ResInsight instance.
18#
19#######################################################
20
21import rips
22
23resinsight = rips.Instance.find()
24
25cases = resinsight.project.cases()
26assert cases, "No case loaded in ResInsight. Open a case before running this script."
27case = cases[0]
28
29data_filters = case.data_filter_collection()
30
31# Create a case-level combined filter that AND-combines a PERMX property filter
32# (100..20000) with a K-slice 5..10 range filter.
33combined = data_filters.add_combined_filter(combine_mode="AND")
34
35permx = combined.add_property_filter(
36 result_variable="PERMX",
37 result_type="STATIC_NATIVE",
38)
39permx.lower_bound = 100.0
40permx.upper_bound = 20000.0
41permx.update()
42
43combined.add_range_filter(name="K=5..10", start_k=5, cell_count_k=6)
44
45# Place the well in the centre of the case's bounding box so the example works
46# regardless of where the loaded reservoir lives in domain space.
47#
48# Note: bounding-box z is positive-up (sea level = 0, subsurface negative), but
49# append_well_target expects z positive-downward (depth). Convert with -z.
50bbox = case.reservoir_boundingbox()
51center_x = 0.5 * (bbox.min_x + bbox.max_x)
52center_y = 0.5 * (bbox.min_y + bbox.max_y)
53depth_top = -bbox.max_z # depth to reservoir top (positive)
54depth_bot = -bbox.min_z # depth to reservoir bottom (positive)
55
56# Build a vertical modeled well path: surface -> reservoir top -> just below the
57# reservoir bottom, all on the central (x, y).
58well_path_coll = resinsight.project.well_path_collection()
59well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
60well_path.name = "Perforation Filter Demo Well"
61well_path.update()
62
63geometry = well_path.well_path_geometry()
64geometry.append_well_target([center_x, center_y, 0.0])
65geometry.append_well_target([center_x, center_y, depth_top])
66geometry.append_well_target([center_x, center_y, depth_bot + 50.0])
67geometry.update()
68
69# Vertical well -> MD is depth below surface. Place two perforation intervals
70# inside the reservoir's vertical extent.
71md_span = depth_bot - depth_top
72perf1_start = depth_top + 0.20 * md_span
73perf1_end = perf1_start + 0.10 * md_span
74perf2_start = depth_top + 0.55 * md_span
75perf2_end = perf2_start + 0.20 * md_span
76
77perf1 = well_path.append_perforation_interval(perf1_start, perf1_end, 0.2, 0.76)
78perf1.add_filter(combined)
79
80perf2 = well_path.append_perforation_interval(perf2_start, perf2_end, 0.2, 0.76)
81perf2.add_filter(combined)
82
83# Read back through the well path / completions tree to confirm both perforations
84# resolve to the same filter object.
85perforations = well_path.completions().perforations().perforations()
86for p in perforations:
87 f = p.cell_filter()
88 print(
89 f" perforation {p.start_measured_depth} .. {p.end_measured_depth} -> "
90 f"{f.name if f else '<no filter>'}"
91 )
Case Grid Group
case_grid_group.py
1import os
2import rips
3
4resinsight = rips.Instance.find()
5
6test_model_path = "e:/gitroot-second/ResInsight/TestModels"
7
8case_paths = []
9case_paths.append(test_model_path + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID")
10case_paths.append(test_model_path + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID")
11case_paths.append(test_model_path + "/Case_with_10_timesteps/Real30/BRUGGE_0030.EGRID")
12case_paths.append(test_model_path + "/Case_with_10_timesteps/Real40/BRUGGE_0040.EGRID")
13
14for case_path in case_paths:
15 assert os.path.exists(case_path), (
16 "You need to set valid case paths for this script to work"
17 )
18
19case_group = resinsight.project.create_grid_case_group(case_paths=case_paths)
20
21case_group.compute_statistics()
22
23view = case_group.views()[0]
24view.apply_cell_result(rips.PropertyType.DYNAMIC_NATIVE, "PRESSURE_DEV")
Case Grid Group Generated Results
case_grid_group_generated_results.py
1import os
2import rips
3
4resinsight = rips.Instance.find()
5
6# ResInsight includes some test models. Adjust this path to fit your system
7test_model_path = "e:/gitroot-second/ResInsight/TestModels"
8
9case_paths = []
10case_paths.append(test_model_path + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID")
11case_paths.append(test_model_path + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID")
12case_paths.append(test_model_path + "/Case_with_10_timesteps/Real30/BRUGGE_0030.EGRID")
13case_paths.append(test_model_path + "/Case_with_10_timesteps/Real40/BRUGGE_0040.EGRID")
14
15for case_path in case_paths:
16 assert os.path.exists(case_path), (
17 "You need to set valid case paths for this script to work"
18 )
19
20case_group = resinsight.project.create_grid_case_group(case_paths=case_paths)
21
22cases = case_group.descendants(rips.EclipseCase)
23print("Got " + str(len(cases)) + " cases: ")
24
25for case in cases:
26 time_step_info = case.time_steps()
27 porv_results = case.active_cell_property(rips.PropertyType.STATIC_NATIVE, "PORV", 0)
28
29 for time_step_index in range(0, len(time_step_info)):
30 pressure_results = case.active_cell_property(
31 rips.PropertyType.DYNAMIC_NATIVE, "PRESSURE", time_step_index
32 )
33
34 results = []
35 for pressure, porv in zip(pressure_results, porv_results):
36 results.append(pressure * porv)
37
38 # set the computed values in the case
39 case.set_active_cell_property(
40 results, rips.PropertyType.GENERATED, "PRESSURE_PORV", time_step_index
41 )
42
43 print(
44 "Case id: " + str(case.id),
45 " Case name: " + case.name,
46 " : Calculation complete",
47 )
48
49
50print("Transferred all results back to ResInsight")
51
52# Pick a value from rips.ResultType (e.g. GENERATED, DYNAMIC_NATIVE, STATIC_NATIVE).
53# https://api.resinsight.org/en/main/rips.html#result-definition
54property_type = rips.ResultType.GENERATED
55
56property_name = "PRESSURE_PORV"
57
58statistics_case = case_group.create_statistics_case()
59statistics_case.set_source_properties(property_type, [property_name])
60statistics_case.compute_statistics()
61
62view = statistics_case.create_view()
63statistics_property_name = property_name + "_MEAN"
64view.apply_cell_result(
65 result_type=property_type, result_variable=statistics_property_name
66)
Compute Avg Poro For Region
compute_avg_poro_for_region.py
1###########################################################################################
2# This example will calculate the average value of the porosity property for a specified
3# region in the reservoir model. The region is identified by its EQLNUM value.
4###########################################################################################
5
6import rips
7
8resinsight = rips.Instance.find()
9
10cases = resinsight.project.cases()
11
12time_step = 0
13region_number = 2
14
15for case in cases:
16 sum_poro = 0.0
17 cell_cout = 0
18
19 eqlnum = case.active_cell_property(
20 rips.PropertyType.STATIC_NATIVE, "EQLNUM", time_step
21 )
22 poro = case.active_cell_property(rips.PropertyType.STATIC_NATIVE, "PORO", time_step)
23 if len(eqlnum) != len(poro):
24 print("Size of eqlnum and poro is not identical.")
25 break
26
27 for i in range(len(eqlnum)):
28 if eqlnum[i] == region_number:
29 sum_poro += poro[i]
30 cell_cout += 1
31
32 # Calculate the average porosity for the specified region
33 if cell_cout > 0:
34 average_poro = sum_poro / cell_cout
35 print(
36 f"Case {case.id}: Cell count {cell_cout} Average PORO for region {region_number} = {average_poro}"
37 )
Create Corner Point Grid
create_corner_point_grid.py
1######################################################################
2# This script creates a corner point grid from a Eclipse coord, zcorn
3# and actnum configuration.
4######################################################################
5import rips
6from xtgeo.grid3d._egrid import EGrid
7from xtgeo.io._file import FileFormat
8import numpy as np
9
10grid_filepath = "/home/resinsight/testdata/01_drogon_ahm/realization-0/iter-0/eclipse/model/DROGON-0.EGRID"
11
12name = "DROGON-0 from python"
13
14grid = EGrid.from_file(grid_filepath, fileformat=FileFormat.EGRID)
15print("Grid: ", grid)
16print("Grid type: ", type(grid))
17print("coord: ", grid.coord.shape, grid.coord.dtype)
18print("zcorn:", grid.zcorn.shape, grid.zcorn.dtype)
19print("actnum: ", grid.actnum.shape, grid.actnum.dtype)
20
21resinsight = rips.Instance.find()
22
23project = resinsight.project
24
25coord = np.ascontiguousarray(grid.coord, dtype=np.float32)
26zcorn = np.ascontiguousarray(grid.zcorn, dtype=np.float32)
27actnum = np.ascontiguousarray(grid.actnum, dtype=np.int32)
28
29
30print("coordsv: ", len(coord), type(coord[0]))
31print("zcornsv: ", len(zcorn), type(zcorn[0]))
32print("actnumsv: ", len(actnum), type(actnum[0]))
33
34
35print("Grid dimensions: ", grid.dimensions)
36nx = grid.dimensions.ncol
37ny = grid.dimensions.nrow
38nz = grid.dimensions.nlay
39
40case = project.create_corner_point_grid(name, nx, ny, nz, coord, zcorn, actnum)
41
42# Geometry properties (DEPTH, DX, DY, DZ, TOPS, BOTTOM) are computed automatically
43print("Static properties: ", case.available_properties("STATIC_NATIVE"))
44depth = case.active_cell_property("STATIC_NATIVE", "DEPTH", 0)
45print("DEPTH min/max: ", min(depth), max(depth))
Export Corner Point Grid
export_corner_point_grid.py
1######################################################################
2# This script demonstrates how to export corner point grid data from
3# ResInsight cases and recreate new grids from the exported data.
4#
5# This is the inverse operation of create_corner_point_grid.py - it
6# extracts COORD, ZCORN, and ACTNUM arrays from existing Eclipse cases.
7######################################################################
8
9import rips
10
11
12def validate_grid_dimensions(coord_array, zcorn_array, actnum_array, nx, ny, nz):
13 """
14 Validate that the exported arrays match the expected dimensions.
15
16 Args:
17 coord_array: COORD array (coordinate lines)
18 zcorn_array: ZCORN array (corner depths)
19 actnum_array: ACTNUM array (active cell flags)
20 nx, ny, nz: Grid dimensions
21
22 Returns:
23 bool: True if arrays match expected dimensions
24 """
25 total_cells = nx * ny * nz
26 expected_coord_size = (nx + 1) * (ny + 1) * 6 # 6 values per coordinate line
27 expected_zcorn_size = nx * ny * nz * 8 # 8 corner depths per cell
28
29 return (
30 len(actnum_array) == total_cells
31 and len(coord_array) == expected_coord_size
32 and len(zcorn_array) == expected_zcorn_size
33 )
34
35
36def main():
37 # Connect to ResInsight, launching it if no existing instance is found.
38 try:
39 resinsight = rips.Instance.find()
40 except rips.RipsError:
41 print("Starting ResInsight...")
42 resinsight = rips.Instance.launch(console=True)
43
44 project = resinsight.project
45 if not project.cases():
46 print("No cases in current project")
47 return
48
49 original_case = project.cases()[0]
50 if original_case is None:
51 print("Failed to load case")
52 return
53
54 print(f"Loaded case: {original_case.name}")
55
56 # Get basic case information
57 cell_count = original_case.cell_count()
58 print("Case information:")
59 print(f" Total cells: {cell_count.reservoir_cell_count}")
60 print(f" Active cells: {cell_count.active_cell_count}")
61
62 # Export corner point grid data
63 print("\nExporting corner point grid data...")
64 zcorn, coord, actnum, nx, ny, nz = original_case.export_corner_point_grid()
65
66 print("Exported arrays:")
67 print(f" ZCORN: {len(zcorn):,} values (corner depths)")
68 print(f" COORD: {len(coord):,} values (coordinate lines)")
69 print(f" ACTNUM: {len(actnum):,} values (active cell flags)")
70
71 # Grid dimensions are now returned directly from the export method!
72 print(f"\nGrid dimensions from export: {nx} x {ny} x {nz} = {nx * ny * nz:,} cells")
73
74 # Validate that the arrays match the expected dimensions
75 if validate_grid_dimensions(coord, zcorn, actnum, nx, ny, nz):
76 print("✓ Array sizes match expected dimensions perfectly")
77 else:
78 print("⚠ Array sizes don't match expected dimensions - this shouldn't happen")
79 return
80
81 # Create a new corner point grid from the exported data
82 print("\nCreating new corner point grid from exported data...")
83 recreated_name = f"{original_case.name}_Recreated"
84 recreated_case = project.create_corner_point_grid(
85 recreated_name, nx, ny, nz, coord, zcorn, actnum
86 )
87
88 if recreated_case is None:
89 print("Failed to create recreated case")
90 return
91
92 print(f"Created recreated case: {recreated_case.name}")
93
94 # Compare the two grids
95 print("\nComparing original and recreated grids:")
96
97 orig_cell_count = original_case.cell_count()
98 recreated_cell_count = recreated_case.cell_count()
99
100 print("Original grid:")
101 print(f" Total cells: {orig_cell_count.reservoir_cell_count:,}")
102 print(f" Active cells: {orig_cell_count.active_cell_count:,}")
103
104 print("Recreated grid:")
105 print(f" Total cells: {recreated_cell_count.reservoir_cell_count:,}")
106 print(f" Active cells: {recreated_cell_count.active_cell_count:,}")
107
108 # Get coordinate ranges for comparison
109 print("\nCoordinate ranges:")
110
111 # Sample some coordinates for comparison
112 orig_bbox = original_case.reservoir_boundingbox()
113 recreated_bbox = recreated_case.reservoir_boundingbox()
114
115 print("Original bounding box:")
116 print(f" X: {orig_bbox.min_x:.2f} to {orig_bbox.max_x:.2f}")
117 print(f" Y: {orig_bbox.min_y:.2f} to {orig_bbox.max_y:.2f}")
118 print(f" Z: {orig_bbox.min_z:.2f} to {orig_bbox.max_z:.2f}")
119
120 print("Recreated bounding box:")
121 print(f" X: {recreated_bbox.min_x:.2f} to {recreated_bbox.max_x:.2f}")
122 print(f" Y: {recreated_bbox.min_y:.2f} to {recreated_bbox.max_y:.2f}")
123 print(f" Z: {recreated_bbox.min_z:.2f} to {recreated_bbox.max_z:.2f}")
124
125
126if __name__ == "__main__":
127 main()
Fault Distance
fault_distance.py
1###################################################################################
2# This example prints the distance to and the name of the fault closest to a point
3###################################################################################
4
5import rips
6
7resinsight = rips.Instance.find()
8
9cases = resinsight.project.cases()
10if len(cases) == 0:
11 exit(1)
12
13case = cases[0]
14print("Using case: " + case.name)
15
16# random test point (positive Z for depth)
17point_x = 5039.84
18point_y = 6303.76
19point_z = 4144.21
20
21print("Looking for closest fault to point %f, %f, %f:" % (point_x, point_y, point_z))
22
23faultname, distance, facename = case.distance_to_closest_fault(
24 point_x, point_y, point_z
25)
26
27if facename == "":
28 print("- No fault found!")
29else:
30 print(
31 "- Distance to closest fault %s is %f, closest face direction is %s"
32 % (faultname, distance, facename)
33 )
Grid Information
grid_information.py
1######################################################################################
2# This example prints information about the grids of all cases in the current project
3######################################################################################
4
5import rips
6
7resinsight = rips.Instance.find()
8
9cases = resinsight.project.cases()
10print("Number of cases found: ", len(cases))
11for case in cases:
12 print(case.name)
13 grids = case.grids()
14 print("Number of grids: ", len(grids))
15 for grid in grids:
16 print("Grid dimensions: ", grid.dimensions())
Import Case Properties
import_case_properties.py
1#######################################################
2#
3# This file shows how to import properties for a
4# grid case created with .ROFFASC files
5#
6# Same procedure can also be used for .GRDECL files
7#
8#######################################################
9
10
11# Access to environment variables and path tools
12import os
13import pathlib
14
15# Load ResInsight Processing Server Client Library
16import rips
17
18# Connect to ResInsight instance
19resinsight = rips.Instance.find()
20
21# This requires the TestModels to be installed with ResInsight (RESINSIGHT_BUNDLE_TESTMODELS):
22resinsight_exe_path = os.environ.get("RESINSIGHT_EXECUTABLE")
23
24# Get the TestModels path from the executable path
25resinsight_install_path = pathlib.PurePath(
26 os.path.dirname(resinsight_exe_path)
27).as_posix()
28
29test_models_path = resinsight_install_path + "/TestModels/"
30
31# Get the .roff case
32roff_case_path = os.path.join(
33 test_models_path, "reek/reek_box_grid_w_out_props.roffasc"
34)
35
36roff_case = resinsight.project.load_case(roff_case_path)
37
38# PORO and EQLNUM should not be among available properties yet
39print("Available properties:")
40for prop in roff_case.available_properties(rips.PropertyType.INPUT_PROPERTY):
41 print(prop)
42
43# Import properties with file paths
44poro_property_path = os.path.join(
45 test_models_path, "reek/reek_box_PORO_property.roffasc"
46)
47eqlnum_property_path = os.path.join(
48 test_models_path, "reek/reek_box_EQLNUM_property.roffasc"
49)
50
51imported_names = roff_case.import_properties(
52 file_names=[poro_property_path, eqlnum_property_path]
53)
54
55print("Imported properties:")
56for name in imported_names.values:
57 print(name)
58
59# PORO and EQLNUM should now be among available properties
60print("Available properties:")
61for prop in roff_case.available_properties(rips.PropertyType.INPUT_PROPERTY):
62 print(prop)
Input Prop Test Async
input_prop_test_async.py
1########################################################################################
2# This example generates a derived property in an asynchronous manner
3# Meaning it does not wait for all the data for each stage to be read before proceeding
4########################################################################################
5import rips
6import time
7
8
9# Internal function for creating a result from a small chunk of poro and permx results
10# The return value of the function is a generator for the results rather than the result itself.
11def create_result(poro_chunks, permx_chunks):
12 # Loop through all the chunks of poro and permx in order
13 for poroChunk, permxChunk in zip(poro_chunks, permx_chunks):
14 resultChunk = []
15 # Loop through all the values inside the chunks, in order
16 for poro, permx in zip(poroChunk.values, permxChunk.values):
17 resultChunk.append(poro * permx)
18 # Return a generator object that behaves like a Python iterator
19 yield resultChunk
20
21
22resinsight = rips.Instance.find()
23start = time.time()
24case = resinsight.project.cases()[0]
25
26# Get a generator for the poro results. The generator will provide a chunk each time it is iterated
27poro_chunks = case.active_cell_property_async(
28 rips.PropertyType.STATIC_NATIVE, "PORO", 0
29)
30# Get a generator for the permx results. The generator will provide a chunk each time it is iterated
31permx_chunks = case.active_cell_property_async(
32 rips.PropertyType.STATIC_NATIVE, "PERMX", 0
33)
34
35# Send back the result with the result provided by a generator object.
36# Iterating the result generator will cause the script to read from the poro and permx generators
37# And return the result of each iteration
38case.set_active_cell_property_async(
39 create_result(poro_chunks, permx_chunks),
40 rips.PropertyType.GENERATED,
41 "POROPERMXAS",
42 0,
43)
44
45end = time.time()
46print("Time elapsed: ", end - start)
47print("Transferred all results back")
48view = case.views()[0].apply_cell_result(rips.PropertyType.GENERATED, "POROPERMXAS")
Input Prop Test Sync
input_prop_test_sync.py
1########################################################################################
2# This example generates a derived property in an synchronous manner
3# Meaning it completes reading each result before calculating the derived result
4# See InputPropTestAsync for how to do this asynchronously instead.
5#
6# Property/porosity/result types accept either a typed enum
7# (rips.PropertyType.STATIC_NATIVE) or a plain string ("STATIC_NATIVE"). This
8# example uses the string form; see input_prop_test_async.py for the typed-enum
9# form.
10########################################################################################
11import rips
12import time
13import grpc
14
15resinsight = rips.Instance.find()
16start = time.time()
17case = resinsight.project.cases()[0]
18
19# Read poro result into list
20poro_results = case.active_cell_property("STATIC_NATIVE", "PORO", 0)
21# Read permx result into list
22permx_results = case.active_cell_property("STATIC_NATIVE", "PERMX", 0)
23
24# Generate output result
25results = []
26for poro, permx in zip(poro_results, permx_results):
27 results.append(poro * permx)
28
29try:
30 # Send back output result
31 case.set_active_cell_property(results, "GENERATED", "POROPERMXSY", 0)
32except grpc.RpcError as e:
33 print("Exception Received: ", e)
34
35
36end = time.time()
37print("Time elapsed: ", end - start)
38print("Transferred all results back")
39
40view = case.views()[0].apply_cell_result("GENERATED", "POROPERMXSY")
Polygon Region From Project
polygon_region_from_project.py
1####################################################################################
2# This example demonstrates how to use existing polygons already defined in the
3# ResInsight project to create grid cell filters and assign a unique integer
4# region value to every active cell:
5# 1. Retrieve polygons from the project's PolygonCollection
6# 2. For each active cell, determine which polygon region it belongs to
7# 3. Create a Generated result that stores the unique integer region index
8####################################################################################
9
10import rips
11
12
13def point_in_polygon_2d(px, py, polygon_xy):
14 """Check if point (px, py) is inside a 2D polygon using the ray casting algorithm.
15
16 Arguments:
17 px (float): X coordinate of the point
18 py (float): Y coordinate of the point
19 polygon_xy (list): List of [x, y] pairs defining the polygon vertices
20
21 Returns:
22 bool: True if the point is inside the polygon, False otherwise
23 """
24 n = len(polygon_xy)
25 inside = False
26 j = n - 1
27 for i in range(n):
28 xi, yi = polygon_xy[i][0], polygon_xy[i][1]
29 xj, yj = polygon_xy[j][0], polygon_xy[j][1]
30 if ((yi > py) != (yj > py)) and (px < (xj - xi) * (py - yi) / (yj - yi) + xi):
31 inside = not inside
32 j = i
33 return inside
34
35
36resinsight = rips.Instance.find()
37
38cases = resinsight.project.cases()
39if not cases:
40 print("No cases found in the project")
41 exit()
42
43case = cases[0]
44print(f"Using case: {case.name}")
45
46# Step 1: Retrieve polygons from the project's PolygonCollection.
47# These polygons must already exist in the project before running this script.
48# Use the companion example polygon_grid_region.py to create example polygons,
49# or define your own interactively in ResInsight.
50polygon_collection = resinsight.project.descendants(rips.PolygonCollection)[0]
51polygons = polygon_collection.polygons()
52
53if not polygons:
54 print(
55 "No polygons found in the project. "
56 "Please create polygons in ResInsight before running this script."
57 )
58 exit()
59
60print(f"Found {len(polygons)} polygon(s) in the project:")
61for i, p in enumerate(polygons):
62 print(f" [{i + 1}] {p.name} ({len(p.coordinates)} vertices)")
63
64# Step 2: For each active cell, determine which polygon region it belongs to
65# by checking whether the cell center (X, Y) falls inside the polygon.
66# The polygon coordinates contain Z (depth) values which are ignored for the
67# 2D containment test.
68print("Computing cell-to-region assignments...")
69cell_centers = case.active_cell_centers()
70
71# Initialize all cells with value 0 (no region assigned)
72region_values = [0.0] * len(cell_centers)
73
74for cell_idx, cell_center in enumerate(cell_centers):
75 for polygon_idx, polygon in enumerate(polygons):
76 polygon_xy = [[c[0], c[1]] for c in polygon.coordinates]
77 if point_in_polygon_2d(cell_center.x, cell_center.y, polygon_xy):
78 # Assign 1-based region index so each region has a unique integer value
79 region_values[cell_idx] = float(polygon_idx + 1)
80 break # Assign cell to the first matching polygon
81
82# Step 3: Create a Generated result that stores the unique integer region value
83# for every active cell. Cells not covered by any polygon receive value 0.
84property_name = "POLYGON_REGION"
85case.set_active_cell_property(
86 region_values, rips.PropertyType.GENERATED, property_name, 0
87)
88
89print(f"Generated property '{property_name}' created successfully")
90for i, polygon in enumerate(polygons):
91 count = sum(1 for v in region_values if v == float(i + 1))
92 print(f" Region {i + 1} (polygon '{polygon.name}'): {count} cells")
93
94unassigned = sum(1 for v in region_values if v == 0.0)
95print(f" Unassigned (no polygon): {unassigned} cells")
96
97# Apply the generated result in the view to visualize the regions
98view = case.views()[0] if case.views() else case.create_view()
99view.apply_cell_result(
100 result_type=rips.PropertyType.GENERATED, result_variable=property_name
101)
102print(f"Applied '{property_name}' cell result to view")
Result Aliases
result_aliases.py
1#######################################################
2#
3# This file shows how to set up an alias name for
4# a result, so that you could access the data
5# using the alias name.
6#
7# This works for both eclipse and roff cases.
8#
9#######################################################
10
11
12# Access to environment variables and path tools
13import os
14import pathlib
15
16# Load ResInsight Processing Server Client Library
17import rips
18
19# Connect to ResInsight instance
20resinsight = rips.Instance.find()
21
22# This requires the TestModels to be installed with ResInsight
23# (RESINSIGHT_BUNDLE_TESTMODELS):
24resinsight_exe_path = os.environ.get("RESINSIGHT_EXECUTABLE")
25
26# Get the TestModels path from the executable path
27resinsight_install_path = pathlib.PurePath(
28 os.path.dirname(resinsight_exe_path)
29).as_posix()
30
31test_models_path = resinsight_install_path + "/TestModels/"
32
33# Get the .roff case
34roff_case_path = os.path.join(test_models_path, "reek/reek_box_grid_w_props.roff")
35
36roff_case = resinsight.project.load_case(roff_case_path)
37
38# Print all available properties
39print("Results on file:")
40for prop in roff_case.available_properties(rips.PropertyType.STATIC_NATIVE):
41 print(prop)
42
43# The name "DYBDE" should point to the "DEPTH" result
44roff_case.add_result_alias("DEPTH", "DYBDE")
45
46# The name "PERMX" should point to the "BOTTOM" result
47roff_case.add_result_alias("BOTTOM", "PERMX")
48
49# Print all available properties, now with two additional props
50print("Results including aliases:")
51for prop in roff_case.available_properties(rips.PropertyType.STATIC_NATIVE):
52 print(prop)
53
54real_result = roff_case.grid_property(rips.PropertyType.STATIC_NATIVE, "BOTTOM", 0)
55alias_result = roff_case.grid_property(rips.PropertyType.STATIC_NATIVE, "PERMX", 0)
56
57if real_result[40] == alias_result[40]:
58 print("Result values at index 40 match!")
59
60# Remove our aliases
61roff_case.clear_result_aliases()
62
63# Print all available properties, now just the original ones
64print("Original results:")
65for prop in roff_case.available_properties(rips.PropertyType.STATIC_NATIVE):
66 print(prop)
67
68try:
69 alias_result = roff_case.grid_property(rips.PropertyType.STATIC_NATIVE, "PERMX", 0)
70except Exception:
71 print("Result PERMX no longer exists!")
Selected Cells
selected_cells.py
1############################################################################
2# This example prints center and corners for the currently selected cells
3# in ResInsight
4############################################################################
5
6import rips
7
8resinsight = rips.Instance.find()
9cases = resinsight.project.cases()
10
11print("Got " + str(len(cases)) + " cases: ")
12for case in cases:
13 print(case.name)
14 cells = case.selected_cells()
15 print("Found " + str(len(cells)) + " selected cells")
16
17 time_step_info = case.time_steps()
18
19 for idx, cell in enumerate(cells):
20 print(
21 "Selected cell: [{}, {}, {}] grid: {}".format(
22 cell.ijk.i + 1, cell.ijk.j + 1, cell.ijk.k + 1, cell.grid_index
23 )
24 )
25
26 # Get the grid and dimensions
27 grid = case.grids()[cell.grid_index]
28 dimensions = grid.dimensions()
29
30 # Map ijk to cell index
31 cell_index = (
32 dimensions.i * dimensions.j * cell.ijk.k
33 + dimensions.i * cell.ijk.j
34 + cell.ijk.i
35 )
36
37 # Print the cell center
38 cell_centers = grid.cell_centers()
39 cell_center = cell_centers[cell_index]
40 print(
41 "Cell center: [{}, {}, {}]".format(
42 cell_center.x, cell_center.y, cell_center.z
43 )
44 )
45
46 # Print the cell corners
47 cell_corners = grid.cell_corners()[cell_index]
48 print("Cell corners:")
49 print("c0:\n" + str(cell_corners.c0))
50 print("c1:\n" + str(cell_corners.c1))
51 print("c2:\n" + str(cell_corners.c2))
52 print("c3:\n" + str(cell_corners.c3))
53 print("c4:\n" + str(cell_corners.c4))
54 print("c5:\n" + str(cell_corners.c5))
55 print("c6:\n" + str(cell_corners.c6))
56 print("c7:\n" + str(cell_corners.c7))
57
58 for tidx, timestep in enumerate(time_step_info):
59 # Read the full SOIL result for time step
60 soil_results = case.selected_cell_property(
61 rips.PropertyType.DYNAMIC_NATIVE, "SOIL", tidx
62 )
63 print(
64 "SOIL: {} ({}.{}.{})".format(
65 soil_results[idx], timestep.year, timestep.month, timestep.day
66 )
67 )
Set Cell Result
set_cell_result.py
1######################################################################
2# This script applies a cell result to the first view in the project
3######################################################################
4import rips
5
6resinsight = rips.Instance.find()
7
8view = resinsight.project.views()[0]
9view.apply_cell_result(
10 result_type=rips.PropertyType.STATIC_NATIVE, result_variable="DX"
11)
Set Discrete Active Cell Property
set_discrete_active_cell_property.py
1######################################################################
2# This script creates a discrete (integer) property for all active
3# cells in the first case in the project.
4#
5# Passing data_type=rips.PropertyDataType.INTEGER flags the property as
6# discrete regardless of the property name (previously this required the
7# name to end with "NUM").
8######################################################################
9import rips
10
11resinsight = rips.Instance.find()
12
13case = resinsight.project.case(case_id=0)
14
15# Derive a discrete region id from a continuous property.
16poro = case.active_cell_property(rips.PropertyType.STATIC_NATIVE, "PORO", 0)
17region_ids = [int(value * 100) % 4 for value in poro]
18
19print("Applying discrete values to active cells")
20case.set_active_cell_property(
21 region_ids,
22 rips.PropertyType.GENERATED,
23 "MY_REGION",
24 0,
25 data_type=rips.PropertyDataType.INTEGER,
26)
27
28# Bind integer values to text labels so the legend shows names instead of numbers.
29case.set_discrete_property_category_names(
30 property_name="MY_REGION",
31 value_names={0: "Sand", 1: "Shale", 2: "Coal", 3: "Limestone"},
32)
33
34# Introspect the property: data_type, category names, and category colors.
35data_type = case.property_data_type(
36 property_type=rips.PropertyType.GENERATED,
37 property_name="MY_REGION",
38)
39print(f"MY_REGION data type: {data_type}")
40assert data_type == rips.PropertyDataType.INTEGER
41
42print("MY_REGION category names:", case.discrete_property_category_names("MY_REGION"))
43print("MY_REGION category colors:", case.discrete_property_category_colors("MY_REGION"))
Set Discrete Grid Property
set_discrete_grid_property.py
1######################################################################
2# This script creates a discrete (integer) grid property for all grid
3# cells in the first case in the project.
4#
5# A discrete property is visualized with a category legend, in contrast
6# to the continuous legend used for floating point properties. Passing
7# data_type=rips.PropertyDataType.INTEGER flags the property as discrete
8# regardless of the property name (previously this required the name to
9# end with "NUM").
10######################################################################
11import rips
12
13resinsight = rips.Instance.find()
14
15case = resinsight.project.case(case_id=0)
16grid = case.grid()
17grid_cell_count = grid.cell_count()
18print("total cell count : " + str(grid_cell_count))
19
20# Assign a simple region id based on IJK index.
21values = []
22for i in range(0, grid_cell_count):
23 values.append(i % 4)
24
25print("Applying discrete values to main grid")
26case.set_grid_property(
27 values,
28 rips.PropertyType.STATIC_NATIVE,
29 "MY_REGION",
30 0,
31 data_type=rips.PropertyDataType.INTEGER,
32)
33
34# Bind integer values to text labels so the legend shows names instead of numbers.
35# Colors are optional — values without a color get an auto-assigned palette color.
36case.set_discrete_property_category_names(
37 property_name="MY_REGION",
38 value_names={0: "Sand", 1: "Shale", 2: "Coal", 3: "Limestone"},
39 value_colors={0: "#e6c878", 1: "#646464"},
40)
Set Flow Diagnostics Result
set_flow_diagnostics_result.py
1######################################################################
2# This script applies a flow diagnostics cell result to the first view in the project
3######################################################################
4
5# Load ResInsight Processing Server Client Library
6import rips
7
8# Connect to ResInsight instance
9resinsight = rips.Instance.find()
10
11view = resinsight.project.view(view_id=1)
12# view.apply_flow_diagnostics_cell_result(result_variable='Fraction',
13# selection_mode='FLOW_TR_INJ_AND_PROD')
14
15# Example of setting individual wells. Commented out because well names are case specific.
16view.apply_flow_diagnostics_cell_result(
17 result_variable="Fraction",
18 selection_mode="FLOW_TR_BY_SELECTION",
19 injectors=["C-1H", "C-2H", "F-2H"],
20 producers=["B-1AH", "B-3H", "D-1H"],
21)
Set Grid Properties
set_grid_properties.py
1######################################################################
2# This script sets values for all grid cells in the first case in the project
3# The script is intended to be used for TEST10K_FLT_LGR_NNC.EGRID
4# This grid case contains one LGR
5######################################################################
6import rips
7
8resinsight = rips.Instance.find()
9
10case = resinsight.project.case(case_id=0)
11grid = case.grid()
12grid_cell_count = grid.cell_count()
13print("total cell count : " + str(grid_cell_count))
14
15values = []
16for i in range(0, grid_cell_count):
17 values.append(i % 2 * 0.75)
18
19# Assign value to IJK grid cell at (31, 53, 21)
20grid = case.grid()
21property_data_index = grid.property_data_index_from_ijk(31, 53, 21)
22values[property_data_index] = 1.5
23
24print("Applying values to main grid")
25case.set_grid_property(values, rips.PropertyType.STATIC_NATIVE, "MY_DATA", 0)
26
27values_from_ri = case.grid_property(rips.PropertyType.STATIC_NATIVE, "MY_DATA", 0)
28assert values[property_data_index] == values_from_ri[property_data_index]
29
30# Get LGR grid as grid index 1
31grid = case.grid(1)
32grid_cell_count = grid.cell_count()
33print("lgr cell count : " + str(grid_cell_count))
34
35values = []
36for i in range(0, grid_cell_count):
37 values.append(i % 3 * 0.75)
38
39print("Applying values to LGR grid")
40case.set_grid_property(values, rips.PropertyType.STATIC_NATIVE, "MY_DATA", 0, 1)
41values_from_ri = case.grid_property(rips.PropertyType.STATIC_NATIVE, "MY_DATA", 0, 1)
Soil Average Async
soil_average_async.py
1###########################################################################################
2# This example will asynchronously calculate the average value for SOIL for all time steps
3###########################################################################################
4
5import rips
6import time
7
8resinsight = rips.Instance.find()
9
10start = time.time()
11
12# Get the case with case id 0
13case = resinsight.project.case(case_id=0)
14
15# Get a list of all time steps
16timeSteps = case.time_steps()
17
18averages = []
19for i in range(0, len(timeSteps)):
20 # Get the results from time step i asynchronously
21 # It actually returns a generator object almost immediately
22 result_chunks = case.active_cell_property_async(
23 rips.PropertyType.DYNAMIC_NATIVE, "SOIL", i
24 )
25 mysum = 0.0
26 count = 0
27 # Loop through and append the average. each time we loop resultChunks
28 # We will trigger a read of the input data, meaning the script will start
29 # Calculating averages before the whole resultValue for this time step has been received
30 for chunk in result_chunks:
31 mysum += sum(chunk.values)
32 count += len(chunk.values)
33
34 averages.append(mysum / count)
35
36end = time.time()
37print("Time elapsed: ", end - start)
38print(averages)
Soil Average Sync
soil_average_sync.py
1###########################################################################################
2# This example will synchronously calculate the average value for SOIL for all time steps
3#
4# Property/porosity types accept either a typed enum (rips.PropertyType.DYNAMIC_NATIVE) or
5# a plain string ("DYNAMIC_NATIVE"). This example uses the string form; see
6# soil_average_async.py for the typed-enum form.
7###########################################################################################
8import rips
9import time
10
11resinsight = rips.Instance.find()
12
13start = time.time()
14
15# Get the case with case id 0
16case = resinsight.project.case(case_id=0)
17
18# Get a list of all time steps
19time_steps = case.time_steps()
20
21averages = []
22for i in range(0, len(time_steps)):
23 # Get a list of all the results for time step i
24 results = case.active_cell_property("DYNAMIC_NATIVE", "SOIL", i)
25 mysum = sum(results)
26 averages.append(mysum / len(results))
27
28end = time.time()
29print("Time elapsed: ", end - start)
30print(averages)
Soil Porv Async
soil_porv_async.py
1##############################################################################
2# This example will create a derived result for each time step asynchronously
3##############################################################################
4
5import rips
6import time
7
8
9# Internal function for creating a result from a small chunk of soil and porv results
10# The return value of the function is a generator for the results rather than the result itself.
11def create_result(soil_chunks, porv_chunks):
12 for soil_chunk, porv_chunk in zip(soil_chunks, porv_chunks):
13 resultChunk = []
14 for soil_value, porv_value in zip(soil_chunk.values, porv_chunk.values):
15 resultChunk.append(soil_value * porv_value)
16 # Return a Python generator
17 yield resultChunk
18
19
20resinsight = rips.Instance.find()
21start = time.time()
22case = resinsight.project.cases()[0]
23timeStepInfo = case.time_steps()
24
25# Get a generator for the porv results. The generator will provide a chunk each time it is iterated
26porv_chunks = case.active_cell_property_async(
27 rips.PropertyType.STATIC_NATIVE, "PORV", 0
28)
29
30# Read the static result into an array, so we don't have to transfer it for each iteration
31# Note we use the async method even if we synchronise here, because we need the values chunked
32# ... to match the soil chunks
33porv_array = []
34for porv_chunk in porv_chunks:
35 porv_array.append(porv_chunk)
36
37for i in range(0, len(timeStepInfo)):
38 # Get a generator object for the SOIL property for time step i
39 soil_chunks = case.active_cell_property_async(
40 rips.PropertyType.DYNAMIC_NATIVE, "SOIL", i
41 )
42 # Create the generator object for the SOIL * PORV derived result
43 result_generator = create_result(soil_chunks, iter(porv_array))
44 # Send back the result asynchronously with a generator object
45 case.set_active_cell_property_async(
46 result_generator, rips.PropertyType.GENERATED, "SOILPORVAsync", i
47 )
48
49end = time.time()
50print("Time elapsed: ", end - start)
51
52print("Transferred all results back")
53
54view = case.views()[0].apply_cell_result(rips.PropertyType.GENERATED, "SOILPORVAsync")
Soil Porv Sync
soil_porv_sync.py
1##############################################################################
2# This example will create a derived result for each time step synchronously
3##############################################################################
4
5import rips
6import time
7
8resinsight = rips.Instance.find()
9start = time.time()
10case = resinsight.project.cases()[0]
11
12# Read the full porv result
13porv_results = case.active_cell_property(rips.PropertyType.STATIC_NATIVE, "PORV", 0)
14time_step_info = case.time_steps()
15
16for i in range(0, len(time_step_info)):
17 # Read the full SOIl result for time step i
18 soil_results = case.active_cell_property(
19 rips.PropertyType.DYNAMIC_NATIVE, "SOIL", i
20 )
21
22 # Generate the result by looping through both lists in order
23 results = []
24 for soil, porv in zip(soil_results, porv_results):
25 results.append(soil * porv)
26
27 # Send back result
28 case.set_active_cell_property(
29 results, rips.PropertyType.GENERATED, "SOILPORVSync", i
30 )
31
32end = time.time()
33print("Time elapsed: ", end - start)
34
35print("Transferred all results back")
36
37view = case.views()[0].apply_cell_result(rips.PropertyType.GENERATED, "SOILPORVSync")