예제 #1
0
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)
예제 #2
0
def DumpGroups(mol):
    print("groups of", mol.GetTitle())
    print("number of atom groups", oechem.OECount(mol, IsAtomGroup()))
    print("number of bond groups", oechem.OECount(mol, IsBondGroup()))
    print("number of aromatic atoms groups",
          oechem.OECount(mol, oechem.OEHasGroupType(oechem.OEGetTag("aromatic atoms"))))
    print("number of aromatic bonds groups",
          oechem.OECount(mol, oechem.OEHasGroupType(oechem.OEGetTag("aromatic bonds"))))
    # loop over groups
    for g in mol.GetGroups():
        DumpGroup(g)
    print()
예제 #3
0
    def packMDData(self, mol):
        """
        This method attached the Parmed structure to the passed OEMol()

        Parameters
        ----------
        mol : OEMol() OpenEye Molecule object
            the molecular system

        Returns
        -------
        mol : OeMol() 
            the changed in place molecule
        """
        try:
            # Try to attach the Parmed structure to the molecule. The molecule is changed in place
            mol = PackageOEMol.pack(mol, self.__parmed_structure__)
        except Exception as e:
            raise RuntimeError(
                'It was not possible to attached '
                'the parmed structure to the molecule {}'.format(e))

        if self.ref_positions:
            packedpos = PackageOEMol.encodePyObj(self.ref_positions)
            mol.SetData(oechem.OEGetTag('OEMDDataRefPositions'), packedpos)

        return mol
def SetPartialCharge(mol, tagname):
    oechem.OEMMFFAtomTypes(mol)
    oechem.OEMMFF94PartialCharges(mol)

    tag = oechem.OEGetTag(tagname)
    for atom in mol.GetAtoms():
        atom.SetData(tag, atom.GetPartialCharge())
예제 #5
0
def _tag_fgroups(mol, fgroups_smarts=None):
    """
    This function tags atoms and bonds of functional groups defined in fgroup_smarts. fgroup_smarts is a dictionary
    that maps functional groups to their smarts pattern. It can be user generated or from yaml file.

    Parameters
    ----------
    mol: Openeye OEMolGraph
    frgroups_smarts: dictionary of functional groups mapped to their smarts pattern.
        Default is None. It uses 'fgroup_smarts.yaml'

    Returns
    -------
    fgroup_tagged: dict
        a dictionary that maps indexed functional groups to corresponding atom and bond indices in mol

    """
    if not fgroups_smarts:
        # Load yaml file
        fn = resource_filename('fragmenter', os.path.join('data', 'fgroup_smarts.yml'))
        f = open(fn, 'r')
        fgroups_smarts = yaml.safe_load(f)
        f.close()

    fgroup_tagged = {}
    for f_group in fgroups_smarts:
        qmol = oechem.OEQMol()
        if not oechem.OEParseSmarts(qmol, fgroups_smarts[f_group]):
            print('OEParseSmarts failed')
        ss = oechem.OESubSearch(qmol)
        oechem.OEPrepareSearch(mol, ss)

        for i, match in enumerate(ss.Match(mol, True)):
            fgroup_atoms = set()
            for ma in match.GetAtoms():
                fgroup_atoms.add(ma.target.GetIdx())
                tag = oechem.OEGetTag('fgroup')
                ma.target.SetData(tag, '{}_{}'.format(f_group, str(i)))
            fgroup_bonds = set()
            for ma in match.GetBonds():
                #if not ma.target.IsInRing():
                fgroup_bonds.add(ma.target.GetIdx())
                tag =oechem.OEGetTag('fgroup')
                ma.target.SetData(tag, '{}_{}'.format(f_group, str(i)))

            fgroup_tagged['{}_{}'.format(f_group, str(i))] = (fgroup_atoms, fgroup_bonds)
    return fgroup_tagged
예제 #6
0
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
예제 #7
0
    def pack(cls, molecule, data):
        """ Encodes the ParmEd Structure or if provided the OpenMM Simulation object,
        this will extract the State and the log file from the state reporter and
        attach them to the OEMol as generic data. Returns the OEMol with attached data."""

        tag_data = {}
        # Attach (base64) encoded ParmEd Structure.
        if isinstance(data, parmed.structure.Structure):
            molecule.SetData(oechem.OEGetTag('Structure'),
                             cls.encodeStruct(data))

        # Attach the encoded OpenMM State and log file from the Simulation.
        if isinstance(data, openmm.app.simulation.Simulation):
            tag_data = cls.encodeSimData(data)
            for k, v in tag_data.items():
                molecule.SetData(oechem.OEGetTag(k), v)
        return molecule
예제 #8
0
def SetPartialCharge(mol, tagname, minvalue, maxvalue):
    oechem.OEMMFFAtomTypes(mol)
    oechem.OEMMFF94PartialCharges(mol)

    tag = oechem.OEGetTag(tagname)
    for atom in mol.GetAtoms():
        charge = atom.GetPartialCharge()
        atom.SetData(tag, charge)
        minvalue = min(minvalue, charge)
        maxvalue = max(maxvalue, charge)

    return minvalue, maxvalue
예제 #9
0
def DumpGroup(group):
    print("type \"%s\"" % oechem.OEGetTag(group.GetGroupType()), end=" ")
    if group.NumAtoms() > 0:
        print("atom indices:", end=" ")
        for atom in group.GetAtoms():
            print(atom.GetIdx(), end=" ")
        print()
    if group.NumBonds() > 0:
        print("bond indices:", end=" ")
        for bond in group.GetBonds():
            print(bond.GetIdx(), end=" ")
        print()
예제 #10
0
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
예제 #11
0
def _tag_rings(mol):
    """
    This function tags ring atom and bonds with ringsystem index

    Parameters
    ----------
    mol: OpenEye OEMolGraph

    Returns
    -------
    tagged_rings: dict
        maps ringsystem index to ring atom and bond indices

    """
    tagged_rings = {}
    nringsystems, parts = oechem.OEDetermineRingSystems(mol)
    for ringidx in range(1, nringsystems +1):
        ringidx_atoms = set()
        for atom in mol.GetAtoms():
            if parts[atom.GetIdx()] == ringidx:
                ringidx_atoms.add(atom.GetIdx())
                tag = oechem.OEGetTag('ringsystem')
                atom.SetData(tag, ringidx)
        # Find bonds in ring and tag
        ringidx_bonds = set()
        for a_idx in ringidx_atoms:
            atom = mol.GetAtom(oechem.OEHasAtomIdx(a_idx))
            for bond in atom.GetBonds():
                nbrAtom = bond.GetNbr(atom)
                nbrIdx = nbrAtom.GetIdx()
                if nbrIdx in ringidx_atoms and nbrIdx != a_idx:
                    ringidx_bonds.add(bond.GetIdx())
                    tag = oechem.OEGetTag('ringsystem')
                    bond.SetData(tag, ringidx)
        tagged_rings[ringidx] = (ringidx_atoms, ringidx_bonds)
    return tagged_rings
예제 #12
0
    def process(self, system, port):

        try:
            # Solvate the system
            sol_system = utils.hydrate(system, self.opt)
            sol_system.SetTitle(system.GetTitle())
            # Attached the original system to the solvated one
            if self.opt['ref_structure']:
                sol_system.SetData(oechem.OEGetTag("RefStructure"), system)
            self.success.emit(sol_system)
        except Exception as e:
            # Attach error message to the molecule that failed
            self.log.error(traceback.format_exc())
            system.SetData('error', str(e))
            # Return failed mol
            self.failure.emit(system)

        return
예제 #13
0
 def __init__(self, infileName, tagname):
     self.pattyTag = oechem.OEGetTag(tagname)
     self.smartsList = []
     ifs = open(infileName)
     lines = ifs.readlines()
     for line in lines:
         # Strip trailing comments
         index = line.find('%')
         if index != -1:
             line = line[0:index]
         # Split into tokens.
         toks = string.split(line)
         if len(toks) == 2:
             smarts, type = toks
             pat = oechem.OESubSearch()
             pat.Init(smarts)
             pat.SetMaxMatches(0)
             self.smartsList.append([pat, type, smarts])
def prep_mols_for_vis(wbo_dict, fgroup):
    # first sort wbo
    wbo_keys = sorted(list(wbo_dict.keys()))
    molecules = []
    bond_map_idx = [(4,5)]*len(wbo_keys)
    wbos = []
    for bo in wbo_keys:
        drop = False
        mol = oechem.OEMol(wbo_dict[bo][0])
        name = mol.GetTitle().split('_')
        if fgroup == name[-1]:
            map_idx = [1]
        elif fgroup == name[1]:
            map_idx = [2, 3]
        for bond in mol.GetBonds():
            a1 = bond.GetBgn()
            a2 = bond.GetEnd()
            m1 = a1.GetMapIdx()
            m2 = a2.GetMapIdx()
            if name[-1] == fgroup:
                to_check_ortho = [1, 4, 5]
            elif name[1] == fgroup:
                to_check_ortho = [2, 3, 4, 5]
            if (m1 in to_check_ortho or m2 in to_check_ortho) and bond.IsInRing():
                if a1.GetAtomicNum() == 7 or a2.GetAtomicNum() == 7:
                    # The N is ortho to the bond. drop out from list
                    drop = True
            if (m1 in map_idx or m2 in map_idx) and not bond.IsInRing():
                bond.GetBgn().SetMapIdx(4)
                bond.GetEnd().SetMapIdx(5)
                wbo = bond.GetData('WibergBondOrder')
            else:
                # Remove wbo so that only R1 WBO is generated in visualization
                to_delete = bond.GetData('WibergBondOrder')
                tag = oechem.OEGetTag('WibergBondOrder')
                bond.DeleteData(tag)
        if not drop:
            molecules.append(mol)
            wbos.append(wbo)
    return molecules, bond_map_idx, wbos
