def compile(self, model, start_time): """ Compile the optimization model :param model: The entire optimization model :param block: The pipe model object :param start_time: The optimization start_time :return: """ Component.compile(self, model, start_time) if not self.compiled: if self.repr_days is None: self.block.heat_flow_in = Var(self.TIME) self.block.heat_flow_out = Var(self.TIME) self.block.mass_flow = Var(self.TIME) def _heat_flow(b, t): return b.heat_flow_in[t] == b.heat_flow_out[t] self.block.heat_flow = Constraint(self.TIME, rule=_heat_flow) else: self.block.heat_flow_in = Var(self.TIME, self.REPR_DAYS) self.block.heat_flow_out = Var(self.TIME, self.REPR_DAYS) self.block.mass_flow = Var(self.TIME, self.REPR_DAYS) def _heat_flow(b, t, c): return b.heat_flow_in[t] == b.heat_flow_out[t] self.block.heat_flow = Constraint(self.TIME, self.REPR_DAYS, rule=_heat_flow) self.compiled = True
def _apply_to(self, instance, **kwds): options = kwds.pop('options', {}) bound = kwds.pop('mpec_bound', 0.0) # # Create a mutable parameter that defines the value of the upper bound # on the constraints # bound = options.get('mpec_bound', bound) instance.mpec_bound = Param(mutable=True, initialize=bound) # # Setup transformation data # tdata = instance._transformation_data['mpec.simple_nonlinear'] tdata.compl_cuids = [] # # Iterate over the model finding Complementarity components # for complementarity in instance.component_objects( Complementarity, active=True, descend_into=(Block, Disjunct), sort=SortComponents.deterministic): block = complementarity.parent_block() for index in sorted(complementarity.keys()): _data = complementarity[index] if not _data.active: continue _data.to_standard_form() # _type = getattr(_data.c, "_complementarity_type", 0) if _type == 1: # # Constraint expression is bounded below, so we can replace # constraint c with a constraint that ensures that either # constraint c is active or variable v is at its lower bound. # _data.ccon = Constraint( expr=(_data.c.body - _data.c.lower) * _data.v <= instance.mpec_bound) del _data.c._complementarity_type elif _type == 3: # # Variable v is bounded above and below. We can define # _data.ccon_l = Constraint( expr=(_data.v - _data.v.bounds[0]) * _data.c.body <= instance.mpec_bound) _data.ccon_u = Constraint( expr=(_data.v - _data.v.bounds[1]) * _data.c.body <= instance.mpec_bound) del _data.c._complementarity_type elif _type == 2: #pragma:nocover raise ValueError( "to_standard_form does not generate _type 2 expressions" ) tdata.compl_cuids.append(ComponentUID(complementarity)) block.reclassify_component_type(complementarity, Block)
def two_kp_model(type): model = ConcreteModel() # Define input files xlsx = pd.ExcelFile( f"{Path(__file__).parent.absolute()}/input/{type}.xlsx", engine="openpyxl") a = pd.read_excel(xlsx, index_col=0, sheet_name="a").to_numpy() b = pd.read_excel(xlsx, index_col=0, sheet_name="b").to_numpy() c = pd.read_excel(xlsx, index_col=0, sheet_name="c").to_numpy() # Define variables model.ITEMS = Set(initialize=range(len(a[0]))) model.x = Var(model.ITEMS, within=Binary) # -------------------------------------- # Define the objective functions # -------------------------------------- def objective1(model): return sum(c[0][i] * model.x[i] for i in model.ITEMS) def objective2(model): return sum(c[1][i] * model.x[i] for i in model.ITEMS) # -------------------------------------- # Define the regular constraints # -------------------------------------- def constraint1(model): return sum(a[0][i] * model.x[i] for i in model.ITEMS) <= b[0][0] def constraint2(model): return sum(a[1][i] * model.x[i] for i in model.ITEMS) <= b[1][0] # -------------------------------------- # Add components to the model # -------------------------------------- # Add the constraints to the model model.con1 = Constraint(rule=constraint1) model.con2 = Constraint(rule=constraint2) # Add the objective functions to the model using ObjectiveList(). Note # that the first index is 1 instead of 0! model.obj_list = ObjectiveList() model.obj_list.add(expr=objective1(model), sense=maximize) model.obj_list.add(expr=objective2(model), sense=maximize) # By default deactivate all the objective functions for o in range(len(model.obj_list)): model.obj_list[o + 1].deactivate() return model
def add_decision_rule_constraints(model_data, config): ''' Function to add the defining Constraint relationships for the decision rules to the working model. :param model_data: model data container object :param config: the config object :return: ''' second_stage_variables = model_data.working_model.util.second_stage_variables uncertain_params = model_data.working_model.util.uncertain_params decision_rule_eqns = [] degree = config.decision_rule_order if degree == 0: for i in range(len(second_stage_variables)): model_data.working_model.add_component("decision_rule_eqn_" + str(i), Constraint(expr=getattr(model_data.working_model, "decision_rule_var_" + str(i)) == second_stage_variables[i])) decision_rule_eqns.append(getattr(model_data.working_model, "decision_rule_eqn_" + str(i))) elif degree == 1: for i in range(len(second_stage_variables)): expr = 0 for j in range(len(getattr(model_data.working_model, "decision_rule_var_" + str(i)))): if j == 0: expr += getattr(model_data.working_model, "decision_rule_var_" + str(i))[j] else: expr += getattr(model_data.working_model, "decision_rule_var_" + str(i))[j] * uncertain_params[j - 1] model_data.working_model.add_component("decision_rule_eqn_" + str(i), Constraint(expr= expr == second_stage_variables[i])) decision_rule_eqns.append(getattr(model_data.working_model, "decision_rule_eqn_" + str(i))) elif degree >= 2: # Using bars and stars groupings of variable powers, construct x1^a * .... * xn^b terms for all c <= a+...+b = degree all_powers = [] for n in range(1, degree+1): all_powers.append(sort_partitioned_powers(list(partition_powers(n, len(uncertain_params))))) for i in range(len(second_stage_variables)): Z = list(z for z in getattr(model_data.working_model, "decision_rule_var_" + str(i)).values()) e = Z.pop(0) for degree_param_powers in all_powers: for param_powers in degree_param_powers: product = 1 for idx, power in enumerate(param_powers): if power == 0: pass else: product = product * uncertain_params[idx]**power e += Z.pop(0) * product model_data.working_model.add_component("decision_rule_eqn_" + str(i), Constraint(expr=e == second_stage_variables[i])) decision_rule_eqns.append(getattr(model_data.working_model, "decision_rule_eqn_" + str(i))) if len(Z) != 0: raise RuntimeError("Construction of the decision rule functions did not work correctly! " "Did not use all coefficient terms.") model_data.working_model.util.decision_rule_eqns = decision_rule_eqns return
def two_objective_model(): model = ConcreteModel() # Define variables model.x1 = Var(within=NonNegativeReals) model.x2 = Var(within=NonNegativeReals) # -------------------------------------- # Define the objective functions # -------------------------------------- def objective1(model): return model.x1 def objective2(model): return 3 * model.x1 + 4 * model.x2 # -------------------------------------- # Define the regular constraints # -------------------------------------- def constraint1(model): return model.x1 <= 20 def constraint2(model): return model.x2 <= 40 def constraint3(model): return 5 * model.x1 + 4 * model.x2 <= 200 # -------------------------------------- # Add components to the model # -------------------------------------- # Add the constraints to the model model.con1 = Constraint(rule=constraint1) model.con2 = Constraint(rule=constraint2) model.con3 = Constraint(rule=constraint3) # Add the objective functions to the model using ObjectiveList(). Note # that the first index is 1 instead of 0! model.obj_list = ObjectiveList() model.obj_list.add(expr=objective1(model), sense=maximize) model.obj_list.add(expr=objective2(model), sense=maximize) # By default deactivate all the objective functions for o in range(len(model.obj_list)): model.obj_list[o + 1].deactivate() return model
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 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 turn_bounds_to_constraints(variable, model, config=None): ''' Turn the variable in question's "bounds" into direct inequality constraints on the model. :param variable: the variable with bounds to be turned to None and made into constraints. :param model: the model in which the variable resides :param config: solver config :return: the list of inequality constraints that are the bounds ''' if variable.lb is not None: name = variable.name + "_lower_bound_con" model.add_component(name, Constraint(expr=-variable <= -variable.lb)) variable.setlb(None) if variable.ub is not None: name = variable.name + "_upper_bound_con" model.add_component(name, Constraint(expr=variable <= variable.ub)) variable.setub(None) return
def _discretize_variable(self, b, v, idx): _lb, _ub = v.bounds if _lb is None or _ub is None: raise RuntimeError("Couldn't discretize variable %s: missing " "finite lower/upper bounds." % (v.name)) _c = Constraint(expr=v == _lb + (_ub - _lb) * (b.dv[idx] + sum(b.z[idx, k] * 2**-k for k in b.DISCRETIZATION))) b.add_component("c_discr_v%s" % idx, _c)
def b1(b): b.v = Var(m.time, m.space, initialize=1) b.dv = DerivativeVar(b.v, wrt=m.time, initialize=0) b.con = Constraint(m.time, m.space, rule=lambda b, t, x: b.dv[t, x] == 7 - b.v[t, x]) # Inconsistent @b.Block(m.time) def b2(b, t): b.v = Var(initialize=2)
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 transform_to_standard_form(model): """ Recast all model inequality constraints of the form `a <= g(v)` (`<= b`) to the 'standard' form `a - g(v) <= 0` (and `g(v) - b <= 0`), in which `v` denotes all model variables and `a` and `b` are contingent on model parameters. Parameters ---------- model : ConcreteModel The model to search for constraints. This will descend into all active Blocks and sub-Blocks as well. Note ---- If `a` and `b` are identical and the constraint is not classified as an equality (i.e. the `equality` attribute of the constraint object is `False`), then the constraint is recast to the equality `g(v) == a`. """ # Note: because we will be adding / modifying the number of # constraints, we want to resolve the generator to a list before # starting. cons = list(model.component_data_objects( Constraint, descend_into=True, active=True)) for con in cons: if not con.equality: has_lb = con.lower is not None has_ub = con.upper is not None if has_lb and has_ub: if con.lower is con.upper: # recast as equality Constraint con.set_value(con.lower == con.body) else: # range inequality; split into two Constraints. uniq_name = unique_component_name(model, con.name + '_lb') model.add_component( uniq_name, Constraint(expr=con.lower - con.body <= 0) ) con.set_value(con.body - con.upper <= 0) elif has_lb: # not in standard form; recast. con.set_value(con.lower - con.body <= 0) elif has_ub: # move upper bound to body. con.set_value(con.body - con.upper <= 0) else: # unbounded constraint: deactivate con.deactivate()
def transform_to_standard_form(model): ''' Make all inequality constraints of the form g(x) <= 0 :param model: the optimization model :return: void ''' for constraint in model.component_data_objects(Constraint, descend_into=True, active=True): if not constraint.equality: if constraint.lower is not None: temp = constraint model.del_component(constraint) model.add_component(temp.name, Constraint(expr= - (temp.body) + (temp.lower) <= 0 )) return
def _discretize_bilinear(self, b, v, v_idx, u, u_idx): _z = b.z _dv = b.dv[v_idx] _u = Var(b.DISCRETIZATION, within=u.domain, bounds=u.bounds) logger.info("Discretizing (v=%s)*(u=%s) as u%s_v%s" % (v.name, u.name, u_idx, v_idx)) b.add_component("u%s_v%s" % (u_idx, v_idx), _u) _lb, _ub = u.bounds if _lb is None or _ub is None: raise RuntimeError("Couldn't relax variable %s: missing " "finite lower/upper bounds." % (u.name)) _c = ConstraintList() b.add_component("c_disaggregate_u%s_v%s" % (u_idx, v_idx), _c) for k in b.DISCRETIZATION: # _lb * z[v_idx,k] <= _u[k] <= _ub * z[v_idx,k] _c.add(expr=_lb * _z[v_idx, k] <= _u[k]) _c.add(expr=_u[k] <= _ub * _z[v_idx, k]) # _lb * (1-z[v_idx,k]) <= u - _u[k] <= _ub * (1-z[v_idx,k]) _c.add(expr=_lb * (1 - _z[v_idx, k]) <= u - _u[k]) _c.add(expr=u - _u[k] <= _ub * (1 - _z[v_idx, k])) _v_lb, _v_ub = v.bounds _bnd_rng = (_v_lb * _lb, _v_lb * _ub, _v_ub * _lb, _v_ub * _ub) _w = Var(bounds=(min(_bnd_rng), max(_bnd_rng))) b.add_component("w%s_v%s" % (u_idx, v_idx), _w) K = max(b.DISCRETIZATION) _dw = Var(bounds=(min(0, _lb * 2**-K, _ub * 2**-K), max(0, _lb * 2**-K, _ub * 2**-K))) b.add_component("dw%s_v%s" % (u_idx, v_idx), _dw) _c = Constraint(expr=_w == _v_lb * u + (_v_ub - _v_lb) * (sum(2**-k * _u[k] for k in b.DISCRETIZATION) + _dw)) b.add_component("c_bilinear_u%s_v%s" % (u_idx, v_idx), _c) _c = ConstraintList() b.add_component("c_mccormick_u%s_v%s" % (u_idx, v_idx), _c) # u_lb * dv <= dw <= u_ub * dv _c.add(expr=_lb * _dv <= _dw) _c.add(expr=_dw <= _ub * _dv) # (u-u_ub)*2^-K + u_ub*dv <= dw <= (u-u_lb)*2^-K + u_lb*dv _c.add(expr=(u - _ub) * 2**-K + _ub * _dv <= _dw) _c.add(expr=_dw <= (u - _lb) * 2**-K + _lb * _dv) return _w
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 _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 _apply_to(self, instance, **kwds): # # Setup transformation data # tdata = instance._transformation_data['mpec.simple_disjunction'] tdata.compl_cuids = [] # # Iterate over the model finding Complementarity components # for complementarity in instance.component_objects(Complementarity, active=True, descend_into=(Block, Disjunct), sort=SortComponents.deterministic): block = complementarity.parent_block() for index in sorted(complementarity.keys()): _data = complementarity[index] if not _data.active: continue # _e1 = _data._canonical_expression(_data._args[0]) _e2 = _data._canonical_expression(_data._args[1]) if len(_e1)==3 and len(_e2) == 3 and (_e1[0] is None) + (_e1[2] is None) + (_e2[0] is None) + (_e2[2] is None) != 2: raise RuntimeError("Complementarity condition %s must have exactly two finite bounds" % _data.name) if len(_e1) == 3 and _e1[0] is None and _e1[2] is None: # # Swap _e1 and _e2. The ensures that # only e2 will be an unconstrained expression # _e1, _e2 = _e2, _e1 if _e2[0] is None and _e2[2] is None: if len(_e1) == 2: _data.c = Constraint(expr=_e1) else: _data.expr1 = Disjunct() _data.expr1.c0 = Constraint(expr= _e1[0] == _e1[1]) _data.expr1.c1 = Constraint(expr= _e2[1] >= 0) # _data.expr2 = Disjunct() _data.expr2.c0 = Constraint(expr= _e1[1] == _e1[2]) _data.expr2.c1 = Constraint(expr= _e2[1] <= 0) # _data.expr3 = Disjunct() _data.expr3.c0 = Constraint(expr= inequality(_e1[0], _e1[1], _e1[2])) _data.expr3.c1 = Constraint(expr= _e2[1] == 0) _data.complements = Disjunction(expr=(_data.expr1, _data.expr2, _data.expr3)) else: if _e1[0] is None: tmp1 = _e1[2] - _e1[1] else: tmp1 = _e1[1] - _e1[0] if _e2[0] is None: tmp2 = _e2[2] - _e2[1] else: tmp2 = _e2[1] - _e2[0] _data.expr1 = Disjunct() _data.expr1.c0 = Constraint(expr= tmp1 >= 0) _data.expr1.c1 = Constraint(expr= tmp2 == 0) # _data.expr2 = Disjunct() _data.expr2.c0 = Constraint(expr= tmp1 == 0) _data.expr2.c1 = Constraint(expr= tmp2 >= 0) # _data.complements = Disjunction(expr=(_data.expr1, _data.expr2)) tdata.compl_cuids.append( ComponentUID(complementarity) ) block.reclassify_component_type(complementarity, Block)
mod.Mv1 = Var(mod.t, initialize=8.57) mod.Mvn = Var(mod.t, initialize=0.203) # -------------------------------------------------------------------------------------------------------------- #: Controls mod.u1 = Param(mod.t, default=7.72700925775773761472464684629813E-01, mutable=True) #: Dummy mod.u2 = Param(mod.t, default=1.78604740940007800236344337463379E+06, mutable=True) #: Dummy mod.Rec = Var(mod.t, initialize=7.72700925775773761472464684629813E-01) mod.Qr = Var(mod.t, initialize=1.78604740940007800236344337463379E+06) # -------------------------------------------------------------------------------------------------------------- #: Constraints for the differential states #: Then the ode-Con:de_x, collocation-Con:dvar_t_x, noisy-Expr: noisy_x, cp-Constraint: cp_x, initial-Con: x_icc #: Differential equations mod.de_M = Constraint(mod.t, mod.tray, rule=m_ode) mod.de_x = Constraint(mod.t, mod.tray, rule=x_ode) #: Continuation equations (redundancy here) #: Initial condition-Constraints mod.M_icc = Constraint(mod.tray, rule=acm) mod.x_icc = Constraint(mod.tray, rule=acx) # -------------------------------------------------------------------------------------------------------------- #: Constraint section (algebraic equations) mod.hrc = Constraint(mod.t, rule=hrc) mod.gh = Constraint(mod.t, mod.tray, rule=gh) mod.ghb = Constraint(mod.t, rule=ghb) mod.ghc = Constraint(mod.t, rule=ghc)
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 three_objective_model(): model = ConcreteModel() # Define variables model.LIGN = Var(within=NonNegativeReals) model.LIGN1 = Var(within=NonNegativeReals) model.LIGN2 = Var(within=NonNegativeReals) model.OIL = Var(within=NonNegativeReals) model.OIL2 = Var(within=NonNegativeReals) model.OIL3 = Var(within=NonNegativeReals) model.NG = Var(within=NonNegativeReals) model.NG1 = Var(within=NonNegativeReals) model.NG2 = Var(within=NonNegativeReals) model.NG3 = Var(within=NonNegativeReals) model.RES = Var(within=NonNegativeReals) model.RES1 = Var(within=NonNegativeReals) model.RES3 = Var(within=NonNegativeReals) # -------------------------------------- # Define the objective functions # -------------------------------------- def objective1(model): return 30 * model.LIGN + 75 * model.OIL + 60 * model.NG + 90 * model.RES def objective2(model): return 1.44 * model.LIGN + 0.72 * model.OIL + 0.45 * model.NG def objective3(model): return model.OIL + model.NG # -------------------------------------- # Define the regular constraints # -------------------------------------- def constraint1(model): return model.LIGN - model.LIGN1 - model.LIGN2 == 0 def constraint2(model): return model.OIL - model.OIL2 - model.OIL3 == 0 def constraint3(model): return model.NG - model.NG1 - model.NG2 - model.NG3 == 0 def constraint4(model): return model.RES - model.RES1 - model.RES3 == 0 def constraint5(model): return model.LIGN <= 31000 def constraint6(model): return model.OIL <= 15000 def constraint7(model): return model.NG <= 22000 def constraint8(model): return model.RES <= 10000 def constraint9(model): return model.LIGN1 + model.NG1 + model.RES1 >= 38400 def constraint10(model): return model.LIGN2 + model.OIL2 + model.NG2 >= 19200 def constraint11(model): return model.OIL3 + model.NG3 + model.RES3 >= 6400 # -------------------------------------- # Add components to the model # -------------------------------------- # Add the constraints to the model model.con1 = Constraint(rule=constraint1) model.con2 = Constraint(rule=constraint2) model.con3 = Constraint(rule=constraint3) model.con4 = Constraint(rule=constraint4) model.con5 = Constraint(rule=constraint5) model.con6 = Constraint(rule=constraint6) model.con7 = Constraint(rule=constraint7) model.con8 = Constraint(rule=constraint8) model.con9 = Constraint(rule=constraint9) model.con10 = Constraint(rule=constraint10) model.con11 = Constraint(rule=constraint11) # Add the objective functions to the model using ObjectiveList(). Note # that the first index is 1 instead of 0! model.obj_list = ObjectiveList() model.obj_list.add(expr=objective1(model), sense=minimize) model.obj_list.add(expr=objective2(model), sense=minimize) model.obj_list.add(expr=objective3(model), sense=minimize) # By default deactivate all the objective functions for o in range(len(model.obj_list)): model.obj_list[o + 1].deactivate() return model
def __init__(self, nfe_t, ncp_t, **kwargs): ConcreteModel.__init__(self) steady = kwargs.pop('steady', False) _t = kwargs.pop('_t', 1.0) Ntray = kwargs.pop('Ntray', 42) # -------------------------------------------------------------------------------------------------------------- # Orthogonal Collocation Parameters section # Radau self._alp_gauB_t = 1 self._bet_gauB_t = 0 if steady: print("[I] " + str(self.__class__.__name__) + " NFE and NCP Overriden - Steady state mode") self.nfe_t = 1 self.ncp_t = 1 else: self.nfe_t = nfe_t self.ncp_t = ncp_t self.tau_t = collptsgen(self.ncp_t, self._alp_gauB_t, self._bet_gauB_t) # start at zero self.tau_i_t = {0: 0.} # create a list for ii in range(1, self.ncp_t + 1): self.tau_i_t[ii] = self.tau_t[ii - 1] # ======= SETS ======= # # For finite element = 1 .. NFE # This has to be > 0 self.fe_t = Set(initialize=[ii for ii in range(1, self.nfe_t + 1)]) # collocation points # collocation points for differential variables self.cp_t = Set(initialize=[ii for ii in range(0, self.ncp_t + 1)]) # collocation points for algebraic variables self.cp_ta = Set(within=self.cp_t, initialize=[ii for ii in range(1, self.ncp_t + 1)]) # create collocation param self.taucp_t = Param(self.cp_t, initialize=self.tau_i_t) self.ldot_t = Param(self.cp_t, self.cp_t, initialize= (lambda m, j, k: lgrdot(k, m.taucp_t[j], self.ncp_t, self._alp_gauB_t, self._bet_gauB_t))) #: watch out for this! self.l1_t = Param(self.cp_t, initialize= (lambda m, j: lgr(j, 1, self.ncp_t, self._alp_gauB_t, self._bet_gauB_t))) # -------------------------------------------------------------------------------------------------------------- # Model parameters self.Ntray = Ntray self.tray = Set(initialize=[i for i in range(1, Ntray + 1)]) self.feed = Param(self.tray, initialize=lambda m, t: 57.5294 if t == 21 else 0.0, mutable=True) self.xf = Param(initialize=0.32, mutable=True) # feed mole fraction self.hf = Param(initialize=9081.3) # feed enthalpy self.hlm0 = Param(initialize=2.6786e-04) self.hlma = Param(initialize=-0.14779) self.hlmb = Param(initialize=97.4289) self.hlmc = Param(initialize=-2.1045e04) self.hln0 = Param(initialize=4.0449e-04) self.hlna = Param(initialize=-0.1435) self.hlnb = Param(initialize=121.7981) self.hlnc = Param(initialize=-3.0718e04) self.r = Param(initialize=8.3147) self.a = Param(initialize=6.09648) self.b = Param(initialize=1.28862) self.c1 = Param(initialize=1.016) self.d = Param(initialize=15.6875) self.l = Param(initialize=13.4721) self.f = Param(initialize=2.615) self.gm = Param(initialize=0.557) self.Tkm = Param(initialize=512.6) self.Pkm = Param(initialize=8.096e06) self.gn = Param(initialize=0.612) self.Tkn = Param(initialize=536.7) self.Pkn = Param(initialize=5.166e06) self.CapAm = Param(initialize=23.48) self.CapBm = Param(initialize=3626.6) self.CapCm = Param(initialize=-34.29) self.CapAn = Param(initialize=22.437) self.CapBn = Param(initialize=3166.64) self.CapCn = Param(initialize=-80.15) self.pstrip = Param(initialize=250) self.prect = Param(initialize=190) def _p_init(m, t): ptray = 9.39e04 if t <= 20: return _p_init(m, 21) + m.pstrip * (21 - t) elif 20 < t < m.Ntray: return ptray + m.prect * (m.Ntray - t) elif t == m.Ntray: return 9.39e04 self.p = Param(self.tray, initialize=_p_init) self.T29_des = Param(initialize=343.15) self.T15_des = Param(initialize=361.15) self.Dset = Param(initialize=1.83728) self.Qcset = Param(initialize=1.618890) self.Qrset = Param(initialize=1.786050) # self.Recset = Param() self.alpha_T29 = Param(initialize=1) self.alpha_T15 = Param(initialize=1) self.alpha_D = Param(initialize=1) self.alpha_Qc = Param(initialize=1) self.alpha_Qr = Param(initialize=1) self.alpha_Rec = Param(initialize=1) def _alpha_init(m, i): if i <= 21: return 0.62 else: return 0.35 self.alpha = Param(self.tray, initialize=lambda m, t: 0.62 if t <= 21 else 0.35) # -------------------------------------------------------------------------------------------------------------- #: First define differential state variables (state: x, ic-Param: x_ic, derivative-Var:dx_dt #: States (differential) section zero_tray = dict.fromkeys(self.tray) zero3 = dict.fromkeys(self.fe_t * self.cp_t * self.tray) for key in zero3.keys(): zero3[key] = 0.0 def __m_init(m, i, j, t): if t < m.Ntray: return 4000. elif t == 1: return 104340. elif t == m.Ntray: return 5000. #: Liquid hold-up self.M = Var(self.fe_t, self.cp_t, self.tray, initialize=__m_init) #: Mole-fraction self.x = Var(self.fe_t, self.cp_t, self.tray, initialize=lambda m, i, j, t: 0.999 * t / m.Ntray) #: Initial state-Param self.M_ic = zero_tray if steady else Param(self.tray, initialize=0.0, mutable=True) self.x_ic = zero_tray if steady else Param(self.tray, initialize=0.0, mutable=True) #: Derivative-var self.dM_dt = zero3 if steady else Var(self.fe_t, self.cp_t, self.tray, initialize=0.0) self.dx_dt = zero3 if steady else Var(self.fe_t, self.cp_t, self.tray, initialize=0.0) # -------------------------------------------------------------------------------------------------------------- # States (algebraic) section # Tray temperature self.T = Var(self.fe_t, self.cp_ta, self.tray, initialize=lambda m, i, j, t: ((370.781 - 335.753) / m.Ntray) * t + 370.781) self.Tdot = Var(self.fe_t, self.cp_ta, self.tray, initialize=1e-05) #: Not really a der_var # saturation pressures self.pm = Var(self.fe_t, self.cp_ta, self.tray, initialize=1e4) self.pn = Var(self.fe_t, self.cp_ta, self.tray, initialize=1e4) # Vapor mole flowrate self.V = Var(self.fe_t, self.cp_ta, self.tray, initialize=44.0) def _l_init(m, i, j, t): if 2 <= t <= 21: return 83. elif 22 <= t <= 42: return 23 elif t == 1: return 40 # Liquid mole flowrate self.L = Var(self.fe_t, self.cp_ta, self.tray, initialize=_l_init) # Vapor mole frac & diff var self.y = Var(self.fe_t, self.cp_ta, self.tray, initialize=lambda m, i, j, t: ((0.99 - 0.005) / m.Ntray) * t + 0.005) # Liquid enthalpy # enthalpy self.hl = Var(self.fe_t, self.cp_ta, self.tray, initialize=10000.) # Liquid enthalpy # enthalpy self.hv = Var(self.fe_t, self.cp_ta, self.tray, initialize=5e+04) # Re-boiler & condenser heat self.Qc = Var(self.fe_t, self.cp_ta, initialize=1.6e06) self.D = Var(self.fe_t, self.cp_ta, initialize=18.33) # vol holdups self.Vm = Var(self.fe_t, self.cp_ta, self.tray, initialize=6e-05) self.Mv = Var(self.fe_t, self.cp_ta, self.tray, initialize=lambda m, i, j, t: 0.23 if 1 < t < m.Ntray else 0.0) self.Mv1 = Var(self.fe_t, self.cp_ta, initialize=8.57) self.Mvn = Var(self.fe_t, self.cp_ta, initialize=0.203) hi_t = dict.fromkeys(self.fe_t) for key in hi_t.keys(): hi_t[key] = 1.0 if steady else _t/self.nfe_t self.hi_t = hi_t if steady else Param(self.fe_t, initialize=hi_t) # -------------------------------------------------------------------------------------------------------------- #: Controls self.u1 = Param(self.fe_t, initialize=7.72700925775773761472464684629813E-01, mutable=True) #: Dummy self.u2 = Param(self.fe_t, initialize=1.78604740940007800236344337463379E+06, mutable=True) #: Dummy self.Rec = Var(self.fe_t, initialize=7.72700925775773761472464684629813E-01) self.Qr = Var(self.fe_t, initialize=1.78604740940007800236344337463379E+06) # -------------------------------------------------------------------------------------------------------------- #: Constraints for the differential states #: Then the ode-Con:de_x, collocation-Con:dvar_t_x, noisy-Expr: noisy_x, cp-Constraint: cp_x, initial-Con: x_icc #: Differential equations self.de_M = Constraint(self.fe_t, self.cp_ta, self.tray, rule=m_ode) self.de_x = Constraint(self.fe_t, self.cp_ta, self.tray, rule=x_ode) #: Collocation equations self.dvar_t_M = None if steady else Constraint(self.fe_t, self.cp_ta, self.tray, rule=M_COLL) self.dvar_t_x = None if steady else Constraint(self.fe_t, self.cp_ta, self.tray, rule=x_coll) #: Continuation equations (redundancy here) if self.nfe_t > 1: #: Noisy expressions self.noisy_M = None if steady else Expression(self.fe_t, self.tray, rule=M_CONT) self.noisy_x = None if steady else Expression(self.fe_t, self.tray, rule=x_cont) #: Continuation equations self.cp_M = None if steady else \ Constraint(self.fe_t, self.tray, rule=lambda m, i, t: self.noisy_M[i, t] == 0.0 if i < self.nfe_t else Constraint.Skip) self.cp_x = None if steady else \ Constraint(self.fe_t, self.tray, rule=lambda m, i, t: self.noisy_x[i, t] == 0.0 if i < self.nfe_t else Constraint.Skip) #: Initial condition-Constraints self.M_icc = None if steady else Constraint(self.tray, rule=acm) self.x_icc = None if steady else Constraint(self.tray, rule=acx) # -------------------------------------------------------------------------------------------------------------- #: Constraint section (algebraic equations) self.hrc = Constraint(self.fe_t, self.cp_ta, rule=hrc) self.gh = Constraint(self.fe_t, self.cp_ta, self.tray, rule=gh) self.ghb = Constraint(self.fe_t, self.cp_ta, rule=ghb) self.ghc = Constraint(self.fe_t, self.cp_ta, rule=ghc) self.hkl = Constraint(self.fe_t, self.cp_ta, self.tray, rule=hkl) self.hkv = Constraint(self.fe_t, self.cp_ta, self.tray, rule=hkv) self.lpself = Constraint(self.fe_t, self.cp_ta, self.tray, rule=lpm) self.lpn = Constraint(self.fe_t, self.cp_ta, self.tray, rule=lpn) self.dp = Constraint(self.fe_t, self.cp_ta, self.tray, rule=dp) self.lTdot = Constraint(self.fe_t, self.cp_ta, self.tray, rule=lTdot) self.gy0 = Constraint(self.fe_t, self.cp_ta, rule=gy0) self.gy = Constraint(self.fe_t, self.cp_ta, self.tray, rule=gy) self.dMV = Constraint(self.fe_t, self.cp_ta, self.tray, rule=dMV) self.dMv1 = Constraint(self.fe_t, self.cp_ta, rule=dMv1) self.dMvn = Constraint(self.fe_t, self.cp_ta, rule=dMvn) self.hyd = Constraint(self.fe_t, self.cp_ta, self.tray, rule=hyd) self.hyd1 = Constraint(self.fe_t, self.cp_ta, rule=hyd1) self.hydN = Constraint(self.fe_t, self.cp_ta, rule=hydN) self.dvself = Constraint(self.fe_t, self.cp_ta, self.tray, rule=dvm) # -------------------------------------------------------------------------------------------------------------- #: Control constraint self.u1_e = Expression(self.fe_t, rule=lambda m, i: self.Rec[i]) self.u2_e = Expression(self.fe_t, rule=lambda m, i: self.Qr[i]) self.u1_c = Constraint(self.fe_t, rule=lambda m, i: self.u1[i] == self.u1_e[i]) self.u2_c = Constraint(self.fe_t, rule=lambda m, i: self.u2[i] == self.u2_e[i]) # -------------------------------------------------------------------------------------------------------------- #: Suffixes self.dual = Suffix(direction=Suffix.IMPORT_EXPORT) self.ipopt_zL_out = Suffix(direction=Suffix.IMPORT) self.ipopt_zU_out = Suffix(direction=Suffix.IMPORT) self.ipopt_zL_in = Suffix(direction=Suffix.EXPORT) self.ipopt_zU_in = Suffix(direction=Suffix.EXPORT)
def _apply_to(self, instance, **kwds): if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug("Calling ConnectorExpander") connectorsFound = False for c in instance.component_data_objects(Connector): connectorsFound = True break if not connectorsFound: return if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug(" Connectors found!") # # At this point, there are connectors in the model, so we must # look for constraints that involve connectors and expand them. # connector_types = set([SimpleConnector, _ConnectorData]) constraint_list = [] connector_list = [] matched_connectors = {} found = dict() for constraint in instance.component_data_objects(Constraint): for c in expr.identify_variables( constraint.body, include_potentially_variable=True): if c.__class__ in connector_types: found[id(c)] = c if not found: continue # Note that it is important to copy the set of found # connectors, since the matching routine below will # manipulate sets in place. found_this_constraint = dict(found) constraint_list.append((constraint, found_this_constraint)) # Find all the connectors that are used in the constraint, # so we know which connectors to validate against each # other. Note that the validation must be transitive (that # is, if con1 has a & b and con2 has b & c, then a,b, and c # must all validate against each other. for cId, c in iteritems(found_this_constraint): if cId in matched_connectors: oldSet = matched_connectors[cId] found.update(oldSet) for _cId in oldSet: matched_connectors[_cId] = found else: connector_list.append(c) matched_connectors[cId] = found # Reset found back to empty (this is more efficient as the # bulk of the constraints in the model will not have # connectors - so if we did this at the top of the loop, we # would spend a lot of time clearing empty sets found = {} # Validate all connector sets and expand the empty ones known_conn_sets = {} for connector in connector_list: conn_set = matched_connectors[id(connector)] if id(conn_set) in known_conn_sets: continue known_conn_sets[id(conn_set)] \ = self._validate_and_expand_connector_set(conn_set) # Expand each constraint for constraint, conn_set in constraint_list: cList = ConstraintList() constraint.parent_block().add_component( '%s.expanded' % (constraint.local_name, ), cList) connId = next(iterkeys(conn_set)) ref = known_conn_sets[id(matched_connectors[connId])] for k, v in sorted(iteritems(ref)): if v[1] >= 0: _iter = v[0] else: _iter = (v[0], ) for idx in _iter: substitution = {} for c in itervalues(conn_set): if v[1] >= 0: new_v = c.vars[k][idx] elif k in c.aggregators: new_v = c.vars[k].add() else: new_v = c.vars[k] substitution[id(c)] = new_v cList.add((constraint.lower, expr.clone_expression(constraint.body, substitution), constraint.upper)) constraint.deactivate() # Now, go back and implement VarList aggregators for conn in connector_list: block = conn.parent_block() for var, aggregator in iteritems(conn.aggregators): c = Constraint(expr=aggregator(block, conn.vars[var])) block.add_component('%s.%s.aggregate' % (conn.local_name, var), c)
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 _apply_to(self, instance, **kwds): if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug("Calling ConnectorExpander") connectorsFound = False for c in instance.component_data_objects(Connector): connectorsFound = True break if not connectorsFound: return if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover logger.debug(" Connectors found!") self._name_buffer = {} # # At this point, there are connectors in the model, so we must # look for constraints that involve connectors and expand them. # # List of the connectors in the order in which we found them # (this should be deterministic, provided that the user's model # is deterministic) connector_list = [] # list of constraints with connectors: tuple(constraint, connector_set) # (this should be deterministic, provided that the user's model # is deterministic) constraint_list = [] # ID of the next connector group (set of matched connectors) groupID = 0 # connector_groups stars out as a dict of {id(set): (groupID, set)} # If you sort by the groupID, then this will be deterministic. connector_groups = dict() # map of connector to the set of connectors that must match it matched_connectors = ComponentMap() # The set of connectors found in the current constraint found = ComponentSet() connector_types = set([SimpleConnector, _ConnectorData]) for constraint in instance.component_data_objects( Constraint, sort=SortComponents.deterministic): ref = None for c in EXPR.identify_components(constraint.body, connector_types): found.add(c) if c in matched_connectors: if ref is None: # The first connector in this constraint has # already been seen. We will use that Set as # the reference ref = matched_connectors[c] elif ref is not matched_connectors[c]: # We already have a reference group; merge this # new group into it. # # Optimization: this merge is linear in the size # of the src set. If the reference set is # smaller, save time by switching to a new # reference set. src = matched_connectors[c] if len(ref) < len(src): ref, src = src, ref ref.update(src) for _ in src: matched_connectors[_] = ref del connector_groups[id(src)] # else: pass # The new group *is* the reference group; # there is nothing to do. else: # The connector has not been seen before. connector_list.append(c) if ref is None: # This is the first connector in the constraint: # start a new reference set. ref = ComponentSet() connector_groups[id(ref)] = (groupID, ref) groupID += 1 # This connector hasn't been seen. Record it. ref.add(c) matched_connectors[c] = ref if ref is not None: constraint_list.append((constraint, found)) found = ComponentSet() # Validate all connector sets and expand the empty ones known_conn_sets = {} for groupID, conn_set in sorted(itervalues(connector_groups)): known_conn_sets[id(conn_set)] \ = self._validate_and_expand_connector_set(conn_set) # Expand each constraint for constraint, conn_set in constraint_list: cList = ConstraintList() constraint.parent_block().add_component( '%s.expanded' % (constraint.getname( fully_qualified=False, name_buffer=self._name_buffer), ), cList) connId = next(iter(conn_set)) ref = known_conn_sets[id(matched_connectors[connId])] for k, v in sorted(iteritems(ref)): if v[1] >= 0: _iter = v[0] else: _iter = (v[0], ) for idx in _iter: substitution = {} for c in conn_set: if v[1] >= 0: new_v = c.vars[k][idx] elif k in c.aggregators: new_v = c.vars[k].add() else: new_v = c.vars[k] substitution[id(c)] = new_v cList.add((constraint.lower, EXPR.clone_expression(constraint.body, substitution), constraint.upper)) constraint.deactivate() # Now, go back and implement VarList aggregators for conn in connector_list: block = conn.parent_block() for var, aggregator in iteritems(conn.aggregators): c = Constraint(expr=aggregator(block, conn.vars[var])) block.add_component( '%s.%s.aggregate' % (conn.getname(fully_qualified=True, name_buffer=self._name_buffer), var), c)
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
def to_common_form(self, cdata, free_vars): """ Convert a common form that can processed by AMPL """ _e1 = cdata._canonical_expression(cdata._args[0]) _e2 = cdata._canonical_expression(cdata._args[1]) if False: #pragma:nocover if _e1[0] is None: print(None) else: print(str(_e1[0])) if _e1[1] is None: print(None) else: print(str(_e1[1])) if len(_e1) > 2: if _e1[2] is None: print(None) else: print(str(_e1[2])) if _e2[0] is None: print(None) else: print(str(_e2[0])) if _e2[1] is None: print(None) else: print(str(_e2[1])) if len(_e2) > 2: if _e2[2] is None: print(None) else: print(str(_e2[2])) if len(_e1) == 2: cdata.c = Constraint(expr=_e1) return if len(_e2) == 2: cdata.c = Constraint(expr=_e2) return if (_e1[0] is None) + (_e1[2] is None) + (_e2[0] is None) + ( _e2[2] is None) != 2: raise RuntimeError( "Complementarity condition %s must have exactly two finite bounds" % cdata.name) # # Swap if the body of the second constraint is not a free variable # if not id(_e2[1]) in free_vars and id(_e1[1]) in free_vars: _e1, _e2 = _e2, _e1 # # Rework the first constraint to have a zero bound. # The bound is a lower or upper bound depending on the # variable bound. # if not _e1[0] is None: cdata.bv = Var() cdata.c = Constraint(expr=0 <= cdata.bv) if not _e2[0] is None: cdata.bc = Constraint(expr=cdata.bv == _e1[1] - _e1[0]) else: cdata.bc = Constraint(expr=cdata.bv == _e1[0] - _e1[1]) elif not _e1[2] is None: cdata.bv = Var() cdata.c = Constraint(expr=0 <= cdata.bv) if not _e2[2] is None: cdata.bc = Constraint(expr=cdata.bv == _e1[1] - _e1[2]) else: cdata.bc = Constraint(expr=cdata.bv == _e1[2] - _e1[1]) else: cdata.bv = Var() cdata.bc = Constraint(expr=cdata.bv == _e1[1]) cdata.c = Constraint(expr=(None, cdata.bv, None)) # # If the body of the second constraint is a free variable, then keep it. # Otherwise, create a new variable and a new constraint. # if id(_e2[1]) in free_vars: var = _e2[1] cdata.c._vid = id(_e2[1]) del free_vars[cdata.c._vid] else: var = cdata.v = Var() cdata.c._vid = id(cdata.v) cdata.e = Constraint(expr=cdata.v == _e2[1]) # # Set the variable bound values, and corresponding _complementarity value # cdata.c._complementarity = 0 if not _e2[0] is None: if var.lb is None or value(_e2[0]) > value(var.lb): var.setlb(_e2[0]) cdata.c._complementarity += 1 if not _e2[2] is None: if var.ub is None or value(_e2[2]) > value(var.ub): var.setub(_e2[2]) cdata.c._complementarity += 2
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
mod.Cainb = Param(default=1.0) mod.Tinb = Param(default=275.0) # mod.Tjinb = Param(default=250.0) #: Our control var mod.Tjinb = Var(mod.t, initialize=250) mod.u1 = Param(mod.t, default=250, mutable=True) #: We are making a sort-of port def u1_rule(m, i): return m.Tjinb[i] == m.u1[i] # mod.u1_cdummy = Constraint(mod.t, rule=lambda m, i: m.Tjinb[i] == mod.u1[i]) mod.u1_cdummy = Constraint(mod.t, rule=u1_rule) #: u1 will contain the information from the NMPC problem. This is what drives the plant. #: how about smth like nmpc_u1 or u1_nmpc mod.V = Param(initialize=100) mod.UA = Param(initialize=20000 * 60) mod.rho = Param(initialize=1000) mod.Cp = Param(initialize=4.2) mod.Vw = Param(initialize=10) mod.rhow = Param(initialize=1000) mod.Cpw = Param(initialize=4.2) mod.k0 = Param(initialize=4.11e13) mod.E = Param(initialize=76534.704) mod.R = Param(initialize=8.314472) mod.Er = Param(initialize=lambda m: (value(mod.E) / value(mod.R))) mod.dH = Param(initialize=596619.)
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 unit_commitment_model(): model = ConcreteModel() # Define input files xlsx = pd.ExcelFile( f"{Path(__file__).parent.absolute()}/input/unit_commitment.xlsx", engine="openpyxl", ) system_demand = Helper.read_excel(xlsx, "SystemDemand") storage_systems = Helper.read_excel(xlsx, "StorageSystems") generators = Helper.read_excel(xlsx, "Generators") generator_step_size = Helper.read_excel(xlsx, "GeneratorStepSize") generator_step_cost = Helper.read_excel(xlsx, "GeneratorStepCost") pv_generation = Helper.read_excel(xlsx, "PVGeneration") # Define sets model.T = Set(ordered=True, initialize=system_demand.index) model.I = Set(ordered=True, initialize=generators.index) model.F = Set(ordered=True, initialize=generator_step_size.columns) model.S = Set(ordered=True, initialize=storage_systems.index) # Define parameters model.Pmax = Param(model.I, within=NonNegativeReals, mutable=True) model.Pmin = Param(model.I, within=NonNegativeReals, mutable=True) model.RU = Param(model.I, within=NonNegativeReals, mutable=True) model.RD = Param(model.I, within=NonNegativeReals, mutable=True) model.SUC = Param(model.I, within=NonNegativeReals, mutable=True) model.SDC = Param(model.I, within=NonNegativeReals, mutable=True) model.Pini = Param(model.I, within=NonNegativeReals, mutable=True) model.uini = Param(model.I, within=Binary, mutable=True) model.C = Param(model.I, model.F, within=NonNegativeReals, mutable=True) model.B = Param(model.I, model.F, within=NonNegativeReals, mutable=True) model.SystemDemand = Param(model.T, within=NonNegativeReals, mutable=True) model.Emissions = Param(model.I, within=NonNegativeReals, mutable=True) model.PV = Param(model.T, within=NonNegativeReals, mutable=True) model.ESS_Pmax = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_SOEmax = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_SOEini = Param(model.S, within=NonNegativeReals, mutable=True) model.ESS_Eff = Param(model.S, within=NonNegativeReals, mutable=True) # Give values to parameters of the generators for i in model.I: model.Pmin[i] = generators.loc[i, "Pmin"] model.Pmax[i] = generators.loc[i, "Pmax"] model.RU[i] = generators.loc[i, "RU"] model.RD[i] = generators.loc[i, "RD"] model.SUC[i] = generators.loc[i, "SUC"] model.SDC[i] = generators.loc[i, "SDC"] model.Pini[i] = generators.loc[i, "Pini"] model.uini[i] = generators.loc[i, "uini"] model.Emissions[i] = generators.loc[i, "Emissions"] for f in model.F: model.B[i, f] = generator_step_size.loc[i, f] model.C[i, f] = generator_step_cost.loc[i, f] # Add system demand and PV generation for t in model.T: model.SystemDemand[t] = system_demand.loc[t, "SystemDemand"] model.PV[t] = pv_generation.loc[t, "PVGeneration"] # Give values to ESS parameters for s in model.S: model.ESS_Pmax[s] = storage_systems.loc[s, "Power"] model.ESS_SOEmax[s] = storage_systems.loc[s, "Energy"] model.ESS_SOEini[s] = storage_systems.loc[s, "SOEini"] model.ESS_Eff[s] = storage_systems.loc[s, "Eff"] # Define decision variables model.P = Var(model.I, model.T, within=NonNegativeReals) model.Pres = Var(model.T, within=NonNegativeReals) model.b = Var(model.I, model.F, model.T, within=NonNegativeReals) model.u = Var(model.I, model.T, within=Binary) model.CSU = Var(model.I, model.T, within=NonNegativeReals) model.CSD = Var(model.I, model.T, within=NonNegativeReals) model.SOE = Var(model.S, model.T, within=NonNegativeReals) model.Pch = Var(model.S, model.T, within=NonNegativeReals) model.Pdis = Var(model.S, model.T, within=NonNegativeReals) model.u_ess = Var(model.S, model.T, within=Binary) # -------------------------------------- # Define the objective functions # -------------------------------------- def cost_objective(model): return sum( sum( sum(model.C[i, f] * model.b[i, f, t] for f in model.F) + model.CSU[i, t] + model.CSD[i, t] for i in model.I) for t in model.T) def emissions_objective(model): return sum( sum(model.P[i, t] * model.Emissions[i] for i in model.I) for t in model.T) def unmet_objective(model): return sum(model.Pres[t] for t in model.T) # -------------------------------------- # Define the regular constraints # -------------------------------------- def power_decomposition_rule1(model, i, t): return model.P[i, t] == sum(model.b[i, f, t] for f in model.F) def power_decomposition_rule2(model, i, f, t): return model.b[i, f, t] <= model.B[i, f] def power_min_rule(model, i, t): return model.P[i, t] >= model.Pmin[i] * model.u[i, t] def power_max_rule(model, i, t): return model.P[i, t] <= model.Pmax[i] * model.u[i, t] def ramp_up_rule(model, i, t): if model.T.ord(t) == 1: return model.P[i, t] - model.Pini[i] <= 60 * model.RU[i] if model.T.ord(t) > 1: return model.P[i, t] - model.P[i, model.T.prev(t)] <= 60 * model.RU[i] def ramp_down_rule(model, i, t): if model.T.ord(t) == 1: return (model.Pini[i] - model.P[i, t]) <= 60 * model.RD[i] if model.T.ord(t) > 1: return (model.P[i, model.T.prev(t)] - model.P[i, t]) <= 60 * model.RD[i] def start_up_cost(model, i, t): if model.T.ord(t) == 1: return model.CSU[i, t] >= model.SUC[i] * (model.u[i, t] - model.uini[i]) if model.T.ord(t) > 1: return model.CSU[i, t] >= model.SUC[i] * ( model.u[i, t] - model.u[i, model.T.prev(t)]) def shut_down_cost(model, i, t): if model.T.ord(t) == 1: return model.CSD[i, t] >= model.SDC[i] * (model.uini[i] - model.u[i, t]) if model.T.ord(t) > 1: return model.CSD[i, t] >= model.SDC[i] * ( model.u[i, model.T.prev(t)] - model.u[i, t]) def ESS_SOEupdate(model, s, t): if model.T.ord(t) == 1: return (model.SOE[s, t] == model.ESS_SOEini[s] + model.ESS_Eff[s] * model.Pch[s, t] - model.Pdis[s, t] / model.ESS_Eff[s]) if model.T.ord(t) > 1: return (model.SOE[s, t] == model.SOE[s, model.T.prev(t)] + model.ESS_Eff[s] * model.Pch[s, t] - model.Pdis[s, t] / model.ESS_Eff[s]) def ESS_SOElimit(model, s, t): return model.SOE[s, t] <= model.ESS_SOEmax[s] def ESS_Charging(model, s, t): return model.Pch[s, t] <= model.ESS_Pmax[s] * model.u_ess[s, t] def ESS_Discharging(model, s, t): return model.Pdis[s, t] <= model.ESS_Pmax[s] * (1 - model.u_ess[s, t]) def Balance(model, t): return model.PV[t] + sum(model.P[i, t] for i in model.I) + sum( model.Pdis[s, t] for s in model.S) == model.SystemDemand[t] - model.Pres[t] + sum( model.Pch[s, t] for s in model.S) def Pres_max(model, t): return model.Pres[t] <= 0.1 * model.SystemDemand[t] # -------------------------------------- # Add components to the model # -------------------------------------- # Add the constraints to the model model.power_decomposition_rule1 = Constraint( model.I, model.T, rule=power_decomposition_rule1) model.power_decomposition_rule2 = Constraint( model.I, model.F, model.T, rule=power_decomposition_rule2) model.power_min_rule = Constraint(model.I, model.T, rule=power_min_rule) model.power_max_rule = Constraint(model.I, model.T, rule=power_max_rule) model.start_up_cost = Constraint(model.I, model.T, rule=start_up_cost) model.shut_down_cost = Constraint(model.I, model.T, rule=shut_down_cost) model.ConSOEUpdate = Constraint(model.S, model.T, rule=ESS_SOEupdate) model.ConCharging = Constraint(model.S, model.T, rule=ESS_Charging) model.ConDischarging = Constraint(model.S, model.T, rule=ESS_Discharging) model.ConSOElimit = Constraint(model.S, model.T, rule=ESS_SOElimit) model.ConGenUp = Constraint(model.I, model.T, rule=ramp_up_rule) model.ConGenDown = Constraint(model.I, model.T, rule=ramp_down_rule) model.ConBalance = Constraint(model.T, rule=Balance) model.Pres_max = Constraint(model.T, rule=Pres_max) # Add the objective functions to the model using ObjectiveList(). Note # that the first index is 1 instead of 0! model.obj_list = ObjectiveList() model.obj_list.add(expr=cost_objective(model), sense=minimize) model.obj_list.add(expr=emissions_objective(model), sense=minimize) model.obj_list.add(expr=unmet_objective(model), sense=minimize) # By default deactivate all the objective functions for o in range(len(model.obj_list)): model.obj_list[o + 1].deactivate() return model