How to create a model-agent to manage the simulation
Example with a Netlogo random walk model
The model used is a simple random
walk where, for each simulation step,
agents (so-called walkers) choose a random direction and step forward.
The Netlogo model specification is available
here.
The exchanged data will be here the walkers positions (x,y) the same
for input and output. In this simplistic case, the model exchange
theses
data with itself (i.e. its input port correspond to its output port).
Since not very useful for simulation results, this
example allows to introduce the very first concepts and their
implementation.
In this tutorial, we present the implementation of the model-agent
(which role is to manage the simulation and the data flow).
Model-agent implementation
The role of the model agent is to manage the simulation process (i.e. to
initiate the model, to run the model, to post and to read output and input data). In
order to implement a model-agent, you need to extends the
GenericAgent
abstract class.
Model-agent behaviour
The model-agent behaviour is quite
simple. After initializing the
model, the model-agent need to execute the model. That is, it reads
input data from the coupling-artefact, runs the model and posts the
output data to the coupling-artefact. In the following example, we
decided to process the simulation for only 1000 steps. We also use an
operation in order to filter the positions we receive. That is, when a
walker position is out of the boundaries of the model, we set it to
(0,0).
As a consequence, when the walkers reach the boundaries of their
environment, they go back to the (0,0) position (see operation link).
@Override
public void executeModel() {
// check if the operation has been instantiated
if (opLimit == null) {
initOperation_PositionLimit();
}
int c = 0;
while (c < 1000) {
c++;
// read input data
this.readInputData();
// run a simulation step
modelArtefact.run();
// post output data
this.postOutputData();
}
}
Read data from the coupling-artefact and set them to the
model-artefact
In order to read external data, the model-agent has to check the
coupling-artefact output ports it is linked with. In our example, we
check that there exists a coupling-artefact output port that accepts
TurtlePosition objects and read from this output port the data. In
order to ensure the coordination process, the read() method
automatically provides the data corresponding to our local simulation
time (see LinkCoord).
Once we have read the input data, it is possible to take an operation
on them and then to set them into the model input port.
@Override
public void readInputData() {
for (OutputPort<? extends SimulData> outputPort : couplingArtefactOutputPortList) {
try {
// check if the output port is the one in charge of receiving
// the walkers positions objects
if (outputPort.getClassO().equals(TurtlePositions.class)) {
// ask it to get the turtles positions for the current
// simulation time
ObjectMessage obj = outputPort.read(modelArtefact
.getCurrentTime());
TurtlePositions inputData = (TurtlePositions) obj
.getObject();
// take an operation over the inpuData
SimulData data_after_operation = opLimit.apply(inputData);
// set the input data to the model
modelArtefact.setInputData(data_after_operation);
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Get output data from the model-artefact and post them to the
coupling-artefact
@Override
public void postOutputData() {
ArrayList<SimulData> outputdata = modelArtefact.getOutputData();
for (SimulData data : outputdata) {
post(data);
}
}
}