Пример #1
0
    def constraints(self, mask, load_sum, tot_variable_gen, generator_out_sum,
                    net_ess_power, combined_rating):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                    in the subs data set
            tot_variable_gen (Expression): the sum of the variable/intermittent generation sources
            load_sum (list, Expression): the sum of load within the system
            generator_out_sum (list, Expression): the sum of conventional generation within the system
            net_ess_power (list, Expression): the sum of the net power of all the ESS in the system. flow out into the grid is negative
            combined_rating (Dictionary): the combined rating of each DER class type

        Returns:
            An empty list (for aggregation of later constraints)
        """
        constraint_list = super().constraints(mask, load_sum, tot_variable_gen,
                                              generator_out_sum, net_ess_power,
                                              combined_rating)
        # add time series service participation constraint, if called for
        #   Max and Min will constrain the sum of ch_less and dis_more
        if self.ts_constraints:
            constraint_list += \
                [cvx.NonPos(self.variables['ch_less'] +
                            self.variables['dis_more'] - self.max.loc[mask])]
            constraint_list += \
                [cvx.NonPos(-self.variables['ch_less'] -
                            self.variables['dis_more'] + self.min.loc[mask])]

        return constraint_list
Пример #2
0
    def constraints(self, mask):
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set

        Returns:
            A list of constraints that corresponds the generator's physical constraints and its service constraints
        """
        # parent constraints
        parent_constraints = super().constraints(mask)
        # drop the last constraint from the parent class when sizing
        constraint_list = parent_constraints[:-1]
        if not self.being_sized():
            # add the last constraint from the parent class
            constraint_list += [parent_constraints[-1]]
        else:
            power_out = self.variables_dict['elec']
            on = self.variables_dict['on']
            # cover the constraint that was removed
            if self.max_rated_power:
                constraint_list += [
                    cvx.NonPos(power_out - self.max_rated_power * self.n * on)
                ]
            constraint_list += [
                cvx.NonPos(power_out - self.discharge_capacity())
            ]

        constraint_list += self.size_constraints
        return constraint_list
Пример #3
0
    def objective_constraints(self,
                              variables,
                              mask,
                              reservations,
                              mpc_ene=None):
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            variables (Dict): Dictionary of variables being optimized
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set
            reservations (Dict): Dictionary of energy and power reservations required by the services being
                preformed with the current optimization subset
            mpc_ene (float): value of energy at end of last opt step (for mpc opt)

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """
        constraint_list = []
        ice_gen = variables['ice_gen']
        on_ice = variables['on_ice']

        constraint_list += [
            cvx.NonPos(cvx.multiply(self.p_min, on_ice) - ice_gen)
        ]
        constraint_list += [
            cvx.NonPos(ice_gen -
                       cvx.multiply(self.rated_power * self.n, on_ice))
        ]

        return constraint_list
Пример #4
0
    def objective_constraints(self,
                              variables,
                              mask,
                              reservations,
                              generation,
                              mpc_ene=None):
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            variables (Dict): Dictionary of variables being optimized
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set
            reservations (Dict): Dictionary of energy and power reservations required by the services being
                preformed with the current optimization subset
            generation (list, Expression): the sum of generation within the system for the subset of time
                being optimized
            mpc_ene (float): value of energy at end of last opt step (for mpc opt)

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """

        constraint_list = []
        if self.no_export:
            constraint_list += [
                cvx.NonPos(variables['dis'] - variables['ch'] + generation -
                           self.total_load(mask))
            ]
        if self.no_import:
            constraint_list += [
                cvx.NonPos(-variables['dis'] + variables['ch'] - generation +
                           self.total_load(mask))
            ]
        return constraint_list
Пример #5
0
    def objective_constraints(self, variables, subs, generation, reservations=None):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            variables (Dict): dictionary of variables being optimized
            subs (DataFrame): Subset of time_series data that is being optimized
            generation (list, Expression): the sum of generation within the system for the subset of time
                being optimized
                reservations (Dict): power reservations from dispatch services

        Returns:
            constraint_list (list): list of constraints

        """
        constraint_list = []
        constraint_list += [cvx.NonPos(-variables['regu_c'])]
        constraint_list += [cvx.NonPos(-variables['regd_c'])]
        constraint_list += [cvx.NonPos(-variables['regu_d'])]
        constraint_list += [cvx.NonPos(-variables['regd_d'])]
        # p = opt_vars['dis'] - opt_vars['ch']
        # constraint_list += [cvx.NonPos(opt_vars['regd_d'] - cvx.pos(p))]
        # constraint_list += [cvx.NonPos(opt_vars['regu_c'] - cvx.neg(p))]
        if self.combined_market:
            constraint_list += [cvx.Zero(variables['regd_d'] + variables['regd_c'] - variables['regu_d'] - variables['regu_c'])]

        return constraint_list
Пример #6
0
    def constraints(self, mask):
        constraint_list = super().constraints(mask)
        elec = self.variables_dict['elec']
        steam = self.variables_dict['steam']
        hotwater = self.variables_dict['hotwater']

        # electric energy and heat (steam + hotwater) energy generated are proportional
        #   and defined by electric_heat_ratio
        constraint_list += [
            cvx.Zero(elec - self.electric_heat_ratio * (steam + hotwater))
        ]

        # to ensure that CHP never produces more steam than it can (no excess steam)
        if not self.steam_only and not self.hotwater_only:
            constraint_list += [
                cvx.NonPos(steam - self.max_steam_ratio * hotwater)
            ]

        # to ensure that the upper limit on CHP size in the size optimization
        #     will be the smallest system that can meet both howater and steam loads
        #     use smallest_size_system_needed()
        if self.being_sized() and self.site_thermal_load_exists:
            constraint_list += [
                cvx.NonPos(elec - self.smallest_size_system_needed())
            ]

        return constraint_list
Пример #7
0
    def constraints(self, mask):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                    in the subs data set

        Returns:
            A list of constraints that corresponds the EV requirement to collect the required energy to operate. It also allows
            flexibility to provide other grid services
        """
        constraint_list = []

        # optimization variables

        ch = self.variables_dict['ch']
        # uch = self.variables_dict['uch']

        # constraints on the ch/dis power
        constraint_list += [cvx.NonPos(ch - self.EV_load_TS[mask].values)]
        constraint_list += [
            cvx.NonPos((1 - self.max_load_ctrl) *
                       self.EV_load_TS[mask].values - ch)
        ]

        # the constraint below limits energy throughput and total discharge to less than or equal to
        # (number of cycles * energy capacity) per day, for technology warranty purposes
        # this constraint only applies when optimization window is equal to or greater than 24 hours

        return constraint_list
Пример #8
0
    def constraints(self, mask, load_sum, tot_variable_gen, generator_out_sum,
                    net_ess_power, combined_rating):
        """build constraint list method for the optimization engine

        Args:
            mask (DataFrame): A boolean array that is true for indices
                corresponding to time_series data included in the subs data set
            tot_variable_gen (Expression): the sum of the variable/intermittent
                generation sources
            load_sum (list, Expression): the sum of load within the system
            generator_out_sum (list, Expression): the sum of conventional
                generation within the system
            net_ess_power (list, Expression): the sum of the net power of all
                the ESS in the system. flow out into the grid is negative
            combined_rating (Dictionary): the combined rating of each DER class
                type

        Returns:
            An list of constraints for the optimization variables added to
            the system of equations
        """
        constraint_list = []
        constraint_list += [cvx.NonPos(-self.variables['up_ch'])]
        constraint_list += [cvx.NonPos(-self.variables['down_ch'])]
        constraint_list += [cvx.NonPos(-self.variables['up_dis'])]
        constraint_list += [cvx.NonPos(-self.variables['down_dis'])]
        if self.combined_market:
            constraint_list += [
                cvx.Zero(self.variables['down_dis'] +
                         self.variables['down_ch'] - self.variables['up_dis'] -
                         self.variables['up_ch'])
            ]

        return constraint_list
