Beginner tutorials

This page contains the following tutorials:

T1: Particle motion in outer space

Particle moving with a constant velocity in outer space.

Problem description:

The first tutorial is setup to simulate a particle moving with a constant velocity in the absence of gravity. You can find the simulation setup in Tutorial1_ParticleInOuterSpace.cpp The detailed description of this tutorial is presented below.

Headers:

First, include all headers that are necessary to setup the simulations. They come from the MercuryDPM kernel and the C++ standard libraries (see Developing a kernel feature). Headers files usually have a .h or .hpp extensions. For example:

So here we include three headers. The first

#include <Mercury3D.h>

means we are going to do a 3D problem. The second two

means we include the linear viscoelastic contact model.

Before main function:

Before the main function, a new class (named Tutorial1) is derived from Mercury3D (or Mercury2D).

class Tutorial1 : public Mercury3D
This adds on the hierarchical grid code for 3D problems.
Definition: Mercury3D.h:16
[T1:headers]
Definition: Tutorial1_ParticleInOuterSpace.cpp:22

Next, we override (modify) some of the functions of the inherited class. Most importantly, we override setupInitialConditions:

void setupInitialConditions() override
void setupInitialConditions() override
Use setupInitialConditions to define your particle and wall positions.
Definition: Tutorial1_ParticleInOuterSpace.cpp:27

In setupInitialConditions, we define the initial state of the system (particle and wall positions). In this case, we only create a single particle. An object of type SphericalParticle is created, and the particle properties (positions, radius and velocities) are set. Then the defined information is sent to the classParticleHandler, using the function classParticleHandler::copyAndAddObject

// create a new particle
// set species (material type)
p0.setSpecies(speciesHandler.getObject(0));
// set particle radius, position, velocity
p0.setRadius(0.01);
p0.setPosition(Vec3D(0.1 , 0.1, 0.1 ));
p0.setVelocity(Vec3D(0.1, 0.0, 0.0));
// pass particle to the particle handler (which contains all particles in the simulation)
particleHandler.copyAndAddObject(p0);
Vector3f p0
Definition: MatrixBase_all.cpp:2
A spherical particle is the most simple particle used in MercuryDPM.
Definition: SphericalParticle.h:16
Definition: Kernel/Math/Vector.h:30

Note, the species will be defined later. Here we create a particle on radius 0.01 which is initial at position (0.1,0.1,0.1) and has initial velocity (0.1,0.0,0.0) so it is moving in the x-direction.

Main function:

In the main function, the global parameters of the problem are defined. It includes gravity, spatial dimensions (x,y,z), total run time, the type of contact law, etc.
The object 'problem' is an instance of the defined class Tutorial1. Global parameters and species will point to the object 'problem'.

Constructor for SteadyAxisymAdvectionDiffusion problem
Definition: steady_axisym_advection_diffusion.cc:213

Then, the data members are defined as:

problem.setName("Tutorial1");
problem.setGravity(Vec3D(0.0, 0.0, 0.0));
problem.setXMax(1.0);
problem.setYMax(1.0);
problem.setZMax(1.0);
problem.setTimeMax(1.0);

Subsequently, the Species of the problem are defined. It means, the properties (density,stiffness) and the corresponding contact law (for this tutorial, see LinearViscoelasticSpecies). Initially, when a particle is created, it attains the properties of a default species type with ‘0’ as its index.

species.setDensity(2500.0); //sets the species type_0 density in kg/m3
// The normal spring stiffness and normal dissipation is computed such that
// collision time tc=0.005 and restitution coefficient rc=1.0
species.setStiffness(258.5);//sets the spring stiffness in kN/m.
species.setDissipation(0.0); //sets the dissipation.
problem.speciesHandler.copyAndAddObject(species);
void setDissipation(Mdouble dissipation)
Allows the normal dissipation to be changed.
Definition: LinearViscoelasticNormalSpecies.cc:96
void setStiffness(Mdouble new_k)
Allows the spring constant to be changed.
Definition: LinearViscoelasticNormalSpecies.cc:72
void setDensity(Mdouble density)
Definition: ParticleSpecies.cc:88

Here, 'species' is an object of the class: LinearViscoelasticSpecies. Data members are fitted to point to this object, and then, copied and added to their corresponding handler classSpeciesHandler.

Outputs:
Data output is vital to analyse simulations, which leads to defining ways to save the simulation data for post processing.
The simulations generate several types of data files.

// number of time steps skipped between saves (i.e. every 10-th time step is written to file)
problem.setSaveCount(50);
// creates file with particle positions, velocities, radii for multiple time steps (for plotting)
problem.dataFile.setFileType(FileType::ONE_FILE);
// file with contact forces, overlaps for multiple time steps (for plotting)
problem.fStatFile.setFileType(FileType::NO_FILE);
// file with all parameters of the last saved time step (for restarting)
problem.restartFile.setFileType(FileType::ONE_FILE);
// writes global properties like kinetic/potential energy and center of mass (for quick analysis)
problem.eneFile.setFileType(FileType::NO_FILE);
@ NO_FILE
file will not be created/read
@ ONE_FILE
all data will be written into/ read from a single file called name_

Thereby, data members and member functions are pointed to the object 'problem'.
For Paraview users, additional display options can be set as below

// whether the wall geometry is written into a vtu file (either once initially or for several time steps)
problem.wallHandler.setWriteVTK(FileType::ONE_FILE);
// whether the particle positions are written into a vtu file
problem.setParticlesWriteVTK(true);

After all the simulation parameters are set, we reach a point where we put all the above bits of code in action by the following statements

// set a time step 1/50th of collision time
problem.setTimeStep(0.005 / 50.0);
// start the solver (calls setupInitialConditions and initiates time loop)
problem.solve(argc, argv);



To run this problem go to the corresponding folder (like: MercuryDPM/MercuryBuild/Drivers/Tutorials) and start

./Tutorial1_ParticleInOuterSpace

The program runs until tmax is reached. Now all data is generated like Tutorial1.data, .restart and .xballs
If you turned on XBalls support in cmake, you can visualize the information in the .data file using

./Tutorial1.xballs

Alternatively, you can use ParaView to visualize the vtu fields

paraview --script=Tutorial1.py

