The Block
class has a number of virtual functions that can be
implemented by a concrete block class. These functions are intended to
allow the simulation to be initialised in an orderly fashion. The
initialisation is subdivided into a number of steps. This allows one
class to initialise data in an earlier step and another class to access
that data in a subsequent step, knowing that it has already been
initialised. In the previous
sections
we have already come across some of these methods. In this section a
complete reference is given.
class Block {
protected:
virtual void initParameters(BlockParameters&) {}
virtual void registerData() {}
virtual void preInit() {}
virtual void init() {}
virtual void postInit() {}
};
By default all of the initialisation methods are defined as empty functions. They may be overridden but they don’t have to be. In the following a brief description of each function is given.
void initParameters(BlockParameters&)
This function is called just after the block object is created but before the contents of the block is read from setup file. Here the member variable can be added to theBlockParameters
object. This registers the member variables with the parser and allows automatic initialisation of the member variables from the setup file. For details on this function see the section on reading setup files.void registerData()
In this function data that is intended to be shared among multiple block should be registered using theaddData()
function. Once the fields have been registered other blocks are able to access them via theretrieveData()
function. See the previous section on sharing data between blocks for details.void preInit()
This function is called before the maininit()
function and allows additional initialisation that should be carried out before the main initialisation.init()
This is the main initialisation routine. This is the place where most of the set up should go.
void postInit()
This function is called after the maininit()
function and allows additional initialisation that should be carried out after the main initialisation.
When the simulation hierarchy is created by the parser through
Parser::parse()
, each block instance is created the moment that it
is read from the setup file. At this point the initParameters()
method is called for the newly created block. This enables the parser to
read the remainder of the block’s specification from the setup file.
After the parser has created the hierarch, a call to initAll()
on
the root block of the hierarchy will automatically iterate over all
blocks for each of the remaining initialisation functions. However,
before the registerData()
function is called on each block,
initAll()
will ensure that evaluateParameters()
is called on
each block in the hierarchy. After registerData()
function is called
on each block, preInit()
is called on each block in the hierarchy,
then init()
, and finally postInit()
. This means that, for
example, during execution of the init()
function it is guaranteed
that preInit()
has already been called for every block in the
hierarchy. Below is a flow diagram outlining the parsing and the
initialisation sequence. [caption id=”attachment_425”
align=”alignright” width=”807”] Block initialisation lifecycle. Left part shows the flow of the
Parser::parse() function. The right part shows the flow of the
Block::initAll() function.[/caption] In order to clarify the flow using
an example, let’s look at the following setup file.
Particle A {
Nested N1 { }
}
Force B { }
Force C { }
Particle D {
Nested N2 { }
}
We assume here that the blocks Particle
, Force
, and Nested
have been set up with the parser according to the structure found in
this file. The parsing and the initialisation sequence is then
Calling Parser::parse()
Root Block initParameters
Particle A initParameters
Nested N1 initParameters
Force B initParameters
Force C initParameters
Particle D initParameters
Nested N2 initParameters
Calling initAll()
Root Block registerData
Particle A registerData
Nested N1 registerData
Force B registerData
Force C registerData
Particle D registerData
Nested N2 registerData
Root Block preInit
Particle A preInit
Nested N1 preInit
Force B preInit
Force C preInit
Particle D preInit
Nested N2 preInit
Root Block init
Particle A init
Nested N1 init
Force B init
Force C init
Particle D init
Nested N2 init
Root Block postInit
Particle A postInit
Nested N1 postInit
Force B postInit
Force C postInit
Particle D postInit
Nested N2 postInit
This example illustrates in which order the initialisation functions are called. Notice how the each routine is called for each block in the order they appear in the setup file. This ordering is guaranteed by Schnek. The code for this example can be found here and the setup file is located here.