From 44d755492668847b586bc562cd172fb63c0a9da1 Mon Sep 17 00:00:00 2001 From: Max Liu Date: Fri, 22 Nov 2019 15:04:23 -0500 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 | 71 ++++++++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 24 deletions(-) diff --git a/rmgpy/chemkin.pyx b/rmgpy/chemkin.pyx index c3d125bcc2..ebc0768c47 100644 --- a/rmgpy/chemkin.pyx +++ b/rmgpy/chemkin.pyx @@ -80,7 +80,7 @@ def read_thermo_entry(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: @@ -103,6 +103,21 @@ def read_thermo_entry(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 f27d082a32..59614fd8f2 100644 --- a/rmgpy/chemkinTest.py +++ b/rmgpy/chemkinTest.py @@ -429,7 +429,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.""" @@ -451,20 +451,43 @@ def setUp(self): comment=comment, ) - def test_write_thermo_block(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 C 2H 6 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 +""" + + self.entry2 = """CH3NO2X G 300.000 3000.000 650.73 1& +C 1 H 3 N 1 O 2 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 +""" - expected = """C2H6 C 2H 6 G 300.000 3000.000 650.73 1 + self.entry3 = """CH3NO2SX G 300.000 3000.000 650.73 1& +C 1 H 3 N 1 O 2 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 test_write_thermo_block(self): + """Test that we can write a normal thermo block""" + species = Species(smiles='CC') + species.thermo = self.nasa + result = write_thermo_entry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry1) + + def test_read_thermo_block(self): + """Test that we can read a normal thermo block""" + species, thermo, formula = read_thermo_entry(self.entry1) + + self.assertEqual(species, 'C2H6') + self.assertEqual(formula, {'H': 6, 'C': 2}) + self.assertTrue(self.nasa.is_identical_to(thermo)) def test_write_thermo_block_5_elem(self): """Test that we can write a thermo block for a species with 5 elements""" @@ -480,16 +503,17 @@ def test_write_thermo_block_5_elem(self): """) species.thermo = self.nasa - expected = """CH3NO2X G 300.000 3000.000 650.73 1& -C 1 H 3 N 1 O 2 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 = write_thermo_entry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry2) + + def test_read_thermo_block_5_elem(self): + """Test that we can read a thermo block with 5 elements""" + species, thermo, formula = read_thermo_entry(self.entry2) + + self.assertEqual(species, 'CH3NO2X') + self.assertEqual(formula, {'X': 1, 'C': 1, 'O': 2, 'H': 3, 'N': 1}) + self.assertTrue(self.nasa.is_identical_to(thermo)) def test_write_thermo_block_6_elem(self): """Test that we can write a thermo block for a species with 6 elements""" @@ -506,16 +530,17 @@ def test_write_thermo_block_6_elem(self): """) species.thermo = self.nasa - expected = """CH3NO2SX G 300.000 3000.000 650.73 1& -C 1 H 3 N 1 O 2 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 = write_thermo_entry(species, verbose=False) - self.assertEqual(expected, result) + self.assertEqual(result, self.entry3) + + def test_read_thermo_block_6_elem(self): + """Test that we can read a thermo block with 6 elements""" + species, thermo, formula = read_thermo_entry(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.is_identical_to(thermo)) class TestReadReactionComments(unittest.TestCase):