-2

This is the file that i am trying to read (it is a longer list with more bodies):

Sun 332946.0 0.0 0.0 0.0 0.0 0.0 0.0

Mercury 0.055 0.3598570518147997 -0.06132511797541504 -0.03811110768962459 -0.000716045178241433 0.02901045859848441 0.002432467783842063

Venus 0.815 -0.3935053177409041 -0.6082860993904631 0.01457222641991683 0.01684066443595474 -0.01108032188877406 -0.001122023332246253

It is supposed to be read as a label,mass, array of position, array of velocity. This done by:

def new_particle(input_handle):
    """
    Initialises a Particle3D instance given an input file handle. This
    function reads in a line in the file and spilts it into list items
    where each is labels and initialised using the '__init__' method.
    
    The input file should contain one line per particle in the following format:
    <label>   <mass>  <pos> <y> <z>    <vx> <vy> <vz>
    
    :param inputFile: Readable file handle in the above format

    :return Particle3D instance
    """   
    
    lines = input_handle.readline() 
    
    tokens = lines.split(" ") 
    label = str(tokens[0])
    mass = float(tokens[1]) 
    pos = np.array(tokens[2:5],float)
    vel = np.array(tokens[5:8],float)
            
    return Particle3D(label, mass, pos, vel)

and to read this file I have used this loop:

particle_list = [] 
with open(input("Enter file name: ")) as f:
    # Reading the opened file that contains initial conditions
    n = len(f.readlines()) 
    for i in range(n):
       particle_list.append(p3d.new_particle(f))  

but i keep getting the error that the mass is list index out of range

Mattia Righetti
  • 1,265
  • 1
  • 18
  • 31
astro
  • 1
  • 2
  • You are consuming the file at this step `n = len(f.readlines())` because the pointer is moved to the EOF, so the next calls to `f.readlines()` will be empty. This could help you https://stackoverflow.com/questions/10201008/using-readlines-twice-in-a-row – Mattia Righetti Feb 17 '22 at 14:22
  • @MattiaRighetti I think I understand what you mean and tried to what was suggested in the link but i still get the same error. Can you maybe help me write out what exactly I need to add? – astro Feb 17 '22 at 14:32
  • Does this answer your question? [Why can't I call read() twice on an open file?](https://stackoverflow.com/questions/3906137/why-cant-i-call-read-twice-on-an-open-file) – Tomerikoo Feb 17 '22 at 14:33
  • 1
    Why not just `for line in f: new_particle(line)` and change the `new_particle` function to receive the line instead of the file. Then you don't need to do `input_handle.readline()` inside it... – Tomerikoo Feb 17 '22 at 14:34

1 Answers1

1

You are consuming the file at this step

n = len(f.readlines())

f.readlines() will move the pointer to EOF, so the next calls to f.readlines() will be empty.

So, when you call again lines = input_handle.readlines() it will be empty, same goes for tokens = lines.split(" ") and that's why accessing it will give you index out of range.

Try to iterate over the lines with this

particle_list = [] 
with open(input("Enter file name: ")) as f:
    lines = f.readlines()
    for line in lines:
       particle_list.append(p3d.new_particle(line))

and change the method to take a line as input like this

def new_particle(line):
    """
    Initialises a Particle3D instance given an input file handle. This
    function reads in a line in the file and spilts it into list items
    where each is labels and initialised using the '__init__' method.
    
    The input file should contain one line per particle in the following format:
    <label>   <mass>  <pos> <y> <z>    <vx> <vy> <vz>
    
    :param inputFile: Readable file handle in the above format

    :return Particle3D instance
    """
    
    tokens = line.split(" ") 
    label = str(tokens[0])
    mass = float(tokens[1]) 
    pos = np.array(tokens[2:5],float)
    vel = np.array(tokens[5:8],float)
            
    return Particle3D(label, mass, pos, vel)

Now each line is passed to the method and then split by space and your tokens array should have values in it.

Mattia Righetti
  • 1,265
  • 1
  • 18
  • 31
  • Also can I ask how can I call for just say the position array? I want to calculate the separations between one body with all the others? – astro Feb 17 '22 at 14:44
  • If you just want the position array you have to take the part of the array that you're interested in, it's in your code `tokens[2:5]` – Mattia Righetti Feb 17 '22 at 14:50
  • so i have done this: r = p3d.new_particle(np.array(lines[2:5])) but it says 'numpy.ndarray' object has no attribute 'split', i am not sure to fix it to get just the position – astro Feb 17 '22 at 15:02