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
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
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
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
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
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
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
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
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
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
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)]
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
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) ]
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)
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.")
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