Exemple #1
0
def RemoveBond(mol, bond):
    if bond.HasProp('group'):
        raise MutateFail(mol,
                         'Protected bond (in group) passed to RemoveBond.')
    if not bond.IsInRing():
        raise MutateFail(mol, 'Non-ring bond passed to RemoveBond')
    mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
    return mol
Exemple #2
0
def MakeMutations(candidate):
    ''' The mutations, based on not-aromatic SMILES'''
    # 1. Kekulize:
    try:
        Chem.Kekulize(candidate, True)
    except ValueError:
        print "MakeMutation. Kekulize Error:", Chem.MolToSmiles(candidate)
        raise MutateFail(candidate)
    # 2. Mutate
    candidate = SingleMutate(candidate)
    # 3. SetAromaticity again
    try:
        if aromaticity: Chem.SetAromaticity(candidate)
        candidate = Finalize(candidate, tautomerize=False)
    except ValueError:
        print "MakeMutation. SetAromaticity Error:", Chem.MolToSmiles(
            candidate)
        raise MutateFail(candidate)
    return candidate
Exemple #3
0
def AddAroRing(mol):
    freesinglebonds = GetFreeBonds(mol, order=1, sides=True)
    freedoublebonds = GetFreeBonds(mol, order=2, notprop='group')
    triplebonds = filter(lambda bond: bond.GetBondType() == bondorder[3],
                         mol.GetBonds())
    correctbonds = freedoublebonds + triplebonds + freesinglebonds
    if len(correctbonds) < 1: raise MutateFail()
    bond = random.choice(correctbonds)

    # if double bond
    if all(atom.GetImplicitValence()
           for atom in (bond.GetBeginAtom(), bond.GetEndAtom())):
        pass
    elif bond.GetBondType() == bondorder[3]:
        bond.SetBondType(bondorder[2])
    else:
        print "wrong kind of atom given"
        raise MutateFail()

    def AwithLabel(label, idx=True):
        atom = filter(lambda atom: atom.HasProp(label), mol.GetAtoms())[0]
        if idx:
            return atom.GetIdx()
        else:
            return atom

    butadiene = Chem.MolFromSmiles('C=CC=C')
    butadiene.GetAtomWithIdx(0).SetBoolProp('buta1', True)
    butadiene.GetAtomWithIdx(3).SetBoolProp('buta2', True)
    bond.GetBeginAtom().SetBoolProp('ah1', True)
    bond.GetEndAtom().SetBoolProp('ah2', True)
    mol = Chem.RWMol(Chem.CombineMols(mol, butadiene))
    try:
        mol.AddBond(AwithLabel('buta1'), AwithLabel('ah1'), bondorder[1])
        mol.AddBond(AwithLabel('buta2'), AwithLabel('ah2'), bondorder[1])
    except RuntimeError:
        raise MutateFail()
    finally:
        for prop in ['buta1', 'buta2', 'ah1', 'ah2']:
            AwithLabel(prop, idx=False).ClearProp(prop)

    return mol
Exemple #4
0
def AddBond(mol):
    # NB! This function was overloaded and atoms where possible arguments
    # Not anymore possible to get a cleaner interface

    natoms = mol.GetNumAtoms()
    if natoms < 5: raise MutateFail()  #don't create 4-member rings

    #Don't create non-planar graphs (note that this does not prevent
    #all non-planar graphs, but it does prevent some)
    if natoms >= 3 and mol.GetNumBonds() >= 3 * natoms - 6:
        raise MutateFail()

    # List of atoms that can form new bonds
    atoms = [
        atom for atom in GetAtoms(mol, notprop='protected')
        if EmptyValence(atom) > 0
    ]
    if len(atoms) < 2: raise MutateFail()

    for i in range(MAXTRY):
        atom1 = random.choice(atoms)
        atom2 = random.choice(atoms)
        if atom1 == atom2: continue
        # new rather strict criteria;
        if atom1.IsInRing() and atom2.IsInRing():
            #print "continue because both atoms in ring"
            continue
        # Only make rings of size 5-7
        if not (5 <= len(
                Chem.GetShortestPath(mol, atom1.GetIdx(), atom2.GetIdx())) <=
                7):
            continue
        nfreebonds1 = EmptyValence(atom1)
        nfreebonds2 = EmptyValence(atom2)
        if nfreebonds2 < nfreebonds1: nfreebonds1 = nfreebonds2
        assert nfreebonds1 > 0
        order = random.randrange(1, nfreebonds1 + 1)
        mol.AddBond(atom1.GetIdx(), atom2.GetIdx(), bondorder[order])
        return mol
    # if here, mutation failed
    raise MutateFail()
