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 expressions
  • species_definitions: Species information in reaction path such as gas name and partial pressure, adsorption site types and total coverages.
  • temperature: Reaction temperation in K
  • parser: 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:

ODE integration