{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n\n# Introduction to ASE databases\nASE has its own database format that can be used for storing and retrieving\natoms (and associated data) in a compact and convenient way. In the following,\nwe will create databases and interact with them through python scripts and\nthe command line.\n\n## Setting up a database\nTo construct a database we first need some atomic structures so let's quickly\ncreate some. As you have seen the ASE command line tool provides many convenient\ncommands and in particular we can use the ``build`` command to create some\natomic structures. Remember, if you are unsure how to use a particular command\nyou can always append ``-h`` to the particular command (ie. ``ase build -h``)\nto see the help for that particular command.\n\nWe choose to build aluminium, copper and gold in the diamond crystal\nstructure for which ASE already knows the lattice constants:\n\n::\n\n $ ase build -x fcc Al\n $ ase build -x fcc Cu\n $ ase build -x fcc Au\n\nThis creates three files: :file:`Al.json`, :file:`Cu.json` and :file:`Au.json`.\nIf you want to, you can inspect them with ASE's ``gui`` command, however we\nwant to construct a database containing these structures. To do this we can use\n``convert``::\n\n $ ase convert Al.json Cu.json Au.json database.db\n\nThis has created an ASE database name :file:`database.db`.\n\nAdditionally, one can use the ``ase build`` command to build Si, Ge and C and\nconvert them into a ASE database named :file:`database.db` using the following:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from pathlib import Path\n\nfrom ase.build import bulk\nfrom ase.calculators.emt import EMT\nfrom ase.db import connect\nfrom ase.filters import FrechetCellFilter\nfrom ase.optimize import BFGS\n\ndbfile = Path('database.db')\ndbfile.unlink(missing_ok=True)\n\nstructures = ['Al', 'Cu', 'Au']\ndb = connect(dbfile)\n\nfor structure in structures:\n db.write(bulk(structure))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Inspecting a database on the command line\nWe can inspect the database using the ``db`` command::\n\n $ ase db database.db\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "which will display three entries, one for each structure. From this point\nit is advised to bring up the help for the ``db`` command every time you need\nit.\n\nFrom the help we can see that it is possible to make selections (queries in\ndatabase lingo) in the database by::\n\n $ ase db database.db Al\n\nwhich will show all structures containing silicon. To see the details of a\nparticular row we can do::\n\n $ ase db database.db Al -l\n\nFrom which we can get an overview of the stored data. We can also view all\nstructures in a database using::\n\n $ ase gui database.db\n\nor if we want to view a single one we can do::\n\n $ ase gui database.db@Al\n\nwhere everything after the @ is interpreted as a query.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Opening a database using a Python script\nTo open a database using Python, we can use the :class:`ase.database.connect`\n method which returns a database object from which we can make selections:\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "db = connect(dbfile)\nfor row in db.select():\n atoms = row.toatoms()\n print(atoms)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can make selections in the database using ``db.select(some_selection)``\nwhich returns all rows matching ``some_selection``. In this case\n``some_selection`` was omitted which means that we select all rows in\nthe database. For each row the associated :class:`ase.Atoms` objects\nis retrieved by using the ``row.toatoms()`` method.\n\n.. admonition:: Hint\n\n In order to see the documentation for a particular\n python function import it and use the ``help`` function.\n For example\n ::\n\n from ase.db import connect\n db = connect('database.db')\n help(db.select)\n\n\n will show the documentation for the select method of the database\n object. Another useful function is ``dir`` which shows\n all attributes of a python object. For example\n ::\n\n from ase.db import connect\n db = connect('database.db')\n row = db.select(id=1)[0]\n dir(row)\n\n will show all attributes of the row object.\n\n\n Using a python script, print the formula for each row in your database.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Write new entries to a database using Python\nNext, we loop through all materials, relax them\n(see exercise \"Structure Optimization\")\nand save the relaxed structure as a new entry in the database with an\nadded column relaxed equal to ``True`` that we can use later for selecting\nonly these materials. A new entry in the database can be written using the\n``write()`` method of a database object.\n\n.. admonition:: Hint\n\n To relax crystals we have to specify that the cell parameters\n should be relaxed as well. This is done by wrapping\n :class:`ase.filters.FrechetCellFilter` around the atoms object like\n ::\n\n filter = FrechetCellFilter(atoms)\n\n and feeding ``filter`` into the optimization routine see\n ``help(FrechetCellFilter)`` for more explanation.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for row in db.select():\n atoms = row.toatoms()\n calc = EMT()\n atoms.calc = calc\n atoms.get_stress()\n filter = FrechetCellFilter(atoms)\n opt = BFGS(filter)\n opt.run(fmax=0.05)\n db.write(atoms=atoms, relaxed=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here, we are using EMT, which is a force-field calculator. This is not\naccurate enough for production level computations. For production level\ncomputations, self consistent calculations, such as using GPAW, have to\nbe used.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Adding data to existing database\nNow we want to calculate some data and include the data in the database\nwhich can be done using the ``update`` method of the database object.\nThen use the ``atoms.get_potential_energy()`` method to calculate the\nenergy of the materials and store it under the ``energy`` keyword.\n\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "for row in db.select(relaxed=True):\n atoms = row.toatoms()\n calc = EMT()\n atoms.calc = calc\n e = atoms.get_potential_energy()\n db.update(row.id, data={'energy': e})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we can inspect the database again using the\n``ase db`` command. To see the new column ``bandgap`` you can display all\ncolumns using the ``-c++`` option::\n\n $ ase db database -c++\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Browsing data\nThe database can also be visualized in a browser by using::\n\n $ ase database database.db -w\n $ firefox http://0.0.0.0:5000/\n\nThis opens a local webserver which can be opened in firefox like above. The\nlayout can be customized further than our simple example however this would\nprobably be too much for now. To see a more advanced example of such a web\ninterfaced database in action you can check out the 2D database\nhttps://cmrdb.fysik.dtu.dk/c2db.\n\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced tutorial\nAn additional tutorial using the ASE databases for adsorbates on metals\ncan be found at https://ase-lib.org/tutorials/db/db.html.\n\n" ] } ], "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.13.7" } }, "nbformat": 4, "nbformat_minor": 0 }