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.
Files changed (122) hide show
  1. cxtgeo.py +558 -0
  2. cxtgeoPYTHON_wrap.c +19537 -0
  3. xtgeo/__init__.py +248 -0
  4. xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
  5. xtgeo/_internal.cp313-win_amd64.pyd +0 -0
  6. xtgeo/common/__init__.py +19 -0
  7. xtgeo/common/_angles.py +29 -0
  8. xtgeo/common/_xyz_enum.py +50 -0
  9. xtgeo/common/calc.py +396 -0
  10. xtgeo/common/constants.py +30 -0
  11. xtgeo/common/exceptions.py +42 -0
  12. xtgeo/common/log.py +93 -0
  13. xtgeo/common/sys.py +166 -0
  14. xtgeo/common/types.py +18 -0
  15. xtgeo/common/version.py +34 -0
  16. xtgeo/common/xtgeo_dialog.py +604 -0
  17. xtgeo/cube/__init__.py +9 -0
  18. xtgeo/cube/_cube_export.py +214 -0
  19. xtgeo/cube/_cube_import.py +532 -0
  20. xtgeo/cube/_cube_roxapi.py +180 -0
  21. xtgeo/cube/_cube_utils.py +287 -0
  22. xtgeo/cube/_cube_window_attributes.py +273 -0
  23. xtgeo/cube/cube1.py +1023 -0
  24. xtgeo/grid3d/__init__.py +15 -0
  25. xtgeo/grid3d/_ecl_grid.py +778 -0
  26. xtgeo/grid3d/_ecl_inte_head.py +152 -0
  27. xtgeo/grid3d/_ecl_logi_head.py +71 -0
  28. xtgeo/grid3d/_ecl_output_file.py +81 -0
  29. xtgeo/grid3d/_egrid.py +1004 -0
  30. xtgeo/grid3d/_find_gridprop_in_eclrun.py +625 -0
  31. xtgeo/grid3d/_grdecl_format.py +309 -0
  32. xtgeo/grid3d/_grdecl_grid.py +400 -0
  33. xtgeo/grid3d/_grid3d.py +29 -0
  34. xtgeo/grid3d/_grid3d_fence.py +284 -0
  35. xtgeo/grid3d/_grid3d_utils.py +228 -0
  36. xtgeo/grid3d/_grid_boundary.py +76 -0
  37. xtgeo/grid3d/_grid_etc1.py +1683 -0
  38. xtgeo/grid3d/_grid_export.py +222 -0
  39. xtgeo/grid3d/_grid_hybrid.py +50 -0
  40. xtgeo/grid3d/_grid_import.py +79 -0
  41. xtgeo/grid3d/_grid_import_ecl.py +101 -0
  42. xtgeo/grid3d/_grid_import_roff.py +135 -0
  43. xtgeo/grid3d/_grid_import_xtgcpgeom.py +375 -0
  44. xtgeo/grid3d/_grid_refine.py +258 -0
  45. xtgeo/grid3d/_grid_roxapi.py +292 -0
  46. xtgeo/grid3d/_grid_translate_coords.py +154 -0
  47. xtgeo/grid3d/_grid_wellzone.py +165 -0
  48. xtgeo/grid3d/_gridprop_export.py +202 -0
  49. xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
  50. xtgeo/grid3d/_gridprop_import_grdecl.py +132 -0
  51. xtgeo/grid3d/_gridprop_import_roff.py +52 -0
  52. xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
  53. xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
  54. xtgeo/grid3d/_gridprop_op1.py +272 -0
  55. xtgeo/grid3d/_gridprop_roxapi.py +301 -0
  56. xtgeo/grid3d/_gridprop_value_init.py +140 -0
  57. xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
  58. xtgeo/grid3d/_gridprops_import_roff.py +83 -0
  59. xtgeo/grid3d/_roff_grid.py +470 -0
  60. xtgeo/grid3d/_roff_parameter.py +303 -0
  61. xtgeo/grid3d/grid.py +3010 -0
  62. xtgeo/grid3d/grid_properties.py +699 -0
  63. xtgeo/grid3d/grid_property.py +1313 -0
  64. xtgeo/grid3d/types.py +15 -0
  65. xtgeo/interfaces/rms/__init__.py +18 -0
  66. xtgeo/interfaces/rms/_regular_surface.py +460 -0
  67. xtgeo/interfaces/rms/_rms_base.py +100 -0
  68. xtgeo/interfaces/rms/_rmsapi_package.py +69 -0
  69. xtgeo/interfaces/rms/rmsapi_utils.py +438 -0
  70. xtgeo/io/__init__.py +1 -0
  71. xtgeo/io/_file.py +603 -0
  72. xtgeo/metadata/__init__.py +17 -0
  73. xtgeo/metadata/metadata.py +435 -0
  74. xtgeo/roxutils/__init__.py +7 -0
  75. xtgeo/roxutils/_roxar_loader.py +54 -0
  76. xtgeo/roxutils/_roxutils_etc.py +122 -0
  77. xtgeo/roxutils/roxutils.py +207 -0
  78. xtgeo/surface/__init__.py +20 -0
  79. xtgeo/surface/_regsurf_boundary.py +26 -0
  80. xtgeo/surface/_regsurf_cube.py +210 -0
  81. xtgeo/surface/_regsurf_cube_window.py +391 -0
  82. xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
  83. xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
  84. xtgeo/surface/_regsurf_export.py +388 -0
  85. xtgeo/surface/_regsurf_grid3d.py +275 -0
  86. xtgeo/surface/_regsurf_gridding.py +347 -0
  87. xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
  88. xtgeo/surface/_regsurf_import.py +347 -0
  89. xtgeo/surface/_regsurf_lowlevel.py +122 -0
  90. xtgeo/surface/_regsurf_oper.py +538 -0
  91. xtgeo/surface/_regsurf_utils.py +81 -0
  92. xtgeo/surface/_surfs_import.py +43 -0
  93. xtgeo/surface/_zmap_parser.py +138 -0
  94. xtgeo/surface/regular_surface.py +3043 -0
  95. xtgeo/surface/surfaces.py +276 -0
  96. xtgeo/well/__init__.py +24 -0
  97. xtgeo/well/_blockedwell_roxapi.py +241 -0
  98. xtgeo/well/_blockedwells_roxapi.py +68 -0
  99. xtgeo/well/_well_aux.py +30 -0
  100. xtgeo/well/_well_io.py +327 -0
  101. xtgeo/well/_well_oper.py +483 -0
  102. xtgeo/well/_well_roxapi.py +304 -0
  103. xtgeo/well/_wellmarkers.py +486 -0
  104. xtgeo/well/_wells_utils.py +158 -0
  105. xtgeo/well/blocked_well.py +220 -0
  106. xtgeo/well/blocked_wells.py +134 -0
  107. xtgeo/well/well1.py +1516 -0
  108. xtgeo/well/wells.py +211 -0
  109. xtgeo/xyz/__init__.py +6 -0
  110. xtgeo/xyz/_polygons_oper.py +272 -0
  111. xtgeo/xyz/_xyz.py +758 -0
  112. xtgeo/xyz/_xyz_data.py +646 -0
  113. xtgeo/xyz/_xyz_io.py +737 -0
  114. xtgeo/xyz/_xyz_lowlevel.py +42 -0
  115. xtgeo/xyz/_xyz_oper.py +613 -0
  116. xtgeo/xyz/_xyz_roxapi.py +766 -0
  117. xtgeo/xyz/points.py +698 -0
  118. xtgeo/xyz/polygons.py +827 -0
  119. xtgeo-4.14.1.dist-info/METADATA +146 -0
  120. xtgeo-4.14.1.dist-info/RECORD +122 -0
  121. xtgeo-4.14.1.dist-info/WHEEL +5 -0
  122. 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