In order for simulation codes to be flexible, they should allow the end user to switch different physical effects on or off. They may also allow the user to switch between different algorithms. In addition the user may want to include additional calculations on demand, such as the time averaging of fields. These calculations should only be performed when needed and it should be possible to configure these choices through the configuration file without having to re-compile the code. The hierarchical block structure in Schnek allows the developer to create modules of simulation code which can be included in the configuration file. This allows for highly versatile codes. In Schnek, each type of simulation block is represented by a class that descends from the ``Block`` class. The ``Block`` class was already introduced in the `first example on setup files <../reading-setup-files/a-first-example.html>`__ as the class that represents the complete simulation. However a simulation code can have a large number of different block types and these can be arranged in a hierarchical manner. To start with a simple example, let's assume we want to create a simulation with a number of individual particles. Each particle can have its own mass, position and velocity. In Schnek these particles could be represented by the following code. :: class Particle : public Block { private: Array pos; Array velocity; double mass; protected: void initParameters(BlockParameters ¶meters) { parameters.addArrayParameter("pos", pos); parameters.addArrayParameter("velocity", pos); parameters.addParameter("mass", &mass); } public: void advance(const Array &force, double dt) { pos = pos+velocity*dt; velocity = velocity + force*dt/mass; } void display() { std::cout << "Mass: " << mass << std::endl; std::cout << "Position: (" << pos[0] << ", " << pos[1] << ", " << pos[1] << ")" << std::endl; std::cout << "Velocity: (" << velocity[0] << ", " << velocity[1] << ", " << velocity[1] << ")" << std::endl; } }; The ``Particle`` class is very much like the ``Block`` classes we have seen in the `previous chapter <../reading-setup-files.html>`__. The private members ``pos``, ``velocity``, and ``mass`` are registered with the setup file parser in the ``initParameters()`` function. Two additional functions, ``advance()`` and ``display()`` have been defined. The first function will advance the particle position and velocity based on an external force. The second function will print out the values to the console. Very similar to the ``Particle`` class, we define a class that will act as the root class for the simulation. :: class NBody : public Block { private: double dt; double totalTime; protected: void initParameters(BlockParameters ¶meters) { parameters.addParameter("dt", &dt); parameters.addParameter("totalTime", &totalTime); } public: void runSimulation(); }; Again, this class looks very much like the block classes we have seen before. We have added an additional function ``runSimulation()`` that will run the simulation. We will implement this function later. The logical arrangement of these two classes is that an object of type ``NBody``, as the main simulation class, should contain an arbitrary number of ``Particle`` objects. We can tell the setup file parser this relationship in a few simple commands. In the ``main()`` function simply include the following lines :: BlockClasses blocks; blocks.registerBlock("NBody").setClass(); blocks.registerBlock("Particle").setClass(); blocks("NBody").addChildren("Particle"); These lines will register two block types with the ``BlockClasses`` object. As introduced in the previous chapter, the string argument of the ``registerBlock()`` function determines the name given to the class in the setup file. The last line of the fragment above specifies the relationship between the two classes. Here ``"Particle"`` is specified as the child class of ``"NBody"``. The rest of the main function follows the well known pattern. :: std::ifstream in("example_blocks_hierarchy01.setup"); Parser P("nbody_simulation", "NBody", blocks); pBlock application = P.parse(in); NBody *mysim = dynamic_cast(application.get()); mysim->evaluateParameters(); mysim->runSimulation(); We set the ``NBody`` class as the main class of the simulation and then parse the configuration file through an input file stream. Because we know that the ``pBlock`` pointer really points to an ``NBody`` object we can perform a cast. Then we first need to evaluate the parameters before we finally run the simulation. After this we can write the setup file. In the following example we include two particles. :: dt = 0.01; totalTime = 1; Particle A { posx = 0; posy = 0; posz = 0; velocityx = 0; velocityy = 0; velocityz = 0; mass = 10; } Particle B { posx = 1; posy = 0; posz = 0; velocityx = 0; velocityy = 10; velocityz = 0; mass = 1; } When the code reads this file it will first create an ``NBody`` object and set the ``dt`` and ``totalTime`` members. After this, two ``Particle`` objects are created, each with its own values for ``pos``, ``velocity``, and ``mass``. These two objects are added as children to the ``NBody``. Inside the ``Particle`` class you can get the surrounding ``NBody`` object through the ``getParent()`` function. This function returns a ``pBlock`` which is a boost shared pointer to the parent block. Inside the ``NBody`` class you can get a collection of ``Particle`` objects through the ``getChildren()`` function. This will return a list of ``pBlock`` pointers. You should use the ``BlockList`` type to store this list. This allows us to write the code for the ``runSimulation()`` function. :: void NBody::runSimulation() { BlockList children = getChildren(); Array force(0.0,0.0,0.0); for (double time=0.0; time<=totalTime; time+=dt) { BOOST_FOREACH(pBlock block, children) { boost::shared_ptr particle = boost::dynamic_pointer_cast(block); particle->advance(force, dt); } } BOOST_FOREACH(pBlock block, children) { std::cout << "Child: " << block->getName() << std::endl; boost::shared_ptr particle = boost::dynamic_pointer_cast(block); particle->display(); } } This function iterates through the time steps and for each time step it loops over all children, advancing their positions. After the simulation has finished another loop prints out the positions of all the particles. Note the use of the ``BOOST_FOREACH`` macro here. If you are compiling using the C++11 standard you can use a ranged based for loop ``for (pBlock block : children)`` instead. Please not however, that Schnek has not yet been tested under the C++11 standard. We are using a dynamic cast to cast the ``pBlock`` pointer to a shared pointer of ``Particle`` type. We can do this because we know that all children of ``NBody`` must be of type ``Particle``. This is OK for the example presented here. In general we are allowed to declare different classes as child classes of a block. In this case we would need to check for each child what class it is and perform the required operation only on those objects that match a given class. In the next section we will see how this problem is solved by Schnek. The code for this example can be downloaded `here `__. The setup file can be found `here `__.