python - 找到 Pyomo 最优解,但解数为 0(水电模拟)
问题描述
我希望模拟挪威的水力发电,考虑到所有级联依赖性(每小时分辨率)。首先,我在 Pyomo 中为一组三个工厂和三个水库设置了一天的优化问题。目前我想在所有时间和所有工厂/水库中最大化利润,计算如下:电价[$/MWh]*涡轮机输出[MW]*3600[s=1h] + 体积[m3]*能源当量[MWh/ m3]*电价[$/MWh]
我的限制是:
每小时负载=每小时产生的功率必须等于负载
水平衡= 在每个时间步正确更新存储水平
开始和结束存储水平= 最大存储量的 60% 模拟期的开始和结束(这是在水平衡约束中)
问题:
1)为什么打印语句为 cascade_inflow 和discharge_flow 打印出0.0:因为这是在创建模型时打印而不是在求解时打印?
2A)终止条件是最优的,我有一个目标函数的值,但解决方案的数量是 0:我认为问题在于约束水平衡,我将结果进一步向下发布 6 小时。我是否需要以某种方式设置水平衡的上限和下限? 编辑:如果我使用pyomo solve --solver=glpk script.py input.dat从命令行运行脚本,我会得到一个显示的解决方案..?!
2B) 水约束功能不正常。如果我查看结果,那么从时间步长 1 到 2 的音量跳跃是不可行的。那里有什么问题?我添加级联流的方式是不正确的,还是变量m.volume只是做它想要的?
3)创建网络流问题可能是一个更好的主意吗?Pyomo Gallery中有此类问题的示例代码。但我还不确定如何将节点建模为水库。(一旦我尝试实现一个脚本,我很可能会为此写一篇新文章)。
4)(这是我的第一篇文章:我做错了什么或者下次应该做得更好?)
代码(省略读取参数)
from pyomo.environ import *
from pyomo.opt import SolverFactory
opt = SolverFactory("glpk")
# Initiate model instance
m = AbstractModel()
# Define the variable power for each time step
m.turbine = Var(m.stage, m.res, initialize=0, bounds=turbine_bounds, within=NonNegativeReals)
# Define the variable volume for each time step
m.volume = Var(m.stage, m.res, initialize=volume_Init, bounds=volume_bounds, within=NonNegativeReals)
# Define the variable spill flow for each time step
m.spilledFlow = Var(m.stage, m.res, initialize=0, bounds=spill_bounds, within=NonNegativeReals)
# Constrain total power generated over day
def hourly_load_rule(model, t):
return model.P_load*model.hourly_demand[t] <= sum(model.turbine[t, res] for res in model.res) <= model.P_load*model.hourly_demand[t]
m.hourly_load = Constraint(m.stage, rule=hourly_load_rule)
# Water balance equation
def water_balance_rule(model, t, r):
if t == model.T: # final volume is same as initial volume at 60%
return model.volume[t, r] == model.max_Vol[r]*0.6
elif t > 1:
cascade_inflow = 0
for stor in model.res:
# connectMat is a matrix that has a 1 where there is a connection and 0 where there is not
cascade_inflow = cascade_inflow + model.connectMat[stor, r]*(model.turbine[t, stor]/model.slope[stor]+model.spilledFlow[t, stor])
if model.connectMat[stor, r] == 1:
print(stor, r, t, value(cascade_inflow)) # this always prints out 0.0 for cascade_inflow
discharged_flow = model.turbine[t, r]/model.slope[r] # model.turbine is in MW: divide by slope to get discharge flow [m3/s]
print(value(discharged_flow)) # this always prints out 0.0
return model.volume[t, r] == model.volume[t-1, r]+(cascade_inflow+model.inflow[t, r]-model.spilledFlow[t, r]-discharged_flow)*model.secPerTimeStep
else:
# start volume constrained to 60% of max volume
return model.volume[t, r] == model.max_Vol[r]*0.6
m.water_balance = Constraint(m.stage, m.res, rule=water_balance_rule)
# Revenue = Objective function (sum over all hours and all plants/reservoirs)
def revenue_rule(model):
return sum(sum(model.el_price[i]*model.turbine[i, j]*model.secPerTimeStep+model.volume[i, j]*model.energy_stored[j]*model.el_price[i] for i in model.stage) for j in model.res)
m.obj = Objective(rule=revenue_rule, sense=maximize)
instance = m.create("three_input_stack.dat")
results = opt.solve(instance)
instance.display()
results.write()
结果
0.0
(1, 2, 2, 0.0)
0.0
(2, 3, 2, 0.0)
0.0
0.0
(1, 2, 3, 0.0)
0.0
(2, 3, 3, 0.0)
0.0
0.0
(1, 2, 4, 0.0)
0.0
(2, 3, 4, 0.0)
0.0
0.0
(1, 2, 5, 0.0)
0.0
(2, 3, 5, 0.0)
0.0
Model unknown
Variables:
turbine : Size=18, Index=turbine_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0 : 3.31 : 3.31 : False : False : NonNegativeReals
(1, 2) : 0 : 3.71 : 5.9 : False : False : NonNegativeReals
(1, 3) : 0 : 0.0 : 9.0 : False : False : NonNegativeReals
(2, 1) : 0 : 0.8 : 3.31 : False : False : NonNegativeReals
(2, 2) : 0 : 5.9 : 5.9 : False : False : NonNegativeReals
(2, 3) : 0 : 0.0 : 9.0 : False : False : NonNegativeReals
(3, 1) : 0 : 0.0 : 3.31 : False : False : NonNegativeReals
(3, 2) : 0 : 0.242202133966 : 5.9 : False : False : NonNegativeReals
(3, 3) : 0 : 6.31779786603 : 9.0 : False : False : NonNegativeReals
(4, 1) : 0 : 0.0 : 3.31 : False : False : NonNegativeReals
(4, 2) : 0 : 0.0 : 5.9 : False : False : NonNegativeReals
(4, 3) : 0 : 6.5 : 9.0 : False : False : NonNegativeReals
(5, 1) : 0 : 0.0 : 3.31 : False : False : NonNegativeReals
(5, 2) : 0 : 1.9665 : 5.9 : False : False : NonNegativeReals
(5, 3) : 0 : 4.6535 : 9.0 : False : False : NonNegativeReals
(6, 1) : 0 : 3.31 : 3.31 : False : False : NonNegativeReals
(6, 2) : 0 : 3.83 : 5.9 : False : False : NonNegativeReals
(6, 3) : 0 : 0.0 : 9.0 : False : False : NonNegativeReals
volume : Size=18, Index=volume_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0.0 : 39600000.0 : 66000000.0 : False : False : NonNegativeReals
(1, 2) : 0.0 : 10020000.0 : 16700000.0 : False : False : NonNegativeReals
(1, 3) : 0.0 : 1260000.0 : 2100000.0 : False : False : NonNegativeReals
(2, 1) : 0.0 : 32149783.0468 : 66000000.0 : False : False : NonNegativeReals
(2, 2) : 0.0 : 16684216.9532 : 16700000.0 : False : False : NonNegativeReals
(2, 3) : 0.0 : 2100000.0 : 2100000.0 : False : False : NonNegativeReals
(3, 1) : 0.0 : 32167783.0468 : 66000000.0 : False : False : NonNegativeReals
(3, 2) : 0.0 : 16700000.0 : 16700000.0 : False : False : NonNegativeReals
(3, 3) : 0.0 : 2100000.0 : 2100000.0 : False : False : NonNegativeReals
(4, 1) : 0.0 : 32185783.0468 : 66000000.0 : False : False : NonNegativeReals
(4, 2) : 0.0 : 16700000.0 : 16700000.0 : False : False : NonNegativeReals
(4, 3) : 0.0 : 2100000.0 : 2100000.0 : False : False : NonNegativeReals
(5, 1) : 0.0 : 32203783.0468 : 66000000.0 : False : False : NonNegativeReals
(5, 2) : 0.0 : 16700000.0 : 16700000.0 : False : False : NonNegativeReals
(5, 3) : 0.0 : 2100000.0 : 2100000.0 : False : False : NonNegativeReals
(6, 1) : 0.0 : 39600000.0 : 66000000.0 : False : False : NonNegativeReals
(6, 2) : 0.0 : 10020000.0 : 16700000.0 : False : False : NonNegativeReals
(6, 3) : 0.0 : 1260000.0 : 2100000.0 : False : False : NonNegativeReals
spilledFlow : Size=18, Index=spilledFlow_index
Key : Lower : Value : Upper : Fixed : Stale : Domain
(1, 1) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
(1, 2) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
(1, 3) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
(2, 1) : 0.0 : 2069.67087236 : 10000.0 : False : False : NonNegativeReals
(2, 2) : 0.0 : 213.332062039 : 10000.0 : False : False : NonNegativeReals
(2, 3) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(3, 1) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(3, 2) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(3, 3) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(4, 1) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(4, 2) : 0.0 : 5.0 : 10000.0 : False : False : NonNegativeReals
(4, 3) : 0.0 : 4.22222222222 : 10000.0 : False : False : NonNegativeReals
(5, 1) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(5, 2) : 0.0 : 0.0 : 10000.0 : False : False : NonNegativeReals
(5, 3) : 0.0 : 5.86355555556 : 10000.0 : False : False : NonNegativeReals
(6, 1) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
(6, 2) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
(6, 3) : 0.0 : 0 : 10000.0 : False : True : NonNegativeReals
Objectives:
obj : Size=1, Index=None, Active=True
Key : Active : Value
None : True : 39250323.6272
Constraints:
hourly_load : Size=6
Key : Lower : Body : Upper
1 : 7.02 : 7.02 : 7.02
2 : 6.7 : 6.7 : 6.7
3 : 6.56 : 6.56 : 6.56
4 : 6.5 : 6.5 : 6.5
5 : 6.62 : 6.62 : 6.62
6 : 7.14 : 7.14 : 7.14
water_balance : Size=18
Key : Lower : Body : Upper
(1, 1) : 39600000.0 : 39600000.0 : 39600000.0
(1, 2) : 10020000.0 : 10020000.0 : 10020000.0
(1, 3) : 1260000.0 : 1260000.0 : 1260000.0
(2, 1) : 0.0 : 2.14204192162e-08 : 0.0
(2, 2) : 0.0 : -2.23517417908e-08 : 0.0
(2, 3) : 0.0 : -5.82076609135e-10 : 0.0
(3, 1) : 0.0 : 0.0 : 0.0
(3, 2) : 0.0 : 1.55250745593e-08 : 0.0
(3, 3) : 0.0 : -7.13669123797e-09 : 0.0
(4, 1) : 0.0 : 0.0 : 0.0
(4, 2) : 0.0 : -7.35411731512e-11 : 0.0
(4, 3) : 0.0 : -6.39488462184e-12 : 0.0
(5, 1) : 0.0 : 0.0 : 0.0
(5, 2) : 0.0 : -5.49960077478e-10 : 0.0
(5, 3) : 0.0 : -1.79056769412e-10 : 0.0
(6, 1) : 39600000.0 : 39600000.0 : 39600000.0
(6, 2) : 10020000.0 : 10020000.0 : 10020000.0
(6, 3) : 1260000.0 : 1260000.0 : 1260000.0
# ==========================================================
# = Solver Results =
# ==========================================================
# ----------------------------------------------------------
# Problem Information
# ----------------------------------------------------------
Problem:
- Name: unknown
Lower bound: 39250323.6272
Upper bound: 39250323.6272
Number of objectives: 1
Number of constraints: 25
Number of variables: 49
Number of nonzeros: 89
Sense: maximize
# ----------------------------------------------------------
# Solver Information
# ----------------------------------------------------------
Solver:
- Status: ok
Termination condition: optimal
Statistics:
Branch and bound:
Number of bounded subproblems: 0
Number of created subproblems: 0
Error rc: 0
Time: 0.0750000476837
# ----------------------------------------------------------
# Solution Information
# ----------------------------------------------------------
Solution:
- number of solutions: 0
number of solutions displayed: 0
输入文件
param secPerTimeStep:=3600;
param T:=6;
param numReservoirs:=3;
param connectMat:=
1 1 0
1 2 1
1 3 0
2 1 0
2 2 0
2 3 1
3 1 0
3 2 0
3 3 0;
param el_price:=
1 242.16
2 242.09
3 239.3
4 231.52
5 224.25
6 219.77;
param inflow:=
1 1 5
2 1 5
3 1 5
4 1 5
5 1 5
6 1 5
1 2 5
2 2 5
3 2 5
4 2 5
5 2 5
6 2 5
1 3 5
2 3 5
3 3 5
4 3 5
5 3 5
6 3 5;
param min_Vol:=
1 0.0
2 0.0
3 0.0;
param max_Vol:=
1 66000000.0
2 16700000.0
3 2100000.0;
param min_Turb_gen:=
1 0
2 0
3 0;
param max_Turb_gen:=
1 3.31
2 5.9
3 9.0;
param min_spill:=
1 0.0
2 0.0
3 0.0;
param max_spill:=
1 10000.0
2 10000.0
3 10000.0;
param min_discharge:=
1 0.0
2 0.0
3 0.0;
param max_discharge:=
1 20.0
2 15.0
3 8.0;
param slope:=
1 0.1655
2 0.3933
3 1.125;
param energy_stored:=
1 0.000046
2 0.000109
3 0.00031;
param hourly_demand:=
1 0.0351
2 0.0335
3 0.0328
4 0.0325
5 0.0331
6 0.0357;
param P_load:=200;
解决方案
1) 因为被初始化为 0,所以总是打印零m.tubine
。在模型构建期间(即执行打印语句时),表达式的计算结果为 0。
2A)调用求解器后,结果会自动加载回模型中,因此命令instance.display()
正在打印结果。该results
对象仅在您想延迟加载解决方案时使用(这是您可以在调用求解器时设置的选项)。
2B) 不确定。您始终可以运行该命令instance.water_balance.pprint()
来确认约束表达式是否符合您的预期。
推荐阅读
- reactjs - 组件的重新渲染是否会创建其子组件的新实例?
- angularjs - 如何为 AngularJS(版本 1)的 angular-ui/ui-calendar 设置默认月份?默认情况下,它将其设置为当前月份
- android - 如何比较两个不同的 Firebase 数据库子数据项
- swift - 如何为 NSPoint 返回一个未定义的值
- r-markdown - 如何强制 RMarkdown 文档中的 Tikz 显示西里尔文字?
- python - manage.py runserver 打开 pycharm 而不是运行服务器
- c++ - 我的复制构造函数没有被调用
- javascript - PrimeNG 确认对话框无法点击,锁屏
- angular - 如何在 Angular 6 中使用 take(1)?
- c++ - 宏的逆柯里化?