This tutorial will help you to setup up a simple pe simulation.
The scenario for this tutorial a is particle gas (spheres) confined by solid walls.
For this tutorial only a few includes are needed, namely:
The first important step is to define a BodyTuple. This tuple stores all body types which will be used during the simulation. This tuple helps to generate all the functions which need to be specialized for a particular body type.
Next the waLBerla environment is initialized, the random number generator is seeded and some simulation parameters are set.
The BlockForest is the main datastructure in the waLBerla framework. It is responsible for the domain decomposition and holds all the blocks with their data. For more information about the general design of the waLBerla framework please refer to Tutorial - Basics 1: waLBerla Data Structures: Blocks and Fields and the documentation of domain_decomposition::BlockStorage. You can choose the number of blocks you want to have in each direction. In a parallel simulation these blocks get assigned to different processes. You should make sure that you always have at least as many blocks as processes. The number of processes you want your simulation to run with is specified when you start your program with mpiexec.
There are two types of storages to store particle information. One is the global body storage which is responsible for very large particles. These particles are stored on all processes.
The other one is a block local storage for all bodies which are located within the subdomain of a block. You can find more information about this concept of data on blocks in Tutorial - Basics 1: waLBerla Data Structures: Blocks and Fields.
In addition to the block local storage also the coarse as well as the fine collision detection needs storage on each block. Therefore the corresponding data handling has to be registered.
Only one final component is missing for a successful simulation - the time integrator. Currently there exists two integrators cr::DEM for soft contacts and cr::HCSITS for hard contacts. These have to be setup as local objects.
We now have all our tools together and can start creating the simulation. First we have to specify the material parameters we want to use.
And we have to initialize all body type ids.
Then we can set up the confining walls.
The gas particles are generated with the help of grid generators. These generators are iterators which facilitate the construction of particles on a regular grid. Currently grid_generator::SCIterator (for a simple cubic lattice) as well as grid_generator::HCPIterator (for a hexagonal close packing lattice) are supported. The spheres are create with createSphere which returns a SphereID of the created sphere. This SphereID acts like a pointer to Sphere and can be used like that. If for various reasons the sphere was not created the return value is NULL.
After you have initialized all particles you should synchronize the simulation to make sure that all information is distributed correctly. Two synchronization methods are available syncNextNeighbors() and syncShadowOwners().
Since the setup is finished now we can run the simulation loop. The simulation loop is as simple as:
cr::ICR::timestep() evolves your simulation in time. The subsequent synchronization keeps all particles that are known to more than one process in sync.
After the simulation is finished we can collect the results. In this case we only calculate the mean velocity of all particles. The particles can be easily accessed via the LocalBodyIterator. This iterator allows us to iterate through all particles and access their properties.
Congratulation! You successfully created your first rigid body simulation. In the next tutorial we will look at possible extensions which can make your live easier.