Exemple #5
0
def GetFragment(mol):
    #print "in get fragment with:", Chem.MolToSmiles(mol)
    tried = []
    for itry in xrange(MAXTRY):
        frag = Chem.RWMol(mol)
        #frag.ClearComputedProps()
        ResetProps(frag)

        #Cut an acyclic bond to break molecule in 2
        # get the ring bond ids. this gives a tuple of tuple for every ring
        ringbondids = frag.GetRingInfo().BondRings()
        # flatten this tuple to a 1D set
        ringbondids = list(
            set([bond for subset in ringbondids for bond in subset]))
        # get all the bonds that are NOT ringbonds or already tried
        bonds = [
            bond for bond in mol.GetBonds()
            if bond.GetIdx() not in tried + ringbondids
        ]
        if len(bonds) == 0: break
        if debug: print "CX0",
        # choose a bond
        delbond = random.choice(bonds)
        tried.append(delbond.GetIdx())
        # get atom indices of the bond
        i, j = (delbond.GetBeginAtomIdx(), delbond.GetEndAtomIdx())

        frag.RemoveBond(i, j)
        # get new fragments as two new normal Mol objects
        try:
            frags = Chem.GetMolFrags(frag, asMols=True)
        except ValueError:
            print "frag:", Chem.MolToSmiles(frag)
            print "mol:", Chem.MolToSmiles(mol)
            break
        molfrags = [Chem.MolToSmiles(x, True) for x in frags]
        if len(frags) < 2:
            #print "only one frag"
            continue

        #Check to make sure fragments have at least 2 atoms
        if any(frag.GetNumAtoms() < 2 for frag in frags):
            #print "not enough atoms on frag"
            continue
        #print  molfrags

        # convert to RWMols?
        frags = map(Chem.RWMol, frags)
        return frags

    # If here, we failed to find a good bond to cut
    #print "no nice bond to cut"
    raise MutateFail()
Exemple #6
0
def FlipBond(mol, bond):
    if bond.HasProp('group'):
        raise MutateFail(mol, 'In-group bond passed to FlipBond')
    oldorder = int(bond.GetBondTypeAsDouble())
    atom1 = bond.GetBeginAtom()
    atom2 = bond.GetEndAtom()
    full = False
    if EmptyValence(atom1) == 0: full = True
    if EmptyValence(atom2) == 0: full = True
    if oldorder == 1 and full:
        raise MutateFail()
    elif oldorder == 1:
        add = 1
    elif oldorder == 3:
        add = -1
    elif oldorder == 2 and full:
        add = -1
    else:
        add = random.choice((-1, 1))
    bond.SetBondType(bondorder[oldorder + add])
    return mol
Exemple #7
0
def FlipBond(mol):
    bonds = list(GetBonds(mol, notprop='group'))
    if len(bonds) == 0: raise MutateFail()
    bond = random.choice(bonds)
    oldorder = int(bond.GetBondTypeAsDouble())
    atom1 = bond.GetBeginAtom()
    atom2 = bond.GetEndAtom()
    full = False
    if EmptyValence(atom1) == 0: full = True
    if EmptyValence(atom2) == 0: full = True
    if oldorder == 1 and full:
        raise MutateFail()
    elif oldorder == 1:
        add = 1
    elif oldorder == 3:
        add = -1
    elif oldorder == 2 and full:
        add = -1
    else:
        add = random.choice((-1, 1))
    bond.SetBondType(bondorder[oldorder + add])
    return mol
