Reporting

Last updated on 16th July 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.

Variable

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.

Save Install Path

The terminal will return the path where JDK 8 has been installed. Save this path for use when setting up the IDE.

(Java)

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.

(Java)

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

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

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

(Java)

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

(Java)

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

Console View

JSONValue

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

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 using the within an AgentBasedModel

(Java)

public class MyClass extends AgentBasedModel<GlobalState> {
	...
  {  
  	// create accumulator
  	createLongAccumulator("born");

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

  public void onStart() {
    born.add(10);
  }
}    

When running in the 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.

(Java)

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.

(Java)

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

(Java)

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

(Java)

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

(Java)

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. 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 to true.

Reporting for multirun Simulations

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