CageBreaks: a python library for identifying cage-breaking rearrangements from
configurations of a supercooled liquid.
Sam Niblett, published July 2016

This is a collection of python utilities for reading atomic/molecular
coordinates for systems of supercooled liquids, and comparing pairs of
configurations to identify which atoms/molecules undergo cage-breaking
transitions between the two configurations.

We have aimed to keep the code general and flexible, so that it may be easily
adapted to read different input formats and to handle a variety of systems.
The definition of a "cage break" is also easy to adapt, although the code has
been designed to use the definitions presented in the following two papers:

V. K. de Souza, V.K. and D. J. Wales, J. Chem. Phys., 129, 164507 (2008)
and
S. P. Niblett, V. K. de Souza, J. D. Stevenson, and D. J. Wales, J. Chem.
Phys. 145 (2), 024505 (2016)

At the time of writing, only the core functions are ready for public release
and there is currently no stand-alone documentation. We hope to release all
the code used to produce the 2016 paper, and generate some proper
documentation, in the near future. Until then, please use the comments and
docstrings in the code, which are hopefully complete and comprehensive.

This code will also be made available for external contribution via a github
repository. A link will be added to this file when the repository is set up.


Installation
------------
The library does not require much installation. Simply copy the source code to 
your install directory, run the setup.sh script and add the directory to your 
PYTHONPATH. Importing the package from a python script will then give access 
to most of the useful routines.

Prerequisites:
- numpy
- f2py

If you wish to perform calculations on OTP or similar molecular systems, you
may need to install pele, the Python Energy Landscape Explorer, to access some
of its utilities. pele is available to clone from github:
https://github.com/pele-python/pele

If you are using CageBreaks with atomic systems only, you may comment out any
lines which require pele in order to get the code to run.

We will attempt to remove this dependency in the future.


Contents
--------

setup.sh : simple script to compile the fortran shared objects

cagebreaks.py : contains the main manager class, which takes configurations of 
                the system (either in pairs or as a sequence) and returns a 
                list of cage-breaking atoms for that pair and/or writes this 
                list to a file

checkcb.py : contains classes which manage individual pairs of configurations 
             and compute the cage breaks

cbrule.py : contains classes which check a particular atom/molecule to identify
            whether it has undergone a cage break between the two configurations

reversal_manager.py : contains classes which identify and record chains of 
                      reversed cage breaks

checkneighs.py : a library of different methods for identifying nearest-
                      neighbour particles for each atom/molecule in a 
                      particular configuration

distances.py : a library of functions for calculating different distance 
               metrics between two atoms/molecules or two configurations

CellLists.py : a simple implementation of the cell lists procedure to 
               reduce the number of distance calculations required to 
               compute nearest neighbours.

read_configurations.py : a library of classes for reading configurations from 
                         plaintext coordinate files with no special formatting.

read_minimum.f90 : fortran subroutine which can be compiled into a python 
                   shared object. Extracts coordinates of a potential energy
                   minimum from a PATHSAMPLE-style stationary point 
                   database. If the system is molecular, centre-of-mass 
                   coordinates are returned

read_minimum_atomistic.f90 : As the previous subroutine, but in the case of 
                             molecular systems, atomistic coordinates are 
                             returned. For atomic systems, these two 
                             subroutines are equivalent

sann.f90 : fortran implementation of the solid angle nearest-neighbour 
           algorithm of van Meel et al (see source code for citation). Suitable
           for compilation into a python shared object.


Usage
-----

We recommend that the routines in this library should only be accessed via the
cb_manager class (in cagebreaks.py). An example of the workflow you might 
follow is given at the bottom of cagebreaks.py.

First, select a distance metric from distances.py.

Create a checkneighs object from a class which uses your required
definition of nearest neighbours (e.g. cutoff_checkneighs). This will require
your distance metric as an argument.

Create a cb_rule object from a class which uses your required definition of a
cage break (e.g. binary_neighchange_dcut_cbrule for BLJ). Specify threshold
neighbour changes and other parameters here. If you wish to calculate reversal
chains, you must also define a reversal_manager object and pass it in here.

Create a checkcb object (e.g. checkcb) which takes both the checkneighs and
cb_rule objects as parameters.

Create a cb_manager object with your checkcb object as a parameter.

You may then pass configurations to your cb_manager object either as 
independent pairs of configurations (via the process_pair method) or as a
chain of successive configurations (first configuration passed in using 
start_chain, subsequent configurations using continue_chain). At each step,
a dictionary will be returned with keys that represent the indices of atoms
which undergo cage breaks and values which are cage_break objects containing 
information about that event.

If you set the outname parameter for the cb_manager object then information on
the cage breaks will be written to a file with name=outname. Our tools for
reading and using these files will be added to the repository at a later stage.

If using the configuration chain method, you may wish to return cage breaks 
only at the end of any reversal chains for the atom in question. If this is the
case, you must specify a reversal_manager and set 
reversal_manager.terminated_only=True. A cage break will not be included in the
returned dictionary at the timestep where it is identified, but will be
returned as soon as we can be sure that its reversal chain is terminated (i.e.
when the same atom undergoes a cage break which is not geometrically related to
the previous one).
