grid

The grid module will extract static and dynamic cell properties from a grid (from the output files of reservoir simulators). Each row in a returned dataframe represents one cell.

Typical usage

from res2df import grid, ResdataFiles

resdatafiles = ResdataFiles('MYDATADECK.DATA')
dframe = grid.df(resdatafiles, rstdates='last')

where the API is documented at res2df.grid.df().

Example grid table

I

J

K

X

Y

Z

VOLUME

ZONE

DX

DY

DZ

PERMX

PERMY

PERMZ

MULTX

MULTY

MULTZ

PORO

NTG

TOPS

DEPTH

TRANX

TRANY

TRANZ

MINPVV

MULTPV

MULTX-

MULTY-

MULTZ-

PVTNUM

SATNUM

EQLNUM

FIPNUM

SWCR

SGCR

SWL

SWU

SGU

SWATINIT

PCW

ENDNUM

PORV

33

23

12

462878.51

5935238.80

1696.67

55693.32

LowerReek

155.67

157.75

2.34

872.85

762.13

12.04

1.00

1.00

1.00

0.17

1.00

1695.50

1696.67

2.75

20.80

44.68

0.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

5.00

0.10

0.10

0.10

1.00

0.90

0.52

0.29

1.00

9441.72

28

42

7

463686.47

5932157.60

1665.32

85390.39

MidReek

164.68

145.10

3.79

543.31

500.66

150.98

1.00

1.00

1.00

0.21

1.00

1663.43

1665.32

16.83

24.57

936.74

0.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

3.00

0.10

0.10

0.10

1.00

0.90

0.17

1.38

1.00

17970.08

3

46

10

460477.69

5929629.55

1715.63

51612.48

MidReek

162.53

158.84

2.00

11.17

10.67

2.56

1.00

1.00

1.00

0.10

1.00

1714.64

1715.63

0.22

0.23

143.98

0.00

1.00

1.00

1.00

1.00

1.00

1.00

2.00

4.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

5316.95

40

58

1

466630.07

5930981.02

1746.57

87201.74

UpperReek

162.04

158.67

3.39

18.57

18.20

5.20

1.00

1.00

1.00

0.16

1.00

1744.87

1746.57

0.00

0.41

209.54

0.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

13769.95

1

18

12

457973.31

5933320.14

1707.47

3083.59

LowerReek

162.87

158.88

0.12

1080.20

1092.24

587.32

1.00

1.00

1.00

0.19

1.00

1707.41

1707.47

0.04

0.07

188620.52

0.00

1.00

1.00

1.00

1.00

1.00

1.00

2.00

6.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

588.97

34

18

3

462588.36

5935985.66

1743.73

86129.97

UpperReek

157.82

159.33

3.77

824.81

416.02

7.49

1.00

1.00

1.00

0.15

1.00

1741.85

1743.73

34.85

0.60

72.32

0.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

13159.47

16

33

8

461273.47

5932470.66

1695.74

98164.92

MidReek

159.48

160.87

3.90

3546.26

3705.67

1031.11

1.00

1.00

1.00

0.28

1.00

1693.79

1695.74

84.65

0.69

4601.49

0.00

1.00

1.00

1.00

1.00

1.00

1.00

1.00

3.00

0.10

0.10

0.10

1.00

0.90

0.37

0.28

1.00

27372.72

7

31

1

459824.59

5932016.79

1691.00

90932.57

UpperReek

157.02

161.91

3.45

8.57

8.05

2.40

1.00

1.00

1.00

0.08

1.00

1689.27

1691.00

0.32

0.42

27.87

0.00

1.00

1.00

1.00

1.00

1.00

1.00

2.00

2.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

7239.36

5

42

8

460441.80

5930342.11

1706.57

33530.51

MidReek

161.63

158.73

1.30

8.26

8.77

2.22

1.00

1.00

1.00

0.11

1.00

1705.92

1706.56

0.17

0.19

278.38

0.00

1.00

1.00

1.00

1.00

1.00

1.00

2.00

4.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

3739.00

8

23

4

459334.81

5933199.93

1697.49

78722.27

UpperReek

175.77

156.61

3.35

8.80

9.02

2.29

1.00

1.00

1.00

0.10

1.00

1695.82

1697.49

0.28

0.38

36.92

0.00

1.00

1.00

1.00

1.00

1.00

1.00

2.00

2.00

0.10

0.10

0.10

1.00

0.90

1.00

1.00

7595.92

Alternatively, the same data can be produced as a CSV file using the command line

res2csv grid --help  # Will display some help text
res2csv grid MYDATADECK.DATA --rstdates last --verbose --output grid.csv

Select which vectors to include (INIT and/or restart vectors) with the vectors argument, as in the example:

res2csv grid --verbose MYDATADECK.DATA --vectors PRESSURE PERMX

