def process_request(self, fleet_request): """ The expectation that configuration will have at least the following items :param fleet_request: an instance of FleetRequest :return res: an instance of FleetResponse """ res = FleetResponse() # Dummy values for testing res.P_togrid = 100 res.P_service = 100 res.Q_service = 100 res.Q_togrid = 100 return res
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 fc_model(self, ts, sim_step, Preq, forecast=False, start_time=None): """ :param ts: Request created for current time-step: datetime :param sim_step: Request for simulation time-step: timedelta object :param Preq: Request for current real power request :param forecast: Returns fleet response forecast :param start_time: Request for current real power request :return resp: Fleet response object """ if self.P_tank_ideal <= self.min_charge: pass else: # Create base power profile if isinstance(self.p, ndarray): self.__p_base = sum([ self.p[j] * (self.__inc + 1)**(21 - j) for j in range(22) ]) else: self.__p_base = self.p # Ptogrid: Pbase for None or zero requests since FC is a source if Preq is None or float(Preq) == 0.0: Preq = self.__p_base # Ptogrid: Preq+Pbase for +ve or -ve requests else: Preq += self.__p_base # Compute the power generated by the fleet self.__fc_p_calc(Preq) if self.FW21_Enabled and self.is_autonomous: # all in kW Preq, self.f = self.frequency_watt(p_pre=self.__p_tot_ideal, p_avl=self.fc_Pmax_fleet, p_min=self.fc_Pmin_fleet, ts=ts, start_time=start_time) self.__p_tot_ideal = Preq # Update SOC self.__soc_calc() self.__inc += 1 # Response # Power injected is positive resp = FleetResponse() resp.ts = ts resp.sim_step = sim_step resp.C = 0 resp.dT_hold_limit = 0 resp.E = self.soc_ideal resp.Eff_charge = 1.0 resp.Eff_discharge = self.__eta_ds resp.P_dot_down = 0 resp.P_dot_up = 0 resp.P_togrid = self.__p_tot_ideal resp.P_togrid_max = self.fc_Pmax_fleet resp.P_togrid_min = self.fc_Pmin_fleet resp.P_service = resp.P_togrid - self.__p_base resp.P_service_max = self.fc_Pmax_fleet - self.__p_base resp.P_service_min = self.__p_base - self.fc_Pmin_fleet resp.Q_dot_down = 0 resp.Q_dot_up = 0 resp.Q_service = 0 resp.Q_service_max = 0 resp.Q_service_min = 0 resp.Q_togrid = 0 resp.Q_togrid_max = 0 resp.Q_togrid_min = 0 resp.T_restore = 0 resp.P_base = self.__p_base resp.Q_base = 0 resp.Strike_price = 0 resp.SOC_cost = 0 # Impact metrics if not forecast: self.metrics.append([ str(ts), str(self.__Vr), str(self.__Vr_age), str(self.__ne), str(self.__ne_age), str(self.soc_ideal * 1e2), str(self.soc_age * 1e2), str(self.lka_h2), str(self.__eta_ds * 1e2) ]) # Print Soc every 5 secs. if self.__inc % 5000 == 0: print("Soc:%4.2f%%" % (resp.E * 1e2)) return resp
def Run_Fleet(self, ts, sim_step, P_req, Q_req, return_forecast, WP): # this module aggregates the PV information from a large pool of PV/invertre system # Updates prepares report for system operator based on PV fleet # Breaks down the operation command from system operator to subfleet and device level if P_req == None: P_req = [] if Q_req == None: Q_req = [] def Grid_Param(): from grid_info import GridInfo a = GridInfo('Grid_Info_DATA_2.csv') V = a.get_voltage('XX') f = a.get_frequency('XX') return f, V # pull information about the PV subfleet P_rated = self.p_rated P_min = self.p_min S_max = self.s_max Qmax_Plus = self.qmax_plus Qmax_minus = self.qmax_minus P_up = self.p_ramp_down P_down = self.p_ramp_down Q_up = self.q_ramp_down Q_down = self.q_ramp_down # Create Battery equivalent model (BEM) variables for the subfleets and PV fleet # SubFleetA_NP_C='NA' # SubFleetA_NP_P_grid_max=P_rated*self.SubFleet_NumberOfUnits #Minimum real power for services # SubFleetA_NP_Q_grid_max=Qmax_Plus*self.SubFleet_NumberOfUnits#Maximum reactive power for services # SubFleetA_NP_P_grid_min=P_min*self.SubFleet_NumberOfUnits#Minimum reactive power for services # SubFleetA_NP_Q_grid_min=Qmax_minus*self.SubFleet_NumberOfUnits#Ramp rate real power up # SubFleetA_NP_P_service_max=SubFleetA_NP_P_grid_max-SubFleetA_NP_P_grid_min#Ramp rate real power down # SubFleetA_NP_Q_service_max=SubFleetA_NP_Q_grid_max-SubFleetA_NP_Q_grid_min#Ramp rate reactive power up # SubFleetA_NP_P_service_min=0#Ramp rate reactive power down # SubFleetA_NP_Q_service_min=0 SubFleetA_NP_P_up = P_up SubFleetA_NP_Q_up = Q_up SubFleetA_NP_P_down = P_down SubFleetA_NP_Q_down = Q_down # SubFleetA_NP_e_in='NA' SubFleetA_NP_e_out = [] SubFleetA_NP_S_rating = S_max * self.SubFleet_NumberOfUnits Fleet_PV_NP_C = 'NA' # Fleet_PV_NP_P_grid_max=SubFleetA_NP_P_grid_max#Minimum real power for services # Fleet_PV_NP_Q_grid_max=SubFleetA_NP_Q_grid_max#Maximum reactive power for services # Fleet_PV_NP_P_grid_min=SubFleetA_NP_P_grid_min#Minimum reactive power for services # Fleet_PV_NP_Q_grid_min=SubFleetA_NP_Q_grid_min#Ramp rate real power up # Fleet_PV_NP_P_service_max=SubFleetA_NP_P_service_max#Ramp rate real power down # Fleet_PV_NP_Q_service_max=SubFleetA_NP_Q_service_max#Ramp rate reactive power up # Fleet_PV_NP_P_service_min=0#Ramp rate reactive power down # Fleet_PV_NP_Q_service_min=0 Fleet_PV_NP_P_up = SubFleetA_NP_P_up Fleet_PV_NP_Q_up = SubFleetA_NP_Q_up Fleet_PV_NP_P_down = SubFleetA_NP_P_down Fleet_PV_NP_Q_down = SubFleetA_NP_Q_down Fleet_PV_NP_e_in = 'NA' # Fleet_PV_NP_e_out=[] FleetA_NP_S_rating = SubFleetA_NP_S_rating # break down the command for fleet to command for device Command_to_Device = self.Aggregator_Command( P_req, Q_req, self.SubFleet_NumberOfUnits) # Grid parameters required for autonomous mode of operation #[Time_,P_rec,Q_rec,P_req_,Q_req_,P_MPP,G_rec,T_rec]\ [P_grid,Q_grid,P_service,Q_service,E_t0,c,P_output,Q_output,P_grid_max,Q_grid_max,\ P_grid_min,Q_grid_min,P_service_max,Q_service_max,P_service_min,Q_service_min,del_t_hold,\ t_restore,SP,N_req,Effeciency,sim_step]=self.Device_PV(ts,sim_step,Command_to_Device,return_forecast,WP) #print(P_Output) SubFleetA_P_grid = P_grid * self.SubFleet_NumberOfUnits / 1000 SubFleetA_Q_grid = Q_grid * self.SubFleet_NumberOfUnits / 1000 SubFleetA_P_service = P_service * self.SubFleet_NumberOfUnits / 1000 SubFleetA_Q_service = Q_service * self.SubFleet_NumberOfUnits / 1000 SubFleetA_E_t0 = E_t0 SubFleetA_c = c SubFleetA_P_output = [ x * self.SubFleet_NumberOfUnits / 1000 for x in P_output ] SubFleetA_Q_output = [ x * self.SubFleet_NumberOfUnits / 1000 for x in Q_output ] SubFleetA_P_grid_max = [ x * self.SubFleet_NumberOfUnits / 1000 for x in P_grid_max ] SubFleetA_Q_grid_max = [ x * self.SubFleet_NumberOfUnits / 1000 for x in Q_grid_max ] SubFleetA_P_grid_min = [ x * self.SubFleet_NumberOfUnits / 1000 for x in P_grid_min ] SubFleetA_Q_grid_min = [ x * self.SubFleet_NumberOfUnits / 1000 for x in Q_grid_min ] SubFleetA_P_service_max = [ x * self.SubFleet_NumberOfUnits / 1000 for x in P_service_max ] SubFleetA_Q_service_max = [ x * self.SubFleet_NumberOfUnits / 1000 for x in Q_service_max ] SubFleetA_P_service_min = [ x * self.SubFleet_NumberOfUnits / 1000 for x in P_service_min ] SubFleetA_Q_service_min = [ x * self.SubFleet_NumberOfUnits / 1000 for x in Q_service_min ] SubFleetA_del_t_hold = del_t_hold SubFleetA_t_restore = t_restore SubFleetA_SP = SP SubFleetA_N_req = N_req SubFleetA_NP_e_out = Effeciency # Calculate information about Subfleets # Calculate information about Device Fleet: PV # Calculate information about Subfleets Fleet_PV_P_grid = SubFleetA_P_grid Fleet_PV_Q_grid = SubFleetA_Q_grid Fleet_PV_P_service = SubFleetA_P_service Fleet_PV_Q_service = SubFleetA_Q_service Fleet_PV_E_t0 = SubFleetA_E_t0 # Fleet_PV_c=SubFleetA_c # # Fleet_PV_P_output=SubFleetA_P_output # Fleet_PV_Q_output=SubFleetA_Q_output Fleet_PV_P_grid_max = SubFleetA_P_grid_max Fleet_PV_Q_grid_max = SubFleetA_Q_grid_max Fleet_PV_P_grid_min = SubFleetA_P_grid_min Fleet_PV_Q_grid_min = SubFleetA_Q_grid_min Fleet_PV_P_service_max = SubFleetA_P_service_max Fleet_PV_Q_service_max = SubFleetA_Q_service_max Fleet_PV_P_service_min = SubFleetA_P_service_min Fleet_PV_Q_service_min = SubFleetA_Q_service_min Fleet_PV_del_t_hold = SubFleetA_del_t_hold Fleet_PV_t_restore = SubFleetA_t_restore # Fleet_PV_SP=SubFleetA_SP # Fleet_PV_N_req=SubFleetA_N_req response = FleetResponse() response.ts = ts response.C = Fleet_PV_NP_C response.dT_hold_limit = Fleet_PV_del_t_hold response.E = Fleet_PV_E_t0 response.Eff_charge = Fleet_PV_NP_e_in response.Eff_discharge = SubFleetA_NP_e_out response.P_dot_down = Fleet_PV_NP_P_down response.P_dot_up = Fleet_PV_NP_P_up response.P_service = Fleet_PV_P_service response.P_service_max = Fleet_PV_P_service_max response.P_service_min = Fleet_PV_P_service_min response.P_togrid = Fleet_PV_P_grid response.P_togrid_max = Fleet_PV_P_grid_max[0] response.P_togrid_min = Fleet_PV_P_grid_min[0] response.Q_dot_down = Fleet_PV_NP_Q_down response.Q_dot_up = Fleet_PV_NP_Q_up response.Q_service = Fleet_PV_Q_service response.Q_service_max = Fleet_PV_Q_service_max response.Q_service_min = Fleet_PV_Q_service_min response.Q_togrid = Fleet_PV_Q_grid response.Q_togrid_max = Fleet_PV_Q_grid_max[0] response.Q_togrid_min = Fleet_PV_Q_grid_min[0] response.S_Rating = FleetA_NP_S_rating response.T_restore = Fleet_PV_t_restore response.P_base = Fleet_PV_P_grid_max[0] response.sim_step = sim_step response.Strike_price = 0 response.SOC_cost = 'na' self.energy_impacts += abs( response.P_service) * (int(sim_step.total_seconds()) / 3600) return response
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