resqpy 4.5.0__py3-none-any.whl → 4.6.3__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/grid/_defined_geometry.py +15 -9
- resqpy/grid_surface/__init__.py +61 -40
- resqpy/grid_surface/_find_faces.py +351 -243
- resqpy/grid_surface/grid_surface_cuda.py +172 -125
- resqpy/lines/_common.py +10 -7
- resqpy/lines/_polyline.py +20 -0
- resqpy/lines/_polyline_set.py +64 -34
- resqpy/model/_hdf5.py +17 -7
- resqpy/model/_model.py +2 -1
- resqpy/model/_xml.py +4 -4
- resqpy/multi_processing/_multiprocessing.py +1 -0
- resqpy/multi_processing/wrappers/grid_surface_mp.py +12 -3
- resqpy/olio/intersection.py +2 -3
- resqpy/olio/read_nexus_fault.py +71 -67
- resqpy/olio/triangulation.py +66 -22
- resqpy/olio/vector_utilities.py +175 -71
- resqpy/olio/wellspec_keywords.py +5 -4
- resqpy/olio/write_hdf5.py +16 -8
- resqpy/olio/xml_et.py +3 -3
- resqpy/property/_collection_get_attributes.py +11 -5
- resqpy/property/_property.py +16 -5
- resqpy/property/property_collection.py +36 -11
- resqpy/surface/__init__.py +2 -2
- resqpy/surface/_surface.py +69 -6
- resqpy/time_series/__init__.py +3 -2
- resqpy/time_series/_time_series.py +10 -0
- {resqpy-4.5.0.dist-info → resqpy-4.6.3.dist-info}/METADATA +3 -3
- {resqpy-4.5.0.dist-info → resqpy-4.6.3.dist-info}/RECORD +31 -31
- {resqpy-4.5.0.dist-info → resqpy-4.6.3.dist-info}/WHEEL +1 -1
- {resqpy-4.5.0.dist-info → resqpy-4.6.3.dist-info}/LICENSE +0 -0
@@ -14,7 +14,7 @@ from typing import Tuple, Optional, Dict
|
|
14
14
|
import threading
|
15
15
|
|
16
16
|
import numba # type: ignore
|
17
|
-
from numba import
|
17
|
+
from numba import cuda # type: ignore
|
18
18
|
from numba.cuda.cudadrv.devicearray import DeviceNDArray # type: ignore
|
19
19
|
import cupy # type: ignore
|
20
20
|
|
@@ -39,7 +39,7 @@ def _cross_d(A: DeviceNDArray, B: DeviceNDArray, c: DeviceNDArray):
|
|
39
39
|
@cuda.jit(device = True)
|
40
40
|
def _negative_d(v: DeviceNDArray, nv: DeviceNDArray):
|
41
41
|
for d in range(v.shape[0]):
|
42
|
-
nv[d] = numba.float32(-1.) * v[d]
|
42
|
+
nv[d] = numba.float32(-1.0) * v[d]
|
43
43
|
|
44
44
|
|
45
45
|
@cuda.jit(device = True)
|
@@ -51,18 +51,38 @@ def _dot_d(v1: DeviceNDArray, v2: DeviceNDArray, prod: DeviceNDArray):
|
|
51
51
|
|
52
52
|
@cuda.jit(device = True)
|
53
53
|
def _norm_d(v: DeviceNDArray, n: DeviceNDArray):
|
54
|
-
n[0] = 0.
|
54
|
+
n[0] = 0.0
|
55
55
|
for dim in range(3):
|
56
|
-
n[0] += v[dim]**2.
|
56
|
+
n[0] += v[dim]**2.0
|
57
57
|
n[0] = maths.sqrt(n[0])
|
58
58
|
|
59
59
|
|
60
60
|
@cuda.jit
|
61
|
-
def project_polygons_to_surfaces(
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
61
|
+
def project_polygons_to_surfaces(
|
62
|
+
faces: DeviceNDArray,
|
63
|
+
triangles: DeviceNDArray,
|
64
|
+
axis: int,
|
65
|
+
index1: int,
|
66
|
+
index2: int,
|
67
|
+
colx: int,
|
68
|
+
coly: int,
|
69
|
+
nx: int,
|
70
|
+
ny: int,
|
71
|
+
nz: int,
|
72
|
+
dx: float,
|
73
|
+
dy: float,
|
74
|
+
dz: float,
|
75
|
+
l_tol: float,
|
76
|
+
t_tol: float,
|
77
|
+
return_normal_vectors: bool,
|
78
|
+
normals: DeviceNDArray,
|
79
|
+
return_depths: bool,
|
80
|
+
depths: DeviceNDArray,
|
81
|
+
return_offsets: bool,
|
82
|
+
offsets: DeviceNDArray,
|
83
|
+
return_triangles: bool,
|
84
|
+
triangle_per_face: DeviceNDArray,
|
85
|
+
):
|
66
86
|
"""Maps the projection of a 3D polygon to 2D grid surfaces along a given axis, using GPUs.
|
67
87
|
|
68
88
|
arguments:
|
@@ -163,10 +183,10 @@ def project_polygons_to_surfaces(faces: DeviceNDArray, triangles: DeviceNDArray,
|
|
163
183
|
inside = False
|
164
184
|
# 2a. use cross-product to work out Barycentric weights
|
165
185
|
# this could be made prettier by refactoring a device function
|
166
|
-
w1_denom = (
|
167
|
-
|
168
|
-
w2_denom =
|
169
|
-
if w1_denom == 0. or w2_denom == 0
|
186
|
+
w1_denom = (tp[1, coly] - tp[0, coly]) * (tp[2, colx] - tp[0, colx]) - (tp[1, colx] - tp[0, colx]) * (
|
187
|
+
tp[2, coly] - tp[0, coly])
|
188
|
+
w2_denom = tp[2, coly] - tp[0, coly]
|
189
|
+
if w1_denom == 0.0 or w2_denom == 0.0:
|
170
190
|
inside = True # point lies on a triangle which is actually a line (normally at boundaries)
|
171
191
|
else:
|
172
192
|
w1 = (tp[0, colx] - numba.float64(px)) * (tp[2, coly] - tp[0, coly]) + (
|
@@ -174,18 +194,18 @@ def project_polygons_to_surfaces(faces: DeviceNDArray, triangles: DeviceNDArray,
|
|
174
194
|
w1 /= w1_denom
|
175
195
|
w2 = (numba.float64(py) - tp[0, coly] - w1 * (tp[1, coly] - tp[0, coly]))
|
176
196
|
w2 /= w2_denom
|
177
|
-
if
|
197
|
+
if w1 >= 0.0 and w2 >= 0.0 and (w1 + w2) <= 1.0: # inside
|
178
198
|
inside = True # point lies in triangle
|
179
199
|
|
180
200
|
# 2b. the point is inside if Barycentric weights meet this condition
|
181
201
|
if inside:
|
182
|
-
#
|
202
|
+
# 3. find intersection point with column centre
|
183
203
|
# 3a. Line start point in 3D which had a projection hit
|
184
|
-
line_p[axis] = numba.float64(grid_dxyz[axis]) / 2.
|
204
|
+
line_p[axis] = numba.float64(grid_dxyz[axis]) / 2.0
|
185
205
|
line_p[2 - index1] = (py + 0.5) * grid_dxyz[2 - index1] # kji / xyz & py=d1
|
186
206
|
line_p[2 - index2] = (px + 0.5) * grid_dxyz[2 - index2] # kji / xyz & px=d2
|
187
207
|
|
188
|
-
#
|
208
|
+
# 3b. Line end point in 3D
|
189
209
|
for dim in range(3):
|
190
210
|
line_v[dim] = line_p[dim]
|
191
211
|
line_v[axis] = numba.float64(grid_dxyz[axis]) * (n_axis - numba.float64(0.5)) #!
|
@@ -209,7 +229,7 @@ def project_polygons_to_surfaces(faces: DeviceNDArray, triangles: DeviceNDArray,
|
|
209
229
|
|
210
230
|
_dot_d(norm, lp_t0, t)
|
211
231
|
t[0] /= denom[0]
|
212
|
-
if
|
232
|
+
if t[0] < 0.0 - l_tol or t[0] > 1.0 + l_tol:
|
213
233
|
continue
|
214
234
|
|
215
235
|
_cross_d(p02, line_rv, tmp)
|
@@ -255,11 +275,11 @@ def project_polygons_to_surfaces(faces: DeviceNDArray, triangles: DeviceNDArray,
|
|
255
275
|
_cross_d(line_p, line_v, tmp)
|
256
276
|
_norm_d(tmp, v)
|
257
277
|
for dim in range(3):
|
258
|
-
normals[face_idx[0], face_idx[1], face_idx[2], dim] = -1. * tmp[dim] / v[0]
|
278
|
+
normals[face_idx[0], face_idx[1], face_idx[2], dim] = (-1.0 * tmp[dim] / v[0])
|
259
279
|
norm_idx[index2] = int(px)
|
260
280
|
if normals[norm_idx[0], norm_idx[1], norm_idx[2], 2] > 0.0:
|
261
281
|
for dim in range(3):
|
262
|
-
normals[face_idx[0], face_idx[1], face_idx[2], dim] *= -1.
|
282
|
+
normals[face_idx[0], face_idx[1], face_idx[2], dim] *= -1.0
|
263
283
|
|
264
284
|
if return_triangles:
|
265
285
|
triangle_per_face[face_idx[0], face_idx[1], face_idx[2]] = triangle_num
|
@@ -287,15 +307,20 @@ def _diffuse_closed_faces(a, k_faces, j_faces, i_faces, index1, index2, axis, st
|
|
287
307
|
fault_behind = i_faces[iF, jF, kF - 1]
|
288
308
|
fault_back = i_faces[iF, jF, kF]
|
289
309
|
cuda.syncthreads()
|
290
|
-
a[i,j,k] = (a[i-1,j,k] and (not fault_above))
|
291
|
-
|
292
|
-
|
293
|
-
|
310
|
+
a[i, j, k] = ((a[i - 1, j, k] and (not fault_above)) or (a[i + 1, j, k] and (not fault_below)) or
|
311
|
+
(a[i, j - 1, k] and (not fault_left)) or (a[i, j + 1, k] and (not fault_right)) or
|
312
|
+
(a[i, j, k - 1] and
|
313
|
+
(not fault_behind)) or (a[i, j, k + 1] and
|
314
|
+
(not fault_back)) or a[i, j, k]) # already closed
|
294
315
|
cuda.syncthreads()
|
295
316
|
|
296
317
|
|
297
|
-
def bisector_from_faces_cuda(
|
298
|
-
|
318
|
+
def bisector_from_faces_cuda(
|
319
|
+
grid_extent_kji: Tuple[int, int, int],
|
320
|
+
k_faces: np.ndarray,
|
321
|
+
j_faces: np.ndarray,
|
322
|
+
i_faces: np.ndarray,
|
323
|
+
) -> Tuple[np.ndarray, bool]:
|
299
324
|
"""Returns a numpy bool array denoting the bisection of the grid by the face sets, using GPUs.
|
300
325
|
|
301
326
|
arguments:
|
@@ -314,18 +339,28 @@ def bisector_from_faces_cuda(grid_extent_kji: Tuple[int, int, int], k_faces: np.
|
|
314
339
|
assigned to either the True or False part
|
315
340
|
"""
|
316
341
|
assert len(grid_extent_kji) == 3
|
317
|
-
padded_extent_kji = (
|
342
|
+
padded_extent_kji = (
|
343
|
+
grid_extent_kji[0] + 2,
|
344
|
+
grid_extent_kji[1] + 2,
|
345
|
+
grid_extent_kji[2] + 2,
|
346
|
+
)
|
318
347
|
a = cupy.zeros(padded_extent_kji, dtype = bool)
|
319
348
|
a[1, 1, 1] = True
|
320
349
|
|
321
350
|
a_count = a_count_before = 0
|
322
351
|
blockSize = (16, 16)
|
323
|
-
gridSize_k = (
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
352
|
+
gridSize_k = (
|
353
|
+
(grid_extent_kji[1] + blockSize[0] - 1) // blockSize[0],
|
354
|
+
(grid_extent_kji[2] + blockSize[1] - 1) // blockSize[1],
|
355
|
+
)
|
356
|
+
gridSize_j = (
|
357
|
+
(grid_extent_kji[0] + blockSize[0] - 1) // blockSize[0],
|
358
|
+
(grid_extent_kji[2] + blockSize[1] - 1) // blockSize[1],
|
359
|
+
)
|
360
|
+
gridSize_i = (
|
361
|
+
(grid_extent_kji[0] + blockSize[0] - 1) // blockSize[1],
|
362
|
+
(grid_extent_kji[1] + blockSize[1] - 1) // blockSize[1],
|
363
|
+
)
|
329
364
|
|
330
365
|
while True:
|
331
366
|
# forward sweeps
|
@@ -351,7 +386,7 @@ def bisector_from_faces_cuda(grid_extent_kji: Tuple[int, int, int], k_faces: np.
|
|
351
386
|
|
352
387
|
a = cupy.asnumpy(a[1:-1, 1:-1, 1:-1])
|
353
388
|
cell_count = a.size
|
354
|
-
assert 1 <= a_count < cell_count,
|
389
|
+
assert (1 <= a_count < cell_count), "face set for surface is leaky or empty (surface does not intersect grid)"
|
355
390
|
|
356
391
|
# find mean K for a cells and not a cells; if not a cells mean K is lesser (ie shallower), negate a
|
357
392
|
layer_cell_count = grid_extent_kji[1] * grid_extent_kji[2]
|
@@ -379,7 +414,7 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
379
414
|
name,
|
380
415
|
title = None,
|
381
416
|
agitate = False,
|
382
|
-
feature_type =
|
417
|
+
feature_type = "fault",
|
383
418
|
progress_fn = None,
|
384
419
|
return_properties = None,
|
385
420
|
i_surface = 0,
|
@@ -415,10 +450,10 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
415
450
|
to trim first;
|
416
451
|
organisational objects for the feature are created if needed
|
417
452
|
"""
|
418
|
-
#
|
453
|
+
# todo: update with extra arguments to keep functionality aligned with find_faces...regular_optimised
|
419
454
|
|
420
455
|
cuda.select_device(i_gpu) # bind device to thread
|
421
|
-
device = cuda.get_current_device() # if no GPU present - this will throw an exception and fall back to CPU
|
456
|
+
device = (cuda.get_current_device()) # if no GPU present - this will throw an exception and fall back to CPU
|
422
457
|
|
423
458
|
assert isinstance(grid, grr.RegularGrid)
|
424
459
|
assert grid.is_aligned
|
@@ -430,15 +465,21 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
430
465
|
return_flange_bool = False
|
431
466
|
if return_properties:
|
432
467
|
assert all([
|
433
|
-
p in [
|
434
|
-
|
468
|
+
p in [
|
469
|
+
"triangle",
|
470
|
+
"depth",
|
471
|
+
"offset",
|
472
|
+
"normal vector",
|
473
|
+
"grid bisector",
|
474
|
+
"flange bool",
|
475
|
+
] for p in return_properties
|
435
476
|
])
|
436
|
-
return_triangles =
|
437
|
-
return_normal_vectors =
|
438
|
-
return_depths =
|
439
|
-
return_offsets =
|
440
|
-
return_bisector =
|
441
|
-
return_flange_bool =
|
477
|
+
return_triangles = "triangle" in return_properties
|
478
|
+
return_normal_vectors = "normal vector" in return_properties
|
479
|
+
return_depths = "depth" in return_properties
|
480
|
+
return_offsets = "offset" in return_properties
|
481
|
+
return_bisector = "grid bisector" in return_properties
|
482
|
+
return_flange_bool = "flange bool" in return_properties
|
442
483
|
if return_flange_bool:
|
443
484
|
return_triangles = True
|
444
485
|
|
@@ -450,37 +491,41 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
450
491
|
|
451
492
|
# prepare surfaces
|
452
493
|
surface = surfaces[i_surface] # get surface under consideration
|
453
|
-
log.debug(f
|
494
|
+
log.debug(f"intersecting surface {surface.title} with regular grid {grid.title} on a GPU")
|
454
495
|
# log.debug(f'grid extent kji: {grid.extent_kji}')
|
455
496
|
|
456
497
|
# print some information about the CUDA card
|
457
|
-
log.debug(f
|
458
|
-
f
|
459
|
-
f
|
498
|
+
log.debug(f"{device.name} | Device Controller {i_gpu} | " +
|
499
|
+
f"CC {device.COMPUTE_CAPABILITY_MAJOR}.{device.COMPUTE_CAPABILITY_MINOR} | " +
|
500
|
+
f"Processing surface {i_surface}")
|
460
501
|
# get device attributes to calculate thread dimensions
|
461
502
|
nSMs = device.MULTIPROCESSOR_COUNT # number of SMs
|
462
|
-
maxBlockSize = device.MAX_BLOCK_DIM_X / 2 # max number of threads per block in x-dim
|
503
|
+
maxBlockSize = (device.MAX_BLOCK_DIM_X / 2) # max number of threads per block in x-dim
|
463
504
|
gridSize = 2 * nSMs # prefer 2*nSMs blocks for full occupancy
|
464
505
|
# take the reverse diagonal for relationship between xyz & ijk
|
465
|
-
grid_dxyz = (
|
506
|
+
grid_dxyz = (
|
507
|
+
grid.block_dxyz_dkji[2, 0],
|
508
|
+
grid.block_dxyz_dkji[1, 1],
|
509
|
+
grid.block_dxyz_dkji[0, 2],
|
510
|
+
)
|
466
511
|
# extract polygons from surface
|
467
512
|
with compiler_lock: # HDF5 handles seem not to be threadsafe
|
468
513
|
triangles, points = surface.triangles_and_points()
|
469
|
-
assert triangles is not None and points is not None, f
|
514
|
+
assert (triangles is not None and points is not None), f"surface {surface.title} is empty"
|
470
515
|
|
471
516
|
if agitate:
|
472
517
|
points += 1.0e-5 * (np.random.random(points.shape) - 0.5) # +/- uniform err.
|
473
|
-
#
|
518
|
+
# log.debug(f'surface: {surface.title}; p0: {points[0]}; crs uuid: {surface.crs_uuid}')
|
474
519
|
# log.debug(f'surface min xyz: {np.min(points, axis = 0)}')
|
475
520
|
# log.debug(f'surface max xyz: {np.max(points, axis = 0)}')
|
476
521
|
if not bu.matching_uuids(grid.crs_uuid, surface.crs_uuid):
|
477
|
-
log.debug(
|
522
|
+
log.debug("converting from surface crs to grid crs")
|
478
523
|
s_crs = rqc.Crs(surface.model, uuid = surface.crs_uuid)
|
479
524
|
s_crs.convert_array_to(grid.crs, points)
|
480
525
|
surface.crs_uuid = grid.crs.uuid
|
481
526
|
# log.debug(f'surface: {surface.title}; p0: {points[0]}; crs uuid: {surface.crs_uuid}')
|
482
527
|
# log.debug(f'surface min xyz: {np.min(points, axis = 0)}')
|
483
|
-
#
|
528
|
+
# log.debug(f'surface max xyz: {np.max(points, axis = 0)}')
|
484
529
|
|
485
530
|
p_tri_xyz = points[triangles]
|
486
531
|
p_tri_xyz_d = cupy.asarray(p_tri_xyz)
|
@@ -489,12 +534,12 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
489
534
|
if grid.nk > 1:
|
490
535
|
log.debug("searching for k faces")
|
491
536
|
k_faces = np.zeros((grid.nk - 1, grid.nj, grid.ni), dtype = bool)
|
492
|
-
k_triangles = np.full((grid.nk - 1, grid.nj, grid.ni), -1, dtype = int) if return_triangles else np.full(
|
493
|
-
(1, 1, 1), -1, dtype = int)
|
494
|
-
k_depths = np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_depths else np.full((1, 1, 1), np.nan)
|
495
|
-
k_offsets = np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_offsets else np.full((1, 1, 1), np.nan)
|
496
|
-
k_normals = np.full((grid.nk - 1, grid.nj, grid.ni, 3), np.nan) if return_normal_vectors else np.full(
|
497
|
-
(1, 1, 1, 1), np.nan)
|
537
|
+
k_triangles = (np.full((grid.nk - 1, grid.nj, grid.ni), -1, dtype = int) if return_triangles else np.full(
|
538
|
+
(1, 1, 1), -1, dtype = int))
|
539
|
+
k_depths = (np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_depths else np.full((1, 1, 1), np.nan))
|
540
|
+
k_offsets = (np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_offsets else np.full((1, 1, 1), np.nan))
|
541
|
+
k_normals = (np.full((grid.nk - 1, grid.nj, grid.ni, 3), np.nan) if return_normal_vectors else np.full(
|
542
|
+
(1, 1, 1, 1), np.nan))
|
498
543
|
k_faces_d = cupy.asarray(k_faces)
|
499
544
|
k_triangles_d = cupy.asarray(k_triangles)
|
500
545
|
k_depths_d = cupy.asarray(k_depths)
|
@@ -505,10 +550,10 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
505
550
|
axis = 2
|
506
551
|
index1 = 1
|
507
552
|
index2 = 2
|
508
|
-
blockSize = (p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
509
|
-
|
553
|
+
blockSize = ((p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
554
|
+
(p_tri_xyz.shape[0] < gridSize * maxBlockSize) else 64) # prefer factors of 32 (threads per warp)
|
510
555
|
log.debug(
|
511
|
-
f
|
556
|
+
f"Executing polygon-intersection GPU-kernel along k-axis using gridSize={gridSize}, blockSize={blockSize}")
|
512
557
|
project_polygons_to_surfaces[gridSize, blockSize](
|
513
558
|
k_faces_d,
|
514
559
|
p_tri_xyz_d,
|
@@ -523,8 +568,8 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
523
568
|
grid_dxyz[0],
|
524
569
|
grid_dxyz[1],
|
525
570
|
grid_dxyz[2],
|
526
|
-
0
|
527
|
-
0
|
571
|
+
0.0,
|
572
|
+
0.0,
|
528
573
|
return_normal_vectors,
|
529
574
|
k_normals_d,
|
530
575
|
return_depths,
|
@@ -556,12 +601,12 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
556
601
|
if grid.nj > 1:
|
557
602
|
log.debug("searching for j faces")
|
558
603
|
j_faces = np.zeros((grid.nk, grid.nj - 1, grid.ni), dtype = bool)
|
559
|
-
j_triangles = np.full((grid.nk, grid.nj - 1, grid.ni), -1, dtype = int) if return_triangles else np.full(
|
560
|
-
(1, 1, 1), -1, dtype = int)
|
561
|
-
j_depths = np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_depths else np.full((1, 1, 1), np.nan)
|
562
|
-
j_offsets = np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_offsets else np.full((1, 1, 1), np.nan)
|
563
|
-
j_normals = np.full((grid.nk, grid.nj - 1, grid.ni, 3), np.nan) if return_normal_vectors else np.full(
|
564
|
-
(1, 1, 1, 1), np.nan)
|
604
|
+
j_triangles = (np.full((grid.nk, grid.nj - 1, grid.ni), -1, dtype = int) if return_triangles else np.full(
|
605
|
+
(1, 1, 1), -1, dtype = int))
|
606
|
+
j_depths = (np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_depths else np.full((1, 1, 1), np.nan))
|
607
|
+
j_offsets = (np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_offsets else np.full((1, 1, 1), np.nan))
|
608
|
+
j_normals = (np.full((grid.nk, grid.nj - 1, grid.ni, 3), np.nan) if return_normal_vectors else np.full(
|
609
|
+
(1, 1, 1, 1), np.nan))
|
565
610
|
j_faces_d = cupy.asarray(j_faces)
|
566
611
|
j_triangles_d = cupy.asarray(j_triangles)
|
567
612
|
j_depths_d = cupy.asarray(j_depths)
|
@@ -572,10 +617,10 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
572
617
|
axis = 1
|
573
618
|
index1 = 0
|
574
619
|
index2 = 2
|
575
|
-
blockSize = (p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
576
|
-
|
620
|
+
blockSize = ((p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
621
|
+
(p_tri_xyz.shape[0] < gridSize * maxBlockSize) else 64) # prefer factors of 32 (threads per warp)
|
577
622
|
log.debug(
|
578
|
-
f
|
623
|
+
f"Executing polygon-intersection GPU-kernel along j-axis using gridSize={gridSize}, blockSize={blockSize}")
|
579
624
|
project_polygons_to_surfaces[gridSize, blockSize](
|
580
625
|
j_faces_d,
|
581
626
|
p_tri_xyz_d,
|
@@ -590,8 +635,8 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
590
635
|
grid_dxyz[0],
|
591
636
|
grid_dxyz[1],
|
592
637
|
grid_dxyz[2],
|
593
|
-
0
|
594
|
-
0
|
638
|
+
0.0,
|
639
|
+
0.0,
|
595
640
|
return_normal_vectors,
|
596
641
|
j_normals_d,
|
597
642
|
return_depths,
|
@@ -623,12 +668,12 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
623
668
|
if grid.ni > 1:
|
624
669
|
log.debug("searching for i faces")
|
625
670
|
i_faces = np.zeros((grid.nk, grid.nj, grid.ni - 1), dtype = bool)
|
626
|
-
i_triangles = np.full((grid.nk, grid.nj, grid.ni - 1), -1, dtype = int) if return_triangles else np.full(
|
627
|
-
(1, 1, 1), -1, dtype = int)
|
628
|
-
i_depths = np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_depths else np.full((1, 1, 1), np.nan)
|
629
|
-
i_offsets = np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_offsets else np.full((1, 1, 1), np.nan)
|
630
|
-
i_normals = np.full((grid.nk, grid.nj, grid.ni - 1, 3), np.nan) if return_normal_vectors else np.full(
|
631
|
-
(1, 1, 1, 1), np.nan)
|
671
|
+
i_triangles = (np.full((grid.nk, grid.nj, grid.ni - 1), -1, dtype = int) if return_triangles else np.full(
|
672
|
+
(1, 1, 1), -1, dtype = int))
|
673
|
+
i_depths = (np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_depths else np.full((1, 1, 1), np.nan))
|
674
|
+
i_offsets = (np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_offsets else np.full((1, 1, 1), np.nan))
|
675
|
+
i_normals = (np.full((grid.nk, grid.nj, grid.ni - 1, 3), np.nan) if return_normal_vectors else np.full(
|
676
|
+
(1, 1, 1, 1), np.nan))
|
632
677
|
i_faces_d = cupy.asarray(i_faces)
|
633
678
|
i_triangles_d = cupy.asarray(i_triangles)
|
634
679
|
i_depths_d = cupy.asarray(i_depths)
|
@@ -639,10 +684,10 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
639
684
|
axis = 0
|
640
685
|
index1 = 0
|
641
686
|
index2 = 1
|
642
|
-
blockSize = (p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
643
|
-
|
687
|
+
blockSize = ((p_tri_xyz.shape[0] - 1) // (gridSize - 1) if
|
688
|
+
(p_tri_xyz.shape[0] < gridSize * maxBlockSize) else 64) # prefer factors of 32 (threads per warp)
|
644
689
|
log.debug(
|
645
|
-
f
|
690
|
+
f"Executing polygon-intersection GPU-kernel along i-axis using gridSize={gridSize}, blockSize={blockSize}")
|
646
691
|
project_polygons_to_surfaces[gridSize, blockSize](
|
647
692
|
i_faces_d,
|
648
693
|
p_tri_xyz_d,
|
@@ -657,8 +702,8 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
657
702
|
grid_dxyz[0],
|
658
703
|
grid_dxyz[1],
|
659
704
|
grid_dxyz[2],
|
660
|
-
0
|
661
|
-
0
|
705
|
+
0.0,
|
706
|
+
0.0,
|
662
707
|
return_normal_vectors,
|
663
708
|
i_normals_d,
|
664
709
|
return_depths,
|
@@ -706,36 +751,36 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
706
751
|
|
707
752
|
# NB. following assumes faces have been added to gcs in a particular order!
|
708
753
|
if return_triangles:
|
709
|
-
k_tri_list = np.empty((0,)) if k_triangles is None else k_triangles[rgs_ff.
|
710
|
-
j_tri_list = np.empty((0,)) if j_triangles is None else j_triangles[rgs_ff.
|
711
|
-
i_tri_list = np.empty((0,)) if i_triangles is None else i_triangles[rgs_ff.
|
754
|
+
k_tri_list = (np.empty((0,)) if k_triangles is None else k_triangles[rgs_ff._where_true(k_faces)])
|
755
|
+
j_tri_list = (np.empty((0,)) if j_triangles is None else j_triangles[rgs_ff._where_true(j_faces)])
|
756
|
+
i_tri_list = (np.empty((0,)) if i_triangles is None else i_triangles[rgs_ff._where_true(i_faces)])
|
712
757
|
all_tris = np.concatenate((k_tri_list, j_tri_list, i_tri_list), axis = 0)
|
713
758
|
# log.debug(f'gcs count: {gcs.count}; all triangles shape: {all_tris.shape}')
|
714
759
|
assert all_tris.shape == (gcs_list[i_surface].count,)
|
715
760
|
|
716
761
|
# NB. following assumes faces have been added to gcs in a particular order!
|
717
762
|
if return_depths:
|
718
|
-
k_depths_list = np.empty((0,)) if k_depths is None else k_depths[rgs_ff.
|
719
|
-
j_depths_list = np.empty((0,)) if j_depths is None else j_depths[rgs_ff.
|
720
|
-
i_depths_list = np.empty((0,)) if i_depths is None else i_depths[rgs_ff.
|
763
|
+
k_depths_list = (np.empty((0,)) if k_depths is None else k_depths[rgs_ff._where_true(k_faces)])
|
764
|
+
j_depths_list = (np.empty((0,)) if j_depths is None else j_depths[rgs_ff._where_true(j_faces)])
|
765
|
+
i_depths_list = (np.empty((0,)) if i_depths is None else i_depths[rgs_ff._where_true(i_faces)])
|
721
766
|
all_depths = np.concatenate((k_depths_list, j_depths_list, i_depths_list), axis = 0)
|
722
767
|
# log.debug(f'gcs count: {gcs.count}; all depths shape: {all_depths.shape}')
|
723
768
|
assert all_depths.shape == (gcs_list[i_surface].count,)
|
724
769
|
|
725
770
|
# NB. following assumes faces have been added to gcs in a particular order!
|
726
771
|
if return_offsets:
|
727
|
-
k_offsets_list = np.empty((0,)) if k_offsets is None else k_offsets[rgs_ff.
|
728
|
-
j_offsets_list = np.empty((0,)) if j_offsets is None else j_offsets[rgs_ff.
|
729
|
-
i_offsets_list = np.empty((0,)) if i_offsets is None else i_offsets[rgs_ff.
|
772
|
+
k_offsets_list = (np.empty((0,)) if k_offsets is None else k_offsets[rgs_ff._where_true(k_faces)])
|
773
|
+
j_offsets_list = (np.empty((0,)) if j_offsets is None else j_offsets[rgs_ff._where_true(j_faces)])
|
774
|
+
i_offsets_list = (np.empty((0,)) if i_offsets is None else i_offsets[rgs_ff._where_true(i_faces)])
|
730
775
|
all_offsets = np.concatenate((k_offsets_list, j_offsets_list, i_offsets_list), axis = 0)
|
731
776
|
# log.debug(f'gcs count: {gcs.count}; all offsets shape: {all_offsets.shape}')
|
732
777
|
assert all_offsets.shape == (gcs_list[i_surface].count,)
|
733
778
|
|
734
779
|
if return_flange_bool:
|
735
|
-
flange_bool_uuid = surface.model.uuid(title =
|
736
|
-
obj_type =
|
780
|
+
flange_bool_uuid = surface.model.uuid(title = "flange bool",
|
781
|
+
obj_type = "DiscreteProperty",
|
737
782
|
related_uuid = surface.uuid)
|
738
|
-
assert flange_bool_uuid is not None, f"No flange bool property found for surface: {surface.title}"
|
783
|
+
assert (flange_bool_uuid is not None), f"No flange bool property found for surface: {surface.title}"
|
739
784
|
flange_bool = rqp.Property(surface.model, uuid = flange_bool_uuid)
|
740
785
|
flange_array = flange_bool.array_ref()
|
741
786
|
all_flange = np.take(flange_array, all_tris)
|
@@ -743,9 +788,9 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
743
788
|
|
744
789
|
# NB. following assumes faces have been added to gcs in a particular order!
|
745
790
|
if return_normal_vectors:
|
746
|
-
k_normals_list = np.empty((0, 3)) if k_normals is None else k_normals[rgs_ff.
|
747
|
-
j_normals_list = np.empty((0, 3)) if j_normals is None else j_normals[rgs_ff.
|
748
|
-
i_normals_list = np.empty((0, 3)) if i_normals is None else i_normals[rgs_ff.
|
791
|
+
k_normals_list = (np.empty((0, 3)) if k_normals is None else k_normals[rgs_ff._where_true(k_faces)])
|
792
|
+
j_normals_list = (np.empty((0, 3)) if j_normals is None else j_normals[rgs_ff._where_true(j_faces)])
|
793
|
+
i_normals_list = (np.empty((0, 3)) if i_normals is None else i_normals[rgs_ff._where_true(i_faces)])
|
749
794
|
all_normals = np.concatenate((k_normals_list, j_normals_list, i_normals_list), axis = 0)
|
750
795
|
# log.debug(f'gcs count: {gcs.count}; all normals shape: {all_normals.shape}')
|
751
796
|
assert all_normals.shape == (gcs_list[i_surface].count, 3)
|
@@ -762,17 +807,17 @@ def find_faces_to_represent_surface_regular_cuda_sgpu(
|
|
762
807
|
if return_properties:
|
763
808
|
props_dict_list[i_surface] = {}
|
764
809
|
if return_triangles:
|
765
|
-
props_dict_list[i_surface][
|
810
|
+
props_dict_list[i_surface]["triangle"] = all_tris
|
766
811
|
if return_depths:
|
767
|
-
props_dict_list[i_surface][
|
812
|
+
props_dict_list[i_surface]["depth"] = all_depths
|
768
813
|
if return_offsets:
|
769
|
-
props_dict_list[i_surface][
|
814
|
+
props_dict_list[i_surface]["offset"] = all_offsets
|
770
815
|
if return_normal_vectors:
|
771
|
-
props_dict_list[i_surface][
|
816
|
+
props_dict_list[i_surface]["normal vector"] = all_normals
|
772
817
|
if return_bisector:
|
773
|
-
props_dict_list[i_surface][
|
818
|
+
props_dict_list[i_surface]["grid bisector"] = (bisector, is_curtain)
|
774
819
|
if return_flange_bool:
|
775
|
-
props_dict_list[i_surface][
|
820
|
+
props_dict_list[i_surface]["flange bool"] = all_flange
|
776
821
|
|
777
822
|
|
778
823
|
def find_faces_to_represent_surface_regular_cuda_mgpu(
|
@@ -781,7 +826,7 @@ def find_faces_to_represent_surface_regular_cuda_mgpu(
|
|
781
826
|
name,
|
782
827
|
title = None,
|
783
828
|
agitate = False,
|
784
|
-
feature_type =
|
829
|
+
feature_type = "fault",
|
785
830
|
progress_fn = None,
|
786
831
|
return_properties = None,
|
787
832
|
):
|
@@ -823,21 +868,23 @@ def find_faces_to_represent_surface_regular_cuda_mgpu(
|
|
823
868
|
props_dict_list = [None] * n_surfs
|
824
869
|
threads = [None] * n_gpus
|
825
870
|
for i_surface in range(n_surfs):
|
826
|
-
threads[i_surface % n_gpus] = threading.Thread(
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
871
|
+
threads[i_surface % n_gpus] = threading.Thread(
|
872
|
+
target = find_faces_to_represent_surface_regular_cuda_sgpu,
|
873
|
+
args = (
|
874
|
+
grid,
|
875
|
+
surfaces,
|
876
|
+
name,
|
877
|
+
title,
|
878
|
+
agitate,
|
879
|
+
feature_type,
|
880
|
+
progress_fn,
|
881
|
+
return_properties,
|
882
|
+
i_surface,
|
883
|
+
i_surface % n_gpus,
|
884
|
+
gcs_list,
|
885
|
+
props_dict_list,
|
886
|
+
),
|
887
|
+
)
|
841
888
|
threads[i_surface % n_gpus].start() # start parallel run
|
842
889
|
# if this is the last GPU available or we're at the last array ...
|
843
890
|
if (i_surface + 1) % n_gpus == 0 or (i_surface + 1) == n_surfs:
|
resqpy/lines/_common.py
CHANGED
@@ -56,22 +56,25 @@ class _BasePolyline(BaseResqpy):
|
|
56
56
|
self.rep_int_root = interp_root
|
57
57
|
|
58
58
|
|
59
|
-
def load_hdf5_array(object, node, array_attribute, tag = 'Values'):
|
59
|
+
def load_hdf5_array(object, node, array_attribute, tag = 'Values', dtype = 'float'):
|
60
60
|
"""Loads the property array data as an attribute of object, from the hdf5 referenced in xml node.
|
61
61
|
|
62
62
|
:meta private:
|
63
63
|
"""
|
64
|
-
|
65
64
|
assert (rqet.node_type(node) in ['DoubleHdf5Array', 'IntegerHdf5Array', 'Point3dHdf5Array'])
|
66
65
|
# ignore null value
|
67
66
|
h5_key_pair = object.model.h5_uuid_and_path_for_node(node, tag = tag)
|
68
67
|
if h5_key_pair is None:
|
69
68
|
return None
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
object.model.h5_array_element(h5_key_pair,
|
70
|
+
index = None,
|
71
|
+
cache_array = True,
|
72
|
+
dtype = dtype,
|
73
|
+
object = object,
|
74
|
+
array_attribute = array_attribute)
|
75
|
+
a = getattr(object, array_attribute)
|
76
|
+
assert a is not None
|
77
|
+
return a
|
75
78
|
|
76
79
|
|
77
80
|
def shift_polyline(parent_model, poly_root, xyz_shift = (0, 0, 0), title = ''):
|
resqpy/lines/_polyline.py
CHANGED
@@ -563,6 +563,26 @@ class Polyline(rql_c._BasePolyline):
|
|
563
563
|
segment = -1
|
564
564
|
return meet.point_snapped_to_line_segment_2d(p, self.coordinates[segment], self.coordinates[segment + 1])
|
565
565
|
|
566
|
+
def segment_xyz_from_xy(self, segment, x, y):
|
567
|
+
"""Returns xyz point on segment given x and y (which should be on or close to the segment).
|
568
|
+
|
569
|
+
note:
|
570
|
+
this method allows a return to a 3D point after working in the 2D xy plane;
|
571
|
+
it will fail if the segment is 'vertical', ie. without range in x or y
|
572
|
+
"""
|
573
|
+
|
574
|
+
if segment == len(self.coordinates) - 1:
|
575
|
+
segment = -1
|
576
|
+
seg_vector = self.coordinates[segment + 1] - self.coordinates[segment]
|
577
|
+
if abs(seg_vector[0]) > abs(seg_vector[1]):
|
578
|
+
assert (x - self.coordinates[segment, 0]) * (x - self.coordinates[segment + 1, 0]) <= 0
|
579
|
+
f = (x - self.coordinates[segment, 0]) / seg_vector[0]
|
580
|
+
else:
|
581
|
+
assert (y - self.coordinates[segment, 1]) * (y - self.coordinates[segment + 1, 1]) <= 0
|
582
|
+
f = (y - self.coordinates[segment, 1]) / seg_vector[1]
|
583
|
+
assert 0.0 <= f <= 1.0
|
584
|
+
return (1.0 - f) * self.coordinates[segment] + f * self.coordinates[segment + 1]
|
585
|
+
|
566
586
|
def xy_crossings(self, other):
|
567
587
|
"""Returns list of (x, y) pairs of crossing points with other polyline, in xy plane."""
|
568
588
|
|