Exemplo n.º 1
0
    def test_c5h6o(self):
        inchi = "InChI=1S/C5H6O/c6-5-3-1-2-4-5/h1-3,5H,4H2"
        mol = Molecule().from_inchi(inchi)
        start = mol.atoms[1]
        path = find_allyl_end_with_charge(start)[0]
        idx_path = [mol.atoms.index(atom) + 1 for atom in path[0::2]]

        expected_idx_path = [2, 1, 3]
        self.assertEquals(idx_path, expected_idx_path)
Exemplo n.º 2
0
    def test_c3h4o4(self):
        inchi = "InChI=1S/C3H4O4/c4-3(5)1-2-7-6/h1-3,6H"
        mol = Molecule().from_inchi(inchi)
        start = mol.atoms[6]
        path = find_allyl_end_with_charge(start)[0]
        idx_path = [mol.atoms.index(atom) + 1 for atom in path[0::2]]

        expected_idx_path = [7, 2, 1]
        self.assertEquals(idx_path, expected_idx_path)
Exemplo n.º 3
0
    def test_c3h4(self):
        inchi = "InChI=1S/C3H4/c1-3-2/h1,3H,2H2"
        mol = Molecule().from_inchi(inchi)
        start = mol.atoms[0]
        path = find_allyl_end_with_charge(start)[0]
        idx_path = [mol.atoms.index(atom) + 1 for atom in path[0::2]]

        expected_idx_path = [1, 3, 2]
        self.assertEquals(idx_path, expected_idx_path)
Exemplo n.º 4
0
def fix_oxygen_unsaturated_bond(mol, u_indices):
    """
    Searches for a radical or a charged oxygen atom connected to 
    a closed-shell carbon via an unsatured bond.

    Decrements the unsatured bond,
    transfers the unpaired electron from O to C or
    converts the charge from O to an unpaired electron on C, 
    increases the lone pair count of O to 2.

    Only do this once per molecule.
    """

    for at in mol.atoms:
        if at.isOxygen() and at.radicalElectrons == 1 and at.lonePairs == 1:
            bonds = mol.getBonds(at)
            oxygen = at
            for atom2, bond in bonds.iteritems():
                if bond.isTriple():
                    bond.decrementOrder()
                    oxygen.radicalElectrons -= 1
                    atom2.radicalElectrons += 1
                    oxygen.lonePairs += 1
                    return
        elif at.isOxygen() and at.charge == 1 and at.lonePairs == 1:
            bonds = mol.getBonds(at)
            oxygen = at

            start = oxygen
            # search for 3-atom-2-bond [X=X-X] paths
            paths = pathfinder.find_allyl_end_with_charge(start)
            for path in paths:    
                end = path[-1]
                start.charge += 1 if start.charge < 0 else -1
                end.charge += 1 if end.charge < 0 else -1
                start.lonePairs += 1
                # filter bonds from path and convert bond orders:
                bonds = path[1::2]#odd elements
                for bond in bonds[::2]:# even bonds
                    assert isinstance(bond, Bond)
                    bond.decrementOrder()
                for bond in bonds[1::2]:# odd bonds
                    assert isinstance(bond, Bond)
                    bond.incrementOrder()  
                return
            else:
                for atom2, bond in bonds.iteritems():
                    if not bond.isSingle() and atom2.charge == 0:
                        oxygen.charge -= 1
                        if (mol.atoms.index(atom2) + 1) in u_indices:
                            bond.decrementOrder()
                            atom2.radicalElectrons += 1
                            u_indices.remove(mol.atoms.index(atom2) + 1)
                        oxygen.lonePairs += 1
                        return
