resqpy 4.16.4__py3-none-any.whl → 4.16.6__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.4" # Set at build time
31
+ __version__ = "4.16.6" # Set at build time
32
32
  log = logging.getLogger(__name__)
33
33
  log.info(f"Imported resqpy version {__version__}")
@@ -495,19 +495,18 @@ def find_faces_to_represent_surface_regular(
495
495
  return gcs
496
496
 
497
497
 
498
- def find_faces_to_represent_surface_regular_optimised(
499
- grid,
500
- surface,
501
- name,
502
- title = None,
503
- agitate = False,
504
- random_agitation = False,
505
- feature_type = "fault",
506
- is_curtain = False,
507
- progress_fn = None,
508
- return_properties = None,
509
- raw_bisector = False,
510
- ):
498
+ def find_faces_to_represent_surface_regular_optimised(grid,
499
+ surface,
500
+ name,
501
+ title = None,
502
+ agitate = False,
503
+ random_agitation = False,
504
+ feature_type = "fault",
505
+ is_curtain = False,
506
+ progress_fn = None,
507
+ return_properties = None,
508
+ raw_bisector = False,
509
+ n_batches = 20):
511
510
  """Returns a grid connection set containing those cell faces which are deemed to represent the surface.
512
511
 
513
512
  argumants:
@@ -539,6 +538,8 @@ def find_faces_to_represent_surface_regular_optimised(
539
538
  the returned dictionary has the passed strings as keys and numpy arrays as values
540
539
  raw_bisector (bool, default False): if True and grid bisector is requested then it is left in a raw
541
540
  form without assessing which side is shallower (True values indicate same side as origin cell)
541
+ n_batches (int, default 20): the number of batches of triangles to use at the low level (numba multi
542
+ threading allows some parallelism between the batches)
542
543
 
543
544
  returns:
544
545
  gcs or (gcs, gcs_props)
@@ -627,8 +628,9 @@ def find_faces_to_represent_surface_regular_optimised(
627
628
  p_xy = np.delete(points, 2, 1)
628
629
 
629
630
  k_hits = vec.points_in_triangles_aligned_optimised(grid.ni, grid.nj, grid_dxyz[0], grid_dxyz[1],
630
- p_xy[triangles])
631
+ p_xy[triangles], n_batches)
631
632
 
633
+ del p_xy
632
634
  axis = 2
633
635
  index1 = 1
634
636
  index2 = 2
@@ -650,7 +652,6 @@ def find_faces_to_represent_surface_regular_optimised(
650
652
  k_triangles,
651
653
  )
652
654
  del k_hits
653
- del p_xy
654
655
  log.debug(f"k face count: {np.count_nonzero(k_faces)}")
655
656
  else:
656
657
  k_faces = None
@@ -670,8 +671,10 @@ def find_faces_to_represent_surface_regular_optimised(
670
671
  j_offsets = np.full((nk, grid.nj - 1, grid.ni), np.nan)
671
672
  p_xz = np.delete(points, 1, 1)
672
673
 
673
- j_hits = vec.points_in_triangles_aligned_optimised(grid.ni, nk, grid_dxyz[0], grid_dxyz[2], p_xz[triangles])
674
+ j_hits = vec.points_in_triangles_aligned_optimised(grid.ni, nk, grid_dxyz[0], grid_dxyz[2], p_xz[triangles],
675
+ n_batches)
674
676
 
677
+ del p_xz
675
678
  axis = 1
676
679
  index1 = 0
677
680
  index2 = 2
@@ -693,7 +696,6 @@ def find_faces_to_represent_surface_regular_optimised(
693
696
  j_triangles,
694
697
  )
695
698
  del j_hits
696
- del p_xz
697
699
  if is_curtain and grid.nk > 1: # expand arrays to all layers
698
700
  j_faces = np.repeat(j_faces, grid.nk, axis = 0)
699
701
  j_triangles = np.repeat(j_triangles, grid.nk, axis = 0)
@@ -718,8 +720,10 @@ def find_faces_to_represent_surface_regular_optimised(
718
720
  i_offsets = np.full((nk, grid.nj, grid.ni - 1), np.nan)
719
721
  p_yz = np.delete(points, 0, 1)
720
722
 
721
- i_hits = vec.points_in_triangles_aligned_optimised(grid.nj, nk, grid_dxyz[1], grid_dxyz[2], p_yz[triangles])
723
+ i_hits = vec.points_in_triangles_aligned_optimised(grid.nj, nk, grid_dxyz[1], grid_dxyz[2], p_yz[triangles],
724
+ n_batches)
722
725
 
726
+ del p_yz
723
727
  axis = 0
724
728
  index1 = 0
725
729
  index2 = 1
@@ -741,7 +745,6 @@ def find_faces_to_represent_surface_regular_optimised(
741
745
  i_triangles,
742
746
  )
743
747
  del i_hits
744
- del p_yz
745
748
  if is_curtain and grid.nk > 1: # expand arrays to all layers
746
749
  # log.debug('expanding curtain faces')
747
750
  i_faces = np.repeat(i_faces, grid.nk, axis = 0)
resqpy/model/_hdf5.py CHANGED
@@ -286,6 +286,14 @@ def _h5_overwrite_array_slice(model, h5_key_pair, slice_tuple, array_slice):
286
286
  dset[slice_tuple] = array_slice
287
287
 
288
288
 
289
+ def _h5_overwrite_array(model, h5_key_pair, array):
290
+ """Overwrites (updates) the whole of an hdf5 array."""
291
+
292
+ h5_root = _h5_access(model, h5_key_pair[0], mode = 'a')
293
+ dset = h5_root[h5_key_pair[1]]
294
+ dset[...] = array
295
+
296
+
289
297
  def h5_clear_filename_cache(model):
290
298
  """Clears the cached filenames associated with all ext uuids."""
291
299
 
resqpy/model/_model.py CHANGED
@@ -1475,6 +1475,21 @@ class Model():
1475
1475
 
1476
1476
  return m_h._h5_overwrite_array_slice(self, h5_key_pair, slice_tuple, array_slice)
1477
1477
 
1478
+ def h5_overwrite_array(self, h5_key_pair, array):
1479
+ """Overwrites (updates) the whole of an hdf5 array.
1480
+
1481
+ arguments:
1482
+ h5_key_pair (uuid, string): the uuid of the hdf5 ext part and the hdf5 internal path to the
1483
+ required hdf5 array
1484
+ array (numpy array of shape to match existing hdf5 dataset): the data to write
1485
+
1486
+ notes:
1487
+ this method naively updates an hdf5 array without using mpi to look after parallel updates;
1488
+ metadata (such as uuid or property min, max values) is not modified in any way by the method
1489
+ """
1490
+
1491
+ return m_h._h5_overwrite_array(self, h5_key_pair, array)
1492
+
1478
1493
  def h5_clear_filename_cache(self):
1479
1494
  """Clears the cached filenames associated with all ext uuids."""
1480
1495
 
@@ -13,7 +13,7 @@ log = logging.getLogger(__name__)
13
13
  import math as maths
14
14
  import numpy as np
15
15
  import numba # type: ignore
16
- from numba import njit # type: ignore
16
+ from numba import njit, prange # type: ignore
17
17
  from typing import Tuple, Optional
18
18
 
19
19
 
@@ -952,13 +952,13 @@ def triangle_box(triangle: np.ndarray) -> Tuple[float, float, float, float]: #
952
952
  """
953
953
  x_values = triangle[:, 0]
954
954
  y_values = triangle[:, 1]
955
- return min(x_values), max(x_values), min(y_values), max(y_values)
955
+ return np.min(x_values), np.max(x_values), np.min(y_values), np.max(y_values)
956
956
 
957
957
 
958
958
  @njit
959
959
  def vertical_intercept(x: float, x_values: np.ndarray, y_values: np.ndarray) -> Optional[float]: # pragma: no cover
960
960
  """Finds the y value of a straight line between two points at a given x.
961
-
961
+
962
962
  If the x value given is not within the x values of the points, returns None.
963
963
 
964
964
  arguments:
@@ -982,8 +982,40 @@ def vertical_intercept(x: float, x_values: np.ndarray, y_values: np.ndarray) ->
982
982
 
983
983
 
984
984
  @njit
985
- def points_in_triangles_aligned_optimised(nx: int, ny: int, dx: float, dy: float,
986
- triangles: np.ndarray) -> np.ndarray: # pragma: no cover
985
+ def vertical_intercept_nan(x: float, x_value_0: float, x_value_1: float, y_value_0: float,
986
+ y_value_1: float) -> float: # pragma: no cover
987
+ """Finds the y value of a straight line between two points at a given x.
988
+
989
+ If the x value given is not within the x values of the points, returns NaN.
990
+
991
+ arguments:
992
+ x (float): x value at which to determine the y value
993
+ x_value_0 (np.ndarray): the x coordinate of point 1
994
+ x_value_1 (np.ndarray): the x coordinate of point 2
995
+ y_value_0 (np.ndarray): the y coordinate of point 1
996
+ y_value_1 (np.ndarray): the y coordinate of point 2
997
+
998
+ returns:
999
+ y (float): y value of the straight line segment between point 1 and point 2,
1000
+ evaluated at x; if x is outside the x values range, y is NaN
1001
+ """
1002
+ y = np.NaN
1003
+ if x_value_1 < x_value_0:
1004
+ x_value_0, x_value_1 = x_value_1, x_value_0
1005
+ y_value_0, y_value_1 = y_value_1, y_value_0
1006
+ if x >= x_value_0 and x <= x_value_1:
1007
+ if x_value_0 == x_value_1:
1008
+ y = y_value_0
1009
+ else:
1010
+ m = (y_value_1 - y_value_0) / (x_value_1 - x_value_0)
1011
+ c = y_value_1 - m * x_value_1
1012
+ y = m * x + c
1013
+ return y
1014
+
1015
+
1016
+ @njit
1017
+ def points_in_triangles_aligned_optimised_old(nx: int, ny: int, dx: float, dy: float,
1018
+ triangles: np.ndarray) -> np.ndarray: # pragma: no cover
987
1019
  """Calculates which points are within which triangles in 2D for a regular mesh of aligned points.
988
1020
 
989
1021
  arguments:
@@ -1023,6 +1055,116 @@ def points_in_triangles_aligned_optimised(nx: int, ny: int, dx: float, dy: float
1023
1055
  return triangles_points
1024
1056
 
1025
1057
 
1058
+ @njit
1059
+ def points_in_triangles_aligned_optimised_serial(nx: int, ny: int, dx: float, dy: float,
1060
+ triangles: np.ndarray) -> np.ndarray: # pragma: no cover
1061
+ """Calculates which points are within which triangles in 2D for a regular mesh of aligned points.
1062
+
1063
+ arguments:
1064
+ nx (int): number of points in x axis
1065
+ ny (int): number of points in y axis
1066
+ dx (float): spacing of points in x axis (first point is at half dx)
1067
+ dy (float): spacing of points in y axis (first point is at half dy)
1068
+ triangles (np.ndarray): float array of each triangles' vertices in 2D, shape (N, 3, 2)
1069
+
1070
+ returns:
1071
+ triangles_points (np.ndarray): 2D array (list-like) containing only the points within each triangle,
1072
+ with each row being the triangle number, points y index, and points x index
1073
+ """
1074
+ triangles = triangles.copy()
1075
+ triangles[..., 0] /= dx
1076
+ triangles[..., 1] /= dy
1077
+ triangles -= 0.5
1078
+ triangles_points_list = []
1079
+ for triangle_num in range(len(triangles)):
1080
+ triangle = triangles[triangle_num]
1081
+ min_x, max_x, min_y, max_y = triangle_box(triangle)
1082
+ for xi in range(max(maths.ceil(min_x), 0), min(maths.floor(max_x) + 1, nx)):
1083
+ x = float(xi)
1084
+ e0_y = vertical_intercept_nan(x, triangle[1, 0], triangle[2, 0], triangle[1, 1], triangle[2, 1])
1085
+ e1_y = vertical_intercept_nan(x, triangle[0, 0], triangle[1, 0], triangle[0, 1], triangle[1, 1])
1086
+ e2_y = vertical_intercept_nan(x, triangle[0, 0], triangle[2, 0], triangle[0, 1], triangle[2, 1])
1087
+ ey_list = np.array([e0_y, e1_y, e2_y], dtype = np.float64)
1088
+ floor_y = np.nanmin(ey_list)
1089
+ ceil_y = np.nanmax(ey_list)
1090
+ triangles_points_list.extend(
1091
+ [[triangle_num, y, xi] for y in range(max(maths.ceil(floor_y), 0), min(maths.floor(ceil_y) + 1, ny))])
1092
+
1093
+ if len(triangles_points_list) == 0:
1094
+ triangles_points = np.empty((0, 3), dtype = np.int32)
1095
+ else:
1096
+ triangles_points = np.array(triangles_points_list, dtype = np.int32)
1097
+
1098
+ return triangles_points
1099
+
1100
+
1101
+ @njit(parallel = True)
1102
+ def points_in_triangles_aligned_optimised(nx: int,
1103
+ ny: int,
1104
+ dx: float,
1105
+ dy: float,
1106
+ triangles: np.ndarray,
1107
+ n_batches: int = 20) -> np.ndarray: # pragma: no cover
1108
+ """Calculates which points are within which triangles in 2D for a regular mesh of aligned points.
1109
+
1110
+ arguments:
1111
+ nx (int): number of points in x axis
1112
+ ny (int): number of points in y axis
1113
+ dx (float): spacing of points in x axis (first point is at half dx)
1114
+ dy (float): spacing of points in y axis (first point is at half dy)
1115
+ triangles (np.ndarray): float array of each triangles' vertices in 2D, shape (N, 3, 2)
1116
+ n_batches (int, default 20): number of parallel batches
1117
+
1118
+ returns:
1119
+ triangles_points (np.ndarray): 2D array (list-like) containing only the points within each triangle,
1120
+ with each row being the triangle number, points y index, and points x index
1121
+ """
1122
+ n_triangles = len(triangles)
1123
+ if n_triangles == 0:
1124
+ return np.empty((0, 3), dtype = np.int32)
1125
+ triangles = triangles.copy()
1126
+ triangles[..., 0] /= dx
1127
+ triangles[..., 1] /= dy
1128
+ triangles -= 0.5
1129
+ n_batches = min(n_triangles, n_batches)
1130
+ batch_size = (n_triangles - 1) // n_batches + 1
1131
+ tp = [np.empty((0, 3), dtype = np.int32)] * n_batches
1132
+ for batch in prange(n_batches):
1133
+ base = batch * batch_size
1134
+ tp[batch] = _points_in_triangles_aligned_optimised_batch(nx, ny, base, triangles[base:(batch + 1) * batch_size])
1135
+ collated = np.empty((0, 3), dtype = np.int32)
1136
+ for batch in range(n_batches):
1137
+ collated = np.concatenate((collated, tp[batch]), axis = 0)
1138
+ return collated
1139
+
1140
+
1141
+ @njit
1142
+ def _points_in_triangles_aligned_optimised_batch(nx: int, ny: int, base_triangle: int,
1143
+ triangles: np.ndarray) -> np.ndarray: # pragma: no cover
1144
+ triangles_points_list = []
1145
+ for triangle_num in range(len(triangles)):
1146
+ triangle = triangles[triangle_num]
1147
+ min_x, max_x, min_y, max_y = triangle_box(triangle)
1148
+ for xi in range(max(maths.ceil(min_x), 0), min(maths.floor(max_x) + 1, nx)):
1149
+ x = float(xi)
1150
+ e0_y = vertical_intercept_nan(x, triangle[1, 0], triangle[2, 0], triangle[1, 1], triangle[2, 1])
1151
+ e1_y = vertical_intercept_nan(x, triangle[0, 0], triangle[1, 0], triangle[0, 1], triangle[1, 1])
1152
+ e2_y = vertical_intercept_nan(x, triangle[0, 0], triangle[2, 0], triangle[0, 1], triangle[2, 1])
1153
+ ey_list = np.array([e0_y, e1_y, e2_y], dtype = np.float64)
1154
+ floor_y = np.nanmin(ey_list)
1155
+ ceil_y = np.nanmax(ey_list)
1156
+ triangles_points_list.extend([[triangle_num + base_triangle, y, xi]
1157
+ for y in range(max(maths.ceil(floor_y), 0), min(maths.floor(ceil_y) + 1, ny))
1158
+ ])
1159
+
1160
+ if len(triangles_points_list) == 0:
1161
+ triangles_points = np.empty((0, 3), dtype = np.int32)
1162
+ else:
1163
+ triangles_points = np.array(triangles_points_list, dtype = np.int32)
1164
+
1165
+ return triangles_points
1166
+
1167
+
1026
1168
  def triangle_normal_vector(p3):
1027
1169
  """For a triangle in 3D space, defined by 3 vertex points, returns a unit vector normal to the plane of the triangle.
1028
1170
 
@@ -1417,20 +1417,21 @@ class BlockedWell(BaseResqpy):
1417
1417
  time_series_uuid (UUID, optional): the uuid of the time series for time dependent properties being added
1418
1418
 
1419
1419
  notes:
1420
- units of length along wellbore will be those of the trajectory's length_uom (also applies to K.H values) unless
1421
- the length_uom argument is used;
1422
- the constraints are applied independently for each row and a row is excluded if it fails any constraint;
1423
- the min_k0 and max_k0 arguments do not stop later rows within the layer range from being included;
1424
- the min_length and min_kh limits apply to individual cell intervals and thus depend on cell size;
1425
- the water and oil saturation limits are for saturations at a single time and affect whether the interval
1426
- is included in the dataframe – there is no functionality to support turning perforations off and on over time;
1427
- the saturation limits do not stop deeper intervals with qualifying saturations from being included;
1428
- the k0_list, perforation_list and region_list arguments should be set to None to disable the corresponding functionality,
1429
- if set to an empty list, no rows will be included in the dataframe;
1430
- if add_as_properties is True, the blocked well must already have been added as a part to the model;
1431
- add_as_properties and use_properties cannot both be True;
1432
- add_as_properties and use_properties are only currently functional for single grid blocked wells;
1433
- at present, unit conversion is not handled when using properties
1420
+ - units of length along wellbore will be those of the trajectory's length_uom (also applies to K.H values) unless
1421
+ the length_uom argument is used;
1422
+ - the constraints are applied independently for each row and a row is excluded if it fails any constraint;
1423
+ - the min_k0 and max_k0 arguments do not stop later rows within the layer range from being included;
1424
+ - the min_length and min_kh limits apply to individual cell intervals and thus depend on cell size;
1425
+ - the water and oil saturation limits are for saturations at a single time and affect whether the interval
1426
+ is included in the dataframe
1427
+ to turn perforations off and on over time create a time series dependent bunch of boolean properties on
1428
+ the blocked well, with title 'STAT' or local property kind 'well connection open';
1429
+ - the saturation limits do not stop deeper intervals with qualifying saturations from being included;
1430
+ - the k0_list, perforation_list and region_list arguments should be set to None to disable the
1431
+ corresponding functionality, if set to an empty list, no rows will be included in the dataframe;
1432
+ - if add_as_properties is True, the blocked well must already have been added as a part to the model;
1433
+ - add_as_properties and use_properties cannot both be True;
1434
+ - add_as_properties and use_properties are only currently functional for single grid blocked wells;
1434
1435
 
1435
1436
  :meta common:
1436
1437
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: resqpy
3
- Version: 4.16.4
3
+ Version: 4.16.6
4
4
  Summary: Python API for working with RESQML models
5
5
  Home-page: https://github.com/bp/resqpy
6
6
  License: MIT
@@ -1,4 +1,4 @@
1
- resqpy/__init__.py,sha256=BXevcj5cpaKQi4covmL8avFA-mmrCtOHy_bpSrVAVik,556
1
+ resqpy/__init__.py,sha256=HShUsMyW_Opst0QwCwfVL9ZeafR-pFfMTCvvDzmU6rU,556
2
2
  resqpy/crs.py,sha256=R7DfcTP5xGv5pu9Y8RHA2WVM9DjBCSVMoHcz4RmQ7Yw,27646
3
3
  resqpy/derived_model/__init__.py,sha256=NFvMSOKI3cxmH7lAbddV43JjoUj-r2G7ExEfOqinD1I,1982
4
4
  resqpy/derived_model/_add_edges_per_column_property_array.py,sha256=cpW3gwp6MSYIrtvFmCjoJXcyUsgGuCDbgmwlJCJebUs,6410
@@ -48,7 +48,7 @@ resqpy/grid/_write_nexus_corp.py,sha256=yEVfiObsedEAXX6UG6ZTf56kZnQVkd3lLqE2NpL-
48
48
  resqpy/grid/_xyz.py,sha256=RLQWOdM_DRoCj4JypwB5gUJ78HTdk5JnZHSeAzuU634,13087
49
49
  resqpy/grid_surface/__init__.py,sha256=iyK3_Vlg9mXffc_1gjvRdKwQE0zicbNXya0tryHkr04,2593
50
50
  resqpy/grid_surface/_blocked_well_populate.py,sha256=MQIHf7Sh_XR3cUCfGhvlu4Xl498DtIKH2ffo4iud93w,35843
51
- resqpy/grid_surface/_find_faces.py,sha256=WRoc5g-kLtR0JkuT0nueVF8ZgG09YfR3K_aRp2Rc2K8,64645
51
+ resqpy/grid_surface/_find_faces.py,sha256=frwC2pTuFkHkBdmrLjx7X43e1Crtjh9TfHrgsbhIiAw,65534
52
52
  resqpy/grid_surface/_grid_skin.py,sha256=D0cjHkcuT5KCKb-8EZfXgh0GgJj3kzOBS2wVNXg4bfY,26056
53
53
  resqpy/grid_surface/_grid_surface.py,sha256=l2NJo7Kiucolbb_TlLPC7NGdksg_JahkihfsrJVq99w,14379
54
54
  resqpy/grid_surface/_trajectory_intersects.py,sha256=Och9cZYU9Y7ofovhPzsLyIblRUl2xj9_5nHH3fMZp-A,22498
@@ -62,8 +62,8 @@ resqpy/model/_catalogue.py,sha256=duvZlNlTPjAfXyqae0J9lMSEx_8-WIcrw2MYxnNEg_Q,30
62
62
  resqpy/model/_context.py,sha256=0tLBVMcuuIj3i87Ig8lhFMLHE5GHgEA2PEl1NjKaohc,2840
63
63
  resqpy/model/_forestry.py,sha256=QYE3P9uSsh77J6ghcgp2cBQP6UKrs8edF-m05sqgboo,34518
64
64
  resqpy/model/_grids.py,sha256=d7hRQRmni5pJrm1CY31D2icJV1XDar7xTmUexq_eVGY,3371
65
- resqpy/model/_hdf5.py,sha256=2iQdyUp5eNLfWhmvl_XuFO8j7dCdtTBjtrr6-9mq3Qg,14238
66
- resqpy/model/_model.py,sha256=MMiYRrBUitraEg7IeM09PagTP3hZ_e1JJv_C7E6zZX4,105370
65
+ resqpy/model/_hdf5.py,sha256=49Ip2ks7EVt6jT7STqkPNcuk1dE3XrrnlLl5TVEWH84,14469
66
+ resqpy/model/_model.py,sha256=8kBehyWplIi_zYy_TVJY2V0MaVaROfOKAGEBvvrRfxk,106033
67
67
  resqpy/model/_xml.py,sha256=TiZKHZezMdcjRvHSa-HzzrYe9kyDdd8L4hacNV0bjEg,24402
68
68
  resqpy/multi_processing/__init__.py,sha256=ZRudHfN9aaZjxvat7t8BZr6mwMi9baiCNjczwwT0WjI,909
69
69
  resqpy/multi_processing/_multiprocessing.py,sha256=bnCKfSC1tWwvZmZ7BZqCyje0C93m6q7HZPxNpx8xoxA,7301
@@ -98,7 +98,7 @@ resqpy/olio/transmission.py,sha256=ojMRvzMOulb-S3FHnkR3ouIBTXA4knI0drDOt_WACso,6
98
98
  resqpy/olio/triangulation.py,sha256=JA4LN4uASqkN_gx4eE_cAHNOJfTqAQQPYET_cLPJuU8,45621
99
99
  resqpy/olio/uuid.py,sha256=JRMi-RZNeGm8tGNloIwTATzNtdj29lBQDV9OILboPRI,7324
100
100
  resqpy/olio/vdb.py,sha256=lQYuK1kr1Wnucq2EoKgT6lrR7vloCemnCKZktzBcLUc,45231
101
- resqpy/olio/vector_utilities.py,sha256=yPxHseCCAG8z-IqLvqIVYRQvXte5jBiSTinYkuN-5EY,46836
101
+ resqpy/olio/vector_utilities.py,sha256=V4DRixcJPtM6Z0i_eHxu9HA-gLiRTj3rXKEsChKA-j4,53546
102
102
  resqpy/olio/volume.py,sha256=F1pMnDoJ4ricy4dfdLuLuK1xkVgJckL9V06tUeyK6Wc,6185
103
103
  resqpy/olio/wellspec_keywords.py,sha256=MqrXRSzVfXAKUhiJkop3EwoVdKEjgZRwHYBJjx2IW8Q,26265
104
104
  resqpy/olio/write_data.py,sha256=bIX7ilMkXWCMz_zQh-Gqk56sNzng4W5l4BahW2EV7Kw,5142
@@ -184,7 +184,7 @@ resqpy/weights_and_measures/__init__.py,sha256=Kp1pPZFH4rS5_PkCERZBEzGoat6n_dSS0
184
184
  resqpy/weights_and_measures/nexus_units.py,sha256=pHqcFbe-8nyqozFgN5Ce-W-UvEnXQ6yiaX3dP1ONtAQ,5434
185
185
  resqpy/weights_and_measures/weights_and_measures.py,sha256=1WnrmhtcyCgY2crClNddmfwtf33JdVZy9wNhqPQIvuc,16210
186
186
  resqpy/well/__init__.py,sha256=v5_gd7sSPRM9q2KsLiLWaw3jbnXFZkou38qeB7_HSN4,990
187
- resqpy/well/_blocked_well.py,sha256=07Do0oKvxPFc5HL4SWEwjWE0xYIeJHQCOB2DtI6YgzI,192034
187
+ resqpy/well/_blocked_well.py,sha256=XszaLuRs-McCEP9jjQkpflPqTyaez3v-F0H5qa01UjM,192115
188
188
  resqpy/well/_deviation_survey.py,sha256=d3u31JbBqMCsaz6MUrtZium90wrC3omtm46A755fvgk,23115
189
189
  resqpy/well/_md_datum.py,sha256=rRrDQckTJwZtIEh28dlgXj32kcBSu-ZvHFYZOiQsyqg,7154
190
190
  resqpy/well/_trajectory.py,sha256=QGFgdYVvA_gJth3n-RaFPS71S5KGgECnNMx0dp1r4Tw,52771
@@ -194,7 +194,7 @@ resqpy/well/_wellbore_marker_frame.py,sha256=xvYH2_2Ie3a18LReFymbUrZboOx7Rhv5DOD
194
194
  resqpy/well/blocked_well_frame.py,sha256=Lg7TgynfPv9WkklXTLt9VN6uBXWUqX1LI-Xmv_FBqYk,22555
195
195
  resqpy/well/well_object_funcs.py,sha256=LYTcC07ezlBxClfrug_B4iXXZUkXDPgsVufNzp361Wo,24703
196
196
  resqpy/well/well_utils.py,sha256=zwpYjT85nXAwWBhYB1Pygu2SgouZ-44k6hEOnpoMfBI,5969
197
- resqpy-4.16.4.dist-info/LICENSE,sha256=2duHPIkKQyESMdQ4hKjL8CYEsYRHXaYxt0YQkzsUYE4,1059
198
- resqpy-4.16.4.dist-info/METADATA,sha256=E_5Hy6Q2M8CAe6ESaa0CaNgOl76upOfLan60-EWrxwY,4028
199
- resqpy-4.16.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
200
- resqpy-4.16.4.dist-info/RECORD,,
197
+ resqpy-4.16.6.dist-info/LICENSE,sha256=2duHPIkKQyESMdQ4hKjL8CYEsYRHXaYxt0YQkzsUYE4,1059
198
+ resqpy-4.16.6.dist-info/METADATA,sha256=nKWccolEPWrZ8qsjWUWMrrbdDSGX1uFvnJOtD7hJySI,4028
199
+ resqpy-4.16.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
200
+ resqpy-4.16.6.dist-info/RECORD,,