Developing an application/driver code

A driver file usually contains a class derived from Mercury3D in which the concrete parameters of the application are defined, such as species, particles, walls, boundaries, time step, ..., and a main function where the class is declared and the time integration routine (solve) is called. Thus, the basic setup looks like this:

\code{.cpp}    
#include <Mercury3D.h>

class Example : public Mercury3D    
{ 
public:
  void setupInitialConditions() override
  { 
    // define your particles, walls, boundaries here
  }
};

int main(int argc, char *argv[])
{
  Example problem;
  // define global variables, species here
  problem.solve(argc, argv);
  return 0;
}
\endcode

This file defines a class named Example, that is derived from Mercury3D. It overrides the function setupInitialConditions (which is empty by default) with a function where the simulation objects (particles, walls, boundaries, species) are defined.

Then the main function is defined (which is the function that is executed when you run the executable): First, the Example class is instantiated (a concrete instance of the class is created and stored in memory). Then, the global variables are set, such as name, gravity, spatial/temporal domain. Finally, the time integration routine (solve) is called.

Global variables

The following global variables should be set:

problem.setName("Example");
problem.setXMin(0.0);
problem.setYMin(0.0);
problem.setZMin(0.0);
problem.setXMax(1.0);
problem.setYMax(1.0);
problem.setZMax(1.0);
problem.setTimeMax(2.0);
problem.setTimeStep(1e-4);

The first command sets the name variable to Example, so the output files will be named Example.data, Example.restart, ... The next six commands set the dimensions of the system that are used in displaying the output. Finally, the final time and the time step are set.

There are additional global parameters that can be set here, such as

  • gravity, e.g. in z-direction
    problem.setGravity(Vec3D(0.0, 0.0, -9.8)); //sets gravity
    Definition: Vector.h:51
  • the amount of time steps between each write command
    problem.setSaveCount(50); //writes every 50th time step
  • additional output parameters for the xBalls viewer
    problem.setXBallsAdditionalArguments("-v0"); //displays velocity vectors in xBalls
  • ...

Species

A species can be defined as follows:

//include above all other code:
//include in main, before solve:
LinearViscoelasticSpecies species; // defines linear-viscoelastic contact law
species.setDensity(2500.0); // sets the particle density
species.setStiffness(200.0); // sets the linear contact stiffness
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:117
void setStiffness(Mdouble new_k)
Allows the spring constant to be changed.
Definition: LinearViscoelasticNormalSpecies.cc:93
void setDensity(Mdouble density)
Definition: ParticleSpecies.cc:108

Other contact laws are possible; see the documentation of Species for more details.

Particles

A particle can be defined as follows:

//include above all other code:
//include in setupInitialConditions:
BaseParticle p; // defines a new particle
p.setSpecies(speciesHandler.getObject(0)); // sets particle species
p.setRadius(0.5); // sets particle radius
p.setPosition(Vec3D(0.0,0.0,0.0)); // sets particle position
p.setVelocity(Vec3D(1.0,0.0,0.0)); // sets particle velocity
particleHandler.copyAndAddObject(p); // copies particle into the handler
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
Definition: BaseParticle.h:54
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
void setSpecies(const ParticleSpecies *species)
Definition: BaseParticle.cc:818

See the documentation of BaseParticle for more details.

Walls

A planar bottom wall at the bottom of the domain can be defined as follows:

//include above all other code:
//include in setupInitialConditions:
InfiniteWall w; // defines a new planar wall
w.setSpecies(speciesHandler.getObject(0)); // sets wall species
w.set(Vec3D(0,0,-1),Vec3D(0,0,getZMin())); // defines normal into the wall and point on the wall
wallHandler.copyAndAddObject(w); // copies wall into the handler
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

Other walls are possible; see the documentation of WallHandler for more details.

Boundaries

A periodic boundary in x-direction can be defined as follows:

//include above all other code:
//include in setupInitialConditions:
PeriodicBoundary b0; // defines a new periodic boundary
b.set(Vec3D(1,0,0),getXMin(),getXMax()); // defines normal and position of the boundary
boundaryHandler.copyAndAddObject(b); // copies boundary into the handler
Defines a pair of periodic walls. Inherits from BaseBoundary.
Definition: PeriodicBoundary.h:41
void set(Vec3D normal, Mdouble distanceLeft, Mdouble distanceRight)
Defines a PeriodicBoundary by its normal and positions.
Definition: PeriodicBoundary.cc:84

Other boundaries are possible; see the documentation of BoundaryHandler for more details.

Overriding functions

In some cases it is not enough to define suitable initial conditions. This is done by overriding certain functions in the Mercury3D class, just as we are overriding setupInitialConditions.

For example, to define a criterium to stop the simulation, one can override the

//include as member function in class definition:
bool continueSolve() const override
{
if (getKineticEnergy()<1e-5*getElasticEnergy())
return false;
else
return true;
}

In this case, the simulation is stopped as soon as the kinetic energy drops below 0.00001 times the elastic energy stored in the contact springs (a useful criteria to determine arresting flow).

For more examples, see Overriding functions.

Avoiding magic numbers

While the above example works, we advise you to avoid the number of explicitly used parameters such as the tolerance \(1e-5\) inside the class definition. A good coding guideline is to define all parameters in one place (the main function), with the exception of the particles, walls and boundaries, so they can easily be found and changed later.

\code{.cpp}
//include as member function in class definition:
bool continueSolve() const override
{
    if (getKineticEnergy()<tolerance*getElasticEnergy())
        return false;
    else
        return true;
}

//include as member variable in class definition:
Mdouble tolerance = 0.0;

//include in main function:
problem.tolerance = 1e-5;
\endcode

Creating new drivers

You can start a new driver code by creating your own user directory. First, chose a UserName, then add a folder to the user directory and create a new source file, e.g. Example.cpp, which for convenience is copied here from the file Tutorial1_ParticleInOuterSpace.cpp. cd ~/MercurySource/Drivers/USER svn mkdir UserName cd UserName svn cp ../../Tutorials/Tutorial1_ParticleInOuterSpace.cpp Example.cpp

Now write your code in the Example.cpp file. Note, you cannot yet execute your code, as the Makefiles in your build directory doesn't know about the new file. To update your Makefiles, use cmake. Note, the file name of your source file has to be unique, otherwise you get error messages. cd ~/MercuryBuild cmake .

Now you can build and execute your new code: cd ~/MercuryBuild/Drivers/USER/UserName make Example

Note, as we currently only support MercuryDPM on Linux/Mac OS, these instructions are only valid for such systems.