简体   繁体   中英

Termination condition infeasible for pyomo (solver glpk)

I am trying to solve a power flow optimisation with N-1 reliability constraint, which means that the power from the four generators can still supply the 8 loads through the remaining 17 power lines when 1 line is down.

To solve this questions, I introduced 3 sets I: set of nodes (i:1 to 4 is the generators while i:5 to 12 are the loads) J: set of edges (total 18) K: set of scenarios (there are 18 scenarios in total, one scenario for when each edge goes out

the variable p[j,k] is the power flow in edge j for scenario k.

The main constraints i have in this problem are:

  1. 0<g[i]<G[i]max for every i
  2. -Pmax[j]<p[j,k]<Pmax[j] (The Pmax for each edge is the same for all scenarios)
  3. sum(over j) a[i,j]*p[j,k]-(-g[i]+d[i])=0 for every i, for every k (This is the power balance at each node, assuming no power losses on the lines or nodes) 4 p[1,1]=p[2,2]=p[3,3]=p[4,4]=.....p[118,18]=0 (This is to satisfy the 18 different scenarios where the flow in each edge is zero.

I can run the code and used the solver glpk, but it seems like there is a problem with the way i set up my problem because the termination condition is infeasible.

Can someone help to explain what is wrong with my model formulation?

import numpy as np
from pyomo.environ import *

#Max generator output for node 1-4. Nodes 5-12 are not generators so 0.
Gmax_d = {1: 3, 2: 2, 3: 4, 4: 7, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0}

#Cost for each generator
Cost_d = {1: 4, 2: 8, 3: 5, 4: 3, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0, 11: 0, 12: 0}

#Max flow in each edge (total 18 edges)
Pmax_d = {1: 4.8005, 2: 1.9246, 3: 3.4274, 4: 2.9439, 5: 4.5652, 6: 4.0484, 7: 2.8259, 8: 1.074, 9: 4.2856, 10: 2.7788, 11: 3.4617, 12: 4.1677, 13: 4.6873, 14: 3.9528, 15: 1.7051, 16: 2.6228, 17: 4.7419, 18: 4.6676}

#Demand/load at nodes 5-12. Nodes 1-4 are connected to generators so 0.
Demand_d = {1: 0, 2: 0, 3: 0, 4: 0, 5: 1.6154, 6: 2.3405, 7: 1.0868, 8: 1.5293, 9: 2.2197, 10: 1.0148, 11: 1.2083, 12: 1.3041}

#12 by 18 matrix to show the direction between node i and edge j. +1 if the flow is into the node and -1 if the flow is in the direction away from the edge, 0 if the edge j is not connected to node i
A_dict = {(1, 1): -1, (1, 2): -1, (1, 3): 0, (1, 4): 0, (1, 5): 0, (1, 6): 0, (1, 7): 0, (1, 8): 0, (1, 9): 0, (1, 10): 0, (1, 11): 0, (1, 12): 0, (1, 13): 0, (1, 14): 0, (1, 15): 0, (1, 16): 0, (1, 17): 0, (1, 18): 0, (2, 1): 0, (2, 2): 0, (2, 3): -1, (2, 4): -1, (2, 5): 0, (2, 6): 0, (2, 7): 0, (2, 8): 0, (2, 9): 0, (2, 10): 0, (2, 11): 0, (2, 12): 0, (2, 13): 0, (2, 14): 0, (2, 15): 0, (2, 16): 0, (2, 17): 0, (2, 18): 0, (3, 1): 0, (3, 2): 0, (3, 3): 0, (3, 4): 0, (3, 5): 0, (3, 6): 0, (3, 7): 0, (3, 8): 0, (3, 9): 0, (3, 10): -1, (3, 11): -1, (3, 12): 0, (3, 13): 0, (3, 14): 0, (3, 15): 0, (3, 16): 0, (3, 17): 0, (3, 18): -1, (4, 1): 0, (4, 2): 0, (4, 3): 0, (4, 4): 0, (4, 5): 0, (4, 6): 0, (4, 7): -1, (4, 8): 0, (4, 9): 0, (4, 10): 0, (4, 11): 0, (4, 12): 0, (4, 13): 0, (4, 14): 0, (4, 15): -1, (4, 16): 0, (4, 17): -1, (4, 18): 0, (5, 1): 1, (5, 2): 0, (5, 3): 0, (5, 4): 0, (5, 5): 1, (5, 6): -1, (5, 7): 0, (5, 8): 0, (5, 9): 0, (5, 10): 0, (5, 11): 0, (5, 12): 0, (5, 13): 0, (5, 14): 0, (5, 15): 0, (5, 16): 0, (5, 17): 0, (5, 18): 0, (6, 1): 0, (6, 2): 1, (6, 3): 1, (6, 4): 0, (6, 5): -1, (6, 6): 0, (6, 7): 1, (6, 8): -1, (6, 9): 0, (6, 10): 0, (6, 11): 0, (6, 12): 0, (6, 13): 0, (6, 14): 0, (6, 15): 0, (6, 16): 0, (6, 17): 0, (6, 18): 0, (7, 1): 0, (7, 2): 0, (7, 3): 0, (7, 4): 1, (7, 5): 0, (7, 6): 0, (7, 7): 0, (7, 8): 0, (7, 9): -1, (7, 10): 1, (7, 11): 0, (7, 12): 0, (7, 13): 0, (7, 14): 0, (7, 15): 0, (7, 16): 0, (7, 17): 0, (7, 18): 0, (8, 1): 0, (8, 2): 0, (8, 3): 0, (8, 4): 0, (8, 5): 0, (8, 6): 0, (8, 7): 0, (8, 8): 1, (8, 9): 1, (8, 10): 0, (8, 11): 0, (8, 12): 0, (8, 13): -1, (8, 14): 0, (8, 15): 1, (8, 16): 0, (8, 17): 0, (8, 18): 1, (9, 1): 0, (9, 2): 0, (9, 3): 0, (9, 4): 0, (9, 5): 0, (9, 6): 0, (9, 7): 0, (9, 8): 0, (9, 9): 0, (9, 10): 0, (9, 11): 1, (9, 12): -1, (9, 13): 0, (9, 14): 0, (9, 15): 0, (9, 16): 0, (9, 17): 0, (9, 18): 0, (10, 1): 0, (10, 2): 0, (10, 3): 0, (10, 4): 0, (10, 5): 0, (10, 6): 0, (10, 7): 0, (10, 8): 0, (10, 9): 0, (10, 10): 0, (10, 11): 0, (10, 12): 1, (10, 13): 1, (10, 14): -1, (10, 15): 0, (10, 16): 0, (10, 17): 0, (10, 18): 0, (11, 1): 0, (11, 2): 0, (11, 3): 0, (11, 4): 0, (11, 5): 0, (11, 6): 0, (11, 7): 0, (11, 8): 0, (11, 9): 0, (11, 10): 0, (11, 11): 0, (11, 12): 0, (11, 13): 0, (11, 14): 1, (11, 15): 0, (11, 16): 1, (11, 17): 0, (11, 18): 0, (12, 1): 0, (12, 2): 0, (12, 3): 0, (12, 4): 0, (12, 5): 0, (12, 6): 1, (12, 7): 0, (12, 8): 0, (12, 9): 0, (12, 10): 0, (12, 11): 0, (12, 12): 0, (12, 13): 0, (12, 14): 0, (12, 15): 0, (12, 16): -1, (12, 17): 1, (12, 18): 0}


# Creation of a Concrete Model
model = ConcreteModel()

# Sets
model.i = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12], doc='Nodes')
model.j = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18], doc='Edges')
model.k = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18], doc='Set of scenarios, where in each scenario the flow in edge j is zero so total 18 scenarios')