Exemple #8
0
def FlipAtom(mol):
    atoms = filter(CanChangeAtom, mol.GetAtoms())
    if len(atoms) == 0: raise MutateFail()
    atom = random.choice(atoms)

    changed = False
    neighbors = list(atom.GetNeighbors())
    valence = atom.GetExplicitValence() + atom.GetNumRadicalElectrons()

    # Add a halogen, if possible
    # we only add halogens when neighbor and neighbor-neighbor only C
    if valence == 1:
        if (len(halogens) > 0 and random.random() > 0.6
                and neighbors[0].GetAtomicNum() == 6):
            CanAddHalogen = True
            nextneighbors = neighbors[0].GetNeighbors()
            for nb in nextneighbors:
                if (nb.GetAtomicNum() != 6 and nb.GetIdx() != atom.GetIdx()):
                    CanAddHalogen = False
                    break
            if CanAddHalogen:
                atom.SetAtomicNum(random.choice(halogens))
                return mol

    # # # # # # # # #
    # Regular atom switching
    atnum = atom.GetAtomicNum()
    elems = [el for el in elements if el != atnum]

    for itry in range(50):
        cand = random.choice(elems)
        if MaxValence[cand] >= valence:
            atom.SetAtomicNum(cand)
            return mol

    if not changed:
        raise MutateFail()  # if here, mutation failed ...
    return mol
Exemple #9
0
def AddAtom(mol):
    # 5. add an atom
    atoms = GetAtoms(mol, notprop='protected')
    bonds = GetBonds(mol, notprop='group')
    if len(atoms) < 1: raise MutateFail()
    obj = random.choice(atoms + bonds)

    # If passed a bond, insert an atom into it
    if type(obj) == Chem.Bond:
        if obj.HasProp('group'):
            raise MutateFail(mol, 'Grouped bond passed to AddAtom')
        # note that we really nead the atoms here because the Idx may change
        # after adding a new atom to the molecule
        atom1 = obj.GetBeginAtom()
        atom2 = obj.GetEndAtom()
        mol.RemoveBond(atom1.GetIdx(), atom2.GetIdx())
        newatomid = mol.AddAtom(Chem.Atom(6))
        mol.AddBond(atom1.GetIdx(), newatomid, bondorder[1])
        mol.AddBond(atom2.GetIdx(), newatomid, bondorder[1])

    #Otherwise, make a new sidechain (or add a terminal atom)
    elif type(obj) == Chem.Atom and EmptyValence(obj) > 0:
        if obj.HasProp('protected'):
            raise MutateFatal(mol, 'Trying to add atom to protected atom.')

        # choose an atom to add
        atnum = obj.GetAtomicNum()
        elems = [el for el in elements if el != atnum]
        if atnum == 6:  # only add halogens to carbons
            elems.extend(halogens)
        cand = random.choice(elems)

        # and add it
        newatomid = mol.AddAtom(Chem.Atom(cand))
        mol.AddBond(obj.GetIdx(), newatomid, bondorder[1])
    else:
        raise MutateFail()
    return mol
Exemple #10
0
def AddFusionRing(mol):
    try:
        p = Chem.MolFromSmarts('[h]@&=*(@*)@[h]')
        matches = mol.GetSubstructMatches(p)
    except RuntimeError:
        raise MutateFail()

    if len(matches) == 0:
        raise MutateFail()

    match = random.choice(matches)

    if mol.GetAtomWithIdx(match[-1]).GetNumRadicalElectrons():
        raise MutateFail()

    def AwithLabel(label, idx=True):
        atom = filter(lambda atom: atom.HasProp(label), mol.GetAtoms())[0]
        if idx:
            return atom.GetIdx()
        else:
            return atom

    propene = Chem.MolFromSmiles('C=CC')
    propene.GetAtomWithIdx(0).SetBoolProp('propane1', True)
    propene.GetAtomWithIdx(2).SetBoolProp('propane2', True)
    mol.GetAtomWithIdx(match[3]).SetBoolProp('ah1', True)
    mol.GetAtomWithIdx(match[0]).SetBoolProp('ah2', True)
    mol = Chem.RWMol(Chem.CombineMols(mol, propene))
    try:
        mol.AddBond(AwithLabel('propane1'), AwithLabel('ah1'), bondorder[1])
        mol.AddBond(AwithLabel('propane2'), AwithLabel('ah2'), bondorder[1])
    except RuntimeError:
        raise MutateFail()
    finally:
        for prop in ['propane1', 'propane2', 'ah1', 'ah2']:
            AwithLabel(prop, idx=False).ClearProp(prop)

    return mol
