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.
@@ -24,7 +24,7 @@ import resqpy.olio.vector_utilities as vec
24
24
  # note: resqpy.grid_surface._grid_surface_cuda will be imported by the find_faces_to_represent_surface() function if needed
25
25
 
26
26
 
27
- def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = 'fault', progress_fn = None):
27
+ def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = "fault", progress_fn = None):
28
28
  """Returns a grid connection set containing those cell faces which are deemed to represent the surface.
29
29
 
30
30
  note:
@@ -92,11 +92,11 @@ def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = '
92
92
  # log.debug('finding surface triangle boxes')
93
93
  t, p = surface.triangles_and_points()
94
94
  if not bu.matching_uuids(grid.crs_uuid, surface.crs_uuid):
95
- log.debug('converting from surface crs to grid crs')
95
+ log.debug("converting from surface crs to grid crs")
96
96
  s_crs = rqc.Crs(surface.model, uuid = surface.crs_uuid)
97
97
  s_crs.convert_array_to(grid.crs, p)
98
98
  triangles = p[t]
99
- assert triangles.size > 0, 'no triangles in surface'
99
+ assert triangles.size > 0, "no triangles in surface"
100
100
  triangle_boxes = np.empty((triangles.shape[0], 2, 3))
101
101
  triangle_boxes[:, 0, :] = np.amin(triangles, axis = 1)
102
102
  triangle_boxes[:, 1, :] = np.amax(triangles, axis = 1)
@@ -120,26 +120,32 @@ def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = '
120
120
  progress_fn(progress_base + progress_batch * (float(j) / float(grid.nj)))
121
121
  for i in range(grid.ni):
122
122
  if column_k_vector_boxes is not None and bx.boxes_overlap(batch_box, column_k_vector_boxes[j, i]):
123
- full_intersects = meet.line_set_triangles_intersects(centre_points[:-1, j, i],
124
- k_vectors[:, j, i],
125
- triangles[ti_base:ti_end],
126
- line_segment = True)
123
+ full_intersects = meet.line_set_triangles_intersects(
124
+ centre_points[:-1, j, i],
125
+ k_vectors[:, j, i],
126
+ triangles[ti_base:ti_end],
127
+ line_segment = True,
128
+ )
127
129
  distilled_intersects, _, _ = meet.distilled_intersects(full_intersects)
128
130
  k_faces[distilled_intersects, j, i] = True
129
- if j < grid.nj - 1 and column_j_vector_boxes is not None and bx.boxes_overlap(
130
- batch_box, column_j_vector_boxes[j, i]):
131
- full_intersects = meet.line_set_triangles_intersects(centre_points[:, j, i],
132
- j_vectors[:, j, i],
133
- triangles[ti_base:ti_end],
134
- line_segment = True)
131
+ if (j < grid.nj - 1 and column_j_vector_boxes is not None and
132
+ bx.boxes_overlap(batch_box, column_j_vector_boxes[j, i])):
133
+ full_intersects = meet.line_set_triangles_intersects(
134
+ centre_points[:, j, i],
135
+ j_vectors[:, j, i],
136
+ triangles[ti_base:ti_end],
137
+ line_segment = True,
138
+ )
135
139
  distilled_intersects, _, _ = meet.distilled_intersects(full_intersects)
136
140
  j_faces[distilled_intersects, j, i] = True
137
- if i < grid.ni - 1 and column_i_vector_boxes is not None and bx.boxes_overlap(
138
- batch_box, column_i_vector_boxes[j, i]):
139
- full_intersects = meet.line_set_triangles_intersects(centre_points[:, j, i],
140
- i_vectors[:, j, i],
141
- triangles[ti_base:ti_end],
142
- line_segment = True)
141
+ if (i < grid.ni - 1 and column_i_vector_boxes is not None and
142
+ bx.boxes_overlap(batch_box, column_i_vector_boxes[j, i])):
143
+ full_intersects = meet.line_set_triangles_intersects(
144
+ centre_points[:, j, i],
145
+ i_vectors[:, j, i],
146
+ triangles[ti_base:ti_end],
147
+ line_segment = True,
148
+ )
143
149
  distilled_intersects, _, _ = meet.distilled_intersects(full_intersects)
144
150
  i_faces[distilled_intersects, j, i] = True
145
151
  ti_base = ti_end
@@ -152,14 +158,16 @@ def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = '
152
158
  # log.debug('face counts: K: ' + str(np.count_nonzero(k_faces)) +
153
159
  # '; J: ' + str(np.count_nonzero(j_faces)) +
154
160
  # '; I: ' + str(np.count_nonzero(i_faces)))
155
- gcs = rqf.GridConnectionSet(grid.model,
156
- grid = grid,
157
- k_faces = k_faces,
158
- j_faces = j_faces,
159
- i_faces = i_faces,
160
- feature_name = name,
161
- feature_type = feature_type,
162
- create_organizing_objects_where_needed = True)
161
+ gcs = rqf.GridConnectionSet(
162
+ grid.model,
163
+ grid = grid,
164
+ k_faces = k_faces,
165
+ j_faces = j_faces,
166
+ i_faces = i_faces,
167
+ feature_name = name,
168
+ feature_type = feature_type,
169
+ create_organizing_objects_where_needed = True,
170
+ )
163
171
 
164
172
  if progress_fn is not None:
165
173
  progress_fn(1.0)
@@ -167,16 +175,18 @@ def find_faces_to_represent_surface_staffa(grid, surface, name, feature_type = '
167
175
  return gcs
168
176
 
169
177
 
170
- def find_faces_to_represent_surface_regular(grid,
171
- surface,
172
- name,
173
- title = None,
174
- centres = None,
175
- agitate = False,
176
- feature_type = 'fault',
177
- progress_fn = None,
178
- consistent_side = False,
179
- return_properties = None):
178
+ def find_faces_to_represent_surface_regular(
179
+ grid,
180
+ surface,
181
+ name,
182
+ title = None,
183
+ centres = None,
184
+ agitate = False,
185
+ feature_type = "fault",
186
+ progress_fn = None,
187
+ consistent_side = False,
188
+ return_properties = None,
189
+ ):
180
190
  """Returns a grid connection set containing those cell faces which are deemed to represent the surface.
181
191
 
182
192
  arguments:
@@ -224,9 +234,9 @@ def find_faces_to_represent_surface_regular(grid,
224
234
  return_normal_vectors = False
225
235
  return_offsets = False
226
236
  if return_properties:
227
- assert all([p in ['offset', 'normal vector'] for p in return_properties])
228
- return_normal_vectors = ('normal vector' in return_properties)
229
- return_offsets = ('offset' in return_properties)
237
+ assert all([p in ["offset", "normal vector"] for p in return_properties])
238
+ return_normal_vectors = "normal vector" in return_properties
239
+ return_offsets = "offset" in return_properties
230
240
 
231
241
  if title is None:
232
242
  title = name
@@ -234,34 +244,38 @@ def find_faces_to_represent_surface_regular(grid,
234
244
  if progress_fn is not None:
235
245
  progress_fn(0.0)
236
246
 
237
- log.debug(f'intersecting surface {surface.title} with regular grid {grid.title}')
238
- log.debug(f'grid extent kji: {grid.extent_kji}')
247
+ log.debug(f"intersecting surface {surface.title} with regular grid {grid.title}")
248
+ log.debug(f"grid extent kji: {grid.extent_kji}")
239
249
 
240
- grid_dxyz = (grid.block_dxyz_dkji[2, 0], grid.block_dxyz_dkji[1, 1], grid.block_dxyz_dkji[0, 2])
250
+ grid_dxyz = (
251
+ grid.block_dxyz_dkji[2, 0],
252
+ grid.block_dxyz_dkji[1, 1],
253
+ grid.block_dxyz_dkji[0, 2],
254
+ )
241
255
  if centres is None:
242
256
  centres = grid.centre_point(use_origin = True)
243
257
  if consistent_side:
244
- log.debug('making all triangles clockwise')
258
+ log.debug("making all triangles clockwise")
245
259
  # note: following will shuffle order of vertices within t cached in surface
246
260
  surface.make_all_clockwise_xy(reorient = True)
247
261
  t, p = surface.triangles_and_points()
248
- assert t is not None and p is not None, f'surface {surface.title} is empty'
262
+ assert t is not None and p is not None, f"surface {surface.title} is empty"
249
263
  if agitate:
250
264
  p += 1.0e-5 * (np.random.random(p.shape) - 0.5)
251
- log.debug(f'surface: {surface.title}; p0: {p[0]}; crs uuid: {surface.crs_uuid}')
252
- log.debug(f'surface min xyz: {np.min(p, axis = 0)}')
253
- log.debug(f'surface max xyz: {np.max(p, axis = 0)}')
265
+ log.debug(f"surface: {surface.title}; p0: {p[0]}; crs uuid: {surface.crs_uuid}")
266
+ log.debug(f"surface min xyz: {np.min(p, axis = 0)}")
267
+ log.debug(f"surface max xyz: {np.max(p, axis = 0)}")
254
268
  if not bu.matching_uuids(grid.crs_uuid, surface.crs_uuid):
255
- log.debug('converting from surface crs to grid crs')
269
+ log.debug("converting from surface crs to grid crs")
256
270
  s_crs = rqc.Crs(surface.model, uuid = surface.crs_uuid)
257
271
  s_crs.convert_array_to(grid.crs, p)
258
272
  surface.crs_uuid = grid.crs.uuid
259
- log.debug(f'surface: {surface.title}; p0: {p[0]}; crs uuid: {surface.crs_uuid}')
260
- log.debug(f'surface min xyz: {np.min(p, axis = 0)}')
261
- log.debug(f'surface max xyz: {np.max(p, axis = 0)}')
273
+ log.debug(f"surface: {surface.title}; p0: {p[0]}; crs uuid: {surface.crs_uuid}")
274
+ log.debug(f"surface min xyz: {np.min(p, axis = 0)}")
275
+ log.debug(f"surface max xyz: {np.max(p, axis = 0)}")
262
276
 
263
- log.debug(f'centres min xyz: {np.min(centres.reshape((-1, 3)), axis = 0)}')
264
- log.debug(f'centres max xyz: {np.max(centres.reshape((-1, 3)), axis = 0)}')
277
+ log.debug(f"centres min xyz: {np.min(centres.reshape((-1, 3)), axis = 0)}")
278
+ log.debug(f"centres max xyz: {np.max(centres.reshape((-1, 3)), axis = 0)}")
265
279
 
266
280
  t_count = len(t)
267
281
 
@@ -269,23 +283,25 @@ def find_faces_to_represent_surface_regular(grid,
269
283
 
270
284
  # K direction (xy projection)
271
285
  if grid.nk > 1:
272
- log.debug('searching for k faces')
286
+ log.debug("searching for k faces")
273
287
  k_faces = np.zeros((grid.nk - 1, grid.nj, grid.ni), dtype = bool)
274
288
  k_sides = np.zeros((grid.nk - 1, grid.nj, grid.ni), dtype = bool)
275
- k_offsets = np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_offsets else None
276
- k_normals = np.full((grid.nk - 1, grid.nj, grid.ni, 3), np.nan) if return_normal_vectors else None
289
+ k_offsets = (np.full((grid.nk - 1, grid.nj, grid.ni), np.nan) if return_offsets else None)
290
+ k_normals = (np.full((grid.nk - 1, grid.nj, grid.ni, 3), np.nan) if return_normal_vectors else None)
277
291
  k_centres = centres[0, :, :].reshape((-1, 3))
278
- k_hits = vec.points_in_triangles(p, t, k_centres, projection = 'xy', edged = True).reshape(
292
+ k_hits = vec.points_in_triangles(p, t, k_centres, projection = "xy", edged = True).reshape(
279
293
  (t_count, grid.nj, grid.ni))
280
294
  del k_centres
281
295
  if consistent_side:
282
- cwt = (vec.clockwise_triangles(p, t, projection = 'xy') >= 0.0)
296
+ cwt = vec.clockwise_triangles(p, t, projection = "xy") >= 0.0
283
297
  for k_t, k_j, k_i in np.stack(np.where(k_hits), axis = -1):
284
- xyz = meet.line_triangle_intersect(centres[0, k_j, k_i],
285
- centres[-1, k_j, k_i] - centres[0, k_j, k_i],
286
- p[t[k_t]],
287
- line_segment = True,
288
- t_tol = 1.0e-6)
298
+ xyz = meet.line_triangle_intersect(
299
+ centres[0, k_j, k_i],
300
+ centres[-1, k_j, k_i] - centres[0, k_j, k_i],
301
+ p[t[k_t]],
302
+ line_segment = True,
303
+ t_tol = 1.0e-6,
304
+ )
289
305
  if xyz is None: # meeting point is outwith grid
290
306
  continue
291
307
  k_face = int((xyz[2] - centres[0, k_j, k_i, 2]) / grid_dxyz[2])
@@ -299,15 +315,15 @@ def find_faces_to_represent_surface_regular(grid,
299
315
  k_sides[k_face, k_j, k_i] = cwt[k_t]
300
316
  if return_offsets:
301
317
  # compute offset as z diff between xyz and face
302
- k_offsets[k_face, k_j, k_i] = \
303
- xyz[2] - 0.5 * (centres[k_face, k_j, k_i, 2] + centres[k_face + 1, k_j, k_i, 2])
318
+ k_offsets[k_face, k_j,
319
+ k_i] = xyz[2] - 0.5 * (centres[k_face, k_j, k_i, 2] + centres[k_face + 1, k_j, k_i, 2])
304
320
  if return_normal_vectors:
305
321
  k_normals[k_face, k_j, k_i] = vec.triangle_normal_vector(p[t[k_t]])
306
322
  # todo: if consistent side, could deliver information about horizon surface inversion
307
323
  if k_normals[k_face, k_j, k_i, 2] > 0.0:
308
324
  k_normals[k_face, k_j, k_i] = -k_normals[k_face, k_j, k_i] # -ve z hemisphere normal
309
325
  del k_hits
310
- log.debug(f'k face count: {np.count_nonzero(k_faces)}')
326
+ log.debug(f"k face count: {np.count_nonzero(k_faces)}")
311
327
  else:
312
328
  k_faces = None
313
329
  k_sides = None
@@ -318,23 +334,25 @@ def find_faces_to_represent_surface_regular(grid,
318
334
 
319
335
  # J direction (xz projection)
320
336
  if grid.nj > 1:
321
- log.debug('searching for j faces')
337
+ log.debug("searching for j faces")
322
338
  j_faces = np.zeros((grid.nk, grid.nj - 1, grid.ni), dtype = bool)
323
339
  j_sides = np.zeros((grid.nk, grid.nj - 1, grid.ni), dtype = bool)
324
- j_offsets = np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_offsets else None
325
- j_normals = np.full((grid.nk, grid.nj - 1, grid.ni, 3), np.nan) if return_normal_vectors else None
340
+ j_offsets = (np.full((grid.nk, grid.nj - 1, grid.ni), np.nan) if return_offsets else None)
341
+ j_normals = (np.full((grid.nk, grid.nj - 1, grid.ni, 3), np.nan) if return_normal_vectors else None)
326
342
  j_centres = centres[:, 0, :].reshape((-1, 3))
327
- j_hits = vec.points_in_triangles(p, t, j_centres, projection = 'xz', edged = True).reshape(
343
+ j_hits = vec.points_in_triangles(p, t, j_centres, projection = "xz", edged = True).reshape(
328
344
  (t_count, grid.nk, grid.ni))
329
345
  del j_centres
330
346
  if consistent_side:
331
- cwt = (vec.clockwise_triangles(p, t, projection = 'xz') >= 0.0)
347
+ cwt = vec.clockwise_triangles(p, t, projection = "xz") >= 0.0
332
348
  for j_t, j_k, j_i in np.stack(np.where(j_hits), axis = -1):
333
- xyz = meet.line_triangle_intersect(centres[j_k, 0, j_i],
334
- centres[j_k, -1, j_i] - centres[j_k, 0, j_i],
335
- p[t[j_t]],
336
- line_segment = True,
337
- t_tol = 1.0e-6)
349
+ xyz = meet.line_triangle_intersect(
350
+ centres[j_k, 0, j_i],
351
+ centres[j_k, -1, j_i] - centres[j_k, 0, j_i],
352
+ p[t[j_t]],
353
+ line_segment = True,
354
+ t_tol = 1.0e-6,
355
+ )
338
356
  if xyz is None: # meeting point is outwith grid
339
357
  continue
340
358
  j_face = int((xyz[1] - centres[j_k, 0, j_i, 1]) / grid_dxyz[1])
@@ -348,14 +366,14 @@ def find_faces_to_represent_surface_regular(grid,
348
366
  j_sides[j_k, j_face, j_i] = cwt[j_t]
349
367
  if return_offsets:
350
368
  # compute offset as y diff between xyz and face
351
- j_offsets[j_k, j_face, j_i] = \
352
- xyz[1] - 0.5 * (centres[j_k, j_face, j_i, 1] + centres[j_k, j_face + 1, j_i, 1])
369
+ j_offsets[j_k, j_face,
370
+ j_i] = xyz[1] - 0.5 * (centres[j_k, j_face, j_i, 1] + centres[j_k, j_face + 1, j_i, 1])
353
371
  if return_normal_vectors:
354
372
  j_normals[j_k, j_face, j_i] = vec.triangle_normal_vector(p[t[j_t]])
355
373
  if j_normals[j_k, j_face, j_i, 2] > 0.0:
356
374
  j_normals[j_k, j_face, j_i] = -j_normals[j_k, j_face, j_i] # -ve z hemisphere normal
357
375
  del j_hits
358
- log.debug(f'j face count: {np.count_nonzero(j_faces)}')
376
+ log.debug(f"j face count: {np.count_nonzero(j_faces)}")
359
377
  else:
360
378
  j_faces = None
361
379
  j_sides = None
@@ -366,23 +384,25 @@ def find_faces_to_represent_surface_regular(grid,
366
384
 
367
385
  # I direction (yz projection)
368
386
  if grid.ni > 1:
369
- log.debug('searching for i faces')
387
+ log.debug("searching for i faces")
370
388
  i_faces = np.zeros((grid.nk, grid.nj, grid.ni - 1), dtype = bool)
371
389
  i_sides = np.zeros((grid.nk, grid.nj, grid.ni - 1), dtype = bool)
372
- i_offsets = np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_offsets else None
373
- i_normals = np.full((grid.nk, grid.nj, grid.ni - 1, 3), np.nan) if return_normal_vectors else None
390
+ i_offsets = (np.full((grid.nk, grid.nj, grid.ni - 1), np.nan) if return_offsets else None)
391
+ i_normals = (np.full((grid.nk, grid.nj, grid.ni - 1, 3), np.nan) if return_normal_vectors else None)
374
392
  i_centres = centres[:, :, 0].reshape((-1, 3))
375
- i_hits = vec.points_in_triangles(p, t, i_centres, projection = 'yz', edged = True).reshape(
393
+ i_hits = vec.points_in_triangles(p, t, i_centres, projection = "yz", edged = True).reshape(
376
394
  (t_count, grid.nk, grid.nj))
377
395
  del i_centres
378
396
  if consistent_side:
379
- cwt = (vec.clockwise_triangles(p, t, projection = 'yz') >= 0.0)
397
+ cwt = vec.clockwise_triangles(p, t, projection = "yz") >= 0.0
380
398
  for i_t, i_k, i_j in np.stack(np.where(i_hits), axis = -1):
381
- xyz = meet.line_triangle_intersect(centres[i_k, i_j, 0],
382
- centres[i_k, i_j, -1] - centres[i_k, i_j, 0],
383
- p[t[i_t]],
384
- line_segment = True,
385
- t_tol = 1.0e-6)
399
+ xyz = meet.line_triangle_intersect(
400
+ centres[i_k, i_j, 0],
401
+ centres[i_k, i_j, -1] - centres[i_k, i_j, 0],
402
+ p[t[i_t]],
403
+ line_segment = True,
404
+ t_tol = 1.0e-6,
405
+ )
386
406
  if xyz is None: # meeting point is outwith grid
387
407
  continue
388
408
  i_face = int((xyz[0] - centres[i_k, i_j, 0, 0]) / grid_dxyz[0])
@@ -396,14 +416,14 @@ def find_faces_to_represent_surface_regular(grid,
396
416
  i_sides[i_k, i_j, i_face] = cwt[i_t]
397
417
  if return_offsets:
398
418
  # compute offset as x diff between xyz and face
399
- i_offsets[i_k, i_j, i_face] = \
400
- xyz[0] - 0.5 * (centres[i_k, i_j, i_face, 0] + centres[i_k, i_j, i_face + 1, 0])
419
+ i_offsets[i_k, i_j,
420
+ i_face] = xyz[0] - 0.5 * (centres[i_k, i_j, i_face, 0] + centres[i_k, i_j, i_face + 1, 0])
401
421
  if return_normal_vectors:
402
422
  i_normals[i_k, i_j, i_face] = vec.triangle_normal_vector(p[t[i_t]])
403
423
  if i_normals[i_k, i_j, i_face, 2] > 0.0:
404
424
  i_normals[i_k, i_j, i_face] = -i_normals[i_k, i_j, i_face] # -ve z hemisphere normal
405
425
  del i_hits
406
- log.debug(f'i face count: {np.count_nonzero(i_faces)}')
426
+ log.debug(f"i face count: {np.count_nonzero(i_faces)}")
407
427
  else:
408
428
  i_faces = None
409
429
  i_sides = None
@@ -417,36 +437,38 @@ def find_faces_to_represent_surface_regular(grid,
417
437
  j_sides = None
418
438
  i_sides = None
419
439
 
420
- log.debug('converting face sets into grid connection set')
421
- gcs = rqf.GridConnectionSet(grid.model,
422
- grid = grid,
423
- k_faces = k_faces,
424
- j_faces = j_faces,
425
- i_faces = i_faces,
426
- k_sides = k_sides,
427
- j_sides = j_sides,
428
- i_sides = i_sides,
429
- feature_name = name,
430
- feature_type = feature_type,
431
- title = title,
432
- create_organizing_objects_where_needed = True)
440
+ log.debug("converting face sets into grid connection set")
441
+ gcs = rqf.GridConnectionSet(
442
+ grid.model,
443
+ grid = grid,
444
+ k_faces = k_faces,
445
+ j_faces = j_faces,
446
+ i_faces = i_faces,
447
+ k_sides = k_sides,
448
+ j_sides = j_sides,
449
+ i_sides = i_sides,
450
+ feature_name = name,
451
+ feature_type = feature_type,
452
+ title = title,
453
+ create_organizing_objects_where_needed = True,
454
+ )
433
455
 
434
456
  # NB. following assumes faces have been added to gcs in a particular order!
435
457
  if return_offsets:
436
- k_offsets_list = np.empty((0,)) if k_offsets is None else k_offsets[np.where(k_faces)]
437
- j_offsets_list = np.empty((0,)) if j_offsets is None else j_offsets[np.where(j_faces)]
438
- i_offsets_list = np.empty((0,)) if i_offsets is None else i_offsets[np.where(i_faces)]
458
+ k_offsets_list = (np.empty((0,)) if k_offsets is None else k_offsets[np.where(k_faces)])
459
+ j_offsets_list = (np.empty((0,)) if j_offsets is None else j_offsets[np.where(j_faces)])
460
+ i_offsets_list = (np.empty((0,)) if i_offsets is None else i_offsets[np.where(i_faces)])
439
461
  all_offsets = _all_offsets(grid.crs, k_offsets_list, j_offsets_list, i_offsets_list)
440
- log.debug(f'gcs count: {gcs.count}; all offsets shape: {all_offsets.shape}')
462
+ log.debug(f"gcs count: {gcs.count}; all offsets shape: {all_offsets.shape}")
441
463
  assert all_offsets.shape == (gcs.count,)
442
464
 
443
465
  # NB. following assumes faces have been added to gcs in a particular order!
444
466
  if return_normal_vectors:
445
- k_normals_list = np.empty((0, 3)) if k_normals is None else k_normals[np.where(k_faces)]
446
- j_normals_list = np.empty((0, 3)) if j_normals is None else j_normals[np.where(j_faces)]
447
- i_normals_list = np.empty((0, 3)) if i_normals is None else i_normals[np.where(i_faces)]
467
+ k_normals_list = (np.empty((0, 3)) if k_normals is None else k_normals[np.where(k_faces)])
468
+ j_normals_list = (np.empty((0, 3)) if j_normals is None else j_normals[np.where(j_faces)])
469
+ i_normals_list = (np.empty((0, 3)) if i_normals is None else i_normals[np.where(i_faces)])
448
470
  all_normals = np.concatenate((k_normals_list, j_normals_list, i_normals_list), axis = 0)
449
- log.debug(f'gcs count: {gcs.count}; all normals shape: {all_normals.shape}')
471
+ log.debug(f"gcs count: {gcs.count}; all normals shape: {all_normals.shape}")
450
472
  assert all_normals.shape == (gcs.count, 3)
451
473
  if grid.crs.xy_units != grid.crs.z_units:
452
474
  wam.convert_lengths(all_normals[:, 2], grid.crs.z_units, grid.crs.xy_units)
@@ -459,24 +481,26 @@ def find_faces_to_represent_surface_regular(grid,
459
481
  if return_properties:
460
482
  props_dict = {}
461
483
  if return_offsets:
462
- props_dict['offset'] = all_offsets
484
+ props_dict["offset"] = all_offsets
463
485
  if return_normal_vectors:
464
- props_dict['normal vector'] = all_normals
486
+ props_dict["normal vector"] = all_normals
465
487
  return (gcs, props_dict)
466
488
 
467
489
  return gcs
468
490
 
469
491
 
470
- def find_faces_to_represent_surface_regular_optimised(grid,
471
- surface,
472
- name,
473
- title = None,
474
- agitate = False,
475
- feature_type = 'fault',
476
- is_curtain = False,
477
- progress_fn = None,
478
- return_properties = None,
479
- raw_bisector = False):
492
+ def find_faces_to_represent_surface_regular_optimised(
493
+ grid,
494
+ surface,
495
+ name,
496
+ title = None,
497
+ agitate = False,
498
+ feature_type = "fault",
499
+ is_curtain = False,
500
+ progress_fn = None,
501
+ return_properties = None,
502
+ raw_bisector = False,
503
+ ):
480
504
  """Returns a grid connection set containing those cell faces which are deemed to represent the surface.
481
505
 
482
506
  argumants:
@@ -532,15 +556,21 @@ def find_faces_to_represent_surface_regular_optimised(grid,
532
556
  return_flange_bool = False
533
557
  if return_properties:
534
558
  assert all([
535
- p in ['triangle', 'depth', 'offset', 'grid bisector', 'grid shadow', 'flange bool']
536
- for p in return_properties
559
+ p in [
560
+ "triangle",
561
+ "depth",
562
+ "offset",
563
+ "grid bisector",
564
+ "grid shadow",
565
+ "flange bool",
566
+ ] for p in return_properties
537
567
  ])
538
- return_triangles = ('triangle' in return_properties)
539
- return_depths = ('depth' in return_properties)
540
- return_offsets = ('offset' in return_properties)
541
- return_bisector = ('grid bisector' in return_properties)
542
- return_shadow = ('grid shadow' in return_properties)
543
- return_flange_bool = ('flange bool' in return_properties)
568
+ return_triangles = "triangle" in return_properties
569
+ return_depths = "depth" in return_properties
570
+ return_offsets = "offset" in return_properties
571
+ return_bisector = "grid bisector" in return_properties
572
+ return_shadow = "grid shadow" in return_properties
573
+ return_flange_bool = "flange bool" in return_properties
544
574
  if return_flange_bool:
545
575
  return_triangles = True
546
576
 
@@ -550,25 +580,29 @@ def find_faces_to_represent_surface_regular_optimised(grid,
550
580
  if progress_fn is not None:
551
581
  progress_fn(0.0)
552
582
 
553
- log.debug(f'intersecting surface {surface.title} with regular grid {grid.title}')
583
+ log.debug(f"intersecting surface {surface.title} with regular grid {grid.title}")
554
584
  # log.debug(f'grid extent kji: {grid.extent_kji}')
555
585
 
556
- grid_dxyz = (grid.block_dxyz_dkji[2, 0], grid.block_dxyz_dkji[1, 1], grid.block_dxyz_dkji[0, 2])
586
+ grid_dxyz = (
587
+ grid.block_dxyz_dkji[2, 0],
588
+ grid.block_dxyz_dkji[1, 1],
589
+ grid.block_dxyz_dkji[0, 2],
590
+ )
557
591
  triangles, points = surface.triangles_and_points()
558
- assert triangles is not None and points is not None, f'surface {surface.title} is empty'
592
+ assert (triangles is not None and points is not None), f"surface {surface.title} is empty"
559
593
  if agitate:
560
594
  points += 1.0e-5 * (np.random.random(points.shape) - 0.5)
561
- # log.debug(f'surface: {surface.title}; p0: {points[0]}; crs uuid: {surface.crs_uuid}')
595
+ # log.debug(f'surface: {surface.title}; p0: {points[0]}; crs uuid: {surface.crs_uuid}')
562
596
  # log.debug(f'surface min xyz: {np.min(points, axis = 0)}')
563
597
  # log.debug(f'surface max xyz: {np.max(points, axis = 0)}')
564
598
  if not bu.matching_uuids(grid.crs_uuid, surface.crs_uuid):
565
- log.debug('converting from surface crs to grid crs')
599
+ log.debug("converting from surface crs to grid crs")
566
600
  s_crs = rqc.Crs(surface.model, uuid = surface.crs_uuid)
567
601
  s_crs.convert_array_to(grid.crs, points)
568
602
  surface.crs_uuid = grid.crs.uuid
569
603
  # log.debug(f'surface: {surface.title}; p0: {points[0]}; crs uuid: {surface.crs_uuid}')
570
604
  # log.debug(f'surface min xyz: {np.min(points, axis = 0)}')
571
- # log.debug(f'surface max xyz: {np.max(points, axis = 0)}')
605
+ # log.debug(f'surface max xyz: {np.max(points, axis = 0)}')
572
606
 
573
607
  nk = 1 if is_curtain else grid.nk
574
608
  # K direction (xy projection)
@@ -586,11 +620,23 @@ def find_faces_to_represent_surface_regular_optimised(grid,
586
620
  axis = 2
587
621
  index1 = 1
588
622
  index2 = 2
589
- k_faces, k_offsets, k_triangles = \
590
- intersect_numba(axis, index1, index2, k_hits, nk, points,
591
- triangles, grid_dxyz, k_faces,
592
- return_depths, k_depths,
593
- return_offsets, k_offsets, return_triangles, k_triangles)
623
+ k_faces, k_offsets, k_triangles = intersect_numba(
624
+ axis,
625
+ index1,
626
+ index2,
627
+ k_hits,
628
+ nk,
629
+ points,
630
+ triangles,
631
+ grid_dxyz,
632
+ k_faces,
633
+ return_depths,
634
+ k_depths,
635
+ return_offsets,
636
+ k_offsets,
637
+ return_triangles,
638
+ k_triangles,
639
+ )
594
640
  del k_hits
595
641
  del p_xy
596
642
  log.debug(f"k face count: {np.count_nonzero(k_faces)}")
@@ -617,11 +663,23 @@ def find_faces_to_represent_surface_regular_optimised(grid,
617
663
  axis = 1
618
664
  index1 = 0
619
665
  index2 = 2
620
- j_faces, j_offsets, j_triangles = \
621
- intersect_numba(axis, index1, index2, j_hits, grid.nj, points,
622
- triangles, grid_dxyz, j_faces,
623
- return_depths, j_depths,
624
- return_offsets, j_offsets, return_triangles, j_triangles)
666
+ j_faces, j_offsets, j_triangles = intersect_numba(
667
+ axis,
668
+ index1,
669
+ index2,
670
+ j_hits,
671
+ grid.nj,
672
+ points,
673
+ triangles,
674
+ grid_dxyz,
675
+ j_faces,
676
+ return_depths,
677
+ j_depths,
678
+ return_offsets,
679
+ j_offsets,
680
+ return_triangles,
681
+ j_triangles,
682
+ )
625
683
  del j_hits
626
684
  del p_xz
627
685
  if is_curtain and grid.nk > 1: # expand arrays to all layers
@@ -653,11 +711,23 @@ def find_faces_to_represent_surface_regular_optimised(grid,
653
711
  axis = 0
654
712
  index1 = 0
655
713
  index2 = 1
656
- i_faces, i_offsets, i_triangles = \
657
- intersect_numba(axis, index1, index2, i_hits, grid.ni, points,
658
- triangles, grid_dxyz, i_faces,
659
- return_depths, i_depths,
660
- return_offsets, i_offsets, return_triangles, i_triangles)
714
+ i_faces, i_offsets, i_triangles = intersect_numba(
715
+ axis,
716
+ index1,
717
+ index2,
718
+ i_hits,
719
+ grid.ni,
720
+ points,
721
+ triangles,
722
+ grid_dxyz,
723
+ i_faces,
724
+ return_depths,
725
+ i_depths,
726
+ return_offsets,
727
+ i_offsets,
728
+ return_triangles,
729
+ i_triangles,
730
+ )
661
731
  del i_hits
662
732
  del p_yz
663
733
  if is_curtain and grid.nk > 1: # expand arrays to all layers
@@ -696,9 +766,9 @@ def find_faces_to_represent_surface_regular_optimised(grid,
696
766
  # NB. following assumes faces have been added to gcs in a particular order!
697
767
  if return_triangles:
698
768
  # log.debug('preparing triangles array')
699
- k_tri_list = np.empty((0,)) if k_triangles is None else k_triangles[where_true(k_faces)]
700
- j_tri_list = np.empty((0,)) if j_triangles is None else j_triangles[where_true(j_faces)]
701
- i_tri_list = np.empty((0,)) if i_triangles is None else i_triangles[where_true(i_faces)]
769
+ k_tri_list = (np.empty((0,)) if k_triangles is None else k_triangles[_where_true(k_faces)])
770
+ j_tri_list = (np.empty((0,)) if j_triangles is None else j_triangles[_where_true(j_faces)])
771
+ i_tri_list = (np.empty((0,)) if i_triangles is None else i_triangles[_where_true(i_faces)])
702
772
  all_tris = np.concatenate((k_tri_list, j_tri_list, i_tri_list), axis = 0)
703
773
  # log.debug(f'gcs count: {gcs.count}; all triangles shape: {all_tris.shape}')
704
774
  assert all_tris.shape == (gcs.count,)
@@ -706,9 +776,9 @@ def find_faces_to_represent_surface_regular_optimised(grid,
706
776
  # NB. following assumes faces have been added to gcs in a particular order!
707
777
  if return_depths:
708
778
  # log.debug('preparing depths array')
709
- k_depths_list = np.empty((0,)) if k_depths is None else k_depths[where_true(k_faces)]
710
- j_depths_list = np.empty((0,)) if j_depths is None else j_depths[where_true(j_faces)]
711
- i_depths_list = np.empty((0,)) if i_depths is None else i_depths[where_true(i_faces)]
779
+ k_depths_list = (np.empty((0,)) if k_depths is None else k_depths[_where_true(k_faces)])
780
+ j_depths_list = (np.empty((0,)) if j_depths is None else j_depths[_where_true(j_faces)])
781
+ i_depths_list = (np.empty((0,)) if i_depths is None else i_depths[_where_true(i_faces)])
712
782
  all_depths = np.concatenate((k_depths_list, j_depths_list, i_depths_list), axis = 0)
713
783
  # log.debug(f'gcs count: {gcs.count}; all depths shape: {all_depths.shape}')
714
784
  assert all_depths.shape == (gcs.count,)
@@ -716,19 +786,19 @@ def find_faces_to_represent_surface_regular_optimised(grid,
716
786
  # NB. following assumes faces have been added to gcs in a particular order!
717
787
  if return_offsets:
718
788
  # log.debug('preparing offsets array')
719
- k_offsets_list = np.empty((0,)) if k_offsets is None else k_offsets[where_true(k_faces)]
720
- j_offsets_list = np.empty((0,)) if j_offsets is None else j_offsets[where_true(j_faces)]
721
- i_offsets_list = np.empty((0,)) if i_offsets is None else i_offsets[where_true(i_faces)]
789
+ k_offsets_list = (np.empty((0,)) if k_offsets is None else k_offsets[_where_true(k_faces)])
790
+ j_offsets_list = (np.empty((0,)) if j_offsets is None else j_offsets[_where_true(j_faces)])
791
+ i_offsets_list = (np.empty((0,)) if i_offsets is None else i_offsets[_where_true(i_faces)])
722
792
  all_offsets = _all_offsets(grid.crs, k_offsets_list, j_offsets_list, i_offsets_list)
723
793
  # log.debug(f'gcs count: {gcs.count}; all offsets shape: {all_offsets.shape}')
724
794
  assert all_offsets.shape == (gcs.count,)
725
795
 
726
796
  if return_flange_bool:
727
797
  # log.debug('preparing flange array')
728
- flange_bool_uuid = surface.model.uuid(title = 'flange bool',
729
- obj_type = 'DiscreteProperty',
798
+ flange_bool_uuid = surface.model.uuid(title = "flange bool",
799
+ obj_type = "DiscreteProperty",
730
800
  related_uuid = surface.uuid)
731
- assert flange_bool_uuid is not None, f"No flange bool property found for surface: {surface.title}"
801
+ assert (flange_bool_uuid is not None), f"No flange bool property found for surface: {surface.title}"
732
802
  flange_bool = rqp.Property(surface.model, uuid = flange_bool_uuid)
733
803
  flange_array = flange_bool.array_ref()
734
804
  all_flange = np.take(flange_array, all_tris)
@@ -737,46 +807,46 @@ def find_faces_to_represent_surface_regular_optimised(grid,
737
807
  # note: following is a grid cells property, not a gcs property
738
808
  if return_bisector:
739
809
  if is_curtain:
740
- log.debug('preparing columns bisector')
810
+ log.debug("preparing columns bisector")
741
811
  bisector = column_bisector_from_faces((grid.nj, grid.ni), j_faces[0], i_faces[0])
742
812
  # log.debug('finished preparing columns bisector')
743
813
  else:
744
- log.debug('preparing cells bisector')
814
+ log.debug("preparing cells bisector")
745
815
  bisector, is_curtain = bisector_from_faces(tuple(grid.extent_kji), k_faces, j_faces, i_faces, raw_bisector)
746
816
  if is_curtain:
747
817
  bisector = bisector[0] # reduce to a columns property
748
818
 
749
819
  # note: following is a grid cells property, not a gcs property
750
820
  if return_shadow:
751
- log.debug('preparing cells shadow')
821
+ log.debug("preparing cells shadow")
752
822
  shadow = shadow_from_faces(tuple(grid.extent_kji), k_faces)
753
823
 
754
824
  if progress_fn is not None:
755
825
  progress_fn(1.0)
756
826
 
757
- log.debug(f'finishing find_faces_to_represent_surface_regular_optimised for {name}')
827
+ log.debug(f"finishing find_faces_to_represent_surface_regular_optimised for {name}")
758
828
 
759
829
  # if returning properties, construct dictionary
760
830
  if return_properties:
761
831
  props_dict = {}
762
832
  if return_triangles:
763
- props_dict['triangle'] = all_tris
833
+ props_dict["triangle"] = all_tris
764
834
  if return_depths:
765
- props_dict['depth'] = all_depths
835
+ props_dict["depth"] = all_depths
766
836
  if return_offsets:
767
- props_dict['offset'] = all_offsets
837
+ props_dict["offset"] = all_offsets
768
838
  if return_bisector:
769
- props_dict['grid bisector'] = (bisector, is_curtain)
839
+ props_dict["grid bisector"] = (bisector, is_curtain)
770
840
  if return_shadow:
771
- props_dict['grid shadow'] = shadow
841
+ props_dict["grid shadow"] = shadow
772
842
  if return_flange_bool:
773
- props_dict['flange bool'] = all_flange
843
+ props_dict["flange bool"] = all_flange
774
844
  return (gcs, props_dict)
775
845
 
776
846
  return gcs
777
847
 
778
848
 
779
- def find_faces_to_represent_surface(grid, surface, name, mode = 'auto', feature_type = 'fault', progress_fn = None):
849
+ def find_faces_to_represent_surface(grid, surface, name, mode = "auto", feature_type = "fault", progress_fn = None):
780
850
  """Returns a grid connection set containing those cell faces which are deemed to represent the surface.
781
851
 
782
852
  arguments:
@@ -797,44 +867,49 @@ def find_faces_to_represent_surface(grid, surface, name, mode = 'auto', feature_
797
867
  this is a wrapper function selecting between more specialised functions; use those directly for more options
798
868
  """
799
869
 
800
- log.debug('finding cell faces for surface')
801
- if mode == 'auto':
870
+ log.debug("finding cell faces for surface")
871
+ if mode == "auto":
802
872
  if isinstance(grid, grr.RegularGrid) and grid.is_aligned:
803
- mode = 'regular_optimised'
873
+ mode = "regular_optimised"
804
874
  else:
805
- mode = 'staffa'
806
- if mode == 'staffa':
875
+ mode = "staffa"
876
+ if mode == "staffa":
807
877
  return find_faces_to_represent_surface_staffa(grid,
808
878
  surface,
809
879
  name,
810
880
  feature_type = feature_type,
811
881
  progress_fn = progress_fn)
812
- elif mode == 'regular':
882
+ elif mode == "regular":
813
883
  return find_faces_to_represent_surface_regular(grid,
814
884
  surface,
815
885
  name,
816
886
  feature_type = feature_type,
817
887
  progress_fn = progress_fn)
818
- elif mode == 'regular_optimised':
888
+ elif mode == "regular_optimised":
819
889
  return find_faces_to_represent_surface_regular_optimised(grid,
820
890
  surface,
821
891
  name,
822
892
  feature_type = feature_type,
823
893
  progress_fn = progress_fn)
824
- elif mode == 'regular_cuda':
894
+ elif mode == "regular_cuda":
825
895
  import resqpy.grid_surface.grid_surface_cuda as rgs_c
896
+
826
897
  return rgs_c.find_faces_to_represent_surface_regular_cuda_mgpu(grid,
827
898
  surface,
828
899
  name,
829
900
  feature_type = feature_type,
830
901
  progress_fn = progress_fn)
831
- log.critical('unrecognised mode: ' + str(mode))
902
+ log.critical("unrecognised mode: " + str(mode))
832
903
  return None
833
904
 
834
905
 
835
906
  def bisector_from_faces( # type: ignore
836
- grid_extent_kji: Tuple[int, int, int], k_faces: np.ndarray, j_faces: np.ndarray, i_faces: np.ndarray,
837
- raw_bisector: bool) -> Tuple[np.ndarray, bool]:
907
+ grid_extent_kji: Tuple[int, int, int],
908
+ k_faces: np.ndarray,
909
+ j_faces: np.ndarray,
910
+ i_faces: np.ndarray,
911
+ raw_bisector: bool,
912
+ ) -> Tuple[np.ndarray, bool]:
838
913
  """Creates a boolean array denoting the bisection of the grid by the face sets.
839
914
 
840
915
  arguments:
@@ -861,9 +936,14 @@ def bisector_from_faces( # type: ignore
861
936
  boundary = get_boundary(k_faces, j_faces, i_faces, grid_extent_kji)
862
937
 
863
938
  # Setting up the bisector array for the bounding box.
864
- bounding_array = np.zeros((boundary["k_max"] - boundary["k_min"] + 1, boundary["j_max"] - boundary["j_min"] + 1,
865
- boundary["i_max"] - boundary["i_min"] + 1),
866
- dtype = np.bool_)
939
+ bounding_array = np.zeros(
940
+ (
941
+ boundary["k_max"] - boundary["k_min"] + 1,
942
+ boundary["j_max"] - boundary["j_min"] + 1,
943
+ boundary["i_max"] - boundary["i_min"] + 1,
944
+ ),
945
+ dtype = np.bool_,
946
+ )
867
947
 
868
948
  # Seeding the bisector array from (0, 0, 0) up to the first faces that represent the surface.
869
949
  boundary_values = tuple(boundary.values())
@@ -886,19 +966,25 @@ def bisector_from_faces( # type: ignore
886
966
  point = tuple(point) # type: ignore
887
967
  if point not in points:
888
968
  points.add(point)
889
- bounding_array, _, _, _ = _seed_array(point, k_faces, j_faces, i_faces, boundary_values,
890
- bounding_array)
969
+ bounding_array, _, _, _ = _seed_array(
970
+ point,
971
+ k_faces,
972
+ j_faces,
973
+ i_faces,
974
+ boundary_values,
975
+ bounding_array,
976
+ )
891
977
 
892
978
  # Setting up the array for the changing values.
893
979
  changing_array = np.zeros_like(bounding_array, dtype = np.bool_)
894
980
 
895
981
  # Repeatedly spreading True values to neighbouring cells that are not the other side of a face.
896
982
  open_k = np.logical_not(k_faces)[boundary["k_min"]:boundary["k_max"], boundary["j_min"]:boundary["j_max"] + 1,
897
- boundary["i_min"]:boundary["i_max"] + 1]
983
+ boundary["i_min"]:boundary["i_max"] + 1,]
898
984
  open_j = np.logical_not(j_faces)[boundary["k_min"]:boundary["k_max"] + 1, boundary["j_min"]:boundary["j_max"],
899
- boundary["i_min"]:boundary["i_max"] + 1]
985
+ boundary["i_min"]:boundary["i_max"] + 1,]
900
986
  open_i = np.logical_not(i_faces)[boundary["k_min"]:boundary["k_max"] + 1, boundary["j_min"]:boundary["j_max"] + 1,
901
- boundary["i_min"]:boundary["i_max"]]
987
+ boundary["i_min"]:boundary["i_max"],]
902
988
  while True:
903
989
  changing_array[:] = False
904
990
 
@@ -927,7 +1013,7 @@ def bisector_from_faces( # type: ignore
927
1013
  # Setting up the full bisectors array and assigning the bounding box values.
928
1014
  array = np.zeros(grid_extent_kji, dtype = np.bool_)
929
1015
  array[boundary["k_min"]:boundary["k_max"] + 1, boundary["j_min"]:boundary["j_max"] + 1,
930
- boundary["i_min"]:boundary["i_max"] + 1] = bounding_array
1016
+ boundary["i_min"]:boundary["i_max"] + 1,] = bounding_array
931
1017
 
932
1018
  # Setting values outside of the bounding box.
933
1019
  if boundary["k_max"] != grid_extent_kji[0] - 1 and np.any(bounding_array[-1, :, :]):
@@ -946,7 +1032,7 @@ def bisector_from_faces( # type: ignore
946
1032
  # Check all array elements are not the same.
947
1033
  true_count = np.count_nonzero(array)
948
1034
  cell_count = array.size
949
- assert 0 < true_count < cell_count, 'Face set for surface is leaky or empty (surface does not intersect grid).'
1035
+ assert (0 < true_count < cell_count), "Face set for surface is leaky or empty (surface does not intersect grid)."
950
1036
 
951
1037
  # Negate the array if it minimises the mean k and determine if the surface is a curtain.
952
1038
  layer_cell_count = grid_extent_kji[1] * grid_extent_kji[2]
@@ -1005,7 +1091,7 @@ def column_bisector_from_faces(grid_extent_ji: Tuple[int, int], j_faces: np.ndar
1005
1091
  # j faces
1006
1092
  c[1:, :] = np.logical_or(c[1:, :], np.logical_and(a[:-1, :], open_j))
1007
1093
  c[:-1, :] = np.logical_or(c[:-1, :], np.logical_and(a[1:, :], open_j))
1008
- # i faces
1094
+ # i faces
1009
1095
  c[:, 1:] = np.logical_or(c[:, 1:], np.logical_and(a[:, :-1], open_i))
1010
1096
  c[:, :-1] = np.logical_or(c[:, :-1], np.logical_and(a[:, 1:], open_i))
1011
1097
  c[:] = np.logical_and(c, np.logical_not(a))
@@ -1013,7 +1099,7 @@ def column_bisector_from_faces(grid_extent_ji: Tuple[int, int], j_faces: np.ndar
1013
1099
  break
1014
1100
  a[:] = np.logical_or(a, c)
1015
1101
  if np.all(a):
1016
- log.warning('curtain is leaky or misses grid when setting column bisector')
1102
+ log.warning("curtain is leaky or misses grid when setting column bisector")
1017
1103
  # log.debug(f'returning bisector with count: {np.count_nonzero(a)} of {a.size}; shape: {a.shape}')
1018
1104
  return a
1019
1105
 
@@ -1055,8 +1141,11 @@ def shadow_from_faces(extent_kji, k_faces):
1055
1141
 
1056
1142
 
1057
1143
  def get_boundary( # type: ignore
1058
- k_faces: np.ndarray, j_faces: np.ndarray, i_faces: np.ndarray, grid_extent_kji: Tuple[int, int,
1059
- int]) -> Dict[str, int]:
1144
+ k_faces: np.ndarray,
1145
+ j_faces: np.ndarray,
1146
+ i_faces: np.ndarray,
1147
+ grid_extent_kji: Tuple[int, int, int],
1148
+ ) -> Dict[str, int]:
1060
1149
  """Cretaes a dictionary of the indices that bound the surface (where the faces are True).
1061
1150
 
1062
1151
  arguments:
@@ -1086,24 +1175,24 @@ def get_boundary( # type: ignore
1086
1175
 
1087
1176
  for f_i, faces in enumerate([k_faces, j_faces, i_faces]):
1088
1177
 
1089
- # NB. k, j & i for rest of loop refer to indices of faces, regardless of which face set is being processed
1178
+ # NB. k, j & i for rest of loop refer to indices of faces, regardless of which face set is being processed
1090
1179
 
1091
- where_k, where_j, where_i = where_true(faces)
1180
+ where_k, where_j, where_i = _where_true(faces)
1092
1181
 
1093
1182
  if len(where_k) == 0:
1094
1183
  continue
1095
1184
 
1096
1185
  min_k = where_k[0] # optimisation if np.where() guaranteed to return results in natural order
1097
1186
  max_k = where_k[-1]
1098
- # min_k = np.amin(where_k)
1099
- # max_k = np.amax(where_k)
1187
+ # min_k = np.amin(where_k)
1188
+ # max_k = np.amax(where_k)
1100
1189
  min_j = np.amin(where_j)
1101
1190
  max_j = np.amax(where_j)
1102
1191
  min_i = np.amin(where_i)
1103
1192
  max_i = np.amax(where_i)
1104
1193
 
1105
1194
  # include cells on both sides of internal faces
1106
- # and add buffer slice where edge of grid not reached by surface faces
1195
+ # and add buffer slice where edge of grid not reached by surface faces
1107
1196
  if f_i == 0:
1108
1197
  max_k += 1
1109
1198
  else:
@@ -1127,38 +1216,38 @@ def get_boundary( # type: ignore
1127
1216
  max_i += 1
1128
1217
 
1129
1218
  if starting:
1130
- boundary['k_min'] = min_k
1131
- boundary['k_max'] = max_k
1132
- boundary['j_min'] = min_j
1133
- boundary['j_max'] = max_j
1134
- boundary['i_min'] = min_i
1135
- boundary['i_max'] = max_i
1219
+ boundary["k_min"] = min_k
1220
+ boundary["k_max"] = max_k
1221
+ boundary["j_min"] = min_j
1222
+ boundary["j_max"] = max_j
1223
+ boundary["i_min"] = min_i
1224
+ boundary["i_max"] = max_i
1136
1225
  starting = False
1137
1226
  else:
1138
- if min_k < boundary['k_min']:
1139
- boundary['k_min'] = min_k
1140
- if max_k > boundary['k_max']:
1141
- boundary['k_max'] = max_k
1142
- if min_j < boundary['j_min']:
1143
- boundary['j_min'] = min_j
1144
- if max_j > boundary['j_max']:
1145
- boundary['j_max'] = max_j
1146
- if min_i < boundary['i_min']:
1147
- boundary['i_min'] = min_i
1148
- if max_i > boundary['i_max']:
1149
- boundary['i_max'] = max_i
1227
+ if min_k < boundary["k_min"]:
1228
+ boundary["k_min"] = min_k
1229
+ if max_k > boundary["k_max"]:
1230
+ boundary["k_max"] = max_k
1231
+ if min_j < boundary["j_min"]:
1232
+ boundary["j_min"] = min_j
1233
+ if max_j > boundary["j_max"]:
1234
+ boundary["j_max"] = max_j
1235
+ if min_i < boundary["i_min"]:
1236
+ boundary["i_min"] = min_i
1237
+ if max_i > boundary["i_max"]:
1238
+ boundary["i_max"] = max_i
1150
1239
 
1151
1240
  return boundary # type: ignore
1152
1241
 
1153
1242
 
1154
- @njit
1155
- def where_true(data: np.ndarray):
1243
+ @njit # pragma: no cover
1244
+ def _where_true(data: np.ndarray):
1156
1245
  """Jitted NumPy 'where' function to improve performance on subsequent calls."""
1157
1246
  return np.where(data)
1158
1247
 
1159
1248
 
1160
- @njit
1161
- def first_true(array: np.ndarray) -> Optional[int]: # type: ignore
1249
+ @njit # pragma: no cover
1250
+ def _first_true(array: np.ndarray) -> Optional[int]: # type: ignore
1162
1251
  """Returns the index + 1 of the first True value in the array."""
1163
1252
  for idx, val in np.ndenumerate(array):
1164
1253
  if val:
@@ -1166,11 +1255,24 @@ def first_true(array: np.ndarray) -> Optional[int]: # type: ignore
1166
1255
  return array.size
1167
1256
 
1168
1257
 
1169
- @njit
1170
- def intersect_numba(axis: int, index1: int, index2: int, hits: np.ndarray, n_axis: int, points: np.ndarray,
1171
- triangles: np.ndarray, grid_dxyz: Tuple[float], faces: np.ndarray, return_depths: bool,
1172
- depths: np.ndarray, return_offsets: bool, offsets: np.ndarray, return_triangles: bool,
1173
- triangle_per_face: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
1258
+ @njit # pragma: no cover
1259
+ def intersect_numba(
1260
+ axis: int,
1261
+ index1: int,
1262
+ index2: int,
1263
+ hits: np.ndarray,
1264
+ n_axis: int,
1265
+ points: np.ndarray,
1266
+ triangles: np.ndarray,
1267
+ grid_dxyz: Tuple[float],
1268
+ faces: np.ndarray,
1269
+ return_depths: bool,
1270
+ depths: np.ndarray,
1271
+ return_offsets: bool,
1272
+ offsets: np.ndarray,
1273
+ return_triangles: bool,
1274
+ triangle_per_face: np.ndarray,
1275
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
1174
1276
  """Finds the faces that intersect the surface in 3D.
1175
1277
 
1176
1278
  arguments:
@@ -1204,12 +1306,12 @@ def intersect_numba(axis: int, index1: int, index2: int, hits: np.ndarray, n_axi
1204
1306
  for i in prange(len(hits)):
1205
1307
  tri, d1, d2 = hits[i]
1206
1308
 
1207
- # Line start point in 3D which had a projection hit.
1309
+ # Line start point in 3D which had a projection hit.
1208
1310
  centre_point_start = np.zeros(3, dtype = np.float64) + grid_dxyz[axis] / 2
1209
1311
  centre_point_start[2 - index1] = (d1 + 0.5) * grid_dxyz[2 - index1]
1210
1312
  centre_point_start[2 - index2] = (d2 + 0.5) * grid_dxyz[2 - index2]
1211
1313
 
1212
- # Line end point in 3D.
1314
+ # Line end point in 3D.
1213
1315
  centre_point_end = np.copy(centre_point_start)
1214
1316
  centre_point_end[axis] = grid_dxyz[axis] * (n_axis - 0.5)
1215
1317
 
@@ -1248,9 +1350,15 @@ def intersect_numba(axis: int, index1: int, index2: int, hits: np.ndarray, n_axi
1248
1350
  return faces, offsets, triangle_per_face
1249
1351
 
1250
1352
 
1251
- @njit
1252
- def _seed_array(point: Tuple[int, int, int], k_faces: np.ndarray, j_faces: np.ndarray, i_faces: np.ndarray,
1253
- boundary: Tuple[int, int, int, int, int, int], array: np.ndarray) -> Tuple[np.ndarray, int, int, int]:
1353
+ @njit # pragma: no cover
1354
+ def _seed_array(
1355
+ point: Tuple[int, int, int],
1356
+ k_faces: np.ndarray,
1357
+ j_faces: np.ndarray,
1358
+ i_faces: np.ndarray,
1359
+ boundary: Tuple[int, int, int, int, int, int],
1360
+ array: np.ndarray,
1361
+ ) -> Tuple[np.ndarray, int, int, int]:
1254
1362
  """Sets values of the array True up until a face is hit in each direction.
1255
1363
 
1256
1364
  arguments:
@@ -1279,17 +1387,17 @@ def _seed_array(point: Tuple[int, int, int], k_faces: np.ndarray, j_faces: np.nd
1279
1387
 
1280
1388
  first_k = 0
1281
1389
  if k == 0:
1282
- first_k = first_true(k_faces[boundary[0]:boundary[1], boundary[2] + j, boundary[4] + i])
1390
+ first_k = _first_true(k_faces[boundary[0]:boundary[1], boundary[2] + j, boundary[4] + i])
1283
1391
  array[:first_k, j, i] = True
1284
1392
 
1285
1393
  first_j = 0
1286
1394
  if j == 0:
1287
- first_j = first_true(j_faces[boundary[0] + k, boundary[2]:boundary[3], boundary[4] + i])
1395
+ first_j = _first_true(j_faces[boundary[0] + k, boundary[2]:boundary[3], boundary[4] + i])
1288
1396
  array[k, :first_j, i] = True
1289
1397
 
1290
1398
  first_i = 0
1291
1399
  if i == 0:
1292
- first_i = first_true(i_faces[boundary[0] + k, boundary[2] + j, boundary[4]:boundary[5]])
1400
+ first_i = _first_true(i_faces[boundary[0] + k, boundary[2] + j, boundary[4]:boundary[5]])
1293
1401
  array[k, j, :first_i] = True
1294
1402
 
1295
1403
  return array, first_k, first_j, first_i