def find_neighbor_index(cell, defectIndex, neighborOffset): # very similar to generating the mask indices cutOff = natural_cutoffs(cell, 1) nl = neighborlist.NeighborList(cutOff, 0.3, False, False, False) nl.update(cell) index_nei, offset_nei = nl.get_neighbors(defectIndex) # if index_nei.any(): # return index_nei[0 + neighborOffset] # else: # return defectIndex + 1 try: return index_nei[0 + neighborOffset] except IndexError: print('Warning: The defect atom does not have enough neighbor for neighborOffset = ', neighborOffset) print('Warning: Falling back to first neighbor') try: return index_nei[0] except: print('Warning: The defect atom does not have any available neighbor') print('Warning: Falling further back to next atom') return defectIndex + 1
def xyz_to_json(mol): cutOff = neighborlist.natural_cutoffs(mol) cutOff = [cc - 0.2 for cc in cutOff] neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(mol) neighborList.get_neighbors(0) bmatrix = neighborList.get_connectivity_matrix(sparse=False) dmatrix = sp.spatial.distance_matrix(mol.positions, mol.positions) dmatrix[dmatrix > 2] == 0 g = nx.Graph(dmatrix) g2 = nx.Graph(bmatrix) list(g.edges(data=True)) symbols = mol.get_chemical_symbols() nodes_data = [{'id': node, 'atom': symbols[node]} for node in g.nodes] edge_data = [{ 'id': num, 'source': at[0], 'target': at[1], 'strength': 2 if (at[0], at[1]) in g2.edges() else 0.1, 'bond': 1 if (at[0], at[1]) in g2.edges() else 0, 'distance': at[2]['weight'] * 20 } for num, at in enumerate(list(g.edges(data=True)))] data = {'nodes': nodes_data, 'links': edge_data} return data
def buildNL(mol, path='./', radii=None, save=True): #create nl if radii is None: radii = {} radii['H'] = 0.30 radii['C'] = 0.77 radii['N'] = 0.70 radii['O'] = 0.66 radii['Ni'] = 1.24 nAtoms = len(mol) if (not os.path.isfile(os.path.join(path, 'neighborList.pickle'))) or (not save): #create a list of cutoffs cutOff = [] for j in range(0, nAtoms): cutOff.append(radii[mol[j].symbol]) #initiate neighborlist neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(mol) if save: with open(os.path.join(path, 'neighborList.pickle'), 'wb') as f: pickle.dump(neighborList, f) elif save: with open(os.path.join(path, 'neighborList.pickle'), 'rb') as f: neighborList = pickle.load(f) print("Bond Map created") return neighborList
def get_bonds(self, atoms): atoms = atoms.copy() nl = neighborlist.NeighborList( ase.neighborlist.natural_cutoffs(atoms), self_interaction=False, bothways=True, ) nl.update(atoms) connectivity_matrix = nl.get_connectivity_matrix(sparse=False) con_tuples = {} # connected first neighbors for row in range(connectivity_matrix.shape[0]): con_tuples[row] = [] for col in range(connectivity_matrix.shape[1]): if connectivity_matrix[row, col] == 1: con_tuples[row].append(col) pairs = [] # cleaning up the first neighbors for index in con_tuples.keys(): for value in con_tuples[index]: if index > value: pairs.append((index, value)) elif index <= value: pairs.append((value, index)) pairs = set(pairs) return pairs
def nest(atoms, index): position = atoms[index].position # position of that t site # This centers the atom object on the T site we want to remove center = atoms.get_center_of_mass() trans = center - position atoms.translate(trans) atoms.wrap() # get the neighbor list cutoff = neighborlist.natural_cutoffs(atoms, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms) oxygens = nl.get_neighbors(index)[0] # add a hydrogen next to each neighbor oxygen for o in oxygens: vector = position - atoms[o].position hyd = molecule('H') new_location = atoms[o].position + vector / (vector**2).sum()**.5 hyd.translate(new_location) atoms = atoms + hyd # recenter the atoms back to their original position and delete the Si atoms.translate(-trans) atoms.wrap() del (atoms[index]) return atoms
def create_connectivity_matrix(atoms, bothways): cutOff = neighborlist.natural_cutoffs(atoms) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=bothways) neighborList.update(atoms) connectivity_matrix = neighborList.get_connectivity_matrix() return connectivity_matrix
def get_rings(atoms, index): ''' WARNING: This is old and does not work for all framework types. WARNING: Use the updated get_orings function below instead. atoms: ASE atoms object of the zeolite framework to be analyzed index: (integer) index of the atom that you want to classify ''' cell = atoms.get_cell_lengths_and_angles()[:3] repeat = [] for i, c in enumerate(cell): if c / 2 < 15: l = c re = 1 while l / 2 < 15: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms = atoms.repeat(repeat) center = atoms.get_center_of_mass() trans = center - atoms.positions[index] atoms.translate(trans) atoms.wrap() cutoff = neighborlist.natural_cutoffs(atoms, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) neighbs = nx.neighbors(G, index) for n in neighbs: if atoms[n].symbol == 'Si': fe = [n] fe.append(index) G.remove_edge(fe[0], fe[1]) Class = [] while len(Class) < 6: try: path = nx.shortest_path(G, fe[0], fe[1]) except: break Class.append(int(len(path) / 2)) for i in range(len(path) - 3): G.remove_edge(path[i + 1], path[i + 2]) Class.sort(reverse=True) return Class
def all_trings(atoms, index, possible, delete=True): ''' For developmental testing purposes only. ''' possible = possible * 2 atoms2 = atoms.copy() cell = atoms2.get_cell_lengths_and_angles()[:3] repeat = [] maxring = max(possible) for i, c in enumerate(cell): if c / 2 < maxring / 2 + 5: l = c re = 1 while l / 2 < maxring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms2 = atoms2.repeat(repeat) center = atoms2.get_center_of_mass() trans = center - atoms2.positions[index] atoms2.translate(trans) atoms2.wrap() cutoff = neighborlist.natural_cutoffs(atoms2, mult=0.95) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms2) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) rings = find_simple_o_rings(G, index, possible) paths = remove_dups(rings) # paths = remove_sec(paths) if delete == True: keepers = [] for i in paths: for j in i: if j not in keepers: keepers.append(j) d = [atom.index for atom in atoms2 if atom.index not in keepers] atoms2 = substitute.tsub(atoms2, index, 'Al') del atoms2[d] Class = [] for p in paths: Class.append(int(len(p) / 2)) paths = [x for _, x in sorted(zip(Class, paths), reverse=True)] Class.sort(reverse=True) return Class, paths, atoms2, repeat
def get_neighbor_idx(m_at,latt,n_order,max_radii=3.): """ get the indexes neighbors of order n_order 0 is first order """ n_at=latt.get_number_of_atoms() num_n=nl.NeighborList(np.ones(n_at)*max_radii,self_interaction=False,bothways=True) num_n.update(latt) idxs,vec=num_n.get_neighbors(m_at) dist_lst=latt.get_distances(m_at,idxs).round(4) distances=np.unique(dist_lst) nnidxs=idxs[np.where(dist_lst==distances[n_order])[0]] return nnidxs
def generate_mask_indices_neightbor_list(supercellPristine, defectIndex, numLayers): # this function should be used before the defect was inserted # in type 1 and type 3 defect situation, the defect atom was removed, won't be able to calculate neightbor based an vacancy # generate and update the neightborList cutOff = natural_cutoffs(supercellPristine, 1) nl = neighborlist.NeighborList(cutOff, 0.3, False, True, True) nl.update(supercellPristine) # # takes out the symmetric connectivity matrix # matrix = nl.get_connectivity_matrix() # sets of indices totalSet = [] newSet = [] newNewSet = [] totalSet.append(defectIndex) newSet.append(defectIndex) # print totalSet # print newSet # print "=======" # grow starting from the defect, N layers for layer in range(numLayers): # for idx in newSet: # indices, offsets = nl.get_neighbors(idx) # newSet.remove(idx) # for idxx in indices: # if idxx not in totalSet: # totalSet.add(idxx) # newSet.add(idxx) # else: # pass while newSet: idx = newSet.pop() indices, offsets = nl.get_neighbors(idx) for idxx in indices: if idxx not in totalSet: totalSet.append(idxx) newNewSet.append(idxx) else: pass newSet = newNewSet newNewSet = [] # print totalSet # print newSet # print "=======" return totalSet
def checkBonded(clus): """ Check if every atom of the cluster is bonded to other """ cutOff = neighborlist.natural_cutoffs(clus, mult=1) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(clus) matrix = neighborList.get_connectivity_matrix(sparse=False) n_components, component_list = sparse.csgraph.connected_components(matrix) if n_components == 1: bonded = True else: bonded = False return bonded
def atoms_to_graph(atoms, index, max_ring): ''' Helper function to repeat a unit cell enough times to capture the largest possible ring, and turn the new larger cell into a graph object. RETURNS: G = graph object representing zeolite framework in new larger cell large_atoms = ASE atoms object of the new larger cell framework repeat = array showing the number of times the cell was repeated: [x,y,z] ''' # first, repeat cell, center the cell, and wrap the atoms back into the cell cell = atoms.get_cell_lengths_and_angles()[:3] repeat = [] for i, c in enumerate(cell): if c / 2 < max_ring / 2 + 5: l = c re = 1 while l / 2 < max_ring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) large_atoms = atoms.copy() large_atoms = large_atoms.repeat(repeat) center = large_atoms.get_center_of_mass() trans = center - large_atoms.positions[index] large_atoms.translate(trans) large_atoms.wrap() # we need a neighborlist (connectivity matrix) before we can make our graph from ase import neighborlist cutoff = neighborlist.natural_cutoffs(large_atoms, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(large_atoms) matrix = nl.get_connectivity_matrix(sparse=False) # now we make the graph import networkx as nx G = nx.from_numpy_matrix(matrix) return G, large_atoms, repeat
def get_connectivity(adsorbate): """ Generate the connectivity of an adsorbate atoms obj. Args: adsorbate An `ase.Atoms` object of the adsorbate Returns: matrix The connectivity matrix of the adsorbate. """ cutoff = natural_cutoffs(adsorbate) neighborList = neighborlist.NeighborList(cutoff, self_interaction=False, bothways=True) neighborList.update(adsorbate) matrix = neighborlist.get_connectivity_matrix(neighborList.nl).toarray() return matrix
def create_connectivity_matrix(atoms, bothways): """Summary Args: atoms (TYPE): Description bothways (TYPE): Description Returns: TYPE: Description """ cutOff = neighborlist.natural_cutoffs(atoms) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=bothways) neighborList.update(atoms) connectivity_matrix = neighborList.get_connectivity_matrix() return connectivity_matrix
def neighbor_list_and_relative_vec(pos, r_max, self_interaction=True): """ Create neighbor list (edge_index) and relative vectors (edge_attr) based on radial cutoff. :param pos: torch.tensor of coordinates with shape (N, 3) :param r_max: float of radial cutoff :param self_interaction: whether or not to include self edge :return: list of edges [(2, num_edges)], Tensor of relative vectors [num_edges, 3] edges are given by the convention edge_list[0] = source (convolution center) edge_list[1] = target (neighbor) Thus, the edge_list has the same convention vector notation for relative vectors \vec{r}_{source, target} """ N, _ = pos.shape atoms = Atoms(symbols=['H'] * N, positions=pos) nl = neighborlist.NeighborList( [r_max / 2.] * N, # NeighborList looks for intersecting spheres self_interaction=self_interaction, bothways=True, skin=0.0, ) nl.update(atoms) nei_list = [] geo_list = [] for i, p in enumerate(pos): indices = nl.get_neighbors(i)[0] if self_interaction: indices = indices[:-1] # Remove extra self edge cart = pos[indices] indices = torch.LongTensor([[i, target] for target in indices]) dist = cart - p nei_list.append(indices) geo_list.append(dist) return torch.cat(nei_list, dim=0).transpose(1, 0), torch.cat(geo_list, dim=0)
def get_nuclearity_from_atoms(atoms, structure, actives): #Get surface nuclearity from given Atoms object slab_atoms = atoms.copy() #pick surface atoms bulk_atoms = AseAtomsAdaptor.get_atoms(structure) bulk_cn = find_bulk_cn_dict(bulk_atoms) surface_indices = find_surface_atoms_indices(bulk_cn, slab_atoms) #Generate connectivity matrix cutOff = natural_cutoffs(slab_atoms) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(slab_atoms) connectivity_matrix = neighborList.get_connectivity_matrix() #Ignore connectivity with atoms which are not active or on the surface active_connectivity_matrix = connectivity_matrix.copy() active_list = [ atom.symbol in actives and atom.index in surface_indices for atom in slab_atoms ] if sum(active_list) == 0: # No active surface atoms! return {'max_nuclearity': 0, 'nuclearities': []} else: active_connectivity_matrix = active_connectivity_matrix[active_list, :] active_connectivity_matrix = active_connectivity_matrix[:, active_list] # Make a graph-tool graph from the adjacency matrix graph = gt.Graph(directed=False) for i in range(active_connectivity_matrix.shape[0]): graph.add_vertex() graph.add_edge_list(np.transpose(active_connectivity_matrix.nonzero())) labels, hist = topology.label_components(graph, directed=False) return {'max_nuclearity': np.max(hist), 'nuclearities': hist}
def get_rings(atoms, index, possible_rings): # first we need the connectivity matrix # atoms: ase Atoms object of a zeolite structure # index: (integer) index of the oxygen atom that you want to classify # possible_rings: (array) what size rings are possible in this zeolite framework? # Check IZA if you don't know. Example: CHA has 8-,6-,4-MR i.e. [8,6,4] cell = atoms.get_cell_lengths_and_angles() repeat = [] for i, c in enumerate(cell): if c / 2 < 8: repeat.append(2) else: repeat.append(1) atoms = atoms.repeat(repeat) center = atoms.get_center_of_mass() trans = center - atoms.positions[index] atoms.translate(trans) atoms.wrap() cutoff = neighborlist.natural_cutoffs(atoms) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() Class = [] pr = possible_rings pr.sort() for i in pr: ring, m = zeoc(m, index, i * 2 + 1) if ring: for r in ring: temp = r Class.append(int((len(temp) - 1) / 2)) Class.sort(reverse=True) return Class
def FromXYZtoGraph(input_file): atoms = ['H', 'He', 'Li', 'C', 'N', 'O', 'F', 'Na', 'Si', 'P', 'S', 'Cl'] atomic_numb = [1, 2, 3, 6, 7, 8, 9, 11, 14, 15, 16, 17] mol = io.read(input_file) #compute neighbor of the atoms in xyz format cutOff = neighborlist.natural_cutoffs(mol) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(mol) #compure adjacency matrix and atoms list adj_matrix = neighborList.get_connectivity_matrix(sparse=False) Natom_list = mol.get_atomic_numbers() atoms_list = [] for i, item in enumerate(Natom_list): for k in range(len(atomic_numb)): if item == atomic_numb[k]: atoms_list.append(atoms[k]) #convert in networkx-molecules graph G = nx.from_numpy_matrix(adj_matrix) for i, item in enumerate(atoms_list): tmp_attr = {'atom': item} G.nodes[i].update(tmp_attr.copy()) return (G)
def pruneoverlap(self, criteria=0.5, verbose=False): ''' TODO: remove atoms overlapping assume PBC conditions''' print( "NOTICE: The pruning routine does not accoutn for stoichiometry restrictions." ) cutoff = neighborlist.natural_cutoffs(self.polycrystal) neighbors = neighborlist.NeighborList(cutoff, self_interaction=False, bothways=False) neighbors.update(self.polycrystal) isremoved = [] for a in self.polycrystal: ineigh = neighbors.get_neighbors(a.index) for j in ineigh[0]: r = self.polycrystal.get_distance(a.index, j, mic=True) if r < criteria and j not in isremoved: isremoved.append(j) if verbose: print("Atom ID %i removed due to overlap!" % (j)) del self.polycrystal[isremoved] self.natoms = self.polycrystal.get_global_number_of_atoms()
def lorb2fod(mf, lo_coeff, s=0, grid_level=7): """ lo_coeff[:] localized orbital """ from scipy import optimize # get estimate for FOD'position # by using the COM of the orbital density mol = mf.mol ao1 = numint.eval_ao(mol, mf.grids.coords) phi = ao1.dot(lo_coeff) #print(phi.shape) #print('lorb2fod: s={}'.format(s)) #print('lorb2fod: lo_coeff={}'.format(lo_coeff.sum())) #print(np.sum(phi**2*mf.grids.weights)) dens = np.conjugate(phi) * phi * mf.grids.weights # COM x = np.sum(dens * mf.grids.coords[:, 0]) y = np.sum(dens * mf.grids.coords[:, 1]) z = np.sum(dens * mf.grids.coords[:, 2]) #print x print(" -> COM: {0:7.5f} {1:7.5f} {2:7.5f}".format( x * units.Bohr, y * units.Bohr, z * units.Bohr)) ig_fod = np.array([x, y, z]) #if s==1: # sys.exit() ## build a new, smaller mesh for the density fitting # find nearest atom dists = np.linalg.norm((mol.atom_coords() - ig_fod), axis=1) didx = np.argsort(dists) #print dists #print didx nidx = -1 for i in range(mol.natm): if mol.atom_pure_symbol(i) == 'H': continue nidx = didx[i] break if nidx == -1: print("ERROR") sys.exit() #print nidx, mol.atom_pure_symbol(nidx) # build atom object (make sure to enter ccors in Angst) acoord = mol.atom_coords() atoms = Atoms() for na in range(mol.natm): aa = Atom(symbol=mol.atom_symbol(na), position=acoord[na] * units.Bohr) atoms.extend(aa) cutoffs = natural_cutoffs(atoms) ##print cutoffs nl = NL.NeighborList(cutoffs, self_interaction=False, bothways=True) nl.update(atoms) # generate a per-atom grid (include neigbours) neiatm = nl.get_neighbors(nidx)[0] mstr = '' for na in neiatm: sym = mol.atom_pure_symbol(na) pos = mol.atom_coord(na) * units.Bohr # in Angst #print sym, pos mstr += "{0} {1:0.12f} {2:0.12f} {3:0.12f};".format( sym, pos[0], pos[1], pos[2]) # also add the nearest Atom to the grid algorithm sym = mol.atom_pure_symbol(nidx) pos = mol.atom_coord(nidx) * units.Bohr # in Angst #print sym, pos mstr += "{0} {1:0.12f} {2:0.12f} {3:0.12f};".format( sym, pos[0], pos[1], pos[2]) #print ">>>" #print mstr # build a Mole object from subsystem b = mol.basis try: onmol = gto.M(atom=mstr, basis=b, verbose=0) except RuntimeError: onmol = gto.M(atom=mstr, basis=b, spin=1, verbose=0) _mdft = dft.UKS(onmol) _mdft.max_cycle = 0 _mdft.grids.level = grid_level _mdft.kernel() ongrid = copy.copy(_mdft.grids) #print("Original grid size: {0}".format(mf.grids.coords.shape[0])) #print(" building FO, grid size: {0}" # .format(ongrid.coords.shape[0])) ## re-calculate lo density on O(N) grid ao1 = numint.eval_ao(mol, ongrid.coords) phi = ao1.dot(lo_coeff) dens = np.conjugate(phi) * phi * ongrid.weights #sys.exit() # now build the corresponding fermi orbital #lfo = fo(mf, ig_fod, s) def densdiff(x0): #print ig_fod #print(s) _x = np.reshape(x0, (-1, 3)) lfo = fo(mf, _x, s) mol = mf.mol ao1 = numint.eval_ao(mol, ongrid.coords) _fo = ao1.dot(lfo) dens_fo = np.conjugate(_fo) * _fo * ongrid.weights ##print dens_fo.shape ##print dens.shape diff = np.linalg.norm(dens_fo - dens) return diff options = { 'disp': False, 'eps': 1e-05, 'gtol': 1e-05, 'maxiter': 299, } db = 1.5 if np.linalg.norm(mol.atom_coord(nidx) - ig_fod) < 0.5: db = 0.75 bounds = [(x - db, x + db), (y - db, y + db), (z - db, z + db)] res = optimize.minimize(densdiff, ig_fod.flatten(), method='L-BFGS-B', options=options, bounds=bounds) #print ">> done <<" #print res.x #print ig_fod #print ">> initial FOD moved by: {0:0.4f} [B]".format(np.linalg.norm(res.x-ig_fod)) #print ">> density fit quality : {0:0.4f}".format(res.fun) print(" -> a_i: {0:7.5f} {1:7.5f} {2:7.5f}"\ .format(res.x[0]*units.Bohr,res.x[1]*units.Bohr,res.x[2]*units.Bohr)) return res.x
def tring_driver(atoms, index, possible, delete=True): ''' atoms: ASE atoms object of the zeolite framework to be analyzed index: (integer) index of the atom that you want to classify possible: (list) of the types of rings known to be present in the zeolite framework you are studying. This information is available on IZA or in the collections module of this package. Returns: Class - The size of the rings associated with the desire T Site. Rings - The actual atom indices that compose those rings. atoms2 - An atoms object with the desired T Site changed to an Aluminum atom (just for visual purposes), and all atoms removed except for those that share a ring with the T Site provided. ''' possible = possible * 2 atoms2 = atoms.copy() cell = atoms2.get_cell_lengths_and_angles()[:3] repeat = [] maxring = max(possible) for i, c in enumerate(cell): if c / 2 < maxring / 2 + 5: l = c re = 1 while l / 2 < maxring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms2 = atoms2.repeat(repeat) center = atoms2.get_center_of_mass() trans = center - atoms2.positions[index] atoms2.translate(trans) atoms2.wrap() cutoff = neighborlist.natural_cutoffs(atoms2, mult=0.95) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms2) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) rings = find_o_rings(G, index, possible) paths = remove_dups(rings) paths = remove_sec(paths) if delete == True: keepers = [] for i in paths: for j in i: if j not in keepers: keepers.append(j) d = [atom.index for atom in atoms2 if atom.index not in keepers] atoms2 = substitute.tsub(atoms2, index, 'Al') del atoms2[d] Class = [] for p in paths: Class.append(int(len(p) / 2)) paths = [x for _, x in sorted(zip(Class, paths), reverse=True)] Class.sort(reverse=True) return Class, paths, atoms2, repeat
def find_fragments(atoms, scale=1.0) -> list: """Finds unconnected structural fragments by constructing the first-neighbor topology matrix and the resulting graph of connected vertices. Args: atoms: :class:`~ase.atoms.Atoms` or :class:`~aimstools.structuretools.structure.Structure`. scale: Scaling factor for covalent radii. Note: Requires networkx library. Returns: list: NamedTuple with indices and atoms object. """ atoms = atoms.copy() radii = scale * covalent_radii[atoms.get_atomic_numbers()] nl = neighborlist.NeighborList(radii, skin=0, self_interaction=False, bothways=True) nl.update(atoms) connectivity_matrix = nl.get_connectivity_matrix(sparse=False) con_tuples = {} # connected first neighbors for row in range(connectivity_matrix.shape[0]): con_tuples[row] = [] for col in range(connectivity_matrix.shape[1]): if connectivity_matrix[row, col] == 1: con_tuples[row].append(col) pairs = [] # cleaning up the first neighbors for index in con_tuples.keys(): for value in con_tuples[index]: if index > value: pairs.append((index, value)) elif index <= value: pairs.append((value, index)) pairs = set(pairs) graph = nx.from_edgelist(pairs) # converting to a graph con_tuples = list( nx.connected_components(graph) ) # graph theory can be pretty handy fragments = {} i = 0 for tup in con_tuples: fragment = namedtuple("fragment", ["indices", "atoms"]) ats = ase.Atoms() indices = [] for entry in tup: ats.append(atoms[entry]) indices.append(entry) ats.cell = atoms.cell ats.pbc = atoms.pbc fragments[i] = fragment(indices, ats) i += 1 fragments = [ v for k, v in sorted( fragments.items(), key=lambda item: np.average(item[1][1].get_positions()[:, 2]), ) ] return fragments
def get_orings(atoms, index, possible): ''' atoms: ASE atoms object of the zeolite framework to be analyzed index: (integer) index of the atom that you want to classify possible: (list) of the types of rings known to be present in the zeolite framework you are studying. This information is available on IZA or in the collections module of this package. Returns: Class - The size of rings associated with the oxygen. paths - The actual atom indices that compose those rings. ''' cell = atoms.get_cell_lengths_and_angles()[:3] repeat = [] possible = possible * 2 maxring = max(possible) for i, c in enumerate(cell): if c / 2 < maxring / 2 + 5: l = c re = 1 while l / 2 < maxring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms2 = atoms.copy() atoms2 = atoms2.repeat(repeat) center = atoms2.get_center_of_mass() trans = center - atoms2.positions[index] atoms2.translate(trans) atoms2.wrap() cutoff = neighborlist.natural_cutoffs(atoms2, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms2) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) neighbs = nx.neighbors(G, index) for n in neighbs: if atoms2[n].symbol != 'O': fe = [n] fe.append(index) G.remove_edge(fe[0], fe[1]) tmpClass = [] rings = [] while len(tmpClass) < 6: try: path = nx.shortest_path(G, fe[0], fe[1]) except: break length = len(path) if length in possible: tmpClass.append(int(len(path) / 2)) rings.append(path) if length == 18: G.remove_edge(path[8], path[9]) elif length < 16 and length > 6: G.remove_edge(path[3], path[4]) elif length >= 16: G.remove_edge(path[int(len(path) / 2 - 1)], path[int(len(path) / 2)]) if length == 8: G.remove_node(path[4]) if length == 6: G.remove_node(path[3]) else: G.remove_edge(path[int(length / 2)], path[int(length / 2 + 1)]) rings = remove_dups(rings) rings = remove_sec(rings) Class = [] for r in rings: Class.append(int(len(r) / 2)) paths = rings paths = [x for _, x in sorted(zip(Class, paths), reverse=True)] Class.sort(reverse=True) keepers = [] for i in paths: for j in i: if j not in keepers: keepers.append(j) d = [atom.index for atom in atoms2 if atom.index not in keepers] del atoms2[d] return Class, paths, atoms2
def _render_structure(self, change=None): """Render the structure with POVRAY.""" if not isinstance(self.structure, Atoms): return self.render_btn.disabled = True omat = np.array(self._viewer._camera_orientation).reshape( 4, 4).transpose() zfactor = norm(omat[0, 0:3]) omat[0:3, 0:3] = omat[0:3, 0:3] / zfactor bb = deepcopy(self.structure) bb.pbc = (False, False, False) for i in bb: ixyz = omat[0:3, 0:3].dot(np.array([i.x, i.y, i.z]) + omat[0:3, 3]) i.x, i.y, i.z = -ixyz[0], ixyz[1], ixyz[2] vertices = [] cell = bb.get_cell() vertices.append(np.array([0, 0, 0])) vertices.extend(cell) vertices.extend([ cell[0] + cell[1], cell[0] + cell[2], cell[1] + cell[2], cell[0] + cell[1] + cell[2], ]) for n, i in enumerate(vertices): ixyz = omat[0:3, 0:3].dot(i + omat[0:3, 3]) vertices[n] = np.array([-ixyz[0], ixyz[1], ixyz[2]]) bonds = [] cutOff = neighborlist.natural_cutoffs( bb) # Takes the cutoffs from the ASE database neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=False) neighborList.update(bb) matrix = neighborList.get_connectivity_matrix() for k in matrix.keys(): i = bb[k[0]] j = bb[k[1]] v1 = np.array([i.x, i.y, i.z]) v2 = np.array([j.x, j.y, j.z]) midi = v1 + (v2 - v1) * Radius[i.symbol] / (Radius[i.symbol] + Radius[j.symbol]) bond = Cylinder( v1, midi, 0.2, Pigment("color", np.array(Colors[i.symbol])), Finish("phong", 0.8, "reflection", 0.05), ) bonds.append(bond) bond = Cylinder( v2, midi, 0.2, Pigment("color", np.array(Colors[j.symbol])), Finish("phong", 0.8, "reflection", 0.05), ) bonds.append(bond) edges = [] for x, i in enumerate(vertices): for j in vertices[x + 1:]: if (norm(np.cross(i - j, vertices[1] - vertices[0])) < 0.001 or norm(np.cross(i - j, vertices[2] - vertices[0])) < 0.001 or norm(np.cross(i - j, vertices[3] - vertices[0])) < 0.001): edge = Cylinder( i, j, 0.06, Texture( Pigment("color", [212 / 255.0, 175 / 255.0, 55 / 255.0])), Finish("phong", 0.9, "reflection", 0.01), ) edges.append(edge) camera = Camera( "perspective", "location", [0, 0, -zfactor / 1.5], "look_at", [0.0, 0.0, 0.0], ) light = LightSource([0, 0, -100.0], "color", [1.5, 1.5, 1.5]) spheres = [ Sphere( [i.x, i.y, i.z], Radius[i.symbol], Texture(Pigment("color", np.array(Colors[i.symbol]))), Finish("phong", 0.9, "reflection", 0.05), ) for i in bb ] objects = ( [light] + spheres + edges + bonds + [Background("color", np.array(to_rgb(self._viewer.background)))]) scene = Scene(camera, objects=objects) fname = bb.get_chemical_formula() + ".png" scene.render( fname, width=2560, height=1440, antialiasing=0.000, quality=11, remove_temp=False, ) with open(fname, "rb") as raw: payload = base64.b64encode(raw.read()).decode() self._download(payload=payload, filename=fname) self.render_btn.disabled = False
N_indices = np.flatnonzero(symbols == 'N') C_indices = np.flatnonzero(symbols == 'C') H_indices = np.flatnonzero(symbols == 'H') organic_indices = np.concatenate((N_indices, C_indices, H_indices)) organic = frame[organic_indices] inorganic_indices = np.concatenate((Pb_indices, Br_indices)) inorganic = frame[inorganic_indices] ##### Find positions of nitrogens/carbons in the frame cutOff = neighborlist.natural_cutoffs(organic) neighborList = neighborlist.NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(organic) matrix = neighborList.get_connectivity_matrix() n_components, component_list = sparse.csgraph.connected_components(matrix) MA=np.empty((0), dtype='int') MA_counter = 0 Long=np.empty((0), dtype='int') Long_counter = 0 for i in range(n_components): molIdx=i molIdxs = [ j for j in range(len(component_list)) if component_list[j] == molIdx ]
def get_orings_new(atoms, index, possible): cell = atoms.get_cell_lengths_and_angles()[:3] repeat = [] possible = possible * 2 maxring = max(possible) for i, c in enumerate(cell): if c / 2 < maxring / 2 + 5: l = c re = 1 while l / 2 < maxring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms2 = atoms.copy() atoms2 = atoms2.repeat(repeat) center = atoms2.get_center_of_mass() trans = center - atoms2.positions[index] atoms2.translate(trans) atoms2.wrap() atoms3 = atoms2.copy() cutoff = neighborlist.natural_cutoffs(atoms2, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms2) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) neighbs = nx.neighbors(G, index) fe = [] for n in neighbs: if atoms2[n].symbol != 'O': fe.append(n) fe.append(index) rings = [] for path in nx.all_simple_paths(G, index, fe[0], cutoff=max(possible) - 1): rings.append(path) new_rings = [] for r in rings: if len(r) in possible: new_rings.append(r) rings = new_rings delete = [] for j, r in enumerate(rings): flag = False if len(r) >= 12: for i in range(1, len(r) - 3, 2): angle = atoms3.get_angle(r[i], r[i + 2], r[i + 4], mic=True) if angle < 100: delete.append(j) break new_rings = [] for j, r in enumerate(rings): if j not in delete: new_rings.append(r) rings = new_rings rings = remove_sec(rings) rings = remove_dups(rings) Class = [] for r in rings: Class.append(int(len(r) / 2)) paths = rings paths = [x for _, x in sorted(zip(Class, paths), reverse=True)] Class.sort(reverse=True) keepers = [] for i in paths: for j in i: if j not in keepers: keepers.append(j) d = [atom.index for atom in atoms2 if atom.index not in keepers] del atoms2[d] return Class, paths, atoms2
def test_orings(atoms, index, possible): cell = atoms.get_cell_lengths_and_angles()[:3] repeat = [] possible = possible * 2 maxring = max(possible) for i, c in enumerate(cell): if c / 2 < maxring / 2 + 5: l = c re = 1 while l / 2 < maxring / 2 + 5: re += 1 l = c * re repeat.append(re) else: repeat.append(1) atoms2 = atoms.copy() atoms2 = atoms2.repeat(repeat) center = atoms2.get_center_of_mass() trans = center - atoms2.positions[index] atoms2.translate(trans) atoms2.wrap() cutoff = neighborlist.natural_cutoffs(atoms2, mult=1.05) nl = neighborlist.NeighborList(cutoffs=cutoff, self_interaction=False, bothways=True) nl.update(atoms2) matrix = nl.get_connectivity_matrix(sparse=False) m = matrix.copy() G = nx.from_numpy_matrix(matrix) neighbs = nx.neighbors(G, index) fe = [] for n in neighbs: if atoms2[n].symbol != 'O': fe.append(n) fe.append(index) tmpClass = [] rings = [] G2 = G.copy() G2.remove_edge(fe[0], fe[2]) pr = sorted(possible) rings = [] for q in pr: tmprings = [] paths = nx.all_simple_paths(G2, fe[0], fe[2], cutoff=q - 1) for p in paths: tmprings.append(p) for r in tmprings: length = len(r) if length in possible: if ((len(r) / 2) % 2) == 0: try: G2.remove_node(r[int(length / 2 - 1)]) except: 2 + 2 elif ((len(r) / 2) % 2) != 0: try: G2.remove_node(r[int(length / 2)]) except: 2 + 2 rings.append(r) rings = remove_dups(rings) rings = remove_sec(rings) Class = [] for r in rings: Class.append(int(len(r) / 2)) paths = rings paths = [x for _, x in sorted(zip(Class, paths), reverse=True)] Class.sort(reverse=True) keepers = [] for i in paths: for j in i: if j not in keepers: keepers.append(j) d = [atom.index for atom in atoms2 if atom.index not in keepers] del atoms2[d] return Class, paths, atoms2