Colliding balls in a 2D box

In summary, the problem is to find the position of two identical balls on a 2D box (billiard table) after 10 seconds, taking into account their deceleration rate of 5 m/s^2. The balls may collide during this time.
  • #1
Arman777
Insights Author
Gold Member
2,168
192
We have a 2D box (billiard table) which have size of Width = 600 and Height = 300. We have two identical ball a radius of 20. Also the balls decelerate with a rate of 5 m/s^2. The problem is to find the position of the ball after 10 second. ( The balls may have collide)
Python:
    from math import sqrt, atan, sin, cos, pi, inf
    from numpy import array

    W = 600  # width of the table
    H = 300  # height of the table
    radius = 20  # the radius of the ball
    A = 5  # deceleration constant
    dt = 0.1
    ma = mb = 1

    def collision_test(Xa, Ya, Xb, Yb):
        if sqrt((Yb - Ya) ** 2 + (Xb - Xa)**2) <= 2 * radius:
            return True

    def dot_product(V1, V2):
        return sum(V1 * V2)

    def vec_magnitude(V1):
        return sqrt(V1[0]**2 + V1[1]**2)

    def after_collision_velocity(Va, Vb, Ra, Rb):
        Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /  ((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
        Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /  ((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
        return Va_new, Vb_new

    def check_reflection(R, angle):
        if R[1] < radius:
            R[1] += 2 * (radius - R[1])
            angle *= -1
            R = array([R[0], R[1]])
            return R, angle
        if R[0] < radius:
            R[0] += 2 * (radius - R[0])
            angle = pi - angle
            R = array([R[0], R[1]])
            return R, angle
        if R[1] > H - radius:
            R[1] += 2 * (H - radius - R[1])
            angle *= -1
            R = array([R[0], R[1]])
            return R, angle
        if R[0] > W - radius:
            R[0] += 2 * (W - radius - R[0])
            angle = pi - angle
            R = array([R[0], R[1]])
            return R, angle
        else:
            return R, angle    def motion(V, R, angle):
        V_mag = vec_magnitude(V)
        V_mag -= A * dt
        Vx = V_mag * cos(angle)
        Vy = V_mag * sin(angle)
        R[0] += Vx * dt
        R[1] += Vy * dt
        V = array([Vx, Vy])
        R = array([R[0], R[1]])
        return V, R    for line in open("test1.txt", "r"):
        t = 0
        Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
        Ra = array([Xa, Ya])
        Rb = array([Xb, Yb])
        Va = array([Vxa, Vya])
        Vb = array([Vxb, Vyb])
        angle_a = atan(Vya / Vxa)
        angle_b = atan(Vyb / Vxb)
        while t < 10:
            Va, Ra =  motion(Va, Ra, angle_a)
            Vb, Rb = motion(Vb, Rb, angle_b)
            Ra, angle_a = check_reflection(Ra, angle_a)
            Rb, angle_b = check_reflection(Rb, angle_b)
            if collision_test(Xa, Ya, Xb, Yb) == True:
                Va, Vb = after_collision_velocity(Va, Vb, Ra, Rb)
                angle_a = atan(Va[1] / Va[0])
                angle_b = atan(Vb[1] / Vb[0])
            t += dt
        print(Ra[0], Ra[1], Rb[0], Rb[1])
In file the data is `235 124 365 176 181 34 -34 -14` and answer should be approximately `399 104 106 62` but I get `480 147 426 169` I guess there's a logic problem somewhere.Debug data for dt = 0.1
Code:
  0.1: 253 127 362 175
    0.2: 271 131 358 173
    0.3: 289 134 355 172
    0.4: 307 138 352 171
    0.5: 323 139 350 171
    0.6: 329 129 359 183
    0.7: 335 120 368 194
    0.8: 340 110 377 206
    0.9: 346 101 385 218
    1.0: 352 91 394 229
    1.1: 358 82 403 241
    1.2: 363 73 411 252
    1.3: 369 63 420 263
    1.4: 375 54 429 275
    1.5: 380 45 437 274
    1.6: 386 35 446 263
    1.7: 391 26 454 251
    1.8: 397 23 463 240
    1.9: 402 32 471 229
    2.0: 408 41 479 218
    2.1: 413 50 488 207
    2.2: 419 59 496 196
    2.3: 424 68 505 185
    2.4: 429 76 513 174
    2.5: 435 85 521 163
    2.6: 440 94 529 152
    2.7: 445 103 537 141
    2.8: 451 111 546 131
    2.9: 456 120 554 120
    3.0: 461 129 562 109
    3.1: 466 137 570 98
    3.2: 471 146 578 88
    3.3: 477 154 574 77
    3.4: 482 163 566 67
    3.5: 487 171 558 56
    3.6: 492 179 550 46
    3.7: 497 188 542 35
    3.8: 502 196 535 25
    3.9: 507 204 527 26
    4.0: 512 212 519 36
    4.1: 517 220 511 46
    4.2: 522 228 503 56
    4.3: 526 236 496 67
    4.4: 531 244 488 77
    4.5: 536 252 480 87
    4.6: 541 260 473 97
    4.7: 546 268 465 107
    4.8: 550 276 458 117
    4.9: 555 276 450 127
    5.0: 560 268 443 137
    5.1: 564 261 435 147
    5.2: 569 253 428 156
    5.3: 574 245 420 166
    5.4: 578 238 413 176
    5.5: 577 230 406 186
    5.6: 573 223 398 195
    5.7: 568 215 391 205
    5.8: 564 208 384 215
    5.9: 559 201 377 224
    6.0: 555 193 369 234
    6.1: 550 186 362 243
    6.2: 546 179 355 253
    6.3: 542 172 348 262
    6.4: 537 165 341 271
    6.5: 533 158 334 279
    6.6: 529 150 327 270
    6.7: 524 143 320 261
    6.8: 520 136 313 252
    6.9: 516 130 306 243
    7.0: 512 123 299 233
    7.1: 508 116 292 224
    7.2: 504 109 285 215
    7.3: 499 102 279 206
    7.4: 495 96 272 197
    7.5: 491 89 265 188
    7.6: 487 82 258 180
    7.7: 483 76 252 171
    7.8: 479 69 245 162
    7.9: 475 63 238 153
    8.0: 472 56 232 144
    8.1: 468 50 225 136
    8.2: 464 43 219 127
    8.3: 460 37 212 119
    8.4: 456 31 206 110
    8.5: 452 25 199 101
    8.6: 449 22 193 93
    8.7: 445 28 187 85
    8.8: 441 34 180 76
    8.9: 437 40 174 68
    9.0: 434 46 168 59
    9.1: 430 52 161 51
    9.2: 427 58 155 43
    9.3: 423 64 149 35
    9.4: 419 70 143 27
    9.5: 416 75 137 22
    9.6: 412 81 131 30
    9.7: 409 87 125 38
    9.8: 406 93 118 46
    9.9: 402 98 112 54
    10.0: 399 104 106 62
 

Attachments

  • my_result.png
    my_result.png
    6.3 KB · Views: 252
  • actual_data.png
    actual_data.png
    8.9 KB · Views: 258
Last edited:
Technology news on Phys.org
  • #2
The two pictures look wildly different. They don't have the same starting point checking either end of either track. In the original it looks like the orange ball starts at about 110,60 and the blueball at 400,100

Why not start the balls in the same place and then watch how their tracks differ from the original graph?

It could be as simple are not considering the balls radius when they collide ie using the collision point as the center of mass for one or both balls.
 
  • #3
I remember that I put the same initial values but maybe in the drawing part there could have be some mistake.
jedishrfu said:
It could be as simple are not considering the balls radius when they collide ie using the collision point as the center of mass for one or both balls.

I dod not understand this part ...
 
  • #4
When the balls collide its at their collision pt right? This point is not the position of either ball.

If I have two balls colliding on a one-dimensional number line at 10 and each ball has a 1 unit radius then ball 1 is located at 9 and ball 2 is located at 11 extend this notion to 2D. That's all I'm saying. Its a coding check for you to verify..

I think your chart shows that already so I think you're okay and I was just trying to think where things could go wrong in your calculations.
 
  • Like
Likes Klystron
  • #5
Some general comments:

1) Even with correct logic, the results may be very sensitive to the exact point and angle of contact. Do you know that the ##\Delta t = 0.1## value is small enough for the accuracy needed? In fact, you may not be able to specify a fixed value for ##\Delta t ##. You might need to calculate intersection points and do the calculations at the exactly correct time of the impact. That would be an "event driven" simulation. Maybe you do that somewhere, but it is hard to tell.

2) Your code has a lack of comments as though you are charged $ for every comment. Some comments in the code with explanations of calculations is very good when you are requesting help.

3) As @jedishrfu pointed out, you should make sure that your examples and plots start in the exact same state.
 
Last edited:
  • Like
Likes DEvens, Klystron and jedishrfu
  • #6
This may be the type of simulation that is impossible to make it accurately duplicate a real example. Consider a collision of the two balls. Even the slightest change in the direction of travel can cause a significant change in the impact position and angle. No matter how small the initial error is, these errors accumulate and multiply with each impact until the simulation will have no similarity to the actual example.
If there is no impact of the two balls, the simulation has a much better chance of reasonably duplicating the real example.
 
Last edited:
  • Like
Likes aaroman
  • #7
One other observation is that the wall bounces show rounded trajectories which indicates some elasticity in the balls which makes it even harder to simulate accurately.
 
  • #8
There is at least one obvious error in the simulation graph. There is an impact between the balls where the brown ball completely changes its direction but the blue one continues straight. That is wrong. That part of the code should be examined.
 
  • #9
Two comments from skimming part of code and data.

The condition checks on collisions appear to allow interpenetration of the radii of the balls. (or my poor reading of the code).

For debug purposes at least, consider assigning function calls to a local variable before testing the return condition. Inline function calls look cool but when testing/debugging code I prefer examining the function return value before branching on condition, just in case. (JIC).
 
  • Like
Likes FactChecker
  • #10
FactChecker said:
This may be the type of simulation that is impossible to make it accurately duplicate a real example. Consider a collision of the two balls. Even the slightest change in the direction of travel can cause a significant change in the impact position and angle. These changes accumulate and multiply with each impact until the simulation will have no similarity to the actual example.
If there is no impact of the two balls, the simulation has a much better chance of reasonably duplicating the real example.
Well that's kind of happens in my code at small changes becomes big but I guess its due to algorithm implamentation or some of the rounding errors that happens during the calculation.
FactChecker said:
1) Even with correct logic, the results may be very sensitive to the exact point and angle of contact. Do you know that the Δt=0.1Δt=0.1\Delta t = 0.1 value is small enough for the accuracy needed? In fact, you may not be able to specify a fixed value for ΔtΔt\Delta t . You might need to calculate intersection points and do the calculations at the exactly correct time of the impact. That would be an "event driven" simulation. Maybe you do that somewhere, but it is hard to tell.
Well if I decrease ##dt## the things get worse and my code does not work properly. (You can also try that). I am not sure how can I find the exact time of collusion.
FactChecker said:
2) Your code has a lack of comments as though you are charged $ for every comment. Some comments in the code with explanations of calculations is very good when you are requesting help.
Which part is hard to understand ? So I can explain in a better way that part of the code
FactChecker said:
3) As @jedishrfu pointed out, you should make sure that your examples and plots start in the exact same state.
I re-checked and I started them from the same point but I get same graphs. I don't know why that happens ?
jedishrfu said:
One other observation is that the wall bounces show rounded trajectories which indicates some elasticity in the balls which makes it even harder to simulate accurately.
In which part, real one or my version ? they shouldn't actually have rounded trajectories after bouncing. I solved the similar problem without collision and I got it right. I can share that code if its needed
 
  • #11
Klystron said:
The condition checks on collisions appear to allow interpenetration of the radii of the balls. (or my poor reading of the code).
Thats how collision condition should be right ? If the centers of the two balls are less then the 2 * radius of the balls it means they are collided.

I seperatly tested each function (not the motion and check_reflection) and they seem correct for the simple cases.

I discovered one of my errors and I fixed it..My new code looks like this.

Python:
from math import sqrt, atan, sin, cos, pi, inf
from numpy import array

W = 600  # width of the table
H = 300  # height of the table
radius = 20  # the radius of the ball
A = 5  # decelration constant
dt = 0.1
ma = mb = 1 #masses of the particles a and b

def collision_test(Xa, Ya, Xb, Yb):
    if sqrt((Yb - Ya) ** 2 + (Xb - Xa)**2) <= 2 * radius:
        return True

def dot_product(V1, V2):
    return sum(V1 * V2)

def vec_magnitude(V1):
    return sqrt(V1[0]**2 + V1[1]**2)

def after_collision_velocity(Va, Vb, Ra, Rb):
    ''' the equation that produces the velocity of the objects after the collision'''
    Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /  ((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
    Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /  ((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
    return Va_new, Vb_new

def check_reflection(R, angle):
    '''checks reflection from the billiard table'''
    if R[1] < radius:
        R[1] += 2 * (radius - R[1])
        angle *= -1
        R = array([R[0], R[1]])
        return R, angle
    if R[0] < radius:
        R[0] += 2 * (radius - R[0])
        angle = pi - angle
        R = array([R[0], R[1]])
        return R, angle
    if R[1] > H - radius:
        R[1] += 2 * (H - radius - R[1])
        angle *= -1
        R = array([R[0], R[1]])
        return R, angle
    if R[0] > W - radius:
        R[0] += 2 * (W - radius - R[0])
        angle = pi - angle
        R = array([R[0], R[1]])
        return R, angle
    else:
        return R, angledef motion(V, R, angle):
    V_mag = vec_magnitude(V)
    V_mag -= A * dt
    Vx = V_mag * cos(angle)
    Vy = V_mag * sin(angle)
    R[0] += Vx * dt
    R[1] += Vy * dt
    V = array([Vx, Vy])
    R = array([R[0], R[1]])
    return V, Rfor line in open("test1.txt", "r"):
    t = 0
    Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
    Ra = array([Xa, Ya]) #position vector of the ball a
    Rb = array([Xb, Yb]) #position vector of the ball b
    Va = array([Vxa, Vya]) #Velocity vector of a
    Vb = array([Vxb, Vyb]) #Velocity vector of b
    angle_a = atan(Vya / Vxa) 
    angle_b = atan(Vyb / Vxb)
    while t < 10:
        (Va, Ra), (Vb, Rb) =  motion(Va, Ra, angle_a), motion(Vb, Rb, angle_b)
        (Ra, angle_a), (Rb, angle_b) = check_reflection(Ra, angle_a), check_reflection(Rb, angle_b)
        print(Ra[0], Ra[1], Rb[0], Rb[1])
        if collision_test(Ra[0], Ra[1], Rb[0], Rb[1]) == True:
            Va, Vb = after_collision_velocity(Va, Vb, Ra, Rb)
            angle_a, angle_b = atan(Va[1] / Va[0]), atan(Vb[1] / Vb[0])
        t += dt
 

Attachments

  • my_result.png
    my_result.png
    9.3 KB · Views: 236
  • #12
Arman777 said:
Well that's kind of happens in my code at small changes becomes big but I guess its due to algorithm implamentation or some of the rounding errors that happens during the calculation.

Well if I decrease ##dt## the things get worse and my code does not work properly. (You can also try that). I am not sure how can I find the exact time of collusion.

Which part is hard to understand ? So I can explain in a better way that part of the code

I re-checked and I started them from the same point but I get same graphs. I don't know why that happens ?

In which part, real one or my version ? they shouldn't actually have rounded trajectories after bouncing. I solved the similar problem without collision and I got it right. I can share that code if its needed
Both versions show it, but now I'm thinking it may be due to your time step being too coarse.

In an ideal world, your ball trajectory should make a sharp angle each time there's a collision but the images show that a small deviation before going in a straight line. I guess this is because the collision occurred between two time steps.
 
  • Like
Likes Klystron
  • #13
Step 1: Correct the plots. I don't think that your plots look valid. Even the actual data plot has one ball changing direction for no apparent reason. You should get those corrected first so that you can see events that look like the simulation is wrong.
Step 2: Dump data. When you have a simulation where something might go wrong on frame 10 or 100 or 10,000, I like to dump as much data as possible to a file. Stuff your program with prints to a file. Then you can look at the plots to see strange behavior, go into the data file, find the lines that match the time of the bad behavior and examine the calculation results step-by-step.
 
  • Informative
Likes Klystron
  • #14
FactChecker said:
Even the actual data plot has one ball changing direction for no apparent reason. You should get those corrected first so that you can see events that look like the simulation is wrong.
I just copy and paste the data and draw it. If there's something wrong I don't think that's my fault.

I am trying something new. I understand which part is wrong and I ll try to fix it
jedishrfu said:
Both versions show it, but now I'm thinking it may be due to your time step being too coarse.

In an ideal world, your ball trajectory should make a sharp angle each time there's a collision but the images show that a small deviation before going in a straight line. I guess this is because the collision occurred between two time steps.
I guess so. And I think this part of my code is what is wrong..
 
  • Like
Likes jedishrfu
  • #15
If Arman does not mind, I have a question about this coding form in Python.
if collision_test(Ra[0], Ra[1], Rb[0], Rb[1]) == True:
If the collision_test() function call returns a Boolean value, does the language require a comparison to True; or is the statement written this way for clarity?

Generally, in C-derived languages and most other programming languages that I have used, the simplest form would be (ignoring indentation)
If function_that_returns_boolean (arg1, arg2,...) # then do something

or, using a temporary Boolean variable for test purposes
temp_boolean = function_that_returns_boolean (arg1, arg2,...) If temp_boolean # then...

I had intended to learn Python this Summer but have been delayed by other issues. I ask because 25+ years ago there was a raging discussion in the programming community about the preferred form for conditional branching somewhat analogous to PF "Quantum Interpretation" discussions. The consensus then was to use a form similar to the OP with explicit truth comparisons.

[EDIT: I should have said "Prior consensus seemed to be" to use the longer form.]

I will start another thread if this question detracts from troubleshooting effort. Thanks.
 
Last edited:
  • #16
Klystron said:
If the collision_test() function call returns a Boolean value, does the language require a comparison to True

No. In fact it doesn't require the comparison for any return value at all. Every Python object has a truth value even if it's not of the bool type. (Basically, None is false, False is false, empty strings and containers are false, and anything else is true unless it's an instance of a user-defined class that implements some custom behavior.)

Klystron said:
The consensus then was to use a form similar to the OP with explicit truth comparisons.

In other languages this might be necessary (or might have been necessary 25 years ago), but in Python this is strongly discouraged. The idea of the if statement is that it is going to test a condition for truth or falsity, and as above, every Python object has a truth value already. There's no need to explicitly compare it to True.
 
  • Like
Likes Klystron
  • #17
I re-write my code again. This time I fixed one of my functons. However my code still does not work properly. I don't know what to do now. I really dont. I guess its about something else since I checked my each function and they seem to work well.

Python:
from math import sqrt, atan, sin, cos, pi, inf
from numpy import array

W = 600  # width of the table
H = 300  # height of the table
R = 20  # the radius of the ball
A = 5  # decelration constant
dt = 0.01
ma = mb = 1  # masses of the particles a and bdef vec_magnitude(V1):
    return sqrt(V1[0]**2 + V1[1]**2)def collision_test(V1, V2):
    if vec_magnitude(V1 - V2) < 2 * R:
        return Truedef dot_product(V1, V2):
    return sum(V1 * V2)
def after_collision_velocity(Va, Vb, Ra, Rb):
    ''' the equation that produces the velocity of the objects after the collision'''
    Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /
                   ((ma + mb) * vec_magnitude(Ra - Rb)**2)) * (Ra - Rb)
    Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /
                   ((ma + mb) * vec_magnitude(Rb - Ra)**2)) * (Rb - Ra)
    return Va_new, Vb_new

def check_reflection(P, V_mag, angle, V):
    if P[1] < R:
        P += array([0, 2 * (R - P[1])])
        angle *= -1
        return P, V_mag, angle, V
    if P[0] < R:
        P += array([2 * (R - P[0]), 0])
        angle = pi - angle
        return P, V_mag, angle,V
    if P[1] > H - R:
        P += array([0, 2 * (H - R - P[1])])
        angle *= -1
        return P, V_mag, angle, V
    if P[0] > W - R:
        P += array([2 * (W - R - P[0]), 0])
        angle = pi - angle
        return P, V_mag, angle, V
    else:   
        V_mag -= A * dt
        Vx = V_mag * cos(angle)
        Vy = V_mag * sin(angle)
        P += array([Vx * dt, 0])
        P += array([0, Vy * dt])
        V = array([Vx, Vy])
        return P, V_mag, angle, Vfor line in open("tex.txt", "r"):
    t = 0
    Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [int(i) for i in (line.rstrip()).split(" ")]
    Pa = array([Xa, Ya], dtype=float)  #position vector of ball a
    Pb = array([Xb, Yb], dtype=float) #position vector of ball b
    Va = array([Vxa, Vya], dtype=float) # velocity vector of ball a
    Vb = array([Vxb, Vyb], dtype=float) # velocity vector of ball b
    Va_mag = vec_magnitude(Va)
    Vb_mag = vec_magnitude(Vb)
    angle_a = atan(Vya / Vxa)
    angle_b = atan(Vyb / Vxb)
    while t <= 10:
        Pa, Va_mag, angle_a, Va = check_reflection(Pa, Va_mag, angle_a, Va)
        Pb, Vb_mag, angle_b, Vb= check_reflection(Pb, Vb_mag, angle_b, Vb)
        if collision_test == True:
            Va, Vb = after_collision_velocity(Va, Vb, Pa, Pb)
            Va_mag = vec_magnitude(Va)
            Vb_mag = vec_magnitude(Vb)
            angla_a = atan( Va[1] / Va[0] )
            angle_b = atan( Vb[1] / Vb[0] )
        t += dt
    print(Pa[0], Pa[1], Pb[0], Pb[1])
 
  • #18
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.
 
  • Like
Likes FactChecker
  • #19
jedishrfu said:
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.
I might try online debugger but numpy array will not work in there. I guess i ll just give up and try to solve later on. I can print the values but somehow the things seems okay
 
  • #20
Arman777 said:
I might try online debugger but numpy array will not work in there. I guess i ll just give up and try to solve later on. I can print the values but somehow the things seems okay
One thing to change is from the function atan to atan2. Only atan2 keeps track of the quadrant correctly.

With the changes, do you have new data or a new plot? Your data and plot should include the exact initial values so that we know the initial conditions. A complete state would be the (x,y) positions, and (x,y) velocities. You should print all that at the very least. Looking at the latest plot in post #11, I don't understand the initial(?) slow velocity of one ball that then suddenly speeds up.
 
  • #21
FactChecker said:
One thing to change is from the function atan to atan2. Only atan2 keeps track of the quadrant correctly
I ll try that.

FactChecker said:
With the changes, do you have new data or a new plot? Your data and plot should include the exact initial values so that we know the initial conditions. A complete state would be the (x,y) positions, and (x,y) velocities. You should print all that at the very least. Looking at the latest plot in post #11, I don't understand the initial(?) slow velocity of one ball that then suddenly speeds up.
That picture was bad i agree. Well one of the objects has larger speed than the other. I ll post the graphs and data tomorrow (its late here). The inital conditions are the same as in the post #1.
 
  • #22
Line 75
1) The def statement (line 16) shows collision_test function with two arguments. No args in line 75. Even assuming global variables, the function call does not match the definition.

2) As PeterDonis explained above,
PeterDonis said:
In fact it doesn't require the comparison for any return value at all. Every Python object has a truth value even if it's not of the bool type. (Basically, None is false, False is false, empty strings and containers are false, and anything else is true unless it's an instance of a user-defined class that implements some custom behavior.)
Have you tested this condition? Should not line 75 read
if collision_test (arg1, arg2)
 
  • Like
Likes Arman777
  • #23
Klystron said:
Line 75
1) The def statement (line 16) shows collision_test function with two arguments. No args in line 75. Even assuming global variables, the function call does not match the definition.
I am surprised that it compiles with this mistake.
 
  • Like
Likes Arman777 and Klystron
  • #24
It will help to write unit tests for each of your functions before attempting to debug the program as a whole.
 
  • Like
Likes Arman777 and Klystron
  • #25
jedishrfu said:
This is the lonely life of the programmer ultimately you own the problem and you own the code and only you can fix it.

My approach would now be to annotate with print statements or using a stepping debugger to walk through step by step and let the computer do the hard work and you review it and decide where it went wrong. Sometimes this takes an inordinate amount of time and sometimes you get an epiphany and see the gotcha in your code.
It's my experience that it is possible to stare at code for a long, long time without spotting a simple error. The real trick in debugging is to develop techniques that allow one to narrow down to the specific location of the problem. It may take much less time to stuff a lot of prints into code than it does to find a bug by staring at code.
But before you do that, please put it into a good interpreter/compiler and eliminate all warnings.
 
  • Like
Likes Arman777, Klystron and jedishrfu
  • #26
FactChecker said:
It's my experience that it is possible to stare at code for a long, long time without spotting a simple error. The real trick in debugging is to develop techniques that allow one to narrow down to the specific location of the problem. It may take much less time to stuff a lot of prints into code than it does to find a bug by staring at code.
But before you do that, please put it into a good interpreter/compiler and eliminate all warnings.

Spot on!
 
  • #27
Once you've done all the above, start the sim at the beginning and check if/where it's first going awry as compared to the expected tracking.

Are the initial positions identical?
Are the initial velocities identical?
Are the initial trajectories identical?
And - this one will be harder, because the plot doesn't show it - are they decelerating correctly?
Is the first rail bounce outcome identical?
Is the first collision outcome identical?

Where exactly does your result first deviate from the expected result?
This will help you narrow down where to look for bugz in teh codez.
 
  • Like
Likes FactChecker
  • #28
FactChecker said:
I am surprised that it compiles with this mistake.

I am surprised too

FactChecker said:
But before you do that, please put it into a good interpreter/compiler and eliminate all warnings.

I am using VS Code.

Klystron said:
1) The def statement (line 16) shows collision_test function with two arguments. No args inline 75. Even assuming global variables, the function call does not match the definition.

