Skip to content

Make MATLAB verification suite merge-ready - #217

Merged
KohmeiK merged 4 commits into
mainfrom
codex/verification-tests-merge-ready
Jul 21, 2026
Merged

Make MATLAB verification suite merge-ready#217
KohmeiK merged 4 commits into
mainfrom
codex/verification-tests-merge-ready

Conversation

@KohmeiK

@KohmeiK KohmeiK commented Jul 21, 2026

Copy link
Copy Markdown
Member

Overview

This PR turns the verification-tests work into a merge-ready package: five MATLAB-verified test cases (two teaching-lab mechanisms, a slider-crank with tracer, Stephenson III Ex. 2, Watt I) with ~143k lines of committed generated reference data, a provenance-enforcing generator script, reusable comparison/fixture/suite utilities, a pinned Node 24 CI workflow, and several real production solver fixes that the suite exposed:

  • mechanism.ts: timestep snapshots now deep-copy joints/links/forces with full physical state. Previously timestep-0 links were shared live references and timesteps > 0 got new RealLink(l.id, connectedJoints) with default mass = 1, MoI = 1 and a recomputed geometric-center CoM, so any dynamic analysis past step 0 used wrong mass properties. This is a genuine correctness fix, not just test plumbing.
  • force-solver.ts: removes the spurious parallel-axis term (J + m·d² about the loop's first joint) from the moment equation, which is taken about the CoM. This changes every dynamic force/torque result the app reports.
  • kinematic-solver.ts: fixes identity-based indexOf against per-timestep joint copies (returned −1) by matching on id, and resets previously-leaking static state (inputJointIndex, desiredAngleMap).
  • position-solver.ts: solved slider joints now propagate solve order, so tracer points on a slider's link resolve.
  • joint.ts/unit-enums.ts: breaks the joint→link→joint runtime import cycle with a type-only import, and extracts unit enums so SettingsService avoids the cycle through utils.ts — with a dedicated regression spec for import order.

Verification

  • npm test -- --watch=false — 89 tests passed
  • npm run build
  • git diff --check
  • Regeneration reproduced the committed datasets byte-for-byte
  • Browser smoke: slider animation advanced through precomputed timesteps; a joint force graph rendered without NaNs; welding rendered a two-link compound linkage with the Unweld state enabled

The browser run also reproduced two existing UI defects on unchanged main: the legacy force-example URL crashes Chrome while decoding, and link right-click detection relies on a minified constructor name. Neither is introduced by this PR.

Deliberate scope and gaps

  • Stephenson III Example 1 and OTIS remain deferred.
  • Teaching-case CoM and dynamics are diagnostic-only/not-applicable and are not treated as trusted verification.
  • Static, friction, stress, and slider-reaction validation remain out of scope.
  • Dynamics have independent Newton–Euler and power-consistency checks for Watt I and Stephenson III Example 2, but not a second external dynamics solver.
  • Exact, named toggle-boundary exclusions remain for Watt I and Stephenson III Example 2.

Reference provenance

  • PMKS_Verification: 932951a5316b16bfa41b937b04592c974143c4bb
  • PMKS fork oracle: 644b26c75b07182ce04dc6466cfec74ee4130c93

KohmeiK and others added 3 commits July 21, 2026 15:19
All five fixes were found by comparing the solvers against the MATLAB
reference data in PMKS-Web/PMKS_Verification (tests added separately):

- ForceSolver added a parallel-axis m*d^2 term (d measured from the link
  CoM to an arbitrary loop joint) to the moment-of-inertia while taking
  moments about the CoM, skewing every dynamic force/torque result. The
  inertial term about the CoM is J*alpha alone.
- circleCircleIntersection rejected internally tangent circles, which
  arise whenever a joint is collinear with the two joints it is solved
  from (e.g. a tracer point on a straight ternary link). Positions are
  rounded every timestep, so exact tangency degraded into "no
  intersection" and invalidated the whole mechanism.
- PositionSolver never marked slider-connected joints as known and never
  recursed past them, so a tracer point on the slider's coupler link
  could not be ordered and the mechanism was rejected.
- KinematicsSolver looked up a piston's revolute joint by object identity
  in the per-timestep joint arrays, which hold copies; the index came
  back -1 and slider analysis crashed. It also never reset its cached
  input-joint index, leaking state between mechanisms.
- The joint -> coord -> settings -> utils -> joint import cycle broke
  class initialization when the model modules were entered from a second
  test entry point. The unit enums now live in their own module
  (re-exported from utils.ts) and joint.ts's Link import is type-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Six mechanism configurations from PMKS-Web/PMKS_Verification (four-bar
with tracer points, two crank-sliders, two Stephenson III six-bars, and
a rocking Watt I six-bar with an external load) are rebuilt from the
model classes and every solver output is compared against the MATLAB
reference traces: joint/CoM positions, velocities, accelerations,
angular kinematics, joint reaction forces, slider normal force, and
input torque, across all ~360 one-degree timesteps of each mechanism.

- src/test-data/verification: generated reference series (see README
  for provenance and scripts/generate-verification-data.mjs to
  regenerate).
- src/test-utils/verification: fixture builder (model objects wired the
  way the app wires them, incl. sliders and global-frame link loads), a
  crank-angle row aligner that tolerates the solvers detecting toggle
  points a step apart, and amplitude-relative series comparators.
- src/tests/verification: one spec per mechanism plus structural tests
  (DOF gate, loop coverage, input-speed scaling, URL transcoder
  round-trips). Defects in the MATLAB reference data are excluded
  series-by-series with comments citing the offending MATLAB line;
  PMKS+'s values were hand-verified for each exclusion. A test.fails
  documents the known LoopSolver gap on Stephenson III Example 1.

The old SixbarService spec now resets KinematicsSolver's static caches
before solving, since other spec files share the worker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 21, 2026

Copy link
Copy Markdown

Deploy Preview for pmksprod ready!

Name Link
🔨 Latest commit 0a944d7
🔍 Latest deploy log https://app.netlify.com/projects/pmksprod/deploys/6a5fd62c9d5d140008804367
😎 Deploy Preview https://deploy-preview-217--pmksprod.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@KohmeiK
KohmeiK merged commit 52fd965 into main Jul 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant