def thermal_setpoint_initilize(controller,houseID,NI,NJ): for i in range(NI): for j in range(NJ): value=np.random.uniform(74,76) fncs.publish('controller_'+houseID[i][j], value) setattr(controller,houseID[i][j], value) return
def subscribeVal(self, fncs_sub_value_String,time_granted): # Update market and house information at this time step from subscribed key values: #print('day:', self.day, 'prev day:', self.prevday, flush=True) if "DSO" in fncs_sub_value_String: for k in range(len(self.controller['Dsystem'])): self.market['retail_price'] = fncs_sub_value_String['DSO'][self.market['name']][self.controller['houseName']]['retail_price'] retail_price = self.market['retail_price'] pistar = self.house[self.controller['Dsystem'][k]]['pistar'] systemmode = self.house[self.controller['Dsystem'][k]]['systemmode'] print('time:', time_granted, 'retail price:', retail_price, 'pistar:', pistar, 'systemmode:', systemmode, flush=True) if retail_price > pistar: #retail_price > pistar #print('pi* is below retail_price: setting Cool OFF for the house', flush = True) systemmode = "OFF" self.fncs_publish['controller'][self.controller['name']]['state'] = "OFF" self.house[self.controller['Dsystem'][k]]['Ta'] = self.house[self.controller['Dsystem'][k]]['TaCaseOFF'] self.house[self.controller['Dsystem'][k]]['Tm'] = self.house[self.controller['Dsystem'][k]]['TmCaseOFF'] elif retail_price <= pistar: #print('pi* is above retail_price: setting Cool ON for the house', flush = True) systemmode = "COOL" self.fncs_publish['controller'][self.controller['name']]['state'] = "COOL" self.house[self.controller['Dsystem'][k]]['Ta'] = self.house[self.controller['Dsystem'][k]]['TaCaseON'] self.house[self.controller['Dsystem'][k]]['Tm'] = self.house[self.controller['Dsystem'][k]]['TmCaseON'] self.house[self.controller['Dsystem'][k]]['systemmode'] = systemmode print('setting pistar to:', pistar, flush = True) print('sending systemmode: ',systemmode) publish_key = self.controller['Dsystem'][k] + '_system_mode' #print('publish_key:', publish_key, flush = True) fncs.publish(publish_key, systemmode)
def onmessage(self, peer, sender, bus, topic, headers, message): d = {'topic': topic, 'headers': headers, 'message': message} # Forward message to FNCS if not fncs.is_initialized(): raise RuntimeError("FNCS connection was terminated. Killing Bridge.") fncsmessage = str(message) topic = topic.replace('fncs/input/','') fncs.publish(topic, fncsmessage) _log.debug('Volttron->FNCS:\nTopic:%s\nMessage:%s\n'%(topic, message))
def monitor_powerflow(power_listz, power_maximum): for power_list in power_listz: for i in range(15): #print(power_list) if ((power_list[0] == node_index[i]) and (power_list[1] == phase_index[i])): if (power_list[2] > power_maximum): for j in range(12): fncs.publish('house_' + str(i + 1) + '_' + str(j + 1), ThermostatMode_action) else: for j in range(12): fncs.publish('house_' + str(i + 1) + '_' + str(j + 1), ThermostatMode_default) return 0
def tradeResp(self): print(self.time_granted, self.request, flush=True) req_batt_num = self.msg['ID'] m_batt_num = self.getBattNum(req_batt_num) keyname = m_batt_num + '_solar_power' if(keyname in self.solar_power): #Solar power is negative in GridLabD batt_out = self.msg['power'] + self.solar_power[keyname][-1] print('msg[\'power\']: ', str(self.msg['power']),flush=True) print('solar power:', self.solar_power[keyname][-1],flush=True) print('batt_out:', str(batt_out),flush=True) else: batt_out = 0 fncs.publish(m_batt_num + '_batt_P_Out', str(batt_out)) self.prev_batt_commands[m_batt_num] = batt_out print('fncs published:', m_batt_num + '_batt_P_Out', str(batt_out)) self.server.send_pyobj('Trade Posted')
def publish_Price(value): #print('checking before updation',fncs_publish['auction'][market['name']]['price_cap']['propertyValue'], flush = True) fncs_publish['auction'][market['name']]['market_id']['propertyValue'] = 1 fncs_publish['auction'][market['name']]['std_dev']['propertyValue'] = 0.01 fncs_publish['auction'][ market['name']]['average_price']['propertyValue'] = 0.02078 fncs_publish['auction'][market['name']]['clear_price'] = value fncs_publish['auction'][ market['name']]['price_cap']['propertyValue'] = 3.78 fncs_publish['auction'][market['name']]['period']['propertyValue'] = 300 fncs_publish['auction'][ market['name']]['initial_price']['propertyValue'] = 0.02078 fncs_publishString = json.dumps(fncs_publish) fncs.agentPublish(fncs_publishString) fncs.publish('clear_price', value) # for i in range(15): # for j in range(12): # print('publishing WP: ', value,flush = True) # fncs.publish('clear_price'+'_'+'house_'+str(i+1)+'_'+str(j+1), value) return 0
def house_control(houseID,value): if value==(-1): T=85 fncs.publish(houseID+'_cooling_setpoint', T) #turn off elif value==0: T=72 fncs.publish(houseID+'_cooling_setpoint', T) #restore elif value==1: T=65 fncs.publish(houseID+'_cooling_setpoint', T) #turn on return
def turn_off(i,j): fncs.publish('house_'+str(i)+'_'+str(j)+'_status', -1) return
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 restore(i,j): fncs.publish('house_'+str(i)+'_'+str(j)+'_status', 0) return
elif row[1] == 1: refload = parse_kw(value) aucObj.set_refload(refload) elif row[1] == 2: row[0].set_air_temp(value) elif row[1] == 3: row[0].set_voltage(value) elif row[1] == 4: row[0].set_hvac_load(value) elif row[1] == 5: row[0].set_hvac_state(value) # set the time-of-day schedule for key, obj in hvacObjs.items(): if obj.change_basepoint(hour_of_day): fncs.publish(obj.name + '/cooling_setpoint', obj.basepoint) if bSetDefaults: for key, obj in hvacObjs.items(): fncs.publish(obj.name + '/bill_mode', 'HOURLY') fncs.publish(obj.name + '/monthly_fee', 0.0) fncs.publish(obj.name + '/thermostat_deadband', obj.deadband) bSetDefaults = False if time_granted >= tnext_bid: print('**', tnext_clear) aucObj.clear_bids() time_key = str(int(tnext_clear)) controller_metrics[time_key] = {} for key, obj in hvacObjs.items(): bid = obj.formulate_bid() # bid is [price, quantity, on_state] if bWantMarket:
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()
}, 'period': { 'propertyType': 'double', 'propertyUnit': 'none', 'propertyValue': -1.0 }, 'initial_price': { 'propertyType': 'double', 'propertyUnit': 'none', 'propertyValue': 0.0 } } } } fncs_publish['auction'][market['name']]['clear_price'] = 0.002 fncs.publish('clear_price', 0.002) ts = 0 tnext = 0 tnextBill = 300 dtBill = 300 #2592000 MonthlyBill = 20 fncs.initialize() iter = 1 # ts = -dt # while ts <= tmax: # ts += dt p = 0.0167 a = 0.004 c = -1 while ts <= tmax:
def sync(self, t1): # Update controller t1 information self.controller['t1'] = t1 # Inputs from market object: marketId = self.market['market_id'] clear_price = self.market['clear_price'] avgP = self.market['average_price'] stdP = self.market['std_dev'] # Inputs from controller: ramp_low = self.controller['ramp_low'] ramp_high = self.controller['ramp_high'] range_low = self.controller['range_low'] range_high = self.controller['range_high'] lastmkt_id = self.controller['lastmkt_id'] deadband = self.controller['deadband'] setpoint0 = self.controller['setpoint0'] last_setpoint = self.controller['last_setpoint'] minT = self.controller['minT'] maxT = self.controller['maxT'] bid_delay = self.controller['bid_delay'] next_run = self.controller['next_run'] direction = self.controller['direction'] # Inputs from house object: demand = self.house['controlled_load_all'] monitor = self.house['currTemp'] powerstate = self.house['powerstate'] # determine what we have to do in this sync step update_setpoints = False update_bid = False if marketId != lastmkt_id: print ('sync: market changed, need to update the setpoints', t1, next_run, marketId, lastmkt_id) update_setpoints = True elif t1 >= next_run - bid_delay and self.controller_bid['rebid'] == 0: # temporarily disable rebids print ('sync: t1 within bidding window, need to publish bid and state', t1, next_run - bid_delay) update_bid = True else: # print (' returning', next_run) return next_run print (' processing', demand, powerstate, monitor, last_setpoint, deadband, direction, clear_price, avgP, stdP) # Check t1 to determine if the sync part is needed to be processed or not # if t1 == next_run and marketId == lastmkt_id : # print (' return because t1 == next_run and marketId == lastmkt_id') # return sys.maxsize # if t1 < next_run and marketId == lastmkt_id : # if t1 <= next_run - bid_delay : # if self.controller['use_predictive_bidding'] == 1 and ((self.controller['control_mode'] == 'CN_RAMP' and setpoint0 != last_setpoint) or (self.controller['control_mode'] == 'CN_DOUBLE_RAMP' and (self.controller['heating_setpoint0'] != self.controller['last_heating_setpoint'] or self.controller['cooling_setpoint0'] != self.controller['last_cooling_setpoint']))): # Base set point setpoint0 is changed, and therefore sync is needed: # print (' pass because setpoint0 changed') # pass # elif self.controller['use_override'] == 'ON' and t1 == next_run - bid_delay : # At the exact time that controller is operating, therefore sync is needed: # print (' pass because times match exactly') # pass # else: # if self.house['last_pState'] == powerstate: # If house state not changed, then do not go through sync part: # print (' return because house state did not change') # return next_run # else: # print (' return because t1 > next_run - bid_delay') # return next_run # If market get updated, then update the set point deadband_shift = 0 # Set deadband shift if user predictive bidding is true if self.controller['use_predictive_bidding'] == 1: deadband_shift = 0.5 * deadband # if self.controller['control_mode'] == 'CN_RAMP': if update_setpoints == True: # Update controller last market id and bid id self.controller['lastmkt_id'] = marketId self.controller['lastbid_id'] = -1 self.controller_bid['rebid'] = 0 # Calculate shift direction shift_direction = 0 if self.controller['use_predictive_bidding'] == 1: if (self.controller['dir'] > 0 and clear_price < self.controller['last_p']) or (self.controller['dir'] < 0 and clear_price > self.controller['last_p']): shift_direction = -1 elif (self.controller['dir'] > 0 and clear_price >= self.controller['last_p']) or (self.controller['dir'] < 0 and clear_price <= self.controller['last_p']): shift_direction = 1 else: shift_direction = 0 # Calculate updated set_temp if abs(stdP) < 0.0001: set_temp = setpoint0 elif clear_price < avgP and range_low != 0: set_temp = setpoint0 + (clear_price - avgP) * abs(range_low) / (ramp_low * stdP) + deadband_shift*shift_direction elif clear_price > avgP and range_high != 0: set_temp = setpoint0 + (clear_price - avgP) * abs(range_high) / (ramp_high * stdP) + deadband_shift*shift_direction else: set_temp = setpoint0 + deadband_shift*shift_direction # override # if self.controller['use_override'] == 'ON' and self.house['re_override'] != 'none': # if clear_price <= self.controller['last_p']: # self.fncs_publish['controller'][self.controller['name']]['override_prop'] = 'ON' # else: # self.fncs_publish['controller'][self.controller['name']]['override_prop'] = 'OFF' # Check if set_temp is out of limit if set_temp > maxT: set_temp = maxT elif set_temp < minT: set_temp = minT # Update house set point and the cleared price if t1 != 0: print(' changing', self.house['lastsetpoint0'], 'to', set_temp, 'at', clear_price) self.house['setpoint0'] = set_temp - self.house['lastsetpoint0'] fncs.publish('cooling_setpoint', set_temp) fncs.publish('bill_mode', 'HOURLY') fncs.publish('price', clear_price) self.house['lastsetpoint0'] = set_temp else: # Change of house setpoint only changes when market changes self.house['setpoint0'] = 0; # Calculate bidding price # Bidding price when monitored load temperature is at the min and max limit of the controller bid_price = -1 no_bid = 0 if self.controller['dir'] > 0: if self.controller['use_predictive_bidding'] == 1: if powerstate == 'OFF' and monitor > (maxT - deadband_shift): bid_price = self.market['price_cap'] elif powerstate != 'OFF' and monitor < (minT + deadband_shift): bid_price = 0 no_bid = 1 elif powerstate != 'OFF' and monitor > maxT: bid_price = self.market['price_cap'] elif powerstate == 'OFF' and monitor < minT: bid_price = 0 no_bid = 1 else: if monitor > maxT: bid_price = self.market['price_cap'] elif monitor < minT: bid_price = 0 no_bid = 1 elif self.controller['dir'] < 0: if self.controller['use_predictive_bidding'] == 1: if powerstate == 'OFF' and monitor < (minT + deadband_shift): bid_price = self.market['price_cap'] elif powerstate != 'OFF' and monitor > (maxT - deadband_shift): bid_price = 0 no_bid = 1 elif powerstate != 'OFF' and monitor < minT: bid_price = self.market['price_cap'] elif powerstate == 'OFF' and monitor > maxT: bid_price = 0 no_bid = 1 else: if monitor < minT: bid_price = self.market['price_cap'] elif monitor > maxT: bid_price = 0 no_bid = 1 elif self.controller['dir'] == 0: if self.controller['use_predictive_bidding'] == 1: if not(direction): warnings.warn('the variable direction did not get set correctly') elif ((monitor > maxT + deadband_shift) or (powerstate != 'OFF' and monitor > minT - deadband_shift)) and direction > 0: bid_price = self.market['price_cap'] elif ((monitor < minT - deadband_shift) or (powerstate != 'OFF' and monitor < maxT + deadband_shift)) and direction < 0: bid_price = self.market['price_cap'] elif powerstate == 'OFF' and monitor > maxT: bid_price = 0 no_bid = 1 else: if monitor < minT: bid_price = self.market['price_cap'] elif monitor > maxT: bid_price = 0 no_bid = 1 else: bid_price = avgP # Bidding price when the monitored load temperature is within the controller temp limit if monitor > setpoint0: k_T = ramp_high T_lim = range_high elif monitor < setpoint0: k_T = ramp_low T_lim = range_low else: k_T = 0 T_lim = 0 bid_offset = 0.0001 if bid_price < 0 and monitor != setpoint0: if abs(stdP) < bid_offset: bid_price = avgP else: bid_price = avgP + (monitor - setpoint0)*(k_T * stdP) / abs(T_lim) elif monitor == setpoint0: bid_price = avgP # Update the outputs if demand > 0 and no_bid != 1: # Update bid price and quantity self.controller['last_p'] = bid_price self.controller['last_q'] = demand # self.controller['bid_id'] += 1 # Check market unit with controller default unit kW if (self.market['market_unit']).lower() != "kW": if (self.market['market_unit']).lower() == "w": self.controller['last_q'] = self.controller['last_q']*1000 elif (self.market['market_unit']).lower() == "mw": self.controller['last_q'] = self.controller['last_q']/1000 # Update parameters self.controller_bid['market_id'] = self.controller['lastmkt_id'] self.controller_bid['bid_price'] = self.controller['last_p'] self.controller_bid['bid_quantity'] = self.controller['last_q'] # Set controller_bid state self.controller_bid['state'] = powerstate else: # Update bid price and quantity self.controller['last_p'] = 0 self.controller['last_q'] = 0 # Update controller_bid parameters self.controller_bid['market_id'] = 0 self.controller_bid['bid_price'] = 0 self.controller_bid['bid_quantity'] = 0 # If the controller is double_ramp type elif self.controller['control_mode'] == 'CN_DOUBLE_RAMP': midpoint = 0.0 if self.controller['cool_minT'] - self.controller['heat_maxT'] < deadband: if self.controller_bid['resolve_mode'] == 'DEADBAND': midpoint = (self.controller['heat_maxT'] + self.controller['cool_minT']) / 2 if (midpoint - deadband/2) < self.controller['heating_setpoint0'] or (midpoint + deadband/2) < self.controller['cooling_setpoint0']: warnings.warn('The midpoint between the max heating setpoint and the min cooling setpoint must be half a deadband away from each base setpoint') return -1 else: self.controller['heat_maxT'] = midpoint - deadband/2 self.controller['cool_minT'] = midpoint + deadband/2 elif self.controller_bid['resolve_mode'] == 'SLIDING': if self.controller['heat_maxT'] > self.controller['cooling_setpoint0'] - deadband: warnings.warn('The max heating setpoint must be a full deadband less than the cooling_base_setpoint') return -1 if self.controller['cool_minT'] < self.controller['heating_setpoint0'] + deadband: warnings.warn('The min cooling setpoint must be a full deadband greater than the heating_base_setpoint') return -1 if self.controller['last_mode'] == 'OFF' or self.controller['last_mode'] == 'COOL': self.controller['heat_maxT'] = self.controller['cool_minT'] - deadband elif self.controller['last_mode'] == 'HEAT': self.controller['cool_minT'] = self.controller['heat_maxT'] + deadband else: warnings.warn('Unrecognized resolve_mode when double_ramp overlap resolution is needed') return -1 if update_setpoints == True: # Update controller last market id and bid id self.controller['lastmkt_id'] = marketId self.controller['lastbid_id'] = -1 self.controller_bid['rebid'] = 0 # Calculate shift direction shift_direction = 0 if self.controller['use_predictive_bidding'] == 1: if (self.controller['thermostat_mode'] == 'COOL' and clear_price < self.controller['last_p']) or (self.controller['thermostat_mode'] == 'HEAT' and clear_price > self.controller['last_p']): shift_direction = -1 elif (self.controller['thermostat_mode'] == 'COOL' and clear_price >= self.controller['last_p']) or (self.controller['thermostat_mode'] == 'HEAT' and clear_price <= self.controller['last_p']): shift_direction = 1 else: shift_direction = 0 # Calculate updated set_temp if abs(stdP) < 0.0001: set_temp_cooling = self.controller['cooling_setpoint0'] set_temp_heating = self.controller['heating_setpoint0'] elif clear_price > avgP: set_temp_cooling = self.controller['cooling_setpoint0'] + (clear_price - avgP) * abs(self.controller['cool_range_high']) / (self.controller['cool_ramp_high'] * stdP) + deadband_shift*shift_direction set_temp_heating = self.controller['heating_setpoint0'] + (clear_price - avgP) * abs(self.controller['heat_range_low']) / (self.controller['heat_ramp_low'] * stdP) + deadband_shift*shift_direction elif clear_price < avgP: set_temp_cooling = self.controller['cooling_setpoint0'] + (clear_price - avgP) * abs(self.controller['cool_range_low']) / (self.controller['cool_ramp_low'] * stdP) + deadband_shift*shift_direction set_temp_heating = self.controller['heating_setpoint0'] + (clear_price - avgP) * abs(self.controller['heat_range_high']) / (self.controller['heat_ramp_high'] * stdP) + deadband_shift*shift_direction else: set_temp_cooling = self.controller['cooling_setpoint0'] + deadband_shift*shift_direction set_temp_heating = self.controller['heating_setpoint0'] + deadband_shift*shift_direction # Check if set_temp is out of limit if set_temp_cooling > self.controller['cool_maxT']: set_temp_cooling = self.controller['cool_maxT'] elif set_temp_cooling < self.controller['cool_minT']: set_temp_cooling = self.controller['cool_minT'] if set_temp_heating > self.controller['heat_maxT']: set_temp_heating = self.controller['heat_maxT'] elif set_temp_heating < self.controller['heat_minT']: set_temp_heating = self.controller['heat_minT'] # Update house set point - output delta setpoint0 if t1 != 0: self.house['cooling_setpoint0'] = set_temp_cooling - self.house['lastcooling_setpoint0'] self.house['lastcooling_setpoint0'] = set_temp_cooling self.house['heating_setpoint0'] = set_temp_heating - self.house['lastheating_setpoint0'] self.house['lastheating_setpoint0'] = set_temp_heating # fncs.publish('cooling_setpoint', set_temp_cooling) # fncs.publish('heating_setpoint', set_temp_heating) else: self.house['cooling_setpoint0'] = 0 self.house['heating_setpoint0'] = 0 # Calculate bidding price # Bidding price when monitored load temperature is at the min and max limit of the controller last_p = last_q = 0.0 # We have to cool: if monitor > self.controller['cool_maxT'] and (self.house['thermostat_state'] == 'UNKNOWN' or self.house['thermostat_state'] == 'OFF' or self.house['thermostat_state'] == 'COOL'): last_p = self.market['price_cap'] last_q = self.house['cooling_demand'] # We have to heat: elif monitor < self.controller['heat_minT'] and (self.house['thermostat_state'] == 'UNKNOWN' or self.house['thermostat_state'] == 'OFF' or self.house['thermostat_state'] == 'HEAT'): last_p = self.market['price_cap'] last_q = self.house['heating_demand'] # We are floating in between heating and cooling elif monitor > self.controller['heat_maxT'] and monitor < self.controller['cool_minT']: last_p = last_q = 0.0 # We might heat, if the price is right elif monitor <= self.controller['heat_maxT'] and monitor >= self.controller['heat_minT'] and (self.house['thermostat_state'] == 'UNKNOWN' or self.house['thermostat_state'] == 'OFF' or self.house['thermostat_state'] == 'HEAT'): ramp = self.controller['heat_ramp_high'] if monitor > self.controller['heating_setpoint0'] else self.controller['heat_ramp_low'] range = self.controller['heat_range_high'] if monitor > self.controller['heating_setpoint0'] else self.controller['heat_range_low'] if monitor != self.controller['heating_setpoint0']: if abs(stdP) < 0.0001: last_p = avgP else: last_p = avgP + (monitor - self.controller['heating_setpoint0'])*(ramp * stdP) / abs(range) last_q = self.house['heating_demand'] # We might cool, if the price is right elif monitor <= self.controller['cool_maxT'] and monitor >= self.controller['cool_minT'] and (self.house['thermostat_state'] == 'UNKNOWN' or self.house['thermostat_state'] == 'OFF' or self.house['thermostat_state'] == 'COOL'): ramp = self.controller['cool_ramp_high'] if monitor > self.controller['cooling_setpoint0'] else self.controller['cool_ramp_low'] range = self.controller['cool_range_high'] if monitor > self.controller['cooling_setpoint0'] else self.controller['cool_range_low'] if monitor != self.controller['cooling_setpoint0']: if abs(stdP) < 0.0001: last_p = avgP else: last_p = avgP + (monitor - self.controller['cooling_setpoint0'])*(ramp * stdP) / abs(range) last_q = self.house['cooling_demand'] if last_p > self.market['price_cap']: last_p = self.market['price_cap'] if last_p < -self.market['price_cap']: last_p = -self.market['price_cap'] # Update the outputs # Update bid price and quantity self.controller['last_p'] = bid_price self.controller['last_q'] = demand self.controller['bid_id'] += 1 # Check market unit with controller default unit kW if (self.market['market_unit']).lower() != "kW": if (self.market['market_unit']).lower() == "w": self.controller['last_q'] = self.controller['last_q']*1000 elif (self.market['market_unit']).lower() == "mw": self.controller['last_q'] = self.controller['last_q']/1000 # Update parameters self.controller_bid['market_id'] = self.controller['lastmkt_id'] self.controller_bid['bid_price'] = last_p self.controller_bid['bid_quantity'] = last_q if last_q > 0.001: # Set controller_bid state self.controller_bid['state'] = powerstate else: if self.house['last_pState'] != powerstate: # Set controller_bid state self.controller_bid['state'] = powerstate # Update house last power state self.house['last_pState'] = powerstate # Issue a bid, if appropriate if update_bid == True and self.controller_bid['bid_quantity'] > 0 and self.controller_bid['rebid'] == 0: #temporarily disable rebids self.fncs_publish['controller'][self.controller['name']]['market_id']['propertyValue'] = self.controller_bid['market_id'] self.fncs_publish['controller'][self.controller['name']]['bid_id']['propertyValue'] = self.controller['name'] # bid_id is unique for each controller unchanged self.fncs_publish['controller'][self.controller['name']]['price']['propertyValue'] = self.controller_bid['bid_price'] self.fncs_publish['controller'][self.controller['name']]['quantity']['propertyValue'] = self.controller_bid['bid_quantity'] self.fncs_publish['controller'][self.controller['name']]['bid_accepted']['propertyValue'] = 1 if no_bid == 0 else 0 self.fncs_publish['controller'][self.controller['name']]['state']['propertyValue'] = self.controller_bid['state'] self.fncs_publish['controller'][self.controller['name']]['rebid']['propertyValue'] = self.controller_bid['rebid'] self.fncs_publish['controller'][self.controller['name']]['bid_name'] = self.controller['name'] fncs_publishString = json.dumps(self.fncs_publish) fncs.agentPublish(fncs_publishString) print ('*** Published Bid at', t1, next_run - bid_delay, self.controller_bid['bid_price'], self.controller_bid['bid_quantity'], self.controller_bid['state'], self.controller_bid['rebid']) self.controller_bid['rebid'] = 1 # Return sync time t2 return sys.maxsize
loadforecast_RP(hour, day, FileName) #print ('ts3: ',ts, flush = True) if (len(load) != 0): #print ('ts3: ',ts, flush = True) for i in range(len(load)): #print('ts3:', ts, 'load[i][0]:', load[i][0], flush=True) if (ts >= load[i][0]): #print ('ts4: ',ts, flush = True) if (ts == load[i][0]): print('Publishing loadforecast to AMES: ', str(load[i][0]), str(load[i][1]), load[i][2], flush=True) fncs.publish(str(load[i][1]), load[i][2]) else: break if (ts < (timeSim + deltaT)): ts = fncs.time_request(timeSim + deltaT) else: #print('time_granted2:', ts, flush = True) timeSim = timeSim + deltaT ts = fncs.time_request(timeSim + deltaT) #print('Day:', day, 'Hour:', hour, flush=True) prev_day = day prev_hour = hour fncs.finalize()
def publish_WholesalePrice(value): fncs.publish('WholesalePrice', value) return 0
bline.append(base_line) hour = int(len(bline) / hour_factor) minute = (len(bline) - hour * hour_factor) / (minute_factor) print('hour: ', hour, ' minutes: ', minute) print('base_line: ', base_line) print('distribution load: ', distribution_load) print('base_line - distribution_load:', power_error) dload.append(distribution_load) #clear price clear_price = market_clearing(power_error, total_hvac, list_pistar, list_power_level) print('************************************************') print('************************************************') if sub_time >= 10: sub_time = 0 fncs.publish('clear_price', clear_price) print('clear_price for next 5 mins:', clear_price) #clprice.append(clear_price) clprice.extend([clear_price for i in range(10)]) time_granted = fncs.time_request(timeSim + deltaT) #announce price every 5 mins #sub_time=0 #print('*******DLOAD**************') #print(dload) #print('*******BLINE**************') #print(bline) print('*******DLOAD**************') print(dload) print('*******BLINE**************')
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], gen[2, 1], gen[3, 1], sep=',', file=op) fncs.publish('LMP_B7', 0.001 * bus[6, 13]) fncs.publish('three_phase_voltage_B7', 1000.0 * bus[6, 7] * bus[6, 9]) print('publishing LMP=', 0.001 * bus[6, 13], 'vpos=', 1000.0 * bus[6, 7] * bus[6, 9]) # 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] ]
def turn_on(i, j): #turn on hvac by reducing the temprature setpoints New_T_setpoint = 60 fncs.publish(houseID[i][j] + '/cooling_setpoint', New_T_setpoint) return
fncs.initialize() print('# time key value till', time_stop, flush=True) alpha = 0.4 factor = 0.1 while time_granted < time_stop: print('Resident market time ', time_granted, flush=True) 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 == 'MonthlyBill': alpha = alpha + float(value) * factor fncs.publish('Preference', alpha) # if time_granted >= time_next: # fncs.publish('Preference', alpha) # time_next += deltaT # if time_next > time_stop: # print ('breaking out at',time_next,flush=True) # break time_next = time_next + deltaT 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() # value = value + 0.001
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 turn_on(i,j): #turn on hvac by reducing the temprature setpoints fncs.publish('house_'+str(i)+'_'+str(j)+'_status', 1) return
signalValues=() signals_l = list(RtlabApi.GetSignalsDescription()) #find only V signal values of interest for sig_name in signalNames: for item in signals_l: if sig_name in item: signalValues=signalValues+(item[6],) i=0 for voltage in voltages_topic: Voltage_real=signalValues[2*i] Voltage_imag=signalValues[2*i+1] if Voltage_imag<0: Voltage_str=str(Voltage_real) + str(Voltage_imag) + "j" else: Voltage_str=str(Voltage_real) + "+" + str(Voltage_imag) + "j" fncs.publish(voltage,Voltage_str) i+=1 #Get P&Q values P_val=() for P in load_p_topic: P_val=P_val+(round((float(fncs.get_value(P))/10000),2),) print P_val Q_val=() for Q in load_q_topic: Q_val=Q_val+(round((float(fncs.get_value(Q))/10000),2),) print Q_val # Get control to send parameters RtlabApi.GetParameterControl(1) # Send control signals after getting control timetest=time.time()
def restore(i, j): #assign default setting, i.e. 72 New_T_setpoint = 72 fncs.publish(houseID[i][j] + '/cooling_setpoint', New_T_setpoint) return
def sync(self, timeSim): # Update controller t1 information self.controller['t1'] = timeSim # Inputs from market object: marketId = self.market['market_id'] clear_price = self.market['clear_price'] avgP = self.market['average_price'] stdP = self.market['std_dev'] # Inputs from controller: # Inputs from house object: demand = self.house['controlled_load_all'] monitor = self.house['currTemp'] powerstate = self.house['powerstate'] thermostatcontrol = self.house['thermostatcontrol'] systemmode = self.house['systemmode'] lastmkt_id = self.controller['lastmkt_id'] air_temperature = self.house['currTemp'] Tbliss = self.house['Tbliss'] theta = self.house['theta'] d = self.house['d'] P = self.house['P'] print (" sync:", demand, powerstate, clear_price, flush=True) if self.controller['t1'] < self.controller['next_run'] and marketId == lastmkt_id : if self.controller['t1'] <= self.controller['next_run'] - bid_delay : if self.controller['use_predictive_bidding'] == 1 and ((self.controller['control_mode'] == 'CN_RAMP' and setpoint0 != last_setpoint) or (self.controller['control_mode'] == 'CN_DOUBLE_RAMP' and (self.controller['heating_setpoint0'] != self.controller['last_heating_setpoint'] or self.controller['cooling_setpoint0'] != self.controller['last_cooling_setpoint']))): # Base set point setpoint0 is changed, and therefore sync is needed: pass elif self.controller['use_override'] == 'ON' and self.controller['t1'] == self.controller['next_run']- bid_delay : # At the exact time that controller is operating, therefore sync is needed: pass else: if self.house['last_pState'] == powerstate: # If house state not changed, then do not go through sync part: return self.controller['next_run'] else: return self.controller['next_run'] # Update house last power state self.house['last_pState'] = powerstate print('checking theta', theta, flush=True) print('air_temperature', air_temperature, flush=True) print('clear_price', clear_price, flush=True) pi = theta * air_temperature print('pi*:', pi, theta * air_temperature, flush=True) if air_temperature >= Tbliss + d: print('air_temperature exceeded Tmax: setting Cool ON for the house', flush=True) systemmode = "COOL" elif Tbliss - d >= air_temperature: print('air_temperature is below Tmin: setting Cool OFF for the house', flush = True) systemmode = "OFF" elif clear_price > theta * air_temperature: print('pi* is below clear_price: setting Cool OFF for the house', flush = True) systemmode = "OFF" else: print('pi* is above clear_price: setting Cool ON for the house', flush = True) systemmode = "COOL" fncs.publish('system_mode', systemmode) print('publishing set values', flush = True) fncs_publishString = json.dumps(self.fncs_publish) fncs.agentPublish(fncs_publishString) # Return sync time t2 return sys.maxsize
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 turn_off(i, j): #turn on havac by increasing the temperature set points New_T_setpoint = 100 fncs.publish(houseID[i][j] + '/cooling_setpoint', New_T_setpoint) return
# requires the zpl/yaml file fncs.initialize() print('*****FNCS HAS INITIALIZED******') print("# time key value", file=op) while time_granted < time_stop: time_granted = fncs.time_request(time_stop) events = fncs.get_events() SubKeys = [] SubKeyVals = [] for key in events: print(time_granted, key.decode(), fncs.get_value(key).decode(), file=op) Temp = str(key.decode()) SubKeys.append(Temp) Temp = str(fncs.get_value(key).decode()) SubKeyVals.append(Temp) keys, key_val = fncs_parser.synch(SubKeys, SubKeyVals) for i in range(len(keys)): print(str(keys[i])) print(str(key_val[i])) fncs.publish(str(keys[i]), str(key_val[i])) time.sleep(5) fncs.finalize() op.close() print('*****FNCS HAS ENDED******')
else: pair = topic.split('#') houseName = pair[0] if pair[1] == 'V1': voltages[houseName] = parse_fncs_magnitude(value) elif pair[1] == 'Tair': temperatures[houseName] = parse_fncs_magnitude(value) if bSetDeadbands: bSetDeadbands = False print('setting thermostat deadbands at', time_granted) # set all of the house deadbands and initial setpoints for house, row in dict['houses'].items(): topic = house + '_thermostat_deadband' value = row['deadband'] fncs.publish(topic, value) setpoints[house] = 0.0 lastchange[house] = -lockout_period precooling_status[house] = False # update all of the house setpoints count_temp_dev = 0 sum_temp_dev = 0.0 min_temp_dev = 10000.0 max_temp_dev = 0.0 for house, row in dict['houses'].items(): # time-scheduled setpoints if hour_of_day >= row['day_start_hour'] and hour_of_day <= row[ 'day_end_hour']: value = row['day_set'] else:
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)
distribution_load=[] while ts <= tmax: # print ("looping", ts, tnext, tmax, flush=True) if ts >= tnext: tnext += dt if tnext > tmax: # print ('breaking out at',tnext,flush=True) break ts = fncs.time_request(tnext) events = fncs.get_events() for key in events: topic = key.decode() value = float(fncs.get_value(key).decode()) if topic == 'rt_price': price=value for i in range (15): for j in range(12): New_T_setpoint=house_control(i,j,price,controller) fncs.publish('controller_'+houseID[i][j], New_T_setpoint) #publish new set point to hous i j in gridlab #setattr(controller,houseID[i][j],New_T_setpoint) # set new setpoint to controller dictionary if topic=='distribution_load': distribution_load.append(value) #print (distribution_load) print ('finalizing FNCS', flush=True) logfile('distribution_load.txt',distribution_load) fncs.finalize()