Exemple #1
0
def attach_capping(mol1, mol2):
    """it is connecting all Nterminals with the desired capping

    Arguments:
        mol1 {rdKit mol object} -- first molecule to be connected
        mol2 {rdKit mol object} -- second molecule to be connected - chosen N-capping

    Returns:
        rdKit mol object -- mol1 updated (connected with mol2, one or more)
    """

    count = 0

    # detects all the N terminals in mol1
    for atom in mol1.GetAtoms():
        atom.SetProp('Cterm', 'False')
        if atom.GetSmarts() == '[N:2]' or atom.GetSmarts(
        ) == '[NH2:2]' or atom.GetSmarts() == '[NH:2]':
            count += 1
            atom.SetProp('Nterm', 'True')
        else:
            atom.SetProp('Nterm', 'False')

    # detects all the C terminals in mol2 (it should be one)
    for atom in mol2.GetAtoms():
        atom.SetProp('Nterm', 'False')
        if atom.GetSmarts() == '[C:1]' or atom.GetSmarts() == '[CH:1]':
            atom.SetProp('Cterm', 'True')
        else:
            atom.SetProp('Cterm', 'False')

    # mol2 is addes to all the N terminal of mol1
    for i in range(count):
        combo = rdmolops.CombineMols(mol1, mol2)
        Nterm = []
        Cterm = []

        # saves in two different lists the index of the atoms which has to be connected
        for atom in combo.GetAtoms():
            if atom.GetProp('Nterm') == 'True':
                Nterm.append(atom.GetIdx())
            if atom.GetProp('Cterm') == 'True':
                Cterm.append(atom.GetIdx())

        # creates the amide bond
        edcombo = rdchem.EditableMol(combo)
        edcombo.AddBond(Nterm[0], Cterm[0], order=Chem.rdchem.BondType.SINGLE)
        clippedMol = edcombo.GetMol()

        # removes tags and lables form the atoms which reacted
        clippedMol.GetAtomWithIdx(Nterm[0]).SetProp('Nterm', 'False')
        clippedMol.GetAtomWithIdx(Cterm[0]).SetProp('Cterm', 'False')
        clippedMol.GetAtomWithIdx(Nterm[0]).SetAtomMapNum(0)
        clippedMol.GetAtomWithIdx(Cterm[0]).SetAtomMapNum(0)
        # uptades the 'core' molecule
        mol1 = clippedMol

    return mol1
Exemple #2
0
    def simply_merge_hits(
        self,
        hits: Optional[List[Chem.Mol]] = None,
        linked: bool = True,
    ) -> Chem.Mol:
        """
        Recursively stick the hits together and average the positions.
        This is the monster of automerging, full-merging mapping and partial merging mapping.
        The latter however uses `partially_blend_hits` first.
        The hits are not ring-collapsed and -expanded herein.

        :param hits: optionally give a hit list, else uses the attribute ``.hits``.
        :param linked: if true the molecules are joined, else they are placed
            in the same molecule as disconnected fragments.
        :return: the rdkit.Chem.Mol object that will fill ``.scaffold``
        """
        if hits is None:
            hits = sorted(self.hits,
                          key=lambda h: h.GetNumAtoms(),
                          reverse=True)
        for hit in hits:
            BondProvenance.set_all_bonds(hit, 'original')
        self.journal.debug(
            f"Merging: {[hit.GetProp('_Name') for hit in hits]}")
        scaffold = Chem.Mol(hits[0])
        # first try
        save_for_later = []
        for fragmentanda in hits[1:]:
            try:
                scaffold = self.merge_pair(scaffold, fragmentanda)
            except ConnectionError:
                save_for_later.append(fragmentanda)
        # second try
        join_later = []
        for fragmentanda in save_for_later:
            try:
                scaffold = self.merge_pair(scaffold, fragmentanda)
            except ConnectionError:
                join_later.append(fragmentanda)
        # join (last ditch)
        for fragmentanda in join_later:
            if linked:
                try:
                    scaffold = self.join_neighboring_mols(
                        scaffold, fragmentanda)
                except ConnectionError:
                    self.unmatched.append(fragmentanda.GetProp("_Name"))
                    msg = f'Hit {fragmentanda.GetProp("_Name")} has no connections! Skipping!'
                    if self.throw_on_discard:
                        raise ConnectionError(msg)
                    else:
                        warn(msg)
            else:
                new_name = self._get_combined_name(scaffold, fragmentanda)
                scaffold = rdmolops.CombineMols(scaffold, fragmentanda)
                scaffold.SetProp('_Name', new_name)
        return scaffold
 def merge(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol,
           anchor_index: int, attachment_details: List[Dict]) -> Chem.Mol:
     for detail in attachment_details:
         attachment_index = detail['idx_F']  # fragmentanda attachment_index
         scaffold_attachment_index = detail['idx_S']
         bond_type = detail['type']
         f = Chem.FragmentOnBonds(fragmentanda, [
             fragmentanda.GetBondBetweenAtoms(anchor_index,
                                              attachment_index).GetIdx()
         ],
                                  addDummies=False)
         frag_split = []
         fragmols = Chem.GetMolFrags(f,
                                     asMols=True,
                                     fragsMolAtomMapping=frag_split,
                                     sanitizeFrags=False)
         if self._debug_draw:
             print(frag_split)
         # Get the fragment of interest.
         ii = 0
         for mol_N, indices in enumerate(frag_split):
             if anchor_index in indices:
                 break
             ii += len(indices)
         else:
             raise Exception
         frag = fragmols[mol_N]
         frag_anchor_index = indices.index(anchor_index)
         if self._debug_draw:
             self.draw_nicely(frag)
         combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag))
         scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms()
         if self._debug_draw:
             print(scaffold_anchor_index, scaffold_attachment_index,
                   anchor_index, scaffold.GetNumAtoms())
             self.draw_nicely(combo)
         combo.AddBond(scaffold_anchor_index, scaffold_attachment_index,
                       bond_type)
         Chem.SanitizeMol(
             combo,
             sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS +
             Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY,
             catchErrors=True)
         if self._debug_draw:
             self.draw_nicely(combo)
         scaffold = combo
     return scaffold
