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
Exemple #2
0
    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