def pysp2_callback(scenario_name, node_names=None, cb_data=None): """ mpisppy signature for scenario creation. Then find a starting solution for the scenario if solver option is not None. Note that stage numbers are one-based. Args: scenario_name (str): put the scenario number on the end node_names (int): not used cb_data: (dict) "etree", "solver", "epath", "tee", "acstream" Returns: scenario (pyo.ConcreteModel): the scenario instance Attaches: _enodes (ACtree nodes): a list of the ACtree tree nodes _egret_md (egret tuple with dict as [1]) egret model data """ # pull the number off the end of the scenario name scen_num = sputils.extract_num(scenario_name) etree = cb_data["etree"] solver = cb_data["solver"] acstream = cb_data["acstream"] # seed each scenario every time to avoid troubles acstream.seed(etree.seed + scen_num) def lines_up_and_down(stage_md_dict, enode): # local routine to configure the lines in stage_md_dict for the scenario LinesDown = [] for f in enode.FailedLines: LinesDown.append(f[0]) for this_branch in stage_md_dict.elements("branch"): if this_branch[0] in enode.LinesUp: this_branch[1]["in_service"] = True elif this_branch[0] in LinesDown: this_branch[1]["in_service"] = False else: print("enode.LinesUp=", enode.LinesUp) print("enode.FailedLines=", enode.FailedLines) raise RuntimeError("Branch (line) {} neither up nor down in scenario {}".\ format(this_branch[0], scenario_name)) # pull the number off the end of the scenario name scen_num = sputils.extract_num(scenario_name) #print ("debug scen_num=",scen_num) numstages = etree.NumStages enodes = etree.Nodes_for_Scenario(scen_num) full_scenario_model = pyo.ConcreteModel() full_scenario_model.stage_models = dict() # the exact acopf model is hard-wired here: acopf_model = eac.create_riv_acopf_model # look at egret/data/model_data.py for the format specification of md_dict first_stage_md_dict = _md_dict(cb_data) generator_set = first_stage_md_dict.attributes("generator") generator_names = generator_set["names"] # the following creates the first stage model full_scenario_model.stage_models[1], model_dict = acopf_model( first_stage_md_dict, include_feasibility_slack=True) full_scenario_model.stage_models[1].obj.deactivate() setattr(full_scenario_model, "stage_models_" + str(1), full_scenario_model.stage_models[1]) for stage in range(2, numstages + 1): #print ("stage={}".format(stage)) stage_md_dict = copy.deepcopy(first_stage_md_dict) #print ("debug: processing node {}".format(enodes[stage-1].Name)) lines_up_and_down(stage_md_dict, enodes[stage - 1]) full_scenario_model.stage_models[stage], model_dict = \ acopf_model(stage_md_dict, include_feasibility_slack=True) full_scenario_model.stage_models[stage].obj.deactivate() setattr(full_scenario_model, "stage_models_" + str(stage), full_scenario_model.stage_models[stage]) def aggregate_ramping_rule(m): """ We are adding ramping to the obj instead of a constraint for now because we may not have ramp limit data. """ retval = 0 for stage in range(1, numstages): retval += sum((full_scenario_model.stage_models[stage+1].pg[this_gen]\ - full_scenario_model.stage_models[stage].pg[this_gen])**2\ for this_gen in generator_names) return retval full_scenario_model.ramping = pyo.Expression(rule=aggregate_ramping_rule) full_scenario_model.objective = pyo.Objective(expr=\ 1000000.0 * full_scenario_model.ramping+\ sum(full_scenario_model.stage_models[stage].obj.expr\ for stage in range(1,numstages+1))) inst = full_scenario_model # end code from PySP1 node_list = list() parent_name = None for sm1, enode in enumerate(etree.Nodes_for_Scenario(scen_num)): stage = sm1 + 1 if stage < etree.NumStages: node_list.append( scenario_tree.ScenarioNode( name=enode.Name, cond_prob=enode.CondProb, stage=stage, cost_expression=inst.stage_models[stage].obj, scen_name_list=enode.ScenarioList, nonant_list=[ inst.stage_models[stage].pg, inst.stage_models[stage].qg ], scen_model=inst, parent_name=parent_name)) parent_name = enode.Name inst._PySPnode_list = node_list # Optionally assign probability to PySP_prob inst.PySP_prob = 1 / etree.numscens # solve it so subsequent code will have a good start if solver is not None: solver.solve(inst) # attachments inst._enodes = enodes inst._egret_md = first_stage_md_dict return inst
#Fabrica 1 c11 c12 #Fabrica 2 c21 c22 #Fabrica 3 c31 c32 #Custo de transporte da fabrica i pro cliente j cij = [[162, 247], [117, 193], [131, 185]] capacidades = [1000, 1500, 1200] demandas = [2300, 1400] m = len(capacidades) n = len(demandas) ##-------------------------DECLARACAO DO MODELO E SEUS PARAMETROS--------------------## #Modelo modelo = pyEnv.ConcreteModel() #Indice para as fabricas modelo.I = pyEnv.RangeSet(m) #Indice para os clientes modelo.J = pyEnv.RangeSet(n) #Variaveis de decisao xij modelo.x = pyEnv.Var(modelo.I, modelo.J, within=pyEnv.NonNegativeReals) #Custo de transporte da fabrica i pro cliente j modelo.c = pyEnv.Param(modelo.I, modelo.J, initialize=lambda modelo, i, j: cij[i - 1][j - 1]) #Capacidade de cada fabrica modelo.b = pyEnv.Param(modelo.I, initialize=lambda modelo, i: capacidades[i - 1])
def __init__(self, x, y, bigM=100, shrinkage=None, factor=2, nlambda=10, ngamma=10): ''' x (list lenth M): arrays of predictor variables y (list length M): arrays of response variables bigM (float): bigM parameter value ''' self.shrink = shrinkage self.factor = factor self.nlambda = nlambda self.ngamma = ngamma M = len(x) T = [_x.shape[0] for _x in x] _, P = x[0].shape # pyomo optimisation model model = pyo.ConcreteModel() ''' model properties ''' # number of regression models to fit model.M = M # number of input predictors model.P = P # number of observations model.T = T # ordered set of predictor indices model.oset_P = pyo.Set(name="indices: predictors", within=pyo.NonNegativeIntegers, initialize=list(range(P)), ordered=True) # ordered set of model indices model.oset_M = pyo.Set(name="indices: models", within=pyo.NonNegativeIntegers, initialize=range(M), ordered=True) ''' model parameters ''' # big M model.param_bigM = 100 # k: model sparsity model.param_k = pyo.Param( default=1, doc="maximum number of predictors to allow into models", within=pyo.PositiveIntegers, mutable=True) # lambda: simultaneous shrinkage parameter (ridge shrinkage) model.param_lambda = pyo.Param( initialize=0, doc="ridge-like simultaneous shrinkage parameter", within=pyo.NonNegativeReals, mutable=True) # gamma: l1 parameter model.param_gamma = pyo.Param( initialize=0, doc="lasso-like simultaneous shrinkage parameter", within=pyo.NonNegativeReals, mutable=True) ''' model variables ''' # beta: regression coefficients (continuous variables) model.beta = pyo.Var(model.oset_M, model.oset_P, domain=pyo.Reals) # z: selected variable indicator (binary variables) model.z = pyo.Var(model.oset_P, domain=pyo.Boolean) # betaaux model.beta_aux = pyo.Var(model.oset_P, domain=pyo.Reals) # betatilde model.beta_tilde = pyo.Var(model.oset_M, model.oset_P, [0, 1], domain=pyo.PositiveReals) ''' model arrays ''' model.Q = [x[m].T.dot(x[m]) for m in range(M)] model.R = [-2 * y[m].dot(x[m]) for m in range(M)] model.C = [y[m].T.dot(y[m]) for m in range(M)] # objective, simultaneous OLS model.OBJ = pyo.Objective(rule=Objective_mls, sense=pyo.minimize) # objective, l2 shrinkage model.OBJ_shrinkl2 = pyo.Objective(rule=Objective_mls_shrinkl2, sense=pyo.minimize) model.OBJ_shrinkl2.deactivate() # objective, l1 shrinkage model.OBJ_shrinkl1 = pyo.Objective(rule=Objective_mls_shrinkl1, sense=pyo.minimize) model.OBJ_shrinkl1.deactivate() ''' model constraints ''' # sparsity: total number of selected predictors (across M models) model.constr_sparsity = pyo.Constraint( expr=pyo.quicksum(model.z[p] for p in range(P)) <= model.param_k) # big M above model.constr_Mpos = pyo.Constraint( model.oset_M, model.oset_P, rule=lambda mod, m, p: mod.beta[m, p] <= mod.param_bigM * mod.z[p]) # big M below model.constr_Mneg = pyo.Constraint( model.oset_M, model.oset_P, rule=lambda mod, m, p: -mod.param_bigM * model.z[p] <= mod.beta[m, p]) # l1 shrink: additional constraints model.constr_betatildep = pyo.Constraint( model.oset_M, model.oset_P, rule=lambda mod, m, p: mod.beta[m, p] - mod.beta_aux[ p] <= mod.beta_tilde[m, p, 0] - mod.beta_tilde[m, p, 1]) model.constr_betatildep.deactivate() model.constr_betatilden = pyo.Constraint( model.oset_M, model.oset_P, rule=lambda mod, m, p: mod.beta[m, p] - mod.beta_aux[ p] >= mod.beta_tilde[m, p, 0] - mod.beta_tilde[m, p, 1]) model.constr_betatilden.deactivate() # asssign the pyomo model to the class self.model = model
def test_scaling_without_rename(self): m = pyo.ConcreteModel() m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.v1 = pyo.Var(initialize=10) m.v2 = pyo.Var(initialize=20) m.v3 = pyo.Var(initialize=30) def c1_rule(m): return m.v1 == 1e6 m.c1 = pyo.Constraint(rule=c1_rule) def c2_rule(m): return m.v2 == 1e-4 m.c2 = pyo.Constraint(rule=c2_rule) m.scaling_factor[m.v1] = 1.0 m.scaling_factor[m.v2] = 0.5 m.scaling_factor[m.v3] = 0.25 m.scaling_factor[m.c1] = 1e-5 m.scaling_factor[m.c2] = 1e5 values = {} values[id(m.v1)] = (m.v1.value, m.scaling_factor[m.v1]) values[id(m.v2)] = (m.v2.value, m.scaling_factor[m.v2]) values[id(m.v3)] = (m.v3.value, m.scaling_factor[m.v3]) values[id(m.c1)] = (pyo.value(m.c1.body), m.scaling_factor[m.c1]) values[id(m.c2)] = (pyo.value(m.c2.body), m.scaling_factor[m.c2]) m.c2_ref = pyo.Reference(m.c2) m.v3_ref = pyo.Reference(m.v3) scale = pyo.TransformationFactory('core.scale_model') scale.apply_to(m, rename=False) self.assertTrue(hasattr(m, 'v1')) self.assertTrue(hasattr(m, 'v2')) self.assertTrue(hasattr(m, 'c1')) self.assertTrue(hasattr(m, 'c2')) orig_val, factor = values[id(m.v1)] self.assertAlmostEqual( m.v1.value, orig_val * factor, ) orig_val, factor = values[id(m.v2)] self.assertAlmostEqual( m.v2.value, orig_val * factor, ) orig_val, factor = values[id(m.c1)] self.assertAlmostEqual( pyo.value(m.c1.body), orig_val * factor, ) orig_val, factor = values[id(m.c2)] self.assertAlmostEqual( pyo.value(m.c2.body), orig_val * factor, ) orig_val, factor = values[id(m.v3)] self.assertAlmostEqual( m.v3_ref[None].value, orig_val * factor, ) # Note that because the model was not renamed, # v3_ref is still intact. lhs = m.c2.expr.arg(0) monom_factor = lhs.arg(0) scale_factor = (m.scaling_factor[m.c2] / m.scaling_factor[m.v2]) self.assertAlmostEqual( monom_factor, scale_factor, )
# scont.py import pyomo.environ as pyo from pyomo.gdp import Disjunct, Disjunction L = [1, 2, 3] U = [2, 4, 6] index = [0, 1, 2] model = pyo.ConcreteModel() model.x = pyo.Var(index, within=pyo.Reals, bounds=(0, 20)) model.x_nonzero = pyo.Var(index, bounds=(0, 1)) # Each disjunction is a semi-continuous variable # x[k] == 0 or L[k] <= x[k] <= U[k] def d_0_rule(d, k): m = d.model() d.c = pyo.Constraint(expr=m.x[k] == 0) model.d_0 = Disjunct(index, rule=d_0_rule) def d_nonzero_rule(d, k): m = d.model() d.c = pyo.Constraint(expr=pyo.inequality(L[k], m.x[k], U[k])) d.count = pyo.Constraint(expr=m.x_nonzero[k] == 1) model.d_nonzero = Disjunct(index, rule=d_nonzero_rule)
def test_pyomo_external_model_ndarray_scaling(self): m = pyo.ConcreteModel() m.Pin = pyo.Var(initialize=100, bounds=(0, None)) m.c1 = pyo.Var(initialize=1.0, bounds=(0, None)) m.c2 = pyo.Var(initialize=1.0, bounds=(0, None)) m.F = pyo.Var(initialize=10, bounds=(0, None)) m.P1 = pyo.Var() m.P2 = pyo.Var() m.F_con = pyo.Constraint(expr=m.F == 10) m.Pin_con = pyo.Constraint(expr=m.Pin == 100) # simple parameter estimation test m.obj = pyo.Objective(expr=(m.P1 - 90)**2 + (m.P2 - 40)**2) # set scaling parameters for the pyomo variables and constraints m.scaling_factor = pyo.Suffix(direction=pyo.Suffix.EXPORT) m.scaling_factor[m.obj] = 0.1 # scale the objective m.scaling_factor[m.Pin] = 2.0 # scale the variable m.scaling_factor[m.c1] = 3.0 # scale the variable m.scaling_factor[m.c2] = 4.0 # scale the variable m.scaling_factor[m.F] = 5.0 # scale the variable m.scaling_factor[m.P1] = 6.0 # scale the variable m.scaling_factor[m.P2] = 7.0 # scale the variable m.scaling_factor[m.F_con] = 8.0 # scale the pyomo constraint m.scaling_factor[m.Pin_con] = 9.0 # scale the pyomo constraint # test that this all works with ndarray input as well cyipopt_problem = \ PyomoExternalCyIpoptProblem(pyomo_model=m, ex_input_output_model=PressureDropModel(), inputs=[m.Pin, m.c1, m.c2, m.F], outputs=[m.P1, m.P2], outputs_eqn_scaling=np.asarray([10.0, 11.0], dtype=np.float64) ) # solve the problem options = { 'hessian_approximation': 'limited-memory', 'nlp_scaling_method': 'user-scaling', 'output_file': '_cyipopt-pyomo-ext-scaling-ndarray.log', 'file_print_level': 10, 'max_iter': 0 } solver = CyIpoptSolver(cyipopt_problem, options=options) x, info = solver.solve(tee=False) with open('_cyipopt-pyomo-ext-scaling-ndarray.log', 'r') as fd: solver_trace = fd.read() os.remove('_cyipopt-pyomo-ext-scaling-ndarray.log') self.assertIn('nlp_scaling_method = user-scaling', solver_trace) self.assertIn('output_file = _cyipopt-pyomo-ext-scaling-ndarray.log', solver_trace) self.assertIn('objective scaling factor = 0.1', solver_trace) self.assertIn('x scaling provided', solver_trace) self.assertIn('c scaling provided', solver_trace) self.assertIn('d scaling provided', solver_trace) self.assertIn('DenseVector "x scaling vector" with 7 elements:', solver_trace) self.assertIn('x scaling vector[ 1]= 6.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 2]= 7.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 3]= 2.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 4]= 3.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 5]= 4.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 6]= 5.0000000000000000e+00', solver_trace) self.assertIn('x scaling vector[ 7]= 1.0000000000000000e+00', solver_trace) self.assertIn('DenseVector "c scaling vector" with 5 elements:', solver_trace) self.assertIn('c scaling vector[ 1]= 8.0000000000000000e+00', solver_trace) self.assertIn('c scaling vector[ 2]= 9.0000000000000000e+00', solver_trace) self.assertIn('c scaling vector[ 3]= 1.0000000000000000e+00', solver_trace) self.assertIn('c scaling vector[ 4]= 1.0000000000000000e+01', solver_trace) self.assertIn('c scaling vector[ 5]= 1.1000000000000000e+01', solver_trace)
def get_future_position(base, fleet, rank): # return non-fix group pilot ids whose future position is input return set(future_base_dic[base] and future_fleet_dic[fleet] and future_rank_dic[rank]) base_dic = get_base_dic() rank_dic = get_rank_dic() fleet_dic = get_fleet_dic() def get_position(base, fleet, rank): # return fix group pilot ids whose position is input return set(base_dic[base] and fleet_dic[fleet] and rank_dic[rank]) ################################## #create the model model = pe.ConcreteModel() #get crew list crews=list(set(crew_df['Crew_ID'].values)) #define demand set a = set(1,2) a = {1,2} frbt_set=[] for t in range(26): for fleet in ['A320','A330']: for base in ['B1','B2']: for rank in ['CPT','FO']: frbt_set.append((fleet,rank,base,t)) model.frbt_set=pe.Set(initialize=frbt_set) ################################## #Option 1:
def Create_Model_Stg3(EDLP_Init, TPR_Init, single_comb): def EDLP_Initialize(Model, *Index): # return EDLP_Init[Index[0]] return 1 # def TPR_Initialize(Model, *Index): # return TPR_Init[Index[0]] class Temp: global PROMO_Initialize def PROMO_Initialize(Model, w, promo): # promo_init = Globals.historical_df.Promo_Events.tolist() # #flag_init = [(1 - x) for x in flag_init] # promo_init = np.array(promo_init).reshape(Globals.Tot_Prod, Globals.Tot_Week) # if promo_init[p,w]!=0: # if promo==(promo_init[p,w]-1): # return 1 # return 0 # else: # if promo==3: # return 1 # return 0 # if promo==0: # return 1 return 0 GLV.Model = pyo.ConcreteModel(name="Spend_Optim") GLV.Model.Weeks = pyo.Param( initialize=Globals.Tot_Week, domain=pyo.PositiveIntegers ) GLV.Model.PPGs = pyo.Param(initialize=Globals.Tot_Prod, domain=pyo.PositiveIntegers) GLV.Model.Wk_index = pyo.RangeSet(0, GLV.Model.Weeks - 1) GLV.Model.PPG_index = pyo.RangeSet(0, GLV.Model.PPGs - 1) # Model.EDLP = pyo.Var(Model.PPG_index, Model.Wk_index, initialize=EDLP_Initialize, domain=pyo.PositiveIntegers, # bounds=(Globals.EDLP_LB, Globals.EDLP_UB)) GLV.Model.EDLP = pyo.Param( GLV.Model.PPG_index, GLV.Model.Wk_index, initialize=EDLP_Initialize, domain=pyo.PositiveIntegers, ) # GLV.Model.TPR = pyo.Var(GLV.Model.PPG_index, GLV.Model.Wk_index, initialize=Globals.TPR_LB, domain=pyo.PositiveIntegers, # bounds=(Globals.TPR_LB, Globals.TPR_UB)) for prd in range(Globals.Tot_Prod): setattr( GLV.Model, f"Promos_PPG_{prd}", pyo.Param( initialize=len(Globals.TPR_Perc_Val[prd]), domain=pyo.PositiveIntegers ), ) setattr( GLV.Model, f"Promo_index_{prd}", pyo.RangeSet(0, getattr(GLV.Model, f"Promos_PPG_{0}") - 1), ) setattr( GLV.Model, f"TPR_FLAG_PPG_{prd}", pyo.Var( GLV.Model.Wk_index, getattr(GLV.Model, f"Promo_index_{prd}"), initialize=PROMO_Initialize, domain=pyo.Binary, ), ) # GLV.Model.display() # GLV.Model.TPR_FLAG = pyo.Var(GLV.Model.PPG_index,GLV.Model.Wk_index,GLV.Model.Promo_index,initialize=PROMO_Initialize,domain=pyo.Binary) GLV.Model.Obj = pyo.Objective(rule=Dollar_Sales_Fn, sense=pyo.maximize) # GLV.Model.Tot_Spent_Bnd = pyo.Constraint(GLV.Model.PPG_index, rule=Total_Trade_Spent_Bnd_Fn) # GLV.Model.EDLP_Bnd = pyo.Constraint(GLV.Model.PPG_index, rule=EDLP_Trade_Spent_Bnd_Fn) GLV.Model.TPR_Bnd = pyo.Constraint(GLV.Model.PPG_index, rule=TPR_Trade_Spent_Bnd_Fn) GLV.Model.Overall = pyo.Constraint(rule=Overall_Total_Trade_Spent_Fn) GLV.Model.Promo_con = pyo.Constraint( GLV.Model.PPG_index, GLV.Model.Wk_index, rule=Promo_constraint ) # Model.display() const_list = [ "51_52", "Promo_limits", "Promo_Consecutive", "Deep_Promo_Repeat", "Deep_Promo_Collective", "Promos_Rep_PR", "Weeks_Baseline", "Promo_Retailer_NFL", "TWP_Promo", "RSV_Constraint", "Cross_Ret_Clash_Constraint", "Cat_Clean_Air_Constraint", "Two_Calendar_Constraint", "Deep_Activity_Promo_Constraint", ] name_file = "" # single_comb = [True,True,True,True,True,False,False,True,False,True] for i, s in enumerate(single_comb): if s: name_file += const_list[i] + "_" # logger.info("#####------------ACK_PIN---------------###", name_file) # logger.info(single_comb) window_size = 4 Constraint_51_52(GLV.Model, single_comb[0]) Promo_limits(GLV.Model, single_comb[1]) Promo_Consective(GLV.Model, single_comb[2]) Deep_Promo_Repeat(GLV.Model, single_comb[3], window_size=window_size) # Deep_Promo_Repeat(Model,single_comb[4],window_size=4) Deep_Promo_Collective(GLV.Model, single_comb[4]) Promos_Rep_PR(GLV.Model, single_comb[5]) Weeks_Baseline(GLV.Model, single_comb[6]) Promo_Retailer_NFL(GLV.Model, single_comb[7]) TWP_Promo(GLV.Model, single_comb[8]) RSV_Dollar_Sales(GLV.Model, single_comb[9]) Cross_Ret_Clash_Constraint(GLV.Model, single_comb[10]) Same_Calendar_s3_Constraint(GLV.Model, single_comb[12]) Deep_Activity_Promo_Const_Fn(GLV.Model, single_comb[13]) # Model.display() return GLV.Model
def pysp_instance_creation_callback(scenario_name, node_names): model = aml.ConcreteModel() model.x = aml.Var() model.z = aml.Var() model.FirstStageCost = aml.Expression(expr=5 * (model.z**2 + (model.x - 1.1)**2)) model.SecondStageCost = aml.Expression(expr=0.0) model.ThirdStageCost = aml.Expression(expr=0.0) model.obj = aml.Objective(expr= model.FirstStageCost + \ model.SecondStageCost + \ model.ThirdStageCost) model.c = aml.ConstraintList() model.c.add(model.z == model.x) if scenario_name.startswith("u0"): # All scenarios under second-stage node "u0" model.xu0 = aml.Var() model.c.add(model.xu0 == model.x) model.SecondStageCost.expr = (model.xu0 - 1)**2 model.y0 = aml.Var() model.c.add(expr=-10 <= model.y0 <= 10) if scenario_name == "u00": model.yu00 = aml.Var() model.c.add(model.yu00 == model.y0) model.ThirdStageCost.expr = (model.yu00 + 1)**2 elif scenario_name == "u01": model.yu01 = aml.Var() model.c.add(model.yu01 == model.y0) model.ThirdStageCost.expr = (2 * model.yu01 - 3)**2 + 1 else: assert False elif scenario_name.startswith("u1"): # All scenarios under second-stage node "u1" model.xu1 = aml.Var() model.c.add(model.xu1 == model.x) model.SecondStageCost.expr = (model.xu1 + 1)**2 model.y1 = aml.Var() model.c.add(expr=-10 <= model.y1 <= 10) if scenario_name == "u10": model.yu10 = aml.Var() model.c.add(model.yu10 == model.y1) model.ThirdStageCost.expr = (0.5 * model.yu10 - 1)**2 - 1 elif scenario_name == "u11": model.yu11 = aml.Var() model.c.add(model.yu11 == model.y1) model.ThirdStageCost.expr = (0.2 * model.yu11)**2 else: assert False elif scenario_name.startswith("u2"): # All scenarios under second-stage node "u2" model.xu2 = aml.Var() model.c.add(model.xu2 == model.x) model.SecondStageCost.expr = (model.xu2 - 0.5)**2 model.y2 = aml.Var() model.c.add(expr=-10 <= model.y2 <= 10) if scenario_name == "u20": model.yu20 = aml.Var() model.c.add(model.yu20 == model.y2) model.ThirdStageCost.expr = (0.1 * model.yu20 - 3)**2 + 2 else: assert False else: assert False return model
def test_basics(self): m = pe.ConcreteModel() m.x = pe.Var(bounds=(-10, 10)) m.y = pe.Var() m.obj = pe.Objective(expr=m.x**2 + m.y**2) m.c1 = pe.Constraint(expr=m.y >= 2 * m.x + 1) opt = pe.SolverFactory('xpress_persistent') opt.set_instance(m) self.assertEqual(opt.get_xpress_attribute('cols'), 2) self.assertEqual(opt.get_xpress_attribute('rows'), 1) res = opt.solve() self.assertAlmostEqual(m.x.value, -0.4, delta=1e-6) self.assertAlmostEqual(m.y.value, 0.2, delta=1e-6) opt.load_duals() self.assertAlmostEqual(m.dual[m.c1], -0.4, delta=1e-6) del m.dual m.c2 = pe.Constraint(expr=m.y >= -m.x + 1) opt.add_constraint(m.c2) self.assertEqual(opt.get_xpress_attribute('cols'), 2) self.assertEqual(opt.get_xpress_attribute('rows'), 2) res = opt.solve(save_results=False, load_solutions=False) self.assertAlmostEqual(m.x.value, -0.4, delta=1e-6) self.assertAlmostEqual(m.y.value, 0.2, delta=1e-6) opt.load_vars() self.assertAlmostEqual(m.x.value, 0, delta=1e-6) self.assertAlmostEqual(m.y.value, 1, delta=2e-6) opt.remove_constraint(m.c2) m.del_component(m.c2) self.assertEqual(opt.get_xpress_attribute('cols'), 2) self.assertEqual(opt.get_xpress_attribute('rows'), 1) self.assertEqual(opt.get_xpress_control('feastol'), 1e-6) res = opt.solve(options={'feastol': '1e-7'}) self.assertEqual(opt.get_xpress_control('feastol'), 1e-7) self.assertAlmostEqual(m.x.value, -0.4, delta=1e-6) self.assertAlmostEqual(m.y.value, 0.2, delta=1e-6) m.x.setlb(-5) m.x.setub(5) opt.update_var(m.x) # a nice wrapper for xpress isn't implemented, # so we'll do this directly x_idx = opt._solver_model.getIndex( opt._pyomo_var_to_solver_var_map[m.x]) lb = [] opt._solver_model.getlb(lb, x_idx, x_idx) ub = [] opt._solver_model.getub(ub, x_idx, x_idx) self.assertEqual(lb[0], -5) self.assertEqual(ub[0], 5) m.x.fix(0) opt.update_var(m.x) lb = [] opt._solver_model.getlb(lb, x_idx, x_idx) ub = [] opt._solver_model.getub(ub, x_idx, x_idx) self.assertEqual(lb[0], 0) self.assertEqual(ub[0], 0) m.x.unfix() opt.update_var(m.x) lb = [] opt._solver_model.getlb(lb, x_idx, x_idx) ub = [] opt._solver_model.getub(ub, x_idx, x_idx) self.assertEqual(lb[0], -5) self.assertEqual(ub[0], 5) m.c2 = pe.Constraint(expr=m.y >= m.x**2) opt.add_constraint(m.c2) self.assertEqual(opt.get_xpress_attribute('cols'), 2) self.assertEqual(opt.get_xpress_attribute('rows'), 2) opt.remove_constraint(m.c2) m.del_component(m.c2) self.assertEqual(opt.get_xpress_attribute('cols'), 2) self.assertEqual(opt.get_xpress_attribute('rows'), 1) m.z = pe.Var() opt.add_var(m.z) self.assertEqual(opt.get_xpress_attribute('cols'), 3) opt.remove_var(m.z) del m.z self.assertEqual(opt.get_xpress_attribute('cols'), 2)
import pyomo.environ as py m = py.ConcreteModel() m.x11 = py.Var(within = py.NonNegativeIntegers) m.x12 = py.Var(within = py.NonNegativeIntegers) m.x13 = py.Var(within = py.NonNegativeIntegers) m.x21 = py.Var(within = py.NonNegativeIntegers) m.x22 = py.Var(within = py.NonNegativeIntegers) m.x23 = py.Var(within = py.NonNegativeIntegers) m.x31 = py.Var(within = py.NonNegativeIntegers) m.x32 = py.Var(within = py.NonNegativeIntegers) m.x33 = py.Var(within = py.NonNegativeIntegers) m.x41 = py.Var(within = py.NonNegativeIntegers) m.x42 = py.Var(within = py.NonNegativeIntegers) m.x43 = py.Var(within = py.NonNegativeIntegers) m.x51 = py.Var(within = py.NonNegativeIntegers) m.x52 = py.Var(within = py.NonNegativeIntegers) m.x53 = py.Var(within = py.NonNegativeIntegers) M = 100000000 def obj_rule(m): return (31*m.x11 + 45*m.x12 + 38*m.x13 + 29*m.x21 + 41*m.x22 + 35*m.x23 + 32*m.x31 + 46*m.x32 + 40*m.x33 +
# @model: import pyomo.environ as pyo m = pyo.ConcreteModel() m.x = pyo.Var() m.y = pyo.Var() m.obj = pyo.Objective(expr=m.x**2 + m.y**2) m.c = pyo.Constraint(expr=m.y >= -2 * m.x + 5) # @:model # @creation: opt = pyo.SolverFactory('gurobi_persistent') # @:creation # @set_instance: opt.set_instance(m) # @:set_instance # @solve: results = opt.solve() # @:solve print('Objective after solve 1: ', pyo.value(m.obj)) # @add_constraint: m.c2 = pyo.Constraint(expr=m.y >= m.x) opt.add_constraint(m.c2) # @:add_constraint # @solve2: results = opt.solve()
def __init__(self): self.model = pe.ConcreteModel() self.solver = pe.SolverFactory("couenne") self.top = 0
def create_copperplate_dispatch_approx_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') 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, _ = tx_utils.dict_of_bus_loads(buses, loads) libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads) model.pl.fix() ### declare the fixed shunts at the buses _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts) ### declare the generator real 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'])) ### include the feasibility slack for the system balance p_rhs_kwargs = {} if include_feasibility_slack: p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack( model, gen_attrs, bus_p_loads) ### declare the p balance libbus.declare_eq_p_balance_ed(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, **p_rhs_kwargs) ### declare the generator cost objective libgen.declare_expression_pgqg_operating_cost(model=model, index_set=gen_attrs['names'], p_costs=gen_attrs['p_cost']) 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 model.obj = pe.Objective(expr=obj_expr) return model, md
def test_project_to_F_obj_func(quadratic_NW): # TEST DESCRIPTION: Since project_to_F essentially adds an objective #function to the user defined feasible_set_C pyomo model and then solves the model #with gurobi, the main element to check is this objective function.: #We examined the objective function that project_to_F generates for the second unit test toy #problem’s initial zt by plugging in test values we generated in a separate MATLAB #script (generating_data.m) and comparing the objective function values between #the MATLAB answers and the project_to_F objective function values. #### Part 1: Defining the set C/F ##### feasible_c_region = pyo.ConcreteModel() feasible_c_region.varindex = pyo.RangeSet(1,3) feasible_c_region.c = pyo.Var(feasible_c_region.varindex) # Defining Constraints # # We need all constraints to be in the form of rules (including # if we have non-negativity constraints) def greater_than_zero(model,i): return 0 <= model.c[i] feasible_c_region.greater_than_zero_constraint = pyo.Constraint(feasible_c_region.varindex,\ rule=greater_than_zero) def less_than_one(model,i): return model.c[i] <= 1 feasible_c_region.less_than_one_constraint = pyo.Constraint(feasible_c_region.varindex,\ rule=less_than_one) quadratic_NW.feasible_set_C = feasible_c_region.clone() ######################################################### ## Part 2: Initialize the Model ## quadratic_NW.initialize_IO_method("BMPS_online_GD",alg_specific_params={'diam_flag':0}) #the first y_t_BMPS will be the c that we passed into the initialization #{1:-8,2:-3,3:-3} quadratic_NW.next_iteration(part_for_BMPS=1) #the first y_t_BMPS is the c data that gets fed into #the class when we create an instance of it ## Extracting the project_to_F model to check the objective function ## model_F = quadratic_NW.project_to_F_model.clone() ## Part 3: Test the Model ## ## Input 1 ## model_F.c[1] = 7 model_F.c[2] = 6 model_F.c[3] = -14 obj_value_F = round(pyo.value(model_F.obj_func(model_F)),1) assert obj_value_F == 427.0 ## Input 2 ## model_F.c[1] = -16 model_F.c[2] = 0 model_F.c[3] = 19 obj_value_F = round(pyo.value(model_F.obj_func(model_F)),1) assert obj_value_F == 557.0 ## Input 3 ## model_F.c[1] = -7 model_F.c[2] = 3 model_F.c[3] = -11 obj_value_F = round(pyo.value(model_F.obj_func(model_F)),1) assert obj_value_F == 101.0
def find_component(self, n, coeffs_centered): def norm(model): out = 0 for i in range(self.ndata): x_i = np.copy(coeffs_centered[i, :]) pt_i = np.copy(self.coeff_mat[i, :]) center = np.copy(self.bary) PT = [] for s in range(self.nbasis): vector = model.lamb[i] * model.w[s] PT.append(center[s] + vector) for h in range(model.nvar): for s in range(model.nvar): out += (PT[h] - pt_i[h]) * \ self.metric_aug[h, s]*(PT[s] - pt_i[s]) return out model = pyo.ConcreteModel() model.nvar = self.nbasis model.npoints = self.ndata model.w = pyo.Var(np.arange(model.nvar), domain=pyo.Reals, initialize=lambda m, i: self.initialization[i, n]) model.lamb = pyo.Var(np.arange(model.npoints), domain=pyo.Reals, initialize=1) model.obj = pyo.Objective(rule=norm, sense=pyo.minimize) model.costr = pyo.ConstraintList() # costraint ||w||_E=1 aux = 0 for i in range(model.nvar): aux += self.metric_aug[i, i] * model.w[i]**2 for j in range(i): aux += 2 * model.w[i] * model.w[j] * self.metric_aug[i, j] model.costr.add(aux == 1) # monothonicity contstraint for i in range(self.ndata): x_i = np.copy(coeffs_centered[i, :]) center = np.copy(self.bary) for s in range(n): eig = np.copy(self.eig_vecs[:, s]) center += eig * self.coords[i, s] for j in range(self.nbasis - 1): costr = sum([ self.constraints_mat[j, k] * (model.lamb[i] * model.w[k] + center[k]) for k in range(self.nbasis) ]) model.costr.add(costr <= 0) # orthogonality constraints wrt previous components if n > 0: for s in range(n): eig = np.copy(self.eig_vecs[:, s]) angle = 0 for h in range(model.nvar): for k in range(model.nvar): angle += model.w[h] * eig[k] * self.metric_aug[h, k] model.costr.add(angle == 0) solver = pyo.SolverFactory('ipopt') S = solver.solve(model) cost = model.obj() # needed to get argmin # TODO maybe find more intellingent way w_eval = np.ones((model.nvar, )) for key, val in model.w.extract_values().items(): w_eval[key] = val lamb_eval = np.ones((model.npoints, )) for key, val in model.lamb.extract_values().items(): lamb_eval[key] = val return w_eval, lamb_eval
def test_gradient_step(chan_lee_terekhov_linear_inequalities): #TEST DESCRIPTION: This test uses data we generated in a MATLAB script to #make sure that gradient_step does the correct calculations. We generate data for #eta_t, c_t, x_t, xbat_t, feed the data into gradient_step, and then check #the results against the MATLAB results. ### Setting things up ### chan_lee_terekhov_linear_inequalities.feasible_set_C = pyo.ConcreteModel() chan_lee_terekhov_linear_inequalities.initialize_IO_method("BMPS_online_GD",alg_specific_params={'diam_flag':0}) #this will set up the method ### Passing in Data (to the attributes) ### ## Test 1 ## chan_lee_terekhov_linear_inequalities.c_t_BMPS = {1:3,2:-34} chan_lee_terekhov_linear_inequalities.x_t_BMPS = np.array([[10],[-24]]) chan_lee_terekhov_linear_inequalities.xbar_t_BMPS = np.array([[16],[19]]) eta = 0.2294 z_t = chan_lee_terekhov_linear_inequalities.gradient_step(eta_t=eta,x_t=chan_lee_terekhov_linear_inequalities.x_t_BMPS) assert np.all(np.around(z_t,decimals=4) == np.array([[4.3764],[-24.1358]])) ## Test 2 ## chan_lee_terekhov_linear_inequalities.c_t_BMPS = {1:-5,2:-42} chan_lee_terekhov_linear_inequalities.x_t_BMPS = np.array([[-27],[42]]) chan_lee_terekhov_linear_inequalities.xbar_t_BMPS = np.array([[-35],[33]]) eta = 0.2000 z_t = chan_lee_terekhov_linear_inequalities.gradient_step(eta_t=eta,x_t=chan_lee_terekhov_linear_inequalities.x_t_BMPS) assert np.all(np.around(z_t,decimals=4) == np.array([[-6.6000],[-43.8000]])) ## Test 3 ## chan_lee_terekhov_linear_inequalities.c_t_BMPS = {1:32,2:37} chan_lee_terekhov_linear_inequalities.x_t_BMPS = np.array([[-42],[-10]]) chan_lee_terekhov_linear_inequalities.xbar_t_BMPS = np.array([[-24],[30]]) eta = 0.1890 z_t = chan_lee_terekhov_linear_inequalities.gradient_step(eta_t=eta,x_t=chan_lee_terekhov_linear_inequalities.x_t_BMPS) assert np.all(np.around(z_t,decimals=4) == np.array([[35.4020],[44.5600]]))
def optimize(data, config): # model model = pyomo.ConcreteModel() # parameters shippingcost = {x['seller']: x['shippingcost'] for x in data} distance = {x['seller']: x['distance'] for x in data} ordercount = {x['seller']: x['ordercount'] for x in data} # define sets I = list(set(x['product'] for x in data)) J = list(set(x['seller'] for x in data)) IJ = [(x['product'], x['seller']) for x in data] # decision vaiables model.x = pyomo.Var(IJ, domain=pyomo.Integers, bounds=(0, 1), doc='trans') model.y = pyomo.Var(J, domain=pyomo.Integers, bounds=(0, 1), doc='sellertrans') # constraints model.cons = pyomo.ConstraintList(doc='constraints') # transport to all demand for i in I: model.cons.add(sum([model.x[ij] for ij in model.x if ij[0] == i]) == 1) # seller transportation constraints maxtrans = len(IJ) for j in J: model.cons.add( sum([model.x[ij] for ij in model.x if ij[1] == j]) <= model.y[j] * maxtrans) # objective function shippingcost_penalty = 0 if sum(shippingcost.values()) == 0 \ else 1000000000 * (sum(model.y[j] * shippingcost[j] for j in J) / sum(shippingcost.values())) sellertotal_penalty = 0 if len(J) == 0 \ else 1000000 * (sum(model.y[j] for j in J) / len(J)) distance_penalty = 0 if sum(distance.values()) == 0 \ else 1000 * (sum(model.y[j] * distance[j] for j in J) / sum(distance.values())) ordercount_penalty = 0 if sum(ordercount.values()) == 0 \ else 1 * (sum(model.y[j] * ordercount[j] for j in J) / sum(ordercount.values())) model.obj = pyomo.Objective(expr=shippingcost_penalty + sellertotal_penalty + distance_penalty + ordercount_penalty, sense=pyomo.minimize) # solve if config['app']['solver_path'] == "None": s = SolverFactory(config['app']['solver']) else: s = SolverFactory(config['app']['solver'], executable=config['app']['solver_path']) status = s.solve(model) # gen output x = [] for ij in model.x: if model.x[ij].value > 0: x.append({ "product": ij[0], "seller": ij[1], "shippingcost": shippingcost[ij[1]], }) y = [] for j in model.y: if model.y[j].value > 0: y.append({ "seller": j, }) output = { "status_solver": str(status['Solver'][0]['Status']), "status_termination": str(status['Solver'][0]['Termination condition']), "total_shippingcost": sum([shippingcost[j['seller']] for j in y]), "total_sellers": len(y), "total_distance": sum([distance[j['seller']] for j in y]), "total_ordercount": sum([ordercount[j['seller']] for j in y]), "result": x } return output
def build_im_mip_model(env, bigm=10000, online=False): ''' Optimize base stock level (z variable) on a simulated sample path using an MILP. The existing sample path (historical demands) is used when running online. Notes: -z is constant in time (static base-stock policy) -Using the hull reformulation instead of big-M could speed things up. Using tighter big-M could also be helpful. -All parameters to the simulation environment must have been defined previously when making the environment. env = [InvManagementEnv] current simulation environment. bigm = [Float] big-M value for BM reformulation online = [Boolean] should the optimization be run online? ''' # assert env.spec.id == 'InvManagement-v0', \ # '{} received. Heuristic designed for InvManagement-v0.'.format(env.spec.id) #do not reset environment #big m values M = bigm BigM1 = M BigM2 = M BigM3 = -M BigM4 = -M BigM5 = -M BigM6 = -M #create model mip = pe.ConcreteModel() #define sets if online: mip.n = pe.RangeSet(0, env.period - 1) #periods mip.n1 = pe.RangeSet( 0, env.period ) #periods (includes an additional period for final inventories) else: mip.n = pe.RangeSet(0, env.num_periods - 1) mip.n1 = pe.RangeSet(0, env.num_periods) mip.m = pe.RangeSet(0, env.num_stages - 1) #stages mip.m0 = pe.RangeSet( 0, env.num_stages - 2) #stages (excludes last stage which has no inventory) #define parameters mip.unit_price = pe.Param(mip.m, initialize={i: env.unit_price[i] for i in mip.m }) #sales price for each stage mip.unit_cost = pe.Param(mip.m, initialize={i: env.unit_cost[i] for i in mip.m }) #purchasing cost for each stage mip.demand_cost = pe.Param(mip.m, initialize={ i: env.demand_cost[i] for i in mip.m }) #cost for unfulfilled demand at each stage mip.holding_cost = pe.Param(mip.m, initialize={ i: env.holding_cost[i] for i in mip.m }) #inventory holding cost at each stage mip.supply_capacity = pe.Param(mip.m0, initialize={ i: env.supply_capacity[i] for i in mip.m0 }) #production capacity at each stage mip.lead_time = pe.Param(mip.m0, initialize={i: env.lead_time[i] for i in mip.m0 }) #lead times in between stages mip.discount = env.discount #time-valued discount backlog = env.backlog #backlog or lost sales if online: #only use up to the current period mip.num_periods = env.period D = env.D[:env.period] else: #use full simulation if offline mip.num_periods = env.num_periods D = env.demand_dist.rvs(size=env.num_periods, **env.dist_param) mip.D = pe.Param(mip.n, initialize={i: D[i] for i in mip.n}) #store demands prob = env.demand_dist.pmf( D, **env.dist_param) #probability of each demand based on distribution mip.prob = pe.Param(mip.n, initialize={i: prob[i] for i in mip.n }) #store probability at each period #define variables mip.I = pe.Var( mip.n1, mip.m0, domain=pe.NonNegativeReals) #on hand inventory at each stage mip.T = pe.Var( mip.n1, mip.m0, domain=pe.NonNegativeReals) #pipeline inventory in between each stage mip.R = pe.Var( mip.n, mip.m0, domain=pe.NonNegativeReals) #reorder quantities for each stage mip.R1 = pe.Var( mip.n, mip.m0, domain=pe.NonNegativeReals) #unconstrained reorder quantity mip.S = pe.Var(mip.n, mip.m, domain=pe.NonNegativeReals) #sales at each stage if backlog: mip.B = pe.Var(mip.n, mip.m, domain=pe.NonNegativeReals) #backlogs at each stage else: mip.LS = pe.Var(mip.n, mip.m, domain=pe.NonNegativeReals) #lost sales at each stage mip.P = pe.Var(mip.n, domain=pe.Reals) #profit at each stage mip.y = pe.Var( mip.n, mip.m0, domain=pe.Binary ) #auxiliary variable (y = 0: inventory level is above the base stock level (no reorder)) mip.y1 = pe.Var( mip.n, mip.m0, domain=pe.Binary ) #auxiliary variable (y1 = 1: unconstrained reorder quantity accepted) mip.y2 = pe.Var( mip.n, mip.m0, domain=pe.Binary ) #auxiliary variable (y2 = 1: reorder quantity is capacity constrained) if env.num_stages > 2: mip.y3 = pe.Var( mip.n, mip.m0, domain=pe.Binary ) #auxiliary variable (y3 = 1: reorder quantity is inventory constrained) mip.y4 = pe.Var(mip.n, mip.m, domain=pe.Binary ) #auxiliary variable (y4 = 1: demand + backlog satisfied) mip.x = pe.Var(mip.m0, domain=pe.NonNegativeReals) #inventory level at each stage mip.z = pe.Var(mip.m0, domain=pe.PositiveIntegers) #base stock level at each stage #initialize for m in mip.m0: mip.T[0, m].fix(0) #define constraints mip.inv_bal = pe.ConstraintList() mip.sales1 = pe.ConstraintList() mip.sales2 = pe.ConstraintList() mip.sales3 = pe.ConstraintList() mip.sales4 = pe.ConstraintList() mip.sales5 = pe.ConstraintList() mip.reorder1 = pe.ConstraintList() mip.reorder2 = pe.ConstraintList() mip.reorder3 = pe.ConstraintList() mip.reorder4 = pe.ConstraintList() mip.reorder5 = pe.ConstraintList() mip.reorder6 = pe.ConstraintList() mip.reorder7 = pe.ConstraintList() mip.reorder8 = pe.ConstraintList() mip.reorder9 = pe.ConstraintList() mip.reorder10 = pe.ConstraintList() mip.pip_bal = pe.ConstraintList() mip.unfulfilled = pe.ConstraintList() mip.profit = pe.ConstraintList() mip.basestock = pe.ConstraintList() mip.init_inv = pe.ConstraintList() #build constraints for m in mip.m0: #relate base stock levels to inventory levels: base stock level = total inventory up to that echelon mip.basestock.add(mip.z[m] == sum(mip.x[i] for i in range(m + 1))) #initialize inventory levels to being full (this would be ideal) mip.init_inv.add(mip.I[0, m] == mip.x[m]) for n in mip.n: #calculate profit: apply time value discount to sales revenue - purchasing costs - unfulfilled demand cost - holding cost if backlog: mip.profit.add( mip.P[n] == mip.discount**n * (sum(mip.unit_price[m] * mip.S[n, m] for m in mip.m) - (sum(mip.unit_cost[m] * mip.R[n, m] for m in mip.m0) + mip.unit_cost[mip.m[-1]] * mip.S[n, mip.m[-1]]) - sum(mip.demand_cost[m] * mip.B[n, m] for m in mip.m) - sum(mip.holding_cost[m] * mip.I[n + 1, m] for m in mip.m0))) else: mip.profit.add( mip.P[n] == mip.discount**n * (sum(mip.unit_price[m] * mip.S[n, m] for m in mip.m) - (sum(mip.unit_cost[m] * mip.R[n, m] for m in mip.m0) + mip.unit_cost[mip.m[-1]] * mip.S[n, mip.m[-1]]) - sum(mip.demand_cost[m] * mip.LS[n, m] for m in mip.m) - sum(mip.holding_cost[m] * mip.I[n + 1, m] for m in mip.m0))) for m in mip.m0: #on-hand inventory balance: next period inventory = prev period inventory + arrival from above stage - sales if n - mip.lead_time[m] >= 0: mip.inv_bal.add(mip.I[n + 1, m] == mip.I[n, m] + mip.R[n - mip.lead_time[m], m] - mip.S[n, m]) else: mip.inv_bal.add(mip.I[n + 1, m] == mip.I[n, m] - mip.S[n, m]) #pipeline inventory balance: next period inventory = prev period inventory - delivered material + new reorder if n - mip.lead_time[m] >= 0: mip.pip_bal.add(mip.T[n + 1, m] == mip.T[n, m] - mip.R[n - mip.lead_time[m], m] + mip.R[n, m]) else: mip.pip_bal.add(mip.T[n + 1, m] == mip.T[n, m] + mip.R[n, m]) #reorder quantity constraints: R1 = max(0, z - sum(I + T - B) + B[m+1]) # reorder based on base_stock level = z - sum(I + T - B) # Note: R1 = max(A,B) <-> A <= R1 <= A + M*(1-y) ; B <= R1 <= B + M*y # y = 1 means that the reorder level is positive # y = 0 means that no reorder necessary (already above base stock level) # Disjunction: [y -> R1 = z - sum(I + T - B)] OR [not y -> R1 = 0] if (backlog) & (n - 1 >= 0): mip.reorder1.add( mip.R1[n, m] <= mip.z[m] - sum(mip.I[n, i] + mip.T[n, i] - mip.B[n - 1, i] for i in range(m + 1)) + mip.B[n - 1, m + 1] + BigM1 * (1 - mip.y[n, m])) mip.reorder2.add( mip.R1[n, m] >= mip.z[m] - sum(mip.I[n, i] + mip.T[n, i] - mip.B[n - 1, i] for i in range(m + 1)) + mip.B[n - 1, m + 1]) else: mip.reorder1.add(mip.R1[n, m] <= mip.z[m] - sum(mip.I[n, i] + mip.T[n, i] for i in range(m + 1)) + BigM1 * (1 - mip.y[n, m])) mip.reorder2.add( mip.R1[n, m] >= mip.z[m] - sum(mip.I[n, i] + mip.T[n, i] for i in range(m + 1))) mip.reorder3.add(mip.R1[n, m] <= BigM2 * mip.y[n, m]) #reorder quantity constraints: R = min(c, I[m+1], R1) #last constraint ensures that only one of the 3 options is chosen # Note: R = min(A,B,C) <-> A + M*(1-y1) <= R <= A ; B + M*(1-y2) <= R <= B ; C + M*(1-y3) <= R <= C ; y1+y2+y3==1 mip.reorder4.add(mip.R[n, m] <= mip.R1[n, m]) mip.reorder5.add(mip.R[n, m] >= mip.R1[n, m] + BigM3 * (1 - mip.y1[n, m])) mip.reorder6.add(mip.R[n, m] <= mip.supply_capacity[m]) mip.reorder7.add( mip.R[n, m] >= mip.supply_capacity[m] * mip.y2[n, m]) if (m < mip.m0[-1]) & (env.num_stages > 2): #if number of stages = 2, then there is no inventory constraint since the last level has unlimited inventory #also, last stage has unlimited inventory mip.reorder8.add(mip.R[n, m] <= mip.I[n, m + 1]) mip.reorder9.add(mip.R[n, m] >= mip.I[n, m + 1] + BigM4 * (1 - mip.y3[n, m])) mip.reorder10.add(mip.y1[n, m] + mip.y2[n, m] + mip.y3[n, m] == 1) else: mip.reorder10.add(mip.y1[n, m] + mip.y2[n, m] == 1) for m in mip.m: if m == 0: #sales constraints: S = min(I + R[n-L], D + B[n-1]) at stage 0 if n - mip.lead_time[m] >= 0: mip.sales1.add(mip.S[n, m] <= mip.I[n, m] + mip.R[n - mip.lead_time[m], m]) mip.sales2.add(mip.S[n, m] >= mip.I[n, m] + mip.R[n - mip.lead_time[m], m] + BigM5 * (1 - mip.y4[n, m])) else: mip.sales1.add(mip.S[n, m] <= mip.I[n, m]) mip.sales2.add(mip.S[n, m] >= mip.I[n, m] + BigM5 * (1 - mip.y4[n, m])) if (backlog) & (n - 1 >= 0): mip.sales3.add(mip.S[n, m] <= mip.D[n] + mip.B[n - 1, m]) mip.sales4.add(mip.S[n, m] >= mip.D[n] + mip.B[n - 1, m] + BigM6 * mip.y4[n, m]) else: mip.sales3.add(mip.S[n, m] <= mip.D[n]) mip.sales4.add( mip.S[n, m] >= mip.D[n] + BigM6 * mip.y4[n, m]) else: #sales constraints: S = R[n,m-1] at higher level stages mip.sales5.add(mip.S[n, m] == mip.R[n, m - 1]) if m == 0: #unfulfilled orders at stage 0: U = D + B[n-1] - S if backlog: if n - 1 >= 0: mip.unfulfilled.add(mip.B[n, m] == mip.D[n] + mip.B[n - 1, m] - mip.S[n, m]) else: mip.unfulfilled.add(mip.B[n, m] == mip.D[n] - mip.S[n, m]) else: mip.unfulfilled.add(mip.LS[n, m] == mip.D[n] - mip.S[n, m]) else: #unfulfilled orders at stage higher level stages: U = R[n,m-1] + B[n-1,m] - S[n,m] if backlog: if n - 1 >= 0: mip.unfulfilled.add(mip.B[n, m] == mip.R[n, m - 1] + mip.B[n - 1, m] - mip.S[n, m]) else: mip.unfulfilled.add(mip.B[n, m] == mip.R[n, m - 1] - mip.S[n, m]) else: mip.unfulfilled.add(mip.LS[n, m] == mip.R[n, m - 1] - mip.S[n, m]) #objective function: maximize expected profit mip.obj = pe.Objective(expr=1 / mip.num_periods * sum(mip.prob[n] * mip.P[n] for n in mip.n), sense=pe.maximize) return mip
def sample_model(self, input_changes=None, fixed_outputs=None): import pyomo.environ as pyo from pyomo.opt import SolverFactory # Step 0: Create an instance of the model model = pyo.ConcreteModel() # Step 1: Define index sets time = range(8760) # Input Changes Names = ["CostPV", "CostBat", "CostBuy", "Demand"] Scaling = [1, 1, 1, 1, 1, 1, 1, 1, 1] if input_changes is not None: for i in range(Names.__len__()): try: Scaling[i] = input_changes[Names[i]] except: Scaling[i] = 1 # Output Fixes Names = ["PVFixed", "BatteryFixed", "SelfProdRatioFixed", "TOTEXFixed", "CAPEXFixed"] Fixing = [-1, -1, -1, -1, -1, -1, -1, -1] if fixed_outputs is not None: for i in range(Names.__len__()): try: Fixing[i] = fixed_outputs[Names[i]] except: Fixing[i] = -1 # Step 1.5: Parameters lifetime = self.Settings["lifetime"] # years cost_PV = Scaling[0] * self.Settings["cost_PV"] / lifetime # *((time[-1]+1)/8760) # € / (lifetime * kW) cost_Battery = Scaling[1] * self.Settings[ "cost_Battery"] / lifetime # *((time[-1]+1)/8760) # € / (lifetime * kWh) cost_buy_ele = Scaling[2] * self.Settings["cost_buy"] # €/kWh dem_tot = Scaling[3] * self.Settings["dem_tot"] # kWh battery_in_eff = 1 # efficiency 100% import csv availability_pv = [] # create empty arrays DemandVal = [] with open('TS_PVAvail.csv', 'r') as file: # next(file) reader = csv.reader(file, delimiter='\n') for row in reader: availability_pv.append(float(row[0])) with open('TS_Demand.csv', 'r') as file: # next(file) reader = csv.reader(file, delimiter='\n') for row in reader: DemandVal.append(float(row[0])) availability_pv = dict(enumerate(availability_pv)) DemandVal = dict(enumerate(DemandVal)) # Step 2: Define the decision # Electricity Sector model.EnergyPV = pyo.Var(time, within=pyo.NonNegativeReals) model.Demand = pyo.Var(time, within=pyo.NonNegativeReals) model.EnergyBattery = pyo.Var(time, within=pyo.NonNegativeReals) model.EnergyBattery_IN = pyo.Var(time, within=pyo.NonNegativeReals) model.EnergyBattery_OUT = pyo.Var(time, within=pyo.NonNegativeReals) model.EnergyBuy = pyo.Var(time, within=pyo.NonNegativeReals) model.CapacityPV = pyo.Var(within=pyo.NonNegativeReals) model.CapacityBattery = pyo.Var(within=pyo.NonNegativeReals) model.CostBuy = pyo.Var(within=pyo.Reals) model.CostPV = pyo.Var(within=pyo.Reals) model.CostBat = pyo.Var(within=pyo.Reals) # Step 3: Define Objective model.cost = pyo.Objective(expr=cost_PV * model.CapacityPV + cost_buy_ele * sum( model.EnergyBuy[i] for i in time) + cost_Battery * model.CapacityBattery, sense=pyo.minimize) # Step 4: Constraints model.limEQ = pyo.ConstraintList() for i in time: model.limEQ.add(model.EnergyPV[i] <= model.CapacityPV * availability_pv[i]) # PV Upper Limit for i in time: model.limEQ.add(model.EnergyBattery[i] <= model.CapacityBattery) # Battery Upper Limit model.InitialBattery = pyo.Constraint( expr=model.EnergyBattery[0] == model.EnergyBattery[time[-1]] - model.EnergyBattery_OUT[0] + model.EnergyBattery_IN[0]) # Battery level t=0 == t=T model.DemandEQ = pyo.ConstraintList() for i in time: model.DemandEQ.add(expr=model.Demand[i] == dem_tot * DemandVal[i]) # Electricity Demand model.batteryEQ = pyo.ConstraintList() for i in time[1:]: model.batteryEQ.add( expr=model.EnergyBattery[i] == model.EnergyBattery[i - 1] - model.EnergyBattery_OUT[i] + model.EnergyBattery_IN[i]) # Battery Equation model.EnergyEQ = pyo.ConstraintList() for i in time: model.EnergyEQ.add( expr=model.Demand[i] == model.EnergyBuy[i] + model.EnergyBattery_OUT[i] - model.EnergyBattery_IN[ i] + model.EnergyPV[i]) # Energy Equation # Some equations that store input settings in a Variable model.ValueCostBuy = pyo.Constraint(expr=model.CostBuy == cost_buy_ele) model.ValueCostPV = pyo.Constraint(expr=model.CostPV == cost_PV) model.ValueCostBat = pyo.Constraint(expr=model.CostBat == cost_Battery) # Equations to fix outputs if Fixing[0] != -1: # fixed PV Cap model.fixedPV = pyo.Constraint(expr=model.CapacityPV == Fixing[0]) if Fixing[1] != -1: # fixed Battery cap model.fixedBattery = pyo.Constraint(expr=model.CapacityBattery == Fixing[1]) if Fixing[2] != -1: # fixed Self Generation model.SelfProduction = pyo.Constraint(expr=sum(model.EnergyPV[i] for i in time) / dem_tot == Fixing[2]) if Fixing[3] != -1: # fixed TOTEX model.TOTEX = pyo.Constraint(expr=cost_PV * model.CapacityPV + cost_buy_ele * sum( model.EnergyBuy[i] for i in time) + cost_Battery * model.CapacityBattery == Fixing[3]) if Fixing[4] != -1: # fixed CAPEX model.CAPEX = pyo.Constraint( expr=cost_PV * model.CapacityPV + cost_Battery * model.CapacityBattery == Fixing[4]) # Change lines below to use other solver solver_options = open("solverSettings.txt", "r").read().split("\n") for i in solver_options: if i.find('#') == 0 or i.__len__() == 0: val = 0 # comment or empty line: do nothing elif i.find('solver') == 0: val = i.split('=') val = val[1].strip() # set solver solver = SolverFactory(val) else: val = i.split('=') opt = val[0].strip() val = val[1].strip() try: val2 = float(val) except ValueError: val2 = val solver.options[opt] = val2 results = solver.solve(model, tee=True, keepfiles=True) results.write() # Print full model to console. Only enable for debugging purpose # model.pprint() return model, results.solver.termination_condition
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)
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
def test_pow_neg(self): m = pe.ConcreteModel() m.x = pe.Var(bounds=(-1,1)) m.y = pe.Var() m.z = pe.Var() m.w = pe.Var() m.p = pe.Param(initialize=-2) m.c = pe.Constraint(expr=m.x**m.p + m.y + m.z == 0) m.c2 = pe.Constraint(expr=m.w - 3*m.x**m.p == 0) rel = coramin.relaxations.relax(m) # This model should be relaxed to # # aux2 + y + z = 0 # w - 3 * aux2 = 0 # aux1 = x**2 # aux1*aux2 = aux3 # aux3 = 1 # self.assertTrue(hasattr(rel, 'aux_cons')) self.assertTrue(hasattr(rel, 'aux_vars')) self.assertEqual(len(rel.aux_cons), 2) self.assertEqual(len(rel.aux_vars), 3) self.assertAlmostEqual(rel.aux_vars[1].lb, 0) self.assertAlmostEqual(rel.aux_vars[1].ub, 1) self.assertTrue(rel.aux_vars[3].is_fixed()) self.assertEqual(rel.aux_vars[3].value, 1) self.assertEqual(rel.aux_cons[1].lower, 0) self.assertEqual(rel.aux_cons[1].upper, 0) ders = reverse_sd(rel.aux_cons[1].body) self.assertEqual(ders[rel.z], 1) self.assertEqual(ders[rel.aux_vars[2]], 1) self.assertEqual(ders[rel.y], 1) self.assertEqual(len(list(identify_variables(rel.aux_cons[1].body))), 3) self.assertEqual(rel.aux_cons[2].lower, 0) self.assertEqual(rel.aux_cons[2].upper, 0) ders = reverse_sd(rel.aux_cons[2].body) self.assertEqual(ders[rel.w], 1) self.assertEqual(ders[rel.aux_vars[2]], -3) self.assertEqual(len(list(identify_variables(rel.aux_cons[2].body))), 2) self.assertTrue(hasattr(rel, 'relaxations')) self.assertTrue(hasattr(rel.relaxations, 'rel0')) self.assertTrue(isinstance(rel.relaxations.rel0, coramin.relaxations.PWXSquaredRelaxation)) self.assertIn(rel.x, ComponentSet(rel.relaxations.rel0.get_rhs_vars())) self.assertEqual(id(rel.aux_vars[1]), id(rel.relaxations.rel0.get_aux_var())) self.assertTrue(rel.relaxations.rel0.is_rhs_convex()) self.assertFalse(rel.relaxations.rel0.is_rhs_concave()) self.assertTrue(hasattr(rel.relaxations, 'rel1')) self.assertTrue(isinstance(rel.relaxations.rel1, coramin.relaxations.PWMcCormickRelaxation)) self.assertIn(rel.aux_vars[1], ComponentSet(rel.relaxations.rel1.get_rhs_vars())) self.assertIn(rel.aux_vars[2], ComponentSet(rel.relaxations.rel1.get_rhs_vars())) self.assertEqual(id(rel.aux_vars[3]), id(rel.relaxations.rel1.get_aux_var())) self.assertFalse(hasattr(rel.relaxations, 'rel2'))
def create_model(spt): norm_spt = spt / np.max(spt) m = po.ConcreteModel() """ Sets """ m.i = po.Set(initialize=["A", "B", "C"]) m.j = po.Set(initialize=[1, 2]) """ Time Components """ m.t = pod.ContinuousSet(bounds=(0, 1), initialize=norm_spt) m.tau = po.Var(bounds=(0, None)) """ Concentrations """ m.c = po.Var(m.t, m.i, bounds=(0, None)) m.dcdt = pod.DerivativeVar(m.c, wrt=m.t) """ Experimental Variables """ m.f_in = po.Var(bounds=(0, 10)) m.T = po.Var(bounds=(273.15, 323.15)) """ Reaction Parameters """ s = { ("A", 1): -1, ("B", 1): 1, ("C", 1): 0, ("A", 2): 0, ("B", 2): -1, ("C", 2): 1, } m.s = po.Param(m.i, m.j, initialize=s) c_in = { "A": 1, "B": 0, "C": 0, } m.c_in = po.Param(m.i, initialize=c_in) """ Model Parameters """ m.k = po.Var(m.j, bounds=(0, None)) m.theta0 = po.Var(m.j) m.theta1 = po.Var(m.j) """ Reaction Rates """ m.r = po.Var(m.t, m.j) """ Model Equations """ def _bal(m, t, i): return m.dcdt[t, i] / m.tau == m.f_in * m.c_in[i] + sum(m.s[i, j] * m.r[t, j] for j in m.j) m.bal = po.Constraint(m.t, m.i, rule=_bal) def _r_def(m, t, j): if j == 1: return m.r[t, j] == po.exp(m.theta0[j] + m.theta1[j] * (m.T - 273.15) / m.T) * m.c[t, "A"] elif j == 2: return m.r[t, j] == po.exp(m.theta0[j] + m.theta1[j] * (m.T - 273.15) / m.T) * m.c[t, "B"] else: raise SyntaxError("Unrecognized reaction index, please check the model.") m.r_def = po.Constraint(m.t, m.j, rule=_r_def) return m
def scenario_creator( scenario_name, solar_filname=None, use_LP=False, lam=None, ): """ Args: scenario_name (str): Name of the scenario to create. solar_filename (str): File containing the solar data. use_LP (bool, optional): If True, uses LP. Default is False. lam (float): Value of the dual variable for the chance constraint. """ if 'solar_filename' is None: raise ValueError("kwarg `solar_filename` is required") if 'lam' is None: raise RuntimeError("kwarg `lam` is required") data = getData(solar_filename) num_scenarios = data['solar'].shape[0] scenario_index = extract_scenario_index(scenario_name) if (scenario_index < 0) or (scenario_index >= num_scenarios): raise RuntimeError('Provided scenario index is invalid (must lie in ' '{0,1,...' + str(num_scenarios - 1) + '} inclusive)') model = pyo.ConcreteModel() T = range(data['T']) Tm1 = range(data['T'] - 1) model.y = pyo.Var(T, within=pyo.NonNegativeReals) model.p = pyo.Var(T, bounds=(0, data['cMax'])) model.q = pyo.Var(T, bounds=(0, data['dMax'])) model.x = pyo.Var(T, bounds=(data['eMin'], data['eMax'])) if (use_LP): model.z = pyo.Var([0], within=pyo.UnitInterval) else: model.z = pyo.Var([0], within=pyo.Binary) ''' "Flow balance" constraints ''' def flow_balance_constraint_rule(model, t): return model.x[t+1]==model.x[t] + \ data['eff'] * model.p[t] - (1/data['eff']) * model.q[t] model.flow_constr = pyo.Constraint(Tm1, rule=flow_balance_constraint_rule) ''' Big-M constraints ''' def big_M_constraint_rule(model, t): return model.y[t] - model.q[t] + model.p[t] \ <= data['solar'][scenario_index,t] + \ data['M'][scenario_index,t] * model.z[0] # Why indexed?? model.big_m_constr = pyo.Constraint(T, rule=big_M_constraint_rule) ''' Objective function (must be minimization or PH crashes) ''' model.obj = pyo.Objective(expr=-pyo.dot_product(data['rev'], model.y) + data['char'] * pyo.quicksum(model.p) + data['disc'] * pyo.quicksum(model.q) + lam * model.z[0], sense=pyo.minimize) fscr = lambda model: pyo.dot_product(data['rev'], model.y) model.first_stage_cost = pyo.Expression(rule=fscr) model._PySPnode_list = [ stree.ScenarioNode(name='ROOT', cond_prob=1., stage=1, cost_expression=model.first_stage_cost, scen_name_list=None, nonant_list=[model.y], scen_model=model) ] return model
def test_no_objective(self): m = pyo.ConcreteModel() m.x = pyo.Var() m.c = pyo.Constraint(expr=2.0 * m.x >= 5) with self.assertRaises(NotImplementedError): nlp = PyomoNLP(m)
def create_master(): m = pe.ConcreteModel() m.y = pe.Var(bounds=(1, None)) m.eta = pe.Var(bounds=(-10, None)) m.obj = pe.Objective(expr=m.y**2 + m.eta) return m
def pyomosim(data): # Define rate parameters kco = 35 kst = 1.5 sparam = 1.0 flow = 1.0 vol = 1.0 gc = .008314 # Define kinetic rate parameters k = params[0] E = params[1] # define UB for concentration #nound_ub = 20 # pyomo solver options opt = pyo.SolverFactory('baron') cracmodel = pyo.ConcreteModel() ca0, cb0, cc0, cd0, cf0, cg0, ch0, ci0, cj0, T = [ float(v) for v in data ] bound_ub = 100.0 # Define cracmodel variables # A = Eb , B = St , C = Bz , D = Et, E = Tl, F = Me, G = Water, H = H2 I = CO2, J = N2 cracmodel.a = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=ca0) cracmodel.b = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cb0) cracmodel.c = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cc0) cracmodel.d = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cd0) cracmodel.f = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cf0) cracmodel.g = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cg0) cracmodel.h = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=ch0) cracmodel.i = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=ci0) cracmodel.j = pyo.Var(domain=pyo.NonNegativeReals, bounds=(0, bound_ub), initialize=cj0) cracmodel.r1 = pyo.Var(domain=pyo.Reals) cracmodel.r2 = pyo.Var(domain=pyo.Reals) cracmodel.r4 = pyo.Var(domain=pyo.Reals) cracmodel.r5 = pyo.Var(domain=pyo.Reals) def keq(T): return pyo.exp(0.1 + (300 / T)) # return pyo.exp(-1.0*(122700-126.3*T-0.002194*T**2)/(gc*T)) * sparam # define reaction rate variable def fr1(cracmodel): # A <> B + H return cracmodel.r1 == k[0] * pyo.exp(-(E[0] / (gc)) * ( (1 / T) - (1 / Tr))) * (cracmodel.a - (cracmodel.b * cracmodel.h) / keq(T)) * (1.0 / ( (1 + kst * cracmodel.b) * (1 + kco * cracmodel.i))) def fr2(cracmodel): # A > C + D return cracmodel.r2 == k[1] * pyo.exp(-(E[1] / (gc)) * ( (1 / T) - (1 / Tr))) * cracmodel.a * (1.0 / (1 + kco * cracmodel.i)) def fr4(cracmodel): # D + 2H > 2F return cracmodel.r4 == k[2] * pyo.exp(-(E[2] / (gc)) * ( (1 / T) - (1 / Tr))) * cracmodel.d * cracmodel.h def fr5(cracmodel): # F+G > I + 4H return cracmodel.r5 == k[3] * pyo.exp(-(E[3] / (gc)) * ( (1 / T) - (1 / Tr))) * cracmodel.f * cracmodel.g cracmodel.er1 = pyo.Constraint(rule=fr1) cracmodel.er2 = pyo.Constraint(rule=fr2) cracmodel.er4 = pyo.Constraint(rule=fr4) cracmodel.er5 = pyo.Constraint(rule=fr5) cracmodel.sets = pyo.RangeSet(9) cracmodel.dum = pyo.Var(cracmodel.sets, domain=pyo.Reals) def fra(cracmodel): # A - 1,2,3 return cracmodel.dum[ 1] == ca0 - cracmodel.a - cracmodel.r1 - cracmodel.r2 def frb(cracmodel): # B - 1 return cracmodel.dum[2] == cb0 - cracmodel.b + cracmodel.r1 def frc(cracmodel): # C - 2 return cracmodel.dum[3] == cc0 - cracmodel.c + cracmodel.r2 def frd(cracmodel): # D - 2,4 return cracmodel.dum[ 4] == cd0 - cracmodel.d + cracmodel.r2 - cracmodel.r4 def frf(cracmodel): # F - 3,4,5 return cracmodel.dum[ 5] == cf0 - cracmodel.f + 2 * cracmodel.r4 - cracmodel.r5 def frg(cracmodel): # G - 5 return cracmodel.dum[6] == cg0 - cracmodel.g - 2 * cracmodel.r5 def frh(cracmodel): # H - 1,3,4,5 return cracmodel.dum[ 7] == ch0 - cracmodel.h + cracmodel.r1 - 2 * cracmodel.r4 + 4 * cracmodel.r5 def fri(cracmodel): # I - 5 return cracmodel.dum[8] == ci0 - cracmodel.i + cracmodel.r5 def frj(cracmodel): # J - N2 is inert return cracmodel.dum[9] == cj0 - cracmodel.j cracmodel.era = pyo.Constraint(rule=fra) cracmodel.erb = pyo.Constraint(rule=frb) cracmodel.erc = pyo.Constraint(rule=frc) cracmodel.erd = pyo.Constraint(rule=frd) cracmodel.erf = pyo.Constraint(rule=frf) cracmodel.erg = pyo.Constraint(rule=frg) cracmodel.erh = pyo.Constraint(rule=frh) cracmodel.eri = pyo.Constraint(rule=fri) cracmodel.erj = pyo.Constraint(rule=frj) # minimize square of dummy variables to find steady-state concentrations def objf(cracmodel): return sum(cracmodel.dum[s]**2 for s in cracmodel.sets) cracmodel.OBJ = pyo.Objective(rule=objf) results = opt.solve(cracmodel) cracmodel.solutions.store_to(results) klist = ['a', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 'j'] # Add noise of the specifiec SNR, noise has variance eps ~ N(0,noise*conc) vn = [ results.Solution.Variable[key]['Value'] + np.random.normal( 0, noise * results.Solution.Variable[key]['Value']) for key in klist ] return vn
def test_power_plant_costing(): # Create a Concrete Model as the top level object m = pyo.ConcreteModel() # Add a flowsheet object to the model m.fs = FlowsheetBlock(default={"dynamic": False}) m.fs.get_costing(year='2018') ########################################################################### # Create costing constraints # ########################################################################### # subcritical PC coal_accounts = ['1.1', '1.2', '1.3'] m.fs.subcritical_PC = pyo.Block() m.fs.subcritical_PC.coal_feed_rate = pyo.Var(initialize=7613.37) # tpd m.fs.subcritical_PC.coal_feed_rate.fix() get_PP_costing(m.fs.subcritical_PC, coal_accounts, m.fs.subcritical_PC.coal_feed_rate, 'tpd', 1) # two-stage, slurry-feed IGCC feedwater_accounts = ['3.1', '3.3', '3.5'] m.fs.IGCC_1 = pyo.Block() m.fs.IGCC_1.feedwater_flow_rate = pyo.Var(initialize=1576062.15) # lb/hr m.fs.IGCC_1.feedwater_flow_rate.fix() get_PP_costing(m.fs.IGCC_1, feedwater_accounts, m.fs.IGCC_1.feedwater_flow_rate, 'lb/hr', 3) # single-stage, slurry-feed, IGCC syngas_accounts = ['6.1', '6.2', '6.3'] m.fs.IGCC_2 = pyo.Block() m.fs.IGCC_2.syngas_flow_rate = pyo.Var(initialize=182335.921) # lb/hr m.fs.IGCC_2.syngas_flow_rate.fix() get_PP_costing(m.fs.IGCC_2, syngas_accounts, m.fs.IGCC_2.syngas_flow_rate, 'lb/hr', 4) # single-stage, dry-feed, IGCC HRSG_accounts = ['7.1', '7.2'] m.fs.IGCC_3 = pyo.Block() m.fs.IGCC_3.HRSG_duty = pyo.Var(initialize=1777.86) # MMBtu/hr m.fs.IGCC_3.HRSG_duty.fix() get_PP_costing(m.fs.IGCC_3, HRSG_accounts, m.fs.IGCC_3.HRSG_duty, 'MMBtu/hr', 5) # NGCC steam_turbine_accounts = ['8.1', '8.2', '8.5'] m.fs.NGCC = pyo.Block() m.fs.NGCC.turbine_power = pyo.Var(initialize=212500) # kW m.fs.NGCC.turbine_power.fix() get_PP_costing(m.fs.NGCC, steam_turbine_accounts, m.fs.NGCC.turbine_power, 'kW', 6) # AUSC PC AUSC_accounts = ['4.9', '8.4'] m.fs.AUSC = pyo.Block() m.fs.AUSC.feedwater_flow = pyo.Var(initialize=3298815.58) # lb/hr m.fs.AUSC.feedwater_flow.fix() get_PP_costing(m.fs.AUSC, AUSC_accounts, m.fs.AUSC.feedwater_flow, 'lb/hr', 7) # add total cost build_flowsheet_cost_constraint(m) # add initialize costing_initialization(m.fs) # try solving solver = pyo.SolverFactory('ipopt') results = solver.solve(m, tee=True) assert results.solver.termination_condition == \ pyo.TerminationCondition.optimal # all numbers come from the NETL excel file # "201.001.001_BBR4 COE Spreadsheet_Rev0U_20190919_njk.xlsm" assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.1']), abs=1e-1) == 2379 / 1e3 assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.2']), abs=1e-1) == 6588 / 1e3 assert pytest.approx(pyo.value( m.fs.subcritical_PC.costing.total_plant_cost['1.3']), abs=1e-1) == 61409 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.1']), abs=1e-1) == 10807 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.3']), abs=1e-1) == 2564 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_1.costing.total_plant_cost['3.5']), abs=1e-1) == 923 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.1']), abs=1e-1) == 117850 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.2']), abs=1e-1) == 3207 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_2.costing.total_plant_cost['6.3']), abs=1e-1) == 3770 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_3.costing.total_plant_cost['7.1']), abs=1e-1) == 53530 / 1e3 assert pytest.approx(pyo.value( m.fs.IGCC_3.costing.total_plant_cost['7.2']), abs=1e-1) == 19113 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.1']), abs=1e-1) == 49468 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.2']), abs=1e-1) == 565 / 1e3 assert pytest.approx(pyo.value(m.fs.NGCC.costing.total_plant_cost['8.5']), abs=1e-1) == 4094 / 1e3 assert pytest.approx(pyo.value(m.fs.AUSC.costing.bare_erected_cost['4.9']), abs=1e-1) == 295509 / 1e3 assert pytest.approx(pyo.value(m.fs.AUSC.costing.bare_erected_cost['8.4']), abs=1e-1) == 57265 / 1e3 return m
def declareOptimizationProblem(self, timeSeriesAggregation=False): """ Declare the optimization problem belonging to the specified energy system for which a pyomo concrete model instance is built and filled with * basic time sets, * sets, variables and constraints contributed by the component modeling classes, * basic, component overreaching constraints, and * an objective function. **Default arguments:** :param timeSeriesAggregation: states if the optimization of the energy system model should be done with (a) the full time series (False) or (b) clustered time series data (True). |br| * the default value is False :type timeSeriesAggregation: boolean Last edited: November 10, 2018 |br| @author: Lara Welder """ # Get starting time of the optimization to, later on, obtain the total run time of the optimize function call timeStart = time.time() # Check correctness of inputs utils.checkDeclareOptimizationProblemInput( timeSeriesAggregation, self.isTimeSeriesDataClustered) ################################################################################################################ # Initialize mathematical model (ConcreteModel) instance # ################################################################################################################ # Initialize a pyomo ConcreteModel which will be used to store the mathematical formulation of the model. # The ConcreteModel instance is stored in the EnergySystemModel instance, which makes it available for # post-processing or debugging. A pyomo Suffix with the name dual is declared to make dual values associated # to the model's constraints available after optimization. self.pyM = pyomo.ConcreteModel() pyM = self.pyM pyM.dual = pyomo.Suffix(direction=pyomo.Suffix.IMPORT) # Set time sets for the model instance self.declareTimeSets(pyM, timeSeriesAggregation) ################################################################################################################ # Declare component specific sets, variables and constraints # ################################################################################################################ for key, mdl in self.componentModelingDict.items(): _t = time.time() utils.output( 'Declaring sets, variables and constraints for ' + key, self.verbose, 0) utils.output('\tdeclaring sets... ', self.verbose, 0), mdl.declareSets(self, pyM) utils.output('\tdeclaring variables... ', self.verbose, 0), mdl.declareVariables(self, pyM) utils.output('\tdeclaring constraints... ', self.verbose, 0), mdl.declareComponentConstraints(self, pyM) utils.output('\t\t(%.4f' % (time.time() - _t) + ' sec)\n', self.verbose, 0) ################################################################################################################ # Declare cross-componential sets and constraints # ################################################################################################################ # Declare constraints for enforcing shared capacities _t = time.time() self.declareSharedPotentialConstraints(pyM) utils.output('\t\t(%.4f' % (time.time() - _t) + ' sec)\n', self.verbose, 0) # Declare commodity balance constraints (one balance constraint for each commodity, location and time step) _t = time.time() self.declareCommodityBalanceConstraints(pyM) utils.output('\t\t(%.4f' % (time.time() - _t) + ' sec)\n', self.verbose, 0) ################################################################################################################ # Declare objective function # ################################################################################################################ # Declare objective function by obtaining the contributions to the objective function from all modeling classes _t = time.time() self.declareObjective(pyM) utils.output('\t\t(%.4f' % (time.time() - _t) + ' sec)\n', self.verbose, 0) # Store the build time of the optimize function call in the EnergySystemModel instance self.solverSpecs['buildtime'] = time.time() - timeStart