lukasturcani / stk

A Python library which allows construction and manipulation of complex molecules, as well as automatic molecular design and the creation of molecular databases.
https://stk.readthedocs.io/
MIT License
250 stars 47 forks source link

Carboxylic-based Metal-organic cage #383

Closed AlexLeg closed 3 years ago

AlexLeg commented 3 years ago

Hi! Thanks for the great tutorial for using stk and building structures. I tried to use it to build stk to build carboxylic-based metal-organic cages but without success so far. In particular, I struggle to define the M-M paddlewheel building blocks. In your examples, you use Pd or Fe and define it as stk.SingleAtom. Is there any equivalent for a dimetal like Cu2 paddlewheel? I try as well to create first an M2(OAc)4 metal complex by replacing the C with a Br dummy before adding a spacer building block to form the cage. However, I also could not figure out how to create such a paddlewheel complex. Is there a way to do it only using CarboxylicAcidFactory and not the smartfunctionalgroupfactory?

Best regards

andrewtarzia commented 3 years ago

Hello!

Welcome and thank you!

If I understand correctly, you want to build an stk.metal_complex.Paddlewheel structure - below is an example code to do that. Let me know if that helps?

The SmartsFunctionalGroupFactory is used to afford the specificity seen below - you want two functional groups (one per oxygen atom) in the caborxylic acid -- not one FG from the entire caborxylic acid.

In the example below, I finally turn the constructed complex into a BB with bromo functional groups for further reaction, as I think you requested, for cage formation.

import stk

cu_atom = stk.BuildingBlock(
  smiles='[Cu+2]',
  functional_groups=(
      stk.SingleAtom(stk.Cu(0, charge=2))
      for i in range(4)
  ),
  position_matrix=([0, 0, 0], ),
)

bi_1 = stk.BuildingBlock(
    smiles='O=C(O)c1ccc(Br)cc1',
    functional_groups=[
        stk.SmartsFunctionalGroupFactory(
            smarts='[#6]~[#8]~[#1]',
            bonders=(1, ),
            deleters=(2, ),
        ),
        stk.SmartsFunctionalGroupFactory(
            smarts='[#6]~[#8X1]',
            bonders=(1, ),
            deleters=(),
        ),
    ]
)

mcomplex = stk.ConstructedMolecule(
    stk.metal_complex.Paddlewheel(
        metals=cu_atom,
        ligands=bi_1,
        reaction_factory=stk.DativeReactionFactory(
            stk.GenericReactionFactory(
                bond_orders={
                    frozenset({
                        stk.GenericFunctionalGroup,
                        stk.SingleAtom,
                    }): 9,
                },
            ),
        ),
    )
)

mcomplex.write('test.mol')

# Turn into BB for next reaction.
complex_bb = stk.BuildingBlock.init_from_molecule(mcomplex, (stk.BromoFactory(), ))
AlexLeg commented 3 years ago

Yes, it helps a lot, I could built my cuboctahedral cage by sligthly modifying the complex to match with the spacer. I also run MC Hammer optimization, which give a pretty decent result. I found the cage structure to be closer to the crystalographic structure when replacing C(=O)(O)Br by C(O)(O)Br (even if i got of course an extra hydrogen on the C).

I am a beginner with Python but I could understand the general concept of how it works thanks to your tutorials.

cu_atom = stk.BuildingBlock(
  smiles='[Cu+2]',
  functional_groups=(
      stk.SingleAtom(stk.Cu(0, charge=2))
      for i in range(4)
  ),
  position_matrix=([0, 0, 0], ),
)

bi_1 = stk.BuildingBlock(
    smiles='C(=O)(O)Br',
    functional_groups=[
        stk.SmartsFunctionalGroupFactory(
            smarts='[#6]~[#8]~[#1]',
            bonders=(1, ),
            deleters=(2, ),
        ),
        stk.SmartsFunctionalGroupFactory(
            smarts='[#6]~[#8X1]',
            bonders=(1, ),
            deleters=(),
        ),
    ]
)

mcomplex = stk.ConstructedMolecule(
    stk.metal_complex.Paddlewheel(
        metals=cu_atom,
        ligands=bi_1,
        reaction_factory=stk.DativeReactionFactory(
            stk.GenericReactionFactory(
                bond_orders={
                    frozenset({
                        stk.GenericFunctionalGroup,
                        stk.SingleAtom,
                    }): 9,
                },
            ),
        ),
        optimizer=stk.MCHammer(),
    )
)

show_stk_mol(mcomplex)

# Turn into BB for next reaction.
complex_bb = stk.BuildingBlock.init_from_molecule(mcomplex, (stk.BromoFactory(), ))

# Define spacer building block.
bb3 = stk.BuildingBlock(
    smiles=(
        'C1=CC(=CC(=C1)Br)Br'
    ),
    functional_groups=[stk.BromoFactory()],
)

# Build an M12L24  with a spacer.
cage1 = stk.ConstructedMolecule(
    stk.cage.M12L24(
        building_blocks=(
            complex_bb,
            bb3,
        ),
        optimizer=stk.MCHammer(),
    )
)
show_stk_mol(bb3)
show_stk_mol(cage1)
andrewtarzia commented 3 years ago

Hey Alex,

Thank you! Glad it helped. MCHammer is meant to be a very crude optimisation, but I am glad it gets to the right point. Note that you should encompass the code in ``` to properly show your code blocks in comments.

Are you happy for us to close this issue? @lukasturcani

Additionally, on the main page is a link to a discord, where you can chat to us further as you use stk in your research - we can help you get it going for sure!

andrewtarzia commented 3 years ago

I forgot to mention, if the structure with the appropriate chemistry (C=O(O) instead of CO(O)) is less close to the crystal structure, I would suggest looking into further optimisation with gfn xtb (https://xtb-docs.readthedocs.io/en/latest/contents.html) which is quite good for these structures and is accessible with our package stko (https://github.com/JelfsMaterialsGroup/stko) once you have downloaded the xtb binary.

AlexLeg commented 3 years ago

Yes you can close this issue. I was starting to read about stko and the different possibility for the optimization of the structure. Thanks again for your help!

AlexLeg commented 3 years ago

Is not GULP more adapted as the cage contain a metal?

andrewtarzia commented 3 years ago

GULP and xTB can handle metals. I suggest xTB first because it is a better method for a similar cost. However, it may fail when atoms are initially in high energy states because it does not have the bonding information. Therefore, it may be best to use gulp first, then use xtb. It really depends on what the structure is to be used for, but the following sequence has worked for me in the past:

  1. MCHammer/Collapser
  2. UFF/Gulp with conjugate_gradient=True
  3. UFF/Gulp with conjugate_gradient=False
  4. UFF/Gulp Molecular dynamics at high T
  5. optimisation with xTB

All of the above can be done in stko but is quite costly. You might want to just do steps 1, 2 and 5.

lukasturcani commented 3 years ago

Also moving this into discussions.