簡體   English   中英

使用 scipy.integrate 整合向量場(一個 numpy 數組)

[英]Integrating a vector field (a numpy array) using scipy.integrate

我對使用scipy.integrate庫為給定的初始點積分向量場(即找到流線) 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)]

我打算建議matplotlib.pyplot.streamplot支持關鍵字參數start_points從版本 1.5.0 開始,但是它不實用,也非常不准確。

你的代碼示例讓我有點困惑:如果你有vxvy向量場坐標,那么你應該有兩個網格: 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()

請注意,為了提高精度,我使積分網格更加密集,但在這種情況下並沒有太大變化。

結果:

輸出

更新

在評論中做了一些注釋之后,我重新審視了我原來的基於griddata的方法。 這樣做的原因是,雖然interp2d為整個數據網格計算插值,但griddata只計算給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兼容。 它計算odeint給它的每個p點的內插值。 此解決方案不消耗過多的存儲器,但是它花費更長的時間來與上述參數運行。 這可能是由於在odeintdfun進行了大量評估,遠遠超過從作為輸入提供給它的 100 個時間點中顯而易見的評估。

然而,結果流線比使用interp2d獲得的流線平滑得多,即使兩種方法都使用默認的linear插值方法:

改善結果

如果有人對該領域有表達式,我使用了不帶掩碼和向量的 Andras 答案的簡潔版本:

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode

vx = lambda x,y: -1 - x**2 + y
vy = lambda x,y: 1 + x - y**2

y0, x0 = 0.5, 0.6

def f(x, y):
    return vy(x,y)/vx(x,y)

r = ode(f).set_integrator('vode', method='adams')
r.set_initial_value(y0, x0)

xf =  1.0
dx = -0.001

x, y = [x0,], [y0,]
while r.successful() and r.t <= xf:
    r.integrate(r.t + dx)
    x.append(r.t + dx)
    y.append(r.y[0])

#plot it
plt.figure()
plt.plot(x, y)
plt.axis('equal')
plt.show()

在此處輸入圖片說明

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM