Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --extra option to ck2yaml #794

Merged
merged 5 commits into from
Feb 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 79 additions & 13 deletions interfaces/cython/cantera/ck2yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
[--transport=<filename>]
[--surface=<filename>]
[--name=<name>]
[--extra=<filename>]
[--output=<filename>]
[--permissive]
[--quiet]
[--no-validate]
[-d | --debug]

Example:
Expand All @@ -34,6 +37,10 @@
The '--permissive' option allows certain recoverable parsing errors (e.g.
duplicate transport data) to be ignored. The '--name=<name>' option
is used to override default phase names (i.e. 'gas').

The '--extra=<filename>' option takes a YAML file as input. This option can be
used to add to the file description, or to define custom fields that are
included in the YAML output.
"""

from collections import defaultdict, OrderedDict
Expand Down Expand Up @@ -742,7 +749,8 @@ def __init__(self):
self.species_dict = {} # bulk and surface species
self.surfaces = []
self.reactions = []
self.headerLines = []
self.header_lines = []
self.extra = {} # for extra entries
self.files = [] # input file names

def warn(self, message):
Expand Down Expand Up @@ -1328,6 +1336,35 @@ def parse_expression(expression, dest):

return reaction, revReaction

def load_extra_file(self, path):
"""
Load YAML-formatted entries from ``path`` on disk.
"""
with open(path, 'rt', encoding="utf-8") as stream:
yml = yaml.round_trip_load(stream)

# do not overwrite reserved field names
reserved = {'generator', 'input-files', 'cantera-version', 'date',
'units', 'phases', 'species', 'reactions'}
reserved &= set(yml.keys())
if reserved:
raise InputError("The YAML file '{}' provided as '--extra' input "
"must not redefine reserved field name: "
"'{}'".format(path, reserved))

# replace header lines
if 'description' in yml:
if isinstance(yml['description'], str):
if self.header_lines:
self.header_lines += ['']
self.header_lines += yml.pop('description').split('\n')
else:
raise InputError("The alternate description provided in "
"'{}' needs to be a string".format(path))

# remainder
self.extra = yml

def load_chemkin_file(self, path, skip_undeclared_species=True, surface=False):
"""
Load a Chemkin-format input file from ``path`` on disk.
Expand All @@ -1353,10 +1390,13 @@ def readline():
line, comment = readline()
advance = True
inHeader = True
header = []
indent = 80
while line is not None:
tokens = line.split() or ['']
if inHeader and not line.strip():
self.headerLines.append(comment.rstrip())
header.append(comment.rstrip())
indent = min(indent, re.search('[^ ]', comment).start())

if tokens[0].upper().startswith('ELEM'):
inHeader = False
Expand Down Expand Up @@ -1738,6 +1778,9 @@ def readline():
else:
advance = True

for h in header:
self.header_lines.append(h[indent:])

self.check_duplicate_reactions()

for index, reaction in enumerate(self.reactions):
Expand Down Expand Up @@ -1838,8 +1881,8 @@ def write_yaml(self, name='gas', out_name='mech.yaml'):
if surf.reactions:
n_reacting_phases += 1

# header from original file
desc = '\n'.join(line.rstrip() for line in self.headerLines)
# Write header lines
desc = '\n'.join(line.rstrip() for line in self.header_lines)
desc = desc.strip('\n')
desc = textwrap.dedent(desc)
if desc.strip():
Expand All @@ -1857,6 +1900,13 @@ def write_yaml(self, name='gas', out_name='mech.yaml'):
metadata.yaml_set_comment_before_after_key('generator', before='\n')
emitter.dump(metadata, dest)

# Write extra entries
if self.extra:
extra = BlockMap(self.extra)
key = list(self.extra.keys())[0]
extra.yaml_set_comment_before_after_key(key, before='\n')
emitter.dump(extra, dest)

units = FlowMap([('length', 'cm'), ('time', 's')])
units['quantity'] = self.output_quantity_units
units['activation-energy'] = self.output_energy_units
Expand Down Expand Up @@ -1946,8 +1996,8 @@ def write_yaml(self, name='gas', out_name='mech.yaml'):

@staticmethod
def convert_mech(input_file, thermo_file=None, transport_file=None,
surface_file=None, phase_name='gas', out_name=None,
quiet=False, permissive=None):
surface_file=None, phase_name='gas', extra_file=None,
out_name=None, quiet=False, permissive=None):

parser = Parser()
if quiet:
Expand Down Expand Up @@ -2013,6 +2063,19 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
surface_file, parser.line_number, err))
raise

if extra_file:
parser.files.append(extra_file)
extra_file = os.path.expanduser(extra_file)
if not os.path.exists(extra_file):
raise IOError('Missing input file: {0!r}'.format(extra_file))
try:
# 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))
raise

if out_name:
out_name = os.path.expanduser(out_name)
else:
Expand All @@ -2027,15 +2090,16 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
return surface_names


def convert_mech(input_file, thermo_file=None, transport_file=None, surface_file=None,
phase_name='gas', out_name=None, quiet=False, permissive=None):
def convert_mech(input_file, thermo_file=None, transport_file=None,
surface_file=None, phase_name='gas', extra_file=None,
out_name=None, quiet=False, permissive=None):
return Parser.convert_mech(input_file, thermo_file, transport_file, surface_file,
phase_name, out_name, quiet, permissive)
phase_name, extra_file, out_name, quiet, permissive)

def main(argv):

longOptions = ['input=', 'thermo=', 'transport=', 'surface=', 'name=',
'output=', 'permissive', 'help', 'debug', 'quiet',
'extra=', 'output=', 'permissive', 'help', 'debug', 'quiet',
'no-validate', 'id=']

try:
Expand Down Expand Up @@ -2068,7 +2132,7 @@ def main(argv):
if '--id' in options:
phase_name = options.get('--id', 'gas')
logging.warning("\nFutureWarning: "
"option '--id=...' is superseded by '--name=...'")
"Option '--id=...' will be replaced by '--name=...'")
else:
phase_name = options.get('--name', 'gas')

Expand All @@ -2077,6 +2141,8 @@ def main(argv):
' must be provided.\nRun "ck2yaml.py --help" to see usage help.')
sys.exit(1)

extra_file = options.get('--extra')

if '--output' in options:
out_name = options['--output']
if not out_name.endswith('.yaml') and not out_name.endswith('.yml'):
Expand All @@ -2087,8 +2153,8 @@ def main(argv):
out_name = os.path.splitext(thermo_file)[0] + '.yaml'

surfaces = Parser.convert_mech(input_file, thermo_file, transport_file,
surface_file, phase_name, out_name,
quiet, permissive)
surface_file, phase_name, extra_file,
out_name, quiet, permissive)

# Do full validation by importing the resulting mechanism
if not input_file:
Expand Down
9 changes: 9 additions & 0 deletions interfaces/cython/cantera/test/data/extra.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
description: |-
This is an alternative description.
foo:
- spam
- eggs

bar:
spam: eggs
37 changes: 30 additions & 7 deletions interfaces/cython/cantera/test/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@
import cantera as ct
from cantera import ck2cti, ck2yaml, cti2yaml, ctml2yaml

try:
import ruamel_yaml as yaml
except ImportError:
from ruamel import yaml


class converterTestCommon:
def convert(self, inputFile, thermo=None, transport=None,
surface=None, output=None, quiet=True, permissive=None):
surface=None, output=None, extra=None,
quiet=True, permissive=None):
if output is None:
output = inputFile[:-4] # strip '.inp'
if inputFile is not None:
Expand All @@ -21,11 +27,14 @@ def convert(self, inputFile, thermo=None, transport=None,
transport = pjoin(self.test_data_dir, transport)
if surface is not None:
surface = pjoin(self.test_data_dir, surface)
if extra is not None:
extra = pjoin(self.test_data_dir, extra)
output = pjoin(self.test_work_dir, output + self.ext)
if os.path.exists(output):
os.remove(output)
self._convert(inputFile, thermo=thermo, transport=transport,
surface=surface, output=output, quiet=quiet, permissive=permissive)
surface=surface, output=output, extra=extra,
quiet=quiet, permissive=permissive)

def checkConversion(self, refFile, testFile):
ref = ct.Solution(refFile)
Expand Down Expand Up @@ -415,8 +424,8 @@ class ck2ctiTest(converterTestCommon, utilities.CanteraTest):
ext = '.cti'
InputError = ck2cti.InputParseError

def _convert(self, inputFile, *, thermo, transport, surface, output, quiet,
permissive):
def _convert(self, inputFile, *, thermo, transport, surface, output, extra,
quiet, permissive):
ck2cti.convertMech(inputFile, thermoFile=thermo,
transportFile=transport, surfaceFile=surface, outName=output,
quiet=quiet, permissive=permissive)
Expand All @@ -430,11 +439,25 @@ class ck2yamlTest(converterTestCommon, utilities.CanteraTest):
ext = '.yaml'
InputError = ck2yaml.InputError

def _convert(self, inputFile, *, thermo, transport, surface, output, quiet,
permissive):
def _convert(self, inputFile, *, thermo, transport, surface, output, extra,
quiet, permissive):
ck2yaml.convert_mech(inputFile, thermo_file=thermo,
transport_file=transport, surface_file=surface, out_name=output,
quiet=quiet, permissive=permissive)
extra_file=extra, quiet=quiet, permissive=permissive)

def test_extra(self):
self.convert('gri30.inp', thermo='gri30_thermo.dat',
transport='gri30_tran.dat', output='gri30_extra',
extra='extra.yaml')

output = pjoin(self.test_work_dir, 'gri30_extra' + self.ext)
with open(output, 'rt', encoding="utf-8") as stream:
yml = yaml.safe_load(stream)

desc = yml['description'].split('\n')[-1]
self.assertEqual(desc, 'This is an alternative description.')
for key in ['foo', 'bar']:
self.assertIn(key, yml.keys())


class CtmlConverterTest(utilities.CanteraTest):
Expand Down