resqpy 4.16.11__py3-none-any.whl → 4.17.1__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 +1 -1
- resqpy/fault/_grid_connection_set.py +224 -62
- resqpy/grid/_grid.py +4 -0
- resqpy/grid_surface/__init__.py +4 -0
- resqpy/grid_surface/_blocked_well_populate.py +5 -5
- resqpy/grid_surface/_find_faces.py +731 -212
- resqpy/model/_hdf5.py +3 -3
- resqpy/olio/triangulation.py +17 -13
- resqpy/olio/vector_utilities.py +175 -1
- resqpy/olio/wellspec_keywords.py +16 -10
- resqpy/property/grid_property_collection.py +10 -10
- resqpy/rq_import/_import_vdb_ensemble.py +12 -13
- resqpy/surface/_mesh.py +4 -0
- resqpy/surface/_surface.py +40 -24
- resqpy/surface/_tri_mesh.py +8 -7
- resqpy/surface/_triangulated_patch.py +71 -51
- resqpy/well/_blocked_well.py +28 -25
- resqpy/well/_trajectory.py +2 -2
- resqpy/well/blocked_well_frame.py +1 -1
- resqpy/well/well_object_funcs.py +5 -5
- {resqpy-4.16.11.dist-info → resqpy-4.17.1.dist-info}/METADATA +1 -1
- {resqpy-4.16.11.dist-info → resqpy-4.17.1.dist-info}/RECORD +24 -24
- {resqpy-4.16.11.dist-info → resqpy-4.17.1.dist-info}/LICENSE +0 -0
- {resqpy-4.16.11.dist-info → resqpy-4.17.1.dist-info}/WHEEL +0 -0
resqpy/surface/_tri_mesh.py
CHANGED
@@ -120,6 +120,7 @@ class TriMesh(rqs.Mesh):
|
|
120
120
|
self.origin = None
|
121
121
|
else:
|
122
122
|
self.origin = origin
|
123
|
+
self.t_type = np.int32 if self.is_big() else np.int64
|
123
124
|
|
124
125
|
@classmethod
|
125
126
|
def from_tri_mesh_and_z_values(cls,
|
@@ -302,7 +303,7 @@ class TriMesh(rqs.Mesh):
|
|
302
303
|
def tri_nodes_for_tji(self, tji):
|
303
304
|
"""Return mesh node indices, shape (3, 2), for triangle tji (tj, ti)."""
|
304
305
|
j, i = tji
|
305
|
-
tn = np.zeros((3, 2), dtype =
|
306
|
+
tn = np.zeros((3, 2), dtype = self.t_type)
|
306
307
|
j_odd = j % 2
|
307
308
|
i2, i_odd = divmod(i, 2)
|
308
309
|
assert 0 <= j < self.nj - 1 and 0 <= i < 2 * (self.ni - 1)
|
@@ -325,7 +326,7 @@ class TriMesh(rqs.Mesh):
|
|
325
326
|
j = tji_array[..., 0]
|
326
327
|
i = tji_array[..., 1]
|
327
328
|
tn_shape = tuple(list(tji_array.shape[:-1]) + [3, 2])
|
328
|
-
tn = np.zeros(tn_shape, dtype =
|
329
|
+
tn = np.zeros(tn_shape, dtype = self.t_type)
|
329
330
|
j_odd = j % 2
|
330
331
|
i2, i_odd = np.divmod(i, 2)
|
331
332
|
mask = np.logical_or(np.logical_or(j < 0, j >= self.nj - 1), np.logical_or(i < 0, i >= 2 * (self.ni - 1)))
|
@@ -342,9 +343,9 @@ class TriMesh(rqs.Mesh):
|
|
342
343
|
|
343
344
|
def all_tri_nodes(self):
|
344
345
|
"""Returns array of mesh node indices for all triangles, shape (nj - 1, 2 * (ni - 1), 3, 2)."""
|
345
|
-
tna = np.zeros((self.nj - 1, 2 * (self.ni - 1), 3, 2), dtype =
|
346
|
+
tna = np.zeros((self.nj - 1, 2 * (self.ni - 1), 3, 2), dtype = self.t_type)
|
346
347
|
# set mesh j indices
|
347
|
-
tna[:, :, 0, 0] = np.expand_dims(np.arange(self.nj - 1, dtype =
|
348
|
+
tna[:, :, 0, 0] = np.expand_dims(np.arange(self.nj - 1, dtype = self.t_type), axis = -1)
|
348
349
|
tna[1::2, ::2, 0, 0] += 1
|
349
350
|
tna[::2, 1::2, 0, 0] += 1
|
350
351
|
tna[:, :, 1, 0] = tna[:, :, 0, 0]
|
@@ -352,7 +353,7 @@ class TriMesh(rqs.Mesh):
|
|
352
353
|
tna[1::2, ::2, 2, 0] -= 2
|
353
354
|
tna[::2, 1::2, 2, 0] -= 2
|
354
355
|
# set mesh i indices
|
355
|
-
tna[:, ::2, 0, 1] = np.expand_dims(np.arange(self.ni - 1, dtype =
|
356
|
+
tna[:, ::2, 0, 1] = np.expand_dims(np.arange(self.ni - 1, dtype = self.t_type), axis = 0)
|
356
357
|
tna[:, 1::2, 0, 1] = tna[:, ::2, 0, 1]
|
357
358
|
tna[:, :, 1, 1] = tna[:, :, 0, 1] + 1
|
358
359
|
tna[:, :, 2, 1] = tna[:, :, 0, 1]
|
@@ -362,7 +363,7 @@ class TriMesh(rqs.Mesh):
|
|
362
363
|
def triangles_and_points(self):
|
363
364
|
"""Returns node indices and xyz points in form suitable for a Surface (triangulated set)."""
|
364
365
|
tna = self.all_tri_nodes()
|
365
|
-
composite_ji = tna[:, :, :, 0] * self.ni + tna[:, :, :, 1]
|
366
|
+
composite_ji = (tna[:, :, :, 0] * self.ni + tna[:, :, :, 1]).astype(self.t_type)
|
366
367
|
return (composite_ji.reshape((-1, 3)), self.full_array_ref().reshape((-1, 3)))
|
367
368
|
|
368
369
|
def tji_for_triangle_index(self, ti):
|
@@ -410,7 +411,7 @@ class TriMesh(rqs.Mesh):
|
|
410
411
|
tp)
|
411
412
|
tn_a[:, 1] *= 2 # node j
|
412
413
|
|
413
|
-
return np.concatenate((tn_a, tn_b), axis = 0)
|
414
|
+
return np.concatenate((tn_a, tn_b), axis = 0).astype(self.t_type)
|
414
415
|
|
415
416
|
def edge_zero_crossings(self, z_values = None):
|
416
417
|
"""Returns numpy list of points from edges where z values cross zero (or given value).
|
@@ -31,6 +31,7 @@ class TriangulatedPatch:
|
|
31
31
|
self.ni = None # used to convert a triangle index back into a (j, i) pair when freshly built from mesh
|
32
32
|
self.points = None
|
33
33
|
self.crs_uuid = crs_uuid
|
34
|
+
self.t_type = np.int32 # gets set to int64 if number of points requires it
|
34
35
|
if patch_node is not None:
|
35
36
|
xml_patch_index = rqet.find_tag_int(patch_node, 'PatchIndex')
|
36
37
|
assert xml_patch_index is not None
|
@@ -56,52 +57,61 @@ class TriangulatedPatch:
|
|
56
57
|
crs_root = self.model.root_for_uuid(self.crs_uuid)
|
57
58
|
return crs_root, self.crs_uuid
|
58
59
|
|
59
|
-
def triangles_and_points(self):
|
60
|
+
def triangles_and_points(self, copy = False):
|
60
61
|
"""Returns arrays representing the patch.
|
61
62
|
|
62
|
-
|
63
|
+
arguments:
|
64
|
+
copy (bool, default False): if True, a copy of the arrays is returned; if False, the cached
|
65
|
+
arrays are returned
|
66
|
+
|
67
|
+
returns:
|
63
68
|
Tuple (triangles, points):
|
64
69
|
|
65
70
|
* triangles (int array of shape[:, 3]): integer indices into points array,
|
66
71
|
being the nodes of the corners of the triangles
|
67
72
|
* points (float array of shape[:, 3]): flat array of xyz points, indexed by triangles
|
68
73
|
"""
|
69
|
-
if self.triangles is
|
74
|
+
if self.triangles is None:
|
75
|
+
|
76
|
+
assert self.triangle_count is not None and self.node_count is not None
|
77
|
+
|
78
|
+
geometry_node = rqet.find_tag(self.node, 'Geometry')
|
79
|
+
assert geometry_node is not None
|
80
|
+
p_root = rqet.find_tag(geometry_node, 'Points')
|
81
|
+
assert p_root is not None, 'Points xml node not found for triangle patch'
|
82
|
+
assert rqet.node_type(p_root) == 'Point3dHdf5Array'
|
83
|
+
h5_key_pair = self.model.h5_uuid_and_path_for_node(p_root, tag = 'Coordinates')
|
84
|
+
if h5_key_pair is None:
|
85
|
+
return (None, None)
|
86
|
+
try:
|
87
|
+
self.model.h5_array_element(h5_key_pair,
|
88
|
+
cache_array = True,
|
89
|
+
object = self,
|
90
|
+
array_attribute = 'points',
|
91
|
+
dtype = 'float')
|
92
|
+
except Exception:
|
93
|
+
log.error('hdf5 points failure for triangle patch ' + str(self.patch_index))
|
94
|
+
raise
|
95
|
+
self._set_t_type()
|
96
|
+
triangles_node = rqet.find_tag(self.node, 'Triangles')
|
97
|
+
h5_key_pair = self.model.h5_uuid_and_path_for_node(triangles_node)
|
98
|
+
if h5_key_pair is None:
|
99
|
+
log.warning('No Triangles found in xml for patch index: ' + str(self.patch_index))
|
100
|
+
return (None, None)
|
101
|
+
try:
|
102
|
+
self.model.h5_array_element(h5_key_pair,
|
103
|
+
cache_array = True,
|
104
|
+
object = self,
|
105
|
+
array_attribute = 'triangles',
|
106
|
+
dtype = self.t_type)
|
107
|
+
except Exception:
|
108
|
+
log.error('hdf5 triangles failure for triangle patch ' + str(self.patch_index))
|
109
|
+
raise
|
110
|
+
|
111
|
+
if copy:
|
112
|
+
return (self.triangles.copy(), self.points.copy())
|
113
|
+
else:
|
70
114
|
return (self.triangles, self.points)
|
71
|
-
assert self.triangle_count is not None and self.node_count is not None
|
72
|
-
|
73
|
-
geometry_node = rqet.find_tag(self.node, 'Geometry')
|
74
|
-
assert geometry_node is not None
|
75
|
-
p_root = rqet.find_tag(geometry_node, 'Points')
|
76
|
-
assert p_root is not None, 'Points xml node not found for triangle patch'
|
77
|
-
assert rqet.node_type(p_root) == 'Point3dHdf5Array'
|
78
|
-
h5_key_pair = self.model.h5_uuid_and_path_for_node(p_root, tag = 'Coordinates')
|
79
|
-
if h5_key_pair is None:
|
80
|
-
return (None, None)
|
81
|
-
try:
|
82
|
-
self.model.h5_array_element(h5_key_pair,
|
83
|
-
cache_array = True,
|
84
|
-
object = self,
|
85
|
-
array_attribute = 'points',
|
86
|
-
dtype = 'float')
|
87
|
-
except Exception:
|
88
|
-
log.error('hdf5 points failure for triangle patch ' + str(self.patch_index))
|
89
|
-
raise
|
90
|
-
triangles_node = rqet.find_tag(self.node, 'Triangles')
|
91
|
-
h5_key_pair = self.model.h5_uuid_and_path_for_node(triangles_node)
|
92
|
-
if h5_key_pair is None:
|
93
|
-
log.warning('No Triangles found in xml for patch index: ' + str(self.patch_index))
|
94
|
-
return (None, None)
|
95
|
-
try:
|
96
|
-
self.model.h5_array_element(h5_key_pair,
|
97
|
-
cache_array = True,
|
98
|
-
object = self,
|
99
|
-
array_attribute = 'triangles',
|
100
|
-
dtype = 'int')
|
101
|
-
except Exception:
|
102
|
-
log.error('hdf5 triangles failure for triangle patch ' + str(self.patch_index))
|
103
|
-
raise
|
104
|
-
return (self.triangles, self.points)
|
105
115
|
|
106
116
|
def set_to_trimmed_patch(self, larger_patch, xyz_box = None, xy_polygon = None, internal = False):
|
107
117
|
"""Populate this (empty) patch with triangles and points that overlap with a trimming volume.
|
@@ -147,7 +157,7 @@ class TriangulatedPatch:
|
|
147
157
|
# find unique points used by those triangles
|
148
158
|
p_keep = np.unique(large_t[t_in])
|
149
159
|
# note new point index for each old point that is being kept
|
150
|
-
p_map = np.full(len(points_in), -1, dtype =
|
160
|
+
p_map = np.full(len(points_in), -1, dtype = large_t.dtype)
|
151
161
|
p_map[p_keep] = np.arange(len(p_keep))
|
152
162
|
# copy those unique points into a trimmed points array
|
153
163
|
points_trimmed = large_p[p_keep]
|
@@ -190,10 +200,10 @@ class TriangulatedPatch:
|
|
190
200
|
# create pair of triangles
|
191
201
|
if quad_triangles:
|
192
202
|
self.triangle_count = 4
|
193
|
-
self.triangles = np.array([[0, 2, 4], [2, 1, 4], [1, 3, 4], [3, 0, 4]], dtype =
|
203
|
+
self.triangles = np.array([[0, 2, 4], [2, 1, 4], [1, 3, 4], [3, 0, 4]], dtype = self.t_type)
|
194
204
|
else:
|
195
205
|
self.triangle_count = 2
|
196
|
-
self.triangles = np.array([[0, 1, 2], [0, 3, 1]], dtype =
|
206
|
+
self.triangles = np.array([[0, 1, 2], [0, 3, 1]], dtype = self.t_type)
|
197
207
|
|
198
208
|
def set_to_triangle(self, corners):
|
199
209
|
"""Populate this (empty) patch with a single triangle."""
|
@@ -202,12 +212,12 @@ class TriangulatedPatch:
|
|
202
212
|
self.node_count = 3
|
203
213
|
self.points = corners.copy()
|
204
214
|
self.triangle_count = 1
|
205
|
-
self.triangles = np.array([[0, 1, 2]], dtype =
|
215
|
+
self.triangles = np.array([[0, 1, 2]], dtype = self.t_type)
|
206
216
|
|
207
217
|
def set_to_triangle_pair(self, corners):
|
208
218
|
"""Populate this (empty) patch with a pair of triangles."""
|
209
219
|
|
210
|
-
self.set_from_triangles_and_points(np.array([[0, 1, 3], [0, 3, 2]], dtype =
|
220
|
+
self.set_from_triangles_and_points(np.array([[0, 1, 3], [0, 3, 2]], dtype = self.t_type), corners)
|
211
221
|
|
212
222
|
def set_from_triangles_and_points(self, triangles, points):
|
213
223
|
"""Populate this (empty) patch from triangle node indices and points from elsewhere."""
|
@@ -240,7 +250,7 @@ class TriangulatedPatch:
|
|
240
250
|
self.node_count = (n + 1) * (n + 2) // 2
|
241
251
|
self.points = np.empty((self.node_count, 3))
|
242
252
|
self.triangle_count = n * n
|
243
|
-
self.triangles = np.empty((self.triangle_count, 3), dtype =
|
253
|
+
self.triangles = np.empty((self.triangle_count, 3), dtype = self.t_type)
|
244
254
|
self.points[0] = sail_point(centre, radius, azimuth, 0.0).copy()
|
245
255
|
p = 0
|
246
256
|
t = 0
|
@@ -282,11 +292,12 @@ class TriangulatedPatch:
|
|
282
292
|
quad_centres[:, :] = 0.25 * (mesh_xyz[:-1, :-1, :] + mesh_xyz[:-1, 1:, :] + mesh_xyz[1:, :-1, :] +
|
283
293
|
mesh_xyz[1:, 1:, :]).reshape((-1, 3))
|
284
294
|
self.points = np.concatenate((mesh_xyz.copy().reshape((-1, 3)), quad_centres))
|
295
|
+
self._set_t_type()
|
285
296
|
mesh_size = mesh_xyz.size // 3
|
286
297
|
self.node_count = self.points.size // 3
|
287
298
|
self.triangle_count = 4 * (mesh_shape[0] - 1) * (mesh_shape[1] - 1)
|
288
299
|
self.quad_triangles = True
|
289
|
-
triangles = np.empty((mesh_shape[0] - 1, mesh_shape[1] - 1, 4, 3), dtype =
|
300
|
+
triangles = np.empty((mesh_shape[0] - 1, mesh_shape[1] - 1, 4, 3), dtype = self.t_type) # flatten later
|
290
301
|
nic = ni - 1
|
291
302
|
for j in range(mesh_shape[0] - 1):
|
292
303
|
for i in range(nic):
|
@@ -298,10 +309,11 @@ class TriangulatedPatch:
|
|
298
309
|
triangles[j, i, 3, 2] = j * ni + i
|
299
310
|
else:
|
300
311
|
self.points = mesh_xyz.copy().reshape((-1, 3))
|
312
|
+
self._set_t_type()
|
301
313
|
self.node_count = mesh_shape[0] * mesh_shape[1]
|
302
314
|
self.triangle_count = 2 * (mesh_shape[0] - 1) * (mesh_shape[1] - 1)
|
303
315
|
self.quad_triangles = False
|
304
|
-
triangles = np.empty((mesh_shape[0] - 1, mesh_shape[1] - 1, 2, 3), dtype =
|
316
|
+
triangles = np.empty((mesh_shape[0] - 1, mesh_shape[1] - 1, 2, 3), dtype = self.t_type) # flatten later
|
305
317
|
for j in range(mesh_shape[0] - 1):
|
306
318
|
for i in range(mesh_shape[1] - 1):
|
307
319
|
triangles[j, i, 0, 0] = j * ni + i
|
@@ -321,7 +333,7 @@ class TriangulatedPatch:
|
|
321
333
|
|
322
334
|
indices = self.get_indices_from_sparse_meshxyz(mesh_xyz)
|
323
335
|
|
324
|
-
triangles = np.zeros((2 * (mesh_shape[0] - 1) * (mesh_shape[1] - 1), 3), dtype =
|
336
|
+
triangles = np.zeros((2 * (mesh_shape[0] - 1) * (mesh_shape[1] - 1), 3), dtype = self.t_type) # truncate later
|
325
337
|
nt = 0
|
326
338
|
for j in range(mesh_shape[0] - 1):
|
327
339
|
for i in range(mesh_shape[1] - 1):
|
@@ -357,7 +369,7 @@ class TriangulatedPatch:
|
|
357
369
|
else:
|
358
370
|
raise Exception('code failure in sparse mesh processing')
|
359
371
|
self.ni = None
|
360
|
-
self.triangles = triangles[:nt, :]
|
372
|
+
self.triangles = triangles[:nt, :].copy()
|
361
373
|
self.triangle_count = nt
|
362
374
|
|
363
375
|
def get_indices_from_sparse_meshxyz(self, mesh_xyz):
|
@@ -373,6 +385,7 @@ class TriangulatedPatch:
|
|
373
385
|
points[i] = mesh_xyz[non_nans[0][i], non_nans[1][i]]
|
374
386
|
indices[non_nans[0][i], non_nans[1][i]] = i
|
375
387
|
self.points = points[:len(non_nans[0]), :]
|
388
|
+
self._set_t_type()
|
376
389
|
self.node_count = len(non_nans[0])
|
377
390
|
|
378
391
|
return indices
|
@@ -389,11 +402,12 @@ class TriangulatedPatch:
|
|
389
402
|
quad_centres = np.empty((nj, ni, 3))
|
390
403
|
quad_centres[:, :, :] = 0.25 * np.sum(mesh_xyz, axis = (2, 3))
|
391
404
|
self.points = np.concatenate((mesh_xyz.copy().reshape((-1, 3)), quad_centres.reshape((-1, 3))))
|
405
|
+
self._set_t_type()
|
392
406
|
mesh_size = mesh_xyz.size // 3
|
393
407
|
self.node_count = 5 * nj * ni
|
394
408
|
self.triangle_count = 4 * nj * ni
|
395
409
|
self.quad_triangles = True
|
396
|
-
triangles = np.empty((nj, ni, 4, 3), dtype =
|
410
|
+
triangles = np.empty((nj, ni, 4, 3), dtype = self.t_type) # flatten later
|
397
411
|
for j in range(nj):
|
398
412
|
for i in range(ni):
|
399
413
|
base_p = 4 * (j * ni + i)
|
@@ -405,10 +419,11 @@ class TriangulatedPatch:
|
|
405
419
|
triangles[j, i, 3, 2] = base_p
|
406
420
|
else:
|
407
421
|
self.points = mesh_xyz.copy().reshape((-1, 3))
|
422
|
+
self._set_t_type()
|
408
423
|
self.node_count = 4 * nj * ni
|
409
424
|
self.triangle_count = 2 * nj * ni
|
410
425
|
self.quad_triangles = False
|
411
|
-
triangles = np.empty((nj, ni, 2, 3), dtype =
|
426
|
+
triangles = np.empty((nj, ni, 2, 3), dtype = self.t_type) # flatten later
|
412
427
|
for j in range(nj):
|
413
428
|
for i in range(ni):
|
414
429
|
base_p = 4 * (j * ni + i)
|
@@ -469,7 +484,8 @@ class TriangulatedPatch:
|
|
469
484
|
self.triangle_count = 12
|
470
485
|
self.node_count = 8
|
471
486
|
self.points = cp.copy().reshape((-1, 3))
|
472
|
-
|
487
|
+
self._set_t_type()
|
488
|
+
triangles = np.empty((3, 2, 2, 3), dtype = self.t_type) # flatten later
|
473
489
|
for axis in range(3):
|
474
490
|
if axis == 0:
|
475
491
|
ip1, ip2 = 2, 1
|
@@ -500,7 +516,8 @@ class TriangulatedPatch:
|
|
500
516
|
quad_centres[2, 1, :] = 0.25 * np.sum(cp[:, :, 1, :], axis = (0, 1)) # I+
|
501
517
|
self.node_count = 14
|
502
518
|
self.points = np.concatenate((cp.copy().reshape((-1, 3)), quad_centres.reshape((-1, 3))))
|
503
|
-
|
519
|
+
self._set_t_type()
|
520
|
+
triangles = np.empty((3, 2, 4, 3), dtype = self.t_type) # flatten later
|
504
521
|
for axis in range(3):
|
505
522
|
if axis == 0:
|
506
523
|
ip1, ip2 = 2, 1
|
@@ -544,3 +561,6 @@ class TriangulatedPatch:
|
|
544
561
|
_, _ = self.triangles_and_points() # ensure points are loaded
|
545
562
|
z_values = self.points[:, 2].copy()
|
546
563
|
self.points[:, 2] = ref_depth + scaling_factor * (z_values - ref_depth)
|
564
|
+
|
565
|
+
def _set_t_type(self):
|
566
|
+
self.t_type = np.int64 if len(self.points) > 2_147_483_648 else np.int32
|
resqpy/well/_blocked_well.py
CHANGED
@@ -136,6 +136,7 @@ class BlockedWell(BaseResqpy):
|
|
136
136
|
self.wellbore_interpretation = None #: associated wellbore interpretation object
|
137
137
|
self.wellbore_feature = None #: associated wellbore feature object
|
138
138
|
self.well_name = None #: name of well to import from ascii file formats
|
139
|
+
self.cell_index_dtype = np.int32 #: set to int64 if any grid has more than 2^31 - 1 cells, otherwise int32
|
139
140
|
|
140
141
|
self.cell_interval_map = None # maps from cell index to interval (ie. node) index; populated on demand
|
141
142
|
|
@@ -150,11 +151,11 @@ class BlockedWell(BaseResqpy):
|
|
150
151
|
# this is the default as indicated on page 139 (but not p. 180) of the RESQML Usage Gude v2.0.1
|
151
152
|
# also assumes K is generally increasing downwards
|
152
153
|
# see DevOps backlog item 269001 discussion for more information
|
153
|
-
# self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype =
|
154
|
-
self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype =
|
154
|
+
# self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = np.int8)
|
155
|
+
self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = np.int8) # order: top, base, J-, I+, J+, I-
|
155
156
|
# and the inverse, maps from 0..5 to (axis, p01)
|
156
|
-
# self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype =
|
157
|
-
self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype =
|
157
|
+
# self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = np.int8)
|
158
|
+
self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = np.int8)
|
158
159
|
# note: the rework_face_pairs() method, below, overwrites the face indices based on I, J cell indices
|
159
160
|
|
160
161
|
super().__init__(model = parent_model,
|
@@ -238,14 +239,14 @@ class BlockedWell(BaseResqpy):
|
|
238
239
|
|
239
240
|
assert self.cell_count < self.node_count
|
240
241
|
|
241
|
-
self.__find_ci_node_and_load_hdf5_array(node = node)
|
242
|
-
|
243
|
-
self.__find_fi_node_and_load_hdf5_array(node)
|
244
|
-
|
245
242
|
unique_grid_indices = self.__find_gi_node_and_load_hdf5_array(node = node)
|
246
243
|
|
247
244
|
self.__find_grid_node(node = node, unique_grid_indices = unique_grid_indices)
|
248
245
|
|
246
|
+
self.__find_ci_node_and_load_hdf5_array(node = node)
|
247
|
+
|
248
|
+
self.__find_fi_node_and_load_hdf5_array(node)
|
249
|
+
|
249
250
|
interp_uuid = rqet.find_nested_tags_text(node, ['RepresentedInterpretation', 'UUID'])
|
250
251
|
if interp_uuid is None:
|
251
252
|
self.wellbore_interpretation = None
|
@@ -273,7 +274,7 @@ class BlockedWell(BaseResqpy):
|
|
273
274
|
|
274
275
|
ci_node = rqet.find_tag(node, 'CellIndices')
|
275
276
|
assert ci_node is not None, 'blocked well cell indices hdf5 reference not found in xml'
|
276
|
-
rqwu.load_hdf5_array(self, ci_node, 'cell_indices', dtype =
|
277
|
+
rqwu.load_hdf5_array(self, ci_node, 'cell_indices', dtype = self.cell_index_dtype)
|
277
278
|
assert (self.cell_indices is not None and self.cell_indices.ndim == 1 and
|
278
279
|
self.cell_indices.size == self.cell_count), 'mismatch in number of cell indices for blocked well'
|
279
280
|
self.cellind_null = rqet.find_tag_int(ci_node, 'NullValue')
|
@@ -285,7 +286,7 @@ class BlockedWell(BaseResqpy):
|
|
285
286
|
|
286
287
|
fi_node = rqet.find_tag(node, 'LocalFacePairPerCellIndices')
|
287
288
|
assert fi_node is not None, 'blocked well face indices hdf5 reference not found in xml'
|
288
|
-
rqwu.load_hdf5_array(self, fi_node, 'raw_face_indices', dtype =
|
289
|
+
rqwu.load_hdf5_array(self, fi_node, 'raw_face_indices', dtype = np.int8)
|
289
290
|
assert self.raw_face_indices is not None, 'failed to load face indices for blocked well'
|
290
291
|
assert self.raw_face_indices.size == 2 * self.cell_count, 'mismatch in number of cell faces for blocked well'
|
291
292
|
if self.raw_face_indices.ndim > 1:
|
@@ -305,15 +306,14 @@ class BlockedWell(BaseResqpy):
|
|
305
306
|
|
306
307
|
gi_node = rqet.find_tag(node, 'GridIndices')
|
307
308
|
assert gi_node is not None, 'blocked well grid indices hdf5 reference not found in xml'
|
308
|
-
rqwu.load_hdf5_array(self, gi_node, 'grid_indices', dtype =
|
309
|
+
rqwu.load_hdf5_array(self, gi_node, 'grid_indices', dtype = np.int32)
|
309
310
|
# assert self.grid_indices is not None and self.grid_indices.ndim == 1 and self.grid_indices.size == self.node_count - 1
|
310
311
|
# temporary code to handle blocked wells with incorrectly shaped grid indices wrt. nodes
|
311
312
|
assert self.grid_indices is not None and self.grid_indices.ndim == 1
|
312
313
|
if self.grid_indices.size != self.node_count - 1:
|
313
314
|
if self.grid_indices.size == self.cell_count and self.node_count == 2 * self.cell_count:
|
314
315
|
log.warning(f'handling node duplication or missing unblocked intervals in blocked well: {self.title}')
|
315
|
-
|
316
|
-
expanded_grid_indices = np.full(self.node_count - 1, -1, dtype = int)
|
316
|
+
expanded_grid_indices = np.full(self.node_count - 1, -1, dtype = np.int32)
|
317
317
|
expanded_grid_indices[::2] = self.grid_indices
|
318
318
|
self.grid_indices = expanded_grid_indices
|
319
319
|
else:
|
@@ -342,6 +342,8 @@ class BlockedWell(BaseResqpy):
|
|
342
342
|
grid_uuid = rqet.uuid_for_part_root(grid_node)
|
343
343
|
grid_obj = self.model.grid(uuid = grid_uuid, find_properties = False)
|
344
344
|
self.grid_list.append(grid_obj)
|
345
|
+
if grid_obj.is_big():
|
346
|
+
self.cell_index_dtype = np.int64
|
345
347
|
|
346
348
|
def extract_property_collection(self, refresh = False):
|
347
349
|
"""Returns a property collection for the blocked well."""
|
@@ -434,7 +436,7 @@ class BlockedWell(BaseResqpy):
|
|
434
436
|
def _set_cell_interval_map(self):
|
435
437
|
"""Sets up an index mapping from blocked cell index to interval index, accounting for unblocked intervals."""
|
436
438
|
|
437
|
-
self.cell_interval_map = np.zeros(self.cell_count, dtype =
|
439
|
+
self.cell_interval_map = np.zeros(self.cell_count, dtype = np.int32)
|
438
440
|
ci = 0
|
439
441
|
for ii in range(self.node_count - 1):
|
440
442
|
if self.grid_indices[ii] < 0:
|
@@ -461,7 +463,7 @@ class BlockedWell(BaseResqpy):
|
|
461
463
|
grid_for_cell_list = []
|
462
464
|
grid_indices = self.compressed_grid_indices()
|
463
465
|
assert len(grid_indices) == self.cell_count
|
464
|
-
cell_indices = np.empty((self.cell_count, 3), dtype =
|
466
|
+
cell_indices = np.empty((self.cell_count, 3), dtype = np.int32)
|
465
467
|
for cell_number in range(self.cell_count):
|
466
468
|
grid = self.grid_list[grid_indices[cell_number]]
|
467
469
|
grid_for_cell_list.append(grid)
|
@@ -493,7 +495,7 @@ class BlockedWell(BaseResqpy):
|
|
493
495
|
|
494
496
|
if cells_kji0 is None or len(cells_kji0) == 0:
|
495
497
|
return None
|
496
|
-
well_box = np.empty((2, 3), dtype =
|
498
|
+
well_box = np.empty((2, 3), dtype = np.int32)
|
497
499
|
well_box[0] = np.min(cells_kji0, axis = 0)
|
498
500
|
well_box[1] = np.max(cells_kji0, axis = 0)
|
499
501
|
return well_box
|
@@ -853,9 +855,9 @@ class BlockedWell(BaseResqpy):
|
|
853
855
|
self.node_count = len(trajectory_mds)
|
854
856
|
self.node_mds = np.array(trajectory_mds)
|
855
857
|
self.cell_count = len(blocked_cells_kji0)
|
856
|
-
self.grid_indices = np.array(blocked_intervals, dtype =
|
857
|
-
self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0))
|
858
|
-
self.face_pair_indices = np.array(blocked_face_pairs, dtype =
|
858
|
+
self.grid_indices = np.array(blocked_intervals, dtype = np.int32) # NB. only supporting one grid at the moment
|
859
|
+
self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0)).astype(self.cell_index_dtype)
|
860
|
+
self.face_pair_indices = np.array(blocked_face_pairs, dtype = np.int8)
|
859
861
|
self.grid_list = [grid]
|
860
862
|
|
861
863
|
trajectory_points, trajectory_mds = BlockedWell.__add_tail_to_trajectory_if_necessary(
|
@@ -877,7 +879,7 @@ class BlockedWell(BaseResqpy):
|
|
877
879
|
row = df.iloc[df_row]
|
878
880
|
if pd.isna(row[0]) or pd.isna(row[1]) or pd.isna(row[2]):
|
879
881
|
return None
|
880
|
-
cell_kji0 = np.empty((3,), dtype =
|
882
|
+
cell_kji0 = np.empty((3,), dtype = np.int32)
|
881
883
|
cell_kji0[:] = row[2], row[1], row[0]
|
882
884
|
cell_kji0[:] -= 1
|
883
885
|
return cell_kji0
|
@@ -1201,9 +1203,10 @@ class BlockedWell(BaseResqpy):
|
|
1201
1203
|
self.node_count = len(trajectory_mds)
|
1202
1204
|
self.node_mds = np.array(trajectory_mds)
|
1203
1205
|
self.cell_count = len(blocked_cells_kji0)
|
1204
|
-
|
1205
|
-
|
1206
|
-
self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0))
|
1206
|
+
# NB. only supporting one grid at the moment
|
1207
|
+
self.grid_indices = np.array(blocked_intervals, dtype = np.int32)
|
1208
|
+
self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0)).astype(
|
1209
|
+
self.cell_index_dtype)
|
1207
1210
|
self.face_pair_indices = np.array(blocked_face_pairs)
|
1208
1211
|
self.grid_list = [grid]
|
1209
1212
|
|
@@ -1240,7 +1243,7 @@ class BlockedWell(BaseResqpy):
|
|
1240
1243
|
words = line.split()
|
1241
1244
|
assert len(words) >= 9, 'not enough items on data line in cell I/O file, minimum 9 expected'
|
1242
1245
|
i1, j1, k1 = int(words[0]), int(words[1]), int(words[2])
|
1243
|
-
cell_kji0 = np.array((k1 - 1, j1 - 1, i1 - 1), dtype =
|
1246
|
+
cell_kji0 = np.array((k1 - 1, j1 - 1, i1 - 1), dtype = np.int32)
|
1244
1247
|
assert np.all(0 <= cell_kji0) and np.all(
|
1245
1248
|
cell_kji0 < grid.extent_kji), 'cell I/O cell index not within grid extent'
|
1246
1249
|
entry_xyz = np.array((float(words[3]), float(words[4]), float(words[5])))
|
@@ -1511,7 +1514,7 @@ class BlockedWell(BaseResqpy):
|
|
1511
1514
|
for grid in self.grid_list:
|
1512
1515
|
grid.cache_all_geometry_arrays()
|
1513
1516
|
|
1514
|
-
k_face_check = np.zeros((2, 2), dtype =
|
1517
|
+
k_face_check = np.zeros((2, 2), dtype = np.int8)
|
1515
1518
|
k_face_check[1, 1] = 1 # now represents entry, exit of K-, K+
|
1516
1519
|
k_face_check_end = k_face_check.copy()
|
1517
1520
|
k_face_check_end[1] = -1 # entry through K-, terminating (TD) within cell
|
resqpy/well/_trajectory.py
CHANGED
@@ -448,7 +448,7 @@ class Trajectory(BaseResqpy):
|
|
448
448
|
"""Loads the trajectory object based on the centre points of a list of cells."""
|
449
449
|
|
450
450
|
assert grid is not None, 'grid argument missing for trajectory initislisation from cell list'
|
451
|
-
cell_kji0_list = np.array(cell_kji0_list, dtype =
|
451
|
+
cell_kji0_list = np.array(cell_kji0_list, dtype = np.int32)
|
452
452
|
assert cell_kji0_list.ndim == 2 and cell_kji0_list.shape[1] == 3
|
453
453
|
assert spline_mode in ['none', 'linear', 'square', 'cube']
|
454
454
|
|
@@ -483,7 +483,7 @@ class Trajectory(BaseResqpy):
|
|
483
483
|
df = wellspec_dict[well_name]
|
484
484
|
assert len(df) > 0, 'no rows of perforation data found in wellspec for well ' + well_name
|
485
485
|
|
486
|
-
cell_kji0_list = np.empty((len(df), 3), dtype =
|
486
|
+
cell_kji0_list = np.empty((len(df), 3), dtype = np.int32)
|
487
487
|
cell_kji0_list[:, 0] = df['L']
|
488
488
|
cell_kji0_list[:, 1] = df['JW']
|
489
489
|
cell_kji0_list[:, 2] = df['IW']
|
@@ -191,7 +191,7 @@ def add_blocked_well_properties_from_wellbore_frame(bw,
|
|
191
191
|
wb_a = np.zeros(bw.cell_count, dtype = bool)
|
192
192
|
length = np.zeros(bw.cell_count, dtype = float)
|
193
193
|
pperf = np.zeros(bw.cell_count, dtype = float)
|
194
|
-
dominant_wbf_interval = np.full(bw.cell_count, -1, dtype =
|
194
|
+
dominant_wbf_interval = np.full(bw.cell_count, -1, dtype = np.int32)
|
195
195
|
ci = 0
|
196
196
|
for wb_ii in range(bw.node_count - 1):
|
197
197
|
if bw.grid_indices[wb_ii] < 0:
|
resqpy/well/well_object_funcs.py
CHANGED
@@ -442,10 +442,10 @@ def add_logs_from_cellio(blockedwell, cellio):
|
|
442
442
|
df = df.apply(pd.to_numeric)
|
443
443
|
# Get the cell_indices from the grid for the given i/j/k
|
444
444
|
df['cell_indices'] = grid.natural_cell_indices(
|
445
|
-
np.array((df['k_index'] - 1, df['j_index'] - 1, df['i_index'] - 1), dtype =
|
445
|
+
np.array((df['k_index'] - 1, df['j_index'] - 1, df['i_index'] - 1), dtype = np.int32).T)
|
446
446
|
df = df.drop(['i_index', 'j_index', 'k_index', 'x_in', 'y_in', 'z_in', 'x_out', 'y_out', 'z_out'], axis = 1)
|
447
|
-
assert (df['cell_indices'] == blockedwell.cell_indices
|
448
|
-
|
447
|
+
assert (df['cell_indices'] == blockedwell.cell_indices).all(), \
|
448
|
+
'Cell indices do not match between blocked well and log inputs'
|
449
449
|
|
450
450
|
# Work out if the data columns are continuous, categorical or discrete
|
451
451
|
type_dict = {}
|
@@ -468,11 +468,11 @@ def add_logs_from_cellio(blockedwell, cellio):
|
|
468
468
|
if log not in ['cell_indices']:
|
469
469
|
data_type = type_dict[log]
|
470
470
|
if log == 'ZONES':
|
471
|
-
data_type, dtype, null, discrete = 'discrete',
|
471
|
+
data_type, dtype, null, discrete = 'discrete', np.int32, -1, True
|
472
472
|
elif data_type == 'continuous':
|
473
473
|
dtype, null, discrete = float, np.nan, False
|
474
474
|
else:
|
475
|
-
dtype, null, discrete =
|
475
|
+
dtype, null, discrete = np.int32, -1, True
|
476
476
|
if data_type == 'categorical':
|
477
477
|
lookup_uuid = lookup_dict[log] # For categorical data, find or generate a StringLookupTable
|
478
478
|
else:
|