fix(s3): implement H3/V5/V6 API changes (gauss_bonnet + serialization)

H3: enforce_gauss_bonnet now returns |deficit| (total absolute correction
    applied) so callers can detect pathological input without a separate
    check_gauss_bonnet call.  Both overloads (raw property-map and Maps
    template) now return double instead of void.  API comment updated.

V5: load_result_xml now implements strict-subset XML rejection instead of
    silently mis-reading reformatted-but-valid XML into zeros.  The
    function documents itself as accepting only the one-element-per-line
    format written by save_result_xml.  Three strict-subset checks added:
     1. <ConformalResult geometry=...> attribute must be on its opening line.
     2. <Solver> required attributes must be on the same line.
     3. <DOFVector> tag '>' must be on the same line as the tag name.
    Non-conforming files throw std::runtime_error immediately.

V6: new helper check_dof_vector_size(x, expected_dofs, context) added to
    serialization.hpp.  Throws std::runtime_error with a clear message when
    the loaded DOF-vector size does not match the mesh's expected DOF count.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tarik Moussa
2026-06-01 01:27:09 +02:00
parent fc234c69b5
commit 833f9e7237
2 changed files with 94 additions and 9 deletions

View File

@@ -44,7 +44,7 @@
// double gauss_bonnet_rhs(mesh) — 2π · χ(M)
// double gauss_bonnet_deficit(mesh, maps) — lhs rhs (0 = satisfied)
// void check_gauss_bonnet(mesh, maps [, tol]) — throws if violated
// void enforce_gauss_bonnet(mesh, maps) — shifts θ_v by uniform Δ
// double enforce_gauss_bonnet(mesh, maps) — shifts θ_v by uniform Δ; returns |deficit|
// (HyperIdealMaps overloads are deleted — see box above)
#include "conformal_mesh.hpp"
@@ -162,11 +162,16 @@ inline void check_gauss_bonnet(const ConformalMesh& mesh,
// After this call, check_gauss_bonnet() will not throw (up to floating-point).
// Modifies ALL vertices' θ_v (no v_idx filtering) — the shift is a property
// of the target angles, independent of which vertices are free DOFs.
//
// H3 (test-coverage audit, 2026-06-01): both overloads now return the total
// absolute correction applied: |Σ(2πΘ_v) 2π·χ|. A large value signals
// that the input angles were far from satisfying GaussBonnet.
/// Distribute the Gauss-Bonnet deficit uniformly across all `Θ_v`:
/// add `δ = (lhs rhs) / V` to every entry so that the identity holds
/// exactly afterwards. Overload for a raw property map.
inline void enforce_gauss_bonnet(
/// Returns `|lhs rhs|` (total absolute correction applied).
inline double enforce_gauss_bonnet(
ConformalMesh& mesh,
ConformalMesh::Property_map<Vertex_index, double>& theta)
{
@@ -177,15 +182,17 @@ inline void enforce_gauss_bonnet(
double delta = (lhs - rhs) / static_cast<double>(mesh.number_of_vertices());
for (auto v : mesh.vertices())
theta[v] += delta;
return std::abs(lhs - rhs);
}
/// Distribute the Gauss-Bonnet deficit uniformly across `maps.theta_v`.
/// Supported for EuclideanMaps and SphericalMaps only.
/// HyperIdealMaps overload is deleted — see header comment for why.
/// Returns `|lhs rhs|` (total absolute correction applied; see raw-map overload).
template <typename Maps>
inline void enforce_gauss_bonnet(ConformalMesh& mesh, Maps& maps)
inline double enforce_gauss_bonnet(ConformalMesh& mesh, Maps& maps)
{
enforce_gauss_bonnet(mesh, maps.theta_v);
return enforce_gauss_bonnet(mesh, maps.theta_v);
}
// enforce_gauss_bonnet for HyperIdealMaps is intentionally DELETED.