Skip to content

Commit

Permalink
[UnitTests] Add unit tests for InterfaceKinetics
Browse files Browse the repository at this point in the history
Switch from self.gas to self.kin to accommodate non-gaseous phases
  • Loading branch information
ischoegl committed Jan 20, 2022
1 parent 9eac482 commit a4184d4
Showing 1 changed file with 101 additions and 49 deletions.
150 changes: 101 additions & 49 deletions interfaces/cython/cantera/test/test_reaction.py
Expand Up @@ -71,7 +71,7 @@ def test_duplicate(self):
gas1.write_yaml(fname)

with self.assertRaisesRegex(Exception, "Undeclared duplicate reactions"):
gas2 = ct.Solution(fname)
ct.Solution(fname)

Path(fname).unlink()

Expand Down Expand Up @@ -676,53 +676,53 @@ class ReactionTests:
@classmethod
def setUpClass(cls):
utilities.CanteraTest.setUpClass()
cls.gas = ct.Solution("kineticsfromscratch.yaml", transport_model=None)
cls.species = cls.gas.species()
cls.kin = ct.Solution("kineticsfromscratch.yaml", transport_model=None)
cls.species = cls.kin.species()

def setUp(self):
self.gas.X = "H2:0.1, H2O:0.2, O2:0.7, O:1e-4, OH:1e-5, H:2e-5"
self.gas.TP = 900, 2*ct.one_atm
self.kin.X = "H2:0.1, H2O:0.2, O2:0.7, O:1e-4, OH:1e-5, H:2e-5"
self.kin.TP = 900, 2*ct.one_atm

def eval_rate(self, rate):
# evaluate rate expression
return rate(self.gas.T)
return rate(self.kin.T)

def from_yaml(self, deprecated=False):
# create reaction object from yaml
if deprecated:
with self.assertWarnsRegex(DeprecationWarning, "is renamed to 'from_yaml'"):
return ct.Reaction.fromYaml(self._yaml, kinetics=self.gas)
return ct.Reaction.from_yaml(self._yaml, kinetics=self.gas)
return ct.Reaction.fromYaml(self._yaml, kinetics=self.kin)
return ct.Reaction.from_yaml(self._yaml, kinetics=self.kin)

def from_dict(self):
# create reaction rate object from input data
input_data = self.from_yaml().input_data
return ct.Reaction.from_dict(input_data, kinetics=self.gas)
return ct.Reaction.from_dict(input_data, kinetics=self.kin)

def from_rate(self, rate):
# create reaction object from keywords / rate
return self._cls(equation=self._equation, rate=rate, kinetics=self.gas,
return self._cls(equation=self._equation, rate=rate, kinetics=self.kin,
legacy=self._legacy, **self._kwargs)

def from_parts(self):
# create reaction rate object from parts
orig = self.gas.reaction(self._index)
orig = self.kin.reaction(self._index)
rxn = self._cls(orig.reactants, orig.products, legacy=self._legacy)
rxn.rate = self._rate_obj
return rxn

def check_rate(self, rate_obj):
if self._legacy:
rate = rate_obj(self.gas.T)
rate = rate_obj(self.kin.T)
else:
rate = self.eval_rate(rate_obj)
self.assertNear(rate, self.gas.forward_rate_constants[self._index])
self.assertNear(rate, self.kin.forward_rate_constants[self._index])

def check_rxn(self, rxn, check_legacy=True):
# helper function that checks reaction configuration
ix = self._index
self.assertEqual(rxn.reactants, self.gas.reaction(ix).reactants)
self.assertEqual(rxn.products, self.gas.reaction(ix).products)
self.assertEqual(rxn.reactants, self.kin.reaction(ix).reactants)
self.assertEqual(rxn.products, self.kin.reaction(ix).products)
if check_legacy:
self.assertEqual(rxn.reaction_type, self._type)
self.assertEqual(rxn.uses_legacy, self._type.endswith("-legacy"))
Expand All @@ -731,20 +731,20 @@ def check_rxn(self, rxn, check_legacy=True):
if not self._legacy:
# legacy rate evaluation is not consistent
self.check_rate(rxn.rate)
gas2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
kin2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
species=self.species, reactions=[rxn])
gas2.TPX = self.gas.TPX
self.check_solution(gas2, check_legacy)
kin2.TPX = self.kin.TPX
self.check_solution(kin2, check_legacy)

