With python, you can open a binary file using the 'rb'
option in your open
statement.
Then using numpy.fromfile
you can read the file provided you know the datatypes that are in the file.
First you have to know that, when you write an unformatted file in Fortran, each time you use a write
statement, the program will also write, before the data, 4 bytes that tells the size of the data that is contained in the "data block", then the actual data, and then on 4 bytes again, the size of the data that is contained in the "data block". As this size doesn't matter in your case, you can just skip all of these blocks using python's file.seek
method that allows you to move the cursor.
Looking at the wiki, you'll see that the format of the wfc file is the following :
ik, xk, ispin, gamma_only, scalef
ngw, igwx, npol, nbnd
b1, b2, b3
mill(1:3,1:igwx)
evc(1:npoligwx,1)
evc(1:npoligwx,2)
...
evc(1:npol*igwx,nbnd)
Where the datatypes are :
INTEGER :: ik
REAL(8) :: xk(3)
INTEGER :: ispin
LOGICAL :: gamma_only
REAL(8) :: scalef
INTEGER :: ngw
INTEGER :: igwx
INTEGER :: npol
INTEGER :: nbnd
REAL(8) :: b1(3), b2(3), b3(3)
INTEGER :: mill(3,igwx)
COMPLEX(8) :: evc(npol*igwx,nbnd)
Then, you'll need to know the conversion from the fortran types to the numpy ones
- INTEGER becomes int32
- REAL(8) becomes float64
- COMPLEX(8) becomes complex128
- LOGICAL is written on 4 bytes, you can just read it as an int32
Here's a quick and dirty way to read these files, you can group the np.fromfile
if you define correctly the types, but I thought that it would be clearer doing it step by step.
import numpy as np
with open('wfc1.dat', 'rb') as f:
# Moves the cursor 4 bytes to the right
f.seek(4)
ik = np.fromfile(f, dtype='int32', count=1)[0]
xk = np.fromfile(f, dtype='float64', count=3)
ispin = np.fromfile(f, dtype='int32', count=1)[0]
gamma_only = bool(np.fromfile(f, dtype='int32', count=1)[0])
scalef = np.fromfile(f, dtype='float64', count=1)[0]
# Move the cursor 8 byte to the right
f.seek(8, 1)
ngw = np.fromfile(f, dtype='int32', count=1)[0]
igwx = np.fromfile(f, dtype='int32', count=1)[0]
npol = np.fromfile(f, dtype='int32', count=1)[0]
nbnd = np.fromfile(f, dtype='int32', count=1)[0]
# Move the cursor 8 byte to the right
f.seek(8, 1)
b1 = np.fromfile(f, dtype='float64', count=3)
b2 = np.fromfile(f, dtype='float64', count=3)
b3 = np.fromfile(f, dtype='float64', count=3)
f.seek(8,1)
mill = np.fromfile(f, dtype='int32', count=3*igwx)
mill = mill.reshape( (igwx, 3) )
evc = np.zeros( (nbnd, npol*igwx), dtype="complex128")
f.seek(8,1)
for i in range(nbnd):
evc[i,:] = np.fromfile(f, dtype='complex128', count=npol*igwx)
f.seek(8, 1)
Hope it helped.