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