def run(self, P_req, Q_req, initSOC, t, dt, ts): # ExecuteFleet(self, Steps, Timestep, P_request, Q_request, forecast): # run(self, P_req=[0], Q_req=[0], ts=datetime.utcnow(), del_t=timedelta(hours=1)): # Give the code the capability to respond to None requests if P_req == None: P_req = 0 if Q_req == None: Q_req = 0 P_togrid = 0 P_service = 0 P_base = 0 P_service_max = 0 self.P_request_perWH = P_req / self.numWH # this is only for the first step number = 0 # index for running through all the water heaters NumDevicesToCall = 0 P_service_max0 = 0 # decision making about which water heater to call on for service, check if available at last step, if so then # check for SoC > self.minSOC and Soc < self.maxSOC for n in range(self.numWH): if self.P_request_perWH < 0 and self.IsAvailableAdd[ n] > 0 and self.SOC[n] < self.maxSOC: NumDevicesToCall += 1 elif self.P_request_perWH > 0 and self.IsAvailableShed[ n] > 0 and self.SOC[n] > self.minSOC: NumDevicesToCall += 1 if P_req != None: self.P_request_perWH = P_req / max( NumDevicesToCall, 1 ) # divide the fleet request by the number of devices that can be called upon # create a .csv outputfile with each water heater's metrics # outputfilename = join(self.base_path,"WH_fleet_outputs.csv") # self.outputfile = open(outputfilename,"w") # self.outputfile.write("Timestep,") # create a .csv outputfile with P_service, P_togrid, and P_base # outputfilename = join(self.base_path,"WH_fleet_outputs.csv") ################################# for wh in self.whs: # loop through all water heaters if P_req == None: response = wh.execute( self.TtankInitial[number], self.TtankInitial_b[number], self.TsetInitial[number], self.Tamb[number][0], self.RHamb[number][0], self.Tmains[number][0], self.draw[number][0], 0, self.Type, self.dt, self.draw_fleet_ave[0], self.element_on_last) P_service = 0 if P_req < 0 and self.IsAvailableAdd[number] > 0: response = wh.execute( self.TtankInitial[number], self.TtankInitial_b[number], self.TsetInitial[number], self.Tamb[number][0], self.RHamb[number][0], self.Tmains[number][0], self.draw[number][0], P_req, self.Type, self.dt, self.draw_fleet_ave[0], self.element_on_last) P_req = P_req - response.Eservice P_service += response.Eservice elif P_req > 0 and self.IsAvailableShed[number] > 0: response = wh.execute( self.TtankInitial[number], self.TtankInitial_b[number], self.TsetInitial[number], self.Tamb[number][0], self.RHamb[number][0], self.Tmains[number][0], self.draw[number][0], P_req, self.Type, self.dt, self.draw_fleet_ave[0], self.element_on_last) P_req = P_req + response.Eservice P_service -= response.Eservice #print("P_req = {}, P_service = {}, Eservice = {}".format(P_req,P_service,response.Eservice)) else: response = wh.execute( self.TtankInitial[number], self.TtankInitial_b[number], self.TsetInitial[number], self.Tamb[number][0], self.RHamb[number][0], self.Tmains[number][0], self.draw[number][0], 0, self.Type, self.dt, self.draw_fleet_ave[0], self.element_on_last) # print('P_req = {}'.format(P_req)) # assign returned parameters to associated lists to be recorded self.element_on_last[number] = response.ElementOn self.TtankInitial[number] = response.Ttank self.TtankInitial_b[number] = response.Ttank_b self.SOC[number] = response.SOC self.SOCb[number] = response.SOC_b self.IsAvailableAdd[number] = response.IsAvailableAdd self.IsAvailableShed[number] = response.IsAvailableShed self.AvailableCapacityAdd[number] = response.AvailableCapacityAdd self.AvailableCapacityShed[number] = response.AvailableCapacityShed self.ServiceCallsAccepted[number] = response.ServiceCallsAccepted self.ServiceProvided[number] = response.Eservice ''' P_togrid -= response.Eused P_base -= response.Pbase if P_req <0 or P_req > 0: P_response = (P_togrid - P_base) else: P_response = 0 ''' P_togrid -= response.Eused P_base -= response.Pbase # self.outputfile.write(str(response.Ttank) +"," + str(self.TsetInitial[number]) + "," + str(response.Eused) + "," + str(response.PusedMax) + "," + str(response.Eloss) + "," + str(response.ElementOn) + "," + str(response.Eservice) + "," + str(response.SOC) + "," + str(response.AvailableCapacityAdd) + "," + str(response.AvailableCapacityShed) + "," + str(response.ServiceCallsAccepted) + "," + str(response.IsAvailableAdd) + "," + str(response.IsAvailableShed) + "," + str(self.draw[number][0]) + "," + str(response.Edel) + ",") # resp.sim_step = response.sim_step number += 1 # go to next device if P_req <= 0: P_service_max += response.AvailableCapacityShed # NOTE THIS ASSUMES THE MAX SERVICE IS LOAD SHED else: P_service_max0 += response.AvailableCapacityAdd P_service_max = -1.0 * P_service_max0 # self.outputfile.write("\n") self.step += 1 # To advance the step by step in the disturbance file # Output Fleet Response resp = FleetResponse() resp.P_service = [] resp.P_service_max = [] resp.P_service_min = [] resp.P_togrid = [] resp.P_togrid_max = [] resp.P_togrid_min = [] resp.P_forecast = [] resp.P_base = [] resp.E = [] resp.C = [] resp.ts = ts resp.sim_step = dt # resp.P_dot_up = resp.P_togrid_max / ServiceRequest.Timestep.seconds resp.P_service_max = P_service_max resp.P_service = P_service resp.P_base = P_base resp.P_togrid = P_togrid # if P_service != 0: # print("resp.P_base = {}".format(resp.P_base)) # print("Pbase = {}".format(resp.P_base)) # print("Ptogrid = {}".format(resp.P_togrid)) # Available Energy stored at the end of the most recent timestep # resp.E += response.Estored resp.E = 0 resp.C += response.SOC / (self.numWH) resp.Q_togrid = 'NA' resp.Q_service = 'NA' resp.Q_service_max = 'NA' resp.Q_service_min = 'NA' resp.Q_togrid_min = 'NA' resp.Q_togrid_max = 'NA' resp.Q_dot_up = 'NA' resp.Q_dot_down = 'NA' resp.P_dot_up = 0 resp.P_dot_down = 0 resp.Eff_charge = 1.0 # TODO: change this if we ever use a HPWH to use the HP efficiency resp.Eff_discharge = 1.0 # always equal to 1 for this device resp.P_dot = resp.P_togrid / dt resp.P_service_min = 0 resp.dT_hold_limit = 'NA' resp.T_restore = 'NA' resp.Strike_price = 'NA' resp.SOC_cost = 'NA' # TotalServiceProvidedPerTimeStep[step] = -1.0*self.P_service # per time step for all hvacs -1.0* """ Modify the power and SOC of the different subfeets according to the frequency droop regulation according to IEEE standard """ if self.FW21_Enabled and self.is_autonomous: power_ac = resp.P_service_max p_prev = resp.P_togrid power_fleet = self.frequency_watt(power_ac, p_prev, self.ts, self.location, self.db_UF_subfleet, self.db_OF_subfleet) power_fleet, SOC_step = self.update_soc_due_to_frequency_droop( initSOC, power_fleet, dt) self.time = t + dt self.ts = self.ts + timedelta(seconds=dt) # Restart time if it surpasses 24 hours if self.time > 24 * 3600: self.time = self.time - 24 * 3600 # Impact Metrics # Update the metrics ''' Ttotal = 0 SOCTotal = 0 self.cycle_basee = np.sum(self.cycle_off_base) self.cycle_basee += np.sum(self.cycle_on_base) self.cycle_grid = np.sum(self.cycle_off_grid) self.cycle_grid += np.sum(self.cycle_on_grid) ''' for number in range(self.numWH): if response.Ttank <= self.TsetInitial[ number] - 10: # assume 10F deadband (consistent with wh.py) self.unmet_hours += 1 * self.sim_step / 3600.0 if resp.P_base == 0 and resp.P_togrid == 0: self.ratio_P_togrid_P_base = 1.0 elif resp.P_base == 0 and resp.P_togrid != 0: self.ratio_P_togrid_P_base = 'NA' else: self.ratio_P_togrid_P_base = resp.P_togrid / (resp.P_base) self.energy_impacts += abs(resp.P_service) * (self.sim_step / 3600) return resp
def run(self, P_req, Q_req, initSOC, t, dt, ts): #ExecuteFleet(self, Steps, Timestep, P_request, Q_request, forecast): # run(self, P_req=[0], Q_req=[0], ts=datetime.utcnow(), del_t=timedelta(hours=1)): # Give the code the capability to respond to None requests if P_req == None: P_req = 0 if Q_req == None: Q_req = 0 # run through fleet once as a forecast just to get initial conditions number = 0 # run through all the devices servsum = 0 servmax = 0 servmax2 = 0 NumDevicesToCall = 0 p_togrid = 0 p_service = 0 p_base = 0 service_max = 0 service_min = 0 # laststep = step - 1 # decision making about which RF to call on for service, check if available at last step, if so then # check for SoC > self.minSOC and Soc < self.maxSOC P_request_perRF = P_req/max(NumDevicesToCall,1) #divide the fleet request by the number of devices that can be called upon for n in range(self.numRF): if P_request_perRF < 0 and self.IsAvailableAdd[n] > 0: NumDevicesToCall += 1 elif P_request_perRF > 0 and self.IsAvailableShed[n] > 0: NumDevicesToCall += 1 P_request_perRF = P_req/max(NumDevicesToCall,1) #divide the fleet request by the number of devices that can be called upon ################################# for rfdg in self.RFs: #loop through all RFs TsetLast = self.TsetInitial[number] TairLastB = self.TairInitialB[number] TfoodLastB = self.TfoodInitialB[number] TcaseLastB = self.TcaseInitialB[number] TairLast = self.TairInitial[number] TfoodLast = self.TfoodInitial[number] TcaseLast = self.TcaseInitial[number] if P_req<0 and self.IsAvailableAdd[number] > 0 : # For step >=1, can use last step temperature... response = rfdg.FRIDGE(TairLastB, TfoodLastB, TcaseLastB, TairLast, TfoodLast, TcaseLast, TsetLast, self.Tamb[number][self.step], self.R_case[number], self.R_food[number], self.R_infil[number], self.C_case[number], self.C_food[number], self.C_air[number], P_request_perRF, dt, self.elementOnB[number], self.elementOn[number], self.lockonB[number], self.lockoffB[number], self.lockon[number], self.lockoff[number], self.cycle_off_base[number], self.cycle_on_base[number], self.cycle_off_grid[number], self.cycle_on_grid[number]) P_req = P_req - response.Eservice if P_req >= 0: # all the service request has been met P_req = 0 elif P_req>0 and self.IsAvailableShed[number] > 0 : # For step >=1, can use last step temperature... response = rfdg.FRIDGE(TairLastB, TfoodLastB, TcaseLastB, TairLast, TfoodLast, TcaseLast, TsetLast, self.Tamb[number][self.step], self.R_case[number], self.R_food[number], self.R_infil[number], self.C_case[number], self.C_food[number], self.C_air[number], P_request_perRF, dt, self.elementOnB[number], self.elementOn[number], self.lockonB[number], self.lockoffB[number], self.lockon[number], self.lockoff[number], self.cycle_off_base[number], self.cycle_on_base[number], self.cycle_off_grid[number], self.cycle_on_grid[number]) P_req = P_req - response.Eservice if P_req <= 0: # all the service request has been met P_req = 0 # break else: response = rfdg.FRIDGE(TairLastB, TfoodLastB, TcaseLastB, TairLast, TfoodLast, TcaseLast, TsetLast, self.Tamb[number][self.step], self.R_case[number], self.R_food[number], self.R_infil[number], self.C_case[number], self.C_food[number], self.C_air[number], 0, dt, self.elementOnB[number], self.elementOn[number], self.lockonB[number], self.lockoffB[number], self.lockon[number], self.lockoff[number], self.cycle_off_base[number], self.cycle_on_base[number], self.cycle_off_grid[number], self.cycle_on_grid[number]) # assign returned parameters to associated lists to be recorded self.TsetInitial[number] = response.Tset self.TairInitialB[number] = response.TairB self.TfoodInitialB[number] = response.TfoodB self.TcaseInitialB[number] = response.TcaseB self.elementOnB[number] = response.ElementOnB self.TairInitial[number] = response.Tair self.TfoodInitial[number] = response.Tfood self.TcaseInitial[number] = response.Tcase self.elementOn[number] = response.ElementOn self.lockonB[number] = response.lockonB self.lockoffB[number] = response.lockoffB self.lockon[number] = response.lockon self.lockoff[number] = response.lockoff self.cycle_off_base[number] = response.cycle_off_base self.cycle_on_base[number] = response.cycle_on_base self.cycle_off_grid[number] = response.cycle_off_grid self.cycle_on_grid[number] = response.cycle_on_grid self.SOC[number] = response.SOC self.SOCb[number] = response.SOC_b self.IsAvailableAdd[number] = response.IsAvailableAdd self.IsAvailableShed[number] = response.IsAvailableShed self.AvailableCapacityAdd[number] = response.AvailableCapacityAdd self.AvailableCapacityShed[number] = response.AvailableCapacityShed self.ServiceCallsAccepted[number] = response.ServiceCallsAccepted self.ServiceProvided[number] = response.Eservice p_togrid += response.Eused # resp.P_togrid_max += response.PusedMax # resp.P_togrid_min += response.PusedMin p_service += response.Eservice #Eused/10 #Eservice p_base += response.Pbase # FleetResponse.sim_step = response.sim_step number += 1 # go to next device if P_req>=0: service_max += response.AvailableCapacityShed # NOTE THIS ASSUMES THE MAX SERVICE IS LOAD SHED else: service_min += response.AvailableCapacityAdd # NOTE THIS ASSUMES THE MIN SERVICE IS LOAD ADD self.step += 1 # Output Fleet Response resp = FleetResponse() # Positive Prequest means reducing power consumption resp.ts = ts resp.sim_step = timedelta(seconds=dt) resp.P_service = [] resp.P_service_max = [] # positive only? resp.P_service_min = [] resp.P_togrid = [] resp.P_togrid_max = [] resp.P_togrid_min = [] resp.P_forecast = [] resp.P_base = [] resp.E = [] resp.C = [] # resp.P_dot_up = resp.P_togrid_max / ServiceRequest.Timestep.seconds resp.P_service = p_service resp.P_service_max = service_max # positive decrease loads resp.P_service_min = service_min # negative increase loasd resp.P_base = -p_base resp.P_togrid = -p_togrid resp.P_togrid_max = -(p_base-service_max) resp.P_togrid_min = -(p_base-service_min) resp.E = 0 resp.C = 0 # response.SOC/(self.numRF) resp.Q_togrid = 'NA' resp.Q_service = 'NA' resp.Q_service_max = 'NA' resp.Q_service_min = 'NA' resp.Q_togrid_min = 'NA' resp.Q_togrid_max = 'NA' resp.Q_dot_up = 'NA' resp.Q_dot_down = 'NA' resp.P_dot_up = 0 resp.P_dot_down = 0 resp.dT_hold_limit = 'NA' resp.T_restore = 'NA' resp.Strike_price = 'NA' resp.SOC_cost = 'NA' # TotalServiceProvidedPerTimeStep[step] = -1.0*self.P_service # per time step for all hvacs -1.0* """ Modify the power and SOC of the different subfeets according to the frequency droop regulation according to IEEE standard """ if self.FW21_Enabled and self.is_autonomous: power_ac = resp.P_service_max p_prev = resp.P_togrid power_fleet = self.frequency_watt(power_ac, p_prev, self.ts, self.location, self.db_UF_subfleet, self.db_OF_subfleet) power_fleet_step, SOC_step = self.update_soc_due_to_frequency_droop(initSOC, power_fleet, dt) self.time = t + dt self.ts = self.ts + timedelta(seconds = dt) # Restart time if it surpasses 24 hours if self.time > 24*3600: self.time = self.time - 24*3600 # Impact Metrics # Update the metrics Ttotal = 0 SOCTotal = 0 self.cycle_basee = np.sum(self.cycle_off_base) self.cycle_basee += np.sum(self.cycle_on_base) self.cycle_grid = np.sum(self.cycle_off_grid) self.cycle_grid += np.sum(self.cycle_on_grid) for numberr in range(self.numRF-1): if self.TairInitial[numberr]>=self.TsetInitial[numberr] + 3: #assume 2F, self.deadband self.unmet_hours += 1*self.sim_step/3600.0 self.ave_TairB = np.average(self.TairInitialB) self.ave_Tair = np.average(self.TairInitial) self.SOCb_metric = np.average(self.SOCb) self.SOC_metric = np.average(self.SOC) self.unmet_hours = self.unmet_hours/self.numRF self.ratio_P_togrid_P_base = resp.P_togrid/(resp.P_base) self.energy_impacts += abs(resp.P_service)*(self.sim_step/3600) return resp