From 7f9aafde09b843d8bfa6a62f107c0df551f367bd Mon Sep 17 00:00:00 2001 From: Max Liu Date: Wed, 19 Jun 2019 16:38:01 -0400 Subject: [PATCH] Add parsing for extended element counts in Chemkin thermo entries Add unit tests for various element count syntaxes Fix incorrect index for element count in columns 74-78 (should start at column 73 using zero-indexing) --- rmgpy/chemkin.pyx | 17 ++++++++++- rmgpy/chemkinTest.py | 69 ++++++++++++++++++++++++++++++-------------- 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/rmgpy/chemkin.pyx b/rmgpy/chemkin.pyx index 4224a0b1e6..69f9d476fd 100644 --- a/rmgpy/chemkin.pyx +++ b/rmgpy/chemkin.pyx @@ -80,7 +80,7 @@ def readThermoEntry(entry, Tmin=0, Tint=0, Tmax=0): comment = lines[0][len(species):24].strip() formula = {} - for i in [24, 29, 34, 39, 74]: + for i in [24, 29, 34, 39, 73]: element,count = lines[0][i:i+2].strip(), lines[0][i+2:i+5].strip() if element: try: @@ -99,6 +99,21 @@ def readThermoEntry(entry, Tmin=0, Tint=0, Tmax=0): raise if count != 0: # Some people put garbage elements in, with zero count. Ignore these. Allow negative counts though (eg. negative one electron) formula[element] = count + + # Parsing for extended elemental composition syntax, adapted from Cantera ck2cti.py + if lines[0].rstrip().endswith('&'): + complines = [] + for i in range(len(lines)-1): + if lines[i].rstrip().endswith('&'): + complines.append(lines[i+1]) + else: + break + lines = [lines[0]] + lines[i+1:] + elements = ' '.join(line.rstrip('&\n') for line in complines).split() + formula = {} + for i in range(0, len(elements), 2): + formula[elements[i].capitalize()] = int(elements[i+1]) + phase = lines[0][44] if phase.upper() != 'G': logging.warning("Was expecting gas phase thermo data for {0}. Skipping thermo data.".format(species)) diff --git a/rmgpy/chemkinTest.py b/rmgpy/chemkinTest.py index 08bbedddb4..16ecdfdf39 100644 --- a/rmgpy/chemkinTest.py +++ b/rmgpy/chemkinTest.py @@ -427,7 +427,7 @@ def test_mark_duplicate_reactions(self): self.assertEqual(duplicate_flags, expected_flags) -class TestThermoWrite(unittest.TestCase): +class TestThermoReadWrite(unittest.TestCase): def setUp(self): """This method is run once before each test.""" @@ -449,20 +449,42 @@ def setUp(self): comment=comment, ) - def testWriteThermoBlock(self): - """Test that we can write a normal thermo block""" - species = Species(SMILES='CC') - species.thermo = self.nasa + # Chemkin entries for testing - note that the values are all the same + self.entry1 = """C2H6 H 6C 2 G 300.000 3000.000 650.73 1 +-3.07954000E-01 2.45269000E-02-1.24130000E-05 3.07724000E-09-3.01467000E-13 2 +-1.06930000E+04 2.26280000E+01 4.03055000E+00-2.14171000E-03 4.90611000E-05 3 +-5.99027000E-08 2.38945000E-11-1.12576000E+04 3.56130000E+00 4 +""" - expected = """C2H6 H 6C 2 G 300.000 3000.000 650.73 1 + self.entry2 = """CH3NO2X X 1H 3C 1O 2G 300.000 3000.000 650.73N 1 1 -3.07954000E-01 2.45269000E-02-1.24130000E-05 3.07724000E-09-3.01467000E-13 2 -1.06930000E+04 2.26280000E+01 4.03055000E+00-2.14171000E-03 4.90611000E-05 3 -5.99027000E-08 2.38945000E-11-1.12576000E+04 3.56130000E+00 4 """ + self.entry3 = """CH3NO2SX G 300.000 3000.000 650.73 1& +C 1 H 3 O 2 N 1 S 1 X 1 +-3.07954000E-01 2.45269000E-02-1.24130000E-05 3.07724000E-09-3.01467000E-13 2 +-1.06930000E+04 2.26280000E+01 4.03055000E+00-2.14171000E-03 4.90611000E-05 3 +-5.99027000E-08 2.38945000E-11-1.12576000E+04 3.56130000E+00 4 +""" + + def testWriteThermoBlock(self): + """Test that we can write a normal thermo block""" + species = Species(SMILES='CC') + species.thermo = self.nasa + result = writeThermoEntry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry1) + + def testReadThermoBlock(self): + """Test that we can read a normal thermo block""" + species, thermo, formula = readThermoEntry(self.entry1) + + self.assertEqual(species, 'C2H6') + self.assertEqual(formula, {'H': 6, 'C': 2}) + self.assertTrue(self.nasa.isIdenticalTo(thermo)) def testWriteThermoBlock5Elem(self): """Test that we can write a thermo block for a species with 5 elements""" @@ -478,15 +500,17 @@ def testWriteThermoBlock5Elem(self): """) species.thermo = self.nasa - expected = """CH3NO2X X 1H 3C 1O 2G 300.000 3000.000 650.73N 1 1 --3.07954000E-01 2.45269000E-02-1.24130000E-05 3.07724000E-09-3.01467000E-13 2 --1.06930000E+04 2.26280000E+01 4.03055000E+00-2.14171000E-03 4.90611000E-05 3 --5.99027000E-08 2.38945000E-11-1.12576000E+04 3.56130000E+00 4 -""" - result = writeThermoEntry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry2) + + def testReadThermoBlock5Elem(self): + """Test that we can read a thermo block with 5 elements""" + species, thermo, formula = readThermoEntry(self.entry2) + + self.assertEqual(species, 'CH3NO2X') + self.assertEqual(formula, {'X': 1, 'C': 1, 'O': 2, 'H': 3, 'N': 1}) + self.assertTrue(self.nasa.isIdenticalTo(thermo)) def testWriteThermoBlock6Elem(self): """Test that we can write a thermo block for a species with 6 elements""" @@ -503,16 +527,17 @@ def testWriteThermoBlock6Elem(self): """) species.thermo = self.nasa - expected = """CH3NO2SX G 300.000 3000.000 650.73 1& -C 1 H 3 O 2 N 1 S 1 X 1 --3.07954000E-01 2.45269000E-02-1.24130000E-05 3.07724000E-09-3.01467000E-13 2 --1.06930000E+04 2.26280000E+01 4.03055000E+00-2.14171000E-03 4.90611000E-05 3 --5.99027000E-08 2.38945000E-11-1.12576000E+04 3.56130000E+00 4 -""" - result = writeThermoEntry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry3) + + def testReadThermoBlock6Elem(self): + """Test that we can read a thermo block with 6 elements""" + species, thermo, formula = readThermoEntry(self.entry3) + + self.assertEqual(species, 'CH3NO2SX') + self.assertEqual(formula, {'X': 1, 'C': 1, 'O': 2, 'H': 3, 'N': 1, 'S': 1}) + self.assertTrue(self.nasa.isIdenticalTo(thermo)) class TestReadReactionComments(unittest.TestCase):