When you guys spot the error, I was also surprised that my code worked without giving any error, however when I run the code in different compilers it works.

Try this code
Python:
def motion(a):
  return 2*a

if motion:
  print("yey")

It works in VS code, or online compilers.

I don't know how but it does. Probably function names are considered as True (?)
DavidSnider said:
It will help to write unit tests for each of your functions before attempting to debug the program as a whole.

I already did that. It seems correct as far as I know

Klystron said:
Have you tested this condition? Should not line 75 read
if collision_test (arg1, arg2)

if collision_test (arg1, arg2):
...

and

if collision_test (arg1, arg2) == True

are the same, its just writing "True" in an explicit form. I sometimes use the other one. But professional coders prefer to write implicitly I guess.

The answer will be accepted as correct within a range of ±50 for each pair of coordinate.

Also, dt is very important (I guess someone pointed out the importance of this before )

DaveC426913 said:
check if/where it's first going awry as compared to the expected tracking.

Are the initial positions identical?
Are the initial velocities identical?
Are the initial trajectories identical?

That's kind of the problem it's not obligated to be identical but I guess they should give somewhat similar results (?)

I tested a simple case where the data was "100 50 300 50 100 0 0 0 "
So Pa = [100, 50], Pb = [300, 50], Va = [100 0], Vb = [0, 0]

