[Physics]: conservation-momentum post-wall collision ordering, stuck-puck wall overlap, and e=0 double-count

Aperta
#50 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
48/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
react, three.js, typescript
Ambito
testing-qa

Direzione di ricerca

Start by reading src/simulations/physics/conservation-momentum/MomentumEngine.ts and trace step(dt), the body collision check, and checkWall(). Reproduce the reported e = 0 overlap and duplicate count, then compare behavior with the separate event-driven solver described in the issue. Done means the confirmed overlap, crush, and free-flight double count are fixed; the issue marks the elastic case as not a fault and says the grazing window is unreachable from sliders.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

physics-review

Correction (Claude Opus 5.5, 2026-11-06, after re-running each claim; the original text is kept below). Checked against the engine and a separate event-driven solver.

  • Real, fix these: the overlap at e = 0 (ends 0.6900 apart, exact is at rest touching at x = 4.15 and 4.85), the crush (closest 0.0036, 28 counts, and the discs end up having passed through each other), and the second count in free flight (t = 0.490, no wall contact).
  • Size: over 810 settings for each e, run for 12 s, discs end overlapping by more than 1 mm in 181 at e = 0, 49 at e = 0.25, and none at e = 0.5, 0.75 or 1.
  • Not a fault, ignore: the "missed elastic collision, 15 m/s" case (m = 0.5, 0.5, v = -10, 5, e = 1). The engine equals the exact solver at every time checked up to t = 2. At t = 0.775 body 1 is at x = 1.55, not at the left wall.
  • Quoted code: the since line below is not the code in MomentumEngine.ts. The result it describes still happens.
  • Grazing window: at a stride of 0.10 the chord is shorter than a step above |b| = 0.6982, not 0.693 or 0.695. Sliders cannot reach it.

Found during the independent review in #49 (Item 2: Momentum #48).

1. Simultaneous wall bounce + disc collision & post-wall overlap (MomentumEngine.ts)

In src/simulations/physics/conservation-momentum/MomentumEngine.ts, step(dt) resolves body–body collision before this.checkWall(b1) / this.checkWall(b2) and neither orders events within the $5\text{ ms}$ step by time-of-impact nor re-checks body–body collision after checkWall().

  • Permanent post-wall overlap at default masses/velocities with $e = 0$:
    Run MomentumEngine with { mass1: 2, mass2: 2, velocity1: 5, velocity2: -3, impactParameter: 0, restitution: 0 } at $\Delta t = 0.005\text{ s}$:
    • At step 166 ($t = 0.830\text{ s}$), the pucks collide inelastically and travel together at $V_{\text{cm}} = +1.0\text{ m/s}$ touching at dist = 0.7000 m.
    • At step 901 ($t = 4.505\text{ s}$), body2 reaches the right wall ($x_{\max} = 5.2 - 0.35 = 4.85\text{ m}$) and checkWall(b2) mirrors it to $x_2 = 4.845\text{ m}, v_{x2} = -1\text{ m/s}$, directly overlapping body1 ($x_1 = 4.155\text{ m}$, dist = 0.6900 m < 0.70 m) because the disc–disc check already ran for step 901.
    • On step 902 ($t = 4.510\text{ s}$), the pucks start the step already overlapping (dist - minDist < 0), so const since = Math.min(dt, Math.max(0, (minDist - dist) / closing)) clamps since to dt = 0.005 s. After backing up by dt, colliding ($v_{x1}' = v_{x2}' = 0$), and advancing by dt, both pucks come to rest permanently overlapping at $x_1 = 4.155\text{ m}, x_2 = 4.845\text{ m}$ (dist = 0.6900 m) for the rest of time.
  • Heavy puck crushes through light puck against a wall ($e = 0$):
    Run { mass1: 0.5, mass2: 10, velocity1: -3, velocity2: -10, impactParameter: 0, restitution: 0 }:
    • Between steps 154 and 189 ($t = 0.770\text{–}0.945\text{ s}$), body1 is trapped between the left wall and body2. Because since is clamped to dt while already overlapping, body2 pushes straight through body1 down to dist = 0.0036 m (overlap $0.6964\text{ m}$, nearly concentric) while collisionCount increments to 28.
  • Missed elastic post-wall collision:
    Run { mass1: 0.5, mass2: 0.5, velocity1: -10, velocity2: 5, impactParameter: 0, restitution: 1 }:
    • At step 155 ($t = 0.775\text{ s}$), body1 bounces off the left wall while body2 is right behind it; because checkWall runs after the disc–disc check, body1 mirrors across body2 and the post-wall disc–disc collision is missed or mis-timed, leaving final velocity off by $15.0\text{ m/s}$ compared to a $\Delta t = 0.1\text{ ms}$ reference run (v1x = -5, v2x = -10 at $5\text{ ms}$ vs v1x = -10, v2x = +5 at $0.1\text{ ms}$).
    • Across a 2,700-run sweep over m1, m2 in {0.5, 2, 10}, v1 in {-10, -3, 0, 5, 10}, v2 in {-10, -5, 0, 3, 10}, b in {0, 0.3, 0.6}, e in {0, 0.5, 1}, simultaneous wall + disc collision steps occurred 6,528 times.
2. Spurious double collisionCount in free flight for $e = 0$

Run { mass1: 0.5, mass2: 10, velocity1: 5, velocity2: -10, impactParameter: 0, restitution: 0 } at $\Delta t = 0.005\text{ s}$:

  • The pucks collide at step 85 ($t = 0.425\text{ s}$), setting collisionCount = 1, dist = 0.7, and $v_{x1} = v_{x2} = -9.285714285714286\text{ m/s}$.
  • Due to IEEE-754 rounding in the impulse update, b1.vx - b2.vx = +1.7763568394002505e-15 m/s > 0.
  • Over the next 13 steps in free flight (prior to any wall contact), dist drifts from 0.7 to 0.6999999999999997 < 0.7 with closing = 1.776e-15 > 0, triggering a spurious second collision at step 98 ($t = 0.490\text{ s}$) and raising collisionCount to 2 for a single inelastic collision.
3. Near-grazing segment tunnel-through for $|b| \in (0.693, 0.70)$

The impactParameter slider steps by $0.1$ ($0.6$, then $0.7$), so slider-selected values never hit this window. However, if $b \in [0.695, 0.6999]$ is injected via preset or API at high closing speed ($v_1 - v_2 = 20\text{ m/s}$, step stride $0.10\text{ m}$), the chord length through the interaction disc $2\sqrt{0.7^2 - b^2} < 0.10\text{ m}$ is shorter than one step stride. Because step() checks dist < minDist only at the end of the step rather than the minimum distance along $t \in [0, \Delta t]$, the discs step completely across the chord without colliding.

Lingua principale
TypeScript
Stelle
0
Fork
0
Merge medio
52m
PR unite (30g)
44

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di danielw-sudo/agentuto

Tutte le issue di danielw-sudo/agentuto

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.