简体   繁体   English

如何从文本文件中读取微分方程组,以使用scipy.odeint求解该系统?

[英]How to read a system of differential equations from a text file to solve the system with scipy.odeint?

I have a large (>2000 equations) system of ODE's that I want to solve with python scipy's odeint. 我有一个很大的ODE系统(> 2000个方程式),我想用python scipy的odeint解决。

I have three problems that I want to solve (maybe I will have to ask 3 different questions?). 我有三个要解决的问题(也许我将不得不问三个不同的问题?)。 For simplicity, I will explain them here with a toy model, but please keep in mind that my system is large. 为了简单起见,我将在这里用玩具模型对其进行解释,但是请记住,我的系统很大。 Suppose I have the following system of ODE's: 假设我具有以下ODE系统:

dS/dt = -beta*S
dI/dt = beta*S - gamma*I
dR/dt = gamma*I

with beta = c p I β= c p I

where c, p and gamma are parameters that I want to pass to odeint. 其中c,p和gamma是我要传递给odeint的参数。

odeint is expecting a file like this: odeint期望这样的文件:

def myODEs(y, t, params):
    c,p, gamma = params
    beta = c*p
    S = y[0]
    I = y[1]
    R = y[2]
    dydt = [-beta*S*I,
           beta*S*I - gamma*I,
           - gamma*I]  
    return dydt

that then can be passed to odeint like this: 然后可以将其传递给odeint,如下所示:

myoutput = odeint(myODEs, [1000, 1, 0], np.linspace(0, 100, 50), args = ([c,p,gamma], ))

I generated a text file in Mathematica, say myOdes.txt, where each line of the file corresponds to the RHS of my system of ODE's, so it looks like this 我在Mathematica中生成了一个文本文件,称为myOdes.txt,其中文件的每一行都对应于我的ODE系统的RHS,所以看起来像这样

#myODEs.txt

-beta*S*I
beta*S*I - gamma*I
- gamma*I

My text file looks similar to what odeint is expecting, but I am not quite there yet. 我的文本文件看起来与odeint所期望的相似,但是我还没有到那里。 I have three main problems: 我有三个主要问题:

  1. How can I pass my text file so that odeint understands that this is the RHS of my system? 如何传递文本文件,以便odeint理解这是系统的RHS?
  2. How can I define my variables in a smart way, that is, in a systematic way? 如何以一种聪明的方式(即系统的方式)定义变量? Since there are >2000 of them, I cannot manually define them. 由于它们有2000多个,因此我无法手动定义它们。 Ideally I would define them in a separate file and read that as well. 理想情况下,我将在一个单独的文件中定义它们并阅读。
  3. How can I pass the parameters (there are a lot of them) as a text file too? 如何将参数(很多)作为文本文件传递?

I read this question that is close to my problems 1 and 2 and tried to copy it (I directly put values for the parameters so that I didn't have to worry about my point 3 above): 我看了这个问题,这是接近我的问题1和2,并试图复制它(我直接把该参数值,使我没有担心我的3点以上):

    systemOfEquations = []
    with open("myODEs.txt", "r") as fp :
        for line in fp :
            systemOfEquations.append(line)

    def dX_dt(X, t):
        vals = dict(S=X[0], I=X[1], R=X[2], t=t)
        return [eq for eq in systemOfEquations]

    out = odeint(dX_dt, [1000,1,0], np.linspace(0, 1, 5))

but I got the error: 但我得到了错误:

    odepack.error: Result from function call is not a proper array of          floats.
    ValueError: could not convert string to float: -((12*0.01/1000)*I*S),

Edit: I modified my code to: 编辑:我将代码修改为:

    systemOfEquations = []
    with open("SIREquationsMathematica2.txt", "r") as fp :
        for line in fp :
               pattern = regex.compile(r'.+?\s+=\s+(.+?)$')
               expressionString = regex.search(pattern, line) 
               systemOfEquations.append( sympy.sympify( expressionString) )


    def dX_dt(X, t):
        vals = dict(S=X[0], I=X[1], R=X[2], t=t)
        return [eq for eq in systemOfEquations]

    out = odeint(dX_dt, [1000,1,0], np.linspace(0, 100, 50), )

and this works (I don't quite get what the first two lines of the for loop are doing). 这是可行的(我不太了解for循环的前两行在做什么)。 However, I would like to do the process of defining the variables more automatic, and I still don't know how to use this solution and pass parameters in a text file. 但是,我想更自动地定义变量,而我仍然不知道如何使用此解决方案并在文本文件中传递参数。 Along the same lines, how can I define parameters (that will depend on the variables) inside the dX_dt function? 同样,如何在dX_dt函数中定义参数(取决于变量)?

Thanks in advance! 提前致谢!

This isn't a full answer, but rather some observations/questions, but they are too long for comments. 这不是一个完整的答案,而是一些观察/问题,但是对于评论来说太长了。

dX_dt is called many times by odeint with a 1d array y and tuple t . dX_dt用1d数组y和元组t多次调用odeint You provide t via the args parameter. 您通过args参数提供t y is generated by odeint and varies with each step. yodeint生成,并随每个步骤而变化。 dX_dt should be streamlined so it runs fast. dX_dt应该简化,以便快速运行。

Usually an expresion like [eq for eq in systemOfEquations] can be simplified to systemOfEquations . 通常,可以将诸如[eq for eq in systemOfEquations] systemOfEquations简化为systemOfEquations [eq for eq...] doesn't do anything meaningful. [eq for eq...]没有任何有意义的作用。 But there may be something about systemOfEquations that requires it. 但是关于systemOfEquations可能有一些要求。

I'd suggest you print out systemOfEquations (for this small 3 line case), both for your benefit and ours. 我建议您出于自己和我们的利益,打印出systemOfEquations (对于这种3行小的情况)。 You are using sympy to translated the strings from the file into equations. 您正在使用sympy将文件中的字符串转换为方程式。 We need to see what it produces. 我们需要看看它产生了什么。

Note that myODEs is a function, not a file. 请注意, myODEs是函数,而不是文件。 It may be imported from a module, which of course is a file. 它可以从模块(当然是文件)中导入。

The point to vals = dict(S=X[0], I=X[1], R=X[2], t=t) is to produce a dictionary that the sympy expressions can work with. vals = dict(S=X[0], I=X[1], R=X[2], t=t)是产生一个可以用于sympy表达式的字典。 A more direct (and I think faster) dX_dt function would look like: 更直接(我认为更快)的dX_dt函数如下所示:

def myODEs(y, t, params):
    c,p, gamma = params
    beta = c*p
    dydt = [-beta*y[0]*y[1],
           beta*y[0]*y[1] - gamma*y[1],
           - gamma*y[1]]  
    return dydt

I suspect that the dX_dt that runs sympy generated expressions will be a lot slower than a 'hardcoded' one like this. 我怀疑dX_dt运行sympy产生的表情会比“硬编码”一个像这样的慢了许多。

I'm going add sympy tag, because, as written, that is the key to translating your text file into a function that odeint can use. 我要添加sympy标记,因为按照书面要求,这是将文本文件转换为odeint可以使用的功能的关键。

I'd be inclined to put the equation variability in the t parameters, rather a list of sympy expressions. 我倾向于将方程的可变性放在t参数中,而不是一列sympy表达式。

That is replace: 那就是替换:

    dydt = [-beta*y[0]*y[1],
           beta*y[0]*y[1] - gamma*y[1],
           - gamma*y[1]]  

with something like 用类似的东西

    arg12=np.array([-beta, beta, 0])
    arg1 = np.array([0, -gamma, -gamma])
    arg0 = np.array([0,0,0])
    dydt = arg12*y[0]*y[1] + arg1*y[1] + arg0*y[0]

Once this is right, then the argxx definitions can be move outside dX_dt , and passed via args . 一旦正确,则argxx定义可以移到dX_dt之外,并通过args传递。 Now dX_dt is just a simple, and fast, calculation. 现在, dX_dt只是一个简单而快速的计算。

This whole sympy approach may work fine, but I'm afraid that in practice it will be slow. 整个sympy方法可能很好用,但恐怕在实践中会很慢。 But someone with more sympy experience may have other insights. 但有人更sympy经验可能有其他的见解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM