def generate_isotopomers(spc, N=1): """ Generate all isotopomers of the parameter species by adding max. N carbon isotopes to the atoms of the species. """ mol = spc.molecule[0] isotope = getElement(6, 13) mols = [] add_isotope(0, N, mol, mols, isotope) spcs = [] for isomol in mols: isotopomer = Species(molecule=[isomol], thermo=deepcopy(spc.thermo), transportData=spc.transportData, reactive=spc.reactive) isotopomer.generate_resonance_structures(keep_isomorphic=True) spcs.append(isotopomer) # do not retain identical species: filtered = [] while spcs: candidate = spcs.pop() unique = True for isotopomer in filtered: if isotopomer.isIsomorphic(candidate): unique = False break if unique: filtered.append(candidate) if spc.thermo: for isotopomer in filtered: correct_entropy(isotopomer, spc) return filtered
def testThermoForMonocyclicAndPolycyclicSameMolecule(self): """ Test a molecule that has both a polycyclic and a monocyclic ring in the same molecule """ spec = Species().fromSMILES('C(CCC1C2CCC1CC2)CC1CCC1') spec.generateResonanceIsomers() thermo = self.database.getThermoDataFromGroups(spec) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments( thermo) self.assertEqual(len(ringGroups), 1) self.assertEqual(len(polycyclicGroups), 1) expected_matchedRingsLabels = ['Cyclobutane'] expected_matchedRings = [ self.database.groups['ring'].entries[label] for label in expected_matchedRingsLabels ] self.assertEqual(set(ringGroups), set(expected_matchedRings)) expected_matchedPolyringsLabels = ['s3_5_5_ane'] expected_matchedPolyrings = [ self.database.groups['polycyclic'].entries[label] for label in expected_matchedPolyringsLabels ] self.assertEqual(set(polycyclicGroups), set(expected_matchedPolyrings))
def loadSpeciesDictionary(path): """ Very similar method with `loadSpeciesDictionary` in RMG-Py. Here this method doesn't generateResonanceIsomers for the created species, will just keep it as it is. """ speciesDict = {} inerts = [Species().fromSMILES(inert) for inert in ('[He]', '[Ne]', 'N#N', '[Ar]')] with open(path, 'r') as f: adjlist = '' for line in f: if line.strip() == '' and adjlist.strip() != '': # Finish this adjacency list species = Species().fromAdjacencyList(adjlist) label = species.label for inert in inerts: if inert.isIsomorphic(species): species.reactive = False break speciesDict[label] = species adjlist = '' else: if "InChI" in line: line = line.split()[0] + '\n' if '//' in line: index = line.index('//') line = line[0:index] adjlist += line return speciesDict
def testGetRingGroupsFromComments(self): """ Test that getRingGroupsFromComments method works for fused polycyclics. """ from rmgpy.thermo.thermoengine import generateThermoData # set-up RMG object rmg = RMG() # load kinetic database and forbidden structures rmg.database = RMGDatabase() path = os.path.join(settings['database.directory']) # forbidden structure loading rmg.database.loadThermo(os.path.join(path, 'thermo')) smi = 'C12C(C3CCC2C3)C4CCC1C4'#two norbornane rings fused together spc = Species().fromSMILES(smi) spc.thermo = generateThermoData(spc) thermodb = rmg.database.thermo thermodb.getRingGroupsFromComments(spc.thermo) import rmgpy.data.rmg rmgpy.data.rmg.database = None
def testPolycyclicPicksBestThermo(self): """ Test that RMG prioritizes thermo correctly and chooses the thermo from the isomer which has a non generic polycyclic ring correction """ spec = Species().fromSMILES('C1=C[C]2CCC=C2C1') spec.generateResonanceIsomers() thermoDataList = [] for molecule in spec.molecule: thermo = self.database.estimateRadicalThermoViaHBI(molecule, self.database.computeGroupAdditivityThermo) thermoDataList.append(thermo) thermoDataList.sort(key=lambda x: x.getEnthalpy(298)) most_stable_thermo = thermoDataList[0] ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments(most_stable_thermo) selected_thermo = self.database.getThermoDataFromGroups(spec) self.assertNotEqual(selected_thermo, thermoDataList) selected_ringGroups, selected_polycyclicGroups = self.database.getRingGroupsFromComments(selected_thermo) # The group used to estimate the most stable thermo is the generic polycyclic group and # therefore is not selected. Note that this unit test will have to change if the correction is fixed later. self.assertEqual(polycyclicGroups[0].label, 'PolycyclicRing') self.assertEqual(selected_polycyclicGroups[0].label, 'C12CCC=C1CC=C2')
def testPolycyclicPicksBestThermo(self): """ Test that RMG prioritizes thermo correctly and chooses the thermo from the isomer which has a non generic polycyclic ring correction """ spec = Species().fromSMILES('C1=C[C]2CCC=C2C1') spec.generateResonanceIsomers() thermoDataList = [] for molecule in spec.molecule: thermo = self.database.estimateRadicalThermoViaHBI( molecule, self.database.computeGroupAdditivityThermo) thermoDataList.append(thermo) thermoDataList.sort(key=lambda x: x.getEnthalpy(298)) most_stable_thermo = thermoDataList[0] ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments( most_stable_thermo) selected_thermo = self.database.getThermoDataFromGroups(spec) self.assertNotEqual(selected_thermo, thermoDataList) selected_ringGroups, selected_polycyclicGroups = self.database.getRingGroupsFromComments( selected_thermo) # The group used to estimate the most stable thermo is the generic polycyclic group and # therefore is not selected. Note that this unit test will have to change if the correction is fixed later. self.assertEqual(polycyclicGroups[0].label, 'PolycyclicRing') self.assertEqual(selected_polycyclicGroups[0].label, 'C12CCC=C1CC=C2')
def testNewThermoGeneration(self): """ Test that the new ThermoDatabase generates appropriate thermo data. """ for smiles, symm, H298, S298, Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500 in self.testCases: Cplist = [Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500] molecule=Molecule(SMILES=smiles) species = Species(molecule=molecule) species.generateResonanceIsomers() species.molecule[0] thermoData = self.database.getThermoDataFromGroups(species) molecule = species.molecule[0] for mol in species.molecule[1:]: thermoData0 = self.database.getAllThermoData(Species(molecule=[mol]))[0][0] for data in self.database.getAllThermoData(Species(molecule=[mol]))[1:]: if data.getEnthalpy(298) < thermoData0.getEnthalpy(298): thermoData0 = data if thermoData0.getEnthalpy(298) < thermoData.getEnthalpy(298): thermoData = thermoData0 molecule = mol self.assertAlmostEqual(H298, thermoData.getEnthalpy(298) / 4184, places=1, msg="H298 error for {0}".format(smiles)) self.assertAlmostEqual(S298, thermoData.getEntropy(298) / 4.184, places=1, msg="S298 error for {0}".format(smiles)) for T, Cp in zip(self.Tlist, Cplist): self.assertAlmostEqual(Cp, thermoData.getHeatCapacity(T) / 4.184, places=1, msg="Cp{1} error for {0}".format(smiles,T))
def testGetRingGroupsFromComments(self): """ Test that getRingGroupsFromComments method works for fused polycyclics. """ from rmgpy.thermo.thermoengine import generateThermoData # set-up RMG object rmg = RMG() # load kinetic database and forbidden structures rmg.database = RMGDatabase() path = os.path.join(settings['database.directory']) # forbidden structure loading rmg.database.loadThermo(os.path.join(path, 'thermo')) smi = 'C12C(C3CCC2C3)C4CCC1C4' #two norbornane rings fused together spc = Species().fromSMILES(smi) spc.thermo = generateThermoData(spc) thermodb = rmg.database.thermo thermodb.getRingGroupsFromComments(spc.thermo) import rmgpy.data.rmg rmgpy.data.rmg.database = None
def testReact(self): """ Test that reaction generation from the available families works. """ spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] reactionList = list(react(spcA, spcs)) self.assertIsNotNone(reactionList) self.assertTrue(all([isinstance(rxn, TemplateReaction) for rxn in reactionList]))
def testAddPolyRingCorrectionThermoDataFromHeuristicUsingPyrene(self): # create testing molecule: Pyrene with two ring of aromatic version # the other two ring of kekulized version # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with pyrene radical and get the two aromatic ring isomer # then saturate it. smiles = '[C]1C=C2C=CC=C3C=CC4=CC=CC=1C4=C23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() mols = [] for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: mol.saturate() mols.append(mol) ringGroupLabels = [] polycyclicGroupLabels = [] for mol in mols: polyring = mol.getDisparateRings()[1][0] thermoData = ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "J/(mol*K)"), H298=(0.0, "kJ/mol"), S298=(0.0, "J/(mol*K)"), ) self.database._ThermoDatabase__addPolyRingCorrectionThermoDataFromHeuristic( thermoData, polyring) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments( thermoData) ringGroupLabels += [ringGroup.label for ringGroup in ringGroups] polycyclicGroupLabels += [ polycyclicGroup.label for polycyclicGroup in polycyclicGroups ] self.assertIn('Benzene', ringGroupLabels) self.assertIn('six-inringtwodouble-12', ringGroupLabels) self.assertIn('Cyclohexene', ringGroupLabels) self.assertIn('1,3-Cyclohexadiene', ringGroupLabels) self.assertIn('s2_6_6_ben_ene_1', polycyclicGroupLabels) self.assertIn('s2_6_6_ben_ene_2', polycyclicGroupLabels) self.assertIn('s2_6_6_naphthalene', polycyclicGroupLabels)
def testGetRingGroupsFromComments(self): """ Test that getRingGroupsFromComments method works for fused polycyclics. """ from rmgpy.thermo.thermoengine import generateThermoData smi = 'C12C(C3CCC2C3)C4CCC1C4'#two norbornane rings fused together spc = Species().fromSMILES(smi) spc.thermo = generateThermoData(spc) self.database.getRingGroupsFromComments(spc.thermo)
def testSpeciesThermoGenerationHBIGAV(self): """Test thermo generation for species objects. Ensure that molecule list is only reordered, and not changed after group additivity""" spec = Species().fromSMILES('CCC[CH]c1ccccc1') spec.generateResonanceIsomers() initial = list(spec.molecule) # Make a copy of the list thermo = self.database.getThermoData(spec) self.assertEqual(len(initial), len(spec.molecule)) self.assertEqual(set(initial), set(spec.molecule)) self.assertTrue('group additivity' in thermo.comment, 'Thermo not found from GAV, test purpose not fulfilled.')
def testGetRingGroupsFromComments(self): """ Test that getRingGroupsFromComments method works for fused polycyclics. """ from rmgpy.thermo.thermoengine import generateThermoData smi = 'C12C(C3CCC2C3)C4CCC1C4' #two norbornane rings fused together spc = Species().fromSMILES(smi) spc.thermo = generateThermoData(spc) self.database.getRingGroupsFromComments(spc.thermo)
def testBicyclicDecompositionForPolyringUsingPyrene(self): # create testing molecule: Pyrene with two ring of aromatic version # the other two ring of kekulized version # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with pyrene radical and get the two aromatic ring isomer # then saturate it. smiles = '[C]1C=C2C=CC=C3C=CC4=CC=CC=1C4=C23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: break mol.saturate() # extract polyring from the molecule polyring = mol.getDisparateRings()[1][0] bicyclicList, ringOccurancesDict = bicyclicDecompositionForPolyring( polyring) # 1st test: number of cores self.assertEqual(len(bicyclicList), 5) # 2nd test: ringOccurancesDict ringInCoreOccurances = sorted(ringOccurancesDict.values()) expectedRingInCoreOccurances = [2, 2, 3, 3] self.assertEqual(ringInCoreOccurances, expectedRingInCoreOccurances) # 3rd test: size of each bicyclic core bicyclicSizes = sorted( [len(bicyclic.atoms) for bicyclic in bicyclicList]) expectedBicyclicSizes = [10, 10, 10, 10, 10] self.assertEqual(bicyclicSizes, expectedBicyclicSizes) # 4th test: bond info for members of each core aromaticBondNumInBicyclics = [] for bicyclic in bicyclicList: aromaticBondNum = len(findAromaticBondsFromSubMolecule(bicyclic)) aromaticBondNumInBicyclics.append(aromaticBondNum) aromaticBondNumInBicyclics = sorted(aromaticBondNumInBicyclics) expectedAromaticBondNumInBicyclics = [0, 6, 6, 6, 11] self.assertEqual(aromaticBondNumInBicyclics, expectedAromaticBondNumInBicyclics)
def testAddPolyRingCorrectionThermoDataFromHeuristicUsingPyrene(self): # create testing molecule: Pyrene with two ring of aromatic version # the other two ring of kekulized version # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with pyrene radical and get the two aromatic ring isomer # then saturate it. smiles = '[C]1C=C2C=CC=C3C=CC4=CC=CC=1C4=C23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() mols = [] for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: mol.saturate() mols.append(mol) ringGroupLabels = [] polycyclicGroupLabels = [] for mol in mols: polyring = mol.getDisparateRings()[1][0] thermoData = ThermoData( Tdata = ([300,400,500,600,800,1000,1500],"K"), Cpdata = ([0.0,0.0,0.0,0.0,0.0,0.0,0.0],"J/(mol*K)"), H298 = (0.0,"kJ/mol"), S298 = (0.0,"J/(mol*K)"), ) self.database._ThermoDatabase__addPolyRingCorrectionThermoDataFromHeuristic( thermoData, polyring) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments(thermoData) ringGroupLabels += [ringGroup.label for ringGroup in ringGroups] polycyclicGroupLabels += [polycyclicGroup.label for polycyclicGroup in polycyclicGroups] self.assertIn('Benzene', ringGroupLabels) self.assertIn('six-inringtwodouble-12', ringGroupLabels) self.assertIn('Cyclohexene', ringGroupLabels) self.assertIn('1,3-Cyclohexadiene', ringGroupLabels) self.assertIn('s2_6_6_ben_ene_1', polycyclicGroupLabels) self.assertIn('s2_6_6_ben_ene_2', polycyclicGroupLabels) self.assertIn('s2_6_6_naphthalene', polycyclicGroupLabels)
def testSpeciesThermoGenerationHBIGAV(self): """Test thermo generation for species objects. Ensure that molecule list is only reordered, and not changed after group additivity""" spec = Species().fromSMILES('CCC[CH]c1ccccc1') spec.generateResonanceIsomers() initial = list(spec.molecule) # Make a copy of the list thermo = self.database.getThermoData(spec) self.assertEqual(len(initial), len(spec.molecule)) self.assertEqual(set(initial), set(spec.molecule)) self.assertTrue( 'group additivity' in thermo.comment, 'Thermo not found from GAV, test purpose not fulfilled.')
def testBicyclicDecompositionForPolyringUsingPyrene(self): # create testing molecule: Pyrene with two ring of aromatic version # the other two ring of kekulized version # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with pyrene radical and get the two aromatic ring isomer # then saturate it. smiles = '[C]1C=C2C=CC=C3C=CC4=CC=CC=1C4=C23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: break mol.saturate() # extract polyring from the molecule polyring = mol.getDisparateRings()[1][0] bicyclicList, ringOccurancesDict = bicyclicDecompositionForPolyring(polyring) # 1st test: number of cores self.assertEqual(len(bicyclicList), 5) # 2nd test: ringOccurancesDict ringInCoreOccurances = sorted(ringOccurancesDict.values()) expectedRingInCoreOccurances = [2, 2, 3, 3] self.assertEqual(ringInCoreOccurances, expectedRingInCoreOccurances) # 3rd test: size of each bicyclic core bicyclicSizes = sorted([len(bicyclic.atoms) for bicyclic in bicyclicList]) expectedBicyclicSizes = [10, 10, 10, 10, 10] self.assertEqual(bicyclicSizes, expectedBicyclicSizes) # 4th test: bond info for members of each core aromaticBondNumInBicyclics = [] for bicyclic in bicyclicList: aromaticBondNum = len(findAromaticBondsFromSubMolecule(bicyclic)) aromaticBondNumInBicyclics.append(aromaticBondNum) aromaticBondNumInBicyclics = sorted(aromaticBondNumInBicyclics) expectedAromaticBondNumInBicyclics = [0, 6, 6, 6, 11] self.assertEqual(aromaticBondNumInBicyclics, expectedAromaticBondNumInBicyclics)
def generate(): """ Test that reaction generation from the available families works. """ load() spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] reactionList = list(react(spcA, spcs)) if not reactionList: return False for rxn in reactionList: if not isinstance(rxn, TemplateReaction): return False return True
def testAddPolyRingCorrectionThermoDataFromHeuristicUsingAromaticTricyclic( self): # create testing molecule # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with kekulized version and generateResonanceIsomers # and pick the one with two aromatic rings smiles = 'C1=CC2C=CC=C3C=CC(=C1)C=23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: break # extract polyring from the molecule polyring = mol.getDisparateRings()[1][0] thermoData = ThermoData( Tdata=([300, 400, 500, 600, 800, 1000, 1500], "K"), Cpdata=([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], "J/(mol*K)"), H298=(0.0, "kJ/mol"), S298=(0.0, "J/(mol*K)"), ) self.database._ThermoDatabase__addPolyRingCorrectionThermoDataFromHeuristic( thermoData, polyring) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments( thermoData) ringGroupLabels = [ringGroup.label for ringGroup in ringGroups] polycyclicGroupLabels = [ polycyclicGroup.label for polycyclicGroup in polycyclicGroups ] self.assertIn('Benzene', ringGroupLabels) self.assertIn('Cyclopentene', ringGroupLabels) self.assertIn('s2_5_6_indene', polycyclicGroupLabels) self.assertIn('s2_6_6_naphthalene', polycyclicGroupLabels)
def testSymmetryNumberGeneration(self): """ Test we generate symmetry numbers correctly. This uses the new thermo database to generate the H298, used to select the stablest resonance isomer. """ for smiles, symm, H298, S298, Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500 in self.testCases: molecule = Molecule(SMILES=smiles) species = Species(molecule=molecule) species.generateResonanceIsomers() thermoData = self.database.getThermoDataFromGroups( Species(molecule=[species.molecule[0]])) # pick the molecule with lowest H298 molecule = species.molecule[0] for mol in species.molecule[1:]: thermoData0 = self.database.getAllThermoData( Species(molecule=[mol]))[0][0] for data in self.database.getAllThermoData( Species(molecule=[mol]))[1:]: if data.getEnthalpy(298) < thermoData0.getEnthalpy(298): thermoData0 = data if thermoData0.getEnthalpy(298) < thermoData.getEnthalpy(298): thermoData = thermoData0 molecule = mol self.assertEqual( molecule.calculateSymmetryNumber(), symm, msg="Symmetry number error for {0}".format(smiles))
def testComputeGroupAdditivityThermoForTwoRingMolecule(self): """ The molecule being tested has two rings, one is 13cyclohexadiene5methylene the other is benzene ring. This method is to test thermo estimation will give two different corrections accordingly. """ spec = Species().fromSMILES('CCCCCCCCCCCC(CC=C1C=CC=CC1)c1ccccc1') spec.generateResonanceIsomers() thermo = self.database.getThermoDataFromGroups(spec) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments(thermo) self.assertEqual(len(ringGroups),2) self.assertEqual(len(polycyclicGroups),0) expected_matchedRingsLabels = ['13cyclohexadiene5methylene', 'Benzene'] expected_matchedRings = [self.database.groups['ring'].entries[label] for label in expected_matchedRingsLabels] self.assertEqual(set(ringGroups), set(expected_matchedRings))
def testThermoForMonocyclicAndPolycyclicSameMolecule(self): """ Test a molecule that has both a polycyclic and a monocyclic ring in the same molecule """ spec = Species().fromSMILES('C(CCC1C2CCC1CC2)CC1CCC1') spec.generateResonanceIsomers() thermo = self.database.getThermoDataFromGroups(spec) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments(thermo) self.assertEqual(len(ringGroups),1) self.assertEqual(len(polycyclicGroups),1) expected_matchedRingsLabels = ['Cyclobutane'] expected_matchedRings = [self.database.groups['ring'].entries[label] for label in expected_matchedRingsLabels] self.assertEqual(set(ringGroups), set(expected_matchedRings)) expected_matchedPolyringsLabels = ['s3_5_5_ane'] expected_matchedPolyrings = [self.database.groups['polycyclic'].entries[label] for label in expected_matchedPolyringsLabels] self.assertEqual(set(polycyclicGroups), set(expected_matchedPolyrings))
def testAddPolyRingCorrectionThermoDataFromHeuristicUsingAromaticTricyclic(self): # create testing molecule # # creating it seems not natural in RMG, that's because # RMG cannot parse the adjacencyList of that isomer correctly # so here we start with kekulized version and generateResonanceIsomers # and pick the one with two aromatic rings smiles = 'C1=CC2C=CC=C3C=CC(=C1)C=23' spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() for mol in spe.molecule: sssr0 = mol.getSmallestSetOfSmallestRings() aromaticRingNum = 0 for sr0 in sssr0: sr0mol = Molecule(atoms=sr0) if isAromaticRing(sr0mol): aromaticRingNum += 1 if aromaticRingNum == 2: break # extract polyring from the molecule polyring = mol.getDisparateRings()[1][0] thermoData = ThermoData( Tdata = ([300,400,500,600,800,1000,1500],"K"), Cpdata = ([0.0,0.0,0.0,0.0,0.0,0.0,0.0],"J/(mol*K)"), H298 = (0.0,"kJ/mol"), S298 = (0.0,"J/(mol*K)"), ) self.database._ThermoDatabase__addPolyRingCorrectionThermoDataFromHeuristic( thermoData, polyring) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments(thermoData) ringGroupLabels = [ringGroup.label for ringGroup in ringGroups] polycyclicGroupLabels = [polycyclicGroup.label for polycyclicGroup in polycyclicGroups] self.assertIn('Benzene', ringGroupLabels) self.assertIn('Cyclopentene', ringGroupLabels) self.assertIn('s2_5_6_indene', polycyclicGroupLabels) self.assertIn('s2_6_6_naphthalene', polycyclicGroupLabels)
def testFindAromaticBondsFromSubMolecule(self): smiles = "C1=CC=C2C=CC=CC2=C1" spe = Species().fromSMILES(smiles) spe.generateResonanceIsomers() mol = spe.molecule[1] # get two SSSRs SSSR = mol.getSmallestSetOfSmallestRings() ring1 = SSSR[0] ring2 = SSSR[1] # create two testing submols submol1 = Molecule(atoms=ring1) submol2 = Molecule(atoms=ring2) # check with expected results self.assertEqual(len(findAromaticBondsFromSubMolecule(submol1)), 6) self.assertEqual(len(findAromaticBondsFromSubMolecule(submol2)), 6)
def generate(): """ Test that reaction generation from the available families works. """ load() spcA = Species().fromSMILES('[OH]') spcs = [Species().fromSMILES('CC'), Species().fromSMILES('[CH3]')] spcTuples = [(spcA, spc) for spc in spcs] procnum = 2 reactionList = list( itertools.chain.from_iterable(react(spcTuples, procnum))) if not reactionList: return False for rxn in reactionList: if not isinstance(rxn, TemplateReaction): return False return True
def kinetics(label, kinetics): reactants, products = label.split('_') reactants = reactants.split('+') products = products.split('+') reaction = Reaction(reactants=[], products=[], reversible=True) for in_list, out_list in [(reactants, reaction.reactants), (products, reaction.products)]: for i, smiles in enumerate(in_list): if smiles not in species_dict: species = Species().fromSMILES(smiles) species_dict[smiles] = species species.label = '{0}({1})'.format(species.toChemkin(), len(species_dict)) out_list.append(species_dict[smiles]) reaction.kinetics = kinetics print repr(reaction) display(reaction) addReactionToKineticsLibrary(reaction)
def testComputeGroupAdditivityThermoForTwoRingMolecule(self): """ The molecule being tested has two rings, one is 13cyclohexadiene5methylene the other is benzene ring. This method is to test thermo estimation will give two different corrections accordingly. """ spec = Species().fromSMILES('CCCCCCCCCCCC(CC=C1C=CC=CC1)c1ccccc1') spec.generateResonanceIsomers() thermo = self.database.getThermoDataFromGroups(spec) ringGroups, polycyclicGroups = self.database.getRingGroupsFromComments( thermo) self.assertEqual(len(ringGroups), 2) self.assertEqual(len(polycyclicGroups), 0) expected_matchedRingsLabels = ['13cyclohexadiene5methylene', 'Benzene'] expected_matchedRings = [ self.database.groups['ring'].entries[label] for label in expected_matchedRingsLabels ] self.assertEqual(set(ringGroups), set(expected_matchedRings))
def testSymmetryContributionRadicals(self): """ Test that the symmetry contribution is correctly added for radicals estimated via the HBI method. """ spc = Species(molecule=[Molecule().fromSMILES('[CH3]')]) thermoData_lib = self.database.getThermoDataFromLibraries(spc)[0] thermoData_ga = self.database.getThermoDataFromGroups(spc) self.assertAlmostEqual(thermoData_lib.getEntropy(298.), thermoData_ga.getEntropy(298.), 0)
def testSymmetryNumberGeneration(self): """ Test we generate symmetry numbers correctly. This uses the new thermo database to generate the H298, used to select the stablest resonance isomer. """ for smiles, symm, H298, S298, Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500 in self.testCases: molecule=Molecule(SMILES=smiles) species = Species(molecule=molecule) species.generateResonanceIsomers() thermoData = self.database.getThermoDataFromGroups(Species(molecule=[species.molecule[0]])) # pick the molecule with lowest H298 molecule = species.molecule[0] for mol in species.molecule[1:]: thermoData0 = self.database.getAllThermoData(Species(molecule=[mol]))[0][0] for data in self.database.getAllThermoData(Species(molecule=[mol]))[1:]: if data.getEnthalpy(298) < thermoData0.getEnthalpy(298): thermoData0 = data if thermoData0.getEnthalpy(298) < thermoData.getEnthalpy(298): thermoData = thermoData0 molecule = mol self.assertEqual(molecule.calculateSymmetryNumber(), symm, msg="Symmetry number error for {0}".format(smiles))
def testNewThermoGeneration(self): """ Test that the new ThermoDatabase generates appropriate thermo data. """ for smiles, symm, H298, S298, Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500 in self.testCases: Cplist = [Cp300, Cp400, Cp500, Cp600, Cp800, Cp1000, Cp1500] species = Species().fromSMILES(smiles) species.generateResonanceIsomers() thermoData = self.database.getThermoDataFromGroups(species) molecule = species.molecule[0] for mol in species.molecule[1:]: thermoData0 = self.database.getAllThermoData( Species(molecule=[mol]))[0][0] for data in self.database.getAllThermoData( Species(molecule=[mol]))[1:]: if data[0].getEnthalpy(298) < thermoData0.getEnthalpy(298): thermoData0 = data[0] if thermoData0.getEnthalpy(298) < thermoData.getEnthalpy(298): thermoData = thermoData0 molecule = mol self.assertAlmostEqual( H298, thermoData.getEnthalpy(298) / 4184, places=1, msg="H298 error for {0}. Expected {1}, but calculated {2}.". format(smiles, H298, thermoData.getEnthalpy(298) / 4184)) self.assertAlmostEqual( S298, thermoData.getEntropy(298) / 4.184, places=1, msg="S298 error for {0}. Expected {1}, but calculated {2}.". format(smiles, S298, thermoData.getEntropy(298) / 4.184)) for T, Cp in zip(self.Tlist, Cplist): self.assertAlmostEqual( Cp, thermoData.getHeatCapacity(T) / 4.184, places=1, msg="Cp{3} error for {0}. Expected {1} but calculated {2}." .format(smiles, Cp, thermoData.getHeatCapacity(T) / 4.184, T))
delimiter = '\t' JtoCal = 1.0/4.184 rmg = RMG() rmg.database = RMGDatabase() path = os.path.join(settings['database.directory']) rmg.database.loadThermo(os.path.join(path,'thermo')) fw = open('output_thermo.txt','w') fw.write('Name\tSMILES\tH298\tS298\t300 K\t400 K\t500 K\t600 K\t800 K\t1000 K\t1500 K\tComment\n') for mymol in pybel.readfile("xyz","testfile.txt"): bel_mol = mymol.write('smi') mol_smi = bel_mol.split()[0] mol_name = bel_mol.split()[1] print mol_name spc = Species().fromSMILES(mol_smi) print type(spc) print spc.toAdjacencyList() tdt = rmg.database.thermo.getThermoDataFromGroups(spc) tempstr = mol_name + delimiter + mol_smi + delimiter + str(tdt.H298.value*JtoCal) + delimiter + str(tdt.S298.value*JtoCal) tempstr = tempstr + delimiter + str(tdt.Cpdata.value[0]*JtoCal) + delimiter + str(tdt.Cpdata.value[1]*JtoCal) + delimiter + str(tdt.Cpdata.value[2]*JtoCal) tempstr = tempstr + delimiter + str(tdt.Cpdata.value[3]*JtoCal) + delimiter + str(tdt.Cpdata.value[4]*JtoCal) + delimiter + str(tdt.Cpdata.value[5]*JtoCal) tempstr = tempstr + delimiter + str(tdt.Cpdata.value[6]*JtoCal) + delimiter + tdt.comment + '\n' fw.write( tempstr ) fw.close()
reactants=reaction.reactants, products=reaction.products, reversible=reaction.reversible, kinetics=reaction.kinetics, library=libraryName, ) reactionList.append(library_reaction) speciesList = [] index = 0 speciesDict = kineticLibrary.getSpecies( os.path.join(settings["database.directory"], "kinetics", "libraries", libraryName, "dictionary.txt") ) for spec in speciesDict.values(): index = index + 1 species = Species(molecule=spec.molecule) species.getThermoData() species.index = index speciesList.append(species) for reaction in reactionList: for reactant in reaction.reactants: for spec in speciesList: if reactant.isIsomorphic(spec): reactant.index = spec.index spec.label = reactant.label for product in reaction.products: for spec in speciesList: if product.isIsomorphic(spec): product.index = spec.index spec.label = product.label
def testParseThermoComments(self): """ Test that the ThermoDatabase.extractSourceFromComments function works properly on various thermo comments. """ from rmgpy.thermo import NASA, NASAPolynomial # Pure group additivity thermo propane = Species( index=3, label="Propane", thermo=NASA( polynomials=[ NASAPolynomial(coeffs=[ 3.05257, 0.0125099, 3.79386e-05, -5.12022e-08, 1.87065e-11, -14454.2, 10.0672 ], Tmin=(100, 'K'), Tmax=(986.57, 'K')), NASAPolynomial(coeffs=[ 5.91316, 0.0218763, -8.17661e-06, 1.49855e-09, -1.05991e-13, -16038.9, -8.86555 ], Tmin=(986.57, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment= """Thermo group additivity estimation: group(Cs-CsCsHH) + gauche(Cs(CsCsRR)) + other(R) + group(Cs-CsHHH) + gauche(Cs(Cs(CsRR)RRR)) + other(R) + group(Cs-CsHHH) + gauche(Cs(Cs(CsRR)RRR)) + other(R)""" ), molecule=[Molecule(SMILES="CCC")]) source = self.database.extractSourceFromComments(propane) self.assertTrue( 'GAV' in source, 'Should have found that propane thermo source is GAV.') self.assertEqual(len(source['GAV']['group']), 2) self.assertEqual(len(source['GAV']['other']), 1) self.assertEqual(len(source['GAV']['gauche']), 2) # Pure library thermo dipk = Species(index=1, label="DIPK", thermo=NASA(polynomials=[ NASAPolynomial(coeffs=[ 3.35002, 0.017618, -2.46235e-05, 1.7684e-08, -4.87962e-12, 35555.7, 5.75335 ], Tmin=(100, 'K'), Tmax=(888.28, 'K')), NASAPolynomial(coeffs=[ 6.36001, 0.00406378, -1.73509e-06, 5.05949e-10, -4.49975e-14, 35021, -8.41155 ], Tmin=(888.28, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment="""Thermo library: DIPK"""), molecule=[Molecule(SMILES="CC(C)C(=O)C(C)C")]) source = self.database.extractSourceFromComments(dipk) self.assertTrue('Library' in source) # Mixed library and HBI thermo dipk_rad = Species( index=4, label="R_tert", thermo=NASA(polynomials=[ NASAPolynomial(coeffs=[ 2.90061, 0.0298018, -7.06268e-05, 6.9636e-08, -2.42414e-11, 54431, 5.44492 ], Tmin=(100, 'K'), Tmax=(882.19, 'K')), NASAPolynomial(coeffs=[ 6.70999, 0.000201027, 6.65617e-07, -7.99543e-11, 4.08721e-15, 54238.6, -9.73662 ], Tmin=(882.19, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment="""Thermo library: DIPK + radical(C2CJCHO)"""), molecule=[ Molecule(SMILES="C[C](C)C(=O)C(C)C"), Molecule(SMILES="CC(C)=C([O])C(C)C") ]) source = self.database.extractSourceFromComments(dipk_rad) self.assertTrue('Library' in source) self.assertTrue('GAV' in source) self.assertEqual(len(source['GAV']['radical']), 1) # Pure QM thermo cineole = Species( index=6, label="Cineole", thermo=NASA(polynomials=[ NASAPolynomial(coeffs=[ -0.324129, 0.0619667, 9.71008e-05, -1.60598e-07, 6.28285e-11, -38699.9, 29.3686 ], Tmin=(100, 'K'), Tmax=(985.52, 'K')), NASAPolynomial(coeffs=[ 20.6043, 0.0586913, -2.22152e-05, 4.19949e-09, -3.06046e-13, -46791, -91.4152 ], Tmin=(985.52, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment="""QM MopacMolPM3 calculation attempt 1"""), molecule=[Molecule(SMILES="CC12CCC(CC1)C(C)(C)O2")]) source = self.database.extractSourceFromComments(cineole) self.assertTrue('QM' in source) # Mixed QM and HBI thermo cineole_rad = Species( index=7, label="CineoleRad", thermo=NASA( polynomials=[ NASAPolynomial(coeffs=[ -0.2897, 0.0627717, 8.63299e-05, -1.47868e-07, 5.81665e-11, -14017.6, 31.0266 ], Tmin=(100, 'K'), Tmax=(988.76, 'K')), NASAPolynomial(coeffs=[ 20.4836, 0.0562555, -2.13903e-05, 4.05725e-09, -2.96023e-13, -21915, -88.1205 ], Tmin=(988.76, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment= """QM MopacMolPM3 calculation attempt 1 + radical(Cs_P)"""), molecule=[Molecule(SMILES="[CH2]C12CCC(CC1)C(C)(C)O2")]) source = self.database.extractSourceFromComments(cineole_rad) self.assertTrue('QM' in source) self.assertTrue('GAV' in source) self.assertEqual(len(source['GAV']['radical']), 1) # No thermo comments other = Species( index=7, label="CineoleRad", thermo=NASA( polynomials=[ NASAPolynomial(coeffs=[ -0.2897, 0.0627717, 8.63299e-05, -1.47868e-07, 5.81665e-11, -14017.6, 31.0266 ], Tmin=(100, 'K'), Tmax=(988.76, 'K')), NASAPolynomial(coeffs=[ 20.4836, 0.0562555, -2.13903e-05, 4.05725e-09, -2.96023e-13, -21915, -88.1205 ], Tmin=(988.76, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), ), molecule=[Molecule(SMILES="[CH2]C12CCC(CC1)C(C)(C)O2")]) # Function should complain if there's no thermo comments self.assertRaises(self.database.extractSourceFromComments(cineole_rad)) # Check a dummy species that has plus and minus thermo group contributions polycyclic = Species( index=7, label="dummy", thermo=NASA( polynomials=[ NASAPolynomial(coeffs=[ -0.2897, 0.0627717, 8.63299e-05, -1.47868e-07, 5.81665e-11, -14017.6, 31.0266 ], Tmin=(100, 'K'), Tmax=(988.76, 'K')), NASAPolynomial(coeffs=[ 20.4836, 0.0562555, -2.13903e-05, 4.05725e-09, -2.96023e-13, -21915, -88.1205 ], Tmin=(988.76, 'K'), Tmax=(5000, 'K')) ], Tmin=(100, 'K'), Tmax=(5000, 'K'), comment= """Thermo group additivity estimation: group(Cs-CsCsHH) + group(Cs-CsCsHH) - ring(Benzene)""" ), molecule=[Molecule(SMILES="[CH2]C12CCC(CC1)C(C)(C)O2")]) source = self.database.extractSourceFromComments(polycyclic) self.assertTrue('GAV' in source) self.assertEqual(source['GAV']['ring'][0][1], -1) # the weight of benzene contribution should be -1 self.assertEqual( source['GAV']['group'][0][1], 2) # weight of the group(Cs-CsCsHH) conbtribution should be 2
library_reaction = LibraryReaction(index=reaction.index, reactants=reaction.reactants, products=reaction.products, reversible=reaction.reversible, kinetics=reaction.kinetics, library=library_name) reaction_list.append(library_reaction) species_list = [] index = 0 species_dict = kinetic_library.get_species( os.path.join(settings['database.directory'], 'kinetics', 'libraries', library_name, 'dictionary.txt')) for spec in list(species_dict.values()): index = index + 1 species = Species(molecule=spec.molecule) species.get_thermo_data() species.index = index species_list.append(species) for reaction in reaction_list: for reactant in reaction.reactants: for spec in species_list: if reactant.is_isomorphic(spec): reactant.index = spec.index spec.label = reactant.label for product in reaction.products: for spec in species_list: if product.is_isomorphic(spec): product.index = spec.index spec.label = product.label
library_reaction = LibraryReaction(index=reaction.index, reactants=reaction.reactants, products=reaction.products, reversible=reaction.reversible, kinetics=reaction.kinetics, library=libraryName) reactionList.append(library_reaction) speciesList = [] index = 0 speciesDict = kineticLibrary.getSpecies( os.path.join(settings['database.directory'], 'kinetics', 'libraries', libraryName, 'dictionary.txt')) for spec in speciesDict.values(): index = index + 1 species = Species(molecule=spec.molecule) species.getThermoData() species.index = index speciesList.append(species) for reaction in reactionList: for reactant in reaction.reactants: for spec in speciesList: if reactant.isIsomorphic(spec): reactant.index = spec.index spec.label = reactant.label for product in reaction.products: for spec in speciesList: if product.isIsomorphic(spec): product.index = spec.index spec.label = product.label
kineticLibrary = database.kinetics.libraries[libraryName] reactionList = [] for index, entry in kineticLibrary.entries.iteritems(): reaction = entry.item reaction.kinetics = entry.data reactionList.append(reaction) speciesList = [] index = 0 speciesDict = kineticLibrary.getSpecies( os.path.join(settings['database.directory'], 'kinetics', 'libraries', libraryName, 'dictionary.txt')) for spec in speciesDict.values(): index = index + 1 species = Species(molecule=spec.molecule) species.generateThermoData(database) species.index = index speciesList.append(species) for reaction in reactionList: for reactant in reaction.reactants: for spec in speciesList: if reactant.isIsomorphic(spec): reactant.index = spec.index spec.label = reactant.label for product in reaction.products: for spec in speciesList: if product.isIsomorphic(spec): product.index = spec.index spec.label = product.label
print 'Loading {0} library'.format(libraryName) kineticLibrary = database.kinetics.libraries[libraryName] reactionList = [] for index, entry in kineticLibrary.entries.iteritems(): reaction = entry.item reaction.kinetics = entry.data reactionList.append(reaction) speciesList = [] index = 0 for spec in kineticLibrary.getSpecies().values(): index = index + 1 species = Species(molecule = spec.molecule) species.generateThermoData(database) species.index = index speciesList.append(species) for reaction in reactionList: for reactant in reaction.reactants: for spec in speciesList: if reactant.isIsomorphic(spec): reactant.index = spec.index spec.label = reactant.label for product in reaction.products: for spec in speciesList: if product.isIsomorphic(spec): product.index = spec.index spec.label = product.label