public static void main(String[] args) throws IOException {
if (args.length == 0) {
throw new RuntimeException("One output directory argument is required");
}
= Paths.get(args[0]);
Path outputDirectory if (!Files.exists(outputDirectory)) {
.createDirectory(outputDirectory);
Files} else {
if (!Files.isDirectory(outputDirectory)) {
throw new IOException("Provided path is not a directory");
}
}
= getGlobalPropertiesPluginData();
GlobalPropertiesPluginData globalPropertiesPluginData
= GlobalPropertyReportPluginData.builder()//
GlobalPropertyReportPluginData globalPropertyReportPluginData .setReportLabel(ModelReportLabel.GLOBAL_PROPERTY_REPORT)//
.setDefaultInclusion(true)//
.build();
= GlobalPropertiesPlugin.builder()
Plugin globalPropertiesPlugin .setGlobalPropertiesPluginData(globalPropertiesPluginData)
.setGlobalPropertyReportPluginData(globalPropertyReportPluginData)//
.getGlobalPropertiesPlugin();
= ModelPlugin.getModelPlugin();
Plugin modelPlugin
= //
NIOReportItemHandler nioReportItemHandler .builder()//
NIOReportItemHandler.addReport(ModelReportLabel.GLOBAL_PROPERTY_REPORT, //
.resolve("global property report.csv"))//
outputDirectory.build();
Dimension alphaBetaDimension = getAlphaBetaDimension();
.builder()//
Experiment.addPlugin(globalPropertiesPlugin)//
.addPlugin(modelPlugin)//
.addExperimentContextConsumer(nioReportItemHandler)//
.addDimension(alphaBetaDimension)//
.build()//
.execute();//
}
6 Global Properties Plugin
The global property plugin implements a flexible property system for properties that have global scope. Specifically, global properties have no association with a specific person, place or other instance-based concept.
6.1 Plugin Data Initialization
The plugin is initialized using a GlobalPropertiesPluginData object that collects global property definitions and global property values. Even though the property definitions can contain default property values, the ability to set property values is included to add some flexibility to the collection process since the client model may separate definitions from values in its input files.
6.2 Plugin Behavior
The plugin adds a single data manager to the simulation as an instance of the GlobalPropertiesDataManager that is initialized with the GlobalPropertiesPluginData.
6.3 Data Manager
The data manager provides access to the global properties and provides the ability to:
- Define new global properties (not contained in the initial data)
- Retrieve global property definitions
- Retrieve global property ids
- Retrieve global property values and the times when they were set
- Set global property values
The data manager also produces observable events when a new global property is defined or when a global property value is assigned. The plugin provides the GlobalPropertyReport that subscribes to these events and produces a trace report of property value assignments.
6.4 Example Code (Lesson 13)
Example_13.java shows a simple usage of the global properties plugin. In it we will add three double valued properties: ALPHA, BETA, and GAMMA. ALPHA and BETA will be used to vary the scenarios in the experiment and GAMMA will be set to a simple function of ALPHA and BETA that will change over time in the simulation. This will culminate in a report that shows each time the global variables are defined or their values are set.
The example includes two plugins:
- Global properties plugin – (GCM core plugin) used to manage the properties
- Model plugin – (local plugin) used to introduce a single actor that will alter the value of GAMMA over time
The example’s main method in Code Block 6.1 adds the two plugins:
- Global properties plugin
- initialized with the three global properties
- adds the GlobalPropertyReport
- Model plugin
- Uses no inputs, but will add a single instance of the GammaActor class
The main method continues by associating the report to a file via the NIOReportItemHandler. It then forms a dimension for the experiment from variant values of ALPHA and BETA. Finally, it executes the experiment.
Initialization of the global properties is shown in Code Block 6.2.
private static GlobalPropertiesPluginData getGlobalPropertiesPluginData() {
.Builder builder = GlobalPropertiesPluginData.builder();//
GlobalPropertiesPluginData
= PropertyDefinition.builder()//
PropertyDefinition propertyDefinition .setType(Double.class)//
.setDefaultValue(2.0)//
.setPropertyValueMutability(false)//
.build();
.defineGlobalProperty(GlobalProperty.ALPHA, propertyDefinition, 0);
builder
= PropertyDefinition.builder()//
propertyDefinition .setType(Double.class)//
.setDefaultValue(5.0)//
.setPropertyValueMutability(false)//
.build();
.defineGlobalProperty(GlobalProperty.BETA, propertyDefinition, 0);
builder
= PropertyDefinition.builder()//
propertyDefinition .setType(Double.class)//
.setDefaultValue(1.0)//
.setPropertyValueMutability(true)//
.build();
.defineGlobalProperty(GlobalProperty.GAMMA, propertyDefinition, 0);
builder
return builder.build();
}
Code Block 6.3 shows the construction of the experiment’s single dimension.
private static Dimension getAlphaBetaDimension() {
List<Pair<Double, Double>> alphaBetaPairs = new ArrayList<>();
.add(new Pair<>(3.0, 10.0));
alphaBetaPairs.add(new Pair<>(12.0, 25.0));
alphaBetaPairs.add(new Pair<>(30.0, 40.0));
alphaBetaPairs.add(new Pair<>(45.0, 70.0));
alphaBetaPairs.add(new Pair<>(80.0, 100.0));
alphaBetaPairs
.Builder dimensionDataBuilder = FunctionalDimensionData.builder();
FunctionalDimensionData
for (int i = 0; i < alphaBetaPairs.size(); i++) {
<Double, Double> pair = alphaBetaPairs.get(i);
Pair.addValue("Level_" + i, (c) -> {
dimensionDataBuilderList<String> result = new ArrayList<>();
.Builder builder = c
GlobalPropertiesPluginData.getPluginDataBuilder(GlobalPropertiesPluginData.Builder.class);
.setGlobalPropertyValue(GlobalProperty.ALPHA, pair.getFirst(), 0);
builder.setGlobalPropertyValue(GlobalProperty.BETA, pair.getSecond(), 0);
builder.add(pair.getFirst().toString());
result.add(pair.getSecond().toString());
resultreturn result;
});
}
.addMetaDatum(GlobalProperty.ALPHA.toString());
dimensionDataBuilder.addMetaDatum(GlobalProperty.BETA.toString());
dimensionDataBuilder
= dimensionDataBuilder.build();
FunctionalDimensionData functionalDimensionData return new FunctionalDimension(functionalDimensionData);
}
The GammaActor class in Code Block 6.4 schedules 10 plans, set one day apart, to change the GAMMA value as a successive interpolation between the ALPHA and BETA values that are in turn controlled by the experiment.
public final class GammaActor {
public void init(ActorContext actorContext) {
int count = 10;
.range(0, count).forEach((i) -> {
IntStream.addPlan((c) -> {
actorContext= c
GlobalPropertiesDataManager globalPropertiesDataManager .getDataManager(GlobalPropertiesDataManager.class);
Double alpha = globalPropertiesDataManager.getGlobalPropertyValue(GlobalProperty.ALPHA);
Double beta = globalPropertiesDataManager.getGlobalPropertyValue(GlobalProperty.BETA);
double gamma = (beta - alpha) * i / count + alpha;
.setGlobalPropertyValue(GlobalProperty.GAMMA, gamma);
globalPropertiesDataManager}, i + 1);
});
}
}
The resultant global properties report shows the correct interpolated values for the five scenarios in Figure 6.1.
scenario | ALPHA | BETA | time | property | value |
---|---|---|---|---|---|
0 | 3.0 | 10.0 | 0.0 | ALPHA | 3.0 |
0 | 3.0 | 10.0 | 0.0 | BETA | 10.0 |
0 | 3.0 | 10.0 | 0.0 | GAMMA | 1.0 |
0 | 3.0 | 10.0 | 1.0 | GAMMA | 3.0 |
0 | 3.0 | 10.0 | 2.0 | GAMMA | 3.7 |
0 | 3.0 | 10.0 | 3.0 | GAMMA | 4.4 |
0 | 3.0 | 10.0 | 4.0 | GAMMA | 5.1 |
0 | 3.0 | 10.0 | 5.0 | GAMMA | 5.8 |
0 | 3.0 | 10.0 | 6.0 | GAMMA | 6.5 |
0 | 3.0 | 10.0 | 7.0 | GAMMA | 7.2 |
… | |||||
1 | 12.0 | 25.0 | 9.0 | GAMMA | 22.4 |
1 | 12.0 | 25.0 | 10.0 | GAMMA | 23.7 |
2 | 30.0 | 40.0 | 0.0 | ALPHA | 30.0 |
2 | 30.0 | 40.0 | 0.0 | BETA | 40.0 |
2 | 30.0 | 40.0 | 0.0 | GAMMA | 1.0 |
2 | 30.0 | 40.0 | 1.0 | GAMMA | 30.0 |
… | |||||
4 | 80.0 | 100.0 | 7.0 | GAMMA | 92.0 |
4 | 80.0 | 100.0 | 8.0 | GAMMA | 94.0 |
4 | 80.0 | 100.0 | 9.0 | GAMMA | 96.0 |
4 | 80.0 | 100.0 | 10.0 | GAMMA | 98.0 |