Exemplo n.º 5
0
def fix_oxygen_unsaturated_bond(mol, u_indices):
    """
    Searches for a radical or a charged oxygen atom connected to 
    a closed-shell carbon via an unsatured bond.

    Decrements the unsatured bond,
    transfers the unpaired electron from O to C or
    converts the charge from O to an unpaired electron on C, 
    increases the lone pair count of O to 2.

    Only do this once per molecule.
    """

    for at in mol.atoms:
        if at.isOxygen() and at.radicalElectrons == 1 and at.lonePairs == 1:
            bonds = mol.getBonds(at)
            oxygen = at
            for atom2, bond in bonds.iteritems():
                if bond.isTriple():
                    bond.decrementOrder()
                    oxygen.radicalElectrons -= 1
                    atom2.radicalElectrons += 1
                    oxygen.lonePairs += 1
                    return
        elif at.isOxygen() and at.charge == 1 and at.lonePairs == 1:
            bonds = mol.getBonds(at)
            oxygen = at

            start = oxygen
            # search for 3-atom-2-bond [X=X-X] paths
            paths = pathfinder.find_allyl_end_with_charge(start)
            for path in paths:    
                end = path[-1]
                start.charge += 1 if start.charge < 0 else -1
                end.charge += 1 if end.charge < 0 else -1
                start.lonePairs += 1
                # filter bonds from path and convert bond orders:
                bonds = path[1::2]#odd elements
                for bond in bonds[::2]:# even bonds
                    assert isinstance(bond, Bond)
                    bond.decrementOrder()
                for bond in bonds[1::2]:# odd bonds
                    assert isinstance(bond, Bond)
                    bond.incrementOrder()  
                return
            else:
                for atom2, bond in bonds.iteritems():
                    if not bond.isSingle() and atom2.charge == 0:
                        oxygen.charge -= 1
                        if (mol.atoms.index(atom2) + 1) in u_indices:
                            bond.decrementOrder()
                            atom2.radicalElectrons += 1
                            u_indices.remove(mol.atoms.index(atom2) + 1)
                        oxygen.lonePairs += 1
                        return
Exemplo n.º 6
0
    def test_c2h2o3(self):
        adjlist = """
1 C u0 p0 c0 {5,D} {6,S} {7,S}
2 C u0 p0 c0 {3,D} {4,S} {5,S}
3 O u0 p2 c0 {2,D}
4 O u0 p3 c-1 {2,S}
5 O u0 p1 c+1 {1,D} {2,S}
6 H u0 p0 c0 {1,S}
7 H u0 p0 c0 {1,S}
        """

        mol = Molecule().from_adjacency_list(adjlist)
        start = mol.atoms[2]
        paths = find_allyl_end_with_charge(start)
        idx_path = sorted([[mol.atoms.index(atom) + 1 for atom in path[0::2]] for path in paths])

        expected_idx_path = [[3, 2, 4], [3, 2, 5]]
        self.assertEquals(idx_path, expected_idx_path)
Exemplo n.º 7
0
    def test_c3h2o3(self):
        adjlist = """
1 C u0 p0 c0 {2,D} {7,S} {8,S}
2 C u0 p0 c0 {1,D} {3,D}
3 C u0 p0 c0 {2,D} {4,S} {6,S}
4 O u0 p3 c-1 {3,S}
5 O u0 p2 c0 {6,D}
6 O u0 p1 c+1 {3,S} {5,D}
7 H u0 p0 c0 {1,S}
8 H u0 p0 c0 {1,S}
        """

        mol = Molecule().from_adjacency_list(adjlist)
        start = mol.atoms[1]
        paths = find_allyl_end_with_charge(start)
        idx_paths = sorted([[mol.atoms.index(atom) + 1 for atom in path[0::2]] for path in paths])
        idx_paths = sorted(idx_paths)

        expected_idx_paths = [[2, 3, 4], [2, 3, 6]]
        self.assertEquals(idx_paths, expected_idx_paths)
