Python 如何在求解_bvp时设置适当的边界条件?

Python 如何在求解_bvp时设置适当的边界条件?,python,scipy,Python,Scipy,我试图解决以下边值问题: D*(dS^2/dz^2)-v*(dS/dz)-S/(S+kus)=0 其中D、v和k是常数(见下面的代码)。边界条件为: S(z=0)=23.8和dS/dz(z=无穷大)=0 我试图使用scipy.integrate.solve_bvp来解决z范围(0100)上的问题,但我在设置边界值时遇到了很大困难。我在网上看到的所有示例都没有真正描述用于计算其边界值的函数中的情况,这些函数是solve_bvp的输入。我还有一个额外的复杂问题,就是在无穷远处有一个边界值。这就是我到

我试图解决以下边值问题:

D*(dS^2/dz^2)-v*(dS/dz)-S/(S+kus)=0

其中D、v和k是常数(见下面的代码)。边界条件为:

S(z=0)=23.8和dS/dz(z=无穷大)=0

我试图使用
scipy.integrate.solve_bvp
来解决z范围(0100)上的问题,但我在设置边界值时遇到了很大困难。我在网上看到的所有示例都没有真正描述用于计算其边界值的函数中的情况,这些函数是
solve_bvp
的输入。我还有一个额外的复杂问题,就是在无穷远处有一个边界值。这就是我到目前为止所做的:

# constants
D = 200.6
v = 0.02
k = 0.20

# split second order ODE into 2 first order ODEs
def sulfate_profile(z,U):
    dUdz = [U[1], (v*U[1] + U[0]/(U[0]+k))/D]
    return dUdz

# I initiated these boundary conditions but I don't really know what they mean...
def bc(za, zb):
    return np.array([za[0], zb[1]])

z_list = np.linspace(0,100,1000)
z_a = np.zeros((2, z_list.size))

# solve SO4 concentration ODE over depth range (z_list)
sulfate_reduction = solve_bvp(sulfate_profile,bc,z_list,z_a)
这给了我一个输出,但我肯定这是错误的。我真的很感激任何建议-提前谢谢

bc:callable
函数评估边界条件的残差[← [我的]。
调用签名是
bc(ya,yb)
,或者
bc(ya,yb,p)
(如果存在参数)。
所有参数都是ndarray:
ya
yb
带形状
(n,)
,和
p
带形状
(k,)

返回值必须是具有形状
(n+k,)
的数组

返回值违反了边界条件,或者换句话说,当满足边界条件时,您需要一个计算结果为零的函数

def bc(ya, yb): return ya[0]-23.8, yb[1]

嗯,在发布这个答案之前,我犹豫了一下,因为我宁愿更彻底地检查解决方案,但我看到这里仍然有我发现的所有问题。请参见下面的代码,但首先要做一些解释:

  • 首先,我改变了你的颂歌,所以它与你问题中的颂歌一致
  • 我已经添加了一个修改过的右侧(fun)添加参数-这是为了覆盖现在通过转换ODE而改变的边界条件。我一直紧跟着scipy教程,所以解释是一致的。您可能需要尝试参数p的不同起始值
  • 边界条件(bc1)也是如此-命名bc参数的逻辑为Sn:n=0边界a,n=1边界b
    [0]
    =y,
    [1]
    =y'-因此名称覆盖边界的一侧,索引表示导数的阶数
  • 因为我不知道这个问题的物理性质,所以我添加了一个图表来显示解决方案。这看起来似乎是正确的,但请注意无穷大条件:现在在b边界(“另一边”)处设置为0。无限是无法覆盖的,我看到的唯一解决办法是向外扩展这个极限
这导致


这看起来像深度分布(如果是这样)。

谢谢!这很有帮助。在你的ODE函数中,你消除了我的v和D变量-把它们加回去可以吗?是的,对不起,我忘了。我尝试过不同的方法,但没有把它放回去。
import numpy as np
from scipy.integrate import solve_bvp
import matplotlib.pyplot as plt

# constants
D = 200.6
v = 0.02
k = 0.20

# split second order ODE into 2 first order ODEs
'''def sulfate_profile(U, z):
    print(U, z)
    dUdz = [U[1], (v*U[1] + U[0]/(U[0]+k))/D]
    print(dUdz)
    return dUdz'''

# https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_bvp.html
def sulfate_profile(z, S): # compare to doc: x->z, y->S
    return np.vstack((S[1], v/D*S[1] + S[0]/(S[0]+k)/D))

def fun(z, S, p):
    k0, k1 = p[0], p[1]
    return np.vstack((S[1], k0*S[1] + k1*S[0]/(S[0]+k)))

# I initiated these boundary conditions but I don't really know what they mean...
def bc(S0, S1):
    return np.array([S0[0], S1[0]])

def bc1(S0, S1, p):
    k0 = p[0]
    return np.array([S0[0], S1[0], S0[1] - k0*23.8/(23.8+k), S1[0]]) # Sn: n=0 boundary a, n=1 boundary b; [0] = y, [1] = y',...

z_list = np.linspace(0, 100, 100)
S_a = np.zeros((2, z_list.size))
S_a[0, 0] = 23.8
S_a[0, 99] = 0 # b-boundary which is inf - expand here

# solve SO4 concentration ODE over depth range (z_list)
#sulfate_reduction = solve_bvp(sulfate_profile, bc, z_list, S_a)
sulfate_reduction = solve_bvp(fun, bc1, z_list, S_a, p=[1,1])

#print(sulfate_reduction)
x_plot = np.linspace(0, 1, 100)
y_plot_a = sulfate_reduction.sol(x_plot)[0]
plt.plot(x_plot, y_plot_a, label='sulfate_b_dpth')
plt.show()