Patrick
Patrick

Reputation: 51

Constructing list from file using generators

I'm writing a script to that needs to read in a matrix from a particular location in a large file. The location of interest in the file looks like so:

VOLUME and BASIS-vectors are now :
 -----------------------------------------------------------------------------
  energy-cutoff  :      500.00
  volume of cell :      478.32
      direct lattice vectors                 reciprocal lattice vectors
     7.831488362  0.000000000  0.000000000     0.127689649  0.000000000  0.000000000
     0.000000000  7.773615667  0.000000000     0.000000000  0.128640268  0.000000000
     0.000000000  0.000000000  7.856881120     0.000000000  0.000000000  0.127276967

I need the reciprocal lattice vectors. There are many ways to grab those numbers, but the file is many thousands of lines long, so I can't (shouldn't) store the entire thing as a list of lines. That restriction makes extracting the data I want a little more difficult. This is what I have so far:

with open('OUTCAR','r') as read_outcar:
    for line in read_outcar:
        if 'VOLUME' in line:
            for i in range(5):  #skip to line with data
                next(read_outcar)
            buffer = line.split()
            x = [float(buffer(i+3)) for i in buffer]
            next(read_outcar)
            buffer = line.split()
            y = [float(buffer(i+3)) for i in buffer]
            next(read_outcar)
            buffer = line.split()
            z = [float(buffer(i+3)) for i in buffer]
            break

There are two problems here:

1.) I'm unsure if my usage of 'next' is correct/appropriate, but I don't know how else to grab lines from the file past the current line associated with the iterator

2.) My generators do not work. The interpreter raises a type error, because I am apparently trying to concatenate str and int types. What I want is a list of floats for each row in the the reciprocal lattice matrix.

Any help with this would be greatly appreciated. Thanks in advance.

Upvotes: 0

Views: 55

Answers (3)

Serge
Serge

Reputation: 3765

skip_lines = 0
read_lines = 0
with open('OUTCAR') as read_outcar:
    for line in read_outcar:
        if 'VOLUME' in line:
            skip_lines = 4
            read_lines = 4
        elif skip_lines:
            skip_lines -= 1
        elif read_lines:
            read_lines -= 1

            buffer = line.split()
            x = [float(b) for b in buffer[-3:]]
            print(x)

or use while loop

    while true:
         line = next(read_outcar, '')
         if not x: break
         ...

Upvotes: 0

krflol
krflol

Reputation: 1155

Seems to me that you could do something like

starting_row = 5
filename = r"file.txt"
def make_me_a_generator(filename = None):
    with open(filename, 'r') as f:
        for index, line in enumerate(f.readlines()):
            if index >= starting_row:
                line.replace(r"\n", "")
                row = line[47:].split("  ")

                x = float(row[0])
                y = float(row[1])
                z = float(row[2])
                print(f'{x} {y} {z}')
                yield x, y, z

Turning your file read into a generator that you can use as needed

Upvotes: 0

a_guest
a_guest

Reputation: 36249

There are a few issues with the code:

  • next returns the next item of the iterator and since you split on line you should capture it via line = next(read_outcat)
  • Then the buffer is a list and this is indexed via square brackets, i.e. buffer[...]. However since you seem to be interested in the last three elements you can just access them via buffer[-3:].

Here the modified code:

with open('OUTCAR') as read_outcar:
    for line in read_outcar:
        if 'VOLUME' in line:
            for i in range(5):  #skip to line with data
                line = next(read_outcar)
            buffer = line.split()
            x = [float(b) for b in buffer[-3:]]
            line = next(read_outcar)
            buffer = line.split()
            y = [float(b) for b in buffer[-3:]]
            line = next(read_outcar)
            buffer = line.split()
            z = [float(b) for b in buffer[-3:]]
            print(f'x = {x}, y = {y}, z = {z}')
            break

Upvotes: 1

Related Questions