Exemple #1
0
def tie_bidirectional_link_p_nom(network, snapshots):

    if not hasattr(n.links, "reversed"):
        return

    ext_rev_links = network.links.loc[(network.links.reversed == True) & (
        network.links.p_nom_extendable == True)].index

    if len(ext_rev_links) == 0:
        return

    constraints = {
        lk: [
            [
                (1, network.model.link_p_nom[lk.split("-")[0]]),
                (-1, network.model.link_p_nom[lk]),
            ],
            "==",
            0.0,
        ]
        for lk in ext_rev_links
    }

    l_constraint(network.model, "bidirectional_link", constraints,
                 list(ext_rev_links))

    network.model.bidirectional_link.pprint()
Exemple #2
0
def prepare_model():

#     n = pypsa.Network("../../co2-analysis/results/new/postnetwork_heur125.nc")
    n = pypsa.Network(snakemake.input[0])
    
    # n = pypsa.Network("postnetwork_heur1.0.nc")
#     n = get_representative_snapshots(n, N_SNAPSHOTS)

    n.determine_network_topology()
    sub = n.sub_networks.at["0", "obj"]

    sub.calculate_PTDF()
    sub.calculate_BODF()

    # Define indices
    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")

    # define model
    m = ConcreteModel()

    # Define Variables
    # P_pos(i) >= 0
    m.P_pos = Var(buses, within=NonNegativeReals)

    # P_neg(i) >= 0
    m.P_neg = Var(buses, within=NonNegativeReals)

    # p_pos(i,l,t) >= 0
    m.p_pos = Var(buses, outages, snapshots, within=NonNegativeReals)

    # p_neg(i,l,t) >= 0
    m.p_neg = Var(buses, outages, snapshots, within=NonNegativeReals)

    logger.info("define constraints")

    # Define constraints
    ########### p_pos(i,k,t) <= P_pos(i)  ##########
    c1 = {(i, k, t):
          [[(1, m.p_pos[i, k, t]), (-1, m.P_pos[i])], "<=", 0.]
          for i in buses for k in outages for t in snapshots}

    l_constraint(m, "UpLimitPos", c1, buses, outages, snapshots)

    ######### p_neg(i,k,t) <= P_neg(i)  #########
    c2 = {(i, k, t):
          [[(1, m.p_neg[i, k, t]), (-1, m.P_neg[i])], "<=", 0.]
          for i in buses for k in outages for t in snapshots}

    l_constraint(m, "UpLimitNeg", c2, buses, outages, snapshots)

    ######## sum(i, p_pos(i,k,t) - p_neg(i,k,t)) = 0  #########
    c3 = {(k, t):
          [[*[(1, m.p_pos[i, k, t]) for i in buses],
            *[(-1, m.p_neg[i, k, t]) for i in buses]], "==", 0.]
          for k in outages for t in snapshots}
    l_constraint(m, "FlexBal", c3, outages, snapshots)

    ######## sum(i, PTDF(l,i) * (p_neg(i,k) - p_pos(i,k)) <= F(l) + f(l) + LODF(l,k) * f(k) ########
    c4 = {(l, k, t):
          [[*[(-ptdf.at[l, i], m.p_pos[i, k, t]) for i in buses],
            *[(ptdf.at[l, i], m.p_neg[i, k, t]) for i in buses
              ]], "<=", n.lines_t.p0.at[t, l] + lodf.at[l, k] * n.lines_t.p0.at[t, k] + n.lines.at[l, "s_nom"]]
          for l in lines for k in outages for t in snapshots}

    l_constraint(m, "LineDn", c4, lines, outages, snapshots)

    # sum(i, PTDF(l,i) * (p_pos(i,k) - p_neg(i,k)) <= F(l) - f(l) - LODF(l,k) * f(k)
    c5 = {(l, k, t): [[
        *[(ptdf.at[l, i], m.p_pos[i, k, t]) for i in buses],
        *[(-ptdf.at[l, i], m.p_neg[i, k, t]) for i in buses
          ]], "<=", -n.lines_t.p0.at[t, l] - lodf.at[l, k] * n.lines_t.p0.at[t, k] + n.lines.at[l, "s_nom"]]
          for l in lines for k in outages for t in snapshots}

    l_constraint(m, "LineUp", c5, lines, outages, snapshots)

    logger.info("define objective")

    objective = LExpression()

    coefficient1 = 1
    coefficient2 = 0.0001

    objective.variables.extend([(coefficient1, m.P_pos[i]) for i in buses])
    objective.variables.extend([(coefficient1, m.P_neg[i]) for i in buses])
    objective.variables.extend([(coefficient2, m.p_pos[i, k, t])
                                for i in buses for k in outages for t in snapshots])

    l_objective(m, objective)

    return m
Exemple #3
0
def build_model_bb(c, params: Dict, deployment_dict: Dict, coordinates_data,
                   criticality_data, tech_points_tuples):
    """Model build-up.
    Parameters:
    -----------
    - c: global criticality threshold
    - deployment_vector: dictionary indicating for each location and technology how many locations must be selected
    e.g.: deployment_vector: {"BE": {"wind_onshore": 2, "wind_offshore": 3},
                                  "PT": {"pv_utility": 10}}
    Returns:
    -----------
    """

    from pyomo.opt import SolverFactory
    from pyomo.environ import ConcreteModel, Var, Binary, maximize
    from pypsa.opt import l_constraint, LConstraint, l_objective, LExpression

    # Solver options for the MIP problem
    opt = SolverFactory(params['solver'])
    opt.options['MIPGap'] = params['mipgap']
    opt.options['Threads'] = params['threads']
    opt.options['TimeLimit'] = params['timelimit']
    """ Comment:
    - dict_deployment: same as deployment_vector but not nested
    - partitions: List of names of partitions
    - indices: dictionary giving for each 'partition' the indices of the sites that falls into that partition
    """
    deployment_dict = {(key1, key2): deployment_dict[key1][key2]
                       for key1 in deployment_dict
                       for key2 in deployment_dict[key1]}
    partitions = list(deployment_dict.keys())

    # Compute indices
    indices = dict.fromkeys(deployment_dict.keys())
    for region, tech in indices:
        indices[(region, tech)] = [
            tuple(site) for site in
            coordinates_data[(coordinates_data["Technology Name"] == tech)
                             & (coordinates_data[0] == region)]
            [["Technology Name", "Longitude", "Latitude"]].to_numpy()
        ]

    for item in partitions:
        if item in indices:
            if deployment_dict[item] > len(indices[item]):
                raise ValueError(
                    ' More sites required than available for {}'.format(item))
        else:
            indices[item] = []
            print(
                'Warning! {} not in keys of choice. Make sure there is no requirement here.'
                .format(item))

    model = ConcreteModel()

    # - Parameters - #
    no_windows = len(criticality_data.index)
    model.W = np.arange(1, no_windows + 1)

    # - Variables - #
    model.x = Var(model.W, within=Binary)
    model.y = Var(tech_points_tuples, within=Binary)

    # - Constraints - #
    activation_constraint = {}
    for w in model.W:
        lhs = LExpression([(criticality_data[site].iloc[w - 1], model.y[site])
                           for site in tech_points_tuples])
        rhs = LExpression([(c, model.x[w])])
        activation_constraint[w] = LConstraint(lhs, ">=", rhs)
    l_constraint(model, "activation_constraint", activation_constraint,
                 list(model.W))

    cardinality_constraint = {}
    for item in partitions:
        lhs = LExpression([(1, model.y[site]) for site in indices[item]])
        rhs = LExpression(constant=deployment_dict[item])
        cardinality_constraint[item] = LConstraint(lhs, "==", rhs)
    l_constraint(model, "cardinality_constraint", cardinality_constraint,
                 partitions)

    # - Objective - #
    objective = LExpression([(1, model.x[w]) for w in model.W])
    l_objective(model, objective, sense=maximize)

    return model
def redo_passive_branch_constraints(network, snapshots):

    model_components_to_delete = [
        "flow_upper",
        "flow_lower",
        "flow_upper_index",
        "flow_lower_index",
        "flow_upper_index_0",
        "flow_lower_index_0",
        "flow_upper_index_1",
        "flow_lower_index_1",
    ]
    for model_component in model_components_to_delete:
        network.model.del_component(model_component)

    passive_branches = network.passive_branches()
    extendable_branches = passive_branches[passive_branches.s_nom_extendable]
    fixed_branches = passive_branches[~passive_branches.s_nom_extendable]

    s_max_pu = pd.concat(
        {
            c: get_switchable_as_dense(network, c, "s_max_pu", snapshots)
            for c in network.passive_branch_components
        },
        axis=1,
        sort=False,
    )

    flow_upper = {(b[0], b[1], sn): [
        [
            (1, network.model.passive_branch_p[b[0], b[1], sn]),
            (1, network.model.loss[b[0], b[1], sn]),
        ],
        "<=",
        s_max_pu.at[sn, b] * fixed_branches.at[b, "s_nom"],
    ]
                  for b in fixed_branches.index for sn in snapshots}

    flow_upper.update({(b[0], b[1], sn): [
        [
            (1, network.model.passive_branch_p[b[0], b[1], sn]),
            (1, network.model.loss[b[0], b[1], sn]),
            (
                -s_max_pu.at[sn, b],
                network.model.passive_branch_s_nom[b[0], b[1]],
            ),
        ],
        "<=",
        0,
    ]
                       for b in extendable_branches.index for sn in snapshots})

    l_constraint(network.model, "flow_upper", flow_upper,
                 list(passive_branches.index), snapshots)

    flow_lower = {(b[0], b[1], sn): [
        [
            (1, network.model.passive_branch_p[b[0], b[1], sn]),
            (-1, network.model.loss[b[0], b[1], sn]),
        ],
        ">=",
        -s_max_pu.at[sn, b] * fixed_branches.at[b, "s_nom"],
    ]
                  for b in fixed_branches.index for sn in snapshots}

    flow_lower.update({(b[0], b[1], sn): [
        [
            (1, network.model.passive_branch_p[b[0], b[1], sn]),
            (-1, network.model.loss[b[0], b[1], sn]),
            (
                s_max_pu.at[sn, b],
                network.model.passive_branch_s_nom[b[0], b[1]],
            ),
        ],
        ">=",
        0,
    ]
                       for b in extendable_branches.index for sn in snapshots})

    l_constraint(network.model, "flow_lower", flow_lower,
                 list(passive_branches.index), snapshots)
def define_loss_constraints(network, snapshots):

    tangents = network.tangents

    positions = range(1, tangents + 1)
    signs = [-1, 1]

    passive_branches = network.passive_branches()

    s_max_pus = get_switchable_as_dense(network, "Line", "s_max_pu")

    network.model.loss = Var(list(passive_branches.index),
                             snapshots,
                             domain=NonNegativeReals)

    redo_passive_branch_constraints(network, snapshots)

    loss_upper = {}
    loss_tangents = {}

    for branch in passive_branches.index:

        bus0 = passive_branches.at[branch, "bus0"]
        bus1 = passive_branches.at[branch, "bus1"]
        bt = branch[0]
        bn = branch[1]

        r_pu_eff = passive_branches.at[branch, "r_pu_eff"]

        if passive_branches.at[branch, "s_nom_extendable"]:
            attr = "s_nom_max"
        elif passive_branches.at[branch, "s_nom_opt"] != 0.0:
            attr = "s_nom_opt"
        else:
            attr = "s_nom"

        s_nom_max = passive_branches.at[branch, attr]

        assert np.isfinite(s_nom_max) and not np.isnan(
            s_nom_max
        ), f"Infinite or non-existent 's_nom_max' encountered at line {bn}"

        for sn in snapshots:

            s_max_pu = s_max_pus.loc[sn, bn]

            # adjust kcl
            # use of ._body because of pyomo bug
            for bus in [bus0, bus1]:
                network.model.power_balance[bus, sn]._body -= (
                    network.model.loss[bt, bn, sn] / 2)

            # upper loss limit
            lhs = LExpression(
                [(1, network.model.loss[bt, bn, sn])],
                -r_pu_eff * (s_max_pu * s_nom_max)**2,
            )
            loss_upper[bt, bn, sn] = LConstraint(lhs, "<=", LExpression())

            # loss tangents
            for k in positions:

                p_k = k / tangents * s_max_pu * s_nom_max
                loss_k = r_pu_eff * p_k**2
                slope_k = 2 * r_pu_eff * p_k
                offset_k = loss_k - slope_k * p_k

                for sign in signs:

                    lhs = LExpression([(1, network.model.loss[bt, bn, sn])])
                    rhs = LExpression(
                        [(sign * slope_k,
                          network.model.passive_branch_p[bt, bn, sn])],
                        offset_k,
                    )
                    loss_tangents[sign, k, bt, bn,
                                  sn] = LConstraint(lhs, ">=", rhs)

    l_constraint(network.model, "loss_upper", loss_upper,
                 list(passive_branches.index), snapshots)

    l_constraint(
        network.model,
        "loss_tangents",
        loss_tangents,
        signs,
        list(positions),
        list(passive_branches.index),
        snapshots,
    )