Exercises

  1. Run Tutorial 1
    cd ~/MercuryDPM/MercuryBuild/Drivers/Tutorials/
    make # compile
    ./Tutorial1_ParticleInOuterSpace # run
    void run(const string &dir_name, LinearSolver *linear_solver_pt, const unsigned nel_1d, bool mess_up_order)
    Definition: two_d_poisson_compare_solvers.cc:317
  2. Plot in ParaView
    paraview --script=Tutorial1.py
    Confirm the particle is moving in x-direction.
  3. Change the code so that the particle is moving on the y-direction. Remove the old output files before re-running the code, to avoid plotting old data.
    vi ~/MercuryDPM/MercurySource/Drivers/Tutorials/Tutorial1_ParticleInOuterSpace.cpp #edit the source file
    rm Tutorial1*.* # remove old output files
    make # re-compile
    ./Tutorial1_ParticleInOuterSpace # re-run
    paraview --script=Tutorial1.py # re-plot
    void plot()
    Plot.
    Definition: sphere_scattering.cc:180
    void source(const Vector< double > &x, Vector< double > &f)
    Source function.
    Definition: unstructured_two_d_circle.cc:46
    void output(std::ostream &outfile, const unsigned &nplot)
    Overload output function.
    Definition: overloaded_element_body.h:490
  4. Change the code so that the particle is moving diagonally in x,y and z.


T2: Particle motion on earth

Particle falling due to gravity.

Problem description:

In Tutorial2_ParticleUnderGravity.cpp, we simulate a particle when dropped under the influence of gravity. Basically, this tutorial is an extension of Tutorial1_ParticleInOuterSpace.cpp with few minor changes.
All we need to do is to change the initial particle position and velocity in the inherited class Tutorial2.

p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.05);
p0.setPosition(Vec3D(0.5 * getXMax(), 0.5 * getYMax(), getZMax()));
p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
particleHandler.copyAndAddObject(p0);

Also, gravity is turned on in the negative z-direction, using setGravity:

problem.setName("Tutorial2");
problem.setGravity(Vec3D(0.0, 0.0, -9.81));
problem.setXMax(1.0);
problem.setYMax(1.0);
problem.setZMax(5.0);
problem.setTimeMax(1.5);

Exercises

  1. Run the code.
    cd ~/MercuryDPM/MercuryBuild/Drivers/Tutorials/
    make # compile
    ./Tutorial2_ParticleUnderGravity # run
  2. Plot the particle falling under gravity in ParaView
    paraview --script=Tutorial2.py
    [T2:headers]
    Definition: Tutorial2_ParticleUnderGravity.cpp:22
  3. Give the particle an initial velocity in the x-direction so you can see the parabolic flight.
    vi ~/MercuryDPM/MercurySource/Drivers/Tutorials/Tutorial2_ParticleUnderGravity.cpp #edit the source file
    rm Tutorial2*.* # remove old output files
    make # re-compile
    ./Tutorial2_ParticleUnderGravity # re-run
    paraview --script=Tutorial2.py # re-plot
  4. Change the direction of gravity to point in the positive y-direction.


T3: Bouncing ball (elastic)

Particle bouncing off the blue wall.

Problem description:

The Tutorial3_BouncingBallElastic.cpp simulates a particle bouncing off a wall. It is assumed the collision between the particle and the wall is elastic by implying that the restitution coefficient is unity. It means that the particle velocity before and after collision remains the same. Additionally, we will learn how to add a wall over which the ball bounces.

Headers:

The header InfiniteWall.h is included.

Before the main class:

The class InfiniteWall is included in the inherited class Tutorial3:

class Tutorial3 : public Mercury3D
{
public:
void setupInitialConditions() override {
// add a particle of 1cm diameter at height zMax
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.5 * getXMax(), 0.5 * getYMax(), getZMax()));
p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
// add a bottom wall at zMin
w0.set(Vec3D(0.0, 0.0, -1.0), Vec3D(0, 0, getZMin()));
}
};
std::enable_if<!std::is_pointer< U >::value, U * >::type copyAndAddObject(const U &object)
Creates a copy of a Object and adds it to the BaseHandler.
Definition: BaseHandler.h:360
T * getObject(const unsigned int id)
Gets a pointer to the Object at the specified index in the BaseHandler.
Definition: BaseHandler.h:621
void setSpecies(const ParticleSpecies *species)
Defines the species of the current wall.
Definition: BaseWall.cc:148
Mdouble getXMax() const
If the length of the problem domain in x-direction is XMax - XMin, then getXMax() returns XMax.
Definition: DPMBase.h:610
SpeciesHandler speciesHandler
A handler to that stores the species type i.e. LinearViscoelasticSpecies, etc.
Definition: DPMBase.h:1433
WallHandler wallHandler
An object of the class WallHandler. Contains pointers to all the walls created.
Definition: DPMBase.h:1453
ParticleHandler particleHandler
An object of the class ParticleHandler, contains the pointers to all the particles created.
Definition: DPMBase.h:1443
Mdouble getYMax() const
If the length of the problem domain in y-direction is YMax - YMin, then getYMax() returns XMax.
Definition: DPMBase.h:622
Mdouble getZMax() const
If the length of the problem domain in z-direction is ZMax - ZMin, then getZMax() returns ZMax.
Definition: DPMBase.h:634
Mdouble getZMin() const
If the length of the problem domain in z-direction is ZMax - ZMin, then getZMin() returns ZMin.
Definition: DPMBase.h:628
A infinite wall fills the half-space {point: (position_-point)*normal_<=0}.
Definition: InfiniteWall.h:27
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:97
[T3:headers]
Definition: Tutorial3_BouncingBallElastic.cpp:26
void setupInitialConditions() override
Use setupInitialConditions to define your particle and wall positions.
Definition: Tutorial3_BouncingBallElastic.cpp:30

Where the object "w0" is an instance of the class InfiniteWall. Then, the function "copyAndAddObject" copy and add the object to its corresponding handler. The above set of statements, create and place the wall at \( Z_{min} \).
Note: Don’t forget to include the InfiniteWall.h header, as shown in the header section. In some sense, creation and addition of a wall is similar to creation and addition of a particle.

