From cafcf25a37b350551779f2ff74ffd6c4e293c1db Mon Sep 17 00:00:00 2001
From: Gerardo Tauriello <gerardo.tauriello@unibas.ch>
Date: Fri, 30 Sep 2016 11:25:42 +0200
Subject: [PATCH] SCHWED-1421: Added documentation for SidechainReconstructor.

---
 doc/tests/CMakeLists.txt                     |   1 +
 doc/tests/scripts/sidechain_reconstruct.py   |   4 +-
 doc/tests/scripts/sidechain_reconstructor.py |  20 +++
 doc/tests/scripts/sidechain_steps.py         |   2 +-
 doc/tests/test_doctests.py                   |   8 +
 modelling/doc/monte_carlo.rst                |   6 +-
 sidechain/doc/CMakeLists.txt                 |   1 +
 sidechain/doc/graph.rst                      |   5 +-
 sidechain/doc/index.rst                      |  46 +++--
 sidechain/doc/loading.rst                    |   2 +-
 sidechain/doc/reconstruct.rst                | 167 +++++++++++++++++++
 sidechain/pymod/_reconstruct_sidechains.py   |   4 +-
 12 files changed, 227 insertions(+), 39 deletions(-)
 create mode 100644 doc/tests/scripts/sidechain_reconstructor.py
 create mode 100644 sidechain/doc/reconstruct.rst

diff --git a/doc/tests/CMakeLists.txt b/doc/tests/CMakeLists.txt
index df61bbb8..db07dd88 100644
--- a/doc/tests/CMakeLists.txt
+++ b/doc/tests/CMakeLists.txt
@@ -47,6 +47,7 @@ set (DOC_TEST_SCRIPTS
   scripts/modelling_loop_candidates.py
 
   scripts/sidechain_reconstruct.py
+  scripts/sidechain_reconstructor.py
   scripts/sidechain_steps.py
 )
 
diff --git a/doc/tests/scripts/sidechain_reconstruct.py b/doc/tests/scripts/sidechain_reconstruct.py
index e08c6dde..f1e12512 100644
--- a/doc/tests/scripts/sidechain_reconstruct.py
+++ b/doc/tests/scripts/sidechain_reconstruct.py
@@ -2,10 +2,10 @@ from ost import io, mol
 from promod3 import sidechain
 
 # load a protein 
-prot = io.LoadPDB('data/1eye.pdb')
+prot = io.LoadPDB('data/1CRN.pdb')
 # get only amino acids
 prot = mol.CreateEntityFromView(prot.Select("peptide=true"), True)
 io.SavePDB(prot, 'sidechain_test_orig.pdb')
 # reconstruct sidechains
-sidechain.Reconstruct(prot)
+sidechain.Reconstruct(prot, keep_sidechains=False)
 io.SavePDB(prot, 'sidechain_test_rec.pdb')
diff --git a/doc/tests/scripts/sidechain_reconstructor.py b/doc/tests/scripts/sidechain_reconstructor.py
new file mode 100644
index 00000000..254d7656
--- /dev/null
+++ b/doc/tests/scripts/sidechain_reconstructor.py
@@ -0,0 +1,20 @@
+from ost import io
+from promod3 import sidechain, loop
+
+# load example (has res. numbering starting at 1)
+prot = io.LoadPDB('data/1CRN.pdb')
+res_list = prot.residues
+seqres_str = ''.join([r.one_letter_code for r in res_list])
+
+# initialize AllAtom environment and sidechain reconstructor
+env = loop.AllAtomEnv(seqres_str)
+env.SetInitialEnvironment(prot)
+sc_rec = sidechain.SidechainReconstructor(keep_sidechains=False)
+sc_rec.AttachEnvironment(env)
+
+# reconstruct subset (res. num. 6..10)
+res = sc_rec.Reconstruct(6, 5)
+# update environment with solution
+env.SetEnvironment(res.env_pos)
+# store all positions of environment
+io.SavePDB(env.GetAllAtomPositions().ToEntity(), 'sc_rec_test.pdb')
diff --git a/doc/tests/scripts/sidechain_steps.py b/doc/tests/scripts/sidechain_steps.py
index ca6d2c5c..c2f5a4f4 100644
--- a/doc/tests/scripts/sidechain_steps.py
+++ b/doc/tests/scripts/sidechain_steps.py
@@ -2,7 +2,7 @@ from ost import io,mol
 from promod3 import sidechain
 
 # load a protein
-prot = io.LoadPDB('data/1eye.pdb')
+prot = io.LoadPDB('data/1CRN.pdb')
 # load rotamer library and settings with default values
 settings = sidechain.RotamerSettings()
 library = sidechain.LoadDunbrackLib()