This means that when the ball "a" hits the ball "b", the ball "a" will stop and "b" will start to move with the same speed.

Here is the graph of it which I made by running my code.
figure_1.png

as you can see the ball "a" stops ( the red line) after hitting the ball "b" ( the green dashed line)
----------------

Now our actual data was
235 124 365 176 181 34 -34 -14

I am getting kind of different images for different dt values. However, it also seems there are patterns in it.

In general, the answer is accepted when each value is within a range of the ±50 from the answer. The answer is 399 104 106 62

I am getting something like
355.7245911085971 202.9357121674485 109.5838027447148 30.913552143226795
or
399.8285196503435 194.65099630877506 173.18316603478155 98.13456362376074
or
355.2222801476294 203.03006892254314 86.53567162928971 74.22940763646008

So only Pa[1] value is off the range for an accepted answer.
dt is 0.0001.png
 
Last edited:
  • #29
FactChecker said:
One thing to change is from the function atan to atan2. Only atan2 keeps track of the quadrant correctly.
I noticed an interesting thing. When I don't use atan2 (and use atan()) Pa[0], Pb[0] and Pb[1] are near the correct value but Pa[1} is not within the range of the accepted value. For instance

355.7245911085971 202.9357121674485 109.5838027447148 30.913552143226795

However, when I use atan2(), Pa[1] becomes an acceptable value but this time Pa[0], Pb[0] and Pb[1] are not within the range of the accepted value (sometimes they are but sometimes not)

