Ejemplo n.º 1
0

def one_per_cust_rule(model, m):
    return sum(model.x[n, m] for n in model.N) == 1


model.one_per_cust = pyo.Constraint(model.M, rule=one_per_cust_rule)


def warehouse_active_rule(model, n, m):
    return model.x[n, m] <= model.y[n]


model.warehouse_active = pyo.Constraint(model.N,
                                        model.M,
                                        rule=warehouse_active_rule)


def num_warehouses_rule(model):
    return sum(model.y[n] for n in model.N) <= model.P


model.num_warehouses = pyo.Constraint(rule=num_warehouses_rule)


def printM_rule(model):
    model.M.pprint()


model.printM = pyo.BuildAction(rule=printM_rule)
Ejemplo n.º 2
0
import pyomo.environ as pyo

import scont
model = scont.model


# @action:
def transform_gdp(m):
    xfrm = pyo.TransformationFactory('gdp.bigm')
    xfrm.apply_to(m)


model.transform_gdp = pyo.BuildAction(rule=transform_gdp)
# @:action
Ejemplo n.º 3
0
def createModel(repn_DQ=3,
                constr_DQ=2,
                PieceCnt_DQ=10,
                func_factor_DQ=2,
                **kwargs):
    """This funtion creates a model.
    
    Parameters
    ----------
    repn_DQ: :const:`int=3`
        Representation of the piecewise function for DataQualities::
        
            0: BIGM_SOS1,   5: DLOG,
            1: BIGM_BIN,    6: LOG,
            2: SOS2,        7: MC,
            3: CC,          8: INC,
            4: DCC,      None: None

    constr_DQ: :const:`int=2`
        Constraint method::
            
            0: UB,          2: EQ,
            1: LB,       None: None
            
    PieceCnt_DQ: :const:`int=10`
        Piecewise section count.
        
    func_factor_DQ: :const:`int=2`
        Sets the power ``**(1/func_factor_DQ)`` to the calculation function :py:func:`Compute_DQ_rule`.
        
    kwargs:
        Add additional Values. (Currently unused.)
    """

    model = pe.AbstractModel(name="MI(N)LP")

    model.instance_name = ""  # Define Instance Name

    ###########################################################################
    # Mengen (list([index, ]))
    model.I = pe.Set()
    model.J = pe.Set()
    model.G = pe.Set()
    model.H = pe.Set()
    model.S = pe.Set()
    model.V = pe.Set()
    model.P = pe.Set()
    model.Q = pe.Set()
    model.Q_bild = pe.Set()

    ###########################################################################

    ############
    # Parameter
    ############

    # Einstellungen
    #model.epsilon           = pe.Param(default=1, domain=pe.NonNegativeReals, mutable=True)
    model.u = pe.Param(default=0, domain=pe.NonNegativeReals, mutable=True)
    model.n = pe.Param(default=1, domain=pe.NonNegativeIntegers, mutable=True)
    model.kappa_sum_zul = pe.Param(default=1,
                                   domain=pe.NonNegativeIntegers,
                                   mutable=True)
    model.beta_sum_zul = pe.Param(default=1,
                                  domain=pe.NonNegativeIntegers,
                                  mutable=True)
    model.delta_sum_zul = pe.Param(default=1,
                                   domain=pe.NonNegativeIntegers,
                                   mutable=True)
    model.gamma_sum_zul = pe.Param(default=1,
                                   domain=pe.NonNegativeIntegers,
                                   mutable=True)
    model.tau_sum_zul = pe.Param(default=1,
                                 domain=pe.NonNegativeIntegers,
                                 mutable=True)
    model.DQ_ges_max = pe.Param(default=1,
                                domain=pe.PercentFraction,
                                mutable=True)  # TODO
    model.DQ_ges_min = pe.Param(default=0,
                                domain=pe.PercentFraction,
                                mutable=True)  # TODO
    model.Costs_ges_max = pe.Param(default=float('inf'),
                                   domain=pe.NonNegativeReals,
                                   mutable=True)  # TODO
    model.Costs_ges_min = pe.Param(default=0,
                                   domain=pe.NonNegativeReals,
                                   mutable=True)  # TODO
    # model.Costs_ges_abs     = pe.Param(default=0, domain=pe.NonNegativeReals, mutable=True)

    # Kombinationen
    model.kappa_ub = pe.Param(model.G, model.J, default=0, domain=pe.Binary)
    model.beta_ub = pe.Param(model.J, model.H, default=0, domain=pe.Binary)
    model.gamma_ub = pe.Param(model.H, model.S, default=0, domain=pe.Binary)
    model.delta_ub = pe.Param(model.J, model.V, default=0, domain=pe.Binary)
    model.tau_ub = pe.Param(model.J, model.P, default=0, domain=pe.Binary)

    # Zuordnungen
    model.upsilon_tilde = pe.Param(model.G,
                                   model.Q,
                                   default=0,
                                   domain=pe.Binary)
    model.lambda_tilde = pe.Param(model.I,
                                  model.G,
                                  default=0,
                                  domain=pe.Binary)

    # Richtung der Güte
    model.ny = pe.Param(model.Q, default=0, domain=pe.Binary)
    model.ny_invers = pe.Param(model.Q, default=0, domain=pe.Binary)

    def upsilon_ny_init(model, g, q):
        return model.upsilon_tilde[g, q] * model.ny[q]

    model.upsilon_ny = pe.Param(model.G,
                                model.Q,
                                default=0,
                                initialize=upsilon_ny_init,
                                domain=pe.Binary)

    def upsilon_ny_invers_init(model, g, q):
        return model.upsilon_tilde[g, q] * model.ny_invers[q]

    model.upsilon_ny_invers = pe.Param(model.G,
                                       model.Q,
                                       default=0,
                                       initialize=upsilon_ny_invers_init,
                                       domain=pe.Binary)
    # Kostensätze

    model.K_hat_J = pe.Param(model.J, default=0, domain=pe.NonNegativeReals)
    model.k_hat_J = pe.Param(model.J, default=0, domain=pe.NonNegativeReals)
    model.k_var_J = pe.Param(model.G,
                             model.J,
                             default=0,
                             domain=pe.NonNegativeReals)  # (z_g)

    model.K_hat_H = pe.Param(model.H, default=0, domain=pe.NonNegativeReals)
    model.k_hat_H = pe.Param(model.H, default=0, domain=pe.NonNegativeReals)
    model.k_var_H = pe.Param(model.G,
                             model.H,
                             default=0,
                             domain=pe.NonNegativeReals)  # time active

    model.K_hat_S = pe.Param(model.S, default=0, domain=pe.NonNegativeReals)
    model.k_hat_S = pe.Param(model.S, default=0, domain=pe.NonNegativeReals)
    model.k_var_S = pe.Param(model.G,
                             model.S,
                             default=0,
                             domain=pe.NonNegativeReals)  # time active

    model.k_var_P = pe.Param(model.P, default=0, domain=pe.NonNegativeReals)

    # DataQuality Beschränkungen
    model.z_ub = pe.Param(model.G, default=0, domain=pe.NonNegativeReals)
    model.z_lb = pe.Param(model.G, default=0, domain=pe.NonNegativeReals)
    model.z_J_lb = pe.Param(model.G,
                            model.J,
                            default=0,
                            domain=pe.NonNegativeReals)
    model.z_J_ub = pe.Param(model.G,
                            model.J,
                            default=0,
                            domain=pe.NonNegativeReals)

    def z_DQ_ub_init(model, g):
        return min(model.z_ub[g], max(model.z_J_ub[g, j] for j in model.J))

    model.z_DQ_ub = pe.Param(model.G,
                             default=0,
                             initialize=z_DQ_ub_init,
                             domain=pe.NonNegativeReals)

    def z_DQ_lb_init(model, g):
        return max(model.z_lb[g], min(model.z_J_lb[g, j] for j in model.J))

    model.z_DQ_lb = pe.Param(model.G,
                             default=0,
                             initialize=z_DQ_lb_init,
                             domain=pe.NonNegativeReals)

    # Gewichte
    model.w = pe.Param(model.G, default=0, domain=pe.NonNegativeReals)

    def w_init(model, g):  # Normierung
        return model.w[g] / sum(model.w[g] for g in model.G)

    model.w_norm = pe.Param(model.G,
                            default=0,
                            initialize=w_init,
                            domain=pe.NonNegativeReals)

    # Arbeitszeit
    model.t_tilde = pe.Param(model.J,
                             model.P,
                             default=0,
                             domain=pe.NonNegativeReals)  # min
    model.t_ub = pe.Param(model.P, default=8 * 60,
                          domain=pe.NonNegativeReals)  # min

    # Temperaturen
    model.theta_V_ub = pe.Param(model.V, default=30,
                                domain=pe.Integers)  # constr. if not None
    model.theta_V_lb = pe.Param(model.V, default=20, domain=pe.Integers)
    model.theta_J_ub = pe.Param(model.J, default=1000000, domain=pe.Integers)
    model.theta_J_lb = pe.Param(model.J, default=-275, domain=pe.Integers)

    # Bandbreiten
    model.r = pe.Param(model.Q, default=1, domain=pe.Reals)
    model.Hz = pe.Param(default=100)
    model.sec = pe.Param(default=101)

    def upsilon_r_init(model, g):
        return sum(model.upsilon_tilde[g, q] * model.r[q]
                   for q in model.Q_bild)

    model.upsilon_r = pe.Param(model.G,
                               domain=pe.Reals,
                               initialize=upsilon_r_init)
    model.R_J_base = pe.Param(model.J,
                              default=0,
                              domain=pe.NonNegativeIntegers)
    model.D_J_base = pe.Param(model.J,
                              default=0,
                              domain=pe.NonNegativeIntegers)

    model.R_H_ub = pe.Param(model.H,
                            default=10000000000,
                            domain=pe.NonNegativeReals)  #10GBit/s
    model.R_S_ub = pe.Param(model.S,
                            default=16000000000,
                            domain=pe.NonNegativeReals)  #2000MB/s

    ###########################################################################
    # Parameters for the Bitrate Function

    # 1-simple / 2-advanced
    model.R_J_func_type = pe.Param(default=1, mutable=True)

    ###########################################################################
    # Parameters for the Piecewise Linear Function for DataQualities

    # 1-linear / 2-quadratic / 3-cubic / etc
    model.func_factor_DQ = pe.Param(model.G,
                                    default=func_factor_DQ,
                                    mutable=True)

    model.translate_repn = {
        0: 'BIGM_SOS1',
        1: 'BIGM_BIN',
        2: 'SOS2',
        3: 'CC',
        4: 'DCC',
        5: 'DLOG',
        6: 'LOG',
        7: 'MC',
        8: 'INC',
        None: None
    }

    model.translate_constr = {0: 'UB', 1: 'LB', 2: 'EQ', None: None}

    model.repn_DQ = repn_DQ
    model.constr_DQ = constr_DQ

    # Number of Breakpoints
    def shift_bit_length(x):
        """Computes the next power of two::
        
            (2^n)
        """
        return (1 << (x - 1).bit_length())

    if repn_DQ == 5 or repn_DQ == 6:
        PieceCnt_DQ = shift_bit_length(PieceCnt_DQ) - 1  # -1 for next use
        print("PieceCnt_DQ has been shifted to next (2^n)+1:", PieceCnt_DQ + 2)

    model.PieceCnt_DQ = PieceCnt_DQ

    ###########################################################################

    ############
    # Variablen
    ############
    # Base Binary

    def z_bounds(model, g):
        return (model.z_lb[g], model.z_ub[g])

    model.z = pe.Var(model.G, domain=pe.NonNegativeReals,
                     bounds=z_bounds)  # ???

    model.alpha = pe.Var(model.I, model.J, domain=pe.Binary)
    model.kappa = pe.Var(model.G, model.J, domain=pe.Binary)
    model.beta = pe.Var(model.J, model.H, domain=pe.Binary)
    model.gamma = pe.Var(model.H, model.S, domain=pe.Binary)
    model.delta = pe.Var(model.J, model.V, domain=pe.Binary)
    model.tau = pe.Var(model.J, model.P, domain=pe.Binary)
    model.a = pe.Var(model.J, domain=pe.Binary)
    model.b = pe.Var(model.H, domain=pe.Binary)
    model.c = pe.Var(model.S, domain=pe.Binary)
    model.d = pe.Var(model.P, domain=pe.Binary)

    # Help Binary
    model.a_beta = pe.Var(model.J, model.H, domain=pe.Binary)
    model.b_gamma = pe.Var(model.H, model.S, domain=pe.Binary)
    model.a_tau = pe.Var(model.J, model.P, domain=pe.Binary)
    model.xi = pe.Var(model.J, domain=pe.Binary)
    model.a_xi = pe.Var(model.J, domain=pe.Binary)

    # Help Binary/Real
    model.z_kappa = pe.Var(model.G, model.J, domain=pe.NonNegativeReals)
    model.R_J_a_beta = pe.Var(model.J, model.H, domain=pe.NonNegativeReals)
    model.R_H_b_gamma = pe.Var(model.H, model.S, domain=pe.NonNegativeReals)

    # Help Others
    model.R_J = pe.Var(model.J, domain=pe.NonNegativeReals)
    model.R_H = pe.Var(model.H, domain=pe.NonNegativeReals)
    model.R_S = pe.Var(model.S, domain=pe.NonNegativeReals)
    model.K_J = pe.Var(model.J, domain=pe.NonNegativeReals)
    model.K_H = pe.Var(model.H, domain=pe.NonNegativeReals)
    model.K_S = pe.Var(model.S, domain=pe.NonNegativeReals)
    model.K_P = pe.Var(model.P, domain=pe.NonNegativeReals)
    model.Costs_J = pe.Var(domain=pe.NonNegativeReals)
    model.Costs_H = pe.Var(domain=pe.NonNegativeReals)
    model.Costs_S = pe.Var(domain=pe.NonNegativeReals)
    model.Costs_P = pe.Var(domain=pe.NonNegativeReals)
    model.Costs_ges = pe.Var(domain=pe.NonNegativeReals)
    model.DQ = pe.Var(model.G, domain=pe.NonNegativeReals)
    model.DQ_ges = pe.Var(domain=pe.NonNegativeReals)
    model.K_J_a = pe.Var(model.J, domain=pe.NonNegativeReals)
    model.K_H_b = pe.Var(model.H, domain=pe.NonNegativeReals)
    model.K_S_c = pe.Var(model.S, domain=pe.NonNegativeReals)
    model.K_P_d = pe.Var(model.P, domain=pe.NonNegativeReals)
    model.t = pe.Var(model.P, domain=pe.NonNegativeReals)

    def R_J_ub_init(model, j):  # !!!
        if pe.value(model.R_J_func_type) == 1:
            return (model.R_J_base[j] + (sum(
                model.z_ub[g] * model.upsilon_tilde[g, pe.value(model.Hz)] *
                (model.D_J_base[j]) + (1 / model.z_lb[g]) *
                model.upsilon_tilde[g, pe.value(model.sec)] *
                (model.D_J_base[j]) for g in model.G)) / 1000 + 1)
        if pe.value(model.R_J_func_type) is 2:
            return (
                model.R_J_base[j] +
                sum(model.z_J_ub[g, j] *
                    model.upsilon_tilde[g, pe.value(model.Hz)] * (
                        model.D_J_base[j] + pe.prod(model.z_J_ub[g, j]  #!!!
                                                    * model.upsilon_r[g]
                                                    for g in model.G)) +
                    (1 / model.z_J_lb[g, j]) *
                    model.upsilon_tilde[g, pe.value(model.sec)] * (
                        model.D_J_base[j] + pe.prod(model.z_J_ub[g, j]  #!!!
                                                    * model.upsilon_r[g]
                                                    for g in model.G))
                    for g in model.G) / 1000 + 1)

    model.R_J_ub = pe.Param(model.J, default=1e10,
                            initialize=R_J_ub_init)  # !!!

    def K_J_ub_init(model, j):
        return (model.K_hat_J[j] + model.n * (model.k_hat_J[j]) +
                sum(model.z_ub[g] * model.k_var_J[g, j] for g in model.G))

    model.K_J_ub = pe.Param(model.J,
                            domain=pe.PositiveReals,
                            initialize=K_J_ub_init)

    def K_H_ub_init(model, h):
        return (model.K_hat_H[h] + model.n * model.k_hat_H[h] + 1)

    model.K_H_ub = pe.Param(model.H, domain=pe.PositiveReals, rule=K_H_ub_init)

    def K_S_ub_init(model, s):
        return (model.K_hat_S[s] + model.n * model.k_hat_S[s] + 1)

    model.K_S_ub = pe.Param(model.S,
                            domain=pe.PositiveReals,
                            initialize=K_S_ub_init)

    def K_P_ub_init(model,
                    p):  # Achtung hier werden Min in Stunden umgerechnet
        return (model.n * model.t_ub[p] / 60 * model.k_var_P[p] + 1)  #!!!

    model.K_P_ub = pe.Param(model.P,
                            domain=pe.PositiveReals,
                            initialize=K_P_ub_init)

    # Binary Operations

    def Constrain_a_beta_1_rule(model, j, h):
        return model.a_beta[j, h] <= model.a[j]

    model.Constrain_a_beta_1 = pe.Constraint(model.J,
                                             model.H,
                                             rule=Constrain_a_beta_1_rule)

    def Constrain_a_beta_2_rule(model, j, h):
        return model.a_beta[j, h] <= model.beta[j, h]

    model.Constrain_a_beta_2 = pe.Constraint(model.J,
                                             model.H,
                                             rule=Constrain_a_beta_2_rule)

    def Constrain_a_beta_3_rule(model, j, h):
        return model.a_beta[j, h] >= (model.a[j] + model.beta[j, h] - 1)

    model.Constrain_a_beta_3 = pe.Constraint(model.J,
                                             model.H,
                                             rule=Constrain_a_beta_3_rule)

    def Constrain_b_gamma_1_rule(model, h, s):
        return model.b_gamma[h, s] <= model.b[h]

    model.Constrain_b_gamma_1 = pe.Constraint(model.H,
                                              model.S,
                                              rule=Constrain_b_gamma_1_rule)

    def Constrain_b_gamma_2_rule(model, h, s):
        return model.b_gamma[h, s] <= model.gamma[h, s]

    model.Constrain_b_gamma_2 = pe.Constraint(model.H,
                                              model.S,
                                              rule=Constrain_b_gamma_2_rule)

    def Constrain_b_gamma_3_rule(model, h, s):
        return model.b_gamma[h, s] >= model.b[h] + model.gamma[h, s] - 1

    model.Constrain_b_gamma_3 = pe.Constraint(model.H,
                                              model.S,
                                              rule=Constrain_b_gamma_3_rule)

    def Constrain_a_tau_1_rule(model, j, p):
        return model.a_tau[j, p] <= model.a[j]

    model.Constrain_a_tau_1 = pe.Constraint(model.J,
                                            model.P,
                                            rule=Constrain_a_tau_1_rule)

    def Constrain_a_tau_2_rule(model, j, p):
        return model.a_tau[j, p] <= model.tau[j, p]

    model.Constrain_a_tau_2 = pe.Constraint(model.J,
                                            model.P,
                                            rule=Constrain_a_tau_2_rule)

    def Constrain_a_tau_3_rule(model, j, p):
        return model.a_tau[j, p] >= model.a[j] + model.tau[j, p] - 1

    model.Constrain_a_tau_3 = pe.Constraint(model.J,
                                            model.P,
                                            rule=Constrain_a_tau_3_rule)

    ###########################################################################
    #
    # Constraints
    #

    #==============================================================================

    def Constrain_alpha_BigM_rule(model, i, j):
        """
        .. math::

            \\tilde{\\lambda}_{gj} \\wedge \\kappa_{gj} = 1 \\Rightarrow \\alpha_{ij} = 1
        """
        return (sum(model.lambda_tilde[i, g] * model.kappa[g, j]
                    for g in model.G) - model.alpha[i, j] *
                (len(model.I) + len(model.G)) <= 0)

    model.Constrain_alpha_BigM = pe.Constraint(model.I,
                                               model.J,
                                               rule=Constrain_alpha_BigM_rule)

    def Constrain_alpha_smallm_rule(model, i, j):
        return (sum(model.lambda_tilde[i, g] * model.kappa[g, j]
                    for g in model.G) - model.alpha[i, j] * 1 >= 0)

    model.Constrain_alpha_smallm = pe.Constraint(
        model.I, model.J, rule=Constrain_alpha_smallm_rule)

    def Constrain_alpha_rule(model, i):
        return sum(model.alpha[i, j] for j in model.J) <= 1

    model.Constrain_alpha = pe.Constraint(model.I, rule=Constrain_alpha_rule)

    def Constrain_a_BigM_rule(model, j):
        return sum(
            model.kappa[g, j]
            for g in model.G) - model.a[j] * (len(model.J) + len(model.G)) <= 0

    model.Constrain_a_BigM = pe.Constraint(model.J, rule=Constrain_a_BigM_rule)

    def Constrain_a_smallm_rule(model, j):
        return sum(model.kappa[g, j] for g in model.G) - model.a[j] * 1 >= 0

    model.Constrain_a_smallm = pe.Constraint(model.J,
                                             rule=Constrain_a_smallm_rule)

    def Constrain_b_BigM_rule(model, h):
        return sum(
            model.a_beta[j, h]
            for j in model.J) - model.b[h] * (len(model.H) + len(model.J)) <= 0

    model.Constrain_b_BigM = pe.Constraint(model.H, rule=Constrain_b_BigM_rule)

    def Constrain_b_smallm_rule(model, h):
        return sum(model.a_beta[j, h] for j in model.J) - model.b[h] * 1 >= 0

    model.Constrain_b_smallm = pe.Constraint(model.H,
                                             rule=Constrain_b_smallm_rule)

    def Constrain_c_BigM_rule(model, s):
        return sum(
            model.b_gamma[h, s]
            for h in model.H) - model.c[s] * (len(model.S) + len(model.H)) <= 0

    model.Constrain_c_BigM = pe.Constraint(model.S, rule=Constrain_c_BigM_rule)

    def Constrain_c_smallm_rule(model, s):
        return sum(model.b_gamma[h, s] for h in model.H) - model.c[s] * 1 >= 0

    model.Constrain_c_smallm = pe.Constraint(model.S,
                                             rule=Constrain_c_smallm_rule)

    def Constrain_d_BigM_rule(model, p):
        return sum(
            model.a_tau[j, p]
            for j in model.J) - model.d[p] * (len(model.P) + len(model.J)) <= 0

    model.Constrain_d_BigM = pe.Constraint(model.P, rule=Constrain_d_BigM_rule)

    def Constrain_d_smallm_rule(model, p):
        return sum(model.a_tau[j, p] for j in model.J) - model.d[p] * 1 >= 0

    model.Constrain_d_smallm = pe.Constraint(model.P,
                                             rule=Constrain_d_smallm_rule)

    #==============================================================================

    #  # Max min Dataquality
    # Einführung von Hilfsvariablen zur Linearisierung

    def Constrain_z_kappa_1_rule(model, g, j):
        return model.z_kappa[g, j] <= model.kappa[g, j] * model.z_ub[g]

    model.Constrain_z_kappa_1 = pe.Constraint(model.G,
                                              model.J,
                                              rule=Constrain_z_kappa_1_rule)

    def Constrain_z_kappa_2_rule(model, g, j):
        return model.z_kappa[g, j] <= model.z[g]

    model.Constrain_z_kappa_2 = pe.Constraint(model.G,
                                              model.J,
                                              rule=Constrain_z_kappa_2_rule)

    def Constrain_z_kappa_3_rule(model, g, j):
        return model.z_kappa[
            g, j] >= model.z[g] - (1 - model.kappa[g, j]) * model.z_ub[g]

    model.Constrain_z_kappa_3 = pe.Constraint(model.G,
                                              model.J,
                                              rule=Constrain_z_kappa_3_rule)

    # Beschränkung Datenqualität lokal
    def ConstrainLocalDQ_ub_rule(model, g, j):  # DQ Upper bound local
        return model.z_kappa[g, j] <= model.kappa[g, j] * model.z_J_ub[g, j]

    model.ConstrainLocalDQ_ub = pe.Constraint(model.G,
                                              model.J,
                                              rule=ConstrainLocalDQ_ub_rule)

    def ConstrainLocalDQ_lb_rule(model, g, j):  # DQ Lower bound local
        return model.z_kappa[g, j] >= model.kappa[g, j] * model.z_J_lb[g, j]

    model.ConstrainLocalDQ_lb = pe.Constraint(model.G,
                                              model.J,
                                              rule=ConstrainLocalDQ_lb_rule)

    # Beschränkung Datenqualität global
    def ConstrainGlobalDQ_ub_rule(model, g):  # DQ upper bound global
        return model.z[g] <= model.z_ub[g]

    model.ConstrainGlobalDQ_ub = pe.Constraint(model.G,
                                               rule=ConstrainGlobalDQ_ub_rule)

    def ConstrainGlobalDQ_lb_rule(model, g):  # DQ lower bound global
        return model.z[g] >= model.z_lb[g]

    model.ConstrainGlobalDQ_lb = pe.Constraint(model.G,
                                               rule=ConstrainGlobalDQ_lb_rule)

    #==============================================================================

    # Gültige Kombinationen
    def ConstrainPossibleCombinations_kappa_rule(model, x, y):
        return model.kappa[x, y] <= model.kappa_ub[x, y]

    model.ConstraintPossibleCombinations_kappa = pe.Constraint(
        model.G, model.J, rule=ConstrainPossibleCombinations_kappa_rule)

    def ConstrainPossibleCombinations_beta_rule(model, x, y):
        return model.beta[x, y] <= model.beta_ub[x, y]

    model.ConstraintPossibleCombinations_beta = pe.Constraint(
        model.J, model.H, rule=ConstrainPossibleCombinations_beta_rule)

    def ConstrainPossibleCombinations_gamma_rule(model, x, y):
        return model.gamma[x, y] <= model.gamma_ub[x, y]

    model.ConstraintPossibleCombinations_gamma = pe.Constraint(
        model.H, model.S, rule=ConstrainPossibleCombinations_gamma_rule)

    def ConstrainPossibleCombinations_delta_rule(model, x, y):
        return model.delta[x, y] <= model.delta_ub[x, y]

    model.ConstraintPossibleCombinations_delta = pe.Constraint(
        model.J, model.V, rule=ConstrainPossibleCombinations_delta_rule)

    def ConstrainPossibleCombinations_tau_rule(model, x, y):
        return model.tau[x, y] <= model.tau_ub[x, y]

    model.ConstraintPossibleCombinations_tau = pe.Constraint(
        model.J, model.P, rule=ConstrainPossibleCombinations_tau_rule)

    #==============================================================================
    # x pro y
    # def ConstrainMethodsPerDQ_rule(model, g):
    #         return sum(model.kappa[g, j] for j in model.J) == 1  #model.kappa_sum_zul  # ???
    # model.ConstrainMethodsPerDQ = pe.Constraint(
    #         model.G, rule=ConstrainMethodsPerDQ_rule)
    # def ConstrainMethodsPerDQ_rule(model, g):
    #         return sum(pe.sumproduct(model.lambda_tilde,model.kappa) for j in model.J == 1  #model.kappa_sum_zul  # ???
    # model.ConstrainMethodsPerDQ = pe.Constraint(
    #         model.G, rule=ConstrainMethodsPerDQ_rule)

    def ConstrainMethodsPerDQ_smallm_rule(model, g):
        return sum(model.kappa[g, j] for j in model.J) >= 0.5  # ???

    model.ConstrainMethodsPerDQ_smallm = pe.Constraint(
        model.G, rule=ConstrainMethodsPerDQ_smallm_rule)

    #def ConstrainMethodsPerDQ_smallm_rule(model):
    #        return sum(sum(model.kappa[g, j] for j in model.J) for g in model.G) >= 1  # ???
    #model.ConstrainMethodsPerDQ_smallm = pe.Constraint(
    #       rule=ConstrainMethodsPerDQ_smallm_rule)

    def ConstrainTransfersPerMethod_rule(model, j):
        return sum(model.beta[j, h] for h in model.H) <= model.beta_sum_zul

    model.ConstrainTransfersPerMethod = pe.Constraint(
        model.J, rule=ConstrainTransfersPerMethod_rule)

    def ConstrainMinTransfersPerMethod_rule(model, j):
        return sum(model.beta[j, h] for h in model.H) - 1 >= (model.a[j] - 1)

    model.ConstrainMinTransfersPerMethod = pe.Constraint(
        model.J, rule=ConstrainMinTransfersPerMethod_rule)

    def ConstrainStoragesPerTransfers_rule(model, h):
        return sum(model.gamma[h, s] for s in model.S) <= model.gamma_sum_zul

    model.ConstrainStoragesPerTransfers = pe.Constraint(
        model.H, rule=ConstrainStoragesPerTransfers_rule)

    def ConstrainMinStoragesPerTransfers_rule(model, h):
        return sum(model.gamma[h, s] for s in model.S) - 1 >= (model.b[h] - 1)

    model.ConstrainMinStoragesPerTransfers = pe.Constraint(
        model.H, rule=ConstrainMinStoragesPerTransfers_rule)

    def ConstrainMethodPerPosition_rule(model, v):
        return sum(model.delta[j, v] for j in model.J) <= model.delta_sum_zul

    model.ConstrainMethodPerPosition = pe.Constraint(
        model.V, rule=ConstrainMethodPerPosition_rule)

    #def ConstrainMinMethodPerPosition_rule(model, v):
    #    return sum(model.delta[j, v] for j in model.J) - 1 >= (model.d[v] - 1)
    #model.ConstrainMinMethodPerPosition = pe.Constraint(
    #        model.V, rule=ConstrainMinMethodPerPosition_rule)

    def ConstrainPersonPerMethod_rule(model, j):
        return sum(model.tau[j, p] for p in model.P) <= model.tau_sum_zul

    model.ConstrainPersonPerMethod = pe.Constraint(
        model.J, rule=ConstrainPersonPerMethod_rule)

    #==============================================================================

    # Temperatures
    def ConstrainMaxTheta_rule(model, j, v):
        return model.delta[j, v] * model.theta_J_ub[j] >= model.delta[
            j, v] * model.theta_V_ub[v]

    model.ConstrainMaxTheta = pe.Constraint(model.J,
                                            model.V,
                                            rule=ConstrainMaxTheta_rule)

    def ConstrainMinTheta_rule(model, j, v):
        return model.delta[j, v] * model.theta_J_lb[j] <= model.delta[
            j, v] * model.theta_V_lb[v]

    model.ConstrainMinTheta = pe.Constraint(model.J,
                                            model.V,
                                            rule=ConstrainMinTheta_rule)

    #==============================================================================

    # Personalzeiten
    # Berechnung xi "Sollte eine Person benötigt werden?"
    def Constrain_bigM_xi_rule(model, j):
        return sum(model.tau_ub[j, p]
                   for p in model.P) - len(model.P) * model.xi[j] <= 0

    model.Constrain_bigM_xi = pe.Constraint(model.J,
                                            rule=Constrain_bigM_xi_rule)

    def Constrain_smallm_xi_rule(model, j):
        return sum(model.tau_ub[j, p] for p in model.P) - 1 * model.xi[j] >= 0

    model.Constrain_smallm_xi = pe.Constraint(model.J,
                                              rule=Constrain_smallm_xi_rule)

    # Berechnung a_xi "Wird eine Person wirklich benötigt?"
    def Constrain_a_xi_1_rule(model, j):
        return model.a_xi[j] <= model.a[j]

    model.Constrain_a_xi_1 = pe.Constraint(model.J, rule=Constrain_a_xi_1_rule)

    def Constrain_a_xi_2_rule(model, j):
        return model.a_xi[j] <= model.xi[j]

    model.Constrain_a_xi_2 = pe.Constraint(model.J, rule=Constrain_a_xi_2_rule)

    def Constrain_a_xi_3_rule(model, j):
        return model.a_xi[j] >= model.a[j] + model.xi[j] - 1

    model.Constrain_a_xi_3 = pe.Constraint(model.J, rule=Constrain_a_xi_3_rule)

    # wenn a_xi = 1 -> sum(tau[j, p] for p in model.P) >= 1 "Min 1 Person muss ran"
    def Constrain_sumtau_smallm_rule(model, j):
        return sum(model.a_tau[j, p] for p in model.P) - model.a_xi[j] * 1 >= 0

    model.Constrain_sumtau_smallm = pe.Constraint(
        model.J, rule=Constrain_sumtau_smallm_rule)

    def Compute_t_rule(model, p):  # Berechne Zeit pro Person
        return model.t[p] - sum(model.a_tau[j, p] * model.t_tilde[j, p]
                                for j in model.J) == 0

    model.Compute_t = pe.Constraint(model.P, rule=Compute_t_rule)

    def ConstrainPersonalWorkTimes_rule(model,
                                        p):  # Zeitrestriktion pro Person
        return model.t[p] <= model.t_ub[p]

    model.ConstrainPersonalWorkTimes = pe.Constraint(
        model.P, rule=ConstrainPersonalWorkTimes_rule)

    #==============================================================================

    # Bitrates

    def Compute_R_J_rule(model, j):
        if pe.value(model.R_J_func_type) == 1:
            return (model.R_J[j] == model.R_J_base[j] +
                    (sum(model.z_kappa[g, j] *
                         model.upsilon_tilde[g, pe.value(model.Hz)] *
                         (model.D_J_base[j]) + (1 / model.z_kappa[g, j]) *
                         model.upsilon_tilde[g, pe.value(model.sec)] *
                         (model.D_J_base[j]) for g in model.G)) / 1000)
        if pe.value(model.R_J_func_type) is 2:
            return (
                model.R_J[j] == model.R_J_base[j] +
                sum(model.z_kappa[g, j] *
                    model.upsilon_tilde[g, pe.value(model.Hz)] * (
                        model.D_J_base[j] + pe.prod(model.z_kappa[g, j]  #!!!
                                                    * model.upsilon_r[g]
                                                    for g in model.G)) +
                    (1 / model.z_kappa[g, j]) *
                    model.upsilon_tilde[g, pe.value(model.sec)] * (
                        model.D_J_base[j] + pe.prod(model.z_kappa[g, j]  #!!!
                                                    * model.upsilon_r[g]
                                                    for g in model.G))
                    for g in model.G) / 1000)

    model.Compute_R_J = pe.Constraint(model.J, rule=Compute_R_J_rule)

    # Linearisierung R_J_a_beta = a_beta * R_J
    def Constrain_R_J_a_beta_1_rule(model, j, h):
        return model.R_J_a_beta[
            j, h] <= model.a_beta[j, h] * model.R_J_ub[j]  # !!!

    model.Constrain_R_J_a_beta_1 = pe.Constraint(
        model.J, model.H, rule=Constrain_R_J_a_beta_1_rule)

    def Constrain_R_J_a_beta_2_rule(model, j, h):
        return model.R_J_a_beta[j, h] <= model.R_J[j]

    model.Constrain_R_J_a_beta_2 = pe.Constraint(
        model.J, model.H, rule=Constrain_R_J_a_beta_2_rule)

    def Constrain_R_J_a_beta_3_rule(model, j, h):
        return model.R_J_a_beta[j, h] >= model.R_J[j] - (
            1 - model.a_beta[j, h]) * model.R_J_ub[j]  # !!!

    model.Constrain_R_J_a_beta_3 = pe.Constraint(
        model.J, model.H, rule=Constrain_R_J_a_beta_3_rule)

    # Constraint for Transfer Rates
    def Compute_R_H_rule(model, h):
        return model.R_H[h] - sum(model.R_J_a_beta[j, h] for j in model.J) == 0

    model.Compute_R_H = pe.Constraint(model.H, rule=Compute_R_H_rule)

    def Constrain_R_H_rule(model, j, h):
        return model.R_H[h] <= model.R_H_ub[h]

    model.Constrain_R_H = pe.Constraint(model.J,
                                        model.H,
                                        rule=Constrain_R_H_rule)

    # Linearisierung R_H_b_gamma = b_gamma * R_H
    def Constrain_R_H_b_gamma_1_rule(model, h, s):
        return model.R_H_b_gamma[
            h, s] <= model.b_gamma[h, s] * model.R_H_ub[h]  # !!!

    model.Constrain_R_H_b_gamma_1 = pe.Constraint(
        model.H, model.S, rule=Constrain_R_H_b_gamma_1_rule)

    def Constrain_R_H_b_gamma_2_rule(model, h, s):
        return model.R_H_b_gamma[h, s] <= model.R_H[h]

    model.Constrain_R_H_b_gamma_2 = pe.Constraint(
        model.H, model.S, rule=Constrain_R_H_b_gamma_2_rule)

    def Constrain_R_H_b_gamma_3_rule(model, h, s):
        return model.R_H_b_gamma[h, s] >= model.R_H[h] - (
            1 - model.b_gamma[h, s]) * model.R_H_ub[h]  # !!!

    model.Constrain_R_H_b_gamma_3 = pe.Constraint(
        model.H, model.S, rule=Constrain_R_H_b_gamma_3_rule)

    # Constraint for Storage Rates
    def Compute_R_S_rule(model, s):
        return model.R_S[s] - sum(model.R_H_b_gamma[h, s]
                                  for h in model.H) == 0

    model.Compute_R_S = pe.Constraint(model.S, rule=Compute_R_S_rule)

    def Constrain_R_S_rule(model, s):
        return model.R_S[s] <= model.R_S_ub[s]

    model.Constrain_R_S = pe.Constraint(model.S, rule=Constrain_R_S_rule)

    ###########################################################################

    # Funktionen Kosten

    # Kostenberechnungen

    def Compute_K_J_rule(model, j):
        return model.K_J[j] == (
            model.K_hat_J[j] + model.n * (model.k_hat_J[j])
            # + sum(model.z[g] * model.k_var_J[g,j] for g in model.G)
        )

    model.Compute_K_J = pe.Constraint(model.J, rule=Compute_K_J_rule)

    def Constrain_K_J_a_1_rule(model, j):
        return model.K_J_a[j] <= model.a[j] * model.K_J_ub[j]  # !!!

    model.Constrain_K_J_a_1 = pe.Constraint(model.J,
                                            rule=Constrain_K_J_a_1_rule)

    def Constrain_K_J_a_2_rule(model, j):
        return model.K_J_a[j] <= model.K_J[j]

    model.Constrain_K_J_a_2 = pe.Constraint(model.J,
                                            rule=Constrain_K_J_a_2_rule)

    def Constrain_K_J_a_3_rule(model, j):
        return model.K_J_a[j] >= model.K_J[j] - (
            1 - model.a[j]) * model.K_J_ub[j]  # !!!

    model.Constrain_K_J_a_3 = pe.Constraint(model.J,
                                            rule=Constrain_K_J_a_3_rule)

    # =============================================================================
    def Compute_K_H_rule(model, h):
        return model.K_H[h] == (model.K_hat_H[h] + model.n * model.k_hat_H[h])

    model.Compute_K_H = pe.Constraint(model.H, rule=Compute_K_H_rule)

    def Constrain_K_H_b_1_rule(model, h):
        return model.K_H_b[h] <= model.b[h] * model.K_H_ub[h]

    model.Constrain_K_H_b_1 = pe.Constraint(model.H,
                                            rule=Constrain_K_H_b_1_rule)

    def Constrain_K_H_b_2_rule(model, h):
        return model.K_H_b[h] <= model.K_H[h]

    model.Constrain_K_H_b_2 = pe.Constraint(model.H,
                                            rule=Constrain_K_H_b_2_rule)

    def Constrain_K_H_b_3_rule(model, h):
        return model.K_H_b[h] >= model.K_H[h] - (1 -
                                                 model.b[h]) * model.K_H_ub[h]

    model.Constrain_K_H_b_3 = pe.Constraint(model.H,
                                            rule=Constrain_K_H_b_3_rule)

    # =============================================================================
    def Compute_K_S_rule(model, s):
        return model.K_S[s] == (model.K_hat_S[s] + model.n * model.k_hat_S[s])

    model.Compute_K_S = pe.Constraint(model.S, rule=Compute_K_S_rule)

    def Constrain_K_S_c_1_rule(model, s):
        return model.K_S_c[s] <= model.c[s] * model.K_S_ub[s]

    model.Constrain_K_S_c_1 = pe.Constraint(model.S,
                                            rule=Constrain_K_S_c_1_rule)

    def Constrain_K_S_c_2_rule(model, s):
        return model.K_S_c[s] <= model.K_S[s]

    model.Constrain_K_S_c_2 = pe.Constraint(model.S,
                                            rule=Constrain_K_S_c_2_rule)

    def Constrain_K_S_c_3_rule(model, s):
        return model.K_S_c[s] >= model.K_S[s] - (1 -
                                                 model.c[s]) * model.K_S_ub[s]

    model.Constrain_K_S_c_3 = pe.Constraint(model.S,
                                            rule=Constrain_K_S_c_3_rule)

    # =============================================================================
    def Compute_K_P_rule(model,
                         p):  # Achtung hier werden Min in Stunden umgerechnet
        return model.K_P[p] == (model.n * model.t[p] / 60 * model.k_var_P[p]
                                )  #!!!

    model.Compute_K_P = pe.Constraint(model.P, rule=Compute_K_P_rule)

    def Constrain_K_P_d_1_rule(model, p):
        return model.K_P_d[p] <= model.d[p] * model.K_P_ub[p]

    model.Constrain_K_P_d_1 = pe.Constraint(model.P,
                                            rule=Constrain_K_P_d_1_rule)

    def Constrain_K_P_d_2_rule(model, p):
        return model.K_P_d[p] <= model.K_P[p]

    model.Constrain_K_P_d_2 = pe.Constraint(model.P,
                                            rule=Constrain_K_P_d_2_rule)

    def Constrain_K_P_d_3_rule(model, p):
        return model.K_P_d[p] >= model.K_P[p] - (1 -
                                                 model.d[p]) * model.K_P_ub[p]

    model.Constrain_K_P_d_3 = pe.Constraint(model.P,
                                            rule=Constrain_K_P_d_3_rule)

    #==============================================================================

    # Zielfunktion Kosten Sammler
    def ComputeCosts_J_rule(model):
        expcost = sum(model.K_J_a[j] for j in model.J)
        return model.Costs_J - expcost == 0.0

    model.ComputeCosts_J = pe.Constraint(rule=ComputeCosts_J_rule)

    def ComputeCosts_H_rule(model):
        expcost = sum(model.K_H_b[h] for h in model.H)
        return model.Costs_H - expcost == 0.0

    model.ComputeCosts_H = pe.Constraint(rule=ComputeCosts_H_rule)

    def ComputeCosts_S_rule(model):
        expcost = sum(model.K_S_c[s] for s in model.S)
        return model.Costs_S - expcost == 0.0

    model.ComputeCosts_S = pe.Constraint(rule=ComputeCosts_S_rule)

    def ComputeCosts_P_rule(model):
        expcost = sum(model.K_P_d[p] for p in model.P)
        return model.Costs_P - expcost == 0.0

    model.ComputeCosts_P = pe.Constraint(rule=ComputeCosts_P_rule)

    def ComputeCosts_ges_rule(model):
        return model.Costs_ges - (model.Costs_J + model.Costs_H +
                                  model.Costs_S + model.Costs_P) == 0

    model.ComputeCosts_ges = pe.Constraint(rule=ComputeCosts_ges_rule)

    ###########################################################################

    # Funktionen Datenqualität

    model.bpts_DQ = {}

    def bpts_DQ_build(model, g):
        model.bpts_DQ[g] = []
        for i in range(int(model.PieceCnt_DQ + 2)):
            (model.bpts_DQ[g].append((i**(pe.value(model.func_factor_DQ[g])) /
                                      (model.PieceCnt_DQ + 1)**
                                      (pe.value(model.func_factor_DQ[g]))) *
                                     (model.z_ub[g] - model.z_lb[g]) +
                                     model.z_lb[g]))

    # The object model.BuildBpts_DQ is not refered to again;
    # the only goal is to trigger the action at build time
    model.BuildBpts_DQ = pe.BuildAction(model.G, rule=bpts_DQ_build)

    def Compute_DQ_rule(model, g, z):
        return (sum(model.upsilon_ny[g, q] for q in model.Q) *
                ((z - pe.value(model.z_DQ_lb[g]))**
                 (1 / pe.value(model.func_factor_DQ[g]))) /
                ((pe.value(model.z_DQ_ub[g]) - pe.value(model.z_DQ_lb[g]))**
                 (1 / pe.value(model.func_factor_DQ[g]))) +
                sum(model.upsilon_ny_invers[g, q] for q in model.Q) *
                (1 - ((z - pe.value(model.z_DQ_lb[g]))**
                      (1 / pe.value(model.func_factor_DQ[g]))) /
                 ((pe.value(model.z_DQ_ub[g]) - pe.value(model.z_DQ_lb[g]))**
                  (1 / pe.value(model.func_factor_DQ[g])))))

    model.ComputePieces = pe.Piecewise(
        model.G,
        model.DQ,
        model.z,
        pw_pts=model.bpts_DQ,
        pw_repn=model.translate_repn[model.repn_DQ],
        pw_constr_type=model.translate_constr[model.constr_DQ],
        f_rule=Compute_DQ_rule)

    # Zielfunktion Datenqualität Sammler
    def Compute_DQ_ges_rule(model):
        return model.DQ_ges == (sum(model.w_norm[g] * model.DQ[g]
                                    for g in model.G))

    model.Compute_DQ_ges = pe.Constraint(rule=Compute_DQ_ges_rule)

    ###########################################################################

    # Zielfunktion Kosten Formel
    def Constrain_DQ_ges_max_rule(model):
        return model.DQ_ges <= model.DQ_ges_max

    model.Constrain_DQ_ges_max = pe.Constraint(rule=Constrain_DQ_ges_max_rule)

    def Constrain_DQ_ges_min_rule(model):
        return model.DQ_ges >= model.DQ_ges_min

    model.Constrain_DQ_ges_min = pe.Constraint(rule=Constrain_DQ_ges_min_rule)

    #
    #def CostValue_rule(model):
    #    return model.Costs_ges
    #model.CostValue = pe.Objective(rule=CostValue_rule, sense=1)

    def Constrain_Costs_ges_max_rule(model):
        return model.Costs_ges <= model.Costs_ges_max

    model.Constrain_Costs_ges_max = pe.Constraint(
        rule=Constrain_Costs_ges_max_rule)

    def Constrain_Costs_ges_min_rule(model):
        return model.Costs_ges >= model.Costs_ges_min

    model.Constrain_Costs_ges_min = pe.Constraint(
        rule=Constrain_Costs_ges_min_rule)

    # def Constrain_Costs_abs_rule(model):
    #     if pe.value(model.Costs_ges_abs) is 0:
    #         pe.Constraint.Skip
    #     return model.Costs_ges == model.Costs_ges_abs
    # model.Constrain_Costs_abs = pe.Constraint(rule=Constrain_Costs_abs_rule)
    #
    ## Zielfunktion Datenqualität Formel
    #def DQValue_rule(model):
    #    return model.DQ_ges     # Maximizing
    #model.DQValue = pe.Objective(rule=DQValue_rule, sense=-1)

    def obj_Combined_rule(model):
        return model.u * model.Costs_ges - (1 - model.u) * model.DQ_ges

    #    return model.u * (model.Costs_J + model.Costs_H + model.Costs_S + model.Costs_P) - (1-model.u) * model.DQ_ges
    model.CombinedValue = pe.Objective(rule=obj_Combined_rule, sense=1)

    return model
def create_model(preserve_total_values=False, preserve_peak_values=False):

    m = pe.AbstractModel()

    #===================================
    #             Options
    #===================================

    m.options = dict(preserve_total_values=preserve_total_values,
                     preserve_peak_values=preserve_peak_values)

    def _apply_options(m):
        '''
        BuildAction used to apply options by (de)activating 
        constraints and (un)fixing variables.
        '''
        if not m.options['preserve_total_values']:
            m.relative_error_upper.deactivate()
            m.relative_error_lower.deactivate()
        if not m.options['preserve_peak_values']:
            m.preserve_peak.deactivate()
            m.at_least_one_preserved.deactivate()
            m.w.fix(0)

    #===================================
    #           Model Parameters
    #===================================

    m.n_days = pe.Param(within=pe.PositiveIntegers, doc='''Number of days.''')

    m.n_clusters = pe.Param(within=pe.PositiveIntegers,
                            doc='''Number of clusters.''')

    m.n_extreme_days = pe.Param(within=pe.NonNegativeIntegers,
                                initialize=0,
                                doc='''Number of extreme days.''')

    #====================================#
    #                 Sets
    #====================================#

    m.Days = pe.RangeSet(m.n_days)

    m.Days_cross = pe.Set(
        initialize=m.Days * m.Days,
        doc='''Auxiliary Set. Cross-set between Days and Days.''')

    m.Properties = pe.Set(doc='''Properties considered''')

    #====================================#
    #            Parameters
    #====================================#

    m.distance = pe.Param(m.Days_cross)

    m.x_daily_tot = pe.Param(
        m.Properties,
        m.Days,
        doc='''Total value of each property on each day.''')

    m.x_daily_max = pe.Param(
        m.Properties,
        m.Days,
        mutable=True,  # used to prevent errors in constraints
        doc='''Max value of each property on each day.''')

    m.x_max = pe.Param(
        m.Properties,
        mutable=True,  # used to prevent errors in constraints
        doc='''Max overall values of each property.''')

    def _x_total(m, p):
        return sum(m.x_daily_tot[p, i] for i in m.Days)

    m.x_total = pe.Param(m.Properties,
                         initialize=_x_total,
                         doc='''Total value of each property.''')

    m.rel_tol = pe.Param(m.Properties,
                         doc='''Relative error accepted for each property.''')

    m.min_peak_share = pe.Param(
        m.Properties, doc='''Minimum share of peak to be represented.''')

    #====================================#
    #             Variables
    #====================================#

    m.z = pe.Var(m.Days_cross,
                 within=pe.Binary,
                 initialize=0,
                 doc='''1 iff object j is assigned to the cluster 
        whose representative element is object i.''')

    m.y = pe.Var(m.Days,
                 within=pe.Binary,
                 initialize=0,
                 doc='''1 iff object i is chosen as representative 
        of its cluster.''')

    #====================================#
    #         Auxiliary Variables
    #====================================#

    def _x_weight(m, i):
        '''
        Returns the weight assigned to day i.
        First term: number of days it represents.
        Second term: 1 iff day i is extreme.
        '''
        n_days_represented = sum(m.z[i, j] for j in m.Days)
        extreme = 1 - sum(m.z[k, i] for k in m.Days)

        return n_days_represented + extreme

    m.x_weight = pe.Expression(m.Days, rule=_x_weight, doc='''''')

    def _x_total_estimated(m, p):
        '''Total estimated value of property p.'''
        return sum(m.x_weight[i] * m.x_daily_tot[p, i] for i in m.Days)

    m.x_total_estimated = pe.Expression(m.Properties,
                                        rule=_x_total_estimated,
                                        doc='''''')

    def _chosen(m, i):
        '''Auxiliary. 1 iff day i is either typical or extreme.'''
        return m.y[i] + (1 - sum(m.z[j, i] for j in m.Days))

    m.chosen = pe.Expression(m.Days, rule=_chosen)

    m.w = pe.Var(m.Properties,
                 m.Days,
                 within=pe.Binary,
                 doc='''Binary, used to impose that at least one chosen days 
        has a peak larger than a given proportion of the real peak.''')

    #====================================#
    #             Constraints
    #====================================#

    def _total_representative_days(m):
        return sum(m.y[i] for i in m.Days) == m.n_clusters

    m.total_representative_days = pe.Constraint(
        rule=_total_representative_days,
        doc='''One representative day for each cluster.''')

    def _each_non_extreme_day_is_represented(m, j):
        return sum(m.z[i, j] for i in m.Days) <= 1

    m.each_non_extreme_day_is_represented = pe.Constraint(
        m.Days,
        rule=_each_non_extreme_day_is_represented,
        doc='''each day is represented by exactly 1 day 
        (without EDs)''')

    def _total_represented_days(m):
        return sum(m.z[ij] for ij in m.Days_cross) == \
            m.n_days - m.n_extreme_days

    m.total_represented_days = pe.Constraint(
        rule=_total_represented_days,
        doc='''All non-extreme days are represented.''')

    def _represented_by_representative(m, i, j):
        return m.z[i, j] <= m.y[i]

    m.represented_by_representative = pe.Constraint(
        m.Days_cross,
        rule=_represented_by_representative,
        doc='''Days can only be represented by 
        representative days.''')

    #===================================
    #       Auxiliary Constraints
    #===================================

    def _relative_error_upper(m, p):
        return m.x_total_estimated[p] <= \
            (1 + m.rel_tol[p]) * m.x_total[p]

    m.relative_error_upper = pe.Constraint(m.Properties,
                                           rule=_relative_error_upper,
                                           doc='''''')

    def _relative_error_lower(m, p):
        return m.x_total_estimated[p] >= \
            (1 - m.rel_tol[p]) * m.x_total[p]

    m.relative_error_lower = pe.Constraint(m.Properties,
                                           rule=_relative_error_lower,
                                           doc='''''')

    def _preserve_peak(m, p, i):
        return m.x_daily_max[p, i] * m.chosen[i] >= m.w[
            p, i] * m.min_peak_share[p] * m.x_max[p]

    m.preserve_peak = pe.Constraint(
        m.Properties,
        m.Days,
        rule=_preserve_peak,
        doc='''The day must be chosen and its max value
        must be larger than the overall peak.
        ''')

    def _at_least_one_preserved(m, p):
        return sum(m.w[p, i] for i in m.Days) >= 1

    m.at_least_one_preserved = pe.Constraint(
        m.Properties,
        rule=_at_least_one_preserved,
        doc='''Auxiliary. At least one of the days must 
        satisfy preserve_peak.''')

    def _represent_itself(m, i):
        return m.z[i, i] >= m.y[i]

    m.represent_itself = pe.Constraint(
        m.Days,
        rule=_represent_itself,
        doc='''Auxiliary. Prevents the model from cheating.''')

    #====================================#
    #           Objective Function
    #====================================#

    def _total_distance(m):
        return sum(m.distance[ij] * m.z[ij] for ij in m.Days_cross)

    m.minimize_total_distance = pe.Objective(
        rule=_total_distance,
        doc='''Mininimize total distance between days 
        of the same cluster.''')

    # apply options
    m.apply_options = pe.BuildAction(rule=_apply_options)

    return m
