Example #1
0
 def get_positions(self, coords='direct'):
     if self.direct_coords == True and coords[0].lower() == 'c':
         return oppvasp.direct_to_cartesian(self.positions, self.basis)
     elif self.direct_coords == False and coords[0].lower() == 'd':
         return oppvasp.cartesian_to_direct(self.positions, self.basis)
     else:
         return self.positions.copy()
Example #2
0
 def get_positions(self, coords = 'direct'):
     if self.direct_coords == True and coords[0].lower() == 'c':
         return oppvasp.direct_to_cartesian(self.positions, self.basis)
     elif self.direct_coords == False and coords[0].lower() == 'd':
         return oppvasp.cartesian_to_direct(self.positions, self.basis)
     else:
         return self.positions.copy()
Example #3
0
 def get_forces(self, coords):
     """ (n,3) array """
     if not self.has_forces():
         return None
     if coords[0].lower() == 'd':
         return self._forces
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._forces, self._cell)
Example #4
0
 def get_forces(self, coords):
     """ (n,3) array """
     if not self.has_forces():
         return None
     if coords[0].lower() == 'd':
         return self._forces
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._forces, self._cell)
Example #5
0
 def get_supercell_positions(self, sx, sy, sz, coords = 'cart'):
     """ Returns a (sx,sy,sz) supercell in the form of a (sx*sy*sz,3) numpy array """
     nat = self.get_num_atoms()
     sup = np.zeros((nat*sx*sy*sz,3))
     c = np.diag((1,1,1)) # since we use direct coordinates
     for i in range(sx):
         for j in range(sy):
             for k in range(sz):
                 m = i*sy*sz + j*sz + k
                 #print m
                 sup[m*nat:(m+1)*nat] = self._positions + np.dot(c,[i, j, k])
     if coords[0].lower() == 'c':
         return direct_to_cartesian(sup, self._cell)
     else:
         return sup
Example #6
0
 def get_supercell_positions(self, sx, sy, sz, coords='cart'):
     """ Returns a (sx,sy,sz) supercell in the form of a (sx*sy*sz,3) numpy array """
     nat = self.get_num_atoms()
     sup = np.zeros((nat * sx * sy * sz, 3))
     c = np.diag((1, 1, 1))  # since we use direct coordinates
     for i in range(sx):
         for j in range(sy):
             for k in range(sz):
                 m = i * sy * sz + j * sz + k
                 #print m
                 sup[m * nat:(m + 1) *
                     nat] = self._positions + np.dot(c, [i, j, k])
     if coords[0].lower() == 'c':
         return direct_to_cartesian(sup, self._cell)
     else:
         return sup
Example #7
0
    def get_positions(self, coords = 'direct', atom = -1):
        """
        Returns positions for one (atom_no>=0) or all (atom_no=-1) atoms 
        in direct or cartesian coordinates as a numpy array 
        of dimension (steps, atoms, 3).
        
        Parameters:
            - coords : either 'direct' or 'cartesian'
            - atom   : (int) Set this to only return positions for a single atom.
        """
        
        if atom == -1: 
            p = self.positions.copy()
        else:
            p = self.positions[:,atom,:].copy()

        if coords[0].lower() == 'd':
            return p
        elif coords[0].lower() == 'c':
            return direct_to_cartesian(p, self.basis)
