Repository navigation
Conversation
…till has problems, could be numerical issues
The continuous overload accepted all_types but never passed it to the broad phase. Only the discrete overload, which ESP uses, needs it. The signature and its Python binding match upstream again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
Fixes: - The ESP TangentialCollisions::build never reset the lagged friction coefficients, which default to 0, so ESP friction was identically zero. It now calls reset_lagged_anisotropic_friction_coefficients() like the other overloads, and the friction test requires a nonzero force. - ESPPotential::hessian returned a 0x0 matrix on a 3D mesh without faces. - ESPCollisions::to_string read the face quadrature point, a virtual vertex, out of bounds. Face collisions now print ids and weights only. Dead code (each removal verified against its callers): - Edge-edge guards for non-EA_EB types and shared vertices, which the builder already filters out, become asserts. The ESP edge-edge distance helpers keep only the EA_EB case. - Zero-weight fallbacks of the near/far normalization, the dbar_factor = 0 edge-edge terms (the edge-edge pairs are skipped there), skips that ee_set/ef_set already guarantee, the obstacle-edge candidate check that was always true, the deep copies of the TBB exemplar and the unused copy assignment of QuadratureCollisionsBuilder, the uninstantiated Edge3P1-Edge3P1 distance and the ESPCollision near/far default bodies (now pure virtual). - The 20-point Gauss-Lobatto rule now uses its table. Tests: ESP friction with edge-edge contact, two cubes and zero stiffness; obstacle integration types with a face rule, in 2D and with dynamic vertex-vertex candidates; dbar_factor = 0; a 3D mesh without faces; 2D Hessian projection; an edge-midpoint face rule; collision accessors and stencils; distance helpers; candidate adjacency sets; and error paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
Rename the ESPParameters constructor parameter dbar_factor_value, which shadowed the member of the same name, to _dbar_factor like the other parameters, and use static_cast in ESPCollisionTemplate::vertex_id. Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
Remove PointPotential::build_collisions_at_face_center and the gradient and Hessian at the face center, with and without the near/far split. Nothing in the library or the Python bindings called them; ESPPotential uses the face-interior-point versions. The test that only checked them against each other goes with them. The two value functions stay: they evaluate the potential at every face quadrature point. Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
evaluate_potential_at_face_center_with_cached_collisions and its _nearfar version evaluate at any face quadrature point, not only the center. They now match the gradient, Hessian and build functions, which already use face_interior_point. Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
fsichetti
marked this pull request as ready for review
October 9, 2026 15:53
The PSD check ran inside "ESP potential 2D finite differences" for every configuration, including the 880-DOF mesh, and pushed that test past the 1500 s CTest limit in the Windows Debug job (it passed in 1115 s before). It now runs on the two small configurations, in under a second. Claude-Session: https://claude.ai/code/session_01R7sJzFKyZAgyK7X4Vs6mXf
2 of 10 tasks
3 of 11 tasks
The test timed out (1500 s) in the Windows Debug job in 4 of the last 5 runs; Linux and macOS Debug take about 850 s. Orders 1 and 14 keep the two extremes (endpoints only, and the densest rule with points near the endpoints); orders 2 and 7 stay covered by the 2D no-forces and Hessian PSD tests. The test takes 59% of its previous time in a local Debug build.
These new tests ran several times over one code path and made the Debug CI jobs three times longer than on main. - ESP potential 2D no forces: quadrature orders 1 and 14, and circles up to 200 vertices. The 2000-vertex circle took 97% of the test. - Convergent Quadrature Gradient and Hessian: dbar_factor 0.3, 1.0 and 2.0. dhat = 0.15 / min(dbar_factor, 1) keeps the edge-edge support at 0.15; dividing by dbar_factor left no collisions at 2.0. - Face Quadrature Gradient and Hessian: drop the interior-degree-2 rule, whose interior points the centroid of vertices+centroid already covers. - Convergent Quadrature Hessian PSD: dbar_factor 0.4 only, since every value in (0, 2] takes the same projection path. - Face Quadrature Hessian PSD: one rule, and dbar_factor 0.4 and 0. Zero is the per-stencil projection branch. - Random distance-type tests: 10,000 samples instead of 100,000. The rarest type (edge-edge vertex-vertex, 2.5%) still appears about 250 times per run.
- Prefix the non-public members of ESPPotential, ArbitraryPointESP, ArbitraryPointBVH, ESPCollisionDict and ESPCollisionTemplate with m_. - Rename the getters ESPParameters::get_quad_rule() to quad_rule() and ESPPotential::get_use_near_far() to use_near_far(). - Make ESPParameters' dbar_factor private behind dbar_factor(). - closest_point_uv() takes ea0, ea1, eb0 and eb1. - Document the ESPPotential and ESPCollisions constructors and maps(). - Remove the unused Vertex2ogc primitive, and the minimum-distance tracker that every collision evaluation updated with an atomic compare-and-swap but nothing read. - Cast the six vertex-count asserts that MSVC flagged as signed/unsigned comparisons (C4389).
- Geogram compiles its sources with -Weverything on clang, which added about 3,000 warnings to the macOS builds. Build it with -w. - Clear the link directory geogram adds from its source and relative build dirs. Under CPM that path does not exist, and the macOS linker warned about it.
- Download the two-file PSM zip through CPM and delete its CGAL example - Rename its namespace to ipc_geogram so it can coexist with a downstream geogram (e.g., PolyFEM), and fail configure if any GEO token survives - Always build the exact predicates: remove IPC_TOOLKIT_WITH_GEOGRAM and the floating-point fallback - Add ExactVector3 to replace geogram's vec3E - List geogram as a required dependency and regenerate the dependency graph Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Update the lobatto_set and lobatto_compute notices to match Burkardt's current MIT-licensed quad_rule release, citing the source - Port the 2014 lobatto_compute convergence check - Credit quad_rule in the dependencies docs
- Move sphere.obj and wrapped_sphere.obj to ipc-toolkit-tests-data and bump its GIT_TAG - Fail the test when a mesh cannot be read instead of crashing on an empty mesh
- Emit a compiler warning when including the smooth_contact forwarding headers - Raise a DeprecationWarning for the old Smooth* names in Python through a module-level __getattr__ Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Define GEO_STATIC_LIBS so the header stops emitting dllimport - Remove trailing whitespace flagged by clang-format
- Apply the skip to the IMPROVED_MAX_APPROX corrections, vertex-vertex candidates, and plane-vertex pairs so net weights stay non-negative - Weight edge-edge and vertex-vertex pairs with one obstacle by the non-obstacle primitive's area only, instead of halving the sum Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Record the quadrature rule in ESPCollisions at build time; ESPPotential and the ESP friction build throw on a mismatch instead of reading out of bounds - Reject non-positive or non-finite dhat and negative quad_order in ESPParameters, and quad_order < 1 in 2D builds - Reject non-positive or non-finite InversePowerBarrier powers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Skip the codim. passes when all_types is set in 3D, since they replaced the whole-mesh vertex-vertex and edge-vertex candidates - Record all_types in Candidates::has_all_types - Throw when ESP gets 3D candidates without all types, or IPC gets them with all types Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds the Extremum Sum Proximity Potential (ESP) as a new
ipc/esp/module, with supporting changes to barriers, candidates, collision meshes, friction and distance-type classification; also renamessmooth_contacttogcpwith appropriate compatibility aliases.Mechanism
ESPParameters:dhat, the near/far split parameterdbar_factorin [0, 2], the barrier (defaultNormalizedClampedLogBarrier), the 2Dquad_order, an optional 3D face quadrature rule,area_weightsandintegration_type.ESPCollisions: builds the quadrature collision set from broad-phase candidates.ESPPotential: value, gradient and Hessian, with PSD projection.use_near_far = true(the default), the 3D quadrature weights are normalized to sum to 1, split into near and far parts (NearFarBarrier) whendbar_factor > 0.ArbitraryPointESP<dim>: value, gradient and Hessian of the potential at an arbitrary point, with inclusion-exclusion weights for open and codimensional input.TangentialCollisions::buildoverload that takesESPCollisions; the existingFrictionPotentialconsumes the result.point_edge_distance_type_exact,point_triangle_distance_type_exact,edge_edge_distance_type_exact) built on three shared sign predicates, so their classifications agree.Impact
smooth_contact→gcprename removes most old header paths (see below).ESPParameters(without the barrier and face-rule settings),ESPCollisions,ESPPotential, theGCP*names andCandidates.build(..., all_types=False); the rest of the new API is C++ only.API changes
New public types outside
ipc/esp/InversePowerBarrier(p): b(d) = h(d) / d^p, where h is a cubic B-spline that vanishes atdhat.NearFarBarrier(base, alpha): splits a barrier into a near and a far part, with a smooth step betweenalpha * dhat / 2andalpha * dhat.DistanceTypeConfig, the*_distance_type_exactfunctions andis_parallel_edge_edge.Additions to existing classes
Candidates::build(..., all_types = false)andBroadPhase::detect_collision_candidates(..., all_types = false): in 3D,all_typesalso collects vertex-vertex, edge-vertex, edge-face and face-face candidates, for ESP only.Candidates: newef_candidates,ff_candidatesand adjacency sets (convert_candidates_to_sets(),vv_set()…ff_set()).CollisionMesh: a constructor overload with anobstacle_vertexmask;is_obstacle_vertex/edge/face();face_areas().NormalCollisions::set_skip_obstacles(bool), defaultfalse.BarrierPotential(..., use_squared_distance = true):falseevaluates the barrier on the unsquared distance, whereforce_magnitude()throws.CollisionStencil::name().💥 Breaking changes
ipc/smooth_contact/is renamed toipc/gcp/, and its classes toGCP*.SmoothCollision,SmoothCollisionTemplate,SmoothCollisions,SmoothCollisionsBuilder,SmoothContactParameters,SmoothContactPotential.TangentialPotential::smooth_contact_force*is renamed togcp_force*, with deprecated forwarders.smooth_contact/smooth_collisions.hppandsmooth_contact/smooth_contact_potential.hppremain, as forwarding headers; the other 15 old headers (and two.tppfiles) are gone.TangentialCollision::smooth_collisionis renamed togcp_collision, without an alias.Candidates::buildorBroadPhase::detect_collision_candidateswith the old parameter list (e.g.py::overload_cast) must add thebool.Known limitations
gcp_force_jacobian, always area-weights, and ignores theInversePowerBarrierpower thatESPPotentialapplies to edge-edge weights.integration_typehas no effect there.New dependencies
IPC_TOOLKIT_WITH_GEOGRAM(defaultON).PRIVATEand used only indistance_type_exact.cpp; no public header includes it.ipctkmodule there needlibgeogramat run time.tbb, and OpenMP when built with GCC.libgeogram; no PR check builds a wheel.OFF, the classifiers use floating-point predicates and log a warning once; no CI job builds this configuration.Other changes
FindSIMD.cmakeno longer emits both/arch:AVX2and/arch:AVX.Type of change
How Has This Been Tested?
New test files
test_esp_potential.cpp(30 cases, one hidden): FD derivatives, PSD projection, zero potential on closed meshes, bounded edge-edge terms near edge endpoints, and continuity indbar_factor.test_arbitrary_point_esp.cpp(8 cases): zero beyonddhat, FD derivatives, and inclusion-exclusion weights on open input.test_obstacles.cpp(5 cases): obstacle flags, obstacle skipping inNormalCollisions, and ESP integration types.test_vertex_matrix_view.cpp(5 cases).New cases in existing files
test_distance_type.cpp(+6): four random tests (10,000 samples each, geogram builds only) compare the classifiers with an exact geogram reference; two check mutual consistency and theuse_standardfallback.test_force_jacobian.cpp(+4): ESP friction force against −∇D and friction Hessian against finite differences, in 2D and 3D.test_candidates.cpp(+1, adjacency sets),test_barrier_potential.cpp(+1, unsquared distance),test_barrier.cpp(InversePowerBarriersections).TestESPPotentialandTestGCPAliases.Reproduce
cmake --preset=test && cmake --build --preset=test -j 8 && cd build/test && ctestpip install . && pytest python/tests/test_potentials.pyCI on
03c39d2Test Configuration:
IPC_TOOLKIT_WITH_GEOGRAM=ON,IPC_TOOLKIT_WITH_CUDA=OFFChecklist