# Parameters
model.Gmax = Param(model.i,initialize = Gmax_d, doc = 'Maximum generator power')
model.Pmax = Param(model.j, initialize = Pmax_d, doc = 'Maximum power flow ')
model.cost = Param(model.i, initialize = Cost_d, doc = 'Cost to generate power from each generator')
model.demand = Param(model.i, initialize = Demand_d, doc = 'Demand in each electric load node')
model.A = Param(model.i,model.j, initialize = A_dict, doc = 'Incidence matrix')

#Variable
model.g = Var(model.i, bounds=(0.0,None), doc = 'generator power')
model.p = Var(model.j, model.k, bounds =(0.0, None), doc = 'power flow in each edge for each scenario')

#Constraints
def max_gen_power(model, i):
    return model.g[i] <= model.Gmax[i]
model.gen_power = Constraint(model.i, rule = max_gen_power, doc = 'Maximum generation capacity')

def max_power_flow_positive(model, j, k):
    return model.p[j,k] <= model.Pmax[j] 
model.power_flow_positive = Constraint(model.j, model.k, rule = max_power_flow_positive, doc = 'Maximum power flow')

def max_power_flow_negative(model, j, k):
    return model.p[j,k] >= -model.Pmax[j]
model.power_flow_negative = Constraint(model.j, model.k, rule = max_power_flow_negative, doc = 'Minimum power flow')

def balance(model, i, k):
     return sum(model.A[i,j] * model.p[j,k] for j in model.j) - (-model.g[i] + model.demand[i]) == 0.0  
model.flow_balance = Constraint(model.i, model.k, rule = balance, doc ='Balance in every node, total power generated must be equal to the total demand by the loads')

