Ejemplo n.º 1
0
    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
Ejemplo n.º 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

        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
Ejemplo n.º 3
0
    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