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.
- cxtgeo.py +558 -0
- cxtgeoPYTHON_wrap.c +19537 -0
- xtgeo/__init__.py +248 -0
- xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
- xtgeo/_internal.cp313-win_amd64.pyd +0 -0
- xtgeo/common/__init__.py +19 -0
- xtgeo/common/_angles.py +29 -0
- xtgeo/common/_xyz_enum.py +50 -0
- xtgeo/common/calc.py +396 -0
- xtgeo/common/constants.py +30 -0
- xtgeo/common/exceptions.py +42 -0
- xtgeo/common/log.py +93 -0
- xtgeo/common/sys.py +166 -0
- xtgeo/common/types.py +18 -0
- xtgeo/common/version.py +34 -0
- xtgeo/common/xtgeo_dialog.py +604 -0
- xtgeo/cube/__init__.py +9 -0
- xtgeo/cube/_cube_export.py +214 -0
- xtgeo/cube/_cube_import.py +532 -0
- xtgeo/cube/_cube_roxapi.py +180 -0
- xtgeo/cube/_cube_utils.py +287 -0
- xtgeo/cube/_cube_window_attributes.py +273 -0
- xtgeo/cube/cube1.py +1023 -0
- xtgeo/grid3d/__init__.py +15 -0
- xtgeo/grid3d/_ecl_grid.py +778 -0
- xtgeo/grid3d/_ecl_inte_head.py +152 -0
- xtgeo/grid3d/_ecl_logi_head.py +71 -0
- xtgeo/grid3d/_ecl_output_file.py +81 -0
- xtgeo/grid3d/_egrid.py +1004 -0
- xtgeo/grid3d/_find_gridprop_in_eclrun.py +625 -0
- xtgeo/grid3d/_grdecl_format.py +309 -0
- xtgeo/grid3d/_grdecl_grid.py +400 -0
- xtgeo/grid3d/_grid3d.py +29 -0
- xtgeo/grid3d/_grid3d_fence.py +284 -0
- xtgeo/grid3d/_grid3d_utils.py +228 -0
- xtgeo/grid3d/_grid_boundary.py +76 -0
- xtgeo/grid3d/_grid_etc1.py +1683 -0
- xtgeo/grid3d/_grid_export.py +222 -0
- xtgeo/grid3d/_grid_hybrid.py +50 -0
- xtgeo/grid3d/_grid_import.py +79 -0
- xtgeo/grid3d/_grid_import_ecl.py +101 -0
- xtgeo/grid3d/_grid_import_roff.py +135 -0
- xtgeo/grid3d/_grid_import_xtgcpgeom.py +375 -0
- xtgeo/grid3d/_grid_refine.py +258 -0
- xtgeo/grid3d/_grid_roxapi.py +292 -0
- xtgeo/grid3d/_grid_translate_coords.py +154 -0
- xtgeo/grid3d/_grid_wellzone.py +165 -0
- xtgeo/grid3d/_gridprop_export.py +202 -0
- xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
- xtgeo/grid3d/_gridprop_import_grdecl.py +132 -0
- xtgeo/grid3d/_gridprop_import_roff.py +52 -0
- xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
- xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
- xtgeo/grid3d/_gridprop_op1.py +272 -0
- xtgeo/grid3d/_gridprop_roxapi.py +301 -0
- xtgeo/grid3d/_gridprop_value_init.py +140 -0
- xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
- xtgeo/grid3d/_gridprops_import_roff.py +83 -0
- xtgeo/grid3d/_roff_grid.py +470 -0
- xtgeo/grid3d/_roff_parameter.py +303 -0
- xtgeo/grid3d/grid.py +3010 -0
- xtgeo/grid3d/grid_properties.py +699 -0
- xtgeo/grid3d/grid_property.py +1313 -0
- xtgeo/grid3d/types.py +15 -0
- xtgeo/interfaces/rms/__init__.py +18 -0
- xtgeo/interfaces/rms/_regular_surface.py +460 -0
- xtgeo/interfaces/rms/_rms_base.py +100 -0
- xtgeo/interfaces/rms/_rmsapi_package.py +69 -0
- xtgeo/interfaces/rms/rmsapi_utils.py +438 -0
- xtgeo/io/__init__.py +1 -0
- xtgeo/io/_file.py +603 -0
- xtgeo/metadata/__init__.py +17 -0
- xtgeo/metadata/metadata.py +435 -0
- xtgeo/roxutils/__init__.py +7 -0
- xtgeo/roxutils/_roxar_loader.py +54 -0
- xtgeo/roxutils/_roxutils_etc.py +122 -0
- xtgeo/roxutils/roxutils.py +207 -0
- xtgeo/surface/__init__.py +20 -0
- xtgeo/surface/_regsurf_boundary.py +26 -0
- xtgeo/surface/_regsurf_cube.py +210 -0
- xtgeo/surface/_regsurf_cube_window.py +391 -0
- xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
- xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
- xtgeo/surface/_regsurf_export.py +388 -0
- xtgeo/surface/_regsurf_grid3d.py +275 -0
- xtgeo/surface/_regsurf_gridding.py +347 -0
- xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
- xtgeo/surface/_regsurf_import.py +347 -0
- xtgeo/surface/_regsurf_lowlevel.py +122 -0
- xtgeo/surface/_regsurf_oper.py +538 -0
- xtgeo/surface/_regsurf_utils.py +81 -0
- xtgeo/surface/_surfs_import.py +43 -0
- xtgeo/surface/_zmap_parser.py +138 -0
- xtgeo/surface/regular_surface.py +3043 -0
- xtgeo/surface/surfaces.py +276 -0
- xtgeo/well/__init__.py +24 -0
- xtgeo/well/_blockedwell_roxapi.py +241 -0
- xtgeo/well/_blockedwells_roxapi.py +68 -0
- xtgeo/well/_well_aux.py +30 -0
- xtgeo/well/_well_io.py +327 -0
- xtgeo/well/_well_oper.py +483 -0
- xtgeo/well/_well_roxapi.py +304 -0
- xtgeo/well/_wellmarkers.py +486 -0
- xtgeo/well/_wells_utils.py +158 -0
- xtgeo/well/blocked_well.py +220 -0
- xtgeo/well/blocked_wells.py +134 -0
- xtgeo/well/well1.py +1516 -0
- xtgeo/well/wells.py +211 -0
- xtgeo/xyz/__init__.py +6 -0
- xtgeo/xyz/_polygons_oper.py +272 -0
- xtgeo/xyz/_xyz.py +758 -0
- xtgeo/xyz/_xyz_data.py +646 -0
- xtgeo/xyz/_xyz_io.py +737 -0
- xtgeo/xyz/_xyz_lowlevel.py +42 -0
- xtgeo/xyz/_xyz_oper.py +613 -0
- xtgeo/xyz/_xyz_roxapi.py +766 -0
- xtgeo/xyz/points.py +698 -0
- xtgeo/xyz/polygons.py +827 -0
- xtgeo-4.14.1.dist-info/METADATA +146 -0
- xtgeo-4.14.1.dist-info/RECORD +122 -0
- xtgeo-4.14.1.dist-info/WHEEL +5 -0
- 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
|