AuToGraFS Examples
******************

The following examples are compatible with all calculators within the
Amsterdam Modeling Suite. Any Python script utilizing these libraries
should be executed using the "$AMSBIN/amspython" binary.

   "$AMSBIN/amspython" code.py

These examples illustrate the construction of various metal-organic
frameworks (MOFs) using their secondary building units and Reticular
Chemistry Structure Resource (RCSR) topological codes. They are
specifically designed to work with the version of AuToGraFS included
in SCM.


Simplest approach
=================

We will construct the structures of MOF-5 and UIO66 using two
different approaches. In AuToGraFS, you have the option to build a MOF
using secondary building units from the default database or by
supplying your own building units. We will employ both approaches to
give users greater autonomy in constructing their MOFs.


1.1 Using default database
--------------------------

In SCM, there are two default databases available for AuToGraFS. The
first database comprises approximately 82 secondary building units and
serves as the default path for AuToGraFS. You can directly access this
path from "amshome/atomicdata/autografs/database". The following
scripts offer the simplest method for constructing any MOF.

   # MOF-5/IRMOF-1
   from scm.autografs import autografs

   # Initialize the model generator
   mofgen = autografs.Autografs(sbu_path=None)

   # The secondary building units should be provided as a list.
   sbu_names = ["Benzene_linear", "Zn_mof5_octahedral"]

   topology_name = "pcu"
   mof = mofgen.make(topology_name=topology_name, sbu_names=sbu_names)

   # The MOF generated can be viewed directly using the ASE visualizer as follows
   mof.view()

   # You can also choose to write the mof to a gin (GULP) input file or any ASE input format.

   # Writing to .gin
   mof.write("MOF-5", "gin")

   # Writing to cif
   mof.write("MOF-5", "cif")


Checking list of secondary building units in the default database and topologies
--------------------------------------------------------------------------------

You can quickly access the secondary building units in the default
database with the following command: "mofgen.sbu". Additionally, the
topologies can be accessed as follows: "mofgen.topologies".


1.2 Using same default database as the gui
------------------------------------------

The GUI utilizes an updated database containing 5483 secondary
building units that are shipped with SCM. This data can be found in
"~/.scm_gui/autografs/default" after the first time the GUI is used to
build a MOF. The database can also be manually extracted from
"$AMSHOME/atomicdata/autografs/database/database.tar.gz" into there.
Custom built secondary building units from the GUI are stored in
"~/.scm_gui/autografs/custom". We can leverage the GUI default
database as follows:

   import os

   from scm.autografs import autografs

   sbu_path = os.path.join(os.path.expanduser("~"), ".scm_gui", "autografs", "default")
   mofgen = autografs.Autografs(sbu_path=sbu_path)

   sbu_names = ["Bis_phenylethynylbenzene_linear", "Zn_mof5_octahedral"]
   topology_name = "acs"

   mof = mofgen.make(topology_name=topology_name, sbu_names=sbu_names)
   mof.view()

   # UIO-66
   sbu_names = ["UIO66_Zr_icosahedral", "Benzene_linear"]
   topology_name = "fcu"

   mof = mofgen.make(topology_name=topology_name, sbu_names=sbu_names)
   mof.view()
   mof.write("UIO66", "cif")


1.3 Finding suitable topologies for a given set of SBUs
-------------------------------------------------------

One common problem often revolves around determining which topologies
would be suitable for a given set of building units. This situation
becomes particularly intriguing when you’ve synthesized a new MOF and
possess knowledge of the building units used, but are not sure of the
precise structure. Identifying the range of available topologies can
facilitate the construction of all potential MOFs stemming from these
building units. The PXRD from these hypothetical structures can then
be compared with the experimental diffraction patterns to infer the
structure of the synthesized MOF. The following example provides a
straightforward illustration, which can be adapted to more complex
systems.

   from scm.autografs import autografs

   mofgen = autografs.Autografs()
   print(mofgen.sbu)

   sbu_names = ["Pyrene_linear", "Zn_mof5_octahedral"]

   list_of_available_topologies = mofgen.list_available_topologies(from_list=sbu_names)
   print(list_of_available_topologies)

   for idx, topology_name in enumerate(list_of_available_topologies[:10]):
       try:
           mofgen.set_topology(topology_name=topology_name)
           print(topology_name)
           mof = mofgen.make(sbu_names=sbu_names)
           mof.view()
           mof.write(topology_name, "cif")
       except Exception:
           pass


1.4 Finding available building units for a given topology
---------------------------------------------------------

Similarly, one may be interested in finding possible building units
that can be used to construct a MOF with a specific topology. This
becomes valuable when investigating stability or conducting studies on
isoreticular MOFs, where one aims to analyze the properties of a given
topology. In such cases, it is essential to construct hypothetical
MOFs based on a specified topology.

   from scm.autografs import autografs

   mofgen = autografs.Autografs()

   topology_name = "acs"

   available_sbus = mofgen.list_available_sbu(topology_name=topology_name, coercion=True)

   print(available_sbus)
   # {
   #     (0, 1): [
   #         "Al_trimeric_prism",
   #         "Benzene_hexagonal",
   #         "H6BHEHPI_Yaghi_hexagonal",
   #         "Persulfurated_benzene_hexagonal",
   #         "ReS_cluster_octahedral",
   #         "Zn_mof5_octahedral",
   #         "Zn_octahedral_paddlewheel",
   #     ],
   #     (14, 15, 16, 17, 18, 19): [
   #         "Acetylene_linear",
   #         "Benzene_linear",
   #         "Benzil_linear",
   #         "Benzo_bis_dioxaborole_linear",
   #         "Benzodithiophene_linear",
   #         "Benzothiadiazole_linear",
   #         "Betabinaphtol_linear",
   #         "Bicyclooctane_linear",
   #         "Biphenyl_linear",
   #         "Bipyridine_linear",
   #         "Bis_phenylethynylbenzene_linear",
   #         "Butane_linear",
   #         "Chrysene_linear",
   #         "Cubane_linear",
   #         "DCDPBN_Yaghi_linear",
   #         "DPMDBDA_linear",
   #         "Decapentene",
   #         "Diethinylbenzene_linear",
   #         "Diphenylbutadiyne_linear",
   #         "Diphenylperylimide_linear",
   #         "Fluorenone_linear",
   #         "H4DH11PhDC_Yaghi_linear",
   #         "H4DH9PhDC_Yaghi_linear",
   #         "Naphtalene_linear",
   #         "Pentaphenyl_linear",
   #         "Peropyrene_linear",
   #         "Phenazine_linear",
   #         "Phenylethynylbenzene_linear",
   #         "Pyrene_linear",
   #         "Stilbene_linear",
   #         "Tetracene_linear",
   #         "Tetraphenyl_linear",
   #         "Thienothiophene_linear",
   #         "Triphenyl_linear",
   #         "Zn_porphyrin_linear",
   #     ],
   # }

   selected_sbu = ["Al_trimeric_prism", "Acetylene_linear"]

   mof = mofgen.make(topology_name=topology_name, sbu_names=selected_sbu)
   mof.view()


N.B
---

There are a few important things to note regarding the following line
of code: "available_sbus =
molgen.list_available_sbu(topology_name=topology_name,
coercion=True)"


i. Coercion
~~~~~~~~~~~

When setting coercion to True, AutoGraFS is compelled to match only
SBUs that can combine based on their number of points of extension/
number of dummies/coordination number of SBUs. This feature is
beneficial as it ensures a strong likelihood of building a MOF by
combining outputs from "available_sbus".


ii. available_sbus
~~~~~~~~~~~~~~~~~~

The "available_sbus" is a dictionary with keys represented as tuples.
It is crucial to use items from different keys as centers and linkers.
For instance:

   available_sbus = {(0, 1): ['Al_trimeric_prism', 'Benzene_hexagonal', 'H6BHEHPI_Yaghi_hexagonal', 'Persulfurated_benzene_hexagonal', 'ReS_cluster_octahedral', 'Zn_mof5_octahedral', 'Zn_octahedral_paddlewheel'], (14, 15, 16, 17, 18, 19): ['Acetylene_linear', 'Benzene_linear', 'Benzil_linear', 'Benzo_bis_dioxaborole_linear', 'Benzodithiophene_linear', 'Benzothiadiazole_linear', 'Betabinaphtol_linear', 'Bicyclooctane_linear', 'Biphenyl_linear', 'Bipyridine_linear', 'Bis_phenylethynylbenzene_linear', 'Butane_linear', 'Chrysene_linear', 'Cubane_linear', 'DCDPBN_Yaghi_linear', 'DPMDBDA_linear', 'Decapentene', 'Diethinylbenzene_linear', 'Diphenylbutadiyne_linear', 'Diphenylperylimide_linear', 'Fluorenone_linear', 'H4DH11PhDC_Yaghi_linear', 'H4DH9PhDC_Yaghi_linear', 'Naphtalene_linear', 'Pentaphenyl_linear', 'Peropyrene_linear', 'Phenazine_linear', 'Phenylethynylbenzene_linear', 'Pyrene_linear', 'Stilbene_linear', 'Tetracene_linear', 'Tetraphenyl_linear', 'Thienothiophene_linear', 'Triphenyl_linear', 'Zn_porphyrin_linear']}

"key = (0, 1)" Items listed here represent the center nodes or
centers.

"key = (14, 15, 16, 17, 18, 19)" Items listed here should be used as
linkers.

For example, incorrect usage like:

"sbu_names != ['Al_trimeric_prism', 'Benzene_hexagonal']" will cause
the code to fail.

Instead, one should select items from different keys, such as:

"sbu_names = ['Al_trimeric_prism', 'Benzo_bis_dioxaborole_linear']"

or

"sbu_names = ['Benzene_hexagonal', 'DPMDBDA_linear']" note that this
will build a COF instead of a MOF.


Making SURMOFs
==============

Surface Mounted Metal-Organic Frameworks are a class of materials that
combine organic linkers and metal ions or clusters to form highly
porous structures. SURMOFs are unique because they can be grown as
thin films directly on substrates, allowing for their integration into
various devices and applications.

Simply put, these are pillared MOFs that are horizontally linked with
a given linker and vertically linked with another linker. The
following examples can be used to generate all possible SURMOFs for a
list of available SBUs present in the default database. N.B. Note that
SURMOFs generally adopt the "pcu" topology.

   from scm.autografs import autografs

   mofgen = autografs.Autografs()

   topology_name = "pcu"

   # get all available linkers, center, pillars for the pcu topology
   all_sbus = mofgen.list_available_sbu(topology_name=topology_name)

   center_key, linker_key = list(all_sbus.keys())
   centers = all_sbus[center_key]
   linkers = all_sbus[linker_key]

   for node in centers:
       for i in range(len(linkers) - 1):
           for j in range(1, len(linkers)):
               linker = linkers[i]
               pillar = linkers[j]
               if linker != pillar:
                   sbu_names = [node, (linker, 1), (pillar, 1)]
                   framework = mofgen.make(topology_name=topology_name, sbu_names=sbu_names)
                   surmof_name = "node-linker-pillar"
                   framework.write(surmof_name, "gin")