For instance,
120.63023480435133 102.51617670357922 126.89167814780772 87.78085456018776

423.0257577924453 131.3197556076701 433.00009977473553 122.80783144468634

88.07944536334713 70.8248555671061 204.2954606777806 127.95018019597957

350.04117035554316 117.60994360228256 351.7414000498847 119.25903023712435


(all data values represent Pa[0], Pa[1], Pb[0], Pb[1] repectively)
 
  • #30
Arman777 said:
When you guys spot the error, I was also surprised that my code worked without giving any error, however when I run the code in different compilers it works.

Try this code
Python:
def motion(a):
  return 2*a

if motion:
  print("yey")

It works in VS code, or online compilers.

I don't know how but it does.
I don't know what to think about this. I am not a Python programmer. I would not trust a program that accepted that as valid code.
That's kind of the problem it's not obligated to be identical but I guess they should give somewhat similar results (?)

I tested a simple case where the data was "100 50 300 50 100 0 0 0 "
So Pa = [100, 50], Pb = [300, 50], Va = [100 0], Vb = [0, 0]
I assume that he means that the initial conditions of the simulation must match the initial conditions of the actual data.
So only Pa[1] value is off the range for an accepted answer.
View attachment 248210
The green line makes some unexplained changes of direction. It would be nice to know exactly what was going on when that happened. That is why I keep trying to encourage you to dump as much data as possible into a file. Then you could go to that part of the data file and see why the direction changed.
 
  • #31
