From fa1f00e34d776403a08acf30a84ffbe0fce74372 Mon Sep 17 00:00:00 2001
From: Gerardo Tauriello <gerardo.tauriello@unibas.ch>
Date: Thu, 11 Jul 2019 20:40:25 +0200
Subject: [PATCH] SCHWED-4333: remove early inf-catch as OpenMM may recover
 from it.

Instead, we catch the exception thrown when energy minimization fails. OpenMM
can recover from inf-energy which appears due to clashing hydrogens.
---
 modelling/pymod/_pipeline.py     | 23 +++++++++++++----------
 modelling/tests/test_pipeline.py |  8 ++++----
 2 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/modelling/pymod/_pipeline.py b/modelling/pymod/_pipeline.py
index d8202b42..b8aef45f 100644
--- a/modelling/pymod/_pipeline.py
+++ b/modelling/pymod/_pipeline.py
@@ -315,7 +315,7 @@ def MinimizeModelEnergy(mhandle, max_iterations=12, max_iter_sd=20,
     # setup mm simulation
     sim = _SetupMmSimulation(mhandle.model, force_fields)
 
-    # check for certain failure -> we get NaN/Inf if atoms are on top each other
+    # check for certain failure -> we get NaN if atoms are on top each other
     cur_energy = sim.GetEnergy()
     if math.isnan(cur_energy):
         msg = "OpenMM could not minimize energy as atoms are on top of "\
@@ -323,12 +323,6 @@ def MinimizeModelEnergy(mhandle, max_iterations=12, max_iter_sd=20,
         ost.LogError(msg)
         AddModellingIssue(mhandle, msg, ModellingIssue.Severity.MAJOR)
         return
-    if math.isinf(cur_energy):
-        msg = "OpenMM could not minimize energy as atoms are almost "\
-              "on top of each other!"
-        ost.LogError(msg)
-        AddModellingIssue(mhandle, msg, ModellingIssue.Severity.MAJOR)
-        return
         
     # settings to check for stereochemical problems
     clashing_distances = mol.alg.DefaultClashingDistances()
@@ -339,9 +333,18 @@ def MinimizeModelEnergy(mhandle, max_iterations=12, max_iter_sd=20,
         # update atoms
         ost.LogInfo("Perform energy minimization "
                     "(iteration %d, energy: %g)" % (i+1, cur_energy))
-        sim.ApplySD(tolerance = 1.0, max_iterations = max_iter_sd)
-        sim.ApplyLBFGS(tolerance = 1.0, max_iterations = max_iter_lbfgs)
-        sim.UpdatePositions()
+        try:
+            sim.ApplySD(tolerance = 1.0, max_iterations = max_iter_sd)
+            sim.ApplyLBFGS(tolerance = 1.0, max_iterations = max_iter_lbfgs)
+            sim.UpdatePositions()
+        except Exception as ex:
+            # ABORT ON FAIL
+            msg = "OpenMM could not minimize energy! Usually this is caused "\
+                  "by atoms which are almost on top of each other. Exception: "\
+                  "%s('%s')!" % (type(ex).__name__, ex)
+            ost.LogError(msg)
+            AddModellingIssue(mhandle, msg, ModellingIssue.Severity.MAJOR)
+            return
 
         # check for stereochemical problems
         if ignore_stereo_log:
diff --git a/modelling/tests/test_pipeline.py b/modelling/tests/test_pipeline.py
index ac4e4bac..61c8f44d 100644
--- a/modelling/tests/test_pipeline.py
+++ b/modelling/tests/test_pipeline.py
@@ -342,11 +342,11 @@ class PipelineTests(unittest.TestCase):
         modelling.MinimizeModelEnergy(mhandle)
         self.assertEqual(len(log.messages['ERROR']), 1)
         self.assertEqual(len(mhandle.modelling_issues), 1)
-        exp_msg = "OpenMM could not minimize energy as atoms are "\
-                  "almost on top of each other!"
-        self.assertEqual(log.messages['ERROR'][0], exp_msg)
+        exp_msg = "OpenMM could not minimize energy! Usually this is caused "\
+                  "by atoms which are almost on top of each other."
+        self.assertTrue(log.messages['ERROR'][0].startswith(exp_msg))
         issue = mhandle.modelling_issues[0]
-        self.assertEqual(issue.text, exp_msg)
+        self.assertTrue(issue.text.startswith(exp_msg))
         self.assertTrue(issue.is_major())
         self.assertEqual(len(issue.residue_list), 0)
 
-- 
GitLab