resqpy 4.16.10.dev2__py3-none-any.whl → 4.17.0__py3-none-any.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.
resqpy/__init__.py CHANGED
@@ -28,6 +28,6 @@
28
28
 
29
29
  import logging
30
30
 
31
- __version__ = "4.16.10.dev2" # Set at build time
31
+ __version__ = "4.17.0" # Set at build time
32
32
  log = logging.getLogger(__name__)
33
33
  log.info(f"Imported resqpy version {__version__}")
@@ -118,7 +118,7 @@ class GridConnectionSet(BaseResqpy):
118
118
  self.cell_index_pairs = None #: shape (count, 2); dtype int; index normalized for flattened array
119
119
  self.cell_index_pairs_null_value = -1 #: integer null value for array above
120
120
  self.grid_index_pairs = None #: shape (count, 2); dtype int; optional; used if more than one grid referenced
121
- self.face_index_pairs = None #: shape (count, 2); dtype int32; local to cell, ie. range 0 to 5
121
+ self.face_index_pairs = None #: shape (count, 2); dtype int8; local to cell, ie. range 0 to 5
122
122
  self.face_index_pairs_null_value = -1 #: integer null value for array above
123
123
  # NB face index values 0..5 usually mean [K-, K+, J+, I+, J-, I-] respectively but there is some ambiguity
124
124
  # over I & J in the Energistics RESQML Usage Guide; see comments in DevOps backlog item 269001 for more info
@@ -129,17 +129,18 @@ class GridConnectionSet(BaseResqpy):
129
129
  self.feature_list = None #: ordered list, actually of interpretations, indexed by feature_indices
130
130
  # feature list contains tuples: (content_type, uuid, title) for fault features (or other interpretations)
131
131
  self.property_collection = None #: optional property.PropertyCollection
132
+ self.cell_index_dtype = np.int32 #: set to int64 if any grid is big, otherwise int32
132
133
 
133
134
  # NB: RESQML documentation is not clear which order is correct; should be kept consistent with same data in property.py
134
135
  # face_index_map maps from (axis, p01) to face index value in range 0..5
135
136
  # this is the default as indicated on page 139 (but not p. 180) of the RESQML Usage Gude v2.0.1
136
137
  # also assumes K is generally increasing downwards
137
138
  # see DevOps backlog item 269001 discussion for more information
138
- # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = int)
139
- self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = int) # order: top, base, J-, I+, J+, I-
139
+ # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = np.int8)
140
+ self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = np.int8) # order: top, base, J-, I+, J+, I-
140
141
  # and the inverse, maps from 0..5 to (axis, p01)
141
- # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = int)
142
- self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = int)
142
+ # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = np.int8)
143
+ self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = np.int8)
143
144
  # note: the rework_face_pairs() method, below, overwrites the face indices based on I, J cell indices
144
145
  if not title:
145
146
  title = feature_name
@@ -196,6 +197,7 @@ class GridConnectionSet(BaseResqpy):
196
197
  self.cache_arrays()
197
198
  if find_properties:
198
199
  self.extract_property_collection()
200
+ self._set_cell_index_dtype()
199
201
 
200
202
  @classmethod
