or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

file-operations.mdgeometry-operations.mdgravimetry-subsidence.mdgrid-operations.mdindex.mdrft-plt-data.mdsummary-analysis.mdutilities.mdwell-data.md

summary-analysis.mddocs/

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

```