Пример #1
0
def find_tip_coordination(a, bondlength=2.6, bulk_nn=4):
    """
    Find position of tip in crack cluster from coordination
    """
    nl = NeighborList([bondlength / 2.0] * len(a),
                      skin=0.0,
                      self_interaction=False,
                      bothways=True)
    nl.update(a)
    nn = np.array([len(nl.get_neighbors(i)[0]) for i in range(len(a))])
    a.set_array('n_neighb', nn)
    g = a.get_array('groups')

    y = a.positions[:, 1]
    above = (nn < bulk_nn) & (g != 0) & (y > a.cell[1, 1] / 2.0)
    below = (nn < bulk_nn) & (g != 0) & (y < a.cell[1, 1] / 2.0)

    a.set_array('above', above)
    a.set_array('below', below)

    bond1 = np.asscalar(above.nonzero()[0][a.positions[above, 0].argmax()])
    bond2 = np.asscalar(below.nonzero()[0][a.positions[below, 0].argmax()])

    # These need to be ints, otherwise they are no JSON serializable.
    a.info['bond1'] = bond1
    a.info['bond2'] = bond2

    return bond1, bond2
Пример #2
0
def find_tip_coordination(a, bondlength=2.6, bulk_nn=4):
    """
    Find position of tip in crack cluster from coordination
    """
    nl = NeighborList([bondlength/2.0]*len(a),
                      skin=0.0,
                      self_interaction=False,
                      bothways=True)
    nl.update(a)
    nn = np.array([len(nl.get_neighbors(i)[0]) for i in range(len(a))])
    a.set_array('n_neighb', nn)
    g = a.get_array('groups')

    y = a.positions[:, 1]
    above = (nn < bulk_nn) & (g != 0) & (y > a.cell[1,1]/2.0)
    below = (nn < bulk_nn) & (g != 0) & (y < a.cell[1,1]/2.0)

    a.set_array('above', above)
    a.set_array('below', below)

    bond1 = np.asscalar(above.nonzero()[0][a.positions[above, 0].argmax()])
    bond2 = np.asscalar(below.nonzero()[0][a.positions[below, 0].argmax()])

    # These need to be ints, otherwise they are no JSON serializable.
    a.info['bond1'] = bond1
    a.info['bond2'] = bond2

    return bond1, bond2
Пример #3
0
Файл: pov.py Проект: jboes/ase
def get_bondpairs(atoms, radius=1.1):
    """Get all pairs of bonding atoms

    Return all pairs of atoms which are closer than radius times the
    sum of their respective covalent radii.  The pairs are returned as
    tuples::

      (a, b, (i1, i2, i3))

    so that atoms a bonds to atom b displaced by the vector::

        _     _     _
      i c + i c + i c ,
       1 1   2 2   3 3

    where c1, c2 and c3 are the unit cell vectors and i1, i2, i3 are
    integers."""
    
    from ase.data import covalent_radii
    from ase.calculators.neighborlist import NeighborList
    cutoffs = radius * covalent_radii[atoms.numbers]
    nl = NeighborList(cutoffs=cutoffs, self_interaction=False)
    nl.update(atoms)
    bondpairs = []
    for a in range(len(atoms)):
        indices, offsets = nl.get_neighbors(a)
        bondpairs.extend([(a, a2, offset)
                          for a2, offset in zip(indices, offsets)])
    return bondpairs
def calculate_image_center(atoms, watchindex, pdirs):
    """Calculates the center of the image in the pdir basis coordinates."""

    # The first moment of the image around the center atom is calculated.
    atoms = atoms.copy()
    from ase.calculators.neighborlist import NeighborList
    _nl = NeighborList(cutoffs=([6.5 / 2.] * len(atoms)),
                       self_interaction=False,
                       bothways=True,
                       skin=0.)
    _nl.update(atoms)

    position = atoms.positions[watchindex]

    # Step 1: Calculating neighbors of atom.
    n_indices, n_offsets = _nl.get_neighbors(watchindex)
    Rs = [atoms.positions[n_index] +
          np.dot(n_offset, atoms.get_cell()) - position
          for n_index, n_offset in zip(n_indices, n_offsets)]

    xtilde = 0.
    ytilde = 0.
    ztilde = 0.
    for rs in Rs:
        xtilde += rs[0] * np.dot([1, 0, 0], pdirs[0])
        xtilde += rs[1] * np.dot([0, 1, 0], pdirs[0])
        xtilde += rs[2] * np.dot([0, 0, 1], pdirs[0])
        ytilde += rs[0] * np.dot([1, 0, 0], pdirs[1])
        ytilde += rs[1] * np.dot([0, 1, 0], pdirs[1])
        ytilde += rs[2] * np.dot([0, 0, 1], pdirs[1])
        ztilde += rs[0] * np.dot([1, 0, 0], pdirs[2])
        ztilde += rs[1] * np.dot([0, 1, 0], pdirs[2])
        ztilde += rs[2] * np.dot([0, 0, 1], pdirs[2])

    return xtilde, ytilde, ztilde
Пример #5
0
    def relax(self, individual):
        """Relaxes the individual using a hard-sphere cutoff method.
        Args:
            individual (Individual):  the individual to relax
        """
        rank = gparameters.mpi.rank
        print("Relaxing individual {} on rank {} with hard-sphere cutoff method".format(individual.id, rank))
        radii = [2.0 for atom in individual]
        nl = NeighborList(radii, bothways=True, self_interaction=False)
        nl.update(individual)

        ntries = 0
        modified = True
        while modified and ntries < 100:
            modified = False
            for atom in individual:
                indices, offsets = nl.get_neighbors(atom.index)
                for neigh in indices:
                    if individual.get_distance(atom.index, neigh) < self.cutoff:
                        individual.set_distance(atom.index, neigh, self.cutoff, fix=0.5)
                        modified = True
            nl.update(individual)
            individual.wrap()
            ntries += 1
        if ntries == 100:
            print("WARNING! Iterated through the hard-sphere cutoff relaxation 100 times and it still did not converge!")
Пример #6
0
def get_fingerprints(atoms):
    elements =['O','Ru']
    Gs = make_symmetry_functions(elements)
    fp = np.zeros([2, len(Gs['O'])])
    cutoff ={'name': 'Cosine', 'kwargs': {'Rc': 6.5}}
    cutoff_globle = 6.5
    _nl = NeighborList(cutoffs=([cutoff_globle / 2.] *
                                len(atoms)),
                       self_interaction=False,
                       bothways=True,
                       skin=0.)
    _nl.update(atoms)

    amp_obj = FingerprintCalculator(neighborlist=_nl, Gs=Gs, cutoff=cutoff,fortran=False)
    amp_obj.initialize(fortran=False,atoms=atoms)
    n=0
    fingerprint = []
    for index in range(12,14):
        symbol = atoms[index].symbol
        neighborindices, neighboroffsets = _nl.get_neighbors(index)
        neighborsymbols = [atoms[_].symbol for _ in neighborindices]
        neighborpositions = [atoms.positions[neighbor] + np.dot(offset, atoms.cell)
                             for (neighbor, offset) in zip(neighborindices,
                                                           neighboroffsets)]
        indexfp = amp_obj.get_fingerprint(
            index, symbol, neighborsymbols, neighborpositions)
        fp[n] = indexfp[1]
        n = n+1
    return fp
Пример #7
0
    def bind(self, frame):
        if not self.ui.get_widget('/MenuBar/ViewMenu/ShowBonds'
                                  ).get_active():
            self.bonds = np.empty((0, 5), int)
            return
        
        from ase.atoms import Atoms
        from ase.calculators.neighborlist import NeighborList
        nl = NeighborList(self.images.r * 1.5, skin=0, self_interaction=False)
        nl.update(Atoms(positions=self.images.P[frame],
                        cell=(self.images.repeat[:, np.newaxis] *
                              self.images.A[frame]),
                        pbc=self.images.pbc))
        nb = nl.nneighbors + nl.npbcneighbors
        self.bonds = np.empty((nb, 5), int)
        if nb == 0:
            return
        
        n1 = 0
        for a in range(self.images.natoms):
            indices, offsets = nl.get_neighbors(a)
            n2 = n1 + len(indices)
            self.bonds[n1:n2, 0] = a
            self.bonds[n1:n2, 1] = indices
            self.bonds[n1:n2, 2:] = offsets
            n1 = n2

        i = self.bonds[:n2, 2:].any(1)
        self.bonds[n2:, 0] = self.bonds[i, 1]
        self.bonds[n2:, 1] = self.bonds[i, 0]
        self.bonds[n2:, 2:] = -self.bonds[i, 2:]
Пример #8
0
    def bind(self, frame):
        if not self.ui.get_widget('/MenuBar/ViewMenu/ShowBonds').get_active():
            self.bonds = np.empty((0, 5), int)
            return

        from ase.atoms import Atoms
        from ase.calculators.neighborlist import NeighborList
        nl = NeighborList(self.images.r * 1.5, skin=0, self_interaction=False)
        nl.update(
            Atoms(positions=self.images.P[frame],
                  cell=(self.images.repeat[:, np.newaxis] *
                        self.images.A[frame]),
                  pbc=self.images.pbc))
        nb = nl.nneighbors + nl.npbcneighbors
        self.bonds = np.empty((nb, 5), int)
        if nb == 0:
            return

        n1 = 0
        for a in range(self.images.natoms):
            indices, offsets = nl.get_neighbors(a)
            n2 = n1 + len(indices)
            self.bonds[n1:n2, 0] = a
            self.bonds[n1:n2, 1] = indices
            self.bonds[n1:n2, 2:] = offsets
            n1 = n2

        i = self.bonds[:n2, 2:].any(1)
        self.bonds[n2:, 0] = self.bonds[i, 1]
        self.bonds[n2:, 1] = self.bonds[i, 0]
        self.bonds[n2:, 2:] = -self.bonds[i, 2:]
Пример #9
0
Файл: pov.py Проект: lqcata/ase
def get_bondpairs(atoms, radius=1.1):
    """Get all pairs of bonding atoms

    Return all pairs of atoms which are closer than radius times the
    sum of their respective covalent radii.  The pairs are returned as
    tuples::

      (a, b, (i1, i2, i3))

    so that atoms a bonds to atom b displaced by the vector::

        _     _     _
      i c + i c + i c ,
       1 1   2 2   3 3

    where c1, c2 and c3 are the unit cell vectors and i1, i2, i3 are
    integers."""
    
    from ase.data import covalent_radii
    from ase.calculators.neighborlist import NeighborList
    cutoffs = radius * covalent_radii[atoms.numbers]
    nl = NeighborList(cutoffs=cutoffs, self_interaction=False)
    nl.update(atoms)
    bondpairs = []
    for a in range(len(atoms)):
        indices, offsets = nl.get_neighbors(a)
        bondpairs.extend([(a, a2, offset)
                          for a2, offset in zip(indices, offsets)])
    return bondpairs
 def calculate(self, image, key):
     cutoff = self.globals.cutoff
     n = NeighborList(cutoffs=[cutoff / 2.] * len(image),
                      self_interaction=False,
                      bothways=True,
                      skin=0.)
     n.update(image)
     return [n.get_neighbors(index) for index in xrange(len(image))]
Пример #11
0
    def find_connected(self, index, dmax=None, scale=1.5):
        """Find the atoms connected to self[index] and return them.

        If dmax is not None:
        Atoms are defined to be connected if they are nearer than dmax
        to each other.

        If dmax is None:
        Atoms are defined to be connected if they are nearer than the
        sum of their covalent radii * scale to each other.

        """

        if index < 0:
            index = len(self) + index

        # set neighbor lists
        if dmax is None:
            # define neighbors according to covalent radii
            radii = scale * covalent_radii[self.get_atomic_numbers()]
        else:
            # define neighbors according to distance
            radii = [0.5 * dmax] * len(self)
        nl = NeighborList(radii, skin=0, self_interaction=False, bothways=True)
        nl.update(self)

        connected = [index] + list(nl.get_neighbors(index)[0])
        isolated = False
        while not isolated:
            isolated = True
            for i in connected:
                for j in nl.get_neighbors(i)[0]:
                    if j in connected:
                        pass
                    else:
                        connected.append(j)
                        isolated = False

        atoms = Cluster()
        for i in connected:
            atoms.append(self[i])

        return atoms
Пример #12
0
def vacancy_energy(bulk, remove_index=0):
    Nat = bulk.get_number_of_atoms()
    vac = bulk.copy()
    vac.set_calculator(bulk.get_calculator())

    nl = NeighborList([a0*sqrt(3.0)/4*0.6]*len(bulk), self_interaction=False, bothways=True)
    nl.update(bulk)
    indices, offsets = nl.get_neighbors(remove_index)
    offset_factor=0.13
    for i, offset in zip(indices, offsets):
       ri = vac.positions[remove_index] - (vac.positions[i] + dot(offset, vac.get_cell()))
       vac.positions[i] += offset_factor*ri
       offset_factor += 0.01

    del vac[remove_index] # remove an atom to introduce a vacancy

    # perturb positions
    vac.rattle(0.1)

    ##
    try:
        model.calculator.set(local_gap_error='local_gap_error')
        vac.get_potential_energy()
        unrelaxed_local_gap_error_max = amax(model.calculator.results['local_gap_error'])
        unrelaxed_local_gap_error_sum = sum(model.calculator.results['local_gap_error'])
    except:
        unrelaxed_local_gap_error_max = None
        unrelaxed_local_gap_error_sum = None
    if isinstance(model, Potential):
        model.calculator.set(local_gap_error='')

    # relax atom positions, holding cell fixed
    vac = relax_atoms(vac, tol=fmax, traj_file="model-"+model.name+"-test-vacancy-energy.opt.xyz")

    vac.write("model-"+model.name+"test-vacancy-energy-relaxed.xyz")

    ##
    try:
        model.calculator.set(local_gap_error='local_gap_error')
        vac.get_potential_energy()
        relaxed_local_gap_error_max = amax(model.calculator.results['local_gap_error'])
        relaxed_local_gap_error_sum = sum(model.calculator.results['local_gap_error'])
    except:
        relaxed_local_gap_error_max = None
        relaxed_local_gap_error_sum = None
    if isinstance(model, Potential):
        model.calculator.set(local_gap_error='')
    ##

    # compute vacancy formation energy as difference of bulk and vac energies
    print 'bulk cell energy', bulk_energy
    print 'vacancy cell energy', vac.get_potential_energy()
    e_form = vac.get_potential_energy() - bulk_energy*vac.get_number_of_atoms()/bulk.get_number_of_atoms()
    print 'vacancy formation energy', e_form
    return (e_form, unrelaxed_local_gap_error_max, unrelaxed_local_gap_error_sum, relaxed_local_gap_error_max, relaxed_local_gap_error_sum)
Пример #13
0
    def find_connected(self, index, dmax=None, scale=1.5):
        """Find the atoms connected to self[index] and return them.

        If dmax is not None:
        Atoms are defined to be connected if they are nearer than dmax
        to each other.

        If dmax is None:
        Atoms are defined to be connected if they are nearer than the
        sum of their covalent radii * scale to each other.

        """

        # set neighbor lists
        neighborlist = []
        if dmax is None:
            # define neighbors according to covalent radii
            radii = scale * covalent_radii[self.get_atomic_numbers()]
            for atom in self:
                positions = self.positions - atom.position
                distances = np.sqrt(np.sum(positions**2, axis=1))
                radius = scale * covalent_radii[atom.get_atomic_number()]
                neighborlist.append(np.where(distances < radii + radius)[0])
        else:
            # define neighbors according to distance
            nl = NeighborList([0.5 * dmax] * len(self), skin=0)
            nl.update(self)
            for i, atom in enumerate(self):
                neighborlist.append(list(nl.get_neighbors(i)[0]))

        connected = list(neighborlist[index])
        isolated = False
        while not isolated:
            isolated = True
            for i in connected:
                for j in neighborlist[i]:
                    if j in connected:
                        pass
                    else:
                        connected.append(j)
                        isolated = False 
 
        atoms = Cluster()
        for i in connected:
            atoms.append(self[i])

        return atoms
Пример #14
0
 def testNeighborlist(self):
     atoms = read('range', format='lammps')
     atoms.set_pbc((1, 1, 1))
     nl = NeighborList([0.8 for atom in atoms],
                       self_interaction=False,
                       bothways=True)
     nl.update(atoms)
     ang = []
     for i in xrange(3):
         indices, offsets = nl.get_neighbors(i)
         angs = []
         for j, offset in zip(indices, offsets):
             pos = atoms.positions[j] + dot(
                 offset, atoms.get_cell()) - atoms.positions[i]
             ang1 = atan2(pos[1], pos[0]) + pi
             angs.append((j, ang1))
         newangs = sorted(angs, key=lambda d: d[1])
         print newangs
Пример #15
0
def check_min_dist(totalsol, type='Defect', nat=None, min_len=0.7, STR=''):
    if type == 'Defect' or type == 'Crystal' or type == 'Surface':
        if nat == None:
            nat = len(totalsol)
        cutoffs = [2.0 for one in totalsol]
        nl = NeighborList(cutoffs, bothways=True, self_interaction=False)
        nl.update(totalsol)
        for one in totalsol[0:nat]:
            nbatoms = Atoms()
            nbatoms.append(one)
            indices, offsets = nl.get_neighbors(one.index)
            for index, d in zip(indices, offsets):
                index = int(index)
                sym = totalsol[index].symbol
                pos = totalsol[index].position + numpy.dot(
                    d, totalsol.get_cell())
                at = Atom(symbol=sym, position=pos)
                nbatoms.append(at)
            while True:
                dflag = False
                for i in range(1, len(nbatoms)):
                    d = nbatoms.get_distance(0, i)
                    if d < min_len:
                        nbatoms.set_distance(0, i, min_len + .01, fix=0.5)
                        STR += '--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                        dflag = True
                if dflag == False:
                    break
            for i in range(len(indices)):
                totalsol[indices[i]].position = nbatoms[i + 1].position
            totalsol[one.index].position = nbatoms[0].position
            nl.update(totalsol)
    elif type == 'Cluster':
        for i in range(len(totalsol)):
            for j in range(len(totalsol)):
                if i != j:
                    d = totalsol.get_distance(i, j)
                    if d < min_len:
                        totalsol.set_distance(i, j, min_len, fix=0.5)
                        STR += '--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
    else:
        print 'WARNING: In Check_Min_Dist in EvalEnergy: Structure Type not recognized'
    return totalsol, STR
Пример #16
0
def check_min_dist(totalsol, type='Defect', nat=None, min_len=0.7, STR=''):
    if type=='Defect' or type=='Crystal' or type=='Surface':
        if nat==None:
            nat=len(totalsol)
        cutoffs=[2.0 for one in totalsol]
        nl=NeighborList(cutoffs,bothways=True,self_interaction=False)
        nl.update(totalsol)
        for one in totalsol[0:nat]:
            nbatoms=Atoms()
            nbatoms.append(one)
            indices, offsets=nl.get_neighbors(one.index)
            for index, d in zip(indices,offsets):
                index = int(index)
                sym=totalsol[index].symbol
                pos=totalsol[index].position + numpy.dot(d,totalsol.get_cell())
                at=Atom(symbol=sym,position=pos)
                nbatoms.append(at)
            while True:
                dflag=False
                for i in range(1,len(nbatoms)):
                    d=nbatoms.get_distance(0,i)
                    if d < min_len:
                        nbatoms.set_distance(0,i,min_len+.01,fix=0.5)
                        STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                        dflag=True
                if dflag==False:
                    break
            for i in range(len(indices)):
                totalsol[indices[i]].position=nbatoms[i+1].position
            totalsol[one.index].position=nbatoms[0].position
            nl.update(totalsol)
    elif type=='Cluster':
        for i in range(len(totalsol)):
            for j in range(len(totalsol)):
                if i != j:
                    d=totalsol.get_distance(i,j)
                    if d < min_len:
                        totalsol.set_distance(i,j,min_len,fix=0.5)
                        STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
    else:
        print 'WARNING: In Check_Min_Dist in EvalEnergy: Structure Type not recognized'
    return totalsol, STR
Пример #17
0
class NeighborPairs:
    """Class for looping over pairs of atoms using a neighbor list."""
    def __init__(self, cutoff_a, cell_cv, pbc_c, self_interaction):
        self.neighbors = NeighborList(cutoff_a, skin=0, sorted=True, 
                                      self_interaction=self_interaction)
        self.atoms = Atoms('X%d' % len(cutoff_a), cell=cell_cv, pbc=pbc_c)
        # Warning: never use self.atoms.get_scaled_positions() for
        # anything.  Those positions suffer from roundoff errors!
        
    def set_positions(self, spos_ac):
        self.spos_ac = spos_ac
        self.atoms.set_scaled_positions(spos_ac)
        self.neighbors.update(self.atoms)

    def iter(self):
        cell_cv = self.atoms.cell
        for a1, spos1_c in enumerate(self.spos_ac):
            a2_a, offsets = self.neighbors.get_neighbors(a1)
            for a2, offset in zip(a2_a, offsets):
                spos2_c = self.spos_ac[a2] + offset
                R_c = np.dot(spos2_c - spos1_c, cell_cv)
                yield a1, a2, R_c, offset
Пример #18
0
class NeighborPairs:
    """Class for looping over pairs of atoms using a neighbor list."""
    def __init__(self, cutoff_a, cell_cv, pbc_c, self_interaction):
        self.neighbors = NeighborList(cutoff_a,
                                      skin=0,
                                      sorted=True,
                                      self_interaction=self_interaction)
        self.atoms = Atoms('X%d' % len(cutoff_a), cell=cell_cv, pbc=pbc_c)
        # Warning: never use self.atoms.get_scaled_positions() for
        # anything.  Those positions suffer from roundoff errors!

    def set_positions(self, spos_ac):
        self.spos_ac = spos_ac
        self.atoms.set_scaled_positions(spos_ac)
        self.neighbors.update(self.atoms)

    def iter(self):
        cell_cv = self.atoms.cell
        for a1, spos1_c in enumerate(self.spos_ac):
            a2_a, offsets = self.neighbors.get_neighbors(a1)
            for a2, offset in zip(a2_a, offsets):
                spos2_c = self.spos_ac[a2] + offset
                R_c = np.dot(spos2_c - spos1_c, cell_cv)
                yield a1, a2, R_c, offset
Пример #19
0
        (b.positions[:,0] < 2*a.cell[0,0]) &
        (b.positions[:,1] < (a.cell[1,1]/2.0 + final_height/2.0)) &
        (b.positions[:,1] > (a.cell[1,1]/2.0 - final_height/2.0)))

nl = NeighborList([1.0]*len(b),
                 self_interaction=False,
                 bothways=True)
nl.update(b)

term = Atoms()

if tetra:
    for i in range(len(b)):
        if not mask[i]:
            continue
        indices, offsets = nl.get_neighbors(i)
        if b.numbers[i] == 8 and mask[indices].sum() == 0:
            mask[i] = False
        if b.numbers[i] == 14:
            # complete tetrahedra
            for (j, o) in zip(indices, offsets):        
                if b.numbers[j] == 8:
                    mask[j] = True

if terminate:
    for i in range(len(b)):
        if not mask[i]:
            continue    
        indices, offsets = nl.get_neighbors(i)    
        for (j, o) in zip(indices, offsets):
            if mask[j]:
Пример #20
0
def create_stucture(ratio, width, edge, key = 'top', a = 1.42):
    
    vacuum  =   10
    length  =   get_length(ratio, width, edge)
    length_b=   int(length * .8)*2
    width_b =   width * 4
    
    if edge == 'zz':    
        orig    =   [np.sqrt(3)*a, 2*a] # -> AB-stacking
        b_l, b_w=   4, 3*width
        if width % 2 == 1: raise
    if edge == 'ac':    
        orig    =   [2*a, np.sqrt(3)*a] # -> AB-stacking
        b_l, b_w=   2, 3*width 
        if width % 2 == 0: raise        
    
    bottom  =   graphene_nanoribbon2(length_b, width_b, edge_type=edge, 
                                    saturated=False, 
                                    C_H=1.09,
                                    C_C=a, 
                                    vacuum=2.5, 
                                    sheet=False, 
                                    main_element='C', 
                                    saturate_element='H')
    
    top     =   graphene_nanoribbon2(length, width, edge_type=edge, 
                                    saturated=True, 
                                    C_H=1.09,
                                    C_C=a, 
                                    vacuum=2.5, 
                                    sheet=False, 
                                    main_element='C', 
                                    saturate_element='H')
    
    base    =   graphene_nanoribbon2(b_l, b_w, edge_type=edge, 
                                    saturated=True, 
                                    C_H=1.09,
                                    C_C=a, 
                                    vacuum=2.5, 
                                    sheet=False, 
                                    main_element='C', 
                                    saturate_element='H')
    
    if key == 'top_bottom':
        top.translate([orig[0],orig[1],3.4])
        atoms       =   bottom 
        atoms.extend(top)
        atoms.cell  =   [bottom.cell[0,0], bottom.cell[1,1], 2 * vacuum + 3.4]
        atoms.center()
        atoms.pbc   =   [True, True, False]
        
        #view(atoms)
        return atoms

    if key == 'top':
        atoms       =   top
        L, W        =   top.cell[0,0], top.cell[1,1] 
        atoms.cell  =   [top.cell[0,0]*1.5, 2*top.cell[0,0] + top.cell[1,1], 2 * vacuum]
        atoms.center()
        atoms.positions[:,2] = 3.4
        atoms.pbc   =   [False, False, False]
        return atoms, L, W, length, None
    
    if key == 'rib+base':

        if edge == 'zz':    base.translate([-base.cell[0,0], -base.cell[1,1]/3 ,0])
        if edge == 'ac':    base.translate([-base.cell[0,0], -base.cell[1,1]/3 + np.sqrt(3) / 2. * a,0])

        atoms       =   top + base
        
        rads    =   np.ones(len(atoms))*.3
        nl = NeighborList(rads, self_interaction=False,
                 bothways=True)
        nl.update(atoms)
        
        coll        =   []
        for i, atom in enumerate(atoms):
            if atom.number == 1:
                if 1 < len(nl.get_neighbors(i)[0]):
                    for j in nl.get_neighbors(i)[0]:
                        if atoms.numbers[j] == 1:
                            coll.append(j)
        del atoms[coll]

        atoms_base  =   []
        for i, atom in enumerate(atoms):
            if atom.position[0] < 0:
                atoms_base.append(i)
                
        rads    =   np.ones(len(atoms))*.7
        nl = NeighborList(rads, self_interaction=False,
                 bothways=True)
        nl.update(atoms)

        
        new_pos =   []
        for i, atom in enumerate(atoms):
            if len(nl.get_neighbors(i)[0]) == 2 and atom.number == 6 and i not in atoms_base:
                pos =   np.zeros(3)
                for j in nl.get_neighbors(i)[0]:
                    pos +=  atoms.positions[j] - atoms.positions[i] 
                    if atoms.numbers[j] != 6: raise
                new_pos.append(atoms.positions[i] - pos)
        
        for pos in new_pos:
            atoms   +=  Atom('C', position = pos)
        
        rads    =   np.ones(len(atoms))*.7
        nl = NeighborList(rads, self_interaction=False,
                 bothways=True)
        nl.update(atoms)
        
        h_pos =   []
        for i, atom in enumerate(atoms):
            if len(nl.get_neighbors(i)[0]) == 2 and atom.number == 6:
                pos =   np.zeros(3)
                for j in nl.get_neighbors(i)[0]:
                    pos +=  atoms.positions[j] - atoms.positions[i] 
                    if atoms.numbers[j] != 6: raise
                pos =   pos/np.linalg.norm(pos)
                
                h_pos.append(atoms.positions[i] - pos)
        
        for pos in h_pos:
            atoms   +=  Atom('H', position = pos)
        
        
        
        L, W        =   top.cell[0,0], top.cell[1,1] 
        
        
        
        atoms.cell  =   [top.cell[0,0]*1.5, 2*top.cell[0,0] + top.cell[1,1], 2 * vacuum]
        atoms.center()
        atoms.positions[:,2] = 3.4
        atoms.pbc   =   [False, False, False]
        return atoms, L, W, length, atoms_base
Пример #21
0
def check_min_dist(Optimizer, totalsol, type='Defect', nat=None, min_len=0.7, STR=''):
        if type=='Defect' or type=='Crystal' or type=='Surface':
            if nat==None:
                nat=len(totalsol)
            cutoffs=[2.0 for one in totalsol]
            nl=NeighborList(cutoffs,bothways=True,self_interaction=False)
            nl.update(totalsol)
            for one in totalsol[0:nat]:
                nbatoms=Atoms()
                nbatoms.append(one)
                indices, offsets=nl.get_neighbors(one.index)
                for index, d in zip(indices,offsets):
                    index = int(index)
                    sym=totalsol[index].symbol
                    pos=totalsol[index].position + numpy.dot(d,totalsol.get_cell())
                    at=Atom(symbol=sym,position=pos)
                    nbatoms.append(at)
                while True:
                    dflag=False
                    for i in range(1,len(nbatoms)):
                        d=nbatoms.get_distance(0,i)
                        if d < min_len:
                            nbatoms.set_distance(0,i,min_len+.01,fix=0.5)
                            STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                            dflag=True
                    if dflag==False:
                        break
                for i in range(len(indices)):
                    totalsol[indices[i]].position=nbatoms[i+1].position
                totalsol[one.index].position=nbatoms[0].position
                nl.update(totalsol)
        elif type=='Cluster':
            if not 'LAMMPS' in Optimizer.modules:
                for i in range(len(totalsol)):
                    for j in range(len(totalsol)):
                        if i != j:
                            d=totalsol.get_distance(i,j)
                            if d < min_len:
                                totalsol.set_distance(i,j,min_len,fix=0.5)
                                STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
            else:
                rank = MPI.COMM_WORLD.Get_rank()
                #logger = logging.getLogger(Optimizer.loggername)
                R = totalsol.arrays['positions']
                tol = 0.01
                epsilon = 0.05
                fix = 0.5
                
                closelist = numpy.arange(len(totalsol))
                iter = 0
                while len(closelist) > 0 and iter<2:
                    iter+=1
                    closelist = []
                    dist=spatial.distance.cdist(R,R)
                    numpy.fill_diagonal(dist,1.0)
                    smalldist = numpy.where(dist < min_len-tol)
   
                    for ind in range(len(smalldist[0])):
                        i = smalldist[0][ind]
                        j = smalldist[1][ind]
                        if i < j and dist[i][j] < min_len-tol:
                            closelist.append(i)
                            closelist.append(j)
                            if dist[i][j] > epsilon:
                                x = 1.0 - min_len / dist[i][j]
                                D = R[j]-R[i]
                                R[i] += (x * fix) * D
                                R[j] -= (x * (1.0 - fix)) * D
                            else:
                                R[i] += [0.2, 0.0, 0.0]
                                R[j] -= [0.2, 0.0, 0.0]
                            R2P = [R[i],R[j]]
                            dist2P=spatial.distance.cdist(R2P,R)
                            dist[i] = dist2P[0]
                            dist[j] = dist2P[1]
                            for k in range(len(R)):
                                dist[k][i] = dist[i][k]
                                dist[k][j] = dist[j][k]
                    closelist=list(set(closelist))
                    closelist.sort()
                    #if len(closelist) != 0:
                    #    logger.info('M:iter {0}, closelist size {1}'.format(iter,len(closelist)))
        else:
            print 'WARNING: In Check_Min_Dist in EvalEnergy: Structure Type not recognized'
        return totalsol, STR
Пример #22
0
def biatomic(atoms, A, B, R1=3.0, calc_energy=False):
    r"""This routine analyzes atomic structure
    by the calculation of coordination numbers
    in cluster with atoms of two types (A and B).

    Parameters
    ----------
    atoms: ase.Atoms
        ase Atoms object, containing atomic cluster.
    A: string
        atom type, like 'Ag', 'Pt', etc.
    B: string
        atom type, like 'Ag', 'Pt', etc.
    R1: float
        First coordination shell will icnlude all atoms
        with distance less then R1 [Angstrom].
        Default value is 3.
    calc_energy: bool
        Flag used for calculation of potential energy with EMT
        calculator.  The default value is False, so that
        energy is not calculated.

    Returns
    -------
    N: int
        number of atoms in cluster
    nA:
        number of atoms of type A
    R: float
        radius of the cluster
    CN_AA: float
        average number of atoms A around atom A
    CN_AB: float
        average number of atoms A around atom B
    CN_BB: float
        average number of atoms B around atom B
    CN_BA: float
        average number of atoms B around atom A
    etha: float
        parameter of local ordering, -1 < etha < 1.
        Returns 999 if concentration of one of the
        component is too low.
    E: float
        potential energy
    NAcore:
        number of A atoms in core
    NBcore:
        number of B atoms in core
    CNshellAA:
        average CN of A-A for surface atoms only
    CNshellAB:
        average CN of A-B for surface atoms only
    CNshellBB:
        average CN of B-B for surface atoms only
    CNshellBA:
        average CN of B-A for surface atoms only

    Notes
    -----
        The radius of the cluster is roughly determined as
        maximum the distance from the center to most distant atom
        in the cluster.

    Example
    --------
    >>> atoms = FaceCenteredCubic('Ag',
      [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [7,8,7], 4.09)
    >>> atoms = CoreShellFCC(atoms, 'Pt', 'Ag', 0.6, 4.09)
    >>> [N, nA, R, CN_AA, CN_AB, CN_BB, CN_BA, etha] =
      biatomic(atoms, 'Pt', 'Ag')
    >>> print "Short range order parameter: ", etha
    """
    N = len(atoms)
    nA = 0
    nB = 0
    for element in atoms.get_chemical_symbols():
        if element == A:
            nA += 1
        elif element == B:
            nB += 1
        else:
            raise Exception('Extra element ' + element)
    if (nA + nB != N):
        raise Exception('Number of A (' + str(nA) + ') ' +
          'and B (' + str(nB) + ') artoms mismatch!')
    nl = NeighborList([R1 / 2.0] * N, self_interaction=False, bothways=True)
    nl.build(atoms)

    # initialize counters:
    CN_AA = 0    # averaged total coord. numbers
    CN_AB = 0
    CN_BB = 0
    CN_BA = 0
    NAcore = 0  # number of atoms in core region
    NBcore = 0
    CNshellAA = 0  # average coord. numbers for surface atoms
    CNshellAB = 0
    CNshellBB = 0
    CNshellBA = 0
    for iatom in xrange(0, N):
        indeces, offsets = nl.get_neighbors(iatom)
        if atoms[iatom].symbol == B:
            CN_BB_temp = 0
            CN_BA_temp = 0
            for ii in indeces:
                if atoms[ii].symbol == B:
                    CN_BB_temp += 1
                else:  # atoms[i].symbol == A :
                    CN_BA_temp += 1
            CN_BB += CN_BB_temp
            CN_BA += CN_BA_temp
            if len(indeces) < 12:
                # SHELL
                CNshellBB += CN_BB_temp
                CNshellBA += CN_BA_temp
            else:
                # CORE
                NBcore += 1
        else:  # atoms[iatom].symbol == A :
            CN_AA_temp = 0
            CN_AB_temp = 0
            for i in indeces:
                if atoms[i].symbol == A:
                    CN_AA_temp += 1
                else:  # atoms[i].symbol==B :
                    CN_AB_temp += 1
            CN_AA += CN_AA_temp
            CN_AB += CN_AB_temp
            if len(indeces) < 12:
                # SHELL
                CNshellAA += CN_AA_temp
                CNshellAB += CN_AB_temp
            else:
                # CORE
                NAcore += 1
    # averaging:
    CN_AA = CN_AA * 1.0 / nA
    CN_AB = CN_AB * 1.0 / nA
    CN_BB = CN_BB * 1.0 / nB
    CN_BA = CN_BA * 1.0 / nB
    znam = (nA - NAcore)
    if znam > 0.0001:
        CNshellAA = CNshellAA * 1.0 / znam
        CNshellAB = CNshellAB * 1.0 / znam
    else:
        CNshellAA = 0
        CNshellAB = 0
    znam = (nB - NBcore)
    if znam > 0.0001:
        CNshellBB = CNshellBB * 1.0 / znam
        CNshellBA = CNshellBA * 1.0 / znam
    else:
        CNshellBB = 0
        CNshellBA = 0

    # calc concentrations:
    concB = nB * 1.0 / N
    if concB < 0.0001:
        #print "WARNING! Too low B concentration: ",concB
        etha = 999
    else:
        etha = 1 - CN_AB / (concB * (CN_AA + CN_AB))
    R = atoms.positions.max() / 2.0
    if calc_energy:
        #from asap3 import EMT
        from ase.calculators.emt import EMT
        atoms.set_calculator(EMT())
        E = atoms.get_potential_energy()
    else:
        E = -1
    return N, nA, R, CN_AA, CN_AB, CN_BB, CN_BA, etha, E, NAcore, \
      NBcore, CNshellAA, CNshellAB, CNshellBB, CNshellBA
Пример #23
0
def find_defects(solid, bulko, rcutoff, atomlistcheck = False, trackvacs = False, trackswaps = False, debug = False, dcheck = 0.6):
    """Function to find interstitials, vacancies, and substitutional atoms (swaps) in a defected structure.
    Identifies species by comparison to perfect structure.
    Inputs:
        solid = ASE atoms class for defected structure
        bulko = ASE atoms class for perfect structure
        rcutoff = float value of distance to surrounding atoms to include
        atomlistcheck = False/list of atom types and concentrations according to atomlist format
        trackvacs = True/False whether or not to identify vacancies in defect
        trackswaps = True/False whether or not to identify substitutional defects
        debug = False/file object to write debug structures"""

    # Combine perfect and defect structures together
    b = bulko.copy()
    b.extend(solid)
    b.set_pbc(True)

    # Debug: Write solid and bulko to file
    if debug:
        print len(bulko)
        write_xyz(debug, b, 'Find Ints: Solid and Bulko')

    # Identify nearest neighbor atoms for each atom in perfect structure
    ntot = len(bulko)
    ctoff1 = [1.2 for one in b]
    nl = NeighborList(ctoff1, bothways = True, self_interaction = False)
    nl.update(b)
    slist = []
    blist = []
    wlist = []

    # Loop over each atom in perfect structure
    for one in range(ntot):
        indices, offsets = nl.get_neighbors(one)
        for index, d in zip(indices, offsets):
            index = int(index)
            if index >= ntot:
                pos = b[index].position + numpy.dot(d, bulko.get_cell())
                natm1 = Atom(position = pos)
                dist, dx, dy, dz = calc_dist(b[one], natm1)
                if dist <= dcheck:
                    # Assume atoms closer than 0.6 Angstroms to be equivalent
                    slist.append(index-ntot)
                    blist.append(one)
                    if b[one].symbol == b[index].symbol:
                        wlist.append(index-ntot)

    # Identify those atoms corresponding to interstitials, vacancies, and substitutions
    oslist = [atm.index for atm in solid if atm.index not in slist]
    vlist = [atm.index for atm in bulko if atm.index not in blist]
    swlist = [atm.index for atm in solid if atm.index not in wlist and atm.index not in oslist]

    # Create Atoms objects for each identified defect
    ntot = len(solid)
    cluster = Atoms()
    for one in oslist:
        cluster.append(solid[one])
    vacant = Atoms()
    if trackvacs == True:
        for one in vlist:
            vacant.append(Atom(symbol = bulko[one].symbol, position = bulko[one].position))
            solid.append(Atom(symbol = 'X', position = bulko[one].position))
            oslist.append(len(solid)-1)
        stro = 'Cluster Identified with length = {0}\nIdentified {1} vacancies\n'.format(len(cluster), len(vlist))
    swaps = Atoms()
    if trackswaps == True:
        for one in swlist:
            swaps.append(solid[one])
            oslist.append(one)
        stro = 'Cluster Identified with length = {0}\nIdentified {1} swaps\n'.format(len(cluster), len(swlist))
    else:
        stro = 'Cluster Identified with length = {0}\n'.format(len(cluster))

    # Debug: write cluster to file
    if debug:
        b = cluster.copy()
        write_xyz(debug, b, 'Find Ints: Cluster')
        debug.flush()
        print('Found cluster size = ', len(b))

    # Identify atoms surrounding the identified defects in the defected structure
    box = Atoms()
    bulki = Atoms()
    if rcutoff != 0:
        if rcutoff > 2.0:
            cutoffs = [rcutoff for one in solid]
        else:
            cutoffs = [2.0 for one in solid]
        solid.set_pbc(True)
        nl = NeighborList(cutoffs, bothways = True, self_interaction = False)
        nl.update(solid)
        nbatmsd = []
        repinds = []
        for one in oslist:
            if one not in repinds:
                if one < ntot:
                    nbatmsd.append((0, one))
                    repinds.append(one)
        for one in oslist:
            indices, offsets = nl.get_neighbors(one)
            for index, d in zip(indices, offsets):
                index = int(index)
                if index not in repinds and index < ntot:
                    opos = copy.copy(solid[index].position)
                    solid[index].position = solid[index].position + numpy.dot(d, solid.get_cell())
                    dist = solid.get_distance(one, index)
                    solid[index].position = opos
                    if dist <= rcutoff:
                        nbatmsd.append((dist, index))
                        repinds.append(index)
    else:
        nbatmsd = []
        repinds = []
        for one in oslist:
            if one not in repinds:
                if one < ntot:
                    nbatmsd.append((0, one))
                    repinds.append(one)
    nbatmsd = sorted(nbatmsd, key = lambda one:one[0], reverse = True)
    indices = []
    natomsbox = 0

    # Select only atoms closest to defects that satisfy concentrations specified by atomlist given in atomlistcheck
    if atomlistcheck:
        for sym, c, m, u in atomlistcheck:
            i = 0
            nbsym = [one for one in nbatmsd if solid[one[1]].symbol == sym]
            if len(nbsym) > c:
                while i < c:
                    a = nbsym.pop()
                    box.append(solid[a[1]])
                    indices.append(a[1])
                    i += 1
            else:
                for a in nbsym:
                    box.append(solid[a[1]])
                    indices.append(a[1])
                    i += 1
                if len(box)-natomsbox < c:
                    try:
                        while True:
                            for n in range(len(nbatmsd)-1, -1, -1):
                                inds, offsets = nl.get_neighbors(nbatmsd[n][1])
                                for one, d in zip(inds, offsets):
                                    if len(box)-natomsbox < c:
                                        if one not in indices and one < ntot and solid[one].symbol == sym:
                                            opos = copy.copy(solid[one].position)
                                            solid[one].position = solid[one].position + numpy.dot(d, solid.get_cell())
                                            dist = solid.get_distance(nbatmsd[n][1], one)
                                            solid[one].position = opos
                                            if dist <= rcutoff*5.0:
                                                box.append(solid[one])
                                                indices.append(one)
                                    else:
                                        raise StopIteration()
                                for one, d in zip(inds, offsets):
                                    if len(box)-natomsbox < c:
                                        if one not in indices and one < ntot and solid[one].symbol == sym:
                                            opos = copy.copy(solid[one].position)
                                            solid[one].position = solid[one].position + numpy.dot(d, solid.get_cell())
                                            dist = solid.get_distance(nbatmsd[n][1], one)
                                            solid[one].position = opos
                                            box.append(solid[one])
                                            indices.append(one)
                                    else:
                                        raise StopIteration()
                    except StopIteration:
                        pass
            natomsbox = len(box)
        # Double check for sanity
        for sym, c, m, u in atomlistcheck:
            symsbox = [one for one in box if one.symbol == sym]
            if len(symsbox) != c:
                stro += 'WARNING!!!! : FAILURE IN FIND_DEFECTS TO MATCH PROVIDED ATOMLIST. DEBUG!!!!\n'

    # If atomlistcheck is False then use all the atoms in the given cutoff distance
    else:
        for a in nbatmsd:
            box.append(solid[a[1]])
            indices.append(a[1])

    # Add remaining atoms in defect to defected bulk atoms object
    for one in range(len(solid)):
        if one not in indices and one < ntot:
            bulki.append(solid[one])

    # Check for accidental vacancy admissions
    #checklist = [atm for atm in box if atm.symbol == 'X']
    #checklist.extend([atm for atm in bulki if atm.symbol == 'X'])

    # Set up new individual
    indiv = box.copy()
    bulki.set_cell(bulko.get_cell())
    indiv.set_cell(bulko.get_cell())
    bulki.set_pbc(True)
    indiv.set_pbc(True)
    stro += 'Atomlist check = {0}\n'.format(atomlistcheck)
    stro += 'Bulko = {0}\n'.format(bulko)
    stro += 'New individual ({0} atoms) : {1}\n'.format(len(indiv), indiv)
    stro += 'New bulki ({0} atoms) : {1}\n'.format(len(bulki), bulki)

    # Debug: write new indiv to file
    if debug:
        b = indiv.copy()
        write_xyz(debug, b, 'Find Ints: New Individual')
        # Debug: write new bulki to file
        b = bulki.copy()
        write_xyz(debug, b, 'Find Ints: New Bulki')
        debug.flush()
        print(len(bulko))

    return indiv, bulki, vacant, swaps, stro
Пример #24
0
Файл: emt.py Проект: grhawk/ASE
class EMT(Calculator):
    implemented_properties = ['energy', 'forces']

    nolabel = True

    def __init__(self):
        Calculator.__init__(self)

    def initialize(self, atoms):
        self.par = {}
        self.rc = 0.0
        self.numbers = atoms.get_atomic_numbers()
        maxseq = max(par[1] for par in parameters.values()) * Bohr
        rc = self.rc = beta * maxseq * 0.5 * (sqrt(3) + sqrt(4))
        rr = rc * 2 * sqrt(4) / (sqrt(3) + sqrt(4))
        self.acut = np.log(9999.0) / (rr - rc)
        for Z in self.numbers:
            if Z not in self.par:
                p = parameters[chemical_symbols[Z]]
                s0 = p[1] * Bohr
                eta2 = p[3] / Bohr
                kappa = p[4] / Bohr
                x = eta2 * beta * s0
                gamma1 = 0.0
                gamma2 = 0.0
                for i, n in enumerate([12, 6, 24]):
                    r = s0 * beta * sqrt(i + 1)
                    x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
                    gamma1 += x * exp(-eta2 * (r - beta * s0))
                    gamma2 += x * exp(-kappa / beta * (r - beta * s0))

                self.par[Z] = {
                    'E0': p[0],
                    's0': s0,
                    'V0': p[2],
                    'eta2': eta2,
                    'kappa': kappa,
                    'lambda': p[5] / Bohr,
                    'n0': p[6] / Bohr**3,
                    'rc': rc,
                    'gamma1': gamma1,
                    'gamma2': gamma2
                }
                #if rc + 0.5 > self.rc:
                #    self.rc = rc + 0.5

        self.ksi = {}
        for s1, p1 in self.par.items():
            self.ksi[s1] = {}
            for s2, p2 in self.par.items():
                #self.ksi[s1][s2] = (p2['n0'] / p1['n0'] *
                #                    exp(eta1 * (p1['s0'] - p2['s0'])))
                self.ksi[s1][s2] = p2['n0'] / p1['n0']

        self.forces = np.empty((len(atoms), 3))
        self.sigma1 = np.empty(len(atoms))
        self.deds = np.empty(len(atoms))

        self.nl = NeighborList([0.5 * self.rc + 0.25] * len(atoms),
                               self_interaction=False)

    def calculate(self,
                  atoms=None,
                  properties=['energy'],
                  system_changes=[
                      'positions', 'numbers', 'cell', 'pbc', 'charges',
                      'magmoms'
                  ]):
        Calculator.calculate(self, atoms, properties, system_changes)

        if 'numbers' in system_changes:
            self.initialize(self.atoms)

        positions = self.atoms.positions
        numbers = self.atoms.numbers
        cell = self.atoms.cell

        self.nl.update(self.atoms)

        self.energy = 0.0
        self.sigma1[:] = 0.0
        self.forces[:] = 0.0

        natoms = len(self.atoms)

        for a1 in range(natoms):
            Z1 = numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, cell)
            for a2, offset in zip(neighbors, offsets):
                d = positions[a2] + offset - positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = numbers[a2]
                    p2 = self.par[Z2]
                    self.interact1(a1, a2, d, r, p1, p2, ksi[Z2])

        for a in range(natoms):
            Z = numbers[a]
            p = self.par[Z]
            try:
                ds = -log(self.sigma1[a] / 12) / (beta * p['eta2'])
            except (OverflowError, ValueError):
                self.deds[a] = 0.0
                self.energy -= p['E0']
                continue
            x = p['lambda'] * ds
            y = exp(-x)
            z = 6 * p['V0'] * exp(-p['kappa'] * ds)
            self.deds[a] = ((x * y * p['E0'] * p['lambda'] + p['kappa'] * z) /
                            (self.sigma1[a] * beta * p['eta2']))
            self.energy += p['E0'] * ((1 + x) * y - 1) + z

        for a1 in range(natoms):
            Z1 = numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, cell)
            for a2, offset in zip(neighbors, offsets):
                d = positions[a2] + offset - positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = numbers[a2]
                    p2 = self.par[Z2]
                    self.interact2(a1, a2, d, r, p1, p2, ksi[Z2])

        self.results['energy'] = self.energy
        self.results['forces'] = self.forces

    def interact1(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (0.5 * p1['V0'] * exp(-p2['kappa'] * (r / beta - p2['s0'])) *
              ksi / p1['gamma2'] * theta)
        y2 = (0.5 * p2['V0'] * exp(-p1['kappa'] * (r / beta - p1['s0'])) /
              ksi / p2['gamma2'] * theta)
        self.energy -= y1 + y2
        f = ((y1 * p2['kappa'] + y2 * p1['kappa']) / beta +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] += f
        self.forces[a2] -= f
        self.sigma1[a1] += (exp(-p2['eta2'] * (r - beta * p2['s0'])) * ksi *
                            theta / p1['gamma1'])
        self.sigma1[a2] += (exp(-p1['eta2'] * (r - beta * p1['s0'])) / ksi *
                            theta / p2['gamma1'])

    def interact2(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (exp(-p2['eta2'] * (r - beta * p2['s0'])) * ksi / p1['gamma1'] *
              theta * self.deds[a1])
        y2 = (exp(-p1['eta2'] * (r - beta * p1['s0'])) / ksi / p2['gamma1'] *
              theta * self.deds[a2])
        f = ((y1 * p2['eta2'] + y2 * p1['eta2']) +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] -= f
        self.forces[a2] += f
Пример #25
0
def fss_bcc(indiv, Optimizer):
    defected = indiv[0].copy()
    defected.extend(indiv.bulki)
    #Identify nearest neighbor cutoff distance
    nndists = []
    for i in range(5):
        one = random.choice(defected)
        distances = [defected.get_distance(one.index, j) for j in range(len(defected)) if j != one.index]
        distances.sort()
        nndists.extend(distances[0:3])
    nndist = sum(nndists)/len(nndists)
    cutoff = nndist*0.6
    #Create nearest neighbor list from cutoff distance
    ctflist = [cutoff for one in defected]
    nl = NeighborList(ctflist, bothways=True, self_interaction=False)
    nl.update(defected)
    #Identify most common number of nearest neighbors for each atom
    nneigh = []
    for one in defected:
        indices, offsets = nl.get_neighbors(one.index)
        nneigh.append(len(indices))
    avn = mode(nneigh)
    #Identify those atoms that have a different number of nearest neighbors
    defs = [i for i in range(len(nneigh)) if nneigh[i] != avn[0][0]]
    #Create new structure from translated defected atoms
    defsat = Atoms(pbc = defected.get_pbc(), cell=defected.get_cell())
    for i in defs:
        defsat.append(defected[i])
    #Identify center of mass of defected group and translate to center of cell
    cop = position_average(defsat)
    ndefsat = shift_atoms(defsat, cop)
    ndefected = shift_atoms(defected, cop)
    #Identify bounds of defected portion of structure
    maxpos = max(numpy.maximum.reduce(ndefsat.positions))
    minpos = min(numpy.minimum.reduce(ndefsat.positions))
    #Identify size of structure that will encompass defected structure
    osc = copy.deepcopy(Optimizer.supercell)
    latcont = numpy.maximum.reduce(ndefsat.get_cell())[0]/osc[0]
    deltapos = abs(maxpos-minpos)
    newsupercell = round(deltapos/latcont)+1
    bxlen = newsupercell*latcont
    #Identify those atoms within a box of encompassing length centered at the center of the cell
    tol = .1
    cell = numpy.maximum.reduce(ndefsat.get_cell())
    boxlow = [cell[i]/2.0-bxlen/2.0-tol for i in range(3)]
    boxhigh = [cell[i]/2.0+bxlen/2.0+tol for i in range(3)]
    atlist = []
    otherlist = []
    for one in ndefected:
        pos = one.position
        if boxlow[0] < pos[0] < boxhigh[0]:
            if boxlow[1] < pos[1] < boxhigh[1]:
                if boxlow[2] < pos[2] < boxhigh[2]:
                    atlist.append(one)
                else:
                    otherlist.append(one)
            else:
                otherlist.append(one)
        else:
            otherlist.append(one)
    ncell = [bxlen,bxlen,bxlen]
    #Create a new atoms object from the atoms within the box
    ssats = Atoms(pbc = True, cell=ncell)
    for one in atlist:
        ssats.append(one)
    #Attach a calculator for the atoms
    ssats.set_calculator(Optimizer.calc)
    #Calculate the energy
    out = REE(ssats)
Пример #26
0
class EAM(Calculator):
    r"""

    EAM Interface Documentation

Introduction
============

The Embedded Atom Method (EAM) [1]_ is a classical potential which is
good for modelling metals, particularly fcc materials. Because it is
an equiaxial potential the EAM does not model directional bonds
well. However, the Angular Dependent Potential (ADP) [2]_ which is an
extended version of EAM is able to model directional bonds and is also
included in the EAM calculator.

Generally all that is required to use this calculator is to supply a
potential file or as a set of functions that describe the potential.
The files containing the potentials for this calculator are not
included but many suitable potentials can be downloaded from The
Interatomic Potentials Repository Project at
http://www.ctcms.nist.gov/potentials/

Theory
======

A single element EAM potential is defined by three functions: the
embedded energy, electron density and the pair potential.  A two
element alloy contains the individual three functions for each element
plus cross pair interactions.  The ADP potential has two additional
sets of data to define the dipole and quadrupole directional terms for
each alloy and their cross interactions.

The total energy `E_{\rm tot}` of an arbitrary arrangement of atoms is
given by the EAM potential as

.. math::
   E_{\rm tot} = \sum_i F(\bar\rho_i) + \frac{1}{2}\sum_{i\ne j} \phi(r_{ij})

and

.. math::
   \bar\rho_i = \sum_j \rho(r_{ij})

where `F` is an embedding function, namely the energy to embed an atom `i` in
the combined electron density `\bar\rho_i` which is contributed from
each of its neighbouring atoms `j` by an amount `\rho(r_{ij})`,
`\phi(r_{ij})` is the pair potential function representing the energy
in bond `ij` which is due to the short-range electro-static
interaction between atoms, and `r_{ij}` is the distance between an
atom and its neighbour for that bond.

The ADP potential is defined as

.. math::
   E_{\rm tot} = \sum_i F(\bar\rho_i) + \frac{1}{2}\sum_{i\ne j} \phi(r_{ij})
   + {1\over 2} \sum_{i,\alpha} (\mu_i^\alpha)^2
   + {1\over 2} \sum_{i,\alpha,\beta} (\lambda_i^{\alpha\beta})^2
   - {1 \over 6} \sum_i \nu_i^2

where `\mu_i^\alpha` is the dipole vector, `\lambda_i^{\alpha\beta}`
is the quadrupole tensor and `\nu_i` is the trace of
`\lambda_i^{\alpha\beta}`.

Running the Calculator
======================

EAM calculates the cohesive atom energy and forces. Internally the
potential functions are defined by splines which may be directly
supplied or created by reading the spline points from a data file from
which a spline function is created.  The LAMMPS compatible ``.alloy``
and ``.adp`` formats are supported. The LAMMPS ``.eam`` format is
slightly different from the ``.alloy`` format and is currently not
supported.

For example::

    from ase.calculators.eam import EAM

    mishin = EAM(potential='Al99.eam.alloy')
    mishin.write_potential('new.eam.alloy')
    mishin.plot()

    slab.set_calculator(mishin)
    slab.get_potential_energy()
    slab.get_forces()

The breakdown of energy contribution from the indvidual components are
stored in the calculator instance ``.results['energy_components']``

Arguments
=========

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``potential``              file of potential in ``.alloy`` or ``.adp`` format
                           (This is generally all you need to supply)

``elements[N]``            array of N element abbreviations

``embedded_energy[N]``     arrays of embedded energy functions

``electron_density[N]``    arrays of electron density functions

``phi[N,N]``               arrays of pair potential functions

``d_embedded_energy[N]``   arrays of derivative embedded energy functions

``d_electron_density[N]``  arrays of derivative electron density functions

``d_phi[N,N]``             arrays of derivative pair potentials functions

``d[N,N], q[N,N]``         ADP dipole and quadrupole function

``d_d[N,N], d_q[N,N]``     ADP dipole and quadrupole derivative functions

``skin``                   skin distance passed to NeighborList(). If no atom
                           has moved more than the skin-distance since the last
                           call to the ``update()`` method then the neighbor
                           list can be reused. Defaults to 1.0.

``form``                   the form of the potential ``alloy`` or ``adp``. This
                           will be determined from the file suffix or must be
                           set if using equations

=========================  ====================================================


Additional parameters for writing potential files
=================================================

The following parameters are only required for writing a potential in
``.alloy`` or ``.adp`` format file.

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``header``                 Three line text header. Default is standard message.

``Z[N]``                   Array of atomic number of each element

``mass[N]``                Atomic mass of each element

``a[N]``                   Array of lattice parameters for each element

``lattice[N]``             Lattice type

``nrho``                   No. of rho samples along embedded energy curve

``drho``                   Increment for sampling density

``nr``                     No. of radial points along density and pair
                           potential curves

``dr``                     Increment for sampling radius

=========================  ====================================================

Special features
================

``.plot()``
  Plots the individual functions. This may be called from multiple EAM
  potentials to compare the shape of the individual curves. This
  function requires the installation of the Matplotlib libraries.

Notes/Issues
=============

* Although currently not fast, this calculator can be good for trying
  small calculations or for creating new potentials by matching baseline
  data such as from DFT results. The format for these potentials is
  compatible with LAMMPS_ and so can be used either directly by LAMMPS or
  with the ASE LAMMPS calculator interface.

* Supported formats are the LAMMPS_ ``.alloy`` and ``.adp``. The
  ``.eam`` format is currently not supported. The form of the
  potential will be determined from the file suffix.

* Any supplied values will override values read from the file.

* The derivative functions, if supplied, are only used to calculate
  forces.

* There is a bug in early versions of scipy that will cause eam.py to
  crash when trying to evaluate splines of a potential with one
  neighbor such as caused by evaluating a dimer.

.. _LAMMPS: http://lammps.sandia.gov/

.. [1] M.S. Daw and M.I. Baskes, Phys. Rev. Letters 50 (1983)
       1285.

.. [2] Y. Mishin, M.J. Mehl, and D.A. Papaconstantopoulos,
       Acta Materialia 53 2005 4029--4041.


End EAM Interface Documentation
    """

    implemented_properties = ['energy', 'forces']

    default_parameters = dict(
        skin=1.0,
        potential=None,
        header="""EAM/ADP potential file\nGenerated from eam.py\nblank\n""")

    def __init__(self,
                 restart=None,
                 ignore_bad_restart_file=False,
                 label=os.curdir,
                 atoms=None,
                 **kwargs):

        if 'potential' in kwargs:
            self.read_potential(kwargs['potential'])

        Calculator.__init__(self, restart, ignore_bad_restart_file, label,
                            atoms, **kwargs)

        valid_args = (
            'potential',
            'elements',
            'header',
            'drho',
            'dr',
            'cutoff',
            'atomic_number',
            'mass',
            'a',
            'lattice',
            'embedded_energy',
            'electron_density',
            'phi',
            # derivatives
            'd_embedded_energy',
            'd_electron_density',
            'd_phi',
            'd',
            'q',
            'd_d',
            'd_q',  # adp terms
            'skin',
            'form',
            'Z',
            'nr',
            'nrho',
            'mass')

        # set any additional keyword arguments
        for arg, val in self.parameters.iteritems():
            if arg in valid_args:
                setattr(self, arg, val)
            else:
                raise RuntimeError('unknown keyword arg "%s" : not in %s' %
                                   (arg, valid_args))

    def set_form(self, fileobj):
        """set the form variable based on the file name suffix"""
        extension = os.path.splitext(fileobj)[1]

        if extension == '.eam':
            self.form = 'eam'
            raise NotImplementedError
        elif extension == '.alloy':
            self.form = 'alloy'
        elif extension == '.adp':
            self.form = 'adp'
        else:
            raise RuntimeError('unknown file extension type: %s' % extension)

    def read_potential(self, fileobj):
        """Reads a LAMMPS EAM file in alloy or adp format
        and creates the interpolation functions from the data
        """

        if isinstance(fileobj, str):
            f = open(fileobj)
            self.set_form(fileobj)
        else:
            f = fileobj

        lines = f.readlines()
        self.header = lines[:3]
        i = 3

        # make the data one long line so as not to care how its formatted
        data = []
        for line in lines[i:]:
            data.extend(line.split())

        self.Nelements = int(data[0])
        d = 1
        self.elements = data[d:(d + self.Nelements)]
        d += self.Nelements

        self.nrho = int(data[d])
        self.drho = float(data[d + 1])
        self.nr = int(data[d + 2])
        self.dr = float(data[d + 3])
        self.cutoff = float(data[d + 4])

        self.embedded_data = np.zeros([self.Nelements, self.nrho])
        self.density_data = np.zeros([self.Nelements, self.nr])
        self.Z = np.zeros([self.Nelements], dtype=int)
        self.mass = np.zeros([self.Nelements])
        self.a = np.zeros([self.Nelements])
        self.lattice = []
        d += 5

        # reads in the part of the eam file for each element
        for elem in range(self.Nelements):
            self.Z[elem] = int(data[d])
            self.mass[elem] = float(data[d + 1])
            self.a[elem] = float(data[d + 2])
            self.lattice.append(data[d + 3])
            d += 4

            self.embedded_data[elem] = np.float_(data[d:(d + self.nrho)])
            d += self.nrho
            self.density_data[elem] = np.float_(data[d:(d + self.nr)])
            d += self.nr

        # reads in the r*phi data for each interaction between elements
        self.rphi_data = np.zeros([self.Nelements, self.Nelements, self.nr])

        for i in range(self.Nelements):
            for j in range(i + 1):
                self.rphi_data[j, i] = np.float_(data[d:(d + self.nr)])
                d += self.nr

        self.r = np.arange(0, self.nr) * self.dr
        self.rho = np.arange(0, self.nrho) * self.drho

        self.set_splines()

        if (self.form == 'adp'):
            self.read_adp_data(data, d)
            self.set_adp_splines()

    def set_splines(self):
        # this section turns the file data into three functions (and
        # derivative functions) that define the potential
        self.embedded_energy = np.empty(self.Nelements, object)
        self.electron_density = np.empty(self.Nelements, object)
        self.d_embedded_energy = np.empty(self.Nelements, object)
        self.d_electron_density = np.empty(self.Nelements, object)

        for i in range(self.Nelements):
            self.embedded_energy[i] = spline(self.rho,
                                             self.embedded_data[i],
                                             k=3)
            self.electron_density[i] = spline(self.r,
                                              self.density_data[i],
                                              k=3)
            self.d_embedded_energy[i] = self.deriv(self.embedded_energy[i])
            self.d_electron_density[i] = self.deriv(self.electron_density[i])

        self.phi = np.empty([self.Nelements, self.Nelements], object)
        self.d_phi = np.empty([self.Nelements, self.Nelements], object)

        # ignore the first point of the phi data because it is forced
        # to go through zero due to the r*phi format in alloy and adp
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                if self.form == 'eam':  # not stored as rphi
                    # should we ignore the first point for eam ?
                    raise RuntimeError('.eam format not yet supported')

                    self.phi[i, j] = spline(self.r[1:],
                                            self.rphi_data[i, j][1:],
                                            k=3)
                else:
                    self.phi[i,
                             j] = spline(self.r[1:],
                                         self.rphi_data[i, j][1:] / self.r[1:],
                                         k=3)

                self.d_phi[i, j] = self.deriv(self.phi[i, j])

                if j != i:
                    self.phi[j, i] = self.phi[i, j]
                    self.d_phi[j, i] = self.d_phi[i, j]

    def set_adp_splines(self):
        self.d = np.empty([self.Nelements, self.Nelements], object)
        self.d_d = np.empty([self.Nelements, self.Nelements], object)
        self.q = np.empty([self.Nelements, self.Nelements], object)
        self.d_q = np.empty([self.Nelements, self.Nelements], object)

        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.d[i, j] = spline(self.r[1:], self.d_data[i, j][1:], k=3)
                self.d_d[i, j] = self.deriv(self.d[i, j])
                self.q[i, j] = spline(self.r[1:], self.q_data[i, j][1:], k=3)
                self.d_q[i, j] = self.deriv(self.q[i, j])

                # make symmetrical
                if j != i:
                    self.d[j, i] = self.d[i, j]
                    self.d_d[j, i] = self.d_d[i, j]
                    self.q[j, i] = self.q[i, j]
                    self.d_q[j, i] = self.d_q[i, j]

    def read_adp_data(self, data, d):
        """read in the extra adp data from the potential file"""

        self.d_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i + 1):
                self.d_data[j, i] = data[d:d + self.nr]
                d += self.nr

        self.q_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i + 1):
                self.q_data[j, i] = data[d:d + self.nr]
                d += self.nr

    def write_potential(self, filename, nc=1, numformat='%.8e'):
        """Writes out the potential in the format given by the form
        variable to 'filename' with a data format that is nc columns
        wide.  Note: array lengths need to be an exact multiple of nc
        """

        f = open(filename, 'w')

        assert self.nr % nc == 0
        assert self.nrho % nc == 0

        for line in self.header:
            f.write(line)

        f.write('%d ' % self.Nelements)
        for i in range(self.Nelements):
            f.write('%s ' % str(self.elements[i]))
        f.write('\n')

        f.write('%d %f %d %f %f \n' %
                (self.nrho, self.drho, self.nr, self.dr, self.cutoff))

        # start of each section for each element
        #        rs = np.linspace(0, self.nr * self.dr, self.nr)
        #        rhos = np.linspace(0, self.nrho * self.drho, self.nrho)

        rs = np.arange(0, self.nr) * self.dr
        rhos = np.arange(0, self.nrho) * self.drho

        for i in range(self.Nelements):
            f.write('%d %f %f %s\n' %
                    (self.Z[i], self.mass[i], self.a[i], str(self.lattice[i])))
            np.savetxt(f,
                       self.embedded_energy[i](rhos).reshape(
                           self.nrho / nc, nc),
                       fmt=nc * [numformat])
            np.savetxt(f,
                       self.electron_density[i](rs).reshape(self.nr / nc, nc),
                       fmt=nc * [numformat])

        # write out the pair potentials in Lammps DYNAMO setfl format
        # as r*phi for alloy format
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                np.savetxt(f,
                           (rs * self.phi[i, j](rs)).reshape(self.nr / nc, nc),
                           fmt=nc * [numformat])

        if self.form == 'adp':
            # these are the u(r) or dipole values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.d_data[i, j])

            # these are the w(r) or quadrupole values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.q_data[i, j])

        f.close()

    def update(self, atoms):
        # check all the elements are available in the potential
        self.Nelements = len(self.elements)
        elements = np.unique(atoms.get_chemical_symbols())
        unavailable = np.logical_not(
            np.array([item in self.elements for item in elements]))

        if np.any(unavailable):
            raise RuntimeError('These elements are not in the potential: %s' %
                               elements[unavailable])

        # cutoffs need to be a vector for NeighborList
        cutoffs = self.cutoff * np.ones(len(atoms))

        # convert the elements to an index of the position
        # in the eam format
        self.index = np.array(
            [self.elements.index(el) for el in atoms.get_chemical_symbols()])
        self.pbc = atoms.get_pbc()

        # since we need the contribution of all neighbors to the
        # local electron density we cannot just calculate and use
        # one way neighbors
        self.neighbors = NeighborList(cutoffs,
                                      skin=self.parameters.skin,
                                      self_interaction=False,
                                      bothways=True)
        self.neighbors.update(atoms)

    def calculate(self,
                  atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):
        """EAM Calculator

        atoms: Atoms object
            Contains positions, unit-cell, ...
        properties: list of str
            List of what needs to be calculated.  Can be any combination
            of 'energy', 'forces'
        system_changes: list of str
            List of what has changed since last calculation.  Can be
            any combination of these five: 'positions', 'numbers', 'cell',
            'pbc', 'initial_charges' and 'initial_magmoms'.
            """

        Calculator.calculate(self, atoms, properties, system_changes)

        # we shouldn't really recalc if charges or magmos change
        if len(system_changes) > 0:  # something wrong with this way
            self.update(self.atoms)
            self.calculate_energy(self.atoms)

            if 'forces' in properties:
                self.calculate_forces(self.atoms)

        # check we have all the properties requested
        for property in properties:
            if property not in self.results:
                if property is 'energy':
                    self.calculate_energy(self.atoms)

                if property is 'forces':
                    self.calculate_forces(self.atoms)

        # we need to remember the previous state of parameters
#        if 'potential' in parameter_changes and potential != None:
#                self.read_potential(potential)

    def calculate_energy(self, atoms):
        """Calculate the energy
        the energy is made up of the ionic or pair interaction and
        the embedding energy of each atom into the electron cloud
        generated by its neighbors
        """

        pair_energy = 0.0
        embedding_energy = 0.0
        mu_energy = 0.0
        lam_energy = 0.0
        trace_energy = 0.0

        self.total_density = np.zeros(len(atoms))
        if (self.form == 'adp'):
            self.mu = np.zeros([len(atoms), 3])
            self.lam = np.zeros([len(atoms), 3, 3])

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())

            rvec = (atoms.positions[neighbors] + offset - atoms.positions[i])

            ## calculate the distance to the nearest neighbors
            r = np.sqrt(np.sum(np.square(rvec), axis=1))  # fast
            #            r = np.apply_along_axis(np.linalg.norm, 1, rvec)  # sloow

            nearest = np.arange(len(r))[r <= self.cutoff]
            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                pair_energy += np.sum(self.phi[self.index[i], j_index](
                    r[nearest][use])) / 2.

                density = np.sum(self.electron_density[j_index](
                    r[nearest][use]))
                self.total_density[i] += density

                if self.form == 'adp':
                    self.mu[i] += self.adp_dipole(
                        r[nearest][use], rvec[nearest][use],
                        self.d[self.index[i], j_index])

                    self.lam[i] += self.adp_quadrupole(
                        r[nearest][use], rvec[nearest][use],
                        self.q[self.index[i], j_index])

            # add in the electron embedding energy
            embedding_energy += self.embedded_energy[self.index[i]](
                self.total_density[i])

        components = dict(pair=pair_energy, embedding=embedding_energy)

        if self.form == 'adp':
            mu_energy += np.sum(self.mu**2) / 2.
            lam_energy += np.sum(self.lam**2) / 2.

            for i in range(len(atoms)):  # this is the atom to be embedded
                trace_energy -= np.sum(self.lam[i].trace()**2) / 6.

            adp_result = dict(adp_mu=mu_energy,
                              adp_lam=lam_energy,
                              adp_trace=trace_energy)
            components.update(adp_result)

        self.positions = atoms.positions.copy()
        self.cell = atoms.get_cell().copy()

        energy = 0.0
        for i in components.keys():
            energy += components[i]

        self.energy_free = energy
        self.energy_zero = energy

        self.results['energy_components'] = components
        self.results['energy'] = energy

    def calculate_forces(self, atoms):
        # calculate the forces based on derivatives of the three EAM functions

        self.update(atoms)
        self.results['forces'] = np.zeros((len(atoms), 3))

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())
            # create a vector of relative positions of neighbors
            rvec = atoms.positions[neighbors] + offset - atoms.positions[i]
            r = np.sqrt(np.sum(np.square(rvec), axis=1))
            nearest = np.arange(len(r))[r < self.cutoff]

            d_embedded_energy_i = self.d_embedded_energy[self.index[i]](
                self.total_density[i])
            urvec = rvec.copy()  # unit directional vector

            for j in np.arange(len(neighbors)):
                urvec[j] = urvec[j] / r[j]

            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                rnuse = r[nearest][use]
                density_j = self.total_density[neighbors[nearest][use]]
                scale = (self.d_phi[self.index[i], j_index](rnuse) +
                         (d_embedded_energy_i *
                          self.d_electron_density[j_index](rnuse)) +
                         (self.d_embedded_energy[j_index](density_j) *
                          self.d_electron_density[self.index[i]](rnuse)))

                self.results['forces'][i] += np.dot(scale, urvec[nearest][use])

                if (self.form == 'adp'):
                    adp_forces = self.angular_forces(
                        self.mu[i], self.mu[neighbors[nearest][use]],
                        self.lam[i], self.lam[neighbors[nearest][use]], rnuse,
                        rvec[nearest][use], self.index[i], j_index)

                    self.results['forces'][i] += adp_forces

    def angular_forces(self, mu_i, mu, lam_i, lam, r, rvec, form1, form2):
        # calculate the extra components for the adp forces
        # rvec are the relative positions to atom i
        psi = np.zeros(mu.shape)
        for gamma in range(3):
            term1 = (mu_i[gamma] - mu[:, gamma]) * self.d[form1][form2](r)

            term2 = np.sum(
                (mu_i - mu) * self.d_d[form1][form2](r)[:, np.newaxis] *
                (rvec * rvec[:, gamma][:, np.newaxis] / r[:, np.newaxis]),
                axis=1)

            term3 = 2 * np.sum((lam_i[:, gamma] + lam[:, :, gamma]) * rvec *
                               self.q[form1][form2](r)[:, np.newaxis],
                               axis=1)
            term4 = 0.0
            for alpha in range(3):
                for beta in range(3):
                    rs = rvec[:, alpha] * rvec[:, beta] * rvec[:, gamma]
                    term4 += ((lam_i[alpha, beta] + lam[:, alpha, beta]) *
                              self.d_q[form1][form2](r) * rs) / r

            term5 = ((lam_i.trace() + lam.trace(axis1=1, axis2=2)) *
                     (self.d_q[form1][form2](r) * r + 2 * self.q[form1][form2]
                      (r)) * rvec[:, gamma]) / 3.

            # the minus for term5 is a correction on the adp
            # formulation given in the 2005 Mishin Paper and is posted
            # on the NIST website with the AlH potential
            psi[:, gamma] = term1 + term2 + term3 + term4 - term5

        return np.sum(psi, axis=0)

    def adp_dipole(self, r, rvec, d):
        # calculate the dipole contribution
        mu = np.sum((rvec * d(r)[:, np.newaxis]), axis=0)

        return mu  # sign to agree with lammps

    def adp_quadrupole(self, r, rvec, q):
        # slow way of calculating the quadrupole contribution
        r = np.sqrt(np.sum(rvec**2, axis=1))

        lam = np.zeros([rvec.shape[0], 3, 3])
        qr = q(r)
        for alpha in range(3):
            for beta in range(3):
                lam[:, alpha, beta] += qr * rvec[:, alpha] * rvec[:, beta]

        return np.sum(lam, axis=0)

    def deriv(self, spline):
        """Wrapper for extracting the derivative from a spline"""
        def d_spline(aspline):
            return spline(aspline, 1)

        return d_spline

    def plot(self, name=''):
        """Plot the individual curves"""

        try:
            import matplotlib.pyplot as plt

        except ImportError:
            raise NotAvailable('This needs matplotlib module.')

        if self.form == 'eam' or self.form == 'alloy':
            nrow = 2
        elif self.form == 'adp':
            nrow = 3
        else:
            raise RuntimeError('Unknown form of potential: %s' % self.form)

        if hasattr(self, 'r'):
            r = self.r
        else:
            r = np.linspace(0, self.cutoff, 50)

        if hasattr(self, 'rho'):
            rho = self.rho
        else:
            rho = np.linspace(0, 10.0, 50)

        plt.subplot(nrow, 2, 1)
        self.elem_subplot(rho, self.embedded_energy, r'$\rho$',
                          r'Embedding Energy $F(\bar\rho)$', name, plt)

        plt.subplot(nrow, 2, 2)
        self.elem_subplot(r, self.electron_density, r'$r$',
                          r'Electron Density $\rho(r)$', name, plt)

        plt.subplot(nrow, 2, 3)
        self.multielem_subplot(r, self.phi, r'$r$',
                               r'Pair Potential $\phi(r)$', name, plt)
        plt.ylim(-1.0, 1.0)  # need reasonable values

        if self.form == 'adp':
            plt.subplot(nrow, 2, 5)
            self.multielem_subplot(r, self.d, r'$r$', r'Dipole Energy', name,
                                   plt)

            plt.subplot(nrow, 2, 6)
            self.multielem_subplot(r, self.q, r'$r$', r'Quadrupole Energy',
                                   name, plt)

        plt.plot()

    def elem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            label = name + ' ' + self.elements[i]
            plt.plot(curvex, curvey[i](curvex), label=label)
        plt.legend()

    def multielem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            for j in np.arange(i + 1):
                label = name + ' ' + self.elements[i] + '-' + self.elements[j]
                plt.plot(curvex, curvey[i, j](curvex), label=label)
        plt.legend()
Пример #27
0
class LennardJones(Calculator):
    implemented_properties = ['energy', 'forces', 'stress']
    default_parameters = {'epsilon': 1.0, 'sigma': 1.0, 'rc': None}
    nolabel = True

    def __init__(self, **kwargs):
        Calculator.__init__(self, **kwargs)

    def calculate(self,
                  atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        natoms = len(self.atoms)

        sigma = self.parameters.sigma
        epsilon = self.parameters.epsilon
        rc = self.parameters.rc
        if rc is None:
            rc = 3 * sigma

        if 'numbers' in system_changes:
            self.nl = NeighborList([rc / 2] * natoms, self_interaction=False)

        self.nl.update(self.atoms)

        positions = self.atoms.positions
        cell = self.atoms.cell

        e0 = 4 * epsilon * ((sigma / rc)**12 - (sigma / rc)**6)

        energy = 0.0
        forces = np.zeros((natoms, 3))
        stress = np.zeros((3, 3))

        for a1 in range(natoms):
            neighbors, offsets = self.nl.get_neighbors(a1)
            cells = np.dot(offsets, cell)
            d = positions[neighbors] + cells - positions[a1]
            r2 = (d**2).sum(1)
            c6 = (sigma**2 / r2)**3
            c6[r2 > rc**2] = 0.0
            energy -= e0 * (c6 != 0.0).sum()
            c12 = c6**2
            energy += 4 * epsilon * (c12 - c6).sum()
            f = (24 * epsilon * (2 * c12 - c6) / r2)[:, np.newaxis] * d
            #print d
            #print r2**.5
            #print offsets
            #print f
            #print neighbors
            forces[a1] -= f.sum(axis=0)
            for a2, f2 in zip(neighbors, f):
                forces[a2] += f2
            stress += np.dot(f.T, d)

        #stress = np.dot(stress, cell)
        stress += stress.T.copy()
        stress *= -0.5 / self.atoms.get_volume()

        self.results['energy'] = energy
        self.results['forces'] = forces
        self.results['stress'] = stress.flat[[0, 4, 8, 5, 2, 1]]
Пример #28
0
class EAM(Calculator):
    r"""

    EAM Interface Documentation
    
Introduction
============

The Embedded Atom Method (EAM) [1]_ is a classical potential which is
good for modelling metals particularly or fcc materials. Because it is
an equiaxial potential the EAM does not model directional bonds
well. However, the Angular Dependent Potential (ADP) [2]_ which is an
extended version of EAM is able to model directional bonds is part of
the EAM calculator.

A single element EAM potential is defined by three functions: the
embedded energy, electron density and the pair potential (phi).
A two element alloy contains the individual three functions
for each element plus cross pair interactions.
The ADP potential has additional two additional sets of data to
define the dipole and quadrupole directional terms for each alloy
and their cross interactions.

The files containing the potentials for this calculator are not
included but many suitable potentials can be downloaded from The
Interatomic Potentials Repository Project at
http://www.ctcms.nist.gov/potentials/

Running the Calculator
======================

EAM calculates the cohesive atom energy and forces. Internally the
potential functions are defined by splines which may be directly
supplied or created by reading the spline points from a data file from
which a slpline function is created.  The LAMMPS compatible ``.alloy``
and ``.adp`` formats are supported. The LAMMPS ``.eam`` format is
slightly different from the ``.alloy`` format and is currently not
supported.

For example::

    from eam import EAM

    mishin = EAM('Al99.eam.alloy')
    mishin.write_file('new.eam.alloy')
    mishin.plot()

    slab.set_calculator(mishin)
    slab.get_potential_energy()
    slab.get_forces()


Arguments
=========

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``fileobj``                file of potential in ``.alloy`` or ``.adp`` format
                           (This is generally all you need to supply)
                            
``elements[N]``            array of N element abreviations

``embedded_energy[N]``     arrays of embedded energy functions

``electron_density[N]``    arrays of electron density functions

``phi[N,N]``               arrays of pair potential funtions

``d_embedded_energy[N]``   arrays of derivative embedded energy functions

``d_electron_density[N]``  arrays of derivative electron density functions

``d_phi[N,N]``             arrays of derivative pair potentials functions

``d[N], q[N,N]``           ADP dipole and quadrupole function

``d_d[N,N], d_q[N,N]``     ADP dipole and quadrupole derivative functions

=========================  ====================================================


Additional parameters for writing potential files
=================================================

The following parameters are only required for writing a potential in
``.alloy`` or ``.adp`` format file.

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``Z[N]``                   Array of atomic number of each element

``mass[N]``                Atomic mass of each element

``a[N]``                   Array of lattice parameters for each element

``lattice[N]``             Lattice type

``nrho``                   No. of rho samples

``drho``                   Increment for sampling density

``nr``                     No. of radial points

``dr``                     Increment for sampling radius

=========================  ====================================================

Special features
================

``.plot()``
  Plots the individual funtions. This may be called from multiple EAM
  potentials to compare the shape of the individual curves. This
  function requires the installation of the Matplotlib libraries.

Notes/Issues
=============

* Although currently not fast, this calculator can be good for trying
  small calculations or for creating new potentials by matching baseline
  data such as from DFT results. The format for these potentials is
  compatable with LAMMPS_ and so can be used either directly by LAMMPS or
  with the ASE LAMMPS calculator interface.

* Supported formats are the LAMMPS_ ``.alloy`` and ``.adp``. The
  ``.eam`` format is currently not supported.

* Any supplied values will overide values read from the file.

* The derivative functions, if supplied, are only used to calculate
  forces.


.. _LAMMPS: http://lammps.sandia.gov/

.. [1] M.S. Daw and M.I. Baskes, Phys. Rev. Letters 50 (1983)
       1285.

.. [2] Y. Mishin, M.J. Mehl, and D.A. Papaconstantopoulos,
       Acta Materialia 53 2005 4029--4041.


End EAM Interface Documentation
    """

    def __init__(self, fileobj=None, **kwargs):

        if fileobj != None:
            self.read_file(fileobj)

        valid_args = ('elements', 'header', 'drho', 'dr', 'cutoff',
                      'atomic_number', 'mass', 'a', 'lattice',
                      'embedded_energy', 'electron_density', 'phi',
                      # adp terms
                      'd', 'q', 'd_d', 'd_q',
                      # derivatives
                      'd_embedded_energy', 'd_electron_density', 'd_phi',
                      'skin', 'form', 'Z', 'nr', 'nrho', 'mass')

        # these variables need to be set, but are not read in
        if 'skin' not in kwargs:
            self.skin = 1.0

        # set any additional keyword arguments
        for arg, val in kwargs.iteritems():
            if arg in valid_args:
                setattr(self, arg, val)
            else:
                raise RuntimeError('unknown keyword arg "%s" : not in %s'
                                   % (arg, valid_args))

        # initialise the state of the calculation
        self.Nelements = len(self.elements)
        self.energy = 0.0
        self.positions = None
        self.cell = None
        self.pbc = None
        
    def set_form(self, fileobj):
        extension = os.path.splitext(fileobj)[1]

        if extension == '.eam':
            self.form = 'eam'
            raise NotImplementedError
        
        elif extension == '.alloy':
            self.form = 'alloy'
                
        elif extension == '.adp':
            self.form = 'adp'

        else:
            raise RuntimeError('unknown file extension type: %s' % extension)

    def read_file(self, fileobj):
        """Reads a LAMMPS EAM file in alloy format
        and creates the interpolation functions from the data
        """

        if isinstance(fileobj, str):
            f = open(fileobj)
            self.set_form(fileobj)
        else:
            f = fileobj
         
        lines = f.readlines()
        self.header = lines[:3]
        i = 3

        # make the data one long line so as not to care how its formatted
        data = []
        for line in lines[i:]:
            data.extend(line.split())
            
        self.Nelements = int(data[0])
        d = 1
        self.elements = data[d:(d + self.Nelements)]
        d += self.Nelements

        self.nrho = int(data[d])
        self.drho = float(data[d + 1])
        self.nr = int(data[d + 2])
        self.dr = float(data[d + 3])
        self.cutoff = float(data[d + 4])
        
        self.embedded_data = np.zeros([self.Nelements, self.nrho])
        self.density_data = np.zeros([self.Nelements, self.nr])
        self.Z = np.zeros([self.Nelements], dtype=int)
        self.mass = np.zeros([self.Nelements])
        self.a = np.zeros([self.Nelements])
        self.lattice = []
        d += 5

        # reads in the part of the eam file for each element
        for elem in range(self.Nelements):
            self.Z[elem] = int(data[d])
            self.mass[elem] = float(data[d + 1])
            self.a[elem] = float(data[d + 2])
            self.lattice.append(data[d + 3])
            d += 4
            
            self.embedded_data[elem] = np.float_(data[d:(d + self.nrho)])
            d += self.nrho
            self.density_data[elem] = np.float_(data[d:(d + self.nr)])
            d += self.nr

        # reads in the r*phi data for each interaction between elements
        self.rphi_data = np.zeros([self.Nelements, self.Nelements, self.nr])

        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.rphi_data[i, j] = np.float_(data[d:(d + self.nr)])
                d += self.nr

        self.r = np.arange(0, self.nr) * self.dr
        self.rho = np.arange(0, self.nrho) * self.drho

        # this section turns the file data into three functions (and
        # derivative functions) that define the potential
        self.embedded_energy = np.zeros(self.Nelements, object)
        self.electron_density = np.zeros(self.Nelements, object)
        self.d_embedded_energy = np.zeros(self.Nelements, object)
        self.d_electron_density = np.zeros(self.Nelements, object)

        for i in range(self.Nelements):
            self.embedded_energy[i] = spline(self.rho,
                                             self.embedded_data[i], k=3)
            self.electron_density[i] = spline(self.r,
                                              self.density_data[i], k=3)
            self.d_embedded_energy[i] = self.deriv(self.embedded_energy[i])
            self.d_electron_density[i] = self.deriv(self.electron_density[i])

        self.phi = np.zeros([self.Nelements, self.Nelements], object)
        self.d_phi = np.zeros([self.Nelements, self.Nelements], object)

        # ignore the first point of the phi data because it is forced
        # to go through zero due to the r*phi format in alloy and adp
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                if self.form == 'eam':  # not stored as rphi
                    # should we igore the first point for eam ?
                    raise RuntimeError('.eam format not yet supported')

                    self.phi[i, j] = spline(
                        self.r[1:], self.rphi_data[i, j][1:], k=3)
                else:
                    self.phi[i, j] = spline(
                        self.r[1:],
                        self.rphi_data[i, j][1:] / self.r[1:], k=3)

                self.d_phi[i, j] = self.deriv(self.phi[i, j])

                if j != i:
                    self.phi[j, i] = self.phi[i, j]
                    self.d_phi[j, i] = self.d_phi[i, j]

        if (self.form == 'adp'):
            self.read_adp_data(data, d)

    def read_adp_data(self, data, d):
        """reads in the extra data fro the adp format"""

        self.d_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.d_data[i, j] = data[d:d + self.nr]
                d += self.nr
                
        self.q_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.q_data[i, j] = data[d:d + self.nr]
                d += self.nr
    
        self.d = np.zeros([self.Nelements, self.Nelements], object)
        self.d_d = np.zeros([self.Nelements, self.Nelements], object)
        self.q = np.zeros([self.Nelements, self.Nelements], object)
        self.d_q = np.zeros([self.Nelements, self.Nelements], object)
    
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.d[i, j] = spline(self.r[1:], self.d_data[i, j][1:], k=3)
                self.d_d[i, j] = self.deriv(self.d[i, j])
                self.q[i, j] = spline(self.r[1:], self.q_data[i, j][1:], k=3)
                self.d_q[i, j] = self.deriv(self.q[i, j])

                # make symmetrical
                if j != i:
                    self.d[j, i] = self.d[i, j]
                    self.d_d[j, i] = self.d_d[i, j]
                    self.q[j, i] = self.q[i, j]
                    self.d_q[j, i] = self.d_q[i, j]

    def write_file(self, filename, nc=1, form='%.8e'):
        """Writes out the model of the eam_alloy in lammps alloy
        format to file with name = 'filename' with a data format that
        is nc columns wide.  Note: array lengths need to be an exact
        multiple of nc
"""

        f = open(filename, 'w')

        assert self.nr % nc == 0
        assert self.nrho % nc == 0

        if not hasattr(self, 'header'):
            self.header = """Unknown EAM potential file
Generated from eam.py
blank
"""
        for line in self.header:
            f.write(line)

        f.write('%d ' % self.Nelements)
        for i in range(self.Nelements):
            f.write('%s ' % str(self.elements[i]))
        f.write('\n')

        f.write('%d %f %d %f %f \n' %
                (self.nrho, self.drho, self.nr, self.dr, self.cutoff))
    
        # start of each section for each element
#        rs = np.linspace(0, self.nr * self.dr, self.nr)
#        rhos = np.linspace(0, self.nrho * self.drho, self.nrho)

        rs = np.arange(0, self.nr) * self.dr
        rhos = np.arange(0, self.nrho) * self.drho

        for i in range(self.Nelements):
            f.write('%d %f %f %s\n' % (self.Z[i], self.mass[i],
                                       self.a[i], str(self.lattice[i])))
            np.savetxt(f,
                       self.embedded_energy[i](rhos).reshape(self.nrho / nc,
                                                             nc),
                       fmt=nc * [form])
            np.savetxt(f,
                       self.electron_density[i](rs).reshape(self.nr / nc,
                                                            nc),
                       fmt=nc * [form])

        # write out the pair potentials in Lammps DYNAMO setfl format
        # as r*phi for alloy format
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                np.savetxt(f,
                           (rs * self.phi[i, j](rs)).reshape(self.nr / nc,
                                                             nc),
                           fmt=nc * [form])

        if self.form == 'adp':
            # these are the u(r) values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.d_data[i, j])
            
            # these are the w(r) values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.q_data[i, j])
                
        f.close()

    def update(self, atoms):
        # check all the elements are available in the potential
        elements = np.unique(atoms.get_chemical_symbols())
        unavailable = np.logical_not(
            np.array([item in self.elements for item in elements]))
        if np.any(unavailable):
            raise RuntimeError('These elements are not in the potential: %s' %
                               elements[unavailable])
                    
        # check if anything has changed to require re-calculation
        if (self.positions is None or
            len(self.positions) != len(atoms.get_positions()) or
            (self.positions != atoms.get_positions()).any() or
            (self.cell != atoms.get_cell()).any() or
            (self.pbc != atoms.get_pbc()).any()):

            # cutoffs need to be a vector for NeighborList
            cutoffs = self.cutoff * np.ones(len(atoms))

            # convert the elements to an index of the position
            # in the eam format
            self.index = np.array([atoms.calc.elements.index(el)
                                   for el in atoms.get_chemical_symbols()])
            self.pbc = atoms.get_pbc()

            # since we need the contribution of all neighbors to the
            # local electron density we cannot just calculate and use
            # one way neighbors
            self.neighbors = NeighborList(cutoffs, skin=self.skin,
                                          self_interaction=False,
                                          bothways=True)
            self.neighbors.update(atoms)
            self.calculate(atoms)
            
    def get_forces(self, atoms):
        # calculate the forces based on derivatives of the three EAM functions
        self.update(atoms)
        self.forces = np.zeros((len(atoms), 3))

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())
            # create a vector of relative positions of neighbors
            rvec = atoms.positions[neighbors] + offset - atoms.positions[i]
            r = np.sqrt(np.sum(np.square(rvec), axis=1))
            nearest = np.arange(len(r))[r < self.cutoff]

            d_embedded_energy_i = self.d_embedded_energy[
                self.index[i]](self.total_density[i])
            urvec = rvec.copy()  # unit directional vector

            for j in np.arange(len(neighbors)):
                urvec[j] = urvec[j] / r[j]
    
            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                rnuse = r[nearest][use]
                density_j = self.total_density[neighbors[nearest][use]]
                scale = (self.d_phi[self.index[i], j_index](rnuse) +
                         (d_embedded_energy_i *
                          self.d_electron_density[j_index](rnuse)) +
                         (self.d_embedded_energy[j_index](density_j) *
                          self.d_electron_density[self.index[i]](rnuse)))
            
                self.forces[i] += np.dot(scale, urvec[nearest][use])
                
                if (self.form == 'adp'):
                    adp_forces = self.angular_forces(
                        self.mu[i],
                        self.mu[neighbors[nearest][use]],
                        self.lam[i],
                        self.lam[neighbors[nearest][use]],
                        rnuse,
                        rvec[nearest][use],
                        self.index[i],
                        j_index)

                    self.forces[i] += adp_forces
                    
        return self.forces.copy()
            
    def get_stress(self, atoms):
        ## currently not implemented
        raise NotImplementedError
    
    def calculate(self, atoms):
        # calculate the energy
        # the energy is made up of the ionic or pair interaction and
        # the embedding energy of each atom into the electron cloud
        # generated by its neighbors

        energy = 0.0
        adp_energy = 0.0
        self.total_density = np.zeros(len(atoms))
        if (self.form == 'adp'):
            self.mu = np.zeros([len(atoms), 3])
            self.lam = np.zeros([len(atoms), 3, 3])

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())
            
            rvec = (atoms.positions[neighbors] + offset -
                    atoms.positions[i])

            ## calculate the distance to the nearest neighbors
            r = np.sqrt(np.sum(np.square(rvec), axis=1))  # fast
#            r = np.apply_along_axis(np.linalg.norm, 1, rvec)  # sloow

            nearest = np.arange(len(r))[r <= self.cutoff]
            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                pair_energy = np.sum(self.phi[self.index[i], j_index](
                        r[nearest][use])) / 2.
                energy += pair_energy

                density = np.sum(
                    self.electron_density[j_index](r[nearest][use]))
                self.total_density[i] += density

                if self.form == 'adp':
                    self.mu[i] += self.eam_dipole(
                        r[nearest][use],
                        rvec[nearest][use],
                        self.d[self.index[i], j_index])
                    
                    self.lam[i] += self.eam_quadrupole(
                        r[nearest][use],
                        rvec[nearest][use],
                        self.q[self.index[i], j_index])

            # add in the electron embedding energy
            embedding_energy = self.embedded_energy[self.index[i]](
                self.total_density[i])
#            print 'pair energy',energy
#            print 'embed energy',embedding_energy
            
            energy += embedding_energy

        if self.form == 'adp':
            mu_energy = np.sum(self.mu**2) / 2.
            adp_energy += mu_energy
#            print 'adp mu', mu_energy
            lam_energy = np.sum(self.lam**2) / 2.
            adp_energy += lam_energy
#            print 'adp lam', lam_energy

            for i in range(len(atoms)):  # this is the atom to be embedded
                adp_energy -= np.sum(self.lam[i].trace()**2) / 6.

#            print 'energy no adp', energy
            energy += adp_energy

        self.positions = atoms.positions.copy()
        self.cell = atoms.get_cell().copy()
        
        self.energy_free = energy
        self.energy_zero = energy

    def plot(self, name=''):
        """Plot the individual curves"""

        try:
            import matplotlib.pyplot as plt
        
        except ImportError:
            raise NotAvailable('This needs matplotlib module.')

        if self.form == 'eam' or self.form == 'alloy':
            nrow = 2
        elif self.form == 'adp':
            nrow = 3
        else:
            raise RuntimeError('Unknown form of potential: %s' % self.form)

        if hasattr(self, 'r'):
            r = self.r
        else:
            r = np.linspace(0, self.cutoff, 50)

        if hasattr(self, 'rho'):
            rho = self.rho
        else:
            rho = np.linspace(0, 10.0, 50)
        
        plt.subplot(nrow, 2, 1)
        self.elem_subplot(rho, self.embedded_energy,
                          r'$\rho$', r'Embedding Energy $F(\bar\rho)$',
                          name, plt)
        
        plt.subplot(nrow, 2, 2)
        self.elem_subplot(r, self.electron_density,
                          r'$r$', r'Electron Density $\rho(r)$', name, plt)

        plt.subplot(nrow, 2, 3)
        self.multielem_subplot(r, self.phi,
                               r'$r$', r'Pair Potential $\phi(r)$', name, plt)
        plt.ylim(-1.0, 1.0)  # need reasonable values

        if self.form == 'adp':
            plt.subplot(nrow, 2, 5)
            self.multielem_subplot(r, self.d,
                                   r'$r$', r'Dipole Energy', name, plt)
            
            plt.subplot(nrow, 2, 6)
            self.multielem_subplot(r, self.q,
                                   r'$r$', r'Quadrupole Energy', name, plt)

        plt.plot()

    def elem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            label = name + ' ' + self.elements[i]
            plt.plot(curvex, curvey[i](curvex), label=label)
        plt.legend()

    def multielem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            for j in np.arange(i + 1):
                label = name + ' ' + self.elements[i] + '-' + self.elements[j]
                plt.plot(curvex, curvey[i, j](curvex), label=label)
        plt.legend()

    def angular_forces(self, mu_i, mu, lam_i, lam, r, rvec, form1, form2):
        # calculate the extra components for the adp forces
        # rvec are the relative positions to atom i
        psi = np.zeros(mu.shape)
        for gamma in range(3):
            term1 = (mu_i[gamma] - mu[:, gamma]) * self.d[form1][form2](r)

            term2 = np.sum((mu_i - mu) * self.d_d[form1][form2](r)[:, np.newaxis]
                           * (rvec * rvec[:, gamma][:, np.newaxis]
                              / r[:, np.newaxis]), axis=1)
            
            term3 = 2 * np.sum((lam_i[:, gamma] + lam[:, :, gamma])
                               * rvec * self.q[form1][form2](r)[:, np.newaxis],
                               axis=1)
            term4 = 0.0
            for alpha in range(3):
                for beta in range(3):
                    rs = rvec[:, alpha] * rvec[:, beta] * rvec[:, gamma]
                    term4 += ((lam_i[alpha, beta] + lam[:, alpha, beta]) *
                              self.d_q[form1][form2](r) * rs) / r
                    
            term5 = ((lam_i.trace() + lam.trace(axis1=1, axis2=2)) *
                     (self.d_q[form1][form2](r) * r
                      + 2 * self.q[form1][form2](r)) * rvec[:, gamma]) / 3.

            # the minus for term5 is a correction on the adp
            # formulation given in the 2005 Mishin Paper and is posted
            # on the NIST website with the AlH potential
            psi[:, gamma] = term1 + term2 + term3 + term4 - term5

        return np.sum(psi, axis=0)

    def eam_dipole(self, r, rvec, d):
        # calculate the dipole contribution
        mu = np.sum((rvec * d(r)[:, np.newaxis]), axis=0)

        return mu  # sign to agree with lammps

    def eam_quadrupole(self, r, rvec, q):
        # slow way of calculating the quadrupole contribution
        r = np.sqrt(np.sum(rvec**2, axis=1))
    
        lam = np.zeros([rvec.shape[0], 3, 3])
        qr = q(r)
        for alpha in range(3):
            for beta in range(3):
                lam[:, alpha, beta] += qr * rvec[:, alpha] * rvec[:, beta]
            
        return np.sum(lam, axis=0)

    def deriv(self, spline):
        """Wrapper for extracting the derivative from a spline"""
        def d_spline(aspline):
            return spline(aspline, 1)

        return d_spline
Пример #29
0
def lattice_alteration_nn(indiv, Optimizer):
    """Move function to perform random move along random axis for nearest neighbor distance to random atoms
    Inputs:
        indiv = Individual class object to be altered
        Optimizer = Optimizer class object with needed parameters
    Outputs:
        indiv = Altered Individual class object
    """
    if 'MU' in Optimizer.debug:
        debug = True
    else:
        debug = False
    if Optimizer.structure=='Defect':
        if Optimizer.isolate_mutation:
            indc,indb,vacant,swaps,stro = find_defects(indiv[0],Optimizer.solidbulk,0)
            ind = indc.copy()
            ind.extend(indb)
        else:
            ind=indiv[0].copy()
            indc=indiv[0].copy()
    else:
        ind=indiv[0].copy()
        indc=indiv[0].copy()
    if len(indc) != 0:
        ctoff1 = [1.0 for one in ind]
        nl = NeighborList(ctoff1, bothways=True, self_interaction=False)
        nl.update(ind)
        try:
            natomsmove=random.randint(1,len(indc)/2)
        except ValueError:
            natomsmove=1
        passn=0
        for count in range(natomsmove):
            try:
                indexmv = random.choice([i for i in range(len(indc))])
                indices, offsets = nl.get_neighbors(indexmv)
                nns = Atoms()
                nns.append(ind[indexmv])
                for index, d in zip(indices,offsets):
                    index = int(index)
                    pos = ind[index].position + numpy.dot(d,ind.get_cell())
                    nns.append(Atom(symbol=ind[index].symbol, position=pos))
                dist = [nns.get_distance(0,i) for i in range(1, len(nns))]
                r = sum(dist)/len(dist)
                dir = random.choice([[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]])
                ind[indexmv].position += [i*r for i in dir]
            except:
                passn+=1
        indiv[0]=ind.copy()
    else:
        natomsmove=0
        passn=0
    Optimizer.output.write('Lattice Alteration NN Mutation performed on individual\n')
    Optimizer.output.write('Index = '+repr(indiv.index)+'\n')
    natomsmove-=passn
    Optimizer.output.write('Number of atoms moved = '+repr(natomsmove)+'\n')
    Optimizer.output.write(repr(indiv[0])+'\n')
    muttype='LANN'+repr(natomsmove)
    if indiv.energy==0:
        indiv.history_index=indiv.history_index+'m'+muttype
    else:
        indiv.history_index=repr(indiv.index)+'m'+muttype
    return indiv
Пример #30
0
def find_defects(solid,
                 bulko,
                 rcutoff,
                 atomlistcheck=False,
                 trackvacs=False,
                 trackswaps=False,
                 debug=False,
                 dcheck=0.6):
    """Function to find interstitials, vacancies, and substitutional atoms (swaps) in a defected structure.
    Identifies species by comparison to perfect structure.
    Inputs:
        solid = ASE atoms class for defected structure
        bulko = ASE atoms class for perfect structure
        rcutoff = float value of distance to surrounding atoms to include
        atomlistcheck = False/list of atom types and concentrations according to atomlist format
        trackvacs = True/False whether or not to identify vacancies in defect
        trackswaps = True/False whether or not to identify substitutional defects
        debug = False/file object to write debug structures"""
    # Combine perfect and defect structures together
    b = bulko.copy()
    b.extend(solid)
    b.set_pbc(True)
    #Debug: Write solid and bulko to file
    if debug:
        print len(bulko)
        write_xyz(debug, b, 'Find Ints: Solid and Bulko')
    # Identify nearest neighbor atoms for each atom in perfect structure
    ntot = len(bulko)
    ctoff1 = [1.2 for one in b]
    nl = NeighborList(ctoff1, bothways=True, self_interaction=False)
    nl.update(b)
    slist = []
    blist = []
    wlist = []
    #Loop over each atom in perfect structure
    for one in range(ntot):
        indices, offsets = nl.get_neighbors(one)
        for index, d in zip(indices, offsets):
            index = int(index)
            if index >= ntot:
                pos = b[index].position + numpy.dot(d, bulko.get_cell())
                natm1 = Atom(position=pos)
                dist, dx, dy, dz = calc_dist(b[one], natm1)
                if dist <= dcheck:
                    #Assume atoms closer than 0.6 Angstroms to be equivalent
                    slist.append(index - ntot)
                    blist.append(one)
                    if b[one].symbol == b[index].symbol:
                        wlist.append(index - ntot)
    #Identify those atoms corresponding to interstitials, vacancies, and substitutions
    oslist = [atm.index for atm in solid if atm.index not in slist]
    vlist = [atm.index for atm in bulko if atm.index not in blist]
    swlist = [
        atm.index for atm in solid
        if atm.index not in wlist and atm.index not in oslist
    ]
    # Create Atoms objects for each identified defect
    ntot = len(solid)
    cluster = Atoms()
    for one in oslist:
        cluster.append(solid[one])
    vacant = Atoms()
    if trackvacs == True:
        for one in vlist:
            vacant.append(
                Atom(symbol=bulko[one].symbol, position=bulko[one].position))
            solid.append(Atom(symbol='X', position=bulko[one].position))
            oslist.append(len(solid) - 1)
        stro = 'Cluster Identified with length = {0}\nIdentified {1} vacancies\n'.format(
            len(cluster), len(vlist))
    swaps = Atoms()
    if trackswaps == True:
        for one in swlist:
            swaps.append(solid[one])
            oslist.append(one)
        stro = 'Cluster Identified with length = {0}\nIdentified {1} swaps\n'.format(
            len(cluster), len(swlist))
    else:
        stro = 'Cluster Identified with length = {0}\n'.format(len(cluster))
    #Debug: write cluster to file
    if debug:
        b = cluster.copy()
        write_xyz(debug, b, 'Find Ints: Cluster')
        debug.flush()
        print 'Found cluster size = ', len(b)
    # Identify atoms surrounding the identified defects in the defected structure
    box = Atoms()
    bulki = Atoms()
    if rcutoff != 0:
        if rcutoff > 2.0:
            cutoffs = [rcutoff for one in solid]
        else:
            cutoffs = [2.0 for one in solid]
        solid.set_pbc(True)
        nl = NeighborList(cutoffs, bothways=True, self_interaction=False)
        nl.update(solid)
        nbatmsd = []
        repinds = []
        for one in oslist:
            if one not in repinds:
                if one < ntot:
                    nbatmsd.append((0, one))
                    repinds.append(one)
        for one in oslist:
            indices, offsets = nl.get_neighbors(one)
            for index, d in zip(indices, offsets):
                index = int(index)
                if index not in repinds and index < ntot:
                    opos = copy.copy(solid[index].position)
                    solid[index].position = solid[index].position + numpy.dot(
                        d, solid.get_cell())
                    dist = solid.get_distance(one, index)
                    solid[index].position = opos
                    if dist <= rcutoff:
                        nbatmsd.append((dist, index))
                        repinds.append(index)
    else:
        nbatmsd = []
        repinds = []
        for one in oslist:
            if one not in repinds:
                if one < ntot:
                    nbatmsd.append((0, one))
                    repinds.append(one)
    nbatmsd = sorted(nbatmsd, key=lambda one: one[0], reverse=True)
    indices = []
    natomsbox = 0
    # Select only atoms closest to defects that satisfy concentrations specified by atomlist given in atomlistcheck
    if atomlistcheck:
        for sym, c, m, u in atomlistcheck:
            i = 0
            nbsym = [one for one in nbatmsd if solid[one[1]].symbol == sym]
            if len(nbsym) > c:
                while i < c:
                    a = nbsym.pop()
                    box.append(solid[a[1]])
                    indices.append(a[1])
                    i += 1
            else:
                for a in nbsym:
                    box.append(solid[a[1]])
                    indices.append(a[1])
                    i += 1
                if len(box) - natomsbox < c:
                    try:
                        while True:
                            for n in range(len(nbatmsd) - 1, -1, -1):
                                inds, offsets = nl.get_neighbors(nbatmsd[n][1])
                                for one, d in zip(inds, offsets):
                                    if len(box) - natomsbox < c:
                                        if one not in indices and one < ntot and solid[
                                                one].symbol == sym:
                                            opos = copy.copy(
                                                solid[one].position)
                                            solid[one].position = solid[
                                                one].position + numpy.dot(
                                                    d, solid.get_cell())
                                            dist = solid.get_distance(
                                                nbatmsd[n][1], one)
                                            solid[one].position = opos
                                            if dist <= rcutoff * 5.0:
                                                box.append(solid[one])
                                                indices.append(one)
                                    else:
                                        raise StopIteration()
                                for one, d in zip(inds, offsets):
                                    if len(box) - natomsbox < c:
                                        if one not in indices and one < ntot and solid[
                                                one].symbol == sym:
                                            opos = copy.copy(
                                                solid[one].position)
                                            solid[one].position = solid[
                                                one].position + numpy.dot(
                                                    d, solid.get_cell())
                                            dist = solid.get_distance(
                                                nbatmsd[n][1], one)
                                            solid[one].position = opos
                                            box.append(solid[one])
                                            indices.append(one)
                                    else:
                                        raise StopIteration()
                    except StopIteration:
                        pass
            natomsbox = len(box)
        #Double check for sanity
        for sym, c, m, u in atomlistcheck:
            symsbox = [one for one in box if one.symbol == sym]
            if len(symsbox) != c:
                stro += 'WARNING!!!! : FAILURE IN FIND_DEFECTS TO MATCH PROVIDED ATOMLIST. DEBUG!!!!\n'
    # If atomlistcheck is False then use all the atoms in the given cutoff distance
    else:
        for a in nbatmsd:
            box.append(solid[a[1]])
            indices.append(a[1])
    # Add remaining atoms in defect to defected bulk atoms object
    for one in range(len(solid)):
        if one not in indices and one < ntot:
            bulki.append(solid[one])
    #Check for accidental vacancy admissions
    #checklist=[atm for atm in box if atm.symbol=='X']
    #checklist.extend([atm for atm in bulki if atm.symbol=='X'])
    #Set up new individual
    indiv = box.copy()
    bulki.set_cell(bulko.get_cell())
    indiv.set_cell(bulko.get_cell())
    bulki.set_pbc(True)
    indiv.set_pbc(True)
    stro += 'Atomlist check = {0}\n'.format(atomlistcheck)
    stro += 'Bulko = {0}\n'.format(bulko)
    stro += 'New individual ({0} atoms) : {1}\n'.format(len(indiv), indiv)
    stro += 'New bulki ({0} atoms) : {1}\n'.format(len(bulki), bulki)
    #Debug: write new indiv to file
    if debug:
        b = indiv.copy()
        write_xyz(debug, b, 'Find Ints: New Individual')
        #Debug: write new bulki to file
        b = bulki.copy()
        write_xyz(debug, b, 'Find Ints: New Bulki')
        debug.flush()
        print len(bulko)

    return indiv, bulki, vacant, swaps, stro
Пример #31
0
                nl = NeighborList(atoms.numbers * 0.2 + 0.5,
                                  skin=0.0, sorted=sorted)
                nl.update(atoms)
                d, c = count(nl, atoms)
                atoms2 = atoms.repeat((p1 + 1, p2 + 1, p3 + 1))
                nl2 = NeighborList(atoms2.numbers * 0.2 + 0.5,
                                   skin=0.0, sorted=sorted)
                nl2.update(atoms2)
                d2, c2 = count(nl2, atoms2)
                c2.shape = (-1, 10)
                dd = d * (p1 + 1) * (p2 + 1) * (p3 + 1) - d2
                print dd
                print c2 - c
                assert abs(dd) < 1e-10
                assert not (c2 - c).any()

h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)])
nl = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False)
assert nl.update(h2)
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert nl.update(h2)
assert (nl.get_neighbors(0)[0] == []).all()
assert nl.nupdates == 2
Пример #32
0
                nl2 = NeighborList(atoms2.numbers * 0.2 + 0.5,
                                   skin=0.0, sorted=sorted)
                nl2.update(atoms2)
                d2, c2 = count(nl2, atoms2)
                c2.shape = (-1, 10)
                dd = d * (p1 + 1) * (p2 + 1) * (p3 + 1) - d2
                print dd
                print c2 - c
                assert abs(dd) < 1e-10
                assert not (c2 - c).any()

h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)])
nl = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False)
assert nl.update(h2)
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert nl.update(h2)
assert (nl.get_neighbors(0)[0] == []).all()
assert nl.nupdates == 2

x = bulk('X', 'fcc', a=2**0.5)
print x

nl = NeighborList([0.5], skin=0.01, bothways=True, self_interaction=False)
nl.update(x)
Пример #33
0
def newclus(ind1, ind2, Optimizer):
    """Select a box in the cluster configuration"""

    if 'CX' in Optimizer.debug:
        debug = True
    else:
        debug = False
    Optimizer.output.write('Box Cluster Cx between individual {} and individual {}'.format(repr(ind1.index), repr(ind2.index)))

    # Perserve starting conditions of individual
    solid1 = ind1[0].copy()
    solid2 = ind2[0].copy()
    cello1 = ind1[0].get_cell()
    cello2 = ind2[0].get_cell()
    cell1 = numpy.maximum.reduce(solid1.get_positions())
    cell1m = numpy.minimum.reduce(solid1.get_positions())
    cell2 = numpy.maximum.reduce(solid2.get_positions())
    cell2m = numpy.minimum.reduce(solid2.get_positions())
    cell = numpy.minimum(cell1, cell2)
    pbc1 = solid1.get_pbc()
    pbc2 = solid2.get_pbc()

    # Get starting concentrations and number of atoms
    nat1 = len(solid1)
    nat2 = len(solid2)

    # Pick a origin point for box in the cell
    pt1 = random.choice(solid1)
    pt1f = [(pt1.position[i]-cell1m[i])/cell1[i] for i in range(3)]
    pt2 = [pt1f[i]*cell2[i]+cell2m[i] for i in range(3)]
    solid2.append(Atom(position=pt2))
    pt2 = solid2[len(solid2)-1]

    # Find max neighborsize of circle cut
    r = random.uniform(0, min(nat1, nat2)/5.0)
    if debug:
        print('DEBUG CX: Point one = {}'.format(pt1.position))
        print('DEBUG CX: Point two = {}'.format(pt2.position))

    # Find atoms within sphere of neighborsize r for both individuals
    # Make sure that crossover is only selection of atoms not all
    while True:
        ctoff = [r for on in solid1]
        nl = NeighborList(ctoff, bothways=True, self_interaction=False)
        nl.update(solid1)
        indices1, offsets = nl.get_neighbors(pt1.index)
        if len(indices1) == 0:
            r = r*1.2
        elif len(indices1) < nat1*.75:
            break
        else:
            r = r*0.8

    if debug:
        print('Neighborsize of box = {}'.format(repr(r)))
        print('Position in solid1 = {}'.format(repr(pt1.position)))
        print('Position in solid2 = {}'.format(repr(pt2.position)))

    group1 = Atoms(cell=solid1.get_cell(), pbc=solid1.get_pbc())
    group1.append(pt1)
    indices1a = [pt1.index]
    for index, d in zip(indices1, offsets):
        if index not in indices1a:
            index = int(index)
            pos = solid1[index].position + numpy.dot(d, solid1.get_cell())
            group1.append(Atom(symbol=solid1[index].symbol, position=pos))
            indices1a.append(index)
    indices1 = indices1a
    ctoff = [r for on in solid2]
    nl = NeighborList(ctoff, bothways=True, self_interaction=False)
    nl.update(solid2)
    indices2, offsets = nl.get_neighbors(pt2.index)
    group2 = Atoms(cell=solid2.get_cell(), pbc=solid2.get_pbc())
    indices2a = []
    for index, d in zip(indices2, offsets):
        if index not in indices2a:
            index = int(index)
            pos = solid2[index].position + numpy.dot(d, solid2.get_cell())
            group2.append(Atom(symbol=solid2[index].symbol, position=pos))
            indices2a.append(index)
    indices2 = indices2a
    if len(indices2) == 0:
        for one in group1:
            while True:
                sel = random.choice(solid2)
                if sel.symbol == one.symbol:
                    if sel.index not in indices2:
                        group2.append(sel)
                        indices2.append(sel.index)
                        break

    if Optimizer.forcing == 'Concentration':
        symlist = list(set(group1.get_chemical_symbols()))
        seplist = [[atm for atm in group2 if atm.symbol == sym] for sym in symlist]
        group2n = Atoms(cell=group2.get_cell(), pbc=group2.get_pbc())
        indices2n = []
        dellist = []
        for one in group1:
            sym1 = one.symbol
            listpos = [i for i, s in enumerate(symlist) if s == sym1][0]
            if len(seplist[listpos]) > 0:
                pos = random.choice(range(len(seplist[listpos])))
                group2n.append(seplist[listpos][pos])
                indices2n.append(indices2[seplist[listpos][pos].index])
                del seplist[listpos][pos]
            else:
                dellist.append(one.index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group1[one]
                del indices1[one]
        indices2n.append(pt2.index)
        indices2 = indices2n
        group2 = group2n.copy()
    else:
        dellist = []
        while len(group2) < len(group1)-len(dellist):
            # Too many atoms in group 1
            dellist.append(random.choice(group1).index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group1[one]
                del indices1[one]
        dellist = []
        while len(group1) < len(group2)-len(dellist):
            # Too many atoms in group 2
            dellist.append(random.choice(group2).index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group2[one]
                del indices2[one]

    other2 = Atoms(cell=solid2.get_cell(), pbc=solid2.get_pbc())
    for one in solid2:
        if one.index not in indices2:
            other2.append(one)
    other1 = Atoms(cell=solid1.get_cell(), pbc=solid1.get_pbc())
    for one in solid1:
        if one.index not in indices1:
            other1.append(one)

    # Exchange atoms in sphere and build new solids
    nsolid1 = other1.copy()
    nsolid1.extend(group2.copy())
    nsolid2 = other2.copy()
    nsolid2.extend(group1.copy())

    # DEBUG: Write crossover to file
    if debug:
        write_xyz(Optimizer.debugfile, nsolid1, 'CX(randalloybx):nsolid1')
        write_xyz(Optimizer.debugfile, nsolid2, 'CX(randalloybx):nsolid2')


    # DEBUG: Check structure of atoms exchanged
    for sym, c, m, u in Optimizer.atomlist:
        if Optimizer.structure == 'Defect':
            nc = len([atm for atm in nsolid1 if atm.symbol == sym])
            nc += len([atm for atm in ind1.bulki if atm.symbol == sym])
            oc = len([atm for atm in solid1 if atm.symbol == sym])
            oc += len([atm for atm in ind1.bulki if atm.symbol == sym])
        else:
            nc = len([atm for atm in nsolid1 if atm.symbol == sym])
            oc = len([atm for atm in solid1 if atm.symbol == sym])
        Optimizer.output.write('CX(clustbx):New solid1 contains '+repr(nc)+' '+repr(sym)+' atoms\n')
        if debug:
            print('DEBUG CX: New solid1 contains {} {} atoms'.format(repr(nc), repr(sym)))
        if oc != nc:
            # pdb.set_trace()
            print('CX: Issue in maintaining atom concentration\n Dropping new individual')
            Optimizer.output.write('CX: Issue in maintaining atom concentration\n Dropping new individual 1\n')
            nsolid1 = solid1
    for sym, c, m, u in Optimizer.atomlist:
        if Optimizer.structure == 'Defect':
            nc = len([atm for atm in nsolid2 if atm.symbol == sym])
            nc += len([atm for atm in ind2.bulki if atm.symbol == sym])
            oc = len([atm for atm in solid2 if atm.symbol == sym])
            oc += len([atm for atm in ind2.bulki if atm.symbol == sym])
        else:
            nc = len([atm for atm in nsolid2 if atm.symbol == sym])
            oc = len([atm for atm in solid2 if atm.symbol == sym])
        Optimizer.output.write('CX(clustbx):New solid2 contains '+repr(nc)+' '+repr(sym)+' atoms\n')
        if debug:
            print('DEBUG CX: New solid2 contains {} and {} atoms'.format(repr(nc), repr(sym)))
        if oc != nc:
            #pdb.set_trace()
            print('CX: Issue in maintaining atom concentration\n Dropping new individual')
            Optimizer.output.write('CX: Issue in maintaining atom concentration\n Dropping new individual 2\n')
            solid2.pop()
            nsolid2 = solid2
    if Optimizer.forcing != 'Concentration':
        for i in range(len(Optimizer.atomlist)):
            atms1 = [inds for inds in nsolid1 if inds.symbol == Optimizer.atomlist[i][0]]
            atms2 = [inds for inds in nsolid2 if inds.symbol == Optimizer.atomlist[i][0]]
            if len(atms1) == 0:
                if len(atms2) == 0:
                    nsolid1[random.randint(0, len(indi1)-1)].symbol == Optimizer.atomlist[i][0]
                    nsolid2[random.randint(0, len(indi2)-1)].symbol == Optimizer.atomlist[i][0]
                else:
                    nsolid1.append(atms2[random.randint(0, len(atms2)-1)])
                    nsolid1.pop(random.randint(0, len(nsolid1)-2))
            else:
                if len(atms2) == 0:
                    nsolid2.append(atms1[random.randint(0, len(atms1)-1)])
                    nsolid2.pop(random.randint(0, len(nsolid2)-2))

    nsolid1.set_cell(cello1)
    nsolid2.set_cell(cello2)
    nsolid1.set_pbc(pbc1)
    nsolid2.set_pbc(pbc2)

    ind1[0] = nsolid1.copy()
    ind2[0] = nsolid2.copy()

    return ind1, ind2
Пример #34
0
def eval_energy(input):
    """Function to evaluate energy of an individual
    Inputs:
        input = [Optimizer class object with parameters, Individual class structure to be evaluated]
    Outputs:
        energy, bul, individ, signal
        energy = energy of Individual evaluated
        bul = bulk structure of Individual if simulation structure is Defect
        individ = Individual class structure evaluated
        signal = string of information about evaluation
    """
    if input[0] == None:
        energy = 0
        bul = 0
        individ = 0
        rank = MPI.COMM_WORLD.Get_rank()
        signal = 'Evaluated none individual on ' + repr(rank) + '\n'
    else:
        [Optimizer, individ] = input
    if Optimizer.calc_method == 'MAST':
        energy = individ.energy
        bul = individ.energy
        signal = 'Recieved MAST structure\n'
    else:
        if Optimizer.parallel: rank = MPI.COMM_WORLD.Get_rank()
        if not Optimizer.genealogy:
            STR = '----Individual ' + str(
                individ.index) + ' Optimization----\n'
        else:
            STR = '----Individual ' + str(
                individ.history_index) + ' Optimization----\n'
        indiv = individ[0]
        if 'EE' in Optimizer.debug:
            debug = True
        else:
            debug = False
        if debug:
            write_xyz(Optimizer.debugfile, indiv, 'Recieved by eval_energy')
            Optimizer.debugfile.flush()
        if Optimizer.structure == 'Defect':
            indi = indiv.copy()
            if Optimizer.alloy == True:
                bulk = individ.bulki
            else:
                bulk = individ.bulko
            nat = indi.get_number_of_atoms()
            csize = bulk.get_cell()
            totalsol = Atoms(cell=csize, pbc=True)
            totalsol.extend(indi)
            totalsol.extend(bulk)
            for sym, c, m, u in Optimizer.atomlist:
                nc = len([atm for atm in totalsol if atm.symbol == sym])
                STR += 'Defect configuration contains ' + repr(
                    nc) + ' ' + repr(sym) + ' atoms\n'

        elif Optimizer.structure == 'Surface':
            totalsol = Atoms()
            totalsol.extend(indiv)
            nat = indiv.get_number_of_atoms()
            totalsol.extend(individ.bulki)
            for sym, c, m, u in Optimizer.atomlist:
                nc = len([atm for atm in totalsol if atm.symbol == sym])
                STR += 'Surface-Bulk configuration contains ' + repr(
                    nc) + ' ' + repr(sym) + ' atoms\n'
            cell = numpy.maximum.reduce(indiv.get_cell())
            totalsol.set_cell([cell[0], cell[1], 500])
            totalsol.set_pbc([True, True, False])

        if Optimizer.constrain_position:
            ts = totalsol.copy()
            indc, indb, vacant, swap, stro = find_defects(
                ts, Optimizer.solidbulk, 0)
            sbulk = Optimizer.solidbulk.copy()
            bcom = sbulk.get_center_of_mass()
            #totalsol.translate(-bulkcom)
            #indc.translate(-bulkcom)
            #totalsol.append(Atom(position=[0,0,0]))
            # 			for one in indc:
            # 				index = [atm.index for atm in totalsol if atm.position[0]==one.position[0] and atm.position[1]==one.position[1] and atm.position[2]==one.position[2]][0]
            # 				if totalsol.get_distance(-1,index) > Optimizer.sf:
            # 					r = random.random()
            # 					totalsol.set_distance(-1,index,Optimizer.sf*r,fix=0)
            # 			totalsol.pop()
            # 			totalsol.translate(bulkcom)
            com = indc.get_center_of_mass()
            dist = (sum((bcom[i] - com[i])**2 for i in range(3)))**0.5
            if dist > Optimizer.sf:
                STR += 'Shifting structure to within region\n'
                r = random.random() * Optimizer.sf
                comv = numpy.linalg.norm(com)
                ncom = [one * r / comv for one in com]
                trans = [ncom[i] - com[i] for i in range(3)]
                indices = []
                for one in indc:
                    id = [
                        atm.index for atm in totalsol
                        if atm.position[0] == one.position[0]
                        and atm.position[1] == one.position[1]
                        and atm.position[2] == one.position[2]
                    ][0]
                    totalsol[id].position += trans

        # Check for atoms that are too close
        min_len = 0.7
        #pdb.set_trace()
        if not Optimizer.fixed_region:
            if Optimizer.structure == 'Defect' or Optimizer.structure == 'Surface':
                cutoffs = [2.0 for one in totalsol]
                nl = NeighborList(cutoffs,
                                  bothways=True,
                                  self_interaction=False)
                nl.update(totalsol)
                for one in totalsol[0:nat]:
                    nbatoms = Atoms()
                    nbatoms.append(one)
                    indices, offsets = nl.get_neighbors(one.index)
                    for index, d in zip(indices, offsets):
                        index = int(index)
                        sym = totalsol[index].symbol
                        pos = totalsol[index].position + numpy.dot(
                            d, totalsol.get_cell())
                        at = Atom(symbol=sym, position=pos)
                        nbatoms.append(at)
                    while True:
                        dflag = False
                        for i in range(1, len(nbatoms)):
                            d = nbatoms.get_distance(0, i)
                            if d < min_len:
                                nbatoms.set_distance(0,
                                                     i,
                                                     min_len + .01,
                                                     fix=0.5)
                                STR += '--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                                dflag = True
                        if dflag == False:
                            break
                    for i in range(len(indices)):
                        totalsol[indices[i]].position = nbatoms[i + 1].position
                    totalsol[one.index].position = nbatoms[0].position
                    nl.update(totalsol)
                if debug:
                    write_xyz(Optimizer.debugfile, totalsol,
                              'After minlength check')
                    Optimizer.debugfile.flush()
            else:
                for i in range(len(indiv)):
                    for j in range(len(indiv)):
                        if i != j:
                            d = indiv.get_distance(i, j)
                            if d < min_len:
                                indiv.set_distance(i, j, min_len, fix=0.5)
                                STR += '--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                if debug:
                    write_xyz(Optimizer.debugfile, indiv,
                              'After minlength check')
                    Optimizer.debugfile.flush()

        # Set calculator to use to get forces/energies
        if Optimizer.parallel:
            calc = setup_calculator(Optimizer)
            if Optimizer.fixed_region:
                pms = copy.deepcopy(calc.parameters)
                try:
                    pms['mass'][
                        len(pms['mass']) - 1] += '\ngroup RO id >= ' + repr(
                            nat) + '\nfix freeze RO setforce 0.0 0.0 0.0\n'
                except KeyError:
                    pms['pair_coeff'][0] += '\ngroup RO id >= ' + repr(
                        nat) + '\nfix freeze RO setforce 0.0 0.0 0.0\n'
                calc = LAMMPS(parameters=pms,
                              files=calc.files,
                              keep_tmp_files=calc.keep_tmp_files,
                              tmp_dir=calc.tmp_dir)
                lmin = copy.copy(Optimizer.lammps_min)
                Optimizer.lammps_min = None
                Optimizer.static_calc = setup_calculator(Optimizer)
                Optimizer.lammps_min = lmin
        else:
            calc = Optimizer.calc
        if Optimizer.structure == 'Defect' or Optimizer.structure == 'Surface':
            totalsol.set_calculator(calc)
            totalsol.set_pbc(True)
        else:
            indiv.set_calculator(calc)
            indiv.set_pbc(
                True)  #Current bug in ASE optimizer-Lammps prevents pbc=false
            if Optimizer.structure == 'Cluster':
                indiv.set_cell([500, 500, 500])
                indiv.translate([250, 250, 250])

        cwd = os.getcwd()
        # Perform Energy Minimization
        if not Optimizer.parallel:
            Optimizer.output.flush()
        if Optimizer.ase_min == True:
            try:
                if Optimizer.structure == 'Defect' or Optimizer.structure == 'Surface':
                    dyn = BFGS(totalsol)
                else:
                    dyn = BFGS(indiv)
                dyn.run(fmax=Optimizer.ase_min_fmax,
                        steps=Optimizer.ase_min_maxsteps)
            except OverflowError:
                STR += '--- Error: Infinite Energy Calculated - Implement Random ---\n'
                box = Atoms()
                indiv = gen_pop_box(Optimizer.natoms, Optimizer.atomlist,
                                    Optimizer.size)
                indiv.set_calculator(calc)
                dyn = BFGS(indiv)
                dyn.run(fmax=fmax, steps=steps)
            except numpy.linalg.linalg.LinAlgError:
                STR += '--- Error: Singular Matrix - Implement Random ---\n'
                indiv = gen_pop_box(Optimizer.natoms, Optimizer.atomlist,
                                    Optimizer.size)
                indiv.set_calculator(calc)
                dyn = BFGS(indiv)
                dyn.run(fmax=fmax, steps=steps)
            # Get Energy of Minimized Structure
            if Optimizer.structure == 'Defect' or Optimizer.structure == 'Surface':
                en = totalsol.get_potential_energy()
                #force=numpy.maximum.reduce(abs(totalsol.get_forces()))
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure = totalsol.get_isotropic_pressure(
                        totalsol.get_stress())
                    cell_max = numpy.maximum.reduce(totalsol.get_positions())
                    cell_min = numpy.minimum.reduce(totalsol.get_positions())
                    cell = cell_max - cell_min
                    volume = cell[0] * cell[1] * cell[2]
                else:
                    pressure = 0
                    volume = 0
                na = totalsol.get_number_of_atoms()
                ena = en / na
                energy = en
                individ[0] = totalsol[0:nat]
                bul = totalsol[(nat):len(totalsol)]
                STR += 'Number of positions = ' + repr(
                    len(bul) + len(individ[0])) + '\n'
                individ[0].set_cell(csize)
                indiv = individ[0]
            else:
                en = indiv.get_potential_energy()
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure = indiv.get_isotropic_pressure(indiv.get_stress())
                    cell_max = numpy.maximum.reduce(indiv.get_positions())
                    cell_min = numpy.minimum.reduce(indiv.get_positions())
                    cell = cell_max - cell_min
                    volume = cell[0] * cell[1] * cell[2]
                else:
                    pressure = 0
                    volume = 0
                na = indiv.get_number_of_atoms()
                ena = en / na
                energy = ena
                individ[0] = indiv
                bul = 0
        else:
            if Optimizer.structure == 'Defect' or Optimizer.structure == 'Surface':
                if Optimizer.calc_method == 'VASP':
                    en = totalsol.get_potential_energy()
                    calcb = Vasp(restart=True)
                    totalsol = calcb.get_atoms()
                    stress = calcb.read_stress()
                else:
                    try:
                        totcop = totalsol.copy()
                        if debug:
                            write_xyz(Optimizer.debugfile, totcop,
                                      'Individual sent to lammps')
                        OUT = totalsol.calc.calculate(totalsol)
                        totalsol = OUT['atoms']
                        totalsol.set_pbc(True)
                        if Optimizer.fixed_region:
                            if debug:
                                print 'Energy of fixed region calc = ', OUT[
                                    'thermo'][-1]['pe']
                            totalsol.set_calculator(Optimizer.static_calc)
                            OUT = totalsol.calc.calculate(totalsol)
                            totalsol = OUT['atoms']
                            totalsol.set_pbc(True)
                            if debug:
                                print 'Energy of static calc = ', OUT[
                                    'thermo'][-1]['pe']
                        en = OUT['thermo'][-1]['pe']
                        stress = numpy.array([
                            OUT['thermo'][-1][i]
                            for i in ('pxx', 'pyy', 'pzz', 'pyz', 'pxz', 'pxy')
                        ]) * (-1e-4 * GPa)
                        #force=numpy.maximum.reduce(abs(totalsol.get_forces()))
                        if debug:
                            write_xyz(Optimizer.debugfile, totalsol,
                                      'After Lammps Minimization')
                            Optimizer.debugfile.flush()
                    except Exception, e:
                        os.chdir(cwd)
                        STR += 'WARNING: Exception during energy eval:\n' + repr(
                            e) + '\n'
                        f = open('problem-structures.xyz', 'a')
                        write_xyz(f,
                                  totcop,
                                  data='Starting structure hindex=' +
                                  individ.history_index)
                        write_xyz(f, totalsol, data='Lammps Min structure')
                        en = 10
                        stress = 0
                        f.close()
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure = totalsol.get_isotropic_pressure(stress)
                    cell_max = numpy.maximum.reduce(totalsol.get_positions())
                    cell_min = numpy.minimum.reduce(totalsol.get_positions())
                    cell = cell_max - cell_min
                    volume = cell[0] * cell[1] * cell[2]
                else:
                    pressure = totalsol.get_isotropic_pressure(stress)
                    volume = 0
                na = totalsol.get_number_of_atoms()
                ena = en / na
                energy = en
                if Optimizer.structure == 'Defect':
                    if Optimizer.fixed_region == True or Optimizer.finddefects == False:
                        individ[0] = totalsol[0:nat]
                        bul = totalsol[(nat):len(totalsol)]
                        individ[0].set_cell(csize)
                    else:
                        if 'FI' in Optimizer.debug:
                            outt = find_defects(
                                totalsol,
                                Optimizer.solidbulk,
                                Optimizer.sf,
                                atomlistcheck=Optimizer.atomlist,
                                trackvacs=Optimizer.trackvacs,
                                trackswaps=Optimizer.trackswaps,
                                debug=Optimizer.debugfile)
                        else:
                            outt = find_defects(
                                totalsol,
                                Optimizer.solidbulk,
                                Optimizer.sf,
                                atomlistcheck=Optimizer.atomlist,
                                trackvacs=Optimizer.trackvacs,
                                trackswaps=Optimizer.trackswaps,
                                debug=False)
                        individ[0] = outt[0]
                        bul = outt[1]
                        individ.vacancies = outt[2]
                        individ.swaps = outt[3]
                        STR += outt[4]
                    indiv = individ[0]
                else:
                    top, bul = find_top_layer(totalsol, Optimizer.surftopthick)
                    indiv = top.copy()
                    individ[0] = top.copy()
            else:
Пример #35
0
class EMT:
    disabled = False  # Set to True to disable (asap does this).
    
    def __init__(self):
        self.energy = None
        if self.disabled:
            print >> sys.stderr, """
            ase.EMT has been disabled by Asap.  Most likely, you
            intended to use Asap's EMT calculator, but accidentally
            imported ase's EMT calculator after Asap's.  This could
            happen if your script contains the lines

              from asap3 import *
              from ase.calculators.emt import EMT
            Swap the two lines to solve the problem.

            (or 'from ase import *' in older versions of ASE.) Swap 
            the two lines to solve the problem.

            In the UNLIKELY event that you actually wanted to use
            ase.calculators.emt.EMT although asap3 is loaded into memory,
            please reactivate it with the command
              ase.calculators.emt.EMT.disabled = False
            """
            raise RuntimeError('ase.EMT has been disabled.  ' +
                               'See message printed above.')
        
    def get_spin_polarized(self):
        return False
    
    def initialize(self, atoms):
        self.par = {}
        self.rc = 0.0
        self.numbers = atoms.get_atomic_numbers()
        maxseq = 0.0
        seen = {}
        for Z in self.numbers:
            if Z not in seen:
                seen[Z] = True
                ss = parameters[chemical_symbols[Z]][1] * Bohr
                if maxseq < ss:
                    maxseq = ss
        rc = self.rc = beta * maxseq * 0.5 * (sqrt(3) + sqrt(4))
        rr = rc * 2 * sqrt(4) / (sqrt(3) + sqrt(4))
        self.acut = np.log(9999.0) / (rr - rc)
        for Z in self.numbers:
            if Z not in self.par:
                p = parameters[chemical_symbols[Z]]
                s0 = p[1] * Bohr
                eta2 = p[3] / Bohr
                kappa = p[4] / Bohr
                x = eta2 * beta * s0
                gamma1 = 0.0
                gamma2 = 0.0
                for i, n in enumerate([12, 6, 24]):
                    r = s0 * beta * sqrt(i + 1)
                    x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
                    gamma1 += x * exp(-eta2 * (r - beta * s0))
                    gamma2 += x * exp(-kappa / beta * (r - beta * s0))

                self.par[Z] = {'E0': p[0],
                               's0': s0,
                               'V0': p[2],
                               'eta2': eta2,
                               'kappa': kappa,
                               'lambda': p[5] / Bohr,
                               'n0': p[6] / Bohr**3,
                               'rc': rc,
                               'gamma1': gamma1,
                               'gamma2': gamma2}
                #if rc + 0.5 > self.rc:
                #    self.rc = rc + 0.5

        self.ksi = {}
        for s1, p1 in self.par.items():
            self.ksi[s1] = {}
            for s2, p2 in self.par.items():
                #self.ksi[s1][s2] = (p2['n0'] / p1['n0'] *
                #                    exp(eta1 * (p1['s0'] - p2['s0'])))
                self.ksi[s1][s2] = p2['n0'] / p1['n0']
                
        self.forces = np.empty((len(atoms), 3))
        self.sigma1 = np.empty(len(atoms))
        self.deds = np.empty(len(atoms))
                    
        self.nl = NeighborList([0.5 * self.rc + 0.25] * len(atoms),
                               self_interaction=False)

    def update(self, atoms):
        if (self.energy is None or
            len(self.numbers) != len(atoms) or
            (self.numbers != atoms.get_atomic_numbers()).any()):
            self.initialize(atoms)
            self.calculate(atoms)
        elif ((self.positions != atoms.get_positions()).any() or
              (self.pbc != atoms.get_pbc()).any() or
              (self.cell != atoms.get_cell()).any()):
            self.calculate(atoms)

    def calculation_required(self, atoms, quantities):
        if len(quantities) == 0:
            return False

        return (self.energy is None or
                len(self.numbers) != len(atoms) or
                (self.numbers != atoms.get_atomic_numbers()).any() or
                (self.positions != atoms.get_positions()).any() or
                (self.pbc != atoms.get_pbc()).any() or
                (self.cell != atoms.get_cell()).any())
                
    def get_potential_energy(self, atoms):
        self.update(atoms)
        return self.energy

    def get_numeric_forces(self, atoms):
        self.update(atoms)
        p = atoms.positions
        p0 = p.copy()
        forces = np.empty_like(p)
        eps = 0.0001
        for a in range(len(p)):
            for c in range(3):
                p[a, c] += eps
                self.calculate(atoms)
                de = self.energy
                p[a, c] -= 2 * eps
                self.calculate(atoms)
                de -= self.energy
                p[a, c] += eps
                forces[a, c] = -de / (2 * eps)
        p[:] = p0
        return forces

    def get_forces(self, atoms):
        self.update(atoms)
        return self.forces.copy()
    
    def get_stress(self, atoms):
        raise NotImplementedError
    
    def calculate(self, atoms):
        self.positions = atoms.get_positions().copy()
        self.cell = atoms.get_cell().copy()
        self.pbc = atoms.get_pbc().copy()
        
        self.nl.update(atoms)
        
        self.energy = 0.0
        self.sigma1[:] = 0.0
        self.forces[:] = 0.0
        
        natoms = len(atoms)

        for a1 in range(natoms):
            Z1 = self.numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, atoms.cell)
            for a2, offset in zip(neighbors, offsets):
                d = self.positions[a2] + offset - self.positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = self.numbers[a2]
                    p2 = self.par[Z2]
                    self.interact1(a1, a2, d, r, p1, p2, ksi[Z2])
                                
        for a in range(natoms):
            Z = self.numbers[a]
            p = self.par[Z]
            try:
                ds = -log(self.sigma1[a] / 12) / (beta * p['eta2'])
            except (OverflowError, ValueError):
                self.deds[a] = 0.0
                self.energy -= p['E0']
                continue
            x = p['lambda'] * ds
            y = exp(-x)
            z = 6 * p['V0'] * exp(-p['kappa'] * ds)
            self.deds[a] = ((x * y * p['E0'] * p['lambda'] + p['kappa'] * z) /
                            (self.sigma1[a] * beta * p['eta2']))
            e = p['E0'] * ((1 + x) * y - 1) + z
            self.energy += p['E0'] * ((1 + x) * y - 1) + z

        for a1 in range(natoms):
            Z1 = self.numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, atoms.cell)
            for a2, offset in zip(neighbors, offsets):
                d = self.positions[a2] + offset - self.positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = self.numbers[a2]
                    p2 = self.par[Z2]
                    self.interact2(a1, a2, d, r, p1, p2, ksi[Z2])

    def interact1(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (0.5 * p1['V0'] * exp(-p2['kappa'] * (r / beta - p2['s0'])) *
              ksi / p1['gamma2'] * theta)
        y2 = (0.5 * p2['V0'] * exp(-p1['kappa'] * (r / beta - p1['s0'])) /
              ksi / p2['gamma2'] * theta)
        self.energy -= y1 + y2
        f = ((y1 * p2['kappa'] + y2 * p1['kappa']) / beta +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] += f
        self.forces[a2] -= f
        self.sigma1[a1] += (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
                            ksi * theta / p1['gamma1'])
        self.sigma1[a2] += (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
                            ksi * theta / p2['gamma1'])

    def interact2(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
              ksi / p1['gamma1'] * theta * self.deds[a1])
        y2 = (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
              ksi / p2['gamma1'] * theta * self.deds[a2])
        f = ((y1 * p2['eta2'] + y2 * p1['eta2']) +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] -= f
        self.forces[a2] += f

    def set_atoms(self,*args,**kwargs):
        'empty function for compatibility with other calculators and tests'
        pass
Пример #36
0
def eval_energy(input):
    """Function to evaluate energy of an individual
    Inputs:
        input = [Optimizer class object with parameters, Individual class structure to be evaluated]
    Outputs:
        energy, bul, individ, signal
        energy = energy of Individual evaluated
        bul = bulk structure of Individual if simulation structure is Defect
        individ = Individual class structure evaluated
        signal = string of information about evaluation
    """
    if input[0]==None:
        energy=0
        bul=0
        individ=0
        rank = MPI.COMM_WORLD.Get_rank()
        signal='Evaluated none individual on '+repr(rank)+'\n'
    else:
        [Optimizer, individ]=input
    if Optimizer.calc_method=='MAST':
        energy = individ.energy
        bul = individ.energy
        signal = 'Recieved MAST structure\n'
    else:
        if Optimizer.parallel: rank = MPI.COMM_WORLD.Get_rank()
        if not Optimizer.genealogy:
            STR='----Individual ' + str(individ.index)+ ' Optimization----\n'
        else:
            STR='----Individual ' + str(individ.history_index)+ ' Optimization----\n'
        indiv=individ[0]
        if 'EE' in Optimizer.debug:
            debug = True
        else:
            debug = False
        if debug: 
            write_xyz(Optimizer.debugfile,indiv,'Recieved by eval_energy')
            Optimizer.debugfile.flush()
        if Optimizer.structure=='Defect':
            indi=indiv.copy()
            if Optimizer.alloy==True:
                bulk=individ.bulki
            else:
                bulk=individ.bulko
            nat=indi.get_number_of_atoms()
            csize=bulk.get_cell()                                                                                                         
            totalsol=Atoms(cell=csize, pbc=True)
            totalsol.extend(indi)
            totalsol.extend(bulk)
            for sym,c,m,u in Optimizer.atomlist:
                nc=len([atm for atm in totalsol if atm.symbol==sym])
                STR+='Defect configuration contains '+repr(nc)+' '+repr(sym)+' atoms\n'
    
        elif Optimizer.structure=='Surface':
            totalsol=Atoms()
            totalsol.extend(indiv)
            nat=indiv.get_number_of_atoms()
            totalsol.extend(individ.bulki)
            for sym,c,m,u in Optimizer.atomlist:
                nc=len([atm for atm in totalsol if atm.symbol==sym])
                STR+='Surface-Bulk configuration contains '+repr(nc)+' '+repr(sym)+' atoms\n'
            cell=numpy.maximum.reduce(indiv.get_cell())
            totalsol.set_cell([cell[0],cell[1],500])
            totalsol.set_pbc([True,True,False])
    
        if Optimizer.constrain_position:
            ts = totalsol.copy()
            indc,indb,vacant,swap,stro = find_defects(ts,Optimizer.solidbulk,0)
            sbulk = Optimizer.solidbulk.copy()
            bcom = sbulk.get_center_of_mass()
            #totalsol.translate(-bulkcom)
            #indc.translate(-bulkcom)
            #totalsol.append(Atom(position=[0,0,0]))
    # 			for one in indc:
    # 				index = [atm.index for atm in totalsol if atm.position[0]==one.position[0] and atm.position[1]==one.position[1] and atm.position[2]==one.position[2]][0]
    # 				if totalsol.get_distance(-1,index) > Optimizer.sf:
    # 					r = random.random()
    # 					totalsol.set_distance(-1,index,Optimizer.sf*r,fix=0)
    # 			totalsol.pop()
    # 			totalsol.translate(bulkcom)
            com = indc.get_center_of_mass()
            dist = (sum((bcom[i] - com[i])**2 for i in range(3)))**0.5
            if dist > Optimizer.sf:
                STR+='Shifting structure to within region\n'
                r = random.random()*Optimizer.sf
                comv = numpy.linalg.norm(com)
                ncom = [one*r/comv for one in com]
                trans = [ncom[i]-com[i] for i in range(3)]
                indices = []
                for one in indc:
                    id = [atm.index for atm in totalsol if atm.position[0]==one.position[0] and atm.position[1]==one.position[1] and atm.position[2]==one.position[2]][0]
                    totalsol[id].position += trans
    
        # Check for atoms that are too close
        min_len=0.7
        #pdb.set_trace()
        if not Optimizer.fixed_region:
            if Optimizer.structure=='Defect' or Optimizer.structure=='Surface':
                cutoffs=[2.0 for one in totalsol]
                nl=NeighborList(cutoffs,bothways=True,self_interaction=False)
                nl.update(totalsol)
                for one in totalsol[0:nat]:
                    nbatoms=Atoms()
                    nbatoms.append(one)
                    indices, offsets=nl.get_neighbors(one.index)
                    for index, d in zip(indices,offsets):
                        index = int(index)
                        sym=totalsol[index].symbol
                        pos=totalsol[index].position + numpy.dot(d,totalsol.get_cell())
                        at=Atom(symbol=sym,position=pos)
                        nbatoms.append(at)
                    while True:
                        dflag=False
                        for i in range(1,len(nbatoms)):
                            d=nbatoms.get_distance(0,i)
                            if d < min_len:
                                nbatoms.set_distance(0,i,min_len+.01,fix=0.5)
                                STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                                dflag=True
                        if dflag==False:
                            break
                    for i in range(len(indices)):
                        totalsol[indices[i]].position=nbatoms[i+1].position
                    totalsol[one.index].position=nbatoms[0].position
                    nl.update(totalsol)
                if debug:
                    write_xyz(Optimizer.debugfile,totalsol,'After minlength check')
                    Optimizer.debugfile.flush()
            else:
                for i in range(len(indiv)):
                    for j in range(len(indiv)):
                        if i != j:
                            d=indiv.get_distance(i,j)
                            if d < min_len:
                                indiv.set_distance(i,j,min_len,fix=0.5)
                                STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                if debug:
                    write_xyz(Optimizer.debugfile,indiv,'After minlength check')
                    Optimizer.debugfile.flush()
    
        # Set calculator to use to get forces/energies
        if Optimizer.parallel:
            calc = setup_calculator(Optimizer)
            if Optimizer.fixed_region:
                pms=copy.deepcopy(calc.parameters)
                try:
                    pms['mass'][len(pms['mass'])-1] += '\ngroup RO id >= '+repr(nat)+'\nfix freeze RO setforce 0.0 0.0 0.0\n'
                except KeyError:
                    pms['pair_coeff'][0] += '\ngroup RO id >= '+repr(nat)+'\nfix freeze RO setforce 0.0 0.0 0.0\n'
                calc = LAMMPS(parameters=pms, files=calc.files, keep_tmp_files=calc.keep_tmp_files, tmp_dir=calc.tmp_dir)
                lmin = copy.copy(Optimizer.lammps_min)
                Optimizer.lammps_min = None
                Optimizer.static_calc = setup_calculator(Optimizer)
                Optimizer.lammps_min = lmin
        else:
            calc=Optimizer.calc
        if Optimizer.structure=='Defect' or Optimizer.structure=='Surface':
            totalsol.set_calculator(calc)
            totalsol.set_pbc(True)
        else:
            indiv.set_calculator(calc)
            indiv.set_pbc(True)	#Current bug in ASE optimizer-Lammps prevents pbc=false 
            if Optimizer.structure=='Cluster':
                indiv.set_cell([500,500,500])
                indiv.translate([250,250,250])
    
        cwd=os.getcwd()
        # Perform Energy Minimization
        if not Optimizer.parallel:
            Optimizer.output.flush()
        if Optimizer.ase_min == True:
            try:
                if Optimizer.structure=='Defect' or Optimizer.structure=='Surface':
                    dyn=BFGS(totalsol)
                else:
                    dyn=BFGS(indiv)
                dyn.run(fmax=Optimizer.ase_min_fmax, steps=Optimizer.ase_min_maxsteps)
            except OverflowError:
                STR+='--- Error: Infinite Energy Calculated - Implement Random ---\n'
                box=Atoms()
                indiv=gen_pop_box(Optimizer.natoms, Optimizer.atomlist, Optimizer.size)
                indiv.set_calculator(calc)
                dyn=BFGS(indiv)
                dyn.run(fmax=fmax, steps=steps)
            except numpy.linalg.linalg.LinAlgError:
                STR+='--- Error: Singular Matrix - Implement Random ---\n'
                indiv=gen_pop_box(Optimizer.natoms, Optimizer.atomlist, Optimizer.size)
                indiv.set_calculator(calc)
                dyn=BFGS(indiv)
                dyn.run(fmax=fmax, steps=steps)
            # Get Energy of Minimized Structure
            if Optimizer.structure=='Defect' or Optimizer.structure=='Surface':
                en=totalsol.get_potential_energy()
                #force=numpy.maximum.reduce(abs(totalsol.get_forces()))
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure=totalsol.get_isotropic_pressure(totalsol.get_stress())
                    cell_max=numpy.maximum.reduce(totalsol.get_positions())
                    cell_min=numpy.minimum.reduce(totalsol.get_positions())
                    cell=cell_max-cell_min
                    volume=cell[0]*cell[1]*cell[2]
                else:
                    pressure=0
                    volume=0
                na=totalsol.get_number_of_atoms()
                ena=en/na
                energy=en
                individ[0]=totalsol[0:nat]
                bul=totalsol[(nat):len(totalsol)]
                STR+='Number of positions = '+repr(len(bul)+len(individ[0]))+'\n'
                individ[0].set_cell(csize)
                indiv=individ[0]
            else:
                en=indiv.get_potential_energy()
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure=indiv.get_isotropic_pressure(indiv.get_stress())
                    cell_max=numpy.maximum.reduce(indiv.get_positions())
                    cell_min=numpy.minimum.reduce(indiv.get_positions())
                    cell=cell_max-cell_min
                    volume=cell[0]*cell[1]*cell[2]
                else: 
                    pressure=0
                    volume=0
                na=indiv.get_number_of_atoms()
                ena=en/na
                energy=ena
                individ[0]=indiv
                bul=0
        else:
            if Optimizer.structure=='Defect' or Optimizer.structure=='Surface':
                if Optimizer.calc_method=='VASP':
                    en=totalsol.get_potential_energy()
                    calcb=Vasp(restart=True)
                    totalsol=calcb.get_atoms()
                    stress=calcb.read_stress()
                else:
                    try:
                        totcop=totalsol.copy()
                        if debug: write_xyz(Optimizer.debugfile,totcop,'Individual sent to lammps')
                        OUT=totalsol.calc.calculate(totalsol)
                        totalsol=OUT['atoms']
                        totalsol.set_pbc(True)
                        if Optimizer.fixed_region:
                            if debug:
                                print 'Energy of fixed region calc = ', OUT['thermo'][-1]['pe']
                            totalsol.set_calculator(Optimizer.static_calc)
                            OUT=totalsol.calc.calculate(totalsol)
                            totalsol=OUT['atoms']
                            totalsol.set_pbc(True)
                            if debug:
                                print 'Energy of static calc = ', OUT['thermo'][-1]['pe']
                        en=OUT['thermo'][-1]['pe']
                        stress=numpy.array([OUT['thermo'][-1][i] for i in ('pxx','pyy','pzz','pyz','pxz','pxy')])*(-1e-4*GPa)
                        #force=numpy.maximum.reduce(abs(totalsol.get_forces()))
                        if debug:
                            write_xyz(Optimizer.debugfile,totalsol,'After Lammps Minimization')
                            Optimizer.debugfile.flush()
                    except Exception, e:
                        os.chdir(cwd)
                        STR+='WARNING: Exception during energy eval:\n'+repr(e)+'\n'
                        f=open('problem-structures.xyz','a')
                        write_xyz(f,totcop,data='Starting structure hindex='+individ.history_index)
                        write_xyz(f,totalsol,data='Lammps Min structure')
                        en=10
                        stress=0
                        f.close()
                if Optimizer.fitness_scheme == 'enthalpyfit':
                    pressure=totalsol.get_isotropic_pressure(stress)
                    cell_max=numpy.maximum.reduce(totalsol.get_positions())
                    cell_min=numpy.minimum.reduce(totalsol.get_positions())
                    cell=cell_max-cell_min
                    volume=cell[0]*cell[1]*cell[2]
                else:
                    pressure=totalsol.get_isotropic_pressure(stress)
                    volume=0
                na=totalsol.get_number_of_atoms()
                ena=en/na
                energy=en
                if Optimizer.structure=='Defect':
                    if Optimizer.fixed_region==True or Optimizer.finddefects==False:
                        individ[0]=totalsol[0:nat]
                        bul=totalsol[(nat):len(totalsol)]
                        individ[0].set_cell(csize)
                    else:
                        if 'FI' in Optimizer.debug:
                            outt=find_defects(totalsol,Optimizer.solidbulk,Optimizer.sf,atomlistcheck=Optimizer.atomlist,trackvacs=Optimizer.trackvacs,trackswaps=Optimizer.trackswaps,debug=Optimizer.debugfile)
                        else:
                            outt=find_defects(totalsol,Optimizer.solidbulk,Optimizer.sf,atomlistcheck=Optimizer.atomlist,trackvacs=Optimizer.trackvacs,trackswaps=Optimizer.trackswaps,debug=False)
                        individ[0]=outt[0]
                        bul=outt[1]
                        individ.vacancies = outt[2]
                        individ.swaps = outt[3]
                        STR += outt[4]
                    indiv=individ[0]
                else:
                    top,bul=find_top_layer(totalsol,Optimizer.surftopthick)
                    indiv=top.copy()
                    individ[0]=top.copy()
            else:
Пример #37
0
class EAM(Calculator):
    r"""

    EAM Interface Documentation

Introduction
============

The Embedded Atom Method (EAM) [1]_ is a classical potential which is
good for modelling metals, particularly fcc materials. Because it is
an equiaxial potential the EAM does not model directional bonds
well. However, the Angular Dependent Potential (ADP) [2]_ which is an
extended version of EAM is able to model directional bonds and is also
included in the EAM calculator.

Generally all that is required to use this calculator is to supply a
potential file or as a set of functions that describe the potential.
The files containing the potentials for this calculator are not
included but many suitable potentials can be downloaded from The
Interatomic Potentials Repository Project at
http://www.ctcms.nist.gov/potentials/

Theory
======

A single element EAM potential is defined by three functions: the
embedded energy, electron density and the pair potential.  A two
element alloy contains the individual three functions for each element
plus cross pair interactions.  The ADP potential has two additional
sets of data to define the dipole and quadrupole directional terms for
each alloy and their cross interactions.

The total energy `E_{\rm tot}` of an arbitrary arrangement of atoms is
given by the EAM potential as

.. math::
   E_{\rm tot} = \sum_i F(\bar\rho_i) + \frac{1}{2}\sum_{i\ne j} \phi(r_{ij})

and

.. math::
   \bar\rho_i = \sum_j \rho(r_{ij})

where `F` is an embedding function, namely the energy to embed an atom `i` in
the combined electron density `\bar\rho_i` which is contributed from
each of its neighbouring atoms `j` by an amount `\rho(r_{ij})`,
`\phi(r_{ij})` is the pair potential function representing the energy
in bond `ij` which is due to the short-range electro-static
interaction between atoms, and `r_{ij}` is the distance between an
atom and its neighbour for that bond.

The ADP potential is defined as

.. math::
   E_{\rm tot} = \sum_i F(\bar\rho_i) + \frac{1}{2}\sum_{i\ne j} \phi(r_{ij})
   + {1\over 2} \sum_{i,\alpha} (\mu_i^\alpha)^2
   + {1\over 2} \sum_{i,\alpha,\beta} (\lambda_i^{\alpha\beta})^2
   - {1 \over 6} \sum_i \nu_i^2

where `\mu_i^\alpha` is the dipole vector, `\lambda_i^{\alpha\beta}`
is the quadrupole tensor and `\nu_i` is the trace of
`\lambda_i^{\alpha\beta}`.

Running the Calculator
======================

EAM calculates the cohesive atom energy and forces. Internally the
potential functions are defined by splines which may be directly
supplied or created by reading the spline points from a data file from
which a spline function is created.  The LAMMPS compatible ``.alloy``
and ``.adp`` formats are supported. The LAMMPS ``.eam`` format is
slightly different from the ``.alloy`` format and is currently not
supported.

For example::

    from ase.calculators.eam import EAM

    mishin = EAM(potential='Al99.eam.alloy')
    mishin.write_potential('new.eam.alloy')
    mishin.plot()

    slab.set_calculator(mishin)
    slab.get_potential_energy()
    slab.get_forces()

The breakdown of energy contribution from the indvidual components are
stored in the calculator instance ``.results['energy_components']``

Arguments
=========

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``potential``              file of potential in ``.alloy`` or ``.adp`` format
                           (This is generally all you need to supply)

``elements[N]``            array of N element abbreviations

``embedded_energy[N]``     arrays of embedded energy functions

``electron_density[N]``    arrays of electron density functions

``phi[N,N]``               arrays of pair potential functions

``d_embedded_energy[N]``   arrays of derivative embedded energy functions

``d_electron_density[N]``  arrays of derivative electron density functions

``d_phi[N,N]``             arrays of derivative pair potentials functions

``d[N,N], q[N,N]``         ADP dipole and quadrupole function

``d_d[N,N], d_q[N,N]``     ADP dipole and quadrupole derivative functions

``skin``                   skin distance passed to NeighborList(). If no atom
                           has moved more than the skin-distance since the last
                           call to the ``update()`` method then the neighbor
                           list can be reused. Defaults to 1.0.

``form``                   the form of the potential ``alloy`` or ``adp``. This
                           will be determined from the file suffix or must be
                           set if using equations

=========================  ====================================================


Additional parameters for writing potential files
=================================================

The following parameters are only required for writing a potential in
``.alloy`` or ``.adp`` format file.

=========================  ====================================================
Keyword                    Description
=========================  ====================================================
``header``                 Three line text header. Default is standard message.

``Z[N]``                   Array of atomic number of each element

``mass[N]``                Atomic mass of each element

``a[N]``                   Array of lattice parameters for each element

``lattice[N]``             Lattice type

``nrho``                   No. of rho samples along embedded energy curve

``drho``                   Increment for sampling density

``nr``                     No. of radial points along density and pair
                           potential curves

``dr``                     Increment for sampling radius

=========================  ====================================================

Special features
================

``.plot()``
  Plots the individual functions. This may be called from multiple EAM
  potentials to compare the shape of the individual curves. This
  function requires the installation of the Matplotlib libraries.

Notes/Issues
=============

* Although currently not fast, this calculator can be good for trying
  small calculations or for creating new potentials by matching baseline
  data such as from DFT results. The format for these potentials is
  compatible with LAMMPS_ and so can be used either directly by LAMMPS or
  with the ASE LAMMPS calculator interface.

* Supported formats are the LAMMPS_ ``.alloy`` and ``.adp``. The
  ``.eam`` format is currently not supported. The form of the
  potential will be determined from the file suffix.

* Any supplied values will override values read from the file.

* The derivative functions, if supplied, are only used to calculate
  forces.

* There is a bug in early versions of scipy that will cause eam.py to
  crash when trying to evaluate splines of a potential with one
  neighbor such as caused by evaluating a dimer.

.. _LAMMPS: http://lammps.sandia.gov/

.. [1] M.S. Daw and M.I. Baskes, Phys. Rev. Letters 50 (1983)
       1285.

.. [2] Y. Mishin, M.J. Mehl, and D.A. Papaconstantopoulos,
       Acta Materialia 53 2005 4029--4041.


End EAM Interface Documentation
    """

    implemented_properties = ["energy", "forces"]

    default_parameters = dict(
        skin=1.0, potential=None, header="""EAM/ADP potential file\nGenerated from eam.py\nblank\n"""
    )

    def __init__(self, restart=None, ignore_bad_restart_file=False, label=os.curdir, atoms=None, **kwargs):

        if "potential" in kwargs:
            self.read_potential(kwargs["potential"])

        Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs)

        valid_args = (
            "potential",
            "elements",
            "header",
            "drho",
            "dr",
            "cutoff",
            "atomic_number",
            "mass",
            "a",
            "lattice",
            "embedded_energy",
            "electron_density",
            "phi",
            # derivatives
            "d_embedded_energy",
            "d_electron_density",
            "d_phi",
            "d",
            "q",
            "d_d",
            "d_q",  # adp terms
            "skin",
            "form",
            "Z",
            "nr",
            "nrho",
            "mass",
        )

        # set any additional keyword arguments
        for arg, val in self.parameters.iteritems():
            if arg in valid_args:
                setattr(self, arg, val)
            else:
                raise RuntimeError('unknown keyword arg "%s" : not in %s' % (arg, valid_args))

    def set_form(self, fileobj):
        """set the form variable based on the file name suffix"""
        extension = os.path.splitext(fileobj)[1]

        if extension == ".eam":
            self.form = "eam"
            raise NotImplementedError
        elif extension == ".alloy":
            self.form = "alloy"
        elif extension == ".adp":
            self.form = "adp"
        else:
            raise RuntimeError("unknown file extension type: %s" % extension)

    def read_potential(self, fileobj):
        """Reads a LAMMPS EAM file in alloy or adp format
        and creates the interpolation functions from the data
        """

        if isinstance(fileobj, str):
            f = open(fileobj)
            self.set_form(fileobj)
        else:
            f = fileobj

        lines = f.readlines()
        self.header = lines[:3]
        i = 3

        # make the data one long line so as not to care how its formatted
        data = []
        for line in lines[i:]:
            data.extend(line.split())

        self.Nelements = int(data[0])
        d = 1
        self.elements = data[d : (d + self.Nelements)]
        d += self.Nelements

        self.nrho = int(data[d])
        self.drho = float(data[d + 1])
        self.nr = int(data[d + 2])
        self.dr = float(data[d + 3])
        self.cutoff = float(data[d + 4])

        self.embedded_data = np.zeros([self.Nelements, self.nrho])
        self.density_data = np.zeros([self.Nelements, self.nr])
        self.Z = np.zeros([self.Nelements], dtype=int)
        self.mass = np.zeros([self.Nelements])
        self.a = np.zeros([self.Nelements])
        self.lattice = []
        d += 5

        # reads in the part of the eam file for each element
        for elem in range(self.Nelements):
            self.Z[elem] = int(data[d])
            self.mass[elem] = float(data[d + 1])
            self.a[elem] = float(data[d + 2])
            self.lattice.append(data[d + 3])
            d += 4

            self.embedded_data[elem] = np.float_(data[d : (d + self.nrho)])
            d += self.nrho
            self.density_data[elem] = np.float_(data[d : (d + self.nr)])
            d += self.nr

        # reads in the r*phi data for each interaction between elements
        self.rphi_data = np.zeros([self.Nelements, self.Nelements, self.nr])

        for i in range(self.Nelements):
            for j in range(i + 1):
                self.rphi_data[j, i] = np.float_(data[d : (d + self.nr)])
                d += self.nr

        self.r = np.arange(0, self.nr) * self.dr
        self.rho = np.arange(0, self.nrho) * self.drho

        self.set_splines()

        if self.form == "adp":
            self.read_adp_data(data, d)
            self.set_adp_splines()

    def set_splines(self):
        # this section turns the file data into three functions (and
        # derivative functions) that define the potential
        self.embedded_energy = np.empty(self.Nelements, object)
        self.electron_density = np.empty(self.Nelements, object)
        self.d_embedded_energy = np.empty(self.Nelements, object)
        self.d_electron_density = np.empty(self.Nelements, object)

        for i in range(self.Nelements):
            self.embedded_energy[i] = spline(self.rho, self.embedded_data[i], k=3)
            self.electron_density[i] = spline(self.r, self.density_data[i], k=3)
            self.d_embedded_energy[i] = self.deriv(self.embedded_energy[i])
            self.d_electron_density[i] = self.deriv(self.electron_density[i])

        self.phi = np.empty([self.Nelements, self.Nelements], object)
        self.d_phi = np.empty([self.Nelements, self.Nelements], object)

        # ignore the first point of the phi data because it is forced
        # to go through zero due to the r*phi format in alloy and adp
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                if self.form == "eam":  # not stored as rphi
                    # should we ignore the first point for eam ?
                    raise RuntimeError(".eam format not yet supported")

                    self.phi[i, j] = spline(self.r[1:], self.rphi_data[i, j][1:], k=3)
                else:
                    self.phi[i, j] = spline(self.r[1:], self.rphi_data[i, j][1:] / self.r[1:], k=3)

                self.d_phi[i, j] = self.deriv(self.phi[i, j])

                if j != i:
                    self.phi[j, i] = self.phi[i, j]
                    self.d_phi[j, i] = self.d_phi[i, j]

    def set_adp_splines(self):
        self.d = np.empty([self.Nelements, self.Nelements], object)
        self.d_d = np.empty([self.Nelements, self.Nelements], object)
        self.q = np.empty([self.Nelements, self.Nelements], object)
        self.d_q = np.empty([self.Nelements, self.Nelements], object)

        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                self.d[i, j] = spline(self.r[1:], self.d_data[i, j][1:], k=3)
                self.d_d[i, j] = self.deriv(self.d[i, j])
                self.q[i, j] = spline(self.r[1:], self.q_data[i, j][1:], k=3)
                self.d_q[i, j] = self.deriv(self.q[i, j])

                # make symmetrical
                if j != i:
                    self.d[j, i] = self.d[i, j]
                    self.d_d[j, i] = self.d_d[i, j]
                    self.q[j, i] = self.q[i, j]
                    self.d_q[j, i] = self.d_q[i, j]

    def read_adp_data(self, data, d):
        """read in the extra adp data from the potential file"""

        self.d_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i + 1):
                self.d_data[j, i] = data[d : d + self.nr]
                d += self.nr

        self.q_data = np.zeros([self.Nelements, self.Nelements, self.nr])
        # should be non symetrical combinations of 2
        for i in range(self.Nelements):
            for j in range(i + 1):
                self.q_data[j, i] = data[d : d + self.nr]
                d += self.nr

    def write_potential(self, filename, nc=1, numformat="%.8e"):
        """Writes out the potential in the format given by the form
        variable to 'filename' with a data format that is nc columns
        wide.  Note: array lengths need to be an exact multiple of nc
        """

        f = open(filename, "w")

        assert self.nr % nc == 0
        assert self.nrho % nc == 0

        for line in self.header:
            f.write(line)

        f.write("%d " % self.Nelements)
        for i in range(self.Nelements):
            f.write("%s " % str(self.elements[i]))
        f.write("\n")

        f.write("%d %f %d %f %f \n" % (self.nrho, self.drho, self.nr, self.dr, self.cutoff))

        # start of each section for each element
        #        rs = np.linspace(0, self.nr * self.dr, self.nr)
        #        rhos = np.linspace(0, self.nrho * self.drho, self.nrho)

        rs = np.arange(0, self.nr) * self.dr
        rhos = np.arange(0, self.nrho) * self.drho

        for i in range(self.Nelements):
            f.write("%d %f %f %s\n" % (self.Z[i], self.mass[i], self.a[i], str(self.lattice[i])))
            np.savetxt(f, self.embedded_energy[i](rhos).reshape(self.nrho / nc, nc), fmt=nc * [numformat])
            np.savetxt(f, self.electron_density[i](rs).reshape(self.nr / nc, nc), fmt=nc * [numformat])

        # write out the pair potentials in Lammps DYNAMO setfl format
        # as r*phi for alloy format
        for i in range(self.Nelements):
            for j in range(i, self.Nelements):
                np.savetxt(f, (rs * self.phi[i, j](rs)).reshape(self.nr / nc, nc), fmt=nc * [numformat])

        if self.form == "adp":
            # these are the u(r) or dipole values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.d_data[i, j])

            # these are the w(r) or quadrupole values
            for i in range(self.Nelements):
                for j in range(i + 1):
                    np.savetxt(f, self.q_data[i, j])

        f.close()

    def update(self, atoms):
        # check all the elements are available in the potential
        self.Nelements = len(self.elements)
        elements = np.unique(atoms.get_chemical_symbols())
        unavailable = np.logical_not(np.array([item in self.elements for item in elements]))

        if np.any(unavailable):
            raise RuntimeError("These elements are not in the potential: %s" % elements[unavailable])

        # cutoffs need to be a vector for NeighborList
        cutoffs = self.cutoff * np.ones(len(atoms))

        # convert the elements to an index of the position
        # in the eam format
        self.index = np.array([self.elements.index(el) for el in atoms.get_chemical_symbols()])
        self.pbc = atoms.get_pbc()

        # since we need the contribution of all neighbors to the
        # local electron density we cannot just calculate and use
        # one way neighbors
        self.neighbors = NeighborList(cutoffs, skin=self.parameters.skin, self_interaction=False, bothways=True)
        self.neighbors.update(atoms)

    def calculate(self, atoms=None, properties=["energy"], system_changes=all_changes):
        """EAM Calculator

        atoms: Atoms object
            Contains positions, unit-cell, ...
        properties: list of str
            List of what needs to be calculated.  Can be any combination
            of 'energy', 'forces'
        system_changes: list of str
            List of what has changed since last calculation.  Can be
            any combination of these five: 'positions', 'numbers', 'cell',
            'pbc', 'initial_charges' and 'initial_magmoms'.
            """

        Calculator.calculate(self, atoms, properties, system_changes)

        # we shouldn't really recalc if charges or magmos change
        if len(system_changes) > 0:  # something wrong with this way
            self.update(self.atoms)
            self.calculate_energy(self.atoms)

            if "forces" in properties:
                self.calculate_forces(self.atoms)

        # check we have all the properties requested
        for property in properties:
            if property not in self.results:
                if property is "energy":
                    self.calculate_energy(self.atoms)

                if property is "forces":
                    self.calculate_forces(self.atoms)

        # we need to remember the previous state of parameters

    #        if 'potential' in parameter_changes and potential != None:
    #                self.read_potential(potential)

    def calculate_energy(self, atoms):
        """Calculate the energy
        the energy is made up of the ionic or pair interaction and
        the embedding energy of each atom into the electron cloud
        generated by its neighbors
        """

        pair_energy = 0.0
        embedding_energy = 0.0
        mu_energy = 0.0
        lam_energy = 0.0
        trace_energy = 0.0

        self.total_density = np.zeros(len(atoms))
        if self.form == "adp":
            self.mu = np.zeros([len(atoms), 3])
            self.lam = np.zeros([len(atoms), 3, 3])

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())

            rvec = atoms.positions[neighbors] + offset - atoms.positions[i]

            ## calculate the distance to the nearest neighbors
            r = np.sqrt(np.sum(np.square(rvec), axis=1))  # fast
            #            r = np.apply_along_axis(np.linalg.norm, 1, rvec)  # sloow

            nearest = np.arange(len(r))[r <= self.cutoff]
            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                pair_energy += np.sum(self.phi[self.index[i], j_index](r[nearest][use])) / 2.0

                density = np.sum(self.electron_density[j_index](r[nearest][use]))
                self.total_density[i] += density

                if self.form == "adp":
                    self.mu[i] += self.adp_dipole(r[nearest][use], rvec[nearest][use], self.d[self.index[i], j_index])

                    self.lam[i] += self.adp_quadrupole(
                        r[nearest][use], rvec[nearest][use], self.q[self.index[i], j_index]
                    )

            # add in the electron embedding energy
            embedding_energy += self.embedded_energy[self.index[i]](self.total_density[i])

        components = dict(pair=pair_energy, embedding=embedding_energy)

        if self.form == "adp":
            mu_energy += np.sum(self.mu ** 2) / 2.0
            lam_energy += np.sum(self.lam ** 2) / 2.0

            for i in range(len(atoms)):  # this is the atom to be embedded
                trace_energy -= np.sum(self.lam[i].trace() ** 2) / 6.0

            adp_result = dict(adp_mu=mu_energy, adp_lam=lam_energy, adp_trace=trace_energy)
            components.update(adp_result)

        self.positions = atoms.positions.copy()
        self.cell = atoms.get_cell().copy()

        energy = 0.0
        for i in components.keys():
            energy += components[i]

        self.energy_free = energy
        self.energy_zero = energy

        self.results["energy_components"] = components
        self.results["energy"] = energy

    def calculate_forces(self, atoms):
        # calculate the forces based on derivatives of the three EAM functions

        self.update(atoms)
        self.results["forces"] = np.zeros((len(atoms), 3))

        for i in range(len(atoms)):  # this is the atom to be embedded
            neighbors, offsets = self.neighbors.get_neighbors(i)
            offset = np.dot(offsets, atoms.get_cell())
            # create a vector of relative positions of neighbors
            rvec = atoms.positions[neighbors] + offset - atoms.positions[i]
            r = np.sqrt(np.sum(np.square(rvec), axis=1))
            nearest = np.arange(len(r))[r < self.cutoff]

            d_embedded_energy_i = self.d_embedded_energy[self.index[i]](self.total_density[i])
            urvec = rvec.copy()  # unit directional vector

            for j in np.arange(len(neighbors)):
                urvec[j] = urvec[j] / r[j]

            for j_index in range(self.Nelements):
                use = self.index[neighbors[nearest]] == j_index
                if not use.any():
                    continue
                rnuse = r[nearest][use]
                density_j = self.total_density[neighbors[nearest][use]]
                scale = (
                    self.d_phi[self.index[i], j_index](rnuse)
                    + (d_embedded_energy_i * self.d_electron_density[j_index](rnuse))
                    + (self.d_embedded_energy[j_index](density_j) * self.d_electron_density[self.index[i]](rnuse))
                )

                self.results["forces"][i] += np.dot(scale, urvec[nearest][use])

                if self.form == "adp":
                    adp_forces = self.angular_forces(
                        self.mu[i],
                        self.mu[neighbors[nearest][use]],
                        self.lam[i],
                        self.lam[neighbors[nearest][use]],
                        rnuse,
                        rvec[nearest][use],
                        self.index[i],
                        j_index,
                    )

                    self.results["forces"][i] += adp_forces

    def angular_forces(self, mu_i, mu, lam_i, lam, r, rvec, form1, form2):
        # calculate the extra components for the adp forces
        # rvec are the relative positions to atom i
        psi = np.zeros(mu.shape)
        for gamma in range(3):
            term1 = (mu_i[gamma] - mu[:, gamma]) * self.d[form1][form2](r)

            term2 = np.sum(
                (mu_i - mu)
                * self.d_d[form1][form2](r)[:, np.newaxis]
                * (rvec * rvec[:, gamma][:, np.newaxis] / r[:, np.newaxis]),
                axis=1,
            )

            term3 = 2 * np.sum(
                (lam_i[:, gamma] + lam[:, :, gamma]) * rvec * self.q[form1][form2](r)[:, np.newaxis], axis=1
            )
            term4 = 0.0
            for alpha in range(3):
                for beta in range(3):
                    rs = rvec[:, alpha] * rvec[:, beta] * rvec[:, gamma]
                    term4 += ((lam_i[alpha, beta] + lam[:, alpha, beta]) * self.d_q[form1][form2](r) * rs) / r

            term5 = (
                (lam_i.trace() + lam.trace(axis1=1, axis2=2))
                * (self.d_q[form1][form2](r) * r + 2 * self.q[form1][form2](r))
                * rvec[:, gamma]
            ) / 3.0

            # the minus for term5 is a correction on the adp
            # formulation given in the 2005 Mishin Paper and is posted
            # on the NIST website with the AlH potential
            psi[:, gamma] = term1 + term2 + term3 + term4 - term5

        return np.sum(psi, axis=0)

    def adp_dipole(self, r, rvec, d):
        # calculate the dipole contribution
        mu = np.sum((rvec * d(r)[:, np.newaxis]), axis=0)

        return mu  # sign to agree with lammps

    def adp_quadrupole(self, r, rvec, q):
        # slow way of calculating the quadrupole contribution
        r = np.sqrt(np.sum(rvec ** 2, axis=1))

        lam = np.zeros([rvec.shape[0], 3, 3])
        qr = q(r)
        for alpha in range(3):
            for beta in range(3):
                lam[:, alpha, beta] += qr * rvec[:, alpha] * rvec[:, beta]

        return np.sum(lam, axis=0)

    def deriv(self, spline):
        """Wrapper for extracting the derivative from a spline"""

        def d_spline(aspline):
            return spline(aspline, 1)

        return d_spline

    def plot(self, name=""):
        """Plot the individual curves"""

        try:
            import matplotlib.pyplot as plt

        except ImportError:
            raise NotAvailable("This needs matplotlib module.")

        if self.form == "eam" or self.form == "alloy":
            nrow = 2
        elif self.form == "adp":
            nrow = 3
        else:
            raise RuntimeError("Unknown form of potential: %s" % self.form)

        if hasattr(self, "r"):
            r = self.r
        else:
            r = np.linspace(0, self.cutoff, 50)

        if hasattr(self, "rho"):
            rho = self.rho
        else:
            rho = np.linspace(0, 10.0, 50)

        plt.subplot(nrow, 2, 1)
        self.elem_subplot(rho, self.embedded_energy, r"$\rho$", r"Embedding Energy $F(\bar\rho)$", name, plt)

        plt.subplot(nrow, 2, 2)
        self.elem_subplot(r, self.electron_density, r"$r$", r"Electron Density $\rho(r)$", name, plt)

        plt.subplot(nrow, 2, 3)
        self.multielem_subplot(r, self.phi, r"$r$", r"Pair Potential $\phi(r)$", name, plt)
        plt.ylim(-1.0, 1.0)  # need reasonable values

        if self.form == "adp":
            plt.subplot(nrow, 2, 5)
            self.multielem_subplot(r, self.d, r"$r$", r"Dipole Energy", name, plt)

            plt.subplot(nrow, 2, 6)
            self.multielem_subplot(r, self.q, r"$r$", r"Quadrupole Energy", name, plt)

        plt.plot()

    def elem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            label = name + " " + self.elements[i]
            plt.plot(curvex, curvey[i](curvex), label=label)
        plt.legend()

    def multielem_subplot(self, curvex, curvey, xlabel, ylabel, name, plt):
        plt.xlabel(xlabel)
        plt.ylabel(ylabel)
        for i in np.arange(self.Nelements):
            for j in np.arange(i + 1):
                label = name + " " + self.elements[i] + "-" + self.elements[j]
                plt.plot(curvex, curvey[i, j](curvex), label=label)
        plt.legend()
Пример #38
0
def newclus(ind1, ind2, Optimizer):
    """Select a box in the cluster configuration"""
    if 'CX' in Optimizer.debug:
        debug = True
    else:
        debug = False
    Optimizer.output.write('Box Cluster Cx between individual ' +
                           repr(ind1.index) + ' and individual ' +
                           repr(ind2.index) + '\n')

    #Perserve starting conditions of individual
    solid1 = ind1[0].copy()
    solid2 = ind2[0].copy()
    cello1 = ind1[0].get_cell()
    cello2 = ind2[0].get_cell()
    cell1 = numpy.maximum.reduce(solid1.get_positions())
    cell1m = numpy.minimum.reduce(solid1.get_positions())
    cell2 = numpy.maximum.reduce(solid2.get_positions())
    cell2m = numpy.minimum.reduce(solid2.get_positions())
    cell = numpy.minimum(cell1, cell2)
    pbc1 = solid1.get_pbc()
    pbc2 = solid2.get_pbc()
    #Get starting concentrations and number of atoms
    nat1 = len(solid1)
    nat2 = len(solid2)

    # Pick a origin point for box in the cell
    pt1 = random.choice(solid1)
    pt1f = [(pt1.position[i] - cell1m[i]) / cell1[i] for i in range(3)]
    pt2 = [pt1f[i] * cell2[i] + cell2m[i] for i in range(3)]
    solid2.append(Atom(position=pt2))
    pt2 = solid2[len(solid2) - 1]
    #Find max neighborsize of circle cut
    r = random.uniform(0, min(nat1, nat2) / 5.0)
    if debug:
        print 'DEBUG CX: Point one =', pt1.position
        print 'DEBUG CX: Point two =', pt2.position
    #Find atoms within sphere of neighborsize r for both individuals
    #Make sure that crossover is only selection of atoms not all
    while True:
        ctoff = [r for on in solid1]
        nl = NeighborList(ctoff, bothways=True, self_interaction=False)
        nl.update(solid1)
        indices1, offsets = nl.get_neighbors(pt1.index)
        if len(indices1) == 0:
            r = r * 1.2
        elif len(indices1) < nat1 * .75:
            break
        else:
            r = r * 0.8
    if debug:
        print 'Neighborsize of box = ' + repr(
            r) + '\nPosition in solid1 = ' + repr(
                pt1.position) + '\nPosition in solid2 = ' + repr(pt2.position)
    group1 = Atoms(cell=solid1.get_cell(), pbc=solid1.get_pbc())
    group1.append(pt1)
    indices1a = [pt1.index]
    for index, d in zip(indices1, offsets):
        if index not in indices1a:
            index = int(index)
            pos = solid1[index].position + numpy.dot(d, solid1.get_cell())
            group1.append(Atom(symbol=solid1[index].symbol, position=pos))
            indices1a.append(index)
    indices1 = indices1a
    ctoff = [r for on in solid2]
    nl = NeighborList(ctoff, bothways=True, self_interaction=False)
    nl.update(solid2)
    indices2, offsets = nl.get_neighbors(pt2.index)
    group2 = Atoms(cell=solid2.get_cell(), pbc=solid2.get_pbc())
    indices2a = []
    for index, d in zip(indices2, offsets):
        if index not in indices2a:
            index = int(index)
            pos = solid2[index].position + numpy.dot(d, solid2.get_cell())
            group2.append(Atom(symbol=solid2[index].symbol, position=pos))
            indices2a.append(index)
    indices2 = indices2a
    if len(indices2) == 0:
        for one in group1:
            while True:
                sel = random.choice(solid2)
                if sel.symbol == one.symbol:
                    if sel.index not in indices2:
                        group2.append(sel)
                        indices2.append(sel.index)
                        break

    if Optimizer.forcing == 'Concentration':
        symlist = list(set(group1.get_chemical_symbols()))
        seplist = [[atm for atm in group2 if atm.symbol == sym]
                   for sym in symlist]
        group2n = Atoms(cell=group2.get_cell(), pbc=group2.get_pbc())
        indices2n = []
        dellist = []
        for one in group1:
            sym1 = one.symbol
            listpos = [i for i, s in enumerate(symlist) if s == sym1][0]
            if len(seplist[listpos]) > 0:
                pos = random.choice(range(len(seplist[listpos])))
                group2n.append(seplist[listpos][pos])
                indices2n.append(indices2[seplist[listpos][pos].index])
                del seplist[listpos][pos]
            else:
                dellist.append(one.index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group1[one]
                del indices1[one]
        indices2n.append(pt2.index)
        indices2 = indices2n
        group2 = group2n.copy()
    else:
        dellist = []
        while len(group2) < len(group1) - len(dellist):
            #Too many atoms in group 1
            dellist.append(random.choice(group1).index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group1[one]
                del indices1[one]
        dellist = []
        while len(group1) < len(group2) - len(dellist):
            #Too many atoms in group 2
            dellist.append(random.choice(group2).index)
        if len(dellist) != 0:
            dellist.sort(reverse=True)
            for one in dellist:
                del group2[one]
                del indices2[one]

    other2 = Atoms(cell=solid2.get_cell(), pbc=solid2.get_pbc())
    for one in solid2:
        if one.index not in indices2:
            other2.append(one)
    other1 = Atoms(cell=solid1.get_cell(), pbc=solid1.get_pbc())
    for one in solid1:
        if one.index not in indices1:
            other1.append(one)

    #Exchange atoms in sphere and build new solids
    nsolid1 = other1.copy()
    nsolid1.extend(group2.copy())
    nsolid2 = other2.copy()
    nsolid2.extend(group1.copy())

    #DEBUG: Write crossover to file
    if debug:
        write_xyz(Optimizer.debugfile, nsolid1, 'CX(randalloybx):nsolid1')
        write_xyz(Optimizer.debugfile, nsolid2, 'CX(randalloybx):nsolid2')

    #DEBUG: Check structure of atoms exchanged
    for sym, c, m, u in Optimizer.atomlist:
        if Optimizer.structure == 'Defect':
            nc = len([atm for atm in nsolid1 if atm.symbol == sym])
            nc += len([atm for atm in ind1.bulki if atm.symbol == sym])
            oc = len([atm for atm in solid1 if atm.symbol == sym])
            oc += len([atm for atm in ind1.bulki if atm.symbol == sym])
        else:
            nc = len([atm for atm in nsolid1 if atm.symbol == sym])
            oc = len([atm for atm in solid1 if atm.symbol == sym])
        Optimizer.output.write('CX(clustbx):New solid1 contains ' + repr(nc) +
                               ' ' + repr(sym) + ' atoms\n')
        if debug:
            print 'DEBUG CX: New solid1 contains ' + repr(nc) + ' ' + repr(
                sym) + ' atoms'
        if oc != nc:
            #pdb.set_trace()
            print 'CX: Issue in maintaining atom concentration\n Dropping new individual'
            Optimizer.output.write(
                'CX: Issue in maintaining atom concentration\n Dropping new individual 1\n'
            )
            nsolid1 = solid1
    for sym, c, m, u in Optimizer.atomlist:
        if Optimizer.structure == 'Defect':
            nc = len([atm for atm in nsolid2 if atm.symbol == sym])
            nc += len([atm for atm in ind2.bulki if atm.symbol == sym])
            oc = len([atm for atm in solid2 if atm.symbol == sym])
            oc += len([atm for atm in ind2.bulki if atm.symbol == sym])
        else:
            nc = len([atm for atm in nsolid2 if atm.symbol == sym])
            oc = len([atm for atm in solid2 if atm.symbol == sym])
        Optimizer.output.write('CX(clustbx):New solid2 contains ' + repr(nc) +
                               ' ' + repr(sym) + ' atoms\n')
        if debug:
            print 'DEBUG CX: New solid2 contains ' + repr(nc) + ' ' + repr(
                sym) + ' atoms'
        if oc != nc:
            #pdb.set_trace()
            print 'CX: Issue in maintaining atom concentration\n Dropping new individual'
            Optimizer.output.write(
                'CX: Issue in maintaining atom concentration\n Dropping new individual 2\n'
            )
            solid2.pop()
            nsolid2 = solid2
    if Optimizer.forcing != 'Concentration':
        for i in range(len(Optimizer.atomlist)):
            atms1 = [
                inds for inds in nsolid1
                if inds.symbol == Optimizer.atomlist[i][0]
            ]
            atms2 = [
                inds for inds in nsolid2
                if inds.symbol == Optimizer.atomlist[i][0]
            ]
            if len(atms1) == 0:
                if len(atms2) == 0:
                    nsolid1[random.randint(
                        0,
                        len(indi1) - 1)].symbol == Optimizer.atomlist[i][0]
                    nsolid2[random.randint(
                        0,
                        len(indi2) - 1)].symbol == Optimizer.atomlist[i][0]
                else:
                    nsolid1.append(atms2[random.randint(0, len(atms2) - 1)])
                    nsolid1.pop(random.randint(0, len(nsolid1) - 2))
            else:
                if len(atms2) == 0:
                    nsolid2.append(atms1[random.randint(0, len(atms1) - 1)])
                    nsolid2.pop(random.randint(0, len(nsolid2) - 2))

    nsolid1.set_cell(cello1)
    nsolid2.set_cell(cello2)
    nsolid1.set_pbc(pbc1)
    nsolid2.set_pbc(pbc2)

    ind1[0] = nsolid1.copy()
    ind2[0] = nsolid2.copy()

    return ind1, ind2
Пример #39
0
bulk.set_calculator(model.calculator)
e_bulk_per_atom = bulk.get_potential_energy() / len(bulk)
print 'e_bulk_per_atom', e_bulk_per_atom

if remove_index == 'center':
    half_cell = np.diag(bulk.cell) / 2.
    remove_index = ((bulk.positions - half_cell)**2).sum(axis=1).argmin()

initial = bulk.copy()
orig_pos = initial.get_positions()[remove_index, :]

nl = NeighborList([a0 * sqrt(3.0) / 4 * 0.6] * len(initial),
                  self_interaction=False,
                  bothways=True)
nl.update(initial)
indices, offsets = nl.get_neighbors(remove_index)
remove_index_f = None
initial.arrays['ind'] = array([i for i in range(len(initial))])
offset_factor = 0.13
for i, offset in zip(indices, offsets):
    ri = initial.positions[remove_index] - (initial.positions[i] +
                                            dot(offset, initial.get_cell()))
    if remove_index_f is None:
        remove_index_f = i
    print "initial offset ", i, offset_factor, ri
    initial.positions[i] += offset_factor * ri
    offset_factor += 0.01

del initial[remove_index]
initial.set_calculator(model.calculator)
Пример #40
0
def fss_bcc(indiv, Optimizer):
    defected = indiv[0].copy()
    defected.extend(indiv.bulki)
    #Identify nearest neighbor cutoff distance
    nndists = []
    for i in range(5):
        one = random.choice(defected)
        distances = [defected.get_distance(one.index, j) for j in range(len(defected)) if j != one.index]
        distances.sort()
        nndists.extend(distances[0:3])
    nndist = sum(nndists)/len(nndists)
    cutoff = nndist*0.6
    #Create nearest neighbor list from cutoff distance
    ctflist = [cutoff for one in defected]
    nl = NeighborList(ctflist, bothways=True, self_interaction=False)
    nl.update(defected)
    #Identify most common number of nearest neighbors for each atom
    nneigh = []
    for one in defected:
        indices, offsets = nl.get_neighbors(one.index)
        nneigh.append(len(indices))
    avn = mode(nneigh)
    #Identify those atoms that have a different number of nearest neighbors
    defs = [i for i in range(len(nneigh)) if nneigh[i] != avn[0][0]]
    #Create new structure from translated defected atoms
    defsat = Atoms(pbc = defected.get_pbc(), cell=defected.get_cell())
    for i in defs:
        defsat.append(defected[i])
    #Identify center of mass of defected group and translate to center of cell
    cop = position_average(defsat)
    ndefsat = shift_atoms(defsat, cop)
    ndefected = shift_atoms(defected, cop)
    #Identify bounds of defected portion of structure
    maxpos = max(numpy.maximum.reduce(ndefsat.positions))
    minpos = min(numpy.minimum.reduce(ndefsat.positions))
    #Identify size of structure that will encompass defected structure
    osc = copy.deepcopy(Optimizer.supercell)
    latcont = numpy.maximum.reduce(ndefsat.get_cell())[0]/osc[0]
    deltapos = abs(maxpos-minpos)
    newsupercell = round(deltapos/latcont)+1
    bxlen = newsupercell*latcont
    #Identify those atoms within a box of encompassing length centered at the center of the cell
    tol = .1
    cell = numpy.maximum.reduce(ndefsat.get_cell())
    boxlow = [cell[i]/2.0-bxlen/2.0-tol for i in range(3)]
    boxhigh = [cell[i]/2.0+bxlen/2.0+tol for i in range(3)]
    atlist = []
    otherlist = []
    for one in ndefected:
        pos = one.position
        if boxlow[0] < pos[0] < boxhigh[0]:
            if boxlow[1] < pos[1] < boxhigh[1]:
                if boxlow[2] < pos[2] < boxhigh[2]:
                    atlist.append(one)
                else:
                    otherlist.append(one)
            else:
                otherlist.append(one)
        else:
            otherlist.append(one)
    ncell = [bxlen,bxlen,bxlen]
    #Create a new atoms object from the atoms within the box
    ssats = Atoms(pbc = True, cell=ncell)
    for one in atlist:
        ssats.append(one)
    #Attach a calculator for the atoms
    ssats.set_calculator(Optimizer.calc)
    #Calculate the energy
    out = REE(ssats)
Пример #41
0
b.set_scaled_positions(b.get_scaled_positions())

mask = ((b.positions[:, 0] > 0.) & (b.positions[:, 0] < 2 * a.cell[0, 0]) &
        (b.positions[:, 1] < (a.cell[1, 1] / 2.0 + final_height / 2.0)) &
        (b.positions[:, 1] > (a.cell[1, 1] / 2.0 - final_height / 2.0)))

nl = NeighborList([1.0] * len(b), self_interaction=False, bothways=True)
nl.update(b)

term = Atoms()

if tetra:
    for i in range(len(b)):
        if not mask[i]:
            continue
        indices, offsets = nl.get_neighbors(i)
        if b.numbers[i] == 8 and mask[indices].sum() == 0:
            mask[i] = False
        if b.numbers[i] == 14:
            # complete tetrahedra
            for (j, o) in zip(indices, offsets):
                if b.numbers[j] == 8:
                    mask[j] = True

if terminate:
    for i in range(len(b)):
        if not mask[i]:
            continue
        indices, offsets = nl.get_neighbors(i)
        for (j, o) in zip(indices, offsets):
            if mask[j]:
Пример #42
0
Файл: lj.py Проект: PHOTOX/fuase
class LennardJones(Calculator):
    implemented_properties = ['energy', 'forces', 'stress']
    default_parameters = {'epsilon': 1.0,
                          'sigma': 1.0,
                          'rc': None}
    nolabel = True

    def __init__(self, **kwargs):
        Calculator.__init__(self, **kwargs)

    def calculate(self, atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        natoms = len(self.atoms)

        sigma = self.parameters.sigma
        epsilon = self.parameters.epsilon
        rc = self.parameters.rc
        if rc is None:
            rc = 3 * sigma
        
        if 'numbers' in system_changes:
            self.nl = NeighborList([rc / 2] * natoms, self_interaction=False)

        self.nl.update(self.atoms)
        
        positions = self.atoms.positions
        cell = self.atoms.cell
        
        e0 = 4 * epsilon * ((sigma / rc)**12 - (sigma / rc)**6)
        
        energy = 0.0
        forces = np.zeros((natoms, 3))
        stress = np.zeros((3, 3))

        for a1 in range(natoms):
            neighbors, offsets = self.nl.get_neighbors(a1)
            cells = np.dot(offsets, cell)
            d = positions[neighbors] + cells - positions[a1]
            r2 = (d**2).sum(1)
            c6 = (sigma**2 / r2)**3
            c6[r2 > rc**2] = 0.0
            energy -= e0 * (c6 != 0.0).sum()
            c12 = c6**2
            energy += 4 * epsilon * (c12 - c6).sum()
            f = (24 * epsilon * (2 * c12 - c6) / r2)[:, np.newaxis] * d
            #print d
            #print r2**.5
            #print offsets
            #print f
            #print neighbors
            forces[a1] -= f.sum(axis=0)
            for a2, f2 in zip(neighbors, f):
                forces[a2] += f2
            stress += np.dot(f.T, d)
        
        #stress = np.dot(stress, cell)
        stress += stress.T.copy()
        stress *= -0.5 / self.atoms.get_volume()
        
        self.results['energy'] = energy
        self.results['forces'] = forces
        self.results['stress'] = stress.flat[[0, 4, 8, 5, 2, 1]]
Пример #43
0
def lattice_alteration_nn(indiv, Optimizer):
    """Move function to perform random move along random axis for nearest neighbor distance to random atoms
    Inputs:
        indiv = Individual class object to be altered
        Optimizer = Optimizer class object with needed parameters
    Outputs:
        indiv = Altered Individual class object
    """
    if 'MU' in Optimizer.debug:
        debug = True
    else:
        debug = False
    if Optimizer.structure == 'Defect':
        if Optimizer.isolate_mutation:
            indc, indb, vacant, swaps, stro = find_defects(
                indiv[0], Optimizer.solidbulk, 0)
            ind = indc.copy()
            ind.extend(indb)
        else:
            ind = indiv[0].copy()
            indc = indiv[0].copy()
    else:
        ind = indiv[0].copy()
        indc = indiv[0].copy()
    if len(indc) != 0:
        ctoff1 = [1.0 for one in ind]
        nl = NeighborList(ctoff1, bothways=True, self_interaction=False)
        nl.update(ind)
        try:
            natomsmove = random.randint(1, len(indc) / 2)
        except ValueError:
            natomsmove = 1
        passn = 0
        for count in range(natomsmove):
            try:
                indexmv = random.choice([i for i in range(len(indc))])
                indices, offsets = nl.get_neighbors(indexmv)
                nns = Atoms()
                nns.append(ind[indexmv])
                for index, d in zip(indices, offsets):
                    index = int(index)
                    pos = ind[index].position + numpy.dot(d, ind.get_cell())
                    nns.append(Atom(symbol=ind[index].symbol, position=pos))
                dist = [nns.get_distance(0, i) for i in range(1, len(nns))]
                r = sum(dist) / len(dist)
                dir = random.choice([[1, 0, 0], [-1, 0, 0], [0, 1, 0],
                                     [0, -1, 0], [0, 0, 1], [0, 0, -1]])
                ind[indexmv].position += [i * r for i in dir]
            except:
                passn += 1
        indiv[0] = ind.copy()
    else:
        natomsmove = 0
        passn = 0
    Optimizer.output.write(
        'Lattice Alteration NN Mutation performed on individual\n')
    Optimizer.output.write('Index = ' + repr(indiv.index) + '\n')
    natomsmove -= passn
    Optimizer.output.write('Number of atoms moved = ' + repr(natomsmove) +
                           '\n')
    Optimizer.output.write(repr(indiv[0]) + '\n')
    muttype = 'LANN' + repr(natomsmove)
    if indiv.energy == 0:
        indiv.history_index = indiv.history_index + 'm' + muttype
    else:
        indiv.history_index = repr(indiv.index) + 'm' + muttype
    return indiv
Пример #44
0
class OPLSff:
    def __init__(self, fileobj=None, warnings=0):
        self.warnings = warnings
        self.data = {}
        if fileobj is not None:
            self.read(fileobj)

    def read(self, fileobj, comments='#'):
        if isinstance(fileobj, str):
            fileobj = open(fileobj)

        def read_block(name, 
                       symlen, # length of the symbol
                       nvalues # of values expected
                       ):
            if name not in self.data:
                self.data[name] = {}
            data = self.data[name]

            def add_line():
                line = fileobj.readline()
                if len(line) <= 1: # end of the block
                    return False
                line = line.split('#')[0] # get rid of comments
                if len(line) > symlen:
                    symbol = line[:symlen]
                    words = line[symlen:].split()
                    if len(words) >=  nvalues:
                        if nvalues == 1:
                            data[symbol] = float(words[0])
                        else:
                            data[symbol] = [float(word) 
                                            for word in words[:nvalues]]
                return True

            while add_line():
                pass
 
        read_block('one',      2, 3)
        read_block('bonds',      5, 2)
        read_block('angles',     8, 2)
        read_block('dihedrals', 11, 3)

        read_block('cutoffs',      5, 1)

        self.bonds = BondData(self.data['bonds'])
        self.angles = AnglesData(self.data['angles'])
        self.cutoffs = CutoffList(self.data['cutoffs'])

    def write_lammps(self, atoms):
        btypes, atypes = self.write_lammps_atoms(atoms)
        self.write_lammps_definitions(atoms, btypes, atypes)

    def write_lammps_atoms(self, atoms):
        """Write atoms infor for LAMMPS"""
        
        fileobj = 'lammps_atoms'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')
        write_lammps_data(fileobj, atoms, 
                          specorder=atoms.types,
                          speclist=(atoms.get_tags() + 1),
                          )

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write('%6d %g # %s -> %s\n' % 
                          (i + 1, 
                           atomic_masses[chemical_symbols.index(cs)],
                           typ, cs))
  
        # bonds
        btypes, blist = self.get_bonds(atoms)
        fileobj.write('\n' + str(len(btypes)) + ' bond types\n')
        fileobj.write(str(len(blist)) + ' bonds\n')
        fileobj.write('\nBonds\n\n')
        
        for ib, bvals in enumerate(blist):
            fileobj.write('%8d %6d %6d %6d\n' %
                          (ib + 1, bvals[0] + 1, bvals[1] + 1, bvals[2] + 1))

        # angles
        atypes, alist = self.get_angles()
        fileobj.write('\n' + str(len(atypes)) + ' angle types\n')
        fileobj.write(str(len(alist)) + ' angles\n')
        fileobj.write('\nAngles\n\n')
        
        for ia, avals in enumerate(alist):
            fileobj.write('%8d %6d %6d %6d %6d\n' %
                          (ia + 1, avals[0] + 1, 
                           avals[1] + 1, avals[2] + 1, avals[3] + 1))

        return btypes, atypes

    def update_neighbor_list(self, atoms):
        cut = 0.5 * max(self.data['cutoffs'].values())
        self.nl = NeighborList([cut] * len(atoms), skin=0, bothways=True)
        self.nl.update(atoms)
        self.atoms = atoms
    
    def get_bonds(self, atoms):
        """Find bonds and return them and their types"""
        cutoffs = CutoffList(self.data['cutoffs'])
        self.update_neighbor_list(atoms)

        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        positions = atoms.get_positions()
        bond_list = []
        bond_types = []
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indices, offsets = self.nl.get_neighbors(i)
            for j, offset in zip(indices, offsets):
                if j <= i:
                    continue # do not double count
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    if self.warnings > 1:
                        print ('Warning: cutoff %s-%s not found'
                               % (iname, jname))
                    continue # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position
                                      - np.dot(offset, cell))
                if dist > cut:
                    continue # too far away
                name, val = self.bonds.name_value(iname, jname)
                if name is None:
                    if self.warnings:
                        print ('Warning: potential %s-%s not found'
                               % (iname, jname))
                    continue # don't have it
                if name not in bond_types:
                    bond_types.append(name)
                bond_list.append([bond_types.index(name), i, j])
        return bond_types, bond_list
                
    def get_angles(self, atoms=None):
        cutoffs = CutoffList(self.data['cutoffs'])
        if atoms is not None:
            self.update_neighbor_list(atoms)
        else:
            atoms = self.atoms
         
        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        positions = atoms.get_positions()
        ang_list = []
        ang_types = []
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indicesi, offsetsi = self.nl.get_neighbors(i)
            for j, offsetj in zip(indicesi, offsetsi):
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    continue # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position
                                      - np.dot(offsetj, cell))
                if dist > cut:
                    continue # too far away
                indicesj, offsetsj = self.nl.get_neighbors(j)
                for k, offsetk in zip(indicesj, offsetsj):
                    if k <= i:
                        continue # avoid double count
                    kname = types[tags[k]]
                    cut = cutoffs.value(jname, kname)
                    if cut is None:
                        continue # don't have it
                    dist = np.linalg.norm(atoms[k].position +
                                          np.dot(offsetk, cell) - 
                                          atoms[j].position)
                    if dist > cut:
                        continue # too far away
                    name, val = self.angles.name_value(iname, jname, 
                                                       kname)
                    if name is None:
                        continue # don't have it
                    if name not in ang_types:
                        ang_types.append(name)
                    ang_list.append([ang_types.index(name), i, j, k])
        return ang_types, ang_list

    def write_lammps_definitions(self, atoms, btypes, atypes):
        """Write force field definitions for LAMMPS."""

        fileobj = 'lammps_opls'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        print >> fileobj, '# OPLS potential'
        print >> fileobj, '# write_lammps', time.asctime(
            time.localtime(time.time()))

        # bonds
        fileobj.write('\n# bonds\n')
        fileobj.write('bond_style      harmonic\n')
        for ib, btype in enumerate(btypes):
            fileobj.write('bond_coeff %6d' % (ib + 1))
            for value in self.bonds.nvh[btype]:
                fileobj.write(' ' + str(value))
            fileobj.write(' # ' + btype + '\n')

        # angles
        fileobj.write('\n# angles\n')
        fileobj.write('angle_style      harmonic\n')
        for ia, atype in enumerate(atypes):
            fileobj.write('angle_coeff %6d' % (ia + 1))
            for value in self.angles.nvh[atype]:
                fileobj.write(' ' + str(value))
            fileobj.write(' # ' + atype + '\n')

        # Lennard Jones settings
        fileobj.write('\n# L-J parameters\n')
        fileobj.write('pair_style lj/cut/coul/long 10.0 7.4' +
                      ' # consider changing these parameters\n')
        fileobj.write('special_bonds lj/coul 0.0 0.0 0.5\n')
        data = self.data['one']
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('pair_coeff ' + str(ia + 1) + ' ' + str(ia + 1))
            for value in data[atype][:2]:
                fileobj.write(' ' + str(value))
            fileobj.write(' # ' + atype + '\n')
        fileobj.write('pair_modify shift yes mix geometric\n')

        # Charges
        fileobj.write('\n# charges\n')
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('set type ' + str(ia + 1))
            fileobj.write(' ' + str(data[atype][2]))
            fileobj.write(' # ' + atype + '\n')
Пример #45
0
Файл: opls.py Проект: grhawk/ASE
class OPLSff:
    def __init__(self, fileobj=None, warnings=0):
        self.warnings = warnings
        self.data = {}
        if fileobj is not None:
            self.read(fileobj)

    def read(self, fileobj, comments='#'):
        if isinstance(fileobj, str):
            fileobj = open(fileobj)

        def read_block(name, symlen, nvalues):
            """Read a data block.

            name: name of the block to store in self.data
            symlen: length of the symbol
            nvalues: number of values expected
            """

            if name not in self.data:
                self.data[name] = {}
            data = self.data[name]

            def add_line():
                line = fileobj.readline().strip()
                if not len(line):  # end of the block
                    return False
                line = line.split('#')[0]  # get rid of comments
                if len(line) > symlen:
                    symbol = line[:symlen]
                    words = line[symlen:].split()
                    if len(words) >= nvalues:
                        if nvalues == 1:
                            data[symbol] = float(words[0])
                        else:
                            data[symbol] = [
                                float(word) for word in words[:nvalues]
                            ]
                return True

            while add_line():
                pass

        read_block('one', 2, 3)
        read_block('bonds', 5, 2)
        read_block('angles', 8, 2)
        read_block('dihedrals', 11, 4)
        read_block('cutoffs', 5, 1)

        self.bonds = BondData(self.data['bonds'])
        self.angles = AnglesData(self.data['angles'])
        self.dihedrals = DihedralsData(self.data['dihedrals'])
        self.cutoffs = CutoffList(self.data['cutoffs'])

    def write_lammps(self, atoms, prefix='lammps'):
        """Write input for a LAMMPS calculation."""
        self.prefix = prefix
        btypes, atypes, dtypes = self.write_lammps_atoms(atoms)
        self.write_lammps_definitions(atoms, btypes, atypes, dtypes)
        self.write_lammps_in()

    def write_lammps_in(self):
        # XXX change this
        # XXX some input file for syntax checks
        # XXX change this
        fileobj = self.prefix + '_in'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')
        fileobj.write("""
# (written by ASE)
clear
variable dump_file string "dump_traj"
variable data_file string "dump_data"
units metal
boundary p p f

atom_style full
""")
        fileobj.write('read_data ' + self.prefix + '_atoms\n')
        fileobj.write('include  ' + self.prefix + '_opls\n')
        fileobj.write("""
### run
fix fix_nve all nve
dump dump_all all custom 1 trj_lammps id type x y z vx vy vz fx fy fz
thermo_style custom step temp press cpu pxx pyy pzz pxy pxz pyz ke pe etotal vol lx ly lz atoms
thermo_modify flush yes
thermo 1
run 0
print "__end_of_ase_invoked_calculation__"
log /dev/stdout
""")
        fileobj.close()

    def write_lammps_atoms(self, atoms):
        """Write atoms infor for LAMMPS"""

        fileobj = self.prefix + '_atoms'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        btypes, blist = self.get_bonds(atoms)
        if len(blist):
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        atypes, alist = self.get_angles()
        if len(alist):
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dtypes, dlist = self.get_dihedrals(alist, atypes)
        if len(dlist):
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)

        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        for i, r in enumerate(map(p.pos_to_lammps_str, atoms.get_positions())):
            q = 0  # charge will be overwritten
            fileobj.write('%6d %3d %3d %s %s %s %s' %
                          ((i + 1, 1, tag[i] + 1, q) + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' % (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write(
                '%6d %g # %s -> %s\n' %
                (i + 1, atomic_masses[chemical_symbols.index(cs)], typ, cs))

        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write(
                    '%8d %6d %6d %6d ' %
                    (ib + 1, bvals[0] + 1, bvals[1] + 1, bvals[2] + 1))
                fileobj.write('# ' + btypes[bvals[0]] + '\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1, avals[1] + 1,
                               avals[2] + 1, avals[3] + 1))
                fileobj.write('# ' + atypes[avals[0]] + '\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1, dvals[1] + 1, dvals[2] + 1,
                               dvals[3] + 1, dvals[4] + 1))
                fileobj.write('# ' + dtypes[dvals[0]] + '\n')

        return btypes, atypes, dtypes

    def update_neighbor_list(self, atoms):
        cut = 0.5 * max(self.data['cutoffs'].values())
        self.nl = NeighborList([cut] * len(atoms),
                               skin=0,
                               bothways=True,
                               self_interaction=False)
        self.nl.update(atoms)
        self.atoms = atoms

    def get_bonds(self, atoms):
        """Find bonds and return them and their types"""
        cutoffs = CutoffList(self.data['cutoffs'])
        self.update_neighbor_list(atoms)

        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        positions = atoms.get_positions()
        bond_list = []
        bond_types = []
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indices, offsets = self.nl.get_neighbors(i)
            for j, offset in zip(indices, offsets):
                if j <= i:
                    continue  # do not double count
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    if self.warnings > 1:
                        print('Warning: cutoff %s-%s not found' %
                              (iname, jname))
                    continue  # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position -
                                      np.dot(offset, cell))
                if dist > cut:
                    continue  # too far away
                name, val = self.bonds.name_value(iname, jname)
                if name is None:
                    if self.warnings:
                        print('Warning: potential %s-%s not found' %
                              (iname, jname))
                    continue  # don't have it
                if name not in bond_types:
                    bond_types.append(name)
                bond_list.append([bond_types.index(name), i, j])
        return bond_types, bond_list

    def get_angles(self, atoms=None):
        cutoffs = CutoffList(self.data['cutoffs'])
        if atoms is not None:
            self.update_neighbor_list(atoms)
        else:
            atoms = self.atoms

        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        positions = atoms.get_positions()
        ang_list = []
        ang_types = []

        # center atom *-i-*
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indicesi, offsetsi = self.nl.get_neighbors(i)

            # search for first neighbor j-i-*
            for j, offsetj in zip(indicesi, offsetsi):
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    continue  # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position -
                                      np.dot(offsetj, cell))
                if dist > cut:
                    continue  # too far away

                # search for second neighbor j-i-k
                for k, offsetk in zip(indicesi, offsetsi):
                    if k <= j:
                        continue  # avoid double count
                    kname = types[tags[k]]
                    cut = cutoffs.value(iname, kname)
                    if cut is None:
                        continue  # don't have it
                    dist = np.linalg.norm(atom.position -
                                          np.dot(offsetk, cell) -
                                          atoms[k].position)
                    if dist > cut:
                        continue  # too far away
                    name, val = self.angles.name_value(jname, iname, kname)
                    if name is None:
                        continue  # don't have it
                    if name not in ang_types:
                        ang_types.append(name)
                    ang_list.append([ang_types.index(name), j, i, k])

        return ang_types, ang_list

    def get_dihedrals(self, ang_types, ang_list):
        'Dihedrals derived from angles.'

        cutoffs = CutoffList(self.data['cutoffs'])

        atoms = self.atoms
        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()

        dih_list = []
        dih_types = []

        def append(name, i, j, k, l):
            if name not in dih_types:
                dih_types.append(name)
            index = dih_types.index(name)
            if (([index, i, j, k, l] not in dih_list)
                    and ([index, l, k, j, i] not in dih_list)):
                dih_list.append([index, i, j, k, l])

        for angle in ang_types:
            l, i, j, k = angle
            iname = types[tags[i]]
            jname = types[tags[j]]
            kname = types[tags[k]]

            # search for l-i-j-k
            indicesi, offsetsi = self.nl.get_neighbors(i)
            for l, offsetl in zip(indicesi, offsetsi):
                if l == j:
                    continue  # avoid double count
                lname = types[tags[l]]
                cut = cutoffs.value(iname, lname)
                if cut is None:
                    continue  # don't have it
                dist = np.linalg.norm(atoms[i].position - atoms[l].position -
                                      np.dot(offsetl, cell))
                if dist > cut:
                    continue  # too far away
                name, val = self.dihedrals.name_value(lname, iname, jname,
                                                      kname)
                if name is None:
                    continue  # don't have it
                append(name, l, i, j, k)

            # search for i-j-k-l
            indicesk, offsetsk = self.nl.get_neighbors(k)
            for l, offsetl in zip(indicesk, offsetsk):
                if l == j:
                    continue  # avoid double count
                lname = types[tags[l]]
                cut = cutoffs.value(kname, lname)
                if cut is None:
                    continue  # don't have it
                dist = np.linalg.norm(atoms[k].position - atoms[l].position -
                                      np.dot(offsetl, cell))
                if dist > cut:
                    continue  # too far away
                name, val = self.dihedrals.name_value(iname, jname, kname,
                                                      lname)
                if name is None:
                    continue  # don't have it
                append(name, i, j, k, l)

        return dih_types, dih_list

    def write_lammps_definitions(self, atoms, btypes, atypes, dtypes):
        """Write force field definitions for LAMMPS."""

        fileobj = self.prefix + '_opls'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        fileobj.write('# OPLS potential\n')
        fileobj.write('# write_lammps' +
                      str(time.asctime(time.localtime(time.time()))))

        # bonds
        if len(btypes):
            fileobj.write('\n# bonds\n')
            fileobj.write('bond_style      harmonic\n')
            for ib, btype in enumerate(btypes):
                fileobj.write('bond_coeff %6d' % (ib + 1))
                for value in self.bonds.nvh[btype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + btype + '\n')

        # angles
        if len(atypes):
            fileobj.write('\n# angles\n')
            fileobj.write('angle_style      harmonic\n')
            for ia, atype in enumerate(atypes):
                fileobj.write('angle_coeff %6d' % (ia + 1))
                for value in self.angles.nvh[atype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + atype + '\n')

        # dihedrals
        if len(dtypes):
            fileobj.write('\n# dihedrals\n')
            fileobj.write('dihedral_style      opls\n')
            for i, dtype in enumerate(dtypes):
                fileobj.write('dihedral_coeff %6d' % (i + 1))
                for value in self.dihedrals.nvh[dtype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + dtype + '\n')

        # Lennard Jones settings
        fileobj.write('\n# L-J parameters\n')
        fileobj.write('pair_style lj/cut/coul/long 10.0 7.4' +
                      ' # consider changing these parameters\n')
        fileobj.write('special_bonds lj/coul 0.0 0.0 0.5\n')
        data = self.data['one']
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('pair_coeff ' + str(ia + 1) + ' ' + str(ia + 1))
            for value in data[atype][:2]:
                fileobj.write(' ' + str(value))
            fileobj.write(' # ' + atype + '\n')
        fileobj.write('pair_modify shift yes mix geometric\n')

        # Coulomb
        fileobj.write("""
# Coulomb
kspace_style pppm 1e-5
kspace_modify slab 3.0
""")

        # Charges
        fileobj.write('\n# charges\n')
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('set type ' + str(ia + 1))
            fileobj.write(' charge ' + str(data[atype][2]))
            fileobj.write(' # ' + atype + '\n')
Пример #46
0
def swap_int_local(indiv, Optimizer):
    """Move function to perform n atom structure swap based on swaplist for cluster in local region
    Inputs:
        indiv = Individual class object to be altered
        Optimizer = Optimizer class object with needed parameters
    Outputs:
        indiv = Altered Individual class object
    """
    if 'MU' in Optimizer.debug:
        debug = True
    else:
        debug = False
    Optimizer.output.write('Local Cluster Swap Mutation performed on individual\n')
    Optimizer.output.write('Index = '+repr(indiv.index)+'\n')
    # Identify the local atoms available for swapping
    atmsst = indiv[0].copy()
    nat = len(atmsst)
    totalsol = atmsst.copy()
    if Optimizer.structure=='Defect':
        totalsol.extend(indiv.bulki.copy())
        ctoff = [Optimizer.sf for one in totalsol]
    else:
        ctoff = [1.5 for one in totalsol]
    nl = NeighborList(ctoff, bothways=True, self_interaction=False)
    nl.update(totalsol)
    cluster = Atoms()
    indices = [] #store indices of the atoms for later
    for i in range(nat):
        indices1, offsets = nl.get_neighbors(i)
        for index, d in zip(indices1,offsets):
            index = int(index)
            #Make sure to prevent repeats of the same atom
            if index not in indices:
                pos = totalsol[index].position + numpy.dot(d,totalsol.get_cell())
                cluster.append(Atom(symbol=totalsol[index].symbol,position=pos))
                indices.append(index)
    # Identify Number of atoms to swap
    swapmax=sum([c for sym,c in indiv.swaplist])
    if swapmax >1:
        natomsswap=random.randint(1,swapmax)
    elif swapmax==1:
        natomsswap=1
    else:
        Optimizer.output.write('Maximum number of swaps is '+repr(swapmax)+'. Unable to perform mutation')
        natomsswap=0
    if len(indiv.swaplist)==1:
        Optimizer.output.write('WARNING: Swap Mutation attempted on single atom structure system\n')
        natomsswap=0
    Optimizer.output.write('Number of swaps = '+repr(natomsswap)+'\n')
    # Identify symbols that can be swapped
    syms=[sym for sym,c in indiv.swaplist]
    slist = copy.deepcopy(indiv.swaplist)
    if debug: print 'Starting swaplist = '+repr(indiv.swaplist)
    #Sanity check
    sanch = [[sym,0] for sym in syms]
    for i in range(len(sanch)):
        nc = len([atm for atm in cluster if atm.symbol==sanch[i][0]])
        nc += [c for sym,c in slist if sym==sanch[i][0]][0]
        sanch[i][1]=nc
    # Swap Atoms
    for i in range(natomsswap):
        while True:
            at1 = random.choice(cluster)
            osym = at1.symbol
            nsyml=[sym for sym,c in slist if sym != osym and c > 0]
            if len(nsyml) > 0:
                break
        nsym = random.choice(nsyml)
        cluster[at1.index].symbol = nsym
        Optimizer.output.write('Swapped '+nsym+' atom with '+osym+'\n')
        for i in range(len(slist)):
            if slist[i][0]==nsym:
                slist[i][1]-=1
            elif slist[i][0]==osym:
                slist[i][1]+=1
    # Apply the new swap to the actual atoms in the structure
    for i in range(len(indices)):
        totalsol[indices[i]].symbol = cluster[i].symbol
    # Separate out bulk from defects
    indiv[0] = totalsol[0:nat]
    if Optimizer.structure=='Defect':
        indiv.bulki = totalsol[nat::]
    # Update new swaplist
    indiv.swaplist = slist
    #Sanity check
    sanchn = [[sym,0] for sym in syms]
    for i in range(len(sanchn)):
        nc = len([atm for atm in cluster if atm.symbol==sanchn[i][0]])
        nc += [c for sym,c in slist if sym==sanchn[i][0]][0]
        sanchn[i][1]=nc
    if debug:
        for i in range(len(sanch)):
            print 'INTSWAP: Starting Atom structure '+repr(sanch[i][0])+' = '+repr(sanch[i][1])
            print 'INTSWAP: After Mutation Atom structure '+repr(sanchn[i][0])+' = '+repr(sanchn[i][1])
    Optimizer.output.write(repr(indiv[0])+'\n')
    muttype='SCL'+repr(natomsswap)
    if indiv.energy==0:
        indiv.history_index=indiv.history_index+'m'+muttype
    else:
        indiv.history_index=repr(indiv.index)+'m'+muttype
    return indiv
Пример #47
0
def monoatomic(atoms, R1=3, calc_energy=False):
    r"""This routine analyzes atomic structure
    by the calculation of coordination numbers
    in cluster with only one type of atom.

    Parameters
    ----------
    atoms: ase.Atoms
        ase Atoms object, containing atomic cluster.
    R1: float
        First coordination shell will icnlude all atoms
        with distance less then R1 [Angstrom].
        Default value is 3.
    calc_energy: bool
        Flag used for calculation of potential energy with EMT
        calculator.  The default value is False, so that
        energy is not calculated.

    Returns
    -------
    N: int
        number of atoms in cluster
    R: float
        radius of the cluster
    CN: float
        average coord number
    E: float
        potential energy, -1 if calc_energy is False
    Ncore:
        number of atoms in core region (number of atoms with
        all 12 neighbors)
    CNshell:
        average coordination number for surface atoms only

    Notes
    -----
        The radius of the cluster is roughly determined as
        maximum the distance from the center to most distant atom
        in the cluster.

    Example
    --------
    >>> atoms = FaceCenteredCubic('Ag',
      [(1, 0, 0), (1, 1, 0), (1, 1, 1)], [7,8,7], 4.09)
    >>> [N, R, CN] = monoatomic(atoms)
    >>> print "average CN is ", CN
    """
    N = len(atoms)
    nl = NeighborList([R1 / 2.0] * N, self_interaction=False, bothways=True)
    nl.build(atoms)
    CN = 0
    Ncore = 0
    Nshell = 0
    CNshell = 0  # average CN of surface atoms
    for i in xrange(0, N):
        indeces, offsets = nl.get_neighbors(i)
        CN += len(indeces)
        if len(indeces) < 12:
            Nshell += 1
            CNshell += len(indeces)
        else:
            Ncore += 1
    CN = CN * 1.0 / N
    CNshell = CNshell * 1.0 / Nshell
    atoms.center()
    R = atoms.positions.max() / 2.0
    if calc_energy:
        #from asap3 import EMT
        from ase.calculators.emt import EMT
        atoms.set_calculator(EMT())
        E = atoms.get_potential_energy()
    else:
        E = -1
    return N, R, CN, E, Ncore, CNshell
Пример #48
0
class EMT(Calculator):
    implemented_properties = ['energy', 'forces']

    nolabel = True

    def __init__(self):
        Calculator.__init__(self)

    def initialize(self, atoms):
        self.par = {}
        self.rc = 0.0
        self.numbers = atoms.get_atomic_numbers()
        maxseq = max(par[1] for par in parameters.values()) * Bohr
        rc = self.rc = beta * maxseq * 0.5 * (sqrt(3) + sqrt(4))
        rr = rc * 2 * sqrt(4) / (sqrt(3) + sqrt(4))
        self.acut = np.log(9999.0) / (rr - rc)
        for Z in self.numbers:
            if Z not in self.par:
                p = parameters[chemical_symbols[Z]]
                s0 = p[1] * Bohr
                eta2 = p[3] / Bohr
                kappa = p[4] / Bohr
                x = eta2 * beta * s0
                gamma1 = 0.0
                gamma2 = 0.0
                for i, n in enumerate([12, 6, 24]):
                    r = s0 * beta * sqrt(i + 1)
                    x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
                    gamma1 += x * exp(-eta2 * (r - beta * s0))
                    gamma2 += x * exp(-kappa / beta * (r - beta * s0))

                self.par[Z] = {'E0': p[0],
                               's0': s0,
                               'V0': p[2],
                               'eta2': eta2,
                               'kappa': kappa,
                               'lambda': p[5] / Bohr,
                               'n0': p[6] / Bohr**3,
                               'rc': rc,
                               'gamma1': gamma1,
                               'gamma2': gamma2}
                #if rc + 0.5 > self.rc:
                #    self.rc = rc + 0.5

        self.ksi = {}
        for s1, p1 in self.par.items():
            self.ksi[s1] = {}
            for s2, p2 in self.par.items():
                #self.ksi[s1][s2] = (p2['n0'] / p1['n0'] *
                #                    exp(eta1 * (p1['s0'] - p2['s0'])))
                self.ksi[s1][s2] = p2['n0'] / p1['n0']
                
        self.forces = np.empty((len(atoms), 3))
        self.sigma1 = np.empty(len(atoms))
        self.deds = np.empty(len(atoms))
                    
        self.nl = NeighborList([0.5 * self.rc + 0.25] * len(atoms),
                               self_interaction=False)

    def calculate(self, atoms=None, properties=['energy'],
                  system_changes=all_changes):
        Calculator.calculate(self, atoms, properties, system_changes)

        if 'numbers' in system_changes:
            self.initialize(self.atoms)

        positions = self.atoms.positions
        numbers = self.atoms.numbers
        cell = self.atoms.cell
        
        self.nl.update(self.atoms)
        
        self.energy = 0.0
        self.sigma1[:] = 0.0
        self.forces[:] = 0.0

        natoms = len(self.atoms)

        for a1 in range(natoms):
            Z1 = numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, cell)
            for a2, offset in zip(neighbors, offsets):
                d = positions[a2] + offset - positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = numbers[a2]
                    p2 = self.par[Z2]
                    self.interact1(a1, a2, d, r, p1, p2, ksi[Z2])
                                
        for a in range(natoms):
            Z = numbers[a]
            p = self.par[Z]
            try:
                ds = -log(self.sigma1[a] / 12) / (beta * p['eta2'])
            except (OverflowError, ValueError):
                self.deds[a] = 0.0
                self.energy -= p['E0']
                continue
            x = p['lambda'] * ds
            y = exp(-x)
            z = 6 * p['V0'] * exp(-p['kappa'] * ds)
            self.deds[a] = ((x * y * p['E0'] * p['lambda'] + p['kappa'] * z) /
                            (self.sigma1[a] * beta * p['eta2']))
            self.energy += p['E0'] * ((1 + x) * y - 1) + z

        for a1 in range(natoms):
            Z1 = numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, cell)
            for a2, offset in zip(neighbors, offsets):
                d = positions[a2] + offset - positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = numbers[a2]
                    p2 = self.par[Z2]
                    self.interact2(a1, a2, d, r, p1, p2, ksi[Z2])

        self.results['energy'] = self.energy
        self.results['forces'] = self.forces

    def interact1(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (0.5 * p1['V0'] * exp(-p2['kappa'] * (r / beta - p2['s0'])) *
              ksi / p1['gamma2'] * theta)
        y2 = (0.5 * p2['V0'] * exp(-p1['kappa'] * (r / beta - p1['s0'])) /
              ksi / p2['gamma2'] * theta)
        self.energy -= y1 + y2
        f = ((y1 * p2['kappa'] + y2 * p1['kappa']) / beta +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] += f
        self.forces[a2] -= f
        self.sigma1[a1] += (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
                            ksi * theta / p1['gamma1'])
        self.sigma1[a2] += (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
                            ksi * theta / p2['gamma1'])

    def interact2(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
              ksi / p1['gamma1'] * theta * self.deds[a1])
        y2 = (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
              ksi / p2['gamma1'] * theta * self.deds[a2])
        f = ((y1 * p2['eta2'] + y2 * p1['eta2']) +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] -= f
        self.forces[a2] += f
Пример #49
0
class EMT:
    disabled = False  # Set to True to disable (asap does this).
    
    def __init__(self, fakestress=False):
        self.energy = None
        self.name = 'EMT'
        self.version = '1.0'
        # fakestress is needed to fake some stress value for the testsuite
        # in order to test the filter functionality.
        self.fakestress = fakestress
        if self.disabled:
            print >> sys.stderr, """
            ase.EMT has been disabled by Asap.  Most likely, you
            intended to use Asap's EMT calculator, but accidentally
            imported ase's EMT calculator after Asap's.  This could
            happen if your script contains the lines

              from asap3 import *
              from ase.calculators.emt import EMT
            Swap the two lines to solve the problem.

            (or 'from ase import *' in older versions of ASE.) Swap 
            the two lines to solve the problem.

            In the UNLIKELY event that you actually wanted to use
            ase.calculators.emt.EMT although asap3 is loaded into memory,
            please reactivate it with the command
              ase.calculators.emt.EMT.disabled = False
            """
            raise RuntimeError('ase.EMT has been disabled.  ' +
                               'See message printed above.')
        
    def get_name(self):
        return self.name

    def get_version(self):
        return self.version

    def get_spin_polarized(self):
        return False
    
    def initialize(self, atoms):
        self.par = {}
        self.rc = 0.0
        self.numbers = atoms.get_atomic_numbers()
        maxseq = max(par[1] for par in parameters.values()) * Bohr
        rc = self.rc = beta * maxseq * 0.5 * (sqrt(3) + sqrt(4))
        rr = rc * 2 * sqrt(4) / (sqrt(3) + sqrt(4))
        self.acut = np.log(9999.0) / (rr - rc)
        for Z in self.numbers:
            if Z not in self.par:
                p = parameters[chemical_symbols[Z]]
                s0 = p[1] * Bohr
                eta2 = p[3] / Bohr
                kappa = p[4] / Bohr
                x = eta2 * beta * s0
                gamma1 = 0.0
                gamma2 = 0.0
                for i, n in enumerate([12, 6, 24]):
                    r = s0 * beta * sqrt(i + 1)
                    x = n / (12 * (1.0 + exp(self.acut * (r - rc))))
                    gamma1 += x * exp(-eta2 * (r - beta * s0))
                    gamma2 += x * exp(-kappa / beta * (r - beta * s0))

                self.par[Z] = {'E0': p[0],
                               's0': s0,
                               'V0': p[2],
                               'eta2': eta2,
                               'kappa': kappa,
                               'lambda': p[5] / Bohr,
                               'n0': p[6] / Bohr**3,
                               'rc': rc,
                               'gamma1': gamma1,
                               'gamma2': gamma2}
                #if rc + 0.5 > self.rc:
                #    self.rc = rc + 0.5

        self.ksi = {}
        for s1, p1 in self.par.items():
            self.ksi[s1] = {}
            for s2, p2 in self.par.items():
                #self.ksi[s1][s2] = (p2['n0'] / p1['n0'] *
                #                    exp(eta1 * (p1['s0'] - p2['s0'])))
                self.ksi[s1][s2] = p2['n0'] / p1['n0']
                
        self.forces = np.empty((len(atoms), 3))
        self.sigma1 = np.empty(len(atoms))
        self.deds = np.empty(len(atoms))
                    
        self.nl = NeighborList([0.5 * self.rc + 0.25] * len(atoms),
                               self_interaction=False)

    def update(self, atoms):
        if (self.energy is None or
            len(self.numbers) != len(atoms) or
            (self.numbers != atoms.get_atomic_numbers()).any()):
            self.initialize(atoms)
            self.calculate(atoms)
        elif ((self.positions != atoms.get_positions()).any() or
              (self.pbc != atoms.get_pbc()).any() or
              (self.cell != atoms.get_cell()).any()):
            self.calculate(atoms)

    def calculation_required(self, atoms, quantities):
        if len(quantities) == 0:
            return False

        return (self.energy is None or
                len(self.numbers) != len(atoms) or
                (self.numbers != atoms.get_atomic_numbers()).any() or
                (self.positions != atoms.get_positions()).any() or
                (self.pbc != atoms.get_pbc()).any() or
                (self.cell != atoms.get_cell()).any())
                
    def get_number_of_iterations(self):
        return 0

    def get_potential_energy(self, atoms):
        self.update(atoms)
        return self.energy

    def get_numeric_forces(self, atoms):
        self.update(atoms)
        p = atoms.positions
        p0 = p.copy()
        forces = np.empty_like(p)
        eps = 0.0001
        for a in range(len(p)):
            for c in range(3):
                p[a, c] += eps
                self.calculate(atoms)
                de = self.energy
                p[a, c] -= 2 * eps
                self.calculate(atoms)
                de -= self.energy
                p[a, c] += eps
                forces[a, c] = -de / (2 * eps)
        p[:] = p0
        return forces

    def get_forces(self, atoms):
        self.update(atoms)
        return self.forces.copy()
    
    def get_stress(self, atoms):
        if self.fakestress:
            return np.zeros((6))
        else:
            raise NotImplementedError
    
    def calculate(self, atoms):
        self.positions = atoms.get_positions().copy()
        self.cell = atoms.get_cell().copy()
        self.pbc = atoms.get_pbc().copy()
        
        self.nl.update(atoms)
        
        self.energy = 0.0
        self.sigma1[:] = 0.0
        self.forces[:] = 0.0
        
        natoms = len(atoms)

        for a1 in range(natoms):
            Z1 = self.numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, atoms.cell)
            for a2, offset in zip(neighbors, offsets):
                d = self.positions[a2] + offset - self.positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = self.numbers[a2]
                    p2 = self.par[Z2]
                    self.interact1(a1, a2, d, r, p1, p2, ksi[Z2])
                                
        for a in range(natoms):
            Z = self.numbers[a]
            p = self.par[Z]
            try:
                ds = -log(self.sigma1[a] / 12) / (beta * p['eta2'])
            except (OverflowError, ValueError):
                self.deds[a] = 0.0
                self.energy -= p['E0']
                continue
            x = p['lambda'] * ds
            y = exp(-x)
            z = 6 * p['V0'] * exp(-p['kappa'] * ds)
            self.deds[a] = ((x * y * p['E0'] * p['lambda'] + p['kappa'] * z) /
                            (self.sigma1[a] * beta * p['eta2']))
            e = p['E0'] * ((1 + x) * y - 1) + z
            self.energy += p['E0'] * ((1 + x) * y - 1) + z

        for a1 in range(natoms):
            Z1 = self.numbers[a1]
            p1 = self.par[Z1]
            ksi = self.ksi[Z1]
            neighbors, offsets = self.nl.get_neighbors(a1)
            offsets = np.dot(offsets, atoms.cell)
            for a2, offset in zip(neighbors, offsets):
                d = self.positions[a2] + offset - self.positions[a1]
                r = sqrt(np.dot(d, d))
                if r < self.rc + 0.5:
                    Z2 = self.numbers[a2]
                    p2 = self.par[Z2]
                    self.interact2(a1, a2, d, r, p1, p2, ksi[Z2])

    def interact1(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (0.5 * p1['V0'] * exp(-p2['kappa'] * (r / beta - p2['s0'])) *
              ksi / p1['gamma2'] * theta)
        y2 = (0.5 * p2['V0'] * exp(-p1['kappa'] * (r / beta - p1['s0'])) /
              ksi / p2['gamma2'] * theta)
        self.energy -= y1 + y2
        f = ((y1 * p2['kappa'] + y2 * p1['kappa']) / beta +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] += f
        self.forces[a2] -= f
        self.sigma1[a1] += (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
                            ksi * theta / p1['gamma1'])
        self.sigma1[a2] += (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
                            ksi * theta / p2['gamma1'])

    def interact2(self, a1, a2, d, r, p1, p2, ksi):
        x = exp(self.acut * (r - self.rc))
        theta = 1.0 / (1.0 + x)
        y1 = (exp(-p2['eta2'] * (r - beta * p2['s0'])) *
              ksi / p1['gamma1'] * theta * self.deds[a1])
        y2 = (exp(-p1['eta2'] * (r - beta * p1['s0'])) /
              ksi / p2['gamma1'] * theta * self.deds[a2])
        f = ((y1 * p2['eta2'] + y2 * p1['eta2']) +
             (y1 + y2) * self.acut * theta * x) * d / r
        self.forces[a1] -= f
        self.forces[a2] += f

    def set_atoms(self,*args,**kwargs):
        'empty function for compatibility with other calculators and tests'
        pass
Пример #50
0
def check_min_dist(Optimizer, totalsol, type='Defect', nat=None, min_len=0.7, STR=''):
    if type=='Defect' or type=='Crystal' or type=='Surface':
        if nat==None:
            nat=len(totalsol)
        cutoffs=[2.0 for one in totalsol]
        nl=NeighborList(cutoffs,bothways=True,self_interaction=False)
        nl.update(totalsol)
        for one in totalsol[0:nat]:
            nbatoms=Atoms()
            nbatoms.append(one)
            indices, offsets=nl.get_neighbors(one.index)
            for index, d in zip(indices,offsets):
                index = int(index)
                sym=totalsol[index].symbol
                pos=totalsol[index].position + numpy.dot(d,totalsol.get_cell())
                at=Atom(symbol=sym,position=pos)
                nbatoms.append(at)
            while True:
                dflag=False
                for i in range(1,len(nbatoms)):
                    d=nbatoms.get_distance(0,i)
                    if d < min_len:
                        nbatoms.set_distance(0,i,min_len+.01,fix=0.5)
                        STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
                        dflag=True
                if dflag==False:
                    break
            for i in range(len(indices)):
                totalsol[indices[i]].position=nbatoms[i+1].position
            totalsol[one.index].position=nbatoms[0].position
            nl.update(totalsol)
    elif type=='Cluster':
        rank = MPI.COMM_WORLD.Get_rank()
        logger = logging.getLogger(Optimizer.loggername)
        R = totalsol.arrays['positions']
        tol = 0.01
        epsilon = 0.05
        fix = 0.5
        if Optimizer.forcing == 'EllipoidShape' or Optimizer.forcing == 'FreeNatom': 
          com = totalsol.get_center_of_mass()       
          cmax = numpy.maximum.reduce(R)
          cmin = numpy.minimum.reduce(R)
          rmax= (cmax-cmin)/2.0 
          if Optimizer.forcing == 'FreeNatom':
             rcutoff = 44.0
             cutoff = [44.0,44.0,20.0]        
          else:
             rcutoff = 11.0
             cutoff = [12.0,12.0,12.0]        
          rcutoff = 44.0
          cutoff = [44.0,44.0,20.0]        
          #check if atoms are isolated outside of cluster
          cutoffs=[3.0 for one in totalsol]
          nl=NeighborList(cutoffs,bothways=True,self_interaction=False)
          nl.update(totalsol)
          for i in range(len(totalsol)):
             indices, offsets=nl.get_neighbors(i)
             D = R[i]-com
             radius = (numpy.dot(D,D))**0.5 #numpy.linalg.norm(D)
             if len(indices) < 12 or radius > rcutoff :
                # logger.info('M:move atoms back when indice {0} or radius {1}'.format(len(indices),radius))
                # R[i] = [com[j] + D[j]/radius*rcutoff for j in range(3)]
                theta=math.radians(random.uniform(0,360))
                phi=math.radians(random.uniform(0,180))
                R[i][0] = com[0] + (rmax[0]+2.5)*math.sin(theta)*math.cos(phi) #allow atoms expend by 2.5 ang
                R[i][1] = com[1] + (rmax[1]+2.5)*math.sin(theta)*math.sin(phi)
                R[i][2] = com[2] + rmax[2]*math.cos(theta)
                # logger.info('M:move atoms back new pos {0} {1} {2}'.format(rmax[0]*math.sin(theta)*math.cos(phi),rmax[1]*math.sin(theta)*math.sin(phi),rmax[2]*math.cos(theta)))
               
          # check if atoms are within cluster region 
          for i in range(0,len(totalsol)):
            # D = R[i]-com
            for j in range(3):                 
               if D[j] > cutoff[j] or D[j] < -cutoff[j]:
         #         logger.info('M:before move R {0} & com {1}'.format(R[i][j],com[j]))
                  #if rank==0:
                  #   print "before:",j,R[i][j],com[j] 
                  R[i][j] = com[j]+numpy.sign(D[j])*cutoff[j]*random.random()
         #         logger.info('M:after move R {0} '.format(R[i][j]))
                  #if rank==0:
                  #   print "after:",R[i][j]
              #    STR+='--- WARNING: Atoms too far along x-y (>44A) - Implement Move ---\n'          
                  D = R[i]-com
        #    radius = (numpy.dot(D,D))**0.5 #numpy.linalg.norm(D)
             #  STR+='--- WARNING: Atoms too far (>56A) - Implement Move ---\n'          
              

        closelist = numpy.arange(len(totalsol))
        iter = 0
        while len(closelist) > 0 and iter<2:
          iter+=1 
         # checklist = numpy.copy(closelist)
          closelist = []  
          dist=scipy.spatial.distance.cdist(R,R)       
          numpy.fill_diagonal(dist,1.0)
          smalldist = numpy.where(dist < min_len-tol)
         # for i in checklist:
            # for j in range(i+1,len(totalsol)):
         #    if len(checklist) == len(totalsol):
         #       jstart = i+1
         #    else:
         #       jstart = 0
         #    for j in range(jstart,len(totalsol)):
         #       if i != j and dist[i][j] < min_len:
             #       d=totalsol.get_distance(i,j)
             #       if d < min_len:
             #           totalsol.set_distance(i,j,min_len,fix=0.5)
                    # d = (D[0]*D[0]+D[1]*D[1]+D[2]*D[2])**0.5
          for ind in range(len(smalldist[0])):
                   i = smalldist[0][ind]
                   j = smalldist[1][ind]
                   if i < j and dist[i][j] < min_len-tol:   
                        closelist.append(i)
                        closelist.append(j)
                        if dist[i][j] > epsilon:
                      	  x = 1.0 - min_len / dist[i][j]
                          D = R[j]-R[i]
                         # print "node:",rank,"x",x,R[i],R[j],D, dist[i][j]
                       	  R[i] += (x * fix) * D
                          R[j] -= (x * (1.0 - fix)) * D
                        else:
                          R[i] += [0.2, 0.0, 0.0]
                          R[j] -= [0.2, 0.0, 0.0] 
                        R2P = [R[i],R[j]]
                        dist2P=scipy.spatial.distance.cdist(R2P,R)       
                        dist[i] = dist2P[0]
                        dist[j] = dist2P[1]
                        for k in range(len(R)):
                            dist[k][i] = dist[i][k]
                            dist[k][j] = dist[j][k]
                      #  STR+='--- WARNING: Atoms too close (<0.7A) - Implement Move ---\n'
          closelist=list(set(closelist))
          closelist.sort()
          if len(closelist) != 0: 
             logger.info('M:iter {0}, closelist size {1}'.format(iter,len(closelist)))
         #    print "rank", rank, closelist
    else:
        print 'WARNING: In Check_Min_Dist in EvalEnergy: Structure Type not recognized'
    return totalsol, STR
Пример #51
0
class ANNCalculator(Calculator):
    def __init__(self, potentials, **kwargs):
        Calculator.__init__(self, **kwargs)
        self.ann = ANNPotentials(potentials)
        self.cutoff = self.ann.Rc_max
        self.cutoff2 = self.cutoff**2
        self.neighbors = None
        self.implemented_properties = {
            'energy': self.calculate_energy,
            'forces': self.calculate_energy_and_forces,
        }
        self.results = {}

    def __del__(self):
        try:
            del self.ann
        except (AttributeError, NameError):
            pass

    def release(self):
        del self.ann

    def update(self, atoms):

        if (self.neighbors is None) or (len(self.neighbors.cutoffs) !=
                                        len(atoms)):
            cutoffs = self.cutoff * np.ones(len(atoms))
            self.neighbors = NeighborList(cutoffs,
                                          self_interaction=False,
                                          bothways=True)
        self.neighbors.update(atoms)

    def calculate(self,
                  atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):

        # Calculator essentially does: self.atoms = atoms
        Calculator.calculate(self, atoms, properties, system_changes)

        has_results = [p in self.results for p in properties]
        if (len(system_changes) > 0) or (not np.all(has_results)):
            self.update(self.atoms)
            if ('energy' in properties) and ('forces' in properties):
                # Forces evaluation requires energy. No need to compute
                # energy twice.
                del properties[properties.index('energy')]
            for p in properties:
                if p in self.implemented_properties:
                    self.implemented_properties[p](self.atoms)
                else:
                    raise NotImplementedError(
                        "Property not implemented: {}".format(p))

    def calculate_energy(self, atoms):
        energy = 0.0
        atom_types = atoms.get_chemical_symbols()
        for i in range(len(atoms)):
            indices, offsets = self.neighbors.get_neighbors(i)
            type_i = atom_types[i]
            coords_i = atoms.positions[i]
            coords_j = np.empty((len(indices), 3), dtype=np.double)
            types_j = []
            inb = 0
            for j, offset in zip(indices, offsets):
                coo = (atoms.positions[j] + np.dot(offset, atoms.get_cell()))
                d2 = np.sum((coo - coords_i)**2)
                if d2 <= self.cutoff2:
                    coords_j[inb] = coo
                    types_j.append(atom_types[j])
                    inb += 1
            energy += self.ann.atomic_energy(coords_i, type_i, coords_j[:inb],
                                             types_j)
        self.results['energy'] = energy

    def calculate_energy_and_forces(self, atoms):
        energy = 0.0
        atom_types = atoms.get_chemical_symbols()
        forces = np.zeros((len(atoms), 3), dtype=np.double)
        for i in range(len(atoms)):
            indices, offsets = self.neighbors.get_neighbors(i)
            type_i = atom_types[i]
            index_i = i + 1
            index_j = np.empty(indices.size, dtype=np.intc)
            coords_i = atoms.positions[i]
            coords_j = np.empty((indices.size, 3), dtype=np.double)
            types_j = []
            inb = 0
            for j, offset in zip(indices, offsets):
                coo = (atoms.positions[j] + np.dot(offset, atoms.get_cell()))
                d2 = np.sum((coo - coords_i)**2)
                if d2 <= self.cutoff2:
                    coords_j[inb] = coo
                    index_j[inb] = j + 1
                    types_j.append(atom_types[j])
                    inb += 1
            energy += self.ann.atomic_energy_and_forces(
                coords_i, type_i, index_i, coords_j[:inb], types_j,
                index_j[:inb], forces)
        self.results['energy'] = energy
        self.results['forces'] = forces
Пример #52
0
class OPLSff:
    def __init__(self, fileobj=None, warnings=0):
        self.warnings = warnings
        self.data = {}
        if fileobj is not None:
            self.read(fileobj)

    def read(self, fileobj, comments='#'):
        if isinstance(fileobj, str):
            fileobj = open(fileobj)

        def read_block(name, symlen, nvalues):
            """Read a data block.

            name: name of the block to store in self.data
            symlen: length of the symbol
            nvalues: number of values expected
            """

            if name not in self.data:
                self.data[name] = {}
            data = self.data[name]

            def add_line():
                line = fileobj.readline().strip()
                if not len(line):  # end of the block
                    return False
                line = line.split('#')[0]  # get rid of comments
                if len(line) > symlen:
                    symbol = line[:symlen]
                    words = line[symlen:].split()
                    if len(words) >= nvalues:
                        if nvalues == 1:
                            data[symbol] = float(words[0])
                        else:
                            data[symbol] = [float(word)
                                            for word in words[:nvalues]]
                return True

            while add_line():
                pass
 
        read_block('one', 2, 3)
        read_block('bonds', 5, 2)
        read_block('angles', 8, 2)
        read_block('dihedrals', 11, 4)
        read_block('cutoffs', 5, 1)

        self.bonds = BondData(self.data['bonds'])
        self.angles = AnglesData(self.data['angles'])
        self.dihedrals = DihedralsData(self.data['dihedrals'])
        self.cutoffs = CutoffList(self.data['cutoffs'])

    def write_lammps(self, atoms, prefix='lammps'):
        """Write input for a LAMMPS calculation."""
        self.prefix = prefix

        if hasattr(atoms, 'connectivities'):
            connectivities = atoms.connectivities
        else:
            btypes, blist = self.get_bonds(atoms)
            atypes, alist = self.get_angles()
            dtypes, dlist = self.get_dihedrals(alist, atypes)
            connectivities = {
                'bonds': blist,
                'bond types': btypes,
                'angles': alist,
                'angle types': atypes,
                'dihedrals': dlist,
                'dihedral types': dtypes,
                }
            self.write_lammps_definitions(atoms, btypes, atypes, dtypes)
            self.write_lammps_in()
            
        self.write_lammps_atoms(atoms, connectivities)

    def write_lammps_in(self):
        fileobj = self.prefix + '_in'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')
        fileobj.write("""# LAMMPS relaxation (written by ASE)

units           metal
atom_style      full
boundary        p p p
#boundary       p p f

""")
        fileobj.write('read_data ' + self.prefix + '_atoms\n')
        fileobj.write('include  ' + self.prefix + '_opls\n')
        fileobj.write("""
kspace_style    pppm 1e-5
#kspace_modify  slab 3.0

neighbor        1.0 bin
neigh_modify    delay 0 every 1 check yes

thermo          1000
thermo_style    custom step temp press cpu pxx pyy pzz pxy pxz pyz ke pe etotal vol lx ly lz atoms

dump            1 all xyz 1000 dump_relax.xyz
dump_modify     1 sort id

restart         100000 test_relax

min_style       fire
minimize        1.0e-14 1.0e-5 100000 100000
""")
        fileobj.close()

    def write_lammps_atoms(self, atoms, connectivities):
        """Write atoms input for LAMMPS"""
        
        fname = self.prefix + '_atoms'
        fileobj = open(fname, 'w')

        # header
        fileobj.write(fileobj.name + ' (by ' + str(self.__class__) + ')\n\n')
        fileobj.write(str(len(atoms)) + ' atoms\n')
        fileobj.write(str(len(atoms.types)) + ' atom types\n')
        blist = connectivities['bonds']
        if len(blist):
            btypes = connectivities['bond types']
            fileobj.write(str(len(blist)) + ' bonds\n')
            fileobj.write(str(len(btypes)) + ' bond types\n')
        alist = connectivities['angles']
        if len(alist):
            atypes = connectivities['angle types']
            fileobj.write(str(len(alist)) + ' angles\n')
            fileobj.write(str(len(atypes)) + ' angle types\n')
        dlist = connectivities['dihedrals']
        if len(dlist):
            dtypes = connectivities['dihedral types']
            fileobj.write(str(len(dlist)) + ' dihedrals\n')
            fileobj.write(str(len(dtypes)) + ' dihedral types\n')

        # cell
        p = prism(atoms.get_cell())
        xhi, yhi, zhi, xy, xz, yz = p.get_lammps_prism_str()
        fileobj.write('\n0.0 %s  xlo xhi\n' % xhi)
        fileobj.write('0.0 %s  ylo yhi\n' % yhi)
        fileobj.write('0.0 %s  zlo zhi\n' % zhi)
        
        # atoms
        fileobj.write('\nAtoms\n\n')
        tag = atoms.get_tags()
        if atoms.has('molid'):
            molid = atoms.get_array('molid')
        else:
            molid = [1] * len(atoms)
        for i, r in enumerate(map(p.pos_to_lammps_str,
                                  atoms.get_positions())):
            q = self.data['one'][atoms.types[tag[i]]][2]
            fileobj.write('%6d %3d %3d %s %s %s %s' % ((i + 1, molid[i],
                                                        tag[i] + 1,
                                                        q)
                                                       + tuple(r)))
            fileobj.write(' # ' + atoms.types[tag[i]] + '\n')

        # velocities
        velocities = atoms.get_velocities()
        if velocities is not None:
            fileobj.write('\nVelocities\n\n')
            for i, v in enumerate(velocities):
                fileobj.write('%6d %g %g %g\n' %
                              (i + 1, v[0], v[1], v[2]))

        # masses
        fileobj.write('\nMasses\n\n')
        for i, typ in enumerate(atoms.types):
            cs = atoms.split_symbol(typ)[0]
            fileobj.write('%6d %g # %s -> %s\n' %
                          (i + 1,
                           atomic_masses[chemical_symbols.index(cs)],
                           typ, cs))
  
        # bonds
        if len(blist):
            fileobj.write('\nBonds\n\n')
            for ib, bvals in enumerate(blist):
                fileobj.write('%8d %6d %6d %6d ' %
                              (ib + 1, bvals[0] + 1, bvals[1] + 1,
                               bvals[2] + 1))
                try:
                    fileobj.write('# ' + btypes[bvals[0]])
                except:
                    pass
                fileobj.write('\n')

        # angles
        if len(alist):
            fileobj.write('\nAngles\n\n')
            for ia, avals in enumerate(alist):
                fileobj.write('%8d %6d %6d %6d %6d ' %
                              (ia + 1, avals[0] + 1,
                               avals[1] + 1, avals[2] + 1, avals[3] + 1))
                try:
                    fileobj.write('# ' + atypes[avals[0]])
                except:
                    pass
                fileobj.write('\n')

        # dihedrals
        if len(dlist):
            fileobj.write('\nDihedrals\n\n')
            for i, dvals in enumerate(dlist):
                fileobj.write('%8d %6d %6d %6d %6d %6d ' %
                              (i + 1, dvals[0] + 1,
                               dvals[1] + 1, dvals[2] + 1,
                               dvals[3] + 1, dvals[4] + 1))
                try:
                    fileobj.write('# ' + dtypes[dvals[0]])
                except:
                    pass
                fileobj.write('\n')

    def update_neighbor_list(self, atoms):
        cut = 0.5 * max(self.data['cutoffs'].values())
        self.nl = NeighborList([cut] * len(atoms), skin=0,
                               bothways=True, self_interaction=False)
        self.nl.update(atoms)
        self.atoms = atoms
    
    def get_bonds(self, atoms):
        """Find bonds and return them and their types"""
        cutoffs = CutoffList(self.data['cutoffs'])
        self.update_neighbor_list(atoms)

        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        bond_list = []
        bond_types = []
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indices, offsets = self.nl.get_neighbors(i)
            for j, offset in zip(indices, offsets):
                if j <= i:
                    continue  # do not double count
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    if self.warnings > 1:
                        print('Warning: cutoff %s-%s not found'
                              % (iname, jname))
                    continue  # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position
                                      - np.dot(offset, cell))
                if dist > cut:
                    continue  # too far away
                name, val = self.bonds.name_value(iname, jname)
                if name is None:
                    if self.warnings:
                        print('Warning: potential %s-%s not found'
                              % (iname, jname))
                    continue  # don't have it
                if name not in bond_types:
                    bond_types.append(name)
                bond_list.append([bond_types.index(name), i, j])
        return bond_types, bond_list
                
    def get_angles(self, atoms=None):
        cutoffs = CutoffList(self.data['cutoffs'])
        if atoms is not None:
            self.update_neighbor_list(atoms)
        else:
            atoms = self.atoms
         
        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()
        ang_list = []
        ang_types = []

        # center atom *-i-*
        for i, atom in enumerate(atoms):
            iname = types[tags[i]]
            indicesi, offsetsi = self.nl.get_neighbors(i)

            # search for first neighbor j-i-*
            for j, offsetj in zip(indicesi, offsetsi):
                jname = types[tags[j]]
                cut = cutoffs.value(iname, jname)
                if cut is None:
                    continue  # don't have it
                dist = np.linalg.norm(atom.position - atoms[j].position
                                      - np.dot(offsetj, cell))
                if dist > cut:
                    continue  # too far away

                # search for second neighbor j-i-k
                for k, offsetk in zip(indicesi, offsetsi):
                    if k <= j:
                        continue  # avoid double count
                    kname = types[tags[k]]
                    cut = cutoffs.value(iname, kname)
                    if cut is None:
                        continue  # don't have it
                    dist = np.linalg.norm(atom.position -
                                          np.dot(offsetk, cell) -
                                          atoms[k].position)
                    if dist > cut:
                        continue  # too far away
                    name, val = self.angles.name_value(jname, iname,
                                                       kname)
                    if name is None:
                        if self.warnings > 1:
                            print('Warning: angles %s-%s-%s not found'
                                  % (jname, iname, kname))
                        continue  # don't have it
                    if name not in ang_types:
                        ang_types.append(name)
                    ang_list.append([ang_types.index(name), j, i, k])

        return ang_types, ang_list

    def get_dihedrals(self, ang_types, ang_list):
        'Dihedrals derived from angles.'

        cutoffs = CutoffList(self.data['cutoffs'])

        atoms = self.atoms
        types = atoms.get_types()
        tags = atoms.get_tags()
        cell = atoms.get_cell()

        dih_list = []
        dih_types = []

        def append(name, i, j, k, l):
            if name not in dih_types:
                dih_types.append(name)
            index = dih_types.index(name)
            if (([index, i, j, k, l] not in dih_list) and
                ([index, l, k, j, i] not in dih_list)):
                dih_list.append([index, i, j, k, l])

        for angle in ang_types:
            l, i, j, k = angle
            iname = types[tags[i]]
            jname = types[tags[j]]
            kname = types[tags[k]]

            # search for l-i-j-k
            indicesi, offsetsi = self.nl.get_neighbors(i)
            for l, offsetl in zip(indicesi, offsetsi):
                if l == j:
                    continue # avoid double count
                lname = types[tags[l]]
                cut = cutoffs.value(iname, lname)
                if cut is None:
                    continue # don't have it
                dist = np.linalg.norm(atoms[i].position - atoms[l].position
                                      - np.dot(offsetl, cell))
                if dist > cut:
                    continue # too far away
                name, val = self.dihedrals.name_value(lname, iname,
                                                      jname, kname)
                if name is None:
                    continue # don't have it
                append(name, l, i, j, k)
              
            # search for i-j-k-l
            indicesk, offsetsk = self.nl.get_neighbors(k)
            for l, offsetl in zip(indicesk, offsetsk):
                if l == j:
                    continue # avoid double count
                lname = types[tags[l]]
                cut = cutoffs.value(kname, lname)
                if cut is None:
                    continue # don't have it
                dist = np.linalg.norm(atoms[k].position - atoms[l].position
                                      - np.dot(offsetl, cell))
                if dist > cut:
                    continue # too far away
                name, val = self.dihedrals.name_value(iname, jname,
                                                      kname, lname)
                if name is None:
                    continue # don't have it
                append(name, i, j, k, l)

        return dih_types, dih_list

    def write_lammps_definitions(self, atoms, btypes, atypes, dtypes):
        """Write force field definitions for LAMMPS."""

        fileobj = self.prefix + '_opls'
        if isinstance(fileobj, str):
            fileobj = open(fileobj, 'w')

        fileobj.write('# OPLS potential\n')
        fileobj.write('# write_lammps' +
                      str(time.asctime(
                    time.localtime(time.time()))))

        # bonds
        if len(btypes):
            fileobj.write('\n# bonds\n')
            fileobj.write('bond_style      harmonic\n')
            for ib, btype in enumerate(btypes):
                fileobj.write('bond_coeff %6d' % (ib + 1))
                for value in self.bonds.nvh[btype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + btype + '\n')

        # angles
        if len(atypes):
            fileobj.write('\n# angles\n')
            fileobj.write('angle_style      harmonic\n')
            for ia, atype in enumerate(atypes):
                fileobj.write('angle_coeff %6d' % (ia + 1))
                for value in self.angles.nvh[atype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + atype + '\n')

        # dihedrals
        if len(dtypes):
            fileobj.write('\n# dihedrals\n')
            fileobj.write('dihedral_style      opls\n')
            for i, dtype in enumerate(dtypes):
                fileobj.write('dihedral_coeff %6d' % (i + 1))
                for value in self.dihedrals.nvh[dtype]:
                    fileobj.write(' ' + str(value))
                fileobj.write(' # ' + dtype + '\n')

        # Lennard Jones settings
        fileobj.write('\n# L-J parameters\n')
        fileobj.write('pair_style lj/cut/coul/long 10.0 7.4' +
                      ' # consider changing these parameters\n')
        fileobj.write('special_bonds lj/coul 0.0 0.0 0.5\n')
        data = self.data['one']
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('pair_coeff ' + str(ia + 1) + ' ' + str(ia + 1))
            for value in data[atype][:2]:
                fileobj.write(' ' + str(value))
            fileobj.write(' # ' + atype + '\n')
        fileobj.write('pair_modify shift yes mix geometric\n')

        # Charges
        fileobj.write('\n# charges\n')
        for ia, atype in enumerate(atoms.types):
            if len(atype) < 2:
                atype = atype + ' '
            fileobj.write('set type ' + str(ia + 1))
            fileobj.write(' charge ' + str(data[atype][2]))
            fileobj.write(' # ' + atype + '\n')
Пример #53
0
                nl2 = NeighborList(atoms2.numbers * 0.2 + 0.5,
                                   skin=0.0, sorted=sorted)
                nl2.update(atoms2)
                d2, c2 = count(nl2, atoms2)
                c2.shape = (-1, 10)
                dd = d * (p1 + 1) * (p2 + 1) * (p3 + 1) - d2
                print(dd)
                print(c2 - c)
                assert abs(dd) < 1e-10
                assert not (c2 - c).any()

h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)])
nl = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False)
assert nl.update(h2)
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert not nl.update(h2)
assert (nl.get_neighbors(0)[0] == [1]).all()

h2[1].z += 0.09
assert nl.update(h2)
assert (nl.get_neighbors(0)[0] == []).all()
assert nl.nupdates == 2

x = bulk('X', 'fcc', a=2**0.5)
print(x)

nl = NeighborList([0.5], skin=0.01, bothways=True, self_interaction=False)
nl.update(x)
Пример #54
0
def create_stucture(ratio, width, edge, key='top', a=1.42):

    vacuum = 10
    length = get_length(ratio, width, edge)
    length_b = int(length * .8) * 2
    width_b = width * 4

    if edge == 'zz':
        orig = [np.sqrt(3) * a, 2 * a]  # -> AB-stacking
        b_l, b_w = 4, 3 * width
        if width % 2 == 1: raise
    if edge == 'ac':
        orig = [2 * a, np.sqrt(3) * a]  # -> AB-stacking
        b_l, b_w = 2, 3 * width
        if width % 2 == 0: raise

    bottom = graphene_nanoribbon2(length_b,
                                  width_b,
                                  edge_type=edge,
                                  saturated=False,
                                  C_H=1.09,
                                  C_C=a,
                                  vacuum=2.5,
                                  sheet=False,
                                  main_element='C',
                                  saturate_element='H')

    top = graphene_nanoribbon2(length,
                               width,
                               edge_type=edge,
                               saturated=True,
                               C_H=1.09,
                               C_C=a,
                               vacuum=2.5,
                               sheet=False,
                               main_element='C',
                               saturate_element='H')

    base = graphene_nanoribbon2(b_l,
                                b_w,
                                edge_type=edge,
                                saturated=True,
                                C_H=1.09,
                                C_C=a,
                                vacuum=2.5,
                                sheet=False,
                                main_element='C',
                                saturate_element='H')

    if key == 'top_bottom':
        top.translate([orig[0], orig[1], 3.4])
        atoms = bottom
        atoms.extend(top)
        atoms.cell = [bottom.cell[0, 0], bottom.cell[1, 1], 2 * vacuum + 3.4]
        atoms.center()
        atoms.pbc = [True, True, False]

        #view(atoms)
        return atoms

    if key == 'top':
        atoms = top
        L, W = top.cell[0, 0], top.cell[1, 1]
        atoms.cell = [
            top.cell[0, 0] * 1.5, 2 * top.cell[0, 0] + top.cell[1, 1],
            2 * vacuum
        ]
        atoms.center()
        atoms.positions[:, 2] = 3.4
        atoms.pbc = [False, False, False]
        return atoms, L, W, length, None

    if key == 'rib+base':

        if edge == 'zz':
            base.translate([-base.cell[0, 0], -base.cell[1, 1] / 3, 0])
        if edge == 'ac':
            base.translate([
                -base.cell[0, 0], -base.cell[1, 1] / 3 + np.sqrt(3) / 2. * a, 0
            ])

        atoms = top + base

        rads = np.ones(len(atoms)) * .3
        nl = NeighborList(rads, self_interaction=False, bothways=True)
        nl.update(atoms)

        coll = []
        for i, atom in enumerate(atoms):
            if atom.number == 1:
                if 1 < len(nl.get_neighbors(i)[0]):
                    for j in nl.get_neighbors(i)[0]:
                        if atoms.numbers[j] == 1:
                            coll.append(j)
        del atoms[coll]

        atoms_base = []
        for i, atom in enumerate(atoms):
            if atom.position[0] < 0:
                atoms_base.append(i)

        rads = np.ones(len(atoms)) * .7
        nl = NeighborList(rads, self_interaction=False, bothways=True)
        nl.update(atoms)

        new_pos = []
        for i, atom in enumerate(atoms):
            if len(nl.get_neighbors(i)
                   [0]) == 2 and atom.number == 6 and i not in atoms_base:
                pos = np.zeros(3)
                for j in nl.get_neighbors(i)[0]:
                    pos += atoms.positions[j] - atoms.positions[i]
                    if atoms.numbers[j] != 6: raise
                new_pos.append(atoms.positions[i] - pos)

        for pos in new_pos:
            atoms += Atom('C', position=pos)

        rads = np.ones(len(atoms)) * .7
        nl = NeighborList(rads, self_interaction=False, bothways=True)
        nl.update(atoms)

        h_pos = []
        for i, atom in enumerate(atoms):
            if len(nl.get_neighbors(i)[0]) == 2 and atom.number == 6:
                pos = np.zeros(3)
                for j in nl.get_neighbors(i)[0]:
                    pos += atoms.positions[j] - atoms.positions[i]
                    if atoms.numbers[j] != 6: raise
                pos = pos / np.linalg.norm(pos)

                h_pos.append(atoms.positions[i] - pos)

        for pos in h_pos:
            atoms += Atom('H', position=pos)

        L, W = top.cell[0, 0], top.cell[1, 1]

        atoms.cell = [
            top.cell[0, 0] * 1.5, 2 * top.cell[0, 0] + top.cell[1, 1],
            2 * vacuum
        ]
        atoms.center()
        atoms.positions[:, 2] = 3.4
        atoms.pbc = [False, False, False]
        return atoms, L, W, length, atoms_base