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 empower users with 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 lists and this lists.
sbu_names = ["Benzene_linear", "Zn_mof5_octahedral"]

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

# The MOF generated directly view using ASE visualizer as follows
mof.view()

# You can also choose to write the mof to a gin (GULP) file 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 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 seconadry 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 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’s 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 linkered 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")