Example #8
0
    def get_shortest_bond(self, include_self = False, safe_mode = True, rmax = 3.0):
        """
        Returns a tupple containing the shortest bond length in Angstrom,
        followed by the indices of the two atoms making up the bond
        
        Parameters:
            include_self : bool (default False)
                Whether to check for bonds between an atom and its _own_ periodic image.
                This is only needed for very small unit cells, typically with a single atom.
            safe_mode : bool (default True)
                Much slower, but safer for non-cubic cells
            rmax : float (default 3.0)
                Maximum bond length (in Angstrom) to check for 
                (only used in safe_mode)

        """
        a = self._cell[0]
        b = self._cell[1]
        c = self._cell[2]

        pos = self._positions
        natoms = pos.shape[0]
        if natoms == 1:
            print "Note from get_shortest_bond(): include_self is enabled since only a single atom was found!"
            include_self = True

        # Limit to sphere of radius Rc
        if safe_mode:
            #if include_self:
            #    print "include_self and safe_mode are not currently compatible. sorry"
            #    return
            
            natoms = self.get_num_atoms()
            a = self._cell[0]
            b = self._cell[1]
            c = self._cell[2]

            # Find distance between opposing faces of the cell:
            wa = abs(np.dot(a,np.cross(b,c))) / np.linalg.norm(np.cross(b,c))
            wb = abs(np.dot(b,np.cross(c,a))) / np.linalg.norm(np.cross(c,a))
            wc = abs(np.dot(c,np.cross(a,b))) / np.linalg.norm(np.cross(a,b))

            # If half the max radius exceeds one of the face-to-face distances (wa, wb or wc), 
            # we add more atoms in the given direction(s) as necessary.
            la = 1 + int(2*rmax/wa)
            lb = 1 + int(2*rmax/wb)
            lc = 1 + int(2*rmax/wc)
            print "dim:",la,lb,lc
            #p2 = self.get_supercell_positions(la,lb,lc, coords='d')
            pos = np.zeros((natoms*la*lb*lc,3))
            #offsets = np.zeros((natoms*la*lb*lc,3), dtype=np.int)
            #c = np.diag((1,1,1)) # since we use direct coordinates
            for i in range(la):
                for j in range(lb):
                    for k in range(lc):
                        m = i*lb*lc + j*lc + k
                        pos[m*natoms:(m+1)*natoms] = self._positions + np.array((i, j, k))
                        #offsets[m*natoms:(m+1)*natoms] = [i, j, k]
            indices = np.tile(np.arange(natoms), la*lb*lc)

            paired = np.zeros(natoms, dtype=np.int)
            minr = np.zeros(natoms)
            for j in np.arange(natoms):
                # Center at atom <index>:
                pos -= pos[j]
                # Minimum image convention with coordinates in range lb*[-0.5,0.5>
                pos[:,0] -= la*(pos[:,0]*2/la).astype('int')
                pos[:,1] -= lb*(pos[:,1]*2/lb).astype('int')
                pos[:,2] -= lc*(pos[:,2]*2/lc).astype('int')
                
                cart = direct_to_cartesian(pos,self._cell)
                dr = np.sqrt(np.sum(cart**2,1))
                cond = np.logical_and(dr < rmax, dr > 0.0)

                dr = dr[cond]
                if dr.shape[0] == 0:
                    print "[Warning]: No neighbours found within %.2f Angstrom of atom %d" % (rmax,j)
                    minr[j] = 1001.0
                    continue

                so = np.argsort(dr)

                #pos = pos[cond]
                #offsets = (2*pos).astype('int')
                ##indices = indices[cond]

                ## sort:
                #dr = dr[so]
                #pos = pos[so]
                #offsets = offsets[so]
                #indices = indices[so]

                #indices, dr, offsets, pos = self.get_neighbours(j)
                paired[j] = indices[cond][so][0]
                minr[j] = dr[so][0]
                #pairs[j,nearest] = 
                #minpair = pairs[j,nearest] 
                #minr = dr[0]
            
            #print nearest,shortest
            minidx = np.argmin(minr)
            minr = minr[minidx]
            if minr > 1000.0:
                print "[Error]: No bonds shorter than %.2f Angstrom found. Please increase rmax" % rmax

            return (minr,minidx,paired[minidx])

        else:

            # Build array of pair indices:
            pairs = get_pairs(natoms, include_self=include_self)
            npairs = pairs.shape[0]

            # Find displacement vectors for all pairs:
            x = pos[pairs[:,0]] - pos[pairs[:,1]]
        
            # Use minimum image convention to threat bonds over PBCs
            # Note: use safe_mode with tilted unit cells in which the 
            # shortest bond is close to half of one of the cell dimensions
            x = x - (2*x).astype('int')

            X = direct_to_cartesian(x, self._cell)

            r2 = (X**2).sum(axis=1)
            r = np.sqrt(r2)

            meanr2 = np.mean(r2,axis=0)
            meanr = np.mean(r,axis=0)

            minidx = np.argmin(r)
            minpair = pairs[minidx]
            minr = r[minidx]
    
            return (minr,minpair[0],minpair[1])
Example #9
0
    def get_neighbours(self, atom_no, rmax = 3.0):
        """
        Returns a list of all atoms within <rmax> of atom <atom_no>,
        including atoms across periodic boundary conditions.
        """

        natoms = self.get_num_atoms()
        a = self._cell[0]
        b = self._cell[1]
        c = self._cell[2]

        # Find distance between opposing faces of the cell:
        wa = abs(np.dot(a,np.cross(b,c))) / np.linalg.norm(np.cross(b,c))
        wb = abs(np.dot(b,np.cross(c,a))) / np.linalg.norm(np.cross(c,a))
        wc = abs(np.dot(c,np.cross(a,b))) / np.linalg.norm(np.cross(a,b))

        # If half the max radius exceeds one of the face-to-face distances (wa, wb or wc), 
        # we add more atoms in the given direction(s) as necessary.
        la = 1 + int(2*rmax/wa)
        lb = 1 + int(2*rmax/wb)
        lc = 1 + int(2*rmax/wc)
        #print "dim:",la,lb,lc
        #p2 = self.get_supercell_positions(la,lb,lc, coords='d')

        pos = np.zeros((natoms*la*lb*lc,3))
        offsets = np.zeros((natoms*la*lb*lc,3), dtype=np.int)
        #c = np.diag((1,1,1)) # since we use direct coordinates
        for i in range(la):
            for j in range(lb):
                for k in range(lc):
                    m = i*lb*lc + j*lc + k
                    pos[m*natoms:(m+1)*natoms] = self._positions + np.array((i, j, k))
                    offsets[m*natoms:(m+1)*natoms] = [i, j, k]

        indices = np.tile(np.arange(0,natoms), la*lb*lc)

        # Center at atom <index>:
        pos -= pos[atom_no]
        # Minimum image convention with coordinates in range lb*[-0.5,0.5>
        pos[:,0] -= la*(pos[:,0]*2/la).astype('int')
        pos[:,1] -= lb*(pos[:,1]*2/lb).astype('int')
        pos[:,2] -= lc*(pos[:,2]*2/lc).astype('int')
        
        cart = direct_to_cartesian(pos, self._cell)
        dr = np.sqrt(np.sum(cart**2, axis = 1))
        cond = np.logical_and(dr < rmax, dr > 0.0)

        dr = dr[cond]
        pos = pos[cond]
        offsets = (2*pos).astype('int')
        indices = indices[cond]

        if len(dr) == 0:
            q = np.sqrt(np.sum(cart**2, axis = 1))
            q = q[q>0.]
            print u'No neighbours within %.2f Å. Nearest neighbour found at %.2f Å' % (rmax, np.sort(q)[0])
            return None

        # sort:
        so = np.argsort(dr)
        dr = dr[so]
        pos = pos[so]
        offsets = offsets[so]
        indices = indices[so]

        return indices, dr, offsets, pos
Example #10
0
 def get_velocities(self, coords):
     """ (n,3) array """
     if coords[0].lower() == 'd':
         return self._velocities
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._velocities, self._cell)
Example #11
0
pos = poscar1.get_positions(coords='direct')
natoms = pos.shape[0]

# Build array of pair indices:
pairs = get_pairs(natoms)
npairs = pairs.shape[0]

print "%d atoms, %d pairs" % (natoms, npairs)

# Find displacement vectors for all atoms:
x = pos[pairs[:, 0]] - pos[pairs[:, 1]]

# Use minimum image convention to threat bonds over PBCs
# Note: This will not work with *very* tilted unit cells
x = x - (2 * x).astype('int')

X = direct_to_cartesian(x, poscar1.get_cell())

r2 = (X**2).sum(axis=1)
r = np.sqrt(r2)

meanr2 = np.mean(r2, axis=0)
meanr = np.mean(r, axis=0)

minidx = np.argmin(r)
minpair = pairs[minidx]
minr = r[minidx]

print "Shortest bond is: %.3f Angstrom (between atoms %d and %d)" % (
    minr, minpair[0], minpair[1])
Example #12
0
    def get_shortest_bond(self, include_self=False, safe_mode=True, rmax=3.0):
        """
        Returns a tupple containing the shortest bond length in Angstrom,
        followed by the indices of the two atoms making up the bond
        
        Parameters:
            include_self : bool (default False)
                Whether to check for bonds between an atom and its _own_ periodic image.
                This is only needed for very small unit cells, typically with a single atom.
            safe_mode : bool (default True)
                Much slower, but safer for non-cubic cells
            rmax : float (default 3.0)
                Maximum bond length (in Angstrom) to check for 
                (only used in safe_mode)

        """
        a = self._cell[0]
        b = self._cell[1]
        c = self._cell[2]

        pos = self._positions
        natoms = pos.shape[0]
        if natoms == 1:
            print "Note from get_shortest_bond(): include_self is enabled since only a single atom was found!"
            include_self = True

        # Limit to sphere of radius Rc
        if safe_mode:
            #if include_self:
            #    print "include_self and safe_mode are not currently compatible. sorry"
            #    return

            natoms = self.get_num_atoms()
            a = self._cell[0]
            b = self._cell[1]
            c = self._cell[2]

            # Find distance between opposing faces of the cell:
            wa = abs(np.dot(a, np.cross(b, c))) / np.linalg.norm(np.cross(
                b, c))
            wb = abs(np.dot(b, np.cross(c, a))) / np.linalg.norm(np.cross(
                c, a))
            wc = abs(np.dot(c, np.cross(a, b))) / np.linalg.norm(np.cross(
                a, b))

            # If half the max radius exceeds one of the face-to-face distances (wa, wb or wc),
            # we add more atoms in the given direction(s) as necessary.
            la = 1 + int(2 * rmax / wa)
            lb = 1 + int(2 * rmax / wb)
            lc = 1 + int(2 * rmax / wc)
            print "dim:", la, lb, lc
            #p2 = self.get_supercell_positions(la,lb,lc, coords='d')
            pos = np.zeros((natoms * la * lb * lc, 3))
            #offsets = np.zeros((natoms*la*lb*lc,3), dtype=np.int)
            #c = np.diag((1,1,1)) # since we use direct coordinates
            for i in range(la):
                for j in range(lb):
                    for k in range(lc):
                        m = i * lb * lc + j * lc + k
                        pos[m * natoms:(m + 1) *
                            natoms] = self._positions + np.array((i, j, k))
                        #offsets[m*natoms:(m+1)*natoms] = [i, j, k]
            indices = np.tile(np.arange(natoms), la * lb * lc)

            paired = np.zeros(natoms, dtype=np.int)
            minr = np.zeros(natoms)
            for j in np.arange(natoms):
                # Center at atom <index>:
                pos -= pos[j]
                # Minimum image convention with coordinates in range lb*[-0.5,0.5>
                pos[:, 0] -= la * (pos[:, 0] * 2 / la).astype('int')
                pos[:, 1] -= lb * (pos[:, 1] * 2 / lb).astype('int')
                pos[:, 2] -= lc * (pos[:, 2] * 2 / lc).astype('int')

                cart = direct_to_cartesian(pos, self._cell)
                dr = np.sqrt(np.sum(cart**2, 1))
                cond = np.logical_and(dr < rmax, dr > 0.0)

                dr = dr[cond]
                if dr.shape[0] == 0:
                    print "[Warning]: No neighbours found within %.2f Angstrom of atom %d" % (
                        rmax, j)
                    minr[j] = 1001.0
                    continue

                so = np.argsort(dr)

                #pos = pos[cond]
                #offsets = (2*pos).astype('int')
                ##indices = indices[cond]

                ## sort:
                #dr = dr[so]
                #pos = pos[so]
                #offsets = offsets[so]
                #indices = indices[so]

                #indices, dr, offsets, pos = self.get_neighbours(j)
                paired[j] = indices[cond][so][0]
                minr[j] = dr[so][0]
                #pairs[j,nearest] =
                #minpair = pairs[j,nearest]
                #minr = dr[0]

            #print nearest,shortest
            minidx = np.argmin(minr)
            minr = minr[minidx]
            if minr > 1000.0:
                print "[Error]: No bonds shorter than %.2f Angstrom found. Please increase rmax" % rmax

            return (minr, minidx, paired[minidx])

        else:

            # Build array of pair indices:
            pairs = get_pairs(natoms, include_self=include_self)
            npairs = pairs.shape[0]

            # Find displacement vectors for all pairs:
            x = pos[pairs[:, 0]] - pos[pairs[:, 1]]

            # Use minimum image convention to threat bonds over PBCs
            # Note: use safe_mode with tilted unit cells in which the
            # shortest bond is close to half of one of the cell dimensions
            x = x - (2 * x).astype('int')

            X = direct_to_cartesian(x, self._cell)

            r2 = (X**2).sum(axis=1)
            r = np.sqrt(r2)

            meanr2 = np.mean(r2, axis=0)
            meanr = np.mean(r, axis=0)

            minidx = np.argmin(r)
            minpair = pairs[minidx]
            minr = r[minidx]

            return (minr, minpair[0], minpair[1])
