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,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)