def readMachinePowers(self): ''' Reads and stores active and reactive powers of each generator ''' ierr1, [self.machinePowerP] = psspy.amachreal(-1, 4, 'PGEN') ierr2, [self.machinePowerQ] = psspy.amachreal(-1, 4, 'QGEN') assert (ierr1 == 0) and (ierr2 == 0), 'Error with reading active and reactive powers' return self.machinePowerP, self.machinePowerQ
def amachreal(sid,flag,string): ierr, iarray = psspy.amachreal(sid,flag,string) if ierr: print("-------------------------------------------------------------") print("Cannot get machine real values") print("Function: amachreal") print("Error Code: " + str(ierr)) print("-------------------------------------------------------------") pdb.set_trace() return iarray
def amachreal(sid, flag, string): ierr, iarray = psspy.amachreal(sid, flag, string) if ierr: print("-------------------------------------------------------------") print("Cannot get machine real values") print("Function: amachreal") print("Error Code: " + str(ierr)) print("-------------------------------------------------------------") pdb.set_trace() return iarray
def read_raw(self): ''' Read the raw file.''' # Read bus numbers ierr, bus_numbers = psspy.abusint(-1, 2, 'NUMBER') assert ierr == 0, 'Error with reading bus numbers' # Reads voltage levels at buses stored in self.busNumbers ierr, voltage_levels = psspy.abusreal(-1, 2, 'PU') assert ierr == 0, 'Error reading voltage levels' # Reads voltage levels at buses stored in self.busNumbers ierr, voltage_angles = psspy.abusreal(-1, 2, 'ANGLED') assert ierr == 0, 'Error reading voltage angles' # Creates a Python dictionary containing bus numbers as keys and associates # a dictionary with voltage and angle to each of the keys for bus, voltage, angle in zip(bus_numbers[0], voltage_levels[0], voltage_angles[0]): self.buses[bus] = {'voltage': voltage, 'angle': angle} # Reads and stores bus numbers where generators are connected ierr, [machine_bus_numbers] = psspy.amachint(-1, 4, 'NUMBER') ierr, [machine_ids] = psspy.amachchar(-1, 4, 'ID') assert ierr == 0, 'Error reading generator bus numbers' # Reads and stores active and reactive powers of each generator ierr1, [machine_power_p] = psspy.amachreal(-1, 4, 'PGEN') ierr2, [machine_power_q] = psspy.amachreal(-1, 4, 'QGEN') assert ierr1 == 0 and ierr2 == 0, 'Error with reading active and reactive powers' # Creates a Python dictionary containing keys in form of # "BUSNUMBER_MACHINEID" and associates a dictionary with active and # reactive powers to each of the keys for k in range(0, len(machine_ids)): self.machines[(str(machine_bus_numbers[k]) + '_' + machine_ids[k][:-1])] = { 'bus': machine_bus_numbers[k], 'P': machine_power_p[k], 'Q': machine_power_q[k] } # Reads and stores bus numbers where loads are connected ierr, [load_bus_numbers] = psspy.aloadint(-1, 4, 'NUMBER') ierr, [load_ids] = psspy.aloadchar(-1, 4, 'ID') assert ierr == 0, 'Error reading load bus numbers' # Reads and stores active and reactive powers of each load ierr1, [load] = psspy.aloadcplx(-1, 4, 'TOTALACT') load_power_p = [] load_power_q = [] for cplxload in load: load_power_p.append(cplxload.real) load_power_q.append(cplxload.imag) assert ierr1 == 0, 'Error with reading active and reactive powers' # Creates a Python dictionary containing keys in form of # "BUSNUMBER_LOADID" and associates a dictionary with active and # reactive powers to each of the keys for load, bus, active, reactive in zip(load_ids, load_bus_numbers, load_power_p, load_power_q): self.loads[(str(bus) + '_' + load[:-1])] = { 'bus': bus, 'P': active, 'Q': reactive } # Reads and stores bus numbers where 2WindingTrafos are connected ierr1, [two_w_trafo_from] = psspy.atrnint(-1, 1, 1, 2, 1, 'FROMNUMBER') ierr2, [two_w_trafo_to] = psspy.atrnint(-1, 1, 1, 2, 1, 'TONUMBER') assert ierr1 == 0 and ierr2 == 0, 'Error reading trafo bus numbers' # Reads and stores 2WindingTrafo ratios taking into account the primary side ierr1, [two_w_trafo_ratio1] = psspy.atrnreal(-1, 1, 1, 2, 1, 'RATIO') ierr2, [two_w_trafo_ratio2] = psspy.atrnreal(-1, 1, 1, 2, 1, 'RATIO2') assert ierr1 == 0 and ierr2 == 0, 'Error reading trafo bus numbers' # Creates a Python dictionary containing keys in form of # "BUSNUMBER_LOADID" and associates a dictionary with active and # reactive powers to each of the keys for f_bus, to_bus, ratio1, ratio2 in zip(two_w_trafo_from, two_w_trafo_to, two_w_trafo_ratio1, two_w_trafo_ratio2): self.trafos[(str(f_bus) + '_' + str(to_bus))] = { 'fromBus': f_bus, 'toBus': to_bus, 't1': ratio1, 't2': ratio2 }
if partxt[5] in swingbus_str: swingbusincont = True fcon.close() print('-------swingbus_str: ') print(swingbus_str) print('------swingbusincont: ') print(swingbusincont) # check if swing bus in contingency: if swingbusincont: #sort in-service generators ierr, iarray = psspy.amachint(-1, 1, 'NUMBER') vtmpgenbusno = iarray[0] ierr, rarray = psspy.amachreal(-1, 1, 'PGEN') vtmpgenpgen = rarray[0] gen_tmp_info = zip(vtmpgenbusno, vtmpgenpgen) gen_tmp_sorted = sorted(gen_tmp_info, key=lambda item: item[1], reverse=True) newswingbus = -1 for igen in range(0, len(gen_tmp_sorted)): if str(gen_tmp_sorted[igen][0]) not in cont_genbus_array: newswingbus = gen_tmp_sorted[igen][0] break if newswingbus != -1: print('!!!!!!!!!!!--------new swing bus find, is bus: ' + str(newswingbus) + ' ----------------!!!!!')
def update_raw_files(self, to_excel=True, out_dir=None): """Function for updating the psse case file. Args: to_excel(default=True): If a summary should be written to excel out_dir: The directory where the results are stored """ if not out_dir: out_dir = os.getcwd() redirect.psse2py() psspy.throwPsseExceptions = True nbuses = 50000 # max no of buses ierr = psspy.psseinit(nbuses) psspy.case(self.basecase) if to_excel: self.create_excel_sheet() self.to_excel = True else: self.sheet = None for i, col in zip(range(0, 24), range(2, 2 + 24 * 3, 3)): # Represent HVDC links as load and some other exchanges as well print('Changing additional loads...') row = 15 for load in self.ex_as_load: self.load_change(load, i, to_excel, row, col) row = row + 1 print('Changing interarea exchanges...') row = 3 for area, info in self.area_info.items(): country = area[0:2] # Changing interarea exchanges exchange = self.calculate_exchange(info, area, i) self.area_data(info.number, info.bus, exchange, area, row, col + 2) # Changing areas production and consumption self.change_prod_con(info.number, self.data[country]["PS"][area][i], self.data[country]["FB"][area][i], info.pf, tol=4, row=row, column=col) row = row + 1 print('Changes completed...') # Save the raw file to convert to CIM psspy.rawd_2(0, 1, [0, 0, 1, 0, 0, 0, 0], 0, "Snap_before_PF.raw") b = os.path.join(out_dir, 'h' + str( (col - 1) / 3) + '_before_PF.raw') os.rename("Snap_before_PF.raw", b) # Solve the power flow psspy.fnsl([1, 2, 0, 0, 1, 0, 0, 0]) ival = psspy.solved() # flag to check power flow convergence if ival == 0: print('Convergence') if self.to_excel: self.sheet.cell(row=42, column=col).value = 'Convergence' temp_fname = os.path.join(out_dir, "temp.sav") print(temp_fname) psspy.save(temp_fname) # save temporarily the solved case psspy.case(temp_fname) # set the saved case as current case # save the raw file to convert to CIM raw_fname = os.path.join(out_dir, "Snap_after_PF.raw") psspy.rawd_2(0, 1, [0, 0, 1, 0, 0, 0, 0], 0, raw_fname) b = os.path.join(out_dir, 'h' + str(i) + '_after_PF.raw') os.rename(raw_fname, b) if self.to_excel: # Merge cells self.sheet.merge_cells(start_row=1, start_column=col, end_row=1, end_column=col + 2) self.sheet.cell( row=2, column=col).alignment = (Alignment(wrapText=True)) self.sheet.cell(row=2, column=col + 1).alignment = (Alignment(wrapText=True)) self.sheet.cell(row=2, column=col + 2).alignment = (Alignment(wrapText=True)) self.sheet.cell( row=14, column=col).alignment = (Alignment(wrapText=True)) self.sheet.cell(row=14, column=col + 1).alignment = (Alignment(wrapText=True)) self.sheet.cell( row=30, column=col).alignment = (Alignment(wrapText=True)) self.sheet.cell(row=30, column=col + 1).alignment = (Alignment(wrapText=True)) # Headers for data from nordpool self.sheet.cell(row=1, column=col).value = ('hour ' + str(i)) self.sheet.cell( row=2, column=col).value = ('Scheduled\nProduction\n[MWh]') self.sheet.cell( row=2, column=col + 1).value = ('Scheduled\nConsumption\n[MWh]') self.sheet.cell(row=2, column=col + 2).value = ('Scheduled\nExchange\n[MWh]') # Headers for exchanges represented as loads self.sheet.cell(row=14, column=col).value = ('Active Power\n[MW]') self.sheet.cell(row=14, column=col + 1).value = ('Reactive Power\n[MW]') # Headers for results after PSS/E self.sheet.cell( row=30, column=col).value = ('PSSE\nProduction\n[MWh]') self.sheet.cell(row=30, column=col + 1).value = ('PSSE\nConsumption\n[MWh]') self.sheet.cell(row=30, column=col + 2).value = ('PSSE\nExchange\n[MWh]') row = 31 for _, info in self.area_info.items(): # to get the area production complex power ierr = psspy.ardat(info.number, 'GEN') self.sheet.cell(row=row, column=col).value = (round( ierr[1].real, 0)) # to get the area consumption complex power ierr = psspy.ardat(info.number, 'LOAD') self.sheet.cell(row=row, column=col + 1).value = (round( ierr[1].real, 0)) row += 1 # to get the value of the areas active power interchange ierr, intch = psspy.aareareal(-1, 1, 'PINT') for r in range(0, len(intch[0])): self.sheet.cell(row=31 + r, column=col + 2).value = round( intch[0][r].real, 0) # limits check ierr, busvoltages = psspy.abusreal(sid=-1, string="PU") if any(x < 0.95 or x > 1.05 for x in busvoltages[0]): self.sheet.cell( row=43, column=col).value = ('Bus voltage problem') ierr, machPGen = psspy.amachreal(sid=-1, string="PGEN") ierr, machPMax = psspy.amachreal(sid=-1, string="PMAX") ierr, machPMin = psspy.amachreal(sid=-1, string="PMIN") ierr, machQGen = psspy.amachreal(sid=-1, string="QGEN") ierr, machQMax = psspy.amachreal(sid=-1, string="QMAX") ierr, machQMin = psspy.amachreal(sid=-1, string="QMIN") ierr, machS = psspy.amachreal(sid=-1, string="MVA") ierr, machMbase = psspy.amachreal(sid=-1, string="MBASE") for l in range(0, len(machPGen[0])): if (machPGen[0][l] <= machPMin[0][l] or machPGen[0][l] >= machPMax[0][l]): self.sheet.cell(row=45, column=col).value = ( 'Generator active power output problem') for m in range(0, len(machQGen[0])): if (machQGen[0][m] <= machQMin[0][m] or machQGen[0][m] >= machQMax[0][m]): self.sheet.cell(row=46, column=col).value = ( 'Generator reactive power output problem') break for n in range(0, len(machS[0])): if machS[0][n] >= machMbase[0][n]: self.sheet.cell(row=47, column=col).value = ( 'Generator overloading problem') break ierr, brflowA = psspy.aflowreal(sid=-1, string="PCTCORPRATEA") if any(x >= 100 for x in brflowA[0]): self.sheet.cell(row=48, column=col).value = ( 'Branch overloading problem (Rate A)') ierr, brflowB = psspy.aflowreal(sid=-1, string="PCTCORPRATEB") if any(x >= 100 for x in brflowB[0]): self.sheet.cell(row=48, column=col).value = ( 'Branch overloading problem (Rate B)') ierr, brflowC = psspy.aflowreal(sid=-1, string="PCTCORPRATEC") if any(x >= 100 for x in brflowC[0]): self.sheet.cell(row=48, column=col).value = ( 'Branch overloading problem (Rate C)') else: print('No convergence') self.sheet.cell(row=43, column=col).value = 'No convergence' psspy.close_powerflow() # save the Excel file with all data self.wb.save(os.path.join(out_dir, 'PSSE_in_out.xlsx')) os.remove(temp_fname)
def get_gen_reactive_power(gen_bus): psspy.bsys(sid=2, numbus=len(gen_bus), buses=gen_bus) ierr, Qgen = psspy.amachreal(sid=2, flag=1, string='O_QGEN') Qgen = Qgen[0] return Qgen
def get_gen_active_power(gen_bus): psspy.bsys(sid=2, numbus=len(gen_bus), buses=gen_bus) ierr, Pgen = psspy.amachreal(sid=2, flag=1, string='O_PGEN') Pgen = Pgen[0] return Pgen