Skip to content

Commit

Permalink
[Input] Move all duplicate reaction checking out of ck2yaml
Browse files Browse the repository at this point in the history
Use the more comprehensive duplicate reaction check in
Kinetics::checkDuplicates when validating the mechanism.

Parse the error message generated by Kinetics::checkDuplicates to determine
the line number in the original input file, which is more useful to users
than the line number in the newly-generated YAML file.
  • Loading branch information
speth committed Jun 18, 2020
1 parent a9714a8 commit 1253997
Showing 1 changed file with 30 additions and 46 deletions.
76 changes: 30 additions & 46 deletions interfaces/cython/cantera/ck2yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -1783,51 +1783,12 @@ def readline():
for h in header:
self.header_lines.append(h[indent:])

self.check_duplicate_reactions()

for index, reaction in enumerate(self.reactions):
reaction.index = index + 1

if transportLines:
self.parse_transport_data(transportLines, path, transport_start_line)

def check_duplicate_reactions(self):
"""
Check for marked (and unmarked!) duplicate reactions. Raise exception
for unmarked duplicate reactions.
Pressure-independent and pressure-dependent reactions are treated as
different, so they don't need to be marked as duplicate.
"""
possible_duplicates = defaultdict(list)
for r in self.reactions:
k = (tuple(r.reactants), tuple(r.products), r.kinetics.pressure_dependent)
possible_duplicates[k].append(r)

for reactions in possible_duplicates.values():
for r1,r2 in itertools.combinations(reactions, 2):
if r1.duplicate and r2.duplicate:
pass # marked duplicate reaction
elif (type(r1.kinetics) == ThreeBody and
type(r2.kinetics) != ThreeBody):
pass
elif (type(r1.kinetics) != ThreeBody and
type(r2.kinetics) == ThreeBody):
pass
elif (r1.third_body.upper() == 'M' and
r1.kinetics.efficiencies.get(r2.third_body) == 0):
pass # explicit zero efficiency
elif (r2.third_body.upper() == 'M' and
r2.kinetics.efficiencies.get(r1.third_body) == 0):
pass # explicit zero efficiency
elif r1.third_body != r2.third_body:
pass # distinct third bodies
else:
raise InputError(
'Encountered unmarked duplicate reaction {} '
'(See lines {} and {} of the input file.).',
r1, r1.line_number, r2.line_number)

def parse_transport_data(self, lines, filename, line_offset):
"""
Parse the Chemkin-format transport data in ``lines`` (a list of strings)
Expand Down Expand Up @@ -2095,14 +2056,33 @@ def convert_mech(input_file, thermo_file=None, transport_file=None,
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))
return surface_names
return parser, surface_names

def show_duplicate_reactions(self, error_message):
reactions = []
for line in error_message.split('\n'):
match = re.match('>.*# Reaction ([0-9]+)', line)
if match:
reactions.append(int(match.group(1))-1)

if len(reactions) != 2:
print(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]))


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, extra_file, out_name, quiet, permissive)
parser, surface_names = Parser.convert_mech(
input_file, thermo_file, transport_file, surface_file, phase_name,
extra_file, out_name, quiet, permissive)
return surface_names


def main(argv):

Expand Down Expand Up @@ -2160,9 +2140,9 @@ def main(argv):
else:
out_name = os.path.splitext(thermo_file)[0] + '.yaml'

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

# Do full validation by importing the resulting mechanism
if not input_file:
Expand All @@ -2187,7 +2167,11 @@ def main(argv):
print('PASSED.')
except RuntimeError as e:
print('FAILED.')
print(e)
msg = str(e)
if ('Undeclared duplicate reactions' in msg):
parser.show_duplicate_reactions(msg)
else:
print(e)
sys.exit(1)


Expand Down

0 comments on commit 1253997

Please sign in to comment.