test: add degenerate-triangle limiting-angle and edge-DOF guard tests
Finding-F and Finding-G from doc/reviewer/external-audit-2026-05-30.md
(java-port-audit missing-test items 1 and 2).
Finding-F — Degenerate triangle: limiting angles (item 1)
test_euclidean_functional.cpp:
DegenerateTriangle_LimitingAngles_L{12,23,31}TooLong
— verifies α_opposite = π, other two = 0, valid = false
for all three edge-over-long cases
DegenerateTriangle_GradientPicksUpPiCorner
— end-to-end mesh test: forces effective l12 >> l23+l31 via
lambda0, evaluates gradient, asserts G_v3 = π (not 2π from
a skipped degenerate face) and G_v1=G_v2 = 2π
test_spherical_functional.cpp:
DegenerateTriangle_LimitingAngles_S{12,23,31}TooLong
— same coverage for spherical_angles()
Finding-G — euclidean_hessian edge-DOF guard (item 2)
test_euclidean_hessian.cpp:
EdgeDOFGuard_Throws
— assign_euclidean_all_dof_indices + euclidean_hessian → throw
EdgeDOFGuard_VertexOnlyDoesNotThrow
— vertex-only layout → no throw (regression guard)
275/275 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -214,3 +214,42 @@ TEST(EuclideanHessian, FDCheck_MixedPinnedVertices)
|
||||
EXPECT_TRUE(hessian_check_euclidean(mesh, x, maps))
|
||||
<< "FD Hessian check failed for mixed pinned/variable vertices";
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Edge-DOF guard (Finding-G, java-port-audit item 2)
|
||||
//
|
||||
// euclidean_hessian() (vertex-only cotangent Laplacian) must throw
|
||||
// std::logic_error when any edge DOF is active. Without this guard the
|
||||
// function would silently return a Hessian with zero rows/cols for the
|
||||
// edge DOFs, causing SimplicialLDLT to fail in a hard-to-diagnose way.
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
TEST(EuclideanHessian, EdgeDOFGuard_Throws)
|
||||
{
|
||||
auto mesh = make_tetrahedron();
|
||||
auto maps = setup_euclidean_maps(mesh);
|
||||
compute_euclidean_lambda0_from_mesh(mesh, maps);
|
||||
assign_euclidean_all_dof_indices(mesh, maps); // assigns vertex + edge DOFs
|
||||
|
||||
const int n = euclidean_dimension(mesh, maps);
|
||||
std::vector<double> x(static_cast<std::size_t>(n), 0.0);
|
||||
|
||||
EXPECT_THROW(euclidean_hessian(mesh, x, maps), std::logic_error)
|
||||
<< "euclidean_hessian must throw when edge DOFs are present";
|
||||
}
|
||||
|
||||
TEST(EuclideanHessian, EdgeDOFGuard_VertexOnlyDoesNotThrow)
|
||||
{
|
||||
// Vertex-only layout must NOT trigger the guard.
|
||||
auto mesh = make_tetrahedron();
|
||||
auto maps = setup_euclidean_maps(mesh);
|
||||
compute_euclidean_lambda0_from_mesh(mesh, maps);
|
||||
auto gauge = *mesh.vertices().begin();
|
||||
assign_euclidean_vertex_dof_indices(mesh, maps, gauge);
|
||||
|
||||
const int n = euclidean_dimension(mesh, maps);
|
||||
std::vector<double> x(static_cast<std::size_t>(n), 0.0);
|
||||
|
||||
EXPECT_NO_THROW(euclidean_hessian(mesh, x, maps))
|
||||
<< "euclidean_hessian must not throw for vertex-only DOF layout";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user