Skip to content

Commit

Permalink
[Input] Add test of mechanism validation when using ck2yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
speth committed Jun 18, 2020
1 parent 1253997 commit 22f7f69
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 33 deletions.
77 changes: 44 additions & 33 deletions interfaces/cython/cantera/ck2yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@

BlockMap = yaml.comments.CommentedMap

logger = logging.getLogger(__name__)
loghandler = logging.StreamHandler(sys.stdout)
logformatter = logging.Formatter('%(message)s')
loghandler.setFormatter(logformatter)
logger.handlers.clear()
logger.addHandler(loghandler)
logger.setLevel(logging.INFO)

def FlowMap(*args, **kwargs):
m = yaml.comments.CommentedMap(*args, **kwargs)
m.fa.set_flow_style()
Expand Down Expand Up @@ -757,7 +765,7 @@ def warn(self, message):
if self.warning_as_error:
raise InputError(message)
else:
logging.warning(message)
logger.warning(message)

@staticmethod
def parse_composition(elements, nElements, width):
Expand Down Expand Up @@ -1562,7 +1570,7 @@ def readline():
entry = []
if label not in self.species_dict:
if skip_undeclared_species:
logging.info('Skipping unexpected species "{0}" while reading thermodynamics entry.'.format(label))
logger.info('Skipping unexpected species "{0}" while reading thermodynamics entry.'.format(label))
continue
else:
# Add a new species entry
Expand Down Expand Up @@ -1612,15 +1620,17 @@ def readline():
except Exception as e:
error_line_number = self.line_number - len(current) + 1
error_entry = ''.join(current).rstrip()
logging.info(
logger.info(
'Error while reading thermo entry starting on line {0}:\n'
'"""\n{1}\n"""'.format(error_line_number, error_entry)
)
raise

if label not in self.species_dict:
if skip_undeclared_species:
logging.info('Skipping unexpected species "{0}" while reading thermodynamics entry.'.format(label))
logger.info(
'Skipping unexpected species "{0}" while'
' reading thermodynamics entry.'.format(label))
thermo = []
line, comment = readline()
current = []
Expand Down Expand Up @@ -1740,7 +1750,7 @@ def readline():
reaction, revReaction = self.read_kinetics_entry(kinetics, surface)
except Exception as e:
self.line_number = line_number
logging.info('Error reading reaction starting on '
logger.info('Error reading reaction starting on '
'line {0}:\n"""\n{1}\n"""'.format(
line_number, kinetics.rstrip()))
raise
Expand Down Expand Up @@ -1970,9 +1980,9 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,

parser = Parser()
if quiet:
logging.basicConfig(level=logging.ERROR)
logger.setLevel(level=logging.ERROR)
else:
logging.basicConfig(level=logging.INFO)
logger.setLevel(level=logging.INFO)

if permissive is not None:
parser.warning_as_error = not permissive
Expand All @@ -1986,7 +1996,7 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
# Read input mechanism files
parser.load_chemkin_file(input_file)
except Exception as err:
logging.warning("\nERROR: Unable to parse '{0}' near line {1}:\n{2}\n".format(
logger.warning("\nERROR: Unable to parse '{0}' near line {1}:\n{2}\n".format(
input_file, parser.line_number, err))
raise
else:
Expand All @@ -2001,8 +2011,8 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
parser.load_chemkin_file(thermo_file,
skip_undeclared_species=bool(input_file))
except Exception:
logging.warning("\nERROR: Unable to parse '{0}' near line {1}:\n".format(
thermo_file, parser.line_number))
logger.warning("\nERROR: Unable to parse '{0}' near line {1}:\n".format(
thermo_file, parser.line_number))
raise

if transport_file:
Expand All @@ -2028,8 +2038,8 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
# Read input mechanism files
parser.load_chemkin_file(surface_file, surface=True)
except Exception as err:
logging.warning("\nERROR: Unable to parse '{0}' near line {1}:\n{2}\n".format(
surface_file, parser.line_number, err))
logger.warning("\nERROR: Unable to parse '{0}' near line {1}:\n{2}\n".format(
surface_file, parser.line_number, err))
raise

if extra_file:
Expand All @@ -2041,8 +2051,8 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
# Read input mechanism files
parser.load_extra_file(extra_file)
except Exception as err:
logging.warning("\nERROR: Unable to parse '{0}':\n{1}\n".format(
extra_file, err))
logger.warning("\nERROR: Unable to parse '{0}':\n{1}\n".format(
extra_file, err))
raise

if out_name:
Expand All @@ -2054,8 +2064,9 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
surface_names = parser.write_yaml(name=phase_name, out_name=out_name)
if not quiet:
nReactions = len(parser.reactions) + sum(len(surf.reactions) for surf in parser.surfaces)
print('Wrote YAML mechanism file to {0!r}.'.format(out_name))
print('Mechanism contains {0} species and {1} reactions.'.format(len(parser.species_list), nReactions))
logger.info('Wrote YAML mechanism file to {0!r}.'.format(out_name))
logger.info('Mechanism contains {0} species and {1} reactions.'.format(
len(parser.species_list), nReactions))
return parser, surface_names

def show_duplicate_reactions(self, error_message):
Expand All @@ -2066,13 +2077,13 @@ def show_duplicate_reactions(self, error_message):
reactions.append(int(match.group(1))-1)

if len(reactions) != 2:
print(error_message)
logger.warning(error_message)
return

equation = str(self.reactions[0])
lines = [self.reactions[i].line_number for i in reactions]
print('Undeclared duplicate reaction {}\nfound on lines {} and {} of '
' the kinetics input file.'.format(equation, lines[0], lines[1]))
logger.warning('Undeclared duplicate reaction {}\nfound on lines {} and {} of '
'the kinetics input file.'.format(equation, lines[0], lines[1]))


def convert_mech(input_file, thermo_file=None, transport_file=None,
Expand Down Expand Up @@ -2101,13 +2112,13 @@ def main(argv):
repr(' '.join(args)))

except getopt.GetoptError as e:
print('ck2yaml.py: Error parsing arguments:')
print(e)
print('Run "ck2yaml.py --help" to see usage help.')
logger.error('ck2yaml.py: Error parsing arguments:')
logger.error(e)
logger.error('Run "ck2yaml.py --help" to see usage help.')
sys.exit(1)

if not options or '-h' in options or '--help' in options:
print(__doc__)
logger.info(__doc__)
sys.exit(0)

input_file = options.get('--input')
Expand All @@ -2119,14 +2130,14 @@ def main(argv):

if '--id' in options:
phase_name = options.get('--id', 'gas')
logging.warning("\nFutureWarning: "
"Option '--id=...' will be replaced by '--name=...'")
logger.warning("\nFutureWarning: "
"Option '--id=...' will be replaced by '--name=...'")
else:
phase_name = options.get('--name', 'gas')

if not input_file and not thermo_file:
print('At least one of the arguments "--input=..." or "--thermo=..."'
' must be provided.\nRun "ck2yaml.py --help" to see usage help.')
logger.error('At least one of the arguments "--input=..." or "--thermo=..."'
' must be provided.\nRun "ck2yaml.py --help" to see usage help.')
sys.exit(1)

extra_file = options.get('--extra')
Expand Down Expand Up @@ -2155,23 +2166,23 @@ def main(argv):
try:
import cantera as ct
except ImportError:
print('WARNING: Unable to import Cantera Python module. Output '
'mechanism has not been validated')
logger.warning('WARNING: Unable to import Cantera Python module. '
'Output mechanism has not been validated')
sys.exit(0)

try:
print('Validating mechanism...', end='')
logger.info('Validating mechanism...')
gas = ct.Solution(out_name)
for surf_name in surfaces:
phase = ct.Interface(out_name, surf_name, [gas])
print('PASSED.')
logger.info('PASSED')
except RuntimeError as e:
print('FAILED.')
logger.info('FAILED')
msg = str(e)
if ('Undeclared duplicate reactions' in msg):
parser.show_duplicate_reactions(msg)
else:
print(e)
logger.warning(e)
sys.exit(1)


Expand Down
25 changes: 25 additions & 0 deletions interfaces/cython/cantera/test/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
from os.path import join as pjoin
import itertools
from pathlib import Path
import logging
import io
import sys

from . import utilities
import cantera as ct
Expand Down Expand Up @@ -467,6 +470,28 @@ def test_extra(self):
for key in ['foo', 'bar']:
self.assertIn(key, yml.keys())

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.

# clear global handler created by logging.basicConfig() in ck2cti
logging.getLogger().handlers.clear()

log_stream = io.StringIO()
logger = logging.getLogger('cantera.ck2yaml')
logger.handlers[0].setStream(log_stream)

with self.assertRaises(SystemExit):
ck2yaml.main([
'--input={}/undeclared-duplicate-reactions.inp'.format(self.test_data_dir),
'--thermo={}/dummy-thermo.dat'.format(self.test_data_dir)])

logger.handlers[0].setStream(sys.stdout)
message = log_stream.getvalue()
self.assertIn('FAILED', message)
self.assertIn('lines 11 and 13', message)


class CtmlConverterTest(utilities.CanteraTest):
def test_sofc(self):
Expand Down
14 changes: 14 additions & 0 deletions test/data/undeclared-duplicate-reactions.inp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ELEMENTS
H C
END

SPECIES
H
R1A R1B P1 R3 P3A P3B
END

REACTIONS
R1A+R1B <=> P1+H 1.0e19 0.0 5000.0
R1A+R1B+M <=> P1+H+M 1.0e-2 0.0 5000.0
P1+H => R1A+R1B 1.0e19 0.0 5000.0
END

0 comments on commit 22f7f69

Please sign in to comment.