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,152 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal, cast
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import numpy.typing as npt
|
|
7
|
+
|
|
8
|
+
from xtgeo.common.log import null_logger
|
|
9
|
+
|
|
10
|
+
from ._ecl_output_file import Phases, Simulator, TypeOfGrid, UnitSystem
|
|
11
|
+
|
|
12
|
+
_logger = null_logger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class InteHead:
|
|
16
|
+
"""Contains the values for the INTEHEAD array in ecl restart
|
|
17
|
+
and init files.
|
|
18
|
+
|
|
19
|
+
Output files from eclipse and opm flow will contain sections
|
|
20
|
+
starting with keyword-array headers. One of these is the INTEHEAD
|
|
21
|
+
keyword. The values in the array are integers, and the meaning
|
|
22
|
+
of each index is described in the e.g. the OPM user manual (2021-04 rev_01
|
|
23
|
+
section D.6-D.7).
|
|
24
|
+
|
|
25
|
+
The length of the array is not specified, meaning some values are missing,
|
|
26
|
+
the InteHead class creates a lookup for these values:
|
|
27
|
+
|
|
28
|
+
>>> intehead = InteHead(np.array([0,1,2,3,4,5,6,7,8]))
|
|
29
|
+
>>> intehead.num_x
|
|
30
|
+
8
|
|
31
|
+
>>> # The year field is missing in the input
|
|
32
|
+
>>> intehead.year is None
|
|
33
|
+
True
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, values: npt.NDArray[np.int_]) -> None:
|
|
37
|
+
"""Create an InteHead from the corresponding array.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
values: Array of values following the INTEHEAD keyword
|
|
41
|
+
in an ECL restart or init file.
|
|
42
|
+
"""
|
|
43
|
+
self.values = values
|
|
44
|
+
|
|
45
|
+
def __eq__(self, other: Any) -> bool:
|
|
46
|
+
if not isinstance(other, InteHead):
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
return np.array_equal(self.values, other.values)
|
|
50
|
+
|
|
51
|
+
def __repr__(self) -> str:
|
|
52
|
+
return f"InteHead(values={self.values})"
|
|
53
|
+
|
|
54
|
+
def __str__(self) -> str:
|
|
55
|
+
return self.__repr__()
|
|
56
|
+
|
|
57
|
+
def _optional_index_lookup(self, index: int) -> int | None:
|
|
58
|
+
"""Looks up the value at the given index, returning None if out of bound.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
index: The index in the value array to look up
|
|
62
|
+
constructor: Constructor function to wrap non-None values in, defaults
|
|
63
|
+
to identity.
|
|
64
|
+
Returns:
|
|
65
|
+
value at the index, None if out of bounds.
|
|
66
|
+
"""
|
|
67
|
+
return self.values[index] if len(self.values) > index else None
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def unit_system(self) -> UnitSystem | None:
|
|
71
|
+
"""
|
|
72
|
+
The unit system used in the file.
|
|
73
|
+
"""
|
|
74
|
+
v = self._optional_index_lookup(2)
|
|
75
|
+
return None if v is None else UnitSystem(v)
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def num_x(self) -> int | None:
|
|
79
|
+
"""The number of columns (x direction) of cells"""
|
|
80
|
+
return self._optional_index_lookup(8)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def num_y(self) -> int | None:
|
|
84
|
+
"""The number of rows (y direction) of cells"""
|
|
85
|
+
return self._optional_index_lookup(9)
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def num_z(self) -> int | None:
|
|
89
|
+
"""The number of layers (z direction) of cells"""
|
|
90
|
+
return self._optional_index_lookup(10)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def num_active(self) -> int | None:
|
|
94
|
+
"""The number of active cells"""
|
|
95
|
+
return self._optional_index_lookup(11)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def phases(self) -> Phases | None:
|
|
99
|
+
"""The phase system used for simulation"""
|
|
100
|
+
if any(ids in str(self.simulator) for ids in ["300", "INTERSECT"]):
|
|
101
|
+
# item 14 in E300 runs is number of tracers, not IPHS; assume oil/wat/gas
|
|
102
|
+
# item 14 in INTERSECT is always(?) undef., not IPHS; assume oil/wat/gas
|
|
103
|
+
return Phases.OIL_WATER_GAS
|
|
104
|
+
v = self._optional_index_lookup(14)
|
|
105
|
+
return None if v is None else Phases(v)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def day(self) -> int | None:
|
|
109
|
+
"""The simulated time calendar day
|
|
110
|
+
|
|
111
|
+
(e.g. 3rd of april 2018)
|
|
112
|
+
|
|
113
|
+
"""
|
|
114
|
+
return self._optional_index_lookup(64)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def month(self) -> int | None:
|
|
118
|
+
"""The simulated time calendar month
|
|
119
|
+
|
|
120
|
+
4 for simulation being in month 4.
|
|
121
|
+
|
|
122
|
+
"""
|
|
123
|
+
return self._optional_index_lookup(65)
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def year(self) -> int | None:
|
|
127
|
+
"""The simulated time calendar month
|
|
128
|
+
|
|
129
|
+
e.g. 2018 for simulation being done in year 2018
|
|
130
|
+
"""
|
|
131
|
+
return self._optional_index_lookup(66)
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def simulator(self) -> Simulator | int | None:
|
|
135
|
+
"""The simulator used for producing the run, or integer code if unknown"""
|
|
136
|
+
s_code = self._optional_index_lookup(94)
|
|
137
|
+
try:
|
|
138
|
+
return Simulator(s_code)
|
|
139
|
+
except ValueError:
|
|
140
|
+
# changed from a UserWarning to a logging message
|
|
141
|
+
_logger.warning("Unknown simulator code %s", s_code)
|
|
142
|
+
return s_code
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def type_of_grid(self) -> TypeOfGrid | None:
|
|
146
|
+
"""The type of grid used in the simulation"""
|
|
147
|
+
value = self._optional_index_lookup(13)
|
|
148
|
+
return (
|
|
149
|
+
None
|
|
150
|
+
if value is None
|
|
151
|
+
else TypeOfGrid.alternate_code(cast("Literal[0, 1, 2, 3]", value))
|
|
152
|
+
)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from ._ecl_output_file import Simulator
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def lookup_optional_code(values: list[bool], index: int) -> bool | None:
|
|
9
|
+
if len(values) <= index:
|
|
10
|
+
return None
|
|
11
|
+
return values[index]
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class LogiHead:
|
|
16
|
+
"""Contains the values for the LOGIHEAD array in restart and init files.
|
|
17
|
+
|
|
18
|
+
Output files from eclipse and opm flow will contain sections
|
|
19
|
+
starting with keyword-array headers. One of these is the LOGIHEAD
|
|
20
|
+
keyword. The values in the array are booleans, and the meaning
|
|
21
|
+
of each index is described in the e.g. the OPM user manual (2021-04 rev_01
|
|
22
|
+
section D.6-D.7).
|
|
23
|
+
|
|
24
|
+
The length of the array is not specified, meaning some values are missing,
|
|
25
|
+
the InteHead class creates a lookup for these values:
|
|
26
|
+
|
|
27
|
+
Generally, the field describe whether an option has been enabled in the
|
|
28
|
+
model, ie. if logihead.dual_porosity is True then the model uses the
|
|
29
|
+
dual porosity feature.
|
|
30
|
+
|
|
31
|
+
>>> logihead = LogiHead.from_file_values([True, True, False], Simulator.ECLIPSE_100)
|
|
32
|
+
>>> logihead.dissolved_gas
|
|
33
|
+
True
|
|
34
|
+
>>> # Whether coal bed methane is used is missing
|
|
35
|
+
>>> logihead.coal_bed_methane is None
|
|
36
|
+
True
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
dissolved_gas: bool | None = None
|
|
41
|
+
vaporized_oil: bool | None = None
|
|
42
|
+
directional: bool | None = None
|
|
43
|
+
radial: bool | None = None
|
|
44
|
+
reversible: bool | None = None
|
|
45
|
+
hysterisis: bool | None = None
|
|
46
|
+
dual_porosity: bool | None = None
|
|
47
|
+
end_point_scaling: bool | None = None
|
|
48
|
+
directional_end_point_scaling: bool | None = None
|
|
49
|
+
reversible_end_point_scaling: bool | None = None
|
|
50
|
+
alternate_end_point_scaling: bool | None = None
|
|
51
|
+
miscible_displacement: bool | None = None
|
|
52
|
+
scale_water_pressure1: bool | None = None
|
|
53
|
+
scale_water_pressure2: bool | None = None
|
|
54
|
+
coal_bed_methane: bool | None = None
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def from_file_values(cls, values: list[bool], simulator: Simulator) -> LogiHead:
|
|
58
|
+
"""Construct a LogiHead from the array following the LOGIHEAD keyword
|
|
59
|
+
Args:
|
|
60
|
+
values: The iterable of boolean values following the LOGIHEAD keyword
|
|
61
|
+
simulator: The meaning of each field is simulator dependent, so
|
|
62
|
+
the simulator must be given.
|
|
63
|
+
"""
|
|
64
|
+
if simulator == Simulator.ECLIPSE_100:
|
|
65
|
+
# Weirdly, eclipse_100 outputs reversible and radial flags
|
|
66
|
+
# in swapped order.
|
|
67
|
+
indices = [0, 1, 2, 4, 3, 6, 14, 16, 17, 18, 19, 35, 55, 56, 127]
|
|
68
|
+
else:
|
|
69
|
+
indices = [0, 1, 2, 3, 4, 6, 14, 16, 17, 18, 19, 35, 55, 56, 127]
|
|
70
|
+
|
|
71
|
+
return cls(*[lookup_optional_code(values, i) for i in indices])
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum, unique
|
|
4
|
+
from typing import Literal
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@unique
|
|
8
|
+
class TypeOfGrid(Enum):
|
|
9
|
+
"""
|
|
10
|
+
A Grid has three possible data layout formats, UNSTRUCTURED, CORNER_POINT,
|
|
11
|
+
BLOCK_CENTER and COMPOSITE (meaning combination of the two former). Only
|
|
12
|
+
CORNER_POINT layout is supported by XTGeo.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
COMPOSITE = 0
|
|
16
|
+
CORNER_POINT = 1
|
|
17
|
+
UNSTRUCTURED = 2
|
|
18
|
+
BLOCK_CENTER = 3
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def alternate_code(cls, code: Literal[0, 1, 2, 3]) -> TypeOfGrid:
|
|
22
|
+
"""Converts from alternate code to TypeOfGrid member.
|
|
23
|
+
|
|
24
|
+
weirdly, type of grid sometimes (For instance init's INTHEAD and
|
|
25
|
+
FILEHEAD) have an alternate integer code for type of grid.
|
|
26
|
+
"""
|
|
27
|
+
if code == 0:
|
|
28
|
+
type_of_grid = cls.CORNER_POINT
|
|
29
|
+
elif code == 1:
|
|
30
|
+
type_of_grid = cls.UNSTRUCTURED
|
|
31
|
+
elif code == 2:
|
|
32
|
+
type_of_grid = cls.COMPOSITE
|
|
33
|
+
elif code == 3:
|
|
34
|
+
type_of_grid = cls.BLOCK_CENTER
|
|
35
|
+
else:
|
|
36
|
+
raise ValueError(f"Unknown grid type {code}")
|
|
37
|
+
return type_of_grid
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def alternate_value(self) -> int:
|
|
41
|
+
"""Inverse of alternate_code."""
|
|
42
|
+
alternate_value = 0
|
|
43
|
+
if self == TypeOfGrid.CORNER_POINT:
|
|
44
|
+
alternate_value = 0
|
|
45
|
+
elif self == TypeOfGrid.UNSTRUCTURED:
|
|
46
|
+
alternate_value = 1
|
|
47
|
+
elif self == TypeOfGrid.COMPOSITE:
|
|
48
|
+
alternate_value = 2
|
|
49
|
+
elif self == TypeOfGrid.BLOCK_CENTER:
|
|
50
|
+
alternate_value = 3
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError(f"Unknown grid type {self}")
|
|
53
|
+
return alternate_value
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@unique
|
|
57
|
+
class UnitSystem(Enum):
|
|
58
|
+
METRIC = 1
|
|
59
|
+
FIELD = 2
|
|
60
|
+
LAB = 3
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@unique
|
|
64
|
+
class Phases(Enum):
|
|
65
|
+
E300_GENERIC = 0
|
|
66
|
+
OIL = 1
|
|
67
|
+
WATER = 2
|
|
68
|
+
OIL_WATER = 3
|
|
69
|
+
GAS = 4
|
|
70
|
+
OIL_GAS = 5
|
|
71
|
+
GAS_WATER = 6
|
|
72
|
+
OIL_WATER_GAS = 7
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@unique
|
|
76
|
+
class Simulator(Enum):
|
|
77
|
+
ECLIPSE_100 = 100
|
|
78
|
+
ECLIPSE_300 = 300
|
|
79
|
+
ECLIPSE_300_THERMAL = 500
|
|
80
|
+
INTERSECT = 700
|
|
81
|
+
FRONTSIM = 800
|