This Python module parses Gaussian cube files, produced by quite a few QM software packages, and makes volume data available as numpy array as well as some associated properties.
Look at this example for api reference:
import load_cube # create an object and read in data from file cube=load_cube.CUBE('/path/to/your.cube') # calculate total number of data points print "Number of voxels: %d"%(cube.NX*cube.NY*cube.NZ) # calculate box volume print "Total volume, Angs^3: %d"%((cube.NX-1)*cube.X[0]*(cube.NY-1)*cube.Y[1]*(cube.NZ-1)*cube.Z[2]) # calculate total electron density by summing up squared values, contained in 3d array cube.data print "Number of electrons (sort of): %.2f"%((cube.data**2).sum()*cube.X[0]*cube.Y[1]*cube.Z[2])
Here is the module, save it as «load_cube.py» for use as in the previous example:
import numpy as np from math import ceil, floor, sqrt class CUBE: def __init__(self, fname): f = open(fname, 'r') for i in range(2): f.readline() # echo comment tkns = f.readline().split() # number of atoms included in the file followed by the position of the origin of the volumetric data self.natoms = int(tkns[0]) self.origin = np.array([float(tkns[1]),float(tkns[2]),float(tkns[3])]) # The next three lines give the number of voxels along each axis (x, y, z) followed by the axis vector. tkns = f.readline().split() # self.NX = int(tkns[0]) self.X = np.array([float(tkns[1]),float(tkns[2]),float(tkns[3])]) tkns = f.readline().split() # self.NY = int(tkns[0]) self.Y = np.array([float(tkns[1]),float(tkns[2]),float(tkns[3])]) tkns = f.readline().split() # self.NZ = int(tkns[0]) self.Z = np.array([float(tkns[1]),float(tkns[2]),float(tkns[3])]) # The last section in the header is one line for each atom consisting of 5 numbers, the first is the atom number, second (?), the last three are the x,y,z coordinates of the atom center. self.atoms = [] for i in range(self.natoms): tkns = f.readline().split() self.atoms.append([tkns[0], tkns[2], tkns[3], tkns[4]]) # Volumetric data self.data = np.zeros((self.NX,self.NY,self.NZ)) i=0 for s in f: for v in s.split(): self.data[i/(self.NY*self.NZ), (i/self.NZ)%self.NY, i%self.NZ] = float(v) i+=1 if i != self.NX*self.NY*self.NZ: raise NameError, "FSCK!" def dump(self, f): # output Gaussian cube into file descriptor "f". # Usage pattern: f=open('filename.cube'); cube.dump(f); f.close() print >>f, "CUBE file\ngenerated by piton _at_ erg.biophys.msu.ru" print >>f, "%4d %.6f %.6f %.6f" % (self.natoms, self.origin[0], self.origin[1], self.origin[2]) print >>f, "%4d %.6f %.6f %.6f"% (self.NX, self.X[0], self.X[1], self.X[2]) print >>f, "%4d %.6f %.6f %.6f"% (self.NY, self.Y[0], self.Y[1], self.Y[2]) print >>f, "%4d %.6f %.6f %.6f"% (self.NZ, self.Z[0], self.Z[1], self.Z[2]) for atom in self.atoms: print >>f, "%s %d %s %s %s" % (atom[0], 0, atom[1], atom[2], atom[3]) for ix in xrange(self.NX): for iy in xrange(self.NY): for iz in xrange(self.NZ): print >>f, "%.5e " % self.data[ix,iy,iz], if (iz % 6 == 5): print >>f, '' print >>f, "" def mask_sphere(self, R, Cx,Cy,Cz): # produce spheric volume mask with radius R and center @ [Cx,Cy,Cz] # can be used for integration over spherical part of the volume m=0*self.data for ix in xrange( int(ceil((Cx-R)/self.X[0])), int(floor((Cx+R)/self.X[0])) ): ryz=sqrt(R**2-(ix*self.X[0]-Cx)**2) for iy in xrange( int(ceil((Cy-ryz)/self.Y[1])), int(floor((Cy+ryz)/self.Y[1])) ): rz=sqrt(ryz**2 - (iy*self.Y[1]-Cy)**2) for iz in xrange( int(ceil((Cz-rz)/self.Z[2])), int(floor((Cz+rz)/self.Z[2])) ): m[ix,iy,iz]=1 return m