Arman777 said:
However, when I use atan2(), Pa[1] becomes an acceptable value but this time Pa[0], Pb[0] and Pb[1] are not within the range of the accepted value (sometimes they are but sometimes not)
I'm not sure what you mean by "acceptable value". The function atan2 will return the correct angle. What you do with that angle is up to you.
 
  • #32
FactChecker said:
I'm not sure what you mean by "acceptable value". The function atan2 will return the correct angle. What you do with that angle is up to you.
When I use atan2 for dt = 0.001 I get
526.4046809656061 170.8742588241399 445.23248886773865 256.0652790027961
But for atan I get
341.36661845405075 44.75395042783804 338.65671584881693 84.45754194958526

I don't know why this happens.

FactChecker said:
The green line makes some unexplained changes of direction
I guess that's the part where two particles collide. Since they have a radius of 20. The collision will happen when they are near then 40. Since we are plotting these datas on the graph this change might have looked like a direction change.
FactChecker said:
I assume that he means that the initial conditions of the simulation must match the initial conditions of the actual data.
I am just copying the initial conditions copying them and putting them on a file to run the code. Theres no mistake in there.
FactChecker said:
I don't know what to think about this. I am not a Python programmer. I would not trust a program that accepted that as valid code.
Python:
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def motion(a):
...     return 2 * a
...
>>> if motion:
...     print("yey")
...
yey
>>>

