xtgeo 4.14.1__cp313-cp313-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. cxtgeo.py +558 -0
  2. cxtgeoPYTHON_wrap.c +19537 -0
  3. xtgeo/__init__.py +248 -0
  4. xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
  5. xtgeo/_internal.cp313-win_amd64.pyd +0 -0
  6. xtgeo/common/__init__.py +19 -0
  7. xtgeo/common/_angles.py +29 -0
  8. xtgeo/common/_xyz_enum.py +50 -0
  9. xtgeo/common/calc.py +396 -0
  10. xtgeo/common/constants.py +30 -0
  11. xtgeo/common/exceptions.py +42 -0
  12. xtgeo/common/log.py +93 -0
  13. xtgeo/common/sys.py +166 -0
  14. xtgeo/common/types.py +18 -0
  15. xtgeo/common/version.py +34 -0
  16. xtgeo/common/xtgeo_dialog.py +604 -0
  17. xtgeo/cube/__init__.py +9 -0
  18. xtgeo/cube/_cube_export.py +214 -0
  19. xtgeo/cube/_cube_import.py +532 -0
  20. xtgeo/cube/_cube_roxapi.py +180 -0
  21. xtgeo/cube/_cube_utils.py +287 -0
  22. xtgeo/cube/_cube_window_attributes.py +273 -0
  23. xtgeo/cube/cube1.py +1023 -0
  24. xtgeo/grid3d/__init__.py +15 -0
  25. xtgeo/grid3d/_ecl_grid.py +778 -0
  26. xtgeo/grid3d/_ecl_inte_head.py +152 -0
  27. xtgeo/grid3d/_ecl_logi_head.py +71 -0
  28. xtgeo/grid3d/_ecl_output_file.py +81 -0
  29. xtgeo/grid3d/_egrid.py +1004 -0
  30. xtgeo/grid3d/_find_gridprop_in_eclrun.py +625 -0
  31. xtgeo/grid3d/_grdecl_format.py +309 -0
  32. xtgeo/grid3d/_grdecl_grid.py +400 -0
  33. xtgeo/grid3d/_grid3d.py +29 -0
  34. xtgeo/grid3d/_grid3d_fence.py +284 -0
  35. xtgeo/grid3d/_grid3d_utils.py +228 -0
  36. xtgeo/grid3d/_grid_boundary.py +76 -0
  37. xtgeo/grid3d/_grid_etc1.py +1683 -0
  38. xtgeo/grid3d/_grid_export.py +222 -0
  39. xtgeo/grid3d/_grid_hybrid.py +50 -0
  40. xtgeo/grid3d/_grid_import.py +79 -0
  41. xtgeo/grid3d/_grid_import_ecl.py +101 -0
  42. xtgeo/grid3d/_grid_import_roff.py +135 -0
  43. xtgeo/grid3d/_grid_import_xtgcpgeom.py +375 -0
  44. xtgeo/grid3d/_grid_refine.py +258 -0
  45. xtgeo/grid3d/_grid_roxapi.py +292 -0
  46. xtgeo/grid3d/_grid_translate_coords.py +154 -0
  47. xtgeo/grid3d/_grid_wellzone.py +165 -0
  48. xtgeo/grid3d/_gridprop_export.py +202 -0
  49. xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
  50. xtgeo/grid3d/_gridprop_import_grdecl.py +132 -0
  51. xtgeo/grid3d/_gridprop_import_roff.py +52 -0
  52. xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
  53. xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
  54. xtgeo/grid3d/_gridprop_op1.py +272 -0
  55. xtgeo/grid3d/_gridprop_roxapi.py +301 -0
  56. xtgeo/grid3d/_gridprop_value_init.py +140 -0
  57. xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
  58. xtgeo/grid3d/_gridprops_import_roff.py +83 -0
  59. xtgeo/grid3d/_roff_grid.py +470 -0
  60. xtgeo/grid3d/_roff_parameter.py +303 -0
  61. xtgeo/grid3d/grid.py +3010 -0
  62. xtgeo/grid3d/grid_properties.py +699 -0
  63. xtgeo/grid3d/grid_property.py +1313 -0
  64. xtgeo/grid3d/types.py +15 -0
  65. xtgeo/interfaces/rms/__init__.py +18 -0
  66. xtgeo/interfaces/rms/_regular_surface.py +460 -0
  67. xtgeo/interfaces/rms/_rms_base.py +100 -0
  68. xtgeo/interfaces/rms/_rmsapi_package.py +69 -0
  69. xtgeo/interfaces/rms/rmsapi_utils.py +438 -0
  70. xtgeo/io/__init__.py +1 -0
  71. xtgeo/io/_file.py +603 -0
  72. xtgeo/metadata/__init__.py +17 -0
  73. xtgeo/metadata/metadata.py +435 -0
  74. xtgeo/roxutils/__init__.py +7 -0
  75. xtgeo/roxutils/_roxar_loader.py +54 -0
  76. xtgeo/roxutils/_roxutils_etc.py +122 -0
  77. xtgeo/roxutils/roxutils.py +207 -0
  78. xtgeo/surface/__init__.py +20 -0
  79. xtgeo/surface/_regsurf_boundary.py +26 -0
  80. xtgeo/surface/_regsurf_cube.py +210 -0
  81. xtgeo/surface/_regsurf_cube_window.py +391 -0
  82. xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
  83. xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
  84. xtgeo/surface/_regsurf_export.py +388 -0
  85. xtgeo/surface/_regsurf_grid3d.py +275 -0
  86. xtgeo/surface/_regsurf_gridding.py +347 -0
  87. xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
  88. xtgeo/surface/_regsurf_import.py +347 -0
  89. xtgeo/surface/_regsurf_lowlevel.py +122 -0
  90. xtgeo/surface/_regsurf_oper.py +538 -0
  91. xtgeo/surface/_regsurf_utils.py +81 -0
  92. xtgeo/surface/_surfs_import.py +43 -0
  93. xtgeo/surface/_zmap_parser.py +138 -0
  94. xtgeo/surface/regular_surface.py +3043 -0
  95. xtgeo/surface/surfaces.py +276 -0
  96. xtgeo/well/__init__.py +24 -0
  97. xtgeo/well/_blockedwell_roxapi.py +241 -0
  98. xtgeo/well/_blockedwells_roxapi.py +68 -0
  99. xtgeo/well/_well_aux.py +30 -0
  100. xtgeo/well/_well_io.py +327 -0
  101. xtgeo/well/_well_oper.py +483 -0
  102. xtgeo/well/_well_roxapi.py +304 -0
  103. xtgeo/well/_wellmarkers.py +486 -0
  104. xtgeo/well/_wells_utils.py +158 -0
  105. xtgeo/well/blocked_well.py +220 -0
  106. xtgeo/well/blocked_wells.py +134 -0
  107. xtgeo/well/well1.py +1516 -0
  108. xtgeo/well/wells.py +211 -0
  109. xtgeo/xyz/__init__.py +6 -0
  110. xtgeo/xyz/_polygons_oper.py +272 -0
  111. xtgeo/xyz/_xyz.py +758 -0
  112. xtgeo/xyz/_xyz_data.py +646 -0
  113. xtgeo/xyz/_xyz_io.py +737 -0
  114. xtgeo/xyz/_xyz_lowlevel.py +42 -0
  115. xtgeo/xyz/_xyz_oper.py +613 -0
  116. xtgeo/xyz/_xyz_roxapi.py +766 -0
  117. xtgeo/xyz/points.py +698 -0
  118. xtgeo/xyz/polygons.py +827 -0
  119. xtgeo-4.14.1.dist-info/METADATA +146 -0
  120. xtgeo-4.14.1.dist-info/RECORD +122 -0
  121. xtgeo-4.14.1.dist-info/WHEEL +5 -0
  122. xtgeo-4.14.1.dist-info/licenses/LICENSE.md +165 -0
@@ -0,0 +1,301 @@
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
+ from warnings import warn
8
+
9
+ import numpy as np
10
+ from numpy import ma
11
+
12
+ from xtgeo.common import null_logger
13
+ from xtgeo.common.constants import UNDEF, UNDEF_INT, UNDEF_INT_LIMIT, UNDEF_LIMIT
14
+ from xtgeo.roxutils import RoxUtils
15
+ from xtgeo.roxutils._roxar_loader import roxar
16
+
17
+ if TYPE_CHECKING:
18
+ from xtgeo.grid3d.grid_property import GridProperty
19
+
20
+ if roxar is not None:
21
+ from roxar import Project as RoxarProjectType
22
+ from roxar.grids import Grid3D as RoxarGrid3DType
23
+
24
+ logger = null_logger(__name__)
25
+
26
+ VALID_ROXAR_DTYPES = [np.uint8, np.uint16, np.float32]
27
+
28
+
29
+ def import_prop_roxapi(
30
+ project: RoxarProjectType,
31
+ gname: str,
32
+ pname: str,
33
+ realisation: int,
34
+ faciescodes: bool,
35
+ ) -> dict[str, Any]:
36
+ """Import a Property via ROXAR API spec."""
37
+ logger.info("Opening RMS project ...")
38
+
39
+ rox = RoxUtils(project, readonly=True)
40
+
41
+ result = _get_gridprop_data(rox, gname, pname, realisation, faciescodes)
42
+
43
+ rox.safe_close()
44
+ return result
45
+
46
+
47
+ def _get_gridprop_data(
48
+ rox: RoxUtils, gname: str, pname: str, realisation: int, faciescodes: bool
49
+ ) -> dict[str, Any]:
50
+ # inside a RMS project
51
+
52
+ if gname not in rox.project.grid_models:
53
+ raise ValueError(f"No gridmodel with name {gname}")
54
+ if pname not in rox.project.grid_models[gname].properties:
55
+ raise ValueError(f"No property in {gname} with name {pname}")
56
+
57
+ try:
58
+ return _convert_to_xtgeo_prop(rox, gname, pname, realisation, faciescodes)
59
+ except KeyError as keyerror:
60
+ raise RuntimeError(keyerror) from keyerror
61
+
62
+
63
+ def _convert_to_xtgeo_prop(
64
+ rox: RoxUtils, gname: str, pname: str, realisation: int, faciescodes: bool
65
+ ) -> dict[str, Any]:
66
+ result: dict[str, Any] = {}
67
+ roxgrid = rox.project.grid_models[gname]
68
+ roxprop = roxgrid.properties[pname]
69
+
70
+ discrete = str(roxprop.type) in ("discrete", "body_facies")
71
+ result["discrete"] = discrete
72
+
73
+ result["roxorigin"] = True
74
+ indexer = roxgrid.get_grid(realisation=realisation).grid_indexer
75
+ result["ncol"], result["nrow"], result["nlay"] = indexer.dimensions
76
+
77
+ logger.info(indexer.ijk_handedness)
78
+
79
+ pvalues = roxprop.get_values(realisation=realisation)
80
+
81
+ if str(roxprop.type) == "body_facies" and faciescodes:
82
+ fmap = roxprop.get_facies_map(realisation=realisation)
83
+ pvalues = fmap[pvalues] # numpy magics
84
+
85
+ result["roxar_dtype"] = pvalues.dtype
86
+
87
+ mybuffer: np.ndarray = np.ndarray(
88
+ indexer.dimensions, dtype=np.int32 if discrete else np.float64
89
+ )
90
+ mybuffer.fill(UNDEF_INT if discrete else UNDEF)
91
+
92
+ cellno = indexer.get_cell_numbers_in_range((0, 0, 0), indexer.dimensions)
93
+
94
+ ijk = indexer.get_indices(cellno)
95
+
96
+ iind = ijk[:, 0]
97
+ jind = ijk[:, 1]
98
+ kind = ijk[:, 2]
99
+
100
+ mybuffer[iind, jind, kind] = pvalues[cellno]
101
+
102
+ mybuffer = ma.masked_greater(mybuffer, UNDEF_INT_LIMIT if discrete else UNDEF_LIMIT)
103
+
104
+ result["values"] = mybuffer
105
+ result["name"] = pname
106
+
107
+ if discrete:
108
+ result["codes"] = _fix_codes(
109
+ result["values"].reshape(-1).compressed(), roxprop.code_names
110
+ )
111
+ logger.info("Fixed codes: %s", result["codes"])
112
+ return result
113
+
114
+
115
+ def export_prop_roxapi(
116
+ self: GridProperty,
117
+ project: RoxarProjectType,
118
+ gname: str,
119
+ pname: str,
120
+ realisation: int = 0,
121
+ casting: Literal["no", "equiv", "safe", "same_kind", "unsafe"] | None = "unsafe",
122
+ ) -> None:
123
+ """Export (i.e. store or save) to a Property icon in RMS via ROXAR API spec."""
124
+ rox = RoxUtils(project, readonly=False)
125
+
126
+ try:
127
+ roxgrid = rox.project.grid_models[gname]
128
+ _store_in_roxar(self, pname, roxgrid, realisation, casting)
129
+
130
+ except KeyError as keyerror:
131
+ raise RuntimeError(keyerror)
132
+
133
+ if rox._roxexternal:
134
+ rox.project.save()
135
+
136
+ rox.safe_close()
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
+ # for mypy
154
+ min_val: int | float
155
+ max_val: int | float
156
+
157
+ if np.issubdtype(dtype, np.integer):
158
+ # Integer type
159
+ min_val = int(np.iinfo(dtype).min)
160
+ max_val = int(np.iinfo(dtype).max)
161
+ elif np.issubdtype(dtype, np.floating):
162
+ # Float type
163
+ min_val = float(np.finfo(dtype).min)
164
+ max_val = float(np.finfo(dtype).max)
165
+ else:
166
+ # Unknown type
167
+ raise RuntimeError("Probable bug, values array not integer or float")
168
+
169
+ if pval.min() < min_val or pval.max() > max_val:
170
+ message += (
171
+ f"Values outside {dtype} range [{min_val}, {max_val}] found. "
172
+ f"Range in xtgeo values are [{pval.min()}, {pval.max()}]"
173
+ )
174
+
175
+ except (ValueError, OverflowError):
176
+ # Handle edge cases gracefully
177
+ message += f"Could not validate range for dtype {dtype}. "
178
+
179
+ if message and allow_unsafe_casting:
180
+ message += (
181
+ "\nUnsafe casting is allowed; this means that original values may "
182
+ "be truncated which may give unpredictable results and/or mess "
183
+ "up code names and values settings."
184
+ )
185
+
186
+ if message:
187
+ warn(message, UserWarning)
188
+
189
+
190
+ def _store_in_roxar(
191
+ self: GridProperty,
192
+ pname: str,
193
+ roxgrid: RoxarGrid3DType,
194
+ realisation: int,
195
+ casting: Literal["no", "equiv", "safe", "same_kind", "unsafe"] | None,
196
+ ) -> None:
197
+ """Store property in RMS."""
198
+ indexer = roxgrid.get_grid(realisation=realisation).grid_indexer
199
+
200
+ logger.info("Store in RMS...")
201
+
202
+ roxtype: Any = roxar # needed for mypy
203
+ roxar_property_type = (
204
+ roxtype.GridPropertyType.discrete
205
+ if self.isdiscrete
206
+ else roxtype.GridPropertyType.continuous
207
+ )
208
+
209
+ val3d = self.values.copy()
210
+
211
+ dtype = self._roxar_dtype
212
+ logger.info("DTYPE is %s for %s", dtype, pname)
213
+
214
+ if dtype not in VALID_ROXAR_DTYPES:
215
+ raise TypeError(
216
+ f"Roxar dtype is not valid: {dtype} must be in {VALID_ROXAR_DTYPES}"
217
+ )
218
+
219
+ properties = roxgrid.properties
220
+ original_dtype = dtype
221
+ if pname not in properties:
222
+ rprop = properties.create(
223
+ pname, property_type=roxar_property_type, data_type=dtype
224
+ )
225
+ else:
226
+ rprop = properties[pname]
227
+ original_dtype = rprop.data_type
228
+
229
+ _validate_dtype_in_roxar(val3d, original_dtype, dtype, casting == "unsafe")
230
+
231
+ dtype = original_dtype
232
+ val3d = val3d.astype(dtype, casting=casting)
233
+
234
+ cellno = indexer.get_cell_numbers_in_range((0, 0, 0), indexer.dimensions)
235
+
236
+ ijk = indexer.get_indices(cellno)
237
+
238
+ iind = ijk[:, 0]
239
+ jind = ijk[:, 1]
240
+ kind = ijk[:, 2]
241
+
242
+ pvalues = roxgrid.get_grid(realisation=realisation).generate_values(data_type=dtype)
243
+
244
+ pvalues[cellno] = val3d[iind, jind, kind]
245
+ rprop.set_values(pvalues, realisation=realisation)
246
+
247
+ if self.isdiscrete and "float" not in str(original_dtype):
248
+ try:
249
+ rprop.code_names = _rox_compatible_codes(self.codes)
250
+ except ValueError as verr:
251
+ message = (
252
+ f"Trying to set codes in Roxar: {self.codes} for type "
253
+ f"{self._roxar_dtype}. {str(verr)} Consider editing the codes!"
254
+ )
255
+ raise ValueError(message)
256
+
257
+
258
+ def _fix_codes(
259
+ active_values: np.ndarray, codes: dict[str | int, str]
260
+ ) -> dict[int, str]:
261
+ """Roxar may provide a code list with empty strings values, fix this issue here.
262
+
263
+ Roxar may also interpolate code values which are actually not present in the
264
+ property. Here, the presence of actual codes is also checked.
265
+ """
266
+ newcodes = {}
267
+ codes_data = {val: str(val) for val in np.unique(active_values)}
268
+
269
+ for code, name in codes.items():
270
+ if not isinstance(code, int):
271
+ code = int(code)
272
+
273
+ if not name:
274
+ name = str(code)
275
+
276
+ if code not in codes_data:
277
+ continue
278
+
279
+ newcodes[code] = name
280
+
281
+ return newcodes
282
+
283
+
284
+ def _rox_compatible_codes(codes: dict) -> dict:
285
+ """Ensure that keys in codes are int's prior to storage in RMS."""
286
+
287
+ newcodes = {}
288
+ for code, name in codes.items():
289
+ if code is None:
290
+ continue # skip codes of type None; assumed to be spurious
291
+ if not isinstance(code, int):
292
+ try:
293
+ code = int(code)
294
+ except ValueError:
295
+ raise ValueError(
296
+ "The keys in codes must be an integer prior to RMS "
297
+ f"storage. Actual key found here is '{code}' of type {type(code)}"
298
+ )
299
+
300
+ newcodes[code] = name
301
+ 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
+ )