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

grid-operations.mddocs/

0

# Grid Operations

1

2

Comprehensive 3D grid processing and analysis capabilities for reservoir simulation grids. Supports corner-point grids, structured grids, Local Grid Refinement (LGR), and advanced region selection operations.

3

4

## Capabilities

5

6

### Grid Structure and Analysis

7

8

Main grid class providing access to 3D reservoir grid structure, cell properties, and spatial operations.

9

10

```python { .api }

11

class Grid:

12

"""3D reservoir grid operations and analysis."""

13

14

def __init__(self, filename: str):

15

"""

16

Load grid from GRID or EGRID file.

17

18

Args:

19

filename (str): Path to grid file (.GRID or .EGRID)

20

"""

21

22

def save_EGRID(self, filename: str):

23

"""Save grid in EGRID format."""

24

25

def get_name(self) -> str:

26

"""Get grid name."""

27

28

def get_cell_dims(self) -> tuple:

29

"""

30

Get grid dimensions.

31

32

Returns:

33

tuple: (nx, ny, nz) grid dimensions

34

"""

35

36

def get_cell_volume(self, i: int, j: int, k: int) -> float:

37

"""

38

Get cell volume.

39

40

Args:

41

i, j, k (int): Cell indices

42

43

Returns:

44

float: Cell volume in cubic meters

45

"""

46

47

def get_cell_corner(self, i: int, j: int, k: int, corner: int) -> tuple:

48

"""

49

Get cell corner coordinates.

50

51

Args:

52

i, j, k (int): Cell indices

53

corner (int): Corner index (0-7)

54

55

Returns:

56

tuple: (x, y, z) coordinates

57

"""

58

59

def active_index(self, i: int, j: int, k: int) -> int:

60

"""

61

Get active index for cell.

62

63

Args:

64

i, j, k (int): Cell indices

65

66

Returns:

67

int: Active index or -1 if inactive

68

"""

69

70

def global_index(self, i: int, j: int, k: int) -> int:

71

"""Get global index for cell."""

72

73

def get_xyz(self, i: int, j: int, k: int) -> tuple:

74

"""

75

Get cell center coordinates.

76

77

Args:

78

i, j, k (int): Cell indices

79

80

Returns:

81

tuple: (x, y, z) center coordinates

82

"""

83

84

def get_corner_xyz(self, corner: int) -> tuple:

85

"""Get corner coordinates for all cells."""

86

87

def grid_value(self, x: float, y: float, z: float) -> tuple:

88

"""

89

Find cell containing point.

90

91

Args:

92

x, y, z (float): World coordinates

93

94

Returns:

95

tuple: (i, j, k) indices or None if outside

96

"""

97

98

def depth(self, i: int, j: int, k: int) -> float:

99

"""Get cell depth (negative Z)."""

100

101

def cell_invalid(self, i: int, j: int, k: int) -> bool:

102

"""Check if cell is invalid."""

103

104

def cell_valid(self, i: int, j: int, k: int) -> bool:

105

"""Check if cell is valid."""

106

107

def get_active_index(self, i: int, j: int, k: int) -> int:

108

"""Get active index (raises exception if inactive)."""

109

110

def try_get_global_index(self, i: int, j: int, k: int) -> int:

111

"""Try to get global index, returns -1 if invalid."""

112

113

def get_global_index(self, i: int, j: int, k: int) -> int:

114

"""Get global index (raises exception if invalid)."""

115

116

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

117

"""

118

Get IJK indices from global index.

119

120

Args:

121

global_index (int): Global cell index

122

123

Returns:

124

tuple: (i, j, k) indices

125

"""

126

127

def get_xyz_from_ijk(self, i: int, j: int, k: int) -> tuple:

128

"""Get XYZ coordinates from IJK indices."""

129

130

def distance(self, i1: int, j1: int, k1: int, i2: int, j2: int, k2: int) -> float:

131

"""Calculate distance between two cells."""

132

133

def num_active(self) -> int:

134

"""Get number of active cells."""

135

136

def get_num_active(self) -> int:

137

"""Get number of active cells (alias)."""

138

139

def get_num_lgr(self) -> int:

140

"""Get number of Local Grid Refinements."""

141

142

def wells(self) -> list:

143

"""Get list of wells intersecting the grid."""

144

145

def grid_attach(self, lgr_grid):

146

"""Attach Local Grid Refinement."""

147

148

def grid_get_lgr(self, lgr_name: str):

149

"""Get Local Grid Refinement by name."""

150

```

151

152

### Individual Cell Operations

153

154

Access to individual cell properties and metadata.

155

156

