xtgeo 4.8.0__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.

Potentially problematic release.


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

Files changed (117) hide show
  1. cxtgeo.py +582 -0
  2. cxtgeoPYTHON_wrap.c +20938 -0
  3. xtgeo/__init__.py +246 -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 +21 -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 +340 -0
  23. xtgeo/cube/cube1.py +1023 -0
  24. xtgeo/grid3d/__init__.py +15 -0
  25. xtgeo/grid3d/_ecl_grid.py +774 -0
  26. xtgeo/grid3d/_ecl_inte_head.py +148 -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 +266 -0
  32. xtgeo/grid3d/_grdecl_grid.py +388 -0
  33. xtgeo/grid3d/_grid3d.py +29 -0
  34. xtgeo/grid3d/_grid3d_fence.py +181 -0
  35. xtgeo/grid3d/_grid3d_utils.py +228 -0
  36. xtgeo/grid3d/_grid_boundary.py +76 -0
  37. xtgeo/grid3d/_grid_etc1.py +1566 -0
  38. xtgeo/grid3d/_grid_export.py +221 -0
  39. xtgeo/grid3d/_grid_hybrid.py +66 -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 +125 -0
  45. xtgeo/grid3d/_grid_roxapi.py +292 -0
  46. xtgeo/grid3d/_grid_wellzone.py +165 -0
  47. xtgeo/grid3d/_gridprop_export.py +178 -0
  48. xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
  49. xtgeo/grid3d/_gridprop_import_grdecl.py +130 -0
  50. xtgeo/grid3d/_gridprop_import_roff.py +52 -0
  51. xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
  52. xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
  53. xtgeo/grid3d/_gridprop_op1.py +174 -0
  54. xtgeo/grid3d/_gridprop_roxapi.py +239 -0
  55. xtgeo/grid3d/_gridprop_value_init.py +140 -0
  56. xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
  57. xtgeo/grid3d/_gridprops_import_roff.py +83 -0
  58. xtgeo/grid3d/_roff_grid.py +469 -0
  59. xtgeo/grid3d/_roff_parameter.py +303 -0
  60. xtgeo/grid3d/grid.py +2537 -0
  61. xtgeo/grid3d/grid_properties.py +699 -0
  62. xtgeo/grid3d/grid_property.py +1341 -0
  63. xtgeo/grid3d/types.py +15 -0
  64. xtgeo/io/__init__.py +1 -0
  65. xtgeo/io/_file.py +592 -0
  66. xtgeo/metadata/__init__.py +17 -0
  67. xtgeo/metadata/metadata.py +431 -0
  68. xtgeo/roxutils/__init__.py +7 -0
  69. xtgeo/roxutils/_roxar_loader.py +54 -0
  70. xtgeo/roxutils/_roxutils_etc.py +122 -0
  71. xtgeo/roxutils/roxutils.py +207 -0
  72. xtgeo/surface/__init__.py +18 -0
  73. xtgeo/surface/_regsurf_boundary.py +26 -0
  74. xtgeo/surface/_regsurf_cube.py +210 -0
  75. xtgeo/surface/_regsurf_cube_window.py +391 -0
  76. xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
  77. xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
  78. xtgeo/surface/_regsurf_export.py +388 -0
  79. xtgeo/surface/_regsurf_grid3d.py +271 -0
  80. xtgeo/surface/_regsurf_gridding.py +347 -0
  81. xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
  82. xtgeo/surface/_regsurf_import.py +347 -0
  83. xtgeo/surface/_regsurf_lowlevel.py +122 -0
  84. xtgeo/surface/_regsurf_oper.py +631 -0
  85. xtgeo/surface/_regsurf_roxapi.py +241 -0
  86. xtgeo/surface/_regsurf_utils.py +81 -0
  87. xtgeo/surface/_surfs_import.py +43 -0
  88. xtgeo/surface/_zmap_parser.py +138 -0
  89. xtgeo/surface/regular_surface.py +2967 -0
  90. xtgeo/surface/surfaces.py +276 -0
  91. xtgeo/well/__init__.py +24 -0
  92. xtgeo/well/_blockedwell_roxapi.py +221 -0
  93. xtgeo/well/_blockedwells_roxapi.py +68 -0
  94. xtgeo/well/_well_aux.py +30 -0
  95. xtgeo/well/_well_io.py +327 -0
  96. xtgeo/well/_well_oper.py +574 -0
  97. xtgeo/well/_well_roxapi.py +304 -0
  98. xtgeo/well/_wellmarkers.py +486 -0
  99. xtgeo/well/_wells_utils.py +158 -0
  100. xtgeo/well/blocked_well.py +216 -0
  101. xtgeo/well/blocked_wells.py +122 -0
  102. xtgeo/well/well1.py +1514 -0
  103. xtgeo/well/wells.py +211 -0
  104. xtgeo/xyz/__init__.py +6 -0
  105. xtgeo/xyz/_polygons_oper.py +272 -0
  106. xtgeo/xyz/_xyz.py +741 -0
  107. xtgeo/xyz/_xyz_data.py +646 -0
  108. xtgeo/xyz/_xyz_io.py +490 -0
  109. xtgeo/xyz/_xyz_lowlevel.py +42 -0
  110. xtgeo/xyz/_xyz_oper.py +613 -0
  111. xtgeo/xyz/_xyz_roxapi.py +766 -0
  112. xtgeo/xyz/points.py +681 -0
  113. xtgeo/xyz/polygons.py +811 -0
  114. xtgeo-4.8.0.dist-info/METADATA +145 -0
  115. xtgeo-4.8.0.dist-info/RECORD +117 -0
  116. xtgeo-4.8.0.dist-info/WHEEL +5 -0
  117. xtgeo-4.8.0.dist-info/licenses/LICENSE.md +165 -0
