我正在使用Pyomo 5.6.6和Couenne 0.5.6作为MacOS的下载可执行文件,将热交换器优化问题编程为MINLP问题。该模型具有两个决策变量,分别是蒸汽形式的外部供热和冷却水形式的制冷效用。
出现的问题是,仅当我在最佳值附近的一个很小的窗口中设置使用热/制冷的边界时,模型才能解决。否则,库恩(Couenne)认为该问题不可行。
有人知道为什么求解器在更大范围内难以求解吗?
热交换器优化模型基于扩展转运模型。
现在,热交换器网络由两个热流和两个冷流组成,这两个流由入口和出口温度及其热容量流速定义。此外,优化过程中应计算出一条自由热流(热蒸汽)和一条冷流(冷却水),以实现热量平衡,同时尽量减少使用额外的热蒸汽。
我以Constraint1: Q <= value1 and Constraint2: Q >= value2
的形式设置了加热和冷却工具的使用限制。
问题是我将这些值设置为非常接近最佳值,如果我对该值不太了解,这是不切实际的。
可以在Github here上找到模型的代码以及用于工作/不工作情况的示例数据和求解器输出。
我知道在我的模型中附加供热的最小值必须为950。但是,仅当我将范围设置为1到1100之间时,才计算此值。 0和5000求解器返回不可行。
在最佳情况下,我想将额外的加热和冷却设置为“非负”,然后计算其余的。
该模型的代码为:
import sys
sys.path.append('Here comes the path of the data.dat file')
from pyomo.environ import *
model = AbstractModel(name="(HEN_MODEL_V1)")
# hot streams
model.I = Set()
# cold streams
model.J = Set()
# k = grid point and kk =temperature interval boundaries
model.K = Set()
# hot/ cold utilities
model.I_HU = Set(within=model.I)
model.J_CU = Set(within=model.J)
# hot process streams
model.I_P = Set(within=model.I)
model.J_P = Set(within=model.J)
# temperature intervals
model.K_I = Set(within=model.K)
# ----- Parameters ----
# Minimal temperature approach
model.MAT = Param()
# Upper bound for inlet temperature
model.ai = Param(model.I)
model.aj = Param(model.J)
# Upperbound for outlet temperature
model.bi = Param(model.I)
model.bj = Param(model.J)
#Upperbound for heat steam
model.yi = Param(model.I, model.K_I)
model.yj = Param(model.J, model.K_I)
#Upperbounds for R and D
model.yyi = Param(model.I, model.K_I)
model.yyj = Param(model.J, model.K_I)
# Parameter for in and outlet temperature constraints
model.T_H_IN_CON = Param(model.I)
model.T_H_OUT_CON = Param(model.I)
model.T_C_IN_CON = Param(model.J)
model.T_C_OUT_CON = Param(model.J)
model.F_CON = Param(model.I)
model.F2_CON = Param(model.J)
# ----- Variables-----
# Gridtemperature
model.T = Var(model.K, within=NonNegativeReals)
# Residual heat of heat steam i in intervall k
model.R = Var(model.I, model.K_I, within=NonNegativeReals)
# Deficite heat of cold stream j in intervall k
model.D = Var(model.J, model.K_I, within=NonNegativeReals)
# Exchanged Heat from i to j in intervall k
model.Q = Var(model.I, model.J, model.K_I, within=NonNegativeReals)
# Heat in Cold stream j
model.QC = Var(model.J, model.K_I, within=NonNegativeReals)
#Disaggregates Cold streams j
model.QC1 = Var(model.J, model.K_I, within=NonNegativeReals)
model.QC2 = Var(model.J, model.K_I, within=NonNegativeReals)
# Heat in hot stream i
model.QH = Var(model.I, model.K_I, within=NonNegativeReals)
# Disaggregates hot streams i
model.QH1 = Var(model.I, model.K_I, within=NonNegativeReals)
model.QH2 = Var(model.I, model.K_I, within=NonNegativeReals)
# Heat Capacity flows of i and j
model.FH = Var(model.I_P, within=NonNegativeReals)
model.FC = Var(model.J, within=NonNegativeReals)
# Used additional Steam
model.steam = Var()
# Binary variables X for Inlet-Temp on Gridpoint
# Binary variables Y for Outlet-Temp in Grid k
# Binary variales Z for Stream through intervall k
model.XC = Var(model.J, model.K, within=Binary)
model.XH = Var(model.I, model.K, within=Binary)
model.YC = Var(model.J, model.K_I, within=Binary)
model.YH = Var(model.I, model.K_I, within=Binary)
model.ZC = Var(model.J, model.K_I, within=Binary)
model.ZH = Var(model.I, model.K_I, within=Binary)
# Disaggregated Inlettemperatures from Cold and Hot stream
model.TIN_HD = Var(model.I, model.K, within=NonNegativeReals)
model.TIN_CD = Var(model.J, model.K, within=NonNegativeReals)
# Inlettemperatures from Cold and hot stream
model.TIN_H = Var(model.I, within=NonNegativeReals)
model.TIN_C = Var(model.J, within=NonNegativeReals)
# Outlettemperature from Hot and cold streams
model.TOUT_HD = Var(model.I, model.K_I, within=NonNegativeReals)
model.TOUT_CD = Var(model.J, model.K_I, within=NonNegativeReals)
# Outlettemperatures from Cold and hot stream
model.TOUT_H = Var(model.I, within=NonNegativeReals)
model.TOUT_C = Var(model.J, within=NonNegativeReals)
# ------ Constraints ------
# DEFINITION OF THE INLET AND OUTLET TEMPERATURES OF THE HOT AND COLD STREAMS
# THAT HAVE TO BE MET
def T1_rule(model, i):
return model.TIN_H[i] == model.T_H_IN_CON[i]
def T2_rule(model,i):
return model.TOUT_H[i] == model.T_H_OUT_CON[i]
def T3_rule(model,j):
return model.TIN_C[j] == model.T_C_IN_CON[j]
def T4_rule(model, j):
return model.TOUT_C[j] == model.T_C_OUT_CON[j]
model.T1_con = Constraint(model.I, rule=T1_rule)
model.T2_con = Constraint(model.I, rule=T2_rule)
model.T3_con = Constraint(model.J, rule=T3_rule)
model.T4_con = Constraint(model.J, rule=T4_rule)
# DEFINITION OF THE FLOW CAPACITIES OF THE HEAT AND COLD PROCESS STREAMS
# DEFINTION OF THE UPPER AND LOWER BOUNDS OF THE FLOW CAPACITY OF THE
# COOLING ULTILITY
def F1_rule(model, i):
return model.FH[i] == model.F_CON[i]
def F2_rule_a(model,j):
return model.FC[j] == model.F2_CON[j]
def F2_rule_b(model,j):
return model.FC[j] >= 0
def F2_rule_c(model,j):
return model.FC[j] <= 5000
model.F1_con = Constraint(model.I_P, rule=F1_rule)
model.F2_con_a = Constraint(model.J_P, rule=F2_rule_a)
model.F2_con_b = Constraint(model.J_CU, rule=F2_rule_b)
model.F2_con_c = Constraint(model.J_CU, rule=F2_rule_c)
############ GLG 1 + 2 ################
# DEFINITION OF HEAT CASCADE
def Rcas_rule(model,i,k):
if k > 1:
return model.R[i,k] + sum(model.Q[i,j,k] for j in model.J) == model.R[i,k-1] + model.QH[i,k]
else:
return model.R[i,k] + sum(model.Q[i,j,k] for j in model.J) == model.QH[i,k]
def Dcas_rule(model,j,k):
a=len(model.K_I)
if k < a:
return model.D[j,k] + sum(model.Q[i,j,k] for i in model.I) == model.D[j,k+1] + model.QC[j,k]
else:
return model.D[j,k] + sum(model.Q[i,j,k] for i in model.I) == model.QC[j,k]
model.Rcas_con = Constraint(model.I, model.K_I, rule=Rcas_rule)
model.Dcas_con = Constraint(model.J, model.K_I, rule=Dcas_rule)
######### GLG 3 ############
# DEFINITION OF GRIDPOINT TEMPERATURES
def T_k_rule(model,k):
a = len(model.K)
if k < a-1:
return model.T[k] >= model.T[k+1]
else:
return model.T[k] <= model.T[k-1]
model.T_k_con = Constraint(model.K, rule=T_k_rule)
######### GLG 4 - 7 ###########
# DISAGGREGATED HOT INLET TEMPERATURES
# ASSIGNMENT TO GRIDPOINT TEMPERATURES
def TIN_Hot(model,i):
return sum(model.TIN_HD[i,k] for k in model.K) == model.TIN_H[i]
def THD_1(model,i,k):
return model.TIN_HD[i,k] >= model.T[k] - model.ai[i] * (1-model.XH[i,k])
def THD_2(model,i,k):
return model.TIN_HD[i,k] <= model.T[k]
def THD_3(model,i,k):
return model.TIN_HD[i,k] <= model.ai[i] * model.XH[i,k]
model.THIN1 = Constraint(model.I, rule=TIN_Hot)
model.THIN2 = Constraint(model.I, model.K, rule=THD_1)
model.THIN3 = Constraint(model.I, model.K, rule=THD_2)
model.THIN4 = Constraint(model.I, model.K, rule=THD_3)
#
########## GLG 8 - 11 #############
# DISSAGREGATED COLD INLET TEMPERATURES
# ASSIGMENT TO GRIDPOINT TEMPERATUES
def TIN_Cold(model,j):
return sum(model.TIN_CD[j,k] for k in model.K) == model.TIN_C[j]
# return model.TIN_C[j] == sum(model.TIN_CD[j,k] for k in model.K)
def TCD_1(model,j,k):
return model.TIN_CD[j,k] >= model.T[k] - model.MAT - model.aj[j] * (1-model.XC[j,k])
def TCD_2(model,j,k):
return model.TIN_CD[j,k] <= model.T[k] - model.MAT
def TCD_3(model,j,k):
return model.TIN_CD[j,k] <= model.aj[j] * model.XC[j,k]
model.TCIN1 = Constraint(model.J, rule=TIN_Cold)
model.TCIN2 = Constraint(model.J, model.K, rule=TCD_1)
model.TCIN3 = Constraint(model.J, model.K, rule=TCD_2)
model.TCIN4 = Constraint(model.J, model.K, rule=TCD_3)
#
######### GLG 12 - 15 ##############
# DISSAGREGATED HOT OUTLET TEMPERATURES
# ASSIGMENT TO TEMPERATURE INTERVALS
def TOUT_Hot(model,i):
return sum(model.TOUT_HD[i,k] for k in model.K_I) == model.TOUT_H[i]
def THD_11(model,i,k):
return model.TOUT_HD[i,k] >= model.T[k] - model.bi[i] * (1-model.YH[i,k])
def THD_22(model,i,k):
return model.TOUT_HD[i,k] <= model.T[k-1] # -1 Funktuniert sicher nicht
def THD_33(model,i,k):
return model.TOUT_HD[i,k] <= model.bi[i] * model.YH[i,k]
model.THOUT1 = Constraint(model.I, rule=TOUT_Hot)
model.THOUT2 = Constraint(model.I, model.K_I, rule=THD_11)
model.THOUT3 = Constraint(model.I, model.K_I, rule=THD_22)
model.THOUT4 = Constraint(model.I, model.K_I, rule=THD_33)
#
#
######### GLG 16 - 19 ###########
# DISAGGREGATED COLD OUTLET TEMPERATURES
# ASSIGNMENT TO TEMPERATURE INVERTALS
def TOUT_Cold(model,j):
return sum(model.TOUT_CD[j,k] for k in model.K_I) == model.TOUT_C[j]
def TCD_11(model,j,k):
return model.TOUT_CD[j,k] >= model.T[k] - model.MAT - model.bj[j] * (1-model.YC[j,k])
def TCD_22(model,j,k):
return model.TOUT_CD[j,k] <= model.T[k-1] # Auch hier -1 in der Klammer
def TCD_33(model,j,k):
return model.TOUT_CD[j,k] <= model.bj[j] * model.YC[j,k]
model.TCOUT1 = Constraint(model.J, rule=TOUT_Cold)
model.TCOUT2 = Constraint(model.J, model.K_I, rule=TCD_11)
model.TCOUT3 = Constraint(model.J, model.K_I, rule=TCD_22)
model.TCOUT4 = Constraint(model.J, model.K_I, rule=TCD_33)
############ GLG 20 - 25 ###############
# BINARY CONSTRAINTS FÜR TEMPERATURE GRID
# Constraints for Binary Variables of Temperature Grid
def XH_rule(model,i):
return sum(model.XH[i,k] for k in model.K) == 1
def XC_rule(model,j):
return sum(model.XC[j,k] for k in model.K) == 1
def YH_rule(model,i):
return sum(model.YH[i,k] for k in model.K_I) == 1
def YC_rule(model,j):
return sum(model.YC[j,k] for k in model.K_I) == 1
def ZH_rule(model,i,k):
if k==1:
return model.ZH[i,k] == model.XH[i,k-1] - model.YH[i,k] # Auch hier die -1
else:
return model.ZH[i,k] == model.ZH[i,k-1] + model.XH[i,k-1] - model.YH[i,k] # Auch hier die -1
def ZC_rule(model,j,k):
temp = len(model.K_I)
if k < temp:
return model.ZC[j,k] == model.ZC[j,k+1] + model.XC[j,k] - model.YC[j,k]
else:
return model.ZC[j,k] == model.XC[j,k] - model.YC[j,k]
model.XH_con = Constraint(model.I, rule=XH_rule)
model.XC_con = Constraint(model.J, rule=XC_rule)
model.YH_con = Constraint(model.I, rule=YH_rule)
model.YC_con = Constraint(model.J, rule=YC_rule)
model.ZH_con = Constraint(model.I, model.K_I, rule=ZH_rule)
model.ZC_con = Constraint(model.J, model.K_I, rule=ZC_rule)
############### GLG 26 - 32 ################
# DISAGGRATED HEAT LOADS IN Q1 IF HEAT GOES THROUGH k AND Q2 if PARTIAL SPANS k
# Constraints for disaggregated Heat streams
def QH_rule(model,i,k):
return model.QH[i,k] == model.QH1[i,k] + model.QH2[i,k]
###### QH1 ######
def QH2_rule(model,i,k):
return model.QH1[i,k] >= model.FH[i] * (model.T[k-1] - model.T[k]) - model.yi[i,k] * (1-model.ZH[i,k]) # Hier wieder -1
def QH3_rule(model,i,k):
return model.QH1[i,k] <= model.FH[i] * (model.T[k-1] - model.T[k]) # hier wieder die -1
def QH4_rule(model,i,k):
return model.QH1[i,k] <= model.yi[i,k] * model.ZH[i,k]
###### QH2 ######
def QH5_rule(model,i,k):
return model.QH2[i,k] >= model.FH[i] * (model.T[k-1] - model.TOUT_HD[i,k]) - model.yi[i,k] * (1-model.YH[i,k])
def QH6_rule(model,i,k):
return model.QH2[i,k] <= model.FH[i] * (model.T[k-1] - model.TOUT_HD[i,k]) + model.yi[i,k] * (1-model.YH[i,k])
def QH7_rule(model,i,k):
return model.QH2[i,k] <= model.yi[i,k] * model.YH[i,k]
model.QH_con = Constraint(model.I_P, model.K_I, rule=QH_rule)
model.QH2_con = Constraint(model.I_P, model.K_I, rule=QH2_rule)
model.QH3_con = Constraint(model.I_P, model.K_I, rule=QH3_rule)
model.QH4_con = Constraint(model.I_P, model.K_I, rule=QH4_rule)
model.QH5_con = Constraint(model.I_P, model.K_I, rule=QH5_rule)
model.QH6_con = Constraint(model.I_P, model.K_I, rule=QH6_rule)
model.QH7_con = Constraint(model.I_P, model.K_I, rule=QH7_rule)
############### GLG 33 ###################
# HEAT LOAD FOR HEAT UTILITY
def QH8_rule(model,i,k):
return model.QH[i,k] <= model.yi[i,k] * model.XH[i,k-1]
model.QH8_con = Constraint(model.I_HU, model.K_I, rule=QH8_rule)
############## GLG 34 - 40 #####################
# DISAGGREGATED COLD HEAT LOADS; Q1 IF COLD GOES THROUGH k , Q2 IF IT ENDS THERE
# Constraints for disaggregated Cold streams
def QC_rule(model,j,k):
return model.QC[j,k] == model.QC1[j,k] + model.QC2[j,k]
####### QC1 #########
def QC2_rule(model,j,k):
return model.QC1[j,k] >= model.FC[j] * (model.T[k-1] - model.T[k]) - model.yj[j,k] * (1 - model.ZC[j,k]) # Hier wieder -1
def QC3_rule(model,j,k):
return model.QC1[j,k] <= model.FC[j] * (model.T[k-1] - model.T[k]) # hier wieder die -1
def QC4_rule(model,j,k):
return model.QC1[j,k] <= model.yj[j,k] * model.ZC[j,k]
####### QC2 ###########
def QC5_rule(model,j,k):
return model.QC2[j,k] >= model.FC[j] * (model.TOUT_CD[j,k] - model.T[k] + model.MAT) - model.yj[j,k] * (1 - model.YC[j,k])
def QC6_rule(model,j,k):
return model.QC2[j,k] <= model.FC[j] * (model.TOUT_CD[j,k] - model.T[k] + model.MAT) + model.yj[j,k] * (1 - model.YC[j,k])
def QC7_rule(model,j,k):
return model.QC2[j,k] <= model.yj[j,k] * model.YC[j,k]
model.QC_con = Constraint(model.J, model.K_I, rule=QC_rule)
model.QC2_con = Constraint(model.J, model.K_I, rule=QC2_rule)
model.QC3_con = Constraint(model.J, model.K_I, rule=QC3_rule)
model.QC4_con = Constraint(model.J, model.K_I, rule=QC4_rule)
###
model.QC5_con = Constraint(model.J, model.K_I, rule=QC5_rule)
model.QC6_con = Constraint(model.J, model.K_I, rule=QC6_rule)
model.QC7_con = Constraint(model.J, model.K_I, rule=QC7_rule)
###### GLG 41 + 42 #########
# RESIDUAL HEAT AND DEFIZIT SHOULD BE BELOW A GIVEN UPPER BOUND
#####
def R_rule(model, i, k):
temp=len(model.K_I)
if k < temp:
return model.R[i,k] <= model.yyi[i,k] * sum(model.XH[i,kk] for kk in model.K if kk<= k-1)
else:
return model.R[i,k] == 0
def D_rule(model, j, k):
if k > 1:
return model.D[j,k] <= model.yyj[j,k] * (1 - sum(model.XC[j,kk] for kk in model.K if kk <= k-1))
else:
return model.D[j,k] == 0
model.R1_con = Constraint(model.I, model.K_I, rule=R_rule)
model.D1_con = Constraint(model.J, model.K_I, rule=D_rule)
#####
# DEFINITION OF LOWER AND UPPER BOUND OF STEAM- HEAT THAT CAN BE USED
#####
def Steam_lb(model,):
return model.QH[3,1] >= 1
def Steam_ub(model,):
return model.QH[3,1] <= 1500
model.St_lb=Constraint(rule=Steam_lb)
model.St_ub=Constraint(rule=Steam_ub)
#####
# DEFINITION OF ADDITIONAL VARIABLE TO DISPLAY THE OBJECTIVE VALUE
####
def Steam_use(model):
return model.steam == sum(model.QH[3,k] for k in model.K_I)
model.Steam_use_con = Constraint(rule=Steam_use)
######
# DEFINITION OF OBJECTIVE RULE: MINIMIZE THE USAGE OF ADDITIONAL STEAM
####
def obj_rule(model):
return sum(model.QH[3,k] for k in model.K_I)
model.objective= Objective(rule=obj_rule)
#
#-------------------------Solving---------------------------------------------
#--------------------------------------------------------------------
instance= model.create_instance('data.dat')
solver = SolverFactory('couenne')
results = solver.solve(instance, tee=True)
instance.steam.pprint()
将数据文件中的文本保存为上述代码指定的路径中的“ data.dat”:
set K := 0 1 2 3 4 5;
set K_I := 1 2 3 4 5;
set I := 1 2 3;
set J := 1 2 3;
set I_P := 1 2;
set J_P := 1 2;
set I_HU := 3;
set J_CU := 3;
param MAT := 10;
param T_H_IN_CON :=
1 600
2 590
3 680
;
param T_H_OUT_CON :=
1 370
2 400
3 680
;
param T_C_OUT_CON :=
1 650
2 490
3 320
;
param T_C_IN_CON :=
1 400
2 350
3 300
;
param ai :=
1 1000
2 1000
3 1000
;
param aj :=
1 1000
2 1000
3 1000
;
param bi :=
1 1000
2 1000
3 1000
;
param bj :=
1 1000
2 1000
3 1000
;
param yi :=
1 1 100000
1 2 100000
1 3 100000
1 4 100000
1 5 100000
2 1 100000
2 2 100000
2 3 100000
2 4 100000
2 5 100000
3 1 100000
3 2 100000
3 3 100000
3 4 100000
3 5 100000
;
param yj :=
1 1 100000
1 2 100000
1 3 100000
1 4 100000
1 5 100000
2 1 100000
2 2 100000
2 3 100000
2 4 100000
2 5 100000
3 1 100000
3 2 100000
3 3 100000
3 4 100000
3 5 100000
;
param yyi :=
1 1 100000
1 2 100000
1 3 100000
1 4 100000
1 5 100000
2 1 100000
2 2 100000
2 3 100000
2 4 100000
2 5 100000
3 1 100000
3 2 100000
3 3 100000
3 4 100000
3 5 100000
;
param yyj :=
1 1 100000
1 2 100000
1 3 100000
1 4 100000
1 5 100000
2 1 100000
2 2 100000
2 3 100000
2 4 100000
2 5 100000
3 1 100000
3 2 100000
3 3 100000
3 4 100000
3 5 100000
;
param F_CON :=
1 10
2 20
;
param F2_CON :=
1 15
2 14
;
答案 0 :(得分:1)
Couenne是一个受人尊敬的求解器,但与所有求解器一样,它也有缺点。我没有仔细研究您的表述,但是可能变量值接近于零,出现数值问题,因此Couenne终止失败。