xtgeo 4.10.1__cp310-cp310-macosx_11_0_arm64.whl → 4.12.0__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
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '4.10.1'
21
- __version_tuple__ = version_tuple = (4, 10, 1)
31
+ __version__ = version = '4.12.0'
32
+ __version_tuple__ = version_tuple = (4, 12, 0)
33
+
34
+ __commit_id__ = commit_id = 'g4f136d221'
@@ -63,6 +63,7 @@ class CubeAttrs:
63
63
  _upper: RegularSurface | None = None # upper surf, resampled to cube map resolution
64
64
  _lower: RegularSurface | None = None # lower surf, resampled to cube map resolution
65
65
  _min_thickness_mask: RegularSurface | None = None # mask for min. thickness trunc.
66
+ _mask_map_by_traceidcode: RegularSurface | None = None # mask for traceidcode 2
66
67
 
67
68
  _result_attr_maps: dict = field(default_factory=dict) # holds the resulting maps
68
69
 
@@ -94,6 +95,7 @@ class CubeAttrs:
94
95
  else self.lower_surface
95
96
  )
96
97
 
98
+ # the template surface is the topology that defines the resulting attribute maps
97
99
  self._template_surface = (
98
100
  upper
99
101
  if isinstance(self.upper_surface, (float, int))
@@ -184,7 +186,7 @@ class CubeAttrs:
184
186
  from xtgeo import Cube # avoid circular import by having this here
185
187
 
186
188
  cubev = self.cube.values.copy() # copy, so we don't change the input instance
187
- cubev[self.cube.traceidcodes == 2] = np.nan # set dead traces to nan
189
+ cubev[self.cube.traceidcodes == 2] = 0.0 # set traceidcode 2 to zero
188
190
 
189
191
  # Create a boolean mask based on the threshold
190
192
  mask = self._depth_array < self._outside_depth
@@ -311,13 +313,20 @@ class CubeAttrs:
311
313
  attr_map = self._upper.copy()
312
314
  attr_map.values = np.ma.masked_invalid(values)
313
315
 
316
+ # apply mask for the cube's dead traces (traceidcode 2)
317
+ attr_map.values = np.ma.masked_where(
318
+ self.cube.traceidcodes == 2, attr_map.values
319
+ )
320
+
314
321
  # now resample to the original input map
315
322
  attr_map_resampled = self._template_surface.copy()
316
323
  attr_map_resampled.resample(attr_map)
317
324
 
318
- attr_map_resampled.values = np.ma.masked_where(
319
- self.upper_surface.values.mask, attr_map_resampled.values
320
- )
325
+ # Use template_surface consistently for masking (it's already set correctly)
326
+ if hasattr(self._template_surface.values, "mask"):
327
+ attr_map_resampled.values = np.ma.masked_where(
328
+ self._template_surface.values.mask, attr_map_resampled.values
329
+ )
321
330
 
322
331
  self._result_attr_maps[attr_name] = attr_map_resampled
323
332
 
@@ -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(
@@ -1053,13 +1064,18 @@ def inactivate_inside(
1053
1064
  raise RuntimeError("Problems with one or more polygons. Not closed?")
1054
1065
 
1055
1066
 
1056
- def collapse_inactive_cells(self: Grid) -> None:
1067
+ def collapse_inactive_cells(self: Grid, internal: bool = True) -> None:
1057
1068
  """Collapse inactive cells."""
1058
- self._set_xtgformat1()
1069
+ logger.debug("Collapsing inactive cells...")
1070
+ self._set_xtgformat2()
1059
1071
 
1060
- _cxtgeo.grd3d_collapse_inact(
1061
- self.ncol, self.nrow, self.nlay, self._zcornsv, self._actnumsv
1062
- )
1072
+ grid_cpp = _internal.grid3d.Grid(self)
1073
+ new_zcornsv = grid_cpp.collapse_inactive_cells(collapse_internal=internal)
1074
+
1075
+ if new_zcornsv is not None:
1076
+ self._zcornsv = new_zcornsv
1077
+
1078
+ logger.debug("Collapsing inactive cells done")
1063
1079
 
1064
1080
 
1065
1081
  def copy(self: Grid) -> Grid:
@@ -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:
@@ -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
@@ -2295,7 +2321,7 @@ class Grid(_Grid3D):
2295
2321
  * maxangle_topbase_proj (degrees) max angle projected (bird view)
2296
2322
  * minangle_sides (degress) minimum angle, all side surfaces
2297
2323
  * maxangle_sides (degress) maximum angle, all side surfaces
2298
- * collapsed (int) Integer, 1 of one or more corners are collpased in Z
2324
+ * collapsed (int) Integer, 1 of one or more corners are collapsed in Z
2299
2325
  * faulted (int) Integer, 1 if cell is faulted (one or more neighbours offset)
2300
2326
  * negative_thickness (int) Integer, 1 if cell has negative thickness
2301
2327
  * concave_proj (int) 1 if cell is concave seen from projected bird view
@@ -2332,7 +2358,7 @@ class Grid(_Grid3D):
2332
2358
  inside: bool = True,
2333
2359
  force_close: bool = False,
2334
2360
  ) -> None:
2335
- """Inacativate grid inside a polygon.
2361
+ """Inactivate grid inside a polygon.
2336
2362
 
2337
2363
  The Polygons instance may consist of several polygons. If a polygon
2338
2364
  is open, then the flag force_close will close any that are not open
@@ -2359,14 +2385,30 @@ class Grid(_Grid3D):
2359
2385
  layer_range: tuple[int, int] | None = None,
2360
2386
  force_close: bool = False,
2361
2387
  ) -> None:
2362
- """Inacativate grid outside a polygon."""
2388
+ """Inactivate grid outside a polygon."""
2363
2389
  self.inactivate_inside(
2364
2390
  poly, layer_range=layer_range, inside=False, force_close=force_close
2365
2391
  )
2366
2392
 
2367
- def collapse_inactive_cells(self) -> None:
2368
- """Collapse inactive layers where, for I J with other active cells."""
2369
- _grid_etc1.collapse_inactive_cells(self)
2393
+ def collapse_inactive_cells(self, internal: bool = True) -> None:
2394
+ """Collapse inactive layers per I J column (~vertically).
2395
+
2396
+ Seen by I,J column, the inactive cells are collapsed to the first active cell in
2397
+ the column. First transversed from top, then from bottom. If no active cells in
2398
+ the column, the (invisible) Z coordinates are averaged to one common location.
2399
+
2400
+ If `internal` is True (default), then also internal inactive cells (i.e.
2401
+ inactive "hole" surrounded by active cells) are collapsed. In this case the Z
2402
+ coordinates of the adjacent active cells are moved to fill the gap.
2403
+
2404
+ The current grid instance will be updated.
2405
+
2406
+ Args:
2407
+ internal: If True (default), then the internal collapse is also done.
2408
+
2409
+ .. versionchanged:: 4.11 Added ``internal option``, algorithm is improved
2410
+ """
2411
+ _grid_etc1.collapse_inactive_cells(self, internal=internal)
2370
2412
 
2371
2413
  def crop(
2372
2414
  self,
@@ -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/y6/nj790rtn62lfktb1sh__79hc0000gn/T/tmpt8yc8s7_/wheel/platlib/xtgeo
2
- exec_prefix=/var/folders/y6/nj790rtn62lfktb1sh__79hc0000gn/T/tmpt8yc8s7_/wheel/platlib/xtgeo
1
+ prefix=/var/folders/sw/lqy3v8g55m76fhwckg439jjm0000gn/T/tmp3m0t6bqc/wheel/platlib/xtgeo
2
+ exec_prefix=/var/folders/sw/lqy3v8g55m76fhwckg439jjm0000gn/T/tmp3m0t6bqc/wheel/platlib/xtgeo
3
3
  libdir=${exec_prefix}/lib
4
4
  includedir=${prefix}/include
5
5
 
@@ -10,10 +10,17 @@ The metadata works through the various datatypes in XTGeo. For example::
10
10
 
11
11
  """
12
12
 
13
+ from __future__ import annotations
14
+
15
+ from typing import TYPE_CHECKING, Any
16
+
13
17
  import xtgeo
14
18
  from xtgeo.common.constants import UNDEF
15
19
  from xtgeo.common.log import null_logger
16
20
 
21
+ if TYPE_CHECKING:
22
+ from datetime import datetime
23
+
17
24
  logger = null_logger(__name__)
18
25
 
19
26
 
@@ -50,10 +57,10 @@ class _OptionalMetaData:
50
57
  self._name = "A Longer Descriptive Name e.g. from SMDA"
51
58
  self._shortname = "TheShortName"
52
59
  self._datatype = None
53
- self._md5sum = None
60
+ self._md5sum: str | None = None
54
61
  self._description = "Some description"
55
62
  self._crs = None
56
- self._datetime = None
63
+ self._datetime: datetime | None = None
57
64
  self._deltadatetime = None
58
65
  self._visuals = {"colortable": "rainbow", "lower": None, "upper": None}
59
66
  self._domain = "depth"
@@ -68,29 +75,29 @@ class _OptionalMetaData:
68
75
  self._source = "unknown"
69
76
 
70
77
  @property
71
- def name(self):
78
+ def name(self) -> str:
72
79
  return self._name
73
80
 
74
81
  @name.setter
75
- def name(self, newname):
82
+ def name(self, newname: str) -> None:
76
83
  # TODO: validation
77
84
  self._name = newname
78
85
 
79
86
  @property
80
- def datetime(self):
87
+ def datetime(self) -> datetime | None:
81
88
  return self._datetime
82
89
 
83
90
  @datetime.setter
84
- def datetime(self, newdate):
91
+ def datetime(self, newdate: datetime) -> None:
85
92
  # TODO: validation
86
93
  self._datetime = newdate
87
94
 
88
95
  @property
89
- def shortname(self):
96
+ def shortname(self) -> str:
90
97
  return self._shortname
91
98
 
92
99
  @shortname.setter
93
- def shortname(self, newname):
100
+ def shortname(self, newname: str) -> None:
94
101
  if not isinstance(newname, str):
95
102
  raise ValueError("The shortname must be a string.")
96
103
  if len(newname) >= 32:
@@ -99,11 +106,11 @@ class _OptionalMetaData:
99
106
  self._shortname = newname
100
107
 
101
108
  @property
102
- def description(self):
109
+ def description(self) -> str:
103
110
  return self._description
104
111
 
105
112
  @description.setter
106
- def description(self, newstr):
113
+ def description(self, newstr: str) -> None:
107
114
  if not isinstance(newstr, str):
108
115
  raise ValueError("The description must be a string.")
109
116
  if len(newstr) >= 64:
@@ -115,7 +122,7 @@ class _OptionalMetaData:
115
122
  self._description = newstr
116
123
 
117
124
  @property
118
- def md5sum(self):
125
+ def md5sum(self) -> str | None:
119
126
  """Set or get the md5 checksum of file content.
120
127
 
121
128
  See generate_hash() method in e.g. RegularSurface.
@@ -123,11 +130,11 @@ class _OptionalMetaData:
123
130
  return self._md5sum
124
131
 
125
132
  @md5sum.setter
126
- def md5sum(self, newhash):
133
+ def md5sum(self, newhash: str) -> None:
127
134
  # TODO: validation
128
135
  self._md5sum = newhash
129
136
 
130
- def get_meta(self):
137
+ def get_meta(self) -> dict[str, Any]:
131
138
  """Return metadata as an dict."""
132
139
  meta = {}
133
140
  for key in self.__slots__:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: xtgeo
3
- Version: 4.10.1
3
+ Version: 4.12.0
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,12 +1,8 @@
1
1
  cxtgeo.py,sha256=MjY_SfwNrahCXED08vVn7OsQPQPU7rsKwxSp2GY5WKI,33396
2
2
  cxtgeoPYTHON_wrap.c,sha256=jdx6wYGtLu7KKXcEHC9XqRTEMkYc4x4D07FPmYKSjPE,635145
3
- xtgeo-4.10.1.dist-info/RECORD,,
4
- xtgeo-4.10.1.dist-info/WHEEL,sha256=DQEqkN11DF-lVG0mTSUr80pmU3oSybmBAADfv3nLAsQ,141
5
- xtgeo-4.10.1.dist-info/METADATA,sha256=BgjBbVjXQOmIf5Rb2f9KsWqpP5CMTilfqnLgm5kLzqw,5789
6
- xtgeo-4.10.1.dist-info/licenses/LICENSE.md,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
7
3
  xtgeo/__init__.py,sha256=-p6vKOv7EfAt1S-7CmWHfN8iHjFHQ--5UwhIysS_gRQ,5588
8
- xtgeo/_internal.cpython-310-darwin.so,sha256=uGJmCPwG-llX1LoZ_YUOinzHbMSDbmyISM5B255N5X0,664080
9
- xtgeo/_cxtgeo.cpython-310-darwin.so,sha256=pXKovl38CXF78m_m7brWj-71Jm_mYVGYfdoN0h7xheY,414864
4
+ xtgeo/_internal.cpython-310-darwin.so,sha256=lbuA03zaiPz7wBe1oi_DeNwiJOvh5GSa80nICyv_Obw,731600
5
+ xtgeo/_cxtgeo.cpython-310-darwin.so,sha256=0POVU6BjxcFM28OJFsBGQ3XImpw0AIjm0j4msDRA3M8,414912
10
6
  xtgeo/well/_wells_utils.py,sha256=hjJEBdtILtK87sbCYWHJ7aEgqgKkak6ihfOcxSixNPo,4945
11
7
  xtgeo/well/_blockedwell_roxapi.py,sha256=G0IEChtCF7SPV_nXDIYsJ5L601HjA9QdWU7cNoyJyus,7489
12
8
  xtgeo/well/_well_io.py,sha256=CHvLfuIVNoX_4PQd7sCWg5xvyCd1L73J5dkmV2uaJqU,9821
@@ -36,47 +32,47 @@ xtgeo/include/fmt/std.h,sha256=ogzbgTUxCUFupDozCWAG0yMhWeiV6QtkEbaR0p9jR8A,22277
36
32
  xtgeo/include/fmt/base.h,sha256=E8jZU_stmNyVUondFmmZvSLbq_66f0hrNpPCxtnWJ9s,103990
37
33
  xtgeo/grid3d/_grid_import.py,sha256=T--Nk4CVKifCskc2i8y6cpFXV2LZdTmJC3iSxKXXiZE,2593
38
34
  xtgeo/grid3d/_roff_parameter.py,sha256=UNS2cngVP3GIAr5nVCoGQYJq062KtfvCAkFb0FEJY68,11073
39
- xtgeo/grid3d/grid.py,sha256=1zPBimDbI2X6zPSu7dDHPM3RbTvPxOFtYI0gJ-tvBTw,104960
35
+ xtgeo/grid3d/grid.py,sha256=hzKS9W51pgWl6WKHgykqpVyyo11pLGmHF4nTgpe0pm8,106706
40
36
  xtgeo/grid3d/_grid_boundary.py,sha256=oxWmQdy9cG1PzAtOH-IcCqAQYfmIwTD87tc-c4VgTA8,2308
41
37
  xtgeo/grid3d/_grid_import_ecl.py,sha256=gIcX4uMnwg0UnYMXyUdJsFSNKV-yhLFtc88AL1fmx6Y,3453
42
- xtgeo/grid3d/_gridprop_roxapi.py,sha256=4asCcVUXF42TKyD3oXTavBdPkAcAjZsra9QI12I3has,6857
43
- xtgeo/grid3d/_gridprop_op1.py,sha256=7xiGJe9rK4pKNux1rOi-UWcuPYKZAd6TqlBTmkryjjM,6813
38
+ xtgeo/grid3d/_gridprop_roxapi.py,sha256=llGUYpBeLhj3A7bf3EcMe2kz-OiW_O-Y6JCjsqVM-e0,8967
39
+ xtgeo/grid3d/_gridprop_op1.py,sha256=o0JemRzyECX0qzUpj9OXGB9nb1IOZ8-5Gs-1i_a302g,8956
44
40
  xtgeo/grid3d/_grid_import_roff.py,sha256=UViMnU44b75x4EfgnEmUYLFTK0R33lS9wAw0aBgzVzw,4039
45
41
  xtgeo/grid3d/_grid_hybrid.py,sha256=e-wj_RKknOSqPMU3wMBG_0maYJLEqJnv1_zp5eG55MY,1600
46
42
  xtgeo/grid3d/_grid3d_fence.py,sha256=XdIY-TlSgoTuRtRyRNqLvXLoR9F1QTEkFJO-rgKlqwE,9217
47
43
  xtgeo/grid3d/_grid3d.py,sha256=eM6842v2Q1Sb75zM3KynCITeV57OlXcusGEa_NWLPSU,740
48
44
  xtgeo/grid3d/_ecl_output_file.py,sha256=WPb7VGPyt89MpKtxL2jLoSKwn04jIfNsB11L-9wMhSY,2014
49
- xtgeo/grid3d/_grdecl_grid.py,sha256=R5zm3ninIts17pGWPbVI-1a747s9Igwj7pZXIylS4I4,12893
45
+ xtgeo/grid3d/_grdecl_grid.py,sha256=Er13V2E-4LtvpeLwFA-EhGKJxqWU-LUzR-OMZTKPoZo,13602
50
46
  xtgeo/grid3d/_grid_refine.py,sha256=qHdiHF2DJRhP6QGzPryr2nsghZtWAgscBi8kLgIDCTM,8541
51
47
  xtgeo/grid3d/_roff_grid.py,sha256=Or-QR92AB_oE-6lbMVhQjXC_E1HAcxZjFlbep3cFo6w,17272
52
48
  xtgeo/grid3d/__init__.py,sha256=k6T-xKWIBey_WMjWDnYZfvCsLQGokCL9RjqBZNvbUq0,332
53
49
  xtgeo/grid3d/types.py,sha256=s4iR1hmpZ_mF7xLXqujZaT2Sa6RK0uA48ZywBmkjoD0,275
54
- xtgeo/grid3d/_grid_export.py,sha256=bzjHHcwVggip3efzwSHI6Sl0Sw-EIqT_f3GJAcFkJsk,7170
50
+ xtgeo/grid3d/_grid_export.py,sha256=2Idg_5OGwS3Swu992RqYovDHBxfakjphN6ozKnDU1V0,7270
55
51
  xtgeo/grid3d/_ecl_inte_head.py,sha256=F22CT5VOpIYED2tMgmR5_FWtwq843S5vV3IbYvTehHM,4625
56
52
  xtgeo/grid3d/_gridprop_import_eclrun.py,sha256=k1SjOp4PmZ3nIcDM6N-2FDvDx3jMPf7rea3IGOrgo88,5096
57
53
  xtgeo/grid3d/_grid3d_utils.py,sha256=zIQZpWqAf33nVpC2aDqquPhd7Tqr-rRZvAaXPF-kxG0,7249
58
54
  xtgeo/grid3d/_ecl_grid.py,sha256=f12-cvxZblUZSAGIxKxJ438akK5gBFYebgSbVxZP6Jc,25905
59
55
  xtgeo/grid3d/_grid_roxapi.py,sha256=DJnG2CL56ygt2OEdVyH3oiMoyud-bra08tuLpFedCWQ,8907
60
56
  xtgeo/grid3d/_ecl_logi_head.py,sha256=CzBi7MSyPFeFGIKeBcex8qgm6VICUY6YjiKs0X9_UR4,2664
61
- xtgeo/grid3d/_grdecl_format.py,sha256=qUxq4c4e4-HGccFshLoOoGkgwwpaZeMbnWi4PhxPA78,8775
57
+ xtgeo/grid3d/_grdecl_format.py,sha256=Nrp-dUh8p6G0WgDiWRfY_otxPwS_wUaUpReXVoj-U_s,10138
62
58
  xtgeo/grid3d/_grid_wellzone.py,sha256=cBLmO4YL62vHEVvltxFHyQScZIY2RQQcrIqq9Cx6euE,5786
63
59
  xtgeo/grid3d/_find_gridprop_in_eclrun.py,sha256=zUv1Fk5ouSICYd9SR7NpHbN78rFBcN7FBlURmeyaedk,21434
64
60
  xtgeo/grid3d/_gridprop_lowlevel.py,sha256=8aUDxj1mPu8yH0F9FVaxxumew1OdBOkwEQI5tjIZEQI,5086
65
- xtgeo/grid3d/_grid_etc1.py,sha256=Wj9YmfOW4LXo5rUC01j0V_LLb-uWb9kaeOB6jc7tTUA,42969
61
+ xtgeo/grid3d/_grid_etc1.py,sha256=Yt5AjeXJ6xPbUlIbzer6N37_Cv53NVkxO2nnhY2uVWU,43571
66
62
  xtgeo/grid3d/_gridprops_import_eclrun.py,sha256=kWzubpyeorvfUSEjIF-UdoGnzQYYsUePW2jUtgoTuf0,11438
67
63
  xtgeo/grid3d/_gridprop_import_roff.py,sha256=tXp_mMqwfblSEb5KUbMOcL-TgGVn--vEqzPeXAK1IuI,1523
68
- xtgeo/grid3d/_gridprop_export.py,sha256=J_EL1bfs2ZB0B-foQLRhYjCQ1lB40yVHUD_utrd3TlU,5456
64
+ xtgeo/grid3d/_gridprop_export.py,sha256=i4aukBXCeoYYIVJytG8ObjA1KyDGQqsQr2XukSSbZYg,6533
69
65
  xtgeo/grid3d/_gridprop_import_grdecl.py,sha256=t2Heqw5f9azf_LJlIae-vMe9s0-HJr88TIKZCeTfqpc,4133
70
66
  xtgeo/grid3d/_egrid.py,sha256=zOYcmK_3-BrCwHLZiZis7nuzdm_n0jPq_P2_J0X4_wY,33835
71
67
  xtgeo/grid3d/_grid_import_xtgcpgeom.py,sha256=VtLKqxwNRZYlrPFRPHq-GUO0er-qLkmRlHVrhiTMosA,10202
72
68
  xtgeo/grid3d/grid_properties.py,sha256=Ur2gPRV69JEfLidUxRulr5lO2pKMs6CVsFtxp5ZLMIo,24294
73
69
  xtgeo/grid3d/_gridprops_import_roff.py,sha256=u6UobGgMaIBrCUOvGotAv_PJAoAJQYaFGH_kGo1RvRY,2467
74
- xtgeo/grid3d/grid_property.py,sha256=MDcyEpCXAW6eLLOO3E129rVNv3zURkwPAWhnT_33O7A,45352
70
+ xtgeo/grid3d/grid_property.py,sha256=aeBgWQ9cGq3ZPSuWm9crlFulWP25Leu21V4Ax51KvqQ,44667
75
71
  xtgeo/grid3d/_gridprop_import_xtgcpprop.py,sha256=-9576pMYO78IZl4VgaI_dk-ArCh0LRHt6cQL8MyEgos,4859
76
72
  xtgeo/grid3d/_gridprop_value_init.py,sha256=tN3LVziZsyIxbghkpGt6tCsHWFvGEm1e8ZpYpBgBdB8,4314
77
73
  xtgeo/cube/_cube_roxapi.py,sha256=mj9Nnug13t_Fsu0w4KKaJNEmrB_kYb0m133T6W-7wt0,4921
78
74
  xtgeo/cube/__init__.py,sha256=JJHhXXkXgFYRZTk5JDtqjxVzczDgLsHSLS-NPgCutIU,160
79
- xtgeo/cube/_cube_window_attributes.py,sha256=NSzfMioXxCCyl8fu3Kj3No4KK3pW2luxAjb1PdeQJ8Y,12095
75
+ xtgeo/cube/_cube_window_attributes.py,sha256=Ld4cGYQnN-jEu1m2CROWu6uCVbBIhr9TDv2G3pJSEFc,12607
80
76
  xtgeo/cube/_cube_utils.py,sha256=wTQZX2sNgmsYRRswjqr4h_NJp1CwbXVH1DWIejaIRbo,7440
81
77
  xtgeo/cube/_cube_import.py,sha256=7wgjUZHeXnP2KyW5zKQwX1X1k_t0RC6Rat7PL-m67PA,16782
82
78
  xtgeo/cube/_cube_export.py,sha256=G2e4ybxl7htjkGn1O-Eb9FrVf1o55esr_roNNubEknk,6445
@@ -113,7 +109,7 @@ xtgeo/surface/_regsurf_cube.py,sha256=xZXIE418guB3rG8iscI9xQ0deAtJ_auu1XDe3ml9GB
113
109
  xtgeo/surface/_regsurf_utils.py,sha256=P91jVmstYGe-bn6ut-9xfd8DiOw7QUCt2DLwbnlJwB4,2307
114
110
  xtgeo/surface/_regsurf_import.py,sha256=IXD1T4hLRk705RbixSfcOxyrBUilRRbUHYC_S_xZqZA,10396
115
111
  xtgeo/common/_xyz_enum.py,sha256=IiKRWhvIKKRhUH2QwpDttW4XqJ4f4StPrVt1vfVBTxM,1045
116
- xtgeo/common/version.py,sha256=vAiDsjske6vYWCo19AZtvfNbZxxZSZdkh63Bfib72AE,513
112
+ xtgeo/common/version.py,sha256=0dim9k4-Ulw2G1eNEsLWzB-cqRtPUtZBa0CDGryYUWI,714
117
113
  xtgeo/common/log.py,sha256=3C_WdYpCMEr5ebIGoGmalXNP0O2IGvLuJdzeuR8Cd-o,2742
118
114
  xtgeo/common/xtgeo_dialog.py,sha256=AcT8DrIBViSZJltwZuEfrcRbmicQEFfbwlf_gV2-6k8,17129
119
115
  xtgeo/common/constants.py,sha256=vp6k7lkWKKxyvojQZ1yYhhwXRXGZlMCPK8WY9nG2yns,749
@@ -123,15 +119,19 @@ xtgeo/common/_angles.py,sha256=VuNLV9pTooF_V3thFTg9SmTMBnKkv6ZxyvOXw22vLE0,822
123
119
  xtgeo/common/calc.py,sha256=xrJIVqFlrPIjhORbMThQylbjD4xdMM_vtEqBu5vc7C8,10134
124
120
  xtgeo/common/exceptions.py,sha256=4BRCtzk74eyc4LeeapAWFLkNh-TT0ev5pDxKJlPaI7s,1175
125
121
  xtgeo/common/sys.py,sha256=NGxnVoPoAGx_lekTF9QPBEf-VF8ORp4buoBeh6jkZko,4978
126
- xtgeo/lib/libfmt.a,sha256=Tu1x0eHKWdOpRAiRa0uUxNW-L1NkRRWV9hMlK70Yqs8,164136
127
- xtgeo/lib/pkgconfig/fmt.pc,sha256=vMarGs8UKKa6nGzxtADPDu9XasfDqIva1NZmDJs0Y9I,353
122
+ xtgeo/lib/libfmt.a,sha256=e2GPqamReUftoygvOcHpvAbYbSRdBUMsI8NLIpnatQ8,163432
123
+ xtgeo/lib/pkgconfig/fmt.pc,sha256=_DIiLXYj0jeHSjD4Aef7EgSyZ6qHSBrevmGMxKuEQok,353
128
124
  xtgeo/lib/cmake/fmt/fmt-targets-release.cmake,sha256=0hurnnAYtVc8r8yvaxkXAS5Op01RPnwKE6SFNOL1nYA,807
129
125
  xtgeo/lib/cmake/fmt/fmt-config.cmake,sha256=Cd-Xn_HSZ-Lk5ZBDX8q49OQKSvnS0_k4r0-tb6G8LW4,999
130
126
  xtgeo/lib/cmake/fmt/fmt-config-version.cmake,sha256=p1j16l20z3aEnEsIu-cbcrqFT32K2IJNZl10B8Ww2pk,1862
131
- xtgeo/lib/cmake/fmt/fmt-targets.cmake,sha256=311cnawW6a6LfThZkmD63ECINF5kzP6ZDIPUNuQocoQ,4464
127
+ xtgeo/lib/cmake/fmt/fmt-targets.cmake,sha256=ldmu9wnYq11UbsJ79TSK4ejJA-Zr20Ih9DyGS7EbPHM,4464
132
128
  xtgeo/roxutils/roxutils.py,sha256=BGvnWhYKvX2h7eU0ZXNUuDnHi8IM_2lLIzpq9lWZI6M,6904
133
129
  xtgeo/roxutils/__init__.py,sha256=UJKTgNSIGdtRxaUAwot4D5sGCTdfITw6BRaOnGkk41k,92
134
130
  xtgeo/roxutils/_roxutils_etc.py,sha256=K1fJKFBinfj32GGYnauU5t1sIgJ0l7N2gkXvaxMpNS8,3730
135
131
  xtgeo/roxutils/_roxar_loader.py,sha256=R2yBt7su6_u87UP00lLaiDxW0QuSnFLkEJQgcTWhjZI,1904
136
- xtgeo/metadata/metadata.py,sha256=kvbXu6dzVtdt-rEHsiHK_wJ0MRHNQCCzopBsw53T2l8,12137
132
+ xtgeo/metadata/metadata.py,sha256=mGkjNYcU4Y11EoLKTzSNW6JYpJVvIYNCbQ8obKMv21g,12436
137
133
  xtgeo/metadata/__init__.py,sha256=WXmKZjBGV3kr-lmrPxr3Ph7CpI5KIn3WKlE23crBteA,320
134
+ xtgeo-4.12.0.dist-info/RECORD,,
135
+ xtgeo-4.12.0.dist-info/WHEEL,sha256=ARvpZEbgFu-cAxZINNemqHWSYlsYgHkQqksAmhPJqFw,141
136
+ xtgeo-4.12.0.dist-info/METADATA,sha256=au9aO7YlUYU5YAt5jB5uAwdsSjIqhAuyWSmIMUt7TYI,5741
137
+ xtgeo-4.12.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.4
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