def is_bounded(self, config): """ Return True if the uncertainty set is bounded, else False. """ # === Determine bounds on all uncertain params bounding_model = ConcreteModel() bounding_model.util = Block() # So that boundedness checks work for Cardinality and FactorModel sets bounding_model.uncertain_param_vars = IndexedVar(range(len(config.uncertain_params)), initialize=1) for idx, param in enumerate(config.uncertain_params): bounding_model.uncertain_param_vars[idx].value = param.value bounding_model.add_component("uncertainty_set_constraint", config.uncertainty_set.set_as_constraint( uncertain_params=bounding_model.uncertain_param_vars, model=bounding_model, config=config )) for idx, param in enumerate(list(bounding_model.uncertain_param_vars.values())): bounding_model.add_component("lb_obj_" + str(idx), Objective(expr=param, sense=minimize)) bounding_model.add_component("ub_obj_" + str(idx), Objective(expr=param, sense=maximize)) for o in bounding_model.component_data_objects(Objective): o.deactivate() for i in range(len(bounding_model.uncertain_param_vars)): for limit in ("lb", "ub"): getattr(bounding_model, limit + "_obj_" + str(i)).activate() res = config.global_solver.solve(bounding_model, tee=False) getattr(bounding_model, limit + "_obj_" + str(i)).deactivate() if not check_optimal_termination(res): return False return True
def __init__(self, pyomo_model): """Constructor""" args = (Set(),) kwargs = {} self.pyomo_model = pyomo_model Objective.__init__(self, *args, **kwargs) #self._data = ObjectiveDataSequence( poek_model ) self._data = []
def add_bounds_for_uncertain_parameters(model, config): ''' This function solves a set of optimization problems to determine bounds on the uncertain parameters given the uncertainty set description. These bounds will be added as additional constraints to the uncertainty_set_constr constraint. Should only be called once set_as_constraint() has been called on the separation_model object. :param separation_model: the model on which to add the bounds :param config: solver config :return: ''' # === Determine bounds on all uncertain params uncertain_param_bounds = [] bounding_model = ConcreteModel() bounding_model.util = Block() bounding_model.util.uncertain_param_vars = IndexedVar( model.util.uncertain_param_vars.index_set()) for tup in model.util.uncertain_param_vars.items(): bounding_model.util.uncertain_param_vars[tup[0]].value = tup[1].value bounding_model.add_component( "uncertainty_set_constraint", config.uncertainty_set.set_as_constraint( uncertain_params=bounding_model.util.uncertain_param_vars, model=bounding_model, config=config)) for idx, param in enumerate( list(bounding_model.util.uncertain_param_vars.values())): bounding_model.add_component("lb_obj_" + str(idx), Objective(expr=param, sense=minimize)) bounding_model.add_component("ub_obj_" + str(idx), Objective(expr=param, sense=maximize)) for o in bounding_model.component_data_objects(Objective): o.deactivate() for i in range(len(bounding_model.util.uncertain_param_vars)): bounds = [] for limit in ("lb", "ub"): getattr(bounding_model, limit + "_obj_" + str(i)).activate() res = config.global_solver.solve(bounding_model, tee=False) bounds.append(bounding_model.util.uncertain_param_vars[i].value) getattr(bounding_model, limit + "_obj_" + str(i)).deactivate() uncertain_param_bounds.append(bounds) # === Add bounds as constraints to uncertainty_set_constraint ConstraintList for idx, bound in enumerate(uncertain_param_bounds): model.util.uncertain_param_vars[idx].setlb(bound[0]) model.util.uncertain_param_vars[idx].setub(bound[1]) return
def make_model_2(): m = ConcreteModel() m.x = Var(initialize=0.1, bounds=(0, 1)) m.y = Var(initialize=0.1, bounds=(0, 1)) m.obj = Objective(expr=-m.x**2 - m.y**2) m.c = Constraint(expr=m.y <= pe.exp(-m.x)) return m
def is_empty_intersection(self, uncertain_params, nlp_solver): """ Determine if intersection is empty Args: uncertain_params: list of uncertain parameters nlp_solver: a Pyomo Solver object for solving NLPs """ # === Non-emptiness check for the set intersection is_empty_intersection = True if any(a_set.type == "discrete" for a_set in self.all_sets): disc_sets = (a_set for a_set in self.all_sets if a_set.type == "discrete") disc_set = min(disc_sets, key=lambda x: len(x.scenarios)) # minimum set of scenarios # === Ensure there is at least one scenario from this discrete set which is a member of all other sets for scenario in disc_set.scenarios: if all(a_set.point_in_set(point=scenario) for a_set in self.all_sets): is_empty_intersection = False break else: # === Compile constraints and solve NLP m = ConcreteModel() m.obj = Objective(expr=0) # dummy objective required if using baron m.param_vars = Var(uncertain_params.index_set()) for a_set in self.all_sets: m.add_component(a_set.type + "_constraints", a_set.set_as_constraint(uncertain_params=m.param_vars)) try: res = nlp_solver.solve(m) except: raise ValueError("Solver terminated with an error while checking set intersection non-emptiness.") if check_optimal_termination(res): is_empty_intersection = False return is_empty_intersection
def build_Block_with_objects(): """Build an empty Block""" obj = Block(concrete=True) obj.construct() obj.x = Var() obj.x._domain = None obj.c = Constraint() obj.o = Objective() return obj
def build_BlockData_with_objects(): """Build an empty _BlockData""" obj = _BlockData(build_BlockData_with_objects.owner) obj.x = Var() obj.x._domain = None obj.c = Constraint() obj.o = Objective() obj._component = None return obj
def make_model_tri(n, small_val=1e-7, big_val=1e2): m = ConcreteModel() m.x = Var(range(n), initialize=0.5) def c_rule(m, i): return big_val*m.x[i-1] + small_val*m.x[i] + big_val*m.x[i+1] == 1 m.c = Constraint(range(1,n-1), rule=c_rule) m.obj = Objective(expr=small_val*sum((m.x[i]-1)**2 for i in range(n))) return m
def make_model(): m = ConcreteModel() m.x = Var([1,2,3], initialize=0) m.f = Var([1,2,3], initialize=0) m.F = Var(initialize=0) m.f[1].fix(1) m.f[2].fix(2) m.sum_con = Constraint(expr= (1 == m.x[1] + m.x[2] + m.x[3])) def bilin_rule(m, i): return m.F*m.x[i] == m.f[i] m.bilin_con = Constraint([1,2,3], rule=bilin_rule) m.obj = Objective(expr=m.F**2) return m
def make_noisy(self, cov_dict, conf_level=2): self.d1.name = "Noisy plant (d1)" k = 0 for x in self.states: s = getattr(self.d1, x) #: state xicc = getattr(self.d1, x + "_icc") xicc.deactivate() for j in self.state_vars[x]: self.xp_l.append(s[(1, 0) + j]) self.xp_key[(x, j)] = k k += 1 self.d1.xS_pnoisy = Set(initialize=[ i for i in range(0, len(self.xp_l)) ]) #: Create set of noisy_states self.d1.w_pnoisy = Var(self.d1.xS_pnoisy, initialize=0.0) #: Model disturbance self.d1.Q_pnoisy = Param(self.d1.xS_pnoisy, initialize=1, mutable=True) self.d1.obj_fun_noisy = Objective( sense=maximize, expr=0.5 * sum(self.d1.Q_pnoisy[k] * self.d1.w_pnoisy[k]**2 for k in self.d1.xS_pnoisy)) self.d1.ics_noisy = ConstraintList() k = 0 for x in self.states: s = getattr(self.d1, x) #: state xic = getattr(self.d1, x + "_ic") for j in self.state_vars[x]: expr = s[(1, 1) + j] == xic[j] + self.d1.w_pnoisy[k] self.d1.ics_noisy.add(expr) k += 1 for key in cov_dict: vni = key v_i = self.xp_key[vni] self.d1.Q_pnoisy[v_i].value = cov_dict[vni] self.d1.w_pnoisy[v_i].setlb(-conf_level * cov_dict[vni]) self.d1.w_pnoisy[v_i].setub(conf_level * cov_dict[vni]) with open("debug.txt", "w") as f: self.d1.Q_pnoisy.display(ostream=f) self.d1.obj_fun_noisy.pprint(ostream=f) self.d1.ics_noisy.pprint(ostream=f) self.d1.w_pnoisy.display(ostream=f)
def model_is_valid(model): ''' Possibilities: Deterministic model has a single objective Deterministic model has no objective Deterministic model has multiple objectives :param model: the deterministic model :return: True if it satisfies certain properties, else False. ''' objectives = list(model.component_data_objects(Objective)) for o in objectives: o.deactivate() if len(objectives) == 1: ''' Ensure objective is a minimization. If not, change the sense. ''' obj = objectives[0] if obj.sense is not minimize: sympy_obj = sympyify_expression(-obj.expr) # Use sympy to distribute the negation so the method for determining first/second stage costs is valid min_obj = Objective(expr=sympy2pyomo_expression( sympy_obj[1].simplify(), sympy_obj[0])) model.del_component(obj) model.add_component( unique_component_name(model, obj.name + '_min'), min_obj) return True elif len(objectives) > 1: ''' User should deactivate all Objectives in the model except the one represented by the output of first_stage_objective + second_stage_objective ''' return False else: ''' No Objective objects provided as part of the model, please provide an Objective to your model so that PyROS can infer first- and second-stage objective. ''' return False
def solveropfnlp_2(ppc, solver="ipopt"): if solver == "ipopt": opt = SolverFactory("ipopt", executable="/home/iso/PycharmProjects/opfLC_python3/Python3/py_solvers/ipopt-linux64/ipopt") if solver == "bonmin": opt = SolverFactory("bonmin", executable="/home/iso/PycharmProjects/opfLC_python3/Python3/py_solvers/bonmin-linux64/bonmin") if solver == "knitro": opt = SolverFactory("knitro", executable="D:/ICT/Artelys/Knitro 10.2.1/knitroampl/knitroampl") ppc = ext2int(ppc) # convert to continuous indexing starting from 0 # Gather information about the system # ============================================================= baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] nb = bus.shape[0] # number of buses ng = gen.shape[0] # number of generators nl = branch.shape[0] # number of lines # generator buses gb = tolist(np.array(gen[:, GEN_BUS]).astype(int)) sb = find((bus[:, BUS_TYPE] == REF)) # slack bus index fr = branch[:, F_BUS].astype(int) # from bus indices to = branch[:, T_BUS].astype(int) # to bus indices tr = branch[:, TAP] # transformation ratios tr[find(tr == 0)] = 1 # set to 1 transformation ratios that are 0 r = branch[:, BR_R] # branch resistances x = branch[:, BR_X] # branch reactances b = branch[:, BR_B] # branch susceptances start_time = time.clock() # Admittance matrix computation # ============================================================= y = makeYbus(baseMVA, bus, branch)[0] # admittance matrix yk = 1./(r+x*1j) # branch admittance yft = yk + 0.5j*b # branch admittance + susceptance gk = yk.real # branch resistance yk = yk/tr # include /tr in yk # Optimization # ============================================================= branch[find(branch[:, RATE_A] == 0), RATE_A] = 9999 # set undefined Sflow limit to 9999 Smax = branch[:, RATE_A] / baseMVA # Max. Sflow # Power demand parameters Pd = bus[:, PD] / baseMVA Qd = bus[:, QD] / baseMVA # Max and min Pg and Qg Pg_max = zeros(nb) Pg_max[gb] = gen[:, PMAX] / baseMVA Pg_min = zeros(nb) Pg_min[gb] = gen[:, PMIN] / baseMVA Qg_max = zeros(nb) Qg_max[gb] = gen[:, QMAX] / baseMVA Qg_min = zeros(nb) Qg_min[gb] = gen[:, QMIN] / baseMVA # Vmax and Vmin vectors Vmax = bus[:, VMAX] Vmin = bus[:, VMIN] vm = bus[:, VM] va = bus[:, VA]*pi/180 # create a new optimization model model = ConcreteModel() # Define sets # ------------ model.bus = Set(ordered=True, initialize=range(nb)) # Set of all buses model.gen = Set(ordered=True, initialize=gb) # Set of buses with generation model.line = Set(ordered=True, initialize=range(nl)) # Set of all lines # Define variables # ----------------- # Voltage magnitudes vector (vm) model.vm = Var(model.bus) # Voltage angles vector (va) model.va = Var(model.bus) # Reactive power generation, synchronous machines(SM) (Qg) model.Qg = Var(model.gen) Qg0 = zeros(nb) Qg0[gb] = gen[:, QG]/baseMVA # Active power generation, synchronous machines(SM) (Pg) model.Pg = Var(model.gen) Pg0 = zeros(nb) Pg0[gb] = gen[:, PG] / baseMVA # Active and reactive power from at all branches model.Pf = Var(model.line) model.Qf = Var(model.line) # Active and reactive power to at all branches model.Pt = Var(model.line) model.Qt = Var(model.line) # Warm start the problem # ------------------------ for i in range(nb): model.vm[i] = vm[i] model.va[i] = va[i] if i in gb: model.Pg[i] = Pg0[i] model.Qg[i] = Qg0[i] for i in range(nl): model.Pf[i] = vm[fr[i]] ** 2 * abs(yft[i]) / (tr[i] ** 2) * np.cos(-ang(yft[i])) -\ vm[fr[i]] * vm[to[i]] * abs(yk[i]) * np.cos(va[fr[i]] - va[to[i]] - ang(yk[i])) model.Qf[i] = vm[fr[i]] ** 2 * abs(yft[i]) / (tr[i] ** 2) * np.sin(-ang(yft[i])) -\ vm[fr[i]] * vm[to[i]] * abs(yk[i]) * np.sin(va[fr[i]] - va[to[i]] - ang(yk[i])) model.Pt[i] = vm[to[i]] ** 2 * abs(yft[i]) * np.cos(-ang(yft[i])) -\ vm[to[i]] * vm[fr[i]] * abs(yk[i]) * np.cos(va[to[i]] - va[fr[i]] - ang(yk[i])) model.Qt[i] = vm[to[i]] ** 2 * abs(yft[i]) * np.sin(-ang(yft[i])) -\ vm[to[i]] * vm[fr[i]] * abs(yk[i]) * np.sin(va[to[i]] - va[fr[i]] - ang(yk[i])) # Define constraints # ---------------------------- # Equalities: # ------------ # Active power flow equalities def powerflowact(model, i): if i in gb: return model.Pg[i]-Pd[i] == sum(model.vm[i]*model.vm[j]*abs(y[i, j]) * cos(model.va[i] - model.va[j] - ang(y[i, j])) for j in range(nb)) else: return sum(model.vm[i]*model.vm[j]*abs(y[i, j]) * cos(model.va[i] - model.va[j] - ang(y[i, j])) for j in range(nb)) == -Pd[i] model.const1 = Constraint(model.bus, rule=powerflowact) # Reactive power flow equalities def powerflowreact(model, i): if i in gb: return model.Qg[i]-Qd[i] == sum(model.vm[i]*model.vm[j]*abs(y[i, j]) * sin(model.va[i] - model.va[j] - ang(y[i, j])) for j in range(nb)) else: return sum(model.vm[i]*model.vm[j]*abs(y[i, j]) * sin(model.va[i] - model.va[j] - ang(y[i, j])) for j in range(nb)) == -Qd[i] model.const2 = Constraint(model.bus, rule=powerflowreact) # Active power from def pfrom(model, i): return model.Pf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / (tr[i] ** 2) * np.cos(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) * \ cos(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) model.const3 = Constraint(model.line, rule=pfrom) # Reactive power from def qfrom(model, i): return model.Qf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / (tr[i] ** 2) * np.sin(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) * \ sin(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) model.const4 = Constraint(model.line, rule=qfrom) # Active power to def pto(model, i): return model.Pt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.cos(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) * \ cos(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) model.const5 = Constraint(model.line, rule=pto) # Reactive power to def qto(model, i): return model.Qt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.sin(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) * \ sin(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) model.const6 = Constraint(model.line, rule=qto) # Slack bus phase angle model.const7 = Constraint(expr=model.va[sb[0]] == 0) # Inequalities: # ---------------- # Active power generator limits Pg_min <= Pg <= Pg_max def genplimits(model, i): return Pg_min[i] <= model.Pg[i] <= Pg_max[i] model.const8 = Constraint(model.gen, rule=genplimits) # Reactive power generator limits Qg_min <= Qg <= Qg_max def genqlimits(model, i): return Qg_min[i] <= model.Qg[i] <= Qg_max[i] model.const9 = Constraint(model.gen, rule=genqlimits) # Voltage constraints ( Vmin <= V <= Vmax ) def vlimits(model, i): return Vmin[i] <= model.vm[i] <= Vmax[i] model.const10 = Constraint(model.bus, rule=vlimits) # Sfrom line limit def sfrommax(model, i): return model.Pf[i]**2 + model.Qf[i]**2 <= Smax[i]**2 model.const11 = Constraint(model.line, rule=sfrommax) # Sto line limit def stomax(model, i): return model.Pt[i]**2 + model.Qt[i]**2 <= Smax[i]**2 model.const12 = Constraint(model.line, rule=stomax) # Set objective function # ------------------------ def obj_fun(model): return sum(gk[i] * ((model.vm[fr[i]] / tr[i])**2 + model.vm[to[i]]**2 - 2/tr[i] * model.vm[fr[i]] * model.vm[to[i]] * cos(model.va[fr[i]] - model.va[to[i]])) for i in range(nl)) model.obj = Objective(rule=obj_fun, sense=minimize) mt = time.clock() - start_time # Modeling time # Execute solve command with the selected solver # ------------------------------------------------ start_time = time.clock() results = opt.solve(model, tee=True) et = time.clock() - start_time # Elapsed time print(results) # Update the case info with the optimized variables # ================================================== for i in range(nb): bus[i, VM] = model.vm[i].value # Bus voltage magnitudes bus[i, VA] = model.va[i].value*180/pi # Bus voltage angles # Include Pf - Qf - Pt - Qt in the branch matrix branchsol = zeros((nl, 17)) branchsol[:, :-4] = branch for i in range(nl): branchsol[i, PF] = model.Pf[i].value * baseMVA branchsol[i, QF] = model.Qf[i].value * baseMVA branchsol[i, PT] = model.Pt[i].value * baseMVA branchsol[i, QT] = model.Qt[i].value * baseMVA # Update gen matrix variables for i in range(ng): gen[i, PG] = model.Pg[gb[i]].value * baseMVA gen[i, QG] = model.Qg[gb[i]].value * baseMVA gen[i, VG] = bus[gb[i], VM] # Convert to external (original) numbering and save case results ppc = int2ext(ppc) ppc['bus'][:, 1:] = bus[:, 1:] branchsol[:, 0:2] = ppc['branch'][:, 0:2] ppc['branch'] = branchsol ppc['gen'][:, 1:] = gen[:, 1:] ppc['obj'] = value(obj_fun(model)) ppc['ploss'] = value(obj_fun(model)) * baseMVA ppc['et'] = et ppc['mt'] = mt ppc['success'] = 1 # ppc solved case is returned return ppc
def solveropfnlp_4(ppc, solver="ipopt"): if solver == "ipopt": opt = SolverFactory( "ipopt", executable= "/home/iso/PycharmProjects/opfLC_python3/Python3/py_solvers/ipopt-linux64/ipopt" ) if solver == "bonmin": opt = SolverFactory( "bonmin", executable= "/home/iso/PycharmProjects/opfLC_python3/Python3/py_solvers/bonmin-linux64/bonmin" ) if solver == "knitro": opt = SolverFactory( "knitro", executable="D:/ICT/Artelys/Knitro 10.2.1/knitroampl/knitroampl") ppc = ext2int(ppc) # convert to continuous indexing starting from 0 # Gather information about the system # ============================================================= baseMVA, bus, gen, branch = \ ppc["baseMVA"], ppc["bus"], ppc["gen"], ppc["branch"] nb = bus.shape[0] # number of buses ng = gen.shape[0] # number of generators nl = branch.shape[0] # number of lines # generator buses gb = tolist(np.array(gen[:, GEN_BUS]).astype(int)) sb = find((bus[:, BUS_TYPE] == REF)) # slack bus index fr = branch[:, F_BUS].astype(int) # from bus indices to = branch[:, T_BUS].astype(int) # to bus indices tr0 = copy(branch[:, TAP]) # transformation ratios tr0[find(tr0 == 0)] = 1 # set to 1 transformation ratios that are 0 tp = find(branch[:, TAP] != 0) # lines with tap changers ntp = find(branch[:, TAP] == 0) # lines without tap changers # Tap changer settings dudtap = 0.01 # Voltage per unit variation with tap changes tapmax = 10 # Highest tap changer setting tapmin = -10 # Lowest tap changer setting # Shunt element options stepmax = 1 # maximum step of the shunt element Bs0 = bus[:, BS] / baseMVA # shunt elements susceptance sd = find(bus[:, BS] != 0) # buses with shunt devices r = branch[:, BR_R] # branch resistances x = branch[:, BR_X] # branch reactances b = branch[:, BR_B] # branch susceptances start_time = time.clock() # Admittance matrix computation # ============================================================= # Set tap ratios and shunt elements to neutral position branch[:, TAP] = 1 bus[:, BS] = 0 y = makeYbus(baseMVA, bus, branch)[0] # admittance matrix yk = 1. / (r + x * 1j) # branch admittance yft = yk + 0.5j * b # branch admittance + susceptance gk = yk.real # branch resistance # Optimization # ============================================================= branch[find(branch[:, RATE_A] == 0), RATE_A] = 9999 # set undefined Sflow limit to 9999 Smax = branch[:, RATE_A] / baseMVA # Max. Sflow # Power demand parameters Pd = bus[:, PD] / baseMVA Qd = bus[:, QD] / baseMVA # Max and min Pg and Qg Pg_max = zeros(nb) Pg_max[gb] = gen[:, PMAX] / baseMVA Pg_min = zeros(nb) Pg_min[gb] = gen[:, PMIN] / baseMVA Qg_max = zeros(nb) Qg_max[gb] = gen[:, QMAX] / baseMVA Qg_min = zeros(nb) Qg_min[gb] = gen[:, QMIN] / baseMVA # Vmax and Vmin vectors Vmax = bus[:, VMAX] Vmin = bus[:, VMIN] vm = bus[:, VM] va = bus[:, VA] * pi / 180 # create a new optimization model model = ConcreteModel() # Define sets # ------------ model.bus = Set(ordered=True, initialize=range(nb)) # Set of all buses model.gen = Set(ordered=True, initialize=gb) # Set of buses with generation model.line = Set(ordered=True, initialize=range(nl)) # Set of all lines model.taps = Set(ordered=True, initialize=tp) # Set of all lines with tap changers model.shunt = Set(ordered=True, initialize=sd) # Set of buses with shunt elements # Define variables # ----------------- # Voltage magnitudes vector (vm) model.vm = Var(model.bus) # Voltage angles vector (va) model.va = Var(model.bus) # Reactive power generation, synchronous machines(SM) (Qg) model.Qg = Var(model.gen) Qg0 = zeros(nb) Qg0[gb] = gen[:, QG] / baseMVA # Active power generation, synchronous machines(SM) (Pg) model.Pg = Var(model.gen) Pg0 = zeros(nb) Pg0[gb] = gen[:, PG] / baseMVA # Active and reactive power from at all branches model.Pf = Var(model.line) model.Qf = Var(model.line) # Active and reactive power to at all branches model.Pt = Var(model.line) model.Qt = Var(model.line) # Transformation ratios model.tr = Var(model.taps) # Tap changer positions + their bounds model.tap = Var(model.taps, bounds=(tapmin, tapmax)) # Shunt susceptance model.Bs = Var(model.shunt) # Shunt positions + their bounds model.s = Var(model.shunt, bounds=(0, stepmax)) # Warm start the problem # ------------------------ for i in range(nb): model.vm[i] = vm[i] model.va[i] = va[i] if i in gb: model.Pg[i] = Pg0[i] model.Qg[i] = Qg0[i] for i in range(nl): model.Pf[i] = vm[fr[i]] ** 2 * abs(yft[i]) / (tr0[i] ** 2) * np.cos(-ang(yft[i])) -\ vm[fr[i]] * vm[to[i]] * abs(yk[i]) / tr0[i] * np.cos(va[fr[i]] - va[to[i]] - ang(yk[i])) model.Qf[i] = vm[fr[i]] ** 2 * abs(yft[i]) / (tr0[i] ** 2) * np.sin(-ang(yft[i])) -\ vm[fr[i]] * vm[to[i]] * abs(yk[i]) / tr0[i] * np.sin(va[fr[i]] - va[to[i]] - ang(yk[i])) model.Pt[i] = vm[to[i]] ** 2 * abs(yft[i]) * np.cos(-ang(yft[i])) -\ vm[to[i]] * vm[fr[i]] * abs(yk[i]) / tr0[i] * np.cos(va[to[i]] - va[fr[i]] - ang(yk[i])) model.Qt[i] = vm[to[i]] ** 2 * abs(yft[i]) * np.sin(-ang(yft[i])) -\ vm[to[i]] * vm[fr[i]] * abs(yk[i]) / tr0[i] * np.sin(va[to[i]] - va[fr[i]] - ang(yk[i])) for i in tp: model.tr[i] = tr0[i] for i in sd: model.Bs[i] = Bs0[i] # Define constraints # ---------------------------- # Equalities: # ------------ # Active power flow equalities def powerflowact(model, i): bfrom_i = tp[find(fr[tp] == i)] # branches from bus i with transformer bto_i = tp[find(to[tp] == i)] # branches to bus i with transformer allbut_i = find(bus[:, BUS_I] != i) # Set of other buses if i in gb: return model.Pg[i]-Pd[i] == sum(model.vm[i] * model.vm[j] * abs(y[i, j]) * cos(model.va[i] - model.va[j] - ang(y[i, j])) for j in allbut_i) - \ sum(model.vm[i] * model.vm[to[j]] * abs(yk[j]) * cos(model.va[i] - model.va[to[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bfrom_i) - \ sum(model.vm[i] * model.vm[fr[j]] * abs(yk[j]) * cos(model.va[i] - model.va[fr[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bto_i) + \ model.vm[i] ** 2 * (sum(abs(yk[j]) * (1 / model.tr[j]**2 - 1) * np.cos(- ang(yk[j])) for j in bfrom_i) + real(y[i, i])) else: return sum(model.vm[i] * model.vm[j] * abs(y[i, j]) * cos(model.va[i] - model.va[j] - ang(y[i, j])) for j in allbut_i) - \ sum(model.vm[i] * model.vm[to[j]] * abs(yk[j]) * cos(model.va[i] - model.va[to[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bfrom_i) - \ sum(model.vm[i] * model.vm[fr[j]] * abs(yk[j]) * cos(model.va[i] - model.va[fr[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bto_i) + \ model.vm[i] ** 2 * (sum(abs(yk[j]) * (1 / model.tr[j]**2 - 1) * np.cos(- ang(yk[j])) for j in bfrom_i) + real(y[i, i])) == -Pd[i] model.const1 = Constraint(model.bus, rule=powerflowact) # Reactive power flow equalities def powerflowreact(model, i): bfrom_i = tp[find(fr[tp] == i)] # branches from bus i with transformer bto_i = tp[find(to[tp] == i)] # branches to bus i with transformer allbut_i = find(bus[:, BUS_I] != i) # Set of other buses sh = sd[find(sd == i)] # Detect shunt elements if i in gb: return model.Qg[i]-Qd[i] == \ sum(model.vm[i] * model.vm[j] * abs(y[i, j]) * sin(model.va[i] - model.va[j] - ang(y[i, j])) for j in allbut_i) - \ sum(model.vm[i] * model.vm[to[j]] * abs(yk[j]) * sin(model.va[i] - model.va[to[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bfrom_i) - \ sum(model.vm[i] * model.vm[fr[j]] * abs(yk[j]) * sin(model.va[i] - model.va[fr[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bto_i) + \ model.vm[i] ** 2 * (sum(abs(yk[j]) * (1 / model.tr[j] ** 2 - 1) * np.sin(- ang(yk[j])) for j in bfrom_i) - imag(y[i, i]) - sum(model.Bs[j] for j in sh)) else: return sum(model.vm[i] * model.vm[j] * abs(y[i, j]) * sin(model.va[i] - model.va[j] - ang(y[i, j])) for j in allbut_i) - \ sum(model.vm[i] * model.vm[to[j]] * abs(yk[j]) * sin(model.va[i] - model.va[to[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bfrom_i) - \ sum(model.vm[i] * model.vm[fr[j]] * abs(yk[j]) * sin(model.va[i] - model.va[fr[j]] - ang(yk[j])) * (1 / model.tr[j] - 1) for j in bto_i) + \ model.vm[i] ** 2 * (sum(abs(yk[j]) * (1 / model.tr[j] ** 2 - 1) * np.sin(- ang(yk[j])) for j in bfrom_i) - imag(y[i, i]) - sum(model.Bs[j] for j in sh)) == - Qd[i] model.const2 = Constraint(model.bus, rule=powerflowreact) # Active power from def pfrom(model, i): if i in tp: return model.Pf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / (model.tr[i] ** 2) * np.cos(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) / model.tr[i] * \ cos(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) else: return model.Pf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / tr0[i] ** 2 * np.cos(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) / tr0[i] * \ cos(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) model.const3 = Constraint(model.line, rule=pfrom) # Reactive power from def qfrom(model, i): if i in tp: return model.Qf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / (model.tr[i] ** 2) * np.sin(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) / model.tr[i] * \ sin(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) else: return model.Qf[i] == model.vm[fr[i]] ** 2 * abs(yft[i]) / tr0[i] ** 2 * np.sin(-ang(yft[i])) - \ model.vm[fr[i]] * model.vm[to[i]] * abs(yk[i]) / tr0[i] * \ sin(model.va[fr[i]] - model.va[to[i]] - ang(yk[i])) model.const4 = Constraint(model.line, rule=qfrom) # Active power to def pto(model, i): if i in tp: return model.Pt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.cos(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) / model.tr[i] * \ cos(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) else: return model.Pt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.cos(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) / tr0[i] * \ cos(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) model.const5 = Constraint(model.line, rule=pto) # Reactive power to def qto(model, i): if i in tp: return model.Qt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.sin(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) / model.tr[i] * \ sin(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) else: return model.Qt[i] == model.vm[to[i]] ** 2 * abs(yft[i]) * np.sin(-ang(yft[i])) - \ model.vm[to[i]] * model.vm[fr[i]] * abs(yk[i]) / tr0[i] * \ sin(model.va[to[i]] - model.va[fr[i]] - ang(yk[i])) model.const6 = Constraint(model.line, rule=qto) # Slack bus phase angle model.const7 = Constraint(expr=model.va[sb[0]] == 0) # Transformation ratio equalities def trfunc(model, i): return model.tr[i] == 1 + dudtap * model.tap[i] model.const8 = Constraint(model.taps, rule=trfunc) # Shunt susceptance equality def shuntfunc(model, i): return model.Bs[i] == model.s[i] / stepmax * Bs0[i] model.const9 = Constraint(model.shunt, rule=shuntfunc) # Inequalities: # ---------------- # Active power generator limits Pg_min <= Pg <= Pg_max def genplimits(model, i): return Pg_min[i] <= model.Pg[i] <= Pg_max[i] model.const10 = Constraint(model.gen, rule=genplimits) # Reactive power generator limits Qg_min <= Qg <= Qg_max def genqlimits(model, i): return Qg_min[i] <= model.Qg[i] <= Qg_max[i] model.const11 = Constraint(model.gen, rule=genqlimits) # Voltage constraints ( Vmin <= V <= Vmax ) def vlimits(model, i): return Vmin[i] <= model.vm[i] <= Vmax[i] model.const12 = Constraint(model.bus, rule=vlimits) # Sfrom line limit def sfrommax(model, i): return model.Pf[i]**2 + model.Qf[i]**2 <= Smax[i]**2 model.const13 = Constraint(model.line, rule=sfrommax) # Sto line limit def stomax(model, i): return model.Pt[i]**2 + model.Qt[i]**2 <= Smax[i]**2 model.const14 = Constraint(model.line, rule=stomax) # Set objective function # ------------------------ def obj_fun(model): return sum(gk[i] * ((model.vm[fr[i]] / model.tr[i])**2 + model.vm[to[i]]**2 - 2 / model.tr[i] * model.vm[fr[i]] * model.vm[to[i]] * cos(model.va[fr[i]] - model.va[to[i]])) for i in tp) + \ sum(gk[i] * ((model.vm[fr[i]] / tr0[i]) ** 2 + model.vm[to[i]] ** 2 - 2 / tr0[i] * model.vm[fr[i]] * model.vm[to[i]] * cos(model.va[fr[i]] - model.va[to[i]])) for i in ntp) model.obj = Objective(rule=obj_fun, sense=minimize) mt = time.clock() - start_time # Modeling time # Execute solve command with the selected solver # ------------------------------------------------ start_time = time.clock() results = opt.solve(model, tee=True) et = time.clock() - start_time # Elapsed time print(results) # Update the case info with the optimized variables and approximate the continuous variables to discrete values # ============================================================================================================== for i in range(nb): if i in sd: bus[i, BS] = round(model.s[i].value) * Bs0[i] * baseMVA bus[i, VM] = model.vm[i].value # Bus voltage magnitudes bus[i, VA] = model.va[i].value * 180 / pi # Bus voltage angles # Update transformation ratios for i in range(nl): if i in tp: branch[i, TAP] = 1 + dudtap * round(model.tap[i].value) # Update gen matrix variables for i in range(ng): gen[i, PG] = model.Pg[gb[i]].value * baseMVA gen[i, QG] = model.Qg[gb[i]].value * baseMVA gen[i, VG] = bus[gb[i], VM] # Convert to external (original) numbering and save case results ppc = int2ext(ppc) ppc['bus'][:, 1:] = bus[:, 1:] branch[:, 0:2] = ppc['branch'][:, 0:2] ppc['branch'] = branch ppc['gen'][:, 1:] = gen[:, 1:] # Execute a second optimization with only the discrete approximated values (requires solveropfnlp_2) sol = solveropfnlp_2(ppc) sol['mt'] = sol['mt'] + mt sol['et'] = sol['et'] + et sol['tap'] = zeros((tp.shape[0], 1)) for i in range(tp.shape[0]): sol['tap'][i] = round(model.tap[tp[i]].value) sol['shunt'] = zeros((sd.shape[0], 1)) for i in range(sd.shape[0]): sol['shunt'][i] = round(model.s[sd[i]].value) # ppc solved case is returned return sol
def __build_objectives(self): """ Initialize different objectives :return: """ self.model.Slack = Var(within=NonNegativeReals) def _decl_slack(model): return model.Slack == 10**6 * sum( comp.obj_slack() for comp in self.iter_components()) self.model.decl_slack = Constraint(rule=_decl_slack) def obj_energy(model): return model.Slack + sum(comp.obj_energy() for comp in self.iter_components()) def obj_cost(model): return model.Slack + sum(comp.obj_fuel_cost() for comp in self.iter_components()) + sum( comp.obj_elec_cost() for comp in self.iter_components()) def obj_cost_ramp(model): return model.Slack + sum(comp.obj_cost_ramp() for comp in self.iter_components()) def obj_co2(model): return model.Slack + sum(comp.obj_co2() for comp in self.iter_components()) def obj_co2_fuel_cost(model): return model.Slack + sum( comp.obj_co2_cost() + comp.obj_fuel_cost() for comp in self.iter_components()) self.model.OBJ_ENERGY = Objective(rule=obj_energy, sense=minimize) self.model.OBJ_COST = Objective(rule=obj_cost, sense=minimize) self.model.OBJ_COST_RAMP = Objective(rule=obj_cost_ramp, sense=minimize) self.model.OBJ_CO2 = Objective(rule=obj_co2, sense=minimize) self.model.OBJ_COST_CO2_FUEL = Objective(rule=obj_co2_fuel_cost, sense=minimize) self.objectives = { 'energy': self.model.OBJ_ENERGY, 'cost': self.model.OBJ_COST, 'cost_ramp': self.model.OBJ_COST_RAMP, 'co2': self.model.OBJ_CO2, 'cost_fuel_co2': self.model.OBJ_COST_CO2_FUEL } for objective in self.objectives.values(): objective.deactivate() if self.temperature_driven: def obj_temp(model): return model.Slack + sum(comp.obj_temp() for comp in self.iter_components()) self.model.OBJ_TEMP = Objective(rule=obj_temp, sense=minimize) self.objectives['temp'] = self.model.OBJ_TEMP
# Network arcs model.A = Set(within=model.N*model.N) # Source node model.s = Param(within=model.N) # Sink node model.t = Param(within=model.N) # Flow capacity limits model.c = Param(model.A) # The flow over each arc model.f = Var(model.A, within=NonNegativeReals) # Maximize the flow into the sink nodes def total_rule(model): return sum(model.f[i,j] for (i, j) in model.A if j == value(model.t)) model.total = Objective(rule=total_rule, sense=maximize) # Enforce an upper limit on the flow across each arc def limit_rule(model, i, j): return model.f[i,j] <= model.c[i, j] model.limit = Constraint(model.A, rule=limit_rule) # Enforce flow through each node def flow_rule(model, k): if k == value(model.s) or k == value(model.t): return Constraint.Skip inFlow = sum(model.f[i,j] for (i,j) in model.A if j == k) outFlow = sum(model.f[i,j] for (i,j) in model.A if i == k) return inFlow == outFlow model.flow = Constraint(model.N, rule=flow_rule)
def create_model(self): """ Create and return the mathematical model. """ if options.DEBUG: logging.info("Creating model for day %d" % self.day_id) # Obtain the orders book book = self.orders complexOrders = self.complexOrders # Create the optimization model model = ConcreteModel() model.periods = Set(initialize=book.periods) maxPeriod = max(book.periods) model.bids = Set(initialize=range(len(book.bids))) model.L = Set(initialize=book.locations) model.sBids = Set(initialize=[ i for i in range(len(book.bids)) if book.bids[i].type == 'SB' ]) model.bBids = Set(initialize=[ i for i in range(len(book.bids)) if book.bids[i].type == 'BB' ]) model.cBids = RangeSet(len(complexOrders)) # Complex orders model.C = RangeSet(len(self.connections)) model.directions = RangeSet(2) # 1 == up, 2 = down TODO: clean # Variables model.xs = Var(model.sBids, domain=Reals, bounds=(0.0, 1.0)) # Single period bids acceptance model.xb = Var(model.bBids, domain=Binary) # Block bids acceptance model.xc = Var(model.cBids, domain=Binary) # Complex orders acceptance model.pi = Var(model.L * model.periods, domain=Reals, bounds=self.priceCap) # Market prices model.s = Var(model.bids, domain=NonNegativeReals) # Bids model.sc = Var(model.cBids, domain=NonNegativeReals) # complex orders model.complexVolume = Var(model.cBids, model.periods, domain=Reals) # Bids model.pi_lg_up = Var(model.cBids * model.periods, domain=NonNegativeReals) # Market prices model.pi_lg_down = Var(model.cBids * model.periods, domain=NonNegativeReals) # Market prices model.pi_lg = Var(model.cBids * model.periods, domain=Reals) # Market prices def flowBounds(m, c, d, t): capacity = self.connections[c - 1].capacity_up[t] if d == 1 else \ self.connections[c - 1].capacity_down[t] return (0, capacity) model.f = Var(model.C * model.directions * model.periods, domain=NonNegativeReals, bounds=flowBounds) model.u = Var(model.C * model.directions * model.periods, domain=NonNegativeReals) # Objective def primalObj(m): # Single period bids cost expr = summation( {i: book.bids[i].price * book.bids[i].volume for i in m.sBids}, m.xs) # Block bids cost expr += summation( { i: book.bids[i].price * sum(book.bids[i].volumes.values()) for i in m.bBids }, m.xb) return -expr if options.PRIMAL and not options.DUAL: model.obj = Objective(rule=primalObj, sense=maximize) def primalDualObj(m): return primalObj(m) + sum(1e-5 * m.xc[i] for i in model.cBids) if options.PRIMAL and options.DUAL: model.obj = Objective(rule=primalDualObj, sense=maximize) # Complex order constraint if options.PRIMAL and options.DUAL: model.deactivate_suborders = ConstraintList() for o in model.cBids: sub_ids = complexOrders[o - 1].ids curves = complexOrders[o - 1].curves for id in sub_ids: bid = book.bids[id] if bid.period <= complexOrders[o - 1].SSperiods and bid.price == \ curves[bid.period].bids[0].price: pass # This bid, first step of the cruve in the scheduled stop periods, is not automatically deactivated when MIC constraint is not satisfied else: model.deactivate_suborders.add( model.xs[id] <= model.xc[o]) # Ramping constraints for complex orders def complex_volume_def_rule(m, o, p): sub_ids = complexOrders[o - 1].ids return m.complexVolume[o, p] == sum(m.xs[i] * book.bids[i].volume for i in sub_ids if book.bids[i].period == p) if options.PRIMAL: model.complex_volume_def = Constraint(model.cBids, model.periods, rule=complex_volume_def_rule) def complex_lg_down_rule(m, o, p): if p + 1 > maxPeriod or complexOrders[o - 1].ramp_down == None: return Constraint.Skip else: return m.complexVolume[o, p] - m.complexVolume[o, p + 1] <= complexOrders[ o - 1].ramp_down * \ m.xc[o] if options.PRIMAL and options.APPLY_LOAD_GRADIENT: model.complex_lg_down = Constraint(model.cBids, model.periods, rule=complex_lg_down_rule) def complex_lg_up_rule(m, o, p): if p + 1 > maxPeriod or complexOrders[o - 1].ramp_up == None: return Constraint.Skip else: return m.complexVolume[o, p + 1] - m.complexVolume[ o, p] <= complexOrders[o - 1].ramp_up if options.PRIMAL and options.APPLY_LOAD_GRADIENT: model.complex_lg_up = Constraint( model.cBids, model.periods, rule=complex_lg_up_rule) # Balance constraint # Energy balance constraints balanceExpr = {l: {t: 0.0 for t in model.periods} for l in model.L} for i in model.sBids: # Simple bids bid = book.bids[i] balanceExpr[bid.location][bid.period] += bid.volume * model.xs[i] for i in model.bBids: # Block bids bid = book.bids[i] for t, v in bid.volumes.items(): balanceExpr[bid.location][t] += v * model.xb[i] def balanceCstr(m, l, t): export = 0.0 for c in model.C: if self.connections[c - 1].from_id == l: export += m.f[c, 1, t] - m.f[c, 2, t] elif self.connections[c - 1].to_id == l: export += m.f[c, 2, t] - m.f[c, 1, t] return balanceExpr[l][t] == export if options.PRIMAL: model.balance = Constraint(model.L * book.periods, rule=balanceCstr) # Surplus of single period bids def sBidSurplus(m, i): # For the "usual" step orders bid = book.bids[i] if i in self.plain_single_orders: return m.s[i] >= (m.pi[bid.location, bid.period] - bid.price) * bid.volume else: return Constraint.Skip if options.DUAL: model.sBidSurplus = Constraint(model.sBids, rule=sBidSurplus) # Surplus definition for complex suborders accounting for impact of load gradient condition if options.DUAL: model.complex_sBidSurplus = ConstraintList() for o in model.cBids: sub_ids = complexOrders[o - 1].ids l = complexOrders[o - 1].location for i in sub_ids: bid = book.bids[i] model.complex_sBidSurplus.add( model.s[i] >= (model.pi[l, bid.period] + model.pi_lg[o, bid.period] - bid.price) * bid.volume) def LG_price_def_rule(m, o, p): l = complexOrders[o - 1].location exp = 0 if options.APPLY_LOAD_GRADIENT: D = complexOrders[o - 1].ramp_down U = complexOrders[o - 1].ramp_up if D is not None: exp += (m.pi_lg_down[o, p - 1] if p > 1 else 0) - (m.pi_lg_down[o, p] if p < maxPeriod else 0) if U is not None: exp -= (m.pi_lg_up[o, p - 1] if p > 1 else 0) - (m.pi_lg_up[o, p] if p < maxPeriod else 0) return m.pi_lg[o, p] == exp if options.DUAL: model.LG_price_def = Constraint(model.cBids, model.periods, rule=LG_price_def_rule) # Surplus of block bids def bBidSurplus(m, i): bid = book.bids[i] bidVolume = -sum(bid.volumes.values()) bigM = (self.priceCap[1] - self.priceCap[0]) * bidVolume # FIXME tighten BIGM return m.s[i] + sum([ m.pi[bid.location, t] * -v for t, v in bid.volumes.items() ]) >= bid.cost * bidVolume + bigM * (1 - m.xb[i]) if options.DUAL: model.bBidSurplus = Constraint(model.bBids, rule=bBidSurplus) # Surplus of complex orders def cBidSurplus(m, o): complexOrder = complexOrders[o - 1] sub_ids = complexOrder.ids if book.bids[sub_ids[0]].volume > 0: # supply bigM = sum((self.priceCap[1] - book.bids[i].price) * book.bids[i].volume for i in sub_ids) else: bigM = sum((book.bids[i].price - self.priceCap[0]) * book.bids[i].volume for i in sub_ids) return m.sc[o] + bigM * (1 - m.xc[o]) >= sum(m.s[i] for i in sub_ids) if options.DUAL: model.cBidSurplus = Constraint(model.cBids, rule=cBidSurplus) # Surplus of complex orders def cBidSurplus_2(m, o): complexOrder = complexOrders[o - 1] expr = 0 for i in complexOrder.ids: bid = book.bids[i] if (bid.period <= complexOrder.SSperiods) and ( bid.price == complexOrder.curves[bid.period].bids[0].price): expr += m.s[i] return m.sc[o] >= expr if options.DUAL: model.cBidSurplus_2 = Constraint( model.cBids, rule=cBidSurplus_2) # MIC constraint def cMIC(m, o): complexOrder = complexOrders[o - 1] if complexOrder.FT == 0 and complexOrder.VT == 0: return Constraint.Skip expr = 0 bigM = complexOrder.FT for i in complexOrder.ids: bid = book.bids[i] if (bid.period <= complexOrder.SSperiods) and ( bid.price == complexOrder.curves[bid.period].bids[0].price): bigM += (bid.volume * (self.priceCap[1] - bid.price) ) # FIXME assumes order is supply expr += bid.volume * m.xs[i] * (bid.price - complexOrder.VT) return m.sc[o] + expr + bigM * (1 - m.xc[o]) >= complexOrder.FT if options.DUAL and options.PRIMAL: model.cMIC = Constraint(model.cBids, rule=cMIC) # Dual connections capacity def dualCapacity(m, c, t): exportPrices = 0.0 for l in m.L: if l == self.connections[c - 1].from_id: exportPrices += m.pi[l, t] elif l == self.connections[c - 1].to_id: exportPrices -= m.pi[l, t] return m.u[c, 1, t] - m.u[c, 2, t] + exportPrices == 0.0 if options.DUAL: model.dualCapacity = Constraint(model.C * model.periods, rule=dualCapacity) # Dual optimality def dualObj(m): dualObj = summation(m.s) + summation(m.sc) for o in m.cBids: sub_ids = complexOrders[o - 1].ids for id in sub_ids: dualObj -= m.s[ id] # Remove contribution of complex suborders which were accounted for in prevous summation over single bids if options.APPLY_LOAD_GRADIENT: ramp_down = complexOrders[o - 1].ramp_down ramp_up = complexOrders[o - 1].ramp_up for p in m.periods: if p == maxPeriod: continue if ramp_down is not None: dualObj += ramp_down * m.pi_lg_down[ o, p] # Add contribution of load gradient if ramp_up is not None: dualObj += ramp_up * m.pi_lg_up[ o, p] # Add contribution of load gradient for c in model.C: for t in m.periods: dualObj += self.connections[c - 1].capacity_up[t] * m.u[c, 1, t] dualObj += self.connections[c - 1].capacity_down[t] * m.u[c, 2, t] return dualObj if not options.PRIMAL: model.obj = Objective(rule=dualObj, sense=minimize) def primalEqualsDual(m): return primalObj(m) >= dualObj(m) if options.DUAL and options.PRIMAL: model.primalEqualsDual = Constraint(rule=primalEqualsDual) self.model = model
def representative(duration_repr, selection, VWat=75000, solArea=2 * (18300 + 15000), VSTC=75000, pipe_model='ExtensivePipe', time_step=3600): """ Args: duration_repr: selection: VWat: solArea: VSTC: pipe_model: time_step: Returns: """ unit_sec = 3600 * 24 # Seconds per unit time of duration (seconds per day) netGraph = CaseFuture.make_graph(repr=True) import pandas as pd import time begin = time.clock() topmodel = ConcreteModel() # In[14]: optimizers = {} epoch = pd.Timestamp('20140101') for start_day, duration in selection.items(): start_time = epoch + pd.Timedelta(days=start_day) optmodel = Modesto(graph=netGraph, pipe_model=pipe_model) for comp in optmodel.get_node_components( filter_type='StorageCondensed').values(): comp.set_reps(num_reps=int(duration)) topmodel.add_component(name='repr_' + str(start_day), val=optmodel.model) ##################### # Assign parameters # ##################### optmodel = CaseFuture.set_params( optmodel, pipe_model=pipe_model, repr=True, horizon=duration_repr * unit_sec, time_step=time_step, ) optmodel.change_param(node='SolarArray', comp='solar', param='area', val=solArea) optmodel.change_param(node='SolarArray', comp='tank', param='volume', val=VSTC) optmodel.change_param(node='WaterscheiGarden', comp='tank', param='volume', val=VWat) optmodel.change_param(node='Production', comp='backup', param='ramp', val=0) optmodel.change_param(node='Production', comp='backup', param='ramp_cost', val=0) optmodel.compile(start_time=start_time) # optmodel.set_objective('energy') optimizers[start_day] = optmodel # In[ ]: ############################## # Compile aggregated problem # ############################## selected_days = selection.keys() for i, next_day in enumerate(selected_days): current = selected_days[i - 1] next_heat = optimizers[next_day].get_node_components( filter_type='StorageCondensed') current_heat = optimizers[current].get_node_components( filter_type='StorageCondensed') for component_id in next_heat: # Link begin and end of representative periods def _link_stor(m): """ Args: m: Returns: """ return next_heat[component_id].get_heat_stor_init() == \ current_heat[component_id].get_heat_stor_final() topmodel.add_component(name='_'.join( [component_id, str(current), 'eq']), val=Constraint(rule=_link_stor)) # print 'State equation added for storage {} in representative week starting on day {}'.format( # component_id, # current) # In[ ]: def _top_objective(m): """ Args: m: Returns: """ return 365 / (duration_repr * (365 // duration_repr)) * sum( repetitions * optimizers[start_day].get_objective(objtype='energy', get_value=False) for start_day, repetitions in selection.items()) # Factor 365/364 to make up for missing day # set get_value to False to return object instead of value of the objective function topmodel.obj = Objective(rule=_top_objective, sense=minimize) # In[ ]: end = time.clock() # print 'Writing time:', str(end - begin) return topmodel, optimizers
def minimize_dr_vars(model_data, config): """ Decision rule polishing: For a given optimal design (x) determined in separation, and the optimal value for control vars (z), choose min magnitude decision_rule_var values. """ #config.progress_logger.info("Executing decision rule variable polishing solve.") model = model_data.master_model polishing_model = model.clone() first_stage_variables = polishing_model.scenarios[ 0, 0].util.first_stage_variables decision_rule_vars = polishing_model.scenarios[0, 0].util.decision_rule_vars polishing_model.obj.deactivate() index_set = decision_rule_vars[0].index_set() polishing_model.tau_vars = [] # ========== for idx in range(len(decision_rule_vars)): polishing_model.scenarios[0, 0].add_component( "polishing_var_" + str(idx), Var(index_set, initialize=1e6, domain=NonNegativeReals)) polishing_model.tau_vars.append( getattr(polishing_model.scenarios[0, 0], "polishing_var_" + str(idx))) # ========== this_iter = polishing_model.scenarios[ max(polishing_model.scenarios.keys())[0], 0] nom_block = polishing_model.scenarios[0, 0] if config.objective_focus == ObjectiveType.nominal: obj_val = value(this_iter.second_stage_objective + this_iter.first_stage_objective) polishing_model.scenarios[0,0].polishing_constraint = \ Constraint(expr=obj_val >= nom_block.second_stage_objective + nom_block.first_stage_objective) elif config.objective_focus == ObjectiveType.worst_case: polishing_model.zeta.fix( ) # Searching equivalent optimal solutions given optimal zeta # === Make absolute value constraints on polishing_vars polishing_model.scenarios[ 0, 0].util.absolute_var_constraints = cons = ConstraintList() uncertain_params = nom_block.util.uncertain_params if config.decision_rule_order == 1: for i, tau in enumerate(polishing_model.tau_vars): for j in range(len(this_iter.util.decision_rule_vars[i])): if j == 0: cons.add( -tau[j] <= this_iter.util.decision_rule_vars[i][j]) cons.add(this_iter.util.decision_rule_vars[i][j] <= tau[j]) else: cons.add( -tau[j] <= this_iter.util.decision_rule_vars[i][j] * uncertain_params[j - 1]) cons.add(this_iter.util.decision_rule_vars[i][j] * uncertain_params[j - 1] <= tau[j]) elif config.decision_rule_order == 2: l = list(range(len(uncertain_params))) index_pairs = list(it.combinations(l, 2)) for i, tau in enumerate(polishing_model.tau_vars): Z = this_iter.util.decision_rule_vars[i] indices = list(k for k in range(len(Z))) for r in indices: if r == 0: cons.add(-tau[r] <= Z[r]) cons.add(Z[r] <= tau[r]) elif r <= len(uncertain_params) and r > 0: cons.add(-tau[r] <= Z[r] * uncertain_params[r - 1]) cons.add(Z[r] * uncertain_params[r - 1] <= tau[r]) elif r <= len(indices) - len(uncertain_params) - 1 and r > len( uncertain_params): cons.add(-tau[r] <= Z[r] * uncertain_params[index_pairs[ r - len(uncertain_params) - 1][0]] * uncertain_params[ index_pairs[r - len(uncertain_params) - 1][1]]) cons.add(Z[r] * uncertain_params[index_pairs[ r - len(uncertain_params) - 1][0]] * uncertain_params[index_pairs[ r - len(uncertain_params) - 1][1]] <= tau[r]) elif r > len(indices) - len(uncertain_params) - 1: cons.add(-tau[r] <= Z[r] * uncertain_params[r - len(index_pairs) - len(uncertain_params) - 1]**2) cons.add(Z[r] * uncertain_params[r - len(index_pairs) - len(uncertain_params) - 1]**2 <= tau[r]) else: raise NotImplementedError( "Decision rule variable polishing has not been generalized to decision_rule_order " + str(config.decision_rule_order) + ".") polishing_model.scenarios[0,0].polishing_obj = \ Objective(expr=sum(sum(tau[j] for j in tau.index_set()) for tau in polishing_model.tau_vars)) # === Fix design for d in first_stage_variables: d.fix() # === Unfix DR vars num_dr_vars = len(model.scenarios[ 0, 0].util.decision_rule_vars[0]) # there is at least one dr var num_uncertain_params = len(config.uncertain_params) if model.const_efficiency_applied: for d in decision_rule_vars: for i in range(1, num_dr_vars): d[i].fix(0) d[0].unfix() elif model.linear_efficiency_applied: for d in decision_rule_vars: d.unfix() for i in range(num_uncertain_params + 1, num_dr_vars): d[i].fix(0) else: for d in decision_rule_vars: d.unfix() # === Unfix all control var values for block in polishing_model.scenarios.values(): for c in block.util.second_stage_variables: c.unfix() if model.const_efficiency_applied: for d in block.util.decision_rule_vars: for i in range(1, num_dr_vars): d[i].fix(0) d[0].unfix() elif model.linear_efficiency_applied: for d in block.util.decision_rule_vars: d.unfix() for i in range(num_uncertain_params + 1, num_dr_vars): d[i].fix(0) else: for d in block.util.decision_rule_vars: d.unfix() # === Solve the polishing model polish_soln = MasterResult() solver = config.global_solver if not solver.available(): raise RuntimeError("NLP solver %s is not available." % config.solver) try: results = solver.solve(polishing_model, tee=config.tee) polish_soln.termination_condition = results.solver.termination_condition except ValueError as err: polish_soln.pyros_termination_condition = pyrosTerminationCondition.subsolver_error polish_soln.termination_condition = tc.error raise polish_soln.fsv_values = list( v.value for v in polishing_model.scenarios[0, 0].util.first_stage_variables) polish_soln.ssv_values = list( v.value for v in polishing_model.scenarios[0, 0].util.second_stage_variables) polish_soln.first_stage_objective = value(nom_block.first_stage_objective) polish_soln.second_stage_objective = value( nom_block.second_stage_objective) # === Process solution by termination condition acceptable = [tc.optimal, tc.locallyOptimal, tc.feasible] if polish_soln.termination_condition not in acceptable: return results for i, d in enumerate( model_data.master_model.scenarios[0, 0].util.decision_rule_vars): for index in d: d[index].set_value(polishing_model.scenarios[ 0, 0].util.decision_rule_vars[i][index].value, skip_validation=True) return results
def _dualize(self, block, unfixed=[]): """ Generate the dual of a block """ # # Collect linear terms from the block # A, b_coef, c_rhs, c_sense, d_sense, vnames, cnames, v_domain = collect_linear_terms( block, unfixed) ##print(A) ##print(vnames) ##print(cnames) ##print(list(A.keys())) ##print("---") ##print(A.keys()) ##print(c_sense) ##print(c_rhs) # # Construct the block # if isinstance(block, Model): dual = ConcreteModel() else: dual = Block() dual.construct() _vars = {} def getvar(name, ndx=None): v = _vars.get((name, ndx), None) if v is None: v = Var() if ndx is None: v_name = name elif type(ndx) is tuple: v_name = "%s[%s]" % (name, ','.join(map(str, ndx))) else: v_name = "%s[%s]" % (name, str(ndx)) setattr(dual, v_name, v) _vars[name, ndx] = v return v # # Construct the objective # if d_sense == minimize: dual.o = Objective(expr=sum(-b_coef[name, ndx] * getvar(name, ndx) for name, ndx in b_coef), sense=d_sense) else: dual.o = Objective(expr=sum(b_coef[name, ndx] * getvar(name, ndx) for name, ndx in b_coef), sense=d_sense) # # Construct the constraints # for cname in A: for ndx, terms in iteritems(A[cname]): expr = 0 for term in terms: expr += term.coef * getvar(term.var, term.ndx) if not (cname, ndx) in c_rhs: c_rhs[cname, ndx] = 0.0 if c_sense[cname, ndx] == 'e': e = expr - c_rhs[cname, ndx] == 0 elif c_sense[cname, ndx] == 'l': e = expr - c_rhs[cname, ndx] <= 0 else: e = expr - c_rhs[cname, ndx] >= 0 c = Constraint(expr=e) if ndx is None: c_name = cname elif type(ndx) is tuple: c_name = "%s[%s]" % (cname, ','.join(map(str, ndx))) else: c_name = "%s[%s]" % (cname, str(ndx)) setattr(dual, c_name, c) # for (name, ndx), domain in iteritems(v_domain): v = getvar(name, ndx) flag = type(ndx) is tuple and (ndx[-1] == 'lb' or ndx[-1] == 'ub') if domain == 1: v.domain = NonNegativeReals elif domain == -1: v.domain = NonPositiveReals else: # TODO: verify that this case is possible v.domain = Reals return dual
for x in e.states: con = getattr(e.d1, x + '_icc') with open("states_sens.txt", "a") as f: for key in con.keys(): if not con[key].active: continue f.write(x + "\t" + str(key) + "\n") f.close() # con.set_suffix_value(e.d1.dcdp, 1) var = getattr(e.d1, x) for key in var.keys(): if key[1] == e.ncp_t: if var[key].stale: continue con[key[2:]].set_suffix_value(e.d1.dcdp, ii) var[key].set_suffix_value(e.d1.var_order, ii) ii += 1 f = open("suf0.txt", "w") e.d1.var_order.pprint(ostream=f) f.close() e.d1.dum_of = Objective(expr=1, sense=minimize) e.d1.write_nl(name="whatevs0.nl") kaug = SolverFactory("k_aug", executable="/home/dav0/k2/KKT_matrix/src/kmatrix/k_aug") kaug.options["compute_dsdp"] = "" f = open("suf1.txt", "w") e.d1.var_order.pprint(ostream=f) f.close() e.d1.write_nl(name="whatevs.nl") kaug.solve(e.d1, tee=True) # Turn off file determinism
def find_target_ss(self, ref_state=None, **kwargs): """Attempt to find a second steady state Args: ref_state (dict): Contains the reference state with value key "state", (j,): value kwargs (dict): Optional arguments Returns None""" if ref_state: self.ref_state = ref_state else: if not ref_state: self.journalist("W", self._iteration_count, "find_target_ss", "No reference state was given, using default") if not self.ref_state: self.journalist("W", self._iteration_count, "find_target_ss", "No default reference state was given, exit") sys.exit() weights_ref = dict.fromkeys(self.ref_state.keys()) for i in self.ref_state.keys(): v = getattr(self.SteadyRef, i[0]) vkey = i[1] vss0 = value(v[(0, 1) + vkey]) val = abs(self.ref_state[i] - vss0) if val < 1e-09: val = 1e+06 else: val = 1/val weights_ref[i] = val weights = kwargs.pop("weights", weights_ref) self.journalist("I", self._iteration_count, "find_target_ss", "Attempting to find steady state") del self.SteadyRef2 self.SteadyRef2 = self.d_mod(1, 1, steady=True) self.SteadyRef2.name = "SteadyRef2 (reference)" for u in self.u: cv = getattr(self.SteadyRef2, u) #: Get the param c_val = [value(cv[i]) for i in cv.keys()] #: Current value self.SteadyRef2.del_component(cv) #: Delete the param self.SteadyRef2.add_component(u, Var(self.SteadyRef2.fe_t, initialize=lambda m, i: c_val[i-1])) self.SteadyRef2.equalize_u(direction="r_to_u") cc = getattr(self.SteadyRef2, u + "_c") #: Get the constraint ce = getattr(self.SteadyRef2, u + "_e") #: Get the expression cv = getattr(self.SteadyRef2, u) #: Get the new variable for k in cv.keys(): cv[k].setlb(self.u_bounds[u][0]) cv[k].setub(self.u_bounds[u][1]) cc.clear() cc.rule = lambda m, i: cv[i] == ce[i] cc.reconstruct() self.SteadyRef2.create_bounds() self.SteadyRef2.equalize_u(direction="r_to_u") for vs in self.SteadyRef.component_objects(Var, active=True): #: Load_guess vt = getattr(self.SteadyRef2, vs.getname()) for ks in vs.keys(): vt[ks].set_value(value(vs[ks])) ofexp = 0 for i in self.ref_state.keys(): v = getattr(self.SteadyRef2, i[0]) val = value((v[(0, 1) + vkey])) vkey = i[1] ofexp += weights[i] * (v[(0, 1) + vkey] - self.ref_state[i])**2 # ofexp += -weights[i] * (v[(1, 1) + vkey])**2 #- self.ref_state[i])**2 self.SteadyRef2.obfun_SteadyRef2 = Objective(expr=ofexp, sense=minimize) tst = self.solve_dyn(self.SteadyRef2, iter_max=10000, stop_if_nopt=True, halt_on_ampl_error=False, **kwargs) # self.SteadyRef2.write_nl(name="steady.nl") # self.SteadyRef2.write_nl() # self.SteadyRef2.snap_shot(filename="mom.py") # sys.exit() if tst != 0: self.SteadyRef2.display(filename="failed_SteadyRef2.txt") self.SteadyRef2.write(filename="failed_SteadyRef2.nl", format=ProblemFormat.nl, io_options={"symbolic_solver_labels": True}) # sys.exit(-1) self.journalist("I", self._iteration_count, "find_target_ss", "Target: solve done") for i in self.ref_state.keys(): v = getattr(self.SteadyRef2, i[0]) vkey = i[1] val = value(v[(0, 1) + vkey]) print("target {:}".format(i[0]), "key {:}".format(i[1]), "weight {:f}".format(weights[i]), "value {:f}".format(val)) for u in self.u: v = getattr(self.SteadyRef2, u) val = value(v[0]) print("target {:}".format(u), " value {:f}".format(val)) self.update_targets_nmpc()
def __init__( self, data, target, number_regions, lam, epsilon=0.01, f_star=None, selected_features=None, ): super().__init__( name="OplraRegression %d regions (f*=%s)" % (number_regions, f_star) ) self.number_regions = number_regions # Data and parameters self.data = data self.target = target self.lam = lam self.U1 = 1.5 self.U2 = sum(self.target) self.epsilon = epsilon # Indices of the model self.s = Set(initialize=data.index.tolist()) self.r = Set(initialize=range(self.number_regions)) if self.number_regions == 1 or selected_features is None: self.f = Set(initialize=self.data.columns, ordered=True) else: self.f = Set(initialize=selected_features, ordered=True) # Variables common to both FEATURE_SELECTION and PIECEWISE models self.W = Var(self.r, self.f, initialize=0) self.absW = Var(self.r, self.f, domain=NonNegativeReals, initialize=0) self.B = Var(self.r, initialize=0) self.Pred = Var(self.r, self.s, initialize=0) self.D = Var(self.s, domain=NonNegativeReals, initialize=0) self.F = Var(self.r, self.s, domain=Binary, initialize=0) self.z = Var(domain=NonNegativeReals, initialize=0) self.mae = Var(domain=NonNegativeReals, initialize=0) self.reg = Var(domain=NonNegativeReals, initialize=0) if self.number_regions > 1 and f_star is None: raise ValueError("f_star is invalid.") self.fStar = f_star # Specific variables and constraints according to model (number of regions) if self.number_regions == 1: self.sf = Var(self.f, domain=Binary, initialize=0) # Old equations used for explicit feature selection # self.number_features = Constraint(rule=OplraPyomoModel.number_features_rule) # self.upper_bound_coeff = Constraint(self.r, self.f, rule=OplraPyomoModel.upper_bound_coeff_rule) # self.lower_bound_coeff = Constraint(self.r, self.f, rule=OplraPyomoModel.lower_bound_coeff_rule) else: self.isSimpleLinear = False self.fStar = self.fStar self.X = Var(self.r, bounds=(0.0, 1.0), initialize=0) self.rr = Set(within=self.r) self.breakpoint_order = Constraint( self.r, rule=OplraPyomoModel.breakpoint_order_rule ) self.region_divider1 = Constraint( self.r, self.s, rule=OplraPyomoModel.region_divider1_rule ) self.region_divider2 = Constraint( self.r, self.s, rule=OplraPyomoModel.region_divider2_rule ) # Common constraints self.sample_to_region = Constraint( self.s, rule=OplraPyomoModel.sample_to_region_rule ) self.prediction = Constraint( self.r, self.s, rule=OplraPyomoModel.prediction_rule ) self.abs_error1 = Constraint( self.r, self.s, rule=OplraPyomoModel.abs_error1_rule ) self.abs_error2 = Constraint( self.r, self.s, rule=OplraPyomoModel.abs_error2_rule ) self.abs_coeff1 = Constraint( self.r, self.f, rule=OplraPyomoModel.abs_coeff1_rule ) self.abs_coeff2 = Constraint( self.r, self.f, rule=OplraPyomoModel.abs_coeff2_rule ) self.mae_eqn = Constraint(rule=OplraPyomoModel.mae_rule) self.reg_eqn = Constraint(rule=OplraPyomoModel.regularisation_rule) self.z_eqn = Constraint(rule=OplraPyomoModel.z_rule) self.obj = Objective(rule=OplraPyomoModel.objective_rule, sense=minimize)
def _dualize(self, block, unfixed=[]): """ Generate the dual of a block """ # # Collect linear terms from the block # A, b_coef, c_rhs, c_sense, d_sense, vnames, cnames, v_domain = collect_linear_terms( block, unfixed) # # Construct the block # if isinstance(block, Model): dual = ConcreteModel() else: dual = Block() for v, is_indexed in vnames: if is_indexed: setattr(dual, v + '_Index', Set(dimen=None)) setattr(dual, v, Var(getattr(dual, v + '_Index'))) else: setattr(dual, v, Var()) for cname, is_indexed in cnames: if is_indexed: setattr(dual, cname + '_Index', Set(dimen=None)) setattr(dual, cname, Constraint(getattr(dual, cname + '_Index'))) setattr(dual, cname + '_lower_', Var(getattr(dual, cname + '_Index'))) setattr(dual, cname + '_upper_', Var(getattr(dual, cname + '_Index'))) else: setattr(dual, cname, Constraint()) setattr(dual, cname + '_lower_', Var()) setattr(dual, cname + '_upper_', Var()) dual.construct() # # Add variables # # TODO: revisit this hack. We shouldn't be calling # _getitem_when_not_present() # for name, ndx in b_coef: v = getattr(dual, name) if not ndx in v: v._getitem_when_not_present(ndx) # # Construct the objective # if d_sense == minimize: dual.o = Objective(expr=sum(-b_coef[name, ndx] * getattr(dual, name)[ndx] for name, ndx in b_coef), sense=d_sense) else: dual.o = Objective(expr=sum(b_coef[name, ndx] * getattr(dual, name)[ndx] for name, ndx in b_coef), sense=d_sense) # # Construct the constraints # for cname in A: c = getattr(dual, cname) c_index = getattr(dual, cname + "_Index") if c.is_indexed() else None for ndx, terms in iteritems(A[cname]): if not c_index is None and not ndx in c_index: c_index.add(ndx) expr = 0 for term in terms: v = getattr(dual, term.var) if not term.ndx in v: v.add(term.ndx) expr += term.coef * v[term.ndx] if not (cname, ndx) in c_rhs: c_rhs[cname, ndx] = 0.0 if c_sense[cname, ndx] == 'e': c.add(ndx, expr - c_rhs[cname, ndx] == 0) elif c_sense[cname, ndx] == 'l': c.add(ndx, expr - c_rhs[cname, ndx] <= 0) else: c.add(ndx, expr - c_rhs[cname, ndx] >= 0) for (name, ndx), domain in iteritems(v_domain): v = getattr(dual, name) flag = type(ndx) is tuple and (ndx[-1] == 'lb' or ndx[-1] == 'ub') if domain == 1: if flag: v[ndx].domain = NonNegativeReals else: v.domain = NonNegativeReals elif domain == -1: if flag: v[ndx].domain = NonPositiveReals else: v.domain = NonPositiveReals else: if flag: # TODO: verify that this case is possible v[ndx].domain = Reals else: v.domain = Reals return dual
def __init__(self, **kwargs): # Values for the suffixes of input files self.int_file_mhe_suf = int() self.res_file_mhe_suf = str() self.int_file_nmpc_suf = int() self.res_file_nmpc_suf = str() self.res_file_suf = str(int(time.time())) self.d_mod = kwargs.pop('d_mod', None) self.nfe_t = kwargs.pop('nfe_t', 5) self.ncp_t = kwargs.pop('ncp_t', 3) self._t = kwargs.pop('_t', 100) self.states = kwargs.pop('states', []) self.u = kwargs.pop('u', []) #: The inputs (controls) self.hi_t = self._t / self.nfe_t self.ss = self.d_mod(1, 1, steady=True) self.ss2 = object self.d1 = self.d_mod(1, self.ncp_t, _t=self.hi_t) self.d2 = object() self.ss.name = "ss" self.d1.name = "d1" self.ipopt = SolverFactory("ipopt") self.asl_ipopt = SolverFactory("asl:ipopt") self.k_aug = SolverFactory( "k_aug", executable="/home/dav0/k2/KKT_matrix/src/kmatrix/k_aug") self.k_aug_sens = SolverFactory( "k_aug", executable="/home/dav0/k2/KKT_matrix/src/kmatrix/k_aug") self.dot_driver = SolverFactory( "dot_driver", executable= "/home/dav0/k2/KKT_matrix/src/kmatrix/dot_driver/dot_driver") # self.k_aug.options["eig_rh"] = "" self.asl_ipopt.options["halt_on_ampl_error"] = "yes" # self.ipopt.options["print_user_options"] = "yes" # self.k_aug.options["deb_kkt"] = "" self.ss.ofun = Objective(expr=1, sense=minimize) self.dyn = object() self.l_state = [] self.l_vals = [] self._c_it = 0 self.ccl = [] self.iput = [] self.sp = [] self._kt_list = [] self._dt_list = [] self._ipt_list = [] self._k_timing = ["0", "0", "0"] self._dot_timing = "0" self.ip_time = 0 self._stall_iter = 0 self._window_keep = self.nfe_t + 2 self._u_plant = {} #: key: (ui, time) for i in self.u: u = getattr(self.d1, i) for t in range(0, self._window_keep): self._u_plant[(i, t)] = value(u[1]) self.curr_u = dict.fromkeys(self.u, 0.0) self.state_vars = {} self.curr_estate = {} #: Current estimated state (for the olnmpc) self.curr_rstate = {} #: Current real state (for the olnmpc) self.curr_state_offset = {} #: Current offset of measurement self.curr_pstate = {} #: Current offset of measurement self.curr_state_noise = {} #: Current noise of the state self.curr_state_target = {} #: Current target state self.curr_u_target = {} #: Current control state self.xp_l = [] self.xp_key = {} with open("ipopt.opt", "w") as f: f.close()
def __init__(self, **kwargs): NmpcGen.__init__(self, **kwargs) self.int_file_mhe_suf = int(time.time())-1 # Need a list of relevant measurements y self.y = kwargs.pop('y', []) self.y_vars = kwargs.pop('y_vars', {}) # Need a list or relevant noisy-states z self.x_noisy = kwargs.pop('x_noisy', []) self.x_vars = kwargs.pop('x_vars', {}) self.deact_ics = kwargs.pop('del_ics', True) self.diag_Q_R = kwargs.pop('diag_QR', True) #: By default use diagonal matrices for Q and R matrices self.u = kwargs.pop('u', []) self.IgnoreProcessNoise = kwargs.pop('IgnoreProcessNoise', False) print("-" * 120) print("I[[create_lsmhe]] lsmhe (full) model created.") print("-" * 120) nstates = sum(len(self.x_vars[x]) for x in self.x_noisy) self.journalizer("I", self._c_it, "MHE with \t", str(nstates) + "states") self.journalizer("I", self._c_it, "MHE with \t", str(nstates*self.nfe_t*self.ncp_t) + "noise vars") self.lsmhe = self.d_mod(self.nfe_t, self.ncp_t, _t=self._t) self.lsmhe.name = "LSMHE (Least-Squares MHE)" self.lsmhe.create_bounds() #: create x_pi constraint #: Create list of noisy-states vars self.xkN_l = [] self.xkN_nexcl = [] self.xkN_key = {} k = 0 for x in self.x_noisy: n_s = getattr(self.lsmhe, x) #: Noisy-state for jth in self.x_vars[x]: #: the jth variable self.xkN_l.append(n_s[(1, 0) + jth]) self.xkN_nexcl.append(1) #: non-exclusion list for active bounds self.xkN_key[(x, jth)] = k k += 1 self.lsmhe.xkNk_mhe = Set(initialize=[i for i in range(0, len(self.xkN_l))]) #: Create set of noisy_states self.lsmhe.x_0_mhe = Param(self.lsmhe.xkNk_mhe, initialize=0.0, mutable=True) #: Prior-state self.lsmhe.wk_mhe = Param(self.lsmhe.fe_t, self.lsmhe.cp_ta, self.lsmhe.xkNk_mhe, initialize=0.0) \ if self.IgnoreProcessNoise else Expression(self.lsmhe.fe_t, self.lsmhe.cp_ta, self.lsmhe.xkNk_mhe) #: Model disturbance self.lsmhe.PikN_mhe = Param(self.lsmhe.xkNk_mhe, self.lsmhe.xkNk_mhe, initialize=lambda m, i, ii: 1. if i == ii else 0.0, mutable=True) #: Prior-Covariance self.lsmhe.Q_mhe = Param(range(1, self.nfe_t), self.lsmhe.xkNk_mhe, initialize=1, mutable=True) if self.diag_Q_R\ else Param(range(1, self.nfe_t), self.lsmhe.xkNk_mhe, self.lsmhe.xkNk_mhe, initialize=lambda m, t, i, ii: 1. if i == ii else 0.0, mutable=True) #: Disturbance-weight j = 0 for i in self.x_noisy: de_exp = getattr(self.lsmhe, "de_" + i) for k in self.x_vars[i]: for tfe in range(1, self.nfe_t+1): for tcp in range(1, self.ncp_t + 1): self.lsmhe.wk_mhe[tfe, tcp, j].set_value(de_exp[(tfe, tcp) + k]._body) de_exp[(tfe, tcp) + k].deactivate() j += 1 #: Create list of measurements vars self.yk_l = {} self.yk_key = {} k = 0 self.yk_l[1] = [] for y in self.y: m_v = getattr(self.lsmhe, y) #: Measured "state" for jth in self.y_vars[y]: #: the jth variable self.yk_l[1].append(m_v[(1, self.ncp_t) + jth]) self.yk_key[(y, jth)] = k #: The key needs to be created only once, that is why the loop was split k += 1 for t in range(2, self.nfe_t + 1): self.yk_l[t] = [] for y in self.y: m_v = getattr(self.lsmhe, y) #: Measured "state" for jth in self.y_vars[y]: #: the jth variable self.yk_l[t].append(m_v[(t, self.ncp_t) + jth]) self.lsmhe.ykk_mhe = Set(initialize=[i for i in range(0, len(self.yk_l[1]))]) #: Create set of measured_vars self.lsmhe.nuk_mhe = Var(self.lsmhe.fe_t, self.lsmhe.ykk_mhe, initialize=0.0) #: Measurement noise self.lsmhe.yk0_mhe = Param(self.lsmhe.fe_t, self.lsmhe.ykk_mhe, initialize=1.0, mutable=True) self.lsmhe.hyk_c_mhe = Constraint(self.lsmhe.fe_t, self.lsmhe.ykk_mhe, rule= lambda mod, t, i:mod.yk0_mhe[t, i] - self.yk_l[t][i] - mod.nuk_mhe[t, i] == 0.0) self.lsmhe.hyk_c_mhe.deactivate() self.lsmhe.R_mhe = Param(self.lsmhe.fe_t, self.lsmhe.ykk_mhe, initialize=1.0, mutable=True) if self.diag_Q_R else \ Param(self.lsmhe.fe_t, self.lsmhe.ykk_mhe, self.lsmhe.ykk_mhe, initialize=lambda mod, t, i, ii: 1.0 if i == ii else 0.0, mutable=True) f = open("file_cv.txt", "w") f.close() #: Constraints for the input noise for u in self.u: # cv = getattr(self.lsmhe, u) #: Get the param # c_val = [value(cv[i]) for i in cv.keys()] #: Current value # self.lsmhe.del_component(cv) #: Delete the param # self.lsmhe.add_component(u + "_mhe", Var(self.lsmhe.fe_t, initialize=lambda m, i: c_val[i-1])) self.lsmhe.add_component("w_" + u + "_mhe", Var(self.lsmhe.fe_t, initialize=0.0)) #: Noise for input self.lsmhe.add_component("w_" + u + "c_mhe", Constraint(self.lsmhe.fe_t)) self.lsmhe.equalize_u(direction="r_to_u") # cc = getattr(self.lsmhe, u + "_c") #: Get the constraint for input con_w = getattr(self.lsmhe, "w_" + u + "c_mhe") #: Get the constraint-noisy var_w = getattr(self.lsmhe, "w_" + u + "_mhe") #: Get the constraint-noisy ce = getattr(self.lsmhe, u + "_e") #: Get the expression cp = getattr(self.lsmhe, u) #: Get the param con_w.rule = lambda m, i: cp[i] == ce[i] + var_w[i] con_w.reconstruct() con_w.deactivate() # con_w.rule = lambda m, i: cp[i] == cv[i] + var_w[i] # con_w.reconstruct() # with open("file_cv.txt", "a") as f: # cc.pprint(ostream=f) # con_w.pprint(ostream=f) # f.close() self.lsmhe.U_mhe = Param(range(1, self.nfe_t + 1), self.u, initialize=1, mutable=True) #: Deactivate icc constraints if self.deact_ics: pass # for i in self.states: # self.lsmhe.del_component(i + "_icc") #: Maybe only for a subset of the states else: for i in self.states: if i in self.x_noisy: ic_con = getattr(self.lsmhe, i + "_icc") for k in self.x_vars[i]: ic_con[k].deactivate() #: Put the noise in the continuation equations (finite-element) j = 0 self.lsmhe.noisy_cont = ConstraintList() for i in self.x_noisy: # cp_con = getattr(self.lsmhe, "cp_" + i) cp_exp = getattr(self.lsmhe, "noisy_" + i) # self.lsmhe.del_component(cp_con) for k in self.x_vars[i]: #: This should keep the same order for t in range(1, self.nfe_t): self.lsmhe.noisy_cont.add(cp_exp[t, k] == 0.0) # self.lsmhe.noisy_cont.add(cp_exp[t, k] == 0.0) j += 1 # cp_con.reconstruct() j = 0 self.lsmhe.noisy_cont.deactivate() #: Expressions for the objective function (least-squares) self.lsmhe.Q_e_mhe = 0.0 if self.IgnoreProcessNoise else Expression( expr=0.5 * sum( sum( sum(self.lsmhe.Q_mhe[1, k] * self.lsmhe.wk_mhe[i, j, k]**2 for k in self.lsmhe.xkNk_mhe) for j in range(1, self.ncp_t +1)) for i in range(1, self.nfe_t+1))) if self.diag_Q_R else Expression( expr=sum(sum(self.lsmhe.wk_mhe[i, j] * sum(self.lsmhe.Q_mhe[i, j, k] * self.lsmhe.wk_mhe[i, 1, k] for k in self.lsmhe.xkNk_mhe) for j in self.lsmhe.xkNk_mhe) for i in range(1, self.nfe_t))) self.lsmhe.R_e_mhe = Expression( expr=0.5 * sum( sum( self.lsmhe.R_mhe[i, k] * self.lsmhe.nuk_mhe[i, k]**2 for k in self.lsmhe.ykk_mhe) for i in self.lsmhe.fe_t)) if self.diag_Q_R else Expression( expr=sum(sum(self.lsmhe.nuk_mhe[i, j] * sum(self.lsmhe.R_mhe[i, j, k] * self.lsmhe.nuk_mhe[i, k] for k in self.lsmhe.ykk_mhe) for j in self.lsmhe.ykk_mhe) for i in self.lsmhe.fe_t)) expr_u_obf = 0 for i in self.lsmhe.fe_t: for u in self.u: var_w = getattr(self.lsmhe, "w_" + u + "_mhe") #: Get the constraint-noisy expr_u_obf += self.lsmhe.U_mhe[i, u] * var_w[i] ** 2 self.lsmhe.U_e_mhe = Expression(expr=0.5 * expr_u_obf) # how about this # with open("file_cv.txt", "a") as f: # self.lsmhe.U_e_mhe.pprint(ostream=f) # f.close() self.lsmhe.Arrival_e_mhe = Expression( expr=0.5 * sum((self.xkN_l[j] - self.lsmhe.x_0_mhe[j]) * sum(self.lsmhe.PikN_mhe[j, k] * (self.xkN_l[k] - self.lsmhe.x_0_mhe[k]) for k in self.lsmhe.xkNk_mhe) for j in self.lsmhe.xkNk_mhe)) self.lsmhe.Arrival_dummy_e_mhe = Expression( expr=100000.0 * sum((self.xkN_l[j] - self.lsmhe.x_0_mhe[j]) ** 2 for j in self.lsmhe.xkNk_mhe)) self.lsmhe.obfun_dum_mhe_deb = Objective(sense=minimize, expr=self.lsmhe.Q_e_mhe) self.lsmhe.obfun_dum_mhe = Objective(sense=minimize, expr=self.lsmhe.R_e_mhe + self.lsmhe.Q_e_mhe + self.lsmhe.U_e_mhe) # no arrival self.lsmhe.obfun_dum_mhe.deactivate() self.lsmhe.obfun_mhe_first = Objective(sense=minimize, expr=self.lsmhe.Arrival_dummy_e_mhe + self.lsmhe.Q_e_mhe) self.lsmhe.obfun_mhe_first.deactivate() self.lsmhe.obfun_mhe = Objective(sense=minimize, expr=self.lsmhe.Arrival_dummy_e_mhe + self.lsmhe.R_e_mhe + self.lsmhe.Q_e_mhe + self.lsmhe.U_e_mhe) self.lsmhe.obfun_mhe.deactivate() # with open("file_cv.txt", "a") as f: # self.lsmhe.obfun_mhe.pprint(ostream=f) # f.close() self._PI = {} #: Container of the KKT matrix self.xreal_W = {} self.curr_m_noise = {} #: Current measurement noise self.curr_y_offset = {} #: Current offset of measurement for y in self.y: for j in self.y_vars[y]: self.curr_m_noise[(y, j)] = 0.0 self.curr_y_offset[(y, j)] = 0.0 self.s_estimate = {} self.s_real = {} for x in self.x_noisy: self.s_estimate[x] = [] self.s_real[x] = [] self.y_estimate = {} self.y_real = {} self.y_noise_jrnl = {} self.yk0_jrnl = {} for y in self.y: self.y_estimate[y] = [] self.y_real[y] = [] self.y_noise_jrnl[y] = [] self.yk0_jrnl[y] = []
def create_nmpc(self, **kwargs): kwargs.pop("newnfe", self.nfe_tnmpc) kwargs.pop("newncp", self.ncp_tnmpc) self.journalist('W', self._iteration_count, "Initializing NMPC", "With {:d} fe and {:d} cp".format(self.nfe_tnmpc, self.ncp_tnmpc)) _tnmpc = self.hi_t * self.nfe_tnmpc self.olnmpc = self.d_mod(self.nfe_tnmpc, self.ncp_tnmpc, _t=_tnmpc) self.olnmpc.name = "olnmpc (Open-Loop NMPC)" self.olnmpc.create_bounds() for u in self.u: cv = getattr(self.olnmpc, u) #: Get the param c_val = [value(cv[i]) for i in cv.keys()] #: Current value self.olnmpc.del_component(cv) #: Delete the param self.olnmpc.add_component(u, Var(self.olnmpc.fe_t, initialize=lambda m, i: c_val[i-1])) self.olnmpc.equalize_u(direction="r_to_u") cc = getattr(self.olnmpc, u + "_c") #: Get the constraint ce = getattr(self.olnmpc, u + "_e") #: Get the expression cv = getattr(self.olnmpc, u) #: Get the new variable for k in cv.keys(): cv[k].setlb(self.u_bounds[u][0]) cv[k].setub(self.u_bounds[u][1]) cc.clear() cc.rule = lambda m, i: cv[i] == ce[i] cc.reconstruct() #: Dictionary of the states for a particular time point i self.xmpc_l = {} #: Dictionary of the position for a state in the dictionary self.xmpc_key = {} #: self.xmpc_l[0] = [] #: First build the name dictionary k = 0 for x in self.states: n_s = getattr(self.olnmpc, x) #: State for j in self.state_vars[x]: self.xmpc_l[0].append(n_s[(0, self.ncp_tnmpc) + j]) self.xmpc_key[(x, j)] = k k += 1 #: Iterate over the rest for t in range(1, self.nfe_tnmpc): self.xmpc_l[t] = [] for x in self.states: n_s = getattr(self.olnmpc, x) #: State for j in self.state_vars[x]: self.xmpc_l[t].append(n_s[(t, self.ncp_tnmpc) + j]) #: A set with the length of flattened states self.olnmpc.xmpcS_nmpc = Set(initialize=[i for i in range(0, len(self.xmpc_l[0]))]) #: Create set of noisy_states self.olnmpc.xmpc_ref_nmpc = Param(self.olnmpc.xmpcS_nmpc, initialize=0.0, mutable=True) #: Ref-state self.olnmpc.Q_nmpc = Param(self.olnmpc.xmpcS_nmpc, initialize=1, mutable=True) #: Control-weight # (diagonal Matrices) self.olnmpc.Q_w_nmpc = Param(self.olnmpc.fe_t, initialize=1e-04, mutable=True) self.olnmpc.R_w_nmpc = Param(self.olnmpc.fe_t, initialize=1e+02, mutable=True) #: Build the xT*Q*x part self.olnmpc.xQ_expr_nmpc = Expression(expr=sum( sum(self.olnmpc.Q_w_nmpc[fe] * self.olnmpc.Q_nmpc[k] * (self.xmpc_l[fe][k] - self.olnmpc.xmpc_ref_nmpc[k])**2 for k in self.olnmpc.xmpcS_nmpc) for fe in range(0, self.nfe_tnmpc))) #: Build the control list self.umpc_l = {} for t in range(0, self.nfe_tnmpc): self.umpc_l[t] = [] for u in self.u: uvar = getattr(self.olnmpc, u) self.umpc_l[t].append(uvar[t]) #: Create set of u self.olnmpc.umpcS_nmpc = Set(initialize=[i for i in range(0, len(self.umpc_l[0]))]) #: ref u self.olnmpc.umpc_ref_nmpc = Param(self.olnmpc.umpcS_nmpc, initialize=0.0, mutable=True) self.olnmpc.R_nmpc = Param(self.olnmpc.umpcS_nmpc, initialize=1, mutable=True) #: Control-weight #: Build the uT * R * u expression self.olnmpc.xR_expr_nmpc = Expression(expr=sum( sum(self.olnmpc.R_w_nmpc[fe] * self.olnmpc.R_nmpc[k] * (self.umpc_l[fe][k] - self.olnmpc.umpc_ref_nmpc[k]) ** 2 for k in self.olnmpc.umpcS_nmpc) for fe in range(0, self.nfe_tnmpc))) self.olnmpc.objfun_nmpc = Objective(expr=self.olnmpc.xQ_expr_nmpc + self.olnmpc.xR_expr_nmpc)
def set_testl(market_instances_list, airport_list, market_data, segment_travel_time, time_zone_dict, iti_dict, fleet_data, passeger_type_dict, attr_value, marketpt_attr_sum, solver): """ 很多输入变量都是字典,就是为了在模型中生成子集的时候有筛选功能 即 if dict【m】 in dict :param airport_list: :param market_data: :param segment_travel_time: :param iti_dict:itinerary number key ,info value :{0: {'market': "M('SEA', 'LAX')", 'non_stop': ('SEA', 'LAX'), ('SEA', 'LAX'): 1, 'legs': [('SEA', 'LAX')]} :param fleet_data: :param passeger_type_dict: passenger_type as key , and it's proportions :param attr_value: :param marketpt_attr_sum: :param solver: :return: time_table, q_variable for each itinerary, """ market_iti = {} #market:itinerary list for m in market_instances_list: l = [ i for i, v in iti_dict.items() if v['market'] == 'M' + str(m.od_pair) ] market_iti.update({m: l}) model = ConcreteModel() market = list(market_data.keys()) #['M' + str(m.od_pair) for m in ] # market_segment={m:[(market_data[m][4],market_data[m][5])] for m in market_data.keys()} model.M = Set(initialize=market, doc='Player Market_obj') model.Mi = Set(list(market_iti.keys()), initialize=market_iti, doc='Player Market_obj') model.AP = Set(initialize=airport_list) model.Segment = Set(initialize=((i, j) for i in model.AP for j in model.AP if i != j)) # create time spot [1-72] and it's time a = np.linspace(1, int((1440 - 360) / 15), int((1440 - 360) / 15)) time_list = np.arange(360, 1440, 15) time_dict = dict(zip(a, time_list)) # reverse_time_dict = {v: k for k, v in time_dict.items()} model.T = Set( initialize=a, ordered=True, doc='Time period from 300 min to 1440 ,step :15min,number:73') model.I = Set(initialize=iti_dict.keys(), doc='itinerary _index,size 4334') model.Im = Set(initialize=((m, i) for m in model.M for i in market_iti[m]), doc='tuple(m,i),size 4334') # 筛选出只在m的itinerary 的 号码 model.PT = Set(initialize=passeger_type_dict.keys()) model.F = Set(initialize=fleet_data.keys()) d = {} #create a dict as which OD and time get all itinerary_index in it for ap1, ap2 in model.Segment: for t in model.T: v = [] for i, va in iti_dict.items(): if (ap1, ap2) in va['legs'] and t == va[(ap1, ap2)]: v.append(i) d[(ap1, ap2, t)] = v model.St = Set( list(d.keys()), initialize=d) # index as (ap1,ap2,time) get [itinerary index list] def _filter3(model, i, m, ap1, ap2, t): return i in model.Mi[m].value and i in model.St[(ap1, ap2, t)].value # def Parameters demand_pt = { } # get demand of pt in the market by total demand times its proportion print("passenger_type_proportion:", passeger_type_dict) for m, va in market_data.items(): for ty, rato in passeger_type_dict.items(): demand_pt.update({(m, ty): va[0] * rato}) # market demand times proportions model.Dem = Param(model.M, model.PT, initialize=demand_pt, doc='Market demand for each type of passenger') price_dict = {} for i in model.I: rato = np.linspace(1.3, 0.7, len(passeger_type_dict)) for index, ty in enumerate(passeger_type_dict): if iti_dict[i]['non_stop']: price_dict.update({ (i, ty): market_data[iti_dict[i]['market']][2] * rato[index] }) # market_data[m][2] is price else: price_dict.update({ (i, ty): 0.8 * market_data[iti_dict[i]['market']][2] * rato[index] }) # market_data[m][2] is price model.p = Param(model.I, model.PT, initialize=price_dict) model.Avail = Param( model.F, initialize={fleet: value[0] for fleet, value in fleet_data.items()}) model.Cap = Param( model.F, initialize={fleet: value[1] for fleet, value in fleet_data.items()}) model.distance = Param(model.Segment, initialize={(value[-2], value[-1]): value[1] for value in market_data.values()}) def ope_cost(model, ap1, ap2, f): if model.distance[ap1, ap2] <= 3106: return (1.6 * model.distance[ap1, ap2] + 722) * (model.Cap[f] + 104) * 0.019 else: return (1.6 * model.distance[ap1, ap2] + 2200) * (model.Cap[f] + 211) * 0.0115 model.Ope = Param(model.Segment, model.F, initialize=ope_cost, doc='cost') freq = {(market_data[m][4], market_data[m][5]): market_data[m][3] for m in market_data.keys()} model.Freq = Param(model.Segment, initialize=freq) model.A = Param(model.I, model.PT, initialize=attr_value) model.Am = Param(model.M, model.PT, initialize=marketpt_attr_sum) # Step 2: Define decision variables model.x = Var(model.Segment, model.F, model.T, within=Binary) model.y_1 = Var(model.F, model.AP, model.T, within=PositiveIntegers) model.y_2 = Var(model.F, model.AP, model.T, within=PositiveIntegers) model.q = Var(model.I, model.PT, within=NonNegativeReals) model.non_q = Var(model.M, model.PT, within=NonNegativeReals ) # number of pax that choose others airine and no fly. # Step 3: Define Objective def obj_rule(model): return sum(model.q[i, pt] * model.p[i, pt] for i in model.I for pt in model.PT) - sum(model.Ope[s, f] * model.x[s, f, t] for s in model.Segment for f in model.F for t in model.T) model.obj = Objective(rule=obj_rule, sense=maximize) def obj_cost(model): return sum(model.Ope[s, f] * model.x[s, f, t] for s in model.Segment for f in model.F for t in model.T) model.obj_cost = Expression(rule=obj_cost) def obj_revenue(model): return sum(model.q[i, pt] * model.p[i, pt] for i in model.I for pt in model.PT) model.obj_revenue = Expression(rule=obj_revenue) # add constraint # Aircraft count: def aircraft_con(model, f): return sum(model.y_1[f, ap, model.T[1]] for ap in model.AP) <= model.Avail[f] model.count = Constraint(model.F, rule=aircraft_con) # flow balance cons def flow_balance_1(model, f, ap): return model.y_1[f, ap, model.T[1]] == model.y_2[f, ap, model.T[-1]] model.con_fb_1 = Constraint(model.F, model.AP, rule=flow_balance_1) def flow_balance_2(model, f, ap, t): # if t == model.T[-1]: # return Constraint.Skip # else: return model.y_1[f, ap, t + 1] == model.y_2[f, ap, t] def filter2(model, t): return t != model.T[-1] model.Tm = Set(initialize=(i for i in model.T if i != model.T[-1])) #model.con_fb_2 = Constraint(model.F, model.AP, model.T, rule=flow_balance_2) model.con_fb_2 = Constraint(model.F, model.AP, model.Tm, rule=flow_balance_2) # time_zone_dict={('ANC', 'PDX'): 60, ('SEA', 'PDX'): 0, ('SEA', 'ANC'): -60, ('ANC', 'LAX'): 60, ('PDX', 'SEA'): 0, ('LAX', 'PDX'): 0, # ('LAX', 'SEA'): 0, ('PDX', 'ANC'): -60, ('SEA', 'LAX'): 0, ('ANC', 'SEA'): 60, ('LAX', 'ANC'): -60, ('PDX', 'LAX'): 0} Travel_time = segment_travel_time def flow_balance_3(model, f, ap, t): def D(s, t, turnaround=30): arrival_time = time_dict[t] dep_time = arrival_time - (Travel_time[s] + turnaround) - time_zone_dict[s] if dep_time >= 360: t0 = ((dep_time - 360) // 15) + 1 else: t0 = 72 - (abs(360 - dep_time) // 15) return t0 return model.y_1[f, ap, t] + sum( model.x[s, f, D(s, t)] for s in model.Segment if s[1] == ap) == model.y_2[f, ap, t] + sum( model.x[s, f, t] for s in model.Segment if s[0] == ap) model.con_fb_3 = Constraint(model.F, model.AP, model.T, rule=flow_balance_3) # Demand and capacity constrains: def attract_con(model, market, i, pt): return model.Am[market, pt] * ( model.q[i, pt] / model.Dem[market, pt]) <= model.A[i, pt] * ( model.non_q[market, pt] / model.Dem[market, pt]) model.attractiveness = Constraint(model.Im, model.PT, rule=attract_con) def capacity_con(model, ap1, ap2, t): return sum(model.q[i, pt] for i in d[(ap1, ap2, t)] for pt in model.PT) <= sum( model.Cap[f] * model.x[ap1, ap2, f, t] for f in model.F) model.con_d1 = Constraint(model.Segment, model.T, rule=capacity_con) def demand_market_con(model, market, pt): return sum(model.q[i, pt] for i in model.I if iti_dict[i]['market'] == market) + model.non_q[market, pt] == \ model.Dem[market, pt] model.con_d3 = Constraint(model.M, model.PT, rule=demand_market_con) # Itinerary selection constraints: model.AC = Set(initialize=model.I * model.M * model.Segment * model.T, filter=_filter3) def iti_selection(model, i, m, ap1, ap2, t, pt): # if i in market_iti[m] and i in d[(ap1, ap2, t)]: return sum(model.x[ap1, ap2, f, t] for f in model.F) >= model.q[i, pt] / model.Dem[m, pt] model.con_iti_selection = Constraint(model.AC, model.PT, rule=iti_selection) # Restrictions on fight leg variables: def flight_leg_con(model, ap1, ap2, t): return sum(model.x[ap1, ap2, f, t] for f in model.F) <= 1 model.con_leg_1 = Constraint(model.Segment, model.T, rule=flight_leg_con) def freq_con(model, ap1, ap2): return sum(model.x[ap1, ap2, f, t] for t in model.T for f in model.F) == model.Freq[ap1, ap2] model.con_let_2 = Constraint(model.Segment, rule=freq_con) print("____" * 5) # for con in model.component_map(Constraint).itervalues(): # con.pprint() SOLVER_NAME = solver TIME_LIMIT = 60 * 60 * 2 results = SolverFactory(SOLVER_NAME) if SOLVER_NAME == 'cplex': results.options['timelimit'] = TIME_LIMIT elif SOLVER_NAME == 'glpk': results.options['tmlim'] = TIME_LIMIT elif SOLVER_NAME == 'gurobi': results.options['TimeLimit'] = TIME_LIMIT com = results.solve(model, tee=True) com.write() #absgap = com.solution(0).gap # get x results in matrix form df_x = pd.DataFrame(columns=list(model.Segment), index=model.T) for s in model.Segment: for t in model.T: for f in model.F: if model.x[s, f, t].value > 0: df_x.loc[t, [s]] = f #df_x=df_x.reset_index()# return value is a dataframe of new time table # 所有的决策变量都遍历一遍 # for v in instance.component_objects(Var, active=True): # print("Variable", v) # varobject = getattr(instance, str(v)) # for index in varobject: # print(" ", index, varobject[index].value) varobject = getattr(model, 'q') q_data = {(i, pt): varobject[(i, pt)].value for (i, pt), v in varobject.items() if varobject[(i, pt)] != 0} df_q = pd.DataFrame.from_dict(q_data, orient="index", columns=["variable value"]) varobject2 = getattr(model, 'non_q') nonq_data = {(m, pt): varobject2[(m, pt)].value for (m, pt), v in varobject2.items() if varobject2[(m, pt)] != 0} # q = list(model.q.get_values().values()) # print('q = ', q) profit = model.obj() print('\nProfit = ', profit) cost = value_s(model.obj_cost()) #revenue=value_s(model.obj_revenue()) print('cost is:' * 10, cost) #print('revenue is:' * 10, revenue) ''' print('\nDecision Variables') #list_of_vars = [v.value for v in model.component_objects(ctype=Var, active=True, descend_into=True)] #var_names = [v.name for v in model.component_objects(ctype=Var, active=True, descend_into=True) if v.value!=0] # print("y=",y) model.obj.display() def pyomo_postprocess( options=None, instance=None, results=None ): model.x.display() pyomo_postprocess(None, model, results) for v in model.component_objects(Var, active=True): print("Variable component object", v) varobject = getattr(model, str(v)) for index in varobject: if varobject[index].value != 0: print(" ", index, varobject[index].value) ''' return df_x, q_data, profit, cost, nonq_data
def ROSolver_iterative_solve(model_data, config): ''' GRCS algorithm implementation :model_data: ROSolveData object with deterministic model information :config: ConfigBlock for the instance being solved ''' # === The "violation" e.g. uncertain parameter values added to the master problem are nominal in iteration 0 # User can supply a nominal_uncertain_param_vals if they want to set nominal to a certain point, # Otherwise, the default init value for the params is used as nominal_uncertain_param_vals violation = list(p for p in config.nominal_uncertain_param_vals) # === Do coefficient matching constraints = [ c for c in model_data.working_model.component_data_objects(Constraint) if c.equality and c not in ComponentSet( model_data.working_model.util.decision_rule_eqns) ] model_data.working_model.util.h_x_q_constraints = ComponentSet() for c in constraints: coeff_matching_success, robust_infeasible = coefficient_matching( model=model_data.working_model, constraint=c, uncertain_params=model_data.working_model.util.uncertain_params, config=config) if not coeff_matching_success and not robust_infeasible: raise ValueError( "Equality constraint \"%s\" cannot be guaranteed to be robustly feasible, " "given the current partitioning between first-stage, second-stage and state variables. " "You might consider editing this constraint to reference some second-stage " "and/or state variable(s)." % c.name) elif not coeff_matching_success and robust_infeasible: config.progress_logger.info( "PyROS has determined that the model is robust infeasible. " "One reason for this is that equality constraint \"%s\" cannot be satisfied " "against all realizations of uncertainty, " "given the current partitioning between first-stage, second-stage and state variables. " "You might consider editing this constraint to reference some (additional) second-stage " "and/or state variable(s)." % c.name) return None, None else: pass # h(x,q) == 0 becomes h'(x) == 0 for c in model_data.working_model.util.h_x_q_constraints: c.deactivate() # === Build the master problem and master problem data container object master_data = master_problem_methods.initial_construct_master(model_data) # === If using p_robustness, add ConstraintList for additional constraints if config.p_robustness: master_data.master_model.p_robust_constraints = ConstraintList() # === Add scenario_0 master_data.master_model.scenarios[0, 0].transfer_attributes_from( master_data.original.clone()) if len(master_data.master_model.scenarios[ 0, 0].util.uncertain_params) != len(violation): raise ValueError # === Set the nominal uncertain parameters to the violation values for i, v in enumerate(violation): master_data.master_model.scenarios[ 0, 0].util.uncertain_params[i].value = v # === Add objective function (assuming minimization of costs) with nominal second-stage costs if config.objective_focus is ObjectiveType.nominal: master_data.master_model.obj = Objective( expr=master_data.master_model.scenarios[0, 0].first_stage_objective + master_data.master_model.scenarios[0, 0].second_stage_objective) elif config.objective_focus is ObjectiveType.worst_case: # === Worst-case cost objective master_data.master_model.zeta = Var(initialize=value( master_data.master_model.scenarios[0, 0].first_stage_objective + master_data.master_model.scenarios[0, 0].second_stage_objective)) master_data.master_model.obj = Objective( expr=master_data.master_model.zeta) master_data.master_model.scenarios[0, 0].epigraph_constr = Constraint( expr=master_data.master_model.scenarios[0, 0].first_stage_objective + master_data.master_model.scenarios[0, 0].second_stage_objective <= master_data.master_model.zeta) master_data.master_model.scenarios[ 0, 0].util.first_stage_variables.append(master_data.master_model.zeta) # === Add deterministic constraints to ComponentSet on original so that these become part of separation model master_data.original.util.deterministic_constraints = \ ComponentSet(c for c in master_data.original.component_data_objects(Constraint, descend_into=True)) # === Make separation problem model once before entering the solve loop separation_model = separation_problem_methods.make_separation_problem( model_data=master_data, config=config) # === Create separation problem data container object and add information to catalog during solve separation_data = SeparationProblemData() separation_data.separation_model = separation_model separation_data.points_separated = [ ] # contains last point separated in the separation problem separation_data.points_added_to_master = [ config.nominal_uncertain_param_vals ] # explicitly robust against in master separation_data.constraint_violations = [ ] # list of constraint violations for each iteration separation_data.total_global_separation_solves = 0 # number of times global solve is used separation_data.timing = master_data.timing # timing object # === Keep track of subsolver termination statuses from each iteration separation_data.separation_problem_subsolver_statuses = [] # === Nominal information nominal_data = Block() nominal_data.nom_fsv_vals = [] nominal_data.nom_ssv_vals = [] nominal_data.nom_first_stage_cost = 0 nominal_data.nom_second_stage_cost = 0 nominal_data.nom_obj = 0 # === Time information timing_data = Block() timing_data.total_master_solve_time = 0 timing_data.total_separation_local_time = 0 timing_data.total_separation_global_time = 0 timing_data.total_dr_polish_time = 0 dr_var_lists_original = [] dr_var_lists_polished = [] k = 0 while config.max_iter == -1 or k < config.max_iter: master_data.iteration = k # === Add p-robust constraint if iteration > 0 if k > 0 and config.p_robustness: master_problem_methods.add_p_robust_constraint( model_data=master_data, config=config) # === Solve Master Problem config.progress_logger.info("PyROS working on iteration %s..." % k) master_soln = master_problem_methods.solve_master( model_data=master_data, config=config) #config.progress_logger.info("Done solving Master Problem!") master_soln.master_problem_subsolver_statuses = [] # === Keep track of total time and subsolver termination conditions timing_data.total_master_solve_time += get_time_from_solver( master_soln.results) timing_data.total_master_solve_time += get_time_from_solver( master_soln.feasibility_problem_results) master_soln.master_problem_subsolver_statuses.append( master_soln.results.solver.termination_condition) # === Check for robust infeasibility or error or time-out in master problem solve if master_soln.master_subsolver_results[ 1] is pyrosTerminationCondition.robust_infeasible: term_cond = pyrosTerminationCondition.robust_infeasible output_logger(config=config, robust_infeasible=True) elif master_soln.pyros_termination_condition is pyrosTerminationCondition.subsolver_error: term_cond = pyrosTerminationCondition.subsolver_error else: term_cond = None if term_cond == pyrosTerminationCondition.subsolver_error or \ term_cond == pyrosTerminationCondition.robust_infeasible: update_grcs_solve_data(pyros_soln=model_data, k=k, term_cond=term_cond, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) return model_data, [] # === Check if time limit reached elapsed = get_main_elapsed_time(model_data.timing) if config.time_limit: if elapsed >= config.time_limit: output_logger(config=config, time_out=True, elapsed=elapsed) update_grcs_solve_data( pyros_soln=model_data, k=k, term_cond=pyrosTerminationCondition.time_out, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) return model_data, [] # === Save nominal information if k == 0: for val in master_soln.fsv_vals: nominal_data.nom_fsv_vals.append(val) for val in master_soln.ssv_vals: nominal_data.nom_ssv_vals.append(val) nominal_data.nom_first_stage_cost = master_soln.first_stage_objective nominal_data.nom_second_stage_cost = master_soln.second_stage_objective nominal_data.nom_obj = value(master_data.master_model.obj) if ( # === Decision rule polishing (do not polish on first iteration if no ssv or if decision_rule_order = 0) (config.decision_rule_order != 0 and len(config.second_stage_variables) > 0 and k != 0)): # === Save initial values of DR vars to file for varslist in master_data.master_model.scenarios[ 0, 0].util.decision_rule_vars: vals = [] for dvar in varslist.values(): vals.append(dvar.value) dr_var_lists_original.append(vals) polishing_results = master_problem_methods.minimize_dr_vars( model_data=master_data, config=config) timing_data.total_dr_polish_time += get_time_from_solver( polishing_results) #=== Save after polish for varslist in master_data.master_model.scenarios[ 0, 0].util.decision_rule_vars: vals = [] for dvar in varslist.values(): vals.append(dvar.value) dr_var_lists_polished.append(vals) # === Set up for the separation problem separation_data.opt_fsv_vals = [ v.value for v in master_soln.master_model.scenarios[ 0, 0].util.first_stage_variables ] separation_data.opt_ssv_vals = master_soln.ssv_vals # === Provide master model scenarios to separation problem for initialization options separation_data.master_scenarios = master_data.master_model.scenarios if config.objective_focus is ObjectiveType.worst_case: separation_model.util.zeta = value(master_soln.master_model.obj) # === Solve Separation Problem separation_data.iteration = k separation_data.master_nominal_scenario = master_data.master_model.scenarios[ 0, 0] separation_data.master_model = master_data.master_model separation_solns, violating_realizations, constr_violations, is_global, \ local_sep_time, global_sep_time = \ separation_problem_methods.solve_separation_problem(model_data=separation_data, config=config) for sep_soln_list in separation_solns: for s in sep_soln_list: separation_data.separation_problem_subsolver_statuses.append( s.termination_condition) if is_global: separation_data.total_global_separation_solves += 1 timing_data.total_separation_local_time += local_sep_time timing_data.total_separation_global_time += global_sep_time separation_data.constraint_violations.append(constr_violations) if not any(s.found_violation for solve_data_list in separation_solns for s in solve_data_list): separation_data.points_separated = [] else: separation_data.points_separated = violating_realizations # === Check if time limit reached elapsed = get_main_elapsed_time(model_data.timing) if config.time_limit: if elapsed >= config.time_limit: output_logger(config=config, time_out=True, elapsed=elapsed) termination_condition = pyrosTerminationCondition.time_out update_grcs_solve_data(pyros_soln=model_data, k=k, term_cond=termination_condition, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) return model_data, separation_solns # === Check if we exit due to solver returning unsatisfactory statuses (not in permitted_termination_conditions) local_solve_term_conditions = { TerminationCondition.optimal, TerminationCondition.locallyOptimal, TerminationCondition.globallyOptimal } global_solve_term_conditions = { TerminationCondition.optimal, TerminationCondition.globallyOptimal } if (is_global and any((s.termination_condition not in global_solve_term_conditions) for sep_soln_list in separation_solns for s in sep_soln_list)) or \ (not is_global and any((s.termination_condition not in local_solve_term_conditions) for sep_soln_list in separation_solns for s in sep_soln_list)): termination_condition = pyrosTerminationCondition.subsolver_error update_grcs_solve_data(pyros_soln=model_data, k=k, term_cond=termination_condition, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) return model_data, separation_solns # === Check if we terminate due to robust optimality or feasibility if not any(s.found_violation for sep_soln_list in separation_solns for s in sep_soln_list) and is_global: if config.solve_master_globally and config.objective_focus is ObjectiveType.worst_case: output_logger(config=config, robust_optimal=True) termination_condition = pyrosTerminationCondition.robust_optimal else: output_logger(config=config, robust_feasible=True) termination_condition = pyrosTerminationCondition.robust_feasible update_grcs_solve_data(pyros_soln=model_data, k=k, term_cond=termination_condition, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) return model_data, separation_solns # === Add block to master at violation master_problem_methods.add_scenario_to_master(master_data, violating_realizations) separation_data.points_added_to_master.append(violating_realizations) k += 1 output_logger(config=config, max_iter=True) update_grcs_solve_data(pyros_soln=model_data, k=k, term_cond=pyrosTerminationCondition.max_iter, nominal_data=nominal_data, timing_data=timing_data, separation_data=separation_data, master_soln=master_soln) # === In this case we still return the final solution objects for the last iteration return model_data, separation_solns
def GradientsTool(self): self.journalizer("E", self._c_it, "GradientsTool", "Begin") src = self.d1 src.dum_objfun = Objective(expr=1, sense=minimize) self.d1.var_order = Suffix(direction=Suffix.EXPORT) self.d1.con_order = Suffix(direction=Suffix.EXPORT) src.pprint(filename="first.txt") #: Fix/Deactivate irrelevant stuff for var in src.component_objects(Var, active=True): if not var.is_indexed(): var.fix() for index in var.keys(): if type(index) != tuple: var.fix() continue try: if index[1] == self.ncp_t: continue var[index].fix() except IndexError: var.fix() print("Variable not indexed by time", var.name, file=sys.stderr) for con in src.component_objects(Constraint, active=True): if not con.is_indexed(): con.deactivate() for index in con.keys(): if type(index) != tuple: con.deactivate() continue try: if index[1] == self.ncp_t: continue con[index].deactivate() except IndexError: con.deactivate() print("Constraint not indexed by time", con.name, file=sys.stderr) for i in self.states: #: deactivate collocation related equations # con = getattr(src, "cp_" + i) #: continuation # con.deactivate() con = getattr(src, "dvar_t_" + i) #: derivative vars con.deactivate() con = getattr(src, i + "_icc") #: initial-conditions con.deactivate() var = getattr(src, "d" + i + "_dt") var.fix() var = getattr(src, i) var.fix() #: left with the av con = getattr(src, "de_" + i) #: initial-conditions con.deactivate() # colcount = 0 # for i in src.component_data_objects(Var, active=True): # if i.is_fixed(): # continue # print(i) # colcount += 1 # i.set_suffix_value(src.var_order, colcount) # print(colcount) self.d1.write_nl(name="dgy.nl") sfxdict = dict() self.parse_rc("dgy.row", sfxdict) colcount = 1 for ob in sfxdict.keys(): con = getattr(src, sfxdict[ob][0]) con[sfxdict[ob][1]].set_suffix_value(src.con_order, colcount) colcount += 1 sfxdict = dict() self.parse_rc("dgy.col", sfxdict) colcount = 1 for ob in sfxdict.keys(): var = getattr(src, sfxdict[ob][0]) var[sfxdict[ob][1]].set_suffix_value(src.var_order, colcount) colcount += 1 print("Colcount\t", str(colcount), file=sys.stderr) src.write_nl(name="dgy.nl") #: Now dgx for var in src.component_objects(Var): var.fix() #: Fix everything for i in self.states: var = getattr(src, i) for index in var.keys(): try: if index[1] == self.ncp_t: var[index].unfix() except IndexError: print("Something whent wrong :(\t", var.name, file=sys.stderr) self.d1.write_nl(name="dgx.nl") sfxdict = dict() self.parse_rc("dgx.col", sfxdict) colcount = 1 for ob in sfxdict.keys(): var = getattr(src, sfxdict[ob][0]) var[sfxdict[ob][1]].set_suffix_value(src.var_order, colcount) colcount += 1 src.write_nl(name="dgx.nl") #: Now dfy for var in src.component_objects(Var): var.unfix() for var in src.component_objects(Var): if not var.is_indexed(): var.fix() for index in var.keys(): if type(index) != tuple: var.fix() continue try: if index[1] == self.ncp_t: continue var[index].fix() except IndexError: var.fix() print("Variable not indexed by time", var.name, file=sys.stderr) for con in src.component_objects(Constraint): con.deactivate() #: deactivate everything for i in self.states: #: deactivate collocation related terms var = getattr(src, "d" + i + "_dt") var.fix() var = getattr(src, i) var.fix() #: left with the av con = getattr(src, "de_" + i) for index in con.keys(): if index[1] == self.ncp_t: con[index].activate() self.d1.reconstruct() # self.d1.write_nl(name="dfy.nl") sfxdict = dict() self.parse_rc("dgx.col", sfxdict) colcount = 1 for ob in sfxdict.keys(): col = getattr(src, "de_" + sfxdict[ob][0]) col[sfxdict[ob][1]].set_suffix_value(src.con_order, colcount) colcount += 1 src.write_nl(name="dfy.nl") #: Now dfx for var in src.component_objects(Var): var.fix() #: Fix everything for i in self.states: var = getattr(src, i) for index in var.keys(): try: if index[1] == self.ncp_t: var[index].unfix() except IndexError: print("Something whent wrong :(\t", var.name, file=sys.stderr) # var.pprint() self.d1.reconstruct() src.pprint(filename="second.txt") self.d1.write_nl(name="dfx.nl")