This tutorial is currently being written and is incomplete.

This tutorial introduces the use of polydisperse particles (e.g., Properties), the challenges of granular/dissipative interactions in gravity, and how to introduce walls/boundaries into a configuration file. It also uses python to ease the generation of configuration files.

Given that many concepts are already dealt with in the previous tutorials, we'll start to move a little quicker in these tutorials.

For this tutorial we will study our first granular system. Fundamentally, granular particle systems are distinguished from molecular systems through their dissipation of energy. Granular systems also usually have complex boundary conditions and include gravity as an external force. Examples of granular systems include sand piles, mining operations, mill/grinding, grain hoppers/silos, tableting in pharmaceutical/food industries, and so on. It is clear that in these systems we must also capture the polydispersity of the particles. Each particle has a different mass and geometry which, in its simplest form, is a variation in diameter.

We are going to simulate a granular system of $N=1372$ polydisperse inelastic hard-spheres falling onto a flat ground which is bounded by a set of walls.

# Creating the configuration

As is usual, we will take a simple base configuration and the complexity we need. Starting with a simple hard sphere system:

dynamod -m0 -d 1.0 -C 7 -o config.hs.xml


This creates a system of mono-sized spheres in periodic boundary conditions. First, we want to add polydispersity to the system. We can do this by hand, but we really should learn to automate these tedious tasks using a nice language like python.

To add polydispersity to our configuration, we need to use the Property tags. For details on exactly how these work, please see the Property tags reference page. Here, we'll just look at what changes we need to make. First, we take each particle (Pt) tag in the configuration file:

<ParticleData>
<Pt ID="0">...</Pt>
<Pt ID="1">...</Pt>
...
</ParticleData>


And add some attributes which specify its mass and diameter:

<ParticleData>
<Pt D="0.313438730606" ID="0" M="0.0307934238237">...</Pt>
<Pt D="0.634910505277" ID="1" M="0.255939630727">...</Pt>
...
</ParticleData>


These attributes are just extra data attached to the particle, the names are arbitrary but its convenient to choose "M" for mass and "D" for diameter. We need to then tell DynamO it should load these attributes by adding definitions of the properties to the Property tag:

<Properties>
<Property Name="M" Type="PerParticle" Units="Mass"/>
<Property Name="D" Type="PerParticle" Units="Length"/>
</Properties>


Here you can see all we've done is tell DynamO there are these properties with names "M" and "D", and they have units of mass and length respectively.

These attributes will be loaded and saved by DynamO, but they're not used in the configuration yet. Lets change the current Interaction:

<Interaction Type="HardSphere" Diameter="1" Name="Bulk">
<IDPairRange Type="All"/>
</Interaction>


Here, we can replace the numerical property "1" used in the Diameter attribute with "D".

<Interaction Diameter="D" Name="Bulk" Type="HardSphere">
<IDPairRange Type="All"/>
</Interaction>


If you check the reference entry for HardSphere Interactions, you'll see that the Diameter attribute has units of Length. DynamO will check that the same units are used when defining the Properties and when they're actually used.

<Species Mass="M" Name="Bulk" Type="Point">
<IDRange Type="All"/>
</Species>


## Adding polydispersity automatically using python

Of course, with $N=1372$ particles I didn't add the polydisperse attributes to each particle by hand. The main reason that DynamO has XML configuration files is to allow you to write your own tools to build systems in the programming language of your choice. One easy-to-use language is python. I achieved everything above using the script below:

#!/usr/bin/env python
import xml.etree.ElementTree as ET
import random

XMLFile = ET.parse("config.HS.xml")

#Add the diameter and mass tags
for ParticleTag in XMLFile.findall("./ParticleData/Pt"):
#Calculate a random diameter
diameter = random.uniform(0.1, 1)
ParticleTag.attrib["D"] = str(diameter)
#Add a mass attribute which scales with the particle volume (for D=1 M=1)
ParticleTag.attrib["M"] = str(diameter * diameter * diameter)

massProperty = ET.SubElement(XMLFile.findall("./Properties")[0], "Property")
massProperty.attrib["Type"] = "PerParticle"
massProperty.attrib["Units"] = "Mass"
massProperty.attrib["Name"] = "M"
diamProperty = ET.SubElement(XMLFile.findall("./Properties")[0], "Property")
diamProperty.attrib["Type"] = "PerParticle"
diamProperty.attrib["Units"] = "Length"
diamProperty.attrib["Name"] = "D"

#Change the Interaction and Species to use the properties
XMLFile.findall(".//Interaction")[0].attrib["Diameter"] = "D"
XMLFile.findall(".//Species")[0].attrib["Mass"] = "M"

#Write out XML file
XMLFile.write("config.poly.xml",xml_declaration=True)


Please take a look at the documentation on "Parsing Output and Config Files" to find out more about how this script works.