Exemple #4
0
def merge_molecules(molecules):
    """Helper method to merge two molecules.

  Parameters
  ----------
  molecules: list
    List of rdkit molecules

  Returns
  -------
  merged: rdkit molecule
  """
    from rdkit.Chem import rdmolops
    if len(molecules) == 0:
        return None
    elif len(molecules) == 1:
        return molecules[0]
    else:
        combined = molecules[0]
        for nextmol in molecules[1:]:
            combined = rdmolops.CombineMols(combined, nextmol)
        return combined
Exemple #5
0
def connect_mol(mol1, mol2):
    """it is connecting all Nterminals of mol1 with the Cterminal
        of the maximum possible number of mol2s

        Arguments:
            mol1 {rdKit mol object} -- first molecule to be connected
            mol2 {rdKit mol object} -- second molecule to be connected

        Returns:
            rdKit mol object -- mol1 updated (connected with mol2, one or more)
    """
    # used internally to recognize a methylated aa:
    metbond = False
    # can be set with exclude or allow methylation,
    # it refers to the possibility of having methylation in the entire GA:
    methyl = False

    count = 0

    # detects all the N terminals in mol1
    for atom in mol1.GetAtoms():
        atom.SetProp('Cterm', 'False')
        atom.SetProp('methyl', 'False')
        if atom.GetSmarts() == '[N:2]' or atom.GetSmarts(
        ) == '[NH2:2]' or atom.GetSmarts() == '[NH:2]':
            count += 1
            atom.SetProp('Nterm', 'True')
        else:
            atom.SetProp('Nterm', 'False')

    # detects all the C terminals in mol2 (it should be one)
    for atom in mol2.GetAtoms():
        atom.SetProp('Nterm', 'False')
        atom.SetProp('methyl', 'False')
        if atom.GetSmarts() == '[C:1]' or atom.GetSmarts() == '[CH:1]':
            atom.SetProp('Cterm', 'True')
        else:
            atom.SetProp('Cterm', 'False')

    # mol2 is addes to all the N terminal of mol1
    for i in range(count):
        combo = rdmolops.CombineMols(mol1, mol2)
        Nterm = []
        Cterm = []
        # saves in two different lists the index of the atoms which has to be connected
        for atom in combo.GetAtoms():
            if atom.GetProp('Nterm') == 'True':
                Nterm.append(atom.GetIdx())
            if atom.GetProp('Cterm') == 'True':
                Cterm.append(atom.GetIdx())

        # creates the amide bond
        edcombo = rdchem.EditableMol(combo)
        edcombo.AddBond(Nterm[0], Cterm[0], order=Chem.rdchem.BondType.SINGLE)
        edcombo.RemoveAtom(Cterm[0] + 1)
        clippedMol = edcombo.GetMol()

        # removes tags and lables form c term atoms which reacted
        clippedMol.GetAtomWithIdx(Cterm[0]).SetProp('Cterm', 'False')
        clippedMol.GetAtomWithIdx(Cterm[0]).SetAtomMapNum(0)

        # methylates amide bond
        if metbond == True and methyl == True:
            Nterm = []
            Met = []
            methyl = rdmolfiles.MolFromSmiles('[C:4]')
            for atom in methyl.GetAtoms():
                atom.SetProp('methyl', 'True')
                atom.SetProp('Nterm', 'False')
                atom.SetProp('Cterm', 'False')
            metcombo = rdmolops.CombineMols(clippedMol, methyl)
            for atom in metcombo.GetAtoms():
                if atom.GetProp('Nterm') == 'True':
                    Nterm.append(atom.GetIdx())
                if atom.GetProp('methyl') == 'True':
                    Met.append(atom.GetIdx())
            metedcombo = rdchem.EditableMol(metcombo)
            metedcombo.AddBond(Nterm[0],
                               Met[0],
                               order=Chem.rdchem.BondType.SINGLE)
            clippedMol = metedcombo.GetMol()
            clippedMol.GetAtomWithIdx(Met[0]).SetProp('methyl', 'False')
            clippedMol.GetAtomWithIdx(Met[0]).SetAtomMapNum(0)

        # removes tags and lables form the atoms which reacted
        clippedMol.GetAtomWithIdx(Nterm[0]).SetProp('Nterm', 'False')
        clippedMol.GetAtomWithIdx(Nterm[0]).SetAtomMapNum(0)

        # uptades the 'core' molecule
        mol1 = clippedMol
    metbond = False
    return mol1
