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()
14
15# Get a list of all wells
16cases = resinsight.project.cases()
17if len(cases) == 0:
18    sys.exit("No cases found in the project. Please open a case and try again.")
19
20case = cases[0]
21print("Using Case: " + case.name)
22
23timesteps = case.time_steps()
24
25# store results in a dictionary,
26# use well name as the key and a list of the wells accumulated perforation
27# lengths for each timestep as the value
28results = {}
29
30# loop over all available simulation wells
31sim_wells = case.simulation_wells()
32for sim_well in sim_wells:
33    acclengths = []
34    for tidx, timestep in enumerate(timesteps):
35        acclengths.append(sim_well.accumulated_perforation_length(tidx))
36    results[sim_well.name] = acclengths
37
38# Print header
39header = ["Timestep"]
40for tidx, ts in enumerate(timesteps):
41    header.append("%d/%d/%d" % (ts.day, ts.month, ts.year))
42print(";".join(header))
43
44# Print the results
45for well_name, lengths in results.items():
46    line = [well_name]
47    for idx, length in enumerate(lengths):
48        line.append(str(length))
49    print(";".join(line))

Add Valve

add_valve.py
 1"""
 2Example demonstrating how to create a stand-alone ICV valve,
 3shut it and move it deeper
 4"""
 5
 6import rips
 7
 8rips_instance = rips.Instance.find()
 9well_path_coll = rips_instance.project.well_path_collection()
10
11# Create main well path using ModeledWellPath with targets
12main_well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
13main_well_path.name = "main_well_check_connection"
14main_well_path.update()
15
16# Add geometry targets to main well path
17main_geometry = main_well_path.well_path_geometry()
18main_geometry.append_well_target([1000.0, 2000.0, 0.0])  # Surface
19main_geometry.append_well_target([1000.0, 2000.0, -100.0])  # 100m down
20main_geometry.append_well_target([1000.0, 2000.0, -300.0])  # 300m down
21main_geometry.append_well_target([1000.0, 2000.0, -500.0])  # 500m down
22main_geometry.use_auto_generated_target_at_sea_level = False
23main_geometry.update()
24
25# Add a stand-alone valve at md 240
26valve = main_well_path.add_icv_valve(240.0)
27
28# default for valve should be open
29if valve.is_open:
30    print("Valve %s is open!" % valve.name)
31else:
32    print("Valve shut!")
33
34# close valve and move it to md = 275
35valve.is_open = False
36valve.start_measured_depth = 275
37valve.update()
38
39# valve should now be shut
40if valve.is_open:
41    print("Valve %s is open!" % valve.name)
42else:
43    print("Valve shut!")
44
45# valve should be at md = 275
46print("Valve measured depth: " + str(valve.start_measured_depth))

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()
11
12# Get a list of all wells
13cases = resinsight.project.cases()
14
15for 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()
11
12# Get a list of all wells
13wells = resinsight.project.well_paths()
14
15print("Got " + str(len(wells)) + " wells: ")
16for 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()
 4
 5# Create a modeled well path and add well path targets
 6# The coordinates are based on the Norne case
 7
 8well_path_coll = resinsight.project.well_path_collection()
 9well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
10well_path.name = "Test Well-1"
11well_path.update()
12
13geometry = well_path.well_path_geometry()
14
15reference_point = geometry.reference_point
16reference_point[0] = 457196
17reference_point[1] = 7322270
18reference_point[2] = 2742
19geometry.update()  # Commit updates back to ResInsight
20
21# Create the first well target at the reference point
22coord = [0, 0, 0]
23geometry.append_well_target(coord)
24
25# Append new well targets relative the the reference point
26coord = [454.28, 250, -10]
27target = geometry.append_well_target(coord)
28
29coord = [1054.28, 250, -50]
30target = geometry.append_well_target(coord)
31
32################################
33## Create a lateral well path and append it to the main well path
34################################
35
36lateral_well = well_path_coll.add_new_object(rips.ModeledWellPath)
37lateral_well.name = "Lateral-1"
38lateral_well.update()
39
40lateral_geometry = lateral_well.well_path_geometry()
41
42# Only create geometry starting from the first target of the lateral
43lateral_geometry.use_auto_generated_target_at_sea_level = False
44
45reference_point = lateral_geometry.reference_point
46reference_point[0] = 457550
47reference_point[1] = 7322481
48reference_point[2] = 2735
49lateral_geometry.update()  # Commit updates back to ResInsight
50
51coord = [0, 0, 0]
52lateral_geometry.append_well_target(coord)
53
54coord = [454.28, 250, -10]
55target = lateral_geometry.append_well_target(coord)
56
57coord = [1054.28, 250, -50]
58target = lateral_geometry.append_well_target(coord)
59
60# Append the lateral to the main well path
61well_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()
 20
 21# Get a list of all wells
 22wells = resinsight.project.well_paths()
 23
 24# Get a list of all cases
 25cases = resinsight.project.cases()
 26
 27# Use the first one
 28the_case = cases[0]
 29print("Using case " + the_case.name)
 30
 31print("Got " + str(len(wells)) + " well paths: ")
 32for well in wells:
 33    print("Well path name: " + well.name + "\n\n")
 34
 35    completion_data = well.completion_data(the_case.id)
 36
 37    print("WELSPECS")
 38
 39    welspecs = completion_data.welspecs
 40    welspecl_entries = []
 41
 42    for line in welspecs:
 43        # Check if grid_name is present and not empty
 44        has_grid_name = (
 45            hasattr(line, "grid_name")
 46            and line.HasField("grid_name")
 47            and line.grid_name.strip()
 48        )
 49
 50        if has_grid_name:
 51            # Store for WELSPECL section
 52            welspecl_entries.append(line)
 53        else:
 54            # Output as WELSPECS
 55            txt = line.well_name + "  "
 56            txt += line.group_name + "  "
 57            txt += str(line.grid_i) + "  "
 58            txt += str(line.grid_j) + "  "
 59            txt += fieldValueOrDefaultText(line, "bhp_depth") + "  "
 60            txt += line.phase + "  "
 61            txt += fieldValueOrDefaultText(line, "drainage_radius") + "  "
 62            txt += fieldValueOrDefaultText(line, "inflow_equation") + "  "
 63            txt += fieldValueOrDefaultText(line, "auto_shut_in") + "  "
 64            txt += fieldValueOrDefaultText(line, "cross_flow") + "  "
 65            txt += fieldValueOrDefaultText(line, "pvt_num") + "  "
 66            txt += fieldValueOrDefaultText(line, "hydrostatic_density_calc") + "  "
 67            txt += fieldValueOrDefaultText(line, "fip_region") + "  "
 68            txt += "/"
 69
 70            print(txt)
 71
 72    print("/\n")
 73
 74    # Output WELSPECL section if there are entries with grid_name
 75    if len(welspecl_entries) > 0:
 76        print("WELSPECL")
 77
 78        for line in welspecl_entries:
 79            txt = line.well_name + "  "
 80            txt += line.group_name + "  "
 81            txt += line.grid_name + "  "
 82            txt += str(line.grid_i) + "  "
 83            txt += str(line.grid_j) + "  "
 84            txt += fieldValueOrDefaultText(line, "bhp_depth") + "  "
 85            txt += line.phase + "  "
 86            txt += fieldValueOrDefaultText(line, "drainage_radius") + "  "
 87            txt += fieldValueOrDefaultText(line, "inflow_equation") + "  "
 88            txt += fieldValueOrDefaultText(line, "auto_shut_in") + "  "
 89            txt += fieldValueOrDefaultText(line, "cross_flow") + "  "
 90            txt += fieldValueOrDefaultText(line, "pvt_num") + "  "
 91            txt += fieldValueOrDefaultText(line, "hydrostatic_density_calc") + "  "
 92            txt += fieldValueOrDefaultText(line, "fip_region") + "  "
 93            txt += "/"
 94
 95            print(txt)
 96
 97        print("/\n")
 98
 99    compdat = completion_data.compdat