diff --git a/doc/tests/test_doctests.py b/doc/tests/test_doctests.py
index 201aee01..e06f3f48 100644
--- a/doc/tests/test_doctests.py
+++ b/doc/tests/test_doctests.py
@@ -363,6 +363,14 @@ class DocTests(unittest.TestCase):
         os.remove('sidechain_test_orig.pdb')
         os.remove('sidechain_test_rec.pdb')
 
+    def testSidechainReconstructor(self):
+        # run it
+        self.checkPMRun('sidechain_reconstructor.py', [], 0)
+        # check that result exists and is readable
+        io.LoadPDB('sc_rec_test.pdb')
+        # clean up
+        os.remove('sc_rec_test.pdb')
+
     def testSidechainSteps(self):
         # run it
         self.checkPMRun('sidechain_steps.py', [], 0)
diff --git a/modelling/doc/monte_carlo.rst b/modelling/doc/monte_carlo.rst
index a7a37b91..dbb394d6 100644
--- a/modelling/doc/monte_carlo.rst
+++ b/modelling/doc/monte_carlo.rst
@@ -22,8 +22,8 @@ Carlo sampling to the N-terminal part of crambin:
 .. literalinclude:: ../../../tests/doc/scripts/modelling_monte_carlo.py
 
 .. method:: SampleMonteCarlo(sampler, closer, scorer, cooler, steps,\
-                             bb_list, initialize=true, seed=0,\
-                             lowest_energy_conformation=true)
+                             bb_list, initialize=True, seed=0,\
+                             lowest_energy_conformation=True)
 
   A convenient function to perform Monte Carlo sampling using a simulated
   annealing scheme. In every iteration, a new loop conformation gets proposed by
@@ -47,7 +47,7 @@ Carlo sampling to the N-terminal part of crambin:
                         point, based on the samplers Initialize function.
                         The input *bb_list* gets used otherwise.
   :param seed:          Seed for internal random number generator.
-  :param lowest_energy_conformation:  If true, we choose the lowest scoring
+  :param lowest_energy_conformation:  If True, we choose the lowest scoring
                                       conformation of the trajectory. Otherwise,
                                       the last accepted proposal.
 
