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.

@@ -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)
@@ -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, max_val = np.iinfo(dtype).min, np.iinfo(dtype).max
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, max_val = np.finfo(dtype).min, np.finfo(dtype).max
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
- ) -> None:
2481
- """Translate (move) and/or flip grid coordinates in 3D.
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 array are multiplied
2484
- with -1.
2491
+ By 'flip' here, it means that the full coordinate arrays are inverted.
2485
2492
 
2486
2493
  Args:
2487
- translate (tuple): Translation distance in X, Y, Z coordinates
2488
- flip (tuple): Flip array. The flip values must be 1 or -1.
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
- _grid_etc1.translate_coordinates(self, translate=translate, flip=flip)
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 stated.
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 (int): Number of hybrid layers.
2560
- toplevel (float): Top of hybrid grid.
2561
- bottomlevel (float): Base of hybrid grid.
2562
- region (GridProperty, optional): Region property (if needed).
2563
- region_number (int): Which region to apply hybrid grid in if region.
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 '.'
@@ -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 = __class__.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 = __class__.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 = __class__.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 = __class__.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 = __class__.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