Wells And Fractures

This page shows Python examples from the wells_and_fractures folder.

Accumulated Perforation Length

accumulated_perforation_length.py
 1###################################################################################
 2# This example will connect to ResInsight, retrieve a list of
 3# simulation wells for a case and get the accumulated perforated length for all
 4# simulation wells per timestep. If a well is closed at a given timestep, the
 5# accumulated perforated length will be zero.
 6###################################################################################
 7
 8# Import the ResInsight Processing Server Module
 9import rips
10import sys
11
12# Connect to ResInsight
13resinsight = rips.Instance.find()
14if resinsight is None:
15    sys.exit("ResInsight is not running. Please start ResInsight and try again.")
16
17# Get a list of all wells
18cases = resinsight.project.cases()
19if len(cases) == 0:
20    sys.exit("No cases found in the project. Please open a case and try again.")
21
22case = cases[0]
23print("Using Case: " + case.name)
24
25timesteps = case.time_steps()
26
27# store results in a dictionary,
28# use well name as the key and a list of the wells accumulated perforation
29# lengths for each timestep as the value
30results = {}
31
32# loop over all available simulation wells
33sim_wells = case.simulation_wells()
34for sim_well in sim_wells:
35    acclengths = []
36    for tidx, timestep in enumerate(timesteps):
37        acclengths.append(sim_well.accumulated_perforation_length(tidx))
38    results[sim_well.name] = acclengths
39
40# Print header
41header = ["Timestep"]
42for tidx, ts in enumerate(timesteps):
43    header.append("%d/%d/%d" % (ts.day, ts.month, ts.year))
44print(";".join(header))
45
46# Print the results
47for well_name, lengths in results.items():
48    line = [well_name]
49    for idx, length in enumerate(lengths):
50        line.append(str(length))
51    print(";".join(line))

All Simulation Wells

all_simulation_wells.py
 1###################################################################################
 2# This example will connect to ResInsight, retrieve a list of
 3# simulation wells and print info
 4###################################################################################
 5
 6# Import the ResInsight Processing Server Module
 7import rips
 8
 9# Connect to ResInsight
10resinsight = rips.Instance.find()
11if resinsight is not None:
12    # Get a list of all wells
13    cases = resinsight.project.cases()
14
15    for case in cases:
16        print("Case id: " + str(case.id))
17        print("Case name: " + case.name)
18
19        timesteps = case.time_steps()
20        sim_wells = case.simulation_wells()
21        for sim_well in sim_wells:
22            print("Simulation well: " + sim_well.name)
23
24            for tidx, timestep in enumerate(timesteps):
25                status = sim_well.status(tidx)
26                cells = sim_well.cells(tidx)
27                print(
28                    "timestep: "
29                    + str(tidx)
30                    + " type: "
31                    + status.well_type
32                    + " open: "
33                    + str(status.is_open)
34                    + " cells:"
35                    + str(len(cells))
36                )

All Wells

all_wells.py
 1###################################################################################
 2# This example will connect to ResInsight, retrieve a list of wells and print info
 3#
 4###################################################################################
 5
 6# Import the ResInsight Processing Server Module
 7import rips
 8
 9# Connect to ResInsight
10resinsight = rips.Instance.find()
11if resinsight is not None:
12    # Get a list of all wells
13    wells = resinsight.project.well_paths()
14
15    print("Got " + str(len(wells)) + " wells: ")
16    for well in wells:
17        print("Well name: " + well.name)

Append Lateral To Well

append_lateral_to_well.py
 1import rips
 2
 3resinsight = rips.Instance.find()
 4if resinsight is None:
 5    raise RuntimeError("No running ResInsight instance found on the expected ports.")
 6
 7# Create a modeled well path and add well path targets
 8# The coordinates are based on the Norne case
 9
10well_path_coll = resinsight.project.well_path_collection()
11well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
12well_path.name = "Test Well-1"
13well_path.update()
14
15geometry = well_path.well_path_geometry()
16
17reference_point = geometry.reference_point
18reference_point[0] = 457196
19reference_point[1] = 7322270
20reference_point[2] = 2742
21geometry.update()  # Commit updates back to ResInsight
22
23# Create the first well target at the reference point
24coord = [0, 0, 0]
25geometry.append_well_target(coord)
26
27# Append new well targets relative the the reference point
28coord = [454.28, 250, -10]
29target = geometry.append_well_target(coord)
30
31coord = [1054.28, 250, -50]
32target = geometry.append_well_target(coord)
33
34################################
35## Create a lateral well path and append it to the main well path
36################################
37
38lateral_well = well_path_coll.add_new_object(rips.ModeledWellPath)
39lateral_well.name = "Lateral-1"
40lateral_well.update()
41
42lateral_geometry = lateral_well.well_path_geometry()
43
44# Only create geometry starting from the first target of the lateral
45lateral_geometry.use_auto_generated_target_at_sea_level = False
46
47reference_point = lateral_geometry.reference_point
48reference_point[0] = 457550
49reference_point[1] = 7322481
50reference_point[2] = 2735
51lateral_geometry.update()  # Commit updates back to ResInsight
52
53coord = [0, 0, 0]
54lateral_geometry.append_well_target(coord)
55
56coord = [454.28, 250, -10]
57target = lateral_geometry.append_well_target(coord)
58
59coord = [1054.28, 250, -50]
60target = lateral_geometry.append_well_target(coord)
61
62# Append the lateral to the main well path
63well_path.append_lateral_from_geometry(lateral_well)

Completion Data

completion_data.py
  1###################################################################################
  2# This example will connect to ResInsight, retrieve a list of wells, print info and
  3#  get the completion data for the first well found
  4#
  5###################################################################################
  6
  7# Import the ResInsight Processing Server Module
  8import rips
  9
 10
 11# helper method to format printing for optional fields
 12def fieldValueOrDefaultText(grpc_object, optional_field_name: str):
 13    if not grpc_object.HasField(optional_field_name):
 14        return "1*"
 15    return str(grpc_object.__getattribute__(optional_field_name))
 16
 17
 18# Connect to ResInsight
 19resinsight = rips.Instance.find()
 20if resinsight is None:
 21    exit(1)
 22
 23# Get a list of all wells
 24wells = resinsight.project.well_paths()
 25
 26# Get a list of all cases
 27cases = resinsight.project.cases()
 28
 29# Use the first one
 30the_case = cases[0]
 31print("Using case " + the_case.name)
 32
 33print("Got " + str(len(wells)) + " well paths: ")
 34for well in wells:
 35    print("Well path name: " + well.name + "\n\n")
 36
 37    completion_data = well.completion_data(the_case.id)
 38
 39    print("WELSPECS")
 40
 41    welspecs = completion_data.welspecs
 42    welspecl_entries = []
 43
 44    for line in welspecs:
 45        # Check if grid_name is present and not empty
 46        has_grid_name = (
 47            hasattr(line, "grid_name")
 48            and line.HasField("grid_name")
 49            and line.grid_name.strip()
 50        )
 51
 52        if has_grid_name:
 53            # Store for WELSPECL section
 54            welspecl_entries.append(line)
 55        else:
 56            # Output as WELSPECS
 57            txt = line.well_name + "  "
 58            txt += line.group_name + "  "
 59            txt += str(line.grid_i) + "  "
 60            txt += str(line.grid_j) + "  "
 61            txt += fieldValueOrDefaultText(line, "bhp_depth") + "  "
 62            txt += line.phase + "  "
 63            txt += fieldValueOrDefaultText(line, "drainage_radius") + "  "
 64            txt += fieldValueOrDefaultText(line, "inflow_equation") + "  "
 65            txt += fieldValueOrDefaultText(line, "auto_shut_in") + "  "
 66            txt += fieldValueOrDefaultText(line, "cross_flow") + "  "
 67            txt += fieldValueOrDefaultText(line, "pvt_num") + "  "
 68            txt += fieldValueOrDefaultText(line, "hydrostatic_density_calc") + "  "
 69            txt += fieldValueOrDefaultText(line, "fip_region") + "  "
 70            txt += "/"
 71
 72            print(txt)
 73
 74    print("/\n")
 75
 76    # Output WELSPECL section if there are entries with grid_name
 77    if len(welspecl_entries) > 0:
 78        print("WELSPECL")
 79
 80        for line in welspecl_entries:
 81            txt = line.well_name + "  "
 82            txt += line.group_name + "  "
 83            txt += line.grid_name + "  "
 84            txt += str(line.grid_i) + "  "
 85            txt += str(line.grid_j) + "  "
 86            txt += fieldValueOrDefaultText(line, "bhp_depth") + "  "
 87            txt += line.phase + "  "
 88            txt += fieldValueOrDefaultText(line, "drainage_radius") + "  "
 89            txt += fieldValueOrDefaultText(line, "inflow_equation") + "  "
 90            txt += fieldValueOrDefaultText(line, "auto_shut_in") + "  "
 91            txt += fieldValueOrDefaultText(line, "cross_flow") + "  "
 92            txt += fieldValueOrDefaultText(line, "pvt_num") + "  "
 93            txt += fieldValueOrDefaultText(line, "hydrostatic_density_calc") + "  "
 94            txt += fieldValueOrDefaultText(line, "fip_region") + "  "
 95            txt += "/"
 96
 97            print(txt)
 98
 99        print("/\n")
100
101    compdat = completion_data.compdat
102
103    complump_entries = []
104    compdatl_entries = []
105
106    print("COMPDAT")
107
108    for line in compdat:
109        # Check if grid_name is present and not empty
110        has_grid_name = (
111            hasattr(line, "grid_name")
112            and line.HasField("grid_name")
113            and line.grid_name.strip()
114        )
115
116        if has_grid_name:
117            # Store for COMPDATL section
118            compdatl_entries.append(line)
119        else:
120            # Output as COMPDAT
121            txt = ""
122            complump = ""
123
124            if line.HasField("start_md"):
125                txt += "-- Perforation MD In " + str(line.start_md)
126                txt += ", MD Out " + str(line.end_md) + "--\n"
127
128            txt += "   "
129            txt += line.well_name + "  "
130            txt += str(line.grid_i) + "  "
131            txt += str(line.grid_j) + "  "
132            txt += str(line.upper_k) + "  "
133            txt += str(line.lower_k) + "  "
134            txt += line.open_shut_flag + "  "
135            txt += fieldValueOrDefaultText(line, "saturation") + "  "
136            txt += str(line.transmissibility) + "  "
137            txt += str(line.diameter) + "  "
138            txt += str(line.kh) + "  "
139            txt += fieldValueOrDefaultText(line, "skin_factor") + "  "
140            txt += fieldValueOrDefaultText(line, "d_factor") + "  "
141            txt += "'%s'" % line.direction
142            txt += " /"
143
144            if (line.HasField("completion_number")) and (line.completion_number > 0):
145                complump += "   "
146                complump += line.well_name + "  "
147                complump += str(line.grid_i) + "  "
148                complump += str(line.grid_j) + "  "
149                complump += str(line.upper_k) + "  "
150                complump += str(line.lower_k) + "  "
151                complump += str(line.completion_number) + "  "
152                complump += " /"
153
154                complump_entries.append(complump)
155
156            print(txt)
157
158    print("/\n")
159
160    # Output COMPDATL section if there are entries with grid_name
161    if len(compdatl_entries) > 0:
162        print("COMPDATL")
163
164        for line in compdatl_entries:
165            txt = ""
166
167            if line.HasField("start_md"):
168                txt += "-- Perforation MD In " + str(line.start_md)
169                txt += ", MD Out " + str(line.end_md) + "--\n"
170
171            txt += "   "
172            txt += line.well_name + "  "
173            txt += line.grid_name + "  "
174            txt += str(line.grid_i) + "  "
175            txt += str(line.grid_j) + "  "
176            txt += str(line.upper_k) + "  "
177            txt += str(line.lower_k) + "  "
178            txt += line.open_shut_flag + "  "
179            txt += fieldValueOrDefaultText(line, "saturation") + "  "
180            txt += str(line.transmissibility) + "  "
181            txt += str(line.diameter) + "  "
182            txt += str(line.kh) + "  "
183            txt += fieldValueOrDefaultText(line, "skin_factor") + "  "
184            txt += fieldValueOrDefaultText(line, "d_factor") + "  "
185            txt += "'%s'" % line.direction
186            txt += " /"
187
188            print(txt)
189
190        print("/\n")
191
192    if len(complump_entries) > 0:
193        print("COMPLUMP")
194        for complump_entry in complump_entries:
195            print(complump_entry)
196        print("/\n")
197    else:
198        print("-- No COMPLUMP entries --\n")
199
200    print("WELSEGS")
201    welsegs = completion_data.welsegs
202    if (welsegs is None) or (len(welsegs) == 0):
203        print("  -- No WELSEGS data --\n")
204    else:
205        for welsegs_entry in welsegs:
206            # Print WELSEGS header
207            header = welsegs_entry.header
208            txt = "-- Header: " + header.well_name + "\n"
209            txt += "   " + header.well_name + "  "
210            txt += str(header.top_depth) + "  "
211            txt += str(header.top_length) + "  "
212            txt += fieldValueOrDefaultText(header, "wellbore_volume") + "  "
213            txt += header.info_type + "  "
214            txt += fieldValueOrDefaultText(header, "pressure_components") + "  "
215            txt += fieldValueOrDefaultText(header, "flow_model")
216            txt += " /"
217            print(txt)
218
219            # Print WELSEGS segment rows
220            for row in welsegs_entry.row:
221                txt = "   "
222                txt += str(row.segment_1) + "  "
223                txt += str(row.segment_2) + "  "
224                txt += str(row.branch) + "  "
225                txt += str(row.join_segment) + "  "
226                txt += str(row.length) + "  "
227                txt += str(row.depth) + "  "
228                txt += fieldValueOrDefaultText(row, "diameter") + "  "
229                txt += fieldValueOrDefaultText(row, "roughness") + "  "
230                txt += " /"
231                print(txt)
232
233    print("/")
234
235    # Print COMPSEGS (MSW completion segments)
236    print("\nCOMPSEGS")
237    compsegs = completion_data.compsegs
238    compsegl_entries = []
239
240    if (compsegs is None) or (len(compsegs) == 0):
241        print("  -- No COMPSEGS data --")
242    else:
243        for compseg in compsegs:
244            # Check if grid_name is present and not empty
245            has_grid_name = (
246                hasattr(compseg, "grid_name")
247                and compseg.HasField("grid_name")
248                and compseg.grid_name.strip()
249            )
250
251            if has_grid_name:
252                # Store for COMPSEGL section
253                compsegl_entries.append(compseg)
254            else:
255                # Output as COMPSEGS
256                txt = "   "
257                txt += str(compseg.i) + "  "
258                txt += str(compseg.j) + "  "
259                txt += str(compseg.k) + "  "
260                txt += str(compseg.branch) + "  "
261                txt += str(compseg.distance_start) + "  "
262                txt += str(compseg.distance_end) + "  "
263                txt += " /"
264                print(txt)
265
266    print("/\n")
267
268    # Output COMPSEGL section if there are entries with grid_name
269    if len(compsegl_entries) > 0:
270        print("COMPSEGL")
271
272        for compseg in compsegl_entries:
273            txt = "   "
274            txt += compseg.grid_name + "  "
275            txt += str(compseg.i) + "  "
276            txt += str(compseg.j) + "  "
277            txt += str(compseg.k) + "  "
278            txt += str(compseg.branch) + "  "
279            txt += str(compseg.distance_start) + "  "
280            txt += str(compseg.distance_end) + "  "
281            txt += " /"
282            print(txt)
283
284        print("/\n")

Create And Export Stim Plan Model

create_and_export_stim_plan_model.py
  1# Load ResInsight Processing Server Client Library
  2import rips
  3import tempfile
  4from os.path import expanduser
  5from pathlib import Path
  6
  7# Connect to ResInsight instance
  8resinsight = rips.Instance.find()
  9# Example code
 10project = resinsight.project
 11
 12# Look for input files in the home directory of the user
 13home_dir = expanduser("~")
 14elastic_properties_file_path = (Path(home_dir) / "elastic_properties.csv").as_posix()
 15print("Elastic properties file path:", elastic_properties_file_path)
 16
 17facies_properties_file_path = (Path(home_dir) / "facies_id.roff").as_posix()
 18print("Facies properties file path:", facies_properties_file_path)
 19
 20# Find a case
 21cases = resinsight.project.cases()
 22case = cases[1]
 23
 24# Use the last time step
 25time_steps = case.time_steps()
 26time_step = time_steps[len(time_steps) - 1]
 27
 28
 29# Create stim plan model template
 30fmt_collection = project.descendants(rips.StimPlanModelTemplateCollection)[0]
 31stim_plan_model_template = fmt_collection.append_stim_plan_model_template(
 32    eclipse_case=case,
 33    time_step=time_step,
 34    elastic_properties_file_path=elastic_properties_file_path,
 35    facies_properties_file_path=facies_properties_file_path,
 36)
 37stim_plan_model_template.overburden_formation = "Garn"
 38stim_plan_model_template.overburden_facies = "Shale"
 39stim_plan_model_template.underburden_formation = "Garn"
 40stim_plan_model_template.underburden_facies = "Shale"
 41stim_plan_model_template.overburden_height = 68
 42stim_plan_model_template.update()
 43print("Overburden: ", stim_plan_model_template.overburden_formation)
 44
 45
 46# Set eclipse result for facies definition
 47eclipse_result = stim_plan_model_template.facies_properties().facies_definition()
 48eclipse_result.result_type = "INPUT_PROPERTY"
 49eclipse_result.result_variable = "OPERNUM_1"
 50eclipse_result.update()
 51
 52# Set eclipse result for non-net layers
 53non_net_layers = stim_plan_model_template.non_net_layers()
 54non_net_layers_result = non_net_layers.facies_definition()
 55non_net_layers_result.result_type = "STATIC_NATIVE"
 56non_net_layers_result.result_variable = "NTG"
 57non_net_layers_result.update()
 58non_net_layers.formation = "Not"
 59non_net_layers.facies = "Shale"
 60non_net_layers.update()
 61
 62# Add some pressure table items
 63pressure_table = stim_plan_model_template.pressure_table()
 64pressure_table.add_pressure(depth=2800.0, initial_pressure=260.0, pressure=261.0)
 65pressure_table.add_pressure(depth=3000.0, initial_pressure=270.0, pressure=273.0)
 66pressure_table.add_pressure(depth=3400.0, initial_pressure=274.0, pressure=276.0)
 67pressure_table.add_pressure(depth=3800.0, initial_pressure=276.0, pressure=280.0)
 68
 69print("Pressure table ({} items)".format(len(pressure_table.items())))
 70for item in pressure_table.items():
 71    print(
 72        "TDVMSL [m]: {} Initial Pressure: {} Pressure: {}".format(
 73            item.depth, item.initial_pressure, item.pressure
 74        )
 75    )
 76
 77# Add some scaling factors
 78elastic_properties = stim_plan_model_template.elastic_properties()
 79elastic_properties.add_property_scaling(
 80    formation="Garn", facies="Calcite", property="YOUNGS_MODULUS", scale=1.44
 81)
 82
 83
 84well_name = "B-2 H"
 85
 86# Find a well
 87well_path = project.well_path_by_name(well_name)
 88print("well path:", well_path)
 89stim_plan_model_collection = project.descendants(rips.StimPlanModelCollection)[0]
 90
 91
 92export_folder = tempfile.gettempdir()
 93
 94stim_plan_models = []
 95
 96# Create and export a StimPlan model for each depth
 97measured_depths = [3200.0, 3400.0, 3600.0]
 98for measured_depth in measured_depths:
 99    # Create stim plan model at a give measured depth
100    stim_plan_model = stim_plan_model_collection.append_stim_plan_model(
101        well_path=well_path,
102        measured_depth=measured_depth,
103        stim_plan_model_template=stim_plan_model_template,
104    )
105    stim_plan_models.append(stim_plan_model)
106
107    # Make the well name safer to use as a directory path
108    well_name_part = well_name.replace(" ", "_")
109    directory_path = Path(export_folder) / "{}_{}".format(
110        well_name_part, int(measured_depth)
111    )
112
113    # Create the folder
114    directory_path.mkdir(parents=True, exist_ok=True)
115
116    print("Exporting fracture model to: ", directory_path)
117    stim_plan_model.export_to_file(directory_path=directory_path.as_posix())
118
119    # Create a fracture mode plot
120    stim_plan_model_plot_collection = project.descendants(
121        rips.StimPlanModelPlotCollection
122    )[0]
123    stim_plan_model_plot = stim_plan_model_plot_collection.append_stim_plan_model_plot(
124        stim_plan_model=stim_plan_model
125    )
126
127    print("Exporting fracture model plot to: ", directory_path)
128    stim_plan_model_plot.export_snapshot(export_folder=directory_path.as_posix())
129
130
131print("Setting measured depth and perforation length.")
132stim_plan_models[0].measured_depth = 3300.0
133stim_plan_models[0].perforation_length = 123.445
134stim_plan_models[0].update()

Create Surface From Thermal Fracture

create_surface_from_thermal_fracture.py
  1#!/usr/bin/env python
  2# coding: utf-8
  3
  4import rips
  5import tempfile
  6from os.path import expanduser
  7from pathlib import Path
  8import numpy as np
  9import pyvista as pv
 10
 11
 12def generate_surface_from_file(path):
 13    point_cloud_data = np.loadtxt(path, delimiter=" ", skiprows=1)
 14
 15    # Get [x, y, z] components in separate matrix
 16    num_rows = point_cloud_data.shape[0]
 17    xyz = point_cloud_data[0:num_rows, 0:3]
 18
 19    # Generate surface
 20    cloud = pv.PolyData(xyz)
 21    surf = cloud.delaunay_2d()
 22
 23    # Read properties names from header data
 24    f = open(path)
 25    header = f.readline()
 26    properties = header.strip().split(" ")
 27
 28    return (surf, point_cloud_data, properties)
 29
 30
 31def export_surface_as_ts_file(surf, point_cloud, properties, path):
 32    # open text file
 33    text_file = open(path, "w")
 34
 35    # write GOCAD header
 36    top_header = """GOCAD TSurf 1
 37HEADER {
 38name:MF_027_SU
 39}
 40"""
 41
 42    properties_str = "PROPERTIES " + " ".join(properties)
 43
 44    bottom_header = """
 45GOCAD_ORIGINAL_COORDINATE_SYSTEM
 46NAME Default
 47AXIS_NAME "X" "Y" "Z"
 48AXIS_UNIT "m" "m" "m"
 49ZPOSITIVE Depth
 50END_ORIGINAL_COORDINATE_SYSTEM
 51TFACE
 52"""
 53
 54    text_file.write(top_header)
 55    text_file.write(properties_str)
 56    text_file.write(bottom_header)
 57
 58    i = 1
 59    num_rows, num_props = point_cloud.shape
 60    for row in range(0, num_rows):
 61        x = point_cloud[row, 0]
 62        y = point_cloud[row, 1]
 63        z = point_cloud[row, 2]
 64        txt = "PVRTX {} {:.3f} {:.3f} {:.3f} ".format(i, x, y, z)
 65        for property_index in range(0, num_props):
 66            txt += "{:.3f} ".format(point_cloud[row, property_index])
 67        txt += "\n"
 68        text_file.write(txt)
 69        i += 1
 70
 71    mysurface = surf.faces.reshape(-1, 4)
 72    for p in mysurface:
 73        txt = "TRGL {} {} {}\n".format(p[1] + 1, p[2] + 1, p[3] + 1)
 74        text_file.write(txt)
 75
 76    text_file.write("END")
 77    text_file.close()
 78
 79
 80# Connect to ResInsight instance
 81resinsight = rips.Instance.find()
 82project = resinsight.project
 83
 84
 85fractures = project.descendants(rips.ThermalFractureTemplate)
 86print("Number of thermal fractures: ", len(fractures))
 87
 88
 89temp_folder = tempfile.gettempdir()
 90
 91# Write results to a suitable directory
 92home_dir = expanduser("~")
 93
 94for fracture in fractures:
 95    fracture_name = fracture.user_description
 96
 97    # Create the output directory
 98    output_directory = (
 99        Path(home_dir) / "thermal_fracture_surfaces" / "{}".format(fracture_name)
100    )
101
102    output_directory.mkdir(parents=True, exist_ok=True)
103    print("Creating result directory: ", output_directory.as_posix())
104
105    time_steps = fracture.time_steps().values
106    for time_step_index, time_step in enumerate(time_steps):
107        print(
108            "Generating surface for time step #{}: {}".format(
109                time_step_index, time_step
110            )
111        )
112        temp_file_path = Path(temp_folder) / "output.xyz"
113        fracture.export_to_file(
114            file_path=temp_file_path.as_posix(), time_step=time_step_index
115        )
116
117        # Reconstruct a surface from the exported values file
118        surface, point_cloud, properties = generate_surface_from_file(
119            temp_file_path.as_posix()
120        )
121
122        # Export surface ts file from the surface data
123        output_file_path = output_directory / "time_step_{:03d}.ts".format(
124            time_step_index
125        )
126        export_surface_as_ts_file(
127            surface, point_cloud, properties, output_file_path.as_posix()
128        )
129        print(
130            "Wrote surface for time step #{} to {}".format(
131                time_step, output_file_path.as_posix()
132            )
133        )

Duplicate Well

duplicate_well.py
 1###################################################################################
 2# This example will connect to ResInsight, retrieve a list of wells, print info and
 3#  make a duplicate of the first well found, if any
 4#
 5###################################################################################
 6
 7# Import the ResInsight Processing Server Module
 8import rips
 9
10# Connect to ResInsight
11resinsight = rips.Instance.find()
12if resinsight is not None:
13    # Get a list of all wells
14    wells = resinsight.project.well_paths()
15
16    print("Got " + str(len(wells)) + " wells: ")
17    for well in wells:
18        print("Well name: " + well.name)
19
20        # will only work for editable well paths (ModeledWellPath)
21        new_well = well.duplicate()
22        print("New Well name: " + new_well.name)

Export Well Path Completions

export_well_path_completions.py
 1############################################################################
 2# This script will export completions for a well path for all cases in the project
 3#
 4############################################################################
 5
 6import rips
 7
 8# Load instance
 9resinsight = rips.Instance.find()
10cases = resinsight.project.cases()
11
12for case in cases:
13    print("Case name: ", case.name)
14    print("Case id: ", case.id)
15
16    case.export_well_path_completions(
17        time_step=0,
18        well_path_names=["Well-1"],
19        file_split="UNIFIED_FILE",
20        include_perforations=True,
21        custom_file_name="d:/scratch/well_path_export/myfile.myext",
22    )