Exercises:

  1. Run Tutorial3 and visualise the outcome in ParaView.
  2. Visualise the gravitational ($mgh$) and kinetic energy ( \(\frac12mv^2\)) of the particle over time using gnuplot.
    gnuplot> set xlabel "Time (s)"
    gnuplot> set ylabel "Kinetic Energy (J)"
    gnuplot> plot 'Tutorial3.ene' using 1:3 with linespoints
    void gnuplot(std::string command)
    Plots to a gnuplot window.
    Definition: MiscHelpers.cc:17
    void set(Container &c, Position position, const Value &value)
    Definition: stdlist_overload.cpp:36
    What collision time/restitution coefficient do you expect/observe?
  3. Increase contact time by a factor 100 and rerun the simulation. What do you observe?
  4. Set restitution to \(0.5\) and rerun the simulation. What do you observe? This idea is expanded in the next exercise


T4: Bouncing ball with dissipation (inelastic)

Particle bouncing off the blue wall with restitution coefficient.

Problem description:

In Tutorial4_BouncingBallInelastic.cpp, the difference between an elastic and inelastic collision between a particle and a wall is illustrated. The only difference between Tutorial3_BouncingBallElastic.cpp and Tutorial4_BouncingBallInelastic.cpp is the value of the restitution coefficient:

double rc = 0.88; // restitution coefficient
list rc
Definition: plotDoE.py:16

See Bouncing ball - inelastic (code) for more details.

Exercises:

  1. In the .cpp file change 'problem.eneFile.setFileType' from NO_FILE to ONE_FILE to create the .ene file, recompile using make and start the code again. Now we can show the energy graph in gnuplot using
    gnuplot> set xlabel "Time (s)"
    gnuplot> set ylabel "Particle's centre of mass in z-direction (m)"
    gnuplot> plot 'Tutorial4.ene' using 1:8 with linespoints
  2. Change the coefficient of restitution rc to 1.0 and replot the energy.
  3. Now try 0.2.
  4. Now try 0.0.
  5. Now add the commands to create the vtu files so you can visualise in ParaView.


T5: Elastic collision (2 particles)

Particles moving towards each other.

Problem description:
So far, in the above tutorials, we have seen how a particle and a wall interact during a collision. In this tutorial, we illustrate how two particles interact using Tutorial5_ElasticCollision.cpp. For this purpose, we need two particles. The particles may or may not be of the same species type. But, here we shall assume they are of same species and same size.

Before the main function

class Tutorial5 : public Mercury3D
{
public:
void setupInitialConditions() override {
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005); //particle-1 radius
p0.setPosition(Vec3D(0.25 * getXMax(), 0.5 * getYMax(), 0.5 * getZMax()));
p0.setVelocity(Vec3D(0.25, 0.0, 0.0));
particleHandler.copyAndAddObject(p0); // 1st particle created
p0.setRadius(0.005); // particle-2 radius
p0.setPosition(Vec3D(0.75 * getXMax(), 0.5 * getYMax(), 0.5 * getZMax()));
p0.setVelocity(Vec3D(-0.25, 0.0, 0.0));
particleHandler.copyAndAddObject(p0); // 2nd particle created
}
};
[T5:headers]
Definition: Tutorial5_ElasticCollision.cpp:22
void setupInitialConditions() override
This function allows to set the initial conditions for our problem to be solved, by default particle ...
Definition: Tutorial5_ElasticCollision.cpp:25

On comparison between the above class and class Tutorial1, we see how an additional particle is added. Two particles are created, and positioned oppositely apart at a certain distance between them. Both the particles, have a certain velocity directing them towards each other.

Exercises:

  1. Add the lines to create the particle and wall vtu files so you can plot in ParaView.
  2. Change the size of the 1st ball from 0.05 m to 0.07 m and re-plot to see the difference.

T6: Elastic collisions with periodic boundaries

(a) Illustrates the idea behind periodic boundaries, particle exiting boundary b2 re-enters through boundary b1 (b) Illustrates the problem setup.

Problem description:

In order to have multiple collisions, Tutorial5_ElasticCollision.cpp is fitted with periodic boundaries in X.

Headers:

The header PeriodicBoundary.h is included.

Before the main function:

class Tutorial6 : public Mercury3D
{
public:
void setupInitialConditions() override {
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.015);//particle-1
p0.setPosition(Vec3D(0.15 * getXMax(), 0.5 * getYMax(), 0.5 * getZMax()));
p0.setVelocity(Vec3D(0.25, 0.0, 0.0));
p0.setRadius(0.005);// particle-2
p0.setPosition(Vec3D(0.75 * getXMax(), 0.5 * getYMax(), 0.5 * getZMax()));
p0.setVelocity(Vec3D(-0.25, 0.0, 0.0));
b0.set(Vec3D(1.0, 0.0, 0.0), getXMin(), getXMax());
}
};
Mdouble getXMin() const
If the length of the problem domain in x-direction is XMax - XMin, then getXMin() returns XMin.
Definition: DPMBase.h:603
BoundaryHandler boundaryHandler
An object of the class BoundaryHandler which concerns insertion and deletion of particles into or fro...
Definition: DPMBase.h:1458
Defines a pair of periodic walls. Inherits from BaseBoundary.
Definition: PeriodicBoundary.h:20
void set(Vec3D normal, Mdouble distanceLeft, Mdouble distanceRight)
Defines a PeriodicBoundary by its normal and positions.
Definition: PeriodicBoundary.cc:63
[T6:headers]
Definition: Tutorial6_ElasticCollisionPeriodic.cpp:23
void setupInitialConditions() override
This function allows to set the initial conditions for our problem to be solved, by default particle ...
Definition: Tutorial6_ElasticCollisionPeriodic.cpp:26

In the Class Tutorial6
(i) we create two particles of same type and different sizes. (ii) we setup periodic boundaries in X-direction as

b0.set(Vec3D(1.0, 0.0, 0.0), getXMin(), getXMax());
boundaryHandler.copyAndAddObject(b0);

Where "b0" is an instance of the class PeriodicBoundary. Then, the object is copied and added to its corresponding handler: classBoundaryHandler.

Exercise

  1. Add a second periodic wall in the y-direction.
  2. Change the initial velocity of wall of the particles so that it goes through both periodic walls.
  3. Advanced: How do you think the two-periodic walls interact in the corner?

T7: Motion of a particle in a two dimensional (2D) box

Particle motion in a box (blue and black denote the walls).

Problem description:

In previous tutorials, we have seen how a particle interacts with a wall and itself. In this tutorial, we will design boxes of different shapes by using more than one wall. As an example, in absence of gravity, we will simulate a particle moving in a two dimensional square shaped box. We consider two dimensions only for the sake of simplicity. The same idea was introduced in Tutorial3_BouncingBallElastic.cpp.

Before the main function:

class Tutorial7 : public Mercury3D
{
public:
void setupInitialConditions() override {
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.5 * getXMax(), 0.5 * getYMax(), 0.0));
p0.setVelocity(Vec3D(1.2, 1.3, 0.0));
w0.set(Vec3D(1.0, 0.0, 0.0), Vec3D(getXMax(), 0.0, 0.0));
w0.set(Vec3D(-1.0, 0.0, 0.0), Vec3D(getXMin(), 0.0, 0.0));
w0.set(Vec3D(0.0, 1.0, 0.0), Vec3D(0.0, getYMax(), 0.0));
w0.set(Vec3D(0.0, -1.0, 0.0), Vec3D(0.0, getYMin(), 0.0));
}
};
Mdouble getYMin() const
If the length of the problem domain in y-direction is YMax - YMin, then getYMin() returns YMin.
Definition: DPMBase.h:616
[T7:headers]
Definition: Tutorial7_ParticleIn2DBox.cpp:23
void setupInitialConditions() override
This function allows to set the initial conditions for our problem to be solved, by default particle ...
Definition: Tutorial7_ParticleIn2DBox.cpp:26

In this class, we setup a 2D square shaped box or a polygon by adding more walls as shown above. In total, we have 4 walls forming our box within which the particle will traverse.
Note: As we simulate in 2D, no walls are set in z-direction.

Main function:

As our simulation is two dimensional, we set the system dimensions as 2

problem.setSystemDimensions(2);

The complete code for the above problem description can be found in Tutorial7_ParticleIn2DBox.cpp.

Exercise

  1. Change the angle of left (x-wall) so it tilts at 45 degrees.
  2. Add a 5th wall and change the positions of each such that you are simulating particles in a pentagon.

T8: Motion of a particle in a box with an obstacle

Problem description:

We extend the problem setup of Tutorial 7, by adding a rectangular block as shown in the above figure. To create this block of wall or obstacle, we will use the Class IntersectionOfWalls. Before we go ahead it is advised to know the difference between an infinite wall and finite wall, see Different types of walls. As an example, we create an obstacle using a set of finite walls and place it within the box created using a set of infinite walls. See the above figure.

Headers:

The header IntersectionOfWalls.h is included.

Before the main function:

To add intersection walls, we use:

w1.setSpecies(speciesHandler.getObject(0));
w1.addObject(Vec3D(-1.0, 0.0, 0.0), Vec3D(0.75 * getXMax(), 0.0, 0.0));
w1.addObject(Vec3D(1.0, 0.0, 0.0), Vec3D(0.25 * getXMax(), 0.0, 0.0));
w1.addObject(Vec3D(0.0, -1.0, 0.0), Vec3D(0.0, 0.75 * getYMax(), 0.0));
w1.addObject(Vec3D(0.0, 1.0, 0.0), Vec3D(0.0, 0.25 * getYMax(), 0.0));
wallHandler.copyAndAddObject(w1);
A IntersectionOfWalls is convex polygon defined as an intersection of InfiniteWall's.
Definition: IntersectionOfWalls.h:38
void addObject(Vec3D normal, Vec3D point)
Adds a wall to the set of infinite walls, given a normal vector pointing into the wall (i....
Definition: IntersectionOfWalls.cc:117
void setSpecies(const ParticleSpecies *species)
sets species of subwalls as well
Definition: IntersectionOfWalls.cc:51

where "w1" is an instance of the class IntersectionOfWalls. This surface (wall) will have the properties of the index 0: "getObject(0)". Then, the object is copied and added to its corresponding handler: wallHandler.

Exercise

  1. Change the inner shape to a triangle.
  2. Change the outer wall to a doubly periodic box.

T9: Motion of a ball over an inclined plane (Sliding + Rolling)

Problem description:

the motion of three particles over an inclined plane is presented in Tutorial9_InclinedPlane.cpp. Here, the particles are fitted with different features.

Headers:

For Tutorial9_InclinedPlane.cpp, the header which implements the elastic properties and contact force model has been changed. In order to include the rolling and sliding effects, LinearViscoelasticFrictionSpecies.h is used.

Before the main function:

class Tutorial9 : public Mercury3D
{
public:
void setupInitialConditions() override {
//sets the particle to species type-1
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.05 * getXMax(), 0.25 * getYMax(), getZMin() + p0.getRadius()));
p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
//sets the particle to species type-2
p0.setSpecies(speciesHandler.getObject(1));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.05 * getXMax(), 0.5 * getYMax(), getZMin() + p0.getRadius()));
p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
//sets the particle to species type-3
p0.setSpecies(speciesHandler.getObject(2));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.05 * getXMax(), 0.75 * getYMax(), getZMin() + p0.getRadius()));
p0.setVelocity(Vec3D(0.0, 0.0, 0.0));
w0.set(Vec3D(0.0, 0.0, -1.0), Vec3D(0.0, 0.0, getZMin()));
}
};
[T9:headers]
Definition: Tutorial9_InclinedPlane.cpp:23
void setupInitialConditions() override
This function allows to set the initial conditions for our problem to be solved, by default particle ...
Definition: Tutorial9_InclinedPlane.cpp:26

Three particles are fitted with radius, initial positions and initial velocities.Then, all particles are copied and added to their corresponding handler.
It is defined the object 'w0' as an instance of the class InfiniteWall. For this tutorial, the surface will have the same properties of "object0". It means the surface and the first particle will have the same elastic properties.

Main function:

This simulation contains particles and walls made from three different species (particle-0 and the wall belongs to species-0, particle-1 belongs to species-1, particle-2 belongs to species-2) Hence, three species, and the interactions between the three species, need to be defined.

int main(int argc, char* argv[])
{
// Instantiate an object of class Tutorial 9
// Problem setup
problem.setName("Tutorial9");
problem.removeOldFiles();
double angle = constants::pi / 180.0 * 20.0;
problem.setGravity(Vec3D(sin(angle), 0.0, -cos(angle)) * 9.81);
problem.setXMax(0.3);
problem.setYMax(0.3);
problem.setZMax(0.05);
problem.setTimeMax(0.4);
// Set the species (material properties such as density and stiffness) of particles and walls
// (in this case, particle-0 and the wall are made from species-0, particle-1 belongs to species-1, particle-2 belongs to species-2)
// Species-0 properties
// The normal spring stiffness and normal dissipation is computed and set as
// For collision time tc=0.005 and restitution coefficient rc=0.88,
species0.setDensity(2500.0);//sets the species type_0 density
species0.setStiffness(259.018);//sets the spring stiffness.
species0.setDissipation(0.0334);//sets the dissipation.
species0.setSlidingStiffness(2.0 / 7.0 * species0.getStiffness());
species0.setRollingStiffness(2.0 / 5.0 * species0.getStiffness());
auto ptrToSp0=problem.speciesHandler.copyAndAddObject(species0);
// Species-1 properties
species1.setDensity(2500.0);//sets the species type-1 density
species1.setStiffness(259.018);//sets the spring stiffness
species1.setDissipation(0.0334);//sets the dissipation
species1.setSlidingStiffness(2.0 / 7.0 * species1.getStiffness());
species1.setRollingStiffness(2.0 / 5.0 * species1.getStiffness());
auto ptrToSp1=problem.speciesHandler.copyAndAddObject(species1);
// Properties of contacts between species-0 and species-1
// (no new species is defined since the mixed species is automatically created)
auto species01 = problem.speciesHandler.getMixedObject(ptrToSp0,ptrToSp1);
species01->setStiffness(259.018);//sets the spring stiffness
species01->setDissipation(0.0334);//sets the dissipation
species01->setSlidingStiffness(2.0 / 7.0 * species01->getStiffness());
species01->setRollingStiffness(2.0 / 5.0 * species01->getStiffness());
species01->setSlidingFrictionCoefficient(0.5);
species01->setRollingFrictionCoefficient(0.0);
// Species 2 properties
species2.setDensity(2500.0);//sets the species type-2 density
species2.setStiffness(258.5);//sets the spring stiffness
species2.setDissipation(0.0);//sets the dissipation
species2.setSlidingStiffness(2.0 / 7.0 * species2.getStiffness());
species2.setRollingStiffness(2.0 / 5.0 * species2.getStiffness());
auto ptrToSp2 = problem.speciesHandler.copyAndAddObject(species2);
// Properties of contacts between species-0 and species-2
auto species02 = problem.speciesHandler.getMixedObject(ptrToSp0, ptrToSp2);
species02->setStiffness(259.018);//sets the stiffness
species02->setDissipation(0.0334);//sets the dissipation
species02->setSlidingStiffness(2.0 / 7.0 * species02->getStiffness());
species02->setRollingStiffness(2.0 / 5.0 * species02->getStiffness());
species02->setSlidingFrictionCoefficient(0.5);
species02->setRollingFrictionCoefficient(0.5);
// Note: Properties of contacts between species-0 and species-1 are never defined, since no contacts between those
// two materials occurs in this simulation; note: if no properties are defined, then default properties are assumed,
// mostly harmonic means of the properties of both individual species
//Output
problem.setSaveCount(25);
problem.dataFile.setFileType(FileType::ONE_FILE);
problem.restartFile.setFileType(FileType::ONE_FILE);
problem.fStatFile.setFileType(FileType::ONE_FILE);
problem.eneFile.setFileType(FileType::NO_FILE);
// whether the wall geometry is written into a vtu file (either once initially or for several time steps)
problem.wallHandler.setWriteVTK(FileType::ONE_FILE);
// whether the particle positions are written into a vtu file
problem.setParticlesWriteVTK(true);
// set a time step 1/50th of collision time
problem.setTimeStep(0.005 / 50.0);
// start the solver (calls setupInitialConditions and initiates time loop)
problem.solve(argc, argv);
return 0;
}
AnnoyingScalar cos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:136
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
int main(int argc, char *argv[])
Definition: T_protectiveWall.cpp:194
void setRollingFrictionCoefficient(Mdouble new_mu)
Allows the (dynamic) Coulomb friction coefficient to be changed; also sets mu_s by default.
Definition: FrictionSpecies.cc:165
void setRollingStiffness(Mdouble new_kt)
Allows the spring constant to be changed.
Definition: FrictionSpecies.cc:128
Mdouble getStiffness() const
Allows the spring constant to be accessed.
Definition: LinearViscoelasticNormalSpecies.cc:83
void setSlidingStiffness(Mdouble new_kt)
Allows the spring constant to be changed.
Definition: SlidingFrictionSpecies.cc:83
void setSlidingFrictionCoefficient(Mdouble new_mu)
Allows the (dynamic) Coulomb friction coefficient to be changed; also sets mu_s by default.
Definition: SlidingFrictionSpecies.cc:120
double angle(const double &t)
Angular position as a function of time t.
Definition: jeffery_orbit.cc:98
const Mdouble pi
Definition: ExtendedMath.h:23

Exercise

  1. Increase the plane angle until all three particles roll.
  2. Set the rolling and sliding friction so that all the particles only roll at a 25 degree inclined plane
  3. What happens when \( mu_s < \mu_{ro}\) ?
  4. Set \( \mu_{ro} = 0\); how does the speed of the particle at time tmax depend on \(\mu_s\) ? Can you explain it?


T10: How to load restart and data files

Problem description:

Sometimes if your computer crashes or you want to start over with minor changes in the data, you like to restart.

Headers:

No species, particles or walls are configured as in this tutorial this is already configured in the restart and data file.

Main function:

