0

I am trying to convert the following code from Trefethen's Spectral Methods in MATLAB to Python. But run into the following error regarding an index out of bounds. I am a bit confused as to what index is out of bounds and how to fix it. Any help would be appreciated.

Error

Traceback (most recent call last):
  File "C:\Documents and Settings\My Documents\Computational Physics\Wave-eqn.py", line 56, in <module>
ax.plot_wireframe(x,tdata,data,rstride=10, cstride=10)
  File "C:\Python32\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 906, in  plot_wireframe
    tylines = [tY[i] for i in cii]
  File "C:\Python32\lib\site-packages\mpl_toolkits\mplot3d\axes3d.py", line 906, in  <listcomp>
    tylines = [tY[i] for i in cii]
IndexError: index out of bounds

Trefethen's Code

% p6.m - variable coefficient wave equation using differentiation matrices

% Grid, variable coefficient, and initial data:
N = 512; h = 2*pi/N; x = h*(1:N); t = 0; dt = h/4;
a = .1;
c = a + sin (x-1).^2;
v = exp(-100*(x-1).^2); vold = exp(-100*(x-a*dt-1).^2);

column = [0 .5*(-1).^(1:N-1).*cot((1:N-1)*h/2)];
D = toeplitz(column,-column);

% Time-stepping by leap frog formula:
tmax = 15; tplot = .15; clf, drawnow, set(gcf,'renderer','zbuffer')
plotgap = round(tplot/dt); dt = tplot/plotgap;
nplots = round(tmax/tplot);
data = [v; zeros(nplots,N)]; tdata = t;
for i = 1:nplots
 for n = 1:plotgap
        t = t+dt;
        %       v_hat = fft(v);
        %       w_hat = 1i*[0:N/2-1 0 -N/2+1:-1] .* v_hat;
        %       w = real(ifft(w_hat));
        w = (D*v')';
        vnew = vold - 2*dt*c.*w; vold = v; v = vnew;
    end
    data(i+1,:) = v; tdata = [tdata; t];
end
waterfall(x,tdata,data), view(10,70), colormap(1e-6*[1 1 1]);
axis([0 2*pi 0 tmax 0 3]), ylabel t, zlabel u, grid off

My Code

import numpy as np
from numpy import *
from math import  pi
from scipy.linalg import toeplitz
from scipy.special import cotdg
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt


N = 512
h = (2*np.pi)/N
x = h*(np.arange(N)+1)
t = 0
dt = h/4.
a = .1
c = a + np.sin(x - 1)**2
v = np.exp(-100 * (x - 1)**2)
vold = np.exp(-100 * (x - a*dt - 1)**2)

column = ((0.5*(-1)**arange(N))*cotdg(arange(N))*(h/2));
D = toeplitz(column,-column);
#print(D.shape);


tmax = 15   
tplot = .15
plotgap = int(around(tplot/dt));print(plotgap)
dt = tplot/plotgap
nplots = int(round((tmax/tplot)));print(nplots)
k = np.zeros(((nplots,N))) 
data = np.concatenate((v.reshape((512,1)).transpose(), k))
tdata = t

for i in range(nplots):
    for n in range(plotgap):
        t = t+dt
        w = (D*v)
        vnew = vold-2*dt*c*w
        vold = v
        v = vnew
    data[i,:] = v[0,:]
    tdata = vstack([tdata, t])
print('shape data =',data.shape)
print('shape v =',v.shape)
print('shape tdata =',tdata.shape)
print('shape x =',x.shape)

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(x,tdata,data,rstride=10, cstride=10)
plt.show()

Shapes of arrays done by python

 shape data = (101, 512)
 shape tdata = (101, 1)
 shape x = (512,)

I had a friend run the size() command in MatLab for this code and he came up with these shapes for the arrays

data =  101 512
tdata = 101 1
x =     1   512
4
  • 1
    I'm not really familiar with the details of matplotlib,scipy or numpy, but I'm guessing that you introduced some off-by-1 errors when porting from Matlab, since Matlab arrays are index from 1 to n, whereas python arrays are from 0 to n-1. I hope this comment is actually useful! Commented Aug 1, 2012 at 20:35
  • That's a good point, but it only applies to indexing, not the total number of elements -- shape in numpy and size in Matlab should return the same numbers. Commented Aug 1, 2012 at 20:46
  • I took that in to account by having the (1:N-1) lines in the Matlab code be arange(N)) in the Python code. Commented Aug 1, 2012 at 20:49
  • @SteveTjoa is there a way to change shape =(512,) to (1,512) like the Matlab output? Commented Aug 1, 2012 at 20:54

2 Answers 2

1

The first two arguments of plot_wireframe need to be 2D arrays. Documentation.

I don't know exactly how to customize your code (because there is a lot of it), but I hope that helps.

EDIT: Try axes3d.get_test_data to see an example of what valid inputs are supposed to look like.

Sign up to request clarification or add additional context in comments.

2 Comments

so I need to some how make x a 2D array?
so I did X,Y,Z=axes3d.get_test_data(0.05) print(X.shape) print(Y.shape) print(Z.shape) and got (120, 120) (120, 120) (120, 120) so does this mean that the length of each dimension of the arrays must be the same?
0

With the help of the folks over at [email protected] I figured it out. The arrays

x and tdata

Need to be broadcast so I did

X,Y = np.broadcast_arrays(x,tdata)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_wireframe(X,Y,data,rstride=5, cstride=5)
plt.show()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.