Export Well Path Trajectory With Properties

export_well_path_trajectory_with_properties.py
 1###################################################################################
 2# This example will connect to ResInsight, extract trajectory properties for
 3# each wells in the project, and extract some properties for each points on the
 4# trajectory.
 5#
 6###################################################################################
 7
 8import rips
 9
10
11def print_dictionary(title, data):
12    # Dictionary of lists of floats.
13    keys = list(data.keys())
14
15    print(title)
16    for i, properties in enumerate(zip(*data.values()), 1):
17        prop_pairs = [
18            f"{key.replace('coordinate_', '')}={prop:.3f}"
19            for key, prop in zip(keys, properties)
20        ]
21        print(f"Point {i}: {', '.join(prop_pairs)}")
22
23
24# Connect to ResInsight
25resinsight = rips.Instance.find()
26if resinsight is not None:
27    # Get a list of all wells
28    wells = resinsight.project.well_paths()
29
30    # Find the first case
31    cases = resinsight.project.cases()
32    c = cases[0] if len(cases) else None
33
34    for well in wells:
35        result = well.trajectory_properties(resampling_interval=10.0)
36
37        if c:
38            # Convert the result data into points
39            positions = [
40                list(coord)
41                for coord in zip(
42                    result["coordinate_x"],
43                    result["coordinate_y"],
44                    result["coordinate_z"],
45                )
46            ]
47
48            # Extract some properties
49            properties = [
50                ("DYNAMIC_NATIVE", "PRESSURE", 0),
51                ("STATIC_NATIVE", "FAULTDIST", 0),
52            ]
53
54            for property_type, property_name, time_step in properties:
55                porosity_model = "MATRIX_MODEL"
56                result[property_name] = c.grid_property_for_positions(
57                    positions, property_type, property_name, time_step, porosity_model
58                )
59
60            title = "Well name: " + well.name
61            print_dictionary(title, result)

Fishbones Completion

fishbones_completion.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3
 4# Connect to ResInsight instance
 5resinsight = rips.Instance.find()
 6
 7# Create a modeled well path and add well path targets
 8# The coordinates are based on the Norne case
 9# Add a lateral to the main well path
10
11well_path_coll = resinsight.project.well_path_collection()
12
13editable_well_paths = well_path_coll.descendants(rips.ModeledWellPath)
14if editable_well_paths:
15    # Use the first well path if it exists
16    well_path = editable_well_paths[0]
17else:
18    # Create a well path
19    well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
20    well_path.name = "Test Well-1"
21    well_path.update()
22
23    geometry = well_path.well_path_geometry()
24
25    reference_point = geometry.reference_point
26    reference_point[0] = 457196
27    reference_point[1] = 7322270
28    reference_point[2] = 2742
29    geometry.update()
30
31    coord = [0, 0, 0]
32    geometry.append_well_target(coord)
33
34    coord = [454.28, 250, -10]
35    target = geometry.append_well_target(coord)
36
37    coord = [1054.28, 250, -50]
38    target = geometry.append_well_target(coord)
39
40
41# Add a fishbone completion to the well path with default settings
42well_path.append_fishbones([4000.0, 4100.0, 4200.0])
43
44# Optional settings on the collection level that will affect all installed fishbones
45fishbones_collection = well_path.completions().fishbones()
46fishbones_collection.main_bore_skin_factor = 0.1
47fishbones_collection.update()
48
49# Drilling type is one of [STANDARD, EXTENDED, ACID_JETTING]
50drilling_type = "ACID_JETTING"
51
52sub_locations = [3500.0, 3550.0, 3600.0, 3700.0]
53fishbones = fishbones_collection.append_fishbones(sub_locations, drilling_type)
54
55fishbones.lateral_diameter = 47.0
56fishbones.lateral_skin_factor = 27.0
57fishbones.update()
58
59# Optionally set the fixed start location for all fishbones
60fishbones_collection.set_fixed_start_location(2900.0)
61
62# Export completions
63cases = resinsight.project.cases()
64
65for case in cases:
66    print("Case name: ", case.name)
67    print("Case id: ", case.id)
68
69    case.export_well_path_completions(
70        time_step=0,
71        well_path_names=["Test Well-1 Y1"],
72        file_split="UNIFIED_FILE",
73        include_perforations=True,
74        custom_file_name="f:/scratch/2023-11-02/myfile.myext",
75    )

Generate Ensemble Of Well Logs

generate_ensemble_of_well_logs.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3import tempfile
 4from os.path import expanduser
 5from pathlib import Path
 6
 7# Connect to ResInsight instance
 8resinsight = rips.Instance.find()
 9
10
11home_dir = expanduser("~")
12
13
14properties = [
15    ("STATIC_NATIVE", "INDEX_K", 0),
16    ("STATIC_NATIVE", "PORO", 0),
17    ("STATIC_NATIVE", "PERMX", 0),
18    ("DYNAMIC_NATIVE", "PRESSURE", 0),
19]
20
21export_folder = tempfile.mkdtemp()
22
23directory_path = "resprojects/webviz-subsurface-testdata/reek_history_match/"
24
25
26case_file_paths = []
27num_realizations = 9
28num_iterations = 4
29
30
31for realization in range(0, num_realizations):
32    for iteration in range(0, num_iterations):
33        realization_dir = "realization-" + str(realization)
34        iteration_dir = "iter-" + str(iteration)
35        egrid_name = "eclipse/model/5_R001_REEK-" + str(realization) + ".EGRID"
36        path = Path(
37            home_dir, directory_path, realization_dir, iteration_dir, egrid_name
38        )
39        case_file_paths.append(path)
40
41for path in case_file_paths:
42    # Load a case
43    path_name = path.as_posix()
44    grid_only = True
45    case = resinsight.project.load_case(path_name, grid_only)
46
47    # Load some wells
48    well_paths = resinsight.project.import_well_paths(
49        well_path_files=[
50            Path(home_dir, directory_path, "wellpaths", "Well-1.dev").as_posix(),
51            Path(home_dir, directory_path, "wellpaths", "Well-2.dev").as_posix(),
52        ]
53    )
54
55    if resinsight.project.has_warnings():
56        for warning in resinsight.project.warnings():
57            print(warning)
58
59    well_log_plot_collection = resinsight.project.descendants(
60        rips.WellLogPlotCollection
61    )[0]
62
63    for well_path in well_paths:
64        print(
65            "Generating las file for well: " + well_path.name + " in case: " + path_name
66        )
67
68        well_log_plot = well_log_plot_collection.new_well_log_plot(case, well_path)
69
70        # Create a track for each property
71        for prop_type, prop_name, time_step in properties:
72            track = well_log_plot.new_well_log_track(
73                "Track: " + prop_name, case, well_path
74            )
75
76            c = track.add_extraction_curve(
77                case, well_path, prop_type, prop_name, time_step
78            )
79
80        parent_path = path.parent
81        export_folder_path = Path(parent_path, "lasexport")
82        export_folder_path.mkdir(parents=True, exist_ok=True)
83
84        export_folder = export_folder_path.as_posix()
85        well_log_plot.export_data_as_las(export_folder=export_folder)
86
87    resinsight.project.close()

Import Fractures On Well

import_fractures_on_well.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3from os.path import expanduser
 4from pathlib import Path
 5
 6# Connect to ResInsight instance
 7resinsight = rips.Instance.find()
 8project = resinsight.project
 9
10# Look for input files in the home directory of the user
11home_dir = expanduser("~")
12stim_plan_file_path = (Path(home_dir) / "contour.xml").as_posix()
13print("StimPlan contour file path:", stim_plan_file_path)
14
15# Find a case
16cases = resinsight.project.cases()
17case = cases[0]
18
19# Create stim plan template
20fmt_collection = project.descendants(rips.FractureTemplateCollection)[0]
21fracture_template = fmt_collection.append_fracture_template(
22    file_path=stim_plan_file_path
23)
24
25well_name = "B-2 H"
26
27# Find a well
28well_path = project.well_path_by_name(well_name)
29print("well path:", well_path.name)
30
31# Place fracture at given depths
32measured_depths = [3200.0, 3400.0, 3600.0]
33for measured_depth in measured_depths:
34    print("Placing fracture at {} depth (MD)".format(measured_depth))
35    # Create stim plan  at a give measured depth
36    fracture = well_path.add_fracture(
37        measured_depth=measured_depth,
38        stim_plan_fracture_template=fracture_template,
39        align_dip=True,
40        eclipse_case=case,
41    )
42
43# Update the orientation of the fracture. All fracture parameters are displayed, most with default values.
44fracture_template.orientation = "Azimuth"
45fracture_template.azimuth_angle = 60.0
46fracture_template.beta_factor_type = "UserDefinedBetaFactor"
47fracture_template.conductivity_type = "InfiniteConductivity"
48fracture_template.effective_permeability = 0
49fracture_template.fracture_width = 0.01
50fracture_template.fracture_width_type = "FractureWidth"
51fracture_template.gas_viscosity = 0.02
52fracture_template.height_scale_factor = 1
53fracture_template.inertial_coefficient = 0.00608324
54fracture_template.non_darcy_flow_type = "None"
55fracture_template.perforation_length = 12.3
56fracture_template.permeability_type = "FractureConductivity"
57fracture_template.relative_gas_density = 0.8
58fracture_template.relative_permeability = 1
59fracture_template.user_defined_d_factor = 1
60fracture_template.user_defined_perforation_length = True
61fracture_template.width_scale_factor = 1
62fracture_template.update()
63
64# Scale the template
65fracture_template.set_scale_factors(
66    half_length=2.0, height=2.0, d_factor=1.1, conductivity=1.2
67)
68
69# Output scale factors for all fracture templates
70fmt_collection = project.descendants(rips.FractureTemplate)
71for fracture_template in fmt_collection:
72    print(
73        "Fracture: '{}' Scale factors: Height={} Half Length={} D Factor={} Conductivity={}".format(
74            fracture_template.user_description,
75            fracture_template.height_scale_factor,
76            fracture_template.width_scale_factor,
77            fracture_template.d_factor_scale_factor,
78            fracture_template.conductivity_factor,
79        )
80    )

