0
# Well Data Processing
1
2
Comprehensive well data analysis including well states, connections, segments, production and injection rates, and time-based well performance tracking from reservoir simulation results.
3
4
## Capabilities
5
6
### Well Information Management
7
8
Central interface for accessing well data and states across simulation time steps.
9
10
```python { .api }
11
class WellInfo:
12
"""Well information container and state management."""
13
14
def get_ts(self, well_name: str) -> list:
15
"""Get time series data for well."""
16
17
def get_state_from_report(self, well_name: str, report_step: int) -> WellState:
18
"""
19
Get well state at specific report step.
20
21
Args:
22
well_name (str): Name of the well
23
report_step (int): Report step number
24
25
Returns:
26
WellState: Well state at the report step
27
"""
28
29
def get_state_from_time(self, well_name: str, time: datetime) -> WellState:
30
"""
31
Get well state at specific time.
32
33
Args:
34
well_name (str): Name of the well
35
time (datetime): Simulation time
36
37
Returns:
38
WellState: Well state at the specified time
39
"""
40
41
def load_rstfile(self, rst_file: ResdataFile):
42
"""Load well data from restart file."""
43
44
def well_names(self) -> list:
45
"""
46
Get list of all well names.
47
48
Returns:
49
list: List of well name strings
50
"""
51
52
def get_well_time_line(self, well_name: str) -> WellTimeLine:
53
"""Get time line for specific well."""
54
```
55
56
### Well State Analysis
57
58
Well state at specific simulation time including production/injection data and connection information.
59
60
```python { .api }
61
class WellState:
62
"""Well state at specific simulation time."""
63
64
def name(self) -> str:
65
"""Get well name."""
66
67
def report_nr(self) -> int:
68
"""Get report number."""
69
70
def sim_time(self) -> float:
71
"""Get simulation time in days."""
72
73
def has_global_connections(self) -> bool:
74
"""Check if well has global connections."""
75
76
def get_global_connections(self) -> list:
77
"""Get list of global connections."""
78
79
def get_connections(self) -> list:
80
"""Get list of well connections."""
81
82
def is_producer(self) -> bool:
83
"""Check if well is a producer."""
84
85
def is_injector(self) -> bool:
86
"""Check if well is an injector."""
87
88
def get_production_rates(self) -> dict:
89
"""
90
Get production rates.
91
92
Returns:
93
dict: Production rates with keys 'oil', 'gas', 'water', 'liquid'
94
"""
95
96
def get_injection_rates(self) -> dict:
97
"""
98
Get injection rates.
99
100
Returns:
101
dict: Injection rates with keys 'water', 'gas'
102
"""
103
```
104
105
### Well Connection Data
106
107
Individual well connection information including perforation data and flow rates.
108
109
```python { .api }
110
class WellConnection:
111
"""Individual well connection data."""
112
113
def i(self) -> int:
114
"""Get I-index of connection."""
115
116
def j(self) -> int:
117
"""Get J-index of connection."""
118
119
def k(self) -> int:
120
"""Get K-index of connection."""
121
122
def is_open(self) -> bool:
123
"""Check if connection is open."""
124
125
def is_shut(self) -> bool:
126
"""Check if connection is shut."""
127
128
def transmissibility_factor(self) -> float:
129
"""Get transmissibility factor."""
130
131
def diameter(self) -> float:
132
"""Get connection diameter."""
133
134
def connection_factor(self) -> float:
135
"""Get connection factor."""
136
137
def depth(self) -> float:
138
"""Get connection depth."""
139
140
def volume_rate(self) -> float:
141
"""Get total volume rate."""
142
143
def oil_rate(self) -> float:
144
"""Get oil production rate."""
145
146
def gas_rate(self) -> float:
147
"""Get gas production rate."""
148
149
def water_rate(self) -> float:
150
"""Get water production rate."""
151
152
def resv_rate(self) -> float:
153
"""Get reservoir volume rate."""
154
```
155
156
### Well Segment Operations
157
158
Well segment information for multi-segment wells including pressure drop and flow characteristics.
159
160
```python { .api }
161
class WellSegment:
162
"""Well segment information for multi-segment wells."""
163
164
def get_id(self) -> int:
165
"""Get segment ID."""
166
167
def get_outlet(self) -> int:
168
"""Get outlet segment ID."""
169
170
def is_active(self) -> bool:
171
"""Check if segment is active."""
172
173
def is_closest(self) -> bool:
174
"""Check if segment is closest to surface."""
175
176
def is_main_stem(self) -> bool:
177
"""Check if segment is in main stem."""
178
179
def get_length(self) -> float:
180
"""Get segment length."""
181
182
def get_depth(self) -> float:
183
"""Get segment depth."""
184
185
def get_diameter(self) -> float:
186
"""Get segment diameter."""
187
```
188
189
### Well Timeline Management
190
191
Time-based well operations and state changes throughout simulation.
192
193
```python { .api }
194
class WellTimeLine:
195
"""Time line for well operations and state changes."""
196
197
def get_first_date(self) -> datetime:
198
"""Get first operation date."""
199
200
def get_last_date(self) -> datetime:
201
"""Get last operation date."""
202
203
def time_list(self) -> list:
204
"""Get list of operation times."""
205
206
def get_state(self, time: datetime) -> WellState:
207
"""Get well state at specific time."""
208
```
209
210
## Usage Examples
211
212
### Basic Well Analysis
213
214
```python
215
from resdata.well import WellInfo
216
from resdata.resfile import ResdataFile
217
218
# Load restart file and extract well information
219
restart = ResdataFile("SIMULATION.UNRST")
220
well_info = WellInfo()
221
well_info.load_rstfile(restart)
222
223
# Get all well names
224
wells = well_info.well_names()
225
print(f"Wells in simulation: {wells}")
226
227
# Analyze each well's final state
228
for well_name in wells:
229
try:
230
# Get final state (last report step)
231
final_state = well_info.get_state_from_report(well_name, -1)
232
233
print(f"\nWell: {well_name}")
234
print(f" Type: {'Producer' if final_state.is_producer() else 'Injector'}")
235
print(f" Report: {final_state.report_nr()}")
236
print(f" Sim time: {final_state.sim_time():.1f} days")
237
238
# Get production/injection rates
239
if final_state.is_producer():
240
rates = final_state.get_production_rates()
241
print(f" Oil rate: {rates.get('oil', 0):.1f} m³/day")
242
print(f" Gas rate: {rates.get('gas', 0):.1f} m³/day")
243
print(f" Water rate: {rates.get('water', 0):.1f} m³/day")
244
else:
245
rates = final_state.get_injection_rates()
246
print(f" Water inj: {rates.get('water', 0):.1f} m³/day")
247
print(f" Gas inj: {rates.get('gas', 0):.1f} m³/day")
248
249
except Exception as e:
250
print(f"Error processing well {well_name}: {e}")
251
```
252
253
### Well Connection Analysis
254
255
```python
256
from resdata.well import WellInfo
257
from resdata.resfile import ResdataFile
258
259
# Load data
260
restart = ResdataFile("SIMULATION.UNRST")
261
well_info = WellInfo()
262
well_info.load_rstfile(restart)
263
264
# Analyze connections for a specific well
265
well_name = "PROD01"
266
final_state = well_info.get_state_from_report(well_name, -1)
267
268
print(f"Connection analysis for {well_name}:")
269
print(f"Has global connections: {final_state.has_global_connections()}")
270
271
connections = final_state.get_connections()
272
print(f"Number of connections: {len(connections)}")
273
274
total_oil_rate = 0.0
275
active_connections = 0
276
277
for i, conn in enumerate(connections):
278
if conn.is_open():
279
print(f"\nConnection {i+1} (Active):")
280
print(f" Grid cell: ({conn.i()}, {conn.j()}, {conn.k()})")
281
print(f" Depth: {conn.depth():.1f} m")
282
print(f" Diameter: {conn.diameter():.3f} m")
283
print(f" Trans factor: {conn.transmissibility_factor():.2e}")
284
print(f" Oil rate: {conn.oil_rate():.2f} m³/day")
285
print(f" Water rate: {conn.water_rate():.2f} m³/day")
286
print(f" Gas rate: {conn.gas_rate():.2f} m³/day")
287
288
total_oil_rate += conn.oil_rate()
289
active_connections += 1
290
else:
291
print(f"\nConnection {i+1} (Shut)")
292
293
print(f"\nSummary:")
294
print(f" Active connections: {active_connections}/{len(connections)}")
295
print(f" Total oil rate: {total_oil_rate:.1f} m³/day")
296
```
297
298
### Well Performance Over Time
299
300
```python
301
from resdata.well import WellInfo
302
from resdata.resfile import ResdataFile
303
from datetime import datetime, timedelta
304
import matplotlib.pyplot as plt
305
306
# Load data
307
restart = ResdataFile("SIMULATION.UNRST")
308
well_info = WellInfo()
309
well_info.load_rstfile(restart)
310
311
# Get well timeline
312
well_name = "PROD01"
313
timeline = well_info.get_well_time_line(well_name)
314
315
# Get operation period
316
start_date = timeline.get_first_date()
317
end_date = timeline.get_last_date()
318
print(f"Well {well_name} active period: {start_date} to {end_date}")
319
320
# Sample well performance monthly
321
performance_data = {
322
'dates': [],
323
'oil_rates': [],
324
'water_rates': [],
325
'water_cuts': []
326
}
327
328
current_date = start_date
329
while current_date <= end_date:
330
try:
331
state = well_info.get_state_from_time(well_name, current_date)
332
if state.is_producer():
333
rates = state.get_production_rates()
334
oil_rate = rates.get('oil', 0)
335
water_rate = rates.get('water', 0)
336
337
# Calculate water cut
338
total_liquid = oil_rate + water_rate
339
water_cut = water_rate / total_liquid if total_liquid > 0 else 0
340
341
performance_data['dates'].append(current_date)
342
performance_data['oil_rates'].append(oil_rate)
343
performance_data['water_rates'].append(water_rate)
344
performance_data['water_cuts'].append(water_cut * 100) # Percentage
345
346
except Exception as e:
347
print(f"No data for {current_date}: {e}")
348
349
# Move to next month
350
if current_date.month == 12:
351
current_date = current_date.replace(year=current_date.year + 1, month=1)
352
else:
353
current_date = current_date.replace(month=current_date.month + 1)
354
355
# Plot performance
356
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
357
358
# Production rates
359
ax1.plot(performance_data['dates'], performance_data['oil_rates'],
360
'g-', linewidth=2, label='Oil Rate')
361
ax1.plot(performance_data['dates'], performance_data['water_rates'],
362
'b-', linewidth=2, label='Water Rate')
363
ax1.set_ylabel('Rate (m³/day)')
364
ax1.set_title(f'{well_name} Production Performance')
365
ax1.legend()
366
ax1.grid(True)
367
368
# Water cut
369
ax2.plot(performance_data['dates'], performance_data['water_cuts'],
370
'r-', linewidth=2)
371
ax2.set_ylabel('Water Cut (%)')
372
ax2.set_xlabel('Date')
373
ax2.grid(True)
374
375
plt.tight_layout()
376
plt.show()
377
378
# Performance statistics
379
if performance_data['oil_rates']:
380
print(f"\nPerformance Statistics:")
381
print(f" Peak oil rate: {max(performance_data['oil_rates']):.1f} m³/day")
382
print(f" Average oil rate: {sum(performance_data['oil_rates'])/len(performance_data['oil_rates']):.1f} m³/day")
383
print(f" Final water cut: {performance_data['water_cuts'][-1]:.1f}%")
384
```
385
386
### Multi-Segment Well Analysis
387
388
```python
389
from resdata.well import WellInfo
390
from resdata.resfile import ResdataFile
391
392
# Load data (assuming multi-segment well simulation)
393
restart = ResdataFile("SIMULATION.UNRST")
394
well_info = WellInfo()
395
well_info.load_rstfile(restart)
396
397
# Analyze multi-segment well
398
well_name = "MSW01" # Multi-segment well
399
final_state = well_info.get_state_from_report(well_name, -1)
400
401
print(f"Multi-segment well analysis: {well_name}")
402
403
# Note: Segment analysis would require additional well segment data
404
# This is a simplified example showing the interface
405
connections = final_state.get_connections()
406
407
print(f"Well connections: {len(connections)}")
408
for i, conn in enumerate(connections):
409
if conn.is_open():
410
print(f" Connection {i+1}: Cell ({conn.i()}, {conn.j()}, {conn.k()})")
411
print(f" Depth: {conn.depth():.1f} m")
412
print(f" Oil rate: {conn.oil_rate():.2f} m³/day")
413
print(f" Connection factor: {conn.connection_factor():.2e}")
414
```
415
416
### Well State Comparison
417
418
```python
419
from resdata.well import WellInfo
420
from resdata.resfile import ResdataFile
421
422
# Load data
423
restart = ResdataFile("SIMULATION.UNRST")
424
well_info = WellInfo()
425
well_info.load_rstfile(restart)
426
427
# Compare well states at different times
428
well_name = "PROD01"
429
430
# Early production (report step 10)
431
early_state = well_info.get_state_from_report(well_name, 10)
432
433
# Late production (report step -10, i.e., 10th from end)
434
late_state = well_info.get_state_from_report(well_name, -10)
435
436
print(f"Well state comparison: {well_name}")
437
print("\nEarly Production:")
438
print(f" Time: {early_state.sim_time():.1f} days")
439
if early_state.is_producer():
440
early_rates = early_state.get_production_rates()
441
print(f" Oil rate: {early_rates.get('oil', 0):.1f} m³/day")
442
print(f" Water rate: {early_rates.get('water', 0):.1f} m³/day")
443
444
print("\nLate Production:")
445
print(f" Time: {late_state.sim_time():.1f} days")
446
if late_state.is_producer():
447
late_rates = late_state.get_production_rates()
448
print(f" Oil rate: {late_rates.get('oil', 0):.1f} m³/day")
449
print(f" Water rate: {late_rates.get('water', 0):.1f} m³/day")
450
451
# Calculate decline
452
if early_state.is_producer() and late_state.is_producer():
453
early_oil = early_rates.get('oil', 0)
454
late_oil = late_rates.get('oil', 0)
455
456
if early_oil > 0:
457
decline_rate = (early_oil - late_oil) / early_oil * 100
458
print(f"\nOil rate decline: {decline_rate:.1f}%")
459
460
early_wcut = early_rates.get('water', 0) / (early_rates.get('oil', 0) + early_rates.get('water', 0) + 1e-10)
461
late_wcut = late_rates.get('water', 0) / (late_rates.get('oil', 0) + late_rates.get('water', 0) + 1e-10)
462
463
print(f"Water cut increase: {early_wcut*100:.1f}% → {late_wcut*100:.1f}%")
464
```
465
466
## Types
467
468
```python { .api }
469
# Well types
470
WellType = Literal[
471
"UNDOCUMENTED_ZERO", # Unknown/undefined type
472
"PRODUCER", # Production well
473
"WATER_INJECTOR", # Water injection well
474
"GAS_INJECTOR", # Gas injection well
475
"OIL_INJECTOR" # Oil injection well
476
]
477
478
# Connection directions
479
WellConnectionDirection = Literal[
480
"DIR_X", # X-direction perforation
481
"DIR_Y", # Y-direction perforation
482
"DIR_Z", # Z-direction perforation
483
"DIR_FRACX", # X-direction fracture
484
"DIR_FRACY" # Y-direction fracture
485
]
486
487
# Production/injection rates dictionary
488
ProductionRates = dict[str, float] # Keys: 'oil', 'gas', 'water', 'liquid'
489
InjectionRates = dict[str, float] # Keys: 'water', 'gas'
490
491
# Grid cell indices for connections
492
CellIndices = tuple[int, int, int] # (i, j, k)
493
```