Exemple #6
0
    def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol,
                    anchor_index: int, attachment_details: List[Dict],
                    other_attachments: List[int],
                    other_attachment_details: List[List[Dict]]) -> Chem.Mol:
        """
        This does the messy work for merge_pair.

        :param scaffold:
        :param fragmentanda:
        :param anchor_index:
        :param attachment_details:
        :param other_attachments:
        :param other_attachment_details:
        :return:
        """
        # get bit to add.
        bonds_to_frag = []
        for detail in attachment_details:
            attachment_index = detail['idx_F']  # fragmentanda attachment_index
            bonds_to_frag += [
                fragmentanda.GetBondBetweenAtoms(anchor_index,
                                                 attachment_index).GetIdx()
            ]
        bonds_to_frag += [
            fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx()
            for oi, oad in zip(other_attachments, other_attachment_details)
        ]
        if self._debug_draw and other_attachments:
            print('ring!', other_attachments)
            print('ring!', other_attachment_details)
        f = Chem.FragmentOnBonds(fragmentanda, bonds_to_frag, addDummies=False)
        frag_split = []
        fragmols = Chem.GetMolFrags(f,
                                    asMols=True,
                                    fragsMolAtomMapping=frag_split,
                                    sanitizeFrags=False)
        if self._debug_draw:
            print('Fragment splits')
            print(frag_split)
        # Get the fragment of interest.
        ii = 0
        for mol_N, indices in enumerate(frag_split):
            if anchor_index in indices:
                break
            ii += len(indices)
        else:
            raise Exception
        frag = fragmols[mol_N]
        frag_anchor_index = indices.index(anchor_index)
        # pre-emptively fix atom ori_i
        # offset collapsed to avoid clashes.
        self._offset_collapsed_ring(frag)
        self._offset_origins(frag)
        # Experimental code.
        # TODO: finish!
        # frag_atom = frag.GetAtomWithIdx(frag_anchor_index)
        # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()}
        # del old2future[-1] # does nothing but nice to double tap
        # if frag_atom.GetIntProp('_ori_i') == -1: #damn.
        #     for absent in self._get_mystery_ori_i(frag):
        #         old2future[absent] = scaffold_attachment_index
        # self._renumber_original_indices(frag, old2future)
        if self._debug_draw:
            print('Fragment to add')
            self.draw_nicely(frag)
        combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag))
        scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms()
        if self._debug_draw:
            print('Pre-merger')
            print(scaffold_anchor_index, attachment_details, anchor_index,
                  scaffold.GetNumAtoms())
            self.draw_nicely(combo)
        for detail in attachment_details:
            attachment_index = detail['idx_F']  # fragmentanda attachment_index
            scaffold_attachment_index = detail['idx_S']
            bond_type = detail['type']
            combo.AddBond(scaffold_anchor_index, scaffold_attachment_index,
                          bond_type)
        for oi, oad in zip(other_attachments, other_attachment_details):
            bond_type = oad[0]['type']
            scaffold_attachment_index = oad[0]['idx_S']
            scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms()
            combo.AddBond(scaffold_anchor_index, scaffold_attachment_index,
                          bond_type)
            if self._debug_draw:
                print(
                    f"Added additional {bond_type.name} bond between {scaffold_attachment_index} and {scaffold_anchor_index} " + \
                    f"(formerly {indices.index(oi)})")
        Chem.SanitizeMol(
            combo,
            sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS +
            Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY,
            catchErrors=True)
        if self._debug_draw:
            print('Merged')
            self.draw_nicely(combo)
        self._prevent_two_bonds_on_dummy(combo)
        scaffold = combo.GetMol()
        return scaffold
