使用PyDSTool在网络上求解常微分方程
在使用scipy.integrate一段时间后,我发现自己需要更多的功能,比如分岔分析或参数估计。这就是我对PyDSTool感兴趣的原因,但从文档中我无法弄清楚如何使用ModelSpec,也不确定这是否能帮我找到解决方案。
这里有一个简单的例子,说明我想做的事情:我有一个包含两个节点的网络,这两个节点都有相同的动态(SIR模型),用两个常微分方程(ODE)来描述,但初始条件不同。这两个节点之间的方程是通过一个叫做Epsilon的值相互联系的(见下面的公式)。为了更好地阅读,公式以图片的形式展示,'n'和'm'是索引,不是指数 ~> http://image.noelshack.com/fichiers/2014/28/1404918182-odes.png (很遗憾,无法在stack上上传)
在两个节点的情况下,我的代码(使用PyDSTool)看起来是这样的:
#multiple SIR metapopulations
#parameter and initial condition definition; a dict is a must
import PyDSTool as pdt
params={'alpha': 0.7, 'beta':0.1, 'epsilon1':0.5,'epsilon2':0.5}
ini={'s1':0.99,'s2':1,'i1':0.01,'i2':0.00}
DSargs=pdt.args(name='SIRtest_multi',
ics=ini,
pars=params,
tdata=[0,20],
#the for-macro generates formulas for s1,s2 and i1,i2;
#sum works similar but sums over the expressions in it
varspecs={'s[o]':'for(o,1,2,-alpha*s[o]*sum(k,1,2,epsilon[k]*i[k]))',
'i[l]':'for(l,1,2,alpha*s[l]*sum(m,1,2,epsilon[m]*i[m]))'})
#generator
DS = pdt.Generator.Vode_ODEsystem(DSargs)
#computation, a trajectory object is generated
trj=DS.compute('test')
#extraction of the points for plotting
pts=trj.sample()
#plotting; pylab is imported along with PyDSTool as plt
pdt.plt.plot(pts['t'],pts['s1'],label='s1')
pdt.plt.plot(pts['t'],pts['i1'],label='i1')
pdt.plt.plot(pts['t'],pts['s2'],label='s2')
pdt.plt.plot(pts['t'],pts['i2'],label='i2')
pdt.plt.legend()
pdt.plt.xlabel('t')
pdt.plt.show()
但在我原来的问题中,有超过1000个节点,每个节点有5个常微分方程,每个节点与不同数量的其他节点相互联系,并且每个节点的epsilon值也不相同。所以在这个语法上进行调整并没有让我接近解决方案。
我实际上在考虑的是为每个节点构建单独的子模型/求解器,每个节点都有自己的参数(epsilon,因为每个节点的值不同)。然后将它们连接在一起。这就是我不知道在PyDSTool中是否可能,以及是否是处理这类问题的正确方法。
我查看了PyDSTool的示例和文档,但还是没弄明白该怎么做,所以非常感谢任何帮助!如果我尝试的方式不太常规或者很愚蠢,欢迎你提出更高效的做法建议。(其实,解决这类问题的更高效/快速/更好的方法是将其细分为许多小的(仍然没有解耦)模型/求解器,还是一个包含所有常微分方程的模型?)
(我既不是数学家也不是程序员,但我愿意学习,所以请耐心点!)
1 个回答
解决这个问题的方法绝对不是建立独立的模拟模型。这样做不行,因为子模型之间有很多变量是相互关联的。你必须把所有的常微分方程(ODE)放在一起。
听起来你需要的解决方案是使用ModelSpec对象。这些对象可以让你以层级的方式构建子模型的定义,使用一些符号化的部分。它们可以有自己的“epsilon”参数等等。完成后,你可以声明所有的部分,然后让PyDSTool为你生成包含ODE定义的最终字符串。我建议你看看这个教程示例:
http://www.ni.gsu.edu/~rclewley/PyDSTool/Tutorial/Tutorial_compneuro.html
还有提供的示例:ModelSpec_test.py和MultiCompartments.py。但请记住,你仍然需要有参数和耦合数据的来源(也就是从文件加载的大矩阵或字典),这样才能自动化构建模型的过程,否则你还是得手动写出来。
你需要为想要的组件构建一些类。你也可以创建一个工厂函数(可以参考neuralcomp.py工具箱中的'makeSoma'),这个函数会把所有的子组件结合起来,基于每个声明的组件的某些内容来创建一个ODE。最后,你可以通过它们在层级中的位置来引用参数,比如's1.epsilon'和'i4.epsilon'。
不幸的是,要高效地构建这样的模型,你需要学习一些更复杂的编程知识!所以先从理解教程中的所有步骤开始。如果你有具体问题,可以通过SourceForge的支持讨论直接给我发邮件,或者在你开始后再发邮件。