Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
jcrivenaes committed Oct 1, 2023
1 parent 91a6c1c commit 5dab5f4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
66 changes: 47 additions & 19 deletions src/xtgeo/well/_welldata.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
similarly of a column is removed, the corresponding entries in wlogtypes and wlogrecords
will be deleted.
"""
from __future__ import annotations

import math
from dataclasses import dataclass, field
from enum import Enum, EnumMeta, unique
from typing import Any, Optional

import numpy as np
import pandas as pd
Expand All @@ -31,8 +34,6 @@
from xtgeo import XTGeoCLibError # type: ignore[attr-defined]
from xtgeo.cxtgeo import _cxtgeo

from . import _well_aux


class _LogTypeMeta(EnumMeta):
"""For enabling 'in' method, cf https://stackoverflow.com/questions/43634618"""
Expand Down Expand Up @@ -69,20 +70,20 @@ class _WellData:
The wlogstypes is on form {"PHIT": CONT, "FACIES": DISC, ...}
The wlogrecords is somewhat heterogenous, on form:
The wlogrecords is somewhat heterogeneous, on form:
{"PHIT": ("unit", "scale"), "FACIES": {0:BG, 2: "SST", 4: "CALC"}}
Hence the CONT logs hold a tuple or list with 2 str members, or None, while DISC
log holds a dict where the key is an int and the value is a string.
Note::
Callers shall not use properties, but methods, e.g.::
Callers shall not use properties, but methods, e.g.::
instance.well = some_new_dataframe # not
instance.well = some_new_dataframe # not
but::
but
instance.set_dataframe(some_new_dataframe)
instance.set_dataframe(some_new_dataframe)
"""

data: pd.DataFrame
Expand Down Expand Up @@ -112,7 +113,12 @@ def _infer_log_dtypes(self):
datatypes = {}
for name, dtype in dlist.items():
if name in self.wlogtypes:
datatypes[name] = self.wlogtypes[name] # keep as is
datatypes[name] = self.wlogtypes[name]
if "DISC" in datatypes[name]:
datatypes[name] = _LogType.DISC.value
else:
datatypes[name] = _LogType.CONT.value

continue

if name in (self.xname, self.yname, self.zname):
Expand Down Expand Up @@ -205,6 +211,7 @@ def ensure_consistency(self):
* When adding one or columns to the dataframe
* When removing one or more columns from the dataframe
* ...
"""

if list(self.data.columns[:3]) != [self.xname, self.yname, self.zname]:
Expand All @@ -213,6 +220,7 @@ def ensure_consistency(self):
f"and '{self.zname}', got {list(self.data.columns[:3])}"
)

# order matters:
self._ensure_consistency_wlogtypes()
self._ensure_consistency_wlogrecords()
self._ensure_consistency_df_dtypes()
Expand All @@ -232,7 +240,7 @@ def set_wlogtype(self, name: str, wtype: str) -> None:
apply_wtype = "DISC"

if name not in self.wlogtypes:
raise ValueError(f"No such well log name present: {name}")
raise ValueError(f"No such log name present: {name}")

if apply_wtype in _LogType:
self.wlogtypes[name] = _LogType(apply_wtype)
Expand All @@ -247,7 +255,7 @@ def set_wlogrecord(self, name: str, record: dict) -> None:
"""Set a wlogrecord for a named log."""

if name not in self.wlogtypes:
raise ValueError(f"No such well log name present: {name}")
raise ValueError(f"No such logname: {name}")

if self.wlogtypes[name] == _LogType.CONT.value and isinstance(
record, (list, tuple)
Expand All @@ -265,11 +273,13 @@ def set_wlogrecord(self, name: str, record: dict) -> None:
record, dict
):
raise ValueError(
"Cannot set a log record for a discrete log: input record is "
"not a dictionary"
"Input is not a dictionary. Cannot set a log record for a discrete log"
)
else:
raise ValueError("Something went wrong when setting logrecord.")
raise ValueError(
"Something went wrong when setting logrecord: "
f"({self.wlogtypes[name]} {type(record)})."
)

self.ensure_consistency()

Expand Down Expand Up @@ -401,9 +411,9 @@ def geometrics(self):
)

# extract numpies from XYZ trajetory logs
ptr_xv = _well_aux.get_carray(self, "X_UTME")
ptr_yv = _well_aux.get_carray(self, "Y_UTMN")
ptr_zv = _well_aux.get_carray(self, "Z_TVDSS")
ptr_xv = self._get_carray(self.xname)
ptr_yv = self._get_carray(self.yname)
ptr_zv = self._get_carray(self.zname)

# get number of rows in pandas
nlen = len(self.data.index)
Expand Down Expand Up @@ -447,7 +457,7 @@ def _convert_np_carr_int(self, np_array):
The numpy is always a double (float64), so need to convert first
"""
carr = _cxtgeo.new_intarray(self.nrow)
carr = _cxtgeo.new_intarray(len(self.data.index))

np_array = np_array.astype(np.int32)

Expand All @@ -457,7 +467,7 @@ def _convert_np_carr_int(self, np_array):

def _convert_np_carr_double(self, np_array):
"""Convert numpy 1D array to C array, assuming double type."""
carr = _cxtgeo.new_doublearray(self.nrow)
carr = _cxtgeo.new_doublearray(len(self.data.index))

_cxtgeo.swig_numpy_to_carr_1d(np_array, carr)

Expand All @@ -466,8 +476,26 @@ def _convert_np_carr_double(self, np_array):
def _convert_carr_double_np(self, carray, nlen=None):
"""Convert a C array to numpy, assuming double type."""
if nlen is None:
nlen = len(self._wdata.data.index)
nlen = len(self.data.index)

nparray = _cxtgeo.swig_carr_to_numpy_1d(nlen, carray)

return nparray

def _get_carray(self, lname: str) -> Optional[Any]:
"""Returns the C array pointer (via SWIG) for a given log.
Type conversion is double if float64, int32 if DISC log.
Returns None if log does not exist.
"""
if lname in self.data:
np_array = self.data[lname].values
else:
return None

if "DISC" in self.wlogtypes[lname]:
carr = self._convert_np_carr_int(np_array)
else:
carr = self._convert_np_carr_double(np_array)

return carr
1 change: 0 additions & 1 deletion src/xtgeo/well/well1.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from __future__ import annotations

import io
import math
from copy import deepcopy
from pathlib import Path
from typing import Dict, List, Optional, Union
Expand Down

0 comments on commit 5dab5f4

Please sign in to comment.