Source code for mordred.MolecularDistanceEdge
from six import string_types, integer_types
import warnings
import numpy as np
from ._base import Descriptor
from ._graph_matrix import Valence, DistanceMatrix
from ._atomic_property import GetAtomicNumber, GetElementSymbol
__all__ = ("MolecularDistanceEdge",)
_sp_dict = {1: "primary", 2: "secondary", 3: "tertiary", 4: "quaternary"}
[docs]
class MolecularDistanceEdge(Descriptor):
r"""molecular distance edge descriptor.
:type valence1: int
:param valence1: valence of first atom
:type valence2: int
:param valence2: valence of second atom
:type element: str or int
:param element: atomic symbol or atomic number
:returns: NaN when :math:`N_{\rm MDE} = 0`
"""
since = "1.0.0"
__slots__ = ("_valence1", "_valence2", "_atomic_num")
explicit_hydrogens = False
[docs]
def description(self):
return "molecular distance edge between {a} {e} and {b} {e}".format(
a=_sp_dict[self._valence1],
b=_sp_dict[self._valence2],
e=GetElementSymbol(self._atomic_num),
)
@classmethod
def preset(cls, version):
return (
cls(a, b, e)
for e in [6, 8, 7]
for a in range(1, 11 - e)
for b in range(a, 11 - e)
)
def __str__(self):
return "MDE{}-{}{}".format(
GetElementSymbol(self._atomic_num), self._valence1, self._valence2
)
def parameters(self):
return self._valence1, self._valence2, GetElementSymbol(self._atomic_num)
def __init__(self, valence1=1, valence2=1, element="C"):
self._valence1 = min(valence1, valence2)
self._valence2 = max(valence1, valence2)
if isinstance(element, integer_types):
self._atomic_num = element
elif isinstance(element, string_types):
self._atomic_num = GetAtomicNumber(element)
else:
raise ValueError("element must be atomic number or atomic symbol")
def dependencies(self):
return {
"D": DistanceMatrix(self.explicit_hydrogens),
"V": Valence(self.explicit_hydrogens),
}
def calculate(self, D, V):
N = self.mol.GetNumAtoms()
Dv = [
D[i, j]
for i in range(N)
for j in range(i + 1, N)
if (V[i] == self._valence1 and V[j] == self._valence2)
or (V[j] == self._valence1 and V[i] == self._valence2)
if self.mol.GetAtomWithIdx(i).GetAtomicNum()
== self.mol.GetAtomWithIdx(j).GetAtomicNum()
== self._atomic_num
]
n = len(Dv)
with self.rethrow_zerodiv():
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore",
message="overflow encountered in reduce",
category=RuntimeWarning,
)
log_dx = np.sum(np.log(Dv)) / (2.0 * n)
dx = np.exp(log_dx)
return n / (dx**2)
rtype = float