我有这个代码来try 将两个总体的总和与测量数据序列相匹配.

dS/dt = (a - b) * S
dR/dt = (a - b - c)* R
X(t) = S(t) + R(t)

我还想优化第一个点,它现在是固定的,我原本想使用一个新的变量,名为f,它代表01之间,代表人口12之间的初始比率. 大概是这样的:

S0 = x_meas[0] * f
R0 = x_meas[0] * (1-f)

以下是代码:

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

# data
m.time = [0,0.1,0.2,0.3,0.4,0.5,0.8,0.85,0.9,0.95,1]
x_meas = [1.1,1.2,1.56,1.77,1.89,2.1,2.3,2.5,2.7,2.2,2.1]

# parameters, single value over time horizon
p = m.Array(m.FV,3,lb=0.5,ub=10); a,b,c = p
# turn STATUS On for adjustment by solver
for fv in p:
   fv.STATUS=1

f0 = m.FV(value=0.01, lb=0, ub=1)
f0.STATUS=1
# variables
S,R,X = m.Array(m.Var,3,lb=0)
# change initial conditions
S0,R0 = [0.35,0.65]; X0 = S0+R0
S.value=S0; R.value=R0; X.value=X0

# measured values
Xm = m.Param(x_meas)

# equations
m.Equations([S.dt()==(a-b)*S,
             R.dt()==(a-b-c)*R,
             X==S+R])

# minimize difference to measurements
m.Minimize((X-Xm)**2)

m.options.IMODE = 5   # dynamic estimation
m.options.NODES = 3   # collocation nodes
m.solve(disp=False)   # display solver output

print(f'a: {a.value[0]}, b: {b.value[0]}, c: {c.value[0]}')

import matplotlib.pyplot as plt
plt.figure(figsize=(7,3))
plt.plot(m.time,S.value,'b:',linewidth=3,label='S')
plt.plot(m.time,R.value,'r--',linewidth=2,label='R')
plt.plot(m.time,X.value,'k--',label='X')
plt.plot(m.time,Xm.value,'kx',label='Xm')
plt.legend(); plt.grid(); plt.xlabel('Time')
plt.tight_layout()
plt.savefig('fit.png',dpi=300)
plt.show()

推荐答案

默认情况下,将gekko设置为初值问题,其中t=0处的值是固定的,并且方程不会在该初始点处求解.利用所计算的初始值仍然适合于该框架的一种方式是设置fixed_initial=False并且计算微分方程初始条件.然而,这并不能解决时间范围中第一个 node 的方程被停用的问题.

要克服这个问题,请try 在时间范围中设置另一个非常小的时间增量,时间步长非常小,例如1e-5.将分数f创建为FV类型,并设置STATUS=1以使用优化器计算该单个值.我在0.20.8之间加入了f的边界,只是为了让问题更有趣,它们可以改变.

# initial condition variables
f = m.FV(value=0.5,lb=0.2,ub=0.8)
f.STATUS = 1

仅在该小时间步长上激活RSf之间的关系的方程.

# activate only for initial condition
init = np.zeros(len(m.time)); init[1]=1
init = m.Param(init)
m.Equations([init*(S-x_meas[0]*f)==0,
             init*(R-x_meas[0]*(1-f))==0])

问题的其余部分保持不变.

Fit to data

from gekko import GEKKO
import numpy as np
m = GEKKO(remote=True)

# data
m.time = [0,1e-5,0.1,0.2,0.3,0.4,0.5,0.8,0.85,0.9,0.95,1]
x_meas = [1.1,1.1,1.2,1.56,1.77,1.89,2.1,2.3,2.5,2.7,2.2,2.1]

# parameters, single value over time horizon
p = m.Array(m.FV,3,lb=0.5,ub=10); a,b,c = p
# turn STATUS On for adjustment by solver
for fv in p:
   fv.STATUS=1

# variables
S,R,X = m.Array(m.Var,3,value=0.5,lb=0,fixed_initial=False)

# initial condition variables
f = m.FV(value=0.5,lb=0.2,ub=0.8)
f.STATUS = 1

# activate only for initial condition
init = np.zeros(len(m.time)); init[1]=1
init = m.Param(init)
m.Equations([init*(S-x_meas[0]*f)==0,
             init*(R-x_meas[0]*(1-f))==0])

# change initial condition for X
X.value=x_meas[0]

# measured values
Xm = m.Param(x_meas)

# equations
m.Equations([S.dt()==(a-b)*S,
             R.dt()==(a-b-c)*R,
             X==S+R])

# minimize difference to measurements
m.Minimize((X-Xm)**2)

m.options.IMODE = 5   # dynamic estimation
m.options.NODES = 2   # collocation nodes
m.options.SOLVER = 1  # APOPT solver
m.solve(disp=True)    # display solver output

print(f'a: {a.value[0]}, b: {b.value[0]}, c: {c.value[0]}')
print(f'S0: {S.value[0]}, R0: {R.value[0]}, f:{f.value[0]}')

import matplotlib.pyplot as plt
plt.figure(figsize=(7,3))
plt.plot(m.time,S.value,'b:',linewidth=3,label='S')
plt.plot(m.time,R.value,'r--',linewidth=2,label='R')
plt.plot(m.time,X.value,'k--',label='X')
plt.plot(m.time,Xm.value,'kx',label='Xm')
plt.legend(); plt.grid(); plt.xlabel('Time')
plt.tight_layout()
plt.savefig('fit.png',dpi=300)
plt.show()

它通过一个成功的解决方案解决了问题:

 Iter    Objective  Convergence
   20  1.01871E+00  1.15106E-04
   21  1.01863E+00  1.02840E-04
   22  1.01863E+00  3.60679E-09
   23  1.01863E+00  5.74752E-10
   24  1.01863E+00  5.74752E-10
 Successful solution
 
 ---------------------------------------------------
 Solver         :  APOPT (v1.0)
 Solution time  :   6.410000000323635E-002 sec
 Objective      :    1.01863407387195     
 Successful solution
 ---------------------------------------------------
 
a: 1.6769964544, b: 0.50197865393, c: 0.5
S0: 0.21999741496, R0: 0.87999405984, f:0.2

Python相关问答推荐

Polars比较了两个预设-有没有方法在第一次不匹配时立即失败

替换字符串中的多个重叠子字符串

当多个值具有相同模式时返回空

仿制药的类型铸造

试图找到Python方法来部分填充numpy数组

当使用keras.utils.Image_dataset_from_directory仅加载测试数据集时,结果不同

将数据框架与导入的Excel文件一起使用

如何使用pytest来查看Python中是否存在class attribution属性?

Python+线程\TrocessPoolExecutor

给定高度约束的旋转角解析求解

如何使regex代码只适用于空的目标单元格

旋转多边形而不改变内部空间关系

python中csv. Dictreader. fieldname的类型是什么?'

ruamel.yaml dump:如何阻止map标量值被移动到一个新的缩进行?

Polars map_使用多处理对UDF进行批处理

Python pint将1/华氏度转换为1/摄氏度°°

计算机找不到已安装的库'

使用polars. pivot()旋转一个框架(类似于R中的pivot_longer)

对于标准的原始类型注释,从键入`和`从www.example.com `?

在一个数据帧中,我如何才能发现每个行号是否出现在一列列表中?