具有时间序列缺失值的常微分方程系统的Pyomo参数估计

2024-05-13 20:55:19 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个由7个方程组成的ODE系统,用于解释一组特定的微生物动力学形式:

其中是所涉及的不同化学和微生物物种(甚至是化合物的子指数),是产率系数,是伪反应:

我用Pyomo来估计我所有的未知参数,基本上是所有的屈服系数和动力学常数(总共15个)。在

当与每个动态变量的完整实验时间序列一起使用时,以下代码可以完美地工作:

from pyomo.environ import *
from pyomo.dae import *

m = AbstractModel()
m.t = ContinuousSet()   
m.MEAS_t = Set(within=m.t)  # Measurement times, must be subset of t
m.x1_meas = Param(m.MEAS_t)
m.x2_meas = Param(m.MEAS_t)
m.x3_meas = Param(m.MEAS_t)
m.x4_meas = Param(m.MEAS_t)
m.x5_meas = Param(m.MEAS_t)
m.x6_meas = Param(m.MEAS_t)
m.x7_meas = Param(m.MEAS_t)

m.x1 = Var(m.t,within=PositiveReals)
m.x2 = Var(m.t,within=PositiveReals)
m.x3 = Var(m.t,within=PositiveReals)
m.x4 = Var(m.t,within=PositiveReals)
m.x5 = Var(m.t,within=PositiveReals)
m.x6 = Var(m.t,within=PositiveReals)
m.x7 = Var(m.t,within=PositiveReals)

m.k1 = Var(within=PositiveReals)
m.k2 = Var(within=PositiveReals)
m.k3 = Var(within=PositiveReals)
m.k4 = Var(within=PositiveReals)
m.k5 = Var(within=PositiveReals)
m.k6 = Var(within=PositiveReals)
m.k7 = Var(within=PositiveReals)
m.k8 = Var(within=PositiveReals)
m.k9 = Var(within=PositiveReals)
m.y1 = Var(within=PositiveReals)
m.y2 = Var(within=PositiveReals)
m.y3 = Var(within=PositiveReals)
m.y4 = Var(within=PositiveReals)
m.y5 = Var(within=PositiveReals)
m.y6 = Var(within=PositiveReals)

m.x1dot = DerivativeVar(m.x1,wrt=m.t)
m.x2dot = DerivativeVar(m.x2,wrt=m.t)
m.x3dot = DerivativeVar(m.x3,wrt=m.t)
m.x4dot = DerivativeVar(m.x4,wrt=m.t)
m.x5dot = DerivativeVar(m.x5,wrt=m.t)
m.x6dot = DerivativeVar(m.x6,wrt=m.t)
m.x7dot = DerivativeVar(m.x7,wrt=m.t)

def _init_conditions(m):
    yield m.x1[0] == 51.963
    yield m.x2[0] == 6.289
    yield m.x3[0] == 0
    yield m.x4[0] == 6.799
    yield m.x5[0] == 0
    yield m.x6[0] == 4.08
    yield m.x7[0] == 0
m.init_conditions=ConstraintList(rule=_init_conditions)


def _x1dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x1dot[i] == - m.y1*m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.y2*m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i])
m.x1dotcon = Constraint(m.t, rule=_x1dot)

def _x2dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x2dot[i] ==  m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.k7*m.x2[i]*m.x3[i]
m.x2dotcon = Constraint(m.t, rule=_x2dot)

def _x3dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x3dot[i] ==  m.y3*m.k1*m.x1[i]*m.x2[i]/(m.k2+m.x1[i]) - m.y4*m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i])
m.x3dotcon = Constraint(m.t, rule=_x3dot)

def _x4dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x4dot[i] == m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i]) - m.k8*m.x4[i]*m.x3[i]
m.x4dotcon = Constraint(m.t, rule=_x4dot)

def _x5dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x5dot[i] == m.y5*m.k3*m.x1[i]*m.x4[i]/(m.k4+m.x1[i])
m.x5dotcon = Constraint(m.t, rule=_x5dot)

def _x6dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x6dot[i] == m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i]) - m.k9*m.x6[i]*m.x7[i]
m.x6dotcon = Constraint(m.t, rule=_x6dot)

def _x7dot(m,i):
    if i==0:
        return Constraint.Skip
    return m.x7dot[i] == m.y6*m.k5*m.x3[i]*m.x6[i]/(m.k6+m.x3[i])
m.x7dotcon = Constraint(m.t, rule=_x7dot)

def _obj(m):
    return sum((m.x1[i]-m.x1_meas[i])**2+(m.x2[i]-m.x2_meas[i])**2+(m.x3[i]-m.x3_meas[i])**2+(m.x4[i]-m.x4_meas[i])**2+(m.x5[i]-m.x5_meas[i])**2+(m.x6[i]-m.x6_meas[i])**2+(m.x7[i]-m.x7_meas[i])**2 for i in m.MEAS_t)
m.obj = Objective(rule=_obj)

m.pprint()

instance = m.create_instance('exp.dat')
instance.t.pprint()

discretizer = TransformationFactory('dae.collocation')
discretizer.apply_to(instance,nfe=30)#,ncp=3)

solver=SolverFactory('ipopt')

results = solver.solve(instance,tee=True)

然而,我正在尝试在另一个实验数据中运行相同的估计程序,这些数据在某些动态变量的一个或最多两个时间序列的末尾有缺失值。在

换句话说,这些完整的实验数据看起来像(在.dat文件中):

^{2}$

虽然我的一个不完整的数据集可以完成所有的时间序列,但是像这样的一个:

param x6_meas :=
0   4.08
6   4.545
12  4.784
18  4.888
24  5.293
30  5.577
36  5.802
42  5.967
48  6.386
54  6.115
60  6.625
66  6.835
72  6.383
84  6.605
96  5.928
120 5.354
144 .
;

我知道你可以指定Pyomo取某个变量对不同时间序列的导数。然而,经过尝试,它没有起作用,我想这是因为这些是耦合的颂歌。所以基本上我的问题是,是否有办法在Pyomo解决这个问题。在

提前谢谢。在


Tags: returnparamvardefrulex1x2constraint
1条回答
网友
1楼 · 发布于 2024-05-13 20:55:19

我想你需要做的只是稍微修改一下你的目标函数:

def _obj(m):
    sum1 = sum((m.x1[i]-m.x1_meas[i])**2 for i in m.MEAS_t if i in m.x1_meas.keys())
    sum2 = sum((m.x2[i]-m.x2_meas[i])**2 for i in m.MEAS_t if i in m.x2_meas.keys())
    sum3 = sum((m.x3[i]-m.x3_meas[i])**2 for i in m.MEAS_t if i in m.x3_meas.keys())
    sum4 = sum((m.x4[i]-m.x4_meas[i])**2 for i in m.MEAS_t if i in m.x4_meas.keys())
    sum5 = sum((m.x5[i]-m.x5_meas[i])**2 for i in m.MEAS_t if i in m.x5_meas.keys())
    sum6 = sum((m.x6[i]-m.x6_meas[i])**2 for i in m.MEAS_t if i in m.x6_meas.keys())
    sum7 = sum((m.x7[i]-m.x7_meas[i])**2 for i in m.MEAS_t if i in m.x7_meas.keys())
    return sum1+sum2+sum3+sum4+sum5+sum6+sum7
m.obj = Objective(rule=_obj)

在将该指数添加到总和之前,这将双重检查i是否是每组测量值的有效索引。如果您知道哪些测量集丢失了数据,那么您可以简化这个函数,只对这些集进行检查,然后像以前一样对其他集求和。在

相关问题 更多 >