Construction Overview
Introduction
The key idea behind stk is that the construction of a molecule can
be broken down into two fundamental pieces of information, its
building blocks and its topology graph. The building blocks of a
molecule are molecules, or molecular fragments, which are used for
construction. The smallest possible building block is a single atom
and constructed molecules can become the building blocks of other
constructed molecules. The topology graph is an abstract representation
of a constructed molecule. The nodes of the graph represent the
positions of the building blocks and the edges of the graph represent
which building blocks have bonds formed between them during
construction.
To use stk you only have to choose which building blocks and
topology graph you wish to use and stk will take care of everything
else, take for example the construction of a linear polymer
import stk
polymer = stk.ConstructedMolecule(
topology_graph=stk.polymer.Linear(
building_blocks=(
stk.BuildingBlock(
smiles='Brc1ccc(Br)cc1',
functional_groups=[stk.BromoFactory()],
),
stk.BuildingBlock(
smiles='BrC#CBr',
functional_groups=[stk.BromoFactory()],
),
),
repeating_unit='ABBA',
num_repeating_units=1,
)
)
# You can write the molecule to a file if you want to view it.
stk.MolWriter().write(polymer, 'polymer.mol')
which will produce:
Because the topology graph is an idealized representation of the constructed molecule, the bonds formed during construction often have unrealistic lengths. This means that constructed molecules will need to undergo structure optimization. There is no single correct way to go about this, because the appropriate methodology for structure optimization will depend on various factors, such as the nature of the constructed molecule, the desired accuracy, and time constraints.
However, stk does provide a handful of
simple and lightweight methods for making structures more
realistic, via optimizers
import stk
optimized_polymer = stk.ConstructedMolecule(
topology_graph=stk.polymer.Linear(
building_blocks=(
stk.BuildingBlock(
smiles='Brc1ccc(Br)cc1',
functional_groups=[stk.BromoFactory()],
),
stk.BuildingBlock(
smiles='BrC#CBr',
functional_groups=[stk.BromoFactory()],
),
),
repeating_unit='ABBA',
num_repeating_units=1,
optimizer=stk.Collapser(scale_steps=False),
),
)
stk only provides limited capacity in this regard because
there are countless options already available,
be it Python libraries such as rdkit or ase, or
some sort of computational chemistry software. In order to
easily interact with these other tools, stk does try to make it
easy for you to convert an
stk Molecule into whatever format you need to make
use of other software. This means you can access atoms and
bonds with Molecule.get_atoms() and Molecule.get_bonds(),
you can convert any stk Molecule into an
rdkit molecule with Molecule.to_rdkit_mol() or you
can write it to a file using the various writer classes, such as
MolWriter.
The general construction workflow of stk.
Topology Graph
The abstraction provided by the topology graph has a number of powerful benefits. Firstly, because every vertex is responsible for the placement of a building block, it is extremely easy to construct different structural isomers of the constructed molecule. The vertex can be told to perform different transformations on the building block, so that its orientation in the constructed molecule changes. For the end user, selecting the transformation from a set of predefined ones is easy. Also, since the transformation is restricted to a single building block on a single vertex, it easy for developers to define.
The second major benefit of the topology graph is that the vertices and
edges can hold additional state useful for the construction of a
molecule. An example of this is in the construction of different
structural isomers, but another can be seen in the construction of
periodic systems. For example, stk allows you to construct
covalent organic frameworks. With the topology graph this is trivial
to implement, simply label some of the edges as periodic and they
will construct periodic bonds instead of regular ones.
Thirdly, the topology graph allows users to easily modify the construction of molecules by placing different building blocks on different vertices.
Finally, the topology graph breaks down the construction of
a molecule into independent steps. Each vertex
represents a single, independent operation on a building block while
each edge represents a single, independent operation on a collection
of building blocks. As a result, each vertex and edge represents a
single operation, which can be executed in parallel. This allows
stk to scale efficiently to large topology graphs and take
advantage of multiple cores even during the construction of a single
molecule.
Building Blocks
Building blocks in stk are molecules, or molecular fragments,
which are placed on the nodes of the TopologyGraph. After
building blocks are placed the nodes, they are connected to
each other through a reaction. stk supports
multiple reactions and users can define their own. Reactions can add or
remove atoms and bonds between building blocks, which are connected by
edges in the topology graph.
When it comes to reactions, an important question, which must be
addressed, is, which atoms of a BuildingBlock are modified
by a reaction? In stk, the answer to this is
a functional_group. When a user of
stk creates a BuildingBlock, they also specify which
functional groups are present in the BuildingBlock. This
lets stk know which atoms the user intends to transform during
construction.
There are many different types of
functional_group present
in stk, for example, Bromo, Alcohol or
Aldehyde. When a user creates a BuildingBlock,
they can specify multiple functional groups at at time using
a functional_group_factory. A
functional_group_factory finds all the functional groups of a
specific type, and adds them to the BuildingBlock. For
example, if we want to create
a BuildingBlock, and you want to react its bromo groups
during construction, you can use a BromoFactory.
import stk
building_block = stk.BuildingBlock('BrCCBr', [stk.BromoFactory()])
In the example above, building_block will have two
Bromo functional groups. When building_block is used
for construction, it is the atoms held by the Bromo
groups, which will be modified. If we have a building block with
aldehyde functional groups, we could have used an
AldehydeFactory.
building_block2 = stk.BuildingBlock(
smiles='O=CCC=O',
functional_groups=[stk.AldehydeFactory()],
)
Finally, if we had a mix of functional groups, we could have used a mix of factories
building_block3 = stk.BuildingBlock(
smiles='O=CCCBr',
functional_groups=[stk.AldehydeFactory(), stk.BromoFactory()],
)
Based on the specific functional groups found on an
edge of the TopologyGraph, stk will select an
appropriate reaction to join them. You can also force
stk to use a different reaction of your
choosing, which is covered in the basic examples.