Example #1
0
    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
Example #2
0
 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
Example #4
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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
Example #9
0
 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)
Example #10
0
    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)
Example #11
0
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
Example #12
0
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()
Example #13
0
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
Example #14
0
    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
Example #15
0
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
Example #16
0
 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
Example #17
0
    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)
Example #18
0
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)
Example #19
0
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
Example #21
0
    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)
Example #22
0
    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)
Example #23
0
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
Example #24
0
    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)
Example #25
0
    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
Example #26
0
 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
Example #27
0
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
Example #28
0
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.)
Example #29
0
    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