Пример #9
0
    def set_size(self, value_streams, start_year):
        """ part of Deferral's sizing module: TODO USE THIS INSTEAD OF set_size IN MICROGRID SERVICE AGGREGATOR
        iterates over a list of DER+DERExtension objects and sets their minimum size
        based on the P and E requirements set by MIN_YEAR objective.

        Args:
            value_streams:
            start_year:

        Returns: der_list with size minimums

        """
        deferral = value_streams.get('Deferral')
        min_year = deferral.min_years
        last_year_to_defer = start_year.year + min_year - 1
        p_e_req = deferral.deferral_df.loc[last_year_to_defer, :]
        min_power = p_e_req.loc['Power Capacity Requirement (kW)']
        min_energy = p_e_req.loc['Energy Capacity Requirement (kWh)']
        ess_inst = self.der_list[0]
        if len(value_streams.keys()) > 1:
            ess_inst.size_constraints += [
                cvx.NonPos(min_energy - ess_inst.ene_max_rated)
            ]
            ess_inst.size_constraints += [
                cvx.NonPos(min_power - ess_inst.ch_max_rated)
            ]
            ess_inst.size_constraints += [
                cvx.NonPos(min_power - ess_inst.dis_max_rated)
            ]
        else:
            ess_inst.ch_max_rated = min_power
            ess_inst.dis_max_rated = min_power
            ess_inst.ene_max_rated = min_energy
Пример #10
0
    def objective_constraints(self,
                              variables,
                              mask,
                              load,
                              generation,
                              reservations=None):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            variables (Dict): dictionary of variables being optimized
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set
            load (list, Expression): the sum of load within the system
            generation (list, Expression): the sum of generation within the system for the subset of time
                being optimized
            reservations (Dict): power reservations from dispatch services

        Returns:
            constraint_list (list): list of constraints

        """
        constraint_list = []
        constraint_list += [cvx.NonPos(-variables['sr_c'])]
        constraint_list += [cvx.NonPos(-variables['sr_d'])]
        return constraint_list
Пример #11
0
    def __init__(self, params):
        """ Initialize all technology with the following attributes.

        Args:
            params (dict): Dict of parameters for initialization
        """
        TellUser.debug(f"Initializing {__name__}")
        PVSystem.PV.__init__(self, params)
        DERExtension.__init__(self, params)
        ContinuousSizing.__init__(self, params)

        self.nu = params['nu'] / 100
        self.gamma = params['gamma'] / 100
        self.curtail = params['curtail']
        self.max_rated_capacity = params['max_rated_capacity']
        self.min_rated_capacity = params['min_rated_capacity']
        self.ppa = params['PPA']
        self.ppa_cost = params['PPA_cost']
        self.ppa_inflation = params['PPA_inflation_rate'] / 100

        if not self.rated_capacity:
            self.rated_capacity = cvx.Variable(name=f'{self.name}rating', integer=True)
            self.inv_max = self.rated_capacity
            self.size_constraints += [cvx.NonPos(-self.rated_capacity)]
            if self.min_rated_capacity:
                self.size_constraints += [cvx.NonPos(self.min_rated_capacity - self.rated_capacity)]
            if self.max_rated_capacity:
                self.size_constraints += [cvx.NonPos(self.rated_capacity - self.max_rated_capacity)]
Пример #12
0
    def set_size(self, der_lst, start_year):
        """ part of Deferral's sizing module: TODO REPLACE WITH set_size IN MICROGRID POI
        iterates over a list of DER+DERExtension objects and sets their minimum size
        based on the P and E requirements set by MIN_YEAR objective.

        Args:
            der_lst:
            start_year:

        Returns: der_list with size minimums

        """
        deferral = self.value_streams.get('Deferral')
        min_year = deferral.min_years
        last_year_to_defer = start_year.year + min_year - 1
        p_e_req = deferral.deferral_df.loc[last_year_to_defer, :]
        min_power = p_e_req.loc['Power Capacity Requirement (kW)']
        min_energy = p_e_req.loc['Energy Capacity Requirement (kWh)']
        if len(self.value_streams.keys()) > 1:
            der_lst[0].size_constraints += [
                cvx.NonPos(min_energy - der_lst[0].ene_max_rated)
            ]
            der_lst[0].size_constraints += [
                cvx.NonPos(min_power - der_lst[0].ch_max_rated)
            ]
            der_lst[0].size_constraints += [
                cvx.NonPos(min_power - der_lst[0].dis_max_rated)
            ]
        else:
            der_lst[0].ch_max_rated = min_power
            der_lst[0].dis_max_rated = min_power
            der_lst[0].ene_max_rated = min_energy
        return der_lst
Пример #13
0
    def objective_constraints(self,
                              variables,
                              mask,
                              load,
                              generation,
                              reservations=None):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            variables (Dict): dictionary of variables being optimized
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set
            load (list, Expression): the sum of load within the system
            generation (list, Expression): the sum of generation within the system for the subset of time
                being optimized
                reservations (Dict): power reservations from dispatch services

        Returns:
            An list of constraints to be included for deferral

        # TODO: consider verifying timesteps are in sequential order before just taking the values of the Series --HN
        """

        # adding constraints to ensure power dispatch does not violate thermal limits of transformer deferred
        # only include them if deferral is not going to fail
        constraints = []
        year_of_optimization = mask.loc[mask].index.year[-1]
        print(str(year_of_optimization)) if self.verbose else None
        if year_of_optimization < self.year_failed:
            print('adding constraint') if self.verbose else None
            # optimization variables
            dis = variables['dis']
            ch = variables['ch']

            net_battery = dis - ch

            tot_load_deferred = load + self.load.loc[mask].values

            # -(max export) >= dis - ch + generation - deferral load
            constraints += [
                cvx.NonPos(self.max_export + generation - tot_load_deferred +
                           net_battery)
            ]

            # max import >= loads - (dis - ch) - generation
            constraints += [
                cvx.NonPos(-generation + tot_load_deferred - net_battery -
                           self.max_import)
            ]

            # # make sure power does doesn't go above the inverter constraints during dispatch service activity
            # constraints += [cvx.NonPos(self.max_export - load_tot + net_battery + generation + reservations['D_max'] + reservations['C_min'])]
            # constraints += [cvx.NonPos(load_tot - net_battery - generation - reservations['C_max'] - reservations['D_min'] - self.max_import)]

        return constraints
