Adding observation to simulations and SimulData manipulation
Here, we will show how to use the visualization tool of
MECSYCO
. You will first need to add in your project the MECSYCO-visu jar and the dependencies (jfreechart, JCommon, Jzy3d 0.9.1, Gluegen and JOGL).
We will also manipulate the model artifact in order to create special output for the observer.
You can use any time step, but for better results, the default time step is advised.
For detailed information, see User Guide MECSYCO-visu.
Agent, dispatcher and connection
The observer is used as any other agent, but we give it the capacity to get more than one model artifact thanks to a dispatcher. For the first step, you need to create the observing system (agent and dispatcher):
ObservingMAgent obs=new ObservingMAgent("obs",maxSimulationTime);
SwingDispatcherArtifact Dispatcher=new SwingDispatcherArtifact();
obs.setDispatcherArtifact(Dispatcher);
Code 10: Creation of the observing system
Then you can connect the output port of the Lorenz agents to our observer like we did before for connecting the agents.
Add of special outputs
Some observing artifact need specific SimulData to work. We will now create specific ports where the usual data will be converted to the correct SimulData we need, i.e. a Tuple3 of Double values, a SimulVector of Double values, and a Tuple2 of Double values (cf User Guide section “Simulation data” or SimulData manipulation ).
Take a look to our model artifact (EquationModelArtifact) at the method named getExternalOutputEvent. This is where we manage the outputs of our model in order to create output ports. As you can see, 3 condition were not filled. They are our new outputs port (obs2D, obs3d and obsVector).
obs2D
We need to create a Tuple2 filled with real values. We will try to catch the X and Y values, to do this we have the method getVariable contains in the model (Equation). We can now create the event that will contains those values under the form of a Tuple2, with a time stamp:
final Double x=equation.getVariable("X");
final Double y=equation.getVariable("Y");
result=new SimulEvent(new Tuple2<>(x,y), equation.getTime());
Code 11: obs2D section
obs3d
This time we need a Tuple3. This is the same process as before, but we add the Z value.
obsVector
Lastly, we need a SimulVector, but as the guide said, the constructor is contained in the Java class ArrayedSimulVector. This vector will contain the value of X, Y and Z:
final Double x=equation.getVariable("X");
final Double y=equation.getVariable("Y");
final Double z=equation.getVariable("Z");
result=new SimulEvent(new ArrayedSimulVector<>(x,y,z), equation.getTime());
Code 12: obsVector section
else
This condition is already filled. It allows the user to use any kind of port’s name, but due to the method getVariable, only X, Y and Z can really work (state variable of the model).
Notes
The Z value is not contained in every model (LorenzX do not), so only agents’ link to LorenzY and LorenzZ can use the last two output ports.
You can now use them now to create the links (AgentX to obs with obs2D, AgentZ to obs with obs3d and obsVector for example).
Of course, obs is also an agent so at the end of the main, a startModelSoftware and a start are mandatory.
Graphics
You can now use all graphics available in MECSYCO-visu! But how?
Try to add code 13 after the new links you have created:
Dispatcher.addObservingArtifact (
new LiveTXGraphic ("Lorenz temporal", "Value", Renderer.Line,
new String [] {"SeriesX", "SeriesY", "SeriesZ"},
new String [] {"X", "Y", "Z" }));
Dispatcher.addObservingArtifact (
new LiveXYGraphic("Lorenz phase", "X", "Y", Renderer.Line, "XY", "XY"));
Dispatcher.addObservingArtifact (
new LiveBarGraphic("Lorenz bar", "Bars", "Value",
new String [] {"X", "Y", "Z"}, "XYZVector"));
Dispatcher.addObservingArtifact (
new LivePieGraphic("Lorenz Pie", new String [] {"X", "Y", "Z"}, "XYZVector"));
Dispatcher.addObservingArtifact (
new LiveEventGraphic("Lorenz factual", "time", "X", "X", "X"));
Dispatcher.addObservingArtifact (
new Live3DGraphic("Lorenz 3D", "X", "Y", "Z", "XYZ"));
Code 13: Creation of the observing artifacts for the graphs
In this code we named the input of the observing agent following this mapping:
- input “X” link to AgentX output
- input “Y” link to AgentY output
- input “Z” link to AgentZ output
- input “XY” link to the agent using output “obs2D”
- input “XYZ” link to the agent using output “obs3d”
- input “XYZVector” link to the agent using output “obsVector”
As you can see, it is not mandatory here to have the same names for input and output, only the same CentralizedEventCouplingArtifact is needed.
Nice graphics you have there, no? (Figure5) In all this case, we used the live version of our graphics as a consequence, the simulation take more time than before. In order to avoid this issue, it is advised to use the postmortem version of the graphs (replace Live by PostMortem).
Figure 5: All graphs
Post treatment
The visualization package does not only contain visualization tool, but post treatment tool too.
Data comparator
One of them is the data comparator. It will compare the result of the simulation with data sheets. For the Lorenz case, the data sheets with the right format are already provided. You only need to turn on the Debug system, and put it in info mode. To do so, thanks to your project explorer, go to the file mecsyco.properties in the folder conf, and make sure you have the following configuration:
# 1. Logging configuration
# 1.1 Logging level
# level order: off < error < warn < info < debug < trace < all
ROOT_LOGGING_LEVEL=info
# Use `inherited' value for using ROOT_LOGGING_LEVEL
M_AGENT_LOGGING_LEVEL=inherited
INTERFACE_LOGGING_LEVEL=inherited
COUPLING_LOGGING_LEVEL=inherited
# 1.2 Logging output
# Comment/Uncomment for enabling/disabling console or file logging
CONSOLE_LOGGING_ENABLED
# FILE_LOGGING_ENABLED
# 1.3 Other
ASYNC_LOGGING_ENABLED
LOGGING_FILE_PATH=./log
# %thread Thread name
# %level Logging level
# %logger Logger name
# %marker Logging marker
# %message Logging message
# %date ISO-8601 date
# %relative Elapsed time since the application starting
# %n New line
LOGGING_PATTERN=[%thread] %level %logger -- %message%n
Code 14: Mecsyco debug system properties
Now, everything is ready so let just try code 15 and see what the console has to say (Figure 6):
Dispatcher.addObservingArtifact (
new DataComparator(
new String[] { "resources/model_checking/lorenzLog_x.csv", "resources/model_checking/lorenzLog_y.csv","resources/model_checking/lorenzLog_z.csv"} ,
new String[] { "X", "Y", "Z" }));
Code 15: Creation of the observing artifact for data comparator
Figure 6: Comparator result
Logging
The package also contains a logging system, which means that you can save your result in external files. The logging can be done by creating one file per output you need to log, or by creating one for all:
String path="data_log/";
//Dispatcher.addObservingArtifact (new LoggingArtifact (
//new String[] {path+"X.csv",path+"Y.csv",path+"Z.csv"},
//new String [] {"Xobs","Yobs","Zobs"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"X.csv", new String [] {"X"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"Y.csv", new String [] {"Y"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"Z.csv", new String [] {"Z"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"XYZ.csv", new String [] {"XYZ"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"result.csv", new String [] {"X", "Y", "Z", "XYZ"}, "%time;%value\n"));
Dispatcher.addObservingArtifact (new LoggingArtifact (
path+"multi.csv", new String [] {"X", "Y", "Z", "XYZ"}, "%time;%value\n",
new String[]{"X_Tuple2_1","X_Tuple2_2","Y_Tuple2_1","Y_Tuple2_2","Z_Tuple2_1","Z_Tuple2_2","XYZ_Tuple3_1","XYZ_Tuple3_2","XYZ_Tuple3_3"},
false));
Code 16: Creation of the observing artifact for the logs
Since no agent have an output port that provide a simple Tuple1 containing the output value, we have to use the alternative option to create one file per output (line 7 to 12). You are free to create the output ports Xobs, Yobs and Zobs yourself and try the commented code (it means that the inputs of the observer are also named Xobs, Yobs and Zobs)! As the result you should have the following file created in data_log:
Figure 7: Files created and content
Analyze with R
The last functionality of MECSYCO-visu is the possibility to launch an R script in order to treat your result. This functionality is not optimal yet:
- When installing R, choose a file with a path without space or special character
- File path (of the file to treat) as to be define in the script
Dispatcher.addObservingArtifact (new LogToRProject (
path+"ResultR2.csv", new String[]{"X","Y","Z"}));
Code 17: Creation of the model artifact for launching R script
Figure 8: R launcher
ResultR2.csv is a file created by LogToRProject using the ports given (here X, Y, Z). This file can be use by your Rscript. In this example, we already provide you a script (DemoR.R) that will analyze the file named “result.csv”” in the folder “data_log” and create a file named “ResultR.csv” in the same folder. This Script will give the min and max value of each column, and the mean value. The csv to treat with this script follow the following structure:
- Without header
- The first column is not analyzed, so it could be the name, or the time step
- The others columns contain only real values
- Column separator are “;” and decimal separator are “.”
The results will also be found in “data_log”:
Figure 9: Files created and content (R)