-
Notifications
You must be signed in to change notification settings - Fork 247
Coverage-dependent thermochemistry for catalysis #2646
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
base: main
Are you sure you want to change the base?
Changes from all commits
5952dc6
d153155
24e0290
5b54479
92f40d3
a0ba53b
d34117c
38e418b
6a6f97f
200a13d
d597e78
3718c2a
77150bb
7ebaefa
590b4f4
3fa775e
af61472
bd0d510
4659cb4
b89289e
72f0026
15ac535
18e056b
1f485af
12c6a38
2639f39
263a5a2
7ffa50f
9432998
ab1464b
c35021a
7b41c29
8632afe
f156f76
3553228
b2cad6d
ecd87ae
3578564
410675c
ee940ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -50,6 +50,7 @@ | |
| import yaml | ||
| from cantera import ck2yaml | ||
| from scipy.optimize import brute | ||
| import cantera as ct | ||
|
|
||
| import rmgpy.util as util | ||
| from rmgpy import settings | ||
|
|
@@ -196,6 +197,7 @@ def clear(self): | |
| self.surface_site_density = None | ||
| self.binding_energies = None | ||
| self.coverage_dependence = False | ||
| self.thermo_coverage_dependence = False | ||
| self.forbidden_structures = [] | ||
|
|
||
| self.reaction_model = None | ||
|
|
@@ -513,7 +515,7 @@ def initialize(self, **kwargs): | |
|
|
||
| # Read input file | ||
| self.load_input(self.input_file) | ||
|
|
||
| # Check if ReactionMechanismSimulator reactors are being used | ||
| # if RMS is not installed but the user attempted to use it, the load_input_file would have failed | ||
| # if RMS is not installed and they did not use it, we avoid calling certain functions that would raise an error | ||
|
|
@@ -526,6 +528,7 @@ def initialize(self, **kwargs): | |
| self.reaction_model.core.phase_system.phases["Surface"].site_density = self.surface_site_density.value_si | ||
| self.reaction_model.edge.phase_system.phases["Surface"].site_density = self.surface_site_density.value_si | ||
| self.reaction_model.coverage_dependence = self.coverage_dependence | ||
| self.reaction_model.thermo_coverage_dependence = self.thermo_coverage_dependence | ||
|
|
||
| if kwargs.get("restart", ""): | ||
| import rmgpy.rmg.input | ||
|
|
@@ -771,7 +774,7 @@ def register_listeners(self, requires_rms=False): | |
| """ | ||
|
|
||
| self.attach(ChemkinWriter(self.output_directory)) | ||
|
|
||
| self.attach(RMSWriter(self.output_directory)) | ||
|
|
||
| if self.generate_output_html: | ||
|
|
@@ -1232,6 +1235,44 @@ def execute(self, initialize=True, **kwargs): | |
| os.path.join(self.output_directory, "chemkin", "chem_annotated-gas.inp"), | ||
| surface_file=(os.path.join(self.output_directory, "chemkin", "chem_annotated-surface.inp")), | ||
| ) | ||
| if self.thermo_coverage_dependence: | ||
| # add thermo coverage dependence to Cantera files | ||
| chem_yaml_path = os.path.join(self.output_directory, "cantera", "chem.yaml") | ||
| gas = ct.Solution(chem_yaml_path, "gas") | ||
| surf = ct.Interface(chem_yaml_path, "surface1", [gas]) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of loading the cantera gas and surf objects, we can get the order of species names in the cantera file with something like this: |
||
| with open(chem_yaml_path, 'r') as f: | ||
| content = yaml.load(f, Loader=yaml.FullLoader) | ||
|
|
||
| content['phases'][1]['reference-state-coverage'] = 0.11 | ||
| content['phases'][1]['thermo'] = 'coverage-dependent-surface' | ||
|
|
||
| for s in self.reaction_model.core.species: | ||
| if s.contains_surface_site() and s.thermo.thermo_coverage_dependence: | ||
| for dep_sp, parameters in s.thermo.thermo_coverage_dependence.items(): | ||
| mol = Molecule().from_adjacency_list(dep_sp) | ||
| for sp in self.reaction_model.core.species: | ||
| if sp.is_isomorphic(mol, strict=False): | ||
| parameters['units'] = {'energy':'J', 'quantity':'mol'} | ||
| parameters['enthalpy-coefficients'] = [value.value_si for value in parameters['enthalpy-coefficients']] | ||
| parameters['entropy-coefficients'] = [value.value_si for value in parameters['entropy-coefficients']] | ||
| try: | ||
| content["species"][gas.n_species+surf.species_index(sp.to_chemkin())]['coverage-dependencies'][sp.to_chemkin()] = parameters | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then we can get the species order with a call like this:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I edited this suggestion to fix the cross-species interaction bug described below) |
||
| except KeyError: | ||
| content["species"][gas.n_species+surf.species_index(sp.to_chemkin())]['coverage-dependencies'] = {sp.to_chemkin(): parameters} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there's a bug here preventing the code from writing cross-species interactions. The first index should reference the species we're writing thermo for. The second index should reference the species it's interacting with, and these should be allowed to be different. content["species"][FIRST INDEX]['coverage-dependencies][SECOND INDEX] Here, I think FIRST INDEX refers to species |
||
|
|
||
| annotated_yaml_path = os.path.join(self.output_directory, "cantera", "chem_annotated.yaml") | ||
| with open(annotated_yaml_path, 'r') as f: | ||
| annotated_content = yaml.load(f, Loader=yaml.FullLoader) | ||
|
|
||
| annotated_content['phases'] = content['phases'] | ||
| annotated_content['species'] = content['species'] | ||
|
|
||
| with open(chem_yaml_path, 'w') as output_f: | ||
| yaml.dump(content, output_f, sort_keys=False) | ||
|
|
||
| with open(annotated_yaml_path, 'w') as output_f: | ||
| yaml.dump(annotated_content, output_f, sort_keys=False) | ||
|
|
||
| else: # gas phase only | ||
| self.generate_cantera_files(os.path.join(self.output_directory, "chemkin", "chem.inp")) | ||
| self.generate_cantera_files(os.path.join(self.output_directory, "chemkin", "chem_annotated.inp")) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can avoid importing cantera here because it's just used to look up the order of the species in a yaml file, and this can be done with information that already exists in memory.