Skip to content

Commit

Permalink
Fix get_labeled_reactants_and_products for new families
Browse files Browse the repository at this point in the history
The R_Recombination family was changed for auto tree generation
There is only a single template now, and duplicate * labels
This copies template handling from __generate_reactions
A unit test is also added
  • Loading branch information
mliu49 committed Oct 21, 2019
1 parent 1d1920a commit 1a236da
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 8 deletions.
31 changes: 23 additions & 8 deletions rmgpy/data/kinetics/family.py
Original file line number Diff line number Diff line change
Expand Up @@ -2619,22 +2619,37 @@ def get_labeled_reactants_and_products(self, reactants, products):
template = self.forward_template
reactants0 = [reactant.copy(deep=True) for reactant in reactants]

if self.auto_generated and self.reactant_num != len(reactants):
return None, None

if len(reactants) > len(template.reactants):
# if the family has one template and is bimolecular split template into multiple reactants
try:
grps = template.reactants[0].item.split()
template_reactants = []
for grp in grps:
template_reactants.append(grp)
except AttributeError:
template_reactants = [x.item for x in template.reactants]
else:
template_reactants = [x.item for x in template.reactants]

if len(reactants0) == 1:
molecule = reactants0[0]
mappings = self._match_reactant_to_template(molecule, template.reactants[0].item)
mappings = self._match_reactant_to_template(molecule, template_reactants[0])
mappings = [[map0] for map0 in mappings]
num_mappings = len(mappings)
reactant_structures = [molecule]
elif len(reactants0) == 2:
molecule_a = reactants0[0]
molecule_b = reactants0[1]
# get mappings in forward direction
mappings_a = self._match_reactant_to_template(molecule_a, template.reactants[0].item)
mappings_b = self._match_reactant_to_template(molecule_b, template.reactants[1].item)
mappings_a = self._match_reactant_to_template(molecule_a, template_reactants[0])
mappings_b = self._match_reactant_to_template(molecule_b, template_reactants[1])
mappings = list(itertools.product(mappings_a, mappings_b))
# get mappings in the reverse direction
mappings_a = self._match_reactant_to_template(molecule_a, template.reactants[1].item)
mappings_b = self._match_reactant_to_template(molecule_b, template.reactants[0].item)
mappings_a = self._match_reactant_to_template(molecule_a, template_reactants[1])
mappings_b = self._match_reactant_to_template(molecule_b, template_reactants[0])
mappings.extend(list(itertools.product(mappings_a, mappings_b)))

reactant_structures = [molecule_a, molecule_b]
Expand All @@ -2646,9 +2661,9 @@ def get_labeled_reactants_and_products(self, reactants, products):
# Get mappings for all permutations of reactants
mappings = []
for order in itertools.permutations(range(3), 3):
mappings_a = self._match_reactant_to_template(molecule_a, template.reactants[order[0]].item)
mappings_b = self._match_reactant_to_template(molecule_b, template.reactants[order[1]].item)
mappings_c = self._match_reactant_to_template(molecule_c, template.reactants[order[2]].item)
mappings_a = self._match_reactant_to_template(molecule_a, template_reactants[order[0]])
mappings_b = self._match_reactant_to_template(molecule_b, template_reactants[order[1]])
mappings_c = self._match_reactant_to_template(molecule_c, template_reactants[order[2]])
mappings.extend(list(itertools.product(mappings_a, mappings_b, mappings_c)))

reactant_structures = [molecule_a, molecule_b, molecule_c]
Expand Down
66 changes: 66 additions & 0 deletions rmgpy/data/kinetics/familyTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,72 @@ def test_add_atom_labels_for_reaction(self):

self.assertTrue(expected_products[i].is_isomorphic(product.molecule[0], mapping))

def test_add_atom_labels_for_reaction_r_recombination(self):
"""Test that we can add atom labels to an existing R_Recombination reaction"""
reactants = [Species().from_smiles('C[CH2]'), Species().from_smiles('[CH3]')]
products = [Species().from_smiles('CCC')]

reaction = TemplateReaction(reactants=reactants, products=products)

self.database.kinetics.families['R_Recombination'].add_atom_labels_for_reaction(reaction)

expected_reactants = [
Molecule().from_adjacency_list("""
multiplicity 2
1 C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 * C u1 p0 c0 {1,S} {6,S} {7,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
"""),
Molecule().from_adjacency_list("""
multiplicity 2
1 * C u1 p0 c0 {2,S} {3,S} {4,S}
2 H u0 p0 c0 {1,S}
3 H u0 p0 c0 {1,S}
4 H u0 p0 c0 {1,S}
""")]

expected_products = [
Molecule().from_adjacency_list("""
1 * C u0 p0 c0 {2,S} {3,S} {4,S} {5,S}
2 * C u0 p0 c0 {1,S} {6,S} {7,S} {8,S}
3 C u0 p0 c0 {1,S} {9,S} {10,S} {11,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {2,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
9 H u0 p0 c0 {3,S}
10 H u0 p0 c0 {3,S}
11 H u0 p0 c0 {3,S}
""")]

for i, reactant in enumerate(reaction.reactants):
mapping = {}
for label, atom in expected_reactants[i].get_all_labeled_atoms().items():
mapping[atom] = reactant.molecule[0].get_labeled_atoms(label)[0]

self.assertTrue(expected_reactants[i].is_isomorphic(reactant.molecule[0], mapping))

for i, product in enumerate(reaction.products):
# There are two identical labels in the product, so we need to check both mappings
# Only one of the mappings will result in isomorphic structures though
atoms_a = expected_products[i].get_labeled_atoms('*')
atoms_b = product.molecule[0].get_labeled_atoms('*')
mapping1 = {atoms_a[0]: atoms_b[0], atoms_a[1]: atoms_b[1]}
mapping2 = {atoms_a[0]: atoms_b[1], atoms_a[1]: atoms_b[0]}

results = [
expected_products[i].is_isomorphic(product.molecule[0], mapping1),
expected_products[i].is_isomorphic(product.molecule[0], mapping2)
]

self.assertTrue(any(results))
self.assertFalse(all(results))

def test_irreversible_reaction(self):
"""Test that the Singlet_Val6_to_triplet and 1,2-Birad_to_alkene families generate irreversible reactions."""

Expand Down

0 comments on commit 1a236da

Please sign in to comment.