Source code for mordred.TopoPSA
from collections import defaultdict
from rdkit.Chem import BondType, rdMolDescriptors
from ._base import Descriptor
__all__ = ("TopoPSA",)
[docs]
class TopoPSA(Descriptor):
r"""topological polar surface area descriptor(NO only: rdkit wrapper).
:type no_only: bool
:param no_only:
* True: N,O only TPSA
* False: all(N,O,S,P) TPSA
References
* :doi:`10.1021/jm000942e`
"""
since = "1.0.0"
__slots__ = ("_no_only",)
[docs]
def description(self):
return "topological polar surface area{}".format(
" (use only nitrogen and oxygen)" if self._no_only else ""
)
@classmethod
def preset(cls, version):
yield cls(True)
yield cls(False)
def __str__(self):
return "TopoPSA(NO)" if self._no_only else "TopoPSA"
def parameters(self):
return (self._no_only,)
def __init__(self, no_only=True):
self._no_only = no_only
def calculate(self):
tpsa = rdMolDescriptors.CalcTPSA(self.mol)
if self._no_only:
return tpsa
for atom in self.mol.GetAtoms():
atomic_num = atom.GetAtomicNum()
if atomic_num == 15:
tpsa += self._get_phosphorus_contrib(atom)
elif atomic_num == 16:
tpsa += self._get_sulfur_contrib(atom)
return tpsa
@staticmethod
def _hydrogen_count(atom):
return atom.GetTotalNumHs() + sum(
1 for a in atom.GetNeighbors() if a.GetAtomicNum() == 1
)
@staticmethod
def _bond_type_count(atom):
cnt = defaultdict(int)
for bond in atom.GetBonds():
if bond.GetIsAromatic():
cnt[BondType.AROMATIC] += 1
else:
cnt[bond.GetBondType()] += 1
return dict(cnt)
@classmethod
def _get_phosphorus_contrib(cls, atom):
nH = cls._hydrogen_count(atom)
cnt = cls._bond_type_count(atom)
if atom.GetFormalCharge() != 0 or atom.GetIsAromatic():
return 0.0
if nH == 1 and cnt == {BondType.SINGLE: 3, BondType.DOUBLE: 1}:
return 23.47
elif nH == 0:
if cnt == {BondType.SINGLE: 3}:
return 13.59
elif cnt == {BondType.SINGLE: 1, BondType.DOUBLE: 1}:
return 34.14
elif cnt == {BondType.SINGLE: 3, BondType.DOUBLE: 1}:
return 9.81
return 0.0
@classmethod
def _get_sulfur_contrib(cls, atom):
nH = cls._hydrogen_count(atom)
cnt = cls._bond_type_count(atom)
if atom.GetFormalCharge() != 0:
return 0.0
if atom.GetIsAromatic():
if nH == 0:
if cnt == {BondType.AROMATIC: 2}:
return 28.24
elif cnt == {BondType.AROMATIC: 2, BondType.DOUBLE: 1}:
return 21.70
else:
if nH == 1 and cnt == {BondType.SINGLE: 2}:
return 38.80
elif nH == 0:
if cnt == {BondType.SINGLE: 2}:
return 25.30
elif cnt == {BondType.DOUBLE: 1}:
return 32.09
elif cnt == {BondType.SINGLE: 2, BondType.DOUBLE: 1}:
return 19.21
elif cnt == {BondType.SINGLE: 2, BondType.DOUBLE: 2}:
return 8.38
return 0.0
rtype = float