コード例 #1
0
def test_multiple_particles():
    """
        Function that checks if the energy is conserved for many particles. Is seen from the printed outputs.
    """
    # B.3 Many particles
    N = 100
    xi = 1
    v_0 = 0.15
    positions, min_radius = uf.random_positions_and_radius(N)
    random_angles = np.random.random(N) * (2 * np.pi)
    velocities = np.zeros((N, 2))
    velocities[:,
               0], velocities[:,
                              1] = np.cos(random_angles), np.sin(random_angles)
    velocities *= v_0
    radii = np.ones(N) * min_radius
    mass = np.ones(N)

    box_of_particles = ParticleBox(number_of_particles=N,
                                   restitution_coefficient=xi,
                                   initial_positions=positions,
                                   initial_velocities=velocities,
                                   masses=mass,
                                   radii=radii)
    simulation = Simulation(box_of_particles, stopping_criterion=0.5)
    simulation.simulate_until_given_number_of_collisions('testManyParticles',
                                                         output_timestep=0.1)
コード例 #2
0
def simulate_and_get_crater_size(number_of_particles, restitution_coefficient,
                                 initial_positions, initial_velocities, masses,
                                 radii, simulation):
    """
        Help function to initial a ParticleBox and simulate a crater formation by solving problem 5. After simulation
        the function computes the size of the newly made crater.
    :param number_of_particles: number of particles in the box
    :param restitution_coefficient: restitution coefficient of the system. Tells how much energy is kept after colliding
    :param initial_positions: array with shape (numb_particles, 2) to indicate starting point for particles
    :param initial_velocities: array with shape (numb_particles, 2) to indicate starting velocity for particles
    :param masses: array with shape (numb_particles) to indicate the mass of each particle
    :param radii: array with shape (numb_particles) to indicate the radius of each particle
    :param simulation: Simulation object to be used in the simulation
    :return: crater_size
    """
    # initialize system
    box_of_particles = ParticleBox(
        number_of_particles=number_of_particles,
        restitution_coefficient=restitution_coefficient,
        initial_positions=initial_positions,
        initial_velocities=initial_velocities,
        masses=masses,
        radii=radii)
    # update simulation object with the given system
    simulation.box_of_particles = box_of_particles
    simulation.time_at_previous_collision = np.zeros(box_of_particles.N)
    # simulate
    simulation.simulate_until_given_energy('craterFormation',
                                           output_timestep=0.01)
    # compute crater size
    crater_size = get_crater_size(initial_positions[1:, :],
                                  simulation.box_of_particles.positions[1:, :],
                                  radii[-1])
    return crater_size
コード例 #3
0
def test_two_particles():
    """
        Function to check the system for tests with two particles. Can both check that two particles hitting each
        other head on with opposite speeds change speeds, go back to the wall and then collide again. Can also check
        for a certain impact parameter that the scattering angle will be 90 degrees for similar particles.
    """
    # B.2 Two particles
    # first test of two particles hitting each other, bouncing and then colling again.
    N = 2
    xi = 1
    positions = np.array([[0.15, 0.5], [0.75, 0.5]])
    velocities = np.array([[0.05, 0], [-0.05, 0]])
    mass = np.ones(N)
    radius = np.ones(N) * 0.05
    # create system object
    box_of_particles = ParticleBox(number_of_particles=N,
                                   restitution_coefficient=xi,
                                   initial_positions=positions,
                                   initial_velocities=velocities,
                                   masses=mass,
                                   radii=radius)
    # create simulation object
    simulation = Simulation(box_of_particles, stopping_criterion=5)
    # simulate until the average number of collisions is equal to 5
    simulation.simulate_until_given_number_of_collisions('testTwoParticles',
                                                         output_timestep=0.5)
