From 24c509f53954ec5da2cd29add32355c1ec605751 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Fri, 7 Nov 2014 02:15:03 +0000 Subject: [PATCH] [Kinetics] Fix some cases where duplicate reactions were not detected Also add several tests which check that the various kinds of duplicate reactions are being identified as errors or allowed as intended. --- .../cython/cantera/test/test_kinetics.py | 40 +++++++++++++ src/kinetics/importKinetics.cpp | 6 +- test/data/duplicate-reactions.cti | 59 +++++++++++++++++++ 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 test/data/duplicate-reactions.cti diff --git a/interfaces/cython/cantera/test/test_kinetics.py b/interfaces/cython/cantera/test/test_kinetics.py index 0113dfe85..353e66111 100644 --- a/interfaces/cython/cantera/test/test_kinetics.py +++ b/interfaces/cython/cantera/test/test_kinetics.py @@ -462,3 +462,43 @@ class TestSofcKinetics(utilities.CanteraTest): anode_bulk.electric_potential]) self.compare(data, '../data/sofc-test.csv') + + +class TestDuplicateReactions(utilities.CanteraTest): + infile = 'duplicate-reactions.cti' + + def check(self, name): + with self.assertRaises(Exception) as cm: + ct.Solution(self.infile, name) + self.assertIn('duplicate reaction', str(cm.exception)) + + def test_forward_multiple(self): + self.check('A') + + def test_opposite_direction1(self): + self.check('B') + + def test_opposite_direction2(self): + self.check('C') + + def test_opposite_direction3(self): + self.check('D') + + def test_opposite_direction4(self): + gas = ct.Solution(self.infile, 'E') + self.assertEqual(gas.n_reactions, 2) + + def test_common_efficiencies(self): + self.check('F') + + def test_disjoint_efficiencies(self): + gas = ct.Solution(self.infile, 'G') + self.assertEqual(gas.n_reactions, 2) + + def test_different_type(self): + gas = ct.Solution(self.infile, 'H') + self.assertEqual(gas.n_reactions, 2) + + def test_declared_duplicate(self): + gas = ct.Solution(self.infile, 'I') + self.assertEqual(gas.n_reactions, 2) diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index d37bd809a..46ba2c7cc 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -1027,15 +1027,13 @@ bool rxninfo::installReaction(int iRxn, const XML_Node& rxnNode, Kinetics& kin, } for (size_t nn = 0; nn < rdata.products.size(); nn++) { rdata.net_stoich[int(rdata.products[nn])+1] += rdata.pstoich[nn]; - participants += 1000000 * static_cast(rdata.products[nn]); + participants += static_cast(rdata.products[nn]); } vector& related = m_participants[participants]; for (size_t mm = 0; mm < related.size(); mm++) { ReactionData& other = *m_rdata[related[mm]]; - if (rdata.reactants.size() != other.reactants.size()) { - continue; // different numbers of reactants - } else if (rdata.reactionType != other.reactionType) { + if (rdata.reactionType != other.reactionType) { continue; // different reaction types } else if (rdata.duplicate && other.duplicate) { continue; // marked duplicates diff --git a/test/data/duplicate-reactions.cti b/test/data/duplicate-reactions.cti new file mode 100644 index 000000000..0cb914912 --- /dev/null +++ b/test/data/duplicate-reactions.cti @@ -0,0 +1,59 @@ +units(length='cm', time='s', quantity='mol', act_energy='cal/mol') + +def make_gas(name, reactions): + ideal_gas(name=name, + elements=" O H Ar ", + species="""h2o2: H2 H O O2 OH H2O HO2 H2O2 AR """, + reactions=reactions, + transport="None") + +make_gas('A', 'A-*') +make_gas('B', 'B-*') +make_gas('C', 'C-*') +make_gas('D', 'D-*') +make_gas('E', 'E-*') +make_gas('F', 'F-*') +make_gas('G', 'G-*') +make_gas('H', 'H-*') +make_gas('I', 'I-*') + +kf = [1e10, 0, 100] + +# Forward multiple (not allowed) +reaction('O + H2 <=> H + OH', kf, id='A-1') +reaction('2 O + 2 H2 <=> 2 H + 2 OH', kf, id='A-2') + +# Opposite direction #1 (not allowed) +reaction('O + H2 <=> H + OH', kf, id='B-1') +reaction('H + OH <=> O + H2', kf, id='B-2') + +# Opposite direction #2 (not allowed) +reaction('H + O2 + AR <=> HO2 + AR', kf, id='C-1') +reaction('HO2 + AR <=> H + O2 + AR', kf, id='C-2') + +# Opposite direction #3 (not allowed) +reaction('H + O2 + AR <=> HO2 + AR', kf, id='D-1') +reaction('HO2 + AR => H + O2 + AR', kf, id='D-2') + +# Opposite direction #4 (allowed) +reaction('H + O2 + AR => HO2 + AR', kf, id='E-1') +reaction('HO2 + AR => H + O2 + AR', kf, id='E-2') + +# Common efficiencies (not allowed) +falloff_reaction('2 OH (+ M) <=> H2O2 (+ M)', kf=kf, kf0=kf, + efficiencies='H2:2.0 H2O:6.0', id='F-1') +falloff_reaction('2 OH (+ M) <=> H2O2 (+ M)', kf=kf, kf0=kf, + efficiencies='AR:0.7 H2:2.0', id='F-2') + +# Disjoint efficiencies (allowed) +falloff_reaction('2 OH (+ H2O) <=> H2O2 (+ H2O)', kf=kf, kf0=kf, id='G-1') +falloff_reaction('2 OH (+ M) <=> H2O2 (+ M)', kf=kf, kf0=kf, + efficiencies='AR:0.7 H2:2.0 H2O:0.0', id='G-2') + +# Different reaction type (allowed) +reaction('O + H2 <=> H + OH', kf, id='H-1') +three_body_reaction('O + H2 + M <=> H + OH + M', kf, id='H-2') + +# Declared duplicate (allowed) +reaction('O + H2 <=> H + OH', kf, options='duplicate', id='I-1') +reaction('H + OH <=> O + H2', kf, options='duplicate', id='I-2')