Skip to content

Commit 0df9520

Browse files
committed
Update rips module, proto files, and Python examples
1 parent 8524b2a commit 0df9520

File tree

6 files changed

+2910
-24
lines changed

6 files changed

+2910
-24
lines changed
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
#!/usr/bin/env python3
2+
3+
"""
4+
Example demonstrating how to use well event timeline and schedule data generation.
5+
6+
This example shows:
7+
1. Creating well events (perforations, tubing, valves) on a timeline
8+
2. Applying events up to a specific date using set_timestamp()
9+
3. Viewing the created completions after applying events
10+
4. Generating Eclipse schedule text from the event timeline
11+
12+
This 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+
19+
import rips
20+
21+
22+
def 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+
327+
if __name__ == "__main__":
328+
main()

docs/rips/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from .simulation_well import SimulationWell as SimulationWell
2222
from .exception import RipsError as RipsError
2323
from .surface import RegularSurface as RegularSurface
24+
from . import well_events as well_events # noqa: F401
2425

2526
from typing import List
2627

0 commit comments

Comments
 (0)