Free cooling granular system (2D) in walls

Description:

This tutorial is used to simulate the homogeneous and inhomogeneous regimes of a free cooling granular system (2D) contained in a square box (four infinite walls, InfiniteWall). It mimics a laboratory model for the experimenting the behaviour of granular gases. For a 3D version of this code, see Free cooling granular system (3D) in walls.

The animation below shows the free cooling granular system/particles contained in a square (2D) box.

Simulation set up:

Particles are inserted into a square box, with infinite walls in both dimensions. Just like the Free cooling granular system (2D), a well-defined initial state with random particle positions and velocities is prepared in the following way:

  1. The particles first sit on a regular lattice and get a random velocity with a total momentum of zero.
  2. Then the simulation is started without dissipation and runs for a reasonable number of collisions per particle so that the system becomes homogeneous, "and the velocity distribution approaches a Maxwellian."
  3. The above state is then used as the initial configuration for the dissipative regimes.

About the code

First, we need to include the following headers:

Then, we define a new class Free cooling granular system (2D) in walls. Again, since we want to run 2D simulations, this class inherits from the Mercury2D class.

[FCD_2D_Walls:headers]
Definition: FreeCooling2DinWallsDemo.cpp:43
This adds on the hierarchical grid code for 2D problems.
Definition: Mercury2D.h:36

Data members of the class:\n

The FreeCooling2DinWallsDemo class has, but is not limited to, two (public) data members, namely a pointer to the species and number of particles

The key components of the class are explained in-turn, in the following:

Step 1: Define Walls/Periodic Boundaries
The particles are the inserted in a two dimensional box made up of four infinite walls.

