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")