FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
0006 — Point-versus-disk face contact: the disk's rotational Jacobian has the wrong sign
ID 0006
Class BUG
Severity 2
Severity note 3 if the owner confirms that a sphere-versus-chamfer face contact occurs in a shipped model. Not rated 3 now, because no such contact has been shown to be reachable
Status blocked
Models — (internal to GeometryTools/CollisionManager; annotated on the fhsim_coribo library group)
Found 2026-09-24 issue-resolution pass at 6921106, by the finite-difference test added for CORIBO-0002
Decision needed Model owner: approve flipping the sign. It changes contact forces and moments for sphere-versus-chamfer face contacts, and so changes results of any model that has such contacts

Evidence

src/Utilities/GeometryTools.cpp:461, in Distance(MinDistanceInfo&, Point&, Disk&), is the branch where the point projects inside the disk radius (face contact):

result.JacobianB.segment<3>(3) = planeR.cross(result.u);

Derivation: in this branch, minDistance is |P.N| with P = point.P - disk.P. Rotating the disk by a small rotation vector w about its centre gives dN = w x N. The change in distance is then sign(P.N) P.(w x N) = w.(u x P) = w.(u x planeR), because u is parallel to N. The correct entry is therefore u x planeR = -planeR x u. The code uses +planeR x u.

The sibling branches use the correct sign:

  • the rim branch of the same function (GeometryTools.cpp:446): -R.cross(u)
  • Distance(Segment&, Disk&) for both rim and face (GeometryTools.cpp:718): u.cross(R). The SegmentDisk and SegmentDiskFace tests pass on this overload at 1e-6.

The same wrong value also enters minDistance_dot (GeometryTools.cpp:463). The swapped overload Distance(Disk&, Point&) (GeometryTools.cpp:763-773) inherits the error.

Test: tests/GeometryTools-Jacobian_Test.cpp, DISABLED_PointDiskFace and DISABLED_DiskPointFace. Run them with --gtest_also_run_disabled_tests. They fail on exactly the three rotation entries, which have equal magnitude and opposite sign. Example: analytic -0.5075 0.0390 0.0976, finite difference 0.5075 -0.0390 -0.0976. The three translation entries agree to 1e-10.

Effect

CollisionManager uses this overload for SPHERE-versus-CHAMFER and CHAMFER-versus-SPHERE pairs (src/ConstraintSet/CollisionManager.cpp:32,58). In face contact the constraint therefore applies the contact moment on the disk body in the wrong rotational direction. The winch flanges are chamfers (src/Structures/Winch.cpp:49-51). I have not established whether WinchableCable ever creates sphere-versus-flange pairs; its cable elements collide as capsules, which use the correct Segment/Disk overload.

Why this was not fixed

The code change is one character. It changes the constraint forces, and so the numerical results of every simulation with a sphere-versus-chamfer face contact. The owner must review changes of that kind before they are made.

Possible fix

Change line 461 to result.JacobianB.segment<3>(3) = result.u.cross(planeR);. Remove the DISABLED_ prefix from both tests, and check that they pass.

Test that would prove it

DISABLED_PointDiskFace and DISABLED_DiskPointFace, enabled.

Risk

The results of models with sphere-versus-chamfer face contact change. The change moves them towards the correct derivative.