Exemple #7
0
    def _merge_part(self, scaffold: Chem.Mol, fragmentanda: Chem.Mol,
                    anchor_index: int, attachment_details: List[Dict],
                    other_attachments: List[int],
                    other_attachment_details: List[List[Dict]]) -> Chem.Mol:
        """
        This does the messy work for merge_pair.

        :param scaffold: the Chem.Mol molecule onto whose copy the fragmentanda Chem.Mol gets added
        :param fragmentanda: The other Chem.Mol molecule
        :param anchor_index: the fragment-to-added's internal atom that attaches (hit indexed)
        :param attachment_details: see `_pre_fragment_pairs` or example below fo an entry
        :type attachment_details: List[Dict]
        :param other_attachments:
        :param other_attachment_details:
        :return: a new Chem.Mol molecule

        Details object example:

            [{'idx': 5,
              'type': rdkit.Chem.rdchem.BondType.SINGLE,
              'idx_F': 5, # fragmentanda index
              'idx_S': 1  # scaffold index
              }], ...}
        """
        # get bit to add.
        bonds_to_frag = []
        for detail in attachment_details:
            attachment_index = detail['idx_F']  # fragmentanda attachment_index
            bonds_to_frag += [
                fragmentanda.GetBondBetweenAtoms(anchor_index,
                                                 attachment_index).GetIdx()
            ]
        bonds_to_frag += [
            fragmentanda.GetBondBetweenAtoms(oi, oad[0]['idx_F']).GetIdx()
            for oi, oad in zip(other_attachments, other_attachment_details)
        ]
        f = Chem.FragmentOnBonds(fragmentanda, bonds_to_frag, addDummies=False)
        frag_split = []
        fragmols = Chem.GetMolFrags(f,
                                    asMols=True,
                                    fragsMolAtomMapping=frag_split,
                                    sanitizeFrags=False)
        # Get the fragment of interest.
        ii = 0
        for mol_N, indices in enumerate(frag_split):
            if anchor_index in indices:
                break
            ii += len(indices)
        else:
            raise Exception
        frag = fragmols[mol_N]
        frag_anchor_index = indices.index(anchor_index)
        # pre-emptively fix atom ori_i
        # offset collapsed to avoid clashes.
        self.offset(frag)
        # Experimental code.
        # TODO: finish!
        # frag_atom = frag.GetAtomWithIdx(frag_anchor_index)
        # old2future = {atom.GetIntProp('_ori_i'): atom.GetIdx() + scaffold.GetNumAtoms() for atom in frag.GetAtoms()}
        # del old2future[-1] # does nothing but nice to double tap
        # if frag_atom.GetIntProp('_ori_i') == -1: #damn.
        #     for absent in self._get_mystery_ori_i(frag):
        #         old2future[absent] = scaffold_attachment_index
        # self._renumber_original_indices(frag, old2future)
        combo = Chem.RWMol(rdmolops.CombineMols(scaffold, frag))
        scaffold_anchor_index = frag_anchor_index + scaffold.GetNumAtoms()
        for detail in attachment_details:
            # scaffold_anchor_index : atom index in scaffold that needs to be added to scaffold_attachment_index
            # but was originally attached to attachment_index in fragmentanda.
            # the latter is not kept.
            attachment_index = detail['idx_F']  # fragmentanda attachment_index
            scaffold_attachment_index = detail[
                'idx_S']  # scaffold attachment index
            bond_type = detail['type']
            combo.AddBond(scaffold_anchor_index, scaffold_attachment_index,
                          bond_type)
            new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index,
                                                 scaffold_attachment_index)
            # BondProvenance.set_bond(new_bond, '???')
            # self.transfer_ring_data(fragmentanda.GetAtomWithIdx(attachment_index),
            #                         combo.GetAtomWithIdx(scaffold_anchor_index))
        for oi, oad in zip(other_attachments, other_attachment_details):
            bond_type = oad[0]['type']
            scaffold_attachment_index = oad[0]['idx_S']
            scaffold_anchor_index = indices.index(oi) + scaffold.GetNumAtoms()
            combo.AddBond(scaffold_anchor_index, scaffold_attachment_index,
                          bond_type)
            new_bond = combo.GetBondBetweenAtoms(scaffold_anchor_index,
                                                 scaffold_attachment_index)
            # BondProvenance.set_bond(new_bond, '???')
        Chem.SanitizeMol(
            combo,
            sanitizeOps=Chem.rdmolops.SanitizeFlags.SANITIZE_ADJUSTHS +
            Chem.rdmolops.SanitizeFlags.SANITIZE_SETAROMATICITY,
            catchErrors=True)
        self._prevent_two_bonds_on_dummy(combo)
        scaffold = combo.GetMol()
        return scaffold
Exemple #8
0
def merge_molecules(ligand, protein):
    """Helper method to merge ligand and protein molecules."""
    from rdkit.Chem import rdmolops
    return rdmolops.CombineMols(ligand, protein)