def OPFAC(ppc, Pload, Qload, u, weight): baseMVA, bus, gen, branch = ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc[ "branch"] nbus = ppc['bus'].shape[0] ngen = ppc['gen'].shape[0] ngenInfo = ppc['gen'].shape[1] ppc["bus"][:, 2] = Pload ppc["bus"][:, 3] = Qload for i in range(ngen): ppc["gen"][i, 3] = u[i] * ppc["gen"][i, 3] ppc["gen"][i, 4] = u[i] * ppc["gen"][i, 4] ppc["gen"][i, 8] = u[i] * ppc["gen"][i, 8] ppc["gen"][i, 9] = u[i] * ppc["gen"][i, 9] DeltaPMatrix = np.zeros((nbus, ngenInfo)) for i in range(nbus): DeltaPMatrix[i, :] = [ i + 1, 0., 0., 0., 0, 1., 100., 1., 1000, -1000., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. ] genNew = np.append(gen, DeltaPMatrix, axis=0) ppc["gen"] = genNew DeltaPCost = np.zeros((nbus, ppc["gencost"].shape[1])) DeltaPCost[:, -3] = weight DeltaPCost[:, -4] = 3 DeltaPCost[:, 0] = 2 newGenCost = np.append(ppc["gencost"], DeltaPCost, axis=0) ppc["gencost"] = newGenCost ppc["bus"][:, 1] = 2 ppc["bus"][0, 1] = 3 runopf(ppc) # ppc = loadcase(case()) #Load test system # baseMVA=ppc['baseMVA'] # Pload=ppc['bus'][:,2] # Qload=ppc['bus'][:,3] # nbus=ppc['bus'].shape[0] #number of buses # ngen=ppc['gen'].shape[0] # ngenInfo=ppc['gen'].shape[1] # # genMatrix=np.zeros((nbus,ngenInfo)) # # for i in range(ngen): # # genMatrix[int(ppc['gen'][i][0])-1,:]=ppc['gen'][i] # # genBusIndex=ppc['gen'][:,0].astype(int)-1 # u=np.zeros(ngen, dtype=int) # for i in range(ngen): # u[i]=1 # weight=10000000 # OPFAC(ppc, Pload, Qload, u, weight)
def case_iteration(): ppc = mycase() ppopt = ppoption(PF_ALG=2) r = runopf(ppc, ppopt) myprintpf(r)
def get_output(self): self.power_factor_correction() #returns the output of the load flow calculation ppc_result = runopf(self.ppc, self.ppopt) #print ppc_result["bus"][node,7] print ppc_result["gen"] print type(ppc_result) return ppc_result
def opf(args=sys.argv[1:]): usage = 'Runs an optimal power flow.' options, casedata, ppopt, fname, solvedcase = \ parse_options(args, usage, True) if options.test: sys.exit(test_opf()) if options.uopf: if options.w_res: stderr.write('uopf and opf_w_res are mutex\n') r = runuopf(casedata, ppopt, fname, solvedcase) elif options.w_res: r = runopf_w_res(casedata, ppopt, fname, solvedcase) else: r = runopf(casedata, ppopt, fname, solvedcase) exit(r['success'])
def mainJAPowerFlow(baseMVAName, busName, genName, branchName, splitCharacter, outputBusName, outputBranchName, outputGenName, optimal, printOutput, areasName, genCostName): #Variables (by for testing) #baseMVAName = "baseMVA.txt" #busName = "bus.txt" #genName = "gen.txt" #branchName = "branch.txt" #splitCharacter = ' ' #outputBusName = "outputBus.txt" #outputBranchName = "outputBranch.txt" #outputBranchName = "outputGen.txt" #optimal = 0 #optimal = 0 or 1, 0 for power flow, 1 for optimal power flow. #printOutput = 0 #printOutput = 0 or 1, 0 for no stdout printed output, 1 if it is wanted. Note that both still output to the text files. #areasName = "areas.txt" #genCostName = "genCost.txt" #Assign ppc ppc = readText(baseMVAName, busName, genName, branchName, splitCharacter, optimal, areasName, genCostName) #ppc = casetest() #Set pf test type #ppopt = ppoption(PF_ALG=1) #Includes printing output (of standard pf) #ppopt = ppoption(OUT_ALL=0, VERBOSE=0) #These options prevent printing output #ppopt = ppoption(PF_ALG=1, OUT_ALL=0, VERBOSE=0) if (printOutput == 1): ppopt = ppoption(OUT_ALL=1, VERBOSE=1) elif (printOutput == 0): ppopt = ppoption(OUT_ALL=0, VERBOSE=0) else: print( "printOutput must be 0 or 1, 0 for no stdout printed output, and 1 if that is desired. Both still output to text files." ) #Run pf or opf test if (optimal == 0): r = runpf(ppc, ppopt) elif (optimal == 1): r = runopf(ppc, ppopt) else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.") #Now clear the output files (method of writing to them might be altered, so doing this is to be sure open(outputBusName, 'w').close() open(outputBranchName, 'w').close() open(outputGenName, 'w').close() #For Optimal Power Flow if (optimal == 1): #Establish lengths busCount = len(r['bus']) branchCount = len(r['branch']) genCount = len(r['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r['gen'][i][1]) + splitCharacter + str(r['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r['gen'][i][0])] += r['gen'][i][1] busGenQ[int(r['gen'][i][0])] += r['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r['bus'][i][7]) + splitCharacter + str(r['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r['bus'][i][2]) + splitCharacter + str(r['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): f.write( str(i + 1) + splitCharacter + str(absDiff(r['branch'][i][15], r['branch'][i][13])) + splitCharacter + str(absDiff(r['branch'][i][16], r['branch'][i][14])) + '\n') i += 1 f.close() #For Standard Power Flow elif (optimal == 0): #Establish lengths busCount = len(r[0]['bus']) branchCount = len(r[0]['branch']) #print(branchCount) genCount = len(r[0]['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r[0]['gen'][i][1]) + splitCharacter + str(r[0]['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r[0]['gen'][i][0])] += r[0]['gen'][i][1] busGenQ[int(r[0]['gen'][i][0])] += r[0]['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r[0]['bus'][i][7]) + splitCharacter + str(r[0]['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r[0]['bus'][i][2]) + splitCharacter + str(r[0]['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): f.write( str(i + 1) + splitCharacter + str(absDiff(r[0]['branch'][i][15], r[0]['branch'][i][13])) + splitCharacter + str(absDiff(r[0]['branch'][i][16], r[0]['branch'][i][14])) + '\n') i += 1 f.close() else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.")
def runopf_case(self): self.results = runopf(self.ppc, self.ppopt)
ppc['gencost'][genidx, 3] = 3 ppc['gencost'][genidx, 4] = -c2 ppc['gencost'][genidx, 5] = c1 elif deg == 1: ppc['gencost'][genidx, 3] = 2 ppc['gencost'][genidx, 4] = c1 ppc['gencost'][genidx, 5] = 0.0 else: ppc['gencost'][genidx, 3] = 1 ppc['gencost'][genidx, 4] = 999.0 ppc['gencost'][genidx, 5] = 0.0 ppc['gencost'][genidx, 6] = 0.0 ppc['bus'][busnum - 1, 2] = gld_load[busnum]['pcrv'] + unresp ppc['bus'][busnum - 1, 3] = gld_load[busnum]['qcrv'] # print_gld_load (ppc, gld_load, 'OPF', ts) ropf = pp.runopf(ppc, ppopt_market) if ropf['success'] == False: conv_accum = False opf_bus = deepcopy(ropf['bus']) opf_gen = deepcopy(ropf['gen']) Pswing = 0 for idx in range(opf_gen.shape[0]): if opf_gen[idx, 0] == swing_bus: Pswing += opf_gen[idx, 1] print(ts, ropf['success'], '{:.2f}'.format(opf_bus[:, 2].sum()), '{:.2f}'.format(opf_gen[:, 1].sum()), '{:.2f}'.format(Pswing), '{:.4f}'.format(opf_bus[0, 13]), '{:.4f}'.format(opf_bus[7, 13]),
def mainJAPowerFlow(baseMVAName, busName, genName, branchName, splitCharacter, outputBusName, outputBranchName, outputGenName, printOutput, optimal, areasName, genCostName): #Variables (by for testing) #baseMVAName = "baseMVA.txt" #busName = "bus.txt" #genName = "gen.txt" #branchName = "branch.txt" #splitCharacter = ' ' #outputBusName = "outputBus.txt" #outputBranchName = "outputBranch.txt" #outputBranchName = "outputGen.txt" #printOutput = 0 #printOutput = 0 or 1, 0 for no stdout printed output, 1 if it is wanted. Note that both still output to the text files. #optimal = 0 #optimal = 0 or 1, 0 for power flow, 1 for optimal power flow. NOTE: All following inputs are only used in optimal power flow, OPF, analysis (optimal = 1), but some values are still required as inputs, even if they are not used in the event of PF (optimal = 0). #areasName = "areas.txt" #genCostName = "genCost.txt" #Assign ppc ppc = readText(baseMVAName, busName, genName, branchName, splitCharacter, optimal, areasName, genCostName) #ppc = casetest() #Set pf test type #ppopt = ppoption(PF_ALG=1) #Includes printing output (of standard pf) #ppopt = ppoption(OUT_ALL=0, VERBOSE=0) #These options prevent printing output #ppopt = ppoption(PF_ALG=1, OUT_ALL=0, VERBOSE=0) if (printOutput == 1): ppopt = ppoption(OUT_ALL=1, VERBOSE=1) elif (printOutput == 0): ppopt = ppoption(OUT_ALL=0, VERBOSE=0) else: print( "printOutput must be 0 or 1, 0 for no stdout printed output, and 1 if that is desired. Both still output to text files." ) #Run pf or opf test if (optimal == 0): r = runpf(ppc, ppopt) elif (optimal == 1): r = runopf(ppc, ppopt) else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.") #Now clear the output files (method of writing to them might be altered, so doing this is to be sure open(outputBusName, 'w').close() open(outputBranchName, 'w').close() open(outputGenName, 'w').close() #For Optimal Power Flow if (optimal == 1): #Establish lengths busCount = len(r['bus']) branchCount = len(r['branch']) genCount = len(r['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r['gen'][i][1]) + splitCharacter + str(r['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r['gen'][i][0])] += r['gen'][i][1] busGenQ[int(r['gen'][i][0])] += r['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r['bus'][i][7]) + splitCharacter + str(r['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r['bus'][i][2]) + splitCharacter + str(r['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 dic = {} while (i < branchCount): f.write( str(i + 1) + splitCharacter + str(absDiff(r['branch'][i][15], r['branch'][i][13])) + splitCharacter + str(absDiff(r['branch'][i][16], r['branch'][i][14])) + '\n') dic[i] = [ str(absDiff(r['branch'][i][15], r['branch'][i][13])), str(absDiff(r['branch'][i][16], r['branch'][i][14])) ] i += 1 f.close() with open( 'C:\\Users\\LONG01\\TOMCAT\\webapps\\ROOT\OntoEN\\outputOPF.json', 'w') as fp: json.dump(dic, fp) #For Standard Power Flow elif (optimal == 0): #Establish lengths busCount = len(r[0]['bus']) branchCount = len(r[0]['branch']) #print(branchCount) genCount = len(r[0]['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r[0]['gen'][i][1]) + splitCharacter + str(r[0]['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r[0]['gen'][i][0])] += r[0]['gen'][i][1] busGenQ[int(r[0]['gen'][i][0])] += r[0]['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r[0]['bus'][i][7]) + splitCharacter + str(r[0]['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r[0]['bus'][i][2]) + splitCharacter + str(r[0]['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): #P, Q and S (average) PAve = (r[0]['branch'][i][15] + r[0]['branch'][i][13]) / 2.0 QAve = (r[0]['branch'][i][14] + r[0]['branch'][i][16]) / 2.0 SAve = numpy.sqrt(((PAve * PAve) + (QAve * QAve))) #Print P loss, Q loss, aveP, aveQ and aveS. f.write( str(i + 1) + splitCharacter + str(absDiff(r[0]['branch'][i][15], r[0]['branch'][i][13])) + splitCharacter + str(absDiff(r[0]['branch'][i][16], r[0]['branch'][i][14])) + splitCharacter + str(PAve) + splitCharacter + str(QAve) + splitCharacter + str(SAve) + '\n') i += 1 f.close() else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.")
idx = int(ts / 300) % nloads bus = ppc['bus'] gen = ppc['gen'] bus[6, 2] = loads[idx, 0] bus[4, 2] = loads[idx, 1] bus[8, 2] = loads[idx, 2] if ts >= outage[1] and ts <= outage[2]: gen[outage[0], 7] = 0 else: gen[outage[0], 7] = 1 for row in ppc['FNCS']: newload = float(row[2]) * float(row[3]) newidx = int(row[0]) - 1 print('GLD load', newload, 'at', newidx) bus[newidx, 2] += newload res = pp.runopf(ppc, ppopt) bus = res['bus'] gen = res['gen'] Pload = bus[:, 2].sum() Pgen = gen[:, 1].sum() Ploss = Pgen - Pload print(ts, res['success'], bus[:, 2].sum()) print(ts, res['success'], bus[:, 2].sum(), bus[6, 2], bus[6, 7], bus[6, 13], bus[6, 14], gen[0, 1], gen[1, 1],
def pypower_loop (casefile, rootname): """ Public function to start PYPOWER solutions under control of FNCS The time step, maximum time, and other data must be set up in a JSON file. This function will run the case under FNCS, manage the FNCS message traffic, and shutdown FNCS upon completion. Five files are written: - *rootname.csv*; intermediate solution results during simulation - *rootname_m_dict.json*; metadata for post-processing - *bus_rootname_metrics.json*; bus metrics for GridLAB-D connections, upon completion - *gen_rootname_metrics.json*; bulk system generator metrics, upon completion - *sys_rootname_metrics.json*; bulk system-level metrics, upon completion Args: casefile (str): the configuring JSON file name, without extension rootname (str): the root filename for metrics output, without extension """ # if len(sys.argv) == 3: # rootname = sys.argv[1] # casefile = sys.argv[2] # else: # print ('usage: python fncsPYPOWER.py metrics_rootname casedata.json') # sys.exit() ppc = load_json_case (casefile) StartTime = ppc['StartTime'] tmax = int(ppc['Tmax']) period = int(ppc['Period']) dt = int(ppc['dt']) make_dictionary (ppc, rootname) bus_mp = open ("bus_" + rootname + "_metrics.json", "w") gen_mp = open ("gen_" + rootname + "_metrics.json", "w") sys_mp = open ("sys_" + rootname + "_metrics.json", "w") bus_meta = {'LMP_P':{'units':'USD/kwh','index':0},'LMP_Q':{'units':'USD/kvarh','index':1}, 'PD':{'units':'MW','index':2},'QD':{'units':'MVAR','index':3},'Vang':{'units':'deg','index':4}, 'Vmag':{'units':'pu','index':5},'Vmax':{'units':'pu','index':6},'Vmin':{'units':'pu','index':7}} gen_meta = {'Pgen':{'units':'MW','index':0},'Qgen':{'units':'MVAR','index':1},'LMP_P':{'units':'USD/kwh','index':2}} sys_meta = {'Ploss':{'units':'MW','index':0},'Converged':{'units':'true/false','index':1}} bus_metrics = {'Metadata':bus_meta,'StartTime':StartTime} gen_metrics = {'Metadata':gen_meta,'StartTime':StartTime} sys_metrics = {'Metadata':sys_meta,'StartTime':StartTime} gencost = ppc['gencost'] fncsBus = ppc['FNCS'] gen = ppc['gen'] ppopt_market = pp.ppoption(VERBOSE=0, OUT_ALL=0, PF_DC=ppc['opf_dc']) ppopt_regular = pp.ppoption(VERBOSE=0, OUT_ALL=0, PF_DC=ppc['pf_dc']) loads = np.loadtxt(ppc['CSVFile'], delimiter=',') for row in ppc['UnitsOut']: print ('unit ', row[0], 'off from', row[1], 'to', row[2], flush=True) for row in ppc['BranchesOut']: print ('branch', row[0], 'out from', row[1], 'to', row[2], flush=True) nloads = loads.shape[0] ts = 0 tnext_opf = -dt # initializing for metrics collection tnext_metrics = 0 loss_accum = 0 conv_accum = True n_accum = 0 bus_accum = {} gen_accum = {} for i in range (fncsBus.shape[0]): busnum = int(fncsBus[i,0]) bus_accum[str(busnum)] = [0,0,0,0,0,0,0,99999.0] for i in range (gen.shape[0]): gen_accum[str(i+1)] = [0,0,0] op = open (rootname + '.csv', 'w') print ('t[s],Converged,Pload,P7 (csv),Unresp (opf),P7 (rpf),Resp (opf),GLD Pub,BID?,P7 Min,V7,LMP_P7,LMP_Q7,Pgen1,Pgen2,Pgen3,Pgen4,Pdisp,Deg,c2,c1', file=op, flush=True) fncs.initialize() # transactive load components csv_load = 0 # from the file unresp = 0 # unresponsive load estimate from the auction agent resp = 0 # will be the responsive load as dispatched by OPF resp_deg = 0 # RESPONSIVE_DEG from FNCS resp_c1 = 0 # RESPONSIVE_C1 from FNCS resp_c2 = 0 # RESPONSIVE_C2 from FNCS resp_max = 0 # RESPONSIVE_MAX_MW from FNCS feeder_load = 0 # amplified feeder MW while ts <= tmax: # start by getting the latest inputs from GridLAB-D and the auction events = fncs.get_events() new_bid = False load_scale = float (fncsBus[0][2]) for topic in events: value = fncs.get_value(topic) if topic == 'UNRESPONSIVE_MW': unresp = load_scale * float(value) fncsBus[0][3] = unresp # to poke unresponsive estimate into the bus load slot new_bid = True elif topic == 'RESPONSIVE_MAX_MW': resp_max = load_scale * float(value) new_bid = True elif topic == 'RESPONSIVE_C2': resp_c2 = float(value) / load_scale new_bid = True elif topic == 'RESPONSIVE_C1': resp_c1 = float(value) new_bid = True elif topic == 'RESPONSIVE_DEG': resp_deg = int(value) new_bid = True else: gld_load = parse_mva (value) # actual value, may not match unresp + resp load feeder_load = float(gld_load[0]) * load_scale if new_bid == True: dummy = 2 # print('**Bid', ts, unresp, resp_max, resp_deg, resp_c2, resp_c1) # update the case for bids, outages and CSV loads idx = int ((ts + dt) / period) % nloads bus = ppc['bus'] gen = ppc['gen'] branch = ppc['branch'] gencost = ppc['gencost'] csv_load = loads[idx,0] bus[4,2] = loads[idx,1] bus[8,2] = loads[idx,2] # process the generator and branch outages for row in ppc['UnitsOut']: if ts >= row[1] and ts <= row[2]: gen[row[0],7] = 0 else: gen[row[0],7] = 1 for row in ppc['BranchesOut']: if ts >= row[1] and ts <= row[2]: branch[row[0],10] = 0 else: branch[row[0],10] = 1 if resp_deg == 2: gencost[4][3] = 3 gencost[4][4] = -resp_c2 gencost[4][5] = resp_c1 elif resp_deg == 1: gencost[4][3] = 2 gencost[4][4] = resp_c1 gencost[4][5] = 0.0 else: gencost[4][3] = 1 gencost[4][4] = 999.0 gencost[4][5] = 0.0 gencost[4][6] = 0.0 if ts >= tnext_opf: # expecting to solve opf one dt before the market clearing period ends, so GridLAB-D has time to use it # for OPF, the FNCS bus load is CSV + Unresponsive estimate, with Responsive separately dispatchable bus = ppc['bus'] gen = ppc['gen'] bus[6,2] = csv_load for row in ppc['FNCS']: unresp = float(row[3]) newidx = int(row[0]) - 1 if unresp >= feeder_load: bus[newidx,2] += unresp else: bus[newidx,2] += feeder_load gen[4][9] = -resp_max res = pp.runopf(ppc, ppopt_market) if res['success'] == False: conv_accum = False opf_bus = deepcopy (res['bus']) opf_gen = deepcopy (res['gen']) lmp = opf_bus[6,13] resp = -1.0 * opf_gen[4,1] fncs.publish('LMP_B7', 0.001 * lmp) # publishing $/kwh # print (' OPF', ts, csv_load, '{:.3f}'.format(unresp), '{:.3f}'.format(resp), # '{:.3f}'.format(feeder_load), '{:.3f}'.format(opf_bus[6,2]), # '{:.3f}'.format(opf_gen[0,1]), '{:.3f}'.format(opf_gen[1,1]), '{:.3f}'.format(opf_gen[2,1]), # '{:.3f}'.format(opf_gen[3,1]), '{:.3f}'.format(opf_gen[4,1]), '{:.3f}'.format(lmp)) # if unit 2 (the normal swing bus) is dispatched at max, change the swing bus to 9 if opf_gen[1,1] >= 191.0: ppc['bus'][1,1] = 2 ppc['bus'][8,1] = 3 print (' SWING Bus 9') else: ppc['bus'][1,1] = 3 ppc['bus'][8,1] = 1 print (' SWING Bus 2') tnext_opf += period # always update the electrical quantities with a regular power flow bus = ppc['bus'] gen = ppc['gen'] bus[6,13] = lmp gen[0,1] = opf_gen[0, 1] gen[1,1] = opf_gen[1, 1] gen[2,1] = opf_gen[2, 1] gen[3,1] = opf_gen[3, 1] # during regular power flow, we use the actual CSV + feeder load, ignore dispatchable load and use actual bus[6,2] = csv_load + feeder_load gen[4,1] = 0 # opf_gen[4, 1] gen[4,9] = 0 rpf = pp.runpf(ppc, ppopt_regular) if rpf[0]['success'] == False: conv_accum = False bus = rpf[0]['bus'] gen = rpf[0]['gen'] Pload = bus[:,2].sum() Pgen = gen[:,1].sum() Ploss = Pgen - Pload # update the metrics n_accum += 1 loss_accum += Ploss for i in range (fncsBus.shape[0]): busnum = int(fncsBus[i,0]) busidx = busnum - 1 row = bus[busidx].tolist() # LMP_P, LMP_Q, PD, QD, Vang, Vmag, Vmax, Vmin: row[11] and row[12] are Vmax and Vmin constraints PD = row[2] + resp # the ERCOT version shows how to track scaled_resp separately for each FNCS bus Vpu = row[7] bus_accum[str(busnum)][0] += row[13]*0.001 bus_accum[str(busnum)][1] += row[14]*0.001 bus_accum[str(busnum)][2] += PD bus_accum[str(busnum)][3] += row[3] bus_accum[str(busnum)][4] += row[8] bus_accum[str(busnum)][5] += Vpu if Vpu > bus_accum[str(busnum)][6]: bus_accum[str(busnum)][6] = Vpu if Vpu < bus_accum[str(busnum)][7]: bus_accum[str(busnum)][7] = Vpu for i in range (gen.shape[0]): row = gen[i].tolist() busidx = int(row[0] - 1) # Pgen, Qgen, LMP_P (includes the responsive load as dispatched by OPF) gen_accum[str(i+1)][0] += row[1] gen_accum[str(i+1)][1] += row[2] gen_accum[str(i+1)][2] += float(opf_bus[busidx,13])*0.001 # write the metrics if ts >= tnext_metrics: sys_metrics[str(ts)] = {rootname:[loss_accum / n_accum,conv_accum]} bus_metrics[str(ts)] = {} for i in range (fncsBus.shape[0]): busnum = int(fncsBus[i,0]) busidx = busnum - 1 row = bus[busidx].tolist() met = bus_accum[str(busnum)] bus_metrics[str(ts)][str(busnum)] = [met[0]/n_accum, met[1]/n_accum, met[2]/n_accum, met[3]/n_accum, met[4]/n_accum, met[5]/n_accum, met[6], met[7]] bus_accum[str(busnum)] = [0,0,0,0,0,0,0,99999.0] gen_metrics[str(ts)] = {} for i in range (gen.shape[0]): met = gen_accum[str(i+1)] gen_metrics[str(ts)][str(i+1)] = [met[0]/n_accum, met[1]/n_accum, met[2]/n_accum] gen_accum[str(i+1)] = [0,0,0] tnext_metrics += period n_accum = 0 loss_accum = 0 conv_accum = True volts = 1000.0 * bus[6,7] * bus[6,9] / sqrt(3.0) # VLN for GridLAB-D fncs.publish('three_phase_voltage_B7', volts) # CSV file output print (ts, res['success'], '{:.3f}'.format(Pload), # Pload '{:.3f}'.format(csv_load), # P7 (csv) '{:.3f}'.format(unresp), # GLD Unresp '{:.3f}'.format(bus[6,2]), # P7 (rpf) '{:.3f}'.format(resp), # Resp (opf) '{:.3f}'.format(feeder_load), # GLD Pub new_bid, '{:.3f}'.format(gen[4,9]), # P7 Min '{:.3f}'.format(bus[6,7]), # V7 '{:.3f}'.format(bus[6,13]), # LMP_P7 '{:.3f}'.format(bus[6,14]), # LMP_Q7 '{:.2f}'.format(gen[0,1]), # Pgen1 '{:.2f}'.format(gen[1,1]), # Pgen2 '{:.2f}'.format(gen[2,1]), # Pgen3 '{:.2f}'.format(gen[3,1]), # Pgen4 '{:.2f}'.format(res['gen'][4, 1]), # Pdisp '{:.4f}'.format(resp_deg), # degree '{:.8f}'.format(ppc['gencost'][4, 4]), # c2 '{:.8f}'.format(ppc['gencost'][4, 5]), # c1 sep=',', file=op, flush=True) # request the next time step, if necessary if ts >= tmax: print ('breaking out at',ts,flush=True) break ts = fncs.time_request(min(ts + dt, tmax)) # =================================== print ('writing metrics', flush=True) print (json.dumps(sys_metrics), file=sys_mp, flush=True) print (json.dumps(bus_metrics), file=bus_mp, flush=True) print (json.dumps(gen_metrics), file=gen_mp, flush=True) print ('closing files', flush=True) bus_mp.close() gen_mp.close() sys_mp.close() op.close() print ('finalizing FNCS', flush=True) fncs.finalize() if sys.platform != 'win32': usage = resource.getrusage(resource.RUSAGE_SELF) RESOURCES = [ ('ru_utime', 'User time'), ('ru_stime', 'System time'), ('ru_maxrss', 'Max. Resident Set Size'), ('ru_ixrss', 'Shared Memory Size'), ('ru_idrss', 'Unshared Memory Size'), ('ru_isrss', 'Stack Size'), ('ru_inblock', 'Block inputs'), ('ru_oublock', 'Block outputs')] print('Resource usage:') for name, desc in RESOURCES: print(' {:<25} ({:<10}) = {}'.format(desc, name, getattr(usage, name)))
def main_loop(): if len(sys.argv) == 2: rootname = sys.argv[1] else: print('usage: python fncsPYPOWER.py rootname') sys.exit() ppc = ppcasefile() StartTime = ppc['StartTime'] tmax = int(ppc['Tmax']) period = int(ppc['Period']) dt = int(ppc['dt']) make_dictionary(ppc, rootname) bus_mp = open("bus_" + rootname + "_metrics.json", "w") gen_mp = open("gen_" + rootname + "_metrics.json", "w") sys_mp = open("sys_" + rootname + "_metrics.json", "w") bus_meta = { 'LMP_P': { 'units': 'USD/kwh', 'index': 0 }, 'LMP_Q': { 'units': 'USD/kvarh', 'index': 1 }, 'PD': { 'units': 'MW', 'index': 2 }, 'QD': { 'units': 'MVAR', 'index': 3 }, 'Vang': { 'units': 'deg', 'index': 4 }, 'Vmag': { 'units': 'pu', 'index': 5 }, 'Vmax': { 'units': 'pu', 'index': 6 }, 'Vmin': { 'units': 'pu', 'index': 7 } } gen_meta = { 'Pgen': { 'units': 'MW', 'index': 0 }, 'Qgen': { 'units': 'MVAR', 'index': 1 }, 'LMP_P': { 'units': 'USD/kwh', 'index': 2 } } sys_meta = { 'Ploss': { 'units': 'MW', 'index': 0 }, 'Converged': { 'units': 'true/false', 'index': 1 } } bus_metrics = {'Metadata': bus_meta, 'StartTime': StartTime} gen_metrics = {'Metadata': gen_meta, 'StartTime': StartTime} sys_metrics = {'Metadata': sys_meta, 'StartTime': StartTime} gencost = ppc['gencost'] fncsBus = ppc['FNCS'] ppopt = pp.ppoption(VERBOSE=0, OUT_ALL=0, PF_DC=1) loads = np.loadtxt('NonGLDLoad.txt', delimiter=',') for row in ppc['UnitsOut']: print('unit ', row[0], 'off from', row[1], 'to', row[2], flush=True) for row in ppc['BranchesOut']: print('branch', row[0], 'out from', row[1], 'to', row[2], flush=True) nloads = loads.shape[0] ts = 0 tnext_opf = -dt op = open(rootname + '.csv', 'w') print( 't[s],Converged,Pload,P7 (csv), GLD Unresp, P7 (opf), Resp (opf), GLD Pub, BID?, P7 Min, V7,LMP_P7,LMP_Q7,Pgen1,Pgen2,Pgen3,Pgen4,Pdisp, gencost2, gencost1, gencost0', file=op, flush=True) # print ('t[s], ppc-Pd5, ppc-Pd9, ppc-Pd7, bus-Pd7, ppc-Pg1, gen-Pg1, ppc-Pg2, gen-Pg2, ppc-Pg3, gen-Pg3, ppc-Pg4, gen-Pg4, ppc-Pg5, gen-Pg5, ppc-Cost2, gencost-Cost2, ppc-Cost1, gencost-Cost1, ppc-Cost0, gencost-Cost0', file=op, flush=True) fncs.initialize() # transactive load components csv_load = 0 scaled_unresp = 0 scaled_resp = 0 resp_c0 = 0 resp_c1 = 0 resp_c2 = 0 resp_max = 0 gld_load = 0 # this is the actual # ================================== # Laurentiu Marinovici - 2017-12-14 actual_load = 0 new_bid = False # saveInd = 0 # saveDataDict = {} # =================================== while ts <= tmax: if ts >= tnext_opf: # expecting to solve opf one dt before the market clearing period ends, so GridLAB-D has time to use it idx = int((ts + dt) / period) % nloads bus = ppc['bus'] print( '<<<<< ts = {}, ppc-Pd5 = {}, bus-Pd5 = {}, ppc-Pd7 = {}, bus-Pd7 = {}, ppc-Pd9 = {}, bus-Pd9 = {} >>>>>>>' .format(ts, ppc["bus"][4, 2], bus[4, 2], ppc["bus"][6, 2], bus[6, 2], ppc["bus"][8, 2], bus[8, 2])) gen = ppc['gen'] branch = ppc['branch'] gencost = ppc['gencost'] csv_load = loads[idx, 0] bus[4, 2] = loads[idx, 1] bus[8, 2] = loads[idx, 2] print( '<<<<< ts = {}, ppc-Pd5 = {}, bus-Pd5 = {}, ppc-Pd7 = {}, bus-Pd7 = {}, ppc-Pd9 = {}, bus-Pd9 = {} >>>>>>>' .format(ts, ppc["bus"][4, 2], bus[4, 2], ppc["bus"][6, 2], bus[6, 2], ppc["bus"][8, 2], bus[8, 2])) # process the generator and branch outages for row in ppc['UnitsOut']: if ts >= row[1] and ts <= row[2]: gen[row[0], 7] = 0 else: gen[row[0], 7] = 1 for row in ppc['BranchesOut']: if ts >= row[1] and ts <= row[2]: branch[row[0], 10] = 0 else: branch[row[0], 10] = 1 bus[6, 2] = csv_load # ================================= # Laurentiu Marinovici - 2017-12-14 # bus[6,2] = csv_load + actual_load # ================================= for row in ppc['FNCS']: scaled_unresp = float(row[2]) * float(row[3]) newidx = int(row[0]) - 1 bus[newidx, 2] += scaled_unresp print( '<<<<< ts = {}, ppc-Pd5 = {}, bus-Pd5 = {}, ppc-Pd7 = {}, bus-Pd7 = {}, ppc-Pd9 = {}, bus-Pd9 = {} >>>>>>>' .format(ts, ppc["bus"][4, 2], bus[4, 2], ppc["bus"][6, 2], bus[6, 2], ppc["bus"][8, 2], bus[8, 2])) gen[4][9] = -resp_max * float(fncsBus[0][2]) gencost[4][3] = 3 gencost[4][4] = resp_c2 gencost[4][5] = resp_c1 gencost[4][6] = resp_c0 # ================================= # Laurentiu Marinovici - 2017-12-14 # print('Before running OPF:') # print('Disp load/neg gen: Pg = ', gen[4][1], ', Pmax = ', gen[4][8], ', Pmin = ', gen[4][9], ', status = ', gen[4][7]) # print('Disp load/neg gen cost coefficients: ', gencost[4][4], ', ', gencost[4][5], ', ', gencost[4][6]) # gen[4, 7] = 1 # turn on dispatchable load #ppc['gen'] = gen #ppc['bus'] = bus #ppc['branch'] = branch #ppc['gencost'] = gencost # print (ts, ppc["bus"][4, 2], ppc["bus"][8, 2], ppc["bus"][6, 2], bus[6, 2], ppc["gen"][0, 1], gen[0, 1], ppc["gen"][1, 1], gen[1, 1], ppc["gen"][2, 1], gen[2, 1], ppc["gen"][3, 1], gen[3, 1], ppc["gen"][4, 1], gen[4, 1], ppc["gencost"][4, 4], gencost[4, 4], ppc["gencost"][4, 5], gencost[4, 5], ppc["gencost"][4, 6], gencost[4, 6], sep=',', file=op, flush=True) # ===================================================================================================================== res = pp.runopf(ppc, ppopt) # ================================= # Laurentiu Marinovici - 2017-12-21 # mpcKey = 'mpc' + str(saveInd) # resKey = 'res' + str(saveInd) # saveDataDict[mpcKey] = copy.deepcopy(ppc) # saveDataDict[resKey] = copy.deepcopy(res) # saveInd += 1 # ================================= bus = res['bus'] gen = res['gen'] Pload = bus[:, 2].sum() Pgen = gen[:, 1].sum() Ploss = Pgen - Pload scaled_resp = -1.0 * gen[4, 1] # CSV file output print(ts, res['success'], '{:.3f}'.format(bus[:, 2].sum()), '{:.3f}'.format(csv_load), '{:.3f}'.format(scaled_unresp), '{:.3f}'.format(bus[6, 2]), '{:.3f}'.format(scaled_resp), '{:.3f}'.format(actual_load), new_bid, '{:.3f}'.format(gen[4, 9]), '{:.3f}'.format(bus[6, 7]), '{:.3f}'.format(bus[6, 13]), '{:.3f}'.format(bus[6, 14]), '{:.2f}'.format(gen[0, 1]), '{:.2f}'.format(gen[1, 1]), '{:.2f}'.format(gen[2, 1]), '{:.2f}'.format(gen[3, 1]), '{:.2f}'.format(res['gen'][4, 1]), '{:.6f}'.format(ppc['gencost'][4, 4]), '{:.4f}'.format(ppc['gencost'][4, 5]), '{:.4f}'.format(ppc['gencost'][4, 6]), sep=',', file=op, flush=True) fncs.publish('LMP_B7', 0.001 * bus[6, 13]) fncs.publish('three_phase_voltage_B7', 1000.0 * bus[6, 7] * bus[6, 9]) print('**OPF', ts, csv_load, scaled_unresp, gen[4][9], scaled_resp, bus[6, 2], 'LMP', 0.001 * bus[6, 13]) # update the metrics sys_metrics[str(ts)] = {rootname: [Ploss, res['success']]} bus_metrics[str(ts)] = {} for i in range(fncsBus.shape[0]): busnum = int(fncsBus[i, 0]) busidx = busnum - 1 row = bus[busidx].tolist() bus_metrics[str(ts)][str(busnum)] = [ row[13] * 0.001, row[14] * 0.001, row[2], row[3], row[8], row[7], row[11], row[12] ] gen_metrics[str(ts)] = {} for i in range(gen.shape[0]): row = gen[i].tolist() busidx = int(row[0] - 1) gen_metrics[str(ts)][str(i + 1)] = [ row[1], row[2], float(bus[busidx, 13]) * 0.001 ] tnext_opf += period if tnext_opf > tmax: print('breaking out at', tnext_opf, flush=True) break # apart from the OPF, keep loads updated ts = fncs.time_request(ts + dt) events = fncs.get_events() new_bid = False for key in events: topic = key.decode() # ================================== # Laurentiu Marinovici - 2017-12-14l # print('The event is: ........ ', key) # print('The topic is: ........ ', topic) # print('The value is: ........ ', fncs.get_value(key).decode()) # ============================================================= if topic == 'UNRESPONSIVE_KW': unresp_load = 0.001 * float(fncs.get_value(key).decode()) fncsBus[0][ 3] = unresp_load # poke unresponsive estimate into the bus load slot new_bid = True elif topic == 'RESPONSIVE_MAX_KW': resp_max = 0.001 * float(fncs.get_value(key).decode()) # in MW new_bid = True elif topic == 'RESPONSIVE_M': # resp_c2 = 1000.0 * 0.5 * float(fncs.get_value(key).decode()) resp_c2 = -1e6 * float(fncs.get_value(key).decode()) new_bid = True elif topic == 'RESPONSIVE_B': # resp_c1 = 1000.0 * float(fncs.get_value(key).decode()) resp_c1 = 1e3 * float(fncs.get_value(key).decode()) new_bid = True # ============================================ # Laurentiu Marinovici elif topic == 'RESPONSIVE_BB': resp_c0 = -float(fncs.get_value(key).decode()) new_bid = True # ============================================ elif topic == 'UNRESPONSIVE_PRICE': # not actually used unresp_price = float(fncs.get_value(key).decode()) new_bid = True else: gld_load = parse_mva(fncs.get_value(key).decode( )) # actual value, may not match unresp + resp load # ================================== # Laurentiu Marinovici - 2017-12-14 # print('GLD real = ', float(gld_load[0]), '; GLD imag = ', float(gld_load[1])) # print('Amp factor = ', float(fncsBus[0][2])) # ================================================================== actual_load = float(gld_load[0]) * float(fncsBus[0][2]) print(' Time = ', ts, '; actual load real = ', actual_load) if new_bid == True: print('**Bid', ts, unresp_load, resp_max, resp_c2, resp_c1, resp_c0) # Laurentiu Marinovici - 2017-12-21 # spio.savemat('matFile.mat', saveDataDict) # =================================== print('writing metrics', flush=True) print(json.dumps(bus_metrics), file=bus_mp, flush=True) print(json.dumps(gen_metrics), file=gen_mp, flush=True) print(json.dumps(sys_metrics), file=sys_mp, flush=True) print('closing files', flush=True) bus_mp.close() gen_mp.close() sys_mp.close() op.close() print('finalizing FNCS', flush=True) fncs.finalize()
def solveOpf(caseName, config): bxObj = ptbx.InitCases(caseName) sysN, sysopt = opf_args.opf_args2(bxObj.System) sysopt = pyp.ppoption(sysopt, VERBOSE=3) results = pyp.runopf(bxObj.System, sysopt) print("Success")
def main_loop(): if len(sys.argv) == 2: rootname = sys.argv[1] else: print('usage: python fncsPYPOWER.py rootname') sys.exit() ppc = ppcasefile() StartTime = ppc['StartTime'] tmax = int(ppc['Tmax']) period = int(ppc['Period']) dt = int(ppc['dt']) make_dictionary(ppc, rootname) bus_mp = open("bus_" + rootname + "_metrics.json", "w") gen_mp = open("gen_" + rootname + "_metrics.json", "w") sys_mp = open("sys_" + rootname + "_metrics.json", "w") bus_meta = { 'LMP_P': { 'units': 'USD/kwh', 'index': 0 }, 'LMP_Q': { 'units': 'USD/kvarh', 'index': 1 }, 'PD': { 'units': 'MW', 'index': 2 }, 'QD': { 'units': 'MVAR', 'index': 3 }, 'Vang': { 'units': 'deg', 'index': 4 }, 'Vmag': { 'units': 'pu', 'index': 5 }, 'Vmax': { 'units': 'pu', 'index': 6 }, 'Vmin': { 'units': 'pu', 'index': 7 } } gen_meta = { 'Pgen': { 'units': 'MW', 'index': 0 }, 'Qgen': { 'units': 'MVAR', 'index': 1 }, 'LMP_P': { 'units': 'USD/kwh', 'index': 2 } } sys_meta = { 'Ploss': { 'units': 'MW', 'index': 0 }, 'Converged': { 'units': 'true/false', 'index': 1 } } bus_metrics = {'Metadata': bus_meta, 'StartTime': StartTime} gen_metrics = {'Metadata': gen_meta, 'StartTime': StartTime} sys_metrics = {'Metadata': sys_meta, 'StartTime': StartTime} gencost = ppc['gencost'] fncsBus = ppc['FNCS'] gen = ppc['gen'] ppopt_market = pp.ppoption(VERBOSE=0, OUT_ALL=0, PF_DC=1) ppopt_regular = pp.ppoption(VERBOSE=0, OUT_ALL=0, PF_DC=1) loads = np.loadtxt('NonGLDLoad.txt', delimiter=',') for row in ppc['UnitsOut']: print('unit ', row[0], 'off from', row[1], 'to', row[2], flush=True) for row in ppc['BranchesOut']: print('branch', row[0], 'out from', row[1], 'to', row[2], flush=True) nloads = loads.shape[0] ts = 0 tnext_opf = -dt # initializing for metrics collection tnext_metrics = 0 loss_accum = 0 conv_accum = True n_accum = 0 bus_accum = {} gen_accum = {} for i in range(fncsBus.shape[0]): busnum = int(fncsBus[i, 0]) bus_accum[str(busnum)] = [0, 0, 0, 0, 0, 0, 0, 99999.0] for i in range(gen.shape[0]): gen_accum[str(i + 1)] = [0, 0, 0] op = open(rootname + '.csv', 'w') print( 't[s],Converged,Pload,P7 (csv),Unresp (opf),P7 (rpf),Resp (opf),GLD Pub,BID?,P7 Min,V7,LMP_P7,LMP_Q7,Pgen1,Pgen2,Pgen3,Pgen4,Pdisp,Deg,c2,c1', file=op, flush=True) fncs.initialize() # transactive load components csv_load = 0 # from the file unresp = 0 # unresponsive load estimate from the auction agent resp = 0 # will be the responsive load as dispatched by OPF resp_deg = 0 # RESPONSIVE_DEG from FNCS resp_c1 = 0 # RESPONSIVE_C1 from FNCS resp_c2 = 0 # RESPONSIVE_C2 from FNCS resp_max = 0 # RESPONSIVE_MAX_MW from FNCS feeder_load = 0 # amplified feeder MW while ts <= tmax: # start by getting the latest inputs from GridLAB-D and the auction events = fncs.get_events() new_bid = False load_scale = float(fncsBus[0][2]) for key in events: topic = key.decode() if topic == 'UNRESPONSIVE_MW': unresp = load_scale * float(fncs.get_value(key).decode()) fncsBus[0][ 3] = unresp # to poke unresponsive estimate into the bus load slot new_bid = True elif topic == 'RESPONSIVE_MAX_MW': resp_max = load_scale * float(fncs.get_value(key).decode()) new_bid = True elif topic == 'RESPONSIVE_C2': resp_c2 = float(fncs.get_value(key).decode()) / load_scale new_bid = True elif topic == 'RESPONSIVE_C1': resp_c1 = float(fncs.get_value(key).decode()) new_bid = True elif topic == 'RESPONSIVE_DEG': resp_deg = int(fncs.get_value(key).decode()) new_bid = True else: gld_load = parse_mva(fncs.get_value(key).decode( )) # actual value, may not match unresp + resp load feeder_load = float(gld_load[0]) * load_scale if new_bid == True: dummy = 2 # print('**Bid', ts, unresp, resp_max, resp_deg, resp_c2, resp_c1) # update the case for bids, outages and CSV loads idx = int((ts + dt) / period) % nloads bus = ppc['bus'] gen = ppc['gen'] branch = ppc['branch'] gencost = ppc['gencost'] csv_load = loads[idx, 0] bus[4, 2] = loads[idx, 1] bus[8, 2] = loads[idx, 2] # process the generator and branch outages for row in ppc['UnitsOut']: if ts >= row[1] and ts <= row[2]: gen[row[0], 7] = 0 else: gen[row[0], 7] = 1 for row in ppc['BranchesOut']: if ts >= row[1] and ts <= row[2]: branch[row[0], 10] = 0 else: branch[row[0], 10] = 1 if resp_deg == 2: gencost[4][3] = 3 gencost[4][4] = -resp_c2 gencost[4][5] = resp_c1 elif resp_deg == 1: gencost[4][3] = 2 gencost[4][4] = resp_c1 gencost[4][5] = 0.0 else: gencost[4][3] = 1 gencost[4][4] = 999.0 gencost[4][5] = 0.0 gencost[4][6] = 0.0 if ts >= tnext_opf: # expecting to solve opf one dt before the market clearing period ends, so GridLAB-D has time to use it # for OPF, the FNCS bus load is CSV + Unresponsive estimate, with Responsive separately dispatchable bus = ppc['bus'] gen = ppc['gen'] bus[6, 2] = csv_load for row in ppc['FNCS']: unresp = float(row[3]) newidx = int(row[0]) - 1 if unresp >= feeder_load: bus[newidx, 2] += unresp else: bus[newidx, 2] += unresp # feeder_load gen[4][9] = -resp_max res = pp.runopf(ppc, ppopt_market) if res['success'] == False: conv_accum = False opf_bus = deepcopy(res['bus']) opf_gen = deepcopy(res['gen']) lmp = opf_bus[6, 13] resp = -1.0 * opf_gen[4, 1] fncs.publish('LMP_B7', 0.001 * lmp) # publishing $/kwh print(' OPF', ts, csv_load, '{:.3f}'.format(unresp), '{:.3f}'.format(resp), '{:.3f}'.format(feeder_load), '{:.3f}'.format(opf_bus[6, 2]), '{:.3f}'.format(opf_gen[0, 1]), '{:.3f}'.format(opf_gen[1, 1]), '{:.3f}'.format(opf_gen[2, 1]), '{:.3f}'.format(opf_gen[3, 1]), '{:.3f}'.format(opf_gen[4, 1]), '{:.3f}'.format(lmp)) # if unit 2 (the normal swing bus) is dispatched at max, change the swing bus to 9 if opf_gen[1, 1] >= 191.0: ppc['bus'][1, 1] = 2 ppc['bus'][8, 1] = 3 print(' SWING Bus 9') else: ppc['bus'][1, 1] = 3 ppc['bus'][8, 1] = 1 print(' SWING Bus 2') tnext_opf += period # always update the electrical quantities with a regular power flow bus = ppc['bus'] gen = ppc['gen'] bus[6, 13] = lmp gen[0, 1] = opf_gen[0, 1] gen[1, 1] = opf_gen[1, 1] gen[2, 1] = opf_gen[2, 1] gen[3, 1] = opf_gen[3, 1] # during regular power flow, we use the actual CSV + feeder load, ignore dispatchable load and use actual bus[6, 2] = csv_load + feeder_load gen[4, 1] = 0 # opf_gen[4, 1] gen[4, 9] = 0 rpf = pp.runpf(ppc, ppopt_regular) if rpf[0]['success'] == False: conv_accum = False bus = rpf[0]['bus'] gen = rpf[0]['gen'] Pload = bus[:, 2].sum() Pgen = gen[:, 1].sum() Ploss = Pgen - Pload # update the metrics n_accum += 1 loss_accum += Ploss for i in range(fncsBus.shape[0]): busnum = int(fncsBus[i, 0]) busidx = busnum - 1 row = bus[busidx].tolist() # LMP_P, LMP_Q, PD, QD, Vang, Vmag, Vmax, Vmin: row[11] and row[12] are Vmax and Vmin constraints PD = row[ 2] + resp # TODO, if more than one FNCS bus, track scaled_resp separately Vpu = row[7] bus_accum[str(busnum)][0] += row[13] * 0.001 bus_accum[str(busnum)][1] += row[14] * 0.001 bus_accum[str(busnum)][2] += PD bus_accum[str(busnum)][3] += row[3] bus_accum[str(busnum)][4] += row[8] bus_accum[str(busnum)][5] += Vpu if Vpu > bus_accum[str(busnum)][6]: bus_accum[str(busnum)][6] = Vpu if Vpu < bus_accum[str(busnum)][7]: bus_accum[str(busnum)][7] = Vpu for i in range(gen.shape[0]): row = gen[i].tolist() busidx = int(row[0] - 1) # Pgen, Qgen, LMP_P (includes the responsive load as dispatched by OPF) gen_accum[str(i + 1)][0] += row[1] gen_accum[str(i + 1)][1] += row[2] gen_accum[str(i + 1)][2] += float(opf_bus[busidx, 13]) * 0.001 # write the metrics if ts >= tnext_metrics: sys_metrics[str(ts)] = { rootname: [loss_accum / n_accum, conv_accum] } bus_metrics[str(ts)] = {} for i in range(fncsBus.shape[0]): busnum = int(fncsBus[i, 0]) busidx = busnum - 1 row = bus[busidx].tolist() met = bus_accum[str(busnum)] bus_metrics[str(ts)][str(busnum)] = [ met[0] / n_accum, met[1] / n_accum, met[2] / n_accum, met[3] / n_accum, met[4] / n_accum, met[5] / n_accum, met[6], met[7] ] bus_accum[str(busnum)] = [0, 0, 0, 0, 0, 0, 0, 99999.0] gen_metrics[str(ts)] = {} for i in range(gen.shape[0]): met = gen_accum[str(i + 1)] gen_metrics[str(ts)][str(i + 1)] = [ met[0] / n_accum, met[1] / n_accum, met[2] / n_accum ] gen_accum[str(i + 1)] = [0, 0, 0] tnext_metrics += period n_accum = 0 loss_accum = 0 conv_accum = True volts = 1000.0 * bus[6, 7] * bus[6, 9] fncs.publish('three_phase_voltage_B7', volts) # CSV file output print( ts, res['success'], '{:.3f}'.format(Pload), # Pload '{:.3f}'.format(csv_load), # P7 (csv) '{:.3f}'.format(unresp), # GLD Unresp '{:.3f}'.format(bus[6, 2]), # P7 (rpf) '{:.3f}'.format(resp), # Resp (opf) '{:.3f}'.format(feeder_load), # GLD Pub new_bid, '{:.3f}'.format(gen[4, 9]), # P7 Min '{:.3f}'.format(bus[6, 7]), # V7 '{:.3f}'.format(bus[6, 13]), # LMP_P7 '{:.3f}'.format(bus[6, 14]), # LMP_Q7 '{:.2f}'.format(gen[0, 1]), # Pgen1 '{:.2f}'.format(gen[1, 1]), # Pgen2 '{:.2f}'.format(gen[2, 1]), # Pgen3 '{:.2f}'.format(gen[3, 1]), # Pgen4 '{:.2f}'.format(res['gen'][4, 1]), # Pdisp '{:.4f}'.format(resp_deg), # degree '{:.8f}'.format(ppc['gencost'][4, 4]), # c2 '{:.8f}'.format(ppc['gencost'][4, 5]), # c1 sep=',', file=op, flush=True) # request the next time step ts = fncs.time_request(ts + dt) if ts > tmax: print('breaking out at', ts, flush=True) break # spio.savemat('matFile.mat', saveDataDict) # =================================== print('writing metrics', flush=True) print(json.dumps(sys_metrics), file=sys_mp, flush=True) print(json.dumps(bus_metrics), file=bus_mp, flush=True) print(json.dumps(gen_metrics), file=gen_mp, flush=True) print('closing files', flush=True) bus_mp.close() gen_mp.close() sys_mp.close() op.close() print('finalizing FNCS', flush=True) fncs.finalize()
import sys import numpy as np import hashlib import paho.mqtt.client as mqttcli import paho.mqtt.publish as publish import time import struct from receive import receive from settings import settings_fromRTDS, NumData, IP_send, IP_receive, Port_send, Port_receive, IP_broker, \ dcssim, DSO_control, wait_lte, wait_dcs, results, attack from pypower.api import ppoption, runpf, printpf, runopf, rundcopf, case9 from pypower.api import * from case33bw_dcs2 import case33bw_dcs2 from send import send import bitstring #from runopf_no_printpf import runopf as runopf2 #from opf_setup_edit import opf_setup #from opf_edit import opf as opf_setup #from runopf_edit import runopf #ppc = case33bw_dcs2() ppc = case9Q() r = runopf(ppc) print(r["f"])
def mainJAPowerFlow(baseMVAName, busName, genName, branchName, splitCharacter, outputBusName, outputBranchName, outputGenName, printOutput, optimal, areasName, genCostName): # Variables (by for testing) # baseMVAName = "baseMVA.txt" # busName = "bus.txt" # genName = "gen.txt" # branchName = "branch.txt" # splitCharacter = ' ' # outputBusName = "outputBus.txt" # outputBranchName = "outputBranch.txt" # outputBranchName = "outputGen.txt" # printOutput = 0 ##### printOutput = 0 or 1, 0 for no stdout printed output, 1 if it is wanted. ##### Note that both still output to the text files. # optimal = 0 ##### optimal = 0 or 1, 0 for power flow, 1 for optimal power flow. ##### NOTE: All following inputs are only used in optimal power flow, OPF, analysis (optimal = 1), ##### but some values are still required as inputs, even if they are not used in the event of PF (optimal = 0). # areasName = "areas.txt" # genCostName = "genCost.txt" # Assign ppc ppc = readText(baseMVAName, busName, genName, branchName, splitCharacter, optimal, areasName, genCostName) #ppc = casetest() # Set pf test type # ppopt = ppoption(PF_ALG=1) ---> Power Flow algorithm: 1- NR Method # ppopt = ppoption(OUT_ALL=0, VERBOSE=0) ---> These options prevent printing output # ppopt = ppoption(PF_ALG=1, OUT_ALL=0, VERBOSE=0) if (printOutput == 1): ppopt = ppoption(OUT_ALL=1, VERBOSE=1) elif (printOutput == 0): ppopt = ppoption(OUT_ALL=0, VERBOSE=0) else: print( "printOutput must be 0 or 1, 0 for no stdout printed output, and 1 if that is desired. Both still output to text files." ) # (A) --pf_alg = PF_ALG # power flow algorithm : # 1 - Newton’s method, # 2 - FastDecoupled (XB version), # 3 - Fast-Decoupled (BX # version), # 4 - Gauss Seidel # [default: 1] # (B) --verbose = VERBOSE # amount of progress info printed: # 0 - print no progress info, # 1 - print a little progress info, # 2 - print a lot of progress info, # 3 - print all progress info # [default: 1] # (C) --out_all = OUT_ALL # controls printing of results: # -1 - individual flags control what prints, # 0 - don’t print anything # (overrides individual flags, except OUT_RAW), # 1 - print everything (overrides individual flags, except OUT_RAW) # [default: -1] # Run pf or opf test if (optimal == 0): r = runpf(ppc, ppopt) elif (optimal == 1): r = runopf(ppc, ppopt) else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.") # Check if voltage constraints are met? # Check if solution converged? if (optimal == 1): genCount = len(r['gen']) #check no. of generators = 16 busCount = len(r['bus']) #check no. of buses = 15 branchCount = len(r['branch']) #check no. of branches = 25 print("\nNo. of gen= ", genCount) print("\nbus= ", busCount) print("\nbranch=", branchCount) busGenP = numpy.zeros( genCount, dtype=numpy.float ) #create a zero column vector (16x1) for P generation busLoadP = numpy.zeros( busCount, dtype=numpy.float) #create a zero column vector (15x1) for P load branchLoss = numpy.zeros( branchCount, dtype=numpy.float ) #create a zero column vector (25x1) for branch losses i = 0 while (i < genCount): #busGenP[int(r['gen'][i][1])] += r['gen'][i][1] busGenP[i] += r['gen'][i][1] i += 1 j = 0 while (j < busCount): busLoadP[j] += r['bus'][j][2] j += 1 k = 0 while (k < branchCount): branchLoss[k] += absDiff(r['branch'][k][15], r['branch'][k][13]) k += 1 # print("\nReal power generated= \n",busGenP) # print("\nReal power demand= \n", busLoadP) # print ("\nBranch Losses= \n", branchLoss) sumGen = round(busGenP.sum(), 2) # round off up to 2 decimal points. sumLoad = round(busLoadP.sum(), 2) sumLoss = round(branchLoss.sum(), 2) print("\n") print("\nTotal Real Power Generation= ", sumGen) print("\nTotal Real Power Load= ", sumLoad) print("\nTotal Real Power Losses= ", sumLoss) print("\n") # Clears the output files (method of writing to them might be altered, so doing this is to be sure open(outputBusName, 'w').close() open(outputBranchName, 'w').close() open(outputGenName, 'w').close() # For Optimal Power Flow #Establish lengths busCount = len(r['bus']) branchCount = len(r['branch']) genCount = len(r['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #Print Gen Output f.write( str(i + 1) + splitCharacter + str(r['gen'][i][1]) + splitCharacter + str(r['gen'][i][2]) + '\n') #For Bus Output --> assign values for busGenP and busGenQ busGenP[int(r['gen'][i][0])] += r['gen'][i][1] busGenQ[int(r['gen'][i][0])] += r['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r['bus'][i][7]) + splitCharacter + str(r['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r['bus'][i][2]) + splitCharacter + str(r['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): #P, Q and S (average) PAve = (r['branch'][i][15] + r['branch'][i][13]) / 2.0 QAve = (r['branch'][i][14] + r['branch'][i][16]) / 2.0 SAve = numpy.sqrt(((PAve * PAve) + (QAve * QAve))) f.write( str(i + 1) + splitCharacter + str(absDiff(r['branch'][i][15], r['branch'][i][13])) + splitCharacter + str(absDiff(r['branch'][i][16], r['branch'][i][14])) + splitCharacter + str(PAve) + splitCharacter + str(QAve) + splitCharacter + str(SAve) + '\n') i += 1 f.close()
#print(votlage_plot,real_demand) actual_demand = peak_demand * bus_profiles[x, :] ppc['bus'][:, 2] = actual_demand ppc['bus'][:, 3] = actual_demand * math.tan(math.acos(.85)) ppc['bus'][cosim_bus, 2] = rload * load_amplification_factor / 1000000 ppc['bus'][cosim_bus, 3] = iload * load_amplification_factor / 1000000 ppopt = ppoption(PF_ALG=1) print('PF TIme is {} and ACOPF time is {}'.format( time_pf[x], time_opf[k])) ############################ Running OPF For optimal power flow intervals ############################## if (time_pf[x] == time_opf[k]): results_opf = runopf(ppc, ppopt) if (results_opf['success']): ppc['bus'] = results_opf['bus'] ppc['gen'] = results_opf['gen'] if (k == 0): LMP_solved = results_opf['bus'][:, 13] else: LMP_solved = numpy.vstack( (LMP_solved, results_opf['bus'][:, 13])) opf_time = time_opf[0:k + 1] / 3600 k = k + 1 ################################ Running PF For optimal power flow intervals ############################## solved_pf = runpf(ppc, ppopt) results_pf = solved_pf[0]
def runopf_case(self): self.results = runopf(self.ppc_2hrs)
def mainJAPowerFlow(baseMVAName, busName, genName, branchName, splitCharacter, outputBusName, outputBranchName, outputGenName, printOutput, optimal, areasName, genCostName, convergedOutputName): #Variables (by for testing) #baseMVAName = "baseMVA.txt" #busName = "bus.txt" #genName = "gen.txt" #branchName = "branch.txt" #splitCharacter = ' ' #outputBusName = "outputBus.txt" #outputBranchName = "outputBranch.txt" #outputBranchName = "outputGen.txt" #printOutput = 0 #printOutput = 0 or 1, 0 for no stdout printed output, 1 if it is wanted. Note that both still output to the text files. #optimal = 0 #optimal = 0 or 1, 0 for power flow, 1 for optimal power flow. NOTE: All following inputs are only used in optimal power flow, OPF, analysis (optimal = 1), but some values are still required as inputs, even if they are not used in the event of PF (optimal = 0). #areasName = "areas.txt" #genCostName = "genCost.txt" #convergedOutputName = "outputStatus.txt", which will have three lines. The first will just be the inputs variables given (inputs to mainJAPowerFLow). The second of which will state "0" (if it did not converge) or "1" (if it converged), while the third line will state this in text as "Converged!" (if it converged) or "Diverged!" (if it did not). Note that the "'s are not printed, just to show the contents. Also note that the second and third lines show the same information in different formats. #Assign ppc ppc = readText(baseMVAName, busName, genName, branchName, splitCharacter, optimal, areasName, genCostName) #ppc = casetest() #Set pf test type #ppopt = ppoption(PF_ALG=1) #Includes printing output (of standard pf) #ppopt = ppoption(OUT_ALL=0, VERBOSE=0) #These options prevent printing output (so prints to terminal if 1 and does not if 0) #ppopt = ppoption(PF_ALG=1, OUT_ALL=0, VERBOSE=0) if (printOutput == 1): ppopt = ppoption(OUT_ALL=1, VERBOSE=1) elif (printOutput == 0): ppopt = ppoption(OUT_ALL=0, VERBOSE=0) else: print( "printOutput must be 0 or 1, 0 for no stdout printed output, and 1 if that is desired. Both still output to text files." ) #Run pf or opf test if (optimal == 0): r = runpf(ppc, ppopt) elif (optimal == 1): r = runopf(ppc, ppopt) else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.") #Output Metadata, which outputs the input variables to the function as well as if the model converged as described in the convergedOutputName description above. out = open(convergedOutputName, 'w') out.write(baseMVAName + splitCharacter + busName + splitCharacter + genName + splitCharacter + branchName + splitCharacter + splitCharacter + splitCharacter + outputBusName + splitCharacter + outputBranchName + splitCharacter + outputGenName + splitCharacter + str(printOutput) + splitCharacter + str(optimal) + splitCharacter + areasName + splitCharacter + genCostName + splitCharacter + convergedOutputName + '\n') if (optimal == 1): #If this is OPF the convergence can be found as follows. if (r['success'] == True): print("Converged.") out.write("1\n") out.write("Converged!\n") else: print("Did not converge.") out.write("0\n") out.write("Diverged!\n") elif (optimal == 0): #For some reason this doesn't work for just PF, so will check in a more crude mannor. if ("'success': 1" in str(r)): print("Converged.") out.write("1\n") out.write("Converged!\n") else: print("Did not converge.") out.write("0\n") out.write("Diverged!\n") out.close() #Now clear the output files (method of writing to them might be altered, so doing this is to be sure open(outputBusName, 'w').close() open(outputBranchName, 'w').close() open(outputGenName, 'w').close() #For Optimal Power Flow if (optimal == 1): #Establish lengths busCount = len(r['bus']) branchCount = len(r['branch']) genCount = len(r['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r['gen'][i][1]) + splitCharacter + str(r['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r['gen'][i][0])] += r['gen'][i][1] busGenQ[int(r['gen'][i][0])] += r['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r['bus'][i][7]) + splitCharacter + str(r['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r['bus'][i][2]) + splitCharacter + str(r['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): PAve = (r['branch'][i][15] + r['branch'][i][13]) / 2.0 QAve = (r['branch'][i][14] + r['branch'][i][16]) / 2.0 SAve = numpy.sqrt(((PAve * PAve) + (QAve * QAve))) f.write( str(i + 1) + splitCharacter + str(absDiff(r['branch'][i][15], r['branch'][i][13])) + splitCharacter + str(absDiff(r['branch'][i][16], r['branch'][i][14])) + splitCharacter + str(PAve) + splitCharacter + str(QAve) + splitCharacter + str(SAve) + '\n') i += 1 f.close() #For Standard Power Flow elif (optimal == 0): #Establish lengths busCount = len(r[0]['bus']) branchCount = len(r[0]['branch']) #print(branchCount) genCount = len(r[0]['gen']) #Find Generator Per Bus Output busGenP = numpy.zeros(busCount, dtype=numpy.float) busGenQ = numpy.zeros(busCount, dtype=numpy.float) f = open(outputGenName, 'w') i = 0 while (i < genCount): #For Gen Output f.write( str(i + 1) + splitCharacter + str(r[0]['gen'][i][1]) + splitCharacter + str(r[0]['gen'][i][2]) + '\n') #For Bus Output busGenP[int(r[0]['gen'][i][0])] += r[0]['gen'][i][1] busGenQ[int(r[0]['gen'][i][0])] += r[0]['gen'][i][2] i += 1 f.close() #Print Bus Output f = open(outputBusName, 'w') i = 0 while (i < busCount): f.write( str(i + 1) + splitCharacter + str(r[0]['bus'][i][7]) + splitCharacter + str(r[0]['bus'][i][8]) + splitCharacter + str(busGenP[i]) + splitCharacter + str(busGenQ[i]) + splitCharacter + str(r[0]['bus'][i][2]) + splitCharacter + str(r[0]['bus'][i][3]) + '\n') i += 1 f.close() #Print Branch Output f = open(outputBranchName, 'w') i = 0 while (i < branchCount): #P, Q and S (average) PAve = (r[0]['branch'][i][15] + r[0]['branch'][i][13]) / 2.0 QAve = (r[0]['branch'][i][14] + r[0]['branch'][i][16]) / 2.0 SAve = numpy.sqrt(((PAve * PAve) + (QAve * QAve))) #Print P loss, Q loss, aveP, aveQ and aveS. f.write( str(i + 1) + splitCharacter + str(absDiff(r[0]['branch'][i][15], r[0]['branch'][i][13])) + splitCharacter + str(absDiff(r[0]['branch'][i][16], r[0]['branch'][i][14])) + splitCharacter + str(PAve) + splitCharacter + str(QAve) + splitCharacter + str(SAve) + '\n') i += 1 f.close() else: print("optimal must be 0 or 1, 0 for pf and 1 for opf.")