resqpy 4.17.0__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 +150 -16
- resqpy/grid_surface/__init__.py +4 -0
- resqpy/grid_surface/_find_faces.py +727 -209
- resqpy/olio/vector_utilities.py +175 -1
- resqpy/surface/_surface.py +25 -14
- resqpy/surface/_triangulated_patch.py +46 -38
- {resqpy-4.17.0.dist-info → resqpy-4.17.1.dist-info}/METADATA +1 -1
- {resqpy-4.17.0.dist-info → resqpy-4.17.1.dist-info}/RECORD +11 -11
- {resqpy-4.17.0.dist-info → resqpy-4.17.1.dist-info}/LICENSE +0 -0
- {resqpy-4.17.0.dist-info → resqpy-4.17.1.dist-info}/WHEEL +0 -0
resqpy/__init__.py
CHANGED
@@ -10,6 +10,7 @@ import math as maths
|
|
10
10
|
import numpy as np
|
11
11
|
import pandas as pd
|
12
12
|
|
13
|
+
import resqpy.grid as grr
|
13
14
|
import resqpy.fault
|
14
15
|
import resqpy.olio.read_nexus_fault as rnf
|
15
16
|
import resqpy.olio.trademark as tm
|
@@ -199,6 +200,109 @@ class GridConnectionSet(BaseResqpy):
|
|
199
200
|
self.extract_property_collection()
|
200
201
|
self._set_cell_index_dtype()
|
201
202
|
|
203
|
+
@classmethod
|
204
|
+
def from_faces_indices(cls,
|
205
|
+
grid,
|
206
|
+
k_faces_kji0,
|
207
|
+
j_faces_kji0,
|
208
|
+
i_faces_kji0,
|
209
|
+
remove_duplicates = True,
|
210
|
+
k_properties = None,
|
211
|
+
j_properties = None,
|
212
|
+
i_properties = None,
|
213
|
+
feature_name = None,
|
214
|
+
feature_type = 'fault',
|
215
|
+
create_organizing_objects_where_needed = True,
|
216
|
+
title = None,
|
217
|
+
originator = None,
|
218
|
+
extra_metadata = None):
|
219
|
+
"""Create a GridConnectionSet given a grid and 3 list-like arrays identifying faces by indices.
|
220
|
+
|
221
|
+
arguments:
|
222
|
+
- grid (Grid): the single grid to be referenced by the grid connection set
|
223
|
+
- k_faces_kji0 (numpy int array of shape (Nk, 3)): indices of cells on negative side of desired K faces
|
224
|
+
- j_faces_kji0 (numpy int array of shape (Nj, 3)): indices of cells on negative side of desired J faces
|
225
|
+
- i_faces_kji0 (numpy int array of shape (Ni, 3)): indices of cells on negative side of desired I faces
|
226
|
+
- remove_duplicates (bool, default True): if True, indices are sorted and duplicates removed
|
227
|
+
- k_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
|
228
|
+
is sorted and has elements removed to keep them compatible with the indices
|
229
|
+
- j_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
|
230
|
+
is sorted and has elements removed to keep them compatible with the indices
|
231
|
+
- i_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
|
232
|
+
is sorted and has elements removed to keep them compatible with the indices
|
233
|
+
- feature_name (string, optional): the feature name to use when setting from faces
|
234
|
+
- feature_type (string, default 'fault'): 'fault', 'horizon' or 'geobody boundary'
|
235
|
+
- create_organizing_objects_where_needed (boolean, default True): if True, a fault interpretation object
|
236
|
+
and tectonic boundary feature object will be created if such objects do not exist for the feature;
|
237
|
+
if False, missing organizational objects will cause an error to be logged
|
238
|
+
- title (str, optional): the citation title to use for a new grid connection set
|
239
|
+
- originator (str, optional): the name of the person creating the new grid connection set, defaults to login id
|
240
|
+
- extra_metadata (dict, optional): string key, value pairs to add as extra metadata for the grid connection set
|
241
|
+
|
242
|
+
returns:
|
243
|
+
- a new GridConnectionSet populated based on the faces indices
|
244
|
+
|
245
|
+
notes:
|
246
|
+
- this method only supports creation of single grid connection sets
|
247
|
+
- the faces indices are for cells on the negative side of the face
|
248
|
+
- the paired cell is implicitly the neighbouring cell in the positive direction of the axis
|
249
|
+
- the indices must therefore not include the last cell in the axis, though this is not checked
|
250
|
+
- if properties are passed, they should be passed in list variables which have their elements
|
251
|
+
replaced; individual property arrays should therefore be extracted from the lists afterwards
|
252
|
+
"""
|
253
|
+
assert isinstance(grid, grr.Grid)
|
254
|
+
|
255
|
+
gcs = cls(grid.model, title = title, originator = originator, extra_metadata = extra_metadata)
|
256
|
+
|
257
|
+
gcs._sort_out_organizing_objects(feature_type, feature_name, create_organizing_objects_where_needed)
|
258
|
+
|
259
|
+
nj_ni = grid.nj * grid.ni
|
260
|
+
if k_faces_kji0 is not None and len(k_faces_kji0) > 0:
|
261
|
+
ci = grid.natural_cell_indices(k_faces_kji0)
|
262
|
+
if remove_duplicates:
|
263
|
+
ci = _sort_and_remove_duplicates(ci, k_properties)
|
264
|
+
cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
|
265
|
+
cip[:, 0] = ci
|
266
|
+
cip[:, 1] = ci + nj_ni
|
267
|
+
fip = np.empty(cip.shape, dtype = np.int8)
|
268
|
+
fip[:, 0] = gcs.face_index_map[0, 1]
|
269
|
+
fip[:, 1] = gcs.face_index_map[0, 0]
|
270
|
+
else:
|
271
|
+
cip = np.empty((0, 2), dtype = gcs.cell_index_dtype)
|
272
|
+
fip = np.empty((0, 2), dtype = np.int8)
|
273
|
+
if j_faces_kji0 is not None and len(j_faces_kji0) > 0:
|
274
|
+
ci = grid.natural_cell_indices(j_faces_kji0)
|
275
|
+
if remove_duplicates:
|
276
|
+
ci = _sort_and_remove_duplicates(ci, j_properties)
|
277
|
+
j_cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
|
278
|
+
j_cip[:, 0] = ci
|
279
|
+
j_cip[:, 1] = ci + grid.ni
|
280
|
+
j_fip = np.empty(j_cip.shape, dtype = np.int8)
|
281
|
+
j_fip[:, 0] = gcs.face_index_map[1, 1]
|
282
|
+
j_fip[:, 1] = gcs.face_index_map[1, 0]
|
283
|
+
cip = np.concatenate((cip, j_cip), axis = 0)
|
284
|
+
fip = np.concatenate((fip, j_fip), axis = 0)
|
285
|
+
del j_cip, j_fip
|
286
|
+
if i_faces_kji0 is not None and len(i_faces_kji0) > 0:
|
287
|
+
ci = grid.natural_cell_indices(i_faces_kji0)
|
288
|
+
if remove_duplicates:
|
289
|
+
ci = _sort_and_remove_duplicates(ci, i_properties)
|
290
|
+
i_cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
|
291
|
+
i_cip[:, 0] = ci
|
292
|
+
i_cip[:, 1] = ci + 1
|
293
|
+
i_fip = np.empty(i_cip.shape, dtype = np.int8)
|
294
|
+
i_fip[:, 0] = gcs.face_index_map[2, 1]
|
295
|
+
i_fip[:, 1] = gcs.face_index_map[2, 0]
|
296
|
+
cip = np.concatenate((cip, i_cip), axis = 0)
|
297
|
+
fip = np.concatenate((fip, i_fip), axis = 0)
|
298
|
+
del i_cip, i_fip
|
299
|
+
gcs.cell_index_pairs = cip
|
300
|
+
gcs.face_index_pairs = fip
|
301
|
+
gcs.count = len(gcs.cell_index_pairs)
|
302
|
+
gcs.feature_indices = np.zeros(gcs.count, dtype = np.int8)
|
303
|
+
assert len(gcs.face_index_pairs) == gcs.count
|
304
|
+
return gcs
|
305
|
+
|
202
306
|
@classmethod
|
203
307
|
def from_gcs_uuid_list(cls,
|
204
308
|
parent_model,
|
@@ -448,24 +552,13 @@ class GridConnectionSet(BaseResqpy):
|
|
448
552
|
create_organizing_objects_where_needed,
|
449
553
|
feature_type = feature_type)
|
450
554
|
|
451
|
-
def
|
452
|
-
|
453
|
-
k_faces,
|
454
|
-
j_faces,
|
455
|
-
i_faces,
|
456
|
-
feature_name,
|
457
|
-
create_organizing_objects_where_needed,
|
458
|
-
feature_type = 'fault', # other feature_type values: 'horizon', 'geobody boundary'
|
459
|
-
k_sides = None,
|
460
|
-
j_sides = None,
|
461
|
-
i_sides = None):
|
462
|
-
"""Sets cell_index_pairs and face_index_pairs based on triple face masks, using simple no throw pairing."""
|
463
|
-
|
555
|
+
def _sort_out_organizing_objects(self, feature_type, feature_name, create_organizing_objects_where_needed):
|
556
|
+
"""Finds or creates interpretation and feature objects."""
|
464
557
|
assert feature_type in ['fault', 'horizon', 'geobody boundary']
|
465
558
|
if feature_name is None:
|
466
|
-
feature_name = 'feature from
|
559
|
+
feature_name = 'feature from faces' # not sure this default is wise
|
467
560
|
if len(self.grid_list) > 1:
|
468
|
-
log.warning('setting grid connection set pairs from
|
561
|
+
log.warning('setting grid connection set pairs from faces for first grid in list only')
|
469
562
|
grid = self.grid_list[0]
|
470
563
|
if feature_type == 'fault':
|
471
564
|
feature_flavour = 'TectonicBoundaryFeature'
|
@@ -522,6 +615,23 @@ class GridConnectionSet(BaseResqpy):
|
|
522
615
|
log.error('no interpretation found for feature: ' + feature_name)
|
523
616
|
return
|
524
617
|
self.feature_list = [('obj_' + interpretation_flavour, fi_uuid, str(feature_name))]
|
618
|
+
|
619
|
+
def set_pairs_from_face_masks(
|
620
|
+
self,
|
621
|
+
k_faces,
|
622
|
+
j_faces,
|
623
|
+
i_faces,
|
624
|
+
feature_name,
|
625
|
+
create_organizing_objects_where_needed,
|
626
|
+
feature_type = 'fault', # other feature_type values: 'horizon', 'geobody boundary'
|
627
|
+
k_sides = None,
|
628
|
+
j_sides = None,
|
629
|
+
i_sides = None):
|
630
|
+
"""Sets cell_index_pairs and face_index_pairs based on triple face masks, using simple no throw pairing."""
|
631
|
+
|
632
|
+
self._sort_out_organizing_objects(feature_type, feature_name, create_organizing_objects_where_needed)
|
633
|
+
|
634
|
+
grid = self.grid_list[0]
|
525
635
|
cell_pair_list = []
|
526
636
|
face_pair_list = []
|
527
637
|
nj_ni = grid.nj * grid.ni
|
@@ -561,7 +671,7 @@ class GridConnectionSet(BaseResqpy):
|
|
561
671
|
self.cell_index_pairs = np.array(cell_pair_list, dtype = self.cell_index_dtype)
|
562
672
|
self.face_index_pairs = np.array(face_pair_list, dtype = np.int8)
|
563
673
|
self.count = len(self.cell_index_pairs)
|
564
|
-
self.feature_indices = np.zeros(self.count, dtype = np.
|
674
|
+
self.feature_indices = np.zeros(self.count, dtype = np.int8)
|
565
675
|
assert len(self.face_index_pairs) == self.count
|
566
676
|
|
567
677
|
def set_pairs_from_faces_df(self,
|
@@ -2190,3 +2300,27 @@ def _copy_organisation_objects(target_model, source_model, gcs):
|
|
2190
2300
|
for _, uuid, _ in gcs.feature_list:
|
2191
2301
|
target_model.copy_uuid_from_other_model(source_model,
|
2192
2302
|
uuid) # will copy related features as well as interpretations
|
2303
|
+
|
2304
|
+
|
2305
|
+
def _sort_and_remove_duplicates(a, props = None):
|
2306
|
+
"""Return copy of 1D array a, sorted and with duplicates removed; secondary arrays can be kept in alignment."""
|
2307
|
+
if a is None or a.size <= 1:
|
2308
|
+
return a
|
2309
|
+
assert a.ndim == 1
|
2310
|
+
si = None
|
2311
|
+
no_props = (props is None or len(props) == 0)
|
2312
|
+
if no_props:
|
2313
|
+
a = np.sort(a)
|
2314
|
+
else:
|
2315
|
+
si = np.argsort(a)
|
2316
|
+
a = a[si]
|
2317
|
+
m = np.empty(a.size, dtype = bool)
|
2318
|
+
m[0] = True
|
2319
|
+
m[1:] = (a[1:] != a[:-1])
|
2320
|
+
if np.all(m):
|
2321
|
+
return a
|
2322
|
+
if not no_props:
|
2323
|
+
for i in range(len(props)):
|
2324
|
+
p = props[i][si]
|
2325
|
+
props[i] = p[m]
|
2326
|
+
return a[m]
|
resqpy/grid_surface/__init__.py
CHANGED
@@ -20,11 +20,13 @@ __all__ = [
|
|
20
20
|
"find_faces_to_represent_surface_staffa",
|
21
21
|
"find_faces_to_represent_surface_regular",
|
22
22
|
"find_faces_to_represent_surface_regular_optimised",
|
23
|
+
"find_faces_to_represent_surface_regular_dense_optimised",
|
23
24
|
"find_faces_to_represent_surface",
|
24
25
|
"bisector_from_faces",
|
25
26
|
"column_bisector_from_faces",
|
26
27
|
"shadow_from_faces",
|
27
28
|
"get_boundary",
|
29
|
+
"get_boundary_dict",
|
28
30
|
"_where_true",
|
29
31
|
"_first_true",
|
30
32
|
"intersect_numba",
|
@@ -56,11 +58,13 @@ from ._find_faces import (
|
|
56
58
|
find_faces_to_represent_surface_staffa,
|
57
59
|
find_faces_to_represent_surface_regular,
|
58
60
|
find_faces_to_represent_surface_regular_optimised,
|
61
|
+
find_faces_to_represent_surface_regular_dense_optimised,
|
59
62
|
find_faces_to_represent_surface,
|
60
63
|
bisector_from_faces,
|
61
64
|
column_bisector_from_faces,
|
62
65
|
shadow_from_faces,
|
63
66
|
get_boundary,
|
67
|
+
get_boundary_dict,
|
64
68
|
_where_true,
|
65
69
|
_first_true,
|
66
70
|
intersect_numba,
|