为什么我的2D插值在SciPy中生成具有交换轴的矩阵?

时间:2013-11-27 17:13:32

标签: python numpy matplotlib scipy ipython

我用矢量输入

求解微分方程

y'= f(t,y),y(t_0)= y_0

其中 y0 = y(x)

使用显式的Euler方法,即

y_(i + 1)= y_i + h * f(t_i,y_i)

其中 t 是时间向量, h 是步长, f 是微分方程的右侧。

该方法的python代码如下所示:

for i in np.arange(0,n-1):
        y[i+1,...] = y[i,...] + dt*myode(t[i],y[i,...])

结果是 k,m 矩阵 y ,其中 k t 维度的大小, m y 的大小。

返回 y t 的向量。

t x y 传递给scipy.interpolate.RectBivariateSpline(t, x, y, kx=1, ky=1)

g = scipy.interpolate.RectBivariateSpline(t, x, y, kx=1, ky=1)

生成的对象g使用新的向量ti,xi ( g(p,q) )来提供y_int,这是 ti 定义的点处的 y 插值>和 xi

这是我的问题:

  • RectBivariateSpline的文档根据x和y描述了__call__方法: __call__(x, y[, mth]) 评估坐标数组定义的网格点的样条线

  • plot_surface的matplotlib文档使用了类似的表示法: Axes3D.plot_surface(X, Y, Z, *args, **kwargs) X和Y是由numpy.meshgrid()生成的2D数组的重要区别。

当我计算简单的例子时,两者的输入顺序是相同的,结果正是我所期望的。然而,在我的显式Euler示例中,初始顺序是ti,xi,但是如果我颠倒输入的顺序,插值输出的表面图也是有意义的,如下所示:

ax2.plot_surface(xi, ti, u, cmap=cm.coolwarm)

虽然我很高兴它有效,但我并不满意,因为我无法解释为什么,也没有为什么(除了数组几何)有必要交换输入。理想情况下,我想重构代码,以便输入顺序一致。

这是一个工作代码示例来说明我的意思:

# Heat equation example with explicit Euler method
import numpy as np
import matplotlib.pyplot as mplot
import matplotlib.cm as cm
import scipy.sparse as sp
import scipy.interpolate as interp
from mpl_toolkits.mplot3d import Axes3D
import pdb

# explicit Euler method
def eev(myode,tspan,y0,dt):
    # Preprocessing
    # Time steps
    tspan[1] = tspan[1] + dt
    t = np.arange(tspan[0],tspan[1],dt,dtype=float)
    n = t.size
    m = y0.shape[0]
    y = np.zeros((n,m),dtype=float)
    y[0,:] = y0

    # explicit Euler recurrence relation
    for i in np.arange(0,n-1):
        y[i+1,...] = y[i,...] + dt*myode(t[i],y[i,...])

    return y,t

# generate matrix A
# u'(t) = A*u(t) + g*u(t)
def a_matrix(n):
    aa = sp.diags([1, -2, 1],[-1,0,1],(n,n))
    return aa

# System of ODEs with finite differences
def f(t,u):
    dydt = np.divide(1,h**2)*A.dot(u)
    return dydt

# homogenous Dirichlet boundary conditions
def rbd(t):
    ul = np.zeros((t,1))
    return ul

# Initial value problem -----------

def main():
    # Metal rod 
    # spatial discretization
    # number of inner nodes
    m = 20
    x0 = 0
    xn = 1
    x = np.linspace(x0,xn,m+2)
    # Step size
    global h
    h = x[1]-x[0]

    # Initial values
    u0 = np.sin(np.pi*x)

    # A matrix
    global A
    A = a_matrix(m)

    # Time
    t0 = 0
    tend = 0.2
    # Time step width
    dt = 0.0001
    tspan = [t0,tend]

    # Test r for stability
    r = np.divide(dt,h**2)
    if r <= 0.5:
        u,t = eev(f,tspan,u0[1:-1],dt)      
    else:
        print('r = ',r)
        print('r > 0.5. Explicit Euler method will not be stable.')

    # Add boundary values back
    rb = rbd(t.size)
    u = np.hstack((rb,u,rb))

    # Interpolate heat values
    # Create interpolant. Note the parameter order
    fi = interp.RectBivariateSpline(t, x, u, kx=1, ky=1)

    # Create vectors for interpolant
    xi = np.linspace(x[0],x[-1],100)
    ti = np.linspace(t0,tend,100)

    # Compute function values from interpolant
    u_int = fi(ti,xi)

    # Change xi, ti in to 2D arrays
    xi,ti = np.meshgrid(xi,ti)

    # Create figure and axes objects
    fig3 = mplot.figure(1)
    ax3 = fig3.gca(projection='3d')
    print('xi.shape =',xi.shape,'ti.shape =',ti.shape,'u_int.shape =',u_int.shape)

    # Plot surface. Note the parameter order, compare with interpolant!
    ax3.plot_surface(xi, ti, u_int, cmap=cm.coolwarm)
    ax3.set_xlabel('xi')
    ax3.set_ylabel('ti')

main()
mplot.show()

1 个答案:

答案 0 :(得分:3)

我可以看到你定义:

# Change xi, ti in to 2D arrays
    xi,ti = np.meshgrid(xi,ti)

将其更改为:

ti,xi = np.meshgrid(ti,xi)

ax3.plot_surface(xi, ti, u_int, cmap=cm.coolwarm)

ax3.plot_surface(ti, xi, u_int, cmap=cm.coolwarm)

它工作正常(如果我理解的话)。