Source code for openpharmacophore.pharmacophore.pharmacophoric_point

# OpenPharmacophore
from openpharmacophore.pharmacophore.input_arguments import validate_input_array_like, validate_input_quantity
from openpharmacophore.pharmacophore.exceptions import InvalidFeatureError
from openpharmacophore.constants import PALETTE, FEAT_TO_CHAR, CHAR_TO_FEAT
# Third Party
import numpy as np
import pyunitwizard as puw


[docs]class PharmacophoricPoint: """ Class to store pharmacophoric points of any feature type. Parameters ----------- feat_type : str The feature type of the point. This can be hb donor, hb acceptor, aromatic ring hydrophobic, positive charge, negative charge, excluded volume. center : Quantity (dimensionality:{'[L]':1}; shape:(3,)) Coordinates of the sphere center. radius : Quantity (dimensionality:{'[L]':1}) Radius of the pharmacophoric sphere. direction : array-like; shape:(3,), optional Direction as a three-dimensional vector. atom_indices : array-like of int, optional The indices of the atoms corresponding to the pharmacophoric point in the molecule from which they were extracted. Attributes ---------- feature_name : str The feature type of the point. center : Quantity (dimensionality:{'[L]':1}; shape:(3,)) Coordinates of the sphere center. radius : Quantity (dimensionality:{'[L]':1}; value:float) Radius of the pharmacophoric sphere. direction : ndarray; shape:(3,) Unit vector. atom_indices : set of int A set of the indices of the atoms corresponding to the pharmacophoric point in the molecule from which they were extracted. """ def __init__(self, feat_type, center, radius, direction=None, atom_indices=None): try: self._feat_name = FEAT_TO_CHAR[feat_type] except KeyError: raise InvalidFeatureError(feat_type) self._validate_input_arguments(center, radius, direction) self._center = puw.standardize(center) self._radius = puw.standardize(radius) if direction is not None: self._direction = direction / np.linalg.norm(direction) else: self._direction = None if atom_indices is not None: self._atom_indices = set(atom_indices) else: self._atom_indices = set() @property def center(self): return self._center @center.setter def center(self, new_center): validate_input_quantity(new_center, {"[L]": 1}, "center", shape=(3,)) self._center = new_center @property def radius(self): return self._radius @radius.setter def radius(self, new_radius): validate_input_quantity(new_radius, {"[L]": 1}, "radius") self._radius = new_radius @property def direction(self): return self._direction @property def atom_indices(self): return self._atom_indices @atom_indices.setter def atom_indices(self, atom_indices): self._atom_indices = set(atom_indices) @property def has_direction(self): return self._direction is not None @property def feature_name(self): return CHAR_TO_FEAT[self._feat_name] @property def short_name(self): return self._feat_name @staticmethod def _validate_input_arguments(center, radius, direction): """ Validates the input arguments of the PharmacophoricPoint constructor. """ # Validate center validate_input_quantity(center, {"[L]": 1}, "center", shape=(3,)) # Validate radius validate_input_quantity(radius, {"[L]": 1}, "radius") # Validate direction if direction is not None: validate_input_array_like(direction, shape=(3,), name="direction")
[docs] @staticmethod def get_valid_features(): """ Get a list of all valid chemical features for a PharmacophoricPoint object""" return list(PALETTE.keys())
def __eq__(self, other): """ Compare equality of two pharmacophoric points based on their 3D coordinates, directionality and radius. """ if isinstance(other, type(self)): if self._feat_name != other._feat_name: return False if self.has_direction != other.has_direction: return False radius_eq = np.allclose(self._radius, other.radius, rtol=0, atol=1e-02) center_eq = np.allclose(self._center, other.center, rtol=0, atol=1e-04) if self.has_direction: direction_eq = np.allclose(self._direction, other.direction, rtol=0, atol=1e-04) return radius_eq and center_eq and direction_eq else: return radius_eq and center_eq return False def __repr__(self): center = np.around(puw.get_value(self._center, "angstroms"), 2) radius = np.around(puw.get_value(self._radius, "angstroms"), 2) x, y, z = center[0], center[1], center[2] if self.has_direction: direction = np.around(self._direction, 2) xd, yd, zd = direction[0], direction[1], direction[2] return (f"{self.__class__.__name__}(" f"feat_type={self.feature_name}; " f"center=({x}, {y}, {z}); radius={radius}; " f"direction=({xd}, {yd}, {zd}))") else: return (f"{self.__class__.__name__}(" f"feat_type={self.feature_name}; " f"center=({x}, {y}, {z}); radius={radius})")