Skip to content

Commit

Permalink
Replace EclSum with ecl_data_io
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindjahren committed Sep 1, 2023
1 parent 6aea45f commit adb6d21
Show file tree
Hide file tree
Showing 5 changed files with 644 additions and 64 deletions.
179 changes: 179 additions & 0 deletions src/ert/config/_read_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
from __future__ import annotations

import ctypes

Check failure on line 3 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / annotate-python-linting

'ctypes' imported but unused
import re
from datetime import datetime
from enum import Enum, auto
from fnmatch import fnmatch
from typing import TYPE_CHECKING

import numpy as np

Check failure on line 10 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / annotate-python-linting

'numpy as np' imported but unused
from ecl.summary import EclSum
from pydantic import PositiveInt
from typing_extensions import Self

if TYPE_CHECKING:
from typing import Any, List, Optional, Sequence, Tuple

SPECIAL_KEYWORDS = [
"NEWTON",
"NAIMFRAC",
"NLINEARS",
"NLINSMIN",
"NLINSMAX",
"ELAPSED",
"MAXDPR",
"MAXDSO",
"MAXDSG",
"MAXDSW",
"STEPTYPE",
"WNEWTON",
]


class _SummaryType(Enum):
AQUIFER = auto()
BLOCK = auto()
COMPLETION = auto()
FIELD = auto()
GROUP = auto()
LOCAL_BLOCK = auto()
LOCAL_COMPLETION = auto()
LOCAL_WELL = auto()
NETWORK = auto()
SEGMENT = auto()
WELL = auto()
REGION = auto()
INTER_REGION = auto()
OTHER = auto()

@classmethod
def from_keyword(cls, summary_keyword: str) -> Self:
KEYWORD_TYPE_MAPPING = {
"A": cls.AQUIFER,
"B": cls.BLOCK,
"C": cls.COMPLETION,
"F": cls.FIELD,
"G": cls.GROUP,
"LB": cls.LOCAL_BLOCK,
"LC": cls.LOCAL_COMPLETION,
"LW": cls.LOCAL_WELL,
"N": cls.NETWORK,
"S": cls.SEGMENT,
"W": cls.WELL,
}
if summary_keyword == "":
raise ValueError("Got empty summary_keyword")
if any(special in summary_keyword for special in SPECIAL_KEYWORDS):
return cls.OTHER

Check failure on line 68 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")
if summary_keyword[0] in KEYWORD_TYPE_MAPPING:
return KEYWORD_TYPE_MAPPING[summary_keyword[0]]

Check failure on line 70 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")
if summary_keyword[0:2] in KEYWORD_TYPE_MAPPING:
return KEYWORD_TYPE_MAPPING[summary_keyword[0:2]]

Check failure on line 72 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")
if summary_keyword == "RORFR":
return cls.REGION

Check failure on line 74 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")

if any(
re.match(pattern, summary_keyword)
for pattern in [r"R.FT.*", r"R..FT.*", r"R.FR.*", r"R..FR.*", r"R.F"]
):
return cls.INTER_REGION

Check failure on line 80 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")
if summary_keyword[0] == "R":
return cls.REGION

Check failure on line 82 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")

return cls.OTHER

Check failure on line 84 in src/ert/config/_read_summary.py

View workflow job for this annotation

GitHub Actions / type-checking (3.11)

Incompatible return value type (got "_SummaryType", expected "Self")


def _cell_index(
array_index: int, nx: PositiveInt, ny: PositiveInt
) -> Tuple[int, int, int]:
k = array_index // (nx * ny)
array_index -= k * (nx * ny)
j = array_index // nx
array_index -= j * nx

return array_index + 1, j + 1, k + 1