예제 #15
0
def tag_conjugated_bond(mol, tautomers=None, tag=None, threshold=1.05):
    """
    Add conjugated bond data tag. If the bond order is above the threshold, this tag will be True, otherwise it will be
    False
    Parameters
    ----------
    mol: OEMol
    tautomers: list of OEMols, optional, Default None
        If a list is provided, the conjugation tag will be true if the bond in any of the set of molecules is double.
        The list should consist of resonance structures of the molecules. You can get that from oequacpac.EnumerateTautomres
    tag: str, optional, Default None
        If provided, will use that bond order. Options are WibergBondOrder, Wiberg_psi4, Mayer_psi4
    threshold: int, optional, Default is 1.05
        The fractional bond order threshold above which the bond will be considered conjugated.

    Returns
    -------
    atom_indices: list of atom indices in conjugated bonds.

    """
    atom_indices = []
    for bond in mol.GetBonds():
        resonance = False
        if tautomers is not None:
            for tmol in tautomers:
                t_bond = tmol.GetBond(oechem.OEHasBondIdx(bond.GetIdx()))
                if t_bond.GetOrder() > 1:
                    resonance = True
                    break
        elif bond.GetData()[tag] >= threshold:
            resonance = True
        # Add tag to bond
        conj_tag = oechem.OEGetTag("conjugated")
        bond.SetData(conj_tag, resonance)
        if resonance:
            a1 = bond.GetBgnIdx()
            a2 = bond.GetEndIdx()
            atom_indices.extend([a1, a2])
    return atom_indices
예제 #16
0
    def test_failure(self):
        print('Testing cube:', self.cube.name)
        # Read a molecule
        mol = oechem.OEMol()
        ifs = oechem.oemolistream(
            get_data_filename('uranium-hexafluoride.sdf'))

        # Test a single molecule
        if not oechem.OEReadMolecule(ifs, mol):
            raise Exception('Cannot read molecule')
        ifs.close()

        # Process the molecules
        self.cube.process(mol, self.cube.intake.name)
        # Assert that one molecule was emitted on the success port
        self.assertEqual(self.runner.outputs['success'].qsize(), 0)
        # Assert that zero molecules were emitted on the failure port
        self.assertEqual(self.runner.outputs['failure'].qsize(), 1)

        outmol = self.runner.outputs["failure"].get()
        # Check that the number of atoms in input and output molecules match.
        self.assertEqual(outmol.NumAtoms(), mol.NumAtoms())
        # Check that an error message has been attached
        self.assertTrue(outmol.HasData(oechem.OEGetTag('error')))
예제 #17
0
    def __iter__(self):
        max_idx = self.args.limit
        if max_idx is not None:
            max_idx = int(max_idx)
        count = 0
        self.config = config_from_env()
        in_orion = self.config is not None
        if not in_orion:
            with oechem.oemolistream(str(self.args.data_in)) as ifs:
                for mol in ifs.GetOEMols():
                    mol.SetData(oechem.OEGetTag('prefix'), self.opt['prefix'])
                    mol.SetData(oechem.OEGetTag('suffix'), self.opt['suffix'])

                    for at in mol.GetAtoms():
                        residue = oechem.OEAtomGetResidue(at)
                        residue.SetName(self.opt['type'])
                        oechem.OEAtomSetResidue(at, residue)

                    if self.opt['IDTag']:
                        mol.SetData(oechem.OEGetTag('IDTag'), 'l' + mol.GetTitle()[0:12] + '_' + str(count))
                    yield mol
                    count += 1
                    if max_idx is not None and count == max_idx:
                        break
        else:
            stream = StreamingDataset(self.args.data_in,
                                      input_format=self.args.download_format)
            for mol in stream:
                mol.SetData(oechem.OEGetTag('prefix'), self.opt['prefix'])
                mol.SetData(oechem.OEGetTag('suffix'), self.opt['suffix'])

                for at in mol.GetAtoms():
                    residue = oechem.OEAtomGetResidue(at)
                    residue.SetName(self.opt['type'])
                    oechem.OEAtomSetResidue(at, residue)

                if self.opt['IDTag']:
                    mol.SetData(oechem.OEGetTag('IDTag'), 'l' + mol.GetTitle()[0:12] + '_'+str(count))
                yield mol
                count += 1
                if max_idx is not None and count == max_idx:
                    break
예제 #18
0
def DepictMoleculeWithFragmentCombinations(report, mol, frags, opts): #fragcombs, opts):
    """ This function was taken from https://docs.eyesopen.com/toolkits/cookbook/python/depiction/enumfrags.html with some modification
    """
    stag = "fragment idx"
    itag = oechem.OEGetTag(stag)
    for fidx, frag in enumerate(frags):
        for bond in frags[frag].GetBonds():
            bond.SetData(itag, fidx)

    # setup depiction styles

    nrfrags = len(frags)
    colors = [c for c in oechem.OEGetLightColors()]
    if len(colors) < nrfrags:
        colors = [c for c in oechem.OEGetColors(oechem.OEYellowTint, oechem.OEDarkOrange, nrfrags)]

    bondglyph = ColorBondByFragmentIndex(colors, itag)

    lineWidthScale = 0.75
    fadehighlight = oedepict.OEHighlightByColor(oechem.OEGrey, lineWidthScale)

    # depict each fragment combinations

    for frag in frags:

        cell = report.NewCell()
        disp = oedepict.OE2DMolDisplay(mol, opts)

        fragatoms = oechem.OEIsAtomMember(frags[frag].GetAtoms())
        fragbonds = oechem.OEIsBondMember(frags[frag].GetBonds())

        notfragatoms = oechem.OENotAtom(fragatoms)
        notfragbonds = oechem.OENotBond(fragbonds)

        oedepict.OEAddHighlighting(disp, fadehighlight, notfragatoms, notfragbonds)

        bond = mol.GetBond(oechem.OEHasBondIdx(frag))

        atomBondSet = oechem.OEAtomBondSet()
        atomBondSet.AddBond(bond)
        atomBondSet.AddAtom(bond.GetBgn())
        atomBondSet.AddAtom(bond.GetEnd())

        hstyle = oedepict.OEHighlightStyle_BallAndStick
        hcolor = oechem.OEColor(oechem.OELightBlue)
        oedepict.OEAddHighlighting(disp, hcolor, hstyle, atomBondSet)

        #oegrapheme.OEAddGlyph(disp, bondglyph, fragbonds)

        oedepict.OERenderMolecule(cell, disp)

    # depict original fragmentation in each header

    cellwidth, cellheight = report.GetHeaderWidth(), report.GetHeaderHeight()
    opts.SetDimensions(cellwidth, cellheight, oedepict.OEScale_AutoScale)
    opts.SetAtomColorStyle(oedepict.OEAtomColorStyle_WhiteMonochrome)

    bondlabel = LabelBondOrder()
    opts.SetBondPropertyFunctor(bondlabel)
    disp = oedepict.OE2DMolDisplay(mol, opts)
    #oegrapheme.OEAddGlyph(disp, bondglyph, oechem.IsTrueBond())

    headerpen = oedepict.OEPen(oechem.OEWhite, oechem.OELightGrey, oedepict.OEFill_Off, 2.0)
    for header in report.GetHeaders():
        oedepict.OERenderMolecule(header, disp)
        oedepict.OEDrawBorder(header, headerpen)
