def get_atom_surface_areas(molecule, surface): """ """ # create empty array to hold area values for all triangles areas = oechem.OEFloatArray(surface.GetNumTriangles()) # fill array with calculated surface areas oespicoli.OECalculateTriangleAreas(surface, areas) # create empty array to hold atom surface areas atom_areas = oechem.OEFloatArray(molecule.GetMaxAtomIdx()) # fill array with surface contributions for each atom for i in xrange(surface.GetNumTriangles()): # get the triangle elements v1 = surface.GetTrianglesElement(i * 3) v2 = surface.GetTrianglesElement(i * 3 + 1) v3 = surface.GetTrianglesElement(i * 3 + 2) # get the atom indices for each triangle element a1 = surface.GetAtomsElement(v1) a2 = surface.GetAtomsElement(v2) a3 = surface.GetAtomsElement(v3) atom_areas[a1] += areas[i] / 3.0 atom_areas[a2] += areas[i] / 3.0 atom_areas[a3] += areas[i] / 3.0 return np.array(atom_areas)
def generate_grid_conformers(molecule, dihedrals, intervals, max_rotation=360, copy_mol=True): """ Generate conformers using torsion angle grids. Parameters ---------- molecule: OEMol dihedrals: list of intervals Returns ------- """ # molecule must be mapped if copy_mol: molecule = copy.deepcopy(molecule) if cmiles.utils.has_atom_map(molecule): remove_map(molecule) else: raise ValueError("Molecule must have map indices") # Check length of dihedrals match length of intervals conf_mol = generate_conformers(molecule, max_confs=1) conf = conf_mol.GetConfs().next() coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3) conf.GetCoords(coords) torsions = [[conf_mol.GetAtom(oechem.OEHasMapIdx(i + 1)) for i in dih] for dih in dihedrals] for i, tor in enumerate(torsions): copy_conf_mol = copy.deepcopy(conf_mol) conf_mol.DeleteConfs() for conf in copy_conf_mol.GetConfs(): coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3) conf.GetCoords(coords) for angle in range(5, max_rotation + 5, intervals[i]): newconf = conf_mol.NewConf(coords) oechem.OESetTorsion(newconf, tor[0], tor[1], tor[2], tor[3], radians(angle)) restore_map(conf_mol) return conf_mol
def setPositionsInOEMol(oemol, positions): """Set the positions in an OEMol using a position array with units from simtk.unit, i.e. from OpenMM. Atoms must have same order. Arguments: --------- oemol : OEMol OpenEye molecule positions : Nx3 array Unit-bearing via simtk.unit Nx3 array of coordinates """ warnings.warn(DEPRECATION_WARNING_TEXT, PendingDeprecationWarning) from openeye import oechem if oemol.NumAtoms() != len(positions): raise ValueError( "Number of atoms in molecule does not match length of position array." ) pos_unitless = positions / unit.angstroms coordlist = [] for idx in range(len(pos_unitless)): for j in range(3): coordlist.append(pos_unitless[idx][j]) oemol.SetCoords(oechem.OEFloatArray(coordlist))
def GetMolDetails(mol, label): """ Parameters ---------- mol: single OEChem conformer with coordinates label: string - name of the molecule. Can be an empty string. Returns ------- optinfo: string - Turbomole input file for autoDefine.py xinfo: string - XYZ format coordinates to feed into Turbomole's x2t """ optinfo = ("$title %s" % label) optinfo += ("\n$charge %d" % oechem.OENetCharge(mol)) optinfo += ("\n$end") xinfo = ("%d\n" % mol.NumAtoms()) xyz = oechem.OEFloatArray(3) # get coordinates of each atom for atom in mol.GetAtoms(): mol.GetCoords(atom, xyz) xinfo+=( '\n %s %10.4f %10.4f %10.4f' \ %(oechem.OEGetAtomicSymbol(atom.GetAtomicNum()), xyz[0], xyz[1], xyz[2]) ) return optinfo, xinfo
def test_oemol_nhfcl(): """Test coordinates for NHFCl read in as OEMol.""" import openeye.oechem as oechem import openeye.oeomega as oeomega # coordinates for N, F, H, Cl respectively # generated after minimization with improper phase of 150 degrees coordlist = [ 0.155, -0.088, -0.496, -1.054, -0.776, -0.340, -0.025, 0.906, -0.516, 1.689, -0.635, -1.263 ] # create OEMol mol = oechem.OEMol() oechem.OESmilesToMol(mol, 'FNCl') omega = oeomega.OEOmega() omega.SetMaxConfs(1) omega.SetIncludeInput(False) omega.SetStrictStereo(False) status = omega(mol) oechem.OETriposAtomTypes(mol) oechem.OETriposAtomNames(mol) oechem.OEAddExplicitHydrogens(mol) # set provided coordinates mol.SetCoords(oechem.OEFloatArray(coordlist)) # calculate and check improper angle crds, names = find_improper_angles(mol) ang = calc_improper_angle(crds[0][0], crds[0][1], crds[0][2], crds[0][3]) if abs(ang - 15.0) > 0.1 and abs(ang - 165.0) > 0.1: raise Exception( "Error calculating improper of test OEMol. Calculated {} degrees, but should be 15 or 165 degrees." .format(ang))
def process_molecule(smiles: str) -> Tuple[Optional[Molecule], Optional[str]]: error = None try: oe_molecule = smiles_to_molecule(smiles, guess_stereochemistry=True) # Generate a set of conformers and charges for the molecule. conformers = ConformerGenerator.generate(oe_molecule, ConformerSettings()) charges = ChargeGenerator.generate(oe_molecule, conformers, ChargeSettings()) # Add the charges and conformers to the OE object. for oe_atom in oe_molecule.GetAtoms(): oe_atom.SetPartialCharge(charges[oe_atom.GetIdx()].item()) oe_molecule.DeleteConfs() for conformer in conformers: oe_molecule.NewConf(oechem.OEFloatArray(conformer.flatten())) # Map to an OpenFF molecule object. molecule = Molecule.from_openeye(oe_molecule) # Compute the WBOs molecule.assign_fractional_bond_orders( "am1-wiberg", use_conformers=molecule.conformers) except (BaseException, Exception) as e: molecule = None error = f"Failed to process {smiles}: {str(e)}" return molecule, error
def main(argv=[__name__]): if len(argv) != 3: oechem.OEThrow.Usage("%s <molfile.pdb> <out.srf>" % argv[0]) mol = oechem.OEGraphMol() ifs = oechem.oemolistream(argv[1]) oechem.OEReadMolecule(ifs, mol) if not oechem.OEHasResidues(mol): oechem.OEPerceiveResidues(mol, oechem.OEPreserveResInfo_All) serials = {} for atom in mol.GetAtoms(): res = oechem.OEAtomGetResidue(atom) serials[res.GetSerialNumber()] = atom outsurf = oespicoli.OESurface() center = oechem.OEFloatArray(3) for line in open(argv[1]): if line.startswith("ANISOU"): serno, factors = ParseFactors(line) if serno in serials: mol.GetCoords(serials[serno], center) surf = GetEllipsoidalSurface(center, factors) oespicoli.OEAddSurfaces(outsurf, surf) oespicoli.OEWriteSurface(argv[2], outsurf)
def GetSzmapEnergies(lig, prot): """ run szmap at ligand coordinates in the protein context @rtype : None @param lig: mol defining coordinates for szmap calcs @param prot: context mol for szmap calcs (must have charges and radii) """ print("num\tatom\t%s\t%s\t%s\t%s\t%s" % (oeszmap.OEGetEnsembleName(oeszmap.OEEnsemble_NeutralDiffDeltaG), oeszmap.OEGetEnsembleName(oeszmap.OEEnsemble_PSolv), oeszmap.OEGetEnsembleName(oeszmap.OEEnsemble_WSolv), oeszmap.OEGetEnsembleName(oeszmap.OEEnsemble_VDW), oeszmap.OEGetEnsembleName(oeszmap.OEEnsemble_OrderParam))) coord = oechem.OEFloatArray(3) sz = oeszmap.OESzmapEngine(prot) rslt = oeszmap.OESzmapResults() for i, atom in enumerate(lig.GetAtoms()): lig.GetCoords(atom, coord) if not oeszmap.OEIsClashing(sz, coord): oeszmap.OECalcSzmapResults(rslt, sz, coord) print("%2d\t%s\t%.3f\t%.3f\t%.3f\t%.3f\t%.3f" % (i, atom.GetName(), rslt.GetEnsembleValue(oeszmap.OEEnsemble_NeutralDiffDeltaG), rslt.GetEnsembleValue(oeszmap.OEEnsemble_PSolv), rslt.GetEnsembleValue(oeszmap.OEEnsemble_WSolv), rslt.GetEnsembleValue(oeszmap.OEEnsemble_VDW), rslt.GetEnsembleValue(oeszmap.OEEnsemble_OrderParam))) else: print("%2d\t%s CLASH" % (i, atom.GetName()))
def molecule_from_record(record: MoleculeESPRecord) -> Molecule: """Converts an ``openff-recharge`` ESP record to to an Open Force Field molecule.""" oe_molecule = oechem.OEMol() oechem.OESmilesToMol(oe_molecule, record.tagged_smiles) ordered_conformer = reorder_conformer(oe_molecule, record.conformer) # Clear the records index map. for atom in oe_molecule.GetAtoms(): atom.SetMapIdx(0) oe_molecule.DeleteConfs() oe_molecule.NewConf(oechem.OEFloatArray(ordered_conformer.flatten())) with NamedTemporaryFile(suffix=".mol2") as file: # Workaround for stereochemistry being incorrectly perceived. molecule = Molecule.from_openeye(oe_molecule, allow_undefined_stereo=True) molecule.to_file(file.name, "mol2") molecule = molecule.from_file(file.name) return molecule
def GenerateSzmapProbes(oms, cumulativeProb, lig, prot): """ generate multiconf probes and data-rich points at ligand coords @rtype : None @param oms: output mol stream for points and probes @param cumulativeProb: cumulative probability for cutoff of point set @param lig: mol defining coordinates for szmap calcs @param prot: context mol for szmap calcs (must have charges and radii) """ coord = oechem.OEFloatArray(3) sz = oeszmap.OESzmapEngine(prot) rslt = oeszmap.OESzmapResults() points = oechem.OEGraphMol() points.SetTitle("points %s" % lig.GetTitle()) probes = oechem.OEMol() for i, atom in enumerate(lig.GetAtoms()): lig.GetCoords(atom, coord) if not oeszmap.OEIsClashing(sz, coord): oeszmap.OECalcSzmapResults(rslt, sz, coord) rslt.PlaceNewAtom(points) clear = False rslt.PlaceProbeSet(probes, cumulativeProb, clear) oechem.OEWriteMolecule(oms, points) oechem.OEWriteMolecule(oms, probes)
def optSMIRNOFF(input_Mol, FF_file, output_mol2, log ): """ Creates OpenMM Topology, System, and initial positions of given molecule. Parameters ---------- Mol: an OEChem molecule FF_file: string name of *.ffxml file with path output_mol2: string path/filename.mol2 to save output structure log: open file to write output data to Returns ------- Boolean: True if output is successfully created """ # make copy of the input_Mol Mol = oechem.OEMol(input_Mol) # check that the *.ffxml file exists if not os.path.exists(FF_file): log.write("Cannot find the ffxml file (%s)!\n"\ % FF_file) return ff = forcefield.ForceField(FF_file) top, syst, pos = ff_utils.create_system_from_molecule(ff, Mol, verbose = False) ### minimize with OpenMM and return the final coordinates in the OEform min_pos = minimizeOpenMM(top, syst, pos) Mol.SetCoords(oechem.OEFloatArray(min_pos)) return writeUpdatedMol(Mol, output_mol2, log)
def _create_receptor(self): """Create an OpenEye receptor from a mol2 file. Returns ------- openeye.oedocking.OEReceptor The OpenEye receptor object. """ from openeye import oechem, oedocking input_stream = oechem.oemolistream(self.receptor_coordinate_file) original_receptor_molecule = oechem.OEGraphMol() oechem.OEReadMolecule(input_stream, original_receptor_molecule) center_of_mass = oechem.OEFloatArray(3) oechem.OEGetCenterOfMass(original_receptor_molecule, center_of_mass) receptor = oechem.OEGraphMol() oedocking.OEMakeReceptor( receptor, original_receptor_molecule, center_of_mass[0], center_of_mass[1], center_of_mass[2], ) return receptor
def main(argv=[__name__]): if len(argv) != 3: oechem.OEThrow.Usage("%s <molfile> <queryfile>" % sys.argv[0]) molfs = oechem.oemolistream(sys.argv[1]) mol = oechem.OEGraphMol() oechem.OEReadMolecule(molfs, mol) if oechem.OEGetFileExtension(sys.argv[2]) != "sq": oechem.OEThrow.Fatal( "Only can write shape query to .sq output file format") # Use OEOverlapPrep to remove hydrogens and add # color atoms to the molecule prep = oeshape.OEOverlapPrep() prep.Prep(mol) # Get the color atoms, create gaussians and add them # to the shape query query = oeshape.OEShapeQuery() for atom in oeshape.OEGetColorAtoms(mol): coords = oechem.OEFloatArray(3) mol.GetCoords(atom, coords) gauss = oegrid.OEGaussian(1.0, 1.0, coords, oeshape.OEGetColorType(atom)) query.AddColorGaussian(gauss) # Remove color atoms from the molecule and add to the query oeshape.OERemoveColorAtoms(mol) query.SetMolecule(mol) oeshape.OEWriteShapeQuery(sys.argv[2], query) print("shape query created")
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 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 doAlignSs(self, unique=True, maxMatches=20): """Test the SS comparison between current reference and fit molecules - Return list of corresponding atoms on success or an empty list otherwise. """ atomMapL = [] fitAtomUnMappedL = [] # nAtomsRef = self.__refmol.NumAtoms() nAtomsFit = self.__fitmol.NumAtoms() # ------- oechem.OEAddExplicitHydrogens(self.__refmol) oechem.OEAddExplicitHydrogens(self.__fitmol) fitAtD = {} # for at in self.__fitmol.GetAtoms(): nAtL = at.GetAtoms() neighbors = [nAt.GetName() for nAt in nAtL] atType = oechem.OEGetAtomicSymbol(at.GetAtomicNum()) xyzL = oechem.OEFloatArray(3) self.__fitmol.GetCoords(at, xyzL) fitAtD[at.GetIdx()] = AlignAtomUnMapped( fitId=self.__fitId, fitAtIdx=at.GetIdx(), fitAtName=at.GetName(), fitAtType=atType, fitAtNo=at.GetAtomicNum(), fitAtFormalCharge=at.GetFormalCharge(), x=xyzL[0], y=xyzL[1], z=xyzL[2], fitNeighbors=neighbors, ) # logger.debug("nAtomsRef %d nAtomsFit %d", nAtomsRef, nAtomsFit) # # -------- self.__setupSubStructure(self.__refmol) self.__ss.SetMaxMatches(maxMatches) miter = self.__ss.Match(self.__fitmol, unique) if miter.IsValid(): match = miter.Target() for mAt in match.GetAtoms(): atomMapL.append( AlignAtomMap( refId=self.__refId, refAtIdx=mAt.pattern.GetIdx(), refAtNo=mAt.pattern.GetAtomicNum(), refAtName=mAt.pattern.GetName(), fitId=self.__fitId, fitAtIdx=mAt.target.GetIdx(), fitAtNo=mAt.target.GetAtomicNum(), fitAtName=mAt.target.GetName(), ) ) fitAtD.pop(mAt.target.GetIdx()) logger.debug("fitAtD %r", fitAtD) fitAtomUnMappedL = list(fitAtD.values()) return (nAtomsRef, self.__refFD, nAtomsFit, self.__fitFD, atomMapL, fitAtomUnMappedL)
def GetEllipsoidalSurface(center, factors): surf = oespicoli.OESurface() dir1 = oechem.OEFloatArray(3) dir1[0] = factors[0] dir1[1] = factors[3] dir1[2] = factors[4] dir2 = oechem.OEFloatArray(3) dir2[0] = factors[3] dir2[1] = factors[1] dir2[2] = factors[5] dir3 = oechem.OEFloatArray(3) dir3[0] = factors[4] dir3[1] = factors[5] dir3[2] = factors[2] oespicoli.OEMakeEllipsoidSurface(surf, center, 10.0, 10.0, 10.0, dir1, dir2, dir3, 4) return surf
def doAlignMcss(self, unique=True, minFrac=1.0, useExhaustive=True): """Test the MCSS comparison between current reference and fit molecules - Return list of corresponding atoms on success or an empty list otherwise. """ atomMapL = [] fitAtomUnMappedL = [] # nAtomsRef = self.__refmol.NumAtoms() nAtomsFit = self.__fitmol.NumAtoms() fitAtD = {} for at in self.__fitmol.GetAtoms(): nAtL = at.GetAtoms() neighbors = [nAt.GetName() for nAt in nAtL] atType = oechem.OEGetAtomicSymbol(at.GetAtomicNum()) xyzL = oechem.OEFloatArray(3) self.__fitmol.GetCoords(at, xyzL) fitAtD[at.GetIdx()] = AlignAtomUnMapped( fitId=self.__fitId, fitAtIdx=at.GetIdx(), fitAtName=at.GetName(), fitAtType=atType, fitAtNo=at.GetAtomicNum(), fitAtFormalCharge=at.GetFormalCharge(), x=xyzL[0], y=xyzL[1], z=xyzL[2], fitNeighbors=neighbors, ) minAtoms = int(min(nAtomsRef, nAtomsFit) * minFrac) # ------- self.__setupMCSS(self.__refmol, useExhaustive=useExhaustive) self.__mcss.SetMCSFunc(oechem.OEMCSMaxAtoms()) self.__mcss.SetMinAtoms(minAtoms) oechem.OEAddExplicitHydrogens(self.__refmol) oechem.OEAddExplicitHydrogens(self.__fitmol) # # -------- miter = self.__mcss.Match(self.__fitmol, unique) if miter.IsValid(): match = miter.Target() for mAt in match.GetAtoms(): atomMapL.append( AlignAtomMap( refId=self.__refId, refAtIdx=mAt.pattern.GetIdx(), refAtNo=mAt.pattern.GetAtomicNum(), refAtName=mAt.pattern.GetName(), fitId=self.__fitId, fitAtIdx=mAt.target.GetIdx(), fitAtNo=mAt.target.GetAtomicNum(), fitAtName=mAt.target.GetName(), ) ) fitAtD.pop(mAt.target.GetIdx()) fitAtomUnMappedL = list(fitAtD.values()) return (nAtomsRef, self.__refFD, nAtomsFit, self.__fitFD, atomMapL, fitAtomUnMappedL)
def optGAFFx(mol, gaffdir, output_mol2, log): """ Uses OEMol and GAFF input files to minimize the system and write output mol2 Parameters ---------- mol: OEMol gaffdir: directory with GAFF input files output_mol2: string, path/to/mol2 where output structure should be saved log: open file to write log data Returns ------- boolean: True minimization succeeded, False otherwise """ ### Check: optimized file not existing, gaff dependencies present, gaff files have content if os.path.exists(output_mol2): log.write('Optimization file %s already exists\n' % (output_mol2)) return False ### Locate GAFF input files prmFile = os.path.join(gaffdir,mol.GetTitle()+'.prmtop') inpFile = os.path.join(gaffdir,mol.GetTitle()+'.inpcrd') # Check prmtop file if not os.path.exists(prmFile): log.write("%s does not exist, skipping minimization\n" % prmFile) return False elif not os.path.getsize(prmFile) > 40: log.write("%s is empty, skipping minimization\n" % prmFile) return False # Check inpcrd file if not os.path.exists(inpFile): log.write("%s does not exist, skipping minimization\n" % inpFile) return False elif not os.path.getsize(inpFile) > 40: log.write("%s is empty, skipping minimization\n" % inpFile) return False # make copy of mol2 file tmpmol = oechem.OEMol(mol) # load input files and create parmed system parm = parmed.load_file(prmFile, inpFile) Topology = parm.topology Positions = parm.positions System = parm.createSystem(nonbondedMethod=app.NoCutoff) ### Use parmed to write out mol2 file from optimized coordinates. minimized_positions = minimizeOpenMM(Topology, System, Positions) tmpmol.SetCoords(oechem.OEFloatArray(minimized_positions)) return writeUpdatedMol(tmpmol, output_mol2, log)
def set_conf_data(mol, props, calctype): # Set last coordinates from optimization. skip if missing. if 'coords' in props and len(props['coords']) != 0: mol.SetCoords(oechem.OEFloatArray(props['coords'])) # Set SD tags for this molecule pt.set_sd_tags(mol, props, calctype) return mol
def CullClashPts(mol, nbrList, scalefac, pts, moltype='OEMol'): '''Culls out points in the list which are within scaled vdw radii of any other atom in the OEMol mol. Input arguments: mol: the OEMol(or RDMol) whose neighbors are examined. nbrList: a list of OEAtoms which are neighbors of the point list. scalefac: the scale factor for the atomic radii. pts: the list of points to cull Returns the list of points outside the scaled radii of the neighboring atoms.''' # precalculate neighbor coords nbrXyz = [] if moltype is 'OEMol': xyztmp = oechem.OEFloatArray(3) for atom in nbrList: if not mol.GetCoords(atom, xyztmp): print('cannot get coords for atom', atom.GetName()) nbrXyz.append(list(xyztmp)) # precalculate neighbor scaled squared radii nbrRadiusSq = [ atom.GetRadius() * scalefac * atom.GetRadius() * scalefac for atom in nbrList ] elif moltype is 'RDMol': xyztmp = np.zeros(3) pos = mol.GetConformer().GetPositions() for atom in nbrList: xyztmp = pos[atom.GetIdx()] nbrXyz.append(list(xyztmp)) # precalculate neighbor scaled squared radii nbrRadiusSq = [ float(atom.GetProp('radius')) * scalefac * float(atom.GetProp('radius')) * scalefac for atom in nbrList ] culled = [] # iterate over each point in the point list for pt in pts: #print(pt) goodPt = True # iterate over all atoms in the neighborlist; precalculated coords and radiusSq for i, (xyz, radiusSq) in enumerate(zip(nbrXyz, nbrRadiusSq)): #print(xyz) dx = pt[0] - xyz[0] dy = pt[1] - xyz[1] dz = pt[2] - xyz[2] distSq = dx * dx + dy * dy + dz * dz #print( i, distSq, radiusSq) if distSq < radiusSq: #print('bad point; breaking') goodPt = False break if goodPt: #print('good point; adding') culled.append(pt) return culled
def make_psi_input(mol, label, method, basisset, SPE=False, mem=None): """ Parameters ---------- mol: single OEChem conformer with coordinates label: string - name of the molecule. Can be an empty string. method: string - specification of method (see Psi4 website for options) basisset: string - specification of basis set SPE: boolean - False (default) for geom opt. True for single point E calcns mem: string - specify Psi4 job memory. E.g. "2 Gb" "2000 Mb" "2000000 Kb" Returns ------- inputstring: string - containing contents of whole input file for this conf """ inputstring = "" xyz = oechem.OEFloatArray(3) # specify memory requirements, if defined if mem != None: inputstring += "memory %s\n" % mem inputstring+=( 'molecule %s {\n' % label ) # charge and multiplicity; multiplicity hardwired to singlet (usually is) netCharge = oechem.OENetCharge( mol) inputstring+=( ' %s 1' % netCharge ) # get coordinates of each atom for atom in mol.GetAtoms(): mol.GetCoords( atom, xyz) inputstring+=( '\n %s %10.4f %10.4f %10.4f' \ %(oechem.OEGetAtomicSymbol(atom.GetAtomicNum()), xyz[0], xyz[1], xyz[2]) ) inputstring+=( '\n units angstrom\n}') # check if mol has a "freeze" tag for x in oechem.OEGetSDDataPairs(mol): if "atoms to freeze" in x.GetTag(): freeze_list = x.GetValue() inputstring += "\n\nfreeze_list = \"\"\"\n {} xyz\n {} xyz\n {} xyz\n {} xyz\n\"\"\"".format(freeze_list[1], freeze_list[4], freeze_list[7], freeze_list[10]) inputstring += "\nset optking frozen_cartesian $freeze_list" inputstring += "\nset optking dynamic_level = 1\nset optking consecutive_backsteps = 2\nset optking intrafrag_step_limit = 0.1\nset optking interfrag_step_limit = 0.1" # explicitly specify MP2 RI-auxiliary basis for Ahlrichs basis set # http://www.psicode.org/psi4manual/master/basissets_byfamily.html if method.lower()=='mp2' and 'def' in basisset and basisset.lower()!='def2-qzvpd': inputstring+=('\n\nset basis %s' % (basisset)) inputstring+=('\nset df_basis_mp2 %s-ri' % (basisset)) inputstring+=('\nset freeze_core True') else: inputstring+=('\n\nset basis %s' % (basisset)) inputstring+=('\nset freeze_core True') # specify command for type of calculation if SPE is False: inputstring+=('\noptimize(\'%s\')' % (method)) else: inputstring+=('\nenergy(\'%s\')' % (method)) return inputstring
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 GenerateMSKShellPts(mol, options, moltype='OEMol'): '''Generates a set of points around the molecule, based on scaled atomic radii, according to the Merz-Singh-Kollman (MSK) scheme for ESP points. The MSK scheme is based on Bondi atomic radii, with four Connolly-sphere shells of points set at scaled atomic radii with scale factors 1.4, 1.6, 1.8, and 2.0 with a targeted surface density of 1 point per angstrom squared on each shell. This function offers flexibility in that it uses the atomic radii on the molecule and the options object to specify target surface spacing (inverse of density) and lower and upper scale factors (incrementing by 0.2 for each shell). Input arguments: mol: the OEMol(or RDMol) molecule for which we want the MSK point set. options: a dictionary with keys "space", "inner", and "outer", pointing to values for the target surface spacing, inner and outer vdw scale factors, respectively, all in angstrom units. Returns the MSK set as a list of xyz triples (in angstroms)''' density = 1 / options['space'] print('MSK points with density', density) if moltype is 'OEMol': xyz = oechem.OEFloatArray(3) elif moltype is 'RDMol': xyz = np.zeros(3) pos = mol.GetConformer().GetPositions() molPts = [] shellScale = options['inner'] # increment atom radius shellScale by 0.2 placing a shell of points each time # the "while" test has a tiny increment to prevent premature termination while shellScale < (options['outer'] + .000001): shellPts = [] for atom in mol.GetAtoms(): if atom.GetAtomicNum() < 1: # dummy atoms are ignored continue if moltype is 'OEMol': if not mol.GetCoords(atom, xyz): print('cannot get coords for atom', atom.GetName()) scaledRad = atom.GetRadius() * shellScale elif moltype is 'RDMol': xyz = pos[atom.GetIdx()] scaledRad = float(atom.GetProp('radius')) * shellScale nbrs = GenerateVdwNeighborList(mol, atom, shellScale, moltype) atomPts = GenerateConnollySphere(scaledRad, xyz, density) culledPts = CullClashPts(mol, nbrs, shellScale, atomPts, moltype) #print( atom.GetName(), atom.GetRadius(), 'numPts pre-cull:', len(atomPts), 'post-cull:', len(culledPts)) shellPts += culledPts print('MSK shell scaling vdW by {0:5.2f}: {1:d} points'.format( shellScale, len(shellPts))) # molPts += shellPts molPts.append(shellPts) # changed shellScale += 0.2 return molPts
def MoleculeCenter(mol, moltype='OEMol'): if moltype is 'OEMol': xyzs = [] for atom in mol.GetAtoms(): xyz = oechem.OEFloatArray(3) mol.GetCoords(atom, xyz) xyzs.append(xyz) xyzs = np.array(xyzs) center = np.average(xyzs, axis=0) elif moltype is 'RDMol': xyzs = mol.GetConformer().GetPositions() center = np.average(xyzs, axis=0) return center
def CalcBindingEnergy(zap, protein, ligand, cmplx): stopwatch = oechem.OEStopwatch() stopwatch.Start() ppot = oechem.OEFloatArray(protein.GetMaxAtomIdx()) zap.SetMolecule(protein) zap.CalcAtomPotentials(ppot) proteinEnergy = 0.0 for atom in protein.GetAtoms(): proteinEnergy += ppot[atom.GetIdx()] * atom.GetPartialCharge() proteinEnergy *= 0.5 lpot = oechem.OEFloatArray(ligand.GetMaxAtomIdx()) zap.SetMolecule(ligand) zap.CalcAtomPotentials(lpot) ligandEnergy = 0.0 for atom in ligand.GetAtoms(): ligandEnergy += lpot[atom.GetIdx()] * atom.GetPartialCharge() ligandEnergy *= 0.5 cpot = oechem.OEFloatArray(cmplx.GetMaxAtomIdx()) zap.SetMolecule(cmplx) zap.CalcAtomPotentials(cpot) cmplxEnergy = 0.0 for atom in cmplx.GetAtoms(): cmplxEnergy += cpot[atom.GetIdx()] * atom.GetPartialCharge() cmplxEnergy *= 0.5 energy = cmplxEnergy - ligandEnergy - proteinEnergy time = stopwatch.Elapsed() if zap.IsFocusTargetSet(): focused = "Yes" else: focused = "No" PrintInfo(focused, energy, time)
def SetCustomConstraints(receptor, proteinHeavyAtom): # @ <SNIPPET-RECEPTOR-CUSTOM-CONSTRAINT-EDITING-3> customConstraints = oedocking.OEReceptorGetCustomConstraints(receptor) feature = customConstraints.AddFeature() feature.SetFeatureName("Example protein contact constraint") sphereRadius = 4.0 sphereCenter = oechem.OEFloatArray(3) receptor.GetCoords(proteinHeavyAtom, sphereCenter) sphere = feature.AddSphere() sphere.SetRad(sphereRadius) sphere.SetCenter(sphereCenter[0], sphereCenter[1], sphereCenter[2]) oedocking.OEReceptorSetCustomConstraints(receptor, customConstraints)
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
def min_ffxml(mol, ofs, ffxml): """ Minimize the mol with force field input from FFXML file. Parameters ---------- mol : OpenEye single-conformer molecule ofs : OpenEye output filestream ffxml : string name of FFXML file """ # make copy of the input mol oe_mol = oechem.OEGraphMol(mol) try: # create openforcefield molecule ==> prone to triggering Exception off_mol = Molecule.from_openeye(oe_mol) # load in force field ff = ForceField(ffxml) # create components for OpenMM system topology = Topology.from_molecules(molecules=[off_mol]) # create openmm system ==> prone to triggering Exception #system = ff.create_openmm_system(topology, charge_from_molecules=[off_mol]) system = ff.create_openmm_system(topology) except Exception as e: smilabel = oechem.OEGetSDData(oe_mol, "SMILES QCArchive") print( ' >>> openforcefield failed to create OpenMM system: ' f'{oe_mol.GetTitle()} {smilabel}: {e}') return positions = structure.extractPositionsFromOEMol(oe_mol) # minimize structure with ffxml newpos, energy = run_openmm(topology, system, positions) # save geometry, save energy as tag, write mol to file oe_mol.SetCoords(oechem.OEFloatArray(newpos)) oechem.OESetSDData(oe_mol, "Energy FFXML", str(energy)) oechem.OEWriteConstMolecule(ofs, oe_mol) return
def GenerateBoxMinMax(mol, moltype='OEMol'): '''finds the smallest box dimension to enclose the molecule around the outer boundary radius of all the atoms. Each atom's outer boundary radius is stored in the atom's Generic Data with tag "PointSetOuterRad". Input arguments: mol: the OEMol(or RDMol) molecule for which the box dimensions are desired. Returns two tuples of xyz coords, the first is the box minimum coords and the second is the the box maximum coords.''' if moltype is 'OEMol': xyzOEArr = oechem.OEFloatArray(3) elif moltype is 'RDMol': xyzOEArr = np.zeros(3) pos = mol.GetConformer().GetPositions() # print(pos) # input() boxmin = np.array([1.e10, 1.e10, 1.e10]) boxmax = np.array([-1.e10, -1.e10, -1.e10]) for atom in mol.GetAtoms(): # dummy atoms are ignored atomicNum = atom.GetAtomicNum() if atomicNum < 1: continue # get xyz coords for atom if moltype is 'OEMol': if not mol.GetCoords(atom, xyzOEArr): print('Molecule', mol.GetTitle(), 'cannot get coords for atom', atom.GetName()) xyz = np.array(xyzOEArr) # get outer (larger) radius for atom to use for outer limit of box outer = atom.GetRadius() if atom.HasData('PointSetOuterRad'): outer = atom.GetData('PointSetOuterRad') elif moltype is 'RDMol': xyzOEArr = pos[atom.GetIdx()] xyz = np.array(xyzOEArr) outer = float(atom.GetProp('radius')) if atom.GetProp('PointSetOuterRad') is not None: outer = float(atom.GetProp('PointSetOuterRad')) # find atom min and max vdw atomMin = xyz - outer atomMax = xyz + outer for crd in [0, 1, 2]: if atomMin[crd] < boxmin[crd]: boxmin[crd] = atomMin[crd] if atomMax[crd] > boxmax[crd]: boxmax[crd] = atomMax[crd] return boxmin, boxmax