A First KMC Model

Let’s begin by understanding how to setup a model, which will turn out to be surprisingly straightforward. It will also pay off, especially when you start tinkering with existing models and make little changes here and there.

Note

You may also take a look at the examples directory. It contains a variety of ready-to-use models of different complexity.

Build the Model

We start by making the necessary import statements eitehr in a Python script or using IPython

import kmos3
from kmos3.types import *
from kmos3.io import *
import numpy as np

which imports all classes that make up a KMC project. The functions from kmos3.io will only be needed at the end to save the project or to export compilable code.

The example sketched out here leads you to a KMC model for CO adsorption and desorption on Pd(100). First you need to instantiate a new project and fill in meta information

kmc_model = kmos3.create_kmc_model()
kmc_model.set_meta(
    author = 'Your Name',
    email = 'your.name@server.com',
    model_name = 'MyFirstModel',
    model_dimension = 2,
    )

Next, you add some species (or states). Note that whichever species you add first is the default species with which all sites in the system will be initialized. Of course this default can be changed later as needed.

For surface science simulations it is useful to define an empty state, so we add

kmc_model.add_species(name='empty')

and some surface species. Given you want to simulate CO adsorption and desorption on a single crystal surface you would say

kmc_model.add_species(
    name='CO',
    representation="Atoms('CO',[[0,0,0],[0,0,1.2]])"
    )

where the string passed as representation is a string representing a CO molecule, which can be evaluated in ASE namespace.

Once you have all species declared is a good time to think about the geometry. To keep it simple we will stick with a simple cubic lattice in 2D. This lattice could for example represent the (100) surface of an fcc crystal with only one adsorption site per unit cell. You start by giving your layer a name

layer = kmc_model.add_layer(name='simple_cubic')

and adding a site

layer.sites.append(
    Site(
        name='hollow',
        pos='0.5 0.5 0.5',
        default_species='empty'
        )
    )

Where pos is given in fractional coordinates, so this site will be in the center of the unit cell.

Now you might be wondering about the absence of additional geometry details. The reason is quite simple: the geometric location of a site is meaningless from a KMC point of view. The master equation, which governs the KMC process, is solely concerned with states and transitions between them. Nevertheless, for visualization purposes, geometric information can be included, as you have already done for the site. You can set the size of the unit cell via

kmc_model.lattice.cell = np.diag([3.5, 3.5, 10])

which are prototypical dimensions for a single-crystal surface in Angstrom.

Ok, let us see what we managed so far: you have a lattice with a site that can be either empty or occupied with CO.

Populate Process List and Parameter List

The remaining work is to populate the process list and the parameter list. The parameter list defines the parameters that can be used in the rate constant expressions. In principle you could skip the parameter list and simply hard code all parameters in the process list. However you will miss out on some handy features like being able to easily change parameters on-the-fly or even interactively.

A second benefit is that you achieve a clear separation of the kinetic model from the barrier input, which usually come from different sources.

In practice, filling both the parameter list and the process list is often an iterative process. However, since our list is fairly short, we can try to set all parameters simultaneously.

Firstly, you’ll need to define the external parameters that our model depends on. In this case, we consider the temperature and the CO partial pressure

kmc_model.add_parameter(name='T', value=600., adjustable=True, min=400, max=800)
kmc_model.add_parameter(name='p_CO', value=1., adjustable=True, min=1e-10, max=1.e2)

You can also set a default value along with a minimum and a maximum value. These settings define the behavior of the scrollbars in the runtime GUI.

To describe the adsorption rate constant you will need the area of the unit cell

kmc_model.add_parameter(name='A', value='(3.5*angstrom)**2')

Last but not least you need a binding energy of the particle on the surface. Since we do not have an immediate value for the gas phase chemical potential, we’ll refer to it as deltaG and keep it adjustable

kmc_model.add_parameter(name='deltaG', value='-0.5', adjustable=True,
                        min=-1.3, max=0.3)

To define processes we first need a coordinate [2]

coord = kmc_model.lattice.generate_coord('hollow.(0,0,0).simple_cubic')

Then you need to have at least two processes. A process or elementary step in KMC entails a specific local configuration where an event can occur at a certain rate constant. In the framework here, this is articulated in terms of conditions and actions. [1] So for example an adsorption process requires at least one vacant site (condition). Only after fulfilling this condition can the site be occupied by CO (action) with a designated rate constant. Translated into code, this appears as follows

kmc_model.add_process(
    name='CO_adsorption',
    conditions=[Condition(coord=coord, species='empty')],
    actions=[Action(coord=coord, species='CO')],
    rate_constant='p_CO*bar*A/sqrt(2*pi*umass*m_CO/beta)',
    tof_count="{'adsorption':1}"
    )

Note

In order to ensure correct functioning of the kmos3 KMC solver, every action should have a corresponding condition for the same coordinate.

Now you might wonder, how come we can simply use m_CO and beta and such. Well, that is because the evaluator will do some trickery to resolve such terms. For example, beta is initially converted to 1/(kboltzmann*T) and as long as you’ve defined a parameter T earlier, this will occur seamlessly. Similarly for m_CO, the evaluator looks up and includes the atomic masses. Note that we need conversion factors of bar and umass.

Then the desorption process is almost the same, except the reverse

kmc_model.add_process(
    name='CO_desorption',
    conditions=[Condition(coord=coord, species='CO')],
    actions=[Action(coord=coord, species='empty')],
    rate_constant='p_CO*bar*A/sqrt(2*pi*umass*m_CO/beta)*exp(beta*deltaG*eV)',
    tof_count="{'desorption':1}"
    )

To reduce typing, kmos3 also knows a shorthand notation for processes. In order to produce the same process you could also type

p = kmc_model.parse_process(
    'CO_desorption; CO@hollow->empty@hollow; ' \
    'p_CO*bar*A/sqrt(2*pi*umass*m_CO/beta)*exp(beta*deltaG*eV)'
    )
p.tof_count = {'desorption':1}
kmc_model.add_process(p)

and since any non-existing on either side of the -> symbol gets replaced by a corresponding term from the default_species (in this case empty) you could as well type

p = kmc_model.parse_process(
    'CO_desorption; CO@hollow->; ' \
    'p_CO*bar*A/sqrt(2*pi*umass*m_CO/beta)*exp(beta*deltaG*eV)'
    )
p.tof_count = {'desorption':1}
kmc_model.add_process(p)

and to make it even shorter you can parse and add the process on one line

p = kmc_model.parse_and_add_process(
    'CO_desorption; CO@hollow->; ' \
    'p_CO*bar*A/sqrt(2*pi*umass*m_CO/beta)*exp(beta*deltaG*eV)'
    )
p.tof_count = {'desorption':1}

In order to add processes on more than one site possible spanning across unit cells, there is a shorthand as well. The full-fledged syntax for each coordinate is

"<site-name>.<offset>.<lattice>"

For details check Manual Generation.

Export, Save, Compile

Before we compile the model, we should specify and understand the various backends that are involved:

  • local_smart backend (default) for models with <100 processes

  • lat_int backend for models with >100 processes. (built in the same way as local_smart but different backend for compile step)

  • otf backend requires customized model (build requires different process definitions compared to local_smart) and can work for models which require >10,000 processes, since each process rate is calculated on the fly rather than being stored in memory

Here is how we specify the model’s backend

kmc_model.backend = 'local_smart'
kmc_model.backend = 'lat_int'
kmc_model.backend = 'otf'

Next, it’s a good idea to save and compile your work

kmc_model.save_model()
kmos3.compile(kmc_model)

This creates an XML file with the full definition of your model and exports the model to compiled code.

Now is the time to run the Python script or leave the IPython shell. In the current directory you should see a MyFirstModel.xml. You will also see a directory ending with _local_smart, this directory includes your compiled model.

You can also skip the model exporting by commenting out kmos3.compile(kmc_model) and do it later by typing kmos3 export MyFirstModel.xml from the terminal if you are in the same directory as the XML file.

During troubleshooting, exporting separately can sometimes be useful to make sure the compiling occurs smoothly without any line containing an error.

Running and Viewing the Model

After successfully exporting and compiling the model you get two files: kmc_model_*.so and kmc_settings.py in the MyFirstModel_local_smart folder. These two files are really all you need for simulations and you need to be in the same directory as these two files to run it (more precisely these two files need to be in the python import path). To test if everything works as expected, run

kmos3 benchmark

and you should see that the model was able to run.

A simple way to view the model is the

kmos3 view

command from the command line. This feature can be quite useful to quickly obtain an intuitive understanding of the model at hand. A lot of settings can be changed through the kmc_settings.py such as rate constants or parameters. To be even more interactive you can set a parameter to be adjustable. This can happen either in the generating XML file or directly in the kmc_settings.py. Also make sure to set sensible minimum and maximum values.

Note

The view command only works on certain operating systems and currently only works if a tof_count was defined for at leat one process.

Todo

Fix the tof_count bug!

For running the model, it is recommended to use a runfile.

If you’re wondering why the CO molecules appear to be hanging in mid-air, it’s because you haven’t set up the background yet. Choose a transition metal of your choice and add it to the lattice setup.

Wondering where to go from here? If the workflow makes complete sense, you have a specific model in mind, and just need some more idioms to implement it we suggest you take a look at the examples folder for some hints. To learn more about the kmos3 approach and methods you should take a look into the Topic Guides.

Note

In technical terms, kmos3 is run an API via the kmos3 python module.

An Alternative Way Using INI Files

Presently, a full description of the INI capability is not being provided because this way is not the standard way of using kmos3, however, it is available. This method is an alternative to making an XML file, and can be used instead for exporting with kmos3 export.

Prepare a minimal input file with the following content and save it as mini_101.ini

[Meta]
author = Your Name
email = you@server.com
model_dimension = 2
model_name = fcc_100

[Species empty]
color = #FFFFFF

[Species CO]
representation = Atoms("CO", [[0, 0, 0], [0, 0, 1.17]])
color = #FF0000

[Lattice]
cell_size = 3.5 3.5 10.0

[Layer simple_cubic]
site hollow = (0.5, 0.5, 0.5)
color = #FFFFFF

[Parameter k_CO_ads]
value = 100
adjustable = True
min = 1
max = 1e13
scale = log

[Parameter k_CO_des]
value = 100
adjustable = True
min = 1
max = 1e13
scale = log

[Process CO_ads]
rate_constant = k_CO_ads
conditions = empty@hollow
actions = CO@hollow
tof_count = {'adsorption':1}

[Process CO_des]
rate_constant = k_CO_des
conditions = CO@hollow
actions = empty@hollow
tof_count = {'desorption':1}

In the same directory run kmos3 export mini_101.ini. You should now have a folder mini_101_local_smart in the same directory. cd into it and run kmos3 benchmark. If everything went well you should see something like

Using the [local_smart] backend.
1000000 steps took X seconds
Or X steps/s

In the same directory try running kmos3 view to watch the model run or fire up kmos3 shell to interact with the model interactively. Explore more commands with kmos3 --help and please refer to the documentation for building complex models and evaluating them systematically.

Taking it Home

Despite its simplicity you have now seen all elements needed to implement a KMC model. Hopefully, this has given you a foundational understanding of the general workflow.

Todo

Describe modelling of more complicated structures and, e.g., boundary conditions.