Files
ResInsight/ThirdParty/Ert/python/ecl/grid/ecl_grid.py
T
Magne Sjaastad 04091ad77d #4266 Update libecl
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020

Excluded multibuild folder, as this caused git issues
2019-05-09 08:40:32 +02:00

1441 lines
57 KiB
Python

# Copyright (C) 2011 Equinor ASA, Norway.
#
# The file 'ecl_grid.py' is part of ERT - Ensemble based Reservoir Tool.
#
# ERT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.
#
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
# for more details.
"""
Module to load and query ECLIPSE GRID/EGRID files.
The ecl_grid module contains functionality to load and query an
ECLIPSE grid file; it is currently not possible to manipulate or let
alone create a grid with ecl_grid module. The functionality is
implemented in the EclGrid class. The ecl_grid module is a thin
wrapper around the ecl_grid.c implementation from the libecl library.
"""
import ctypes
import warnings
import numpy
import pandas
import sys
import os.path
import math
import itertools
from cwrap import CFILE, BaseCClass, load, open as copen
from ecl import EclPrototype
from ecl.util.util import monkey_the_camel
from ecl.util.util import IntVector
from ecl import EclDataType, EclUnitTypeEnum, EclTypeEnum
from ecl.eclfile import EclKW, FortIO
from ecl.grid import Cell
class EclGrid(BaseCClass):
"""
Class for loading and internalizing ECLIPSE GRID/EGRID files.
"""
TYPE_NAME = "ecl_grid"
_fread_alloc = EclPrototype("void* ecl_grid_load_case__(char*, bool)", bind = False)
_grdecl_create = EclPrototype("ecl_grid_obj ecl_grid_alloc_GRDECL_kw(int, int, int, ecl_kw, ecl_kw, ecl_kw, ecl_kw)", bind = False)
_alloc_rectangular = EclPrototype("ecl_grid_obj ecl_grid_alloc_rectangular(int, int, int, double, double, double, int*)", bind = False)
_exists = EclPrototype("bool ecl_grid_exists(char*)", bind = False)
_get_numbered_lgr = EclPrototype("ecl_grid_ref ecl_grid_get_lgr_from_lgr_nr(ecl_grid, int)")
_get_named_lgr = EclPrototype("ecl_grid_ref ecl_grid_get_lgr(ecl_grid, char*)")
_get_cell_lgr = EclPrototype("ecl_grid_ref ecl_grid_get_cell_lgr1(ecl_grid, int)")
_num_coarse_groups = EclPrototype("int ecl_grid_get_num_coarse_groups(ecl_grid)")
_in_coarse_group1 = EclPrototype("bool ecl_grid_cell_in_coarse_group1(ecl_grid, int)")
_free = EclPrototype("void ecl_grid_free(ecl_grid)")
_get_nx = EclPrototype("int ecl_grid_get_nx(ecl_grid)")
_get_ny = EclPrototype("int ecl_grid_get_ny(ecl_grid)")
_get_nz = EclPrototype("int ecl_grid_get_nz(ecl_grid)")
_get_global_size = EclPrototype("int ecl_grid_get_global_size(ecl_grid)")
_get_active = EclPrototype("int ecl_grid_get_active_size(ecl_grid)")
_get_active_fracture = EclPrototype("int ecl_grid_get_nactive_fracture(ecl_grid)")
_get_name = EclPrototype("char* ecl_grid_get_name(ecl_grid)")
_ijk_valid = EclPrototype("bool ecl_grid_ijk_valid(ecl_grid, int, int, int)")
_get_active_index3 = EclPrototype("int ecl_grid_get_active_index3(ecl_grid, int, int, int)")
_get_global_index3 = EclPrototype("int ecl_grid_get_global_index3(ecl_grid, int, int, int)")
_get_active_index1 = EclPrototype("int ecl_grid_get_active_index1(ecl_grid, int)")
_get_active_fracture_index1 = EclPrototype("int ecl_grid_get_active_fracture_index1(ecl_grid, int)")
_get_global_index1A = EclPrototype("int ecl_grid_get_global_index1A(ecl_grid, int)")
_get_global_index1F = EclPrototype("int ecl_grid_get_global_index1F(ecl_grid, int)")
_get_ijk1 = EclPrototype("void ecl_grid_get_ijk1(ecl_grid, int, int*, int*, int*)")
_get_ijk1A = EclPrototype("void ecl_grid_get_ijk1A(ecl_grid, int, int*, int*, int*)")
_get_xyz3 = EclPrototype("void ecl_grid_get_xyz3(ecl_grid, int, int, int, double*, double*, double*)")
_get_xyz1 = EclPrototype("void ecl_grid_get_xyz1(ecl_grid, int, double*, double*, double*)")
_get_cell_corner_xyz1 = EclPrototype("void ecl_grid_get_cell_corner_xyz1(ecl_grid, int, int, double*, double*, double*)")
_get_corner_xyz = EclPrototype("void ecl_grid_get_corner_xyz(ecl_grid, int, int, int, double*, double*, double*)")
_get_xyz1A = EclPrototype("void ecl_grid_get_xyz1A(ecl_grid, int, double*, double*, double*)")
_get_ij_xy = EclPrototype("bool ecl_grid_get_ij_from_xy(ecl_grid, double, double, int, int*, int*)")
_get_ijk_xyz = EclPrototype("int ecl_grid_get_global_index_from_xyz(ecl_grid, double, double, double, int)")
_cell_contains = EclPrototype("bool ecl_grid_cell_contains_xyz1(ecl_grid, int, double, double, double)")
_cell_regular = EclPrototype("bool ecl_grid_cell_regular1(ecl_grid, int)")
_num_lgr = EclPrototype("int ecl_grid_get_num_lgr(ecl_grid)")
_has_numbered_lgr = EclPrototype("bool ecl_grid_has_lgr_nr(ecl_grid, int)")
_has_named_lgr = EclPrototype("bool ecl_grid_has_lgr(ecl_grid, char*)")
_grid_value = EclPrototype("double ecl_grid_get_property(ecl_grid, ecl_kw, int, int, int)")
_get_cell_volume = EclPrototype("double ecl_grid_get_cell_volume1(ecl_grid, int)")
_get_cell_thickness = EclPrototype("double ecl_grid_get_cell_thickness1(ecl_grid, int)")
_get_cell_dx = EclPrototype("double ecl_grid_get_cell_dx1(ecl_grid, int)")
_get_cell_dy = EclPrototype("double ecl_grid_get_cell_dy1(ecl_grid, int)")
_get_depth = EclPrototype("double ecl_grid_get_cdepth1(ecl_grid, int)")
_fwrite_grdecl = EclPrototype("void ecl_grid_grdecl_fprintf_kw(ecl_grid, ecl_kw, char*, FILE, double)")
_load_column = EclPrototype("void ecl_grid_get_column_property(ecl_grid, ecl_kw, int, int, double_vector)")
_get_top = EclPrototype("double ecl_grid_get_top2(ecl_grid, int, int)")
_get_top1A = EclPrototype("double ecl_grid_get_top1A(ecl_grid, int)")
_get_bottom = EclPrototype("double ecl_grid_get_bottom2(ecl_grid, int, int)")
_locate_depth = EclPrototype("int ecl_grid_locate_depth(ecl_grid, double, int, int)")
_invalid_cell = EclPrototype("bool ecl_grid_cell_invalid1(ecl_grid, int)")
_valid_cell = EclPrototype("bool ecl_grid_cell_valid1(ecl_grid, int)")
_get_distance = EclPrototype("void ecl_grid_get_distance(ecl_grid, int, int, double*, double*, double*)")
_fprintf_grdecl2 = EclPrototype("void ecl_grid_fprintf_grdecl2(ecl_grid, FILE, ecl_unit_enum) ")
_fwrite_GRID2 = EclPrototype("void ecl_grid_fwrite_GRID2(ecl_grid, char*, ecl_unit_enum)")
_fwrite_EGRID2 = EclPrototype("void ecl_grid_fwrite_EGRID2(ecl_grid, char*, ecl_unit_enum)")
_equal = EclPrototype("bool ecl_grid_compare(ecl_grid, ecl_grid, bool, bool)")
_dual_grid = EclPrototype("bool ecl_grid_dual_grid(ecl_grid)")
_init_actnum = EclPrototype("void ecl_grid_init_actnum_data(ecl_grid, int*)")
_compressed_kw_copy = EclPrototype("void ecl_grid_compressed_kw_copy(ecl_grid, ecl_kw, ecl_kw)")
_global_kw_copy = EclPrototype("void ecl_grid_global_kw_copy(ecl_grid, ecl_kw, ecl_kw)")
_create_volume_keyword = EclPrototype("ecl_kw_obj ecl_grid_alloc_volume_kw(ecl_grid, bool)")
_use_mapaxes = EclPrototype("bool ecl_grid_use_mapaxes(ecl_grid)")
_export_coord = EclPrototype("ecl_kw_obj ecl_grid_alloc_coord_kw(ecl_grid)")
_export_zcorn = EclPrototype("ecl_kw_obj ecl_grid_alloc_zcorn_kw(ecl_grid)")
_export_actnum = EclPrototype("ecl_kw_obj ecl_grid_alloc_actnum_kw(ecl_grid)")
_export_mapaxes = EclPrototype("ecl_kw_obj ecl_grid_alloc_mapaxes_kw(ecl_grid)")
_get_unit_system = EclPrototype("ecl_unit_enum ecl_grid_get_unit_system(ecl_grid)")
_export_index_frame = EclPrototype("void ecl_grid_export_index(ecl_grid, int*, int*, bool)")
_export_data_as_int = EclPrototype("void ecl_grid_export_data_as_int(int, int*, ecl_kw, int*)", bind = False)
_export_data_as_double = EclPrototype("void ecl_grid_export_data_as_double(int, int*, ecl_kw, double*)", bind = False)
_export_volume = EclPrototype("void ecl_grid_export_volume(ecl_grid, int, int*, double*)")
_export_position = EclPrototype("void ecl_grid_export_position(ecl_grid, int, int*, double*)")
_export_corners = EclPrototype("void export_corners(ecl_grid, int, int*, double*)")
@classmethod
def load_from_grdecl(cls, filename):
"""Will create a new EclGrid instance from grdecl file.
This function will scan the input file @filename and look for
the keywords required to build a grid. The following keywords
are required:
SPECGRID ZCORN COORD
In addition the function will look for and use the ACTNUM and
MAPAXES keywords if they are found; if ACTNUM is not found all
cells are assumed to be active.
Slightly more exotic grid concepts like dual porosity, NNC
mapping, LGR and coarsened cells will be completely ignored;
if you need such concepts you must have an EGRID file and use
the default EclGrid() constructor - that is also considerably
faster.
"""
if os.path.isfile(filename):
with copen(filename) as f:
specgrid = EclKW.read_grdecl(f, "SPECGRID", ecl_type=EclDataType.ECL_INT, strict=False)
zcorn = EclKW.read_grdecl(f, "ZCORN")
coord = EclKW.read_grdecl(f, "COORD")
try:
actnum = EclKW.read_grdecl(f, "ACTNUM", ecl_type=EclDataType.ECL_INT)
except ValueError:
actnum = None
try:
mapaxes = EclKW.read_grdecl(f, "MAPAXES")
except ValueError:
mapaxes = None
return EclGrid.create(specgrid, zcorn, coord, actnum, mapaxes)
else:
raise IOError("No such file:%s" % filename)
@classmethod
def load_from_file(cls, filename):
"""
Will inspect the @filename argument and create a new EclGrid instance.
"""
if FortIO.isFortranFile(filename):
return EclGrid(filename)
else:
return EclGrid.loadFromGrdecl(filename)
@classmethod
def create(cls, specgrid, zcorn, coord, actnum, mapaxes=None):
"""
Create a new grid instance from existing keywords.
This is a class method which can be used to create an EclGrid
instance based on the EclKW instances @specgrid, @zcorn,
@coord and @actnum. An ECLIPSE EGRID file contains the
SPECGRID, ZCORN, COORD and ACTNUM keywords, so a somewhat
involved way to create a EclGrid instance could be:
file = ecl.EclFile("ECLIPSE.EGRID")
specgrid_kw = file.iget_named_kw("SPECGRID", 0)
zcorn_kw = file.iget_named_kw("ZCORN", 0)
coord_kw = file.iget_named_kw("COORD", 0)
actnum_kw = file.iget_named_kw("ACTNUM", 0)
grid = EclGrid.create(specgrid_kw, zcorn_kw, coord_kw, actnum_kw)
If you are so inclined ...
"""
return cls._grdecl_create(specgrid[0], specgrid[1], specgrid[2], zcorn, coord, actnum, mapaxes)
@classmethod
def create_rectangular(cls, dims, dV, actnum=None):
"""
Will create a new rectangular grid. @dims = (nx,ny,nz) @dVg = (dx,dy,dz)
With the default value @actnum == None all cells will be active,
"""
warnings.warn("EclGrid.createRectangular is deprecated. " +
"Please used the similar method in EclGridGenerator!",
DeprecationWarning)
if actnum is None:
ecl_grid = cls._alloc_rectangular(dims[0], dims[1], dims[2], dV[0], dV[1], dV[2], None)
else:
if not isinstance(actnum, IntVector):
tmp = IntVector(initial_size=len(actnum))
for (index, value) in enumerate(actnum):
tmp[index] = value
actnum = tmp
if not len(actnum) == dims[0] * dims[1] * dims[2]:
raise ValueError("ACTNUM size mismatch: len(ACTNUM):%d Expected:%d" % (len(actnum), dims[0] * dims[1] * dims[2]))
ecl_grid = cls._alloc_rectangular(dims[0], dims[1], dims[2], dV[0], dV[1], dV[2], actnum.getDataPtr())
# If we have not succeeded in creatin the grid we *assume* the
# error is due to a failed malloc.
if ecl_grid is None:
raise MemoryError("Failed to allocated regualar grid")
return ecl_grid
def __init__(self, filename, apply_mapaxes=True):
"""
Will create a grid structure from an EGRID or GRID file.
"""
c_ptr = self._fread_alloc(filename, apply_mapaxes)
if c_ptr:
super(EclGrid, self).__init__(c_ptr)
else:
raise IOError("Loading grid from:%s failed" % filename)
def free(self):
self._free()
def _nicename(self):
"""name is often full path to grid, if so, output basename, else name"""
name = self.getName()
if os.path.isfile(name):
name = os.path.basename(name)
return name
def __repr__(self):
"""Returns, e.g.:
EclGrid("NORNE_ATW2013.EGRID", 46x112x22, global_size=113344, active_size=44431) at 0x28c4a70
"""
name = self._nicename()
if name:
name = '"%s", ' % name
g_size = self.getGlobalSize()
a_size = self.getNumActive()
xyz_s = '%dx%dx%d' % (self.getNX(),self.getNY(),self.getNZ())
return self._create_repr('%s%s, global_size=%d, active_size=%d' % (name, xyz_s, g_size, a_size))
def __len__(self):
"""
len(grid) wil return the total number of cells.
"""
return self._get_global_size()
def equal(self, other, include_lgr=True, include_nnc=False, verbose=False):
"""
Compare the current grid with the other grid.
"""
if not isinstance(other, EclGrid):
raise TypeError("The other argument must be an EclGrid instance")
return self._equal(other, include_lgr, include_nnc, verbose)
def dual_grid(self):
"""Is this grid dual porosity model?"""
return self._dual_grid()
def get_dims(self):
"""A tuple of four elements: (nx, ny, nz, nactive)."""
return (self.getNX(),
self.getNY(),
self.getNZ(),
self.getNumActive())
@property
def nx(self):
return self._get_nx()
def get_nx(self):
""" The number of elements in the x direction"""
return self._get_nx()
@property
def ny(self):
return self._get_ny()
def get_ny(self):
""" The number of elements in the y direction"""
return self._get_ny()
@property
def nz(self):
return self._get_nz()
def get_nz(self):
""" The number of elements in the z direction"""
return self._get_nz()
def get_global_size(self):
"""Returns the total number of cells in this grid"""
return self._get_global_size()
def get_num_active(self):
"""The number of active cells in the grid."""
return self._get_active()
def get_num_active_fracture(self):
"""The number of active cells in the grid."""
return self._get_active_fracture()
def get_bounding_box_2d(self, layer=0, lower_left=None, upper_right=None):
if 0 <= layer <= self.getNZ():
x = ctypes.c_double()
y = ctypes.c_double()
z = ctypes.c_double()
if lower_left is None:
i1 = 0
j1 = 0
else:
i1,j1 = lower_left
if not 0 < i1 < self.getNX():
raise ValueError("lower_left i coordinate invalid")
if not 0 < j1 < self.getNY():
raise ValueError("lower_left j coordinate invalid")
if upper_right is None:
i2 = self.getNX()
j2 = self.getNY()
else:
i2,j2 = upper_right
if not 1 < i2 <= self.getNX():
raise ValueError("upper_right i coordinate invalid")
if not 1 < j2 <= self.getNY():
raise ValueError("upper_right j coordinate invalid")
if not i1 < i2:
raise ValueError("Must have lower_left < upper_right")
if not j1 < j2:
raise ValueError("Must have lower_left < upper_right")
self._get_corner_xyz(i1, j1, layer, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
p0 = (x.value, y.value)
self._get_corner_xyz(i2, j1, layer, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
p1 = (x.value, y.value )
self._get_corner_xyz( i2, j2, layer, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
p2 = (x.value, y.value )
self._get_corner_xyz(i1, j2, layer, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
p3 = (x.value, y.value )
return (p0,p1,p2,p3)
else:
raise ValueError("Invalid layer value:%d Valid range: [0,%d]" % (layer, self.getNZ()))
def get_name(self):
"""
Name of the current grid, returns a string.
For the main grid this is the filename given to the
constructor when loading the grid; for an LGR this is the name
of the LGR. If the grid instance has been created with the
create() classmethod this can be None.
"""
n = self._get_name()
return str(n) if n else ''
def cell(self, global_index=None, active_index=None, i=None, j=None, k=None):
if global_index is not None:
return Cell(self, global_index)
if active_index is not None:
return Cell(self, self.global_index(active_index=active_index))
if i is not None:
return Cell(self, self.global_index(ijk=(i,j,k)))
def __getitem__(self, global_index):
if isinstance(global_index, tuple):
i,j,k = global_index
return self.cell(i=i, j=j, k=k)
return self.cell(global_index=global_index)
def __iter__(self):
for i in range(len(self)):
yield self[i]
def cells(self, active=False):
"""Iterator over all the (active) cells"""
if not active:
for c in self:
yield c
else:
for i in range(self.get_num_active()):
yield self.cell(active_index=i)
def global_index(self, active_index=None, ijk=None):
"""
Will convert either active_index or (i,j,k) to global index.
"""
return self.__global_index(active_index=active_index, ijk=ijk)
def __global_index(self, active_index=None, global_index=None, ijk=None):
"""
Will convert @active_index or @ijk to global_index.
This method will convert @active_index or @ijk to a global
index. Exactly one of the arguments @active_index,
@global_index or @ijk must be supplied.
The method is used extensively internally in the EclGrid
class; most methods which take coordinate input pass through
this method to normalize the coordinate representation.
"""
set_count = 0
if not active_index is None:
set_count += 1
if not global_index is None:
set_count += 1
if ijk:
set_count += 1
if not set_count == 1:
raise ValueError("Exactly one of the kewyord arguments active_index, global_index or ijk must be set")
if not active_index is None:
global_index = self._get_global_index1A( active_index)
elif ijk:
nx = self.getNX()
ny = self.getNY()
nz = self.getNZ()
i,j,k = ijk
if not 0 <= i < nx:
raise IndexError("Invalid value i:%d Range: [%d,%d)" % (i, 0, nx))
if not 0 <= j < ny:
raise IndexError("Invalid value j:%d Range: [%d,%d)" % (j, 0, ny))
if not 0 <= k < nz:
raise IndexError("Invalid value k:%d Range: [%d,%d)" % (k, 0, nz))
global_index = self._get_global_index3(i,j,k)
else:
if not 0 <= global_index < self.getGlobalSize():
raise IndexError("Invalid value global_index:%d Range: [%d,%d)" % (global_index, 0, self.getGlobalSize()))
return global_index
def get_active_index(self, ijk=None, global_index=None):
"""
Lookup active index based on ijk or global index.
Will determine the active_index of a cell, based on either
@ijk = (i,j,k) or @global_index. If the cell specified by the
input arguments is not active the function will return -1.
"""
gi = self.__global_index(global_index=global_index, ijk=ijk)
return self._get_active_index1(gi)
def get_active_fracture_index(self, ijk=None, global_index=None):
"""
For dual porosity - get the active fracture index.
"""
gi = self.__global_index(global_index=global_index, ijk=ijk)
return self._get_active_fracture_index1(gi)
def get_global_index1F(self, active_fracture_index):
"""
Will return the global index corresponding to active fracture index.
"""
return self._get_global_index1F(active_fracture_index)
def cell_invalid(self, ijk=None, global_index=None, active_index=None):
"""
Tries to check if a cell is invalid.
Cells which are used to represent numerical aquifers are
typically located in UTM position (0,0); these cells have
completely whacked up shape and size, and should **NOT** be
used in calculations involving real world coordinates. To
protect against this a heuristic is used identify such cells
and mark them as invalid. There might be other sources than
numerical aquifers to this problem.
"""
gi = self.__global_index(global_index=global_index, ijk=ijk, active_index=active_index)
return self._invalid_cell(gi)
def valid_cell_geometry(self, ijk=None, global_index=None, active_index=None):
"""Checks if the cell has valid geometry.
There are at least two reasons why a cell might have invalid
gemetry:
1. In the case of GRID files it is not necessary to supply
the geometry for all the cells; in that case this
function will return false for cells which do not have
valid coordinates.
2. Cells which are used to represent numerical aquifers are
typically located in UTM position (0,0); these cells have
completely whacked up shape and size; these cells are
identified by a heuristic - which might fail
If the validCellGeometry() returns false for a particular
cell functions which calculate cell volumes, real world
coordinates and so on - should not be used.
"""
gi = self.__global_index(global_index=global_index, ijk=ijk, active_index=active_index)
return self._valid_cell(gi)
def active(self, ijk=None, global_index=None):
"""
Is the cell active?
See documentation og get_xyz() for explanation of parameters
@ijk and @global_index.
"""
gi = self.__global_index(global_index=global_index, ijk=ijk)
active_index = self._get_active_index1(gi)
if active_index >= 0:
return True
else:
return False
def get_global_index(self, ijk=None, active_index=None):
"""
Lookup global index based on ijk or active index.
"""
gi = self.__global_index(active_index=active_index, ijk=ijk)
return gi
def get_ijk(self, active_index=None, global_index=None):
"""
Lookup (i,j,k) for a cell, based on either active index or global index.
The return value is a tuple with three elements (i,j,k).
"""
i = ctypes.c_int()
j = ctypes.c_int()
k = ctypes.c_int()
gi = self.__global_index(active_index=active_index, global_index=global_index)
self._get_ijk1(gi, ctypes.byref(i), ctypes.byref(j), ctypes.byref(k))
return (i.value, j.value, k.value)
def get_xyz(self, active_index=None, global_index=None, ijk=None):
"""
Find true position of cell center.
Will return world position of the center of a cell in the
grid. The return value is a tuple of three elements:
(utm_x, utm_y, depth).
The cells of a grid can be specified in three different ways:
(i,j,k) : As a tuple of i,j,k values.
global_index : A number in the range [0,nx*ny*nz). The
global index is related to (i,j,k) as:
global_index = i + j*nx + k*nx*ny
active_index : A number in the range [0,nactive).
For many of the EclGrid methods a cell can be specified using
any of these three methods. Observe that one and only method is
allowed:
OK:
pos1 = grid.get_xyz(active_index=100)
pos2 = grid.get_xyz(ijk=(10,20,7))
Crash and burn:
pos3 = grid.get_xyz(ijk=(10,20,7), global_index=10)
pos4 = grid.get_xyz()
All the indices in the EclGrid() class are zero offset, this
is in contrast to ECLIPSE which has an offset 1 interface.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
x = ctypes.c_double()
y = ctypes.c_double()
z = ctypes.c_double()
self._get_xyz1(gi, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
return (x.value, y.value, z.value)
def get_node_pos(self, i, j, k):
"""Will return the (x,y,z) for the node given by (i,j,k).
Observe that this method does not consider cells, but the
nodes in the grid. This means that the valid input range for
i,j and k are are upper end inclusive. To get the four
bounding points of the lower layer of the grid:
p0 = grid.getNodePos(0, 0, 0)
p1 = grid.getNodePos(grid.getNX(), 0, 0)
p2 = grid.getNodePos(0, grid.getNY(), 0)
p3 = grid.getNodePos(grid.getNX(), grid.getNY(), 0)
"""
if not 0 <= i <= self.getNX():
raise IndexError("Invalid I value:%d - valid range: [0,%d]" % (i, self.getNX()))
if not 0 <= j <= self.getNY():
raise IndexError("Invalid J value:%d - valid range: [0,%d]" % (j, self.getNY()))
if not 0 <= k <= self.getNZ():
raise IndexError("Invalid K value:%d - valid range: [0,%d]" % (k, self.getNZ()))
x = ctypes.c_double()
y = ctypes.c_double()
z = ctypes.c_double()
self._get_corner_xyz(i,j,k, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
return (x.value, y.value, z.value)
def get_cell_corner(self, corner_nr, active_index=None, global_index=None, ijk=None):
"""
Will look up xyz of corner nr @corner_nr
lower layer: upper layer
2---3 6---7
| | | |
0---1 4---5
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
x = ctypes.c_double()
y = ctypes.c_double()
z = ctypes.c_double()
self._get_cell_corner_xyz1(gi, corner_nr, ctypes.byref(x), ctypes.byref(y), ctypes.byref(z))
return (x.value, y.value, z.value)
def get_node_xyz(self, i,j,k):
"""
This function returns the position of Vertex (i,j,k).
The coordinates are in the inclusive interval [0,nx] x [0,ny] x [0,nz].
"""
nx = self.getNX()
ny = self.getNY()
nz = self.getNZ()
corner = 0
if i == nx:
i -= 1
corner += 1
if j == ny:
j -= 1
corner += 2
if k == nz:
k -= 1
corner += 4
if self._ijk_valid(i, j, k):
return self.getCellCorner(corner, global_index=i + j*nx + k*nx*ny)
else:
raise IndexError("Invalid coordinates: (%d,%d,%d) " % (i,j,k))
def get_layer_xyz(self, xy_corner, layer):
nx = self.getNX()
(j, i) = divmod(xy_corner, nx + 1)
k = layer
return self.getNodeXYZ(i,j,k)
def distance(self, global_index1, global_index2):
dx = ctypes.c_double()
dy = ctypes.c_double()
dz = ctypes.c_double()
self._get_distance(global_index1, global_index2, ctypes.byref(dx), ctypes.byref(dy), ctypes.byref(dz))
return (dx.value, dy.value, dz.value)
def depth(self, active_index=None, global_index=None, ijk=None):
"""
Depth of the center of a cell.
Returns the depth of the center of the cell given by
@active_index, @global_index or @ijk. See method get_xyz() for
documentation of @active_index, @global_index and @ijk.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
return self._get_depth( gi)
def top(self, i, j):
"""
Top of the reservoir; in the column (@i, @j).
Returns average depth of the four top corners.
"""
return self._get_top(i, j)
def top_active(self, i, j):
"""
Top of the active part of the reservoir; in the column (@i, @j).
Raises ValueError if (i,j) column is inactive.
"""
for k in range(self.getNZ()):
a_idx = self.get_active_index(ijk=(i,j,k))
if a_idx >= 0:
return self._get_top1A(a_idx)
raise ValueError('No active cell in column (%d,%d)' % (i,j))
def bottom(self, i, j):
"""
Bottom of the reservoir; in the column (@i, @j).
"""
return self._get_bottom( i, j)
def locate_depth(self, depth, i, j):
"""
Will locate the k value of cell containing specified depth.
Will scan through the grid column specified by the input
arguments @i and @j and search for a cell containing the depth
given by input argument @depth. The return value is the k
value of cell containing @depth.
If @depth is above the top of the reservoir the function will
return -1, and if @depth is below the bottom of the reservoir
the function will return -nz.
"""
return self._locate_depth( depth, i, j)
def find_cell(self, x, y, z, start_ijk=None):
"""
Lookup cell containg true position (x,y,z).
Will locate the cell in the grid which contains the true
position (@x,@y,@z), the return value is as a triplet
(i,j,k). The underlying C implementation is not veeery
efficient, and can potentially take quite long time. If you
provide a good intial guess with the parameter @start_ijk (a
tuple (i,j,k)) things can speed up quite substantially.
If the location (@x,@y,@z) can not be found in the grid, the
method will return None.
"""
start_index = 0
if start_ijk:
start_index = self.__global_index(ijk=start_ijk)
global_index = self._get_ijk_xyz(x, y, z, start_index)
if global_index >= 0:
i = ctypes.c_int()
j = ctypes.c_int()
k = ctypes.c_int()
self._get_ijk1(global_index,
ctypes.byref(i), ctypes.byref(j), ctypes.byref(k))
return (i.value, j.value, k.value)
return None
def cell_contains(self, x, y, z, active_index=None, global_index=None, ijk=None):
"""
Will check if the cell contains point given by world
coordinates (x,y,z).
See method get_xyz() for documentation of @active_index,
@global_index and @ijk.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
return self._cell_contains(gi, x,y,z)
def find_cell_xy(self, x, y, k):
"""Will find the i,j of cell with utm coordinates x,y.
The @k input is the layer you are interested in, the allowed
values for k are [0,nz]. If the coordinates (x,y) are found to
be outside the grid a ValueError exception is raised.
"""
if 0 <= k <= self.getNZ():
i = ctypes.c_int()
j = ctypes.c_int()
ok = self._get_ij_xy(x,y,k, ctypes.byref(i), ctypes.byref(j))
if ok:
return (i.value, j.value)
else:
raise ValueError("Could not find the point:(%g,%g) in layer:%d" % (x,y,k))
else:
raise IndexError("Invalid layer value:%d" % k)
def find_cell_corner_xy(self, x, y, k):
"""Will find the corner nr of corner closest to utm coordinates x,y.
The @k input is the layer you are interested in, the allowed
values for k are [0,nz]. If the coordinates (x,y) are found to
be outside the grid a ValueError exception is raised.
"""
i,j = self.findCellXY(x,y,k)
if k == self.getNZ():
k -= 1
corner_shift = 4
else:
corner_shift = 0
nx = self.getNX()
x0,y0,z0 = self.getCellCorner(corner_shift, ijk=(i,j,k))
d0 = math.sqrt((x0 - x)*(x0 - x) + (y0 - y)*(y0 - y))
c0 = i + j*(nx + 1)
x1,y1,z1 = self.getCellCorner(1 + corner_shift, ijk=(i,j,k))
d1 = math.sqrt((x1 - x)*(x1 - x) + (y1 - y)*(y1 - y))
c1 = i + 1 + j*(nx + 1)
x2,y2,z2 = self.getCellCorner(2 + corner_shift, ijk=(i,j,k))
d2 = math.sqrt((x2 - x)*(x2 - x) + (y2 - y)*(y2 - y))
c2 = i + (j + 1)*(nx + 1)
x3,y3,z3 = self.getCellCorner(3 + corner_shift, ijk=(i,j,k))
d3 = math.sqrt((x3 - x)*(x3 - x) + (y3 - y)*(y3 - y))
c3 = i + 1 + (j + 1)*(nx + 1)
l = [(d0, c0), (d1,c1), (d2, c2), (d3,c3)]
l.sort(key=lambda k: k[0])
return l[0][1]
def cell_regular(self, active_index=None, global_index=None, ijk=None):
"""
The ECLIPSE grid models often contain various degenerate cells,
which are twisted, have overlapping corners or what not. This
function gives a moderate sanity check on a cell, essentially
what the function does is to check if the cell contains it's
own centerpoint - which is actually not as trivial as it
sounds.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
return self._cell_regular( gi)
def cell_volume(self, active_index=None, global_index=None, ijk=None):
"""
Calculate the volume of a cell.
Will calculate the total volume of the cell. See method
get_xyz() for documentation of @active_index, @global_index
and @ijk.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
return self._get_cell_volume(gi)
def cell_dz(self, active_index=None, global_index=None, ijk=None):
"""
The thickness of a cell.
Will calculate the (average) thickness of the cell. See method
get_xyz() for documentation of @active_index, @global_index
and @ijk.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
return self._get_cell_thickness( gi)
def get_cell_dims(self, active_index=None, global_index=None, ijk=None):
"""Will return a tuple (dx,dy,dz) for cell dimension.
The dx and dy values are best effor estimates of the cell size
along the i and j directions respectively. The three values
are guaranteed to satisfy:
dx * dy * dz = dV
See method get_xyz() for documentation of @active_index,
@global_index and @ijk.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
dx = self._get_cell_dx(gi)
dy = self._get_cell_dy(gi)
dz = self._get_cell_thickness( gi)
return (dx,dy,dz)
def get_num_lgr(self):
"""
How many LGRs are attached to this main grid?
How many LGRs are attached to this main grid; the grid
instance doing the query must itself be a main grid.
"""
return self._num_lgr()
def has_lgr(self, lgr_name):
"""
Query if the grid has an LGR with name @lgr_name.
"""
if self._has_named_lgr(lgr_name):
return True
else:
return False
def get_lgr(self, lgr_key):
"""Get EclGrid instance with LGR content.
Return an EclGrid instance based on the LGR @lgr, the input
argument can either be the name of an LGR or the grid number
of the LGR. The LGR grid instance is mostly like an ordinary
grid instance; the only difference is that it can not be used
for further queries about LGRs.
If the grid does not contain an LGR with this name/nr
exception KeyError will be raised.
"""
lgr = None
if isinstance(lgr_key, int):
if self._has_numbered_lgr(lgr_key):
lgr = self._get_numbered_lgr(lgr_key)
else:
if self._has_named_lgr(lgr_key):
lgr = self._get_named_lgr(lgr_key)
if lgr is None:
raise KeyError("No such LGR: %s" % lgr_key)
lgr.setParent(self)
return lgr
def get_cell_lgr(self, active_index=None, global_index=None, ijk=None):
"""
Get EclGrid instance located in cell.
Will query the current grid instance if the cell given by
@active_index, @global_index or @ijk has been refined with an
LGR. Will return None if the cell in question has not been
refined, the return value can be used for further queries.
See get_xyz() for documentation of the input parameters.
"""
gi = self.__global_index(ijk=ijk, active_index=active_index, global_index=global_index)
lgr = self._get_cell_lgr(gi)
if lgr:
lgr.setParent(self)
return lgr
else:
raise IndexError("No LGR defined for this cell")
def grid_value(self, kw, i, j, k):
"""
Will evalute @kw in location (@i,@j,@k).
The ECLIPSE properties and solution vectors are stored in
restart and init files as 1D vectors of length nx*nx*nz or
nactive. The grid_value() method is a minor convenience
function to convert the (@i,@j,@k) input values to an
appropriate 1D index.
Depending on the length of kw the input arguments are
converted either to an active index or to a global index. If
the length of kw does not fit with either the global size of
the grid or the active size of the grid things will fail hard.
"""
return self._grid_value(kw, i, j, k)
def load_column(self, kw, i, j, column):
"""
Load the values of @kw from the column specified by (@i,@j).
The method will scan through all k values of the input field
@kw for fixed values of i and j. The size of @kw must be
either nactive or nx*ny*nz.
The input argument @column should be a DoubleVector instance,
observe that if size of @kw == nactive k values corresponding
to inactive cells will not be modified in the @column
instance; in that case it is important that @column is
initialized with a suitable default value.
"""
self._load_column( kw, i, j, column)
def create_kw(self, array, kw_name, pack):
"""
Creates an EclKW instance based on existing 3D numpy object.
The method create3D() does the inverse operation; creating a
3D numpy object from an EclKW instance. If the argument @pack
is true the resulting keyword will have length 'nactive',
otherwise the element will have length nx*ny*nz.
"""
if array.ndim == 3:
dims = array.shape
if dims[0] == self.getNX() and dims[1] == self.getNY() and dims[2] == self.getNZ():
dtype = array.dtype
if dtype == numpy.int32:
type = EclDataType.ECL_INT
elif dtype == numpy.float32:
type = EclDataType.ECL_FLOAT
elif dtype == numpy.float64:
type = EclDataType.ECL_DOUBLE
else:
sys.exit("Do not know how to create ecl_kw from type:%s" % dtype)
if pack:
size = self.getNumActive()
else:
size = self.getGlobalSize()
if len(kw_name) > 8:
# Silently truncate to length 8 - ECLIPSE has it's challenges.
kw_name = kw_name[0:8]
kw = EclKW(kw_name, size, type)
active_index = 0
global_index = 0
for k in range(self.getNZ()):
for j in range(self.getNY()):
for i in range(self.getNX()):
if pack:
if self.active(global_index=global_index):
kw[active_index] = array[i,j,k]
active_index += 1
else:
if dtype == numpy.int32:
kw[global_index] = int(array[i,j,k])
else:
kw[global_index] = array[i,j,k]
global_index += 1
return kw
raise ValueError("Wrong size / dimension on array")
def coarse_groups(self):
"""
Will return the number of coarse groups in this grid.
"""
return self._num_coarse_groups()
def in_coarse_group(self, global_index=None, ijk=None, active_index=None):
"""
Will return True or False if the cell is part of coarse group.
"""
global_index = self.__global_index(active_index=active_index, ijk=ijk, global_index=global_index)
return self._in_coarse_group1(global_index)
def create_3d(self, ecl_kw, default = 0):
"""
Creates a 3D numpy array object with the data from @ecl_kw.
Observe that 3D numpy object is a copy of the data in the
EclKW instance, i.e. modification to the numpy object will not
be reflected in the ECLIPSE keyword.
The methods createKW() does the inverse operation; creating an
EclKW instance from a 3D numpy object.
Alternative: Creating the numpy array object is not very
efficient; if you only need a limited number of elements from
the ecl_kw instance it might be wiser to use the grid_value()
method:
value = grid.grid_value(ecl_kw, i, j, k)
"""
if len(ecl_kw) == self.getNumActive() or len(ecl_kw) == self.getGlobalSize():
array = numpy.ones([ self.getGlobalSize() ], dtype=ecl_kw.dtype) * default
kwa = ecl_kw.array
if len(ecl_kw) == self.getGlobalSize():
for i in range(kwa.size):
array[i] = kwa[i]
else:
data_index = 0
for global_index in range(self.getGlobalSize()):
if self.active(global_index=global_index):
array[global_index] = kwa[data_index]
data_index += 1
array = array.reshape([self.getNX(), self.getNY(), self.getNZ()], order='F')
return array
else:
err_msg_fmt = 'Keyword "%s" has invalid size %d; must be either nactive=%d or nx*ny*nz=%d'
err_msg = err_msg_fmt % (ecl_kw, len(ecl_kw), self.getNumActive(),
self.getGlobalSize())
raise ValueError(err_msg)
def save_grdecl(self, pyfile, output_unit=EclUnitTypeEnum.ECL_METRIC_UNITS):
"""
Will write the the grid content as grdecl formatted keywords.
Will only write the main grid.
"""
cfile = CFILE(pyfile)
self._fprintf_grdecl2(cfile, output_unit)
def save_EGRID(self, filename, output_unit=None):
if output_unit is None:
output_unit = self.unit_system
self._fwrite_EGRID2(filename, output_unit)
def save_GRID(self, filename, output_unit=EclUnitTypeEnum.ECL_METRIC_UNITS):
"""
Will save the current grid as a GRID file.
"""
self._fwrite_GRID2( filename, output_unit)
def write_grdecl(self, ecl_kw, pyfile, special_header=None, default_value=0):
"""
Writes an EclKW instance as an ECLIPSE grdecl formatted file.
The input argument @ecl_kw must be an EclKW instance of size
nactive or nx*ny*nz. If the size is nactive the inactive cells
will be filled with @default_value; hence the function will
always write nx*ny*nz elements.
The data in the @ecl_kw argument can be of type integer,
float, double or bool. In the case of bool the default value
must be specified as 1 (True) or 0 (False).
The input argument @pyfile should be a valid python filehandle
opened for writing; i.e.
pyfile = open("PORO.GRDECL", "w")
grid.write_grdecl(poro_kw , pyfile, default_value=0.0)
grid.write_grdecl(permx_kw, pyfile, default_value=0.0)
pyfile.close()
"""
if len(ecl_kw) == self.getNumActive() or len(ecl_kw) == self.getGlobalSize():
cfile = CFILE(pyfile)
self._fwrite_grdecl(ecl_kw, special_header, cfile, default_value)
else:
raise ValueError("Keyword: %s has invalid size(%d), must be either nactive:%d or nx*ny*nz:%d" % (ecl_kw.getName(), len(ecl_kw), self.getNumActive(), self.getGlobalSize()))
def exportACTNUM(self):
actnum = IntVector(initial_size=self.getGlobalSize())
self._init_actnum(actnum.getDataPtr())
return actnum
def compressed_kw_copy(self, kw):
if len(kw) == self.getNumActive():
return kw.copy()
elif len(kw) == self.getGlobalSize():
kw_copy = EclKW(kw.getName(), self.getNumActive(), kw.data_type)
self._compressed_kw_copy(kw_copy, kw)
return kw_copy
else:
raise ValueError("The input keyword must have nx*n*nz or nactive elements. Size:%d invalid" % len(kw))
def global_kw_copy(self, kw, default_value):
if len(kw) == self.getGlobalSize():
return kw.copy()
elif len(kw) == self.getNumActive():
kw_copy = EclKW(kw.getName(), self.getGlobalSize(), kw.data_type)
kw_copy.assign(default_value)
self._global_kw_copy(kw_copy, kw)
return kw_copy
else:
raise ValueError("The input keyword must have nx*n*nz or nactive elements. Size:%d invalid" % len(kw))
def export_ACTNUM_kw(self):
actnum = EclKW("ACTNUM", self.getGlobalSize(), EclDataType.ECL_INT)
self._init_actnum(actnum.getDataPtr())
return actnum
def create_volume_keyword(self, active_size=True):
"""Will create a EclKW initialized with cell volumes.
The purpose of this method is to create a EclKW instance which
is initialized with all the cell volumes, this can then be
used to perform volume summation; i.e. to calculate the total
oil volume:
soil = 1 - sgas - swat
cell_volume = grid.createVolumeKeyword()
tmp = cell_volume * soil
oip = tmp.sum()
The oil in place calculation shown above could easily be
implemented by iterating over the soil kw, however using the
volume keyword has two advantages:
1. The calculation of cell volumes is quite time consuming,
by storing the results in a kw they can be reused.
2. By using the compact form 'oip = cell_volume * soil' the
inner loop iteration will go in C - which is faster.
By default the kw will only have values for the active cells,
but by setting the optional variable @active_size to False you
will get volume values for all cells in the grid.
"""
return self._create_volume_keyword(active_size)
def export_index(self, active_only = False):
"""
Exports a pandas dataframe containing index data of grid cells.
The global_index of the cells is used as index in the pandas frame.
columns 0, 1, 2 are i, j, k, respectively
column 3 contains the active_index
if active_only == True, only active cells are listed,
otherwise all cells are listed.
This index frame should typically be passed to the epxport_data(),
export_volume() and export_corners() functions.
"""
if active_only:
size = self.get_num_active()
else:
size = self.get_global_size()
indx = numpy.zeros(size, dtype=numpy.int32)
data = numpy.zeros([size, 4], dtype=numpy.int32)
self._export_index_frame( indx.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)), data.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)), active_only )
df = pandas.DataFrame(data=data, index=indx, columns=['i', 'j', 'k', 'active'])
return df
def export_data(self, index_frame, kw, default = 0):
"""
Exports keywoard data to a numpy vector.
Index_fram must be a pandas dataframe with the same structure
as obtained from export_index.
kw must have size of either global_size or num_active.
The length of the numpy vector is the number of rows in index_frame.
If kw is of length num_active, values in the output vector
corresponding to inactive cells are set to default.
"""
if not isinstance(index_frame, pandas.DataFrame):
raise TypeError("index_frame must be pandas.DataFrame")
if len(kw) == self.get_global_size():
index = numpy.array( index_frame.index, dtype=numpy.int32 )
elif len(kw) == self.get_num_active():
index = numpy.array( index_frame["active"], dtype=numpy.int32 )
else:
raise ValueError("The keyword must have a 3D compatible length")
if kw.type is EclTypeEnum.ECL_INT_TYPE:
data = numpy.full( len(index), default, dtype=numpy.int32 )
self._export_data_as_int( len(index),
index.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
kw,
data.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)) )
return data
elif kw.type is EclTypeEnum.ECL_FLOAT_TYPE or kw.type is EclTypeEnum.ECL_DOUBLE_TYPE:
data = numpy.full( len(index), default, dtype=numpy.float64 )
self._export_data_as_double( len(index),
index.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
kw,
data.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) )
return data
else:
raise TypeError("Keyword must be either int, float or double.")
def export_volume(self, index_frame):
"""
Exports cell volume data to a numpy vector.
Index_fram must be a pandas dataframe with the same structure
as obtained from export_index.
"""
index = numpy.array( index_frame.index, dtype=numpy.int32 )
data = numpy.zeros( len(index ), dtype=numpy.float64 )
self._export_volume( len(index),
index.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
data.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) )
return data
def export_position(self, index_frame):
"""Exports cell position coordinates to a numpy vector (matrix), with columns
0, 1, 2 denoting coordinates x, y, and z, respectively.
Index_fram must be a pandas dataframe with the same structure
as obtained from export_index.
"""
index = numpy.array( index_frame.index, dtype=numpy.int32 )
data = numpy.zeros( [len(index), 3], dtype=numpy.float64 )
self._export_position( len(index),
index.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
data.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) )
return data
def export_corners(self, index_frame):
"""Exports cell corner position coordinates to a numpy vector (matrix).
Index_fram must be a pandas dataframe with the same structure
as obtained from export_index.
Example of a row of the output matrix:
0 1 2 .... 21 22 23
x1 y1 z1 .... x8 y8 z8
In total there are eight 8 corners. They are described as follows:
The corners in a cell are numbered 0 - 7, where corners 0-3 constitute
one layer and the corners 4-7 consitute the other layer. Observe
that the numbering does not follow a consistent rotation around the face:
j
6---7 /|\
| | |
4---5 |
|
o----------> i
2---3
| |
0---1
Many grids are left-handed, i.e. the direction of increasing z will
point down towards the center of the earth. Hence in the figure above
the layer 4-7 will be deeper down in the reservoir than layer 0-3, and
also have higher z-value.
Warning: The main author of this code suspects that the coordinate
system can be right-handed as well, giving a z axis which will
increase 'towards the sky'; the safest way is probably to check this
explicitly if it matters for the case at hand.
"""
index = numpy.array( index_frame.index, dtype=numpy.int32 )
data = numpy.zeros( [len(index), 24], dtype=numpy.float64 )
self._export_corners( len(index),
index.ctypes.data_as(ctypes.POINTER(ctypes.c_int32)),
data.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) )
return data
def export_coord(self):
return self._export_coord()
def export_zcorn(self):
return self._export_zcorn()
def export_actnum(self):
return self._export_actnum()
def export_mapaxes(self):
if not self._use_mapaxes():
return None
return self._export_mapaxes()
@property
def unit_system(self):
return self._get_unit_system()
monkey_the_camel(EclGrid, 'loadFromGrdecl', EclGrid.load_from_grdecl, classmethod)
monkey_the_camel(EclGrid, 'loadFromFile', EclGrid.load_from_file, classmethod)
monkey_the_camel(EclGrid, 'createRectangular', EclGrid.create_rectangular, classmethod)
monkey_the_camel(EclGrid, 'dualGrid', EclGrid.dual_grid)
monkey_the_camel(EclGrid, 'getDims', EclGrid.get_dims)
monkey_the_camel(EclGrid, 'getNX', EclGrid.get_nx)
monkey_the_camel(EclGrid, 'getNY', EclGrid.get_ny)
monkey_the_camel(EclGrid, 'getNZ', EclGrid.get_nz)
monkey_the_camel(EclGrid, 'getGlobalSize', EclGrid.get_global_size)
monkey_the_camel(EclGrid, 'getNumActive', EclGrid.get_num_active)
monkey_the_camel(EclGrid, 'getNumActiveFracture', EclGrid.get_num_active_fracture)
monkey_the_camel(EclGrid, 'getBoundingBox2D', EclGrid.get_bounding_box_2d)
monkey_the_camel(EclGrid, 'getName', EclGrid.get_name)
monkey_the_camel(EclGrid, 'validCellGeometry', EclGrid.valid_cell_geometry)
monkey_the_camel(EclGrid, 'getNodePos', EclGrid.get_node_pos)
monkey_the_camel(EclGrid, 'getCellCorner', EclGrid.get_cell_corner)
monkey_the_camel(EclGrid, 'getNodeXYZ', EclGrid.get_node_xyz)
monkey_the_camel(EclGrid, 'getLayerXYZ', EclGrid.get_layer_xyz)
monkey_the_camel(EclGrid, 'findCellXY', EclGrid.find_cell_xy)
monkey_the_camel(EclGrid, 'findCellCornerXY', EclGrid.find_cell_corner_xy)
monkey_the_camel(EclGrid, 'getCellDims', EclGrid.get_cell_dims)
monkey_the_camel(EclGrid, 'getNumLGR', EclGrid.get_num_lgr)
monkey_the_camel(EclGrid, 'createKW', EclGrid.create_kw)
monkey_the_camel(EclGrid, 'create3D', EclGrid.create_3d)
monkey_the_camel(EclGrid, 'compressedKWCopy', EclGrid.compressed_kw_copy)
monkey_the_camel(EclGrid, 'globalKWCopy', EclGrid.global_kw_copy)
monkey_the_camel(EclGrid, 'exportACTNUMKw', EclGrid.export_ACTNUM_kw)
monkey_the_camel(EclGrid, 'createVolumeKeyword', EclGrid.create_volume_keyword)