201
203
  def from_gcs_uuid_list(cls,
@@ -357,6 +359,14 @@ class GridConnectionSet(BaseResqpy):
357
359
  self.property_collection = rqp.PropertyCollection(support = self)
358
360
  return self.property_collection
359
361
 
362
+ def _set_cell_index_dtype(self):
363
+ """Determines whether to use int32 or int64 for normalised cell indices."""
364
+ self.cell_index_dtype = np.int32
365
+ for g in self.grid_list:
366
+ if g.is_big():
367
+ self.cell_index_dtype = np.int64
368
+ break
369
+
360
370
  def set_pairs_from_kelp(self,
361
371
  kelp_0,
362
372
  kelp_1,
@@ -394,7 +404,7 @@ class GridConnectionSet(BaseResqpy):
394
404
  k_layer = np.zeros((grid.nk - 1, grid.ni), dtype = bool)
395
405
  else:
396
406
  k_layer = np.zeros((grid.nk - 1, grid.nj), dtype = bool)
397
- kelp_a = np.array(kelp_k, dtype = int).T
407
+ kelp_a = np.array(kelp_k, dtype = np.int32).T
398
408
  k_layer[kelp_a[0], kelp_a[1]] = True
399
409
  k_faces = np.zeros((grid.nk - 1, grid.nj, grid.ni), dtype = bool)
400
410
  if axis == 'J':
@@ -408,7 +418,7 @@ class GridConnectionSet(BaseResqpy):
408
418
  j_layer = np.zeros((grid.nj - 1, grid.ni), dtype = bool)
409
419
  else:
410
420
  j_layer = np.zeros((grid.nk, grid.nj - 1), dtype = bool)
411
- kelp_a = np.array(kelp_j, dtype = int).T
421
+ kelp_a = np.array(kelp_j, dtype = np.int32).T
412
422
  j_layer[kelp_a[0], kelp_a[1]] = True
413
423
  j_faces = np.zeros((grid.nk, grid.nj - 1, grid.ni), dtype = bool)
414
424
  if axis == 'K':
@@ -422,7 +432,7 @@ class GridConnectionSet(BaseResqpy):
422
432
  i_layer = np.zeros((grid.nj, grid.ni - 1), dtype = bool)
423
433
  else:
424
434
  i_layer = np.zeros((grid.nk, grid.ni - 1), dtype = bool)
425
- kelp_a = np.array(kelp_i, dtype = int).T
435
+ kelp_a = np.array(kelp_i, dtype = np.int32).T
426
436
  i_layer[kelp_a[0], kelp_a[1]] = True
427
437
  i_faces = np.zeros((grid.nk, grid.nj, grid.ni - 1), dtype = bool)
428
438
  if axis == 'K':
@@ -548,10 +558,10 @@ class GridConnectionSet(BaseResqpy):
548
558
  else:
549
559
  cell_pair_list.append((cell, cell + 1))
550
560
  face_pair_list.append((self.face_index_map[2, 1], self.face_index_map[2, 0]))
551
- self.cell_index_pairs = np.array(cell_pair_list, dtype = int)
552
- self.face_index_pairs = np.array(face_pair_list, dtype = int)
561
+ self.cell_index_pairs = np.array(cell_pair_list, dtype = self.cell_index_dtype)
562
+ self.face_index_pairs = np.array(face_pair_list, dtype = np.int8)
553
563
  self.count = len(self.cell_index_pairs)
554
- self.feature_indices = np.zeros(self.count, dtype = int)
564
+ self.feature_indices = np.zeros(self.count, dtype = np.int32)
555
565
  assert len(self.face_index_pairs) == self.count
556
566
 
557
567
  def set_pairs_from_faces_df(self,
@@ -609,9 +619,9 @@ class GridConnectionSet(BaseResqpy):
609
619
  if success:
610
620
  feature_index += 1
611
621
 
612
- self.feature_indices = np.array(fi_list, dtype = int)
613
- self.cell_index_pairs = np.array(cell_pair_list, dtype = int)
614
- self.face_index_pairs = np.array(face_pair_list, dtype = int)
622
+ self.feature_indices = np.array(fi_list, dtype = np.int32)
623
+ self.cell_index_pairs = np.array(cell_pair_list, dtype = self.cell_index_dtype)
624
+ self.face_index_pairs = np.array(face_pair_list, dtype = np.int8)
615
625
  self.count = len(self.cell_index_pairs)
616
626
  assert len(self.face_index_pairs) == self.count
617
627
  if create_mult_prop and self.count > 0:
@@ -696,7 +706,7 @@ class GridConnectionSet(BaseResqpy):
696
706
  singleton.cell_index_pairs, singleton.face_index_pairs = \
697
707
  self.raw_list_of_cell_face_pairs_for_feature_index(feature_index)
698
708
  singleton.count = singleton.cell_index_pairs.shape[0]
699
- singleton.feature_indices = np.zeros((singleton.count,), dtype = int)
709
+ singleton.feature_indices = np.zeros((singleton.count,), dtype = np.int32)
700
710
  singleton.feature_list = [self.feature_list[feature_index]]
701
711
  return singleton
702
712
 
@@ -823,7 +833,7 @@ class GridConnectionSet(BaseResqpy):
823
833
  cache_array = True,
824
834
  object = self,
825
835
  array_attribute = 'cell_index_pairs',
826
- dtype = 'int')
836
+ dtype = 'int64' if self.cell_index_dtype is np.int64 else 'int32')
827
837
 
828
838
  if self.face_index_pairs is None:
829
839
  log.debug('caching face index pairs from hdf5')
@@ -834,7 +844,7 @@ class GridConnectionSet(BaseResqpy):
834
844
  cache_array = True,
835
845
  object = self,
836
846
  array_attribute = 'face_index_pairs',
837
- dtype = 'int32')
847
+ dtype = 'int8')
838
848
 
839
849
  if len(self.grid_list) > 1 and self.grid_index_pairs is None:
840
850
  grid_index_node = rqet.find_tag(self.root, 'GridIndexPairs')
@@ -845,7 +855,7 @@ class GridConnectionSet(BaseResqpy):
845
855
  cache_array = True,
846
856
  object = self,
847
857
  array_attribute = 'grid_index_pairs',
848
- dtype = 'int')
858
+ dtype = 'int32' if len(self.grid_list) > 127 else 'int8')
849
859
 
850
860
  if self.feature_list is None:
851
861
  return
@@ -854,18 +864,18 @@ class GridConnectionSet(BaseResqpy):
854
864
  if self.feature_indices is None:
855
865
  log.debug('caching feature indices')
856
866
  elements_node = rqet.find_nested_tags(interp_root, ['InterpretationIndices', 'Elements'])
857
- # elements_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'Elements'])
867
+ # elements_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'Elements'])
858
868
  h5_key_pair = self.model.h5_uuid_and_path_for_node(elements_node, tag = 'Values')
859
869
  assert h5_key_pair is not None
860
870
  self.model.h5_array_element(h5_key_pair,
861
871
  cache_array = True,
862
872
  object = self,
863
873
  array_attribute = 'feature_indices',
864
- dtype = 'uint32')
874
+ dtype = 'int32')
865
875
  assert self.feature_indices.shape == (self.count,)
