def test_supercell(): atoms = Atoms(numbers=range(10), cell=[(0.2, 1.2, 1.4), (1.4, 0.1, 1.6), (1.3, 2.0, -0.1)]) atoms.set_scaled_positions(3 * random.random((10, 3)) - 1) 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 assert abs(dd) < 1e-10 assert not (c2 - c).any()
def test_H2(): h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)]) nl = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False) nl2 = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False, primitive=NewPrimitiveNeighborList) assert nl2.update(h2) assert nl.update(h2) assert not nl.update(h2) assert (nl.get_neighbors(0)[0] == [1]).all() m = np.zeros((2, 2)) m[0, 1] = 1 assert np.array_equal(nl.get_connectivity_matrix(sparse=False), m) assert np.array_equal(nl.get_connectivity_matrix(sparse=True).todense(), m) assert np.array_equal(nl.get_connectivity_matrix().todense(), nl2.get_connectivity_matrix().todense()) 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
def gfx_queue_bonds(self): fa = self.get_frame_atoms() ra = fa.repeat( (int(self.repeatx.get_value()), int(self.repeaty.get_value()), int(self.repeatz.get_value()))) if not 'nlist' in fa.__dict__: cutoffs = [1.5 * elements[i.symbol]['radius'] for i in ra] fa.nlist = NeighborList(cutoffs, skin=0, self_interaction=False, bothways=True) if len(fa.nlist.nl.cutoffs) != len(ra): cutoffs = [1.5 * elements[i.symbol]['radius'] for i in ra] fa.nlist = NeighborList(cutoffs, skin=0, self_interaction=False, bothways=True) fa.nlist.update(ra) for a in range(len(ra)): element = elements[ra[a].symbol] indices, offsets = fa.nlist.get_neighbors(a) for i, o in zip(indices, offsets): r = ra.positions[i] + np.dot(o, ra.get_cell()) v = r - ra.positions[a] vm = np.linalg.norm(v) vunit = v / vm rad = 0.5 * element['radius'] * self.radiusbutton.get_value() p1 = ra.positions[a] + vunit * rad p2 = ra.positions[a] + v * 0.5 self.gfx_queue_line(p1, p2, [c * 0.85 for c in element['color']], width=self.bond_width)
def test_fcc(): x = bulk('X', 'fcc', a=2**0.5) nl = NeighborList([0.5], skin=0.01, bothways=True, self_interaction=False) nl.update(x) assert len(nl.get_neighbors(0)[0]) == 12 nl = NeighborList([0.5] * 27, skin=0.01, bothways=True, self_interaction=False) nl.update(x * (3, 3, 3)) for a in range(27): assert len(nl.get_neighbors(a)[0]) == 12 assert not np.any(nl.get_neighbors(13)[1]) c = 0.0058 for NeighborListClass in [PrimitiveNeighborList, NewPrimitiveNeighborList]: nl = NeighborListClass([c, c], skin=0.0, sorted=True, self_interaction=False, use_scaled_positions=True) nl.update([True, True, True], np.eye(3) * 7.56, np.array([[0, 0, 0], [0, 0, 0.99875]])) n0, d0 = nl.get_neighbors(0) n1, d1 = nl.get_neighbors(1) # != is xor assert (np.all(n0 == [0]) and np.all(d0 == [0, 0, 1])) != \ (np.all(n1 == [1]) and np.all(d1 == [0, 0, -1]))
def add_cap_ox(clust): # TODO: fix bug where adds multiple oxygen's to the same place """ Args: clust: """ nl = NeighborList(natural_cutoffs(clust), bothways=True, self_interaction=False) nl.update(clust) new_clust = clust cap_inds = get_cap_si(clust) for ind in cap_inds: while len(nl.get_neighbors(ind)[0]) < 4: neighb = nl.get_neighbors(ind)[0][ -1] # last index in the list of neighbor indicies direction = clust.get_positions()[ind] - clust.get_positions()[ neighb] # vector pointing from neighbor to Si ox_pos = clust.get_positions( )[ind] + 1.6 * direction / np.linalg.norm(direction) new_ox = Atom('O', position=ox_pos) new_clust.append(new_ox) nl = NeighborList(natural_cutoffs(clust), bothways=True, self_interaction=False) nl.update(clust) return (new_clust)
def test_small_cell_and_large_cutoff(): # See: https://gitlab.com/ase/ase/-/issues/441 cutoff = 50 atoms = bulk('Cu', 'fcc', a=3.6) atoms *= (2, 2, 2) atoms.set_pbc(False) radii = cutoff * np.ones(len(atoms.get_atomic_numbers())) neighborhood_new = NeighborList(radii, skin=0.0, self_interaction=False, bothways=True, primitive=NewPrimitiveNeighborList) neighborhood_old = NeighborList(radii, skin=0.0, self_interaction=False, bothways=True, primitive=PrimitiveNeighborList) neighborhood_new.update(atoms) neighborhood_old.update(atoms) n0, d0 = neighborhood_new.get_neighbors(0) n1, d1 = neighborhood_old.get_neighbors(0) assert np.all(n0 == n1) assert np.all(d0 == d1)
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.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_Z_TM(self, atoms, d_Z_TM, TM_type): # todo: improve flexibility to allow Z-TM-H or Z-TM-OH insertions while avoid overlapping nl = NeighborList(natural_cutoffs(atoms), bothways=True, self_interaction=False) nl.update(atoms) index_Al = [a.index for a in atoms if a.symbol == 'Al'] indices, offsets = nl.get_neighbors(index_Al[0]) indices = [val for val in indices if atoms[val].symbol == 'O'] assert len(indices) == 4 dict_Z_TM = {} original_atoms = copy.copy(atoms) pairs = list(itertools.combinations(indices, 2)) for i, pair in enumerate(pairs): atoms = copy.copy(original_atoms) v = self._get_direction_of_insertion(atoms, index_Al[0], pair[0], pair[1], tag='TM') atoms = atoms + Atoms( TM_type, positions=[atoms[index_Al[0]].position] + v * d_Z_TM) atoms.wrap() key_tag = 'O' + str(pair[0]) + '_O' + str(pair[1]) dict_Z_TM[key_tag] = atoms return dict_Z_TM
def all_connected_to(id_atom, atoms, exclude): cov_radii = [covalent_radii[a.number] for a in atoms] atoms.set_pbc([False, False, False]) nl_no_pbc = NeighborList(cov_radii, bothways=True, self_interaction=False) nl_no_pbc.update(atoms) atoms.set_pbc([True, True, True]) tofollow = [] followed = [] isconnected = [] tofollow.append(id_atom) isconnected.append(id_atom) while len(tofollow) > 0: indices, offsets = nl_no_pbc.get_neighbors(tofollow[0]) indices = list(indices) followed.append(tofollow[0]) for i in indices: if (i not in isconnected) and (atoms[i].symbol not in exclude): tofollow.append(i) isconnected.append(i) for i in followed: if i in tofollow: ### do not remove this check tofollow.remove(i) #try: # tofollow.remove(i) #except: # pass # return isconnected
def get_donor_vec(self, donor_index): """finds direction of lone pair electrons on an adsorbate donor atom :return: vector direction of donor atoms Args: donor_index: """ nl = NeighborList(natural_cutoffs(self), self_interaction=False, bothways=True) nl.update(self) # gets neighbors of donor atom and adds the vectors from neighbor to donor # for most donor atoms this is roughly in the proper binding direction donor_neighbors = nl.get_neighbors(donor_index)[0] # neighbor's index donor_vec = np.array([0, 0, 0]) for i in donor_neighbors: a = self.get_distance(i, donor_index, vector=True) donor_vec = donor_vec + a if np.linalg.norm(donor_vec) == 0: warnings.warn( "donor vector with magnitude 0 found, providing default vector" ) return np.array([1, 0, 0]) donor_vec = donor_vec / np.linalg.norm( donor_vec) # normalizes donor vec return donor_vec
def main(): args = sys.argv imgs = read(args[1], index="::40") #layers = find_layers(atoms.copy()) traj = Trajectory('traj.traj','w') H_indices = random.sample([a.index for a in imgs[0] if a.symbol == 'H'],8) n_img = 0 for atoms in imgs: nl=NeighborList([2.5/2]*len(atoms), self_interaction=False, bothways=True) nl.update(atoms) pair_selected = [] for H_index in H_indices: nl_indices, nl_offsets = nl.get_neighbors(H_index) pair_selected.append([H_index, random.sample(nl_indices, 1)[0]]) for HPd_dist in [1.0, 1.1, 1.2, 1.3, 1.4]: img = atoms.copy() for pair in pair_selected: H_index = pair[0] Pd_selected = pair[1] v = atoms[H_index].position - atoms[Pd_selected].position vn = v/np.linalg.norm(v) del img[H_index] img.append(Atom('H',atoms[Pd_selected].position + vn * HPd_dist)) traj.write(img) print n_img n_img+=1
def add_pairwise(self, properties): positions = self.atoms.get_positions() mcut = 0.0 lcut = 2.5 if self.pwiter: N = positions.shape[0] self.nl = NeighborList(np.full(N, mcut / 2.0), skin=0.25, self_interaction=False) self.Xn = np.zeros((N, 0, 3), dtype=np.float64) self.Dn = np.zeros((N, 0, 3), dtype=np.float64) self.pwiter = False #start_time = time.time() self.nl.update(self.atoms) Epairwise = 0.0 if 'forces' in properties: Fpairwise = 0. * positions # loop over all atoms in the cell for ia, posa in enumerate(positions): indices, offsets = self.nl.get_neighbors(ia) #print('Neh/Dsp:', indices.shape, offsets.shape) #nposition = positions[indices] R = positions[indices] + np.dot( offsets, self.atoms.get_cell()) - posa[np.newaxis, :] Rmag = np.linalg.norm(R, axis=1) cidx = np.where((Rmag >= lcut) & (Rmag < mcut)) sidx = np.where(Rmag >= mcut) E = self.Efunc(Rmag) Ecut = coscut(Rmag[cidx], 1.0 / (mcut - lcut), lcut) #Ecut = tanhcut(Rmag[cidx], lcut-0.1*lcut) E[cidx] = E[cidx] * Ecut E[sidx] = 0.0 * E[sidx] Epairwise += E.sum( ) # Neighbors list supplies only neighbors once (NO DOUBLE COUNT) if 'forces' in properties: F = self.Ffunc(Rmag[:, np.newaxis], R) F[cidx] = (E[cidx][:, np.newaxis] * dcoscut(Rmag[cidx][:, np.newaxis], R[cidx], 1.0 / (mcut - lcut), lcut) + Ecut[:, np.newaxis] * F[cidx]) #F[cidx] = (E[cidx][:,np.newaxis]*dtanhcut(Rmag[cidx][:,np.newaxis], R[cidx], lcut-0.1*lcut)+Ecut[:,np.newaxis]*F[cidx]) F[sidx] = 0.0 * F[sidx] Fpairwise[indices] += -F Fpairwise[ia] += np.sum(F, axis=0) self.results['energy'] += Epairwise self.Epwise = Epairwise if 'forces' in properties: #print(Fpairwise.shape,np.sum(Fpairwise, axis=1)) #print(Fpairwise[0]) self.results['forces'] += Fpairwise
def find_tmpo(atoms): """ Args: atoms: """ tmpo_indices = [] p_index = None for a in atoms: if a.symbol == 'P': p_index = a.index break tmpo_indices.append(p_index) if p_index is None: return tmpo_indices nl = NeighborList(natural_cutoffs(atoms), bothways=True, self_interaction=False) nl.update(atoms) p_nl = nl.get_neighbors(p_index)[0] tmpo_indices.extend(p_nl) for i in p_nl: if atoms[i].symbol == 'C': tmpo_indices.extend(nl.get_neighbors(i)[0]) return tmpo_indices
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 get_rdf(atoms, a, rs, dr, rmax, nl=None): """number of atoms in a shell between r and r+dr centered around atom a and normalized by the shell volume. The number of atoms are devided into types according to their atomic number. """ V_r = get_shell_volume(rs, dr) if nl is None: cutoffs = [ rmax / 2 + 0.1, ] * len(atoms) nl = NeighborList(cutoffs=cutoffs, skin=0, self_interaction=False, bothways=True) nl.update(atoms) cluster = get_cluster(atoms, a=a, nl=nl) # first atom in the cluser -> a=0 zs = set(atoms.get_chemical_symbols()) p = dict([[z, np.zeros(len(rs))] for z in zs]) for ir, r in enumerate(rs): shell = get_shell(atoms=cluster, r=r, dr=dr, a=0) zs_shell, count = np.unique(shell.get_chemical_symbols(), return_counts=True) zc = dict([(z, c) for z, c in zip(zs_shell, count)]) for z in zs: if z in zc: p[z][ir] = zc[z] else: p[z][ir] = 0 for z in zs: p[z] /= V_r return p
def main(): imgs = read('train.traj', index='0::10', format='traj') natoms = len(imgs[0]) cutoff = 3.3 mindist = 2.7 traj = Trajectory('traj.traj', 'w') for atoms in imgs: nl = NeighborList([cutoff / 2] * len(atoms), self_interaction=False, bothways=False) nl.update(atoms) neighbor_info = {} n_pairs = 0 for i in range(natoms): i_indices, i_offsets = nl.get_neighbors(i) neighbor_info[i] = i_indices n_pairs += len(i_indices) print len(i_indices) #randomvalues=np.random.random((n_pairs,)) + mindist randomvalues = np.random.normal(mindist, 0.5, (n_pairs, )) pullcloser = {} pointer = 0 for key in neighbor_info.keys(): pullcloser[key] = randomvalues[pointer:len(neighbor_info[key]) + pointer:1] pointer += len(neighbor_info[key]) atoms.set_positions( pull_closer(atoms.get_positions(), neighbor_info, pullcloser)) #write('CONTCAR',atoms,format='vasp') traj.write(atoms)
def test0(self): """check one-way neighborlist for fcc on different repeats.""" a = 3.6 for rep in ((1, 1, 1), (2, 1, 1), (1, 2, 1), (1, 1, 2), (1, 2, 2), (2, 1, 1), (2, 2, 1), (2, 2, 2), (1, 2, 3), (4, 1, 1)): for cutoff_radius in np.linspace(a / 2.1, 5 * a, 5): atoms = bulk('Cu', 'fcc', a=a).repeat(rep) # It is important to rattle the atoms off the lattice points. # Otherwise, float tolerances makes it hard to count correctly. atoms.rattle(0.02) nl = NeighborList( [cutoff_radius / 2] * len(atoms), skin=0.0, self_interaction=False, bothways=False) nl.update(atoms) neighbors, displacements = get_neighbors_oneway( atoms.positions, atoms.cell, cutoff_radius, skin=0.0) for i in range(len(atoms)): an, ad = nl.get_neighbors(i) # Check the same number of neighbors self.assertEqual(len(neighbors[i]), len(an)) # Check the same indices self.assertCountEqual(neighbors[i], an)
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.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) self.coordination = np.zeros((self.images.natoms), dtype=int) if nb == 0: return n1 = 0 for a in range(self.images.natoms): indices, offsets = nl.get_neighbors(a) self.coordination[a] += len(indices) for a2 in indices: self.coordination[a2] += 1 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 get_color_scalars(self, frame=None): if self.colormode == 'tag': return self.atoms.get_tags() if self.colormode == 'force': f = (self.get_forces()**2).sum(1)**0.5 return f * self.images.get_dynamic(self.atoms) elif self.colormode == 'velocity': return (self.atoms.get_velocities()**2).sum(1)**0.5 elif self.colormode == 'initial charge': return self.atoms.get_initial_charges() elif self.colormode == 'magmom': return get_magmoms(self.atoms) elif self.colormode == 'neighbors': from ase.neighborlist import NeighborList n = len(self.atoms) nl = NeighborList(self.get_covalent_radii(self.atoms) * 1.5, skin=0, self_interaction=False, bothways=True) nl.update(self.atoms) return [len(nl.get_neighbors(i)[0]) for i in range(n)] else: scalars = np.array(self.atoms.get_array(self.colormode), dtype=float) return np.ma.array(scalars, mask=np.isnan(scalars))
def generate_normals(atoms, surface_normal=0.5, normalize_final=True, adsorbate_atoms=[]): normals = np.zeros(shape=(len(atoms), 3), dtype=float) atoms = atoms.copy() del atoms[adsorbate_atoms] cutoffs = natural_cutoffs(atoms) nl = NeighborList(cutoffs, self_interaction=False, bothways=True) nl.update(atoms) cell = atoms.get_cell() for index, atom in enumerate(atoms): normal = np.array([0, 0, 0], dtype=float) for neighbor, offset in zip(*nl.get_neighbors(index)): direction = atom.position - relative_position( atoms, neighbor, offset) normal += direction if norm(normal) > surface_normal: normals[index, :] = normalize( normal) if normalize_final else normal surface_mask = [ index for index in range(len(atoms)) if norm(normals[index]) > 1e-5 ] return normals, surface_mask
def get_external_internal(atoms, symbols=None): # Atoms to include in external and internal indices if symbols is None: symbols = list(set(atoms.symbols)) try: symbols.pop(symbols.index('H')) except ValueError as e: print(e) # symbols = list(symbols) # Define list of neighbors cov_radii = [covalent_radii[a.number] for a in atoms] nl = NeighborList(cov_radii, bothways=True, self_interaction=False) nl.update(atoms) external_i = [] internal_i = [] for a in atoms: if a.symbol not in symbols: continue nlist = nl.get_neighbors(a.index)[0] n_is_H = [True if atoms[n0].symbol == 'H' else False for n0 in nlist] if any(n_is_H): external_i.append(a.index) else: internal_i.append(a.index) return external_i, internal_i
def ase_connectivity(atoms, cutoffs=None, count_bonds=True): """Return a connectivity matrix calculated of an atoms object. If no neighborlist or connectivity matrix is attached to the atoms object, a new one will be generated. Multiple connections are counted. Parameters ---------- atoms : object An ase atoms object. cutoffs : list A list of cutoff radii for the atoms, ordered by atom index. Returns ------- conn : array An n by n, where n is len(atoms). """ if hasattr(atoms, 'neighborlist'): nl = atoms.neighborlist else: nl = NeighborList(cutoffs=cutoffs, bothways=True) nl.update(atoms) conn_mat = nl.get_connectivity_matrix(sparse=False) np.fill_diagonal(conn_mat, 0) return np.asarray(conn_mat, dtype=int)
def find_layers(atoms): cutoff = 3.2 nlayer = 0 layers = {} while True: if len(atoms) == 0: break nl=NeighborList([cutoff/2]*len(atoms), self_interaction=False, bothways=True) nl.update(atoms) com=atoms.get_center_of_mass() core = [] for i in range(len(atoms)): #first_layer (most outer layer) i_indices, i_offsets = nl.get_neighbors(i) if i==13 or i==15 or i==3: print i, len(i_indices) if len(i_indices) < 10: if nlayer not in layers.keys(): layers[nlayer] = [i] else: layers[nlayer].append(i) else: core.append(i) #layers[nlayer].sort(reverse=True) shell = atoms.copy() del shell[core] del atoms[layers[nlayer]] write('shell_'+str(nlayer)+'.xyz',shell,format='xyz') write('core_'+str(nlayer)+'.xyz',atoms,format='xyz') layers[nlayer].append(shell.copy()) print nlayer print " ",layers[nlayer] nlayer += 1 return layers
def ase_neighborlist(atoms, cutoffs=None): """Make dict of neighboring atoms using ase function. This provides a wrapper for the ASE neighborlist generator. Currently default values are used. Parameters ---------- atoms : object Target ase atoms object on which to get neighbor list. cutoffs : list A list of radii for each atom in atoms. rtol : float The tolerance factor to allow for small variation in the cutoff radii. Returns ------- neighborlist : dict A dictionary containing the atom index and each neighbor index. """ if cutoffs is None: cutoffs = [get_radius(a.number) for a in atoms] nl = NeighborList( cutoffs, skin=0., sorted=False, self_interaction=False, bothways=True) nl.update(atoms) neighborlist = {} for i, _ in enumerate(atoms): neighborlist[i] = sorted(list(map(int, nl.get_neighbors(i)[0]))) return neighborlist
def get_bonds(atoms, covalent_radii): from ase.neighborlist import NeighborList nl = NeighborList(covalent_radii * 1.5, skin=0, self_interaction=False) nl.update(atoms) nbonds = nl.nneighbors + nl.npbcneighbors bonds = np.empty((nbonds, 5), int) if nbonds == 0: return bonds n1 = 0 for a in range(len(atoms)): indices, offsets = nl.get_neighbors(a) n2 = n1 + len(indices) bonds[n1:n2, 0] = a bonds[n1:n2, 1] = indices bonds[n1:n2, 2:] = offsets n1 = n2 i = bonds[:n2, 2:].any(1) pbcbonds = bonds[:n2][i] bonds[n2:, 0] = pbcbonds[:, 1] bonds[n2:, 1] = pbcbonds[:, 0] bonds[n2:, 2:] = -pbcbonds[:, 2:] return bonds
def get_angles(cluster, mult=1, excluded_index=None, excluded_pair=None): """ #TODO: consider combining get_bonds and get_angles function ase.geometry.analysis.Analysis.unique_angles function does not work, return all angles. three-body interactions. :param excluded_pair: excluding all [particle1, particle2, particle3] lists involving the excluded pair """ if excluded_index is None: excluded_index = [] if excluded_pair is None: excluded_pair = [] nl = NeighborList(natural_cutoffs(cluster, mult=mult), bothways=True, self_interaction=False) nl.update(cluster) angle_list, shortened_list = [], [] for count, indices in enumerate(Analysis(cluster, nl=nl).all_angles[0]): for index in indices: if all( list(val) not in angle_list for val in list( permutations([count, index[0], index[1]]))): angle_list.append([count, index[0], index[1]]) for angle in angle_list: if all(single_index not in angle for single_index in excluded_index) and \ all(list(value) not in excluded_pair for value in list(permutations(angle, 2))): shortened_list.append(angle) return angle_list, shortened_list
def __init__(self, quadrature, cutoff, atoms=None, I=5E-2, sigma=2, g=None, w=1, debug=False): self.g = g self.I = I self.sigma = sigma self.cutoff = cutoff self.debug = debug self.quad = quadrature self.weights = self.quad.weights self.sensors = self.quad.points self.w_integral = w self.atoms = atoms if atoms is not None: self.nlist = NeighborList([cutoff * 0.5] * len(atoms), skin=0, self_interaction=False, bothways=True) self.nlist.update(atoms)
def get_all_Z_TM(self, d_Z_TM, TM_type): """ :param d_Z_TM: Z-TM distance with Z being the T sites on the zeolite framework and TM being extraframework atom to be inserted :return: a dictionary of structures for each T site name """ dict_Z_TM = {} for site_name, all_zeo_with_same_T in self.dict_1Al_replaced.items(): atoms = copy.copy(all_zeo_with_same_T[0]) nl = NeighborList(natural_cutoffs(atoms), bothways=True, self_interaction=False) nl.update(atoms) index_Al = [a.index for a in atoms if a.symbol == 'Al'] indices, offsets = nl.get_neighbors(index_Al[0]) assert len(indices) == 4 traj = [] pairs = list(itertools.combinations(indices, 2)) for i, pair in enumerate(pairs): atoms = copy.copy(all_zeo_with_same_T[0]) v = self._get_direction_of_insertion(atoms, index_Al[0], pair[0], pair[1], tag='TM') atoms = atoms + Atoms( TM_type, positions=[atoms[index_Al[0]].position] + v * d_Z_TM) traj.append(atoms) dict_Z_TM[site_name] = traj return dict_Z_TM
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 get_bonds(cluster, mult=1, excluded_index=None, excluded_pair=None): """ Using ase.geometry.analysis.Analysis to get all bonds, then remove the repeated ones. Function also allows removing certain bonding pair defined by user (excluded_pair). Or removing pairs including certain atomic indices (excluded_index). :param cluster: :param mult: :param excluded_index: list of integers :param excluded_pair: list of lists :return: full bonding list, shortened list. If both excluded_index and excluded_pair are None, bonding list == shortened list """ if excluded_index is None: excluded_index = [] if excluded_pair is None: excluded_pair = [] nl = NeighborList(natural_cutoffs(cluster, mult=mult), bothways=True, self_interaction=False) nl.update(cluster) bond_list, shortened_list = [], [] for count, indices in enumerate(Analysis(cluster, nl=nl).all_bonds[0]): for index in indices: if [count, index] not in bond_list and [index, count ] not in bond_list: bond_list.append([count, index]) for bond in bond_list: if all(single_index not in bond for single_index in excluded_index) and \ all(tuple(bond) not in list(permutations(pair)) for pair in excluded_pair): shortened_list.append(bond) return bond_list, shortened_list