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,360 @@
1
+ """Regular surface vs Cube, slice a window interval v3, in pure numpy."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from typing import TYPE_CHECKING
7
+
8
+ import numpy as np
9
+
10
+ from xtgeo.common.log import null_logger
11
+
12
+ if TYPE_CHECKING:
13
+ from xtgeo.cube.cube1 import Cube
14
+
15
+ from .regular_surface import RegularSurface
16
+
17
+
18
+ warnings.filterwarnings(action="ignore", message="All-NaN slice encountered")
19
+ warnings.filterwarnings(action="ignore", message="Mean of empty slice")
20
+ warnings.filterwarnings(action="ignore", message="Degree of freedom")
21
+
22
+ logger = null_logger(__name__)
23
+
24
+
25
+ STATATTRS = [
26
+ "min",
27
+ "max",
28
+ "mean",
29
+ "var",
30
+ "rms",
31
+ "maxpos",
32
+ "maxneg",
33
+ "maxabs",
34
+ "meanabs",
35
+ "meanpos",
36
+ "meanneg",
37
+ ]
38
+ SUMATTRS = [
39
+ "sumpos",
40
+ "sumneg",
41
+ "sumabs",
42
+ ]
43
+ ALLATTRS = STATATTRS + SUMATTRS
44
+
45
+ # self ~ RegularSurface() instance
46
+
47
+
48
+ def _cut_cube_deadtraces(cube: Cube, deadtraces: bool) -> np.ndarray:
49
+ """Take the cube numpy values and filter away dead traces as np.nan."""
50
+ logger.info("Assign dead traces")
51
+ dvalues = cube.values.copy()
52
+
53
+ if deadtraces and 2 in cube.traceidcodes:
54
+ dvalues[cube.traceidcodes == 2] = np.nan
55
+ logger.info("Dead traces encountered in this cube, set values to np.nan")
56
+ else:
57
+ logger.info("No dead traces encountered in this cube, or deadtraces is False")
58
+
59
+ return dvalues
60
+
61
+
62
+ def _get_iso_maskthreshold_surface(
63
+ upper: RegularSurface,
64
+ lower: RegularSurface,
65
+ maskthreshold: float,
66
+ ) -> RegularSurface:
67
+ """Return a surface with value 0 where isochore <= threshold"""
68
+ logger.info("Maskthreshold based on isochore")
69
+ result = upper.copy()
70
+ result.fill()
71
+ diff = lower - upper
72
+ result.values = np.ma.where(diff.values <= maskthreshold, 0, 1)
73
+ return result
74
+
75
+
76
+ def _proxy_surf_outside_cube(
77
+ self,
78
+ cube: Cube,
79
+ scube: RegularSurface,
80
+ ) -> RegularSurface:
81
+ """Proxy for the part of input surface that is outside the cube area."""
82
+ logger.info("Get a proxy for part of original surface being outside the cube")
83
+ outside = self.copy()
84
+ outside.values = 0.0
85
+
86
+ boundary = scube.get_boundary_polygons()
87
+ outside.set_outside(boundary, 1.0)
88
+ return outside # is 1 outside the cube area, 0 within the cube
89
+
90
+
91
+ def _upper_lower_surface(
92
+ self,
93
+ cube: Cube,
94
+ scube: RegularSurface,
95
+ zsurf: RegularSurface,
96
+ other: RegularSurface,
97
+ other_position: str,
98
+ zrange: float,
99
+ ) -> tuple[RegularSurface, RegularSurface]:
100
+ """Return upper and lower surface, sampled to cube resolution."""
101
+
102
+ logger.info("Define surfaces to apply...")
103
+ this = zsurf if zsurf is not None else self.copy()
104
+
105
+ if other is not None:
106
+ if other_position.lower() == "below":
107
+ surf1 = this
108
+ surf2 = other
109
+ else:
110
+ surf1 = other # avoid changing self instance
111
+ surf2 = this
112
+ else:
113
+ surf1 = this.copy()
114
+ surf2 = this.copy()
115
+ surf1.values -= zrange
116
+ surf2.values += zrange
117
+
118
+ # get the surfaces on cube resolution
119
+ lower = scube.copy()
120
+ scube.resample(surf1)
121
+ lower.resample(surf2)
122
+
123
+ logger.info(
124
+ "Return resmapled surfaces, avg for upper and lower is %s, %s",
125
+ scube.values.mean(),
126
+ lower.values.mean(),
127
+ )
128
+ return scube, lower
129
+
130
+
131
+ def _create_depth_cube(cube: Cube) -> np.ndarray:
132
+ """Create a cube (np array) where values are cube depths; to be used as filter."""
133
+ logger.info("Create a depth cube...")
134
+ dcube = cube.values.copy()
135
+ darr = [cube.zori + n * cube.zinc for n in range(dcube.shape[2])]
136
+ dcube[:, :, :] = darr
137
+
138
+ logger.info("Created a depth cube starting from %s", np.mean(dcube))
139
+
140
+ return dcube
141
+
142
+
143
+ def _refine_cubes_vertically(cvalues, dvalues, ndiv=2):
144
+ """Refine the cubes vertically for better resolution."""
145
+ if not ndiv:
146
+ ndiv = 2 # default
147
+ logger.info("Resampling vertically, according to ndiv = %s", ndiv)
148
+ if ndiv <= 1:
149
+ logger.info("ndiv is less or equal to 1; no refinement done")
150
+ return cvalues, dvalues
151
+
152
+ logger.info("Original shape is %s", cvalues.shape)
153
+
154
+ # Determine the new shape
155
+ new_shape = (cvalues.shape[0], cvalues.shape[1], ndiv * cvalues.shape[2])
156
+ cref = np.zeros(new_shape)
157
+ dref = np.zeros(new_shape)
158
+
159
+ # Compute new indices for interpolation
160
+ new_x = np.linspace(0, cvalues.shape[2] - 1, new_shape[2])
161
+
162
+ # Interpolate for each layer and column
163
+ for i in range(cvalues.shape[0]):
164
+ for j in range(cvalues.shape[1]):
165
+ cref[i, j, :] = np.interp(
166
+ new_x, np.arange(cvalues.shape[2]), cvalues[i, j, :]
167
+ )
168
+ dref[i, j, :] = np.interp(
169
+ new_x, np.arange(dvalues.shape[2]), dvalues[i, j, :]
170
+ )
171
+
172
+ logger.info("Resampling done, new shape is %s", cref.shape)
173
+ return cref, dref
174
+
175
+
176
+ def _filter_cube_values_upper_lower(cvalues, dvalues, upper, lower):
177
+ """Filter the cube (cvalues) based on depth interval."""
178
+
179
+ nnans = np.count_nonzero(np.isnan(cvalues))
180
+ logger.info("Filter cube in depth... number of nans is %s", nnans)
181
+
182
+ upv = np.expand_dims(upper.values, axis=2)
183
+ lov = np.expand_dims(lower.values, axis=2)
184
+
185
+ cvalues[dvalues < upv] = np.nan
186
+ cvalues[dvalues > lov] = np.nan
187
+
188
+ nnans = np.count_nonzero(np.isnan(cvalues))
189
+ ndefi = np.count_nonzero(~np.isnan(cvalues))
190
+ logger.info("Filter cube in depth done, updated number of nans is %s", nnans)
191
+ logger.info("Filter cube in depth done, remaining is %s", ndefi)
192
+ return cvalues
193
+
194
+
195
+ def _expand_attributes(attribute: str | list) -> list:
196
+ """The 'attribute' may be a name, 'all', or a list of attributes"""
197
+ useattrs = None
198
+ if isinstance(attribute, str):
199
+ useattrs = ALLATTRS if attribute == "all" else [attribute]
200
+ else:
201
+ useattrs = attribute
202
+
203
+ if not all(item in ALLATTRS for item in useattrs):
204
+ raise ValueError(
205
+ f"One or more values are not a valid, input list is {useattrs}, "
206
+ f"allowed list is {ALLATTRS}"
207
+ )
208
+ return useattrs
209
+
210
+
211
+ def _compute_stats(
212
+ cref: np.ndarray,
213
+ attr: str,
214
+ self: RegularSurface,
215
+ upper: RegularSurface,
216
+ masksurf: RegularSurface,
217
+ sampling: str,
218
+ snapxy: bool,
219
+ ) -> RegularSurface:
220
+ """Compute the attribute and return the attribute map"""
221
+ logger.info("Compute stats...")
222
+
223
+ if attr == "mean":
224
+ values = np.nanmean(cref, axis=2)
225
+ elif attr == "var":
226
+ values = np.nanvar(cref, axis=2)
227
+ elif attr == "max":
228
+ values = np.nanmax(cref, axis=2)
229
+ elif attr == "min":
230
+ values = np.nanmin(cref, axis=2)
231
+ elif attr == "rms":
232
+ values = np.sqrt(np.nanmean(np.square(cref), axis=2))
233
+ elif attr == "maxneg":
234
+ use = cref.copy()
235
+ use[cref >= 0] = np.nan
236
+ values = np.nanmin(use, axis=2)
237
+ elif attr == "maxpos":
238
+ use = cref.copy()
239
+ use[cref < 0] = np.nan
240
+ values = np.nanmax(use, axis=2)
241
+ elif attr == "maxabs":
242
+ use = cref.copy()
243
+ use = np.abs(use)
244
+ values = np.nanmax(use, axis=2)
245
+ elif attr == "meanabs":
246
+ use = cref.copy()
247
+ use = np.abs(use)
248
+ values = np.nanmean(use, axis=2)
249
+ elif attr == "meanpos":
250
+ use = cref.copy()
251
+ use[cref < 0] = np.nan
252
+ values = np.nanmean(use, axis=2)
253
+ elif attr == "meanneg":
254
+ use = cref.copy()
255
+ use[cref >= 0] = np.nan
256
+ values = np.nanmean(use, axis=2)
257
+ elif attr == "sumneg":
258
+ use = cref.copy()
259
+ use[cref >= 0] = np.nan
260
+ values = np.nansum(use, axis=2)
261
+ values = np.ma.masked_greater_equal(values, 0.0) # to make undefined map areas
262
+ elif attr == "sumpos":
263
+ use = cref.copy()
264
+ use[cref < 0] = np.nan
265
+ values = np.nansum(use, axis=2)
266
+ values = np.ma.masked_less_equal(values, 0.0) # to make undefined map areas
267
+ elif attr == "sumabs":
268
+ use = cref.copy()
269
+ use = np.abs(use)
270
+ values = np.nansum(use, axis=2)
271
+ else:
272
+ raise ValueError(f"The attribute name {attr} is not supported")
273
+
274
+ actual = self.copy()
275
+ sampled = upper.copy()
276
+
277
+ sampled.values = np.ma.masked_invalid(values)
278
+ sampled.values = np.ma.masked_where(masksurf.values == 0, sampled.values)
279
+
280
+ if not snapxy:
281
+ sampling_option = "nearest" if sampling in ("nearest", "cube") else "bilinear"
282
+ actual.resample(
283
+ sampled, sampling=sampling_option
284
+ ) # will be on input map resolution
285
+ else:
286
+ actual = sampled
287
+
288
+ logger.info("Compute stats... done")
289
+ return actual
290
+
291
+
292
+ def slice_cube_window(
293
+ self,
294
+ cube: Cube,
295
+ scube: RegularSurface,
296
+ zsurf: RegularSurface | None = None,
297
+ other: RegularSurface | None = None,
298
+ other_position: str = "below",
299
+ sampling: str = "nearest",
300
+ mask: bool = True,
301
+ zrange: float = 10.0,
302
+ ndiv: int | None = None,
303
+ attribute: str = "max",
304
+ maskthreshold: float = 0.1,
305
+ snapxy: bool = False,
306
+ showprogress: bool = False,
307
+ deadtraces: bool = True,
308
+ ):
309
+ """Main entry point towards caller"""
310
+ if showprogress:
311
+ print("progress: initialising for attributes...")
312
+
313
+ cvalues = _cut_cube_deadtraces(cube, deadtraces)
314
+
315
+ upper, lower = _upper_lower_surface(
316
+ self, cube, scube, zsurf, other, other_position, zrange
317
+ )
318
+
319
+ outside_proxy = None
320
+ if not mask:
321
+ outside_proxy = _proxy_surf_outside_cube(self, cube, scube)
322
+
323
+ masksurf = _get_iso_maskthreshold_surface(upper, lower, maskthreshold)
324
+
325
+ dvalues = _create_depth_cube(cube)
326
+
327
+ apply_ndiv = 1 if sampling == "cube" else ndiv
328
+ if showprogress:
329
+ print(f"progress: refine according to actual ndiv = {apply_ndiv}...")
330
+
331
+ cref, dref = _refine_cubes_vertically(cvalues, dvalues, apply_ndiv)
332
+
333
+ cref = _filter_cube_values_upper_lower(cref, dref, upper, lower)
334
+
335
+ cval = _filter_cube_values_upper_lower(cvalues, dvalues, upper, lower)
336
+
337
+ use_attrs = _expand_attributes(attribute)
338
+
339
+ attrs = {}
340
+ if showprogress:
341
+ print("progress: compute mean, variance, etc attributes...")
342
+ for attr in use_attrs:
343
+ if attr in SUMATTRS:
344
+ # use cval, which is not refined vertically
345
+ res = _compute_stats(cval, attr, self, upper, masksurf, sampling, snapxy)
346
+ else:
347
+ res = _compute_stats(cref, attr, self, upper, masksurf, sampling, snapxy)
348
+
349
+ if outside_proxy and not snapxy:
350
+ res.values = np.ma.where(outside_proxy > 0, self.values, res.values)
351
+
352
+ attrs[attr] = res
353
+
354
+ # if attribute is str, self shall be updated and None returned,
355
+ # otherwise a dict of attributes objects shall be returned
356
+ if isinstance(attrs, dict) and len(attrs) == 1 and isinstance(attribute, str):
357
+ self.values = attrs[attribute].values
358
+ return None
359
+
360
+ return attrs