General AuToGraFS Scripting concepts
************************************

AuToGraFS relies on the concept of underlying nets common to many
structures. These nets, or topologies, can be found in the RCSR and
EPINET databases. Once implemented, AuToGraFS will follow these
blueprints to generate a framework from building units of compatible
geometries. Since these geometries are ideal objects and most chemical
structures are distorted, an optimization step using UFF is necessary
for the building units to "snap into place". Correct handling of
bonding information and UFF atom types are crucial to the generation
of correct structures.


Components of AuToGraFS
=======================


The Fragment class
------------------

This is a slightly modified version of the native ASE Atoms object,
designed to hold essential data for UFF post-processing. This includes
the UFF atom types and the bonding information.

   from scm.autografs.fragment import Fragment
   from ase import Atoms

   line = Fragment(ase.Atoms("X2", positions=...),
                   mmtypes=["H_", "H_"],
                   bonds = [[0,0,1],[0,0,1],[1,1,0]],
                   shape="linear",
                   unit=None,
                   name="a_line_has_no_name")

Where mmtypes is a list of the UFF atom type symbols, ordered as the
corresponding atoms in the structure, and bonds is a symmetric numpy
array of size equal to the number of atoms. The i,j elements in the
bonds array are the bond order between atom i and atom j of the
structure. These bond orders should follow the UFF conventions (1.5
for aromatic, 0.5 for coordination bonds, 0.001 for hydrogen
bonds...). The shape holds information for AuToGraFS about the
connectivity of the fragment. Each dummy atom, with symbol "X" in ASE,
represents a point of connection between two fragments. In the above
example, the shape is clearly "linear". This is used to check
compatibility between a fragment and a given topology. The unit of a
fragment is set internally by AuToGraFS and is of no interest here.
The name of a fragment is used only for logging purposes. Individual
building blocks of a framework are manipulated through the Fragment
class. It is possible to export a fragment from the GUI using edit ->
framework -> export fragment. If the UFF atom types are not specified,
an automatic typing script will take care of it.


The Model class
---------------

This is a container class that holds in one place the topology of a
framework and the correctly positioned fragments. Most of the
postprocessing methods found in AuToGraFS are Model methods.

   from scm.autografs import *

   model = autografs.Model(...)

   # view the framework in adfinput. set clean to False to keep dummy atoms.
   model.view(clean=True, verbose=True)

   # write the name.ams and name.run files
   model.write(name="framework", clean=True, verbose=True)

   # returns a Fragment, with correct bonding information and mmtypes
   # if indices is True, it also returns the index of the corresponding fragment in the model for each atom
   atoms = model.get_atoms(self, clean=False, indices=False)

   # returns a supercell of the framework as a Fragment
   supercell = model * (2,2,2)

   # deletes a fragment in the framework. if no index is given, the fragment will be chosen at random.
   # the defects will cap with hydrogen the empty spaces. returns a Fragment
   # here, a linker at random will be deleted
   model.insert_defect(indices=None, centers=0, linkers=1)

   # flip a linear object
   model.flip_fragment(index=the_fragment_index)

   # rotates a linear object around its axis by angle in degrees
   model.rotate_fragment(index=the_fragment_index, angle=85.0)

   # Will add a functional group to the selected fragment on a random hydrogen
   # if and only if the hydogen is connected to a carbon.
   # for more precise handling, use the GUI for now.
   model.functionalize_fragment(functional_group="NH2", index=the_fragment_index)


The Autografs class
-------------------

This class is the builder in itself. Given a path to a database of
building units in .inp format (exportable via the GUI), it will
generate any valid framework from a topology name, a center and linker
name or objects, and optionally a pillar name or object. The linkers,
centers, and pillars objects have to be passed as Fragment.

   from scm.autografs import *
   from random import choice

   # create the generator and update the database of building units
   mofgen = autografs.Autografs(refresh_database=True, verbose=True, path="path/to/my/fragments/")

   # choose a topology from the available one given no center or linkers
   topologies = mofgen.get_available_topologies(center=None, linker=None)
   topology = choice(topologies)

   # choose a center in the list of available centers for the topology
   centers = mofgen.get_available_centers(topology=topology, linker=None)
   center = choice(centers)

   # choose a linker in the list of available linkers for the topology and center
   linkers = mofgen.get_available_linkers(topology=topology,  center=center)
   linker = choice(linkers)

   # modify the linker by changing all hydrogens to fluorine
   linker_structure = mofgen.database[linker]
   linker_symbols = linker_structure.get_chemical_symbols()
   linker_structure.set_chemical_symbols(["F" if l=="H" else l for l in linker_symbols])

   # generate the framework using multiprocessing tools and automatic scaling of unit cell
   framework = mofgen.make(lable="my_framework", topology=topology, center=center, linker=linker, pillar=None, form_factor=None, parallel=True)

   # visualize in adfinput
   framework.view()

Do not forget to run a quick UFF optimization after generation to
optimize the lattice and fragment into an optimal configuration.


About the databases of building units
=====================================

AuToGraFS uses both a binary database format and structures in the
DemonNano file format from which the binary is compiled. To ask
AuToGraFS to use a custom directory containing .inp files, simply pass
the directory to the path argument when initializing the constructor.
The ".inp" file format should be formatted like the following example.

   Data: SBUtype = linker
   Data: shape = linear
   Data: name = benzene
   GEOMETRY CARTESIAN
   C       0.00000000     -1.39103633      0.00000000     MMTYPE=C_R   QMMM=MM BOND=2/1.5:6/1.5:12/1.0
   C      -1.20606758     -0.69440959      0.00000000     MMTYPE=C_R   QMMM=MM BOND=1/1.5:3/1.5:8/1.0
   C      -1.20606758      0.69440959     -0.00000000     MMTYPE=C_R   QMMM=MM BOND=2/1.5:4/1.5:10/1.0
   C      -0.00000000      1.39103633      0.00000000     MMTYPE=C_R   QMMM=MM BOND=3/1.5:5/1.5:11/1.0
   C       1.20606758      0.69440959      0.00000000     MMTYPE=C_R   QMMM=MM BOND=4/1.5:6/1.5:7/1.0
   C       1.20606758     -0.69440959     -0.00000000     MMTYPE=C_R   QMMM=MM BOND=1/1.5:5/1.5:9/1.0
   H       2.02806392      1.16933783      0.00000000     MMTYPE=H_    QMMM=MM BOND=5/1.0
   H      -2.02806392     -1.16933783      0.00000000     MMTYPE=H_    QMMM=MM BOND=2/1.0
   H       2.02806392     -1.16933783      0.00000000     MMTYPE=H_    QMMM=MM BOND=6/1.0
   H      -2.02806392      1.16933783      0.00000000     MMTYPE=H_    QMMM=MM BOND=3/1.0
   X       0.00000000      2.09099413      0.00000000     MMTYPE=H_    QMMM=MM BOND=4/1.0
   X       0.00000000     -2.09099413      0.00000000     MMTYPE=H_    QMMM=MM BOND=1/1.0
   END


Using the overhauled Atom Typer
===============================

Both AuToGraFS and the GUI now use a new Python library for the
assignment of UFF types to atoms and generation of the bonding matrix.
The process goes as follows:

   from scm.autografs import atomtyper

   # instantiate the typer on a readable molecule file (e.g: "mol.cif")
   typer = atomtyper.MolTyper("path/of/fileToType")

   # choose the UFF library. options are uff and uff4mof
   library = read_db("uff4mof")

   # actual typing is done here
   typer.type_mol(library)

   # prints the bond matrix as a numpy array
   # item i, j of matrix is the bond order between atoms i and j
   print typer.get_guibonds()

   # print a list of UFF types in order
   print typer.get_mmtypes()

   # write a SCM-UFF input file with correct info
   typer.structure.write(name="mytypedmol")