866
876
 
867
877
  cl_node = rqet.find_nested_tags(interp_root, ['InterpretationIndices', 'CumulativeLength'])
868
- # cl_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'CumulativeLength'])
878
+ # cl_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'CumulativeLength'])
869
879
  h5_key_pair = self.model.h5_uuid_and_path_for_node(cl_node, tag = 'Values')
870
880
  assert h5_key_pair is not None
871
881
  self.model.h5_array_element(h5_key_pair,
@@ -873,8 +883,8 @@ class GridConnectionSet(BaseResqpy):
873
883
  object = self,
874
884
  array_attribute = 'fi_cl',
875
885
  dtype = 'uint32')
876
- assert self.fi_cl.shape == (
877
- self.count,), 'connection set face pair(s) not assigned to exactly one feature' # rough check
886
+ assert self.fi_cl.shape == (self.count,), \
887
+ 'connection set face pair(s) not assigned to exactly one feature' # rough check
878
888
 
879
889
  # delattr(self, 'fi_cl') # assumed to be one-to-one mapping, so cumulative length is discarded
880
890
 
@@ -1196,7 +1206,7 @@ class GridConnectionSet(BaseResqpy):
1196
1206
  # uuid/InterpretationIndices/elements (N,) uint32
1197
1207
  h5_reg.register_dataset(self.uuid, 'InterpretationIndices/elements', self.feature_indices)
1198
1208
  # uuid/InterpretationIndices/cumulativeLength (N,) uint32
1199
- one_to_one = np.arange(1, self.count + 1, dtype = int)
1209
+ one_to_one = np.arange(1, self.count + 1, dtype = np.uint32)
1200
1210
  h5_reg.register_dataset(self.uuid, 'InterpretationIndices/cumulativeLength', one_to_one)
1201
1211
 
1202
1212
  h5_reg.write(file_name, mode = mode)
@@ -1371,11 +1381,16 @@ class GridConnectionSet(BaseResqpy):
1371
1381
  include_both_sides = False,
1372
1382
  use_minus = False,
1373
1383
  trans_mult_uuid = None):
1374
- """Creates a Nexus include file holding MULT keywords and data. trans_mult_uuid (optional) is the uuid of a property on the gcs containing transmissibility multiplier values. If not provided values of 1.0 will be used."""
1384
+ """Creates a Nexus include file holding MULT keywords and data.
1385
+
1386
+ note:
1387
+ trans_mult_uuid (optional) is the uuid of a property on the gcs containing transmissibility multiplier values;
1388
+ If not provided values of 1.0 will be used
1389
+ """
1375
1390
  if trans_mult_uuid is not None:
1376
1391
  self.extract_property_collection()
1377
- assert self.property_collection.part_in_collection(self.model.part_for_uuid(
1378
- trans_mult_uuid)), f'trans_mult_uuid provided is not part of collection {trans_mult_uuid}'
1392
+ assert self.property_collection.part_in_collection(self.model.part_for_uuid(trans_mult_uuid)), \
1393
+ f'trans_mult_uuid provided is not part of collection {trans_mult_uuid}'
1379
1394
  tmult_array = self.property_collection.cached_part_array_ref(self.model.part_for_uuid(trans_mult_uuid))
1380
1395
  assert tmult_array is not None
1381
1396
  else:
@@ -1421,26 +1436,39 @@ class GridConnectionSet(BaseResqpy):
1421
1436
  feature_name = self.feature_list[feature_index][2].split()[0].upper()
1422
1437
  cell_index_pairs, face_index_pairs = self.list_of_cell_face_pairs_for_feature_index(feature_index)
1423
1438
  if tmult_array is not None:
1424
- feature_mask = np.where(self.feature_indices == feature_index, 1, 0)
1439
+ feature_mask = (self.feature_indices == feature_index)
1425
1440
  feat_mult_array = np.extract(feature_mask, tmult_array)
1426
1441
  else:
1427
1442
  feat_mult_array = np.ones(shape = (cell_index_pairs.shape[0],), dtype = float)
1428
1443
  for side in sides:
1429
- both = np.empty((cell_index_pairs.shape[0], 6), dtype = int) # axis, polarity, k, j, i, tmult
1444
+ both = np.empty((cell_index_pairs.shape[0], 5), dtype = np.int32) # axis, polarity, k, j, i
1430
1445
  both[:, :2] = face_index_pairs[:, side, :] # axis, polarity
1431
- both[:, 2:-1] = cell_index_pairs[:, side, :] # k, j, i
1432
- both[:, -1] = feat_mult_array.flatten()
1433
- df = pd.DataFrame(both, columns = ['axis', 'polarity', 'k', 'j', 'i', 'tmult'])
1434
- df = df.sort_values(by = ['axis', 'polarity', 'j', 'i', 'k', 'tmult'])
1435
- both_sorted = np.empty(both.shape, dtype = int)
1436
- both_sorted[:] = df
1437
- cell_indices = both_sorted[:, 2:-1]
1438
- face_indices = np.empty((both_sorted.shape[0], 2), dtype = int)
1439
- face_indices[:, :] = both_sorted[:, :2]
1440
- tmult_values = both_sorted[:, -1]
1441
- del both_sorted
1446
+ both[:, 2:] = cell_index_pairs[:, side, :] # k, j, i
1447
+ # both[:, -1] = feat_mult_array.flatten()
1448
+ # df = pd.DataFrame(both, columns = ['axis', 'polarity', 'k', 'j', 'i', 'tmult'])
1449
+ # df = df.sort_values(by = ['axis', 'polarity', 'j', 'i', 'k', 'tmult'])
1450
+ # both_sorted = np.empty(both.shape, dtype = np.int32)
1451
+ # both_sorted[:] = df
1452
+ si = np.argsort(both[:, 2]) # k
1453
+ msi = si
1454
+ both = both[si]
1455
+ si = np.argsort(both[:, 4], kind = 'stable') # i
1456
+ msi = msi[si]
1457
+ both = both[si]
1458
+ si = np.argsort(both[:, 3], kind = 'stable') # j
1459
+ msi = msi[si]
1460
+ both = both[si]
1461
+ si = np.argsort(both[:, 1], kind = 'stable') # polarity
1462
+ msi = msi[si]
1463
+ both = both[si]
1464
+ si = np.argsort(both[:, 0], kind = 'stable') # axis
1465
+ msi = msi[si]
1466
+ both = both[si]
1467
+ cell_indices = both[:, 2:]
1468
+ face_indices = np.empty((both.shape[0], 2), dtype = np.int8)
1469
+ face_indices[:, :] = both[:, :2]
1470
+ tmult_values = feat_mult_array[msi]
1442
1471
  del both
1443
- del df
1444
1472
  k = None
1445
1473
  i = j = k2 = axis = polarity = None # only needed to placate flake8 which whinges incorrectly otherwise
1446
1474
  for row in range(cell_indices.shape[0]):
@@ -1692,7 +1720,7 @@ class GridConnectionSet(BaseResqpy):
1692
1720
  combined_values = property_value_by_column_edge.copy()
1693
1721
  else:
1694
1722
  combined_values = None
1695
- combined_index = np.full((fault_by_column_edge_mask.shape), -1, dtype = int)
1723
+ combined_index = np.full((fault_by_column_edge_mask.shape), -1, dtype = np.int32)
1696
1724
  combined_index = np.where(fault_by_column_edge_mask, feature, combined_index)
1697
1725
  sum_unmasked = np.sum(fault_by_column_edge_mask)
1698
1726
  else:
@@ -1802,7 +1830,7 @@ class GridConnectionSet(BaseResqpy):
1802
1830
  def sorted_paired_cell_face_index_position(cell_face_index, a_or_b):
1803
1831
  # pair one side (a_or_b) of cell_face_index with its position, then sort
1804
1832
  count = len(cell_face_index)
1805
- sp = np.empty((count, 2), dtype = int)
1833
+ sp = np.empty((count, 2), dtype = np.int32)
1806
1834
  sp[:, 0] = cell_face_index[:, a_or_b]
1807
1835
  sp[:, 1] = np.arange(count)
1808
1836
  t = [tuple(r) for r in sp] # could use numpy fields based sort instead of tuple list?
@@ -1985,19 +2013,19 @@ class GridConnectionSet(BaseResqpy):
1985
2013
  for k0 in range(entry['k1'], entry['k2'] + 1):
1986
2014
  for j0 in range(entry['j1'], entry['j2'] + 1):
1987
2015
  for i0 in range(entry['i1'], entry['i2'] + 1):
1988
- neighbour = np.array([k0, j0, i0], dtype = int)
2016
+ neighbour = np.array([k0, j0, i0], dtype = np.int32)
1989
2017
  if fp:
1990
2018
  neighbour[axis] += 1
1991
2019
  else:
1992
2020
  neighbour[axis] -= 1
1993
2021
  fi_list.append(feature_index)
1994
- cell_pair_list.append((grid.natural_cell_index(
1995
- (k0, j0, i0)), grid.natural_cell_index(neighbour)))
2022
+ cell_pair_list.append((grid.natural_cell_index((k0, j0, i0)), \
2023
+ grid.natural_cell_index(neighbour)))
1996
2024
  face_pair_list.append((self.face_index_map[axis, fp], self.face_index_map[axis, 1 - fp]))
1997
2025
  if create_mult_prop:
1998
2026
  mult_list.append(multiplier)
1999
2027
  if fi_root is not None and fault_const_mult and fault_mult_value is not None:
2000
- #patch extra_metadata into xml for new fault interpretation object
2028
+ # patch extra_metadata into xml for new fault interpretation object
2001
2029
  rqet.create_metadata_xml(fi_root, {"Transmissibility multiplier": str(fault_mult_value)})
2002
2030
  return True, const_mult
2003
2031
 
resqpy/grid/_grid.py CHANGED
@@ -265,6 +265,10 @@ class Grid(BaseResqpy):
265
265
  return np.count_nonzero(self.array_cell_geometry_is_defined)
266
266
  return None
267
267
 
268
+ def is_big(self):
269
+ """Returns True if number of cells exceeds 2^31 - 1, otherwise False."""
270
+ return (np.prod(self.extent_kji) >= 2_147_483_648)
271
+
268
272
  def natural_cell_index(self, cell_kji0):
269
273
  """Returns a single integer for the cell, being the index into a flattened array."""
270
274
 
@@ -118,7 +118,7 @@ def populate_blocked_well_from_trajectory(blocked_well,
118
118
  if xyz is None:
119
119
  log.error('failed to lazily find intersection of trajectory with top surface of grid')
120
120
  return None
121
- cell_kji0 = np.array((0, col_ji0[0], col_ji0[1]), dtype = int)
121
+ cell_kji0 = np.array((0, col_ji0[0], col_ji0[1]), dtype = np.int32)
122
122
  axis = 0
123
123
  polarity = 0
124
124
 
@@ -133,7 +133,7 @@ def populate_blocked_well_from_trajectory(blocked_well,
133
133
  else:
134
134
  log.debug(f"skin intersection x,y,z: {xyz}; knot: {entry_knot}; cell kji0: {cell_kji0}; face: "
135
135
  f"{'KJI'[axis]}{'-+'[polarity]}")
136
- cell_kji0 = np.array(cell_kji0, dtype = int)
136
+ cell_kji0 = np.array(cell_kji0, dtype = np.int32)
137
137
 
138
138
  previous_kji0 = cell_kji0.copy()
139
139
  previous_kji0[axis] += polarity * 2 - 1 # note: previous may legitimately be 'beyond' edge of grid
@@ -244,9 +244,9 @@ def populate_blocked_well_from_trajectory(blocked_well,
244
244
 
245
245
  blocked_well.node_mds = np.array(node_mds_list, dtype = float)
246
246
  blocked_well.node_count = node_count
247
- blocked_well.grid_indices = np.array(grid_indices_list, dtype = int)
248
- blocked_well.cell_indices = np.array(cell_indices_list, dtype = int)
249
- blocked_well.face_pair_indices = np.array(face_pairs_list, dtype = int)
247
+ blocked_well.grid_indices = np.array(grid_indices_list, dtype = np.int32)
248
+ blocked_well.cell_indices = np.array(cell_indices_list, dtype = np.int64)
249
+ blocked_well.face_pair_indices = np.array(face_pairs_list, dtype = np.int8)
250
250
  blocked_well.cell_count = cell_count
251
251
  blocked_well.grid_list = [grid]
252
252
 
@@ -599,6 +599,7 @@ def find_faces_to_represent_surface_regular_optimised(grid,
599
599
  grid.block_dxyz_dkji[0, 2],
600
600
  )
601
601
  triangles, points = surface.triangles_and_points()
602
+ t_dtype = np.int32 if len(triangles) < 2_000_000_000 else np.int64
602
603
  assert (triangles is not None and points is not None), f"surface {surface.title} is empty"
603
604
  if agitate:
604
605
  if random_agitation:
@@ -622,7 +623,7 @@ def find_faces_to_represent_surface_regular_optimised(grid,
622
623
  if nk > 1:
623
624
  # log.debug("searching for k faces")
624
625
  k_faces = np.zeros((nk - 1, grid.nj, grid.ni), dtype = bool)
625
- k_triangles = np.full((nk - 1, grid.nj, grid.ni), -1, dtype = int)
626
+ k_triangles = np.full((nk - 1, grid.nj, grid.ni), -1, dtype = t_dtype)
626
627
  k_depths = np.full((nk - 1, grid.nj, grid.ni), np.nan)
627
628
  k_offsets = np.full((nk - 1, grid.nj, grid.ni), np.nan)
628
629
  p_xy = np.delete(points, 2, 1)
@@ -666,7 +667,7 @@ def find_faces_to_represent_surface_regular_optimised(grid,
666
667
  if grid.nj > 1:
667
668
  # log.debug("searching for j faces")
668
669
  j_faces = np.zeros((nk, grid.nj - 1, grid.ni), dtype = bool)
669
- j_triangles = np.full((nk, grid.nj - 1, grid.ni), -1, dtype = int)
670
+ j_triangles = np.full((nk, grid.nj - 1, grid.ni), -1, dtype = t_dtype)
670
671
  j_depths = np.full((nk, grid.nj - 1, grid.ni), np.nan)
671
672
  j_offsets = np.full((nk, grid.nj - 1, grid.ni), np.nan)
672
673
  p_xz = np.delete(points, 1, 1)
@@ -715,7 +716,7 @@ def find_faces_to_represent_surface_regular_optimised(grid,
715
716
  if grid.ni > 1:
716
717
  # log.debug("searching for i faces")
717
718
  i_faces = np.zeros((nk, grid.nj, grid.ni - 1), dtype = bool)
718
- i_triangles = np.full((nk, grid.nj, grid.ni - 1), -1, dtype = int)
719
+ i_triangles = np.full((nk, grid.nj, grid.ni - 1), -1, dtype = t_dtype)
719
720
  i_depths = np.full((nk, grid.nj, grid.ni - 1), np.nan)
720
721
  i_offsets = np.full((nk, grid.nj, grid.ni - 1), np.nan)
721
722
  p_yz = np.delete(points, 0, 1)
resqpy/model/_hdf5.py CHANGED
@@ -262,11 +262,11 @@ def _h5_array_element(model,
262
262
  if dtype is None:
263
263
  return result
264
264
  if result.size == 1:
265
- if dtype is float or (isinstance(dtype, str) and dtype.startswith('float')):
265
+ if dtype is float or (isinstance(dtype, str) and ('float' in dtype)):
266
266
  return float(result)
267
- elif dtype is int or (isinstance(dtype, str) and dtype.startswith('int')):
267
+ elif dtype is int or (isinstance(dtype, str) and ('int' in dtype)):
268
268
  return int(result)
269
- elif dtype is bool or (isinstance(dtype, str) and dtype.startswith('bool')):
269
+ elif dtype is bool or (isinstance(dtype, str) and ('bool' in dtype)):
270
270
  return bool(result)
271
271
  return np.array(result, dtype = dtype)
272
272
 
@@ -115,7 +115,7 @@ def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = N
115
115
  if n_p < 3:
116
116
  return None, None # not enough points
117
117
  elif n_p == 3:
118
- return np.array([0, 1, 2], dtype = int).reshape((1, 3)), np.array([0, 1, 2], dtype = int)
118
+ return np.array([0, 1, 2], dtype = np.int32).reshape((1, 3)), np.array([0, 1, 2], dtype = np.int32)
119
119
 
120
120
  if progress_fn is not None:
121
121
  progress_fn(0.0)
@@ -133,19 +133,20 @@ def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = N
133
133
  p[-1] = (min_xy[0] + 0.5 * csf * dxy[0], max_xy[1] + 0.8 * csf * dxy[1])
134
134
 
135
135
  # triangle vertex indices
136
- t = np.empty((2 * n_p + 2, 3), dtype = int) # empty space for triangle vertex indices
136
+ t_type = np.int32 if n_p < 2_147_483_648 else np.int64
137
+ t = np.empty((2 * n_p + 2, 3), dtype = t_type) # empty space for triangle vertex indices
137
138
  t[0] = (n_p, n_p + 1, n_p + 2) # initial set of one containing triangle
138
139
  nt = 1 # number of triangles so far populated
139
140
 
140
141
  # edges: list of indices of triangles and edge within triangle; -1 indicates no triangle using edge
141
- e = np.full((3 * n_p + 6, 2, 2), fill_value = -1, dtype = int)
142
+ e = np.full((3 * n_p + 6, 2, 2), fill_value = -1, dtype = t_type)
142
143
  e[:3, 0, 0] = 0
143
144
  for edge in range(3):
144
145
  e[edge, 0, 1] = edge
145
146
  ne = 3 # number of edges so far in use
146
147
 
147
148
  # edge indices (in e) for each triangle, first axis indexed in sync with t
148
- te = np.empty((2 * n_p + 2, 3), dtype = int) # empty space for triangle edge indices
149
+ te = np.empty((2 * n_p + 2, 3), dtype = t_type) # empty space for triangle edge indices
149
150
  te[0] = (0, 1, 2)
150
151
 
151
152
  # mask tracking which edges have been flipped
@@ -501,7 +502,7 @@ def voronoi(p, t, b, aoi: rql.Polyline):
501
502
  return trimmed_ci
502
503
 
503
504
  def __veroni_cells(aoi_count, aoi_intersect_segments, b, c, c_count, ca_count, cah_count, caho_count, cahon_count,
504
- hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi):
505
+ hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi, t_type):
505
506
  # list of voronoi cells (each a numpy list of node indices into c extended with aoi points etc)
506
507
  v = []
507
508
  # for each seed point build the voronoi cell
@@ -550,7 +551,7 @@ def voronoi(p, t, b, aoi: rql.Polyline):
550
551
  ci_for_p, out_pair_intersect_segments)
551
552
 
552
553
  #  remove circumcircle centres that are outwith area of interest
553
- ci_for_p = np.array([ti for ti in ci_for_p if ti >= c_count or ti not in tc_outwith_aoi], dtype = int)
554
+ ci_for_p = np.array([ti for ti in ci_for_p if ti >= c_count or ti not in tc_outwith_aoi], dtype = t_type)
554
555
 
555
556
  # find azimuths of vectors from seed point to circumcircle centres and aoi boundary points
556
557
  azi = [vec.azimuth(centre - p[p_i, :2]) for centre in c[ci_for_p, :2]]
@@ -612,11 +613,12 @@ def voronoi(p, t, b, aoi: rql.Polyline):
612
613
  caho_count = cah_count + 2 * o_count
613
614
  cahon_count = caho_count + hull_count
614
615
  assert cahon_count + hull_count == len(c)
616
+ t_type = np.int32 if len(c) < 2_147_483_648 else np.int64
615
617
 
616
618
  #  compute intersection points between hull edge normals and aoi polyline
617
619
  # also extended virtual centres for hull edges
618
620
  extension_scaling = 1000.0 * np.sum((np.max(aoi.coordinates, axis = 0) - np.min(aoi.coordinates, axis = 0))[:2])
619
- aoi_intersect_segments = np.empty((hull_count,), dtype = int)
621
+ aoi_intersect_segments = np.empty((hull_count,), dtype = t_type)
620
622
  for ei in range(hull_count):
621
623
  # use segment midpoint and normal methods of hull to project out
622
624
  m = hull.segment_midpoint(ei)[:2] # midpoint
@@ -638,8 +640,8 @@ def voronoi(p, t, b, aoi: rql.Polyline):
638
640
  c[cahon_count + ei] = hull.coordinates[ei, :2] + extension_scaling * vector
639
641
 
640
642
  # where cicrumcircle centres are outwith aoi, compute intersections of normals of wing edges with aoi
641
- out_pair_intersect_segments = np.empty((o_count, 2), dtype = int)
642
- wing_hull_segments = np.empty((o_count, 2), dtype = int)
643
+ out_pair_intersect_segments = np.empty((o_count, 2), dtype = t_type)
644
+ wing_hull_segments = np.empty((o_count, 2), dtype = t_type)
643
645
  for oi, ti in enumerate(tc_outwith_aoi):
644
646
  tpi = __shorter_sides_p_i(p[t[ti]])
645
647
  for wing in range(2):
@@ -658,7 +660,7 @@ def voronoi(p, t, b, aoi: rql.Polyline):
658
660
  tpi = (tpi + 1) % 3
659
661
 
660
662
  v = __veroni_cells(aoi_count, aoi_intersect_segments, b, c, c_count, ca_count, cah_count, caho_count, cahon_count,
661
- hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi)
663
+ hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi, t_type)
662
664
 
663
665
  return c[:caho_count], v
664
666
 
@@ -703,7 +705,8 @@ def triangulated_polygons(p, v, centres = None):
703
705
  points[len(p):] = centres
704
706
 
705
707
  t_count = sum([len(x) for x in v])
706
- triangles = np.empty((t_count, 3), dtype = int)
708
+ t_type = np.int32 if len(points) < 2_147_483_648 else np.int64
709
+ triangles = np.empty((t_count, 3), dtype = t_type)
707
710
  t_index = 0
708
711
 
709
712
  for cell, poly_vertices in enumerate(v):
@@ -711,7 +714,7 @@ def triangulated_polygons(p, v, centres = None):
711
714
  centre_i = len(p) + cell
712
715
  if centres is None:
713
716
  polygon = rql.Polyline(model,
714
- set_coord = p[np.array(poly_vertices, dtype = int)],
717
+ set_coord = p[np.array(poly_vertices, dtype = t_type)],
715
718
  is_closed = True,
716
719
  set_crs = crs.uuid,
717
720
  title = 'v cell')
@@ -917,7 +920,7 @@ def edges(t):
917
920
  """
918
921
 
919
922
  assert t.ndim == 2 and t.shape[1] == 3
920
- all_edges = np.empty((len(t), 3, 2), dtype = int)
923
+ all_edges = np.empty((len(t), 3, 2), dtype = t.dtype)
921
924
  all_edges[:, :, 0] = t
922
925
  all_edges[:, :2, 1] = t[:, 1:]
923
926
  all_edges[:, 2, 1] = t[:, 0]
@@ -946,6 +949,7 @@ def triangles_using_edges(t, edges):
946
949
  """Returns int array of shape (len(edges), 2) with indices of upto 2 triangles using each edge (-1 for unused)."""
947
950
 
948
951
  assert t.ndim == 2 and t.shape[1] == 3 and edges.ndim == 2 and edges.shape[1] == 2
952
+ t_type = np.int32 if len(t) < 2_147_483_648 else np.int64
949
953
  ti = np.full((len(edges), 2), -1, dtype = int)
950
954
  for i in range(len(edges)):
951
955
  te = triangles_using_edge(t, edges[i, 0], edges[i, 1])
@@ -75,9 +75,9 @@ wellspec_dict['DZ'] = (0, wk_preferably_not, wk_okay, None, True) # no
75
75
 
76
76
  wellspec_dtype: Dict[str, Type] = { } # mapping wellspec column key to expected data type
77
77
 
78
- wellspec_dtype['IW'] = int
79
- wellspec_dtype['JW'] = int
80
- wellspec_dtype['L'] = int
78
+ wellspec_dtype['IW'] = np.int32
79
+ wellspec_dtype['JW'] = np.int32
80
+ wellspec_dtype['L'] = np.int32
81
81
  wellspec_dtype['GRID'] = str
82
82
  wellspec_dtype['RADW'] = float
83
83
  wellspec_dtype['KHMULT'] = float
@@ -89,11 +89,11 @@ wellspec_dtype['KH'] = float
89
89
  wellspec_dtype['SKIN'] = float
90
90
  wellspec_dtype['PPERF'] = float
91
91
  wellspec_dtype['ANGLE'] = float
92
- wellspec_dtype['IRELPM'] = int
92
+ wellspec_dtype['IRELPM'] = np.int32
93
93
  wellspec_dtype['RADB'] = float
94
94
  wellspec_dtype['WI'] = float
95
95
  wellspec_dtype['K'] = float
96
- wellspec_dtype['LAYER'] = int
96
+ wellspec_dtype['LAYER'] = np.int32
97
97
  wellspec_dtype['DEPTH'] = float # '#' causes nexus to use cell depth
98
98
  wellspec_dtype['X'] = float # use cell X for i.p. perf
99
99
  wellspec_dtype['Y'] = float # use cell Y for i.p. perf
@@ -109,10 +109,10 @@ wellspec_dtype['PARENT'] = str
109
109
  wellspec_dtype['MDCON'] = float
110
110
  wellspec_dtype['SECT'] = str # todo: need to check type
111
111
  wellspec_dtype['FLOWSECT'] = str # todo: need to check type
112
- wellspec_dtype['ZONE'] = int
112
+ wellspec_dtype['ZONE'] = np.int32
113
113
  wellspec_dtype['GROUP'] = str
114
114
  wellspec_dtype['TEMP'] = float
115
- wellspec_dtype['IPTN'] = int
115
+ wellspec_dtype['IPTN'] = np.int32
116
116
  wellspec_dtype['D'] = float
117
117
  wellspec_dtype['ND'] = str
118
118
  wellspec_dtype['DZ'] = float
@@ -456,7 +456,7 @@ def get_well_data(
456
456
  line = kf.strip_trailing_comment(file.readline()).upper()
457
457
  columns_present = line.split()
458
458
  if selecting:
459
- column_map = np.full((len(column_list),), -1, dtype = int)
459
+ column_map = np.full((len(column_list),), -1, dtype = np.int32)
460
460
  for i in range(len(column_list)):
461
461
  column = column_list[i].upper()
462
462
  if column in columns_present:
@@ -519,13 +519,19 @@ def get_well_data(
519
519
 
520
520
  def stat_tranformation(row):
521
521
  if row["STAT"] == "ON":
522
- return 1
522
+ return np.int8(1)
523
523
  else:
524
- return 0
524
+ return np.int8(0)
525
525
 
526
526
  if "STAT" in df.columns:
527
527
  df["STAT"] = df.apply(lambda row: stat_tranformation(row), axis = 1)
528
528
 
529
+ int_col_dict = {}
530
+ for col in ["IW", "JW", "L", "LAYER", "STAT"]:
531
+ if col in df.columns:
532
+ int_col_dict[col] = (np.int8 if col == "STAT" else np.int32)
533
+ df = df.astype(int_col_dict)
534
+
529
535
  return df
530
536
 
531
537
 
@@ -51,11 +51,11 @@ class GridPropertyCollection(rqp.PropertyCollection):
51
51
 
52
52
  # NB: RESQML documentation is not clear which order is correct; should be kept consistent with same data in fault.py
53
53
  # face_index_map maps from (axis, p01) to face index value in range 0..5
54
- # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = int)
55
- self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = int) # order: top, base, J-, I+, J+, I-
54
+ # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = np.int8)
55
+ self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = np.int8) # order: top, base, J-, I+, J+, I-
56
56
  # and the inverse, maps from 0..5 to (axis, p01)
57
- # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = int)
58
- self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = int)
57
+ # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = np.int8)
58
+ self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = np.int8)
59
59
 
60
60
  def _copy_support_to_grid_attributes(self):
61
61
  # following three pseudonyms are for backward compatibility
@@ -266,11 +266,11 @@ class GridPropertyCollection(rqp.PropertyCollection):
266
266
  dtype = None
267
267
  if keyword[0].upper() == 'I' or keyword in ['KID', 'UID', 'UNPACK', 'DAD']:
268
268
  # coerce to integer values (vdb stores integer data as reals!)
269
- dtype = 'int32'
269
+ dtype = np.int32
270
270
  elif keyword in ['DEADCELL', 'LIVECELL']:
271
- dtype = 'bool' # could use the default dtype of 64 bit integer
271
+ dtype = bool # could use the default dtype of 64 bit integer
272
272
  else:
273
- dtype = 'float' # convert to 64 bit; could omit but RESQML states 64 bit
273
+ dtype = np.float32
274
274
  discrete = False
275
275
  import_array = vdbase.grid_static_property(grid_name, keyword, dtype = dtype)
276
276
  assert import_array is not None
@@ -335,7 +335,7 @@ class GridPropertyCollection(rqp.PropertyCollection):
335
335
  time_index = timestep
336
336
  keyword = keyword.upper()
337
337
  try:
338
- import_array = vdbase.grid_recurrent_property_for_timestep(grid_name, keyword, timestep, dtype = 'float')
338
+ import_array = vdbase.grid_recurrent_property_for_timestep(grid_name, keyword, timestep, dtype = np.float32)
339
339
  assert import_array is not None
340
340
  except Exception:
341
341
  # could raise an exception (as for static properties)
@@ -489,9 +489,9 @@ class GridPropertyCollection(rqp.PropertyCollection):
489
489
  for k0 in range(self.grid.nk):
490
490
  for j0 in range(self.grid.nj):
491
491
  for i0 in range(self.grid.ni):
492
- # if decoarsen_array[k0, j0, i0] < 0:
492
+ # if decoarsen_array[k0, j0, i0] < 0:
493
493
  if kid[k0, j0, i0] == 0:
494
- # assert not kid_mask[k0, j0, i0]
494
+ # assert not kid_mask[k0, j0, i0]
495
495
  ke = k0 + 1
496
496
  while ke < self.grid.nk and kid_mask[ke, j0, i0]:
497
497
  ke += 1