Пример #14
0
    def constraints(self, mask, **kwargs):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                    in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """
        constraint_list = []
        if self.duration:
            power = self.variables_dict[
                'power']  # p_t = charge_t - discharge_t
            energy = self.variables_dict['ene_load']
            uene = self.variables_dict['uene']
            udis = self.variables_dict['udis']
            uch = self.variables_dict['uch']

            # constraints that keep the variables inside their limits
            constraint_list += [cvx.NonPos(power - self.rated_power)]
            constraint_list += [cvx.NonPos(-self.rated_power - power)]
            constraint_list += [cvx.NonPos(-energy)]
            constraint_list += [
                cvx.NonPos(energy - self.operational_max_energy())
            ]
            # uene accounts for change in energy due to participating in sub timestep scale markets
            constraint_list += [
                cvx.Zero(uene + (self.dt * udis) - (self.dt * uch))
            ]

            sub = mask.loc[mask]
            for day in sub.index.dayofyear.unique():
                day_mask = (day == sub.index.dayofyear)
                # general:  e_{t+1} = e_t + (charge_t - discharge_t) * dt = e_t + power_t * dt
                constraint_list += [
                    cvx.Zero(energy[day_mask][:-1] +
                             (power[day_mask][:-1] * self.dt) -
                             energy[day_mask][1:])
                ]
                # start of first timestep of the day
                constraint_list += [
                    cvx.Zero(energy[day_mask][0] -
                             self.operational_max_energy())
                ]
                # end of the last timestep of the day
                constraint_list += [
                    cvx.Zero(energy[day_mask][-1] +
                             (power[day_mask][-1] * self.dt) -
                             self.operational_max_energy())
                ]

        return constraint_list
Пример #15
0
    def constraints(self, mask, load_sum, tot_variable_gen, generator_out_sum,
                    net_ess_power, combined_rating):
        """build constraint list method for the optimization engine

        Args:
            mask (DataFrame): A boolean array that is true for indices
                corresponding to time_series data included in the subs data set
            tot_variable_gen (Expression): the sum of the variable/intermittent
                generation sources
            load_sum (list, Expression): the sum of load within the system
            generator_out_sum (list, Expression): the sum of conventional
                generation within the system
            net_ess_power (list, Expression): the sum of the net power of all
                the ESS in the system. flow out into the grid is negative
            combined_rating (Dictionary): the combined rating of each DER class
                type

        Returns:
            An list of constraints for the optimization variables added to
            the system of equations
        """
        constraint_list = super().constraints(mask, load_sum, tot_variable_gen,
                                              generator_out_sum, net_ess_power,
                                              combined_rating)
        # add time series service participation constraints, if called for
        #   Reg Up Max and Reg Up Min will constrain the sum of up_ch + up_dis
        if self.u_ts_constraints:
            constraint_list += [
                cvx.NonPos(self.variables['up_ch'] + self.variables['up_dis'] -
                           self.regu_max.loc[mask])
            ]
            constraint_list += [
                cvx.NonPos((-1) * self.variables['up_ch'] +
                           (-1) * self.variables['up_dis'] +
                           self.regu_min.loc[mask])
            ]
        #   Reg Down Max and Reg Down Min will constrain the sum down_ch+down_dis
        if self.d_ts_constraints:
            constraint_list += [
                cvx.NonPos(self.variables['down_ch'] +
                           self.variables['down_dis'] -
                           self.regd_max.loc[mask])
            ]
            constraint_list += [
                cvx.NonPos(-self.variables['down_ch'] -
                           self.variables['down_dis'] +
                           self.regd_min.loc[mask])
            ]

        return constraint_list
Пример #16
0
    def size_for_outages(self, opt_index, outage_start_indices, der_list):
        """ Sets up sizing optimization.

        Args:
            opt_index (Index): index should match the index of the timeseries
                data being passed around
            der_list (list): list of initialized DERs from the POI class
            outage_start_indices

        Returns: modified DER list

        """

        consts = []
        cost_funcs = sum(
            [der_instance.get_capex() for der_instance in der_list])
        outage_length = int(self.outage_duration / self.dt)

        mask = pd.Series(index=opt_index)
        for outage_ind in outage_start_indices:
            mask.iloc[:] = False
            mask.iloc[outage_ind:(outage_ind + outage_length)] = True
            # set up variables
            gen_sum = cvx.Parameter(value=np.zeros(outage_length),
                                    shape=outage_length,
                                    name='POI-Zero')
            tot_net_ess = cvx.Parameter(value=np.zeros(outage_length),
                                        shape=outage_length,
                                        name='POI-Zero')

            for der_instance in der_list:
                # initialize variables
                der_instance.initialize_variables(outage_length)
                consts += der_instance.constraints(mask,
                                                   sizing_for_rel=True,
                                                   find_min_soe=False)
                if der_instance.technology_type == 'Energy Storage System':
                    tot_net_ess += der_instance.get_net_power(mask)
                if der_instance.technology_type == 'Generator':
                    gen_sum += der_instance.get_discharge(mask)
                if der_instance.technology_type == 'Intermittent Resource':
                    gen_sum += der_instance.get_discharge(mask) * \
                               der_instance.nu
            critical_load = self.critical_load.loc[mask].values
            if self.load_shed:
                critical_load = critical_load * (
                    self.load_shed_data[0:outage_length].values / 100)

            critical_load_arr = cvx.Parameter(value=critical_load,
                                              shape=outage_length)
            consts += [
                cvx.NonPos(tot_net_ess + (-1) * gen_sum + critical_load_arr)
            ]

        obj = cvx.Minimize(cost_funcs)
        prob = cvx.Problem(obj, consts)
        prob.solve(solver=cvx.GLPK_MI)

        return der_list
Пример #17
0
    def constraints(self, mask, **kwargs):
        constraint_list = super().constraints(mask)
        cold = self.variables_dict['cold']

        # limit the cold power of the chiller to at most its rated power
        constraint_list += [cvx.NonPos(cold - self.rated_power)]

        constraint_list += self.size_constraints
        return constraint_list
Пример #18
0
    def objective_constraints(self, variables, subs, generation, reservations=None):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            variables (Dict): dictionary of variables being optimized
            subs (DataFrame): Subset of time_series data that is being optimized
            generation (list, Expression): the sum of generation within the system for the subset of time
                being optimized
                reservations (Dict): power reservations from dispatch services

        Returns:

        """
        constraint_list = []
        constraint_list += [cvx.NonPos(-variables['nsr_c'])]
        constraint_list += [cvx.NonPos(-variables['nsr_d'])]
        constraint_list += [cvx.NonPos(variables['nsr_d'] - self.dis_power)]
        return constraint_list
Пример #19
0
    def constraints(self, mask):
        # NOTE:  size constraints are handled here
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """
        constraint_list = []

        if self.being_sized():

            constraint_list += [cvx.NonPos(self.n_min - self.n)]
            constraint_list += [cvx.NonPos(self.n - self.n_max)]

        return constraint_list
Пример #20
0
    def constraints(self, mask, **kwargs):
        constraint_list = super().constraints(mask)
        steam = self.variables_dict['steam']
        hotwater = self.variables_dict['hotwater']

        # limit the heating power of the Boiler to at most its rated power
        constraint_list += [cvx.NonPos(steam + hotwater - self.rated_power)]

        constraint_list += self.size_constraints
        return constraint_list
Пример #21
0
    def constraints(self, mask, load_sum, tot_variable_gen, generator_out_sum,
                    net_ess_power, combined_rating):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                    in the subs data set
            tot_variable_gen (Expression): the sum of the variable/intermittent generation sources
            load_sum (list, Expression): the sum of load within the system
            generator_out_sum (list, Expression): the sum of conventional generation within the system
            net_ess_power (list, Expression): the sum of the net power of all the ESS in the system. [= charge - discharge]
            combined_rating (Dictionary): the combined rating of each DER class type

        Returns:
            An empty list (for aggregation of later constraints)
        """
        # adding constraints to ensure power dispatch does not violate thermal limits of transformer deferred
        # only include them if deferral is not going to fail
        constraints = []
        year_of_optimization = mask.loc[mask].index.year[-1]
        if year_of_optimization < self.year_failed:
            load_beyond_poi = cvx.Parameter(value=self.load.loc[mask].values,
                                            name='deferral_load',
                                            shape=sum(mask))
            # -(max export) >= dis - ch + generation - loads
            constraints += [
                cvx.NonPos(self.max_export - load_sum - load_beyond_poi +
                           (-1) * net_ess_power + generator_out_sum +
                           tot_variable_gen)
            ]
            # max import >= loads - (dis - ch) - generation
            constraints += [
                cvx.NonPos(load_sum + load_beyond_poi + net_ess_power +
                           (-1) * generator_out_sum + (-1) * tot_variable_gen -
                           self.max_import)
            ]
            # TODO make sure power does doesn't violate the constraints during dispatch service activity
        else:
            TellUser.debug(
                f"{self.name} did not add any constraints to our system of equations"
            )

        return constraints
Пример #22
0
    def constraints(self, mask, **kwargs):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                    in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """
        constraint_list = []

        if self.loc == 'ac':
            constraint_list += [cvx.NonPos(self.get_discharge(mask) - self.inv_max)]
            constraint_list += [cvx.NonPos(- self.inv_max - self.get_discharge(mask))]
        if self.curtail:
            constraint_list += [cvx.NonPos(self.get_discharge(mask) - self.maximum_generation(mask))]

        return constraint_list
Пример #23
0
    def constraints(self, mask):
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """
        constraint_list = []
        elec = self.variables_dict['elec']
        on = self.variables_dict['on']

        constraint_list += [cvx.NonPos((on * self.p_min) - elec)]
        constraint_list += [
            cvx.NonPos(elec - (on * self.rated_power * self.n))
        ]

        return constraint_list
Пример #24
0
    def constraints(self, mask, **kwargs):
        """ Builds the master constraint list for the subset of timeseries data being optimized.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series data included
                in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical constraints and its service constraints
        """

        constraint_list = super().constraints(mask, **kwargs)
        constraint_list += self.size_constraints
        if self.incl_energy_limits:
            # add timeseries energy limits on this instance
            ene = self.variables_dict['ene']
            if self.limit_energy_max is not None:
                energy_max = cvx.Parameter(
                    value=self.limit_energy_max.loc[mask].values,
                    shape=sum(mask),
                    name='ts_energy_max')
                constraint_list += [cvx.NonPos(ene - energy_max)]
            if self.limit_energy_min is not None:
                energy_min = cvx.Parameter(
                    value=self.limit_energy_min.loc[mask].values,
                    shape=sum(mask),
                    name='ts_energy_min')
                constraint_list += [cvx.NonPos(energy_min - ene)]
        if self.incl_charge_limits:
            # add timeseries energy limits on this instance
            charge = self.variables_dict['ch']
            if self.limit_charge_max is not None:
                charge_max = cvx.Parameter(
                    value=self.limit_charge_max.loc[mask].values,
                    shape=sum(mask),
                    name='ts_charge_max')
                constraint_list += [cvx.NonPos(charge - charge_max)]
            if self.limit_charge_min is not None:
                charge_min = cvx.Parameter(
                    value=self.limit_charge_min.loc[mask].values,
                    shape=sum(mask),
                    name='ts_charge_min')
                constraint_list += [cvx.NonPos(charge_min - charge)]
        if self.incl_discharge_limits:
            # add timeseries energy limits on this instance
            discharge = self.variables_dict['dis']
            if self.limit_discharge_max is not None:
                discharge_max = cvx.Parameter(
                    value=self.limit_discharge_max.loc[mask].values,
                    shape=sum(mask),
                    name='ts_discharge_max')
                constraint_list += [cvx.NonPos(discharge - discharge_max)]
            if self.limit_discharge_min is not None:
                discharge_min = cvx.Parameter(
                    value=self.limit_discharge_min.loc[mask].values,
                    shape=sum(mask),
                    name='ts_discharge_min')
                constraint_list += [cvx.NonPos(discharge_min - discharge)]
        return constraint_list
Пример #25
0
    def constraints(self, mask, load_sum, tot_variable_gen, generator_out_sum,
                    net_ess_power, combined_rating):
        """Default build constraint list method. Used by services that do not have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices corresponding to time_series
                data included in the subs data set
            tot_variable_gen (Expression): the sum of the variable/intermittent generation sources
            load_sum (list, Expression): the sum of load within the system
            generator_out_sum (list, Expression): the sum of conventional generation within
                the system
            net_ess_power (list, Expression): the sum of the net power of all the ESS in the
                system. flow out into the grid is negative
            combined_rating (Dictionary): the combined rating of each DER class type

        Returns:
            constraint_list (list): list of constraints

        """
        constraint_list = []
        constraint_list += [cvx.NonPos(-self.variables['ch_less'])]
        constraint_list += [cvx.NonPos(-self.variables['dis_more'])]
        return constraint_list
Пример #26
0
    def test_nonpos(self) -> None:
        """Tests the NonPos constraint for correctness.
        """
        n = 3
        x = cp.Variable(n)
        c = np.arange(n)
        prob = cp.Problem(cp.Maximize(cp.sum(x)), [cp.NonPos(x - c)])
        # Solve through cone program path.
        prob.solve(solver=cp.ECOS)
        self.assertItemsAlmostEqual(x.value, c)

        # Solve through QP path.
        prob.solve(solver=cp.OSQP)
        self.assertItemsAlmostEqual(x.value, c)
Пример #27
0
    def __init__(self, params):
        """ Initialize all technology with the following attributes.

        Args:
            params (dict): Dict of parameters for initialization
        """
        TellUser.debug(f"Initializing {__name__}")
        RotatingGenerator.__init__(self, params)
        DERExtension.__init__(self, params)
        ContinuousSizing.__init__(self, params)
        self.max_rated_power = params['max_rated_capacity']
        self.min_rated_power = params['min_rated_capacity']
        if not self.rated_power:
            self.rated_power = cvx.Variable(integer=True,
                                            name=f'{self.name} rating')
            self.size_constraints += [cvx.NonPos(-self.rated_power)]
            if self.min_rated_power:
                self.size_constraints += [
                    cvx.NonPos(self.min_rated_power - self.rated_power)
                ]
            if self.max_rated_power:
                self.size_constraints += [
                    cvx.NonPos(self.rated_power - self.max_rated_power)
                ]
Пример #28
0
    def test_nonpos_dual(self) -> None:
        """Test dual variables work for NonPos.
        """
        n = 3
        x = cp.Variable(n)
        c = np.arange(n)
        prob = cp.Problem(cp.Maximize(cp.sum(x)), [(x - c) <= 0])
        prob.solve(solver=cp.ECOS)
        dual = prob.constraints[0].dual_value
        prob = cp.Problem(cp.Maximize(cp.sum(x)), [cp.NonPos(x - c)])
        # Solve through cone program path.
        prob.solve(solver=cp.ECOS)
        self.assertItemsAlmostEqual(prob.constraints[0].dual_value, dual)

        # Solve through QP path.
        prob.solve(solver=cp.OSQP)
        self.assertItemsAlmostEqual(prob.constraints[0].dual_value, dual)
Пример #29
0
    def __init__(self, params):
        """ Initializes a battery class that inherits from the technology class.
        It sets the type and physical constraints of the technology.

        Args:
            params (dict): params dictionary from dataframe for one case
        """
        TellUser.debug(f"Initializing {__name__}")
        super().__init__(params)  # BatteryTech.Battery->ESSizing->EnergyStorage->DER->Sizing
        self.user_duration = params['duration_max']
        self.state_of_health = params['state_of_health'] / 100
        self.years_system_degraded = set()
        self.yearly_degradation_report = pd.DataFrame()
        self.actual_time_to_replacement = None  # set by degredation module

        if self.user_duration:
            if self.being_sized():
                self.size_constraints += [cvx.NonPos(self.ene_max_rated - self.user_duration*self.dis_max_rated)]
            else:
                TellUser.warning(f"Ignoring {self.tag}-{self.name} energy storage size duration maximum (duration_max={self.user_duration}) because you are not having DER-VET size the battery. Set it to 0 to abstain from applying.")
Пример #30
0
    def constraints(self, mask, **kwargs):
        """Default build constraint list method. Used by services that do not
        have constraints.

        Args:
            mask (DataFrame): A boolean array that is true for indices
                corresponding to time_series data included in the subs data set

        Returns:
            A list of constraints that corresponds the battery's physical
                constraints and its service constraints
        """
        # create default list of constraints
        constraint_list = super().constraints(mask, **kwargs)
        if self.incl_binary:
            # battery can not charge and discharge in the same timestep
            constraint_list += [
                cvx.NonPos(self.variables_dict['on_c'] +
                           self.variables_dict['on_d'] - 1)
            ]

        return constraint_list