简体   繁体   English

pyomo 的终止条件不可行(求解器 glpk)

[英]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.我正在尝试解决具有 N-1 可靠性约束的功率流优化,这意味着当 1 条线路出现故障时,来自四台发电机的电力仍可以通过剩余的 17 条电力线为 8 个负载供电。

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为了解决这个问题,我引入了 3 组 I:节点集(i:1 到 4 是生成器,而 i:5 到 12 是负载) J:边集(共 18 个) K:场景集(有共18个场景,每条边出的时候一个场景

the variable p[j,k] is the power flow in edge j for scenario k.变量 p[j,k] 是场景 k 边 j 的功率流。

The main constraints i have in this problem are:我在这个问题上的主要限制是:

  1. 0<g[i]<G[i]max for every i 0<g[i]<G[i]max 对于每个 i
  2. -Pmax[j]<p[j,k]<Pmax[j] (The Pmax for each edge is the same for all scenarios) -Pmax[j]<p[j,k]<Pmax[j](每条边的Pmax对于所有场景都是一样的)
  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. sum(over j) a[i,j]*p[j,k]-(-g[i]+d[i])=0 for every i, for every k (这是每个节点的功率平衡,假设线路或节点上没有功率损耗) 4 p[1,1]=p[2,2]=p[3,3]=p[4,4]=.....p[118,18] =0(这是为了满足每条边上的流量为零的 18 种不同场景。

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.我可以运行代码并使用求解器 glpk,但似乎我设置问题的方式有问题,因为终止条件不可行。

Can someone help to explain what is wrong with my model formulation?有人可以帮忙解释一下我的 model 配方有什么问题吗?

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.其中,当使用这种类型的构造时,将JK每个值传递给该约束的构造。 So if you pprint the model you would see that you are making way too many constraints (| J | * | K |).因此,如果您pprint ,您会发现您设置了太多约束 (| J | * | K |)。 They are duplicates because you are hard-coding in the value 1 .它们是重复的,因为您在值1中进行了硬编码。 Inefficient, but probably not killing the model.效率低下,但可能不会杀死 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.你想对每个场景进行限制,所以你唯一应该传递给 function 的是场景,并使用它,巧合的是与节点号相同,只限制场景 - 节点组合中的功率。 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.这是不可能分辨的,因为你在那里埋下了 18.network 流量问题,你不知道哪一个有问题。 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.老实说,我会写一个适当的 .network 流问题并分析它(不使用优化——不是必需的),看看 .network 是否可以在每个场景中做你想做的。

If you change the constraint and just run the first 2 scenarios as:如果您更改约束并只运行前 2 个场景:

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? model 解决了问题,所以这 2 个可以工作,但是您将运行生成器来同时满足所有阵容中最严格的要求,也许这不是您想要的?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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