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,344 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ from copy import deepcopy
5
+ from typing import Generator, Literal
6
+
7
+ import resfo
8
+
9
+ import xtgeo
10
+ from xtgeo.common import null_logger
11
+ from xtgeo.common.constants import MAXKEYWORDS
12
+ from xtgeo.io._file import FileWrapper
13
+
14
+ from . import _grid3d_utils as utils
15
+ from ._find_gridprop_in_eclrun import (
16
+ find_gridprop_from_init_file,
17
+ find_gridprops_from_restart_file,
18
+ valid_gridprop_lengths,
19
+ )
20
+ from ._gridprop_import_eclrun import decorate_name
21
+ from .grid_property import GridProperty
22
+
23
+ xtg = xtgeo.common.XTGeoDialog()
24
+
25
+ logger = null_logger(__name__)
26
+
27
+
28
+ def read_eclrun_properties(xtg_file: FileWrapper) -> Generator[str, None, None]:
29
+ """Generates property names from Eclipse files.
30
+
31
+ Args:
32
+ xtg_file: The FileWrapper representing an Eclipse INIT or restart file.
33
+
34
+ Returns:
35
+ Names of properties within the Eclipse file.
36
+ """
37
+ is_stream = isinstance(xtg_file.file, (io.BytesIO, io.StringIO))
38
+ try:
39
+ if is_stream:
40
+ mark = xtg_file.file.tell()
41
+ ntotal = 0
42
+ nactive = 0
43
+ for item in resfo.lazy_read(xtg_file.file):
44
+ keyword = item.read_keyword().strip()
45
+
46
+ if keyword == "INTEHEAD":
47
+ data = item.read_array()
48
+ # nx * ny * nz
49
+ ntotal = data[8] * data[9] * data[10]
50
+ nactive = data[11]
51
+ continue
52
+
53
+ # Do some simple filtering of things that cannot be properties
54
+ if item.read_length() in (ntotal, nactive) and item.read_type() in (
55
+ b"INTE",
56
+ b"REAL",
57
+ b"DOUB",
58
+ ):
59
+ yield keyword
60
+ finally:
61
+ if is_stream:
62
+ xtg_file.file.seek(mark)
63
+
64
+
65
+ def sanitize_date_list(
66
+ dates: list[int] | list[str] | Literal["first", "all", "last"],
67
+ ) -> list[int] | Literal["first", "all", "last"]:
68
+ """
69
+ Converts dateformats of the form 'YYYY-MM-DD', 'YYYYMMDD' or YYYYMMDD to
70
+ list of integers of the form [YYYYMMDD] (ie. suitible for find_gridprops
71
+ functions), but lets the special literals 'first' and 'last' remain
72
+ unchanged.
73
+
74
+ >>> sanitize_date_list('first')
75
+ 'first'
76
+ >>> sanitize_date_list('last')
77
+ 'last'
78
+ >>> sanitize_date_list('all')
79
+ 'all'
80
+ >>> sanitize_date_list(['2020-01-01'])
81
+ [20200101]
82
+ >>> sanitize_date_list(['20200101'])
83
+ [20200101]
84
+ >>> sanitize_date_list([20200101])
85
+ [20200101]
86
+ """
87
+ if dates in ("first", "last", "all"):
88
+ return dates
89
+ new_dates = []
90
+ for date in dates:
91
+ if isinstance(date, int):
92
+ new_dates.append(date)
93
+ else:
94
+ try:
95
+ if (
96
+ isinstance(date, str)
97
+ and len(date) == 10
98
+ and date[4] == "-"
99
+ and date[7] == "-"
100
+ ):
101
+ date = date.replace("-", "")
102
+ new_dates.append(int(date))
103
+ except ValueError as err:
104
+ raise ValueError(
105
+ "valid dates are either 'first'/'all'/'last', "
106
+ "list ints of the form YYYYMMDD or list of strings of "
107
+ f"'YYYY-MM-DD'/'YYYYMMDD' got {dates}"
108
+ ) from err
109
+ return new_dates
110
+
111
+
112
+ def import_ecl_init_gridproperties(
113
+ pfile,
114
+ names: list[str] | Literal["all"],
115
+ grid,
116
+ strict=True,
117
+ maxkeys: int = MAXKEYWORDS,
118
+ ) -> list[GridProperty]:
119
+ """Imports list of properties from an init file.
120
+
121
+ Note, the method does not determine whether a given keyword in the file
122
+ is a grid property, only that it has the correct data type and length
123
+ to be considered as a grid property.
124
+
125
+ Args:
126
+ pfile: Path to the ecl restart file
127
+ names: List of names to fetch, can also be "all" to fetch all properties.
128
+ grid: The grid used by the simulator to produce the restart file.
129
+ strict: If strict=True, will raise error if key is not found.
130
+ maxkeys: Maximum number of keywords allocated
131
+ Returns:
132
+ List of GridProperty objects fetched from the init file.
133
+ """
134
+ if not isinstance(pfile, FileWrapper):
135
+ pfile = FileWrapper(pfile)
136
+
137
+ if not grid:
138
+ raise ValueError("Grid Geometry object is missing")
139
+
140
+ if not names:
141
+ raise ValueError("Name list cannot be empty (None)")
142
+
143
+ # scan valid keywords
144
+ kwlist = utils.scan_keywords(
145
+ pfile,
146
+ fformat="xecl",
147
+ dataframe=True,
148
+ dates=True,
149
+ maxkeys=maxkeys,
150
+ )
151
+
152
+ validnames = []
153
+
154
+ valid_lengths = valid_gridprop_lengths(grid)
155
+
156
+ # get a list of valid property names
157
+ for kw in list(kwlist.itertuples(index=False, name=None)):
158
+ kwname, _, nlen, _, _ = kw
159
+ if nlen in valid_lengths and kwname not in validnames:
160
+ validnames.append(kwname)
161
+
162
+ usenames = deepcopy(validnames) if names == "all" else list(names)
163
+
164
+ for name in usenames:
165
+ if name not in validnames:
166
+ if strict:
167
+ raise ValueError(
168
+ f"Requested keyword {name} is not in INIT file,"
169
+ f"valid entries are {validnames}, set strict=False to warn instead."
170
+ )
171
+ logger.warning(
172
+ "Requested keyword %s is not in INIT file."
173
+ "Entry will not be read, set strict=True to raise Error instead.",
174
+ name,
175
+ )
176
+
177
+ results = find_gridprop_from_init_file(
178
+ pfile.file,
179
+ names=names,
180
+ grid=grid,
181
+ )
182
+ properties_list = []
183
+ for result in results:
184
+ result["name"] = decorate_name(result["name"], grid.dualporo, fracture=False)
185
+ properties_list.append(GridProperty(**result))
186
+
187
+ return properties_list
188
+
189
+
190
+ def import_ecl_restart_gridproperties(
191
+ pfile,
192
+ names: list[str] | Literal["all"],
193
+ dates: list[int] | list[str] | Literal["all", "last", "first"],
194
+ grid,
195
+ strict: tuple[bool, bool],
196
+ namestyle: Literal[0, 1],
197
+ maxkeys: int = MAXKEYWORDS,
198
+ ) -> list[GridProperty]:
199
+ """Imports list of gridproperties from a restart file.
200
+
201
+ Note, the method does not determine whether a given keyword in the file
202
+ is a grid property, only that it has the correct data type and length
203
+ to be considered as a grid property.
204
+
205
+ Args:
206
+ pfile: Path to the ecl restart file
207
+ names: List of names to fetch, can also be "all" to fetch all properties.
208
+ dates: List of xtgeo style dates (e.g. int(19990101) or "YYYYMMDD"),
209
+ also Also accepts "YYYY-MM-DD". "all", "last" and "first" can be
210
+ given for all, last or first date(s) in the file. Dates=None means
211
+ look for properties in the init file.
212
+ grid: The grid used by the simulator to produce the restart file.
213
+ strict: strict (False, False) means that if keyname,
214
+ optionally with date is not found is will just warn and continue to
215
+ next. If (True, True) it will warn but TRY to import anyway, which
216
+ in turn may raise a KeywordNotError or DateNotFoundError. The
217
+ (True, False) will be strict on keywords, but sloppy on dates,
218
+ meaning that missing dates will be skipped. However, if all dates
219
+ are missing an exception will be raised
220
+ namestyle : 0 (default) for style SWAT_20110223,
221
+ 1 for SWAT--2011_02_23 (applies to restart only)
222
+ maxkeys: Maximum number of keywords allocated
223
+ Returns:
224
+ List of GridProperty objects fetched from the restart file.
225
+ """
226
+
227
+ strictkeycomb, strictdate = strict
228
+ if not grid:
229
+ raise ValueError("Grid Geometry object is missing")
230
+
231
+ if not names:
232
+ raise ValueError("Name list cannot be empty (None)")
233
+
234
+ dates = sanitize_date_list(dates)
235
+
236
+ # scan valid keywords with dates
237
+ kwlist = utils.scan_keywords(
238
+ pfile,
239
+ fformat="xecl",
240
+ dataframe=True,
241
+ dates=True,
242
+ maxkeys=maxkeys,
243
+ )
244
+
245
+ validnamedatepairs, validdates = _process_valid_namesdates(kwlist, grid)
246
+
247
+ # allow sloppy dates, i.e. remove invalid date entries
248
+ if isinstance(dates, list) and strictdate is False:
249
+ dates = _process_sloppydates(dates, validdates)
250
+
251
+ usenamedatepairs = []
252
+ if names == "all" and dates == "all":
253
+ usenamedatepairs = deepcopy(validnamedatepairs)
254
+ usedates = dates
255
+ else:
256
+ if names == "all" and dates != "all":
257
+ usenames = [namedate[0] for namedate in validnamedatepairs]
258
+ usedates = dates
259
+ elif names != "all" and dates == "all":
260
+ usedates = [namedate[1] for namedate in validnamedatepairs]
261
+ usenames = names
262
+ else:
263
+ usedates = dates
264
+ usenames = names
265
+
266
+ for name in usenames:
267
+ for date in usedates:
268
+ usenamedatepairs.append((name, date))
269
+
270
+ # Do the actual import
271
+ for namedate in usenamedatepairs:
272
+ name, date = namedate
273
+
274
+ if name not in ("SGAS", "SOIL", "SWAT") and namedate not in validnamedatepairs:
275
+ # saturation keywords are a mess in Eclipse and friends; check later
276
+ if strictkeycomb:
277
+ raise ValueError(
278
+ f"Keyword data combo {name} {date} is not in RESTART file."
279
+ f"Possible entries are: {validnamedatepairs}"
280
+ )
281
+ logger.warning(
282
+ "Keyword data combo %s %s is not in RESTART file."
283
+ "Possible entries are: %s"
284
+ "Value will not be imported",
285
+ name,
286
+ date,
287
+ validnamedatepairs,
288
+ )
289
+
290
+ results = find_gridprops_from_restart_file(pfile.file, names, dates, grid=grid)
291
+ properties_list = []
292
+ for result in results:
293
+ if namestyle == 1:
294
+ sdate = str(result["date"])
295
+ result["name"] += "--" + sdate[0:4] + "_" + sdate[4:6] + "_" + sdate[6:8]
296
+ else:
297
+ result["name"] = decorate_name(
298
+ result["name"], grid.dualporo, fracture=False, date=result["date"]
299
+ )
300
+
301
+ properties_list.append(GridProperty(**result))
302
+
303
+ return properties_list
304
+
305
+
306
+ def _process_valid_namesdates(kwlist, grid):
307
+ """Return lists with valid pairs, dates scanned from RESTART"""
308
+ validnamedatepairs = []
309
+ validdates = []
310
+ valid_lengths = valid_gridprop_lengths(grid)
311
+ for kw in list(kwlist.itertuples(index=False, name=None)):
312
+ kwname, kwtyp, nlen, _, date = kw
313
+ if (
314
+ kwtyp != "CHAR"
315
+ and nlen in valid_lengths
316
+ and (kwname, date) not in validnamedatepairs
317
+ ):
318
+ validnamedatepairs.append((kwname, date))
319
+ if kwtyp != "CHAR" and nlen in valid_lengths and date not in validdates:
320
+ validdates.append(date)
321
+
322
+ return validnamedatepairs, validdates
323
+
324
+
325
+ def _process_sloppydates(dates, validdates):
326
+ """Allow "sloppy dates", which removes invalid dates from the list"""
327
+
328
+ usedates = []
329
+ skipdates = []
330
+ for date in dates:
331
+ if date not in validdates:
332
+ skipdates.append(date)
333
+ else:
334
+ usedates.append(date)
335
+ if not usedates:
336
+ msg = f"No valid dates given (dates: {dates} vs {validdates})"
337
+ xtg.error(msg)
338
+ raise ValueError(msg)
339
+
340
+ if skipdates:
341
+ msg = f"Some dates not found: {skipdates}; will continue with dates: {usedates}"
342
+ xtg.warn(msg)
343
+
344
+ return usedates
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ from typing import TYPE_CHECKING, Generator, Literal
5
+
6
+ import roffio
7
+
8
+ import xtgeo
9
+ from xtgeo.common import null_logger
10
+
11
+ if TYPE_CHECKING:
12
+ from xtgeo.io._file import FileWrapper
13
+
14
+ from .grid_property import GridProperty
15
+
16
+ logger = null_logger(__name__)
17
+
18
+
19
+ def read_roff_properties(xtg_file: FileWrapper) -> Generator[str, None, None]:
20
+ """Generates parameter names from roff files.
21
+
22
+ Args:
23
+ xtg_file: The FileWrapper representing a roff file.
24
+
25
+ Returns:
26
+ Names of parameters within the roff file.
27
+ """
28
+ is_stream = isinstance(xtg_file.file, (io.BytesIO, io.StringIO))
29
+ try:
30
+ if is_stream:
31
+ mark = xtg_file.file.tell()
32
+ with roffio.lazy_read(xtg_file.file) as roff_iter:
33
+ for tag_name, tag_group in roff_iter:
34
+ for keyword, value in tag_group:
35
+ if tag_name == "parameter" and keyword == "name":
36
+ yield value
37
+ finally:
38
+ if is_stream:
39
+ xtg_file.file.seek(mark)
40
+
41
+
42
+ def import_roff_gridproperties(
43
+ pfile: FileWrapper,
44
+ names: list[str] | Literal["all"] = "all",
45
+ strict: bool = True,
46
+ ) -> list[GridProperty]:
47
+ """
48
+ Imports a list of properties from a ROFF file.
49
+
50
+ Args:
51
+ pfile: Reference to the file.
52
+ names: List of names to fetch, can also be "all" to fetch all properties.
53
+ strict: If strict=True, will raise error if key is not found.
54
+ Defaults to True.
55
+
56
+ Returns:
57
+ List of GridProperty objects fetched from the ROFF file.
58
+ """
59
+ if names == "all":
60
+ return [
61
+ xtgeo.gridproperty_from_file(pfile.file, fformat="roff", name=name)
62
+ for name in read_roff_properties(pfile)
63
+ ]
64
+
65
+ prop_names = list(read_roff_properties(pfile))
66
+ props = []
67
+ for name in names:
68
+ if name in prop_names:
69
+ props.append(
70
+ xtgeo.gridproperty_from_file(pfile.file, fformat="roff", name=name)
71
+ )
72
+ elif strict:
73
+ raise ValueError(
74
+ f"Requested keyword {name} is not in ROFF file. Valid "
75
+ f"entries are {prop_names}. Set strict=False to warn instead."
76
+ )
77
+ else:
78
+ logger.warning(
79
+ "Requested keyword %s is not in ROFF file. Entry will"
80
+ "not be read. Set strict=True to raise Error instead.",
81
+ name,
82
+ )
83
+ return props