Example #13
0
    def get_neighbours(self, atom_no, rmax=3.0):
        """
        Returns a list of all atoms within <rmax> of atom <atom_no>,
        including atoms across periodic boundary conditions.
        """

        natoms = self.get_num_atoms()
        a = self._cell[0]
        b = self._cell[1]
        c = self._cell[2]

        # Find distance between opposing faces of the cell:
        wa = abs(np.dot(a, np.cross(b, c))) / np.linalg.norm(np.cross(b, c))
        wb = abs(np.dot(b, np.cross(c, a))) / np.linalg.norm(np.cross(c, a))
        wc = abs(np.dot(c, np.cross(a, b))) / np.linalg.norm(np.cross(a, b))

        # If half the max radius exceeds one of the face-to-face distances (wa, wb or wc),
        # we add more atoms in the given direction(s) as necessary.
        la = 1 + int(2 * rmax / wa)
        lb = 1 + int(2 * rmax / wb)
        lc = 1 + int(2 * rmax / wc)
        #print "dim:",la,lb,lc
        #p2 = self.get_supercell_positions(la,lb,lc, coords='d')

        pos = np.zeros((natoms * la * lb * lc, 3))
        offsets = np.zeros((natoms * la * lb * lc, 3), dtype=np.int)
        #c = np.diag((1,1,1)) # since we use direct coordinates
        for i in range(la):
            for j in range(lb):
                for k in range(lc):
                    m = i * lb * lc + j * lc + k
                    pos[m * natoms:(m + 1) *
                        natoms] = self._positions + np.array((i, j, k))
                    offsets[m * natoms:(m + 1) * natoms] = [i, j, k]

        indices = np.tile(np.arange(0, natoms), la * lb * lc)

        # Center at atom <index>:
        pos -= pos[atom_no]
        # Minimum image convention with coordinates in range lb*[-0.5,0.5>
        pos[:, 0] -= la * (pos[:, 0] * 2 / la).astype('int')
        pos[:, 1] -= lb * (pos[:, 1] * 2 / lb).astype('int')
        pos[:, 2] -= lc * (pos[:, 2] * 2 / lc).astype('int')

        cart = direct_to_cartesian(pos, self._cell)
        dr = np.sqrt(np.sum(cart**2, axis=1))
        cond = np.logical_and(dr < rmax, dr > 0.0)

        dr = dr[cond]
        pos = pos[cond]
        offsets = (2 * pos).astype('int')
        indices = indices[cond]

        if len(dr) == 0:
            q = np.sqrt(np.sum(cart**2, axis=1))
            q = q[q > 0.]
            print u'No neighbours within %.2f Å. Nearest neighbour found at %.2f Å' % (
                rmax, np.sort(q)[0])
            return None

        # sort:
        so = np.argsort(dr)
        dr = dr[so]
        pos = pos[so]
        offsets = offsets[so]
        indices = indices[so]

        return indices, dr, offsets, pos
