xtgeo 4.8.0__cp313-cp313-macosx_11_0_arm64.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.cpython-313-darwin.so +0 -0
  5. xtgeo/_internal.cpython-313-darwin.so +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 +6 -0
  117. xtgeo-4.8.0.dist-info/licenses/LICENSE.md +165 -0
@@ -0,0 +1,221 @@
1
+ from __future__ import annotations
2
+
3
+ import io
4
+ import json
5
+ import struct
6
+ from contextlib import ExitStack
7
+ from copy import deepcopy
8
+ from typing import IO, TYPE_CHECKING, Any, Literal
9
+
10
+ import h5py
11
+ import hdf5plugin
12
+ import roffio
13
+
14
+ from xtgeo.common import null_logger
15
+
16
+ from ._egrid import EGrid
17
+ from ._grdecl_grid import GrdeclGrid
18
+ from ._roff_grid import RoffGrid
19
+
20
+ logger = null_logger(__name__)
21
+
22
+ if TYPE_CHECKING:
23
+ import numpy as np
24
+
25
+ from xtgeo.common.types import FileLike
26
+ from xtgeo.io._file import FileWrapper
27
+ from xtgeo.metadata.metata import MetaData
28
+
29
+ from .grid import Grid
30
+
31
+ # valid byte settings for xtgeo/hdf5 based export e.g. 441 means
32
+ # 4byte float for coord, 4byte float for zcorn, and 1 byte Int for actnums.
33
+ # Native XTGeo is 844
34
+ VALIDXTGFMT = (221, 421, 441, 444, 841, 844, 881, 884)
35
+
36
+
37
+ def export_roff(
38
+ grid: Grid, gfile: FileLike, roff_format: Literal["ascii", "binary"] = "binary"
39
+ ) -> None:
40
+ """Export grid to ROFF format."""
41
+ if roff_format == "binary":
42
+ RoffGrid.from_xtgeo_grid(grid).to_file(gfile, roff_format=roffio.Format.BINARY)
43
+ elif roff_format == "ascii":
44
+ RoffGrid.from_xtgeo_grid(grid).to_file(gfile, roff_format=roffio.Format.ASCII)
45
+ else:
46
+ raise ValueError(
47
+ "Incorrect format specifier in export_roff,"
48
+ f" expected 'binary' or 'ascii, got {roff_format}"
49
+ )
50
+
51
+
52
+ def export_grdecl(grid: Grid, gfile: FileLike, mode: int) -> None:
53
+ """Export grid to Eclipse GRDECL format (ascii, mode=1) or binary (mode=0)."""
54
+ fileformat = "grdecl" if mode == 1 else "bgrdecl"
55
+ GrdeclGrid.from_xtgeo_grid(grid).to_file(gfile, fileformat=fileformat)
56
+
57
+
58
+ def export_egrid(grid: Grid, gfile: FileLike) -> None:
59
+ """Export grid to Eclipse EGRID format, binary."""
60
+ EGrid.from_xtgeo_grid(grid).to_file(gfile, fileformat="egrid")
61
+
62
+
63
+ def export_fegrid(grid: Grid, gfile: FileLike) -> None:
64
+ """Export grid to Eclipse FEGRID format, ascii."""
65
+ EGrid.from_xtgeo_grid(grid).to_file(gfile, fileformat="fegrid")
66
+
67
+
68
+ def export_xtgcpgeom(grid: Grid, gfile: FileWrapper, subformat: int = 844) -> None:
69
+ """Export grid to binary XTGeo xtgcpgeom format, in prep. and experimental."""
70
+ logger.info("Export to native binary xtgeo...")
71
+
72
+ grid._xtgformat2()
73
+ logger.info("Export to native binary xtgeo...(2)")
74
+
75
+ grid.metadata.required = grid
76
+ meta = grid.metadata.get_metadata()
77
+
78
+ # subformat processing, indicating number of bytes per datatype
79
+ # here, 844 is native XTGeo (float64, float32, int32)
80
+ dtypecoo, dtypezco, dtypeact, meta = _define_dtypes(grid, subformat, meta)
81
+
82
+ coordsv, zcornsv, actnumsv = _transform_vectors(
83
+ grid, meta, dtypecoo, dtypezco, dtypeact
84
+ )
85
+
86
+ prevalues = (1, 1301, int(subformat), grid.ncol, grid.nrow, grid.nlay)
87
+ mystruct = struct.Struct("= i i i q q q")
88
+ hdr = mystruct.pack(*prevalues)
89
+
90
+ # Convert StringIO to BytesIO as this is a binary format
91
+ with ExitStack() as stack:
92
+ if isinstance(gfile.file, io.StringIO):
93
+ data = gfile.file.getvalue().encode("utf-8")
94
+ fout: IO[Any] = io.BytesIO(data)
95
+ elif isinstance(gfile.file, io.BytesIO):
96
+ fout = gfile.file
97
+ else:
98
+ fout = stack.enter_context(open(gfile.file, "wb"))
99
+ fout.write(hdr)
100
+ coordsv.tofile(fout)
101
+ zcornsv.tofile(fout)
102
+ actnumsv.tofile(fout)
103
+ fout.write("\nXTGMETA.v01\n".encode())
104
+ fout.write(json.dumps(meta).encode())
105
+
106
+ logger.info("Export to native binary xtgeo... done!")
107
+
108
+
109
+ def export_hdf5_cpgeom(
110
+ grid: Grid,
111
+ gfile: FileWrapper,
112
+ compression: Literal["blosc"] | None = None,
113
+ chunks: bool = False,
114
+ subformat: int = 844,
115
+ ) -> None:
116
+ """Export grid to h5/hdf5, in prep. and experimental."""
117
+ grid._xtgformat2()
118
+
119
+ logger.debug("Export to hdf5 xtgeo layout...")
120
+
121
+ grid.metadata.required = grid
122
+ meta = grid.metadata.get_metadata()
123
+
124
+ if compression == "blosc":
125
+ compression = hdf5plugin.Blosc(
126
+ cname="blosclz", clevel=9, shuffle=hdf5plugin.Blosc.SHUFFLE
127
+ )
128
+
129
+ dtypecoo, dtypezco, dtypeact, meta = _define_dtypes(grid, subformat, meta)
130
+ coordsv, zcornsv, actnumsv = _transform_vectors(
131
+ grid, meta, dtypecoo, dtypezco, dtypeact
132
+ )
133
+ jmeta = json.dumps(meta).encode()
134
+
135
+ with h5py.File(gfile.name, "w") as fh5:
136
+ grp = fh5.create_group("CornerPointGeometry")
137
+ grp.create_dataset(
138
+ "coord",
139
+ data=coordsv,
140
+ compression=compression,
141
+ chunks=chunks or None,
142
+ )
143
+ grp.create_dataset(
144
+ "zcorn",
145
+ data=zcornsv,
146
+ compression=compression,
147
+ chunks=chunks or None,
148
+ )
149
+ grp.create_dataset(
150
+ "actnum",
151
+ data=actnumsv,
152
+ compression=compression,
153
+ chunks=chunks or None,
154
+ )
155
+
156
+ grp.attrs["metadata"] = jmeta
157
+ grp.attrs["provider"] = "xtgeo"
158
+ grp.attrs["format-idcode"] = 1301
159
+
160
+ logger.debug("Export to hdf5 xtgeo layout... done!")
161
+
162
+
163
+ def _define_dtypes(grid: Grid, fmt: int, meta: MetaData) -> tuple[str, str, str, str]:
164
+ # subformat processing, indicating number of bytes per datatype
165
+ # here, 844 is native XTGeo (float64, float32, int32)
166
+ logger.debug("Define dtypes...")
167
+
168
+ newmeta = deepcopy(meta)
169
+
170
+ if int(fmt) not in VALIDXTGFMT:
171
+ raise ValueError(f"The subformat value is not valid, must be in: {VALIDXTGFMT}")
172
+
173
+ if fmt <= 444:
174
+ # the float() is for JSON serialization which cannot handle float32
175
+ newmeta["_required_"]["xshift"] = float(grid._coordsv[:, :, 0::3].mean())
176
+ newmeta["_required_"]["yshift"] = float(grid._coordsv[:, :, 1::3].mean())
177
+ newmeta["_required_"]["zshift"] = float(grid._zcornsv.mean())
178
+
179
+ nbytecoord, nbytezcorn, nbyteactnum = [int(nbyte) for nbyte in str(fmt)]
180
+
181
+ dtype_coord = "float" + str(nbytecoord * 8)
182
+ dtype_zcorn = "float" + str(nbytezcorn * 8)
183
+ dtype_actnum = "int" + str(nbyteactnum * 8)
184
+
185
+ logger.debug("Define dtypes... done!")
186
+ return dtype_coord, dtype_zcorn, dtype_actnum, newmeta
187
+
188
+
189
+ def _transform_vectors(
190
+ grid: Grid, meta: MetaData, dtypecoo: str, dtypezco: str, dtypeact: str
191
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
192
+ logger.debug("Transform vectors...")
193
+
194
+ xshift = meta["_required_"]["xshift"]
195
+ yshift = meta["_required_"]["yshift"]
196
+ zshift = meta["_required_"]["zshift"]
197
+
198
+ if xshift != 0.0 or yshift != 0.0 or zshift != 0.0:
199
+ coordsv = grid._coordsv.copy()
200
+ zcornsv = grid._zcornsv.copy()
201
+ actnumsv = grid._actnumsv.copy()
202
+ coordsv[:, :, 0::3] -= xshift
203
+ coordsv[:, :, 1::3] -= yshift
204
+ coordsv[:, :, 2::3] -= zshift
205
+ zcornsv -= zshift
206
+ else:
207
+ coordsv = grid._coordsv
208
+ zcornsv = grid._zcornsv
209
+ actnumsv = grid._actnumsv
210
+
211
+ if dtypecoo != "float64":
212
+ coordsv = coordsv.astype(dtypecoo)
213
+
214
+ if dtypecoo != "float32":
215
+ zcornsv = zcornsv.astype(dtypezco)
216
+
217
+ if dtypecoo != "int32":
218
+ actnumsv = actnumsv.astype(dtypeact)
219
+
220
+ logger.debug("Transform vectors... done!")
221
+ return coordsv, zcornsv, actnumsv
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ import numpy as np
6
+
7
+ from xtgeo import _cxtgeo
8
+ from xtgeo.common import null_logger
9
+ from xtgeo.common.constants import UNDEF_INT
10
+
11
+ logger = null_logger(__name__)
12
+
13
+ if TYPE_CHECKING:
14
+ from xtgeo.grid3d import Grid, GridProperty
15
+
16
+
17
+ def make_hybridgrid(
18
+ self: Grid,
19
+ nhdiv: int = 10,
20
+ toplevel: float = 1000.0,
21
+ bottomlevel: float = 1100.0,
22
+ region: GridProperty | None = None,
23
+ region_number: int | None = None,
24
+ ) -> None:
25
+ """Make hybrid grid."""
26
+ self._xtgformat1()
27
+
28
+ newnlay = self.nlay * 2 + nhdiv
29
+ newnzcorn = self.ncol * self.nrow * (newnlay + 1) * 4
30
+ newnactnum = self.ncol * self.nrow * newnlay
31
+
32
+ # initialize
33
+ hyb_zcornsv = np.zeros(newnzcorn, dtype=np.float64)
34
+ hyb_actnumsv = np.zeros(newnactnum, dtype=np.int32)
35
+
36
+ if region is None:
37
+ region_number = -1
38
+ rvalues = np.ones(1, dtype=np.int32)
39
+ else:
40
+ rvalues = np.ma.filled(region.values, fill_value=UNDEF_INT)
41
+ rvalues = rvalues.ravel()
42
+
43
+ _cxtgeo.grd3d_convert_hybrid(
44
+ self.ncol,
45
+ self.nrow,
46
+ self.nlay,
47
+ self._coordsv,
48
+ self._zcornsv,
49
+ self._actnumsv,
50
+ newnlay,
51
+ hyb_zcornsv,
52
+ hyb_actnumsv,
53
+ toplevel,
54
+ bottomlevel,
55
+ nhdiv,
56
+ rvalues,
57
+ region_number,
58
+ )
59
+
60
+ # when a hybridgrid is made, the current subrid settings lose relevance, hence
61
+ # it is forced set to None
62
+ self.subgrids = None
63
+
64
+ self._nlay = newnlay
65
+ self._zcornsv = hyb_zcornsv
66
+ self._actnumsv = hyb_actnumsv
@@ -0,0 +1,79 @@
1
+ """Grid import functions for various formats."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ from xtgeo.common.exceptions import InvalidFileFormatError
9
+ from xtgeo.common.log import null_logger
10
+ from xtgeo.io._file import FileFormat, FileWrapper
11
+
12
+ from . import _grid_import_ecl, _grid_import_roff, _grid_import_xtgcpgeom
13
+
14
+ logger = null_logger(__name__)
15
+
16
+
17
+ def from_file(
18
+ gfile: FileWrapper,
19
+ fformat: FileFormat,
20
+ **kwargs: Any,
21
+ ) -> dict[str, Any]:
22
+ """Import grid geometry from file, and makes an instance of this class.
23
+
24
+ Returns:
25
+ dictionary of keyword arguments to be used in Grid constructor.
26
+ """
27
+ if not isinstance(gfile, FileWrapper):
28
+ raise RuntimeError("Error gfile must be a FileWrapper instance")
29
+
30
+ result: dict[str, Any] = {
31
+ "filesrc": gfile.name,
32
+ }
33
+ gfile.check_file(raiseerror=IOError, raisetext=f"Cannot access file {gfile.name}")
34
+
35
+ if fformat in (FileFormat.ROFF_BINARY, FileFormat.ROFF_ASCII):
36
+ result.update(_grid_import_roff.import_roff(gfile, **kwargs))
37
+ elif fformat in (FileFormat.EGRID, FileFormat.FEGRID):
38
+ result.update(
39
+ _grid_import_ecl.import_ecl_egrid(
40
+ gfile,
41
+ fileformat=fformat,
42
+ **kwargs,
43
+ )
44
+ )
45
+ elif fformat == FileFormat.GRDECL:
46
+ result.update(_grid_import_ecl.import_ecl_grdecl(gfile, **kwargs))
47
+ elif fformat == FileFormat.BGRDECL:
48
+ result.update(_grid_import_ecl.import_ecl_bgrdecl(gfile, **kwargs))
49
+ elif fformat == FileFormat.XTG:
50
+ result.update(_grid_import_xtgcpgeom.import_xtgcpgeom(gfile, **kwargs))
51
+ elif fformat == FileFormat.HDF:
52
+ result.update(_grid_import_xtgcpgeom.import_hdf5_cpgeom(gfile, **kwargs))
53
+ else:
54
+ extensions = FileFormat.extensions_string(
55
+ [
56
+ FileFormat.ROFF_BINARY,
57
+ FileFormat.ROFF_ASCII,
58
+ FileFormat.EGRID,
59
+ FileFormat.FEGRID,
60
+ FileFormat.GRDECL,
61
+ FileFormat.BGRDECL,
62
+ FileFormat.XTG,
63
+ FileFormat.HDF,
64
+ ]
65
+ )
66
+ raise InvalidFileFormatError(
67
+ f"File format {fformat} is invalid for type Grid. "
68
+ f"Supported formats are {extensions}."
69
+ )
70
+
71
+ if gfile.memstream:
72
+ result["name"] = "unknown"
73
+ else:
74
+ # Mypy does not know that if gfile.memstream -> False
75
+ # then .file must be Path.
76
+ assert isinstance(gfile.file, Path)
77
+ result["name"] = gfile.file.stem
78
+
79
+ return result
@@ -0,0 +1,101 @@
1
+ """Grid import functions for Eclipse, new approach (i.e. version 2)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from xtgeo.common import null_logger
8
+ from xtgeo.grid3d._egrid import EGrid, RockModel
9
+ from xtgeo.grid3d._grdecl_grid import GrdeclGrid, GridRelative
10
+ from xtgeo.grid3d.grid_properties import GridProperties, gridproperties_from_file
11
+ from xtgeo.io._file import FileFormat, FileWrapper
12
+
13
+ logger = null_logger(__name__)
14
+
15
+
16
+ if TYPE_CHECKING:
17
+ from xtgeo.grid3d.grid import Grid
18
+
19
+
20
+ def import_ecl_egrid(
21
+ gfile: FileWrapper,
22
+ relative_to: GridRelative = GridRelative.MAP,
23
+ fileformat: FileFormat = FileFormat.EGRID,
24
+ ) -> dict[str, Any]:
25
+ egrid = EGrid.from_file(gfile.file, fileformat=fileformat)
26
+ result = grid_from_ecl_grid(egrid, relative_to=relative_to)
27
+
28
+ if egrid.egrid_head.file_head.rock_model == RockModel.DUAL_POROSITY:
29
+ result["dualporo"] = True
30
+ result["dualperm"] = False
31
+ elif egrid.egrid_head.file_head.rock_model == RockModel.DUAL_PERMEABILITY:
32
+ result["dualporo"] = True
33
+ result["dualperm"] = True
34
+
35
+ return result
36
+
37
+
38
+ def import_ecl_run(
39
+ groot: str,
40
+ ecl_grid: Grid,
41
+ initprops: list[str] | None = None,
42
+ restartprops: list[str] | None = None,
43
+ restartdates: list[str] | None = None,
44
+ ) -> None:
45
+ """Import Eclipse run suite: EGrid and properties from INIT and UNRST.
46
+ For the INIT and UNRST files, property dates shall be selected."""
47
+ ecl_init = FileWrapper(f"{groot}.INIT")
48
+ ecl_rsta = FileWrapper(f"{groot}.UNRST")
49
+ grdprops = GridProperties()
50
+
51
+ # import the init properties unless list is empty
52
+ if initprops:
53
+ initprops_ = gridproperties_from_file(
54
+ ecl_init.name, names=initprops, fformat="init", dates=None, grid=ecl_grid
55
+ )
56
+ if initprops_.props:
57
+ grdprops.append_props(initprops_.props)
58
+
59
+ # import the restart properties for dates unless lists are empty
60
+ if restartprops and restartdates:
61
+ restartprops_ = gridproperties_from_file(
62
+ ecl_rsta.name,
63
+ names=restartprops,
64
+ fformat="unrst",
65
+ dates=restartdates,
66
+ grid=ecl_grid,
67
+ )
68
+ if restartprops_.props:
69
+ grdprops.append_props(restartprops_.props)
70
+ ecl_grid.gridprops = grdprops
71
+
72
+
73
+ def import_ecl_grdecl(
74
+ gfile: FileWrapper, relative_to: GridRelative = GridRelative.MAP
75
+ ) -> dict[str, Any]:
76
+ """Import grdecl format."""
77
+ grdecl_grid = GrdeclGrid.from_file(gfile.file, fileformat=FileFormat.GRDECL)
78
+ return grid_from_ecl_grid(grdecl_grid, relative_to=relative_to)
79
+
80
+
81
+ def import_ecl_bgrdecl(
82
+ gfile: FileWrapper, relative_to: GridRelative = GridRelative.MAP
83
+ ) -> dict[str, Any]:
84
+ """Import binary files with GRDECL layout."""
85
+ grdecl_grid = GrdeclGrid.from_file(gfile.file, fileformat=FileFormat.BGRDECL)
86
+ return grid_from_ecl_grid(grdecl_grid, relative_to=relative_to)
87
+
88
+
89
+ def grid_from_ecl_grid(
90
+ ecl_grid: EGrid, relative_to: GridRelative = GridRelative.MAP
91
+ ) -> dict[str, Any]:
92
+ result = {}
93
+ result["coordsv"] = ecl_grid.xtgeo_coord(relative_to=relative_to)
94
+ result["zcornsv"] = ecl_grid.xtgeo_zcorn(relative_to=relative_to)
95
+ result["actnumsv"] = ecl_grid.xtgeo_actnum()
96
+ if relative_to == GridRelative.MAP and ecl_grid.map_axis_units is not None:
97
+ result["units"] = ecl_grid.map_axis_units
98
+ else:
99
+ result["units"] = ecl_grid.grid_units
100
+
101
+ return result
@@ -0,0 +1,135 @@
1
+ """Private module, Grid Import private functions for ROFF format."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import pathlib
6
+ import tempfile
7
+ import warnings
8
+ from contextlib import contextmanager
9
+ from io import BufferedReader, BytesIO
10
+ from typing import TYPE_CHECKING, Generator
11
+
12
+ from xtgeo.common import null_logger
13
+
14
+ from ._roff_grid import RoffGrid
15
+
16
+ if TYPE_CHECKING:
17
+ from numpy.typing import NDArray
18
+
19
+ from xtgeo.common.types import FileLike
20
+ from xtgeo.io._file import FileWrapper
21
+
22
+
23
+ logger = null_logger(__name__)
24
+
25
+
26
+ def match_xtgeo_214_header(header: bytes) -> bool:
27
+ """
28
+ Check whether the start of a binary file matches
29
+ the problematic xtgeo version 2.14 contents.
30
+
31
+ Params:
32
+ header: the start of a file
33
+
34
+ """
35
+ first_part_match = header.startswith(
36
+ b"roff-bin\0"
37
+ b"#ROFF file#\0"
38
+ b"#Creator: CXTGeo subsystem of XTGeo by JCR#\0"
39
+ b"tag\0filedata\0"
40
+ b"int\0byteswaptest\0"
41
+ )
42
+ problem_area_match = header[99:].startswith(
43
+ b"char\0filetype\0grid\0char\0creationDate\0UNKNOWNendtag"
44
+ )
45
+ return first_part_match and problem_area_match
46
+
47
+
48
+ def replace_xtgeo_214_header(header: bytes) -> bytes:
49
+ """
50
+ Given that match_xtgeo_214_header(header), inserts
51
+ a \0 in the correct place.
52
+ """
53
+ return header[:143] + b"\0" + header[143:]
54
+
55
+
56
+ @contextmanager
57
+ def handle_deprecated_xtgeo_roff_file(
58
+ filelike: FileLike,
59
+ ) -> Generator[
60
+ FileLike | tempfile._TemporaryFileWrapper[bytes],
61
+ None,
62
+ None,
63
+ ]:
64
+ """
65
+ A contextmanager that inplace fixes grid roff files
66
+ that were written by XTGeo prior to version 2.15. This
67
+ backwards compatibility should eventually be deprecated
68
+
69
+ Example::
70
+
71
+ with handle_deprecated_xtgeo_roff_file("grid.roff") as converted_grid:
72
+ roff_grid = RoffGrid.from_file(converted_file)
73
+
74
+
75
+ Before version 2.15, grids with _xtgformat=1 would be written with missing
76
+ '\\0' after the creationDate. However, it would also silently read that
77
+ file without any issues in the final product. roffio is less leanient when
78
+ it comes to the format it will accept and so does not recover. Luckily, the
79
+ creationDate was set to 'UNKNOWN' so we can be fairly certain we replace
80
+ correctly.
81
+
82
+ """
83
+ inhandle: FileLike | BufferedReader = filelike
84
+ close = False
85
+ if isinstance(filelike, (str, pathlib.Path)):
86
+ inhandle = open(filelike, "rb") # noqa: SIM115
87
+ close = True
88
+
89
+ # MYPY is uanble to figur out that isinstance check
90
+ # above means we have an IO-based class now.
91
+ assert isinstance(inhandle, (BufferedReader, BytesIO))
92
+ goback = inhandle.tell()
93
+ header = inhandle.read(200)
94
+
95
+ if match_xtgeo_214_header(header):
96
+ name = "buffer"
97
+ if hasattr(filelike, "name"):
98
+ name = filelike.name
99
+ warnings.warn(
100
+ f"The roff file {name} contains nonstandard but harmless roff"
101
+ " format detail written by XTGeo version <=2.14. Reading of such files"
102
+ " is deprecated, consider re-exporting the file with XTGeo version >=2.15.3"
103
+ )
104
+
105
+ new_header = replace_xtgeo_214_header(header)
106
+
107
+ with tempfile.NamedTemporaryFile() as outhandle:
108
+ outhandle.write(new_header)
109
+ inhandle.seek(200)
110
+ outhandle.write(inhandle.read())
111
+ outhandle.seek(0)
112
+ yield outhandle
113
+ if close:
114
+ inhandle.close()
115
+ else:
116
+ inhandle.seek(goback)
117
+
118
+ else:
119
+ if close:
120
+ inhandle.close()
121
+ else:
122
+ inhandle.seek(goback)
123
+
124
+ yield filelike
125
+
126
+
127
+ def import_roff(gfile: FileWrapper) -> dict[str, NDArray | dict[str, range] | None]:
128
+ with handle_deprecated_xtgeo_roff_file(gfile._file) as converted_file:
129
+ roff_grid = RoffGrid.from_file(converted_file)
130
+ return {
131
+ "actnumsv": roff_grid.xtgeo_actnum(),
132
+ "coordsv": roff_grid.xtgeo_coord(),
133
+ "zcornsv": roff_grid.xtgeo_zcorn(),
134
+ "subgrids": roff_grid.xtgeo_subgrids(),
135
+ }