def atoms_and_bonds_from_structure(structure, atom_types, bond_types): """ Defines the atoms and bonds from the structure and given information from params. Args: structure (obj): A pymatgen structural object created from the transformed matrix structure, with forces included as site properties. atom_types (list(obj)): AtomType objects including atom_type_index (int), label (str), mass (float), charge (float), and core_shell (str). bond_types (list(obj)): BondType objects including bond_type_index (int) and label (str). Returns: atoms (list(obj)): Atom objects including atom_index (int), molecule_index (int), coords (np.array), forces (np.array), and atom_type (obj:AtomType). bonds (list(obj)): Bond objects including bond_index (int), atom_indices (list(int)), and bond_type (obj:BondType). """ atoms = [] bonds = [] atom_types_dict = {} atom_types_dict = {at.label: at for at in atom_types} bond_types_dict = {} bond_types_dict = {bt.label: bt for bt in bond_types} atom_index = 0 bond_index = 0 molecule_index = 0 for site in structure: molecule_index += 1 if site.species_string in atom_types_dict: # not core-shell atom atom_index += 1 atom_type = atom_types_dict[site.species_string] atoms.append( Atom(atom_index=atom_index, molecule_index=molecule_index, coords=site.coords, atom_forces=site.properties['forces'], atom_type=atom_type)) else: # need to handle core + shell atom_index += 1 atom_type = atom_types_dict[site.species_string + ' core'] atoms.append( Atom(atom_index=atom_index, molecule_index=molecule_index, coords=site.coords, atom_forces=site.properties['forces'], atom_type=atom_type)) atom_index += 1 atom_type = atom_types_dict[site.species_string + ' shell'] atoms.append( Atom(atom_index=atom_index, molecule_index=molecule_index, coords=site.coords, atom_forces=np.array([0.0, 0.0, 0.0]), atom_type=atom_type)) bond_index += 1 bond_type = bond_types_dict['{}-{} spring'.format( site.species_string, site.species_string)] bonds.append( Bond(bond_index=bond_index, atom_indices=[atom_index - 1, atom_index], bond_type=bond_type)) return atoms, bonds
def acetylene(bond_length_ch=None, bond_length_cc=None): if bond_length_ch == None: bl_ch = param.acetylene['c-h']['angstrom'] else: bl_ch = bond_length_ch if bond_length_cc == None: bl_cc = param.acetylene['c-c']['angstrom'] else: bl_cc = bond_length_ch # Centred on [0,0,0] return [Atom('H',[0,0,-bl_ch-0.5*bl_cc]), Atom('C', [0,0,-0.5*bl_cc]), Atom('C',[0,0,0.0.5*bl_cc]), Atom('H',[0,0,bl_ch+0.5*bl_cc])]
def __init__(self, xyz, nn_distance): # parent class StructDesignerXYZ stores atom list initialized from xyz-file super(BasisTB, self).__init__(xyz=xyz, nn_distance=nn_distance) # each entry of the dictionary stores a label of the atom species as a key and # corresponding Atom object as a value. Each atom object contains infomation about number, # energy and symmetry of the orbitals self._orbitals_dict = Atom.atoms_factory(self.num_of_species.keys()) # `quantum_number_lims` counts number of species and corresponding number # of orbitals for each; each atom kind is enumerated self.quantum_numbers_lims = [] for item in self.num_of_species.keys(): self.quantum_numbers_lims.append( OrderedDict([('atoms', self.num_of_species[item]), ('l', self.orbitals_dict[item].num_of_orbitals)])) # count total number of basis functions self.basis_size = 0 for item in self.quantum_numbers_lims: self.basis_size += reduce(mul, item.values()) # compute offset index for each atom self._offsets = [0] for j in xrange(len(self.atom_list) - 1): self._offsets.append( self.orbitals_dict[self.atom_list.keys()[j]].num_of_orbitals) self._offsets = np.cumsum(self._offsets)
def xyz_file_to_atoms(filename): """ From an .xyz file get a list of atoms Arguments: filename (str): .xyz filename Returns: (list(autode.atoms.Atom)): Atoms """ atoms = [] if not os.path.exists(filename): raise XYZfileDidNotExist if not filename.endswith('.xyz'): raise XYZfileWrongFormat # Open the file that exists and should(!) be in the correct format with open(filename, 'r') as xyz_file: try: # First item in an xyz file is the number of atoms n_atoms = int(xyz_file.readline().split()[0]) except IndexError: raise XYZfileWrongFormat # XYZ lines should be the following 2 + n_atoms lines xyz_lines = xyz_file.readlines()[1:n_atoms + 1] for line in xyz_lines: try: atom_label, x, y, z = line.split()[:4] atoms.append(Atom(atomic_symbol=atom_label, x=x, y=y, z=z)) except (IndexError, TypeError, ValueError): raise XYZfileWrongFormat return atoms
def read_xyz(self): """ Reads info from xyz file, whose path was given as absolute_path when the object was instantiated. Raises ------ ValueError If the xyz file has extra lines between atoms. If a Lattice is found that has the wrong number of parameters. TypeError If non-numeric values are found for an atom's position. """ self._check_read() lines = iter(self.content) line = next(lines) n_atoms = 0 while True: try: n_atoms = int(line.split()[0]) except TypeError: line = next(lines) continue else: break lattice_indexes = self._find("Lattice") must_invent_cell = False if len(lattice_indexes) > 0: lattice_index = lattice_indexes[0] lattice = find_between(self.content[lattice_index], '"', '"') try: xx, xy, xz, yx, yy, yz, zx, zy, zz = tuple(lattice.split()) except ValueError: raise ValueError("Lattice in xyz file is bad") self.atoms.cell = [[xx, xy, xz], [yx, yy, yz], [zx, zy, zz]] else: # if no "Lattice" is found, atoms.cell is invented below lattice_index = 0 must_invent_cell = True for line in self.content[lattice_index + 1:]: if not line[0].isalpha(): continue try: s, x, y, z = tuple(line.split()) except ValueError: continue # raise ValueError("xyz file has a bad format, avoid extra lines") try: xyz = [float(x), float(y), float(z)] except TypeError: raise TypeError("bad positions in file: {} {} {}".format( x, y, z)) atom = Atom(atom_type=s, position=xyz) self.atoms.add_atom(atom) if len(self.atoms) != n_atoms: print("WARNING: {} atoms declared in file, {} atoms found in file". format(n_atoms, len(self.atoms))) if must_invent_cell: gap = 10 # angstroms min_x = min(atom.position[0] for atom in self.atoms) max_x = max(atom.position[0] for atom in self.atoms) min_y = min(atom.position[1] for atom in self.atoms) max_y = max(atom.position[1] for atom in self.atoms) min_z = min(atom.position[2] for atom in self.atoms) max_z = max(atom.position[2] for atom in self.atoms) xx = max_x - min_x + gap yy = max_y - min_y + gap zz = max_z - min_z + gap self.atoms.cell = [[xx, 0, 0], [0, yy, 0], [0, 0, zz]]
def read(self): index_start = self._find("Number of particles")[0] index_auxiliary = None index_atoms = None self.number_of_particles = int(self.content[index_start].split()[-1]) h0_11, h0_12, h0_13, h0_21, h0_22, h0_23, h0_31, h0_32, h0_33 = 0, 0, 0, 0, 0, 0, 0, 0, 0 if len(self._find(".NO_VELOCITY.")) == 1: self.has_velocity = False if len(self._find("A = 1 Angstrom")) == 0: print( "WARNING: distance units in cfg file may not be in Angstroms!") for (index, line) in enumerate(self.content[index_start:], index_start): if line.startswith("H0"): if "H0(1,1)" in line: h0_11 = float(line.split()[-2]) elif "H0(1,2)" in line: h0_12 = float(line.split()[-2]) elif "H0(1,3)" in line: h0_13 = float(line.split()[-2]) elif "H0(2,1)" in line: h0_21 = float(line.split()[-2]) elif "H0(2,2)" in line: h0_22 = float(line.split()[-2]) elif "H0(2,3)" in line: h0_23 = float(line.split()[-2]) elif "H0(3,1)" in line: h0_31 = float(line.split()[-2]) elif "H0(3,2)" in line: h0_32 = float(line.split()[-2]) elif "H0(3,3)" in line: h0_33 = float(line.split()[-2]) elif "entry_count" in line: self.entry_count = int(line.split()[-1]) n_standard_args = 6 if self.has_velocity else 3 for _ in range(self.entry_count - n_standard_args): self.auxiliary.append(None) index_auxiliary = index + 1 break else: continue self.atoms.cell = [[h0_11, h0_12, h0_13], [h0_21, h0_22, h0_23], [h0_31, h0_32, h0_33]] for (index, line) in enumerate(self.content[index_auxiliary:], index_auxiliary): if line.startswith("auxiliary"): i = int(find_between(line, "[", "]")) _, __, auxiliary = tuple(line.split()) self.auxiliary[i] = auxiliary else: index_atoms = index break for i in range(index_atoms, len(self.content), 3): typ = clear_end(self.content[i + 1], [" ", "\n", "\t"]) if typ in self.ignore_types: continue mass = float(self.content[i + 0]) etc = dict() if self.has_velocity: raise TypeError("cfg with velocities! not implemented yet!") else: x, y, z, *args = tuple(self.content[i + 2].split()) atom = Atom(atom_type=typ, position=[float(x), float(y), float(z)]) atom.position = np.matmul(self.atoms.cell, atom.position) atom.type.mass = mass for (index, arg) in enumerate(args): etc[self.auxiliary[index]] = arg # string atom.etc = etc self.atoms.add_atom(atom) if self.number_of_particles != len( self.atoms) and not self.ignore_types: print("WARNING: file says {} atoms, but only {} were found".format( self.number_of_particles, len(self.atoms)))
def check_bond_dissociation_energy_and_isomorphic_and_rings( self, bond_list, bbond_list): energy = 0.0 reactant_graph = self.reac_mol_graph atoms = [ Atom(atomic_symbol=reactant_graph.atoms[i].label) for i in range(reactant_graph.n_atoms) ] product = Species(atoms) graph = nx.Graph() for i in range(reactant_graph.n_atoms): graph.add_node(i, atom_label=reactant_graph.atoms[i].label, stereo=False) if bond_list is not None: [ graph.add_edge(bond[0], bond[1], pi=False, active=False) for bond in bond_list ] product.graph = graph # Filter the isomorphic if is_isomorphic(reactant_graph.graph, product.graph): return False elif self.check_four_and_three_membered_rings(product.graph): return False else: # Filter the bond dissociation energy num = sum([bb[2] for bb in bbond_list]) for break_bond in bbond_list: first_atom = reactant_graph.atoms[break_bond[0]].label second_atom = reactant_graph.atoms[break_bond[1]].label bond_type = break_bond[2] supported_element = ['C', 'N', 'H', 'O', 'S', 'Cl', 'Si'] if first_atom not in supported_element or second_atom not in supported_element: # use 100 instead energy += 100 else: # consider if break double bond (2-->1 not break 2) then the bond dissociation use double bond energy - single bond energy if num >= 3 and bond_type >= 2: try: energy += props.bond_dissociation_energy[ first_atom, second_atom, bond_type] energy -= props.bond_dissociation_energy[ first_atom, second_atom, bond_type - 1] except: energy += props.bond_dissociation_energy[ second_atom, first_atom, bond_type] energy -= props.bond_dissociation_energy[ second_atom, first_atom, bond_type - 1] else: try: energy += props.bond_dissociation_energy[ first_atom, second_atom, bond_type] except: energy += props.bond_dissociation_energy[ second_atom, first_atom, bond_type] if energy / _constants.CAL2J > self.bond_dissociation_cutoff: return False else: return True
def carbon_dioxide(bond_length=None): if bond_length == None: bl = param.carbon_dioxide['c-h']['angstrom'] else: bl = bond_length return [Atom('C', [0,0,0]), Atom('O', [0,0,-bl]), Atom('O',[0,0,bl])]
def _water(r1 , r2 , theta): molecule = [Atom('O', [0, 0, 0]), Atom('H', [0, r1 * np.sin(theta / 2), r1 * np.cos(theta / 2)]), Atom('H', [0, -r2 * np.sin(theta / 2), r2 * np.cos(theta / 2)])] return molecule