Individual operations on coordinates in 2D arrays - python

Im working on a problem with projectile motion in computational physics, and I want to perform different mathematical operations on the x and y coordinates in my array. The code Im struggling with is indexing inside a for loop.
I've tried different forms for indexing but keep getting errors like "could not broadcast input array from shape (2,2) into shape (2)" and "setting an array element with a sequence."
g = 9.81
theta = 30
dt = 0.1
t = 5
n = int(t/dt)
t = zeros(n)
r = zeros((n, 2), float)
v = zeros((n, 2), float)
a = zeros((n, 2), float)
r[0] = array([0,0])
v[0] = array([10*cos(theta), 10*sin(theta)])
t[0] = 0
for i in range(n-1):
v[i+1] = v[0] - g*dt
r[i+1] = r[i] + v[i]*dt
t[i+1] = t[i] + dt
The inserted code shows two columns (v[x,y] and r[x,y]) with different values, where only the y coordinate is correct. This is because the x coordinate is supposed to be constant. I don't understand how to make the x coordinate constant, and only do the operation on the y coordinate. I want the result to be calculated as:
v[i+1] = v[0] # x-coordinate
v[i+1] = v[0] - g*dt # y-coordinate

you need to only index the y part like this
v[i+1, 1] = v[i,1] - g*dt

Related

How can I code a matrix within a matrix using a loop?

