xtgeo 4.12.1__cp313-cp313-win_amd64.whl → 4.13.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.
Potentially problematic release.
This version of xtgeo might be problematic. Click here for more details.
- cxtgeo.py +0 -18
- cxtgeoPYTHON_wrap.c +0 -843
- xtgeo/_cxtgeo.cp313-win_amd64.pyd +0 -0
- xtgeo/_internal.cp313-win_amd64.pyd +0 -0
- xtgeo/common/version.py +3 -3
- xtgeo/cube/_cube_window_attributes.py +53 -129
- xtgeo/grid3d/_ecl_inte_head.py +6 -2
- xtgeo/grid3d/_grid_etc1.py +70 -60
- xtgeo/grid3d/_grid_hybrid.py +13 -29
- xtgeo/grid3d/_grid_translate_coords.py +154 -0
- xtgeo/grid3d/_gridprop_roxapi.py +8 -2
- xtgeo/grid3d/grid.py +85 -18
- xtgeo/io/_file.py +1 -1
- xtgeo/metadata/metadata.py +49 -52
- xtgeo/surface/_regsurf_oper.py +1 -94
- xtgeo/surface/regular_surface.py +4 -9
- xtgeo/well/_blockedwell_roxapi.py +24 -4
- xtgeo/xyz/_xyz_io.py +7 -5
- xtgeo/xyz/points.py +1 -0
- {xtgeo-4.12.1.dist-info → xtgeo-4.13.1.dist-info}/METADATA +2 -1
- {xtgeo-4.12.1.dist-info → xtgeo-4.13.1.dist-info}/RECORD +23 -22
- {xtgeo-4.12.1.dist-info → xtgeo-4.13.1.dist-info}/WHEEL +0 -0
- {xtgeo-4.12.1.dist-info → xtgeo-4.13.1.dist-info}/licenses/LICENSE.md +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"""Private module for translating coordiantes plus flipping and rotation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from xtgeo.grid3d import Grid
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _rotate_grid3d(
|
|
15
|
+
new_grd: Grid, add_rotation: float, rotation_xy: tuple[float, float] | None = None
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Rotate the grid around the cell 1,1,1 corner, or some other coordinate."""
|
|
18
|
+
|
|
19
|
+
# Convert angle to radians
|
|
20
|
+
angle_rad = math.radians(add_rotation)
|
|
21
|
+
|
|
22
|
+
# Create rotation matrix coefficients
|
|
23
|
+
cos_theta = math.cos(angle_rad)
|
|
24
|
+
sin_theta = math.sin(angle_rad)
|
|
25
|
+
|
|
26
|
+
# extract
|
|
27
|
+
coord_array = new_grd._coordsv.copy()
|
|
28
|
+
rotated_coords = coord_array.copy()
|
|
29
|
+
|
|
30
|
+
if rotation_xy is None:
|
|
31
|
+
x0, y0, _ = new_grd._coordsv[0, 0, :3]
|
|
32
|
+
else:
|
|
33
|
+
x0, y0 = rotation_xy
|
|
34
|
+
|
|
35
|
+
x_coords = coord_array[:, :, [0, 3]].copy() # x1 and x2
|
|
36
|
+
y_coords = coord_array[:, :, [1, 4]].copy() # y1 and y2
|
|
37
|
+
|
|
38
|
+
# Translate to origin
|
|
39
|
+
x_translated = x_coords - x0
|
|
40
|
+
y_translated = y_coords - y0
|
|
41
|
+
|
|
42
|
+
# Rotate using rotation matrix
|
|
43
|
+
x_rotated = x_translated * cos_theta - y_translated * sin_theta
|
|
44
|
+
y_rotated = x_translated * sin_theta + y_translated * cos_theta
|
|
45
|
+
|
|
46
|
+
# Translate back and assign
|
|
47
|
+
rotated_coords[:, :, [0, 3]] = x_rotated + x0
|
|
48
|
+
rotated_coords[:, :, [1, 4]] = y_rotated + y0
|
|
49
|
+
|
|
50
|
+
# Z coordinates remain unchanged (indices 2 and 5)
|
|
51
|
+
new_grd._coordsv = rotated_coords.copy()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _flip_vertically(grid: Grid) -> None:
|
|
55
|
+
"""Flip the grid vertically."""
|
|
56
|
+
|
|
57
|
+
# find average depth of corners
|
|
58
|
+
avg_z = grid._zcornsv.mean()
|
|
59
|
+
|
|
60
|
+
grid._zcornsv = grid._zcornsv[:, :, ::-1, :]
|
|
61
|
+
grid._zcornsv *= -1
|
|
62
|
+
|
|
63
|
+
# find the new average and compute the difference for shifting
|
|
64
|
+
new_avg_z = grid._zcornsv.mean()
|
|
65
|
+
diff = avg_z - new_avg_z
|
|
66
|
+
grid._zcornsv += diff
|
|
67
|
+
|
|
68
|
+
grid._actnumsv = np.flip(grid._actnumsv, axis=2).copy()
|
|
69
|
+
|
|
70
|
+
# Handle properties if they exist
|
|
71
|
+
if grid._props and grid._props.props:
|
|
72
|
+
for prop in grid._props.props:
|
|
73
|
+
prop.values = np.flip(prop.values, axis=2).copy()
|
|
74
|
+
|
|
75
|
+
# When we flip the grid, the subgrid info must also be flipped
|
|
76
|
+
subgrids = grid.get_subgrids()
|
|
77
|
+
if subgrids:
|
|
78
|
+
reverted = dict(reversed(subgrids.items()))
|
|
79
|
+
grid.set_subgrids(reverted)
|
|
80
|
+
|
|
81
|
+
if grid._ijk_handedness == "left":
|
|
82
|
+
grid._ijk_handedness = "right"
|
|
83
|
+
else:
|
|
84
|
+
grid._ijk_handedness = "left"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _translate_geometry(grid: Grid, translate: tuple[float, float, float]) -> None:
|
|
88
|
+
grid._coordsv[:, :, 0] += translate[0]
|
|
89
|
+
grid._coordsv[:, :, 1] += translate[1]
|
|
90
|
+
grid._coordsv[:, :, 2] += translate[2]
|
|
91
|
+
grid._coordsv[:, :, 3] += translate[0]
|
|
92
|
+
grid._coordsv[:, :, 4] += translate[1]
|
|
93
|
+
grid._coordsv[:, :, 5] += translate[2]
|
|
94
|
+
|
|
95
|
+
grid._zcornsv += translate[2]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _transfer_to_target(grid: Grid, target: tuple[float, float, float]) -> None:
|
|
99
|
+
# get the coordinates for the active cells
|
|
100
|
+
x, y, z = grid.get_xyz(asmasked=True)
|
|
101
|
+
|
|
102
|
+
# set the grid center to the desired target coordinates
|
|
103
|
+
shift_x = target[0] - x.values.mean()
|
|
104
|
+
shift_y = target[1] - y.values.mean()
|
|
105
|
+
shift_z = target[2] - z.values.mean()
|
|
106
|
+
|
|
107
|
+
_translate_geometry(grid, (shift_x, shift_y, shift_z))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def translate_coordinates(
|
|
111
|
+
self: Grid,
|
|
112
|
+
translate: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
113
|
+
flip: tuple[int, int, int] = (1, 1, 1),
|
|
114
|
+
add_rotation: float = 0.0,
|
|
115
|
+
rotation_point: tuple[float, float] | None = None,
|
|
116
|
+
target_coordinates: tuple[float, float, float] | None = None,
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Rotate, flip grid and translate grid coordinates.
|
|
119
|
+
|
|
120
|
+
This should be done in a sequence like this
|
|
121
|
+
1) Add rotation (with value ``add_rotation``) to rotate the grid counter-clockwise
|
|
122
|
+
2) Flip the grid
|
|
123
|
+
3a) translate the grid by adding (x, y, z), OR
|
|
124
|
+
3b) set a target location the grid centre.
|
|
125
|
+
|
|
126
|
+
"""
|
|
127
|
+
self._set_xtgformat2()
|
|
128
|
+
|
|
129
|
+
if abs(add_rotation) > 1e-10: # Skip rotation if angle is essentially zero
|
|
130
|
+
_rotate_grid3d(self, add_rotation, rotation_xy=rotation_point)
|
|
131
|
+
|
|
132
|
+
if flip[2] == -1:
|
|
133
|
+
_flip_vertically(self)
|
|
134
|
+
|
|
135
|
+
if flip[0] == -1:
|
|
136
|
+
self.reverse_column_axis()
|
|
137
|
+
|
|
138
|
+
if flip[1] == -1:
|
|
139
|
+
self.reverse_row_axis()
|
|
140
|
+
|
|
141
|
+
use_translate = False
|
|
142
|
+
if not all(abs(x) < 1e-10 for x in translate):
|
|
143
|
+
_translate_geometry(self, translate)
|
|
144
|
+
use_translate = True
|
|
145
|
+
|
|
146
|
+
if target_coordinates and use_translate:
|
|
147
|
+
raise ValueError(
|
|
148
|
+
"Using both key 'translate' and key 'target_coordinates' is not allowed. "
|
|
149
|
+
"Use either."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
if target_coordinates:
|
|
153
|
+
# transfer the grid's geometrical centre to a given location
|
|
154
|
+
_transfer_to_target(self, target_coordinates)
|
xtgeo/grid3d/_gridprop_roxapi.py
CHANGED
|
@@ -150,12 +150,18 @@ def _validate_dtype_in_roxar(
|
|
|
150
150
|
)
|
|
151
151
|
|
|
152
152
|
try:
|
|
153
|
+
# for mypy
|
|
154
|
+
min_val: int | float
|
|
155
|
+
max_val: int | float
|
|
156
|
+
|
|
153
157
|
if np.issubdtype(dtype, np.integer):
|
|
154
158
|
# Integer type
|
|
155
|
-
min_val
|
|
159
|
+
min_val = int(np.iinfo(dtype).min)
|
|
160
|
+
max_val = int(np.iinfo(dtype).max)
|
|
156
161
|
elif np.issubdtype(dtype, np.floating):
|
|
157
162
|
# Float type
|
|
158
|
-
min_val
|
|
163
|
+
min_val = float(np.finfo(dtype).min)
|
|
164
|
+
max_val = float(np.finfo(dtype).max)
|
|
159
165
|
else:
|
|
160
166
|
# Unknown type
|
|
161
167
|
raise RuntimeError("Probable bug, values array not integer or float")
|
xtgeo/grid3d/grid.py
CHANGED
|
@@ -28,6 +28,7 @@ from . import (
|
|
|
28
28
|
_grid_import_ecl,
|
|
29
29
|
_grid_refine,
|
|
30
30
|
_grid_roxapi,
|
|
31
|
+
_grid_translate_coords,
|
|
31
32
|
_grid_wellzone,
|
|
32
33
|
_gridprop_lowlevel,
|
|
33
34
|
)
|
|
@@ -1818,7 +1819,9 @@ class Grid(_Grid3D):
|
|
|
1818
1819
|
name (str): name of property
|
|
1819
1820
|
flip (bool): Use False for Petrel grids were Z is negative down
|
|
1820
1821
|
(experimental)
|
|
1821
|
-
asmasked (bool): True if only for active cells, False for all cells
|
|
1822
|
+
asmasked (bool): True if only for active cells, False for all cells.
|
|
1823
|
+
With `False` the inactive cells are included, but the numpy
|
|
1824
|
+
array is still a MaskedArray instance.
|
|
1822
1825
|
metric (str): One of the following metrics:
|
|
1823
1826
|
* "euclid": sqrt(dx^2 + dy^2 + dz^2)
|
|
1824
1827
|
* "horizontal": sqrt(dx^2 + dy^2)
|
|
@@ -1854,7 +1857,8 @@ class Grid(_Grid3D):
|
|
|
1854
1857
|
Args:
|
|
1855
1858
|
name (str): names of properties
|
|
1856
1859
|
asmasked (bool). If True, make a np.ma array where inactive cells
|
|
1857
|
-
are masked.
|
|
1860
|
+
are masked. Otherwise the inactive cells are included, but the numpy
|
|
1861
|
+
array is still a MaskedArray instance.
|
|
1858
1862
|
metric (str): One of the following metrics:
|
|
1859
1863
|
* "euclid": sqrt(dx^2 + dy^2 + dz^2)
|
|
1860
1864
|
* "horizontal": sqrt(dx^2 + dy^2)
|
|
@@ -1884,7 +1888,8 @@ class Grid(_Grid3D):
|
|
|
1884
1888
|
Args:
|
|
1885
1889
|
name (str): names of properties
|
|
1886
1890
|
asmasked (bool). If True, make a np.ma array where inactive cells
|
|
1887
|
-
are masked.
|
|
1891
|
+
are masked. Otherwise the inactive cells are included, but the numpy
|
|
1892
|
+
array is still a MaskedArray instance.
|
|
1888
1893
|
metric (str): One of the following metrics:
|
|
1889
1894
|
* "euclid": sqrt(dx^2 + dy^2 + dz^2)
|
|
1890
1895
|
* "horizontal": sqrt(dx^2 + dy^2)
|
|
@@ -2476,21 +2481,48 @@ class Grid(_Grid3D):
|
|
|
2476
2481
|
def translate_coordinates(
|
|
2477
2482
|
self,
|
|
2478
2483
|
translate: tuple[float, float, float] = (0.0, 0.0, 0.0),
|
|
2484
|
+
target_coordinates: tuple[float, float, float] | None = None,
|
|
2479
2485
|
flip: tuple[int, int, int] = (1, 1, 1),
|
|
2480
|
-
|
|
2481
|
-
|
|
2486
|
+
add_rotation: float = 0.0,
|
|
2487
|
+
rotation_point: tuple[float, float] | None = None,
|
|
2488
|
+
) -> Grid | None:
|
|
2489
|
+
"""Translate (move), flip and rotate the 3D grid geometry.
|
|
2482
2490
|
|
|
2483
|
-
By 'flip' here, it means that the full coordinate
|
|
2484
|
-
with -1.
|
|
2491
|
+
By 'flip' here, it means that the full coordinate arrays are inverted.
|
|
2485
2492
|
|
|
2486
2493
|
Args:
|
|
2487
|
-
translate
|
|
2488
|
-
|
|
2494
|
+
translate: Translation distance in X, Y, Z coordinates; these
|
|
2495
|
+
values will be added to the current coordinates.
|
|
2496
|
+
target_coordinates: Position for the centerpoint of the active grid cells.
|
|
2497
|
+
Note that key ``translate`` cannot be used with this key; i.e. use
|
|
2498
|
+
either ``translate`` or ``target_coordinates``
|
|
2499
|
+
flip: Flip array. The flip values must be 1 or -1, meaning 1 for
|
|
2500
|
+
keeping the current, and -1 for activating an axis flip.
|
|
2501
|
+
add_rotation: The grid geometry will get an additional rotation by this
|
|
2502
|
+
value, in degrees and counter clock wise.
|
|
2503
|
+
rotation_point: Which (x, y) coordiate to be set as origin when adding
|
|
2504
|
+
rotation. Default is the corner of the first cell number.
|
|
2505
|
+
|
|
2506
|
+
Note:
|
|
2507
|
+
Grid properties attached to the grid will also be transformed
|
|
2508
|
+
|
|
2509
|
+
Example::
|
|
2510
|
+
import xtgeo
|
|
2511
|
+
grd = xtgeo.grid_from_roxar(project, "simpleb8")
|
|
2512
|
+
poro = xtgeo.gridproperty_from_roxar(project, "simpleb8", "PORO")
|
|
2513
|
+
grd.props = [poro]
|
|
2514
|
+
|
|
2515
|
+
grd.translate_coordinates(translate=(10,10, 20), flip=(1,1,-1),
|
|
2516
|
+
add_rotation=30)
|
|
2517
|
+
|
|
2518
|
+
grd.to_roxar(project, "simpleb8_translated")
|
|
2519
|
+
poro1 = grd.get_prop_by_name("PORO")
|
|
2520
|
+
poro1.to_roxar(project, "simpleb8_translated", "PORO")
|
|
2489
2521
|
|
|
2490
|
-
Raises:
|
|
2491
|
-
RuntimeError: If translation goes wrong for unknown reasons
|
|
2492
2522
|
"""
|
|
2493
|
-
|
|
2523
|
+
_grid_translate_coords.translate_coordinates(
|
|
2524
|
+
self, translate, flip, add_rotation, rotation_point, target_coordinates
|
|
2525
|
+
)
|
|
2494
2526
|
|
|
2495
2527
|
def reverse_row_axis(
|
|
2496
2528
|
self, ijk_handedness: Literal["left", "right"] | None = None
|
|
@@ -2498,7 +2530,7 @@ class Grid(_Grid3D):
|
|
|
2498
2530
|
"""Reverse the row axis (J indices).
|
|
2499
2531
|
|
|
2500
2532
|
This means that IJK system will switched between a left vs right handed system.
|
|
2501
|
-
It is here (by using ijk_handedness key), possible to set a wanted
|
|
2533
|
+
It is here (by using ijk_handedness key), possible to set a wanted handedness.
|
|
2502
2534
|
|
|
2503
2535
|
Note that properties that are assosiated with the grid (through the
|
|
2504
2536
|
:py:attr:`~gridprops` or :py:attr:`~props` attribute) will also be
|
|
@@ -2524,6 +2556,38 @@ class Grid(_Grid3D):
|
|
|
2524
2556
|
"""
|
|
2525
2557
|
_grid_etc1.reverse_row_axis(self, ijk_handedness=ijk_handedness)
|
|
2526
2558
|
|
|
2559
|
+
def reverse_column_axis(
|
|
2560
|
+
self, ijk_handedness: Literal["left", "right"] | None = None
|
|
2561
|
+
) -> None:
|
|
2562
|
+
"""Reverse the column axis (I indices).
|
|
2563
|
+
|
|
2564
|
+
This means that IJK system will switched between a left vs right handed system.
|
|
2565
|
+
It is here (by using ijk_handedness key), possible to set a wanted handedness.
|
|
2566
|
+
|
|
2567
|
+
Note that properties that are assosiated with the grid (through the
|
|
2568
|
+
:py:attr:`~gridprops` or :py:attr:`~props` attribute) will also be
|
|
2569
|
+
reversed (which is desirable).
|
|
2570
|
+
|
|
2571
|
+
Args:
|
|
2572
|
+
ijk_handedness (str): If set to "right" or "left", do only reverse columns
|
|
2573
|
+
if handedness is not already achieved.
|
|
2574
|
+
|
|
2575
|
+
Example::
|
|
2576
|
+
|
|
2577
|
+
grd = xtgeo.grid_from_file("somefile.roff")
|
|
2578
|
+
prop1 = xtgeo.gridproperty_from_file("somepropfile1.roff")
|
|
2579
|
+
prop2 = xtgeo.gridproperty_from_file("somepropfile2.roff")
|
|
2580
|
+
|
|
2581
|
+
grd.props = [prop1, prop2]
|
|
2582
|
+
|
|
2583
|
+
# secure that the grid geometry is IJK right-handed
|
|
2584
|
+
grd.reverse_column_axis(ijk_handedness="right")
|
|
2585
|
+
|
|
2586
|
+
.. versionadded:: 4.14
|
|
2587
|
+
|
|
2588
|
+
"""
|
|
2589
|
+
_grid_etc1.reverse_column_axis(self, ijk_handedness=ijk_handedness)
|
|
2590
|
+
|
|
2527
2591
|
def make_zconsistent(self, zsep: float | int = 1e-5) -> None:
|
|
2528
2592
|
"""Make the 3D grid consistent in Z, by a minimal gap (zsep).
|
|
2529
2593
|
|
|
@@ -2556,11 +2620,13 @@ class Grid(_Grid3D):
|
|
|
2556
2620
|
:align: center
|
|
2557
2621
|
|
|
2558
2622
|
Args:
|
|
2559
|
-
nhdiv
|
|
2560
|
-
toplevel
|
|
2561
|
-
bottomlevel
|
|
2562
|
-
region
|
|
2563
|
-
|
|
2623
|
+
nhdiv: Number of hybrid layers.
|
|
2624
|
+
toplevel: Top of hybrid grid.
|
|
2625
|
+
bottomlevel: Base of hybrid grid.
|
|
2626
|
+
region: Region property (if needed). Note that the region will only be
|
|
2627
|
+
applied in a lateral sense: i.e. if a column is in the region, then
|
|
2628
|
+
the full column will be converted to hybrid.
|
|
2629
|
+
region_number: Which region to apply hybrid grid in if region.
|
|
2564
2630
|
|
|
2565
2631
|
Example:
|
|
2566
2632
|
Create a hybridgrid from file, based on a GRDECL file (no region)::
|
|
@@ -2577,6 +2643,7 @@ class Grid(_Grid3D):
|
|
|
2577
2643
|
.. _usage in the Troll field: https://doi.org/10.2118/148023-MS
|
|
2578
2644
|
|
|
2579
2645
|
"""
|
|
2646
|
+
|
|
2580
2647
|
_grid_hybrid.make_hybridgrid(
|
|
2581
2648
|
self,
|
|
2582
2649
|
nhdiv=nhdiv,
|
xtgeo/io/_file.py
CHANGED
|
@@ -227,7 +227,7 @@ class FileWrapper:
|
|
|
227
227
|
date = obj.metadata.opt.datetime # type: ignore
|
|
228
228
|
newname = short + "--" + desc
|
|
229
229
|
if date:
|
|
230
|
-
newname += "--" + date
|
|
230
|
+
newname += "--" + str(date)
|
|
231
231
|
else:
|
|
232
232
|
# return without modifications of self._file to avoid with_suffix() issues
|
|
233
233
|
# if the file name stem itself contains multiple '.'
|
xtgeo/metadata/metadata.py
CHANGED
|
@@ -21,6 +21,12 @@ from xtgeo.common.log import null_logger
|
|
|
21
21
|
if TYPE_CHECKING:
|
|
22
22
|
from datetime import datetime
|
|
23
23
|
|
|
24
|
+
from xtgeo.cube.cube1 import Cube
|
|
25
|
+
from xtgeo.grid3d.grid import Grid, GridProperty
|
|
26
|
+
from xtgeo.surface.regular_surface import RegularSurface
|
|
27
|
+
from xtgeo.well.well1 import Well
|
|
28
|
+
|
|
29
|
+
|
|
24
30
|
logger = null_logger(__name__)
|
|
25
31
|
|
|
26
32
|
|
|
@@ -56,11 +62,11 @@ class _OptionalMetaData:
|
|
|
56
62
|
def __init__(self) -> None:
|
|
57
63
|
self._name = "A Longer Descriptive Name e.g. from SMDA"
|
|
58
64
|
self._shortname = "TheShortName"
|
|
59
|
-
self._datatype = None
|
|
65
|
+
self._datatype: str | None = None
|
|
60
66
|
self._md5sum: str | None = None
|
|
61
67
|
self._description = "Some description"
|
|
62
68
|
self._crs = None
|
|
63
|
-
self._datetime: datetime | None = None
|
|
69
|
+
self._datetime: datetime | str | None = None
|
|
64
70
|
self._deltadatetime = None
|
|
65
71
|
self._visuals = {"colortable": "rainbow", "lower": None, "upper": None}
|
|
66
72
|
self._domain = "depth"
|
|
@@ -84,11 +90,11 @@ class _OptionalMetaData:
|
|
|
84
90
|
self._name = newname
|
|
85
91
|
|
|
86
92
|
@property
|
|
87
|
-
def datetime(self) -> datetime | None:
|
|
93
|
+
def datetime(self) -> datetime | str | None:
|
|
88
94
|
return self._datetime
|
|
89
95
|
|
|
90
96
|
@datetime.setter
|
|
91
|
-
def datetime(self, newdate: datetime) -> None:
|
|
97
|
+
def datetime(self, newdate: datetime | str) -> None:
|
|
92
98
|
# TODO: validation
|
|
93
99
|
self._datetime = newdate
|
|
94
100
|
|
|
@@ -147,15 +153,15 @@ class _OptionalMetaData:
|
|
|
147
153
|
class MetaData:
|
|
148
154
|
"""Generic metadata class, not intended to be used directly."""
|
|
149
155
|
|
|
150
|
-
def __init__(self):
|
|
156
|
+
def __init__(self) -> None:
|
|
151
157
|
"""Generic metadata class __init__, not be used directly."""
|
|
152
|
-
self._required = {}
|
|
158
|
+
self._required: dict[str, Any] = {}
|
|
153
159
|
self._optional = _OptionalMetaData()
|
|
154
160
|
self._freeform = {}
|
|
155
161
|
|
|
156
162
|
self._freeform = {"smda": "whatever"}
|
|
157
163
|
|
|
158
|
-
def get_metadata(self):
|
|
164
|
+
def get_metadata(self) -> dict[str, Any]:
|
|
159
165
|
"""Get all metadata that are present."""
|
|
160
166
|
allmeta = {}
|
|
161
167
|
allmeta["_required_"] = self._required
|
|
@@ -164,7 +170,7 @@ class MetaData:
|
|
|
164
170
|
return allmeta
|
|
165
171
|
|
|
166
172
|
@property
|
|
167
|
-
def optional(self):
|
|
173
|
+
def optional(self) -> dict[str, Any]:
|
|
168
174
|
"""Return or set optional metadata.
|
|
169
175
|
|
|
170
176
|
When setting optional names, it can be done in several ways...
|
|
@@ -176,7 +182,7 @@ class MetaData:
|
|
|
176
182
|
return self._optional.get_meta()
|
|
177
183
|
|
|
178
184
|
@optional.setter
|
|
179
|
-
def optional(self, indict):
|
|
185
|
+
def optional(self, indict: dict[str, Any]) -> None:
|
|
180
186
|
# setting the optional key, including validation
|
|
181
187
|
if not isinstance(indict, dict):
|
|
182
188
|
raise ValueError(f"Input must be a dictionary, not a {type(indict)}")
|
|
@@ -185,7 +191,7 @@ class MetaData:
|
|
|
185
191
|
setattr(self._optional, "_" + key, value)
|
|
186
192
|
|
|
187
193
|
@property
|
|
188
|
-
def opt(self):
|
|
194
|
+
def opt(self) -> _OptionalMetaData:
|
|
189
195
|
"""Return the metadata optional instance.
|
|
190
196
|
|
|
191
197
|
This makes access to the _OptionalMetaData instance.
|
|
@@ -198,26 +204,17 @@ class MetaData:
|
|
|
198
204
|
"""
|
|
199
205
|
return self._optional
|
|
200
206
|
|
|
201
|
-
@optional.setter
|
|
202
|
-
def optional(self, indict):
|
|
203
|
-
# setting the optional key, including validation
|
|
204
|
-
if not isinstance(indict, dict):
|
|
205
|
-
raise ValueError(f"Input must be a dictionary, not a {type(indict)}")
|
|
206
|
-
|
|
207
|
-
for key, value in indict.items():
|
|
208
|
-
setattr(self._optional, "_" + key, value)
|
|
209
|
-
|
|
210
207
|
@property
|
|
211
|
-
def freeform(self):
|
|
208
|
+
def freeform(self) -> dict[str, Any]:
|
|
212
209
|
"""Get or set the current freeform metadata dictionary."""
|
|
213
210
|
return self._freeform
|
|
214
211
|
|
|
215
212
|
@freeform.setter
|
|
216
|
-
def freeform(self, adict):
|
|
213
|
+
def freeform(self, adict: dict[str, Any]) -> None:
|
|
217
214
|
"""Freeform is a whatever you want set, without any validation."""
|
|
218
215
|
self._freeform = adict.copy()
|
|
219
216
|
|
|
220
|
-
def generate_fmu_name(self):
|
|
217
|
+
def generate_fmu_name(self) -> str:
|
|
221
218
|
"""Generate FMU name on form xxxx--yyyy--date but no suffix."""
|
|
222
219
|
fname = ""
|
|
223
220
|
first = "prefix"
|
|
@@ -233,7 +230,7 @@ class MetaData:
|
|
|
233
230
|
class MetaDataRegularSurface(MetaData):
|
|
234
231
|
"""Metadata for RegularSurface() objects."""
|
|
235
232
|
|
|
236
|
-
REQUIRED = {
|
|
233
|
+
REQUIRED: dict[str, Any] = {
|
|
237
234
|
"ncol": 1,
|
|
238
235
|
"nrow": 1,
|
|
239
236
|
"xori": 0.0,
|
|
@@ -245,20 +242,20 @@ class MetaDataRegularSurface(MetaData):
|
|
|
245
242
|
"undef": UNDEF,
|
|
246
243
|
}
|
|
247
244
|
|
|
248
|
-
def __init__(self):
|
|
245
|
+
def __init__(self) -> None:
|
|
249
246
|
"""Docstring."""
|
|
250
247
|
super().__init__()
|
|
251
|
-
self._required =
|
|
248
|
+
self._required = self.REQUIRED
|
|
252
249
|
self._optional._datatype = "Regular Surface"
|
|
253
250
|
|
|
254
251
|
@property
|
|
255
|
-
def required(self):
|
|
252
|
+
def required(self) -> dict[str, Any]:
|
|
256
253
|
"""Get of set required metadata."""
|
|
257
254
|
return self._required
|
|
258
255
|
|
|
259
256
|
@required.setter
|
|
260
|
-
def required(self, obj):
|
|
261
|
-
if not isinstance(obj, xtgeo.RegularSurface):
|
|
257
|
+
def required(self, obj: RegularSurface) -> None:
|
|
258
|
+
if not isinstance(obj, xtgeo.RegularSurface): # type: ignore[attr-defined]
|
|
262
259
|
raise ValueError("Input object is not a RegularSurface()")
|
|
263
260
|
|
|
264
261
|
self._required["ncol"] = obj.ncol
|
|
@@ -276,7 +273,7 @@ class MetaDataRegularCube(MetaData):
|
|
|
276
273
|
"""Metadata for Cube() objects."""
|
|
277
274
|
|
|
278
275
|
# allowed optional keys; these are set to avoid discussions
|
|
279
|
-
REQUIRED = {
|
|
276
|
+
REQUIRED: dict[str, Any] = {
|
|
280
277
|
"ncol": 1,
|
|
281
278
|
"nrow": 1,
|
|
282
279
|
"nlay": 1,
|
|
@@ -292,20 +289,20 @@ class MetaDataRegularCube(MetaData):
|
|
|
292
289
|
"undef": UNDEF,
|
|
293
290
|
}
|
|
294
291
|
|
|
295
|
-
def __init__(self):
|
|
292
|
+
def __init__(self) -> None:
|
|
296
293
|
"""Docstring."""
|
|
297
294
|
super().__init__()
|
|
298
|
-
self._required =
|
|
295
|
+
self._required = self.REQUIRED
|
|
299
296
|
self._optional._datatype = "Regular Cube"
|
|
300
297
|
|
|
301
298
|
@property
|
|
302
|
-
def required(self):
|
|
299
|
+
def required(self) -> dict[str, Any]:
|
|
303
300
|
"""Get of set required metadata."""
|
|
304
301
|
return self._required
|
|
305
302
|
|
|
306
303
|
@required.setter
|
|
307
|
-
def required(self, obj):
|
|
308
|
-
if not isinstance(obj, xtgeo.Cube):
|
|
304
|
+
def required(self, obj: Cube) -> None:
|
|
305
|
+
if not isinstance(obj, xtgeo.Cube): # type: ignore[attr-defined]
|
|
309
306
|
raise ValueError("Input object is not a regular Cube()")
|
|
310
307
|
|
|
311
308
|
self._required["ncol"] = obj.ncol
|
|
@@ -326,7 +323,7 @@ class MetaDataRegularCube(MetaData):
|
|
|
326
323
|
class MetaDataCPGeometry(MetaData):
|
|
327
324
|
"""Metadata for Grid() objects of type simplified CornerPoint Geometry."""
|
|
328
325
|
|
|
329
|
-
REQUIRED = {
|
|
326
|
+
REQUIRED: dict[str, Any] = {
|
|
330
327
|
"ncol": 1,
|
|
331
328
|
"nrow": 1,
|
|
332
329
|
"nlay": 1,
|
|
@@ -338,20 +335,20 @@ class MetaDataCPGeometry(MetaData):
|
|
|
338
335
|
"zscale": 1.0,
|
|
339
336
|
}
|
|
340
337
|
|
|
341
|
-
def __init__(self):
|
|
338
|
+
def __init__(self) -> None:
|
|
342
339
|
"""Docstring."""
|
|
343
340
|
super().__init__()
|
|
344
|
-
self._required =
|
|
341
|
+
self._required = self.REQUIRED
|
|
345
342
|
self._optional._datatype = "CornerPoint GridGeometry"
|
|
346
343
|
|
|
347
344
|
@property
|
|
348
|
-
def required(self):
|
|
345
|
+
def required(self) -> dict[str, Any]:
|
|
349
346
|
"""Get of set required metadata."""
|
|
350
347
|
return self._required
|
|
351
348
|
|
|
352
349
|
@required.setter
|
|
353
|
-
def required(self, obj):
|
|
354
|
-
if not isinstance(obj, xtgeo.Grid):
|
|
350
|
+
def required(self, obj: Grid) -> None:
|
|
351
|
+
if not isinstance(obj, xtgeo.Grid): # type: ignore[attr-defined]
|
|
355
352
|
raise ValueError("Input object is not a Grid()")
|
|
356
353
|
|
|
357
354
|
self._required["ncol"] = obj.ncol
|
|
@@ -369,7 +366,7 @@ class MetaDataCPGeometry(MetaData):
|
|
|
369
366
|
class MetaDataCPProperty(MetaData):
|
|
370
367
|
"""Metadata for GridProperty() objects belonging to CPGeometry."""
|
|
371
368
|
|
|
372
|
-
REQUIRED = {
|
|
369
|
+
REQUIRED: dict[str, Any] = {
|
|
373
370
|
"ncol": 1,
|
|
374
371
|
"nrow": 1,
|
|
375
372
|
"nlay": 1,
|
|
@@ -377,20 +374,20 @@ class MetaDataCPProperty(MetaData):
|
|
|
377
374
|
"discrete": False,
|
|
378
375
|
}
|
|
379
376
|
|
|
380
|
-
def __init__(self):
|
|
377
|
+
def __init__(self) -> None:
|
|
381
378
|
"""Docstring."""
|
|
382
379
|
super().__init__()
|
|
383
|
-
self._required =
|
|
380
|
+
self._required = self.REQUIRED
|
|
384
381
|
self._optional._datatype = "CornerPoint GridProperty"
|
|
385
382
|
|
|
386
383
|
@property
|
|
387
|
-
def required(self):
|
|
384
|
+
def required(self) -> dict[str, Any]:
|
|
388
385
|
"""Get of set required metadata."""
|
|
389
386
|
return self._required
|
|
390
387
|
|
|
391
388
|
@required.setter
|
|
392
|
-
def required(self, obj):
|
|
393
|
-
if not isinstance(obj, xtgeo.GridProperty):
|
|
389
|
+
def required(self, obj: GridProperty) -> None:
|
|
390
|
+
if not isinstance(obj, xtgeo.GridProperty): # type: ignore[attr-defined]
|
|
394
391
|
raise ValueError("Input object is not a GridProperty()")
|
|
395
392
|
|
|
396
393
|
self._required["ncol"] = obj.ncol
|
|
@@ -403,7 +400,7 @@ class MetaDataCPProperty(MetaData):
|
|
|
403
400
|
class MetaDataWell(MetaData):
|
|
404
401
|
"""Metadata for single Well() objects."""
|
|
405
402
|
|
|
406
|
-
REQUIRED = {
|
|
403
|
+
REQUIRED: dict[str, Any] = {
|
|
407
404
|
"rkb": 0.0,
|
|
408
405
|
"xpos": 0.0,
|
|
409
406
|
"ypos": 0.0,
|
|
@@ -413,20 +410,20 @@ class MetaDataWell(MetaData):
|
|
|
413
410
|
"zonelogname": None,
|
|
414
411
|
}
|
|
415
412
|
|
|
416
|
-
def __init__(self):
|
|
413
|
+
def __init__(self) -> None:
|
|
417
414
|
"""Initialisation for Well metadata."""
|
|
418
415
|
super().__init__()
|
|
419
|
-
self._required =
|
|
416
|
+
self._required = self.REQUIRED
|
|
420
417
|
self._optional._datatype = "Well"
|
|
421
418
|
|
|
422
419
|
@property
|
|
423
|
-
def required(self):
|
|
420
|
+
def required(self) -> dict[str, Any]:
|
|
424
421
|
"""Get of set required metadata."""
|
|
425
422
|
return self._required
|
|
426
423
|
|
|
427
424
|
@required.setter
|
|
428
|
-
def required(self, obj):
|
|
429
|
-
if not isinstance(obj, xtgeo.Well):
|
|
425
|
+
def required(self, obj: Well) -> None:
|
|
426
|
+
if not isinstance(obj, xtgeo.Well): # type: ignore[attr-defined]
|
|
430
427
|
raise ValueError("Input object is not a Well() instance!")
|
|
431
428
|
|
|
432
429
|
self._required["rkb"] = obj.rkb
|