Example #14
0
 def get_velocities(self, coords):
     """ (n,3) array """
     if coords[0].lower() == 'd':
         return self._velocities
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._velocities, self._cell)
Example #15
0
 def get_positions(self, coords):
     if coords[0].lower() == 'd':
         return self._positions.copy()
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._positions, self._cell)
    def __init__(self, trajectory, n_bins = 10, atoms = [10], smin = 1000, smax = 20000, cache = None, 
            step = 5):
        
        struc = trajectory.get_snapshot(0)
        vol = struc.get_volume()
        s = sqrt(np.sum(struc.get_cell()[0]**2)) # sidelength a
        #max_dist = sqrt(3*(s/2.)**2) # max distance between atoms in 3D

        self.max_dist = s / 2. # the largest sphere that can be inscribed in a cube of side L

        print "Sidelength: %.2f Å, volume: %.2f Å^3, max r: %.2f Å" % (s, vol, self.max_dist)

        if n_bins == 'auto':
            rr = 0. # mean atom-atom distance
            for i in range(trajectory.natoms):
                rr += struc.get_neighbours(i)[1].mean()
            rr /= trajectory.natoms
            n_bins = int(self.max_dist / (0.025 * rr))
            # the value 0.025 rr from J. M. Haile. Molecular dynamics simulation : elementary methods. Wiley, 1992, p. 263
            print "Average atom-atom distance: %.2f Angstrom => setting n_bins = %d" % (rr, n_bins)

        
        self.dr = self.max_dist / n_bins
        print "Number of bins: %d, makes dr = %.2f Å" % (n_bins, self.dr)
        
        nsteps = trajectory.length
        natoms = trajectory.num_atoms
        
        self.density = natoms / vol
        
        if cache != None:
            hasher = hashlib.sha1()
            f = open(trajectory.filename, 'rb')
            try:
                hasher.update(f.read())
            finally:
                f.close()
            trajhash = hasher.hexdigest()
            print "Trajectory hash:",trajhash

            if os.path.isfile(cache):
                pkl_file = open(cache, 'rb')
                data1 = pickle.load(pkl_file)
                params = data1['params']
                if params['hash'] != trajhash:
                    print 'Note: Trajectory file hash differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['n_bins'] != n_bins:
                    print 'Note: n_bins value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['atoms'] != atoms:
                    print 'Note: atoms value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['smin'] != smin:
                    print 'Note: smin value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['smax'] != smax:
                    print 'Note: smax value differs from value in cache file "%s". Bypassing cache.' % cache
                else:
                    # Hooray, we shall use the cache
                    self.x = data1['r']
                    self.y = data1['g']
                    pkl_file.close()
                    print 'Read data from cache "%s", trajectory has is "%s"' % (cache, trajhash)
                    return
                pkl_file.close()



        #d = 2 # super cell size 
        #fac = 2 * np.pi * d             # 2pi/0.125 = 2pi*8  (0.125 is the smallest distance between atoms in direct coordinates for the 2x2x2 Si cell)


        pos = trajectory.get_positions( coords = 'direct' )
        
        frames = np.arange(smin, np.min([nsteps,smax]), step)
        hist = np.zeros((frames.shape[0], n_bins))
        print hist.shape[0],"steps"
        
        for i, probe_at in enumerate(atoms):
            print "Probing atom %d of %d" % (i+1, len(atoms))

            for i, n in enumerate(frames):

                cpos = pos[n]
                ccell = trajectory.basis[n]

                r = cpos[[x for x in range(cpos.shape[0]) if x != probe_at]] - cpos[probe_at] # use probe_at as center

                # Use minimum image convention to threat bonds over PBCs
                # Note: This will not work with *very* tilted unit cells
                r = r - (2*r).astype('int')

                r = direct_to_cartesian(r, ccell)

                r2 = (r**2).sum(axis=1)
                r = np.sqrt(r2)

                cbin = np.floor(r / self.dr).astype('int')
                # could we vectorise this somehow?
                for x in cbin:
                    if x < n_bins:
                        hist[i,x] += 1


        # Normalize
        hist /= len(atoms)
        #norm = 2.0 * np.pi * dr * density

        self.x = np.zeros(n_bins)
        self.y = np.zeros(n_bins)

        for i in np.arange(0, n_bins):
            shell_r = i * self.dr                                                # distance to beginning of shell
            shell_vol = 4./3. * np.pi * ((shell_r + self.dr)**3 - shell_r**3)    # volume of the shell
            time_avg_n = np.sum(hist[:,i]) / hist.shape[0]                  # time average
            val = time_avg_n / shell_vol / self.density                          # local density to system density ratio

            #natoms / norm / ((rr**2) + (dr**2) / 12.0)
            self.x[i] = shell_r + 0.5*self.dr  # use middle of the shell
            self.y[i] = val

        #self.x = np.arange(n_bins) * dr

        #self.y = np.mean(hist[0:10000], axis = 0)
        ##self.y = np.mean(hist, axis = 0)

        #vmd_r = [0.05, 0.15000000000000002, 0.25, 0.35000000000000003, 0.45, 0.55, 0.65, 0.75, 0.8500000000000001, 0.9500000000000001, 1.05, 1.1500000000000001, 1.25, 1.35, 1.4500000000000002, 1.55, 1.6500000000000001, 1.75, 1.85, 1.9500000000000002, 2.0500000000000003, 2.15, 2.25, 2.35, 2.45, 2.5500000000000003, 2.6500000000000004, 2.75, 2.85, 2.95, 3.0500000000000003, 3.1500000000000004, 3.25, 3.35, 3.45, 3.5500000000000003, 3.6500000000000004, 3.75, 3.85, 3.95, 4.05, 4.15, 4.25, 4.3500000000000005, 4.45, 4.55, 4.65, 4.75, 4.8500000000000005, 4.95, 5.050000000000001, 5.15, 5.25, 5.3500000000000005, 5.45, 5.550000000000001, 5.65, 5.75, 5.8500000000000005, 5.95]
        #vmd_g = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.007519646352273967, 0.16803063700833396, 0.8705159618606413, 1.758370840475422, 2.283940404874828, 1.983953361507034, 1.4766080953857323, 1.1769551771463873, 0.9292292714634547, 0.8134830099213072, 0.7275062820612057, 0.7369909416061019, 0.7738143781341961, 0.8264792577807392, 0.9459870991621928, 1.008875524678367, 1.0764976921218232, 1.1637934824221774, 1.1568744636400938, 1.1417407274585984, 1.1471446817553927, 1.12710440892153, 1.081071932165155, 1.0372008450448278, 0.9681381745490185, 0.9209937945818178, 0.9260629623139609, 0.9387623185735751, 0.9248015478764121, 0.9193931865534244, 0.9593854795073877, 0.969338021724002, 1.0044774942407746, 1.0028481628862973, 1.0456729324756333, 1.0467550666063061, 1.0812861053364635, 1.0873968724468983, 1.102965726490678, 1.0960581045516773, 1.0686904640968937]


        #plt.plot(vmd_r, vmd_g, 'x-')
        #plt.show()
        
        if cache != None:
            # should we ask to overwrite?
            pkl_file = open(cache, 'wb')
            pickle.dump({
                'params': { 'hash': trajhash, 'n_bins': n_bins, 'atoms': atoms, 'smin': smin, 'smax': smax },
                'r': self.x,
                'g': self.y
            }, pkl_file)
            pkl_file.close()
            print 'Wrote cache "%s", trajectory has is "%s"' % (cache, trajhash)
