{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial 1: Generating a training set of structures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this tutorial, you will learn how to create a set of structures with the purpose of training a cluster exapnsion (CE) model. We start by creating a [parent lattice](https://sol.physik.hu-berlin.de/cell/modules/parent_lattice.html) object, which will be used throughout the CE construction. Examples of parent lattice creation for 3D (bulk) and 2D (surface) cases are given. The 2D example shows the multicomposition-multilattice capabilities of [CELL](https://sol.physik.hu-berlin.de/cell/index.html). Next, you will learn to perform the generation of random structures out of [supercells](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html) based on the parent lattice. These random [structures](https://sol.physik.hu-berlin.de/cell/modules/structure.html) are added to a [structures set](https://sol.physik.hu-berlin.de/cell/modules/structures_set.html) object. Such objects are extremely useful, since they allow grouping together structures for different purposes, e.g. training, testing, selection, etc. [CELL](https://sol.physik.hu-berlin.de/cell/index.html)'s structures sets also admit a representation in terms of [ASEs structure database](https://wiki.fysik.dtu.dk/ase/ase/db/db.html#module-ase.db) objects, thus inheriting all the advantages in terms of visualization, storing and retrieving structures and data in a convenient way. Excercises are proposed at the end of the tutorial." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building parent lattices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here you will learn how to set up and visualize a [parent lattice](https://sol.physik.hu-berlin.de/cell/modules/parent_lattice.html), which is the most basic object in [CELL](https://sol.physik.hu-berlin.de/cell/index.html). We will consider two examples: a bulk fcc crystal, and a surface system with adsorbed atoms and surface alloying. \n", "\n", "We start with the example of a **bulk binary fcc** metal alloy:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from ase.build import bulk\n", "from clusterx.parent_lattice import ParentLattice\n", "\n", "pri1 = bulk('Cu', 'fcc')\n", "sub1 = bulk('Al', 'fcc')\n", "\n", "platt1 = ParentLattice(pri1, substitutions=[sub1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the first line of the code shown above, we import the `bulk` module of the [Atomic Simulation Environment (ASE)](https://wiki.fysik.dtu.dk/ase/). In the second line, the [ParentLattice](https://sol.physik.hu-berlin.de/cell/modules/parent_lattice.html) class of **CELL** is loaded. In the next two lines, using the imported `bulk` function, we define [Atoms objects](https://wiki.fysik.dtu.dk/ase/ase/atoms.html#module-ase.atoms) corresponding to the pristine non-substituted Cu (fcc) lattice (`pri1`) and the fully substituted Al (fcc) lattice (`sub1`). These two `Atoms` objects are then employed to initialize the `ParentLattice` object (which we call `platt1`) in the last line. \n", "\n", "Next, we would like to visualize the just created parent lattice. To this end, we use the `juview` function of the [visualization module](https://sol.physik.hu-berlin.de/cell/modules/visualization.html) of **CELL**:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ec889c4c532f484da3433ab5fb86adf9", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(NGLWidget(), NGLWidget())),))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from clusterx.visualization import juview\n", "\n", "juview(platt1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Parent lattice CuAl](fig1-1.png) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The figure on the left, corresponds to the pristine non-substituted Cu fcc crystal, while the figure on the right represents the fully Al-substituted crystal. In general, the function call `juview(parent_lattice)`, will generate as many additional figures as substituent species are present in the parent lattice, as you will see in the next example for a surface system.\n", "\n", "Now, we will set up the parent lattice for a **surface system**. It consists on a fcc(111) Al surface, with possible Na substitution on the uppermost Al layer and adsorption of oxygen atoms in \"on-top\" configuration. This is a fictitious system which is shown here with the only purpose to illustrate possible uses of **CELL**. In order to build the parent lattice for such a system, we start with the creation of an `Atoms` object representing the pristine structure:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "from ase.build import fcc111, add_adsorbate\n", "\n", "pri2 = fcc111('Al', size=(1,1,3)) # 3-atomic-layer Al slab\n", "add_adsorbate(pri2,'X',1.7,'ontop') # on-top vacancy site\n", "pri2.center(vacuum=10.0, axis=2) # add vacuum along z-axis" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the code shown above, we first load some builder utilities from ASE (`fcc111` and `add_adsorbate`). In the next three lines, we *i)* create a fcc(111) Al slab with three atomic layers; *ii)* add a vacancy (symbol `X`) site with \"on top\" configuration, and *iii)* add vaccuum on the sides of the slab along the $z$-direction.\n", "\n", "In this way we have defined the pristine structure `pri2`. Now we would like to set up the substitutions: Na on the top-most Al layer and oxygen on the \"on-top\" vacancy sites. To proceed, we first grab some needed information from the pristine structure, as shown below: " ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Atom index |Chemical symbol |z coordinate \n", "0 |Al |10.000 \n", "1 |Al |12.338 \n", "2 |Al |14.677 \n", "3 |X |16.377 \n" ] } ], "source": [ "print(\"{0:<19s}|{1:<19s}|{2:<19s}\".format(\"Atom index\",\"Chemical symbol\",\"z coordinate\"))\n", "for i, (symbol, z_coord) in enumerate(zip(pri2.get_chemical_symbols(),pri2.get_positions()[:,2])):\n", " print(\"{0:<19d}|{1:<19s}|{2:<19.3f}\".format(i,symbol,z_coord))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From this output, we see that the \"Al\" atom belonging to the uppermost layer (i.e. the Al atom with the largest $z$ coordinate) has atom index 2, and that the adsorbate vacant site (X) has *atom* index 3. With this information, we initialize the parent lattice object in an alternative way, by telling which species can occupy every atom index: This is done with the `site_symbols` argument, which allows us to tell [CELL](https://sol.physik.hu-berlin.de/cell/index.html) which atomic species can occupy every atomic site:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "8ef3d878272a4d9a89b59bf6c7f0db89", "version_major": 2, "version_minor": 0 }, "text/html": [ "
Failed to display Jupyter Widget of type VBox
.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "VBox(children=(HBox(children=(NGLWidget(), NGLWidget(), NGLWidget())),))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "platt2 = ParentLattice(pri2, site_symbols=[['Al'],['Al'],['Al','Na'],['X','O']])\n", "juview(platt2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Parent lattice of complex surface](fig1-2.png) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this way, we see that for atom indices 0 and 1 only `['Al']` is allowed, while atom index 2 admits the species in the array `['Al','Na']` and atom index 3 admits species `['X','O']`, where `'X'` denotes a vacancy. The figures above denote: \n", " - *left:* pristine non-substituted lattice with vacancy-site indicated with white color\n", " - *middle:* on-top vacancy site substituted by oxygen (red)\n", " - *right:* top-most Al layer substituted by Na (purple)\n", "\n", "Note that this pictorial representation of the parent lattice is not meant to show all possible substitutions (this will come later with the generation of structures), but only the possible substitutions of the pristine structure (left), one by one." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Building structure sets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to generate *ab initio* data to train a cluster expansion model, we need to perform calculations of the property of interest for different atomic configurations of the crystal. These are obtained by, first, creating supercells based on the parent lattice, and second, specifying the actual placement of the different species in the supercell's lattice, i.e. *decorating* the supercells. In [CELL](https://sol.physik.hu-berlin.de/cell/index.html), super cells are represented by objects of the class [SuperCell](https://sol.physik.hu-\n", "berlin.de/cell/modules/super_cell.html). We will take the example of the surface system above, and create a $4\\times4\\times1$ super cell object:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "2a50cc610c0c463d93d62c8a03721aeb", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type VBox
.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "VBox(children=(HBox(children=(NGLWidget(), NGLWidget(), NGLWidget())),))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from clusterx.super_cell import SuperCell\n", "import numpy as np\n", "\n", "scell2 = SuperCell(platt2,[4,4])\n", "juview(scell2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Super cell](fig1-3.png) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the code shown above, we start by importing the [SuperCell](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html) class. Then we create an object of this class and assign it to the variable `scell2`. The initialization of the super cell takes two arguments. One is the parent lattice previously created, `platt2`, and the other can be an integer, a vector of integers or a $3\\times 3$ matrix with integer entries defining the transformation matrix $P$, which relates the supercell lattice vectors $S$ with the parent lattice vectors $V$: $S=PV$ (the rows of the matrices $S$ and $V$ are the cartesian coordinates of the corresponding lattice vectors, for the precise use of different input options visit the [documentation](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html)). Finally, we visualize the super cell by calling the `juview` function. The interpretation of the generated figure is the same as in the case of the parent lattice explained above.\n", "\n", "As you can see, a super cell looks very much like an enlarged parent lattice, indeed, objects of the [SuperCell](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html) class inherit from the [ParentLattice](https://sol.physik.hu-berlin.de/cell/modules/parent_lattice.html) class and share many properties.\n", "\n", "Now, using the created super cell, we will generate a few random decorations of it at different concentrations. The generated structures will be collected in a [StructuresSet](https://sol.physik.hu-berlin.de/cell/modules/structures_set.html) object.\n", "\n", "Before doing so, however, we need to find out the sublattice definitions in the just created [SuperCell](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html) object. This is necesary to correctly address the concentrations of Na substituents and oxygen atoms in the generation of random structures. This information is retrieved with the method `get_sublattice_types`:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "+--------------------------------------------------------------------+\n", "| The structure consists of 3 sublattices |\n", "+--------------------------------------------------------------------+\n", "| Sublattice type | Chemical symbols | Atomic numbers |\n", "+--------------------------------------------------------------------+\n", "| 0 | ['X' 'O'] | [0 8] |\n", "| 1 | ['Al' 'Na'] | [13 11] |\n", "| 2 | ['Al'] | [13] |\n", "+--------------------------------------------------------------------+\n", "\n" ] } ], "source": [ "scell2.get_sublattice_types(pretty_print=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This tells us that the supercell consists of three sublattices, with indices $0$, $1$ and $2$. Lattice sites belonging to sublattice $0$, contain species `\"X\"` (vacancy) and can be substituted by species `\"O\"` (oxygen) , sites belonging to sublattice $1$ contain `\"Al\"` and can be substituted by `\"Na\"`; while sites in $2$ contain `\"Al\"` and can not be substituted. \n", "\n", "In the code shown below, we first load the [`StructuresSet`](https://sol.physik.hu-berlin.de/cell/modules/structures_set.html) class and then create a structures-set object that we call `sset2`. Next, in three different `for` loops, by using the [`gen_random()`](https://sol.physik.hu-berlin.de/cell/modules/super_cell.html) method, we create *i)* two random structures with 4 on-top oxygen atoms, *ii)* two random structures with 4 Al$\\rightarrow$Na substitutions, and *iii)* two random structures with 4 oxygen atoms and 4 Al$\\rightarrow$Na substitutions:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "25b821d96efb44279668d77d6feecbca", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type VBox
.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "VBox(children=(HBox(children=(NGLWidget(), NGLWidget(), NGLWidget())), HBox(children=(NGLWidget(), NGLWidget(), NGLWidget()))))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from clusterx.structures_set import StructuresSet\n", "\n", "sset2 = StructuresSet(platt2)\n", "\n", "nstruc = 2\n", "\n", "# i) Random structures with 4 on-top oxygen atoms\n", "for i in range(nstruc):\n", " sset2.add_structure(scell2.gen_random({0:[4]}))\n", "\n", "# ii) Random structures with 4 substituent Na atoms\n", "for i in range(nstruc):\n", " sset2.add_structure(scell2.gen_random({1:[4]}))\n", "\n", "# iii) Random structures with 4 on-top oxygen and 4 substituent Na atoms\n", "for i in range(nstruc):\n", " sset2.add_structure(scell2.gen_random({0:[4],1:[4]}))\n", "\n", "juview(sset2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![Random structures](fig1-4.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the figure shown above, red spheres represent oxygen atoms and purple spheres represent Na substitutions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Excercise 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Build a parent lattice for a two-dimensional square lattice of a binary (e.g. SiGe) material and create (and visualize) 6 random structures on a $5\\times5$ super cell.\n", "\n", "As help, you can use the following Atoms object to initialze the [`ParentLattice`](html/modules/parent_lattice.html) object:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "from ase import Atoms\n", "\n", "a=3.0\n", "pri4 = Atoms(positions=[[0,0,0]],symbols=['Si'],cell=[[a,0,0],[0,a,0],[0,0,2*a]],pbc=(1,1,0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Excercise 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generate and visualize a few random structures for the fcc CuAl alloy of the first example on this tutorial. Do it so in a $3\\times3\\times3$ super cell." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.8" } }, "nbformat": 4, "nbformat_minor": 2 }