コード例 #4
0
def create_fractal_from_sticky_particles():
    """
        Function that creates fractal properties by allowing particles to stick together if a particle collides with
        a particle at rest. Initially the particle closest to the center is at rest and a fractal builds in time
    """
    N = 5000  # number of particles
    v_0 = 0.2  # initial speed of all particles
    xi = 1
    radius = 0.004  # radius of all particles
    positions = np.load(
        os.path.join(init_folder, f'uniform_pos_N_{N}_rad_{radius}.npy'))
    distance_to_center = norm(positions -
                              np.tile([0.5, 0.5], reps=(len(positions), 1)),
                              axis=1)
    closest_particle = np.argmin(distance_to_center)
    velocities = random_uniformly_distributed_velocities(N, v_0)
    velocities[closest_particle, :] = [
        0, 0
    ]  # particle closest to center is at rest
    radii = np.ones(N) * radius  # all particles have the same radius
    mass = np.ones(N)  # all particles have the same mass initially
    mass[
        closest_particle] = 10**10  # increase mass of particle at rest in order to identify them in a collision
    # initialize a ParticleBox with given parameters
    box_of_particles = ParticleBox(number_of_particles=N,
                                   restitution_coefficient=xi,
                                   initial_positions=positions,
                                   initial_velocities=velocities,
                                   masses=mass,
                                   radii=radii)
    # initialize simulation
    energy_stop = 1e-9
    simulation = Simulation(box_of_particles=box_of_particles,
                            stopping_criterion=energy_stop)

    # simulate until all particles is at rest
    simulation.simulate_until_given_energy('fractalCreation',
                                           output_timestep=1,
                                           sticky_particles=True)
    # save the system at rest with all particle positions to file
    np.save(file=os.path.join(results_folder,
                              f'fractalPositions_N_{N}_rad_{radius}'),
            arr=simulation.box_of_particles.positions)
コード例 #5
0
def test_one_particle():
    """
        Function to check that for a system wih one particle, the particle bounces of all walls in a endless loop
    """
    # B.1 One particle
    N = 1
    xi = 1
    position = np.array([0.9, 0.4]).reshape(1, 2)
    velocity = np.array([-0.5, -0.5]).reshape(1, 2)
    mass = np.ones(1).reshape(1, 1)
    radius = np.ones(1).reshape(1, 1) * 10**(-2)
    # create system object
    box_of_particles = ParticleBox(number_of_particles=N,
                                   restitution_coefficient=xi,
                                   initial_positions=position,
                                   initial_velocities=velocity,
                                   masses=mass,
                                   radii=radius)
    # create simulation object
    simulation = Simulation(box_of_particles, stopping_criterion=5)
    # simulate until the average number of collisions is >= 5
    simulation.simulate_until_given_number_of_collisions('testOneParticle',
                                                         output_timestep=0.2)
コード例 #6
0
def compute_diffusion_properties_from_mask_particles(single_bp_particle=False,
                                                     eq_start=False,
                                                     bigger_radius=False):
    """
        Functionality to compute the distance of particles starting close to the center of the box as a function of time
        in order to study diffusion properties. Function will save the results to file.
    """
    N = 2000  # number of particles
    v_0 = 0.2  # initial speed of all particles
    xi = 1
    radius = 0.007  # radius of all particles
    if bigger_radius:
        positions = np.load(
            os.path.join(
                init_folder,
                f'uniform_pos_around_bp_N_{N}_rad_{radius}_bp_rad_{radius * 3}.npy'
            ))
    else:
        positions = np.load(
            os.path.join(init_folder, f'uniform_pos_N_{N}_rad_{radius}.npy'))
    if eq_start:
        velocities = np.load(
            os.path.join(init_folder, f'eq_vel_N_{N}_rad_{radius}.npy'))
    else:
        velocities = random_uniformly_distributed_velocities(N, v_0)

    radii = np.ones(N) * radius  # all particles have the same radius
    mass = np.ones(N)  # all particles have the same mass

    distance_to_center = norm(positions -
                              np.tile([0.5, 0.5], reps=(len(positions), 1)),
                              axis=1)
    closest_particle = np.argmin(distance_to_center)
    if single_bp_particle:
        if not bigger_radius:
            mass[closest_particle] *= 10
        else:
            radii[closest_particle] *= 3

    validate_positions(positions, radius)

    number_of_runs = 10
    t_stop = 5
    timestep = 0.02
    simulation = Simulation(box_of_particles=None, stopping_criterion=t_stop)

    if single_bp_particle:
        simulation.mask = distance_to_center == distance_to_center[
            closest_particle]

    matrix_to_file = np.zeros((int(t_stop / timestep) + 1, 3))
    if single_bp_particle:
        matrix_to_file = np.zeros((int(t_stop / timestep) + 1, 5))

    for i in range(number_of_runs):
        print(f'Run number: {i+1}')
        if eq_start:
            np.random.shuffle(velocities)
        else:
            velocities = random_uniformly_distributed_velocities(N, v_0)
        if single_bp_particle:
            if not bigger_radius:
                velocities[closest_particle] *= 1

        # initialize a ParticleBox with given parameters
        box_of_particles = ParticleBox(number_of_particles=N,
                                       restitution_coefficient=xi,
                                       initial_positions=positions,
                                       initial_velocities=velocities,
                                       masses=mass,
                                       radii=radii)

        # update simulation object with the given system
        simulation.box_of_particles = box_of_particles
        simulation.time_at_previous_collision = np.zeros(box_of_particles.N)
        if single_bp_particle:
            time_array, bp_position_array, bp_velocity_array = \
                simulation.simulate_until_given_time_bp('brownianParticle', output_timestep=timestep,
                                                        save_positions=True)
            matrix_to_file[:, 0] = time_array
            matrix_to_file[:, 1] = bp_position_array[:, 0]
            matrix_to_file[:, 2] = bp_position_array[:, 1]
            matrix_to_file[:, 3] = bp_velocity_array[:, 0]
            matrix_to_file[:, 4] = bp_velocity_array[:, 1]
            if bigger_radius:
                np.save(file=os.path.join(
                    results_folder,
                    f'diffProperties_3r0m0_particle_tmax_{t_stop}_run_{i+200}'
                ),
                        arr=matrix_to_file)
            else:
                np.save(file=os.path.join(
                    results_folder,
                    f'diffProperties_r010m0_particle_tmax_{t_stop}_run_{i}_eq_speed'
                ),
                        arr=matrix_to_file)
        else:
            time_array, mean_quadratic_distance_array, mean_quadratic_speed_array = \
                simulation.simulate_until_given_time_mask_quantities('diffusionProperties', output_timestep=timestep,
                                                                     save_positions=True)

            matrix_to_file[:, 0] = time_array
            matrix_to_file[:, 1] = mean_quadratic_distance_array
            matrix_to_file[:, 2] = mean_quadratic_speed_array
            if eq_start:
                np.save(file=os.path.join(
                    results_folder,
                    f'diffProperties_r0m0_particle_tmax_{t_stop}_run_{i}_eq_start'
                ),
                        arr=matrix_to_file)
            else:
                np.save(file=os.path.join(
                    results_folder,
                    f'diffProperties_r0m0_particle_tmax_{t_stop}_run_{i+30}'),
                        arr=matrix_to_file)

        simulation.reset()
