2

我正在使用 Pyomo 5.6.6 和 Couenne 0.5.6 作为 MacOS 下载的可执行文件将热交换器优化问题编程为 MINLP 问题。该模型有两个决策变量,即蒸汽形式的外部供热和冷却水形式的冷却效用。

正在发生的问题是,只有当我在最佳值附近的一个相当小的窗口中设置使用热/冷却的边界时,该模型才能得到解决。否则 Couenne 说这个问题是不可行的。

有人知道为什么求解器难以解决更大的界限吗?

换热器优化模型基于扩展转运模型。

目前,热交换器网络由两股热流和两股冷流组成,它们由入口和出口温度以及它们的热容量流量定义。此外,还应通过优化计算出一股自由热流(热蒸汽)和一股冷流(冷却水),以实现热平衡,同时最大限度地减少额外热蒸汽的使用。

我在表格中设置了使用加热和冷却设施的界限作为约束 Constraint1: Q <= value1 and Constraint2: Q >= value2

问题是我已经将这些值设置为非常接近最优值,如果我对该值没有一个好主意,这是不切实际的。

模型的代码以及工作/不工作情况的示例数据和求解器输出可以在Github上找到。

我知道在我的模型中,额外供热的最小值必须为 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
;
4

1 回答 1

1

Couenne 是一个受人尊敬的求解器,但与所有求解器一样,它也有弱点。我没有仔细查看您的公式,但可能会出现接近零的变量值,出现数值问题,因此 Couenne 终止失败。

于 2019-08-14T14:57:51.923 回答