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,304 @@
|
|
|
1
|
+
"""Well input and output, private module for ROXAPI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Literal, Optional
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
import numpy.ma as npma
|
|
9
|
+
import pandas as pd
|
|
10
|
+
|
|
11
|
+
from xtgeo.common import XTGeoDialog, null_logger
|
|
12
|
+
from xtgeo.common._xyz_enum import _AttrName, _AttrType
|
|
13
|
+
from xtgeo.common.constants import UNDEF, UNDEF_INT, UNDEF_INT_LIMIT, UNDEF_LIMIT
|
|
14
|
+
from xtgeo.roxutils import RoxUtils
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from .well1 import Well
|
|
18
|
+
|
|
19
|
+
xtg = XTGeoDialog()
|
|
20
|
+
logger = null_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Well() instance: self
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Import from ROX api
|
|
27
|
+
# --------------------------------------------------------------------------------------
|
|
28
|
+
def import_well_roxapi(
|
|
29
|
+
project,
|
|
30
|
+
wname,
|
|
31
|
+
trajectory="Drilled trajectory",
|
|
32
|
+
logrun="log",
|
|
33
|
+
lognames="all",
|
|
34
|
+
lognames_strict=False,
|
|
35
|
+
inclmd=False,
|
|
36
|
+
inclsurvey=False,
|
|
37
|
+
): # pragma: no cover
|
|
38
|
+
"""Private function for loading project and ROXAPI well import."""
|
|
39
|
+
rox = RoxUtils(project, readonly=True)
|
|
40
|
+
|
|
41
|
+
result = _roxapi_import_well(
|
|
42
|
+
rox,
|
|
43
|
+
wname,
|
|
44
|
+
trajectory,
|
|
45
|
+
logrun,
|
|
46
|
+
lognames,
|
|
47
|
+
lognames_strict,
|
|
48
|
+
inclmd,
|
|
49
|
+
inclsurvey,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
rox.safe_close()
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _roxapi_import_well(
|
|
57
|
+
rox, wname, traj, lrun, lognames, lognames_strict, inclmd, inclsurvey
|
|
58
|
+
): # pragma: no cover
|
|
59
|
+
"""Private function for ROXAPI well import."""
|
|
60
|
+
if wname in rox.project.wells:
|
|
61
|
+
roxwell = rox.project.wells[wname]
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(f"No such well name present: {wname}")
|
|
64
|
+
|
|
65
|
+
if traj in roxwell.wellbore.trajectories:
|
|
66
|
+
roxtraj = roxwell.wellbore.trajectories[traj]
|
|
67
|
+
else:
|
|
68
|
+
raise ValueError(f"No such well traj present for {wname}: {traj}")
|
|
69
|
+
|
|
70
|
+
if lrun in roxtraj.log_runs:
|
|
71
|
+
roxlrun = roxtraj.log_runs[lrun]
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError(f"No such logrun present for {wname}: {lrun}")
|
|
74
|
+
|
|
75
|
+
wlogtypes = {}
|
|
76
|
+
wlogrecords = {}
|
|
77
|
+
|
|
78
|
+
# get logs repr trajecetry
|
|
79
|
+
mdlogname, logs = _roxapi_traj(roxtraj, roxlrun, inclmd, inclsurvey)
|
|
80
|
+
|
|
81
|
+
if lognames and lognames == "all":
|
|
82
|
+
for logcurv in roxlrun.log_curves:
|
|
83
|
+
lname = logcurv.name
|
|
84
|
+
logs[lname] = _get_roxlog(wlogtypes, wlogrecords, roxlrun, lname)
|
|
85
|
+
elif lognames:
|
|
86
|
+
for lname in lognames:
|
|
87
|
+
if lname in roxlrun.log_curves:
|
|
88
|
+
logs[lname] = _get_roxlog(wlogtypes, wlogrecords, roxlrun, lname)
|
|
89
|
+
else:
|
|
90
|
+
if lognames_strict:
|
|
91
|
+
validlogs = [logname.name for logname in roxlrun.log_curves]
|
|
92
|
+
raise ValueError(
|
|
93
|
+
f"Could not get log name {lname}, validlogs are {validlogs}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
"rkb": roxwell.rkb,
|
|
98
|
+
"xpos": roxwell.wellhead[0],
|
|
99
|
+
"ypos": roxwell.wellhead[1],
|
|
100
|
+
"wname": wname,
|
|
101
|
+
"wlogtypes": wlogtypes,
|
|
102
|
+
"wlogrecords": wlogrecords,
|
|
103
|
+
"mdlogname": mdlogname,
|
|
104
|
+
"df": pd.DataFrame.from_dict(logs),
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _roxapi_traj(roxtraj, roxlrun, inclmd, inclsurvey): # pragma: no cover
|
|
109
|
+
"""Get trajectory in ROXAPI."""
|
|
110
|
+
|
|
111
|
+
surveyset = roxtraj.survey_point_series
|
|
112
|
+
measured_depths = roxlrun.get_measured_depths()
|
|
113
|
+
|
|
114
|
+
mds = measured_depths.tolist()
|
|
115
|
+
|
|
116
|
+
geo_array_shape = (len(measured_depths), 6)
|
|
117
|
+
geo_array = np.empty(geo_array_shape)
|
|
118
|
+
|
|
119
|
+
for ino, mdv in enumerate(mds):
|
|
120
|
+
try:
|
|
121
|
+
geo_array[ino] = surveyset.interpolate_survey_point(mdv)
|
|
122
|
+
except ValueError:
|
|
123
|
+
logger.warning("MD is %s, surveyinterpolation fails, CHECK RESULT!", mdv)
|
|
124
|
+
geo_array[ino] = geo_array[ino - 1]
|
|
125
|
+
|
|
126
|
+
logs = {}
|
|
127
|
+
mdlogname = None
|
|
128
|
+
|
|
129
|
+
logs[_AttrName.XNAME.value] = geo_array[:, 3]
|
|
130
|
+
logs[_AttrName.YNAME.value] = geo_array[:, 4]
|
|
131
|
+
logs[_AttrName.ZNAME.value] = geo_array[:, 5]
|
|
132
|
+
if inclmd or inclsurvey:
|
|
133
|
+
logs[_AttrName.M_MD_NAME.value] = geo_array[:, 0]
|
|
134
|
+
mdlogname = _AttrName.M_MD_NAME.value
|
|
135
|
+
if inclsurvey:
|
|
136
|
+
logs[_AttrName.M_INCL_NAME.value] = geo_array[:, 1]
|
|
137
|
+
logs[_AttrName.M_AZI_NAME.value] = geo_array[:, 2]
|
|
138
|
+
|
|
139
|
+
return mdlogname, logs
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _get_roxlog(wlogtypes, wlogrecords, roxlrun, lname): # pragma: no cover
|
|
143
|
+
roxcurve = roxlrun.log_curves[lname]
|
|
144
|
+
tmplog = roxcurve.get_values().astype(np.float64)
|
|
145
|
+
tmplog = npma.filled(tmplog, fill_value=np.nan)
|
|
146
|
+
tmplog[tmplog == -999] = np.nan
|
|
147
|
+
if roxcurve.is_discrete:
|
|
148
|
+
wlogtypes[lname] = _AttrType.DISC.value
|
|
149
|
+
wlogrecords[lname] = roxcurve.get_code_names()
|
|
150
|
+
else:
|
|
151
|
+
wlogtypes[lname] = _AttrType.CONT.value
|
|
152
|
+
wlogrecords[lname] = None
|
|
153
|
+
|
|
154
|
+
return tmplog
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def export_well_roxapi(
|
|
158
|
+
self: Well,
|
|
159
|
+
project,
|
|
160
|
+
wname,
|
|
161
|
+
lognames: str | list[str] = "all",
|
|
162
|
+
logrun: str = "log",
|
|
163
|
+
trajectory: str = "Drilled trajectory",
|
|
164
|
+
realisation: int = 0,
|
|
165
|
+
update_option: Optional[Literal["overwrite", "append"]] = None,
|
|
166
|
+
):
|
|
167
|
+
"""Private function for well export (i.e. store in RMS) from XTGeo to RoxarAPI."""
|
|
168
|
+
logger.debug("Opening RMS project ...")
|
|
169
|
+
|
|
170
|
+
rox = RoxUtils(project, readonly=False)
|
|
171
|
+
|
|
172
|
+
if wname in rox.project.wells:
|
|
173
|
+
_roxapi_update_well(
|
|
174
|
+
self, rox, wname, lognames, logrun, trajectory, realisation, update_option
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
_roxapi_create_well(self, rox, wname, lognames, logrun, trajectory, realisation)
|
|
178
|
+
|
|
179
|
+
if rox._roxexternal:
|
|
180
|
+
rox.project.save()
|
|
181
|
+
|
|
182
|
+
rox.safe_close()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def _store_log_in_roxapi(self, lrun: Any, logname: str) -> None:
|
|
186
|
+
"""Store a single log in RMS / Roxar API for a well"""
|
|
187
|
+
if logname in (self.xname, self.yname, self.zname):
|
|
188
|
+
return
|
|
189
|
+
|
|
190
|
+
isdiscrete = False
|
|
191
|
+
xtglimit = UNDEF_LIMIT
|
|
192
|
+
apply_undef = UNDEF
|
|
193
|
+
if self.wlogtypes[logname] == _AttrType.DISC.value:
|
|
194
|
+
isdiscrete = True
|
|
195
|
+
xtglimit = UNDEF_INT_LIMIT
|
|
196
|
+
apply_undef = UNDEF_INT
|
|
197
|
+
|
|
198
|
+
store_logname = logname
|
|
199
|
+
|
|
200
|
+
# the MD name is applied as default in RMS for measured depth; hence it can be wise
|
|
201
|
+
# to avoid duplicate names here, since the measured depth log is crucial.
|
|
202
|
+
if logname == "MD":
|
|
203
|
+
store_logname = "MD_imported"
|
|
204
|
+
xtg.warn(f"Logname MD is stored as {store_logname}")
|
|
205
|
+
|
|
206
|
+
if isdiscrete:
|
|
207
|
+
thelog = lrun.log_curves.create_discrete(name=store_logname)
|
|
208
|
+
else:
|
|
209
|
+
thelog = lrun.log_curves.create(name=store_logname)
|
|
210
|
+
|
|
211
|
+
values = thelog.generate_values()
|
|
212
|
+
|
|
213
|
+
if values.size != self.get_dataframe(copy=False)[logname].values.size:
|
|
214
|
+
raise ValueError("New logs have different sampling or size, not possible")
|
|
215
|
+
|
|
216
|
+
usedtype = values.dtype
|
|
217
|
+
|
|
218
|
+
vals = np.ma.masked_invalid(self.get_dataframe(copy=False)[logname].values)
|
|
219
|
+
vals = np.ma.masked_greater(vals, xtglimit)
|
|
220
|
+
|
|
221
|
+
# to avoid that Nans behind the masks trigger RuntimeWarning, they are converted to
|
|
222
|
+
# the apply_undef value prior to astype() cast (see issue 1283)
|
|
223
|
+
vals = np.nan_to_num(vals, nan=apply_undef).astype(usedtype)
|
|
224
|
+
thelog.set_values(vals)
|
|
225
|
+
|
|
226
|
+
if isdiscrete:
|
|
227
|
+
# roxarapi requires keys to be ints, while xtgeo can accept any, e.g. strings
|
|
228
|
+
if vals.mask.all():
|
|
229
|
+
codedict = {0: "unset"}
|
|
230
|
+
else:
|
|
231
|
+
codedict = {
|
|
232
|
+
int(key): str(value) for key, value in self.wlogrecords[logname].items()
|
|
233
|
+
}
|
|
234
|
+
thelog.set_code_names(codedict)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def _roxapi_update_well(
|
|
238
|
+
self: Well,
|
|
239
|
+
rox: Any,
|
|
240
|
+
wname: str,
|
|
241
|
+
lognames: str | list[str],
|
|
242
|
+
logrun: str,
|
|
243
|
+
trajectory: str,
|
|
244
|
+
realisation: int,
|
|
245
|
+
update_option: Optional[Literal["overwrite", "append"]] = None,
|
|
246
|
+
):
|
|
247
|
+
"""Assume well is to updated only with logs, new only are appended
|
|
248
|
+
|
|
249
|
+
Also, the length of arrays are not allowed not change (at least not for now).
|
|
250
|
+
|
|
251
|
+
"""
|
|
252
|
+
logger.debug("Key realisation not in use: %s", realisation)
|
|
253
|
+
if update_option not in (None, "overwrite", "append"):
|
|
254
|
+
raise ValueError(
|
|
255
|
+
f"The update_option <{update_option}> is invalid, valid "
|
|
256
|
+
"options are: None | overwrite | append"
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
lrun = rox.project.wells[wname].wellbore.trajectories[trajectory].log_runs[logrun]
|
|
260
|
+
|
|
261
|
+
# find existing lognames in target
|
|
262
|
+
current_logs = [lname.name for lname in lrun.log_curves]
|
|
263
|
+
|
|
264
|
+
uselognames = self.lognames if lognames == "all" else lognames
|
|
265
|
+
|
|
266
|
+
if update_option is None:
|
|
267
|
+
lrun.log_curves.clear() # clear existing logs; all will be replaced
|
|
268
|
+
|
|
269
|
+
for lname in uselognames:
|
|
270
|
+
if update_option == "append" and lname in current_logs:
|
|
271
|
+
continue
|
|
272
|
+
_store_log_in_roxapi(self, lrun, lname)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def _roxapi_create_well(self, rox, wname, lognames, logrun, trajectory, realisation):
|
|
276
|
+
"""Save Well() instance to a new well in RMS.
|
|
277
|
+
|
|
278
|
+
From version 2.15.
|
|
279
|
+
"""
|
|
280
|
+
logger.debug("Key realisation is not supported: %s", realisation)
|
|
281
|
+
|
|
282
|
+
roxwell = rox.project.wells.create(wname)
|
|
283
|
+
roxwell.rkb = self.rkb
|
|
284
|
+
roxwell.wellhead = (self.xpos, self.ypos)
|
|
285
|
+
|
|
286
|
+
traj = roxwell.wellbore.trajectories.create(trajectory)
|
|
287
|
+
|
|
288
|
+
series = traj.survey_point_series
|
|
289
|
+
|
|
290
|
+
dataframe = self.get_dataframe(copy=False)
|
|
291
|
+
east = dataframe[self.xname].values
|
|
292
|
+
north = dataframe[self.yname].values
|
|
293
|
+
tvd = dataframe[self.zname].values
|
|
294
|
+
values = np.array([east, north, tvd]).transpose()
|
|
295
|
+
series.set_points(values)
|
|
296
|
+
|
|
297
|
+
md = series.get_measured_depths_and_points()[:, 0]
|
|
298
|
+
|
|
299
|
+
lrun = traj.log_runs.create(logrun)
|
|
300
|
+
lrun.set_measured_depths(md)
|
|
301
|
+
|
|
302
|
+
uselognames = self.lognames if lognames == "all" else lognames
|
|
303
|
+
for lname in uselognames:
|
|
304
|
+
_store_log_in_roxapi(self, lrun, lname)
|