def optimize(self, el_price, cost, grid_num): coeff = self.coefficents_linear_model(grid_num) costs = pd.read_csv(cost + '.csv', sep=",", index_col=0).astype(np.float64) seq = pd.read_csv(el_price + '.csv', index_col=0).astype(np.float64) m = po.ConcreteModel() m.T = po.Set(initialize=seq.index.values) m.cmp_P_max = po.Param(initialize=self.P_cmp) m.cmp_P_min = po.Param(initialize=self.P_cmp * 0.5) m.cmp_a = po.Param(initialize=coeff['cmp_a']) m.cmp_b = po.Param(initialize=coeff['cmp_b']) m.cmp_c = po.Param(initialize=coeff['cmp_c']) m.cmp_d = po.Param(initialize=coeff['cmp_d']) m.cmp_e = po.Param(initialize=coeff['cmp_e']) m.C_var_cmp = costs.loc[('c_var_cmp'), 'value'] m.C_var_exp = costs.loc[('c_var_exp'), 'value'] m.C_fuel = costs.loc[('c_fuel'), 'value'] m.C_emi = costs.loc[('c_emi'), 'value'] m.C_charge = costs.loc[('c_charges'), 'value'] m.exp_P_max = po.Param(initialize=self.P_exp) m.exp_P_min = po.Param(initialize=self.P_exp * 0.5) m.exp_a = po.Param(initialize=coeff['exp_a']) m.exp_b = po.Param(initialize=coeff['exp_b']) m.exp_c = po.Param(initialize=coeff['exp_c']) m.exp_d = po.Param(initialize=coeff['exp_d']) m.exp_e = po.Param(initialize=coeff['exp_e']) m.exp_f = po.Param(initialize=coeff['exp_f']) m.cas_m0 = po.Param(initialize=self.m_cav_0) m.cas_Pi_o_0 = po.Param( initialize=(self.pi_cav_max - self.pi_cav_min) / 2) m.cas_Pi_min = po.Param(initialize=self.pi_cav_min) m.cas_Pi_o_max = po.Param(initialize=self.pi_cav_max - self.pi_cav_min) m.eta = po.Param(initialize=self.pi_loss) m.mkt_C_el = po.Param(m.T, initialize=dict( zip(seq.index.values, seq['2030NEPC'].values))) m.cmp_P = po.Var(m.T, domain=po.NonNegativeReals, bounds=(0, self.P_cmp)) m.cmp_m = po.Var(m.T, domain=po.NonNegativeReals) m.cmp_Q = po.Var(m.T, domain=po.NonNegativeReals) m.cmp_y = po.Var(m.T, domain=po.Binary) m.cmp_z = po.Var(m.T, domain=po.NonNegativeReals) m.exp_P = po.Var(m.T, domain=po.NonNegativeReals, bounds=(0, self.P_exp)) m.exp_m = po.Var(m.T, domain=po.NonNegativeReals) m.exp_Q = po.Var(m.T, domain=po.NonNegativeReals) m.exp_y = po.Var(m.T, domain=po.Binary) m.exp_z = po.Var(m.T, domain=po.NonNegativeReals) m.cas_Pi_o = po.Var(m.T, domain=po.NonNegativeReals, bounds=(0, self.pi_cav_max - self.pi_cav_min)) m.profit_test = po.Objective(sense=po.minimize, rule=ru.obj) m.boundary = po.Constraint(m.T, rule=ru.boundary) m.cas_pi = po.Constraint(m.T, rule=ru.cas_pi) m.cmp_p_range_min = po.Constraint(m.T, rule=ru.cmp_p_range_min) m.cmp_p_range_max = po.Constraint(m.T, rule=ru.cmp_p_range_max) m.massflow_cmp = po.Constraint(m.T, rule=ru.massflow_cmp) m.q_cmp = po.Constraint(m.T, rule=ru.q_cmp) m.cmp_z1 = po.Constraint(m.T, rule=ru.cmp_z1) m.cmp_z2 = po.Constraint(m.T, rule=ru.cmp_z2) m.cmp_z3 = po.Constraint(m.T, rule=ru.cmp_z3) m.cmp_z4 = po.Constraint(m.T, rule=ru.cmp_z4) m.exp_p_range_min = po.Constraint(m.T, rule=ru.exp_p_range_min) m.exp_p_range_max = po.Constraint(m.T, rule=ru.exp_p_range_max) m.massflow_exp = po.Constraint(m.T, rule=ru.massflow_exp) m.q_exp = po.Constraint(m.T, rule=ru.q_exp) m.exp_z1 = po.Constraint(m.T, rule=ru.exp_z1) m.exp_z2 = po.Constraint(m.T, rule=ru.exp_z2) m.exp_z3 = po.Constraint(m.T, rule=ru.exp_z3) m.exp_z4 = po.Constraint(m.T, rule=ru.exp_z4) m.cmp_exp_excl = po.Constraint(m.T, rule=ru.cmp_exp_excl) opt = SolverFactory('gurobi') opt.options["mipgap"] = 0.02 results = opt.solve(m, tee=True) m.solutions.load_from(results) "post processing" data = { 'cmp_P': [m.cmp_P[t].value for t in m.T], 'cmp_m': [m.cmp_m[t].value for t in m.T], 'cmp_Q': [m.cmp_Q[t].value for t in m.T], 'cmp_y': [m.cmp_y[t].value for t in m.T], 'exp_P': [m.exp_P[t].value for t in m.T], 'exp_m': [m.exp_m[t].value for t in m.T], 'exp_Q': [m.exp_Q[t].value for t in m.T], 'exp_y': [m.exp_y[t].value for t in m.T], 'cas_Pi_o': [m.cas_Pi_o[t].value for t in m.T] } df = pd.DataFrame.from_dict(data) li = [] for k in range(df.shape[0]): i = 3 o = 7 j = 8 n = 4 if df.iat[k, i] == 1: value = df.iat[k, j] s = (self.exergy_cmp(value + self.pi_cav_min)) / 10e5 li.append(s) elif df.iat[k, o] == 1: value = df.iat[k, o] power_a = df.iat[k, n] s = (self.exergy_exp(power_a, value + self.pi_cav_min)) / 10e5 li.append(s) else: s = 0 li.append(s) df1 = pd.DataFrame(li) df['spec_exergy'] = df1 df.to_csv('results.csv', sep=',')
def pysp_instance_creation_callback(scenario_name, use_integer=False, sense=pyo.minimize, crops_multiplier=1): # long function to create the entire model # scenario_name is a string (e.g. AboveAverageScenario0) # # Returns a concrete model for the specified scenario # scenarios come in groups of three scengroupnum = sputils.extract_num(scenario_name) scenario_base_name = scenario_name.rstrip("0123456789") model = pyo.ConcreteModel() def crops_init(m): retval = [] for i in range(crops_multiplier): retval.append("WHEAT" + str(i)) retval.append("CORN" + str(i)) retval.append("SUGAR_BEETS" + str(i)) return retval model.CROPS = pyo.Set(initialize=crops_init) # # Parameters # model.TOTAL_ACREAGE = 500.0 * crops_multiplier def _scale_up_data(indict): outdict = {} for i in range(crops_multiplier): for crop in ['WHEAT', 'CORN', 'SUGAR_BEETS']: outdict[crop + str(i)] = indict[crop] return outdict model.PriceQuota = _scale_up_data({ 'WHEAT': 100000.0, 'CORN': 100000.0, 'SUGAR_BEETS': 6000.0 }) model.SubQuotaSellingPrice = _scale_up_data({ 'WHEAT': 170.0, 'CORN': 150.0, 'SUGAR_BEETS': 36.0 }) model.SuperQuotaSellingPrice = _scale_up_data({ 'WHEAT': 0.0, 'CORN': 0.0, 'SUGAR_BEETS': 10.0 }) model.CattleFeedRequirement = _scale_up_data({ 'WHEAT': 200.0, 'CORN': 240.0, 'SUGAR_BEETS': 0.0 }) model.PurchasePrice = _scale_up_data({ 'WHEAT': 238.0, 'CORN': 210.0, 'SUGAR_BEETS': 100000.0 }) model.PlantingCostPerAcre = _scale_up_data({ 'WHEAT': 150.0, 'CORN': 230.0, 'SUGAR_BEETS': 260.0 }) # # Stochastic Data # Yield = {} Yield['BelowAverageScenario'] = \ {'WHEAT':2.0,'CORN':2.4,'SUGAR_BEETS':16.0} Yield['AverageScenario'] = \ {'WHEAT':2.5,'CORN':3.0,'SUGAR_BEETS':20.0} Yield['AboveAverageScenario'] = \ {'WHEAT':3.0,'CORN':3.6,'SUGAR_BEETS':24.0} def Yield_init(m, cropname): # yield as in "crop yield" crop_base_name = cropname.rstrip("0123456789") if scengroupnum != 0: return Yield[scenario_base_name][ crop_base_name] + farmerstream.rand() else: return Yield[scenario_base_name][crop_base_name] model.Yield = pyo.Param(model.CROPS, within=pyo.NonNegativeReals, initialize=Yield_init, mutable=True) # # Variables # if (use_integer): model.DevotedAcreage = pyo.Var(model.CROPS, within=pyo.NonNegativeIntegers, bounds=(0.0, model.TOTAL_ACREAGE)) else: model.DevotedAcreage = pyo.Var(model.CROPS, bounds=(0.0, model.TOTAL_ACREAGE)) model.QuantitySubQuotaSold = pyo.Var(model.CROPS, bounds=(0.0, None)) model.QuantitySuperQuotaSold = pyo.Var(model.CROPS, bounds=(0.0, None)) model.QuantityPurchased = pyo.Var(model.CROPS, bounds=(0.0, None)) # # Constraints # def ConstrainTotalAcreage_rule(model): return pyo.sum_product(model.DevotedAcreage) <= model.TOTAL_ACREAGE model.ConstrainTotalAcreage = pyo.Constraint( rule=ConstrainTotalAcreage_rule) def EnforceCattleFeedRequirement_rule(model, i): return model.CattleFeedRequirement[i] <= ( model.Yield[i] * model.DevotedAcreage[i] ) + model.QuantityPurchased[i] - model.QuantitySubQuotaSold[ i] - model.QuantitySuperQuotaSold[i] model.EnforceCattleFeedRequirement = pyo.Constraint( model.CROPS, rule=EnforceCattleFeedRequirement_rule) def LimitAmountSold_rule(model, i): return model.QuantitySubQuotaSold[i] + model.QuantitySuperQuotaSold[ i] - (model.Yield[i] * model.DevotedAcreage[i]) <= 0.0 model.LimitAmountSold = pyo.Constraint(model.CROPS, rule=LimitAmountSold_rule) def EnforceQuotas_rule(model, i): return (0.0, model.QuantitySubQuotaSold[i], model.PriceQuota[i]) model.EnforceQuotas = pyo.Constraint(model.CROPS, rule=EnforceQuotas_rule) # Stage-specific cost computations; def ComputeFirstStageCost_rule(model): return pyo.sum_product(model.PlantingCostPerAcre, model.DevotedAcreage) model.FirstStageCost = pyo.Expression(rule=ComputeFirstStageCost_rule) def ComputeSecondStageCost_rule(model): expr = pyo.sum_product(model.PurchasePrice, model.QuantityPurchased) expr -= pyo.sum_product(model.SubQuotaSellingPrice, model.QuantitySubQuotaSold) expr -= pyo.sum_product(model.SuperQuotaSellingPrice, model.QuantitySuperQuotaSold) return expr model.SecondStageCost = pyo.Expression(rule=ComputeSecondStageCost_rule) def total_cost_rule(model): if (sense == pyo.minimize): return model.FirstStageCost + model.SecondStageCost return -model.FirstStageCost - model.SecondStageCost model.Total_Cost_Objective = pyo.Objective(rule=total_cost_rule, sense=sense) return model
# electricity purchased with the forward contract master.p1 = pyo.Var(master.H, within=pyo.NonNegativeReals) # value function for second stage problem master.alpha = pyo.Var(master.H) # ************************************************************************** # Objective function # ************************************************************************** def master_obj(master): return sum(c1 * master.u[h] + l1 * master.p1[h] + master.alpha[h] for h in master.H) master.OBJ = pyo.Objective(rule=master_obj) # ************************************************************************** # Constraints # ************************************************************************** # alpha down (-500) is an arbitrary selected bound def alphacon1(master, H): return master.alpha[H] >= -500 master.alphacon1 = pyo.Constraint(master.H, rule=alphacon1) # initialization for forward contract def p1_zero(master): return master.p1[0] == 0
from pyomo.environ import * from pyomo.opt import SolverFactory #creation of the model and variables model = pyo.ConcreteModel() model.C = pyo.Var(range(1, 4)) model.n = pyo.Var(range(1, 4), within=Integers, bounds=(0, 1000)) model.b = pyo.Var(within=Binary) C = model.C n = model.n b = model.b M = 100000 #objective function model.obj = pyo.Objective(expr=pyo.summation(C)) #constraint model.total = pyo.Constraint(expr=pyo.summation(n) == 2100) model.C1 = pyo.Constraint(expr=C[1] == 2 * n[1]) # aqui el constrain C2 es reemplazado por por estos atendiendo a la tecnica BigM: # -b * M <= C <= b * M --> constrains C2a y C2b (para cada lado de la desigualdad). # -(1-b) * M <= C - x <= (1-b) * M --> constrains C2c y C3c (para cada lado de la desigualdad). model.C2a = pyo.Constraint(expr=-b * M <= C[2]) model.C2b = pyo.Constraint(expr=C[2] <= b * M) model.C2c = pyo.Constraint(expr=-(1 - b) * M <= C[2] - (6 * n[2] + 1000)) model.C3c = pyo.Constraint(expr=C[2] - (6 * n[2] + 1000) <= (1 - b) * M) model.C2n = pyo.Constraint(expr=n[2] <= b * 1000) model.C3 = pyo.Constraint(expr=C[3] == 7 * n[3])
def _find_error_canceling_reaction(self, reference_subset, milp_software=None): """ Automatically find a valid error canceling reaction given a subset of the available benchmark species. This is done by solving a mixed integer linear programming (MILP) problem similiar to Buerger et al. (https://doi.org/10.1016/j.combustflame.2017.08.013) Args: reference_subset (list): A list of indices from self.reference_species that can participate in the reaction milp_software (list, optional): Solvers to try in order. Defaults to ['lpsolve'] or if pyomo is available defaults to ['lpsolve', 'pyomo']. lpsolve is usually faster. Returns: tuple(ErrorCancelingReaction, np.ndarray) - Reaction with the target species (if a valid reaction is found, else ``None``) - Indices (of the subset) for the species that participated in the return reaction """ if milp_software is None: milp_software = ['lpsolve'] if pyo is not None: milp_software.append('pyomo') # Define the constraints based on the provided subset c_matrix = np.take(self.constraint_matrix, reference_subset, axis=0) c_matrix = np.tile(c_matrix, (2, 1)) sum_constraints = np.sum(c_matrix, 1, dtype=int) targets = -1 * self.target_constraint m = c_matrix.shape[0] n = c_matrix.shape[1] split = int(m / 2) for solver in milp_software: if solver == 'pyomo': # Check that pyomo is available if pyo is None: raise ImportError( 'Cannot import optional package pyomo. Either install this dependency with ' '`conda install -c conda-forge pyomo glpk` or set milp_software to `lpsolve`' ) # Setup the MILP problem using pyomo lp_model = pyo.ConcreteModel() lp_model.i = pyo.RangeSet(0, m - 1) lp_model.j = pyo.RangeSet(0, n - 1) lp_model.r = pyo.RangeSet( 0, split - 1) # indices before the split correspond to reactants lp_model.p = pyo.RangeSet( split, m - 1) # indices after the split correspond to products lp_model.v = pyo.Var(lp_model.i, domain=pyo.NonNegativeIntegers ) # The stoich. coef. we are solving for lp_model.c = pyo.Param( lp_model.i, lp_model.j, initialize=lambda _, i_ind, j_ind: c_matrix[i_ind, j_ind]) lp_model.s = pyo.Param( lp_model.i, initialize=lambda _, i_ind: sum_constraints[i_ind]) lp_model.t = pyo.Param( lp_model.j, initialize=lambda _, j_ind: targets[j_ind]) lp_model.obj = pyo.Objective(rule=_pyo_obj_expression) lp_model.constraints = pyo.Constraint( lp_model.j, rule=_pyo_constraint_rule) # Solve the MILP problem using the GLPK MILP solver (https://www.gnu.org/software/glpk/) opt = pyo.SolverFactory('glpk') results = opt.solve(lp_model, timelimit=1) # Return the solution if a valid reaction is found. Otherwise continue to next solver if results.solver.termination_condition == pyo.TerminationCondition.optimal: # Extract the solution and find the species with non-zero stoichiometric coefficients solution = lp_model.v.extract_values().values() break elif solver == 'lpsolve': # Save the current signal handler sig = signal.getsignal(signal.SIGINT) # Setup the MILP problem using lpsolve lp = lpsolve('make_lp', 0, m) lpsolve('set_verbose', lp, 2) # Reduce the logging from lpsolve lpsolve('set_obj_fn', lp, sum_constraints) lpsolve('set_minim', lp) for j in range(n): lpsolve( 'add_constraint', lp, np.concatenate( (c_matrix[:split, j], -1 * c_matrix[split:, j])), EQ, targets[j]) lpsolve('add_constraint', lp, np.ones(m), LE, 20) # Use at most 20 species (including replicates) lpsolve('set_timeout', lp, 1) # Move on if lpsolve can't find a solution quickly # Constrain v_i to be 4 or less for i in range(m): lpsolve('set_upbo', lp, i, 4) # All v_i must be integers lpsolve('set_int', lp, [True] * m) status = lpsolve('solve', lp) # Reset signal handling since lpsolve changed it try: signal.signal(signal.SIGINT, sig) except ValueError: # This is not being run in the main thread, so we cannot reset signal pass # Return the solution if a valid reaction is found. Otherwise continue to next solver if status == 0: _, solution = lpsolve('get_solution', lp)[:2] break else: raise ValueError( f'Unrecognized MILP solver {solver} for isodesmic reaction generation' ) else: return None, None reaction = ErrorCancelingReaction(self.target, dict()) subset_indices = [] for index, v in enumerate(solution): if v > 0: subset_indices.append(index % split) if index < split: reaction.species.update( {self.reference_species[reference_subset[index]]: -v}) else: reaction.species.update({ self.reference_species[reference_subset[index % split]]: v }) return reaction, np.array(subset_indices)
import pyomo.environ as pe from pyomo.contrib.interior_point.interior_point import InteriorPointSolver from pyomo.contrib.interior_point.interface import InteriorPointInterface from pyomo.contrib.interior_point.linalg.mumps_interface import MumpsInterface import logging logging.basicConfig(level=logging.INFO) # Supposedly this sets the root logger's level to INFO. # But when linear_solver.logger logs with debug, # it gets propagated to a mysterious root logger with # level NOTSET... m = pe.ConcreteModel() m.x = pe.Var() m.y = pe.Var() m.obj = pe.Objective(expr=m.x**2 + m.y**2) m.c1 = pe.Constraint(expr=m.y == pe.exp(m.x)) m.c2 = pe.Constraint(expr=m.y >= (m.x - 1)**2) interface = InteriorPointInterface(m) linear_solver = MumpsInterface( # log_filename='lin_sol.log', icntl_options={11: 1}, # Set error level to 1 (most detailed) ) ip_solver = InteriorPointSolver(linear_solver) x, duals_eq, duals_ineq = ip_solver.solve(interface) print(x, duals_eq, duals_ineq)
def _k_medoids_exact(self, distances, n_clusters): """ Parameters ---------- distances : int, required Pairwise distances between each row. n_clusters : int, required Number of clusters. """ # Create model M = pyomo.ConcreteModel() # get distance matrix M.d = distances # set number of clusters M.no_k = n_clusters # Distances is a symmetrical matrix, extract its length length = distances.shape[0] # get indices M.i = [j for j in range(length)] M.j = [j for j in range(length)] # initialize vars M.z = pyomo.Var(M.i, M.j, within=pyomo.Binary) M.y = pyomo.Var(M.i, within=pyomo.Binary) # get objective def objRule(M): return sum(sum(M.d[i, j] * M.z[i, j] for j in M.j) for i in M.i) M.obj = pyomo.Objective(rule=objRule) # s.t. # Assign all candidates to clusters def candToClusterRule(M, j): return sum(M.z[i, j] for i in M.i) == 1 M.candToClusterCon = pyomo.Constraint(M.j, rule=candToClusterRule) # no of clusters def noClustersRule(M): return sum(M.y[i] for i in M.i) == M.no_k M.noClustersCon = pyomo.Constraint(rule=noClustersRule) # cluster relation def clusterRelationRule(M, i, j): return M.z[i, j] <= M.y[i] M.clusterRelationCon = pyomo.Constraint(M.i, M.j, rule=clusterRelationRule) # create optimization problem optprob = opt.SolverFactory(self.solver) if self.solver == 'gurobi': optprob.set_options("Threads=" + str(self.threads) + " TimeLimit=" + str(self.timelimit)) results = optprob.solve(M, tee=False) # check that it does not fail if self.solver == 'gurobi' and results['Solver'][0][ 'Termination condition'].index == 11: print(results['Solver'][0]['Termination message']) return False elif self.solver == 'gurobi' and not results['Solver'][0][ 'Termination condition'].index in [2, 7, 8, 9, 10]: # optimal raise ValueError(results['Solver'][0]['Termination message']) # Get results r_x = np.array([[round(M.z[i, j].value) for i in range(length)] for j in range(length)]) r_y = np.array([round(M.y[j].value) for j in range(length)]) r_obj = pyomo.value(M.obj) return (r_y, r_x.T, r_obj)
def create_embedded(): model = aml.ConcreteModel() model.d1 = aml.Param(mutable=True, initialize=0) model.d2 = aml.Param(mutable=True, initialize=0) model.d3 = aml.Param(mutable=True, initialize=0) model.d4 = aml.Param(mutable=True, initialize=0) # first stage model.x = aml.Var(bounds=(0, 10)) # first stage derived model.y = aml.Expression(expr=model.x + 1) model.fx = aml.Var() # second stage model.z = aml.Var(bounds=(-10, 10)) # second stage derived model.q = aml.Expression(expr=model.z**2) model.fz = aml.Var() model.r = aml.Var() # stage costs model.StageCost = aml.Expression([1, 2]) model.StageCost.add(1, model.fx) model.StageCost.add(2, -model.fz + model.r + model.d1) model.o = aml.Objective(expr=aml.sum_product(model.StageCost)) model.c_first_stage = aml.Constraint(expr=model.x >= 0) # test our handling of intermediate variables that # are created by Piecewise but can not necessarily # be declared on the scenario tree model.p_first_stage = aml.Piecewise(model.fx, model.x, pw_pts=[0., 2., 5., 7., 10.], pw_constr_type='EQ', pw_repn='INC', f_rule=[10., 10., 9., 10., 10.], force_pw=True) model.c_second_stage = aml.Constraint( expr=model.x + model.r * model.d2 >= -100) model.cL_second_stage = aml.Constraint(expr=model.d3 >= -model.r) model.cU_second_stage = aml.Constraint(expr=model.r <= 0) # exercise more of the code by making this an indexed # block model.p_second_stage = aml.Piecewise([1], model.fz, model.z, pw_pts=[-10, -5., 0., 5., 10.], pw_constr_type='EQ', pw_repn='INC', f_rule=[0., 0., -1., model.d4, 1.], force_pw=True) # annotate the model model.varstage = VariableStageAnnotation() # first stage model.varstage.declare(model.x, 1) model.varstage.declare(model.y, 1, derived=True) model.varstage.declare(model.fx, 1, derived=True) model.varstage.declare(model.p_first_stage, 1, derived=True) # second stage model.varstage.declare(model.z, 2) model.varstage.declare(model.q, 2, derived=True) model.varstage.declare(model.fz, 2, derived=True) model.varstage.declare(model.r, 2, derived=True) model.varstage.declare(model.p_second_stage, 2, derived=True) model.stagecost = StageCostAnnotation() for i in [1, 2]: model.stagecost.declare(model.StageCost[i], i) model.stochdata = StochasticDataAnnotation() model.stochdata.declare(model.d1, distribution=TableDistribution([0.0, 1.0, 2.0])) model.stochdata.declare(model.d2, distribution=TableDistribution([0.0, 1.0, 2.0])) model.stochdata.declare(model.d3, distribution=TableDistribution([0.0, 1.0, 2.0])) model.stochdata.declare(model.d4, distribution=TableDistribution([0.0, 1.0, 2.0])) return EmbeddedSP(model)
# fixed master problem variables model.u = pyo.Var(model.H) model.p1 = pyo.Var(model.H) # electricity produced by generator model.pg = pyo.Var(model.H, within=pyo.NonNegativeReals) # electrictiy bought from retailer model.p2 = pyo.Var(model.H, within=pyo.NonNegativeReals) # ****************************************************************** # Objective function # ****************************************************************** model.OBJ = pyo.Objective(expr=sum( c1 * model.u[h] + l1 * model.p1[h] + c2 * model.pg[h] + l2 * model.p2[h] for h in model.H)) # ****************************************************************** # Constraints # ****************************************************************** # load must be covered by production or purchasing electrictiy # take first random vector from samples pl = sample def con_load(model, H): return model.pg[H] + model.p1[H] + model.p2[H] >= pl[H] model.con_load = pyo.Constraint(model.H, rule=con_load)
def test_tower_dispatch(site): """Tests setting up tower dispatch using system model and running simulation with dispatch""" expected_objective = 99485.378 dispatch_n_look_ahead = 48 tower = TowerPlant(site, technologies['tower']) tower.optimize_field_before_sim = False tower.setup_performance_model() model = pyomo.ConcreteModel(name='tower_only') model.forecast_horizon = pyomo.Set(initialize=range(dispatch_n_look_ahead)) tower._dispatch = TowerDispatch(model, model.forecast_horizon, tower, tower._financial_model) # Manually creating objective for testing prices = {} block_length = 8 index = 0 for i in range(int(dispatch_n_look_ahead / block_length)): for j in range(block_length): if i % 2 == 0: prices[index] = 30.0 # assuming low prices else: prices[index] = 100.0 # assuming high prices index += 1 model.price = pyomo.Param(model.forecast_horizon, within=pyomo.Reals, initialize=prices, mutable=True, units=u.USD / u.MWh) # TODO: Use hybrid simulation class with grid and remove this objective set-up def create_test_objective_rule(m): return sum(m.tower[t].time_duration * m.price[t] * m.tower[t].cycle_generation - m.tower[t].cost_per_field_generation * m.tower[t].receiver_thermal_power * m.tower[t].time_duration - m.tower[t].cost_per_field_start * m.tower[t].incur_field_start - m.tower[t].cost_per_cycle_generation * m.tower[t].cycle_generation * m.tower[t].time_duration - m.tower[t].cost_per_cycle_start * m.tower[t].incur_cycle_start - m.tower[t].cost_per_change_thermal_input * m.tower[t].cycle_thermal_ramp for t in m.tower.index_set()) model.test_objective = pyomo.Objective( rule=create_test_objective_rule, sense=pyomo.maximize) tower.dispatch.initialize_parameters() tower.dispatch.update_time_series_parameters(0) tower.dispatch.update_initial_conditions() assert_units_consistent(model) results = HybridDispatchBuilderSolver.glpk_solve_call(model) tower.simulate_with_dispatch(48, 0) assert results.solver.termination_condition == TerminationCondition.optimal assert pyomo.value(model.test_objective) == pytest.approx(expected_objective, 1e-5) assert sum(tower.dispatch.receiver_thermal_power) > 0.0 # Useful thermal generation assert sum(tower.dispatch.cycle_generation) > 0.0 # Useful power generation
def test_detailed_battery_dispatch(site): expected_objective = 37003.621 expected_lifecycles = 0.331693 # TODO: McCormick error is large enough to make objective 50% higher than # the value of simple battery dispatch objective dispatch_n_look_ahead = 48 battery = Battery(site, technologies['battery']) model = pyomo.ConcreteModel(name='detailed_battery_only') model.forecast_horizon = pyomo.Set(initialize=range(dispatch_n_look_ahead)) battery._dispatch = ConvexLinearVoltageBatteryDispatch(model, model.forecast_horizon, battery._system_model, battery._financial_model) # Manually creating objective for testing prices = {} block_length = 8 index = 0 for i in range(int(dispatch_n_look_ahead / block_length)): for j in range(block_length): if i % 2 == 0: prices[index] = 30.0 # assuming low prices else: prices[index] = 100.0 # assuming high prices index += 1 model.price = pyomo.Param(model.forecast_horizon, within=pyomo.Reals, initialize=prices, mutable=True, units=u.USD / u.MWh) def create_test_objective_rule(m): return (sum((m.convex_LV_battery[t].time_duration * ( (m.price[t] - m.convex_LV_battery[t].cost_per_discharge) * m.convex_LV_battery[t].discharge_power - (m.price[t] + m.convex_LV_battery[t].cost_per_charge) * m.convex_LV_battery[t].charge_power)) for t in m.convex_LV_battery.index_set()) - m.lifecycle_cost * m.lifecycles) model.test_objective = pyomo.Objective( rule=create_test_objective_rule, sense=pyomo.maximize) battery.dispatch.initialize_parameters() battery.dispatch.update_time_series_parameters(0) model.initial_SOC = battery.dispatch.minimum_soc # Set initial SOC to minimum assert_units_consistent(model) results = HybridDispatchBuilderSolver.glpk_solve_call(model) # TODO: trying to solve the nonlinear problem but solver doesn't work... # Need to try another nonlinear solver # results = HybridDispatchBuilderSolver.mindtpy_solve_call(model) assert results.solver.termination_condition == TerminationCondition.optimal assert pyomo.value(model.test_objective) == pytest.approx(expected_objective, 1e-3) assert pyomo.value(battery.dispatch.lifecycles) == pytest.approx(expected_lifecycles, 1e-3) assert sum(battery.dispatch.charge_power) > 0.0 assert sum(battery.dispatch.discharge_power) > 0.0 assert sum(battery.dispatch.charge_current) >= sum(battery.dispatch.discharge_current) - 1e-7
def test_csp_dispatch_model(site): expected_objective = 217896.9003 dispatch_n_look_ahead = 48 model = pyomo.ConcreteModel(name='csp') model.forecast_horizon = pyomo.Set(initialize=range(dispatch_n_look_ahead)) csp_dispatch = CspDispatch(model, model.forecast_horizon, None, None) # Manually creating objective for testing model.price = pyomo.Param(model.forecast_horizon, within=pyomo.Reals, default=60.0, # assuming flat PPA of $60/MWh mutable=True, units=u.USD / u.MWh) price = [60.]*5 price.extend([30.]*8) price.extend([100.]*4) price.extend([75.]*7) price.extend(price) for i, p in enumerate(price): model.price[i] = p def create_test_objective_rule(m): return sum(m.csp[t].time_duration * m.price[t] * m.csp[t].cycle_generation - m.csp[t].cost_per_field_generation * m.csp[t].receiver_thermal_power * m.csp[t].time_duration - m.csp[t].cost_per_field_start * m.csp[t].incur_field_start - m.csp[t].cost_per_cycle_generation * m.csp[t].cycle_generation * m.csp[t].time_duration - m.csp[t].cost_per_cycle_start * m.csp[t].incur_cycle_start - m.csp[t].cost_per_change_thermal_input * m.csp[t].cycle_thermal_ramp for t in m.csp.index_set()) model.test_objective = pyomo.Objective( rule=create_test_objective_rule, sense=pyomo.maximize) assert_units_consistent(model) # WITHIN csp_dispatch.initialize_parameters() # Cost Parameters csp_dispatch.cost_per_field_generation = 3.0 csp_dispatch.cost_per_field_start = 5650.0 csp_dispatch.cost_per_cycle_generation = 2.0 csp_dispatch.cost_per_cycle_start = 6520.0 csp_dispatch.cost_per_change_thermal_input = 0.3 # Solar field and thermal energy storage performance parameters csp_dispatch.field_startup_losses = 1.5 csp_dispatch.receiver_required_startup_energy = 141.0 csp_dispatch.storage_capacity = 10. * 393.0 csp_dispatch.minimum_receiver_power = 141.0 csp_dispatch.allowable_receiver_startup_power = 141.0 csp_dispatch.receiver_pumping_losses = 0.0265 csp_dispatch.field_track_losses = 0.3 csp_dispatch.heat_trace_losses = 1.5 # Power cycle performance csp_dispatch.cycle_required_startup_energy = 197.0 csp_dispatch.cycle_nominal_efficiency = 0.414 csp_dispatch.cycle_pumping_losses = 0.0127 csp_dispatch.allowable_cycle_startup_power = 197.0 csp_dispatch.minimum_cycle_thermal_power = 117.9 csp_dispatch.maximum_cycle_thermal_power = 393 minimum_cycle_power = 40.75 csp_dispatch.maximum_cycle_power = 163 csp_dispatch.cycle_performance_slope = ((csp_dispatch.maximum_cycle_power - minimum_cycle_power) / (csp_dispatch.maximum_cycle_thermal_power - csp_dispatch.minimum_cycle_thermal_power)) n_horizon = len(csp_dispatch.blocks.index_set()) csp_dispatch.time_duration = [1.0] * n_horizon csp_dispatch.cycle_ambient_efficiency_correction = [csp_dispatch.cycle_nominal_efficiency] * n_horizon heat_gen = [0.0]*6 heat_gen.extend([0.222905449, 0.698358974, 0.812419872, 0.805703526, 0.805679487, 0.805360577, 0.805392628, 0.805285256, 0.805644231, 0.811056090, 0.604987179, 0.515375000, 0.104403045]) # 13 heat_gen.extend([0.0]*11) heat_gen.extend([0.171546474, 0.601642628, 0.755834936, 0.808812500, 0.810616987, 0.73800641, 0.642097756, 0.544584936, 0.681479167, 0.547671474, 0.438600962, 0.384945513, 0.034808173]) # 13 heat_gen.extend([0.0] * 5) heat_gen = [heat * 565.0 for heat in heat_gen] csp_dispatch.available_thermal_generation = heat_gen print("Total available thermal generation: {}".format(sum(csp_dispatch.available_thermal_generation))) results = HybridDispatchBuilderSolver.glpk_solve_call(model) assert results.solver.termination_condition == TerminationCondition.optimal assert pyomo.value(model.test_objective) == pytest.approx(expected_objective, 1e-5)
def create_psv_acopf_model(model_data, include_feasibility_slack=False): md = model_data.clone_in_service() tx_utils.scale_ModelData_to_pu(md, inplace=True) gens = dict(md.elements(element_type='generator')) buses = dict(md.elements(element_type='bus')) branches = dict(md.elements(element_type='branch')) loads = dict(md.elements(element_type='load')) shunts = dict(md.elements(element_type='shunt')) gen_attrs = md.attributes(element_type='generator') bus_attrs = md.attributes(element_type='bus') branch_attrs = md.attributes(element_type='branch') load_attrs = md.attributes(element_type='load') shunt_attrs = md.attributes(element_type='shunt') inlet_branches_by_bus, outlet_branches_by_bus = \ tx_utils.inlet_outlet_branches_by_bus(branches, buses) gens_by_bus = tx_utils.gens_by_bus(buses, gens) model = pe.ConcreteModel() ### declare (and fix) the loads at the buses bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads) libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads) libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads) model.pl.fix() model.ql.fix() ### declare the fixed shunts at the buses bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts( buses, shunts) ### declare the polar voltages libbus.declare_var_vm(model, bus_attrs['names'], initialize=bus_attrs['vm'], bounds=zip_items(bus_attrs['v_min'], bus_attrs['v_max'])) va_bounds = {k: (-pi, pi) for k in bus_attrs['va']} libbus.declare_var_va(model, bus_attrs['names'], initialize=bus_attrs['va'], bounds=va_bounds) ### include the feasibility slack for the bus balances p_rhs_kwargs = {} q_rhs_kwargs = {} if include_feasibility_slack: p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack( model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads) ### fix the reference bus ref_bus = md.data['system']['reference_bus'] ref_angle = md.data['system']['reference_bus_angle'] model.va[ref_bus].fix(radians(ref_angle)) ### declare the generator real and reactive power pg_init = { k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg'] } libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init, bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])) qg_init = { k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg'] } libgen.declare_var_qg(model, gen_attrs['names'], initialize=qg_init, bounds=zip_items(gen_attrs['q_min'], gen_attrs['q_max'])) ### declare the current flows in the branches vr_init = { k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm'] } vj_init = { k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm'] } s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()} s_lbub = dict() for k in branches.keys(): if s_max[k] is None: s_lbub[k] = (None, None) else: s_lbub[k] = (-s_max[k], s_max[k]) pf_bounds = s_lbub pt_bounds = s_lbub qf_bounds = s_lbub qt_bounds = s_lbub pf_init = dict() pt_init = dict() qf_init = dict() qt_init = dict() for branch_name, branch in branches.items(): from_bus = branch['from_bus'] to_bus = branch['to_bus'] y_matrix = tx_calc.calculate_y_matrix_from_branch(branch) ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus]) pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus]) qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus]) qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus]) libbranch.declare_var_pf(model=model, index_set=branch_attrs['names'], initialize=pf_init, bounds=pf_bounds) libbranch.declare_var_pt(model=model, index_set=branch_attrs['names'], initialize=pt_init, bounds=pt_bounds) libbranch.declare_var_qf(model=model, index_set=branch_attrs['names'], initialize=qf_init, bounds=qf_bounds) libbranch.declare_var_qt(model=model, index_set=branch_attrs['names'], initialize=qt_init, bounds=qt_bounds) ### declare the branch power flow constraints libbranch.declare_eq_branch_power(model=model, index_set=branch_attrs['names'], branches=branches, branch_attrs=branch_attrs, coordinate_type=CoordinateType.POLAR) ### declare the pq balances libbus.declare_eq_p_balance(model=model, index_set=bus_attrs['names'], bus_p_loads=bus_p_loads, gens_by_bus=gens_by_bus, bus_gs_fixed_shunts=bus_gs_fixed_shunts, inlet_branches_by_bus=inlet_branches_by_bus, outlet_branches_by_bus=outlet_branches_by_bus, coordinate_type=CoordinateType.POLAR, **p_rhs_kwargs) libbus.declare_eq_q_balance(model=model, index_set=bus_attrs['names'], bus_q_loads=bus_q_loads, gens_by_bus=gens_by_bus, bus_bs_fixed_shunts=bus_bs_fixed_shunts, inlet_branches_by_bus=inlet_branches_by_bus, outlet_branches_by_bus=outlet_branches_by_bus, coordinate_type=CoordinateType.POLAR, **q_rhs_kwargs) ### declare the thermal limits libbranch.declare_ineq_s_branch_thermal_limit( model=model, index_set=branch_attrs['names'], branches=branches, s_thermal_limits=s_max, flow_type=FlowType.POWER) ### declare the voltage min and max inequalities libbus.declare_ineq_vm_bus_lbub(model=model, index_set=bus_attrs['names'], buses=buses, coordinate_type=CoordinateType.POLAR) ### declare angle difference limits on interconnected buses libbranch.declare_ineq_angle_diff_branch_lbub( model=model, index_set=branch_attrs['names'], branches=branches, coordinate_type=CoordinateType.POLAR) ### declare the generator cost objective libgen.declare_expression_pgqg_operating_cost(model=model, index_set=gen_attrs['names'], p_costs=gen_attrs['p_cost'], q_costs=gen_attrs.get( 'q_cost', None)) obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost) if include_feasibility_slack: obj_expr += penalty_expr if hasattr(model, 'qg_operating_cost'): obj_expr += sum(model.qg_operating_cost[gen_name] for gen_name in model.qg_operating_cost) model.obj = pe.Objective(expr=obj_expr) return model, md
def create_riv_acopf_model(model_data, include_feasibility_slack=False): md = model_data.clone_in_service() tx_utils.scale_ModelData_to_pu(md, inplace=True) gens = dict(md.elements(element_type='generator')) buses = dict(md.elements(element_type='bus')) branches = dict(md.elements(element_type='branch')) loads = dict(md.elements(element_type='load')) shunts = dict(md.elements(element_type='shunt')) gen_attrs = md.attributes(element_type='generator') bus_attrs = md.attributes(element_type='bus') branch_attrs = md.attributes(element_type='branch') load_attrs = md.attributes(element_type='load') shunt_attrs = md.attributes(element_type='shunt') inlet_branches_by_bus, outlet_branches_by_bus = \ tx_utils.inlet_outlet_branches_by_bus(branches, buses) gens_by_bus = tx_utils.gens_by_bus(buses, gens) model = pe.ConcreteModel() ### declare (and fix) the loads at the buses bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads) libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads) libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads) model.pl.fix() model.ql.fix() ### declare the fixed shunts at the buses bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts( buses, shunts) ### declare the rectangular voltages neg_v_max = map_items(op.neg, bus_attrs['v_max']) vr_init = { k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm'] } libbus.declare_var_vr(model, bus_attrs['names'], initialize=vr_init, bounds=zip_items(neg_v_max, bus_attrs['v_max'])) vj_init = { k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm'] } libbus.declare_var_vj(model, bus_attrs['names'], initialize=vj_init, bounds=zip_items(neg_v_max, bus_attrs['v_max'])) ### include the feasibility slack for the bus balances p_rhs_kwargs = {} q_rhs_kwargs = {} if include_feasibility_slack: p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack( model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads) ### fix the reference bus ref_bus = md.data['system']['reference_bus'] ref_angle = md.data['system']['reference_bus_angle'] if ref_angle != 0.0: libbus.declare_eq_ref_bus_nonzero(model, ref_angle, ref_bus) else: model.vj[ref_bus].fix(0.0) model.vr[ref_bus].setlb(0.0) ### declare the generator real and reactive power pg_init = { k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg'] } libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init, bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])) qg_init = { k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg'] } libgen.declare_var_qg(model, gen_attrs['names'], initialize=qg_init, bounds=zip_items(gen_attrs['q_min'], gen_attrs['q_max'])) ### declare the current flows in the branches branch_currents = tx_utils.dict_of_branch_currents(branches, buses) s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()} if_bounds = dict() it_bounds = dict() ifr_init = dict() ifj_init = dict() itr_init = dict() itj_init = dict() for branch_name, branch in branches.items(): from_bus = branch['from_bus'] to_bus = branch['to_bus'] y_matrix = tx_calc.calculate_y_matrix_from_branch(branch) ifr_init[branch_name] = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) ifj_init[branch_name] = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) itr_init[branch_name] = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) itj_init[branch_name] = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus], vj_init[to_bus], y_matrix) if s_max[branch_name] is None: if_bounds[branch_name] = (None, None) it_bounds[branch_name] = (None, None) else: if_max = s_max[branch_name] / buses[branches[branch_name] ['from_bus']]['v_min'] it_max = s_max[branch_name] / buses[branches[branch_name] ['to_bus']]['v_min'] if_bounds[branch_name] = (-if_max, if_max) it_bounds[branch_name] = (-it_max, it_max) libbranch.declare_var_ifr(model=model, index_set=branch_attrs['names'], initialize=ifr_init, bounds=if_bounds) libbranch.declare_var_ifj(model=model, index_set=branch_attrs['names'], initialize=ifj_init, bounds=if_bounds) libbranch.declare_var_itr(model=model, index_set=branch_attrs['names'], initialize=itr_init, bounds=it_bounds) libbranch.declare_var_itj(model=model, index_set=branch_attrs['names'], initialize=itj_init, bounds=it_bounds) ir_init = dict() ij_init = dict() for bus_name, bus in buses.items(): ir_expr = sum([ ifr_init[branch_name] for branch_name in outlet_branches_by_bus[bus_name] ]) ir_expr += sum([ itr_init[branch_name] for branch_name in inlet_branches_by_bus[bus_name] ]) ij_expr = sum([ ifj_init[branch_name] for branch_name in outlet_branches_by_bus[bus_name] ]) ij_expr += sum([ itj_init[branch_name] for branch_name in inlet_branches_by_bus[bus_name] ]) if bus_gs_fixed_shunts[bus_name] != 0.0: ir_expr += bus_gs_fixed_shunts[bus_name] * vr_init[bus_name] ij_expr += bus_gs_fixed_shunts[bus_name] * vj_init[bus_name] if bus_bs_fixed_shunts[bus_name] != 0.0: ir_expr += bus_bs_fixed_shunts[bus_name] * vj_init[bus_name] ij_expr += bus_bs_fixed_shunts[bus_name] * vr_init[bus_name] ir_init[bus_name] = ir_expr ij_init[bus_name] = ij_expr # TODO: Implement better bounds (?) for these aggregated variables -- note, these are unbounded in old Egret libbus.declare_var_ir_aggregation_at_bus(model=model, index_set=bus_attrs['names'], initialize=ir_init, bounds=(None, None)) libbus.declare_var_ij_aggregation_at_bus(model=model, index_set=bus_attrs['names'], initialize=ij_init, bounds=(None, None)) ### declare the branch current flow constraints libbranch.declare_eq_branch_current(model=model, index_set=branch_attrs['names'], branches=branches) ### declare the ir/ij_aggregation constraints libbus.declare_eq_i_aggregation_at_bus( model=model, index_set=bus_attrs['names'], bus_bs_fixed_shunts=bus_bs_fixed_shunts, bus_gs_fixed_shunts=bus_gs_fixed_shunts, inlet_branches_by_bus=inlet_branches_by_bus, outlet_branches_by_bus=outlet_branches_by_bus) ### declare the pq balances libbus.declare_eq_p_balance_with_i_aggregation( model=model, index_set=bus_attrs['names'], bus_p_loads=bus_p_loads, gens_by_bus=gens_by_bus, **p_rhs_kwargs) libbus.declare_eq_q_balance_with_i_aggregation( model=model, index_set=bus_attrs['names'], bus_q_loads=bus_q_loads, gens_by_bus=gens_by_bus, **q_rhs_kwargs) ### declare the thermal limits libbranch.declare_ineq_s_branch_thermal_limit( model=model, index_set=branch_attrs['names'], branches=branches, s_thermal_limits=s_max, flow_type=FlowType.CURRENT) ### declare the voltage min and max inequalities libbus.declare_ineq_vm_bus_lbub(model=model, index_set=bus_attrs['names'], buses=buses, coordinate_type=CoordinateType.RECTANGULAR) ### declare angle difference limits on interconnected buses libbranch.declare_ineq_angle_diff_branch_lbub( model=model, index_set=branch_attrs['names'], branches=branches, coordinate_type=CoordinateType.RECTANGULAR) ### declare the generator cost objective libgen.declare_expression_pgqg_operating_cost(model=model, index_set=gen_attrs['names'], p_costs=gen_attrs['p_cost'], q_costs=gen_attrs.get( 'q_cost', None)) obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost) if include_feasibility_slack: obj_expr += penalty_expr if hasattr(model, 'qg_operating_cost'): obj_expr += sum(model.qg_operating_cost[gen_name] for gen_name in model.qg_operating_cost) model.obj = pe.Objective(expr=obj_expr) return model, md
def DC_OPF_RO_TruthTable(Elecdata, TruthTable): Gen = Elecdata.Gen Branch = Elecdata.Branch Bus = Elecdata.Bus GasGenerators = Gen[Gen.FuelType == 'Gas'].index.tolist() nscen = len(TruthTable) m = pm.ConcreteModel() m.gen_set = pm.Set(initialize=Gen.index.tolist()) m.branch_set = pm.Set(initialize=Branch.index.tolist()) m.bus_set = pm.Set(initialize=Bus.index.tolist()) m.scen_set = pm.RangeSet(0, nscen - 1) m.gasgen_set = pm.Set(initialize=GasGenerators, within=m.gen_set, ordered=True) m.P_UB = pm.Var(m.gasgen_set, bounds=lambda m, i: (Gen.DC_OPF_RES[i], Gen.Pmax_MW[i]), initialize=lambda m, i: Gen.DC_OPF_RES[i]) m.P_LB = pm.Var(m.gasgen_set, bounds=lambda m, i: (Gen.Pmin_MW[i], Gen.DC_OPF_RES[i]), initialize=lambda m, i: Gen.DC_OPF_RES[i]) m.P = pm.Var(m.gen_set, m.scen_set, bounds=lambda m, i, s: (Gen.Pmin_MW[i], Gen.Pmax_MW[i]), initialize=1) m.Pij = pm.Var(m.branch_set, m.scen_set, bounds=lambda m, i, s: (-Branch.RateA_MVA[i], Branch.RateA_MVA[i]), initialize=1) m.th = pm.Var(m.bus_set, m.scen_set, bounds=(-np.pi, np.pi), initialize=0) m.P_Shed = pm.Var(m.gasgen_set, bounds=(0, None)) m.P_Add = pm.Var(m.gasgen_set, bounds=(0, None)) def PowerBal_constr(model, i, s): PowerBal = -Bus.PD_MW[i] \ + sum(m.P[k,s] for k in Gen[Gen.Gen_Bus==i].index.tolist()) \ - sum(m.Pij[k,s] for k in Branch[Branch.From_Bus==i].index.tolist()) \ + sum(m.Pij[k,s] for k in Branch[Branch.To_Bus==i].index.tolist()) \ ==0 return PowerBal m.PowerBal_constr = pm.Constraint(m.bus_set, m.scen_set, rule=PowerBal_constr) def Branch_Flow(model, i, s): From_ix = Branch.From_Bus[i] To_ix = Branch.To_Bus[i] B = Elecdata.Params.BaseMVA / Branch.BR_X_PU[i] return m.Pij[i, s] == (B) * (m.th[From_ix, s] - m.th[To_ix, s]) m.branchflow = pm.Constraint(m.branch_set, m.scen_set, rule=Branch_Flow) def SlackNode(model, i, s): if Bus.Bus_Type[i] == 3: return m.th[i, s] == 0 else: return pm.Constraint.Skip m.slack = pm.Constraint(m.bus_set, m.scen_set, rule=SlackNode) def Power_UB_LB(model, i, s): Binary_LB = TruthTable[i][s] # Truth table index Binary_UB = 1 - Binary_LB return m.P[i, s] == Binary_UB * m.P_UB[i] + Binary_LB * m.P_LB[i] m.Power_UB_LB = pm.Constraint(m.gasgen_set, m.scen_set, rule=Power_UB_LB) def Costs(model, s): return sum(Gen.CostCoeff_1[k] * m.P[k, s] for k in m.gen_set) <= Elecdata.Params.C_max_RO m.Costs = pm.Constraint(m.scen_set, rule=Costs) def Shed(model, i): return m.P_Shed[i] == Gen.DC_OPF_RES[i] - m.P_LB[i] m.shed = pm.Constraint(m.gasgen_set, rule=Shed) def Add(model, i): return m.P_Add[i] == m.P_UB[i] - Gen.DC_OPF_RES[i] m.add = pm.Constraint(m.gasgen_set, rule=Add) def DC_OPF_Obj(model): return sum(Gen.AddWeight[i] * m.P_Add[i] + Gen.ShedWeight[i] * m.P_Shed[i] for i in m.gasgen_set) m.objective = pm.Objective(rule=DC_OPF_Obj, sense=pm.maximize, doc='Define objective function') opt = pm.SolverFactory('ipopt') opt.options['print_level'] = 5 # Optimize print('Starting Optimization') results = opt.solve(m, tee=True) status = 0 if (results.solver.status == SolverStatus.ok) and (results.solver.termination_condition == TerminationCondition.optimal): print('Model Solved to Optimality') status = 1 # Do something when the solution in optimal and feasible elif (results.solver.termination_condition == TerminationCondition.infeasible): print('Model is infeasible') # Do something when model in infeasible else: print('Solver Status: ', results.solver.status) UB_Res = dict([[i, np.round(m.P_UB[i].value, decimals=8)] for i in m.P_UB]) LB_Res = dict([[i, np.round(m.P_LB[i].value, decimals=8)] for i in m.P_LB]) P_Shed = dict([[i, np.round(m.P_Shed[i].value, decimals=8)] for i in m.P_Shed]) P_Add = dict([[i, np.round(m.P_Add[i].value, decimals=8)] for i in m.P_Add]) Elecdata.Gen = Elecdata.Gen.assign(DC_RO_OPF_P_UB=pd.Series(UB_Res)) Elecdata.Gen = Elecdata.Gen.assign(DC_RO_OPF_P_LB=pd.Series(LB_Res)) Elecdata.Gen = Elecdata.Gen.assign(P_Shed=pd.Series(P_Shed)) Elecdata.Gen = Elecdata.Gen.assign(P_Add=pd.Series(P_Add)) #Elecdata.Gen = Elecdata.Gen.combine(pd.DataFrame.from_dict(LB_Res,orient='index',columns=['DC_RO_OPF_P_LB'])) # Unload results Pc = pd.DataFrame(columns=[Gen.index.tolist() + ['Cost', 'Max Cost']], index=TruthTable.index.tolist()) for s in m.scen_set: for g in m.gen_set: Pc.loc[s][g] = m.P[g, s].value Pc.loc[s]['Cost'] = m.Costs[s].body() Pc.loc[s]['Max Cost'] = m.Costs[s].upper() Pc.index = ['Case' + str(x) for x in range(0, len(Pc))] Pc = Pc.astype(float).round(decimals=1) Elecdata.Params.Cases = Pc Elecdata.Params.RO_OPF_Obj = m.objective() Elecdata.Params.status = status
within=pyEnv.NonNegativeIntegers, bounds=(0, n - 1)) #Cost Matrix cij model.c = pyEnv.Param(model.N, model.M, initialize=lambda model, i, j: cost_matrix[i - 1][j - 1]) ##-------------------------OBJECTIVE FUNCTION AND CONSTRAINTS--------------------## def obj_func(model): return sum(model.x[i, j] * model.c[i, j] for i in model.N for j in model.M) model.objective = pyEnv.Objective(rule=obj_func, sense=pyEnv.minimize) ##------------------------------------------------------## #Only 1 leaves each city def rule_const1(model, M): return sum(model.x[i, M] for i in model.N if i != M) == 1 model.const1 = pyEnv.Constraint(model.M, rule=rule_const1) ##------------------------------------------------------## #Only 1 enters each city def rule_const2(model, N):
def build_time_block(t0: int, delta_t: int, num_finite_elements: int, constant_control_duration: int, time_scale: float) -> _BlockData: """ Parameters ---------- t0: int start time delta_t: float end time num_finite_elements: number of finite elements constant_control_duration: number of finite elements over which the control (p) is constant time_scale: float coefficient of t within the sin function Returns ------- m: _BlockData The Pyomo model """ assert constant_control_duration >= delta_t assert constant_control_duration % delta_t == 0 assert (num_finite_elements * delta_t) % constant_control_duration == 0 def finite_element_ndx_to_start_t_x(ndx): return t0 + ndx * delta_t def finite_element_ndx_to_end_t_x(ndx): return t0 + (ndx + 1) * delta_t def finite_element_ndx_to_start_t_p(ndx): return t0 + (math.floor( ndx / (constant_control_duration / delta_t))) * constant_control_duration m = pe.Block(concrete=True) m.x_time_points = pe.Set(initialize=[ t for t in range(t0, t0 + delta_t * (num_finite_elements + 1), delta_t) ]) m.x = pe.Var(m.x_time_points) num_p_elements = int( (num_finite_elements * delta_t) / constant_control_duration) m.p_time_points = pe.Set(initialize=[ t for t in range(t0, t0 + constant_control_duration * num_p_elements, constant_control_duration) ]) bnds = (None, 2) m.p = pe.Var(m.p_time_points, bounds=bnds) obj_expr = 0 for fe_ndx in range(num_finite_elements): start_t_x = finite_element_ndx_to_start_t_x(fe_ndx) end_t_x = finite_element_ndx_to_end_t_x(fe_ndx) obj_expr += 0.5 * delta_t * ( (m.x[start_t_x] - (math.sin(time_scale * start_t_x) + 1))**2 + (m.x[end_t_x] - (math.sin(time_scale * end_t_x) + 1))**2) m.obj = pe.Objective(expr=obj_expr) m.con_indices = pe.Set(initialize=[t for t in m.x_time_points if t > t0]) m.cons = pe.Constraint(m.con_indices) for fe_ndx in range(num_finite_elements): start_t_x = finite_element_ndx_to_start_t_x(fe_ndx) end_t_x = finite_element_ndx_to_end_t_x(fe_ndx) start_t_p = finite_element_ndx_to_start_t_p(fe_ndx) m.cons[end_t_x] = m.x[end_t_x] - (m.x[start_t_x] + delta_t * (m.p[start_t_p] - m.x[end_t_x])) == 0 return m
# Diametro de particula #################################### """ m.dps = dps.h_k_model() # Restricciones de ensamble m.split_dp = pe.ConstraintList() m.split_dp.add(expr = m.CPh.Rho == m.dps.c_den) m.split_dp.add(expr = m.Sr['prop'] == m.dps.Sr) m.split_dp.add(expr = m.ti == m.dps.st) m.split_dp.add(expr = m.DPh.Dmu == m.dps.d_mu) #### m.split_dp.add(expr = m.dM == m.dps.dD) m.split_dp.pprint() """ ######################### # Caso de estudio ########################333 m.obj = pe.Objective(expr=-m.mu["appl"]) opt.solve(m, tee=True) m.oldy.pprint() CPh.mass_flow.pprint() m.k.pprint()
def constraint_autoscale_large_jac(m, ignore_constraint_scaling=False, ignore_variable_scaling=False, max_grad=100, min_scale=1e-6, no_scale=False): """Automatically scale constraints based on the Jacobian. This function imitates Ipopt's default constraint scaling. This scales constraints down to avoid extremely large values in the Jacobian. This function also returns the unscaled and scaled Jacobian matrixes and the Pynumero NLP which can be used to identify the constraints and variables corresponding to the rows and comlumns. Args: m: model to scale ignore_constraint_scaling: ignore existing constraint scaling ignore_variable_scaling: ignore existing variable scaling max_grad: maximum value in Jacobian after scaling, subject to minimum scaling factor restriction. min_scale: minimum scaling factor allowed, keeps constraints from being scaled too much. no_scale: just calculate the Jacobian and scaled Jacobian, don't scale anything Returns: unscaled Jacobian CSR from, scaled Jacobian CSR from, Pynumero NLP """ # Pynumero requires an objective, but I don't, so let's see if we have one n_obj = 0 for c in m.component_data_objects(pyo.Objective, active=True): n_obj += 1 # Add an objective if there isn't one if n_obj == 0: dummy_objective_name = unique_component_name(m, "objective") setattr(m, dummy_objective_name, pyo.Objective(expr=0)) # Create NLP and calculate the objective nlp = PyomoNLP(m) jac = nlp.evaluate_jacobian().tocsr() # Get lists of varibles and constraints to translate Jacobian indexes # save them on the NLP for later, since genrating them seems to take a while nlp.clist = clist = nlp.get_pyomo_constraints() nlp.vlist = vlist = nlp.get_pyomo_variables() # Create a scaled Jacobian to account for variable scaling, for now ignore # constraint scaling jac_scaled = jac.copy() for i, c in enumerate(clist): for j in jac_scaled[i].indices: v = vlist[j] if ignore_variable_scaling: sv = 1 else: sv = get_scaling_factor(v, default=1) jac_scaled[i, j] = jac_scaled[i, j] / sv # calculate constraint scale factors for i, c in enumerate(clist): sc = get_scaling_factor(c, default=1) if not no_scale: if (ignore_constraint_scaling or get_scaling_factor(c) is None): row = jac_scaled[i] for d in row.indices: row[0, d] = abs(row[0, d]) mg = row.max() if mg > max_grad: sc = max(min_scale, max_grad / mg) set_scaling_factor(c, sc) for j in jac_scaled[i].indices: # update the scaled jacobian jac_scaled[i, j] = jac_scaled[i, j] * sc # delete dummy objective if n_obj == 0: delattr(m, dummy_objective_name) return jac, jac_scaled, nlp
def filterpyomofit(self, iterationNo): from pyomo import environ def lsqObjPyomo(model): sum = 0 for index in range(model.trainingsize): p_ipo = model.pipo[index] q_ipo = model.qipo[index] P = 0 for i in model.prange: P += model.coeff[i] * p_ipo[i] Q = 0 for i in model.qrange: Q += model.coeff[i] * q_ipo[i - model.M] sum += (model.Y[index] * Q - P)**2 return sum def robustConstrPyomo(model, index): q_ipo = model.qipo[index] Q = 0 for i in model.qrange: Q += model.coeff[i] * q_ipo[i - model.M] return Q >= 1 if (self._strategy != 0): raise Exception( "strategy %d for fitstrategy, %s not yet implemented" % (self.strategy, self.fitstrategy)) # concrete model model = environ.ConcreteModel() model.dimrange = range(self._dim) model.prange = range(self.M) model.qrange = range(self.M, self.M + self.N) model.coeffrange = range(self.M + self.N) model.M = self._M model.N = self._N model.trainingsize = self.trainingsize model.trainingsizerangeforconstr = range(self._trainingsize + iterationNo) model.pipo = self._ipo[:, 0].tolist() model.qipo = self._ipo[:, 1].tolist() model.Y = self._Y.tolist() model.coeff = environ.Var(model.coeffrange) for d in range(self.M + self.N): model.coeff[d].value = 1 model.coeff[self.M].value = 2 model.lsqfit = environ.Objective(rule=lsqObjPyomo, sense=1) model.robustConstr = environ.Constraint( model.trainingsizerangeforconstr, rule=robustConstrPyomo) opt = environ.SolverFactory('filter') # opt.options['eps'] = 1e-10 # opt.options['iprint'] = 1 pyomodebug = self._filterpyomodebug if (pyomodebug == 0): ret = opt.solve(model) elif (pyomodebug == 1): import uuid uniquefn = str(uuid.uuid4()) logfn = "/tmp/%s.log" % (uniquefn) print("Log file name: %s" % (logfn)) ret = opt.solve(model, tee=True, logfile=logfn) model.pprint() ret.write() elif (pyomodebug == 2): opt.options['iprint'] = 1 logfn = "%s/%s_p%d_q%d_ts%s_i%d.log" % ( self._debugfolder, self._fnname, self.m, self.n, self.trainingscale, iterationNo) self.printDebug("Starting filter") ret = opt.solve(model, logfile=logfn) optstatus = { 'message': str(ret.solver.termination_condition), 'status': str(ret.solver.status), 'time': ret.solver.time, 'error_rc': ret.solver.error_rc } coeffs = np.array( [model.coeff[i].value for i in range(self._M + self._N)]) leastSq = model.lsqfit() return coeffs, leastSq, optstatus
#Only for electricity we have charge and dischare efficiency; for the heat storage, we have thermal loss and therefore dissipation efficiency. eta_ch ={'BAT':0.97} eta_disch = {'BAT':0.97} eta_diss = {'TES':0.995} ##Obejctive Function #We have to add the fuel cost, the O&M Cost and the Sold-Bought Electricity the function obj_func does this def obj_func(m): machine_fuel_cost = sum(Fuel_cost[i]*m.f[i,t] for i in m.I_f for t in m.T) machine_OM_cost = sum(OM_cost[i]*m.z[i,t] for i in m.I for t in m.T) machine_SU_cost = sum(SU_cost[i]*m.dSU[i,t] for i in m.I for t in m.T) grid_SellBuy = sum(El_price_buy[t]*m.El_buy[t] - El_price_sell[t]*m.El_sell[t] for t in m.T) return machine_fuel_cost + machine_OM_cost + machine_SU_cost + grid_SellBuy #This is the syntax to minimize the objective function. m.obj = pyo.Objective(rule = obj_func, sense = pyo.minimize) ##Constrains #El balance #This function returns if the electric balance is satisfied. #We basically set a rule as a function and then assign it to a constraint by the pyomo's module. def el_balance_rule(m,t): return sum(m.p[i,t] for i in m.I_el) - sum(m.el_in[i,t] for i in m.I_el_consum) + m.El_buy[t] - m.El_sell[t] + sum(m.Discharge[s,t] for s in m.S_el) - sum(m.Charge[s,t] for s in m.S_el) == d_el[t] m.el_balance_con = pyo.Constraint(m.T, rule = el_balance_rule) #Th balance #for the Heat Balance, we do the same as the electricity balance def th_balance_rule(m,t): return sum(m.q[i,t] for i in m.I_th) + sum(m.Discharge[s,t] for s in m.S_th) - sum(m.Charge[s,t] for s in m.S_th) == d_th[t] m.th_balance_con = pyo.Constraint(m.T, rule = th_balance_rule)
def pyomoRobO(self, coeffs, threshold=0.2, solver='filter', r=0): from pyomo import environ def robObjPyomo(model): res = 0 for l in range(len(model.struct_q)): mon = model.struct_q[l] term = 1 for d in model.dimrange: try: exp = mon[d] except: exp = mon term *= model.x[d]**exp res += model.coeffs[l + model.M] * term return res def variableBound(model, i): b = (model.box[i][0], model.box[i][1]) return b model = environ.ConcreteModel() model.struct_q = self._struct_q.tolist() model.coeffs = coeffs.tolist() model.dimrange = range(self._dim) model.box = self.box.tolist() model.M = self._M model.x = environ.Var(model.dimrange, bounds=variableBound) if (r == 0): for d in range(self.dim): model.x[d].value = (self.box[d][0] + self.box[d][1]) / 2 else: for d in range(self.dim): model.x[d].value = np.random.rand() * ( self.box[d][1] - self.box[d][0]) + self.box[d][0] model.robO = environ.Objective(rule=robObjPyomo, sense=1) opt = environ.SolverFactory(solver) """ Control where the log file is written by passing logfile=<name> to the solve method. If you want to print solver log to console, add tee=True to solve method If you want the solution and problem files to be logged, you can set keepfiles=True for that file to not be deleted. Also, if you set keepfiles to True, you can find the location of Solver log file, Solver problem files, and Solver solution file printed on console (usually located in /var/folders/) """ pyomodebug = 0 if (pyomodebug == 0): ret = opt.solve(model) elif (pyomodebug == 1): import uuid uniquefn = str(uuid.uuid4()) logfn = "/tmp/%s.log" % (uniquefn) print("Log file name: %s" % (logfn)) ret = opt.solve(model, tee=True, logfile=logfn) model.pprint() ret.write() optstatus = { 'message': str(ret.solver.termination_condition), 'status': str(ret.solver.status), 'time': ret.solver.time, 'error_rc': ret.solver.error_rc } robO = model.robO() x = np.array([model.x[i].value for i in range(self._dim)]) # info = [{'robustArg':x.tolist(),'robustObj':robO,'log':optstatus}] return x, robO, optstatus
#tir set TL.tir = pe.Set() #trucks' maximum capacity (cubic meters) TL.maxcap = pe.Param() #0-1 variable for trucks (used/not used) TL.y = pe.Var(TL.tir, within=pe.Binary) #quantity matrix of i pallet in j truck, pallets being non partitionable TL.x = pe.Var(TL.pallet, TL.tir, within=pe.NonNegativeIntegers) #objective function, minimize trucks def mintir_rule(m): return sum(m.y[j] for j in m.tir) TL.mintir = pe.Objective(rule=mintir_rule) #capacity constraint, each truck cannot be filled more than a given number. def maxload_rule(m, j): return sum(m.x[i, j] * m.vol[i] for i in m.pallet) <= m.y[j] * m.maxcap TL.maxload = pe.Constraint(TL.tir, rule=maxload_rule) #quantity demand constraint, delivered pallets must be demanded pallets def qtaric_rule(m, i): return sum(m.x[i, j] for j in m.tir) == m.qta[i]
def post_iter0(self): opt = self.opt # NOTE: the LShaped code negates the objective, so # we do the same here for consistency if 'cross_scen_options' in opt.options and \ 'valid_eta_bound' in opt.options['cross_scen_options']: valid_eta_bound = opt.options['cross_scen_options'][ 'valid_eta_bound'] if not opt.is_minimizing: _eta_init = {k: -v for k, v in valid_eta_bound.items()} else: _eta_init = valid_eta_bound _eta_bounds = lambda m, k: (_eta_init[k], None) else: lb = (-sys.maxsize - 1) * 1. / len(opt.all_scenario_names) _eta_init = lambda m, k: lb _eta_bounds = lambda m, k: (lb, None) # eta is attached to each subproblem, regardless of bundles bundling = opt.bundling for k, s in opt.local_subproblems.items(): s.eta = pyo.Var(opt.all_scenario_names, initialize=_eta_init, bounds=_eta_bounds) if sputils.is_persistent(s._solver_plugin): for var in s.eta.values(): s._solver_plugin.add_var(var) if bundling: ## create a refence to eta on each subproblem for sn in s.scen_list: scenario = opt.local_scenarios[sn] scenario.eta = { k: s.eta[k] for k in opt.all_scenario_names } ## hold the PH object harmless self._disable_W_and_prox() for k, s in opt.local_subproblems.items(): obj = find_active_objective(s) repn = generate_standard_repn(obj.expr, quadratic=True) if len(repn.nonlinear_vars) > 0: raise ValueError( "CrossScenario does not support models with nonlinear objective functions" ) if bundling: ## NOTE: this is slighly wasteful, in that for a bundle ## the first-stage cost appears len(s.scen_list) times ## If this really made a difference, we could use s.ref_vars ## to do the substitution nonant_vardata_list = list() for sn in s.scen_list: nonant_vardata_list.extend( \ opt.local_scenarios[sn]._PySPnode_list[0].nonant_vardata_list) else: nonant_vardata_list = s._PySPnode_list[0].nonant_vardata_list nonant_ids = set((id(var) for var in nonant_vardata_list)) linear_coefs = list(repn.linear_coefs) linear_vars = list(repn.linear_vars) quadratic_coefs = list(repn.quadratic_coefs) # adjust coefficients by scenario/bundle probability scen_prob = s.PySP_prob for i, var in enumerate(repn.linear_vars): if id(var) not in nonant_ids: linear_coefs[i] *= scen_prob for i, (x, y) in enumerate(repn.quadratic_vars): # only multiply through once if id(x) not in nonant_ids: quadratic_coefs[i] *= scen_prob elif id(y) not in nonant_ids: quadratic_coefs[i] *= scen_prob # NOTE: the LShaped code negates the objective, so # we do the same here for consistency if not opt.is_minimizing: for i, coef in enumerate(linear_coefs): linear_coefs[i] = -coef for i, coef in enumerate(quadratic_coefs): quadratic_coefs[i] = -coef # add the other etas if bundling: these_scenarios = set(s.scen_list) else: these_scenarios = [k] eta_scenarios = list() for sn in opt.all_scenario_names: if sn not in these_scenarios: linear_coefs.append(1) linear_vars.append(s.eta[sn]) eta_scenarios.append(sn) expr = LinearExpression(constant=repn.constant, linear_coefs=linear_coefs, linear_vars=linear_vars) if repn.quadratic_vars: expr += pyo.quicksum((coef * x * y for coef, ( x, y) in zip(quadratic_coefs, repn.quadratic_vars))) s._EF_obj = pyo.Expression(expr=expr) if opt.is_minimizing: s._EF_Obj = pyo.Objective(expr=s._EF_obj, sense=pyo.minimize) else: s._EF_Obj = pyo.Objective(expr=-s._EF_obj, sense=pyo.maximize) s._EF_Obj.deactivate() # add cut constraint dicts s._benders_cuts = pyo.Constraint(pyo.Any) s._ib_constr = pyo.Constraint(pyo.Any) self._enable_W_and_prox() # try to get the initial eta LB cuts # (may not be available) opt.spcomm.get_from_cross_cuts()
def test_linear_scaling(self): model = pyo.ConcreteModel() model.x = pyo.Var([1, 2, 3], bounds=(-10, 10), initialize=5.0) model.z = pyo.Var(bounds=(10, 20)) model.obj = pyo.Objective(expr=model.z + model.x[1]) # test scaling of duals as well model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) model.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT) def con_rule(m, i): if i == 1: return m.x[1] + 2*m.x[2] + 1*m.x[3] == 4.0 if i == 2: return m.x[1] + 2*m.x[2] + 2*m.x[3] == 5.0 if i == 3: return m.x[1] + 3.0*m.x[2] + 1*m.x[3] == 5.0 model.con = pyo.Constraint([1,2,3], rule=con_rule) model.zcon = pyo.Constraint(expr=model.z >= model.x[2]) x_scale = 0.5 obj_scale = 2.0 z_scale = -10.0 con_scale1 = 0.5 con_scale2 = 2.0 con_scale3 = -5.0 zcon_scale = -3.0 unscaled_model = model.clone() unscaled_model.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) unscaled_model.scaling_factor[unscaled_model.obj] = obj_scale unscaled_model.scaling_factor[unscaled_model.x] = x_scale unscaled_model.scaling_factor[unscaled_model.z] = z_scale unscaled_model.scaling_factor[unscaled_model.con[1]] = con_scale1 unscaled_model.scaling_factor[unscaled_model.con[2]] = con_scale2 unscaled_model.scaling_factor[unscaled_model.con[3]] = con_scale3 unscaled_model.scaling_factor[unscaled_model.zcon] = zcon_scale scaled_model = pyo.TransformationFactory('core.scale_model').create_using(unscaled_model) # print('*** unscaled ***') # unscaled_model.pprint() # print('*** scaled ***') # scaled_model.pprint() glpk_solver = pyo.SolverFactory('glpk') if isinstance(glpk_solver, UnknownSolver) or \ (not glpk_solver.available()): raise unittest.SkipTest("glpk solver not available") glpk_solver.solve(unscaled_model) glpk_solver.solve(scaled_model) # check vars self.assertAlmostEqual(pyo.value(unscaled_model.x[1]), pyo.value(scaled_model.scaled_x[1])/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[2]), pyo.value(scaled_model.scaled_x[2])/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[3]), pyo.value(scaled_model.scaled_x[3])/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.z), pyo.value(scaled_model.scaled_z)/z_scale, 4) # check var lb self.assertAlmostEqual(pyo.value(unscaled_model.x[1].lb), pyo.value(scaled_model.scaled_x[1].lb)/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[2].lb), pyo.value(scaled_model.scaled_x[2].lb)/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[3].lb), pyo.value(scaled_model.scaled_x[3].lb)/x_scale, 4) # note: z_scale is negative, therefore, the inequality directions swap self.assertAlmostEqual(pyo.value(unscaled_model.z.lb), pyo.value(scaled_model.scaled_z.ub)/z_scale, 4) # check var ub self.assertAlmostEqual(pyo.value(unscaled_model.x[1].ub), pyo.value(scaled_model.scaled_x[1].ub)/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[2].ub), pyo.value(scaled_model.scaled_x[2].ub)/x_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.x[3].ub), pyo.value(scaled_model.scaled_x[3].ub)/x_scale, 4) # note: z_scale is negative, therefore, the inequality directions swap self.assertAlmostEqual(pyo.value(unscaled_model.z.ub), pyo.value(scaled_model.scaled_z.lb)/z_scale, 4) # check var multipliers (rc) self.assertAlmostEqual(pyo.value(unscaled_model.rc[unscaled_model.x[1]]), pyo.value(scaled_model.rc[scaled_model.scaled_x[1]])*x_scale/obj_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.rc[unscaled_model.x[2]]), pyo.value(scaled_model.rc[scaled_model.scaled_x[2]])*x_scale/obj_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.rc[unscaled_model.x[3]]), pyo.value(scaled_model.rc[scaled_model.scaled_x[3]])*x_scale/obj_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.rc[unscaled_model.z]), pyo.value(scaled_model.rc[scaled_model.scaled_z])*z_scale/obj_scale, 4) # check constraint multipliers self.assertAlmostEqual(pyo.value(unscaled_model.dual[unscaled_model.con[1]]),pyo.value(scaled_model.dual[scaled_model.scaled_con[1]])*con_scale1/obj_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.dual[unscaled_model.con[2]]),pyo.value(scaled_model.dual[scaled_model.scaled_con[2]])*con_scale2/obj_scale, 4) self.assertAlmostEqual(pyo.value(unscaled_model.dual[unscaled_model.con[3]]),pyo.value(scaled_model.dual[scaled_model.scaled_con[3]])*con_scale3/obj_scale, 4) # put the solution from the scaled back into the original pyo.TransformationFactory('core.scale_model').propagate_solution(scaled_model, model) # compare var values and rc with the unscaled soln for vm in model.component_objects(ctype=pyo.Var, descend_into=True): cuid = pyo.ComponentUID(vm) vum = cuid.find_component_on(unscaled_model) self.assertEqual((vm in model.rc), (vum in unscaled_model.rc)) if vm in model.rc: self.assertAlmostEqual(pyo.value(model.rc[vm]), pyo.value(unscaled_model.rc[vum]), 4) for k in vm: vmk = vm[k] vumk = vum[k] self.assertAlmostEqual(pyo.value(vmk), pyo.value(vumk), 4) self.assertEqual((vmk in model.rc), (vumk in unscaled_model.rc)) if vmk in model.rc: self.assertAlmostEqual(pyo.value(model.rc[vmk]), pyo.value(unscaled_model.rc[vumk]), 4) # compare constraint duals and value for model_con in model.component_objects(ctype=pyo.Constraint, descend_into=True): cuid = pyo.ComponentUID(model_con) unscaled_model_con = cuid.find_component_on(unscaled_model) self.assertEqual((model_con in model.rc), (unscaled_model_con in unscaled_model.rc)) if model_con in model.dual: self.assertAlmostEqual(pyo.value(model.dual[model_con]), pyo.value(unscaled_model.dual[unscaled_model_con]), 4) for k in model_con: mk = model_con[k] umk = unscaled_model_con[k] self.assertEqual((mk in model.dual), (umk in unscaled_model.dual)) if mk in model.dual: self.assertAlmostEqual(pyo.value(model.dual[mk]), pyo.value(unscaled_model.dual[umk]), 4)
else: return model.x[i]**2 model.e = pyo.Expression(N, rule=e_rule) # @:decl3 model.pprint() del e_rule model = None model = pyo.ConcreteModel() # @decl4: model.x = pyo.Var() model.e = pyo.Expression(expr=(model.x - 1.0)**2) model.o = pyo.Objective(expr=0.1 * model.e + model.x) model.c = pyo.Constraint(expr=model.e <= 1.0) # @:decl4 model.pprint() # @decl5: model.x.set_value(2.0) print(pyo.value(model.e)) # 1.0 print(pyo.value(model.o)) # 2.1 print(pyo.value(model.c.body)) # 1.0 model.e.set_value((model.x - 2.0)**2) print(pyo.value(model.e)) # 0.0 print(pyo.value(model.o)) # 2.0 print(pyo.value(model.c.body)) # 0.0
model.Demanda = pyo.Param(model.REF) model.Frecuencia = pyo.Param(model.REF) model.Costo = pyo.Param(model.RACKS) ## ---------------------- VARIABLES ---------------------------- model.x = pyo.Var(model.REF, model.RACKS, domain=pyo.Binary) model.y = pyo.Var(model.RACKS, domain=pyo.Binary) ## ---------------------- FUNCIÓN OBJETIVO ---------------------------- def ObjFunc(model): return sum(model.Demanda[ref] * model.Frecuencia[ref] * model.Costo[rack] * model.x[ref, rack] for ref in model.REF for rack in model.RACKS) model.FO = pyo.Objective(rule=ObjFunc) ## ---------------------- RESTRICCIONES ---------------------------- def r1(model, ref): return sum(model.x[ref, rack] for rack in model.RACKS) == 1 model.r1 = pyo.Constraint(model.REF, rule=r1) def r2(model, rack): return sum(model.AnchoCaja[ref] * model.x[ref, rack] for ref in model.REF) <= 250 * (1 - model.y[rack]) + 750 * (model.y[rack])
def DC_OPF_RO_TruthTable_ConstraintCheck(Elecdata, Cur_TruthTable): Gen = Elecdata.Gen Branch = Elecdata.Branch Bus = Elecdata.Bus GasGenerators = Gen[Gen.FuelType == 'Gas'].index.tolist() m = pm.ConcreteModel() m.gen_set = pm.Set(initialize=Gen.index.tolist()) m.branch_set = pm.Set(initialize=Branch.index.tolist()) m.bus_set = pm.Set(initialize=Bus.index.tolist()) m.gasgen_set = pm.Set(initialize=GasGenerators, within=m.gen_set, ordered=True) m.TruthTable = pm.Param(m.gasgen_set, mutable=True, initialize=lambda m, i: (Cur_TruthTable[i])) m.P_UB = pm.Param(m.gasgen_set, mutable=False, initialize=lambda m, i: (Gen.DC_RO_OPF_P_UB[i])) m.P_LB = pm.Param(m.gasgen_set, mutable=False, initialize=lambda m, i: (Gen.DC_RO_OPF_P_LB[i])) #m.P_UB = pm.Var(m.gasgen_set,bounds= lambda m,i : (Gen.DC_RO_OPF_P_UB[i],Gen.DC_RO_OPF_P_UB[i]),initialize=lambda m,i : Gen.DC_OPF_RES[i] ) #m.P_LB = pm.Var(m.gasgen_set,bounds= lambda m,i : (Gen.Pmin_MW[i],Gen.DC_OPF_RES[i]),initialize=lambda m,i : Gen.DC_OPF_RES[i] ) m.P = pm.Var(m.gen_set, bounds=lambda m, i: (Gen.Pmin_MW[i], Gen.Pmax_MW[i]), initialize=1) m.Pij = pm.Var(m.branch_set, bounds=lambda m, i: (-Branch.RateA_MVA[i], Branch.RateA_MVA[i]), initialize=1) m.th = pm.Var(m.bus_set, bounds=(-np.pi, np.pi), initialize=0) m.P_Shed = pm.Var(m.gasgen_set, bounds=(0, None)) m.P_Add = pm.Var(m.gasgen_set, bounds=(0, None)) def PowerBal_constr(model, i): PowerBal = -Bus.PD_MW[i] \ + sum(m.P[k] for k in Gen[Gen.Gen_Bus==i].index.tolist()) \ - sum(m.Pij[k] for k in Branch[Branch.From_Bus==i].index.tolist()) \ + sum(m.Pij[k] for k in Branch[Branch.To_Bus==i].index.tolist()) \ ==0 return PowerBal m.PowerBal_constr = pm.Constraint(m.bus_set, rule=PowerBal_constr) def Branch_Flow(model, i): From_ix = Branch.From_Bus[i] To_ix = Branch.To_Bus[i] B = Elecdata.Params.BaseMVA / Branch.BR_X_PU[i] return m.Pij[i] == (B) * (m.th[From_ix] - m.th[To_ix]) m.branchflow = pm.Constraint(m.branch_set, rule=Branch_Flow) def SlackNode(model, i): if Bus.Bus_Type[i] == 3: return m.th[i] == 0 else: return pm.Constraint.Skip m.slack = pm.Constraint(m.bus_set, rule=SlackNode) def Power_UB_LB(model, i): Binary_LB = m.TruthTable[i] # Truth table index Binary_UB = 1 - Binary_LB return m.P[i] == Binary_UB * m.P_UB[i] + Binary_LB * m.P_LB[i] m.Power_UB_LB = pm.Constraint(m.gasgen_set, rule=Power_UB_LB) def Costs(model): return sum(Gen.CostCoeff_1[k] * m.P[k] for k in m.gen_set) <= Elecdata.Params.C_max_RO m.Costs = pm.Constraint(rule=Costs) def Shed(model, i): return m.P_Shed[i] == Gen.DC_OPF_RES[i] - m.P_LB[i] m.shed = pm.Constraint(m.gasgen_set, rule=Shed) def Add(model, i): return m.P_Add[i] == m.P_UB[i] - Gen.DC_OPF_RES[i] m.add = pm.Constraint(m.gasgen_set, rule=Add) def DC_OPF_Obj(model): return sum(Gen.AddWeight[i] * m.P_Add[i] + Gen.ShedWeight[i] * m.P_Shed[i] for i in m.gasgen_set) m.objective = pm.Objective(rule=DC_OPF_Obj, sense=pm.maximize, doc='Define objective function') return m
# quantity of products that are to be produced for each month m.made = pe.Var(items, months, initialize=0, within=pe.NonNegativeReals) m.sold = pe.Var(items, months, initialize=0, within=pe.NonNegativeReals) m.stored = pe.Var(items, months, initialize=0, within=pe.NonNegativeReals) def rule_objective(m): # profit contribution per unit per item per month # storage cost 0.5 dollar per unit. expr1 = sum(m.sold[(pi, mon)] * profit[pi] - m.stored[(pi, mon)] * 0.5 for pi, mon in product(items, months)) return expr1 m.objective = pe.Objective(rule=rule_objective, sense=pe.maximize) # relative quantites constraint m.qrel = pe.ConstraintList() for i in items: # total constraints = 7* 7 = 49 m.qrel.add(m.stored[(i, 'jan')] == m.made[(i, 'jan')] - m.sold[(i, 'jan')]) m.qrel.add(m.stored[(i, 'feb')] == m.made[(i, 'feb')] + m.stored[(i, 'jan')] - m.sold[(i, 'feb')]) m.qrel.add(m.stored[(i, 'mar')] == m.made[(i, 'mar')] + m.stored[(i, 'feb')] - m.sold[(i, 'mar')]) m.qrel.add(m.stored[(i, 'apr')] == m.made[(i, 'apr')] + m.stored[(i, 'mar')] - m.sold[(i, 'apr')]) m.qrel.add(m.stored[(i, 'may')] == m.made[(i, 'may')] + m.stored[(i, 'apr')] - m.sold[(i, 'may')]) m.qrel.add(m.stored[(i, 'jun')] == m.made[(i, 'jun')] + m.stored[(i, 'may')] - m.sold[(i, 'jun')])
#Matriz de custo cij modelo.c = pyEnv.Param( modelo.N, modelo.M, initialize=lambda modelo, i, j: custoMatrix[i - 1][j - 1]) ##-------------------------DECLARACAO DA FUNCAO OBJETIVO E RESTRICOES--------------------## def func_objetivo(modelo): return sum(modelo.x[i, j] * modelo.c[i, j] for i in modelo.N for j in modelo.M) modelo.objetivo = pyEnv.Objective(rule=func_objetivo, sense=pyEnv.minimize) ##------------------------------------------------------## #So sai 1 caminho de cada cidade def rule_rest1(modelo, M): return sum(modelo.x[i, M] for i in modelo.N if i != M) == 1 modelo.rest1 = pyEnv.Constraint(modelo.M, rule=rule_rest1) ##------------------------------------------------------## #So entra 1 caminho em cada cidade def rule_rest2(modelo, N):