This notebook describes pmutt's functionality to write OpenMKM CTI and YAML files. We will use the NH3 formation mechanism as a case study.
All the data will be imported from the ./inputs/NH3_Input_data.xlsx
file. There are several sheets:
units
contains the units that types of quantities should be writtenrefs
contains ab-initio and experimental data for a handful of gas species to calculate references (optional)species
contains ab-initio data for each speciebeps
contains Bronsted-Evans-Polanyi relationships for reactions (optional)reactions
contains elementary steps lateral_interactions
contains lateral interactions between species (optional)phases
contains phases for the speciesreactor
contains reactor operating conditions and solver tolerancesThe refs
, beps
and lateral_interactions
sheets can be deleted and the code written below should still work.
First, we change the working directory to the location of the Jupyter notebook.
import os
from pathlib import Path
# Find the location of Jupyter notebook
# Note that normally Python scripts have a __file__ variable but Jupyter notebook doesn't.
# Using pathlib can overcome this limiation
try:
notebook_path = os.path.dirname(__file__)
except NameError:
notebook_path = Path().resolve()
os.chdir(notebook_path)
input_path = './inputs/NH3_Input_Data.xlsx'
And we define a helper function to print data from the Excel spreadsheet easily.
import pandas as pd
from IPython.display import display
def disp_data(io, sheet_name):
try:
data = pd.read_excel(io=io, sheet_name=sheet_name, skiprows=[1])
except:
print('The {} sheet could not be found in {}.'.format(sheet_name, io))
else:
data = data.fillna(' ')
display(data)
Below, we show the contents of the Excel sheets.
Units
disp_data(io=input_path, sheet_name='units')
References
disp_data(io=input_path, sheet_name='refs')
Species
In this mechanism, we have species existing on terraces and steps. We also define the transition states of species.
Note that later we will use BEPs to calculate barriers for most steps. Hence, these transition state species will actually be ignored. You should use either transition state species or BEP relationships to calculate barriers.
disp_data(io=input_path, sheet_name='species')
BEPs
disp_data(io=input_path, sheet_name='beps')
Reactions
Note that reactions with two '=' signs indicate it has a transition state or BEP relationship.
disp_data(io=input_path, sheet_name='reactions')
Lateral Interactions
Currently we use piece-wise linear equations for lateral interactions. Here, we only define one interval between 0 - 1 ML but additional list.intervals
and list.slopes
columns can be added for more complicated behavior.
disp_data(io=input_path, sheet_name='lateral_interactions')
Phases
As previously stated, there are two surface sites: terrace and step. There are also the gas and bulk phases defined.
disp_data(io=input_path, sheet_name='phases')
Reactor
The reactor sheet contains options for the YAML file.
disp_data(io=input_path, sheet_name='reactor')
Throughout this exercise, we will use pmutt.io.read_excel
to extract the data from the Excel spreadsheet.
First, we will designate the units to write the CTI and YAML file.
from pmutt.io.excel import read_excel
from pmutt.omkm.units import Units
units_data = read_excel(io=input_path, sheet_name='units')[0]
units = Units(**units_data)
Second, we will open the input spreadsheet and read the refs
sheet.
from pmutt.empirical.references import Reference, References
try:
refs_data = read_excel(io=input_path, sheet_name='refs')
except:
# If references are not used, skip this section
print('The "refs" sheet could not be found in {}. Skiping references'.format(input_path))
refs = None
else:
refs = [Reference(**ref_data) for ref_data in refs_data]
refs = References(references=refs)
from pmutt.empirical.nasa import Nasa
# Read the species' data
species_data = read_excel(io=input_path, sheet_name='species')
# Create NASA polynomials from the species
species = [Nasa.from_model(references=refs, **ind_species_data) \
for ind_species_data in species_data]
import numpy as np
from pmutt.empirical.shomate import Shomate
Ar = Shomate(name='Ar', elements={'Ar': 1}, phase='gas', T_low=298., T_high=6000.,
a=np.array([20.78600, 2.825911e-7, -1.464191e-7, 1.092131e-8, -3.661371e-8, -6.19735, 179.999, 0.]))
species.append(Ar)
Next, we read the BEP relationships to include.
from pmutt.omkm.reaction import BEP
try:
beps_data = read_excel(io=input_path, sheet_name='beps')
except:
print('The "beps" sheet could not be found in {}. Skiping BEPs'.format(input_path))
beps = None
species_with_beps = species.copy()
else:
beps = [BEP(**bep_data) for bep_data in beps_data]
species_with_beps = species + beps
Then, we read the reactions to include.
from pmutt import pmutt_list_to_dict
from pmutt.omkm.reaction import SurfaceReaction
# Convert species to dictionary for easier reaction assignment
species_with_beps_dict = pmutt_list_to_dict(species_with_beps)
reactions_data = read_excel(io=input_path, sheet_name='reactions')
reactions = [SurfaceReaction.from_string(species=species_with_beps_dict, **reaction_data) \
for reaction_data in reactions_data]
After, we read lateral interactions to include.
from pmutt.mixture.cov import PiecewiseCovEffect
try:
interactions_data = read_excel(io=input_path, sheet_name='lateral_interactions')
except:
# If no lateral interactions exist, skip this section
print('The "lateral_interactions" sheet could not be found in {}. Skiping lateral interactions'.format(input_path))
interactions = None
else:
interactions = [PiecewiseCovEffect(**interaction_data) for interaction_data in interactions_data]
Finally, we read the phases data from Excel and organize it for use in OpenMKM.
from pmutt.io.omkm import organize_phases
# Read data from Excel sheet about phases
phases_data = read_excel(io=input_path, sheet_name='phases')
phases = organize_phases(phases_data, species=species, reactions=reactions, interactions=interactions)
The YAML file specifying the reactor configuration can be written using the write_yaml
function. Note that if:
units
is not specified, float values are assumed to be in SI unitsunits
is specified, float values are consistent with unit
's attributesfrom pmutt.io.omkm import write_yaml
Path('./outputs').mkdir(exist_ok=True)
yaml_path = './outputs/reactor.yaml'
reactor_data = read_excel(io=input_path, sheet_name='reactor')[0]
write_yaml(filename=yaml_path, phases=phases, units=units, **reactor_data)
If you would prefer to return the file as a string instead of writing it, omit the filename
.
print(write_yaml(phases=phases, units=units, **reactor_data))
As of OpenMKM version 0.6.0 onwards, the thermodynamic and kinetic parameters can be written as a YAML file. We recommend using this format over the older CTI format. To generate the Thermo/Kinetic YAML file using pMuTT, use the write_thermo_yaml
function
from pmutt.io.omkm import write_thermo_yaml
write_thermo_yaml(phases=phases,
species=species,
reactions=reactions,
lateral_interactions=interactions,
units=units,
filename='./outputs/thermo.yaml')
Like before, omitting the filename
parameter returns a string
print(write_thermo_yaml(phases=phases,
species=species,
reactions=reactions,
lateral_interactions=interactions,
units=units))
from pmutt.io.omkm import write_cti
cti_path = './outputs/thermo.cti'
use_motz_wise = True
T = reactor_data['T']
write_cti(reactions=reactions, species=species, phases=phases, units=units,
lateral_interactions=interactions, filename=cti_path,
use_motz_wise=use_motz_wise, T=T, P=1.)
Like before, omitting the filename
parameter returns a string.
print(write_cti(reactions=reactions, species=species, phases=phases, units=units,
lateral_interactions=interactions, use_motz_wise=use_motz_wise))