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)