Exemple #11
0
def AddAtom(mol, obj):
    # If passed a bond, insert an atom into it
    if type(obj) == Chem.Bond:
        if obj.HasProp('group'):
            raise MutateFail(mol, 'Grouped bond passed to AddAtom')
        # note that we really nead the atoms here because the Idx may change
        # after adding a new atom to the molecule
        atom1 = obj.GetBeginAtom()
        atom2 = obj.GetEndAtom()
        mol.RemoveBond(atom1.GetIdx(), atom2.GetIdx())
        newatomid = mol.AddAtom(Chem.Atom(6))
        mol.AddBond(atom1.GetIdx(), newatomid, bondorder[1])
        mol.AddBond(atom2.GetIdx(), newatomid, bondorder[1])

    #Otherwise, make a new sidechain (or add a terminal atom)
    elif type(obj) == Chem.Atom and EmptyValence(obj) > 0:
        if obj.HasProp('protected'):
            raise MutateFatal(mol, 'Trying to add atom to protected atom.')
        newatomid = mol.AddAtom(Chem.Atom(6))
        mol.AddBond(obj.GetIdx(), newatomid, bondorder[1])
    else:
        raise MutateFail()
    return mol
Exemple #12
0
    def __call__(self, mol):
        Chem.Kekulize(mol, True)
        try:
            mol = self.mutator(mol)
        except MutateFail as e:
            raise
        except RuntimeError as e:
            print "RuntimeError in Mutator:", self.mutator, self.name
            print "repr(e):", repr(e)
            raise MutateFail()
        except Exception as e:
            if 'MutateFail' in repr(e):
                raise MutateFail()
            else:
                raise

        if mol is None:
            raise MutateFail()

        mol = Finalize(mol, tautomerize=False, aromatic=False)

        if type(mol) == Chem.Mol:
            mol = Chem.RWMol(mol)
        return mol
Exemple #13
0
def DelBond(mol):
    bondringids = mol.GetRingInfo().BondRings()

    # need to flatten bondringids:
    if len(bondringids) > 0:
        # fancy manner to flatten a list of tuples with possible duplicates
        #bondringids = set.intersection(*map(set, bondringids))
        bondringids = set.union(*map(set, bondringids))
        bonds = GetIBonds(bondringids, mol, notprop='group')
    else:
        raise MutateFail()
    try:
        bond = random.choice(bonds)
    except IndexError:
        print bondringids
    mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())

    #print "succesful delbond:", Chem.MolToSmiles(mol)
    return mol
Exemple #14
0
def Finalize(mol, tautomerize=None, aromatic=aromaticity):
    ''' This function makes sure that a new mutated/crossover/fixfilter molecule:
        - corrects the implicit valence
        - removes data from parent molecules.
        - optionally converts the molecule to its canonical tautomer
        - checks if it is a valid molecule, i.e. Sanitize step. (without aromaticity)
    '''
    # 1.
    try:
        mol.UpdatePropertyCache()
    except ValueError:
        raise MutateFail(mol)

    # 2.
    RW = type(mol) == Chem.RWMol

    # 3.
    ResetProps(mol)

    # 4.
    if canonicalTautomer and not tautomerize is False:
        mol = Tautomerize(mol, aromatic)

    # 5.
    try:
        Sanitize(mol, aromatic)
    except Exception as e:
        print "Error in Finalize with", Chem.MolToSmiles(mol, False),
        if verbose: print e,
        if debug:
            for item in traceback.extract_stack():
                print item

    # 6.
    if aromatic: Chem.SetAromaticity(mol)

    # 7.
    if RW and not type(mol) == Chem.RWMol:
        return Chem.RWMol(mol)
    else:
        return mol
Exemple #15
0
def Tautomerize(mol):
    try:
        if mol.GetBoolProp('tautomerized'): return
    except KeyError:
        pass
    smi1 = Chem.MolToSmiles(mol)
    from molvs import Standardizer
    s = Standardizer()
    try:
        s.standardize(mol)
    except ValueError as e:
        MutateFail(mol)
        return False
    #from molvs.tautomer import TautomerCanonicalizer
    #t = TautomerCanonicalizer()
    #t.canonicalize(mol)
    mol.SetBoolProp('tautomerized', True)
    smi2 = Chem.MolToSmiles(mol)

    if not smi1 == smi2: print "tautomerized:", smi1, 'to:', smi2
    return True
Exemple #16
0
def SingleMutate(candidateraw):
    if candidateraw is None: raise ValueError('candidate is none')
    else: candidate = Chem.RWMol(candidateraw)
    global stats

    parent = candidate.GetProp('isosmi')
    ResetProps(candidate)
    change = False
    candidate.SetProp('parent', parent)

    for mutationtype, mutator in mutators.items():
        if random.random() < mutator.p:
            #print "in mutate:",  mutationtype, Chem.MolToSmiles(candidate),
            change = True
            stats[mutator.nname] += 1
            try:
                candidate = mutator(candidate)
            # I don't understand why these errors are not similar?! but this works
            except MutateFail as e:
                stats[mutator.nnameFail] += 1
            except Exception as e:
                if 'MutateFail' in repr(e):
                    #print "exotic MutateFail"
                    stats[mutator.nnameFail] += 1
                else:
                    print "Exception is not MutateFail!"
                    print e, repr(e), type(e)
                    raise

            # should we allow multiple mutation at the same time:
            # if not:
            # break

    if not change:
        stats['nNoMutation'] += 1
        raise MutateFail()
    return candidate
Exemple #17
0
def Tautomerize(mol, aromatic=aromaticity):
    try:
        if mol.GetBoolProp('tautomerized'): return mol
    except KeyError:
        pass


    Chem.SanitizeMol(mol)
    if not (aromatic or aromaticity):
        Chem.Kekulize(mol, True)

    smi1 = Chem.MolToSmiles(mol)
    from molvs import Standardizer
    s = Standardizer()
    try:
        molnew = s.standardize(mol)
    except ValueError as e:
        raise MutateFail(mol)

    if not aromatic:
        Chem.Kekulize(molnew, True)
    smi2 = Chem.MolToSmiles(molnew)

    if smi1 == smi2:
        # we return mol because it contains some properties
        # tautomerized mols need to get the props again
        mol.SetBoolProp('tautomerized', True)
        return mol
    else:
        if mol.HasProp('failedfilter'):
            ff = mol.GetProp('failedfilter')
            molnew.SetProp('failedfilter', ff)
        #print "tautomerized:", smi1, 'to:', smi2
        with open('tautomerized.smi', 'a') as f:
            f.write("{} {}\n".format(smi1, smi2))
        molnew.SetBoolProp('tautomerized', True)
        return molnew
Exemple #18
0
def SwitchAtom(mol, atom):
    if atom.HasProp('group') and not atom.HasProp('grouprep'):
        raise MutateFail(mol, 'protected or grouped atom passed to switchatom')

    changed = False
    neighbors=list(atom.GetNeighbors())

    # # # # # # # # # # # # #
    # from Filters import OptSulfone
    # Special rules for sulfurs that can optionally be sulfones
    #if atom.GetAtomicNum()==16 and len(OptSulfone)>0:
    #    SulfCand=set()
    #    for group in OptSulfone:
    #        for match in mol.GetSubstructMatches(group, True):
    #            for mat in GetIAtoms(match, mol):
    #                if mat.target.IsSulfur(): SulfCand.add(mat.target)
    #    if atom in SulfCand and random.random()>0.4:
    #        if atom.HasProp('grouprep'):
    #            RemoveGroup(mol,atom.GetProp('group'))
    #            return
    #        elif not atom.HasProp('group'):
    #            MakeSulfone(mol,atom)
    #            return

    #If it's a group representative, switching it will delete the
    #rest of the group; since they're hard to create, they're also
    #hard to destroy
    #if atom.HasProp('grouprep':
    #    if random.random()>0.3:
    #        RemoveGroup(mol,atom.GetProp('group'))
    #        changed=True
    #    else:
    #        raise MutateFail()

    # # # # # # # # # # # # # #
    #Special cases for Nitro groups and halogens,
    #which can only be on aromatic rings
    #if (  atom.GetExplicitValence()==1
    #      and neighbors[0].IsAromatic() ):

    # Add a halogen, if possible
    # we only add halogens when neighbor and neighbor-neighbor only C
    if atom.GetExplicitValence()==1:
        if (len(halogens)>0
        and random.random()>0.6
        and neighbors[0].GetAtomicNum()==6):
            CanAddHalogen=True
            nextneighbors=neighbors[0].GetNeighbors()
            for nb in nextneighbors:
                if (  nb.GetAtomicNum() != 6
                      and nb.GetIdx() != atom.GetIdx()):
                    CanAddHalogen=False
                    break
            if CanAddHalogen:
                atom.SetAtomicNum( random.choice(halogens))
                return

    # If not a halogen, maybe make a nitro group
    #    if random.random() < 0.15:
    #        MakeNitro(mol,atom)
    #        return

    # # # # # # # # #
    # Regular atom switching
    atnum = atom.GetAtomicNum()
    elems = [el for el in elements if el != atnum]

    for itry in range(50):
        cand = random.choice(elems)
        if MaxValence[cand] >= atom.GetExplicitValence():
            atom.SetAtomicNum(cand)
            return

    if not changed:
        raise MutateFail()  # if here, mutation failed ...
    return mol
