diff --git a/modules/mol/alg/pymod/ligand_scoring.py b/modules/mol/alg/pymod/ligand_scoring.py index f94e1740edbc4bf6a455276d569a54f79a19b2e8..347b8e91a66a31e645d463e643d755ccfe87b04d 100644 --- a/modules/mol/alg/pymod/ligand_scoring.py +++ b/modules/mol/alg/pymod/ligand_scoring.py @@ -740,7 +740,14 @@ class LigandScorer: no_intrachain=True, return_dist_test=True, check_resnames=self.check_resnames) - LogDebug("lDDT-PLI for symmetry %d: %.4f" % (i, global_lddt)) + if lddt_tot == 0: + LogDebug("lDDT-PLI is undefined for %d" % i) + self._unassigned_target_ligands_reason[ + target_ligand] = ("no_contact", + "No lDDT-PLI contacts in the" + " reference structure") + else: + LogDebug("lDDT-PLI for symmetry %d: %.4f" % (i, global_lddt)) # Save results? if not lddt_pli_full_matrix[target_i, model_i]: @@ -832,7 +839,7 @@ class LigandScorer: # First only consider top coverage matches. min_coverage = np.max(coverage) - while min_coverage > 0: + while min_coverage > 0 and not np.all(np.isnan(mat1)): LogVerbose("Looking for matches with coverage >= %s" % min_coverage) min_mat1 = LigandScorer._nanmin_nowarn(mat1, coverage < min_coverage) while not np.isnan(min_mat1): @@ -1362,6 +1369,9 @@ class LigandScorer: This indicates different stoichiometries. * `symmetries`: too many symmetries were found (by graph isomorphisms). Increase `max_symmetries`. + * `no_contact`: there were no lDDT contacts between the binding site + and the ligand, and lDDT-PLI is undefined. Increase the value of + `lddt_pli_radius` to at least the value of the binding site `radius`. Some of these reasons can be overlapping, but a single reason will be reported. @@ -1424,6 +1434,10 @@ class LigandScorer: This indicates different stoichiometries. * `symmetries`: too many symmetries were found (by graph isomorphisms). Increase `max_symmetries`. + * `no_contact`: there were no lDDT contacts between the binding site + and the ligand in the target structure, and lDDT-PLI is undefined. + Increase the value of `lddt_pli_radius` to at least the value of the + binding site `radius`. Some of these reasons can be overlapping, but a single reason will be reported. diff --git a/modules/mol/alg/tests/test_ligand_scoring.py b/modules/mol/alg/tests/test_ligand_scoring.py index df2cd5287185328197d240fa5755818af91d69dc..4d39ced9cfd38cfd28644f851e5ff0df926b948d 100644 --- a/modules/mol/alg/tests/test_ligand_scoring.py +++ b/modules/mol/alg/tests/test_ligand_scoring.py @@ -708,6 +708,40 @@ class TestLigandScoring(unittest.TestCase): sc.unassigned_target_ligands["F"][1] == "symmetries" + def test_no_lddt_pli_contact(self): + """ + Test behaviour where a binding site has no lDDT-PLI contacts. + + We give two copies of the target ligand which have binding site atoms + within radius=5A but no atoms at 4A. We set lddt_pli_radius=4 so that + there are no contacts for the lDDT-PLI computation, and lDDT is None. + + We check that: + - We don't get an lDDT-PLI assignment + - Both target ligands are unassigned and have the + - We get an RMSD assignment + - The second copy of the target and model ligands ensure that the + disambiguation code (which checks for the best lDDT-PLI when 2 RMSDs + are identical) works in this case (where there is no lDDT-PLI to + disambiguate the RMSDs). + """ + trg = _LoadPDB("T1118v1.pdb") + trg_lig = _LoadEntity("T1118v1_001.sdf") + mdl = _LoadPDB("T1118v1LG035_1.pdb") + mdl_lig = _LoadEntity("T1118v1LG035_1_1_1.sdf") + + # Ensure it's unassigned in lDDT + sc = LigandScorer(mdl, trg, [mdl_lig, mdl_lig], [trg_lig, trg_lig], + radius=5, lddt_pli_radius=4, rename_ligand_chain=True) + assert sc.lddt_pli == {} + assert sc.unassigned_target_ligands['00001_C'][1] == "no_contact" + assert sc.unassigned_target_ligands['00001_C_2'][1] == "no_contact" + assert sc.unassigned_model_ligands['00001_FE'][1] == "no_contact" + assert sc.unassigned_model_ligands['00001_FE_2'][1] == "no_contact" + # However the first ligand should have an RMSD + self.assertAlmostEqual(sc.rmsd['00001_FE'][1], 2.1703031063079834, 4) + + if __name__ == "__main__": from ost import testutils if testutils.DefaultCompoundLibIsSet():