Source code for molvs.metal
# -*- coding: utf-8 -*-
"""
molvs.metal
~~~~~~~~~~~
This module contains tools for disconnecting metal atoms that are defined as covalently bonded to non-metals.
"""
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import division
import logging
from rdkit import Chem
log = logging.getLogger(__name__)
# TODO: This won't disconnect e.g. covalent [Na]Cl...
[docs]class MetalDisconnector(object):
"""Class for breaking covalent bonds between metals and organic atoms under certain conditions."""
def __init__(self):
log.debug('Initializing MetalDisconnector')
# Initialize SMARTS to identify relevant substructures
# TODO: Use atomic numbers instead of element symbols in SMARTS to allow for isotopes?
self._metal_nof = Chem.MolFromSmarts('[Li,Na,K,Rb,Cs,Fr,Be,Mg,Ca,Sr,Ba,Ra,Sc,Ti,V,Cr,Mn,Fe,Co,Ni,Cu,Zn,Al,Ga,Y,Zr,Nb,Mo,Tc,Ru,Rh,Pd,Ag,Cd,In,Sn,Hf,Ta,W,Re,Os,Ir,Pt,Au,Hg,Tl,Pb,Bi]~[N,O,F]')
self._metal_non = Chem.MolFromSmarts('[Al,Sc,Ti,V,Cr,Mn,Fe,Co,Ni,Cu,Zn,Y,Zr,Nb,Mo,Tc,Ru,Rh,Pd,Ag,Cd,Hf,Ta,W,Re,Os,Ir,Pt,Au]~[B,C,Si,P,As,Sb,S,Se,Te,Cl,Br,I,At]')
[docs] def __call__(self, mol):
"""Calling a MetalDisconnector instance like a function is the same as calling its disconnect(mol) method."""
return self.disconnect(mol)
[docs] def disconnect(self, mol):
"""Break covalent bonds between metals and organic atoms under certain conditions.
The algorithm works as follows:
- Disconnect N, O, F from any metal.
- Disconnect other non-metals from transition metals + Al (but not Hg, Ga, Ge, In, Sn, As, Tl, Pb, Bi, Po).
- For every bond broken, adjust the charges of the begin and end atoms accordingly.
:param mol: The input molecule.
:type mol: rdkit.Chem.rdchem.Mol
:return: The molecule with metals disconnected.
:rtype: rdkit.Chem.rdchem.Mol
"""
log.debug('Running MetalDisconnector')
# Remove bonds that match SMARTS
for smarts in [self._metal_nof, self._metal_non]:
pairs = mol.GetSubstructMatches(smarts)
rwmol = Chem.RWMol(mol)
orders = []
for i, j in pairs:
# TODO: Could get the valence contributions of the bond instead of GetBondTypeAsDouble?
orders.append(int(mol.GetBondBetweenAtoms(i, j).GetBondTypeAsDouble()))
rwmol.RemoveBond(i, j)
# Adjust neighbouring charges accordingly
mol = rwmol.GetMol()
for n, (i, j) in enumerate(pairs):
chg = orders[n]
atom1 = mol.GetAtomWithIdx(i)
atom1.SetFormalCharge(atom1.GetFormalCharge() + chg)
atom2 = mol.GetAtomWithIdx(j)
atom2.SetFormalCharge(atom2.GetFormalCharge() - chg)
log.info('Removed covalent bond between %s and %s', atom1.GetSymbol(), atom2.GetSymbol())
Chem.SanitizeMol(mol)
return mol