python -- IndexError: list index out of range / dividing lists - python

I'm not great at programming and I've been driving myself crazy trying to figure this out.
I have a program to calculate binding energies that stores values in lists. At a certain point one list is divided by a different one, but I keep getting this error:
Traceback (most recent call last):
File "semf.py", line 76, in <module>
BpN = BpN(A, Z)
File "semf.py", line 68, in BpN
bper = B[i]/A[i]
IndexError: list index out of range
The relevant code is below, sorry there's so much of it:
A = 0.0
def mass_A(Z):
"""
ranges through all A values Z, ..., 3Z+1 for Z ranging from 1 to 100
"""
a = 0.0
a = np.arange(Z, 3*Z+1)
return a
def semf(A, Z):
"""
The semi-empirical mass formula (SEMF) calculates the binding energy of the nucleus.
N is the number of neutrons.
"""
i = 0
E = []
for n in A:
# if statement to determine value of a5
if np.all(Z%2==0 and (A-Z)%2==0):
a5 = 12.0
elif np.all(Z%2!=0 and (A-Z)%2!=0):
a5 = -12.0
else:
a5 = 0
B = a1*A[i] - a2*A[i]**(2/3) - a3*(Z**2 / A[i]**(1/3)) - a4*( (A[i] - 2*Z)**2 / A[i] ) + a5 / A[i]**(1/2)
i += 1
E.append(B)
return E
def BpN(A, Z):
"""
function to calculate the binding energy per nucleon (B/A)
"""
i = 0
R = []
for n in range(1,101):
bper = B[i]/A[i]
i += 1
R.append(bper)
return R
for Z in range(1,101):
A = mass_A(Z)
B = semf(A, Z)
BpN = BpN(A, Z)
It seems like somehow, the two lists A and B aren't the same length, but I'm not sure how to fix that issue.
Please help.
Thanks

In Python, list indices start from zero and not from one.
It's hard to be sure without seeing your code in its entirety, but range(1,101) looks suspect. If the list has 100 elements, the correct bounds for the loop are range(0,100) or, equivalently, range(100) or, better still, range(len(A)).
P.S. Since you're using Numpy already, you should look into rewriting your code using Numpy arrays instead of using lists and loops. If A and B were Numpy arrays, your entire troublesome function could become:
return B / A
(This is element-wise division of B by A.)

Related

How can I solve the error: 'int' object does not support item assignment

def foo(x, a, b, i, j):
k = j
ct = 0
while k > i-1:
if x[k] <= b and not (x[k] <= a):
ct = ct + 1
k = k - 1
return ct
x = (11,10,10,5,10,15,20,10,7,11)
y = [10000000000000000000]
m = 0
while m < 10000000000000000000:
y[m] = m
m = m +1
print(foo(x,8,18,3,6))
print(foo(x,10,20,0,9))
print(foo(x,8,18,6,3))
print(foo(x,20,10,0,9))
print(foo(x,6,7,8,8))
# Please be careful with typos for the output of the following lines!
print(foo(y,
111112222233333, # five 1's, then five 2's, then five 3's
999998888877777, # five 9's, then five 8's, then five 7's
222223333344444, # five 2's, then five 3's, then five 4's
905003340009900023))
---------------------------------------------------------------------------
TypeError Traceback (most recent call
last) <ipython-input-17-d3d2cd54b367> in <module>()
14
15 while m < 10000000000000000000:
---> 16 y[m] = m
17 m = m +1
18
TypeError: 'int' object does not support item assignment
In python, when you write y = [10000000000000000000], you are creating an array with a single item in index 0, which has 10000000000000000000 as value. And, maybe, your idea was to define an array with 10000000000000000000 items in it?
If that is the case, what you want to do is: y = [] to initialize an array/list. In python, you don't specify the size of arrays, they are dynamic. But you need to use methods to remove or to add new items. You can change an existing item by using index, though.
If you fix that, you will still get an Exception where the arrow is pointing at, in the Traceback, because you are trying to modify the value of an index that does not exist. Since you instantiated the array as y = [10000000000000000000], you only have a value in index 0. It works the first time, because the loop starts at index 0, when it sets y[0] = 0. But when m get incremented and it tries y[1] = 1, the array does not have that index, which will raise IndexError: list assignment index out of range.
If you want to initialize an array with 10000000000000000000 items in it, you could do:
y = []
for i in range(10000000000000000000):
y.append(i)
or
y = [i for i in range(10000000000000000000)]
More about range() function: https://docs.python.org/3/library/functions.html#func-range
More about array/list: https://docs.python.org/3/tutorial/datastructures.html

Python List in List trouble

