Python 从CSV文件写入微分方程(与solve_ivp一起使用)
我正在尝试使用Python 从CSV文件写入微分方程(与solve_ivp一起使用),python,csv,differential-equations,Python,Csv,Differential Equations,我正在尝试使用solve\u ivp求解一个大型微分方程组 from scipy import integrate sol = integrate.solve_ivp(func_system, (0,100), initial_value_array, t_eval) func_系统是一个微分方程系统,必须从CSV文件中推断,其示例如下: From,To,Rate Blood,Other_3,3.0000E+02 Blood,Blood_5,7.0000E+02 Blood_5
solve\u ivp
求解一个大型微分方程组
from scipy import integrate
sol = integrate.solve_ivp(func_system, (0,100), initial_value_array, t_eval)
func_系统
是一个微分方程系统,必须从CSV文件中推断,其示例如下:
From,To,Rate
Blood,Other_3,3.0000E+02
Blood,Blood_5,7.0000E+02
Blood_5,Liver_1,4.6200E-01
Blood_5,C-bone-S,8.7780E-02
Blood_5,C-bone-V,4.6200E-03
Blood_5,T-bone-S,1.2474E-01
Blood_5,T-bone-V,1.3860E-02
Blood_5,UB-cont,1.5400E-02
Blood_5,Kidneys_1,7.7000E-03
Blood_5,Kidneys_2,3.8500E-04
Blood_5,RC-cont,1.1550E-02
Blood_5,Testes,2.6950E-04
Blood_5,Ovaries,8.4700E-05
Blood_5,Other_4,1.8511E-02
Blood_5,Other_5,2.3100E-02
Other_3,Blood_5,9.9000E-02
Blood_4,UB-cont,3.5000E+00
Blood_4,Blood_5,6.7550E+01
Blood_4,Other_3,2.8950E+01
Kidneys_1,UB-cont,1.7329E-02
Kidneys_2,Blood_4,1.2660E-04
Other_4,Blood_4,1.3860E-03
Other_5,Blood_4,1.2660E-04
Liver_1,SI-cont,9.2420E-04
Liver_1,Liver_2,4.5286E-02
[...]
from jitcode import jitcode,y
import numpy as np
from pandas import read_csv
# Dictionary describing the RHS of the ODE:
f = {}
def add_to_equation(dynvar,to_be_added):
try:
f[dynvar] += to_be_added
except KeyError:
f[dynvar] = to_be_added
# Dictionary mapping identifiers to JiTCODE’s dynamic variables
dynvars = {}
def get_dynvar(name):
try:
return dynvars[name]
except KeyError:
new_dynvar = y(len(dynvars))
dynvars[name] = new_dynvar
return new_dynvar
# Parsing the file
for source_name,target_name,rate in read_csv("flows.csv").values:
rate = float(rate)
source = get_dynvar(source_name)
target = get_dynvar(target_name)
add_to_equation(target, rate*source)
add_to_equation(source,-rate*source)
initial_condition = np.random.random(len(dynvars))
# Your test case:
Liver_1 = get_dynvar("Liver_1")
Blood_5 = get_dynvar("Blood_5")
assert f[Liver_1] == 0.462*Blood_5-0.0009242*Liver_1-0.045286*Liver_1
# Setup integrator
ODE = jitcode(f)
ODE.set_integrator("dopri5")
ODE.set_initial_value(initial_condition,0.0)
# Actual integration
times = np.linspace(0,100,50)
for time in times:
print(ODE.integrate(time))
微分方程,例如,隔室肝1
,将为:
dLiver_1/dt = 0.462*Blood_5 - 0.000924*Liver_1 - 0.045286*Liver_1
必须在func_系统中写入
dLiver_1_dt = 0.462*Blood_5 - 0.000924*Liver_1 - 0.045286*Liver_1
其中,0.462是从血液_5
到肝脏_1
的比率,0.000924和0.045286是远离肝脏_1
的比率
有没有一种方法可以创建所有这些方程(我总共有150多个),而不必实际编写它们?
我可以使用矩阵方法,但我还需要添加另一个非线性微分方程组。我不确定.solve_ivp()是如何工作的,但如果您只需要方程的字符串表示,我会执行以下操作
import pandas as pd
df = pd.read_csv("test.csv") # create DataFrame
def get_dt(some_variable):
equation = ["d{}/dt =".format(some_variable)] # store str representation of our eqn in a list
variables = []
for index, row in df.iterrows(): # iterate over all rows to check for a match
if (row["From"] == some_variable) or (row["To"] == some_variable): # if variable is found in row
if len(variables):
variables.append("- {}*{}".format(row["Rate"], row["From"])) # add it to our equation
else:
variables.append("{}*{}".format(row["Rate"], row["From"])) # the first number is positive for some reason
equation.extend(variables) # combine left and right hand sides into one list
return " ".join(equation) # combine our list or strings and return a nicely formatted single string
eqn = get_dt("Liver_1")
print(eqn)
输出
D肝脏1/dt=0.462*血液5-0.0009242*肝脏1-0.045286*肝脏1
另外,如果你想一次得到所有的方程式
all_vars = set(df["From"]) # make a "list" of the From variables that doesn't contain duplicates
all_vars.update(set(df["To"])) # add in all To variables still without duplicates
for var in all_vars:
eqn = get_dt(var)
print(eqn)
这给了我们输出
dT-bone-S/dt = 0.12474*Blood_5
dT-bone-V/dt = 0.013859999999999999*Blood_5
dUB-cont/dt = 0.0154*Blood_5 - 3.5*Blood_4 - 0.017329*Kidneys_1
dRC-cont/dt = 0.01155*Blood_5
dSI-cont/dt = 0.0009242*Liver_1
dOther_3/dt = 300.0*Blood - 0.099*Other_3 - 28.95*Blood_4
dLiver_2/dt = 0.045286*Liver_1
dOther_5/dt = 0.0231*Blood_5 - 0.0001266*Other_5
dLiver_1/dt = 0.462*Blood_5 - 0.0009242*Liver_1 - 0.045286*Liver_1
dOvaries/dt = 8.47e-05*Blood_5
dKidneys_1/dt = 0.0077*Blood_5 - 0.017329*Kidneys_1
dKidneys_2/dt = 0.000385*Blood_5 - 0.0001266*Kidneys_2
dBlood/dt = 300.0*Blood - 700.0*Blood
dOther_4/dt = 0.018511*Blood_5 - 0.0013859999999999999*Other_4
dBlood_5/dt = 700.0*Blood - 0.462*Blood_5 - 0.08778*Blood_5 - 0.00462*Blood_5 - 0.12474*Blood_5 - 0.013859999999999999*Blood_5 - 0.0154*Blood_5 - 0.0077*Blood_5 - 0.000385*Blood_5 - 0.01155*Blood_5 - 0.0002695*Blood_5 - 8.47e-05*Blood_5 - 0.018511*Blood_5 - 0.0231*Blood_5 - 0.099*Other_3 - 67.55*Blood_4
dBlood_4/dt = 3.5*Blood_4 - 67.55*Blood_4 - 28.95*Blood_4 - 0.0001266*Kidneys_2 - 0.0013859999999999999*Other_4 - 0.0001266*Other_5
dTestes/dt = 0.0002695*Blood_5
dC-bone-S/dt = 0.08778*Blood_5
dC-bone-V/dt = 0.00462*Blood_5
我认为这足以让你走,这样你就可以找到它,但它可能不完全是你想要的,因为奇怪的线条,如:
D血液/dt=300.0*血液-700.0*血液
这对我来说似乎没有多大意义。我编写了一个名为的模块,它允许您以符号形式指定微分方程。这对您来说很方便,因为它主要负责将您的方程转换为函数。此外,在实际积分过程中,函数求值将非常有效,因为它是用C硬编码的。如果你有150个方程,这可能很重要
针对您的具体问题,我会这样做:
From,To,Rate
Blood,Other_3,3.0000E+02
Blood,Blood_5,7.0000E+02
Blood_5,Liver_1,4.6200E-01
Blood_5,C-bone-S,8.7780E-02
Blood_5,C-bone-V,4.6200E-03
Blood_5,T-bone-S,1.2474E-01
Blood_5,T-bone-V,1.3860E-02
Blood_5,UB-cont,1.5400E-02
Blood_5,Kidneys_1,7.7000E-03
Blood_5,Kidneys_2,3.8500E-04
Blood_5,RC-cont,1.1550E-02
Blood_5,Testes,2.6950E-04
Blood_5,Ovaries,8.4700E-05
Blood_5,Other_4,1.8511E-02
Blood_5,Other_5,2.3100E-02
Other_3,Blood_5,9.9000E-02
Blood_4,UB-cont,3.5000E+00
Blood_4,Blood_5,6.7550E+01
Blood_4,Other_3,2.8950E+01
Kidneys_1,UB-cont,1.7329E-02
Kidneys_2,Blood_4,1.2660E-04
Other_4,Blood_4,1.3860E-03
Other_5,Blood_4,1.2660E-04
Liver_1,SI-cont,9.2420E-04
Liver_1,Liver_2,4.5286E-02
[...]
from jitcode import jitcode,y
import numpy as np
from pandas import read_csv
# Dictionary describing the RHS of the ODE:
f = {}
def add_to_equation(dynvar,to_be_added):
try:
f[dynvar] += to_be_added
except KeyError:
f[dynvar] = to_be_added
# Dictionary mapping identifiers to JiTCODE’s dynamic variables
dynvars = {}
def get_dynvar(name):
try:
return dynvars[name]
except KeyError:
new_dynvar = y(len(dynvars))
dynvars[name] = new_dynvar
return new_dynvar
# Parsing the file
for source_name,target_name,rate in read_csv("flows.csv").values:
rate = float(rate)
source = get_dynvar(source_name)
target = get_dynvar(target_name)
add_to_equation(target, rate*source)
add_to_equation(source,-rate*source)
initial_condition = np.random.random(len(dynvars))
# Your test case:
Liver_1 = get_dynvar("Liver_1")
Blood_5 = get_dynvar("Blood_5")
assert f[Liver_1] == 0.462*Blood_5-0.0009242*Liver_1-0.045286*Liver_1
# Setup integrator
ODE = jitcode(f)
ODE.set_integrator("dopri5")
ODE.set_initial_value(initial_condition,0.0)
# Actual integration
times = np.linspace(0,100,50)
for time in times:
print(ODE.integrate(time))
一些注意事项:
- 包括不同的非线性组件应该很简单
- 我在这里打印输出,但您可以用不同的方式存储和处理输出
- 您还可以使用标识符(通过
dynvars
)作为字典访问解决方案。这样,您就不需要直接处理动态变量的编号
- 基本的简化如
-0.000924*Liver_1 - 0.045286*Liver_1 = -0.04621*Liver_1
将由SymEngine(象征性主干)在引擎盖下动态完成
- JiTCODE在引擎盖下使用
scipy.integrate.ode
或solve\u ivp
所以你没有csv?为什么不能通过编程实现呢?也许我不明白这个问题。@JeffTilton,我有csv文件。我正在寻找一种使用csv文件制作微分方程的方法,这样它们就可以与solve_ivp一起使用。谢谢。为了详细说明提问者的问题:他们不希望有方程串,而是希望有一个实现这些方程的函数传递给solve\u ivp
。