def test_reaction_degeneracy_independent_of_generatereactions_direction( self): """ test_reaction_degeneracy_independent_of_generatereactions_direction Ensure the returned kinetics have the same degeneracy irrespective of whether __generateReactions has forward = True or False """ family = database.kinetics.families['Disproportionation'] molA = Molecule().fromSMILES('C[CH2]') molB = Molecule().fromSMILES('C[CH2]') molC = Molecule().fromSMILES('C=C') molD = Molecule().fromSMILES('CC') molA.assignAtomIDs() molB.assignAtomIDs() molC.assignAtomIDs() molD.assignAtomIDs() # generate reactions in both directions forward_reactions = family._KineticsFamily__generateReactions( [molA, molB], products=[molC, molD], forward=True) reverse_reactions = family._KineticsFamily__generateReactions( [molC, molD], products=[molA, molB], forward=False) forward_reactions = find_degenerate_reactions(forward_reactions) reverse_reactions = find_degenerate_reactions(reverse_reactions) self.assertEqual( forward_reactions[0].degeneracy, reverse_reactions[0].degeneracy, 'the kinetics from forward and reverse directions had different degeneracies, {} and {} respectively' .format(forward_reactions[0].degeneracy, reverse_reactions[0].degeneracy))
def test_reaction_degeneracy_independent_of_generatereactions_direction(self): """ test_reaction_degeneracy_independent_of_generatereactions_direction Ensure the returned kinetics have the same degeneracy irrespective of whether __generateReactions has forward = True or False """ family = database.kinetics.families['Disproportionation'] molA = Molecule().fromSMILES('C[CH2]') molB = Molecule().fromSMILES('C[CH2]') molC = Molecule().fromSMILES('C=C') molD = Molecule().fromSMILES('CC') molA.assignAtomIDs() molB.assignAtomIDs() molC.assignAtomIDs() molD.assignAtomIDs() # generate reactions in both directions forward_reactions = family._KineticsFamily__generateReactions([molA, molB], products=[molC, molD], forward=True) reverse_reactions = family._KineticsFamily__generateReactions([molC, molD], products=[molA, molB], forward=False) forward_reactions = find_degenerate_reactions(forward_reactions) reverse_reactions = find_degenerate_reactions(reverse_reactions) self.assertEqual(forward_reactions[0].degeneracy, reverse_reactions[0].degeneracy, 'the kinetics from forward and reverse directions had different degeneracies, {} and {} respectively'.format(forward_reactions[0].degeneracy, reverse_reactions[0].degeneracy))
def loop_families(rmgdb, reaction): """ Loop through kinetic families and return a list of tuples of (family, degenerate_reactions) `reaction` is an RMG Reaction object Returns a list of (family, degenerate_reactions) tuples """ fam_list = list() for family in rmgdb.kinetics.families.values(): degenerate_reactions = list() family_reactions_by_r = list( ) # family reactions for the specified reactants family_reactions_by_rnp = list( ) # family reactions for the specified reactants and products if len(reaction.reactants) == 1: for reactant0 in reaction.reactants[0].molecule: fam_rxn = family.generateReactions(reactants=[reactant0], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 2: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: fam_rxn = family.generateReactions( reactants=[reactant0, reactant1], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 3: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: for reactant2 in reaction.reactants[2].molecule: fam_rxn = family.generateReactions( reactants=[reactant0, reactant1, reactant2], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) if len(reaction.products) == 1: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: if isomorphic_species_lists([product0], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) elif len(reaction.products) == 2: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: if isomorphic_species_lists([product0, product1], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) elif len(reaction.products) == 3: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: for product2 in reaction.products[2].molecule: if isomorphic_species_lists( [product0, product1, product2], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) if degenerate_reactions: fam_list.append((family, degenerate_reactions)) return fam_list
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
def loop_families(rmgdb, reaction): """ Loop through kinetic families and return a list of tuples of (family, degenerate_reactions) `reaction` is an RMG Reaction object. Returns a list of (family, degenerate_reactions) tuples. Args: rmgdb (RMGDatabase): The RMG database instance. reaction (Reaction): The RMG Reaction object. Returns: list Entries are corresponding RMG reaction families. """ reaction = reaction.copy( ) # use a copy to avoid changing atom order in the molecules by RMG fam_list = list() for family in rmgdb.kinetics.families.values(): degenerate_reactions = list() family_reactions_by_r = list( ) # family reactions for the specified reactants family_reactions_by_rnp = list( ) # family reactions for the specified reactants and products if len(reaction.reactants) == 1: for reactant0 in reaction.reactants[0].molecule: fam_rxn = family.generate_reactions(reactants=[reactant0], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 2: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: fam_rxn = family.generate_reactions( reactants=[reactant0, reactant1], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 3: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: for reactant2 in reaction.reactants[2].molecule: fam_rxn = family.generate_reactions( reactants=[reactant0, reactant1, reactant2], products=reaction.products) if fam_rxn: family_reactions_by_r.extend(fam_rxn) if len(reaction.products) == 1: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: if same_species_lists([product0], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) elif len(reaction.products) == 2: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: if same_species_lists([product0, product1], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) elif len(reaction.products) == 3: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: for product2 in reaction.products[2].molecule: if same_species_lists( [product0, product1, product2], fam_rxn.products): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics) if degenerate_reactions: fam_list.append((family, degenerate_reactions)) return fam_list
def loop_families( rmgdb: RMGDatabase, reaction: Reaction, ) -> List[Tuple['KineticsFamily', list]]: """ Loop through kinetic families and return a list of tuples of (family, degenerate_reactions) corresponding to ``reaction``. Args: rmgdb (RMGDatabase): The RMG database instance. reaction (Reaction): The RMG Reaction object instance. Returns: List[Tuple['KineticsFamily', list]] Entries are tuples of a corresponding RMG KineticsFamily instance and a list of degenerate reactions. """ reaction = reaction.copy( ) # Use a copy to avoid changing atom order in the molecules by RMG. for spc in reaction.reactants + reaction.products: spc.generate_resonance_structures(save_order=True) fam_list = list() for family in rmgdb.kinetics.families.values(): family.save_order = True degenerate_reactions = list() family_reactions_by_r = list( ) # Family reactions for the specified reactants. family_reactions_by_rnp = list( ) # Family reactions for the specified reactants and products. if len(reaction.reactants) == 1: for reactant0 in reaction.reactants[0].molecule: fam_rxn = family.generate_reactions( reactants=[reactant0], products=reaction.products, delete_labels=False, ) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 2: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: fam_rxn = family.generate_reactions( reactants=[reactant0, reactant1], products=reaction.products, delete_labels=False, ) if fam_rxn: family_reactions_by_r.extend(fam_rxn) elif len(reaction.reactants) == 3: for reactant0 in reaction.reactants[0].molecule: for reactant1 in reaction.reactants[1].molecule: for reactant2 in reaction.reactants[2].molecule: fam_rxn = family.generate_reactions( reactants=[reactant0, reactant1, reactant2], products=reaction.products, delete_labels=False, ) if fam_rxn: family_reactions_by_r.extend(fam_rxn) if len(reaction.products) == 1: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: if same_species_lists([product0], fam_rxn.products, save_order=True): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics, save_order=True) elif len(reaction.products) == 2: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: if same_species_lists([product0, product1], fam_rxn.products, save_order=True): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics, save_order=True) elif len(reaction.products) == 3: for fam_rxn in family_reactions_by_r: for product0 in reaction.products[0].molecule: for product1 in reaction.products[1].molecule: for product2 in reaction.products[2].molecule: if same_species_lists( [product0, product1, product2], fam_rxn.products, save_order=True): family_reactions_by_rnp.append(fam_rxn) degenerate_reactions = find_degenerate_reactions( rxn_list=family_reactions_by_rnp, same_reactants=False, kinetics_database=rmgdb.kinetics, save_order=True) if degenerate_reactions: fam_list.append((family, degenerate_reactions)) return fam_list