@@ -0,0 +1,174 @@
1
+ """Various grid property operations"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, List, Literal, Optional, Tuple, Union
6
+
7
+ import numpy as np
8
+
9
+ import xtgeo
10
+ from xtgeo import _cxtgeo
11
+ from xtgeo.common import XTGeoDialog, null_logger
12
+ from xtgeo.grid3d import _gridprop_lowlevel as gl
13
+
14
+ xtg = XTGeoDialog()
15
+ logger = null_logger(__name__)
16
+
17
+ if TYPE_CHECKING:
18
+ from xtgeo.grid3d import Grid, GridProperty
19
+ from xtgeo.xyz import Polygons
20
+
21
+ _CoordOrValue = Union[float, int]
22
+ _XYCoordinate = Tuple[_CoordOrValue, _CoordOrValue]
23
+ _XYCoordList = List[List[List[_XYCoordinate]]]
24
+ _ValueList = List[List[_CoordOrValue]]
25
+ XYValueLists = Tuple[_XYCoordList, _ValueList]
26
+
27
+
28
+ def get_xy_value_lists(
29
+ self: GridProperty,
30
+ grid: Optional[Grid | GridProperty] = None,
31
+ mask: Optional[bool] = None,
32
+ ) -> XYValueLists:
33
+ """Get values for webportal format
34
+
35
+ Two cells:
36
+ [[[(x1,y1), (x2,y2), (x3,y3), (x4,y4)],
37
+ [(x5,y5), (x6,y6), (x7,y7), (x8,y8)]]]
38
+
39
+ If mask is True then inactive cells are ommited from the lists,
40
+ else the active cells corners will be present while the property
41
+ will have a -999 value.
42
+
43
+ """
44
+ if grid is None:
45
+ raise RuntimeError("Missing grid object")
46
+
47
+ if not isinstance(grid, xtgeo.grid3d.Grid):
48
+ raise RuntimeError("The input grid is not a XTGeo Grid instance")
49
+
50
+ if not isinstance(self, xtgeo.grid3d.GridProperty):
51
+ raise RuntimeError("The property is not a XTGeo GridProperty instance")
52
+
53
+ clist = grid.get_xyz_corners()
54
+ actnum = grid.get_actnum()
55
+
56
+ # set value 0 if actnum is 0 to facilitate later operations
57
+ if mask:
58
+ for cli in clist:
59
+ cli.values[actnum.values == 0] = 0
60
+
61
+ # now some numpy operations (coffee?, any?)
62
+ xy0 = np.column_stack((clist[0].values1d, clist[1].values1d))
63
+ xy1 = np.column_stack((clist[3].values1d, clist[4].values1d))
64
+ xy2 = np.column_stack((clist[6].values1d, clist[7].values1d))
65
+ xy3 = np.column_stack((clist[9].values1d, clist[10].values1d))
66
+
67
+ xyc = np.column_stack((xy0, xy1, xy2, xy3))
68
+ xyc = xyc.reshape(grid.nlay, grid.ncol * grid.nrow, 4, 2)
69
+
70
+ coordlist = xyc.tolist()
71
+
72
+ # remove cells that are undefined ("marked" as coordinate [0, 0] if mask)
73
+ coordlist = [
74
+ [[tuple(xy) for xy in cell if xy[0] > 0] for cell in lay] for lay in coordlist
75
+ ]
76
+
77
+ coordlist = [[cell for cell in lay if len(cell) > 1] for lay in coordlist]
78
+
79
+ pval = self.values1d.reshape((grid.nlay, grid.ncol * grid.nrow))
80
+ valuelist = pval.tolist(fill_value=-999.0)
81
+ if mask:
82
+ valuelist = [[val for val in lay if val != -999.0] for lay in valuelist]
83
+
84
+ return coordlist, valuelist
85
+
86
+
87
+ def operation_polygons(
88
+ self: GridProperty,
89
+ poly: Polygons,
90
+ value: float | int,
91
+ opname: Literal["add", "sub", "mul", "div", "set"] = "add",
92
+ inside: bool = True,
93
+ ) -> None:
94
+ """A generic function for doing operations restricted to inside
95
+ or outside polygon(s).
96
+
97
+ """
98
+ grid = self.geometry
99
+ grid._xtgformat1()
100
+
101
+ if not isinstance(poly, xtgeo.xyz.Polygons):
102
+ raise ValueError("The poly input is not a Polygons instance")
103
+
104
+ # make a copy of the array which is used a "filter" or "proxy"
105
+ # value will be 1 inside polygons, 0 outside. Undef cells are kept as is
106
+ dtype = self.dtype
107
+
108
+ proxy = self.copy()
109
+ proxy.discrete_to_continuous()
110
+
111
+ proxy.values *= 0.0
112
+ cvals = gl.update_carray(proxy)
113
+
114
+ idgroups = poly.get_dataframe(copy=False).groupby(poly.pname)
115
+
116
+ for id_, grp in idgroups:
117
+ xcor = grp[poly.xname].values
118
+ ycor = grp[poly.yname].values
119
+
120
+ ier = _cxtgeo.grd3d_setval_poly(
121
+ xcor,
122
+ ycor,
123
+ self.ncol,
124
+ self.nrow,
125
+ self.nlay,
126
+ grid._coordsv,
127
+ grid._zcornsv,
128
+ grid._actnumsv,
129
+ cvals,
130
+ 1,
131
+ )
132
+ if ier == -9:
133
+ logger.warning(f"Polygon no {id_ + 1} is not closed")
134
+
135
+ gl.update_values_from_carray(proxy, cvals, np.float64, delete=True)
136
+
137
+ proxyv = proxy.values.astype(np.int8)
138
+
139
+ proxytarget = 1
140
+ if not inside:
141
+ proxytarget = 0
142
+
143
+ if opname == "add":
144
+ tmp = self.values.copy() + value
145
+ elif opname == "sub":
146
+ tmp = self.values.copy() - value
147
+ elif opname == "mul":
148
+ tmp = self.values.copy() * value
149
+ elif opname == "div":
150
+ # Dividing a map of zero is always a hazzle; try to obtain 0.0
151
+ # as result in these cases
152
+ if np.isclose(value, 0.0):
153
+ xtg.warn(
154
+ "Dividing a surface with value or surface with zero "
155
+ "elements; may get unexpected results, try to "
156
+ "achieve zero values as result!"
157
+ )
158
+ with np.errstate(divide="ignore", invalid="ignore"):
159
+ this = np.ma.filled(self.values, fill_value=1.0)
160
+ that = np.ma.filled(value, fill_value=1.0)
161
+ mask = np.ma.getmaskarray(self.values)
162
+ tmp = np.true_divide(this, that)
163
+ tmp = np.where(np.isinf(tmp), 0, tmp)
164
+ tmp = np.nan_to_num(tmp)
165
+ tmp = np.ma.array(tmp, mask=mask)
166
+
167
+ elif opname == "set":
168
+ tmp = self.values.copy() * 0 + value
169
+
170
+ # convert tmp back to correct dtype
171
+ tmp = tmp.astype(dtype)
172
+
173
+ self.values[proxyv == proxytarget] = tmp[proxyv == proxytarget]
174
+ del tmp
@@ -0,0 +1,239 @@
1
+ # coding: utf-8
2
+ """Roxar API functions for XTGeo Grid Property."""
3
+
4
+ from __future__ import annotations
5
+
6
+ from typing import TYPE_CHECKING, Any, Literal
7
+
8
+ import numpy as np
9
+ from numpy import ma
10
+
11
+ from xtgeo.common import null_logger
12
+ from xtgeo.common.constants import UNDEF, UNDEF_INT, UNDEF_INT_LIMIT, UNDEF_LIMIT
13
+ from xtgeo.roxutils import RoxUtils
14
+ from xtgeo.roxutils._roxar_loader import roxar
15
+
16
+ if TYPE_CHECKING:
17
+ from xtgeo.grid3d.grid_property import GridProperty
18
+
19
+ if roxar is not None:
20
+ from roxar import Project as RoxarProjectType
21
+ from roxar.grids import Grid3D as RoxarGrid3DType
22
+
23
+ logger = null_logger(__name__)
24
+
25
+ VALID_ROXAR_DTYPES = [np.uint8, np.uint16, np.float32]
26
+
27
+
28
+ def import_prop_roxapi(
29
+ project: RoxarProjectType,
30
+ gname: str,
31
+ pname: str,
32
+ realisation: int,
33
+ faciescodes: bool,
34
+ ) -> dict[str, Any]:
35
+ """Import a Property via ROXAR API spec."""
36
+ logger.info("Opening RMS project ...")
37
+
38
+ rox = RoxUtils(project, readonly=True)
39
+
40
+ result = _get_gridprop_data(rox, gname, pname, realisation, faciescodes)
41
+
42
+ rox.safe_close()
43
+ return result
44
+
45
+
46
+ def _get_gridprop_data(
47
+ rox: RoxUtils, gname: str, pname: str, realisation: int, faciescodes: bool
48
+ ) -> dict[str, Any]:
49
+ # inside a RMS project
50
+
51
+ if gname not in rox.project.grid_models:
52
+ raise ValueError(f"No gridmodel with name {gname}")
53
+ if pname not in rox.project.grid_models[gname].properties:
54
+ raise ValueError(f"No property in {gname} with name {pname}")
55
+
56
+ try:
57
+ return _convert_to_xtgeo_prop(rox, gname, pname, realisation, faciescodes)
58
+ except KeyError as keyerror:
59
+ raise RuntimeError(keyerror) from keyerror
60
+
61
+
62
+ def _convert_to_xtgeo_prop(
63
+ rox: RoxUtils, gname: str, pname: str, realisation: int, faciescodes: bool
64
+ ) -> dict[str, Any]:
65
+ result: dict[str, Any] = {}
66
+ roxgrid = rox.project.grid_models[gname]
67
+ roxprop = roxgrid.properties[pname]
68
+
69
+ discrete = str(roxprop.type) in ("discrete", "body_facies")
70
+ result["discrete"] = discrete
71
+
72
+ result["roxorigin"] = True
73
+ indexer = roxgrid.get_grid(realisation=realisation).grid_indexer
74
+ result["ncol"], result["nrow"], result["nlay"] = indexer.dimensions
75
+
76
+ logger.info(indexer.ijk_handedness)
77
+
78
+ pvalues = roxprop.get_values(realisation=realisation)
79
+
80
+ if str(roxprop.type) == "body_facies" and faciescodes:
81
+ fmap = roxprop.get_facies_map(realisation=realisation)
82
+ pvalues = fmap[pvalues] # numpy magics
83
+
84
+ result["roxar_dtype"] = pvalues.dtype
85
+
86
+ mybuffer: np.ndarray = np.ndarray(
87
+ indexer.dimensions, dtype=np.int32 if discrete else np.float64
88
+ )
89
+ mybuffer.fill(UNDEF_INT if discrete else UNDEF)
90
+
91
+ cellno = indexer.get_cell_numbers_in_range((0, 0, 0), indexer.dimensions)
92
+
93
+ ijk = indexer.get_indices(cellno)
94
+
95
+ iind = ijk[:, 0]
96
+ jind = ijk[:, 1]
97
+ kind = ijk[:, 2]
98
+
99
+ mybuffer[iind, jind, kind] = pvalues[cellno]
100
+
101
+ mybuffer = ma.masked_greater(mybuffer, UNDEF_INT_LIMIT if discrete else UNDEF_LIMIT)
102
+
103
+ result["values"] = mybuffer
104
+ result["name"] = pname
105
+
106
+ if discrete:
107
+ result["codes"] = _fix_codes(
108
+ result["values"].reshape(-1).compressed(), roxprop.code_names
109
+ )
110
+ logger.info("Fixed codes: %s", result["codes"])
111
+ return result
112
+
113
+
114
+ def export_prop_roxapi(
115
+ self: GridProperty,
116
+ project: RoxarProjectType,
117
+ gname: str,
118
+ pname: str,
119
+ realisation: int = 0,
120
+ casting: Literal["no", "equiv", "safe", "same_kind", "unsafe"] | None = "unsafe",
121
+ ) -> None:
122
+ """Export (i.e. store or save) to a Property icon in RMS via ROXAR API spec."""
123
+ rox = RoxUtils(project, readonly=False)
124
+
125
+ try:
126
+ roxgrid = rox.project.grid_models[gname]
127
+ _store_in_roxar(self, pname, roxgrid, realisation, casting)
128
+
129
+ except KeyError as keyerror:
130
+ raise RuntimeError(keyerror)
131
+
132
+ if rox._roxexternal:
133
+ rox.project.save()
134
+
135
+ rox.safe_close()
136
+
137
+
138
+ def _store_in_roxar(
139
+ self: GridProperty,
140
+ pname: str,
141
+ roxgrid: RoxarGrid3DType,
142
+ realisation: int,
143
+ casting: Literal["no", "equiv", "safe", "same_kind", "unsafe"] | None,
144
+ ) -> None:
145
+ """Store property in RMS."""
146
+ indexer = roxgrid.get_grid(realisation=realisation).grid_indexer
147
+
148
+ logger.info("Store in RMS...")
149
+
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)
155
+
156
+ iind = ijk[:, 0]
157
+ jind = ijk[:, 1]
158
+ kind = ijk[:, 2]
159
+
160
+ dtype = self._roxar_dtype
161
+ logger.info("DTYPE is %s for %s", dtype, pname)
162
+
163
+ # casting will secure correct types
164
+ if dtype not in VALID_ROXAR_DTYPES:
165
+ raise TypeError(
166
+ f"Roxar dtype is not valid: {dtype} must be in {VALID_ROXAR_DTYPES}"
167
+ )
168
+
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
+ properties = roxgrid.properties
181
+
182
+ if pname not in properties:
183
+ rprop = properties.create(
184
+ pname, property_type=roxar_property_type, data_type=dtype
185
+ )
186
+ else:
187
+ rprop = properties[pname]
188
+ dtype = rprop.data_type
189
+
190
+ rprop.set_values(pvalues.astype(dtype, casting=casting), realisation=realisation)
191
+
192
+ if self.isdiscrete:
193
+ rprop.code_names = _rox_compatible_codes(self.codes)
194
+
195
+
196
+ def _fix_codes(
197
+ active_values: np.ndarray, codes: dict[str | int, str]
198
+ ) -> dict[int, str]:
199
+ """Roxar may provide a code list with empty strings values, fix this issue here.
200
+
201
+ Roxar may also interpolate code values which are actually not present in the
202
+ property. Here, the presence of actual codes is also checked.
203
+ """
204
+ newcodes = {}
205
+ codes_data = {val: str(val) for val in np.unique(active_values)}
206
+
207
+ for code, name in codes.items():
208
+ if not isinstance(code, int):
209
+ code = int(code)
210
+
211
+ if not name:
212
+ name = str(code)
213
+
214
+ if code not in codes_data:
215
+ continue
216
+
217
+ newcodes[code] = name
218
+
219
+ return newcodes
220
+
221
+
222
+ def _rox_compatible_codes(codes: dict) -> dict:
223
+ """Ensure that keys in codes are int's prior to storage in RMS."""
224
+
225
+ newcodes = {}
226
+ for code, name in codes.items():
227
+ if code is None:
228
+ continue # skip codes of type None; assumed to be spurious
229
+ if not isinstance(code, int):
230
+ try:
231
+ code = int(code)
232
+ except ValueError:
233
+ raise ValueError(
234
+ "The keys in codes must be an integer prior to RMS "
235
+ f"storage. Actual key found here is '{code}' of type {type(code)}"
236
+ )
237
+
238
+ newcodes[code] = name
239
+ return newcodes
@@ -0,0 +1,140 @@
1
+ """GridProperty (not GridProperies) some etc functions"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import numbers
6
+ from typing import TYPE_CHECKING
7
+
8
+ import numpy as np
9
+
10
+ import xtgeo
11
+ from xtgeo.common import null_logger
12
+
13
+ logger = null_logger(__name__)
14
+
15
+ if TYPE_CHECKING:
16
+ from xtgeo.grid3d import Grid, GridProperty
17
+
18
+
19
+ def gridproperty_non_dummy_values(
20
+ gridlike: Grid | GridProperty | None,
21
+ dimensions: tuple[int, int, int],
22
+ values: np.ndarray | float | int | None,
23
+ isdiscrete: bool,
24
+ ) -> np.ma.MaskedArray:
25
+ """
26
+ Gives the initial values array of an gridprop.
27
+
28
+ Args:
29
+ gridlike: Either Grid or GridProperty, giving the mask to replicate.
30
+ dimensions: The (ncol, nrow, nlay) dimensions of the grid property.
31
+ values: The values parameter given to init.
32
+ isdiscrete: The discrete parameter given to init.
33
+
34
+ Returns:
35
+ The array to be set to GridProperty._values.
36
+
37
+ """
38
+ if values is None:
39
+ _values = initial_gridprop_values_zero(dimensions, isdiscrete)
40
+ elif isinstance(values, numbers.Number):
41
+ _values = initial_gridprop_values_from_scalar(dimensions, values, isdiscrete)
42
+ elif isinstance(values, np.ndarray):
43
+ _values = initial_gridprop_values_from_array(dimensions, values, isdiscrete)
44
+ else:
45
+ raise ValueError(
46
+ f"Cannot create GridProperty with values type '{type(values).__name__}.' "
47
+ "Expected an nd.array, float, int, or None"
48
+ )
49
+
50
+ if gridlike:
51
+ if isinstance(gridlike, xtgeo.grid3d.Grid):
52
+ act = gridlike.get_actnum(asmasked=True)
53
+ _values = np.ma.array(_values, mask=np.ma.getmaskarray(act.values))
54
+ else:
55
+ assert isinstance(gridlike, xtgeo.grid3d.GridProperty)
56
+ _values = np.ma.array(_values, mask=np.ma.getmaskarray(gridlike.values))
57
+
58
+ return _values
59
+
60
+
61
+ def gridproperty_dummy_values(isdiscrete: bool) -> np.ma.MaskedArray:
62
+ """
63
+ Given no parameters to init, these dummy values should be set for backwards
64
+ compatability.
65
+
66
+ Args:
67
+ isdiscrete: If the grid property values are discrete.
68
+
69
+ Returns:
70
+ The array to be set to GridProperty._values.
71
+
72
+ """
73
+ values: np.ma.MaskedArray = np.ma.MaskedArray(
74
+ np.full((4, 3, 5), 99.0), dtype=np.int32 if isdiscrete else np.float64
75
+ )
76
+ values[0:4, 0, 0:2] = np.ma.masked
77
+ return values
78
+
79
+
80
+ def initial_gridprop_values_zero(
81
+ dimensions: tuple[int, int, int], isdiscrete: bool
82
+ ) -> np.ma.MaskedArray:
83
+ """
84
+ Initial values for an GridProperty with zeros.
85
+
86
+ Given that the user supplies at least some parameters, but not a values array,
87
+ values should be initialized to zero.
88
+
89
+ Args:
90
+ dimensions: The (ncol, nrow, nlay) dimensions of the grid property.
91
+
92
+ Returns:
93
+ Zero initialized values array.
94
+
95
+ """
96
+ return np.ma.zeros(dimensions, dtype=np.int32 if isdiscrete else np.float64)
97
+
98
+
99
+ def initial_gridprop_values_from_scalar(
100
+ dimensions: tuple[int, int, int], value: float | int, isdiscrete: bool
101
+ ) -> np.ma.MaskedArray:
102
+ """
103
+ Initial grid property values from scalar.
104
+
105
+ Given scalar values, the gridproperties value array should be
106
+ filled with that value, with possible conversion depending
107
+ on the isdiscrete parameter.
108
+
109
+ Args:
110
+ dimensions: The (ncol, nrow, nlay) dimensions of the grid property.
111
+ value: The scalar value to initialize with.
112
+ isdiscrete: If the values are discrete.
113
+
114
+ Returns:
115
+ Filled array with given scalar value.
116
+
117
+ """
118
+ if not isinstance(value, numbers.Number):
119
+ raise ValueError("Scalar input values of invalid type")
120
+ return np.ma.zeros(dimensions, dtype=np.int32 if isdiscrete else np.float64) + value
121
+
122
+
123
+ def initial_gridprop_values_from_array(
124
+ dimensions: tuple[int, int, int], values: np.ndarray, isdiscrete: bool
125
+ ) -> np.ma.MaskedArray:
126
+ """
127
+ Initial GridProperty values from numpy array.
128
+
129
+ Args:
130
+ dimensions: The (ncol, nrow, nlay) dimensions of the grid property.
131
+ value: The numpy array to initialize with.
132
+ isdiscrete: If the values are discrete.
133
+
134
+ Returns:
135
+ GridProperty with values initialized from a numpy array.
136
+
137
+ """
138
+ return np.ma.MaskedArray(
139
+ values.reshape(dimensions), dtype=np.int32 if isdiscrete else np.float64
140
+ )