0
# Summary Analysis
1
2
Comprehensive time series data processing for reservoir simulation summary data including production rates, cumulative values, well performance, field totals, and economic analysis with NPV calculations.
3
4
## Capabilities
5
6
### Summary Data Loading and Access
7
8
Main interface for loading and accessing summary data from SMSPEC and UNSMRY files.
9
10
```python { .api }
11
class Summary:
12
"""Summary data operations and time series analysis."""
13
14
@classmethod
15
def load(cls, smspec_file: str, unsmry_file: str = None) -> Summary:
16
"""
17
Load summary data from files.
18
19
Args:
20
smspec_file (str): Path to SMSPEC file (.SMSPEC)
21
unsmry_file (str, optional): Path to UNSMRY file (.UNSMRY)
22
If None, inferred from smspec_file
23
24
Returns:
25
Summary: Loaded summary data
26
"""
27
28
@classmethod
29
def writer(cls, start_time: datetime, nx: int, ny: int, nz: int) -> Summary:
30
"""Create summary writer for new data."""
31
32
@classmethod
33
def restart_writer(cls, filename: str, start_time: datetime) -> Summary:
34
"""Create restart summary writer."""
35
36
@classmethod
37
def from_pandas(cls, df: pandas.DataFrame, start_time: datetime) -> Summary:
38
"""Create summary from pandas DataFrame."""
39
40
def add_variable(self, key: str, num: int = 0, wgname: str = ""):
41
"""Add variable to summary."""
42
43
def add_t_step(self, report_step: int, sim_days: float):
44
"""Add time step to summary."""
45
46
def get_vector(self, key: str) -> SummaryVector:
47
"""
48
Get summary vector by key.
49
50
Args:
51
key (str): Summary vector key (e.g., 'FOPT', 'WOPT:PROD01')
52
53
Returns:
54
SummaryVector: Time series data vector
55
"""
56
57
def get_values(self, key: str) -> numpy.ndarray:
58
"""Get values array for key."""
59
60
def numpy_vector(self, key: str) -> numpy.ndarray:
61
"""Get numpy array of values."""
62
63
def numpy_dates(self) -> numpy.ndarray:
64
"""Get numpy array of dates."""
65
66
def dates(self) -> list:
67
"""Get list of datetime objects."""
68
69
def report_dates(self) -> list:
70
"""Get list of report dates."""
71
72
def pandas_frame(self, column_keys: list = None) -> pandas.DataFrame:
73
"""
74
Export to pandas DataFrame.
75
76
Args:
77
column_keys (list, optional): Keys to include. If None, includes all.
78
79
Returns:
80
pandas.DataFrame: Summary data with dates as index
81
"""
82
83
def get_key_index(self, key: str) -> int:
84
"""Get index of summary key."""
85
86
def last_value(self, key: str) -> float:
87
"""Get last value for key."""
88
89
def first_value(self, key: str) -> float:
90
"""Get first value for key."""
91
92
def wells(self) -> list:
93
"""Get list of well names."""
94
95
def groups(self) -> list:
96
"""Get list of group names."""
97
98
def report_index_list(self) -> list:
99
"""Get list of report indices."""
100
```
101
102
### Summary Vector Operations
103
104
Individual time series vector with interpolation and analysis capabilities.
105
106
```python { .api }
107
class SummaryVector:
108
"""Individual summary time series vector."""
109
110
def get_name(self) -> str:
111
"""Get vector name/key."""
112
113
def is_total(self) -> bool:
114
"""Check if vector represents cumulative data."""
115
116
def is_rate(self) -> bool:
117
"""Check if vector represents rate data."""
118
119
def get_num_observations(self) -> int:
120
"""Get number of data points."""
121
122
def days_start(self) -> float:
123
"""Get simulation start day."""
124
125
def sim_length_days(self) -> float:
126
"""Get simulation length in days."""
127
128
def first_day(self) -> datetime:
129
"""Get first date."""
130
131
def last_day(self) -> datetime:
132
"""Get last date."""
133
134
def first_value(self) -> float:
135
"""Get first value."""
136
137
def last_value(self) -> float:
138
"""Get last value."""
139
140
def sum(self) -> float:
141
"""Sum all values."""
142
143
def get_interp(self, time: datetime) -> float:
144
"""
145
Interpolate value at specific time.
146
147
Args:
148
time (datetime): Time for interpolation
149
150
Returns:
151
float: Interpolated value
152
"""
153
154
def get_interp_vector(self, time_points: list) -> numpy.ndarray:
155
"""
156
Interpolate values at multiple times.
157
158
Args:
159
time_points (list): List of datetime objects
160
161
Returns:
162
numpy.ndarray: Interpolated values
163
"""
164
```
165
166
### Summary Node Metadata
167
168
Metadata container for summary variables providing variable information.
169
170
```python { .api }
171
class SummaryNode:
172
"""Summary node metadata and properties."""
173
174
@property
175
def key(self) -> str:
176
"""Summary key string."""
177
178
@property
179
def var_type(self) -> SummaryVarType:
180
"""Variable type (FIELD, WELL, GROUP, etc.)."""
181
182
@property
183
def is_rate(self) -> bool:
184
"""True if rate variable."""
185
186
@property
187
def is_total(self) -> bool:
188
"""True if cumulative variable."""
189
190
@property
191
def unit(self) -> str:
192
"""Variable unit string."""
193
194
@property
195
def keyword(self) -> str:
196
"""Base keyword (e.g., 'WOPT' from 'WOPT:PROD01')."""
197
198
@property
199
def wgname(self) -> str:
200
"""Well/group name if applicable."""
201
202
@property
203
def num(self) -> int:
204
"""Numeric identifier if applicable."""
205
```
206
207
### Time Step Data
208
209
Container for time step information and simulation time mapping.
210
211
```python { .api }
212
class SummaryTStep:
213
"""Time step data container."""
214
215
def get_sim_time(self) -> float:
216
"""Get simulation time in days."""
217
218
def get_report(self) -> int:
219
"""Get report step number."""
220
221
def get_mini_step(self) -> int:
222
"""Get mini step number."""
223
224
def datetime(self) -> datetime:
225
"""Get datetime object."""
226
```
227
228
### Keyword Collections
229
230
Collection management for summary keywords and variable organization.
231
232
```python { .api }
233
class SummaryKeyWordVector:
234
"""Collection of summary keywords."""
235
236
def add_keyword(self, keyword: str):
237
"""Add keyword to collection."""
238
239
def get_keyword(self, index: int) -> str:
240
"""Get keyword by index."""
241
242
def size(self) -> int:
243
"""Get number of keywords."""
244
```
245
246
### Economic Analysis
247
248
Net Present Value (NPV) calculations and economic analysis tools.
249
250
```python { .api }
251
class ResdataNPV:
252
"""Net Present Value calculations."""
253
254
def add_price_vector(self, key: str, price_vector: NPVPriceVector):
255
"""
256
Add price vector for economic variable.
257
258
Args:
259
key (str): Summary key (e.g., 'FOPT')
260
price_vector (NPVPriceVector): Price schedule
261
"""
262
263
def npv_vector(self, key: str) -> SummaryVector:
264
"""Get NPV vector for key."""
265
266
def npv(self, key: str) -> float:
267
"""Get total NPV for key."""
268
269
class NPVPriceVector:
270
"""Price vector for NPV calculations."""
271
272
def __init__(self):
273
"""Create empty price vector."""
274
275
def add_price(self, date: datetime, price: float):
276
"""Add price point."""
277
```
278
279
### Data Comparison
280
281
Comparison operations between different summary cases.
282
283
```python { .api }
284
class ResdataCmp:
285
"""Comparison operations between summary cases."""
286
287
def add_case(self, case_name: str, summary: Summary):
288
"""Add case for comparison."""
289
290
def get_difference(self, key: str, case1: str, case2: str) -> SummaryVector:
291
"""Get difference between cases."""
292
```
293
294
## Usage Examples
295
296
### Basic Summary Analysis
297
298
```python
299
from resdata.summary import Summary
300
import matplotlib.pyplot as plt
301
302
# Load summary data
303
summary = Summary.load("SIMULATION.SMSPEC", "SIMULATION.UNSMRY")
304
305
# Get basic information
306
print(f"Wells: {summary.wells()}")
307
print(f"Groups: {summary.groups()}")
308
print(f"Simulation period: {summary.dates()[0]} to {summary.dates()[-1]}")
309
310
# Get field oil production total
311
fopt = summary.get_vector("FOPT")
312
print(f"Final field oil production: {fopt.last_value():.0f} m³")
313
314
# Get field oil production rate
315
fopr = summary.get_vector("FOPR")
316
print(f"Peak oil rate: {max(fopr.numpy_vector()):.1f} m³/day")
317
318
# Plot production profile
319
dates = summary.dates()
320
fopt_data = fopt.numpy_vector()
321
322
plt.figure(figsize=(10, 6))
323
plt.plot(dates, fopt_data, 'b-', linewidth=2)
324
plt.xlabel('Date')
325
plt.ylabel('Cumulative Oil Production (m³)')
326
plt.title('Field Oil Production')
327
plt.grid(True)
328
plt.show()
329
```
330
331
### Well Performance Analysis
332
333
```python
334
from resdata.summary import Summary
335
import numpy as np
336
337
summary = Summary.load("SIMULATION.SMSPEC")
338
339
# Analyze well performance
340
wells = summary.wells()
341
well_performance = {}
342
343
for well in wells:
344
# Get well oil production total
345
wopt_key = f"WOPT:{well}"
346
if summary.get_key_index(wopt_key) >= 0:
347
wopt = summary.get_vector(wopt_key)
348
349
# Get well water cut
350
wwct_key = f"WWCT:{well}"
351
if summary.get_key_index(wwct_key) >= 0:
352
wwct = summary.get_vector(wwct_key)
353
final_wcut = wwct.last_value()
354
else:
355
final_wcut = 0.0
356
357
well_performance[well] = {
358
'total_oil': wopt.last_value(),
359
'final_water_cut': final_wcut,
360
'active_days': wopt.sim_length_days()
361
}
362
363
# Sort wells by oil production
364
sorted_wells = sorted(well_performance.items(),
365
key=lambda x: x[1]['total_oil'], reverse=True)
366
367
print("Well Performance Ranking:")
368
for i, (well, perf) in enumerate(sorted_wells[:10], 1):
369
print(f"{i:2d}. {well:10s}: {perf['total_oil']:8.0f} m³ oil, "
370
f"{perf['final_water_cut']*100:5.1f}% water cut")
371
```
372
373
### Economic Analysis
374
375
```python
376
from resdata.summary import Summary, ResdataNPV, NPVPriceVector
377
from datetime import datetime
378
379
# Load summary
380
summary = Summary.load("SIMULATION.SMSPEC")
381
382
# Create NPV calculator
383
npv_calc = ResdataNPV()
384
385
# Set up oil price schedule
386
oil_price = NPVPriceVector()
387
oil_price.add_price(datetime(2020, 1, 1), 60.0) # $60/barrel
388
oil_price.add_price(datetime(2021, 1, 1), 70.0) # $70/barrel
389
oil_price.add_price(datetime(2022, 1, 1), 80.0) # $80/barrel
390
391
# Set up operating cost
392
opex = NPVPriceVector()
393
opex.add_price(datetime(2020, 1, 1), -20.0) # $20/barrel operating cost
394
395
# Add to NPV calculation
396
npv_calc.add_price_vector("FOPT", oil_price) # Field oil production
397
npv_calc.add_price_vector("FOPT", opex) # Operating costs
398
399
# Calculate NPV
400
total_npv = npv_calc.npv("FOPT")
401
print(f"Project NPV: ${total_npv:,.0f}")
402
403
# Get NPV time series
404
npv_vector = npv_calc.npv_vector("FOPT")
405
npv_data = npv_vector.numpy_vector()
406
dates = summary.dates()
407
408
print(f"NPV evolution:")
409
for i in range(0, len(dates), 365): # Annual samples
410
if i < len(npv_data):
411
print(f" {dates[i].year}: ${npv_data[i]:,.0f}")
412
```
413
414
### Data Export and Analysis
415
416
```python
417
from resdata.summary import Summary
418
import pandas as pd
419
420
# Load summary
421
summary = Summary.load("SIMULATION.SMSPEC")
422
423
# Define key metrics
424
keys = [
425
'FOPT', # Field oil production total
426
'FGPT', # Field gas production total
427
'FWPT', # Field water production total
428
'FOPR', # Field oil production rate
429
'FGPR', # Field gas production rate
430
'FWPR', # Field water production rate
431
'FWCT', # Field water cut
432
'FGOR', # Field gas-oil ratio
433
]
434
435
# Export to pandas DataFrame
436
df = summary.pandas_frame(keys)
437
438
# Basic statistics
439
print("Summary Statistics:")
440
print(df.describe())
441
442
# Calculate monthly averages
443
monthly_avg = df.resample('M').mean()
444
print("\nMonthly Averages (last 12 months):")
445
print(monthly_avg.tail(12))
446
447
# Save to CSV
448
df.to_csv("simulation_summary.csv")
449
monthly_avg.to_csv("simulation_monthly_avg.csv")
450
451
# Calculate production efficiency
452
df['Oil_Efficiency'] = df['FOPR'] / df['FOPR'].max()
453
df['Production_Index'] = df['FOPR'] / (df['FWPR'] + 1) # Avoid division by zero
454
455
print(f"\nAverage oil efficiency: {df['Oil_Efficiency'].mean():.3f}")
456
print(f"Final production index: {df['Production_Index'].iloc[-1]:.3f}")
457
```
458
459
### Time Series Interpolation
460
461
```python
462
from resdata.summary import Summary
463
from datetime import datetime, timedelta
464
import numpy as np
465
466
summary = Summary.load("SIMULATION.SMSPEC")
467
468
# Get oil production rate vector
469
fopr = summary.get_vector("FOPR")
470
471
# Create custom time points for interpolation
472
start_date = summary.dates()[0]
473
end_date = summary.dates()[-1]
474
475
# Monthly interpolation points
476
monthly_dates = []
477
current_date = start_date
478
while current_date <= end_date:
479
monthly_dates.append(current_date)
480
# Add one month (approximate)
481
if current_date.month == 12:
482
current_date = current_date.replace(year=current_date.year + 1, month=1)
483
else:
484
current_date = current_date.replace(month=current_date.month + 1)
485
486
# Interpolate values
487
monthly_rates = fopr.get_interp_vector(monthly_dates)
488
489
print("Monthly Oil Production Rates:")
490
for date, rate in zip(monthly_dates, monthly_rates):
491
print(f"{date.strftime('%Y-%m')}: {rate:8.1f} m³/day")
492
493
# Calculate average monthly rate
494
avg_monthly_rate = np.mean(monthly_rates)
495
print(f"\nAverage monthly rate: {avg_monthly_rate:.1f} m³/day")
496
```
497
498
## Types
499
500
```python { .api }
501
# Summary variable types
502
SummaryVarType = Literal[
503
"INVALID", "AQUIFER", "WELL", "REGION", "FIELD", "GROUP",
504
"BLOCK", "CONNECTION", "SEGMENT", "LOCAL_BLOCK",
505
"LOCAL_COMPLETION", "LOCAL_WELL", "NETWORK", "MISC"
506
]
507
508
# Common summary keys (examples)
509
FieldKeys = Literal[
510
"FOPT", # Field Oil Production Total
511
"FGPT", # Field Gas Production Total
512
"FWPT", # Field Water Production Total
513
"FOPR", # Field Oil Production Rate
514
"FGPR", # Field Gas Production Rate
515
"FWPR", # Field Water Production Rate
516
"FWCT", # Field Water Cut
517
"FGOR", # Field Gas-Oil Ratio
518
]
519
520
WellKeys = Literal[
521
"WOPT", # Well Oil Production Total
522
"WGPT", # Well Gas Production Total
523
"WWPT", # Well Water Production Total
524
"WOPR", # Well Oil Production Rate
525
"WGPR", # Well Gas Production Rate
526
"WWPR", # Well Water Production Rate
527
"WWCT", # Well Water Cut
528
"WGOR", # Well Gas-Oil Ratio
529
"WTHP", # Well Tubing Head Pressure
530
"WBHP", # Well Bottom Hole Pressure
531
]
532
533
# Time constants
534
HOURS_PER_DAY: float = 24.0
535
MINUTES_PER_DAY: float = 1440.0
536
SECONDS_PER_DAY: float = 86400.0
537
MUSECONDS_PER_DAY: float = 86400000000.0
538
```