1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! Plot3D utilities for mesh connectivity, periodicity detection, and I/O.
//!
//! The crate deliberately mirrors the structure of the legacy Python tooling. For a walkthrough of
//! the rotational periodicity workflow refer to the integration test
//! `tests/test_rotational_periodicity.rs::rotational_periodicity_test`, which doubles as a usage
//! example in the generated documentation (`cargo doc --open`).
//!
//! # Diagonal Convention (FaceRecord)
//!
//! [`FaceRecord`] uses `il/jl/kl` and `ih/jh/kh` to describe the two diagonal
//! corners of a face on a block. These are **not** guaranteed to satisfy
//! `il <= ih`; the ordering encodes **orientation**. When `il > ih`, the
//! I-axis is reversed on that face relative to the matching face on the
//! other block.
//!
//! This matches the GridPro/GlennHT connectivity convention where
//! `IMIN,JMIN,KMIN → IMAX,JMAX,KMAX` are diagonal corners and reversed
//! indices encode face orientation.
//!
//! Use the normalized accessors `i_lo()/i_hi()` when you need min/max values
//! for range iteration or face reconstruction.
//!
//! # Orientation & Permutation System
//!
//! When two block faces meet at an interface, their parametric (u, v)
//! coordinate systems may be flipped, transposed, or both. The crate
//! encodes all 8 valid orientations as a 3-bit index:
//!
//! ```text
//! permutation_index = u_reversed | (v_reversed << 1) | (swapped << 2)
//! ```
//!
//! The constant [`PERMUTATION_MATRICES`] holds the corresponding 2×2
//! matrices (one per index, 0 through 7). Each matrix transforms face2's
//! parametric coordinates to align with face1's.
//!
//! | Index | Binary | u_rev | v_rev | swap | Matrix | Effect |
//! |:-----:|:------:|:-----:|:-----:|:----:|:------:|:------:|
//! | 0 | `000` | no | no | no | `[[ 1, 0],[ 0, 1]]` | identity |
//! | 1 | `001` | yes | no | no | `[[-1, 0],[ 0, 1]]` | flip u |
//! | 2 | `010` | no | yes | no | `[[ 1, 0],[ 0,-1]]` | flip v |
//! | 3 | `011` | yes | yes | no | `[[-1, 0],[ 0,-1]]` | flip both |
//! | 4 | `100` | no | no | yes | `[[ 0, 1],[ 1, 0]]` | transpose |
//! | 5 | `101` | yes | no | yes | `[[ 0,-1],[ 1, 0]]` | transpose + flip u |
//! | 6 | `110` | no | yes | yes | `[[ 0, 1],[-1, 0]]` | transpose + flip v |
//! | 7 | `111` | yes | yes | yes | `[[ 0,-1],[-1, 0]]` | transpose + both |
//!
//! The `u` and `v` names are abstract parametric axes that map to concrete
//! i/j/k axes depending on which axis is constant on the face:
//!
//! | Constant axis | u (outer loop) | v (inner loop) |
//! |:-------------:|:--------------:|:--------------:|
//! | I-constant | j | k |
//! | J-constant | i | k |
//! | K-constant | i | j |
//!
//! [`Orientation`] stores the index together with an [`OrientationPlane`]
//! tag indicating whether the match is **in-plane** (same constant axis)
//! or **cross-plane** (different constant axes, requiring a swap). The
//! connectivity pipeline populates `FaceMatch::orientation` automatically
//! so downstream code can reconstruct the exact node-to-node mapping
//! without re-sampling block coordinates.
//!
//! # Verification Pipeline
//!
//! After computing connectivity or periodicity, use the verification
//! functions in the [`verification`] module:
//!
//! 1. [`verify_connectivity`] — extracts a canonical 2D grid from each
//! face pair, tries all 8 permutation matrices, and picks the one
//! that aligns nodes point-by-point within tolerance. Sets
//! [`Orientation`] on each verified match.
//!
//! 2. [`verify_periodicity`] — same approach but rotates block1's face
//! by the periodicity angle before comparing grids.
//!
//! 3. [`align_face_orientations`] — for same-dimension in-plane matches,
//! walks all 8 diagonal orientations to find the one where directed
//! I→J→K traversal matches node-by-node.
//!
//! The recommended pipeline (as used by the `connectivity_finder` binary):
//!
//! ```text
//! connectivity_fast → face_matches_to_dict → verify_connectivity
//! → align_face_orientations → rotated_periodicity → verify_periodicity
//! ```
//!
//! # JSON Output Format
//!
//! The [`serialization`] module exports directed `lb`/`ub` corners
//! (raw `il/jl/kl` and `ih/jh/kh` — no ascending sort). After
//! [`face_matches_to_dict`], block1's `lb` physically matches block2's
//! `lb` in xyz space, and `ub` likewise.
//!
//! ```json
//! {
//! "block1": { "block_index": 0, "lb": [0,0,0], "ub": [24,408,0] },
//! "block2": { "block_index": 1, "lb": [408,0,0], "ub": [0,0,24] },
//! "permutation_index": 5
//! }
//! ```
//!
//! The `permutation_index` (0-7) is relative to ascending canonical grids
//! (as computed by [`extract_canonical_grid`]). It is included as metadata;
//! the directed corners already encode the corner-to-corner mapping.
//!
//! [`permutation_matrices_json`] embeds the full 8-matrix array in the
//! JSON output header so consumers can reconstruct orientations without
//! hard-coding the table.
/// Floating-point precision type used throughout the crate.
/// Defaults to `f64`; enable the `f32` Cargo feature for single precision.
pub type Float = f64;
pub type Float = f32;
pub use PI;
/// Pi constant matching the active [`Float`] precision.
pub use PI;
pub
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use point_match;
pub use ;
pub use ;
pub use ;
pub use ;
pub use translational_periodicity;
pub use ;
pub use ;
pub use write_plot3d;
pub use ;
pub use ;