Import Thermal Fracture On Well

import_thermal_fracture_on_well.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3from os.path import expanduser
 4from pathlib import Path
 5
 6# Connect to ResInsight instance
 7resinsight = rips.Instance.find()
 8project = resinsight.project
 9
10# Look for input files in the home directory of the user
11home_dir = expanduser("~")
12fracture_file_path = (Path(home_dir) / "fracture.csv").as_posix()
13print("Thermal fracture file path:", fracture_file_path)
14
15# Find a case
16cases = resinsight.project.cases()
17case = cases[0]
18
19# Create thermal template
20fmt_collection = project.descendants(rips.FractureTemplateCollection)[0]
21fracture_template = fmt_collection.append_thermal_fracture_template(
22    file_path=fracture_file_path
23)
24
25well_name = "F-1 H"
26
27# Find a well
28well_path = project.well_path_by_name(well_name)
29print("Well path:", well_path.name)
30
31# Create fracture and place it using data from the fracture template
32fracture = well_path.add_thermal_fracture(
33    fracture_template=fracture_template,
34    place_using_template_data=True,
35)
36
37
38time_steps = fracture_template.time_steps().values
39for time_step_index, time_stamp in enumerate(time_steps):
40    print("Time step #{}: {}".format(time_step_index, time_stamp))
41    fracture_template.active_time_step_index = time_step_index
42    fracture_template.conductivity_result_name = "Conductivity"
43    fracture_template.update()

Import Well Paths And Logs

import_well_paths_and_logs.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3
 4# Connect to ResInsight instance
 5resInsight = rips.Instance.find()
 6
 7well_paths = resInsight.project.import_well_paths(
 8    well_path_folder="D:/Projects/ResInsight-regression-test/ModelData/norne/wellpaths"
 9)
10if resInsight.project.has_warnings():
11    for warning in resInsight.project.warnings():
12        print(warning)
13
14
15for well_path in well_paths:
16    print("Imported from folder: " + well_path.name)
17
18well_paths = resInsight.project.import_well_paths(
19    well_path_files=[
20        "D:/Projects/ResInsight-regression-test/ModelData/Norne_WellPaths/E-3H.json",
21        "D:/Projects/ResInsight-regression-test/ModelData/Norne_WellPaths/C-1H.json",
22    ]
23)
24if resInsight.project.has_warnings():
25    for warning in resInsight.project.warnings():
26        print(warning)
27
28
29for well_path in well_paths:
30    print("Imported from individual files: " + well_path.name)
31
32
33well_path_names = resInsight.project.import_well_log_files(
34    well_log_folder="D:/Projects/ResInsight-regression-test/ModelData/Norne_PLT_LAS"
35)
36if resInsight.project.has_warnings():
37    for warning in resInsight.project.warnings():
38        print(warning)
39
40for well_path_name in well_path_names:
41    print("Imported well log file for: " + well_path_name)

Import Wells No Grouping

import_wells_no_grouping.py
 1import rips
 2
 3# Connect to ResInsight instance
 4resInsight = rips.Instance.find()
 5
 6# Clear any existing MSW grouping pattern to avoid interference with the import
 7well_path_coll = resInsight.project.well_path_collection()
 8well_path_coll.set_msw_name_grouping("")
 9
10well1 = well_path_coll.import_well_path(
11    "f:/scratch/2026-well-path-import/Well-1_Y1.dev"
12)
13well2 = well_path_coll.import_well_path(
14    "f:/scratch/2026-well-path-import/Well-1_Y2.dev"
15)
16
17# Create lateral well path from geometry of another well path
18well1.append_lateral_from_geometry(well2)

Modeled Well Path

modeled_well_path.py
  1# Load ResInsight Processing Server Client Library
  2import rips
  3
  4# Connect to ResInsight instance
  5resinsight = rips.Instance.find()
  6
  7# Create a modeled well path and add well path targets
  8# The coordinates are based on the Norne case
  9
 10well_path_coll = resinsight.project.well_path_collection()
 11well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
 12well_path.name = "Test Well-1"
 13well_path.update()
 14
 15geometry = well_path.well_path_geometry()
 16
 17reference_point = geometry.reference_point
 18reference_point[0] = 457196
 19reference_point[1] = 7322270
 20reference_point[2] = 2742
 21geometry.update()  # Commit updates back to ResInsight
 22
 23# Create the first well target at the reference point
 24coord = [0, 0, 0]
 25geometry.append_well_target(coord)
 26
 27# Append new well targets relative the the reference point
 28coord = [454.28, 250, -10]
 29target = geometry.append_well_target(coord)
 30
 31coord = [1054.28, 250, -50]
 32target = geometry.append_well_target(coord)
 33
 34perforation = well_path.append_perforation_interval(3300, 3350, 0.2, 0.76)
 35
 36# Make some changes to the AICD parameters of the valve template
 37valve_templates = resinsight.project.valve_templates()
 38aicd_template = valve_templates.valve_definitions()[0]
 39aicd_parameters = aicd_template.aicd_parameters()
 40aicd_parameters.max_flow_rate = 899.43
 41aicd_parameters.density_calibration_fluid = 45.5
 42aicd_parameters.update()
 43
 44# Add a valve to the perforation interval
 45valve = perforation.add_valve(
 46    template=aicd_template, start_md=3310, end_md=3340, valve_count=2
 47)
 48
 49
 50# Update skin factor of the perforation
 51perforation_coll = well_path.completions().perforations()
 52perforation = perforation_coll.perforations()[0]
 53new_skin_factor = 0.9
 54print(
 55    "Changing perforation skin factor from {} to {}.".format(
 56        perforation.skin_factor, new_skin_factor
 57    )
 58)
 59perforation.skin_factor = new_skin_factor
 60perforation.update()
 61
 62# Optionally update the completion settings
 63completions_settings = well_path.completion_settings()
 64completions_settings.msw_roughness = 12.34
 65completions_settings.msw_liner_diameter = 0.2222
 66completions_settings.well_name_for_export = "file name"
 67completions_settings.group_name_for_export = "msj"
 68completions_settings.well_type_for_export = "GAS"
 69completions_settings.update()  # Commit updates back to ResInsight
 70
 71# Add diameter roughness intervals for interval-specific configuration
 72interval1 = completions_settings.add_diameter_roughness_interval(
 73    start_md=3200, end_md=3300, diameter=0.18, roughness_factor=1.5e-5
 74)
 75interval2 = completions_settings.add_diameter_roughness_interval(
 76    start_md=3300, end_md=3400, diameter=0.16, roughness_factor=2.0e-5
 77)
 78print(
 79    f"Added diameter roughness intervals: {interval1.start_md}-{interval1.end_md}m and {interval2.start_md}-{interval2.end_md}m"
 80)
 81
 82# Add custom segment intervals to define explicit segment boundaries for MSW export
 83segment1 = completions_settings.add_custom_segment_interval(start_md=3200, end_md=3250)
 84segment2 = completions_settings.add_custom_segment_interval(start_md=3250, end_md=3320)
 85segment3 = completions_settings.add_custom_segment_interval(start_md=3320, end_md=3400)
 86print(
 87    f"Added custom segment intervals: {segment1.start_md}-{segment1.end_md}m, {segment2.start_md}-{segment2.end_md}m, {segment3.start_md}-{segment3.end_md}m"
 88)
 89
 90# Optionally update the MSW settings
 91msw_settings = well_path.msw_settings()
 92msw_settings.custom_values_for_lateral = False
 93msw_settings.enforce_max_segment_length = False
 94msw_settings.liner_diameter = 0.152
 95msw_settings.max_segment_length = 200
 96msw_settings.pressure_drop = "HF-"
 97msw_settings.reference_md_type = "GridEntryPoint"
 98msw_settings.roughness_factor = 1e-05
 99msw_settings.user_defined_reference_md = 0
