Exemplo n.º 1
0
def epsilon_infty(pot, at, deltafield=0.001, zerotol=1e-5):
   """
   Calculate dielectric tensor.

   Potential must be polarisable and allow an external electic field to be applied.
   """

   dielectric_tensor = fzeros((3,3))
   celldip = fzeros((3,3))

   # Calculation with no applied field
   pot.calc(at, force=True, restart=True, applied_efield=False)
   celldip0 = at.dipoles.sum(axis=2)/BOHR

   at.add_property('ext_efield', 0., n_cols=3)

   # Now we apply field along each of x,y,z in turn, and
   # calculate overall cell dipole moment
   for i in frange(3):

      at.ext_efield[:] = 0.0
      at.ext_efield[i,:] += deltafield/(BOHR/HARTREE)

      pot.calc(at, force=True, applied_efield=True)
      celldip[:,i] = at.dipoles.sum(axis=2)/BOHR
      dielectric_tensor[:,i] = celldip[:,i] - celldip0
      
   dielectric_tensor = 4.0*PI*dielectric_tensor/deltafield/(at.cell_volume()/BOHR**3) + fidentity(3)
   at.ext_efield[:] = 0.0

   dielectric_tensor[dielectric_tensor < zerotol] = 0.0

   return dielectric_tensor
Exemplo n.º 2
0
    def __getitem__(self, i):
        if not self.initialised:
            if self is self.parent.hysteretic_connect:
                self.calc_connect_hysteretic(self.parent)
            else:
                self.calc_connect(self.parent)

        distance = farray(0.0)
        diff = fzeros(3)
        cosines = fzeros(3)
        shift = fzeros(3, dtype=np.int32)

        res = []
        if not get_fortran_indexing():
            i = i + 1  # convert to 1-based indexing

        for n in frange(self.n_neighbours(i)):
            j = self.neighbour(self.parent, i, n, distance, diff, cosines,
                               shift)
            if not get_fortran_indexing():
                j = j - 1
            res.append(NeighbourInfo(j, distance, diff, cosines, shift))

        if get_fortran_indexing():
            res = farray(res)  # to give 1-based indexing
        return res
Exemplo n.º 3
0
def find_mapping(at_in, vectors, lattice_constant, tol=1e-4):
   """
   Find a mapping between pairs of atoms displaced by a given vector
   (or by one of a number of given vectors).
   """

   class FoundMapping:
      pass

   mapping = fzeros(at_in.n, dtype=np.int32)
   at = at_in.copy()

   # cutoff should be larger than all displacment vectors
   vlen = [farray(vector).norm()*lattice_constant for vector in vectors]
   at.set_cutoff(max(vlen)+0.5)
   print 'cutoff = ', at.cutoff
   at.calc_connect()

   for i in at.indices:
      try:
         for neighb in at.neighbours[i]:
            for vector in vectors:
               if ((neighb.diff/lattice_constant - vector)**2).sum() < tol:
                  print i, neighb.j, vector
                  mapping[i] = neighb.j
                  raise FoundMapping

         # corresponding atom is off the edge, so map atom onto itself
         print i, 'not found!'
         mapping[i] = i
      except FoundMapping:
         continue

   return mapping
Exemplo n.º 4
0
def calc_effective_charge_vectors(a, born_tensor):

   effective_charge = fzeros(3)
   for i in frange(a.n):
      p_norm = a.phonon[i]/np.sqrt(np.dot(a.phonon[i],a.phonon[i]))
      disp = (p_norm/np.sqrt(ElementMass[str(a.species[i])]*MASSCONVERT))/BOHR
      print disp
      effective_charge = effective_charge + dot(born_tensor[:,:,i], disp)

   return effective_charge
Exemplo n.º 5
0
    def calc(self, at, grad=False, args_str=None, **calc_args):
        """
        Calculates all descriptors of this type in the Atoms object, and
        gradients if grad=True. Results can be accessed dictionary- or
        attribute-style; 'descriptor' contains descriptor values, 
        'descriptor_index_0based' contains the 0-based indices of the central 
        atom(s) in each descriptor, 'grad' contains gradients, 
        'grad_index_0based' contains indices to gradients (descriptor, atom).
        Cutoffs and gradients of cutoffs are also returned.
        """
        if args_str is None:
            args_str = dict_to_args_str(calc_args)

        n_index = fzeros(1, 'i')
        n_desc, n_cross = self.descriptor_sizes(at, n_index=n_index)
        n_index = n_index[1]
        data = fzeros((self.n_dim, n_desc))
        cutoff = fzeros(n_desc)
        data_index = fzeros((n_index, n_desc), 'i')

        if grad:
            # n_cross is number of cross-terms, proportional to n_desc
            data_grad = fzeros((self.n_dim, 3, n_cross))
            data_grad_index = fzeros((2, n_cross), 'i')
            cutoff_grad = fzeros((3, n_cross))

        if not grad:
            RawDescriptor.calc(self,
                               at,
                               descriptor_out=data,
                               covariance_cutoff=cutoff,
                               descriptor_index=data_index,
                               args_str=args_str)
        else:
            RawDescriptor.calc(self,
                               at,
                               descriptor_out=data,
                               covariance_cutoff=cutoff,
                               descriptor_index=data_index,
                               grad_descriptor_out=data_grad,
                               grad_descriptor_index=data_grad_index,
                               grad_covariance_cutoff=cutoff_grad,
                               args_str=args_str)

        results = DescriptorCalcResult()
        convert = lambda data: np.array(data).T
        results.descriptor = convert(data)
        results.cutoff = convert(cutoff)
        results.descriptor_index_0based = convert(data_index - 1)
        if grad:
            results.grad = convert(data_grad)
            results.grad_index_0based = convert(data_grad_index - 1)
            results.cutoff_grad = convert(cutoff_grad)

        return results