```python { .api }

157

class Cell:

158

"""Individual grid cell representation."""

159

160

@property

161

def active(self) -> bool:

162

"""Check if cell is active."""

163

164

@property

165

def i(self) -> int:

166

"""I-index of cell."""

167

168

@property

169

def j(self) -> int:

170

"""J-index of cell."""

171

172

@property

173

def k(self) -> int:

174

"""K-index of cell."""

175

176

@property

177

def global_index(self) -> int:

178

"""Global index of cell."""

179

180

@property

181

def volume(self) -> float:

182

"""Volume of cell."""

183

184

@property

185

def dimensions(self) -> tuple:

186

"""Cell dimensions (dx, dy, dz)."""

187

```

188

189

### Region Selection and Masking

190

191

Advanced region selection capabilities for creating masks based on various criteria.

192

193

```python { .api }

194

class ResdataRegion:

195

"""Region selection and masking operations."""

196

197

def __init__(self, grid: Grid, preselect: bool = True):

198

"""

199

Create region selector.

200

201

Args:

202

grid (Grid): Grid to operate on

203

preselect (bool): Whether to preselect all cells

204

"""

205

206

def select_equal(self, kw: ResdataKW, value: float):

207

"""Select cells where keyword equals value."""

208

209

def select_less(self, kw: ResdataKW, value: float):

210

"""Select cells where keyword is less than value."""

211

212

def select_more(self, kw: ResdataKW, value: float):

213

"""Select cells where keyword is greater than value."""

214

215

def select_in_range(self, kw: ResdataKW, min_value: float, max_value: float):

216

"""Select cells where keyword is in range."""

217

218

def select_active(self):

219

"""Select only active cells."""

220

221

def select_inactive(self):

222

"""Select only inactive cells."""

223

224

def select_small(self, kw: ResdataKW, num_cells: int):

225

"""Select cells with smallest keyword values."""

226

227

def select_large(self, kw: ResdataKW, num_cells: int):

228

"""Select cells with largest keyword values."""

229

230

def select_thin(self, kw: ResdataKW, num_cells: int):

231

"""Select thinnest cells based on keyword."""

232

233

def select_thick(self, kw: ResdataKW, num_cells: int):

234

"""Select thickest cells based on keyword."""

235

236

def select_box(self, i1: int, i2: int, j1: int, j2: int, k1: int, k2: int):

237

"""

238

Select cells in box region.

239

240

Args:

241

i1, i2 (int): I-index range (inclusive)

242

j1, j2 (int): J-index range (inclusive)

243

k1, k2 (int): K-index range (inclusive)

244

"""

245

246

def select_islice(self, i1: int, i2: int):

247

"""Select I-slice of cells."""

248

249

def select_jslice(self, j1: int, j2: int):

250

"""Select J-slice of cells."""

251

252

def select_kslice(self, k1: int, k2: int):

253

"""Select K-slice of cells."""

254

255

def invert(self):

256

"""Invert current selection."""

257

258

def copy(self) -> ResdataRegion:

259

"""Create copy of region."""

260

261

def reset(self):

262

"""Reset selection to all cells."""

263

```

264

265

### Grid Generation Utilities

266

267

Utilities for creating synthetic grids for testing and modeling.

268

269

```python { .api }

270

class GridGenerator:

271

"""Grid generation utilities."""

272

273

@classmethod

274

def create_rectangular(cls, nx: int, ny: int, nz: int,

275

dx: float, dy: float, dz: float) -> Grid:

276

"""

277

Create rectangular grid.

278

279

Args:

280

nx, ny, nz (int): Grid dimensions

281

dx, dy, dz (float): Cell sizes

282

283

Returns:

284

Grid: Generated rectangular grid

285

"""

286

287

@classmethod

288

def create_GRDECL(cls, nx: int, ny: int, nz: int,

289

coord: list, zcorn: list, actnum: list = None) -> Grid:

290

"""

291

Create grid from GRDECL format data.

292

293

Args:

294

nx, ny, nz (int): Grid dimensions

295

coord (list): Coordinate data

296

zcorn (list): Z-corner data

297

actnum (list, optional): Active cell flags

298

299

Returns:

300

Grid: Generated grid

301

"""

302

```

303

304

## Usage Examples

305

306

### Basic Grid Operations

307

308

```python

309

from resdata.grid import Grid

310

311

# Load grid

312

grid = Grid("SIMULATION.EGRID")

313

314

# Get basic information

315

nx, ny, nz = grid.get_cell_dims()

316

print(f"Grid dimensions: {nx} x {ny} x {nz}")

317

print(f"Total cells: {nx * ny * nz}")

318

print(f"Active cells: {grid.num_active()}")

319

320

# Get cell properties

321

i, j, k = 10, 15, 5 # Cell indices

322

if grid.cell_valid(i, j, k):

323

volume = grid.get_cell_volume(i, j, k)

324

x, y, z = grid.get_xyz(i, j, k)

325

depth = grid.depth(i, j, k)

326

327

print(f"Cell ({i},{j},{k}):")

328

print(f" Volume: {volume:.2f} m³")

329

print(f" Center: ({x:.1f}, {y:.1f}, {z:.1f})")

330

print(f" Depth: {depth:.1f} m")

331

```

