Tutorials
- Discovering examples
- Building compact discrete domains
- Introduction to input file
- Plugins and input files
- Initialize project
- Initialize your first custom plugin
- Implement your first custom plugin (You are here)
- Run your first project
- granoo-viewer usage
- Inputs/Outputs with GranOO
- Building a very simple tensile test
- Using numerical sensor
This page describes how to implement a custom plugin
Prerequisites
You must follow the previous tutorial steps before starting this tutorial. You must have a new project with the required plugin source files. Remember that we want to build this domain.
Adding attributes to plugin
We want to create three new attributes :
length_
that corresponds to the length of the domain,radius_
that corresponds to the radii of the discrete elements,number_
that corresponds to the number of discrete element.
In C++ and object oriented programming, a common usage it to keep attributes private.
So, we can introduce these attributes in the private part of the plugin.
Now, the PlugIn_BuildDomain.hpp
looks like :
Note that, for C++11, you can directly initialize variable in the class declaration.
To introduce these attributes in the plugin we implement the __init__(self)
method of the
PlugIn_BuildDomain.py
file.
Implementing the constructor and destructor
The constructor and destructor do nothing, they must look like :
Reading attribute values from input file
Here, we want to read the length_
, radius_
and number_
values from input file.
You can find below the corresponding implementation. You can implement the ParseXml()
method
for C++ or the read(self)
method for Python.
Here, we use the read_attribute()
method that comes from the Core::XmlParser
class where :
- the first parameter tells if the attribute is required or not. You can use
Attr::GRANOO_OPTIONAL
if you want to an optional attribute. - the second attribute corresponds to the name of the attribute inside the input file.
- the third attribute is your variable, where the value will be stored.
Here, we use the read_float(...)
and read_int(...)
methods that comes from the
singleton reader
class where :
- the first parameter tells if the attribute is required or not. You can use
granoo.attr.OPTIONAL
if you want to tell that an attribute is not required. - the second attribute corresponds to the name of the attribute inside the input file.
This syntax corresponds to the following line inside your input file.
Note that the input file reader is really powerful. Types are checked. The following line raises an error :
Required attributes are also checked. The following line raises an error because
the Length
attribute is not present.
and unknown attributes are also checked. The following line raises an error because
the Toto
attribute is unknown.
Implementing the Run() method
Now, you have to implement the Run()
method. This method will create
several discrete elements and link them through a special class named
DEM::ElementPair
. The first discrete element (at the left) is registered
in a special array Core::SetOf<DEM::DiscreteElement>
named "right"
and the last discrete element (at the right) is registered in a array
named "left"
.
Step by step description of the Run() method
The following code block simply uses the granoo::cout
function that mimics
the terminal ouptut of the standard C++ library. It allows to display nice
message to the user. Here, the main parameters of the wanted domain are summarized.
The following code block creates new discrete elements. A loop is used here to create the required number of discrete elements. Building a new discrete element requires the following parameters:
- its center that is defined by a geometrical point in the 3D space,
- its density and,
- its radius.
Note the use of the Geom::Point
class. It defines the initial position of the discrete element center.
The following code block parses the “global discrete element set” and creates ElementPair
instances
between discrete elements. The global set is a special instance of the Core::SetOf<T>
class.
This instance can be accessed through the static method get()
. The global set is unique and
contains all the discrete elements of the domain. You can access to an item indexed by a Core::SetOf<T>
through the parenthesis operator ().
Later, these ElementPair
will be used to implement mechanical
bonds between discrete elements.
The following code block builds a new empty Core::SetOf<T>
. Note that each Core::SetOf<T>
is identified
with a unique string. The first discrete element is caught thanks to the globalSet
variable
(created in the previous source block). The first discrete element is added to the “left” Core::SetOf<T>
.
The same procedure is applied with the last discrete element and the “right” Core::SetOf<T>
.
Later, these Core::SetOf<T>
will be used to apply some loads and boundary conditions to the
discrete elements indexed by these Core::SetOf<T>
.
Note that Core::SetOf
is a very important feature of granoo. It allows to mark some elements.
The Core::SetOf<T>
classes mimic std::vector<T>
arrays with extended features such as automatic registering and unregistering, smart parsing, identification with unique id, bilateral message….
Implementing the run(self) method
Now, you have to implement the run(self)
method. This method will create
several discrete elements and link them through a special class named
element_pair
. The first discrete element (at the left) is registered
in a discrete_element_set
named "right"
and the last discrete
element (at the right) is registered in a discrete_element_set
named "left"
.
Step by step description of the run() method
The following code block simply uses the granoo.cout
function that mimics the terminal ouptut of
the standard python library. It allows to display nice message to the user.
Here, the main parameters of the wanted domain are summarized.
The following code block creates new discrete_element
. A loop is used here
to create the required number of discrete elements. Building a new discrete element
requires the following parameters:
- its center that is defined by a
point
in the 3D space, - its density and,
- its radius.
Note that the new discrete elements must be added to the self.de_list
in order
to avoid automatic object deletion.
The following code block parses the global discrete_element_set
and creates element_pair
instances
between discrete elements. The global set is a special instance of the discrete_element_set
class.
This instance can be accessed through the static method glob()
. The global set is unique and
contains all the discrete elements of the domain.
Later, these element_pair
will be used
to implement mechanical bonds between discrete elements. Note that the xxxx_set
class instances
can be parsed as standard python list.
The following code block builds a new empty discrete_element_set
.
Note that each xxxxx_set
instances are identified with a unique string identifier.
The first discrete element is caught thanks to the globalSet
variable
(created in the previous source block). The first discrete element is added to the
“left” discrete_element_set
.
The same procedure is applied with the last discrete element and the “right”
discrete_element_set
. Later, these discrete_element_set
will be used to
apply some loads and boundary conditions to the
discrete elements indexed by these discrete_element_set
.
Note that xxxxx_set
is a very important feature of granoo. It allows to mark some elements.
The xxxxx_set
classes mimic standard list
arrays with extended features such as automatic
registering and unregistering, smart parsing, identification with unique id, bilateral message….
Navigating through the granoo C++ API
In order to full exploit the power of plugin, you must have a good knowledge of the GranOO C++ API. You can get a quick tour of the granoo C++ API in the documentation section of this website.