Its in the core of the python. I mean it somehow works. Its of course wrong to use it like that... Weird side of the python :p

FactChecker said:
you to dump as much data as possible
What do you mean by dump as much as data. Like giving some random meaningful inputs and see what happens ?. Also I couldn't do it before since one of my functions were wrong...
I tried a simple case for the linear momentum conservation now I ll try with introcuding some angles.. and we will see.

Okay I ll try that
 
  • #33
When you use if on a non-boolean object in python it converts it to a boolean

>>> [(i,bool(i)) for i in [None, 0, 0.0, 3.14, "abc", "", 'a', '',True, False, [1,2,3],[]]]
[(None, False), (0, False), (0.0, False), (3.14, True), ('abc', True), ('', False), ('a', True), ('', False), (True, True), (False, False), ([1, 2, 3], True), ([], False)]

in the case of the motion function it is the same as saying "if motion(x) != 0"
 
  • Like
Likes Arman777
  • #34
Arman777 said:
When I use atan2 for dt = 0.001 I get
526.4046809656061 170.8742588241399 445.23248886773865 256.0652790027961
But for atan I get
341.36661845405075 44.75395042783804 338.65671584881693 84.45754194958526

I don't know why this happens.
What do you mean "you get" these numbers? Both functions return an angle, not position values. Are these the final results of the 10 second run? That is no help at all, with all the questionable stuff happening before the end of the run.
I guess that's the part where two particles collide. Since they have a radius of 20. The collision will happen when they are near then 40. Since we are plotting these datas on the graph this change might have looked like a direction change.
It looks like one ball changes direction, but the other does not. So how can that be a collision?
What do you mean by dump as much as data. Like giving some random meaningful inputs and see what happens ?.
I mean that you should print a lot of detailed data to a file so that you can see exactly what calculations are happening at each step. Put prints at every key point in your code so you can see the exact calculation results. There are some points in the plots where one ball changes direction but I don't see the other ball change direction. You need to see what is happening there. A file of data would help. Until then, we are just blind to what is going on.
 