Exemplo n.º 6
0
def screened_effective_charge(born, eps):
   """
   Compute screened effective charge tensor from Born and dielectric tensors
   """

   screened = fzeros((3,3,3,3))
   for i in frange(3):
      for j in frange(3):
         for k in frange(3):
            for l in frange(3):
               if eps[k,l] == 0.0: continue
               screened[i,j,k,l] = born[i,j]/np.sqrt(eps[k,l])

   return screened
Exemplo n.º 7
0
def force_test(at, p, dx=1e-4):
    """
    Compare analyric and numeric forces for the Potential `p` with Atoms `at`

    Finite difference derivates are calculated by moving each atom by `dx`.
    """
    analytic_f = fzeros((3, at.n))
    p.calc(at, force=analytic_f)
    num_f = fzeros((3, at.n))
    ep, em = farray(0.0), farray(0.0)

    for i in frange(at.n):
        for j in (1, 2, 3):
            ap = at.copy()
            ap.pos[j, i] += dx
            p.calc(ap, energy=ep)
            print 'e+', j, i, ep
            ap.pos[j, i] -= 2.0 * dx
            p.calc(ap, energy=em)
            print 'e-', j, i, em
            num_f[j, i] = -(ep - em) / (2 * dx)

    return analytic_f, num_f, analytic_f - num_f
Exemplo n.º 8
0
def born_effective_charge(pot, at0, dx=1e-5, args_str=None):
   """
   Calculate Born effective charges for all atoms in at0

   Potential must be polarizable, i.e. compute dipole moments.
   """

   born_tensor = fzeros((3,3,at0.n))

   restart = True
   for i in frange(at0.n):
      for j in frange(3):

         at = at0.copy()
         at.pos[j,i] -= dx
         at.calc_connect()

         pot.calc(at, force=True, restart=restart, args_str=args_str)
         restart = True

         dip1 = fzeros(3)
         for k in frange(at.n):
            dip1 += at.dipoles[k] + at.charge[k]*at.pos[:,k]

         at = at0.copy()
         at.pos[j,i] += dx
         at.calc_connect()

         pot.calc(at, force=True, restart=restart, args_str=args_str)
         
         dip2 = fzeros(3)
         for k in frange(at.n):
            dip2 += at.dipoles[k] + at.charge[k]*at.pos[:,k]

         born_tensor[:,j,i] = (dip2 - dip1)/(dx*2.0)

   return born_tensor
Exemplo n.º 9
0
def unpack_reftraj_output_str_to_results(data):
    lines = data.strip().split('\n')
    nstep = int(lines[0])
    natoms = int(lines[1])
    energy = float(lines[2])
    force = farray(np.loadtxt(lines[3:-1])).T
    v6 = [float(v) for v in lines[-1].split()]
    virial = fzeros((3, 3))
    virial[1, 1], virial[2, 2], virial[3,
                                       3], virial[1,
                                                  2], virial[2,
                                                             3], virial[1,
                                                                        3] = v6
    virial[2, 1] = virial[1, 2]
    virial[3, 2] = virial[2, 3]
    virial[3, 1] = virial[1, 3]
    return (nstep, natoms, energy, force, virial)
Exemplo n.º 10
0
    def read_header(xdatcar):
       comment = p.readline().rstrip()
       if comment.find("Direct configuration") == 0: # is the beginning of some positions
	 return (None, None, comment, None, None, None)
       l = p.readline().strip(); lc_factor=float(l)
       l = p.readline().strip(); a1 = np.real(l.split())
       l = p.readline().strip(); a2 = np.real(l.split())
       l = p.readline().strip(); a3 = np.real(l.split())
       l = p.readline().strip(); at_species = l.split()
       try:
	   ns = [ int(n) for n in at_species ]
	   no_species_read = True
       except:
	   no_species_read = False

       if species is not None:
	  at_species = species.split()
	  have_species = True
       else:
	  if no_species_read:
	     have_species = False
	     for i in range(len(ns)):
		at_species[i] = ("%d" % (i+1))
	  else:
	    have_species = True

       if not no_species_read:
          l = p.readline().strip();
          ns = [ int(n) for n in l.split() ]

       n=0
       for i in range(len(ns)):
	   n += ns[i]

       lat = fzeros( (3,3) )
       lat[:,1] = a1[0:3]
       lat[:,2] = a2[0:3]
       lat[:,3] = a3[0:3]

       lat *= lc_factor
       return (lat, n, comment, ns, at_species, have_species)
Exemplo n.º 11
0
 def callback(at):
     at.set_calculator(calculator)
     if at.calc_energy:
         at.params['energy'] = at.get_potential_energy()
     if at.calc_local_e:
         at.add_property('local_e', 0.0, overwrite=True)
         at.local_e[:] = at.get_potential_energies()
     if at.calc_force:
         at.add_property('force', 0.0, n_cols=3, overwrite=True)
         at.force[:] = at.get_forces().T
     if at.calc_virial:
         stress = at.get_stress()
         virial = fzeros((3, 3))
         virial[:, :] = stress_matrix(-stress * at.get_volume())
         at.params['virial'] = virial
     if at.calc_local_virial:
         stresses = at.get_stresses()
         at.add_property('local_virial', 0.0, n_cols=9, overwrite=True)
         lv = at.local_virial.view(np.ndarray)
         vol_per_atom = at.get_volume() / len(at)
         lv[...] = -stresses.T.reshape((len(at), 9)) * vol_per_atom
Exemplo n.º 12
0
def rotation_matrix(unit, y, z=None, x=None, tol=1e-5):
    """Return 3x3 matrix rotation matrix defining a crack with open
    surface defined by the plane `y`=(l,m.n) or (h,k,i,l), and either
    crack tip line `z` or crack propagation direction `x`."""

    axes = fzeros((3, 3))
    y = MillerIndex(y).as3()

    if (x is None and z is None) or (x is not None and z is not None):
        raise ValueError('exactly one of x and z must be non-null')

    axes[:, 2] = np.dot(unit.g.T, y)  # plane defined by y=(lmn)

    if z is not None:
        z = MillerIndex(z).as3()
        axes[:, 3] = np.dot(unit.lattice, z)  # line defined by z=[pqr]

        axes[:, 2] = axes[:, 2] / axes[:, 2].norm()
        axes[:, 3] = axes[:, 3] / axes[:, 3].norm()

        if abs(np.dot(axes[:, 2], axes[:, 3])) > tol:
            raise ValueError(
                'y (%s) and z (%s) directions are not perpendicular' % (y, z))

        axes[:, 1] = np.cross(axes[:, 2], axes[:, 3])
    else:
        x = MillerIndex(x).as3()
        axes[:, 1] = np.dot(unit.lattice, x)

        axes[:, 2] = axes[:, 2] / axes[:, 2].norm()
        axes[:, 1] = axes[:, 1] / axes[:, 1].norm()

        if abs(np.dot(axes[:, 2], axes[:, 3])) > tol:
            raise ValueError(
                'y (%s) and x (%s) directions are not perpendicular' % (y, x))

        axes[:, 3] = np.cross(axes[:, 1], axes[:, 2])

    # Rotation matrix is transpose of axes matrix
    return axes.T
Exemplo n.º 13
0
from quippy.farray import fzeros

infile = sys.argv[1]
basename = os.path.splitext(infile)[0]

a = Atoms(infile)

grid_size = 0.25
min_void_size = 2.0

nx = int((a.pos[1,:].max() - a.pos[1,:].min())/grid_size)
ny = int((a.pos[2,:].max() - a.pos[2,:].min())/grid_size)
nz = int((a.pos[3,:].max() - a.pos[3,:].min())/grid_size)
n = nx*ny*nz

grid = fzeros((3, n))
radii = fzeros(n)

void_analysis(a, grid_size, min_void_size, grid, radii)

extent = (grid[:,-1] - grid[:,1])

grid = np.array(grid.reshape(3, nx, ny, nz))
radii = np.array(radii.reshape((nx, ny, nz)))

a.write(basename+'.cube', data=radii, extent=extent, 
        origin=[a.pos[1,:].min(), a.pos[2,:].min(), a.pos[3,:].min()])

voids = (radii > min_void_size).nonzero()

void_positions = []
Exemplo n.º 14
0
def orthorhombic_slab(at,
                      tol=1e-5,
                      min_nrep=1,
                      max_nrep=5,
                      graphics=False,
                      rot=None,
                      periodicity=None,
                      vacuum=None,
                      shift=None,
                      verbose=True):
    """Try to construct an orthorhombic cell equivalent to the
       primitive cell `at`, using supercells up to at most `max_nrep`
       repeats. Symmetry must be exact within a tolerance of `tol`. If
       `rot` is not None, we first transform `at` by the rotation
       matrix `rot`. The optional argument `periodicity` can be used to
       fix the periodicity one or more directions. It should be a three
       component vector with value zero in the unconstrained
       directions. The vector `vacuum` can be used to add vacuum in one
       or more directions. `shift` is a three component vector which
       can be used to shift the positions in the final cell. """
    def atoms_near_plane(at, n, d, tol=1e-5):
        """Return a list of atoms within a distance `tol` of the plane defined by np.dot(n, at.pos) == d"""
        pd = np.dot(n, at.pos) - d
        return (abs(pd) < tol).nonzero()[0]

    def sort_by_distance(at, ref_atom, dir, candidates):
        """Return a copy of `candidates` sorted by perpendicular distance from `ref_atom` in direction `dir`"""
        distances_candidates = zip(
            [at.pos[dir, i] - at.pos[dir, ref_atom] for i in candidates],
            candidates)
        distances_candidates.sort()
        return [p for (d, p) in distances_candidates]

    def orthorhombic_box(at):
        """Return a copy of `at` in an orthorhombic box surrounded by vacuum"""
        at = at.copy()
        at.map_into_cell()
        at.set_lattice(
            [[2.0 * (at.pos[1, :].max() - at.pos[1, :].min()), 0.0, 0.0],
             [0.0, 2.0 * (at.pos[2, :].max() - at.pos[2, :].min()), 0.0],
             [0.0, 0.0, 2.0 * (at.pos[3, :].max() - at.pos[3, :].min())]],
            scale_positions=False)
        at.map_into_cell()
        return at

    def discard_outliers(at, indices, dirs, keep_fraction=0.5):
        """Return a copy of `indices` with the atoms with fractional coordinates along directions in `dirs`
           outside +/-`keep_fraction`/2 excluded. Lattice used is close fitting, `at.lattice`/2."""
        g = np.linalg.inv(at.lattice / 2)
        t = np.dot(g, at.pos[:, indices])
        return indices[np.logical_and(
            t[dirs, :] >= -keep_fraction / 2.0,
            t[dirs, :] < keep_fraction / 2.0).all(axis=1)]

    def check_candidate_plane(at,
                              ref_plane,
                              cand_plane,
                              dirs,
                              verbose=False,
                              label=''):
        """Check whether in-plane displacements of atoms listed in `ref_plane` match those of `cand_plane` in directions given by `dirs`"""

        # Which pair of planes has more atoms, reference or candidate?
        if len(ref_plane) < len(cand_plane):
            smaller = ref_plane
            larger = cand_plane
        else:
            smaller = cand_plane
            larger = ref_plane

        matches = {}
        for j in smaller:
            for k in larger:
                if at.z[k] == at.z[j] and abs(at.pos[dirs, k] -
                                              at.pos[dirs, j]).max() < tol:
                    matches[j] = k
                    break

        if verbose:
            print '   ', label, len(matches), '/', len(smaller), 'matches'

        return len(matches) == len(smaller)

    if rot is not None:
        at = transform(at, rot)

    xyz = fidentity(3)
    nrep = min_nrep - 1
    max_dist = fzeros(3)

    if periodicity is not None:
        periodicity = farray(periodicity)
        periodicity = dict(
            zip((periodicity != 0).nonzero()[0],
                periodicity[periodicity != 0]))
    else:
        periodicity = {}

    if verbose:
        for (dir, p) in periodicity.iteritems():
            print 'Periodicity in direction %d fixed at %f' % (dir, p)

    if graphics:
        import atomeye
        viewer = atomeye.AtomEyeViewer()

    while sorted(periodicity.keys()) != [1, 2, 3]:
        nrep += 1
        if nrep > max_nrep:
            raise ValueError('Maximum size of supercell (%d) exceeded' %
                             max_nrep)
        if verbose:
            print '\n\nSupercell %d' % nrep
        sup = supercell(at, nrep, nrep, nrep)
        box = orthorhombic_box(sup)
        box.pos[:] = box.pos - np.tile(box.pos.mean(axis=2), [box.n, 1]).T

        for dir in set([1, 2, 3]) - set(periodicity.keys()):

            if verbose:
                print '  Direction %d' % dir

            other_dirs = list(set([1, 2, 3]) - set([dir]))

            pos_index = zip(box.pos[dir, :], frange(box.n))
            pos_index.sort()

            # Find a pair of planes
            while pos_index:
                ref_pos1, ref_atom1 = pos_index.pop(0)

                # Find atom to define second plane
                while pos_index:
                    ref_pos2, ref_atom2 = pos_index.pop(0)
                    if abs(ref_pos2 - ref_pos1) > tol: break
                else:
                    continue

                ref_plane1 = atoms_near_plane(box, xyz[:, dir],
                                              box.pos[dir, ref_atom1], tol)
                ref_plane2 = atoms_near_plane(box, xyz[:, dir],
                                              box.pos[dir, ref_atom2], tol)

                # Only keep reference atoms in the centre of the cell
                ref_plane1 = discard_outliers(box, ref_plane1, other_dirs)
                ref_plane2 = discard_outliers(box, ref_plane2, other_dirs)

                if len(ref_plane1) > 2 and len(ref_plane2) > 2:
                    # Now we've got two planes, both with more than two atoms in them
                    break
            else:
                # Used up all atoms without finding two planes
                if verbose:
                    print '    No valid reference planes found.\n'
                continue

            if verbose:
                print '    Reference plane #1 through atom %d ' % ref_atom1
                print '    Reference plane #2 through atom %d at distance %r\n' % (
                    ref_atom2, ref_pos2 - ref_pos1)

            if graphics:
                highlight = fzeros(box.n)
                highlight[ref_plane1] = 1
                highlight[ref_plane2] = 2
                box.add_property('highlight', highlight, overwrite=True)
                viewer.show(box, 'highlight')
                viewer.wait()
                raw_input('continue')

            candidates = [
                i for i in frange(box.n)
                if box.pos[dir,
                           i] > box.pos[dir, ref_atom2] + max_dist[dir] + tol
            ]
            candidates = sort_by_distance(box, ref_atom1, dir, candidates)

            while candidates:
                cand1 = candidates.pop(0)

                max_dist[dir] = box.pos[dir, cand1] - box.pos[dir, ref_atom1]

                if verbose:
                    print '    Trying plane through atom %d distance %r' % (
                        cand1, max_dist[dir])

                cand_plane1 = atoms_near_plane(box, xyz[:, dir],
                                               box.pos[dir, cand1], tol)

                for cand2 in sort_by_distance(
                        box, ref_atom1, dir,
                        set(candidates) - set(cand_plane1)):
                    if abs((box.pos[dir, cand2] - box.pos[dir, cand1]) -
                           (box.pos[dir, ref_atom2] -
                            box.pos[dir, ref_atom1])) < tol:
                        if verbose:
                            print '    Found pair to plane, passing through atom %d distance %r ' % (
                                cand2,
                                box.pos[dir, cand2] - box.pos[dir, ref_atom1])
                        break
                else:
                    if verbose:
                        print '    Cannot find second candidate plane.\n'
                    candidates = sort_by_distance(
                        box, ref_atom1, dir,
                        set(candidates) - set(cand_plane1))
                    continue

                if graphics:
                    highlight[cand_plane1] = 3
                    box.highlight[:] = highlight
                    viewer.show(box, 'highlight')
                    viewer.wait()

                cand_plane2 = atoms_near_plane(box, xyz[:, dir],
                                               box.pos[dir, cand2], tol)

                if graphics:
                    highlight[cand_plane2] = 4
                    box.highlight[:] = highlight
                    viewer.show(box, 'highlight')
                    viewer.wait()

                    highlight[cand_plane1] = 0
                    highlight[cand_plane2] = 0

                # Remove cand_plane1 from list of candidates
                candidates = sort_by_distance(
                    box, ref_atom1, dir,
                    set(candidates) - set(cand_plane1))

                # Check ref_plane1 against cand_plane1 and ref_plane2 against cand_plane2 in directions
                # listed in other_dirs
                match1 = check_candidate_plane(box, ref_plane1, cand_plane1,
                                               other_dirs, verbose,
                                               'Plane #1:')
                match2 = check_candidate_plane(box, ref_plane2, cand_plane2,
                                               other_dirs, verbose,
                                               'Plane #2:')

                if match1 and match2:
                    periodicity[dir] = box.pos[dir, cand1] - box.pos[dir,
                                                                     ref_atom1]
                    if verbose:
                        print '\n  Periodicity in direction %d is %f\n' % (
                            dir, box.pos[dir, cand1] - box.pos[dir, ref_atom1])

                    if graphics:
                        highlight[cand_plane1] = 3
                        highlight[cand_plane2] = 3
                        box.highlight[:] = highlight
                        viewer.show(box, 'highlight')
                        viewer.wait()
                        raw_input('continue...')
                    break

                if graphics:
                    raw_input('continue...')
            else:
                # Failed to find match for direction dir
                continue

    # Finally, construct new cell by selecting atoms within first unit cell
    lattice = farray(np.diag([periodicity[1], periodicity[2], periodicity[3]]))
    g = np.linalg.inv(lattice)

    nrepx, nrepy, nrepz = fit_box_in_cell(periodicity[1], periodicity[2],
                                          periodicity[3], at.lattice)

    sup = supercell(at, nrepx, nrepy, nrepz)
    sup.map_into_cell()

    # small shift to avoid coincidental cell alignments
    delta = np.tile([0.01, 0.02, 0.03], [sup.n, 1]).T
    if shift is not None and vacuum is not None:
        delta = delta + np.tile(shift, [sup.n, 1]).T
    t = np.dot(g, sup.pos) + delta

    orthorhombic = sup.select(np.logical_and(t >= -0.5, t < 0.5).all(axis=1))

    if vacuum:
        lattice = farray(np.diag(lattice.diagonal() + vacuum))

    if shift is not None and vacuum is None:
        if verbose:
            print 'Shifting positions by %s' % np.dot(lattice, shift)
        orthorhombic.pos += np.tile(np.dot(lattice, shift),
                                    [orthorhombic.n, 1]).T

    orthorhombic.set_lattice(lattice, scale_positions=False)
    orthorhombic.map_into_cell()
    return orthorhombic
