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)