def five_element_pharmacophore(): radius = puw.quantity(1.0, "angstroms") ring_1 = PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([1, 0, 0], "angstroms"), radius=radius, direction=[0, 0, 1], atom_indices=None) ring_2 = PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([0, 1, 2], "angstroms"), radius=puw.quantity(1.0, "angstroms")) acceptor = PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([1, 2, 2], "angstroms"), radius=radius, direction=[0, 1, 1]) hb_donor = PharmacophoricPoint(feat_type="hb donor", center=puw.quantity([1, 2, 2], "angstroms"), radius=radius, direction=[0, 1, 1]) hydrophobicity = PharmacophoricPoint( feat_type="hydrophobicity", center=puw.quantity([-1, 2, 2], "angstroms"), radius=radius, ) return StructuredBasedPharmacophore(pharmacophoric_points=[ acceptor, hb_donor, hydrophobicity, ring_1, ring_2 ], is_sorted=True)
def two_element_pharmacophore(): """Returns a pharmacophore with an aromatic ring and an hb acceptor""" radius = puw.quantity(1.0, "angstroms") ring = PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([1, 0, 0], "angstroms"), radius=radius, direction=[0, 0, 1], atom_indices=None) acceptor = PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([1, 2, 2], "angstroms"), direction=[0, 1, 1], radius=radius) return StructuredBasedPharmacophore(pharmacophoric_points=[ring, acceptor])
def two_point_pharmacophore() -> Pharmacophore: """Returns a pharmacophore with two pharmacophoric points.""" hb_donor = PharmacophoricPoint( feat_type="hb donor", center=puw.quantity([1,0,1], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) hydrophobicity = PharmacophoricPoint( feat_type="hydrophobicity", center=puw.quantity([-1, 0, 3], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) return Pharmacophore(pharmacophoric_points=[hb_donor, hydrophobicity])
def test_add_point(three_point_pharmacophore): hydrophobic = PharmacophoricPoint( feat_type="hydrophobicity", center=puw.quantity([-1, 0, 2], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) positive = PharmacophoricPoint( feat_type="positive charge", center=puw.quantity([3, -1, 4], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) pharmacophore = copy.deepcopy(three_point_pharmacophore) pharmacophore.add_point(hydrophobic) assert pharmacophore.n_pharmacophoric_points == len(pharmacophore) assert pharmacophore.n_pharmacophoric_points == 4 # Element should be sorted assert pharmacophore[1].feature_name == "hydrophobicity" pharmacophore.add_point(positive) assert pharmacophore.n_pharmacophoric_points == len(pharmacophore) assert pharmacophore.n_pharmacophoric_points == 5 assert pharmacophore[2].feature_name == "positive charge" # Test adding a repetead feature type hb_acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity([-1,0,-1], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) pharmacophore.add_point(hb_acceptor) assert pharmacophore.n_pharmacophoric_points == len(pharmacophore) assert pharmacophore.n_pharmacophoric_points == 6 assert pharmacophore[0].feature_name == "hb acceptor" assert pharmacophore[1].feature_name == "hb acceptor" ring = PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity([-5, -1, -3], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) pharmacophore.add_point(ring) assert pharmacophore.n_pharmacophoric_points == len(pharmacophore) assert pharmacophore.n_pharmacophoric_points == 7 assert pharmacophore[4].feature_name == "aromatic ring" assert pharmacophore[5].feature_name == "aromatic ring" assert pharmacophore[6].feature_name == "aromatic ring"
def five_point_pharmacophore(three_point_pharmacophore) -> Pharmacophore: hydrophobicity = PharmacophoricPoint( feat_type="hydrophobicity", center=puw.quantity([-1, 0, 3], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) positive = PharmacophoricPoint( feat_type="positive charge", center=puw.quantity([3, -1, 4], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) pharmacophore = copy.deepcopy(three_point_pharmacophore) pharmacophore.add_point(hydrophobicity) pharmacophore.add_point(positive) return pharmacophore
def three_element_pharmacophore(): radius = puw.quantity(1.0, "angstroms") ring = PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([1, 0, 0], "angstroms"), radius=radius, direction=[0, 0, 1], atom_indices=None) acceptor = PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([1, 2, 2], "angstroms"), radius=radius, direction=[0, 1, 1]) excluded = PharmacophoricPoint(feat_type="excluded volume", center=puw.quantity([2, 1, 2], "angstroms"), radius=radius) return StructuredBasedPharmacophore( pharmacophoric_points=[ring, acceptor, excluded])
def get_pharmacophoric_point(ligand: Chem.Mol, feat_name: str, atom_indices: Sequence, conformer_index: int, radius: float, directionality: bool) -> PharmacophoricPoint: """ Obtain the coordinates and if specified the direction vector and return a pharmacophoric point. Parameters ---------- ligand : rdkit.Chem.Mol A ligand conformer_index : int The conformer whose coordinates will be used to obtain the pharmacophoric points. radius : float Lenght of the radius in angstroms of the parmacohporic point. directionality : bool Whether to compute the direction vectgor of that point. Returns ------- openpharmacophore.PharmacophoricPoint A pharmacophoric point. """ if len(atom_indices) > 1: # Find the centroid # Aromatic, hydrophobic, positive or negative feature coords = PharmacophoricPointExtractor._feature_centroid( ligand, atom_indices, conformer_index) # Find direction vector if directionality: direction = PharmacophoricPointExtractor._aromatic_direction_vector( ligand, atom_indices, conformer_index) else: direction = None else: # Find the centroid # Donor or acceptor feature position = ligand.GetConformer(conformer_index).GetAtomPosition( atom_indices[0]) coords = np.zeros((3, )) coords[0] = position.x coords[1] = position.y coords[2] = position.z # Find direction vector if directionality: direction = PharmacophoricPointExtractor._donor_acceptor_direction_vector( ligand, atom_indices[0], coords, conformer_index) else: direction = None return PharmacophoricPoint(feat_type=feat_name, center=puw.quantity(coords, "angstroms"), radius=puw.quantity(radius, "angstroms"), direction=direction, atom_indices=atom_indices)
def pharmacophoric_points(): """ Returns a tuple with lists of 20 pharmacophoric points of the same kind.""" radius = puw.quantity(1.0, "angstroms") donor_1 = [] for ii in range(20): center = np.array([1.0, 0.0, 3.0]) + ii / 10 donor_1.append( PharmacophoricPoint(feat_type="hb donor", center=puw.quantity(center, "angstroms"), radius=radius, atom_indices=(1, ))) donor_2 = [] for ii in range(20): center = np.array([-5.0, 1.5, -2.4]) + ii / 10 donor_2.append( PharmacophoricPoint(feat_type="hb donor", center=puw.quantity(center, "angstroms"), radius=radius, atom_indices=(8, ))) aromatic = [] for ii in range(20): center = np.array([-5.0, 1.5, -2.4]) + ii / 10 aromatic.append( PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity(center, "angstroms"), radius=radius, atom_indices=(2, 3, 4, 5, 6, 7))) acceptor = [] for ii in range(20): center = np.array([-0.5, 8.5, 2.4]) + ii / 10 acceptor.append( PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity(center, "angstroms"), radius=radius, atom_indices=(10, ))) hydrophobic = [] for ii in range(20): center = np.array([-0.5, 8.5, 2.4]) + ii / 10 hydrophobic.append( PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity(center, "angstroms"), radius=radius, atom_indices=(12, ))) return (donor_1, donor_2, aromatic, acceptor, hydrophobic)
def test_distance_between_pharmacophoric_points(): radius = puw.quantity(1.0, "angstroms") point_1 = PharmacophoricPoint("aromatic ring", puw.quantity([3, 4, 0], "angstroms"), radius) point_2 = PharmacophoricPoint("hb acceptor", puw.quantity([0, 0, 0], "angstroms"), radius) assert distance_bewteen_pharmacophoric_points(point_1, point_2) == 5 point_1 = PharmacophoricPoint("aromatic ring", puw.quantity([1, 1, 1], "angstroms"), radius) point_2 = PharmacophoricPoint("hb acceptor", puw.quantity([1, 1, 1], "angstroms"), radius) assert distance_bewteen_pharmacophoric_points(point_1, point_2) == 0
def three_point_pharmacophore() -> Pharmacophore: """Returns as pharmacophore with three pharmacophoric_points""" hb_acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity([1,0,0], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) ring_1 = PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity([2, 1, 4], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) ring_2 = PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity([0, 1, 2], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) return Pharmacophore(pharmacophoric_points=[ring_1, hb_acceptor, ring_2])
def test_inmutable(three_point_pharmacophore): # Test that we cannot modify the pharmacophoric point list hydrophobicity = PharmacophoricPoint( feat_type="hydrophobicity", center=puw.quantity([-1, 0, 3], "angstroms"), radius=puw.quantity(1.0, "angstroms") ) with pytest.raises(TypeError): three_point_pharmacophore[2] = hydrophobicity
def read_pharmagist(file_name: str) -> List[LigandBasedPharmacophore]: """ Loads pharmacophores from a pharmagist mol2 file. Parameters ---------- file_name : str Name of the file containing the pharmacophore. pharmacophore_index : int, optional If given, returns the pharmacophore which index is provided. Else, all the pharmcophores from the file will be returned. Returns ------- pharmacophores : list of openpharmacophore.LigandBasedPharmacophores A list of ligand based pharmacophores. """ # dictionary to map pharmagist feature names to openpharmacophore pharmacophoric_points pharmagist_element_name = { "AR": "aromatic ring", "HYD": "hydrophobicity", "ACC": "hb acceptor", "DON": "hb donor", "CAT": "positive charge", "ANI": "negative charge", } pharmacophores = [] pattern = r"[A-Z]{2,3} " with open(file_name, "r") as f: for line in f.readlines(): match = re.search(pattern, line) if "@<TRIPOS>ATOM" in line: points = [] if match: point_line = [p for p in line.split(" ") if p != ""] feat_type = pharmagist_element_name[point_line[1]] center = [float(coord) for coord in point_line[2:5] ] # convert coordinates to float center = puw.quantity(center, "angstroms") element = PharmacophoricPoint(feat_type=feat_type, center=center, radius=puw.quantity( 1.0, "angstroms")) insort_right(points, element, key=lambda p: p.short_name) if "@<TRIPOS>BOND" in line: pharmacophores.append(points) pharmacophores = [ph for ph in pharmacophores if len(ph) > 0] # filter empty lists pharmacophores = [LigandBasedPharmacophore(ph) for ph in pharmacophores] return pharmacophores
def four_element_pharmacophore(): pharmacophoric_points = [ PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([3.877, 7.014, 1.448], "angstroms"), radius=puw.quantity(1.0, "angstroms")), PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([7.22, 11.077, 5.625], "angstroms"), radius=puw.quantity(1.0, "angstroms")), PharmacophoricPoint(feat_type="hb donor", center=puw.quantity([4.778, 8.432, 7.805], "angstroms"), radius=puw.quantity(1.0, "angstroms")), PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity([1.56433333333334, 7.06399999999999, 3.135], "angstroms"), radius=puw.quantity(1.0, "angstroms")) ] return Pharmacophore(pharmacophoric_points)
def test_pharmacophoric_point_extractor(): # Known points of acetic acid acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity( [0.07903459193908467, 0.1487388014682705, 0.002355596284157232], "nanometer"), radius=puw.quantity(1.0, "angstroms")) negative = PharmacophoricPoint( feat_type="negative charge", center=puw.quantity( [0.08966065176585349, 0.03784658233931392, -0.01482808230401158], "nanometer"), radius=puw.quantity(1.0, "angstroms")) acetic_acid = Chem.MolFromSmiles("CC(=O)O") acetic_acid = utils.conformers.generate_conformers(acetic_acid, 1, random_seed=1, alignment=False) extractor = PharmacophoricPointExtractor() points = extractor(acetic_acid, 0) assert len(points) == 3 assert acceptor.feature_name == points[0].feature_name assert np.all(acceptor.center == points[0].center) assert acceptor.radius == points[0].radius rdkit_extractor = PharmacophoricPointExtractor( featdef=rdkit_featuredefinition()) points = rdkit_extractor(acetic_acid, 0) assert len(points) == 5 assert acceptor.feature_name == points[0].feature_name assert np.all(acceptor.center == points[0].center) assert acceptor.radius == points[0].radius assert negative.feature_name == points[-1].feature_name assert np.all(negative.center == points[-1].center) assert negative.radius == points[-1].radius
def test_distance_matrix(): # Test pharmacophore with zero elements pharmacophore = Pharmacophore() matrix = pharmacophore.distance_matrix() assert matrix.shape == (0, 0) radius = puw.quantity(1.0, "angstroms") points = [ PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([1, 0, -5], "angstroms"), radius=radius), PharmacophoricPoint(feat_type="hb donor", center=puw.quantity([2, 1, 0], "angstroms"), radius=radius), PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([-3, 2, -1], "angstroms"), radius=radius), ] pharmacophore = Pharmacophore(pharmacophoric_points=points) distance_matrix = pharmacophore.distance_matrix() assert distance_matrix.shape == (3, 3) assert np.allclose(distance_matrix, np.array([[0, np.sqrt(27), 6], [np.sqrt(27), 0, np.sqrt(27)], [6, np.sqrt(27), 0]]) ) points = [ PharmacophoricPoint(feat_type="hb acceptor", center=puw.quantity([1, 2, 3], "angstroms"), radius=radius), PharmacophoricPoint(feat_type="negative charge", center=puw.quantity([0, 0, 0], "angstroms"), radius=radius), PharmacophoricPoint(feat_type="positive charge", center=puw.quantity([-1, 0, -1], "angstroms"), radius=radius), PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity([2, -1, 1], "angstroms"), radius=radius), ] sq = np.sqrt pharmacophore = Pharmacophore(pharmacophoric_points=points) distance_matrix = pharmacophore.distance_matrix() assert distance_matrix.shape == (4, 4) assert np.allclose(distance_matrix, np.array([[0, sq(14), sq(24), sq(14)], [sq(14), 0, sq(2), sq(6)], [sq(24), sq(2), 0, sq(14)], [sq(14), sq(6), sq(14), 0]]))
def remove_feature(self, feat_type: str) -> None: """ Remove an especific feature type from the pharmacophore pharmacophoric_points list Parameters ---------- feat_type : str Name or type of the feature to be removed. """ feats = PharmacophoricPoint.get_valid_features() if feat_type not in feats: raise InvalidFeatureError(f"Cannot remove feature. \"{feat_type}\" is not a valid feature type") temp_pharmacophoric_points = [element for element in self._pharmacophoric_points if element.feature_name != feat_type] self._pharmacophoric_points = temp_pharmacophoric_points self.n_pharmacophoric_points = len(self._pharmacophoric_points)
def _plip_hydrophobics(hydrophobics: List[PharmacophoricPoint], radius: float) -> List[PharmacophoricPoint]: """ Groups plip hydrophobic points that are to close into a single point. Parameters ---------- hydrophobics : list of openpharmacophore.PharmacophoricPoint List with the hydrophobic points. Returns ------- grouped_points : list of openpharmacophore.PharmacophoricPoint List with the grouped points. """ grouped_points = [] skip = [] for inx, hyd1 in enumerate(hydrophobics): if hyd1 in skip: continue centroid = hyd1.center indices = hyd1.atom_indices count = 0 hyd1_center = puw.get_value(hyd1.center, "angstroms") for hyd2 in hydrophobics[inx + 1:]: if hyd1 == hyd2: skip.append(hyd2) continue hyd2_center = puw.get_value(hyd2.center, "angstroms") distance = np.linalg.norm(hyd1_center - hyd2_center) if distance <= 2.5: centroid += hyd2.center indices.union(hyd2.atom_indices) count += 1 skip.append(hyd2) if count > 0: centroid /= (count + 1) grouped_points.append( PharmacophoricPoint(feat_type="hydrophobicity", center=centroid, radius=radius, direction=None, atom_indices=indices)) return grouped_points
def rdkit_to_point( feat_name: str, coords: np.ndarray, radius: float, direction: Optional[Sequence] = None, atom_indices: Optional[Sequence] = None) -> PharmacophoricPoint: """ Transform an rdkit feature point to an openpharmacophore pharmacophoric point. Parameters ---------- feat_name : str rdkit name of the feature point. coords : numpy.ndarray; shape: (3, ) 3D coordinates of the centroid of the feature. radius : float Lenght of the radius of the parmacohporic points. direction : list, tuple, numpy.ndarray; shape:(3,) Unit vector. Returns ------- openpharmacophore.PharmacophoricPoint The pharmacophoric point. """ points = { "Acceptor": "hb acceptor", "Donor": "hb donor", "Aromatic": "aromatic ring", "Hydrophobe": "hydrophobicity", "PosIonizable": "positive charge", "NegIonizable": "negative charge", } return PharmacophoricPoint(feat_type=points[feat_name], center=puw.quantity(coords, "angstroms"), radius=puw.quantity(radius, "angstroms"), direction=direction, atom_indices=atom_indices)
def test_smarts_hydrophobics(): ligand = Chem.MolFromSmiles( "CC1=CC(=CC(=C1OCCCC2=CC(=NO2)C)C)C3=NOC(=N3)C(F)(F)F") ligand = generate_conformers(ligand, 1, random_seed=1) hydrophobics = SBP()._smarts_hydrophobics(ligand, 1.0) assert len(hydrophobics) == 3 hyd_1 = hydrophobics[0] hyd_2 = hydrophobics[2] hyd_2_center = puw.get_value(hyd_2.center, "angstroms") hyd_2_radius = puw.get_value(hyd_2.radius, "angstroms") assert hyd_1 == PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (1.4268, -1.9841, -1.4186), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert np.allclose(np.around(hyd_2_center, 3), (-2.130, -0.542, -0.479), rtol=0, atol=1e-04) assert np.allclose(hyd_2_radius, hyd_2_radius, rtol=0, atol=1e-03)
def from_ligandscout(file_name: str) -> List[PharmacophoricPoint]: """ Loads a pharmacophore from a ligandscout pml file. Parameters ---------- file_name : str Name of the file containing the pharmacophore. Returns ------- points : list of openpharmacophore.PharmacophoricPoints A list of pharmacophoric pharmacophoric_points. """ tree = ET.parse(file_name) pharmacophore = tree.getroot() ligandscout_to_oph = { # dictionary to map ligandscout features to openpharmacophore pharmacophoric_points "PI": "positive charge", "NI": "negative charge", "HBD": "hb donor", "HBA": "hb acceptor", "H": "hydrophobicity", "AR": "aromatic ring", "exclusion": "excluded volume" } points = [] for element in pharmacophore: if element.tag == "point": feat_name = element.attrib["name"] for position in element: coords = position.attrib x = float(coords["x3"]) y = float(coords["y3"]) z = float(coords["z3"]) radius = float(coords["tolerance"]) point = PharmacophoricPoint( feat_type=ligandscout_to_oph[feat_name], center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms")) insort_right(points, point, key=lambda p: p.short_name) elif element.tag == "vector": feat_name = element.attrib["name"] for position in element: if position.tag == "origin": coords_1 = position.attrib x_1 = float(coords_1["x3"]) y_1 = float(coords_1["y3"]) z_1 = float(coords_1["z3"]) radius_1 = float(coords_1["tolerance"]) elif position.tag == "target": coords_2 = position.attrib x_2 = float(coords_2["x3"]) y_2 = float(coords_2["y3"]) z_2 = float(coords_2["z3"]) radius_2 = float(coords_2["tolerance"]) point = PharmacophoricPoint( feat_type=ligandscout_to_oph[feat_name], center=puw.quantity([x_1, y_1, z_1], "angstroms"), radius=puw.quantity(radius_1, "angstroms"), direction=[x_2, y_2, z_2]) insort_right(points, point, key=lambda p: p.short_name) elif element.tag == "plane": feat_name = element.attrib["name"] for position in element: if position.tag == "position": coords_1 = position.attrib x_1 = float(coords_1["x3"]) y_1 = float(coords_1["y3"]) z_1 = float(coords_1["z3"]) radius_1 = float(coords_1["tolerance"]) center = np.array([x_1, y_1, z_1]) elif position.tag == "normal": coords_2 = position.attrib x_2 = float(coords_2["x3"]) y_2 = float(coords_2["y3"]) z_2 = float(coords_2["z3"]) radius_2 = float(coords_2["tolerance"]) point = PharmacophoricPoint( feat_type=ligandscout_to_oph[feat_name], center=puw.quantity(center, "angstroms"), radius=puw.quantity(radius_1, "angstroms"), direction=[x_2, y_2, z_2]) insort_right(points, point, key=lambda p: p.short_name) elif element.tag == "volume": feat_name = element.attrib["type"] for position in element: coords = position.attrib x = float(coords["x3"]) y = float(coords["y3"]) z = float(coords["z3"]) radius = float(coords["tolerance"]) point = PharmacophoricPoint( feat_type=ligandscout_to_oph[feat_name], center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms")) insort_right(points, point, key=lambda p: p.short_name) return points
def from_moe(file_name: str) -> List[PharmacophoricPoint]: """ Loads a pharmacophore from a MOE ph4 file. Parameters ---------- file_name : str Name of the file containing the pharmacophore. Returns ------- points : list of openpharmacophore.PharmacophoricPoint A list of pharmacophoric points. """ moe_to_oph = { "Cat": "positive charge", "Ani": "negative charge", "Don": "hb donor", "Acc": "hb acceptor", "Hyd": "hydrophobicity", "Aro": "aromatic ring", } points = [] with open(file_name, "r") as f: moe_ph4_string = f.read() # pieces = re.split("\s", moe_ph4_string) pieces = moe_ph4_string.split() pattern = r"Don|Acc|Aro|Cat|Ani|Hyd" # Index where the excluded volumes spheres coordinates, if any, start exclusion_inx = None for i, piece in enumerate(pieces): if re.match(pattern, piece): if len(piece) == 7: # Double features have seven characters i.e Acc|Aro feat_name_1 = piece[0: 3] feat_name_2 = piece[4:] # Coordinates are always two items after the feature name x = float(pieces[i + 2]) y = float(pieces[i + 3]) z = float(pieces[i + 4]) radius = float(pieces[i + 5]) point_1 = PharmacophoricPoint( feat_type=moe_to_oph[feat_name_1], center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms") ) point_2 = PharmacophoricPoint( feat_type=moe_to_oph[feat_name_2], center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms") ) insort_right(points, point_1, key=lambda p: p.short_name) insort_right(points, point_2, key=lambda p: p.short_name) else: # Regular features and # features with weird names i.e Cat$mDon, Acc2 feat_name = piece[0:3] # Coordinates are always two items after the feature name x = float(pieces[i + 2]) y = float(pieces[i + 3]) z = float(pieces[i + 4]) radius = float(pieces[i + 5]) point = PharmacophoricPoint( feat_type=moe_to_oph[feat_name], center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms") ) insort_right(points, point, key=lambda p: p.short_name) if piece == "#volumesphere": # Excluded volume spheres are 10 items after #volumesphere exclusion_inx = i + 10 break if exclusion_inx: count = 1 for p in pieces[exclusion_inx :]: if p == "#volume": break if count == 1: x = float(p) count += 1 elif count == 2: y = float(p) count += 1 elif count == 3: z = float(p) count += 1 elif count == 4: radius = float(p) excluded_sphere = PharmacophoricPoint( feat_type="excluded volume", center=puw.quantity([x, y, z], "angstroms"), radius=puw.quantity(radius, "angstroms") ) insort_right(points, excluded_sphere, key=lambda p: p.short_name) count = 1 return points
def test_from_pdb(file_name, ligand_id, hydrophobics): pdbs_path = "./openpharmacophore/data/pdb/" file_path = os.path.join(pdbs_path, file_name + ".pdb") pharmacophore = SBP().from_pdb(file_path, radius=1.0, ligand_id=ligand_id, hydrophobics=hydrophobics) if file_name == "1ncr": assert len(pharmacophore) == 5 assert pharmacophore.molecular_system is not None hyd_1 = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (42.4462, -1.1092, 122.6226), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd_1 == pharmacophore[0] hyd_2 = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (37.699, 4.393, 122.609), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd_2 == pharmacophore[1] hyd_3 = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (35.827, 5.861, 123.815), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd_3 == pharmacophore[2] hyd_4 = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (45.46, 2.006, 123.421), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd_4 == pharmacophore[3] ring = PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity((38.0292, 4.3594, 123.7382), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([-0.6702, -0.0512, -0.7404])) assert ring == pharmacophore[4] elif file_name == "2hz1": assert len(pharmacophore) == 10 assert pharmacophore.molecular_system is not None assert pharmacophore.ligand is None # Acceptor hb_acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity((2.327, 3.574, 2.628), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([-0.8834, 0.2719, 0.3816])) # Hydrophobics assert hb_acceptor == pharmacophore[0] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (5.134, 11.9745, 11.8155), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[1] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((0.396, 6.793, 7.373), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[2] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((11.724, 5.702, 7.226), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[3] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((12.502, 7.731, 9.51), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[4] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((7.62, 3.602, 4.389), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[5] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((8.728, 11.736, 11.502), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[6] # Negative charges neg_sphere = PharmacophoricPoint(feat_type="negative charge", center=puw.quantity( (2.279, 2.6625, 3.2525), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert neg_sphere == pharmacophore[8] neg_sphere = PharmacophoricPoint(feat_type="negative charge", center=puw.quantity( (1.074, 4.8205, 7.3245), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert neg_sphere == pharmacophore[9] elif file_name == "2hzi": assert len(pharmacophore) == 5 assert pharmacophore.molecular_system is not None assert pharmacophore.ligand is None acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity((16.163, 12.126, 2.521), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([-0.0991, 0.9107, 0.4011])) assert acceptor == pharmacophore[0] donor = PharmacophoricPoint( feat_type="hb donor", center=puw.quantity((13.988, 12.055, 2.867), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([-0.1195, -0.9419, -0.3139])) assert donor == pharmacophore[1] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (10.418, 11.8007, 2.3763), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[2] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((21.7962, 17.734, 4.249), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[3] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity((17.506, 13.853, 3.414), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[4] elif file_name == "1qku": assert len(pharmacophore) == 6 assert pharmacophore.molecular_system is not None assert pharmacophore.ligand is not None # Acceptors acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity((100.598, 17.99, 25.704), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([0.7872, -0.4533, 0.4182])) assert acceptor == pharmacophore[0] acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity((109.61, 12.027, 22.746), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([-0.5805, 0.431, 0.6908])) assert acceptor == pharmacophore[1] # Hydrophobics hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (107.379, 12.449, 24.419), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[3] hyd = PharmacophoricPoint(feat_type="hydrophobicity", center=puw.quantity( (107.2112, 12.5732, 22.1112), "angstroms"), radius=puw.quantity(1.0, "angstroms")) assert hyd == pharmacophore[4] # Rings ring = PharmacophoricPoint( feat_type="aromatic ring", center=puw.quantity((102.8133, 16.7163, 24.5195), "angstroms"), radius=puw.quantity(1.0, "angstroms"), direction=np.array([0.0937, 0.4983, -0.8619])) assert ring == pharmacophore[5]
def _sb_pharmacophore_points( interactions, radius: float, ligand: Chem.Mol, hydrophobics: str = "smarts") -> List[PharmacophoricPoint]: """Static method to obtain a list of pharmacophoric points for the protein-ligand complex. Parameters ---------- interacions : plip.structure.preparation.PLInteraction object containing all interacion data for a single ligand and a protein. radius : float Radius of the spheres of the pharmacophoric points. ligand : rdkit.Chem.Mol The ligand in from the protein-ligand complex. hydrophobics : {"plip", "smarts"} Can be "plip" or "smarts". If the former is chosen the hydrophobic points will be retrieved from the interactions plip calculates. Else smarts patterns will be used. Returns ------- list of openpharmacophore.pharmacophoric_point.PharmacophoricPoint A list of pharmacophoric points. """ radius = puw.quantity(radius, "angstroms") # List with all interactions interactions = interactions.all_itypes # list of pharmacophoric_pharmacophoric_points points = [] # list oh hydrophobic points hydrophobic_points = [] for interaction in interactions: interaction_name = type(interaction).__name__ if interaction_name == "pistack": ligand_center = np.array(interaction.ligandring.center) protein_center = np.array(interaction.proteinring.center) direction = protein_center - ligand_center atom_indices = { atom.idx for atom in interaction.ligandring.atoms } aromatic = PharmacophoricPoint(feat_type="aromatic ring", center=puw.quantity( ligand_center, "angstroms"), radius=radius, direction=direction, atom_indices=atom_indices) points.append(aromatic) elif interaction_name == "hydroph_interaction": if hydrophobics != "plip": continue center = puw.quantity(interaction.ligatom.coords, "angstroms") atom_inx = {interaction.ligatom.idx} hydrophobic = PharmacophoricPoint(feat_type="hydrophobicity", center=center, radius=radius, direction=None, atom_indices=atom_inx) hydrophobic_points.append(hydrophobic) elif interaction_name == "saltbridge": if interaction.protispos: # The ligand has a negative charge center = puw.quantity(interaction.negative.center, "angstroms") atom_indices = { atom.idx for atom in interaction.negative.atoms } charge_sphere = PharmacophoricPoint( feat_type="negative charge", center=center, radius=radius, atom_indices=atom_indices) else: # The ligand has a positive charge center = puw.quantity(interaction.positive.center, "angstroms") atom_indices = { atom.idx for atom in interaction.positive.atoms } charge_sphere = PharmacophoricPoint( feat_type="positive charge", center=center, radius=radius, atom_indices=atom_indices) points.append(charge_sphere) elif interaction_name == "hbond": if interaction.protisdon: # The ligand has an acceptor atom ligand_acceptor_center = np.array(interaction.a.coords) ligand_acceptor_inx = {interaction.a.idx} protein_donor_center = np.array(interaction.d.coords) direction = ligand_acceptor_center - protein_donor_center acceptor = PharmacophoricPoint( feat_type="hb acceptor", center=puw.quantity(ligand_acceptor_center, "angstroms"), radius=radius, direction=direction, atom_indices=ligand_acceptor_inx) points.append(acceptor) else: # The ligand has a donor atom ligand_donor_center = np.array(interaction.d.coords) ligand_donor_inx = {interaction.d.idx} protein_acceptor_center = np.array(interaction.a.coords) direction = protein_acceptor_center - ligand_donor_center donor = PharmacophoricPoint(feat_type="hb donor", center=puw.quantity( ligand_donor_center, "angstroms"), radius=radius, direction=direction, atom_indices=ligand_donor_inx) points.append(donor) else: # TODO: Incorporate other features such as halogenbonds, waterbridges and metal complexes continue # Remove duplicate points points_filtered = [] for p in points: if p not in points_filtered: points_filtered.append(p) # Group hydrophobic interactions within a distance of 2.5 angstroms if len(hydrophobic_points) > 1: hydrophobic_points = StructuredBasedPharmacophore._plip_hydrophobics( hydrophobic_points, radius) if hydrophobics == "smarts": radius = puw.get_value(radius, "angstroms") hydrophobic_points = StructuredBasedPharmacophore._smarts_hydrophobics( ligand, radius) return points_filtered + hydrophobic_points
def test_PharmacophoricPoint(): # First we test that it raises the correct exceptions when the input arguments # are not valid radius = puw.quantity(1.0, "angstroms") center = puw.quantity([1.0, 1.0, 1.0], "angstroms") # Test that center is validated correctly with pytest.raises(exc.IsNotQuantityError, match="center is not a quantity"): PharmacophoricPoint(feat_type="hb donor", center=[1, 2, 3], radius=radius) with pytest.raises(exc.WrongDimensionalityError, match="center has dimensionality"): PharmacophoricPoint(feat_type="hb donor", center=puw.quantity([1.0, 1.0, 1.0], "seconds"), radius=radius) with pytest.raises(exc.BadShapeError, match="center has shape"): PharmacophoricPoint(feat_type="hb donor", center=puw.quantity([1.0, 1.0], "angstroms"), radius=radius) # Test for radius with pytest.raises(exc.IsNotQuantityError, match="radius is not a quantity"): PharmacophoricPoint(feat_type="hb donor", center=center, radius=1.0) with pytest.raises(exc.NegativeRadiusError, match="radius must be a positive"): PharmacophoricPoint(feat_type="hb donor", center=center, radius=puw.quantity(-1.0, "angstroms")) with pytest.raises(exc.WrongDimensionalityError, match="radius has dimensionality"): PharmacophoricPoint(feat_type="hb donor", center=center, radius=puw.quantity(1.0, "seconds")) # Test feature type with pytest.raises(exc.InvalidFeatureType, match="is not a valid feature type"): PharmacophoricPoint(feat_type="rubber duck", center=center, radius=radius) with pytest.raises(exc.OpenPharmacophoreTypeError, match="atom_indices must be"): PharmacophoricPoint(feat_type="hb donor", center=center, radius=radius, atom_indices=1) feat_name = "hb donor" atom_inxs = (3, 4, 5, 6) donor_1 = PharmacophoricPoint(feat_name, center, radius, None, atom_inxs) donor_2 = PharmacophoricPoint(feat_name, center, radius, direction=np.array([1.0, 1.0, 1.0]), atom_indices=atom_inxs) assert donor_1.has_direction == False assert np.allclose(puw.get_value(donor_1.center, "angstroms"), np.array([1.0, 1.0, 1.0])) assert np.allclose(puw.get_value(donor_1.radius, "angstroms"), 1.0) assert atom_inxs == (3, 4, 5, 6) feat_name = "aromatic ring" center = puw.quantity([1.5, -2.0, 3.2], "angstroms") radius = puw.quantity(1.5, "angstroms") direction = np.array([1.0, 1.0, 1.0]) atom_inxs = None ring = PharmacophoricPoint(feat_name, center, radius, direction, atom_inxs) assert ring.has_direction == True assert ring.atom_indices is None assert np.allclose(puw.get_value(ring.center, "angstroms"), np.array([1.5, -2.0, 3.2])) assert np.allclose(puw.get_value(ring.radius, "angstroms"), 1.5) assert np.allclose( ring.direction, np.array([[1.0, 1.0, 1.0]]) / np.linalg.norm(np.array([1.0, 1.0, 1.0]))) assert donor_1 != ring assert donor_2 != donor_1
def from_pharmer( pharmacophore_file: str, load_mol_sys: bool = False ) -> Tuple[List[PharmacophoricPoint], Chem.Mol, Chem.Mol]: """ Loads a pharmacophore from a pharmer json file Parameters ---------- pharmacophore_file : str name of the file containing the pharmacophore load_mol_sys : bool If true loads the molecular system associated to the pharmacophore (Default: False). Returns ------- points : list of openpharmacophore.PharmacophoricPoint A list of pharmacophoric points. molecular_system : rdkit.Chem.Mol The molecular system associated with the pharmacophore. If there is no molecular system or if load_mol_sys is set to false, None is returned. ligand : rdkit.Chem.Mol The ligand associeted to the pharmacophore in case there is one. If there is no ligand None is returnde. """ points = [] molecular_system = None ligand = None if pharmacophore_file.endswith('.json'): with open(pharmacophore_file, "r") as fff: pharmacophore = json.load(fff) else: raise NotImplementedError for pharmer_element in pharmacophore['points']: pharmer_feature_name = pharmer_element['name'] if pharmer_feature_name == 'Aromatic': center, radius, direction = get_pharmer_element_properties( pharmer_element, direction=True) element = PharmacophoricPoint("aromatic ring", center, radius, direction) elif pharmer_feature_name == 'Hydrophobic': center, radius = get_pharmer_element_properties(pharmer_element, direction=False) element = PharmacophoricPoint("hydrophobicity", center, radius) elif pharmer_feature_name == 'HydrogenAcceptor': center, radius, direction = get_pharmer_element_properties( pharmer_element, direction=True) element = PharmacophoricPoint("hb acceptor", center, radius, direction) elif pharmer_feature_name == "HydrogenDonor": center, radius, direction = get_pharmer_element_properties( pharmer_element, direction=True) element = PharmacophoricPoint("hb donor", center, radius, direction) elif pharmer_feature_name == "PositiveIon": center, radius = get_pharmer_element_properties(pharmer_element, direction=False) element = PharmacophoricPoint("positive charge", center, radius) elif pharmer_feature_name == "NegativeIon": center, radius = get_pharmer_element_properties(pharmer_element, direction=False) element = PharmacophoricPoint("negative charge", center, radius) elif pharmer_feature_name == "ExclusionSphere": center, radius = get_pharmer_element_properties(pharmer_element, direction=False) element = PharmacophoricPoint("excluded volume", center, radius) elif pharmer_feature_name == 'InclusionSphere': center, radius = get_pharmer_element_properties(pharmer_element, direction=False) element = PharmacophoricPoint("included volume", center, radius) insort_right(points, element, key=lambda p: p.short_name) if load_mol_sys: has_ligand = "ligand" in pharmacophore and pharmacophore["ligand"] != "" if has_ligand: ligand = Chem.rdmolfiles.MolFromPDBBlock(pharmacophore["ligand"]) has_receptor = "receptor" in pharmacophore and pharmacophore[ "receptor"] != "" if has_receptor: receptor = Chem.rdmolfiles.MolFromPDBBlock( pharmacophore["receptor"]) molecular_system = receptor return points, molecular_system, ligand