100msw_settings.update()
101
102# Optionally update the Perforation Non-Darcy settings
103non_darcy_parameters = perforation_coll.non_darcy_parameters()
104non_darcy_parameters.non_darcy_flow_type = "UserDefined"
105non_darcy_parameters.user_defined_d_factor = 1.2345
106non_darcy_parameters.update()
107
108# export completions
109cases = resinsight.project.cases()
110
111for case in cases:
112    print("Case name: ", case.name)
113    print("Case id: ", case.id)
114
115    case.export_well_path_completions(
116        time_step=0,
117        well_path_names=["Test Well-1 Y1"],
118        file_split="UNIFIED_FILE",
119        include_perforations=True,
120        # Replace the following with a valid path
121        custom_file_name="f:/scratch/2023-11-02/myfile.myext",
122    )

Modeled Well Path Lateral

modeled_well_path_lateral.py
 1# Load ResInsight Processing Server Client Library
 2import rips
 3import time
 4
 5# Connect to ResInsight instance
 6resinsight = rips.Instance.find()
 7
 8# Create a modeled well path and add well path targets
 9# The coordinates are based on the Norne case
10# Add a lateral to the main well path
11
12well_path_coll = resinsight.project.well_path_collection()
13well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
14well_path.name = "Test Well-1"
15well_path.update()
16
17geometry = well_path.well_path_geometry()
18
19reference_point = geometry.reference_point
20reference_point[0] = 457196
21reference_point[1] = 7322270
22reference_point[2] = 2742
23geometry.update()  # Commit updates back to ResInsight
24
25# Create the first well target at the reference point
26coord = [0, 0, 0]
27geometry.append_well_target(coord)
28
29# Append new well targets relative the the reference point
30coord = [454.28, 250, -10]
31target = geometry.append_well_target(coord)
32
33coord = [1054.28, 250, -50]
34target = geometry.append_well_target(coord)
35
36# Create a lateral at specified location on parent well
37measured_depth = 3600
38lateral = well_path.append_lateral(measured_depth)
39geometry = lateral.well_path_geometry()
40
41coord = [770, 280, 50]
42target = geometry.append_well_target(coord)
43
44coord = [1054.28, -100, 50]
45target = geometry.append_well_target(coord)
46
47coord = [2054.28, -100, 45]
48target = geometry.append_well_target(coord)
49
50# Wait 2 second
51print("Wait 2 seconds ...")
52time.sleep(2)
53print("Move reference point of parent well")
54
55geometry = well_path.well_path_geometry()
56reference_point = geometry.reference_point
57reference_point[2] += 50
58geometry.update()  # Commit updates back to ResInsight
59
60# Check that lateral is a lateral
61parentWell = lateral.parent_branch()
62
63if parentWell is not None:
64    print("Parent is " + parentWell.name)
65
66if parentWell.parent_branch() is None:
67    print("Parent is top level well.")

Valve Template Creation

valve_template_creation.py
  1#!/usr/bin/env python3
  2
  3"""
  4Example demonstrating how to create valve templates programmatically using the Python API.
  5
  6This example shows:
  71. Creating different types of valve templates (ICD, ICV, AICD)
  82. Setting custom parameters for orifice diameter and flow coefficient
  93. Using the created templates in well completions
 10"""
 11
 12import rips
 13
 14
 15def main():
 16    # Connect to ResInsight instance
 17    resinsight = rips.Instance.find()
 18
 19    print("Creating valve templates...")
 20
 21    # Get the valve template collection
 22    valve_templates = resinsight.project.valve_templates()
 23
 24    # Check initial number of templates
 25    initial_templates = valve_templates.valve_definitions()
 26    print(f"Initial number of valve templates: {len(initial_templates)}")
 27
 28    # Create an ICD template with default values
 29    print("\n1. Creating ICD template with default values")
 30    icd_template = valve_templates.add_template(completion_type="ICD")
 31    print(f"   Created: {icd_template.name}")
 32    print(f"   Orifice Diameter: {icd_template.orifice_diameter}")
 33    print(f"   Flow Coefficient: {icd_template.flow_coefficient}")
 34
 35    # Create an ICV template with custom values
 36    print("\n2. Creating ICV template with custom values")
 37    icv_template = valve_templates.add_template(
 38        completion_type="ICV",
 39        orifice_diameter=12.5,
 40        flow_coefficient=0.85,
 41        user_label="Custom ICV for High Flow",
 42    )
 43    print(f"   Created: {icv_template.name}")
 44    print(f"   Orifice Diameter: {icv_template.orifice_diameter}")
 45    print(f"   Flow Coefficient: {icv_template.flow_coefficient}")
 46
 47    # Create an AICD template
 48    print("\n3. Creating AICD template as suggested in issue #12773")
 49    aicd_template = valve_templates.add_template(
 50        completion_type="AICD",
 51        user_label="Issue Example AICD",
 52    )
 53
 54    aicd_params = aicd_template.aicd_parameters()
 55
 56    aicd_params.strength_aicd = 0.001
 57    aicd_params.density_calibration_fluid = 1000.0
 58    aicd_params.viscosity_calibration_fluid = 1.5
 59    aicd_params.update()
 60
 61    print(f"   Created: {aicd_template.name}")
 62    print(f"   Strength: {aicd_params.strength_aicd}")
 63    print(f"   Calibration Fluid Density: {aicd_params.density_calibration_fluid}")
 64    print(f"   Calibration Fluid Viscosity: {aicd_params.viscosity_calibration_fluid}")
 65
 66    # Create an SICD template
 67    print("\n4. Creating SICD template")
 68    sicd_template = valve_templates.add_template(
 69        completion_type="SICD",
 70        user_label="Example SICD",
 71    )
 72
 73    sicd_params = sicd_template.sicd_parameters()
 74
 75    sicd_params.strength = 0.001
 76    sicd_params.calibration_density = 1000.0
 77    sicd_params.update()
 78
 79    print(f"   Created: {sicd_template.name}")
 80    print(f"   Strength: {sicd_params.strength}")
 81    print(f"   Calibration Fluid Density: {sicd_params.calibration_density}")
 82
 83    # Show all valve templates
 84    current_templates = valve_templates.valve_definitions()
 85    print(f"\nTotal valve templates now: {len(current_templates)}")
 86    print("All valve templates:")
 87    for i, template in enumerate(current_templates):
 88        print(f"   {i + 1}. {template.name}")
 89
 90    # Example of using the new template in a completion (requires a loaded case with well paths)
 91    print("\n5. Example usage in well completion (requires loaded case)")
 92    try:
 93        # This assumes you have a case loaded with well paths
 94        well_paths = resinsight.project.well_paths()
 95        if well_paths:
 96            well_path = well_paths[0]
 97            print(f"   Using well path: {well_path.name}")
 98
 99            # Add a perforation interval
100            perf_interval = well_path.append_perforation_interval(
101                start_md=2450, end_md=2500, diameter=0.25, skin_factor=0.1
102            )
103
104            # Add a valve using our new AICD template
105            valve = perf_interval.add_valve(
106                template=aicd_template, start_md=2451, end_md=2499, valve_count=3
107            )
108            print(f"   Created valve: {valve.name}")
109            print(f"   Number of valves in interval: {len(perf_interval.valves())}")
110
111            # Add a perforation interval
112            perf_interval_2 = well_path.append_perforation_interval(
113                start_md=2510, end_md=2560, diameter=0.2, skin_factor=0.12
114            )
115
116            # Add a valve using our new SICD template
117            valve2 = perf_interval_2.add_valve(
118                template=sicd_template, start_md=2510, end_md=2560, valve_count=5
119            )
120
121            valve_templ = valve2.template()
122            valve_sicd_params = valve_templ.sicd_parameters()
123
124            print(f"   Created valve: {valve2.name}")
125            print(f"   Valve SICD strength: {valve_sicd_params.strength}")
126            print(f"   Number of valves in interval: {len(perf_interval_2.valves())}")
127
128        else:
129            print("   No well paths available - skipping completion example")
130            print("   Load a case with well paths to see this in action")
131
132    except Exception as e:
133        print(f"   Could not create completion example: {e}")
134        print("   This is expected if no case/well paths are loaded")
135
136    print("\nExample completed successfully!")
137
138
139if __name__ == "__main__":
140    main()

Well Event Schedule

