In [ ]:
from rmgpy.molecule import Molecule
from rmgpy.molecule.resonance import *

from IPython.display import display
import pdb

In [ ]:
mol = Molecule(SMILES='C1=CC2=CC=C3C=CC=C4C=CC(=C1)C2=C43')
out = generateAromaticResonanceStructures(mol)
display(out[0])
kekulize(out[0])
display(out[0])

In [ ]:
def kekulize(self):
    from rmgpy.molecule import PeriodicSystem
    import numpy as np
    import itertools

    rings = self.getAllCyclesOfSize(6)

    # We want to identify all aromatic rings, especially ones that have been modified
    aromaticRings = []
    invalidRings = []
    for ring in rings:
        endoBonds = set()
        exoBonds = set()
        aromatic = True
        valid = True
        for atom1 in ring:
            for atom2, bond in atom1.bonds.iteritems():
                if atom2 in ring:
                    if bond.order[0] != 'B':
                        aromatic = False
                        break
                    elif bond.order == 'B+' or bond.order == 'B-':
                        valid = False
                    endoBonds.add(bond)
                else:
                    exoBonds.add(bond)
            if not aromatic:
                break
        if aromatic:
            if valid:
                aromaticRings.append((ring, list(endoBonds), list(exoBonds)))
            else:
                invalidRings.append((ring, list(endoBonds), list(exoBonds)))

    bondOrders = {'S': 1, 'D': 2, 'T': 3, 'B': 1.5}
    bondOrdersInv = {1: 'S', 2: 'D', 3: 'T'}
    valences = PeriodicSystem.valences

    for ring, endo, exo in itertools.chain(invalidRings, aromaticRings):
        print 'Solving ring...'
        exoAromatic = sum([1 for bond in exo if bond.order == 'B'])
        print 'There are {} exocyclic aromatic bonds.'.format(exoAromatic)
        endoNonArom = sum([bondOrders[bond.order] for bond in endo if bond.order[0] != 'B'])
        print 'Endocyclic Bond:' + '-'.join([bond.order for bond in endo])

        a = []
        b = []
        for atom in ring:
            a.append([1 if atom in [bond.atom1, bond.atom2] else 0 for bond in endo])
            v = valences[atom.element.symbol]
            for bond in atom.bonds.itervalues():
                if bond in exo:
                    if exoAromatic == 1:
                        v -= np.ceil(bondOrders[bond.order])
                    else:
                        v -= np.floor(bondOrders[bond.order])
            v -= atom.radicalElectrons
            b.append(v)
        constraints = []
        for index, bond in enumerate(endo):
            if bond.order == 'B-':
                # Must become single bond
                new_a = [0] * len(endo)
                new_a[index] = 1
                constraints.append((new_a, 1))
            elif bond.order == 'B+':
                # Must become double bond
                new_a = [0] * len(endo)
                new_a[index] = 1
                constraints.append((new_a, 2))
            elif bond.order != 'B':
                # Bond has already been altered, so keep the new order
                new_a = [0] * len(endo)
                new_a[index] = 1
                constraints.append((new_a, bondOrders[bond.order]))
        if len(constraints) == 0:
            # Move on to next ring and come back later
            print 'No constraints, picking arbitrary constraint.'
            # Pick an arbitrary bond to constrain
            index = 0
            new_a = [0] * len(endo)
            new_a[index] = 1
            constraints.append((new_a, 2))
        for new_a, new_b in constraints:
            a.append(new_a)
            b.append(new_b)

        a = np.array(a)
        b = np.array(b)

        x = np.rint(np.dot(np.linalg.pinv(a), b)).tolist()

        for index, bond in enumerate(endo):
            try:
                bond.order = bondOrdersInv[x[index]]
            except KeyError:
                pdb.set_trace()

In [ ]: