{
"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",
" Cartesian\n",
"\n",
" \n",
" | \n",
" atom | \n",
" x | \n",
" y | \n",
" z | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" O | \n",
" 0.000000 | \n",
" 0.0 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 2 | \n",
" H | \n",
" 0.758602 | \n",
" 0.0 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 3 | \n",
" H | \n",
" 0.260455 | \n",
" 0.0 | \n",
" -0.872893 | \n",
"
\n",
" \n",
" 4 | \n",
" O | \n",
" 3.000000 | \n",
" 0.5 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 5 | \n",
" H | \n",
" 3.758602 | \n",
" 0.5 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 6 | \n",
" H | \n",
" 3.260455 | \n",
" 0.5 | \n",
" -0.872893 | \n",
"
\n",
" \n",
"
\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",
" atom | \n",
" x | \n",
" y | \n",
" z | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" 2 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" 3 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" 4 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" 5 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
" 6 | \n",
" True | \n",
" False | \n",
" False | \n",
" False | \n",
"
\n",
" \n",
"
\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",
" atom | \n",
" x | \n",
" y | \n",
" z | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" 2 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" 3 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" 4 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" 5 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
" 6 | \n",
" True | \n",
" True | \n",
" True | \n",
" True | \n",
"
\n",
" \n",
"
\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",
" Cartesian\n",
"\n",
" \n",
" | \n",
" atom | \n",
" x | \n",
" y | \n",
" z | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" O | \n",
" $x$ | \n",
" 0.0 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 2 | \n",
" H | \n",
" $x + 1$ | \n",
" 0.0 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 3 | \n",
" H | \n",
" $x + 2$ | \n",
" 0.0 | \n",
" -0.872893 | \n",
"
\n",
" \n",
" 4 | \n",
" O | \n",
" $x + 3$ | \n",
" 0.5 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 5 | \n",
" H | \n",
" $x + 4$ | \n",
" 0.5 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 6 | \n",
" H | \n",
" $x + 5$ | \n",
" 0.5 | \n",
" -0.872893 | \n",
"
\n",
" \n",
"
\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",
" Cartesian\n",
"\n",
" \n",
" | \n",
" atom | \n",
" x | \n",
" y | \n",
" z | \n",
"
\n",
" \n",
" \n",
" \n",
" 1 | \n",
" O | \n",
" 2.0 | \n",
" 0.0 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 2 | \n",
" H | \n",
" 3.0 | \n",
" 0.0 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 3 | \n",
" H | \n",
" 4.0 | \n",
" 0.0 | \n",
" -0.872893 | \n",
"
\n",
" \n",
" 4 | \n",
" O | \n",
" 5.0 | \n",
" 0.5 | \n",
" 0.000000 | \n",
"
\n",
" \n",
" 5 | \n",
" H | \n",
" 6.0 | \n",
" 0.5 | \n",
" 0.504284 | \n",
"
\n",
" \n",
" 6 | \n",
" H | \n",
" 7.0 | \n",
" 0.5 | \n",
" -0.872893 | \n",
"
\n",
" \n",
"
\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
}