well_event_schedule.py
  1#!/usr/bin/env python3
  2
  3"""
  4Example demonstrating how to use well event timeline and schedule data generation.
  5
  6This example shows:
  71. Creating well events (perforations, tubing, valves) on a timeline
  82. Applying events up to a specific date using set_timestamp()
  93. Viewing the created completions after applying events
 104. Generating Eclipse schedule text from the event timeline
 11
 12This workflow is useful for:
 13- Time-dependent well completion modeling
 14- Simulating well workover schedules
 15- Planning and visualizing completion changes over time
 16- Generating schedule files for Eclipse simulation
 17"""
 18
 19import rips
 20
 21
 22def main():
 23    # Connect to ResInsight instance
 24    resinsight = rips.Instance.find()
 25    project = resinsight.project
 26
 27    print("Well Event Schedule Example")
 28    print("=" * 50)
 29
 30    # Create a modeled well path for demonstration
 31    print("\n1. Finding well")
 32    wells = project.well_paths()
 33
 34    if len(wells) > 0:
 35        well_path = wells[0]
 36
 37    print("Well name: ", well_path.name)
 38
 39    # Get the event timeline
 40    print("\n2. Adding well events to the timeline...")
 41    well_path_coll = project.descendants(rips.WellPathCollection)[0]
 42    timeline = well_path_coll.event_timeline()
 43
 44    # Add tubing event (installed early)
 45    _tubing_event = timeline.add_tubing_event(
 46        event_date="2024-01-01",
 47        well_path=well_path,
 48        start_md=0.0,
 49        end_md=2500.0,
 50        inner_diameter=0.15,
 51        roughness=1.0e-5,
 52    )
 53    print("   Added tubing event on 2024-01-01 (MD 0-2500m)")
 54
 55    # Add first perforation event
 56    _perf_event1 = timeline.add_perf_event(
 57        event_date="2024-02-01",
 58        well_path=well_path,
 59        start_md=2000.0,
 60        end_md=2200.0,
 61        diameter=0.1,
 62        skin_factor=0.5,
 63        state="OPEN",
 64    )
 65    print("   Added perforation event on 2024-02-01 (MD 2000-2200m)")
 66
 67    # Add second perforation event (later)
 68    _perf_event2 = timeline.add_perf_event(
 69        event_date="2024-04-01",
 70        well_path=well_path,
 71        start_md=2400.0,
 72        end_md=2600.0,
 73        diameter=0.1,
 74        skin_factor=0.3,
 75        state="OPEN",
 76    )
 77    print("   Added perforation event on 2024-04-01 (MD 2400-2600m)")
 78
 79    # Add valve event (requires existing perforation)
 80    _valve_event = timeline.add_valve_event(
 81        event_date="2024-03-01",
 82        well_path=well_path,
 83        measured_depth=2100.0,
 84        valve_type="ICV",
 85        state="OPEN",
 86        flow_coefficient=0.7,
 87        area=0.0001,
 88    )
 89    print("   Added valve event on 2024-03-01 (MD 2100m)")
 90
 91    # Add state events (for documentation, not applied to completions)
 92    _state_event = timeline.add_state_event(
 93        event_date="2024-02-15",
 94        well_path=well_path,
 95        well_state="OPEN",
 96    )
 97    print("   Added state event on 2024-02-15 (OPEN)")
 98
 99    # Add well keyword events (arbitrary Eclipse keywords)
100    print("\n   Adding well keyword events...")
101
102    # Example 1: WCONHIST - Historical production data
103    _wconhist_event = timeline.add_well_keyword_event(
104        event_date="2024-01-15",
105        well_path=well_path,
106        keyword_name="WCONHIST",
107        keyword_data={
108            "WELL": well_path.name,
109            "STATUS": "OPEN",
110            "CMODE": "RESV",
111            "ORAT": 3999.99,
112            "WRAT": 0.01,
113            "GRAT": 550678.44,
114            "VFP_TABLE": 1,
115        },
116    )
117    print("   Added WCONHIST event on 2024-01-15 (historical production control)")
118
119    # Example 2: WELTARG - Well target change
120    _weltarg_event = timeline.add_well_keyword_event(
121        event_date="2024-05-01",
122        well_path=well_path,
123        keyword_name="WELTARG",
124        keyword_data={
125            "WELL": well_path.name,
126            "CMODE": "ORAT",
127            "NEW_VALUE": 5000.0,
128        },
129    )
130    print("   Added WELTARG event on 2024-05-01 (well target change)")
131
132    # Example 3: WRFTPLT - RFT/PLT output control
133    _wrftplt_event = timeline.add_well_keyword_event(
134        event_date="2024-06-01",
135        well_path=well_path,
136        keyword_name="WRFTPLT",
137        keyword_data={
138            "WELL": well_path.name,
139            "OUTPUT_RFT": "YES",
140            "OUTPUT_PLT": "NO",
141            "OUTPUT_SEGMENT": "NO",
142        },
143    )
144    print("   Added WRFTPLT event on 2024-06-01 (RFT/PLT output control)")
145
146    # Add schedule-level keyword events (not tied to a well)
147    print("\n   Adding schedule-level keyword events...")
148
149    # Example 4: RPTRST - Report restart settings (schedule-level, not well-specific)
150    _rptrst_event = timeline.add_keyword_event(
151        event_date="2024-01-01",
152        keyword_name="RPTRST",
153        keyword_data={
154            "BASIC": 2,
155            "FREQ": 1,
156        },
157    )
158    print("   Added RPTRST event on 2024-01-01 (report restart settings)")
159
160    # Example 5: GRUPTREE - Group tree definition
161    _gruptree_event = timeline.add_keyword_event(
162        event_date="2024-01-01",
163        keyword_name="GRUPTREE",
164        keyword_data={
165            "CHILD": "OP",
166            "PARENT": "FIELD",
167        },
168    )
169    print("   Added GRUPTREE event on 2024-01-01 (group tree definition)")
170
171    # Apply events up to March 15, 2024
172    # This should create:
173    # - Tubing interval (Jan 1)
174    # - First perforation (Feb 1)
175    # - Valve in first perforation (Mar 1)
176    # But NOT the second perforation (Apr 1)
177    timeline.set_timestamp(timestamp="2024-12-24")
178
179    # Get the Eclipse case (if available)
180    # Show what was created
181    print("\n3. Verifying created completions...")
182
183    # Check perforations
184    perforation_coll = well_path.completions().perforations()
185    perforations = perforation_coll.perforations()
186    print(f"   Perforations created: {len(perforations)}")
187    for perf in perforations:
188        print(
189            f"      - MD {perf.start_measured_depth:.0f} to {perf.end_measured_depth:.0f}m"
190        )
191        valves = perf.valves()
192        if valves:
193            print(f"        Valves: {len(valves)}")
194
195    # Check MSW settings (tubing intervals)
196    msw_settings = well_path.msw_settings()
197    if msw_settings:
198        print(f"   MSW diameter/roughness mode: {msw_settings.diameter_roughness_mode}")
199
200    # Generate Eclipse schedule text
201    print("\n4. Generating Eclipse schedule text from events...")
202
203    # Get the Eclipse case (if available)
204    cases = project.cases()
205    if cases:
206        case = cases[0]
207        print(f"   Using Eclipse case: {case.name}")
208
209        # Generate schedule text
210        schedule_text = timeline.generate_schedule_text(eclipse_case=case)
211
212        if schedule_text:
213            print(f"\n   Generated schedule text ({len(schedule_text)} characters)")
214            print("   " + "=" * 60)
215            # Show the full schedule
216            lines = schedule_text.split("\n")
217            for line in lines:
218                print(f"   {line}")
219            print("   " + "=" * 60)
220
221            # Validate expected keywords are present
222            print("\n7. Validating generated Eclipse keywords...")
223            expected_keywords = [
224                "DATES",
225                "WELSEGS",
226                "COMPSEGS",
227                "WCONHIST",
228                "WELTARG",
229                "WRFTPLT",
230                "RPTRST",
231                "GRUPTREE",
232            ]
233            found_keywords = [kw for kw in expected_keywords if kw in schedule_text]
234
235            print(f"   Keywords found: {', '.join(found_keywords)}")
236
237            if "WELSEGS" in schedule_text:
238                print("   ✓ WELSEGS keyword generated (MSW well segments)")
239                # Count segment lines (lines with segment data)
240                welsegs_lines = [
241                    line
242                    for line in lines
243                    if line.strip() and line.strip()[0].isdigit() and " 1 " in line
244                ]
245                print(f"     Number of segments: {len(welsegs_lines)}")
246
247            if "COMPSEGS" in schedule_text:
248                print("   ✓ COMPSEGS keyword generated (completion segments)")
249
250            if "WSEGVALV" in schedule_text:
251                print("   ✓ WSEGVALV keyword generated (segment valves)")
252                # Extract valve parameters
253                wsegvalv_idx = schedule_text.find("WSEGVALV")
254                if wsegvalv_idx > 0:
255                    wsegvalv_section = schedule_text[wsegvalv_idx : wsegvalv_idx + 500]
256                    if "0.7" in wsegvalv_section:
257                        print("     Flow coefficient (Cv) = 0.7 detected")
258
259            if "WCONPROD" in schedule_text or "WCONINJE" in schedule_text:
260                kw_name = "WCONPROD" if "WCONPROD" in schedule_text else "WCONINJE"
261                print(f"   ✓ {kw_name} keyword generated (well control)")
262
263            # Show keyword summary
264            print("\n   Eclipse Keyword Summary:")
265            print(f"   - DATES entries: {schedule_text.count('DATES')}")
266            print(f"   - WELSEGS entries: {schedule_text.count('WELSEGS')}")
267            print(f"   - COMPSEGS entries: {schedule_text.count('COMPSEGS')}")
268            print(f"   - WSEGVALV entries: {schedule_text.count('WSEGVALV')}")
269            print(f"   - WCONHIST entries: {schedule_text.count('WCONHIST')}")
270            print(f"   - WELTARG entries: {schedule_text.count('WELTARG')}")
271            print(f"   - WRFTPLT entries: {schedule_text.count('WRFTPLT')}")
272            print(f"   - RPTRST entries: {schedule_text.count('RPTRST')}")
273            print(f"   - GRUPTREE entries: {schedule_text.count('GRUPTREE')}")
274
275            # Save to file
276            output_file = "generated_schedule.sch"
277            with open(output_file, "w") as f:
278                f.write(schedule_text)
279            print(f"\n   Schedule text saved to: {output_file}")
280
281            # Show example of generated keywords
282            print("\n8. Example of generated Eclipse keywords:")
283            print("   (See generated_schedule.sch for complete output)")
284            if "WELSEGS" in schedule_text:
285                print("\n   Sample WELSEGS segment:")
286                for line in lines:
287                    if "WELSEGS" in line:
288                        idx = lines.index(line)
289                        # Show keyword and first data line
290                        if idx + 2 < len(lines):
291                            print(f"   {lines[idx]}")
292                            print(f"   {lines[idx + 1]}")
293                            print(f"   {lines[idx + 2]}")
294                        break
295        else:
296            print("   Warning: No schedule text was generated")
297    else:
298        print("   Note: No Eclipse case loaded - skipping schedule generation")
299        print("   Load a case first to generate schedule text")
300
301    print("\nExample completed successfully!")
302    print("\nAPI Usage Summary:")
303    print("- timeline = well_path.event_timeline()")
304    print("- timeline.add_perf_event(event_date='2024-01-01', well_name='WellA', ...)")
305    print(
306        "- timeline.add_tubing_event(event_date='2024-01-01', well_name='WellA', ...)"
307    )
308    print("- timeline.add_valve_event(event_date='2024-01-01', well_name='WellA', ...)")
309    print("- timeline.add_well_keyword_event(  # Well-specific Eclipse keywords:")
310    print("      event_date='2024-01-01',")
311    print("      well_path=well_path,")
312    print("      keyword_name='WCONHIST',  # WCONHIST, WELTARG, WRFTPLT, etc.")
313    print("      keyword_data={'WELL': 'WellA', 'ORAT': 1000.0, ...}")
314    print("  )")
315    print(
316        "- timeline.add_keyword_event(  # Schedule-level keywords (not tied to wells):"
317    )
318    print("      event_date='2024-01-01',")
319    print("      keyword_name='RPTRST',  # RPTRST, GRUPTREE, RPTSCHED, etc.")
320    print("      keyword_data={'BASIC': 2, 'FREQ': 1}")
321    print("  )")
322    print("- timeline.set_timestamp(timestamp='2024-06-01')  # Apply events up to date")
323    print("- schedule_text = timeline.generate_schedule_text(eclipse_case=case)")
324    print("  # Generate Eclipse schedule text")
325
326
327if __name__ == "__main__":
328    main()

