xtgeo 4.11.0__cp310-cp310-macosx_11_0_arm64.whl → 4.12.1__cp310-cp310-macosx_11_0_arm64.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.

Potentially problematic release.


This version of xtgeo might be problematic. Click here for more details.

Binary file
Binary file
xtgeo/common/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '4.11.0'
32
- __version_tuple__ = version_tuple = (4, 11, 0)
31
+ __version__ = version = '4.12.1'
32
+ __version_tuple__ = version_tuple = (4, 12, 1)
33
33
 
34
- __commit_id__ = commit_id = 'gee9361dd9'
34
+ __commit_id__ = commit_id = 'g6f276d4df'
@@ -4,6 +4,8 @@ import warnings
4
4
  from contextlib import contextmanager
5
5
  from typing import TYPE_CHECKING
6
6
 
7
+ import numpy as np
8
+
7
9
  from xtgeo.common import null_logger
8
10
 
9
11
  if TYPE_CHECKING:
@@ -15,6 +17,47 @@ if TYPE_CHECKING:
15
17
  logger = null_logger(__name__)
16
18
 
17
19
 
20
+ def run_length_encoding(arr: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
21
+ """
22
+ Perform run-length encoding on a 1D NumPy array.
23
+
24
+ Run-length encoding is a data compression technique that represents
25
+ consecutive repeated values as a single value and its count.
26
+
27
+ Args:
28
+ arr (np.ndarray): A 1D NumPy array to be encoded.
29
+
30
+ Returns:
31
+ tuple[np.ndarray, np.ndarray]: A tuple containing two 1D NumPy arrays:
32
+ - counts (np.ndarray): An array of counts representing the number
33
+ of consecutive occurrences of each unique value.
34
+ - values (np.ndarray): An array of the unique values corresponding to
35
+ the counts.
36
+
37
+ Examples:
38
+ >>> import numpy as np
39
+ >>> arr = np.array([1, 1, 2, 2, 2, 3, 3, 1, 1, 1])
40
+ >>> counts, values = run_length_encoding(arr)
41
+ >>> print(counts)
42
+ [2 3 2 3]
43
+ >>> print(values)
44
+ [1 2 3 1]
45
+
46
+ >>> arr = np.array([5, 5, 5, 5, 5])
47
+ >>> counts, values = run_length_encoding(arr)
48
+ >>> print(counts)
49
+ [5]
50
+ >>> print(values)
51
+ [5]
52
+
53
+ """
54
+ change_indices = np.where(~np.isclose(arr[:-1], arr[1:]))[0] + 1
55
+ counts = np.diff(np.concatenate(([0], change_indices, [len(arr)])))
56
+ values = arr[np.concatenate(([0], change_indices))]
57
+
58
+ return counts, values
59
+
60
+
18
61
  def split_line(line: str) -> Generator[str, None, None]:
19
62
  """
20
63
  split a keyword line inside a grdecl file. This splits the values of a
@@ -41,7 +41,7 @@ from ._ecl_grid import (
41
41
  MapAxes,
42
42
  Units,
43
43
  )
44
- from ._grdecl_format import IGNORE_ALL, open_grdecl
44
+ from ._grdecl_format import IGNORE_ALL, open_grdecl, run_length_encoding
45
45
 
46
46
 
47
47
  @dataclass
@@ -311,20 +311,22 @@ class GrdeclGrid(EclGrid):
311
311
  results[kw.lower()] = factory(values)
312
312
  return cls(**results)
313
313
 
314
- def to_file(self, filename, fileformat="grdecl"):
314
+ def to_file(self, filename, fileformat="grdecl", rle: bool = False):
315
315
  """
316
316
  write the grdeclgrid to a file.
317
317
  :param filename: path to file to write.
318
318
  :param fileformat: Either "grdecl" or "bgrdecl" to
319
319
  indicate binary or ascii format.
320
+ :param rle: Boolean flag indicating whether to use Run-Length Encoding (RLE)
321
+ compression when writing the file (only for grdecl).
320
322
  """
321
323
  if fileformat == "grdecl":
322
- return self._to_grdecl_file(filename)
324
+ return self._to_grdecl_file(filename, rle)
323
325
  if fileformat == "bgrdecl":
324
326
  return self._to_bgrdecl_file(filename)
325
327
  raise ValueError(b"Unknown grdecl file format {fileformat}")
326
328
 
327
- def _to_grdecl_file(self, filename):
329
+ def _to_grdecl_file(self, filename, rle):
328
330
  with open(filename, "w") as filestream:
329
331
  keywords = [
330
332
  ("SPECGRID", self.specgrid.to_grdecl()),
@@ -340,14 +342,24 @@ class GrdeclGrid(EclGrid):
340
342
  if values is None:
341
343
  continue
342
344
  filestream.write(f"{kw}\n")
343
- numcolumns = 0
344
- for value in values:
345
- numcolumns += 1
346
- filestream.write(f" {value}")
347
-
348
- if numcolumns >= 6: # 6 should ensure < 128 character width total
349
- filestream.write("\n")
350
- numcolumns = 0
345
+ if rle and (kw == "ACTNUM"):
346
+ counts, unique_values = run_length_encoding(values)
347
+ for i, (count, unique_value) in enumerate(
348
+ zip(counts, unique_values)
349
+ ):
350
+ filestream.write(
351
+ f" {count}*{unique_value}"
352
+ if count > 1
353
+ else f" {unique_value}"
354
+ )
355
+ if i % 6 == 5:
356
+ filestream.write("\n")
357
+ else:
358
+ for i, value in enumerate(values):
359
+ filestream.write(f" {value}")
360
+
361
+ if i % 6 == 5: # 6 should ensure < 128 character width total
362
+ filestream.write("\n")
351
363
 
352
364
  filestream.write("\n /\n")
353
365
 
@@ -309,23 +309,34 @@ def get_heights_above_ffl(
309
309
  grid: Grid,
310
310
  ffl: GridProperty,
311
311
  option: Literal[
312
- "cell_center_above_ffl", "cell_corners_above_ffl"
312
+ "cell_center_above_ffl",
313
+ "cell_corners_above_ffl",
314
+ "truncated_cell_corners_above_ffl",
313
315
  ] = "cell_center_above_ffl",
314
316
  ) -> tuple[GridProperty, GridProperty, GridProperty]:
315
317
  """Compute delta heights for cell top, bottom and midpoints above a given level."""
316
318
 
317
- valid_options = ("cell_center_above_ffl", "cell_corners_above_ffl")
319
+ valid_options = (
320
+ "cell_center_above_ffl",
321
+ "cell_corners_above_ffl",
322
+ "truncated_cell_corners_above_ffl",
323
+ )
318
324
  if option not in valid_options:
319
325
  raise ValueError(
320
326
  f"The option key <{option}> is invalid, must be one of {valid_options}"
321
327
  )
328
+ if option == "cell_center_above_ffl":
329
+ option_flag = _internal.grid3d.HeightAboveFFLOption.CellCenter
330
+ elif option == "cell_corners_above_ffl":
331
+ option_flag = _internal.grid3d.HeightAboveFFLOption.CellCorners
332
+ else:
333
+ option_flag = _internal.grid3d.HeightAboveFFLOption.TruncatedCellCorners
322
334
 
323
335
  grid._set_xtgformat2()
324
336
 
325
337
  grid_cpp = grid._get_grid_cpp()
326
338
  htop_arr, hbot_arr, hmid_arr = grid_cpp.get_height_above_ffl(
327
- ffl.values.ravel(),
328
- 1 if option == "cell_center_above_ffl" else 2,
339
+ ffl.values.ravel(), option_flag
329
340
  )
330
341
 
331
342
  htop = GridProperty(
@@ -49,10 +49,11 @@ def export_roff(
49
49
  )
50
50
 
51
51
 
52
- def export_grdecl(grid: Grid, gfile: FileLike, mode: int) -> None:
53
- """Export grid to Eclipse GRDECL format (ascii, mode=1) or binary (mode=0)."""
52
+ def export_grdecl(grid: Grid, gfile: FileLike, mode: int, rle: bool = False) -> None:
53
+ """Export grid to Eclipse GRDECL format (ascii, mode=1) or binary (mode=0).
54
+ Optionally for ASCII GRDECL, run-length encoding RLE can be applied"""
54
55
  fileformat = "grdecl" if mode == 1 else "bgrdecl"
55
- GrdeclGrid.from_xtgeo_grid(grid).to_file(gfile, fileformat=fileformat)
56
+ GrdeclGrid.from_xtgeo_grid(grid).to_file(gfile, fileformat=fileformat, rle=rle)
56
57
 
57
58
 
58
59
  def export_egrid(grid: Grid, gfile: FileLike) -> None:
@@ -243,7 +243,7 @@ def refine_vertically(
243
243
  # update instance:
244
244
  self._nlay = newnlay
245
245
  self._zcornsv = ref_zcornsv
246
- self._actnumsv = ref_actnumsv
246
+ self._actnumsv = ref_actnumsv.astype(np.int32)
247
247
 
248
248
  if self.subgrids is None or len(self.subgrids) <= 1:
249
249
  self.subgrids = None
@@ -17,6 +17,7 @@ from xtgeo.common.exceptions import InvalidFileFormatError
17
17
  from xtgeo.common.log import null_logger
18
18
  from xtgeo.io._file import FileFormat, FileWrapper
19
19
 
20
+ from ._grdecl_format import run_length_encoding
20
21
  from ._roff_parameter import RoffParameter
21
22
 
22
23
  if TYPE_CHECKING:
@@ -37,6 +38,7 @@ def to_file(
37
38
  append: bool = False,
38
39
  dtype: type[np.float32] | type[np.float64] | type[np.int32] | None = None,
39
40
  fmt: str | None = None,
41
+ rle: bool = False,
40
42
  ) -> None:
41
43
  """Export the grid property to file."""
42
44
  logger.debug("Export property to file %s as %s", pfile, fformat)
@@ -62,6 +64,7 @@ def to_file(
62
64
  append=append,
63
65
  binary=binary,
64
66
  fmt=fmt,
67
+ rle=rle,
65
68
  )
66
69
  elif fformat == "xtgcpprop":
67
70
  _export_xtgcpprop(gridprop, xtg_file.name)
@@ -104,6 +107,7 @@ def _export_grdecl(
104
107
  append: bool = False,
105
108
  binary: bool = False,
106
109
  fmt: str | None = None,
110
+ rle: bool = False,
107
111
  ) -> None:
108
112
  """Export ascii or binary GRDECL"""
109
113
  vals: npt.NDArray = gridprop.values.ravel(order="F")
@@ -132,18 +136,36 @@ def _export_grdecl(
132
136
  else:
133
137
  # Always the case when not binary
134
138
  assert isinstance(fout, io.TextIOWrapper)
135
- fout.write(name)
136
- fout.write("\n")
137
- for i, v in enumerate(vals):
138
- fout.write(" ")
139
- if fmt:
140
- fout.write(fmt % v)
141
- elif gridprop.isdiscrete:
142
- fout.write(str(v))
143
- else:
144
- fout.write(f"{v:3e}")
145
- if i % 6 == 5:
146
- fout.write("\n")
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")
147
169
  fout.write(" /\n")
148
170
 
149
171
 
@@ -25,6 +25,77 @@ _ValueList = List[List[_CoordOrValue]]
25
25
  XYValueLists = Tuple[_XYCoordList, _ValueList]
26
26
 
27
27
 
28
+ def _validate_cast_range(values: np.ndarray, target_dtype: np.dtype) -> None:
29
+ """Validate that values fit in target dtype range."""
30
+ if np.issubdtype(target_dtype, np.integer):
31
+ info = np.iinfo(target_dtype)
32
+ min_val, max_val = info.min, info.max
33
+
34
+ # Check actual value ranges
35
+ actual_min = np.nanmin(values)
36
+ actual_max = np.nanmax(values)
37
+
38
+ if actual_min < min_val or actual_max > max_val:
39
+ raise ValueError(
40
+ f"Values [{actual_min}, {actual_max}] exceed {target_dtype} "
41
+ f"range [{min_val}, {max_val}]"
42
+ )
43
+ elif np.issubdtype(target_dtype, np.floating):
44
+ info = np.finfo(target_dtype)
45
+ # Check for overflow/underflow
46
+ if np.any(np.abs(values[np.isfinite(values)]) > info.max):
47
+ raise ValueError(f"Values too large for {target_dtype}")
48
+
49
+
50
+ def discrete_to_continuous(self: GridProperty) -> None:
51
+ """Convert from discrete to continuous values."""
52
+ if not self.isdiscrete:
53
+ logger.debug("No need to convert, already continuous")
54
+ return
55
+
56
+ logger.debug("Converting to continuous ...")
57
+ val = self._values.copy()
58
+ val = val.astype(np.float64)
59
+ self._values = val
60
+ self._isdiscrete = False
61
+ self._codes = {}
62
+ self.roxar_dtype = np.float32
63
+
64
+
65
+ def continuous_to_discrete(self) -> None:
66
+ """Convert from continuous to discrete values."""
67
+ if self.isdiscrete:
68
+ logger.debug("No need to convert, already discrete")
69
+ return
70
+
71
+ logger.debug("Converting to discrete ...")
72
+ val = self._values.copy()
73
+
74
+ # Validate finite values only
75
+ finite_vals = (
76
+ val[np.isfinite(val)]
77
+ if not isinstance(val, np.ma.MaskedArray)
78
+ else val.compressed()
79
+ )
80
+ if len(finite_vals) > 0:
81
+ _validate_cast_range(finite_vals, np.int32)
82
+
83
+ # Round and cast, suppressing the NaN warning
84
+ val = np.round(val)
85
+ with np.errstate(invalid="ignore"):
86
+ val = val.astype(np.int32)
87
+
88
+ self._values = val
89
+ self._isdiscrete = True
90
+
91
+ self._codes = {
92
+ v: str(v)
93
+ for v in np.ma.unique(val)
94
+ if np.isfinite(v) and not isinstance(v, np.ma.core.MaskedConstant)
95
+ }
96
+ self.roxar_dtype = np.uint16
97
+
98
+
28
99
  def get_xy_value_lists(
29
100
  self: GridProperty,
30
101
  grid: Optional[Grid | GridProperty] = None,
@@ -134,12 +205,6 @@ def operation_polygons(
134
205
 
135
206
  gl.update_values_from_carray(proxy, cvals, np.float64, delete=True)
136
207
 
137
- proxyv = proxy.values.astype(np.int8)
138
-
139
- proxytarget = 1
140
- if not inside:
141
- proxytarget = 0
142
-
143
208
  if opname == "add":
144
209
  tmp = self.values.copy() + value
145
210
  elif opname == "sub":
@@ -170,8 +235,9 @@ def operation_polygons(
170
235
  # convert tmp back to correct dtype
171
236
  tmp = tmp.astype(dtype)
172
237
 
173
- self.values[proxyv == proxytarget] = tmp[proxyv == proxytarget]
174
- del tmp
238
+ mask = proxy.values == 1 if inside else proxy.values == 0
239
+
240
+ self.values[mask] = tmp[mask]
175
241
 
176
242
 
177
243
  def refine(
@@ -4,6 +4,7 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  from typing import TYPE_CHECKING, Any, Literal
7
+ from warnings import warn
7
8
 
8
9
  import numpy as np
9
10
  from numpy import ma
@@ -135,6 +136,51 @@ def export_prop_roxapi(
135
136
  rox.safe_close()
136
137
 
137
138
 
139
+ def _validate_dtype_in_roxar(
140
+ pval: np.ndarray, original_dtype: Any, dtype: Any, allow_unsafe_casting: bool = True
141
+ ) -> None:
142
+ """Local routine that check the range in xtgeo's parameter vs Roxar dtype"""
143
+ message = ""
144
+
145
+ if dtype != original_dtype:
146
+ message += (
147
+ f"Existing RMS icon has data type {original_dtype} while "
148
+ f"GridProperty has RMS data type {dtype}. This may cause issues in data "
149
+ "content while saving to RMS."
150
+ )
151
+
152
+ try:
153
+ if np.issubdtype(dtype, np.integer):
154
+ # Integer type
155
+ min_val, max_val = np.iinfo(dtype).min, np.iinfo(dtype).max
156
+ elif np.issubdtype(dtype, np.floating):
157
+ # Float type
158
+ min_val, max_val = np.finfo(dtype).min, np.finfo(dtype).max
159
+ else:
160
+ # Unknown type
161
+ raise RuntimeError("Probable bug, values array not integer or float")
162
+
163
+ if pval.min() < min_val or pval.max() > max_val:
164
+ message += (
165
+ f"Values outside {dtype} range [{min_val}, {max_val}] found. "
166
+ f"Range in xtgeo values are [{pval.min()}, {pval.max()}]"
167
+ )
168
+
169
+ except (ValueError, OverflowError):
170
+ # Handle edge cases gracefully
171
+ message += f"Could not validate range for dtype {dtype}. "
172
+
173
+ if message and allow_unsafe_casting:
174
+ message += (
175
+ "\nUnsafe casting is allowed; this means that original values may "
176
+ "be truncated which may give unpredictable results and/or mess "
177
+ "up code names and values settings."
178
+ )
179
+
180
+ if message:
181
+ warn(message, UserWarning)
182
+
183
+
138
184
  def _store_in_roxar(
139
185
  self: GridProperty,
140
186
  pname: str,
@@ -147,50 +193,60 @@ def _store_in_roxar(
147
193
 
148
194
  logger.info("Store in RMS...")
149
195
 
150
- val3d = self.values.copy()
151
-
152
- cellno = indexer.get_cell_numbers_in_range((0, 0, 0), indexer.dimensions)
153
-
154
- ijk = indexer.get_indices(cellno)
196
+ roxtype: Any = roxar # needed for mypy
197
+ roxar_property_type = (
198
+ roxtype.GridPropertyType.discrete
199
+ if self.isdiscrete
200
+ else roxtype.GridPropertyType.continuous
201
+ )
155
202
 
156
- iind = ijk[:, 0]
157
- jind = ijk[:, 1]
158
- kind = ijk[:, 2]
203
+ val3d = self.values.copy()
159
204
 
160
205
  dtype = self._roxar_dtype
161
206
  logger.info("DTYPE is %s for %s", dtype, pname)
162
207
 
163
- # casting will secure correct types
164
208
  if dtype not in VALID_ROXAR_DTYPES:
165
209
  raise TypeError(
166
210
  f"Roxar dtype is not valid: {dtype} must be in {VALID_ROXAR_DTYPES}"
167
211
  )
168
212
 
169
- pvalues = roxgrid.get_grid(realisation=realisation).generate_values(data_type=dtype)
170
-
171
- roxtype: Any = roxar # needed for mypy
172
- roxar_property_type = (
173
- roxtype.GridPropertyType.discrete
174
- if self.isdiscrete
175
- else roxtype.GridPropertyType.continuous
176
- )
177
-
178
- pvalues[cellno] = val3d[iind, jind, kind]
179
-
180
213
  properties = roxgrid.properties
181
-
214
+ original_dtype = dtype
182
215
  if pname not in properties:
183
216
  rprop = properties.create(
184
217
  pname, property_type=roxar_property_type, data_type=dtype
185
218
  )
186
219
  else:
187
220
  rprop = properties[pname]
188
- dtype = rprop.data_type
221
+ original_dtype = rprop.data_type
222
+
223
+ _validate_dtype_in_roxar(val3d, original_dtype, dtype, casting == "unsafe")
189
224
 
190
- rprop.set_values(pvalues.astype(dtype, casting=casting), realisation=realisation)
225
+ dtype = original_dtype
226
+ val3d = val3d.astype(dtype, casting=casting)
191
227
 
192
- if self.isdiscrete:
193
- rprop.code_names = _rox_compatible_codes(self.codes)
228
+ cellno = indexer.get_cell_numbers_in_range((0, 0, 0), indexer.dimensions)
229
+
230
+ ijk = indexer.get_indices(cellno)
231
+
232
+ iind = ijk[:, 0]
233
+ jind = ijk[:, 1]
234
+ kind = ijk[:, 2]
235
+
236
+ pvalues = roxgrid.get_grid(realisation=realisation).generate_values(data_type=dtype)
237
+
238
+ pvalues[cellno] = val3d[iind, jind, kind]
239
+ rprop.set_values(pvalues, realisation=realisation)
240
+
241
+ if self.isdiscrete and "float" not in str(original_dtype):
242
+ try:
243
+ rprop.code_names = _rox_compatible_codes(self.codes)
244
+ except ValueError as verr:
245
+ message = (
246
+ f"Trying to set codes in Roxar: {self.codes} for type "
247
+ f"{self._roxar_dtype}. {str(verr)} Consider editing the codes!"
248
+ )
249
+ raise ValueError(message)
194
250
 
195
251
 
196
252
  def _fix_codes(
xtgeo/grid3d/grid.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
- from typing import TYPE_CHECKING, Any, Literal, NoReturn
6
+ from typing import TYPE_CHECKING, Any, Literal
7
7
 
8
8
  import numpy as np
9
9
  import numpy.ma as ma
@@ -994,13 +994,16 @@ class Grid(_Grid3D):
994
994
  # Create/import/export
995
995
  # ==================================================================================
996
996
 
997
- def to_file(self, gfile: FileLike, fformat: str = "roff") -> None:
997
+ def to_file(
998
+ self, gfile: FileLike, fformat: str = "roff", rle: bool = False
999
+ ) -> None:
998
1000
  """Export grid geometry to file, various vendor formats.
999
1001
 
1000
1002
  Args:
1001
1003
  gfile (str): Name of output file
1002
1004
  fformat (str): File format; roff/roff_binary/roff_ascii/
1003
1005
  grdecl/bgrdecl/egrid.
1006
+ rle (bool): Use run-length encoding (only for grdecl file)
1004
1007
 
1005
1008
  Raises:
1006
1009
  OSError: Directory does not exist
@@ -1018,7 +1021,7 @@ class Grid(_Grid3D):
1018
1021
  elif fformat in FileFormat.ROFF_ASCII.value:
1019
1022
  _grid_export.export_roff(self, _gfile.name, "ascii")
1020
1023
  elif fformat in FileFormat.GRDECL.value:
1021
- _grid_export.export_grdecl(self, _gfile.name, 1)
1024
+ _grid_export.export_grdecl(self, _gfile.name, 1, rle)
1022
1025
  elif fformat in FileFormat.BGRDECL.value:
1023
1026
  _grid_export.export_grdecl(self, _gfile.name, 0)
1024
1027
  elif fformat in FileFormat.EGRID.value:
@@ -1577,9 +1580,30 @@ class Grid(_Grid3D):
1577
1580
 
1578
1581
  return self.get_subgrids()
1579
1582
 
1580
- def get_zoneprop_from_subgrids(self) -> NoReturn:
1581
- """Make a XTGeo GridProperty instance for a Zone property subgrid index."""
1582
- raise NotImplementedError("Not yet; todo")
1583
+ def get_zoneprop_from_subgrids(self) -> xtgeo.GridProperty | None:
1584
+ """
1585
+ Create a discrete GridProperty encoding subgrid indices as zone values.
1586
+
1587
+ Returns:
1588
+ A GridProperty where each layer belonging to a subgrid is assigned a unique
1589
+ integer zone index (starting from 1). The property codes map these indices
1590
+ to subgrid names. Returns None if no subgrids are defined.
1591
+ """
1592
+ if not self.subgrids:
1593
+ return None
1594
+
1595
+ zoneprop = xtgeo.GridProperty(
1596
+ ncol=self.ncol,
1597
+ nrow=self.nrow,
1598
+ nlay=self.nlay,
1599
+ name="Zone",
1600
+ discrete=True,
1601
+ values=0,
1602
+ )
1603
+ for i, (name, layers) in enumerate(self.subgrids.items()):
1604
+ zoneprop.codes[i + 1] = name
1605
+ zoneprop.values[:, :, min(layers) - 1 : max(layers)] = i + 1
1606
+ return zoneprop
1583
1607
 
1584
1608
  def get_boundary_polygons(
1585
1609
  self: Grid,
@@ -1966,12 +1990,14 @@ class Grid(_Grid3D):
1966
1990
  ffl: Free fluid level e.g. FWL (or level whatever is required; a level from
1967
1991
  which cells above will be shown as delta heights (positive), while
1968
1992
  cells below will have 0.0 values.
1969
- option: How to compute values, as either "cell_center_above_ffl" or
1970
- "cell_corners_above_ffl". The first one looks at cell Z centerlines, and
1971
- compute the top, the bottom and the midpoint. The second will look at
1972
- cell corners, using the uppermost corner for top, and the lowermost
1973
- corner for bottom. In both cases, values are modified if cell is
1974
- intersected with the provided ffl.
1993
+ option: How to compute values, as either "cell_center_above_ffl",
1994
+ "cell_corners_above_ffl" or "truncated_cell_corners_above_ffl".
1995
+ The first one looks at cell Z centerlines, and compute the top,
1996
+ the bottom and the midpoint. The second will look at cell corners,
1997
+ using the uppermost corner for top, and the lowermost corner for bottom.
1998
+ The third will truncate all cell corners above ffl and compute cell Z
1999
+ centerlines. In all cases, values are modified if cell is intersected
2000
+ with the provided ffl.
1975
2001
 
1976
2002
  Returns:
1977
2003
  (htop, hbot, hmid) delta heights, as xtgeo GridProperty objects
@@ -773,6 +773,7 @@ class GridProperty(_Grid3D):
773
773
  append: bool = False,
774
774
  dtype: type[np.float32] | type[np.float64] | type[np.int32] | None = None,
775
775
  fmt: str | None = None,
776
+ rle: bool = False,
776
777
  ) -> None:
777
778
  """
778
779
  Export the grid property to file.
@@ -791,6 +792,7 @@ class GridProperty(_Grid3D):
791
792
  Eclipse formats.
792
793
  fmt: Format for ascii grdecl format. Default is None. If specified,
793
794
  the user is responsible for a valid format specifier, e.g. "%8.4f".
795
+ rle: Use run length encoding, only for grdecl format.
794
796
 
795
797
  Example::
796
798
 
@@ -815,6 +817,7 @@ class GridProperty(_Grid3D):
815
817
  append=append,
816
818
  dtype=dtype,
817
819
  fmt=fmt,
820
+ rle=rle,
818
821
  )
819
822
 
820
823
  @classmethod
@@ -1222,36 +1225,11 @@ class GridProperty(_Grid3D):
1222
1225
 
1223
1226
  def discrete_to_continuous(self) -> None:
1224
1227
  """Convert from discrete to continuous values."""
1225
- if not self.isdiscrete:
1226
- logger.debug("No need to convert, already continuous")
1227
- return
1228
-
1229
- logger.debug("Converting to continuous ...")
1230
- val = self._values.copy()
1231
- val = val.astype("float64")
1232
- self._values = val
1233
- self._isdiscrete = False
1234
- self._codes = {}
1235
- self.roxar_dtype = np.float32
1228
+ _gridprop_op1.discrete_to_continuous(self)
1236
1229
 
1237
1230
  def continuous_to_discrete(self) -> None:
1238
1231
  """Convert from continuous to discrete values."""
1239
- if self.isdiscrete:
1240
- logger.debug("No need to convert, already discrete")
1241
- return
1242
-
1243
- logger.debug("Converting to discrete ...")
1244
- val = self._values.copy()
1245
- val = val.astype(np.int32)
1246
- self._values = val
1247
- self._isdiscrete = True
1248
-
1249
- # make the code list
1250
- uniq = np.unique(val).tolist()
1251
- codes = dict(zip(uniq, uniq))
1252
- codes = {k: str(v) for k, v in codes.items()} # val as strings
1253
- self._codes = codes
1254
- self.roxar_dtype = np.uint16
1232
+ _gridprop_op1.continuous_to_discrete(self)
1255
1233
 
1256
1234
  # ==================================================================================
1257
1235
  # Operations restricted to inside/outside polygons
@@ -7,7 +7,7 @@ if(CMAKE_VERSION VERSION_LESS "3.0.0")
7
7
  message(FATAL_ERROR "CMake >= 3.0.0 required")
8
8
  endif()
9
9
  cmake_policy(PUSH)
10
- cmake_policy(VERSION 3.0.0...3.29)
10
+ cmake_policy(VERSION 3.0.0...3.31)
11
11
  #----------------------------------------------------------------
12
12
  # Generated CMake target import file.
13
13
  #----------------------------------------------------------------
xtgeo/lib/libfmt.a CHANGED
Binary file
@@ -1,5 +1,5 @@
1
- prefix=/var/folders/x7/ch5v91h56_zbvbd1y2f600dm0000gn/T/tmpwcubuvqo/wheel/platlib/xtgeo
2
- exec_prefix=/var/folders/x7/ch5v91h56_zbvbd1y2f600dm0000gn/T/tmpwcubuvqo/wheel/platlib/xtgeo
1
+ prefix=/var/folders/sw/lqy3v8g55m76fhwckg439jjm0000gn/T/tmpzomsrilx/wheel/platlib/xtgeo
2
+ exec_prefix=/var/folders/sw/lqy3v8g55m76fhwckg439jjm0000gn/T/tmpzomsrilx/wheel/platlib/xtgeo
3
3
  libdir=${exec_prefix}/lib
4
4
  includedir=${prefix}/include
5
5
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xtgeo
3
- Version: 4.11.0
3
+ Version: 4.12.1
4
4
  Summary: XTGeo is a Python library for 3D grids, surfaces, wells, etc
5
5
  Keywords: grids,surfaces,wells,cubes
6
6
  Author-Email: Equinor <fg_fmu-atlas@equinor.com>
@@ -14,7 +14,6 @@ Classifier: Operating System :: Microsoft :: Windows
14
14
  Classifier: Operating System :: MacOS
15
15
  Classifier: Natural Language :: English
16
16
  Classifier: Programming Language :: Python
17
- Classifier: Programming Language :: Python :: 3.9
18
17
  Classifier: Programming Language :: Python :: 3.10
19
18
  Classifier: Programming Language :: Python :: 3.11
20
19
  Classifier: Programming Language :: Python :: 3.12
@@ -27,7 +26,7 @@ Project-URL: Homepage, https://github.com/equinor/xtgeo
27
26
  Project-URL: Repository, https://github.com/equinor/xtgeo
28
27
  Project-URL: Issues, https://github.com/equinor/xtgeo/issues
29
28
  Project-URL: Documentation, https://xtgeo.readthedocs.io
30
- Requires-Python: >=3.9
29
+ Requires-Python: >=3.10
31
30
  Requires-Dist: deprecation
32
31
  Requires-Dist: h5py>=3
33
32
  Requires-Dist: hdf5plugin>=2.3
@@ -92,7 +91,7 @@ Detailed documentation for [XTGeo at Read _the_ Docs](https://xtgeo.readthedocs.
92
91
 
93
92
  ## Feature summary
94
93
 
95
- - Python 3.9+ support
94
+ - Python 3.10+ support
96
95
  - Focus on high speed, using numpy and pandas with C backend
97
96
  - Regular surfaces, i.e. 2D maps with regular sampling and rotation
98
97
  - 3D grids (corner-point), supporting several formats such as
@@ -1,8 +1,12 @@
1
1
  cxtgeo.py,sha256=MjY_SfwNrahCXED08vVn7OsQPQPU7rsKwxSp2GY5WKI,33396
2
2
  cxtgeoPYTHON_wrap.c,sha256=jdx6wYGtLu7KKXcEHC9XqRTEMkYc4x4D07FPmYKSjPE,635145
3
+ xtgeo-4.12.1.dist-info/RECORD,,
4
+ xtgeo-4.12.1.dist-info/WHEEL,sha256=ARvpZEbgFu-cAxZINNemqHWSYlsYgHkQqksAmhPJqFw,141
5
+ xtgeo-4.12.1.dist-info/METADATA,sha256=_bQC78VJmRcAEiNh0saCXL7wAfj0v0NO0NorLX8PaRk,5741
6
+ xtgeo-4.12.1.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
3
7
  xtgeo/__init__.py,sha256=-p6vKOv7EfAt1S-7CmWHfN8iHjFHQ--5UwhIysS_gRQ,5588
4
- xtgeo/_internal.cpython-310-darwin.so,sha256=T8kZvEleb5ut1Z4sXGcoQajgFEohSDX13fH5fwei8JY,714816
5
- xtgeo/_cxtgeo.cpython-310-darwin.so,sha256=dBa834ccc7b2VxkZJN-KMMTKxrj2BGiv0HpSujeYQ_E,414880
8
+ xtgeo/_internal.cpython-310-darwin.so,sha256=lbuA03zaiPz7wBe1oi_DeNwiJOvh5GSa80nICyv_Obw,731600
9
+ xtgeo/_cxtgeo.cpython-310-darwin.so,sha256=0POVU6BjxcFM28OJFsBGQ3XImpw0AIjm0j4msDRA3M8,414912
6
10
  xtgeo/well/_wells_utils.py,sha256=hjJEBdtILtK87sbCYWHJ7aEgqgKkak6ihfOcxSixNPo,4945
7
11
  xtgeo/well/_blockedwell_roxapi.py,sha256=G0IEChtCF7SPV_nXDIYsJ5L601HjA9QdWU7cNoyJyus,7489
8
12
  xtgeo/well/_well_io.py,sha256=CHvLfuIVNoX_4PQd7sCWg5xvyCd1L73J5dkmV2uaJqU,9821
@@ -32,42 +36,42 @@ xtgeo/include/fmt/std.h,sha256=ogzbgTUxCUFupDozCWAG0yMhWeiV6QtkEbaR0p9jR8A,22277
32
36
  xtgeo/include/fmt/base.h,sha256=E8jZU_stmNyVUondFmmZvSLbq_66f0hrNpPCxtnWJ9s,103990
33
37
  xtgeo/grid3d/_grid_import.py,sha256=T--Nk4CVKifCskc2i8y6cpFXV2LZdTmJC3iSxKXXiZE,2593
34
38
  xtgeo/grid3d/_roff_parameter.py,sha256=UNS2cngVP3GIAr5nVCoGQYJq062KtfvCAkFb0FEJY68,11073
35
- xtgeo/grid3d/grid.py,sha256=8ImGx_fgKcbcsnV3GuxWX_9sPxK_iWe3cPWbAmI6bjA,105740
39
+ xtgeo/grid3d/grid.py,sha256=hzKS9W51pgWl6WKHgykqpVyyo11pLGmHF4nTgpe0pm8,106706
36
40
  xtgeo/grid3d/_grid_boundary.py,sha256=oxWmQdy9cG1PzAtOH-IcCqAQYfmIwTD87tc-c4VgTA8,2308
37
41
  xtgeo/grid3d/_grid_import_ecl.py,sha256=gIcX4uMnwg0UnYMXyUdJsFSNKV-yhLFtc88AL1fmx6Y,3453
38
- xtgeo/grid3d/_gridprop_roxapi.py,sha256=4asCcVUXF42TKyD3oXTavBdPkAcAjZsra9QI12I3has,6857
39
- xtgeo/grid3d/_gridprop_op1.py,sha256=7xiGJe9rK4pKNux1rOi-UWcuPYKZAd6TqlBTmkryjjM,6813
42
+ xtgeo/grid3d/_gridprop_roxapi.py,sha256=llGUYpBeLhj3A7bf3EcMe2kz-OiW_O-Y6JCjsqVM-e0,8967
43
+ xtgeo/grid3d/_gridprop_op1.py,sha256=o0JemRzyECX0qzUpj9OXGB9nb1IOZ8-5Gs-1i_a302g,8956
40
44
  xtgeo/grid3d/_grid_import_roff.py,sha256=UViMnU44b75x4EfgnEmUYLFTK0R33lS9wAw0aBgzVzw,4039
41
45
  xtgeo/grid3d/_grid_hybrid.py,sha256=e-wj_RKknOSqPMU3wMBG_0maYJLEqJnv1_zp5eG55MY,1600
42
46
  xtgeo/grid3d/_grid3d_fence.py,sha256=XdIY-TlSgoTuRtRyRNqLvXLoR9F1QTEkFJO-rgKlqwE,9217
43
47
  xtgeo/grid3d/_grid3d.py,sha256=eM6842v2Q1Sb75zM3KynCITeV57OlXcusGEa_NWLPSU,740
44
48
  xtgeo/grid3d/_ecl_output_file.py,sha256=WPb7VGPyt89MpKtxL2jLoSKwn04jIfNsB11L-9wMhSY,2014
45
- xtgeo/grid3d/_grdecl_grid.py,sha256=R5zm3ninIts17pGWPbVI-1a747s9Igwj7pZXIylS4I4,12893
46
- xtgeo/grid3d/_grid_refine.py,sha256=qHdiHF2DJRhP6QGzPryr2nsghZtWAgscBi8kLgIDCTM,8541
49
+ xtgeo/grid3d/_grdecl_grid.py,sha256=Er13V2E-4LtvpeLwFA-EhGKJxqWU-LUzR-OMZTKPoZo,13602
50
+ xtgeo/grid3d/_grid_refine.py,sha256=VgcwTyUPafgtLRb5Cam0GbW7DJiL94xBgj1yM6fKKQM,8558
47
51
  xtgeo/grid3d/_roff_grid.py,sha256=Or-QR92AB_oE-6lbMVhQjXC_E1HAcxZjFlbep3cFo6w,17272
48
52
  xtgeo/grid3d/__init__.py,sha256=k6T-xKWIBey_WMjWDnYZfvCsLQGokCL9RjqBZNvbUq0,332
49
53
  xtgeo/grid3d/types.py,sha256=s4iR1hmpZ_mF7xLXqujZaT2Sa6RK0uA48ZywBmkjoD0,275
50
- xtgeo/grid3d/_grid_export.py,sha256=bzjHHcwVggip3efzwSHI6Sl0Sw-EIqT_f3GJAcFkJsk,7170
54
+ xtgeo/grid3d/_grid_export.py,sha256=2Idg_5OGwS3Swu992RqYovDHBxfakjphN6ozKnDU1V0,7270
51
55
  xtgeo/grid3d/_ecl_inte_head.py,sha256=F22CT5VOpIYED2tMgmR5_FWtwq843S5vV3IbYvTehHM,4625
52
56
  xtgeo/grid3d/_gridprop_import_eclrun.py,sha256=k1SjOp4PmZ3nIcDM6N-2FDvDx3jMPf7rea3IGOrgo88,5096
53
57
  xtgeo/grid3d/_grid3d_utils.py,sha256=zIQZpWqAf33nVpC2aDqquPhd7Tqr-rRZvAaXPF-kxG0,7249
54
58
  xtgeo/grid3d/_ecl_grid.py,sha256=f12-cvxZblUZSAGIxKxJ438akK5gBFYebgSbVxZP6Jc,25905
55
59
  xtgeo/grid3d/_grid_roxapi.py,sha256=DJnG2CL56ygt2OEdVyH3oiMoyud-bra08tuLpFedCWQ,8907
56
60
  xtgeo/grid3d/_ecl_logi_head.py,sha256=CzBi7MSyPFeFGIKeBcex8qgm6VICUY6YjiKs0X9_UR4,2664
57
- xtgeo/grid3d/_grdecl_format.py,sha256=qUxq4c4e4-HGccFshLoOoGkgwwpaZeMbnWi4PhxPA78,8775
61
+ xtgeo/grid3d/_grdecl_format.py,sha256=Nrp-dUh8p6G0WgDiWRfY_otxPwS_wUaUpReXVoj-U_s,10138
58
62
  xtgeo/grid3d/_grid_wellzone.py,sha256=cBLmO4YL62vHEVvltxFHyQScZIY2RQQcrIqq9Cx6euE,5786
59
63
  xtgeo/grid3d/_find_gridprop_in_eclrun.py,sha256=zUv1Fk5ouSICYd9SR7NpHbN78rFBcN7FBlURmeyaedk,21434
60
64
  xtgeo/grid3d/_gridprop_lowlevel.py,sha256=8aUDxj1mPu8yH0F9FVaxxumew1OdBOkwEQI5tjIZEQI,5086
61
- xtgeo/grid3d/_grid_etc1.py,sha256=54q91KLpkvtYweWHer7Fq18O0haA2nP-K-nikGPl-dI,43173
65
+ xtgeo/grid3d/_grid_etc1.py,sha256=Yt5AjeXJ6xPbUlIbzer6N37_Cv53NVkxO2nnhY2uVWU,43571
62
66
  xtgeo/grid3d/_gridprops_import_eclrun.py,sha256=kWzubpyeorvfUSEjIF-UdoGnzQYYsUePW2jUtgoTuf0,11438
63
67
  xtgeo/grid3d/_gridprop_import_roff.py,sha256=tXp_mMqwfblSEb5KUbMOcL-TgGVn--vEqzPeXAK1IuI,1523
64
- xtgeo/grid3d/_gridprop_export.py,sha256=J_EL1bfs2ZB0B-foQLRhYjCQ1lB40yVHUD_utrd3TlU,5456
68
+ xtgeo/grid3d/_gridprop_export.py,sha256=i4aukBXCeoYYIVJytG8ObjA1KyDGQqsQr2XukSSbZYg,6533
65
69
  xtgeo/grid3d/_gridprop_import_grdecl.py,sha256=t2Heqw5f9azf_LJlIae-vMe9s0-HJr88TIKZCeTfqpc,4133
66
70
  xtgeo/grid3d/_egrid.py,sha256=zOYcmK_3-BrCwHLZiZis7nuzdm_n0jPq_P2_J0X4_wY,33835
67
71
  xtgeo/grid3d/_grid_import_xtgcpgeom.py,sha256=VtLKqxwNRZYlrPFRPHq-GUO0er-qLkmRlHVrhiTMosA,10202
68
72
  xtgeo/grid3d/grid_properties.py,sha256=Ur2gPRV69JEfLidUxRulr5lO2pKMs6CVsFtxp5ZLMIo,24294
69
73
  xtgeo/grid3d/_gridprops_import_roff.py,sha256=u6UobGgMaIBrCUOvGotAv_PJAoAJQYaFGH_kGo1RvRY,2467
70
- xtgeo/grid3d/grid_property.py,sha256=MDcyEpCXAW6eLLOO3E129rVNv3zURkwPAWhnT_33O7A,45352
74
+ xtgeo/grid3d/grid_property.py,sha256=aeBgWQ9cGq3ZPSuWm9crlFulWP25Leu21V4Ax51KvqQ,44667
71
75
  xtgeo/grid3d/_gridprop_import_xtgcpprop.py,sha256=-9576pMYO78IZl4VgaI_dk-ArCh0LRHt6cQL8MyEgos,4859
72
76
  xtgeo/grid3d/_gridprop_value_init.py,sha256=tN3LVziZsyIxbghkpGt6tCsHWFvGEm1e8ZpYpBgBdB8,4314
73
77
  xtgeo/cube/_cube_roxapi.py,sha256=mj9Nnug13t_Fsu0w4KKaJNEmrB_kYb0m133T6W-7wt0,4921
@@ -109,7 +113,7 @@ xtgeo/surface/_regsurf_cube.py,sha256=xZXIE418guB3rG8iscI9xQ0deAtJ_auu1XDe3ml9GB
109
113
  xtgeo/surface/_regsurf_utils.py,sha256=P91jVmstYGe-bn6ut-9xfd8DiOw7QUCt2DLwbnlJwB4,2307
110
114
  xtgeo/surface/_regsurf_import.py,sha256=IXD1T4hLRk705RbixSfcOxyrBUilRRbUHYC_S_xZqZA,10396
111
115
  xtgeo/common/_xyz_enum.py,sha256=IiKRWhvIKKRhUH2QwpDttW4XqJ4f4StPrVt1vfVBTxM,1045
112
- xtgeo/common/version.py,sha256=O12saSYjwbRCsG-uGD4_hG7qeZhWVDdXRNxpZkiz9TU,714
116
+ xtgeo/common/version.py,sha256=2O2wY2SWIqA5uRiQW5SoPKR83a3fWIokUR1A5gARznI,714
113
117
  xtgeo/common/log.py,sha256=3C_WdYpCMEr5ebIGoGmalXNP0O2IGvLuJdzeuR8Cd-o,2742
114
118
  xtgeo/common/xtgeo_dialog.py,sha256=AcT8DrIBViSZJltwZuEfrcRbmicQEFfbwlf_gV2-6k8,17129
115
119
  xtgeo/common/constants.py,sha256=vp6k7lkWKKxyvojQZ1yYhhwXRXGZlMCPK8WY9nG2yns,749
@@ -119,19 +123,15 @@ xtgeo/common/_angles.py,sha256=VuNLV9pTooF_V3thFTg9SmTMBnKkv6ZxyvOXw22vLE0,822
119
123
  xtgeo/common/calc.py,sha256=xrJIVqFlrPIjhORbMThQylbjD4xdMM_vtEqBu5vc7C8,10134
120
124
  xtgeo/common/exceptions.py,sha256=4BRCtzk74eyc4LeeapAWFLkNh-TT0ev5pDxKJlPaI7s,1175
121
125
  xtgeo/common/sys.py,sha256=NGxnVoPoAGx_lekTF9QPBEf-VF8ORp4buoBeh6jkZko,4978
122
- xtgeo/lib/libfmt.a,sha256=oADtTh14EgQOyojMXk2LQQqYSpX53A6x4a8st-SyUUg,165328
123
- xtgeo/lib/pkgconfig/fmt.pc,sha256=vlmt5NrdOiUkCUMie9v8r46IFLegnMgi_4CP6luRlE4,353
126
+ xtgeo/lib/libfmt.a,sha256=omuVtaV2vS0fAnQplzSzk1w4MlTs-8KvsenMsUgrd6w,163432
127
+ xtgeo/lib/pkgconfig/fmt.pc,sha256=5hTjD4wdFSaXxPcZV3J948BpGjVDJ0Ej9vmp9ZPZ7jM,353
124
128
  xtgeo/lib/cmake/fmt/fmt-targets-release.cmake,sha256=0hurnnAYtVc8r8yvaxkXAS5Op01RPnwKE6SFNOL1nYA,807
125
129
  xtgeo/lib/cmake/fmt/fmt-config.cmake,sha256=Cd-Xn_HSZ-Lk5ZBDX8q49OQKSvnS0_k4r0-tb6G8LW4,999
126
130
  xtgeo/lib/cmake/fmt/fmt-config-version.cmake,sha256=p1j16l20z3aEnEsIu-cbcrqFT32K2IJNZl10B8Ww2pk,1862
127
- xtgeo/lib/cmake/fmt/fmt-targets.cmake,sha256=311cnawW6a6LfThZkmD63ECINF5kzP6ZDIPUNuQocoQ,4464
131
+ xtgeo/lib/cmake/fmt/fmt-targets.cmake,sha256=ldmu9wnYq11UbsJ79TSK4ejJA-Zr20Ih9DyGS7EbPHM,4464
128
132
  xtgeo/roxutils/roxutils.py,sha256=BGvnWhYKvX2h7eU0ZXNUuDnHi8IM_2lLIzpq9lWZI6M,6904
129
133
  xtgeo/roxutils/__init__.py,sha256=UJKTgNSIGdtRxaUAwot4D5sGCTdfITw6BRaOnGkk41k,92
130
134
  xtgeo/roxutils/_roxutils_etc.py,sha256=K1fJKFBinfj32GGYnauU5t1sIgJ0l7N2gkXvaxMpNS8,3730
131
135
  xtgeo/roxutils/_roxar_loader.py,sha256=R2yBt7su6_u87UP00lLaiDxW0QuSnFLkEJQgcTWhjZI,1904
132
136
  xtgeo/metadata/metadata.py,sha256=mGkjNYcU4Y11EoLKTzSNW6JYpJVvIYNCbQ8obKMv21g,12436
133
137
  xtgeo/metadata/__init__.py,sha256=WXmKZjBGV3kr-lmrPxr3Ph7CpI5KIn3WKlE23crBteA,320
134
- xtgeo-4.11.0.dist-info/RECORD,,
135
- xtgeo-4.11.0.dist-info/WHEEL,sha256=iPQWBjKNkGcw8UzZdE3DxEbRx5fyyzLkJ1izF6VsBJA,141
136
- xtgeo-4.11.0.dist-info/METADATA,sha256=_ORJH3UT7GiS4VR4R8EJ5sw4uahZ_BjT6yugeM_76sU,5789
137
- xtgeo-4.11.0.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: scikit-build-core 0.11.5
2
+ Generator: scikit-build-core 0.11.6
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp310-cp310-macosx_11_0_arm64
5
5
  Generator: delocate 0.13.0