コード例 #7
0
def compute_mean_free_path():
    """
        Function that computes the mean free path in a simulation for the particles inside a radius of 0.1 from the
        center of the box. The results is computed for a different set of radius at given radius and below to see how
        the numerical results change as a function of the packing fraction/radius.
    """
    N = 2000  # number of particles
    v_0 = 0.2  # initial speed of all particles
    xi = 1
    initial_radius = 0.007  # radius of all particles
    positions = np.load(
        os.path.join(init_folder,
                     f'uniform_pos_N_{N}_rad_{initial_radius}.npy'))
    velocities = random_uniformly_distributed_velocities(N, v_0)
    mass = np.ones(N)  # all particles have the same mass

    number_of_parameters = 10
    radius_parameter = np.linspace(0.1, 1,
                                   number_of_parameters) * initial_radius

    number_of_runs = 10
    t_stop = 5
    simulation = Simulation(box_of_particles=None, stopping_criterion=t_stop)

    matrix_to_file = np.zeros((number_of_parameters, 2))

    for i in range(number_of_runs):
        print(f"Run: {i}")
        for counter, radius in enumerate(radius_parameter):
            # velocities = random_uniformly_distributed_velocities(N, v_0)
            np.random.shuffle(velocities)

            radii = np.ones(N) * radius  # all particles have the same radius

            # initialize a ParticleBox with given parameters
            box_of_particles = ParticleBox(number_of_particles=N,
                                           restitution_coefficient=xi,
                                           initial_positions=positions,
                                           initial_velocities=velocities,
                                           masses=mass,
                                           radii=radii)

            # update simulation object with the given system
            simulation.box_of_particles = box_of_particles
            simulation.time_at_previous_collision = np.zeros(
                box_of_particles.N)

            # simulate
            simulation.simulate_until_given_time_mask_quantities(
                'mfp',
                output_timestep=0.1,
                update_positions=True,
                save_positions=False)
            computed_mean_free_path =\
                simulation.box_of_particles.distance_to_collisions / simulation.box_of_particles.collision_count_particles
            mean_free_path_mask = np.mean(
                computed_mean_free_path[simulation.mask])
            matrix_to_file[counter, 0] = radius
            matrix_to_file[counter, 1] = mean_free_path_mask

            simulation.reset()

        # save results to file
        np.save(file=os.path.join(
            results_folder,
            f'mean_free_path_N_{N}_func_radius_run_{i}_eq_start'),
                arr=matrix_to_file)
コード例 #8
0
def compute_avg_energy_development_after_time():
    """
        Function to mainly solve problem 4 in the exam by saving how the energy develop at a short output step. Will
        save the average kinetic energy of all particles(together and separate for m0 and m particles) at all outputs
        and save to file.
    """
    N = 2000  # number of particles
    v_0 = 0.2  # initial speed of all particles
    radius = 0.007  # radius of all particles
    positions = np.load(
        os.path.join(init_folder, f'uniform_pos_N_{N}_rad_{radius}.npy'))
    # velocities = random_uniformly_distributed_velocities(N, v_0)
    radii = np.ones(N) * radius  # all particles have the same radius
    # first half will be m0 particles and second half is m particles with m=4*m0.
    mass = np.ones(N)
    mass[int(N / 2):] *= 4

    xi_list = [1, 0.9, 0.8
               ]  # will do for multiple values of the restitution coefficient

    number_of_realizations = 5

    # create simulation object
    t_stop = 1
    dt = 0.01  # timestep
    simulation = Simulation(box_of_particles=None, stopping_criterion=t_stop)

    for xi in xi_list:
        matrix_to_file = np.zeros(
            (int(t_stop / dt) + 1, 4)
        )  # matrix used to save information. Size given by stop and output
        for i in range(number_of_realizations):
            print(f"Run number: {i+1}")
            # new velocity vectors for each realization, but same initial positions
            velocities = random_uniformly_distributed_velocities(N, v_0)
            # initialize a ParticleBox with given parameters
            box_of_particles = ParticleBox(number_of_particles=N,
                                           restitution_coefficient=xi,
                                           initial_positions=positions,
                                           initial_velocities=velocities,
                                           masses=mass,
                                           radii=radii)
            # update simulation object with the given system
            simulation.box_of_particles = box_of_particles
            simulation.time_at_previous_collision = np.zeros(
                box_of_particles.N)

            time_array, energy_array_all, energy_array_m0, energy_array_m, mean_speed_array =\
                simulation.simulate_statistics_until_given_time('energyDevNEqParticles', output_timestep=dt,
                                                                equal_particles=False)

            # add results in a matrix with given form: time, avg_energy, avg_energy_m0 and avg_energy_m
            matrix_to_file[:, 0] += time_array
            matrix_to_file[:, 1] += energy_array_all
            matrix_to_file[:, 2] += energy_array_m0
            matrix_to_file[:, 3] += energy_array_m
            # reset simulation
            simulation.reset()
        matrix_to_file /= number_of_realizations  # get average values for multiple realizations
        # save to file
        np.save(file=os.path.join(results_folder,
                                  f'energyDevNEqParticles_N_{N}_xi_{xi}'),
                arr=matrix_to_file)
コード例 #9
0
def speed_distribution(use_equal_particles=True, number_of_runs=1):
    """
        Function to get speed of every particle after the system has reached equilibrium. Mainly solves problem 2 and
        3 in the exam. The procedure is based on initializing a system of many particles with the same initial speed.
        Then you start the simulation and let them collide until equilibrium have been reached. One then return the
        speed of each particle in order to create speed distribution plots.
    :param use_equal_particles: bool value that separates problem 2 and 3. If not equal: Second half will have m=4*m0
    :param number_of_runs: In order to achieve better statistics, take averages over multiple runs.
    """
    N = 2000  # number of particles
    xi = 1  # restitution coefficient
    v_0 = 0.2  # initial speed
    radius = 0.007  # radius of all particles
    positions = np.load(
        os.path.join(init_folder, f'uniform_pos_N_{N}_rad_{radius}.npy'))
    radii = np.ones(N) * radius  # all particles have the same radius
    mass = np.ones(N)  # all particles get initially the same mass
    energy_matrix = np.zeros(
        (N, 2))  # array with mass and speed to save to file

    if not use_equal_particles:
        # Problem 3: Second half of particles will have an mass which is bigger than the first half by a factor 4.
        mass[int(N / 2):] *= 4

    energy_matrix[:, 0] = mass  # mass does not change through the simulation

    # use stopping criterion that the avg_numb_collision should be equal to 2% of numb_particles.
    average_number_of_collisions_stop = N * 0.02
    simulation = Simulation(
        box_of_particles=None,
        stopping_criterion=average_number_of_collisions_stop)

    for run_number in range(number_of_runs):
        # use same initial positions but new initial velocities every run
        # update velocities by getting new random angles, taking cos and sin and multiply with the initial speed
        velocities = random_uniformly_distributed_velocities(N, v_0)

        if run_number == 0:
            # save initial speed as a reference point
            initial_speeds = norm(velocities, axis=1)
            energy_matrix[:, 1] = initial_speeds
            if use_equal_particles:
                np.save(file=os.path.join(
                    results_folder,
                    f'distributionEqParticles_N_{N}_init_energy_matrix'),
                        arr=energy_matrix)
            else:
                np.save(file=os.path.join(
                    results_folder,
                    f'distributionNEqParticles_N_{N}_init_energy_matrix'),
                        arr=energy_matrix)
        # initialize system
        box_of_particles = ParticleBox(number_of_particles=N,
                                       restitution_coefficient=xi,
                                       initial_positions=positions,
                                       initial_velocities=velocities,
                                       masses=mass,
                                       radii=radii)
        # update simulation object
        simulation.box_of_particles = box_of_particles
        simulation.time_at_previous_collision = np.zeros(box_of_particles.N)

        # simulate system until given stopping criteria, save speed of particles, reset simulation object and repeat
        if use_equal_particles:
            simulation.simulate_until_given_number_of_collisions(
                'distributionEqParticles', output_timestep=0.1)
            energy_matrix[:, 1] = norm(simulation.box_of_particles.velocities,
                                       axis=1)
            np.save(file=os.path.join(
                results_folder,
                f'distributionEqParticles_N_{N}_eq_energy_matrix_{run_number}'
            ),
                    arr=energy_matrix)
        else:
            simulation.simulate_until_given_number_of_collisions(
                'distributionNEqParticles', output_timestep=0.1)
            energy_matrix[:, 1] = norm(simulation.box_of_particles.velocities,
                                       axis=1)
            np.save(file=os.path.join(
                results_folder,
                f'distributionNEqParticles_N_{N}_eq_energy_matrix_{run_number}'
            ),
                    arr=energy_matrix)

        simulation.reset()
コード例 #10
0
def scattering_angle_func_impact_parameter():
    """
        Function to compute scattering angle as a function of the impact parameter b. Solves problem 1 from exam.
        Involves two particles, one big and massive, and see how the velocity changes for the smaller particle
        by colliding with the bigger particle.
    """
    N = 2
    xi = 1
    initial_position_big_particle = [0.5, 0.5]
    initial_velocity_small_particle = [0.2, 0]
    initial_velocity_big_particle = [0, 0]
    initial_positions = np.zeros((N, 2))
    initial_positions[1, :] = initial_position_big_particle
    initial_velocities = np.zeros_like(initial_positions)
    initial_velocities[0, :] = initial_velocity_small_particle
    initial_velocities[1, :] = initial_velocity_big_particle
    # given initial values from exam in numerical physics
    mass_array = np.array([1, 10**6])
    radius_array = np.array([0.001, 0.1])

    # initialize a simulation, where the box_of_particles is set for each parameter
    average_number_of_collisions_stop = 0.5
    simulation = Simulation(
        box_of_particles=None,
        stopping_criterion=average_number_of_collisions_stop)

    impact_parameters = np.linspace(-radius_array[1] * 1.5,
                                    radius_array[1] * 1.5, 500)
    scattering_angles = np.zeros_like(impact_parameters)

    for counter, impact_parameter in enumerate(impact_parameters):
        # update initial position of small particle
        initial_position_small_particle = [0.1, 0.5 + impact_parameter]
        initial_positions[0, :] = initial_position_small_particle
        # create new system of particles
        box_of_particles = ParticleBox(number_of_particles=N,
                                       restitution_coefficient=xi,
                                       initial_positions=initial_positions,
                                       initial_velocities=initial_velocities,
                                       masses=mass_array,
                                       radii=radius_array)
        # update the system in the simulation
        simulation.box_of_particles = box_of_particles
        simulation.time_at_previous_collision = np.zeros(box_of_particles.N)

        simulation.simulate_until_given_number_of_collisions(
            'scatteringAngle', output_timestep=1.0)
        velocity_small_particle_after_collision = simulation.box_of_particles.velocities[
            0, :]
        scattering_angles[counter] = compute_scattering_angle(
            np.array(initial_velocity_small_particle),
            velocity_small_particle_after_collision)
        simulation.reset(
        )  # set time and some parameters equal to zero to make simulation ready for new realization

    # save results in a matrix where each row gives impact parameter and scattering angle
    matrix_to_file = np.zeros((len(impact_parameters), 2))
    matrix_to_file[:, 0] = impact_parameters / np.sum(radius_array)
    matrix_to_file[:, 1] = scattering_angles
    # save to file
    np.save(file=os.path.join(results_folder,
                              'scattering_angle_func_impact_parameter'),
            arr=matrix_to_file)