def testAddNewSurfaceObjects(self): """ basic test that surface movement object management works properly """ #create object with ReactionSystem behavior class rsys: pass class item: pass T = item() P = item() T.value_si = 1000.0 P.value_si = 101000.0 rsys.T = T rsys.P = P cerm = CoreEdgeReactionModel() spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] rxns = list(react(*spcTuples)) rxns += list(react(*[(spcs[0],spcs[1])])) for rxn in rxns: cerm.makeNewReaction(rxn) cerm.core.species = [spcA]+spcs corerxns = [] edgerxns = [] edgespcs = set() for rxn in rxns: if set(rxn.reactants+rxn.products) <= set(cerm.core.species): corerxns.append(rxn) else: edgespcs |= set(cerm.core.species)-set(rxn.reactants+rxn.products) edgerxns.append(rxn) cerm.edge.species += list(edgespcs) cerm.core.reactions = corerxns cerm.edge.reactions = edgerxns cerm.surface.species = [] cerm.surface.reactions = [] newSurfaceReactions = [cerm.edge.reactions[0]] newSurfaceSpecies = [] obj = newSurfaceReactions cerm.addNewSurfaceObjects(obj,newSurfaceSpecies,newSurfaceReactions,rsys) empty = set() self.assertEqual(cerm.newSurfaceSpcsAdd,empty) self.assertEqual(cerm.newSurfaceSpcsLoss,empty) self.assertEqual(cerm.newSurfaceRxnsLoss,empty) self.assertEqual(cerm.newSurfaceRxnsAdd,set([cerm.edge.reactions[0]]))
def test_degeneracy_keeps_separate_transition_states_separated(self): """ ensure rxns with multiple transition states are kept as separate reactions this test uses C[C]=C + C=C[CH2] -> C=C=C + C=CC as an example. This reaction should have two transition states, which should occur regardless of the order . """ spcA = Species().fromSMILES('C[C]=C') spcB = Species().fromSMILES('C=C[CH2]') spcTuples = [(spcA, spcB)] reactionList = list(react(*spcTuples)) # find reaction with a specific product specific_products = [ Species().fromSMILES('C=C=C'), Species().fromSMILES('CC=C'), ] # eliminate rxns that do not match products isomorphic_rxns = 0 for rxn in reactionList: # rxn contains all products if all([ any([ specific_product.isIsomorphic(product) for product in rxn.products ]) for specific_product in specific_products ]): isomorphic_rxns += 1 self.assertEqual( isomorphic_rxns, 2, 'The reaction output did not output all the transition states in either order of reactants' )
def test_degeneracy_does_not_include_identical_atom_labels(self): """ ensure rxns with identical atom_ids are not counted twice for degeneracy this test uses [H] + CC=C[CH]C -> H2 + [CH2]C=C[CH]C as an example. Since the reactant is symmetric with the middle carbon, the degeneracy should be 6. """ spcA = Species().fromSMILES('[H]') spcB = Species().fromSMILES('CC=C[CH]C') spcB.generateResonanceIsomers(keepIsomorphic=True) spcTuples = [(spcA, spcB)] reactionList = list(react(*spcTuples)) # find reaction with a specific product specific_product = Species().fromSMILES('[CH2]C=C[CH]C') specific_product.generateResonanceIsomers() specific_reaction = None for rxn in reactionList: if any([ specific_product.isIsomorphic(product) for product in rxn.products ]): specific_reaction = rxn break self.assertIsNotNone(specific_reaction, 'no reaction found with the specified product') self.assertEqual( specific_reaction.degeneracy, 6, 'The reaction output the wrong degeneracy of {}.'.format( specific_reaction.degeneracy))
def exploreIsomer(self, isomer): """ Explore a previously-unexplored unimolecular `isomer` in this partial network using the provided core-edge reaction model `reactionModel`, returning the new reactions and new species. """ if isomer in self.explored: logging.warning('Already explored isomer {0} in pressure-dependent network #{1:d}'.format(isomer, self.index)) return [] assert isomer not in self.source, "Attempted to explore isomer {0}, but that is the source configuration for this network.".format(isomer) for product in self.products: if product.species == [isomer]: break else: raise Exception('Attempted to explore isomer {0}, but that species not found in product channels.'.format(isomer)) logging.info('Exploring isomer {0} in pressure-dependent network #{1:d}'.format(isomer, self.index)) self.explored.append(isomer) self.isomers.append(product) self.products.remove(product) # Find reactions involving the found species as unimolecular # reactant or product (e.g. A <---> products) # Don't find reactions involving the new species as bimolecular # reactants or products with itself (e.g. A + A <---> products) # Don't find reactions involving the new species as bimolecular # reactants or products with other core species (e.g. A + B <---> products) newReactions = react((isomer,)) return newReactions
def test_degeneracy_keeps_track_of_both_rate_rules_from_resonance_isomers( self): """ rxns that have multiple resonance structures hitting different rate rules should be kept separate when findDegeneracy is used. this test uses [H] + CC=C[CH]C -> H2 + [CH2]C=C[CH]C as an example. This reaction should have two transition states. """ spcA = Species().fromSMILES('[H]') spcB = Species().fromSMILES('CC=C[CH]C') spcB.generateResonanceIsomers(keepIsomorphic=True) spcTuples = [(spcA, spcB)] reactionList = list(react(*spcTuples)) # find reaction with a specific product specific_product = Species().fromSMILES('CC=C[CH][CH2]') specific_product.generateResonanceIsomers() specific_reactions_found = 0 templates_found = [] for rxn in reactionList: if any([ specific_product.isIsomorphic(product) for product in rxn.products ]): specific_reactions_found += 1 templates_found.append(rxn.template) self.assertEqual( specific_reactions_found, 2, 'The reaction output did not contain 2 transition states.') self.assertNotEqual(templates_found[0], templates_found[1], 'The reactions should have different templates')
def testInflate(self): """ Test that CoreEdgeReactionModel.inflate method correctly works. """ spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] rxns = list(react(*spcTuples)) cerm = CoreEdgeReactionModel() for rxn in rxns: cerm.makeNewReaction(rxn) """ 3 expected H-abstraction reactions: OH + CC = H2O + C[CH2] OH + [CH3] = H2O + [CH2] OH + [CH3] = [O] + C """ for i, rxn in enumerate(rxns): rxns[i] = cerm.inflate(rxn) for rxn in rxns: self.assertTrue(rxn.isBalanced())
def testMakeNewReaction(self): """ Test that CoreEdgeReactionModel.makeNewReaction method correctly works. """ spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] rxns = list(react(*spcTuples)) cerm = CoreEdgeReactionModel() for rxn in rxns: cerm.makeNewReaction(rxn) """ 3 expected H-abstraction reactions: OH + CC = H2O + C[CH2] OH + [CH3] = H2O + [CH2] OH + [CH3] = [O] + C """ # count no. of entries in reactionDict: counter = 0 for fam, v1 in cerm.reactionDict.iteritems(): for key2, v2 in v1.iteritems(): for key3, rxnList in v2.iteritems(): counter += len(rxnList) self.assertEquals(counter, 3)
def test_make_new_reaction(self): """ Test that CoreEdgeReactionModel.make_new_reaction method correctly works. """ procnum = 2 spcA = Species().from_smiles('[OH]') spcs = [Species().from_smiles('CC'), Species().from_smiles('[CH3]')] spc_tuples = [((spcA, spc), ['H_Abstraction']) for spc in spcs] rxns = list(itertools.chain.from_iterable(react(spc_tuples, procnum))) cerm = CoreEdgeReactionModel() for rxn in rxns: cerm.make_new_reaction(rxn) """ 3 expected H-abstraction reactions: OH + CC = H2O + C[CH2] OH + [CH3] = H2O + [CH2] OH + [CH3] = [O] + C """ # count no. of entries in reactionDict: counter = 0 for fam, v1 in cerm.reaction_dict.items(): for key2, v2 in v1.items(): for key3, rxnList in v2.items(): counter += len(rxnList) self.assertEquals(counter, 3)
def testReactStoreIndices(self): """ Test that reaction generation keeps track of the original species indices. """ indices = {'[OH]': 1, 'CC': 2, '[CH3]': 3} # make it bidirectional so that we can look-up indices as well: revd = dict([reversed(i) for i in indices.items()]) indices.update(revd) spcA = Species(index=indices['[OH]']).fromSMILES('[OH]') spcs = [ Species(index=indices['CC']).fromSMILES('CC'), Species(index=indices['[CH3]']).fromSMILES('[CH3]') ] spcTuples = [(spcA, spc) for spc in spcs] reactionList = list(react(*spcTuples)) self.assertIsNotNone(reactionList) self.assertEquals(len(reactionList), 3) for rxn in reactionList: for i, reactant in enumerate(rxn.reactants): rxn.reactants[i] = Molecule().fromSMILES(indices[reactant]) self.assertTrue(rxn.isBalanced())
def testDeterministicReactionTemplateMatching(self): """ Test RMG work flow can match reaction template for kinetics estimation deterministically. In this test, a change of molecules order in a reacting species should not change the reaction template matched. """ # react spc = Species().fromSMILES("O=C[C]=C") spc.generateResonanceIsomers() newReactions = [] newReactions.extend(react(spc)) # process newly generated reactions to make sure no duplicated reactions self.rmg.reactionModel.processNewReactions(newReactions, spc, None) # try to pick out the target reaction mol_H = Molecule().fromSMILES("[H]") mol_C3H2O = Molecule().fromSMILES("C=C=C=O") target_rxns = findTargetRxnsContaining(mol_H, mol_C3H2O, \ self.rmg.reactionModel.edge.reactions) self.assertEqual(len(target_rxns), 1) # reverse the order of molecules in spc spc.molecule = list(reversed(spc.molecule)) # react again newReactions_reverse = [] newReactions_reverse.extend(react(spc)) # process newly generated reactions again to make sure no duplicated reactions self.rmg_dummy.reactionModel.processNewReactions( newReactions_reverse, spc, None) # try to pick out the target reaction target_rxns_reverse = findTargetRxnsContaining(mol_H, mol_C3H2O, \ self.rmg_dummy.reactionModel.edge.reactions) self.assertEqual(len(target_rxns_reverse), 1) # whatever order of molecules in spc, the reaction template matched should be same self.assertEqual(target_rxns[0].template, target_rxns_reverse[0].template)
def testDeterministicReactionTemplateMatching(self): """ Test RMG work flow can match reaction template for kinetics estimation deterministically. In this test, a change of molecules order in a reacting species should not change the reaction template matched. """ # react spc = Species().fromSMILES("O=C[C]=C") spc.generateResonanceIsomers() newReactions = [] newReactions.extend(react(spc)) # process newly generated reactions to make sure no duplicated reactions self.rmg.reactionModel.processNewReactions(newReactions, spc, None) # try to pick out the target reaction mol_H = Molecule().fromSMILES("[H]") mol_C3H2O = Molecule().fromSMILES("C=C=C=O") target_rxns = findTargetRxnsContaining(mol_H, mol_C3H2O, \ self.rmg.reactionModel.edge.reactions) self.assertEqual(len(target_rxns), 1) # reverse the order of molecules in spc spc.molecule = list(reversed(spc.molecule)) # react again newReactions_reverse = [] newReactions_reverse.extend(react(spc)) # process newly generated reactions again to make sure no duplicated reactions self.rmg_dummy.reactionModel.processNewReactions(newReactions_reverse, spc, None) # try to pick out the target reaction target_rxns_reverse = findTargetRxnsContaining(mol_H, mol_C3H2O, \ self.rmg_dummy.reactionModel.edge.reactions) self.assertEqual(len(target_rxns_reverse), 1) # whatever order of molecules in spc, the reaction template matched should be same self.assertEqual(target_rxns[0].template, target_rxns_reverse[0].template)
def testReact(self): """ Test that reaction generation from the available families works. """ spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] reactionList = list(react(*spcTuples)) self.assertIsNotNone(reactionList) self.assertTrue(all([isinstance(rxn, TemplateReaction) for rxn in reactionList]))
def testDeterministicReactionTemplateMatching(self): """ Test RMG work flow can match reaction template for kinetics estimation deterministically. In this test, a change of molecules order in a reacting species should not change the reaction template matched. However, this is inherently impossible with the existing reaction generation algorithm. Currently, the first reaction will be the one that is kept if the reactions are identical. If different templates are a result of different transition states, all are kept. {O=C-[C]=C, [O]-C=C=C} -> H + C=C=C=O """ # react spc = Species().fromSMILES("O=C[C]=C") spc.generate_resonance_structures() newReactions = react((spc,)) # try to pick out the target reaction mol_H = Molecule().fromSMILES("[H]") mol_C3H2O = Molecule().fromSMILES("C=C=C=O") target_rxns = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions) self.assertEqual(len(target_rxns), 2) # reverse the order of molecules in spc spc.molecule = list(reversed(spc.molecule)) # react again newReactions_reverse = [] newReactions_reverse.extend(react((spc,))) # try to pick out the target reaction target_rxns_reverse = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions_reverse) self.assertEqual(len(target_rxns_reverse), 2) # whatever order of molecules in spc, the reaction template matched should be same self.assertEqual(target_rxns[0].template, target_rxns_reverse[0].template)
def testReact(self): """ Test that reaction generation from the available families works. """ spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] reactionList = list(react(*spcTuples)) self.assertIsNotNone(reactionList) self.assertTrue( all([isinstance(rxn, TemplateReaction) for rxn in reactionList]))
def testDeterministicReactionTemplateMatching(self): """ Test RMG work flow can match reaction template for kinetics estimation deterministically. In this test, a change of molecules order in a reacting species should not change the reaction template matched. H + C=C=C=O -> O=C[C]=C """ # react spc = Species().fromSMILES("O=C[C]=C") spc.generateResonanceIsomers() newReactions = [] newReactions.extend(react((spc, ))) # try to pick out the target reaction mol_H = Molecule().fromSMILES("[H]") mol_C3H2O = Molecule().fromSMILES("C=C=C=O") target_rxns = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions) self.assertEqual(len(target_rxns), 2) # reverse the order of molecules in spc spc.molecule = list(reversed(spc.molecule)) # react again newReactions_reverse = [] newReactions_reverse.extend(react((spc, ))) # try to pick out the target reaction target_rxns_reverse = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions_reverse) self.assertEqual(len(target_rxns_reverse), 2) # whatever order of molecules in spc, the reaction template matched should be same self.assertEqual(target_rxns[0].template, target_rxns_reverse[-1].template)
def testReact(self): """ Test that the ``react`` function works in serial """ procnum = 1 spc_a = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spc_tuples = [((spc_a, spc), ['H_Abstraction']) for spc in spcs] reaction_list = list(itertools.chain.from_iterable(react(spc_tuples, procnum))) self.assertIsNotNone(reaction_list) self.assertEqual(len(reaction_list), 3) self.assertTrue(all([isinstance(rxn, TemplateReaction) for rxn in reaction_list]))
def testDeterministicReactionTemplateMatching(self): """ Test RMG work flow can match reaction template for kinetics estimation deterministically. In this test, a change of molecules order in a reacting species should not change the reaction template matched. H + C=C=C=O -> O=C[C]=C """ # react spc = Species().fromSMILES("O=C[C]=C") spc.generate_resonance_structures() newReactions = [] newReactions.extend(react((spc,))) # try to pick out the target reaction mol_H = Molecule().fromSMILES("[H]") mol_C3H2O = Molecule().fromSMILES("C=C=C=O") target_rxns = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions) self.assertEqual(len(target_rxns), 2) # reverse the order of molecules in spc spc.molecule = list(reversed(spc.molecule)) # react again newReactions_reverse = [] newReactions_reverse.extend(react((spc,))) # try to pick out the target reaction target_rxns_reverse = findTargetRxnsContaining(mol_H, mol_C3H2O, newReactions_reverse) self.assertEqual(len(target_rxns_reverse), 2) # whatever order of molecules in spc, the reaction template matched should be same self.assertEqual(target_rxns[0].template, target_rxns_reverse[-1].template)
def testReactParallel(self): """ Test that the ``react`` function works in parallel using Python multiprocessing """ import rmgpy.rmg.main rmgpy.rmg.main.maxproc = 2 procnum = 2 spc_a = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spc_tuples = [((spc_a, spc), ['H_Abstraction']) for spc in spcs] reaction_list = list(react(spc_tuples, procnum)) self.assertIsNotNone(reaction_list) self.assertEqual(len(reaction_list), 3) self.assertTrue( all([isinstance(rxn, TemplateReaction) for rxn in reaction_list]))
def testRestartFileGenerationAndParsing(self): # react spc1 = Species().fromSMILES("[H]") spc2 = Species().fromSMILES("C=C=C=O") self.rmg.reactionModel.core.species.append(spc1) self.rmg.reactionModel.core.species.append(spc2) newReactions = [] newReactions.extend(react((spc1, spc2))) # process newly generated reactions to make sure no duplicated reactions self.rmg.reactionModel.processNewReactions(newReactions, spc2, None) # save restart file restart_folder = os.path.join(os.path.dirname(rmgpy.__file__), 'rmg/test_data/restartFile') if not os.path.exists(restart_folder): os.mkdir(restart_folder) restart_path = os.path.join(restart_folder, 'restart.pkl') saveRestartFile(restart_path, self.rmg) # load the generated restart file rmg_load = RMG() rmg_load.loadRestartFile(restart_path) core_species_num_orig = len(self.rmg.reactionModel.core.species) core_rxn_num_orig = len(self.rmg.reactionModel.core.reactions) core_species_num_load = len(rmg_load.reactionModel.core.species) core_rxn_num_load = len(rmg_load.reactionModel.core.reactions) edge_species_num_orig = len(self.rmg.reactionModel.edge.species) edge_rxn_num_orig = len(self.rmg.reactionModel.edge.reactions) edge_species_num_load = len(rmg_load.reactionModel.edge.species) edge_rxn_num_load = len(rmg_load.reactionModel.edge.reactions) self.assertEqual(core_species_num_orig, core_species_num_load) self.assertEqual(core_rxn_num_orig, core_rxn_num_load) self.assertEqual(edge_species_num_orig, edge_species_num_load) self.assertEqual(edge_rxn_num_orig, edge_rxn_num_load) import shutil shutil.rmtree(restart_folder)
def testRestartFileGenerationAndParsing(self): # react spc1 = Species().fromSMILES("[H]") spc2 = Species().fromSMILES("C=C=C=O") self.rmg.reactionModel.core.species.append(spc1) self.rmg.reactionModel.core.species.append(spc2) newReactions = [] newReactions.extend(react((spc1,spc2))) # process newly generated reactions to make sure no duplicated reactions self.rmg.reactionModel.processNewReactions(newReactions, spc2, None) # save restart file restart_folder = os.path.join(os.path.dirname(rmgpy.__file__),'rmg/test_data/restartFile') if not os.path.exists(restart_folder): os.mkdir(restart_folder) restart_path = os.path.join(restart_folder, 'restart.pkl') saveRestartFile(restart_path, self.rmg) # load the generated restart file rmg_load = RMG() rmg_load.loadRestartFile(restart_path) core_species_num_orig = len(self.rmg.reactionModel.core.species) core_rxn_num_orig = len(self.rmg.reactionModel.core.reactions) core_species_num_load = len(rmg_load.reactionModel.core.species) core_rxn_num_load = len(rmg_load.reactionModel.core.reactions) edge_species_num_orig = len(self.rmg.reactionModel.edge.species) edge_rxn_num_orig = len(self.rmg.reactionModel.edge.reactions) edge_species_num_load = len(rmg_load.reactionModel.edge.species) edge_rxn_num_load = len(rmg_load.reactionModel.edge.reactions) self.assertEqual(core_species_num_orig, core_species_num_load) self.assertEqual(core_rxn_num_orig, core_rxn_num_load) self.assertEqual(edge_species_num_orig, edge_species_num_load) self.assertEqual(edge_rxn_num_orig, edge_rxn_num_load) import shutil shutil.rmtree(restart_folder)
def test_react_parallel(self): """ Test that the ``react`` function works in parallel using Python multiprocessing """ import rmgpy.rmg.main rmgpy.rmg.main.maxproc = 2 procnum = 2 spc_a = Species().from_smiles('[OH]') spcs = [Species().from_smiles('CC'), Species().from_smiles('[CH3]')] spc_tuples = [((spc_a, spc), ['H_Abstraction']) for spc in spcs] reaction_list = list(itertools.chain.from_iterable(react(spc_tuples, procnum))) self.assertIsNotNone(reaction_list) self.assertEqual(len(reaction_list), 3) self.assertTrue(all([isinstance(rxn, TemplateReaction) for rxn in reaction_list])) # Reset module level maxproc back to default rmgpy.rmg.main.maxproc = 1
def testReactStoreIndices(self): """ Test that reaction generation keeps track of the original species indices. """ indices = {'[OH]':1, 'CC':2, '[CH3]':3} # make it bidirectional so that we can look-up indices as well: revd=dict([reversed(i) for i in indices.items()]) indices.update(revd) spcA = Species(index=indices['[OH]']).fromSMILES('[OH]') spcs = [Species(index=indices['CC']).fromSMILES('CC'), Species(index=indices['[CH3]']).fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] reactionList = list(react(*spcTuples)) self.assertIsNotNone(reactionList) self.assertEquals(len(reactionList), 3) for rxn in reactionList: for i, reactant in enumerate(rxn.reactants): rxn.reactants[i] = Molecule().fromSMILES(indices[reactant]) self.assertTrue(rxn.isBalanced())
def test_add_new_surface_objects(self): """ basic test that surface movement object management works properly """ # create object with ReactionSystem behavior class rsys: pass class item: pass T = item() P = item() T.value_si = 1000.0 P.value_si = 101000.0 rsys.T = T rsys.P = P procnum = 2 cerm = CoreEdgeReactionModel() spcA = Species().from_smiles('[OH]') spcs = [Species().from_smiles('CC'), Species().from_smiles('[CH3]')] spc_tuples = [((spcA, spc), ['H_Abstraction']) for spc in spcs] rxns = list(itertools.chain.from_iterable(react(spc_tuples, procnum))) rxns += list( itertools.chain.from_iterable( react([((spcs[0], spcs[1]), ['H_Abstraction'])], procnum))) for rxn in rxns: cerm.make_new_reaction(rxn) cerm.core.species = [spcA] + spcs corerxns = [] edgerxns = [] edgespcs = set() for rxn in rxns: if set(rxn.reactants + rxn.products) <= set(cerm.core.species): corerxns.append(rxn) else: edgespcs |= set( cerm.core.species) - set(rxn.reactants + rxn.products) edgerxns.append(rxn) cerm.edge.species += list(edgespcs) cerm.core.reactions = corerxns cerm.edge.reactions = edgerxns cerm.surface.species = [] cerm.surface.reactions = [] new_surface_reactions = [cerm.edge.reactions[0]] new_surface_species = [] obj = new_surface_reactions cerm.add_new_surface_objects(obj, new_surface_species, new_surface_reactions, rsys) empty = set() self.assertEqual(cerm.new_surface_spcs_add, empty) self.assertEqual(cerm.new_surface_spcs_loss, empty) self.assertEqual(cerm.new_surface_rxns_loss, empty) self.assertEqual(cerm.new_surface_rxns_add, set([cerm.edge.reactions[0]]))