def readXYZ(xyz, bonds=None): # extract molecule information from xyz mol = next(pb.readfile('xyz', xyz)) # Manually give bond information # (Because in metal system the bond information detect by openbabel usually have some problem) m = Molecule(pb.ob.OBMol()) obmol = m.OBMol obmol.BeginModify() for atom in mol: coords = [coord for coord in atom.coords] atomno = atom.atomicnum obatom = ob.OBAtom() obatom.thisown = 0 obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) del obatom bonds = [(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetBondOrder()) for bond in pb.ob.OBMolBondIter(mol.OBMol)] bonds.extend([(12, 14, 1), (12, 15, 1), (12, 16, 1), (12, 17, 1), (12, 13, 1), (17, 23, 1), (16, 23, 1)]) for bond in bonds: obmol.AddBond(bond[0], bond[1], bond[2]) # obmol.PerceiveBondOrders() # obmol.SetTotalCharge(int(mol.charge)) # obmol.Center() obmol.EndModify() mol_obj = gen3D.Molecule(obmol) return mol_obj
def xyz_to_pyMol(xyz, cluster_bond_path=None): mol = next(pybel.readfile('xyz', xyz)) if cluster_bond_path: m = pybel.ob.OBMol() m.BeginModify() for atom in mol: coords = [coord for coord in atom.coords] atomno = atom.atomicnum obatom = ob.OBAtom() obatom.thisown = 0 obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) m.AddAtom(obatom) del obatom with open(cluster_bond_path, 'r') as f: lines = f.read() cluster_bond = eval(lines) bonds = [(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetBondOrder()) for bond in pybel.ob.OBMolBondIter(mol.OBMol)] bonds.extend(cluster_bond) for bond in bonds: m.AddBond(bond[0], bond[1], bond[2]) pybelmol = pybel.Molecule(m) return pybelmol else: return mol
def readXYZ(xyz, bonds=None, cluster_bond=None, fixed_atoms=None): # extract molecule information from xyz mol = next(pb.readfile('xyz', xyz)) reactant_atom = [a.OBAtom.GetAtomicNum() for a in mol] # Manually give bond information # (Because in metal system the bond information detect by openbabel usually have some problem) if bonds or cluster_bond: m = Molecule(pb.ob.OBMol()) obmol = m.OBMol obmol.BeginModify() for atom in mol: coords = [coord for coord in atom.coords] atomno = atom.atomicnum obatom = ob.OBAtom() obatom.thisown = 0 obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) del obatom if cluster_bond: bonds = [(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx(), bond.GetBondOrder()) for bond in pb.ob.OBMolBondIter(mol.OBMol)] #bonds = imaginary_bond(bonds, reactant_atom, fixed_atoms) bonds.extend(cluster_bond) for bond in bonds: obmol.AddBond(bond[0], bond[1], bond[2]) # obmol.ConnectTheDots() obmol.PerceiveBondOrders() # obmol.SetTotalSpinMultiplicity(1) obmol.SetTotalCharge(int(mol.charge)) obmol.Center() obmol.EndModify() mol_obj = gen3D.Molecule(obmol) reactant_graph = Species(xyz_file_to_atoms(xyz)) reactant_bonds = [(i[0] - 1, i[1] - 1) for i in bonds] make_graph(reactant_graph, bond_list=reactant_bonds) else: mol_obj = gen3D.Molecule(mol.OBMol) reactant_graph = Species(xyz_file_to_atoms(xyz)) reactant_bonds = tuple( sorted([(bond.GetBeginAtomIdx() - 1, bond.GetEndAtomIdx() - 1) for bond in pb.ob.OBMolBondIter(mol.OBMol)])) make_graph(reactant_graph, bond_list=reactant_bonds) return mol_obj, reactant_graph
def generate_inter_lp(init_str: pybel.Molecule, end_str: pybel.Molecule, inter: int): int_list = [pybel.Molecule(ob.OBMol()) for i in range(inter)] for i, j in zip(init_str.atoms, end_str.atoms): # define the vector for propagation i_coord = np.array(i.coords) j_coord = np.array(j.coords) coord_vector = (j_coord - i_coord) / (inter + 1) for k in range(inter): # define the atomic position for k-th intermediate and write to OBmol object atom_position = i_coord + coord_vector * (k + 1) newatom = ob.OBAtom() newatom.SetAtomicNum(i.OBAtom.GetAtomicNum()) newatom.SetVector(atom_position[0], atom_position[1], atom_position[2]) int_list[k].OBMol.AddAtom(newatom) return int_list
def add_atom(self, _atom): """ Adds an atom to the molecule This method creates OBAtoms based on the atoms so it can use the internal functions that openbabel provides through OBMol. Note: This will surely break at some point for .pdb files etc. """ if not isinstance(_atom, Atom): raise TypeError _obatom = openbabel.OBAtom() _obatom.SetAtomicNum(_atom.get_nuclear_charge()) x, y, z = _atom.get_coordinate() _obatom.SetVector(x, y, z) _obatom.SetId(_atom.get_idx()) _obatom.SetFormalCharge(_atom.get_formal_charge()) self._obmol.AddAtom(_obatom)
def makeopenbabel(atomcoords, atomnos, charge=0, mult=1): """Create an Open Babel molecule.""" _check_openbabel(_found_openbabel) obmol = ob.OBMol() for i in range(len(atomnos)): # Note that list(atomcoords[i]) is not equivalent!!! # For now, only take the last geometry. # TODO: option to export last geometry or all geometries? coords = atomcoords[-1][i].tolist() atomno = int(atomnos[i]) obatom = ob.OBAtom() obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) obmol.ConnectTheDots() obmol.PerceiveBondOrders() obmol.SetTotalSpinMultiplicity(mult) obmol.SetTotalCharge(int(charge)) return obmol
def find_N_cap(self): a1 = ob.OBAtom() for atom in ob.OBAtomAtomIter(self.NTerminus): if atom.GetAtomicNum() == 6: for n_atom in ob.OBAtomAtomIter(atom): if n_atom.GetAtomicNum() == 8 and atom.GetBond( n_atom).GetBondOrder() == 2: self.NTermCap.AddAtom(atom) self.NTermCap.AddAtom(n_atom) a1 = atom for atom in ob.OBAtomAtomIter(self.NTerminus): if OBAminoAcid.Equals(atom, a1): for atom1 in ob.OBAtomAtomIter(atom): if atom1.GetAtomicNum() == 6: self.NTermCap.AddAtom(atom1) for n_atom1 in ob.OBAtomAtomIter(atom1): if not OBAminoAcid.Equals(n_atom1, atom): self.NTermCap.AddAtom(n_atom1)
def SulfurHydrogenator(sulfur, mainAtom, mol): sulfur_coords = np.array( [sulfur.GetX(), sulfur.GetY(), sulfur.GetZ()], dtype=float) main_atom_coords = np.array( [mainAtom.GetX(), mainAtom.GetY(), mainAtom.GetZ()], dtype=float) S = sulfur_coords C = main_atom_coords V = C - S print(S, C, V) V = V / np.linalg.norm(V) R = np.array([V[1] * V[2], -2 * V[0] * V[2], V[0] * V[1]], dtype=float) R = R / np.linalg.norm(R) H = R * math.cos(math.radians(2.1)) - V * math.sin(math.radians(2.1)) print(V, R, H) H = S + (1.34 * H) print(S, H) hydrogen = ob.OBAtom() hydrogen.SetAtomicNum(1) print(H[0], H[1], H[2]) hydrogen.SetVector(H[0], H[1], H[2]) if mol.AddAtom(hydrogen): print("Hydrogen Added Successfully to Sulfur") return mol
def to_obmol(self, explicit_hydrogen: Optional[bool] = True) -> ob.OBMol: obmol = ob.OBMol() for a in self.atoms: obatom = ob.OBAtom() obatom.SetAtomicNum(a.Z) obatom.SetVector(*a.position.squeeze()) obmol.AddAtom(obatom) obmol.ConnectTheDots() obmol.PerceiveBondOrders() if not explicit_hydrogen: obmol.DeleteHydrogens() # NOTE: empirically, this appears to renumber the atoms correctly # (i.e. it maintains the original order as specified by self.atoms while # removing hydrogens & renumbering sequentially) # this is consistent with how to_graph works return obmol
def __init__(self, mol): """ Initializes with pymatgen Molecule or OpenBabel"s OBMol. Args: mol: pymatgen's Molecule/IMolecule or OpenBabel OBMol """ if isinstance(mol, IMolecule): if not mol.is_ordered: raise ValueError( "OpenBabel Molecule only supports ordered molecules.") # For some reason, manually adding atoms does not seem to create # the correct OBMol representation to do things like force field # optimization. So we go through the indirect route of creating # an XYZ file and reading in that file. obmol = ob.OBMol() obmol.BeginModify() for site in mol: coords = list(site.coords) atomno = site.specie.Z obatom = ob.OBAtom() obatom.thisown = 0 obatom.SetAtomicNum(atomno) obatom.SetVector(*coords) obmol.AddAtom(obatom) del obatom obmol.ConnectTheDots() obmol.PerceiveBondOrders() obmol.SetTotalSpinMultiplicity(mol.spin_multiplicity) obmol.SetTotalCharge(int(mol.charge)) obmol.Center() obmol.EndModify() self._obmol = obmol elif isinstance(mol, ob.OBMol): self._obmol = mol elif isinstance(mol, pb.Molecule): self._obmol = mol.OBMol
def test_building_a_molecule(self): mol = ob.OBMol() C = add_atom(mol, 6) N = add_atom(mol, 7) # XXX Why can't I do mol.AddBond(C, N, 3)? mol.AddBond(C.GetIdx(), N.GetIdx(), 3) self.assertEqual(C.ImplicitHydrogenCount(), 1) C.IncrementImplicitValence( ) # Is this how to increment the implicit hcount? self.assertEqual(C.ImplicitHydrogenCount(), 2) conv = ob.OBConversion() conv.SetOutFormat("can") s = conv.WriteString(mol).strip() # XXX How does this work when the ImplicitHydrogenCount is 2?? XXX self.assertEqual(s, "C#N") # I can even add an atom this way. (Why are there 2 ways?) O = ob.OBAtom() O.SetAtomicNum(8) mol.AddAtom(O) O.SetImplicitValence(2) s = conv.WriteString(mol).strip() self.assertEqual(s, "C#N.O")
def Hydrogenate(carbon, mainAtom, mol): """ Adds 3 hydrogens to a molecule that will be bonded to a carbon carbon: The carbon atom where the 3 hydrogens will be added to mainAtom: The other atom the carbon is attached to mol: The molecule that will be hydrogenated returns: THe hydrogenated molecule """ chbl = 1.09 bond_length = carbon.GetDistance(mainAtom) Ux = mainAtom.GetX() - carbon.GetX() Uy = mainAtom.GetY() - carbon.GetY() Uz = mainAtom.GetZ() - carbon.GetZ() U = np.array([Ux, Uy, Uz]) V = np.array([Uy * Uz, -2 * Ux * Uz, Ux * Uy]) U = U / (np.linalg.norm(U)) V = V / (np.linalg.norm(V)) ang1 = math.radians(70.5) H1 = -U * math.cos(ang1) + V * math.sin(ang1) h1 = ob.OBAtom() h1.SetAtomicNum(1) h1.SetVector(carbon.GetX() + H1[0] * chbl, carbon.GetY() + H1[1] * chbl, carbon.GetZ() + H1[2] * chbl) mol.AddAtom(h1) Z = -U - H1 Z = Z / (np.linalg.norm(Z)) Y = np.cross(U, H1) Y = Y / (np.linalg.norm(Y)) X = np.cross(Y, Z) X = X / (np.linalg.norm(X)) ang2 = math.radians(54.7) H2 = Z * math.cos(ang2) + Y * math.sin(ang2) h2 = ob.OBAtom() h2.SetAtomicNum(1) h2.SetVector(carbon.GetX() + H2[0] * chbl, carbon.GetY() + H2[1] * chbl, carbon.GetZ() + H2[2] * chbl) if mol.AddAtom(h2): print("Success adding H2") H3 = -(H1 + H2 + U) H3 = H3 / (np.linalg.norm(H3)) h3 = ob.OBAtom() h3.SetAtomicNum(1) h3.SetVector(carbon.GetX() + H3[0] * chbl, carbon.GetY() + H3[1] * chbl, carbon.GetZ() + H3[2] * chbl) if mol.AddAtom(h3): print("Success adding H3") return mol