If2 / 3 在 Gekko 中使用有限元正交搭配方法

问题描述

我目前正在使用 Gekko 库研究动态传热模型。该模型由偏微分方程组组成。如APMonitor平台所示,空间变化的微分已被离散化,而时间上的微分则通过有限元正交搭配法进行数值求解。

我有两个问题:

  1. 该模型仅使用空间中最多 3 个离散点和 NODES = 3 时间中最多 30 个离散点求解。而对于 NODES = 4,节点不遵循函数的值。什么解释了这种行为?

  2. 当使用任何 if2/3 时,模型都无法求解。测试了所有类型的求解器,但没有找到解决方案。当 m.if3 被 m.Intermediates 替换时,模型正常求解。此外,如果未指定节点数,则最多使用 n = 20 和 nt = 300 个点来求解模型。通过添加 if 和节点可以解释这种性能下降的原因是什么?模型的表述或结构是否不正确?

可以做些什么来改进?该模型需要至少用 100 个时间点和 NODES = 3 求解。

***我也想知道如何在另一个 if2/3 中使用 if2/3。

这是模型的主要部分:

import numpy as np
import data
from func_H import func_h
from func_KW import func_kw
from func_den import func_fg_cpv
from func_PG import func_pg
from func_CPV import func_cpv11,func_cpv21,func_cpv31,func_cpv41,func_cpv51,func_cpv6,func_cpv7,func_cpv8,func_cpv12,func_cpv22,func_cpv32,func_cpv42,func_cpv52
from func_CPL import func_cpl11,func_cpl12,func_cpl21,func_cpl22,func_cpl31,func_cpl32,func_cpl4,func_cpl5,func_cpl6,func_cpl71,func_cpl72,func_cpl8,func_cpl9
from func_cond_in import func_cond_inic
from func_DHW import func_dhw

import matplotlib.pyplot as plt

from gekko import GEKKO
m = GEKKO(remote=False)

zf = 0.17
tf = 768.24
dz = zf/n

n = 3
nt = 10
m.time = np.linspace(0,tf,nt)
nd = 3
####################################################################################################

u = func_cond_inic(data.tg,data.g,data.p1,data.yi[0],data.yi[1],data.yi[2],data.yi[3],data.yi[4],data.yi[5],data.yi[6],data.yi[7],n)

tg = [m.Var(u[0][i]) for i in range(n)]
g = [m.Var(u[1][i]) for i in range(n)]
pg = [m.Var(u[2][i]) for i in range(n)]

tp = [m.Var(data.tp) for i in range(n)]

y1 = [m.Var(u[3][i][0]) for i in range(n)]
y2 = [m.Var(u[4][i][0]) for i in range(n)]
y3 = [m.Var(u[5][i][0]) for i in range(n)]
y4 = [m.Var(u[6][i][0]) for i in range(n)]
y5 = [m.Var(u[7][i][0]) for i in range(n)]
y6 = [m.Var(u[8][i][0]) for i in range(n)]
y7 = [m.Var(u[9][i][0]) for i in range(n)]
y8 = [m.Var(u[10][i][0]) for i in range(n)]

y = [np.array([y1[i],y2[i],y3[i],y4[i],y5[i],y6[i],y7[i],y8[i]]) for i in range(n)]
yt = [np.transpose(y[i]) for i in range(n)]
    
x1 = [m.Var(data.xi[0]) for i in range(n)]
x2 = [m.Var(data.xi[1]) for i in range(n)]
x3 = [m.Var(data.xi[2]) for i in range(n)]
x4 = [m.Var(data.xi[3]) for i in range(n)]
x5 = [m.Var(data.xi[4]) for i in range(n)]
x6 = [m.Var(data.xi[5]) for i in range(n)]
x7 = [m.Var(data.xi[6]) for i in range(n)]
x8 = [m.Var(data.xi[7]) for i in range(n)]
x9 = [m.Var(data.xi[8]) for i in range(n)]

x = [np.array([x1[i],x2[i],x3[i],x4[i],x5[i],x6[i],x7[i],x8[i],x9[i]]) for i in range(n)]

####################################################################################################

rhog = [m.Intermediate((pg[i]*(data.mmg @ y[i])/(data.r*tg[i]))) for i in range(n)]

kw = [m.Intermediate(func_kw(g[i],tg[i],y[i],pg[i],rhog[i])) for i in range(n)]

weg = [m.Intermediate(m.exp(-3.5+(0.0549/tg[i]))) for i in range(n)]

wg = [m.Intermediate((pg[i]*data.mmg[3]*y4[i])/(data.r*tg[i])) for i in range(n)]

rw_f = [m.Intermediate(kw[i]*data.a*(weg[i]-wg[i])) for i in range(n)]

rw_m = [m.Intermediate(rw_f[i]*1000/18.01528) for i in range(n)]

dhw = [m.Intermediate(func_dhw(tg[i],tp[i])) for i in range(n)]

qcond = [m.Intermediate(rw_m[i]*dhw[i]) for i in range(n)]

