使用 scipy.integrate 整合向量场(一个 numpy 数组)

imr*_*nal 4 python interpolation scipy numerical-integration pde

我有兴趣使用该scipy.integrate库为给定的初始点集成向量场(即找到流线)。由于矢量场是numpy.ndarray在计算网格上定义的对象,因此必须对网格点之间的值进行插值。有没有集成商处理这个问题?也就是说,如果我要尝试以下操作

import numpy as np
import scipy.integrate as sc
vx = np.random.randn(10,10)
vy = np.random.randn(10,10)
def f(x,t):
    return [vx[x[0],x[1]], vy[x[0],x[1]]] # which obviously does not work if x[i] is a float
p0 = (0.5,0.5)
dt = 0.1
t0 = 0
t1 = 1
t = np.arange(t0,t1+dt,dt)
sc.odeint(f,p0,t)
Run Code Online (Sandbox Code Playgroud)

编辑 :

我需要返回周围网格点的向量场的插值:

def f(x,t):
    im1 = int(np.floor(x[0]))
    ip1 = int(np.ceil(x[1]))
    jm1 = int(np.floor(x[0]))
    jp1 = int(np.ceil(x[1]))
    if (im1 == ip1) and (jm1 == jp1):
        return [vx[x[0],x[1]], vy[x[0],x[1]]]
    else:
        points = (im1,jm1),(ip1,jm1),(im1,jp1),(ip1,jp1)
        values_x = vx[im1,jm1],vx[ip1,jm1],vx[im1,jp1],vx[ip1,jp1]
        values_y = vy[im1,jm1],vy[ip1,jm1],vy[im1,jp1],vy[ip1,jp1]
        return interpolated_values(points,values_x,values_y) # how ?
Run Code Online (Sandbox Code Playgroud)

最后一个 return 语句只是一些伪代码。但这基本上是我正在寻找的。

编辑 :

scipy.interpolate.griddata功能似乎是要走的路。是否可以将它合并到它自己的功能中?在这行的东西:

    def f(x,t):
        return [scipy.interpolate.griddata(x,vx),scipy.interpolate.griddata(x,vy)]
Run Code Online (Sandbox Code Playgroud)

And*_*eak 5

我打算建议matplotlib.pyplot.streamplotstart_points1.5.0 版开始,哪个支持关键字参数,但是它不实用,而且非常不准确。

你的代码示例让我有点困惑:如果你有vx,vy向量场坐标,那么你应该有两个网格:xy。使用这些确实可以scipy.interpolate.griddata用来获得平滑的向量场进行积分,但是当我尝试这样做时,这似乎占用了太多内存。这是基于的类似解决方案scipy.interpolate.interp2d

import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as interp
import scipy.integrate as integrate

#dummy input from the streamplot demo
y, x = np.mgrid[-3:3:100j, -3:3:100j]
vx = -1 - x**2 + y
vy = 1 + x - y**2

#dfun = lambda x,y: [interp.griddata((x,y),vx,np.array([[x,y]])), interp.griddata((x,y),vy,np.array([[x,y]]))]
dfunx = interp.interp2d(x[:],y[:],vx[:])
dfuny = interp.interp2d(x[:],y[:],vy[:])
dfun = lambda xy,t: [dfunx(xy[0],xy[1])[0], dfuny(xy[0],xy[1])[0]]

p0 = (0.5,0.5)
dt = 0.01
t0 = 0
t1 = 1
t = np.arange(t0,t1+dt,dt)

streamline=integrate.odeint(dfun,p0,t)

#plot it
plt.figure()
plt.plot(streamline[:,0],streamline[:,1])
plt.axis('equal')
mymask = (streamline[:,0].min()*0.9<=x) & (x<=streamline[:,0].max()*1.1) & (streamline[:,1].min()*0.9<=y) & (y<=streamline[:,1].max()*1.1)
plt.quiver(x[mymask],y[mymask],vx[mymask],vy[mymask])
plt.show()
Run Code Online (Sandbox Code Playgroud)

请注意,为了提高精度,我使积分网格更加密集,但在这种情况下并没有太大变化。

结果:

输出

更新

在评论中做了一些注释之后,我重新审视了我原来的griddata基于方法。这样做的原因是,虽然interp2d为整个数据网格计算griddata插值,但只计算给定点的插值,因此在少数点的情况下,后者应该快得多。

我修复了之前griddata尝试中的错误并提出了

xyarr = np.array(zip(x.flatten(),y.flatten()))
dfun = lambda p,t: [interp.griddata(xyarr,vx.flatten(),np.array([p]))[0], interp.griddata(xyarr,vy.flatten(),np.array([p]))[0]]
Run Code Online (Sandbox Code Playgroud)

odeint. 它计算由p赋予它的每个点的内插值odeint。此解决方案不消耗过多的存储器,但是它需要很多很多更长的时间来与上述参数运行。这可能是由于对dfunin进行了大量评估odeint,远远超过从作为输入提供给它的 100 个时间点中显而易见的评估。

然而,结果流线比使用 获得的流线平滑得多interp2d,即使两种方法都使用默认linear插值方法:

改善结果