Exemple #19
0
def RemoveAtom(mol, atom):
    #
    # Deal with special groups
    #
    if atom.HasProp('protected') or atom.HasProp('fixed'):
        raise MutateFatal(mol,
                          'Protected or fixed atom passed to' + " RemoveAtom.")
    Degree = atom.GetDegree()
    if debug: print "D{:d}".format(Degree)

    # If atom is the representative of a larger group (e.g. N in nitro group)
    # delete the entire group
    if atom.HasProp('grouprep'):
        groupnum = atom.GetProp('group')
        RemoveGroup(mol, groupnum)

    #If there's only one atom, refuse to remove it
    if len(atom.GetNeighbors()) == 0:
        raise MutateFail(mol)

    #Remove a terminal atom:
    elif Degree == 1:
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())

    # until here it seems fine

    #Remove an in-chain atom:
    #
    #NOT WORKING WELL
    elif Degree == 2:
        #print Chem.MolToSmiles(mol, True)
        nbr = []
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        # this line give indexerrors:
        mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
    elif True:
        pass

    #Remove a 3-bond atom:
    elif Degree == 3:
        nbr = []
        nbrCarbon = []
        nChoice = 3
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
            if neighb.GetAtomicNum()==6 and \
                   len(neighb.GetNeighbors())==3:
                nChoice = nChoice + 1
                nbrCarbon.append(neighb)
        choose = random.randrange(0, nChoice, 1)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetBeginAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        if choose == 0:
            mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
            mol.AddBond(nbr[1].GetIdx(), nbr[2].GetIdx(), bondorder[1])
        elif choose == 1:
            mol.AddBond(nbr[0].GetIdx(), nbr[2].GetIdx(), bondorder[1])
            mol.AddBond(nbr[2].GetIdx(), nbr[1].GetIdx(), bondorder[1])
        elif choose == 2:
            mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
            mol.AddBond(nbr[2].GetIdx(), nbr[0].GetIdx(), bondorder[1])
        else:
            for neighb in nbr:
                if not neighb.GetIdx() == nbrCarbon[choose - 3].GetIdx():
                    mol.AddBond(neighb.GetIdx(),
                                nbrCarbon[choose - 3].GetIdx(), bondorder[1])

    #Remove a 4-bond atom
    elif Degree == 4:
        nbr = []
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        n1 = nbr.pop(random.randrange(0, 4, 1))

        if random.random() < 0.75:  #XA4 -> A-A-A-A
            n2 = nbr.pop(random.randrange(0, 3, 1))
            mol.AddBond(n1.GetIdx(), n2.GetIdx(), bondorder[1])
            n3 = nbr.pop(random.randrange(0, 2, 1))
            mol.AddBond(n2.GetIdx(), n3.GetIdx(), bondorder[1])
            mol.AddBond(n3.GetIdx(), nbr[0].GetIdx(), bondorder[1])
        else:  #XA4 -> A(A3)
            for neighb in nbr:
                mol.AddBond(n1.GetIdx(), neighb.GetIdx(), bondorder[1])

    #Make sure nothing is bonded twice
    oldpairs = []
    todelete = []
    for bond in mol.GetBonds():
        pair = [bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()]
        pair.sort()
        if pair in oldpairs: todelete.append(bond)
        else: oldpairs.append(pair)
    for bond in todelete:
        mol.RemoveBond(bond.GetIdx())

    # Make sure bonding makes sense
    for atom in mol.GetAtoms():
        try:
            if EmptyValence(atom) < 0:
                for bond in atom.GetBonds():
                    if not bond.HasProp('group'):
                        bond.SetBondType(bondorder[1])
                if EmptyValence(atom) < 0: raise MutateFail(mol)
        except KeyError:
            raise MutateFail(mol)

    try:
        Finalize(mol, aromatic=False)
    except Exception as e:
        print "in Remove Atom with:", Chem.MolToSmiles(mol, True), e
    return mol