def zeroflow1(model, j, k):
     return model.p[1,1] <= 0.0  
model.zero_flow1 = Constraint(model.j, model.k, rule = zeroflow1, doc ='zero flow for p11')

def zeroflow1a(model, j, k):
     return model.p[1,1] >= 0.0  
model.zero_flow1a = Constraint(model.j, model.k, rule = zeroflow1a, doc ='zero flow for p11')

def zeroflow2(model, j, k):
     return model.p[2,2] <= 0.0   
model.zero_flow2 = Constraint(model.j, model.k, rule = zeroflow2, doc ='zero flow for p22')

def zeroflow2a(model, j, k):
     return model.p[2,2] >= 0.0   
model.zero_flow2a = Constraint(model.j, model.k, rule = zeroflow2a, doc ='zero flow for p22')

def zeroflow3(model, j, k):
     return model.p[3,3] <= 0.0   
model.zero_flow3 = Constraint(model.j, model.k, rule = zeroflow3, doc ='zero flow for p33')

def zeroflow3a(model, j, k):
     return model.p[3,3] >= 0.0   
model.zero_flow3a = Constraint(model.j, model.k, rule = zeroflow3a, doc ='zero flow for p33')

def zeroflow4(model, j, k):
     return model.p[4,4] <= 0.0  
model.zero_flow4 = Constraint(model.j, model.k, rule = zeroflow4, doc ='zero flow for p44')

def zeroflow4a(model, j, k):
     return model.p[4,4] >= 0.0  
model.zero_flow4a = Constraint(model.j, model.k, rule = zeroflow4a, doc ='zero flow for p44')

def zeroflow5(model, j, k):
     return model.p[5,5] <= 0.0   
model.zero_flow5 = Constraint(model.j, model.k, rule = zeroflow5, doc ='zero flow for p55')

def zeroflow5a(model, j, k):
     return model.p[5,5] >= 0.0   
model.zero_flow5a = Constraint(model.j, model.k, rule = zeroflow5a, doc ='zero flow for p55')

def zeroflow6(model, j, k):
     return model.p[6,6] <= 0.0   
model.zero_flow6 = Constraint(model.j, model.k, rule = zeroflow6, doc ='zero flow for p66')

def zeroflow6a(model, j, k):
     return model.p[6,6] >= 0.0   
model.zero_flow6a = Constraint(model.j, model.k, rule = zeroflow6a, doc ='zero flow for p66')

def zeroflow7a(model, j, k):
     return model.p[7,7] <= 0.0  
model.zero_flow7a = Constraint(model.j, model.k, rule = zeroflow7a, doc ='zero flow for p77')

def zeroflow7(model, j, k):
     return model.p[7,7] >= 0.0  
model.zero_flow7 = Constraint(model.j, model.k, rule = zeroflow7, doc ='zero flow for p77')

def zeroflow8(model, j, k):
     return model.p[8,8] <= 0.0  
model.zero_flow8 = Constraint(model.j, model.k, rule = zeroflow8, doc ='zero flow for p88')

def zeroflow8a(model, j, k):
     return model.p[8,8] >= 0.0  
model.zero_flow8a = Constraint(model.j, model.k, rule = zeroflow8a, doc ='zero flow for p88')

def zeroflow9(model, j, k):
     return model.p[9,9] <= 0.0  
model.zero_flow9 = Constraint(model.j, model.k, rule = zeroflow9, doc ='zero flow for p99')

def zeroflow9a(model, j, k):
     return model.p[9,9] >= 0.0  
model.zero_flow9a = Constraint(model.j, model.k, rule = zeroflow9a, doc ='zero flow for p99')

def zeroflow10(model, j, k):
     return model.p[10,10] <= 0.0   
model.zero_flow10 = Constraint(model.j, model.k, rule = zeroflow10, doc ='zero flow for p1010')

def zeroflow10a(model, j, k):
     return model.p[10,10] >= 0.0   
model.zero_flow10a = Constraint(model.j, model.k, rule = zeroflow10a, doc ='zero flow for p1010')

def zeroflow11(model, j, k):
     return model.p[11,11] <= 0.0   
model.zero_flow11 = Constraint(model.j, model.k, rule = zeroflow11, doc ='zero flow for p1111')

def zeroflow11a(model, j, k):
     return model.p[11,11] >= 0.0   
model.zero_flow11a = Constraint(model.j, model.k, rule = zeroflow11a, doc ='zero flow for p1111')

def zeroflow12(model, j, k):
     return model.p[12,12] <= 0.0   
model.zero_flow12 = Constraint(model.j, model.k, rule = zeroflow12, doc ='zero flow for p1212')

def zeroflow12a(model, j, k):
     return model.p[12,12] >= 0.0   
model.zero_flow12a = Constraint(model.j, model.k, rule = zeroflow12a, doc ='zero flow for p1212')

def zeroflow13(model, j, k):
     return model.p[13,13] <= 0.0   
model.zero_flow13 = Constraint(model.j, model.k, rule = zeroflow13, doc ='zero flow for p1313')

def zeroflow13a(model, j, k):
     return model.p[13,13] >= 0.0   
model.zero_flow13a = Constraint(model.j, model.k, rule = zeroflow13a, doc ='zero flow for p1313')

def zeroflow14(model, j, k):
     return model.p[14,14] <= 0.0   
model.zero_flow14 = Constraint(model.j, model.k, rule = zeroflow14, doc ='zero flow for p1414')

def zeroflow14a(model, j, k):
     return model.p[14,14] >= 0.0   
model.zero_flow14a = Constraint(model.j, model.k, rule = zeroflow14a, doc ='zero flow for p1414')

def zeroflow15(model, j, k):
     return model.p[15,15] <= 0.0   
model.zero_flow15 = Constraint(model.j, model.k, rule = zeroflow15, doc ='zero flow for p1515')

def zeroflow15a(model, j, k):
     return model.p[15,15] >= 0.0   
model.zero_flow15a = Constraint(model.j, model.k, rule = zeroflow15a, doc ='zero flow for p1515')

def zeroflow16(model, j, k):
     return model.p[16,16] <= 0.0   
model.zero_flow16 = Constraint(model.j, model.k, rule = zeroflow16, doc ='zero flow for p1616')

def zeroflow16a(model, j, k):
     return model.p[16,16] >= 0.0   
model.zero_flow16a = Constraint(model.j, model.k, rule = zeroflow16a, doc ='zero flow for p1616')

def zeroflow17(model, j, k):
     return model.p[17,17] <= 0.0   
model.zero_flow17 = Constraint(model.j, model.k, rule = zeroflow17, doc ='zero flow for p1717')

def zeroflow17a(model, j, k):
     return model.p[17,17] >= 0.0   
model.zero_flow17a = Constraint(model.j, model.k, rule = zeroflow17a, doc ='zero flow for p1717')

def zeroflow18(model, j, k):
     return model.p[18,18] <= 0.0   
model.zero_flow18 = Constraint(model.j, model.k, rule = zeroflow18, doc ='zero flow for p1818')

def zeroflow18a(model, j, k):
     return model.p[18,18] >= 0.0   
model.zero_flow18a = Constraint(model.j, model.k, rule = zeroflow18a, doc ='zero flow for p1818')

#Objective Function
def objective_rule(model):
    return sum(model.cost[i] * model.g[i] for i in model.i)
model.objective = Objective(rule = objective_rule, sense = minimize, doc = 'Cost minimization')

#Display Output
def pyomo_postprocess(options=None, instance=None, results=None):
  model.g.display()
if __name__ == '__main__':
    # This emulates what the pyomo command-line tools does
    from pyomo.opt import SolverFactory
    import pyomo.environ
    opt = SolverFactory("glpk")
    results = opt.solve(model)
    #sends results to stdout
    results.write()
    print("\nDisplaying Solution\n" + '-'*60)
    pyomo_postprocess(None, model, results)

You are incorrectly building the "zero flow" constraints. You are doing this:

def zeroflow1(model, j, k):
     return model.p[1,1] <= 0.0  
model.zero_flow1 = Constraint(model.j, model.k, rule = zeroflow1, doc ='zero flow for p11')

which, when using this type of construction, passes each value of J and K to the construction of this constraint. So if you pprint the model you would see that you are making way too many constraints (| J | * | K |). They are duplicates because you are hard-coding in the value 1 . Inefficient, but probably not killing the model.

You want to make a restriction for each scenario so the only thing you should pass in to the function is the scenario, and use that, which coincidentally is the same as the node number, to restrict power in only that scenario-node combo. Delete all of them and do this:

def zero_flow(model, scenario):
     # we know scenario == node number of interest by problem definition... so:
     node = scenario    # unneccessary, but adds clarity
     return model.p[node, scenario] == 0
model.scenario_constraint = Constraint(model.k, rule=zero_flow)

Note that if you do this, the status of the problem is still infeasible. Why? It is impossible to tell because you have buried 18.network flow problems in there and you don't know which one is problematic. Honestly, I would write a proper.network flow problem and analyze it (without using optimization--not necessary) to see if the.network can do what you want in each of the scenarios.

If you change the constraint and just run the first 2 scenarios as:

model.k = Set(initialize=[1,2]) 

the model solves ok, so those 2 work, but you would be running the generators to satisfy the most restrictive of all of the lineups at once, perhaps not what you want?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM