Most people who work with DIgSILENT PowerFactory know that sometimes it is convenient to automatize certain tasks to avoid tedious manual work. However, automatization is also key if you want to carry out a large number of simulations with varying parameters. Luckily, DIgSILENT PowerFactory comes with an API interface for Python to do precisely that.
This post gives a short overview of the Python API for DIgSILENT and provides the basic Python code to jump-start your DIgSILENT PowerFactory automatization.
Before we continue…
For the demonstration, I use a standard nine-bus system as shown below. The nine-bus system is available in the example projects in PowerFactory.
Install Python (if not installed yet)
For users who have not yet installed Python, I recommend installing the Anaconda distribution. It comes with all the needed packages including Spyder, which is a convenient editor to use with Python.
Advantages: open-source, easy to install, includes the most important packages
Load the PowerFactory application with Python
At the beginning of every Python script, you need to load the PowerFactory application. The code below loads the PowerFactory application and throws an error if unsuccessful. Important: a) replace the path (shown in red) with the path to the Python directory of your PowerFactory installation as indicated, b) close PowerFactory before running the script (it is not possible to run the script when an instance of PowerFactory is open).
import sys sys.path.append(r'C:\Program Files\DIgSILENT\PowerFactory 2021 SP1\Python\3.8') if __name__ == "__main__": import powerfactory as pf app = pf.GetApplication() if app is None: raise Exception('getting Powerfactory application failed')
Run a load flow
The next step is to define the project name and study case. Then the script is basically ready to run a load flow.
#define project name and study case projName = '_TSI_Nine-bus System' study_case = '01_Study_Case.IntCase' #activate project project = app.ActivateProject(projName) proj = app.GetActiveProject() #get the study case folder and activate project oFolder_studycase = app.GetProjectFolder('study') oCase = oFolder_studycase.GetContents(study_case) oCase.Activate() #get load flow object and execute oLoadflow=app.GetFromStudyCase('ComLdf') #get load flow object oLoadflow.Execute() #execute load flow
Print the results for generators, lines, and buses
Running a load flow is quite useless without seeing any results, right? That is why below you can find code on how to get and print the load flow results of generators, lines, and buses. Results for other elements can be added similarly.
#get the generators and their active/reactive power and loading Generators = app.GetCalcRelevantObjects('*.ElmSym') for gen in Generators: #loop through list name = getattr(gen, 'loc_name') # get name of the generator actPower = getattr(gen,'c:p') #get active power reacPower = getattr(gen,'c:q') #get reactive power genloading = getattr(gen,'c:loading') #get loading #print results print('%s: P = %.2f MW, Q = %.2f MVAr, loading = %.0f percent' %(name,actPower,reacPower,genloading)) print('-----------------------------------------') #get the lines and print their loading Lines=app.GetCalcRelevantObjects('*.ElmLne') for line in Lines: #loop through list name = getattr(line, 'loc_name') # get name of the line value = getattr(line, 'c:loading') #get value for the loading #print results print('Loading of the line: %s = %.2f percent' %(name,value)) print('-----------------------------------------') #get the buses and print their voltage Buses=app.GetCalcRelevantObjects('*.ElmTerm') for bus in Buses: #loop through list name = getattr(bus, 'loc_name') # get name of the bus amp = getattr(bus, 'm:u1') #get voltage magnitude phase = getattr(bus, 'm:phiu') #get voltage angle #print results print('Voltage at %s = %.2f pu %.2f deg' %(name,amp,phase))
Run an RMS simulation
In the following, I will show you how to run RMS simulations via the Python API. Just adapt the project name and the study case and you are ready to go.
#define project name and study case projName = '_TSI_nine_bus_system' study_case = '01_Study_Case.IntCase' #activate project project = app.ActivateProject(projName) proj = app.GetActiveProject() #get the study case folder and activate project oFolder_studycase = app.GetProjectFolder('study') oCase = oFolder_studycase.GetContents(study_case) oCase.Activate() # calculate initial conditions oInit = app.GetFromStudyCase('ComInc') #get initial condition calculation object oInit.Execute() #run RMS-simulation oRms = app.GetFromStudyCase('ComSim') #get RMS-simulation object oRms.Execute()
Retrieve RMS results from PowerFactory in Python
In this part, I will show you how to retrieve the results of the RMS simulation as pandas dataframe in Python. This can be very handy (for example) if you want to change the parameters of the PowerFactory model based on the RMS simulation results.
The script below shows a function to retrieve the results from the RMS simulation as pandas dataframe. The function also uses numpy and pandas commands, therefore, don’t forget to import them before.
The function retrieves the following variables:
- simulation time
- active/reactive power of generator 1
- terminal voltage of generator 1
- voltage of bus 1
- loading of line 4-5
If you want to retrieve other variables, simply adapt the code as needed.
import numpy as np import pandas as pd def getResults(): #get result file elmRes = app.GetFromStudyCase('*.ElmRes') app.ResLoadData(elmRes) #Get number of rows and columns NrRow = app.ResGetValueCount(elmRes,0) #get objects of interest oSG1 = app.GetCalcRelevantObjects('G1.ElmSym') oBus1 = app.GetCalcRelevantObjects('Bus 1.ElmTerm') oLine4_5 = app.GetCalcRelevantObjects('Line 4-5.ElmLne') #Get index of variable of interest ColIndex_time = app.ResGetIndex(elmRes,elmRes,'b:tnow') ColIndex_ut = app.ResGetIndex(elmRes,oSG1,'s:ut') ColIndex_P = app.ResGetIndex(elmRes,oSG1,'s:P1') ColIndex_Q = app.ResGetIndex(elmRes,oSG1,'s:Q1') ColIndex_speed = app.ResGetIndex(elmRes,oSG1,'s:xspeed') ColIndex_u_bus1 = app.ResGetIndex(elmRes,oBus1,'m:u') ColIndex_loading_line_4_5 = app.ResGetIndex(elmRes,oLine4_5,'c:loading') #pre-allocate result variables result_time = np.zeros((NrRow,)) result_ut = np.zeros((NrRow)) result_P = np.zeros((NrRow)) result_Q = np.zeros((NrRow)) result_speed = np.zeros((NrRow)) result_u_bus1 = np.zeros((NrRow)) result_loading_line_4_5 = np.zeros((NrRow)) #get results for each time step for i in range(NrRow): result_time[i] = app.ResGetData(elmRes,i,ColIndex_time) result_ut[i] = app.ResGetData(elmRes,i,ColIndex_ut) result_P[i] = app.ResGetData(elmRes,i,ColIndex_P) result_Q[i] = app.ResGetData(elmRes,i,ColIndex_Q) result_speed[i] = app.ResGetData(elmRes,i,ColIndex_speed) result_u_bus1[i] = app.ResGetData(elmRes,i,ColIndex_u_bus1) result_loading_line_4_5[i] = app.ResGetData(elmRes,i,ColIndex_loading_line_4_5) results = pd.DataFrame() results['time'] = result_time results['P'] = result_P results['Q'] = result_Q results['ut'] = result_ut results['speed'] = result_speed results['u_bus1'] = result_u_bus1 results['loading_line_4_5'] = result_loading_line_4_5 return results #query results RES = getResults()
The following screenshot shows an example of the pandas dataframe with the results of the RMS simulation. So all the variables defined in the getResults() function are available neatly in tabular format.
You can download the complete Python script of this post by clicking the banner at the end of the post.
I hope you find this article insightful. Consider leaving a comment to let me know your thoughts on the topic.
More insights within energy are to follow in the next article.
Btw, have you also checked how to query data from the ENTSO-E transparency platform? If not, find it here: Query data from ENTSO-E transparency platform