Well Log Import Example

well_log_import_example.py
 1"""
 2Example: Import Well Log Data to Well Paths
 3
 4This example demonstrates how to import well log data with measured depth
 5and multiple channels from Python arrays into ResInsight well paths using
 6the new well log import API.
 7"""
 8
 9import rips
10
11
12def create_example_well_log_data():
13    """Create example well log data with measured depth and multiple channels"""
14    # Measured depth values in meters
15    measured_depth = [1000, 1200, 1400, 1600, 1800, 2000, 2200, 2400, 2600, 2800]
16
17    # Multiple channel data corresponding to each measured depth
18    channel_data = {
19        "gamma_ray": [75.2, 82.1, 78.5, 80.3, 85.7, 88.2, 90.1, 87.3, 84.6, 82.8],
20        "porosity": [0.12, 0.15, 0.18, 0.22, 0.25, 0.28, 0.24, 0.20, 0.16, 0.14],
21        "permeability": [15.5, 22.3, 35.8, 48.2, 65.1, 78.4, 52.9, 38.7, 25.6, 18.9],
22        "resistivity": [2.1, 1.8, 3.2, 2.5, 1.9, 1.4, 2.8, 3.1, 2.7, 2.3],
23    }
24
25    return measured_depth, channel_data
26
27
28def main():
29    # Connect to ResInsight
30    resinsight = rips.Instance.find()
31    project = resinsight.project
32
33    # Create a well path from coordinates
34    coordinates = [
35        [458000, 5934000, -1000],  # X, Y, Z coordinates
36        [458100, 5934100, -1500],
37        [458200, 5934200, -2000],
38        [458300, 5934300, -2500],
39        [458400, 5934400, -3000],
40    ]
41
42    well_path = project.well_path_collection().import_well_path_from_points(
43        name="ExampleWell", coordinates=coordinates
44    )
45
46    print(f"Created well path: {well_path.name}")
47
48    # Get example well log data
49    measured_depth, channel_data = create_example_well_log_data()
50
51    # Import well log with multiple channels using the new API
52    well_log = well_path.add_well_log(
53        name="ComprehensiveWellLog",
54        measured_depth=measured_depth,
55        channel_data=channel_data,
56    )
57
58    print(f"Added well log: {well_log.name}")
59    print(
60        f"  - Measured depth range: {min(measured_depth):.1f} - {max(measured_depth):.1f} m"
61    )
62    print(f"  - Number of data points: {len(measured_depth)}")
63    print(f"  - Channels imported: {', '.join(channel_data.keys())}")
64
65    # You can also import additional well logs with different data
66    # For example, a well log with different measured depth intervals
67    additional_measured_depth = [1100, 1300, 1500, 1700, 1900, 2100, 2300, 2500, 2700]
68    additional_channel_data = {
69        "caliper": [8.5, 8.2, 8.7, 8.3, 8.1, 8.4, 8.6, 8.2, 8.3],
70        "neutron": [0.18, 0.22, 0.25, 0.28, 0.31, 0.29, 0.26, 0.23, 0.20],
71    }
72
73    additional_well_log = well_path.add_well_log(
74        name="AdditionalWellLog",
75        measured_depth=additional_measured_depth,
76        channel_data=additional_channel_data,
77    )
78
79    print(f"Added additional well log: {additional_well_log.name}")
80    print(
81        f"  - MD range: {min(additional_measured_depth):.1f} - {max(additional_measured_depth):.1f} m"
82    )
83    print(f"  - Channels imported: {', '.join(additional_channel_data.keys())}")
84
85
86if __name__ == "__main__":
87    main()

Well Path From Points

well_path_from_points.py
 1"""
 2Example demonstrating how to create well paths from XYZ coordinates
 3using the import_well_path_from_points API.
 4"""
 5
 6import rips
 7
 8
 9def create_norne_well():
10    coordinates = [
11        [457121.858, 7322122.992, -371.7],
12        [457121.820, 7322122.956, -404.999],
13        [457121.767, 7322122.946, -434.999],
14        [457123.250, 7322120.048, -644.946],
15        [457132.573, 7322112.750, -914.534],
16        [457132.853, 7322111.663, -1184.492],
17        [457141.541, 7322111.158, -1484.359],
18        [457147.535, 7322109.991, -1694.269],
19        [457152.835, 7322107.659, -1934.198],
20        [457142.201, 7322088.313, -2182.14],
21        [457108.159, 7322025.317, -2335.345],
22        [457077.300, 7321905.985, -2464.557],
23        [457100.629, 7321698.916, -2584.388],
24        [457226.480, 7321457.656, -2629.045],
25        [457374.455, 7321253.227, -2633.377],
26        [457499.332, 7321103.741, -2630.816],
27        [457581.202, 7321019.105, -2630.42],
28        [457661.101, 7320934.536, -2630.212],
29        [457727.784, 7320862.819, -2632.240],
30    ]
31
32    return coordinates
33
34
35resinsight = rips.Instance.find()
36
37# Get the well path collection
38well_path_coll = resinsight.project.well_path_collection()
39
40# Create different types of well paths
41well_paths_data = [
42    ("B 2-H", create_norne_well()),
43]
44
45created_wells = []
46
47for name, coordinates in well_paths_data:
48    print(f"\nCreating well path: {name}")
49    print(f"  Number of coordinate points: {len(coordinates)}")
50    print(
51        f"  Start: [{coordinates[0][0]:.1f}, {coordinates[0][1]:.1f}, {coordinates[0][2]:.1f}]"
52    )
53    print(
54        f"  End: [{coordinates[-1][0]:.1f}, {coordinates[-1][1]:.1f}, {coordinates[-1][2]:.1f}]"
55    )
56
57    # Create the well path using the new API
58    well_path = well_path_coll.import_well_path_from_points(
59        name=name, coordinates=coordinates
60    )
61
62    created_wells.append(well_path)