使用scipy.integrate集成矢量字段(numpy数组)

时间:2015-11-22 17:05:38

标签: python scipy interpolation pde numerical-integration

我有兴趣使用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)

修改:

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

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 ?

最后一个return语句只是一些伪代码。但这基本上就是我要找的东西。

修改:

scipy.interpolate.griddata功能似乎是要走的路。是否有可能将其纳入自己的功能?事情如下:

    def f(x,t):
        return [scipy.interpolate.griddata(x,vx),scipy.interpolate.griddata(x,vy)]

2 个答案:

答案 0 :(得分:2)

我打算建议matplotlib.pyplot.streamplot从版本1.5.0开始支持关键字参数events = ['A','B','A','A','B','B','A','A'] target = ['B', 'A', 'A'] size = len(target) count = len([start for start in range(len(events) - size + 1) if events[start:start + size] == target]) ,但它不实用且非常不准确。

您的代码示例对我来说有点混乱:如果您有start_pointsvx向量字段坐标,那么您应该有两个网格:vyx。使用这些你确实可以使用y来获得一个平滑的向量场来进行整合,但是当我尝试这样做时,这似乎会占用太多的内存。以下是基于scipy.interpolate.griddata的类似解决方案:

scipy.interpolate.interp2d

请注意,我使集成网格更加密集以获得额外的精度,但在这种情况下它并没有太大变化。

结果:

output

更新

在评论中的一些注释后,我重新审视了我原来基于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() 的方法。这样做的原因是,虽然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]] 兼容。它计算odeint给出的每个p点的插值。此解决方案不会消耗过多的内存,但使用上述参数运行要花费更长的时间。这可能是由于odeint中对dfun进行了大量评估,远远超过了作为输入的100个时间点所显示的内容。

但是,生成的流线比使用odeint获得的流线要平滑得多,即使两种方法都使用默认的interp2d插值方法:

improved result

答案 1 :(得分:1)

如果有人对此字段进行了表达,我使用的是Andras答案的简洁版本,没有掩码和向量:

backgroundColor

enter image description here

我希望它对有相同需求的人有用。