def _initialize_psse(self): redirect.psse2py() psspy.psseinit(1000) # Read load flow and dynamic files psspy.read(0, self.raw_file) psspy.dyre_new([1, 1, 1, 1], self.dyr_file, "", "", "") psspy.fdns([0, 0, 0, 1, 1, 0, 0, 0]) # Convert Generator and Loads psspy.cong(0) # Order Network for matrix operation psspy.ordr(0) # Factorize Admittance matrix psspy.fact() # Solve switching study network solutions psspy.tysl()
if LoadScenario == "SummerPeakLoad": file_name = "SummerHi-20171219-153047-34-SystemNormal_all_bus_DDSF" if LoadScenario == "SummerLowLoad": file_name = "SummerLo-20171226-043047-34-SystemNormal_all_bus_DDSF" if LoadScenario == "SimplifiedSystem": file_name = "NEOEN Western Downs Solar Farm_C3WV_mod" ######################################### Read Input List ####################################### # Active Power Setpoint ActivePowerSetpoint = range(0, 101, 50) ReactivePowerSetpoint = [-40, 40] vref = numpy.arange(0.70, 1.3, 0.05) S = 100 # Initialize psspy.read(0, GridInfoPath + LoadScenario + "/" + file_name + ".raw") psspy.resq(GridInfoPath + LoadScenario + "/" + file_name + ".seq") psspy.dyre_new([1, 1, 1, 1], GridInfoPath + LoadScenario + "/" + file_name + ".dyr", "", "", "") psspy.addmodellibrary(HuaweiModelPath + 'HWH9001_342.dll') psspy.addmodellibrary(HuaweiModelPath + 'PPC_PSSE_ver_13_08_34_2_10082018_AUS.dll') psspy.addmodellibrary(HuaweiModelPath + 'MOD_GPM_SB_V7.dll') psspy.dynamics_solution_param_2([_i, _i, _i, _i, _i, _i, _i, _i], [1.000, _f, 0.001, 0.004, _f, _f, _f, _f]) for i in range(0, len(ActivePowerSetpoint)): for j in range(0, len(ReactivePowerSetpoint)): for k in range(0, len(vref)): # re - initialize
if LoadScenario == "WinterLowLoad": file_name = "---" if LoadScenario == "SimplifiedSystem": file_name = "Tamworth_SMIB" SMIB_bus_no = 9999 # SIM bus number, where the generator is added for simplified SMIB system POC_bus_gen = 106 # POC bus number at near end/farm side POC_bus_grid = 9999 # POC bus number at far end/grid side inverter_bus_1 = 100 inverter_bus_2 = 200 # Initialize psspy.read(0, GridInfoPath + file_name + ".raw") P_Record = [] Q_Record = [] T_Record = [] V_Record = [] S_Record = [] overloop = 0 S_1 = 83.6 # S for inverter bus. S_BESS = 21.14 # S for inverter bus. overloop = 0
def main(): try: ''' Drives a PSS/E Dynamic simulation and returns values ''' ##### Get everything set up on the PSSE side redirect.psse2py() #output = StringIO.StringIO() with silence(): psspy.psseinit(buses=80000) _i = psspy.getdefaultint() _f = psspy.getdefaultreal() _s = psspy.getdefaultchar() """ # Redirect any psse outputs to psse_log psspy.report_output(2,psse_log,[0,0]) psspy.progress_output(2,psse_log,[0,0]) #ignored psspy.alert_output(2,psse_log,[0,0]) #ignored psspy.prompt_output(2,psse_log,[0,0]) #ignored """ k = 1 for rawFile in RawFileList: # get the percentage loading from the raw file name if rawFile == 'savnw_conp.raw': PL = '100' else: rawFileName = rawFile.replace('.raw', '') PL = rawFileName[-3:] #Parameters. CONFIGURE THIS settings = { # use the same raw data in PSS/E and TS3ph ##################################### 'filename': rawFile, #use the same raw data in PSS/E and TS3ph ################################################################################ 'dyr_file': dyrFile, 'out_file': 'output2.out', 'pf_options': [ 0, #disable taps 0, #disable area exchange 0, #disable phase-shift 0, #disable dc-tap 0, #disable switched shunts 0, #do not flat start 0, #apply var limits immediately 0, #disable non-div solution ] } ##### Load Raw Datafile and do power flow print "\n Reading raw file:", settings['filename'] # " Reading raw file: {0:s}".format('text') FaultRpu = 1e-06 Sbase = 100.0 #FaultBusNomVolt = float(BusDataDict[FaultBus].NominalVolt) #Zbase = FaultBusNomVolt**2/Sbase # float since Sbase is a float #Rohm = FaultRpu*Zbase # fault impedance in ohms ########################## # run nested loops to see if there are any abnormal low voltages simCount = 0 # to keep track of how many simulations are already done croppedHVLineSet = list(HVLineSet) for line1 in croppedHVLineSet: for line2 in croppedHVLineSet: # stability_indicator = 1 # Bus_issues = [] # list of buses where issues (low voltage or high dv_dt) are reported # the lines cannot be the same if line1 == line2: continue # part to ensure there is no duplication of events currentSet = line1 + ';' + line2 currentSetReverse = line2 + ';' + line1 # if case causes topology inconsistencies, continue if currentSet in topology_inconsistent_set or currentSetReverse in topology_inconsistent_set: continue line1Elements = line1.split(',') line2Elements = line2.split(',') # Line 1 params L1Bus1 = int(line1Elements[0]) L1Bus2 = int(line1Elements[1]) L1cktID = line1Elements[2].strip("'").strip() # Line 2 params L2Bus1 = int(line2Elements[0]) L2Bus2 = int(line2Elements[1]) L2cktID = line2Elements[2].strip("'").strip() FaultBusList = [L2Bus1, L2Bus2] # apply faults at both buses for FaultBus in FaultBusList: output = StringIO.StringIO() with silence(): ierr = psspy.read(0, settings['filename']) #This is for the power flow. I'll use the solved case instead ierr = psspy.fnsl(settings['pf_options']) ##### Prepare case for dynamic simulation # Load conversion (multiple-step) psspy.conl(_i, _i, 1, [0, _i], [_f, _f, _f, _f]) # all constant power load to constant current, constant reactive power load to constant admittance # standard practice for dynamic simulations, constant MVA load is not acceptable psspy.conl(1, 1, 2, [_i, _i], [100.0, 0.0, 0.0, 100.0]) psspy.conl(_i, _i, 3, [_i, _i], [_f, _f, _f, _f]) ierr = psspy.cong(0) #converting generators ierr = psspy.ordr( 0 ) #order the network nodes to maintain sparsity ierr = psspy.fact( ) #factorise the network admittance matrix ierr = psspy.tysl(0) #solving the converted case ierr = psspy.dynamicsmode(0) #enter dynamics mode print "\n Reading dyr file:", settings['dyr_file'] ierr = psspy.dyre_new([1, 1, 1, 1], settings['dyr_file']) ierr = psspy.docu(0, 1, [ 0, 3, 1 ]) #print the starting point of state variables # select time step ############################################################## ierr = psspy.dynamics_solution_params( [_i, _i, _i, _i, _i, _i, _i, _i], [ _f, _f, 0.00833333333333333, _f, _f, _f, _f, _f ], 'out_file') # the number here is the time step ################################################################################ ##### select channels ierr = psspy.delete_all_plot_channels( ) # clear channels # get all the bus voltages, angles and frequencies for bus in BusDataDict: bus = int(bus) ierr = psspy.voltage_and_angle_channel( [-1, -1, -1, bus]) ierr = psspy.bus_frequency_channel([-1, bus]) eventStr = PL + '/' + line1 + ';' + line2 + '/F' + str( FaultBus) print 'Event: {}'.format(eventStr) # get the nominal voltages as well as the fault impedance in ohms FaultBusNomVolt = float( BusDataDict[str(FaultBus)].NominalVolt) Zbase = FaultBusNomVolt**2 / Sbase # float since Sbase is a float Rohm = FaultRpu * Zbase # fault impedance in ohms # run simulation till just before the fault ResultsDict = {} #output = StringIO.StringIO() with silence(output): ierr = psspy.strt(0, settings['out_file']) ierr = psspy.run(0, 0.1, 1, 1, 1) ierr = psspy.dist_branch_trip( L1Bus1, L1Bus2, L1cktID) #output = StringIO.StringIO() with silence(output): ierr = psspy.run(0, 0.2, 1, 1, 1) #fault on time outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + eventStr + ':' print 'Network did not converge between branch 1 trip and fault application, skipping...' continue ####### # check for convergence during fault #output = StringIO.StringIO() with silence(output): ierr = psspy.dist_bus_fault( FaultBus, 3, 0.0, [Rohm, 0.0]) ierr = psspy.run(0, 0.3, 1, 1, 1) #fault off time ierr = psspy.dist_clear_fault(1) outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + eventStr + ':' print 'Network did not converge during fault, skipping...' continue # check for convergence between fault clearance and second branch trip #output = StringIO.StringIO() with silence(output): ierr = psspy.run(0, 0.31, 1, 1, 1) #fault off time ierr = psspy.dist_branch_trip( L2Bus1, L2Bus2, L2cktID) ierr = psspy.run(0, 0.35, 1, 1, 1) #fault off time # check for non-convergence #output = StringIO.StringIO() outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + eventStr + ':' print 'Network did not converge between fault clearance and branch 2 trip, skipping...' continue # select run time ############################################################## output = StringIO.StringIO() with silence(output): ierr = psspy.run( 0, 10.0, 1, 1, 1 ) #exit time (second argument is the end time) ################################################################################ # check for non-convergence outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + eventStr + ':' print 'Network did not converge sometime after 2nd branch trip, skipping...' continue outputData = dyntools.CHNF(settings['out_file']) data = outputData.get_data() channelDict = data[ 1] # dictionary where the value is the channel description valueDict = data[ 2] # dictionary where the values are the signal values, keys match that of channelDict tme = valueDict['time'] # get time ResultsDict['time'] = tme for key in channelDict: if key == 'time': continue signalDescr = channelDict[key] words = signalDescr.split() signalType = words[0].strip() bus = words[1].strip() #print Bus + ' ' + signalType if bus not in ResultsDict: ResultsDict[bus] = Results() if signalType == 'VOLT': ResultsDict[bus].volt = valueDict[key] elif signalType == 'ANGL': ResultsDict[bus].angle = valueDict[key] elif signalType == 'FREQ': ResultsDict[bus].freq = valueDict[key] EventsDict[eventStr] = ResultsDict simCount += 1 print 'Simulation ' + str(simCount) + ' out of ' + str( totalSims) # Uncomment next two lines if you want to see the output #with open('output'+str(k) + '.txt','w') as f: # f.write(outputStr) k += 1 save_obj(EventsDict, 'EventData') except Exception: traceback.print_exc(file=logfile) sys.exit(0)
def runSimulation(self): """Runs the simulation by crating an instance of psspy, loading the raw and dyr data, applying the disturbance and controling PEV output power. Finally plots in native PSS/E or export to matlab.""" sufix = str(self._disturbance) + "_" + str(self._control) conec_file = trash_dir + "\\CC1_" + sufix + ".out" conet_file = trash_dir + "\\CT1_" + sufix + ".out" compile_file = trash_dir + "\\compile_" + sufix + ".out" psspy.psseinit(49) #suppress output if required, else redirect it to python if self._suppress_output: psspy.report_output(6, "", [0, 0]) psspy.progress_output(6, "", [0, 0]) #psspy.progress_output(2,r"""pot.txt""",[0,0]) else: #redirect psse output to python import redirect redirect.psse2py() #---------------------- #read in case data psspy.read(0, self._power_system_object._raw_filename) #solve the power flow psspy.fdns([0, 0, 0, 1, 1, 1, 99, 0]) #---------------------- #convert all generators psspy.cong(0) #---------------------- #conv_standard_loads #change the vector of numbers to get constant current, admittance or power conversion utils.convertLoads([0.0, 100.0, 0.0, 100.0]) #convert the PEVs to constant power loads utils.convertPEVs() #---------------------------------------- #read in dynamics data psspy.dyre_new([1, 1, 1, 1], self._power_system_object._dyr_filename, "", "", "") #solve power flow with dynamics tysl - and fact devices (was in tutorial) - not sure if we need it though psspy.fact() psspy.tysl(1) #set up pre designated channels self._channels.setUpChannels() #designate channel output_file psspy.strt(0, self._channels._channel_file) self._performDynamicSimulation() if self._plot: self._channels.plot(self._channels._channels_to_include) if self._export_to_matlab: description = sufix.replace(" ", "_").replace(".", "_").replace("=", "__") self._channels.exportToMatlab( matlab_dir + "\\" + description + ".m", description, True, True, self._export_figures) if self._export_figures: import win32com.client h = win32com.client.Dispatch('matlab.application') h.Execute("cd('" + os.getcwd() + "\\" + matlab_dir + "');") h.Execute(description) #clean up try: os.remove(conec_file) except: pass try: os.remove(conet_file) except: pass try: os.remove(compile_file) except: pass return self._channels
def main(): # set output path outpath = r"""TpeOut\\""" # TPE reduction TPE_list = r"""TPE_list.xlsx""" rootbus1_list, bus_red_list, d1bus_list, rootbus2_list, retdbus_list, N_tpe = read_bus_TPE(TPE_list) for instance_i in range(N_tpe): bus_root1 = rootbus1_list[instance_i] bus_root2 = rootbus2_list[instance_i] bus_ret = retdbus_list[instance_i] bus_red = bus_red_list[instance_i] bus_d1 = d1bus_list[instance_i] # read power flow model before reduction step i psspy.psseinit(50000) if instance_i == 0: psspy.read(0, r"""FullModel\wecc179_v33.raw""") else: pass psspy.fnsl([1, 0, 0, 1, 1, 0, 0, 0]) # get power flow data pfd = PFData() pfd.getdata(psspy) # count elements in full model if instance_i == 0: n_gen_bf, n_load_bf, n_bus_bf, n_line_bf, n_xfmr_bf, n_shunt_bf = CountEle(pfd) # prepare data for two-port equivalent P1, Q1, Vm1, Va1, PrateA1, PrateB1, P3, Q3, Vm3, Va3, PrateA3, PrateB3, PL, QL, PG, QG, MW_ll, MW_ul, Mvar_ll,\ Mvar_ul, MVA_base, PS, QS, load_bus, gen_bus, shunt_bus = read_subsys_TPE(pfd, bus_root1, bus_red, bus_d1, bus_root2, bus_ret) # calculate TPE equivalent Vm2, Va2, r1, x1, r2, x2 = CalcTwoPortEqui(pfd, P1, Q1, Vm1, Va1, P3, Q3, Vm3, Va3, PL, QL, PG, QG, PS, QS) # Implement two-port equivalent in PSSE DoTpeInPsse(psspy, pfd, bus_root1, bus_root2, bus_ret, bus_red, bus_d1, PL, QL, PG, QG, PS, QS, PrateA1, PrateB1, PrateA3, PrateB3, MW_ll, MW_ul, Mvar_ll, Mvar_ul, MVA_base, Vm2, Va2, r1, x1, r2, x2) # save new power flow data psspy.rawd_2(0, 1, [0, 0, 1, 0, 0, 0, 0], 0, outpath + "tpe_step_" + str(instance_i + 1)) # calc a summary for TPE reduction pfd.getdata(psspy) n_gen_af, n_load_af, n_bus_af, n_line_af, n_xfmr_af, n_shunt_af = CountEle(pfd) # print("\nTPE reduction summary:") print("(# of elements, Before, After, Reduction %)") print("-----------------------------------------------") print(" Buses: ", n_bus_bf, n_bus_af, str(float((n_bus_bf - n_bus_af))/n_bus_bf*100)[0:5] + "%") print(" Generations: ", n_gen_bf, n_gen_af, str(float((n_gen_bf - n_gen_af))/n_gen_bf*100)[0:5] + "%") print(" Loads: ", n_load_bf, n_load_af, str(float((n_load_bf - n_load_af))/n_load_bf*100)[0:5] + "%") print(" Lines: ", n_line_bf, n_line_af, str(float((n_line_bf - n_line_af))/n_line_bf*100)[0:5] + "%") print("Transformers: ", n_xfmr_bf + 1, n_xfmr_af + 1, str(float((n_xfmr_bf - n_xfmr_af))/(n_xfmr_bf+1)*100)[0:5] + "%") print(" Shunts: ", n_shunt_bf, n_shunt_af, str(float((n_shunt_bf - n_shunt_af)) / (n_shunt_bf + 1) * 100)[0:5] + "%")
import excelpy redirect.psse2py() psspy.psseinit(10000) # required files raw_file = r'OPAL50.raw' dyr_file = r'OPAL50.dyr' # generated files file_name = r'39b_V2' out_file = r'PSSE_' + file_name + r'.out' psse_xls_file = r'PSSE_' + file_name + r'.xlsx' # Read load flow and dynamic files psspy.read(0, raw_file) psspy.dyre_new([1, 1, 1, 1], dyr_file, "", "", "") # Remove old xls files if os.path.isfile(psse_xls_file) == True: os.remove(psse_xls_file) # Convert Generator and Loads psspy.cong(0) psspy.conl(0, 1, 1, [1, 0], [0.0, 100.0, 0.0, 100.0]) psspy.conl(0, 1, 2, [1, 0], [0.0, 100.0, 0.0, 100.0]) psspy.conl(0, 1, 3, [1, 0], [0.0, 100.0, 0.0, 100.0]) # Order Network for matrix operation psspy.ordr(0)
'output2.out', 'pf_options': [ 0, #disable taps 0, #disable area exchange 0, #disable phase-shift 0, #disable dc-tap 0, #disable switched shunts 0, #do not flat start 0, #apply var limits immediately 0, #disable non-div solution ] } output = StringIO.StringIO() with silence(output): ierr = psspy.read(0, settings['filename']) #This is for the power flow. I'll use the solved case instead ierr = psspy.fnsl(settings['pf_options']) ##### Prepare case for dynamic simulation # Load conversion (multiple-step) psspy.conl(_i, _i, 1, [0, _i], [_f, _f, _f, _f]) # all constant power load to constant current, constant reactive power load to constant admittance # standard practice for dynamic simulations, constant MVA load is not acceptable psspy.conl(1, 1, 2, [_i, _i], [100.0, 0.0, 0.0, 100.0]) psspy.conl(_i, _i, 3, [_i, _i], [_f, _f, _f, _f]) ierr = psspy.cong(0) #converting generators ierr = psspy.ordr(0) #order the network nodes to maintain sparsity ierr = psspy.fact() #factorise the network admittance matrix ierr = psspy.tysl(0) #solving the converted case
#BusAngleDict[Bus] = angle ComedBusSet.add(Bus) #### #planningRaw = 'hls18v1dyn_1219.raw' psse_log = 'log_allCAPEComedBusReports.txt' redirect.psse2py() psspy.psseinit(buses=80000) # Silence all psse outputs psspy.report_output(2, psse_log, [0, 0]) psspy.progress_output(6, psse_log, [0, 0]) #ignored psspy.alert_output(6, psse_log, [0, 0]) #ignored psspy.prompt_output(6, psse_log, [0, 0]) #ignored ############################## ierr = psspy.read(0, CAPERaw) # File:"C:\Users\bikiran_remote\Desktop\report_bus_data.py", generated on MON, MAR 05 2018 19:33, release 33.03.00 for bus in ComedBusSet: ierr = psspy.bsys(1, 0, [0.0, 0.0], 0, [], 1, [int(bus)], 0, [], 0, []) # PAGE 1373 of API book ierr = psspy.lamp(1, 0) # page 258 of API book """ with open(psse_log,'r') as f: filecontent = f.read() fileLines = filecontent.split('\n') print fileLines[-1] """
L2Bus2 = int(line2Elements[1]) L2cktID = line2Elements[2].strip("'").strip() FaultBusList = [L2Bus1, L2Bus2] # apply faults at both buses for FaultBus in FaultBusList: output = StringIO.StringIO() with silence(output): #ierr = psspy.read(0, settings['filename']) ierr = psspy.read(0, bullshit) #This is for the power flow. I'll use the solved case instead ierr = psspy.fnsl(settings['pf_options']) ##### Prepare case for dynamic simulation # Load conversion (multiple-step) psspy.conl(_i,_i,1,[0,_i],[_f,_f,_f,_f]) # all constant power load to constant current, constant reactive power load to constant admittance # standard practice for dynamic simulations, constant MVA load is not acceptable psspy.conl(1,1,2,[_i,_i],[100.0, 0.0,0.0, 100.0]) psspy.conl(_i,_i,3,[_i,_i],[_f,_f,_f,_f]) ierr = psspy.cong(0) #converting generators ierr = psspy.ordr(0) #order the network nodes to maintain sparsity
def changeLoad(raw, start, end, step, newdir): """ New raw files are created for each percentage step in [start,end]. The current step defines the percentage scaling up (or down) factor for load and generation """ # convert the raw file to another one where all the load is constant power raw_conp = raw.replace('.raw', '') + '_conp.raw' redirect.psse2py() psspy.psseinit(buses=80000) # ignore the output psspy.report_output(6, '', [0, 0]) psspy.progress_output(6, '', [0, 0]) psspy.alert_output(6, '', [0, 0]) psspy.prompt_output(6, '', [0, 0]) # read the raw file and convert all the loads to constant power ierr = psspy.read(0, raw) # multi-line command to convert the loads to 100% constant power psspy.conl(0, 1, 1, [1, 0], [0.0, 0.0, 0.0, 0.0]) psspy.conl(0, 1, 2, [1, 0], [0.0, 0.0, 0.0, 0.0]) psspy.conl(0, 1, 3, [1, 0], [0.0, 0.0, 0.0, 0.0]) ierr = psspy.rawd_2(0, 1, [1, 1, 1, 0, 0, 0, 0], 0, raw_conp) # run change Load on the constant power load raw file rawBusDataDict = getBusData(raw_conp) # create a new directory to put the files in currentdir = os.getcwd() if not os.path.exists(newdir): os.mkdir(newdir) output_dir = currentdir + '/' + newdir #genDiscount = 0.90 # ratio of the actual increase in generation genDiscount = 1.0 lossRatio = 0.0 # gen scale-up factor: (scalePercent + (scalePercent-100)*lossRatio)/100 ############################################ # create new raw files with scaled up loads and generation for scalePercent in range(start, end + step, step): scalePercent = float( scalePercent) # float is needed, otherwise 101/100 returns 1 scalePercentInt = int( scalePercent) # integer value needed to append to filename scalePercentStr = str(scalePercentInt) # variables to store load data loadBusList = [] # list of load buses (string) loadPList = [] # list of Pload values (string) loadQList = [] # list of Qload values (string) loadPListInt = [] # list of Pload values (float) loadQListInt = [] # list of Qload values (float) #loadBusListInt = [] # list of load buses (int) # variables to store gen data genBusList = [] #genBusListInt = [] genPList = [] genMVAList = [] genMVAListInt = [] genPListInt = [] raw_name = raw_conp.replace('.raw', '') out_file = raw_name + scalePercentStr + '.raw' # output file out_path = output_dir + '/' + out_file impLoadBuses = [ ] # enter specified load buses to scale, if empty all loads are scaled incLoss = ( scalePercent - 100 ) * lossRatio # Additional percentage increase in Pgen (to account for losses) ############################################# #Read raw file with open(raw_conp, 'r') as f: filecontent = f.read() filelines = filecontent.split('\n') ## Get start and end indices of load and gen info ######################################### loadStartIndex = filelines.index( '0 / END OF BUS DATA, BEGIN LOAD DATA') + 1 loadEndIndex = filelines.index( '0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA') genStartIndex = filelines.index( '0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA') + 1 genEndIndex = filelines.index( '0 / END OF GENERATOR DATA, BEGIN BRANCH DATA') ############################################################################## totalPincr = 0.0 totalQincr = 0.0 percentIncr = (scalePercent - 100.0) / 100 # increment in percentage newPConList = [] newQConList = [] newIPList = [] newIQList = [] newZPList = [] newZQList = [] # Extract load info for i in range(loadStartIndex, loadEndIndex): words = filelines[i].split(',') loadBus = words[0].strip() #loadBusList.append(words[0].strip()) loadPCon = float(words[5].strip()) loadQCon = float(words[6].strip()) loadIP = float(words[7].strip()) loadIQ = float(words[8].strip()) loadZP = float(words[9].strip()) loadZQ = float(words[10].strip()) # calculate the total MW (MVAr) increase in load loadBusVolt = float(rawBusDataDict[loadBus].voltpu) Pincr = percentIncr * ( loadPCon + loadIP * loadBusVolt + loadZP * loadBusVolt**2 ) # this equation is provided in PAGV1 page 293 Qincr = percentIncr * (loadQCon + loadIQ * loadBusVolt + loadZQ * loadBusVolt**2) totalPincr += Pincr totalQincr += Qincr ### # new load values newPConList.append(loadPCon * scalePercent / 100) newQConList.append(loadQCon * scalePercent / 100) newIPList.append(loadIP * scalePercent / 100) newIQList.append(loadIQ * scalePercent / 100) newZPList.append(loadZP * scalePercent / 100) newZQList.append(loadZQ * scalePercent / 100) """ loadPList.append(words[5].strip()) # adding P value (constant power) loadQList.append(words[6].strip()) # adding Q value (constant power) loadIPList.append(words[7].strip()) # constant current P loadIQList.append(words[7].strip()) # constant current Q loadZPList.append(words[9].strip()) # adding P value (constant admittance) loadZQList.append(words[10].strip()) # adding Q value (constant admittance) """ # get total MW gen totalGenMW = 0.0 # total generation excluding the swing bus for i in range(genStartIndex, genEndIndex): words = filelines[i].split(',') GenBus = words[0].strip() if rawBusDataDict[GenBus].type == '3': continue PGen = float(words[2].strip()) totalGenMW += PGen # get new MW Gen GenMWDict = {} # dictionary to hold new PGen values for i in range(genStartIndex, genEndIndex): words = filelines[i].split(',') Bus = words[0].strip() if rawBusDataDict[Bus].type == '3': continue macID = words[1].strip() key = Bus + macID PGen = float(words[2].strip()) genIncr = PGen / totalGenMW * totalPincr newPGen = (PGen + genIncr) * genDiscount GenMVA = float(words[8].strip()) if newPGen < GenMVA: GenMWDict[key] = newPGen else: GenMWDict[key] = GenMVA # generate the new raw file with open(out_path, 'w') as f: # copy everything before load data for i in range(loadStartIndex): f.write(filelines[i]) f.write('\n') # modify the load data j = 0 for i in range(loadStartIndex, loadEndIndex): words = filelines[i].split(',') # change the constant MVA values words[5] = '%.3f' % newPConList[j] words[6] = '%.3f' % newQConList[j] words[5] = words[5].rjust(10) words[6] = words[6].rjust(10) # change the constant current values words[7] = '%.3f' % newIPList[j] words[8] = '%.3f' % newIQList[j] words[7] = words[7].rjust(10) words[8] = words[8].rjust(10) # change the constant impedance values words[9] = '%.3f' % newZPList[j] words[10] = '%.3f' % newZQList[j] words[9] = words[9].rjust(10) words[10] = words[10].rjust(10) # construct a whole string by inserting commas between the words list filelines[i] = reconstructLine2(words) f.write(filelines[i]) f.write('\n') # increment the load list index j += 1 # copy the shunt data, which is in between the load and gen data for i in range(loadEndIndex, genStartIndex): f.write(filelines[i]) f.write('\n') # update and write the gen data for i in range(genStartIndex, genEndIndex): words = filelines[i].split(',') Bus = words[0].strip() if rawBusDataDict[Bus].type == '3': f.write(filelines[i]) f.write('\n') continue macID = words[1].strip() key = Bus + macID newPGen = GenMWDict[key] words[2] = '%.3f' % newPGen words[2] = words[2].rjust(10) # construct a whole string by inserting commas between the words list filelines[i] = reconstructLine2(words) f.write(filelines[i]) f.write('\n') # copy the rest of the raw data for i in range(genEndIndex, len(filelines)): f.write(filelines[i]) f.write('\n') # solves each of the newly generated raw files and saves them output_dir = currentdir + '/' + newdir NewRawFiles = os.listdir(output_dir) PathList = [(output_dir + '/' + f) for f in NewRawFiles] redirect.psse2py() psspy.psseinit(buses=80000) _i = psspy.getdefaultint() _f = psspy.getdefaultreal() _s = psspy.getdefaultchar() for i in range(len(PathList)): #Settings. CONFIGURE THIS settings = { # use the same raw data in PSS/E and TS3ph ##################################### 'filename': PathList[i], #use the same raw data in PSS/E and TS3ph ################################################################################ 'dyr_file': '', 'out_file': 'output2.out', 'pf_options': [ 0, #disable taps 0, #disable area exchange 0, #disable phase-shift 0, #disable dc-tap 0, #disable switched shunts 0, #do not flat start 0, #apply var limits immediately 0, #disable non-div solution ] } psse_log = output_dir + '/' + 'log' + NewRawFiles[i].replace( '.raw', '.txt') psspy.report_output(2, psse_log, [0, 0]) psspy.progress_output(2, psse_log, [0, 0]) psspy.alert_output(2, psse_log, [0, 0]) psspy.prompt_output(2, psse_log, [0, 0]) print "\n Reading raw file:", settings['filename'] ierr = psspy.read(0, settings['filename']) ierr = psspy.fnsl(settings['pf_options']) converge = psspy.solved() if converge == 0: ierr = psspy.rawd_2(0, 1, [1, 1, 1, 0, 0, 0, 0], 0, PathList[i]) else: # file does not converge, remove raw file, keep log file os.remove(PathList[i]) """
def main(): # set output path outpath = r"""SpeOut\\""" # SPE reduction SPE_list = r"""SPE_list.xlsx""" rootbus_list, redbus_list, d1bus_list, N_spe = read_bus(SPE_list) for instance_i in range(N_spe): bus_root = rootbus_list[instance_i] bus_red = redbus_list[instance_i] bus_d1 = d1bus_list[instance_i] # read power flow model before reduction step i psspy.psseinit(50000) if instance_i == 0: # psspy.readrawversion(0, r"""30""", r"""FullModel\wecc179.raw""") # reading .raw file # psspy.case(r"""FullModel\Maui2022dm_v4_wHydro_step0""") # reading .sav file psspy.read(0, r"""FullModel\wecc179_v33.raw""") else: pass psspy.fnsl([1, 0, 0, 1, 1, 0, 0, 0]) # get power flow data pfd = PFData() pfd.getdata(psspy) # count elements in full model if instance_i == 0: n_gen_bf, n_load_bf, n_bus_bf, n_line_bf, n_xfmr_bf, n_shunt_bf = CountEle(pfd) # prepare data for single-port equivalent Pin, Qin, PL, QL, PG, QG, PS, QS, Vm, Va, Ve, PrateA, PrateB, MW_ll, MW_ul, Mvar_ll, Mvar_ul, MVA_base, \ red_load_bus, red_gen_bus, red_shunt_bus = read_subsys(pfd, bus_root, bus_red, bus_d1) # calculate SPE equivalent k, Vae, r, x = CalcSinglePortEqui(pfd, Pin, Qin, PL, QL, PG, QG, PS, QS, Vm, Va, Ve) # Implement single-port equivalent in PSSE DoSpeInPsse(psspy, bus_root, bus_red, bus_d1, pfd, PL, QL, PG, QG, PS, QS, Ve, PrateA, PrateB, MW_ll, MW_ul, Mvar_ll, Mvar_ul, MVA_base, k, r, x) # save new power flow data psspy.rawd_2(0, 1, [0, 0, 1, 0, 0, 0, 0], 0, outpath + "spe_step_" + str(instance_i + 1)) # calc a summary for SPE reduction pfd.getdata(psspy) n_gen_af, n_load_af, n_bus_af, n_line_af, n_xfmr_af, n_shunt_af = CountEle(pfd) # print("\nSPE reduction summary:") print("(# of elements, Before, After, Reduction %)") print("-----------------------------------------------") print(" Buses: ", n_bus_bf, n_bus_af, str(float((n_bus_bf - n_bus_af))/n_bus_bf*100)[0:5] + "%") print(" Generations: ", n_gen_bf, n_gen_af, str(float((n_gen_bf - n_gen_af))/n_gen_bf*100)[0:5] + "%") print(" Loads: ", n_load_bf, n_load_af, str(float((n_load_bf - n_load_af))/n_load_bf*100)[0:5] + "%") print(" Lines: ", n_line_bf, n_line_af, str(float((n_line_bf - n_line_af))/n_line_bf*100)[0:5] + "%") print("Transformers: ", n_xfmr_bf + 1, n_xfmr_af + 1, str(float((n_xfmr_bf - n_xfmr_af))/(n_xfmr_bf+1)*100)[0:5] + "%") print(" Shunts: ", n_shunt_bf, n_shunt_af, str(float((n_shunt_bf - n_shunt_af)) / (n_shunt_bf + 1) * 100)[0:5] + "%")
def runSimulation(self): """Runs the simulation by crating an instance of psspy, loading the raw and dyr data, applying the disturbance and controling PEV output power. Finally plots in native PSS/E or export to matlab.""" sufix = str(self._disturbance)+"_"+str(self._control) conec_file = trash_dir+"\\CC1_"+sufix+".out" conet_file = trash_dir+"\\CT1_"+sufix+".out" compile_file = trash_dir+"\\compile_"+sufix+".out" psspy.psseinit(49) #suppress output if required, else redirect it to python if self._suppress_output: psspy.report_output(6,"",[0,0]) psspy.progress_output(6,"",[0,0]) #psspy.progress_output(2,r"""pot.txt""",[0,0]) else: #redirect psse output to python import redirect redirect.psse2py() #---------------------- #read in case data psspy.read(0,self._power_system_object._raw_filename) #solve the power flow psspy.fdns([0,0,0,1,1,1,99,0]) #---------------------- #convert all generators psspy.cong(0) #---------------------- #conv_standard_loads #change the vector of numbers to get constant current, admittance or power conversion utils.convertLoads([0.0,100.0,0.0,100.0]) #convert the PEVs to constant power loads utils.convertPEVs() #---------------------------------------- #read in dynamics data psspy.dyre_new([1,1,1,1],self._power_system_object._dyr_filename,"","","") #solve power flow with dynamics tysl - and fact devices (was in tutorial) - not sure if we need it though psspy.fact() psspy.tysl(1) #set up pre designated channels self._channels.setUpChannels() #designate channel output_file psspy.strt(0,self._channels._channel_file) self._performDynamicSimulation() if self._plot: self._channels.plot(self._channels._channels_to_include) if self._export_to_matlab: description = sufix.replace(" ","_").replace(".","_").replace("=","__") self._channels.exportToMatlab(matlab_dir+"\\"+description+".m",description,True,True,self._export_figures) if self._export_figures: import win32com.client h = win32com.client.Dispatch('matlab.application') h.Execute ("cd('"+os.getcwd()+"\\"+matlab_dir+"');") h.Execute (description) #clean up try: os.remove(conec_file) except: pass try: os.remove(conet_file) except: pass try: os.remove(compile_file) except: pass return self._channels
##### Get everything set up on the PSSE side redirect.psse2py() psspy.psseinit(buses=80000) _i = psspy.getdefaultint() _f = psspy.getdefaultreal() _s = psspy.getdefaultchar() psse_log = 'log.log' # Redirect any psse outputs to psse_log psspy.report_output(2, psse_log, [0, 0]) psspy.progress_output(2, psse_log, [0, 0]) #ignored psspy.alert_output(2, psse_log, [0, 0]) #ignored psspy.prompt_output(2, psse_log, [0, 0]) #ignored for currentRawFile in RawFileList: ierr = psspy.read(0, currentRawFile) rawFileName = currentRawFile.replace('.raw', '') if rawFileName == 'savnw_conp': PL = '' else: PL = rawFileName[ -3:] # last 3 character contain the percentage loading # Load conversion (multiple-step) # all constant power load converted to constant admittance load psspy.conl(0, 1, 1, [0, 0], [0.0, 100.0, 0.0, 100.0]) psspy.conl(0, 1, 2, [0, 0], [0.0, 100.0, 0.0, 100.0]) psspy.conl(0, 1, 3, [0, 0], [0.0, 100.0, 0.0, 100.0]) newRawFileName = 'conZRaw/savnw_conz{}.raw'.format(PL) ierr = psspy.rawd_2(0, 1, [1, 1, 1, 0, 0, 0, 0], 0, newRawFileName)
P_Flow_Record = [[] for i in range(len(Power_Flow_Monitor_Start))] S_Flow_Record = [[] for i in range(len(Power_Flow_Monitor_Start))] Event_Name = [] P_setpoint = [ 0, 100, 50, 0 ] # CHANG: change this value according to your suggestion from 5.2.5.1 Reactive Power Capability Q_max_setpoint = [0, 40, 40, 40] # CHANG: sample : change this value according to your suggestion from 5.2.5.1 Reactive Power Capability Q_min_setpoint = [0, -40, -40, -40] # CHANG: sample :change this value according to your suggestion from 5.2.5.1 Reactive Power Capability InverterCapacity = 120 # CHANG: sample :change this value according to your suggestion from 5.2.5.1 Reactive Power Capability ###### standard power variation for i in range(0, len(P_setpoint)): psspy.read(0, GridInfoPath + FileName) ## psspy.dscn(20022) # eliminate negative power output by slack bus, does not need to consider outside NSW. psspy.machine_data_2(101, r"""1""", [_i, _i, _i, _i, _i, _i], [ P_setpoint[i], 0, Q_max_setpoint[i], Q_min_setpoint[i], InverterCapacity, 0, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f ]) psspy.machine_data_2(102, r"""1""", [_i, _i, _i, _i, _i, _i], [ P_setpoint[i], 0, Q_max_setpoint[i], Q_min_setpoint[i], InverterCapacity, 0, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f ]) psspy.machine_data_2(103, r"""1""", [_i, _i, _i, _i, _i, _i], [ P_setpoint[i], 0, Q_max_setpoint[i], Q_min_setpoint[i], InverterCapacity, 0, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f, _f ]) psspy.machine_data_2(104, r"""1""", [_i, _i, _i, _i, _i, _i], [
import redirect import psspy import dyntools import csv planningRaw = 'hls18v1dyn_1219.raw' psse_log = 'log_planning_multTFLoad.txt' redirect.psse2py() psspy.psseinit(buses=80000) # Silence all psse outputs psspy.report_output(2, psse_log, [0, 0]) psspy.progress_output(6, psse_log, [0, 0]) #ignored psspy.alert_output(6, psse_log, [0, 0]) #ignored psspy.prompt_output(6, psse_log, [0, 0]) #ignored ############################## ierr = psspy.read(0, planningRaw) # File:"C:\Users\bikiran_remote\Desktop\report_bus_data.py", generated on MON, MAR 05 2018 19:33, release 33.03.00 for bus in LoadSet: ierr = psspy.bsys(1, 0, [0.0, 0.0], 0, [], 1, [int(bus)], 0, [], 0, []) # PAGE 1373 of API book ierr = psspy.lamp(1, 0) # page 258 of API book """ with open(psse_log,'r') as f: filecontent = f.read() fileLines = filecontent.split('\n') print fileLines[-1] """
def runPSSESimBatches(simList, dyrFile, objName): import sys, os # add psspy to the system path sys.path.append(r"C:\Program Files (x86)\PTI\PSSE33\PSSBIN") os.environ['PATH'] = (r"C:\Program Files (x86)\PTI\PSSE33\PSSBIN;" + os.environ['PATH']) from contextlib import contextmanager import StringIO from getBusDataFn import getBusData @contextmanager def silence(file_object=None): #Discard stdout (i.e. write to null device) or #optionally write to given file-like object. if file_object is None: file_object = open(os.devnull, 'w') old_stdout = sys.stdout try: sys.stdout = file_object yield finally: sys.stdout = old_stdout if file_object is None: file_object.close() # Local imports import redirect import psspy import dyntools # getting the raw file ##### Get everything set up on the PSSE side redirect.psse2py() #output = StringIO.StringIO() with silence(): psspy.psseinit(buses=80000) _i = psspy.getdefaultint() _f = psspy.getdefaultreal() _s = psspy.getdefaultchar() # some important parameters FaultRpu = 1e-06 Sbase = 100.0 EventsDict = {} for event in simList: eventWords = event.split('/') RawFileIndicator = eventWords[0].strip() linesOutage = eventWords[1].strip() FaultBus = eventWords[2].strip()[ 1:] # exclude the 'F' at the beginning # get the raw file if RawFileIndicator == '100': rawFile = 'savnw_conp.raw' else: rawFile = 'savnw_conp{}.raw'.format(RawFileIndicator) #Parameters. CONFIGURE THIS settings = { # use the same raw data in PSS/E and TS3ph ##################################### 'filename': rawFile, #use the same raw data in PSS/E and TS3ph ################################################################################ 'dyr_file': dyrFile, 'out_file': 'output2.out', 'pf_options': [ 0, #disable taps 0, #disable area exchange 0, #disable phase-shift 0, #disable dc-tap 0, #disable switched shunts 0, #do not flat start 0, #apply var limits immediately 0, #disable non-div solution ] } output = StringIO.StringIO() with silence(output): ierr = psspy.read(0, settings['filename']) #This is for the power flow. I'll use the solved case instead ierr = psspy.fnsl(settings['pf_options']) ##### Prepare case for dynamic simulation # Load conversion (multiple-step) psspy.conl(_i, _i, 1, [0, _i], [_f, _f, _f, _f]) # all constant power load to constant current, constant reactive power load to constant admittance # standard practice for dynamic simulations, constant MVA load is not acceptable psspy.conl(1, 1, 2, [_i, _i], [100.0, 0.0, 0.0, 100.0]) psspy.conl(_i, _i, 3, [_i, _i], [_f, _f, _f, _f]) ierr = psspy.cong(0) #converting generators ierr = psspy.ordr(0) #order the network nodes to maintain sparsity ierr = psspy.fact() #factorise the network admittance matrix ierr = psspy.tysl(0) #solving the converted case ierr = psspy.dynamicsmode(0) #enter dynamics mode print "\n Reading dyr file:", settings['dyr_file'] ierr = psspy.dyre_new([1, 1, 1, 1], settings['dyr_file']) ierr = psspy.docu( 0, 1, [0, 3, 1]) #print the starting point of state variables # select time step ############################################################## ierr = psspy.dynamics_solution_params( [_i, _i, _i, _i, _i, _i, _i, _i], [_f, _f, 0.00833333333333333, _f, _f, _f, _f, _f], 'out_file') # the number here is the time step ################################################################################ ##### select channels ierr = psspy.delete_all_plot_channels() # clear channels BusDataDict = getBusData(rawFile) # get all the bus voltages, angles and frequencies for bus in BusDataDict: bus = int(bus) ierr = psspy.voltage_and_angle_channel([-1, -1, -1, bus]) ierr = psspy.bus_frequency_channel([-1, bus]) print 'Event: {}'.format(event) # get the nominal voltages as well as the fault impedance in ohms FaultBusNomVolt = float(BusDataDict[str(FaultBus)].NominalVolt) Zbase = FaultBusNomVolt**2 / Sbase # float since Sbase is a float Rohm = FaultRpu * Zbase # fault impedance in ohms # run simulation till just before the fault ResultsDict = {} # get the line params line1Elements = linesOutage.split(';')[0].strip() line2Elements = linesOutage.split(';')[1].strip() # Line 1 params line1 = line1Elements.split(',') L1Bus1 = int(line1[0].strip()) L1Bus2 = int(line1[1].strip()) L1cktID = line1[2].strip("'").strip() #print L1Bus1 #print L1Bus2 #print L1cktID # Line 2 params line2 = line2Elements.split(',') L2Bus1 = int(line2[0].strip()) L2Bus2 = int(line2[1].strip()) L2cktID = line2[2].strip("'").strip() #print L2Bus1 #print L2Bus2 #print L2cktID #output = StringIO.StringIO() with silence(output): ierr = psspy.strt(0, settings['out_file']) ierr = psspy.run(0, 0.1, 1, 1, 1) ierr = psspy.dist_branch_trip(L1Bus1, L1Bus2, L1cktID) #output = StringIO.StringIO() with silence(output): ierr = psspy.run(0, 0.2, 1, 1, 1) #fault on time outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + event + ':' print 'Network did not converge between branch 1 trip and fault application, skipping...' continue ####### # check for convergence during fault #output = StringIO.StringIO() with silence(output): ierr = psspy.dist_bus_fault(int(FaultBus), 3, 0.0, [Rohm, 0.0]) ierr = psspy.run(0, 0.3, 1, 1, 1) #fault off time ierr = psspy.dist_clear_fault(1) outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + event + ':' print 'Network did not converge during fault, skipping...' continue # check for convergence between fault clearance and second branch trip #output = StringIO.StringIO() with silence(output): ierr = psspy.run(0, 0.31, 1, 1, 1) #fault off time ierr = psspy.dist_branch_trip(L2Bus1, L2Bus2, L2cktID) ierr = psspy.run(0, 0.35, 1, 1, 1) #fault off time # check for non-convergence #output = StringIO.StringIO() outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + event + ':' print 'Network did not converge between fault clearance and branch 2 trip, skipping...' continue # select run time ############################################################## #output = StringIO.StringIO() with silence(output): ierr = psspy.run(0, 10.0, 1, 1, 1) #exit time (second argument is the end time) ################################################################################ # check for non-convergence outputStr = output.getvalue() if "Network not converged" in outputStr: print 'For ' + event + ':' print 'Network did not converge sometime after 2nd branch trip, skipping...' continue # write to output file #with open('outputTmp.txt','w') as f: # f.write(outputStr) outputData = dyntools.CHNF(settings['out_file']) data = outputData.get_data() channelDict = data[ 1] # dictionary where the value is the channel description valueDict = data[ 2] # dictionary where the values are the signal values, keys match that of channelDict tme = valueDict['time'] # get time ResultsDict['time'] = tme for key in channelDict: if key == 'time': continue signalDescr = channelDict[key] words = signalDescr.split() signalType = words[0].strip() bus = words[1].strip() #print Bus + ' ' + signalType if bus not in ResultsDict: ResultsDict[bus] = Results() if signalType == 'VOLT': ResultsDict[bus].volt = valueDict[key] elif signalType == 'ANGL': ResultsDict[bus].angle = valueDict[key] elif signalType == 'FREQ': ResultsDict[bus].freq = valueDict[key] EventsDict[event] = ResultsDict return EventsDict
ierr = psspy.prompt_output(6, ' ', [0, 0]) # disable output ierr = psspy.report_output(6, ' ', [0, 0]) # disable output # Set Simulation Path. LoadScenario = "SimplifiedSystem" ClauseName = "5.2.5.1 Reactive Power Capability" ProgramPath = "F:/PosDoc Projects/11_Industrial Projects/NEOEN_HW/P_SimulationProgram/" GridInfoPath = "F:/PosDoc Projects/11_Industrial Projects/NEOEN_HW/NEM_files/" + LoadScenario + "/" HuaweiModelPath = "F:/PosDoc Projects/11_Industrial Projects/NEOEN_HW/D_HuaweiModels/34" OutputFilePath = ProgramPath + "SimulationOutput.out" FigurePath = "F:/PosDoc Projects/11_Industrial Projects/NEOEN_HW/R_Results/" PowerFlowFileName = 'NEOEN Western Downs Solar Farm_C3WV_3.raw' # Initialize psspy.read(0, GridInfoPath + PowerFlowFileName) P_Record = [] Q_Record = [] T_Record = [] V_Record = [] S_Record = [] overloop = 0 S = 120 # chang: this is wrong, each cluster has only ~120MVA capacity. I guess the power flow does not converge. overloop = 0 # add this line.
import psspy import dyntools import csv filename = 'NewCAPERawClean_alt0305.raw' psse_log = 'psse_log.txt' redirect.psse2py() psspy.psseinit(buses=80000) # Silence all psse outputs psspy.report_output(2, psse_log, [0, 0]) psspy.progress_output(6, psse_log, [0, 0]) #ignored psspy.alert_output(6, psse_log, [0, 0]) #ignored psspy.prompt_output(6, psse_log, [0, 0]) #ignored ############################## ierr = psspy.read(0, filename) # File:"C:\Users\bikiran_remote\Desktop\report_bus_data.py", generated on MON, MAR 05 2018 19:33, release 33.03.00 ierr = psspy.bsys(1, 0, [0.0, 0.0], 0, [], 1, [750333], 0, [], 0, []) # PAGE 1373 of API book ierr = psspy.lamp(1, 0) # page 258 of API book ierr = psspy.bsys(1, 0, [0.0, 0.0], 0, [], 1, [3148], 0, [], 0, []) # PAGE 1373 of API book ierr = psspy.lamp(1, 0) # page 258 of API book with open(psse_log, 'r') as f: filecontent = f.read() fileLines = filecontent.split('\n') print fileLines[-1]