Last time, I discovered that the OpenSees recorder command can send data to a TCP port and monitored it with Python. This time, I decided to directly obtain the model displacement and display it in real-time. The recorder TCP transmission does not affect the computational efficiency of OpenSees and we can achieve the following the effect in the figure,
Since a loop is created to listen on a TCP port, it is necessary to use Python subprocess or threading module for monitoring displacement. The main difference between a subprocess and a threading is the variable sharing mechanism. A subprocess is an independent process, so it has its own variable space and requires consideration of communication between processes. In contrast, threads share the same variable space with the main thread, so it only needs to set a global variable to enable data transmission to the threads. Additionally, due to some design reasons in Python, using threading does not achieve concurrency. If we want to perform multi-core computing, it is better to use subprocess method.
Let’s plot the flowchart for real-time model display,
Before starting the plotting, it is necessary to add the following statement in the OpenSees model,
1 |
|
The above statement sends the data of node 504 recorded by the recorder to port 127.0.0.1:8099. For more detailed information, see my previous post: OpenSees recorder data via TCP
First, define global variables and the port listening function,
1 |
|
Note that two global variables are defined above. The global variable Data
is refreshed and cleared after each data reception, so it is not suitable for plotting. Actual data used for plotting will be read from TotalData
.
Then, we need to define the subprocess part for OpenSees, which is used to call OpenSees to run FILENAME after starting TCP listening,
1 |
|
Here, the simple check_output
is used to run the opensees with FILENAME. It is worth noting that I have already added the folder where the OpenSees program is located to the PATH in the system environment variables, so opensees command can be used directly to start OpenSees analysis. Later, Matplotlib is called for plotting. The basic form is similar to the previous CPU monitoring. I slightly adjusted the figure refresh method. The figure axes will change as the data set changes,
1 |
|
Let’s talk about the emitter generator first, which is used as frames for the figure. Matplotlib frames can use iterators and generators as parameters, and Matplotlib will sequentially obtain frames from them for figure update functions. Additionally, the generator returns a tuple representing the newly generated data, which comes from the TotalData
. The update function, which updates the figure, is called at each interval. This function takes one parameter, which is the current frame, coming from the frames iterator or generator return value.
In the update function, it checks whether the data set edges have reached the edges of the axes. If so, it updates the axes and refreshes the figrue. Next, start the threads and begin plotting,
1 |
|
This allows to plot the animation above. However, it is important to note that when I started the OpenSees, I used time.sleep(3) to pause the program for three seconds. This is because OpenSees itself also needs to parse and execute TCL language. Therefore, without pausing, the plotting function cannot obtain data from TotalData
at the beginning, and the main program would exit with an error. Besides, we should try to run the program on the local machine during its operation. Online testing might experience packet loss, a issue that has been discussed previously and will not be discussed again.
All source code is available upon request.