def test_simple_heterocycle_mapping(iupac_pairs=[('benzene', 'pyridine')]): """ Test the ability to map conjugated heterocycles (that preserves all rings). Will assert that the number of ring members in both molecules is the same. """ # TODO: generalize this to test for ring breakage and closure. from openmoltools.openeye import iupac_to_oemol from openeye import oechem from perses.rjmc.topology_proposal import AtomMapper for iupac_pair in iupac_pairs: old_oemol, new_oemol = iupac_to_oemol(iupac_pair[0]), iupac_to_oemol( iupac_pair[1]) new_to_old_map = AtomMapper._get_mol_atom_map( old_oemol, new_oemol, allow_ring_breaking=False) #assert that the number of ring members is consistent in the mapping... num_hetero_maps = 0 for new_index, old_index in new_to_old_map.items(): old_atom, new_atom = old_oemol.GetAtom( oechem.OEHasAtomIdx(old_index)), new_oemol.GetAtom( oechem.OEHasAtomIdx(new_index)) if old_atom.IsInRing() and new_atom.IsInRing(): if old_atom.GetAtomicNum() != new_atom.GetAtomicNum(): num_hetero_maps += 1 assert num_hetero_maps > 0, f"there are no differences in atomic number mappings in {iupac_pair}"
def bond_order_tag(molecule, atom_map, bond_order_array): """ Add psi bond order to bond in molecule. This function adds a tag to the GetData dictionary in bond.GetData() Parameters ---------- molecule: OEMol This molecule must have tags that corresponds to the atom_map atom_map: dict dictionary that maps atom tag to atom index bond_order_array: dict maps Wiberg and Meyer bond indices to N x N numpy arrays. N - atoms in molecule. This array contains the bond order for bond(i,j) where i,j correspond to tag on atom and index in bond_order_array """ wiberg_bond_order = bond_order_array['Wiberg_psi4'] mayer_bond_order = bond_order_array['Mayer_psi4'] # Sanity check, both arrays are same shape for i, j in itertools.combinations(range(wiberg_bond_order.shape[0]), 2): idx_1 = atom_map[i + 1] idx_2 = atom_map[j + 1] atom_1 = molecule.GetAtom(oechem.OEHasAtomIdx(idx_1)) atom_2 = molecule.GetAtom(oechem.OEHasAtomIdx(idx_2)) bond = molecule.GetBond(atom_1, atom_2) if bond: wbo = wiberg_bond_order[i][j] mbo = mayer_bond_order[i][j] tag = oechem.OEGetTag('Wiberg_psi4') bond.SetData(tag, wbo) tag = oechem.OEGetTag('Mayer_psi4') bond.SetData(tag, mbo)
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False): """ Generate OEMol from QCSchema molecule specs Parameters ---------- inp_molecule: dict Must have symbols and connectivity and/or geometry Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and isomeric SMILES. Returns ------- molecule: OEMol """ molecule = oechem.OEMol() for s in symbols: molecule.NewAtom(_symbols[s]) # Add connectivity for bond in connectivity: a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0])) a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1])) bond_order = bond[-1] if not isinstance(bond_order, int) and not bond_order.is_integer(): raise ValueError( "bond order must be a whole number. A bond order of 1.5 is not allowed" ) molecule.NewBond(a1, a2, int(bond_order)) # Add geometry if molecule.NumAtoms() != geometry.shape[0] / 3: raise ValueError( "Number of atoms in molecule does not match length of position array" ) molecule.SetCoords(oechem.OEFloatArray(geometry)) molecule.SetDimension(3) if not permute_xyz: # Add tag that the geometry is from JSON and shouldn't be changed. geom_tag = oechem.OEGetTag("json_geometry") molecule.SetData(geom_tag, True) oechem.OEDetermineConnectivity(molecule) oechem.OEFindRingAtomsAndBonds(molecule) # No need to perceive Bond Order because the information was added from the connectivity table. Apparently, this # function does many different perceptions under the hood and it can add implicit hydrogens to divalent N that should be negatively charged. #oechem.OEPerceiveBondOrders(molecule) # This seems to add hydrogens that are not in the json #oechem.OEAssignImplicitHydrogens(molecule) oechem.OEAssignFormalCharges(molecule) oechem.OEAssignAromaticFlags(molecule) oechem.OEPerceiveChiral(molecule) oechem.OE3DToAtomStereo(molecule) oechem.OE3DToBondStereo(molecule) return molecule
def __call__(self, bond): atomB = bond.GetBgn() atomE = bond.GetEnd() mol = bond.GetParent() atom1 = mol.GetAtom(oechem.OEHasAtomIdx(self.atom1_idx)) atom2 = mol.GetAtom(oechem.OEHasAtomIdx(self.atom2_idx)) return max(oechem.OEGetPathLength(atomB, atom1), oechem.OEGetPathLength(atomE, atom1), oechem.OEGetPathLength(atomB, atom2), oechem.OEGetPathLength(atomE, atom2)) <= 3
def test_tag_molecule(self): """Test tag molecule""" tagged_rings, tagged_funcgroup = fragment.tag_molecule(charged) atom_idx = tagged_rings[1][0].pop() atom = charged.GetAtom(oechem.OEHasAtomIdx(atom_idx)) ringsystem = atom.GetData('ringsystem') self.assertEquals(1, ringsystem) atom_idx = tagged_funcgroup['amide_0'][0].pop() atom = charged.GetAtom(oechem.OEHasAtomIdx(atom_idx)) funcgroup = atom.GetData('fgroup') self.assertEquals('amide_0', funcgroup)
def gen_starting_confs(mol, torsion_library, max_one_bond_away=True, num_conformers=MAX_CONFS, rms_cutoff=0.0, energy_window=25): # Identify the atoms in the dihedral TAGNAME = 'TORSION_ATOMS_FRAGMENT' if not has_sd_data(mol, TAGNAME): raise ValueError("Molecule does not have the SD Data Tag '{}'.".format(TAGNAME)) dihedralAtomIndices = [int(x)-1 for x in get_sd_data(mol, TAGNAME).split()] inDih = \ oechem.OEOrAtom(oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[0]), oechem.OEHasAtomIdx(dihedralAtomIndices[1])), oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[2]), oechem.OEHasAtomIdx(dihedralAtomIndices[3])) ) mol1 = mol.CreateCopy() mc_mol = oechem.OEMol(mol1) if num_conformers > 1: # Set criterion for rotatable bond if False and max_one_bond_away: # this max function makes this seem potentially broken only_one_bond_away = distance_predicate(dihedralAtomIndices[1], dihedralAtomIndices[2]) rotor_predicate = oechem.OEAndBond(only_one_bond_away, oechem.PyBondPredicate(isRotatableBond)) elif False: # this ONLY samples special bonds & neglects "regualr" torsions rotor_predicate = oechem.PyBondPredicate(isRotatableBond) else: # try this more general sampling, but leave prior versions untouched rotor_predicate = oechem.OEOrBond(oechem.OEIsRotor(), oechem.PyBondPredicate(isRotatableBond)) #Initialize conformer generator and multi-conformer library conf_generator = configure_omega(torsion_library, rotor_predicate, rms_cutoff, energy_window, num_conformers) # Generator conformers if not conf_generator(mc_mol, inDih): raise ValueError("Conformers cannot be generated.") logging.debug("Generated a total of %d conformers for %s.", mc_mol.NumConfs(), mol.GetTitle()) for conf_no, conf in enumerate(mc_mol.GetConfs()): conformer_label = mol.GetTitle()+'_' +\ '_'.join(get_sd_data(mol, 'TORSION_ATOMS_ParentMol').split()) +\ '_{:02d}'.format(conf_no) oechem.OESetSDData(conf, "CONFORMER_LABEL", conformer_label) conf.SetTitle(conformer_label) return mc_mol
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False): """ Generate OEMol from QCSchema molecule specs Parameters ---------- inp_molecule: dict Must have symbols and connectivity and/or geometry Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and isomeric SMILES. Returns ------- molecule: OEMol """ molecule = oechem.OEMol() for s in symbols: molecule.NewAtom(_symbols[s]) # Add connectivity for bond in connectivity: a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0])) a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1])) molecule.NewBond(a1, a2, bond[-1]) # Add geometry if molecule.NumAtoms() != geometry.shape[0] / 3: raise ValueError( "Number of atoms in molecule does not match length of position array" ) molecule.SetCoords(oechem.OEFloatArray(geometry)) molecule.SetDimension(3) if not permute_xyz: # Add tag that the geometry is from JSON and shouldn't be changed. geom_tag = oechem.OEGetTag("json_geometry") molecule.SetData(geom_tag, True) oechem.OEDetermineConnectivity(molecule) oechem.OEFindRingAtomsAndBonds(molecule) oechem.OEPerceiveBondOrders(molecule) # This seems to add hydrogens that are not in the json #oechem.OEAssignImplicitHydrogens(molecule) oechem.OEAssignFormalCharges(molecule) oechem.OEAssignAromaticFlags(molecule) oechem.OEPerceiveChiral(molecule) oechem.OE3DToAtomStereo(molecule) oechem.OE3DToBondStereo(molecule) return molecule
def gen_starting_confs(mol, torsion_library, num_conformers=MAX_CONFS, rms_cutoff=0.0, energy_window=25): # Identify the atoms in the dihedral TAGNAME = 'TORSION_ATOMS_FRAGMENT' if not has_sd_data(mol, TAGNAME): raise ValueError( "Molecule does not have the SD Data Tag '{}'.".format(TAGNAME)) dihedralAtomIndices = [ int(x) - 1 for x in get_sd_data(mol, TAGNAME).split() ] inDih = \ oechem.OEOrAtom(oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[0]), oechem.OEHasAtomIdx(dihedralAtomIndices[1])), oechem.OEOrAtom(oechem.OEHasAtomIdx(dihedralAtomIndices[2]), oechem.OEHasAtomIdx(dihedralAtomIndices[3])) ) mol1 = mol.CreateCopy() mc_mol = oechem.OEMol(mol1) if num_conformers > 1: rotor_predicate = oechem.OEOrBond( oechem.OEIsRotor(), oechem.PyBondPredicate(isRotatableBond)) #Initialize conformer generator and multi-conformer library conf_generator = configure_omega(torsion_library, rotor_predicate, rms_cutoff, energy_window, num_conformers) # Generator conformers if not conf_generator(mc_mol, inDih): raise ValueError("Conformers cannot be generated.") logging.debug("Generated a total of %d conformers for %s.", mc_mol.NumConfs(), mol.GetTitle()) for conf_no, conf in enumerate(mc_mol.GetConfs()): conformer_label = mol.GetTitle()+'_' +\ '_'.join(get_sd_data(mol, 'TORSION_ATOMS_ParentMol').split()) +\ '_{:02d}'.format(conf_no) oechem.OESetSDData(conf, "CONFORMER_LABEL", conformer_label) conf.SetTitle(conformer_label) return mc_mol
def to_atom_bond_set(oemol, atoms, bonds): from openeye import oechem atom_bond_set = oechem.OEAtomBondSet() for a_idx in atoms: atom = oemol.GetAtom(oechem.OEHasAtomIdx(a_idx)) atom_bond_set.AddAtom(atom) for b_tuple in bonds: a1 = oemol.GetAtom(oechem.OEHasAtomIdx(b_tuple[0])) a2 = oemol.GetAtom(oechem.OEHasAtomIdx(b_tuple[-1])) bond = oemol.GetBond(a1, a2) if not bond: raise ValueError("{} is a disconnected bond".format(b_tuple)) atom_bond_set.AddBond(bond) return atom_bond_set
def get_modified_inchi_key(mol, atoms): """ Generates InChIKey for the input molecule. Passed atoms of the molecule are mutated (atomic number changed) based on the mapping defined in the function. @param mol: @param atoms: @type mol: OEGraphMol @type atoms: list[OEAtombase] @return: str """ copy_mol = oechem.OEGraphMol(mol) atom_map = { oechem.OEElemNo_C: oechem.OEElemNo_Pb, oechem.OEElemNo_N: oechem.OEElemNo_Bi, oechem.OEElemNo_O: oechem.OEElemNo_Po, oechem.OEElemNo_F: oechem.OEElemNo_At, oechem.OEElemNo_S: oechem.OEElemNo_Te, oechem.OEElemNo_Cl: oechem.OEElemNo_I, oechem.OEElemNo_P: oechem.OEElemNo_Sb, oechem.OEElemNo_Br: 117, oechem.OEElemNo_I: 118, } for ref_atom in atoms: copy_atom = copy_mol.GetAtom(oechem.OEHasAtomIdx(ref_atom.GetIdx())) if copy_atom is None: raise Exception("Null atom found") copy_atom.SetAtomicNum(atom_map[copy_atom.GetAtomicNum()]) return oechem.OECreateInChIKey(copy_mol)
def _ring_substiuents(mol, bond, rotor_bond, tagged_rings, ring_idx, fgroup_tagged): """ This function finds ring substituents that shouldn't be cut off Parameters ---------- mol: OpeneEye OEMolGraph bond: OpenEye Bond Base current bond that the iterator is looking at rotor_bond: OpeneEye Bond Base rotatable bond that fragment is being grown on tagged_rings: dict mapping of ring index and atom and bonds indices ring_idx: int ring index fgroup_tagged: dict mapping of functional group and atom and bond indices Returns ------- rs_atoms, rs_bonds: sets of ring substituents atoms and bonds indices """ rs_atoms = set() rs_bonds = set() r_atoms, r_bonds = tagged_rings[ring_idx] for a_idx in r_atoms: atom = mol.GetAtom(oechem.OEHasAtomIdx(a_idx)) for a in atom.GetAtoms(): if a.GetIdx() in rs_atoms: continue fgroup = False rs_bond = mol.GetBond(atom, a) if not a.IsInRing(): if not rs_bond.IsRotor(): rs_atoms.add(a.GetIdx()) rs_bonds.add(rs_bond.GetIdx()) # Check for functional group fgroup = _is_fgroup(fgroup_tagged, element=a) elif _is_ortho(rs_bond, rotor_bond, bond): # Keep bond and attached atom. rs_atoms.add(a.GetIdx()) rs_bonds.add(rs_bond.GetIdx()) # Check for functional group fgroup = _is_fgroup(fgroup_tagged, element=a) if fgroup: rs_atoms = rs_atoms.union(fgroup[0]) rs_bonds = rs_bonds.union(fgroup[-1]) else: # Check if they are in the same ring r_idx2 = a.GetData('ringsystem') if r_idx2 != ring_idx: if _is_ortho(rs_bond, rotor_bond, bond): # Add ring system rs_bonds.add(rs_bond.GetIdx()) r2_atoms, r2_bonds = tagged_rings[r_idx2] rs_atoms = rs_atoms.union(r2_atoms) rs_bonds = rs_bonds.union(r2_bonds) return rs_atoms, rs_bonds
def bond_order_to_bond_graph(bond_order, threshold=0.8, hydrogen_bond=True, molecule=None, atom_map=None): """ Get bond graph from bond orders. This function returns a set of bonds where the bond order is above a threshold Parameters ---------- bond_order: np array threshold: int Returns ------- bonds: set """ bonds = set() for i in range(bond_order.shape[0]): for j in range(bond_order.shape[1]): if bond_order[i, j] >= threshold: if not hydrogen_bond: idx_1 = atom_map[i + 1] idx_2 = atom_map[j + 1] atom_1 = molecule.GetAtom(oechem.OEHasMapIdx(idx_1)) atom_2 = molecule.GetAtom(oechem.OEHasAtomIdx(idx_2)) if atom_1.IsHydrogen() or atom_2.IsHydrogen(): continue if (j + 1, i + 1) in bonds: continue bonds.add((i + 1, j + 1)) return bonds
def to_mapped_xyz(molecule, atom_map=None, conformer=None, xyz_format=True, filename=None): """ Generate xyz coordinates for molecule in the order given by the atom_map. atom_map is a dictionary that maps the tag on the SMILES to the atom idex in OEMol. Parameters ---------- molecule: OEMol with conformers atom_map: dict maps tag in SMILES to atom index conformer: int Which conformer to write xyz file for. If None, write out all conformers. Default is None xyz_format: bool If True, will write out number of atoms and molecule name. If false, will only write out elements and coordinates filename: str Name of file to save to. If None, only returns a string. Returns ------- str: elements and xyz coordinates (in angstroms) in order of tagged SMILES """ if not atom_map and not cmiles.utils.has_atom_map(molecule): raise ValueError( "If molecule does not have atom map, you must provide an atom map") if not has_conformer(molecule, check_two_dimension=True): raise ValueError("Molecule must have conformers") xyz = "" for k, mol in enumerate(molecule.GetConfs()): if k == conformer or conformer is None: if xyz_format: xyz += "{}\n".format(mol.GetMaxAtomIdx()) xyz += "{}\n".format(mol.GetTitle()) coords = oechem.OEFloatArray(mol.GetMaxAtomIdx() * 3) mol.GetCoords(coords) if k != 0 and not xyz_format: xyz += "*" for mapping in range(1, molecule.NumAtoms() + 1): if not atom_map: atom = molecule.GetAtom(oechem.OEHasMapIdx(mapping)) idx = atom.GetIdx() else: idx = atom_map[mapping] atom = mol.GetAtom(oechem.OEHasAtomIdx(idx)) syb = oechem.OEGetAtomicSymbol(atom.GetAtomicNum()) xyz += " {} {:05.3f} {:05.3f} {:05.3f}\n".format( syb, coords[idx * 3], coords[idx * 3 + 1], coords[idx * 3 + 2]) if filename: file = open("{}.xyz".format(filename), 'w') file.write(xyz) file.close() else: return xyz
def test_tag_funcgroup(self): """ Test tag functional groups """ tagged_funcgroups = fragment._tag_fgroups(charged) self.assertEquals(len(tagged_funcgroups), 3) atom_idx = tagged_funcgroups['amide_0'][0].pop() atom = charged.GetAtom(oechem.OEHasAtomIdx(atom_idx)) fgroup = atom.GetData('fgroup') self.assertEquals('amide_0', fgroup)
def test_tag_rings(self): """ Test tag rings""" tagged_rings = fragment._tag_rings(charged) self.assertEquals(len(tagged_rings), 3) atom_idx = tagged_rings[1][0].pop() atom = charged.GetAtom(oechem.OEHasAtomIdx(atom_idx)) ringsystem = atom.GetData('ringsystem') self.assertEquals(1, ringsystem)
def MakeCliques(surf, mol): for i in range(surf.GetNumVertices()): atom = mol.GetAtom(oechem.OEHasAtomIdx(surf.GetAtomsElement(i))) if atom.IsOxygen() or atom.IsNitrogen() or atom.IsPolarHydrogen(): surf.SetVertexCliqueElement(i, 1) surf.SetColorElement(i, 0.0, 0.0, 1.0) else: surf.SetColorElement(i, 1.0, 0.0, 0.0) return True
def test_is_fgroup(self): """Test is functional group """ tagged_rings, taggged_funcgroup = fragment.tag_molecule(charged) atom_idx = taggged_funcgroup['amide_0'][0].pop() bond_idx = taggged_funcgroup['amide_0'][-1].pop() atom = charged.GetAtom(oechem.OEHasAtomIdx(atom_idx)) bond = charged.GetBond(oechem.OEHasBondIdx(bond_idx)) self.assertTrue(fragment._is_fgroup(taggged_funcgroup, atom)) self.assertTrue(fragment._is_fgroup(taggged_funcgroup, bond))
def _ring_fgroup_union(mol, tagged_rings, tagged_fgroups, wbo_threshold=1.2): """ This function combines rings and fgroups that are conjugated (the bond between them has a Wiberg bond order > 1.2) Parameters ---------- mol: OpenEye OEMolGraph tagged_rings: dict map of ringsystem indices to ring atom and bond indices tagged_fgroup: dict map of fgroup to fgroup atom and bond indices Returns ------- tagged_fgroup: dict updated tagged_fgroup mapping with rings that shouldn't be fragmented from fgroups """ ring_idxs = list(tagged_rings.keys()) fgroups = list(tagged_fgroups.keys()) tagged_fgroups = copy.deepcopy(tagged_fgroups) # Check if fgroups are overlapping. If they are - combine them. for func_group_1, func_group_2 in itertools.combinations(list(tagged_fgroups.keys()), 2): atoms_intersection = tagged_fgroups[func_group_1][0].intersection(tagged_fgroups[func_group_2][0]) if len(atoms_intersection) > 1: # Combine fgroups atoms_union = tagged_fgroups[func_group_1][0].union(tagged_fgroups[func_group_2][0]) bonds_union = tagged_fgroups[func_group_1][-1].union(tagged_fgroups[func_group_2][-1]) tagged_fgroups[func_group_1] = (atoms_union, bonds_union) tagged_fgroups[func_group_2] = (atoms_union, bonds_union) for idx in ring_idxs: for fgroup in fgroups: atom_intersection = tagged_rings[idx][0].intersection(tagged_fgroups[fgroup][0]) if len(atom_intersection) > 1: # Must include ring if including fgroup. Add ring atoms and bonds to fgroup atoms_union = tagged_rings[idx][0].union(tagged_fgroups[fgroup][0]) bonds_union = tagged_rings[idx][-1].union(tagged_fgroups[fgroup][-1]) tagged_fgroups[fgroup] = (atoms_union, bonds_union) elif len(atom_intersection) > 0: # Check Wiberg bond order of bond # First find bond connectiong fgroup and ring atom = mol.GetAtom(oechem.OEHasAtomIdx(atom_intersection.pop())) for a in atom.GetAtoms(): if a.GetIdx() in tagged_fgroups[fgroup][0]: bond = mol.GetBond(a, atom) if bond.GetData('WibergBondOrder') > wbo_threshold: # Don't cut off ring. atoms_union = tagged_rings[idx][0].union(tagged_fgroups[fgroup][0]) bonds_union = tagged_rings[idx][-1].union(tagged_fgroups[fgroup][-1]) tagged_fgroups[fgroup] = (atoms_union, bonds_union) # Should I also combine non-rotatable rings? This will pick up the alkyn in ponatinib? if not bond.IsRotor(): atoms_union = tagged_rings[idx][0].union(tagged_fgroups[fgroup][0]) bonds_union = tagged_rings[idx][-1].union(tagged_fgroups[fgroup][-1]) tagged_fgroups[fgroup] = (atoms_union, bonds_union) # Do something when it's neither for edge cases (Afatinib)? return tagged_fgroups
def get_fragment_to_parent_atom_mapping(parent_mol, frag_mol): try: mapping_data = oechem.OEGetSDData(frag_mol, FRAGMENT_TO_PARENT_ATOMS_KEY) idx_map = dict( map(int, idx_pair.split('_')) for idx_pair in mapping_data.split('-')) atom_map = {} for frag_idx, parent_idx in idx_map.items(): frag_atom = frag_mol.GetAtom(oechem.OEHasAtomIdx(frag_idx - 1)) parent_atom = parent_mol.GetAtom( oechem.OEHasAtomIdx(parent_idx - 1)) if frag_atom is not None and parent_atom is not None: atom_map[frag_atom] = parent_atom return atom_map except Exception as e: logging.warning(e) return {}
def test_mapped_xyz(self): """Test writing out mapped xyz""" from openeye import oechem, oeomega tagged_smiles = '[H:10][c:4]1[c:3]([c:2]([c:1]([c:6]([c:5]1[H:11])[H:12])[C:7]([H:13])([H:14])[H:15])[H:8])[H:9]' mol_1 = chemi.smiles_to_oemol('Cc1ccccc1') inf = get_fn('toluene.mol2') ifs = oechem.oemolistream(inf) mol_2 = oechem.OEMol() oechem.OEReadMolecule(ifs, mol_2) mol_1 = chemi.generate_conformers(mol_1, max_confs=1) atom_map = get_atom_map(mol_1, tagged_smiles) for i, mapping in enumerate(atom_map): atom_1 = mol_1.GetAtom(oechem.OEHasAtomIdx(atom_map[mapping])) atom_1.SetAtomicNum(i + 1) atom_2 = mol_2.GetAtom(oechem.OEHasAtomIdx(mapping - 1)) atom_2.SetAtomicNum(i + 1) xyz_1 = chemi.to_mapped_xyz(mol_1, atom_map, xyz_format=False) # molecule generated from mol2 should be in the right order. atom_map_mol2 = { 1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7, 9: 8, 10: 9, 11: 10, 12: 11, 13: 12, 14: 13, 15: 14 } xyz_2 = chemi.to_mapped_xyz(mol_2, atom_map_mol2, xyz_format=False) for ele1, ele2 in zip(xyz_1.split('\n')[:-1], xyz_2.split('\n')[:-1]): self.assertEqual(ele1.split(' ')[2], ele2.split(' ')[2])
def test_atom_map_order(self): """Test atom map""" from openeye import oechem tagged_smiles = '[H:5][C:1]#[N+:4][C:3]([H:9])([H:10])[C:2]([H:6])([H:7])[H:8]' mol_from_tagged_smiles = openeye.smiles_to_oemol(tagged_smiles) atom_map = utils.get_atom_map(tagged_smiles, mol_from_tagged_smiles) # Compare atom map to tag for i in range(1, len(atom_map) + 1): atom_1 = mol_from_tagged_smiles.GetAtom( oechem.OEHasAtomIdx(atom_map[i])) self.assertEqual(i, atom_1.GetMapIdx())
def extract_torsion_atoms(mol, bond): torsion_atoms_str_list = bond.GetData(TORSION_ATOMS_FRAGMENT_TAG).split( ':') torsion_atoms_list = [] for torsion_atoms_str in torsion_atoms_str_list: torsion_atoms_idx = list(map(int, torsion_atoms_str.split())) torsion_oeatoms \ = map(lambda idx: mol.GetAtom(oechem.OEHasAtomIdx(idx)), torsion_atoms_idx) a, b, c, d = list(torsion_oeatoms) torsion_atoms_list.append((a, b, c, d)) return torsion_atoms_list
def get_molecule(self): """ Extracts the parent molecule this atom is in Returns ------- mol: chemper Mol molecule this atom is stored in """ mol = oechem.OEMol(self.atom.GetParent()) self.atom = mol.GetAtom(oechem.OEHasAtomIdx(self._index)) return Mol(mol)
def get_torsion_oeatom_list(mol, tag="TORSION_ATOMS_FRAGMENT"): if has_sd_data(mol, tag): torsion_atoms = get_sd_data(mol, tag) try: torsion_atoms_idx = list(map(int, torsion_atoms.split())) torsion_oeatoms = map( lambda idx: mol.GetAtom(oechem.OEHasAtomIdx(idx - 1)), torsion_atoms_idx) return list(torsion_oeatoms) except Exception as e: print(e) return None
def get_dihedral(mol, dihedralAtomIndices): """Get the dihedral corresponding to the indices in dihedralAtomIndices. Note that the indices are zero-indexed. The torsion of interest is the bond between atoms with indices 1 and 2. """ # dihedralAtomIndices = [int(x) for x in get_sd_data(mol, 'TORSION_ATOMS_FRAGMENT').split()] dih = oechem.OEAtomBondSet() tor = oechem.OEAtomBondSet() for i in range(3): srcIdx = dihedralAtomIndices[i] destIdx = dihedralAtomIndices[i + 1] src = mol.GetAtom(oechem.OEHasAtomIdx(srcIdx)) dest = mol.GetAtom(oechem.OEHasAtomIdx(destIdx)) dih.AddAtom(src) bond = mol.GetBond(src, dest) dih.AddBond(bond) if i == 1: tor.AddBond(bond) dih.AddAtom(dest) return dih, tor
def get_atom_by_index(self, idx): """ Parameters ---------- idx: int atom index Returns ------- atom: chemper Atom object atom with index idx """ return Atom(self.mol.GetAtom(oechem.OEHasAtomIdx(idx)))
def highlight_atoms_in_mol(mol2, dihedralAtomIndices, width=200, height=200): mol = mol2.CreateCopy() opts = oedepict.OE2DMolDisplayOptions(width, height, oedepict.OEScale_AutoScale) oedepict.OEPrepareDepiction(mol) disp = oedepict.OE2DMolDisplay(mol, opts) img = oedepict.OEImage(width, height) hstyle = oedepict.OEHighlightByBallAndStick(oechem.OEBlueTint) for atom_idx in dihedralAtomIndices: oedepict.OEAddHighlighting(disp, hstyle, oechem.OEHasAtomIdx(atom_idx)) oedepict.OERenderMolecule(img, disp) return img
def noh(ls, dsets): """ This function remove hydrogens from the selection """ data_set = build_set(ls[1], dsets) noh_set = set() pred = oechem.OEIsHydrogen() for idx in data_set: atom = system.GetAtom(oechem.OEHasAtomIdx(idx)) if not pred(atom): noh_set.add(idx) return noh_set
def test_atom_map(self): """Test get atom map""" from openeye import oechem tagged_smiles = '[H:5][C:1]#[N+:4][C:3]([H:9])([H:10])[C:2]([H:6])([H:7])[H:8]' mol_1 = openeye.smiles_to_oemol('CC[N+]#C') inf = get_fn('ethylmethylidyneamonium.mol2') ifs = oechem.oemolistream(inf) mol_2 = oechem.OEMol() oechem.OEReadMolecule(ifs, mol_2) atom_map = utils.get_atom_map(tagged_smiles, mol_1) for i, mapping in enumerate(atom_map): atom_1 = mol_1.GetAtom(oechem.OEHasAtomIdx(atom_map[mapping])) atom_1.SetAtomicNum(i + 1) atom_2 = mol_2.GetAtom(oechem.OEHasAtomIdx(mapping - 1)) atom_2.SetAtomicNum(i + 1) self.assertEqual(oechem.OECreateCanSmiString(mol_1), oechem.OECreateCanSmiString(mol_2)) # Test aromatic molecule tagged_smiles = '[H:10][c:4]1[c:3]([c:2]([c:1]([c:6]([c:5]1[H:11])[H:12])[C:7]([H:13])([H:14])[H:15])[H:8])[H:9]' mol_1 = openeye.smiles_to_oemol('Cc1ccccc1') inf = get_fn('toluene.mol2') ifs = oechem.oemolistream(inf) mol_2 = oechem.OEMol() oechem.OEReadMolecule(ifs, mol_2) atom_map = utils.get_atom_map(tagged_smiles, mol_1) for i, mapping in enumerate(atom_map): atom_1 = mol_1.GetAtom(oechem.OEHasAtomIdx(atom_map[mapping])) atom_1.SetAtomicNum(i + 1) atom_2 = mol_2.GetAtom(oechem.OEHasAtomIdx(mapping - 1)) atom_2.SetAtomicNum(i + 1) self.assertEqual(oechem.OECreateCanSmiString(mol_1), oechem.OECreateCanSmiString(mol_2))
def to_mapped_xyz(molecule, atom_map, conformer=None, xyz_format=False, filename=None): """ Generate xyz coordinates for molecule in the order given by the atom_map. atom_map is a dictionary that maps the tag on the SMILES to the atom idex in OEMol. Parameters ---------- molecule: OEMol with conformers atom_map: dict maps tag in SMILES to atom index conformer: int Which conformer to write xyz file for. If None, write out all conformers. Default is None xyz_format: bool If True, will write out number of atoms and molecule name. If false, will only write out elements and coordinates filename: str Name of file to save to. If None, only returns a string. Returns ------- str: elements and xyz coordinates in order of tagged SMILES """ xyz = "" for k, mol in enumerate(molecule.GetConfs()): if k == conformer or conformer is None: if xyz_format: xyz += "{}\n".format(mol.GetMaxAtomIdx()) xyz += "{}\n".format(mol.GetTitle()) coords = oechem.OEFloatArray(mol.GetMaxAtomIdx() * 3) mol.GetCoords(coords) if k != 0 and not xyz_format: xyz += "*" for mapping in range(1, len(atom_map) + 1): idx = atom_map[mapping] atom = mol.GetAtom(oechem.OEHasAtomIdx(idx)) syb = oechem.OEGetAtomicSymbol(atom.GetAtomicNum()) xyz += " {} {:05.3f} {:05.3f} {:05.3f}\n".format( syb, coords[idx * 3], coords[idx * 3 + 1], coords[idx * 3 + 2]) if filename: file = open("{}.xyz".format(filename, 'w')) file.write(xyz) file.close() return xyz