UCEF Time Step Federation Tutorial - SCU-Smart-Grid-CPS/smart-grid-energy-simulation-research GitHub Wiki
This is the first tutorial on UCEF federations. A federation is a set of programs of different types that can send data between each other. Each object in a federation is called a federate. For SCU's research, we use Java federates to connect Python, MATLAB, and Energy Plus (EP or E+) simulations. This is necessary because normally each can only run independently, so an Energy Plus simulation would not be able to get data from Python and either the researcher could only access tools from one of them, or would have to manually transfer data for hundreds of timesteps one by one.
Virtual Machines
UCEF runs only in the Ubuntu Virtual Machines (VM). For SCU research, version 1.1.0 and 1.0.0 pre-compiled machines already exist; ask your advisor. For all others, UCEF is available here: https://github.com/usnistgov/ucef
[To Do: add VM tutorial]
Tutorial Intro
We will build a very primitive model showing the timesteps between three different federates. These will be a "socket" which would often be an E+ model outside of the UCEF VM, "processor" that links to a Java or Python code making decisions based on the data from socket, and "control" that combines data from socket and processor and returns it back out to the E+ model. In this simulation, they will only exchange the current timestep, but in later work they can exchange simulation data.
Build Federation in WebGME
The federations are built in a program called WebGME. See the tutorial: https://github.com/SCU-Smart-Grid-CPS/smart-grid-energy-simulation-research/wiki/Intro-to-WebGME-for-Federations
Once in the Federation Design, add three "JavaFederate" and four "C2WInteractionRoot" objects to the screen. Rename and arrange them as shown in the following picture, but do not connect the arrows yet.
Now double click on one of the C2WInteractionRoot objects. Click and drag "Parameter" onto the screen. Click on it and change it to ParameterType = double in the Property Editor.
Do the following with the C2WInteractionRoots (abridge to "Interaction"):
- For the interaction between socket and processor, create one double and name it something to signify it holds the time according to the socket, such as "sockTime". You can use different names if you prefer.
- For the interaction between socket and control, do the same as in 1. Using the same variable name is allowed but not required.
- For the interaction from processor to control, create two doubles, one for the time the socket sent, one for the time according to processor (I used "procTime").
- For the interaction from control to socket, create three doubles to represent time elapsed since the socket, time elapsed since the processor, and time according to the control (I used "elapsedFromSock", "elapsedFromProc", and "ctrlTime").
To add the arrows, hover over each item and click and drag one of the little white squares that pop up in the top and bottom to another object.
Now, export the _deployment and _generated from WebGME, and unzip in a convenient location.
Java Code
We now need to tell the federates what to do when sending data between each other.
Option 1: Eclipse
Preferred method; Eclipse has some useful utilities but downside is learning curve and can be slow to run.
- Open Eclipse. Import the directory where the federation is stored.
- Go to projectName_generated
- For the name of each federate, click on that folder, then
src/...many nested folders.../federateName
and open federateName.Java
Option 2: Text Editor
- Go to projectName_generated
- For the name of each federate, click on that folder, then
src/...many nested folders.../federateName
- Right click on federateName.Java and choose Open With gedit or Text Editor or Mousepad or Xed or Notepad (one of these, depending on your setup)
Edits
Note: See the example code if you get stuck; there are explanations within the code to help you. https://github.com/SCU-Smart-Grid-CPS/smart-grid-energy-simulation-research/tree/Tutorials/timestep_tutorial/timestep_bw_2021_06_generated
socket.java
Above the line private void execute() throw Exception{
add variables to send
ex:
double sockTime // the current time
and variables to receive: ex:
double elapProc;
double elapSock;
In the following section:
// Set the interaction's parameters.
//
// sockToCtrl vsockToCtrl = create_sockToCtrl();
// vsockToCtrl.set_actualLogicalGenerationTime( < YOUR VALUE HERE > );
// vsockToCtrl.set_federateFilter( < YOUR VALUE HERE > );
// vsockToCtrl.set_originFed( < YOUR VALUE HERE > );
// vsockToCtrl.set_sockTime( < YOUR VALUE HERE > );
// vsockToCtrl.set_sourceFed( < YOUR VALUE HERE > );
// vsockToCtrl.sendInteraction(getLRC(), currentTime + getLookAhead());
// sockToProc vsockToProc = create_sockToProc();
// vsockToProc.set_actualLogicalGenerationTime( < YOUR VALUE HERE > );
// vsockToProc.set_federateFilter( < YOUR VALUE HERE > );
// vsockToProc.set_originFed( < YOUR VALUE HERE > );
// vsockToProc.set_sockTime( < YOUR VALUE HERE > );
// vsockToProc.set_sourceFed( < YOUR VALUE HERE > );
// vsockToProc.sendInteraction(getLRC(), currentTime + getLookAhead());
checkReceivedSubscriptions();
Now set the current time:
sockTime = currentTime;
Note: we could have instead skipped this step and simply put in "currentTime" everywhere there is "sockTime" below. It was done this way here because it's easier to explain where the info goes.
Create the C2W Interaction root objects through which info is sent across. Copy paste this from the big commented section above labeled "Set the interaction's parameters" Note we need two of them in the socket - sockToCtrl to control federate, and sockToProc to processor federate.
sockToCtrl vsockToCtrl = create_sockToCtrl();
sockToProc vsockToProc = create_sockToProc();
Set the variable sockTime in each of the C2Ws Copy pasted from above, but replaced "< YOUR VALUE HERE >" with "sockTime"
vsockToCtrl.set_sockTime( sockTime );
vsockToProc.set_sockTime( sockTime );
Copy paste these lines without modification. These tell the socket to send data in the interactions
vsockToCtrl.sendInteraction(getLRC(), currentTime + getLookAhead());
vsockToProc.sendInteraction(getLRC(), currentTime + getLookAhead());
Now log the output. The first part in quotes is a string, the {}
means insert variable, and the sockTime after the comma is the variable to insert.
log.info("=> sent sockTime = {}", sockTime);
Further down, find the method:
private void handleInteractionClass(ctrlToSock interaction) {
///////////////////////////////////////////////////////////////
// TODO implement how to handle reception of the interaction //
///////////////////////////////////////////////////////////////
// HERE
}
Even though elapsedFromSock and elapsedThruProc were sent by control, by default socket doesn't know to do anything with them. So we need to tell it to retrieve them, set them equal to a useful known variable, and then log them for us. After TODO, before the ending curly braces insert the following
double elapsedFromSock = interaction.get_elapsedFromSock();
double elapsedThruProc = interaction.get_elapsedThruProc();
double ctrlTime = interaction.get_ctrlTime();
Immediately below, we will log this data so that we can see it later and debug.
log.info("From socket, fromSock = {}, thruProc = {}", elapsedFromSock);
log.info("From processor, thruProc = {}", elapsedThruProc);
processor.java
Similar to socket, but with the noted changes. For help, see the example files.
Above the line private void execute() throw Exception{
add variables for the socket time and processor time.
Under Set the interaction's parameters, do the same except instead set procTime = current time, and set up only one interaction from processor to control and send two variables, one for socket time, one for processor time. Log them.
In handleInteractionClass(sockToProc interaction)
get only one variable for socket time and log it.
control.java
Above the line private void execute() throw Exception{
add variables for socket time, socket time from processor, processor time, control time, and elapsed times from socket and processor.
Under Set the interaction's parameters, do the same except instead set ctrlTime = current time, calculate the elapsed time from socket and from processor, and set up only one interaction from processor to control and send three variables for control time, socket elapsed time, and processor elapsed time. Log them.
Control has two handleInteractionClass
methods. Look in the parenthesis to figure out which is which. From the socket, get only one variable for socket time and log it. From processor, get two variables for processor time and the socket time according to processor. Log them.
Build & Compile
When the code is complete, be sure to save the files (ok to leave open), then build and compile. Build instructions: https://github.com/SCU-Smart-Grid-CPS/smart-grid-energy-simulation-research/wiki/Build-&-Compile-UCEF-Simulations
Ready to Run
Run the simulation as described here: https://github.com/SCU-Smart-Grid-CPS/smart-grid-energy-simulation-research/wiki/Running-UCEF-Simulations