예제 #19
0
def _file_processing(**opt):
    """
    This supporting function compresses the produced trajectory
    and supporting files in a .tar file (if required ) and eventually
    uploaded them to Orion. If not .tar file is selected then all the
    generated files are eventually uploaded in Orion

    Parameters
    ----------
    opt: python dictionary
        A dictionary containing all the MD setting info
    """

    # Set the trajectory file name
    if opt['trajectory_filetype'] == 'NetCDF':
        trj_fn = opt['outfname'] +'.nc'
    elif opt['trajectory_filetype'] == 'DCD':
        trj_fn = opt['outfname'] +'.dcd'
    elif opt['trajectory_filetype'] == 'HDF5':
        trj_fn = opt['outfname'] + '.hdf5'
    else:
        oechem.OEThrow.Fatal("The selected trajectory filetype is not supported: {}"
                             .format(opt['trajectory_filetype']))
    # Set .pdb file names
    pdb_fn = opt['outfname'] + '.pdb'
    pdb_order_fn = opt['outfname'] + '_ordering_test' + '.pdb'
    log_fn = opt['outfname'] + '.log'

    # List all the file names
    fnames = [trj_fn, pdb_fn, pdb_order_fn, log_fn]

    ex_files = []

    # Check which file names are actually produced files
    for fn in fnames:
        if os.path.isfile(fn):
            ex_files.append(fn)

    # Tar the outputted files if required
    if opt['tar']:

        tarname = opt['outfname'] + '.tar'

        opt['Logger'].info('Creating tar file: {}'.format(tarname))

        tar = tarfile.open(tarname, "w")

        for name in ex_files:
            opt['Logger'].info('Adding {} to {}'.format(name, tarname))
            tar.add(name)
        tar.close()

        opt['molecule'].SetData(oechem.OEGetTag("Tar_fname"), tarname)

        if in_orion():
            upload_file(tarname, tarname, tags=['TRJ_INFO'])

        # Clean up files that have been added to tar.
        for tmp in ex_files:
            try:
                os.remove(tmp)
            except:
                pass
    else:  # If not .tar file is required the files are eventually uploaded in Orion
        if in_orion():
            for fn in ex_files:
                upload_file(fn, fn, tags=['TRJ_INFO'])

    return
예제 #20
0
    def process(self, mol, port):
        try:
            # Split the complex in components in order to apply the FF
            protein, ligand, water, excipients = utils.split(mol)

            # Unique prefix name used to output parametrization files
            self.opt['prefix_name'] = mol.GetTitle()

            # Apply FF to the Protein
            protein_structure = utils.applyffProtein(protein, self.opt)

            # Apply FF to water molecules
            water_structure = utils.applyffWater(water, self.opt)

            # Apply FF to the excipients
            if excipients.NumAtoms() > 0:
                excipient_structure = utils.applyffExcipients(excipients, self.opt)

                # The excipient order is set equal to the order in related
                # parmed structure to avoid possible atom index mismatching
                excipients = oeommutils.openmmTop_to_oemol(excipient_structure.topology,
                                                           excipient_structure.positions,
                                                           verbose=False)

            # Apply FF to the ligand
            ligand_structure = utils.applyffLigand(ligand, self.opt)

            # Build the Parmed structure
            if excipients.NumAtoms() > 0:
                complex_structure = protein_structure + ligand_structure + \
                                    excipient_structure + water_structure
            else:
                complex_structure = protein_structure + ligand_structure + water_structure

            num_atom_system = protein.NumAtoms() + ligand.NumAtoms() + excipients.NumAtoms() + water.NumAtoms()

            if not num_atom_system == complex_structure.topology.getNumAtoms():
                oechem.OEThrow.Fatal("Parmed and OE topologies mismatch atom number error")

            # Assemble a new OEMol complex in a specific order
            # to match the defined Parmed structure complex
            complx = protein.CreateCopy()
            oechem.OEAddMols(complx, ligand)
            oechem.OEAddMols(complx, excipients)
            oechem.OEAddMols(complx, water)

            complx.SetTitle(mol.GetTitle())

            # Set Parmed structure box_vectors
            vec_data = pack_utils.PackageOEMol.getData(complx, tag='box_vectors')
            vec = pack_utils.PackageOEMol.decodePyObj(vec_data)
            complex_structure.box_vectors = vec

            # Attach the Parmed structure to the complex
            packed_complex = pack_utils.PackageOEMol.pack(complx, complex_structure)

            # Attach the reference positions to the complex
            ref_positions = complex_structure.positions
            packedpos = pack_utils.PackageOEMol.encodePyObj(ref_positions)
            packed_complex.SetData(oechem.OEGetTag('OEMDDataRefPositions'), packedpos)

            # Set atom serial numbers, Ligand name and HETATM flag
            # oechem.OEPerceiveResidues(packed_complex, oechem.OEPreserveResInfo_SerialNumber)
            for at in packed_complex.GetAtoms():
                thisRes = oechem.OEAtomGetResidue(at)
                thisRes.SetSerialNumber(at.GetIdx())
                if thisRes.GetName() == 'UNL':
                    thisRes.SetName("LIG")
                    thisRes.SetHetAtom(True)
                oechem.OEAtomSetResidue(at, thisRes)

            if packed_complex.GetMaxAtomIdx() != complex_structure.topology.getNumAtoms():
                raise ValueError("OEMol complex and Parmed structure mismatch atom numbers")

            # Check if it is possible to create the OpenMM System
            system = complex_structure.createSystem(nonbondedMethod=app.CutoffPeriodic,
                                                    nonbondedCutoff=10.0 * unit.angstroms,
                                                    constraints=app.HBonds,
                                                    removeCMMotion=False)

            self.success.emit(packed_complex)
        except Exception as e:
            # Attach error message to the molecule that failed
            self.log.error(traceback.format_exc())
            mol.SetData('error', str(e))
            # Return failed mol
            self.failure.emit(mol)

        return
예제 #21
0
def main(argv=[__name__]):
    """
    itf = oechem.OEInterface()
    oechem.OEConfigure(itf, InterfaceData)
    if not oechem.OEParseCommandLine(itf, argv):
        return 1

    oname = itf.GetString("-out")
    iname = itf.GetString("-in")

    ext = oechem.OEGetFileExtension(oname)
    if not oedepict.OEIsRegisteredImageFile(ext):
        oechem.OEThrow.Fatal("Unknown image type!")

    ofs = oechem.oeofstream()
    if not ofs.open(oname):
        oechem.OEThrow.Fatal("Cannot open output file!")

  
    ## INPUT PARAMETERS
    #########################################################
    #########################################################
    
    mm = 'tyk2/og_pdbs'
    qml = 'tyk2/forward_snapshots'
    phase = 'solvent'
    which_ligand = 'old'
    dir_name = iname
    ligand_pdbs_mm = glob.glob(f"{mm}/{dir_name}/{which_ligand}*{phase}.pdb")
    print(len(ligand_pdbs_mm))
    ligand_pdbs_qml = glob.glob(f"{qml}/{dir_name}/{which_ligand}*{phase}.pdb")
    print(len(ligand_pdbs_qml))

    #d = np.load('full_data_dict.npy', allow_pickle=True)
    from_ligand, to_ligand = iname.replace('from', '').replace('to', '').replace('lig', '')
    print(from_ligand)
    print(to_ligand)
    #key1 = (1, 8)
    #key2 = ('solvent', which_ligand)
    #########################################################
    #########################################################

    #d = d.flatten()[0]
    #work = d[key1][key2]
    #print(work)

    
    for i, (mm_pdb_path, ani_pdb_path) in enumerate(zip(ligand_pdbs_mm, ligand_pdbs_qml)):
        print(mm_pdb_path, ani_pdb_path)
        if i == 0:
            MM_mol = createOEMolFromSDF(mm_pdb_path, 0)
            ANI_mol = createOEMolFromSDF(ani_pdb_path, 0)
        else:
            # there absolutely must be a better/faster way of doing this because this is ugly and slow
            MM_mol.NewConf(createOEMolFromSDF(mm_pdb_path, 0))
            ANI_mol.NewConf(createOEMolFromSDF(ani_pdb_path, 0))
"""
    ofs = oechem.oeofstream()
    oname = f"tor_out"
    ext = oechem.OEGetFileExtension(oname)

    mm_pdb_path = f"og_lig0_solvent.pdb"
    ani_pdb_path = f"forward_lig0.solvent.pdb"
    MM_mol = createOEMolFromSDF(mm_pdb_path, 0)
    ANI_mol = createOEMolFromSDF(ani_pdb_path, 0)

    mol = MM_mol
    mol2 = ANI_mol

    for m in [mol, mol2]:
        oechem.OESuppressHydrogens(m)
        oechem.OECanonicalOrderAtoms(m)
        oechem.OECanonicalOrderBonds(m)
        m.Sweep()

    refmol = None

    stag = "dihedral_histogram"
    itag = oechem.OEGetTag(stag)

    nrbins = 20

    print(mol.NumConfs())
    print(mol2.NumConfs())

    get_dihedrals(mol, itag)
    set_dihedral_histograms(mol, itag, nrbins)

    get_dihedrals(mol2, itag)
    #set_weighted_dihedral_histograms(mol2, itag, work, nrbins)
    set_dihedral_histograms(mol2, itag, nrbins)

    width, height = 800, 400
    image = oedepict.OEImage(width, height)

    moffset = oedepict.OE2DPoint(0, 0)
    mframe = oedepict.OEImageFrame(image, width * 0.70, height, moffset)
    doffset = oedepict.OE2DPoint(mframe.GetWidth(), height * 0.30)
    dframe = oedepict.OEImageFrame(image, width * 0.30, height * 0.5, doffset)

    flexibility = True
    colorg = get_color_gradient(nrbins, flexibility)

    opts = oedepict.OE2DMolDisplayOptions(mframe.GetWidth(),
                                          mframe.GetHeight(),
                                          oedepict.OEScale_AutoScale)

    depict_dihedrals(mframe, dframe, mol, mol2, refmol, opts, itag, nrbins,
                     colorg)

    if flexibility:
        lopts = oedepict.OELegendLayoutOptions(
            oedepict.OELegendLayoutStyle_HorizontalTopLeft,
            oedepict.OELegendColorStyle_LightBlue,
            oedepict.OELegendInteractiveStyle_Hover)
        lopts.SetButtonWidthScale(1.2)
        lopts.SetButtonHeightScale(1.2)
        lopts.SetMargin(oedepict.OEMargin_Right, 40.0)
        lopts.SetMargin(oedepict.OEMargin_Bottom, 80.0)

        legend = oedepict.OELegendLayout(image, "Legend", lopts)

        legend_area = legend.GetLegendArea()
        draw_color_gradient(legend_area, colorg)

        oedepict.OEDrawLegendLayout(legend)

    iconscale = 0.5
    oedepict.OEAddInteractiveIcon(image, oedepict.OEIconLocation_TopRight,
                                  iconscale)
    oedepict.OEDrawCurvedBorder(image, oedepict.OELightGreyPen, 10.0)

    oedepict.OEWriteImage(ofs, ext, image)

    return 0
예제 #22
0
def hydrate(system, opt):
    """
    This function solvates the system by using PDBFixer

    Parameters:
    -----------
    system: OEMol molecule
        The system to solvate
    opt: python dictionary
        The parameters used to solvate the system

    Return:
    -------
    oe_mol: OEMol
        The solvated system
    """
    def BoundingBox(molecule):
        """
        This function calculates the Bounding Box of the passed
        molecule

        molecule: OEMol

        return: bb (numpy array)
            the calculated bounding box is returned as numpy array:
            [(xmin,ymin,zmin), (xmax,ymax,zmax)]
        """
        coords = [v for k, v in molecule.GetCoords().items()]
        np_coords = np.array(coords)
        min_coord = np_coords.min(axis=0)
        max_coord = np_coords.max(axis=0)
        bb = np.array([min_coord, max_coord])
        return bb

    # Create a system copy
    sol_system = system.CreateCopy()

    # Calculate system BoundingBox (Angstrom units)
    BB = BoundingBox(sol_system)

    # Estimation of the box cube length in A
    box_edge = 2.0 * opt['solvent_padding'] + np.max(BB[1] - BB[0])

    # BB center
    xc = (BB[0][0]+BB[1][0])/2.
    yc = (BB[0][1]+BB[1][1])/2.
    zc = (BB[0][2]+BB[1][2])/2.

    delta = np.array([box_edge/2., box_edge/2., box_edge/2.]) - np.array([xc, yc, zc])

    sys_coord_dic = {k: (v+delta) for k, v in sol_system.GetCoords().items()}

    sol_system.SetCoords(sys_coord_dic)

    # Load a fake system to initialize PDBfixer
    filename = resource_filename('pdbfixer', 'tests/data/test.pdb')
    fixer = PDBFixer(filename=filename)

    # Convert between OE and OpenMM topology
    omm_top, omm_pos = oeommutils.oemol_to_openmmTop(sol_system)

    chain_names = []

    for chain in omm_top.chains():
        chain_names.append(chain.id)

    # Set the correct topology to the fake system
    fixer.topology = omm_top
    fixer.positions = omm_pos

    # Solvate the system
    fixer.addSolvent(padding=unit.Quantity(opt['solvent_padding'], unit.angstroms),
                     ionicStrength=unit.Quantity(opt['salt_concentration'], unit.millimolar))

    # The OpenMM topology produced by the solvation fixer has missing bond
    # orders and aromaticity. The following section is creating a new openmm
    # topology made of just water molecules and ions. The new topology is then
    # converted in an OEMol and added to the passed molecule to produce the
    # solvated system

    wat_ion_top = app.Topology()

    # Atom dictionary between the the PDBfixer topology and the water_ion topology
    fixer_atom_to_wat_ion_atom = {}

    for chain in fixer.topology.chains():
        if chain.id not in chain_names:
            n_chain = wat_ion_top.addChain(chain.id)
            for res in chain.residues():
                n_res = wat_ion_top.addResidue(res.name, n_chain)
                for at in res.atoms():
                    n_at = wat_ion_top.addAtom(at.name, at.element, n_res)
                    fixer_atom_to_wat_ion_atom[at] = n_at

    for bond in fixer.topology.bonds():
        at0 = bond[0]
        at1 = bond[1]
        try:
            wat_ion_top.addBond(fixer_atom_to_wat_ion_atom[at0],
                                fixer_atom_to_wat_ion_atom[at1], type=None, order=1)
        except:
            pass

    wat_ion_pos = fixer.positions[len(omm_pos):]

    oe_mol = oeommutils.openmmTop_to_oemol(wat_ion_top, wat_ion_pos)

    # Setting the box vectors
    omm_box_vectors = fixer.topology.getPeriodicBoxVectors()
    box_vectors = utils.PackageOEMol.encodePyObj(omm_box_vectors)
    oe_mol.SetData(oechem.OEGetTag('box_vectors'), box_vectors)

    oechem.OEAddMols(oe_mol, sol_system)

    return oe_mol
예제 #23
0
    def process(self, mol, port):
        try:
            if port == 'system_port':
                self.system = mol
                self.check_system = True
                return

            if self.check_system:
                num_conf = 0
                name = 'p' + self.system.GetTitle() + '_l' + mol.GetTitle()[0:12] + '_' + str(self.count)
                for conf in mol.GetConfs():
                    conf_mol = oechem.OEMol(conf)
                    complx = self.system.CreateCopy()
                    oechem.OEAddMols(complx, conf_mol)

                    # Split the complex in components
                    protein, ligand, water, excipients = utils.split(complx)

                    # If the protein does not contain any atom emit a failure
                    if not protein.NumAtoms():  # Error: protein molecule is empty
                        oechem.OEThrow.Fatal("The protein molecule does not contains atoms")

                    # If the ligand does not contain any atom emit a failure
                    if not ligand.NumAtoms():  # Error: ligand molecule is empty
                        oechem.OEThrow.Fatal("The Ligand molecule does not contains atoms")

                    # If the water does not contain any atom emit a failure
                    if not water.NumAtoms():  # Error: water molecule is empty
                        oechem.OEThrow.Fatal("The water does not contains atoms. This could happen if not"
                                             "solvation process has occurred")

                    # Check if the ligand is inside the binding site. Cutoff distance 3A
                    if not oeommutils.check_shell(ligand, protein, 3):
                        oechem.OEThrow.Fatal("The ligand is probably outside the protein binding site")

                    # Removing possible clashes between the ligand and water or excipients
                    water_del = oeommutils.delete_shell(ligand, water, 1.5, in_out='in')
                    excipient_del = oeommutils.delete_shell(ligand, excipients, 1.5, in_out='in')

                    # Reassemble the complex
                    new_complex = protein.CreateCopy()
                    oechem.OEAddMols(new_complex, ligand)
                    oechem.OEAddMols(new_complex, excipient_del)
                    oechem.OEAddMols(new_complex, water_del)

                    name_c = name
                    if mol.GetMaxConfIdx() > 1:
                        name_c = name + '_c' + str(num_conf)
                    new_complex.SetData(oechem.OEGetTag('IDTag'), name_c)
                    new_complex.SetTitle(name_c)
                    num_conf += 1
                    self.success.emit(new_complex)
                self.count += 1

        except Exception as e:
            # Attach error message to the molecule that failed
            self.log.error(traceback.format_exc())
            mol.SetData('error', str(e))
            # Return failed mol
            self.failure.emit(mol)

        return
예제 #24
0
def main(argv=[__name__]):

    itf = oechem.OEInterface()
    oechem.OEConfigure(itf, InterfaceData)
    oedepict.OEConfigureImageWidth(itf, 600.0)
    oedepict.OEConfigureImageHeight(itf, 600.0)
    oedepict.OEConfigure2DMolDisplayOptions(itf, oedepict.OE2DMolDisplaySetup_AromaticStyle)
    oechem.OEConfigureSplitMolComplexOptions(itf, oechem.OESplitMolComplexSetup_LigName)

    if not oechem.OEParseCommandLine(itf, argv):
        return 1

    iname = itf.GetString("-complex")
    oname = itf.GetString("-out")

    ifs = oechem.oemolistream()
    if not ifs.open(iname):
        oechem.OEThrow.Fatal("Cannot open input file!")

    ext = oechem.OEGetFileExtension(oname)
    if not oedepict.OEIsRegisteredImageFile(ext):
        oechem.OEThrow.Fatal("Unknown image type!")

    ofs = oechem.oeofstream()
    if not ofs.open(oname):
        oechem.OEThrow.Fatal("Cannot open output file!")

    complexmol = oechem.OEGraphMol()
    if not oechem.OEReadMolecule(ifs, complexmol):
        oechem.OEThrow.Fatal("Unable to read molecule from %s" % iname)

    if not oechem.OEHasResidues(complexmol):
        oechem.OEPerceiveResidues(complexmol, oechem.OEPreserveResInfo_All)

    # Separate ligand and protein

    sopts = oechem.OESplitMolComplexOptions()
    oechem.OESetupSplitMolComplexOptions(sopts, itf)

    ligand = oechem.OEGraphMol()
    protein = oechem.OEGraphMol()
    water = oechem.OEGraphMol()
    other = oechem.OEGraphMol()

    oechem.OESplitMolComplex(ligand, protein, water, other, complexmol, sopts)

    if ligand.NumAtoms() == 0:
        oechem.OEThrow.Fatal("Cannot separate complex!")

    # Calculate average BFactor of the whole complex

    avgbfactor = GetAverageBFactor(complexmol)

    # Calculate minimum and maximum BFactor of the ligand and its environment

    minbfactor, maxbfactor = GetMinAndMaxBFactor(ligand, protein)

    # Attach to each ligand atom the average BFactor of the nearby protein atoms

    stag = "avg residue BFfactor"
    itag = oechem.OEGetTag(stag)
    SetAverageBFactorOfNearbyProteinAtoms(ligand, protein, itag)

    oechem.OEThrow.Info("Average BFactor of the complex = %+.3f" % avgbfactor)
    oechem.OEThrow.Info("Minimum BFactor of the ligand and its environment = %+.3f" % minbfactor)
    oechem.OEThrow.Info("Maximum BFactor of the ligand and its environment = %+.3f" % maxbfactor)

    # Create image

    imagewidth, imageheight = oedepict.OEGetImageWidth(itf), oedepict.OEGetImageHeight(itf)
    image = oedepict.OEImage(imagewidth, imageheight)

    mframe = oedepict.OEImageFrame(image, imagewidth,
                                   imageheight * 0.90, oedepict.OE2DPoint(0.0, 0.0))
    lframe = oedepict.OEImageFrame(image, imagewidth, imageheight * 0.10,
                                   oedepict.OE2DPoint(0.0, imageheight * 0.90))

    opts = oedepict.OE2DMolDisplayOptions(mframe.GetWidth(), mframe.GetHeight(),
                                          oedepict.OEScale_AutoScale)
    oedepict.OESetup2DMolDisplayOptions(opts, itf)
    opts.SetAtomColorStyle(oedepict.OEAtomColorStyle_WhiteMonochrome)

    # Create BFactor color gradient

    colorg = oechem.OELinearColorGradient()
    colorg.AddStop(oechem.OEColorStop(0.0, oechem.OEDarkBlue))
    colorg.AddStop(oechem.OEColorStop(10.0, oechem.OELightBlue))
    colorg.AddStop(oechem.OEColorStop(25.0, oechem.OEYellowTint))
    colorg.AddStop(oechem.OEColorStop(50.0, oechem.OERed))
    colorg.AddStop(oechem.OEColorStop(100.0, oechem.OEDarkRose))

    # Prepare ligand for depiction

    oegrapheme.OEPrepareDepictionFrom3D(ligand)
    arcfxn = BFactorArcFxn(colorg, itag)
    for atom in ligand.GetAtoms():
        oegrapheme.OESetSurfaceArcFxn(ligand, atom, arcfxn)
    opts.SetScale(oegrapheme.OEGetMoleculeSurfaceScale(ligand, opts))

    # Render ligand and visualize BFactor

    disp = oedepict.OE2DMolDisplay(ligand, opts)
    colorbfactor = ColorLigandAtomByBFactor(colorg)
    oegrapheme.OEAddGlyph(disp, colorbfactor, oechem.OEIsTrueAtom())
    oegrapheme.OEDraw2DSurface(disp)
    oedepict.OERenderMolecule(mframe, disp)

    # Draw color gradient

    opts = oegrapheme.OEColorGradientDisplayOptions()
    opts.SetColorStopPrecision(1)
    opts.AddMarkedValue(avgbfactor)
    opts.SetBoxRange(minbfactor, maxbfactor)

    oegrapheme.OEDrawColorGradient(lframe, colorg, opts)

    oedepict.OEWriteImage(oname, image)

    return 0
예제 #25
0
    def process(self, mol, port):
        try:

            # Split the complex in components in order to apply the FF
            protein, ligand, water, excipients = oeommutils.split(
                mol, ligand_res_name=self.opt['ligand_res_name'])

            self.log.info(
                "\nComplex name: {}\nProtein atom numbers = {}\nLigand atom numbers = {}\n"
                "Water atom numbers = {}\nExcipients atom numbers = {}".format(
                    mol.GetTitle(), protein.NumAtoms(), ligand.NumAtoms(),
                    water.NumAtoms(), excipients.NumAtoms()))

            # Unique prefix name used to output parametrization files
            self.opt['prefix_name'] = mol.GetTitle()

            oe_mol_list = []
            par_mol_list = []

            # Apply FF to the Protein
            if protein.NumAtoms():
                oe_mol_list.append(protein)
                protein_structure = utils.applyffProtein(protein, self.opt)
                par_mol_list.append(protein_structure)

            # Apply FF to the ligand
            if ligand.NumAtoms():
                oe_mol_list.append(ligand)
                ligand_structure = utils.applyffLigand(ligand, self.opt)
                par_mol_list.append(ligand_structure)

            # Apply FF to water molecules
            if water.NumAtoms():
                oe_mol_list.append(water)
                water_structure = utils.applyffWater(water, self.opt)
                par_mol_list.append(water_structure)

            # Apply FF to the excipients
            if excipients.NumAtoms():
                excipient_structure = utils.applyffExcipients(
                    excipients, self.opt)
                par_mol_list.append(excipient_structure)

                # The excipient order is set equal to the order in related
                # parmed structure to avoid possible atom index mismatching
                excipients = oeommutils.openmmTop_to_oemol(
                    excipient_structure.topology,
                    excipient_structure.positions,
                    verbose=False)
                oechem.OEPerceiveBondOrders(excipients)
                oe_mol_list.append(excipients)

            # Build the overall Parmed structure
            complex_structure = parmed.Structure()

            for struc in par_mol_list:
                complex_structure = complex_structure + struc

            complx = oe_mol_list[0].CreateCopy()
            num_atom_system = complx.NumAtoms()

            for idx in range(1, len(oe_mol_list)):
                oechem.OEAddMols(complx, oe_mol_list[idx])
                num_atom_system += oe_mol_list[idx].NumAtoms()

            if not num_atom_system == complex_structure.topology.getNumAtoms():
                oechem.OEThrow.Fatal(
                    "Parmed and OE topologies mismatch atom number error")

            complx.SetTitle(mol.GetTitle())

            # Set Parmed structure box_vectors
            is_periodic = True
            try:
                vec_data = pack_utils.PackageOEMol.getData(complx,
                                                           tag='box_vectors')
                vec = pack_utils.PackageOEMol.decodePyObj(vec_data)
                complex_structure.box_vectors = vec
            except:
                is_periodic = False
                self.log.warn(
                    "System has been parametrize without periodic box vectors for vacuum simulation"
                )

            # Attach the Parmed structure to the complex
            packed_complex = pack_utils.PackageOEMol.pack(
                complx, complex_structure)

            # Attach the reference positions to the complex
            ref_positions = complex_structure.positions
            packedpos = pack_utils.PackageOEMol.encodePyObj(ref_positions)
            packed_complex.SetData(oechem.OEGetTag('OEMDDataRefPositions'),
                                   packedpos)

            # Set atom serial numbers, Ligand name and HETATM flag
            # oechem.OEPerceiveResidues(packed_complex, oechem.OEPreserveResInfo_SerialNumber)
            for at in packed_complex.GetAtoms():
                thisRes = oechem.OEAtomGetResidue(at)
                thisRes.SetSerialNumber(at.GetIdx())
                if thisRes.GetName() == 'UNL':
                    # thisRes.SetName("LIG")
                    thisRes.SetHetAtom(True)
                oechem.OEAtomSetResidue(at, thisRes)

            if packed_complex.GetMaxAtomIdx(
            ) != complex_structure.topology.getNumAtoms():
                raise ValueError(
                    "OEMol complex and Parmed structure mismatch atom numbers")

            # Check if it is possible to create the OpenMM System
            if is_periodic:
                complex_structure.createSystem(
                    nonbondedMethod=app.CutoffPeriodic,
                    nonbondedCutoff=10.0 * unit.angstroms,
                    constraints=app.HBonds,
                    removeCMMotion=False)
            else:
                complex_structure.createSystem(nonbondedMethod=app.NoCutoff,
                                               constraints=app.HBonds,
                                               removeCMMotion=False)

            self.success.emit(packed_complex)
        except Exception as e:
            # Attach error message to the molecule that failed
            self.log.error(traceback.format_exc())
            mol.SetData('error', str(e))
            # Return failed mol
            self.failure.emit(mol)

        return
예제 #26
0
 def getData(molecule, tag):
     return molecule.GetData(oechem.OEGetTag(str(tag)))
