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

file-operations.mddocs/

0

# File Operations

1

2

Comprehensive file I/O capabilities for reservoir simulation formats including binary Fortran files, keyword data containers, and specialized file readers. ResData supports RESTART, INIT, RFT, Summary, and GRID files in both unified and non-unified, formatted and unformatted variants.

3

4

## Capabilities

5

6

### Binary Fortran File I/O

7

8

Low-level binary Fortran file operations providing the foundation for reading and writing reservoir simulation data files.

9

10

```python { .api }

11

class FortIO:

12

"""Binary Fortran file I/O operations."""

13

14

# Constants

15

READ_MODE: str

16

WRITE_MODE: str

17

READ_AND_WRITE_MODE: str

18

APPEND_MODE: str

19

20

def __init__(self, filename: str, mode: str = READ_MODE):

21

"""

22

Open a Fortran binary file.

23

24

Args:

25

filename (str): Path to the file

26

mode (str): File mode (READ_MODE, WRITE_MODE, etc.)

27

"""

28

29

def close(self):

30

"""Close the file."""

31

32

def get_position(self) -> int:

33

"""Get current file position."""

34

35

def seek(self, position: int):

36

"""Seek to position in file."""

37

38

def truncate(self, position: int):

39

"""Truncate file at position."""

40

41

def filename(self) -> str:

42

"""Get filename."""

43

44

def is_fortran_file(self) -> bool:

45

"""Check if file is a valid Fortran binary file."""

46

47

def free(self):

48

"""Free resources."""

49

50

def openFortIO(filename: str, mode: str = FortIO.READ_MODE):

51

"""

52

Context manager for FortIO operations.

53

54

Args:

55

filename (str): Path to the file

56

mode (str): File mode

57

58

Returns:

59

FortIO: File handle

60

61

Example:

62

with openFortIO("data.bin") as f:

63

# Use f for file operations

64

position = f.get_position()

65

"""

66

```

67

68

### Keyword Data Container

69

70

Container for simulation data keywords with comprehensive data manipulation and arithmetic operations.

71

72

```python { .api }

73

class ResdataKW:

74

"""Container for keyword data with operations."""

75

76

def __init__(self, name: str, data_type: ResDataType, size: int):

77

"""

78

Create a new keyword.

79

80

Args:

81

name (str): Keyword name (max 8 characters)

82

data_type (ResDataType): Data type

83

size (int): Number of elements

84

"""

85

86

def copy(self) -> ResdataKW:

87

"""Create a complete copy."""

88

89

def slice_copy(self, start: int, stop: int) -> ResdataKW:

90

"""Create copy of slice."""

91

92

def sub_copy(self, index_list: list) -> ResdataKW:

93

"""Create copy with selected indices."""

94

95

@classmethod

96

def read_grdecl(cls, file_handle, kw_name: str) -> ResdataKW:

97

"""Read GRDECL format keyword from file."""

98

99

def fread(self, fortio: FortIO):

100

"""Read data from Fortran binary file."""

101

102

def name(self) -> str:

103

"""Get keyword name."""

104

105

def set_name(self, name: str):

106

"""Set keyword name."""

107

108

def resize(self, new_size: int):

109

"""Resize the keyword data array."""

110

111

def get_min_max(self) -> tuple:

112

"""Get (min, max) values."""

113

114

def get_min(self) -> float:

115

"""Get minimum value."""

116

117

def get_max(self) -> float:

118

"""Get maximum value."""

119

120

def type(self) -> ResDataType:

121

"""Get data type."""

122

123

def data_type(self) -> ResDataType:

124

"""Get data type (alias for type())."""

125

126

def header(self) -> tuple:

127

"""Get (name, size, type) header information."""

128

129

def array(self) -> numpy.ndarray:

130

"""Get numpy array view of data."""

131

132

def numpy_view(self) -> numpy.ndarray:

133

"""Get numpy array view (read-only)."""

134

135

def numpy_copy(self) -> numpy.ndarray:

136

"""Get numpy array copy."""

137

138

def fwrite(self, fortio: FortIO):

139

"""Write to Fortran binary file."""

140

141

def write_grdecl(self, file_handle):

142

"""Write in GRDECL format."""

143

144

def fprintf_data(self, file_handle, format_str: str):

145

"""Write formatted data to file."""

146

147

def create_actnum(self) -> ResdataKW:

148

"""Create ACTNUM keyword from this keyword."""

149

150

def fix_uninitialized(self, actnum: ResdataKW):

151

"""Fix uninitialized values using ACTNUM."""

152

153

def first_different(self, other: ResdataKW, offset: int = 0) -> int:

154

"""Find first different element index."""

155

156

def scatter_copy(self, target: ResdataKW, mapping: list):

157

"""Scatter copy using index mapping."""

158

159

def safe_div(self, other: ResdataKW) -> ResdataKW:

160

"""Safe division avoiding division by zero."""

161

162

# Arithmetic operations

163

def add(self, other: ResdataKW):

164

"""In-place addition."""

165

166

def sub(self, other: ResdataKW):

167

"""In-place subtraction."""

168

169

def mul(self, other: ResdataKW):

170

"""In-place multiplication."""

171

172

def div(self, other: ResdataKW):

173

"""In-place division."""

174

175

def assign(self, other: ResdataKW):

176

"""Assign values from another keyword."""

177

178

def apply(self, func):

179

"""Apply function to all elements."""

180

181

def sum(self) -> float:

182

"""Sum all elements."""

183

184

def isqrt(self):

185

"""In-place inverse square root."""

186

187

def add_squared(self, other: ResdataKW):

188

"""Add squared values of other keyword."""

189

190

def equal(self, other: ResdataKW) -> bool:

191

"""Check exact equality."""

192

193

def equal_numeric(self, other: ResdataKW, epsilon: float = 1e-6) -> bool:

194

"""Check numeric equality within tolerance."""

195

```

196

197

### Main File Reader

198

199

High-level file reader for restart format files with keyword selection and filtering capabilities.

200

201

```python { .api }

202

class ResdataFile:

203

"""Main reader for restart format files."""

204

205

def __init__(self, filename: str, flags: int = 0):

206

"""

207

Open a restart format file.

208

209

Args:

210

filename (str): Path to the file

211

flags (int): Optional flags for file opening

212

"""

213

214

def close(self):

215

"""Close the file."""

216

217

def save_kw(self, kw: ResdataKW):

218

"""Save keyword to file."""

219

220

def select_matching_kw(self, pattern: str) -> ResdataFileView:

221

"""Select keywords matching pattern."""

222

223

def select_from_report(self, report_step: int) -> ResdataFileView:

224

"""Select data from specific report step."""

225

226

def select_restart_section(self, report_step: int, occurrence: int = 0) -> ResdataFileView:

227

"""Select restart section."""

228

229

def select_global(self) -> ResdataFileView:

230

"""Select global keywords."""

231

232

def restart_get_kw(self, kw_name: str, report_step: int, occurrence: int = 0) -> ResdataKW:

233

"""Get keyword from restart step."""

234

235

def has_kw(self, kw_name: str) -> bool:

236

"""Check if keyword exists."""

237

238

def num_named_kw(self, kw_name: str) -> int:

239

"""Count occurrences of named keyword."""

240

241

def iget_named_kw(self, kw_name: str, index: int) -> ResdataKW:

242

"""Get named keyword by index."""

243

244

def get_kw(self, kw_name: str, index: int = 0) -> ResdataKW:

245

"""Get keyword by name and index."""

246

247

def replace_kw(self, kw: ResdataKW, kw_name: str, index: int):

248

"""Replace keyword in file."""

249

250

def fwrite_kw(self, kw_name: str, fortio: FortIO, index: int = 0):

251

"""Write keyword to Fortran file."""

252

253

def get_header(self) -> dict:

254

"""Get file header information."""

255

256

def wells(self) -> list:

257

"""Get list of well names."""

258

259

def groups(self) -> list:

260

"""Get list of group names."""

261

262

def openResdataFile(filename: str):

263

"""

264

Context manager for ResdataFile.

265

266

Args:

267

filename (str): Path to the file

268

269

Returns:

270

ResdataFile: File handle

271

272

Example:

273

with openResdataFile("CASE.UNRST") as f:

274

pressure = f.get_kw("PRESSURE")

275

"""

276

```

277

278

### File View Operations

279

280

Filtered view of file data enabling efficient data access and manipulation.

281

282

```python { .api }

283

class ResdataFileView:

284

"""Filtered view into ResdataFile."""

285

286

def get_kw(self, kw_name: str, index: int = 0) -> ResdataKW:

287

"""Get keyword from view."""

288

289

def has_kw(self, kw_name: str) -> bool:

290

"""Check if keyword exists in view."""

291

292

def size(self) -> int:

293

"""Get number of keywords in view."""

294

295

def restart_get_kw(self, kw_name: str, report_step: int) -> ResdataKW:

296

"""Get restart keyword from view."""

297

```

298

299

### 3D Data Operations

300

301

Specialized operations for 3D grid-based data including layered access and spatial operations.

302

303

