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).

random walk example 1


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 = (TurtlePositionsobj
              .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);
    }
  }
}