def __init__(self, filename): atoms = ase.io.read(filename, format='vasp') cell = atoms.get_cell() symb = atoms.get_atomic_numbers() cutoffs = np.ones( (len(atoms) )) * 1.35 # radius around each atom (half the max bondlength) nl = NeighborList(cutoffs, 0., self_interaction=False, bothways=False) nl.update(atoms) std_len = 2.35805097505 # Loop over atoms bond_no = 0 bonds = np.zeros((nl.nneighbors, 4)) for atom1idx, (indices, offsets, atom1pos) in enumerate( zip(nl.neighbors, nl.displacements, nl.positions)): # Loop over bonds for atom2idx, offset in zip(indices, offsets): #if symb[atom1idx] == symb[atom2idx] == 'Si': atom2pos = nl.positions[atom2idx] + np.dot(offset, cell) #print "pos[%i] = %.2f %.2f %.2f" % (atom1idx, atom1pos[0],atom1pos[1],atom1pos[2]) #print "pos[%i] = %.2f %.2f %.2f" % (atom2idx, atom2pos[0],atom2pos[1],atom2pos[2]) bond = atom2pos - atom1pos bond_center = atom1pos + bond / 2. bond_z = bond_center[2] bondlength = np.sqrt(np.dot(bond, bond)) bonds[bond_no] = [ bond_z, bondlength, symb[atom1idx], symb[atom2idx] ] bond_no += 1 self.bonds = bonds print bonds
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
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!")
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_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
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 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
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:]
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 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.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.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]]
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)
def buildNeighborList(self): atoms = self.atoms nl = NeighborList([0.8 for atom in atoms], self_interaction=False, bothways=True) nl.update(atoms) self.nl = nl neigh = [] for i in range(self.natom): neigh.append(self.sort_nei(i)) # print neigh[i] self.neigh = neigh
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
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
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
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
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:
print 'bulk reference len=%d cell=%r' % (len(bulk), bulk.cell) bulk *= (N, N, N) 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
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
C[5, 5] = 47.5 * GPa # Surface energy computed with DFT (PBE-GGA) surface_energy = 0.161 * (J / m**2) * 10 a = atoms.copy() b = a * [nx, 1, 1] b.center() b.positions[:, 0] += 0.5 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:
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
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
d = 0.0 for a in range(len(atoms)): i, offsets = nl.get_neighbors(a) for j in i: c[j] += 1 c[a] += len(i) d += (((R[i] + np.dot(offsets, cell) - R[a])**2).sum(1)**0.5).sum() return d, c for sorted in [False, True]: for p1 in range(2): for p2 in range(2): for p3 in range(2): print p1, p2, p3 atoms.set_pbc((p1, p2, p3)) 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)])
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)
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
def newoverlap(wfs, spos_ac): assert wfs.ksl.block_comm.size == wfs.gd.comm.size * wfs.bd.comm.size even_part = EvenPartitioning( wfs.gd.comm, #wfs.ksl.block_comm, len(wfs.atom_partition.rank_a)) atom_partition = even_part.as_atom_partition() tci = wfs.tci gd = wfs.gd kd = wfs.kd nq = len(kd.ibzk_qc) # New neighbor list because we want it "both ways", heh. Or do we? neighbors = NeighborList(tci.cutoff_a, skin=0, sorted=True, self_interaction=True, bothways=False) atoms = Atoms('X%d' % len(tci.cutoff_a), cell=gd.cell_cv, pbc=gd.pbc_c) atoms.set_scaled_positions(spos_ac) neighbors.update(atoms) # XXX pcutoff_a = [] phicutoff_a = [] for setup in wfs.setups: if setup.pt_j: pcutoff = max([pt.get_cutoff() for pt in setup.pt_j]) else: pcutoff = 0.0 if setup.phit_j: phicutoff = max([phit.get_cutoff() for phit in setup.phit_j]) else: phicutoff = 0.0 pcutoff_a.append(pcutoff) phicutoff_a.append(phicutoff) # Calculate the projector--basis function overlaps: # # a1 ~a1 # P = < p | Phi > , # i mu i mu # # i.e. projector is on a1 and basis function is on what we will call a2. overlapcalc = TwoCenterIntegralCalculator(wfs.kd.ibzk_qc, derivative=False) P_aaqim = {} # keys: (a1, a2). Values: matrix blocks dists_and_offsets = DistsAndOffsets(neighbors, spos_ac, gd.cell_cv) #ng = 2**extra_parameters.get('log2ng', 10) #transformer = FourierTransformer(rcmax, ng) #tsoc = TwoSiteOverlapCalculator(transformer) #msoc = ManySiteOverlapCalculator(tsoc, I_a, I_a) msoc = wfs.tci.msoc phit_Ij = [setup.phit_j for setup in tci.setups_I] l_Ij = [] for phit_j in phit_Ij: l_Ij.append([phit.get_angular_momentum_number() for phit in phit_j]) pt_l_Ij = [setup.l_j for setup in tci.setups_I] pt_Ij = [setup.pt_j for setup in tci.setups_I] phit_Ijq = msoc.transform(phit_Ij) pt_Ijq = msoc.transform(pt_Ij) #self.Theta_expansions = msoc.calculate_expansions(l_Ij, phit_Ijq, # l_Ij, phit_Ijq) #self.T_expansions = msoc.calculate_kinetic_expansions(l_Ij, phit_Ijq) P_expansions = msoc.calculate_expansions(pt_l_Ij, pt_Ijq, l_Ij, phit_Ijq) P_neighbors_a = {} for a1 in atom_partition.my_indices: for a2 in range(len(wfs.setups)): R_ca_and_offset_a = dists_and_offsets.get(a1, a2) if R_ca_and_offset_a is None: # No overlap between a1 and a2 continue maxdistance = pcutoff_a[a1] + phicutoff_a[a2] expansion = P_expansions.get(a1, a2) P_qim = expansion.zeros((nq, ), dtype=wfs.dtype) disp = None for R_c, offset in R_ca_and_offset_a: r = np.linalg.norm(R_c) if r > maxdistance: continue # Below lines are meant to make use of symmetry. Will not # be relevant for P. #remainder = (a1 + a2) % 2 #if a1 < a2 and not remainder: # continue # if a1 > a2 and remainder: # continue phases = overlapcalc.phaseclass(overlapcalc.ibzk_qc, offset) disp = AtomicDisplacement(None, a1, a2, R_c, offset, phases) disp.evaluate_overlap(expansion, P_qim) if disp is not None: # there was at least one non-zero overlap assert (a1, a2) not in P_aaqim P_aaqim[(a1, a2)] = P_qim P_neighbors_a.setdefault(a1, []).append(a2) Pkeys = P_aaqim.keys() Pkeys.sort() def get_M1M2(a): M1 = wfs.setups.M_a[a] M2 = M1 + wfs.setups[a].nao return M1, M2 oldstyle_P_aqMi = None if 0: #wfs.world.size == 1: oldstyle_P_aqMi = {} for a, setup in enumerate(wfs.setups): oldstyle_P_aqMi[a] = np.zeros((nq, wfs.setups.nao, setup.ni), dtype=wfs.dtype) print([(s.ni, s.nao) for s in wfs.setups]) for a1, a2 in Pkeys: M1, M2 = get_M1M2(a2) Pconj_qmi = P_aaqim[(a1, a2)].transpose(0, 2, 1).conjugate() oldstyle_P_aqMi[a1][:, M1:M2, :] = Pconj_qmi # XXX mind distribution return P_neighbors_a, P_aaqim, oldstyle_P_aqMi
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
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)