Skip to content

Multisize Ball-Ball Collision#290

Open
derek-mcblane wants to merge 4 commits into
ekiefl:mainfrom
derek-mcblane:multi-size-ball-ball
Open

Multisize Ball-Ball Collision#290
derek-mcblane wants to merge 4 commits into
ekiefl:mainfrom
derek-mcblane:multi-size-ball-ball

Conversation

@derek-mcblane
Copy link
Copy Markdown
Collaborator

@derek-mcblane derek-mcblane commented May 9, 2026

Update ball_ball/frictional_inelastic to support collisions between balls of different sizes.

I checked the A-14 and A-27 plots before and after this change (See my other #258). They appear slightly different, which is pretty annoying. It might be floating point error, but I'm surprised it's noticeable at all on the plots.

TODO:

  • verify normal velocity equivalence
  • verify tangent velocity equivalence
  • verify angular velocity equivalence
  • update rotation for collision normal out of XY-plane
  • update frictionless elastic model, too
  • check if writing normal velocities in final form instead of delta form improves similarity to old results
    I'm stumped by this one. I still see slightly different results in the plots compared to the original. I'm convinced that when m1 == m2 and R1 == R2, the result should be equivalent to the original.
    I also see that with the new version, I get equivalent results whether I use:
    • quaternion 3D rotation or rotation around Z-axis (with R1 == R2 so normal is in XY-plane)
    • final normal velocity or delta normal velocity
  • look into collision detection for unequal radii
    I have the math worked out for doing this in 3D with different radii balls. It's not a big change. Going to hold off until we have a plan for the 3d branch.

Summary by CodeRabbit

  • Bug Fixes

    • Improved collision physics calculations to correctly handle balls with different sizes and masses, resulting in more realistic ball interactions and friction behavior during collisions.
  • Documentation

    • Updated model documentation for clarity.

Review Change Stack

@derek-mcblane derek-mcblane requested a review from ekiefl as a code owner May 9, 2026 05:18
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae9efb4e-ff79-4c96-bd19-4c64412d80b8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The collision resolver for FrictionalInelastic is generalized to accept individual mass and radius parameters for each ball, replacing equal-mass/equal-radius assumptions. Normal impulse calculations use mass-ratio-based formulations, and tangential resolution paths (slip and no-slip) apply radius-dependent angular velocity updates. The public solve method interface remains unchanged; only the internal resolver is parameterized.

Changes

Parameterized Frictional Inelastic Collision Generalization

Layer / File(s) Summary
Function Signature and Documentation
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py
_resolve_ball_ball signature updated to accept separate masses (m1, m2) and radii (R1, R2). Class docstring generalized to remove equal-mass-specific wording.
Normal Impulse Calculation
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py
Post-collision normal velocities computed using mass-ratio-based impulse deltas instead of symmetric averaging.
Slip-Condition Tangential Resolution
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py
Surface velocities calculated with per-ball radii; tangential and angular velocity deltas derived from normal impulse magnitude with R1/R2-dependent updates.
No-Slip Fallback Resolution
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py
Simplified tangential/rotational update applied directly from relative surface-velocity vector, with mass-ratio and radius-dependent angular changes.
Method Integration
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py
solve method passes each ball's mass and radius explicitly to _resolve_ball_ball.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Multisize Ball-Ball Collision' directly and clearly summarizes the main change—enabling ball-ball collision resolution to support different ball sizes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 9, 2026

Codecov Report

❌ Patch coverage is 61.40351% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.51%. Comparing base (b2ce363) to head (32ae316).

Files with missing lines Patch % Lines
...resolve/ball_ball/frictional_inelastic/__init__.py 37.14% 22 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #290      +/-   ##
==========================================
+ Coverage   46.36%   46.51%   +0.15%     
==========================================
  Files         144      144              
  Lines       10314    10332      +18     
==========================================
+ Hits         4782     4806      +24     
+ Misses       5532     5526       -6     
Flag Coverage Δ
service 46.51% <61.40%> (+0.15%) ⬆️
service-no-ani 56.73% <61.40%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@derek-mcblane derek-mcblane force-pushed the multi-size-ball-ball branch from b306054 to dfd7115 Compare May 9, 2026 05:22
@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

Fixed review comments from old PR (#289 (review))

@ekiefl
Copy link
Copy Markdown
Owner

ekiefl commented May 9, 2026

Thanks @derek-mcblane, I'm going to review it today.

@ekiefl
Copy link
Copy Markdown
Owner

ekiefl commented May 9, 2026

@ekiefl
Copy link
Copy Markdown
Owner

ekiefl commented May 9, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 9, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

To be thorough, I should check that the math works out to be the same when the masses and radii are equal. I should also spot check the simulator visualization.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py (1)

29-89: ⚡ Quick win

Add an automated unequal-ball regression test.

This block now owns all of the asymmetric impulse math, but the PR notes that the A-14/A-27 plots already moved slightly and the current validation was manual. A small test for one m1 != m2 / R1 != R2 case that checks key invariants here—e.g. linear momentum conservation and the expected slip/no-slip contact-velocity behavior—would make future sign or radius regressions much easier to catch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py` around
lines 29 - 89, Add a small automated unit test that constructs an unequal-ball
collision (set m1 != m2 and R1 != R2), builds representative rvw1/rvw2 input
arrays, calls the collision routine in this frictional_inelastic module to get
rvw1_f and rvw2_f, and then verifies (1) linear momentum conservation by
checking m1*rvw1[1] + m2*rvw2[1] ≈ m1*rvw1_f[1] + m2*rvw2_f[1], and (2) the
slip/no-slip behavior by computing pre/post contact velocities with
ptmath.surface_velocity and asserting either that relative contact velocity
magnitude reduced to zero for no-slip or that the slip-case sign/direction
matches the expected D_v?_t logic; choose a single concrete unequal-case that
previously showed drift and add it as a regression test (use small tolerances
and reference m1, m2, R1, R2, rvw1_f, rvw2_f, and ptmath.surface_velocity in the
assertions).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py`:
- Around line 29-89: Add a small automated unit test that constructs an
unequal-ball collision (set m1 != m2 and R1 != R2), builds representative
rvw1/rvw2 input arrays, calls the collision routine in this frictional_inelastic
module to get rvw1_f and rvw2_f, and then verifies (1) linear momentum
conservation by checking m1*rvw1[1] + m2*rvw2[1] ≈ m1*rvw1_f[1] + m2*rvw2_f[1],
and (2) the slip/no-slip behavior by computing pre/post contact velocities with
ptmath.surface_velocity and asserting either that relative contact velocity
magnitude reduced to zero for no-slip or that the slip-case sign/direction
matches the expected D_v?_t logic; choose a single concrete unequal-case that
previously showed drift and add it as a regression test (use small tolerances
and reference m1, m2, R1, R2, rvw1_f, rvw2_f, and ptmath.surface_velocity in the
assertions).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 41e2f52a-ead8-4c77-a304-52a4d0173f82

📥 Commits

Reviewing files that changed from the base of the PR and between 91b4bd7 and dfd7115.

📒 Files selected for processing (1)
  • pooltool/physics/resolve/ball_ball/frictional_inelastic/__init__.py

@ekiefl
Copy link
Copy Markdown
Owner

ekiefl commented May 9, 2026

This is a welcome change, especially if you can establish equivalence to the r1=r2 & m1=m2 behavior.

As I'm sure you've also reasoned, a full integration of unequal ball radii would involve at minimum updating ball-ball collision detection logic to account for differing radii. And ideally, the other ball-ball models would also have to account for different radii/mass -- although that could simply be a caveat of those models (they assume equal mass and radii, use at your own risk). That would be a reasonable concession.

With what little time I'm finding recently, I'm personally prioritizing shipping 3D trajectories. This kind of matches the order of operations (as I see it), since unequal ball radii break the 2D plane assumption and can lead to some interesting effects in 3D.

@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

derek-mcblane commented May 10, 2026

This is a welcome change, especially if you can establish equivalence to the r1=r2 & m1=m2 behavior.

I just quickly checked normal velocity, I'll do the others when I get a chance.

As I'm sure you've also reasoned, a full integration of unequal ball radii would involve at minimum updating ball-ball collision detection logic to account for differing radii.

I can take a quick look at what this would require. If it's simple enough, I can take a shot at it. In my own simulator, I do have 3D collision prediction working, and I imagine it's just something like substituting 2R for R_a + R_b somewhere.

And ideally, the other ball-ball models would also have to account for different radii/mass -- although that could simply be a caveat of those models (they assume equal mass and radii, use at your own risk). That would be a reasonable concession.

The other models are:

  • FrictionlessElastic
  • FrictionalMathavan

I think the frictionless model would be very easy to update. It should be identical to the slip case from this model, but with e = 1, and mu = 0.

I'm not really interested in updating the Mathavan model. I think it's feasible to update it to allow for different mass/radii, though. I think, at least for now, it should just be a requirement of the model that the balls are the same size and mass.

With what little time I'm finding recently, I'm personally prioritizing shipping 3D trajectories. This kind of matches the order of operations (as I see it), since unequal ball radii break the 2D plane assumption and can lead to some interesting effects in 3D.

I don't think it really matters whether you add unequal radii or 3D first. Even though unequal radii can cause an airborne state, I think it's reasonable to just discard that z component like we do now. It's certainly another reason to motivate 3D trajectories, though!

@derek-mcblane derek-mcblane marked this pull request as draft May 10, 2026 22:59
@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

derek-mcblane commented May 10, 2026

I just realized this isn't quite valid.

For each ball's velocity and angular velocity, I rotate the x-axis around the z-axis to align it with the line of centers between the balls. This is basically a 2D rotation. Then I assume the contact normal direction is the x-axis, and the tangent direction is in the yz-plane.

Now that the contact normal can be out of the xy-plane, these assumptions are no longer valid.

The two ways to deal with it are:

  1. decompose the velocity and angular velocity vectors each into normal and tangent vectors.
  2. property rotate the vectors in 3D (I suggest quaternions for this) so that the x-axis is aligned with the contact normal direction.

I think I'll go w/ 2. to be consistent w/ what I did in the ball-cushion collision model.

@derek-mcblane derek-mcblane marked this pull request as ready for review May 11, 2026 00:59
@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

derek-mcblane commented May 11, 2026

I just realized this isn't quite valid.

For each ball's velocity and angular velocity, I rotate the x-axis around the z-axis to align it with the line of centers between the balls. This is basically a 2D rotation. Then I assume the contact normal direction is the x-axis, and the tangent direction is in the yz-plane.

Now that the contact normal can be out of the xy-plane, these assumptions are no longer valid.

The two ways to deal with it are:

  1. decompose the velocity and angular velocity vectors each into normal and tangent vectors.
  2. property rotate the vectors in 3D (I suggest quaternions for this) so that the x-axis is aligned with the contact normal direction.

I think I'll go w/ 2. to be consistent w/ what I did in the ball-cushion collision model.

This is taken care of now. This has the benefit of making support for 3D as simple as not zeroing the velocity z components, here and here

@ekiefl
Copy link
Copy Markdown
Owner

ekiefl commented May 13, 2026

Looks like you've ironed everything else. I wasn't quite clear from your activity whether you established the m1=m2 and r1=r2 equivalence you were hoping to. Are there still discrepancies? And if so, how severe?

@derek-mcblane
Copy link
Copy Markdown
Collaborator Author

Looks like you've ironed everything else. I wasn't quite clear from your activity whether you established the m1=m2 and r1=r2 equivalence you were hoping to. Are there still discrepancies? And if so, how severe?

I'm convinced mathematically it's equivalent. But I still get a different result and I don't know why.

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.

2 participants