```python { .api }

304

class Resdata3DKW(ResdataKW):

305

"""3D keyword data operations."""

306

307

def get_xyz(self, grid: Grid) -> tuple:

308

"""Get XYZ coordinates for grid."""

309

310

def get_ijk(self, grid: Grid, global_index: int) -> tuple:

311

"""Get IJK indices from global index."""

312

313

class Resdata3DFile(ResdataFile):

314

"""3D file operations."""

315

316

def get_3d_kw(self, kw_name: str) -> Resdata3DKW:

317

"""Get 3D keyword."""

318

319

class ResdataInitFile(Resdata3DFile):

320

"""INIT file operations."""

321

322

def get_porv(self) -> ResdataKW:

323

"""Get pore volume data."""

324

325

def get_tranx(self) -> ResdataKW:

326

"""Get X-direction transmissibility."""

327

328

def get_trany(self) -> ResdataKW:

329

"""Get Y-direction transmissibility."""

330

331

def get_tranz(self) -> ResdataKW:

332

"""Get Z-direction transmissibility."""

333

334

class ResdataRestartFile(Resdata3DFile):

335

"""Restart file operations."""

336

337

def unified_read(self, report_step: int) -> dict:

338

"""Read unified restart data for step."""

339

340

def time_map(self) -> list:

341

"""Get time mapping for restart steps."""

342

```

343

344

## Usage Examples

345

346

### Reading Restart Files

347

348

```python

349

from resdata.resfile import ResdataFile

350

351

# Open restart file

352

restart = ResdataFile("SIMULATION.UNRST")

353

354

# Get keywords

355

pressure = restart.get_kw("PRESSURE", 0) # First occurrence

356

swat = restart.get_kw("SWAT", 0)

357

358

# Access data as numpy arrays

359

pressure_data = pressure.numpy_copy()

360

water_sat = swat.numpy_copy()

361

362

print(f"Pressure range: {pressure_data.min():.2f} - {pressure_data.max():.2f}")

363

print(f"Water saturation range: {water_sat.min():.3f} - {water_sat.max():.3f}")

364

365

restart.close()

366

```

367

368

### Keyword Arithmetic

369

370

```python

371

from resdata.resfile import ResdataFile, ResdataKW

372

373

restart = ResdataFile("SIMULATION.UNRST")

374

375

# Get oil and water saturations

376

soil = restart.get_kw("SOIL")

377

swat = restart.get_kw("SWAT")

378

379

# Calculate gas saturation (Sg = 1 - So - Sw)

380

sgas = soil.copy()

381

sgas.add(swat) # sgas = soil + swat

382

sgas.mul(-1.0) # sgas = -(soil + swat)

383

sgas.add(1.0) # sgas = 1 - (soil + swat)

384

385

sgas_data = sgas.numpy_copy()

386

print(f"Gas saturation range: {sgas_data.min():.3f} - {sgas_data.max():.3f}")

387

```

388

389

### Working with Binary Files

390

391

```python

392

from resdata.resfile import FortIO, ResdataKW, ResDataType

393

394

# Create and write data

395

with openFortIO("output.bin", FortIO.WRITE_MODE) as f:

396

# Create keyword

397

pressure_kw = ResdataKW("PRESSURE", ResDataType.RD_FLOAT, 1000)

398

399

# Set values

400

pressure_array = pressure_kw.numpy_view()

401

pressure_array[:] = 250.0 # Set all to 250 bar

402

403

# Write to file

404

pressure_kw.fwrite(f)

405

406

# Read data back

407

with openFortIO("output.bin", FortIO.READ_MODE) as f:

408

read_kw = ResdataKW("PRESSURE", ResDataType.RD_FLOAT, 1000)

409

read_kw.fread(f)

410

411

data = read_kw.numpy_copy()

412

print(f"Read {len(data)} pressure values, first value: {data[0]}")

413

```

414

415

## Types

416

417

```python { .api }

418

# Data types

419

class ResDataType:

420

RD_INT: ResDataType # Integer type

421

RD_FLOAT: ResDataType # Single precision float

422

RD_DOUBLE: ResDataType # Double precision float

423

RD_BOOL: ResDataType # Boolean type

424

RD_MESS: ResDataType # Message type

425

RD_CHAR: ResDataType # Character type

426

427

@classmethod

428

def RD_STRING(cls, elem_size: int) -> ResDataType:

429

"""String type with specified element size."""

430

431

def is_int(self) -> bool: ...

432

def is_float(self) -> bool: ...

433

def is_double(self) -> bool: ...

434

def is_bool(self) -> bool: ...

435

def is_char(self) -> bool: ...

436

def is_string(self) -> bool: ...

437

def is_numeric(self) -> bool: ...

438

def is_equal(self, other: ResDataType) -> bool: ...

439

440

# Enumerations

441

ResdataTypeEnum = Literal[

442

"RD_CHAR_TYPE", "RD_FLOAT_TYPE", "RD_DOUBLE_TYPE",

443

"RD_INT_TYPE", "RD_BOOL_TYPE", "RD_MESS_TYPE", "RD_STRING_TYPE"

444

]

445

446

FileType = Literal[

447

"OTHER", "RESTART", "UNIFIED_RESTART", "SUMMARY",

448

"UNIFIED_SUMMARY", "SUMMARY_HEADER", "GRID", "EGRID", "INIT", "RFT", "DATA"

449

]

450

451

FileMode = Literal["DEFAULT", "CLOSE_STREAM", "WRITABLE"]

452

```