use plot3d::{
read_plot3d_ascii, read_plot3d_binary, verify_periodicity, BinaryFormat, Endian, FaceMatch,
FaceRecord, Float, FloatPrecision, Orientation, OrientationPlane,
};
const VSPT_THETA_RAD: Float = 0.11423973285781065;
const TOL: Float = 2.0e-6;
fn load_vspt_blocks() -> Option<Vec<plot3d::Block>> {
let ascii_path = "/Users/pjuangph/glennht_comparison/mesh/finalmesh-ASCII.xyz";
if std::path::Path::new(ascii_path).exists() {
return Some(read_plot3d_ascii(ascii_path).expect("read finalmesh-ASCII.xyz"));
}
let bin_path = "tests/data/vspt_mesh_scaled.xyz";
if std::path::Path::new(bin_path).exists() {
return Some(
read_plot3d_binary(bin_path, BinaryFormat::Raw, FloatPrecision::F32, Endian::Little)
.expect("read vspt_mesh_scaled.xyz"),
);
}
None
}
fn face_record(block_index: usize, lb: [usize; 3], ub: [usize; 3]) -> FaceRecord {
FaceRecord {
block_index,
il: lb[0],
jl: lb[1],
kl: lb[2],
ih: ub[0],
jh: ub[1],
kh: ub[2],
id: None,
u_physical: None,
v_physical: None,
}
}
fn periodic_face(
b1: (usize, [usize; 3], [usize; 3]),
b2: (usize, [usize; 3], [usize; 3]),
matrix: [[i8; 2]; 2],
) -> FaceMatch {
FaceMatch {
block1: face_record(b1.0, b1.1, b1.2),
block2: face_record(b2.0, b2.1, b2.2),
points: Vec::new(),
orientation: Some(Orientation {
permutation_index: 0,
plane: OrientationPlane::InPlane,
permutation_matrix: Some(matrix),
}),
}
}
#[test]
fn vspt_periodic_faces_verify_via_matrix() {
let Some(blocks) = load_vspt_blocks() else {
eprintln!("skipping: no VSPT mesh available");
return;
};
assert_eq!(blocks.len(), 2, "VSPT mesh has 2 blocks");
let pf = vec![
periodic_face(
(1, [0, 0, 0], [40, 100, 0]),
(1, [0, 0, 52], [40, 100, 52]),
[[1, 0], [0, 1]],
),
periodic_face(
(0, [0, 0, 32], [128, 100, 32]),
(1, [168, 0, 52], [40, 100, 52]),
[[-1, 0], [0, 1]],
),
periodic_face(
(1, [168, 0, 0], [268, 100, 0]),
(1, [168, 0, 52], [268, 100, 52]),
[[1, 0], [0, 1]],
),
];
let (verified, mismatched) = verify_periodicity(&blocks, &pf, VSPT_THETA_RAD, 'x', TOL);
assert_eq!(
mismatched.len(),
0,
"all 3 VSPT periodic_faces must verify at 2e-6; mismatched={}",
mismatched.len()
);
assert_eq!(verified.len(), 3, "expected 3 verified periodic_faces");
let resolved: Vec<u8> = verified
.iter()
.map(|fm| fm.orientation.as_ref().unwrap().permutation_index)
.collect();
assert_eq!(
resolved,
vec![0, 1, 0],
"periodic_faces[1] must resolve to canonical index 1 (u-flip)"
);
let matrices: Vec<[[i8; 2]; 2]> = verified
.iter()
.map(|fm| fm.orientation.as_ref().unwrap().permutation_matrix.unwrap())
.collect();
assert_eq!(matrices[0], [[1, 0], [0, 1]]);
assert_eq!(matrices[1], [[-1, 0], [0, 1]]);
assert_eq!(matrices[2], [[1, 0], [0, 1]]);
}
#[test]
fn vspt_wrong_matrix_does_not_silently_match() {
let Some(blocks) = load_vspt_blocks() else {
eprintln!("skipping: no VSPT mesh available");
return;
};
let bad = vec![periodic_face(
(0, [0, 0, 32], [128, 100, 32]),
(1, [168, 0, 52], [40, 100, 52]),
[[1, 0], [0, 1]], )];
let (verified, mismatched) =
verify_periodicity(&blocks, &bad, VSPT_THETA_RAD, 'x', TOL);
assert_eq!(verified.len(), 0, "wrong matrix must not silently pass");
assert_eq!(mismatched.len(), 1, "wrong matrix must be reported as mismatched");
}