def run(self, P_req=[0], Q_req=[0], initSoC=50, dt=1):
        P_req = P_req / self.num_of_devices
        Q_req = Q_req / self.num_of_devices

        # error checking
        if initSoC < self.min_soc or initSoC > self.max_soc:
            print('ERROR: initSoC out of range')
            return [[], []]
        elif P_req == []:
            print('ERROR: P_req vector must not be empty')
            return [[], []]
        else:
            self.t = self.t + dt
            response = FleetResponse()
            # pre-define output vectors SoC
            SoC = numpy.zeros(2)
            SoC[0] = initSoC  # initialize SoC
            p_ach = 0
            q_ach = 0

            #  Max ramp rate and aparent powerlimit checking
            if (P_req - self.P_injected) > self.max_ramp_up:
                p_ach = self.max_ramp_up
            elif (P_req - self.P_injected) < self.max_ramp_down:
                p_ach = self.max_ramp_down
            else:
                p_ach = P_req

            if (Q_req - self.Q_injected) > self.max_ramp_up:
                q_ach = self.max_ramp_up
            elif (Q_req - self.Q_injected) < self.max_ramp_down:
                q_ach = self.max_ramp_down
            else:
                q_ach = Q_req

            if p_ach < self.max_power_discharge:
                p_ach = self.max_power_discharge
            if p_ach > self.max_power_charge:
                p_ach = self.max_power_charge
            S_req = float(numpy.sqrt(p_ach**2 + q_ach**2))
            if S_req > self.max_apparent_power:
                q_ach = float(
                    numpy.sqrt(numpy.abs(self.max_apparent_power**2 -
                                         p_ach**2)) * numpy.sign(q_ach))
                S_req = float(numpy.sqrt(p_ach**2 + q_ach**2))
            if p_ach != 0.0:
                if float(numpy.abs(S_req / p_ach)) < self.min_pf:
                    q_ach = float(
                        numpy.sqrt(
                            numpy.abs((p_ach / self.min_pf)**2 - p_ach**2)) *
                        numpy.sign(q_ach))
            # run function for ERM model type
            if self.model_type == 'ERM':

                response.P_injected_max = self.max_power_discharge
                response.Q_injected_max = float(
                    numpy.sqrt(numpy.abs(self.max_apparent_power**2 -
                                         p_ach**2)))

                # Calculate SoC and Power Achieved
                Ppos = min(self.max_power_charge, max(p_ach, 0))
                Pneg = max(self.max_power_discharge, min(p_ach, 0))
                SoC[1] = SoC[0] + float(100) * dt * (
                    Pneg + (Ppos * self.energy_efficiency) +
                    self.self_discharge_power) / self.energy_capacity
                if SoC[1] > self.max_soc:
                    Ppos = (self.energy_capacity * (self.max_soc - SoC[0]) /
                            (float(100) * dt) -
                            self.self_discharge_power) / self.energy_efficiency
                    SoC[1] = self.max_soc
                    if SoC[0] == self.max_soc:
                        Ppos = 0
                if SoC[1] < self.min_soc:
                    Pneg = self.energy_capacity * (self.min_soc - SoC[0]) / (
                        float(100) * dt) - self.self_discharge_power
                    SoC[1] = self.min_soc
                    if SoC[0] == self.min_soc:
                        Pneg = 0

                p_ach = (Ppos + Pneg) * self.num_of_devices
                q_ach = q_ach * self.num_of_devices

                response.P_injected = p_ach
                response.Q_injected = q_ach
                response.P_dot = p_ach - self.P_injected
                response.Q_dot = q_ach - self.Q_injected
                response.P_service = 0
                response.Q_service = 0
                response.P_service_max = 0
                response.Q_service_max = 0
                response.Loss_standby = self.self_discharge_power
                response.Eff_throughput = float(
                    p_ach > 0) * self.energy_efficiency + float(p_ach > 0)

                self.soc = SoC[1]
                return response
            # run function for ERM model type
            elif self.model_type == 'CRM':

                # convert AC power p_ach to DC power pdc
                self.pdc = self.coeff_2 * (p_ach**2) + self.coeff_1 * (
                    p_ach) + self.coeff_0
                # convert DC power pdc to DC current
                """ self.ibat = self.pdc *1000 / self.vbat

                self.pdc = self.ibat * ((self.v1 + self.v2 + self.voc + self.ibat*self.r0) *self.n_cells) *1000

                0 = -self.pdc + (self.v1 + self.v2 + self.voc)*self.n_cells) *1000*self.ibat + self.r0 *self.n_cells*1000* (self.ibat**2) """

                b = ((self.v1 + self.v2 + self.voc) * self.n_cells)
                a = self.r0 * self.n_cells
                c = -self.pdc * 1000
                self.ibat = (-b + numpy.sqrt(b**2 - 4 * a * c)) / (2 * a)

                self.vbat = (self.v1 + self.v2 + self.voc +
                             self.ibat * self.r0) * self.n_cells

                # calculate dynamic voltages
                self.v1 = self.v1 + dt * ((1 / (self.r1 * self.c1)) * self.v1 +
                                          (1 / (self.c1)) * self.ibat)
                self.v2 = self.v2 + dt * ((1 / (self.r2 * self.c2)) * self.v1 +
                                          (1 / (self.c2)) * self.ibat)

                response.P_injected_max = self.max_power_discharge
                response.Q_injected_max = float(
                    numpy.sqrt(numpy.abs(self.max_apparent_power**2 -
                                         p_ach**2)))

                # Calculate SoC and Power Achieved
                Ipos = min(self.max_current_charge, max(self.ibat, 0))
                Ineg = max(self.max_current_discharge, min(self.ibat, 0))
                SoC[1] = SoC[0] + float(100) * dt * (
                    Ineg + (Ipos * self.coulombic_efficiency) +
                    self.self_discharge_current) / self.charge_capacity
                if SoC[1] > self.max_soc:
                    Ipos = (self.charge_capacity * (self.max_soc - SoC[0]) /
                            (float(100) * dt) - self.self_discharge_current
                            ) / self.coulombic_efficiency
                    SoC[1] = self.max_soc
                    if SoC[0] == self.max_soc:
                        Ipos = 0
                    self.pdc = Ipos * self.vbat / 1000
                    if self.coeff_2 != 0:
                        p_ach = (-self.coeff_1 + float(
                            numpy.sqrt(self.coeff_1**2 - 4 * self.coeff_2 *
                                       (self.coeff_0 - self.pdc)))) / (
                                           2 * self.coeff_2)
                    else:
                        p_ach = (self.pdc - self.coeff_0) / self.coeff_1
                if SoC[1] < self.min_soc:
                    Ineg = self.charge_capacity * (self.min_soc - SoC[0]) / (
                        float(100) * dt) - self.self_discharge_current
                    SoC[1] = self.min_soc
                    if SoC[0] == self.min_soc:
                        Ineg = 0
                    self.pdc = Ineg * self.vbat / 1000
                    if self.coeff_2 != 0:
                        p_ach = (-self.coeff_1 + float(
                            numpy.sqrt(self.coeff_1**2 - 4 * self.coeff_2 *
                                       (self.coeff_0 - self.pdc)))) / (
                                           2 * self.coeff_2)
                    else:
                        p_ach = (self.pdc - self.coeff_0) / self.coeff_1

                self.ibat = Ipos + Ineg
                self.soc = SoC[1]
                self.voc_update()

                self.vbat = (self.v1 + self.v2 + self.voc +
                             self.ibat * self.r0) * self.n_cells

                p_ach = p_ach * self.num_of_devices
                q_ach = q_ach * self.num_of_devices

                response.P_injected = p_ach
                response.Q_injected = q_ach
                response.P_dot = p_ach - self.P_injected
                response.Q_dot = q_ach - self.Q_injected
                response.P_service = 0
                response.Q_service = 0
                response.P_service_max = 0
                response.Q_service_max = 0
                response.Loss_standby = self.self_discharge_current * (
                    self.voc)
                response.E = (self.soc -
                              self.min_soc) * self.charge_capacity * self.voc
                response.Eff_throughput = (response.E - self.es) / (p_ach * dt)
                self.es = response.E
                self.vbat = (self.v1 + self.v2 + self.voc +
                             self.ibat * self.r0) * self.n_cells

                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

        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