mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
1398 lines
63 KiB
Python
1398 lines
63 KiB
Python
from __future__ import annotations
|
|
|
|
import itertools
|
|
from pathlib import Path
|
|
import logging
|
|
import io
|
|
import pytest
|
|
|
|
from . import utilities
|
|
from .utilities import allow_deprecated
|
|
|
|
import cantera as ct
|
|
from cantera import ck2yaml, cti2yaml, ctml2yaml, yaml2ck
|
|
|
|
class ck2yamlTest(utilities.CanteraTest):
|
|
def convert(self, inputFile, thermo=None, transport=None,
|
|
surface=None, output=None, extra=None, **kwargs):
|
|
if output is None:
|
|
output = Path(inputFile).stem # strip '.inp'
|
|
if inputFile is not None:
|
|
inputFile = self.test_data_path / inputFile
|
|
if thermo is not None:
|
|
thermo = self.test_data_path / thermo
|
|
if transport is not None:
|
|
transport = self.test_data_path / transport
|
|
if surface is not None:
|
|
surface = self.test_data_path / surface
|
|
if extra is not None:
|
|
extra = self.test_data_path / extra
|
|
output = self.test_work_path / (output + "-from-ck.yaml")
|
|
# In Python >= 3.8, this can be replaced by the missing_ok argument
|
|
if output.is_file():
|
|
output.unlink()
|
|
ck2yaml.convert(inputFile, thermo_file=thermo,
|
|
transport_file=transport, surface_file=surface, out_name=output,
|
|
extra_file=extra, quiet=True, **kwargs)
|
|
return output
|
|
|
|
def checkConversion(self, refFile, testFile):
|
|
ref = ct.Solution(refFile)
|
|
gas = ct.Solution(testFile)
|
|
|
|
self.assertEqual(ref.element_names, gas.element_names)
|
|
self.assertEqual(ref.species_names, gas.species_names)
|
|
coeffs_ref = ref.reactant_stoich_coeffs
|
|
coeffs_gas = gas.reactant_stoich_coeffs
|
|
self.assertEqual(coeffs_gas.shape, coeffs_ref.shape)
|
|
self.assertTrue((coeffs_gas == coeffs_ref).all())
|
|
|
|
compositionA = [[ref.n_atoms(i,j) for j in range(ref.n_elements)]
|
|
for i in range(ref.n_species)]
|
|
compositionB = [[gas.n_atoms(i,j) for j in range(gas.n_elements)]
|
|
for i in range(gas.n_species)]
|
|
self.assertEqual(compositionA, compositionB)
|
|
|
|
return ref, gas
|
|
|
|
def checkThermo(self, ref, gas, temperatures):
|
|
for T in temperatures:
|
|
ref.TP = T, ct.one_atm
|
|
gas.TP = T, ct.one_atm
|
|
ref_cp = ref.standard_cp_R
|
|
gas_cp = gas.standard_cp_R
|
|
ref_h = ref.standard_enthalpies_RT
|
|
gas_h = gas.standard_enthalpies_RT
|
|
ref_s = ref.standard_entropies_R
|
|
gas_s = gas.standard_entropies_R
|
|
for i in range(gas.n_species):
|
|
message = ' for species {0} at T = {1}'.format(i, T)
|
|
self.assertNear(ref_cp[i], gas_cp[i], 1e-7, msg='cp'+message)
|
|
self.assertNear(ref_h[i], gas_h[i], 1e-7, msg='h'+message)
|
|
self.assertNear(ref_s[i], gas_s[i], 1e-7, msg='s'+message)
|
|
|
|
def checkKinetics(self, ref, gas, temperatures, pressures, tol=1e-8):
|
|
for T,P in itertools.product(temperatures, pressures):
|
|
ref.TP = T, P
|
|
gas.TP = T, P
|
|
ref_kf = ref.forward_rate_constants
|
|
ref_kr = ref.reverse_rate_constants
|
|
gas_kf = gas.forward_rate_constants
|
|
gas_kr = gas.reverse_rate_constants
|
|
for i in range(gas.n_reactions):
|
|
message = ' for reaction {0} at T = {1}, P = {2}'.format(i, T, P)
|
|
self.assertNear(ref_kf[i], gas_kf[i], rtol=tol, msg='kf' + message)
|
|
self.assertNear(ref_kr[i], gas_kr[i], rtol=tol, msg='kr' + message)
|
|
|
|
@utilities.slow_test
|
|
def test_gri30(self):
|
|
output = self.convert('gri30.inp', thermo='gri30_thermo.dat',
|
|
transport='gri30_tran.dat', output='gri30_test')
|
|
|
|
ref, gas = self.checkConversion("gri30.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 1500], [5e3, 1e5, 2e6])
|
|
|
|
def test_soot(self):
|
|
output = self.convert("soot.inp", thermo="soot-therm.dat", output="soot_test")
|
|
ref, gas = self.checkConversion("soot.yaml", output)
|
|
self.checkThermo(ref, gas, [300, 1100])
|
|
self.checkKinetics(ref, gas, [300, 1100], [5e3, 1e5, 2e6])
|
|
|
|
def test_pdep(self):
|
|
output = self.convert('pdep-test.inp')
|
|
ref, gas = self.checkConversion('pdep-test.yaml', output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_species_only(self):
|
|
self.convert(None, thermo='dummy-thermo.dat', output='dummy-thermo')
|
|
yaml = ("{phases: [{name: gas, species: "
|
|
"[{dummy-thermo-from-ck.yaml/species: [R1A, R1B, P1]}], "
|
|
"thermo: ideal-gas}]}")
|
|
gas = ct.Solution(yaml=yaml)
|
|
self.assertEqual(gas.n_species, 3)
|
|
self.assertEqual(gas.n_reactions, 0)
|
|
|
|
def test_missingThermo(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'No thermo data'):
|
|
self.convert('h2o2_missingThermo.inp')
|
|
|
|
def test_duplicate_thermo(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'additional thermo'):
|
|
self.convert('duplicate-thermo.inp')
|
|
|
|
output = self.convert('duplicate-thermo.inp', permissive=True)
|
|
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_species, 3)
|
|
self.assertEqual(gas.n_reactions, 2)
|
|
|
|
def test_duplicate_species(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'additional declaration'):
|
|
self.convert('duplicate-species.inp')
|
|
|
|
output = self.convert('duplicate-species.inp', permissive=True)
|
|
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.species_names, ['foo','bar','baz'])
|
|
|
|
def test_pathologicalSpeciesNames(self):
|
|
output = self.convert('species-names.inp')
|
|
gas = ct.Solution(output)
|
|
|
|
self.assertEqual(gas.n_species, 10)
|
|
self.assertEqual(gas.species_name(0), '(Parens)')
|
|
self.assertEqual(gas.species_name(1), '@#$%^-2')
|
|
self.assertEqual(gas.species_index('co:lons:'), 2)
|
|
self.assertEqual(gas.species_name(3), '[xy2]*{.}')
|
|
self.assertEqual(gas.species_name(4), 'plus+')
|
|
self.assertEqual(gas.species_name(5), 'eq=uals')
|
|
self.assertEqual(gas.species_name(6), 'plus')
|
|
self.assertEqual(gas.species_name(7), 'trans_butene')
|
|
self.assertEqual(gas.species_name(8), 'co')
|
|
self.assertEqual(gas.species_name(9), "amp&ersand")
|
|
|
|
self.assertEqual(gas.n_reactions, 13)
|
|
nu = gas.product_stoich_coeffs - gas.reactant_stoich_coeffs
|
|
self.assertEqual(list(nu[:,0]), [-1, -1, 0, 2, 0, 0, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,1]), [-2, 3, 0, -1, 0, 0, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,2]), [-1, 0, 0, 0, 1, 0, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,3]), [3, 0, 0, 0, -2, -1, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,4]), [2, 0, 0, 0, -1, 0, -1, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,5]), [1, 0, 0, 0, 1, -1, -1, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,6]), [2, 0, -1, 0, 0, -1, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,7]), [0, 0, 0, 0, -1, 1, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,8]), [0, 0, 0, 0, -1, 1, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,9]), [0, 0, 0, 0, -1, 1, 0, 0, 0, 0])
|
|
self.assertEqual(list(nu[:,10]), [0, 0, -1, 0, 2, 0, 0, -1, 0, 0])
|
|
self.assertEqual(list(nu[:,11]), [0, 0, -1, 0, 2, 0, 0, 0, -1, 0])
|
|
self.assertEqual(list(nu[:,12]), [0, 0, 0, 0, 1, 0, 0, 0, 0, -1])
|
|
|
|
def test_unterminatedSections(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'implicitly ended'):
|
|
self.convert('unterminated-sections.inp')
|
|
|
|
output = self.convert('unterminated-sections.inp', permissive=True)
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_species, 3)
|
|
self.assertEqual(gas.n_reactions, 2)
|
|
|
|
def test_unterminatedSections2(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'implicitly ended'):
|
|
self.convert('unterminated-sections2.inp')
|
|
|
|
output = self.convert('unterminated-sections2.inp', permissive=True)
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_species, 3)
|
|
self.assertEqual(gas.n_reactions, 2)
|
|
|
|
def test_unrecognized_section(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'SPAM'):
|
|
self.convert('unrecognized-section.inp', thermo='dummy-thermo.dat',
|
|
permissive=True)
|
|
|
|
def test_nasa9(self):
|
|
output = self.convert("nasa9-test.inp", thermo="nasa9-test-therm.dat")
|
|
ref, gas = self.checkConversion("nasa9-test.yaml", output)
|
|
self.checkThermo(ref, gas, [300, 500, 1200, 5000])
|
|
|
|
def test_nasa9_subset(self):
|
|
output = self.convert("nasa9-test-subset.inp", thermo="nasa9-test-therm.dat")
|
|
ref, gas = self.checkConversion("nasa9-test-subset.yaml", output)
|
|
self.checkThermo(ref, gas, [300, 500, 1200, 5000])
|
|
|
|
def test_sri_falloff(self):
|
|
output = self.convert("sri-falloff.inp", thermo="dummy-thermo.dat")
|
|
ref, gas = self.checkConversion("sri-falloff.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_chemically_activated(self):
|
|
output = self.convert("chemically-activated-reaction.inp")
|
|
ref, gas = self.checkConversion("chemically-activated-reaction.yaml",
|
|
output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6, 1e7])
|
|
|
|
def test_explicit_third_bodies(self):
|
|
output = self.convert("explicit-third-bodies.inp", thermo="dummy-thermo.dat")
|
|
ref, gas = self.checkConversion("explicit-third-bodies.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_explicit_reverse_rate(self):
|
|
output = self.convert("explicit-reverse-rate.inp", thermo="dummy-thermo.dat")
|
|
ref, gas = self.checkConversion("explicit-reverse-rate.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
# Reactions with explicit reverse rate constants are transformed into
|
|
# two irreversible reactions with reactants and products swapped, unless
|
|
# the explicit reverse rate is zero so only the forward reaction is used.
|
|
Rr = gas.reverse_rate_constants
|
|
self.assertEqual(Rr[0], 0.0)
|
|
self.assertEqual(Rr[1], 0.0)
|
|
self.assertEqual(Rr[2], 0.0)
|
|
self.assertEqual(Rr[3], 0.0)
|
|
self.assertEqual(Rr[4], 0.0)
|
|
Rstoich = gas.reactant_stoich_coeffs
|
|
Pstoich = gas.product_stoich_coeffs
|
|
self.assertEqual(list(Rstoich[:, 0]), list(Pstoich[:, 1]))
|
|
self.assertEqual(list(Rstoich[:, 1]), list(Pstoich[:, 0]))
|
|
self.assertEqual(list(Rstoich[:, 2]), list(Pstoich[:, 3]))
|
|
self.assertEqual(list(Rstoich[:, 3]), list(Pstoich[:, 2]))
|
|
|
|
self.assertEqual(gas.n_reactions, 5)
|
|
|
|
def test_explicit_forward_order(self):
|
|
output = self.convert("explicit-forward-order.inp", thermo="dummy-thermo.dat")
|
|
ref, gas = self.checkConversion("explicit-forward-order.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_negative_order(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Negative reaction order'):
|
|
self.convert('negative-order.inp', thermo='dummy-thermo.dat')
|
|
|
|
def test_negative_order_permissive(self):
|
|
output = self.convert('negative-order.inp', thermo='dummy-thermo.dat',
|
|
permissive=True)
|
|
ref, gas = self.checkConversion("negative-order.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_negative_A_factor(self):
|
|
output = self.convert('negative-rate.inp', thermo='dummy-thermo.dat')
|
|
gas = ct.Solution(output) # Validate the mechanism
|
|
self.assertLess(gas.reaction(4).rate.pre_exponential_factor, 0)
|
|
self.assertLess(gas.reaction(1).rate.pre_exponential_factor, 0)
|
|
self.assertLess(gas.reaction(2).rate.pre_exponential_factor, 0)
|
|
self.assertLess(gas.forward_rate_constants[5], 0)
|
|
|
|
def test_bad_troe_value(self):
|
|
with self.assertRaises(ValueError):
|
|
self.convert('bad-troe.inp', thermo='dummy-thermo.dat')
|
|
|
|
def test_invalid_reaction_equation(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Unparsable'):
|
|
self.convert('invalid-equation.inp', thermo='dummy-thermo.dat')
|
|
|
|
@utilities.slow_test
|
|
def test_reaction_units(self):
|
|
out_def = self.convert('units-default.inp', thermo='dummy-thermo.dat')
|
|
out_cus = self.convert('units-custom.inp', thermo='dummy-thermo.dat')
|
|
default, custom = self.checkConversion(out_def, out_cus)
|
|
self.checkKinetics(default, custom,
|
|
[300, 800, 1450, 2800], [5e0, 5e3, 1e5, 2e6, 1e8], 1e-7)
|
|
|
|
def test_float_stoich_coeffs(self):
|
|
output = self.convert('float-stoich.inp', thermo='dummy-thermo.dat')
|
|
gas = ct.Solution(output)
|
|
|
|
R = gas.reactant_stoich_coeffs
|
|
P = gas.product_stoich_coeffs
|
|
self.assertArrayNear(R[:,0], [0, 1.5, 0.5, 0])
|
|
self.assertArrayNear(P[:,0], [1, 0, 0, 1])
|
|
self.assertArrayNear(R[:,1], [1, 0, 0, 1])
|
|
self.assertArrayNear(P[:,1], [0, 0.33, 1.67, 0])
|
|
|
|
def test_photon(self):
|
|
output = self.convert('photo-reaction.inp', thermo='dummy-thermo.dat',
|
|
permissive=True)
|
|
|
|
ref, gas = self.checkConversion("photo-reaction.yaml", output)
|
|
self.checkKinetics(ref, gas, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_transport_normal(self):
|
|
output = self.convert('h2o2.inp', transport='gri30_tran.dat',
|
|
output='h2o2_transport_normal')
|
|
|
|
gas = ct.Solution(output)
|
|
gas.TPX = 300, 101325, 'H2:1.0, O2:1.0'
|
|
self.assertAlmostEqual(gas.thermal_conductivity, 0.07663, 4)
|
|
|
|
def test_transport_embedded(self):
|
|
output = self.convert('with-transport.inp')
|
|
gas = ct.Solution(output)
|
|
gas.X = [0.2, 0.3, 0.5]
|
|
D = gas.mix_diff_coeffs
|
|
for d in D:
|
|
self.assertTrue(d > 0.0)
|
|
|
|
def test_transport_missing_species(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'No transport data'):
|
|
self.convert('h2o2.inp', transport='h2o2-missing-species-tran.dat',
|
|
output='h2o2_transport_missing_species')
|
|
|
|
def test_transport_extra_column_entries(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, '572.400'):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-extra-column-entries-tran.dat',
|
|
output='h2o2_extra-column-entries-tran')
|
|
|
|
def test_transport_duplicate_species(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'duplicate transport'):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-duplicate-species-tran.dat',
|
|
output='h2o2_transport_duplicate_species')
|
|
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-duplicate-species-tran.dat',
|
|
output='h2o2_transport_duplicate_species', permissive=True)
|
|
|
|
def test_transport_bad_geometry(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Invalid geometry flag value'):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-bad-geometry-tran.dat',
|
|
output='h2o2_transport_bad_geometry')
|
|
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Invalid geometry flag \''):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-character-geometry-tran.dat',
|
|
output='h2o2_transport_character_geometry')
|
|
|
|
def test_transport_float_geometry(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Incorrect geometry flag syntax'):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-float-geometry-tran.dat',
|
|
output='h2o2_transport_float_geometry')
|
|
|
|
output = self.convert('h2o2.inp',
|
|
transport='h2o2-float-geometry-tran.dat',
|
|
output='h2o2_transport_float_geometry', permissive=True)
|
|
|
|
gas = ct.Solution(output)
|
|
self.assertTrue(gas.species("H").transport.geometry == 'atom')
|
|
self.assertTrue(gas.species("H2").transport.geometry == 'linear')
|
|
self.assertTrue(gas.species("H2O").transport.geometry == 'nonlinear')
|
|
|
|
with self.assertRaisesRegex(ck2yaml.InputError, 'Invalid float geometry flag'):
|
|
self.convert('h2o2.inp',
|
|
transport='h2o2-float-arithmetic-error-geometry-tran.dat',
|
|
output='h2o2_transport_float_geometry', permissive=True)
|
|
|
|
def test_empty_reaction_section(self):
|
|
output = self.convert('h2o2_emptyReactions.inp')
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_species, 9)
|
|
self.assertEqual(gas.n_reactions, 0)
|
|
|
|
def test_reaction_comments1(self):
|
|
output = self.convert('pdep-test.inp')
|
|
text = output.read_text()
|
|
self.assertIn('Generic mechanism header', text)
|
|
self.assertIn('Single PLOG reaction', text)
|
|
self.assertIn('Multiple PLOG expressions at the same pressure', text)
|
|
|
|
def test_reaction_comments2(self):
|
|
output = self.convert('explicit-third-bodies.inp', thermo='dummy-thermo.dat')
|
|
text = output.read_text()
|
|
self.assertIn('An end of line comment', text)
|
|
self.assertIn('A comment after the last reaction', text)
|
|
|
|
def test_custom_element(self):
|
|
output = self.convert('custom-elements.inp')
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_elements, 4)
|
|
self.assertNear(gas.atomic_weight(2), 13.003)
|
|
self.assertEqual(gas.n_atoms('ethane', 'C'), 2)
|
|
self.assertEqual(gas.n_atoms('CC', 'C'), 1)
|
|
self.assertEqual(gas.n_atoms('CC', 'Ci'), 1)
|
|
|
|
def test_surface_mech(self):
|
|
output = self.convert('surface1-gas.inp', surface='surface1.inp',
|
|
output='surface1')
|
|
|
|
surf = ct.Interface(output, 'PT_SURFACE')
|
|
gas = surf.adjacent["gas"]
|
|
|
|
self.assertEqual(gas.n_reactions, 11)
|
|
self.assertEqual(surf.n_reactions, 15)
|
|
self.assertEqual(surf.species('O2_Pt').size, 3)
|
|
|
|
# Different units for rate constants in each input file
|
|
# 62.1 kJ/gmol = 6.21e7 J/kmol
|
|
self.assertNear(gas.reaction(0).rate.activation_energy, 6.21e7)
|
|
# 67400 J/mol = 6.74e7 J/kmol
|
|
self.assertNear(surf.reaction(1).rate.activation_energy, 6.74e7)
|
|
|
|
# Sticking coefficients
|
|
self.assertTrue(surf.reaction(4).duplicate)
|
|
self.assertNotIsInstance(surf.reaction(1).rate, ct.StickingArrheniusRate)
|
|
self.assertIsInstance(surf.reaction(2).rate, ct.StickingArrheniusRate)
|
|
self.assertTrue(surf.reaction(2).rate.motz_wise_correction)
|
|
self.assertIsInstance(surf.reaction(4).rate, ct.StickingArrheniusRate)
|
|
self.assertFalse(surf.reaction(4).rate.motz_wise_correction)
|
|
self.assertTrue(surf.reaction(6).rate.motz_wise_correction)
|
|
|
|
# Coverage dependencies
|
|
covdeps = surf.reaction(1).rate.coverage_dependencies
|
|
self.assertEqual(len(covdeps), 2)
|
|
self.assertIn("H_Pt", covdeps)
|
|
self.assertEqual(covdeps["OH_Pt"]["m"], 1.0)
|
|
self.assertNear(covdeps["H_Pt"]["E"], -6e6) # 6000 J/gmol = 6e6 J/kmol
|
|
|
|
def test_surface_mech2(self):
|
|
output = self.convert('surface1-gas-noreac.inp', surface='surface1.inp',
|
|
output='surface1-nogasreac')
|
|
|
|
gas = ct.Solution(output, 'gas')
|
|
surf = ct.Interface(output, 'PT_SURFACE', [gas])
|
|
|
|
self.assertEqual(gas.n_reactions, 0)
|
|
self.assertEqual(surf.n_reactions, 15)
|
|
|
|
covdeps = surf.reaction(1).rate.coverage_dependencies
|
|
self.assertIn("H_Pt", covdeps)
|
|
self.assertEqual(covdeps["OH_Pt"]["m"], 1.0)
|
|
self.assertNear(covdeps["H_Pt"]["E"], -6e6)
|
|
|
|
def test_surface_mech3(self):
|
|
# This tests the case where the thermo data for both the gas and surface are
|
|
# combined in a file separate from the gas and surface definitions.
|
|
|
|
output = self.convert('surface2-gas.inp', thermo='surface2-thermo.dat',
|
|
surface='surface2.inp', output='surface2')
|
|
surf = ct.Interface(output, 'PT_SURFACE')
|
|
|
|
assert surf.n_species == 6
|
|
assert surf.n_reactions == 15
|
|
assert surf.reaction(4).duplicate is True
|
|
|
|
def test_third_body_plus_falloff_reactions(self):
|
|
output = self.convert("third_body_plus_falloff_reaction.inp")
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_reactions, 2)
|
|
|
|
def test_blank_line_in_header(self):
|
|
output = self.convert("blank_line_in_header.inp")
|
|
gas = ct.Solution(output)
|
|
self.assertEqual(gas.n_reactions, 1)
|
|
|
|
@utilities.slow_test
|
|
def test_extra(self):
|
|
output = self.convert("gri30.inp", thermo="gri30_thermo.dat",
|
|
transport="gri30_tran.dat", output="gri30_extra",
|
|
extra="extra.yaml")
|
|
|
|
yml = utilities.load_yaml(output)
|
|
|
|
desc = yml['description'].split('\n')[-1]
|
|
self.assertEqual(desc, 'This is an alternative description.')
|
|
for key in ['foo', 'bar']:
|
|
self.assertIn(key, yml.keys())
|
|
|
|
def test_sri_zero(self):
|
|
# This test tests it can convert the SRI parameters when D or E equal to 0
|
|
output = self.convert('sri_convert_test.txt')
|
|
mech = utilities.load_yaml(output)
|
|
D = mech['reactions'][0]['SRI']['D']
|
|
E = mech['reactions'][0]['SRI']['E']
|
|
self.assertEqual(D, 0)
|
|
self.assertEqual(E, 0)
|
|
|
|
def test_duplicate_reactions(self):
|
|
# Running a test this way instead of using the convertMech function
|
|
# tests the behavior of the ck2yaml.main function and the mechanism
|
|
# validation step.
|
|
|
|
# Replace the ck2yaml logger with our own in order to capture the output
|
|
log_stream = io.StringIO()
|
|
logger = logging.getLogger('cantera.ck2yaml')
|
|
original_handler = logger.handlers.pop()
|
|
logformatter = logging.Formatter('%(message)s')
|
|
handler = logging.StreamHandler(log_stream)
|
|
handler.setFormatter(logformatter)
|
|
logger.addHandler(handler)
|
|
|
|
with self.assertRaises(SystemExit):
|
|
ck2yaml.main([
|
|
f"--input={self.test_data_path}/undeclared-duplicate-reactions.inp",
|
|
f"--thermo={self.test_data_path}/dummy-thermo.dat",
|
|
f"--output={self.test_work_path}/undeclared-duplicate-reactions.yaml"])
|
|
|
|
# Put the original logger back in place
|
|
logger.handlers.clear()
|
|
logger.addHandler(original_handler)
|
|
|
|
message = log_stream.getvalue()
|
|
for token in ('FAILED', 'lines 12 and 14', 'R1A', 'R1B'):
|
|
self.assertIn(token, message)
|
|
|
|
def test_single_Tint(self):
|
|
output = self.convert(None, thermo="thermo_single_Tint.dat",
|
|
output="thermo_single_Tint",
|
|
single_intermediate_temperature=True)
|
|
mech = utilities.load_yaml(output)
|
|
|
|
# Al(cr)
|
|
thermo = mech["species"][0]["thermo"]
|
|
assert thermo["temperature-ranges"] == [200.0, 933.61]
|
|
assert len(thermo["data"]) == 1
|
|
assert thermo["data"][0][0] == 1.01040191
|
|
|
|
# AlBr3(L)
|
|
thermo = mech["species"][1]["thermo"]
|
|
assert thermo["temperature-ranges"] == [370.6, 5000.0]
|
|
assert len(thermo["data"]) == 1
|
|
assert thermo["data"][0][0] == 15.02975
|
|
|
|
# AlF3(b)
|
|
thermo = mech["species"][2]["thermo"]
|
|
assert thermo["temperature-ranges"] == [728.0, 1000.0, 2523.0]
|
|
assert len(thermo["data"]) == 2
|
|
assert thermo["data"][1][0] == 10.41947
|
|
|
|
# AlF3(L)
|
|
thermo = mech["species"][3]["thermo"]
|
|
assert thermo["temperature-ranges"] == [2523.0, 5000.0]
|
|
assert len(thermo["data"]) == 1
|
|
assert thermo["data"][0][0] == 15.096679
|
|
|
|
def test_error_for_big_element_number(self):
|
|
with self.assertRaisesRegex(ck2yaml.InputError,
|
|
'Element amounts can have no more than 3 digits.'):
|
|
self.convert('big_element_num_err.inp')
|
|
|
|
|
|
class yaml2ckTest(utilities.CanteraTest):
|
|
"""Test yaml2ck by converting to CK then back to YAML to read with Cantera."""
|
|
ext: str = "-from-yaml2ck.yaml"
|
|
|
|
def _convert_to_ck(
|
|
self,
|
|
input_file: Path,
|
|
phase_name: str = "",
|
|
output: tuple[str, str, str] | tuple = (),
|
|
) -> tuple[Path | None, Path | None, Path | None]:
|
|
mechanism_path: Path | str
|
|
if not output:
|
|
stem = Path(input_file).stem # strip '.inp'
|
|
mechanism_path = self.test_work_path / (stem + "-from-yaml.ck")
|
|
thermo_path = transport_path = None
|
|
else:
|
|
if len(output) != 3:
|
|
raise ValueError(
|
|
"convert_to_ck output must be a tuple of length three "
|
|
"containing the mechanism, thermo, and transport file names."
|
|
)
|
|
mechanism_path, thermo_path, transport_path = output
|
|
|
|
mech, thermo, transport = yaml2ck.convert(
|
|
input_file,
|
|
phase_name=phase_name,
|
|
mechanism_path=mechanism_path,
|
|
thermo_path=thermo_path,
|
|
transport_path=transport_path,
|
|
overwrite=True,
|
|
sort_elements=None,
|
|
sort_species=None
|
|
)
|
|
|
|
return mech, thermo, transport
|
|
|
|
def convert(
|
|
self,
|
|
input_file: Path,
|
|
phase_name: str = "",
|
|
mech: str | Path | None = None,
|
|
thermo: str | Path | None = None,
|
|
transport: str | Path | None = None,
|
|
permissive: bool = False,
|
|
) -> str:
|
|
if mech is not None:
|
|
mech, thermo, transport = self._convert_to_ck(
|
|
input_file,
|
|
phase_name,
|
|
(mech, thermo, transport),
|
|
)
|
|
else:
|
|
mech, thermo, transport = self._convert_to_ck(input_file, phase_name)
|
|
|
|
output = self.test_work_path / (Path(input_file).stem + self.ext)
|
|
ck2yaml.convert(
|
|
mech,
|
|
thermo_file=thermo,
|
|
transport_file=transport,
|
|
out_name=output,
|
|
quiet=True,
|
|
permissive=permissive,
|
|
)
|
|
return mech
|
|
|
|
def check_conversion(self, basename, cls=ct.Solution, **kwargs):
|
|
# The round-trip YAML->CK->YAML will always have the single phase name 'gas'
|
|
# even if the input YAML phase has a different name
|
|
if "name" in kwargs:
|
|
phase_name = kwargs.pop("name")
|
|
else:
|
|
phase_name = ""
|
|
ckname = self.test_work_path / (basename.stem + self.ext)
|
|
ck_phase = cls(ckname, **kwargs)
|
|
yaml_phase = cls(basename, phase_name, **kwargs)
|
|
|
|
self.assertEqual(set(ck_phase.element_names), set(yaml_phase.element_names))
|
|
self.assertEqual(set(ck_phase.species_names), set(yaml_phase.species_names))
|
|
|
|
yamlSpecies = [yaml_phase.species(s) for s in ck_phase.species_names]
|
|
for C, Y in zip(ck_phase.species(), yamlSpecies):
|
|
self.assertEqual(C.composition, Y.composition)
|
|
|
|
self.assertEqual(ck_phase.n_reactions, yaml_phase.n_reactions)
|
|
for C, Y in zip(ck_phase.reactions(), yaml_phase.reactions()):
|
|
self.assertEqual(C.__class__, Y.__class__)
|
|
self.assertEqual(C.reactants, Y.reactants)
|
|
self.assertEqual(C.products, Y.products)
|
|
self.assertEqual(C.duplicate, Y.duplicate)
|
|
|
|
for i, sp in zip(range(ck_phase.n_reactions), ck_phase.kinetics_species_names):
|
|
self.assertEqual(ck_phase.reactant_stoich_coeff(sp, i),
|
|
yaml_phase.reactant_stoich_coeff(sp, i))
|
|
|
|
return ck_phase, yaml_phase
|
|
|
|
def check_thermo(self, ck_phase, yaml_phase, temperatures, tol=1e-7):
|
|
yaml_idx = {ck_phase.species_index(s): yaml_phase.species_index(s) for s in ck_phase.species_names}
|
|
|
|
for T in temperatures:
|
|
ck_phase.TP = T, ct.one_atm
|
|
yaml_phase.TP = T, ct.one_atm
|
|
cp_ck = ck_phase.partial_molar_cp
|
|
cp_yaml = yaml_phase.partial_molar_cp
|
|
h_ck = ck_phase.partial_molar_enthalpies
|
|
h_yaml = yaml_phase.partial_molar_enthalpies
|
|
s_ck = ck_phase.partial_molar_entropies
|
|
s_yaml = yaml_phase.partial_molar_entropies
|
|
self.assertNear(ck_phase.density, yaml_phase.density)
|
|
for i in range(ck_phase.n_species):
|
|
message = ' for species {0} at T = {1}'.format(i, T)
|
|
self.assertNear(cp_ck[i], cp_yaml[yaml_idx[i]], tol, msg='cp'+message)
|
|
self.assertNear(h_ck[i], h_yaml[yaml_idx[i]], tol, msg='h'+message)
|
|
self.assertNear(s_ck[i], s_yaml[yaml_idx[i]], tol, msg='s'+message)
|
|
|
|
def check_kinetics(self, ck_phase, yaml_phase, temperatures, pressures, tol=1e-7):
|
|
for T, P in itertools.product(temperatures, pressures):
|
|
ck_phase.TP = T, P
|
|
yaml_phase.TP = T, P
|
|
kf_ck = ck_phase.forward_rate_constants
|
|
kr_ck = ck_phase.reverse_rate_constants
|
|
kf_yaml = yaml_phase.forward_rate_constants
|
|
kr_yaml = yaml_phase.reverse_rate_constants
|
|
for i in range(yaml_phase.n_reactions):
|
|
message = f"for reaction {i+1}: {yaml_phase.reaction(i)} at T = {T}, P = {P}"
|
|
self.assertNear(kf_ck[i], kf_yaml[i], rtol=tol, msg="kf " + message)
|
|
self.assertNear(kr_ck[i], kr_yaml[i], rtol=tol, msg="kr " + message)
|
|
|
|
def check_transport(self, ck_phase, yaml_phase, temperatures, model="mixture-averaged"):
|
|
yaml_idx = {ck_phase.species_index(s): yaml_phase.species_index(s) for s in ck_phase.species_names}
|
|
ck_phase.transport_model = model
|
|
yaml_phase.transport_model = model
|
|
for T in temperatures:
|
|
ck_phase.TP = T, ct.one_atm
|
|
yaml_phase.TP = T, ct.one_atm
|
|
self.assertNear(ck_phase.viscosity, yaml_phase.viscosity)
|
|
self.assertNear(ck_phase.thermal_conductivity,
|
|
yaml_phase.thermal_conductivity)
|
|
Dkm_ck = ck_phase.mix_diff_coeffs
|
|
Dkm_yaml = yaml_phase.mix_diff_coeffs
|
|
for i in range(ck_phase.n_species):
|
|
message = 'dkm for species {0} at T = {1}'.format(i, T)
|
|
self.assertNear(Dkm_ck[i], Dkm_yaml[yaml_idx[i]], msg=message)
|
|
|
|
@utilities.slow_test
|
|
def test_gri30(self):
|
|
input_file = self.cantera_data_path / "gri30.yaml"
|
|
self.convert(input_file)
|
|
X = {'O2': 0.3, 'H2': 0.1, 'CH4': 0.2, 'CO2': 0.4}
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
ck_phase.X = X
|
|
yaml_phase.X = X
|
|
self.check_thermo(ck_phase, yaml_phase, [300, 500, 1300, 2000])
|
|
self.check_kinetics(ck_phase, yaml_phase, [900, 1800], [2e5, 20e5])
|
|
self.check_transport(ck_phase, yaml_phase, [298, 1001, 2400])
|
|
|
|
def test_nonreactant_orders(self):
|
|
input_file = self.test_data_path / "reaction-orders.yaml"
|
|
self.convert(input_file, permissive=True)
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
self.check_thermo(ck_phase, yaml_phase, [300, 500])
|
|
self.check_kinetics(ck_phase, yaml_phase, [300, 1001, 2500], [1e5, 10e5])
|
|
|
|
def test_phase_id(self):
|
|
input_file = self.cantera_data_path / "nDodecane_Reitz.yaml"
|
|
self.convert(input_file, "nDodecane_IG")
|
|
ck_phase, yaml_phase = self.check_conversion(input_file, name="nDodecane_IG")
|
|
ck_phase.X = "h2:1"
|
|
yaml_phase.X = "h2:1"
|
|
self.check_kinetics(
|
|
ck_phase, yaml_phase, [300, 800, 1450, 2800], [5e3, 1e5, 2e6], tol=4e-6
|
|
)
|
|
|
|
def test_third_body_reactions(self):
|
|
input_file = self.test_data_path / "explicit-third-bodies.yaml"
|
|
mech = self.convert(input_file)
|
|
with open(mech) as fid:
|
|
lines = fid.readlines()
|
|
for i, line in enumerate(lines):
|
|
if line.startswith("R1A + R1B"):
|
|
next = lines[i + 1]
|
|
assert next.startswith("LOW") or next.strip() == "DUPLICATE"
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
self.check_kinetics(
|
|
ck_phase, yaml_phase, [300, 800, 1450, 2800], [5e3, 1e5, 2e6]
|
|
)
|
|
|
|
def test_pdep(self):
|
|
input_file = self.test_data_path / "pdep-test.yaml"
|
|
self.convert(input_file)
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
# Chebyshev coefficients in XML are truncated to 6 digits, limiting accuracy
|
|
self.check_kinetics(ck_phase, yaml_phase, [300, 1000, 2200],
|
|
[100, ct.one_atm, 2e5, 2e6, 9.9e6], tol=2e-4)
|
|
|
|
def test_sri_falloff(self):
|
|
input_file = self.test_data_path / "sri-falloff.yaml"
|
|
self.convert(input_file)
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
self.check_kinetics(ck_phase, yaml_phase, [300, 800, 1450, 2800], [5e3, 1e5, 2e6])
|
|
|
|
def test_chemically_activated(self):
|
|
input_file = self.test_data_path / "chemically-activated-reaction.yaml"
|
|
self.convert(input_file)
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
# pre-exponential factor in XML is truncated to 7 sig figs, limiting accuracy
|
|
self.check_kinetics(
|
|
ck_phase, yaml_phase, [300, 800, 1450, 2800], [5e3, 1e5, 2e6, 1e7], tol=1e-7
|
|
)
|
|
|
|
def test_yaml_2_ck_reactions(self):
|
|
input_file = self.test_data_path / "yaml-ck-reactions.yaml"
|
|
self.convert(input_file)
|
|
ck_phase, yaml_phase = self.check_conversion(input_file)
|
|
X = {'O2': 0.3, 'H': 0.1, 'H2': 0.2, 'AR': 0.4}
|
|
ck_phase.X = X
|
|
yaml_phase.X = X
|
|
self.check_thermo(ck_phase, yaml_phase, [300, 500, 1300, 2000])
|
|
self.check_kinetics(ck_phase, yaml_phase, [900, 1800], [2e5, 20e5], tol=2e-7)
|
|
self.check_transport(ck_phase, yaml_phase, [298, 1001, 2400])
|
|
|
|
def test_write_chemkin(self):
|
|
# test alternative converter
|
|
yaml_phase = ct.Solution('h2o2.yaml')
|
|
ck_file = self.test_work_path / 'test.ck'
|
|
ck_file.unlink(missing_ok=True)
|
|
yaml_phase.write_chemkin(ck_file, quiet=True)
|
|
yaml_phase.write_chemkin(
|
|
ck_file, sort_species='alphabetical', overwrite=True, quiet=True)
|
|
assert ck_file.exists()
|
|
|
|
yaml_file = self.test_work_path / 'test.yaml'
|
|
yaml_file.unlink(missing_ok=True)
|
|
ck2yaml.convert(ck_file, out_name=yaml_file, quiet=True)
|
|
assert yaml_file.exists()
|
|
ck_phase = ct.Solution(yaml_file)
|
|
|
|
X = {'O2': 0.3, 'H': 0.1, 'H2': 0.2, 'AR': 0.4}
|
|
ck_phase.X = X
|
|
yaml_phase.X = X
|
|
self.check_thermo(ck_phase, yaml_phase, [300, 500, 1300, 2000])
|
|
self.check_kinetics(ck_phase, yaml_phase, [900, 1800], [2e5, 20e5], tol=2e-7)
|
|
self.check_transport(ck_phase, yaml_phase, [298, 1001, 2400])
|
|
|
|
def test_write_notes(self):
|
|
input_file = self.test_data_path / 'species-names.yaml'
|
|
yaml_phase = ct.Solution(input_file)
|
|
assert yaml_phase.species("eq=uals").input_data["thermo"]["note"] == 120521
|
|
assert yaml_phase.species("plus").input_data["thermo"]["note"] == 12.05
|
|
|
|
ck_file = self.test_work_path / 'species-names.ck'
|
|
ck_file.unlink(missing_ok=True)
|
|
yaml_phase.write_chemkin(ck_file, quiet=True)
|
|
|
|
yaml_file = self.test_work_path / 'species-names.yaml'
|
|
yaml_file.unlink(missing_ok=True)
|
|
ck2yaml.convert(ck_file, out_name=yaml_file, quiet=True)
|
|
assert yaml_file.exists()
|
|
|
|
ck_phase = ct.Solution(yaml_file)
|
|
assert ck_phase.species("eq=uals").input_data["thermo"]["note"] == "120521"
|
|
assert ck_phase.species("plus").input_data["thermo"]["note"] == "12.05"
|
|
|
|
|
|
class cti2yamlTest(utilities.CanteraTest):
|
|
def convert(self, basename, src_dir=None, encoding=None):
|
|
if src_dir is None:
|
|
src_dir = self.test_data_path
|
|
|
|
cti2yaml.convert(
|
|
filename=Path(src_dir) / f"{basename}.cti",
|
|
output_name=self.test_work_path / f"{basename}-from-cti.yaml",
|
|
encoding=encoding,
|
|
)
|
|
|
|
def checkConversion(self, basename, cls=ct.Solution, ctiphases=(),
|
|
yamlphases=(), **kwargs):
|
|
ctiPhase = cls(f"{basename}-from-cti.yaml", adjacent=ctiphases, **kwargs)
|
|
yamlPhase = cls(f"{basename}.yaml", adjacent=yamlphases, **kwargs)
|
|
|
|
self.assertEqual(ctiPhase.element_names, yamlPhase.element_names)
|
|
self.assertEqual(ctiPhase.species_names, yamlPhase.species_names)
|
|
self.assertEqual(ctiPhase.n_reactions, yamlPhase.n_reactions)
|
|
for C, Y in zip(ctiPhase.species(), yamlPhase.species()):
|
|
self.assertEqual(C.composition, Y.composition)
|
|
|
|
for C, Y in zip(ctiPhase.reactions(), yamlPhase.reactions()):
|
|
self.assertEqual(C.__class__, Y.__class__)
|
|
self.assertEqual(C.reactants, Y.reactants)
|
|
self.assertEqual(C.products, Y.products)
|
|
self.assertEqual(C.duplicate, Y.duplicate)
|
|
|
|
for i, sp in zip(range(ctiPhase.n_reactions), ctiPhase.kinetics_species_names):
|
|
self.assertEqual(ctiPhase.reactant_stoich_coeff(sp, i),
|
|
yamlPhase.reactant_stoich_coeff(sp, i))
|
|
|
|
return ctiPhase, yamlPhase
|
|
|
|
def checkThermo(self, ctiPhase, yamlPhase, temperatures, tol=1e-7, check_cp=True):
|
|
for T in temperatures:
|
|
ctiPhase.TP = T, ct.one_atm
|
|
yamlPhase.TP = T, ct.one_atm
|
|
if check_cp:
|
|
cp_cti = ctiPhase.partial_molar_cp
|
|
cp_yaml = yamlPhase.partial_molar_cp
|
|
else:
|
|
with pytest.raises(NotImplementedError):
|
|
yamlPhase.partial_molar_cp
|
|
h_cti = ctiPhase.partial_molar_enthalpies
|
|
h_yaml = yamlPhase.partial_molar_enthalpies
|
|
s_cti = ctiPhase.partial_molar_entropies
|
|
s_yaml = yamlPhase.partial_molar_entropies
|
|
self.assertNear(ctiPhase.density, yamlPhase.density)
|
|
for i in range(ctiPhase.n_species):
|
|
message = ' for species {0} at T = {1}'.format(i, T)
|
|
if check_cp:
|
|
self.assertNear(cp_cti[i], cp_yaml[i], tol, msg='cp'+message)
|
|
self.assertNear(h_cti[i], h_yaml[i], tol, msg='h'+message)
|
|
self.assertNear(s_cti[i], s_yaml[i], tol, msg='s'+message)
|
|
|
|
def checkKinetics(self, ctiPhase, yamlPhase, temperatures, pressures, tol=1e-7):
|
|
for T,P in itertools.product(temperatures, pressures):
|
|
ctiPhase.TP = T, P
|
|
yamlPhase.TP = T, P
|
|
kf_cti = ctiPhase.forward_rate_constants
|
|
kr_cti = ctiPhase.reverse_rate_constants
|
|
kf_yaml = yamlPhase.forward_rate_constants
|
|
kr_yaml = yamlPhase.reverse_rate_constants
|
|
for i in range(yamlPhase.n_reactions):
|
|
message = ' for reaction {0} at T = {1}, P = {2}'.format(i, T, P)
|
|
self.assertNear(kf_cti[i], kf_yaml[i], rtol=tol, msg='kf '+message)
|
|
self.assertNear(kr_cti[i], kr_yaml[i], rtol=tol, msg='kr '+message)
|
|
|
|
def checkTransport(self, ctiPhase, yamlPhase, temperatures,
|
|
model='mixture-averaged'):
|
|
ctiPhase.transport_model = model
|
|
yamlPhase.transport_model = model
|
|
for T in temperatures:
|
|
ctiPhase.TP = T, ct.one_atm
|
|
yamlPhase.TP = T, ct.one_atm
|
|
self.assertNear(ctiPhase.viscosity, yamlPhase.viscosity)
|
|
self.assertNear(ctiPhase.thermal_conductivity,
|
|
yamlPhase.thermal_conductivity)
|
|
Dkm_cti = ctiPhase.mix_diff_coeffs
|
|
Dkm_yaml = yamlPhase.mix_diff_coeffs
|
|
for i in range(ctiPhase.n_species):
|
|
message = 'dkm for species {0} at T = {1}'.format(i, T)
|
|
self.assertNear(Dkm_cti[i], Dkm_yaml[i], msg=message)
|
|
|
|
@utilities.slow_test
|
|
def test_gri30(self):
|
|
self.convert("gri30")
|
|
ctiPhase, yamlPhase = self.checkConversion('gri30')
|
|
X = {'O2': 0.3, 'H2': 0.1, 'CH4': 0.2, 'CO2': 0.4}
|
|
ctiPhase.X = X
|
|
yamlPhase.X = X
|
|
self.checkThermo(ctiPhase, yamlPhase, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctiPhase, yamlPhase, [900, 1800], [2e5, 20e5])
|
|
self.checkTransport(ctiPhase, yamlPhase, [298, 1001, 2400])
|
|
|
|
def test_pdep(self):
|
|
self.convert("pdep-test")
|
|
ctiPhase, yamlPhase = self.checkConversion('pdep-test')
|
|
# Agreement limited by low precision used by ck2cti for Chebyshev coeffs
|
|
self.checkKinetics(ctiPhase, yamlPhase, [300, 1000, 2200],
|
|
[100, ct.one_atm, 2e5, 2e6, 9.9e6], tol=2e-4)
|
|
|
|
def test_ptcombust(self):
|
|
self.convert("ptcombust")
|
|
ctiSurf, yamlSurf = self.checkConversion("ptcombust", ct.Interface,
|
|
name="Pt_surf")
|
|
yamlGas = yamlSurf.adjacent["gas"]
|
|
ctiGas = ctiSurf.adjacent["gas"]
|
|
|
|
self.checkKinetics(ctiGas, yamlGas, [500, 1200], [1e4, 3e5])
|
|
self.checkThermo(ctiSurf, yamlSurf, [400, 800, 1600])
|
|
self.checkKinetics(ctiSurf, yamlSurf, [500, 1200], [1e4, 3e5])
|
|
|
|
@utilities.slow_test
|
|
def test_ptcombust_motzwise(self):
|
|
self.convert("ptcombust-motzwise")
|
|
ctiSurf, yamlSurf = self.checkConversion("ptcombust-motzwise", ct.Interface,
|
|
name="Pt_surf")
|
|
yamlGas = yamlSurf.adjacent["gas"]
|
|
ctiGas = ctiSurf.adjacent["gas"]
|
|
|
|
self.checkKinetics(ctiGas, yamlGas, [500, 1200], [1e4, 3e5])
|
|
self.checkThermo(ctiSurf, yamlSurf, [400, 800, 1600])
|
|
self.checkKinetics(ctiSurf, yamlSurf, [900], [101325])
|
|
|
|
def test_sofc(self):
|
|
self.convert("sofc")
|
|
cti_tpb, yaml_tpb = self.checkConversion("sofc", ct.Interface, name="tpb")
|
|
ctiMetal, ctiMSurf, ctiOSurf = cti_tpb.adjacent.values()
|
|
yamlMetal, yamlMSurf, yamlOSurf = yaml_tpb.adjacent.values()
|
|
|
|
self.assertIn("oxide_bulk", ctiOSurf.adjacent)
|
|
self.assertIn("gas", ctiOSurf.adjacent)
|
|
|
|
self.checkThermo(ctiMSurf, yamlMSurf, [900, 1000, 1100])
|
|
self.checkThermo(ctiOSurf, yamlOSurf, [900, 1000, 1100])
|
|
ctiMetal.electric_potential = yamlMetal.electric_potential = 2
|
|
self.checkKinetics(cti_tpb, yaml_tpb, [900, 1000, 1100], [1e5])
|
|
ctiMetal.electric_potential = yamlMetal.electric_potential = 4
|
|
self.checkKinetics(cti_tpb, yaml_tpb, [900, 1000, 1100], [1e5])
|
|
|
|
@utilities.slow_test
|
|
def test_liquidvapor(self):
|
|
self.convert("liquidvapor")
|
|
for name in ["water", "nitrogen", "methane", "hydrogen", "oxygen", "heptane"]:
|
|
ctiPhase, yamlPhase = self.checkConversion("liquidvapor", name=name)
|
|
self.checkThermo(ctiPhase, yamlPhase,
|
|
[1.3 * ctiPhase.min_temp, 0.7 * ctiPhase.max_temp])
|
|
|
|
def test_Redlich_Kwong_CO2(self):
|
|
self.convert("co2_RK_example")
|
|
ctiGas, yamlGas = self.checkConversion('co2_RK_example')
|
|
for P in [1e5, 2e6, 1.3e7]:
|
|
yamlGas.TP = ctiGas.TP = 300, P
|
|
self.checkThermo(ctiGas, yamlGas, [300, 400, 500], check_cp=False)
|
|
|
|
def test_diamond(self):
|
|
self.convert("diamond")
|
|
ctiSurf, yamlSurf = self.checkConversion("diamond", ct.Interface,
|
|
name="diamond_100")
|
|
ctiSolid = ctiSurf.adjacent["diamond"]
|
|
yamlSolid = yamlSurf.adjacent["diamond"]
|
|
self.checkThermo(ctiSolid, yamlSolid, [300, 500])
|
|
self.checkThermo(ctiSurf, yamlSurf, [330, 490])
|
|
self.checkKinetics(ctiSurf, yamlSurf, [400, 800], [2e5])
|
|
|
|
def test_lithium_ion_battery(self):
|
|
name = 'lithium_ion_battery'
|
|
self.convert(name, encoding="utf-8")
|
|
ctiAnode, yamlAnode = self.checkConversion(name, name='anode')
|
|
ctiCathode, yamlCathode = self.checkConversion(name, name='cathode')
|
|
ctiMetal, yamlMetal = self.checkConversion(name, name='electron')
|
|
ctiElyt, yamlElyt = self.checkConversion(name, name='electrolyte')
|
|
ctiAnodeInt, yamlAnodeInt = self.checkConversion(name,
|
|
name='edge_anode_electrolyte',
|
|
ctiphases=[ctiAnode, ctiMetal, ctiElyt],
|
|
yamlphases=[yamlAnode, yamlMetal, yamlElyt])
|
|
ctiCathodeInt, yamlCathodeInt = self.checkConversion(name,
|
|
name='edge_cathode_electrolyte',
|
|
ctiphases=[ctiCathode, ctiMetal, ctiElyt],
|
|
yamlphases=[yamlCathode, yamlMetal, yamlElyt])
|
|
|
|
self.checkThermo(ctiAnode, yamlAnode, [300, 330])
|
|
self.checkThermo(ctiCathode, yamlCathode, [300, 330])
|
|
|
|
ctiAnode.X = yamlAnode.X = [0.7, 0.3]
|
|
self.checkThermo(ctiAnode, yamlAnode, [300, 330])
|
|
ctiCathode.X = yamlCathode.X = [0.2, 0.8]
|
|
self.checkThermo(ctiCathode, yamlCathode, [300, 330])
|
|
|
|
for phase in [ctiAnode, yamlAnode, ctiCathode, yamlCathode, ctiMetal,
|
|
yamlMetal, ctiElyt, yamlElyt, ctiAnodeInt, yamlAnodeInt,
|
|
ctiCathodeInt, yamlCathodeInt]:
|
|
phase.TP = 300, 1e5
|
|
ctiMetal.electric_potential = yamlMetal.electric_potential = 0
|
|
ctiElyt.electric_potential = yamlElyt.electric_potential = 1.9
|
|
self.checkKinetics(ctiAnodeInt, yamlAnodeInt, [300], [1e5])
|
|
|
|
ctiMetal.electric_potential = yamlMetal.electric_potential = 2.2
|
|
ctiElyt.electric_potential = yamlElyt.electric_potential = 0
|
|
self.checkKinetics(ctiCathodeInt, yamlCathodeInt, [300], [1e5])
|
|
|
|
def test_ch4_ion(self):
|
|
self.convert("ch4_ion")
|
|
ctiGas, yamlGas = self.checkConversion("ch4_ion")
|
|
self.checkThermo(ctiGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctiGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
self.checkTransport(ctiGas, yamlGas, [298, 1001, 2400])
|
|
|
|
def test_description(self):
|
|
self.convert("haca2")
|
|
ctiGas, yamlGas = self.checkConversion("haca2")
|
|
assert ctiGas.input_header["description"].startswith("HACA Mechanism")
|
|
assert yamlGas.input_header["description"].startswith("HACA Mechanism")
|
|
|
|
def test_nonreactant_orders(self):
|
|
self.convert("reaction-orders")
|
|
ctiGas, yamlGas = self.checkConversion("reaction-orders")
|
|
assert ctiGas.input_header["description"].startswith("Input file to test")
|
|
self.checkThermo(ctiGas, yamlGas, [300, 500])
|
|
self.checkKinetics(ctiGas, yamlGas, [300, 1001, 2500], [1e5, 10e5])
|
|
|
|
|
|
class ctml2yamlTest(utilities.CanteraTest):
|
|
def convert(self, basename, src_dir=None):
|
|
if src_dir is None:
|
|
src_dir = self.test_data_path
|
|
|
|
ctml2yaml.convert(
|
|
Path(src_dir) / f"{basename}.xml",
|
|
self.test_work_path / f"{basename}-from-xml.yaml",
|
|
)
|
|
|
|
def checkConversion(self, basename, cls=ct.Solution, ctmlphases=(),
|
|
yamlphases=(), **kwargs):
|
|
ctmlPhase = cls(f"{basename}-from-xml.yaml", adjacent=ctmlphases, **kwargs)
|
|
yamlPhase = cls(f"{basename}.yaml", adjacent=yamlphases, **kwargs)
|
|
|
|
self.assertEqual(ctmlPhase.element_names, yamlPhase.element_names)
|
|
self.assertEqual(ctmlPhase.species_names, yamlPhase.species_names)
|
|
self.assertEqual(ctmlPhase.n_reactions, yamlPhase.n_reactions)
|
|
for C, Y in zip(ctmlPhase.species(), yamlPhase.species()):
|
|
self.assertEqual(C.composition, Y.composition)
|
|
|
|
for C, Y in zip(ctmlPhase.reactions(), yamlPhase.reactions()):
|
|
self.assertEqual(C.__class__, Y.__class__)
|
|
self.assertEqual(C.reactants, Y.reactants)
|
|
self.assertEqual(C.products, Y.products)
|
|
self.assertEqual(C.duplicate, Y.duplicate)
|
|
|
|
for i, sp in zip(range(ctmlPhase.n_reactions), ctmlPhase.kinetics_species_names):
|
|
self.assertEqual(ctmlPhase.reactant_stoich_coeff(sp, i),
|
|
yamlPhase.reactant_stoich_coeff(sp, i))
|
|
|
|
return ctmlPhase, yamlPhase
|
|
|
|
def checkThermo(self, ctmlPhase, yamlPhase, temperatures, pressure=ct.one_atm,
|
|
tol=1e-7, check_cp=True):
|
|
for T in temperatures:
|
|
ctmlPhase.TP = T, pressure
|
|
yamlPhase.TP = T, pressure
|
|
if check_cp:
|
|
cp_ctml = ctmlPhase.partial_molar_cp
|
|
cp_yaml = yamlPhase.partial_molar_cp
|
|
else:
|
|
with pytest.raises(NotImplementedError):
|
|
yamlPhase.partial_molar_cp
|
|
h_ctml = ctmlPhase.partial_molar_enthalpies
|
|
h_yaml = yamlPhase.partial_molar_enthalpies
|
|
s_ctml = ctmlPhase.partial_molar_entropies
|
|
s_yaml = yamlPhase.partial_molar_entropies
|
|
self.assertNear(ctmlPhase.density, yamlPhase.density)
|
|
for i in range(ctmlPhase.n_species):
|
|
message = ' for species {0} at T = {1}'.format(ctmlPhase.species_names[i], T)
|
|
if check_cp:
|
|
self.assertNear(cp_ctml[i], cp_yaml[i], tol, msg='cp'+message)
|
|
self.assertNear(h_ctml[i], h_yaml[i], tol, msg='h'+message)
|
|
self.assertNear(s_ctml[i], s_yaml[i], tol, msg='s'+message)
|
|
|
|
def checkKinetics(self, ctmlPhase, yamlPhase, temperatures, pressures, tol=1e-7):
|
|
for T,P in itertools.product(temperatures, pressures):
|
|
ctmlPhase.TP = T, P
|
|
yamlPhase.TP = T, P
|
|
kf_ctml = ctmlPhase.forward_rate_constants
|
|
kr_ctml = ctmlPhase.reverse_rate_constants
|
|
kf_yaml = yamlPhase.forward_rate_constants
|
|
kr_yaml = yamlPhase.reverse_rate_constants
|
|
for i in range(yamlPhase.n_reactions):
|
|
message = ' for reaction {0} at T = {1}, P = {2}'.format(i, T, P)
|
|
self.assertNear(kf_ctml[i], kf_yaml[i], rtol=tol, msg='kf '+message)
|
|
self.assertNear(kr_ctml[i], kr_yaml[i], rtol=tol, msg='kr '+message)
|
|
|
|
def checkTransport(self, ctmlPhase, yamlPhase, temperatures,
|
|
model='mixture-averaged'):
|
|
ctmlPhase.transport_model = model
|
|
yamlPhase.transport_model = model
|
|
for T in temperatures:
|
|
ctmlPhase.TP = T, ct.one_atm
|
|
yamlPhase.TP = T, ct.one_atm
|
|
self.assertNear(ctmlPhase.viscosity, yamlPhase.viscosity)
|
|
self.assertNear(ctmlPhase.thermal_conductivity,
|
|
yamlPhase.thermal_conductivity)
|
|
Dkm_ctml = ctmlPhase.mix_diff_coeffs
|
|
Dkm_yaml = yamlPhase.mix_diff_coeffs
|
|
for i in range(ctmlPhase.n_species):
|
|
message = 'dkm for species {0} at T = {1}'.format(i, T)
|
|
self.assertNear(Dkm_ctml[i], Dkm_yaml[i], msg=message)
|
|
|
|
@utilities.slow_test
|
|
def test_gri30(self):
|
|
self.convert("gri30")
|
|
ctmlPhase, yamlPhase = self.checkConversion('gri30')
|
|
X = {'O2': 0.3, 'H2': 0.1, 'CH4': 0.2, 'CO2': 0.4}
|
|
ctmlPhase.X = X
|
|
yamlPhase.X = X
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlPhase, yamlPhase, [900, 1800], [2e5, 20e5])
|
|
self.checkTransport(ctmlPhase, yamlPhase, [298, 1001, 2400])
|
|
|
|
def test_pdep(self):
|
|
self.convert("pdep-test")
|
|
ctmlPhase, yamlPhase = self.checkConversion('pdep-test')
|
|
# Chebyshev coefficients in XML are truncated to 6 digits, limiting accuracy
|
|
self.checkKinetics(ctmlPhase, yamlPhase, [300, 1000, 2200],
|
|
[100, ct.one_atm, 2e5, 2e6, 9.9e6], tol=2e-4)
|
|
|
|
def test_ptcombust(self):
|
|
self.convert("ptcombust")
|
|
ctmlSurf, yamlSurf = self.checkConversion("ptcombust", ct.Interface,
|
|
name="Pt_surf")
|
|
ctmlGas = ctmlSurf.adjacent["gas"]
|
|
yamlGas = yamlSurf.adjacent["gas"]
|
|
|
|
self.checkKinetics(ctmlGas, yamlGas, [500, 1200], [1e4, 3e5])
|
|
self.checkThermo(ctmlSurf, yamlSurf, [400, 800, 1600])
|
|
self.checkKinetics(ctmlSurf, yamlSurf, [500, 1200], [1e4, 3e5])
|
|
|
|
def test_ptcombust_motzwise(self):
|
|
self.convert("ptcombust-motzwise")
|
|
ctmlGas, yamlGas = self.checkConversion('ptcombust-motzwise')
|
|
ctmlSurf, yamlSurf = self.checkConversion('ptcombust-motzwise', ct.Interface,
|
|
name='Pt_surf', ctmlphases=[ctmlGas], yamlphases=[yamlGas])
|
|
|
|
self.checkKinetics(ctmlGas, yamlGas, [500, 1200], [1e4, 3e5])
|
|
self.checkThermo(ctmlSurf, yamlSurf, [400, 800, 1600])
|
|
self.checkKinetics(ctmlSurf, yamlSurf, [500, 1200], [1e4, 3e5])
|
|
|
|
def test_sofc(self):
|
|
self.convert("sofc")
|
|
ctml_tpb, yaml_tpb = self.checkConversion("sofc", ct.Interface, name="tpb")
|
|
ctmlMetal, ctmlMSurf, ctmlOSurf = ctml_tpb.adjacent.values()
|
|
yamlMetal, yamlMSurf, yamlOSurf = yaml_tpb.adjacent.values()
|
|
|
|
self.assertIn("oxide_bulk", ctmlOSurf.adjacent)
|
|
self.assertIn("gas", ctmlOSurf.adjacent)
|
|
|
|
self.checkThermo(ctmlMSurf, yamlMSurf, [900, 1000, 1100])
|
|
self.checkThermo(ctmlOSurf, yamlOSurf, [900, 1000, 1100])
|
|
ctmlMetal.electric_potential = yamlMetal.electric_potential = 2
|
|
self.checkKinetics(ctml_tpb, yaml_tpb, [900, 1000, 1100], [1e5])
|
|
ctmlMetal.electric_potential = yamlMetal.electric_potential = 4
|
|
self.checkKinetics(ctml_tpb, yaml_tpb, [900, 1000, 1100], [1e5])
|
|
|
|
def test_liquidvapor(self):
|
|
self.convert("liquidvapor")
|
|
for name in ["water", "nitrogen", "methane", "hydrogen", "oxygen", "heptane"]:
|
|
ctmlPhase, yamlPhase = self.checkConversion("liquidvapor", name=name)
|
|
self.checkThermo(ctmlPhase, yamlPhase,
|
|
[1.3 * ctmlPhase.min_temp, 0.7 * ctmlPhase.max_temp])
|
|
|
|
def test_Redlich_Kwong_CO2(self):
|
|
self.convert("co2_RK_example")
|
|
ctmlGas, yamlGas = self.checkConversion('co2_RK_example')
|
|
for P in [1e5, 2e6, 1.3e7]:
|
|
yamlGas.TP = ctmlGas.TP = 300, P
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 400, 500], check_cp=False)
|
|
|
|
def test_diamond(self):
|
|
self.convert("diamond")
|
|
ctmlGas, yamlGas = self.checkConversion('diamond', name='gas')
|
|
ctmlSolid, yamlSolid = self.checkConversion('diamond', name='diamond')
|
|
ctmlSurf, yamlSurf = self.checkConversion('diamond',
|
|
ct.Interface, name='diamond_100', ctmlphases=[ctmlGas, ctmlSolid],
|
|
yamlphases=[yamlGas, yamlSolid])
|
|
self.checkThermo(ctmlSolid, yamlSolid, [300, 500])
|
|
self.checkThermo(ctmlSurf, yamlSurf, [330, 490])
|
|
self.checkKinetics(ctmlSurf, yamlSurf, [400, 800], [2e5])
|
|
|
|
def test_lithium_ion_battery(self):
|
|
name = 'lithium_ion_battery'
|
|
self.convert(name)
|
|
ctmlAnode, yamlAnode = self.checkConversion(name, name='anode')
|
|
ctmlCathode, yamlCathode = self.checkConversion(name, name='cathode')
|
|
ctmlMetal, yamlMetal = self.checkConversion(name, name='electron')
|
|
ctmlElyt, yamlElyt = self.checkConversion(name, name='electrolyte')
|
|
ctmlAnodeInt, yamlAnodeInt = self.checkConversion(name,
|
|
name='edge_anode_electrolyte',
|
|
ctmlphases=[ctmlAnode, ctmlMetal, ctmlElyt],
|
|
yamlphases=[yamlAnode, yamlMetal, yamlElyt])
|
|
ctmlCathodeInt, yamlCathodeInt = self.checkConversion(name,
|
|
name='edge_cathode_electrolyte',
|
|
ctmlphases=[ctmlCathode, ctmlMetal, ctmlElyt],
|
|
yamlphases=[yamlCathode, yamlMetal, yamlElyt])
|
|
|
|
self.checkThermo(ctmlAnode, yamlAnode, [300, 330])
|
|
self.checkThermo(ctmlCathode, yamlCathode, [300, 330])
|
|
|
|
ctmlAnode.X = yamlAnode.X = [0.7, 0.3]
|
|
self.checkThermo(ctmlAnode, yamlAnode, [300, 330])
|
|
ctmlCathode.X = yamlCathode.X = [0.2, 0.8]
|
|
self.checkThermo(ctmlCathode, yamlCathode, [300, 330])
|
|
|
|
for phase in [ctmlAnode, yamlAnode, ctmlCathode, yamlCathode, ctmlMetal,
|
|
yamlMetal, ctmlElyt, yamlElyt, ctmlAnodeInt, yamlAnodeInt,
|
|
ctmlCathodeInt, yamlCathodeInt]:
|
|
phase.TP = 300, 1e5
|
|
ctmlMetal.electric_potential = yamlMetal.electric_potential = 0
|
|
ctmlElyt.electric_potential = yamlElyt.electric_potential = 1.9
|
|
self.checkKinetics(ctmlAnodeInt, yamlAnodeInt, [300], [1e5])
|
|
|
|
ctmlMetal.electric_potential = yamlMetal.electric_potential = 2.2
|
|
ctmlElyt.electric_potential = yamlElyt.electric_potential = 0
|
|
self.checkKinetics(ctmlCathodeInt, yamlCathodeInt, [300], [1e5])
|
|
|
|
def test_noxNeg(self):
|
|
self.convert("noxNeg")
|
|
ctmlGas, yamlGas = self.checkConversion('noxNeg')
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 1000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [300, 1000], [1e5])
|
|
|
|
def test_ch4_ion(self):
|
|
self.convert("ch4_ion")
|
|
ctmlGas, yamlGas = self.checkConversion("ch4_ion")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
self.checkTransport(ctmlGas, yamlGas, [298, 1001, 2400])
|
|
|
|
def test_nasa9(self):
|
|
self.convert("nasa9-test")
|
|
ctmlGas, yamlGas = self.checkConversion("nasa9-test")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
|
|
def test_chemically_activated(self):
|
|
self.convert("chemically-activated-reaction")
|
|
ctmlGas, yamlGas = self.checkConversion("chemically-activated-reaction")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
|
|
def test_explicit_forward_order(self):
|
|
self.convert("explicit-forward-order")
|
|
ctmlGas, yamlGas = self.checkConversion("explicit-forward-order")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
# Accuracy limited by precision of ck2cti
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5], tol=2e-7)
|
|
|
|
def test_explicit_reverse_rate(self):
|
|
self.convert("explicit-reverse-rate")
|
|
ctmlGas, yamlGas = self.checkConversion("explicit-reverse-rate")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
|
|
def test_explicit_third_bodies(self):
|
|
self.convert("explicit-third-bodies")
|
|
ctmlGas, yamlGas = self.checkConversion("explicit-third-bodies")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
|
|
def test_fractional_stoich_coeffs(self):
|
|
self.convert("frac")
|
|
ctmlGas, yamlGas = self.checkConversion("frac")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
|
|
def test_water_IAPWS95_thermo(self):
|
|
self.convert("liquid-water")
|
|
ctmlWater, yamlWater = self.checkConversion("liquid-water")
|
|
self.checkThermo(ctmlWater, yamlWater, [300, 500, 1300, 2000], pressure=22064000.0)
|
|
self.assertEqual(ctmlWater.transport_model, yamlWater.transport_model)
|
|
ctmlWater.TP = yamlWater.TP = 300, 22064000.0
|
|
dens = ctmlWater.density
|
|
for T in [298, 1001, 2400]:
|
|
ctmlWater.TD = T, dens
|
|
yamlWater.TD = T, dens
|
|
self.assertNear(ctmlWater.viscosity, yamlWater.viscosity)
|
|
self.assertNear(ctmlWater.thermal_conductivity,
|
|
yamlWater.thermal_conductivity)
|
|
|
|
def test_hmw_nacl_phase(self):
|
|
basename = "HMW_NaCl_sp1977_alt"
|
|
self.convert(basename)
|
|
ctmlPhase, yamlPhase = self.checkConversion(basename)
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_NaCl_solid_phase(self):
|
|
self.convert("NaCl_Solid")
|
|
ctmlPhase, yamlPhase = self.checkConversion("NaCl_Solid")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500, 1300, 2000])
|
|
|
|
def test_DH_NaCl_phase(self):
|
|
self.convert("debye-huckel-all")
|
|
for name in [
|
|
"debye-huckel-dilute",
|
|
"debye-huckel-B-dot-ak",
|
|
"debye-huckel-B-dot-a",
|
|
"debye-huckel-pitzer-beta_ij",
|
|
"debye-huckel-beta_ij",
|
|
]:
|
|
ctmlPhase, yamlPhase = self.checkConversion("debye-huckel-all", name=name)
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_Redlich_Kister(self):
|
|
self.convert("RedlichKisterVPSSTP_valid")
|
|
ctmlPhase, yamlPhase = self.checkConversion("RedlichKisterVPSSTP_valid")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_species_names(self):
|
|
self.convert("species-names")
|
|
ctmlGas, yamlGas = self.checkConversion('species-names')
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
|
|
def test_sri_falloff_reaction(self):
|
|
self.convert("sri-falloff")
|
|
ctmlGas, yamlGas = self.checkConversion("sri-falloff")
|
|
self.checkThermo(ctmlGas, yamlGas, [300, 500, 1300, 2000])
|
|
self.checkKinetics(ctmlGas, yamlGas, [900, 1800], [2e5, 20e5])
|
|
|
|
def test_vpss_and_hkft(self):
|
|
self.convert("pdss_hkft")
|
|
ctmlPhase, yamlPhase = self.checkConversion("pdss_hkft")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_lattice_solid(self):
|
|
self.convert("Li7Si3_ls")
|
|
ctmlPhase, yamlPhase = self.checkConversion("Li7Si3_ls",
|
|
name="Li7Si3_and_Interstitials(S)")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_margules(self):
|
|
self.convert("LiKCl_liquid")
|
|
ctmlPhase, yamlPhase = self.checkConversion("LiKCl_liquid")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_idealsolidsoln(self):
|
|
with self.assertWarnsRegex(UserWarning, "SolidKinetics type is not implemented"):
|
|
self.convert("IdealSolidSolnPhaseExample")
|
|
|
|
# SolidKinetics is not implemented, so can't create a Kinetics class instance.
|
|
basename = "IdealSolidSolnPhaseExample"
|
|
ctmlPhase = ct.ThermoPhase(basename + "-from-xml.yaml")
|
|
yamlPhase = ct.ThermoPhase(basename + ".yaml")
|
|
|
|
self.assertEqual(ctmlPhase.element_names, yamlPhase.element_names)
|
|
self.assertEqual(ctmlPhase.species_names, yamlPhase.species_names)
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_idealmolalsoln(self):
|
|
self.convert("IdealMolalSolnPhaseExample")
|
|
ctmlPhase, yamlPhase = self.checkConversion("IdealMolalSolnPhaseExample")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_transport_models(self):
|
|
self.convert("transport_models_test")
|
|
for name in ["UnityLewis", "CK_Mix", "CK_Multi", "HighP"]:
|
|
ctmlPhase, yamlPhase = self.checkConversion("transport_models_test", name=name)
|
|
self.checkTransport(ctmlPhase, yamlPhase, [298, 1001, 2500])
|
|
|
|
def test_nonreactant_orders(self):
|
|
self.convert("reaction-orders")
|
|
ctmlPhase, yamlPhase = self.checkConversion("reaction-orders")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
self.checkKinetics(ctmlPhase, yamlPhase, [300, 1001, 2500], [1e5, 10e5])
|
|
|
|
def test_species_ss_temperature_polynomials(self):
|
|
self.convert("Li_Liquid")
|
|
ctmlPhase, yamlPhase = self.checkConversion("Li_Liquid")
|
|
self.checkThermo(ctmlPhase, yamlPhase, [300, 500])
|
|
|
|
def test_duplicate_section_ids(self):
|
|
with self.assertWarnsRegex(UserWarning, "Duplicate 'speciesData' id"):
|
|
self.convert("duplicate-speciesData-ids")
|
|
with self.assertWarnsRegex(UserWarning, "Duplicate 'reactionData' id"):
|
|
self.convert("duplicate-reactionData-ids")
|