Example #1
0
def _import_eclbinary_checks2(kwlist, name, etype, date):
    """More checks, and returns what's needed for actual import"""

    datefound = True

    kwfound = False
    datefoundhere = False
    usedate = "0"
    restart = False

    kwname = "unset"
    kwlen = 0
    kwtype = "unset"
    kwbyte = 0

    if etype == 5:
        usedate = str(date)
        restart = True

    kwxlist = list(kwlist.itertuples(index=False, name=None))
    for kwitem in kwxlist:
        kwname, kwtype, kwlen, kwbyte, kwdate = kwitem
        logger.debug("Keyword %s -  date: %s usedate: %s", kwname, kwdate,
                     usedate)
        if name == kwname:
            kwfound = True

        if name == kwname and usedate == str(kwdate):
            logger.info("Keyword %s ok at date %s", name, usedate)
            kwname, kwtype, kwlen, kwbyte, kwdate = kwitem
            datefoundhere = True
            break

    if restart:
        if datefound and not kwfound:
            msg = "Date <{}> is found, but not keyword <{}>".format(date, name)
            xtg.warn(msg)
            raise xtgeo.KeywordNotFoundError(msg)

        if not datefoundhere and kwfound:
            msg = "The keyword <{}> exists but not for " "date <{}>".format(
                name, date)
            xtg.warn(msg)
            raise xtgeo.KeywordFoundNoDateError(msg)
    else:
        if not kwfound:
            msg = "The keyword <{}> is not found".format(name)
            xtg.warn(msg)
            raise xtgeo.KeywordNotFoundError(msg)

    return kwname, kwlen, kwtype, kwbyte
def read_grdecl_3d_property(filename, keyword, dimensions, dtype=float):
    """
    Read a 3d grid property from a grdecl file, see open_grdecl for description
    of format.

    Args:
        filename (pathlib.Path or str): File in grdecl format.
        keyword (str): The keyword of the property in the file
        dimensions ((int,int,int)): Triple of the size of grid.
        dtype (function): The datatype to be read, ie., float.

    Raises:
        xtgeo.KeywordNotFoundError: If keyword is not found in the file.

    Returns:
        numpy array with given dimensions and data type read
        from the grdecl file.
    """
    result = None

    with open_grdecl(filename, keywords=[],
                     simple_keywords=(keyword, )) as kw_generator:
        try:
            _, result = next(kw_generator)
        except StopIteration as si:
            raise xtgeo.KeywordNotFoundError(
                f"Cannot import {keyword}, not present in file {filename}?"
            ) from si

    # The values are stored in F order in the grdecl file
    f_order_values = np.array([dtype(v) for v in result])
    return np.ascontiguousarray(f_order_values.reshape(dimensions, order="F"))
Example #3
0
def import_bgrdecl_prop(self, pfile, name="unknown", grid=None):
    """Import property from binary files with GRDECL layout"""

    local_fhandle = False
    fhandle = pfile
    if isinstance(pfile, str):
        local_fhandle = True
        pfile = xtgeo._XTGeoCFile(pfile)
        fhandle = pfile.fhandle

    # scan file for properties; these have similar binary format as e.g. EGRID
    logger.info("Make kwlist by scanning")
    kwlist = utils.scan_keywords(fhandle,
                                 fformat="xecl",
                                 maxkeys=1000,
                                 dataframe=False,
                                 dates=False)
    bpos = {}
    bpos[name] = -1

    for kwitem in kwlist:
        kwname, kwtype, kwlen, kwbyte = kwitem
        logger.info("KWITEM: %s", kwitem)
        if name == kwname:
            bpos[name] = kwbyte
            break

    if bpos[name] == -1:
        raise xtgeo.KeywordNotFoundError(
            "Cannot find property name {} in file {}".format(name, pfile))
    self._ncol = grid.ncol
    self._nrow = grid.nrow
    self._nlay = grid.nlay

    values = _eclbin.eclbin_record(fhandle, kwname, kwlen, kwtype, kwbyte)
    if kwtype == "INTE":
        self._isdiscrete = True
        # make the code list
        uniq = np.unique(values).tolist()
        codes = dict(zip(uniq, uniq))
        codes = {key: str(val) for key, val in codes.items()}  # val: strings
        self.codes = codes

    else:
        self._isdiscrete = False
        values = values.astype(np.float64)  # cast REAL (float32) to float64
        self.codes = {}

    # property arrays from binary GRDECL will be for all cells, but they
    # are in Fortran order, so need to convert...

    actnum = grid.get_actnum().values
    allvalues = values.reshape(self.dimensions, order="F")
    allvalues = np.asanyarray(allvalues, order="C")
    allvalues = ma.masked_where(actnum < 1, allvalues)
    self.values = allvalues
    self._name = name

    if local_fhandle and not pfile.close(cond=local_fhandle):
        raise RuntimeError("Error in file handling; cannot close file")
Example #4
0
def import_grdecl_prop(self, pfile, name="unknown", grid=None):
    """Read a GRDECL ASCII property record"""

    if grid is None:
        raise ValueError("A grid instance is required as argument")

    self._ncol = grid.ncol
    self._nrow = grid.nrow
    self._nlay = grid.nlay
    self._name = name
    self._filesrc = pfile
    actnumv = grid.get_actnum().values

    # This requires that the Python part clean up comments
    # etc, and make a tmp file.

    # make a temporary file
    fds, tmpfile = mkstemp()
    # make a temporary

    with open(pfile) as oldfile, open(tmpfile, "w") as newfile:
        for line in oldfile:
            if not (re.search(r"^--", line) or re.search(r"^\s+$", line)):
                newfile.write(line)

    newfile.close()
    oldfile.close()

    # now read the property
    nlen = self._ncol * self._nrow * self._nlay
    ier, values = _cxtgeo.grd3d_import_grdecl_prop(tmpfile, self._ncol,
                                                   self._nrow, self._nlay,
                                                   name, nlen, 0, XTGDEBUG)
    # remove tmpfile
    os.close(fds)
    os.remove(tmpfile)

    if ier != 0:
        raise xtgeo.KeywordNotFoundError(
            "Cannot import {}, not present in file {}?".format(name, pfile))

    self.values = values.reshape(self.dimensions)

    self.values = ma.masked_equal(self.values, actnumv == 0)

    return 0
Example #5
0
def from_file(self,
              pfile,
              fformat=None,
              name="unknown",
              grid=None,
              date=None,
              _roffapiv=1):  # _roffapiv for devel.
    """Import grid property from file, and makes an instance of this."""

    # pylint: disable=too-many-branches, too-many-statements

    self._filesrc = pfile

    # it may be that pfile already is an open file; hence a filehandle
    # instead. Check for this, and skip tests if so
    pfile_is_not_fhandle = True
    _fhandle, pclose = _get_fhandle(pfile)
    if not pclose:
        pfile_is_not_fhandle = False

    if pfile_is_not_fhandle:
        if os.path.isfile(pfile):
            logger.debug("File %s exists OK", pfile)
        else:
            raise IOError("No such file: {}".format(pfile))

        # work on file extension
        _froot, fext = os.path.splitext(pfile)
        if fformat is None or fformat == "guess":
            if not fext:
                raise ValueError("File extension missing. STOP")

            fformat = fext.lower().replace(".", "")

        logger.debug("File name to be used is %s", pfile)
        logger.debug("File format is %s", fformat)

    ier = 0
    if fformat == "roff":
        logger.info("Importing ROFF...")
        ier = import_roff(self, pfile, name, grid=grid, _roffapiv=_roffapiv)

    elif fformat.lower() == "init":
        ier = import_eclbinary(self,
                               pfile,
                               name=name,
                               etype=1,
                               date=None,
                               grid=grid)

    elif fformat.lower() == "unrst":
        if date is None:
            raise ValueError("Restart file, but no date is given")

        if isinstance(date, str):
            if "-" in date:
                date = int(date.replace("-", ""))
            elif date == "first":
                date = 0
            elif date == "last":
                date = 9
            else:
                date = int(date)

        if not isinstance(date, int):
            raise RuntimeError("Date is not int format")

        ier = import_eclbinary(self,
                               pfile,
                               name=name,
                               etype=5,
                               date=date,
                               grid=grid)

    elif fformat.lower() == "grdecl":
        ier = import_grdecl_prop(self, pfile, name=name, grid=grid)

    elif fformat.lower() == "bgrdecl":
        ier = import_bgrdecl_prop(self, pfile, name=name, grid=grid)
    else:
        logger.warning("Invalid file format")
        raise SystemExit("Invalid file format")

    # if grid, then append this gridprop to the current grid object
    if ier == 0:
        if grid:
            grid.append_prop(self)
    elif ier == 22:
        raise xtgeo.DateNotFoundError(
            "Date {} not found when importing {}".format(date, name))
    elif ier == 23:
        raise xtgeo.KeywordNotFoundError(
            "Keyword {} not found for date {} when importing".format(
                name, date))
    elif ier == 24:
        raise xtgeo.KeywordFoundNoDateError(
            "Keyword {} found but not for date "
            "{} when importing".format(name, date))
    elif ier == 25:
        raise xtgeo.KeywordNotFoundError(
            "Keyword {} not found when importing".format(name))
    else:
        raise RuntimeError("Something went wrong, code {}".format(ier))

    return self
