xtgeo 4.8.0__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.

Potentially problematic release.


This version of xtgeo might be problematic. Click here for more details.

Files changed (117) hide show
  1. cxtgeo.py +582 -0
  2. cxtgeoPYTHON_wrap.c +20938 -0
  3. xtgeo/__init__.py +246 -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 +21 -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 +340 -0
  23. xtgeo/cube/cube1.py +1023 -0
  24. xtgeo/grid3d/__init__.py +15 -0
  25. xtgeo/grid3d/_ecl_grid.py +774 -0
  26. xtgeo/grid3d/_ecl_inte_head.py +148 -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 +266 -0
  32. xtgeo/grid3d/_grdecl_grid.py +388 -0
  33. xtgeo/grid3d/_grid3d.py +29 -0
  34. xtgeo/grid3d/_grid3d_fence.py +181 -0
  35. xtgeo/grid3d/_grid3d_utils.py +228 -0
  36. xtgeo/grid3d/_grid_boundary.py +76 -0
  37. xtgeo/grid3d/_grid_etc1.py +1566 -0
  38. xtgeo/grid3d/_grid_export.py +221 -0
  39. xtgeo/grid3d/_grid_hybrid.py +66 -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 +125 -0
  45. xtgeo/grid3d/_grid_roxapi.py +292 -0
  46. xtgeo/grid3d/_grid_wellzone.py +165 -0
  47. xtgeo/grid3d/_gridprop_export.py +178 -0
  48. xtgeo/grid3d/_gridprop_import_eclrun.py +164 -0
  49. xtgeo/grid3d/_gridprop_import_grdecl.py +130 -0
  50. xtgeo/grid3d/_gridprop_import_roff.py +52 -0
  51. xtgeo/grid3d/_gridprop_import_xtgcpprop.py +168 -0
  52. xtgeo/grid3d/_gridprop_lowlevel.py +171 -0
  53. xtgeo/grid3d/_gridprop_op1.py +174 -0
  54. xtgeo/grid3d/_gridprop_roxapi.py +239 -0
  55. xtgeo/grid3d/_gridprop_value_init.py +140 -0
  56. xtgeo/grid3d/_gridprops_import_eclrun.py +344 -0
  57. xtgeo/grid3d/_gridprops_import_roff.py +83 -0
  58. xtgeo/grid3d/_roff_grid.py +469 -0
  59. xtgeo/grid3d/_roff_parameter.py +303 -0
  60. xtgeo/grid3d/grid.py +2537 -0
  61. xtgeo/grid3d/grid_properties.py +699 -0
  62. xtgeo/grid3d/grid_property.py +1341 -0
  63. xtgeo/grid3d/types.py +15 -0
  64. xtgeo/io/__init__.py +1 -0
  65. xtgeo/io/_file.py +592 -0
  66. xtgeo/metadata/__init__.py +17 -0
  67. xtgeo/metadata/metadata.py +431 -0
  68. xtgeo/roxutils/__init__.py +7 -0
  69. xtgeo/roxutils/_roxar_loader.py +54 -0
  70. xtgeo/roxutils/_roxutils_etc.py +122 -0
  71. xtgeo/roxutils/roxutils.py +207 -0
  72. xtgeo/surface/__init__.py +18 -0
  73. xtgeo/surface/_regsurf_boundary.py +26 -0
  74. xtgeo/surface/_regsurf_cube.py +210 -0
  75. xtgeo/surface/_regsurf_cube_window.py +391 -0
  76. xtgeo/surface/_regsurf_cube_window_v2.py +297 -0
  77. xtgeo/surface/_regsurf_cube_window_v3.py +360 -0
  78. xtgeo/surface/_regsurf_export.py +388 -0
  79. xtgeo/surface/_regsurf_grid3d.py +271 -0
  80. xtgeo/surface/_regsurf_gridding.py +347 -0
  81. xtgeo/surface/_regsurf_ijxyz_parser.py +278 -0
  82. xtgeo/surface/_regsurf_import.py +347 -0
  83. xtgeo/surface/_regsurf_lowlevel.py +122 -0
  84. xtgeo/surface/_regsurf_oper.py +631 -0
  85. xtgeo/surface/_regsurf_roxapi.py +241 -0
  86. xtgeo/surface/_regsurf_utils.py +81 -0
  87. xtgeo/surface/_surfs_import.py +43 -0
  88. xtgeo/surface/_zmap_parser.py +138 -0
  89. xtgeo/surface/regular_surface.py +2967 -0
  90. xtgeo/surface/surfaces.py +276 -0
  91. xtgeo/well/__init__.py +24 -0
  92. xtgeo/well/_blockedwell_roxapi.py +221 -0
  93. xtgeo/well/_blockedwells_roxapi.py +68 -0
  94. xtgeo/well/_well_aux.py +30 -0
  95. xtgeo/well/_well_io.py +327 -0
  96. xtgeo/well/_well_oper.py +574 -0
  97. xtgeo/well/_well_roxapi.py +304 -0
  98. xtgeo/well/_wellmarkers.py +486 -0
  99. xtgeo/well/_wells_utils.py +158 -0
  100. xtgeo/well/blocked_well.py +216 -0
  101. xtgeo/well/blocked_wells.py +122 -0
  102. xtgeo/well/well1.py +1514 -0
  103. xtgeo/well/wells.py +211 -0
  104. xtgeo/xyz/__init__.py +6 -0
  105. xtgeo/xyz/_polygons_oper.py +272 -0
  106. xtgeo/xyz/_xyz.py +741 -0
  107. xtgeo/xyz/_xyz_data.py +646 -0
  108. xtgeo/xyz/_xyz_io.py +490 -0
  109. xtgeo/xyz/_xyz_lowlevel.py +42 -0
  110. xtgeo/xyz/_xyz_oper.py +613 -0
  111. xtgeo/xyz/_xyz_roxapi.py +766 -0
  112. xtgeo/xyz/points.py +681 -0
  113. xtgeo/xyz/polygons.py +811 -0
  114. xtgeo-4.8.0.dist-info/METADATA +145 -0
  115. xtgeo-4.8.0.dist-info/RECORD +117 -0
  116. xtgeo-4.8.0.dist-info/WHEEL +5 -0
  117. xtgeo-4.8.0.dist-info/licenses/LICENSE.md +165 -0
xtgeo/xyz/points.py ADDED
@@ -0,0 +1,681 @@
1
+ """The XTGeo xyz.points module, which contains the Points class."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import warnings
6
+ from copy import deepcopy
7
+ from typing import TYPE_CHECKING
8
+
9
+ import numpy as np
10
+ import pandas as pd
11
+
12
+ from xtgeo.common._xyz_enum import _AttrName, _XYZType
13
+ from xtgeo.common.exceptions import InvalidFileFormatError
14
+ from xtgeo.common.log import null_logger
15
+ from xtgeo.common.sys import inherit_docstring
16
+ from xtgeo.io._file import FileFormat, FileWrapper
17
+ from xtgeo.xyz import XYZ, _xyz_io, _xyz_oper, _xyz_roxapi
18
+
19
+ if TYPE_CHECKING:
20
+ import io
21
+ import pathlib
22
+
23
+ from xtgeo.well import Well
24
+
25
+ logger = null_logger(__name__)
26
+
27
+
28
+ def _data_reader_factory(file_format: FileFormat):
29
+ if file_format == FileFormat.XYZ:
30
+ return _xyz_io.import_xyz
31
+ if file_format == FileFormat.ZMAP_ASCII:
32
+ return _xyz_io.import_zmap
33
+ if file_format == FileFormat.RMS_ATTR:
34
+ return _xyz_io.import_rms_attr
35
+
36
+ extensions = FileFormat.extensions_string(
37
+ [FileFormat.XYZ, FileFormat.ZMAP_ASCII, FileFormat.RMS_ATTR]
38
+ )
39
+ raise InvalidFileFormatError(
40
+ f"File format {file_format} is invalid for type Points. "
41
+ f"Supported formats are {extensions}."
42
+ )
43
+
44
+
45
+ def _file_importer(
46
+ points_file: str | pathlib.Path | io.BytesIO,
47
+ fformat: str | None = None,
48
+ ):
49
+ """General function for points_from_file"""
50
+ pfile = FileWrapper(points_file)
51
+ fmt = pfile.fileformat(fformat)
52
+ kwargs = _data_reader_factory(fmt)(pfile)
53
+ kwargs["values"].dropna(inplace=True)
54
+ kwargs["filesrc"] = pfile.name
55
+ return kwargs
56
+
57
+
58
+ def _surface_importer(surf, zname=_AttrName.ZNAME.value):
59
+ """General function for _read_surface()"""
60
+ val = surf.values
61
+ xc, yc = surf.get_xy_values()
62
+
63
+ coord = []
64
+ for vv in [xc, yc, val]:
65
+ vv = np.ma.filled(vv.flatten(order="C"), fill_value=np.nan)
66
+ vv = vv[~np.isnan(vv)]
67
+ coord.append(vv)
68
+
69
+ return {
70
+ "values": pd.DataFrame(
71
+ {
72
+ _AttrName.XNAME.value: coord[0],
73
+ _AttrName.YNAME.value: coord[1],
74
+ zname: coord[2],
75
+ }
76
+ ),
77
+ "zname": zname,
78
+ }
79
+
80
+
81
+ def _roxar_importer(
82
+ project,
83
+ name: str,
84
+ category: str,
85
+ stype: str = "horizons",
86
+ realisation: int = 0,
87
+ attributes: bool | list[str] = False,
88
+ ):
89
+ return _xyz_roxapi.load_xyz_from_rms(
90
+ project, name, category, stype, realisation, attributes, _XYZType.POINTS.value
91
+ )
92
+
93
+
94
+ def _wells_importer(
95
+ wells: list[Well],
96
+ tops: bool = True,
97
+ incl_limit: float | None = None,
98
+ top_prefix: str = "Top",
99
+ zonelist: list | None = None,
100
+ use_undef: bool = False,
101
+ ) -> dict:
102
+ """General function importing from wells"""
103
+ dflist = []
104
+ for well in wells:
105
+ wp = well.get_zonation_points(
106
+ tops=tops,
107
+ incl_limit=incl_limit,
108
+ top_prefix=top_prefix,
109
+ zonelist=zonelist,
110
+ use_undef=use_undef,
111
+ )
112
+
113
+ if wp is not None:
114
+ dflist.append(wp)
115
+
116
+ dfr = pd.concat(dflist, ignore_index=True)
117
+
118
+ attrs = {}
119
+ for col in dfr.columns:
120
+ col_lower = col.lower()
121
+ if "float" in dfr[col].dtype.name:
122
+ attrs[col] = "float"
123
+ elif "int" in dfr[col].dtype.name:
124
+ attrs[col] = "int"
125
+ else: # usually 'object'
126
+ if col_lower == "zone":
127
+ attrs[col] = "int"
128
+ elif "name" in col_lower:
129
+ attrs[col] = "str"
130
+ else:
131
+ attrs[col] = "float" # fall-back
132
+
133
+ return {"values": dfr, "attributes": attrs}
134
+
135
+
136
+ def _wells_dfrac_importer(
137
+ wells: list[Well],
138
+ dlogname: str,
139
+ dcodes: list[int],
140
+ incl_limit: float = 90,
141
+ count_limit: int = 3,
142
+ zonelist: list = None,
143
+ zonelogname: str = None,
144
+ ) -> dict:
145
+ """General function, get fraction of discrete code(s) e.g. facies per zone."""
146
+
147
+ dflist = []
148
+ for well in wells:
149
+ wpf = well.get_fraction_per_zone(
150
+ dlogname,
151
+ dcodes,
152
+ zonelist=zonelist,
153
+ incl_limit=incl_limit,
154
+ count_limit=count_limit,
155
+ zonelogname=zonelogname,
156
+ )
157
+
158
+ if wpf is not None:
159
+ dflist.append(wpf)
160
+
161
+ dfr = pd.concat(dflist, ignore_index=True)
162
+
163
+ attrs = {}
164
+ for col in dfr.columns[3:]:
165
+ col_lower = col.lower()
166
+ if col_lower == "zone":
167
+ attrs[col] = "int"
168
+ elif col_lower == "zonename" or col_lower == "wellname":
169
+ attrs[col] = "str"
170
+ else:
171
+ attrs[col] = "float"
172
+
173
+ return {
174
+ "values": dfr,
175
+ "attributes": attrs,
176
+ "zname": "DFRAC",
177
+ }
178
+
179
+
180
+ def points_from_file(pfile: str | pathlib.Path, fformat: str | None = "guess"):
181
+ """Make an instance of a Points object directly from file import.
182
+
183
+ Supported formats are:
184
+
185
+ * 'xyz' or 'poi' or 'pol': Simple XYZ format
186
+ * 'zmap': ZMAP line format as exported from RMS (e.g. fault lines)
187
+ * 'rms_attr': RMS points formats with attributes (extra columns)
188
+ * 'guess': Try to choose file format based on extension
189
+
190
+
191
+ Args:
192
+ pfile: Name of file or pathlib object.
193
+ fformat: File format, xyz/pol/... Default is `guess` where file
194
+ extension or file signature is parsed to guess the correct format.
195
+
196
+ Example::
197
+
198
+ import xtgeo
199
+ mypoints = xtgeo.points_from_file('somefile.xyz')
200
+ """
201
+ return Points(**_file_importer(pfile, fformat=fformat))
202
+
203
+
204
+ def points_from_roxar(
205
+ project,
206
+ name: str,
207
+ category: str,
208
+ stype: str = "horizons",
209
+ realisation: int = 0,
210
+ attributes: bool | list[str] = False,
211
+ ):
212
+ """Load a Points instance from Roxar RMS project.
213
+
214
+ The import from the RMS project can be done either within the project
215
+ or outside the project.
216
+
217
+ Note also that horizon/zone/faults name and category must exists
218
+ in advance, otherwise an Exception will be raised.
219
+
220
+ Args:
221
+ project: Name of project (as folder) if outside RMS, or just use the
222
+ magic `project` word if within RMS.
223
+ name (str): Name of points item, or name of well pick set if
224
+ well picks.
225
+ category: For horizons/zones/faults: for example 'DL_depth'
226
+ or use a folder notation on clipboard/general2d_data.
227
+ For well picks it is the well pick type: 'horizon' or 'fault'.
228
+ stype: RMS folder type, 'horizons' (default), 'zones', 'clipboard',
229
+ 'general2d_data', 'faults' or 'well_picks'
230
+ realisation: Realisation number, default is 0
231
+ attributes (bool): Bool or list with attribute names to collect.
232
+ If True, all attributes are collected.
233
+
234
+ Example::
235
+
236
+ # inside RMS:
237
+ import xtgeo
238
+ mypoints = xtgeo.points_from_roxar(project, 'TopEtive', 'DP_seismic')
239
+
240
+ .. versionadded:: 2.19 general2d_data support is added
241
+ """
242
+
243
+ return Points(
244
+ **_roxar_importer(
245
+ project,
246
+ name,
247
+ category,
248
+ stype,
249
+ realisation,
250
+ attributes,
251
+ )
252
+ )
253
+
254
+
255
+ def points_from_surface(
256
+ regular_surface,
257
+ zname: str = _AttrName.ZNAME.value,
258
+ ):
259
+ """This makes an instance of a Points directly from a RegularSurface object.
260
+
261
+ Each surface node will be stored as a X Y Z point.
262
+
263
+ Args:
264
+ regular_surface: XTGeo RegularSurface() instance
265
+ zname: Name of third column
266
+
267
+ .. versionadded:: 2.16
268
+ Replaces the from_surface() method.
269
+ """
270
+
271
+ return Points(**_surface_importer(regular_surface, zname=zname))
272
+
273
+
274
+ def points_from_wells(
275
+ wells: list[Well],
276
+ tops: bool = True,
277
+ incl_limit: float | None = None,
278
+ top_prefix: str = "Top",
279
+ zonelist: list | None = None,
280
+ use_undef: bool = False,
281
+ ):
282
+ """Get tops or zone points data from a list of wells.
283
+
284
+ Args:
285
+ wells: List of XTGeo well objects.
286
+ If a list of well files, the routine will try to load well based on file
287
+ signature and/or extension, but only default settings are applied. Hence
288
+ this is less flexible and more fragile.
289
+ tops: Get the tops if True (default), otherwise zone.
290
+ incl_limit: Inclination limit for zones (thickness points)
291
+ top_prefix: Prefix used for Tops.
292
+ zonelist: Which zone numbers to apply, None means all.
293
+ use_undef: If True, then transition from UNDEF is also used.
294
+
295
+ Returns:
296
+ None if empty data, otherwise a Points() instance.
297
+
298
+ Example::
299
+
300
+ wells = [xtgeo.well_from_file("w1.w"), xtgeo.well_from_file("w2.w")]
301
+ points = xtgeo.points_from_wells(wells)
302
+ """
303
+ return Points(
304
+ **_wells_importer(wells, tops, incl_limit, top_prefix, zonelist, use_undef)
305
+ )
306
+
307
+
308
+ def points_from_wells_dfrac(
309
+ wells: list[Well],
310
+ dlogname: str,
311
+ dcodes: list[int],
312
+ incl_limit: float = 90,
313
+ count_limit: int = 3,
314
+ zonelist: list | None = None,
315
+ zonelogname: str | None = None,
316
+ ):
317
+ """Get fraction of discrete code(s) e.g. facies per zone.
318
+
319
+ Args:
320
+ wells: List of XTGeo well objects.
321
+ If a list of file names, the routine will try to load well based on file
322
+ signature and/or extension, but only default settings are applied. Hence
323
+ this is less flexible and more fragile.
324
+ dlogname: Name of discrete log (e.g. Facies)
325
+ dcodes: Code(s) to get fraction for, e.g. [3]
326
+ incl_limit: Inclination limit for zones (thickness points)
327
+ count_limit: Min. no of counts per segment for valid result
328
+ zonelist: Which zone numbers to apply, default None means all.
329
+ zonelogname: If None, the zonelogname property in the well object will be
330
+ applied. This option is particualr useful if one uses wells directly from
331
+ files.
332
+
333
+ Returns:
334
+ None if empty data, otherwise a Points() instance.
335
+
336
+ Example::
337
+
338
+ wells = [xtgeo.well_from_file("w1.w"), xtgeo.well_from_file("w2.w")]
339
+ points = xtgeo.points_from_wells_dfrac(
340
+ wells, dlogname="Facies", dcodes=[4], zonelogname="ZONELOG"
341
+ )
342
+ """
343
+ return Points(
344
+ **_wells_dfrac_importer(
345
+ wells, dlogname, dcodes, incl_limit, count_limit, zonelist, zonelogname
346
+ )
347
+ )
348
+
349
+
350
+ def _generate_docstring_points(xname, yname, zname):
351
+ """In order to have dynamic naming of xname, yname, etc"""
352
+ return f"""
353
+ Class for Points data in XTGeo.
354
+
355
+ The Points class is a subclass of the :py:class:`~xtgeo.xyz._xyz.XYZ` abstract
356
+ class, and the point set itself is a `pandas <http://pandas.pydata.org>`_
357
+ dataframe object.
358
+
359
+ For points, 3 float columns (X Y Z) are mandatory. In addition it is possible to
360
+ have addiotional points attribute columns, and such attributes may be integer,
361
+ strings or floats.
362
+
363
+ The instance can be made either from file (then as classmethod), from another
364
+ object or by a spesification, e.g. from file or a surface::
365
+
366
+ xp1 = xtgeo.points_from_file('somefilename', fformat='xyz')
367
+ # or
368
+ regsurf = xtgeo.surface_from_file("somefile.gri")
369
+ xp2 = xtgeo.points_from_surface(regsurf)
370
+
371
+ You can also initialise points from list of tuples/lists in Python, where
372
+ each tuple is a (X, Y, Z) coordinate::
373
+
374
+ plist = [(234, 556, 12), (235, 559, 14), (255, 577, 12)]
375
+ mypoints = Points(values=plist)
376
+
377
+ The tuples can also contain point attributes which needs spesification via
378
+ an attributes dictionary::
379
+
380
+ plist = [
381
+ (234, 556, 12, "Well1", 22),
382
+ (235, 559, 14, "Well2", 44),
383
+ (255, 577, 12, "Well3", 55)]
384
+ attrs = {{"WellName": "str", "ID": "int"}}
385
+ mypoints = Points(values=plist, attributes=attrs)
386
+
387
+ And points can be initialised from a 2D numpy array or an existing dataframe::
388
+
389
+ >>> mypoints1 = Points(values=[(1,1,1), (2,2,2), (3,3,3)])
390
+ >>> mypoints2 = Points(
391
+ ... values=pd.DataFrame(
392
+ ... [[1, 2, 3], [1, 2, 3], [1, 2, 3]],
393
+ ... columns=["{xname}", "{yname}", "{zname}"]
394
+ ... )
395
+ ... )
396
+
397
+
398
+ Similar as for lists, attributes are alse possible for numpy and dataframes.
399
+
400
+ Default column names in the dataframe:
401
+
402
+ * {xname}: UTM X coordinate as self._xname
403
+ * {yname}: UTM Y coordinate as self._yname
404
+ * {zname}: Z coordinate, often depth below TVD SS, but may also be
405
+ something else! Use zname attribute to change name.
406
+
407
+ Note:
408
+ Attributes may have undefined entries. Pandas version 0.21 (which is applied
409
+ for RMS version up to 12.0.x) do not support NaN values for Integers. The
410
+ solution is store undefined values as large numbers, xtgeo.UNDEF_INT
411
+ (2000000000) for integers and xtgeo.UNDEF (10e32) for float values.
412
+ This will change from xtgeo version 3.x where Pandas version 1 and
413
+ above will be required, which in turn support will pandas.NA
414
+ entries.
415
+
416
+ Args:
417
+ values: Provide input values on various forms (list-like or dataframe).
418
+ xname: Name of first (X) mandatory column
419
+ yname: Name of second (Y) mandatory column
420
+ zname: Name of third (Z) mandatory column
421
+ attributes: A dictionary for attribute columns as 'name: type', e.g.
422
+ {{"WellName": "str", "IX": "int"}}. This is applied when values are input
423
+ and is to name and type the extra attribute columns in a point set.
424
+ """
425
+
426
+
427
+ class Points(XYZ):
428
+ __doc__ = _generate_docstring_points(
429
+ _AttrName.XNAME.value, _AttrName.YNAME.value, _AttrName.ZNAME.value
430
+ )
431
+
432
+ def __init__(
433
+ self,
434
+ values: list | np.ndarray | pd.DataFrame = None,
435
+ xname: str = _AttrName.XNAME.value,
436
+ yname: str = _AttrName.YNAME.value,
437
+ zname: str = _AttrName.ZNAME.value,
438
+ attributes: dict | None = None,
439
+ filesrc: str = None,
440
+ ):
441
+ """Initialisation of Points()."""
442
+ self._xyztype = _XYZType.POINTS.value
443
+
444
+ super().__init__(self._xyztype, xname, yname, zname)
445
+
446
+ if values is None:
447
+ values = []
448
+
449
+ self._attrs = attributes if attributes is not None else {}
450
+ self._filesrc = filesrc
451
+
452
+ if not isinstance(values, pd.DataFrame):
453
+ self._df = _xyz_io._from_list_like(
454
+ values, self._zname, attributes, self._xyztype
455
+ )
456
+ else:
457
+ self._df: pd.DataFrame = values
458
+ self._dataframe_consistency_check()
459
+
460
+ def __repr__(self):
461
+ # should be able to newobject = eval(repr(thisobject))
462
+ return f"{self.__class__.__name__} (filesrc={self._filesrc!r}, ID={id(self)})"
463
+
464
+ def __str__(self):
465
+ """User friendly print."""
466
+ return self.describe(flush=False)
467
+
468
+ def __eq__(self, value):
469
+ """Magic method for ==."""
470
+ return self.get_dataframe(copy=False)[self.zname] == value
471
+
472
+ def __gt__(self, value):
473
+ return self.get_dataframe(copy=False)[self.zname] > value
474
+
475
+ def __ge__(self, value):
476
+ return self.get_dataframe(copy=False)[self.zname] >= value
477
+
478
+ def __lt__(self, value):
479
+ return self.get_dataframe(copy=False)[self.zname] < value
480
+
481
+ def __le__(self, value):
482
+ return self.get_dataframe(copy=False)[self.zname] <= value
483
+
484
+ # ----------------------------------------------------------------------------------
485
+ # Methods
486
+ # ----------------------------------------------------------------------------------
487
+
488
+ @property
489
+ def dataframe(self) -> pd.DataFrame:
490
+ """Returns or set the Pandas dataframe object."""
491
+ warnings.warn(
492
+ "Direct access to the dataframe property in Points class will be "
493
+ "deprecated in xtgeo 5.0. Use `get_dataframe()` instead.",
494
+ PendingDeprecationWarning,
495
+ )
496
+ return self._df
497
+
498
+ @dataframe.setter
499
+ def dataframe(self, df):
500
+ warnings.warn(
501
+ "Direct access to the dataframe property in Points class will be "
502
+ "deprecated in xtgeo 5.0. Use `set_dataframe(df)` instead.",
503
+ PendingDeprecationWarning,
504
+ )
505
+ self.set_dataframe(df)
506
+
507
+ def get_dataframe(self, copy: bool = True) -> pd.DataFrame:
508
+ """Returns the Pandas dataframe object.
509
+
510
+ Args:
511
+ copy: If True (default) the a deep copy is returned; otherwise a view
512
+ which may be faster in some cases)
513
+
514
+ .. versionchanged:: 3.7 Add keyword `copy`, defaulted to True
515
+
516
+ """
517
+ return self._df.copy() if copy else self._df
518
+
519
+ def set_dataframe(self, df):
520
+ self._df = df.apply(deepcopy)
521
+
522
+ def _random(self, nrandom=10):
523
+ """Generate nrandom random points within the range 0..1
524
+
525
+ Args:
526
+ nrandom (int): Number of random points (default 10)
527
+
528
+ .. versionadded:: 2.3
529
+ """
530
+
531
+ # currently a non-published method
532
+
533
+ self._df = pd.DataFrame(
534
+ np.random.rand(nrandom, 3), columns=[self._xname, self._yname, self._zname]
535
+ )
536
+
537
+ def to_file(
538
+ self,
539
+ pfile,
540
+ fformat="xyz",
541
+ attributes=True,
542
+ pfilter=None,
543
+ wcolumn=None,
544
+ hcolumn=None,
545
+ mdcolumn="M_MDEPTH",
546
+ **kwargs,
547
+ ):
548
+ """Export Points to file.
549
+
550
+ Args:
551
+ pfile (str): Name of file
552
+ fformat (str): File format xyz/poi/pol or rms_attr
553
+ attributes (bool or list): List of extra columns to export (some formats)
554
+ or True for all attributes present
555
+ pfilter (dict): Filter on e.g. top name(s) with keys TopName
556
+ or ZoneName as {'TopName': ['Top1', 'Top2']}.
557
+ wcolumn (str): Name of well column (rms_wellpicks format only)
558
+ hcolumn (str): Name of horizons column (rms_wellpicks format only)
559
+ mdcolumn (str): Name of MD column (rms_wellpicks format only)
560
+
561
+ Returns:
562
+ Number of points exported
563
+
564
+ Note that the rms_wellpicks will try to output to:
565
+
566
+ * HorizonName, WellName, MD if a MD (mdcolumn) is present,
567
+ * HorizonName, WellName, X, Y, Z otherwise
568
+
569
+ Note:
570
+ For backward compatibility, the key ``filter`` can be applied instead of
571
+ ``pfilter``.
572
+
573
+ Raises:
574
+ KeyError if pfilter is set and key(s) are invalid
575
+
576
+ """
577
+ return _xyz_io.to_file(
578
+ self,
579
+ pfile,
580
+ fformat=fformat,
581
+ attributes=attributes,
582
+ pfilter=pfilter,
583
+ wcolumn=wcolumn,
584
+ hcolumn=hcolumn,
585
+ mdcolumn=mdcolumn,
586
+ **kwargs,
587
+ )
588
+
589
+ def to_roxar(
590
+ self,
591
+ project,
592
+ name,
593
+ category,
594
+ stype="horizons",
595
+ pfilter=None,
596
+ realisation=0,
597
+ attributes=False,
598
+ ): # pragma: no cover
599
+ """Export (store) a Points item to a Roxar RMS project.
600
+
601
+ The export to the RMS project can be done either within the project
602
+ or outside the project.
603
+
604
+ Note also that horizon/zone name and category must exists in advance,
605
+ otherwise an Exception will be raised.
606
+
607
+ Note:
608
+ When project is file path (direct access, outside RMS) then
609
+ ``to_roxar()`` will implicitly do a project save. Otherwise, the project
610
+ will not be saved until the user do an explicit project save action.
611
+
612
+ Args:
613
+ project (str or special): Name of project (as folder) if
614
+ outside RMS, og just use the magic project word if within RMS.
615
+ name (str): Name of points item, or name of well pick set if
616
+ well picks.
617
+ category (str): For horizons/zones/faults: for example 'DL_depth'
618
+ or use a folder notation on clipboard/general2d_data.
619
+ For well picks it is the well pick type: "horizon" or "fault".
620
+ pfilter (dict): Filter on e.g. top name(s) with keys TopName
621
+ or ZoneName as {'TopName': ['Top1', 'Top2']}
622
+ stype: RMS folder type, 'horizons' (default), 'zones', 'clipboard',
623
+ 'general2d_data', 'faults' or 'well_picks'
624
+ realisation (int): Realisation number, default is 0
625
+ attributes (bool): If True, attributes will be preserved (from RMS 11)
626
+
627
+ Raises:
628
+ ValueError: Various types of invalid inputs.
629
+ NotImplementedError: Not supported in this ROXAPI version
630
+
631
+ .. versionadded:: 2.19 general2d_data support is added
632
+ """
633
+
634
+ _xyz_roxapi.save_xyz_to_rms(
635
+ self,
636
+ project,
637
+ name,
638
+ category,
639
+ stype,
640
+ pfilter,
641
+ realisation,
642
+ attributes,
643
+ )
644
+
645
+ def copy(self):
646
+ """Returns a deep copy of an instance."""
647
+ mycopy = self.__class__()
648
+ mycopy._xyztype = self._xyztype
649
+ mycopy._df = self._df.apply(deepcopy)
650
+ mycopy._xname = self._xname
651
+ mycopy._yname = self._yname
652
+ mycopy._zname = self._zname
653
+
654
+ if self._attrs:
655
+ mycopy._attrs = dict(self._attrs.items())
656
+
657
+ return mycopy
658
+
659
+ def snap_surface(self, surf, activeonly=True):
660
+ """Snap (transfer) the points Z values to a RegularSurface
661
+
662
+ Args:
663
+ surf (~xtgeo.surface.regular_surface.RegularSurface): Surface to snap to.
664
+ activeonly (bool): If True (default), the points outside the defined surface
665
+ will be removed. If False, these points will keep the original values.
666
+
667
+ Returns:
668
+ None (instance is updated inplace)
669
+
670
+ Raises:
671
+ ValueError: Input object of wrong data type, must be RegularSurface
672
+ RuntimeError: Error code from C routine surf_get_zv_from_xyv is ...
673
+
674
+ .. versionadded:: 2.1
675
+
676
+ """
677
+ _xyz_oper.snap_surface(self, surf, activeonly=activeonly)
678
+
679
+ @inherit_docstring(inherit_from=XYZ.get_boundary)
680
+ def get_boundary(self):
681
+ return super().get_boundary()