332

333

### Region Selection

334

335

```python

336

from resdata.grid import Grid, ResdataRegion

337

from resdata.resfile import ResdataFile

338

339

# Load grid and data

340

grid = Grid("SIMULATION.EGRID")

341

restart = ResdataFile("SIMULATION.UNRST")

342

343

# Get keyword data

344

porosity = restart.get_kw("PORO")

345

pressure = restart.get_kw("PRESSURE")

346

347

# Create region selector

348

region = ResdataRegion(grid, preselect=True)

349

350

# Select high porosity cells

351

region.select_more(porosity, 0.2) # Porosity > 20%

352

353

# Further refine: high pressure in high porosity zone

354

region.select_more(pressure, 200.0) # Pressure > 200 bar

355

356

# Select a specific layer

357

layer_region = ResdataRegion(grid, preselect=False)

358

layer_region.select_kslice(10, 10) # Just layer 10

359

360

print(f"High porosity, high pressure cells: {region.active_size()}")

361

print(f"Layer 10 cells: {layer_region.active_size()}")

362

```

363

364

### Working with Cell Data

365

366

```python

367

from resdata.grid import Grid

368

from resdata.resfile import ResdataFile

369

import numpy as np

370

371

# Load data

372

grid = Grid("SIMULATION.EGRID")

373

restart = ResdataFile("SIMULATION.UNRST")

374

375

# Get pressure data

376

pressure_kw = restart.get_kw("PRESSURE")

377

pressure_data = pressure_kw.numpy_copy()

378

379

# Create arrays for analysis

380

nx, ny, nz = grid.get_cell_dims()

381

avg_pressure_by_layer = np.zeros(nz)

382

383

# Calculate average pressure by layer

384

for k in range(nz):

385

layer_pressures = []

386

for j in range(ny):

387

for i in range(nx):

388

if grid.cell_valid(i, j, k):

389

active_idx = grid.active_index(i, j, k)

390

if active_idx >= 0:

391

layer_pressures.append(pressure_data[active_idx])

392

393

if layer_pressures:

394

avg_pressure_by_layer[k] = np.mean(layer_pressures)

395

396

print("Average pressure by layer:")

397

for k, avg_p in enumerate(avg_pressure_by_layer):

398

if avg_p > 0:

399

print(f" Layer {k+1}: {avg_p:.1f} bar")

400

```

401

402

### Grid Generation

403

404

```python

405

from resdata.grid import GridGenerator

406

407

# Create simple rectangular grid

408

grid = GridGenerator.create_rectangular(

409

nx=10, ny=10, nz=5, # 10x10x5 cells

410

dx=100.0, dy=100.0, dz=10.0 # 100m x 100m x 10m cells

411

)

412

413

print(f"Generated grid: {grid.get_cell_dims()}")

414

print(f"Active cells: {grid.num_active()}")

415

416

# Check cell properties

417

volume = grid.get_cell_volume(5, 5, 2) # Middle cell

418

x, y, z = grid.get_xyz(5, 5, 2)

419

print(f"Cell (5,5,2): volume={volume:.0f} m³, center=({x:.0f},{y:.0f},{z:.0f})")

420

```

421

422

### Finding Cells by Location

423

424

```python

425

from resdata.grid import Grid

426

427

grid = Grid("SIMULATION.EGRID")

428

429

# Find cell containing a point

430

x, y, z = 1000.0, 2000.0, -1500.0 # World coordinates

431

cell_ijk = grid.grid_value(x, y, z)

432

433

if cell_ijk:

434

i, j, k = cell_ijk

435

print(f"Point ({x}, {y}, {z}) is in cell ({i}, {j}, {k})")

436

437

# Get cell properties

438

if grid.cell_valid(i, j, k):

439

volume = grid.get_cell_volume(i, j, k)

440

center_x, center_y, center_z = grid.get_xyz(i, j, k)

441

print(f"Cell center: ({center_x:.1f}, {center_y:.1f}, {center_z:.1f})")

442

print(f"Cell volume: {volume:.2f} m³")

443

else:

444

print(f"Point ({x}, {y}, {z}) is outside the grid")

445

```

446

447

## Types

448

449

```python { .api }

450

# Grid dimensions

451

GridDimensions = tuple[int, int, int] # (nx, ny, nz)

452

453

# Cell coordinates

454

CellIndices = tuple[int, int, int] # (i, j, k)

455

WorldCoordinates = tuple[float, float, float] # (x, y, z)

456

457

# Cell properties

458

CellCorners = tuple[tuple[float, float, float], ...] # 8 corner coordinates

459

```