So I have this 3x3 G matrix (not shown here, it's irrelevant to my problem) that I created using the two variables u (a vector, x - y) and the scalar k. x_j = (x_1 (j), x_2 (j), x_3 (j)) and y_j = (y_1 (j), y_2 (j), y_3 (j)). alpha_j is a 3x3 matrix. The A matrix is block diagonal matrix of size 3nx3n. I am having trouble with the W matrix. How do I code a matrix of size 3nx3n, where the (i,j)th block is the 3x3 matrix given by alpha_i*G_[ij]*alpha_j?? I am lost.
My alpha_j matrix also seems to be having some trouble. The loop keeps throwing me the error, "only length-1 arrays can be converted to Python scalars." pls help :/
def W(x, y, k, alpha, A):
u = x - y
n = x.shape[0]
W = np.zeros((3*n, 3*n))
for i in range(0, n-1):
for j in range(0, n-1):
#u = -np.array([[x[i,0] - x[j,0]], [x[i,1] - x[j,1]], [0]]) ??
W[i][j] = (alpha_j(alpha, A) * G(u, k) * alpha_j(alpha, A))
W[i][i] = np.zeros((n, n))
return W
def alpha_j(a, A):
alph = np.array([[0,0,0],[0,0,0],[0,0,0]],complex)
rho = np.random.rand(3,1)
for i in range(0, 2):
for j in range(0, 2):
alph[i][j] = (rho[i] * a * A[i][j])
return alph
#-------------------------------------------------------------------
x1 = np.array([[1], [2], [0]])
y1 = np.array([[4], [5], [0]])
# SYSTEM PARAMETERS
# incoming Wave angle
theta = 0 # can range from [0, 2pi)
# susceptibility
chi = 10 + 1j
# wavelength
lam = 0.5 # microns (values between .4-.7)
# frequency
k = (2 * np.pi)/lam # 1/microns
# volume
V_0 = (0.05)**3 # microns^3
# incoming wave vector
K = k * np.array([[0], [np.sin(theta)], [np.cos(theta)]])
# polarization vector
vecinc = np.array([[1], [0], [0]]) # (can choose any vector perpendicular to K)
# for the fixed alpha case
alpha = (V_0 * 3 * chi)/(chi + 3)
# 3 x 3 matrix
A = np.matlib.identity(3) # could be any symmetric matrix,
#-------------------------------------------------------------------
# TEST FUNCTIONS
test = G((x1-y1), k)
print(test)
w = W(x1, y1, k, alpha, A)
print(w)
Sometimes my W loops throws me the error, "can't set an array element with a sequence." But I need to set each array element in this arbitrary matrix W to the 3x3 matrix created by multiplying alpha by G...
To your question of how to create a new array with a block for each element, the following should do the trick:
G = np.random.random([3,3])
result = np.zeros([9,9])
num_blocks = 3
a = np.random.random([3,3])
b = np.random.random([3,3])
for i in range(G.shape[0]):
for j in range(G.shape[1]):
block_result = a*G[i,j]*b
for k in range(num_blocks):
for l in range(num_blocks):
result[3*i + k, 3*j + l] = block_result[i, j]
You should be able to generalize from there. I hope I've understood correctly.
EDIT: It looks like I haven't understood correctly. I'm leaving it in hopes it spurs you to an answer. The general idea is to generate ranges of indices to operate on, and then just operate on them directly. Slicing might be helpful, too.
Ah, you asked how to create a diagonal filled with blocks. In that case:
num_diagonal_blocks = 3 # for example
for block_dim in range(num_diagonal_blocks)
# do your block calculation...
for k in range(G.shape[0]):
for l in range(G.shape[1]):
result[3*block_dim + k, 3*block_dim + l] = # assign to element of block
I think that's nearly it.

Points on sphere

I am new in Python and I have a sphere of radius (R) and centred at (x0,y0,z0). Now, I need to find those points which are either on the surface of the sphere or inside the sphere e.g. points (x1,y1,z1) which satisfy ((x1-x0)**2+(y1-y0)**2+(z1-x0)*82)**1/2 <= R. I would like to print only those point's coordinates in a form of numpy array. Output would be something like this-[[x11,y11,z11],[x12,y12,z12],...]. I have the following code so far-
import numpy as np
import math
def create_points_around_atom(number,atom_coordinates):
n= number
x0 = atom_coordinates[0]
y0 = atom_coordinates[1]
z0 = atom_coordinates[2]
R = 1.2
for i in range(n):
phi = np.random.uniform(0,2*np.pi,size=(n,))
costheta = np.random.uniform(-1,1,size=(n,))
u = np.random.uniform(0,1,size=(n,))
theta = np.arccos(costheta)
r = R * np.cbrt(u)
x1 = r*np.sin(theta)*np.cos(phi)
y1 = r*np.sin(theta)*np.sin(phi)
z1 = r*np.cos(theta)
dist = np.sqrt((x1-x0)**2+(y1-y0)**2+(z1-z0)**2)
distance = list(dist)
point_on_inside_sphere = []
for j in distance:
if j <= R:
point_on_inside_sphere.append(j)
print('j:',j,'\tR:',R)
print('The list is:', point_on_inside_sphere)
print(len(point_on_inside_sphere))
kk =0
for kk in range(len(point_on_inside_sphere)):
for jj in point_on_inside_sphere:
xx = np.sqrt(jj**2-y1**2-z1**2)
yy = np.sqrt(jj**2-x1**2-z1**2)
zz = np.sqrt(jj**2-y1**2-x1**2)
print("x:", xx, "y:", yy,"z:", zz)
kk +=1
And I am running it-
create_points_around_atom(n=2,structure[1].coords)
where, structure[1].coords is a numpy array of three coordinates.
To sum up what has been discussed in the comments, and some other points:
There is no need to filter the points because u <= 1, which means np.cbrt(u) <= 1 and hence r = R * np.cbrt(u) <= R, i.e. all points will already be inside or on the surface of the sphere.
Calling np.random.uniform with size=(n,) creates an array of n elements, so there's no need to do this n times in a loop.
You are filtering distances from the atom_coordinate, but the points you are generating are centered on [0, 0, 0], because you are not adding this offset.
Passing R as an argument seems more sensible than hard-coding it.
There's no need to "pre-load" arguments in Python like one would sometimes do in C.
Since sin(theta) is non-negative over the sphere, you can directly calculate it from the costheta array using the identity cosĀ²(x) + sinĀ²(x) = 1.
Sample implementation:
# pass radius as an argument
def create_points_around_atom(number, center, radius):
# generate the random quantities
phi = np.random.uniform( 0, 2*np.pi, size=(number,))
theta_cos = np.random.uniform(-1, 1, size=(number,))
u = np.random.uniform( 0, 1, size=(number,))
# calculate sin(theta) from cos(theta)
theta_sin = np.sqrt(1 - theta_cos**2)
r = radius * np.cbrt(u)
# use list comprehension to generate the coordinate array without a loop
# don't forget to offset by the atom's position (center)
return np.array([
np.array([
center[0] + r[i] * theta_sin[i] * np.cos(phi[i]),
center[1] + r[i] * theta_sin[i] * np.sin(phi[i]),
center[2] + r[i] * theta_cos[i]
]) for i in range(number)
])

how to do this interpolation formula faster?

I have a function of Everett interpolation and I'd like to make it a little bit faster than it is right now. It works very well b
x and y are the parameters: time and values.
xi is the time which I want to have interpolated value.
def everett(x,y,xi):
'''
function everett
INPUT:
x list float
y list float
xi float
RETURN:
yi float
'''
n = len(x) #interpolation degree
h = x[1]-x[0] #differences between epochs
D = np.zeros([n,n+1])
D[:,0] = x
D[:,1] = y
for j in range(1,n): #loop to each column
for i in range(0,n-j): #loop to cell within a column
D[i,j+1] = D[i+1,j] - D[i,j]
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
z = i
w = 1 - u
i = 0
yi = 0
m1 = u
m2 = w
for j in range(1,n+1,2):
yi += m1 * D[z+1-i,j] + m2 * D[z-i,j]
i = i + 1
m1 *= (u - i) * (u + i) / ((j+1)*(j+2))
m2 *= (w - i) * (w + i) / ((j+1)*(j+2))
if (z-i)<0 or (z+1-i)>(n-j-1):
break #//checks validity of index in the table
return yi
Thx!
EDIT: some modification using numpy
I change this part of code:
#Finding the value of u
for i in range(0,n):
u = ( xi - x[i] ) / h
if u == 0:
return y[i]
elif( u > 0 and u < 1.0 ):
break
if i == n-1:
return None
by this one:
#Finding the value of u
u = (xi - x) /h
u0 = np.where(u == 0)[0]
if u0.size:
return y[u0[0]]
i = np.where((u > 0) & (u < 1.0))[0]
if not i.size:
return None
z = i[0]
u = u[z]
the biggest problem I have right now is how to modify the last loop and the first loop where variable D is filled with values.
Any ideas?
Include numpy, put the data into numpy.array()s and use numpy operations. You'll simplify your code and get, potentially, orders of magnitude better performance. If you're comfortable with Matlab, you'll find numpy easy to learn.
Loops like
for i in range(0,n):
u = ( xi - x[i] ) / h
become simple one liners:
u = (xi - x) / h
(where x is an array, u will be an array and the - and / will do element-wise arithmetic if xi and h are numbers)
This even works for whole arrays. For example, a forward difference can be expressed in 1D as
Dx = X[1:] - x[:1]
The X[1:] means the elements of X excluding the first and X[:1] means the elements of X excluding the last.
You can do the same on N-dimensional arrays, eliminating nested loops.
I wrote this article a long time ago, but it's still relevant. You'll see where I use numpy to speed up a finite difference calculation on a mesh (solving the 2D diffusion equation) while also simplifying the code: http://www.timteatro.net/2010/10/29/performance-python-solving-the-2d-diffusion-equation-with-numpy/
If I get a chance, I will come back and help you work on your specific code. But actually, I think this algorithm is a perfect project to introduce yourself to numpy.
And, if you're more interested in the result than you are the method, SciPy (an extension of numpy) has interpolation functions:
http://docs.scipy.org/doc/scipy/reference/tutorial/interpolate.html

Norm of moving window submatrix

I try to create a function for performing a convolution between a matrix and a filter. I managed to do the basic operations, but I stumbled on calculating the norm of the sliced matrix (the submatrix of the main matrix), corresponding to each position in the output.
The code is this:
def convol2d(matrix, kernel):
# matrix - input matrix indexed (v, w)
# kernel - filtre indexed (s, t),
# h -output indexed (x, y),
# The output size is calculated by adding smid, tmid to each side of the dimensions of the input image.
norm_filter = np.linalg.norm(kernel) # The norm of the filter
vmax = matrix.shape[0]
wmax = matrix.shape[1]
smax = kernel.shape[0]
tmax = kernel.shape[1]
smid = smax // 2
tmid = tmax // 2
xmax = vmax + 2 * smid
ymax = wmax + 2 * tmid
window_list = [] # Initialized an empty list for storing the submatrix
print vmax
print xmax
h = np.zeros([xmax, ymax], dtype=np.float)
for x in range(xmax):
for y in range(ymax):
s_from = max(smid - x, -smid)
s_to = min((xmax - x) - smid, smid + 1)
t_from = max(tmid - y, -tmid)
t_to = min((ymax - y) - tmid, tmid + 1)
value = 0
for s in range(s_from, s_to):
for t in range(t_from, t_to):
v = x - smid + s
w = y - tmid + t
print matrix[v, w]
value += kernel[smid - s, tmid - t] * matrix[v, w]
# This does not work
window_list.append(matrix[v,w])
norm_window = np.linalg.norm(window_list)
h[x, y] = value / norm_filter * norm_window
return h
For example, my input matrix is A(v, w), I want that my output values in the output matrix h (x,y), be calculated as:
h(x,y) = value/ (norm_of_filer * norm_of_sumbatrix)
Thanks for any help!
Edit: Following the suggestions, I modified like this:
I modified like this, but I only get the first row appended, and used in calculation and not the entire submatrix.
`for s in range(s_from, s_to):
for t in range(t_from, t_to):
v = x - smid + s
w = y - tmid + t
value += kernel[smid - s, tmid - t] * matrix[v, w]
window_list.append(matrix[v,w])
window_array = np.asarray(window_list, dtype=float)
window_list = []
norm_window = np.linalg.norm(window_array)
h[x, y] = value / norm_filter * norm_window`
The input of np.linalg.norm is supposed to be an "Input array." Try converting the list of matrices to an array. (python: list of matrices to numpy array?)
Also, maybe move the norm_window line out of the loop, since you only later use it as evaluated at the last step, with everything in it. In fact, wait 'til the loop is done, convert the finished list to an array (so it's only done once) and evaluate norm_window on that.

