resqpy 4.5.0__py3-none-any.whl → 4.6.3__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|