Skip to content

Kernels

Elijah Andrews edited this page Apr 23, 2018 · 4 revisions

All of the kernels can be found in the kernels/ directory. This page explains the structure of the kernels, how they are compiled, and other implementation details.


There are three sets of kernels:

  • Broad phase collision detection:
    • assign_particles.cl
    • make_pp_collisions.cl
  • Collision resolution:
    • calculate_pp_collision.cl
    • calculate_pw_collision.cl
  • Particle iteration:
    • iterate_particle.cl

Broad Phase Collision Detection

Broad phase collision detection is performed with assign_particles.cl and make_pp_collisions.cl.

assign_particles.cl assigns particles to control volumes. It contains two kernels, assign_particle_count and assign_particles. assign_particle_count counts how many particles are in each control volume so that the control volume array can be created with the correct number of particles in each control volume. assign_particles then assigns actual particle IDs to the control volume array that is created based on the result of assign_particle_count.

The three arrays used are the particle count array, the CV start index array, and the sorted particle array. The particle count array contains a count for how many particles are in each control volume. The CV start index array contains indexes of where each control volume starts in the sorted particle array (-1 if there are no particles in the control volume). The sorted particle array contains a sorted list of particles where control volumes are consecutive. This is only useful in conjunction with the other two arrays.

The arrays used are as represented in this diagram:

Array structure diagram.

Collision Resolution

Collision resolution is performed in calculate_pp_collision.cl for particle-particle collisions, and calculate_pw_collision.cl for particle-wall collisions. Each kernel takes a list of collisions to be resolved (pp_collision and pw_collision, respectively). The collision is then calculated as per the DEM mathematics and the force is atomically added to the relevant particles.

There are a couple of warnings in these kernels. The first warning refers to excessive force caused by a calculation error, these do happen occasionally and the warning may be changed to simply re-calculate the forces until they're of a reasonable magnitude. The second warning refers to excessive overlap. Usually this is because there are a lot of particles and the stiffness isn't high enough to stop them overlapping a lot. There is a risk of particles phasing through one another or a wall if this behaviour is prolonged. This can be avoided by using appropriate values.

Particle Iteration

Particle iteration is performed in iterate_particle.cl. The mathematics can be found in the report. Position and velocity are iterated and the forces are reset to zero for the next iteration. If the domain is periodic then the appropriate checks are performed, if a particle leaves the domain on one side it is teleported back in on the other side.

There are two options that can be selected for the kernel, different functions for get_vel_fluid and get_gravity. Both of these take a particle and timestep and return a vector. get_vel_fluid returns the fluid velocity at the particle location, and get_gravity returns the gravity at the particle location. By default get_vel_fluid returns {0, 0, 0} and get_gravity returns {0, -9.81, 0}. Different options can be chosen by adding a separate file with the following code.

For get_vel_fluid:

#define DEFAULT_PARTICLE_FLUID_VEL 0

float3 get_vel_fluid(particle p, float delta_t) {
    // Code goes here.
}

For get_gravity:

#define DEFAULT_PARTICLE_GRAVITY 0

float3 get_gravity(particle p, float delta_t) {
    // Code goes here.
}

The default get_vel_fluid is only defined if DEFAULT_PARTICLE_FLUID_VEL is undefined.

The default get_gravity is only defined if DEFAULT_PARTICLE_GRAVITY is undefined.

These can be easily added to the iterate_particle kernel by using the getKernel utility function, for example:

char *iterate_particle_files[] = {"../util/kernelUtils.cl",
                                      "../kernels/get_gravity/no_gravity.cl",
                                      "../kernels/get_vel_fluid/tgv.cl",
                                      "../kernels/iterate_particle.cl"};
cl_kernel iterate_particle = getKernel(device, context, iterate_particle_files, 4, "iterate_particle", TRUE);