100
101    complump_entries = []
102    compdatl_entries = []
103
104    print("COMPDAT")
105
106    for line in compdat:
107        # Check if grid_name is present and not empty
108        has_grid_name = (
109            hasattr(line, "grid_name")
110            and line.HasField("grid_name")
111            and line.grid_name.strip()
112        )
113
114        if has_grid_name:
115            # Store for COMPDATL section
116            compdatl_entries.append(line)
117        else:
118            # Output as COMPDAT
119            txt = ""
120            complump = ""
121
122            if line.HasField("start_md"):
123                txt += "-- Perforation MD In " + str(line.start_md)
124                txt += ", MD Out " + str(line.end_md) + "--\n"
125
126            txt += "   "
127            txt += line.well_name + "  "
128            txt += str(line.grid_i) + "  "
129            txt += str(line.grid_j) + "  "
130            txt += str(line.upper_k) + "  "
131            txt += str(line.lower_k) + "  "
132            txt += line.open_shut_flag + "  "
133            txt += fieldValueOrDefaultText(line, "saturation") + "  "
134            txt += str(line.transmissibility) + "  "
135            txt += str(line.diameter) + "  "
136            txt += str(line.kh) + "  "
137            txt += fieldValueOrDefaultText(line, "skin_factor") + "  "
138            txt += fieldValueOrDefaultText(line, "d_factor") + "  "
139            txt += "'%s'" % line.direction
140            txt += " /"
141
142            if (line.HasField("completion_number")) and (line.completion_number > 0):
143                complump += "   "
144                complump += line.well_name + "  "
145                complump += str(line.grid_i) + "  "
146                complump += str(line.grid_j) + "  "
147                complump += str(line.upper_k) + "  "
148                complump += str(line.lower_k) + "  "
149                complump += str(line.completion_number) + "  "
150                complump += " /"
151
152                complump_entries.append(complump)
153
154            print(txt)
155
156    print("/\n")
157
158    # Output COMPDATL section if there are entries with grid_name
159    if len(compdatl_entries) > 0:
160        print("COMPDATL")
161
162        for line in compdatl_entries:
163            txt = ""
164
165            if line.HasField("start_md"):
166                txt += "-- Perforation MD In " + str(line.start_md)
167                txt += ", MD Out " + str(line.end_md) + "--\n"
168
169            txt += "   "
170            txt += line.well_name + "  "
171            txt += line.grid_name + "  "
172            txt += str(line.grid_i) + "  "
173            txt += str(line.grid_j) + "  "
174            txt += str(line.upper_k) + "  "
175            txt += str(line.lower_k) + "  "
176            txt += line.open_shut_flag + "  "
177            txt += fieldValueOrDefaultText(line, "saturation") + "  "
178            txt += str(line.transmissibility) + "  "
179            txt += str(line.diameter) + "  "
180            txt += str(line.kh) + "  "
181            txt += fieldValueOrDefaultText(line, "skin_factor") + "  "
182            txt += fieldValueOrDefaultText(line, "d_factor") + "  "
183            txt += "'%s'" % line.direction
184            txt += " /"
185
186            print(txt)
187
188        print("/\n")
189
190    if len(complump_entries) > 0:
191        print("COMPLUMP")
192        for complump_entry in complump_entries:
193            print(complump_entry)
194        print("/\n")
195    else:
196        print("-- No COMPLUMP entries --\n")
197
198    print("WELSEGS")
199    welsegs = completion_data.welsegs
200    if (welsegs is None) or (len(welsegs) == 0):
201        print("  -- No WELSEGS data --\n")
202    else:
203        for welsegs_entry in welsegs:
204            # Print WELSEGS header
205            header = welsegs_entry.header
206            txt = "-- Header: " + header.well_name + "\n"
207            txt += "   " + header.well_name + "  "
208            txt += str(header.top_depth) + "  "
209            txt += str(header.top_length) + "  "
210            txt += fieldValueOrDefaultText(header, "wellbore_volume") + "  "
211            txt += header.info_type + "  "
212            txt += fieldValueOrDefaultText(header, "pressure_components") + "  "
213            txt += fieldValueOrDefaultText(header, "flow_model")
214            txt += " /"
215            print(txt)
216
217            # Print WELSEGS segment rows
218            for row in welsegs_entry.row:
219                txt = "   "
220                txt += str(row.segment_1) + "  "
221                txt += str(row.segment_2) + "  "
222                txt += str(row.branch) + "  "
223                txt += str(row.join_segment) + "  "
224                txt += str(row.length) + "  "
225                txt += str(row.depth) + "  "
226                txt += fieldValueOrDefaultText(row, "diameter") + "  "
227                txt += fieldValueOrDefaultText(row, "roughness") + "  "
228                txt += " /"
229                print(txt)
230
231    print("/")
232
233    # Print COMPSEGS (MSW completion segments)
234    print("\nCOMPSEGS")
235    compsegs = completion_data.compsegs
236    compsegl_entries = []
237
238    if (compsegs is None) or (len(compsegs) == 0):
239        print("  -- No COMPSEGS data --")
240    else:
241        for compseg in compsegs:
242            # Check if grid_name is present and not empty
243            has_grid_name = (
244                hasattr(compseg, "grid_name")
245                and compseg.HasField("grid_name")
246                and compseg.grid_name.strip()
247            )
248
249            if has_grid_name:
250                # Store for COMPSEGL section
251                compsegl_entries.append(compseg)
252            else:
253                # Output as COMPSEGS
254                txt = "   "
255                txt += str(compseg.i) + "  "
256                txt += str(compseg.j) + "  "
257                txt += str(compseg.k) + "  "
258                txt += str(compseg.branch) + "  "
259                txt += str(compseg.distance_start) + "  "
260                txt += str(compseg.distance_end) + "  "
261                txt += " /"
262                print(txt)
263
264    print("/\n")
265
266    # Output COMPSEGL section if there are entries with grid_name
267    if len(compsegl_entries) > 0:
268        print("COMPSEGL")
269
270        for compseg in compsegl_entries:
271            txt = "   "
272            txt += compseg.grid_name + "  "
273            txt += str(compseg.i) + "  "
274            txt += str(compseg.j) + "  "
275            txt += str(compseg.k) + "  "
276            txt += str(compseg.branch) + "  "
277            txt += str(compseg.distance_start) + "  "
278            txt += str(compseg.distance_end) + "  "
279            txt += " /"
280            print(txt)
281
282        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 = rips.PropertyType.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 = rips.PropertyType.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()
12
13# Get a list of all wells
14wells = resinsight.project.well_paths()
15
16print("Got " + str(len(wells)) + " wells: ")
17for 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()
26
27# Get a list of all wells
28wells = resinsight.project.well_paths()
29
30# Find the first case
31cases = resinsight.project.cases()
32c = cases[0] if len(cases) else None
33
34for 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            (rips.PropertyType.DYNAMIC_NATIVE, "PRESSURE", 0),
51            (rips.PropertyType.STATIC_NATIVE, "FAULTDIST", 0),
52        ]
53
54        for property_type, property_name, time_step in properties:
55            porosity_model = rips.PorosityModelType.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    (rips.PropertyType.STATIC_NATIVE, "INDEX_K", 0),
16    (rips.PropertyType.STATIC_NATIVE, "PORO", 0),
17    (rips.PropertyType.STATIC_NATIVE, "PERMX", 0),
18    (rips.PropertyType.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# Set well path colors using hex color strings
33all_well_paths = resInsight.project.well_paths()
34colors = ["#ff0000", "#00ff00", "#0000ff", "#ffff00"]
35for i, well_path in enumerate(all_well_paths):
36    well_path.well_path_color = colors[i % len(colors)]
37    well_path.update()
38    print("Set color of " + well_path.name + " to " + well_path.well_path_color)
39
40
41well_path_names = resInsight.project.import_well_log_files(
42    well_log_folder="D:/Projects/ResInsight-regression-test/ModelData/Norne_PLT_LAS"
43)
44if resInsight.project.has_warnings():
45    for warning in resInsight.project.warnings():
46        print(warning)
47
48for well_path_name in well_path_names:
49    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.")

Tie In Example

tie_in_example.py
 1"""
 2Example demonstrating how to create well paths from XYZ coordinates
 3and add a tie-in valve, adjusting the valve MD to a custom value.
 4"""
 5
 6import rips
 7
 8rips_instance = rips.Instance.find()
 9
10
11well_path_coll = rips_instance.project.well_path_collection()
12
13# Create main well path using ModeledWellPath with targets
14main_well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
15main_well_path.name = "main_well_check_connection"
16main_well_path.update()
17
18# Add geometry targets to main well path
19main_geometry = main_well_path.well_path_geometry()
20main_geometry.append_well_target([1000.0, 2000.0, 0.0])  # Surface
21main_geometry.append_well_target([1000.0, 2000.0, -100.0])  # 100m down
22main_geometry.append_well_target([1000.0, 2000.0, -300.0])  # 300m down
23main_geometry.append_well_target([1000.0, 2000.0, -500.0])  # 500m down
24main_geometry.use_auto_generated_target_at_sea_level = False
25main_geometry.update()
26
27measured_depth = 150
28lateral = main_well_path.append_lateral(measured_depth)
29
30# Get the valve template collection
31valve_templates = rips_instance.project.valve_templates()
32
33# create an ICV valve template
34icv_template = valve_templates.add_template(
35    completion_type="ICV",
36    orifice_diameter=12.5,
37    flow_coefficient=0.85,
38    user_label="Custom ICV for Lateral",
39)
40
41# Enable well valve
42valve = lateral.enable_outlet_valve(
43    enable=True, icv_template=icv_template, use_custom_valve_md=False
44)
45
46# Enable a custom md for the outlet valve
47tiein = lateral.tie_in()
48
49custom_enabled, custom_md = tiein.custom_outlet_valve_md
50print("Custom outlet valve md: " + str(custom_enabled))
51
52tiein.custom_outlet_valve_md = (True, 200.0)
53tiein.update()
54
55custom_enabled, custom_md = tiein.custom_outlet_valve_md
56print("Custom outlet valve md: " + str(custom_enabled) + " at " + str(custom_md))

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    # completion_number assigns the perforation to a completion group, which makes
 57    # the schedule emit a COMPLUMP keyword lumping these connections into group 1.
 58    _perf_event1 = timeline.add_perf_event(
 59        event_date="2024-02-01",
 60        well_path=well_path,
 61        start_md=2000.0,
 62        end_md=2200.0,
 63        diameter=0.1,
 64        skin_factor=0.5,
 65        state="OPEN",
 66        completion_number=1,
 67    )
 68    print("   Added perforation event on 2024-02-01 (MD 2000-2200m, completion 1)")
 69
 70    # Add second perforation event (later), assigned to a different completion group.
 71    _perf_event2 = timeline.add_perf_event(
 72        event_date="2024-04-01",
 73        well_path=well_path,
 74        start_md=2400.0,
 75        end_md=2600.0,
 76        diameter=0.1,
 77        skin_factor=0.3,
 78        state="OPEN",
 79        completion_number=2,
 80    )
 81    print("   Added perforation event on 2024-04-01 (MD 2400-2600m, completion 2)")
 82
 83    # Add a perforation event with an explicit time-of-day. event_date accepts an ISO 8601
 84    # timestamp, so a non-midnight time (here with millisecond precision) is preserved and
 85    # emitted as the optional TIME field of the DATES keyword (e.g. "DATES\n 15 'MAY' 2024
 86    # '14:45:30.500' /"). Date-only events keep their plain DAY/MONTH/YEAR output.
 87    _perf_event3 = timeline.add_perf_event(
 88        event_date="2024-05-15T14:45:30.500",
 89        well_path=well_path,
 90        start_md=2300.0,
 91        end_md=2350.0,
 92        diameter=0.1,
 93        skin_factor=0.4,
 94        state="OPEN",
 95        completion_number=3,
 96    )
 97    print(
 98        "   Added perforation event on 2024-05-15T14:45:30.500 (MD 2300-2350m, completion 3, time-of-day preserved)"
 99    )
100
101    # Add valve event (requires existing perforation)
102    _valve_event = timeline.add_valve_event(
103        event_date="2024-03-01",
104        well_path=well_path,
105        measured_depth=2100.0,
106        valve_type="ICV",
107        state="OPEN",
108        flow_coefficient=0.7,
109        area=0.0001,
110    )
111    print("   Added valve event on 2024-03-01 (MD 2100m)")
112
113    # Add state events (for documentation, not applied to completions)
114    _state_event = timeline.add_state_event(
115        event_date="2024-02-15",
116        well_path=well_path,
117        well_state="OPEN",
118    )
119    print("   Added state event on 2024-02-15 (OPEN)")
120
121    # Add well keyword events (arbitrary Eclipse keywords)
122    print("\n   Adding well keyword events...")
123
124    # Example 1: WCONHIST - Historical production data
125    _wconhist_event = timeline.add_well_keyword_event(
126        event_date="2024-01-15",
127        well_path=well_path,
128        keyword_name="WCONHIST",
129        keyword_data={
130            "WELL": well_path.name,
131            "STATUS": "OPEN",
132            "CMODE": "RESV",
133            "ORAT": 3999.99,
134            "WRAT": 0.01,
135            "GRAT": 550678.44,
136            "VFP_TABLE": 1,
137        },
138    )
139    print("   Added WCONHIST event on 2024-01-15 (historical production control)")
140
141    # Example 2: WELTARG - Well target change
142    _weltarg_event = timeline.add_well_keyword_event(
143        event_date="2024-05-01",
144        well_path=well_path,
145        keyword_name="WELTARG",
146        keyword_data={
147            "WELL": well_path.name,
148            "CMODE": "ORAT",
149            "NEW_VALUE": 5000.0,
150        },
151    )
152    print("   Added WELTARG event on 2024-05-01 (well target change)")
153
154    # Example 3: WRFTPLT - RFT/PLT output control
155    _wrftplt_event = timeline.add_well_keyword_event(
156        event_date="2024-06-01",
157        well_path=well_path,
158        keyword_name="WRFTPLT",
159        keyword_data={
160            "WELL": well_path.name,
161            "OUTPUT_RFT": "YES",
162            "OUTPUT_PLT": "NO",
163            "OUTPUT_SEGMENT": "NO",
164        },
165    )
166    print("   Added WRFTPLT event on 2024-06-01 (RFT/PLT output control)")
167
168    # Add schedule-level keyword events (not tied to a well)
169    print("\n   Adding schedule-level keyword events...")
170
171    # Example 4: RPTRST - Report restart settings (schedule-level, not well-specific)
172    _rptrst_event = timeline.add_keyword_event(
173        event_date="2024-01-01",
174        keyword_name="RPTRST",
175        keyword_data={
176            "BASIC": 2,
177            "FREQ": 1,
178        },
179    )
180    print("   Added RPTRST event on 2024-01-01 (report restart settings)")
181
182    # Example 5: GRUPTREE - Group tree definition
183    _gruptree_event = timeline.add_keyword_event(
184        event_date="2024-01-01",
185        keyword_name="GRUPTREE",
186        keyword_data={
187            "CHILD": "OP",
188            "PARENT": "FIELD",
189        },
190    )
191    print("   Added GRUPTREE event on 2024-01-01 (group tree definition)")
192
193    # Example 6: TUNING - Time stepping / convergence control.
194    # TUNING is a multi-record keyword: items are distributed into the record that
195    # defines them (record 1: TSINIT/TSMAXZ/TMAXWC, record 3: NEWTMX..MXWPIT), so the
196    # generated keyword has three records, each terminated by its own '/'.
197    _tuning_event = timeline.add_keyword_event(
198        event_date="2024-01-01",
199        keyword_name="TUNING",
200        keyword_data={
201            "TSINIT": 1,
202            "TSMAXZ": 30,
203            "TMAXWC": 1,
204            "NEWTMX": 12,
205            "NEWTMN": 1,
206            "LITMAX": 50,
207            "LITMIN": 1,
208            "MXWSIT": 50,
209            "MXWPIT": 50,
210        },
211    )
212    print("   Added TUNING event on 2024-01-01 (time stepping / convergence control)")
213
214    # Apply events up to March 15, 2024
215    # This should create:
216    # - Tubing interval (Jan 1)
217    # - First perforation (Feb 1)
218    # - Valve in first perforation (Mar 1)
219    # But NOT the second perforation (Apr 1)
220    timeline.set_timestamp(timestamp="2024-12-24")
221
222    # Get the Eclipse case (if available)
223    # Show what was created
224    print("\n3. Verifying created completions...")
225
226    # Check perforations
227    perforation_coll = well_path.completions().perforations()
228    perforations = perforation_coll.perforations()
229    print(f"   Perforations created: {len(perforations)}")
230    for perf in perforations:
231        print(
232            f"      - MD {perf.start_measured_depth:.0f} to {perf.end_measured_depth:.0f}m"
233        )
234        valves = perf.valves()
235        if valves:
236            print(f"        Valves: {len(valves)}")
237
238    # Check MSW settings (tubing intervals)
239    msw_settings = well_path.msw_settings()
240    if msw_settings:
241        print(f"   MSW diameter/roughness mode: {msw_settings.diameter_roughness_mode}")
242
243    # Generate Eclipse schedule text
244    print("\n4. Generating Eclipse schedule text from events...")
245
246    # Get the Eclipse case (if available)
247    cases = project.cases()
248    if cases:
249        case = cases[0]
250        print(f"   Using Eclipse case: {case.name}")
251
252        # Generate schedule text. Pass the wells that should get multi-segment-well
253        # keywords (WELSEGS, COMPSEGS, WSEGVALV, WSEGAICD); an empty list omits them.
254        schedule_text = timeline.generate_schedule_text(
255            eclipse_case=case, export_msw_for_wells=[well_path]
256        )
257
258        # Generate the same schedule with align_columns=True, which adds a "--"-prefixed
259        # column-header comment per keyword and right-aligns the data into fixed-width
260        # columns. Only the formatting differs from the unaligned text above.
261        schedule_text_aligned = timeline.generate_schedule_text(
262            eclipse_case=case, export_msw_for_wells=[well_path], align_columns=True
263        )
264
265        if schedule_text:
266            print(f"\n   Generated schedule text ({len(schedule_text)} characters)")
267            print("   " + "=" * 60)
268            # Show the full schedule
269            lines = schedule_text.split("\n")
270            for line in lines:
271                print(f"   {line}")
272            print("   " + "=" * 60)
273
274            # Validate expected keywords are present
275            print("\n7. Validating generated Eclipse keywords...")
276            expected_keywords = [
277                "DATES",
278                "WELSEGS",
279                "COMPSEGS",
280                "COMPDAT",
281                "COMPLUMP",
282                "WCONHIST",
283                "WELTARG",
284                "WRFTPLT",
285                "RPTRST",
286                "GRUPTREE",
287                "TUNING",
288            ]
289            found_keywords = [kw for kw in expected_keywords if kw in schedule_text]
290
291            print(f"   Keywords found: {', '.join(found_keywords)}")
292
293            # The 2024-05-15T14:45:30.500 perforation event should surface as a DATES
294            # keyword carrying the optional TIME field with millisecond precision.
295            if "14:45:30.500" in schedule_text:
296                print(
297                    "   ✓ DATES keyword preserves event time-of-day (TIME field: 14:45:30.500)"
298                )
299
300            if "WELSEGS" in schedule_text:
301                print("   ✓ WELSEGS keyword generated (MSW well segments)")
302                # Count segment lines (lines with segment data)
303                welsegs_lines = [
304                    line
305                    for line in lines
306                    if line.strip() and line.strip()[0].isdigit() and " 1 " in line
307                ]
308                print(f"     Number of segments: {len(welsegs_lines)}")
309
310            if "COMPSEGS" in schedule_text:
311                print("   ✓ COMPSEGS keyword generated (completion segments)")
312
313            if "COMPLUMP" in schedule_text:
314                print("   ✓ COMPLUMP keyword generated (perforation completion groups)")
315
316            if "WSEGVALV" in schedule_text:
317                print("   ✓ WSEGVALV keyword generated (segment valves)")
318                # Extract valve parameters
319                wsegvalv_idx = schedule_text.find("WSEGVALV")
320                if wsegvalv_idx > 0:
321                    wsegvalv_section = schedule_text[wsegvalv_idx : wsegvalv_idx + 500]
322                    if "0.7" in wsegvalv_section:
323                        print("     Flow coefficient (Cv) = 0.7 detected")
324
325            if "WCONPROD" in schedule_text or "WCONINJE" in schedule_text:
326                kw_name = "WCONPROD" if "WCONPROD" in schedule_text else "WCONINJE"
327                print(f"   ✓ {kw_name} keyword generated (well control)")
328
329            # Show keyword summary
330            print("\n   Eclipse Keyword Summary:")
331            print(f"   - DATES entries: {schedule_text.count('DATES')}")
332            print(f"   - WELSEGS entries: {schedule_text.count('WELSEGS')}")
333            print(f"   - COMPSEGS entries: {schedule_text.count('COMPSEGS')}")
334            print(f"   - COMPLUMP entries: {schedule_text.count('COMPLUMP')}")
335            print(f"   - WSEGVALV entries: {schedule_text.count('WSEGVALV')}")
336            print(f"   - WCONHIST entries: {schedule_text.count('WCONHIST')}")
337            print(f"   - WELTARG entries: {schedule_text.count('WELTARG')}")
338            print(f"   - WRFTPLT entries: {schedule_text.count('WRFTPLT')}")
339            print(f"   - RPTRST entries: {schedule_text.count('RPTRST')}")
340            print(f"   - GRUPTREE entries: {schedule_text.count('GRUPTREE')}")
341            print(f"   - TUNING entries: {schedule_text.count('TUNING')}")
342
343            # Save both formats to file
344            unaligned_file = "generate_schedule_unaligned.sch"
345            with open(unaligned_file, "w") as f:
346                f.write(schedule_text)
347            print(f"\n   Unaligned schedule text saved to: {unaligned_file}")
348
349            aligned_file = "generate_schedule_aligned.sch"
350            with open(aligned_file, "w") as f:
351                f.write(schedule_text_aligned)
352            print(f"   Aligned schedule text saved to:   {aligned_file}")
353
354            # Show example of generated keywords
355            print("\n8. Example of generated Eclipse keywords:")
356            print(f"   (See {unaligned_file} / {aligned_file} for complete output)")
357            if "WELSEGS" in schedule_text:
358                print("\n   Sample WELSEGS segment:")
359                for line in lines:
360                    if "WELSEGS" in line:
361                        idx = lines.index(line)
362                        # Show keyword and first data line
363                        if idx + 2 < len(lines):
364                            print(f"   {lines[idx]}")
365                            print(f"   {lines[idx + 1]}")
366                            print(f"   {lines[idx + 2]}")
367                        break
368        else:
369            print("   Warning: No schedule text was generated")
370    else:
371        print("   Note: No Eclipse case loaded - skipping schedule generation")
372        print("   Load a case first to generate schedule text")
373
374    print("\nExample completed successfully!")
375    print("\nAPI Usage Summary:")
376    print("- timeline = well_path.event_timeline()")
377    print("- timeline.add_perf_event(event_date='2024-01-01', well_name='WellA', ...)")
378    print(
379        "- timeline.add_tubing_event(event_date='2024-01-01', well_name='WellA', ...)"
380    )
381    print("- timeline.add_valve_event(event_date='2024-01-01', well_name='WellA', ...)")
382    print("- timeline.add_well_keyword_event(  # Well-specific Eclipse keywords:")
383    print("      event_date='2024-01-01',")
384    print("      well_path=well_path,")
385    print("      keyword_name='WCONHIST',  # WCONHIST, WELTARG, WRFTPLT, etc.")
386    print("      keyword_data={'WELL': 'WellA', 'ORAT': 1000.0, ...}")
387    print("  )")
388    print(
389        "- timeline.add_keyword_event(  # Schedule-level keywords (not tied to wells):"
390    )
391    print("      event_date='2024-01-01',")
392    print("      keyword_name='RPTRST',  # RPTRST, GRUPTREE, RPTSCHED, etc.")
393    print("      keyword_data={'BASIC': 2, 'FREQ': 1}")
394    print("  )")
395    print("- timeline.set_timestamp(timestamp='2024-06-01')  # Apply events up to date")
396    print(
397        "- schedule_text = timeline.generate_schedule_text(eclipse_case=case, export_msw_for_wells=[well_path])"
398    )
399    print(
400        "  # Generate Eclipse schedule text (export_msw_for_wells enables MSW keywords)"
401    )
402
403
404if __name__ == "__main__":
405    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    # Read the well logs back using the well log read API
 86    print("\nReading well logs back from the project:")
 87    for log in well_path.well_logs():
 88        data = log.well_log_data()
 89        md = data["measured_depth"]
 90        channel_names = [
 91            key for key in data if key not in ("measured_depth", "tvd_msl", "tvd_rkb")
 92        ]
 93        print(f"  {log.name}: {len(md)} samples, channels = {channel_names}")
 94
 95        depth_keys = [k for k in ("measured_depth", "tvd_msl", "tvd_rkb") if k in data]
 96        columns = depth_keys + channel_names
 97        for label, idx in (("First", 0), ("Last", len(md) - 1)):
 98            parts = [f"{key}={data[key][idx]:.3f}" for key in columns]
 99            print(f"    {label}: {', '.join(parts)}")
100
101
102if __name__ == "__main__":
103    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)