Exemplo n.º 8
0
def _convert_3_atom_2_bond_path(start, mol):
    """
    Searches for 3-atom-2-bond [X=X-X+] paths paths starting from the parameter atom.
    If a correct path is found, the starting atom receives an unpaired electron while
    the bonds in the delocalization path are "inverted". A unit of charge on the
    end atom is neutralized and a lone pair is added.

    If it turns out the path was invalid, the actions are reverted, and another path
    is tried instead.

    To facilitate reverting the changes, we use a reaction recipe and populate it
    with a number of actions that reflect the changes in bond orders and unpaired
    electrons that the molecule should undergo.
    """
    from rmgpy.data.kinetics.family import ReactionRecipe

    def is_valid(mol):
        """Check if total bond order of oxygen atoms is smaller than 4."""

        for at in mol.atoms:
            if at.number == 8:
                order = at.get_total_bond_order()
                not_correct = order >= 4
                if not_correct:
                    return False

        return True

    paths = pathfinder.find_allyl_end_with_charge(start)

    for path in paths:
        # label atoms so that we can use the labels in the actions of the recipe
        for i, at in enumerate(path[::2]):
            at.label = str(i)
        # we have found the atom we are looking for
        recipe = ReactionRecipe()
        recipe.add_action(['GAIN_RADICAL', start.label, 1])

        end = path[-1]
        end_original_charge = end.charge

        # filter bonds from path and convert bond orders:
        bonds = path[1::2]  # odd elements
        for bond in bonds[::2]:  # even
            recipe.add_action(
                ['CHANGE_BOND', bond.atom1.label, -1, bond.atom2.label])
        for bond in bonds[1::2]:  # odd
            recipe.add_action(
                ['CHANGE_BOND', bond.atom1.label, 1, bond.atom2.label])

        end.charge += 1 if end.charge < 0 else -1
        recipe.apply_forward(mol)

        if is_valid(mol):
            # unlabel atoms so that they never cause trouble downstream
            for i, at in enumerate(path[::2]):
                at.label = ''
            return True
        else:
            recipe.apply_reverse(mol)
            end.charge = end_original_charge

            # unlabel atoms so that they never cause trouble downstream
            for i, at in enumerate(path[::2]):
                assert isinstance(at, Atom)
                at.label = ''

    return False
Exemplo n.º 9
0
def convert_3_atom_2_bond_path(start, mol):
    """
    Searches for 3-atom-2-bond [X=X-X+] paths paths starting from the parameter atom.
    If a correct path is found, the starting atom receives an unpaired electron while
    the bonds in the delocalization path are "inverted". A unit of charge on the 
    end atom is neutralized and a lone pair is added.

    If it turns out the path was invalid, the actions are reverted, and another path
    is tried instead.

    To facilitate reverting the changes, we use a reaction recipe and populate it
    with a number of actions that reflect the changes in bond orders and unpaired
    electrons that the molecule should undergo.
    """
    from rmgpy.data.kinetics.family import ReactionRecipe

    def is_valid(mol):
        """Check if total bond order of oxygen atoms is smaller than 4."""

        for at in mol.atoms:
            if at.number == 8:
                order = sum([bond_orders[b.order] for _, b in at.bonds.iteritems()])
                not_correct = order >= 4
                if not_correct:
                    return False

        return True

    index = mol.atoms.index(start) + 1

    paths = pathfinder.find_allyl_end_with_charge(start)

    for path in paths:
        # label atoms so that we can use the labels in the actions of the recipe
        for i, at in enumerate(path[::2]):
            at.label = str(i)
        # we have found the atom we are looking for
        recipe = ReactionRecipe()
        recipe.addAction(['GAIN_RADICAL', start.label, 1])

        end = path[-1]
        end_original_charge = end.charge
      
        # filter bonds from path and convert bond orders:
        bonds = path[1::2]#odd elements
        for bond in bonds[::2]:# even
            recipe.addAction(['CHANGE_BOND', bond.atom1.label, -1, bond.atom2.label])
        for bond in bonds[1::2]:# odd
            recipe.addAction(['CHANGE_BOND', bond.atom1.label, 1, bond.atom2.label])

        end.charge += 1 if end.charge < 0 else -1
        recipe.applyForward(mol)

        if is_valid(mol):
            # unlabel atoms so that they never cause trouble downstream
            for i, at in enumerate(path[::2]):
                at.label = ''
            return True
        else:
            recipe.applyReverse(mol)
            end.charge = end_original_charge

            # unlabel atoms so that they never cause trouble downstream
            for i, at in enumerate(path[::2]):
                assert isinstance(at, Atom)
                at.label = ''

    return False