def test_is_valid_and_test_empty(self): pat = ob.OBSmartsPattern() self.assertFalse(pat.IsValid()) self.assertTrue(pat.Empty()) pat.Init("CO") self.assertTrue(pat.IsValid()) self.assertFalse(pat.Empty()) pat = ob.OBSmartsPattern() with SuppressLogging(): # This will send message to the error log. self.assertFalse(pat.Init("=O")) self.assertFalse(pat.IsValid()) self.assertTrue(pat.Empty())
def test_bad_smarts(self): pat = ob.OBSmartsPattern() # This writes an error to the log with SuppressLogging(): self.assertFalse(pat.Init("%")) self.assertEqual(pat.NumAtoms(), 0) self.assertFalse(pat.IsValid())
def matchsmarts(smarts, outf, catoms): sm = openbabel.OBSmartsPattern() sm.Init(smarts) f = open(outf, 'r') s = f.read().splitlines() f.close() moll = openbabel.OBMol() obConversion = openbabel.OBConversion() obConversion.SetInAndOutFormats("smi", "smi") f = open(outf, 'w') for i, mol in enumerate(s): obConversion.ReadString(moll, mol) sm.Match(moll) # sm.Match(mol) smm = list(sm.GetUMapList()) if len(smm) > 0: pmatch = smm[0] cc = '' for at in catoms: att = at - 1 # indexing cc += str(pmatch[att]) + ',' #if i < nres: f.write(mol + ' ' + cc[:-1] + '\n') #f.write(s[i]+'\n') else: pass f.close() return 0
def __init__(self, mol, **kwargs): """ Readies a fragmentation object for an OpenBabel molecule Arguments: mol -- molecule Keyword Arguments: defaults -- FragItConfig object defaults """ conffile = kwargs.get('conffile', None) defaults = kwargs.pop('defaults', FragItDataBase) FragItConfig.__init__(self, defaults=defaults, filename=conffile, **kwargs) self.mol = mol self.obc = openbabel.OBConversion() self.pat = openbabel.OBSmartsPattern() self._atom_names = [] self._residue_names = [] self._fragment_names = [] self._fragment_charges = [] self._fragments = [] self._backbone_atoms = [] self._mergeable_atoms = [] self._atoms = [] self._fixAtomsAndCharges() self._nbonds_broken = 0
def process_types(poltype, mol): """ Intent: Set up scalelist array for scaling certain multipole values For alchol, the quadrupole on O and H should be mannually scaled by 0.6. This only applies to OH that connect to sp3 Carbon. Similarly for NH in amine (that connects to a sp3 C), scale the Q by 0.75 or 75%. See JCC 2011 32(5):967-77. """ scalelist = {} multipole_scale_dict = {} for atm in openbabel.OBMolAtomIter(mol): if symm.get_class_number(poltype, atm.GetIdx()) not in scalelist: scalelist[symm.get_class_number(poltype, atm.GetIdx())] = [] scalelist[symm.get_class_number(poltype, atm.GetIdx())].append(None) scalelist[symm.get_class_number(poltype, atm.GetIdx())].append(None) scalelist[symm.get_class_number(poltype, atm.GetIdx())].append(None) multipole_scale_dict = {} #multipole_scale_dict['[OH][CX4]'] = [2, 0.6] #multipole_scale_dict['[NH2][CX4]'] = [2, 0.75] for (sckey, scval) in multipole_scale_dict.items(): sp = openbabel.OBSmartsPattern() openbabel.OBSmartsPattern.Init(sp, sckey) match = sp.Match(mol) for ia in sp.GetUMapList(): scalelist[symm.get_class_number(poltype, ia[0])][scval[0]] = scval[1] return scalelist
def test_replace_with_bad_smarts(self): pat = ob.OBSmartsPattern() self.assertTrue(pat.Init("CCCC")) self.assertEqual(pat.NumAtoms(), 4) # Re-init and verify that there's an overwrite # This writes an error to the log with SuppressLogging(): self.assertFalse(pat.Init("Q")) self.assertEqual(pat.NumAtoms(), 0) self.assertFalse(pat.IsValid())
def test_4_membered_ring(self): pat = ob.OBSmartsPattern() self.assertTrue(pat.Init("*1~*~*~*~1"), "failed to Init") mol = parse_smiles("C1CCCC1") m = pat.Match(mol) self.assertFalse(m, "had a match?") mol = parse_smiles("C1CCC1") m = pat.Match(mol) self.assertTrue(m, "no match?")
def __init__(self, mol): FragItConfig.__init__(self) self.mol = mol self.obc = openbabel.OBConversion() self.pat = openbabel.OBSmartsPattern() self._residue_names = [] self._fragment_names = [] self._fragment_charges = [] self._fragments = [] self._backbone_atoms = [] self._atoms = [mol.GetAtom(i) for i in range(1, mol.NumAtoms() + 1)] self._mergeable_atoms = []
def __init__(self, name, smarts): self.name = name self.smarts = smarts self.obsmarts = None # smarts not provided means this is a fake root define if smarts is not None: self.obsmarts = ob.OBSmartsPattern() if not self.obsmarts.Init(smarts): raise Exception('Invalid SMARTS: %s' % smarts) self.children: [TypeDefine] = [] self.parent: TypeDefine = None
def test_num_atoms_and_bonds(self): pat = ob.OBSmartsPattern() self.assertEqual(pat.NumAtoms(), 0) self.assertEqual(pat.NumBonds(), 0) pat.Init("C") self.assertEqual(pat.NumAtoms(), 1) self.assertEqual(pat.NumBonds(), 0) pat.Init("C#N") self.assertEqual(pat.NumAtoms(), 2) self.assertEqual(pat.NumBonds(), 1) pat.Init("c1ccccc1") self.assertEqual(pat.NumAtoms(), 6) self.assertEqual(pat.NumBonds(), 6)
def parse_sma(self, sma): """parse smarts and return OBSmartsPattern after storing in global dict or return from global dict""" if self.pat.has_key(sma): return self.pat[sma] if len(self.pat) < self.maxsma: pat = openbabel.OBSmartsPattern() #notice('new pat for %s' % sma) else: key, pat = self.pat.popitem() #notice('pattern reuse %s for %s' % (key,sma)) if pat.Init(sma): self.pat[sma] = pat return pat else: #notice('pattern None') return None
def matchsmarts(smarts, outf, catoms): sm = openbabel.OBSmartsPattern() print('---Test for developer version----') sm.Init(smarts) print('smart is:', smarts) current_path = os.getcwd() print('current path:', current_path) print('file open:', outf) f = open(outf, 'r') s = f.read().splitlines() f.close() # moll = openbabel.OBMol() # obConversion = openbabel.OBConversion() # obConversion.SetInAndOutFormats("smi", "smi") f = open(outf, 'w') # print('in file is:', s) moll = openbabel.OBMol() # add obConversion = openbabel.OBConversion() # add obConversion.SetInAndOutFormats("smi", "smi") # add for i, mol in enumerate(s): obConversion.ReadString(moll, mol) sm.Match(moll) # sm.Match(mol) # print('mol current:', mol) smm = list(sm.GetUMapList()) print('#:', i) print('mol current:', mol) print('smm current', smm) print('catoms:', catoms) if len(smm) > 0: pmatch = smm[0] cc = '' for at in catoms: att = at - 1 # indexing cc += str(pmatch[att]) + ',' # if i < nres: f.write(mol + ' ' + cc[:-1] + '\n') # f.write(s[i]+'\n') else: pass f.close() return 0
def is_in_polargroup(poltype, mol, smarts, bond, f): """ Intent: Check if a given bond is in the group defined by the smarts string Input: mol: OBMol object smarts: Smarts String defining the group (e.g. O-[*]) bond: bond in question f: output file (not used) Output: True if the bond is in the group, False if not Referenced By: gen_peditinfile Description: - """ sp = openbabel.OBSmartsPattern() openbabel.OBSmartsPattern.Init(sp, smarts) sp.Match(mol) for i in sp.GetUMapList(): if ((bond.GetBeginAtomIdx() in i) and \ (bond.GetEndAtomIdx() in i)): return True return False
def MatchPlattsBGroups(self, smiles): # Load functional group database current_dir = os.getcwd() filepath = os.path.join(current_dir, 'groups.xls') wb = xlrd.open_workbook(filepath) wb.sheet_names() data = wb.sheet_by_name(u'PlattsB') col1 = data.col_values(0) col2 = data.col_values(1) col3 = data.col_values(2) databaseB = [] for (SMART, name, B) in zip(col1, col2, col3): databaseB.append(functionalgroup(SMART, name, B)) platts_B = 0 mol = pybel.readstring("smi", smiles) for x in databaseB: # Initialize with dummy SMLES to check for validity of real one smarts = pybel.Smarts("CC") smarts.obsmarts = ob.OBSmartsPattern() success = smarts.obsmarts.Init(x.smarts.__str__()) if success: smarts = pybel.Smarts(x.smarts.__str__()) else: print "Invalid SMARTS pattern", x.smarts.__str__() break matched = smarts.findall(mol) x.num = len(matched) if (x.num > 0): print "Found group", x.smarts.__str__( ), 'named', x.name, 'with contribution', x.value, 'to B', x.num, 'times' platts_B += (x.num) * (x.value) self.B = platts_B + 0.071
def get_atom_types(molecule, config): """ Creates a dictionary containing all the identified atom types for all atoms in this molecule. Only feasible really for small molecules and not for protein structures. """ # PREPARE DICTIONARY DATA STRUCTURE FOR MOLECULE ATOM TYPES atom_types = dict((atom.idx, {}) for atom in molecule.atoms) # ITERATE THROUGH ALL SMARTS PATTERNS OF ALL CREDO ATOM TYPES for atom_type in config['atom types']: for smarts in config['atom types'][atom_type].values(): # MATCH THAT IS GOING TO BE SET FOR MATCHING ATOMS pattern = ob.OBSmartsPattern() pattern.Init(str(smarts)) pattern.Match(molecule.OBMol) for match in pattern.GetUMapList(): for idx in match: atom_types[idx][atom_type] = 1 return atom_types
def process_arpeggio(mol2_filename): slig = SmallMol(mol2_filename) slig.write('tmp.pdb') pdb_filename = 'tmp.pdb' # LOAD STRUCTURE (BIOPYTHON) pdb_parser = PDBParser() s = pdb_parser.get_structure('structure', pdb_filename) s_atoms = list(s.get_atoms()) logging.info('Loaded PDB structure (BioPython)') # CHECK FOR HYDROGENS IN THE INPUT STRUCTURE input_has_hydrogens = False hydrogens = [x for x in s_atoms if x.element == 'H'] if hydrogens: logging.info( 'Detected that the input structure contains hydrogens. Hydrogen addition will be skipped.' ) input_has_hydrogens = True # LOAD STRUCTURE (OPENBABEL) ob_conv = ob.OBConversion() ob_conv.SetInFormat('pdb') mol = ob.OBMol() ob_conv.ReadFile(mol, pdb_filename) # CHECK THAT EACH ATOM HAS A UNIQUE SERIAL NUMBER all_serials = [x.serial_number for x in s_atoms] if len(all_serials) > len(set(all_serials)): raise AtomSerialError # MAPPING OB ATOMS TO BIOPYTHON ATOMS AND VICE VERSA # FIRST MAP PDB SERIAL NUMBERS TO BIOPYTHON ATOMS FOR SPEED LATER # THIS AVOIDS LOOPING THROUGH `s_atoms` MANY TIMES serial_to_bio = {x.serial_number: x for x in s_atoms} # DICTIONARIES FOR CONVERSIONS ob_to_bio = {} bio_to_ob = {} for ob_atom in ob.OBMolAtomIter(mol): serial = ob_atom.GetResidue().GetSerialNum(ob_atom) # MATCH TO THE BIOPYTHON ATOM BY SERIAL NUMBER try: biopython_atom = serial_to_bio[serial] except KeyError: # ERRORWORTHY IF WE CAN'T MATCH AN OB ATOM TO A BIOPYTHON ONE raise OBBioMatchError(serial) # `Id` IS A UNIQUE AND STABLE ID IN OPENBABEL # CAN RECOVER THE ATOM WITH `mol.GetAtomById(id)` ob_to_bio[ob_atom.GetId()] = biopython_atom bio_to_ob[biopython_atom] = ob_atom.GetId() logging.info('Mapped OB to BioPython atoms and vice-versa.') # ADD EMPTY DATA STRUCTURES FOR TAGGED ATOM DATA # IN A SINGLE ITERATION for atom in s_atoms: # FOR ATOM TYPING VIA OPENBABEL atom.atom_types = set([]) # LIST FOR EACH ATOM TO STORE EXPLICIT HYDROGEN COORDINATES atom.h_coords = [] # DETECT METALS if atom.element.upper() in METALS: atom.is_metal = True else: atom.is_metal = False # DETECT HALOGENS if atom.element.upper() in HALOGENS: atom.is_halogen = True else: atom.is_halogen = False # ADD EXPLICIT HYDROGEN COORDS FOR H-BONDING INTERACTIONS # ADDING HYDROGENS DOESN'T SEEM TO INTERFERE WITH ATOM SERIALS (THEY GET ADDED AS 0) # SO WE CAN STILL GET BACK TO THE PERSISTENT BIOPYTHON ATOMS THIS WAY. if not input_has_hydrogens: mol.AddHydrogens(False, True, ph) # polaronly, correctForPH, pH logging.info('Added hydrogens.') # ATOM TYPING VIA OPENBABEL # ITERATE OVER ATOM TYPE SMARTS DEFINITIONS for atom_type, smartsdict in ATOM_TYPES.items(): #logging.info('Typing: {}'.format(atom_type)) # FOR EACH ATOM TYPE SMARTS STRING for smarts in smartsdict.values(): #logging.info('Smarts: {}'.format(smarts)) # GET OPENBABEL ATOM MATCHES TO THE SMARTS PATTERN ob_smart = ob.OBSmartsPattern() ob_smart.Init(str(smarts)) #logging.info('Initialised for: {}'.format(smarts)) ob_smart.Match(mol) #logging.info('Matched for: {}'.format(smarts)) matches = [x for x in ob_smart.GetMapList()] #logging.info('List comp matches: {}'.format(smarts)) if matches: # REDUCE TO A SINGLE LIST matches = set(reduce(operator.add, matches)) #logging.info('Set reduce matches: {}'.format(smarts)) for match in matches: atom = mol.GetAtom(match) ob_to_bio[atom.GetId()].atom_types.add(atom_type) #logging.info('Assigned types: {}'.format(smarts)) # ALL WATER MOLECULES ARE HYDROGEN BOND DONORS AND ACCEPTORS for atom in (x for x in s_atoms if x.get_full_id()[3][0] == 'W'): atom.atom_types.add('hbond acceptor') atom.atom_types.add('hbond donor') # OVERRIDE PROTEIN ATOM TYPING FROM DICTIONARY for residue in s.get_residues(): if residue.resname in STD_RES: for atom in residue.child_list: # REMOVE TYPES IF ALREADY ASSIGNED FROM SMARTS for atom_type in PROT_ATOM_TYPES.keys(): atom.atom_types.discard(atom_type) # ADD ATOM TYPES FROM DICTIONARY for atom_type, atom_ids in PROT_ATOM_TYPES.items(): atom_id = residue.resname.strip() + atom.name.strip() if atom_id in atom_ids: atom.atom_types.add(atom_type) def make_pymol_string(entity): ''' Feed me a BioPython atom or BioPython residue. See `http://pymol.sourceforge.net/newman/user/S0220commands.html`. chain-identifier/resi-identifier/name-identifier chain-identifier/resi-identifier/ ''' if isinstance(entity, Atom): chain = entity.get_parent().get_parent() residue = entity.get_parent() atom_name = entity.name elif isinstance(entity, Residue): chain = entity.get_parent() residue = entity atom_name = '' else: raise TypeError( 'Cannot make a PyMOL string from a non-Atom or Residue object.' ) res_num = residue.id[1] # ADD INSERTION CODE IF NEED BE if residue.id[2] != ' ': res_num = str(res_num) + residue.id[2] macro = '{}/{}/{}'.format(chain.id, res_num, atom_name) return macro ''' with open(pdb_filename.replace('.pdb', '.atomtypes'), 'w') as fo: if headers: fo.write('{}\n'.format('\t'.join( ['atom', 'atom_types'] ))) for atom in s_atoms: fo.write('{}\n'.format('\t'.join([str(x) for x in [make_pymol_string(atom), sorted(tuple(atom.atom_types))]]))) logging.info('Typed atoms.') ''' return s_atoms
class Molecule(object): # for more rendering options visit: # http://www.ggasoftware.com/opensource/indigo/api/options#rendering _obElements = openbabel.OBElementTable() _obSmarts = openbabel.OBSmartsPattern() @staticmethod def GetNumberOfElements(): return Molecule._obElements.GetNumberOfElements() @staticmethod def GetAllElements(): return [Molecule._obElements.GetSymbol(i) for i in xrange(Molecule.GetNumberOfElements())] @staticmethod def GetSymbol(atomic_num): return Molecule._obElements.GetSymbol(atomic_num) @staticmethod def GetAtomicNum(elem): if type(elem) == types.UnicodeType: elem = str(elem) return Molecule._obElements.GetAtomicNum(elem) @staticmethod def VerifySmarts(smarts): return Molecule._obSmarts.Init(smarts) def __init__(self): self.title = None self.obmol = openbabel.OBMol() self.smiles = None self.inchi = None def __str__(self): return self.title or self.smiles or self.inchi or "" def __len__(self): return self.GetNumAtoms() def Clone(self): tmp = Molecule() tmp.title = self.title tmp.obmol = openbabel.OBMol(self.obmol) tmp.smiles = self.smiles tmp.inchi = self.inchi return tmp def SetTitle(self, title): self.title = title @staticmethod def FromSmiles(smiles): m = Molecule() m.smiles = smiles obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetInFormat("smiles") if not obConversion.ReadString(m.obmol, m.smiles): raise OpenBabelError("Cannot read the SMILES string: " + smiles) try: m.UpdateInChI() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from SMILES: " + smiles) m.SetTitle(smiles) return m @staticmethod def FromInChI(inchi): m = Molecule() m.inchi = inchi obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetInFormat("inchi") obConversion.ReadString(m.obmol, m.inchi) try: m.UpdateSmiles() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from InChI: " + inchi) m.SetTitle(inchi) return m @staticmethod def FromMol(mol): m = Molecule() obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetInFormat("mol") obConversion.ReadString(m.obmol, mol) try: m.UpdateInChI() m.UpdateSmiles() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from MOL file:\n" + mol) m.SetTitle("") return m @staticmethod def FromOBMol(obmol): m = Molecule() m.obmol = obmol try: m.UpdateInChI() m.UpdateSmiles() except OpenBabelError: raise OpenBabelError("Failed to create Molecule from OBMol") m.SetTitle("") return m @staticmethod def _FromFormat(s, fmt='inchi'): if fmt == 'smiles' or fmt == 'smi': return Molecule.FromSmiles(s) if fmt == 'inchi': return Molecule.FromInChI(s) if fmt == 'mol': return Molecule.FromMol(s) if fmt == 'obmol': return Molecule.FromOBMol(s) @staticmethod def _ToFormat(obmol, fmt='inchi'): obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetOutFormat(fmt) res = obConversion.WriteString(obmol) if not res: raise OpenBabelError("Cannot convert OBMol to %s" % fmt) if fmt == 'smiles' or fmt == 'smi': res = res.split() if res == []: raise OpenBabelError("Cannot convert OBMol to %s" % fmt) else: return res[0] elif fmt == 'inchi': return res.strip() else: return res @staticmethod def Smiles2InChI(smiles): obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetInAndOutFormats("smiles", "inchi") obmol = openbabel.OBMol() if not obConversion.ReadString(obmol, smiles): raise OpenBabelError("Cannot read the SMILES string: " + smiles) return obConversion.WriteString(obmol).strip() @staticmethod def InChI2Smiles(inchi): obConversion = openbabel.OBConversion() obConversion.AddOption("w", obConversion.OUTOPTIONS) obConversion.SetInAndOutFormats("inchi", "smiles") obmol = openbabel.OBMol() if not obConversion.ReadString(obmol, inchi): raise OpenBabelError("Cannot read the InChI string: " + inchi) return obConversion.WriteString(obmol).split()[0] def RemoveHydrogens(self): self.obmol.DeleteHydrogens() def RemoveAtoms(self, indices): self.obmol.BeginModify() for i in sorted(indices, reverse=True): self.obmol.DeleteAtom(self.obmol.GetAtom(i+1)) self.obmol.EndModify() self.smiles = None self.inchi = None def SetAtomicNum(self, index, new_atomic_num): self.obmol.GetAtom(index+1).SetAtomicNum(new_atomic_num) self.smiles = None self.inchi = None def ToOBMol(self): return self.obmol def ToFormat(self, fmt='inchi'): return Molecule._ToFormat(self.obmol, fmt=fmt) def ToMolfile(self): return self.ToFormat('mol') def UpdateInChI(self): self.inchi = Molecule._ToFormat(self.obmol, 'inchi') def ToInChI(self): """ Lazy storage of the InChI identifier (calculate once only when asked for and store for later use). """ if not self.inchi: self.UpdateInChI() return self.inchi def UpdateSmiles(self): self.smiles = Molecule._ToFormat(self.obmol, 'smiles') def ToSmiles(self): """ Lazy storage of the SMILES identifier (calculate once only when asked for and store for later use). """ if not self.smiles: self.UpdateSmiles() return self.smiles def GetFormula(self): tokens = re.findall('InChI=1S?/([0-9A-Za-z\.]+)', self.ToInChI()) if len(tokens) == 1: return tokens[0] elif len(tokens) > 1: raise ValueError('Bad InChI: ' + self.ToInChI()) else: return '' def GetExactMass(self): return self.obmol.GetExactMass() def GetAtomBagAndCharge(self): inchi = self.ToInChI() fixed_charge = 0 for s in re.findall('/q([0-9\+\-]+)', inchi): fixed_charge += int(s) fixed_protons = 0 for s in re.findall('/p([0-9\+\-]+)', inchi): fixed_protons += int(s) formula = self.GetFormula() atom_bag = {} for mol_formula_times in formula.split('.'): for times, mol_formula in re.findall('^(\d+)?(\w+)', mol_formula_times): if not times: times = 1 else: times = int(times) for atom, count in re.findall("([A-Z][a-z]*)([0-9]*)", mol_formula): if count == '': count = 1 else: count = int(count) atom_bag[atom] = atom_bag.get(atom, 0) + count * times if fixed_protons: atom_bag['H'] = atom_bag.get('H', 0) + fixed_protons fixed_charge += fixed_protons return atom_bag, fixed_charge def GetHydrogensAndCharge(self): atom_bag, charge = self.GetAtomBagAndCharge() return atom_bag.get('H', 0), charge def GetNumElectrons(self): """Calculates the number of electrons in a given molecule.""" atom_bag, fixed_charge = self.GetAtomBagAndCharge() n_protons = 0 for elem, count in atom_bag.iteritems(): n_protons += count * self._obElements.GetAtomicNum(elem) return n_protons - fixed_charge def GetNumAtoms(self): return self.obmol.NumAtoms() def GetAtoms(self): return [self.obmol.GetAtom(i+1) for i in xrange(self.obmol.NumAtoms())] def FindSmarts(self, smarts): """ Corrects the pyBel version of Smarts.findall() which returns results as tuples, with 1-based indices even though Molecule.atoms is 0-based. Args: mol: the molecule to search in. smarts_str: the SMARTS query to search for. Returns: The re-mapped list of SMARTS matches. """ Molecule._obSmarts.Init(smarts) if Molecule._obSmarts.Match(self.obmol): match_list = Molecule._obSmarts.GetMapList() shift_left = lambda m: [(n - 1) for n in m] return map(shift_left, match_list) else: return [] def GetAtomCharges(self): """ Returns: A list of charges, according to the number of atoms in the molecule """ return [atom.GetFormalCharge() for atom in self.GetAtoms()]
def prepare(self, to_format = 'mol2', addH = False, calc_charge = False, correct_for_pH = False, pH = 7.4): """ Read a molecule structure with Openbabel and get basic information from it. If requested modifiy the data and convert the file. :param to_format: format to convert to if not empty :type to_format: string :param addH: add hydrogens? (experimental) :type addH: bool :param calc_charge: force total formal charge calculation if True, leave it to Openbabel if False :type calc_charge: bool :param correct_for_pH: correct for pH, i.e. determine protonation state? (very experimental!) :type correct_for_pH: bool :param pH: pH to be considered when correct_for_pH is True (very experimental!) :type pH: float :raises: SetupError """ conv = ob.OBConversion() mol = ob.OBMol() ob_read_one(conv, self.mol_file, mol, self.mol_fmt, to_format) # FIXME: does this test for the right thing? if mol.GetDimension() != 3: raise errors.SetupError('input cooridnates (%s) must have 3 dimensions' % self.mol_file) orig_atoms = [] etab = ob.OBElementTable() acnt = 0 for atom in ob.OBMolAtomIter(mol): acnt += 1 res = atom.GetResidue() # when is this NULL? element = etab.GetSymbol(atom.GetAtomicNum() ) orig_atoms.append( (res.GetAtomID(atom).strip(), element) ) if to_format: res.SetAtomID(atom, '%s%d' % (element, acnt) ) if addH: logger.write('Adding hydrogens') mol.DeleteHydrogens() if correct_for_pH: # reimplementation from phmodel.cpp mol.SetAutomaticFormalCharge(correct_for_pH) transform = ob.OBChemTsfm() logger.write('Applying transforms') for reactant, product, pKa in const.TRANSFORM_SMARTS: success = transform.Init(reactant, product) if not success: raise ValueError('BUG in SMARTS transform Init %s >> %s', (reactant, product) ) if (transform.IsAcid() and pH > pKa) or \ (transform.IsBase() and pH < pKa): success = transform.Apply(mol) mol.AddHydrogens(False, False, 0.0) # valence filling if mol.GetTotalSpinMultiplicity() != 1: raise errors.SetupError('only multiplicity=1 supported (%s)' % self.mol_file) if to_format: logger.write('Converting/Writing %s (%s format) to %s format' % (self.mol_file, self.mol_fmt, to_format) ) # NOTE: this relies on a modified Openbabel MOL2 writer conv.AddOption('r', ob.OBConversion.OUTOPTIONS) # do not append resnum self.mol_file = const.CONV_MOL2_FILE % to_format self.mol_fmt = to_format try: conv.WriteFile(mol, self.mol_file) except IOError as why: raise errors.SetupError(why) else: logger.write('Leaving %s unmodified.' % self.mol_file) # some formats allow formal charge definition: # PDB (col 79-80), SDF(M CHG, atom block), MOL2 (UNITY_ATOM_ATTR?) if calc_charge: logger.write('Computing total formal charge\n') # set formal charge for some functional groups by hand because # OpenBabel doesn't support it in C++ for formats like mol2 formal_charge = 0 sm = ob.OBSmartsPattern() for smarts, fchg in const.CHARGE_SMARTS: sm.Init(smarts) if sm.Match(mol): m = list(sm.GetUMapList() ) formal_charge += fchg * len(m) mol.SetTotalCharge(formal_charge) self.charge = formal_charge else: logger.write('Total formal charge taken from coordinate file\n') self.charge = mol.GetTotalCharge() # trust Openbabel... self.atomtype = 'sybyl' # Openbabel will try to convert to Sybyl format conv.SetOutFormat('smi') conv.AddOption('n') conv.AddOption('c') smiles = conv.WriteString(mol).rstrip() conv.SetOutFormat('inchikey') errlev = ob.obErrorLog.GetOutputLevel() ob.obErrorLog.SetOutputLevel(0) inchi_key = conv.WriteString(mol).rstrip() ob.obErrorLog.SetOutputLevel(errlev) logger.write('''Ligand key data: Formula: %s SMILES: %s InChIKey: %s Net charge: %i Molecular weight: %f\n''' % (mol.GetFormula(), smiles, inchi_key, self.charge, mol.GetMolWt() ) )
def partition_protein(self, mol, special_reslists=None, fragsize=None): """ Partition a protein into the individual amino acids and caps. @param mol: the protein @type mol: L{molecule} @param special_reslists: lists of residue numbers that should be treated within one 3-FDE fragment @type special_reslists: list of lists of integers @param fragsize: number of residues in one 3-FDE fragment (not for residues in special_reslist) @type fragsize: int """ import openbabel # generate fragment list res_of_atoms = mol.get_residue_numbers_of_atoms() capped_bonds = [] # list of bonds between residues within fragment non_capped_res = [] # to which fragment belongs the residue frag_indices = [] # clear the fragment list self._frags = [] self._caps = [] if fragsize == None: fragsize = 1 if special_reslists == None: special_reslists = {} #---------------------------------------------------------------------------------- # simplest fragmentation: each residue is one fragment if special_reslists == {} and fragsize == 1: # get the individual residues for res in mol.get_residues(): self.append(cappedfragment(None, res)) frag_indices.append(len(self._frags) - 1) #---------------------------------------------------------------------------------- # more complicated fragmentation else: # careful with residue numbers (internal openbabel index idx starts at 0) fragmentation_list = [] residuelist = mol.get_residues() frag_indices = [-1 for i in range(len(residuelist))] # get list of residues connected by covalent bonds (tuples) connected_residues = [] for b in mol.get_all_bonds(): if not (res_of_atoms[b[0] - 1] == res_of_atoms[b[1] - 1]): # -1 is not totally clear to me, but works connected_residues.append( set([res_of_atoms[b[0] - 1], res_of_atoms[b[1] - 1]])) #------------------------------------------------------------------------------ # first get fragmentation list: which residues belong to which fragment # something like [ [3,4,5], [11,12,14], [1, 2], [6, 7], [8, 9], [10], [13]] # ugly # dictionary that connects pdb resnums with internal idx # problem: resnum as key is not unique, use combination of residue name and chain as key res_idx = {} for res in residuelist: resnum = res.mol.GetResidue(0).GetNum() reschain = res.mol.GetResidue(0).GetChain() reskey = 'c' + str(reschain) + str(resnum) intresnum = res.mol.GetResidue(0).GetIdx() res_idx[reskey] = intresnum # convert residue numbers in special_reslists to internal numbers for i in range(len(special_reslists)): for j in range(len(special_reslists[i])): special_reslists[i][j] = res_idx[special_reslists[i][j]] # flatten list of lists so that you can check whether a residue is a special residue specialresnums = [] for slist in special_reslists: if isinstance(slist, (list, tuple)): specialresnums.extend(slist) # else should not occur, but maybe it is needed later else: specialresnums.append(slist) # first add special residues to fragmentation list for slist in special_reslists: fragmentation_list.append(slist) fragl = [] # templist for fragments # add all other residues # use res.GetIdx() instead of enumerate for res in residuelist: resnum = res.mol.GetResidue(0).GetIdx() if resnum not in specialresnums: # take care of fragsize if fragsize == 1: fragmentation_list.append([resnum]) else: # check whether there has to be a new fragment if len(fragl) != 0: if not set([resnum, fragl[-1]]) in connected_residues or \ len(fragl) == fragsize: # no covalent connection? new fragment! fragsize reached? fragmentation_list.append(fragl) fragl = [] # new fragment if len(fragl) == 0: fragl.append(resnum) # add to fragment else: fragl.append(resnum) # last fragment if len(fragl) != 0: fragmentation_list.append(fragl) #------------------------------------------------------------------------------ # now add fragments to _frags using fragmentation list # take care of uncapped bonds and fragindices etc. frag_reslist = [] for rlist in fragmentation_list: for rnum in range(len(rlist)): res = mol.get_residues(idx=rlist[rnum])[0] frag_reslist.append(res) # if residue is added to an existing fragment: add tuple of residues to # list of connected (non-capped) residues (only if they are connected) # take also care of disulfide bonds within one fragment # check whether new residue is connected to another residue within this fragment if len(frag_reslist) > 1: for rd in range(len(frag_reslist)): if set([rlist[rnum], rlist[rd]]) in connected_residues: non_capped_res.append( set([rlist[rnum], rlist[rd]])) # take care of residue information here frag_indices[rlist[rnum]] = len(self._frags) res_frag = fragment(None, mols=frag_reslist) self.append(cappedfragment(None, res_frag.get_total_molecule())) # clear frag_reslist for next fragment frag_reslist = [] #------------------------------------------------------------------------------ # find all peptide bonds and create caps sp = openbabel.OBSmartsPattern() sp.Init('[C;X4;H1,H2][CX3](=O)[NX3][C;X4;H1,H2][CX3](=O)') # this SMARTS pattern matches all peptide bonds # # (in this comment: atom numbering starts at 1; # in the code below the numbering of the list starts at 0) # the peptide bond is between atoms 2 and 4 # atoms 1-5 (+ connected hydrogens) form the cap fragment # part 1 (o-part): atoms 1-3 # part 2 (n-part): atoms 4-5 sp.Match(mol.mol) maplist = sp.GetUMapList() for mp in maplist: mp = list(mp) if set([res_of_atoms[mp[3] - 1], res_of_atoms[mp[1] - 1]]) not in non_capped_res: capped_bonds.append(set([mp[1], mp[3]])) cap_o = mp[0:3] + mol.find_adjacent_hydrogens(mp[0:3]) cap_n = mp[3:5] + mol.find_adjacent_hydrogens(mp[3:5]) m_cap = mol.get_fragment(cap_o + cap_n) m_cap.set_spin(0) m_cap.set_residue('CAP', 1, atoms=range(1, len(cap_o) + 1)) m_cap.set_residue('CAP', 2, atoms=range( len(cap_o) + 1, len(cap_o + cap_n) + 1)) m_cap.add_hydrogens() # find the capped fragments # frag1: fragment that contains the N atom (mp[3]) # frag2: fragment that contains the C=O atom (mp[1]) # why minus 1??? fi1 = frag_indices[res_of_atoms[mp[3] - 1]] fi2 = frag_indices[res_of_atoms[mp[1] - 1]] frag1 = self._frags[fi1] frag2 = self._frags[fi2] self.append_cap(cappedfragment(None, capmolecule(m_cap)), frag1, frag2) #------------------------------------------------------------------------------ # check here for disulfide bonds and create disulfide bond caps sp_sulfide = openbabel.OBSmartsPattern() sp_sulfide.Init('[C;X4;H1,H2]SS[C;X4;H1,H2]') # SMARTS pattern for disulfde bonds sp_sulfide.Match(mol.mol) maplist_sulfide = sp_sulfide.GetUMapList() for mps in maplist_sulfide: mps = list(mps) if set([res_of_atoms[mps[2] - 1], res_of_atoms[mps[1] - 1]]) not in non_capped_res: capped_bonds.append(set([mps[1], mps[2]])) cap_s1 = mps[0:2] + mol.find_adjacent_hydrogens(mps[0:2]) cap_s2 = mps[2:] + mol.find_adjacent_hydrogens(mps[2:]) m_cap_s = mol.get_fragment(cap_s1 + cap_s2) m_cap_s.set_spin(0) m_cap_s.set_residue('SCP', 1, atoms=range(1, len(cap_s1) + 1)) m_cap_s.set_residue('SCP', 2, atoms=range( len(cap_s1) + 1, len(cap_s1 + cap_s2) + 1)) m_cap_s.add_hydrogens() fi1 = frag_indices[res_of_atoms[mps[2] - 1]] fi2 = frag_indices[res_of_atoms[mps[1] - 1]] frag_s1 = self._frags[fi1] frag_s2 = self._frags[fi2] self.append_scap(cappedfragment(None, capmolecule(m_cap_s)), frag_s1, frag_s2) #------------------------------------------------------------------------------ # find bonds between different residues and check if they have been capped num_uncapped_bonds = 0 for b in mol.get_all_bonds(): if not (res_of_atoms[b[0] - 1] == res_of_atoms[b[1] - 1]): if not set([b[0], b[1]]) in capped_bonds \ and not set([res_of_atoms[b[0] - 1], res_of_atoms[b[1] - 1]]) in non_capped_res \ and not set([res_of_atoms[b[0] - 1], res_of_atoms[b[1] - 1]]).issubset(special_reslists): num_uncapped_bonds += 1 print "Bond between atoms ", b[0], " and ", b[ 1], "not capped." print "Bond between res ", res_of_atoms[ b[0] - 1], " and ", res_of_atoms[b[1] - 1], "not capped." if num_uncapped_bonds > 0: print num_uncapped_bonds, " bonds not capped. " raise PyAdfError('Not all bonds capped in partition_protein')
def parse_smarts(smarts): "Parse a SMARTS into an ObSmartsPattern" pat = ob.OBSmartsPattern() assert pat.Init(smarts) return pat
def make_structure(request): def makeResidue(mol, idx, aaatoms): res = mol.NewResidue() res.SetNum(idx) for atom in ob.OBMolAtomIter(mol): if atom.GetIdx() not in aaatoms: res.AddAtom(atom) aminoacids = request.GET.getlist("as") color = request.GET.get("rescol", "#3EC1CD") mol = ob.OBMol() conv = ob.OBConversion() pattern = ob.OBSmartsPattern() pattern.Init("[NX3][$([CX4H1]([*])),$([CX4H2])][CX3](=[OX1])[OX2]") builder = ob.OBBuilder() conv.SetInAndOutFormats("sdf", "svg") conv.AddOption("d", ob.OBConversion.OUTOPTIONS) conv.AddOption("b", ob.OBConversion.OUTOPTIONS, "none") conv.ReadString(mol, str(Substrate.objects.get(pk=int(aminoacids[0])).structure)) pattern.Match(mol) mollist = pattern.GetUMapList()[0] oatom = mol.GetAtom(mollist[4]) catom = mol.GetAtom(mollist[2]) firstnatom = mol.GetAtom(mollist[0]) makeResidue(mol, 0, mollist) i = 1 for aa in aminoacids[1:]: mol2 = ob.OBMol() conv.ReadString(mol2, str(Substrate.objects.get(pk=int(aa)).structure)) pattern.Match(mol2) mollist = pattern.GetUMapList()[0] makeResidue(mol2, i, mollist) molnatoms = mol.NumAtoms() mol += mol2 natom = mol.GetAtom(molnatoms + mol2.GetAtom(mollist[0]).GetIdx()) builder.Connect(mol, catom.GetIdx(), natom.GetIdx()) foatom = mol.GetAtom(molnatoms + mol2.GetAtom(mollist[4]).GetIdx()) catom = mol.GetAtom(molnatoms + mol2.GetAtom(mollist[2]).GetIdx()) mol.DeleteHydrogens(oatom) mol.DeleteAtom(oatom) natom.SetImplicitValence(3) mol.DeleteHydrogens(natom) mol.AddHydrogens(natom) oatom = foatom i += 1 nidx = firstnatom.GetIdx() oidx = oatom.GetIdx() builder.Build(mol) natom = mol.GetAtom(nidx) oatom = mol.GetAtom(oidx) for res in ob.OBResidueIter(mol): for atom in ob.OBResidueAtomIter(res): for bond in ob.OBAtomBondIter(atom): data = ob.OBPairData() data.SetAttribute("color") data.SetValue(color) bond.CloneData(data) mol.DeleteHydrogens() gen2d = ob.OBOp.FindType("gen2d") gen2d.Do(mol) opp = oatom.GetY() - natom.GetY() adj = oatom.GetX() - natom.GetX() angle = abs(math.atan(opp / adj)) if opp > 0 and adj > 0: pass elif opp > 0 and adj < 0: angle = math.pi - angle elif opp < 0 and adj < 0: angle = math.pi + angle elif opp < 0 and adj > 0: angle = 2 * math.pi - angle angle = -angle mol.Rotate(ob.double_array([math.cos(angle), -math.sin(angle), 0, math.sin(angle), math.cos(angle), 0, 0, 0, 1])) svg = conv.WriteString(mol) # need to get rid of square aspect ratio delstart = svg.find("width") delend = svg.find("svg", delstart) delend = svg.find("viewBox", delend) svgend = svg.rfind("</g>") svg = svg[0:delstart] + svg[delend:svgend] return HttpResponse(svg, mimetype="image/svg+xml")
def __init__(self,smartspattern): """Initialise with a SMARTS pattern.""" self.obsmarts = ob.OBSmartsPattern() success = self.obsmarts.Init(smartspattern) if not success: raise IOError("Invalid SMARTS pattern")
def _setupSmartsPattern(self): self._pattern = openbabel.OBSmartsPattern()
def gen_peditinfile(poltype, mol): """ Intent: Create a file with local frame definitions for each multipole These frame definitions are given as input into tinker's poledit Input: mol: OBMol object Output: *-peditin.txt is created Referenced By: main Description: 1. Initialize lfzerox, or local-frame-zero-x-component, array 2. For each atom a a. find the two heaviest atoms that a is bound to (heaviest defined by their symmetry class; the more atoms an atom is bound to, the higher its symmetry class) These two atoms define the local frame for atom a b. This information is stored in the localframe1 and localframe2 arrays 3. If atom a is bound to two atoms of the same symm class (that aren't Hydrogens), use these two atoms to define the frame 4. Find the atoms that are only bound to one atom and define their local frame based on the local frame of the one atom they are bound to. 5. Zero out the x-component of the local frame if there is more than one choice for the x-component Note: If the atom is only bound to one atom, then the array lfzerox is altered If the atom is bound to more than one atom, then the array lf2write is altered Related to how poledit handles the local frames of atoms with valence 1 6. Define bisectors; i.e. local frames where both components belong to the same sym class 7. Write out frames to *-peditin.txt 8. Write out polarizabilities for certain atom types 9. Define polarizability groups by 'cutting' certain bonds The openbabel method, IsRotor() is used to decide whether a bond is cut or not """ lfzerox = [False] * mol.NumAtoms() atomindextoremovedipquad = { } # for methane need to make dipole and quadupole on the carbon zeroed out, will return this for post proccesing the keyfile after poledit is run atomindextoremovedipquadcross = {} atomtypetospecialtrace = { } # for H on CH4 need to make sure Qxx=Qyy=-1/2*Qzz idxtobisecthenzbool = {} idxtobisectidxs = {} idxtotrisecbool = {} idxtotrisectidxs = {} # Assign local frame for atom a based on the symmetry classes of the atoms it is bound to for a in openbabel.OBMolAtomIter(mol): # iterate over the atoms that a is bound to for b in openbabel.OBAtomAtomIter(a): lf1 = poltype.localframe1[a.GetIdx() - 1] # defined to be zero at first? lf2 = poltype.localframe2[a.GetIdx() - 1] # defined to be zero at first? # Sort list based on symmetry class, largest first a1 = sorted( (lf1, lf2, b.GetIdx()), key=lambda x: symm.get_symm_class(poltype, x), reverse=True) # the lf1 and lf2 return -1 via get_symm_class while a1[ 0] == 0: # redundant if you got the order (reverse or not ) in previous line a1 = rotate_list(a1) # Set localframe1 and localframe2 for atom a to be the first two atoms # of the above sorted list 'a1' poltype.localframe1[a.GetIdx() - 1] = a1[ 0] # highest neighboring symmetry class gets stored as local frame 1 poltype.localframe2[a.GetIdx() - 1] = a1[1] # next highest is 2 # if a is bound to two atoms of the same symmetry class that aren't hydrogens # use these two atoms to define the local frame for a in openbabel.OBMolAtomIter( mol): # it seems that this case is not handled by above case classlist = {} for b in openbabel.OBAtomAtomIter(a): if b.GetAtomicNum() != 1: clsidx = poltype.symmetryclass[b.GetIdx() - 1] if clsidx not in classlist: classlist[clsidx] = [] classlist[clsidx].append(b.GetIdx()) for clstype in classlist.values(): if len(clstype) > 1: poltype.localframe1[a.GetIdx() - 1] = clstype[0] poltype.localframe2[a.GetIdx() - 1] = clstype[1] # Find atoms bonded to only one atom iteratom = openbabel.OBMolAtomIter(mol) for a in iteratom: lfa1 = poltype.localframe1[a.GetIdx() - 1] lfa2 = poltype.localframe2[a.GetIdx() - 1] lfb1 = poltype.localframe1[lfa1 - 1] lfb2 = poltype.localframe2[lfa1 - 1] if a.GetValence() == 1: # Set lfa2 to the other atom (the atom that isn't 'a') in the local frame of atom 'b' if lfb1 != a.GetIdx() and symm.get_symm_class( poltype, lfb1) != symm.get_symm_class( poltype, lfa1): # make sure they are not the same type poltype.localframe2[a.GetIdx() - 1] = lfb1 elif lfb1 == a.GetIdx(): poltype.localframe2[a.GetIdx() - 1] = lfb2 atomiter = openbabel.OBMolAtomIter(mol) lf2write = list(poltype.localframe2) for a in atomiter: idxtobisecthenzbool[a.GetIdx()] = False idxtotrisecbool[a.GetIdx()] = False for atom in openbabel.OBMolAtomIter(mol): atomidx = atom.GetIdx() val = atom.GetValence() atomneighbs = [neighb for neighb in openbabel.OBAtomAtomIter(atom)] lf1 = poltype.localframe1[atomidx - 1] lf2 = poltype.localframe2[atomidx - 1] lf1atom = mol.GetAtom(lf1) lf2atom = mol.GetAtom(lf2) lf1val = lf1atom.GetValence() lf1neighbs = [neighb for neighb in openbabel.OBAtomAtomIter(lf1atom)] lf1neighbsnota = RemoveFromList(poltype, lf1neighbs, atom) neighbsnotlf1 = RemoveFromList(poltype, atomneighbs, lf1atom) lf1neighbsallsameclass = CheckIfAllAtomsSameClass(poltype, lf1neighbs) # write out the local frames iteratom = openbabel.OBMolAtomIter(mol) if not os.path.isfile(poltype.peditinfile): f = open(poltype.peditinfile, 'w') f.write("\n") f.write('A\n') #Find aromatic carbon, halogens, and bonded hydrogens to correct polarizability iteratom = openbabel.OBMolAtomIter(mol) writesection = False lines = [] for a in iteratom: if (a.GetAtomicNum() == 6 and a.IsAromatic()): lines.append(str(a.GetIdx()) + " " + str(1.750) + "\n") writesection = True elif (a.GetAtomicNum() == 9): lines.append(str(a.GetIdx()) + " " + str(0.507) + "\n") writesection = True elif (a.GetAtomicNum() == 17): lines.append(str(a.GetIdx()) + " " + str(2.500) + "\n") writesection = True elif (a.GetAtomicNum() == 35): lines.append(str(a.GetIdx()) + " " + str(3.595) + "\n") writesection = True elif (a.GetAtomicNum() == 1): iteratomatom = openbabel.OBAtomAtomIter(a) for b in iteratomatom: if (b.GetAtomicNum() == 6 and b.IsAromatic()): lines.append(str(a.GetIdx()) + " " + str(0.696) + "\n") writesection = True if writesection == True: for line in lines: f.write(line) # Carboxylate ion O- sp = openbabel.OBSmartsPattern() openbabel.OBSmartsPattern.Init(sp, '[OD1]~C~[OD1]') sp.Match(mol) for ia in sp.GetMapList(): f.write(str(ia[0]) + " " + str(0.921) + "\n") f.write("\n") f.flush() os.fsync(f.fileno()) #Define polarizable groups by cutting bonds iterbond = openbabel.OBMolBondIter(mol) for b in iterbond: if (b.IsRotor()): cut_bond = True # If in this group, then don't cut bond cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, 'a[CH2][*]', b, f)) cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, '[#6]O-[#1]', b, f)) #cut_bond = cut_bond and (not is_in_polargroup(mol,'[#6][#6]~O', b,f)) # Formamide RC=O cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, '[*][CH]=O', b, f)) # Amide cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, 'N(C=O)', b, f)) cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, 'C(C=O)', b, f)) cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, 'aN', b, f)) cut_bond = cut_bond and (not is_in_polargroup( poltype, mol, 'O-[*]', b, f)) #cut_bond = cut_bond and (not is_in_polargroup(mol,'C[NH2]', b,f)) if (cut_bond): f.write( str(b.GetBeginAtomIdx()) + " " + str(b.GetEndAtomIdx()) + "\n") f.write("\nN\n") f.write("\nN\n") f.flush() os.fsync(f.fileno()) f.close() return lfzerox, atomindextoremovedipquad, atomtypetospecialtrace, atomindextoremovedipquadcross
"Shannon R" + str(rnum) + " neutral", "Shannon R" + str(rnum) + " red" ]) RCentre = np.array([0.0, 0.0, 0.0]) for id in ring._path: at = mol.GetAtom(id) RCentre += np.array([at.GetX(), at.GetY(), at.GetZ()]) RCentre /= ring.Size() ex = [homaring, seed + ".log"] hr = [] for atom in list(sorted(ring._path)): hr.append(str(atom)) rings.append(atom) ex.extend(hr) obpat = ob.OBSmartsPattern() obpat.Init("C=O") obpat.Match(mol) # avoid getting lots of <openbabel.vectorvInt; proxy ... > etc. matches = [m for m in obpat.GetUMapList()] quins = [] for match in matches: if match[0] in rings: quins.append(match[1]) homas = [] flus = [] pdis = [] shans = [] out = subprocess.Popen(ex, stdout=subprocess.PIPE).stdout.read().split() homas.append(out[1]) ex[0] = fluring
def __init__(self, smartspattern): """Initialise with a SMARTS pattern.""" self.obsmarts = ob.OBSmartsPattern() self.obsmarts.Init(smartspattern)