plot3d 1.8.1__tar.gz → 1.8.2__tar.gz
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.
- {plot3d-1.8.1 → plot3d-1.8.2}/PKG-INFO +1 -1
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/__init__.py +11 -4
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/blockfunctions.py +134 -55
- plot3d-1.8.2/plot3d/connectivity.py +1255 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/differencing.py +9 -9
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/face.py +3 -7
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/facefunctions.py +64 -82
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/glennht/export_functions.py +26 -22
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/glennht/import_functions.py +13 -13
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/graph.py +5 -5
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/gridpro/import_functions.py +3 -3
- plot3d-1.8.2/plot3d/normals.py +391 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/periodicity.py +287 -411
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/pointwise/import_functions.py +5 -9
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/read.py +18 -24
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/split_block.py +1 -1
- plot3d-1.8.2/plot3d/verify.py +411 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/write.py +14 -44
- {plot3d-1.8.1 → plot3d-1.8.2}/pyproject.toml +1 -1
- plot3d-1.8.1/plot3d/connectivity.py +0 -723
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/block.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/block_merging_mixed_facepairs.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/glennht/__init__.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/glennht/class_definitions.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/gridpro/__init__.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/listfunctions.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/point_match.py +0 -0
- {plot3d-1.8.1 → plot3d-1.8.2}/plot3d/pointwise/__init__.py +0 -0
|
@@ -3,17 +3,24 @@ from importlib import import_module
|
|
|
3
3
|
import os, warnings
|
|
4
4
|
|
|
5
5
|
from .block import Block
|
|
6
|
-
from .blockfunctions import rotate_block, get_outer_bounds, block_connection_matrix,split_blocks, plot_blocks, reduce_blocks, find_matching_faces
|
|
6
|
+
from .blockfunctions import rotate_block, get_outer_bounds, block_connection_matrix,split_blocks, plot_blocks, reduce_blocks, find_matching_faces, compute_min_gcd, scale_face_bounds, constant_axis
|
|
7
7
|
from .block_merging_mixed_facepairs import combine_nxnxn_cubes_mixed_pairs
|
|
8
|
-
from .connectivity import find_matching_blocks, get_face_intersection, connectivity_fast, face_matches_to_dict,
|
|
8
|
+
from .connectivity import find_matching_blocks, get_face_intersection, connectivity_fast, face_matches_to_dict, PERMUTATION_MATRICES
|
|
9
9
|
from .face import Face
|
|
10
10
|
from .facefunctions import create_face_from_diagonals, get_outer_faces, find_bounding_faces,split_face,find_face_nearest_point,match_faces_dict_to_list,outer_face_dict_to_list,find_closest_block
|
|
11
11
|
from .read import read_plot3D, read_ap_nasa
|
|
12
12
|
from .write import write_plot3D
|
|
13
13
|
from .differencing import find_edges, find_face_edges
|
|
14
|
-
from .periodicity import periodicity, periodicity_fast, create_rotation_matrix, rotated_periodicity, translational_periodicity
|
|
14
|
+
from .periodicity import periodicity, periodicity_fast, create_rotation_matrix, rotated_periodicity, translational_periodicity
|
|
15
|
+
from .verify import (verify_connectivity, verify_periodicity,
|
|
16
|
+
extract_canonical_grid, apply_permutation, verify_match,
|
|
17
|
+
verify_partial_match, try_all_permutations, get_bounds,
|
|
18
|
+
determine_plane)
|
|
15
19
|
from .point_match import point_match
|
|
16
20
|
from .split_block import split_blocks, Direction
|
|
17
21
|
from .listfunctions import unique_pairs
|
|
18
22
|
|
|
19
|
-
from .graph import write_ddcmp, build_weighted_graph_from_face_matches,csr_from_adj_and_weights,partition_from_face_matches
|
|
23
|
+
from .graph import write_ddcmp, build_weighted_graph_from_face_matches,csr_from_adj_and_weights,partition_from_face_matches
|
|
24
|
+
from .normals import (index_space_normal, compute_permutation_matrix,
|
|
25
|
+
validate_connectivity, compute_all_normals,
|
|
26
|
+
export_normals_json, import_normals_json, plot_face_normals)
|
|
@@ -14,38 +14,79 @@ import matplotlib.pyplot as plt
|
|
|
14
14
|
from mpl_toolkits.mplot3d import Axes3D
|
|
15
15
|
import numpy.typing as npt
|
|
16
16
|
|
|
17
|
+
def compute_min_gcd(blocks: List[Block]) -> int:
|
|
18
|
+
"""Compute the minimum GCD across all block dimensions.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
blocks: List of blocks.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
The minimum GCD value to use for uniform reduction.
|
|
25
|
+
"""
|
|
26
|
+
return min(
|
|
27
|
+
math.gcd(b.IMAX - 1, math.gcd(b.JMAX - 1, b.KMAX - 1))
|
|
28
|
+
for b in blocks
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def scale_face_bounds(face_dicts: list, factor: int, divide: bool = False):
|
|
33
|
+
"""Scale lb/ub bounds in face-match or outer-face dicts by a factor.
|
|
34
|
+
|
|
35
|
+
For face-match dicts (with 'block1'/'block2' sub-dicts) both sides
|
|
36
|
+
are scaled. For outer-face dicts (flat dict with 'lb'/'ub') the
|
|
37
|
+
bounds are scaled directly.
|
|
38
|
+
|
|
39
|
+
Modifies *face_dicts* in place.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
face_dicts: List of face-match or outer-face dicts.
|
|
43
|
+
factor: Scale factor.
|
|
44
|
+
divide: If True, divide by *factor*; otherwise multiply.
|
|
45
|
+
"""
|
|
46
|
+
op = (lambda x: x // factor) if divide else (lambda x: x * factor)
|
|
47
|
+
for d in face_dicts:
|
|
48
|
+
if 'block1' in d:
|
|
49
|
+
for side in ('block1', 'block2'):
|
|
50
|
+
d[side]['lb'] = [op(x) for x in d[side]['lb']]
|
|
51
|
+
d[side]['ub'] = [op(x) for x in d[side]['ub']]
|
|
52
|
+
else:
|
|
53
|
+
d['lb'] = [op(x) for x in d['lb']]
|
|
54
|
+
d['ub'] = [op(x) for x in d['ub']]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def constant_axis(lb: list, ub: list) -> int:
|
|
58
|
+
"""Return the index (0, 1, or 2) of the constant axis on a face, or -1.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
lb: Lower bound [i, j, k].
|
|
62
|
+
ub: Upper bound [i, j, k].
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Axis index where lb[d] == ub[d], or -1 if none found.
|
|
66
|
+
"""
|
|
67
|
+
for d in range(3):
|
|
68
|
+
if lb[d] == ub[d]:
|
|
69
|
+
return d
|
|
70
|
+
return -1
|
|
71
|
+
|
|
72
|
+
|
|
17
73
|
def rotate_block(block,rotation_matrix:np.ndarray) -> Block:
|
|
18
|
-
"""Rotates a block by a rotation matrix
|
|
74
|
+
"""Rotates a block by a rotation matrix
|
|
19
75
|
|
|
20
76
|
Args:
|
|
21
|
-
|
|
77
|
+
block (Block): Block to rotate
|
|
78
|
+
rotation_matrix (np.ndarray): 3x3 rotation matrix
|
|
22
79
|
|
|
23
80
|
Returns:
|
|
24
|
-
Block: returns a new rotated block
|
|
81
|
+
Block: returns a new rotated block
|
|
25
82
|
"""
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
for k in range(block.KMAX):
|
|
34
|
-
points[0,indx] = block.X[i,j,k]
|
|
35
|
-
points[1,indx] = block.Y[i,j,k]
|
|
36
|
-
points[2,indx] = block.Z[i,j,k]
|
|
37
|
-
indx+=1
|
|
38
|
-
points_rotated = np.matmul(rotation_matrix,points)
|
|
39
|
-
indx=0
|
|
40
|
-
for i in range(block.IMAX):
|
|
41
|
-
for j in range(block.JMAX):
|
|
42
|
-
for k in range(block.KMAX):
|
|
43
|
-
X[i,j,k] = points_rotated[0,indx]
|
|
44
|
-
Y[i,j,k] = points_rotated[1,indx]
|
|
45
|
-
Z[i,j,k] = points_rotated[2,indx]
|
|
46
|
-
indx+=1
|
|
47
|
-
|
|
48
|
-
return Block(X,Y,Z)
|
|
83
|
+
shape = block.X.shape
|
|
84
|
+
pts = np.stack([block.X.ravel(), block.Y.ravel(), block.Z.ravel()], axis=0) # (3, N)
|
|
85
|
+
rotated = rotation_matrix @ pts # (3, N)
|
|
86
|
+
X = rotated[0].reshape(shape)
|
|
87
|
+
Y = rotated[1].reshape(shape)
|
|
88
|
+
Z = rotated[2].reshape(shape)
|
|
89
|
+
return Block(X, Y, Z)
|
|
49
90
|
|
|
50
91
|
def get_outer_bounds(blocks:List[Block]):
|
|
51
92
|
"""Get outer bounds for a set of blocks
|
|
@@ -105,21 +146,31 @@ def block_connection_matrix(
|
|
|
105
146
|
use_area_fallback: bool = True,
|
|
106
147
|
area_min_overlap_frac: float = 0.01
|
|
107
148
|
) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
108
|
-
"""
|
|
109
|
-
|
|
149
|
+
"""Create matrices representing how blocks are connected.
|
|
150
|
+
|
|
151
|
+
GCD-reduces blocks for speed, then checks every block pair for shared
|
|
152
|
+
nodes (primary) or overlapping face area (fallback).
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
blocks: List of all blocks.
|
|
156
|
+
outer_faces: Pre-computed outer faces as dicts with 'block_index', 'lb', 'ub'.
|
|
157
|
+
If empty, outer faces are computed automatically.
|
|
158
|
+
tol: General tolerance (unused directly; kept for API compat).
|
|
159
|
+
node_tol_xyz: Tolerance for node-sharing check.
|
|
160
|
+
min_shared_frac: Minimum fraction of shared nodes to count as connected.
|
|
161
|
+
min_shared_abs: Minimum absolute number of shared nodes.
|
|
162
|
+
stride_u: Sampling stride along u-axis for node check.
|
|
163
|
+
stride_v: Sampling stride along v-axis for node check.
|
|
164
|
+
use_area_fallback: If True, fall back to polygon-overlap check.
|
|
165
|
+
area_min_overlap_frac: Minimum overlap fraction for area fallback.
|
|
110
166
|
|
|
111
167
|
Returns:
|
|
112
|
-
connectivity
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
connectivity_k : (n,n) connections where both faces are K-constant
|
|
168
|
+
(connectivity, connectivity_i, connectivity_j, connectivity_k):
|
|
169
|
+
Four (n, n) matrices where 1 = connected, -1 = not connected.
|
|
170
|
+
The last three are axis-specific (both faces I/J/K-constant).
|
|
116
171
|
"""
|
|
117
172
|
# Reduce the size of the blocks by the minimum GCD so index grids line up
|
|
118
|
-
|
|
119
|
-
for block_indx in range(len(blocks)):
|
|
120
|
-
block = blocks[block_indx]
|
|
121
|
-
gcd_array.append(math.gcd(block.IMAX - 1, math.gcd(block.JMAX - 1, block.KMAX - 1)))
|
|
122
|
-
gcd_to_use = min(gcd_array)
|
|
173
|
+
gcd_to_use = compute_min_gcd(blocks)
|
|
123
174
|
blocks = reduce_blocks(deepcopy(blocks), gcd_to_use)
|
|
124
175
|
|
|
125
176
|
# Convert dict outer faces (if provided) to Face objects at the reduced resolution
|
|
@@ -127,8 +178,8 @@ def block_connection_matrix(
|
|
|
127
178
|
for o in outer_faces:
|
|
128
179
|
face = create_face_from_diagonals(
|
|
129
180
|
blocks[o["block_index"]],
|
|
130
|
-
int(o["
|
|
131
|
-
int(o["
|
|
181
|
+
[int(o["lb"][0] / gcd_to_use), int(o["lb"][1] / gcd_to_use), int(o["lb"][2] / gcd_to_use)],
|
|
182
|
+
[int(o["ub"][0] / gcd_to_use), int(o["ub"][1] / gcd_to_use), int(o["ub"][2] / gcd_to_use)]
|
|
132
183
|
)
|
|
133
184
|
face.set_block_index(o["block_index"])
|
|
134
185
|
if "id" in o:
|
|
@@ -211,7 +262,15 @@ def block_connection_matrix(
|
|
|
211
262
|
return connectivity, connectivity_i, connectivity_j, connectivity_k
|
|
212
263
|
|
|
213
264
|
def plot_blocks(blocks):
|
|
214
|
-
|
|
265
|
+
"""Plot all blocks as a 3D wireframe grid using matplotlib.
|
|
266
|
+
|
|
267
|
+
GCD-reduces blocks for faster rendering, then draws grid lines
|
|
268
|
+
along each axis for every block with alternating markers.
|
|
269
|
+
|
|
270
|
+
Args:
|
|
271
|
+
blocks: List of Block objects to plot.
|
|
272
|
+
"""
|
|
273
|
+
gcd_array = list()
|
|
215
274
|
for block_indx in range(len(blocks)):
|
|
216
275
|
block = blocks[block_indx]
|
|
217
276
|
gcd_array.append(math.gcd(block.IMAX-1, math.gcd(block.JMAX-1, block.KMAX-1)))
|
|
@@ -300,6 +359,15 @@ def standardize_block_orientation(block:Block):
|
|
|
300
359
|
return Block(X, Y, Z)
|
|
301
360
|
|
|
302
361
|
def checkCollinearity(v1:npt.NDArray, v2:npt.NDArray):
|
|
362
|
+
"""Check if two 3D vectors are collinear (parallel or anti-parallel).
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
v1: First 3D vector.
|
|
366
|
+
v2: Second 3D vector.
|
|
367
|
+
|
|
368
|
+
Returns:
|
|
369
|
+
True if the cross product is the zero vector, False otherwise.
|
|
370
|
+
"""
|
|
303
371
|
# Calculate their cross product
|
|
304
372
|
cross_P = np.cross(v1,v2)
|
|
305
373
|
|
|
@@ -313,24 +381,35 @@ def checkCollinearity(v1:npt.NDArray, v2:npt.NDArray):
|
|
|
313
381
|
return False
|
|
314
382
|
|
|
315
383
|
def calculate_outward_normals(block:Block):
|
|
384
|
+
"""Compute outward-facing normal vectors for all six faces of a block.
|
|
385
|
+
|
|
386
|
+
Uses corner points of each face to compute cross-product normals.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
block: Block to compute normals for.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
(n_imin, n_jmin, n_kmin, n_imax, n_jmax, n_kmax): Six 3D normal vectors.
|
|
393
|
+
"""
|
|
316
394
|
# Calculate Normals
|
|
317
395
|
X = block.X
|
|
318
396
|
Y = block.Y
|
|
319
397
|
Z = block.Z
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
398
|
+
# IMAX/JMAX/KMAX are shapes (e.g. 41); last valid index is shape-1
|
|
399
|
+
imax = block.IMAX - 1
|
|
400
|
+
jmax = block.JMAX - 1
|
|
401
|
+
kmax = block.KMAX - 1
|
|
402
|
+
# IMAX - Normal should be out of the page
|
|
324
403
|
# Normals I direction: IMIN https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
|
|
325
|
-
x = [X[0,0,0],X[0,jmax,0],X[0,0,kmax]]
|
|
404
|
+
x = [X[0,0,0],X[0,jmax,0],X[0,0,kmax]]
|
|
326
405
|
y = [Y[0,0,0],Y[0,jmax,0],Y[0,0,kmax]]
|
|
327
406
|
z = [Z[0,0,0],Z[0,jmax,0],Z[0,0,kmax]]
|
|
328
|
-
u = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
407
|
+
u = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
329
408
|
v = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
|
|
330
409
|
n_imin = np.cross(u,v)
|
|
331
|
-
|
|
410
|
+
|
|
332
411
|
# Normals I direction: IMAX
|
|
333
|
-
x = [X[imax,0,0],X[imax,jmax,0],X[imax,0,kmax]]
|
|
412
|
+
x = [X[imax,0,0],X[imax,jmax,0],X[imax,0,kmax]]
|
|
334
413
|
y = [Y[imax,0,0],Y[imax,jmax,0],Y[imax,0,kmax]]
|
|
335
414
|
z = [Z[imax,0,0],Z[imax,jmax,0],Z[imax,0,kmax]]
|
|
336
415
|
v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
@@ -338,7 +417,7 @@ def calculate_outward_normals(block:Block):
|
|
|
338
417
|
n_imax = np.cross(v1,v2)
|
|
339
418
|
|
|
340
419
|
# Normals J direction: JMIN
|
|
341
|
-
x = [X[0,0,0],X[imax,0,0],X[0,0,kmax]]
|
|
420
|
+
x = [X[0,0,0],X[imax,0,0],X[0,0,kmax]]
|
|
342
421
|
y = [Y[0,0,0],Y[imax,0,0],Y[0,0,kmax]]
|
|
343
422
|
z = [Z[0,0,0],Z[imax,0,0],Z[0,0,kmax]]
|
|
344
423
|
v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
@@ -346,7 +425,7 @@ def calculate_outward_normals(block:Block):
|
|
|
346
425
|
n_jmin = np.cross(v1,v2)
|
|
347
426
|
|
|
348
427
|
# Normals J direction: JMAX
|
|
349
|
-
x = [X[0,jmax,0],X[imax,jmax,0],X[0,jmax,kmax]]
|
|
428
|
+
x = [X[0,jmax,0],X[imax,jmax,0],X[0,jmax,kmax]]
|
|
350
429
|
y = [Y[0,jmax,0],Y[imax,jmax,0],Y[0,jmax,kmax]]
|
|
351
430
|
z = [Z[0,jmax,0],Z[imax,jmax,0],Z[0,jmax,kmax]]
|
|
352
431
|
v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
@@ -354,7 +433,7 @@ def calculate_outward_normals(block:Block):
|
|
|
354
433
|
n_jmax = np.cross(v1,v2)
|
|
355
434
|
|
|
356
435
|
# Normals K direction: KMIN
|
|
357
|
-
x = [X[imax,0,0],X[0,jmax,0],X[0,0,0]]
|
|
436
|
+
x = [X[imax,0,0],X[0,jmax,0],X[0,0,0]]
|
|
358
437
|
y = [Y[imax,0,0],Y[0,jmax,0],Y[0,0,0]]
|
|
359
438
|
z = [Z[imax,0,0],Z[0,jmax,0],Z[0,0,0]]
|
|
360
439
|
v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
@@ -362,7 +441,7 @@ def calculate_outward_normals(block:Block):
|
|
|
362
441
|
n_kmin = np.cross(v1,v2)
|
|
363
442
|
|
|
364
443
|
# Normals K direction: KMAX
|
|
365
|
-
x = [X[imax,0,kmax],X[0,jmax,kmax],X[0,0,kmax]]
|
|
444
|
+
x = [X[imax,0,kmax],X[0,jmax,kmax],X[0,0,kmax]]
|
|
366
445
|
y = [Y[imax,0,kmax],Y[0,jmax,kmax],Y[0,0,kmax]]
|
|
367
446
|
z = [Z[imax,0,kmax],Z[0,jmax,kmax],Z[0,0,kmax]]
|
|
368
447
|
v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
|
|
@@ -372,11 +451,11 @@ def calculate_outward_normals(block:Block):
|
|
|
372
451
|
return n_imin,n_jmin,n_kmin,n_imax,n_jmax,n_kmax
|
|
373
452
|
|
|
374
453
|
def split_blocks(blocks:List[Block],gcd:int=4):
|
|
375
|
-
"""Split blocks
|
|
454
|
+
"""Split blocks into smaller sub-blocks while preserving GCD divisibility.
|
|
376
455
|
|
|
377
456
|
Args:
|
|
378
|
-
blocks (List[]):
|
|
379
|
-
gcd (int
|
|
457
|
+
blocks (List[Block]): Blocks to split.
|
|
458
|
+
gcd (int): Target greatest common divisor for sub-block dimensions.
|
|
380
459
|
"""
|
|
381
460
|
pass
|
|
382
461
|
|