Example #1
0
    def _nitrogen_protonate(self, nitrogens, previous):
        """

        :param nitrogens: list of Nitrogens
        :param previous:
        :return:
        """
        def reset():
            for n in nitrogens:
                self.rwmol.GetAtomWithIdx(n).SetNumExplicitHs(0)

        reset()
        p = Chem.DetectChemistryProblems(self.rwmol)
        if len(p) == 0 or p[0].Message() != previous:
            return True
        for i in range(1, len(nitrogens)):
            for c in itertools.combinations(nitrogens, i):
                reset()
                for n in c:
                    self.rwmol.GetAtomWithIdx(n).SetNumExplicitHs(1)
                p = Chem.DetectChemistryProblems(self.rwmol)
                if len(p) == 0 or p[0].Message() != previous:
                    return True
        return False

        self.log.debug(f'KekulizeException likely caused by nitrogen')
Example #2
0
    def _nitrogen_protonate(self, N, previous):
        def reset():
            for n in N:
                self.mol.GetAtomWithIdx(n).SetNumExplicitHs(0)

        reset()
        p = Chem.DetectChemistryProblems(self.mol)
        if len(p) == 0 or p[0].Message() != previous:
            return True
        for i in range(1, len(N)):
            for c in itertools.combinations(N, i):
                reset()
                for n in c:
                    self.mol.GetAtomWithIdx(n).SetNumExplicitHs(1)
                p = Chem.DetectChemistryProblems(self.mol)
                if len(p) == 0 or p[0].Message() != previous:
                    return True
        return False

        log.debug(f'KekulizeException likely caused by nitrogen')
Example #3
0
 def fix_issues(self, _previous=None):
     problems = Chem.DetectChemistryProblems(self.mol)
     if self._iterations_done > 100:
         log.error(f'Iterations maxed out!')
         return None
     elif self._subiterations_done > 5:
         log.error(f'Unfixable')
         return None
     elif len(problems) == 0:
         return None
     else:
         log.debug(
             f'(Iteration: {self._iterations_done}) N problems {len(problems)}'
         )
         p = problems[0]
         log.debug(
             f'(Iteration: {self._iterations_done}) Issue {p.GetType()}: {p.Message()}'
         )
         if p.Message() == _previous:
             self.triage_rings()
         ############################################################
         if p.GetType() == 'KekulizeException':
             if p.Message() != _previous:
                 N = self._get_nitrogens(p.GetAtomIndices())
                 if len(N) > 0 and self._nitrogen_protonate(N, p.Message()):
                     pass  # been fixed.
                 else:
                     # triage rings should have altered any not ring atoms that are aromatic.
                     # self._get_ring_info()
                     # so it is likely a hetatom thing.
                     log.info(
                         f'Ring triages seems to have failed. Is it a valence thing?'
                     )
                     valence_issues = [
                         self._has_correct_valence(i)
                         for i in p.GetAtomIndices()
                     ]
                     if not all(valence_issues):
                         for i in p.GetAtomIndices():
                             self.fix_valence(i)
                     else:
                         log.warning(
                             f'Attempting default valency (not max)')
                         self._valence_mode = 'default'
                         for i in p.GetAtomIndices():
                             self.fix_valence(i)
                         self._valence_mode = 'max'
             else:
                 for i in p.GetAtomIndices():
                     self.downgrade_ring(self.mol.GetAtomWithIdx(i))
                 self.triage_rings()
         ############################################################
         elif p.GetType(
         ) == 'AtomKekulizeException' and 'non-ring atom' in p.Message():
             atom = self.mol.GetAtomWithIdx(p.GetAtomIdx())
             atom.SetIsAromatic(False)
             log.debug(f'Atom {p.GetAtomIdx()} set to non-aromatic.')
             for bond in atom.GetBonds():
                 bond.SetBondType(Chem.BondType.SINGLE)
         elif p.GetType(
         ) == 'AtomKekulizeException' and 'Aromatic bonds on non aromatic atom' in p.Message(
         ):
             atom = self.mol.GetAtomWithIdx(p.GetAtomIdx())
             log.debug(f'Atom {p.GetAtomIdx()} set to aromatic.')
             atom.SetIsAromatic(True)
         ############################################################
         elif p.GetType() == 'AtomValenceException':
             i = p.GetAtomIdx()
             self.fix_valence(i)
         else:
             log.error('???', p.GetType(), p.Message())
         self._iterations_done += 1
         if _previous != p.Message():
             log.debug(f'{self._iterations_done} appears successful.')
             self._subiterations_done = 0
         else:
             self._subiterations_done += 1
             log.debug(f'{self._iterations_done} appears unsuccessful.')
         return self.fix_issues(_previous=p.Message())
Example #4
0
    def fix_issues(self, _previous=None) -> None:
        """
        This get run during instantiation. It is the third and final one run before sanitization.
        Deals with a variety of problems.
        It calls itself until no problems according to `Chem.DetectChemistryProblems` exits.
        It is a bit shoddy and any oddity likely steps from here. TODO

        :return: None
        """
        self.modifications.append(self.mol)  # may not have changed.
        problems = Chem.DetectChemistryProblems(self.rwmol)
        if self._iterations_done > 100:
            self.log.error(f'Iterations maxed out!')
            return None
        elif self._subiterations_done > 5:
            self.log.error(f'Unfixable')
            return None
        elif len(problems) == 0:
            return None
        else:
            self.log.debug(
                f'(Iteration: {self._iterations_done}) N problems {len(problems)}'
            )
            p = problems[0]
            self.log.debug(
                f'(Iteration: {self._iterations_done}) Issue {p.GetType()}: {p.Message()}'
            )
            if p.Message() == _previous:
                self.triage_rings()
            ############################################################
            if p.GetType() == 'KekulizeException':
                if p.Message() != _previous:
                    N = self._get_nitrogens(p.GetAtomIndices())
                    if len(N) > 0 and self._nitrogen_protonate(N, p.Message()):
                        pass  # been fixed.
                    else:
                        # triage rings should have altered any not ring atoms that are aromatic.
                        # self._get_ring_info()
                        # so it is likely a hetatom thing.
                        self.log.info(
                            f'Ring triages seems to have failed. Is it a valence thing?'
                        )
                        valence_issues = [
                            self._has_correct_valence(i)
                            for i in p.GetAtomIndices()
                        ]
                        if not all(valence_issues):
                            for i in p.GetAtomIndices():
                                self.fix_valence(i)
                        else:
                            self.log.warning(
                                f'Attempting default valency (not max)')
                            self._valence_mode = 'default'
                            for i in p.GetAtomIndices():
                                self.fix_valence(i)
                            self._valence_mode = 'max'
                else:
                    for i in p.GetAtomIndices():
                        self.downgrade_ring(self.rwmol.GetAtomWithIdx(i))
                    self.triage_rings()
            ############################################################
            elif p.GetType(
            ) == 'AtomKekulizeException' and 'non-ring atom' in p.Message():
                atom = self.rwmol.GetAtomWithIdx(p.GetAtomIdx())
                atom.SetIsAromatic(False)
                self.log.debug(f'Atom {p.GetAtomIdx()} set to non-aromatic.')
                for bond in atom.GetBonds():
                    bond.SetBondType(Chem.BondType.SINGLE)
            elif p.GetType(
            ) == 'AtomKekulizeException' and 'Aromatic bonds on non aromatic atom' in p.Message(
            ):
                atom = self.rwmol.GetAtomWithIdx(p.GetAtomIdx())
                self.log.debug(f'Atom {p.GetAtomIdx()} set to aromatic.')
                atom.SetIsAromatic(True)
            ############################################################
            elif p.GetType() == 'AtomValenceException':
                i = p.GetAtomIdx()
                self.fix_valence(i)
            else:
                self.log.error('???', p.GetType(), p.Message())
            self._iterations_done += 1
            if _previous != p.Message():
                self.log.debug(f'{self._iterations_done} appears successful.')
                self._subiterations_done = 0
            else:
                self._subiterations_done += 1
                self.log.debug(
                    f'{self._iterations_done} appears unsuccessful.')
            return self.fix_issues(_previous=p.Message())