From 9481742cf2e8246d9dab27929812bcdb6fa4bdcf Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Mon, 12 Sep 2022 10:42:33 +0200
Subject: [PATCH] Accept 0.0 QS-score mappings in QS-score based optimization

The reason for that is that one might start with an initial seed
somewhere in Nirvana that leads to no possible increase in QS-score.
Stoping there might hinder a non-zero QS-score when continuing with
other seeds. And even if the QS-score is 0.0 in the end, the mapping
should make sense from an lDDT perspective more or less...
---
 modules/mol/alg/pymod/chain_mapping.py | 38 +++++++++++++-------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/modules/mol/alg/pymod/chain_mapping.py b/modules/mol/alg/pymod/chain_mapping.py
index 9455000f7..286b440aa 100644
--- a/modules/mol/alg/pymod/chain_mapping.py
+++ b/modules/mol/alg/pymod/chain_mapping.py
@@ -2487,7 +2487,7 @@ def _QSScoreGreedyFull(the_greed, n_mdl_chains):
     while something_happened:
         something_happened = False
         # Try all possible starting points and keep the one giving the best QS score
-        best_score = 0.0
+        best_score = -1.0
         best_mapping = None
         mapped_ref_chains = set(mapping.keys())
         mapped_mdl_chains = set(mapping.values())
@@ -2516,11 +2516,11 @@ def _QSScoreGreedyFull(the_greed, n_mdl_chains):
                             best_score = tmp_score
                             best_mapping = tmp_mapping
 
-        if best_score == 0.0:
-            break # no proper mapping found anymore...
-
-        something_happened = True
-        mapping = best_mapping
+        if best_mapping is not None and len(best_mapping) > len(mapping):
+            # this even accepts extensions that lead to no increase in QS-score
+            # at least they make sense from an lDDT perspective
+            something_happened = True
+            mapping = best_mapping
 
     # translate mapping format and return
     final_mapping = list()
@@ -2577,7 +2577,7 @@ def _QSScoreGreedyBlock(the_greed, seed_size, blocks_per_chem_group):
 
             # extend starting seeds to *seed_size* and retain best scoring block
             # for further extension
-            best_score = 0.0
+            best_score = -1.0
             best_mapping = None
             for s in seeds:
                 seed = dict(mapping)
@@ -2594,7 +2594,7 @@ def _QSScoreGreedyBlock(the_greed, seed_size, blocks_per_chem_group):
                 starting_blocks.append(best_mapping)
 
         # fully expand initial starting blocks
-        best_score = 0.0
+        best_score = -1.0
         best_mapping = None
         for seed in starting_blocks:
             seed = the_greed.ExtendMapping(seed)
@@ -2606,17 +2606,17 @@ def _QSScoreGreedyBlock(the_greed, seed_size, blocks_per_chem_group):
                 best_score = seed_score
                 best_mapping = seed
 
-        if best_score == 0.0:
-            break # no proper mapping found anymore
-
-        something_happened = True
-        mapping.update(best_mapping)
-        for ref_ch, mdl_ch in best_mapping.items():
-            for group_idx in range(len(ref_chem_groups)):
-                if ref_ch in ref_chem_groups[group_idx]:
-                    ref_chem_groups[group_idx].remove(ref_ch)
-                if mdl_ch in mdl_chem_groups[group_idx]:
-                    mdl_chem_groups[group_idx].remove(mdl_ch)
+        if best_mapping is not None and len(best_mapping) > len(mapping):
+            # this even accepts extensions that lead to no increase in QS-score
+            # at least they make sense from an lDDT perspective
+            something_happened = True
+            mapping.update(best_mapping)
+            for ref_ch, mdl_ch in best_mapping.items():
+                for group_idx in range(len(ref_chem_groups)):
+                    if ref_ch in ref_chem_groups[group_idx]:
+                        ref_chem_groups[group_idx].remove(ref_ch)
+                    if mdl_ch in mdl_chem_groups[group_idx]:
+                        mdl_chem_groups[group_idx].remove(mdl_ch)
 
     # translate mapping format and return
     final_mapping = list()
-- 
GitLab