int main(int argc, char* argv[])
{
//writeToFile is used here to create a restart and a data file, which will be loaded below.
helpers::writeToFile("Tutorial10.ini.restart",
"restart_version 1.0 name Tutorial10\n"
"dataFile name Tutorial10.data fileType ONE_FILE saveCount 10 counter 0 nextSavedTimeStep 0\n"
"fStatFile name Tutorial10.fstat fileType NO_FILE saveCount 10 counter 0 nextSavedTimeStep 0\n"
"eneFile name Tutorial10.ene fileType ONE_FILE saveCount 10 counter 0 nextSavedTimeStep 0\n"
"restartFile name Tutorial10.restart fileType ONE_FILE saveCount 10 counter 0 nextSavedTimeStep 0\n"
"statFile name Tutorial10.stat fileType ONE_FILE saveCount 10 counter 0 nextSavedTimeStep 0\n"
"xMin 0 xMax 2 yMin 0 yMax 2 zMin 0 zMax 2\n"
"timeStep 1e-03 time 0 ntimeSteps 0 timeMax 10\n"
"systemDimensions 3 particleDimensions 3 gravity 0 0 -1\n"
"Species 1\n"
"LinearViscoelasticSpecies id 0 density 1.9098593 stiffness 2000 dissipation 10\n"
"Walls 1\n"
"InfiniteWall id 0 indSpecies 0 position 0 0 0 orientation 0 0 0 1 velocity 0 0 0 angularVelocity 0 0 0 0 force 0 0 0 torque 0 0 0 normal 0 0 -1 factor 1\n"
"Boundaries 0\n"
"Particles 0\n"
"Interactions 0\n"
);
helpers::writeToFile("Tutorial10.ini.data",
"1 0 0 0 0 2 2 2\n"
"1 1 1.5 0 0 0 0.5 0 0 0 0 0 0 0\n"
);
DPMBase Tutorial10;
//use readRestartFile to load information from a restart file
Tutorial10.readRestartFile("Tutorial10.ini.restart");
//use readDataFile to load information from a data file
Tutorial10.readDataFile("Tutorial10.ini.data");
//now start the calculations
Tutorial10.solve();
return 0;
}
The DPMBase header includes quite a few header files, defining all the handlers, which are essential....
Definition: DPMBase.h:56
bool readDataFile(std::string fileName="", unsigned int format=0)
This allows particle data to be reloaded from data files.
Definition: DPMBase.cc:2457
void solve()
The work horse of the code.
Definition: DPMBase.cc:4334
bool readRestartFile(ReadOptions opt=ReadOptions::ReadAll)
Reads all the particle data corresponding to a given, existing . restart file (for more details regar...
Definition: DPMBase.cc:3043
bool writeToFile(const std::string &filename, const std::string &filecontent)
Writes a string to a file.
Definition: FileIOHelpers.cc:29

The main function of Tutorial10_LoadingDataRestart.cpp presents how to create a restart and a data file, then reads these files and subsequently solves it. Mostly however you don't create these files as you restart from a previous session.


T11: Axisymmetric walls inside a cylindrical domain

Problem description:

This tutorial explains how to include axisymmetric walls inside a cylindrical domain. Also, the user will find an useful implementation of how to create polydisperse particle size distribution and perform internal validation tests. The full code can be found in Tutorial11_AxisymmetricWalls.cpp

Headers:

To work with axisymmetric walls, the user needs to add the following headers:

Before the main function:

The class Tutorial 11 contains the constructor Tutorial 11

Tutorial11(const Mdouble width, const Mdouble height){
logger(INFO, "Tutorial 11");
setName("Tutorial11");
setFileType(FileType::ONE_FILE);
restartFile.setFileType(FileType::ONE_FILE);
fStatFile.setFileType(FileType::NO_FILE);
eneFile.setFileType(FileType::NO_FILE);
setParticlesWriteVTK(true);
wallHandler.setWriteVTK(FileType::ONE_FILE);
setXBallsAdditionalArguments("-v0 -solidf");
//specify body forces
setGravity(Vec3D(0.0, 0.0, -9.8));
//set domain accordingly (domain boundaries are not walls!)
setXMin(0.0);
setXMax(width);
setYMin(0.0);
setYMax(width);
setZMin(0.0);
setZMax(height);
}
double Mdouble
Definition: GeneralDefine.h:13
Logger< MERCURYDPM_LOGLEVEL > logger("MercuryKernel")
Definition of different loggers with certain modules. A user can define its own custom logger here.
[T11:headers]
Definition: Tutorial11_AxisymmetricWalls.cpp:24
#define INFO(i)
Definition: mumps_solver.h:54
double height(const double &x)
Height of domain.
Definition: simple_spine_channel.cc:429

This constructor is an instance of the main class. Here it's defined the global output and non-changeable parameters.

In this tutorial, it overrides the member function setupInitialConditions(), which doesn't return any value (defined then as void).

void setupInitialConditions() override {
Vec3D mid = {
(getXMin() + getXMax()) / 2.0,
(getYMin() + getYMax()) / 2.0,
(getZMin() + getZMax()) / 2.0};
const Mdouble halfWidth = (getXMax() - getXMin()) / 2.0;
//Cylinder
w1.setSpecies(speciesHandler.getObject(0));
w1.setPosition(Vec3D(mid.X, mid.Y, 0));
w1.setAxis(Vec3D(0, 0, 1));
w1.addObject(Vec3D(1, 0, 0), Vec3D((getXMax() - getXMin()) / 2.0, 0, 0));
// Display the cylinder only, when not coinciding with the neck
std::vector<Mdouble> displayedSegmentsCylinder = {-constants::inf, mid.Z - contractionHeight, mid.Z + contractionHeight, constants::inf};
w1.setDisplayedSegments(displayedSegmentsCylinder);
wallHandler.copyAndAddObject(w1);
//Cone
w2.setSpecies(speciesHandler.getObject(0));
w2.setPosition(Vec3D(mid.X, mid.Y, 0));
w2.setAxis(Vec3D(0, 0, 1));
std::vector<Vec3D> points(3);
//define the neck as a prism through corners of your prismatic wall in clockwise direction
points[0] = Vec3D(halfWidth, 0.0, mid.Z + contractionHeight);
points[1] = Vec3D(halfWidth - contractionWidth, 0.0, mid.Z);
points[2] = Vec3D(halfWidth, 0.0, mid.Z - contractionHeight);
w2.createOpenPrism(points);
// Display the neck only until reaching the cylinder
std::vector<Mdouble> displayedSegmentsPrism = {mid.Z - contractionHeight, mid.Z + contractionHeight};
w2.setDisplayedSegments(displayedSegmentsPrism);
wallHandler.copyAndAddObject(w2);
//Flat surface
w0.setSpecies(speciesHandler.getObject(0));
w0.set(Vec3D(0, 0, -1), Vec3D(0, 0, mid.Z));
wallHandler.copyAndAddObject(w0);
const int N = 600; //maximum number of particles
p0.setSpecies(speciesHandler.getObject(0));
for (Mdouble z = mid.Z + contractionHeight;
particleHandler.getNumberOfObjects() <= N;
z += 2.0 * maxParticleRadius)
{
for (Mdouble r = halfWidth - maxParticleRadius; r > 0; r -= 1.999 * maxParticleRadius)
{
for (Mdouble c = 2.0 * maxParticleRadius; c <= 2 * constants::pi * r; c += 2.0 * maxParticleRadius)
{
p0.setRadius(random.getRandomNumber(minParticleRadius, maxParticleRadius));
p0.setPosition(Vec3D(mid.X + r * mathsFunc::sin(c / r),
mid.Y + r * mathsFunc::cos(c / r),
z + p0.getRadius()));
const Mdouble vz = random.getRandomNumber(-1, 0);
const Mdouble vx = random.getRandomNumber(-1, 1);
p0.setVelocity(Vec3D(vx,0.0,vz));
particleHandler.copyAndAddObject(p0);
}
}
}
}
Use AxisymmetricIntersectionOfWalls to Screw Screw::read Screw::read Screw::read define axisymmetric ...
Definition: AxisymmetricIntersectionOfWalls.h:105
void setAxis(Vec3D a)
Definition: AxisymmetricIntersectionOfWalls.cc:149
void setDisplayedSegments(const std::vector< Mdouble > &displayedSegments)
Sets the displayed segments.
Definition: AxisymmetricIntersectionOfWalls.h:189
virtual void setPosition(const Vec3D &position)
Sets the position of this BaseInteractable.
Definition: BaseInteractable.h:218
void createOpenPrism(std::vector< Vec3D > points, Vec3D prismAxis)
Creates an open prism which is a polygon between the points, except the first and last point,...
Definition: IntersectionOfWalls.cc:446
Mdouble Y
Definition: Kernel/Math/Vector.h:45
Mdouble Z
Definition: Kernel/Math/Vector.h:45
Mdouble X
the vector components
Definition: Kernel/Math/Vector.h:45
@ N
Definition: constructor.cpp:22
StridedVectorType vx(make_vector(x, *n, std::abs(*incx)))
r
Definition: UniformPSDSelfTest.py:20
int c
Definition: calibrate.py:100
const Mdouble inf
Definition: GeneralDefine.h:23
Mdouble cos(Mdouble x)
Definition: ExtendedMath.cc:43
Mdouble sin(Mdouble x)
Definition: ExtendedMath.cc:23

First, it is added the cylinder, then the prism shape or cone that represents the outer part. A flat surface is included in the middle to stop the downforward flow until a specific time. After adding the walls, the species of the particles are included. All particles have the same properties and they are randomly distributed.

An additional member function is included.

//Initially, a wall is inserted in the neck of the hourglass to prevent particles flowing through.
//This wall is moved to form the base of the hourglass at time 0.9
void actionsAfterTimeStep() override {
if (getTime() < 0.9 && getTime() + getTimeStep() > 0.9)
{
logger(INFO, "Shifting bottom wall downward");
dynamic_cast<InfiniteWall*>(wallHandler.getLastObject())->set(Vec3D(0, 0, -1), Vec3D(0, 0, getZMin()));
}
}

This overrides function moves the flat surface to the base domain. It happens at a defined time, thus the particles can continue to flow.

Main function:

The main function of this tutorial includes the setup parameters and the tests for a valid collision time and restitution coefficient.

int main(int argc, char *argv[])
{
Mdouble width = 10e-2; // 10cm
Mdouble height = 60e-2; // 60cm
//Point the object HG to class
Tutorial11 HG(width,height);
//Specify particle radius:
//these parameters are needed in setupInitialConditions()
HG.minParticleRadius = 6e-3; // 6mm
HG.maxParticleRadius = 10e-3; //10mm
//Specify the number of particles
//specify how big the wedge of the contraction should be
const Mdouble contractionWidth = 2.5e-2; //2.5cm
const Mdouble contractionHeight = 5e-2; //5cm
HG.contractionWidth = contractionWidth;
HG.contractionHeight = contractionHeight;
//make the species of the particle and wall
species.setDensity(2000);
species.setStiffness(1e5);
species.setDissipation(0.63);
HG.speciesHandler.copyAndAddObject(species);
//test normal forces
const Mdouble minParticleMass = species.getDensity() * 4.0 / 3.0 * constants::pi * mathsFunc::cubic(HG.minParticleRadius);
//Calculates collision time for two copies of a particle of given dissipation_, k, effective mass
logger(INFO, "minParticleMass = %", minParticleMass);
//Calculates collision time for two copies of a particle of given dissipation_, k, effective mass
const Mdouble tc = species.getCollisionTime(minParticleMass);
logger(INFO, "tc = %", tc);
//Calculates restitution coefficient for two copies of given dissipation_, k, effective mass
const Mdouble r = species.getRestitutionCoefficient(minParticleMass);
logger(INFO, "restitution coefficient = %", r);
//time integration parameters
HG.setTimeStep(tc / 10.0);
HG.setTimeMax(5.0);
HG.setSaveCount(500);
HG.solve(argc, argv);
return 0;
}
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Mdouble getCollisionTime(Mdouble mass) const
Calculates collision time for two copies of a particle of given disp, k, mass.
Definition: LinearViscoelasticNormalSpecies.cc:116
Mdouble getRestitutionCoefficient(Mdouble mass) const
Calculates restitution coefficient for two copies of given disp, k, mass.
Definition: LinearViscoelasticNormalSpecies.cc:147
Mdouble getDensity() const
Allows density_ to be accessed.
Definition: ParticleSpecies.cc:98
T cubic(const T val)
calculates the cube of a number
Definition: ExtendedMath.h:95

note: to produce the pictures as shown you can use Paraview.


T12: Creating objects by using Prisms

Problem description:

This tutorial explains how to define objects in space with the Prism function. Also, the user will find that you can prescribe the location and motion of the object. The full code can be found in Tutorial12_PrismWalls.cpp

Headers:

To work with prismatic walls in this tutorial, the user needs to add the following headers:

Before the main function:

The walls and Prism object are all predefined in the initial conditions.

void setupInitialConditions() override {
p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.15 * getXMax(), 0.3335 * getYMax(), 0.0));
p0.setVelocity(Vec3D(1.2, 0.2, 0.0));
particleHandler.copyAndAddObject(p0);
// Creating outer walls
w0.setSpecies(speciesHandler.getObject(0));
w0.set(Vec3D(1.0, 0.0, 0.0), Vec3D(getXMax(), 0.0, 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(-1.0, 0.0, 0.0), Vec3D(getXMin(), 0.0, 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(0.0, 1.0, 0.0), Vec3D(0.0, getYMax(), 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(0.0, -1.0, 0.0), Vec3D(0.0, getYMin(), 0.0));
wallHandler.copyAndAddObject(w0);
// Defining the object in het center of the box
// Create an intersection of walls object w1
// Set the species of the wall
w1.setSpecies(speciesHandler.getObject(0));
std::vector<Vec3D> Points(4);
// Define the vertices of the insert and ensure that points are in clockwise order
Points[0] = Vec3D(0.25 * getXMax(), -0.25 * getYMax(), 0.0);
Points[1] = Vec3D(-0.25 * getXMax(), -0.25 * getYMax(), 0.0);
Points[2] = Vec3D(-0.25 * getXMax(), 0.25 * getYMax(), 0.0);
Points[3] = Vec3D(0.25 * getXMax(), 0.25 * getYMax(), 0.0);
// Creating the object from the vector containing points
/* Define the angular velocity of the object (optional).
* Setting the angular velocity of the object results in rotation of the object around
* the origin (0.0,0.0,0.0). If the object is build such that the center of rotation of the object
* coincides with the origin the object will rotate around its own axis. */
w1.setAngularVelocity(Vec3D(0.0,0.0,1.0));
/* Define the translational velocity of the object (optional) */
w1.setVelocity(Vec3D(0.0,0.0,0.0));
/* Set the desired position of center of the object (optional).
* With this command you can position your object (with the set angular velocity)
* at a specific location in the domain.*/
w1.setPosition(Vec3D(0.5 * getXMax(),0.5 * getYMax(),0.0));
// Add the object to wall w1
wallHandler.copyAndAddObject(w1);
}
void setAngularVelocity(const Vec3D &angularVelocity)
set the angular velocity of the BaseInteractble.
Definition: BaseInteractable.cc:338
void setVelocity(const Vec3D &velocity)
set the velocity of the BaseInteractable.
Definition: BaseInteractable.cc:328
void createPrism(std::vector< Vec3D > points, Vec3D prismAxis)
Creates an open prism which is a polygon between the points and extends infinitely in the PrismAxis d...
Definition: IntersectionOfWalls.cc:461
Points
Definition: pebble_output.py:56

The first part in the the initial conditions is defining the particle.

p0.setSpecies(speciesHandler.getObject(0));
p0.setRadius(0.005);
p0.setPosition(Vec3D(0.15 * getXMax(), 0.3335 * getYMax(), 0.0));
p0.setVelocity(Vec3D(1.2, 0.2, 0.0));
particleHandler.copyAndAddObject(p0);

After defining the particle that outer walls are generated by using four finite walls as seen in previous tutorials

// Creating outer walls
w0.setSpecies(speciesHandler.getObject(0));
w0.set(Vec3D(1.0, 0.0, 0.0), Vec3D(getXMax(), 0.0, 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(-1.0, 0.0, 0.0), Vec3D(getXMin(), 0.0, 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(0.0, 1.0, 0.0), Vec3D(0.0, getYMax(), 0.0));
wallHandler.copyAndAddObject(w0);
w0.set(Vec3D(0.0, -1.0, 0.0), Vec3D(0.0, getYMin(), 0.0));
wallHandler.copyAndAddObject(w0);

To create the prism we have to do the following: First one creates an instance of IntersectionOfWalls "w1". Next the species are assigned. This line is followed by defining a 3D vector "Points" with space for four vertices. After that the location of the four vertices are defined. Then, by using w1.createPrism(Points) the prism is formed centered at the origin.

// Defining the object in het center of the box
// Create an intersection of walls object w1
// Set the species of the wall
w1.setSpecies(speciesHandler.getObject(0));
std::vector<Vec3D> Points(4);
// Define the vertices of the insert and ensure that points are in clockwise order
Points[0] = Vec3D(0.25 * getXMax(), -0.25 * getYMax(), 0.0);
Points[1] = Vec3D(-0.25 * getXMax(), -0.25 * getYMax(), 0.0);
Points[2] = Vec3D(-0.25 * getXMax(), 0.25 * getYMax(), 0.0);
Points[3] = Vec3D(0.25 * getXMax(), 0.25 * getYMax(), 0.0);
// Creating the object from the vector containing points

Now the object has been formed you can prescribe several properties of the object such as the angular velocity or translational velocity (using setVelocity). Notice that when using setAngularVelocity the object rotates around the origin, so if an object is located at the origin it will rotate around its own axis while located elsewhere it will rotate around the origin. It is essential that you set velocities and positions in the correct order such that you get the desired motion.

w1.setAngularVelocity(Vec3D(0.0,0.0,1.0));
w1.setVelocity(Vec3D(0.0,0.0,0.0));
w1.setPosition(Vec3D(0.5 * getXMax(),0.5 * getYMax(),0.0));

Main:

In the main function the problem is defined in the problem instance, an instance of class Tutorial 12.

// Problem setup
Tutorial12 problem; // instantiate an object of class Tutorial 12
problem.setName("Tutorial12");
problem.setGravity(Vec3D(0.0, 0.0, 0.0));
problem.setXMax(0.5);
problem.setYMax(0.5);
problem.setZMax(0.1);
problem.setTimeMax(5.0);
// The normal spring stiffness and normal dissipation is computed and set as
// For collision time tc=0.005 and restitution coefficient rc=1.0,
species.setDensity(2500.0); //sets the species type_0 density
species.setStiffness(258.5);//sets the spring stiffness.
species.setDissipation(0.0); //sets the dissipation.
problem.speciesHandler.copyAndAddObject(species);
problem.setSaveCount(10);
problem.dataFile.setFileType(FileType::ONE_FILE);
problem.restartFile.setFileType(FileType::ONE_FILE);
problem.fStatFile.setFileType(FileType::NO_FILE);
problem.eneFile.setFileType(FileType::NO_FILE);
problem.setParticlesWriteVTK(true);
problem.wallHandler.setWriteVTK(FileType::ONE_FILE);
problem.setTimeStep(.005 / 50.0); // (collision time)/50.0
[T12:headers]
Definition: Tutorial12_PrismWalls.cpp:24

At the end of the main function we call the solve function

problem.solve(argc, argv);

After solving the problem you can visualize the results and see the effect of the motion of the object on the trajectory of the particle.


Click here to go to the Advanced tutorials.