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 test_neighborlist_initialization(): atoms = bulk('Al', 'fcc', a=4) nl = NeighborList([8] * len(atoms), skin=0, self_interaction=False) with pytest.raises(Exception, match="Must call update"): nl.get_neighbors(0) with pytest.raises(Exception, match="Must call update"): nl.get_connectivity_matrix() nl.update(atoms) indices, offsets = nl.get_neighbors(0)
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 _get_neighbours(atoms, buffer_factor = 1.0, radii_dct ={'H': 0.37, 'C': 0.77, 'N': 0.75, 'O': 0.73, 'F': 0.71, 'B': 0.88, 'P': 1.036, 'S': 1.02, 'X': 0.77}, from_ase = True): """Helper function for place_and_preoptimize_adsorbates Args: atoms (ase.Atoms) : adsorbate molecule buffer_factor (float) : factor by which the atomic radii get scaled radii_dct (dict) : atomic radii to determine neighbors. Is ignored if from_ase is True from_ase (bool) : If set to True, ase makes an educated guess of the neigbors using sensible atomic radii Returns: tuple : list of neigbours (tuples of bond distances and pairs of atom indices), ase.neighborlist.NeighborList object """ cutoffs = _determine_cutoffs(atoms, buffer_factor=buffer_factor, radii_dct = radii_dct, from_ase = from_ase) nl = NeighborList(cutoffs=cutoffs, bothways=True, self_interaction=False, skin=0.0) nl.update(atoms) cmat = nl.get_connectivity_matrix(sparse=False) cmat = np.triu(cmat) nb_lst = np.transpose(np.nonzero(cmat)) return nb_lst, nl
def find_molecules(struct, mult=1.05): """ Identify molecular fragments in struct Returns ------- List of lists for atom index of each molecule """ atoms = struct.get_ase_atoms() cutOff = natural_cutoffs(atoms, mult=mult) ## Skin=0.3 is not a great parameter, but it seems to work pretty well ## for mulicule identification. In addition, it's not the same affect as ## change the mult value because it's a constant addition to all ## covalent bonds. neighborList = NeighborList(cutOff, skin=0.0) neighborList.update(atoms) matrix = neighborList.get_connectivity_matrix() n_components, component_list = sparse.csgraph.connected_components(matrix) molecule_list = [ np.where(component_list == x)[0] for x in range(n_components) ] return molecule_list
def calculate_molecules(atoms, print_output=False): ''' Returns information on the molecules in the system. Needs refinement! Parameters: atoms: Atoms object Input structure from which to calculate molecular information print_output: Boolean Whether to print any information whilst working out molecules Returns: molecules: List of list of integers Indices of atoms involved in each molecule can view individual molecules vis atoms[molecules[0]] ect ''' from ase.neighborlist import natural_cutoffs, NeighborList from scipy import sparse cutOff = natural_cutoffs(atoms) neighborList = NeighborList(cutOff, self_interaction=False, bothways=True) neighborList.update(atoms) matrix = neighborList.get_connectivity_matrix() n_molecules, component_list = sparse.csgraph.connected_components(matrix) molecules = [] for n in range(n_molecules): atomsIdxs = [ i for i in range(len(component_list)) if component_list[i] == n ] molecules.append(atomsIdxs) if (print_output): print("The following atoms are part of molecule {}: {}".format( n, atomsIdxs)) return molecules
def process_image(image_number): traj = Trajectory(traj_file) Trajectory_Fragments = [] Trajectory_Fragments_for_view = [] atoms = traj[image_number] syms = atoms.get_chemical_symbols() cutoff_dict = {'Al': 1, 'Cl': 1.7, 'H': .37, 'O': 1, 'N': 1, 'C': 1} cutoffs = [cutoff_dict[s.symbol] for s in atoms] nl = NeighborList(cutoffs, skin=0, self_interaction=False, bothways=False) nl.update(atoms) mat = nl.get_connectivity_matrix(sparse=False) Cl_indices = np.array([a.index for a in atoms if a.symbol == 'Cl']) for i in Cl_indices: for j in range(len(atoms)): if syms[j] != 'Al': mat[i, j] = 0 mat[j, i] = 0 n_components, component_list = sparse.csgraph.connected_components(mat) All_fragments = [] All_fragments_for_view = [] for i in range(n_components): # view(atoms[np.where(component_list == i)[0]]) fragments_for_view = atoms[np.where(component_list == i)[0]] fragments = atoms[np.where(component_list == i)[0]].get_chemical_formula() All_fragments.append(fragments) All_fragments_for_view.append(fragments_for_view) Trajectory_Fragments.append(All_fragments) Trajectory_Fragments_for_view.append(All_fragments_for_view) dict_fragments = Counter(All_fragments) # N-Dimensional list of lists -> 1D list, so that counter works properly! flat_Trajectory_Fragments = [item for sublist in Trajectory_Fragments for item in sublist] flat_Trajectory_Fragments_for_view = [item for sublist in Trajectory_Fragments_for_view for item in sublist] # to remove duplicates: from collections import defaultdict formula_dct = defaultdict(list) All_chemical_formula_in_flat_Trajectory_Fragments_for_view = [] for i in flat_Trajectory_Fragments_for_view: chemical_formula_in_flat_Trajectory_Fragments_for_view = i.get_chemical_formula() formula_dct[chemical_formula_in_flat_Trajectory_Fragments_for_view].append(i) All_chemical_formula_in_flat_Trajectory_Fragments_for_view.append(chemical_formula_in_flat_Trajectory_Fragments_for_view) """Save a trajectory of the fragments: """ # for formula, images in formula_dct.items(): # traj = Trajectory(formula + ".traj", mode="w") # for img in images: # traj.write(img) u, indices = np.unique(All_chemical_formula_in_flat_Trajectory_Fragments_for_view, return_index=True) res_list = [flat_Trajectory_Fragments_for_view[i] for i in indices] """Save a database: """ # if os.path.exists("./species.db"): # os.remove("./species.db") # else: # print('File does not exists') # outdb = connect('./species.db') # for i in res_list: # print ('i to view = ', i.get_chemical_formula()) # outdb.write(i) """ to show an overview of the database: 'ase db species.db' to view a fragment of the database: 'ase gui species.db@<id>' to show complete list: 'ase db species.db --limit=0' """ """ partition the trajectory: `ase convert R3-R19.traj@:1000 -o 1ps.traj` from t=209fs to t=210fs: `ase convert -n 209:211 R3-R19.traj 209-210ps.traj` """ dict_Trajectory_Fragments = Counter(flat_Trajectory_Fragments) f = open('molecules_found.dat.%d' % image_number, 'w') total_fragments = sum(dict_Trajectory_Fragments.values()) for chemical_symbol, number in sorted(dict_Trajectory_Fragments.items(), reverse=True, key=lambda item: item[1]): print("{:>15} = {:>2} {:3.20f} %".format(chemical_symbol, number, (number/total_fragments)*100.), file=f) f.close() return dict_Trajectory_Fragments
class Detect(object): def __init__(self, traj, cutoff_dict, saved_components_file=f"components_traj_{traj_name}.npz"): atoms = traj[0] self.cutoffs = [cutoff_dict[s.symbol] for s in atoms] self.save_file = saved_components_file self.syms = atoms.get_chemical_symbols() self.Cl_indices = np.array( [a.index for a in atoms if a.symbol == 'Cl']) self.Al_indices = np.array( [a.index for a in atoms if a.symbol == 'Al']) self.nl = NeighborList(self.cutoffs, skin=0, self_interaction=False, bothways=True) self.initial_components = None self.traj = [a for a in traj] self.atoms = atoms self.molecule_information = {} self.open_reactions = {} self.closed_reactions = [] self.reaction_indices = [] self.distinct_indices = [] self.distinct_strings = [] self.distinct_counts = [] self.broken_bonds = [] self._initialize(atoms) self.parse_trajectory() def _initialize(self, atoms): cl = self.get_component_list(atoms)[0] self.initial_components = cl for Al_idx in self.Al_indices: fragment = self.get_fragment(Al_idx, cl) self.molecule_information[Al_idx] = [ (0, self.get_formula(fragment))] def parse_trajectory(self): if os.path.isfile(self.save_file) and os.stat(self.save_file).st_size > 0: components, matrices = load_components_file(self.save_file) self.traj_components = components self.connectivity_matrices = matrices else: pool = multiprocessing.Pool(processes=24) pm = pool.map(self.get_component_list, self.traj) pool.close() pool.join() components, matrices = zip(*pm) self.traj_components = components self.connectivity_matrices = matrices save_components_file(self.save_file, components, matrices) def get_fragment(self, idx, component_list): return np.where(component_list == component_list[idx])[0] def get_formula(self, fragment): if self.atoms[fragment].get_chemical_formula() in dict_labels: return dict_labels[self.atoms[fragment].get_chemical_formula()] else: return self.atoms[fragment].get_chemical_formula() def get_component_list(self, atoms): self.nl.update(atoms) mat = self.nl.get_connectivity_matrix(sparse=False) for i in self.Cl_indices: for j in range(len(atoms)): if self.syms[j] != 'Al': mat[i, j] = 0 mat[j, i] = 0 return sparse.csgraph.connected_components(mat)[1], mat # for the visualization of the reaction: def get_reaction(self, time, all_reaction_indices): #, bond): traj_file2 = f"{time}fs__bonds.traj" traj2 = Trajectory(traj_file2, 'w') initial = 0 # Processing image = initial = 0: for i, image in enumerate(self.traj[:initial+1]): sub = image[all_reaction_indices] L1 = sub.get_cell()[0] L2 = sub.get_cell()[1] L3 = sub.get_cell()[2] center = 0.5 * (L1 + L2 + L3) dist_cum = np.zeros(len(sub)) for j in range(len(sub)): pos_atom0 = sub.get_positions()[j] V = pos_atom0 - center sub.set_positions(sub.get_positions() - V) sub.wrap() for k in range(len(sub)): if k != j: C1 = L1/np.linalg.norm(L1)**2 C2 = L2/np.linalg.norm(L2)**2 C3 = L3/np.linalg.norm(L3)**2 vec = sub.get_positions()[k] - center test = [np.abs(np.dot(vec,C1)), np.abs(np.dot(vec,C2)), np.abs(np.dot(vec,C3))] num=np.amax(test) if num > dist_cum[j]: dist_cum[j]= num minimum=np.argmin(dist_cum) # using this minimum in image = initial = 0: In principle this is not needed sub = image[all_reaction_indices] pos_atom0 = sub.get_positions()[minimum] V = pos_atom0 - center sub.set_positions(sub.get_positions() - V) sub.wrap() # Processing all images: # restricting the visualization to the interval where reaction occurs: intial = time-70 final = time+100 # final = len(self.traj) for i, image in enumerate(self.traj[initial+1:final+1]): sub2 = image[all_reaction_indices] for s in range(len(sub2)): dist = 1000 stat = sub2.get_positions()[s] for h in [-1,0,1]: for j in [-1,0,1]: for k in [-1,0,1]: tras = sub2.get_positions()[s] - V pos = tras + h*L1 + j*L2 + k*L3 curr_dist = np.linalg.norm(pos-sub.get_positions()[s]) if curr_dist < dist : dist = curr_dist stat = pos sub2[s].position = stat traj2.write(sub2) def follow(self): previous_components = self.initial_components # All_counts = [] # All_distinct_R = [] # All_distinct_s_R = [] # All_distinct_P = [] # All_distinct_s_P = [] for count, component_list in enumerate(self.traj_components): diff = component_list - previous_components if any(diff): print('Reaction took place at', count) reactant_dict = {} for Al_idx in self.Al_indices: fragment = self.get_fragment( Al_idx, previous_components) reactant_dict[Al_idx] = ( self.get_formula(fragment), fragment) product_dict = {} for Al_idx in self.Al_indices: fragment = self.get_fragment(Al_idx, component_list) product_dict[Al_idx] = ( self.get_formula(fragment), fragment) reacted_idx = [] reactants = [] products = [] all_indices_of_reaction = set() all_indx_R = [] all_indx_P = [] for Al_idx in self.Al_indices: reac = reactant_dict[Al_idx][0] prod = product_dict[Al_idx][0] if reac != prod: print(Al_idx, f'changed from {reac} to {prod}') self.molecule_information[Al_idx].append((count, prod)) reactants.append(reac) products.append(prod) reacted_idx.append(Al_idx) # Add the indices from the fragment belonging # to this Al index to all the indices of all # the fragments in this reaction all_indices_of_reaction |= set( reactant_dict[Al_idx][1]) alla_R = reactant_dict[Al_idx]#[1] all_indx_R.append(alla_R) alla_P = product_dict[Al_idx]#[1] all_indx_P.append(alla_P) # print ('alla R = ', alla_R) # print ('alla P = ', alla_P) all_indices_of_reaction |= set(product_dict[Al_idx][1]) all_reaction_idx = sorted(all_indices_of_reaction) print('All indices of this reaction: ', all_reaction_idx) # print ('all_indices_of_reaction_R = ', all_indx_R) # print ('all_indices_of_reaction_P = ', all_indx_P) np.set_printoptions(threshold=sys.maxsize) # print all np arrays ################### specific indices for reactants : distinct_R # specific reactants string: distinct_s_R. for strings you may have same formula for two different array indices, so: ns_R = [i[1] for i in all_indx_R] distinct_R_strs_indx = list() distinct_R = list() for indx_M, M in enumerate(ns_R): if any(np.array_equal(M, N) for N in distinct_R): continue distinct_R.append(M) distinct_R_strs_indx.append(indx_M) print ('distinct indices Reactants = ', distinct_R) distinct_s_R = [all_indx_R[j][0] for j in distinct_R_strs_indx] print ('distinct strings Reactants = ', distinct_s_R) ################### specific indices for products: # specific products string: distinct_s_P: ns_P = [i[1] for i in all_indx_P] distinct_P_strs_indx = list() distinct_P = list() for indx_M, M in enumerate(ns_P): if any(np.array_equal(M, N) for N in distinct_P): continue distinct_P.append(M) distinct_P_strs_indx.append(indx_M) print ('distinct indices Products = ', distinct_P) distinct_s_P = [all_indx_P[j][0] for j in distinct_P_strs_indx] print ('distinct strings Products = ', distinct_s_P) cm = self.connectivity_matrices # np.set_printoptions(threshold=sys.maxsize) diff_cm = cm[count] - cm[count - 1] # Is diff_cm symmetric ? # diff_cm is symmetric if all elements of (diff_cm - diff_cm.T) are zero. (T=transpose) # If not, the matrix is not symmetric. if not np.all(diff_cm - diff_cm.T == 0): print(f"diff_cm between {count}fs and {count -1}fs is not symmetric. Either cm[count] or cm[count- 1], of both, are non symmetric. Use bothways=True") sys.exit() # broken_indices = np.ravel(np.where(diff_cm < 0)) # which indices are broken in the lower trianguar of diff_cm ? broken_indices = np.argwhere(np.tril(diff_cm) < 0) print('The bond between the following indices broke: ', broken_indices) # broken_indices_vis = [[all_reaction_idx.index(i) for i in elmt]\ # for elmt in broken_indices] # sometimes breaks. commented # print('.... for visualization: ', # broken_indices_vis) # formed_indices = np.ravel(np.where(diff_cm > 0)) # which indices are broken in the lower trianguar of diff_cm ? formed_indices = np.argwhere(np.tril(diff_cm) > 0) print('The bond between the following indices formed: ', formed_indices) # formed_indices_vis = [[all_reaction_idx.index(i) for i in elmt]\ # for elmt in formed_indices] # sometimes breaks. commented. # print('.... for visualization: ', # formed_indices_vis) # Save the time of reaction, all indices and broken # indices to easier process the specific reaction # later self.reaction_indices.append((count, all_reaction_idx, broken_indices, formed_indices)) self.distinct_indices.append((distinct_R, distinct_P)) self.distinct_strings.append((distinct_s_R, distinct_s_P)) self.distinct_counts.append((count)) # visualize the reaction (expensive part): # self.get_reaction(count, all_reaction_idx) #, broken_indices) reactant_str = ', '.join(sorted(list(set(reactants)))) product_str = ', '.join(sorted(list(set(products)))) reaction_str = f'{reactant_str} -> {product_str}' opposite_reaction = f'{product_str} -> {reactant_str}' # A reaction should be identified by both Aluminium # indices and reaction species. reacts = tuple(reacted_idx + [opposite_reaction]) # print ('self.open_reactions.keys() = ', self.open_reactions.keys()) # print ('self.open_reactions = ', self.open_reactions) # print ('reacts = ', reacts) # print ('self.reaction_indices = ', self.reaction_indices) if reacts in self.open_reactions.keys(): # It is now a closed reaction!?! lifetime = count - self.open_reactions[reacts][0] tot_reaction_str = opposite_reaction + ' -> ' + \ reaction_str.split(' -> ')[-1] lst = [i[0] for i in self.reaction_indices] indx = lst.index(self.open_reactions[reacts][0]) ################### BEGIN calculating distances for closed reactions, parallelized: iterable = self.traj[self.open_reactions[reacts][0]-1 : count+1] pool = multiprocessing.Pool() broken_past = self.reaction_indices[indx][2] if np.array_equal(broken_past, formed_indices): if formed_indices.size != 0 : max_fr_v = [] min_fr_v = [] func = partial(calculate_distances, formed_indices) res = pool.map(func, iterable) pool.close() pool.join() for i in range(np.shape(res)[1]): aux_max = max([row[i] for row in res]) aux_min = min([row[i] for row in res]) max_fr_v.append(aux_max) min_fr_v.append(aux_min) max_br = max_fr_v min_br = min_fr_v else: max_fr_v = [] min_fr_v = [] max_br = max_fr_v min_br = min_fr_v if not np.array_equal(broken_past, formed_indices): print ("broken_past and formed_indices are different") if formed_indices.size != 0: max_fr_v = [] min_fr_v = [] all_res = [] for image in iterable: res = [image.get_distance(row[0], row[1], mic=True) \ for row in formed_indices] all_res.append(res) for i in range(np.shape(all_res)[1]): aux_max = max([row[i] for row in all_res]) aux_min = min([row[i] for row in all_res]) max_fr_v.append(aux_max) min_fr_v.append(aux_min) if formed_indices.size == 0: max_fr_v = [] min_fr_v = [] if broken_past.size != 0: max_br = [] min_br = [] all_res = [] for image in iterable: res = [image.get_distance(row[0], row[1], mic=True) \ for row in broken_past] all_res.append(res) for i in range(np.shape(all_res)[1]): aux_max = max([row[i] for row in all_res]) aux_min = min([row[i] for row in all_res]) max_br.append(aux_max) min_br.append(aux_min) if broken_past.size == 0: max_br = [] min_br = [] formed_past = self.reaction_indices[indx][3] if np.array_equal(formed_past, broken_indices): if broken_indices.size != 0 : max_br_v = [] min_br_v = [] func = partial(calculate_distances, broken_indices) res = pool.map(func, iterable) pool.close() pool.join() for i in range(np.shape(res)[1]): aux_max = max([row[i] for row in res]) aux_min = min([row[i] for row in res]) max_br_v.append(aux_max) min_br_v.append(aux_min) max_fr = max_br_v min_fr = min_br_v else: max_br_v = [] min_br_v = [] max_fr = max_br_v min_fr = min_br_v if not np.array_equal(formed_past, broken_indices): print ("formed_past and broken_indices are different") if broken_indices.size != 0: max_br_v = [] min_br_v = [] all_res = [] for image in iterable: res = [image.get_distance(row[0], row[1], mic=True) \ for row in broken_indices] all_res.append(res) for i in range(np.shape(all_res)[1]): aux_max = max([row[i] for row in all_res]) aux_min = min([row[i] for row in all_res]) max_br_v.append(aux_max) min_br_v.append(aux_min) if broken_indices.size == 0: max_br_v = [] min_br_v = [] if formed_past.size != 0: max_fr = [] min_fr = [] all_res = [] for image in iterable: res = [image.get_distance(row[0], row[1], mic=True) \ for row in formed_past] all_res.append(res) for i in range(np.shape(all_res)[1]): aux_max = max([row[i] for row in all_res]) aux_min = min([row[i] for row in all_res]) max_fr.append(aux_max) min_fr.append(aux_min) if formed_past.size == 0: max_fr = [] min_fr = [] pool.close() pool.join() ################### END calculating distances for closed reactions, parallelized. self.closed_reactions.append( (reacts[:-1], f'{tot_reaction_str}',\ f':: lifetime: {lifetime}',\ f'(from {self.open_reactions[reacts][0]} to {count})',\ f' At {self.open_reactions[reacts][0]} we have:',\ # f' ; distinct indices R = {self.distinct_indices[indx][0]}',\ # If we want parsing_closed.py module to work, these # f' ; distinct indices P = {self.distinct_indices[indx][1]}',\ # two lines have to be commented (we dont need this info in the Closed_reactions huge array f' ; broken indices = {self.reaction_indices[indx][2]}',\ f' ; formed indices = {self.reaction_indices[indx][3]}',\ f'Max distance between {self.reaction_indices[indx][2]}: {max_br}',\ f'Min distance between {self.reaction_indices[indx][2]}: {min_br}',\ f'Max distance between {self.reaction_indices[indx][3]}: {max_fr}',\ f'Min distance between {self.reaction_indices[indx][3]}: {min_fr}',\ f' At {count} we have:',\ # f' ; distinct indices R = {distinct_R}',\ # If we want parsing_closed.py module to work, these # f' ; distinct indices P = {distinct_P}',\ # two lines have to be commented (we dont need this info in the Closed_reactions huge array f' ; broken indices = {broken_indices}',\ f' ; formed indices = {formed_indices}',\ f'Max distance between {broken_indices}: {max_br_v}',\ f'Min distance between {broken_indices}: {min_br_v}',\ f'Max distance between {formed_indices}: {max_fr_v}',\ f'Min distance between {formed_indices}: {min_fr_v}',\ )) self.open_reactions.pop(reacts) # print ('self.open_reactions = ', self.open_reactions) else: ################### BEGIN calculating distances for open reactions, parallelized: iterable = self.traj[count-1:] pool = multiprocessing.Pool() max_br = [] min_br = [] if broken_indices.size != 0: func = partial(calculate_distances, broken_indices) res = pool.map(func, iterable) for i in range(np.shape(res)[1]): aux_max = max([row[i] for row in res]) aux_min = min([row[i] for row in res]) max_br.append(aux_max) min_br.append(aux_min) max_fr = [] min_fr = [] if formed_indices.size != 0: func = partial(calculate_distances, formed_indices) res = pool.map(func, iterable) for i in range(np.shape(res)[1]): aux_max = max([row[i] for row in res]) aux_min = min([row[i] for row in res]) max_fr.append(aux_max) min_fr.append(aux_min) ################### END calculating distances for open reactions, parallelized: # key is Al_idx and forward reaction # when checking for a closed reaction we need to # use the backward/opposite reaction self.open_reactions[tuple ( reacted_idx + [reaction_str])] = (count,\ f'broken indices = {broken_indices}',\ # f' ; distinct indices R = {distinct_R}',\ # If we want parsing_open.py module to work, these # f' ; distinct indices P = {distinct_P}',\ # two lines have to be commented (we dont need this info in the Open_reactions huge array f'Max distance between {broken_indices}: {max_br}',\ f'Min distance between {broken_indices}: {min_br}',\ f'formed indices = {formed_indices}',\ f'Max distance between {formed_indices}: {max_fr}',\ f'Min distance between {formed_indices}: {min_fr}') pool.close() # uncomment these two if distance is calculated. pool.join() previous_components = component_list
assert not (c2 - c).any() h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)]) nl = NeighborList([0.5, 0.5], skin=0.1, sorted=True, self_interaction=False) 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 h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)]) nl = NeighborList([0.1, 0.1], skin=0.1, bothways=True, self_interaction=False)
def test_neighbor(): 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() 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 h2 = Atoms('H2', positions=[(0, 0, 0), (0, 0, 1)]) nl = NeighborList([0.1, 0.1], skin=0.1, bothways=True, self_interaction=False) assert nl.update(h2) assert nl.get_neighbors(0)[1].shape == (0, 3) assert nl.get_neighbors(0)[1].dtype == int 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])) # Test empty neighbor list nl = PrimitiveNeighborList([]) nl.update([True, True, True], np.eye(3) * 7.56, np.zeros((0, 3))) # Test hexagonal cell and large cutoff pbc_c = np.array([True, True, True]) cutoff_a = np.array([8.0, 8.0]) cell_cv = np.array([[0., 3.37316113, 3.37316113], [3.37316113, 0., 3.37316113], [3.37316113, 3.37316113, 0.]]) spos_ac = np.array([[0., 0., 0.], [0.25, 0.25, 0.25]]) nl = PrimitiveNeighborList(cutoff_a, skin=0.0, sorted=True, use_scaled_positions=True) nl2 = NewPrimitiveNeighborList(cutoff_a, skin=0.0, sorted=True, use_scaled_positions=True) nl.update(pbc_c, cell_cv, spos_ac) nl2.update(pbc_c, cell_cv, spos_ac) a0, offsets0 = nl.get_neighbors(0) b0 = np.zeros_like(a0) d0 = np.dot(spos_ac[a0] + offsets0 - spos_ac[0], cell_cv) a1, offsets1 = nl.get_neighbors(1) d1 = np.dot(spos_ac[a1] + offsets1 - spos_ac[1], cell_cv) b1 = np.ones_like(a1) a = np.concatenate([a0, a1]) b = np.concatenate([b0, b1]) d = np.concatenate([d0, d1]) _a = np.concatenate([a, b]) _b = np.concatenate([b, a]) a = _a b = _b d = np.concatenate([d, -d]) a0, offsets0 = nl2.get_neighbors(0) d0 = np.dot(spos_ac[a0] + offsets0 - spos_ac[0], cell_cv) b0 = np.zeros_like(a0) a1, offsets1 = nl2.get_neighbors(1) d1 = np.dot(spos_ac[a1] + offsets1 - spos_ac[1], cell_cv) b1 = np.ones_like(a1) a2 = np.concatenate([a0, a1]) b2 = np.concatenate([b0, b1]) d2 = np.concatenate([d0, d1]) _a2 = np.concatenate([a2, b2]) _b2 = np.concatenate([b2, a2]) a2 = _a2 b2 = _b2 d2 = np.concatenate([d2, -d2]) i = np.argsort(d[:, 0] + d[:, 1] * 1e2 + d[:, 2] * 1e4 + a * 1e6) i2 = np.argsort(d2[:, 0] + d2[:, 1] * 1e2 + d2[:, 2] * 1e4 + a2 * 1e6) assert np.all(a[i] == a2[i2]) assert np.all(b[i] == b2[i2]) assert np.allclose(d[i], d2[i2])