# # Heat capacity 
cpv1 = [m.if2(tg[i]-700,func_cpv11(tg[i]),func_cpv12(tg[i])) for i in range(n)]
cpv2 = [m.if2(tg[i]-500,func_cpv21(tg[i]),func_cpv22(tg[i])) for i in range(n)]
cpv3 = [m.if2(tg[i]-1200,func_cpv31(tg[i]),func_cpv32(tg[i])) for i in range(n)]
cpv4 = [m.if2(tg[i]-1700,func_cpv41(tg[i]),func_cpv42(tg[i])) for i in range(n)]
cpv5 = [m.if2(tg[i]-1300,func_cpv51(tg[i]),func_cpv52(tg[i])) for i in range(n)]
# cpv1 = [m.Intermediate(func_cpv11(tg[i])) for i in range(n)]    
# cpv2 = [m.Intermediate(func_cpv21(tg[i])) for i in range(n)]
# cpv3 = [m.Intermediate(func_cpv31(tg[i])) for i in range(n)]
# cpv4 = [m.Intermediate(func_cpv41(tg[i])) for i in range(n)]
# cpv5 = [m.Intermediate(func_cpv51(tg[i])) for i in range(n)]
cpv6 = [m.Intermediate(func_cpv6(tg[i])) for i in range(n)]
cpv7 = [m.Intermediate(func_cpv7(tg[i])) for i in range(n)]
cpv8 = [m.Intermediate(func_cpv8(tg[i])) for i in range(n)]

cpv = [[cpv1[i],cpv2[i],cpv3[i],cpv4[i],cpv5[i],cpv6[i],cpv7[i],cpv8[i]] for i in range(n)]

fg_cpv = [m.Intermediate(func_fg_cpv(g[i],cpv[i],y[i])) for i in range(n)]

h = [m.Intermediate(func_h(g[i],cpv[i])) for i in range(n)]

qconv = [m.Intermediate((data.a*h[i]*(tg[i]-tp[i]))) for i in range(n)]

p = [m.Intermediate(func_pg(g[i],rhog[i])) for i in range(n)]

# # Heat capacity 
cpl1 = [m.if2(tp[i]-950,func_cpl11(tp[i]),func_cpl12(tp[i])) for i in range(n)]    
cpl2 = [m.if2(tp[i]-900,func_cpl21(tp[i]),func_cpl22(tp[i])) for i in range(n)]
cpl3 = [m.if2(tp[i]-847,func_cpl31(tp[i]),func_cpl32(tp[i])) for i in range(n)]
# cpl1 = [m.Intermediate(func_cpl11(tp[i])) for i in range(n)]
# cpl2 = [m.Intermediate(func_cpl21(tp[i])) for i in range(n)]
# cpl3 = [m.Intermediate(func_cpl31(tp[i])) for i in range(n)]
cpl4 = [m.Intermediate(func_cpl4(tp[i])) for i in range(n)]
cpl5 = [m.Intermediate(func_cpl5(tp[i])) for i in range(n)]
cpl6 = [m.Intermediate(func_cpl6(tp[i])) for i in range(n)]
cpl7 = [m.if2(tp[i]-500,func_cpl71(tp[i]),func_cpl72(tp[i])) for i in range(n)]
# cpl7 = [m.Intermediate(func_cpl71(tp[i])) for i in range(n)]
cpl8 = [m.Intermediate(func_cpl8(tp[i])) for i in range(n)]
cpl9 = [m.Intermediate(func_cpl9(tp[i])) for i in range(n)]

cpl = [[cpl1[i],cpl2[i],cpl3[i],cpl4[i],cpl5[i],cpl6[i],cpl7[i],cpl8[i],cpl9[i]] for i in range(n)]

rhop1 = [m.Intermediate((x1[i]*data.rhoc[0]*(1-data.e))) for i in range(n)]
rhop2 = [m.Intermediate((x2[i]*data.rhoc[1]*(1-data.e))) for i in range(n)]
rhop3 = [m.Intermediate((x3[i]*data.rhoc[2]*(1-data.e))) for i in range(n)]
rhop4 = [m.Intermediate((x4[i]*data.rhoc[3]*(1-data.e))) for i in range(n)]
rhop5 = [m.Intermediate((x5[i]*data.rhoc[4]*(1-data.e))) for i in range(n)]
rhop6 = [m.Intermediate((x6[i]*data.rhoc[5]*(1-data.e))) for i in range(n)]
rhop7 = [m.Intermediate((x7[i]*data.rhoc[6]*(1-data.e))) for i in range(n)]
rhop8 = [m.Intermediate((x8[i]*data.rhoc[7]*(1-data.e))) for i in range(n)]
rhop9 = [m.Intermediate((x9[i]*data.rhoc[8]*(1-data.e))) for i in range(n)]
rhop = [np.array([rhop1[i],rhop2[i],rhop3[i],rhop4[i],rhop5[i],rhop6[i],rhop7[i],rhop8[i],rhop9[i]]) for i in range(n)]

rho_cpl = [m.Intermediate((rhop[i] @ cpl[i])) for i in range(n)]

####################################################################################################

m.Equation(tg[0] == data.tg)
m.Equation([tg[i] == tg[i-1] + dz*(qcond[i-1]-qconv[i-1])/fg_cpv[i-1] for i in range(1,n)])

m.Equation(g[0] == data.g)
m.Equation([g[i] == g[i-1] + dz*rw_f[i-1] for i in range(1,n)])

m.Equation(pg[0] == data.p1)
m.Equation([pg[i] == pg[i-1] + dz*p[i-1] for i in range(1,n)])
    
m.Equation(y1[0] == data.yi[0])
m.Equation(y2[0] == data.yi[1])
m.Equation(y3[0] == data.yi[2])
m.Equation(y4[0] == data.yi[3])
m.Equation(y5[0] == data.yi[4])
m.Equation(y6[0] == data.yi[5])
m.Equation(y7[0] == data.yi[6])
m.Equation(y8[0] == data.yi[7])
m.Equation([y1[i] == y1[i-1] - dz*rw_f[i-1]*y1[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y2[i] == y2[i-1] - dz*rw_f[i-1]*y2[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y3[i] == y3[i-1] - dz*rw_f[i-1]*y3[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y4[i] == y4[i-1] + dz*rw_f[i-1]*(1-y4[i-1])/g[i-1] for i in range(1,n)])
m.Equation([y5[i] == y5[i-1] - dz*rw_f[i-1]*y5[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y6[i] == y6[i-1] - dz*rw_f[i-1]*y6[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y7[i] == y7[i-1] - dz*rw_f[i-1]*y7[i-1]/g[i-1] for i in range(1,n)])
m.Equation([y8[i] == y8[i-1] - dz*rw_f[i-1]*y8[i-1]/g[i-1] for i in range(1,n)])

m.Equation([tp[i].dt() == ((qconv[i]-qcond[i])/rho_cpl[i]) for i in range(n)])

m.Equation([x1[i].dt() == 0 for i in range(n)])
m.Equation([x2[i].dt() == 0 for i in range(n)])
m.Equation([x3[i].dt() == 0 for i in range(n)])
m.Equation([x4[i].dt() == 0 for i in range(n)])
m.Equation([x5[i].dt() == 0 for i in range(n)])
m.Equation([x6[i].dt() == 0 for i in range(n)])
m.Equation([x7[i].dt() == (-rw_f[i]/(rhop1[i]+rhop2[i]+rhop3[i]+rhop4[i]+rhop5[i]+rhop6[i]+rhop7[i]+rhop8[i]+rhop9[i])) for i in range(n)])
m.Equation([x8[i].dt() == 0 for i in range(n)])
m.Equation([x9[i].dt() == 0 for i in range(n)])

####################################################################################################
m.options.imode = 4
m.options.soLVER = 1
m.options.NODES = nd
m.options.REDUCE = 2
m.options.MAX_ITER = 250
m.solve()

完整模型可从以下链接获得:

https://drive.google.com/drive/folders/1_AFnBPZ_mcEhwZb80a3VYOcg8PVXP5Qj?usp=sharing

提前致谢。

解决方法

对于复杂的问题,第一个策略是仅用小步长(例如 0.01)解决一个时间步长(2 个点)。使用 m.options.SOLVER=1 切换到 APOPT 求解器也有助于找到问题的根源,因为它能够更好地识别不可行性。

m.time = np.linspace(0,0.01,2)

求解器报告一个不成功的解,因为在一次迭代后目标是 Inf(无穷大)。

 Number of state variables:    510
 Number of total equations: -  402
 Number of slack variables: -  0
 ---------------------------------------
 Degrees of freedom       :    108
 
 ----------------------------------------------
 Dynamic Control with APOPT Solver
 ----------------------------------------------
 
 Iter    Objective  Convergence
    0  1.67459E+11  1.01245E+05
    1         +Inf  1.01245E+05
 No feasible solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :  1.1939000000000002 sec
 Objective      :  108000.
 Unsuccessful with error code  0
 ---------------------------------------------------
 
 Creating file: infeasibilities.txt
 Use command apm_get(server,app,'infeasibilities.txt') to retrieve file
 @error: Solution Not Found

运行目录显示附加信息。运行目录为 m.path 或在解决命令之前使用 m.open_folder() 打开。

m.open_folder()
m.solve()

打开 infeasibilities.txt 文件显示几个中间体被零除。

rhog = [m.Intermediate((pg[i]*(data.mmg @ y[i])/(data.r*tg[i]))) for i in range(n)]
wg = [m.Intermediate((pg[i]*data.mmg[3]*y4[i])/(data.r*tg[i])) for i in range(n)]

下限有助于避免被零除,例如:

tg = [m.Var(u[0][i],lb=0.1) for i in range(n)]

即使有这个下界,还有另一个表达式可以达到无穷大。这个策略可以用来连续发现模型的问题。