Initialising a vector field in numpy

I'd like to initialize a numpy array to represent a two-dimensional vector field on a 100 x 100 grid of points defined by:
import numpy as np
dx = dy = 0.1
nx = ny = 100
x, y = np.meshgrid(np.arange(0,nx*dx,dx), np.arange(0,ny*dy,dy))
The field is a constant-speed circulation about the point cx,cy and I can initialize it OK with regular Python loops:
v = np.empty((nx, ny, 2))
cx, cy = 5, 5
s = 2
for i in range(nx):
for j in range(ny):
rx, ry = i*dx - cx, j*dy - cy
r = np.hypot(rx, ry)
if r == 0:
v[i,j] = 0,0
continue
# (-ry/r, rx/r): the unit vector tangent to the circle centred at (cx,cy), radius r
v[i,j] = (s * -ry/r, s * rx/r)
But when I'm having trouble vectorizing with numpy. The closest I've got is
v = np.array([s * -(y-cy) / np.hypot(x-cx, y-cy), s * (x-cx) / np.hypot(x-cx, y-cy)])
v = np.rollaxis(v, 1, 0)
v = np.rollaxis(v, 2, 1)
v[np.isinf(v)] = 0
But this isn't equivalent and doesn't give the right answer. What is the correct way to initialize a vector field using numpy?
EDIT: OK - now I'm confused following the suggestion below, I try:
vx = s * -(y-cy) / np.hypot(x-cx, y-cy)
vy = s * (x-cx) / np.hypot(x-cx, y-cy)
v = np.dstack((vx, vy))
v[np.isnan(v)] = 0
but get a completely different array...
From your initial setup:
import numpy as np
dx = dy = 0.1
nx = ny = 100
x, y = np.meshgrid(np.arange(0, nx * dx, dx),
np.arange(0, ny * dy, dy))
cx = cy = 5
s = 2
You could compute v like this:
rx, ry = y - cx, x - cy
r = np.hypot(rx, ry)
v2 = s * np.dstack((-ry, rx)) / r[..., None]
v2[np.isnan(v2)] = 0
If you're feeling really fancy, you could create yx as a 3D array, and broadcast all of the operations over it:
# we make these [2,] arrays to broadcast over the last output dimension
c = np.array([5, 5])
s = np.array([-2, 2])
# this creates a [100, 100, 2] mesh, where the last dimension corresponds
# to (y, x)
yx = np.mgrid[0:nx * dx:dx, 0:ny * dy:dy].T
yxdiff = yx - c[None, None, :]
r = np.hypot(yxdiff[..., 0], yxdiff[..., 1])[..., None]
v3 = s[None, None, :] * yxdiff / r
v3[np.isnan(v3)] = 0
Check that these both give the same answer as your original code:
print np.all(v == v2), np.all(v == v3)
# True, True
Edit
Why rx, ry = y - cx, x - cy rather than rx, ry = x - cx, y - cy? I agree it's very counterintuitive - the only reason I decided to do it that way was to match the output of your original code.
The issue is that in your grids, consecutive x values are actually found in consecutive columns of x, and consecutive y values are found in consecutive rows of y, i.e. x[:, j] is the j th x-value and y[i, :] is the i th y-value. However, in your inner loop, you are multiplying dx by i, which is your row index, and dy by j, which is your column index. You're therefore flipping the x and y dimensions of your output.

Categories