Example #1
0
class TestSoluteDatabase(TestCase):
    def setUp(self):
        self.database = SolvationDatabase()
        self.database.load(
            os.path.join(settings['database.directory'], 'solvation'))

    def runTest(self):
        pass

    def testSoluteLibrary(self):
        "Test we can obtain solute parameters from a library"
        species = Species(molecule=[
            Molecule(SMILES='COC=O')
        ])  #methyl formate - we know this is in the solute library

        libraryData = self.database.getSoluteDataFromLibrary(
            species, self.database.libraries['solute'])
        self.assertEqual(len(libraryData), 3)

        soluteData = self.database.getSoluteData(species)
        self.assertTrue(isinstance(soluteData, SoluteData))

        S = soluteData.S
        self.assertEqual(S, 0.68)
        self.assertTrue(soluteData.V is not None)

    def testMcGowan(self):
        "Test we can calculate and set the McGowan volume for species containing H,C,O,N or S"
        self.testCases = [
            ['CCCCCCCC', 1.2358],  #n-octane, in library
            ['C(CO)O', 0.5078],  #ethylene glycol
            ['CC#N', 0.4042],  #acetonitrile
            ['CCS', 0.5539]  #ethanethiol
        ]

        for smiles, volume in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            soluteData.setMcGowanVolume(
                species)  # even if it was found in library, recalculate
            self.assertTrue(
                soluteData.V is not None
            )  # so if it wasn't found in library, we should have calculated it
            self.assertAlmostEqual(
                soluteData.V, volume
            )  # the volume is what we expect given the atoms and bonds

    def testDiffusivity(self):
        "Test that for a given solvent viscosity and temperature we can calculate a solute's diffusivity"
        species = Species(molecule=[Molecule(SMILES='O')])  # water
        soluteData = self.database.getSoluteData(species)
        T = 298.
        solventViscosity = 0.00089  # water is about 8.9e-4 Pa.s
        D = soluteData.getStokesDiffusivity(T, solventViscosity)  # m2/s
        self.assertAlmostEqual((D * 1e9), 1.3, 1)
        # self-diffusivity of water is about 2e-9 m2/s

    def testSolventLibrary(self):
        "Test we can obtain solvent parameters from a library"
        solventData = self.database.getSolventData('water')
        self.assertTrue(solventData is not None)
        self.assertEqual(solventData.s_h, 2.836)
        self.assertRaises(DatabaseError, self.database.getSolventData,
                          'orange_juice')

    def testViscosity(self):
        "Test we can calculate the solvent viscosity given a temperature and its A-E correlation parameters"
        solventData = self.database.getSolventData('water')
        self.assertAlmostEqual(solventData.getSolventViscosity(298), 0.0009155)

    def testSoluteGeneration(self):
        "Test we can estimate Abraham solute parameters correctly using group contributions"

        self.testCases = [
            [
                '1,2-ethanediol', 'C(CO)O', 0.823, 0.685, 0.327, 2.572, 0.693,
                None
            ],
        ]

        for name, smiles, S, B, E, L, A, V in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteDataFromGroups(
                Species(molecule=[species.molecule[0]]))
            self.assertAlmostEqual(soluteData.S, S, places=2)
            self.assertAlmostEqual(soluteData.B, B, places=2)
            self.assertAlmostEqual(soluteData.E, E, places=2)
            self.assertAlmostEqual(soluteData.L, L, places=2)
            self.assertAlmostEqual(soluteData.A, A, places=2)

    def testLonePairSoluteGeneration(self):
        "Test we can obtain solute parameters via group additivity for a molecule with lone pairs"
        molecule = Molecule().fromAdjacencyList("""
CH2_singlet
multiplicity 1
1 C u0 p1 c0 {2,S} {3,S}
2 H u0 p0 c0 {1,S}
3 H u0 p0 c0 {1,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationAmmonia(self):
        "Test we can obtain solute parameters via group additivity for ammonia"
        molecule = Molecule().fromAdjacencyList("""
1 N u0 p1 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}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationAmide(self):
        "Test that we can obtain solute parameters via group additivity for an amide"
        molecule = Molecule().fromAdjacencyList("""
1  N u0 p1 {2,S} {3,S} {4,S}
2   H   u0 {1,S}
3   C u0 {1,S} {6,S} {7,S} {8,S}
4   C  u0 {1,S} {5,D} {9,S}
5   O  u0 p2 {4,D}
6   H   u0 {3,S}
7   H   u0 {3,S}
8   H   u0 {3,S}
9   H   u0 {4,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationCO(self):
        "Test that we can obtain solute parameters via group additivity for CO."
        molecule = Molecule().fromAdjacencyList("""
1  C u0 p1 c-1 {2,T}
2  O u0 p1 c+1 {1,T}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testRadicalandLonePairGeneration(self):
        """
        Test we can obtain solute parameters via group additivity for a molecule with both lone 
        pairs and a radical
        """
        molecule = Molecule().fromAdjacencyList("""
[C]OH
multiplicity 2
1 C u1 p1 c0 {2,S}
2 O u0 p2 c0 {1,S} {3,S}
3 H u0 p0 c0 {2,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testCorrectionGeneration(self):
        "Test we can estimate solvation thermochemistry."
        self.testCases = [
            # solventName, soluteName, soluteSMILES, Hsolv, Gsolv
            ['water', 'acetic acid', 'C(C)(=O)O', -56500, -6700 * 4.184],
            [
                'water', 'naphthalene', 'C1=CC=CC2=CC=CC=C12', -42800,
                -2390 * 4.184
            ],
            ['1-octanol', 'octane', 'CCCCCCCC', -40080, -4180 * 4.184],
            ['1-octanol', 'tetrahydrofuran', 'C1CCOC1', -28320, -3930 * 4.184],
            ['benzene', 'toluene', 'C1(=CC=CC=C1)C', -37660, -5320 * 4.184],
            ['benzene', '1,4-dioxane', 'C1COCCO1', -39030, -5210 * 4.184]
        ]

        for solventName, soluteName, smiles, H, G in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            solventData = self.database.getSolventData(solventName)
            solvationCorrection = self.database.getSolvationCorrection(
                soluteData, solventData)
            self.assertAlmostEqual(
                solvationCorrection.enthalpy / 10000.,
                H / 10000.,
                0,
                msg=
                "Solvation enthalpy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}"
                .format(soluteName, solventName, solvationCorrection.enthalpy,
                        H))  #0 decimal place, in 10kJ.
            self.assertAlmostEqual(
                solvationCorrection.gibbs / 10000.,
                G / 10000.,
                0,
                msg=
                "Solvation Gibbs free energy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}"
                .format(soluteName, solventName, solvationCorrection.gibbs, G))
Example #2
0
class TestSoluteDatabase(TestCase):
    def setUp(self):
        self.database = SolvationDatabase()
        self.database.load(
            os.path.join(settings['database.directory'], 'solvation'))

    def tearDown(self):
        """
        Reset the database & liquid parameters for solution
        """
        import rmgpy.data.rmg
        rmgpy.data.rmg.database = None

        from rmgpy.rmg.model import Species as DifferentSpecies
        DifferentSpecies.solventData = None
        DifferentSpecies.solventName = None
        DifferentSpecies.solventStructure = None
        DifferentSpecies.solventViscosity = None

    def runTest(self):
        pass

    def testSoluteLibrary(self):
        "Test we can obtain solute parameters from a library"
        species = Species(molecule=[
            Molecule(SMILES='COC=O')
        ])  #methyl formate - we know this is in the solute library

        libraryData = self.database.getSoluteDataFromLibrary(
            species, self.database.libraries['solute'])
        self.assertEqual(len(libraryData), 3)

        soluteData = self.database.getSoluteData(species)
        self.assertTrue(isinstance(soluteData, SoluteData))

        S = soluteData.S
        self.assertEqual(S, 0.68)
        self.assertTrue(soluteData.V is not None)

    def testMcGowan(self):
        "Test we can calculate and set the McGowan volume for species containing H,C,O,N or S"
        self.testCases = [
            ['CCCCCCCC', 1.2358],  #n-octane, in library
            ['C(CO)O', 0.5078],  #ethylene glycol
            ['CC#N', 0.4042],  #acetonitrile
            ['CCS', 0.5539]  #ethanethiol
        ]

        for smiles, volume in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            soluteData.setMcGowanVolume(
                species)  # even if it was found in library, recalculate
            self.assertTrue(
                soluteData.V is not None
            )  # so if it wasn't found in library, we should have calculated it
            self.assertAlmostEqual(
                soluteData.V, volume
            )  # the volume is what we expect given the atoms and bonds

    def testDiffusivity(self):
        "Test that for a given solvent viscosity and temperature we can calculate a solute's diffusivity"
        species = Species(molecule=[Molecule(SMILES='O')])  # water
        soluteData = self.database.getSoluteData(species)
        T = 298.
        solventViscosity = 0.00089  # water is about 8.9e-4 Pa.s
        D = soluteData.getStokesDiffusivity(T, solventViscosity)  # m2/s
        self.assertAlmostEqual((D * 1e9), 1.3, 1)
        # self-diffusivity of water is about 2e-9 m2/s

    def testSolventLibrary(self):
        "Test we can obtain solvent parameters from a library"
        solventData = self.database.getSolventData('water')
        self.assertTrue(solventData is not None)
        self.assertEqual(solventData.s_h, 2.836)
        self.assertRaises(DatabaseError, self.database.getSolventData,
                          'orange_juice')

    def testViscosity(self):
        "Test we can calculate the solvent viscosity given a temperature and its A-E correlation parameters"
        solventData = self.database.getSolventData('water')
        self.assertAlmostEqual(solventData.getSolventViscosity(298), 0.0009155)

    def testSoluteGeneration(self):
        "Test we can estimate Abraham solute parameters correctly using group contributions"

        self.testCases = [
            [
                '1,2-ethanediol', 'C(CO)O', 0.823, 0.685, 0.327, 2.572, 0.693,
                None
            ],
        ]

        for name, smiles, S, B, E, L, A, V in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteDataFromGroups(
                Species(molecule=[species.molecule[0]]))
            self.assertAlmostEqual(soluteData.S, S, places=2)
            self.assertAlmostEqual(soluteData.B, B, places=2)
            self.assertAlmostEqual(soluteData.E, E, places=2)
            self.assertAlmostEqual(soluteData.L, L, places=2)
            self.assertAlmostEqual(soluteData.A, A, places=2)

    def testLonePairSoluteGeneration(self):
        "Test we can obtain solute parameters via group additivity for a molecule with lone pairs"
        molecule = Molecule().fromAdjacencyList("""
CH2_singlet
multiplicity 1
1 C u0 p1 c0 {2,S} {3,S}
2 H u0 p0 c0 {1,S}
3 H u0 p0 c0 {1,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationAmmonia(self):
        "Test we can obtain solute parameters via group additivity for ammonia"
        molecule = Molecule().fromAdjacencyList("""
1 N u0 p1 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}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationAmide(self):
        "Test that we can obtain solute parameters via group additivity for an amide"
        molecule = Molecule().fromAdjacencyList("""
1  N u0 p1 {2,S} {3,S} {4,S}
2   H   u0 {1,S}
3   C u0 {1,S} {6,S} {7,S} {8,S}
4   C  u0 {1,S} {5,D} {9,S}
5   O  u0 p2 {4,D}
6   H   u0 {3,S}
7   H   u0 {3,S}
8   H   u0 {3,S}
9   H   u0 {4,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationCO(self):
        "Test that we can obtain solute parameters via group additivity for CO."
        molecule = Molecule().fromAdjacencyList("""
1  C u0 p1 c-1 {2,T}
2  O u0 p1 c+1 {1,T}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testRadicalandLonePairGeneration(self):
        """
        Test we can obtain solute parameters via group additivity for a molecule with both lone 
        pairs and a radical
        """
        molecule = Molecule().fromAdjacencyList("""
[C]OH
multiplicity 2
1 C u1 p1 c0 {2,S}
2 O u0 p2 c0 {1,S} {3,S}
3 H u0 p0 c0 {2,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testCorrectionGeneration(self):
        "Test we can estimate solvation thermochemistry."
        self.testCases = [
            # solventName, soluteName, soluteSMILES, Hsolv, Gsolv
            ['water', 'acetic acid', 'C(C)(=O)O', -56500, -6700 * 4.184],
            [
                'water', 'naphthalene', 'C1=CC=CC2=CC=CC=C12', -42800,
                -2390 * 4.184
            ],
            ['1-octanol', 'octane', 'CCCCCCCC', -40080, -4180 * 4.184],
            ['1-octanol', 'tetrahydrofuran', 'C1CCOC1', -28320, -3930 * 4.184],
            ['benzene', 'toluene', 'C1(=CC=CC=C1)C', -37660, -5320 * 4.184],
            ['benzene', '1,4-dioxane', 'C1COCCO1', -39030, -5210 * 4.184]
        ]

        for solventName, soluteName, smiles, H, G in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            solventData = self.database.getSolventData(solventName)
            solvationCorrection = self.database.getSolvationCorrection(
                soluteData, solventData)
            self.assertAlmostEqual(
                solvationCorrection.enthalpy / 10000.,
                H / 10000.,
                0,
                msg=
                "Solvation enthalpy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}"
                .format(soluteName, solventName, solvationCorrection.enthalpy,
                        H))  #0 decimal place, in 10kJ.
            self.assertAlmostEqual(
                solvationCorrection.gibbs / 10000.,
                G / 10000.,
                0,
                msg=
                "Solvation Gibbs free energy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}"
                .format(soluteName, solventName, solvationCorrection.gibbs, G))

    def testInitialSpecies(self):
        " Test we can check whether the solvent is listed as one of the initial species in various scenarios "

        # Case 1. when SMILES for solvent is available, the molecular structures of the initial species and the solvent
        # are compared to check whether the solvent is in the initial species list

        # Case 1-1: the solvent water is not in the initialSpecies list, so it raises Exception
        rmg = RMG()
        rmg.initialSpecies = []
        solute = Species(label='n-octane',
                         molecule=[Molecule().fromSMILES('C(CCCCC)CC')])
        rmg.initialSpecies.append(solute)
        rmg.solvent = 'water'
        solventStructure = Species().fromSMILES('O')
        self.assertRaises(Exception,
                          self.database.checkSolventinInitialSpecies, rmg,
                          solventStructure)

        # Case 1-2: the solvent is now octane and it is listed as the initialSpecies. Although the string
        # names of the solute and the solvent are different, because the solvent SMILES is provided,
        # it can identify the 'n-octane' as the solvent
        rmg.solvent = 'octane'
        solventStructure = Species().fromSMILES('CCCCCCCC')
        self.database.checkSolventinInitialSpecies(rmg, solventStructure)
        self.assertTrue(rmg.initialSpecies[0].isSolvent)

        # Case 2: the solvent SMILES is not provided. In this case, it can identify the species as the
        # solvent by looking at the string name.

        # Case 2-1: Since 'n-octane and 'octane' are not equal, it raises Exception
        solventStructure = None
        self.assertRaises(Exception,
                          self.database.checkSolventinInitialSpecies, rmg,
                          solventStructure)

        # Case 2-2: The label 'n-ocatne' is corrected to 'octane', so it is identified as the solvent
        rmg.initialSpecies[0].label = 'octane'
        self.database.checkSolventinInitialSpecies(rmg, solventStructure)
        self.assertTrue(rmg.initialSpecies[0].isSolvent)

    def testSolventMolecule(self):
        " Test we can give a proper value for the solvent molecular structure when different solvent databases are given "

        # solventlibrary.entries['solvent_label'].item should be the instance of Species with the solvent's molecular structure
        # if the solvent database contains the solvent SMILES or adjacency list. If not, then item is None

        # Case 1: When the solventDatabase does not contain the solvent SMILES, the item attribute is None
        solventlibrary = SolventLibrary()
        solventlibrary.loadEntry(index=1, label='water', solvent=None)
        self.assertTrue(solventlibrary.entries['water'].item is None)

        # Case 2: When the solventDatabase contains the correct solvent SMILES, the item attribute is the instance of
        # Species with the correct solvent molecular structure
        solventlibrary.loadEntry(index=2,
                                 label='octane',
                                 solvent=None,
                                 molecule='CCCCCCCC')
        solventSpecies = Species().fromSMILES('C(CCCCC)CC')
        self.assertTrue(
            solventSpecies.isIsomorphic(solventlibrary.entries['octane'].item))

        # Case 3: When the solventDatabase contains the correct solvent adjacency list, the item attribute is the instance of
        # the species with the correct solvent molecular structure.
        # This will display the SMILES Parse Error message from the external function, but ignore it.
        solventlibrary.loadEntry(index=3,
                                 label='ethanol',
                                 solvent=None,
                                 molecule="""
1 C u0 p0 c0 {2,S} {4,S} {5,S} {6,S}
2 C u0 p0 c0 {1,S} {3,S} {7,S} {8,S}
3 O u0 p2 c0 {2,S} {9,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {1,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
9 H u0 p0 c0 {3,S}
""")
        solventSpecies = Species().fromSMILES('CCO')
        self.assertTrue(
            solventSpecies.isIsomorphic(
                solventlibrary.entries['ethanol'].item))

        # Case 4: when the solventDatabase contains incorrect values for the molecule attribute, it raises Exception
        # This will display the SMILES Parse Error message from the external function, but ignore it.
        self.assertRaises(Exception,
                          solventlibrary.loadEntry,
                          index=4,
                          label='benzene',
                          solvent=None,
                          molecule='ring')
Example #3
0
class TestSoluteDatabase(TestCase):
    
    def setUp(self):
        self.database = SolvationDatabase()
        self.database.load(os.path.join(settings['database.directory'], 'solvation'))
    
    def runTest(self):
        pass
    
    def testSoluteLibrary(self):
        "Test we can obtain solute parameters from a library"
        species = Species(molecule=[Molecule(SMILES='COC=O')]) #methyl formate - we know this is in the solute library
        
        libraryData = self.database.getSoluteDataFromLibrary(species, self.database.libraries['solute'])
        self.assertEqual(len(libraryData), 3)
        
        soluteData = self.database.getSoluteData(species)
        self.assertTrue(isinstance(soluteData, SoluteData))
        
        S = soluteData.S
        self.assertEqual(S, 0.68)
        self.assertTrue(soluteData.V is not None)
     
    def testMcGowan(self):
        "Test we can calculate and set the McGowan volume for species containing H,C,O,N or S"
        self.testCases = [
                          ['CCCCCCCC', 1.2358], #n-octane, in library
                          ['C(CO)O', 0.5078], #ethylene glycol
                          ['CC#N', 0.4042], #acetonitrile
                          ['CCS', 0.5539] #ethanethiol
                           ]
        
        for smiles, volume in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            soluteData.setMcGowanVolume(species) # even if it was found in library, recalculate
            self.assertTrue(soluteData.V is not None) # so if it wasn't found in library, we should have calculated it
            self.assertAlmostEqual(soluteData.V, volume) # the volume is what we expect given the atoms and bonds 
            
    
    def testDiffusivity(self):
        "Test that for a given solvent viscosity and temperature we can calculate a solute's diffusivity"
        species = Species(molecule=[Molecule(SMILES='COC=O')])
        soluteData = self.database.getSoluteData(species)
        T = 298
        solventViscosity = 0.001
        D = soluteData.getStokesDiffusivity(T, solventViscosity)
        self.assertAlmostEqual((D*1E12), 0.00000979)
        
    def testSolventLibrary(self):
        "Test we can obtain solvent parameters from a library"
        solventData = self.database.getSolventData('water')
        self.assertTrue(solventData is not None)
        self.assertEqual(solventData.s_h, 2.836)
        self.assertRaises(DatabaseError, self.database.getSolventData, 'orange_juice')
        
    def testViscosity(self):
        "Test we can calculate the solvent viscosity given a temperature and its A-E correlation parameters"
        solventData = self.database.getSolventData('water')  
        self.assertAlmostEqual(solventData.getSolventViscosity(298), 0.0009155)

    def testSoluteGeneration(self):
        "Test we can estimate Abraham solute parameters correctly using group contributions"
        
        self.testCases = [
        ['1,2-ethanediol', 'C(CO)O', 0.823, 0.685, 0.327, 2.572, 0.693, None],
        ]
        
        for name, smiles, S, B, E, L, A, V in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteDataFromGroups(Species(molecule=[species.molecule[0]]))
            self.assertAlmostEqual(soluteData.S, S, places=2)
            self.assertAlmostEqual(soluteData.B, B, places=2)
            self.assertAlmostEqual(soluteData.E, E, places=2)
            self.assertAlmostEqual(soluteData.L, L, places=2)
            self.assertAlmostEqual(soluteData.A, A, places=2)

    def testLonePairSoluteGeneration(self):
        "Test we can obtain solute parameters via group additivity for a molecule with lone pairs"
        molecule=Molecule().fromAdjacencyList(
"""
CH2_singlet
multiplicity 1
1 C u0 p1 c0 {2,S} {3,S}
2 H u0 p0 c0 {1,S}
3 H u0 p0 c0 {1,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
        
    def testSoluteDataGenerationAmmonia(self):
        "Test we can obtain solute parameters via group additivity for ammonia"
        molecule=Molecule().fromAdjacencyList(
"""
1 N u0 p1 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}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
        
    def testSoluteDataGenerationAmide(self):
        "Test that we can obtain solute parameters via group additivity for an amide"        
        molecule=Molecule().fromAdjacencyList(
"""
1  N u0 p1 {2,S} {3,S} {4,S}
2   H   u0 {1,S}
3   C u0 {1,S} {6,S} {7,S} {8,S}
4   C  u0 {1,S} {5,D} {9,S}
5   O  u0 p2 {4,D}
6   H   u0 {3,S}
7   H   u0 {3,S}
8   H   u0 {3,S}
9   H   u0 {4,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
        
    def testRadicalandLonePairGeneration(self):
        """
        Test we can obtain solute parameters via group additivity for a molecule with both lone 
        pairs and a radical
        """
        molecule=Molecule().fromAdjacencyList(
"""
[C]OH
multiplicity 2
1 C u1 p1 c0 {2,S}
2 O u0 p2 c0 {1,S} {3,S}
3 H u0 p0 c0 {2,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testCorrectionGeneration(self):
        "Test we can estimate solvation thermochemistry."
        self.testCases = [
        # solventName, soluteName, soluteSMILES, Hsolv, Gsolv
        ['water', 'acetic acid', 'C(C)(=O)O', -56500, -6700*4.184],
        ['water', 'naphthalene', 'C1=CC=CC2=CC=CC=C12', -42800, -2390*4.184],
        ['1-octanol', 'octane', 'CCCCCCCC', -40080, -4180*4.184],
        ['1-octanol', 'tetrahydrofuran', 'C1CCOC1', -28320, -3930*4.184],
        ['benzene', 'toluene', 'C1(=CC=CC=C1)C', -37660, -5320*4.184],
        ['benzene', '1,4-dioxane', 'C1COCCO1', -39030, -5210*4.184]
        ]
        
        for solventName, soluteName, smiles, H, G in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            solventData = self.database.getSolventData(solventName)
            solvationCorrection = self.database.getSolvationCorrection(soluteData, solventData)
            self.assertAlmostEqual(solvationCorrection.enthalpy / 10000., H / 10000., 0, msg="Solvation enthalpy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.enthalpy, H))  #0 decimal place, in 10kJ.
            self.assertAlmostEqual(solvationCorrection.gibbs / 10000., G / 10000., 0, msg="Solvation Gibbs free energy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.gibbs, G))
class TestDiffusionLimited(unittest.TestCase):
    """
    Contains unit tests of the DiffusionLimited class.
    """
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        octyl_pri = Species(
            label="",
            thermo=NASA(polynomials=[
                NASAPolynomial(coeffs=[
                    -0.772759, 0.093255, -5.84447e-05, 1.8557e-08,
                    -2.37127e-12, -3926.9, 37.6131
                ],
                               Tmin=(298, 'K'),
                               Tmax=(1390, 'K')),
                NASAPolynomial(coeffs=[
                    25.051, 0.036948, -1.25765e-05, 1.94628e-09, -1.12669e-13,
                    -13330.1, -102.557
                ],
                               Tmin=(1390, 'K'),
                               Tmax=(5000, 'K'))
            ],
                        Tmin=(298, 'K'),
                        Tmax=(5000, 'K'),
                        Cp0=(33.2579, 'J/(mol*K)'),
                        CpInf=(577.856, 'J/(mol*K)'),
                        comment="""Thermo library: JetSurF0.2"""),
            molecule=[Molecule(SMILES="[CH2]CCCCCCC")])
        octyl_sec = Species(
            label="",
            thermo=NASA(polynomials=[
                NASAPolynomial(coeffs=[
                    -0.304233, 0.0880077, -4.90743e-05, 1.21858e-08,
                    -8.87773e-13, -5237.93, 36.6583
                ],
                               Tmin=(298, 'K'),
                               Tmax=(1383, 'K')),
                NASAPolynomial(coeffs=[
                    24.9044, 0.0366394, -1.2385e-05, 1.90835e-09, -1.10161e-13,
                    -14713.5, -101.345
                ],
                               Tmin=(1383, 'K'),
                               Tmax=(5000, 'K'))
            ],
                        Tmin=(298, 'K'),
                        Tmax=(5000, 'K'),
                        Cp0=(33.2579, 'J/(mol*K)'),
                        CpInf=(577.856, 'J/(mol*K)'),
                        comment="""Thermo library: JetSurF0.2"""),
            molecule=[Molecule(SMILES="CC[CH]CCCCC")])
        ethane = Species(label="",
                         thermo=ThermoData(
                             Tdata=([300, 400, 500, 600, 800, 1000,
                                     1500], 'K'),
                             Cpdata=([
                                 10.294, 12.643, 14.933, 16.932, 20.033,
                                 22.438, 26.281
                             ], 'cal/(mol*K)'),
                             H298=(12.549, 'kcal/mol'),
                             S298=(52.379, 'cal/(mol*K)'),
                             Cp0=(33.2579, 'J/(mol*K)'),
                             CpInf=(133.032, 'J/(mol*K)'),
                             comment="""Thermo library: CH"""),
                         molecule=[Molecule(SMILES="C=C")])
        decyl = Species(label="",
                        thermo=NASA(polynomials=[
                            NASAPolynomial(coeffs=[
                                -1.31358, 0.117973, -7.51843e-05, 2.43331e-08,
                                -3.17523e-12, -9689.68, 43.501
                            ],
                                           Tmin=(298, 'K'),
                                           Tmax=(1390, 'K')),
                            NASAPolynomial(coeffs=[
                                31.5697, 0.0455818, -1.54995e-05, 2.39711e-09,
                                -1.3871e-13, -21573.8, -134.709
                            ],
                                           Tmin=(1390, 'K'),
                                           Tmax=(5000, 'K'))
                        ],
                                    Tmin=(298, 'K'),
                                    Tmax=(5000, 'K'),
                                    Cp0=(33.2579, 'J/(mol*K)'),
                                    CpInf=(719.202, 'J/(mol*K)'),
                                    comment="""Thermo library: JetSurF0.2"""),
                        molecule=[Molecule(SMILES="[CH2]CCCCCCCCC")])
        acetone = Species(label="",
                          thermo=NASA(polynomials=[
                              NASAPolynomial(coeffs=[
                                  3.75568, 0.0264934, -6.55661e-05,
                                  1.94971e-07, -1.82059e-10, -27905.3, 9.0162
                              ],
                                             Tmin=(10, 'K'),
                                             Tmax=(422.477, 'K')),
                              NASAPolynomial(coeffs=[
                                  0.701289, 0.0344988, -1.9736e-05,
                                  5.48052e-09, -5.92612e-13, -27460.6, 23.329
                              ],
                                             Tmin=(422.477, 'K'),
                                             Tmax=(3000, 'K'))
                          ],
                                      Tmin=(10, 'K'),
                                      Tmax=(3000, 'K'),
                                      E0=(-232.025, 'kJ/mol'),
                                      Cp0=(33.2579, 'J/(mol*K)'),
                                      CpInf=(232.805, 'J/(mol*K)')),
                          molecule=[Molecule(SMILES="CC(=O)C")])
        peracetic_acid = Species(label="",
                                 thermo=NASA(polynomials=[
                                     NASAPolynomial(coeffs=[
                                         3.81786, 0.016419, 3.32204e-05,
                                         -8.98403e-08, 6.63474e-11, -42057.8,
                                         9.65245
                                     ],
                                                    Tmin=(10, 'K'),
                                                    Tmax=(354.579, 'K')),
                                     NASAPolynomial(coeffs=[
                                         2.75993, 0.0283534, -1.72659e-05,
                                         5.08158e-09, -5.77773e-13, -41982.8,
                                         13.6595
                                     ],
                                                    Tmin=(354.579, 'K'),
                                                    Tmax=(3000, 'K'))
                                 ],
                                             Tmin=(10, 'K'),
                                             Tmax=(3000, 'K'),
                                             E0=(-349.698, 'kJ/mol'),
                                             Cp0=(33.2579, 'J/(mol*K)'),
                                             CpInf=(199.547, 'J/(mol*K)')),
                                 molecule=[Molecule(SMILES="CC(=O)OO")])
        acetic_acid = Species(label="",
                              thermo=NASA(polynomials=[
                                  NASAPolynomial(coeffs=[
                                      3.97665, 0.00159915, 8.5542e-05,
                                      -1.76486e-07, 1.20201e-10, -53911.5,
                                      8.99309
                                  ],
                                                 Tmin=(10, 'K'),
                                                 Tmax=(375.616, 'K')),
                                  NASAPolynomial(coeffs=[
                                      1.57088, 0.0272146, -1.67357e-05,
                                      5.01453e-09, -5.82273e-13, -53730.7,
                                      18.2442
                                  ],
                                                 Tmin=(375.616, 'K'),
                                                 Tmax=(3000, 'K'))
                              ],
                                          Tmin=(10, 'K'),
                                          Tmax=(3000, 'K'),
                                          E0=(-448.245, 'kJ/mol'),
                                          Cp0=(33.2579, 'J/(mol*K)'),
                                          CpInf=(182.918, 'J/(mol*K)')),
                              molecule=[Molecule(SMILES="CC(=O)O")])
        criegee = Species(label="",
                          thermo=NASA(polynomials=[
                              NASAPolynomial(coeffs=[
                                  3.23876, 0.0679583, -3.35611e-05,
                                  7.91519e-10, 3.13038e-12, -77986, 13.6438
                              ],
                                             Tmin=(10, 'K'),
                                             Tmax=(1053.46, 'K')),
                              NASAPolynomial(coeffs=[
                                  9.84525, 0.0536795, -2.86165e-05,
                                  7.39945e-09, -7.48482e-13, -79977.6, -21.4187
                              ],
                                             Tmin=(1053.46, 'K'),
                                             Tmax=(3000, 'K'))
                          ],
                                      Tmin=(10, 'K'),
                                      Tmax=(3000, 'K'),
                                      E0=(-648.47, 'kJ/mol'),
                                      Cp0=(33.2579, 'J/(mol*K)'),
                                      CpInf=(457.296, 'J/(mol*K)')),
                          molecule=[Molecule(SMILES="CC(=O)OOC(C)(O)C")])
        self.database = SolvationDatabase()
        self.database.load(
            os.path.join(settings['database.directory'], 'solvation'))
        self.solvent = 'octane'
        diffusionLimiter.enable(self.database.getSolventData(self.solvent),
                                self.database)
        self.T = 298
        self.uni_reaction = Reaction(reactants=[octyl_pri],
                                     products=[octyl_sec])
        self.uni_reaction.kinetics = Arrhenius(A=(2.0, '1/s'),
                                               n=0,
                                               Ea=(0, 'kJ/mol'))
        self.bi_uni_reaction = Reaction(reactants=[octyl_pri, ethane],
                                        products=[decyl])
        self.bi_uni_reaction.kinetics = Arrhenius(A=(1.0E-22,
                                                     'cm^3/molecule/s'),
                                                  n=0,
                                                  Ea=(0, 'kJ/mol'))
        self.tri_bi_reaction = Reaction(
            reactants=[acetone, peracetic_acid, acetic_acid],
            products=[criegee, acetic_acid])
        self.tri_bi_reaction.kinetics = Arrhenius(A=(1.07543e-11,
                                                     'cm^6/(mol^2*s)'),
                                                  n=5.47295,
                                                  Ea=(-38.5379, 'kJ/mol'))
        self.intrinsic_rates = {
            self.uni_reaction:
            self.uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.bi_uni_reaction:
            self.bi_uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.tri_bi_reaction:
            self.tri_bi_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
        }

    def tearDown(self):
        diffusionLimiter.disable()

    def testGetEffectiveRateUnimolecular(self):
        """
        Tests that the effective rate is the same as the intrinsic rate for
        unimiolecular reactions.
        """
        effective_rate = diffusionLimiter.getEffectiveRate(
            self.uni_reaction, self.T)
        self.assertEqual(effective_rate,
                         self.intrinsic_rates[self.uni_reaction])

    def testGetEffectiveRate2to1(self):
        """
        Tests that the effective rate is limited in the forward direction for
        a 2 -> 1 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(
            self.bi_uni_reaction, self.T)
        self.assertTrue(
            effective_rate < self.intrinsic_rates[self.bi_uni_reaction])
        self.assertTrue(
            effective_rate >= 0.2 * self.intrinsic_rates[self.bi_uni_reaction])

    def testGetEffectiveRate3to2(self):
        """
        Tests that the effective rate is limited for a 3 -> 2 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(
            self.tri_bi_reaction, self.T)
        self.assertTrue(
            effective_rate < self.intrinsic_rates[self.tri_bi_reaction])
        self.assertTrue(
            effective_rate >= 0.2 * self.intrinsic_rates[self.tri_bi_reaction])
Example #5
0
class TestSoluteDatabase(TestCase):
    
    def setUp(self):
        self.database = SolvationDatabase()
        self.database.load(os.path.join(settings['database.directory'], 'solvation'))
    
    def runTest(self):
        pass
    
    def testSoluteLibrary(self):
        "Test we can obtain solute parameters from a library"
        species = Species(molecule=[Molecule(SMILES='COC=O')]) #methyl formate - we know this is in the solute library
        
        libraryData = self.database.getSoluteDataFromLibrary(species, self.database.libraries['solute'])
        self.assertEqual(len(libraryData), 3)
        
        soluteData = self.database.getSoluteData(species)
        self.assertTrue(isinstance(soluteData, SoluteData))
        
        S = soluteData.S
        self.assertEqual(S, 0.68)
        self.assertTrue(soluteData.V is not None)
     
    def testMcGowan(self):
        "Test we can calculate and set the McGowan volume for species containing H,C,O,N or S"
        self.testCases = [
                          ['CCCCCCCC', 1.2358], #n-octane, in library
                          ['C(CO)O', 0.5078], #ethylene glycol
                          ['CC#N', 0.4042], #acetonitrile
                          ['CCS', 0.5539] #ethanethiol
                           ]
        
        for smiles, volume in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            soluteData.setMcGowanVolume(species) # even if it was found in library, recalculate
            self.assertTrue(soluteData.V is not None) # so if it wasn't found in library, we should have calculated it
            self.assertAlmostEqual(soluteData.V, volume) # the volume is what we expect given the atoms and bonds 
            
    
    def testDiffusivity(self):
        "Test that for a given solvent viscosity and temperature we can calculate a solute's diffusivity"
        species = Species(molecule=[Molecule(SMILES='O')])  # water
        soluteData = self.database.getSoluteData(species)
        T = 298.
        solventViscosity = 0.00089  # water is about 8.9e-4 Pa.s
        D = soluteData.getStokesDiffusivity(T, solventViscosity)  # m2/s
        self.assertAlmostEqual((D * 1e9), 1.3, 1)
        # self-diffusivity of water is about 2e-9 m2/s
        
    def testSolventLibrary(self):
        "Test we can obtain solvent parameters from a library"
        solventData = self.database.getSolventData('water')
        self.assertTrue(solventData is not None)
        self.assertEqual(solventData.s_h, 2.836)
        self.assertRaises(DatabaseError, self.database.getSolventData, 'orange_juice')
        
    def testViscosity(self):
        "Test we can calculate the solvent viscosity given a temperature and its A-E correlation parameters"
        solventData = self.database.getSolventData('water')  
        self.assertAlmostEqual(solventData.getSolventViscosity(298), 0.0009155)

    def testSoluteGeneration(self):
        "Test we can estimate Abraham solute parameters correctly using group contributions"
        
        self.testCases = [
        ['1,2-ethanediol', 'C(CO)O', 0.823, 0.685, 0.327, 2.572, 0.693, None],
        ]
        
        for name, smiles, S, B, E, L, A, V in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteDataFromGroups(Species(molecule=[species.molecule[0]]))
            self.assertAlmostEqual(soluteData.S, S, places=2)
            self.assertAlmostEqual(soluteData.B, B, places=2)
            self.assertAlmostEqual(soluteData.E, E, places=2)
            self.assertAlmostEqual(soluteData.L, L, places=2)
            self.assertAlmostEqual(soluteData.A, A, places=2)

    def testLonePairSoluteGeneration(self):
        "Test we can obtain solute parameters via group additivity for a molecule with lone pairs"
        molecule=Molecule().fromAdjacencyList(
"""
CH2_singlet
multiplicity 1
1 C u0 p1 c0 {2,S} {3,S}
2 H u0 p0 c0 {1,S}
3 H u0 p0 c0 {1,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
        
    def testSoluteDataGenerationAmmonia(self):
        "Test we can obtain solute parameters via group additivity for ammonia"
        molecule=Molecule().fromAdjacencyList(
"""
1 N u0 p1 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}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
        
    def testSoluteDataGenerationAmide(self):
        "Test that we can obtain solute parameters via group additivity for an amide"        
        molecule=Molecule().fromAdjacencyList(
"""
1  N u0 p1 {2,S} {3,S} {4,S}
2   H   u0 {1,S}
3   C u0 {1,S} {6,S} {7,S} {8,S}
4   C  u0 {1,S} {5,D} {9,S}
5   O  u0 p2 {4,D}
6   H   u0 {3,S}
7   H   u0 {3,S}
8   H   u0 {3,S}
9   H   u0 {4,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testSoluteDataGenerationCO(self):
        "Test that we can obtain solute parameters via group additivity for CO."        
        molecule=Molecule().fromAdjacencyList(
"""
1  C u0 p1 c-1 {2,T}
2  O u0 p1 c+1 {1,T}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)
    
    def testRadicalandLonePairGeneration(self):
        """
        Test we can obtain solute parameters via group additivity for a molecule with both lone 
        pairs and a radical
        """
        molecule=Molecule().fromAdjacencyList(
"""
[C]OH
multiplicity 2
1 C u1 p1 c0 {2,S}
2 O u0 p2 c0 {1,S} {3,S}
3 H u0 p0 c0 {2,S}
""")
        species = Species(molecule=[molecule])
        soluteData = self.database.getSoluteDataFromGroups(species)
        self.assertTrue(soluteData is not None)

    def testCorrectionGeneration(self):
        "Test we can estimate solvation thermochemistry."
        self.testCases = [
        # solventName, soluteName, soluteSMILES, Hsolv, Gsolv
        ['water', 'acetic acid', 'C(C)(=O)O', -56500, -6700*4.184],
        ['water', 'naphthalene', 'C1=CC=CC2=CC=CC=C12', -42800, -2390*4.184],
        ['1-octanol', 'octane', 'CCCCCCCC', -40080, -4180*4.184],
        ['1-octanol', 'tetrahydrofuran', 'C1CCOC1', -28320, -3930*4.184],
        ['benzene', 'toluene', 'C1(=CC=CC=C1)C', -37660, -5320*4.184],
        ['benzene', '1,4-dioxane', 'C1COCCO1', -39030, -5210*4.184]
        ]
        
        for solventName, soluteName, smiles, H, G in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            solventData = self.database.getSolventData(solventName)
            solvationCorrection = self.database.getSolvationCorrection(soluteData, solventData)
            self.assertAlmostEqual(solvationCorrection.enthalpy / 10000., H / 10000., 0, msg="Solvation enthalpy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.enthalpy, H))  #0 decimal place, in 10kJ.
            self.assertAlmostEqual(solvationCorrection.gibbs / 10000., G / 10000., 0, msg="Solvation Gibbs free energy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.gibbs, G))

    def testInitialSpecies(self):
        " Test we can check whether the solvent is listed as one of the initial species in various scenarios "

        # Case 1. when SMILES for solvent is available, the molecular structures of the initial species and the solvent
        # are compared to check whether the solvent is in the initial species list

        # Case 1-1: the solvent water is not in the initialSpecies list, so it raises Exception
        rmg=RMG()
        rmg.initialSpecies = []
        solute = Species(label='n-octane', molecule=[Molecule().fromSMILES('C(CCCCC)CC')])
        rmg.initialSpecies.append(solute)
        rmg.solvent = 'water'
        solventStructure = Species().fromSMILES('O')
        self.assertRaises(Exception, self.database.checkSolventinInitialSpecies, rmg, solventStructure)

        # Case 1-2: the solvent is now octane and it is listed as the initialSpecies. Although the string
        # names of the solute and the solvent are different, because the solvent SMILES is provided,
        # it can identify the 'n-octane' as the solvent
        rmg.solvent = 'octane'
        solventStructure = Species().fromSMILES('CCCCCCCC')
        self.database.checkSolventinInitialSpecies(rmg, solventStructure)
        self.assertTrue(rmg.initialSpecies[0].isSolvent)

        # Case 2: the solvent SMILES is not provided. In this case, it can identify the species as the
        # solvent by looking at the string name.

        # Case 2-1: Since 'n-octane and 'octane' are not equal, it raises Exception
        solventStructure = None
        self.assertRaises(Exception, self.database.checkSolventinInitialSpecies, rmg, solventStructure)

        # Case 2-2: The label 'n-ocatne' is corrected to 'octane', so it is identified as the solvent
        rmg.initialSpecies[0].label = 'octane'
        self.database.checkSolventinInitialSpecies(rmg, solventStructure)
        self.assertTrue(rmg.initialSpecies[0].isSolvent)

    def testSolventMolecule(self):
        " Test we can give a proper value for the solvent molecular structure when different solvent databases are given "

        # solventlibrary.entries['solvent_label'].item should be the instance of Species with the solvent's molecular structure
        # if the solvent database contains the solvent SMILES or adjacency list. If not, then item is None

        # Case 1: When the solventDatabase does not contain the solvent SMILES, the item attribute is None
        solventlibrary = SolventLibrary()
        solventlibrary.loadEntry(index=1, label='water', solvent=None)
        self.assertTrue(solventlibrary.entries['water'].item is None)

        # Case 2: When the solventDatabase contains the correct solvent SMILES, the item attribute is the instance of
        # Species with the correct solvent molecular structure
        solventlibrary.loadEntry(index=2, label='octane', solvent=None, molecule='CCCCCCCC')
        solventSpecies = Species().fromSMILES('C(CCCCC)CC')
        self.assertTrue(solventSpecies.isIsomorphic(solventlibrary.entries['octane'].item))

        # Case 3: When the solventDatabase contains the correct solvent adjacency list, the item attribute is the instance of
        # the species with the correct solvent molecular structure.
        # This will display the SMILES Parse Error message from the external function, but ignore it.
        solventlibrary.loadEntry(index=3, label='ethanol', solvent=None, molecule=
"""
1 C u0 p0 c0 {2,S} {4,S} {5,S} {6,S}
2 C u0 p0 c0 {1,S} {3,S} {7,S} {8,S}
3 O u0 p2 c0 {2,S} {9,S}
4 H u0 p0 c0 {1,S}
5 H u0 p0 c0 {1,S}
6 H u0 p0 c0 {1,S}
7 H u0 p0 c0 {2,S}
8 H u0 p0 c0 {2,S}
9 H u0 p0 c0 {3,S}
""")
        solventSpecies = Species().fromSMILES('CCO')
        self.assertTrue(solventSpecies.isIsomorphic(solventlibrary.entries['ethanol'].item))

        # Case 4: when the solventDatabase contains incorrect values for the molecule attribute, it raises Exception
        # This will display the SMILES Parse Error message from the external function, but ignore it.
        self.assertRaises(Exception, solventlibrary.loadEntry, index=4, label='benzene', solvent=None, molecule='ring')
class TestDiffusionLimited(unittest.TestCase):
    """
    Contains unit tests of the DiffusionLimited class.
    """
    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        octyl_pri = Species(
            label="",
            thermo=NASA(polynomials=[
                NASAPolynomial(coeffs=[
                    -0.772759, 0.093255, -5.84447e-05, 1.8557e-08,
                    -2.37127e-12, -3926.9, 37.6131
                ],
                               Tmin=(298, 'K'),
                               Tmax=(1390, 'K')),
                NASAPolynomial(coeffs=[
                    25.051, 0.036948, -1.25765e-05, 1.94628e-09, -1.12669e-13,
                    -13330.1, -102.557
                ],
                               Tmin=(1390, 'K'),
                               Tmax=(5000, 'K'))
            ],
                        Tmin=(298, 'K'),
                        Tmax=(5000, 'K'),
                        Cp0=(33.2579, 'J/(mol*K)'),
                        CpInf=(577.856, 'J/(mol*K)'),
                        comment="""Thermo library: JetSurF0.2"""),
            molecule=[Molecule(SMILES="[CH2]CCCCCCC")])
        octyl_sec = Species(
            label="",
            thermo=NASA(polynomials=[
                NASAPolynomial(coeffs=[
                    -0.304233, 0.0880077, -4.90743e-05, 1.21858e-08,
                    -8.87773e-13, -5237.93, 36.6583
                ],
                               Tmin=(298, 'K'),
                               Tmax=(1383, 'K')),
                NASAPolynomial(coeffs=[
                    24.9044, 0.0366394, -1.2385e-05, 1.90835e-09, -1.10161e-13,
                    -14713.5, -101.345
                ],
                               Tmin=(1383, 'K'),
                               Tmax=(5000, 'K'))
            ],
                        Tmin=(298, 'K'),
                        Tmax=(5000, 'K'),
                        Cp0=(33.2579, 'J/(mol*K)'),
                        CpInf=(577.856, 'J/(mol*K)'),
                        comment="""Thermo library: JetSurF0.2"""),
            molecule=[Molecule(SMILES="CC[CH]CCCCC")])
        ethane = Species(label="",
                         thermo=ThermoData(
                             Tdata=([300, 400, 500, 600, 800, 1000,
                                     1500], 'K'),
                             Cpdata=([
                                 10.294, 12.643, 14.933, 16.932, 20.033,
                                 22.438, 26.281
                             ], 'cal/(mol*K)'),
                             H298=(12.549, 'kcal/mol'),
                             S298=(52.379, 'cal/(mol*K)'),
                             Cp0=(33.2579, 'J/(mol*K)'),
                             CpInf=(133.032, 'J/(mol*K)'),
                             comment="""Thermo library: CH"""),
                         molecule=[Molecule(SMILES="C=C")])
        decyl = Species(label="",
                        thermo=NASA(polynomials=[
                            NASAPolynomial(coeffs=[
                                -1.31358, 0.117973, -7.51843e-05, 2.43331e-08,
                                -3.17523e-12, -9689.68, 43.501
                            ],
                                           Tmin=(298, 'K'),
                                           Tmax=(1390, 'K')),
                            NASAPolynomial(coeffs=[
                                31.5697, 0.0455818, -1.54995e-05, 2.39711e-09,
                                -1.3871e-13, -21573.8, -134.709
                            ],
                                           Tmin=(1390, 'K'),
                                           Tmax=(5000, 'K'))
                        ],
                                    Tmin=(298, 'K'),
                                    Tmax=(5000, 'K'),
                                    Cp0=(33.2579, 'J/(mol*K)'),
                                    CpInf=(719.202, 'J/(mol*K)'),
                                    comment="""Thermo library: JetSurF0.2"""),
                        molecule=[Molecule(SMILES="[CH2]CCCCCCCCC")])
        self.database = SolvationDatabase()
        self.database.load(
            os.path.join(settings['database.directory'], 'solvation'))
        self.solvent = 'octane'
        diffusionLimiter.enable(self.database.getSolventData(self.solvent),
                                self.database)
        self.T = 298
        self.uni_reaction = Reaction(reactants=[octyl_pri],
                                     products=[octyl_sec])
        self.uni_reaction.kinetics = Arrhenius(A=(2.0, '1/s'),
                                               n=0,
                                               Ea=(0, 'kJ/mol'))
        self.bi_uni_reaction = Reaction(reactants=[octyl_pri, ethane],
                                        products=[decyl])
        self.bi_uni_reaction.kinetics = Arrhenius(A=(1.0E-22,
                                                     'cm^3/molecule/s'),
                                                  n=0,
                                                  Ea=(0, 'kJ/mol'))
        self.intrinsic_rates = {
            self.uni_reaction:
            self.uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.bi_uni_reaction:
            self.bi_uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
        }

    def tearDown(self):
        diffusionLimiter.disable()

    def testGetEffectiveRateUnimolecular(self):
        """
        Tests that the effective rate is the same as the intrinsic rate for
        unimiolecular reactions.
        """
        effective_rate = diffusionLimiter.getEffectiveRate(
            self.uni_reaction, self.T)
        self.assertEqual(effective_rate,
                         self.intrinsic_rates[self.uni_reaction])

    def testGetEffectiveRate2to1(self):
        """
        Tests that the effective rate is limited in the forward direction for
        a 2 -> 1 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(
            self.bi_uni_reaction, self.T)
        self.assertTrue(
            effective_rate < self.intrinsic_rates[self.bi_uni_reaction])
        self.assertTrue(
            effective_rate >= 0.2 * self.intrinsic_rates[self.bi_uni_reaction])
class TestDiffusionLimited(unittest.TestCase):
    """
    Contains unit tests of the DiffusionLimited class.
    """

    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        octyl_pri = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-0.772759,0.093255,-5.84447e-05,1.8557e-08,-2.37127e-12,-3926.9,37.6131], Tmin=(298,'K'), Tmax=(1390,'K')),
            NASAPolynomial(coeffs=[25.051,0.036948,-1.25765e-05,1.94628e-09,-1.12669e-13,-13330.1,-102.557], Tmin=(1390,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(577.856,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="[CH2]CCCCCCC")])
        octyl_sec = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-0.304233,0.0880077,-4.90743e-05,1.21858e-08,-8.87773e-13,-5237.93,36.6583], Tmin=(298,'K'), Tmax=(1383,'K')),
            NASAPolynomial(coeffs=[24.9044,0.0366394,-1.2385e-05,1.90835e-09,-1.10161e-13,-14713.5,-101.345], Tmin=(1383,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(577.856,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="CC[CH]CCCCC")])
        ethane = Species(label="", thermo=ThermoData(
            Tdata=([300,400,500,600,800,1000,1500],'K'), Cpdata=([10.294,12.643,14.933,16.932,20.033,22.438,26.281],'cal/(mol*K)'), H298=(12.549,'kcal/mol'), S298=(52.379,'cal/(mol*K)'),
            Cp0=(33.2579,'J/(mol*K)'), CpInf=(133.032,'J/(mol*K)'), comment="""Thermo library: CH"""),
            molecule=[Molecule(SMILES="C=C")])
        decyl = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-1.31358,0.117973,-7.51843e-05,2.43331e-08,-3.17523e-12,-9689.68,43.501], Tmin=(298,'K'), Tmax=(1390,'K')),
            NASAPolynomial(coeffs=[31.5697,0.0455818,-1.54995e-05,2.39711e-09,-1.3871e-13,-21573.8,-134.709], Tmin=(1390,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(719.202,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="[CH2]CCCCCCCCC")])
        acetone = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs = [3.75568, 0.0264934, -6.55661e-05, 1.94971e-07, -1.82059e-10, -27905.3, 9.0162], Tmin = (10, 'K'), Tmax = (422.477, 'K')),
            NASAPolynomial(coeffs = [0.701289, 0.0344988, -1.9736e-05, 5.48052e-09, -5.92612e-13, -27460.6, 23.329],Tmin = (422.477, 'K'),Tmax = (3000, 'K'))
            ],
            Tmin = (10, 'K'), Tmax = (3000, 'K'), E0 = (-232.025, 'kJ/mol'), Cp0 = (33.2579, 'J/(mol*K)'), CpInf = (232.805, 'J/(mol*K)')),
            molecule=[Molecule(SMILES="CC(=O)C")])
        peracetic_acid = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs = [3.81786, 0.016419, 3.32204e-05, -8.98403e-08, 6.63474e-11, -42057.8, 9.65245], Tmin = (10, 'K'), Tmax = (354.579, 'K')),
            NASAPolynomial(coeffs = [2.75993, 0.0283534, -1.72659e-05, 5.08158e-09, -5.77773e-13, -41982.8, 13.6595], Tmin = (354.579, 'K'), Tmax = (3000, 'K'))
            ],
            Tmin = (10, 'K'), Tmax = (3000, 'K'), E0 = (-349.698, 'kJ/mol'),Cp0 = (33.2579, 'J/(mol*K)'), CpInf = (199.547, 'J/(mol*K)')),
            molecule=[Molecule(SMILES="CC(=O)OO")])
        acetic_acid = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs = [3.97665, 0.00159915, 8.5542e-05, -1.76486e-07, 1.20201e-10, -53911.5, 8.99309], Tmin = (10, 'K'), Tmax = (375.616, 'K')),
            NASAPolynomial(coeffs = [1.57088, 0.0272146, -1.67357e-05, 5.01453e-09, -5.82273e-13, -53730.7, 18.2442], Tmin = (375.616, 'K'), Tmax = (3000, 'K'))
            ],
            Tmin = (10, 'K'), Tmax = (3000, 'K'), E0 = (-448.245, 'kJ/mol'), Cp0 = (33.2579, 'J/(mol*K)'), CpInf = (182.918, 'J/(mol*K)')),
            molecule=[Molecule(SMILES="CC(=O)O")])
        criegee = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs = [3.23876, 0.0679583, -3.35611e-05, 7.91519e-10, 3.13038e-12, -77986, 13.6438], Tmin = (10, 'K'), Tmax = (1053.46, 'K')),
            NASAPolynomial(coeffs = [9.84525, 0.0536795, -2.86165e-05, 7.39945e-09, -7.48482e-13, -79977.6, -21.4187], Tmin = (1053.46, 'K'), Tmax = (3000, 'K'))
            ],
            Tmin = (10, 'K'), Tmax = (3000, 'K'), E0 = (-648.47, 'kJ/mol'),Cp0 = (33.2579, 'J/(mol*K)'), CpInf = (457.296, 'J/(mol*K)')),
            molecule=[Molecule(SMILES="CC(=O)OOC(C)(O)C")])
        self.database = SolvationDatabase()
        self.database.load(os.path.join(settings['database.directory'], 'solvation'))
        self.solvent = 'octane'
        diffusionLimiter.enable(self.database.getSolventData(self.solvent), self.database)
        self.T = 298
        self.uni_reaction = Reaction(reactants=[octyl_pri], products=[octyl_sec])
        self.uni_reaction.kinetics = Arrhenius(A=(2.0, '1/s'), n=0, Ea=(0,'kJ/mol'))
        self.bi_uni_reaction = Reaction(reactants=[octyl_pri, ethane], products=[decyl])
        self.bi_uni_reaction.kinetics = Arrhenius(A=(1.0E-22, 'cm^3/molecule/s'), n=0, Ea=(0,'kJ/mol'))
        self.tri_bi_reaction = Reaction(reactants=[acetone, peracetic_acid, acetic_acid],
                                        products=[criegee, acetic_acid])
        self.tri_bi_reaction.kinetics = Arrhenius(A=(1.07543e-11, 'cm^6/(mol^2*s)'), n=5.47295, Ea=(-38.5379, 'kJ/mol'))
        self.intrinsic_rates = {
            self.uni_reaction: self.uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.bi_uni_reaction: self.bi_uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.tri_bi_reaction: self.tri_bi_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            }

    def tearDown(self):
        diffusionLimiter.disable()

    def testGetEffectiveRateUnimolecular(self):
        """
        Tests that the effective rate is the same as the intrinsic rate for
        unimiolecular reactions.
        """
        effective_rate = diffusionLimiter.getEffectiveRate(self.uni_reaction, self.T)
        self.assertEqual(effective_rate, self.intrinsic_rates[self.uni_reaction])

    def testGetEffectiveRate2to1(self):
        """
        Tests that the effective rate is limited in the forward direction for
        a 2 -> 1 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(self.bi_uni_reaction, self.T)
        self.assertTrue(effective_rate < self.intrinsic_rates[self.bi_uni_reaction])
        self.assertTrue(effective_rate >= 0.2 * self.intrinsic_rates[self.bi_uni_reaction])

    def testGetEffectiveRate3to2(self):
        """
        Tests that the effective rate is limited for a 3 -> 2 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(self.tri_bi_reaction, self.T)
        self.assertTrue(effective_rate < self.intrinsic_rates[self.tri_bi_reaction])
        self.assertTrue(effective_rate >= 0.2 * self.intrinsic_rates[self.tri_bi_reaction])
Example #8
0
class TestDiffusionLimited(unittest.TestCase):
    """
    Contains unit tests of the DiffusionLimited class.
    """

    def setUp(self):
        """
        A function run before each unit test in this class.
        """
        octyl_pri = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-0.772759,0.093255,-5.84447e-05,1.8557e-08,-2.37127e-12,-3926.9,37.6131], Tmin=(298,'K'), Tmax=(1390,'K')),
            NASAPolynomial(coeffs=[25.051,0.036948,-1.25765e-05,1.94628e-09,-1.12669e-13,-13330.1,-102.557], Tmin=(1390,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(577.856,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="[CH2]CCCCCCC")])
        octyl_sec = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-0.304233,0.0880077,-4.90743e-05,1.21858e-08,-8.87773e-13,-5237.93,36.6583], Tmin=(298,'K'), Tmax=(1383,'K')),
            NASAPolynomial(coeffs=[24.9044,0.0366394,-1.2385e-05,1.90835e-09,-1.10161e-13,-14713.5,-101.345], Tmin=(1383,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(577.856,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="CC[CH]CCCCC")])
        ethane = Species(label="", thermo=ThermoData(
            Tdata=([300,400,500,600,800,1000,1500],'K'), Cpdata=([10.294,12.643,14.933,16.932,20.033,22.438,26.281],'cal/(mol*K)'), H298=(12.549,'kcal/mol'), S298=(52.379,'cal/(mol*K)'),
            Cp0=(33.2579,'J/(mol*K)'), CpInf=(133.032,'J/(mol*K)'), comment="""Thermo library: CH"""),
            molecule=[Molecule(SMILES="C=C")])
        decyl = Species(label="", thermo=NASA(polynomials=[
            NASAPolynomial(coeffs=[-1.31358,0.117973,-7.51843e-05,2.43331e-08,-3.17523e-12,-9689.68,43.501], Tmin=(298,'K'), Tmax=(1390,'K')),
            NASAPolynomial(coeffs=[31.5697,0.0455818,-1.54995e-05,2.39711e-09,-1.3871e-13,-21573.8,-134.709], Tmin=(1390,'K'), Tmax=(5000,'K'))
            ],
            Tmin=(298,'K'), Tmax=(5000,'K'), Cp0=(33.2579,'J/(mol*K)'), CpInf=(719.202,'J/(mol*K)'),
            comment="""Thermo library: JetSurF0.2"""), molecule=[Molecule(SMILES="[CH2]CCCCCCCCC")])
        self.database = SolvationDatabase()
        self.database.load(os.path.join(settings['database.directory'], 'solvation'))
        self.solvent = 'octane'
        diffusionLimiter.enable(self.database.getSolventData(self.solvent), self.database)
        self.T = 298
        self.uni_reaction = Reaction(reactants=[octyl_pri], products=[octyl_sec])
        self.uni_reaction.kinetics = Arrhenius(A=(2.0, '1/s'), n=0, Ea=(0,'kJ/mol'))
        self.bi_uni_reaction = Reaction(reactants=[octyl_pri, ethane], products=[decyl])
        self.bi_uni_reaction.kinetics = Arrhenius(A=(1.0E-22, 'cm^3/molecule/s'), n=0, Ea=(0,'kJ/mol'))
        self.intrinsic_rates = {
            self.uni_reaction: self.uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            self.bi_uni_reaction: self.bi_uni_reaction.kinetics.getRateCoefficient(self.T, P=100e5),
            }

    def tearDown(self):
        diffusionLimiter.disable()

    def testGetEffectiveRateUnimolecular(self):
        """
        Tests that the effective rate is the same as the intrinsic rate for
        unimiolecular reactions.
        """
        effective_rate = diffusionLimiter.getEffectiveRate(self.uni_reaction, self.T)
        self.assertEqual(effective_rate, self.intrinsic_rates[self.uni_reaction])

    def testGetEffectiveRate2to1(self):
        """
        Tests that the effective rate is limited in the forward direction for
        a 2 -> 1 reaction
        """
        effective_rate = diffusionLimiter.getEffectiveRate(self.bi_uni_reaction, self.T)
        self.assertTrue(effective_rate < self.intrinsic_rates[self.bi_uni_reaction])
        self.assertTrue(effective_rate >= 0.2 * self.intrinsic_rates[self.bi_uni_reaction])
Example #9
0
class TestSoluteDatabase(TestCase):
    
    def setUp(self):
        self.database = SolvationDatabase()
        self.database.load(os.path.join(settings['database.directory'], 'solvation'))
    
    def runTest(self):
        pass
    
    def testSoluteLibrary(self):
        "Test we can obtain solute parameters from a library"
        species = Species(molecule=[Molecule(SMILES='COC=O')]) #methyl formate - we know this is in the solute library
        
        libraryData = self.database.getSoluteDataFromLibrary(species, self.database.libraries['solute'])
        self.assertEqual(len(libraryData), 3)
        
        soluteData = self.database.getSoluteData(species)
        self.assertTrue(isinstance(soluteData, SoluteData))
        
        S = soluteData.S
        self.assertEqual(S, 0.68)
        self.assertTrue(soluteData.V is not None)
     
    def testMcGowan(self):
        "Test we can calculate and set the McGowan volume for species containing H,C,O,N or S"
        self.testCases = [
                          ['CCCCCCCC', 1.2358], #n-octane, in library
                          ['C(CO)O', 0.5078], #ethylene glycol
                          ['CC#N', 0.4042], #acetonitrile
                          ['CCS', 0.5539] #ethanethiol
                           ]
        
        for smiles, volume in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            soluteData.setMcGowanVolume(species) # even if it was found in library, recalculate
            self.assertTrue(soluteData.V is not None) # so if it wasn't found in library, we should have calculated it
            self.assertAlmostEqual(soluteData.V, volume) # the volume is what we expect given the atoms and bonds 
            
    
    def testDiffusivity(self):
        "Test that for a given solvent viscosity and temperature we can calculate a solute's diffusivity"
        species = Species(molecule=[Molecule(SMILES='COC=O')])
        soluteData = self.database.getSoluteData(species)
        T = 298
        solventViscosity = 0.001
        D = soluteData.getStokesDiffusivity(T, solventViscosity)
        self.assertAlmostEqual((D*1E12), 0.00000979)
        
    def testSolventLibrary(self):
        "Test we can obtain solvent parameters from a library"
        solventData = self.database.getSolventData('water')
        self.assertTrue(solventData is not None)
        self.assertEqual(solventData.s_h, 2.836)
        self.assertRaises(DatabaseError, self.database.getSolventData, 'orange_juice')
        
    def testViscosity(self):
        "Test we can calculate the solvent viscosity given a temperature and its A-E correlation parameters"
        solventData = self.database.getSolventData('water')  
        self.assertAlmostEqual(solventData.getSolventViscosity(298), 0.0009155)

    def testSoluteGeneration(self):
        "Test we can estimate Abraham solute parameters correctly using group contributions"
        
        self.testCases = [
        # from RMG-Java test runs by RWest (mostly in agreement with Jalan et. al. supplementary data)
        ['1,2-ethanediol', 'C(CO)O', 0.823, 0.685, 0.327, 2.572, 0.693, None],
        # a nitrogen case
        #['acetonitrile', 'CC#N', 0.9, 0.33, 0.237, 1.739, 0.04, None],
        # a sulfur case
        #['ethanethiol', 'CCS', 0.35, 0.24, 0.392, 2.173, 0, None]
        ]
        
        for name, smiles, S, B, E, L, A, V in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteDataFromGroups(Species(molecule=[species.molecule[0]]))
            self.assertAlmostEqual(soluteData.S, S, places=2)
            self.assertAlmostEqual(soluteData.B, B, places=2)
            self.assertAlmostEqual(soluteData.E, E, places=2)
            self.assertAlmostEqual(soluteData.L, L, places=2)
            self.assertAlmostEqual(soluteData.A, A, places=2)

    def testCorrectionGeneration(self):
        "Test we can estimate solvation thermochemistry."
        self.testCases = [
        # solventName, soluteName, soluteSMILES, Hsolv, Gsolv
        ['water', 'acetic acid', 'C(C)(=O)O', -56500, -6700*4.184],
        ['water', 'naphthalene', 'C1=CC=CC2=CC=CC=C12', -42800, -2390*4.184],
        ['1-octanol', 'octane', 'CCCCCCCC', -40080, -4180*4.184],
        ['1-octanol', 'tetrahydrofuran', 'C1CCOC1', -28320, -3930*4.184],
        ['benzene', 'toluene', 'C1(=CC=CC=C1)C', -37660, -5320*4.184],
        ['benzene', '1,4-dioxane', 'C1COCCO1', -39030, -5210*4.184]
        ]
        
        for solventName, soluteName, smiles, H, G in self.testCases:
            species = Species(molecule=[Molecule(SMILES=smiles)])
            soluteData = self.database.getSoluteData(species)
            solventData = self.database.getSolventData(solventName)
            solvationCorrection = self.database.getSolvationCorrection(soluteData, solventData)
            self.assertAlmostEqual(solvationCorrection.enthalpy / 10000., H / 10000., 0, msg="Solvation enthalpy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.enthalpy, H))  #0 decimal place, in 10kJ.
            self.assertAlmostEqual(solvationCorrection.gibbs / 10000., G / 10000., 0, msg="Solvation Gibbs free energy discrepancy ({2:.0f}!={3:.0f}) for {0} in {1}".format(soluteName, solventName, solvationCorrection.gibbs, G))