Outputting Data

Last updated on 6th May 2024

@Variable is needed for all data reporting. The Simudyne SDK provides several helper methods and classes that can be used to report more complex data easily.

If using the Simudyne SDK with the console, this reported data will be displayed for you in an appropriate format on the console. If using the Simudyne SDK without the console, the data will be returned in a JSON format.

Accumulators are reported by default. They could be present twice in the console if the annotation is used for them.


The most simple way of reporting data is creating a field in the Model and annotating it with @Variable. Fields annotated with @Variable will be displayed in the console as a line chart.

All fields marked as @Variable need to have public access, and must be a data type that can be reported. Accepted data types include primitive types (float, int, double), and any object that extends simudyne.core.JSONValue (see JsonValue below).


MyAgent agent;
@Variable public float balance = 0;

Console view

Console View

To set the title of the line chart, set the name in the variable annotation. If not set, it defaults to the name of the field.


@Variable(name="Balance Header") public float balance = 0;

Methods that return accepted data types can also be annotated with @Variable. These methods will be called at least once per step, but may be called many more times, so they should not change any values in the model.

Variable methods will only be called after setup, so the model can depend on a state that is initialised as part of the setup (such as AgentSystem).


@Variable(name = "Interest Charge")
public float interestCharge() {
  return interest * balance;

Fields marked as @Variable (this will be ignored for methods marked as @Variable) can set the parameter "initialisable" to true if you want the variable assigned before setup.


@Variable(name = "Balance", initializable = true)
public float balance = 400;

Console View


When reporting complex objects, the Simudyne SDK needs to be able to generate a JSON value and JSON schema of the objects. Therefore, all complex objects need to implement JSONValue and the methods for returning the JSON value.

The Simudyne SDK provides several data types that implement JSONValue, and can be used out of the box to report to the console. These are explained below. Using these provided data types is the recommended way of reporting.

Advanced users can create their own data types that implement JSONValue, and the data returned will be reported as a JSON, but the console will not be able to handle these data types, and will not display the information.


Accumulators are variables that are only added to through an associative and commutative operation. They can be used to implement counters or sums.

The two supported accumulators are DoubleAccumulators and LongAccumulators. They are both used in the same way, DoubleAccumulators for storing values of type double, and LongAccumulators for storing values of type long.

Accumulators can be created within an AgentBasedModel.


public class MyClass extends AgentBasedModel<GlobalState> {
  	// create accumulator

    // get accumulator and add value
// get accumulator and add value from within an Agent
public class Cell extends Agent<GlobalState> {
  public LongAccumulator born = getLongAccumulator("born");

  public void onStart() {

When running a simulation locally, accumulators are automatically reported to the console. To explicitly turn on or off reporting for accumulators, set the config field core-abm.serialize.accumulators. (See Model Configuration). Accumulators can be created with a second parameter for the display name that will be used when reporting the accumulators on the console.


createLongAccumulator("born", "Amount Born");

To view the count or mean of the accumulator, use the getCount() or getMean() methods and save the results as a primitive type annotated with @Variable.


@Variable(name = "Born Mean")
public long bornMean = getLongAccumulator("born").mean();

Agent Statistics

Statistics about the values of specific fields in agents can be collected using AgentSystem.stats().


// Agent statistics are collected for a specific agent class
public AgentStatistics<MyAgent> myAgentStats = stats(MyAgent.class)

// Filters can be used if statistics are only needed for some of the agents.
// In this case, only get statistics of agents where age is > 100   
myAgentStats.filter(x -> x.age)

// Specify which fields to collect statistics for.    
myAgentStats.field("Age", x -> x.age).field("Balance", x -> x.balance);  

// Get the statistics results
public AgentStatisticsResult<MyAgent> statsResults = myAgentStats.get();

This will collect statistics and save as Apache SummaryStatistics.

Get the SummaryStatistics for a field and get the required statistic to report using the SummaryStatistics methods. Annotate the field with @Variable, so the result will be reported to the console.


@Variable public double balanceMean =
  statsResults.getField("Balance").get Mean();

Agent fields

It is also possible to report the fields inside agents. In order to do so, annotate the fields inside Agents.


public class Cell extends Agent<GlobalState> {
  @Variable public boolean alive;

This will output a table for each Agent type, with the values of the fields annotated with @Variable for each agent in the system.

Agent view

The top-right corner lets you select different views. For the following example, select the Agent view.
Example output:
Cell Alive
6565 false
4536 false
7791 false
1209 false
When running models in distributed mode, AgentSystem reporting is muted even if AgentSystem is annotated with @Variable. To report agent fields, core-abm.serialize.agents must be set to true in the config, and to report accumulators, set core-abm.serialize.accumulators must be set to true.

Reporting for multirun Simulations

When running a model as a multirun, Agent tables will not be reported on the console.