{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Introduction" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Welcome to the tutorial for ChemCoord (http://chemcoord.readthedocs.org/)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The manipulation of the coordinates is a lot easier, if you can view them on the fly.\n", "So please install a molecule viewer, which opens xyz-files. \n", "A non complete list includes:\n", "[molcas gv](http://www.molcas.org/GV/),\n", "[avogadro](https://avogadro.cc/),\n", "[vmd](http://www.ks.uiuc.edu/Research/vmd/), and\n", "[pymol](https://www.pymol.org/)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Cartesian" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import chemcoord as cc\n", "from chemcoord.xyz_functions import get_rotation_matrix\n", "import numpy as np\n", "import time" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "water = cc.Cartesian.read_xyz('water_dimer.xyz', start_index=1)\n", "small = cc.Cartesian.read_xyz('MIL53_small.xyz', start_index=1)\n", "middle = cc.Cartesian.read_xyz('MIL53_middle.xyz', start_index=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's have a look at it:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Cartesian
atomxyz
1O0.0000000.00.000000
2H0.7586020.00.504284
3H0.2604550.0-0.872893
4O3.0000000.50.000000
5H3.7586020.50.504284
6H3.2604550.5-0.872893
\n", "
" ], "text/plain": [ " atom x y z\n", "1 O 0.000000 0.0 0.000000\n", "2 H 0.758602 0.0 0.504284\n", "3 H 0.260455 0.0 -0.872893\n", "4 O 3.000000 0.5 0.000000\n", "5 H 3.758602 0.5 0.504284\n", "6 H 3.260455 0.5 -0.872893" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "water" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is also possible to open it with an external viewer. I use Molcas ``gv.exe`` so you have to change it accordingly to your program of choice." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "water.view(viewer='gv.exe')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To make this setting permament, execute:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "cc.settings['defaults']['viewer'] = 'gv.exe' # replace by your viewer of choice" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The slicing operations are the same as for ``pandas.DataFrames``. (http://pandas.pydata.org/pandas-docs/stable/indexing.html)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the ``'x'`` axis is of particular interest you can slice it out with:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1 0.000000\n", "2 0.758602\n", "3 0.260455\n", "4 3.000000\n", "5 3.758602\n", "6 3.260455\n", "Name: x, dtype: float64" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "water['x']\n", "# or explicit label based indexing\n", "water.loc[:, 'x']\n", "# or explicit integer based indexing\n", "water.iloc[:, 1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With boolean slicing it is very easy to cut all the oxygens away:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "water[water['atom'] != 'O'].view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This can be combined with other selections:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "water[(water['atom'] != 'O') & (water['x'] < 1)].view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Returned type" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The indexing behaves like Indexing and Selecting data in\n", "[Pandas]().\n", "You can slice with `Cartesian.loc[key]`, `Cartesian.iloc[keys]`, and `Cartesian[key]`.\n", "The only question is about the return type.\n", "If the information in the columns is enough to draw a molecule,\n", "an instance of the own class (e.g. `Cartesian`)\n", "is returned.\n", "If the information in the columns is not enough to draw a molecule, there \n", "are two cases to consider:\n", "\n", "* A `pandas.Series` instance is returned for one dimensional slices\n", "* A `pandas.DataFrame` instance is returned in all other cases:\n", "\n", " molecule.loc[:, ['atom', 'x', 'y', 'z']] returns a `Cartesian`.\n", "\n", " molecule.loc[:, ['atom', 'x']]`` returns a `pandas.DataFrame`.\n", "\n", " molecule.loc[:, 'atom']`` returns a `pandas.Series`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sideeffects and Method chaining" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Two general rules are: \n", "1. **All functions are sideeffect free unless stated otherwise in the documentation**.\n", "2. **Where possible the methods return an instance of the own class, to allow method chaining**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Have a look at the unmodified molecule" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [], "source": [ "middle.view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Chain the methods:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "middle.cut_sphere(radius=5, preserve_bonds=False).view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The molecule itself remains unchanged." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "middle.view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Chemical bonds" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One really important method is ``get_bonds()``. \n", "It returns a connectivity table, which is represented by a dictionary.\n", "Each index points to set of indices, that are connected to it." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: {2, 3}, 2: {1}, 3: {1}, 4: {5, 6}, 5: {4}, 6: {4}}" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "water.get_bonds()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now the focus switches to another molecule (MIL53_middle)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's explore the coordinationsphere of the Cr atom with the index 7." ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "for i in range(3):\n", " middle.get_coordination_sphere(13, n_sphere=i, only_surface=False).view()\n", " time.sleep(1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Binary operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Mathematical Operations:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Binary operators are supported in the logic of the scipy stack, but you need\n", "python3.x for using the matrix multiplication operator ``@``.\n", "\n", "The general rule is that mathematical operations using the binary operators\n", "``(+ - * / @)`` and the unary operatos ``(+ - abs)``\n", "are only applied to the ``['x', 'y', 'z']`` columns.\n", "\n", "**Addition/Subtraction/Multiplication/Division**:\n", "If you add a scalar to a Cartesian it is added elementwise onto the\n", "``['x', 'y', 'z']`` columns.\n", "If you add a 3-dimensional vector, list, tuple... the first element of this\n", "vector is added elementwise to the ``'x'`` column of the\n", "Cartesian instance and so on.\n", "The last possibility is to add a matrix with\n", "``shape=(len(Cartesian), 3)`` which is again added elementwise.\n", "The same rules are true for subtraction, division and multiplication.\n", "\n", "**Matrixmultiplication**:\n", "Only leftsided multiplication with a matrix of ``shape=(n, 3)``,\n", "where ``n`` is a natural number, is supported.\n", "The usual usecase is for example\n", "``np.diag([1, 1, -1]) @ cartesian_instance``\n", "to mirror on the x-y plane.\n", "Note that if ``A`` is the matrix which is multiplied from the left, and ``X`` is the ``shape=(n, 3)``-matrix\n", "consisting of the ``['x', 'y', 'z']`` columns. The actual calculation is:\n", "``(A @ X.T).T``" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "(water + 3).view()" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "(get_rotation_matrix([1, 0, 0], np.radians(90)) @ water).view()\n", "# If you use python2.x the @ operator is not supported. then you have to use xyz_functions.dot" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Comparison:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The comparison operators ``==`` and ``!=`` are supported and require molecules indexed in the same way:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In some cases it is better to test for numerical equality $ |a - b| < \\epsilon$. This is done using\n", "``allclose`` or ``isclose`` (elementwise)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
atomxyz
1TrueFalseFalseFalse
2TrueFalseFalseFalse
3TrueFalseFalseFalse
4TrueFalseFalseFalse
5TrueFalseFalseFalse
6TrueFalseFalseFalse
\n", "
" ], "text/plain": [ " atom x y z\n", "1 True False False False\n", "2 True False False False\n", "3 True False False False\n", "4 True False False False\n", "5 True False False False\n", "6 True False False False" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "water == water + 1e-15" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
atomxyz
1TrueTrueTrueTrue
2TrueTrueTrueTrue
3TrueTrueTrueTrue
4TrueTrueTrueTrue
5TrueTrueTrueTrue
6TrueTrueTrueTrue
\n", "
" ], "text/plain": [ " atom x y z\n", "1 True True True True\n", "2 True True True True\n", "3 True True True True\n", "4 True True True True\n", "5 True True True True\n", "6 True True True True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cc.xyz_functions.isclose(water, water + 1e-15)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "cc.xyz_functions.allclose(water, water + 1e-15)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Symbolic evaluation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is possible to use symbolic expressions from sympy." ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import sympy\n", "sympy.init_printing()\n", "x = sympy.Symbol('x')" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "symb_water = water.copy()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": true }, "outputs": [], "source": [ "symb_water['x'] = [x + i for i in range(len(symb_water))]" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Cartesian
atomxyz
1O$x$0.00.000000
2H$x + 1$0.00.504284
3H$x + 2$0.0-0.872893
4O$x + 3$0.50.000000
5H$x + 4$0.50.504284
6H$x + 5$0.5-0.872893
\n", "
" ], "text/plain": [ " atom x y z\n", "1 O x 0.0 0.000000\n", "2 H x + 1 0.0 0.504284\n", "3 H x + 2 0.0 -0.872893\n", "4 O x + 3 0.5 0.000000\n", "5 H x + 4 0.5 0.504284\n", "6 H x + 5 0.5 -0.872893" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symb_water" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Cartesian
atomxyz
1O2.00.00.000000
2H3.00.00.504284
3H4.00.0-0.872893
4O5.00.50.000000
5H6.00.50.504284
6H7.00.5-0.872893
\n", "
" ], "text/plain": [ " atom x y z\n", "1 O 2.0 0.0 0.000000\n", "2 H 3.0 0.0 0.504284\n", "3 H 4.0 0.0 -0.872893\n", "4 O 5.0 0.5 0.000000\n", "5 H 6.0 0.5 0.504284\n", "6 H 7.0 0.5 -0.872893" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "symb_water.subs(x, 2)" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "symb_water.subs(x, 2).view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Alignment" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true }, "outputs": [], "source": [ "moved = get_rotation_matrix([1, 2, 3], 1.1) @ middle + 15" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": true }, "outputs": [], "source": [ "moved.view()" ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": true }, "outputs": [], "source": [ "m1, m2 = middle.align(moved)" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": true }, "outputs": [], "source": [ "cc.xyz_functions.view([m1, m2])\n", "# If your viewer of choice does not support molden files, you have to call separately:\n", "# m1.view()\n", "# m2.view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Symmetry" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "It is possible to detect the point group and symmetrize a molecule.\n", "Let's distort a $C_{2,v}$ symmetric molecule and symmetrize it back:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "np.random.seed(77)\n", "dist_molecule = small.copy()\n", "dist_molecule += np.random.randn(len(dist_molecule), 3) / 25" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "C1" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dist_molecule.get_pointgroup(tolerance=0.1)" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true }, "outputs": [], "source": [ "eq = dist_molecule.symmetrize(max_n=25, tolerance=0.3, epsilon=1e-5)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "C2v" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eq['sym_mol'].get_pointgroup(tolerance=0.1)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a, b = small.align(dist_molecule)\n", "a, c = small.align(eq['sym_mol'])\n", "d1 = (a - b).get_distance_to()\n", "d2 = (a - c).get_distance_to()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": true }, "outputs": [], "source": [ "cc.xyz_functions.view([a, b, c])\n", "# If your viewer of choice does not support molden files, you have to call separately:\n", "# a.view()\n", "# b.view()\n", "# c.view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, the symmetrised molecule is a lot more similar to the original molecule.\n", "The average deviation from the original positions decreased by 35 %." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/latex": [ "$$0.34609079359070377$$" ], "text/plain": [ "0.34609079359070377" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(d1['distance'].sum() - d2['distance'].sum()) / d1['distance'].sum()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [default]", "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.2" } }, "nbformat": 4, "nbformat_minor": 1 }