Initialization
After we created a simulation by calling create_simulation
, we must build the initial state of the simulation. As in Vahana the state of a model is represented as a graph, this means we must add the nodes (our agents) and edges to the graph.
Vahana.add_agent!
— Functionadd_agent!(sim, agent::T)::AgentID
Add a single agent of type T to the simulation sim
.
T must have been previously registered by calling register_agenttype!
.
add_agent!
returns a new AgentID, which can be used to create edges from or to this agent until finish_init!
is called (in the case that add_agent!
is called in the initialization phase), or until the transition funcion is finished (in the case that add_agent!
is called in an apply!
callback). Do not use the ID for other purposes, they are not guaranteed to be stable.
See also add_agents!
, add_edge!
and add_edges!
Vahana.add_agents!
— Functionadd_agents!(sim, agents)::Vector{AgentID}
Add multiple agents at once to the simulation sim
.
agents
can be any iterable set of agents, or an arbitrary number of agents as arguments.
The types of the agents must have been previously registered by calling register_agenttype!
.
add_agents!
returns a vector of AgentIDs, which can be used to create edges from or to this agents before finish_init!
is called (in the case that add_agents!
is called in the initialization phase), or before the transition funcion is finished (in the case that add_agents!
is called in an apply!
callback). Do not use the ID for other purposes, they are not guaranteed to be stable.
See also add_agent!
, register_agenttype!
, add_edge!
and add_edges!
The IDs created by add_agent(s)!
contain Vahana internal information, that can change after an apply!
or the finish_init!
call. It is even possible that different agents have the same ID at different times. This has the implication, that the IDs can only be used temporary and should not be stored in the state of an agent or edge.
Vahana.Edge
— Typestruct Edge{T}
from::AgentID
state::T
end
An edge between to agents with (optionally) additional state. T can be also a struct without any field.
The AgentID of the agent at the target of the edge is not a field of Edge
itself, since this information is already part of the containers in which the edges are stored.
See also register_edgetype!
Vahana.add_edge!
— Functionadd_edge!(sim, to::AgentID, edge::Edge{T})
Add a single edge to the simulation sim
. The edges is directed from the agent with ID edge.from
(the source) to the agent with ID to
(the target).
add_edge!(sim, from::AgentID, to::AgentID, state::T)
Add a single edge to the simulation sim
. The edge is directed from the agent with ID from
(the source) to the agent with ID to
(the target) and has the state state
.
T
must have been previously registered in the simulation by calling register_edgetype!
.
See also Edge
register_edgetype!
and add_edges!
Vahana.add_edges!
— Functionadd_edges!(sim, to::AgentID, edges)
Add multiple edges
at once to the simulation sim
, with all edges are directed to to
.
edges
can be any iterable set of agents, or an arbitrary number of edges as arguments.
See also Edge
register_edgetype!
and add_edge!
Graphs
It is also possible to use graph generators from the Graphs.jl package to construct the initial state. Or parts of it, since you can combine it with all the other functions described on this page. Since Graphs.jl has overlapping function names with Vahana, it is advisable to import only the SimpleGraphs module from Graphs.jl.
Vahana.add_graph!
— Functionadd_graph!(sim::Simulation, graph, agent_constructor, edge_constructor) -> Vector{AgentID}
Adds a graph
from the Graphs.jl package to sim
, incl. all vertices of graph
as new agents.
graph
must be a Graphs.Graph or a Graphs.DiGraph.
For each vertix of graph
the agent_constructor
function is called, with the Graphs.vertix as argument. For each edge of graph
the edge_constructor
function is called, with the Graphs.edge as argument.
The agent types of agents created by the agent_constructor
must be already registered via register_agenttype!
and vis a vis the edge type via register_edgetype!
.
add_graph! is only available when the Graphs.jl package is imported by the model implementation.
Returns a vector with the IDs of the created agents.
There is also two function with works the other way and converts the underlying graph of an simulation (or a subset of this graph) to a structure that fulfills the AbstractGraph or AbstractSimpleGraph interface from the Graphs.jl package.
Vahana.vahanagraph
— Functionvahanagraph(sim::Simulation; [agenttypes::Vector{DataType}, edgetypes::Vector{DataType}, show_ignorefrom_warning = true, drop_multiedges = false])
Creates a subgraph with nodes for all agents that have one of the agenttypes
types, and all edges that have one of the edgetypes
types and whose both adjacent agents have are of a type in agenttypes
.
The default values for agenttypes
and edgetypes
are all registered agents/edgetypes (see register_agenttype!
and register_edgetype!
).
This subgraphs implements the AbstractGraph interface from the Graphs.jl package, so that e.g. GraphMakie can be used to visualize the subgraph. See also create_graphplot
.
The AbstractGraph interface allows multiple edges between two nodes, but some functions (e.g. those that convert the graph to a binary (sparse) matrix) may produce undefined results for these graphs, e.g. when graphplot is called from GraphMakie.jl. If the keyword drop_multiedges
is true and there are multiple edges, only the edge of the type that is first in the edgetypes vector is added to the generated graph.
The edge types must not have the :IgnoreFrom property. If there are edge types with this property in the edgetypes
vector, a warning will be displayed and these edges will be ignored. The warning can be suppressed by setting show_ignorefrom_warning
to false.
Vahana.vahanasimplegraph
— Functionvahanasimplegraph(sim::Simulation; [agenttypes::Vector{DataType}, edgetypes::Vector{DataType}, show_ignorefrom_warning = true])
Creates a subgraph with nodes for all agents that have one of the agenttypes
types, and all edges that have one of the edgetypes
types and whose both adjacent node types are in agenttypes
.
The default values for agenttypes
and edgetypes
are all registered agents/edgetypes (see register_agenttype!
and register_edgetype!
).
This subgraphs implements the AbstractSimpleGraph interface from the Graphs.jl package.
The edge types must not have the :IgnoreFrom property. If there are edge types with this property in the edgetypes
vector, a warning will be displayed and these edges will be ignored. The warning can be suppressed by setting show_ignorefrom_warning
to false.
The AbstractGraph interface allows multiple edges between two nodes, but some function (e.g. those that convert the graph into a binary (sparse)matrix can produce undefined results for those graphs. So use this function with care.
Raster
The process for adding raster data to a simulation is documented here.
Set Parameters
After creating a simulation, you can modify parameter values using set_param!
until the simulation is initialized with finish_init!
.
Vahana.set_param!
— Functionset_param!(sim::Simulation, param::Symbol, value)
Assign the specified value
to the param
parameter. This operation is only allowed prior to calling the finish_init!
method.
A pipeable version of set_param!
is also available.
Finish initialization
After all the initial state has been built using the functions described above, finish_init!
must be called before the first call of apply!
Vahana.finish_init!
— Functionfinish_init!(sim::Simulation; [distribute = true,
partition::Dict{AgentID, ProcessID},
partition_algo = :Metis])
Finish the initialization phase of the simulation.
partition
is an option keyword and allows to specify an assignment of the agents to the individual MPI ranks. The dictonary must contain all agentids created on the rank as key, the corresponding value is the rank on which the agent "lives" after finish_init!
.
In the case that no partition
is given and distribute
is set to true, the Graph will be partitioned with the given partition_algo
. Currently two algorithms are supported: - :Metis uses the Metis library for the graph partitioning. - :EqualAgentNumbers just ensures that per agent type more or less the same number of agents are distributed to each process.
finish_init!
must be called before applying a transition function.
When a simulation is run on multiple PEs, per default the graph found on rank 0 will be partitioned using Metis, and distributed to the different ranks. Which means that it's allowed to run the initialization phase on all ranks (there is no need for a mpi.isroot check), but then all added agents and edges on other ranks then 0 will be discarded. If this is not intended distribute
must be set to false.
See also register_agenttype!
, register_edgetype!
, apply!
and finish_simulation!