Reputation: 51
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
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
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
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)
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