Last edited:
  • #35
DavidSnider said:
When you use if on a non-boolean object in python it converts it to a boolean

>>> [(i,bool(i)) for i in [None, 0, 0.0, 3.14, "abc", "", 'a', '',True, False, [1,2,3],[]]]
[(None, False), (0, False), (0.0, False), (3.14, True), ('abc', True), ('', False), ('a', True), ('', False), (True, True), (False, False), ([1, 2, 3], True), ([], False)]

in the case of the motion function it is the same as saying "if motion(x) != 0"
Thanks for the info
FactChecker said:
There are some points in the plots where one ball changes direction but I don't see the other ball change direction.
Yes I noticed that too. The thing is one ball changes its direction and other the other one dont. Its really confusing for me.
I also noticed that atan is wrong and atan2 works.
 
<h2>1. How do you calculate the velocity of the balls after collision?</h2><p>The velocity of the balls after collision can be calculated using the conservation of momentum and energy equations. The mass, initial velocity, and angle of collision of each ball must also be taken into account.</p><h2>2. Can the balls collide multiple times in the same 2D box?</h2><p>Yes, the balls can collide multiple times in the same 2D box. However, the direction and velocity of the balls may change after each collision, making it difficult to predict their movements.</p><h2>3. What factors affect the outcome of the collision between the balls?</h2><p>The outcome of the collision between the balls can be affected by factors such as the mass, initial velocity, angle of collision, and the elasticity of the balls. The shape and size of the 2D box can also play a role in the outcome.</p><h2>4. How does the elasticity of the balls affect the collisions?</h2><p>The elasticity of the balls determines how much kinetic energy is conserved during the collision. A perfectly elastic collision would result in no loss of kinetic energy, while a perfectly inelastic collision would result in a complete loss of kinetic energy.</p><h2>5. Can you predict the exact paths of the balls after collision?</h2><p>No, it is not possible to predict the exact paths of the balls after collision due to the complex nature of the collisions and the influence of various factors such as friction and air resistance. However, we can make predictions based on mathematical models and simulations.</p>

1. How do you calculate the velocity of the balls after collision?

The velocity of the balls after collision can be calculated using the conservation of momentum and energy equations. The mass, initial velocity, and angle of collision of each ball must also be taken into account.

2. Can the balls collide multiple times in the same 2D box?

Yes, the balls can collide multiple times in the same 2D box. However, the direction and velocity of the balls may change after each collision, making it difficult to predict their movements.

3. What factors affect the outcome of the collision between the balls?

The outcome of the collision between the balls can be affected by factors such as the mass, initial velocity, angle of collision, and the elasticity of the balls. The shape and size of the 2D box can also play a role in the outcome.

4. How does the elasticity of the balls affect the collisions?

The elasticity of the balls determines how much kinetic energy is conserved during the collision. A perfectly elastic collision would result in no loss of kinetic energy, while a perfectly inelastic collision would result in a complete loss of kinetic energy.

5. Can you predict the exact paths of the balls after collision?

No, it is not possible to predict the exact paths of the balls after collision due to the complex nature of the collisions and the influence of various factors such as friction and air resistance. However, we can make predictions based on mathematical models and simulations.

Similar threads

  • Introductory Physics Homework Help
Replies
1
Views
2K
  • Programming and Computer Science
Replies
4
Views
10K
  • Introductory Physics Homework Help
Replies
7
Views
11K
  • Programming and Computer Science
Replies
2
Views
4K
Back
Top