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