def make_summary_key(
keyword: str,
number: int,
name: str,
nx: int,
ny: int,
lgr_name: Optional[str] = None,
li: Optional[int] = None,
lj: Optional[int] = None,
lk: Optional[int] = None,
) -> List[str]:
sum_type = _SummaryType.from_keyword(keyword)
if sum_type in [
_SummaryType.FIELD,
_SummaryType.OTHER,
]:
return [f"{keyword}"]
if sum_type in [
_SummaryType.REGION,
_SummaryType.AQUIFER,
]:
return [f"{keyword}:{number}"]
if sum_type == _SummaryType.BLOCK:
i, j, k = _cell_index(number - 1, nx, ny)
return [f"{keyword}:{number}", f"{keyword}:{i},{j},{k}"]
if sum_type in [
_SummaryType.GROUP,
_SummaryType.WELL,
]:
return [f"{keyword}:{name}"]
if sum_type == _SummaryType.SEGMENT:
return [f"{keyword}:{name}:{number}"]
if sum_type == _SummaryType.COMPLETION:
i, j, k = _cell_index(number - 1, nx, ny)
return [f"{keyword}:{name}:{number}", f"{keyword}:{name}:{i},{j},{k}"]
if sum_type == _SummaryType.INTER_REGION:
r1 = number % 32768
r2 = ((number - r1) // 32768) - 10
return [f"{keyword}:{number}", f"{keyword}:{r1}-{r2}"]
if sum_type == _SummaryType.LOCAL_WELL:
return [f"{keyword}:{lgr_name}:{name}"]
if sum_type == _SummaryType.LOCAL_BLOCK:
return [f"{keyword}:{lgr_name}:{li},{lj},{lk}"]
if sum_type == _SummaryType.LOCAL_COMPLETION:
i, j, k = _cell_index(number - 1, nx, ny)
return [f"{keyword}:{lgr_name}:{name}:{li},{lj},{lk}"]
if sum_type == _SummaryType.NETWORK:
return []
raise ValueError(f"Unexpected keyword type: {sum_type}")


def read_summary(
filepath: str, fetch_keys: Sequence[str]
) -> Tuple[List[str], Sequence[datetime], Any]:
try:
summary = EclSum(
filepath,
include_restart=False,
lazy_load=False,
)
except IOError as e:
raise ValueError(
"Could not find SUMMARY file or using non unified SUMMARY "
f"file from: {filepath}.UNSMRY",
) from e

data = []
keys = []
c_time = summary.alloc_time_vector(True)
time_map = [t.datetime() for t in c_time]

user_summary_keys = set(fetch_keys)
for key in summary:
if not _should_load_summary_key(key, user_summary_keys):
continue
keys.append(key)
data.append(summary.numpy_vector(key))
return (keys, time_map, data)


def _should_load_summary_key(data_key: Any, user_set_keys: set[str]) -> bool:
return any(fnmatch(data_key, key) for key in user_set_keys)
40 changes: 3 additions & 37 deletions src/ert/config/summary_config.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
from __future__ import annotations

import ctypes
import logging
from dataclasses import dataclass
from datetime import datetime
from fnmatch import fnmatch
from typing import TYPE_CHECKING, Set

import numpy as np
import xarray as xr
from ecl.summary import EclSum

from ._read_summary import read_summary
from .response_config import ResponseConfig

if TYPE_CHECKING:
from typing import Any, List, Optional
from typing import List, Optional, Set

Check failure on line 14 in src/ert/config/summary_config.py

View workflow job for this annotation

GitHub Actions / annotate-python-linting

redefinition of unused 'Set' from line 6


logger = logging.getLogger(__name__)
Expand All @@ -28,22 +25,8 @@ class SummaryConfig(ResponseConfig):

def read_from_file(self, run_path: str, iens: int) -> xr.Dataset:
filename = self.input_file.replace("<IENS>", str(iens))
try:
summary = EclSum(
f"{run_path}/{filename}",
include_restart=False,
lazy_load=False,
)
except IOError as e:
raise ValueError(
"Could not find SUMMARY file or using non unified SUMMARY "
f"file from: {run_path}/{filename}.UNSMRY",
) from e
keys, time_map, data = read_summary(f"{run_path}/{filename}", self.keys)

data = []
keys = []
c_time = summary.alloc_time_vector(True)
time_map = [t.datetime() for t in c_time]
if self.refcase:
missing = self.refcase.difference(time_map)
if missing:
Expand All @@ -55,24 +38,7 @@ def read_from_file(self, run_path: str, iens: int) -> xr.Dataset:
f"{last} from: {run_path}/{filename}.UNSMRY"
)

user_summary_keys = set(self.keys)
for key in summary:
if not self._should_load_summary_key(key, user_summary_keys):
continue
keys.append(key)

np_vector = np.zeros(len(time_map))
summary._init_numpy_vector_interp(
key,
c_time,
np_vector.ctypes.data_as(ctypes.POINTER(ctypes.c_double)),
)
data.append(np_vector)

return xr.Dataset(
{"values": (["name", "time"], data)},
coords={"time": time_map, "name": keys},
)

def _should_load_summary_key(self, data_key: Any, user_set_keys: set[str]) -> bool:
return any(fnmatch(data_key, key) for key in user_set_keys)
11 changes: 1 addition & 10 deletions tests/unit_tests/config/config_dict_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,16 +406,7 @@ def ert_config_values(draw, use_eclbase=booleans):
smspec = draw(
smspecs(
sum_keys=st.just(sum_keys),
start_date=st.just(
Date(
year=first_date.year,
month=first_date.month,
day=first_date.day,
hour=first_date.hour,
minutes=first_date.minute,
micro_seconds=first_date.second * 10**6 + first_date.microsecond,
)
),
start_date=st.just(Date.from_datetime(first_date)),
)
)
std_cutoff = draw(small_floats)
Expand Down
Loading

0 comments on commit adb6d21

Please sign in to comment.