Before start to tell my problem sorry for my grammar and English is not very good. I'm a Python learner. Today i was working on a project but I have a trouble. I'm trying to make a loop.
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
Here is my list, I'm trying to create a loop. That loop will substract every first values from each others and every seconds to seconds then print. Let me explain my trouble more simple. [[x,y][x1,y1][x2,y2] I need to substract x1-x then print the result after this x2-x1 then print the result but same time y1-y print then print so console output should looks like this;
1,1
1,2
2,1...
Method i've tried
while True:
for x,y in coordinates:
x = x - y
print(x)
This is not worked because it substracts x values to y values. I know it's too wrong.
I've research on internet but i did not understand this subject very well.
I'm looking for help. Thanks everyone.
A simple and naive implementation
def pr(arr):
i = 1
while i < len(arr):
(x,y) = arr[i]
(a,b) = arr[i-1]
print(x-a, y-b)
i += 1
if __name__ == '__main__':
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7],[1,2]]
pr(coordinates)
O/P:
1 1
1 2
2 1
2 1
-6 -5
This is fairly similar to your original code:
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
x_prev = None
for x, y in coordinates:
if x_prev is not None:
print('{}, {}'.format(x - x_prev, y - y_prev)
x_prev, y_prev = x, y
If you want to generalize a bit, for different lengths of coordinates, you could do this:
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7`],[1,2]]
prev = None
for c in coordinates:
if prev is not None:
print(', '.join(c2-c1 for c1, c2 in zip(prev, c)))
prev = c
You need to iterate over the list using range function so that you can get current and next ones together. So you can do the subtraction in the loop.
coordinates = [[1,2],[2,3],[3,5],[5,6],[7,7],[1,2]]
for i in range(len(coordinates) - 1):
print(coordinates[i+1][0] - coordinates[i][0], coordinates[i+1][1] - coordinates[i][1])

Possible differences between list and iterator

I have a weird problem with iterators, which I can't figure out. I have a complicated numerical routine returning a generator object (or after some changes to the code an islice). Afterwards I check, the results as I know that the results must have a negative imaginary part:
import numpy as np
threshold = 1e-8 # just check up to some numerical accuracy
results = result_generator(**inputs)
is_valid = [np.all(_result.imag < threshold) for _result in results]
print("Number of valid results: ", is_valid.count(True))
(Sorry for not giving an executable code, but I can't come up with a simple code at the moment.)
The problem is now, that this returns one valid solution. If I change the code to
import numpy as np
threshold = 1e-8 # just check up to some numerical accuracy
results = list(result_generator(**inputs))
is_valid = [np.all(_result.imag < threshold) for _result in results]
print("Number of valid results: ", is_valid.count(True))
using a list instead of a generator, I get zero valid solution. I can however not wrap my head around what is different and thus have no idea how to debug the problem.
If I go through the debugger and print out the result with the corresponding index the results are even different, the one of the generator is correct, the one of the list is wrong.
Here the numerical function:
def result_generator(z, iw, coeff, n_min, n_max):
assert n_min >= 1
assert n_min < n_max
if n_min % 2:
# index must be even
n_min += 1
id1 = np.ones_like(z, dtype=complex)
A0, A1 = 0.*id1, coeff[0]*id1
A2 = coeff[0] * id1
B2 = 1. * id1
multiplier = np.subtract.outer(z, iw[:-1])*coeff[1:]
multiplier = np.moveaxis(multiplier, -1, 0).copy()
def _iteration(multiplier_im):
multiplier_im = multiplier_im/B2
A2[:] = A1 + multiplier_im*A0
B2[:] = 1. + multiplier_im
A0[:] = A1
A1[:] = A2 / B2
return A1
complete_iterations = (_iteration(multiplier_im) for multiplier_im in multiplier)
return islice(complete_iterations, n_min, n_max, 2)
You're yielding the same array over and over instead of making new arrays. When you call list, you get a list of references to the same array, and that array is in its final state. When you don't call list, you examine the array in the state the generator yields it, each time it's yielded.
Stop reusing the same array over and over.

index 4 is out of bounds for axis 1 with size 4 Code with Double Sum

Hi I have the following function which produces an out of bounds error:
import numpy as np
import pylab as plt
import scipy
import math
import sympy as sy
T = sy.Symbol('T')
rho = sy.Symbol('rho')
g_T = [1,T,T**2,T*sy.log(T),T**2*sy.log(T)]
g_rho = [1,rho,rho**2,rho*sy.log(rho),rho**2*sy.log(rho)]
g_T_np = np.asarray(g_T)
g_rho_np = np.asarray(g_rho)
c = np.loadtxt("c_test.txt")
def F(T,rho):
ret = 0
for n in xrange(1,5):
for m in xrange(1,6):
inner= c[n,m]*g_T_np*g_rho_np
ret += inner
return ret
print F(T,rho)
where the .txt file is like this:
-0.529586 -0.000208559 -3.36563E-09 2.29441E-05
2.22722E-06 -0.00014526 -2.48888E-09 1.89488E-05
-6.26662E-05 0.000421028 6.17407E-09 -5.14488E-05
0.09977346 -0.000622051 -8.56485E-09 7.49956E-05
-0.01437627 -9.86754E-05 -1.59808E-09 1.22574E-05
The full error displayed is:
Traceback (most recent call last):File "EOS_test.py", line 38, in <module> print F(T,rho) File "EOS_test.py", line 31, in F inner=c[n,m]*g_T_np*g_rho_np IndexError: index 4 is out of bounds for axis 1 with size 4
How can I solve this error?
Numpy uses 0-based indexing. From the looks of it you are indexing the array from 1 (2nd position) to 4 (5th position), which is of course out of bounds for the array you are working with. The same is true for the second axis.
Secondly, you've mixed up your axes:
The first axis (0) is the index of the selected row (0 to 5)
the second axis indexes the column, i.e. the value inside a row (indexed 0 to 4)
This should work:
def F(T,rho):
ret = 0
for n in range(5):
for m in range(4):
inner= c[n,m]*g_T_np*g_rho_np
ret += inner
return ret
Your problem is in setting your xranges.
Python lists (and np arrays) are 0 indexed, so you don't want the indices [1,2,3,4,5] and [1,2,3,4,5,6], but instead want [0,1,2,3,4] and [0,1,2,3,4,5] [0,1,2,3] and [0,1,2,3,4].
Setting up your for loops like this would solve your problem:
for n in xrange(0,4):
for m in xrange(0,5):
Or, you can take advantage of xrange's default starting point, and simply list one parameter:
for n in xrange(4):
for m in xrange(5):
Also, for a "more pythonic" solution, instead of having nested for loops, look up how to iterate over an ndarray. The docs give this example:
it = np.nditer(c, flags=['f_index'])
while not it.finished:
inner= c[it[0]]*g_T_np*g_rho_np
ret += inner
it.iternext()
This avoids the whole issue of needing to know the size of the array you're importing, and is therefore much more robust.
Edit: As pdowling mentioned in his answer, the range numbers should be 4 and 5. I had left 5 and 6 in my aswer, and have now changed that.

Issues with using np.linalg.solve in Python

Below, I'm trying to code a Crank-Nicholson numerical solution to the Navier-Stokes equation for momentum (simplified with placeholders for time being), but am having issues with solving for umat[timecount,:], and keep getting the error "ValueError: setting an array element with a sequence". I'm extremely new to Python, does anyone know what I could do differently to avoid this problem?
Thanks!!
def step(timesteps,dn,dt,Numvpts,Cd,g,alpha,Sl,gamma,theta_L,umat):
for timecount in range(0, timesteps+1):
if timecount == 0:
umat[timecount,:] = 0
else:
Km = 1 #placeholder for eddy viscosity
thetaM = 278.15 #placeholder for theta_m for time being
A = Km*dt/(2*(dn**2))
B = (-g*dt/theta_L)*thetaM*np.sin(alpha)
C = -dt*(1/(2*Sl) + Cd)
W_arr = np.zeros(Numvpts+1)
D = np.zeros(Numvpts+1)
for x in (0,Numvpts): #creating the vertical veocity term
if x==0:
W_arr[x] = 0
D[x] = 0
else:
W_arr[x] = W_arr[x-1] - (dn/Sl)*umat[timecount-1,x-1]
D = W_arr/(4*dn)
coef_mat_u = Neumann_mat(Numvpts,D-A,(1+2*A),-(A+D))
b_arr_u = np.zeros(Numvpts+1) #the array of known quantities
umat_forward = umat[timecount-1,2:Numvpts]
umat_center = umat[timecount-1,1:Numvpts-1]
umat_backward = umat[timecount-1,0:Numvpts-2]
b_arr_u = np.zeros(Numvpts+1)
for j in (0,Numvpts):
if j==0:
b_arr_u[j] = 0
elif j==Numvpts:
b_arr_u[j] = 0
else:
b_arr_u[j] = (A+D[j])*umat_backward[j]*(1-2*A)*umat_center[j] + (A-D[j])*umat_forward[j] - C*(umat_center[j]*umat_center[j]) - B
umat[timecount,:] = np.linalg.solve(coef_mat_u,b_arr_u)
return(umat)
Please note that,
for i in (0, 20):
print(i),
will give result 0 20 not 0 1 2 3 4 ... 20
So you have to use the range() function
for i in range(0, 20 + 1):
print(i),
to get 0 1 2 3 4 ... 20
I have not gone through your code rigorously, but I think the problem is in your two inner for loops:
for x in (0,Numvpts): #creating the vertical veocity term
which is setting values only at zero th and (Numvpts-1) th index. I think you must use
for x in range(0,Numvpts):
Similar is the case in (range() must be used):
for j in (0,Numvpts):
Also, here j never becomes == Numvpts, but you are checking the condition? I guess it must be == Numvpts-1
And also the else condition is called for every index other than 0? So in your code the right hand side vector has same numbers from index 1 onwards!
I think the fundamental problem is that you are not using range(). Also it is a good idea to solve the NS eqns for a small grid and manually check the A and b matrix to see whether they are being set correctly.

Categories

Resources