diff --git a/sidechain/doc/CMakeLists.txt b/sidechain/doc/CMakeLists.txt
index 75e2722a..451e2307 100644
--- a/sidechain/doc/CMakeLists.txt
+++ b/sidechain/doc/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(SIDECHAIN_RST
 index.rst
+reconstruct.rst
 rotamer.rst
 rotamer_id.rst
 frame.rst
diff --git a/sidechain/doc/graph.rst b/sidechain/doc/graph.rst
index 3f37634a..965355b4 100644
--- a/sidechain/doc/graph.rst
+++ b/sidechain/doc/graph.rst
@@ -1,4 +1,4 @@
-Coming to a solution
+Rotamer Graph
 ================================================================================
 
 .. currentmodule:: promod3.sidechain
@@ -12,9 +12,6 @@ decomposition and dead end elimination, decomposes the graph in a tree form
 and finally comes back with a solution.
 
 
-The Rotamer Graph
---------------------------------------------------------------------------------
-
 .. class:: RotamerGraph
 
   The Graph object has no constructor exported to python. It is meant to be
diff --git a/sidechain/doc/index.rst b/sidechain/doc/index.rst
index e8528c16..62cc9b2d 100644
--- a/sidechain/doc/index.rst
+++ b/sidechain/doc/index.rst
@@ -6,32 +6,27 @@
 
 .. currentmodule:: promod3.sidechain
 
-Tools and algorithms to model sidechains given backbone coordinates. 
-The full module is heavily based on SCWRL4 [krivov2009]_ .
-The according paper describes the modelling of sidechains using two different
-rotamer models. A rigid model, as well as a flexible model. Both models are
-implemented in PROMOD3 and can be applied in flexible ways.
-
-Reconstruct Function
---------------------------------------------------------------------------------
+Tools and algorithms to model sidechains given backbone coordinates. The full
+module is heavily based on SCWRL4 [krivov2009]_ . The according paper describes
+the modelling of sidechains using two different rotamer models. A rigid model,
+as well as a flexible model. Both models are implemented in PROMOD3 and can be
+applied in flexible ways.
 
 The simplest usage of the module is provided by the :func:`Reconstruct`
 function:
 
 .. literalinclude:: ../../../tests/doc/scripts/sidechain_reconstruct.py
 
-.. autofunction:: Reconstruct
-
+For use during loop modelling, the :class:`SidechainReconstructor` can be used:
 
-Sidechain Module Functionality
---------------------------------------------------------------------------------
+.. literalinclude:: ../../../tests/doc/scripts/sidechain_reconstructor.py
 
 The following code fragment shows an example of a basic sidechain reconstruction
-algorithm using the functionality in the module. Note, that this code will
-crash as soon as you have structures containing all the weirdness the PDB throws
-at us. In this case, you should use the :func:`~promod3.sidechain.Reconstruct` 
-function above. An overview of the full provided functionality can be found at 
-the bottom of this page.
+algorithm using the functionality in the module. Note, that this code will crash
+as soon as you have structures containing all the weirdness the PDB throws at
+us. In this case, you should use the :func:`Reconstruct`  function above. An
+overview of the full provided functionality can be found at  the bottom of this
+page.
 
 .. literalinclude:: ../../../tests/doc/scripts/sidechain_steps.py
 
@@ -40,11 +35,12 @@ Contents:
 .. toctree::
    :maxdepth: 2
 
-   RotamerID <rotamer_id>
-   Rotamers <rotamer>
-   Frame <frame>
-   Rotamer Library <rotamer_lib>
-   RotamerGraph <graph>
-   The Settings - Control Things... <sidechain_settings>
-   Disulfid Bond Evaluation <disulfid>
-   Loading Libraries <loading>
+   reconstruct
+   rotamer_id
+   rotamer
+   frame
+   rotamer_lib
+   graph
+   sidechain_settings
+   disulfid
+   loading
diff --git a/sidechain/doc/loading.rst b/sidechain/doc/loading.rst
index 82ad5bf2..8f147190 100644
--- a/sidechain/doc/loading.rst
+++ b/sidechain/doc/loading.rst
@@ -1,4 +1,4 @@
-Load Rotamer Libraries
+Loading Rotamer Libraries
 ================================================================================
 
 .. currentmodule:: promod3.sidechain
diff --git a/sidechain/doc/reconstruct.rst b/sidechain/doc/reconstruct.rst
new file mode 100644
index 00000000..e461b3cf
--- /dev/null
+++ b/sidechain/doc/reconstruct.rst
@@ -0,0 +1,167 @@
+Sidechain Reconstruction
+================================================================================
+
+.. currentmodule:: promod3.sidechain
+
+Two methods are provided to fully reconstruct sidechains of residues:
+
+- the :func:`Reconstruct` function handles a full OST
+  :class:`~ost.mol.EntityHandle`
+- the :class:`SidechainReconstructor` is linked to an all atom environment
+  and used to reconstruct sidechains of single loops
+
+Reconstruct Function
+--------------------------------------------------------------------------------
+
+.. autofunction:: Reconstruct
+
+
+SidechainReconstructor Class
+--------------------------------------------------------------------------------
+
+.. class:: SidechainReconstructor(keep_sidechains=True, build_disulfids=True, \
+                                  cutoff=20, graph_max_complexity=100000000, \
+                                  graph_intial_epsilon=0.02, \
+                                  disulfid_max_distance=8, \
+                                  disulfid_score_thresh=45)
+
+  Reconstruct sidechains for single loops. Must be linked to an all atom env.
+  (:meth:`AttachEnvironment`) containing the structural data.
+
+  :param keep_sidechains: Flag, whether complete sidechains in env. (i.e. 
+                          containing all required atoms) should be kept rigid
+                          and directly be added to the result.
+  :type keep_sidechains: :class:`bool`
+
+  :param build_disulfids: Flag, whether possible disulfid bonds should be 
+                          searched. If a disulfid bond is found, the two
+                          participating cysteins are fixed and added to
+                          the result.
+  :type build_disulfids: :class:`bool`
+
+  :param cutoff: Cutoff used to search relevant residues surrounding the loop.
+  :type cutoff:  :class:`float`
+
+  :param graph_max_complexity: Max. complexity for
+                               :meth:`RotamerGraph.TreeSolve`.
+  :type graph_max_complexity:  :class:`int`
+  :param graph_intial_epsilon: Initial epsilon for
+                               :meth:`RotamerGraph.TreeSolve`.
+  :type graph_intial_epsilon:  :class:`float`
+
+  :param disulfid_max_distance: Max. distance for 2 CYS-CA atoms to be
+                                considered close enough to check for bridges.
+  :type disulfid_max_distance:  :class:`float`
+  :param disulfid_score_thresh: If :meth:`DisulfidScore` between two CYS is
+                                below this threshold, we consider them to be
+                                disulfid-bonded.
+  :type disulfid_score_thresh:  :class:`float`
+
+
+  .. method:: Reconstruct(start_resnum, num_residues, chain_idx=0)
+
+    Reconstruct sidechains for desired loop (extracted from environment). All
+    residues in the loop are expected to contain valid CB positions (or CA for
+    GLY), which are used to look for other potentially relevant residues
+    surrounding the loop. The resulting structural data will contain all
+    residues in the loop and in the surrounding. Sidechains are added for all
+    residues in the loop and for surrounding residues if they are relevant for
+    the loop sidechains.
+
+    Note that the structural data of the loop is expected to be in the linked
+    environment before calling this!
+
+    :param start_resnum: Start of loop.
+    :type start_resnum:  :class:`int` / :class:`ost.mol.ResNum`
+    :param num_residues: Length of loop.
+    :type num_residues:  :class:`int`
+    :param chain_idx: Chain the loop belongs to.
+    :type chain_idx:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if reconstructor was never attached
+             to an environment or if parameters lead to invalid / unset
+             positions in environment.
+
+  .. method:: AttachEnvironment(env, use_frm=True, use_bbdep_lib=True, \
+                                consider_hbonds=True)
+              AttachEnvironment(env, use_frm, rotamer_library, \
+                                consider_hbonds=True)
+    
+    Link reconstructor to given *env*. A helper class is used in the background
+    to provide sidechain-objects for the environment. As this class is reused by
+    every reconstructor linked to *env*, the used parameters must be consistent
+    if multiple reconstructors are used (or you must use a distinct *env*).
+
+    :param env: Link to this environment.
+    :type env:  :class:`~promod3.loop.AllAtomEnv`
+    :param use_frm: If True, use flexible rotamer model, else rigid.
+    :type use_frm:  :class:`bool`
+    :param use_bbdep_lib: If True, use default backbone dependent rot. library
+                          (:meth:`Dunbrack <LoadDunbrackLib>`), else use
+                          backbone independent one
+                          (:meth:`Penultimate <LoadPenultimateLib>`).
+    :type use_bbdep_lib:  :class:`bool`
+    :param rotamer_library: Custom rotamer library to be used.
+    :type rotamer_library:  :class:`BBDepRotamerLib` / :class:`RotamerLib`
+    :param consider_hbonds: Flag, whether hbonds should be evaluated in the
+                            energy function. If set to False, no hydrogens will
+                            be built when building rotamers and frames.
+    :type consider_hbonds: :class:`bool`
+    
+    :return: :class:`SidechainReconstructionData`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *env* was already linked to
+            another reconstructor with inconsistent parameters. Acceptable
+            changes:
+
+            - *keep_sidechains* = True, if previously False
+            - *build_disulfids* = False, if previously True
+
+The AllAtomEnvPositions class
+--------------------------------------------------------------------------------
+
+.. class:: SidechainReconstructionData
+
+  Contains the results of a sidechain reconstruction
+  (:meth:`SidechainReconstructor.Reconstruct`). All attributes are read only!
+
+  .. attribute:: env_pos
+
+    Container for structural data and mapping to the internal residue indices
+    of the used :class:`~promod3.loop.AllAtomEnv`. Useful for scoring and env.
+    updates.
+
+    :type: :class:`~promod3.loop.AllAtomEnvPositions`
+
+  .. attribute:: loop_length
+
+    Length of the loop used to generate this result. The first *loop_length*
+    residues in *env_pos* are guaranteed to belong to the loop.
+
+    :type: :class:`int`
+
+  .. attribute:: rotamer_res_indices
+
+    Indices of residues within *env_pos* for which we generated a new sidechain
+    (in [*0, len(env_pos.res_indices)-1*]).
+
+    :type: :class:`list` of :class:`int`
+
+  .. attribute:: disulfid_res_indices
+
+    Indices of residues within *env_pos* for which we generated a disulfid
+    bridge (in [*0, len(env_pos.res_indices)-1*]).
+
+    :type: :class:`list` of :class:`int`
+
+  .. attribute:: n_stem_idx
+
+    Residue index of N stem (= *env_pos.res_indices[0]*).
+
+    :type: :class:`int`
+
+  .. attribute:: c_stem_idx
+
+    Residue index of C stem (= *env_pos.res_indices[loop_length-1]*).
+
+    :type: :class:`int`
diff --git a/sidechain/pymod/_reconstruct_sidechains.py b/sidechain/pymod/_reconstruct_sidechains.py
index 9fcf0c45..2bbbfd4f 100644
--- a/sidechain/pymod/_reconstruct_sidechains.py
+++ b/sidechain/pymod/_reconstruct_sidechains.py
@@ -400,9 +400,7 @@ def Reconstruct(ent, keep_sidechains=False, build_disulfids=True,
 
     :param consider_hbonds: Flag, whether hbonds should be evaluated in the
                             energy function. If set to False, no hydrogens will
-                            be built when building rotamers and frame and the
-                            **add_polar_hydrogens** flag won't have any
-                            consequences.
+                            be built when building rotamers and frame.
 
     :param consider_ligands: Flag, whether to add ligands (anything in chain
                              '_') as static objects.
-- 
GitLab