Connectivity

Connectivity detection for multi-block structured (Plot3D) meshes.

The algorithm runs in three phases:

  1. Phase 1 – Candidate pairing: Block pairs whose axis-aligned bounding boxes (AABBs) overlap are identified by candidate_neighbor_pairs(). Only these pairs proceed to expensive point matching.

  2. Phase 2 – Face matching: For each candidate pair, find_matching_blocks() compares every outer face of block i against every outer face of block j. Each comparison (get_face_intersection()) tries three strategies in order:

    • Step 1 (same-size fast path) – if both faces have the same number of points, try all 8 permutations via _try_permutations_with_transpose().

    • Step 2 (sub-region) – for different-size faces, locate the smaller face’s diagonal corners on the larger face to extract a sub-region, then try the same 8 permutations.

    • Step 3 (fallback) – per-point geometric matching for any remaining cases.

  3. Phase 3 – Fresh-face validation: Outer faces left unmatched after Phase 2 (because a partner block’s face pool was consumed by an earlier pair) are re-checked against fresh (un-consumed) outer faces of neighbouring blocks.

Orientation system

When two faces match, the module records how their local (u, v) axes relate. Because each of the two varying axes can independently be reversed and the two axes can be swapped, there are 2 x 2 x 2 = 8 distinct orientations, encoded as 2x2 signed permutation matrices in PERMUTATION_MATRICES.

The index into that array is computed with the bit formula:

index = u_reversed | (v_reversed << 1) | (swapped << 2)

where u_reversed / v_reversed are booleans indicating whether the traversal direction along that axis is flipped between the two faces, and swapped indicates whether the u and v axes of face 1 map to v and u of face 2 (a cross-plane match). Indices 0–3 are the four direct (non-swapped) permutations; indices 4–7 are the four transposed (swapped) permutations.

JSON export convention

The exported permutation_index follows the diagonal (lb/ub) convention:

  • In-plane matches (perm 0–3): permutation_index is -1 because the traversal direction is fully encoded in block2’s lb/ub ordering.

  • Cross-plane matches (perm 4–7): permutation_index is the actual index because lb/ub alone cannot represent an axis swap.

The permutation_matrix field always contains the actual 2x2 matrix.

plot3d.connectivity.PERMUTATION_MATRICES = array([[[ 1,  0],         [ 0,  1]],         [[-1,  0],         [ 0,  1]],         [[ 1,  0],         [ 0, -1]],         [[-1,  0],         [ 0, -1]],         [[ 0,  1],         [ 1,  0]],         [[ 0, -1],         [ 1,  0]],         [[ 0,  1],         [-1,  0]],         [[ 0, -1],         [-1,  0]]], dtype=int8)

8 canonical 2x2 signed permutation matrices.

Bit encoding: index = u_reversed | (v_reversed << 1) | (swapped << 2)

plot3d.connectivity.candidate_neighbor_pairs(blocks: List[Block], tol: float = 1e-06)[source]

Returns candidate block pairs whose AABBs overlap or nearly touch.

This replaces the former centroid-distance approach which only considered the N nearest blocks and could miss neighbours for L-shaped or elongated geometries. AABB overlap is both more robust and more correct.

Parameters:
  • blocks (List[Block]) – list of all your blocks

  • tol (float) – AABB expansion tolerance

Returns:

candidate (i, j) pairs with i < j

Return type:

List[Tuple[int,int]]

plot3d.connectivity.combinations_of_nearest_blocks(blocks: List[Block], nearest_nblocks: int = 4)[source]

Returns the indices of the nearest N blocks based on their centroid.

Deprecated since version Use: candidate_neighbor_pairs() instead for AABB-based pairing.

Parameters:
  • blocks (List[Block]) – list of all your blocks

  • nearest_nblocks (int) – number of nearest blocks to consider

Returns:

combinations of nearest blocks

Return type:

List[Tuple[int,int]]

plot3d.connectivity.connectivity(blocks: List[Block])[source]

Returns a dictionary outlining the connectivity of the blocks along with any exterior surfaces.

Each face match dict includes an orientation sub-dict with:

  • permutation_index: -1 for in-plane matches (direction encoded in lb/ub), or the actual index (4-7) for cross-plane matches.

  • plane: 'in-plane' or 'cross-plane'.

  • permutation_matrix: the actual 2x2 signed permutation matrix.

Parameters:

blocks (List[Block]) – List of all blocks in multi-block plot3d mesh

Returns:

All matching faces formatted as a list of { ‘block1’: {‘block_index’, ‘lb’, ‘ub’} } (List[Dict]): All exterior surfaces formatted as a list of { ‘block_index’, ‘lb’, ‘ub’, ‘id’ }

Return type:

(List[Dict])

plot3d.connectivity.connectivity_fast(blocks: List[Block])[source]

Find connectivity by GCD-reducing blocks first for speed.

Computes the minimum GCD across all block dimensions, reduces all blocks uniformly, runs connectivity(), then scales bounds back up.

Face match dicts follow the diagonal (lb/ub) convention: permutation_index is -1 for in-plane, actual index for cross-plane.

Parameters:

blocks (List[Block]) – List of blocks to find connectivity for.

Returns:

Face matches with orientation info. (List[Dict]): Outer (non-connected) faces.

Return type:

(List[Dict])

plot3d.connectivity.face_matches_to_dict(face1: Face, face2: Face, block1: Block, block2: Block)[source]

Makes sure the diagonal of face 1 match the diagonal of face 2

Parameters:
  • face1 (Face) – Face 1 with block index

  • face2 (Face) – Face 2 with block index

  • block1 (Block) – Block 1

  • block2 (Block) – Block 2

Returns:

dictionary describing the corner matches

Return type:

(dict)

plot3d.connectivity.find_matching_blocks(block1: Block, block2: Block, block1_outer: List[Face], block2_outer: List[Face], tol: float = 1e-06)[source]

Takes two blocks and finds all matching pairs

Parameters:
  • block1 (Block) – Any plot3d Block that is not the same as block2

  • block2 (Block) – Any plot3d Block that is not the same as block1

  • block1_outer (List[Face]) – outer faces for block 1.

  • block2_outer (List[Face]) – Outer faces for block 2

  • tol (float, Optional) – tolerance to use. Defaults to 1E-6

Note

This function was changed to be given an input of outer faces for block 1 and block 2. Outer faces can change and we should use the updated value

Returns:

containing
  • df (pandas.DataFrame): corners of matching pair as block1_corners,block2_corners ([imin,jmin,kmin],[imax,jmax,kmax]), ([imin,jmin,kmin],[imax,jmax,kmax])

  • block1_outer (List[Face]):

  • block2_outer (List[Face]):

Return type:

(tuple)

plot3d.connectivity.get_face_intersection(face1: Face, face2: Face, block1: Block, block2: Block, tol: float = 1e-06)[source]

Get the index of the intersection between two faces located on two different blocks.

Three-step approach:

Step 1 (fast): Same-size faces — try 8 permutations (4 direction + 4 transposed). Step 2 (subregion): Different-size faces — find smaller face’s corners on larger

face to identify subregion, then try 8 permutations on subregion.

Step 3 (fallback): Per-point geometric matching for any remaining cases.

Parameters:
  • face1 (Face) – An exterior face

  • face2 (Face) – An exterior face from a different block

  • block1 (Block) – block containing face1

  • block2 (Block) – block containing face2

  • tol (float) – matching tolerance

Returns:

containing

  • (pandas.DataFrame): dataframe with matches. Columns = i1, j1, k1, i2, j2, k2

  • (List[Face]): any split faces from block 1

  • (List[Face]): any split faces from block 2

Return type:

(Tuple)

plot3d.connectivity.select_multi_dimensional(T: ndarray, dim1: tuple, dim2: tuple, dim3: tuple)[source]
Takes a block (T) and selects X,Y,Z from the block given a face’s dimensions

theres really no good way to do this in python

Parameters:
  • T (np.ndarray) – arbitrary array so say a full matrix containing X

  • dim1 (tuple) – 20,50 this selects X in the i direction from i=20 to 50

  • dim2 (tuple) – 40,60 this selects X in the j direction from j=40 to 60

  • dim3 (tuple) – 10,20 this selects X in the k direction from k=10 to 20

Returns:

returns X or Y or Z given some range of I,J,K

Return type:

np.ndarray