Skip to content

Commit

Permalink
Refactor well class
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrivenaes committed Oct 9, 2023
1 parent b2824d2 commit a6c459f
Show file tree
Hide file tree
Showing 27 changed files with 1,698 additions and 902 deletions.
17 changes: 8 additions & 9 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[build-system]
requires = [
"scikit-build-core[pyproject]",
"swig",
"numpy==1.19.2; python_version == '3.8'",
"numpy==1.19.5; python_version == '3.9'",
"numpy==1.21.6; python_version == '3.10'",
"numpy==1.23.5; python_version == '3.11'",
"scikit-build-core[pyproject]",
"swig",
"numpy==1.19.2; python_version == '3.8'",
"numpy==1.19.5; python_version == '3.9'",
"numpy==1.21.6; python_version == '3.10'",
"numpy==1.23.5; python_version == '3.11'",
]
build-backend = "scikit_build_core.build"

Expand All @@ -22,9 +22,7 @@ description = "XTGeo is a Python library for 3D grids, surfaces, wells, etc"
readme = "README.md"
requires-python = ">=3.8"
license = { text = "LGPL-3.0" }
authors = [
{ name = "Equinor", email = "[email protected]" },
]
authors = [{ name = "Equinor", email = "[email protected]" }]
keywords = ["grids", "surfaces", "wells", "cubes"]
classifiers = [
"Development Status :: 5 - Production/Stable",
Expand All @@ -50,6 +48,7 @@ dependencies = [
"ecl-data-io>=2.1",
"h5py>=3",
"hdf5plugin>=2.3",
"joblib",
"matplotlib>=3.3",
"numpy>=1.19",
"pandas>=1.1",
Expand Down
2 changes: 1 addition & 1 deletion src/xtgeo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def _xprint(msg):
#
_xprint("Import matplotlib etc...DONE")

from xtgeo.common import XTGeoDialog
from xtgeo.common.constants import UNDEF, UNDEF_INT, UNDEF_INT_LIMIT, UNDEF_LIMIT
from xtgeo.common.exceptions import (
BlockedWellsNotFoundError,
Expand All @@ -89,7 +90,6 @@ def _xprint(msg):
WellNotFoundError,
)
from xtgeo.common.sys import _XTGeoFile
from xtgeo.common.xtgeo_dialog import XTGeoDialog
from xtgeo.cxtgeo._cxtgeo import XTGeoCLibError

_xprint("Import common... done")
Expand Down
4 changes: 4 additions & 0 deletions src/xtgeo/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@

MAXKEYWORDS = cx.MAXKEYWORDS # maximum keywords for ECL and ROFF scanning
MAXDATES = cx.MAXDATES # maximum keywords for ECL scanning

# for XYZ data, restricted to float32 and int32
UNDEF_CONT = UNDEF
UNDEF_DISC = UNDEF_INT
59 changes: 59 additions & 0 deletions src/xtgeo/common/sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,62 @@ def decorator_set_docstring(func):
return func

return decorator_set_docstring


# ----------------------------------------------------------------------------------
# Special methods for nerds, to be removed when not appplied any more
# ----------------------------------------------------------------------------------


def _convert_np_carr_int(length, np_array):
"""Convert numpy 1D array to C array, assuming int type.
The numpy is always a double (float64), so need to convert first
"""
carr = _cxtgeo.new_intarray(length)

np_array = np_array.astype(np.int32)

_cxtgeo.swig_numpy_to_carr_i1d(np_array, carr)

return carr


def _convert_np_carr_double(length, np_array):
"""Convert numpy 1D array to C array, assuming double type."""
carr = _cxtgeo.new_doublearray(length)

_cxtgeo.swig_numpy_to_carr_1d(np_array, carr)

return carr


def _convert_carr_double_np(length, carray, nlen=None):
"""Convert a C array to numpy, assuming double type."""
if nlen is None:
nlen = length

nparray = _cxtgeo.swig_carr_to_numpy_1d(nlen, carray)

return nparray


def _get_carray(dataframe, attributes, attrname: str):
"""Returns the C array pointer (via SWIG) for a given attr.
Type conversion is double if float64, int32 if DISC attr.
Returns None if log does not exist.
"""
np_array = None
if attrname in dataframe:
np_array = dataframe[attrname].values
else:
return None

nlen = len(dataframe.index)
if attributes[attrname] == "DISC":
carr = _convert_np_carr_int(nlen, np_array)
else:
carr = _convert_np_carr_double(nlen, np_array)

return carr
3 changes: 2 additions & 1 deletion src/xtgeo/grid3d/_grid_etc1.py
Original file line number Diff line number Diff line change
Expand Up @@ -839,7 +839,8 @@ def _get_geometrics_v2(self, allcells=False, cellcenter=True, return_dict=False)
y1 = ycor.values[self.ncol - 1, midcol, midlay]
glist.append(degrees(atan2(y1 - y0, x1 - x0)))

dx, dy = self.get_dxdy(asmasked=False)
dx = self.get_dx(asmasked=False)
dy = self.get_dy(asmasked=False)
dz = self.get_dz(asmasked=False)
glist.append(dx.values.mean())
glist.append(dy.values.mean())
Expand Down
8 changes: 5 additions & 3 deletions src/xtgeo/grid3d/_grid_wellzone.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,19 @@ def report_zone_mismatch(

# get the IJK along the well as logs; use a copy of the well instance
wll = well.copy()
wll._df[zonelogname] += zonelogshift
wll.dataframe[zonelogname] += zonelogshift

if depthrange:
d1, d2 = depthrange
wll._df = wll._df[(d1 < wll._df.Z_TVDSS) & (wll._df.Z_TVDSS < d2)]
wll.dataframe = wll.dataframe[
(d1 < wll.dataframe.Z_TVDSS) & (wll.dataframe.Z_TVDSS < d2)
]

wll.get_gridproperties(zoneprop, self)
zmodel = zoneprop.name + "_model"

# from here, work with the dataframe only
df = wll._df
df = wll.dataframe

# zonelogrange
z1, z2 = zonelogrange
Expand Down
45 changes: 26 additions & 19 deletions src/xtgeo/well/_blockedwell_roxapi.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# -*- coding: utf-8 -*-
"""Well input and output, private module for ROXAPI"""


from collections import OrderedDict
"""Blocked Well input and output, private module for ROXAPI"""

import numpy as np
import numpy.ma as npma
Expand All @@ -12,16 +8,18 @@
from xtgeo.common.exceptions import WellNotFoundError
from xtgeo.roxutils import RoxUtils

from ..xyz_common._xyz_enum import _AttrName

try:
import roxar
import roxar # type: ignore
except ImportError:
pass

xtg = XTGeoDialog()
logger = xtg.functionlogger(__name__)


# Import / export via ROX api
# Import / export via ROX/RMS api


def import_bwell_roxapi(
Expand Down Expand Up @@ -85,17 +83,18 @@ def _roxapi_import_bwell(
cind = bw_cellindices[dind]
xyz = np.transpose(gmodel.get_grid(realisation=realisation).get_cell_centers(cind))

logs = OrderedDict()
logs["X_UTME"] = xyz[0].astype(np.float64)
logs["Y_UTMN"] = xyz[1].astype(np.float64)
logs["Z_TVDSS"] = xyz[2].astype(np.float64)
logs = {}
logs[_AttrName.XNAME.value] = xyz[0].astype(np.float64)
logs[_AttrName.YNAME.value] = xyz[1].astype(np.float64)
logs[_AttrName.ZNAME.value] = xyz[2].astype(np.float64)

if ijk:
ijk = np.transpose(
gmodel.get_grid(realisation=realisation).grid_indexer.get_indices(cind)
)
logs["I_INDEX"] = ijk[0].astype(np.float64)
logs["J_INDEX"] = ijk[1].astype(np.float64)
logs["K_INDEX"] = ijk[2].astype(np.float64)
logs[_AttrName.I_INDEX.value] = ijk[0].astype(np.float64)
logs[_AttrName.J_INDEX.value] = ijk[1].astype(np.float64)
logs[_AttrName.K_INDEX.value] = ijk[2].astype(np.float64)

usenames = []
if lognames and lognames == "all":
Expand All @@ -112,11 +111,11 @@ def _roxapi_import_bwell(
tmplog = npma.filled(tmplog, fill_value=np.nan)
tmplog[tmplog == -999] = np.nan
if "discrete" in str(bwprop.type):
self._wlogtypes[lname] = "DISC"
self._wlogrecords[lname] = bwprop.code_names
self.set_logtype(lname, "DISC")
self.set_logrecord(lname, bwprop.code_names)
else:
self._wlogtypes[lname] = "CONT"
self._wlogrecords[lname] = None
self.set_logtype(lname, "CONT")
self.set_logrecord(lname, None)

logs[lname] = tmplog

Expand Down Expand Up @@ -165,7 +164,15 @@ def _roxapi_export_bwell(
dind = bwset.get_data_indices([self._wname], realisation=realisation)

for lname in self.lognames:
if not ijk and "_INDEX" in lname:
if (
not ijk
and any(
_AttrName.I_INDEX.value,
_AttrName.J_INDEX.value,
_AttrName.K_INDEX.value,
)
in lname
):
continue

if lognames != "all" and lname not in lognames:
Expand Down
96 changes: 96 additions & 0 deletions src/xtgeo/well/_well_aux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""Auxillary functions for the well class
'self' is a Well() instance
"""

from __future__ import annotations

import functools
import warnings
from pathlib import Path
from typing import Callable, Optional

import pandas as pd

import xtgeo
import xtgeo.cxtgeo._cxtgeo as _cxtgeo # type: ignore
from xtgeo.common import XTGeoDialog

from ..xyz_common._xyz_enum import _AttrName
from . import _well_io

xtg = XTGeoDialog()
logger = xtg.functionlogger(__name__)


def _data_reader_factory(file_format: Optional[str] = None):
if file_format in ["rmswell", "irap_ascii", None]:
return _well_io.import_rms_ascii
if file_format == "hdf":
return _well_io.import_hdf5_well
raise ValueError(
f"Unknown file format {file_format}, supported formats are "
"'rmswell', 'irap_ascii' and 'hdf'"
)


def allow_deprecated_init(func: Callable):
# This decorator is here to maintain backwards compatibility in the
# construction of Well and should be deleted once the deprecation period
# has expired, the construction will then follow the new pattern.
@functools.wraps(func)
def wrapper(self, *args, **kwargs):
if not args and not kwargs:
warnings.warn(
"Initializing empty well is deprecated, please provide "
"non-defaulted values, or use mywell = "
"xtgeo.well_from_file('filename')",
DeprecationWarning,
)
return func(
self,
*([0.0] * 3),
"",
pd.DataFrame(
{
_AttrName.XNAME.value: [],
_AttrName.YNAME.value: [],
_AttrName.ZNAME.value: [],
}
),
)

# Checking if we are doing an initialization from file and raise a
# deprecation warning if we are.
if "wfile" in kwargs or (
len(args) >= 1 and isinstance(args[0], (str, Path, xtgeo._XTGeoFile))
):
warnings.warn(
"Initializing directly from file name is deprecated and will be "
"removed in xtgeo version 4.0. Use: "
"mywell = xtgeo.well_from_file('filename') instead",
DeprecationWarning,
)
if len(args) >= 1:
wfile = args[0]
args = args[1:]
else:
wfile = kwargs.pop("wfile", None)
if len(args) >= 1:
fformat = args[0]
args = args[1:]
else:
fformat = kwargs.pop("fformat", None)

mfile = xtgeo._XTGeoFile(wfile)
if fformat is None or fformat == "guess":
fformat = mfile.detect_fformat()
else:
fformat = mfile.generic_format_by_proposal(fformat)
kwargs = _data_reader_factory(fformat)(mfile, *args, **kwargs)
kwargs["filesrc"] = mfile.file
return func(self, **kwargs)
return func(self, *args, **kwargs)

return wrapper
Loading

0 comments on commit a6c459f

Please sign in to comment.