예제 #27
0
def getReporters(totalSteps=None, outfname=None, **opt):
    """
    Creates 3 OpenMM Reporters for the simulation.

    Parameters
    ----------
    totalSteps : int
        The total number of simulation steps
    reportInterval : (opt), int, default=1000
        Step frequency to write to reporter file.
    outfname : str
        Specifies the filename prefix for the reporters.

    Returns
    -------
    reporters : list of three openmm.app.simulation.reporters
        (0) state_reporter: writes energies to '.log' file.
        (1) progress_reporter: prints simulation progress to 'sys.stdout'
        (2) traj_reporter: writes trajectory to file. Supported format .nc, .dcd, .hdf5
    """
    if totalSteps is None:
        totalSteps = opt['steps']
    if outfname is None:
        outfname = opt['outfname']

    reporters = []

    if opt['reporter_interval']:
        state_reporter = app.StateDataReporter(outfname+'.log', separator="\t",
                                               reportInterval=opt['reporter_interval'],
                                               step=True,
                                               potentialEnergy=True, totalEnergy=True,
                                               volume=True, density=True, temperature=True)

        reporters.append(state_reporter)

        progress_reporter = app.StateDataReporter(stdout, separator="\t",
                                                  reportInterval=opt['reporter_interval'],
                                                  step=True, totalSteps=totalSteps,
                                                  time=True, speed=True, progress=True,
                                                  elapsedTime=True, remainingTime=True)

        reporters.append(progress_reporter)

    if opt['trajectory_interval']:

        trj_fname = outfname
        # Trajectory file format selection
        if opt['trajectory_filetype'] == 'NetCDF':
            trj_fname += '.nc'
            traj_reporter = mdtraj.reporters.NetCDFReporter(trj_fname, opt['trajectory_interval'])
        elif opt['trajectory_filetype'] == 'DCD':
            trj_fname += '.dcd'
            traj_reporter = app.DCDReporter(trj_fname, opt['trajectory_interval'])
        elif opt['trajectory_filetype'] == 'HDF5':
            trj_fname += '.hdf5'
            mdtraj.reporters.HDF5Reporter(trj_fname, opt['trajectory_interval'])
        else:
            oechem.OEThrow.Fatal("The selected trajectory file format is not supported: {}"
                                 .format(opt['trajectory_filetype']))

        opt['molecule'].SetData(oechem.OEGetTag("Trj_fname"), trj_fname)

        reporters.append(traj_reporter)

    return reporters
# (C) 2017 OpenEye Scientific Software Inc. All rights reserved.
#
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of OpenEye products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable OpenEye offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.

# @ <SNIPPET>
from openeye import oechem

mol = oechem.OEGraphMol()
oechem.OESmilesToMol(mol, "C1CCCC(C(=O)O)C1")

# @ <SNIPPET-TYPE-MISMATCH>
tag = oechem.OEGetTag("MolWeight")
weight = oechem.OECalculateMolecularWeight(mol)
mol.SetData(tag, float(weight))
mol.SetData(tag, int(weight))
# @ </SNIPPET-TYPE-MISMATCH>
# @ </SNIPPET>
예제 #29
0
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.

from __future__ import print_function
from openeye import oechem

qmol = oechem.OEGraphMol()
oechem.OESmilesToMol(qmol, "c1ccccc1")

# create a substructure search object
# @ <SNIPPET>
itag = oechem.OEGetTag("__origr_idx")
for ai in qmol.GetAtoms():
    ai.SetData(itag, ai.GetIdx())

ss = oechem.OESubSearch(qmol, oechem.OEExprOpts_DefaultAtoms, oechem.OEExprOpts_DefaultBonds)
tmol = oechem.OEGraphMol()
oechem.OESmilesToMol(tmol, "Cc1ccccc1")
oechem.OEPrepareSearch(tmol, ss)

for mi in ss.Match(tmol, True):
    match = oechem.OEMatch()
    for apairi in mi.GetAtoms():
        pidx = apairi.pattern.GetData(itag)
        pattern = qmol.GetAtom(oechem.OEHasAtomIdx(pidx))
        match.AddPair(pattern, apairi.target)
