Skip to content

Commit 9b0290d

Browse files
committed
rock WIP
1 parent 8cb4d7b commit 9b0290d

File tree

5 files changed

+160
-165
lines changed

5 files changed

+160
-165
lines changed

deepfield/field/base_component.py

Lines changed: 74 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
"""BaseCompoment."""
2-
from abc import abstractmethod
2+
from __future__ import annotations
33
import os
44
from copy import deepcopy
55
from weakref import ref
66
import numpy as np
77
import h5py
88

9-
from deepfield.field.parse_utils.ecl_binary import read_ecl_bin
10-
11-
from .utils import get_single_path
12-
139
from .decorators import apply_to_each_input
1410
from .parse_utils import read_array
1511

12+
from typing import TYPE_CHECKING, Callable, Sequence, TypedDict, override
13+
14+
if TYPE_CHECKING:
15+
from .field import Field
16+
17+
class DumpDict(TypedDict):
18+
attributes: Sequence[Attribute]
19+
state: State
20+
field: Field | None
21+
1622
class Attribute():
17-
def __init__(self, name=None, section=None, kw=None, custom_loader=None, postprocess=None, not_present=None,
23+
def __init__(self, name: str | None=None, section=None, kw=None, custom_loader=None, postprocess=None, not_present=None,
1824
binary_file=None, binary_section=None, binary_process=None):
1925

2026
if name is not None:
21-
self.name = name
27+
self.name: str = name
2228
else:
2329
if kw is None:
2430
raise ValueError('Either name or section should be provided.')
@@ -42,16 +48,19 @@ def __init__(self, name=None, section=None, kw=None, custom_loader=None, postpro
4248
self._binary_file = binary_file
4349
self._binary_section = binary_section
4450
self._binary_process = binary_process
51+
self._component: Callable[[], BaseComponent | None] | None = None
4552

4653
def _load_value(self, data, binary_data, logger):
54+
if self.component is None:
55+
raise ValueError('Attribute should be associated with `BaseComponent` object.')
4756
if self._binary_file is not None:
4857
val = self._load_ecl_binary_value(binary_data, logger)
4958
else:
5059
val = None
5160
if val is not None:
5261
self._value = val
62+
self.component.state.binary_attributes.append(self.name)
5363
return self
54-
__import__('pdb').set_trace()
5564
if self._custom_loader is not None:
5665
self._value = self._custom_loader(data)
5766
return self
@@ -86,6 +95,18 @@ def value(self):
8695
@value.setter
8796
def value(self, value):
8897
self._value = value
98+
@property
99+
def component(self) -> BaseComponent | None:
100+
if self._component is None:
101+
return None
102+
else:
103+
return self._component()
104+
@component.setter
105+
def component(self, value: BaseComponent | None):
106+
if value is None:
107+
self._component = value
108+
return None
109+
self._component = ref(value)
89110

90111
MAX_STRLEN = 40
91112

@@ -108,24 +129,22 @@ def __repr__(self):
108129
class BaseComponent:
109130
"""Base class for components of geological model."""
110131

111-
_attributes_to_load = []
132+
_attributes_to_load: list[Attribute] = []
112133
def __init__(self, dump=None, field=None):
113134
self._field = None
114135
if dump is not None:
115136
self._attributes = dump['attributes']
116137
self.field = dump['field']
117138
self._state = dump['state']
139+
for att in self._attributes:
140+
att.component = self
118141
return None
119-
self._attributes = []
142+
self._attributes: list[Attribute] = []
120143
self._state = State()
121-
# self._class_name = kwargs.pop('class_name', self.__class__.__name__)
122144
self.field = field
123-
# for k, v in kwargs.items():
124-
# if k != 'field':
125-
# setattr(self, k, v)
126145

127146
@property
128-
def field(self):
147+
def field(self) -> Field:
129148
"""Field associated with the component."""
130149
return self._field()
131150

@@ -139,22 +158,22 @@ def field(self, field):
139158
return self
140159

141160
@property
142-
def attributes(self):
161+
def attributes(self) -> Sequence[str]:
143162
"""Array of attributes."""
144163
return tuple((attr.name for attr in self._attributes))
145164

146165
@property
147166
def empty(self):
148167
"""True if component is empty else False."""
149-
return not self._data
168+
return not self._attributes
150169

151170
def keys(self):
152171
"""Array of attributes."""
153-
return self._data.keys()
172+
return (attr.name for attr in self._attributes)
154173

155174
def values(self):
156175
"""Returns a generator of attribute's data."""
157-
return self._data.values()
176+
return (attr.value for attr in self._attributes)
158177

159178
def items(self):
160179
"""Returns pairs of attribute's names and data."""
@@ -202,7 +221,7 @@ def __getattr__(self, key):
202221
if key.upper() == attr.name:
203222
return attr.value
204223
raise AttributeError("{} has no attribute {}".format(self.class_name, key))
205-
def dump_dict(self):
224+
def dump_dict(self) -> DumpDict:
206225
return {
207226
'attributes': deepcopy(self._attributes),
208227
'field': self.field,
@@ -218,22 +237,23 @@ def __setattr__(self, key, value):
218237
for att in self._attributes:
219238
if key == att.name:
220239
att.value = value
221-
return None
240+
return None
222241
raise AttributeError(f'{self.class_name} has no attribute {key}.')
223242

224243
def __setitem__(self, key, value):
225244
return setattr(self, key, value)
226245

227-
def __delattr__(self, key):
228-
if key.upper() in self._data:
229-
del self._data[key.upper()]
246+
@override
247+
def __delattr__(self, key: str):
248+
if key.upper() in self.attributes:
249+
self._attributes = [att for att in self._attributes if att.name != key.upper()]
230250
else:
231-
raise AttributeError("{} has no attribute {}".format(self.class_name, key))
251+
raise AttributeError(f"{self.class_name} has no attribute {key}")
232252

233-
def __delitem__(self, key):
253+
def __delitem__(self, key: str):
234254
return delattr(self, key)
235255

236-
def __contains__(self, x):
256+
def __contains__(self, x: str):
237257
return x.upper() in self.attributes
238258

239259
def copy(self):
@@ -332,40 +352,41 @@ def _get_fmt_loader(self, fmt):
332352
return self._load_hdf5
333353
raise NotImplementedError('File format .%s is not supported.' % fmt.upper())
334354

335-
def load(self, path_or_buffer, **kwargs):
336-
"""Load data from a file or buffer.
337-
338-
Parameters
339-
----------
340-
path_or_buffer : str of string buffer
341-
Source to read data from.
342-
**kwargs : dict, optional
343-
Any kwargs to be passed to load method.
344-
345-
Returns
346-
-------
347-
comp : BaseComponent
348-
BaseComponent with loaded attributes.
349-
"""
350-
__import__('ipdb').set_trace()
351-
if isinstance(path_or_buffer, str):
352-
if os.path.isdir(path_or_buffer):
353-
return self._load_ecl_binary(path_or_buffer, **kwargs)
354-
name = os.path.basename(path_or_buffer)
355-
fmt = os.path.splitext(name)[1].strip('.')
356-
return self._get_fmt_loader(fmt)(path_or_buffer, **kwargs)
357-
return self._read_buffer(path_or_buffer, **kwargs)
355+
# def load(self, path_or_buffer, **kwargs):
356+
# """Load data from a file or buffer.
357+
#
358+
# Parameters
359+
# ----------
360+
# path_or_buffer : str of string buffer
361+
# Source to read data from.
362+
# **kwargs : dict, optional
363+
# Any kwargs to be passed to load method.
364+
#
365+
# Returns
366+
# -------
367+
# comp : BaseComponent
368+
# BaseComponent with loaded attributes.
369+
# """
370+
# __import__('ipdb').set_trace()
371+
# if isinstance(path_or_buffer, str):
372+
# if os.path.isdir(path_or_buffer):
373+
# return self._load_ecl_binary(path_or_buffer, **kwargs)
374+
# name = os.path.basename(path_or_buffer)
375+
# fmt = os.path.splitext(name)[1].strip('.')
376+
# return self._get_fmt_loader(fmt)(path_or_buffer, **kwargs)
377+
# return self._read_buffer(path_or_buffer, **kwargs)
358378

359379
def load(self, data, binary_data, logger):
360380
"""Load data."""
361381
self._attributes = deepcopy(self._attributes_to_load)
362382
for attr in self._attributes:
383+
attr.component = self
363384
attr.load(data, binary_data, logger)
364385

365386

366-
def _load_ecl_binary(self, path_to_results, **kwargs):
367-
"""Load data from RESULTS derictory."""
368-
raise NotImplementedError('Load from binary files is not implemented.')
387+
# def _load_ecl_binary(self, path_to_results, **kwargs):
388+
# """Load data from RESULTS derictory."""
389+
# raise NotImplementedError('Load from binary files is not implemented.')
369390

370391
def _load_hdf5(self, path, attrs=None, raise_errors=False, logger=None, subset=None, **kwargs):
371392
"""Load data from a HDF5 file.
@@ -592,48 +613,3 @@ def _dump_ascii(self, path, attrs=None, mode='w', fmt='%f', compressed=True, **k
592613
self.dump_array_ascii(f, data, header=attr.upper(),
593614
fmt=fmt, compressed=compressed)
594615
return self
595-
596-
@staticmethod
597-
def dump_array_ascii(buffer, array, header=None, fmt='%f', compressed=True):
598-
"""Writes array-like data into an ASCII buffer.
599-
600-
Parameters
601-
----------
602-
buffer : buffer-like
603-
array : 1d, array-like
604-
Array to be saved
605-
header : str, optional
606-
String to be written line before the array
607-
fmt : str or sequence of strs, optional
608-
Format to be passed into ``numpy.savetxt`` function. Default to '%f'.
609-
compressed : bool
610-
If True, uses compressed typing style
611-
"""
612-
if header is not None:
613-
buffer.write(header + '\n')
614-
615-
if compressed:
616-
i = 0
617-
items_written = 0
618-
while i < len(array):
619-
count = 1
620-
while (i + count < len(array)) and (array[i + count] == array[i]):
621-
count += 1
622-
if count <= 4:
623-
buffer.write(' '.join([fmt % array[i]] * count))
624-
items_written += count
625-
else:
626-
buffer.write(str(count) + '*' + fmt % array[i])
627-
items_written += 1
628-
i += count
629-
if items_written > MAX_STRLEN:
630-
buffer.write('\n')
631-
items_written = 0
632-
else:
633-
buffer.write(' ')
634-
buffer.write('/\n')
635-
else:
636-
for i in range(0, len(array), MAX_STRLEN):
637-
buffer.write(' '.join([fmt % d for d in array[i:i + MAX_STRLEN]]))
638-
buffer.write('\n')
639-
buffer.write('/\n')

deepfield/field/base_spatial.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ def to_spatial(self, attr=None, **kwargs):
100100
return self
101101

102102
@apply_to_each_input
103-
def _to_spatial(self, attr, **kwargs):
103+
def _to_spatial(self, attr: str):
104104
"""Spatial transformations."""
105-
_ = self, attr, kwargs
105+
_ = self, attr
106106
raise NotImplementedError()
107107

108108
def _make_data_dump(self, attr, fmt=None, **kwargs):

deepfield/field/field.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ class Field:
100100
Log level to be printed while loading. Default to 'INFO'.
101101
"""
102102
_default_config = default_config
103-
def __init__(self, path=None, config=None, logfile=None, encoding='auto', loglevel='INFO'):
104-
self._path = preprocess_path(path) if path is not None else None
103+
def __init__(self, path: pathlib.Path | None=None, config=None, logfile=None, encoding='auto', loglevel='INFO'):
104+
self._path: pathlib.Path | None = preprocess_path(path) if path is not None else None
105105
self._encoding = encoding
106106
self._components = {}
107107
self._config = None
@@ -113,6 +113,7 @@ def __init__(self, path=None, config=None, logfile=None, encoding='auto', loglev
113113
'MODEL_TYPE': '',
114114
'HUNITS': DEFAULT_HUNITS['METRIC']}
115115
self._state = FieldState(self)
116+
self._data = resdp.DataType
116117

117118
logging.shutdown()
118119
handlers = [logging.StreamHandler(sys.stdout)]
@@ -329,6 +330,8 @@ def load(self, raise_errors=False, include_binary=True):
329330
out : Field
330331
Field with loaded components.
331332
"""
333+
if self._path is None:
334+
raise ValueError('Path to model is not defined.')
332335
name = os.path.basename(self._path)
333336
fmt = os.path.splitext(name)[1].strip('.')
334337

0 commit comments

Comments
 (0)