Example computations on a grid dataframe

Some grid statistic operations are very neatly expressed using Python and Pandas. Some examples (provided that the dframe object is initialized as in the topmost example):

Summation of floating point numbers is difficult for computers, as summing each number in a sequence can lead to accumulation of roundoff errors. This is proven to have an impact on volumetrics computations on a grid. For this, the Python function math.fsum() should always be used.

# Average non-weighted porosity:
dframe["PORO"].mean()

# Bulk volume in Gm3:
math.fsum(dframe["VOLUME"]) / 1e9

# Total pore volume:
math.fsum(dframe["PORV"])

# Average (weighted) porosity:
math.fsum(dframe["PORV"]) / math.fsum(dframe["VOLUME"])

# Apex reservoir (cell centre):
dframe["Z"].min()

# Apex reservoir (topmost cell corner):
dframe["Z_MIN"].min()

Pandas has powerful aggregation operators, and any thinkable statistical measure can be applied to the data. The Pandas groupby() operation can be used to get statistical measures pr. regions. All of the above examples can be rephrased to compute values for every SATNUM, EQLNUM or similar. Example:

# Apex reservoir pr equilibriation zone
In [3]: dframe.groupby(["EQLNUM"])["Z"].min()
Out[3]:
EQLNUM
1.0    1568.876251
2.0    1619.720749
Name: Z, dtype: float64

Zone information

As mentioned in Zone names, if the text file called zones.lyr is found alongside, zone information will automatically be merged into each row based on the K column. This can be used for statistics pr. zone,

# Permeability (arithmetic average) pr. zone
In [4]: dframe.groupby("ZONE")["PERMX"].mean()
Out[4]:
ZONE
LowerReek    979.605462
MidReek      833.304757
UpperReek    545.180473

If you have the layer information in a different file, you need to tell the code the whereabouts of the file:

from res2df import grid, ResdataFiles, common

resdatafiles = ResdataFiles("'MYDATADECK.DATA")
dframe = grid.df(resdatafiles)
# The filename with layers is relative to .DATA file location
# or an absolute path.
subzonemap = res2df.common.parse_zonemapfile("subzones.lyr")
dframe_with_subzones = common.merge_zones(
    dframe, subzonemap, zoneheader="SUBZONE", kname="K"
)

For more control over merging of zones, check the documentation for the function res2df.common.merge_zones() and res2df.common.parse_zonemapfile()

Dynamic data

By adding a restart date, dynamic data for one particular restart date can be added, through the API option rstdates or the command line option --rstdates.

You can write dates in ISO-8601 format, or you can specify first, last or all. If you select all dates, you can choose to have a set of columns for every date, or have the date encoded in a column called DATE, this is controlled via the --stackdates option.

See also the pillars module for an application of the grid data. Calculating volumes of dynamic data (pr. some region parameter) can be obtained from that module as a by-product of the pillar computations.

Generating include files from grid data

If you have loaded grid data into a Pandas frame, some operations are easily performed, scaling porosity, permeability etc. Or remapping some region parameters. Using the res2df.grid.df2res() function these manipulated vectors can be written back as include files.

Say you want to change the FIPNUM, and that FIPNUM 6 should be removed, and set it to FIPNUM 5. This can be accomplished using

from res2df import grid, ResdataFiles, common

resdatafiles = ResdataFiles("'MYDATADECK.DATA")
dframe = grid.df(resdatafiles)

# Change FIPNUM 6 to FIPNUM 5:
rows_to_touch = dframe["FIPNUM"] == 6
dframe.loc[rows_to_touch, "FIPNUM"] = 5

# Write back to new include file, ensure datatype is integer.
grid.df2res(dframe, "FIPNUM", dtype=int, filename="fipnum.inc", resdatafiles=resdatafiles)

This will produce the file fipnum.inc with the contents:

-- Output file printed by res2df.grid 0.17.2
-- at 2023-11-16 9:31:23.318941

FIPNUM
     21*2  19*1  20*2  20*1  20*2  20*1  19*2  21*1  19*2  21*1  18*2
     22*1  18*2  22*1  18*2  22*1  17*2  23*1  16*2  24*1  16*2  24*1
     15*2  25*1  15*2  25*1  15*2  25*1  15*2  25*1  15*2  25*1  14*2
[..snip...]
     39*5  0  94*5  0  148*5  0  2235*5  0  39*5  0  39*5  0  94*5  0
     148*5  0  104*5  0  2130*5  0  39*5  0  39*5  0  94*5  0  148*5
     0  2235*5  0  39*5  0  39*5  0  94*5  0  148*5  0  1195*5
/ -- FIPNUM: 35817 active cells, 35840 total cell count

It is recommended to supply the resdatafiles object to df2res, if not, correct grid size can not be ensured.