我想在 Python 中使用 pyomo 优化工业批处理过程。目标函数是最小化系统成本。在我的简化示例中,我使用随机值指定生产成本。批处理的独特之处在于,一旦系统打开,它必须运行四个或四个时间步的倍数(连续多个批次)。 down_time 不必是四的倍数。 (仅在简化问题中,实际上停机时间不应超过两个或至少 20 个时间步)。
我尝试定义一个阻止规则,这应该确保运行时%4,但它不起作用。仍然出现运行时间 > 4。如果我将约束从 >= 4 切换到 == 4(见下文),则优化根本不起作用。
import pyomo.environ as pyo
import matplotlib.pyplot as plt
# Define the model
model = pyo.ConcreteModel()
# 1. Define the model, sets, and parameters.
T = 56 # number of timesteps
production_goal = 16
model.timesteps = pyo.RangeSet(1, T)
# Assuming a simple production cost function
import random
production_cost = [random.randint(0, 100) for _ in range(T)]
# Create a sin wave for the production cost
import numpy as np
production_cost = (np.sin(np.linspace(0, 8*np.pi, T))+1)*50
# 2. Define the decision variables.
model.x = pyo.Var(model.timesteps, within=pyo.Binary) # production decision
model.y = pyo.Var(model.timesteps, within=pyo.Binary) # plant status
model.batch_over = pyo.Var(model.timesteps, within=pyo.Binary) # batch over decision
# 3. Define the objective function.
def obj_rule(model):
return sum(production_cost[t-1] * model.x[t] + model.batch_over[t] for t in model.timesteps)
model.obj = pyo.Objective(rule=obj_rule, sense=pyo.minimize)
# 4. Define the constraints.
# Total production constraint
def total_production_rule(model):
return sum(model.x[t] for t in model.timesteps) == production_goal
model.total_production_con = pyo.Constraint(rule=total_production_rule)
# Production is only possible if plant is on
def production_on_rule(model, t):
return model.x[t] == model.y[t]
model.production_on_con = pyo.Constraint(model.timesteps, rule=production_on_rule)
# Plant has to work in blocks of 4 hours
def block_rule(model, t):
if t>1 and t < T-2:
return model.y[t] + model.y[t+1] + model.y[t+2] + model.y[t+3] >= 4 * (model.y[t]-model.y[t-1])
return pyo.Constraint.Skip
model.block_con = pyo.Constraint(model.timesteps, rule=block_rule)
# 5. Solve the model using Gurobi.
solver = pyo.SolverFactory('gurobi')
results = solver.solve(model)
我要考虑的第一件事就是让你的时间周期是现在的 4 倍,然后运行 4 个周期的整个问题就会消失,但似乎你还有其他限制来激发更小的时间步长。这导致一些适度复杂的逻辑来控制工厂的运行(正如您所发现的),并且传达的约束开始快速增长,但只要您没有建模太大的时间跨度,它应该是可行的.
我不确定你的模型中的
x
和 y
到底是什么,但你在约束中将它们设置为彼此相等,所以你实际上只有 1 个变量。使用更清晰的名称!
这是伪代码中的框架思想:
有一个二进制变量表示植物何时启动,另一个表示植物是否运行。我已经发布了几个与此类似的其他答案,因此您可以在我的一些答案中搜索“跑步”,看看您会得到什么。喜欢这个。
所以:
running[t] ∈ {0, 1}
start[t] ∈ {0, 1}
为了在任何时期运行,您需要在当前或之前的 3 个时期开始......听起来像是一个限制!只有在前 3 个周期或当前周期开始时,我们才能运行:
running[t] <= sum(start[tt] for tt in range(t-3, t+1) if tt > 0)
for all t
而且我们不能在运行时任意“启动”,所以我们需要在启动发生后限制启动。只有在前 3 个周期没有开始的情况下,我们才能开始:
start[t] <= 1 - sum(start[tt] for tt in range(t-3, t) if tt > 0)
for all t
然后你可以考虑关闭窗口。如果系统关闭(如
running[t-1] - running[t] ≥ 0
所示),那么我们有一个从 [t+2, t+20]
开始新启动的排除窗口。我想我们可以对其进行编码...
sum(start[tt] for tt in range(t+2, t+21)) <= 1 - (running[t-1] - running[t])
for all t ∈ {4, ...}
尝试重构并合并类似的东西。将模型保留为“小”,例如 9 个时间段,将其打印出来并手动验证您的约束以确保它们是正确的。如果您遇到困难,请评论回来。