-
Notifications
You must be signed in to change notification settings - Fork 3
Kernels
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 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:
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 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);