EnvironmentsMethods
Run your own NetLogo model

In this example, we present step by step how to explore a NetLogo model. The Fire model is a common NetLogo example. It studies the percolation of a fire in a forest depending on the density of the forest.

The simulation


We would like to study the impact of the density factor for a fixed population size. To do this, let's build a design of experiment where the density factor ranges from 20% to 80% by steps of 10.

Since the Fire model is stochastic, we are interested in doing replications for each instance of the density factor. Results for each replication will be stored it in a CSV file. In this example case, we will perform 10 replications per step (even though it is a way too small sample to draw up any formal conclusion).

You can get the NetLogo implementation of the model here.

The Design of Experiment


We first need to define 2 OpenMOLE variables in order to repeat our experience 10 times for every step of the density exploration. These 2 variables are:
  • an integer (Int) representing the seed of the random number generator for exploring the replications,
  • and a Double to set the value of density,

val density = Val[Double]
val seed = Val[Int]
val burned = Val[Double]

Given these variables, the definition of the exploration in OpenMOLE writes as follows:
val exploration =
  ExplorationTask(
    (density in (20.0 to 80.0 by 10.0)) x
    (seed in (UniformDistribution[Int]() take 10))
  )

This design of experiment will generate 70 distinct sets of input values for the NetLogo model:
  • 10 replications with 10 different seeds for density = 20%
  • 10 replications with 10 different seeds for density = 30%
  • ...
  • 10 replications with 10 different seeds for density = 80%

We now need to compose this design of experiment in a complete workflow in order to run the 70 distinct experiments.

The NetLogo task


Let's first construct the main task of the workflow. This task runs the actual NetLogo code. OpenMOLE provides a NetLogoTask that expects the following parameters definitions:
  • the path where to find the NetLogo model, i.e. the nlogo source file,
  • the list of NetLogo commands that OpenMOLE needs to run

In this example, the commands list contains:
  • random-seed that initialises the random number generator of NetLogo using the seed provided by OpenMOLE,
  • setup that calls the setup function of the netlogo file to initialise the model,
  • go, a function that runs the model, for this particular model this function is called until no more turttle are active.

The function go-openMOLE takes three parameters:
val cmds = List(
  "random-seed ${seed}",
  "setup",
  "while [any? turtles] [go]")

val fireTask =
  NetLogo5Task("/path/to/the/Fire.nlogo", cmds) set (
    inputs += seed,
    outputs += (density, seed),
    netLogoInputs += (density, "density"),
    netLogoOutputs += ("burned-trees", burned)
  )

The replication and the density OpenMOLE variables are used as parameters of the NetLogo program. Therefore they appear as inputs of the NetLogoTask.

Similarly, 1 output of the model is considered and collected by OpenMOLE at the end of each model execution. It is noted as netLogoOutputs in the task definition.

Storing the results


OpenMOLE usually delegates the tasks execution to many different computers. To gather the results of these remote executions, we use a mechanism called hooks. Hooks can be assimilated to a listener that saves or display results. They are more thoroughly described in a specific section of the documentation.

Here we will create a hook to listen to the model executions and save the results in a CSV file at the end of each of the 70 runs.
val csvHook = AppendToCSVFileHook("result.csv", density, burned, seed)

Bringing all the pieces together


Now that we have defined each component, we can compose the workflow that brings all the pieces of the simulation together:
  
val density = Val[Double]
val seed = Val[Int]
val burned = Val[Double]
  
val exploration =
  ExplorationTask(
    (density in (20.0 to 80.0 by 10.0)) x
    (seed in (UniformDistribution[Int]() take 10))
  )
  
val cmds = List(
  "random-seed ${seed}",
  "setup",
  "while [any? turtles] [go]")

val fireTask =
  NetLogo5Task("/path/to/the/Fire.nlogo", cmds) set (
    inputs += seed,
    outputs += (density, seed),
    netLogoInputs += (density, "density"),
    netLogoOutputs += ("burned-trees", burned)
  )
  
val csvHook = AppendToCSVFileHook("result.csv", density, burned, seed)

  exploration -< (fireTask hook csvHook)

The progress of the simulation can be monitored by printing the state of the execution variable: print(ex).

At the end of the execution, you will find the output values in a file called result.csv.

Going further


The Netlogo code mixes graphical and pure core instructions. Sometimes, you have to modify slightly your code to render it purely headless so that it can be run everywhere. The way to proceed in explained in details in the Headless Netlogo section.