def assign_canonical_am1bcc_charges(molecule): """ Assign canonical AM1-BCC charges to molecule. From canonical AM1-BCC recipe: http://docs.eyesopen.com/toolkits/cookbook/python/modeling/am1-bcc.html Parameters ---------- molecule : openeye.oechem.OEMol Molecule is modified in place. Raises ------ An Exception is raised if no charges were set due to a failure. """ # Create temporary copy of molecule to parameterize. expanded_molecule = oechem.OEMol(molecule) # Initialize Omega. omega = oeomega.OEOmega() omega.SetIncludeInput(True) omega.SetCanonOrder(False) omega.SetSampleHydrogens(True) eWindow = 15.0 omega.SetEnergyWindow(eWindow) omega.SetMaxConfs(800) omega.SetRMSThreshold(1.0) if not omega(expanded_molecule): raise ValueError("Cannot expand molecule with Omega Toolkit!") oequacpac.OEAssignPartialCharges(expanded_molecule, oequacpac.OECharges_AM1BCCSym) # Check whether charges were set. total_charge = 0.0 nonzero_charges_detected = False for (src_atom, dest_atom) in zip(expanded_molecule.GetAtoms(), molecule.GetAtoms()): if src_atom.GetPartialCharge() != dest_atom.GetPartialCharge(): nonzero_charges_detected = True total_charge += src_atom.GetPartialCharge() if not nonzero_charges_detected: raise ValueError("Charge assignment failure.") print " Total charge: %12.8f" % total_charge # Copy charges back to original molecule. for (src_atom, dest_atom) in zip(expanded_molecule.GetAtoms(), molecule.GetAtoms()): dest_atom.SetFormalCharge(src_atom.GetFormalCharge()) dest_atom.SetPartialCharge(src_atom.GetPartialCharge()) return
def assign_charges(molecule): """ Assign AM1-BCC charges using recommended scheme from Christopher Bayly. Parameters ---------- molecule : openeye.oechem.OEMol The molecule to be assigned conformations (will be modified). """ oequacpac.OEAssignPartialCharges( molecule, oequacpac.OECharges_AM1BCCSym ) # AM1BCCSym recommended by Chris Bayly to KAB+JDC, Oct. 20 2014. return
def compute_wbos(map_to_parent): oemol = cmiles.utils.load_molecule(map_to_parent) try: charged = fragmenter.chemi.get_charges(oemol, keep_confs=-1, strict_types=False) except: print('Cannot charge {}'.format(oechem.OEMolToSmiles(oemol))) return False # Collect all wbos elf_wbo_estimate = collect_wbos(charged) if not elf_wbo_estimate: warnings.warn('{} was not charged'.format( oechem.OEMolToSmiles(charged))) return False wbos = { key: { 'elf_estimate': elf_wbo_estimate[key], 'individual_confs': [] } for key in elf_wbo_estimate } # Compute WBO for each conformer for i, conf in enumerate(charged.GetConfs()): mol_copy = oechem.OEMol(conf) # Get WBO if oequacpac.OEAssignPartialCharges(mol_copy, oequacpac.OECharges_AM1BCCSym): ind_wbos = collect_wbos(molecule=mol_copy) for b in ind_wbos: if b not in wbos and 0 in b: wbos[b] = {'individual_confs': [ind_wbos[b]]} elif b not in wbos: reverse = tuple(reversed(b)) wbos[reverse]['individual_confs'].append(ind_wbos[b]) wbos[b]['individual_confs'].append(ind_wbos[b]) else: print('AM1BCC charging failed for {}, {}'.format(str(i), i)) return charged, wbos
def main(argv=[__name__]): itf = oechem.OEInterface(InterfaceData) if oechem.OECheckHelp(itf, argv): return 0 if not oechem.OEParseCommandLine(itf, argv): return 1 ifs = oechem.oemolistream() if not ifs.open(itf.GetString("-i")): oechem.OEThrow.Fatal("Unable to open %s for reading" % itf.GetString("-i")) ofs = oechem.oemolostream() if not ofs.open(itf.GetString("-o")): oechem.OEThrow.Fatal("Unable to open %s for writing" % itf.GetString("-o")) omega = oeomega.OEOmega() maxConfs = 0 omega.SetMaxConfs(maxConfs) omega.SetStrictStereo(False) omega.SetSampleHydrogens(True) omega.SetEnumNitrogen(oeomega.OENitrogenEnumeration_All) mol = oechem.OEMol() for mol in ifs.GetOEMols(): #print( mol.GetTitle() ) if not omega(mol): print("omega failed on %s" % mol.GetTitle()) title = mol.GetTitle() oechem.OETriposAtomNames(mol) oequacpac.OEAssignPartialCharges(mol, oequacpac.OECharges_AM1BCCSym) oechem.OEWriteConstMolecule(ofs, mol) ofs.close() return 0
def assign_simple_am1bcc_charges(molecule, verbose=True): """ Assign AM1-BCC charges to molecule using a single conformer, rather than the canonical scheme. Parameters ---------- molecule : openeye.oechem.OEMol Molecule is modified in place. Raises ------ An Exception is raised if no charges were set due to a failure. """ # Create temporary copy of molecule to parameterize. expanded_molecule = oechem.OEMol(molecule) oequacpac.OEAssignPartialCharges(expanded_molecule, oequacpac.OECharges_AM1BCC) # Check whether charges were set. nonzero_charges_detected = False total_charge = 0.0 for (src_atom, dest_atom) in zip(expanded_molecule.GetAtoms(), molecule.GetAtoms()): if src_atom.GetPartialCharge() != dest_atom.GetPartialCharge(): nonzero_charges_detected = True total_charge += src_atom.GetPartialCharge() if not nonzero_charges_detected: raise Exception("Charge assignment failure.") if verbose: print " Total charge: %12.8f" % total_charge # Copy charges back to original molecule. for (src_atom, dest_atom) in zip(expanded_molecule.GetAtoms(), molecule.GetAtoms()): dest_atom.SetPartialCharge(src_atom.GetPartialCharge()) dest_atom.SetFormalCharge(src_atom.GetFormalCharge()) return
oechem.OESmilesToMol(mol, optimal_mapped_smiles[i]) dih = fragmenter.torsions.find_torsion_around_bond(mol, bond) torsion_scans[ser_bond]['optimal'] = { 'wbos': [], 'elf10_wbo': omega_results[ser_bond][optimal_smiles[i]]['elf_estimate'], 'frag': optimal_mapped_smiles[i] } conformers = fragmenter.chemi.generate_grid_conformers(mol, dihedrals=[dih], intervals=[15], strict_types=False) for conf in conformers.GetConfs(): mol_copy = oechem.OEMol(conf) oechem.OEAddExplicitHydrogens(mol_copy) if oequacpac.OEAssignPartialCharges(mol_copy, oequacpac.OECharges_AM1BCCNoSym): bo = get_bond(mol=mol_copy, bond_tuple=bond) wbo = bo.GetData('WibergBondOrder') torsion_scans[ser_bond]['optimal']['wbos'].append(wbo) plt.figure() sbn.kdeplot(omega_benchmark_results[ser_bond]['parent']['wbo_dist'], shade=True, color=sbn.color_palette('colorblind')[0], label='parent molecule') sbn.distplot(omega_benchmark_results[ser_bond]['parent']['wbo_dist'], rug=True, hist=False, color=sbn.color_palette('colorblind')[0]) # sbn.distplot(results['parent']['wbo_dist'], hist=False, color=sbn.color_palette()[0])
oeiupac.OEParseIUPACName(molecule, name) molecule.SetTitle(name) # Normalize molecule. oechem.OEAddExplicitHydrogens(molecule) oechem.OETriposAtomNames(molecule) oechem.OEAssignAromaticFlags(molecule, oechem.OEAroModelOpenEye) # Create configuration. omega = oeomega.OEOmega() omega.SetStrictStereo(True) omega.SetIncludeInput(False) omega(molecule) # Create charges. oequacpac.OEAssignPartialCharges(molecule, oequacpac.OECharges_AM1BCCSym) # Write molecule. filename = '%s.tripos.mol2' % name print filename ofs = oechem.oemolostream() ofs.open(filename) oechem.OEWriteMolecule(ofs, molecule) ofs.close() # Replace <0> with resname. infile = open(filename, 'r') lines = infile.readlines() infile.close() newlines = [line.replace('<0>', resname) for line in lines] outfile = open(filename, 'w')
def am1wib(insdf, outdat, plotout=None): """ Parameters ---------- insdf: string, name of SDF file """ outf = open(outdat, 'w') ### Read in .sdf file and distinguish each molecule's conformers ifs = oechem.oemolistream() ifs.SetConfTest(oechem.OEAbsoluteConfTest()) if not ifs.open(insdf): oechem.OEThrow.Warning("Unable to open %s for reading" % insdf) return angList = [] # for plotting labelList = [] # for plotting for mol in ifs.GetOEMols(): molName = mol.GetTitle() outf.write('\n\n>>> Molecule: %s\tNumConfs: %d' % (molName, mol.NumConfs())) for i, conf in enumerate(mol.GetConfs()): ### AM1-BCC charge calculation charged_copy = oechem.OEMol(mol) status = oequacpac.OEAssignPartialCharges( charged_copy, oequacpac.OECharges_AM1BCCSym, False, False) if not status: raise (RuntimeError( "OEAssignPartialCharges returned error code %s" % status)) ### Our copy has the charges we want but not the right conformation. ### Copy charges over. Also copy over Wiberg bond orders. partial_charges = [] partial_bondorders = [] for atom in charged_copy.GetAtoms(): partial_charges.append(atom.GetPartialCharge()) for (idx, atom) in enumerate(mol.GetAtoms()): atom.SetPartialCharge(partial_charges[idx]) for bond in charged_copy.GetBonds(): partial_bondorders.append(bond.GetData("WibergBondOrder")) for (idx, bond) in enumerate(mol.GetBonds()): bond.SetData("WibergBondOrder", partial_bondorders[idx]) ### Sum angles around each invertible N, and get Wiberg bond order. for atom in conf.GetAtoms(oechem.OEIsInvertibleNitrogen()): aidx = atom.GetIdx() nbors = list(atom.GetAtoms()) ang1 = math.degrees( oechem.OEGetAngle(conf, nbors[0], atom, nbors[1])) ang2 = math.degrees( oechem.OEGetAngle(conf, nbors[1], atom, nbors[2])) ang3 = math.degrees( oechem.OEGetAngle(conf, nbors[2], atom, nbors[0])) ang_sum = math.fsum([ang1, ang2, ang3]) outf.write("\n\n%s: sum of angles for N, index %d: %f" % (molName, aidx, ang_sum)) angList.append(ang_sum) labelList.append("{}_{}_{}".format(molName, i, aidx)) for bond in atom.GetBonds(): nbor = bond.GetNbr(atom) nidx = nbor.GetIdx() nbor_wib = bond.GetData('WibergBondOrder') outf.write( "\n{}: wiberg bond order for indices {} {}: {}".format( molName, aidx, nidx, nbor_wib)) if plotout is not None: with open(plotout, 'w') as f: lis = [list(range(len(angList))), angList, labelList] for x in zip(*lis): f.write("{0}\t{1}\t{2}\n".format(*x)) ifs.close()
def get_charges(molecule, max_confs=800, strict_stereo=True, normalize=True, keep_confs=None, legacy=True): """Generate charges for an OpenEye OEMol molecule. Parameters ---------- molecule : OEMol Molecule for which to generate conformers. Omega will be used to generate max_confs conformations. max_confs : int, optional, default=800 Max number of conformers to generate strictStereo : bool, optional, default=True If False, permits smiles strings with unspecified stereochemistry. See https://docs.eyesopen.com/omega/usage.html normalize : bool, optional, default=True If True, normalize the molecule by checking aromaticity, adding explicit hydrogens, and renaming by IUPAC name. keep_confs : int, optional, default=None If None, apply the charges to the provided conformation and return this conformation, unless no conformation is present. Otherwise, return some or all of the generated conformations. If -1, all generated conformations are returned. Otherwise, keep_confs = N will return an OEMol with up to N generated conformations. Multiple conformations are still used to *determine* the charges. legacy : bool, default=True If False, uses the new OpenEye charging engine. See https://docs.eyesopen.com/toolkits/python/quacpactk/OEProtonFunctions/OEAssignCharges.html# Returns ------- charged_copy : OEMol A molecule with OpenEye's recommended AM1BCC charge selection scheme. Notes ----- Roughly follows http://docs.eyesopen.com/toolkits/cookbook/python/modeling/am1-bcc.html """ # If there is no geometry, return at least one conformation. if molecule.GetConfs() == 0: keep_confs = 1 if not oechem.OEChemIsLicensed(): raise (ImportError("Need License for OEChem!")) if not oequacpac.OEQuacPacIsLicensed(): raise (ImportError("Need License for oequacpac!")) if normalize: molecule = normalize_molecule(molecule) else: molecule = oechem.OEMol(molecule) charged_copy = generate_conformers( molecule, max_confs=max_confs, strict_stereo=strict_stereo) # Generate up to max_confs conformers if not legacy: # 2017.2.1 OEToolkits new charging function status = oequacpac.OEAssignCharges(charged_copy, oequacpac.OEAM1BCCCharges()) if not status: raise (RuntimeError("OEAssignCharges failed.")) else: # AM1BCCSym recommended by Chris Bayly to KAB+JDC, Oct. 20 2014. status = oequacpac.OEAssignPartialCharges( charged_copy, oequacpac.OECharges_AM1BCCSym) if not status: raise (RuntimeError( "OEAssignPartialCharges returned error code %d" % status)) #Determine conformations to return if keep_confs == None: #If returning original conformation original = molecule.GetCoords() #Delete conformers over 1 for k, conf in enumerate(charged_copy.GetConfs()): if k > 0: charged_copy.DeleteConf(conf) #Copy coordinates to single conformer charged_copy.SetCoords(original) elif keep_confs > 0: logger().debug( "keep_confs was set to %s. Molecule positions will be reset." % keep_confs) #Otherwise if a number is provided, return this many confs if available for k, conf in enumerate(charged_copy.GetConfs()): if k > keep_confs - 1: charged_copy.DeleteConf(conf) elif keep_confs == -1: #If we want all conformations, continue pass else: #Not a valid option to keep_confs raise (ValueError('Not a valid option to keep_confs in get_charges.')) return charged_copy