예제 #30
0
def oesolvate(solute,
              density=1.0,
              padding_distance=10.0,
              distance_between_atoms=2.5,
              solvents='tip3p',
              molar_fractions='1.0',
              geometry='box',
              close_solvent=True,
              salt='[Na+], [Cl-]',
              salt_concentration=0.0,
              neutralize_solute=True,
              verbose=False,
              return_components=False,
              **kargs):
    """
    This function solvates the passed solute in a cubic box or a sphere by using Packmol. Packmol
    creates an initial point for molecular dynamics simulations by packing molecule in defined regions
    of space. For additional info:
    http://www.ime.unicamp.br/~martinez/packmol/home.shtml

    The geometry volume is estimated by the using the padding parameter and the solute size.
    The number of solvent molecules is calculated by using the specified density and volume.
    Solvent molecules are specified as comma separated smiles strings. The molar fractions
    of each solvent molecule are specified in a similar fashion. By default if the solute is
    charged counter ions are added to neutralize it

    Parameters:
    -----------
    solute: OEMol molecule
        The solute to solvate
    density: float
        The solution density in g/ml
    padding_distance: float
        The largest dimension of the solute (along the x, y, or z axis) is determined (in A), 
        and a cubic box of size (largest dimension)+2*padding is used
    distance_between_atoms: float
        The minimum distance between atoms in A
    solvents: python string
        A comma separated smiles string or keywords for the solvent molecules.
        Special water models can be selected by using the keywords:
        tip3p for TIP3P water model geometry
    molar_fractions: python string
        A comma separated molar fraction string of the solvent molecules
    close_solvent: boolean
        If True solvent molecules will be placed very close to the solute
    salt: python string
        A comma separated string of the dissociated salt in solution
    salt_concentration: float
        Salt concentration in millimolar
    neutralize_solute: boolean
        If True counter-ions will be added to the solution to neutralize the solute
    verbose: Bool
        If True verbose mode is enabled
    return_components: Bool
        If True the added solvent molecules are also returned as OEMol

    Return:
    -------
    oe_mol: OEMol
        The solvated system. If the selected geometry is a box a SD tag with
        name 'box_vector' is attached the output molecule containing
        the system box vectors.
    oe_mol_components: OEMol
        If the return_components flag is True the added solvent molecules are
        returned as an additional OEMol
    """
    def BoundingBox(molecule):
        """
        This function calculates the Bounding Box of the passed
        molecule

        molecule: OEMol

        return: bb (numpy array)
            the calculated bounding box is returned as numpy array:
            [(xmin,ymin,zmin), (xmax,ymax,zmax)]
        """
        coords = [v for k, v in molecule.GetCoords().items()]
        np_coords = np.array(coords)
        min_coord = np_coords.min(axis=0)
        max_coord = np_coords.max(axis=0)
        bb = np.array([min_coord, max_coord])
        return bb

    if shutil.which("packmol") is None:
        raise (IOError("Packmol executable not found"))

    # Extract solvent smiles strings and mole fractions
    solvents = [sm.strip() for sm in solvents.split(',')]
    fractions = [float(mf) for mf in molar_fractions.split(',')]

    # If the smiles string and mole fractions lists have different lengths raise an error
    if len(solvents) != len(fractions):
        raise ValueError(
            "Selected solvent number and selected molar fraction number mismatch: {} vs {}"
            .format(len(solvents), len(fractions)))

    # Remove smiles string with 0.0 mole fraction
    solvent_smiles = [
        solvents[i] for i, v in enumerate(fractions) if fractions[i]
    ]
    mol_fractions = [mf for mf in fractions if mf]

    # Mole fractions are non-negative numbers
    if any([v < 0.0 for v in mol_fractions]):
        raise ValueError("Error: Mole fractions are non-negative real numbers")

    # Mole fractions must sum up to 1.0
    if abs(sum(mol_fractions) - 1.0) > 0.001:
        oechem.OEThrow.Error("Error: Mole fractions do not sum up to 1.0")

    if geometry not in ['box', 'sphere']:
        raise ValueError(
            "Error geometry: the supported geometries are box and sphere not {}"
            .format(geometry))

    # Set Units
    density = density * unit.grams / unit.milliliter
    padding_distance = padding_distance * unit.angstrom
    salt_concentration = salt_concentration * unit.millimolar

    # Calculate the Solute Bounding Box
    BB_solute = BoundingBox(solute)

    # Estimate of the box cube length
    box_edge = 2.0 * padding_distance + np.max(BB_solute[1] -
                                               BB_solute[0]) * unit.angstrom

    if geometry == 'box':
        # Box Volume
        Volume = box_edge**3
    if geometry == 'sphere':
        Volume = (4.0 / 3.0) * 3.14159265 * (0.5 * box_edge)**3

    # Omega engine is used to generate conformations
    omegaOpts = oeomega.OEOmegaOptions()
    omegaOpts.SetMaxConfs(1)
    omegaOpts.SetStrictStereo(False)
    omega = oeomega.OEOmega(omegaOpts)

    # Create a string code to identify the solute residues. The code ID used is based
    # on the residue number id, the residue name and the chain id:
    # id+resname+chainID
    hv_solute = oechem.OEHierView(
        solute,
        oechem.OEAssumption_BondedResidue + oechem.OEAssumption_ResPerceived)
    solute_resid_list = []
    for chain in hv_solute.GetChains():
        for frag in chain.GetFragments():
            for hres in frag.GetResidues():
                oe_res = hres.GetOEResidue()
                solute_resid_list.append(
                    str(oe_res.GetResidueNumber()) + oe_res.GetName() +
                    chain.GetChainID())

    # Solvent component list_names
    solvent_resid_dic_names = dict()

    # Neutralize solute
    ion_sum_wgt_n_ions = 0.0 * unit.grams / unit.mole
    if neutralize_solute:
        # Container for the counter-ions
        oe_ions = []
        # Container for the ion smiles strings
        ions_smiles = []
        solute_formal_charge = 0
        for at in solute.GetAtoms():
            solute_formal_charge += at.GetFormalCharge()
        if solute_formal_charge > 0:
            ions_smiles.append("[Cl-]")
        elif solute_formal_charge < 0:
            ions_smiles.append("[Na+]")
        else:
            pass

        # Total number of counter-ions to neutralize the solute
        n_ions = abs(solute_formal_charge)

        # print("Counter ions to add = {} of {}".format(n_ions, ions_smiles[0]))

        # Ions
        if n_ions >= 1:
            for sm in ions_smiles:
                mol = oechem.OEMol()
                if not oechem.OESmilesToMol(mol, sm):
                    raise ValueError(
                        "Error counter ions: SMILES string parsing fails for the string: {}"
                        .format(sm))

                # Generate conformer
                if not omega(mol):
                    raise ValueError(
                        "Error counter ions: Conformer generation fails for the molecule with "
                        "smiles string: {}".format(sm))

                oe_ions.append(mol)

                if sm == '[Na+]':
                    solvent_resid_dic_names[' NA'] = mol
                else:
                    solvent_resid_dic_names[' CL'] = mol

            ion_sum_wgt = 0.0 * unit.grams / unit.mole
            for ion in oe_ions:
                # Molecular weight
                ion_sum_wgt += oechem.OECalculateMolecularWeight(
                    ion) * unit.grams / unit.mole

            ion_sum_wgt_n_ions = ion_sum_wgt * n_ions

            # Create ions .pdb files
            ions_smiles_pdbs = []
            for i in range(0, len(ions_smiles)):
                pdb_name = os.path.basename(tempfile.mktemp(suffix='.pdb'))
                pdb_name = ions_smiles[i] + '_' + pdb_name
                ions_smiles_pdbs.append(pdb_name)

            for i in range(0, len(ions_smiles)):
                ofs = oechem.oemolostream(ions_smiles_pdbs[i])
                oechem.OEWriteConstMolecule(ofs, oe_ions[i])

    # Add salts to the solution

    # Solvent smiles string parsing
    char_set = string.ascii_uppercase
    salt_sum_wgt_n_salt = 0.0 * unit.grams / unit.mole
    if salt_concentration > 0.0 * unit.millimolar:

        salt_smiles = [sm.strip() for sm in salt.split(',')]

        # Container list of oemol salt molecules generated by using smiles strings
        oe_salt = []

        for sm in salt_smiles:
            mol_salt = oechem.OEMol()
            if not oechem.OESmilesToMol(mol_salt, sm):
                raise ValueError(
                    "Error salt: SMILES string parsing fails for the string: {}"
                    .format(sm))

            # Generate conformer
            if not omega(mol_salt):
                raise ValueError(
                    "Error salt: Conformer generation fails for the "
                    "molecule with smiles string: {}".format(sm))

            # Unique 3 code letter are set as solvent residue names
            solv_id = ''.join(random.sample(char_set * 3, 3))

            # Try to recognize the residue name
            oechem.OEPerceiveResidues(mol_salt)

            for atmol in mol_salt.GetAtoms():
                res = oechem.OEAtomGetResidue(atmol)
                if res.GetName() == 'UNL':
                    res.SetName(solv_id)
                    oechem.OEAtomSetResidue(atmol, res)
                    if solv_id not in solvent_resid_dic_names:
                        solvent_resid_dic_names[solv_id] = mol_salt
                else:
                    if res.GetName() not in solvent_resid_dic_names:
                        solvent_resid_dic_names[res.GetName()] = mol_salt
                    break

            oe_salt.append(mol_salt)

        n_salt = int(
            round(unit.AVOGADRO_CONSTANT_NA * salt_concentration *
                  Volume.in_units_of(unit.liter)))

        # for i in range(0, len(salt_smiles)):
        #     print("Number of molecules for the salt component {} = {}".format(salt_smiles[i], n_salt))

        salt_sum_wgt = 0.0 * unit.grams / unit.mole
        for salt in oe_salt:
            # Molecular weight
            salt_sum_wgt += oechem.OECalculateMolecularWeight(
                salt) * unit.grams / unit.mole

        salt_sum_wgt_n_salt = salt_sum_wgt * n_salt

        # Create salt .pdb files
        if n_salt >= 1:
            salt_pdbs = []
            for i in range(0, len(salt_smiles)):
                pdb_name = os.path.basename(tempfile.mktemp(suffix='.pdb'))
                # pdb_name = salt_smiles[i] + '_' + pdb_name
                salt_pdbs.append(pdb_name)

            for i in range(0, len(salt_smiles)):
                ofs = oechem.oemolostream(salt_pdbs[i])
                oechem.OEWriteConstMolecule(ofs, oe_salt[i])

    # Container list of oemol solvent molecules generated by using smiles strings
    oe_solvents = []

    for sm in solvent_smiles:

        if sm == 'tip3p':
            tip3p_fn = os.path.join(PACKAGE_DIR, 'oeommtools', 'data',
                                    'tip3p.pdb')
            ifs = oechem.oemolistream(tip3p_fn)
            mol_sol = oechem.OEMol()

            if not oechem.OEReadMolecule(ifs, mol_sol):
                raise IOError(
                    "It was not possible to read the tip3p molecule file")
        else:

            mol_sol = oechem.OEMol()

            if not oechem.OESmilesToMol(mol_sol, sm):
                raise ValueError(
                    "Error solvent: SMILES string parsing fails for the string: {}"
                    .format(sm))

            # Generate conformer
            if not omega(mol_sol):
                raise ValueError(
                    "Error solvent: Conformer generation fails for "
                    "the molecule with smiles string: {}".format(sm))

        # Unique 3 code letter are set as solvent residue names
        solv_id = ''.join(random.sample(char_set * 3, 3))

        # Try to recognize the residue name
        oechem.OEPerceiveResidues(mol_sol)

        for atmol in mol_sol.GetAtoms():
            res = oechem.OEAtomGetResidue(atmol)
            if res.GetName() == 'UNL':
                res.SetName(solv_id)
                oechem.OEAtomSetResidue(atmol, res)
                if solv_id not in solvent_resid_dic_names:
                    solvent_resid_dic_names[solv_id] = mol_sol
            else:
                if res.GetName() not in solvent_resid_dic_names:
                    solvent_resid_dic_names[res.GetName()] = mol_sol
                break

        oe_solvents.append(mol_sol)

    # Sum of the solvent molecular weights
    solvent_sum_wgt_frac = 0.0 * unit.grams / unit.mole

    for idx in range(0, len(oe_solvents)):
        # Molecular weight
        wgt = oechem.OECalculateMolecularWeight(
            oe_solvents[idx]) * unit.grams / unit.mole
        solvent_sum_wgt_frac += wgt * mol_fractions[idx]

    # Solute molecular weight
    solute_wgt = oechem.OECalculateMolecularWeight(
        solute) * unit.gram / unit.mole

    # Estimate of the number of each molecular species present in the solution accordingly
    # to their molar fraction fi:
    #
    # ni = fi*(density*volume*NA - wgt_solute - sum_k(wgt_salt_k*nk) - wgt_ion*n_ion)/sum_j(wgt_nj * fj)
    #
    # where ni is the number of molecule of specie i, density the mixture density, volume the
    # mixture volume, wgt_solute the molecular weight of the solute, wgt_salt_k the molecular
    # weight of the salt component k, nk the number of molecule of salt component k, wgt_ion
    # the counter ion molecular weight, n_ions the number of counter ions and wgt_nj the molecular
    # weight of the molecule specie j with molar fraction fj

    div = (unit.AVOGADRO_CONSTANT_NA * density * Volume -
           (solute_wgt + salt_sum_wgt_n_salt +
            ion_sum_wgt_n_ions)) / solvent_sum_wgt_frac

    # Solvent number of monomers
    n_monomers = [int(round(mf * div)) for mf in mol_fractions]

    if not all([nm > 0 for nm in n_monomers]):
        raise ValueError(
            "Error negative number of solvent components: the density could be too low"
        )

    # for i in range(0, len(solvent_smiles)):
    #     print("Number of molecules for the component {} = {}".format(solvent_smiles[i], n_monomers[i]))

    # Packmol Configuration file setting
    if close_solvent:
        header_template = """\n# Mixture\ntolerance {}\nfiletype pdb\noutput {}\nadd_amber_ter\navoid_overlap no"""
    else:
        header_template = """\n# Mixture\ntolerance {}\nfiletype pdb\noutput {}\nadd_amber_ter\navoid_overlap yes"""

    # Templates strings
    solute_template = """\n\n# Solute\nstructure {}\nnumber 1\nfixed 0. 0. 0. 0. 0. 0.\nresnumbers 1\nend structure"""

    if geometry == 'box':
        solvent_template = """\nstructure {}\nnumber {}\ninside box {:0.3f} {:0.3f} {:0.3f} {:0.3f} {:0.3f} {:0.3f}\
        \nchain !\nresnumbers 3\nend structure"""
    if geometry == 'sphere':
        solvent_template = """\nstructure {}\nnumber {}\ninside sphere {:0.3f} {:0.3f} {:0.3f} {:0.3f}\
        \nchain !\nresnumbers 3\nend structure"""

    # Create solvents .pdb files
    solvent_pdbs = []
    for i in range(0, len(solvent_smiles)):
        pdb_name = os.path.basename(tempfile.mktemp(suffix='.pdb'))
        solvent_pdbs.append(pdb_name)

    for i in range(0, len(solvent_smiles)):
        ofs = oechem.oemolostream(solvent_pdbs[i])
        oechem.OEWriteConstMolecule(ofs, oe_solvents[i])

    solute_pdb = 'solute' + '_' + os.path.basename(
        tempfile.mktemp(suffix='.pdb'))
    ofs = oechem.oemolostream(solute_pdb)

    if solute.GetMaxConfIdx() > 1:
        raise ValueError("Solutes with multiple conformers are not supported")
    else:
        oechem.OEWriteConstMolecule(ofs, solute)

    # Write Packmol header section
    mixture_pdb = 'mixture' + '_' + os.path.basename(
        tempfile.mktemp(suffix='.pdb'))
    body = header_template.format(distance_between_atoms, mixture_pdb)
    # Write Packmol configuration file solute section
    body += solute_template.format(solute_pdb)

    # The solute is centered inside the box
    xc = (BB_solute[0][0] + BB_solute[1][0]) / 2.
    yc = (BB_solute[0][1] + BB_solute[1][1]) / 2.
    zc = (BB_solute[0][2] + BB_solute[1][2]) / 2.

    # Correct for periodic box conditions to avoid
    # steric clashes at the box edges
    pbc_correction = 1.0 * unit.angstrom

    xmin = xc - ((box_edge - pbc_correction) / 2.) / unit.angstrom
    xmax = xc + ((box_edge - pbc_correction) / 2.) / unit.angstrom
    ymin = yc - ((box_edge - pbc_correction) / 2.) / unit.angstrom
    ymax = yc + ((box_edge - pbc_correction) / 2.) / unit.angstrom
    zmin = zc - ((box_edge - pbc_correction) / 2.) / unit.angstrom
    zmax = zc + ((box_edge - pbc_correction) / 2.) / unit.angstrom

    # Packmol setting for the solvent section
    body += '\n\n# Solvent'
    for i in range(0, len(solvent_smiles)):
        if geometry == 'box':
            body += solvent_template.format(solvent_pdbs[i], n_monomers[i],
                                            xmin, ymin, zmin, xmax, ymax, zmax)
        if geometry == 'sphere':
            body += solvent_template.format(solvent_pdbs[i], n_monomers[i], xc,
                                            yc, zc,
                                            0.5 * box_edge / unit.angstrom)

    # Packmol setting for the salt section
    if salt_concentration > 0.0 * unit.millimolar and n_salt >= 1:
        body += '\n\n# Salt'
        for i in range(0, len(salt_smiles)):
            if geometry == 'box':
                body += solvent_template.format(salt_pdbs[i],
                                                int(round(n_salt)), xmin, ymin,
                                                zmin, xmax, ymax, zmax)
            if geometry == 'sphere':
                body += solvent_template.format(salt_pdbs[i],
                                                int(round(n_salt)), xc, yc, zc,
                                                0.5 * box_edge / unit.angstrom)

    # Packmol setting for the ions section
    if neutralize_solute and n_ions >= 1:
        body += '\n\n# Counter Ions'
        for i in range(0, len(ions_smiles)):
            if geometry == 'box':
                body += solvent_template.format(ions_smiles_pdbs[i], n_ions,
                                                xmin, ymin, zmin, xmax, ymax,
                                                zmax)
            if geometry == 'sphere':
                body += solvent_template.format(ions_smiles_pdbs[i], n_ions,
                                                xc, yc, zc,
                                                0.5 * box_edge / unit.angstrom)

    # Packmol configuration file
    packmol_filename = os.path.basename(tempfile.mktemp(suffix='.inp'))

    with open(packmol_filename, 'w') as file_handle:
        file_handle.write(body)

    # Call Packmol
    if not verbose:
        mute_output = open(os.devnull, 'w')
        with open(packmol_filename, 'r') as file_handle:
            subprocess.check_call(['packmol'],
                                  stdin=file_handle,
                                  stdout=mute_output,
                                  stderr=mute_output)
    else:
        with open(packmol_filename, 'r') as file_handle:
            subprocess.check_call(['packmol'], stdin=file_handle)

    # Read in the Packmol solvated system
    solvated = oechem.OEMol()

    if os.path.exists(mixture_pdb + '_FORCED'):
        os.rename(mixture_pdb + '_FORCED', mixture_pdb)
        print("Warning: Packing solution is not optimal")

    ifs = oechem.oemolistream(mixture_pdb)
    oechem.OEReadMolecule(ifs, solvated)

    # To avoid to change the user oemol starting solute by reading in
    # the generated mixture pdb file and loosing molecule info, the
    # solvent molecules are extracted from the mixture system and
    # added back to the starting solute

    # Extract from the solution system the solvent molecules
    # by checking the previous solute generated ID: id+resname+chainID
    hv_solvated = oechem.OEHierView(
        solvated,
        oechem.OEAssumption_BondedResidue + oechem.OEAssumption_ResPerceived)

    # This molecule will hold the solvent molecules generated directly from
    # the omega conformers. This is useful to avoid problems related to read in
    # the solvent molecules from pdb files and triggering unwanted perceiving actions
    new_components = oechem.OEMol()

    bv = oechem.OEBitVector(solvated.GetMaxAtomIdx())
    for chain in hv_solvated.GetChains():
        for frag in chain.GetFragments():
            for hres in frag.GetResidues():
                oe_res = hres.GetOEResidue()
                if str(oe_res.GetResidueNumber()) + oe_res.GetName(
                ) + chain.GetChainID() not in solute_resid_list:
                    oechem.OEAddMols(new_components,
                                     solvent_resid_dic_names[oe_res.GetName()])
                    atms = hres.GetAtoms()
                    for at in atms:
                        bv.SetBitOn(at.GetIdx())

    pred = oechem.OEAtomIdxSelected(bv)
    components = oechem.OEMol()
    oechem.OESubsetMol(components, solvated, pred)

    new_components.SetCoords(components.GetCoords())

    # This is necessary otherwise just one big residue is created
    oechem.OEPerceiveResidues(new_components)

    # Add the solvent molecules to the solute copy
    solvated_system = solute.CreateCopy()
    oechem.OEAddMols(solvated_system, new_components)

    # Set Title
    solvated_system.SetTitle(solute.GetTitle())

    # Set ions resname to Na+ and Cl-
    for at in solvated_system.GetAtoms():
        res = oechem.OEAtomGetResidue(at)
        if res.GetName() == ' NA':
            res.SetName("Na+")
            oechem.OEAtomSetResidue(atmol, res)
        elif res.GetName() == ' CL':
            res.SetName("Cl-")
            oechem.OEAtomSetResidue(atmol, res)
        else:
            pass

    # Cleaning
    to_delete = solvent_pdbs + [packmol_filename, solute_pdb, mixture_pdb]

    if salt_concentration > 0.0 * unit.millimolar and n_salt >= 1:
        to_delete += salt_pdbs
    if neutralize_solute and n_ions >= 1:
        to_delete += ions_smiles_pdbs

    for fn in to_delete:
        try:
            os.remove(fn)
        except:
            pass

    # Calculate the solution total density
    total_wgt = oechem.OECalculateMolecularWeight(
        solvated_system) * unit.gram / unit.mole
    density_mix = (1 / unit.AVOGADRO_CONSTANT_NA) * total_wgt / Volume
    print("Computed Solution Density = {}".format(
        density_mix.in_units_of(unit.gram / unit.milliliter)))
    # Threshold checking
    ths = 0.1 * unit.gram / unit.milliliter
    if not abs(density -
               density_mix.in_units_of(unit.gram / unit.milliliter)) < ths:
        raise ValueError(
            "Error: the computed density for the solute {} does not match the selected density {} vs {}"
            .format(solute.GetTitle(), density_mix, density))

    if geometry == 'box':
        # Define the box vector and attached it as SD tag to the solvated system
        # with ID tag: 'box_vectors'
        box_vectors = (Vec3(box_edge / unit.angstrom, 0.0,
                            0.0), Vec3(0.0, box_edge / unit.angstrom, 0.0),
                       Vec3(0.0, 0.0,
                            box_edge / unit.angstrom)) * unit.angstrom

        box_vectors = data_utils.encodePyObj(box_vectors)
        solvated_system.SetData(oechem.OEGetTag('box_vectors'), box_vectors)

    if return_components:
        new_components.SetTitle(solute.GetTitle() + '_solvent_comp')
        return solvated_system, new_components
    else:
        return solvated_system