def stop(self): try: self.service.stop() except: pass try: self.broker.kill() except: pass try: self.engine.kill() except: pass try: self.dbase.stop() except: pass try: fncs.finalize() except: pass
import string import sys import fncs time_stop = int(sys.argv[1]) time_granted = 0 time_next = 1 # requires the yaml file fncs.initialize() print('# time key value till', time_stop, flush=True) while time_granted < time_stop: time_granted = fncs.time_request(time_stop) # time_next # print('**', time_granted) events = fncs.get_events() for key in events: topic = key.decode() print(time_granted, key, topic, fncs.get_value(key), flush=True) value = fncs.get_value(key).decode() if topic == 'sw_status': fncs.publish('sw_status', value) time_next = time_granted + 1 print('finalizing FNCS', flush=True) fncs.finalize() print('done', flush=True)
def launch_all(): print('launching all simulators') if sys.platform == 'win32': subprocess.Popen('call run30.bat', shell=True) else: subprocess.Popen( '(export FNCS_BROKER="tcp://*:5570" && exec fncs_broker 36 &> broker.log &)', shell=True) subprocess.Popen( '(export FNCS_CONFIG_FILE=eplus.yaml && exec EnergyPlus -w ../energyplus/USA_AZ_Tucson.Intl.AP.722740_TMY3.epw -d output -r ../energyplus/SchoolDualController.idf &> eplus.log &)', shell=True) subprocess.Popen( '(export FNCS_CONFIG_FILE=eplus_json.yaml && exec eplus_json 2d 5m School_DualController eplus_TE_Challenge_metrics.json &> eplus_json.log &)', shell=True) subprocess.Popen('(exec ./launch_TE_Challenge_agents.sh &)', shell=True) subprocess.Popen( '(export FNCS_CONFIG_FILE=pypower30.yaml && export FNCS_FATAL=NO && export FNCS_LOG_STDOUT=yes && exec python fncsPYPOWER.py TE_Challenge &> pypower.log &)', shell=True) print('launched all simulators') root.update() os.environ['FNCS_CONFIG_FILE'] = 'tesp.yaml' os.environ['FNCS_FATAL'] = 'NO' print('config file =', os.environ['FNCS_CONFIG_FILE']) fncs.initialize() time_granted = 0 time_stop = 2 * 24 * 60 yaml_delta = 5 nsteps = int(time_stop / yaml_delta) hrs = np.linspace(0.0, 48.0, nsteps + 1) idxlast = -1 x0 = np.empty(nsteps + 1) x1 = np.zeros(nsteps + 1) x2 = np.zeros(nsteps + 1) x3 = np.zeros(nsteps + 1) while time_granted < time_stop: time_granted = fncs.time_request(time_stop) events = fncs.get_events() idx = int(time_granted / yaml_delta) if idx <= idxlast: continue idxlast = idx bWantX0 = True bWantX1 = True bWantX2 = True bWantX3 = True for key in events: tok = key.decode() if bWantX1 and tok == 'power_A': val = 3.0 * float( fncs.get_value(key).decode().strip('+ degFkW')) / 1000.0 x1[idx] = val ax[1].plot(hrs[1:idx], x1[1:idx], color='red') bWantX1 = False elif bWantX3 and tok == 'house_air_temperature': val = float(fncs.get_value(key).decode().strip('+ degFkW')) x3[idx] = val ax[3].plot(hrs[1:idx], x3[1:idx], color='magenta') bWantX3 = False elif bWantX0 and tok == 'vpos7': val = float( fncs.get_value(key).decode().strip('+ degFkW')) / 133000.0 x0[idx] = val ax[0].plot(hrs[1:idx], x0[1:idx], color='green') bWantX0 = False elif bWantX2 and tok == 'clear_price': val = float(fncs.get_value(key).decode().strip('+ degFkW')) x2[idx] = val ax[2].plot(hrs[1:idx], x2[1:idx], color='blue') bWantX2 = False elif bWantX2 and tok == 'LMP7': val = float(fncs.get_value(key).decode().strip('+ degFkW')) x2[idx] = val ax[2].plot(hrs[1:idx], x2[1:idx], color='blue') bWantX2 = False elif bWantX1 and tok == 'SUBSTATION7': val = float(fncs.get_value(key).decode().strip( '+ degFkW')) # already in kW x1[idx] = val ax[1].plot(hrs[1:idx], x1[1:idx], color='red') bWantX1 = False # print (time_granted, key.decode(), fncs.get_value(key).decode()) root.update() fig.canvas.draw() fncs.finalize()
def kill_all(): if sys.platform == 'win32': fncs.finalize() subprocess.Popen('call kill5570.bat', shell=True) else: print('TODO: kill all processes')
def launch_all(): print('launching all simulators') if sys.platform == 'win32': subprocess.Popen ('call run30.bat', shell=True) else: subprocess.Popen ('(export simNum=36 && ./runVisualTE30ChallengeDocker.sh &)', shell=True) print('launched all simulators') root.update() os.environ['FNCS_CONFIG_FILE'] = 'tespTE30.yaml' os.environ['FNCS_FATAL'] = 'NO' print('config file =', os.environ['FNCS_CONFIG_FILE']) fncs.initialize() time_granted = 0 time_stop = 2 * 24 * 60 yaml_delta = 5 nsteps = int (time_stop / yaml_delta) hrs=np.linspace(0.0, 48.0, nsteps+1) idxlast = -1 x0 = np.empty(nsteps+1) x1 = np.zeros(nsteps+1) x2 = np.zeros(nsteps+1) x3 = np.zeros(nsteps+1) while time_granted < time_stop: time_granted = fncs.time_request(time_stop) events = fncs.get_events() idx = int (time_granted / yaml_delta) if idx <= idxlast: continue idxlast = idx bWantX0 = True bWantX1 = True bWantX2 = True bWantX3 = True for key in events: tok = key.decode() if bWantX1 and tok == 'power_A': val = 3.0 * float (fncs.get_value(key).decode().strip('+ degFkW')) / 1000.0 x1[idx] = val ax[1].plot(hrs[1:idx],x1[1:idx],color='red') bWantX1 = False elif bWantX3 and tok == 'house_air_temperature': val = float (fncs.get_value(key).decode().strip('+ degFkW')) x3[idx] = val ax[3].plot(hrs[1:idx],x3[1:idx],color='magenta') bWantX3 = False elif bWantX0 and tok == 'vpos7': val = float (fncs.get_value(key).decode().strip('+ degFkW')) / 133000.0 x0[idx] = val ax[0].plot(hrs[1:idx],x0[1:idx],color='green') bWantX0 = False elif bWantX2 and tok == 'clear_price': val = float (fncs.get_value(key).decode().strip('+ degFkW')) x2[idx] = val ax[2].plot(hrs[1:idx],x2[1:idx],color='blue') bWantX2 = False elif bWantX2 and tok == 'LMP7': val = float (fncs.get_value(key).decode().strip('+ degFkW')) x2[idx] = val ax[2].plot(hrs[1:idx],x2[1:idx],color='blue') bWantX2 = False elif bWantX1 and tok == 'SUBSTATION7': val = float (fncs.get_value(key).decode().strip('+ degFkW')) # already in kW x1[idx] = val ax[1].plot(hrs[1:idx],x1[1:idx],color='red') bWantX1 = False # print (time_granted, key.decode(), fncs.get_value(key).decode()) root.update() fig.canvas.draw() fncs.finalize()
import random import string import fncs name = "randome_name_" + "".join( [random.choice(string.digits) for i in xrange(8)] ) config = """name = %s time_delta = 1s""" % name # generate some time steps time_steps = sorted(random.sample([i for i in xrange(100)], 10)) print time_steps fncs.initialize(config) for time in time_steps: current_time = fncs.time_request(time) print "current time is", current_time fncs.publish("some_key", "some_value") fncs.finalize()
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 mainLoop(self): if(self.RIAPS): self.context = zmq.Context(1) self.server = self.context.socket(zmq.REP) self.server.bind("tcp://*:5555") while self.time_granted < self.time_stop: events = fncs.get_events() for topic in events: value = fncs.get_value(topic) #Collect Most recent charge data if('batt_charge' in topic): self.batt_charges[topic] = float(value.split(" ")[0][1:]) if('solar_power' in topic): if topic in self.solar_power: self.solar_power[topic].append(float(value.split(' ')[0])) else: self.solar_power[topic] = [float(value.split(' ')[0])] if('batt_power' in topic): if topic in self.batt_power: self.batt_power[topic].append(float(value.split(' ')[0])) else: self.batt_power[topic] = [float(value.split(' ')[0])] if('step' in events): self.request = '' while(self.request != 'step'): self.msg = self.server.recv_pyobj() self.request = self.msg['request'] if (self.request == 'postTrade'): self.tradeResp() if (self.request == 'charge'): self.chargeResp() print(self.time_granted, self.request, flush=True) print("solar_power: ", self.solar_power) print("batt_power: ", self.batt_power) self.solar_power = {} self.batt_power = {} self.time_granted = fncs.time_request(self.time_stop) self.server.send_pyobj('Step Granted') else: self.time_granted = fncs.time_request(self.time_stop) print("Simulation Continue, new time_granted:", str(self.time_granted)) self.server.close() self.context.term() print('zmq Closed', flush=True) else: while self.time_granted < self.time_stop: self.time_granted = fncs.time_request(self.time_stop) events = fncs.get_events() for topic in events: value = fncs.get_value(topic) #Collect Most recent charge data if('batt_charge' in topic): self.batt_charges[topic] = value if('solar_power' in topic): self.solar_power[topic] = value print('End of Simulation', 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'] 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()
def publish_heartbeat(self): '''Send heartbeat message every HEARTBEAT_PERIOD seconds. HEARTBEAT_PERIOD is set and can be adjusted in the settings module. ''' now = datetime.utcnow().isoformat(' ') + 'Z' nowdate = datetime.utcnow() print "publish_heartbeat", now timeDiff = nowdate - self.simStart valMap = defaultdict(dict) metaMap = defaultdict(dict) headers = {headers_mod.TIMESTAMP: now, headers_mod.DATE: now} #Tell FNCS we are at our next timestep if not fncs.is_initialized(): raise RuntimeError("FNCS connection was terminated. Killing Bridge.") elif self.simtime > self.simlength: fncs.finalize() self.core.stop() elif timeDiff.seconds >= 1: self.simtime+=self.heartbeat_period*self.heartbeat_multiplier print "fncs.time_request(",self.simtime,") request" self.simtime = fncs.time_request(self.simtime) print "fncs.time_request() response", self.simtime #Grab Subscriptions from FNCS to publish to Volttron message bus subKeys = fncs.get_events() if len(subKeys) > 0: for x in subKeys: valStr = fncs.get_value(x) #parse message to split value and unit valList = valStr.split(' ') if len(valList) == 1: val = valList[0] valUnit = ''; try: val = float(val) except: pass elif len(valList) == 2: val = valList[0] valUnit = valList[1] if 'int' in self.fncs_zpl['values'][x]['type']: val = int(val) elif 'double' in self.fncs_zpl['values'][x]['type']: val = float(val) elif 'complex' in self.fncs_zpl['values'][x]['type']: raise RuntimeError("complex data type is currently not supported in Volttron.") #TODO: come up with a better way to handle all types that can come in from fncs else: warnings.warn("FNCS message could not be parsed into value and unit. The message will be farwarded to Volttron message bus as is.") val = valStr valUnit = '' fncsmessage = [val, {'units' : '{0}'.format(valUnit), 'tz' : 'UTC', 'type': '{0[type]}'.format(self.fncs_zpl['values'][x])}] fncsTopic = common.FNCS_OUTPUT_PATH(path = 'devices/{0[topic]}'.format(self.fncs_zpl['values'][x])) #fncs/output/devices/topic self.vip.pubsub.publish('pubsub', fncsTopic, headers, fncsmessage).get(timeout=5) _log.debug('FNCS->Volttron:\nTopic:%s\n:Message:%s\n'%(fncsTopic, str(fncsmessage))) device, point = self.fncs_zpl['values'][x]['topic'].rsplit('/', 1) deviceAllTopic = common.FNCS_OUTPUT_PATH(path = 'devices/' + device + '/all') valMap[deviceAllTopic][point] = val metaMap[deviceAllTopic][point] = fncsmessage[1] for k in valMap.keys(): allMessage = [valMap[k], metaMap[k]] self.vip.pubsub.publish('pubsub', k, headers, allMessage).get(timeout=5) _log.debug('FNCS->Volttron:\nTopic:%s\n:Message:%s\n'%(k, str(allMessage))) #Publish heartbeat message to voltron bus self.vip.pubsub.publish( 'pubsub', '{0[name]}/heartbeat'.format(self.fncs_zpl), headers, now).get(timeout=5)