def test_ensure_independent_atom_ids(self): """ Ensure ensure_independent_atom_ids modifies atomlabels """ s1 = Species().fromSMILES('CCC') s2 = Species().fromSMILES('C=C[CH]C') self.assertEqual(s2.molecule[0].atoms[0].id, -1) ensure_independent_atom_ids([s1, s2]) # checks atom id self.assertNotEqual(s2.molecule[0].atoms[0].id, -1) # checks second resonance structure id self.assertNotEqual(s2.molecule[1].atoms[0].id, -1)
def test_ensure_independent_atom_ids_no_resonance(self): """ Ensure ensure_independent_atom_ids does not generate resonance """ s1 = Species().fromSMILES('CCC') s2 = Species().fromSMILES('C=C[CH]C') self.assertEqual(s2.molecule[0].atoms[0].id, -1) ensure_independent_atom_ids([s1, s2], resonance=False) # checks resonance structures self.assertEqual(len(s2.molecule), 1) # checks that atom ids are changed for atom in s2.molecule[0].atoms: self.assertNotEqual(atom.id, -1)
def test_ensure_independent_atom_ids_no_resonance(self): """ Ensure ensure_independent_atom_ids does not generate resonance """ s1 = Species().fromSMILES('CCC') s2 = Species().fromSMILES('C=C[CH]C') self.assertEqual(s2.molecule[0].atoms[0].id, -1) ensure_independent_atom_ids([s1, s2],resonance=False) # checks resonance structures self.assertEqual(len(s2.molecule),1) # checks that atom ids are changed for atom in s2.molecule[0].atoms: self.assertNotEqual(atom.id, -1)
def generate_reactions_from_families(self, reactants, products=None, only_families=None, resonance=True): """ Generate all reactions between the provided list or tuple of one or two `reactants`, which can be either :class:`Molecule` objects or :class:`Species` objects. This method can apply all kinetics families or a selected subset. Args: reactants: Molecules or Species to react products: List of Molecules or Species of desired product structures (optional) only_families: List of family labels to generate reactions from (optional) Default is to generate reactions from all families resonance: Flag to generate resonance structures for reactants and products (optional) Default is True, resonance structures will be generated Returns: List of reactions containing Species objects with the specified reactants and products. """ # Check if the reactants are the same # If they refer to the same memory address, then make a deep copy so # they can be manipulated independently if isinstance(reactants, tuple): reactants = list(reactants) same_reactants = 0 if len(reactants) == 2: if reactants[0] is reactants[1]: reactants[1] = reactants[1].copy(deep=True) same_reactants = 2 elif reactants[0].is_isomorphic(reactants[1]): same_reactants = 2 elif len(reactants) == 3: same_01 = reactants[0] is reactants[1] same_02 = reactants[0] is reactants[2] if same_01 and same_02: same_reactants = 3 reactants[1] = reactants[1].copy(deep=True) reactants[2] = reactants[2].copy(deep=True) elif same_01: same_reactants = 2 reactants[1] = reactants[1].copy(deep=True) elif same_02: same_reactants = 2 reactants[2] = reactants[2].copy(deep=True) elif reactants[1] is reactants[2]: same_reactants = 2 reactants[2] = reactants[2].copy(deep=True) else: same_01 = reactants[0].is_isomorphic(reactants[1]) same_02 = reactants[0].is_isomorphic(reactants[2]) if same_01 and same_02: same_reactants = 3 elif same_01 or same_02: same_reactants = 2 elif reactants[1].is_isomorphic(reactants[2]): same_reactants = 2 # Label reactant atoms for proper degeneracy calculation (cannot be in tuple) ensure_independent_atom_ids(reactants, resonance=resonance) combos = generate_molecule_combos(reactants) reaction_list = [] for combo in combos: reaction_list.extend( self.react_molecules(combo, products=products, only_families=only_families, prod_resonance=resonance)) # Calculate reaction degeneracy reaction_list = find_degenerate_reactions(reaction_list, same_reactants, kinetics_database=self) # Add reverse attribute to families with ownReverse to_delete = [] for i, rxn in enumerate(reaction_list): family = self.families[rxn.family] if family.own_reverse: successful = family.add_reverse_attribute(rxn) if not successful: to_delete.append(i) # Delete reactions which we could not find a reverse reaction for for i in reversed(to_delete): del reaction_list[i] return reaction_list