def check_solution(self, gas2, check_legacy=True):
def check_solution(self, kin2, check_legacy=True):
# helper function that checks evaluation of reaction rates
ix = self._index
if check_legacy:
self.assertEqual(gas2.reaction_type_str(0), self._type)
self.assertNear(gas2.forward_rate_constants[0],
self.gas.forward_rate_constants[ix])
self.assertNear(gas2.net_rates_of_progress[0],
self.gas.net_rates_of_progress[ix])
self.assertEqual(kin2.reaction_type_str(0), self._type)
self.assertNear(kin2.forward_rate_constants[0],
self.kin.forward_rate_constants[ix])
self.assertNear(kin2.net_rates_of_progress[0],
self.kin.net_rates_of_progress[ix])

def test_rate(self):
# check consistency of reaction rate and forward rate constant
Expand Down Expand Up @@ -782,12 +782,12 @@ def test_add_rxn(self):
# check adding new reaction to solution
if self._rate_obj is None:
return
gas2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
kin2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
species=self.species, reactions=[])
gas2.TPX = self.gas.TPX
kin2.TPX = self.kin.TPX
rxn = self.from_rate(self._rate_obj)
gas2.add_reaction(rxn)
self.check_solution(gas2)
kin2.add_reaction(rxn)
self.check_solution(kin2)

def test_raises_invalid_rate(self):
# check exception for instantiation from keywords / invalid rate
Expand All @@ -806,22 +806,22 @@ def test_no_rate(self):
return
rxn = self.from_rate(None)
if self._legacy:
self.assertNear(rxn.rate(self.gas.T), 0.)
self.assertNear(rxn.rate(self.kin.T), 0.)
else:
self.assertIsNaN(self.eval_rate(rxn.rate))

gas2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
kin2 = ct.Solution(thermo="IdealGas", kinetics="GasKinetics",
species=self.species, reactions=[rxn])
gas2.TPX = self.gas.TPX
kin2.TPX = self.kin.TPX
if self._legacy:
self.assertNear(gas2.forward_rate_constants[0], 0.)
self.assertNear(gas2.net_rates_of_progress[0], 0.)
self.assertNear(kin2.forward_rate_constants[0], 0.)
self.assertNear(kin2.net_rates_of_progress[0], 0.)
elif not ct.debug_mode_enabled():
self.assertIsNaN(gas2.forward_rate_constants[0])
self.assertIsNaN(gas2.net_rates_of_progress[0])
self.assertIsNaN(kin2.forward_rate_constants[0])
self.assertIsNaN(kin2.net_rates_of_progress[0])
else:
with self.assertRaisesRegex(ct.CanteraError, "not finite"):
gas2.net_rates_of_progress
kin2.net_rates_of_progress

def test_replace_rate(self):
# check replacing reaction rate expression
Expand Down Expand Up @@ -974,7 +974,7 @@ def test_rate(self):

def test_efficiencies(self):
# check efficiencies
rxn = self._cls(equation=self._equation, rate=self._rate_obj, kinetics=self.gas,
rxn = self._cls(equation=self._equation, rate=self._rate_obj, kinetics=self.kin,
legacy=self._legacy, **self._kwargs)

self.assertEqual(rxn.efficiencies, self._kwargs["efficiencies"])
Expand Down Expand Up @@ -1037,7 +1037,7 @@ def setUpClass(cls):
cls._rate_obj = ct.TwoTempPlasmaRate(**cls._rate)

def eval_rate(self, rate):
return rate(self.gas.T, self.gas.Te)
return rate(self.kin.T, self.kin.Te)


class TestBlowersMasel(ReactionTests, utilities.CanteraTest):
Expand All @@ -1060,8 +1060,8 @@ def setUpClass(cls):
cls._rate_obj = ct.BlowersMaselRate(**cls._rate)

def eval_rate(self, rate):
delta_enthalpy = self.gas.delta_enthalpy[self._index]
return rate(self.gas.T, delta_enthalpy)
delta_enthalpy = self.kin.delta_enthalpy[self._index]
return rate(self.kin.T, delta_enthalpy)


class TestTroe2(ReactionTests, utilities.CanteraTest):
Expand Down Expand Up @@ -1130,8 +1130,8 @@ def setUpClass(cls):
cls._rate_obj = ct.TroeRate(low=low, high=high, falloff_coeffs=data)

def eval_rate(self, rate):
concm = self.gas.third_body_concentrations[self._index]
return rate(self.gas.T, concm)
concm = self.kin.third_body_concentrations[self._index]
return rate(self.kin.T, concm)

def from_parts(self):
rxn = ReactionTests.from_parts(self)
Expand Down Expand Up @@ -1172,8 +1172,8 @@ def setUpClass(cls):
cls._rate_obj = ct.LindemannRate(low=low, high=high, falloff_coeffs=[])

def eval_rate(self, rate):
concm = self.gas.third_body_concentrations[self._index]
return rate(self.gas.T, concm)
concm = self.kin.third_body_concentrations[self._index]
return rate(self.kin.T, concm)

def from_parts(self):
rxn = ReactionTests.from_parts(self)
Expand Down Expand Up @@ -1237,8 +1237,8 @@ def setUpClass(cls):
cls._rate_obj.chemically_activated = True

def eval_rate(self, rate):
concm = self.gas.third_body_concentrations[self._index]
return rate(self.gas.T, concm)
concm = self.kin.third_body_concentrations[self._index]
return rate(self.kin.T, concm)


class TestPlog2(ReactionTests, utilities.CanteraTest):
Expand Down Expand Up @@ -1321,7 +1321,7 @@ class TestPlog(TestPlog2):
"""

def eval_rate(self, rate):
return rate(self.gas.T, self.gas.P)
return rate(self.kin.T, self.kin.P)


class TestChebyshev2(ReactionTests, utilities.CanteraTest):
Expand Down Expand Up @@ -1377,7 +1377,7 @@ class TestChebyshev(TestChebyshev2):
"""

def eval_rate(self, rate):
return rate(self.gas.T, self.gas.P)
return rate(self.kin.T, self.kin.P)


class TestCustom(ReactionTests, utilities.CanteraTest):
Expand Down Expand Up @@ -1418,9 +1418,61 @@ def test_rate_func(self):
# check result of rate expression
f = ct.Func1(self._rate)
rate = ct.CustomRate(f)
self.assertNear(rate(self.gas.T), self.gas.forward_rate_constants[self._index])
self.assertNear(rate(self.kin.T), self.kin.forward_rate_constants[self._index])

def test_custom_lambda(self):
# check instantiation from keywords / rate provided as lambda function
rxn = self.from_rate(lambda T: 38.7 * T**2.7 * exp(-3150.15428/T))
self.check_rxn(rxn)


class SurfaceReactionTests(ReactionTests):
# test suite for reaction expressions

@classmethod
def setUpClass(cls):
utilities.CanteraTest.setUpClass()
cls.kin = ct.Interface("ptcombust.yaml", "Pt_surf", transport_model=None)
cls.gas = cls.kin.adjacent["gas"]
cls.species = cls.kin.species()

def setUp(self):
self.kin.TP = 900, ct.one_atm
self.gas.X = "H2:0.05, O2:0.21, N2:0.78, AR:0.01"
self.gas.TP = 900, ct.one_atm
self.kin.advance_coverages(1.0)


class TestInterfaceReaction(SurfaceReactionTests, utilities.CanteraTest):

_cls = ct.InterfaceReaction
_equation = "H(S) + O(S) <=> OH(S) + PT(S)"
_rate = {"A": 3.7e+20, "b": 0, "Ea": 1.15e7}
_index = 11
_type = "interface"
_legacy = True
_yaml = """
equation: H(S) + O(S) <=> OH(S) + PT(S)
rate-constant: {A: 3.7e+20, b: 0, Ea: 11500 J/mol}
"""

def check_rxn(self, rxn, check_legacy=True):
# helper function that checks reaction configuration
ix = self._index
self.assertEqual(rxn.reactants, self.kin.reaction(ix).reactants)
self.assertEqual(rxn.products, self.kin.reaction(ix).products)
if check_legacy:
self.assertEqual(rxn.reaction_type, self._type)
#self.assertEqual(rxn.uses_legacy, self._type.endswith("-legacy"))
self.assertEqual(rxn.uses_legacy, self._legacy)

if not self._legacy:
# legacy rate evaluation is not consistent
self.check_rate(rxn.rate)
kin2 = ct.Interface(thermo="Surface", kinetics="interface",
species=self.species, reactions=[rxn], adjacent=[self.gas])

kin2.site_density = self.kin.site_density
kin2.coverages = self.kin.coverages
kin2.TP = self.kin.TP
self.check_solution(kin2, check_legacy)

0 comments on commit a4184d4

Please sign in to comment.