From f7b42cf36cd7697c022ba0c7cb855f9604797029 Mon Sep 17 00:00:00 2001
From: Xavier Robin <xavier.robin@unibas.ch>
Date: Wed, 26 Jul 2023 12:04:39 +0200
Subject: [PATCH] fix: SCHWED-5954 report no ligands instead of raising an
 error

---
 modules/mol/alg/pymod/ligand_scoring.py      | 20 ++++++++++++++--
 modules/mol/alg/tests/test_ligand_scoring.py | 24 ++++++++++++++++++++
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/modules/mol/alg/pymod/ligand_scoring.py b/modules/mol/alg/pymod/ligand_scoring.py
index c0743d196..c06a99959 100644
--- a/modules/mol/alg/pymod/ligand_scoring.py
+++ b/modules/mol/alg/pymod/ligand_scoring.py
@@ -265,7 +265,7 @@ class LigandScorer:
                                                         target_ligands,
                                                         rename_ligand_chain)
         if len(self.target_ligands) == 0:
-            raise ValueError("No ligands in the target")
+            LogWarning("No ligands in the target")
 
         # Extract ligands from model
         if model_ligands is None:
@@ -275,7 +275,9 @@ class LigandScorer:
                                                        model_ligands,
                                                        rename_ligand_chain)
         if len(self.model_ligands) == 0:
-            raise ValueError("No ligands in the model")
+            LogWarning("No ligands in the model")
+            if len(self.target_ligands) == 0:
+                raise ValueError("No ligand in the model and in the target")
 
         self._chain_mapper = chain_mapper
         self.resnum_alignments = resnum_alignments
@@ -764,6 +766,10 @@ class LigandScorer:
         else:
             mat2 = np.copy(mat2)
         assignments = []
+        if 0 in mat1.shape:
+            # No model or target ligand
+            LogDebug("No model or target ligand, returning no assignment.")
+            return assignments
         min_mat1 = LigandScorer._nanmin_nowarn(mat1)
         while not np.isnan(min_mat1):
             best_mat1 = np.argwhere(mat1 == min_mat1)
@@ -1252,6 +1258,7 @@ class LigandScorer:
 
         Currently, the following reasons are reported:
 
+        * `no_ligand`: No ligand in the model.
         * `binding_site`: no residue in proximity of the target ligand.
         * `model_representation`: no representation of the reference binding
           site was found in the model
@@ -1284,6 +1291,7 @@ class LigandScorer:
 
         Currently, the following reasons are reported:
 
+        * `no_ligand`: No ligand in the target.
         * `binding_site`: no residue in proximity of the target ligand.
         * `model_representation`: no representation of the reference binding
           site was found in the model
@@ -1413,6 +1421,10 @@ class LigandScorer:
                 if not ("unassigned" in ligand_details and ligand_details["unassigned"]):
                     raise RuntimeError("Ligand %s is mapped to %s" % (ligand, ligand_details["target_ligand"]))
 
+        # Were there any ligands in the target?
+        if len(self.target_ligands) == 0:
+            return ("no_ligand", "No ligand in the target")
+
         # Do we have isomorphisms with the target?
         for trg_lig_idx, assigned in enumerate(self._assignment_isomorphisms[:, ligand_idx]):
             if np.isnan(assigned):
@@ -1465,6 +1477,10 @@ class LigandScorer:
                         raise RuntimeError("Ligand %s is mapped to %s.%s" % (
                             ligand, cname, rnum))
 
+        # Were there any ligands in the model?
+        if len(self.model_ligands) == 0:
+            return ("no_ligand", "No ligand in the model")
+
         # Is it because there was no valid binding site or no representation?
         if ligand in self._unassigned_target_ligands_reason:
             return self._unassigned_target_ligands_reason[ligand]
diff --git a/modules/mol/alg/tests/test_ligand_scoring.py b/modules/mol/alg/tests/test_ligand_scoring.py
index 961a28093..35de1ffb3 100644
--- a/modules/mol/alg/tests/test_ligand_scoring.py
+++ b/modules/mol/alg/tests/test_ligand_scoring.py
@@ -568,6 +568,30 @@ class TestLigandScoring(unittest.TestCase):
         }
         assert sc.lddt_pli["L_OXY"][1] is None
 
+        # With missing ligands
+        sc = LigandScorer(mdl.Select("cname=A"), trg, None, None)
+        assert sc.unassigned_target_ligands["E"][1] == ('no_ligand', 'No ligand in the model')
+
+        sc = LigandScorer(mdl, trg.Select("cname=A"), None, None)
+        assert sc.unassigned_model_ligands["L_2"][1] == ('no_ligand', 'No ligand in the target')
+
+        sc = LigandScorer(mdl.Select("cname=A"), trg, None, None,
+                          unassigned=True, rmsd_assignment=True)
+        assert sc.unassigned_target_ligands["E"][1] == ('no_ligand', 'No ligand in the model')
+
+        sc = LigandScorer(mdl, trg.Select("cname=A"), None, None,
+                          unassigned=True, rmsd_assignment=True)
+        assert sc.unassigned_model_ligands["L_2"][1] == ('no_ligand', 'No ligand in the target')
+
+        # However not everything must be missing
+        with self.assertRaises(ValueError):
+            sc = LigandScorer(mdl.Select("cname=A"), trg.Select("cname=A"), None, None,
+                              unassigned=True, rmsd_assignment=True)
+
+
+
+
+
 
 if __name__ == "__main__":
     from ost import testutils
-- 
GitLab