Perhaps the easiest way to get started with your own Micro-kinetic modeling is to have a quick look at a few usage examples. We will take a look at few examples from the simplest CO Oxidation reaction on Pt100 surface using both scaks API and web GUI.
Solve a micro-kinetic model¶
scaks.models module provide different model classes for different kinetic model construction(only micro-kinetic model in current version). Model can constructed from either a setup dict data structure for running in interactive shell or a setup input file for submitting a computing job.
Using setup file¶
By providing a set of input files including model definition, energy information, script using scaks API can parse all those files and run the model automatically.
pt-100.mkm
: Input file for micro-kinetic model information:rxn_expressions = [ 'CO_g + *_s -> CO_s', 'O2_g + 2*_s <-> O-O_2s -> 2O_s', 'CO_s + O_s <-> CO-O_2s -> CO2_g + 2*_s', ] # Gas pressure. species_definitions = {} species_definitions['CO_g'] = {'pressure': 1.32*10**-7} species_definitions['O2_g'] = {'pressure': 5.26*10**-7} species_definitions['CO2_g'] = {'pressure': 1.32*10**-7} # Site info. species_definitions['*_s'] = {'site_name': 'top', 'type': 'site', 'total': 1.0} # Temperature. temperature = 500 # K unitcell_area = 9.0e-20 active_ratio = 4./9. parser = "RelativeEnergyParser" solver = "SteadyStateSolver" corrector = "ThermodynamicCorrector" plotter = "EnergyProfilePlotter" rate_algo = "CT" rootfinding = "MDNewton" tolerance = 1e-50 max_rootfinding_iterations = 100
rel_energy.py
: Energy information for each elementary reaction:Ga, dG = [], [] # CO_g + *_s -> CO_s Ga.append(0.0) dG.append(-2.09) # O2_g + 2*_s -> 2O_s Ga.append(0.07) dG.append(-2.39) # CO_s + O_s <-> CO-O_2s -> CO2_g + 2*_s Ga.append(0.39) dG.append(-0.46)
With these input files prepared, we can use scaks’s API to construct a micro-kinetic model:
from scaks.models.micro_kinetic_model import MicroKineticModel
model = MicroKineticModel(setup_file='pt-100.mkm')
While constructing the model, all model components like parser, solver and plotter are instantialized automatically. Thus, we can use components to parse data and solve model:
model.parser.parse_data() # Parse input data
model.solver.get_data() # Pass data to solver
model.run() # Solve micro-kinetic model
Using setup dictionary¶
Setup dictionary is a Python data structure containing essential information for constructing a preliminary Micro-Kinetic Model. It must contain the following informations (keys):
rxn_expressions
: All elementary reaction expressionsspecies_definitions
: Species information in reaction path such as gas name and partial pressure, adsorption site types and total coverages.temperature
: Reaction temperation in Kparser
: The parser name for data and input file parsing
The model definition dict for CO oxidation on Pt(100) surface could be written as:
model_dict = dict(
rxn_expressions = [
'CO_g + *_s -> CO_s',
'O2_g + 2*_s <-> O-O_2s -> 2O_s',
'CO_s + O_s <-> CO-O_2s -> CO2_g + 2*_s',
],
species_definitions = {
'CO_g': {'pressure': 1.32e-7},
'O2_g': {'pressure': 5.26e-7},
'CO2_g': {'pressure': 1.32e-7},
'*_s': {'site_name': '111', 'type': 'site', 'total': 1.0},
},
temperature = 500,
parser = "RelativeEnergyParser",
)
Construct corresponding micro-kinetic model:
from scaks.models.micro_kinetic_model import MicroKineticModel
model = MicroKineticModel(setup_dict=model_dict)
Use constructed model to generate file template for energy data input:
1.Absolute energy input file template:
model.generate_absolute_energies_file('./abs_energy.py')
Then scaks will parse all model information in reaction expressions to create a abs_energy.py
with below content in current directory:
# Absolute energies for all species.
absolute_energies = {
'CO2_g': 0.0, # eV
'CO_g': 0.0, # eV
'O2_g': 0.0, # eV
'CO_s': 0.0, # eV
'O_s': 0.0, # eV
'CO-O_2s': 0.0, # eV
'O-O_2s': 0.0, # eV
'*_s': 0.0, # eV
}
2.Relative energy input file template:
model.generate_relative_energies_file('./rel_energy.py')
Then scaks will parse all model information in reaction expressions to create a rel_energy.py
with below content in current directory:
# Relative Energies for all elementary reactions.
Ga, dG = [], []
# CO_g + *_s -> CO_s
Ga.append()
dG.append()
# O2_g + 2*_s <-> O-O_2s -> 2O_s
Ga.append()
dG.append()
# CO_s + O_s <-> CO-O_2s -> CO2_g + 2*_s
Ga.append()
dG.append()
After inputting energy data in the template file, you can instantialize solver explicitly and put it in micro-kinetic model:
from scaks.solvers.steady_state_solver import SteadyStateSolver
solver = SteadyStateSolver(model)
model.set_solver(solver)
With solver integrated, model can parse data and solve the model:
model.parser.parse_data('./rel_energy.py')
model.solver.get_data()
model.run()
Use script to run a job¶
Besides instantiate model using scaks API, we provide a simple run.py
script to parse those input files and solve the micro-kinetic model automatically, the details of the script:
import logging
import sys
import time
from scaks.compatutil import subprocess
from scaks.mpicommons import mpi
from scaks.models.micro_kinetic_model import MicroKineticModel
from scaks.utilities.format_utilities import convert_time
# Custom parameters.
OdeInterval = 0.001 # ODE integration time interval.
OdeEnd = 1 # ODE integration time limit.
OdeOutput = True # Output ODE integration data or not.
CalcXRC = True # Calculate Degree of Rate Control(XRC) or not.
ProductionName = "CO2_g" # Production name of your model.
OdeOnly = False # Do ODE integration only.
if "__main__" == __name__:
# Clean up current dir.
subprocess.getstatusoutput("rm -rf out.log auto_*")
# Set script logger.
logger = logging.getLogger("model.MkmRunScript")
# Get setup file.
status, output= subprocess.getstatusoutput("ls *.mkm | tail -1")
if status:
if mpi.is_master:
logger.error(output)
logger.info("Exiting...")
sys.exit(1)
start = time.time()
try:
# Build micor-kinetic model.
model = MicroKineticModel(setup_file=output)
# Read data.
parser = model.parser
solver = model.solver
parser.parse_data()
solver.get_data()
# Initial coverages guess.
trajectory = solver.solve_ode(time_span=OdeInterval,
time_end=OdeEnd,
traj_output=OdeOutput)
init_guess = trajectory[-1]
# Run.
model.run(init_cvgs=init_guess,
solve_ode=OdeOnly,
coarse_guess=False,
XRC=CalcXRC,
product_name=ProductionName)
except Exception as e:
if mpi.is_master:
msg = "{} exception is catched.".format(type(e).__name__)
logger.exception(msg)
raise e
# Time used.
end = time.time()
t = end - start
h, m, s = convert_time(t)
if mpi.is_master:
logger.info("Time used: {:d} h {:d} min {:f} sec".format(h, m, s))
Just use Python to execute the script to run the job:
python run.py
Of course, instead of using built-in script, users can write their own script with mikac API to customize the functionality.
After the solving is finished, new output files are generated in current directory:
out.log
: All output log information such as TOFs, reversibilities, steady state coverages and so on.data.pkl
: Serialized result data such as turnover frequencies (TOF), steady state coverages and so on. Variable to be dumped is controlled in setup file.auto_ode_coverages.py
: A python module file containing ODE integration data
With ODE plotting script in scaks package, the ODE integration trajectory can be visualized: