def test_translation(self): dims = (3,3,3) coord = GridGen.create_coord(dims, (1,1,1)) zcorn = GridGen.create_zcorn(dims, (1,1,1), offset=0) grid = EclGrid.create(dims, zcorn, coord, None) ijk_bound = [(0, d-1) for d in dims] translation = (1, 2, 3) sub_coord, sub_zcorn, _ = GridGen.extract_subgrid_data( dims, coord, zcorn, ijk_bound, translation=translation ) tgrid = EclGrid.create(dims, sub_zcorn, sub_coord, None) self.assertEqual(grid.getGlobalSize(), tgrid.getGlobalSize()) for gi in range(grid.getGlobalSize()): translation = numpy.array(translation) corners = [grid.getCellCorner(i, gi) for i in range(8)] corners = [tuple(numpy.array(c)+translation) for c in corners] tcorners = [tgrid.getCellCorner(i, gi) for i in range(8)] self.assertEqual(corners, tcorners)
def test_actnum_extraction(self): dims = (4,4,4) coord = GridGen.create_coord(dims, (1,1,1)) zcorn = GridGen.create_zcorn(dims, (1,1,1), offset=0) actnum = EclKW("ACTNUM", six.functools.reduce(operator.mul, dims), EclDataType.ECL_INT) random.seed(1337) for i in range(len(actnum)): actnum[i] = random.randint(0, 1) grid = EclGrid.create(dims, zcorn, coord, actnum) ijk_bounds = generate_ijk_bounds(dims) for ijk_bound in ijk_bounds: if not decomposition_preserving(ijk_bound): continue sub = GridGen.extract_subgrid_data( dims, coord, zcorn, ijk_bound, actnum=actnum ) sub_coord, sub_zcorn, sub_actnum = sub sub_dims = tuple([u-l+1 for l, u in ijk_bound]) subgrid = EclGrid.create(sub_dims, sub_zcorn, sub_coord, sub_actnum) self.assertEqual(sub_dims, subgrid.getDims()[:-1:]) self.assertSubgrid(grid, subgrid, ijk_bound)
def test_actnum_extraction(self): dims = (4, 4, 4) coord = GridGen.create_coord(dims, (1, 1, 1)) zcorn = GridGen.create_zcorn(dims, (1, 1, 1), offset=0) actnum = EclKW("ACTNUM", six.functools.reduce(operator.mul, dims), EclDataType.ECL_INT) random.seed(1337) for i in range(len(actnum)): actnum[i] = random.randint(0, 1) grid = EclGrid.create(dims, zcorn, coord, actnum) ijk_bounds = generate_ijk_bounds(dims) for ijk_bound in ijk_bounds: if not decomposition_preserving(ijk_bound): continue sub = GridGen.extract_subgrid_data(dims, coord, zcorn, ijk_bound, actnum=actnum) sub_coord, sub_zcorn, sub_actnum = sub sub_dims = tuple([u - l + 1 for l, u in ijk_bound]) subgrid = EclGrid.create(sub_dims, sub_zcorn, sub_coord, sub_actnum) self.assertEqual(sub_dims, subgrid.getDims()[:-1:]) self.assertSubgrid(grid, subgrid, ijk_bound)
def create_single_cell_grid(cls, corners): """ Provided with the corners of the grid in a similar manner as the eight corners are output for a single cell, this method will create a grid consisting of a single cell with the specified corners as its corners. """ zcorn = [corners[i][2] for i in range(8)] coord = [(corners[i], corners[i+4]) for i in range(4)] coord = flatten(flatten(coord)) def construct_floatKW(name, values): kw = EclKW(name, len(values), EclDataType.ECL_FLOAT) for i in range(len(values)): kw[i] = values[i] return kw grid = EclGrid.create( (1, 1, 1), construct_floatKW("ZCORN", zcorn), construct_floatKW("COORD", coord), None ) if not corners == [grid.getCellCorner(i, 0) for i in range(8)]: raise AssertionError("Failed to generate single cell grid. " + "Did not end up the expected corners.") return grid
def create_single_cell_grid(cls, corners): """ Provided with the corners of the grid in a similar manner as the eight corners are output for a single cell, this method will create a grid consisting of a single cell with the specified corners as its corners. """ zcorn = [corners[i][2] for i in range(8)] coord = [(corners[i], corners[i + 4]) for i in range(4)] coord = flatten(flatten(coord)) def construct_floatKW(name, values): kw = EclKW(name, len(values), EclDataType.ECL_FLOAT) for i in range(len(values)): kw[i] = values[i] return kw grid = EclGrid.create((1, 1, 1), construct_floatKW("ZCORN", zcorn), construct_floatKW("COORD", coord), None) if not corners == [grid.getCellCorner(i, 0) for i in range(8)]: raise AssertionError("Failed to generate single cell grid. " + "Did not end up the expected corners.") return grid
def create_grid(cls, dims, dV, offset=1, escape_origo_shift=(1,1,0), irregular_offset=False, irregular=False, concave=False, faults=False, scale=1, translation=(0,0,0), rotate=False, misalign=False): """ Will create a new grid where each cell is a parallelogram (skewed by z-value). The number of cells are given by @dims = (nx, ny, nz) and the dimention of each cell by @dV = (dx, dy, dz). All cells are guaranteed to not be self-intersecting. Hence, no twisted cells and somewhat meaningfull cells. @offset gives how much the layers should fluctuate or "wave" as you move along the X-axis. @irregular_offset decides whether the offset should be constant or increase by dz/2 every now and then. @irregular if true some of the layers will be inclining and others declining at the start. @concave decides whether the cells are to be convex or not. In particular, if set to False, all cells of the grid will be concave. @escape_origo_shift is used to prevent any cell of having corners in (0,0,z) as there is a heuristic in ecl_grid.c that marks such cells as tainted. @faults decides if there are to be faults in the grid. @scale A positive number that scales the "lower" endpoint of all coord's. In particular, @scale != 1 creates trapeziod cells in both the XZ and YZ-plane. @translation the lower part of the grid is translated ("slided") by the specified additive factor. @rotate the lower part of the grid is rotated 90 degrees around its center. @misalign will toggle COORD's slightly in various directions to break alignment Note that cells in the lowermost layer can have multiple corners at the same point. For testing it should give good coverage of the various scenarios this method can produce, by leting @dims be (10,10,10), @dV=(2,2,2), @offset=1, and try all 4 different configurations of @concave and @irregular_offset. """ zcorn = cls.create_zcorn(dims, dV, offset, escape_origo_shift, irregular_offset, irregular, concave, faults) coord = cls.create_coord(dims, dV, escape_origo_shift, scale, translation, rotate, misalign) return EclGrid.create(dims, zcorn, coord, None)
def loadGrid(self): grid_file = self.createTestPath("Statoil/ECLIPSE/Faults/grid.grdecl") fileH = copen(grid_file, "r") specgrid = EclKW.read_grdecl(fileH, "SPECGRID", ecl_type=EclDataType.ECL_INT, strict=False) zcorn = EclKW.read_grdecl(fileH, "ZCORN") coord = EclKW.read_grdecl(fileH, "COORD") actnum = EclKW.read_grdecl(fileH, "ACTNUM", ecl_type=EclDataType.ECL_INT) return EclGrid.create(specgrid, zcorn, coord, actnum)
def test_export(self): dims = (3, 3, 3) coord = GridGen.create_coord(dims, (1,1,1)) zcorn = GridGen.create_zcorn(dims, (1,1,1), offset=0) grid = EclGrid.create(dims, zcorn, coord, None) self.assertEqual(zcorn, grid.export_zcorn()) self.assertEqual(coord, grid.export_coord())
def test_subgrid_translation(self): grid = GridGen.create_grid((4,4,4), (1,1,1), offset=0.5, irregular=True, irregular_offset=True, concave=True, translation=(10,10,0)) # Create grid with MAPAXES mapaxes = EclKW("MAPAXES", 6, EclDataType.ECL_FLOAT) for i, val in enumerate([1200, 1400, 2500, 2500, 3700, 4000]): mapaxes[i] = val grid = EclGrid.create( grid.getDims(), grid.export_zcorn(), grid.export_coord(), None, mapaxes=mapaxes ) for translation in [ (0,0,0), (10, 10, 100), (-1, -1, -1) ]: subgrid = GridGen.extract_subgrid( grid, ((0,3), (0,3), (0,3)), translation=translation ) self.assertEqual(grid.getDims(), subgrid.getDims()) translation = numpy.array(translation) for gindex in range(grid.getGlobalSize()): grid_corners = [ grid.getCellCorner(i, global_index=gindex) for i in range(8) ] subgrid_corners = [ subgrid.getCellCorner(i, global_index=gindex) for i in range(8) ] subgrid_corners = [ list(numpy.array(corner) - translation) for corner in subgrid_corners ] for gc, sc in zip(grid_corners, subgrid_corners): self.assertAlmostEqualList( gc, sc, msg="Failed to translate corners correctly." + "Expected %s, was %s." % (gc, sc), tolerance=10e-10 )
def extract_subgrid(cls, grid, ijk_bounds, decomposition_change=False, translation=None): """ Extracts a subgrid from the given grid according to the specified bounds. @ijk_bounds: The bounds describing the subgrid. Should be a tuple of length 3, where each element gives the bound for the i, j, k coordinates of the subgrid to be described, respectively. Each bound should either be an interval of the form (a, b) where 0 <= a <= b < nx or a single integer a which is equivialent to the bound (a, a). NOTE: The given bounds are including endpoints. @decomposition_change: Depending on the given ijk_bounds, libecl might decompose the cells of the subgrid differently when extracted from grid. This is somewhat unexpected behaviour and if this event occur we give an exception together with an description for how to avoid this, unless decompostion_change is set to True. @translation: Gives the possibility of translating the subgrid. Should be given as a tuple (dx, dy, dz), where each coordinate of the grid will be moved by di in direction i. """ gdims = grid.getDims()[:-1:] nx, ny, nz = gdims ijk_bounds = cls.assert_ijk_bounds(gdims, ijk_bounds) coord = grid.export_coord() cls.assert_coord(nx, ny, nz, coord, negative_values=True) zcorn = grid.export_zcorn() cls.assert_zcorn(nx, ny, nz, zcorn) actnum = grid.export_actnum() cls.assert_actnum(nx, ny, nz, actnum) mapaxes = grid.export_mapaxes() sub_data = cls.extract_subgrid_data( gdims, coord, zcorn, ijk_bounds=ijk_bounds, actnum=actnum, mapaxes=mapaxes, decomposition_change=decomposition_change, translation=translation ) sdim = tuple([b-a+1 for a,b in ijk_bounds]) sub_coord, sub_zcorn, sub_actnum = sub_data return EclGrid.create(sdim, sub_zcorn, sub_coord, sub_actnum, mapaxes=mapaxes)
def create(self, filename, load_actnum=True): fileH = copen(filename, "r") specgrid = EclKW.read_grdecl(fileH, "SPECGRID", ecl_type=EclDataType.ECL_INT, strict=False) zcorn = EclKW.read_grdecl(fileH, "ZCORN") coord = EclKW.read_grdecl(fileH, "COORD") if load_actnum: actnum = EclKW.read_grdecl(fileH, "ACTNUM", ecl_type=EclDataType.ECL_INT) else: actnum = None mapaxes = EclKW.read_grdecl(fileH, "MAPAXES") grid = EclGrid.create(specgrid, zcorn, coord, actnum, mapaxes=mapaxes) return grid
def test_validate_cells(self): for coord, zcorn, grid in self.test_base: grid_dims = grid.getDims()[:-1:] ijk_bounds = generate_ijk_bounds(grid_dims) for ijk_bound in ijk_bounds: if not decomposition_preserving(ijk_bound): continue sub_dims = tuple([u - l + 1 for l, u in ijk_bound]) sub_coord, sub_zcorn, _ = GridGen.extract_subgrid_data( grid_dims, coord, zcorn, ijk_bound) subgrid = EclGrid.create(sub_dims, sub_zcorn, sub_coord, None) self.assertEqual(sub_dims, subgrid.getDims()[:-1:]) self.assertSubgrid(grid, subgrid, ijk_bound)
def test_validate_cells(self): for coord, zcorn, grid in self.test_base: grid_dims = grid.getDims()[:-1:] ijk_bounds = generate_ijk_bounds(grid_dims) for ijk_bound in ijk_bounds: if not decomposition_preserving(ijk_bound): continue sub_dims = tuple([u-l+1 for l, u in ijk_bound]) sub_coord, sub_zcorn, _ = GridGen.extract_subgrid_data( grid_dims, coord, zcorn, ijk_bound ) subgrid = EclGrid.create(sub_dims, sub_zcorn, sub_coord, None) self.assertEqual(sub_dims, subgrid.getDims()[:-1:]) self.assertSubgrid(grid, subgrid, ijk_bound)
def create_egrid(df_coord: pd.DataFrame, filename: pathlib.Path): """ This function does the following: - Takes as input a dataframe with coordinates defining all the grid cells - Store it as a Flow .EGRID file called `filename` The mandatory dataframe columns are xi, yi, zi (where i is the integers 0-7). An optional column name is ACTNUM. A grid cell is defined by 8 corner points (4 in the bottom plane, 4 in the top plane). The ordering is following the Flow definition): 2---3 6---7 | | | | 0---1 4---5 j /|\ | | | o----------> i The grid cells are assumed to correspond to one or more one dimensional flow models. Between two one dimensional models there should always be one inactive cell. Grid cells can be set to be inactive or active using 0 and 1 respectively in the optional ACTNUM column. Args: df_coord: Pandas dataframe with coordinates for all grid cells filename: Path to the EGRID -file to be stored to disk. Returns: Nothing """ if "ACTNUM" not in df_coord.columns: df_coord["ACTNUM"] = 1 # See Flow manual for details on input order definition of ZCORN. zcorn = ( df_coord[["z0", "z1"]].values.flatten().tolist() + df_coord[["z2", "z3"]].values.flatten().tolist() + df_coord[["z4", "z5"]].values.flatten().tolist() + df_coord[["z6", "z7"]].values.flatten().tolist() ) # See Flow manual for details on input order definition of COORD. coord = ( df_coord[["x0", "y0", "z0", "x4", "y4", "z4"]].values.flatten().tolist() + df_coord.tail(1)[["x1", "y1", "z1", "x5", "y5", "z5"]] .values.flatten() .tolist() + df_coord[["x2", "y2", "z2", "x6", "y6", "z6"]].values.flatten().tolist() + df_coord.tail(1)[["x3", "y3", "z3", "x7", "y7", "z7"]] .values.flatten() .tolist() ) actnum = df_coord["ACTNUM"].astype(int).values.flatten().tolist() EclGrid.create( (len(df_coord.index), 1, 1), construct_kw("ZCORN", zcorn), construct_kw("COORD", coord), construct_kw("ACTNUM", actnum, int_type=True), ).save_EGRID(str(filename))