Example #17
0
    def __init__(self,
                 trajectory,
                 n_bins=10,
                 atoms=[10],
                 smin=1000,
                 smax=20000,
                 cache=None,
                 step=5):

        struc = trajectory.get_snapshot(0)
        vol = struc.get_volume()
        s = sqrt(np.sum(struc.get_cell()[0]**2))  # sidelength a
        #max_dist = sqrt(3*(s/2.)**2) # max distance between atoms in 3D

        self.max_dist = s / 2.  # the largest sphere that can be inscribed in a cube of side L

        print "Sidelength: %.2f Å, volume: %.2f Å^3, max r: %.2f Å" % (
            s, vol, self.max_dist)

        if n_bins == 'auto':
            rr = 0.  # mean atom-atom distance
            for i in range(trajectory.natoms):
                rr += struc.get_neighbours(i)[1].mean()
            rr /= trajectory.natoms
            n_bins = int(self.max_dist / (0.025 * rr))
            # the value 0.025 rr from J. M. Haile. Molecular dynamics simulation : elementary methods. Wiley, 1992, p. 263
            print "Average atom-atom distance: %.2f Angstrom => setting n_bins = %d" % (
                rr, n_bins)

        self.dr = self.max_dist / n_bins
        print "Number of bins: %d, makes dr = %.2f Å" % (n_bins, self.dr)

        nsteps = trajectory.length
        natoms = trajectory.num_atoms

        self.density = natoms / vol

        if cache != None:
            hasher = hashlib.sha1()
            f = open(trajectory.filename, 'rb')
            try:
                hasher.update(f.read())
            finally:
                f.close()
            trajhash = hasher.hexdigest()
            print "Trajectory hash:", trajhash

            if os.path.isfile(cache):
                pkl_file = open(cache, 'rb')
                data1 = pickle.load(pkl_file)
                params = data1['params']
                if params['hash'] != trajhash:
                    print 'Note: Trajectory file hash differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['n_bins'] != n_bins:
                    print 'Note: n_bins value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['atoms'] != atoms:
                    print 'Note: atoms value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['smin'] != smin:
                    print 'Note: smin value differs from value in cache file "%s". Bypassing cache.' % cache
                elif params['smax'] != smax:
                    print 'Note: smax value differs from value in cache file "%s". Bypassing cache.' % cache
                else:
                    # Hooray, we shall use the cache
                    self.x = data1['r']
                    self.y = data1['g']
                    pkl_file.close()
                    print 'Read data from cache "%s", trajectory has is "%s"' % (
                        cache, trajhash)
                    return
                pkl_file.close()

        #d = 2 # super cell size
        #fac = 2 * np.pi * d             # 2pi/0.125 = 2pi*8  (0.125 is the smallest distance between atoms in direct coordinates for the 2x2x2 Si cell)

        pos = trajectory.get_positions(coords='direct')

        frames = np.arange(smin, np.min([nsteps, smax]), step)
        hist = np.zeros((frames.shape[0], n_bins))
        print hist.shape[0], "steps"

        for i, probe_at in enumerate(atoms):
            print "Probing atom %d of %d" % (i + 1, len(atoms))

            for i, n in enumerate(frames):

                cpos = pos[n]
                ccell = trajectory.basis[n]

                r = cpos[[x for x in range(cpos.shape[0]) if x != probe_at
                          ]] - cpos[probe_at]  # use probe_at as center

                # Use minimum image convention to threat bonds over PBCs
                # Note: This will not work with *very* tilted unit cells
                r = r - (2 * r).astype('int')

                r = direct_to_cartesian(r, ccell)

                r2 = (r**2).sum(axis=1)
                r = np.sqrt(r2)

                cbin = np.floor(r / self.dr).astype('int')
                # could we vectorise this somehow?
                for x in cbin:
                    if x < n_bins:
                        hist[i, x] += 1

        # Normalize
        hist /= len(atoms)
        #norm = 2.0 * np.pi * dr * density

        self.x = np.zeros(n_bins)
        self.y = np.zeros(n_bins)

        for i in np.arange(0, n_bins):
            shell_r = i * self.dr  # distance to beginning of shell
            shell_vol = 4. / 3. * np.pi * (
                (shell_r + self.dr)**3 - shell_r**3)  # volume of the shell
            time_avg_n = np.sum(hist[:, i]) / hist.shape[0]  # time average
            val = time_avg_n / shell_vol / self.density  # local density to system density ratio

            #natoms / norm / ((rr**2) + (dr**2) / 12.0)
            self.x[i] = shell_r + 0.5 * self.dr  # use middle of the shell
            self.y[i] = val

        #self.x = np.arange(n_bins) * dr

        #self.y = np.mean(hist[0:10000], axis = 0)
        ##self.y = np.mean(hist, axis = 0)

        #vmd_r = [0.05, 0.15000000000000002, 0.25, 0.35000000000000003, 0.45, 0.55, 0.65, 0.75, 0.8500000000000001, 0.9500000000000001, 1.05, 1.1500000000000001, 1.25, 1.35, 1.4500000000000002, 1.55, 1.6500000000000001, 1.75, 1.85, 1.9500000000000002, 2.0500000000000003, 2.15, 2.25, 2.35, 2.45, 2.5500000000000003, 2.6500000000000004, 2.75, 2.85, 2.95, 3.0500000000000003, 3.1500000000000004, 3.25, 3.35, 3.45, 3.5500000000000003, 3.6500000000000004, 3.75, 3.85, 3.95, 4.05, 4.15, 4.25, 4.3500000000000005, 4.45, 4.55, 4.65, 4.75, 4.8500000000000005, 4.95, 5.050000000000001, 5.15, 5.25, 5.3500000000000005, 5.45, 5.550000000000001, 5.65, 5.75, 5.8500000000000005, 5.95]
        #vmd_g = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.007519646352273967, 0.16803063700833396, 0.8705159618606413, 1.758370840475422, 2.283940404874828, 1.983953361507034, 1.4766080953857323, 1.1769551771463873, 0.9292292714634547, 0.8134830099213072, 0.7275062820612057, 0.7369909416061019, 0.7738143781341961, 0.8264792577807392, 0.9459870991621928, 1.008875524678367, 1.0764976921218232, 1.1637934824221774, 1.1568744636400938, 1.1417407274585984, 1.1471446817553927, 1.12710440892153, 1.081071932165155, 1.0372008450448278, 0.9681381745490185, 0.9209937945818178, 0.9260629623139609, 0.9387623185735751, 0.9248015478764121, 0.9193931865534244, 0.9593854795073877, 0.969338021724002, 1.0044774942407746, 1.0028481628862973, 1.0456729324756333, 1.0467550666063061, 1.0812861053364635, 1.0873968724468983, 1.102965726490678, 1.0960581045516773, 1.0686904640968937]

        #plt.plot(vmd_r, vmd_g, 'x-')
        #plt.show()

        if cache != None:
            # should we ask to overwrite?
            pkl_file = open(cache, 'wb')
            pickle.dump(
                {
                    'params': {
                        'hash': trajhash,
                        'n_bins': n_bins,
                        'atoms': atoms,
                        'smin': smin,
                        'smax': smax
                    },
                    'r': self.x,
                    'g': self.y
                }, pkl_file)
            pkl_file.close()
            print 'Wrote cache "%s", trajectory has is "%s"' % (cache,
                                                                trajhash)
Example #18
0
 def get_positions(self, coords):
     if coords[0].lower() == 'd':
         return self._positions.copy()
     elif coords[0].lower() == 'c':
         return direct_to_cartesian(self._positions, self._cell)
Example #19
0
poscar1 = PoscarParser(args.infile).get_structure()
pos = poscar1.get_positions( coords = 'direct' )
natoms = pos.shape[0]

# Build array of pair indices:
pairs = get_pairs(natoms)
npairs = pairs.shape[0]

print "%d atoms, %d pairs" % (natoms, npairs)

# Find displacement vectors for all atoms:
x = pos[pairs[:,0]] - pos[pairs[:,1]]

# Use minimum image convention to threat bonds over PBCs
# Note: This will not work with *very* tilted unit cells
x = x - (2*x).astype('int')

X = direct_to_cartesian(x, poscar1.get_cell())

r2 = (X**2).sum(axis=1)
r = np.sqrt(r2)

meanr2 = np.mean(r2,axis=0)
meanr = np.mean(r,axis=0)

minidx = np.argmin(r)
minpair = pairs[minidx]
minr = r[minidx]

print "Shortest bond is: %.3f Angstrom (between atoms %d and %d)" % (minr,minpair[0],minpair[1])
Example #20
0
    def __init__(self, trajectory, lattice, atom = 0, nn = 8, step = 50, remove_lattice_drift = True, cache = True):
        """
        DistanceFromLatticeSites class
        
        Parameters:
            - trajectory : oppvasp.Trajectory object
            - lattice    : oppvasp.Structure object describing the lattice sites
            - atom       : atom to follow
            - nn         : number of nearest sites
            - step       : step size
        """

        if trajectory.pbc_unwrapped:
            print "----"
            print "DistanceFromLatticeSites: Probably best to use a trajectory with PBCs (no unwrapping)"
            print "----"

        self.entered_site = Event()
        self.left_site = Event()
        self.bottombar_labels = {}
        self.bottombar_height = .5
        self.bottombar_colors = {}
        self.valid = True

        self.lattice = lattice
        self.traj = trajectory.get_selection(step = step)
        if self.traj.length <= 1:
            print "[DistanceFromLatticeSites ERROR] Trajectory selection is too short. Aborting"
            self.valid = False
            return

        ts = self.traj.time[1] - self.traj.time[0]
        print "[DistanceFromLatticeSites] Timestamp for trajectory selection is %.f fs" % ts

        p = trajectory.path.split('/')
        basename = p.pop()
        cache_file = '/'.join(p) + '/' + basename.rsplit('.',1)[0] + '_dist_from_lattice.pkl'
        print "cache file:",cache_file
        
        if cache and os.path.isfile(cache_file):
            pkl_file = open(cache_file, 'rb')
            data = pickle.load(pkl_file)
            pkl_file.close()
            self.x = data['x']
            self.y = data['y']
            self.sites = data['sites']
            print "[DistanceFromLatticeSites] Loaded from cache %s" % cache_file
            return
            #checks?
            
        
        if remove_lattice_drift:
            print "[DistanceFromLatticeSites] Calculating drift using AvgDistPlotter"
            avg = AvgDistPlotter(trajectory = self.traj, lattice = self.lattice, step = 1)
            drift = avg.y_smoothed

        
        pos = self.traj.get_positions(coords = 'direct')
        print "Min/max: %.2f / %.2f" % (np.min(pos), np.max(pos))

        print "[DistanceFromLatticeSites] Unwrapping PBCs before smoothing"
        self.traj.unwrap_pbc()
        pos = self.traj.get_positions(coords = 'direct')
        self.traj.wrap_pbc()
        print "Min/max: %.2f / %.2f" % (np.min(pos), np.max(pos))

        print "[DistanceFromLatticeSites] Generating symmetric running mean..."
        atpos = pos[:,atom]
        atpos = symmetric_running_mean(atpos, 250/ts)
        atpos = symmetric_running_mean(atpos, 500/ts)

        # Wrap back into cell
        atpos = atpos - np.floor(atpos)
        print "Min/max: %.2f / %.2f" % (np.min(atpos), np.max(atpos))

        np.save('temp.npz', atpos)

        cell = self.traj.basis
        latpos = lattice.get_positions(coords = 'direct')

        natoms = pos.shape[1]
        nsteps = pos.shape[0]
        nsites = latpos.shape[0]
        #print "[DistanceFromLatticeSites] Reference lattice contains %d lattice sites" % (nsites)

        dists = np.zeros((nsteps, nn), dtype=np.float)
        sites = np.zeros((nsteps, nn), dtype=np.int)

        pbar = ProgressBar(widgets=['[DistanceFromLatticeSites] Analysing step ',SimpleProgress(),'...'], maxval = nsteps).start()
        for i in np.arange(0, nsteps):
            pbar.update(i)

            # Find displacement vectors between atom and all sites:
            r = atpos[i] - latpos

            # Use minimum image convention to threat bonds over PBCs
            # Note: This will not work with *very* tilted unit cells
            r = r - (2*r).astype('int')
            #r = r - np.floor(r)

            r = direct_to_cartesian(r, cell[i])
            if remove_lattice_drift:
                r -= drift[i] # cartesian? yes

            r2 = (r**2).sum(axis=1)
            r = np.sqrt(r2)

            idx = np.argsort(r)
            dists[i] = r[idx[0:nn]]
            sites[i] = idx[0:nn]

            #print "Shortest bond is: %.3f Angstrom (between atoms %d and %d)" % (minr,minpair[0],minpair[1])
            #break
        pbar.finish()

        #dists = symmetric_running_median(dists,6)
        #dists = symmetric_running_mean(dists,2)

        self.x = self.traj.time/1000.
        self.y = dists
        self.sites = sites

        pkl_file = open(cache_file, 'wb')
        pickle.dump({'x': self.x, 'y': self.y, 'sites': self.sites, 'trajectory': self.traj.path, 'lattice': lattice }, pkl_file)
        pkl_file.close()
        print "[DistanceFromLatticeSites] Wrote cache file: %s" % cache_file