def test_sliding_ball_collision(pool_physics, plot_motion_timelapse, plot_energy, gl_rendering): physics = pool_physics ball_positions = physics.eval_positions(0.0) ball_positions[1] = ball_positions[0] ball_positions[1, 2] -= 8 * physics.ball_radius physics.reset(balls_on_table=[0, 1], ball_positions=ball_positions) start_event = BallSlidingEvent(0, 0, r_0=ball_positions[0], v_0=np.array((0.0, 0.0, -2.0)), omega_0=np.zeros(3, dtype=np.float64)) events = physics.add_event_sequence(start_event) _logger.debug('%d events added:\n\n%s\n', len(events), PhysicsEvent.events_str(events=events))
def test_corner_collision(pool_physics, gl_rendering, plot_motion_timelapse, plot_energy): physics = pool_physics ball_positions = physics.eval_positions(0.0) physics.reset(balls_on_table=[0], ball_positions=ball_positions) r_c = physics._r_cp[0, 0] r_0c = r_c - ball_positions[0] v_0 = 3.0 * r_0c / np.sqrt(np.dot(r_0c, r_0c)) start_event = BallSlidingEvent(0, 0, r_0=ball_positions[0], v_0=v_0, omega_0=np.zeros(3, dtype=np.float64)) events = physics.add_event_sequence(start_event) _logger.debug('%d events added:\n\n%s\n', len(events), PhysicsEvent.events_str(events=events))
def test_angled_ball_collision(pool_physics, plot_motion_timelapse, plot_energy, gl_rendering): physics = pool_physics ball_positions = physics.eval_positions(0.0) ball_positions[1] = ball_positions[0] ball_positions[1, 0] -= 8 / np.sqrt(2) * physics.ball_radius ball_positions[1, 2] -= 8 / np.sqrt(2) * physics.ball_radius physics.reset(balls_on_table=[0, 1], ball_positions=ball_positions) r_ij = ball_positions[1] - ball_positions[0] r_ij[0] += physics.ball_radius e_ij = r_ij / np.linalg.norm(r_ij) v_0 = 0.9 * e_ij start_event = BallSlidingEvent(0, 0, r_0=ball_positions[0], v_0=v_0, omega_0=np.zeros(3, dtype=np.float64)) events = physics.add_event_sequence(start_event) _logger.debug('%d events added:\n\n%s\n', len(events), PhysicsEvent.events_str(events=events))
def test_corner_collision(pool_physics, gl_rendering, plot_motion_timelapse, plot_energy, side, i_c): physics = pool_physics ball_positions = physics.eval_positions(0.0) ball_positions[0, ::2] = 0 physics.reset(balls_on_table=[0], ball_positions=ball_positions) R = physics.ball_radius r_c = physics._r_cp[side, i_c] r_i = r_c + R * np.array([ np.sign(r_c[0]) * np.cos(10 * DEG2RAD), 0.0, np.sign(r_c[2]) * np.sin(10 * DEG2RAD) ]) r_0i = r_i - ball_positions[0] v_0 = 3.0 * r_0i / np.sqrt(np.dot(r_0i, r_0i)) start_event = BallSlidingEvent(0, 0, r_0=ball_positions[0], v_0=v_0, omega_0=np.zeros(3, dtype=np.float64)) events = physics.add_event_sequence(start_event) assert any(isinstance(e, CornerCollisionEvent) for e in events) _logger.debug('%d events added:\n\n%s\n', len(events), PhysicsEvent.events_str(events=events))
def test_collide_balls(request): """Reproduce results of Mathavan et al, 2014 - Table 1""" show_plots = request.config.getoption('--show-plots') e = 0.89 mu_s = 0.21 mu_b = 0.05 M = 0.1406 R = 0.02625 r_i = np.zeros(3) rd = np.array([1.0, 0.0, 0.0]) r_c = np.array([R, 0.0, 0.0]) r_j = r_i + 2 * R * rd v_j = np.zeros(3, dtype=np.float64) omega_j = np.zeros(3, dtype=np.float64) expected = [ # Table 1 # Table 2 (0.914, 0.831, 31.93, 32.20), (0.520, 0.599, 32.45, 25.07), (0.917, 0.676, 29.91, 38.62), (1.28, 0.780, 27.32, 44.38), (0.383, 0.579, 29.47, 17.15) ] for i_cond, (cue_ball_velocity, topspin, cut_angle) in enumerate([(1.539, 58.63, 33.83), (1.032, 39.31, 26.36), (1.364, 51.96, 40.52), (1.731, 65.94, 46.5), (0.942, 35.89, 18.05)]): c, s = np.cos(cut_angle * DEG2RAD), np.sin(cut_angle * DEG2RAD) v_i, omega_i = np.array( ((cue_ball_velocity * c, 0.0, cue_ball_velocity * s), (topspin * s, 0.0, -topspin * c))) v_i[1:] = v_i[:0:-1] v_j[1:] = v_j[:0:-1] omega_i[1:] = omega_i[:0:-1] omega_j[1:] = omega_j[:0:-1] deltaP = (1 + e) * M * cue_ball_velocity / 8000 v_is, omega_is, v_js, omega_js = collide_balls(r_c, r_i, v_i, omega_i, r_j, v_j, omega_j, e, mu_s, mu_b, M, R, 9.81, deltaP=deltaP, return_all=True) if show_plots: plot_collision(deltaP * np.arange(len(v_is)), v_is, v_js, omega_is, omega_js) v_is[:, 1:] = v_is[:, :0:-1] v_js[:, 1:] = v_js[:, :0:-1] omega_is[:, 1:] = omega_is[:, :0:-1] omega_js[:, 1:] = omega_js[:, :0:-1] v_i1 = v_is[-1] omega_i1 = omega_is[-1] v_j1 = v_js[-1] omega_j1 = omega_js[-1] from poolvr.physics.events import PhysicsEvent, BallSlidingEvent PhysicsEvent.ball_radius = R PhysicsEvent.ball_diameter = 2 * R PhysicsEvent.ball_mass = M PhysicsEvent.ball_I = 2.0 / 5 * M * R**2 PhysicsEvent.mu_s = mu_s PhysicsEvent.mu_b = mu_b e_i, e_j = BallSlidingEvent(0.0, 0, r_i, v_i1, omega_i1), \ BallSlidingEvent(0.0, 1, r_j, v_j1, omega_j1) v_iS = e_i.next_motion_event.eval_velocity(0.0) v_jS = e_j.next_motion_event.eval_velocity(0.0) v_iS_mag = np.sqrt(np.dot(v_iS, v_iS)) v_jS_mag = np.sqrt(np.dot(v_jS, v_jS)) lambda_i = np.arctan(v_iS[2] / v_iS[0]) * RAD2DEG lambda_j = np.arctan(-v_jS[2] / v_jS[0]) * RAD2DEG theta_i = abs(lambda_i - cut_angle) theta_j = abs(lambda_j - cut_angle) v_iS_mag_ex, v_jS_mag_ex, theta_i_ex, theta_j_ex = expected[i_cond] v_0 = np.sqrt(np.dot(v_i, v_i)) _logger.info( ''' |v_0|: %s topspin: %s cut_angle: %s |v_iS| = %s expected |v_iS| = %s |v_jS| = %s expected |v_jS| = %s abs(|v_iS| - expected) / |expected| = %s abs(|v_jS| - expected) / |expected| = %s theta_i = %s expected theta_i = %s theta_j = %s expected theta_j = %s abs(theta_i - expected) / |expected| = %s abs(theta_j - expected) / |expected| = %s ''', v_0, topspin, cut_angle, v_iS_mag, v_iS_mag_ex, v_jS_mag, v_jS_mag_ex, abs(v_iS_mag - v_iS_mag_ex) / abs(v_iS_mag_ex), abs(v_jS_mag - v_jS_mag_ex) / abs(v_jS_mag_ex), theta_i, theta_i_ex, theta_j, theta_j_ex, abs(theta_i - theta_i_ex) / abs(theta_i_ex), abs(theta_j - theta_j_ex) / abs(theta_j_ex))