def test_time(): bld = Billiard() assert bld.time == 0.0 ret = bld.evolve(1.0) assert ret == [] assert bld.time == 1.0 ret = bld.evolve(42.0) assert ret == [] assert bld.time == 42.0
def test_simple_collision(): bld = Billiard() bld.add_ball((2, 0), (4, 0), radius=1) bld.evolve(10.0) assert tuple(bld.balls_position[0]) == (42.0, 0.0) assert tuple(bld.balls_velocity[0]) == (4.0, 0.0) # add another ball that will collide with the first one bld.add_ball((50, 18), (0, -9), radius=1, mass=2) assert bld.toi_next == (approx(11.79693), 0, 1) collisions = bld.evolve(14.0) assert bld.time == 14 assert len(collisions) == 1 assert collisions[0] == (approx(11.79693), 0, 1) assert tuple(bld.balls_position[0]) == (approx(46.2503), approx(-26.43683)) assert tuple(bld.balls_position[1]) == (approx(55.8748), approx(-4.78158)) assert tuple(bld.balls_velocity[0]) == (approx(-1.333333), approx(-12)) assert tuple(bld.balls_velocity[1]) == (approx(2.666667), approx(-3))
def test_masses(): bld = Billiard() # setup three balls bld.add_ball((-3, 0), (1, 0), 1, mass=0) # massless bld.add_ball((0, 0), (0, 0), 1, mass=42) # finite mass bld.add_ball((4, 0), (-1, 0), 1, mass=INF) # infinite mass assert bld.toi_table == [[], [1.0], [2.5, 2.0]] bld.evolve(1.0) # massless <-> finite mass collision assert tuple(bld.balls_position[0]) == (-2, 0) assert tuple(bld.balls_velocity[0]) == (-1, 0) assert tuple(bld.balls_position[1]) == (0, 0) assert tuple(bld.balls_velocity[1]) == (0, 0) assert bld.toi_table == [[], [INF], [INF, 2.0]] bld.evolve(2.0) # finite mass <-> infinite mass collision assert tuple(bld.balls_position[1]) == (0, 0) assert tuple(bld.balls_velocity[1]) == (-2, 0) assert tuple(bld.balls_position[2]) == (2, 0) assert tuple(bld.balls_velocity[2]) == (-1, 0) assert bld.toi_table == [[], [3.0], [INF, INF]] bld.evolve(3.0) # again massless <-> finite mass collision assert tuple(bld.balls_position[0]) == (-4, 0) assert tuple(bld.balls_velocity[0]) == (-3, 0) assert tuple(bld.balls_position[1]) == (-2, 0) assert tuple(bld.balls_velocity[1]) == (-2, 0) assert bld.toi_table == [[], [INF], [INF, INF]]
def test_newton_cradle(): bld = Billiard() # setup Newton's cradle with four balls bld.add_ball((-3, 0), (1, 0), 1) bld.add_ball((0, 0), (0, 0), 1) bld.add_ball((5, 0), (0, 0), 1) # this is the last ball (more coverage) bld.add_ball((3, 0), (0, 0), 1) # in direct contact with third ball assert bld.toi_next == (1.0, 0, 1) # first collision collisions = bld.evolve(1.0) assert len(collisions) == 1 assert collisions[0] == (1.0, 0, 1) assert tuple(bld.balls_position[0]) == (-2, 0) assert tuple(bld.balls_velocity[0]) == (0, 0) assert tuple(bld.balls_position[1]) == (0, 0) assert tuple(bld.balls_velocity[1]) == (1, 0) assert bld.toi_next == (2.0, 1, 3) # second and third collision and then some more time collisions = bld.evolve(11.0) assert len(collisions) == 2 assert collisions[0] == (2.0, 1, 3) assert collisions[1] == (2.0, 2, 3) assert tuple(bld.balls_position[1]) == (1, 0) assert tuple(bld.balls_velocity[1]) == (0, 0) assert tuple(bld.balls_position[2]) == (5 + (11 - 2) * 1, 0) assert tuple(bld.balls_velocity[2]) == (1, 0) assert tuple(bld.balls_position[3]) == (3, 0) assert tuple(bld.balls_velocity[3]) == (0, 0) # there are no other collisions assert table_tolist(bld.toi_table) == [[], [INF], [INF, INF], [INF, INF, INF]] assert bld.toi_min == [(INF, -1), (INF, 0), (INF, 0), (INF, 0)] assert bld.toi_next == (INF, -1, 0)
def test_movement(): bld = Billiard() # add ten balls for i in range(10): bld.add_ball((i, 0), (0, 1)) # move time = 42.0 ret = bld.evolve(time) assert ret == [] for idx in range(10): # movement in y-direction assert tuple(bld.balls_position[idx]) == (idx, time) assert tuple(bld.balls_velocity[idx]) == (0, 1)
def test_exceptional_balls(): bld = Billiard() # setup two point particles bld.add_ball((-3, 0), (1, 0), 0, mass=0) # note: massless bld.add_ball((-2, 0), (0, 0), 0, mass=42) assert bld.toi_table == [[], [INF]] # no collision # setup two balls with infinite masses bld.add_ball((0, 0), (0, 0), 1, mass=INF) bld.add_ball((100, 0), (-20, 0), 1, mass=INF) assert bld.toi_table[2] == [2.0, INF] assert bld.toi_table[3] == [ approx(102 / 21), approx(101 / 20), approx(98 / 20), ] assert bld.toi_next == (2.0, 0, 2) bld.evolve(2.0) # massless <-> infinite mass collision assert tuple(bld.balls_position[0]) == (-1, 0) assert tuple(bld.balls_velocity[0]) == (-1, 0) assert tuple(bld.balls_position[2]) == (0, 0) assert tuple(bld.balls_velocity[2]) == (0, 0) assert bld.toi_table[:3] == [[], [INF], [INF, INF]] assert bld.toi_table[3] == [ approx(98 / 19), approx(101 / 20), approx(98 / 20), ] assert bld.toi_next == (approx(98 / 20), 2, 3) # toi == 4.9 bld.evolve(5.0) # infinite mass <-> infinite mass collision assert tuple(bld.balls_position[2]) == (0, 0) assert tuple(bld.balls_velocity[2]) == (0, 0) assert tuple(bld.balls_position[3]) == (approx(2 + 0.1 * 20), 0) assert tuple(bld.balls_velocity[3]) == (20, 0) assert bld.toi_table[3] == [INF, INF, INF] assert tuple(bld.balls_position[0]) == (-4, 0) assert tuple(bld.balls_velocity[0]) == (-1, 0) # add one more massless ball that collides with the first one bld.add_ball((-6, 0), (0, 0), 1, mass=0) assert bld.toi_table[4] == [approx(6.0), INF, INF, INF] assert bld.toi_next == (approx(6.0), 0, 4) # collisions of two massless balls do not make sense with pytest.raises(FloatingPointError): bld.evolve(7.0)