def mga_objective(network, snapshots, direction, options):
    mga_variables = options['mga_variables']
    expr_list = []
    for i, variable in enumerate(mga_variables):
        if variable == 'transmission':
            expr_list.append(
                linexpr((direction[i], get_var(network, 'Link',
                                               'p_nom'))).sum())
        if variable == 'co2_emission':
            expr_list.append(
                linexpr((direction[i], get_var(
                    network, 'Generator', 'p').filter(network.generators.index[
                        network.generators.type == 'ocgt']))).sum().sum())
        elif variable == 'H2' or variable == 'battery':
            expr_list.append(
                linexpr((direction[i], get_var(
                    network, 'StorageUnit',
                    'p_nom').filter(network.storage_units.index[
                        network.storage_units.carrier == variable]))).sum())
        else:
            expr_list.append(
                linexpr(
                    (direction[i],
                     get_var(network, 'Generator',
                             'p_nom').filter(network.generators.index[
                                 network.generators.type == variable]))).sum())

    mga_obj = join_exprs(np.array(expr_list))
    write_objective(network, mga_obj)
def mga_constraint(network, snapshots, options):
    scale = 1e-6
    # This function creates the MGA constraint
    gen_capital_cost = linexpr((scale * network.generators.capital_cost,
                                get_var(network, 'Generator', 'p_nom'))).sum()
    gen_marginal_cost = linexpr((scale * network.generators.marginal_cost,
                                 get_var(network, 'Generator',
                                         'p'))).sum().sum()
    store_capital_cost = linexpr((scale * network.storage_units.capital_cost,
                                  get_var(network, 'StorageUnit',
                                          'p_nom'))).sum()
    link_capital_cost = linexpr(
        (scale * network.links.capital_cost, get_var(network, 'Link',
                                                     'p_nom'))).sum()
    # total system cost
    cost_scaled = join_exprs(
        np.array([
            gen_capital_cost, gen_marginal_cost, store_capital_cost,
            link_capital_cost
        ]))
    # MGA slack
    if options['mga_slack_type'] == 'percent':
        slack = network.old_objective * options[
            'mga_slack'] + network.old_objective
    elif options['mga_slack_type'] == 'fixed':
        slack = options['baseline_cost'] * options['mga_slack'] + options[
            'baseline_cost']

    define_constraints(network, cost_scaled, '<=', slack * scale,
                       'GlobalConstraint', 'MGA_constraint')
def netzbooster_constraints(n, snapshots):
    """
    add to the LOPF the additional Netzbooster constraints
    """

    # Define indices & parameters
    n.determine_network_topology()
    sub = n.sub_networks.at["0", "obj"]
    sub.calculate_PTDF()
    sub.calculate_BODF()

    snapshots = snapshots  #n.snapshots
    buses = sub.buses_i()
    lines = sub.lines_i()
    outages = [l for l in lines if "outage" in l]

    ptdf = pd.DataFrame(sub.PTDF, index=lines, columns=buses)
    lodf = pd.DataFrame(sub.BODF, index=lines, columns=lines)

    logger.info("define variables")

    # i = buses
    # t = snapshots
    # k = outages

    # P_i + >= 0
    define_variables(n, 0, inf, "Bus", "P_pos", axes=[buses])
    # P_i - >= 0
    define_variables(n, 0, inf, "Bus", "P_neg", axes=[buses])
    # p_{i,t,k} + >= 0
    define_variables(
        n,
        0,
        inf,
        "Bus",
        "p_pos",
        axes=[snapshots,
              pd.MultiIndex.from_product([buses, outages])])
    # p_{i,t,k} + >= 0
    define_variables(
        n,
        0,
        inf,
        "Bus",
        "p_neg",
        axes=[snapshots,
              pd.MultiIndex.from_product([buses, outages])])

    logger.info("define constraints")

    # # Define constraints

    # ########### p_pos(i,k,t) <= P_pos(i)  ##########
    P_pos_extend = expand_series(
        get_var(n, "Bus", "P_pos").loc[buses],
        snapshots).T.reindex(pd.MultiIndex.from_product([buses, outages]),
                             axis=1,
                             level=0)
    lhs_1 = linexpr((1, P_pos_extend[buses]),
                    (-1, get_var(n, "Bus", "p_pos").loc[snapshots, buses]))
    define_constraints(n, lhs_1, ">=", 0., "Bus", "UpLimitPos")

    # ######### p_neg(i,k,t) <= P_neg(i)  #########
    P_neg_extend = expand_series(
        get_var(n, "Bus", "P_neg").loc[buses],
        snapshots).T.reindex(pd.MultiIndex.from_product([buses, outages]),
                             axis=1,
                             level=0)
    lhs_2 = linexpr((1, P_neg_extend[buses]),
                    (-1, get_var(n, "Bus", "p_pos").loc[snapshots, buses]))

    define_constraints(n, lhs_2, ">=", 0., "Bus", "UpLimitNeg")

    # ######## sum(i, p_pos(i,k,t) - p_neg(i,k,t)) = 0  #########
    lhs_3 = linexpr((1, get_var(n, "Bus", "p_pos").loc[snapshots].groupby(
        level=1, axis=1).sum()), (-1, get_var(
            n, "Bus", "p_neg").loc[snapshots].groupby(level=1, axis=1).sum()))
    define_constraints(n, lhs_3, "==", 0., "Bus", "FlexBal")

    # ## |f(l,t) + LODF(l,k) * f(k,t) + sum_i (PTDF(l,i) * (p_neg(i,k, t) - p_pos(i,k, t)))| <= F(l)  ########
    # f(l,t) + LODF(l,k) * f(k,t) + sum_i (PTDF(l,i) * (p_neg(i,k, t) - p_pos(i,k, t))) <= F(l)

    # f(l,t) here: f pandas DataFrame(index=snapshots, columns=lines)
    f = get_var(n, "Line", "s")
    # F(l) -> line capacity for n.lines.s_nom_extendable=False
    F = n.lines.s_nom
    # p pos (index=snapshots, columns=[bus, outage])
    p_pos = get_var(n, "Bus", "p_pos")
    # p neg (index=snapshots, columns=[bus, outage])
    p_neg = get_var(n, "Bus", "p_neg")

    for k in outages:
        for l in lines.difference(pd.Index(
            [k])):  # all l except for outage line
            for t in snapshots:

                lhs = ''
                # sum_i (PTDF(l,i) * (p_neg(i,k, t) - p_pos(i,k, t)))
                v1 = linexpr(
                    (ptdf.loc[l], p_neg.loc[t].xs(
                        k, level=1)),  # sum_i (PTDF(l,i) * (p_neg(i,k, t))
                    (-1 * ptdf.loc[l], p_pos.loc[t].xs(k, level=1)
                     )  # sum_i (- PTDF(l,i) * (p_pos(i,k, t))
                )
                lhs += '\n' + join_exprs(v1.sum())

                # f(l,t) + LODF(l,k) * f(k,t)
                v = linexpr(
                    (1, f.loc[t, l]),  # f(l,t)
                    (lodf.loc[l, k], f.loc[t, k]))  # LODF(l,k) * f(k,t)

                lhs += '\n' + join_exprs(v)

                rhs = F.loc[l]

                define_constraints(n, lhs, "<=", rhs, "booster1",
                                   "capacity_limit")

                define_constraints(n, lhs, ">=", -rhs, "booster2",
                                   "capacity_limit2")