xtgeo 4.14.1__cp313-cp313-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cxtgeo.py +558 -0
- cxtgeoPYTHON_wrap.c +19537 -0
- xtgeo/__init__.py +248 -0
- xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
- xtgeo/_internal.cp313-win_amd64.pyd +0 -0
- xtgeo/common/__init__.py +19 -0
- xtgeo/common/_angles.py +29 -0
- xtgeo/common/_xyz_enum.py +50 -0
- xtgeo/common/calc.py +396 -0
- xtgeo/common/constants.py +30 -0
- xtgeo/common/exceptions.py +42 -0
- xtgeo/common/log.py +93 -0
- xtgeo/common/sys.py +166 -0
- xtgeo/common/types.py +18 -0
- xtgeo/common/version.py +34 -0
- xtgeo/common/xtgeo_dialog.py +604 -0
- xtgeo/cube/__init__.py +9 -0
- xtgeo/cube/_cube_export.py +214 -0
- xtgeo/cube/_cube_import.py +532 -0
- xtgeo/cube/_cube_roxapi.py +180 -0
- xtgeo/cube/_cube_utils.py +287 -0
- xtgeo/cube/_cube_window_attributes.py +273 -0
- xtgeo/cube/cube1.py +1023 -0
- xtgeo/grid3d/__init__.py +15 -0
- xtgeo/grid3d/_ecl_grid.py +778 -0
- xtgeo/grid3d/_ecl_inte_head.py +152 -0
- xtgeo/grid3d/_ecl_logi_head.py +71 -0
- xtgeo/grid3d/_ecl_output_file.py +81 -0
- xtgeo/grid3d/_egrid.py +1004 -0
- xtgeo/grid3d/_find_gridprop_in_eclrun.py +625 -0
- xtgeo/grid3d/_grdecl_format.py +309 -0
- xtgeo/grid3d/_grdecl_grid.py +400 -0
- xtgeo/grid3d/_grid3d.py +29 -0
- xtgeo/grid3d/_grid3d_fence.py +284 -0
- xtgeo/grid3d/_grid3d_utils.py +228 -0
- xtgeo/grid3d/_grid_boundary.py +76 -0
- xtgeo/grid3d/_grid_etc1.py +1683 -0
- xtgeo/grid3d/_grid_export.py +222 -0
- xtgeo/grid3d/_grid_hybrid.py +50 -0
- xtgeo/grid3d/_grid_import.py +79 -0
- xtgeo/grid3d/_grid_import_ecl.py +101 -0
- xtgeo/grid3d/_grid_import_roff.py +135 -0
- xtgeo/grid3d/_grid_import_xtgcpgeom.py +375 -0
- xtgeo/grid3d/_grid_refine.py +258 -0
- xtgeo/grid3d/_grid_roxapi.py +292 -0
- xtgeo/grid3d/_grid_translate_coords.py +154 -0
- xtgeo/grid3d/_grid_wellzone.py +165 -0
- xtgeo/grid3d/_gridprop_export.py +202 -0
- xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
- xtgeo/grid3d/_gridprop_import_grdecl.py +132 -0
- xtgeo/grid3d/_gridprop_import_roff.py +52 -0
- xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
- xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
- xtgeo/grid3d/_gridprop_op1.py +272 -0
- xtgeo/grid3d/_gridprop_roxapi.py +301 -0
- xtgeo/grid3d/_gridprop_value_init.py +140 -0
- xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
- xtgeo/grid3d/_gridprops_import_roff.py +83 -0
- xtgeo/grid3d/_roff_grid.py +470 -0
- xtgeo/grid3d/_roff_parameter.py +303 -0
- xtgeo/grid3d/grid.py +3010 -0
- xtgeo/grid3d/grid_properties.py +699 -0
- xtgeo/grid3d/grid_property.py +1313 -0
- xtgeo/grid3d/types.py +15 -0
- xtgeo/interfaces/rms/__init__.py +18 -0
- xtgeo/interfaces/rms/_regular_surface.py +460 -0
- xtgeo/interfaces/rms/_rms_base.py +100 -0
- xtgeo/interfaces/rms/_rmsapi_package.py +69 -0
- xtgeo/interfaces/rms/rmsapi_utils.py +438 -0
- xtgeo/io/__init__.py +1 -0
- xtgeo/io/_file.py +603 -0
- xtgeo/metadata/__init__.py +17 -0
- xtgeo/metadata/metadata.py +435 -0
- xtgeo/roxutils/__init__.py +7 -0
- xtgeo/roxutils/_roxar_loader.py +54 -0
- xtgeo/roxutils/_roxutils_etc.py +122 -0
- xtgeo/roxutils/roxutils.py +207 -0
- xtgeo/surface/__init__.py +20 -0
- xtgeo/surface/_regsurf_boundary.py +26 -0
- xtgeo/surface/_regsurf_cube.py +210 -0
- xtgeo/surface/_regsurf_cube_window.py +391 -0
- xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
- xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
- xtgeo/surface/_regsurf_export.py +388 -0
- xtgeo/surface/_regsurf_grid3d.py +275 -0
- xtgeo/surface/_regsurf_gridding.py +347 -0
- xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
- xtgeo/surface/_regsurf_import.py +347 -0
- xtgeo/surface/_regsurf_lowlevel.py +122 -0
- xtgeo/surface/_regsurf_oper.py +538 -0
- xtgeo/surface/_regsurf_utils.py +81 -0
- xtgeo/surface/_surfs_import.py +43 -0
- xtgeo/surface/_zmap_parser.py +138 -0
- xtgeo/surface/regular_surface.py +3043 -0
- xtgeo/surface/surfaces.py +276 -0
- xtgeo/well/__init__.py +24 -0
- xtgeo/well/_blockedwell_roxapi.py +241 -0
- xtgeo/well/_blockedwells_roxapi.py +68 -0
- xtgeo/well/_well_aux.py +30 -0
- xtgeo/well/_well_io.py +327 -0
- xtgeo/well/_well_oper.py +483 -0
- xtgeo/well/_well_roxapi.py +304 -0
- xtgeo/well/_wellmarkers.py +486 -0
- xtgeo/well/_wells_utils.py +158 -0
- xtgeo/well/blocked_well.py +220 -0
- xtgeo/well/blocked_wells.py +134 -0
- xtgeo/well/well1.py +1516 -0
- xtgeo/well/wells.py +211 -0
- xtgeo/xyz/__init__.py +6 -0
- xtgeo/xyz/_polygons_oper.py +272 -0
- xtgeo/xyz/_xyz.py +758 -0
- xtgeo/xyz/_xyz_data.py +646 -0
- xtgeo/xyz/_xyz_io.py +737 -0
- xtgeo/xyz/_xyz_lowlevel.py +42 -0
- xtgeo/xyz/_xyz_oper.py +613 -0
- xtgeo/xyz/_xyz_roxapi.py +766 -0
- xtgeo/xyz/points.py +698 -0
- xtgeo/xyz/polygons.py +827 -0
- xtgeo-4.14.1.dist-info/METADATA +146 -0
- xtgeo-4.14.1.dist-info/RECORD +122 -0
- xtgeo-4.14.1.dist-info/WHEEL +5 -0
- xtgeo-4.14.1.dist-info/licenses/LICENSE.md +165 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""GridProperty export functions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import io
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import struct
|
|
9
|
+
from contextlib import ExitStack
|
|
10
|
+
from typing import IO, TYPE_CHECKING, Any, Literal
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import resfo
|
|
14
|
+
import roffio
|
|
15
|
+
|
|
16
|
+
from xtgeo.common.exceptions import InvalidFileFormatError
|
|
17
|
+
from xtgeo.common.log import null_logger
|
|
18
|
+
from xtgeo.io._file import FileFormat, FileWrapper
|
|
19
|
+
|
|
20
|
+
from ._grdecl_format import run_length_encoding
|
|
21
|
+
from ._roff_parameter import RoffParameter
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
import numpy.typing as npt
|
|
25
|
+
|
|
26
|
+
from xtgeo.common.types import FileLike
|
|
27
|
+
|
|
28
|
+
from .grid_property import GridProperty
|
|
29
|
+
|
|
30
|
+
logger = null_logger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def to_file(
|
|
34
|
+
gridprop: GridProperty,
|
|
35
|
+
pfile: FileLike,
|
|
36
|
+
fformat: Literal["roff", "roffasc", "grdecl", "bgrdecl", "xtgcpprop"] = "roff",
|
|
37
|
+
name: str | None = None,
|
|
38
|
+
append: bool = False,
|
|
39
|
+
dtype: type[np.float32] | type[np.float64] | type[np.int32] | None = None,
|
|
40
|
+
fmt: str | None = None,
|
|
41
|
+
rle: bool = False,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""Export the grid property to file."""
|
|
44
|
+
logger.debug("Export property to file %s as %s", pfile, fformat)
|
|
45
|
+
|
|
46
|
+
binary = fformat in (
|
|
47
|
+
FileFormat.ROFF_BINARY.value + FileFormat.BGRDECL.value + ["xtgcpprop"]
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if not name:
|
|
51
|
+
name = gridprop.name or ""
|
|
52
|
+
|
|
53
|
+
xtg_file = FileWrapper(pfile, mode="rb")
|
|
54
|
+
xtg_file.check_folder(raiseerror=OSError)
|
|
55
|
+
|
|
56
|
+
if fformat in FileFormat.ROFF_BINARY.value + FileFormat.ROFF_ASCII.value:
|
|
57
|
+
_export_roff(gridprop, xtg_file.name, name, binary, append=append)
|
|
58
|
+
elif fformat in FileFormat.GRDECL.value + FileFormat.BGRDECL.value:
|
|
59
|
+
_export_grdecl(
|
|
60
|
+
gridprop,
|
|
61
|
+
xtg_file.name,
|
|
62
|
+
name,
|
|
63
|
+
dtype=dtype or np.int32 if gridprop.isdiscrete else np.float32,
|
|
64
|
+
append=append,
|
|
65
|
+
binary=binary,
|
|
66
|
+
fmt=fmt,
|
|
67
|
+
rle=rle,
|
|
68
|
+
)
|
|
69
|
+
elif fformat == "xtgcpprop":
|
|
70
|
+
_export_xtgcpprop(gridprop, xtg_file.name)
|
|
71
|
+
else:
|
|
72
|
+
extensions = FileFormat.extensions_string(
|
|
73
|
+
[
|
|
74
|
+
FileFormat.ROFF_BINARY,
|
|
75
|
+
FileFormat.ROFF_ASCII,
|
|
76
|
+
FileFormat.GRDECL,
|
|
77
|
+
FileFormat.BGRDECL,
|
|
78
|
+
]
|
|
79
|
+
)
|
|
80
|
+
raise InvalidFileFormatError(
|
|
81
|
+
f"File format {fformat} is invalid for type GridProperty. "
|
|
82
|
+
f"Supported formats are {extensions}."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _export_roff(
|
|
87
|
+
gridprop: GridProperty,
|
|
88
|
+
pfile: str | io.BytesIO | io.StringIO,
|
|
89
|
+
name: str,
|
|
90
|
+
binary: bool,
|
|
91
|
+
append: bool = False,
|
|
92
|
+
) -> None:
|
|
93
|
+
if append:
|
|
94
|
+
logger.warning(
|
|
95
|
+
"Append is not implemented for roff format, defaulting to write."
|
|
96
|
+
)
|
|
97
|
+
roff = RoffParameter.from_xtgeo_grid_property(gridprop)
|
|
98
|
+
roff.name = name
|
|
99
|
+
roff.to_file(pfile, roffio.Format.BINARY if binary else roffio.Format.ASCII)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _export_grdecl(
|
|
103
|
+
gridprop: GridProperty,
|
|
104
|
+
pfile: str | io.BytesIO | io.StringIO,
|
|
105
|
+
name: str,
|
|
106
|
+
dtype: type[np.float32] | type[np.float64] | type[np.int32],
|
|
107
|
+
append: bool = False,
|
|
108
|
+
binary: bool = False,
|
|
109
|
+
fmt: str | None = None,
|
|
110
|
+
rle: bool = False,
|
|
111
|
+
) -> None:
|
|
112
|
+
"""Export ascii or binary GRDECL"""
|
|
113
|
+
vals: npt.NDArray = gridprop.values.ravel(order="F")
|
|
114
|
+
if np.ma.isMaskedArray(vals):
|
|
115
|
+
undef_export = 1 if gridprop.isdiscrete or "int" in str(dtype) else 0.0
|
|
116
|
+
vals = np.ma.filled(vals, fill_value=undef_export)
|
|
117
|
+
|
|
118
|
+
mode = "a" if append else "w"
|
|
119
|
+
if binary:
|
|
120
|
+
mode += "b"
|
|
121
|
+
|
|
122
|
+
with ExitStack() as stack:
|
|
123
|
+
fout = (
|
|
124
|
+
stack.enter_context(open(pfile, mode)) if isinstance(pfile, str) else pfile
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if append:
|
|
128
|
+
fout.seek(os.SEEK_END)
|
|
129
|
+
|
|
130
|
+
if binary:
|
|
131
|
+
resfo.write(
|
|
132
|
+
fout,
|
|
133
|
+
[(name.ljust(8), vals.astype(dtype))],
|
|
134
|
+
fileformat=resfo.Format.UNFORMATTED,
|
|
135
|
+
)
|
|
136
|
+
else:
|
|
137
|
+
# Always the case when not binary
|
|
138
|
+
assert isinstance(fout, io.TextIOWrapper)
|
|
139
|
+
fout.write(f"{name}\n")
|
|
140
|
+
if rle:
|
|
141
|
+
counts, unique_values = run_length_encoding(vals)
|
|
142
|
+
for i, (count, unique_value) in enumerate(zip(counts, unique_values)):
|
|
143
|
+
fout.write(" ")
|
|
144
|
+
if fmt:
|
|
145
|
+
formatted_value = fmt % unique_value
|
|
146
|
+
elif gridprop.isdiscrete:
|
|
147
|
+
formatted_value = str(unique_value)
|
|
148
|
+
else:
|
|
149
|
+
formatted_value = f"{unique_value:3e}"
|
|
150
|
+
if count > 1:
|
|
151
|
+
# Try to preserve the alignment
|
|
152
|
+
text_width = len(formatted_value)
|
|
153
|
+
new_text = f"{count}*{formatted_value.lstrip()}"
|
|
154
|
+
formatted_value = " " * (text_width - len(new_text)) + new_text
|
|
155
|
+
fout.write(formatted_value)
|
|
156
|
+
if i % 6 == 5:
|
|
157
|
+
fout.write("\n")
|
|
158
|
+
else:
|
|
159
|
+
for i, v in enumerate(vals):
|
|
160
|
+
fout.write(" ")
|
|
161
|
+
if fmt:
|
|
162
|
+
fout.write(fmt % v)
|
|
163
|
+
elif gridprop.isdiscrete:
|
|
164
|
+
fout.write(str(v))
|
|
165
|
+
else:
|
|
166
|
+
fout.write(f"{v:3e}")
|
|
167
|
+
if i % 6 == 5:
|
|
168
|
+
fout.write("\n")
|
|
169
|
+
fout.write(" /\n")
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _export_xtgcpprop(
|
|
173
|
+
gridprop: GridProperty, pfile: str | io.BytesIO | io.StringIO
|
|
174
|
+
) -> None:
|
|
175
|
+
"""Export to experimental xtgcpproperty format, python version."""
|
|
176
|
+
logger.debug("Export as xtgcpprop...")
|
|
177
|
+
gridprop._metadata.required = gridprop
|
|
178
|
+
|
|
179
|
+
magic = 1352 if gridprop.isdiscrete else 1351
|
|
180
|
+
prevalues = (1, magic, 4, gridprop.ncol, gridprop.nrow, gridprop.nlay)
|
|
181
|
+
mystruct = struct.Struct("= i i i q q q")
|
|
182
|
+
pre = mystruct.pack(*prevalues)
|
|
183
|
+
|
|
184
|
+
meta = gridprop.metadata.get_metadata()
|
|
185
|
+
|
|
186
|
+
# Convert StringIO to BytesIO as this is a binary format
|
|
187
|
+
with ExitStack() as stack:
|
|
188
|
+
if isinstance(pfile, io.StringIO):
|
|
189
|
+
data = pfile.getvalue().encode("utf-8")
|
|
190
|
+
fout: IO[Any] = io.BytesIO(data)
|
|
191
|
+
elif isinstance(pfile, io.BytesIO):
|
|
192
|
+
fout = pfile
|
|
193
|
+
else:
|
|
194
|
+
fout = stack.enter_context(open(pfile, "wb"))
|
|
195
|
+
fout.write(pre)
|
|
196
|
+
gridprop.get_npvalues1d(fill_value=gridprop.undef).astype(np.float32).tofile(
|
|
197
|
+
fout
|
|
198
|
+
)
|
|
199
|
+
fout.write("\nXTGMETA.v01\n".encode())
|
|
200
|
+
fout.write(json.dumps(meta).encode())
|
|
201
|
+
|
|
202
|
+
logger.debug("Export as xtgcpprop... done")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
4
|
+
|
|
5
|
+
import resfo
|
|
6
|
+
|
|
7
|
+
from xtgeo.io._file import FileFormat
|
|
8
|
+
|
|
9
|
+
from ._find_gridprop_in_eclrun import (
|
|
10
|
+
find_gridprop_from_init_file,
|
|
11
|
+
find_gridprops_from_restart_file,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from xtgeo.io._file import FileWrapper
|
|
16
|
+
|
|
17
|
+
from .grid import Grid
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def decorate_name(
|
|
21
|
+
name: str, dual_porosity: bool, fracture: bool, date: int | None = None
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Decorate a property name with date and matrix/fracture.
|
|
24
|
+
|
|
25
|
+
>>> decorate_name('PORO', True, False, 19991231)
|
|
26
|
+
'POROM_19991231'
|
|
27
|
+
"""
|
|
28
|
+
decorated_name = name
|
|
29
|
+
if dual_porosity:
|
|
30
|
+
if fracture:
|
|
31
|
+
decorated_name += "F"
|
|
32
|
+
else:
|
|
33
|
+
decorated_name += "M"
|
|
34
|
+
|
|
35
|
+
if date is not None:
|
|
36
|
+
decorated_name += "_" + str(date)
|
|
37
|
+
return decorated_name
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def import_gridprop_from_init(
|
|
41
|
+
pfile: FileWrapper, name: str, grid: Grid, fracture: bool = False
|
|
42
|
+
) -> dict[str, Any]:
|
|
43
|
+
"""Import one parameter with the given name from an init file.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
pfile: The init file.
|
|
47
|
+
name: The name of the parmaeter
|
|
48
|
+
grid: The grid used by the simulator to produce the init file.
|
|
49
|
+
fracture: If a dual porosity module, indicates that the fracture
|
|
50
|
+
(as apposed to the matrix) grid property should be imported.
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ValueError: If the parameter does not exist in the file.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
GridProperty parameter dictionary.
|
|
57
|
+
"""
|
|
58
|
+
init_props = find_gridprop_from_init_file(pfile.file, [name], grid, fracture)
|
|
59
|
+
if len(init_props) != 1:
|
|
60
|
+
raise ValueError(f"Could not find property {name} in {pfile}")
|
|
61
|
+
init_props[0]["name"] = decorate_name(
|
|
62
|
+
init_props[0]["name"], grid.dualporo, fracture
|
|
63
|
+
)
|
|
64
|
+
return init_props[0]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def sanitize_date(
|
|
68
|
+
date: int | str | Literal["first", "last"],
|
|
69
|
+
) -> list[int] | Literal["first", "last"]:
|
|
70
|
+
"""
|
|
71
|
+
Converts dateformats of the form 'YYYY-MM-DD', 'YYYYMMDD' or YYYYMMDD to
|
|
72
|
+
list of integers of the form [YYYYMMDD] (ie. suitible for find_gridprops
|
|
73
|
+
functions), but lets the special literals 'first' and 'last' remain
|
|
74
|
+
unchanged.
|
|
75
|
+
|
|
76
|
+
>>> sanitize_date('first')
|
|
77
|
+
'first'
|
|
78
|
+
>>> sanitize_date('last')
|
|
79
|
+
'last'
|
|
80
|
+
>>> sanitize_date('2020-01-01')
|
|
81
|
+
[20200101]
|
|
82
|
+
>>> sanitize_date('20200101')
|
|
83
|
+
[20200101]
|
|
84
|
+
>>> sanitize_date(20200101)
|
|
85
|
+
[20200101]
|
|
86
|
+
"""
|
|
87
|
+
if isinstance(date, int):
|
|
88
|
+
return [date]
|
|
89
|
+
if date not in ("first", "last"):
|
|
90
|
+
try:
|
|
91
|
+
if (
|
|
92
|
+
isinstance(date, str)
|
|
93
|
+
and len(date) == 10
|
|
94
|
+
and date[4] == "-"
|
|
95
|
+
and date[7] == "-"
|
|
96
|
+
):
|
|
97
|
+
date = date.replace("-", "")
|
|
98
|
+
return [int(date)]
|
|
99
|
+
except ValueError as err:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"valid dates are either of the "
|
|
102
|
+
"form 'YYYY-MM-DD', 'YYYYMMDD' or 'first'/'last' "
|
|
103
|
+
f"got {date}"
|
|
104
|
+
) from err
|
|
105
|
+
# Satisfy mypy that we're not returning a str
|
|
106
|
+
return "first" if date == "first" else "last"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def sanitize_fformat(fformat: FileFormat) -> resfo.Format:
|
|
110
|
+
"""Converts 'unrst' and 'funrst' to the corresponding resfo.Format.
|
|
111
|
+
|
|
112
|
+
>>> sanitize_fformat('unrst')
|
|
113
|
+
<Format.UNFORMATTED: 2>
|
|
114
|
+
>>> sanitize_fformat('funrst')
|
|
115
|
+
<Format.FORMATTED: 1>
|
|
116
|
+
"""
|
|
117
|
+
if fformat == FileFormat.UNRST:
|
|
118
|
+
return resfo.Format.UNFORMATTED
|
|
119
|
+
if fformat == FileFormat.FUNRST:
|
|
120
|
+
return resfo.Format.FORMATTED
|
|
121
|
+
raise ValueError(f"fformat must be either 'unrst' or 'funrst' got {fformat}")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def import_gridprop_from_restart(
|
|
125
|
+
pfile: FileWrapper,
|
|
126
|
+
name: str,
|
|
127
|
+
grid: Grid,
|
|
128
|
+
date: int | str | Literal["first", "last"],
|
|
129
|
+
fracture: bool = False,
|
|
130
|
+
fformat: FileFormat = FileFormat.UNRST,
|
|
131
|
+
) -> dict[str, Any]:
|
|
132
|
+
"""Import one parameter for the given name and date in a restart file.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
pfile: The restart file.
|
|
136
|
+
name: The name of the parmaeter
|
|
137
|
+
date: xtgeo style date (e.g. int(19990101) or "YYYYMMDD"), also
|
|
138
|
+
accepts "YYYY-MM-DD". "last" and "first" can be given for
|
|
139
|
+
last or first date in the file
|
|
140
|
+
grid: The grid used by the simulator to produce the restart file.
|
|
141
|
+
fracture: If a dual porosity module, indicates that the fracture
|
|
142
|
+
(as apposed to the matrix) grid property should be imported.
|
|
143
|
+
Raises:
|
|
144
|
+
ValueError: If the parameter does not exist in the file.
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
GridProperty parameter dictionary.
|
|
148
|
+
"""
|
|
149
|
+
restart_props = find_gridprops_from_restart_file(
|
|
150
|
+
pfile.file,
|
|
151
|
+
[name],
|
|
152
|
+
sanitize_date(date),
|
|
153
|
+
grid,
|
|
154
|
+
fracture,
|
|
155
|
+
sanitize_fformat(fformat),
|
|
156
|
+
)
|
|
157
|
+
if len(restart_props) == 0:
|
|
158
|
+
raise ValueError(f"Could not find property {name} for {date} in {pfile.file}")
|
|
159
|
+
if len(restart_props) > 1:
|
|
160
|
+
raise ValueError(f"Ambiguous property {name} for {date} in {pfile.file}")
|
|
161
|
+
restart_props[0]["name"] = decorate_name(
|
|
162
|
+
restart_props[0]["name"], grid.dualporo, fracture, restart_props[0]["date"]
|
|
163
|
+
)
|
|
164
|
+
return restart_props[0]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Importing grid props from GRDECL, ascii or binary"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import numpy.ma as ma
|
|
9
|
+
import resfo
|
|
10
|
+
|
|
11
|
+
from xtgeo.common import null_logger
|
|
12
|
+
from xtgeo.common.exceptions import KeywordNotFoundError
|
|
13
|
+
|
|
14
|
+
from ._grdecl_format import match_keyword, open_grdecl
|
|
15
|
+
|
|
16
|
+
logger = null_logger(__name__)
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from xtgeo.common.types import FileLike
|
|
20
|
+
from xtgeo.io._file import FileWrapper
|
|
21
|
+
|
|
22
|
+
from .grid import Grid
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def import_bgrdecl_prop(pfile: FileWrapper, name: str, grid: Grid) -> dict[str, Any]:
|
|
26
|
+
"""Import prop for binary files with GRDECL layout.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
pfile (_XTgeoCFile): xtgeo file instance
|
|
30
|
+
name (str): Name of parameter.
|
|
31
|
+
grid (Grid()): XTGeo Grid instance.
|
|
32
|
+
|
|
33
|
+
Raises:
|
|
34
|
+
KeywordNotFoundError: Cannot find property...
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
GridProperty parameter dictionary.
|
|
38
|
+
"""
|
|
39
|
+
result: dict[str, Any] = {}
|
|
40
|
+
result["ncol"] = grid.ncol
|
|
41
|
+
result["nrow"] = grid.nrow
|
|
42
|
+
result["nlay"] = grid.nlay
|
|
43
|
+
result["name"] = name
|
|
44
|
+
result["filesrc"] = pfile
|
|
45
|
+
|
|
46
|
+
for entry in resfo.lazy_read(pfile.file):
|
|
47
|
+
if match_keyword(entry.read_keyword(), name):
|
|
48
|
+
values = entry.read_array()
|
|
49
|
+
if isinstance(values, resfo.MessType):
|
|
50
|
+
raise ValueError(f"Unexpected MESS value in {pfile.file}")
|
|
51
|
+
result["discrete"] = np.issubdtype(values.dtype, np.integer)
|
|
52
|
+
if result["discrete"]:
|
|
53
|
+
uniq = np.unique(values).tolist()
|
|
54
|
+
codes = dict(zip(uniq, uniq))
|
|
55
|
+
codes = {key: str(val) for key, val in codes.items()} # val: strings
|
|
56
|
+
result["codes"] = codes
|
|
57
|
+
values = values.astype(np.int32)
|
|
58
|
+
result["roxar_dtype"] = np.uint16
|
|
59
|
+
else:
|
|
60
|
+
values = values.astype(np.float64)
|
|
61
|
+
result["codes"] = {}
|
|
62
|
+
result["roxar_dtype"] = np.float32
|
|
63
|
+
result["values"] = ma.masked_where(
|
|
64
|
+
grid.get_actnum().values < 1, values.reshape(grid.dimensions, order="F")
|
|
65
|
+
)
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
raise KeywordNotFoundError(f"Cannot find property name {name} in file {pfile.name}")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def read_grdecl_3d_property(
|
|
72
|
+
filename: FileLike,
|
|
73
|
+
keyword: str,
|
|
74
|
+
dimensions: tuple[int, int, int],
|
|
75
|
+
dtype: type[float] | type[int] = float,
|
|
76
|
+
) -> np.ndarray:
|
|
77
|
+
"""
|
|
78
|
+
Read a 3d grid property from a grdecl file, see open_grdecl for description
|
|
79
|
+
of format.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
filename (pathlib.Path or str): File in grdecl format.
|
|
83
|
+
keyword (str): The keyword of the property in the file
|
|
84
|
+
dimensions ((int,int,int)): Triple of the size of grid.
|
|
85
|
+
dtype (function): The datatype to be read, ie., float.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
numpy array with given dimensions and data type read
|
|
89
|
+
from the grdecl file.
|
|
90
|
+
|
|
91
|
+
Raises:
|
|
92
|
+
KeywordNotFoundError: If keyword is not found in the file.
|
|
93
|
+
"""
|
|
94
|
+
with open_grdecl(filename, keywords=[], simple_keywords=[keyword]) as kw_generator:
|
|
95
|
+
try:
|
|
96
|
+
_, result = next(kw_generator)
|
|
97
|
+
except StopIteration as si:
|
|
98
|
+
raise KeywordNotFoundError(
|
|
99
|
+
f"Cannot import {keyword}, not present in file {filename}?"
|
|
100
|
+
) from si
|
|
101
|
+
|
|
102
|
+
# The values are stored in F order in the grdecl file
|
|
103
|
+
f_order_values = np.array([dtype(v) for v in result])
|
|
104
|
+
return np.ascontiguousarray(f_order_values.reshape(dimensions, order="F"))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def import_grdecl_prop(pfile: FileWrapper, name: str, grid: Grid) -> dict[str, Any]:
|
|
108
|
+
"""Import prop for ascii files with GRDECL layout.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
pfile (_XTgeoCFile): xtgeo file instance
|
|
112
|
+
name (str): Name of parameter.
|
|
113
|
+
grid (Grid()): XTGeo Grid instance.
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
KeywordNotFoundError: Cannot find property...
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
GridProperty parameter dictionary.
|
|
120
|
+
"""
|
|
121
|
+
result: dict[str, Any] = {}
|
|
122
|
+
result["ncol"] = grid.ncol
|
|
123
|
+
result["nrow"] = grid.nrow
|
|
124
|
+
result["nlay"] = grid.nlay
|
|
125
|
+
result["name"] = name
|
|
126
|
+
result["filesrc"] = pfile
|
|
127
|
+
actnumv = grid.get_actnum().values
|
|
128
|
+
|
|
129
|
+
result["values"] = ma.masked_where(
|
|
130
|
+
actnumv == 0, read_grdecl_3d_property(pfile.file, name, grid.dimensions, float)
|
|
131
|
+
)
|
|
132
|
+
return result
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Importing grid props from ROFF, binary"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
from xtgeo.common import null_logger
|
|
10
|
+
|
|
11
|
+
from ._roff_parameter import RoffParameter
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from xtgeo.grid3d import Grid
|
|
15
|
+
from xtgeo.io._file import FileWrapper
|
|
16
|
+
|
|
17
|
+
logger = null_logger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def import_roff(
|
|
21
|
+
pfile: FileWrapper,
|
|
22
|
+
name: str | None = None,
|
|
23
|
+
grid: Grid | None = None,
|
|
24
|
+
) -> dict[str, Any]:
|
|
25
|
+
"""Import ROFF format"""
|
|
26
|
+
result: dict[str, Any] = {}
|
|
27
|
+
roff_param = RoffParameter.from_file(pfile._file, name)
|
|
28
|
+
result["codes"] = roff_param.xtgeo_codes()
|
|
29
|
+
result["name"] = roff_param.name
|
|
30
|
+
result["ncol"] = int(roff_param.nx)
|
|
31
|
+
result["nrow"] = int(roff_param.ny)
|
|
32
|
+
result["nlay"] = int(roff_param.nz)
|
|
33
|
+
result["discrete"] = roff_param.is_discrete
|
|
34
|
+
result["values"] = roff_param.xtgeo_values()
|
|
35
|
+
|
|
36
|
+
if grid is not None and (actnum := grid.get_actnum()):
|
|
37
|
+
result["values"] = np.ma.masked_where(
|
|
38
|
+
actnum.values < 1,
|
|
39
|
+
result["values"],
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
roff_val = roff_param.values
|
|
43
|
+
if isinstance(roff_val, bytes) or np.issubdtype(roff_val.dtype, np.uint8):
|
|
44
|
+
result["roxar_dtype"] = np.uint8
|
|
45
|
+
elif np.issubdtype(roff_val.dtype, np.integer):
|
|
46
|
+
result["roxar_dtype"] = np.uint16
|
|
47
|
+
elif np.issubdtype(roff_val.dtype, np.floating):
|
|
48
|
+
result["roxar_dtype"] = np.float32
|
|
49
|
+
else:
|
|
50
|
+
raise ValueError(f"Could not deduce roxar type of {roff_val.dtype}")
|
|
51
|
+
|
|
52
|
+
return result
|