From d60c06127b2955fd2d7f6bb37d1c6b41d4da29df Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Mon, 27 Feb 2012 18:13:53 +0000 Subject: [PATCH] Added tests for some methods of the Python Solution class --- test/SConscript | 17 +++-- test/python/runTests.py | 2 +- test/python/testSolution.py | 141 ++++++++++++++++++++++++++++++++++++ test/python/testThermo.py | 9 --- 4 files changed, 154 insertions(+), 15 deletions(-) create mode 100644 test/python/testSolution.py delete mode 100644 test/python/testThermo.py diff --git a/test/SConscript b/test/SConscript index 520c5c88b..cefa97140 100644 --- a/test/SConscript +++ b/test/SConscript @@ -23,8 +23,12 @@ def testRunner(target, source, env): def scriptRunner(target, source, env): """Scons Action to run a test script using the specified interpreter""" interpreter = env['test_interpreter'] - code = subprocess.call([interpreter, str(source[0])], - env=env['ENV']) + workDir = Dir('#test/work').abspath + if not os.path.isdir(workDir): + os.mkdir(workDir) + code = subprocess.call([interpreter, source[0].abspath], + env=env['ENV'], + cwd=workDir) if not code: open(target[0].path, 'w').write(time.asctime()+'\n') return code @@ -45,7 +49,7 @@ def addTestProgram(subdir, progName): [], [Delete(passedFile.abspath)])) -def addTestScript(subdir, script, interpreter): +def addTestScript(subdir, script, interpreter, dependencies): """ Create targets for running and resetting a test script. """ @@ -53,12 +57,15 @@ def addTestScript(subdir, script, interpreter): testenv['test_interpreter'] = interpreter passedFile = File(pjoin(subdir, '%s.passed' % (script))) run_program = testenv.Command(passedFile, pjoin(subdir, script), scriptRunner) + for dep in dependencies: + testenv.Depends(run_program, File(pjoin(subdir, dep))) Alias('newtest', run_program) if os.path.exists(passedFile.abspath): Alias('newtest-reset', testenv.Command('reset-%s%s' % (subdir, script), [], [Delete(passedFile.abspath)])) - # Instantiate tests addTestProgram('thermo', 'nasapoly') -addTestScript('python', 'runTests.py', interpreter=sys.executable) +addTestScript('python', 'runTests.py', + interpreter=sys.executable, + dependencies=['testSolution.py']) diff --git a/test/python/runTests.py b/test/python/runTests.py index b0965eff8..5da3e8f81 100644 --- a/test/python/runTests.py +++ b/test/python/runTests.py @@ -14,5 +14,5 @@ if __name__ == '__main__': loader = unittest.TestLoader() runner = unittest.TextTestRunner(verbosity=2) - suite = loader.loadTestsFromName('testThermo') + suite = loader.loadTestsFromName('testSolution') runner.run(suite) diff --git a/test/python/testSolution.py b/test/python/testSolution.py new file mode 100644 index 000000000..c8ebfc022 --- /dev/null +++ b/test/python/testSolution.py @@ -0,0 +1,141 @@ +import unittest + +import numpy as np + +import Cantera as ct + +class ImportTest(unittest.TestCase): + """ + Test the various ways of creating a Solution object + """ + def check(self, gas, name, T, P, nSpec, nElem): + self.assertEqual(gas.name(), name) + self.assertAlmostEqual(gas.temperature(), T) + self.assertAlmostEqual(gas.pressure(), P) + self.assertEqual(gas.nSpecies(), nSpec) + self.assertEqual(gas.nElements(), nElem) + + def test_importPhase_cti(self): + gas1 = ct.importPhase('../data/air-no-reactions.cti', 'air') + self.check(gas1, 'air', 300, 101325, 8, 3) + + gas2 = ct.importPhase('../data/air-no-reactions.cti', 'notair') + self.check(gas2, 'notair', 900, 5*101325, 7, 2) + + def test_importPhase_cti2(self): + # This should import the first phase, i.e. 'air' + gas = ct.importPhase('../data/air-no-reactions.cti') + self.check(gas, 'air', 300, 101325, 8, 3) + + def test_importPhase_xml(self): + gas1 = ct.importPhase('../data/air-no-reactions.xml', 'air') + self.check(gas1, 'air', 300, 101325, 8, 3) + + gas2 = ct.importPhase('../data/air-no-reactions.xml', 'notair') + self.check(gas2, 'notair', 900, 5*101325, 7, 2) + + def test_import_GRI30(self): + gas = ct.GRI30() + self.check(gas, 'gri30', 300, 101325, 53, 5) + + +class BasicTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.gas = ct.importPhase('../data/air-no-reactions.xml', 'air') + + def test_counts(self): + self.assertEqual(self.gas.nElements(), 3) + self.assertEqual(self.gas.nSpecies(), 8) + self.assertEqual(self.gas.nPhases(), 1) + + def test_elements(self): + self.assertEqual(self.gas.nElements(), len(self.gas.elementNames())) + for i,name in enumerate(self.gas.elementNames()): + self.assertEqual(self.gas.elementName(i), name) + self.assertEqual(self.gas.elementIndex(name), i) + + def test_species(self): + self.assertEqual(self.gas.nSpecies(), len(self.gas.speciesNames())) + for i,name in enumerate(self.gas.speciesNames()): + self.assertEqual(self.gas.speciesName(i), name) + self.assertEqual(self.gas.speciesIndex(name), i) + + def test_nAtoms(self): + data = [(1, 'O', 'O'), (2, 'O', 'O2'), (1, 'N', 'NO'), + (1, 'O', 'NO'), (1, 'N', 'NO2'), (2, 'O', 'NO2'), + (0, 'O', 'N2'), (0, 'Ar', 'N2O')] + for (n, elem, species) in data: + self.assertEqual(self.gas.nAtoms(species, elem), n) + mElem = self.gas.elementIndex(elem) + kSpec = self.gas.speciesIndex(species) + self.assertEqual(self.gas.nAtoms(kSpec, mElem), n) + + def test_weights(self): + atomic_weights = self.gas.atomicWeights() + molecular_weights = self.gas.molecularWeights() + self.assertEqual(self.gas.nElements(), len(atomic_weights)) + self.assertEqual(self.gas.nSpecies(), len(molecular_weights)) + + for i,mw in enumerate(molecular_weights): + test_weight = 0.0 + for j,aw in enumerate(atomic_weights): + test_weight += aw * self.gas.nAtoms(i,j) + self.assertAlmostEqual(test_weight, mw) + + +class ThermoTest(unittest.TestCase): + """ + Test the thermodynamic property accessor functions of a Solution + """ + @classmethod + def setUpClass(cls): + cls.gas = ct.importPhase('../data/air-no-reactions.xml', 'air') + cls.T0 = cls.gas.temperature() + cls.P0 = cls.gas.pressure() + cls.X0 = cls.gas.moleFractions() + + def setUp(self): + self.gas.set(T=self.T0, P=self.P0, X=self.X0) + + def test_volume(self): + # This class should follow the ideal gas law + g = self.gas + self.assertAlmostEqual( + g.pressure(), + g.molarDensity() * ct.GasConstant * g.temperature()) + + self.assertAlmostEqual( + g.pressure() / g.density(), + ct.GasConstant / g.meanMolecularWeight() * g.temperature()) + + self.assertAlmostEqual(g.density(), 1.0 / g.volume_mass()) + + def test_energy(self): + g = self.gas + mmw = g.meanMolecularWeight() + self.assertAlmostEqual(g.enthalpy_mass(), g.enthalpy_mole() / mmw) + self.assertAlmostEqual(g.intEnergy_mass(), g.intEnergy_mole() / mmw) + self.assertAlmostEqual(g.gibbs_mass(), g.gibbs_mole() / mmw) + self.assertAlmostEqual(g.entropy_mass(), g.entropy_mole() / mmw) + + self.assertAlmostEqual(g.cv_mass(), g.cv_mole() / mmw) + self.assertAlmostEqual(g.cp_mass(), g.cp_mole() / mmw) + self.assertAlmostEqual(g.cv_mole() + ct.GasConstant, g.cp_mole()) + + def test_nondimensional(self): + g = self.gas + T = g.temperature() + R = ct.GasConstant + X = g.moleFractions() + + self.assertAlmostEqual(np.dot(g.cp_R(), X), + g.cp_mole() / R) + self.assertAlmostEqual(np.dot(g.enthalpies_RT(), X), + g.enthalpy_mole() / (R*T)) + + Smix_R = - np.dot(X, np.log(X+1e-20)) + self.assertAlmostEqual(np.dot(g.entropies_R(), X) + Smix_R, + g.entropy_mole() / R) + self.assertAlmostEqual(np.dot(g.gibbs_RT(), X) - Smix_R, + g.gibbs_mole() / (R*T)) diff --git a/test/python/testThermo.py b/test/python/testThermo.py deleted file mode 100644 index 6bfa06891..000000000 --- a/test/python/testThermo.py +++ /dev/null @@ -1,9 +0,0 @@ -import unittest - -import Cantera as ct - -class ImportTest(unittest.TestCase): - def testCtiImport(self): - gas = ct.importPhase('test/data/air-no-reactions.cti', 'air') - - self.assertAlmostEqual(gas.temperature(), 300)