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,375 @@
|
|
|
1
|
+
"""Private module, Grid Import private functions for xtgeo based formats."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from struct import unpack
|
|
7
|
+
from typing import TYPE_CHECKING, Literal, Tuple, TypedDict, Union, overload
|
|
8
|
+
|
|
9
|
+
import h5py
|
|
10
|
+
import numpy as np
|
|
11
|
+
from typing_extensions import NotRequired, TypeAlias
|
|
12
|
+
|
|
13
|
+
import xtgeo.common.sys as xsys
|
|
14
|
+
from xtgeo.common import null_logger
|
|
15
|
+
from xtgeo.grid3d._gridprop_import_xtgcpprop import _read_filelike
|
|
16
|
+
|
|
17
|
+
logger = null_logger(__name__)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from xtgeo.io._file import FileWrapper
|
|
21
|
+
|
|
22
|
+
LMIN: TypeAlias = Literal["min"]
|
|
23
|
+
LMAX: TypeAlias = Literal["max"]
|
|
24
|
+
IJKRANGE: TypeAlias = Tuple[
|
|
25
|
+
Union[int, LMIN],
|
|
26
|
+
Union[int, LMAX],
|
|
27
|
+
Union[int, LMIN],
|
|
28
|
+
Union[int, LMAX],
|
|
29
|
+
Union[int, LMIN],
|
|
30
|
+
Union[int, LMAX],
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _RESULT(TypedDict):
|
|
35
|
+
coordsv: np.ndarray
|
|
36
|
+
zcornsv: np.ndarray
|
|
37
|
+
actnumsv: np.ndarray
|
|
38
|
+
subgrids: NotRequired[dict[str, range]]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class __REQUIRED_(TypedDict):
|
|
42
|
+
xshift: np.ndarray
|
|
43
|
+
xscale: np.ndarray
|
|
44
|
+
yshift: np.ndarray
|
|
45
|
+
yscale: np.ndarray
|
|
46
|
+
zshift: np.ndarray
|
|
47
|
+
zscale: np.ndarray
|
|
48
|
+
subgrids: NotRequired[dict[str, int]]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class _META(TypedDict):
|
|
52
|
+
_required_: __REQUIRED_
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@overload
|
|
56
|
+
def convert_subgrids(sdict: dict[str, int]) -> dict[str, range]: ...
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@overload
|
|
60
|
+
def convert_subgrids(sdict: None) -> None: ...
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def convert_subgrids(sdict: dict[str, int] | None) -> dict[str, range] | None:
|
|
64
|
+
# flake8: noqa: F841
|
|
65
|
+
"""Convert a simplified ordered dictionary to
|
|
66
|
+
subgrid required by Grid.
|
|
67
|
+
|
|
68
|
+
The simplified dictionary is on the form
|
|
69
|
+
{"name1": 3, "name2": 5}
|
|
70
|
+
|
|
71
|
+
Note that the input must be an dict!
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
if sdict is None:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
if not isinstance(sdict, dict):
|
|
78
|
+
raise ValueError("Input sdict is not an dict")
|
|
79
|
+
|
|
80
|
+
start = 1
|
|
81
|
+
return {name: range(start, start := start + nsub) for name, nsub in sdict.items()}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def handle_metadata(
|
|
85
|
+
result: _RESULT,
|
|
86
|
+
meta: _META,
|
|
87
|
+
ncol: int,
|
|
88
|
+
nrow: int,
|
|
89
|
+
nlay: int,
|
|
90
|
+
) -> None:
|
|
91
|
+
# meta _optional_ *may* contain xshift, xscale etc which in case must be taken
|
|
92
|
+
# into account
|
|
93
|
+
coordsv = result["coordsv"]
|
|
94
|
+
zcornsv = result["zcornsv"]
|
|
95
|
+
actnumsv = result["actnumsv"]
|
|
96
|
+
nncol = ncol + 1
|
|
97
|
+
nnrow = nrow + 1
|
|
98
|
+
nnlay = nlay + 1
|
|
99
|
+
req = meta["_required_"]
|
|
100
|
+
shi = req["xshift"]
|
|
101
|
+
coordsv[0::3] = np.where(shi != 0, coordsv[0::3] + shi, coordsv[0::3])
|
|
102
|
+
sca = req["xscale"]
|
|
103
|
+
coordsv[0::3] = np.where(sca != 1, coordsv[0::3] * sca, coordsv[0::3])
|
|
104
|
+
shi = req["yshift"]
|
|
105
|
+
coordsv[1::3] = np.where(shi != 0, coordsv[1::3] + shi, coordsv[1::3])
|
|
106
|
+
sca = req["yscale"]
|
|
107
|
+
coordsv[1::3] = np.where(sca != 1, coordsv[1::3] * sca, coordsv[1::3])
|
|
108
|
+
shi = req["zshift"]
|
|
109
|
+
coordsv[2::3] = np.where(shi != 0, coordsv[2::3] + shi, coordsv[2::3])
|
|
110
|
+
sca = req["zscale"]
|
|
111
|
+
coordsv[2::3] = np.where(sca != 1, coordsv[2::3] * sca, coordsv[2::3])
|
|
112
|
+
|
|
113
|
+
result["coordsv"] = coordsv.reshape((nncol, nnrow, 6)).astype(np.float64)
|
|
114
|
+
result["zcornsv"] = zcornsv.reshape((nncol, nnrow, nnlay, 4)).astype(np.float32)
|
|
115
|
+
result["actnumsv"] = actnumsv.reshape((ncol, nrow, nlay)).astype(np.int32)
|
|
116
|
+
|
|
117
|
+
if "subgrids" in req:
|
|
118
|
+
result["subgrids"] = convert_subgrids(req["subgrids"])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def import_xtgcpgeom(
|
|
122
|
+
mfile: FileWrapper,
|
|
123
|
+
mmap: bool = False,
|
|
124
|
+
) -> _RESULT:
|
|
125
|
+
"""Using pure python for experimental grid geometry import."""
|
|
126
|
+
#
|
|
127
|
+
offset = 36
|
|
128
|
+
with _read_filelike(mfile.file, size=offset) as f:
|
|
129
|
+
# unpack header
|
|
130
|
+
swap, magic, nformat, ncol, nrow, nlay = unpack("= i i i q q q", f)
|
|
131
|
+
|
|
132
|
+
nncol = ncol + 1
|
|
133
|
+
nnrow = nrow + 1
|
|
134
|
+
nnlay = nlay + 1
|
|
135
|
+
|
|
136
|
+
if swap != 1 or magic != 1301:
|
|
137
|
+
raise ValueError(f"Error, swap magic are {swap} {magic}, expected is 1 1301")
|
|
138
|
+
|
|
139
|
+
# subformat processing, indicating number of bytes per datatype
|
|
140
|
+
# here, 844 is native XTGeo (float64, float32, int32)
|
|
141
|
+
if nformat not in (444, 844, 841, 881, 884):
|
|
142
|
+
raise ValueError(f"The subformat value {nformat} is not valid")
|
|
143
|
+
|
|
144
|
+
coordfmt, zcornfmt, actnumfmt = [int(nbyte) for nbyte in str(nformat)]
|
|
145
|
+
|
|
146
|
+
dtype_coordsv = f"float{coordfmt * 8}"
|
|
147
|
+
dtype_zcornsv = f"float{zcornfmt * 8}"
|
|
148
|
+
dtype_actnumv = f"int{actnumfmt * 8}"
|
|
149
|
+
|
|
150
|
+
ncoord = nncol * nnrow * 6
|
|
151
|
+
nzcorn = nncol * nnrow * nnlay * 4
|
|
152
|
+
nactnum = ncol * nrow * nlay
|
|
153
|
+
|
|
154
|
+
# read numpy arrays from file
|
|
155
|
+
coordsv = xsys.npfromfile(
|
|
156
|
+
mfile.file,
|
|
157
|
+
dtype=dtype_coordsv,
|
|
158
|
+
count=ncoord,
|
|
159
|
+
offset=offset,
|
|
160
|
+
mmap=mmap,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
newoffset = offset + ncoord * coordfmt
|
|
164
|
+
zcornsv = xsys.npfromfile(
|
|
165
|
+
mfile.file,
|
|
166
|
+
dtype=dtype_zcornsv,
|
|
167
|
+
count=nzcorn,
|
|
168
|
+
offset=newoffset,
|
|
169
|
+
mmap=mmap,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
newoffset += nzcorn * zcornfmt
|
|
173
|
+
actnumsv = xsys.npfromfile(
|
|
174
|
+
mfile.file,
|
|
175
|
+
dtype=dtype_actnumv,
|
|
176
|
+
count=nactnum,
|
|
177
|
+
offset=newoffset,
|
|
178
|
+
mmap=mmap,
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
newoffset += nactnum * actnumfmt
|
|
182
|
+
result = _RESULT(coordsv=coordsv, zcornsv=zcornsv, actnumsv=actnumsv)
|
|
183
|
+
|
|
184
|
+
# read metadata which will be at position offet + nfloat*narr +13
|
|
185
|
+
with _read_filelike(mfile.file, seek=newoffset + 13) as f:
|
|
186
|
+
meta = json.loads(f, object_pairs_hook=dict)
|
|
187
|
+
|
|
188
|
+
handle_metadata(result, meta, ncol, nrow, nlay)
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def import_hdf5_cpgeom(
|
|
193
|
+
mfile: FileWrapper,
|
|
194
|
+
ijkrange: IJKRANGE | None = None,
|
|
195
|
+
zerobased: bool = False,
|
|
196
|
+
) -> _RESULT:
|
|
197
|
+
"""Experimental grid geometry import using hdf5."""
|
|
198
|
+
#
|
|
199
|
+
with h5py.File(mfile.name, "r") as h5h:
|
|
200
|
+
grp = h5h["CornerPointGeometry"]
|
|
201
|
+
|
|
202
|
+
idcode = grp.attrs["format-idcode"]
|
|
203
|
+
provider = grp.attrs["provider"]
|
|
204
|
+
if idcode != 1301:
|
|
205
|
+
raise ValueError(f"Wrong id code: {idcode}")
|
|
206
|
+
logger.info("Provider is %s", provider)
|
|
207
|
+
|
|
208
|
+
jmeta = grp.attrs["metadata"]
|
|
209
|
+
meta = json.loads(jmeta, object_pairs_hook=dict)
|
|
210
|
+
|
|
211
|
+
req = meta["_required_"]
|
|
212
|
+
ncol = req["ncol"]
|
|
213
|
+
nrow = req["nrow"]
|
|
214
|
+
nlay = req["nlay"]
|
|
215
|
+
|
|
216
|
+
if ijkrange is not None:
|
|
217
|
+
incoord, inzcorn, inactnum, ncol, nrow, nlay = _partial_read(
|
|
218
|
+
h5h, req, ijkrange, zerobased
|
|
219
|
+
)
|
|
220
|
+
if (
|
|
221
|
+
"subgrids" in meta["_required_"]
|
|
222
|
+
and meta["_required_"]["subgrids"] is not None
|
|
223
|
+
):
|
|
224
|
+
*_, k1, k2 = ijkrange
|
|
225
|
+
meta["_required_"]["subgrids"] = filter_subgrids_partial(
|
|
226
|
+
meta["_required_"]["subgrids"],
|
|
227
|
+
k1,
|
|
228
|
+
k2,
|
|
229
|
+
nlay,
|
|
230
|
+
zerobased,
|
|
231
|
+
)
|
|
232
|
+
else:
|
|
233
|
+
incoord = grp["coord"][:, :, :]
|
|
234
|
+
inzcorn = grp["zcorn"][:, :, :, :]
|
|
235
|
+
inactnum = grp["actnum"][:, :, :]
|
|
236
|
+
|
|
237
|
+
result = _RESULT(
|
|
238
|
+
coordsv=incoord.astype("float64"),
|
|
239
|
+
zcornsv=inzcorn.astype("float32"),
|
|
240
|
+
actnumsv=inactnum.astype("float32"),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
handle_metadata(result, meta, ncol, nrow, nlay)
|
|
244
|
+
return result
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def filter_subgrids_partial(
|
|
248
|
+
subgrids: dict[str, int],
|
|
249
|
+
k1: int | LMIN,
|
|
250
|
+
k2: int | LMAX,
|
|
251
|
+
nlay: int,
|
|
252
|
+
zerobased: bool,
|
|
253
|
+
) -> dict[str, int]:
|
|
254
|
+
"""
|
|
255
|
+
Filters and truncates the subgrids of the global grid so that they
|
|
256
|
+
refer to the filtered grid.
|
|
257
|
+
|
|
258
|
+
>>> filter_subgrids_partial(
|
|
259
|
+
... {"subgrid1": 4, "subgrid2": 1, "subgrid3":9},
|
|
260
|
+
... 4,
|
|
261
|
+
... 5,
|
|
262
|
+
... 12,
|
|
263
|
+
... True
|
|
264
|
+
... )
|
|
265
|
+
dict([('subgrid2', 1), ('subgrid3', 1)])
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
subgrids: The dict of subgrids.
|
|
269
|
+
k1: Start of subgrid layers (can be "min" to mean 0 or 1 dependent on zerobased)
|
|
270
|
+
k2: End of subgrid layers (cna be "max" to mean nlay or nlay -1
|
|
271
|
+
dependent on zerobased.
|
|
272
|
+
nlay: Original number of layers
|
|
273
|
+
zerobased: Whether indexing starts with 0 or 1.
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
New Orderedict which is the subgrids dictionary with out of range
|
|
277
|
+
subgrids removed or truncated.
|
|
278
|
+
|
|
279
|
+
"""
|
|
280
|
+
if k1 == "min":
|
|
281
|
+
k1 = 0 if zerobased else 1
|
|
282
|
+
|
|
283
|
+
if k2 == "max":
|
|
284
|
+
k2 = nlay - 1 if zerobased else nlay
|
|
285
|
+
|
|
286
|
+
# convert k1 and k2 to zero based
|
|
287
|
+
if not zerobased:
|
|
288
|
+
k1 -= 1
|
|
289
|
+
k2 -= 1
|
|
290
|
+
|
|
291
|
+
partial_subgrid: dict[str, int] = {}
|
|
292
|
+
start = 0
|
|
293
|
+
for key, value in subgrids.items():
|
|
294
|
+
end = value + start
|
|
295
|
+
partial_start = max(start, k1)
|
|
296
|
+
partial_end = min(end, k2 + 1)
|
|
297
|
+
if partial_end - partial_start > 0:
|
|
298
|
+
partial_subgrid[key] = partial_end - partial_start
|
|
299
|
+
start = end
|
|
300
|
+
return partial_subgrid
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _partial_read(
|
|
304
|
+
h5h: dict[str, np.ndarray],
|
|
305
|
+
req: dict[str, int],
|
|
306
|
+
ijkrange: tuple[
|
|
307
|
+
int | LMIN,
|
|
308
|
+
int | LMAX,
|
|
309
|
+
int | LMIN,
|
|
310
|
+
int | LMAX,
|
|
311
|
+
int | LMIN,
|
|
312
|
+
int | LMAX,
|
|
313
|
+
],
|
|
314
|
+
zerobased: bool,
|
|
315
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray, int, int, int]:
|
|
316
|
+
"""Read a partial IJ range."""
|
|
317
|
+
ncol = req["ncol"]
|
|
318
|
+
nrow = req["nrow"]
|
|
319
|
+
nlay = req["nlay"]
|
|
320
|
+
|
|
321
|
+
if len(ijkrange) != 6:
|
|
322
|
+
raise ValueError("The ijkrange list must have 6 elements")
|
|
323
|
+
|
|
324
|
+
i1, i2, j1, j2, k1, k2 = ijkrange
|
|
325
|
+
|
|
326
|
+
if i1 == "min":
|
|
327
|
+
i1 = 0 if zerobased else 1
|
|
328
|
+
if j1 == "min":
|
|
329
|
+
j1 = 0 if zerobased else 1
|
|
330
|
+
if k1 == "min":
|
|
331
|
+
k1 = 0 if zerobased else 1
|
|
332
|
+
|
|
333
|
+
if i2 == "max":
|
|
334
|
+
i2 = ncol - 1 if zerobased else ncol
|
|
335
|
+
if j2 == "max":
|
|
336
|
+
j2 = nrow - 1 if zerobased else nrow
|
|
337
|
+
if k2 == "max":
|
|
338
|
+
k2 = nlay - 1 if zerobased else nlay
|
|
339
|
+
|
|
340
|
+
if not zerobased:
|
|
341
|
+
i1 -= 1
|
|
342
|
+
i2 -= 1
|
|
343
|
+
j1 -= 1
|
|
344
|
+
j2 -= 1
|
|
345
|
+
k1 -= 1
|
|
346
|
+
k2 -= 1
|
|
347
|
+
|
|
348
|
+
ncol2 = i2 - i1 + 1
|
|
349
|
+
nrow2 = j2 - j1 + 1
|
|
350
|
+
nlay2 = k2 - k1 + 1
|
|
351
|
+
|
|
352
|
+
if (
|
|
353
|
+
ncol2 < 1
|
|
354
|
+
or ncol2 > ncol
|
|
355
|
+
or nrow2 < 1
|
|
356
|
+
or nrow2 > nrow
|
|
357
|
+
or nlay2 < 1
|
|
358
|
+
or nlay2 > nlay
|
|
359
|
+
):
|
|
360
|
+
raise ValueError("The ijkrange spesification exceeds boundaries.")
|
|
361
|
+
|
|
362
|
+
nncol2 = ncol2 + 1
|
|
363
|
+
nnrow2 = nrow2 + 1
|
|
364
|
+
nnlay2 = nlay2 + 1
|
|
365
|
+
|
|
366
|
+
dset = h5h["CornerPointGeometry/coord"]
|
|
367
|
+
cv = dset[i1 : i1 + nncol2, j1 : j1 + nnrow2, :]
|
|
368
|
+
|
|
369
|
+
dset = h5h["CornerPointGeometry/zcorn"]
|
|
370
|
+
zv = dset[i1 : i1 + nncol2, j1 : j1 + nnrow2, k1 : k1 + nnlay2, :]
|
|
371
|
+
|
|
372
|
+
dset = h5h["CornerPointGeometry/actnum"]
|
|
373
|
+
av = dset[i1 : i1 + ncol2, j1 : j1 + nrow2, k1 : k1 + nlay2]
|
|
374
|
+
|
|
375
|
+
return cv, zv, av, ncol2, nrow2, nlay2
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"""Private module for refinement of a grid."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
import xtgeo._internal as _internal # type: ignore
|
|
10
|
+
from xtgeo.common import XTGeoDialog, null_logger
|
|
11
|
+
from xtgeo.grid3d import _gridprop_op1
|
|
12
|
+
|
|
13
|
+
xtg = XTGeoDialog()
|
|
14
|
+
logger = null_logger(__name__)
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from xtgeo.grid3d import Grid, GridProperty
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def refine(
|
|
21
|
+
self: Grid,
|
|
22
|
+
refine_col: int | dict[int, int],
|
|
23
|
+
refine_row: int | dict[int, int],
|
|
24
|
+
refine_layer: int | dict[int, int],
|
|
25
|
+
zoneprop: GridProperty | None = None,
|
|
26
|
+
) -> Grid:
|
|
27
|
+
"""Refine in all direction, proportionally.
|
|
28
|
+
|
|
29
|
+
See details in caller.
|
|
30
|
+
"""
|
|
31
|
+
self._set_xtgformat1()
|
|
32
|
+
self.make_zconsistent()
|
|
33
|
+
|
|
34
|
+
if isinstance(refine_col, int):
|
|
35
|
+
refine_factor_column = [refine_col] * self.dimensions[0]
|
|
36
|
+
else:
|
|
37
|
+
refine_factor_column = [1] * self.dimensions[0]
|
|
38
|
+
for col, factor in refine_col.items():
|
|
39
|
+
if 0 < col < self.dimensions[0] and isinstance(factor, int) and factor > 0:
|
|
40
|
+
refine_factor_column[col - 1] = factor
|
|
41
|
+
else:
|
|
42
|
+
xtg.warning("Invalid refine_col item {col}:{factor}")
|
|
43
|
+
|
|
44
|
+
if isinstance(refine_row, int):
|
|
45
|
+
refine_factor_row = [refine_row] * self.dimensions[1]
|
|
46
|
+
else:
|
|
47
|
+
refine_factor_row = [1] * self.dimensions[1]
|
|
48
|
+
for row, factor in refine_row.items():
|
|
49
|
+
if 0 < row < self.dimensions[1] and isinstance(factor, int) and factor > 0:
|
|
50
|
+
refine_factor_row[row - 1] = factor
|
|
51
|
+
else:
|
|
52
|
+
xtg.warning("Invalid refine_row item {row}:{factor}")
|
|
53
|
+
|
|
54
|
+
refine_factor_layer_dict = {}
|
|
55
|
+
# case 1 rfactor as scalar value.
|
|
56
|
+
if isinstance(refine_layer, int):
|
|
57
|
+
if self.subgrids:
|
|
58
|
+
subgrids = self.get_subgrids()
|
|
59
|
+
for i, _ in enumerate(self.subgrids.keys()):
|
|
60
|
+
refine_factor_layer_dict[i + 1] = refine_layer
|
|
61
|
+
else:
|
|
62
|
+
refine_factor_layer_dict[0] = refine_layer
|
|
63
|
+
subgrids = {}
|
|
64
|
+
subgrids[1] = self.nlay
|
|
65
|
+
|
|
66
|
+
# case 2 rfactor is a dict
|
|
67
|
+
else:
|
|
68
|
+
refine_factor_layer_dict = dict(
|
|
69
|
+
sorted(refine_layer.items())
|
|
70
|
+
) # redefined to ordered
|
|
71
|
+
# 2a: zoneprop is present
|
|
72
|
+
if zoneprop is not None:
|
|
73
|
+
oldsubgrids = None
|
|
74
|
+
if self.subgrids:
|
|
75
|
+
oldsubgrids = self.get_subgrids()
|
|
76
|
+
|
|
77
|
+
subgrids = self.subgrids_from_zoneprop(zoneprop)
|
|
78
|
+
|
|
79
|
+
if oldsubgrids and subgrids.values() != oldsubgrids.values():
|
|
80
|
+
xtg.warn(
|
|
81
|
+
"Subgrid definitions from zone property do not match existing "
|
|
82
|
+
"subgrids. Proceeding with new subgrid definitions from zone "
|
|
83
|
+
"property."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# 2b: zoneprop is not present
|
|
87
|
+
elif zoneprop is None and self.subgrids:
|
|
88
|
+
subgrids = self.get_subgrids()
|
|
89
|
+
|
|
90
|
+
elif zoneprop is None and not self.subgrids:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
"You gave in a dict, but no zoneprops and "
|
|
93
|
+
"subgrids are not present in the grid"
|
|
94
|
+
)
|
|
95
|
+
else:
|
|
96
|
+
raise ValueError("Some major unexpected issue in routine...")
|
|
97
|
+
|
|
98
|
+
if len(subgrids) != len(refine_factor_layer_dict):
|
|
99
|
+
raise RuntimeError("Subgrids and refinements: different definition!")
|
|
100
|
+
|
|
101
|
+
self.set_subgrids(subgrids)
|
|
102
|
+
|
|
103
|
+
# Now, based on dict, give a value per subgrid for key, val in rfactor
|
|
104
|
+
newsubgrids = {}
|
|
105
|
+
newnlay = 0
|
|
106
|
+
for (_x, rfi), (snam, sran) in zip(
|
|
107
|
+
refine_factor_layer_dict.items(), subgrids.items()
|
|
108
|
+
):
|
|
109
|
+
newsubgrids[snam] = sran * rfi
|
|
110
|
+
newnlay += newsubgrids[snam]
|
|
111
|
+
|
|
112
|
+
logger.debug("New layers: %s", newnlay)
|
|
113
|
+
|
|
114
|
+
refine_factor_layer = []
|
|
115
|
+
|
|
116
|
+
for (_, rfi), (_, arr) in zip(
|
|
117
|
+
refine_factor_layer_dict.items(), self.subgrids.items()
|
|
118
|
+
):
|
|
119
|
+
for _ in range(len(arr)):
|
|
120
|
+
refine_factor_layer.append(rfi)
|
|
121
|
+
|
|
122
|
+
self._set_xtgformat2()
|
|
123
|
+
|
|
124
|
+
refine_factor_column = np.array(refine_factor_column, dtype=np.int8)
|
|
125
|
+
refine_factor_row = np.array(refine_factor_row, dtype=np.int8)
|
|
126
|
+
refine_factor_layer = np.array(refine_factor_layer, dtype=np.int8)
|
|
127
|
+
|
|
128
|
+
if refine_factor_column.sum() > self.dimensions[0]:
|
|
129
|
+
grid_cpp = _internal.grid3d.Grid(self)
|
|
130
|
+
ref_coordsv, ref_zcornsv, ref_actnumsv = grid_cpp.refine_columns(
|
|
131
|
+
refine_factor_column
|
|
132
|
+
)
|
|
133
|
+
self._coordsv = ref_coordsv
|
|
134
|
+
self._zcornsv = ref_zcornsv
|
|
135
|
+
self._actnumsv = ref_actnumsv.astype(np.int32)
|
|
136
|
+
self._ncol = int(refine_factor_column.sum())
|
|
137
|
+
|
|
138
|
+
if refine_factor_row.sum() > self.dimensions[1]:
|
|
139
|
+
grid_cpp = _internal.grid3d.Grid(self)
|
|
140
|
+
ref_coordsv, ref_zcornsv, ref_actnumsv = grid_cpp.refine_rows(refine_factor_row)
|
|
141
|
+
self._coordsv = ref_coordsv
|
|
142
|
+
self._zcornsv = ref_zcornsv
|
|
143
|
+
self._actnumsv = ref_actnumsv.astype(np.int32)
|
|
144
|
+
self._nrow = int(refine_factor_row.sum())
|
|
145
|
+
|
|
146
|
+
if refine_factor_layer.sum() > self.dimensions[2]:
|
|
147
|
+
grid_cpp = _internal.grid3d.Grid(self)
|
|
148
|
+
ref_zcornsv, ref_actnumsv = grid_cpp.refine_vertically(refine_factor_layer)
|
|
149
|
+
self._zcornsv = ref_zcornsv
|
|
150
|
+
self._actnumsv = ref_actnumsv.astype(np.int32)
|
|
151
|
+
self._nlay = newnlay
|
|
152
|
+
if self.subgrids is None or len(self.subgrids) <= 1:
|
|
153
|
+
self.subgrids = None
|
|
154
|
+
else:
|
|
155
|
+
self.set_subgrids(newsubgrids)
|
|
156
|
+
|
|
157
|
+
# Check if grid has any properties
|
|
158
|
+
if self._props and self._props.props and len(self._props.props) > 0:
|
|
159
|
+
for prop in self._props.props:
|
|
160
|
+
_gridprop_op1.refine(
|
|
161
|
+
prop, refine_factor_column, refine_factor_row, refine_factor_layer
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
return self
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def refine_vertically(
|
|
168
|
+
self: Grid,
|
|
169
|
+
rfactor: int | dict[int, int],
|
|
170
|
+
zoneprop: GridProperty | None = None,
|
|
171
|
+
) -> Grid:
|
|
172
|
+
"""Refine vertically, proportionally.
|
|
173
|
+
|
|
174
|
+
See details in caller.
|
|
175
|
+
"""
|
|
176
|
+
self._set_xtgformat1()
|
|
177
|
+
self.make_zconsistent()
|
|
178
|
+
|
|
179
|
+
rfactord = {}
|
|
180
|
+
|
|
181
|
+
# case 1 rfactor as scalar value.
|
|
182
|
+
if isinstance(rfactor, int):
|
|
183
|
+
if self.subgrids:
|
|
184
|
+
subgrids = self.get_subgrids()
|
|
185
|
+
for i, _ in enumerate(self.subgrids.keys()):
|
|
186
|
+
rfactord[i + 1] = rfactor
|
|
187
|
+
else:
|
|
188
|
+
rfactord[0] = rfactor
|
|
189
|
+
subgrids = {}
|
|
190
|
+
subgrids[1] = self.nlay
|
|
191
|
+
|
|
192
|
+
# case 2 rfactor is a dict
|
|
193
|
+
else:
|
|
194
|
+
rfactord = dict(sorted(rfactor.items())) # redefined to ordered
|
|
195
|
+
# 2a: zoneprop is present
|
|
196
|
+
if zoneprop is not None:
|
|
197
|
+
oldsubgrids = None
|
|
198
|
+
if self.subgrids:
|
|
199
|
+
oldsubgrids = self.get_subgrids()
|
|
200
|
+
|
|
201
|
+
subgrids = self.subgrids_from_zoneprop(zoneprop)
|
|
202
|
+
|
|
203
|
+
if oldsubgrids and subgrids.values() != oldsubgrids.values():
|
|
204
|
+
xtg.warn("ISSUES!!!")
|
|
205
|
+
|
|
206
|
+
# 2b: zoneprop is not present
|
|
207
|
+
elif zoneprop is None and self.subgrids:
|
|
208
|
+
subgrids = self.get_subgrids()
|
|
209
|
+
|
|
210
|
+
elif zoneprop is None and not self.subgrids:
|
|
211
|
+
raise ValueError(
|
|
212
|
+
"You gave in a dict, but no zoneprops and "
|
|
213
|
+
"subgrids are not present in the grid"
|
|
214
|
+
)
|
|
215
|
+
else:
|
|
216
|
+
raise ValueError("Some major unexpected issue in routine...")
|
|
217
|
+
|
|
218
|
+
if len(subgrids) != len(rfactord):
|
|
219
|
+
raise RuntimeError("Subgrids and refinements: different definition!")
|
|
220
|
+
|
|
221
|
+
self.set_subgrids(subgrids)
|
|
222
|
+
|
|
223
|
+
# Now, based on dict, give a value per subgrid for key, val in rfactor
|
|
224
|
+
newsubgrids = {}
|
|
225
|
+
newnlay = 0
|
|
226
|
+
for (_x, rfi), (snam, sran) in zip(rfactord.items(), subgrids.items()):
|
|
227
|
+
newsubgrids[snam] = sran * rfi
|
|
228
|
+
newnlay += newsubgrids[snam]
|
|
229
|
+
|
|
230
|
+
logger.debug("New layers: %s", newnlay)
|
|
231
|
+
|
|
232
|
+
refine_factors = []
|
|
233
|
+
|
|
234
|
+
for (_, rfi), (_, arr) in zip(rfactord.items(), self.subgrids.items()):
|
|
235
|
+
for _ in range(len(arr)):
|
|
236
|
+
refine_factors.append(rfi)
|
|
237
|
+
|
|
238
|
+
self._set_xtgformat2()
|
|
239
|
+
grid_cpp = _internal.grid3d.Grid(self)
|
|
240
|
+
refine_factors = np.array(refine_factors, dtype=np.int8)
|
|
241
|
+
ref_zcornsv, ref_actnumsv = grid_cpp.refine_vertically(refine_factors)
|
|
242
|
+
|
|
243
|
+
# update instance:
|
|
244
|
+
self._nlay = newnlay
|
|
245
|
+
self._zcornsv = ref_zcornsv
|
|
246
|
+
self._actnumsv = ref_actnumsv.astype(np.int32)
|
|
247
|
+
|
|
248
|
+
if self.subgrids is None or len(self.subgrids) <= 1:
|
|
249
|
+
self.subgrids = None
|
|
250
|
+
else:
|
|
251
|
+
self.set_subgrids(newsubgrids)
|
|
252
|
+
|
|
253
|
+
# Check if grid has any properties
|
|
254
|
+
if self._props and self._props.props and len(self._props.props) > 0:
|
|
255
|
+
for prop in self._props.props:
|
|
256
|
+
_gridprop_op1.refine(prop, 1, 1, refine_factors)
|
|
257
|
+
|
|
258
|
+
return self
|