Esempio n. 1
0
def taylor_green_vortex_sim(number_of_particles=50):
    def get_vel_fluid(self):
        x = self.pos[0]
        y = self.pos[1]
        z = self.pos[2]

        return taylor_green_vortex(x, y, z)

    particles = []
    for i in range(number_of_particles):
        # Generate random start points.
        x_start = (2 * random() - 1) * math.pi
        y_start = (2 * random() - 1) * math.pi
        z_start = (2 * random() - 1) * math.pi

        pos = [x_start, y_start, z_start]
        p = Particle(len(particles),
                     pos, [0, 0, 0],
                     diameter=0.001,
                     get_vel_fluid=get_vel_fluid,
                     get_gravity=lambda _: [0, 0, 0])

        particles.append(p)

    last_time = 0
    for t in range(500):
        time = t / 10
        [p.iterate(time - last_time) for p in particles]
        last_time = time

    return particles
Esempio n. 2
0
    def test_offset_bouncing_collision(self):
        ps = []
        coeff = 1
        for y in np.arange(0, 5, 0.5):
            ps.append(Particle(len(ps), [coeff * 0.025, y + 0.5, 0], [0, 0, 0], 0.1))
            coeff *= -1
        p_fixed = Particle(len(ps), [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        cols = []
        for p in ps:
            cols.append(Collision(p, p_fixed, 1e5, restitution=0.8, friction_coefficient=0.6, friction_stiffness=1e5))
        for i in range(len(ps)):
            for j in range(i + 1, len(ps)):
                cols.append(
                    Collision(ps[i], ps[j], 1e5, restitution=0.8, friction_coefficient=0.6, friction_stiffness=1e5))
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 3, timestep):
            delta_t = time - last_time
            for col in cols:
                col.calculate(delta_t)
            for p in ps:
                p.iterate(delta_t)
            p_fixed.iterate(delta_t)
            last_time = time

        ps.append(p_fixed)
        particles_to_paraview(ps, "offset_bounce_col", "../../run/offset_bounce_collision/")
Esempio n. 3
0
def drag():
    u_0 = -2
    diameter = 0.1
    density = 10
    mass = get_mass(density, diameter)
    fluid_vel = 1
    fluid_viscosity = 0.00193

    tau = density * diameter**2 / (18 * fluid_viscosity)
    sim_length = 5 * tau

    for interval in [8, 16, 32, 64]:
        p1 = Particle(1, [0, 0, 0], [0, 0, 0],
                      diameter,
                      density=density,
                      get_gravity=lambda dummy: [0, 0, 0],
                      get_vel_fluid=lambda dummy: [fluid_vel, 0, 0],
                      fluid_viscosity=fluid_viscosity)

        timestep = tau / interval

        last_time = 0
        for time in np.arange(0, sim_length + timestep, timestep):
            delta_t = time - last_time
            p1.iterate(delta_t)
            last_time = time
            particles_to_file([p1], "1_drag_" + str(interval), "data/", time)
Esempio n. 4
0
 def test_get_collision_normal(self):
     p1 = Particle(1, [0, 0, 0], [0, 0, 0])
     p2 = Particle(2, [1, 1, 1], [0, 0, 0])
     col = Collision(p1, p2)
     TestCase.assertAlmostEquals(self,
                                 vect.mag(
                                     col.get_collision_normal() - (np.array([1, 1, 1]) / vect.mag([1, 1, 1]))),
                                 0)
Esempio n. 5
0
    def test_drag_velocity_implicit_explicit(self):
        """ Tests simulated terminal velocity against a calculated value using implicit and explicit integration. """
        v = 5  # Fluid speed

        def get_vel_fluid(self):
            return [v, 0, 0]

        data = []
        tau = None
        for timestep in [1]:
            p_implicit = Particle(0, [0, 0, 0], [0, 0, 0], get_vel_fluid=get_vel_fluid,
                                  get_gravity=lambda dummy: [0, 0, 0], diameter=0.001)
            p_explicit = Particle(1, [0, 0, 0], [0, 0, 0], get_vel_fluid=get_vel_fluid,
                                  get_gravity=lambda dummy: [0, 0, 0], diameter=0.001)
            times = []
            explicit = []
            implicit = []
            analytic = []
            last_time = 0
            for time in np.arange(0, 40, timestep):
                p_explicit.iterate(time - last_time, implicit=False)
                p_implicit.iterate(time - last_time, implicit=True)
                times.append(time)
                explicit.append(vect.mag(p_explicit.vel))
                implicit.append(vect.mag(p_implicit.vel))
                tau = p_explicit.get_tau()
                analytic.append(v * (1 - math.exp(- time / tau)))
                last_time = time
            data.append([times, explicit])
            data.append([times, implicit])
            data.append([times, analytic])

        fig = plt.figure()
        fig.patch.set_facecolor('white')
        ax = fig.gca()
        plots = []
        for i in range(len(data[0][0])):
            data[0][0][i] /= tau
        for d in data:
            for j in range(len(d[1])):
                d[1][j] = d[1][j] / v
            plots.append(ax.plot(d[0], d[1])[0])
        ax.set_xlabel(r'$t/\tau$')
        ax.set_ylabel(r'Speed / Max Speed')
        plt.legend(plots, ['Explicit', 'Implicit', 'Analytic'], loc=4)
        plt.show()
        print("Explicit terminal velocity = {0}".format(data[0][1][-1]))
        print("Implicit terminal velocity = {0}".format(data[1][1][-1]))
        # Test if terminal velocity is within 0.1% of a calculated value.

        explicit_diff_sum = 0
        implicit_diff_sum = 0
        length = len(data[0][0])
        for i in range(1, length):  # Start at 1 to avoid division by zero at the initial conditions.
            explicit_diff_sum += (data[0][1][i] - data[2][1][i]) / data[2][1][i]
            implicit_diff_sum += (data[1][1][i] - data[2][1][i]) / data[2][1][i]
        explicit_avg = 100 * np.abs(explicit_diff_sum / length)
        print("Explicit average percentage difference = {0}".format(explicit_avg))
        implicit_avg = 100 * np.abs(implicit_diff_sum / length)
        print("Implicit average percentage difference = {0}".format(implicit_avg))
Esempio n. 6
0
    def test_collision_timestep_limits(self):
        stiffnesses = np.arange(1e4, 1e6, 5e4)
        stable_to = []

        def get_percent_dif(particle1, particle2, delta_t):
            print("    Testing " + str(delta_t))
            last_time = 0
            for time in np.arange(0, 10, delta_t):
                delta_t = time - last_time
                col.calculate(delta_t)
                particle1.iterate(delta_t)
                particle2.iterate(delta_t)
                last_time = time
            predicted_overlap = particle1.get_mass() * vect.mag(particle1.get_gravity(particle1)) / col.stiffness
            percent_dif = 100 * np.abs(col.get_particle_overlap() / predicted_overlap) - 100
            return percent_dif

        for stiffness in stiffnesses:
            print("Stiffness = " + str(stiffness))
            p1 = Particle(1, [0, 0.5, 0], [0, 0, 0], 0.1)
            p2 = Particle(2, [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
            col = Collision(p1, p2, stiffness, restitution=0.8)

            timestep = 0.001
            finished = False
            last_valid = None
            while not finished:
                if get_percent_dif(p1, p2, timestep) < 1:
                    last_valid = timestep
                    timestep += 0.00005
                elif last_valid is None:
                    if timestep - 0.00005 > 0:
                        timestep -= 0.00005
                    else:
                        timestep /= 2
                else:
                    stable_to.append(last_valid)
                    finished = True
            print("Timestep = " + str(timestep))

        print(stiffnesses)
        print(stable_to)
        fig = plt.figure()
        fig.patch.set_facecolor('white')
        ax = fig.add_subplot(111)
        # ax.set_title('Percentage error against timestep')
        # ax.set_ylabel('Percentage error (%)')
        # ax.set_xlabel('Timestep (seconds)')
        ax.plot(stiffnesses, stable_to)
        plt.show()
Esempio n. 7
0
    def test_wall_bouncing(self):
        p = Particle([0, 0.5, 0], [0, 0, 0], 0.1)
        w = AAWall([1, 0, 1], [-1, 0, -1])
        col = AAWallCollision(p, w)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p.iterate(delta_t, implicit=True)
            last_time = time
        print("Final offset = {0}".format(p.pos[1]))
        particles_to_paraview([p], "wall_bounce_col", "../../run/wall_bounce_collision/", fps=60)
Esempio n. 8
0
def normal_collision():
    u_0 = -2
    diameter = 0.1
    stiffness = 1e5
    restitution = 0.8
    density = 2000
    mass = get_mass(density, diameter)

    col_duration = col_duration = pi * sqrt(mass / stiffness)

    for interval in [8, 16, 32, 64]:
        p1 = Particle(1, [0, 0, 0], [0, 0, 0],
                      diameter,
                      density=1e99,
                      get_gravity=lambda dummy: [0, 0, 0])
        p2 = Particle(2, [diameter, 0, 0], [u_0, 0, 0],
                      diameter,
                      density=density,
                      get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, stiffness, restitution=restitution)

        timestep = col_duration / interval

        last_time = 0
        for time in np.arange(0, col_duration + timestep, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p1.iterate(delta_t)
            p2.iterate(delta_t)
            last_time = time
            particles_to_file([p1, p2], "2_normal_force_" + str(interval),
                              "data/", time)
Esempio n. 9
0
    def test_side_wall_collision(self):
        p = Particle(1, [1, 0, 0], [-1, 0, 0], 0.1, get_gravity=lambda dummy: [0, 0, 0])
        w = AAWall([-0.5, -0.5, -0.5], [-0.5, 0.5, 0.5])
        col = AAWallCollision(p, w)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p.iterate(delta_t, implicit=True)
            last_time = time
        print("Final offset = {0}".format(p.pos[1]))
        particles_to_paraview([p], "side_wall_col", "../../run/side_wall_collision/")
Esempio n. 10
0
def simple_open_box():
    particles = []
    walls = generate_open_cube_box(1, [0, 0, 0])

    y = 0.5
    for x in np.arange(-0.4, 0.41, 0.2):
        for z in np.arange(-0.4, 0.41, 0.2):
            pos = np.array([x, y, z])
            particles.append(
                Particle(len(particles),
                         pos,
                         -np.array([pos[0], 0, pos[2]]),
                         diameter=0.1))
    y = 0.35
    for x in np.arange(-0.4, 0.41, 0.2):
        for z in np.arange(-0.4, 0.41, 0.2):
            pos = np.array([x, y, z])
            particles.append(
                Particle(len(particles),
                         pos,
                         np.array([pos[0], 0, pos[2]]),
                         diameter=0.1))

    cols = []
    for p in particles:
        for wall in walls:
            cols.append(AAWallCollision(p, wall))

    for i in range(len(particles)):
        for j in range(i + 1, len(particles)):
            cols.append(Collision(particles[i], particles[j]))

    timestep = 0.0005
    last_time = 0
    for time in np.arange(0, 15, timestep):
        delta_t = time - last_time
        for col in cols:
            col.calculate(delta_t)
        for p in particles:
            p.iterate(delta_t, implicit=True)
        last_time = time

    particles_to_paraview(particles, "simple_open_box",
                          "../../run/simple_open_box/")
Esempio n. 11
0
    def test_bouncing_collision(self):
        p1 = Particle(1, [0, 0.5, 0], [0, 0, 0], 0.1)
        p2 = Particle(2, [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, 1e5, restitution=0.8)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p1.iterate(delta_t)
            p2.iterate(delta_t)
            last_time = time

        predicted_overlap = p1.get_mass() * vect.mag(p1.get_gravity(p1)) / col.stiffness
        print("Predicted overlap = {0}".format(predicted_overlap))
        print("Calculated overlap = {0}".format(col.get_particle_overlap()))
        print("Percentage difference = {0}".format(100 * predicted_overlap / col.get_particle_overlap() - 100))
        TestCase.assertAlmostEqual(self, predicted_overlap, col.get_particle_overlap())
        particles_to_paraview([p1, p2], "bounce_col", "../../run/bounce_collision/")
Esempio n. 12
0
    def test_low_mem_logging(self):
        p1 = Particle(1, [0, 0.5, 0], [0, 0, 0], 0.1)
        p2 = Particle(2, [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, 1e5, restitution=0.8)
        timestep = 0.0005

        logger = Logger([p1, p2], "low_mem_logging", "../../run/low_mem_logging/")
        logger.log(0)

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p1.iterate(delta_t)
            p2.iterate(delta_t)
            last_time = time
            logger.log(time)

        predicted_overlap = p1.get_mass() * vect.mag(p1.get_gravity(p1)) / col.stiffness
        print("Predicted overlap = {0}".format(predicted_overlap))
        print("Calculated overlap = {0}".format(col.get_particle_overlap()))
        print("Percentage difference = {0}".format(100 * predicted_overlap / col.get_particle_overlap() - 100))
Esempio n. 13
0
def friction():
    u_0 = 1
    diameter = 0.1
    stiffness = 1e5
    restitution = 0.8
    density = 2000
    mass = get_mass(density, diameter)

    theoretical_overlap = get_mass(density, diameter) * 9.81 / stiffness

    col_duration = pi * sqrt(mass / stiffness)

    wall = AAWall([50, 0, 50], [-50, 0, -50])

    for interval in [8, 16, 32, 64]:
        fp = Particle(1, [0, diameter / 2 - theoretical_overlap, 0],
                      [u_0, 0, 0], diameter)
        fcol = AAWallCollision(fp,
                               wall,
                               1e5,
                               restitution=0.8,
                               friction_coefficient=0.6,
                               friction_stiffness=1e8)

        timestep = col_duration / interval

        last_time = 0
        log_step = 0.01
        last_log = None

        for time in np.arange(0, 0.5 + timestep, timestep):
            delta_t = time - last_time
            fcol.calculate(delta_t)
            fp.iterate(delta_t)
            last_time = time
            if last_log is None or time - last_log >= log_step:
                particles_to_file([fp], "1_friction_" + str(interval), "data/",
                                  time)
                last_log = time
Esempio n. 14
0
    def test_no_friction_slide(self):
        p1 = Particle(1, [0.001, 0.1, 0], [0, 0, 0], 0.1)
        p2 = Particle(2, [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, 1e5, restitution=0.8)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p1.iterate(delta_t)
            p2.iterate(delta_t)
            last_time = time

        particles_to_paraview([p1, p2], "no_friction_slide", "../../run/no_friction_slide/")
Esempio n. 15
0
    def test_simple_collision(self):
        p1 = Particle(1, [0, 0, 0], [0.1, 0, 0], 0.1, get_gravity=lambda dummy: [0, 0, 0])
        p2 = Particle(2, [1, 0, 0], [-0.1, 0, 0], 0.1, get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, 1e4, restitution=0.8)
        timestep = 0.001

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            col.calculate(delta_t)
            p1.iterate(delta_t)
            p2.iterate(delta_t)
            last_time = time

        particles_to_paraview([p1, p2], "simple_col", "../../run/simple_collision/")
Esempio n. 16
0
    def test_terminal_velocity(self):
        """ Tests simulated terminal velocity against a calculated value. """
        data = []
        for timestep in [0.1, 1, 2, 3, 4, 5, 6]:
            p = Particle(1, [0, 0, 0], [0, 0, 0])
            times = []
            speeds = []
            last_time = 0
            for time in np.arange(0, 40, timestep):
                p.iterate(time - last_time)
                times.append(time)
                speeds.append(vect.mag(p.vel))
                last_time = time
            data.append([times, speeds])

        fig = plt.figure()
        fig.patch.set_facecolor('white')
        ax = fig.gca()
        for d in data:
            ax.plot(d[0], d[1])
        plt.show()
        # Test if terminal velocity is within 0.1% of a calculated value.
        self.assertLess(np.abs(vect.mag(data[0][1][-1]) / 56.442091968912 - 1), 0.001)
Esempio n. 17
0
def simple_closed_box():
    manager = CVManager(10, 0.5, -0.5)
    particles = []
    walls = generate_closed_cube_box(1, [0, 0, 0])

    for y in [-0.18, -0.07, 0.1, 0.21, 0.32, 0.43]:
        for x in np.arange(-0.4, 0.41, 0.2):
            for z in np.arange(-0.4, 0.41, 0.2):
                pos = np.array(
                    [x + 0.05 * (rand() - 0.5), y, z + 0.05 * (rand() - 0.5)])
                particles.append(
                    Particle(len(particles),
                             pos,
                             np.array([pos[0], 0, pos[2]]),
                             diameter=0.1))

    wall_cols = []
    for p in particles:
        for wall in walls:
            wall_cols.append(
                AAWallCollision(p,
                                wall,
                                restitution=0.8,
                                friction_coefficient=0.4,
                                friction_stiffness=5e4))

    timestep = 0.0005
    last_time = 0
    max_time = 15
    bar = progressbar.ProgressBar(redirect_stdout=True, max_value=max_time)
    for t in np.arange(0, max_time, timestep):
        bar.update(t)
        manager.add_particles(particles)
        p_cols = manager.get_collisions()
        delta_t = t - last_time
        for col in p_cols + wall_cols:
            col.calculate(delta_t)
        for p in particles:
            p.iterate(delta_t, implicit=True)
        last_time = t
        manager.reset()
    bar.finish()
    particles_to_paraview(particles,
                          "simple_closed_box",
                          "../../run/simple_closed_box/",
                          ignore_warnings=True)
Esempio n. 18
0
    def test_wall_friction_comparison(self):
        wall = AAWall([1, 0, 1], [-1, 0, -1])

        fp = Particle(1, [0, 0.05, -0.25], [1, 0, 0], 0.1)
        fcol = AAWallCollision(fp, wall, 1e5, restitution=0.8, friction_coefficient=0.6, friction_stiffness=1e5)

        nfp = Particle(2, [0.001, 0.05, 0.25], [1, 0, 0], 0.1)
        nfcol = AAWallCollision(nfp, wall, 1e5, restitution=0.8, friction_coefficient=None, friction_stiffness=None)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            fcol.calculate(delta_t)
            nfcol.calculate(delta_t)
            fp.iterate(delta_t)
            nfp.iterate(delta_t)
            last_time = time

        particles_to_paraview([fp, nfp], "wall_friction_comp", "../../run/wall_friction_comparison/")
Esempio n. 19
0
    def test_drag_velocity_implicit_explicit_timestep(self):
        """ Tests simulated terminal velocity against a calculated value using implicit and explicit integration. """
        v = 5  # Fluid speed

        def get_vel_fluid(self):
            return [v, 0, 0]

        timesteps = np.arange(0.01, 5, 0.01)
        explicit_avgs = []
        implicit_avgs = []

        tau = None

        for timestep in timesteps:
            p_implicit = Particle(0, [0, 0, 0], [0, 0, 0], get_vel_fluid=get_vel_fluid,
                                  get_gravity=lambda dummy: [0, 0, 0], diameter=0.001)
            p_explicit = Particle(1, [0, 0, 0], [0, 0, 0], get_vel_fluid=get_vel_fluid,
                                  get_gravity=lambda dummy: [0, 0, 0], diameter=0.001)
            times = []
            explicit = []
            implicit = []
            analytic = []
            last_time = 0
            data = []
            duration = 40

            for time in np.arange(0, duration, timestep):
                p_explicit.iterate(time - last_time, implicit=False)
                p_implicit.iterate(time - last_time, implicit=True)
                times.append(time)
                explicit.append(vect.mag(p_explicit.vel))
                implicit.append(vect.mag(p_implicit.vel))
                tau = p_explicit.get_tau()
                analytic.append(v * (1 - math.exp(- time / tau)))
                last_time = time
            data.append([times, explicit])
            data.append([times, implicit])
            data.append([times, analytic])

            # fig = plt.figure()
            # ax = fig.gca()
            # plots = []
            # for d in data:
            #     plots.append(ax.plot(d[0], d[1])[0])
            # ax.set_xlabel('Time ($s$)')
            # ax.set_ylabel(r'Speed ($ms^{-1}$)')
            # plt.legend(plots, ['Explicit', 'Implicit', 'Analytic'], loc=4)
            # plt.show()

            explicit_dif_sum = 0
            implicit_dif_sum = 0

            for i in range(1, len(times)):  # Start at 1 to avoid division by zero at the initial conditions.
                explicit_dif = (explicit[i] - analytic[i]) / analytic[i]
                explicit_dif_sum += timestep * explicit_dif
                implicit_dif = (implicit[i] - analytic[i]) / analytic[i]
                implicit_dif_sum += timestep * implicit_dif
            explicit_avg = 100 * np.abs(explicit_dif_sum / duration)
            # print("Explicit average percentage difference = {0}".format(explicit_avg))
            implicit_avg = 100 * np.abs(implicit_dif_sum / duration)
            # print("Implicit average percentage difference = {0}".format(implicit_avg))
            explicit_avgs.append(explicit_avg)
            implicit_avgs.append(implicit_avg)

        for i in range(len(timesteps)):
            timesteps[i] /= tau
        fig = plt.figure()
        fig.patch.set_facecolor('white')
        ax = fig.gca()
        explicit_avgs_plot, = ax.plot(timesteps, explicit_avgs)
        implicit_avgs_plot, = ax.plot(timesteps, implicit_avgs)
        ax.set_xlabel(r'$timestep/\tau$')
        ax.set_ylabel(r'Average percentage difference')
        plt.legend([explicit_avgs_plot, implicit_avgs_plot], ['Explicit', 'Implicit'], loc=4)
        plt.show()
Esempio n. 20
0
    def test_friction_comparison(self):
        fp1 = Particle(1, [0.001, 0.1, -0.25], [0, 0, 0], 0.1)
        fp2 = Particle(2, [0, 0, -0.25], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        fcol = Collision(fp1, fp2, 1e5, restitution=0.8, friction_coefficient=0.6, friction_stiffness=1e5)

        nfp1 = Particle(3, [0.001, 0.1, 0.25], [0, 0, 0], 0.1)
        nfp2 = Particle(4, [0, 0, 0.25], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        nfcol = Collision(nfp1, nfp2, 1e5, restitution=0.8, friction_coefficient=None, friction_stiffness=None)
        timestep = 0.0005

        last_time = 0
        for time in np.arange(0, 10, timestep):
            delta_t = time - last_time
            fcol.calculate(delta_t)
            nfcol.calculate(delta_t)
            fp1.iterate(delta_t)
            fp2.iterate(delta_t)
            nfp1.iterate(delta_t)
            nfp2.iterate(delta_t)
            last_time = time

        particles_to_paraview([fp1, fp2, nfp1, nfp2], "friction_comp", "../../run/friction_comparison/")
Esempio n. 21
0
    def test_bouncing_collision_timesteps(self):
        p1 = Particle(1, [0, 0.5, 0], [0, 0, 0], 0.1)
        p2 = Particle(2, [0, 0, 0], [0, 0, 0], 0.1, density=1e99, get_gravity=lambda dummy: [0, 0, 0])
        col = Collision(p1, p2, 1e5, restitution=0.8)

        tau = p1.get_tau()
        timesteps = np.arange(0.0005, 0.001, 0.00001)
        overlap_errors = []
        for timestep in timesteps:
            last_time = 0
            for time in np.arange(0, 10, timestep):
                delta_t = time - last_time
                col.calculate(delta_t)
                p1.iterate(delta_t)
                p2.iterate(delta_t)
                last_time = time

            predicted_overlap = p1.get_mass() * vect.mag(p1.get_gravity(p1)) / col.stiffness
            percent_dif = 100 * np.abs(col.get_particle_overlap() / predicted_overlap) - 100
            overlap_errors.append(percent_dif)

        for i in range(len(timesteps)):
            timesteps[i] /= tau
        fig = plt.figure()
        fig.patch.set_facecolor('white')
        ax = fig.add_subplot(111)
        # ax.set_title('Percentage error against timestep')
        ax.set_ylabel('Percentage error (%)')
        ax.set_xlabel('Timestep (seconds)')
        ax.plot(timesteps, overlap_errors)
        plt.show()