Ejemplo n.º 5
0
def shared_limit(model,
                 quantity,
                 limit_name,
                 components,
                 weights,
                 lower_limit=0,
                 upper_limit=None):
    r"""
    Adds a constraint to the given model that restricts
    the weighted sum of variables to a corridor.

    **The following constraints are build:**

      .. math::
        l_\mathrm{low} \le \sum v_i(t) \times w_i(t) \le l_\mathrm{up}
        \forall t

    Parameters
    ----------
    model : oemof.solph.Model
        Model to which the constraint is added.
    limit_name : string
        Name of the constraint to create
    quantity : pyomo.core.base.var.IndexedVar
        Shared Pyomo variable for all components of a type.
    components : list of components
        list of components of the same type
    weights : list of numeric values
        has to have the same length as the list of components
    lower_limit : numeric
        the lower limit
    upper_limit : numeric
        the lower limit

    Examples
    --------
    The constraint can e.g. be used to define a common storage
    that is shared between parties but that do not exchange
    energy on balance sheet.
    Thus, every party has their own bus and storage, respectively,
    to model the energy flow. However, as the physical storage is shared,
    it has a common limit.

    >>> import pandas as pd
    >>> from oemof import solph
    >>> date_time_index = pd.date_range('1/1/2012', periods=5, freq='H')
    >>> energysystem = solph.EnergySystem(timeindex=date_time_index)
    >>> b1 = solph.Bus(label="Party1Bus")
    >>> b2 = solph.Bus(label="Party2Bus")
    >>> storage1 = solph.components.GenericStorage(
    ...     label="Party1Storage",
    ...     nominal_storage_capacity=5,
    ...     inputs={b1: solph.Flow()},
    ...     outputs={b1: solph.Flow()})
    >>> storage2 = solph.components.GenericStorage(
    ...     label="Party2Storage",
    ...     nominal_storage_capacity=5,
    ...     inputs={b1: solph.Flow()},
    ...     outputs={b1: solph.Flow()})
    >>> energysystem.add(b1, b2, storage1, storage2)
    >>> components = [storage1, storage2]
    >>> model = solph.Model(energysystem)
    >>> solph.constraints.shared_limit(
    ...    model,
    ...    model.GenericStorageBlock.storage_content,
    ...    "limit_storage", components,
    ...    [1, 1], upper_limit=5)
    """

    setattr(model, limit_name, po.Var(model.TIMESTEPS))

    for t in model.TIMESTEPS:
        getattr(model, limit_name)[t].setlb(lower_limit)
        getattr(model, limit_name)[t].setub(upper_limit)

    weighted_sum_constraint = limit_name + "_constraint"

    def _weighted_sum_rule(m):
        for ts in m.TIMESTEPS:
            lhs = sum(quantity[c, ts] * w for c, w in zip(components, weights))
            rhs = getattr(model, limit_name)[ts]
            expr = (lhs == rhs)
            getattr(m, weighted_sum_constraint).add(ts, expr)

    setattr(model, weighted_sum_constraint,
            po.Constraint(model.TIMESTEPS, noruleinit=True))
    setattr(model, weighted_sum_constraint + "_build",
            po.BuildAction(rule=_weighted_sum_rule))
Ejemplo n.º 6
0
def limit_active_flow_count(model,
                            constraint_name,
                            flows,
                            lower_limit=0,
                            upper_limit=None):
    r"""
    Set limits (lower and/or upper) for the number of concurrently
    active NonConvex flows. The flows are given as a list.

    Total actual counts after optimization can be retrieved
    calling the :attr:`om.oemof.solph.Model.$(constraint_name)_count()`.

    Parameters
    ----------
    model: oemof.solph.Model
        Model to which constraints are added
    constraint_name: string
        name for the constraint
    flows: list of flows
        flows (have to be NonConvex) in the format [(in, out)]
    lower_limit: integer
        minimum number of active flows in the list
    upper_limit: integer
        maximum number of active flows in the list

    Returns
    -------
    the updated model

    Note
    ----
    Flow objects required to be NonConvex

    **Constraint:**

    .. math:: N_{X,min} \le \sum_{n \in F} X_n(t)
                        \le N_{X,max} \forall t \in T

    With `F` being the set of considered flows and
    `T` being the set of time steps.

    The symbols used are defined as follows
    (with Variables (V) and Parameters (P)):

    ================== ==== ===================================================
    math. symbol       type explanation
    ================== ==== ===================================================
    :math:`X_n(t)`     V    status (0 or 1) of the flow :math:`n`
                            at time step :math:`t`
    :math:`N_{X,min}`  P    lower_limit
    :math:`N_{X,max}`  P    lower_limit
    ================== ==== ===================================================
    """

    # number of concurrent active flows
    setattr(model, constraint_name, po.Var(model.TIMESTEPS))

    for t in model.TIMESTEPS:
        getattr(model, constraint_name)[t].setlb(lower_limit)
        getattr(model, constraint_name)[t].setub(upper_limit)

    attrname_constraint = constraint_name + "_constraint"

    def _flow_count_rule(m):
        for ts in m.TIMESTEPS:
            lhs = sum(m.NonConvexFlow.status[fi, fo, ts] for fi, fo in flows)
            rhs = getattr(model, constraint_name)[ts]
            expr = (lhs == rhs)
            if expr is not True:
                getattr(m, attrname_constraint).add(ts, expr)

    setattr(model, attrname_constraint,
            po.Constraint(model.TIMESTEPS, noruleinit=True))
    setattr(model, attrname_constraint + "_build",
            po.BuildAction(rule=_flow_count_rule))

    return model