Exemplo n.º 15
0
    def calculate(self, atoms, properties, system_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        # we will do the calculation in place, to minimise number of copies,
        # unless atoms is not a quippy Atoms
        if isinstance(atoms, Atoms):
            self.quippy_atoms = weakref.proxy(atoms)
        else:
            potlog.debug(
                'Potential atoms is not quippy.Atoms instance, copy forced!')
            self.quippy_atoms = Atoms(atoms)
        initial_arrays = self.quippy_atoms.arrays.keys()
        initial_info = self.quippy_atoms.info.keys()

        if properties is None:
            properties = ['energy', 'forces', 'stress']

        # Add any default properties
        properties = set(self.get_default_properties() + properties)

        if len(properties) == 0:
            raise RuntimeError('Nothing to calculate')

        if not self.calculation_required(atoms, properties):
            return

        args_map = {
            'energy': {
                'energy': None
            },
            'energies': {
                'local_energy': None
            },
            'forces': {
                'force': None
            },
            'stress': {
                'virial': None
            },
            'numeric_forces': {
                'force': 'numeric_force',
                'force_using_fd': True,
                'force_fd_delta': 1.0e-5
            },
            'stresses': {
                'local_virial': None
            },
            'elastic_constants': {},
            'unrelaxed_elastic_constants': {}
        }

        # list of properties that require a call to Potential.calc()
        calc_properties = [
            'energy', 'energies', 'forces', 'numeric_forces', 'stress',
            'stresses'
        ]

        # list of other properties we know how to calculate
        other_properties = ['elastic_constants', 'unrelaxed_elastic_constants']

        calc_args = {}
        calc_required = False
        for property in properties:
            if property in calc_properties:
                calc_required = True
                calc_args.update(args_map[property])
            elif property not in other_properties:
                raise RuntimeError(
                    "Don't know how to calculate property '%s'" % property)

        if calc_required:
            self.calc(self.quippy_atoms, args_str=dict_to_args_str(calc_args))

        if 'energy' in properties:
            self.results['energy'] = float(self.quippy_atoms.energy)
        if 'energies' in properties:
            self.results['energies'] = self.quippy_atoms.local_energy.copy(
            ).view(np.ndarray)
        if 'forces' in properties:
            self.results['forces'] = self.quippy_atoms.force.copy().view(
                np.ndarray).T
        if 'numeric_forces' in properties:
            self.results[
                'numeric_forces'] = self.quippy_atoms.numeric_force.copy(
                ).view(np.ndarray).T
        if 'stress' in properties:
            stress = -self.quippy_atoms.virial.copy().view(
                np.ndarray) / self.quippy_atoms.get_volume()
            # convert to 6-element array in Voigt order
            self.results['stress'] = np.array([
                stress[0, 0], stress[1, 1], stress[2, 2], stress[1, 2],
                stress[0, 2], stress[0, 1]
            ])
        if 'stresses' in properties:
            lv = np.array(self.quippy_atoms.local_virial)  # make a copy
            vol_per_atom = self.get(
                'vol_per_atom',
                self.quippy_atoms.get_volume() / len(atoms))
            if isinstance(vol_per_atom, basestring):
                vol_per_atom = self.quippy_atoms.arrays[vol_per_atom]
            self.results['stresses'] = -lv.T.reshape(
                (len(atoms), 3, 3), order='F') / vol_per_atom

        if 'elastic_constants' in properties:
            cij_dx = self.get('cij_dx', 1e-2)
            cij = fzeros((6, 6))
            self.calc_elastic_constants(self.quippy_atoms,
                                        fd=cij_dx,
                                        args_str=self.get_calc_args_str(),
                                        c=cij,
                                        relax_initial=False,
                                        return_relaxed=False)
            if not get_fortran_indexing():
                cij = cij.view(np.ndarray)
            self.results['elastic_constants'] = cij

        if 'unrelaxed_elastic_constants' in properties:
            cij_dx = self.get('cij_dx', 1e-2)
            c0ij = fzeros((6, 6))
            self.calc_elastic_constants(self.quippy_atoms,
                                        fd=cij_dx,
                                        args_str=self.get_calc_args_str(),
                                        c0=c0ij,
                                        relax_initial=False,
                                        return_relaxed=False)
            if not get_fortran_indexing():
                c0ij = c0ij.view(np.ndarray)
            self.results['unrelaxed_elastic_constants'] = c0ij

        # copy back any additional output data to results dictionary
        skip_keys = ['energy', 'force', 'virial', 'numeric_force']
        for key in self.quippy_atoms.arrays.keys():
            if key not in initial_arrays and key not in skip_keys:
                self.results[key] = self.quippy_atoms.arrays[key].copy()
        for key in self.quippy_atoms.info.keys():
            if key not in initial_info and key not in skip_keys:
                if isinstance(self.quippy_atoms.info[key], np.ndarray):
                    self.results[key] = self.quippy_atoms.info[key].copy()
                else:
                    self.results[key] = self.quippy_atoms.info[key]
Exemplo n.º 16
0
def CP2KOutputReader(fh,
                     module=None,
                     type_map=None,
                     kind_map=None,
                     format=None):

    # mapping from run type to (default module index, list of available module)
    run_types = {
        'QS': ['QUICKSTEP'],
        'QMMM': ['FIST', 'QM/MM', 'QUICKSTEP'],
        'MM': ['FIST']
    }

    filename, lines = read_text_file(fh)
    run_type = cp2k_run_type(cp2k_output=lines)

    if type_map is None:
        type_map = {}
    if kind_map is None:
        kind_map = {}

    try:
        available_modules = run_types[run_type]
    except KeyError:
        raise ValueError('Unknown CP2K run type %s' % run_type)

    if module is None:
        module = available_modules[0]

    try:
        cell_index = available_modules.index(module)
    except ValueError:
        raise ValueError("Don't know how to read module %s from file %s" %
                         (module, filename))

    cell_lines = [
        i for i, line in enumerate(lines) if line.startswith(" CELL| Vector a")
    ]
    if cell_lines == []:
        raise ValueError("Cannot find cell in file %s" % filename)

    try:
        cell_line = cell_lines[cell_index]
    except IndexError:
        raise ValueError(
            "Cannot find cell with index %d in file %s for module %s" %
            (cell_index, filename, module))

    lattice = fzeros((3, 3))
    for i in [0, 1, 2]:
        lattice[:,
                i + 1] = [float(c) for c in lines[cell_line + i].split()[4:7]]

    try:
        start_line = lines.index(
            " MODULE %s:  ATOMIC COORDINATES IN angstrom\n" % module)
    except ValueError:
        raise ValueError(
            "Cannot find atomic positions for module %s in file %s" %
            (module, filename))

    kinds = []
    species = []
    Zs = []
    pos = []
    masses = []
    Zeffs = []
    types = []
    qeffs = []
    for line in lines[start_line + 4:]:
        if line.strip() == '':
            break
        if module == 'FIST':
            atom, kind, typ, x, y, z, qeff, mass = line.split()
            types.append(typ)
            Z = type_map.get(typ, 0)
            kind = int(kind)
            if Z == 0:
                Z = kind_map.get(kind, 0)
            Zs.append(Z)
            qeffs.append(float(qeff))
        else:
            atom, kind, sp, Z, x, y, z, Zeff, mass = line.split()
            species.append(sp)
            Zs.append(int(Z))
            Zeffs.append(float(Zeff))
        kinds.append(int(kind))
        pos.append([float(x), float(y), float(z)])
        masses.append(float(mass))

    at = Atoms(n=len(kinds), lattice=lattice)
    at.pos[...] = farray(pos).T
    at.set_atoms(Zs)
    at.add_property('mass', farray(masses) * MASSCONVERT)
    at.add_property('kind', kinds)
    if module == 'FIST':
        at.add_property('type', ' ' * TABLE_STRING_LENGTH)
        at.add_property('qm', False)
        at.qm[:] = (at.type.stripstrings()
                    == '_QM_') | (at.type.stripstrings() == '_LNK')
        at.type[...] = s2a(types, TABLE_STRING_LENGTH)
        at.add_property('qeff', qeffs)
    else:
        at.species[...] = s2a(species, TABLE_STRING_LENGTH)
        at.add_property('zeff', Zeffs)

    yield at
Exemplo n.º 17
0
        if opt.tetra:
            print 'Converting topology from Si-O-Si to Si-Si'
            si_si, si_o, si_si_cutoff = tetrahedra_to_bonds(q)

        if opt.si_si_cutoff is None:
            opt.si_si_cutoff = si_si_cutoff

        dm = distance_map(q, q.n, q.n, diameter=diameter)
        print 'Distance map diameter %d' % diameter
        print 'Max ring size %d' % opt.max_ring_size

        assert (diameter >= opt.max_ring_size)

        print 'Using Si-Si cutoff of %.3f' % opt.si_si_cutoff

        ring_counts = fzeros(opt.max_ring_size, dtype=np.int32)
        count_sp_rings(q, opt.si_si_cutoff, dm, opt.max_ring_size, ring_counts)

        rings_per_si = np.array(ring_counts.astype(float) / (q.z == 14).sum())

        # do it again saving the rings
        n_rings = ring_counts.sum()
        ring_counts[:] = 0
        rings_array = fzeros((opt.max_ring_size + 1, n_rings), dtype=np.int32)
        dr = fzeros((3, opt.max_ring_size, n_rings))
        count_sp_rings(q,
                       opt.si_si_cutoff,
                       dm,
                       opt.max_ring_size,
                       ring_counts,
                       rings_out=rings_array,
Exemplo n.º 18
0
def VASP_POSCAR_Reader(poscar, species=None, format=None):
    """Read a configuration from a VASP POSCAR file.

    Following POSCAR, optionally also read a trajectory from an OUTCAR file."""

    p = open(poscar, 'r')
    comment = p.readline().rstrip()
    l = p.readline().strip()
    lc_factor = float(l)
    l = p.readline().strip()
    a1 = np.real(l.split())
    l = p.readline().strip()
    a2 = np.real(l.split())
    l = p.readline().strip()
    a3 = np.real(l.split())
    l = p.readline().strip()
    at_species = l.split()
    try:
        ns = [int(n) for n in at_species]
        no_species = True
    except:
        no_species = False

    have_species = True
    if (no_species):
        for i in range(len(ns)):
            if (species is not None):
                species_cli = species.split()
                at_species[i] = species_cli[i - 1]
            else:
                have_species = False
                at_species[i] = ("%d" % (i + 1))
    else:
        l = p.readline().strip()
        ns = [int(n) for n in l.split()]

    l = p.readline().strip()
    if (re.compile("^\s*s", re.IGNORECASE).match(l)):
        dyn_type = l
        coord_type = p.readline().strip()
    else:
        coord_type = l

    n = 0
    for i in range(len(ns)):
        n += ns[i]

    lat = fzeros((3, 3))
    lat[:, 1] = a1[0:3]
    lat[:, 2] = a2[0:3]
    lat[:, 3] = a3[0:3]

    lat *= lc_factor

    at = Atoms(n=n, lattice=lat)
    if (len(comment) > 0):
        at.params['VASP_Comment'] = comment

    coord_direct = re.compile("^\s*d", re.IGNORECASE).match(coord_type)

    ii = 1
    for ti in range(len(ns)):
        for i in range(ns[ti]):
            l = p.readline().strip()
            pos = np.array(l.split()[0:3], float)
            if (coord_direct):
                at.pos[:, ii] = np.dot(at.lattice[:, :], pos[:])
            else:
                at.pos[:, ii] = pos[:] * lc_factor
            at.species[:, ii] = at_species[ti]
            ii += 1

    if (have_species):
        at.set_zs()
    else:
        at.Z[:] = [int("".join(n)) for n in at.species[:]]

    yield at
Exemplo n.º 19
0
def VASP_POSCAR_Reader(outcar, species=None, format=None):
    """Read a configuration from a VASP OUTCAR file."""

    if (outcar == 'stdin' or outcar == '-'):
        p = sys.stdin
    else:
        p = open(outcar, 'r')

    re_comment = re.compile("\s*POSCAR:\s*(.+)")
    re_potcar = re.compile("\s*POTCAR:\s*\S+\s+(\S+)")
    re_n_atoms = re.compile("\s*ions per type =\s*((?:\d+\s*)*)")

    energy_i = -1
    at_i = -1
    lat_i = -1
    elements = []
    n_at = -1
    at_cur = None
    for lr in p:
        l = lr.rstrip()
        if (n_at <= 0):
            # parse header type things
            m = re_comment.match(l)
            if (m is not None):
                VASP_Comment = m.group(1)
                # print "got VASP_Comment '%s'" % VASP_Comment
            m = re_potcar.match(l)
            if (m is not None):
                elements.append(m.group(1))
            m = re_n_atoms.match(l)
            if (m is not None):
                # print "got ions per type, groups are:"
                # print m.groups()
                lat = fzeros((3, 3))
                n_types = [int(f) for f in m.group(1).split()]
                n_at = sum(n_types)
                at = Atoms(n=n_at, latttice=lat)
                i_at = 0
                for type_i in range(len(n_types)):
                    for j in range(n_types[type_i]):
                        i_at += 1
                        # print "set species of atom %d to '%s'" % (i_at, elements[type_i])
                        at.species[i_at] = elements[type_i]
                at.set_zs()
        else:
            # parse per-config lattice/pos/force
            if (l.find("direct lattice vectors") >=
                    0):  # get ready to read lattice vectors
                at_cur = at.copy()
                lat_cur = fzeros((3, 3))
                lat_i = 1
            elif (lat_i >= 1 and lat_i <= 3):  # read lattice vectors
                lat_cur[:, lat_i] = [
                    float(r) for r in l.replace("-", " -").split()[0:3]
                ]
                lat_i += 1
            elif (l.find("TOTAL-FORCE (eV/Angst)") >=
                  0):  # get ready to read atomic positions and forces
                if (not hasattr(at_cur, "force")):
                    at_cur.add_property("force", 0.0, n_cols=3)
                at_i = 1
                p.next()
            elif (at_i >= 1
                  and at_i <= at_cur.n):  # read atomic positions and forces
                pos_force = [
                    float(r) for r in l.replace("-", " -").split()[0:6]
                ]
                at_cur.pos[:, at_i] = pos_force[0:3]
                at_cur.force[:, at_i] = pos_force[3:6]
                at_i += 1
            elif (l.find("free  energy") >= 0):  # get ready to read energy
                at_cur.params['Energy'] = float(l.split()[4])
                energy_i = 1
                p.next()
            elif (energy_i == 1):  # read energy
                # print "energy(sigma->0) line"
                # print l.split()
                at_cur.params['Energy_sigma_to_zero'] = float(l.split()[6])
                energy_i += 1
                yield at_cur
            if (at_cur is not None and at_i
                    == at_cur.n):  # at end of configuration, set lattice
                at_cur.set_lattice(lat_cur, False)

    __all__ = ['VASP_POSCAR_Reader', 'VASP_OUTCAR_Reader', 'VASPWriter']
Exemplo n.º 20
0
def CP2KDirectoryReader(run_dir,
                        at_ref=None,
                        proj='quip',
                        calc_qm_charges=None,
                        calc_virial=False,
                        out_i=None,
                        qm_vacuum=6.0,
                        run_suffix='_extended',
                        format=None):
    if at_ref is None:
        filepot_xyz = os.path.join(run_dir, 'filepot.xyz')
        if not os.path.exists(filepot_xyz):
            # try looking up one level
            filepot_xyz = os.path.join(run_dir, '../filepot.xyz')

        if os.path.exists(filepot_xyz):
            at_ref = Atoms(filepot_xyz)
        else:
            at_ref = Atoms(os.path.join(run_dir, 'cp2k_output.out'),
                           format='cp2k_output')

    at = at_ref.copy()

    cp2k_output_filename, cp2k_output = read_text_file(
        os.path.join(run_dir, 'cp2k_output.out'))
    cp2k_params = CP2KInputHeader(
        os.path.join(run_dir, 'cp2k_input.inp.header'))
    at.params.update(cp2k_params)

    run_type = cp2k_run_type(cp2k_output=cp2k_output,
                             cp2k_input_header=cp2k_params)

    try:
        cluster_mark = getattr(at, 'cluster_mark' + run_suffix)
        qm_list_a = ((cluster_mark != HYBRID_NO_MARK).nonzero()[0]).astype(
            np.int32)
    except AttributeError:
        qm_list_a = fzeros(0, dtype=np.int32)

    if calc_qm_charges is None:
        calc_qm_charges = ''

    try:
        cur_qmmm_qm_abc = [
            float(cp2k_params['QMMM_ABC_X']),
            float(cp2k_params['QMMM_ABC_Y']),
            float(cp2k_params['QMMM_ABC_Z'])
        ]
    except KeyError:
        if 'QM_cell' + run_suffix in at.params:
            cur_qmmm_qm_abc = at.params['QM_cell' + run_suffix]
        else:
            cur_qmmm_qm_abc = qmmm_qm_abc(at, qm_list_a, qm_vacuum)

    quip_cp2k_at = Atoms(os.path.join(run_dir, 'quip_cp2k.xyz'))

    rev_sort_index_file = os.path.join(run_dir, '../quip_rev_sort_index')
    fields = [int(x) for x in open(rev_sort_index_file).read().split()]
    rev_sort_index = farray(fields, dtype=np.int32)
    #verbosity_push(PRINT_SILENT)
    cp2k_energy, cp2k_force = read_output(quip_cp2k_at, qm_list_a,
                                          cur_qmmm_qm_abc, run_dir, proj,
                                          calc_qm_charges, calc_virial, True,
                                          3, at.n, out_i)
    #verbosity_pop()

    qm_list = None
    if os.path.exists(os.path.join(run_dir, 'cp2k_input.qmmm_qm_kind')):
        qm_kind_grep_cmd = "grep MM_INDEX %s/cp2k_input.qmmm_qm_kind | awk '{print $2}'" % run_dir
        qm_list = [int(i) for i in os.popen(qm_kind_grep_cmd).read().split()]

    if qm_list is not None:
        if run_type == 'QMMM':
            reordering_index = getattr(at, 'reordering_index', None)

            at.add_property('qm', False, overwrite=True)
            if reordering_index is not None:
                qm_list = reordering_index[qm_list]
            at.qm[qm_list] = True
        elif run_type == 'QS':
            at.add_property('qm_orig_index', 0, overwrite=True)
            for i, qm_at in fenumerate(qm_list):
                at.qm_orig_index[i] = sort_index[qm_at]

    at.add_property('force', cp2k_force, overwrite=True)
    at.params['energy'] = cp2k_energy
    yield at
Exemplo n.º 21
0
    def calculate(self, atoms, quantities=None):
        """
        Perform a calculation of `quantities` for `atoms` using this Potential.

        Automatically determines if a new calculation is required or if previous
        results are still appliciable (i.e. if the atoms haven't moved since last call)
        Called internally by :meth:`get_potential_energy`, :meth:`get_forces`, etc.
        """
        if quantities is None:
            quantities = ['energy', 'forces', 'stress']

        # Add any default quantities
        quantities = set(self.get_default_quantities() + quantities)

        if len(quantities) == 0:
            raise RuntimeError('Nothing to calculate')

        if not self.calculation_required(atoms, quantities):
            return

        args_map = {
            'energy': {
                'energy': None
            },
            'energies': {
                'local_energy': None
            },
            'forces': {
                'force': None
            },
            'stress': {
                'virial': None
            },
            'numeric_forces': {
                'force': 'numeric_force',
                'force_using_fd': True,
                'force_fd_delta': 1.0e-5
            },
            'stresses': {
                'local_virial': None
            },
            'elastic_constants': {},
            'unrelaxed_elastic_constants': {}
        }

        # list of quantities that require a call to Potential.calc()
        calc_quantities = [
            'energy', 'energies', 'forces', 'numeric_forces', 'stress',
            'stresses'
        ]

        # list of other quantities we know how to calculate
        other_quantities = ['elastic_constants', 'unrelaxed_elastic_constants']

        calc_args = {}
        calc_required = False
        for quantity in quantities:
            if quantity in calc_quantities:
                calc_required = True
                calc_args.update(args_map[quantity])
            elif quantity not in other_quantities:
                raise RuntimeError(
                    "Don't know how to calculate quantity '%s'" % quantity)

        if calc_required:
            self.calc(self.atoms, args_str=dict_to_args_str(calc_args))

        if 'energy' in quantities:
            self.energy = float(self.atoms.energy)
        if 'energies' in quantities:
            self.energies = self.atoms.local_energy.view(np.ndarray)
        if 'forces' in quantities:
            self.forces = self.atoms.force.view(np.ndarray).T
        if 'numeric_forces' in quantities:
            self.numeric_forces = self.atoms.numeric_force.view(np.ndarray).T
        if 'stress' in quantities:
            stress = -self.atoms.virial.view(
                np.ndarray) / self.atoms.get_volume()
            # convert to 6-element array in Voigt order
            self.stress = np.array([
                stress[0, 0], stress[1, 1], stress[2, 2], stress[1, 2],
                stress[0, 2], stress[0, 1]
            ])
        if 'stresses' in quantities:
            lv = np.array(self.atoms.local_virial)  # make a copy
            vol_per_atom = self.get('vol_per_atom',
                                    self.atoms.get_volume() / len(atoms))
            if isinstance(vol_per_atom, basestring):
                vol_per_atom = self.atoms.arrays[vol_per_atom]
            self.stresses = -lv.T.reshape(
                (len(atoms), 3, 3), order='F') / vol_per_atom

        if 'elastic_constants' in quantities:
            cij_dx = self.get('cij_dx', 1e-2)
            cij = fzeros((6, 6))
            self.calc_elastic_constants(self.atoms,
                                        fd=cij_dx,
                                        args_str=self.get_calc_args_str(),
                                        c=cij,
                                        relax_initial=False,
                                        return_relaxed=False)
            if not get_fortran_indexing():
                cij = cij.view(np.ndarray)
            self.elastic_constants = cij

        if 'unrelaxed_elastic_constants' in quantities:
            cij_dx = self.get('cij_dx', 1e-2)
            c0ij = fzeros((6, 6))
            self.calc_elastic_constants(self.atoms,
                                        fd=cij_dx,
                                        args_str=self.get_calc_args_str(),
                                        c0=c0ij,
                                        relax_initial=False,
                                        return_relaxed=False)
            if not get_fortran_indexing():
                c0ij = c0ij.view(np.ndarray)
            self.unrelaxed_elastic_constants = c0ij