wallHandler.clear();
w0.setSpecies(speciesHandler.getObject(0));
w0.set(Vec3D(-1, 0, 0), Vec3D(getXMin(), 0, 0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D( 1, 0, 0), Vec3D(getXMax(), 0, 0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D( 0,-1, 0), Vec3D(0, getYMin(), 0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D( 0, 1, 0), Vec3D(0, getYMax(), 0));
wallHandler.copyAndAddObject(w0);
void setSpecies(const ParticleSpecies *species)
Defines the species of the current wall.
Definition: BaseWall.cc:169
A infinite wall fills the half-space {point: (position_-point)*normal_<=0}.
Definition: InfiniteWall.h:48
void set(Vec3D normal, Vec3D point)
Defines a standard wall, given an outward normal vector s.t. normal*x=normal*point for all x of the w...
Definition: InfiniteWall.cc:118
Definition: Vector.h:51

Step 2: Create Particles
Now, the particle species is defined. The particles in this problem use the linear visco-elastic (normal) contact model (LinearViscoelasticSpecies). The dissipation and stiffness defining the contact model can be set in different ways. In this example these contact model parameters are defined.

auto species = speciesHandler.copyAndAddObject(LinearViscoelasticSpecies());
FC2D_Species = species;
species->setDensity(10000);
species->setDissipation(0.0);
species->setStiffness(1e3);
Species< LinearViscoelasticNormalSpecies > LinearViscoelasticSpecies
Definition: LinearViscoelasticSpecies.h:33
void setDensity(Mdouble density)
Definition: ParticleSpecies.cc:108

The particle properties are set subsequently. The particleHandler is cleared just to be sure it is empty, then the particle to be copied into the container is created and the set species is assigned to it.

particleHandler.clear();
p0.setSpecies(speciesHandler.getObject(0));
void setSpecies(const ParticleSpecies *species)
Definition: BaseParticle.cc:818
A spherical particle is the most simple particle used in MercuryDPM.
Definition: SphericalParticle.h:37

Step 3: Place Particles
After specifying the particle properties, the container is filled with copies of the particle. In this example, particles are placed in a lattice grid pattern, on evenly spaced positions.

int N1=static_cast<int>(sqrt(N))+1;
for (int i=0;i<N;i++) {
int ix = i % N1;
int iy = i / N1;
// set particle position
double x = (getXMax() - getXMin()) * (ix + 1) / (N1 + 1);
double y = (getYMax() - getYMin()) * (iy + 1) / (N1 + 1);
p0.setPosition(Vec3D(x, y, 0.0));
// set random velocities for the particle
p0.setVelocity(0.02 * Vec3D(random.getRandomNumber(-0.1,0.1), random.getRandomNumber(-0.1,0.1), 0.0));
p0.setRadius(0.0002);
p0.setSpecies(species);
particleHandler.copyAndAddObject(p0);
}
void setVelocity(const Vec3D &velocity)
set the velocity of the BaseInteractable.
Definition: BaseInteractable.cc:350
virtual void setPosition(const Vec3D &position)
Sets the position of this BaseInteractable.
Definition: BaseInteractable.h:239
virtual void setRadius(Mdouble radius)
Sets the particle's radius_ (and adjusts the mass_ accordingly, based on the particle's species)
Definition: BaseParticle.cc:553
const std::complex< Mdouble > i
Definition: ExtendedMath.h:51

Step 4: Centre of mass velocity
Next, the center of mass velocity is subtracted to ensure a reduced random velocity. This results into a center of mass velocity nearly equal to zero.

// Compute the center of mass velocity
double particle_mass = p0.getMass();
double M_b = N*particle_mass; // mass of the bulk system
Vec3D V_com = {0,0,0};
for (int k = 0; k < particleHandler.getNumberOfObjects() ; k++){
BaseParticle* p = particleHandler.getObject(k);
V_com += (particle_mass*p->getVelocity())/M_b;
}
// Compute the reduced velocity for each particle
for (int k = 0; k < particleHandler.getNumberOfObjects() ; k++){
BaseParticle* p = particleHandler.getObject(k);
p->setVelocity(p->getVelocity() - V_com);
}
virtual const Vec3D & getVelocity() const
Returns the velocity of this interactable.
Definition: BaseInteractable.cc:329
Definition: BaseParticle.h:54
Mdouble getMass() const
Returns the particle's mass.
Definition: BaseParticle.h:322

Actions After TimeStep:
The actionsAfterTimeStep() method specifies all actions that need to be performed in between time steps, i.e. Since, the simulation started with zero dissipation, after a reasonable number of collisions per particle, the system will be homogeneous, and the actionsAfterTimeStep() is used to set the initial configuration for the "next" dissipative regime.

void actionsAfterTimeStep() override{
// Time to switch on dissipation
if (getTime() > 4e5*getTimeStep())
{
FC2D_Species->setDissipation(0.25);
}
}
void setDissipation(Mdouble dissipation)
Allows the normal dissipation to be changed.
Definition: LinearViscoelasticNormalSpecies.cc:117

Main Function

In the main program, the FreeCooling2DinWallsDemo object is created, after which its basic properties are set: like, the number of particles, box dimensions, time step and saving parameters. Lastly, the problem is actually solved by calling its solve() method.

int main()
{
// Problem setup
problem.setName("FreeCooling2DinWallsDemo");
problem.N=2000;
problem.setGravity(Vec3D(0.0,0.0,0.0));
problem.setTimeStep(5e-5);
problem.setSaveCount(4000);
problem.setTimeMax(100.0);
problem.setMax({0.032,0.032,0.032});
problem.setHGridMaxLevels(1);
problem.setParticlesWriteVTK(true);
problem.wallHandler.setWriteVTK(true);
//Uncomment to set the number of threads (cores) for the identity-based OpenMP framework
//problem.setNumberOfOMPThreads(4);
problem.solve();
}
@ ONE_FILE
all data will be written into/ read from a single file called name_
int main(int argc, char *argv[])
Definition: T_protectiveWall.cpp:215
void setSaveCount(unsigned int saveCount)
Sets File::saveCount_ for all files (ene, data, fstat, restart, stat)
Definition: DPMBase.cc:408
void setName(const std::string &name)
Allows to set the name of all the files (ene, data, fstat, restart, stat)
Definition: DPMBase.cc:422
WallHandler wallHandler
An object of the class WallHandler. Contains pointers to all the walls created.
Definition: DPMBase.h:1447
void setFileType(FileType fileType)
Sets File::fileType_ for all files (ene, data, fstat, restart, stat)
Definition: DPMBase.cc:459
void setParticlesWriteVTK(bool writeParticlesVTK)
Sets whether particles are written in a VTK file.
Definition: DPMBase.cc:942
void setTimeStep(Mdouble newDt)
Sets a new value for the simulation time step.
Definition: DPMBase.cc:1234
void setTimeMax(Mdouble newTMax)
Sets a new value for the maximum simulation duration.
Definition: DPMBase.cc:873
void solve()
The work horse of the code.
Definition: DPMBase.cc:4270
void setMax(const Vec3D &max)
Sets the maximum coordinates of the problem domain.
Definition: DPMBase.cc:1082
void setGravity(Vec3D newGravity)
Sets a new value for the gravitational acceleration.
Definition: DPMBase.cc:1383
int N
Definition: FreeCooling2DinWallsDemo.cpp:117
void setHGridUpdateEachTimeStep(bool updateEachTimeStep)
Sets whether or not the HGrid must be updated every time step.
Definition: MercuryBase.cc:176
void setHGridMaxLevels(unsigned int HGridMaxLevels)
Sets the maximum number of levels of the HGrid in this MercuryBase.
Definition: MercuryBase.cc:476
void setHGridCellOverSizeRatio(Mdouble cellOverSizeRatio)
Sets the ratio of the smallest cell over the smallest particle.
Definition: MercuryBase.cc:463
void setWriteVTK(FileType)
Sets whether walls are written into a VTK file.
Definition: WallHandler.cc:467

References:

  1. Luding, S. (2005). Structure and cluster formation in granular media. Pramana, 64(6), 893-902.
  2. Brilliantov, N. V., & Pöschel, T. (2010). Kinetic theory of granular gases. Oxford University Press.
  3. Pöschel, T., & Luding, S. (Eds.). (2001). Granular gases (Vol. 564). Springer Science & Business Media

(Return to Overview of advanced tutorials)