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.
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.
(Java)
MyAgent agent;
@Variable public float balance = 0;
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;
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.
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();
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();
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 |