Conversation
…egration on new potential
This flag switched the high-order-contact collision building and potential evaluation to an alternate per-vertex "feasible region" code path replicating the OGC paper's algorithm directly, calling into src/ipc/ogc/feasible_region.hpp. It was never enabled anywhere (no caller set ogc_collisions=true), so this is dead-code removal, not a behavior change for any existing user. src/ipc/ogc/ (the standalone OGC implementation) is untouched -- verified via `git status --short src/ipc/ogc/` (clean) and the full [ogc] test suite still passing (19 cases, 4147 assertions). The [high_order_potential*] suite also passes unchanged (22 cases, 36559 assertions).
Reorders `#include <array>` into the correct IncludeCategories group per .clang-format, as flagged by clang-format --dry-run --Werror. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts: # CMakeLists.txt # src/ipc/barrier/barrier.cpp # src/ipc/barrier/barrier.hpp # src/ipc/config.hpp.in # src/ipc/distance/distance_type.cpp # src/ipc/potentials/potential.cpp # src/ipc/smooth_contact/distance/edge_edge.cpp # src/ipc/smooth_contact/distance/edge_edge.hpp # src/ipc/smooth_contact/distance/point_edge.cpp # src/ipc/smooth_contact/distance/point_edge.hpp # src/ipc/smooth_contact/distance/point_face.cpp # src/ipc/smooth_contact/distance/point_face.hpp # tests/src/tests/barrier/test_barrier.cpp # tests/src/tests/benchmark_eigen.cpp
…gression from the merge - Barrier classes became templates (default T=double) in the ipc-sim/main merge; ClampedLogBarrier/NormalizedClampedLogBarrier call sites in high_order_contact and barrier tests needed <> to keep compiling. - edge_edge_distance_type's EA_EB near-degenerate fallback (normal-vector check + closest-point min) was templated on T but left hardcoded to Eigen::Vector3d; scope it to is_floating_point_v<T> so autodiff/SIMD scalars still compile. - Rename the pre-existing geogram-based test oracle in tests/.../distance_type_reference.hpp (was distance_type_exact.hpp, now shadowed by the new production header of the same name in src/ipc/distance) and give it its own local PARALLEL_THRESHOLD, since production no longer exposes that as a global constant. - edge_edge_distance_type is now unconditionally the thresholded analytic classifier (no more DistanceTypeConfig exact-predicate default), so update two tests whose assumptions predated that: compare against the reference using the same threshold instead of forcing an exact (0) threshold, and accept the edge-interior-vs-vertex classifications that are valid (and distance-preserving) for collinear degenerate edges. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Consistent naming for the two contact formulations:
- ESP (Extremum Sum Potential): src/ipc/esp/, ESP* types, esp_* symbols
- GCP (Geometric Contact Potential): src/ipc/gcp/, GCP* types, gcp_* symbols
Acronyms are capitalized in type names to match the convention already
used in this repo (LBVH, AABB, BVH, IPCWrapper); files, folders and
namespaces stay lowercase, matching src/ipc/ogc/ and namespace ipc::ogc.
Cosmetic only; no functional changes.
Deliberately left untouched:
- The Ferguson2023HighOrderIPC citation and its prose in the docs.
High-Order IPC is a different method from ESP.
- Generic math helpers whose "smooth" is the ordinary mathematical
sense (smooth_heaviside, smooth_clamp*, smooth_mu*, smooth_friction_*),
which are shared with the friction code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follows the high_order_contact -> ESP rename: the arbitrary-point
evaluator is an ESP evaluation at an off-mesh point.
ArbitraryPointPotential -> ArbitraryPointESP
arbitrary_point_potential.{cpp,hpp} -> arbitrary_point_esp.{cpp,hpp}
[arbitrary_point_potential] -> [arbitrary_point_esp]
Also capitalizes the ESP and GCP acronyms in type names (ESPPotential,
ESPParameters, ESPCollisions, GCPPotential, GCPParameters, ...) to match
the convention already used in this repo for LBVH, AABB, BVH and
IPCWrapper. Files, folders and namespaces stay lowercase, matching
src/ipc/ogc/ and namespace ipc::ogc.
Replaces the remaining "HO potential" comments with "ESP potential".
ArbitraryPointBVH is deliberately left alone: it is a general
broad-phase index wrapping ipc::LBVH, not ESP-specific.
Cosmetic only; no functional changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Reformat the files flagged by the clang-format 21 check (the version pinned in .github/workflows/clang-format-check.yml). Most are fallout from the ESP/GCP rename: the longer type names (HighOrderContactPotential -> ESPPotential, Esp* -> ESP*) shifted line lengths past the column limit, and the new include paths re-sort (ipc/gcp/... now precedes ipc/geometry/...). A handful of files under esp/collisions/, math.tpp and gcp/distance/mollifier.tpp were already failing before the rename and are fixed here too, since the rename had already touched them. Formatting only; no functional changes. Verified: full build clean and the [esp_potential]/[gcp_potential]/[arbitrary_point_esp]/[smooth_clamp] suites give byte-identical results (45,241 assertions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # src/ipc/barrier/barrier.cpp # src/ipc/distance/CMakeLists.txt # src/ipc/math/CMakeLists.txt
Three unrelated CI failures on ipc-sim#259: 1. Windows: near/far are macros in windef.h, so MSVC mangled NearFarBarrier's declarations ("error C2059: syntax error: 'const'"). Renamed the two members to near_value/far_value, matching the existing first_derivative_near/far naming. This also broke polyfem's Windows build, which consumes this header. 2. Python (all 3 platforms) and CUDA: the public candidates.hpp included ipc/utils/unordered_map_and_set.hpp, whose own comment documents it as internal because Abseil is a private dependency. The Python bindings include candidates.hpp and do not link Abseil, so they failed with "absl/hash/hash.h: No such file or directory". Moved the nine unordered_map members into a pimpl defined in the .cpp, following the pattern upstream already uses: every other header including that file is a builder/details/internal header unreachable from python/src. The members were only ever used inside candidates.cpp despite being public, so no caller changes. The accessors return {} when the pimpl is null, preserving the previous empty-map behaviour. 3. Windows: geogram 1.9.8's vendored PoissonRecon includes <hash_map>, a pre-standard header removed from current MSVC, and it is compiled unconditionally (no GEOGRAM_WITH_* guard). geogram 1.10.1 drops Hash.h entirely, so bump to it. It no longer pulls predicates.h in transitively via exact_geometry.h, so include it explicitly where PCK::initialize is used. Note IPC_TOOLKIT_WITH_GEOGRAM=OFF is not a viable alternative: it builds, but 4 test cases fail because the *_exact distance-type classifiers fall back to the analytic implementation. Verified locally: [distance-type],[esp_potential],[gcp_potential], [arbitrary_point_esp] pass (39 cases, 4610315 assertions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
readability-braces-around-statements accounted for 136 of the 200 distinct clang-tidy errors on this branch. Applied via clang-tidy --fix (18.1.8, matching the version CI installs). Braces only: verified the token stream of every changed file is unchanged apart from the added braces. Tests unaffected (51 cases, 4623026 assertions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fixes the remaining readability-identifier-naming errors, plus
performance-enum-size, readability-named-parameter and
performance-unnecessary-value-param.
The config sets MemberCase: lower_case and its ignore patterns allow
*leading* underscores ('^(_.*)$'), so trailing-underscore names were
flagged. Upstream's convention for members is a leading m_ prefix
(e.g. CollisionMesh::m_full_rest_positions), so:
mesh_ -> m_mesh (Candidates)
ptr_ / size_ -> m_ptr / m_size (span)
m_A / n_A_rows -> m_a / m_n_a_rows (VertexMatrixView)
use_standard_ -> m_use_standard (DistanceTypeConfig)
_dbar_factor -> dbar_factor_value (public member)
grad_P, P_near -> grad_p, p_near (local struct members)
Trailing-underscore constructor parameters and locals became leading
underscore, matching ParameterIgnoredRegexp/VariableIgnoredRegexp.
Global constants became UPPER_CASE. IntegrationType now has an explicit
std::uint8_t base. Unused override parameters are commented rather than
unnamed, and PointPotential takes ESPParameters by const reference.
span keeps its lowercase name via NOLINTNEXTLINE, since it deliberately
mirrors std::span -- the same escape hatch upstream uses in
default_init_allocator.hpp.
Verified: clang-tidy 18.1.8 (the version CI installs) reports no errors
for the previously failing translation units, and the tests are unchanged
(56 cases, 4623099 assertions).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
test_avx_availability() emitted /arch:AVX2 and /arch:AVX from two independent ifs, so a host detecting both got "/arch:AVX2 /arch:AVX". /arch: is single-valued on MSVC and the last one wins, so every AVX2-capable Windows build was compiled as plain AVX. CI reported this as "SIMD support found: /arch:AVX2;/arch:AVX". This is not only a performance loss. MSVC has no separate FMA flag -- the FMA probe adds -mfma only on the GCC/Clang branch -- so /arch:AVX2 is the only way MSVC enables fused multiply-add. Dropping to /arch:AVX removes FMA, which changes rounding: a*b+c rounds twice instead of once, so results differ from the AVX2 build rather than merely being computed more slowly. Use if/elseif so AVX2 wins when detected, matching the AVX_VERSION selection a few lines above, which already does this. AVX-only hosts still get /arch:AVX and hosts with neither still get no flag. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Brings in the GPU LBVH broad phase (ipc-sim#260), its profiling (ipc-sim#263), a scalable_ccd pin bump (ipc-sim#261), and a docs/output fix (ipc-sim#264). One conflict, in BroadPhase::detect_collision_candidates: upstream documented that the candidates are cleared first, while this branch had added the all_types parameter that ESP contact needs. The merged implementation already contains both -- candidates.clear() and the all_types branch -- so the declaration keeps our signature with upstream's wording, and documents all_types, which had no @PARAM entry before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Each predicate wrapper contained its exact-arithmetic fallback, which kept it from being inlined, so every classification made one out-of-line call per filter (~8-10) plus nested public point-edge calls. - Move the exact fallbacks out of line so the filtered fast path of every predicate inlines into the classifier. - Pass raw coordinate pointers and the dimension as a template parameter. - Check DistanceTypeConfig and initialize geogram's PCK once per classification instead of once per nested point-edge test. - Fix the trace message of the cross_dot_cross_2 fallback. Same filters in the same order; classifications are bitwise identical. Exact classification is 1.5-2x faster on real scenes (e.g., cloth-ball edge-edge 80 -> 52 ns), with no measurable change at the ESP level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocation Per-query allocation (a make_shared per collision, a hash map, a collision dict with its own std::set/std::map, full-stencil gradient and Hessian arrays) was ~30% of the run time of wildmeshing's smooth offset, which evaluates this potential millions of times per run. - Collisions are kept by value in per-thread lists, one per collision type (the types ESPCollisionDict stores), cleared between queries. - The symbolic cancellation is unchanged: same sub-feature reduction, same distance-type classification, same integer-weight merge by typed hash, done by linear search over the few collisions of one type. - Only the query vertex's block of each collision's gradient and Hessian is accumulated, instead of assembling the whole stencil and extracting it. Measured on the previous base (3a76d75, before the rename): value, gradient and Hessian agree with the old code to 3.6e-16 relative (summation order), no NaN/inf, including points 1e-9 delta above shared edges; ~2.4x faster per call; wildmeshing's cube offset run 456 s -> 337 s with a bit-identical output mesh. On this branch: the six [arbitrary_point_esp] tests pass; [esp_potential] fails the same 17 assertions with and without this commit (test data not downloaded here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ESP sums b(distance to each element) with one weight per element. The weights were fixed at the closed-mesh signs (3D: faces +1, edges -1, vertices +1; 2D: edges +1, vertices -1), which are right only for a closed manifold. On an open sheet the potential was exactly 0 beyond a boundary edge, and an edge in no face or a 2D isolated vertex entered as a negative barrier. The weights now follow the counting rule of the ESP supplemental (S2): for every point of the input, the weights of the elements containing it sum to one. They are computed once from the connectivity: - face: 1 - edge: 1 - (faces on it) - vertex: 1 - (edges at it) + (faces at it) This gives: - closed mesh: +1/-1/+1 as before, so results there are unchanged - boundary edge or vertex of an open sheet, end of an open polyline: 0 (S4) - edge in no face: 1; vertex between two such edges: -1 - isolated vertex: 1 - edge shared by k faces, 2D vertex with k edges: 1 - k Elements of weight 0 are skipped. Tests: on an open sheet, an open polyline, a 3D polyline in no face, isolated vertices and a 2D junction, the potential equals the barrier of the distance, and on the sheet its gradient matches finite differences. With the old weights the new test fails 18 assertions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The search-and-replace in the smooth_contact -> gcp rename rewrote
historical release notes ("Rename GCPPotential to GCPPotential") and
turned the Python naming test into a contradiction: it asserted that
GCPPotential both exists and does not exist.
5f301a2 dropped the std:: prefix, relying on ipc::unordered_map being reachable through collision_mesh.hpp. It no longer is, so the Python module failed to compile. Matches upstream again.
ESPCollisions stored its four maps as ipc::unordered_map members and ESPCollisionDict::initialize took one as a parameter, so the public esp_collisions.hpp included utils/unordered_map_and_set.hpp and with it Abseil, a private dependency. tangential_collisions.hpp includes esp_collisions.hpp, so every friction user needed Abseil on its include path; the Python bindings failed to compile. - ESPCollisions holds the maps in ESPCollisions::Maps, behind a unique_ptr and a maps() accessor, as Candidates does with AdjacencySets. Only library code used the maps. - initialize() takes a named ESPCollisionPairMap, the same map type as before, so iteration order and results are unchanged. - Both types are defined in the internal esp/esp_collision_maps.hpp. Also drops an unused map.begin().value() that only compiled with robin_map, a pair map keyed by std::array<int, 3> instead of index_t, and a stray Abseil include in quadrature_potential.cpp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bindings still targeted the old high-order contact API and no longer compiled: they bound a use_adaptive_dhat overload of build(), an operator[] ESPCollisions no longer has, the removed QuadraturePotential class, and an ESPParameters constructor without area_weights. - ESPCollisions.build takes (mesh, vertices, param, broad_phase). - ESPParameters takes area_weights, and its defaults now match C++ (integration_type NORMAL). - ESPPotential takes use_near_far. Add Python tests for the parameter defaults, the gradient against central finite differences, and the Hessian shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The smooth_contact -> gcp rename broke every downstream user of the released names (e.g. polyfem uses SmoothCollisions, SmoothContactParameters and SmoothContactPotential). - C++: [[deprecated]] aliases SmoothContactParameters, SmoothCollisions, SmoothContactPotential, SmoothCollision and SmoothCollisionsBuilder. - Forwarding headers at ipc/smooth_contact/smooth_collisions.hpp and ipc/smooth_contact/smooth_contact_potential.hpp. - Python: SmoothCollision2, SmoothCollisions, SmoothContactParameters and SmoothContactPotential alias the GCP classes. Replace the SmoothPotential naming test with a check of the aliases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove dead and experimental code: - Remove ProfileRegistry. Nothing reads it, and the ESP Hessian locked its global mutex once per quadrature point. - Restore gcp/ to main's content plus the deprecated aliases. The ESP-only distance helpers move to esp/esp_distance.hpp; half_edge_edge_mollifier had no callers. gcp_collisions_builder.cpp matches main again: upstream ipc-sim#188 had already reverted the by-value shared_ptr parameters. - Remove ESP adaptive support (AdaptiveSupport, smooth_clamp and their tests). It stays on the esp-adaptive-support branch. - Delete dead code: pair_distance.{hpp,tpp}, smoothed_offset_potential_linear.h, math/span.hpp (ESPPrimitive gets vertex_id(i)), Math::log_barrier (superseded by ESPParameters::barrier in c02cc43), CollisionMesh::is_watertight() and its edge-face adjacency, whose non-manifold check could never fire, and ESP debug counters and helpers. Fix: - 3D ESP with default parameters (quad_order 1, empty face rule) built neither vertex nor face collisions, keeping only edge-edge contact: the build keyed on quad_order and the potential on face_quad_rule. Both now key on face_quad_rule; quad_order only sets the 2D rule. - Revert the EA_EB parallel-edge fallback in core edge_edge_distance and the srand(0) added to its test. Its absolute 1e-20 threshold made d² 26x too large for perpendicular edges 1e-6 long. ESP keeps the fallback in edge_edge_distance_parallel_safe. - Candidates::build no longer copies the CollisionMesh; the adjacency-set queries take the mesh instead, and clear() resets them. ESPCollisions::build converts its own copy of the candidates instead of const_casting the caller's. - Move ESP friction to esp/esp_tangential_collisions.cpp, and attribute edge-edge mollifier weights through edges_to_faces instead of scanning every face per pair. - Only look up obstacle edges when skip_obstacles is set. - Build: drop the duplicated CUDA block, the tests' Abseil/robin_map links and the Eigen recipe's EIGEN_DONT_VECTORIZE default (define it on ipc_toolkit with or without SIMD instead), and link geogram privately. - Python: nest IntegrationType under ESPParameters and fix the ESP docstrings. Tests: - Restore the two commented-out codim normal-collision tests. - Fix the FV mollification test's cube.obj path; it always skipped. - Add tests for obstacle flags, skip_obstacles, the ESP integration types, BarrierPotential with unsquared distances, and the 3D ESP quadrature default. - Test the exact distance-type classifiers against the reference (renamed *_reference), with 100k samples instead of 1M. - Hide the 15-minute ESP "Expensive" test in every build, and drop the assertion-free "Number of Pairs" test and the benchmark_eigen experiment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Deprecated aliases for SmoothCollisionTemplate and
TangentialPotential::smooth_contact_force{,_jacobian,_jacobian_unit}.
- Fix the warnings in the PR's code: lambdas captured structured
bindings (a C++20 extension), an old-style cast, a switch without a
default, and the assert-only total_p_far.
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
Implementation of the SigAsia paper "Extremum Sum Proximity Potential".
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Built and ran the test suite locally on macOS/arm64.
This branch adds the following tests, all passing locally:
New test files
tests/src/tests/potential/test_esp_potential.cpp(19 cases,[esp_potential])ESP potential in 2D and 3D: convergent-quadrature edge-edge limits under
three barriers, gradient/Hessian finite differences, Hessian PSD-ness,
codimensional collisions, adaptive support, NearFarBarrier decomposition.
tests/src/tests/potential/test_arbitrary_point_esp.cpp(6 cases,[arbitrary_point_esp]) Evaluating the ESP at an arbitrary off-mesh pointin 2D/3D: zero beyond dhat, FD gradient/Hessian, and that
evaluate()agrees with
operator()/gradient()/hessian().tests/src/tests/potential/test_smooth_clamp.cpp(12 cases,[smooth_clamp])smooth_clamp01andsmooth_clamp_simplex: anchorvalues, saturation, monotonicity, C0/C1 continuity at knots, FD-vs-analytic
derivatives, and simplex partition-of-unity.
tests/src/tests/utils/test_vertex_matrix_view.cpp(5 cases,[vertex_matrix_view]) Non-owning two-matrix vertex view: concatenationagainst a naive vstack, aliasing semantics, empty-matrix edge case.
New cases in existing files
test_distance_type.cpp: four randomized tests comparing the analyticdistance-type classifiers against a geogram exact-predicate reference
(new
distance_type_reference.hpp), including the near-parallel edge-edge case.test_force_jacobian.cpp: ESP friction force-Jacobian in 2D and 3D(
[friction-esp]).test_barrier.cpp: log barrier derivatives.Test Configuration:
IPC_TOOLKIT_WITH_GEOGRAM=ON,IPC_TOOLKIT_WITH_CUDA=OFFChecklist