Defining Execution Order

Once the agents and behaviours of your model have been specified, you must define the dependencies present in the model. Specifying a dependency, e.g. a depends on b ensures that function a will not run until function b has completed. This can be used to define the order you want behaviours to take place in, and to ensure that a function which outputs messages is complete before another function attempts to read them.

Specifying Dependencies

Dependencies are specified between AgentFunctionDescription, Submodel and HostFunctionDescription objects. These are specified using the dependsOn method.

# Declare that agent_fn2 depends on agent_fn1
agent_fn2.dependsOn(agent_fn1)

# Declare that host_fn1 depends on agent_fn2
host_fn1.dependsOn(agent_fn2)

Any of the objects can depend on multiple other objects:

# Declare that agent_fn6 depends on agent_fn3, agent_fn4 and agent_fn5
agent_fn6.dependsOn(agent_fn3)
agent_fn6.dependsOn(agent_fn4)
agent_fn6.dependsOn(agent_fn5)

Accessing the DependencyGraph

Each model has an associated dependency graph which is accessed via a ModelDescription as follows:

# Access the DependencyGraph of model
graph = model.getDependencyGraph()

Specifying Roots

Any functions or submodels which have no dependencies are roots. These must be added to the dependency graph:

# Add agent_fn1 as a root
graph.addRoot(agent_fn1)

You do not need to manually add every function or submodel to the graph. Adding the roots is enough, as the others will be included as a result of the dependency specifications.

Generating Layers

When you have specified all your dependencies and roots, you must instruct the model to generate execution layers from the dependency graph:

# Generate the actual execution layers from the dependency graph
model.generateLayers()

If you wish to see the actual layers generated, you can use the getConstructedLayersString() method of the dependency graph to obtain a string representation of the layers:

# Get the constructed layers and store them in variable actualLayers
actualLayers = graph.getConstructedLayersString()

# Print the layers to the console
print(actualLayers)

Visualising the Dependencies

FLAMEGPU2 can automatically produce a GraphViz format graph of your dependency tree. You can use this to visually validate that behaviours will be happening in the order you expect them to.

# Produce a diagram of the dependency graph, saved as graphdiagram.gv
graph.generateDOTDiagram("graphdiagram.gv")

As an example, the following code would produce the graph below in a file named diamond.gv:

f2.dependsOn(f)
f3.dependsOn(f)
f4.dependsOn(f2)
f4.dependsOn(f3)
graph = model.getDependencyGraph()
graph.addRoot(f)
graph.generateDOTDiagram("diamond.gv")
digraph {
  Function1[style = filled, color = red];
  Function2[style = filled, color = red];
  Function4[style = filled, color = red];
  Function3[style = filled, color = red];
  Function4[style = filled, color = red];
  Function1 -> Function2;
  Function2 -> Function4;
  Function1 -> Function3;
  Function3 -> Function4;
}

Manual Layer Specification

FLAMEGPU2 will automatically determine the optimal execution layers using the DependencyGraph, but you can specify them manually if you wish.