Exemple #20
0
def Crossover(m1, m2):
    #Kekulize mols:
    for m in (m1, m2):
        Chem.Kekulize(m, True)
    #Fragment molecules
    m1fs = GetFragment(m1)
    m2fs = GetFragment(m2)
    if debug: print "CX1",
    #print "in Crossover:", m1fs, m2fs

    #pick fragments for crossover checking:
    # 1. Molecular weight
    Choices = []
    #maxWeight = mprms.maxWeight
    if maxWeight > 0:
        w1 = [Descriptors.MolWt(f) for f in m1fs]
        w2 = [Descriptors.MolWt(f) for f in m2fs]
        for i, j in ((i, j) for i in xrange(2) for j in xrange(2)):
            if w1[i] + w2[j] < maxWeight + 50.0: Choices.append((i, j))
    # 2. Number of Atoms
    #MxAtm=mprms.MxAtm
    if MxAtm > 0:
        a1 = [f.GetNumAtoms() for f in m1fs]
        a2 = [f.GetNumAtoms() for f in m2fs]
        for i, j in ((i, j) for i in xrange(2) for j in xrange(2)):
            if a1[i] + a2[j] < MxAtm + 4: Choices.append((i, j))

    if len(Choices) == 0:
        raise MutateFail()
    else:
        choice = random.choice(Choices)
        mol1 = m1fs[choice[0]]
        mol2 = m2fs[choice[1]]

    # now mol2 has to be connected to mol1
    # but what happens here?
    mol1.SetProp('parent1', m1.GetProp('isosmi'))
    mol2.SetProp('parent2', m2.GetProp('isosmi'))
    if debug: print "CX2",
    '''
    if mol1.HasProp('groups'):
        m1groups=[ groupid for groupid in mol1.GetProp('groups')
                   if len(MolAtIsInGroup(mol1, groupid))>0 ]
        mol1.ClearProp('groups')
    else:
        m1groups=[]
    igrp=1
    if mol2.HasProp('groups'):
        for groupnum in mol2.GetProp('groups'):
            m2groups=mol2.GetProp('groups')
            if len(MolAtIsInGroup(mol2, groupnum))==0: continue
            if groupnum in m1groups: #need to reassign group id
                while igrp in m1groups+m2groups: igrp+=1
                m1groups.append(igrp)
                for atom in MolAtIsInGroup(mol2, groupnum):
                    atom.SetProp('group',igrp)
                for bond in MolBondIsInGroup(mol2, groupnum):
                    bond.SetProp('group',igrp)
                m2groups.append(igrp)
                m2groups.remove(groupnum)
            else:
                m1groups.append(groupnum)
        if len(m2groups)>0: mol2.SetProp('groups',m2groups)
    if len(m1groups)>0: mol1.SetProp('groups',m1groups)
    '''

    ###################################
    #Append molecule 2 to molecule 1.
    newmol = Chem.CombineMols(mol1, mol2)
    newids = Chem.GetMolFrags(newmol)

    # Now, bond the two fragments to create the child molecule.
    # We choose a random pair of possible atoms to do the attachment;
    possibleA1 = [
        atom for atom in GetIAtoms(newids[0], newmol) if EmptyValence(atom) > 0
    ]
    possibleA2 = [
        atom for atom in GetIAtoms(newids[1], newmol) if EmptyValence(atom) > 0
    ]

    if len(possibleA1) == 0 or len(possibleA2) == 0:
        #print "no possible atoms!"
        raise MutateFail()
    if debug: print "CX3",
    newmolRW = Chem.RWMol(newmol)
    atom1 = random.choice(possibleA1)
    atom2 = random.choice(possibleA2)
    newmolRW.AddBond(atom1.GetIdx(), atom2.GetIdx(), Chem.BondType.SINGLE)
    if debug: print "CX4",

    #print "new mol!", Chem.MolToSmiles(newmolRW)
    mol = newmolRW.GetMol()
    try:
        Finalize(mol, aromatic=False)
    except:
        raise MutateFail()
    if debug: print "CX5",
    return mol
Exemple #21
0
def DelAtom(mol):
    inismi = Chem.MolToSmiles(mol)
    atoms = filter(CanRemoveAtom, mol.GetAtoms())
    if len(atoms) == 1:
        raise MutateFail()

    atom = random.choice(atoms)

    # or GetTotalDegree?
    #Degree = atom.GetDegree() + atom.GetNumRadicalElectrons()
    Degree = atom.GetDegree()

    #If there's only one atom, refuse to remove it
    if len(atom.GetNeighbors()) == 0:
        raise MutateFail(mol)

    #Remove a terminal atom:
    elif Degree == 1:
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())

    # until here it seems fine

    #Remove an in-chain atom:
    #
    #NOT WORKING WELL
    elif Degree == 2:
        #print Chem.MolToSmiles(mol, True)
        nbr = []
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        # this line give indexerrors:
        mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
    elif True:
        pass

    #Remove a 3-bond atom:
    elif Degree == 3:
        nbr = []
        nbrCarbon = []
        nChoice = 3
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
            if neighb.GetAtomicNum()==6 and \
                   len(neighb.GetNeighbors())==3:
                nChoice = nChoice + 1
                nbrCarbon.append(neighb)
        choose = random.randrange(0, nChoice, 1)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetBeginAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        if choose == 0:
            mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
            mol.AddBond(nbr[1].GetIdx(), nbr[2].GetIdx(), bondorder[1])
        elif choose == 1:
            mol.AddBond(nbr[0].GetIdx(), nbr[2].GetIdx(), bondorder[1])
            mol.AddBond(nbr[2].GetIdx(), nbr[1].GetIdx(), bondorder[1])
        elif choose == 2:
            mol.AddBond(nbr[0].GetIdx(), nbr[1].GetIdx(), bondorder[1])
            mol.AddBond(nbr[2].GetIdx(), nbr[0].GetIdx(), bondorder[1])
        else:
            for neighb in nbr:
                if not neighb.GetIdx() == nbrCarbon[choose - 3].GetIdx():
                    mol.AddBond(neighb.GetIdx(),
                                nbrCarbon[choose - 3].GetIdx(), bondorder[1])

    #Remove a 4-bond atom
    elif Degree == 4:
        nbr = []
        for neighb in atom.GetNeighbors():
            nbr.append(neighb)
        for bond in atom.GetBonds():
            mol.RemoveBond(bond.GetBeginAtomIdx(), bond.GetEndAtomIdx())
        mol.RemoveAtom(atom.GetIdx())
        n1 = nbr.pop(random.randrange(0, 4, 1))

        if random.random() < 0.75:  #XA4 -> A-A-A-A
            n2 = nbr.pop(random.randrange(0, 3, 1))
            mol.AddBond(n1.GetIdx(), n2.GetIdx(), bondorder[1])
            n3 = nbr.pop(random.randrange(0, 2, 1))
            mol.AddBond(n2.GetIdx(), n3.GetIdx(), bondorder[1])
            mol.AddBond(n3.GetIdx(), nbr[0].GetIdx(), bondorder[1])
        else:  #XA4 -> A(A3)
            for neighb in nbr:
                mol.AddBond(n1.GetIdx(), neighb.GetIdx(), bondorder[1])

    #Make sure nothing is bonded twice
    oldpairs = []
    todelete = []
    for bond in mol.GetBonds():
        pair = [bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()]
        pair.sort()
        if pair in oldpairs: todelete.append(bond)
        else: oldpairs.append(pair)
    for bond in todelete:
        mol.RemoveBond(bond.GetIdx())

    # Make sure bonding makes sense
    for atom in mol.GetAtoms():
        try:
            if EmptyValence(atom) < 0:
                for bond in atom.GetBonds():
                    if not bond.HasProp('group'):
                        bond.SetBondType(bondorder[1])
                if EmptyValence(atom) < 0: raise MutateFail(mol)
        except KeyError:
            raise MutateFail(mol)

    if debug:  # print a file with the results from these mutations:
        with open('delatoms.smi', 'a') as f:
            f.write(Chem.MolToSmiles(mol) + '\n')
    return mol