Run DIgSILENT PowerFactory through the Python API – kickstart your PowerFactory automatization

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.

Screenshot of the nine-bus system in PowerFactory
Screenshot of the nine-bus system 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)[0]
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)[0]
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')[0]
    oBus1 = app.GetCalcRelevantObjects('Bus 1.ElmTerm')[0]
    oLine4_5 = app.GetCalcRelevantObjects('Line 4-5.ElmLne')[0]

    #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)[1]
        result_ut[i] = app.ResGetData(elmRes,i,ColIndex_ut)[1]
        result_P[i] = app.ResGetData(elmRes,i,ColIndex_P)[1]
        result_Q[i] = app.ResGetData(elmRes,i,ColIndex_Q)[1]       
        result_speed[i] = app.ResGetData(elmRes,i,ColIndex_speed)[1]       
        result_u_bus1[i] = app.ResGetData(elmRes,i,ColIndex_u_bus1)[1]       
        result_loading_line_4_5[i] = app.ResGetData(elmRes,i,ColIndex_loading_line_4_5)[1]       
    
    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.

Screenshot of the pandas table with the RMS results
Screenshot of the pandas dataframe with the RMS results

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

Michael

call to action to download the python code to run load flow and rms simulations with digsilent powerfactory
Share this post:

Similar Posts

11 Comments

  1. Nice! I’m trying to use the files but I only have acces to 2018 PowerFactory version. Could you share the .pdf in this version? I will appreciate it.

    Regards,

    1. Hi Francisco, now I am using PF 2021 where it is not possible to export to version 2018.
      The easiest way for you would be to just load the nine-bus system from PF 2018. It is available there as well.

      All the best,
      Michael

        1. Hi Michael,

          the load flow and the RMS calculation automatically consider all components that are in-service.

          All the best,
          Michael

          1. The RMS simulation displays result for Generator 1 only.
            My question is how can you create a “for loop” to display result for all 3 generators at the same time

          2. In the function “def getResults():” at the beginning of script it is defined which variables to retrieve from the RMS simulation from PowerFactory. There you can define all desired variables. For generators you can follow the example of the definition for G1.

  2. Hey, I’m getting an error at the ‘oCase = oFolder_studycase.GetContents(study_case)[0]’ line: AttributeError: ‘NoneType’ object has no attribute ‘GetContents’… any idea what’s causing this/how to fix this? Thx!

    1. Hi Meg, sorry for the late reply. The error means that the study case folder could not be found. Maybe the project could not be loaded…

Leave a Reply