Example #6
0
def _import_eclbinary(self, pfile, name=None, etype=1, date=None, grid=None):
    """Import, private to this routine.

    Raises:
        DateNotFoundError: If restart do not contain requested date.
        KeywordFoundNoDateError: If keyword is found but not at given date.
        KeywordNotFoundError: If Keyword is not found.
        RuntimeError: Mismatch in grid vs property, etc.

    """
    # This function requires simplification!
    # pylint: disable=too-many-locals
    # pylint: disable=too-many-branches
    # pylint: disable=too-many-statements

    fhandle, pclose = _get_fhandle(pfile)

    nentry = 0

    datefound = True
    if etype == 5:
        datefound = False
        logger.info("Look for date %s", date)

        # scan for date and find SEQNUM entry number
        dtlist = utils.scan_dates(fhandle)
        if date == 0:
            date = dtlist[0][1]
        elif date == 9:
            date = dtlist[-1][1]

        logger.info("Redefined date is %s", date)

        for ientry, dtentry in enumerate(dtlist):
            if str(dtentry[1]) == str(date):
                datefound = True
                nentry = ientry
                break

        if not datefound:
            msg = "In {}: Date {} not found, nentry={}".format(
                pfile, date, nentry)
            xtg.warn(msg)
            raise xtgeo.DateNotFoundError(msg)

    # scan file for property
    logger.info("Make kwlist")
    kwlist = utils.scan_keywords(fhandle,
                                 fformat="xecl",
                                 maxkeys=100000,
                                 dataframe=False,
                                 dates=True)

    # first INTEHEAD is needed to verify grid dimensions:
    for kwitem in kwlist:
        if kwitem[0] == "INTEHEAD":
            kwname, kwtype, kwlen, kwbyte, kwdate = kwitem
            break

    # read INTEHEAD record:
    intehead = eclbin_record(fhandle, kwname, kwlen, kwtype, kwbyte)
    ncol, nrow, nlay = intehead[8:11].tolist()

    self._ncol = ncol
    self._nrow = nrow
    self._nlay = nlay

    logger.info("Grid dimensions in INIT or RESTART file: %s %s %s", ncol,
                nrow, nlay)

    logger.info("Grid dimensions from GRID file: %s %s %s", grid.ncol,
                grid.nrow, grid.nlay)

    if grid.ncol != ncol or grid.nrow != nrow or grid.nlay != nlay:
        msg = "In {}: Errors in dimensions prop: {} {} {} vs grid: {} {} {} ".format(
            pfile, ncol, nrow, nlay, grid.ncol, grid.ncol, grid.nlay)
        raise RuntimeError(msg)

    # Restarts (etype == 5):
    # there are cases where keywords do not exist for all dates, e.g .'RV'.
    # The trick is to check for dates also...

    kwfound = False
    datefoundhere = False
    usedate = "0"
    restart = False

    if etype == 5:
        usedate = str(date)
        restart = True

    for kwitem in kwlist:
        kwname, kwtype, kwlen, kwbyte, kwdate = kwitem
        logger.debug("Keyword %s -  date: %s usedate: %s", kwname, kwdate,
                     usedate)
        if name == kwname:
            kwfound = True

        if name == kwname and usedate == str(kwdate):
            logger.info("Keyword %s ok at date %s", name, usedate)
            kwname, kwtype, kwlen, kwbyte, kwdate = kwitem
            datefoundhere = True
            break

    if restart:
        if datefound and not kwfound:
            msg = "For {}: Date <{}> is found, but not keyword <{}>".format(
                pfile, date, name)
            xtg.warn(msg)
            raise xtgeo.KeywordNotFoundError(msg)

        if not datefoundhere and kwfound:
            msg = "For {}: The keyword <{}> exists but not for " "date <{}>".format(
                pfile, name, date)
            xtg.warn(msg)
            raise xtgeo.KeywordFoundNoDateError(msg)
    else:
        if not kwfound:
            msg = "For {}: The keyword <{}> is not found".format(pfile, name)
            xtg.warn(msg)
            raise xtgeo.KeywordNotFoundError(msg)

    # read record:
    values = eclbin_record(fhandle, kwname, kwlen, kwtype, kwbyte)

    if kwtype == "INTE":
        self._isdiscrete = True
        use_undef = xtgeo.UNDEF_INT

        # make the code list
        uniq = np.unique(values).tolist()
        codes = dict(zip(uniq, uniq))
        codes = {key: str(val) for key, val in codes.items()}  # val: strings
        self.codes = codes

    else:
        self._isdiscrete = False
        values = values.astype(np.float64)  # cast REAL (float32) to float64
        use_undef = xtgeo.UNDEF
        self.codes = {}

    # arrays from Eclipse INIT or UNRST are usually for inactive values only.
    # Use the ACTNUM index array for vectorized numpy remapping
    actnum = grid.get_actnum().values
    allvalues = np.zeros((ncol * nrow * nlay), dtype=values.dtype) + use_undef

    msg = "\n"
    msg = msg + "grid.actnum_indices.shape[0] = {}\n".format(
        grid.actnum_indices.shape[0])
    msg = msg + "values.shape[0] = {}\n".format(values.shape[0])
    msg = msg + "ncol nrow nlay {} {} {}, nrow*nrow*nlay = {}\n".format(
        ncol, nrow, nlay, ncol * nrow * nlay)

    logger.info(msg)

    if grid.actnum_indices.shape[0] == values.shape[0]:
        allvalues[grid.get_actnum_indices(order="F")] = values
    elif values.shape[0] == ncol * nrow * nlay:  # often case for PORV array
        allvalues = values.copy()
    else:
        msg = ("BUG somehow... Is the file corrupt? If not contact "
               "the library developer(s)!\n" + msg)
        raise SystemExit(msg)

    allvalues = allvalues.reshape((ncol, nrow, nlay), order="F")
    allvalues = np.asanyarray(allvalues, order="C")
    allvalues = ma.masked_where(actnum < 1, allvalues)

    _close_fhandle(fhandle, pclose)

    self._values = allvalues

    if etype == 1:
        self._name = name
    else:
        self._name = name + "_" + str(date)
        self._date = date

    return 0