From d0a6e492d614254b950ba219e296d8b3c1919c37 Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Sun, 12 Mar 2017 09:25:04 +0100
Subject: [PATCH] move sidechain modelling pipelines into modelling module

---
 doc/contributing.rst                          | 14 ++--
 doc/gettingstarted.rst                        |  2 +-
 doc/tests/CMakeLists.txt                      |  6 +-
 ...py => modelling_reconstruct_sidechains.py} |  4 +-
 ...y => modelling_sidechain_reconstructor.py} |  4 +-
 ...y => unittest_sidechain_reconstruction.py} |  4 +-
 doc/tests/test_doctests.py                    | 14 ++--
 .../generate_bft_chunks.py                    |  4 +-
 loop/doc/structure_db.rst                     |  6 +-
 modelling/doc/CMakeLists.txt                  |  1 +
 modelling/doc/index.rst                       |  3 +-
 modelling/doc/loop_closing.rst                | 10 +--
 modelling/doc/pipeline.rst                    |  2 +-
 .../doc/sidechain_reconstruction.rst          | 18 +++--
 modelling/pymod/CMakeLists.txt                |  2 +
 modelling/pymod/__init__.py                   |  1 +
 modelling/pymod/_closegaps.py                 |  7 +-
 modelling/pymod/_fragger_handle.py            |  3 +-
 modelling/pymod/_pipeline.py                  | 13 ++--
 .../pymod/_reconstruct_sidechains.py          | 16 ++---
 modelling/pymod/_ring_punches.py              |  5 +-
 modelling/pymod/export_loop_closure.cc        |  2 +-
 modelling/pymod/export_model.cc               |  4 +-
 .../pymod/export_sidechain_reconstructor.cc   |  8 +--
 modelling/pymod/wrap_modelling.cc             |  2 +
 modelling/src/CMakeLists.txt                  |  4 ++
 modelling/src/all_atom_relaxer.hh             |  6 +-
 modelling/src/el_enumerador.cc                | 13 ++--
 modelling/src/loop_candidate.cc               |  4 +-
 modelling/src/model.cc                        |  4 +-
 modelling/src/model.hh                        |  4 +-
 .../src/sidechain_env_listener.cc             | 56 ++++++++-------
 .../src/sidechain_env_listener.hh             | 71 ++++++++++---------
 .../src/sidechain_reconstructor.cc            | 46 ++++++------
 .../src/sidechain_reconstructor.hh            | 10 +--
 modelling/tests/CMakeLists.txt                |  6 ++
 .../tests/data/1crn_sc_test.pdb               |  0
 {sidechain => modelling}/tests/data/1eye.pdb  |  0
 .../tests/data/1eye_rec.pdb                   |  0
 .../tests/data/1eye_sc_test.pdb               |  0
 modelling/tests/test_ring_punches.py          |  4 +-
 .../tests/test_sidechain_reconstruction.py    | 18 ++---
 .../tests/test_sidechain_reconstructor.cc     |  4 +-
 sidechain/doc/CMakeLists.txt                  |  1 -
 sidechain/doc/index.rst                       | 16 +----
 sidechain/pymod/CMakeLists.txt                |  2 -
 sidechain/pymod/__init__.py                   |  2 +-
 sidechain/pymod/wrap_sidechain.cc             |  2 -
 sidechain/src/CMakeLists.txt                  |  4 --
 sidechain/tests/CMakeLists.txt                |  6 --
 50 files changed, 231 insertions(+), 207 deletions(-)
 rename doc/tests/scripts/{sidechain_reconstruct.py => modelling_reconstruct_sidechains.py} (75%)
 rename doc/tests/scripts/{sidechain_reconstructor.py => modelling_sidechain_reconstructor.py} (85%)
 rename doc/tests/scripts/{unittest_sidechain.py => unittest_sidechain_reconstruction.py} (84%)
 rename sidechain/doc/reconstruct.rst => modelling/doc/sidechain_reconstruction.rst (94%)
 rename {sidechain => modelling}/pymod/_reconstruct_sidechains.py (97%)
 rename {sidechain => modelling}/pymod/export_sidechain_reconstructor.cc (94%)
 rename {sidechain => modelling}/src/sidechain_env_listener.cc (83%)
 rename {sidechain => modelling}/src/sidechain_env_listener.hh (74%)
 rename {sidechain => modelling}/src/sidechain_reconstructor.cc (89%)
 rename {sidechain => modelling}/src/sidechain_reconstructor.hh (94%)
 rename {sidechain => modelling}/tests/data/1crn_sc_test.pdb (100%)
 rename {sidechain => modelling}/tests/data/1eye.pdb (100%)
 rename {sidechain => modelling}/tests/data/1eye_rec.pdb (100%)
 rename {sidechain => modelling}/tests/data/1eye_sc_test.pdb (100%)
 rename sidechain/tests/test_sidechain.py => modelling/tests/test_sidechain_reconstruction.py (89%)
 rename {sidechain => modelling}/tests/test_sidechain_reconstructor.cc (98%)

diff --git a/doc/contributing.rst b/doc/contributing.rst
index 0081bf3d..ac0a15f3 100644
--- a/doc/contributing.rst
+++ b/doc/contributing.rst
@@ -203,7 +203,7 @@ good practice to develop new functionality along tests and that right from the
 beginning. At some point, new code needs testing anyway to see if it does what
 it should, so just do this by writing unit tests. Test sources are stored in
 files with a prefix :file:`test_` and usually come per submodule instead of
-sporting a single monolithic :file:`test_sidechain.py`.
+sporting a single monolithic :file:`test_sidechain_reconstruction.py`.
 
 |python| code is evaluated using its own :py_docs:`unit testing framework
 <library/unittest.html>` with a little help from |ost_s|_ (|C++| uses the
@@ -211,14 +211,14 @@ sporting a single monolithic :file:`test_sidechain.py`.
 <http://www.boost.org/doc/libs/1_47_0/libs/test/doc/html/index.html>`_). The
 basic scheme is to import your module, subclass :class:`unittest.TestCase` and
 make the whole file runnable as script using the most common |nameattr|_
-attribute. As an example we test the :func:`promod3.sidechain.Reconstruct`
-function:
+attribute. As an example we test the 
+:func:`promod3.modelling.ReconstructSidechains` function:
 
-.. literalinclude:: ../../tests/doc/scripts/unittest_sidechain.py
+.. literalinclude:: ../../tests/doc/scripts/unittest_sidechain_reconstruction.py
   :linenos:
 
 To hook up your tests with ``make codetest`` (and to create a
-``test_reconstruct.py_run`` target), everything has to be introduced to |cmake|.
+``test_reconstruct_sidechains.py_run`` target), everything has to be introduced to |cmake|.
 First, tell |cmake| to search :file:`tests` for a :file:`CMakeLists.txt` file
 by extending the list of sub-directories in :file:`sidechain/CMakeLists.txt`:
 
@@ -237,7 +237,7 @@ you.
   :linenos:
 
   set(SIDECHAIN_UNIT_TESTS
-    test_reconstruct.py
+    test_reconstruct_sidechains.py
   )
 
   set(SIDECHAIN_TEST_DATA
@@ -253,7 +253,7 @@ Note how we listed the test data that we require in the unit test by defining
 ``SIDECHAIN_TEST_DATA``.
 
 Now tests should be available by ``make check``, ``make codetest`` and
-``make test_reconstruct.py_run``.
+``make test_reconstruct_sidechains.py_run``.
 
 --------------------------------------------------------------------------------
 How To Start Your Own Action
diff --git a/doc/gettingstarted.rst b/doc/gettingstarted.rst
index 489002a8..9b2b8024 100644
--- a/doc/gettingstarted.rst
+++ b/doc/gettingstarted.rst
@@ -35,7 +35,7 @@ the desired target sequence. The modelling steps then are:
 - Build a raw model from a template by copying the part of the template which
   is conserved
 - Perform loop modelling to close all gaps (see :mod:`~promod3.loop` module)
-- Reconstruct sidechains (see :mod:`~promod3.sidechain` module)
+- Reconstruct sidechains (using :mod:`~promod3.sidechain` module)
 - Minimize energy of final model using molecular mechanics
   (using :mod:`ost.mol.mm` from |ost_s|)
 
diff --git a/doc/tests/CMakeLists.txt b/doc/tests/CMakeLists.txt
index 43cbacf9..89bd4fcb 100644
--- a/doc/tests/CMakeLists.txt
+++ b/doc/tests/CMakeLists.txt
@@ -24,7 +24,7 @@ set (DOC_TEST_SCRIPTS
   scripts/core_file_checks.py
 
   scripts/hello_world.py
-  scripts/unittest_sidechain.py
+  scripts/unittest_sidechain_reconstruction.py
 
   scripts/loop_main.py
   scripts/loop_backbone.py
@@ -47,9 +47,9 @@ set (DOC_TEST_SCRIPTS
   scripts/modelling_monte_carlo.py
   scripts/modelling_loop_candidates.py
   scripts/modelling_loop_scoring.py
+  scripts/modelling_reconstruct_sidechains.py
+  scripts/modelling_sidechain_reconstructor.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/modelling_reconstruct_sidechains.py
similarity index 75%
rename from doc/tests/scripts/sidechain_reconstruct.py
rename to doc/tests/scripts/modelling_reconstruct_sidechains.py
index f1e12512..de157d80 100644
--- a/doc/tests/scripts/sidechain_reconstruct.py
+++ b/doc/tests/scripts/modelling_reconstruct_sidechains.py
@@ -1,5 +1,5 @@
 from ost import io, mol
-from promod3 import sidechain
+from promod3 import modelling
 
 # load a protein 
 prot = io.LoadPDB('data/1CRN.pdb')
@@ -7,5 +7,5 @@ prot = io.LoadPDB('data/1CRN.pdb')
 prot = mol.CreateEntityFromView(prot.Select("peptide=true"), True)
 io.SavePDB(prot, 'sidechain_test_orig.pdb')
 # reconstruct sidechains
-sidechain.Reconstruct(prot, keep_sidechains=False)
+modelling.ReconstructSidechains(prot, keep_sidechains=False)
 io.SavePDB(prot, 'sidechain_test_rec.pdb')
diff --git a/doc/tests/scripts/sidechain_reconstructor.py b/doc/tests/scripts/modelling_sidechain_reconstructor.py
similarity index 85%
rename from doc/tests/scripts/sidechain_reconstructor.py
rename to doc/tests/scripts/modelling_sidechain_reconstructor.py
index 254d7656..199c8856 100644
--- a/doc/tests/scripts/sidechain_reconstructor.py
+++ b/doc/tests/scripts/modelling_sidechain_reconstructor.py
@@ -1,5 +1,5 @@
 from ost import io
-from promod3 import sidechain, loop
+from promod3 import loop, modelling
 
 # load example (has res. numbering starting at 1)
 prot = io.LoadPDB('data/1CRN.pdb')
@@ -9,7 +9,7 @@ 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 = modelling.SidechainReconstructor(keep_sidechains=False)
 sc_rec.AttachEnvironment(env)
 
 # reconstruct subset (res. num. 6..10)
diff --git a/doc/tests/scripts/unittest_sidechain.py b/doc/tests/scripts/unittest_sidechain_reconstruction.py
similarity index 84%
rename from doc/tests/scripts/unittest_sidechain.py
rename to doc/tests/scripts/unittest_sidechain_reconstruction.py
index 65452ad6..083416eb 100644
--- a/doc/tests/scripts/unittest_sidechain.py
+++ b/doc/tests/scripts/unittest_sidechain_reconstruction.py
@@ -1,5 +1,5 @@
 import unittest
-from promod3 import sidechain
+from promod3 import modelling
 from ost import io,mol
 import os
 
@@ -9,7 +9,7 @@ class ReconstructTests(unittest.TestCase):
     	ref_file = os.path.join('data', '1eye_rec.pdb')
     	# get and reconstruct 1eye
     	prot = io.LoadPDB(in_file)
-    	sidechain.Reconstruct(prot, keep_sidechains=False)
+    	modelling.ReconstructSidechains(prot, keep_sidechains=False)
     	# compare with reference solution
     	prot_rec = io.LoadPDB(ref_file)
         self.assertEqual(prot.GetAtomCount(), prot_rec.GetAtomCount())
diff --git a/doc/tests/test_doctests.py b/doc/tests/test_doctests.py
index 3dce5f46..01a1b196 100644
--- a/doc/tests/test_doctests.py
+++ b/doc/tests/test_doctests.py
@@ -152,7 +152,7 @@ class DocTests(unittest.TestCase):
 
     def testUnittestSidechain(self):
         # run it
-        script_path = os.path.join('scripts', 'unittest_sidechain.py')
+        script_path = os.path.join('scripts', 'unittest_sidechain_reconstruction.py')
         rcode, sout, serr = self.runPM(script_path)
         # check return code and last line of output
         self.assertEqual(rcode, 0)
@@ -367,11 +367,9 @@ class DocTests(unittest.TestCase):
         # clean up
         os.remove('model.pdb')
 
-    ################################################################
-
-    def testSidechainReconstruct(self):
+    def testModellingReconstructSidechains(self):
         # run it
-        self.checkPMRun('sidechain_reconstruct.py', [], 0)
+        self.checkPMRun('modelling_reconstruct_sidechains.py', [], 0)
         # check that result exists and is readable
         io.LoadPDB('sidechain_test_orig.pdb')
         io.LoadPDB('sidechain_test_rec.pdb')
@@ -379,14 +377,16 @@ class DocTests(unittest.TestCase):
         os.remove('sidechain_test_orig.pdb')
         os.remove('sidechain_test_rec.pdb')
 
-    def testSidechainReconstructor(self):
+    def testModellingSidechainReconstructor(self):
         # run it
-        self.checkPMRun('sidechain_reconstructor.py', [], 0)
+        self.checkPMRun('modelling_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/extras/scoring_weight_training/generate_bft_chunks.py b/extras/scoring_weight_training/generate_bft_chunks.py
index f589f932..835e0368 100644
--- a/extras/scoring_weight_training/generate_bft_chunks.py
+++ b/extras/scoring_weight_training/generate_bft_chunks.py
@@ -26,7 +26,7 @@ USAGE: pm generate_bft_chunks.py MODE OPTIONS
 
 import math, json, os, sys, resource, time
 from ost import io, seq
-from promod3 import core, loop, modelling, scoring, sidechain
+from promod3 import core, loop, modelling, scoring, modelling
 
 ###############################################################################
 # SETUP
@@ -317,7 +317,7 @@ for fragment in fragments[frag_start:frag_end]:
   # get sidechain reconstructor
   aa_sc_env = loop.AllAtomEnv(seqres)
   aa_sc_env.SetInitialEnvironment(ent)
-  sc_rec = sidechain.SidechainReconstructor(graph_max_complexity=10000000)
+  sc_rec = modelling.SidechainReconstructor(graph_max_complexity=10000000)
   sc_rec.AttachEnvironment(aa_sc_env)
   # precompute sidechains for chain with reference loop in it?
   if reconstruct_full_chain_sc:
diff --git a/loop/doc/structure_db.rst b/loop/doc/structure_db.rst
index d0af15cb..c66f6078 100644
--- a/loop/doc/structure_db.rst
+++ b/loop/doc/structure_db.rst
@@ -513,8 +513,10 @@ In some cases you might want to use the :class:`StructureDB` to search
 for fragments that possibly represent the structural conformation of interest.
 The :class:`Fragger` searches a :class:`StructureDB` for n fragments, 
 that maximize a certain score and gathers a set of fragments with a guaranteed 
-structural diversity based on an rmsd_threshold. The score can be built using an 
-arbitrary linear combination of following components:
+structural diversity based on an rmsd_threshold. You can use the :class:`Fragger`
+wrapped in a full fletched pipeline implemented in 
+:class:`~promod3.modelling.FraggerHandle` or search for fragments from scratch 
+using an arbitrary linear combination of scores:
 
 * **SeqID**:
   Calculates the fraction of amino acids being identical when comparing
diff --git a/modelling/doc/CMakeLists.txt b/modelling/doc/CMakeLists.txt
index 3b237e21..33a9a878 100644
--- a/modelling/doc/CMakeLists.txt
+++ b/modelling/doc/CMakeLists.txt
@@ -6,6 +6,7 @@ set(MODELLING_RST
   loop_candidates.rst
   loop_closing.rst
   monte_carlo.rst
+  sidechain_reconstruction.rst
   algorithms.rst
 )
 
diff --git a/modelling/doc/index.rst b/modelling/doc/index.rst
index bd065743..27ed6101 100644
--- a/modelling/doc/index.rst
+++ b/modelling/doc/index.rst
@@ -27,5 +27,6 @@ The various steps involved in protein modelling are described here:
   loop_candidates
   loop_closing
   monte_carlo
+  sidechain_reconstruction
   algorithms
-  
\ No newline at end of file
+  
diff --git a/modelling/doc/loop_closing.rst b/modelling/doc/loop_closing.rst
index 1e2b9bc0..bd848429 100644
--- a/modelling/doc/loop_closing.rst
+++ b/modelling/doc/loop_closing.rst
@@ -309,8 +309,8 @@ Relaxing All Atom Loops
 --------------------------------------------------------------------------------
 
 After the reconstruction of loop sidechains with the
-:meth:`~promod3.sidechain.SidechainReconstructor.Reconstruct` method of
-:class:`~promod3.sidechain.SidechainReconstructor`, it may be desired to
+:meth:`~promod3.modelling.SidechainReconstructor.Reconstruct` method of
+:class:`~promod3.modelling.SidechainReconstructor`, it may be desired to
 quickly relax the loop. The :class:`AllAtomRelaxer` class takes care of that.
 
 .. class:: AllAtomRelaxer(sc_data, mm_system_creator)
@@ -321,7 +321,7 @@ quickly relax the loop. The :class:`AllAtomRelaxer` class takes care of that.
   N/C stems of loop are fixed if they are non-terminal.
 
   :param sc_data: Sidechain reconstruction result
-  :type sc_data:  :class:`~promod3.sidechain.SidechainReconstructionData`
+  :type sc_data:  :class:`~promod3.modelling.SidechainReconstructionData`
   :param mm_system_creator: System creator to be used here
   :type mm_system_creator:  :class:`~promod3.loop.MmSystemCreator`
 
@@ -331,7 +331,7 @@ quickly relax the loop. The :class:`AllAtomRelaxer` class takes care of that.
     *sc_data.env_pos.all_pos*.
 
     :param sc_data: Sidechain reconstruction result to be updated
-    :type sc_data:  :class:`~promod3.sidechain.SidechainReconstructionData`
+    :type sc_data:  :class:`~promod3.modelling.SidechainReconstructionData`
     :param steps: Number of steepest descent steps
     :type steps:  :class:`int`
     :param stop_criterion: If maximum force acting on a particle falls below
@@ -351,7 +351,7 @@ quickly relax the loop. The :class:`AllAtomRelaxer` class takes care of that.
     the same disulfid bridges as the one given in the constructor.
 
     :param sc_data: Get new positions from *sc_data.env_pos.all_pos*
-    :type sc_data:  :class:`~promod3.sidechain.SidechainReconstructionData`
+    :type sc_data:  :class:`~promod3.modelling.SidechainReconstructionData`
 
     :raises: :exc:`~exceptions.RuntimeError` if *sc_data* is incompatible with
              the one given in the constructor.
diff --git a/modelling/doc/pipeline.rst b/modelling/doc/pipeline.rst
index c7f9dea8..71c5ba32 100644
--- a/modelling/doc/pipeline.rst
+++ b/modelling/doc/pipeline.rst
@@ -124,7 +124,7 @@ Build Raw Modelling Handle
     scoring. A default one is set with :func:`SetupDefaultAllAtomScoring` when
     needed.
 
-    :type: :class:`~promod3.sidechain.SidechainReconstructor`
+    :type: :class:`~promod3.modelling.SidechainReconstructor`
 
   .. method:: Copy()
 
diff --git a/sidechain/doc/reconstruct.rst b/modelling/doc/sidechain_reconstruction.rst
similarity index 94%
rename from sidechain/doc/reconstruct.rst
rename to modelling/doc/sidechain_reconstruction.rst
index 69ba7155..e844b883 100644
--- a/sidechain/doc/reconstruct.rst
+++ b/modelling/doc/sidechain_reconstruction.rst
@@ -1,19 +1,27 @@
 Sidechain Reconstruction
 ================================================================================
 
-.. currentmodule:: promod3.sidechain
+.. currentmodule:: promod3.modelling
 
 Two methods are provided to fully reconstruct sidechains of residues:
 
-- the :func:`Reconstruct` function handles a full OST
+- the :func:`ReconstructSidechains` 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
 
+Example usage:
+
+.. literalinclude:: ../../../tests/doc/scripts/sidechain_reconstruct.py
+
+.. literalinclude:: ../../../tests/doc/scripts/sidechain_reconstructor.py
+
+
+
 Reconstruct Function
 --------------------------------------------------------------------------------
 
-.. autofunction:: Reconstruct
+.. autofunction:: ReconstructSidechains
 
 
 SidechainReconstructor Class
@@ -51,10 +59,10 @@ SidechainReconstructor Class
   :type cutoff:  :class:`float`
 
   :param graph_max_complexity: Max. complexity for
-                               :meth:`RotamerGraph.TreeSolve`.
+                               :meth:`promod3.sidechain.RotamerGraph.TreeSolve`.
   :type graph_max_complexity:  :class:`int`
   :param graph_intial_epsilon: Initial epsilon for
-                               :meth:`RotamerGraph.TreeSolve`.
+                               :meth:`promod3.sidechain.RotamerGraph.TreeSolve`.
   :type graph_intial_epsilon:  :class:`float`
 
   :param disulfid_score_thresh: If :meth:`DisulfidScore` between two CYS is
diff --git a/modelling/pymod/CMakeLists.txt b/modelling/pymod/CMakeLists.txt
index 09d856ed..16bed159 100644
--- a/modelling/pymod/CMakeLists.txt
+++ b/modelling/pymod/CMakeLists.txt
@@ -10,6 +10,7 @@ set(MODELLING_CPP
   export_score_container.cc
   export_scoring_weights.cc
   export_el_enumerador.cc
+  export_sidechain_reconstructor.cc
   wrap_modelling.cc
 )
 
@@ -21,6 +22,7 @@ set(MODELLING_PYMOD
   _ring_punches.py
   _denovo.py
   _fragger_handle.py
+  _reconstruct_sidechains.py
 )
 
 pymod(NAME modelling
diff --git a/modelling/pymod/__init__.py b/modelling/pymod/__init__.py
index e92e7ff5..cdd41d48 100644
--- a/modelling/pymod/__init__.py
+++ b/modelling/pymod/__init__.py
@@ -3,6 +3,7 @@ from _modelling import *
 from _closegaps import *
 from _molprobity import *
 from _pipeline import *
+from _reconstruct_sidechains import *
 from _ring_punches import *
 from _denovo import *
 from _fragger_handle import *
diff --git a/modelling/pymod/_closegaps.py b/modelling/pymod/_closegaps.py
index 40d2dc1e..96b5f819 100644
--- a/modelling/pymod/_closegaps.py
+++ b/modelling/pymod/_closegaps.py
@@ -4,9 +4,10 @@ as argument.
 '''
 
 # internal
-from promod3 import loop, sidechain, core, scoring
+from promod3 import loop, core, scoring
 from _modelling import *
 from _ring_punches import *
+from _reconstruct_sidechains import *
 # external
 import ost
 import sys
@@ -821,7 +822,7 @@ def FillLoopsByDatabase(mhandle, fragment_db, structure_db,
         else:
             # all good: fix sidechains if we're in ring-punch-mode and continue
             if ring_punch_detection == 2:
-                sidechain.Reconstruct(mhandle.model, keep_sidechains=True)
+                ReconstructSidechains(mhandle.model, keep_sidechains=True)
             gap_idx = new_idx
 
 
@@ -1051,7 +1052,7 @@ def FillLoopsByMonteCarlo(mhandle, torsion_sampler, max_loops_to_search=6,
         else:
             # all good: fix sidechains if we're in ring-punch-mode and continue
             if ring_punch_detection == 2:
-                sidechain.Reconstruct(mhandle.model, keep_sidechains=True)
+                ReconstructSidechains(mhandle.model, keep_sidechains=True)
             gap_idx = new_idx
 
 
diff --git a/modelling/pymod/_fragger_handle.py b/modelling/pymod/_fragger_handle.py
index 3f5bc038..95dee6db 100644
--- a/modelling/pymod/_fragger_handle.py
+++ b/modelling/pymod/_fragger_handle.py
@@ -111,7 +111,8 @@ def _SetupFragger_four(frag_sequence, frag_profile,
                        
 
 class FraggerHandle:
-    '''Handler for Fragger objects linked to a specific chain.
+    '''Handler for :class:`~promod3.loop.Fragger` objects linked to a 
+    specific chain.
 
     Tries to get the most accurate fragments given your input.
     You can only provide a SEQRES, the returned fragments are
diff --git a/modelling/pymod/_pipeline.py b/modelling/pymod/_pipeline.py
index 92e8dacd..6f149369 100644
--- a/modelling/pymod/_pipeline.py
+++ b/modelling/pymod/_pipeline.py
@@ -6,6 +6,7 @@ as argument.
 # internal
 from promod3 import loop, sidechain, core
 from _modelling import *
+from _reconstruct_sidechains import *
 from _closegaps import *
 from _ring_punches import *
 # external
@@ -166,10 +167,10 @@ def BuildSidechains(mhandle, merge_distance=4, fragment_db=None,
                     structure_db=None, torsion_sampler=None):
     '''Build sidechains for model.
 
-    This is a wrapper for :func:`promod3.sidechain.Reconstruct`, followed
-    by a check for ring punches. If ring punches are found it introduces gaps
-    for the residues with punched rings and tries to fill them with 
-    :func:`FillLoopsByDatabase` with *ring_punch_detection=2*.
+    This is a wrapper for :func:`promod3.modelling.ReconstructSidechains`, 
+    followed by a check for ring punches. If ring punches are found it 
+    introduces gaps for the residues with punched rings and tries to fill them 
+    with :func:`FillLoopsByDatabase` with *ring_punch_detection=2*.
 
     :param mhandle: Modelling handle on which to apply change.
     :type mhandle:  :class:`ModellingHandle`
@@ -192,7 +193,7 @@ def BuildSidechains(mhandle, merge_distance=4, fragment_db=None,
     '''
     prof = core.StaticRuntimeProfiler.StartScoped('pipeline::BuildSidechains')
     ost.LogInfo("Rebuilding sidechains.")
-    sidechain.Reconstruct(mhandle.model, keep_sidechains=True)
+    ReconstructSidechains(mhandle.model, keep_sidechains=True)
     # check for ring punches
     rings = GetRings(mhandle.model)
     ring_punches = GetRingPunches(rings, mhandle.model)
@@ -220,7 +221,7 @@ def BuildSidechains(mhandle, merge_distance=4, fragment_db=None,
         FillLoopsByDatabase(mhandle, fragment_db, structure_db,
                             torsion_sampler, ring_punch_detection=2)
         # re-build sidechains
-        sidechain.Reconstruct(mhandle.model, keep_sidechains=True)
+        ReconstructSidechains(mhandle.model, keep_sidechains=True)
         # restore gaps
         mhandle.gaps = StructuralGapList()
         for g in old_gaps:
diff --git a/sidechain/pymod/_reconstruct_sidechains.py b/modelling/pymod/_reconstruct_sidechains.py
similarity index 97%
rename from sidechain/pymod/_reconstruct_sidechains.py
rename to modelling/pymod/_reconstruct_sidechains.py
index b43b7027..aaf1a0eb 100644
--- a/sidechain/pymod/_reconstruct_sidechains.py
+++ b/modelling/pymod/_reconstruct_sidechains.py
@@ -1,6 +1,5 @@
-from . import _sidechain as sidechain
 from ost import geom, mol, conop
-from promod3 import core
+from promod3 import core, sidechain
 
 ###############################################################################
 # helper functions
@@ -352,10 +351,11 @@ def _GetDisulfidBridges(frame_residues, cystein_indices, res_list, rotamer_libra
 
 ###############################################################################
 
-def Reconstruct(ent, keep_sidechains=False, build_disulfids=True,
-                rotamer_model="frm", consider_ligands=True, 
-                rotamer_library=None, optimize_subrotamers=True,
-                graph_max_complexity=100000000, graph_initial_epsilon=0.02):
+def ReconstructSidechains(ent, keep_sidechains=False, build_disulfids=True,
+                          rotamer_model="frm", consider_ligands=True, 
+                          rotamer_library=None, optimize_subrotamers=True,
+                          graph_max_complexity=100000000, 
+                          graph_initial_epsilon=0.02):
     '''Reconstruct sidechains for the given structure.
 
     :param ent: Structure for sidechain reconstruction. Note, that the sidechain
@@ -400,7 +400,7 @@ def Reconstruct(ent, keep_sidechains=False, build_disulfids=True,
                                  :meth:`RotamerGraph.TreeSolve`.
     :type graph_intial_epsilon:  :class:`float`
     '''
-    prof_name = 'sidechain::Reconstruct'
+    prof_name = 'modelling::ReconstructSidechains'
     prof = core.StaticRuntimeProfiler.StartScoped(prof_name)
 
     # setup settings
@@ -503,4 +503,4 @@ def Reconstruct(ent, keep_sidechains=False, build_disulfids=True,
                   res_handle.GetQualifiedName()
 
 # these methods will be exported into module
-__all__ = ('Reconstruct',)
+__all__ = ('ReconstructSidechains',)
diff --git a/modelling/pymod/_ring_punches.py b/modelling/pymod/_ring_punches.py
index 1df95615..969aca39 100644
--- a/modelling/pymod/_ring_punches.py
+++ b/modelling/pymod/_ring_punches.py
@@ -1,7 +1,8 @@
 '''Helper functions to deal with ring punchings.'''
 import ost
 from ost import geom
-from promod3 import sidechain, core
+from promod3 import core
+from _reconstruct_sidechains import ReconstructSidechains
 from collections import namedtuple
 
 def _AddRing(rings, res, atom_names):
@@ -218,7 +219,7 @@ def FilterCandidatesWithSC(candidates, model, gap, orig_indices=[]):
         bb_list = candidates[lc_idx]
         bb_list.InsertInto(cur_model.chains[chain_idx], start_resnum)
         # add sidechains and check for clashes
-        sidechain.Reconstruct(cur_model, keep_sidechains=True)
+        ReconstructSidechains(cur_model, keep_sidechains=True)
         models_new = cur_model.Select(myqueryin)
         rings_new = GetRings(models_new)
         check_punches = HasRingPunches(rings_out, models_new) or\
diff --git a/modelling/pymod/export_loop_closure.cc b/modelling/pymod/export_loop_closure.cc
index 1f819340..a6aa1a0d 100644
--- a/modelling/pymod/export_loop_closure.cc
+++ b/modelling/pymod/export_loop_closure.cc
@@ -99,7 +99,7 @@ void export_loop_closure() {
   ;
 
   class_<AllAtomRelaxer, AllAtomRelaxerPtr>("AllAtomRelaxer", no_init)
-    .def(init<sidechain::SidechainReconstructionDataPtr,
+    .def(init<modelling::SidechainReconstructionDataPtr,
               loop::MmSystemCreatorPtr>(
          (arg("sc_data"), arg("mm_system_creator"))))
     .def("UpdatePositions", &AllAtomRelaxer::UpdatePositions, (arg("sc_data")))
diff --git a/modelling/pymod/export_model.cc b/modelling/pymod/export_model.cc
index c1b705e6..db325e3d 100644
--- a/modelling/pymod/export_model.cc
+++ b/modelling/pymod/export_model.cc
@@ -93,7 +93,7 @@ void WrapSetAllAtomSidechainEnv(ModellingHandle& mhandle,
   mhandle.all_atom_sidechain_env = env;
 }
 
-promod3::sidechain::SidechainReconstructorPtr
+promod3::modelling::SidechainReconstructorPtr
 WrapGetSidechainRec(ModellingHandle& mhandle) {
   if (!mhandle.sidechain_reconstructor) {
     throw promod3::Error("The sidechain_reconstructor must be properly "
@@ -103,7 +103,7 @@ WrapGetSidechainRec(ModellingHandle& mhandle) {
 }
 
 void WrapSetSidechainRec(ModellingHandle& mhandle,
-                         promod3::sidechain::SidechainReconstructorPtr sc_rec) {
+                         promod3::modelling::SidechainReconstructorPtr sc_rec) {
   mhandle.sidechain_reconstructor = sc_rec;
 }
 
diff --git a/sidechain/pymod/export_sidechain_reconstructor.cc b/modelling/pymod/export_sidechain_reconstructor.cc
similarity index 94%
rename from sidechain/pymod/export_sidechain_reconstructor.cc
rename to modelling/pymod/export_sidechain_reconstructor.cc
index b550dd26..e55efdfa 100644
--- a/sidechain/pymod/export_sidechain_reconstructor.cc
+++ b/modelling/pymod/export_sidechain_reconstructor.cc
@@ -1,9 +1,9 @@
 #include <boost/python.hpp>
 #include <promod3/core/export_helper.hh>
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 
 using namespace promod3;
-using namespace promod3::sidechain;
+using namespace promod3::modelling;
 using namespace boost::python;
 
 namespace {
@@ -105,9 +105,9 @@ void export_SidechainReconstructor() {
          (arg("start_resnum_list"), arg("num_residues_list"), arg("chain_idx_list")))
     .def("AttachEnvironment", WrapAttachEnvironment<bool>,
          (arg("env"), arg("use_frm")=true, arg("use_bbdep_lib")=true))
-    .def("AttachEnvironment", WrapAttachEnvironment<BBDepRotamerLibPtr>,
+    .def("AttachEnvironment", WrapAttachEnvironment<sidechain::BBDepRotamerLibPtr>,
          (arg("env"), arg("use_frm"), arg("rotamer_library")))
-    .def("AttachEnvironment", WrapAttachEnvironment<RotamerLibPtr>,
+    .def("AttachEnvironment", WrapAttachEnvironment<sidechain::RotamerLibPtr>,
          (arg("env"), arg("use_frm"), arg("rotamer_library")))
   ;
 }
diff --git a/modelling/pymod/wrap_modelling.cc b/modelling/pymod/wrap_modelling.cc
index 189db190..69f69a6b 100644
--- a/modelling/pymod/wrap_modelling.cc
+++ b/modelling/pymod/wrap_modelling.cc
@@ -10,6 +10,7 @@ void export_monte_carlo();
 void export_rigid_blocks();
 void export_score_container();
 void export_scoring_weights();
+void export_SidechainReconstructor();
 void export_el_enumerador();
 
 BOOST_PYTHON_MODULE(_modelling)
@@ -24,5 +25,6 @@ BOOST_PYTHON_MODULE(_modelling)
   export_rigid_blocks();
   export_score_container();
   export_scoring_weights();
+  export_SidechainReconstructor();
   export_el_enumerador();
 }
diff --git a/modelling/src/CMakeLists.txt b/modelling/src/CMakeLists.txt
index 21619bf0..6dd633e2 100644
--- a/modelling/src/CMakeLists.txt
+++ b/modelling/src/CMakeLists.txt
@@ -16,6 +16,8 @@ set(MODELLING_SOURCES
   rigid_blocks.cc
   score_container.cc
   scoring_weights.cc
+  sidechain_reconstructor.cc
+  sidechain_env_listener.cc
   el_enumerador.cc
 )
 
@@ -37,6 +39,8 @@ set(MODELLING_HEADERS
   rigid_blocks.hh
   score_container.hh
   scoring_weights.hh
+  sidechain_reconstructor.hh
+  sidechain_env_listener.hh
   el_enumerador.hh
 )
 
diff --git a/modelling/src/all_atom_relaxer.hh b/modelling/src/all_atom_relaxer.hh
index dc7965c8..9235a13f 100644
--- a/modelling/src/all_atom_relaxer.hh
+++ b/modelling/src/all_atom_relaxer.hh
@@ -2,7 +2,7 @@
 #define PROMOD3_MODELLING_ALL_ATOM_RELAXER_HH
 
 #include <promod3/loop/mm_system_creator.hh>
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 
 namespace promod3 { namespace modelling {
 
@@ -12,8 +12,8 @@ typedef boost::shared_ptr<AllAtomRelaxer> AllAtomRelaxerPtr;
 /// \brief Relax loops returned by SidechainReconstructor
 class AllAtomRelaxer {
   // for convenience
-  typedef sidechain::SidechainReconstructionData ScRecData;
-  typedef sidechain::SidechainReconstructionDataPtr ScRecDataPtr;
+  typedef SidechainReconstructionData ScRecData;
+  typedef SidechainReconstructionDataPtr ScRecDataPtr;
 public:
   // create relaxer for this data set (will be ready for Run)
   AllAtomRelaxer(ScRecDataPtr sc_data, loop::MmSystemCreatorPtr mm_sys_creator);
diff --git a/modelling/src/el_enumerador.cc b/modelling/src/el_enumerador.cc
index 35c13546..980cb011 100644
--- a/modelling/src/el_enumerador.cc
+++ b/modelling/src/el_enumerador.cc
@@ -1,6 +1,6 @@
 #include <promod3/modelling/el_enumerador.hh>
 #include <promod3/scoring/scoring_object_loader.hh>
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 #include <promod3/core/enumerator.hh>
 #include <promod3/core/graph.hh>
 #include <promod3/core/tree.hh>
@@ -135,8 +135,9 @@ ScorerContainer(const promod3::modelling::ModellingHandle& mhandle, bool all_ato
     aa_sc_env_ = promod3::loop::AllAtomEnvPtr(
       new promod3::loop::AllAtomEnv(mhandle.seqres));
     aa_sc_env_->SetInitialEnvironment(mhandle.model);
-    aa_sc_rec_ = promod3::sidechain::SidechainReconstructorPtr(
-      new promod3::sidechain::SidechainReconstructor(true, true, true, 18.0));
+    aa_sc_rec_ = promod3::modelling::SidechainReconstructorPtr(
+      new promod3::modelling::SidechainReconstructor(true, true, 
+                                                     true, 18.0));
     aa_sc_rec_->AttachEnvironment(*aa_sc_env_, false);
     aa_scorer_env_ = promod3::loop::AllAtomEnvPtr(
       new promod3::loop::AllAtomEnv(mhandle.seqres));
@@ -174,7 +175,7 @@ Real GetScore(const promod3::loop::BackboneList& bb_list,
                                                   start_resnum,
                                                   chain_idx);
   if(all_atom_){
-    promod3::sidechain::SidechainReconstructionDataPtr sc_rec_data = 
+    promod3::modelling::SidechainReconstructionDataPtr sc_rec_data = 
     aa_sc_rec_->Reconstruct(start_resnum, bb_list.size(), chain_idx);
     aa_scorer_env_->SetEnvironment(*(sc_rec_data->env_pos));
     score += aa_scorer_->CalculateLinearCombination(aa_weights_,
@@ -208,7 +209,7 @@ Real GetScore(const std::vector<promod3::loop::BackboneList*>& bb_list_ptrs,
       bb_list_sizes[i] = bb_list_ptrs[i]->size();
     }
 
-    promod3::sidechain::SidechainReconstructionDataPtr sc_rec_data = 
+    promod3::modelling::SidechainReconstructionDataPtr sc_rec_data = 
     aa_sc_rec_->Reconstruct(start_resnums, bb_list_sizes, chain_indices);
     aa_scorer_env_->SetEnvironment(*(sc_rec_data->env_pos));
 
@@ -252,7 +253,7 @@ promod3::scoring::BackboneScoreEnvPtr bb_env_;
 promod3::scoring::BackboneOverallScorerPtr bb_scorer_;
 
 promod3::loop::AllAtomEnvPtr aa_sc_env_;
-promod3::sidechain::SidechainReconstructorPtr aa_sc_rec_;
+promod3::modelling::SidechainReconstructorPtr aa_sc_rec_;
 
 promod3::loop::AllAtomEnvPtr aa_scorer_env_;
 promod3::scoring::AllAtomOverallScorerPtr aa_scorer_;
diff --git a/modelling/src/loop_candidate.cc b/modelling/src/loop_candidate.cc
index b3e72833..49885a31 100644
--- a/modelling/src/loop_candidate.cc
+++ b/modelling/src/loop_candidate.cc
@@ -484,8 +484,8 @@ void LoopCandidates::CalculateAllAtomScores(
   loop::AllAtomEnvPtr aa_score_env = mhandle.all_atom_scorer_env;
   scoring::AllAtomOverallScorerPtr aa_scorer = mhandle.all_atom_scorer;
   loop::AllAtomEnvPtr aa_sc_env = mhandle.all_atom_sidechain_env;
-  sidechain::SidechainReconstructorPtr sc_rec = mhandle.sidechain_reconstructor;
-  sidechain::SidechainReconstructionDataPtr sc_result;
+  SidechainReconstructorPtr sc_rec = mhandle.sidechain_reconstructor;
+  SidechainReconstructionDataPtr sc_result;
 
   // prepare storage for all scores
   std::vector< std::vector<Real> > aa_scores(keys.size());
diff --git a/modelling/src/model.cc b/modelling/src/model.cc
index d4c79287..491a2d9a 100644
--- a/modelling/src/model.cc
+++ b/modelling/src/model.cc
@@ -306,8 +306,8 @@ void SetupDefaultAllAtomScoring(ModellingHandle& mhandle){
   // setup sidechaining needed for scoring
   loop::AllAtomEnvPtr env_sc(new loop::AllAtomEnv(mhandle.seqres));
   env_sc->SetInitialEnvironment(mhandle.model);
-  sidechain::SidechainReconstructorPtr sc_rec;
-  sc_rec.reset(new sidechain::SidechainReconstructor);
+  SidechainReconstructorPtr sc_rec;
+  sc_rec.reset(new SidechainReconstructor);
   sc_rec->AttachEnvironment(*env_sc);
 
   // set mhandle values
diff --git a/modelling/src/model.hh b/modelling/src/model.hh
index 58e81493..e42a2c8d 100644
--- a/modelling/src/model.hh
+++ b/modelling/src/model.hh
@@ -12,7 +12,7 @@
 #include <promod3/scoring/all_atom_overall_scorer.hh>
 #include <promod3/scoring/backbone_overall_scorer.hh>
 #include <promod3/scoring/backbone_score_base.hh>
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 
 namespace promod3 { namespace modelling {
 
@@ -45,7 +45,7 @@ struct ModellingHandle {
   promod3::loop::AllAtomEnvPtr all_atom_scorer_env; // tmp only for scoring
   promod3::scoring::AllAtomOverallScorerPtr all_atom_scorer;
   promod3::loop::AllAtomEnvPtr all_atom_sidechain_env;
-  promod3::sidechain::SidechainReconstructorPtr sidechain_reconstructor;
+  SidechainReconstructorPtr sidechain_reconstructor;
 };
 
 // see Python doc
diff --git a/sidechain/src/sidechain_env_listener.cc b/modelling/src/sidechain_env_listener.cc
similarity index 83%
rename from sidechain/src/sidechain_env_listener.cc
rename to modelling/src/sidechain_env_listener.cc
index 89519e04..18a1297e 100644
--- a/sidechain/src/sidechain_env_listener.cc
+++ b/modelling/src/sidechain_env_listener.cc
@@ -1,8 +1,8 @@
-#include <promod3/sidechain/sidechain_env_listener.hh>
+#include <promod3/modelling/sidechain_env_listener.hh>
 #include <promod3/sidechain/sidechain_object_loader.hh>
 #include <promod3/core/runtime_profiling.hh>
 
-namespace promod3 { namespace sidechain {
+namespace promod3 { namespace modelling {
 
 SidechainEnvListener::SidechainEnvListener(bool use_frm, bool use_bbdep_lib,
                                            bool add_cyd_rotamers,
@@ -17,13 +17,13 @@ SidechainEnvListener::SidechainEnvListener(bool use_frm, bool use_bbdep_lib,
     throw promod3::Error("Cannot use PenultimateLib with FRMRotamers!");
   }
   // setup library
-  if (use_bbdep_lib_) bbdep_library_ = LoadDunbrackLib();
-  else library_ = LoadPenultimateLib();
+  if (use_bbdep_lib_) bbdep_library_ = sidechain::LoadDunbrackLib();
+  else library_ = sidechain::LoadPenultimateLib();
 
 }
 
 SidechainEnvListener::SidechainEnvListener(bool use_frm,
-                                           BBDepRotamerLibPtr bbdep_library,
+                                           sidechain::BBDepRotamerLibPtr bbdep_library,
                                            bool add_cyd_rotamers,
                                            bool all_rotamers)
                                            : all_rotamers_(all_rotamers)
@@ -33,7 +33,8 @@ SidechainEnvListener::SidechainEnvListener(bool use_frm,
                                            , bbdep_library_(bbdep_library)
                                            , env_(20.0), env_data_(NULL) { }
 
-SidechainEnvListener::SidechainEnvListener(bool use_frm, RotamerLibPtr library,
+SidechainEnvListener::SidechainEnvListener(bool use_frm, 
+                                           sidechain::RotamerLibPtr library,
                                            bool add_cyd_rotamers,
                                            bool all_rotamers)
                                            : all_rotamers_(all_rotamers)
@@ -80,20 +81,23 @@ void SidechainEnvListener::Init(const loop::AllAtomEnv& base_env) {
   }
 
   // set rotamer IDs (fixed based on AA in all_pos)
-  r_id_.assign(num_residues, ALA);
+  r_id_.assign(num_residues, sidechain::ALA);
   for (uint res_idx = 0; res_idx < num_residues; ++res_idx) {
-    r_id_[res_idx] = AAToRotID(all_pos->GetAA(res_idx));
+    r_id_[res_idx] = sidechain::AAToRotID(all_pos->GetAA(res_idx));
   }
 
   // initialize rotamer data (all false / NULL for now)
   phi_angle_.assign(num_residues, 0);
   psi_angle_.assign(num_residues, 0);
-  bb_frame_residue_.assign(num_residues, FrameResiduePtr());
-  sc_frame_residue_.assign(num_residues, FrameResiduePtr());
-  if (use_frm_) frm_rotamer_group_.assign(num_residues, FRMRotamerGroupPtr());
-  else          rrm_rotamer_group_.assign(num_residues, RRMRotamerGroupPtr());
+  bb_frame_residue_.assign(num_residues, sidechain::FrameResiduePtr());
+  sc_frame_residue_.assign(num_residues, sidechain::FrameResiduePtr());
+  if (use_frm_) {
+    frm_rotamer_group_.assign(num_residues, sidechain::FRMRotamerGroupPtr());
+  } else {         
+    rrm_rotamer_group_.assign(num_residues, sidechain::RRMRotamerGroupPtr());
+  }
   if (add_cyd_rotamers_) {
-    cyd_frm_rotamer_group_.assign(num_residues, FRMRotamerGroupPtr());
+    cyd_frm_rotamer_group_.assign(num_residues, sidechain::FRMRotamerGroupPtr());
   }
 }
 
@@ -132,7 +136,7 @@ void SidechainEnvListener::UpdateEnvironment(
 
 void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
                                        const uint res_idx) {
-  const RotamerID r_id = r_id_[res_idx];
+  const sidechain::RotamerID r_id = r_id_[res_idx];
   // get atom indices for backbone
   const uint idx_N  = all_pos->GetIndex(res_idx, loop::BB_N_INDEX);
   const uint idx_CA = all_pos->GetIndex(res_idx, loop::BB_CA_INDEX);
@@ -141,7 +145,7 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
   const uint idx_CB = all_pos->GetIndex(res_idx, loop::BB_CB_INDEX);
   const bool bb_set =   all_pos->IsSet(idx_N) && all_pos->IsSet(idx_CA)
                      && all_pos->IsSet(idx_C) && all_pos->IsSet(idx_O)
-                     && (r_id == GLY || all_pos->IsSet(idx_CB));
+                     && (r_id == sidechain::GLY || all_pos->IsSet(idx_CB));
   const bool all_set = all_pos->IsAllSet(res_idx);
   // we only add data if BB is set
   if (bb_set) {
@@ -151,17 +155,17 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
     const geom::Vec3& c_pos  = all_pos->GetPos(idx_C);
     const geom::Vec3& o_pos  = all_pos->GetPos(idx_O);
     geom::Vec3 cb_pos;
-    if (r_id != GLY)  cb_pos = all_pos->GetPos(idx_CB);
+    if (r_id != sidechain::GLY)  cb_pos = all_pos->GetPos(idx_CB);
     
     // update spatial organizer
     if (bb_frame_residue_[res_idx]) {
       // update
       const geom::Vec3 old_pos = env_data_[res_idx].pos;
-      env_data_[res_idx].pos = (r_id == GLY) ? ca_pos : cb_pos;
+      env_data_[res_idx].pos = (r_id == sidechain::GLY) ? ca_pos : cb_pos;
       env_.Reset(&env_data_[res_idx], old_pos, env_data_[res_idx].pos);
     } else {
       // set
-      env_data_[res_idx].pos = (r_id == GLY) ? ca_pos : cb_pos;
+      env_data_[res_idx].pos = (r_id == sidechain::GLY) ? ca_pos : cb_pos;
       env_.Add(&env_data_[res_idx], env_data_[res_idx].pos);
     }
 
@@ -181,7 +185,7 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
                                                        c_ter_[res_idx]);
     
     // do we have a sidechain?
-    if (r_id != ALA && r_id != GLY) {
+    if (r_id != sidechain::ALA && r_id != sidechain::GLY) {
       // set sidechain frame res. if all set
       if (all_set) {
         sc_frame_residue_[res_idx]
@@ -198,9 +202,9 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
         else          rrm_rotamer_group_[res_idx].reset();
       }
       // set extra cystein rotamer if needed
-      if (add_cyd_rotamers_ && r_id == CYS) {
+      if (add_cyd_rotamers_ && r_id == sidechain::CYS) {
         CreateRotamerGroup(cyd_frm_rotamer_group_[res_idx], n_pos, ca_pos,
-                           cb_pos, CYD, res_idx);
+                           cb_pos, sidechain::CYD, res_idx);
       }
     }
   } else {
@@ -223,17 +227,17 @@ void SidechainEnvListener::SetRotamer_(loop::ConstAllAtomPositionsPtr all_pos,
                                        const geom::Vec3& n_pos,
                                        const geom::Vec3& ca_pos,
                                        const geom::Vec3& cb_pos,
-                                       const RotamerID r_id,
+                                       const sidechain::RotamerID r_id,
                                        const uint res_idx) {
   // add rotamer anyways -> potentially need to change ID
-  RotamerID rg_r_id = r_id;
-  if (r_id == CYS) rg_r_id = CYH;
-  if (r_id == PRO) {
+  sidechain::RotamerID rg_r_id = r_id;
+  if (r_id == sidechain::CYS) rg_r_id = sidechain::CYH;
+  if (r_id == sidechain::PRO) {
     // check omega torsion
     Real omega = 4;
     if (!n_ter_[res_idx]) omega = all_pos->GetOmegaTorsion(res_idx, 4);
     if (omega != 4) {
-      rg_r_id = (std::abs(omega) < 1.57) ? CPR : TPR;
+      rg_r_id = (std::abs(omega) < 1.57) ? sidechain::CPR : sidechain::TPR;
     }
   }
   // note: most time spent here to construct new and destruct old
diff --git a/sidechain/src/sidechain_env_listener.hh b/modelling/src/sidechain_env_listener.hh
similarity index 74%
rename from sidechain/src/sidechain_env_listener.hh
rename to modelling/src/sidechain_env_listener.hh
index ad0b411f..a35a0b36 100644
--- a/sidechain/src/sidechain_env_listener.hh
+++ b/modelling/src/sidechain_env_listener.hh
@@ -10,7 +10,7 @@
 #include <promod3/sidechain/bb_dep_rotamer_lib.hh>
 #include <promod3/sidechain/scwrl_rotamer_constructor.hh>
 
-namespace promod3 { namespace sidechain {
+namespace promod3 { namespace modelling {
 
 class SidechainEnvListener;
 typedef boost::shared_ptr<SidechainEnvListener> SidechainEnvListenerPtr;
@@ -31,9 +31,9 @@ public:
   // construct: global options can only be set here!
   SidechainEnvListener(bool use_frm = true, bool use_bbdep_lib = true,
                        bool add_cyd_rotamers = true, bool all_rotamers = false);
-  SidechainEnvListener(bool use_frm, BBDepRotamerLibPtr bbdep_library,
+  SidechainEnvListener(bool use_frm, sidechain::BBDepRotamerLibPtr bbdep_library,
                        bool add_cyd_rotamers = true, bool all_rotamers = false);
-  SidechainEnvListener(bool use_frm, RotamerLibPtr library,
+  SidechainEnvListener(bool use_frm, sidechain::RotamerLibPtr library,
                        bool add_cyd_rotamers = true, bool all_rotamers = false);
 
   // AllAtomEnvListener interface
@@ -61,62 +61,67 @@ public:
   uint GetNumResidues() const { return phi_angle_.size(); }
   bool IsNTerminal(uint res_idx) const { return n_ter_[res_idx]; }
   bool IsCTerminal(uint res_idx) const { return c_ter_[res_idx]; }
-  RotamerID GetRotamerID(uint res_idx) const { return r_id_[res_idx]; }
+  sidechain::RotamerID GetRotamerID(uint res_idx) const { return r_id_[res_idx]; }
   Real GetPhiAngle(uint res_idx) const { return phi_angle_[res_idx]; }
   Real GetPsiAngle(uint res_idx) const { return psi_angle_[res_idx]; }
-  FrameResiduePtr GetBbFrameResidue(uint res_idx) const {
+  sidechain::FrameResiduePtr GetBbFrameResidue(uint res_idx) const {
     return bb_frame_residue_[res_idx];
   }
-  FrameResiduePtr GetScFrameResidue(uint res_idx) const {
+  sidechain::FrameResiduePtr GetScFrameResidue(uint res_idx) const {
     return sc_frame_residue_[res_idx];
   }
-  FRMRotamerGroupPtr GetFRMRotamerGroup(uint res_idx) const {
+  sidechain::FRMRotamerGroupPtr GetFRMRotamerGroup(uint res_idx) const {
     if (!use_frm_) {
       throw promod3::Error("SidechainEnvListener doesn't have FRMRotamers!");
     }
     return frm_rotamer_group_[res_idx];
   }
-  RRMRotamerGroupPtr GetRRMRotamerGroup(uint res_idx) const {
+  sidechain::RRMRotamerGroupPtr GetRRMRotamerGroup(uint res_idx) const {
     if (use_frm_) {
       throw promod3::Error("SidechainEnvListener doesn't have RRMRotamers!");
     }
     return rrm_rotamer_group_[res_idx];
   }
-  FRMRotamerGroupPtr GetCydFRMRotamerGroup(uint res_idx) const {
+  sidechain::FRMRotamerGroupPtr GetCydFRMRotamerGroup(uint res_idx) const {
     return cyd_frm_rotamer_group_[res_idx];
   }
-  RRMRotamerGroupPtr GetCydRRMRotamerGroup(uint res_idx) const {
+  sidechain::RRMRotamerGroupPtr GetCydRRMRotamerGroup(uint res_idx) const {
     // typically all disulfid evaluations are done with FRM disulfids
     // (even when use_frm is false), so this is just a nasty fallback
     uint num_rotamers = cyd_frm_rotamer_group_[res_idx]->size();
-    std::vector<RRMRotamerPtr> rrm_rotamers(num_rotamers);
+    std::vector<sidechain::RRMRotamerPtr> rrm_rotamers(num_rotamers);
     for(uint i = 0; i < num_rotamers; ++i){
       rrm_rotamers[i] = (*cyd_frm_rotamer_group_[res_idx])[i]->ToRRMRotamer(); 
     }
-    RRMRotamerGroupPtr p(new RRMRotamerGroup(rrm_rotamers, res_idx));
+    sidechain::RRMRotamerGroupPtr 
+    p(new sidechain::RRMRotamerGroup(rrm_rotamers, res_idx));
     
     return p;
   }
   
   // for convenience: use overload to set rot_group based on type
-  void GetRotamerGroup(FRMRotamerGroupPtr& rot_group, uint res_idx) const {
+  void GetRotamerGroup(sidechain::FRMRotamerGroupPtr& rot_group, 
+                       uint res_idx) const {
     rot_group = GetFRMRotamerGroup(res_idx);
   }
-  void GetRotamerGroup(RRMRotamerGroupPtr& rot_group, uint res_idx) const {
+  void GetRotamerGroup(sidechain::RRMRotamerGroupPtr& rot_group, 
+                       uint res_idx) const {
     rot_group = GetRRMRotamerGroup(res_idx);
   }
-  void GetCydRotamerGroup(FRMRotamerGroupPtr& rot_group, uint res_idx) const {
+  void GetCydRotamerGroup(sidechain::FRMRotamerGroupPtr& rot_group, 
+                          uint res_idx) const {
     rot_group = GetCydFRMRotamerGroup(res_idx);
   }
-  void GetCydRotamerGroup(RRMRotamerGroupPtr& rot_group, uint res_idx) const {
+  void GetCydRotamerGroup(sidechain::RRMRotamerGroupPtr& rot_group, 
+                          uint res_idx) const {
     rot_group = GetCydRRMRotamerGroup(res_idx);
   }
 
   // create a rotamer group based on internal settings (no use_frm_ check!)
-  void CreateRotamerGroup(FRMRotamerGroupPtr& rot_group,
+  void CreateRotamerGroup(sidechain::FRMRotamerGroupPtr& rot_group,
                           const geom::Vec3& n_pos, const geom::Vec3& ca_pos,
-                          const geom::Vec3& cb_pos, const RotamerID r_id,
-                          const uint res_idx) {
+                          const geom::Vec3& cb_pos, 
+                          const sidechain::RotamerID r_id, const uint res_idx) {
     if (use_bbdep_lib_) {
       rot_group = rot_constructor_.ConstructFRMRotamerGroup(n_pos, ca_pos, 
                                                             cb_pos, r_id, 
@@ -131,9 +136,11 @@ public:
     }
     rot_constructor_.AssignInternalEnergies(rot_group);
   }
-  void CreateRotamerGroup(RRMRotamerGroupPtr& rot_group,
-                          const geom::Vec3& n_pos, const geom::Vec3& ca_pos,
-                          const geom::Vec3& cb_pos, const RotamerID r_id,
+  void CreateRotamerGroup(sidechain::RRMRotamerGroupPtr& rot_group,
+                          const geom::Vec3& n_pos, 
+                          const geom::Vec3& ca_pos,
+                          const geom::Vec3& cb_pos, 
+                          const sidechain::RotamerID r_id,
                           const uint res_idx) {
     if (use_bbdep_lib_) {
       rot_group = rot_constructor_.ConstructRRMRotamerGroup(n_pos, ca_pos, 
@@ -157,7 +164,7 @@ private:
   void SetResidue_(loop::ConstAllAtomPositionsPtr all_pos, const uint res_idx);
   void SetRotamer_(loop::ConstAllAtomPositionsPtr all_pos,
                    const geom::Vec3& n_pos, const geom::Vec3& ca_pos,
-                   const geom::Vec3& cb_pos, const RotamerID r_id,
+                   const geom::Vec3& cb_pos, const sidechain::RotamerID r_id,
                    const uint res_idx);
 
   // global data
@@ -166,15 +173,15 @@ private:
   bool use_frm_;       // use FRMRotamerGroup instead of RRMRotamerGroup
   bool use_bbdep_lib_; // use BBDepRotamerLib instead of RotamerLib
   bool add_cyd_rotamers_;  // build extra rotamers with r_id = CYD for cysteins
-  RotamerLibPtr library_;
-  BBDepRotamerLibPtr bbdep_library_;
-  SCWRLRotamerConstructor rot_constructor_;
+  sidechain::RotamerLibPtr library_;
+  sidechain::BBDepRotamerLibPtr bbdep_library_;
+  sidechain::SCWRLRotamerConstructor rot_constructor_;
   ScCBetaSpatialOrganizer env_;
 
   // fixed data per residue (same numbering as base_env.GetAllPosData())
   std::vector<bool> n_ter_;
   std::vector<bool> c_ter_;
-  std::vector<RotamerID> r_id_;
+  std::vector<sidechain::RotamerID> r_id_;
   
   // dynamic data per residue
   // -> any data only set if BB set ("if (bb_frame_residue_[res_idx]) ...")
@@ -185,14 +192,14 @@ private:
   ScCBetaSpatialOrganizerItem* env_data_;
   std::vector<Real> phi_angle_;
   std::vector<Real> psi_angle_;
-  std::vector<FrameResiduePtr> bb_frame_residue_;
-  std::vector<FrameResiduePtr> sc_frame_residue_;
-  std::vector<FRMRotamerGroupPtr> frm_rotamer_group_;
-  std::vector<RRMRotamerGroupPtr> rrm_rotamer_group_;
+  std::vector<sidechain::FrameResiduePtr> bb_frame_residue_;
+  std::vector<sidechain::FrameResiduePtr> sc_frame_residue_;
+  std::vector<sidechain::FRMRotamerGroupPtr> frm_rotamer_group_;
+  std::vector<sidechain::RRMRotamerGroupPtr> rrm_rotamer_group_;
 
   // extra rotamer groups (r_id == CYD) for cysteins to handle disulfid bridges
   // -> constructed for res. with r_id == CYS indep. of all_rotamers_ setting!
-  std::vector<FRMRotamerGroupPtr> cyd_frm_rotamer_group_;
+  std::vector<sidechain::FRMRotamerGroupPtr> cyd_frm_rotamer_group_;
 };
 
 }} // ns
diff --git a/sidechain/src/sidechain_reconstructor.cc b/modelling/src/sidechain_reconstructor.cc
similarity index 89%
rename from sidechain/src/sidechain_reconstructor.cc
rename to modelling/src/sidechain_reconstructor.cc
index 0fa9cfb9..8ab263f3 100644
--- a/sidechain/src/sidechain_reconstructor.cc
+++ b/modelling/src/sidechain_reconstructor.cc
@@ -1,11 +1,11 @@
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 #include <promod3/sidechain/disulfid.hh>
 #include <promod3/sidechain/rotamer_graph.hh>
 #include <promod3/sidechain/subrotamer_optimizer.hh>
 #include <promod3/core/message.hh>
 #include <promod3/core/runtime_profiling.hh>
 
-namespace promod3 { namespace sidechain {
+namespace promod3 { namespace modelling {
 
 namespace {
 
@@ -101,7 +101,8 @@ void SidechainReconstructor::AttachEnvironment(loop::AllAtomEnv& env,
 }
 void SidechainReconstructor::AttachEnvironment(loop::AllAtomEnv& env,
                                                bool use_frm,
-                                               BBDepRotamerLibPtr bbdep_library) {
+                                               sidechain::BBDepRotamerLibPtr 
+                                               bbdep_library) {
   loop::AllAtomEnvListenerPtr tst = env.GetListener("SidechainEnvListener");
   if (tst) {
     env_ = boost::dynamic_pointer_cast<SidechainEnvListener>(tst);
@@ -116,7 +117,8 @@ void SidechainReconstructor::AttachEnvironment(loop::AllAtomEnv& env,
 }
 void SidechainReconstructor::AttachEnvironment(loop::AllAtomEnv& env,
                                                bool use_frm,
-                                               RotamerLibPtr library) {
+                                               sidechain::RotamerLibPtr 
+                                               library) {
   loop::AllAtomEnvListenerPtr tst = env.GetListener("SidechainEnvListener");
   if (tst) {
     env_ = boost::dynamic_pointer_cast<SidechainEnvListener>(tst);
@@ -173,8 +175,8 @@ SidechainReconstructor::ReconstructFromIndices(const std::vector<uint>& indices)
   }
 
   // solve system
-  if (env_->HasFRMRotamers()) SolveSystem_<FRMRotamerGroup>(res);
-  else                        SolveSystem_<RRMRotamerGroup>(res);
+  if (env_->HasFRMRotamers()) SolveSystem_<sidechain::FRMRotamerGroup>(res);
+  else                        SolveSystem_<sidechain::RRMRotamerGroup>(res);
   return res;
 }
 
@@ -204,7 +206,7 @@ void SidechainReconstructor::SetEnvData_(loop::AllAtomEnv& env) {
 template<typename RotamerGroup> void SidechainReconstructor::BuildDisulfids_(
                        SidechainReconstructionDataPtr res,
                        std::vector<uint>& cys_indices,
-                       std::vector<FrameResiduePtr>& frame_residues,
+                       std::vector<sidechain::FrameResiduePtr>& frame_residues,
                        std::vector<bool>& has_sidechain) const {
   // setup
   std::vector<uint>& res_indices = res->env_pos->res_indices;
@@ -213,7 +215,7 @@ template<typename RotamerGroup> void SidechainReconstructor::BuildDisulfids_(
   loop::AllAtomPositions& out_pos = *(res->env_pos->all_pos);
 
   // collect rotamers and data required to resolve the disulfid bridges
-  FramePtr frame(new Frame(frame_residues));
+  sidechain::FramePtr frame(new sidechain::Frame(frame_residues));
   std::vector<RotamerGroupPtr> cys_rotamer_groups;
   std::vector<geom::Vec3> ca_pos;
   std::vector<geom::Vec3> cb_pos;
@@ -285,7 +287,8 @@ template<typename RotamerGroup> void SidechainReconstructor::BuildDisulfids_(
       if(is_bonded[i] == 0){
         const uint idx = cys_with_rot_groups[i];
         const uint global_idx = res_indices[idx];
-        FrameResiduePtr frame_res = env_->GetScFrameResidue(global_idx);
+        sidechain::FrameResiduePtr frame_res = 
+        env_->GetScFrameResidue(global_idx);
         if(frame_res) {
           frame_residues.push_back(frame_res);
           has_sidechain[idx] = true;
@@ -322,19 +325,21 @@ void SidechainReconstructor::CollectRotamerGroups_(
   }
 }
 
-void ApplySubrotamerOptimization(std::vector<FRMRotamerGroupPtr>& rotamer_groups,
+void ApplySubrotamerOptimization(std::vector<sidechain::FRMRotamerGroupPtr>& 
+                                 rotamer_groups,
                                  const std::vector<int>& solution) {
 
   uint num_rotamer_groups = rotamer_groups.size();
 
-  std::vector<FRMRotamerPtr> rotamers(rotamer_groups.size());
+  std::vector<sidechain::FRMRotamerPtr> rotamers(rotamer_groups.size());
   for(uint i = 0; i < num_rotamer_groups; ++i){
     rotamers[i] = (*rotamer_groups[i])[solution[i]];
   }
-  SubrotamerOptimizer(rotamers);
+  sidechain::SubrotamerOptimizer(rotamers);
 }
 
-void ApplySubrotamerOptimization(std::vector<RRMRotamerGroupPtr>& rotamer_groups,
+void ApplySubrotamerOptimization(std::vector<sidechain::RRMRotamerGroupPtr>& 
+                                 rotamer_groups,
                                  const std::vector<int>& solution) {
   //there's nothing to do... 
 }
@@ -352,16 +357,16 @@ void SidechainReconstructor::SolveSystem_(
   loop::AllAtomPositions& out_pos = *(res->env_pos->all_pos);
   
   // collect frame residues and cysteins (if needed)
-  std::vector<FrameResiduePtr> frame_residues;
+  std::vector<sidechain::FrameResiduePtr> frame_residues;
   std::vector<bool> has_sidechain(res_indices.size(), false);
   std::vector<uint> cys_indices;
   for (uint i = 0; i < res_indices.size(); ++i) {
     const uint res_idx = res_indices[i];
     // add backbone frame residue if available
-    FrameResiduePtr frame_res = env_->GetBbFrameResidue(res_idx);
+    sidechain::FrameResiduePtr frame_res = env_->GetBbFrameResidue(res_idx);
     if (frame_res) frame_residues.push_back(frame_res);
     // check sidechain
-    if (build_disulfids_ && env_->GetRotamerID(res_idx) == CYS) {
+    if (build_disulfids_ && env_->GetRotamerID(res_idx) == sidechain::CYS) {
       cys_indices.push_back(i);
     } else if (keep_sidechains_) {
       frame_res = env_->GetScFrameResidue(res_idx);
@@ -376,8 +381,8 @@ void SidechainReconstructor::SolveSystem_(
   res->disulfid_bridges.clear();
   if (build_disulfids_) {
     // we use the FRM rotamer model in any case for reconstructing disulfids
-    BuildDisulfids_<FRMRotamerGroup>(res, cys_indices, frame_residues,
-                                     has_sidechain);
+    BuildDisulfids_<sidechain::FRMRotamerGroup>(res, cys_indices, 
+                                                frame_residues, has_sidechain);
   }
   
   // collect rotamers
@@ -386,14 +391,15 @@ void SidechainReconstructor::SolveSystem_(
   CollectRotamerGroups_(res, rotamer_groups, has_sidechain);
 
   // set frame energies in rotamers (note: internal energies are precomputed)
-  FramePtr frame(new Frame(frame_residues));
+  sidechain::FramePtr frame(new sidechain::Frame(frame_residues));
   for (uint i = 0; i < rotamer_groups.size(); ++i) {
     rotamer_groups[i]->SetFrameEnergy(frame);
     rotamer_groups[i]->ApplySelfEnergyThresh();
   }
 
   // solve graph
-  RotamerGraphPtr graph = RotamerGraph::CreateFromList(rotamer_groups);
+  sidechain::RotamerGraphPtr graph = 
+  sidechain::RotamerGraph::CreateFromList(rotamer_groups);
   std::pair<std::vector<int>,Real> solution = 
     graph->TreeSolve(graph_max_complexity_, graph_intial_epsilon_);
 
diff --git a/sidechain/src/sidechain_reconstructor.hh b/modelling/src/sidechain_reconstructor.hh
similarity index 94%
rename from sidechain/src/sidechain_reconstructor.hh
rename to modelling/src/sidechain_reconstructor.hh
index bd405ec3..565b830a 100644
--- a/sidechain/src/sidechain_reconstructor.hh
+++ b/modelling/src/sidechain_reconstructor.hh
@@ -2,9 +2,9 @@
 #define PM3_SIDECHAIN_RECONSTRUCTOR_HH
 
 #include <promod3/loop/all_atom_env.hh>
-#include <promod3/sidechain/sidechain_env_listener.hh>
+#include <promod3/modelling/sidechain_env_listener.hh>
 
-namespace promod3 { namespace sidechain {
+namespace promod3 { namespace modelling {
 
 class SidechainReconstructionData;
 class SidechainReconstructor;
@@ -66,9 +66,9 @@ public:
   void AttachEnvironment(loop::AllAtomEnv& env, bool use_frm = true,
                          bool use_bbdep_lib = true);
   void AttachEnvironment(loop::AllAtomEnv& env, bool use_frm,
-                         BBDepRotamerLibPtr bbdep_library);
+                         sidechain::BBDepRotamerLibPtr bbdep_library);
   void AttachEnvironment(loop::AllAtomEnv& env, bool use_frm,
-                         RotamerLibPtr library);
+                         sidechain::RotamerLibPtr library);
 
 private:
 
@@ -87,7 +87,7 @@ private:
   template<typename RotamerGroup>
   void BuildDisulfids_(SidechainReconstructionDataPtr res,
                        std::vector<uint>& cys_indices,
-                       std::vector<FrameResiduePtr>& frame_residues,
+                       std::vector<sidechain::FrameResiduePtr>& frame_residues,
                        std::vector<bool>& has_sidechain) const;
 
   // collects rotamers for residues with has_sidechain[i] = false
diff --git a/modelling/tests/CMakeLists.txt b/modelling/tests/CMakeLists.txt
index 5d222f9c..41792a8b 100644
--- a/modelling/tests/CMakeLists.txt
+++ b/modelling/tests/CMakeLists.txt
@@ -4,8 +4,10 @@ set(MODELLING_UNIT_TESTS
   test_modelling.py
   test_pipeline.py
   test_ring_punches.py
+  test_sidechain_reconstruction.py
   test_loop_candidates.cc
   test_loop_closing.cc
+  test_sidechain_reconstructor.cc
   tests.cc
 )
 
@@ -19,7 +21,11 @@ set(MODELLING_TEST_DATA
   data/1crn_final.pdb
   data/1crn_rec.pdb
   data/1crn_sc.pdb
+  data/1crn_sc_test.pdb
   data/1CRNA.hhm
+  data/1eye.pdb
+  data/1eye_rec.pdb
+  data/1eye_sc_test.pdb
   data/1ITX-A-11_sidechain.pdb
   data/1K5C-A-16_clash.pdb
   data/1mcg.pdb
diff --git a/sidechain/tests/data/1crn_sc_test.pdb b/modelling/tests/data/1crn_sc_test.pdb
similarity index 100%
rename from sidechain/tests/data/1crn_sc_test.pdb
rename to modelling/tests/data/1crn_sc_test.pdb
diff --git a/sidechain/tests/data/1eye.pdb b/modelling/tests/data/1eye.pdb
similarity index 100%
rename from sidechain/tests/data/1eye.pdb
rename to modelling/tests/data/1eye.pdb
diff --git a/sidechain/tests/data/1eye_rec.pdb b/modelling/tests/data/1eye_rec.pdb
similarity index 100%
rename from sidechain/tests/data/1eye_rec.pdb
rename to modelling/tests/data/1eye_rec.pdb
diff --git a/sidechain/tests/data/1eye_sc_test.pdb b/modelling/tests/data/1eye_sc_test.pdb
similarity index 100%
rename from sidechain/tests/data/1eye_sc_test.pdb
rename to modelling/tests/data/1eye_sc_test.pdb
diff --git a/modelling/tests/test_ring_punches.py b/modelling/tests/test_ring_punches.py
index 1a41db71..901cfbc0 100644
--- a/modelling/tests/test_ring_punches.py
+++ b/modelling/tests/test_ring_punches.py
@@ -3,7 +3,7 @@ Unit tests to detect ring punchings.
 """
 import unittest
 import ost
-from promod3 import modelling, loop, sidechain
+from promod3 import modelling, loop
 
 class RingPunchTests(unittest.TestCase):
     def testRings(self):
@@ -24,7 +24,7 @@ class RingPunchTests(unittest.TestCase):
         self.assertEqual(str(rings[2].residue), "A.PRO7")
         self.assertEqual(str(rings[3].residue), "A.PRO8")
         # add sidechains
-        sidechain.Reconstruct(model, keep_sidechains=False)
+        modelling.ReconstructSidechains(model, keep_sidechains=False)
         rings = modelling.GetRings(model)
         self.assertEqual(len(rings), 9)
         self.assertAlmostEqual(rings[0].radius, 1.31, places=1)
diff --git a/sidechain/tests/test_sidechain.py b/modelling/tests/test_sidechain_reconstruction.py
similarity index 89%
rename from sidechain/tests/test_sidechain.py
rename to modelling/tests/test_sidechain_reconstruction.py
index 9211fbfc..37c82e65 100644
--- a/sidechain/tests/test_sidechain.py
+++ b/modelling/tests/test_sidechain_reconstruction.py
@@ -1,6 +1,6 @@
 import unittest
-from promod3 import sidechain, loop
 from ost import io, mol, geom
+from promod3 import loop, sidechain, modelling
 import os
 
 class SidechainTests(unittest.TestCase):
@@ -27,14 +27,14 @@ class SidechainTests(unittest.TestCase):
                      rotamer_model, rotamer_library):
         # reconstruct sidechains for full OST entity
         ent_py = ent.Copy()
-        sidechain.Reconstruct(ent_py, keep_sidechains=keep_sidechains,
-                              build_disulfids=build_disulfids,
-                              optimize_subrotamers=optimize_subrotamers,
-                              rotamer_model=rotamer_model,
-                              rotamer_library=rotamer_library)
+        modelling.ReconstructSidechains(ent_py, keep_sidechains=keep_sidechains,
+                                        build_disulfids=build_disulfids,
+                                        optimize_subrotamers=optimize_subrotamers,
+                                        rotamer_model=rotamer_model,
+                                        rotamer_library=rotamer_library)
 
         # same with SidechainReconstructor
-        sc_rec = sidechain.SidechainReconstructor( \
+        sc_rec = modelling.SidechainReconstructor( \
                                keep_sidechains=keep_sidechains,
                                build_disulfids=build_disulfids,
                                optimize_subrotamers=optimize_subrotamers)
@@ -50,8 +50,8 @@ class SidechainTests(unittest.TestCase):
         outfile = os.path.join('data', '1eye_rec.pdb')
         # get and reconstruct 1eye
         prot = io.LoadPDB(infile)
-        sidechain.Reconstruct(prot, keep_sidechains=False,
-                              rotamer_library=self.bbdep_rotamer_library)
+        modelling.ReconstructSidechains(prot, keep_sidechains=False,
+                                        rotamer_library=self.bbdep_rotamer_library)
         # compare with reference solution
         prot_rec = io.LoadPDB(outfile)
         self.assertEqual(prot.GetAtomCount(), prot_rec.GetAtomCount())
diff --git a/sidechain/tests/test_sidechain_reconstructor.cc b/modelling/tests/test_sidechain_reconstructor.cc
similarity index 98%
rename from sidechain/tests/test_sidechain_reconstructor.cc
rename to modelling/tests/test_sidechain_reconstructor.cc
index 3b09654d..24791410 100644
--- a/sidechain/tests/test_sidechain_reconstructor.cc
+++ b/modelling/tests/test_sidechain_reconstructor.cc
@@ -1,5 +1,5 @@
 
-#include <promod3/sidechain/sidechain_reconstructor.hh>
+#include <promod3/modelling/sidechain_reconstructor.hh>
 #include <promod3/core/message.hh>
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
@@ -12,7 +12,7 @@
 BOOST_AUTO_TEST_SUITE( sidechain );
 
 using namespace promod3;
-using namespace promod3::sidechain;
+using namespace promod3::modelling;
 
 namespace {
 
diff --git a/sidechain/doc/CMakeLists.txt b/sidechain/doc/CMakeLists.txt
index 09dbdca6..4c1d1172 100644
--- a/sidechain/doc/CMakeLists.txt
+++ b/sidechain/doc/CMakeLists.txt
@@ -1,6 +1,5 @@
 set(SIDECHAIN_RST
 index.rst
-reconstruct.rst
 rotamer.rst
 rotamer_id.rst
 frame.rst
diff --git a/sidechain/doc/index.rst b/sidechain/doc/index.rst
index 69da3d91..c0a24dce 100644
--- a/sidechain/doc/index.rst
+++ b/sidechain/doc/index.rst
@@ -12,21 +12,12 @@ 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
-
-For use during loop modelling, the :class:`SidechainReconstructor` can be used:
-
-.. 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:`Reconstruct`  function above. An
-overview of the full provided functionality can be found at  the bottom of this
-page.
+us. In this case, you should use the full fletched sidechain reconstruction
+pipelines available in the modelling module. 
+
 
 .. literalinclude:: ../../../tests/doc/scripts/sidechain_steps.py
 
@@ -35,7 +26,6 @@ Contents:
 .. toctree::
    :maxdepth: 2
 
-   reconstruct
    rotamer_id
    rotamer
    frame
diff --git a/sidechain/pymod/CMakeLists.txt b/sidechain/pymod/CMakeLists.txt
index 3a745384..df22822d 100644
--- a/sidechain/pymod/CMakeLists.txt
+++ b/sidechain/pymod/CMakeLists.txt
@@ -10,7 +10,6 @@ export_rotamer_density.cc
 export_rotamer_ids.cc
 export_rotamer_lib.cc
 export_sidechain_object_loader.cc
-export_sidechain_reconstructor.cc
 export_scwrl_rotamer_constructor.cc
 export_subrotamer_optimizer.cc
 wrap_sidechain.cc
@@ -18,7 +17,6 @@ wrap_sidechain.cc
 
 set(SIDECHAIN_PYMOD
 __init__.py
-_reconstruct_sidechains.py
 )
 
 pymod(NAME sidechain CPP ${SIDECHAIN_CPP} PY ${SIDECHAIN_PYMOD}
diff --git a/sidechain/pymod/__init__.py b/sidechain/pymod/__init__.py
index 8e7127cc..a915c37e 100644
--- a/sidechain/pymod/__init__.py
+++ b/sidechain/pymod/__init__.py
@@ -1,2 +1,2 @@
 from _sidechain import *
-from _reconstruct_sidechains import *
+
diff --git a/sidechain/pymod/wrap_sidechain.cc b/sidechain/pymod/wrap_sidechain.cc
index 5e3f80d7..14a3fc9b 100644
--- a/sidechain/pymod/wrap_sidechain.cc
+++ b/sidechain/pymod/wrap_sidechain.cc
@@ -11,7 +11,6 @@ void export_RotamerDensity();
 void export_RotamerIDs();
 void export_RotamerLib();
 void export_SidechainObjectLoader();
-void export_SidechainReconstructor();
 void export_SCWRLRotamerConstructor();
 void export_SubrotamerOptimizer();
 
@@ -30,7 +29,6 @@ BOOST_PYTHON_MODULE(_sidechain)
   export_RotamerIDs();
   export_RotamerLib(); 
   export_SidechainObjectLoader();
-  export_SidechainReconstructor();
   export_SCWRLRotamerConstructor();
   export_SubrotamerOptimizer();
 }
diff --git a/sidechain/src/CMakeLists.txt b/sidechain/src/CMakeLists.txt
index 34a9a875..dfa815fc 100644
--- a/sidechain/src/CMakeLists.txt
+++ b/sidechain/src/CMakeLists.txt
@@ -13,9 +13,7 @@ set(SIDECHAIN_HEADERS
   rotamer_lib_entry.hh
   rotamer_lib_reader.hh
   sidechain_connector.hh
-  sidechain_env_listener.hh
   sidechain_object_loader.hh
-  sidechain_reconstructor.hh
   scwrl_rotamer_constructor.hh
   subrotamer_optimizer.hh
 )
@@ -35,9 +33,7 @@ set(SIDECHAIN_SOURCES
   rotamer_lib_entry.cc
   rotamer_lib_reader.cc
   sidechain_connector.cc
-  sidechain_env_listener.cc
   sidechain_object_loader.cc
-  sidechain_reconstructor.cc
   scwrl_rotamer_constructor.cc
   subrotamer_optimizer.cc
 )
diff --git a/sidechain/tests/CMakeLists.txt b/sidechain/tests/CMakeLists.txt
index 13d46c0d..e5cd99e0 100644
--- a/sidechain/tests/CMakeLists.txt
+++ b/sidechain/tests/CMakeLists.txt
@@ -1,16 +1,10 @@
 set(SIDECHAIN_UNIT_TESTS
-  test_sidechain.py
   test_frame_construction.cc
   test_rotamers.cc
-  test_sidechain_reconstructor.cc
   tests.cc
 )
 
 set(SIDECHAIN_TEST_DATA
-  data/1crn_sc_test.pdb
-  data/1eye.pdb
-  data/1eye_rec.pdb
-  data/1eye_sc_test.pdb
   data/all_sc.pdb
 )
 
-- 
GitLab