0

I am modelling a network in pypsa with constraints that have statistically calculated RHS, meaning that there is always a chance of an infeasible solution (e.g. X > 10 & X < 9)

To get around this I add a penalty term into the objective function, example given below. However I have had to modify optimize.py as follows:

def assign_solution(n: Network) -> None:
"""
Map solution to network components.
"""
m = n.model
sns = n.model.parameters.snapshots.to_index()

for name, variable in m.variables.items():
    sol = variable.solution
    if name == "objective_constant":
        continue
    **if name[:7].lower() == "penalty":
        continue**
    try:
        c, attr = name.split("-", 1)
        df = sol.to_pandas()
    except ValueError:
        continue

Where the added lines are

    if name[:7].lower() == "penalty":
        continue

If I don't make this change pypsa fails with a KeyError because the function assign_solution which 'Maps solution to network components' can't find a component for the new objective variable.

Is there some way to add these penalty variables to some inert component, or can we get something like these two lines added to the pypsa repo, to help anybody else using constraint relaxation. Or is there another solution out there?

Toy example of constraint relaxation, requiring above modifications to optimize.py

import pypsa

def build_model():
    # Create toy network
    n = pypsa.Network()
    n.add("Carrier", "AC")
    n.add("Bus", "Bus 0",carrier = 'AC')
    n.add("Bus", "Bus 1",carrier = 'AC')
    n.add("Line","Line 01", bus0 = "Bus 0", bus1 = "Bus 1", x=0.1, s_nom=50, carrier =     'AC', r = 1)

    n.add("Generator", "Gen 0",
                bus=f"Bus 0",
                p_nom=100,
                carrier = 'AC',
                marginal_cost=10,
        )

    n.add("Load", "Load 0",
                bus="Bus 1",
                p_set=50,
                carrier = 'AC',
        )
    n.optimize.create_model()

return n

n = build_model()
n.optimize.solve_model()

This network of a 100MW generator connected to a 50MW by 1 line solves, no problem Simple network

However if I add a constraint limiting that line to 40MW, it does not

# Set constraint restricting line flow to 40MW or less (infeasible, as load is 50MW)
n = build_model()
m = n.model
line_flow = m.variables["Line-s"].sel({'Line':'Line 01'})
m.add_constraints(line_flow <= 40)
n.optimize.solve_model()

Solver message: infeasible ('warning', 'infeasible')

So I can add constraint relaxation

# Add constraint relaxation
n = build_model()
m = n.model
penalty = m.add_variables(lower = 0, name = f"Penalty_varible", coords = [n.snapshots])
extra_objective_term = (penalty * 1000).sum() # Add weighting of 1000 to the penalty term
n.model.objective = m.objective + extra_objective_term 
m.add_constraints(line_flow <= penalty + 40)
n.optimize.solve_model()

n.model.solution

Which solves and gives penalty = 10, as you'd expect

Is there any way to make this compatible with PyPSA without having to change the library code?

Cheers

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.