From b0fd18f960ab6d6e312cc35cf6fb775167210ac5 Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Sun, 17 Mar 2019 14:10:51 +0100
Subject: [PATCH] Refactor rotamer construction

The atoms of all standard amino acids are defined in a RotamerLookup class.
This class has three different modes and defines amino acids accordingly:
HEAVY_ATOM_MODE, POLAR_HYDROGEN_MODE, FULL_ATOMIC_MODE
The RotamerConstructor makes sure that all the atoms defined in the
RotamerLookup are stored in position buffers when constructing
rotamers/frame residues.

The actual Particle parametrization happens in an energy function specific
child class of RotamerConstructor that has access to the position buffers
and some additional information to parametrize the constructed particles.
It also determines what mode in the RotamerLookup of the parent class is
used.

The motivation was to move as much away from the child class in order to make
it as easy as possible the add new energy function specific child classes of
RotamerConstructor.

The new implementation does not exactly reproduce the results from before
(but almost), as there have been introdued minor changes / bugfixes.

- The construction of terminal hydrogens / oxygens is more sane
- CB of HSD previously ended up in the sidechain, the default should be backbone frame
- GLY CA is of SCWRL4ParticleType CH2Particle, not CH1Particle
---
 CHANGELOG                                     |    2 +-
 doc/tests/scripts/sidechain_steps.py          |    7 +-
 modelling/pymod/_reconstruct_sidechains.py    |   70 +-
 modelling/src/sidechain_env_listener.cc       |    7 +-
 modelling/src/sidechain_env_listener.hh       |   24 +-
 sidechain/doc/rotamer_constructor.rst         |  120 +-
 sidechain/pymod/export_rotamer_constructor.cc |  151 +-
 sidechain/src/CMakeLists.txt                  |    2 +
 sidechain/src/disulfid.cc                     |    4 +-
 sidechain/src/rotamer_constructor.cc          |  899 +++++-
 sidechain/src/rotamer_constructor.hh          |  159 +-
 sidechain/src/rotamer_lookup.cc               | 2140 ++++++++++++++
 sidechain/src/rotamer_lookup.hh               |  307 ++
 sidechain/src/scwrl4_rotamer_constructor.cc   | 2540 +++++------------
 sidechain/src/scwrl4_rotamer_constructor.hh   |  294 +-
 15 files changed, 4379 insertions(+), 2347 deletions(-)
 create mode 100644 sidechain/src/rotamer_lookup.cc
 create mode 100644 sidechain/src/rotamer_lookup.hh

diff --git a/CHANGELOG b/CHANGELOG
index d9a95434..b55f1798 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,7 +12,7 @@ Release X
   This simplifies the addition of other scoring functions in the future.
   Be aware of breaking changes introduced in the process!
   (SCWRLRotamerConstructor -> SCWRL4RotamerConstructor, changed interface of
-  Particle class).
+  Particle and RotamerConstructor classes).
 * Several minor bug fixes, improvements, and speed-ups  
 
 
diff --git a/doc/tests/scripts/sidechain_steps.py b/doc/tests/scripts/sidechain_steps.py
index d73a626d..6f66e5ee 100644
--- a/doc/tests/scripts/sidechain_steps.py
+++ b/doc/tests/scripts/sidechain_steps.py
@@ -37,7 +37,9 @@ frame_residues = list()
 for i,r in enumerate(prot.residues):
     frame_residue = rot_constructor.ConstructBackboneFrameResidue(
                         r, rotamer_ids[i], i,
-                        torsion_angles[i][0], i == 0,
+                        torsion_angles[i][0],
+                        torsion_angles[i][1], 
+                        i == 0,
                         i == (len(rotamer_ids)-1))
     frame_residues.append(frame_residue)
 
@@ -54,7 +56,8 @@ for i,r in enumerate(prot.residues):
 
     rot_group = rot_constructor.ConstructFRMRotamerGroup(
                     r, rotamer_ids[i], i, library,
-                    torsion_angles[i][0], torsion_angles[i][1])
+                    torsion_angles[i][0], torsion_angles[i][1],
+                    i == 0, i == (len(rotamer_ids)-1), 0.98)
 
     # calculate pairwise energies towards the rigid frame
     # the values will be stored and used by the solving algorithm
diff --git a/modelling/pymod/_reconstruct_sidechains.py b/modelling/pymod/_reconstruct_sidechains.py
index 969df78d..b94c37c9 100644
--- a/modelling/pymod/_reconstruct_sidechains.py
+++ b/modelling/pymod/_reconstruct_sidechains.py
@@ -84,14 +84,14 @@ def _GetDihedrals(res_list):
     return phi_angles, psi_angles
 
 def _AddBackboneFrameResidues(frame_residues, res_list, rotamer_ids,
-                              rotamer_constructor, phi_angles):
+                              rotamer_constructor, phi_angles, psi_angles):
     '''Update frame_residues (list) with BackboneFrameResidues for res_list.'''
     for i,r in enumerate(res_list):
         try:
             frame_residue = rotamer_constructor.ConstructBackboneFrameResidue(\
                                 r.handle, rotamer_ids[i], i,
-                                phi_angles[i], r.HasProp("n_ter"),
-                                r.HasProp("c_ter"))
+                                phi_angles[i], psi_angles[i], 
+                                r.HasProp("n_ter"), r.HasProp("c_ter"))
             frame_residues.append(frame_residue)
         except:
             continue
@@ -110,6 +110,7 @@ def _AddLigandFrameResidues(frame_residues, ent_lig, rotamer_constructor, offset
             if rot_id != sidechain.XXX:
                 # get more info
                 phi = _GetPhiAngle(res)
+                psi = _GetPsiAngle(res)
                 r_prev = res.handle.prev
                 n_ter = not r_prev.IsValid() \
                         or not mol.InSequence(r_prev, res.handle)
@@ -120,10 +121,10 @@ def _AddLigandFrameResidues(frame_residues, ent_lig, rotamer_constructor, offset
                 try:
                     fr1 = rotamer_constructor.ConstructBackboneFrameResidue(\
                               res.handle, rot_id, res_idx,
-                              phi, n_ter, c_ter)
+                              phi, psi, n_ter, c_ter)
 
                     fr2 = rotamer_constructor.ConstructSidechainFrameResidue(\
-                              res.handle, rot_id, res_idx)
+                              res.handle, rot_id, res_idx, phi, psi, n_ter, c_ter)
 
                     frame_residues.extend([fr1,fr2])
                 except:
@@ -137,7 +138,7 @@ def _AddLigandFrameResidues(frame_residues, ent_lig, rotamer_constructor, offset
                 # NOTES:
                 # - ConstructFrameResidueHeuristic has fall back if res unknown
                 # - it only deals with few possible ligand cases and has not
-                #   been tested extensively!
+                #   been tested extensively! 
                 comp_lib = conop.GetDefaultLib()
                 fr = rotamer_constructor.ConstructFrameResidueHeuristic(\
                          res.handle, res_idx, comp_lib)
@@ -147,6 +148,7 @@ def _AddLigandFrameResidues(frame_residues, ent_lig, rotamer_constructor, offset
 
 def _AddSidechainFrameResidues(frame_residues, incomplete_sidechains,
                                keep_sidechains, res_list, rotamer_ids,
+                               phi_angles, psi_angles,
                                rotamer_constructor, cystein_indices=None):
     '''Update frame_residues (list) with SidechainFrameResidues for res_list,
     incomplete_sidechains (list of indices) with sidechains to be constructed,
@@ -165,7 +167,8 @@ def _AddSidechainFrameResidues(frame_residues, incomplete_sidechains,
 
             try:
                 frame_residue = rotamer_constructor.ConstructSidechainFrameResidue(\
-                                    r.handle, rotamer_ids[i], i)
+                                    r.handle, rotamer_ids[i], i, phi_angles[i],
+                                    psi_angles[i], r.HasProp("n_ter"), r.HasProp("c_ter"))
                 frame_residues.append(frame_residue)
             except:
                 incomplete_sidechains.append(i)
@@ -182,6 +185,7 @@ def _AddSidechainFrameResidues(frame_residues, incomplete_sidechains,
 
 def _AddCysteinFrameResidues(frame_residues, incomplete_sidechains,
                              keep_sidechains, res_list, rotamer_ids,
+                             phi_angles, psi_angles,
                              rot_constructor, cystein_indices,
                              disulfid_indices, disulfid_rotamers):
     '''Update frame_residues (list) with cysteins.
@@ -206,7 +210,9 @@ def _AddCysteinFrameResidues(frame_residues, incomplete_sidechains,
             try:
                 frame_residue = rot_constructor.ConstructSidechainFrameResidue(\
                                     res_list[idx].handle, rotamer_ids[idx],
-                                    idx)
+                                    idx, phi_angles[idx], psi_angles[idx],
+                                    res_list[idx].handle.HasProp("n_ter"),
+                                    res_list[idx].handle.HasProp("c_ter"))
                 frame_residues.append(frame_residue)
             except:
                 incomplete_sidechains.append(idx) 
@@ -214,27 +220,24 @@ def _AddCysteinFrameResidues(frame_residues, incomplete_sidechains,
             incomplete_sidechains.append(idx)
 
 def _GetRotamerGroup(res_handle, rot_id, res_idx, rot_lib, rot_constructor,
-                     phi, psi, use_frm, bbdep, probability_cutoff = 0.98):
+                     phi, psi, use_frm, bbdep, 
+                     probability_cutoff = 0.98):
+
     if use_frm:
-        if bbdep:
-            return rot_constructor.ConstructFRMRotamerGroup(res_handle, rot_id,
-                                                            res_idx, rot_lib,
-                                                            phi, psi,
-                                                            probability_cutoff)
-        else:
-            return rot_constructor.ConstructFRMRotamerGroup(res_handle, rot_id,
-                                                            res_idx, rot_lib,
-                                                            probability_cutoff)
-    else:
-        if bbdep:
-            return rot_constructor.ConstructRRMRotamerGroup(res_handle, rot_id,
-                                                            res_idx, rot_lib,
-                                                            phi, psi,
-                                                            probability_cutoff)
-        else:
-            return rot_constructor.ConstructRRMRotamerGroup(res_handle, rot_id,
-                                                            res_idx, rot_lib,
-                                                            probability_cutoff)
+        return rot_constructor.ConstructFRMRotamerGroup(res_handle, rot_id,
+                                                        res_idx, rot_lib,
+                                                        phi, psi, 
+                                                        res_handle.HasProp("n_ter"),
+                                                        res_handle.HasProp("c_ter"),
+                                                        probability_cutoff)
+    else:        
+        return rot_constructor.ConstructRRMRotamerGroup(res_handle, rot_id,
+                                                        res_idx, rot_lib,
+                                                        phi, psi,
+                                                        res_handle.HasProp("n_ter"),
+                                                        res_handle.HasProp("c_ter"),
+                                                        probability_cutoff)
+
 
 def _GetRotamerGroups(res_list, rot_ids, indices, rot_lib, rot_constructor,
                       phi_angles, psi_angles, use_frm, bbdep, frame_residues):
@@ -341,10 +344,14 @@ def _GetDisulfidBridges(frame_residues, keep_sidechains, cystein_indices,
             if sg.IsValid():
                 # we're constructing the required particle through a frame 
                 # residue in the rotamer constructor
+                phi = _GetPhiAngle(r)
+                psi = _GetPsiAngle(r)
                 cys_frame_res = \
                 rotamer_constructor.ConstructSidechainFrameResidue(r.handle, 
                                                                    sidechain.CYD, 
-                                                                   0)
+                                                                   0, phi, psi,
+                                                                   r.HasProp("n_ter"),
+                                                                   r.HasProp("c_ter"))
                 for j in range(len(cys_frame_res)):
                     if cys_frame_res[j].GetName() == "SG":
                         particle_list = [cys_frame_res[j]]
@@ -474,7 +481,7 @@ def ReconstructSidechains(ent, keep_sidechains=False, build_disulfids=True,
     frame_residues = list()         # list of frame residues connected to frame
     incomplete_sidechains = list()  # residue indices
     _AddBackboneFrameResidues(frame_residues, prot.residues, rotamer_ids,
-                              rotamer_constructor, phi_angles)
+                              rotamer_constructor, phi_angles, psi_angles)
     
     # add ligands?
     if consider_ligands:
@@ -489,6 +496,7 @@ def ReconstructSidechains(ent, keep_sidechains=False, build_disulfids=True,
         # update frame_residues, incomplete_sidechains, cystein_indices
         _AddSidechainFrameResidues(frame_residues, incomplete_sidechains,
                                    keep_sidechains, prot.residues, rotamer_ids,
+                                   phi_angles, psi_angles,
                                    rotamer_constructor, cystein_indices)
         # update frame_residues, incomplete_sidechains with cysteins (if needed)
         if len(cystein_indices) > 0:
@@ -501,12 +509,14 @@ def ReconstructSidechains(ent, keep_sidechains=False, build_disulfids=True,
             # update frame_residues, incomplete_sidechains
             _AddCysteinFrameResidues(frame_residues, incomplete_sidechains,
                                      keep_sidechains, prot.residues, rotamer_ids,
+                                     phi_angles, psi_angles,
                                      rotamer_constructor, cystein_indices,
                                      disulfid_indices, disulfid_rotamers)
     else:
         # update frame_residues, incomplete_sidechains
         _AddSidechainFrameResidues(frame_residues, incomplete_sidechains,
                                    keep_sidechains, prot.residues, rotamer_ids,
+                                   phi_angles, psi_angles,
                                    rotamer_constructor)
     
     # get rotamer groups and residues they're linked to
diff --git a/modelling/src/sidechain_env_listener.cc b/modelling/src/sidechain_env_listener.cc
index 19d97aa1..160a0675 100644
--- a/modelling/src/sidechain_env_listener.cc
+++ b/modelling/src/sidechain_env_listener.cc
@@ -193,6 +193,7 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
       = rot_constructor_.ConstructBackboneFrameResidue(*all_pos, res_idx, 
                                                        r_id, res_idx, 
                                                        phi_angle_[res_idx], 
+                                                       psi_angle_[res_idx],
                                                        n_ter_[res_idx], 
                                                        c_ter_[res_idx]);
     
@@ -200,7 +201,11 @@ void SidechainEnvListener::SetResidue_(loop::ConstAllAtomPositionsPtr all_pos,
     if (all_set) {
       sc_frame_residue_[res_idx]
         = rot_constructor_.ConstructSidechainFrameResidue(*all_pos, res_idx, 
-                                                           r_id, res_idx);
+                                                           r_id, res_idx,
+                                                           phi_angle_[res_idx],
+                                                           psi_angle_[res_idx],
+                                                           n_ter_[res_idx],
+                                                           c_ter_[res_idx]);
     } else {
       sc_frame_residue_[res_idx].reset();
     }
diff --git a/modelling/src/sidechain_env_listener.hh b/modelling/src/sidechain_env_listener.hh
index cc8c2709..8c919cc2 100644
--- a/modelling/src/sidechain_env_listener.hh
+++ b/modelling/src/sidechain_env_listener.hh
@@ -142,13 +142,19 @@ public:
                                                             r_id, res_idx,
                                                             bbdep_library_,
                                                             phi_angle_[res_idx],
-                                                            psi_angle_[res_idx]);
+                                                            psi_angle_[res_idx],
+                                                            n_ter_[res_idx],
+                                                            c_ter_[res_idx]);
     } else {
       rot_group = rot_constructor_.ConstructFRMRotamerGroup(*all_pos, res_idx, 
                                                             r_id, res_idx,
-                                                            library_);
+                                                            library_,
+                                                            phi_angle_[res_idx],
+                                                            psi_angle_[res_idx],
+                                                            n_ter_[res_idx],
+                                                            c_ter_[res_idx]);
     }
-    rot_constructor_.AssignInternalEnergies(rot_group);
+    rot_constructor_.AssignInternalEnergies(rot_group, r_id, res_idx);
   }
   void CreateRotamerGroup(sidechain::RRMRotamerGroupPtr& rot_group,
                           loop::ConstAllAtomPositionsPtr all_pos, 
@@ -158,13 +164,19 @@ public:
                                                             r_id, res_idx,
                                                             bbdep_library_,
                                                             phi_angle_[res_idx],
-                                                            psi_angle_[res_idx]);
+                                                            psi_angle_[res_idx],
+                                                            n_ter_[res_idx],
+                                                            c_ter_[res_idx]);
     } else {
       rot_group = rot_constructor_.ConstructRRMRotamerGroup(*all_pos, res_idx,
                                                             r_id, res_idx,
-                                                            library_);
+                                                            library_,
+                                                            phi_angle_[res_idx],
+                                                            psi_angle_[res_idx],
+                                                            n_ter_[res_idx],
+                                                            c_ter_[res_idx]);
     }
-    rot_constructor_.AssignInternalEnergies(rot_group);
+    rot_constructor_.AssignInternalEnergies(rot_group, r_id, res_idx);
   }
 
 private:
diff --git a/sidechain/doc/rotamer_constructor.rst b/sidechain/doc/rotamer_constructor.rst
index b36d7d88..3a297d5d 100644
--- a/sidechain/doc/rotamer_constructor.rst
+++ b/sidechain/doc/rotamer_constructor.rst
@@ -34,22 +34,23 @@ Constructing Rotamers and Frame Residues
   (e.g. :class:`SCWRL4RotamerConstructor`). 
 
   .. method:: ConstructRRMRotamerGroup(res, id, residue_index, rot_lib,\
-                                       [probability_cutoff = 0.98])
-  .. method:: ConstructRRMRotamerGroup(all_atom_pos, aa_res_idx, id,\
-                                       residue_index, rot_lib,\
-                                       [probability_cutoff = 0.98])
-  .. method:: ConstructRRMRotamerGroup(res, id, residue_index, rot_lib,\
-                                       [phi = -1.0472, psi = -0.7854,\
+                                       [phi = -1.0472, psi = -0.7854, \
+                                        n_ter = False, c_ter = False, \
                                         probability_cutoff = 0.98])
   .. method:: ConstructRRMRotamerGroup(all_atom_pos, aa_res_idx, id,\
                                        residue_index, rot_lib,\
-                                       [phi = -1.0472, psi = -0.7854,\
+                                       [phi = -1.0472, psi = -0.7854, \
+                                        n_ter = False, c_ter = False, \
                                         probability_cutoff = 0.98])
   .. method:: ConstructRRMRotamerGroup(res, id, residue_index, rot_lib_entries,\
-                                       [probability_cutoff = 0.98])
+                                       [phi = -1.0472, psi = -0.7854, \
+                                        n_ter = False, c_ter = False, \
+                                        probability_cutoff = 0.98])
   .. method:: ConstructRRMRotamerGroup(all_atom_pos, aa_res_idx, id,\
                                        residue_index, rot_lib_entries,\
-                                       [probability_cutoff = 0.98])
+                                       [phi = -1.0472, psi = -0.7854, \
+                                        n_ter = False, c_ter = False, \
+                                        probability_cutoff = 0.98])
 
     All functions are also avaible for their flexible rotamer model counterpart.
     =>ConstructFRMRotamerGroup(...) with the same parameters. 
@@ -66,10 +67,10 @@ Constructing Rotamers and Frame Residues
     :param rot_lib:     To search for rotamers
     :param rot_lib_entries: :class:`RotamerLibEntry` objects to circumvent the 
                             direct use of a rotamer library
-    :param phi:         Phi dihedral angle used to search for rotamers if a 
-                        :class:`BBDepRotamerLib` is given as input
-    :param psi:         Psi dihedral angle used to search for rotamers if a 
-                        :class:`BBDepRotamerLib` is given as input
+    :param phi:         Phi dihedral angle 
+    :param psi:         Psi dihedral angle 
+    :param n_ter:       Whether the residue is n-terminal
+    :param c_ter:       Whether the residue is c-terminal
     :param probability_cutoff: For some rotamers, there might be many low 
                         probability entries in the library. 
                         The function adds single rotamers to the group until 
@@ -77,8 +78,7 @@ Constructing Rotamers and Frame Residues
                         larger or equal **probability_cutoff**.
 
     :returns:           The rotamer group containing all constructed rotamers 
-                        with internal energies assigned based on the 
-                        probabilities extracted from the rotamer library. 
+                        with internal energies assigned. 
 
     :type res:          :class:`ost.mol.ResidueHandle`
     :type all_atom_pos: :class:`promod3.loop.AllAtomPositions`
@@ -87,6 +87,10 @@ Constructing Rotamers and Frame Residues
     :type residue_index: :class:`int`
     :type rot_lib:      :class:`RotamerLib` / :class:`BBDepRotamerLib`
     :type rot_lib_entries: :class:`list`
+    :type phi:          :class:`float`
+    :type psi:          :class:`float`
+    :type n_ter:        :class:`bool`
+    :type c_ter:        :class:`bool`
     :type probability_cutoff: :class:`float`
     :rtype:             :class:`RRMRotamerGroup`
 
@@ -96,12 +100,13 @@ Constructing Rotamers and Frame Residues
 
 
   .. method:: ConstructBackboneFrameResidue(res, id, residue_index, \
-                                            [ phi = -1.0472, n_ter = False, \
-                                            c_ter = False])
+                                            [phi = -1.0472, psi = -0.7854, \
+                                             n_ter = False, c_ter = False])
 
   .. method:: ConstructBackboneFrameResidue(all_atom_pos, aa_res_idx, id,\
-                                            residue_index, [phi = -1.0472,\
-                                            n_ter = False, c_ter = False])
+                                            residue_index, \
+                                            [phi = -1.0472, psi = -0.7854\
+                                             n_ter = False, c_ter = False])
 
     Constructs frame residues only containing backbone atoms (the ones that 
     don't show up in a rotamer).
@@ -115,19 +120,17 @@ Constructing Rotamers and Frame Residues
                           :class:`Frame` you don't want to calculate a pairwise
                           energy of the sidechain particles towards particles
                           representing the own backbone...
-    :param phi:         The dihedral angle of the current residue, required to 
-                        construct the polar nitrogen hydrogen 
-    :param n_ter:       Whether to add additional hydrogens at the nitrogen
-                        to represent a proper n-terminus
-    :param c_ter:       Whether to add an additional oxygen at the carbon to
-                        represent a proper c-terminus
-
+    :param phi:         The dihedral angle of the current residue
+    :param psi:         The dihedral angle of the current residue
+    :param n_ter:       Whether the residue is n-terminal
+    :param c_ter:       Whether the residue is c-terminal
     :type res:          :class:`ost.mol.ResidueHandle`
     :type all_atom_pos: :class:`promod3.loop.AllAtomPositions`
     :type aa_res_idx:   :class:`int`
     :type id:           :class:`RotamerID`
     :type residue_index: :class:`int`
     :type phi:          :class:`float`
+    :type psi:          :class:`float`
     :type n_ter:        :class:`bool`
     :type c_ter:        :class:`bool`
 
@@ -139,26 +142,40 @@ Constructing Rotamers and Frame Residues
               positions are set in **all_atom_pos**.
 
 
-  .. method:: ConstructSidechainFrameResidue(res, id, residue_index)
+  .. method:: ConstructSidechainFrameResidue(res, id, residue_index, \
+                                             [phi = -1.0472, psi = -0.7854, \
+                                              n_ter = False, c_ter = False])
 
-  .. method:: ConstructSidechainFrameResidue(all_atom, aa_res_idx, id,\ 
-                                             residue_index)
+  .. method:: ConstructSidechainFrameResidue(all_atom_pos, aa_res_idx, id,\
+                                             residue_index, \
+                                             [phi = -1.0472, psi = -0.7854\
+                                             n_ter = False, c_ter = False])
 
     Constructs frame residues only containing sidechain atoms (the ones that
     you observe in a rotamer).
 
-    :param res:         Residue from which to extract the sidechain positions
-    :param all_atom_pos: To extract the sidechain positions
+    :param res:         Residue from which to extract the backbone positions
+    :param all_atom_pos: To extract the backbone positions
     :param aa_res_idx:  Index of residue in **all_atom_pos** from which to 
-                        extract the sidechain positions
+                        extract the backbone positions
     :param id:          Identifies the sidechain
-    :param residue_index: idenfifies residue in frame
-
+    :param residue_index: Important for the energy calculations towards the 
+                          :class:`Frame` you don't want to calculate a pairwise
+                          energy of the sidechain particles towards particles
+                          representing the own backbone...
+    :param phi:         The dihedral angle of the current residue
+    :param psi:         The dihedral angle of the current residue
+    :param n_ter:       Whether the residue is n-terminal
+    :param c_ter:       Whether the residue is c-terminal
     :type res:          :class:`ost.mol.ResidueHandle`
     :type all_atom_pos: :class:`promod3.loop.AllAtomPositions`
     :type aa_res_idx:   :class:`int`
     :type id:           :class:`RotamerID`
     :type residue_index: :class:`int`
+    :type phi:          :class:`float`
+    :type psi:          :class:`float`
+    :type n_ter:        :class:`bool`
+    :type c_ter:        :class:`bool`
 
     :rtype:             :class:`FrameResidue`
 
@@ -167,7 +184,9 @@ Constructing Rotamers and Frame Residues
               atoms are present in **residue** or not all required sidechain 
               atom positions are set in **all_atom_pos**.
 
-  .. method:: AssignInternalEnergies(rot_group)
+  .. method:: AssignInternalEnergies(rot_group, id, residue_index, \
+                                     [phi = -1.0472, psi = -0.7854, \
+                                      n_ter = False, c_ter = False])
 
     Assigns an internal energy to every rotamer in *rot_group*, i.e. an energy
     value before looking at any structural component of the energy function.
@@ -176,8 +195,21 @@ Constructing Rotamers and Frame Residues
 
     :param rot_group:   containing all rotamers for which internal energies have
                         to be assigned
+    :param id:          Identifies the sidechain
+    :param residue_index: The index of the residue which is represented by 
+                          *rot_group*    
+    :param phi:         The dihedral angle of the current residue
+    :param psi:         The dihedral angle of the current residue
+    :param n_ter:       Whether the residue is n-terminal
+    :param c_ter:       Whether the residue is c-terminal
 
     :type rot_group:    :class:`RRMRotamerGroup` / :class:`FRMRotamerGroup`
+    :type id:           :class:`RotamerID`
+    :type residue_index: :class:`int`
+    :type phi:          :class:`float`
+    :type psi:          :class:`float`
+    :type n_ter:        :class:`bool`
+    :type c_ter:        :class:`bool`
 
 
 
@@ -244,7 +276,9 @@ Constructing Rotamers and Frame Residues
   
     :returns:             :class:`FrameResidue`
 
-  .. method:: AssignInternalEnergies(rot_group)
+  .. method:: AssignInternalEnergies(rot_group, id, residue_index, \
+                                     [phi = -1.0472, psi = -0.7854, \
+                                      n_ter = False, c_ter = False])
 
     Overrides the method defined in :class:`RotamerConstructor`.
     Takes the rotamer group and assigns every single rotamer its internal
@@ -257,6 +291,18 @@ Constructing Rotamers and Frame Residues
 
     :param rot_group:   containing all rotamers for which internal energies have
                         to be assigned
+    :param id:          Identifies the sidechain
+    :param residue_index: The index of the residue which is represented by 
+                          *rot_group*    
+    :param phi:         The dihedral angle of the current residue
+    :param psi:         The dihedral angle of the current residue
+    :param n_ter:       Whether the residue is n-terminal
+    :param c_ter:       Whether the residue is c-terminal
 
     :type rot_group:    :class:`RRMRotamerGroup` / :class:`FRMRotamerGroup`
-
+    :type id:           :class:`RotamerID`
+    :type residue_index: :class:`int`
+    :type phi:          :class:`float`
+    :type psi:          :class:`float`
+    :type n_ter:        :class:`bool`
+    :type c_ter:        :class:`bool`
diff --git a/sidechain/pymod/export_rotamer_constructor.cc b/sidechain/pymod/export_rotamer_constructor.cc
index 8b6b6890..cf28f603 100644
--- a/sidechain/pymod/export_rotamer_constructor.cc
+++ b/sidechain/pymod/export_rotamer_constructor.cc
@@ -39,9 +39,11 @@ RRMRotamerGroupPtr WrapRRMGroup_res(RotamerConstructorPtr constructor,
                                     RotamerID id,
                                     uint residue_idx,
                                     RotamerLibPtr rot_lib,
+                                    Real phi, Real psi, bool n_ter, bool c_ter,
                                     Real probability_cutoff){
   return constructor->ConstructRRMRotamerGroup(res, id, residue_idx, 
-                                               rot_lib, probability_cutoff);
+                                               rot_lib, phi, psi, n_ter, c_ter,
+                                               probability_cutoff);
 }
 
 RRMRotamerGroupPtr WrapRRMGroup_aa(RotamerConstructorPtr constructor,
@@ -50,20 +52,27 @@ RRMRotamerGroupPtr WrapRRMGroup_aa(RotamerConstructorPtr constructor,
                                    RotamerID rotamer_id,
                                    uint residue_idx,
                                    RotamerLibPtr rot_lib,
+                                   Real phi, Real psi,
+                                   bool n_ter, bool c_ter,
                                    Real probability_cutoff){
   return constructor->ConstructRRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
-                                               rot_lib, probability_cutoff);
+                                               rot_lib, phi, psi, n_ter, c_ter, 
+                                               probability_cutoff);
 }
 
 FRMRotamerGroupPtr WrapFRMGroup_res(RotamerConstructorPtr constructor,
                                     const ost::mol::ResidueHandle& res,
                                     RotamerID id,
                                     uint residue_idx,
-                                    RotamerLibPtr rot_lib,
+                                    RotamerLibPtr rot_lib, 
+                                    Real phi, Real psi,
+                                    bool n_ter, bool c_ter,
                                     Real probability_cutoff){
   return constructor->ConstructFRMRotamerGroup(res, id, residue_idx, 
-                                               rot_lib, probability_cutoff);
+                                               rot_lib, phi, psi,
+                                               n_ter, c_ter, 
+                                               probability_cutoff);
 }
 
 FRMRotamerGroupPtr WrapFRMGroup_aa(RotamerConstructorPtr constructor,
@@ -72,10 +81,12 @@ FRMRotamerGroupPtr WrapFRMGroup_aa(RotamerConstructorPtr constructor,
                                    RotamerID rotamer_id,
                                    uint residue_idx,
                                    RotamerLibPtr rot_lib,
+                                   Real phi, Real psi, bool n_ter, bool c_ter,
                                    Real probability_cutoff){
   return constructor->ConstructFRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
-                                               rot_lib, probability_cutoff);
+                                               rot_lib, phi, psi, n_ter, c_ter,
+                                               probability_cutoff);
 }
 
 RRMRotamerGroupPtr WrapRRMGroup_bbdep_res(RotamerConstructorPtr constructor,
@@ -84,9 +95,10 @@ RRMRotamerGroupPtr WrapRRMGroup_bbdep_res(RotamerConstructorPtr constructor,
                                           uint residue_idx,
                                           BBDepRotamerLibPtr rot_lib,
                                           Real phi, Real  psi,
+                                          bool n_ter, bool c_ter,
                                           Real probability_cutoff){
   return constructor->ConstructRRMRotamerGroup(res, id, residue_idx, 
-                                               rot_lib, phi, psi, 
+                                               rot_lib, phi, psi, n_ter, c_ter, 
                                                probability_cutoff);
 }
 
@@ -97,6 +109,7 @@ RRMRotamerGroupPtr WrapRRMGroup_bbdep_aa(RotamerConstructorPtr constructor,
                                          uint residue_idx,
                                          BBDepRotamerLibPtr rot_lib,
                                          Real phi, Real psi,
+                                         bool n_ter, bool c_ter,
                                          Real probability_cutoff){
   return constructor->ConstructRRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
@@ -110,9 +123,10 @@ FRMRotamerGroupPtr WrapFRMGroup_bbdep_res(RotamerConstructorPtr constructor,
                                           uint residue_idx,
                                           BBDepRotamerLibPtr rot_lib,
                                           Real phi, Real  psi,
+                                          bool n_ter, bool c_ter,
                                           Real probability_cutoff){
   return constructor->ConstructFRMRotamerGroup(res, id, residue_idx, 
-                                              rot_lib, phi, psi, 
+                                              rot_lib, phi, psi, n_ter, c_ter,
                                               probability_cutoff);
 }
 
@@ -123,10 +137,11 @@ FRMRotamerGroupPtr WrapFRMGroup_bbdep_aa(RotamerConstructorPtr constructor,
                                          uint residue_idx,
                                          BBDepRotamerLibPtr rot_lib,
                                          Real phi, Real  psi,
+                                         bool n_ter, bool c_ter,
                                          Real probability_cutoff){
   return constructor->ConstructFRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
-                                               rot_lib, phi, psi, 
+                                               rot_lib, phi, psi, n_ter, c_ter, 
                                                probability_cutoff);
 }
 
@@ -135,11 +150,14 @@ RRMRotamerGroupPtr WrapRRMGroup_entries_res(RotamerConstructorPtr constructor,
                                             RotamerID id,
                                             uint residue_idx,
                                             const boost::python::list& entries,
+                                            Real phi, Real psi, 
+                                            bool n_ter, bool c_ter,
                                             Real probability_cutoff){
   std::vector<RotamerLibEntry> v_entries;
   core::ConvertListToVector(entries, v_entries);
   return constructor->ConstructRRMRotamerGroup(res, id, residue_idx, 
-                                               v_entries, 
+                                               v_entries, phi, psi, 
+                                               n_ter, c_ter,
                                                probability_cutoff);
 }
 
@@ -149,12 +167,14 @@ RRMRotamerGroupPtr WrapRRMGroup_entries_aa(RotamerConstructorPtr constructor,
                                            RotamerID rotamer_id,
                                            uint residue_idx,
                                            const boost::python::list& entries,
+                                           Real phi, Real psi, 
+                                           bool n_ter, bool c_ter,
                                            Real probability_cutoff){
   std::vector<RotamerLibEntry> v_entries;
   core::ConvertListToVector(entries, v_entries);
   return constructor->ConstructRRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
-                                               v_entries, 
+                                               v_entries, phi, psi, n_ter, c_ter,
                                                probability_cutoff);
 }
 
@@ -163,11 +183,14 @@ FRMRotamerGroupPtr WrapFRMGroup_entries_res(RotamerConstructorPtr constructor,
                                             RotamerID id,
                                             uint residue_idx,
                                             const boost::python::list& entries,
+                                            Real phi, Real psi, 
+                                            bool n_ter, bool c_ter,
                                             Real probability_cutoff){
   std::vector<RotamerLibEntry> v_entries;
   core::ConvertListToVector(entries, v_entries);
   return constructor->ConstructFRMRotamerGroup(res, id, residue_idx, 
                                                v_entries, 
+                                               phi, psi, n_ter, c_ter,
                                                probability_cutoff);
 }
 
@@ -177,56 +200,68 @@ FRMRotamerGroupPtr WrapFRMGroup_entries_aa(RotamerConstructorPtr constructor,
                                            RotamerID rotamer_id,
                                            uint residue_idx,
                                            const boost::python::list& entries,
+                                           Real phi, Real psi, bool n_ter, 
+                                           bool c_ter,
                                            Real probability_cutoff){
   std::vector<RotamerLibEntry> v_entries;
   core::ConvertListToVector(entries, v_entries);
   return constructor->ConstructFRMRotamerGroup(all_atom_pos, all_atom_pos_idx,
                                                rotamer_id, residue_idx,
-                                               v_entries,
+                                               v_entries, phi, psi, n_ter, c_ter,
                                                probability_cutoff);
 }
 
 FrameResiduePtr WrapBBFrame_res(RotamerConstructorPtr constructor,
                                 const ost::mol::ResidueHandle& residue,
                                 RotamerID id, uint residue_index,
-                                Real phi, bool n_ter, bool c_ter){
+                                Real phi, Real psi, bool n_ter, bool c_ter){
     return constructor->ConstructBackboneFrameResidue(residue, id, residue_index,
-                                                      phi, n_ter, c_ter);
+                                                      phi, psi, n_ter, c_ter);
 }
 
 FrameResiduePtr WrapBBFrame_aa(RotamerConstructorPtr constructor,
                                const promod3::loop::AllAtomPositions& all_atom_pos,
                                uint all_atom_pos_idx,
                                RotamerID id, uint residue_index,
-                               Real phi, bool n_ter, bool c_ter){
+                               Real phi, Real psi, bool n_ter, bool c_ter){
     return constructor->ConstructBackboneFrameResidue(all_atom_pos, all_atom_pos_idx, 
                                                       id, residue_index,
-                                                      phi, n_ter, c_ter);
+                                                      phi, psi, n_ter, c_ter);
 }
 
 
 FrameResiduePtr WrapSCFrame_res(RotamerConstructorPtr constructor,
                                 const ost::mol::ResidueHandle& residue,
-                                RotamerID id, uint residue_index){
-    return constructor->ConstructSidechainFrameResidue(residue, id, residue_index);
+                                RotamerID id, uint residue_index,
+                                Real phi, Real psi, bool n_ter, bool c_ter){
+    return constructor->ConstructSidechainFrameResidue(residue, id, residue_index,
+                                                       phi, psi, n_ter, c_ter);
 }
 
 FrameResiduePtr WrapSCFrame_aa(RotamerConstructorPtr constructor,
                                const promod3::loop::AllAtomPositions& all_atom_pos,
                                uint all_atom_pos_idx,
-                               RotamerID id, uint residue_index){
+                               RotamerID id, uint residue_index,
+                               Real phi, Real psi, bool n_ter, bool c_ter){
     return constructor->ConstructSidechainFrameResidue(all_atom_pos, all_atom_pos_idx, 
-                                                      id, residue_index);
+                                                      id, residue_index, phi, psi,
+                                                      n_ter, c_ter);
 }
 
 void AssignInternalEnergiesRRM(RotamerConstructorPtr constructor,
-                               RRMRotamerGroupPtr group){
-  constructor->AssignInternalEnergies(group);
+                               RRMRotamerGroupPtr group, RotamerID id,
+                               uint residue_index,
+                               Real phi, Real psi, bool n_ter, bool c_ter){
+  constructor->AssignInternalEnergies(group, id, residue_index, phi, psi,
+                                      n_ter, c_ter);
 }
 
 void AssignInternalEnergiesFRM(RotamerConstructorPtr constructor,
-                               FRMRotamerGroupPtr group){
-  constructor->AssignInternalEnergies(group);
+                               FRMRotamerGroupPtr group, RotamerID id,
+                               uint residue_index,
+                               Real phi, Real psi, bool n_ter, bool c_ter){
+  constructor->AssignInternalEnergies(group, id, residue_index, phi, psi, 
+                                      n_ter, c_ter);
 }
 
 } // anon ns
@@ -240,23 +275,39 @@ void export_RotamerConstructor(){
                                                         arg("rotamer_id"),
                                                         arg("residue_idx"),
                                                         arg("rot_lib"),
+                                                        arg("phi") = -1.0472,
+                                                        arg("psi") = -0.7854,
+                                                        arg("n_ter") = false,
+                                                        arg("c_ter") = false,
                                                         arg("probability_cutoff") = 0.98))
     .def("ConstructRRMRotamerGroup", &WrapRRMGroup_aa,(arg("all_atom_pos"),
                                                        arg("all_atom_pos_idx"),
                                                        arg("rotamer_id"),
                                                        arg("residue_idx"),
                                                        arg("rot_lib"),
+                                                       arg("phi") = -1.0472,
+                                                       arg("psi") = -0.7854,
+                                                       arg("n_ter") = false,
+                                                       arg("c_ter") = false,                                                       
                                                        arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_res,(arg("residue"),
                                                         arg("rotamer_id"),
                                                         arg("residue_idx"),
                                                         arg("rot_lib"),
+                                                        arg("phi") = -1.0472,
+                                                        arg("psi") = -0.7854,
+                                                        arg("n_ter") = false,
+                                                        arg("c_ter") = false,
                                                         arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_aa,(arg("all_atom_pos"),
                                                        arg("all_atom_pos_idx"),
                                                        arg("rotamer_id"),
                                                        arg("residue_idx"),
                                                        arg("rot_lib"),
+                                                       arg("phi") = -1.0472,
+                                                       arg("psi") = -0.7854,
+                                                       arg("n_ter") = false,
+                                                       arg("c_ter") = false,
                                                        arg("probability_cutoff") = 0.98))
     .def("ConstructRRMRotamerGroup", &WrapRRMGroup_bbdep_res,(arg("residue"),
                                                               arg("rotamer_id"),
@@ -264,6 +315,8 @@ void export_RotamerConstructor(){
                                                               arg("rot_lib"),
                                                               arg("phi") = -1.0472,
                                                               arg("psi") = -0.7854,
+                                                              arg("n_ter") = false,
+                                                              arg("c_ter") = false,
                                                               arg("probability_cutoff") = 0.98))
     .def("ConstructRRMRotamerGroup", &WrapRRMGroup_bbdep_aa,(arg("all_atom_pos"),
                                                              arg("all_atom_pos_idx"),
@@ -272,6 +325,8 @@ void export_RotamerConstructor(){
                                                              arg("rot_lib"),
                                                              arg("phi") = -1.0472,
                                                              arg("psi") = -0.7854,
+                                                             arg("n_ter") = false,
+                                                             arg("c_ter") = false,
                                                              arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_bbdep_res,(arg("residue"),
                                                               arg("rotamer_id"),
@@ -279,6 +334,8 @@ void export_RotamerConstructor(){
                                                               arg("rot_lib"),
                                                               arg("phi") = -1.0472,
                                                               arg("psi") = -0.7854,
+                                                              arg("n_ter") = false,
+                                                              arg("c_ter") = false,
                                                               arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_bbdep_aa,(arg("all_atom_pos"),
                                                              arg("all_atom_pos_idx"),
@@ -287,33 +344,52 @@ void export_RotamerConstructor(){
                                                              arg("rot_lib"),
                                                              arg("phi") = -1.0472,
                                                              arg("psi") = -0.7854,
+                                                             arg("phi") = false,
+                                                             arg("psi") = false,
                                                              arg("probability_cutoff") = 0.98))
     .def("ConstructRRMRotamerGroup", &WrapRRMGroup_entries_res,(arg("residue"),
                                                                 arg("rotamer_id"),
                                                                 arg("residue_idx"),
                                                                 arg("entries"),
+                                                                arg("phi") = -1.0472,
+                                                                arg("psi") = -0.7854,
+                                                                arg("n_ter") = false,
+                                                                arg("c_ter") = false,
                                                                 arg("probability_cutoff") = 0.98))
     .def("ConstructRRMRotamerGroup", &WrapRRMGroup_entries_aa,(arg("all_atom_pos"),
                                                                arg("all_atom_pos_idx"),
                                                                arg("rotamer_id"),
                                                                arg("residue_idx"),
                                                                arg("entries"),
+                                                               arg("phi") = -1.0472,
+                                                               arg("psi") = -0.7854,
+                                                               arg("n_ter") = false,
+                                                               arg("c_ter") = false,
                                                                arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_entries_res,(arg("residue"),
                                                                 arg("rotamer_id"),
                                                                 arg("residue_idx"),
                                                                 arg("entries"),
+                                                                arg("phi") = -1.0472,
+                                                                arg("psi") = -0.7854,
+                                                                arg("n_ter") = false,
+                                                                arg("c_ter") = false,
                                                                 arg("probability_cutoff") = 0.98))
     .def("ConstructFRMRotamerGroup", &WrapFRMGroup_entries_aa,(arg("all_atom_pos"),
                                                                arg("all_atom_pos_idx"),
                                                                arg("rotamer_id"),
                                                                arg("residue_idx"),
                                                                arg("entries"),
+                                                               arg("phi") = -1.0472,
+                                                               arg("psi") = -0.7854,
+                                                               arg("n_ter") = false,
+                                                               arg("c_ter") = false,
                                                                arg("probability_cutoff") = 0.98))
     .def("ConstructBackboneFrameResidue", &WrapBBFrame_res,(arg("residue"),
                                                             arg("rotamer_id"),
                                                             arg("residue_index"),
                                                             arg("phi") = -1.0472,
+                                                            arg("psi") = -0.7854,
                                                             arg("n_ter")=false,
                                                             arg("c_ter")=false))
     .def("ConstructBackboneFrameResidue", &WrapBBFrame_aa,(arg("all_atom_pos"),
@@ -321,17 +397,38 @@ void export_RotamerConstructor(){
                                                            arg("rotamer_id"),
                                                            arg("residue_index"),
                                                            arg("phi") = -1.0472,
+                                                           arg("psi") = -0.7854,
                                                            arg("n_ter")=false,
                                                            arg("c_ter")=false))
     .def("ConstructSidechainFrameResidue", &WrapSCFrame_res,(arg("residue"),
                                                              arg("rotamer_id"),
-                                                             arg("residue_index")))
+                                                             arg("residue_index"),
+                                                             arg("phi") = -1.0472,
+                                                             arg("psi") = -0.7854,
+                                                             arg("n_ter")=false,
+                                                             arg("c_ter")=false))
     .def("ConstructSidechainFrameResidue", &WrapSCFrame_aa,(arg("all_atom_pos"),
                                                             arg("all_atom_pos_idx"),
                                                             arg("rotamer_id"),
-                                                            arg("residue_index")))
-    .def("AssignInternalEnergies", &AssignInternalEnergiesRRM)
-    .def("AssignInternalEnergies", &AssignInternalEnergiesFRM)
+                                                            arg("residue_index"),
+                                                            arg("phi") = -1.0472,
+                                                            arg("psi") = -0.7854,
+                                                            arg("n_ter")=false,
+                                                            arg("c_ter")=false))
+    .def("AssignInternalEnergies", &AssignInternalEnergiesRRM, (arg("rot_group"),
+                                                                arg("rotamer_id"),
+                                                                arg("residue_index"),
+                                                                arg("phi")=-1.0472,
+                                                                arg("psi")=-0.7854,
+                                                                arg("n_ter")=false,
+                                                                arg("c_ter")=false))
+    .def("AssignInternalEnergies", &AssignInternalEnergiesFRM, (arg("rot_group"),
+                                                                arg("rotamer_id"),
+                                                                arg("residue_index"),
+                                                                arg("phi")=-1.0472,
+                                                                arg("psi")=-0.7854,
+                                                                arg("n_ter")=false,
+                                                                arg("c_ter")=false))
   ;
 
 
diff --git a/sidechain/src/CMakeLists.txt b/sidechain/src/CMakeLists.txt
index ac3b4ed8..953b809a 100644
--- a/sidechain/src/CMakeLists.txt
+++ b/sidechain/src/CMakeLists.txt
@@ -18,6 +18,7 @@ set(SIDECHAIN_HEADERS
   sidechain_connector.hh
   sidechain_object_loader.hh
   rotamer_constructor.hh
+  rotamer_lookup.hh
   scwrl4_rotamer_constructor.hh
   subrotamer_optimizer.hh
 )
@@ -39,6 +40,7 @@ set(SIDECHAIN_SOURCES
   sidechain_connector.cc
   sidechain_object_loader.cc
   rotamer_constructor.cc
+  rotamer_lookup.cc
   scwrl4_rotamer_constructor.cc
   subrotamer_optimizer.cc
 )
diff --git a/sidechain/src/disulfid.cc b/sidechain/src/disulfid.cc
index 5cdb808c..bfa4c682 100644
--- a/sidechain/src/disulfid.cc
+++ b/sidechain/src/disulfid.cc
@@ -433,8 +433,8 @@ void ResolveCysteins(const std::vector<FRMRotamerGroupPtr>& rot_groups,
                      std::vector<std::pair<uint, uint> >& rotamer_indices) {
 
   CysteinResolve<FRMRotamerGroupPtr>(rot_groups, ca_pos, cb_pos,
-                                      disulfid_score_thresh, disulfid_indices,
-                                      rotamer_indices);
+                                     disulfid_score_thresh, disulfid_indices,
+                                     rotamer_indices);
 
   if(optimize_subrotamers) {
 
diff --git a/sidechain/src/rotamer_constructor.cc b/sidechain/src/rotamer_constructor.cc
index 3dfe130f..354e2c4b 100644
--- a/sidechain/src/rotamer_constructor.cc
+++ b/sidechain/src/rotamer_constructor.cc
@@ -14,239 +14,957 @@
 // limitations under the License.
 
 #include <promod3/sidechain/rotamer_constructor.hh>
+#include <promod3/loop/amino_acid_atoms.hh>
+#include <promod3/loop/sidechain_atom_constructor.hh>
 
 
+#include <promod3/sidechain/scwrl4_particle_scoring.hh>
+
 namespace promod3 { namespace sidechain{
 
-RotamerConstructor::RotamerConstructor() {
+RotamerConstructor::RotamerConstructor(bool cb_in_sidechain, 
+                                       RotamerLookupMode mode,
+                                       const RotamerLookupParam& param):
+                                  rotamer_lookup_(cb_in_sidechain, mode, param),
+                                  mode_(mode) {
+
   String s(XXX,'X');
   for(uint i = 0; i < XXX; ++i){
     s[i] = RotIDToOLC(RotamerID(i));
   }
   pos_buffer_ = boost::make_shared<promod3::loop::AllAtomPositions>(s);
+  hydrogen_buffer_ = boost::make_shared<promod3::loop::HydrogenStorage>();
 }
 
-
 // PUBLICLY ACCESSIBLE QUERY FUNCTIONS
 
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, RotamerLibPtr rot_lib, 
-        Real probability_cutoff) {
+        uint residue_idx, RotamerLibPtr rot_lib, Real phi,
+        Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id);
-  this->SetPosBuffer(res, id);
-  return this->ConstructRRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructRRMGroup(lib_entries, probability_cutoff);
 }
 
+
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
-        RotamerLibPtr rot_lib, Real probability_cutoff) {
+        uint aa_res_idx, RotamerID id, uint residue_idx,
+        RotamerLibPtr rot_lib, Real phi, Real psi, bool n_ter, bool c_ter,
+        Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id);
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructRRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructRRMGroup(lib_entries, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, RotamerLibPtr rot_lib, 
-        Real probability_cutoff) {
+        uint residue_idx, RotamerLibPtr rot_lib, Real phi, Real psi,
+        bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id);
-  this->SetPosBuffer(res, id);
-  return this->ConstructFRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructFRMGroup(lib_entries, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
-        RotamerLibPtr rot_lib, Real probability_cutoff) {
+        uint aa_res_idx, RotamerID id, uint residue_idx,
+        RotamerLibPtr rot_lib, Real phi, Real psi, bool n_ter, bool c_ter,
+        Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id);
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructFRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructFRMGroup(lib_entries, probability_cutoff);
 }
 
+
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, BBDepRotamerLibPtr rot_lib, 
-        Real phi, Real psi, Real probability_cutoff) {
+        uint residue_idx, BBDepRotamerLibPtr rot_lib, 
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id, phi, psi);
-  this->SetPosBuffer(res, id);
-  return this->ConstructRRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructRRMGroup(lib_entries, probability_cutoff);
 }
 
+
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
+        uint aa_res_idx, RotamerID id, uint residue_idx,
         BBDepRotamerLibPtr rot_lib, 
-        Real phi, Real psi, Real probability_cutoff) {
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id, phi, psi);
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructRRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructRRMGroup(lib_entries, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, BBDepRotamerLibPtr rot_lib, 
-        Real phi, Real psi, Real probability_cutoff) {
+        uint residue_idx, BBDepRotamerLibPtr rot_lib, 
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id, phi, psi);
-  this->SetPosBuffer(res, id);
-  return this->ConstructFRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructFRMGroup(lib_entries, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
+        uint aa_res_idx, RotamerID id, uint residue_idx,
         BBDepRotamerLibPtr rot_lib, 
-        Real phi, Real psi, Real probability_cutoff) {
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> lib_entries = rot_lib->QueryLib(id, phi, psi);
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructFRMGroup(id, residue_index, lib_entries, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructFRMGroup(lib_entries, probability_cutoff);
 }
 
+
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, 
+        uint residue_idx, 
         std::vector<RotamerLibEntry>& lib_entries, 
-        Real probability_cutoff) {
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> I_LIKE_CHEESE = 
   std::make_pair(&lib_entries[0], lib_entries.size());
-  this->SetPosBuffer(res, id);
-  return this->ConstructRRMGroup(id, residue_index, I_LIKE_CHEESE, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructRRMGroup(I_LIKE_CHEESE, probability_cutoff);
 }
 
+
 RRMRotamerGroupPtr RotamerConstructor::ConstructRRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
+        uint aa_res_idx, RotamerID id, uint residue_idx,
         std::vector<RotamerLibEntry>& lib_entries, 
-        Real probability_cutoff) {
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct RRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> I_LIKE_CHEESE = 
   std::make_pair(&lib_entries[0], lib_entries.size());
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructRRMGroup(id, residue_index, I_LIKE_CHEESE, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructRRMGroup(I_LIKE_CHEESE, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const ost::mol::ResidueHandle& res, RotamerID id,
-        uint residue_index, std::vector<RotamerLibEntry>& lib_entries, 
-        Real probability_cutoff) {
+        uint residue_idx, std::vector<RotamerLibEntry>& lib_entries, 
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> I_LIKE_CHEESE = 
   std::make_pair(&lib_entries[0], lib_entries.size());
-  this->SetPosBuffer(res, id);
-  return this->ConstructFRMGroup(id, residue_index, I_LIKE_CHEESE, 
-                                 probability_cutoff);
+  this->SetPosBuffer(res);
+  return this->ConstructFRMGroup(I_LIKE_CHEESE, probability_cutoff);
 }
 
+
 FRMRotamerGroupPtr RotamerConstructor::ConstructFRMRotamerGroup(
         const promod3::loop::AllAtomPositions& all_atom, 
-        uint aa_res_idx, RotamerID id, uint residue_index,
+        uint aa_res_idx, RotamerID id, uint residue_idx,
         std::vector<RotamerLibEntry>& lib_entries, 
-        Real probability_cutoff) {
+        Real phi, Real psi, bool n_ter, bool c_ter, Real probability_cutoff) {
 
   if(id == XXX) {
     throw promod3::Error("Cannot construct FRMRotamerGroup for unknown "
                          "rotamer id!");
   }
 
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
   std::pair<RotamerLibEntry*,uint> I_LIKE_CHEESE = 
   std::make_pair(&lib_entries[0], lib_entries.size());
-  this->SetPosBuffer(all_atom, aa_res_idx, id);
-  return this->ConstructFRMGroup(id, residue_index, I_LIKE_CHEESE, 
-                                 probability_cutoff);
+  this->SetPosBuffer(all_atom, aa_res_idx);
+  return this->ConstructFRMGroup(I_LIKE_CHEESE, probability_cutoff);
 }
 
-void RotamerConstructor::AssignInternalEnergies(RRMRotamerGroupPtr group) {
+
+FrameResiduePtr RotamerConstructor::ConstructBackboneFrameResidue(
+          const ost::mol::ResidueHandle& res, RotamerID id, uint residue_idx,
+          Real phi, Real psi, bool n_ter, bool c_ter) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructBackboneFrameResidue", 2);
+
+  if(id == XXX) {
+    throw promod3::Error("Cannot construct FrameResidue for unknown "
+                         "rotamer id!");
+  }
+
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
+
+  const RotamerInfo& info = rotamer_lookup_.GetBackboneInfo(id);
+
+  for(uint i = 0; i < info.particles.size(); ++i){
+    if(!info.particles[i].is_hydrogen){
+      ost::mol::AtomHandle a = res.FindAtom(info.particles[i].name);
+      if(!a.IsValid()){
+        throw promod3::Error("Expected atom " + info.particles[i].name + 
+                             " to be present in input residue!");
+      }
+      pos_buffer_->SetPos(id, info.particles[i].atom_idx, a.GetPos());
+    }
+  }
+
+  return this->ConstructBackboneFrameResidue();
+}
+
+
+FrameResiduePtr RotamerConstructor::ConstructBackboneFrameResidue(
+          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
+          RotamerID id, uint residue_idx,
+          Real phi, Real psi, bool n_ter, bool c_ter) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructBackboneFrameResidue", 2);
+
+  if(id == XXX) {
+    throw promod3::Error("Cannot construct FrameResidue for unknown "
+                         "rotamer id!");
+  }
+
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
+
+  const RotamerInfo& info = rotamer_lookup_.GetBackboneInfo(id);
+
+  for(uint i = 0; i < info.particles.size(); ++i){
+    if(!info.particles[i].is_hydrogen){
+
+      if(!all_atom.IsSet(aa_res_idx, info.particles[i].atom_idx)){
+        throw promod3::Error("Expected atom " + info.particles[i].name +
+                             " to be set in all_atom");
+      }
+
+      pos_buffer_->SetPos(id, info.particles[i].atom_idx, 
+                          all_atom.GetPos(aa_res_idx, info.particles[i].atom_idx));
+    }
+  }
+
+  return this->ConstructBackboneFrameResidue();
+}
+
+
+FrameResiduePtr RotamerConstructor::ConstructSidechainFrameResidue(
+        const ost::mol::ResidueHandle& res, RotamerID id, uint residue_idx,
+        Real phi, Real psi, bool n_ter, bool c_ter) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructSidechainFrameResidue", 2);
+
+  if(id == XXX) {
+    throw promod3::Error("Cannot construct FrameResidue for unknown "
+                         "rotamer id!");
+  }
+
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
+
+  const RotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
+
+  for(uint i = 0; i < info.particles.size(); ++i){
+    if(!info.particles[i].is_hydrogen){
+      ost::mol::AtomHandle a = res.FindAtom(info.particles[i].name);
+      if(!a.IsValid()){
+        throw promod3::Error("Expected atom " + info.particles[i].name + 
+                             " to be present in input residue!");
+      }
+      pos_buffer_->SetPos(id, info.particles[i].atom_idx, a.GetPos());
+    }
+  }
+
+  //set bb hydrogen
+  if(info.has_hydrogens){
+    // to construct hydrogens, we might also need backbone atoms in the buffer
+    const RotamerInfo& bb_info = rotamer_lookup_.GetBackboneInfo(id);
+
+    for(uint i = 0; i < bb_info.particles.size(); ++i){
+      if(!bb_info.particles[i].is_hydrogen){
+        ost::mol::AtomHandle a = res.FindAtom(bb_info.particles[i].name);
+        if(!a.IsValid()){
+          throw promod3::Error("Expected atom " + bb_info.particles[i].name + 
+                               " to be present in input residue!");
+        }
+        pos_buffer_->SetPos(id, bb_info.particles[i].atom_idx, a.GetPos());
+      }
+    }
+
+    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, 
+                                      mode_ == POLAR_HYDROGEN_MODE, 
+                                      promod3::loop::PROT_STATE_HISH);
+  }
+
+  int num_particles = info.particles.size();
+  std::vector<Particle> particles(num_particles);
+
+  for(int i = 0; i < num_particles; ++i) {
+    const ParticleInfo& pi = info.particles[i];
+    particles[i].SetName(pi.name);
+    this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+  }
+
+  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
+                                                       residue_idx);
+
+  return p;
+}
+
+
+FrameResiduePtr RotamerConstructor::ConstructSidechainFrameResidue(
+          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
+          RotamerID id, uint residue_idx, Real phi, Real psi, 
+          bool n_ter, bool c_ter) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructSidechainFrameResidue", 2);
+
+  if(id == XXX) {
+    throw promod3::Error("Cannot construct FrameResidue for unknown "
+                         "rotamer id!");
+  }
+
+  id_ = id;
+  residue_idx_ = residue_idx;
+  phi_ = phi;
+  psi_ = psi;
+  n_ter_ = n_ter;
+  c_ter_ = c_ter;
+
+  const RotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
+
+  for(uint i = 0; i < info.particles.size(); ++i){
+    if(!info.particles[i].is_hydrogen){
+      if(!all_atom.IsSet(aa_res_idx, info.particles[i].atom_idx)){
+        throw promod3::Error("Expected atom " + info.particles[i].name +
+                             " to be set in all_atom");
+      }
+      pos_buffer_->SetPos(id, info.particles[i].atom_idx, 
+                          all_atom.GetPos(aa_res_idx, info.particles[i].atom_idx));
+    }
+  }
+
+  //set hydrogens
+  if(info.has_hydrogens){
+    // to construct hydrogens, we might also need backbone atoms in the buffer
+    const RotamerInfo& bb_info = rotamer_lookup_.GetBackboneInfo(id);
+
+    for(uint i = 0; i < bb_info.particles.size(); ++i){
+      if(!bb_info.particles[i].is_hydrogen){
+        if(!all_atom.IsSet(aa_res_idx, bb_info.particles[i].atom_idx)){
+          throw promod3::Error("Expected atom " + bb_info.particles[i].name +
+                               " to be set in all_atom");
+        }
+        pos_buffer_->SetPos(id, bb_info.particles[i].atom_idx, 
+                            all_atom.GetPos(aa_res_idx, bb_info.particles[i].atom_idx));
+      }
+    }
+
+    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, 
+                                      mode_ == POLAR_HYDROGEN_MODE, 
+                                      promod3::loop::PROT_STATE_HISH);
+  }
+
+  int num_particles = info.particles.size();
+  std::vector<Particle> particles(num_particles);
+
+  for(int i = 0; i < num_particles; ++i) {
+    const ParticleInfo& pi = info.particles[i];
+    particles[i].SetName(pi.name);
+    this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+  }
+
+  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
+                                                       residue_idx);
+
+  return p; 
+}
+
+
+void RotamerConstructor::AssignInternalEnergies(RRMRotamerGroupPtr group, 
+                                                RotamerID id,
+                                                uint residue_idx,
+                                                Real phi, Real psi,
+                                                bool n_ter, bool c_ter) {
   for(uint i = 0; i < group->size(); ++i){
     (*group)[i]->SetInternalEnergy(0.0);
   }
 }
 
-void RotamerConstructor::AssignInternalEnergies(FRMRotamerGroupPtr group) {
+
+void RotamerConstructor::AssignInternalEnergies(FRMRotamerGroupPtr group,
+                                                RotamerID id,
+                                                uint residue_idx,
+                                                Real phi, Real psi,
+                                                bool n_ter, bool c_ter) {
   for(uint i = 0; i < group->size(); ++i){
     (*group)[i]->SetInternalEnergy(0.0);
   }
 }
 
-void RotamerConstructor::SetPosBuffer(const ost::mol::ResidueHandle& res,
-                                           RotamerID id) {
+
+RRMRotamerGroupPtr RotamerConstructor::ConstructRRMGroup(
+          std::pair<RotamerLibEntry*,uint> lib_entries, 
+          Real probability_cutoff) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructRRMGroup", 2);
+
+  std::vector<RRMRotamerPtr> rotamers;
+  Real summed_prob = 0.0;
+
+  // in case of his, we have to move the backbone positions in the buffer
+  // to the locations defining his in the different protonation states
+  if(id_ == HIS && mode_ != HEAVY_ATOM_MODE){
+    MVBBPosBuffer(HIS, HSD);
+    MVBBPosBuffer(HIS, HSE);
+  }
+
+  // in case of alanine and glycine, the rotamer libraries won't have any 
+  // entries. For consistency we nevertheless construct rotamers.
+  // We simply add a fake RotamerLibEntry in this case that has
+  // no sidechain dihedrals set. In case of Alanine we might still have
+  // some atoms in (depending on cb_in_sidechain flag)
+  std::vector<RotamerLibEntry> fake_rotamers(1);
+  if(lib_entries.second == 0 && (id_ == ALA || id_ == GLY)) {
+    // we have to make sure, that the according probability really is one!
+    fake_rotamers[0].probability = 1.0;
+    lib_entries = std::make_pair(&fake_rotamers[0], 1);
+  }
+  else if(lib_entries.second == 0) {
+    throw promod3::Error("Did not find any rotamers in Rotamer Library!");
+  }
+
+  for(uint i = 0; i < lib_entries.second; ++i){
+
+    probability_ = lib_entries.first[i].probability;
+    summed_prob += probability_;
+    chi_angles_[0] = lib_entries.first[i].chi1;
+    chi_angles_[1] = lib_entries.first[i].chi2;
+    chi_angles_[2] = lib_entries.first[i].chi3;
+    chi_angles_[3] = lib_entries.first[i].chi4;
+
+    if(mode_ == HEAVY_ATOM_MODE) {
+      rotamers.push_back(ConstructRRM());
+    } else {
+      // in POLAR_HYDROGEN_MODE or FULL_ATOMIC_MODE we're sampling
+      // polar hydrogens of SER/THR/TYR and construct different
+      // rotamers for HIS
+      switch(id_){
+        case HIS:{
+          id_ = HSE;
+          rotamers.push_back(ConstructRRM());
+          id_ = HSD;
+          rotamers.push_back(ConstructRRM());
+          id_ = HIS;
+          break;
+        }
+        case SER:{
+          chi_angles_[1] = Real(M_PI);
+          rotamers.push_back(ConstructRRM());
+          chi_angles_[1] = Real(M_PI) / 3.0;
+          rotamers.push_back(ConstructRRM());
+          chi_angles_[1] = -Real(M_PI) / 3.0;
+          rotamers.push_back(ConstructRRM());
+          break;
+        }
+        case THR:{
+          chi_angles_[1] = Real(M_PI);
+          rotamers.push_back(ConstructRRM());
+          chi_angles_[1] = Real(M_PI) / 3.0;
+          rotamers.push_back(ConstructRRM());
+          chi_angles_[1] = -Real(M_PI) / 3.0;
+          rotamers.push_back(ConstructRRM()); 
+          break;       
+        }
+        case TYR:{
+          chi_angles_[2] = Real(M_PI);
+          rotamers.push_back(ConstructRRM());
+          chi_angles_[2] = Real(0.0);
+          rotamers.push_back(ConstructRRM());
+          break;
+        }
+        default:{
+          rotamers.push_back(ConstructRRM());
+        }
+      }
+    }
+
+    if(summed_prob >= probability_cutoff && !rotamers.empty()) break;
+  } 
+  
+  RRMRotamerGroupPtr group = boost::make_shared<RRMRotamerGroup>(rotamers,
+                                                                 residue_idx_);
+  this->AssignInternalEnergies(group, id_, residue_idx_, phi_, psi_, n_ter_, c_ter_);
+  return group;
+}
+
+
+FRMRotamerGroupPtr RotamerConstructor::ConstructFRMGroup(
+          std::pair<RotamerLibEntry*,uint> lib_entries, 
+          Real probability_cutoff) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructFRMGroup", 2);
+
+  std::vector<FRMRotamerPtr> rotamers;
+  Real summed_prob = 0.0;
+
+  // in case of his, we have to move the backbone positions in the buffer
+  // to the locations defining his in the different protonation states
+  if(id_ == HIS && mode_ != HEAVY_ATOM_MODE){
+    MVBBPosBuffer(HIS, HSD);
+    MVBBPosBuffer(HIS, HSE);
+  }
+
+  // in case of alanine and glycine, the rotamer libraries won't have any 
+  // entries. For consistency we nevertheless construct rotamers.
+  // We simply add a fake RotamerLibEntry in this case that has
+  // no sidechain dihedrals set. In case of Alanine we might still have
+  // some atoms in (depending on cb_in_sidechain flag)
+  std::vector<RotamerLibEntry> fake_rotamers(1);
+  if(lib_entries.second == 0 && (id_ == ALA || id_ == GLY)) {
+    // we have to make sure, that the according probability really is one!
+    fake_rotamers[0].probability = 1.0;
+    lib_entries = std::make_pair(&fake_rotamers[0], 1);
+  }
+  else if(lib_entries.second == 0) {
+    throw promod3::Error("Did not find any rotamers in Rotamer Library!");
+  }
+
+  for(uint i = 0; i < lib_entries.second; ++i){
+    probability_ = lib_entries.first[i].probability;
+    summed_prob += probability_;
+    chi_angles_[0] = lib_entries.first[i].chi1;
+    chi_angles_[1] = lib_entries.first[i].chi2;
+    chi_angles_[2] = lib_entries.first[i].chi3;
+    chi_angles_[3] = lib_entries.first[i].chi4;
+    chi_dev_[0] = lib_entries.first[i].sig1;
+    chi_dev_[1] = lib_entries.first[i].sig2;
+    chi_dev_[2] = lib_entries.first[i].sig3;
+    chi_dev_[3] = lib_entries.first[i].sig4;
+    if(mode_ == HEAVY_ATOM_MODE) {
+      rotamers.push_back(ConstructFRM());
+    } else {
+      switch(id_){
+        case HIS:{
+          id_ = HSE;
+          rotamers.push_back(ConstructFRM());
+          id_ = HSD;
+          rotamers.push_back(ConstructFRM());
+          id_ = HIS;
+          break;
+        }
+        case SER:{
+          chi_dev_[1] = Real(0.17453);
+          chi_angles_[1] = Real(M_PI);
+          rotamers.push_back(ConstructFRM());
+          chi_angles_[1] = Real(M_PI) / Real(3.0);
+          rotamers.push_back(ConstructFRM());
+          chi_angles_[1] = -Real(M_PI) / Real(3.0);
+          rotamers.push_back(ConstructFRM());
+          break;
+        }
+        case THR:{
+          chi_dev_[1] = Real(0.17453);
+          chi_angles_[1] = Real(M_PI);
+          rotamers.push_back(ConstructFRM());
+          chi_angles_[1] = Real(M_PI) / Real(3.0);
+          rotamers.push_back(ConstructFRM());
+          chi_angles_[1] = -Real(M_PI) / Real(3.0);
+          rotamers.push_back(ConstructFRM()); 
+          break;       
+        }
+        case TYR:{
+          chi_dev_[2] = Real(0.17453);
+          chi_angles_[2] = Real(M_PI);
+          rotamers.push_back(ConstructFRM());
+          chi_angles_[2] = Real(0.0);
+          rotamers.push_back(ConstructFRM());
+          break;
+        }
+        default: rotamers.push_back(ConstructFRM());
+      }
+    }
+
+    if(summed_prob >= probability_cutoff && !rotamers.empty()) break;
+  } 
+  
+  FRMRotamerGroupPtr group = boost::make_shared<FRMRotamerGroup>(rotamers,
+                                                                 residue_idx_);
+  this->AssignInternalEnergies(group, id_, residue_idx_, phi_, psi_, n_ter_, c_ter_);
+
+  return group;
+}
+
+
+RRMRotamerPtr RotamerConstructor::ConstructRRM() {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructRRM", 2);
+
+  const RotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id_);
+
+  //set the positions
+  promod3::loop::ConstructSidechainAtoms(*pos_buffer_, id_, chi_angles_[0], 
+                                         chi_angles_[1], chi_angles_[2],
+                                         chi_angles_[3]);
+
+  if(info.has_hydrogens){
+
+    promod3::loop::ConstructHydrogens(*pos_buffer_, id_, *hydrogen_buffer_, 
+                                      mode_ == POLAR_HYDROGEN_MODE, 
+                                      promod3::loop::PROT_STATE_HISH);
+
+    // If there are any custom rules, we apply them now and overrule the
+    // default hydrogen construction
+    if(!info.custom_hydrogens.empty()){
+      for(uint i = 0; i < info.custom_hydrogens.size(); ++i){
+        const CustomHydrogenInfo& h_info = info.custom_hydrogens[i];
+        geom::Vec3 anchor_one, anchor_two, anchor_three, new_h_pos;
+        anchor_one = pos_buffer_->GetPos(id_, h_info.anchor_idx_one);
+        anchor_two = pos_buffer_->GetPos(id_, h_info.anchor_idx_two);
+        anchor_three = pos_buffer_->GetPos(id_, h_info.anchor_idx_three);
+        promod3::core::ConstructAtomPos(anchor_one, anchor_two, anchor_three,
+                                        h_info.bond_length, h_info.angle, 
+                                        chi_angles_[h_info.chi_idx], new_h_pos);
+        hydrogen_buffer_->SetPos(h_info.atom_idx, new_h_pos);
+      }
+    }
+  }
+
+  int num_particles = info.particles.size();
+  std::vector<Particle> particles(num_particles);
+  for(int i = 0; i < num_particles; ++i) {
+    const ParticleInfo& pi = info.particles[i];
+    particles[i].SetName(pi.name);
+    this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+  }
+
+  RRMRotamerPtr rot = boost::make_shared<RRMRotamer>(particles, 
+                                                     probability_, 
+                                                     info.internal_e_prefactor);
+
+  return rot; 
+}
+
+
+FRMRotamerPtr RotamerConstructor::ConstructFRM() {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+          "RotamerConstructor::ConstructFRM", 2);
+
+  const RotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id_);
+
+  //set the positions
+  promod3::loop::ConstructSidechainAtoms(*pos_buffer_, id_, chi_angles_[0], 
+                                         chi_angles_[1], chi_angles_[2],
+                                         chi_angles_[3]);
+  if(info.has_hydrogens){
+    promod3::loop::ConstructHydrogens(*pos_buffer_, id_, *hydrogen_buffer_, 
+                                      mode_ == POLAR_HYDROGEN_MODE, 
+                                      promod3::loop::PROT_STATE_HISH);
+    // If there are any custom rules, we apply them now an overrule the
+    // default hydrogen construction
+    if(!info.custom_hydrogens.empty()){
+      for(uint i = 0; i < info.custom_hydrogens.size(); ++i){
+        const CustomHydrogenInfo& h_info = info.custom_hydrogens[i];
+        geom::Vec3 anchor_one, anchor_two, anchor_three, new_h_pos;
+        anchor_one = pos_buffer_->GetPos(id_, h_info.anchor_idx_one);
+        anchor_two = pos_buffer_->GetPos(id_, h_info.anchor_idx_two);
+        anchor_three = pos_buffer_->GetPos(id_, h_info.anchor_idx_three);
+        promod3::core::ConstructAtomPos(anchor_one, anchor_two, anchor_three,
+                                        h_info.bond_length, h_info.angle, 
+                                        chi_angles_[h_info.chi_idx], new_h_pos);
+        hydrogen_buffer_->SetPos(h_info.atom_idx, new_h_pos);
+      }
+    }
+  }
+
+  int num_rrm_particles = rotamer_lookup_.GetNumSidechainParticles(id_);
+  int num_particles = rotamer_lookup_.GetNumFRMSidechainParticles(id_);
+  std::vector<Particle> particles(num_particles);
+
+  for(int i = 0; i < num_rrm_particles; ++i) {
+    const ParticleInfo& pi = info.particles[i];
+    particles[i].SetName(pi.name);
+    this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+  }
+
+  // Keep track of the subrotamers
+  std::vector<std::vector<int> > subrotamer_definitions;
+  std::vector<int> actual_definition;
+  actual_definition.resize(num_rrm_particles);
+  // Directly add the first particles as first subrotamer
+  for(int i = 0; i < num_rrm_particles; ++i) actual_definition[i] = i;
+  subrotamer_definitions.push_back(actual_definition);
+
+  const std::vector<FRMRule>& frm_rules = rotamer_lookup_.GetFRMRules(id_);
+  geom::Vec3 rot_axis, rot_anchor;
+  geom::Vec3 orig_pos, rot_pos;
+  geom::Mat4 transform;
+  int base_idx = num_rrm_particles;
+
+  for(uint frm_rule_idx = 0; frm_rule_idx < frm_rules.size(); ++frm_rule_idx){
+    const FRMRule& frm_rule = frm_rules[frm_rule_idx];
+    int num_fix_particles = frm_rule.fix_particles.size();
+    int num_rotating_particles = frm_rule.rotating_particles.size();
+
+    // Update the subrotamer definition... all particles that are fixed are 
+    // taken from the first subrotamer.
+    for(int i = 0; i < num_fix_particles; ++i) {
+      actual_definition[i] = frm_rule.fix_particles[i];
+    }
+
+    // The data required for the rotation around the specified axis
+    rot_anchor = pos_buffer_->GetPos(id_, frm_rule.anchor_idx_two);
+    rot_axis = rot_anchor - pos_buffer_->GetPos(id_, frm_rule.anchor_idx_one); 
+
+    // Every rotation results in a new subrotamer
+    for(uint prefac_idx = 0; prefac_idx < frm_rule.prefactors.size(); 
+        ++prefac_idx){
+
+      // Get the rotation matrix
+      Real rot_angle = frm_rule.prefactors[prefac_idx] * chi_dev_[frm_rule_idx];
+      transform = promod3::core::RotationAroundLine(rot_axis, rot_anchor,
+                                                    rot_angle);
+
+      for(int i = 0; i < num_rotating_particles; ++i){
+        int orig_particle_idx = frm_rule.rotating_particles[i];
+        int new_particle_idx = base_idx + i;
+
+        // replace the old with the new index...
+        actual_definition[orig_particle_idx] = new_particle_idx;
+
+        // construct the rotated particle
+        particles[new_particle_idx] = particles[orig_particle_idx];
+        particles[new_particle_idx].ApplyTransform(transform);
+      }
+
+      subrotamer_definitions.push_back(actual_definition);
+
+      // start of next subrotamer
+      base_idx += num_rotating_particles;
+    }
+  }
+
+  FRMRotamerPtr r = boost::make_shared<FRMRotamer>(particles,
+                                                   info.frm_t, probability_,
+                                                   info.internal_e_prefactor);
+
+
+
+  for(uint i = 0; i < subrotamer_definitions.size(); ++i) {
+    r->AddSubrotamerDefinition(subrotamer_definitions[i]);
+  }
+
+  return r;
+}
+
+
+FrameResiduePtr RotamerConstructor::ConstructBackboneFrameResidue() {
+
+  const RotamerInfo& info = rotamer_lookup_.GetBackboneInfo(id_);
+
+  // set hydrogens (also enter if its an n_ter because proline would have no 
+  // hydrogen)
+  if(info.has_hydrogens || n_ter_){
+    if(mode_ == FULL_ATOMIC_MODE) {
+      promod3::loop::ConstructHydrogens(*pos_buffer_, id_, *hydrogen_buffer_,
+                                        mode_ == POLAR_HYDROGEN_MODE,
+                                        promod3::loop::PROT_STATE_HISH);
+    }
+    if(n_ter_) {
+      promod3::loop::ConstructHydrogenNTerminal(*pos_buffer_, id_, 
+                                                *hydrogen_buffer_);
+    } else {
+      promod3::loop::ConstructHydrogenN(*pos_buffer_, id_, phi_, 
+                                        *hydrogen_buffer_); 
+    }
+  }
+  if(c_ter_) {
+    promod3::core::ConstructCTerminalOxygens(
+                            pos_buffer_->GetPos(id_, promod3::loop::BB_C_INDEX),
+                            pos_buffer_->GetPos(id_, promod3::loop::BB_CA_INDEX),
+                            pos_buffer_->GetPos(id_, promod3::loop::BB_N_INDEX),
+                            terminal_o_pos_, terminal_oxt_pos_); 
+  } 
+  std::vector<Particle> particles;
+  if(n_ter_ || c_ter_) {
+    RotamerInfo terminal_info = 
+    rotamer_lookup_.GetTerminalBackboneInfo(id_, n_ter_, c_ter_);
+    int num_particles = terminal_info.particles.size();
+    particles.resize(num_particles);
+    for(int i = 0; i < num_particles; ++i) {
+      ParticleInfo& pi = terminal_info.particles[i];
+      particles[i].SetName(pi.name);
+      this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+    }
+  } else {
+    int num_particles = info.particles.size();
+    particles.resize(num_particles);
+    for(int i = 0; i < num_particles; ++i) {
+      const ParticleInfo& pi = info.particles[i];
+      particles[i].SetName(pi.name);
+      this->ParametrizeParticle(pi.atom_idx, pi.is_hydrogen, particles[i]);
+    }    
+  }
+
+  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, residue_idx_);
+  return p; 
+}
+
+
+void RotamerConstructor::SetPosBuffer(const ost::mol::ResidueHandle& res) {
 
   core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::SetPosBuffer_residue", 2);
+          "RotamerConstructor::SetPosBuffer_residue", 2);
 
   ost::mol::AtomHandle n = res.FindAtom("N");
   ost::mol::AtomHandle ca = res.FindAtom("CA");
@@ -259,25 +977,26 @@ void RotamerConstructor::SetPosBuffer(const ost::mol::ResidueHandle& res,
                          "rotamer!");
   }
 
-  pos_buffer_->SetPos(id, promod3::loop::BB_N_INDEX, n.GetPos());
-  pos_buffer_->SetPos(id, promod3::loop::BB_CA_INDEX, ca.GetPos());
-  pos_buffer_->SetPos(id, promod3::loop::BB_C_INDEX, c.GetPos());
-  pos_buffer_->SetPos(id, promod3::loop::BB_O_INDEX, o.GetPos());
+  pos_buffer_->SetPos(id_, promod3::loop::BB_N_INDEX, n.GetPos());
+  pos_buffer_->SetPos(id_, promod3::loop::BB_CA_INDEX, ca.GetPos());
+  pos_buffer_->SetPos(id_, promod3::loop::BB_C_INDEX, c.GetPos());
+  pos_buffer_->SetPos(id_, promod3::loop::BB_O_INDEX, o.GetPos());
 
-  if(id != GLY) {
+  if(id_ != GLY) {
     if(!cb.IsValid()) {
       throw promod3::Error("All backbone atoms must be valid to construct "
                            "rotamer!");
     }
-    pos_buffer_->SetPos(id, promod3::loop::BB_CB_INDEX, cb.GetPos());
+    pos_buffer_->SetPos(id_, promod3::loop::BB_CB_INDEX, cb.GetPos());
   }
 }
 
+
 void RotamerConstructor::SetPosBuffer(const promod3::loop::AllAtomPositions& all_atom_pos,
-                                           uint all_atom_idx, RotamerID id) {
+                                      uint all_atom_idx) {
 
   core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::SetPosBuffer_all_atom_pos", 2);
+          "RotamerConstructor::SetPosBuffer_all_atom_pos", 2);
 
 
   if(!(all_atom_pos.IsSet(all_atom_idx, promod3::loop::BB_N_INDEX) &&
@@ -288,29 +1007,45 @@ void RotamerConstructor::SetPosBuffer(const promod3::loop::AllAtomPositions& all
                          "rotamer!");
   }
 
-  pos_buffer_->SetPos(id, promod3::loop::BB_N_INDEX, 
+  pos_buffer_->SetPos(id_, promod3::loop::BB_N_INDEX, 
                       all_atom_pos.GetPos(all_atom_idx, 
                                           promod3::loop::BB_N_INDEX));
-  pos_buffer_->SetPos(id, promod3::loop::BB_CA_INDEX, 
+  pos_buffer_->SetPos(id_, promod3::loop::BB_CA_INDEX, 
                       all_atom_pos.GetPos(all_atom_idx, 
                                           promod3::loop::BB_CA_INDEX));
-  pos_buffer_->SetPos(id, promod3::loop::BB_C_INDEX, 
+  pos_buffer_->SetPos(id_, promod3::loop::BB_C_INDEX, 
                       all_atom_pos.GetPos(all_atom_idx, 
                                           promod3::loop::BB_C_INDEX));
-  pos_buffer_->SetPos(id, promod3::loop::BB_O_INDEX, 
+  pos_buffer_->SetPos(id_, promod3::loop::BB_O_INDEX, 
                       all_atom_pos.GetPos(all_atom_idx, 
                                           promod3::loop::BB_O_INDEX));  
 
-  if(id != GLY) {
+  if(id_ != GLY) {
     if(!all_atom_pos.IsSet(all_atom_idx, promod3::loop::BB_CB_INDEX)) {
       throw promod3::Error("All backbone atoms must be valid to construct "
                            "rotamer!");
     }
-    pos_buffer_->SetPos(id, promod3::loop::BB_CB_INDEX, 
+    pos_buffer_->SetPos(id_, promod3::loop::BB_CB_INDEX, 
                         all_atom_pos.GetPos(all_atom_idx, 
                                             promod3::loop::BB_CB_INDEX));
-
   }
 }
 
+
+void RotamerConstructor::MVBBPosBuffer(RotamerID from, RotamerID to) {
+  pos_buffer_->SetPos(to, promod3::loop::BB_N_INDEX, 
+                      pos_buffer_->GetPos(from, promod3::loop::BB_N_INDEX));
+  pos_buffer_->SetPos(to, promod3::loop::BB_CA_INDEX, 
+                      pos_buffer_->GetPos(from, promod3::loop::BB_CA_INDEX));
+  pos_buffer_->SetPos(to, promod3::loop::BB_C_INDEX, 
+                      pos_buffer_->GetPos(from, promod3::loop::BB_C_INDEX));
+  pos_buffer_->SetPos(to, promod3::loop::BB_O_INDEX, 
+                      pos_buffer_->GetPos(from, promod3::loop::BB_O_INDEX));
+  // Even though we officially count CB as a sidechain atom, we still move it
+  // since its completely independent of any sidechain dihedral angle and
+  // cannot be constructed anyway
+  pos_buffer_->SetPos(to, promod3::loop::BB_CB_INDEX, 
+                      pos_buffer_->GetPos(from, promod3::loop::BB_CB_INDEX));
+}
+
 }} // ns
diff --git a/sidechain/src/rotamer_constructor.hh b/sidechain/src/rotamer_constructor.hh
index 4a496ef0..759d49d4 100644
--- a/sidechain/src/rotamer_constructor.hh
+++ b/sidechain/src/rotamer_constructor.hh
@@ -27,18 +27,22 @@
 #include <promod3/sidechain/frame.hh>
 #include <promod3/sidechain/rotamer_lib.hh>
 #include <promod3/sidechain/bb_dep_rotamer_lib.hh>
+#include <promod3/sidechain/rotamer_lookup.hh>
 
 
 namespace promod3 { namespace sidechain {
 
+
 class RotamerConstructor;
 typedef boost::shared_ptr<RotamerConstructor> RotamerConstructorPtr;
 
+
 class RotamerConstructor {
 
 public:
 
-  RotamerConstructor();
+  RotamerConstructor(bool cb_in_sidechain, RotamerLookupMode mode,
+                     const RotamerLookupParam& param = RotamerLookupParam());
 
   virtual ~RotamerConstructor() { }
 
@@ -46,23 +50,39 @@ public:
   RRMRotamerGroupPtr ConstructRRMRotamerGroup(
                   const ost::mol::ResidueHandle& res, RotamerID id,
                   uint residue_index, RotamerLibPtr rot_lib, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   RRMRotamerGroupPtr ConstructRRMRotamerGroup(
                   const promod3::loop::AllAtomPositions& all_atom, 
                   uint aa_res_idx, RotamerID id, uint residue_index,
                   RotamerLibPtr rot_lib, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
   
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
                   const ost::mol::ResidueHandle& res, RotamerID id,
-                  uint residue_index, RotamerLibPtr rot_lib, 
+                  uint residue_index, RotamerLibPtr rot_lib,
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false, 
                   Real probability_cutoff = 0.98);
 
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
                   const promod3::loop::AllAtomPositions& all_atom, 
                   uint aa_res_idx, RotamerID id, uint residue_index,
-                  RotamerLibPtr rot_lib, 
+                  RotamerLibPtr rot_lib,
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854, 
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   // Construct rotamer groups from backbone dependent library
@@ -71,6 +91,8 @@ public:
                   uint residue_index, BBDepRotamerLibPtr rot_lib, 
                   Real phi = -1.0472, 
                   Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   RRMRotamerGroupPtr ConstructRRMRotamerGroup(
@@ -79,6 +101,8 @@ public:
                   BBDepRotamerLibPtr rot_lib, 
                   Real phi = -1.0472, 
                   Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
   
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
@@ -86,6 +110,8 @@ public:
                   uint residue_index, BBDepRotamerLibPtr rot_lib, 
                   Real phi = -1.0472, 
                   Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
@@ -94,6 +120,8 @@ public:
                   BBDepRotamerLibPtr rot_lib, 
                   Real phi = -1.0472, 
                   Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   // Construct rotamer groups directly from rotamerlib entries
@@ -101,75 +129,148 @@ public:
                   const ost::mol::ResidueHandle& res, RotamerID id,
                   uint residue_index, 
                   std::vector<RotamerLibEntry>& lib_entries, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   RRMRotamerGroupPtr ConstructRRMRotamerGroup(
                   const promod3::loop::AllAtomPositions& all_atom, 
                   uint aa_res_idx, RotamerID id, uint residue_index,
                   std::vector<RotamerLibEntry>& lib_entries, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
   
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
                   const ost::mol::ResidueHandle& res, RotamerID id,
                   uint residue_index,
                   std::vector<RotamerLibEntry>& lib_entries, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   FRMRotamerGroupPtr ConstructFRMRotamerGroup(
                   const promod3::loop::AllAtomPositions& all_atom, 
                   uint aa_res_idx, RotamerID id, uint residue_index,
                   std::vector<RotamerLibEntry>& lib_entries, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false,
                   Real probability_cutoff = 0.98);
 
   // Construct frame residues
-  virtual FrameResiduePtr ConstructBackboneFrameResidue(
+  FrameResiduePtr ConstructBackboneFrameResidue(
                   const ost::mol::ResidueHandle& res, RotamerID id, 
-                  uint residue_index, Real phi, bool n_ter = false,
-                  bool c_ter = false) = 0;
+                  uint residue_index, 
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false);
 
-  virtual FrameResiduePtr ConstructBackboneFrameResidue(
+  FrameResiduePtr ConstructBackboneFrameResidue(
                   const promod3::loop::AllAtomPositions& all_atom, 
                   uint aa_res_idx, RotamerID id, uint residue_index,
-                  Real phi = -1.0472, bool n_ter = false,
-                  bool c_ter = false) = 0;
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false);
   
-  virtual FrameResiduePtr ConstructSidechainFrameResidue(
+  FrameResiduePtr ConstructSidechainFrameResidue(
                   const ost::mol::ResidueHandle& res, RotamerID id, 
-                  uint residue_index) = 0;
+                  uint residue_index,
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false);
   
-  virtual FrameResiduePtr ConstructSidechainFrameResidue(
+  FrameResiduePtr ConstructSidechainFrameResidue(
                   const promod3::loop::AllAtomPositions& all_atom, 
-                  uint aa_res_idx, RotamerID id, uint residue_index) = 0;
+                  uint aa_res_idx, RotamerID id, uint residue_index,
+                  Real phi = -1.0472, 
+                  Real psi =  -0.7854,
+                  bool n_ter = false,
+                  bool c_ter = false);
 
   // Assign internal energies to rotamer groups
-  virtual void AssignInternalEnergies(RRMRotamerGroupPtr group);
+  // This implementation just sets the internal energy of every rotamer to 0.0
+  // Implement this function in the child class
+  virtual void AssignInternalEnergies(RRMRotamerGroupPtr group,
+                                      RotamerID id,
+                                      uint residue_index,
+                                      Real phi = -1.0472, 
+                                      Real psi =  -0.7854,
+                                      bool n_ter = false,
+                                      bool c_ter = false);
 
-  virtual void AssignInternalEnergies(FRMRotamerGroupPtr group);
+  virtual void AssignInternalEnergies(FRMRotamerGroupPtr group,
+                                      RotamerID id,
+                                      uint residue_index,
+                                      Real phi = -1.0472, 
+                                      Real psi =  -0.7854,
+                                      bool n_ter = false,
+                                      bool c_ter = false);
 
 protected:
 
-  // Construct the rotamer groups after all backbone position information has 
-  // been set into the internal positin buffer objects
-  virtual RRMRotamerGroupPtr ConstructRRMGroup(
-              RotamerID id, uint residue_index, 
-              std::pair<RotamerLibEntry*,uint> lib_entries, 
-              Real probability_cutoff) = 0;
-
-  virtual FRMRotamerGroupPtr ConstructFRMGroup(
-              RotamerID id, uint residue_index, 
-              std::pair<RotamerLibEntry*,uint> lib_entries, 
-              Real probability_cutoff) = 0;
+  // Function that must be implemented by child class
+  // there are two special cases that have to be treatet separately:
+  // the terminal oxygens.
+  // atom_idx for terminal O is set to -1
+  // atom_idx for terminal OXT is set to -2
+  virtual void ParametrizeParticle(int atom_idx, bool is_hydrogen, 
+                                   Particle& p) = 0;
 
+  // information that is available to the child class in order to parametrize
+  // the given particle
   promod3::loop::AllAtomPositionsPtr pos_buffer_;
+  promod3::loop::HydrogenStoragePtr hydrogen_buffer_;
+  geom::Vec3 terminal_o_pos_;
+  geom::Vec3 terminal_oxt_pos_;
+  RotamerID id_;
+  uint residue_idx_;
+  Real phi_;
+  Real psi_;
+  bool n_ter_;
+  bool c_ter_;
 
 private:
 
+  // Construct the rotamer groups after all backbone position information has 
+  // been set into the internal position buffer objects
+  virtual RRMRotamerGroupPtr ConstructRRMGroup( 
+              std::pair<RotamerLibEntry*,uint> lib_entries,
+              Real probability_cutoff);
+
+  virtual FRMRotamerGroupPtr ConstructFRMGroup(
+              std::pair<RotamerLibEntry*,uint> lib_entries,
+              Real probability_cutoff);
+
+  // assumes positions / probabilities, chi angles and chi deviations 
+  // to be set in buffer
+  RRMRotamerPtr ConstructRRM();
+  FRMRotamerPtr ConstructFRM();
+  FrameResiduePtr ConstructBackboneFrameResidue();
+
   // helpers
-  void SetPosBuffer(const ost::mol::ResidueHandle& res,
-                    RotamerID id);
+  void SetPosBuffer(const ost::mol::ResidueHandle& res);
 
   void SetPosBuffer(const promod3::loop::AllAtomPositions&,
-                    uint aa_res_index, RotamerID id);
+                    uint aa_res_index);
+
+  void MVBBPosBuffer(RotamerID from, RotamerID to);
+
+  RotamerLookup rotamer_lookup_;
+  RotamerLookupMode mode_;
+  Real chi_angles_[4];
+  Real chi_dev_[4];
+  Real probability_;
 };
 
 }} // ns
diff --git a/sidechain/src/rotamer_lookup.cc b/sidechain/src/rotamer_lookup.cc
new file mode 100644
index 00000000..6ca63be5
--- /dev/null
+++ b/sidechain/src/rotamer_lookup.cc
@@ -0,0 +1,2140 @@
+// Copyright (c) 2013-2018, SIB - Swiss Institute of Bioinformatics and 
+//                          Biozentrum - University of Basel
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//   http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <promod3/sidechain/rotamer_lookup.hh>
+#include <promod3/core/runtime_profiling.hh>
+
+namespace promod3 { namespace sidechain{
+
+RotamerLookup::RotamerLookup(bool cb_in_sidechain, RotamerLookupMode mode,
+                             const RotamerLookupParam& param): mode_(mode) {
+
+  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
+                                "RotamerLookup::RotamerLookup", 2);
+
+  // ARG
+  sidechain_infos_[ARG].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[ARG].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::ARG];
+  sidechain_infos_[ARG].frm_t = param.frm_t[ost::conop::ARG];
+
+  AddInfo(ARG, "CG", promod3::loop::ARG_CG_INDEX, false);
+  AddInfo(ARG, "CD", promod3::loop::ARG_CD_INDEX, false);
+  AddInfo(ARG, "NE", promod3::loop::ARG_NE_INDEX, false);
+  AddInfo(ARG, "CZ", promod3::loop::ARG_CZ_INDEX, false);
+  AddInfo(ARG, "NH1", promod3::loop::ARG_NH1_INDEX, false);
+  AddInfo(ARG, "NH2", promod3::loop::ARG_NH2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(ARG, "HE", promod3::loop::ARG_HE_INDEX, true);
+    AddInfo(ARG, "HH11", promod3::loop::ARG_HH11_INDEX, true);
+    AddInfo(ARG, "HH12", promod3::loop::ARG_HH12_INDEX, true);
+    AddInfo(ARG, "HH21", promod3::loop::ARG_HH21_INDEX, true);
+    AddInfo(ARG, "HH22", promod3::loop::ARG_HH22_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(ARG, "HB2", promod3::loop::ARG_HB2_INDEX, true);
+    AddInfo(ARG, "HB3", promod3::loop::ARG_HB3_INDEX, true);
+    AddInfo(ARG, "HG2", promod3::loop::ARG_HG2_INDEX, true);
+    AddInfo(ARG, "HG3", promod3::loop::ARG_HG3_INDEX, true);
+    AddInfo(ARG, "HD2", promod3::loop::ARG_HD2_INDEX, true);
+    AddInfo(ARG, "HD3", promod3::loop::ARG_HB3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(ARG, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(ARG, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.ARG_CA_CB_prefactors);
+  AddFRMRotatingParticle(ARG, 0, 0); // CG
+  AddFRMRotatingParticle(ARG, 0, 1); // CD
+  AddFRMRotatingParticle(ARG, 0, 2); // NE
+  AddFRMRotatingParticle(ARG, 0, 3); // CZ
+  AddFRMRotatingParticle(ARG, 0, 4); // NH1
+  AddFRMRotatingParticle(ARG, 0, 5); // NH2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ARG, 0, 6); // HE
+    AddFRMRotatingParticle(ARG, 0, 7); // HH11
+    AddFRMRotatingParticle(ARG, 0, 8); // HH12
+    AddFRMRotatingParticle(ARG, 0, 9); // HH21
+    AddFRMRotatingParticle(ARG, 0, 10); // HH22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ARG, 0, 11); // HB2
+    AddFRMRotatingParticle(ARG, 0, 12); // HB3
+    AddFRMRotatingParticle(ARG, 0, 13); // HG2
+    AddFRMRotatingParticle(ARG, 0, 14); // HG3
+    AddFRMRotatingParticle(ARG, 0, 15);  // HD2
+    AddFRMRotatingParticle(ARG, 0, 16);  // HD3
+  }
+
+  AddFRMRule(ARG, promod3::loop::BB_CB_INDEX, promod3::loop::ARG_CG_INDEX,
+             param.ARG_CB_CG_prefactors);
+  AddFRMFixParticle(ARG, 1, 0); // CG
+  AddFRMRotatingParticle(ARG, 1, 1); // CD
+  AddFRMRotatingParticle(ARG, 1, 2); // NE
+  AddFRMRotatingParticle(ARG, 1, 3); // CZ
+  AddFRMRotatingParticle(ARG, 1, 4); // NH1
+  AddFRMRotatingParticle(ARG, 1, 5); // NH2
+  
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ARG, 1, 6); // HE
+    AddFRMRotatingParticle(ARG, 1, 7); // HH11
+    AddFRMRotatingParticle(ARG, 1, 8); // HH12
+    AddFRMRotatingParticle(ARG, 1, 9); // HH21
+    AddFRMRotatingParticle(ARG, 1, 10); // HH22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ARG, 1, 11); // HB2
+    AddFRMFixParticle(ARG, 1, 12); // HB3
+    AddFRMRotatingParticle(ARG, 1, 13); // HG2
+    AddFRMRotatingParticle(ARG, 1, 14); // HG3
+    AddFRMRotatingParticle(ARG, 1, 15);  // HD2
+    AddFRMRotatingParticle(ARG, 1, 16);  // HD3
+  }
+
+  AddFRMRule(ARG, promod3::loop::ARG_CG_INDEX, promod3::loop::ARG_CD_INDEX,
+             param.ARG_CG_CD_prefactors);
+  AddFRMFixParticle(ARG, 2, 0); // CG
+  AddFRMFixParticle(ARG, 2, 1); // CD
+  AddFRMRotatingParticle(ARG, 2, 2); // NE
+  AddFRMRotatingParticle(ARG, 2, 3); // CZ
+  AddFRMRotatingParticle(ARG, 2, 4); // NH1
+  AddFRMRotatingParticle(ARG, 2, 5); // NH2
+  
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ARG, 2, 6); // HE
+    AddFRMRotatingParticle(ARG, 2, 7); // HH11
+    AddFRMRotatingParticle(ARG, 2, 8); // HH12
+    AddFRMRotatingParticle(ARG, 2, 9); // HH21
+    AddFRMRotatingParticle(ARG, 2, 10); // HH22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ARG, 2, 11); // HB2
+    AddFRMFixParticle(ARG, 2, 12); // HB3
+    AddFRMFixParticle(ARG, 2, 13); // HG2
+    AddFRMFixParticle(ARG, 2, 14); // HG3
+    AddFRMRotatingParticle(ARG, 2, 15);  // HD2
+    AddFRMRotatingParticle(ARG, 2, 16);  // HD3
+  }
+
+
+  AddFRMRule(ARG, promod3::loop::ARG_CD_INDEX, promod3::loop::ARG_NE_INDEX,
+             param.ARG_CD_NE_prefactors);
+  AddFRMFixParticle(ARG, 3, 0); // CG
+  AddFRMFixParticle(ARG, 3, 1); // CD
+  AddFRMFixParticle(ARG, 3, 2); // NE
+  AddFRMRotatingParticle(ARG, 3, 3); // CZ
+  AddFRMRotatingParticle(ARG, 3, 4); // NH1
+  AddFRMRotatingParticle(ARG, 3, 5); // NH2
+  
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ARG, 3, 6); // HE
+    AddFRMRotatingParticle(ARG, 3, 7); // HH11
+    AddFRMRotatingParticle(ARG, 3, 8); // HH12
+    AddFRMRotatingParticle(ARG, 3, 9); // HH21
+    AddFRMRotatingParticle(ARG, 3, 10); // HH22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ARG, 3, 11); // HB2
+    AddFRMFixParticle(ARG, 3, 12); // HB3
+    AddFRMFixParticle(ARG, 3, 13); // HG2
+    AddFRMFixParticle(ARG, 3, 14); // HG3
+    AddFRMFixParticle(ARG, 3, 15);  // HD2
+    AddFRMFixParticle(ARG, 3, 16);  // HD3
+  }
+
+
+  if(cb_in_sidechain) {
+    int cb_idx = 6;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 11;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 17;
+    }
+    AddFRMFixParticle(ARG, 0, cb_idx);
+    AddFRMFixParticle(ARG, 1, cb_idx);
+    AddFRMFixParticle(ARG, 2, cb_idx);
+    AddFRMFixParticle(ARG, 3, cb_idx);
+  }
+
+  backbone_infos_[ARG].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(ARG, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(ARG, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(ARG, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(ARG, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ARG, "H", promod3::loop::ARG_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ARG, "HA", promod3::loop::ARG_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(ARG, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // ASN
+  sidechain_infos_[ASN].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[ASN].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::ASN];
+  sidechain_infos_[ASN].frm_t = param.frm_t[ost::conop::ASN];
+
+  AddInfo(ASN, "CG", promod3::loop::ASN_CG_INDEX, false);
+  AddInfo(ASN, "OD1", promod3::loop::ASN_OD1_INDEX, false);
+  AddInfo(ASN, "ND2", promod3::loop::ASN_ND2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(ASN, "HD21", promod3::loop::ASN_HD21_INDEX, true);
+    AddInfo(ASN, "HD22", promod3::loop::ASN_HD22_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(ASN, "HB2", promod3::loop::ASN_HB2_INDEX, true);
+    AddInfo(ASN, "HB3", promod3::loop::ASN_HB3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(ASN, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(ASN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.ASN_CA_CB_prefactors);
+  AddFRMRotatingParticle(ASN, 0, 0); // CG
+  AddFRMRotatingParticle(ASN, 0, 1); // OD1
+  AddFRMRotatingParticle(ASN, 0, 2); // ND2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ASN, 0, 3); // HD21
+    AddFRMRotatingParticle(ASN, 0, 4); // HD22    
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ASN, 0, 5); // HB2
+    AddFRMRotatingParticle(ASN, 0, 6); // HB3       
+  }
+
+  AddFRMRule(ASN, promod3::loop::BB_CB_INDEX, promod3::loop::ASN_CG_INDEX,
+             param.ASN_CB_CG_prefactors);
+  AddFRMFixParticle(ASN, 1, 0); // CG
+  AddFRMRotatingParticle(ASN, 1, 1); // OD1
+  AddFRMRotatingParticle(ASN, 1, 2); // ND2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ASN, 1, 3); // HD21
+    AddFRMRotatingParticle(ASN, 1, 4); // HD22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ASN, 1, 5); // HB2
+    AddFRMFixParticle(ASN, 1, 6); // HB3
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 3;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 5;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 7;
+    }
+    AddFRMFixParticle(ASN, 0, cb_idx);
+    AddFRMFixParticle(ASN, 1, cb_idx);
+  }
+
+
+  backbone_infos_[ASN].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(ASN, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(ASN, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(ASN, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(ASN, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ASN, "H", promod3::loop::ASN_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ASN, "HA", promod3::loop::ASN_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(ASN, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // ASP
+  sidechain_infos_[ASP].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[ASP].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::ASP];
+  sidechain_infos_[ASP].frm_t = param.frm_t[ost::conop::ASP];
+
+  AddInfo(ASP, "CG", promod3::loop::ASP_CG_INDEX, false);
+  AddInfo(ASP, "OD1", promod3::loop::ASP_OD1_INDEX, false);
+  AddInfo(ASP, "OD2", promod3::loop::ASP_OD2_INDEX, false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(ASP, "HB2", promod3::loop::ASP_HB2_INDEX, true);
+    AddInfo(ASP, "HB3", promod3::loop::ASP_HB3_INDEX, true);     
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(ASP, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(ASP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.ASP_CA_CB_prefactors);
+  AddFRMRotatingParticle(ASP, 0, 0); // CG
+  AddFRMRotatingParticle(ASP, 0, 1); // OD1
+  AddFRMRotatingParticle(ASP, 0, 2); // OD2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ASP, 0, 3); // HB2
+    AddFRMRotatingParticle(ASP, 0, 4); // HB3           
+  }
+
+  AddFRMRule(ASP, promod3::loop::BB_CB_INDEX, promod3::loop::ASP_CG_INDEX,
+             param.ASP_CB_CG_prefactors);
+  AddFRMFixParticle(ASP, 1, 0); // CG
+  AddFRMRotatingParticle(ASP, 1, 1); // OD1
+  AddFRMRotatingParticle(ASP, 1, 2); // OD2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ASP, 1, 3); // HB2
+    AddFRMFixParticle(ASP, 1, 4); // HB3                 
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 3;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 5;
+    }
+    AddFRMFixParticle(ASP, 0, cb_idx);
+    AddFRMFixParticle(ASP, 1, cb_idx);
+  }
+
+  backbone_infos_[ASP].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(ASP, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(ASP, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(ASP, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(ASP, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ASP, "H", promod3::loop::ASP_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ASP, "HA", promod3::loop::ASP_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(ASP, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // GLN
+  sidechain_infos_[GLN].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[GLN].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::GLN];
+  sidechain_infos_[GLN].frm_t = param.frm_t[ost::conop::GLN];
+
+  AddInfo(GLN, "CG", promod3::loop::GLN_CG_INDEX, false);
+  AddInfo(GLN, "CD", promod3::loop::GLN_CD_INDEX, false);
+  AddInfo(GLN, "OE1", promod3::loop::GLN_OE1_INDEX, false);
+  AddInfo(GLN, "NE2", promod3::loop::GLN_NE2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(GLN, "HE21", promod3::loop::GLN_HE21_INDEX, true);
+    AddInfo(GLN, "HE22", promod3::loop::GLN_HE22_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(GLN, "HB2", promod3::loop::GLN_HB2_INDEX, true);
+    AddInfo(GLN, "HB3", promod3::loop::GLN_HB3_INDEX, true);
+    AddInfo(GLN, "HG2", promod3::loop::GLN_HG2_INDEX, true);
+    AddInfo(GLN, "HG3", promod3::loop::GLN_HG3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(GLN, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(GLN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.GLN_CA_CB_prefactors);
+  AddFRMRotatingParticle(GLN, 0, 0); // CG
+  AddFRMRotatingParticle(GLN, 0, 1); // CD
+  AddFRMRotatingParticle(GLN, 0, 2); // OE1
+  AddFRMRotatingParticle(GLN, 0, 3); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(GLN, 0, 4); // HE21
+    AddFRMRotatingParticle(GLN, 0, 5); // HE22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(GLN, 0, 6); // HB2
+    AddFRMRotatingParticle(GLN, 0, 7); // HB3
+    AddFRMRotatingParticle(GLN, 0, 8); // HG2
+    AddFRMRotatingParticle(GLN, 0, 9); // HG3
+  }
+
+  AddFRMRule(GLN, promod3::loop::BB_CB_INDEX, promod3::loop::GLN_CG_INDEX,
+             param.GLN_CB_CG_prefactors);
+  AddFRMFixParticle(GLN, 1, 0); // CG
+  AddFRMRotatingParticle(GLN, 1, 1); // CD
+  AddFRMRotatingParticle(GLN, 1, 2); // OE1
+  AddFRMRotatingParticle(GLN, 1, 3); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(GLN, 1, 4); // HE21
+    AddFRMRotatingParticle(GLN, 1, 5); // HE22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(GLN, 1, 6); // HB2
+    AddFRMFixParticle(GLN, 1, 7); // HB3
+    AddFRMRotatingParticle(GLN, 1, 8); // HG2
+    AddFRMRotatingParticle(GLN, 1, 9); // HG3
+  }
+
+  AddFRMRule(GLN, promod3::loop::GLN_CG_INDEX, promod3::loop::GLN_CD_INDEX,
+             param.GLN_CG_CD_prefactors);
+  AddFRMFixParticle(GLN, 2, 0); // CG
+  AddFRMFixParticle(GLN, 2, 1); // CD
+  AddFRMRotatingParticle(GLN, 2, 2); // OE1
+  AddFRMRotatingParticle(GLN, 2, 3); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(GLN, 2, 4); // HE21
+    AddFRMRotatingParticle(GLN, 2, 5); // HE22
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(GLN, 2, 6); // HB2
+    AddFRMFixParticle(GLN, 2, 7); // HB3
+    AddFRMFixParticle(GLN, 2, 8); // HG2
+    AddFRMFixParticle(GLN, 2, 9); // HG3      
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 4;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 6;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 10;
+    }
+    AddFRMFixParticle(GLN, 0, cb_idx);
+    AddFRMFixParticle(GLN, 1, cb_idx);
+    AddFRMFixParticle(GLN, 2, cb_idx);
+  }
+
+
+  backbone_infos_[GLN].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+
+  AddBBInfo(GLN, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(GLN, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(GLN, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(GLN, "O", promod3::loop::BB_O_INDEX, false);
+
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLN, "H", promod3::loop::GLN_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLN, "HA", promod3::loop::GLN_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(GLN, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // GLU
+  sidechain_infos_[GLU].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[GLU].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::GLU];
+  sidechain_infos_[GLU].frm_t = param.frm_t[ost::conop::GLU];
+
+  AddInfo(GLU, "CG", promod3::loop::GLU_CG_INDEX, false);
+  AddInfo(GLU, "CD", promod3::loop::GLU_CD_INDEX, false);
+  AddInfo(GLU, "OE1", promod3::loop::GLU_OE1_INDEX, false);
+  AddInfo(GLU, "OE2", promod3::loop::GLU_OE2_INDEX, false);
+
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(GLU, "HB2", promod3::loop::GLU_HB2_INDEX, true);
+    AddInfo(GLU, "HB3", promod3::loop::GLU_HB3_INDEX, true);
+    AddInfo(GLU, "HG2", promod3::loop::GLU_HG2_INDEX, true);
+    AddInfo(GLU, "HG3", promod3::loop::GLU_HG3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(GLU, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(GLU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.GLU_CA_CB_prefactors);
+  AddFRMRotatingParticle(GLU, 0, 0); // CG
+  AddFRMRotatingParticle(GLU, 0, 1); // CD
+  AddFRMRotatingParticle(GLU, 0, 2); // OE1
+  AddFRMRotatingParticle(GLU, 0, 3); // OE2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(GLU, 0, 4); // HB2
+    AddFRMRotatingParticle(GLU, 0, 5); // HB3
+    AddFRMRotatingParticle(GLU, 0, 6); // HG2
+    AddFRMRotatingParticle(GLU, 0, 7); // HG3
+  }
+
+  AddFRMRule(GLU, promod3::loop::BB_CB_INDEX, promod3::loop::GLU_CG_INDEX,
+             param.GLU_CB_CG_prefactors);
+  AddFRMFixParticle(GLU, 1, 0); // CG
+  AddFRMRotatingParticle(GLU, 1, 1); // CD
+  AddFRMRotatingParticle(GLU, 1, 2); // OE1
+  AddFRMRotatingParticle(GLU, 1, 3); // OE2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(GLU, 1, 4); // HB2
+    AddFRMFixParticle(GLU, 1, 5); // HB3
+    AddFRMRotatingParticle(GLU, 1, 6); // HG2
+    AddFRMRotatingParticle(GLU, 1, 7); // HG3
+  }
+
+  AddFRMRule(GLU, promod3::loop::GLU_CG_INDEX, promod3::loop::GLU_CD_INDEX,
+             param.GLU_CG_CD_prefactors);
+  AddFRMFixParticle(GLU, 2, 0); // CG
+  AddFRMFixParticle(GLU, 2, 1); // CD
+  AddFRMRotatingParticle(GLU, 2, 2); // OE1
+  AddFRMRotatingParticle(GLU, 2, 3); // OE2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(GLU, 2, 4); // HB2
+    AddFRMFixParticle(GLU, 2, 5); // HB3
+    AddFRMFixParticle(GLU, 2, 6); // HG2
+    AddFRMFixParticle(GLU, 2, 7); // HG3      
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 4;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 8;
+    }
+    AddFRMFixParticle(GLU, 0, cb_idx);
+    AddFRMFixParticle(GLU, 1, cb_idx);
+    AddFRMFixParticle(GLU, 2, cb_idx);
+  }
+
+
+  backbone_infos_[GLU].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+
+  AddBBInfo(GLU, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(GLU, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(GLU, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(GLU, "O", promod3::loop::BB_O_INDEX, false);
+
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLU, "H", promod3::loop::GLU_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLU, "HA", promod3::loop::GLU_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(GLU, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // LYS
+  sidechain_infos_[LYS].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[LYS].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::LYS];
+  sidechain_infos_[LYS].frm_t = param.frm_t[ost::conop::LYS];
+
+  AddInfo(LYS, "CG", promod3::loop::LYS_CG_INDEX,false);
+  AddInfo(LYS, "CD", promod3::loop::LYS_CD_INDEX,false);
+  AddInfo(LYS, "CE", promod3::loop::LYS_CE_INDEX,false);
+  AddInfo(LYS, "NZ", promod3::loop::LYS_NZ_INDEX,false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(LYS, "HZ1", promod3::loop::LYS_HZ1_INDEX,true);
+    AddInfo(LYS, "HZ2", promod3::loop::LYS_HZ2_INDEX,true);
+    AddInfo(LYS, "HZ3", promod3::loop::LYS_HZ3_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(LYS, "HB2", promod3::loop::LYS_HB2_INDEX, true);
+    AddInfo(LYS, "HB3", promod3::loop::LYS_HB3_INDEX, true);
+    AddInfo(LYS, "HG2", promod3::loop::LYS_HG2_INDEX, true);
+    AddInfo(LYS, "HG3", promod3::loop::LYS_HG3_INDEX, true);
+    AddInfo(LYS, "HD2", promod3::loop::LYS_HD2_INDEX, true);
+    AddInfo(LYS, "HD3", promod3::loop::LYS_HD3_INDEX, true);
+    AddInfo(LYS, "HE2", promod3::loop::LYS_HE2_INDEX, true);
+    AddInfo(LYS, "HE3", promod3::loop::LYS_HE3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(LYS, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(LYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.LYS_CA_CB_prefactors);
+  AddFRMRotatingParticle(LYS, 0, 0); // CG
+  AddFRMRotatingParticle(LYS, 0, 1); // CD
+  AddFRMRotatingParticle(LYS, 0, 2); // CE
+  AddFRMRotatingParticle(LYS, 0, 3); // NZ
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LYS, 0, 4); // HZ1
+    AddFRMRotatingParticle(LYS, 0, 5); // HZ2
+    AddFRMRotatingParticle(LYS, 0, 6); // HZ3
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LYS, 0, 7); // HB2
+    AddFRMRotatingParticle(LYS, 0, 8); // HB3
+    AddFRMRotatingParticle(LYS, 0, 9); // HG2
+    AddFRMRotatingParticle(LYS, 0, 10); // HG3
+    AddFRMRotatingParticle(LYS, 0, 11); // HD2
+    AddFRMRotatingParticle(LYS, 0, 12); // HD3
+    AddFRMRotatingParticle(LYS, 0, 13); // HE2
+    AddFRMRotatingParticle(LYS, 0, 14); // HE3
+  }
+
+  AddFRMRule(LYS, promod3::loop::BB_CB_INDEX, promod3::loop::LYS_CG_INDEX,
+             param.LYS_CB_CG_prefactors);
+  AddFRMFixParticle(LYS, 1, 0); // CG
+  AddFRMRotatingParticle(LYS, 1, 1); // CD
+  AddFRMRotatingParticle(LYS, 1, 2); // CE
+  AddFRMRotatingParticle(LYS, 1, 3); // NZ
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LYS, 1, 4); // HZ1
+    AddFRMRotatingParticle(LYS, 1, 5); // HZ2
+    AddFRMRotatingParticle(LYS, 1, 6); // HZ3
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(LYS, 1, 7); // HB2
+    AddFRMFixParticle(LYS, 1, 8); // HB3
+    AddFRMRotatingParticle(LYS, 1, 9); // HG2
+    AddFRMRotatingParticle(LYS, 1, 10); // HG3
+    AddFRMRotatingParticle(LYS, 1, 11); // HD2
+    AddFRMRotatingParticle(LYS, 1, 12); // HD3
+    AddFRMRotatingParticle(LYS, 1, 13); // HE2
+    AddFRMRotatingParticle(LYS, 1, 14); // HE3      
+  }
+
+  AddFRMRule(LYS, promod3::loop::LYS_CG_INDEX, promod3::loop::LYS_CD_INDEX,
+             param.LYS_CG_CD_prefactors);
+  AddFRMFixParticle(LYS, 2, 0); // CG
+  AddFRMFixParticle(LYS, 2, 1); // CD
+  AddFRMRotatingParticle(LYS, 2, 2); // CE
+  AddFRMRotatingParticle(LYS, 2, 3); // NZ
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LYS, 2, 4); // HZ1
+    AddFRMRotatingParticle(LYS, 2, 5); // HZ2
+    AddFRMRotatingParticle(LYS, 2, 6); // HZ3
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(LYS, 2, 7); // HB2
+    AddFRMFixParticle(LYS, 2, 8); // HB3
+    AddFRMFixParticle(LYS, 2, 9); // HG2
+    AddFRMFixParticle(LYS, 2, 10); // HG3
+    AddFRMRotatingParticle(LYS, 2, 11); // HD2
+    AddFRMRotatingParticle(LYS, 2, 12); // HD3
+    AddFRMRotatingParticle(LYS, 2, 13); // HE2
+    AddFRMRotatingParticle(LYS, 2, 14); // HE3          
+  }
+
+  AddFRMRule(LYS, promod3::loop::LYS_CD_INDEX, promod3::loop::LYS_CE_INDEX,
+             param.LYS_CD_CE_prefactors);
+  AddFRMFixParticle(LYS, 3, 0); // CG
+  AddFRMFixParticle(LYS, 3, 1); // CD
+  AddFRMFixParticle(LYS, 3, 2); // CE
+  AddFRMRotatingParticle(LYS, 3, 3); // NZ
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LYS, 3, 4); // HZ1
+    AddFRMRotatingParticle(LYS, 3, 5); // HZ2
+    AddFRMRotatingParticle(LYS, 3, 6); // HZ3
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(LYS, 3, 7); // HB2
+    AddFRMFixParticle(LYS, 3, 8); // HB3
+    AddFRMFixParticle(LYS, 3, 9); // HG2
+    AddFRMFixParticle(LYS, 3, 10); // HG3
+    AddFRMFixParticle(LYS, 3, 11); // HD2
+    AddFRMFixParticle(LYS, 3, 12); // HD3
+    AddFRMRotatingParticle(LYS, 3, 13); // HE2
+    AddFRMRotatingParticle(LYS, 3, 14); // HE3                
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 4;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 7;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 15;
+    }
+    AddFRMFixParticle(LYS, 0, cb_idx);
+    AddFRMFixParticle(LYS, 1, cb_idx);
+    AddFRMFixParticle(LYS, 2, cb_idx);
+    AddFRMFixParticle(LYS, 3, cb_idx);
+  }
+
+  backbone_infos_[LYS].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(LYS, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(LYS, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(LYS, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(LYS, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(LYS, "H", promod3::loop::LYS_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(LYS, "HA", promod3::loop::LYS_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(LYS, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // SER
+  sidechain_infos_[SER].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[SER].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::SER];
+  sidechain_infos_[SER].frm_t = param.frm_t[ost::conop::SER];
+
+  AddInfo(SER, "OG", promod3::loop::SER_OG_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(SER, "HG", promod3::loop::SER_HG_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(SER, "HB2", promod3::loop::SER_HB2_INDEX, true);
+    AddInfo(SER, "HB3", promod3::loop::SER_HB3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(SER, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddCustomHydrogenInfo(SER, promod3::loop::SER_HG_INDEX, 
+                          promod3::loop::BB_CA_INDEX, 
+                          promod3::loop::BB_CB_INDEX, 
+                          promod3::loop::SER_OG_INDEX,
+                          0.96, 1.85, 1);
+  }
+
+  AddFRMRule(SER, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.SER_CA_CB_prefactors);
+  AddFRMRotatingParticle(SER, 0, 0); // OG
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(SER, 0, 1); // HG
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(SER, 0, 2); // HB2
+    AddFRMRotatingParticle(SER, 0, 3); // HB3
+  }
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRule(SER, promod3::loop::BB_CB_INDEX, promod3::loop::SER_OG_INDEX,
+               param.SER_CB_OG_prefactors);
+    AddFRMFixParticle(SER, 1, 0); // OG
+    AddFRMRotatingParticle(SER, 1, 1); // HG
+    
+    if(mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(SER, 1, 2); // HB2
+      AddFRMFixParticle(SER, 1, 3); // HB3    
+    }
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 1;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 2;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 4;
+    }
+    AddFRMFixParticle(SER, 0, cb_idx);
+    if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(SER, 1, cb_idx);
+    }
+  }
+
+  backbone_infos_[SER].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(SER, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(SER, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(SER, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(SER, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(SER, "H", promod3::loop::SER_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(SER, "HA", promod3::loop::SER_HA_INDEX, true);    
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(SER, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // CYS
+  sidechain_infos_[CYS].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[CYS].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::CYS];
+  sidechain_infos_[CYS].frm_t = param.frm_t[ost::conop::CYS];
+
+  AddInfo(CYS, "SG", promod3::loop::CYS_SG_INDEX, false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(CYS, "HB2", promod3::loop::CYS_HB2_INDEX, true);
+    AddInfo(CYS, "HB3", promod3::loop::CYS_HB3_INDEX, true);
+    AddInfo(CYS, "HG", promod3::loop::CYS_HG_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(CYS, "CB", promod3::loop::BB_CB_INDEX, false);  
+  }
+
+  AddFRMRule(CYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.CYS_CA_CB_prefactors);
+  AddFRMRotatingParticle(CYS, 0, 0); // SG
+
+  if(FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(CYS, 0, 1); // HB2
+    AddFRMRotatingParticle(CYS, 0, 2); // HB3
+    AddFRMRotatingParticle(CYS, 0, 3); // HG
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 1;
+    if(FULL_ATOMIC_MODE) {
+      cb_idx = 4;
+    }
+    AddFRMFixParticle(CYS, 0, cb_idx);
+  }
+
+  backbone_infos_[CYS].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(CYS, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(CYS, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(CYS, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(CYS, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(CYS, "H", promod3::loop::CYS_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(CYS, "HA", promod3::loop::CYS_HA_INDEX,true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(CYS, "CB", promod3::loop::BB_CB_INDEX, false);   
+  }
+
+
+  // CYH
+  sidechain_infos_[CYH] = sidechain_infos_[CYS];
+  frm_rules_[CYH] = frm_rules_[CYS];
+  backbone_infos_[CYH] = backbone_infos_[CYS];
+
+
+  // CYD
+  sidechain_infos_[CYD].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[CYD].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::CYS];
+  sidechain_infos_[CYD].frm_t = param.frm_t[ost::conop::CYS];
+
+  AddInfo(CYD, "SG", promod3::loop::CYS_SG_INDEX, false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(CYD, "HB2", promod3::loop::CYS_HB2_INDEX, true);
+    AddInfo(CYD, "HB3", promod3::loop::CYS_HB3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(CYD, "CB", promod3::loop::BB_CB_INDEX, false);  
+  }
+
+  AddFRMRule(CYD, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.CYS_CA_CB_prefactors);
+  AddFRMRotatingParticle(CYD, 0, 0); // SG
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(CYD, 0, 1); // HB2
+    AddFRMRotatingParticle(CYD, 0, 2); // HB3
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 1;
+    if(FULL_ATOMIC_MODE) {
+      cb_idx = 3;
+    }
+    AddFRMFixParticle(CYD, 0, cb_idx);
+  }
+
+  backbone_infos_[CYD].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(CYD, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(CYD, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(CYD, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(CYD, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(CYD, "H", promod3::loop::CYS_H_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(CYD, "HA", promod3::loop::CYS_HA_INDEX,true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(CYD, "CB", promod3::loop::BB_CB_INDEX, false);   
+  }
+
+
+  // MET
+  sidechain_infos_[MET].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[MET].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::MET];
+  sidechain_infos_[MET].frm_t = param.frm_t[ost::conop::MET];
+
+  AddInfo(MET, "CG", promod3::loop::MET_CG_INDEX,false);
+  AddInfo(MET, "SD", promod3::loop::MET_SD_INDEX,false);
+  AddInfo(MET, "CE", promod3::loop::MET_CE_INDEX,false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(MET, "HB2", promod3::loop::MET_HB2_INDEX, true);
+    AddInfo(MET, "HB3", promod3::loop::MET_HB3_INDEX, true);
+    AddInfo(MET, "HG2", promod3::loop::MET_HG2_INDEX, true);
+    AddInfo(MET, "HG3", promod3::loop::MET_HG3_INDEX, true);
+    AddInfo(MET, "HE1", promod3::loop::MET_HE1_INDEX, true);
+    AddInfo(MET, "HE2", promod3::loop::MET_HE2_INDEX, true);
+    AddInfo(MET, "HE3", promod3::loop::MET_HE3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(MET, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(MET, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.MET_CA_CB_prefactors);
+  AddFRMRotatingParticle(MET, 0, 0); // CG
+  AddFRMRotatingParticle(MET, 0, 1); // SD
+  AddFRMRotatingParticle(MET, 0, 2); // CE
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(MET, 0, 3); // HB2
+    AddFRMRotatingParticle(MET, 0, 4); // HB3
+    AddFRMRotatingParticle(MET, 0, 5); // HG2
+    AddFRMRotatingParticle(MET, 0, 6); // HG3
+    AddFRMRotatingParticle(MET, 0, 7); // HE1
+    AddFRMRotatingParticle(MET, 0, 8); // HE2
+    AddFRMRotatingParticle(MET, 0, 9); // HE3
+  }
+
+  AddFRMRule(MET, promod3::loop::BB_CB_INDEX, promod3::loop::MET_CG_INDEX,
+             param.MET_CB_CG_prefactors);
+  AddFRMFixParticle(MET, 1, 0); // CG
+  AddFRMRotatingParticle(MET, 1, 1); // SD
+  AddFRMRotatingParticle(MET, 1, 2); // CE
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(MET, 1, 3); // HB2
+    AddFRMFixParticle(MET, 1, 4); // HB3
+    AddFRMRotatingParticle(MET, 1, 5); // HG2
+    AddFRMRotatingParticle(MET, 1, 6); // HG3
+    AddFRMRotatingParticle(MET, 1, 7); // HE1
+    AddFRMRotatingParticle(MET, 1, 8); // HE2
+    AddFRMRotatingParticle(MET, 1, 9); // HE3      
+  }
+
+  AddFRMRule(MET, promod3::loop::MET_CG_INDEX, promod3::loop::MET_SD_INDEX,
+             param.MET_CG_SD_prefactors);
+  AddFRMFixParticle(MET, 2, 0);
+  AddFRMFixParticle(MET, 2, 1);
+  AddFRMRotatingParticle(MET, 2, 2);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(MET, 2, 3); // HB2
+    AddFRMFixParticle(MET, 2, 4); // HB3
+    AddFRMFixParticle(MET, 2, 5); // HG2
+    AddFRMFixParticle(MET, 2, 6); // HG3
+    AddFRMRotatingParticle(MET, 2, 7); // HE1
+    AddFRMRotatingParticle(MET, 2, 8); // HE2
+    AddFRMRotatingParticle(MET, 2, 9); // HE3            
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 3;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 10;
+    }
+    AddFRMFixParticle(MET, 0, cb_idx);
+    AddFRMFixParticle(MET, 1, cb_idx);
+    AddFRMFixParticle(MET, 2, cb_idx);
+  }
+
+  backbone_infos_[MET].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(MET, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(MET, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(MET, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(MET, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(MET, "H", promod3::loop::MET_H_INDEX, true);      
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(MET, "H", promod3::loop::MET_H_INDEX, true);      
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(MET, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // TRP
+  sidechain_infos_[TRP].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[TRP].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::TRP];
+  sidechain_infos_[TRP].frm_t = param.frm_t[ost::conop::TRP];
+
+  AddInfo(TRP, "CG", promod3::loop::TRP_CG_INDEX,false);
+  AddInfo(TRP, "CD1", promod3::loop::TRP_CD1_INDEX,false);
+  AddInfo(TRP, "CD2", promod3::loop::TRP_CD2_INDEX,false);
+  AddInfo(TRP, "CE2", promod3::loop::TRP_CE2_INDEX,false);
+  AddInfo(TRP, "NE1", promod3::loop::TRP_NE1_INDEX,false);
+  AddInfo(TRP, "CE3", promod3::loop::TRP_CE3_INDEX,false);
+  AddInfo(TRP, "CZ3", promod3::loop::TRP_CZ3_INDEX,false);
+  AddInfo(TRP, "CH2", promod3::loop::TRP_CH2_INDEX,false);
+  AddInfo(TRP, "CZ2", promod3::loop::TRP_CZ2_INDEX,false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(TRP, "HE1", promod3::loop::TRP_HE1_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(TRP, "HB2", promod3::loop::TRP_HB2_INDEX, true);
+    AddInfo(TRP, "HB3", promod3::loop::TRP_HB3_INDEX, true);
+    AddInfo(TRP, "HD1", promod3::loop::TRP_HD1_INDEX, true);
+    AddInfo(TRP, "HE3", promod3::loop::TRP_HE3_INDEX, true);
+    AddInfo(TRP, "HZ2", promod3::loop::TRP_HZ2_INDEX, true);
+    AddInfo(TRP, "HZ3", promod3::loop::TRP_HZ3_INDEX, true);
+    AddInfo(TRP, "HH2", promod3::loop::TRP_HH2_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(TRP, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(TRP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.TRP_CA_CB_prefactors);
+  AddFRMRotatingParticle(TRP, 0, 0); // CG
+  AddFRMRotatingParticle(TRP, 0, 1); // CD1
+  AddFRMRotatingParticle(TRP, 0, 2); // CD2
+  AddFRMRotatingParticle(TRP, 0, 3); // CE2
+  AddFRMRotatingParticle(TRP, 0, 4); // NE1
+  AddFRMRotatingParticle(TRP, 0, 5); // CE3
+  AddFRMRotatingParticle(TRP, 0, 6); // CZ3
+  AddFRMRotatingParticle(TRP, 0, 7); // CH2
+  AddFRMRotatingParticle(TRP, 0, 8); // CZ2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TRP, 0, 9);  // HE1    
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TRP, 0, 10); // HB2
+    AddFRMRotatingParticle(TRP, 0, 11); // HB3
+    AddFRMRotatingParticle(TRP, 0, 12); // HD1
+    AddFRMRotatingParticle(TRP, 0, 13); // HE3
+    AddFRMRotatingParticle(TRP, 0, 14); // HZ2
+    AddFRMRotatingParticle(TRP, 0, 15); // HZ3
+    AddFRMRotatingParticle(TRP, 0, 16); // HH2
+  }
+
+  AddFRMRule(TRP, promod3::loop::BB_CB_INDEX, promod3::loop::TRP_CG_INDEX,
+             param.TRP_CB_CG_prefactors);
+  AddFRMFixParticle(TRP, 1, 0); // CG
+  AddFRMRotatingParticle(TRP, 1, 1); // CD1
+  AddFRMRotatingParticle(TRP, 1, 2); // CD2
+  AddFRMRotatingParticle(TRP, 1, 3); // CE2
+  AddFRMRotatingParticle(TRP, 1, 4); // NE1
+  AddFRMRotatingParticle(TRP, 1, 5); // CE3
+  AddFRMRotatingParticle(TRP, 1, 6); // CZ3
+  AddFRMRotatingParticle(TRP, 1, 7); // CH2
+  AddFRMRotatingParticle(TRP, 1, 8); // CZ2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TRP, 1, 9);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(TRP, 1, 10); // HB2
+    AddFRMFixParticle(TRP, 1, 11); // HB3
+    AddFRMRotatingParticle(TRP, 1, 12); // HD1
+    AddFRMRotatingParticle(TRP, 1, 13); // HE3
+    AddFRMRotatingParticle(TRP, 1, 14); // HZ2
+    AddFRMRotatingParticle(TRP, 1, 15); // HZ3
+    AddFRMRotatingParticle(TRP, 1, 16); // HH2      
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 9;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 10;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 17;
+    }
+    AddFRMFixParticle(TRP, 0, cb_idx);
+    AddFRMFixParticle(TRP, 1, cb_idx);
+  }
+
+  backbone_infos_[TRP].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(TRP, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(TRP, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(TRP, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(TRP, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(TRP, "H", promod3::loop::TRP_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(TRP, "HA", promod3::loop::TRP_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(TRP, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // TYR
+  sidechain_infos_[TYR].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[TYR].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::TYR];
+  sidechain_infos_[TYR].frm_t = param.frm_t[ost::conop::TYR];
+
+  AddInfo(TYR, "CG", promod3::loop::TYR_CG_INDEX, false);
+  AddInfo(TYR, "CD1", promod3::loop::TYR_CD1_INDEX, false);
+  AddInfo(TYR, "CD2", promod3::loop::TYR_CD2_INDEX, false);
+  AddInfo(TYR, "CE1", promod3::loop::TYR_CE1_INDEX, false);
+  AddInfo(TYR, "CE2", promod3::loop::TYR_CE2_INDEX, false);
+  AddInfo(TYR, "CZ", promod3::loop::TYR_CZ_INDEX, false);
+  AddInfo(TYR, "OH", promod3::loop::TYR_OH_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(TYR, "HH", promod3::loop::TYR_HH_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(TYR, "HB2", promod3::loop::TYR_HB2_INDEX, true);
+    AddInfo(TYR, "HB3", promod3::loop::TYR_HB3_INDEX, true);
+    AddInfo(TYR, "HD1", promod3::loop::TYR_HD1_INDEX, true);
+    AddInfo(TYR, "HD2", promod3::loop::TYR_HD2_INDEX, true);
+    AddInfo(TYR, "HE1", promod3::loop::TYR_HE1_INDEX, true);
+    AddInfo(TYR, "HE2", promod3::loop::TYR_HE2_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(TYR, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+  
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddCustomHydrogenInfo(TYR, promod3::loop::TYR_HH_INDEX, 
+                          promod3::loop::TYR_CE1_INDEX, 
+                          promod3::loop::TYR_CZ_INDEX, 
+                          promod3::loop::TYR_OH_INDEX,
+                          0.96, 1.885, 2);
+  }
+
+  AddFRMRule(TYR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.TYR_CA_CB_prefactors);
+  AddFRMRotatingParticle(TYR, 0, 0); // CG
+  AddFRMRotatingParticle(TYR, 0, 1); // CD1
+  AddFRMRotatingParticle(TYR, 0, 2); // CD2
+  AddFRMRotatingParticle(TYR, 0, 3); // CE1
+  AddFRMRotatingParticle(TYR, 0, 4); // CE2
+  AddFRMRotatingParticle(TYR, 0, 5); // CZ
+  AddFRMRotatingParticle(TYR, 0, 6); // OH
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TYR, 0, 7); // HH    
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TYR, 0, 8); // HB2
+    AddFRMRotatingParticle(TYR, 0, 9); // HB3
+    AddFRMRotatingParticle(TYR, 0, 10); // HD1
+    AddFRMRotatingParticle(TYR, 0, 11); // HD2
+    AddFRMRotatingParticle(TYR, 0, 12); // HE1
+    AddFRMRotatingParticle(TYR, 0, 13); // HE2
+  }
+
+  AddFRMRule(TYR, promod3::loop::BB_CB_INDEX, promod3::loop::TYR_CG_INDEX,
+             param.TYR_CB_CG_prefactors);
+  AddFRMFixParticle(TYR, 1, 0); // CG
+  AddFRMRotatingParticle(TYR, 1, 1); // CD1
+  AddFRMRotatingParticle(TYR, 1, 2); // CD2
+  AddFRMRotatingParticle(TYR, 1, 3); // CE1
+  AddFRMRotatingParticle(TYR, 1, 4); // CE2
+  AddFRMRotatingParticle(TYR, 1, 5); // CZ
+  AddFRMRotatingParticle(TYR, 1, 6); // OH
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(TYR, 1, 7); // HH
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(TYR, 1, 8); // HB2
+    AddFRMFixParticle(TYR, 1, 9); // HB3
+    AddFRMRotatingParticle(TYR, 1, 10); // HD1
+    AddFRMRotatingParticle(TYR, 1, 11); // HD2
+    AddFRMRotatingParticle(TYR, 1, 12); // HE1
+    AddFRMRotatingParticle(TYR, 1, 13); // HE2
+
+  }
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRule(TYR, promod3::loop::TYR_CZ_INDEX, promod3::loop::TYR_OH_INDEX,
+               param.TYR_CZ_OH_prefactors);
+    AddFRMFixParticle(TYR, 2, 0); // CG
+    AddFRMFixParticle(TYR, 2, 1); // CD1
+    AddFRMFixParticle(TYR, 2, 2); // CD2
+    AddFRMFixParticle(TYR, 2, 3); // CE1
+    AddFRMFixParticle(TYR, 2, 4); // CE2
+    AddFRMFixParticle(TYR, 2, 5); // CZ
+    AddFRMFixParticle(TYR, 2, 6); // OH
+
+    AddFRMRotatingParticle(TYR, 2, 7);
+
+    if(mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(TYR, 2, 8); // HB2
+      AddFRMFixParticle(TYR, 2, 9); // HB3
+      AddFRMFixParticle(TYR, 2, 10); // HD1
+      AddFRMFixParticle(TYR, 2, 11); // HD2
+      AddFRMFixParticle(TYR, 2, 12); // HE1
+      AddFRMFixParticle(TYR, 2, 13); // HE2      
+    }
+  }
+
+
+  if(cb_in_sidechain) {
+    int cb_idx = 7;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 8;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 14;
+    }
+    AddFRMFixParticle(TYR, 0, cb_idx);
+    AddFRMFixParticle(TYR, 1, cb_idx);
+    if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(TYR, 2, cb_idx);
+    }
+  }
+
+  backbone_infos_[TYR].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(TYR, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(TYR, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(TYR, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(TYR, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(TYR, "H", promod3::loop::TYR_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(TYR, "HA", promod3::loop::TYR_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(TYR, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // THR
+  sidechain_infos_[THR].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[THR].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::THR];
+  sidechain_infos_[THR].frm_t = param.frm_t[ost::conop::THR];
+
+  AddInfo(THR, "OG1", promod3::loop::THR_OG1_INDEX, false);
+  AddInfo(THR, "CG2", promod3::loop::THR_CG2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(THR, "HG1", promod3::loop::THR_HG1_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(THR, "HB", promod3::loop::THR_HB_INDEX, true);
+    AddInfo(THR, "HG21", promod3::loop::THR_HG22_INDEX, true);
+    AddInfo(THR, "HG22", promod3::loop::THR_HG23_INDEX, true);
+    AddInfo(THR, "HG23", promod3::loop::THR_HG23_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(THR, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddCustomHydrogenInfo(THR, promod3::loop::THR_HG1_INDEX, 
+                          promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX, 
+                          promod3::loop::THR_OG1_INDEX,
+                          0.96, 1.85, 1);
+  }
+
+  AddFRMRule(THR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.THR_CA_CB_prefactors);
+  AddFRMRotatingParticle(THR, 0, 0); // OG1
+  AddFRMRotatingParticle(THR, 0, 1); // CG2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(THR, 0, 2); // HG1
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(THR, 0, 3); // HB  
+    AddFRMRotatingParticle(THR, 0, 4); // HG21
+    AddFRMRotatingParticle(THR, 0, 5); // HG22  
+    AddFRMRotatingParticle(THR, 0, 6); // HG23  
+  }
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRule(THR, promod3::loop::BB_CB_INDEX, promod3::loop::THR_OG1_INDEX,
+               param.THR_CB_OG1_prefactors);
+    AddFRMFixParticle(THR, 1, 0); // OG1
+    AddFRMFixParticle(THR, 1, 1); //CG2
+    AddFRMRotatingParticle(THR, 1, 2); // HG1
+
+    if(mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(THR, 1, 3); // HB
+      AddFRMFixParticle(THR, 1, 4); // HG21
+      AddFRMFixParticle(THR, 1, 5); // HG22
+      AddFRMFixParticle(THR, 1, 6); // HG23
+    }
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 2;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 3;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 7;
+    }
+    AddFRMFixParticle(THR, 0, cb_idx);
+    if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+      AddFRMFixParticle(THR, 1, cb_idx);
+    }
+  }
+
+  backbone_infos_[THR].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(THR, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(THR, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(THR, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(THR, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(THR, "H", promod3::loop::THR_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(THR, "HA", promod3::loop::THR_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(THR, "CB", promod3::loop::BB_CB_INDEX, false); 
+  }
+
+
+  // VAL
+  sidechain_infos_[VAL].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[VAL].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::VAL];
+  sidechain_infos_[VAL].frm_t = param.frm_t[ost::conop::VAL];
+
+  AddInfo(VAL, "CG1", promod3::loop::VAL_CG1_INDEX, false);
+  AddInfo(VAL, "CG2", promod3::loop::VAL_CG2_INDEX, false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(VAL, "HB", promod3::loop::VAL_HB_INDEX, true);
+    AddInfo(VAL, "HG11", promod3::loop::VAL_HG11_INDEX, true);
+    AddInfo(VAL, "HG12", promod3::loop::VAL_HG12_INDEX, true);
+    AddInfo(VAL, "HG13", promod3::loop::VAL_HG13_INDEX, true);
+    AddInfo(VAL, "HG21", promod3::loop::VAL_HG21_INDEX, true);
+    AddInfo(VAL, "HG22", promod3::loop::VAL_HG22_INDEX, true);
+    AddInfo(VAL, "HG23", promod3::loop::VAL_HG23_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(VAL, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(VAL, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.VAL_CA_CB_prefactors);
+  AddFRMRotatingParticle(VAL, 0, 0); // CG1
+  AddFRMRotatingParticle(VAL, 0, 1); // CG2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(VAL, 0, 2); // HB
+    AddFRMRotatingParticle(VAL, 0, 3); // HG11
+    AddFRMRotatingParticle(VAL, 0, 4); // HG12
+    AddFRMRotatingParticle(VAL, 0, 5); // HG13
+    AddFRMRotatingParticle(VAL, 0, 6); // HG21
+    AddFRMRotatingParticle(VAL, 0, 7); // HG22
+    AddFRMRotatingParticle(VAL, 0, 8); // HG23
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 2;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 9;
+    }
+    AddFRMFixParticle(VAL, 0, cb_idx);
+  }
+
+  backbone_infos_[VAL].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(VAL, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(VAL, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(VAL, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(VAL, "O", promod3::loop::BB_O_INDEX, false);
+  
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(VAL, "H", promod3::loop::VAL_H_INDEX, true);      
+  }
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(VAL, "HA", promod3::loop::VAL_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(VAL, "CB", promod3::loop::BB_CB_INDEX, false); 
+  }
+
+
+  // ILE
+  sidechain_infos_[ILE].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[ILE].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::ILE];
+  sidechain_infos_[ILE].frm_t = param.frm_t[ost::conop::ILE];
+
+  AddInfo(ILE, "CG1", promod3::loop::ILE_CG1_INDEX, false);
+  AddInfo(ILE, "CG2", promod3::loop::ILE_CG2_INDEX, false);  
+  AddInfo(ILE, "CD1", promod3::loop::ILE_CD1_INDEX, false);  
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(ILE, "HB", promod3::loop::ILE_HB_INDEX, true);
+    AddInfo(ILE, "HG12", promod3::loop::ILE_HG12_INDEX, true);
+    AddInfo(ILE, "HG13", promod3::loop::ILE_HG13_INDEX, true);
+    AddInfo(ILE, "HG21", promod3::loop::ILE_HG21_INDEX, true);
+    AddInfo(ILE, "HG22", promod3::loop::ILE_HG22_INDEX, true);
+    AddInfo(ILE, "HG23", promod3::loop::ILE_HG23_INDEX, true);
+    AddInfo(ILE, "HD11", promod3::loop::ILE_HD11_INDEX, true);
+    AddInfo(ILE, "HD12", promod3::loop::ILE_HD12_INDEX, true);
+    AddInfo(ILE, "HD13", promod3::loop::ILE_HD13_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(ILE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(ILE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.ILE_CA_CB_prefactors);
+  AddFRMRotatingParticle(ILE, 0, 0); // CG1
+  AddFRMRotatingParticle(ILE, 0, 1); // CG2
+  AddFRMRotatingParticle(ILE, 0, 2); // CD1
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(ILE, 0, 3); // HB
+    AddFRMRotatingParticle(ILE, 0, 4); // HG12
+    AddFRMRotatingParticle(ILE, 0, 5); // HG13
+    AddFRMRotatingParticle(ILE, 0, 6); // HG21
+    AddFRMRotatingParticle(ILE, 0, 7); // HG22
+    AddFRMRotatingParticle(ILE, 0, 8); // HG23
+    AddFRMRotatingParticle(ILE, 0, 9); // HD11
+    AddFRMRotatingParticle(ILE, 0, 10); // HD12
+    AddFRMRotatingParticle(ILE, 0, 11); // HD13
+  }
+
+
+  AddFRMRule(ILE, promod3::loop::BB_CB_INDEX, promod3::loop::ILE_CG1_INDEX,
+             param.ILE_CB_CG1_prefactors);
+  AddFRMFixParticle(ILE, 1, 0); // CG1
+  AddFRMFixParticle(ILE, 1, 1); // CG2
+  AddFRMRotatingParticle(ILE, 1, 2); // CD1
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(ILE, 1, 3); // HB
+    AddFRMRotatingParticle(ILE, 1, 4); // HG12
+    AddFRMRotatingParticle(ILE, 1, 5); // HG13
+    AddFRMFixParticle(ILE, 1, 6); // HG21
+    AddFRMFixParticle(ILE, 1, 7); // HG22
+    AddFRMFixParticle(ILE, 1, 8); // HG23
+    AddFRMRotatingParticle(ILE, 1, 9); // HD11
+    AddFRMRotatingParticle(ILE, 1, 10); // HD12
+    AddFRMRotatingParticle(ILE, 1, 11); // HD13 
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 3;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 12;
+    }
+    AddFRMFixParticle(ILE, 0, cb_idx);
+    AddFRMFixParticle(ILE, 1, cb_idx);
+  }
+
+  backbone_infos_[ILE].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(ILE, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(ILE, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(ILE, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(ILE, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ILE, "H", promod3::loop::ILE_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ILE, "HA", promod3::loop::ILE_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(ILE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // LEU
+  sidechain_infos_[LEU].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[LEU].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::LEU];
+  sidechain_infos_[LEU].frm_t = param.frm_t[ost::conop::LEU];
+  
+  AddInfo(LEU, "CG", promod3::loop::LEU_CG_INDEX, false);
+  AddInfo(LEU, "CD1", promod3::loop::LEU_CD1_INDEX, false);  
+  AddInfo(LEU, "CD2", promod3::loop::LEU_CD2_INDEX, false);  
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(LEU, "HB2", promod3::loop::LEU_HB2_INDEX, true);
+    AddInfo(LEU, "HB3", promod3::loop::LEU_HB3_INDEX, true);
+    AddInfo(LEU, "HG", promod3::loop::LEU_HG_INDEX, true);
+    AddInfo(LEU, "HD11", promod3::loop::LEU_HD11_INDEX, true);
+    AddInfo(LEU, "HD12", promod3::loop::LEU_HD12_INDEX, true);
+    AddInfo(LEU, "HD13", promod3::loop::LEU_HD13_INDEX, true);
+    AddInfo(LEU, "HD21", promod3::loop::LEU_HD21_INDEX, true);
+    AddInfo(LEU, "HD22", promod3::loop::LEU_HD22_INDEX, true);
+    AddInfo(LEU, "HD23", promod3::loop::LEU_HD23_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(LEU, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  AddFRMRule(LEU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.LEU_CA_CB_prefactors);
+  AddFRMRotatingParticle(LEU, 0, 0); // CG
+  AddFRMRotatingParticle(LEU, 0, 1); // CD1
+  AddFRMRotatingParticle(LEU, 0, 2); // CD2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(LEU, 0, 3); // HB2
+    AddFRMRotatingParticle(LEU, 0, 4); // HB3
+    AddFRMRotatingParticle(LEU, 0, 5); // HG
+    AddFRMRotatingParticle(LEU, 0, 6); // HD11
+    AddFRMRotatingParticle(LEU, 0, 7); // HD12
+    AddFRMRotatingParticle(LEU, 0, 8); // HD13
+    AddFRMRotatingParticle(LEU, 0, 9); // HD21
+    AddFRMRotatingParticle(LEU, 0, 10); // HD22
+    AddFRMRotatingParticle(LEU, 0, 11); // HD23
+  }
+
+  AddFRMRule(LEU, promod3::loop::BB_CB_INDEX, promod3::loop::LEU_CG_INDEX,
+             param.LEU_CB_CG_prefactors);
+  AddFRMFixParticle(LEU, 1, 0); // CG
+  AddFRMRotatingParticle(LEU, 1, 1); // CG1
+  AddFRMRotatingParticle(LEU, 1, 2); // CG2
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(LEU, 1, 3); // HB2
+    AddFRMFixParticle(LEU, 1, 4); // HB3
+    AddFRMRotatingParticle(LEU, 1, 5); // HG
+    AddFRMRotatingParticle(LEU, 1, 6); // HD11
+    AddFRMRotatingParticle(LEU, 1, 7); // HD12
+    AddFRMRotatingParticle(LEU, 1, 8); // HD13
+    AddFRMRotatingParticle(LEU, 1, 9); // HD21
+    AddFRMRotatingParticle(LEU, 1, 10); // HD22
+    AddFRMRotatingParticle(LEU, 1, 11); // HD23
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 3;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 12;
+    }
+    AddFRMFixParticle(LEU, 0, cb_idx);
+    AddFRMFixParticle(LEU, 1, cb_idx);
+  }
+
+  backbone_infos_[LEU].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(LEU, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(LEU, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(LEU, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(LEU, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(LEU, "H", promod3::loop::LEU_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(LEU, "HA", promod3::loop::LEU_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(LEU, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // PROLINES DO NOT HAVE FRM DEFINITIONS!
+  // large scale benchmarks showed, that varying around chi angles in case
+  // of prolines has a negative effect on performance => reduce to one single
+  // subrotamer...
+
+  // PRO
+  sidechain_infos_[PRO].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[PRO].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::PRO];
+  sidechain_infos_[PRO].frm_t = param.frm_t[ost::conop::PRO];
+  
+  AddInfo(PRO, "CG", promod3::loop::PRO_CG_INDEX, false);
+  AddInfo(PRO, "CD", promod3::loop::PRO_CD_INDEX, false); 
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(PRO, "HB2", promod3::loop::PRO_HB2_INDEX, true);
+    AddInfo(PRO, "HB3", promod3::loop::PRO_HB3_INDEX, true);
+    AddInfo(PRO, "HG2", promod3::loop::PRO_HG2_INDEX, true);
+    AddInfo(PRO, "HG3", promod3::loop::PRO_HG3_INDEX, true);
+    AddInfo(PRO, "HD2", promod3::loop::PRO_HD2_INDEX, true);
+    AddInfo(PRO, "HD3", promod3::loop::PRO_HD3_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(PRO, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  backbone_infos_[PRO].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  AddBBInfo(PRO, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(PRO, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(PRO, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(PRO, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(PRO, "HA", promod3::loop::PRO_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(PRO, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // CPR
+  sidechain_infos_[CPR] = sidechain_infos_[PRO]; 
+  frm_rules_[CPR] = frm_rules_[PRO];
+  backbone_infos_[CPR] = backbone_infos_[PRO];
+
+
+  // TPR
+  sidechain_infos_[TPR] = sidechain_infos_[PRO];
+  frm_rules_[TPR] = frm_rules_[PRO];
+  backbone_infos_[TPR] = backbone_infos_[PRO];
+
+
+  // HSD
+  sidechain_infos_[HSD].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[HSD].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::HIS];
+  sidechain_infos_[HSD].frm_t = param.frm_t[ost::conop::HIS];
+
+  AddInfo(HSD, "CG", promod3::loop::HIS_CG_INDEX, false);
+  AddInfo(HSD, "ND1", promod3::loop::HIS_ND1_INDEX, false);
+  AddInfo(HSD, "CD2", promod3::loop::HIS_CD2_INDEX, false);
+  AddInfo(HSD, "CE1", promod3::loop::HIS_CE1_INDEX, false);
+  AddInfo(HSD, "NE2", promod3::loop::HIS_NE2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(HSD, "HD1", promod3::loop::HIS_HD1_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(HSD, "HB2", promod3::loop::HIS_HB2_INDEX, true);
+    AddInfo(HSD, "HB3", promod3::loop::HIS_HB3_INDEX, true);
+    AddInfo(HSD, "HD2", promod3::loop::HIS_HD2_INDEX, true);
+    AddInfo(HSD, "HE1", promod3::loop::HIS_HE1_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(HSD, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(HSD, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.HIS_CA_CB_prefactors);
+  AddFRMRotatingParticle(HSD, 0, 0); // CG
+  AddFRMRotatingParticle(HSD, 0, 1); // ND1
+  AddFRMRotatingParticle(HSD, 0, 2); // CD2
+  AddFRMRotatingParticle(HSD, 0, 3); // CE1
+  AddFRMRotatingParticle(HSD, 0, 4); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSD, 0, 5); // HD1
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSD, 0, 6); // HB2
+    AddFRMRotatingParticle(HSD, 0, 7); // HB3
+    AddFRMRotatingParticle(HSD, 0, 8); // HD2
+    AddFRMRotatingParticle(HSD, 0, 9); // HE1
+  }
+
+  AddFRMRule(HSD, promod3::loop::BB_CB_INDEX, promod3::loop::HIS_CG_INDEX,
+             param.HIS_CB_CG_prefactors);
+  AddFRMFixParticle(HSD, 1, 0); // CG
+  AddFRMRotatingParticle(HSD, 1, 1); // ND1
+  AddFRMRotatingParticle(HSD, 1, 2); // CD2
+  AddFRMRotatingParticle(HSD, 1, 3); // CE1
+  AddFRMRotatingParticle(HSD, 1, 4); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSD, 1, 5); // HD1
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSD, 1, 6); // HB2
+    AddFRMRotatingParticle(HSD, 1, 7); // HB3
+    AddFRMRotatingParticle(HSD, 1, 8); // HD2
+    AddFRMRotatingParticle(HSD, 1, 9); // HE1      
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 5;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 6;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 10;
+    }
+    AddFRMFixParticle(HSD, 0, cb_idx);
+    AddFRMFixParticle(HSD, 1, cb_idx);
+  }
+
+  backbone_infos_[HSD].has_hydrogens = (mode == POLAR_HYDROGEN_MODE || 
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(HSD, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(HSD, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(HSD, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(HSD, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(HSD, "H", promod3::loop::HIS_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(HSD, "HA", promod3::loop::HIS_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(HSD, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // HSE
+  sidechain_infos_[HSE].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                         mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[HSE].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::HIS];
+  sidechain_infos_[HSE].frm_t = param.frm_t[ost::conop::HIS];
+
+  AddInfo(HSE, "CG", promod3::loop::HIS_CG_INDEX, false);
+  AddInfo(HSE, "ND1", promod3::loop::HIS_ND1_INDEX, false);
+  AddInfo(HSE, "CD2", promod3::loop::HIS_CD2_INDEX, false);
+  AddInfo(HSE, "CE1", promod3::loop::HIS_CE1_INDEX, false);
+  AddInfo(HSE, "NE2", promod3::loop::HIS_NE2_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddInfo(HSE, "HE2", promod3::loop::HIS_HE2_INDEX,true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(HSE, "HB2", promod3::loop::HIS_HB2_INDEX, true);
+    AddInfo(HSE, "HB3", promod3::loop::HIS_HB3_INDEX, true);
+    AddInfo(HSE, "HD2", promod3::loop::HIS_HD2_INDEX, true);
+    AddInfo(HSE, "HE1", promod3::loop::HIS_HE1_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(HSE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(HSE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.HIS_CA_CB_prefactors);
+  AddFRMRotatingParticle(HSE, 0, 0); // CG
+  AddFRMRotatingParticle(HSE, 0, 1); // ND1
+  AddFRMRotatingParticle(HSE, 0, 2); // CD2
+  AddFRMRotatingParticle(HSE, 0, 3); // CE1
+  AddFRMRotatingParticle(HSE, 0, 4); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSE, 0, 5); // HE2
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSE, 0, 6); // HB2
+    AddFRMRotatingParticle(HSE, 0, 7); // HB3
+    AddFRMRotatingParticle(HSE, 0, 8); // HD2
+    AddFRMRotatingParticle(HSE, 0, 9); // HE1
+  }
+
+  AddFRMRule(HSE, promod3::loop::BB_CB_INDEX, promod3::loop::HIS_CG_INDEX,
+             param.HIS_CB_CG_prefactors);
+  AddFRMFixParticle(HSE, 1, 0); // CG
+  AddFRMRotatingParticle(HSE, 1, 1); // ND1
+  AddFRMRotatingParticle(HSE, 1, 2); // CD2
+  AddFRMRotatingParticle(HSE, 1, 3); // CE1
+  AddFRMRotatingParticle(HSE, 1, 4); // NE2
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSE, 1, 5); // HE2
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(HSE, 1, 6); // HB2
+    AddFRMRotatingParticle(HSE, 1, 7); // HB3
+    AddFRMRotatingParticle(HSE, 1, 8); // HD2
+    AddFRMRotatingParticle(HSE, 1, 9); // HE1      
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 5;
+    if(mode == POLAR_HYDROGEN_MODE) {
+      cb_idx = 6;
+    }
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 10;
+    }
+    AddFRMFixParticle(HSE, 0, cb_idx);
+    AddFRMFixParticle(HSE, 1, cb_idx);
+  }
+
+  backbone_infos_[HSE].has_hydrogens = (mode == POLAR_HYDROGEN_MODE || 
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(HSE, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(HSE, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(HSE, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(HSE, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(HSE, "H", promod3::loop::HIS_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(HSE, "HA", promod3::loop::HIS_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(HSE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  // HIS
+  // this is a bit hacky... we just assign HSD as determined by a fair
+  // random number generator.
+  sidechain_infos_[HIS] = sidechain_infos_[HSD];
+  frm_rules_[HIS] = frm_rules_[HSD];
+  backbone_infos_[HIS] = backbone_infos_[HSD];
+
+
+  // PHE
+  sidechain_infos_[PHE].has_hydrogens = (mode == FULL_ATOMIC_MODE);
+  sidechain_infos_[PHE].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::PHE];
+  sidechain_infos_[PHE].frm_t = param.frm_t[ost::conop::PHE];
+  
+  AddInfo(PHE, "CG", promod3::loop::PHE_CG_INDEX, false);
+  AddInfo(PHE, "CD1", promod3::loop::PHE_CD1_INDEX, false);  
+  AddInfo(PHE, "CD2", promod3::loop::PHE_CD2_INDEX, false); 
+  AddInfo(PHE, "CE1", promod3::loop::PHE_CE1_INDEX, false);  
+  AddInfo(PHE, "CE2", promod3::loop::PHE_CE2_INDEX, false); 
+  AddInfo(PHE, "CZ", promod3::loop::PHE_CZ_INDEX, false); 
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddInfo(PHE, "HB2", promod3::loop::PHE_HB2_INDEX, true);
+    AddInfo(PHE, "HB3", promod3::loop::PHE_HB3_INDEX, true);
+    AddInfo(PHE, "HD1", promod3::loop::PHE_HD1_INDEX, true);
+    AddInfo(PHE, "HD2", promod3::loop::PHE_HD2_INDEX, true);
+    AddInfo(PHE, "HE1", promod3::loop::PHE_HE1_INDEX, true);
+    AddInfo(PHE, "HE2", promod3::loop::PHE_HE2_INDEX, true);
+    AddInfo(PHE, "HZ", promod3::loop::PHE_HZ_INDEX, true);
+  }
+
+  if(cb_in_sidechain) {
+    AddInfo(PHE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+  AddFRMRule(PHE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX,
+             param.PHE_CA_CB_prefactors);
+  AddFRMRotatingParticle(PHE, 0, 0); // CG
+  AddFRMRotatingParticle(PHE, 0, 1); // CD1
+  AddFRMRotatingParticle(PHE, 0, 2); // CD2
+  AddFRMRotatingParticle(PHE, 0, 3); // CE1
+  AddFRMRotatingParticle(PHE, 0, 4); // CE2
+  AddFRMRotatingParticle(PHE, 0, 5); // CZ
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMRotatingParticle(PHE, 0, 6); // HB2
+    AddFRMRotatingParticle(PHE, 0, 7); // HB3
+    AddFRMRotatingParticle(PHE, 0, 8); // HD1
+    AddFRMRotatingParticle(PHE, 0, 9); // HD2
+    AddFRMRotatingParticle(PHE, 0, 10); // HE1
+    AddFRMRotatingParticle(PHE, 0, 11); // HE2
+    AddFRMRotatingParticle(PHE, 0, 12); // HZ
+  }
+
+  AddFRMRule(PHE, promod3::loop::BB_CB_INDEX, promod3::loop::PHE_CG_INDEX,
+             param.PHE_CB_CG_prefactors);
+  AddFRMFixParticle(PHE, 1, 0); // CG
+  AddFRMRotatingParticle(PHE, 1, 1); // CD1
+  AddFRMRotatingParticle(PHE, 1, 2); // CD2
+  AddFRMRotatingParticle(PHE, 1, 3); // CE1
+  AddFRMRotatingParticle(PHE, 1, 4); // CE2
+  AddFRMRotatingParticle(PHE, 1, 5); // CZ
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddFRMFixParticle(PHE, 1, 6); // HB2
+    AddFRMFixParticle(PHE, 1, 7); // HB2
+    AddFRMRotatingParticle(PHE, 1, 8); // CD1
+    AddFRMRotatingParticle(PHE, 1, 9); // CD2
+    AddFRMRotatingParticle(PHE, 1, 10); // CE1
+    AddFRMRotatingParticle(PHE, 1, 11); // CE2
+    AddFRMRotatingParticle(PHE, 1, 12); // CZ
+  }
+
+  if(cb_in_sidechain) {
+    int cb_idx = 6;
+    if(mode == FULL_ATOMIC_MODE) {
+      cb_idx = 13;
+    }
+    AddFRMFixParticle(PHE, 0, cb_idx);
+    AddFRMFixParticle(PHE, 1, cb_idx);
+  }
+
+  backbone_infos_[PHE].has_hydrogens = (mode == POLAR_HYDROGEN_MODE || 
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(PHE, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(PHE, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(PHE, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(PHE, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(PHE, "H", promod3::loop::PHE_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(PHE, "HA", promod3::loop::PHE_HA_INDEX, true);
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(PHE, "CB", promod3::loop::BB_CB_INDEX, false);
+  }
+
+
+  // ALA
+
+  // The hydrogen situation is a bit special here...
+  // If its full atomic, we only put the hydrogens in the sidechains
+  // if the CBeta is also there. Otherwise, everything goes into the
+  // backbone.
+  sidechain_infos_[ALA].has_hydrogens = (mode == FULL_ATOMIC_MODE &&
+                                         cb_in_sidechain);
+  sidechain_infos_[ALA].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::ALA];
+  sidechain_infos_[ALA].frm_t = param.frm_t[ost::conop::ALA];
+
+  if(cb_in_sidechain) {
+    AddInfo(ALA, "CB", promod3::loop::BB_CB_INDEX, false);
+    if(mode == FULL_ATOMIC_MODE) {
+      AddInfo(ALA, "HB1", promod3::loop::ALA_HB1_INDEX, true);
+      AddInfo(ALA, "HB2", promod3::loop::ALA_HB2_INDEX, true);
+      AddInfo(ALA, "HB3", promod3::loop::ALA_HB3_INDEX, true);
+    }
+  }
+
+  backbone_infos_[ALA].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(ALA, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(ALA, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(ALA, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(ALA, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ALA, "H", promod3::loop::ALA_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(ALA, "HA", promod3::loop::ALA_HA_INDEX, true);      
+  }
+
+  if(!cb_in_sidechain) {
+    AddBBInfo(ALA, "CB", promod3::loop::BB_CB_INDEX, false); 
+    if(mode == FULL_ATOMIC_MODE) {
+      AddBBInfo(ALA, "HB1", promod3::loop::ALA_HB1_INDEX, true);
+      AddBBInfo(ALA, "HB2", promod3::loop::ALA_HB2_INDEX, true);
+      AddBBInfo(ALA, "HB3", promod3::loop::ALA_HB3_INDEX, true);        
+    }
+  }
+
+
+  // GLY
+  sidechain_infos_[GLY].has_hydrogens = false;
+  sidechain_infos_[GLY].internal_e_prefactor = 
+  param.internal_e_prefactor[ost::conop::GLY];
+  sidechain_infos_[GLY].frm_t = param.frm_t[ost::conop::GLY];
+  
+  backbone_infos_[GLY].has_hydrogens = (mode == POLAR_HYDROGEN_MODE ||
+                                        mode == FULL_ATOMIC_MODE);
+  AddBBInfo(GLY, "N", promod3::loop::BB_N_INDEX, false);
+  AddBBInfo(GLY, "CA", promod3::loop::BB_CA_INDEX, false);
+  AddBBInfo(GLY, "C", promod3::loop::BB_C_INDEX, false);
+  AddBBInfo(GLY, "O", promod3::loop::BB_O_INDEX, false);
+
+  if(mode == POLAR_HYDROGEN_MODE || mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLY, "H", promod3::loop::GLY_H_INDEX, true);
+  }
+
+  if(mode == FULL_ATOMIC_MODE) {
+    AddBBInfo(GLY, "HA2", promod3::loop::GLY_HA2_INDEX, true);
+    AddBBInfo(GLY, "HA3", promod3::loop::GLY_HA3_INDEX, true);
+  }
+
+  for(uint i = 0; i <= XXX; ++i){
+    num_sidechain_particles_[i] = sidechain_infos_[i].particles.size();
+    num_frm_particles_[i] = num_sidechain_particles_[i];
+    for(uint j = 0; j < frm_rules_[i].size(); ++j){
+      num_frm_particles_[i] += (frm_rules_[i][j].prefactors.size() * 
+                                frm_rules_[i][j].rotating_particles.size());
+    }
+  }
+}
+
+
+RotamerInfo RotamerLookup::GetTerminalBackboneInfo(RotamerID id, bool n_ter,
+                                                   bool c_ter) {
+  // get a copy to work on
+  RotamerInfo info = backbone_infos_[id];
+
+  if(n_ter && mode_ != HEAVY_ATOM_MODE) {
+    // find and delete particle with name "H", add particles of 
+    // name "H1", "H2", "H3", only the first two in case of Proline
+    for(std::vector<ParticleInfo>::iterator it = info.particles.begin();
+        it != info.particles.end(); ++it) {
+      if(it->name == "H") {
+        info.particles.erase(it);
+        break;
+      }
+    }
+
+    ost::conop::AminoAcid aa = RotIDToAA(id);
+
+    ParticleInfo h1("H1", promod3::loop::AminoAcidLookup::GetInstance().GetH1Index(aa), true);
+    info.particles.push_back(h1);
+
+    ParticleInfo h2("H2", promod3::loop::AminoAcidLookup::GetInstance().GetH2Index(aa), true);
+    info.particles.push_back(h2);
+
+    if(aa != ost::conop::PRO) {
+      ParticleInfo h3("H3", promod3::loop::AminoAcidLookup::GetInstance().GetH3Index(aa), true);
+      info.particles.push_back(h3);
+    }
+  }
+
+  if(c_ter) {
+    // find particle with name "O" and mark it as terminal by setting its
+    // atom_index to -1
+    for(std::vector<ParticleInfo>::iterator it = info.particles.begin();
+        it != info.particles.end(); ++it) {
+      if(it->name == "O") {
+        it->atom_idx = -1;
+        break;
+      }
+    }
+    // atom_index of -2 marks terminal oxt
+    ParticleInfo oxt("OT", -2, false);
+    info.particles.push_back(oxt);
+  }
+
+  return info;
+}
+
+}} // ns
diff --git a/sidechain/src/rotamer_lookup.hh b/sidechain/src/rotamer_lookup.hh
new file mode 100644
index 00000000..50215ce8
--- /dev/null
+++ b/sidechain/src/rotamer_lookup.hh
@@ -0,0 +1,307 @@
+// Copyright (c) 2013-2018, SIB - Swiss Institute of Bioinformatics and 
+//                          Biozentrum - University of Basel
+// 
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// 
+//   http://www.apache.org/licenses/LICENSE-2.0
+// 
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef PROMOD3_ROTAMER_LOOKUP_HH
+#define PROMOD3_ROTAMER_LOOKUP_HH
+
+#include <vector>
+#include <ost/base.hh>
+#include <promod3/loop/amino_acid_atoms.hh>
+#include <promod3/sidechain/rotamer_id.hh>
+
+namespace promod3 { namespace sidechain {
+
+// Controls the particles that will be Constructed from the RotamerConstructor
+enum RotamerLookupMode{
+  HEAVY_ATOM_MODE,
+  POLAR_HYDROGEN_MODE,
+  FULL_ATOMIC_MODE
+};
+
+// Controls the parametrization of the rotamers
+// Must be filled by energy function specific RotamerConstructor and
+// passed to base class RotamerConstructor when calling constructor
+// of RotamerConstructor base class
+struct RotamerLookupParam {
+
+  RotamerLookupParam(bool default_parametrization = true) {
+
+    if(default_parametrization) {
+      for(int i = 0; i < ost::conop::XXX + 1; ++i) {
+        frm_t[i] = 1.0;
+        internal_e_prefactor[i] = 1.0;
+      }
+      std::vector<Real> default_prefactors;
+      default_prefactors.push_back(-1.0);
+      default_prefactors.push_back(1.0);
+      ARG_CA_CB_prefactors = default_prefactors;
+      ARG_CB_CG_prefactors = default_prefactors;
+      ARG_CG_CD_prefactors = default_prefactors;
+      ARG_CD_NE_prefactors = default_prefactors;
+      ASN_CA_CB_prefactors = default_prefactors;
+      ASN_CB_CG_prefactors = default_prefactors;
+      ASP_CA_CB_prefactors = default_prefactors;
+      ASP_CB_CG_prefactors = default_prefactors;
+      GLN_CA_CB_prefactors = default_prefactors;
+      GLN_CB_CG_prefactors = default_prefactors;
+      GLN_CG_CD_prefactors = default_prefactors;
+      GLU_CA_CB_prefactors = default_prefactors;
+      GLU_CB_CG_prefactors = default_prefactors;
+      GLU_CG_CD_prefactors = default_prefactors;
+      LYS_CA_CB_prefactors = default_prefactors;
+      LYS_CB_CG_prefactors = default_prefactors;
+      LYS_CG_CD_prefactors = default_prefactors;
+      LYS_CD_CE_prefactors = default_prefactors;
+      SER_CA_CB_prefactors = default_prefactors;
+      SER_CB_OG_prefactors = default_prefactors;                                    
+      CYS_CA_CB_prefactors = default_prefactors;  
+      MET_CA_CB_prefactors = default_prefactors;
+      MET_CB_CG_prefactors = default_prefactors;
+      MET_CG_SD_prefactors = default_prefactors;
+      TRP_CA_CB_prefactors = default_prefactors;
+      TRP_CB_CG_prefactors = default_prefactors;
+      TYR_CA_CB_prefactors = default_prefactors;
+      TYR_CB_CG_prefactors = default_prefactors;
+      TYR_CZ_OH_prefactors = default_prefactors;                                     
+      THR_CA_CB_prefactors = default_prefactors;
+      THR_CB_OG1_prefactors = default_prefactors; 
+      VAL_CA_CB_prefactors = default_prefactors;
+      ILE_CA_CB_prefactors = default_prefactors;
+      ILE_CB_CG1_prefactors = default_prefactors;
+      LEU_CA_CB_prefactors = default_prefactors;
+      LEU_CB_CG_prefactors = default_prefactors;
+      HIS_CA_CB_prefactors = default_prefactors;
+      HIS_CB_CG_prefactors = default_prefactors;
+      PHE_CA_CB_prefactors = default_prefactors;
+      PHE_CB_CG_prefactors = default_prefactors;
+    }
+  }
+
+  // the internal energy prefactor of the constructed rotamers
+  Real internal_e_prefactor[ost::conop::XXX + 1];
+
+  // frm temperature parameters
+  Real frm_t[ost::conop::XXX + 1];
+
+  // rotation bond specific frm prefactors
+  std::vector<Real> ARG_CA_CB_prefactors;
+  std::vector<Real> ARG_CB_CG_prefactors;
+  std::vector<Real> ARG_CG_CD_prefactors;
+  std::vector<Real> ARG_CD_NE_prefactors;
+
+  std::vector<Real> ASN_CA_CB_prefactors;
+  std::vector<Real> ASN_CB_CG_prefactors;
+
+  std::vector<Real> ASP_CA_CB_prefactors;
+  std::vector<Real> ASP_CB_CG_prefactors;
+
+  std::vector<Real> GLN_CA_CB_prefactors;
+  std::vector<Real> GLN_CB_CG_prefactors;
+  std::vector<Real> GLN_CG_CD_prefactors;
+
+  std::vector<Real> GLU_CA_CB_prefactors;
+  std::vector<Real> GLU_CB_CG_prefactors;
+  std::vector<Real> GLU_CG_CD_prefactors;
+
+  std::vector<Real> LYS_CA_CB_prefactors;
+  std::vector<Real> LYS_CB_CG_prefactors;
+  std::vector<Real> LYS_CG_CD_prefactors;
+  std::vector<Real> LYS_CD_CE_prefactors;
+
+  std::vector<Real> SER_CA_CB_prefactors;
+  std::vector<Real> SER_CB_OG_prefactors; // only relevant when hydrogen is 
+                                          // constructed
+
+  std::vector<Real> CYS_CA_CB_prefactors;  
+
+  std::vector<Real> MET_CA_CB_prefactors;
+  std::vector<Real> MET_CB_CG_prefactors;
+  std::vector<Real> MET_CG_SD_prefactors;
+
+  std::vector<Real> TRP_CA_CB_prefactors;
+  std::vector<Real> TRP_CB_CG_prefactors;
+
+  std::vector<Real> TYR_CA_CB_prefactors;
+  std::vector<Real> TYR_CB_CG_prefactors;
+  std::vector<Real> TYR_CZ_OH_prefactors; // only relevant when hydrogen is 
+                                          // constructed
+
+  std::vector<Real> THR_CA_CB_prefactors;
+  std::vector<Real> THR_CB_OG1_prefactors; // only relevant when hydrogen is 
+                                           // constructed
+
+  std::vector<Real> VAL_CA_CB_prefactors;
+
+  std::vector<Real> ILE_CA_CB_prefactors;
+  std::vector<Real> ILE_CB_CG1_prefactors;
+
+  std::vector<Real> LEU_CA_CB_prefactors;
+  std::vector<Real> LEU_CB_CG_prefactors;
+
+  std::vector<Real> HIS_CA_CB_prefactors;
+  std::vector<Real> HIS_CB_CG_prefactors;
+
+  std::vector<Real> PHE_CA_CB_prefactors;
+  std::vector<Real> PHE_CB_CG_prefactors;
+};
+
+
+struct ParticleInfo {
+
+  ParticleInfo() { }
+
+  ParticleInfo(const String& n, int idx, bool ih): name(n), atom_idx(idx),
+                                                   is_hydrogen(ih) { }
+
+  String name; 
+  int atom_idx;  // for AllAtomPositions 
+                 // (idx in HydrogenStorage if is_hydrogen is true)
+  bool is_hydrogen;
+};
+
+
+struct CustomHydrogenInfo {
+
+  CustomHydrogenInfo() { }
+  
+  CustomHydrogenInfo(int idx, int a_idx_one, int a_idx_two, int a_idx_three, 
+                          Real bl, Real a, int c_idx): atom_idx(idx),
+                                                       anchor_idx_one(a_idx_one), 
+                                                       anchor_idx_two(a_idx_two), 
+                                                       anchor_idx_three(a_idx_three), 
+                                                       bond_length(bl), angle(a),
+                                                       chi_idx(c_idx){ }
+  int atom_idx; //the idx in the hydrogen constructor
+  int anchor_idx_one; // idx in AllAtomPositions
+  int anchor_idx_two; 
+  int anchor_idx_three;
+  Real bond_length;
+  Real angle;
+  int chi_idx;
+};
+
+
+struct FRMRule {
+
+  FRMRule() { }
+  
+  int anchor_idx_one; // idx of heavy atom in RotamerConstructor::pos_buffer_
+  int anchor_idx_two; // idx of heavy atom in RotamerConstructor::pos_buffer_
+  std::vector<Real> prefactors;
+  // The following indices are NOT relative to any position buffer but rather
+  // to the ordering as the particles are defined in RotamerInfo
+  std::vector<int> fix_particles;
+  std::vector<int> rotating_particles;
+};
+
+
+struct RotamerInfo {
+
+  RotamerInfo() { }
+  
+  std::vector<ParticleInfo> particles;
+  std::vector<CustomHydrogenInfo> custom_hydrogens;
+  Real internal_e_prefactor;
+  Real frm_t;
+  bool has_hydrogens;
+};
+
+
+class RotamerLookup{
+
+public:
+  
+  RotamerLookup(bool cb_in_sidechain, 
+                RotamerLookupMode mode,
+                const RotamerLookupParam& param = RotamerLookupParam());
+
+  // Data access
+  const RotamerInfo& GetSidechainInfo(RotamerID id) const { 
+    return sidechain_infos_[id]; 
+  }
+
+  const RotamerInfo& GetBackboneInfo(RotamerID id) const { 
+    return backbone_infos_[id]; 
+  }
+
+  RotamerInfo GetTerminalBackboneInfo(RotamerID id, bool n_ter,
+                                      bool c_ter);
+
+  const std::vector<FRMRule>& GetFRMRules(RotamerID id) const { 
+    return frm_rules_[id]; 
+  }
+
+  int GetNumSidechainParticles(RotamerID id) const { 
+    return num_sidechain_particles_[id]; 
+  }
+
+  int GetNumFRMSidechainParticles(RotamerID id) const { 
+    return num_frm_particles_[id]; 
+  }
+
+private:
+
+  void AddInfo(RotamerID id, const String& name, int idx, bool is_h) {
+    ParticleInfo p(name, idx, is_h);
+    sidechain_infos_[id].particles.push_back(p);
+  }
+
+  void AddCustomHydrogenInfo(RotamerID id, int idx, 
+                             int a_idx_one, int a_idx_two, int a_idx_three, 
+                             Real bl, Real a, int c_idx) {
+    CustomHydrogenInfo i(idx, a_idx_one, a_idx_two, a_idx_three, bl, a, c_idx);
+    sidechain_infos_[id].custom_hydrogens.push_back(i);
+  }
+
+  void AddBBInfo(RotamerID id, const String& name, int idx, bool is_h) {
+    ParticleInfo p(name, idx, is_h);
+    backbone_infos_[id].particles.push_back(p);
+  }
+
+  void AddFRMRule(RotamerID id, int idx_one, int idx_two,
+                  const std::vector<Real>& prefactors){
+    frm_rules_[id].push_back(FRMRule());
+    frm_rules_[id].back().anchor_idx_one = idx_one;
+    frm_rules_[id].back().anchor_idx_two = idx_two;
+    frm_rules_[id].back().prefactors = prefactors;
+  }
+
+  void AddFRMFixParticle(RotamerID id, int rule_idx, int p_idx){
+    frm_rules_[id][rule_idx].fix_particles.push_back(p_idx);
+  }
+
+  void AddFRMRotatingParticle(RotamerID id, int rule_idx, int p_idx){
+    frm_rules_[id][rule_idx].rotating_particles.push_back(p_idx);
+  }
+
+  // To construct classical rotamers or as lookup for sidechain frame residues
+  RotamerInfo sidechain_infos_[XXX + 1];
+
+  // To construct backbone frame residues
+  RotamerInfo backbone_infos_[XXX + 1];
+
+  // Additional info required for generating frm rotamers
+  std::vector<FRMRule> frm_rules_[XXX + 1];
+
+  int num_sidechain_particles_[XXX + 1];
+  int num_frm_particles_[XXX + 1];
+
+  RotamerLookupMode mode_;
+};
+
+
+}} // ns
+
+#endif
diff --git a/sidechain/src/scwrl4_rotamer_constructor.cc b/sidechain/src/scwrl4_rotamer_constructor.cc
index 7619d2ec..687063f6 100644
--- a/sidechain/src/scwrl4_rotamer_constructor.cc
+++ b/sidechain/src/scwrl4_rotamer_constructor.cc
@@ -22,7 +22,36 @@
 #include <promod3/core/runtime_profiling.hh>
 #include <ost/conop/conop.hh>
 
-namespace{
+namespace promod3 { namespace sidechain {
+
+/// \brief Types of lone pair construction
+enum SCWRL4LPRule {
+  LONE_PAIR_CARBONYL, LONE_PAIR_COH, LONE_PAIR_CNC
+};
+
+/// \brief Info for lone pair construction (always involves 3 particles)
+/// -> indices are in same order as particles. The lone pair gets finally added
+/// to particle with p_idx
+/// A, B and C are indices as they are stored in AllAtomPositions, p_idx is the 
+/// index of the particle in the rotamer, where the lone pairs get added
+struct SCWRL4LPInfo {
+  SCWRL4LPInfo() { }
+  SCWRL4LPInfo(int idx_A, int idx_B, int idx_C,
+               bool a_ih, bool b_ih, bool c_ih, 
+               SCWRL4LPRule r)
+               : index_A(idx_A), index_B(idx_B),
+                 index_C(idx_C), A_is_hydrogen(a_ih),
+                 B_is_hydrogen(b_ih), C_is_hydrogen(c_ih),
+                 rule(r) { }
+  int index_A;
+  int index_B;
+  int index_C;
+  bool A_is_hydrogen;
+  bool B_is_hydrogen;
+  bool C_is_hydrogen;
+  SCWRL4LPRule rule;
+};
+
 
 // add lone pairs for carbonyl (X-C-O) to O particle p
 void _AddLonePairsCarbonyl(const geom::Vec3& x_pos, const geom::Vec3& c_pos,
@@ -37,6 +66,7 @@ void _AddLonePairsCarbonyl(const geom::Vec3& x_pos, const geom::Vec3& c_pos,
   p->AddLonePair(lone_pair_center_two - o_pos);
 }
 
+
 // add lone pairs for C-O-H combos (SER / THR / TYR) to O particle p
 void _AddLonePairsCOH(const geom::Vec3& c_pos, const geom::Vec3& o_pos,
                       const geom::Vec3& h_pos, 
@@ -67,7 +97,7 @@ void _AddLonePairsCNC(const geom::Vec3& c1_pos, const geom::Vec3& n_pos,
 }
 
 void EvalLonePairRule(promod3::sidechain::SCWRL4Param* p,
-                      promod3::sidechain::SCWRLLPRule rule,
+                      promod3::sidechain::SCWRL4LPRule rule,
                       const geom::Vec3& a,
                       const geom::Vec3& b,
                       const geom::Vec3& c) {
@@ -87,10 +117,12 @@ void EvalLonePairRule(promod3::sidechain::SCWRL4Param* p,
   }
 }
 
+
 inline bool _IsHydrogen(const String& element) {
   return element == "H" || element == "D";
 }
 
+
 // forward declaration
 struct _AtomInfo;
 
@@ -183,1425 +215,617 @@ _AtomSpecCPList _GetCarboxylAtoms(const _AtomInfo& atom_info) {
   return carbonyl_atoms;
 }
 
-}
-
-namespace promod3 { namespace sidechain {
-
-SCWRLRotamerLookup::SCWRLRotamerLookup(bool cb_in_sidechain) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-                                "SCWRLRotamerLookup::SCWRLRotamerLookup", 2);
-  
-  // ARG
-  sidechain_infos_[ARG].has_hydrogens = true;
-  sidechain_infos_[ARG].internal_e_prefactor = 2.27;
-  sidechain_infos_[ARG].frm_t = 1.23;
-
-  AddInfo(ARG, CH2Particle, 0.0, "CG", promod3::loop::ARG_CG_INDEX, false);
-  AddInfo(ARG, CH2Particle, 0.1, "CD", promod3::loop::ARG_CD_INDEX, false);
-  AddInfo(ARG, NParticle, -0.4, "NE", promod3::loop::ARG_NE_INDEX, false);
-  AddInfo(ARG, CParticle, 0.5, "CZ", promod3::loop::ARG_CZ_INDEX, false);
-  AddInfo(ARG, NParticle, -0.45, "NH1", promod3::loop::ARG_NH1_INDEX, false);
-  AddInfo(ARG, NParticle, -0.45, "NH2", promod3::loop::ARG_NH2_INDEX, false);
-  AddInfo(ARG, HParticle, 0.3, "HE", promod3::loop::ARG_HE_INDEX, true);
-  AddInfo(ARG, HParticle, 0.35, "HH11", promod3::loop::ARG_HH11_INDEX, true);
-  AddInfo(ARG, HParticle, 0.35, "HH12", promod3::loop::ARG_HH12_INDEX, true);
-  AddInfo(ARG, HParticle, 0.35, "HH21", promod3::loop::ARG_HH21_INDEX, true);
-  AddInfo(ARG, HParticle, 0.35, "HH22", promod3::loop::ARG_HH22_INDEX, true);
-
-  if(cb_in_sidechain) {
-    AddInfo(ARG, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(ARG, promod3::loop::ARG_HE_INDEX, promod3::loop::ARG_NE_INDEX, 6);
-  AddPDir(ARG, promod3::loop::ARG_HH11_INDEX, promod3::loop::ARG_NH1_INDEX, 7);
-  AddPDir(ARG, promod3::loop::ARG_HH12_INDEX, promod3::loop::ARG_NH1_INDEX, 8);
-  AddPDir(ARG, promod3::loop::ARG_HH21_INDEX, promod3::loop::ARG_NH2_INDEX, 9);
-  AddPDir(ARG, promod3::loop::ARG_HH22_INDEX, promod3::loop::ARG_NH2_INDEX, 10);
-
-  AddFRMRule(ARG, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(ARG, 0, -0.87);
-  AddFRMPrefactor(ARG, 0, 0.87);
-  AddFRMRotatingParticle(ARG, 0, 0);
-  AddFRMRotatingParticle(ARG, 0, 1);
-  AddFRMRotatingParticle(ARG, 0, 2);
-  AddFRMRotatingParticle(ARG, 0, 3);
-  AddFRMRotatingParticle(ARG, 0, 4);
-  AddFRMRotatingParticle(ARG, 0, 5);
-  AddFRMRotatingParticle(ARG, 0, 6);
-  AddFRMRotatingParticle(ARG, 0, 7);
-  AddFRMRotatingParticle(ARG, 0, 8);
-  AddFRMRotatingParticle(ARG, 0, 9);
-  AddFRMRotatingParticle(ARG, 0, 10);
-
-  AddFRMRule(ARG, promod3::loop::BB_CB_INDEX, promod3::loop::ARG_CG_INDEX);
-  AddFRMPrefactor(ARG, 1, -1.62);
-  AddFRMPrefactor(ARG, 1, 1.62);
-  AddFRMFixParticle(ARG, 1, 0);
-  AddFRMRotatingParticle(ARG, 1, 1);
-  AddFRMRotatingParticle(ARG, 1, 2);
-  AddFRMRotatingParticle(ARG, 1, 3);
-  AddFRMRotatingParticle(ARG, 1, 4);
-  AddFRMRotatingParticle(ARG, 1, 5);
-  AddFRMRotatingParticle(ARG, 1, 6);
-  AddFRMRotatingParticle(ARG, 1, 7);
-  AddFRMRotatingParticle(ARG, 1, 8);
-  AddFRMRotatingParticle(ARG, 1, 9);
-  AddFRMRotatingParticle(ARG, 1, 10);
-
-  AddFRMRule(ARG, promod3::loop::ARG_CG_INDEX, promod3::loop::ARG_CD_INDEX);
-  AddFRMPrefactor(ARG, 2, -1.67);
-  AddFRMPrefactor(ARG, 2, 1.67);
-  AddFRMFixParticle(ARG, 2, 0);
-  AddFRMFixParticle(ARG, 2, 1);
-  AddFRMRotatingParticle(ARG, 2, 2);
-  AddFRMRotatingParticle(ARG, 2, 3);
-  AddFRMRotatingParticle(ARG, 2, 4);
-  AddFRMRotatingParticle(ARG, 2, 5);
-  AddFRMRotatingParticle(ARG, 2, 6);
-  AddFRMRotatingParticle(ARG, 2, 7);
-  AddFRMRotatingParticle(ARG, 2, 8);
-  AddFRMRotatingParticle(ARG, 2, 9);
-  AddFRMRotatingParticle(ARG, 2, 10);
-
-  AddFRMRule(ARG, promod3::loop::ARG_CD_INDEX, promod3::loop::ARG_NE_INDEX);
-  AddFRMPrefactor(ARG, 3, -0.73);
-  AddFRMPrefactor(ARG, 3, 0.73);
-  AddFRMFixParticle(ARG, 3, 0);
-  AddFRMFixParticle(ARG, 3, 1);
-  AddFRMFixParticle(ARG, 3, 2);
-  AddFRMRotatingParticle(ARG, 3, 3);
-  AddFRMRotatingParticle(ARG, 3, 4);
-  AddFRMRotatingParticle(ARG, 3, 5);
-  AddFRMRotatingParticle(ARG, 3, 6);
-  AddFRMRotatingParticle(ARG, 3, 7);
-  AddFRMRotatingParticle(ARG, 3, 8);
-  AddFRMRotatingParticle(ARG, 3, 9);
-  AddFRMRotatingParticle(ARG, 3, 10);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(ARG, 0, 11);
-    AddFRMFixParticle(ARG, 1, 11);
-    AddFRMFixParticle(ARG, 2, 11);
-    AddFRMFixParticle(ARG, 3, 11);
-  }
-
-  backbone_infos_[ARG].has_hydrogens = true;
-  AddBBInfo(ARG, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(ARG, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(ARG, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(ARG, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(ARG, HParticle, 0.25, "H", promod3::loop::ARG_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(ARG, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(ARG, promod3::loop::ARG_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(ARG, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // ASN
-  sidechain_infos_[ASN].has_hydrogens = true;
-  sidechain_infos_[ASN].internal_e_prefactor = 1.80;
-  sidechain_infos_[ASN].frm_t = 1.41;
-
-  AddInfo(ASN, CParticle, 0.55, "CG", promod3::loop::ASN_CG_INDEX, false);
-  AddInfo(ASN, OParticle, -0.55, "OD1", promod3::loop::ASN_OD1_INDEX, false);
-  AddInfo(ASN, NParticle, -0.6, "ND2", promod3::loop::ASN_ND2_INDEX, false);
-  AddInfo(ASN, HParticle, 0.3, "HD21", promod3::loop::ASN_HD21_INDEX, true);
-  AddInfo(ASN, HParticle, 0.3, "HD22", promod3::loop::ASN_HD22_INDEX, true);
-
-  if(cb_in_sidechain) {
-    AddInfo(ASN, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(ASN, promod3::loop::ASN_HD21_INDEX, promod3::loop::ASN_ND2_INDEX, 3);
-  AddPDir(ASN, promod3::loop::ASN_HD22_INDEX, promod3::loop::ASN_ND2_INDEX, 4);
-  AddLP(ASN, promod3::loop::ASN_ND2_INDEX, promod3::loop::ASN_CG_INDEX, 
-        promod3::loop::ASN_OD1_INDEX, false, false, false, 1, LONE_PAIR_CARBONYL);
-
-  AddFRMRule(ASN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(ASN, 0, -0.62);
-  AddFRMPrefactor(ASN, 0, 0.62);
-  AddFRMRotatingParticle(ASN, 0, 0);
-  AddFRMRotatingParticle(ASN, 0, 1);
-  AddFRMRotatingParticle(ASN, 0, 2);
-  AddFRMRotatingParticle(ASN, 0, 3);
-  AddFRMRotatingParticle(ASN, 0, 4);
-
-  AddFRMRule(ASN, promod3::loop::BB_CB_INDEX, promod3::loop::ASN_CG_INDEX);
-  AddFRMPrefactor(ASN, 1, -1.93);
-  AddFRMPrefactor(ASN, 1, 1.93);
-  AddFRMFixParticle(ASN, 1, 0);
-  AddFRMRotatingParticle(ASN, 1, 1);
-  AddFRMRotatingParticle(ASN, 1, 2);
-  AddFRMRotatingParticle(ASN, 1, 3);
-  AddFRMRotatingParticle(ASN, 1, 4);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(ASN, 0, 5);
-    AddFRMFixParticle(ASN, 1, 5);
-  }
-
-  backbone_infos_[ASN].has_hydrogens = true;
-  AddBBInfo(ASN, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(ASN, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(ASN, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(ASN, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(ASN, HParticle, 0.25, "H", promod3::loop::ASN_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(ASN, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(ASN, promod3::loop::ASN_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(ASN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // ASP
-  sidechain_infos_[ASP].internal_e_prefactor = 2.44;
-  sidechain_infos_[ASP].frm_t = 1.48;
-  sidechain_infos_[ASP].has_hydrogens = false;
-
-  AddInfo(ASP, CParticle, 0.36, "CG", promod3::loop::ASP_CG_INDEX, false);
-  AddInfo(ASP, OParticle, -0.60, "OD1", promod3::loop::ASP_OD1_INDEX, false);
-  AddInfo(ASP, OParticle, -0.60, "OD2", promod3::loop::ASP_OD2_INDEX, false);
-
-  if(cb_in_sidechain) {
-    AddInfo(ASP, CH2Particle, -0.16, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddLP(ASP, promod3::loop::ASP_OD2_INDEX, promod3::loop::ASP_CG_INDEX, 
-        promod3::loop::ASP_OD1_INDEX, false, false, false, 1, LONE_PAIR_CARBONYL);
-  AddLP(ASP, promod3::loop::ASP_OD1_INDEX, promod3::loop::ASP_CG_INDEX, 
-        promod3::loop::ASP_OD2_INDEX, false, false, false, 2, LONE_PAIR_CARBONYL);
-
-  AddFRMRule(ASP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(ASP, 0, -1.59);
-  AddFRMPrefactor(ASP, 0, 1.59);
-  AddFRMRotatingParticle(ASP, 0, 0);
-  AddFRMRotatingParticle(ASP, 0, 1);
-  AddFRMRotatingParticle(ASP, 0, 2);
-
-  AddFRMRule(ASP, promod3::loop::BB_CB_INDEX, promod3::loop::ASP_CG_INDEX);
-  AddFRMPrefactor(ASP, 1, -0.63);
-  AddFRMPrefactor(ASP, 1, 0.63);
-  AddFRMFixParticle(ASP, 1, 0);
-  AddFRMRotatingParticle(ASP, 1, 1);
-  AddFRMRotatingParticle(ASP, 1, 2);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(ASP, 0, 3);
-    AddFRMFixParticle(ASP, 1, 3);
-  }
-
-  backbone_infos_[ASP].has_hydrogens = true;
-  AddBBInfo(ASP, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(ASP, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(ASP, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(ASP, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(ASP, HParticle, 0.25, "H", promod3::loop::ASP_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(ASP, CH2Particle, -0.16, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(ASP, promod3::loop::ASP_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(ASP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // GLN
-  sidechain_infos_[GLN].has_hydrogens = true;
-  sidechain_infos_[GLN].internal_e_prefactor = 1.61;
-  sidechain_infos_[GLN].frm_t = 1.32;
-
-  AddInfo(GLN, CH2Particle, 0.0, "CG", promod3::loop::GLN_CG_INDEX, false);
-  AddInfo(GLN, CParticle, 0.55, "CD", promod3::loop::GLN_CD_INDEX, false);
-  AddInfo(GLN, OParticle, -0.55, "OE1", promod3::loop::GLN_OE1_INDEX, false);
-  AddInfo(GLN, NParticle, -0.60, "NE2", promod3::loop::GLN_NE2_INDEX, false);
-  AddInfo(GLN, HParticle, 0.3, "HE21", promod3::loop::GLN_HE21_INDEX, true);
-  AddInfo(GLN, HParticle, 0.3, "HE22", promod3::loop::GLN_HE22_INDEX, true);
-
-  if(cb_in_sidechain) {
-    AddInfo(GLN, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(GLN, promod3::loop::GLN_HE21_INDEX, promod3::loop::GLN_NE2_INDEX, 4);
-  AddPDir(GLN, promod3::loop::GLN_HE22_INDEX, promod3::loop::GLN_NE2_INDEX, 5);
-  AddLP(GLN, promod3::loop::GLN_NE2_INDEX, promod3::loop::GLN_CD_INDEX, 
-        promod3::loop::GLN_OE1_INDEX, false, false, false, 2, LONE_PAIR_CARBONYL);
-
-  AddFRMRule(GLN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(GLN, 0, -1.55);
-  AddFRMPrefactor(GLN, 0, 1.55);
-  AddFRMRotatingParticle(GLN, 0, 0);
-  AddFRMRotatingParticle(GLN, 0, 1);
-  AddFRMRotatingParticle(GLN, 0, 2);
-  AddFRMRotatingParticle(GLN, 0, 3);
-  AddFRMRotatingParticle(GLN, 0, 4);
-  AddFRMRotatingParticle(GLN, 0, 5);
-
-  AddFRMRule(GLN, promod3::loop::BB_CB_INDEX, promod3::loop::GLN_CG_INDEX);
-  AddFRMPrefactor(GLN, 1, -0.53);
-  AddFRMPrefactor(GLN, 1, 0.53);
-  AddFRMFixParticle(GLN, 1, 0);
-  AddFRMRotatingParticle(GLN, 1, 1);
-  AddFRMRotatingParticle(GLN, 1, 2);
-  AddFRMRotatingParticle(GLN, 1, 3);
-  AddFRMRotatingParticle(GLN, 1, 4);
-  AddFRMRotatingParticle(GLN, 1, 5);
-
-  AddFRMRule(GLN, promod3::loop::GLN_CG_INDEX, promod3::loop::GLN_CD_INDEX);
-  AddFRMPrefactor(GLN, 2, -1.89);
-  AddFRMPrefactor(GLN, 2, 1.89);
-  AddFRMFixParticle(GLN, 2, 0);
-  AddFRMFixParticle(GLN, 2, 1);
-  AddFRMRotatingParticle(GLN, 2, 2);
-  AddFRMRotatingParticle(GLN, 2, 3);
-  AddFRMRotatingParticle(GLN, 2, 4);
-  AddFRMRotatingParticle(GLN, 2, 5);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(GLN, 0, 6);
-    AddFRMFixParticle(GLN, 1, 6);
-    AddFRMFixParticle(GLN, 2, 6);
-  }
-
-  backbone_infos_[GLN].has_hydrogens = true;
-  AddBBInfo(GLN, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(GLN, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(GLN, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(GLN, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(GLN, HParticle, 0.25, "H", promod3::loop::GLN_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(GLN, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(GLN, promod3::loop::GLN_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(GLN, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // GLU
-  sidechain_infos_[GLU].has_hydrogens = false;
-  sidechain_infos_[GLU].internal_e_prefactor = 1.85;
-  sidechain_infos_[GLU].frm_t = 0.94;
-
-  AddInfo(GLU, CH2Particle, -0.16, "CG", promod3::loop::GLU_CG_INDEX, false);
-  AddInfo(GLU, CParticle, 0.36, "CD", promod3::loop::GLU_CD_INDEX, false);
-  AddInfo(GLU, OParticle, -0.60, "OE1", promod3::loop::GLU_OE1_INDEX, false);
-  AddInfo(GLU, OParticle, -0.60, "OE2", promod3::loop::GLU_OE2_INDEX, false);
-
-  if(cb_in_sidechain) {
-    AddInfo(GLU, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddLP(GLU, promod3::loop::GLU_OE2_INDEX, promod3::loop::GLU_CD_INDEX, 
-        promod3::loop::GLU_OE1_INDEX, false, false, false, 2, LONE_PAIR_CARBONYL);
-  AddLP(GLU, promod3::loop::GLU_OE1_INDEX, promod3::loop::GLU_CD_INDEX, 
-        promod3::loop::GLU_OE2_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  AddFRMRule(GLU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(GLU, 0, -0.82);
-  AddFRMPrefactor(GLU, 0, 0.82);
-  AddFRMRotatingParticle(GLU, 0, 0);
-  AddFRMRotatingParticle(GLU, 0, 1);
-  AddFRMRotatingParticle(GLU, 0, 2);
-  AddFRMRotatingParticle(GLU, 0, 3);
-
-  AddFRMRule(GLU, promod3::loop::BB_CB_INDEX, promod3::loop::GLU_CG_INDEX);
-  AddFRMPrefactor(GLU, 1, -1.57);
-  AddFRMPrefactor(GLU, 1, 1.57);
-  AddFRMFixParticle(GLU, 1, 0);
-  AddFRMRotatingParticle(GLU, 1, 1);
-  AddFRMRotatingParticle(GLU, 1, 2);
-  AddFRMRotatingParticle(GLU, 1, 3);
-
-  AddFRMRule(GLU, promod3::loop::GLU_CG_INDEX, promod3::loop::GLU_CD_INDEX);
-  AddFRMPrefactor(GLU, 2, -0.76);
-  AddFRMPrefactor(GLU, 2, 0.76);
-  AddFRMFixParticle(GLU, 2, 0);
-  AddFRMFixParticle(GLU, 2, 1);
-  AddFRMRotatingParticle(GLU, 2, 2);
-  AddFRMRotatingParticle(GLU, 2, 3);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(GLU, 0, 4);
-    AddFRMFixParticle(GLU, 1, 4);
-    AddFRMFixParticle(GLU, 2, 4);
-  }
-
-  backbone_infos_[GLU].has_hydrogens = true;
-  AddBBInfo(GLU, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(GLU, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(GLU, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(GLU, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(GLU, HParticle, 0.25, "H", promod3::loop::GLU_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(GLU, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(GLU, promod3::loop::GLU_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(GLU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // LYS
-  sidechain_infos_[LYS].has_hydrogens = true;
-  sidechain_infos_[LYS].internal_e_prefactor = 2.13;
-  sidechain_infos_[LYS].frm_t = 1.27;
-
-  AddInfo(LYS, CH2Particle, 0.0, "CG", promod3::loop::LYS_CG_INDEX,false);
-  AddInfo(LYS, CH2Particle, 0.0, "CD", promod3::loop::LYS_CD_INDEX,false);
-  AddInfo(LYS, CH2Particle, 0.25, "CE", promod3::loop::LYS_CE_INDEX,false);
-  AddInfo(LYS, NParticle, -0.3, "NZ", promod3::loop::LYS_NZ_INDEX,false);
-  AddInfo(LYS, HParticle, 0.35, "HZ1", promod3::loop::LYS_HZ1_INDEX,true);
-  AddInfo(LYS, HParticle, 0.35, "HZ2", promod3::loop::LYS_HZ2_INDEX,true);
-  AddInfo(LYS, HParticle, 0.35, "HZ3", promod3::loop::LYS_HZ3_INDEX,true);
-
-  if(cb_in_sidechain) {
-    AddInfo(LYS, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(LYS, promod3::loop::LYS_HZ1_INDEX, promod3::loop::LYS_NZ_INDEX, 4);
-  AddPDir(LYS, promod3::loop::LYS_HZ2_INDEX, promod3::loop::LYS_NZ_INDEX, 5);
-  AddPDir(LYS, promod3::loop::LYS_HZ3_INDEX, promod3::loop::LYS_NZ_INDEX, 6);
-
-  AddFRMRule(LYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(LYS, 0, -1.62);
-  AddFRMPrefactor(LYS, 0, 1.62);
-  AddFRMRotatingParticle(LYS, 0, 0);
-  AddFRMRotatingParticle(LYS, 0, 1);
-  AddFRMRotatingParticle(LYS, 0, 2);
-  AddFRMRotatingParticle(LYS, 0, 3);
-  AddFRMRotatingParticle(LYS, 0, 4);
-  AddFRMRotatingParticle(LYS, 0, 5);
-  AddFRMRotatingParticle(LYS, 0, 6);
-
-  AddFRMRule(LYS, promod3::loop::BB_CB_INDEX, promod3::loop::LYS_CG_INDEX);
-  AddFRMPrefactor(LYS, 1, -0.99);
-  AddFRMPrefactor(LYS, 1, 0.99);
-  AddFRMFixParticle(LYS, 1, 0);
-  AddFRMRotatingParticle(LYS, 1, 1);
-  AddFRMRotatingParticle(LYS, 1, 2);
-  AddFRMRotatingParticle(LYS, 1, 3);
-  AddFRMRotatingParticle(LYS, 1, 4);
-  AddFRMRotatingParticle(LYS, 1, 5);
-  AddFRMRotatingParticle(LYS, 1, 6);
-
-  AddFRMRule(LYS, promod3::loop::LYS_CG_INDEX, promod3::loop::LYS_CD_INDEX);
-  AddFRMPrefactor(LYS, 2, -0.96);
-  AddFRMPrefactor(LYS, 2, 0.96);
-  AddFRMFixParticle(LYS, 2, 0);
-  AddFRMFixParticle(LYS, 2, 1);
-  AddFRMRotatingParticle(LYS, 2, 2);
-  AddFRMRotatingParticle(LYS, 2, 3);
-  AddFRMRotatingParticle(LYS, 2, 4);
-  AddFRMRotatingParticle(LYS, 2, 5);
-  AddFRMRotatingParticle(LYS, 2, 6);
-
-  AddFRMRule(LYS, promod3::loop::LYS_CD_INDEX, promod3::loop::LYS_CE_INDEX);
-  AddFRMPrefactor(LYS, 3, -1.49);
-  AddFRMPrefactor(LYS, 3, 1.49);
-  AddFRMFixParticle(LYS, 3, 0);
-  AddFRMFixParticle(LYS, 3, 1);
-  AddFRMFixParticle(LYS, 3, 2);
-  AddFRMRotatingParticle(LYS, 3, 3);
-  AddFRMRotatingParticle(LYS, 3, 4);
-  AddFRMRotatingParticle(LYS, 3, 5);
-  AddFRMRotatingParticle(LYS, 3, 6);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(LYS, 0, 7);
-    AddFRMFixParticle(LYS, 1, 7);
-    AddFRMFixParticle(LYS, 2, 7);
-    AddFRMFixParticle(LYS, 3, 7);
-  }
-
-  backbone_infos_[LYS].has_hydrogens = true;
-  AddBBInfo(LYS, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(LYS, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(LYS, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(LYS, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(LYS, HParticle, 0.25, "H", promod3::loop::LYS_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(LYS, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(LYS, promod3::loop::LYS_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(LYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // SER
-  sidechain_infos_[SER].has_hydrogens = true;
-  sidechain_infos_[SER].internal_e_prefactor = 2.78;
-  sidechain_infos_[SER].frm_t = 3.53;
-
-  AddInfo(SER, OParticle, -0.65, "OG", promod3::loop::SER_OG_INDEX, false);
-  AddInfo(SER, HParticle, 0.40, "HG", promod3::loop::SER_HG_INDEX, true);
-
-  if(cb_in_sidechain) {
-    AddInfo(SER, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(SER, promod3::loop::SER_HG_INDEX, promod3::loop::SER_OG_INDEX, 1);
-  AddLP(SER, promod3::loop::BB_CB_INDEX, promod3::loop::SER_OG_INDEX, 
-        promod3::loop::SER_HG_INDEX, false, false, true, 0, LONE_PAIR_COH);
-  AddCustomHydrogenInfo(SER, promod3::loop::SER_HG_INDEX, 
-                        promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX, 
-                        promod3::loop::SER_OG_INDEX,
-                        0.96, 1.85, 1);
-
-  AddFRMRule(SER, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(SER, 0, -0.65);
-  AddFRMPrefactor(SER, 0, 0.65);
-  AddFRMRotatingParticle(SER, 0, 0);
-  AddFRMRotatingParticle(SER, 0, 1);
-
-  AddFRMRule(SER, promod3::loop::BB_CB_INDEX, promod3::loop::SER_OG_INDEX);
-  AddFRMPrefactor(SER, 1, -2.98);
-  AddFRMPrefactor(SER, 1, 2.98);
-  AddFRMFixParticle(SER, 1, 0);
-  AddFRMRotatingParticle(SER, 1, 1);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(SER, 0, 2);
-    AddFRMFixParticle(SER, 1, 2);
-  }
-
-  backbone_infos_[SER].has_hydrogens = true;
-  AddBBInfo(SER, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(SER, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(SER, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(SER, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(SER, HParticle, 0.25, "H", promod3::loop::SER_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(SER, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(SER, promod3::loop::SER_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(SER, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // CYS
-  sidechain_infos_[CYS].has_hydrogens = false;
-  sidechain_infos_[CYS].internal_e_prefactor = 4.07;
-  sidechain_infos_[CYS].frm_t = 1.69;
-
-  AddInfo(CYS, SParticle, -0.19, "SG", promod3::loop::CYS_SG_INDEX, false);
-
-  if(cb_in_sidechain) {
-    AddInfo(CYS, CH2Particle, 0.19, "CB", promod3::loop::BB_CB_INDEX, false);  
-  }
-
-  AddFRMRule(CYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(CYS, 0, -1.69);
-  AddFRMPrefactor(CYS, 0, 1.69);
-  AddFRMRotatingParticle(CYS, 0, 0);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(CYS, 0, 1);
-  }
-
-  backbone_infos_[CYS].has_hydrogens = true;
-  AddBBInfo(CYS, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(CYS, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(CYS, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(CYS, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(CYS, HParticle, 0.25, "H", promod3::loop::CYS_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(CYS, CH2Particle, 0.19, "CB", promod3::loop::BB_CB_INDEX, false);   
-  }
-
-  AddBBPDir(CYS, promod3::loop::CYS_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(CYS, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // CYH
-  sidechain_infos_[CYH] = sidechain_infos_[CYS];
-  frm_rules_[CYH] = frm_rules_[CYS];
-  backbone_infos_[CYH] = backbone_infos_[CYS];
-
-  // CYD
-  sidechain_infos_[CYD] = sidechain_infos_[CYS];
-  frm_rules_[CYD] = frm_rules_[CYS];
-  backbone_infos_[CYD] = backbone_infos_[CYS];
-
-  // MET
-  sidechain_infos_[MET].has_hydrogens = false;
-  sidechain_infos_[MET].internal_e_prefactor = 1.95;
-  sidechain_infos_[MET].frm_t = 1.77;
-
-  AddInfo(MET, CH2Particle, 0.06, "CG", promod3::loop::MET_CG_INDEX,false);
-  AddInfo(MET, SParticle, -0.12, "SD", promod3::loop::MET_SD_INDEX,false);
-  AddInfo(MET, CH3Particle, 0.06, "CE", promod3::loop::MET_CE_INDEX,false);
-
-  if(cb_in_sidechain) {
-    AddInfo(MET, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddFRMRule(MET, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(MET, 0, -0.97);
-  AddFRMPrefactor(MET, 0, 0.97);
-  AddFRMRotatingParticle(MET, 0, 0);
-  AddFRMRotatingParticle(MET, 0, 1);
-  AddFRMRotatingParticle(MET, 0, 2);
-
-  AddFRMRule(MET, promod3::loop::BB_CB_INDEX, promod3::loop::MET_CG_INDEX);
-  AddFRMPrefactor(MET, 1, -1.54);
-  AddFRMPrefactor(MET, 1, 1.54);
-  AddFRMFixParticle(MET, 1, 0);
-  AddFRMRotatingParticle(MET, 1, 1);
-  AddFRMRotatingParticle(MET, 1, 2);
-
-  AddFRMRule(MET, promod3::loop::MET_CG_INDEX, promod3::loop::MET_SD_INDEX);
-  AddFRMPrefactor(MET, 2, -1.21);
-  AddFRMPrefactor(MET, 2, 1.21);
-  AddFRMFixParticle(MET, 2, 0);
-  AddFRMFixParticle(MET, 2, 1);
-  AddFRMRotatingParticle(MET, 2, 2);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(MET, 0, 3);
-    AddFRMFixParticle(MET, 1, 3);
-    AddFRMFixParticle(MET, 2, 3);
-  }
-
-  backbone_infos_[MET].has_hydrogens = true;
-  AddBBInfo(MET, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(MET, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(MET, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(MET, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(MET, HParticle, 0.25, "H", promod3::loop::MET_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(MET, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(MET, promod3::loop::MET_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(MET, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // TRP
-  sidechain_infos_[TRP].has_hydrogens = true;
-  sidechain_infos_[TRP].internal_e_prefactor = 3.24;
-  sidechain_infos_[TRP].frm_t = 0.99;
-
-  AddInfo(TRP, CParticle,-0.03, "CG", promod3::loop::TRP_CG_INDEX,false);
-  AddInfo(TRP, CParticle, 0.06, "CD1", promod3::loop::TRP_CD1_INDEX,false);
-  AddInfo(TRP, CParticle, 0.10, "CD2", promod3::loop::TRP_CD2_INDEX,false);
-  AddInfo(TRP, CParticle, -0.04, "CE2", promod3::loop::TRP_CE2_INDEX,false);
-  AddInfo(TRP, NParticle, -0.36, "NE1", promod3::loop::TRP_NE1_INDEX,false);
-  AddInfo(TRP, CParticle, -0.03, "CE3", promod3::loop::TRP_CE3_INDEX,false);
-  AddInfo(TRP, CParticle, 0.00, "CZ3", promod3::loop::TRP_CZ3_INDEX,false);
-  AddInfo(TRP, CParticle, 0.00, "CH2", promod3::loop::TRP_CH2_INDEX,false);
-  AddInfo(TRP, CParticle, 0.00, "CZ2", promod3::loop::TRP_CZ2_INDEX,false);
-  AddInfo(TRP, HParticle, 0.30, "HE1", promod3::loop::TRP_HE1_INDEX,true);
-
-  if(cb_in_sidechain) {
-    AddInfo(TRP, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(TRP, promod3::loop::TRP_HE1_INDEX, promod3::loop::TRP_NE1_INDEX, 9);
-
-  AddFRMRule(TRP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(TRP, 0, -1.28);
-  AddFRMPrefactor(TRP, 0, 1.28);
-  AddFRMRotatingParticle(TRP, 0, 0);
-  AddFRMRotatingParticle(TRP, 0, 1);
-  AddFRMRotatingParticle(TRP, 0, 2);
-  AddFRMRotatingParticle(TRP, 0, 3);
-  AddFRMRotatingParticle(TRP, 0, 4);
-  AddFRMRotatingParticle(TRP, 0, 5);
-  AddFRMRotatingParticle(TRP, 0, 6);
-  AddFRMRotatingParticle(TRP, 0, 7);
-  AddFRMRotatingParticle(TRP, 0, 8);
-  AddFRMRotatingParticle(TRP, 0, 9);
-
-  AddFRMRule(TRP, promod3::loop::BB_CB_INDEX, promod3::loop::TRP_CG_INDEX);
-  AddFRMPrefactor(TRP, 1, -1.48);
-  AddFRMPrefactor(TRP, 1, 1.48);
-  AddFRMFixParticle(TRP, 1, 0);
-  AddFRMRotatingParticle(TRP, 1, 1);
-  AddFRMRotatingParticle(TRP, 1, 2);
-  AddFRMRotatingParticle(TRP, 1, 3);
-  AddFRMRotatingParticle(TRP, 1, 4);
-  AddFRMRotatingParticle(TRP, 1, 5);
-  AddFRMRotatingParticle(TRP, 1, 6);
-  AddFRMRotatingParticle(TRP, 1, 7);
-  AddFRMRotatingParticle(TRP, 1, 8);
-  AddFRMRotatingParticle(TRP, 1, 9);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(TRP, 0, 10);
-    AddFRMFixParticle(TRP, 1, 10);
-  }
-
-  backbone_infos_[TRP].has_hydrogens = true;
-  AddBBInfo(TRP, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(TRP, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(TRP, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(TRP, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(TRP, HParticle, 0.25, "H", promod3::loop::TRP_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(TRP, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(TRP, promod3::loop::TRP_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(TRP, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // TYR
-  sidechain_infos_[TYR].has_hydrogens = true;
-  sidechain_infos_[TYR].internal_e_prefactor = 2.00;
-  sidechain_infos_[TYR].frm_t = 1.96;
-
-  AddInfo(TYR, CParticle, 0.0, "CG", promod3::loop::TYR_CG_INDEX,false);
-  AddInfo(TYR, CParticle, 0.0, "CD1", promod3::loop::TYR_CD1_INDEX,false);
-  AddInfo(TYR, CParticle, 0.0, "CD2", promod3::loop::TYR_CD2_INDEX,false);
-  AddInfo(TYR, CParticle, 0.0, "CE1", promod3::loop::TYR_CE1_INDEX,false);
-  AddInfo(TYR, CParticle, 0.0, "CE2", promod3::loop::TYR_CE2_INDEX,false);
-  AddInfo(TYR, CParticle, 0.25, "CZ", promod3::loop::TYR_CZ_INDEX,false);
-  AddInfo(TYR, OParticle, -0.65, "OH", promod3::loop::TYR_OH_INDEX,false);
-  AddInfo(TYR, HParticle, 0.40, "HH", promod3::loop::TYR_HH_INDEX,true);
-
-  if(cb_in_sidechain) {
-    AddInfo(TYR, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(TYR, promod3::loop::TYR_HH_INDEX, promod3::loop::TYR_OH_INDEX, 7);
-  AddLP(TYR, promod3::loop::TYR_CZ_INDEX, promod3::loop::TYR_OH_INDEX, 
-        promod3::loop::TYR_HH_INDEX, false, false, true, 6, LONE_PAIR_COH);
-  AddCustomHydrogenInfo(TYR, promod3::loop::TYR_HH_INDEX, 
-                        promod3::loop::TYR_CE1_INDEX, 
-                        promod3::loop::TYR_CZ_INDEX, 
-                        promod3::loop::TYR_OH_INDEX,
-                        0.96, 1.885, 2);
-
-  AddFRMRule(TYR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(TYR, 0, -1.48);
-  AddFRMPrefactor(TYR, 0, 1.48);
-  AddFRMRotatingParticle(TYR, 0, 0);
-  AddFRMRotatingParticle(TYR, 0, 1);
-  AddFRMRotatingParticle(TYR, 0, 2);
-  AddFRMRotatingParticle(TYR, 0, 3);
-  AddFRMRotatingParticle(TYR, 0, 4);
-  AddFRMRotatingParticle(TYR, 0, 5);
-  AddFRMRotatingParticle(TYR, 0, 6);
-  AddFRMRotatingParticle(TYR, 0, 7);
-
-  AddFRMRule(TYR, promod3::loop::BB_CB_INDEX, promod3::loop::TYR_CG_INDEX);
-  AddFRMPrefactor(TYR, 1, -0.73);
-  AddFRMPrefactor(TYR, 1, 0.73);
-  AddFRMFixParticle(TYR, 1, 0);
-  AddFRMRotatingParticle(TYR, 1, 1);
-  AddFRMRotatingParticle(TYR, 1, 2);
-  AddFRMRotatingParticle(TYR, 1, 3);
-  AddFRMRotatingParticle(TYR, 1, 4);
-  AddFRMRotatingParticle(TYR, 1, 5);
-  AddFRMRotatingParticle(TYR, 1, 6);
-  AddFRMRotatingParticle(TYR, 1, 7);
-
-  AddFRMRule(TYR, promod3::loop::TYR_CZ_INDEX, promod3::loop::TYR_OH_INDEX);
-  AddFRMPrefactor(TYR, 2, -0.96);
-  AddFRMPrefactor(TYR, 2, 0.96);
-  AddFRMFixParticle(TYR, 2, 0);
-  AddFRMFixParticle(TYR, 2, 1);
-  AddFRMFixParticle(TYR, 2, 2);
-  AddFRMFixParticle(TYR, 2, 3);
-  AddFRMFixParticle(TYR, 2, 4);
-  AddFRMFixParticle(TYR, 2, 5);
-  AddFRMFixParticle(TYR, 2, 6);
-  AddFRMRotatingParticle(TYR, 2, 7);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(TYR, 0, 8);
-    AddFRMFixParticle(TYR, 1, 8);
-    AddFRMFixParticle(TYR, 2, 8);
-  }
-
-  backbone_infos_[TYR].has_hydrogens = true;
-  AddBBInfo(TYR, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(TYR, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(TYR, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(TYR, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(TYR, HParticle, 0.25, "H", promod3::loop::TYR_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(TYR, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(TYR, promod3::loop::TYR_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(TYR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // THR
-  sidechain_infos_[THR].has_hydrogens = true;
-  sidechain_infos_[THR].internal_e_prefactor = 2.96;
-  sidechain_infos_[THR].frm_t = 1.11;
-
-  AddInfo(THR, OParticle, -0.65, "OG1", promod3::loop::THR_OG1_INDEX, false);
-  AddInfo(THR, CH3Particle, 0.0, "CG2", promod3::loop::THR_CG2_INDEX, false);
-  AddInfo(THR, HParticle, 0.40, "HG1", promod3::loop::THR_HG1_INDEX, true);
-
-  if(cb_in_sidechain) {
-    AddInfo(THR, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(THR, promod3::loop::THR_HG1_INDEX, promod3::loop::THR_OG1_INDEX, 2);
-  AddLP(THR, promod3::loop::BB_CB_INDEX, promod3::loop::THR_OG1_INDEX, 
-        promod3::loop::THR_HG1_INDEX, false, false, true, 0, LONE_PAIR_COH);
-  AddCustomHydrogenInfo(THR, promod3::loop::THR_HG1_INDEX, 
-                        promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX, 
-                        promod3::loop::THR_OG1_INDEX,
-                        0.96, 1.85, 1);
-
-  AddFRMRule(THR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(THR, 0, -0.88);
-  AddFRMPrefactor(THR, 0, 0.88);
-  AddFRMRotatingParticle(THR, 0, 0);
-  AddFRMRotatingParticle(THR, 0, 1);
-  AddFRMRotatingParticle(THR, 0, 2);
-
-  AddFRMRule(THR, promod3::loop::BB_CB_INDEX, promod3::loop::THR_OG1_INDEX);
-  AddFRMPrefactor(THR, 1, -0.88);
-  AddFRMPrefactor(THR, 1, 0.88);
-  AddFRMFixParticle(THR, 1, 0);
-  AddFRMFixParticle(THR, 1, 1);
-  AddFRMRotatingParticle(THR, 1, 2);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(THR, 0, 3);
-    AddFRMFixParticle(THR, 1, 3);
-  }
-
-  backbone_infos_[THR].has_hydrogens = true;
-  AddBBInfo(THR, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(THR, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(THR, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(THR, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(THR, HParticle, 0.25, "H", promod3::loop::THR_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(THR, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false); 
-  }
-
-  AddBBPDir(THR, promod3::loop::THR_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(THR, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // VAL
-  sidechain_infos_[VAL].has_hydrogens = false;
-  sidechain_infos_[VAL].internal_e_prefactor = 1.62;
-  sidechain_infos_[VAL].frm_t = 2.20;
-
-  AddInfo(VAL, CH3Particle, 0.0, "CG1", promod3::loop::VAL_CG1_INDEX, false);
-  AddInfo(VAL, CH3Particle, 0.0, "CG2", promod3::loop::VAL_CG2_INDEX, false);
-
-  if(cb_in_sidechain) {
-    AddInfo(VAL, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddFRMRule(VAL, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(VAL, 0, -2.09);
-  AddFRMPrefactor(VAL, 0, 2.09);
-  AddFRMRotatingParticle(VAL, 0, 0);
-  AddFRMRotatingParticle(VAL, 0, 1);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(VAL, 0, 2);
-  }
-
-  backbone_infos_[VAL].has_hydrogens = true;
-  AddBBInfo(VAL, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(VAL, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(VAL, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(VAL, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(VAL, HParticle, 0.25, "H", promod3::loop::VAL_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(VAL, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false); 
-  }
-
-  AddBBPDir(VAL, promod3::loop::VAL_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(VAL, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // ILE
-  sidechain_infos_[ILE].has_hydrogens = false;
-  sidechain_infos_[ILE].internal_e_prefactor = 2.18;
-  sidechain_infos_[ILE].frm_t = 2.03;
-
-  AddInfo(ILE, CH2Particle, 0.0, "CG1", promod3::loop::ILE_CG1_INDEX, false);
-  AddInfo(ILE, CH3Particle, 0.0, "CG2", promod3::loop::ILE_CG2_INDEX, false);  
-  AddInfo(ILE, CH3Particle, 0.0, "CD1", promod3::loop::ILE_CD1_INDEX, false);  
-
-  if(cb_in_sidechain) {
-    AddInfo(ILE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddFRMRule(ILE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(ILE, 0, -1.23);
-  AddFRMPrefactor(ILE, 0, 1.23);
-  AddFRMRotatingParticle(ILE, 0, 0);
-  AddFRMRotatingParticle(ILE, 0, 1);
-  AddFRMRotatingParticle(ILE, 0, 2);
-
-  AddFRMRule(ILE, promod3::loop::BB_CB_INDEX, promod3::loop::ILE_CG1_INDEX);
-  AddFRMPrefactor(ILE, 1, -0.98);
-  AddFRMPrefactor(ILE, 1, 0.98);
-  AddFRMFixParticle(ILE, 1, 0);
-  AddFRMFixParticle(ILE, 1, 1);
-  AddFRMRotatingParticle(ILE, 1, 2);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(ILE, 0, 3);
-    AddFRMFixParticle(ILE, 1, 3);
-  }
-
-  backbone_infos_[ILE].has_hydrogens = true;
-  AddBBInfo(ILE, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(ILE, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(ILE, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(ILE, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(ILE, HParticle, 0.25, "H", promod3::loop::ILE_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(ILE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(ILE, promod3::loop::ILE_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(ILE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // LEU
-  sidechain_infos_[LEU].has_hydrogens = false;
-  sidechain_infos_[LEU].internal_e_prefactor = 2.25;
-  sidechain_infos_[LEU].frm_t = 2.55;
-  
-  AddInfo(LEU, CH1Particle, 0.0, "CG", promod3::loop::LEU_CG_INDEX, false);
-  AddInfo(LEU, CH3Particle, 0.0, "CD1", promod3::loop::LEU_CD1_INDEX, false);  
-  AddInfo(LEU, CH3Particle, 0.0, "CD2", promod3::loop::LEU_CD2_INDEX, false);  
-
-  if(cb_in_sidechain) {
-    AddInfo(LEU, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-  
-  AddFRMRule(LEU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(LEU, 0, -1.15);
-  AddFRMPrefactor(LEU, 0, 1.15);
-  AddFRMRotatingParticle(LEU, 0, 0);
-  AddFRMRotatingParticle(LEU, 0, 1);
-  AddFRMRotatingParticle(LEU, 0, 2);
-
-  AddFRMRule(LEU, promod3::loop::BB_CB_INDEX, promod3::loop::LEU_CG_INDEX);
-  AddFRMPrefactor(LEU, 1, -1.48);
-  AddFRMPrefactor(LEU, 1, 1.48);
-  AddFRMFixParticle(LEU, 1, 0);  
-  AddFRMRotatingParticle(LEU, 1, 1);
-  AddFRMRotatingParticle(LEU, 1, 2);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(LEU, 0, 3);
-    AddFRMFixParticle(LEU, 1, 3);
-  }
-
-  backbone_infos_[LEU].has_hydrogens = true;
-  AddBBInfo(LEU, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(LEU, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(LEU, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(LEU, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(LEU, HParticle, 0.25, "H", promod3::loop::LEU_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(LEU, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(LEU, promod3::loop::LEU_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(LEU, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // PROLINES DO NOT HAVE FRM DEFINITIONS!
-  // large scale benchmarks showed, that varying around chi angles in case
-  // of prolines has a negative effect on performance => reduce to one single
-  // subrotamer...
-
-  // PRO
-  sidechain_infos_[PRO].has_hydrogens = false;
-  sidechain_infos_[PRO].internal_e_prefactor = 0.76;
-  sidechain_infos_[PRO].frm_t = 2.62;
-  
-  AddInfo(PRO, CH2Particle, 0.0, "CG", promod3::loop::PRO_CG_INDEX, false);
-  AddInfo(PRO, CH2Particle, 0.0, "CD", promod3::loop::PRO_CD_INDEX, false); 
-
-  if(cb_in_sidechain) {
-    AddInfo(PRO, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  backbone_infos_[PRO].has_hydrogens = false;
-  AddBBInfo(PRO, NParticle, -0.20, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(PRO, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(PRO, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(PRO, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(PRO, CH2Particle, 0.25, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBLP(PRO, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // CPR
-  sidechain_infos_[CPR] = sidechain_infos_[PRO]; 
-  frm_rules_[CPR] = frm_rules_[PRO];
-  backbone_infos_[CPR] = backbone_infos_[PRO];
-
-  // TPR
-  sidechain_infos_[TPR] = sidechain_infos_[PRO];
-  frm_rules_[TPR] = frm_rules_[PRO];
-  backbone_infos_[TPR] = backbone_infos_[PRO];
-
-  // HSD
-  sidechain_infos_[HSD].has_hydrogens = true;
-  sidechain_infos_[HSD].internal_e_prefactor = 2.01;
-  sidechain_infos_[HSD].frm_t = 1.35;
-
-  AddInfo(HSD, CParticle, 0.10, "CG", promod3::loop::HIS_CG_INDEX,false);
-  AddInfo(HSD, NParticle, -0.40, "ND1", promod3::loop::HIS_ND1_INDEX,false);
-  AddInfo(HSD, CParticle, 0.10, "CD2", promod3::loop::HIS_CD2_INDEX,false);
-  AddInfo(HSD, CParticle, 0.30, "CE1", promod3::loop::HIS_CE1_INDEX,false);
-  AddInfo(HSD, NParticle, -0.40, "NE2", promod3::loop::HIS_NE2_INDEX,false);
-  AddInfo(HSD, HParticle, 0.30, "HD1", promod3::loop::HIS_HD1_INDEX,true);
-
-  if(cb_in_sidechain) {
-    AddInfo(HSD, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(HSD, promod3::loop::HIS_HD1_INDEX, promod3::loop::HIS_ND1_INDEX, 5);
-  AddLP(HSD, promod3::loop::HIS_CD2_INDEX, promod3::loop::HIS_NE2_INDEX, 
-        promod3::loop::HIS_CE1_INDEX, false, false, false, 4, LONE_PAIR_CNC);
-
-
-  AddFRMRule(HSD, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(HSD, 0, -1.84);
-  AddFRMPrefactor(HSD, 0, 1.84);
-  AddFRMRotatingParticle(HSD, 0, 0);
-  AddFRMRotatingParticle(HSD, 0, 1);
-  AddFRMRotatingParticle(HSD, 0, 2);
-  AddFRMRotatingParticle(HSD, 0, 3);
-  AddFRMRotatingParticle(HSD, 0, 4);
-  AddFRMRotatingParticle(HSD, 0, 5);
-
-  AddFRMRule(HSD, promod3::loop::BB_CB_INDEX, promod3::loop::HIS_CG_INDEX);
-  AddFRMPrefactor(HSD, 1, -0.85);
-  AddFRMPrefactor(HSD, 1, 0.85);
-  AddFRMFixParticle(HSD, 1, 0);
-  AddFRMRotatingParticle(HSD, 1, 1);
-  AddFRMRotatingParticle(HSD, 1, 2);
-  AddFRMRotatingParticle(HSD, 1, 3);
-  AddFRMRotatingParticle(HSD, 1, 4);
-  AddFRMRotatingParticle(HSD, 1, 5);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(HSD, 0, 6);
-    AddFRMFixParticle(HSD, 1, 6);
-  }
-
-  backbone_infos_[HSD].has_hydrogens = true;
-  AddBBInfo(HSD, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(HSD, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(HSD, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(HSD, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(HSD, HParticle, 0.25, "H", promod3::loop::HIS_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddInfo(HSD, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddBBPDir(HSD, promod3::loop::HIS_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(HSD, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // HSE
-  sidechain_infos_[HSE].has_hydrogens = true;
-  sidechain_infos_[HSE].internal_e_prefactor = 2.01;
-  sidechain_infos_[HSE].frm_t = 1.35;
-  
-  AddInfo(HSE, CParticle, 0.10, "CG", promod3::loop::HIS_CG_INDEX,false);
-  AddInfo(HSE, NParticle, -0.40, "ND1", promod3::loop::HIS_ND1_INDEX,false);
-  AddInfo(HSE, CParticle, 0.10, "CD2", promod3::loop::HIS_CD2_INDEX,false);
-  AddInfo(HSE, CParticle, 0.30, "CE1", promod3::loop::HIS_CE1_INDEX,false);
-  AddInfo(HSE, NParticle, -0.40, "NE2", promod3::loop::HIS_NE2_INDEX,false);
-  AddInfo(HSE, HParticle, 0.30, "HE2", promod3::loop::HIS_HE2_INDEX,true);
-  
-  if(cb_in_sidechain) {
-    AddInfo(HSE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddPDir(HSE, promod3::loop::HIS_HE2_INDEX, promod3::loop::HIS_NE2_INDEX, 5);
-  AddLP(HSE, promod3::loop::HIS_CG_INDEX, promod3::loop::HIS_ND1_INDEX, 
-        promod3::loop::HIS_CE1_INDEX, false, false, false, 1, LONE_PAIR_CNC);
-
-  AddFRMRule(HSE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(HSE, 0, -1.84);
-  AddFRMPrefactor(HSE, 0, 1.84);
-  AddFRMRotatingParticle(HSE, 0, 0);
-  AddFRMRotatingParticle(HSE, 0, 1);
-  AddFRMRotatingParticle(HSE, 0, 2);
-  AddFRMRotatingParticle(HSE, 0, 3);
-  AddFRMRotatingParticle(HSE, 0, 4);
-  AddFRMRotatingParticle(HSE, 0, 5);
-
-  AddFRMRule(HSE, promod3::loop::BB_CB_INDEX, promod3::loop::HIS_CG_INDEX);
-  AddFRMPrefactor(HSE, 1, -0.85);
-  AddFRMPrefactor(HSE, 1, 0.85);
-  AddFRMFixParticle(HSE, 1, 0);
-  AddFRMRotatingParticle(HSE, 1, 1);
-  AddFRMRotatingParticle(HSE, 1, 2);
-  AddFRMRotatingParticle(HSE, 1, 3);
-  AddFRMRotatingParticle(HSE, 1, 4);
-  AddFRMRotatingParticle(HSE, 1, 5);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(HSE, 0, 6);
-    AddFRMFixParticle(HSE, 1, 6);
-  }
-
-  backbone_infos_[HSE].has_hydrogens = true;
-  AddBBInfo(HSE, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(HSE, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(HSE, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(HSE, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(HSE, HParticle, 0.25, "H", promod3::loop::HIS_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(HSE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
 
-  AddBBPDir(HSE, promod3::loop::HIS_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(HSE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // HIS
-  // this is a bit hacky...
-  sidechain_infos_[HIS] = sidechain_infos_[HSD];
-  frm_rules_[HIS] = frm_rules_[HSD];
-  backbone_infos_[HIS] = backbone_infos_[HSD];
-
-  // PHE
-  sidechain_infos_[PHE].has_hydrogens = false;
-  sidechain_infos_[PHE].internal_e_prefactor = 1.71;
-  sidechain_infos_[PHE].frm_t = 1.07;
-  
-  AddInfo(PHE, CParticle, 0.0, "CG", promod3::loop::PHE_CG_INDEX, false);
-  AddInfo(PHE, CParticle, 0.0, "CD1", promod3::loop::PHE_CD1_INDEX, false);  
-  AddInfo(PHE, CParticle, 0.0, "CD2", promod3::loop::PHE_CD2_INDEX, false); 
-  AddInfo(PHE, CParticle, 0.0, "CE1", promod3::loop::PHE_CE1_INDEX, false);  
-  AddInfo(PHE, CParticle, 0.0, "CE2", promod3::loop::PHE_CE2_INDEX, false); 
-  AddInfo(PHE, CParticle, 0.0, "CZ", promod3::loop::PHE_CZ_INDEX, false); 
-
-  if(cb_in_sidechain) {
-    AddInfo(PHE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  AddFRMRule(PHE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_CB_INDEX);
-  AddFRMPrefactor(PHE, 0, -1.45);
-  AddFRMPrefactor(PHE, 0, 1.45);
-  AddFRMRotatingParticle(PHE, 0, 0);
-  AddFRMRotatingParticle(PHE, 0, 1);
-  AddFRMRotatingParticle(PHE, 0, 2);
-  AddFRMRotatingParticle(PHE, 0, 3);
-  AddFRMRotatingParticle(PHE, 0, 4);
-  AddFRMRotatingParticle(PHE, 0, 5);
-
-  AddFRMRule(PHE, promod3::loop::BB_CB_INDEX, promod3::loop::PHE_CG_INDEX);
-  AddFRMPrefactor(PHE, 1, -1.35);
-  AddFRMPrefactor(PHE, 1, 1.35);
-  AddFRMFixParticle(PHE, 1, 0);
-  AddFRMRotatingParticle(PHE, 1, 1);
-  AddFRMRotatingParticle(PHE, 1, 2);
-  AddFRMRotatingParticle(PHE, 1, 3);
-  AddFRMRotatingParticle(PHE, 1, 4);
-  AddFRMRotatingParticle(PHE, 1, 5);
-
-  if(cb_in_sidechain) {
-    AddFRMFixParticle(PHE, 0, 6);
-    AddFRMFixParticle(PHE, 1, 6);
-  }
-
-  backbone_infos_[PHE].has_hydrogens = true;
-  AddBBInfo(PHE, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(PHE, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(PHE, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(PHE, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(PHE, HParticle, 0.25, "H", promod3::loop::PHE_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(PHE, CH2Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false); 
-  }
-
-  AddBBPDir(PHE, promod3::loop::PHE_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(PHE, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // ALA
-  sidechain_infos_[ALA].has_hydrogens = false;
-  sidechain_infos_[ALA].internal_e_prefactor = 1.0;
-  sidechain_infos_[ALA].frm_t = 1.0;
-
-  if(cb_in_sidechain) {
-    AddInfo(ALA, CH3Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false);
-  }
-
-  backbone_infos_[ALA].has_hydrogens = true;
-  AddBBInfo(ALA, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(ALA, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(ALA, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(ALA, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(ALA, HParticle, 0.25, "H", promod3::loop::ALA_H_INDEX,true);
-
-  if(!cb_in_sidechain) {
-    AddBBInfo(ALA, CH3Particle, 0.0, "CB", promod3::loop::BB_CB_INDEX, false); 
-  }
-
-  AddBBPDir(ALA, promod3::loop::ALA_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(ALA, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  // GLY
-  sidechain_infos_[GLY].has_hydrogens = false;
-  sidechain_infos_[GLY].internal_e_prefactor = 1.0;
-  sidechain_infos_[GLY].frm_t = 1.0;
-  
-  backbone_infos_[GLY].has_hydrogens = true;
-  AddBBInfo(GLY, NParticle, -0.35, "N", promod3::loop::BB_N_INDEX, false);
-  AddBBInfo(GLY, CH1Particle, 0.1, "CA", promod3::loop::BB_CA_INDEX, false);
-  AddBBInfo(GLY, CParticle, 0.55, "C", promod3::loop::BB_C_INDEX, false);
-  AddBBInfo(GLY, OParticle, -0.55, "O", promod3::loop::BB_O_INDEX, false);
-  AddBBInfo(GLY, HParticle, 0.25, "H", promod3::loop::GLY_H_INDEX,true);
-  AddBBPDir(GLY, promod3::loop::GLY_H_INDEX, promod3::loop::BB_N_INDEX, 4);
-  AddBBLP(GLY, promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
-          promod3::loop::BB_O_INDEX, false, false, false, 3, LONE_PAIR_CARBONYL);
-
-  for(uint i = 0; i <= XXX; ++i){
-    num_sidechain_particles_[i] = sidechain_infos_[i].particles.size();
-    num_backbone_particles_[i] = backbone_infos_[i].particles.size();
-    num_frm_particles_[i] = num_sidechain_particles_[i];
-    for(uint j = 0; j < frm_rules_[i].size(); ++j){
-      num_frm_particles_[i] += (frm_rules_[i][j].prefactors.size() * 
-                                frm_rules_[i][j].rotating_particles.size());
+struct SCWRL4RotamerParam : public RotamerLookupParam {
+
+  SCWRL4RotamerParam() {
+
+    // overwrite default FRM prefactors from base class
+    ARG_CA_CB_prefactors[0] = -0.87;
+    ARG_CB_CG_prefactors[0] = -1.62;
+    ARG_CG_CD_prefactors[0] = -1.67;
+    ARG_CD_NE_prefactors[0] = -0.73;
+    ASN_CA_CB_prefactors[0] = -0.62;
+    ASN_CB_CG_prefactors[0] = -1.93;
+    ASP_CA_CB_prefactors[0] = -1.59;
+    ASP_CB_CG_prefactors[0] = -0.63;
+    GLN_CA_CB_prefactors[0] = -1.55;
+    GLN_CB_CG_prefactors[0] = -0.53;
+    GLN_CG_CD_prefactors[0] = -1.89;
+    GLU_CA_CB_prefactors[0] = -0.82;
+    GLU_CB_CG_prefactors[0] = -1.57;
+    GLU_CG_CD_prefactors[0] = -0.76;
+    LYS_CA_CB_prefactors[0] = -1.62;
+    LYS_CB_CG_prefactors[0] = -0.99;
+    LYS_CG_CD_prefactors[0] = -0.96;
+    LYS_CD_CE_prefactors[0] = -1.49;
+    SER_CA_CB_prefactors[0] = -0.65;
+    SER_CB_OG_prefactors[0] = -2.98;
+    CYS_CA_CB_prefactors[0] = -1.69;  
+    MET_CA_CB_prefactors[0] = -0.97;
+    MET_CB_CG_prefactors[0] = -1.54;
+    MET_CG_SD_prefactors[0] = -1.21;
+    TRP_CA_CB_prefactors[0] = -1.28;
+    TRP_CB_CG_prefactors[0] = -1.48;
+    TYR_CA_CB_prefactors[0] = -1.48;
+    TYR_CB_CG_prefactors[0] = -0.73;
+    TYR_CZ_OH_prefactors[0] = -0.96;
+    THR_CA_CB_prefactors[0] = -0.88;
+    THR_CB_OG1_prefactors[0] = -0.88;
+    VAL_CA_CB_prefactors[0] = -2.09;
+    ILE_CA_CB_prefactors[0] = -1.23;
+    ILE_CB_CG1_prefactors[0] = -0.98;
+    LEU_CA_CB_prefactors[0] = -1.15;
+    LEU_CB_CG_prefactors[0] = -1.48;
+    HIS_CA_CB_prefactors[0] = -1.84;
+    HIS_CB_CG_prefactors[0] = -0.85;
+    PHE_CA_CB_prefactors[0] = -1.45;
+    PHE_CB_CG_prefactors[0] = -1.35;
+
+    ARG_CA_CB_prefactors[1] = 0.87;
+    ARG_CB_CG_prefactors[1] = 1.62;
+    ARG_CG_CD_prefactors[1] = 1.67;
+    ARG_CD_NE_prefactors[1] = 0.73;
+    ASN_CA_CB_prefactors[1] = 0.62;
+    ASN_CB_CG_prefactors[1] = 1.93;
+    ASP_CA_CB_prefactors[1] = 1.59;
+    ASP_CB_CG_prefactors[1] = 0.63;
+    GLN_CA_CB_prefactors[1] = 1.55;
+    GLN_CB_CG_prefactors[1] = 0.53;
+    GLN_CG_CD_prefactors[1] = 1.89;
+    GLU_CA_CB_prefactors[1] = 0.82;
+    GLU_CB_CG_prefactors[1] = 1.57;
+    GLU_CG_CD_prefactors[1] = 0.76;
+    LYS_CA_CB_prefactors[1] = 1.62;
+    LYS_CB_CG_prefactors[1] = 0.99;
+    LYS_CG_CD_prefactors[1] = 0.96;
+    LYS_CD_CE_prefactors[1] = 1.49;
+    SER_CA_CB_prefactors[1] = 0.65;
+    SER_CB_OG_prefactors[1] = 2.98;
+    CYS_CA_CB_prefactors[1] = 1.69;  
+    MET_CA_CB_prefactors[1] = 0.97;
+    MET_CB_CG_prefactors[1] = 1.54;
+    MET_CG_SD_prefactors[1] = 1.21;
+    TRP_CA_CB_prefactors[1] = 1.28;
+    TRP_CB_CG_prefactors[1] = 1.48;
+    TYR_CA_CB_prefactors[1] = 1.48;
+    TYR_CB_CG_prefactors[1] = 0.73;
+    TYR_CZ_OH_prefactors[1] = 0.96;
+    THR_CA_CB_prefactors[1] = 0.88;
+    THR_CB_OG1_prefactors[1] = 0.88;
+    VAL_CA_CB_prefactors[1] = 2.09;
+    ILE_CA_CB_prefactors[1] = 1.23;
+    ILE_CB_CG1_prefactors[1] = 0.98;
+    LEU_CA_CB_prefactors[1] = 1.15;
+    LEU_CB_CG_prefactors[1] = 1.48;
+    HIS_CA_CB_prefactors[1] = 1.84;
+    HIS_CB_CG_prefactors[1] = 0.85;
+    PHE_CA_CB_prefactors[1] = 1.45;
+    PHE_CB_CG_prefactors[1] = 1.35;
+
+    // overwrite default frm_t from base class
+    frm_t[ost::conop::ARG] = 1.23;
+    frm_t[ost::conop::ASN] = 1.41;
+    frm_t[ost::conop::ASP] = 1.48;
+    frm_t[ost::conop::GLN] = 1.32;
+    frm_t[ost::conop::GLU] = 0.94;
+    frm_t[ost::conop::LYS] = 1.27;
+    frm_t[ost::conop::SER] = 3.53;
+    frm_t[ost::conop::CYS] = 1.69;
+    frm_t[ost::conop::MET] = 1.77;
+    frm_t[ost::conop::TRP] = 0.99;
+    frm_t[ost::conop::TYR] = 1.96;
+    frm_t[ost::conop::THR] = 1.11;
+    frm_t[ost::conop::VAL] = 2.20;
+    frm_t[ost::conop::ILE] = 2.03;
+    frm_t[ost::conop::LEU] = 2.55;
+    frm_t[ost::conop::PRO] = 2.62;
+    frm_t[ost::conop::HIS] = 1.35;
+    frm_t[ost::conop::PHE] = 1.07;
+
+    // overwrite default internal_e_prefactor from base class
+    internal_e_prefactor[ost::conop::ARG] = 2.27;
+    internal_e_prefactor[ost::conop::ASN] = 1.80;
+    internal_e_prefactor[ost::conop::ASP] = 2.44;
+    internal_e_prefactor[ost::conop::GLN] = 1.61;
+    internal_e_prefactor[ost::conop::GLU] = 1.85;
+    internal_e_prefactor[ost::conop::LYS] = 2.13;
+    internal_e_prefactor[ost::conop::SER] = 2.78;
+    internal_e_prefactor[ost::conop::CYS] = 4.07;
+    internal_e_prefactor[ost::conop::MET] = 1.95;
+    internal_e_prefactor[ost::conop::TRP] = 3.24;
+    internal_e_prefactor[ost::conop::TYR] = 2.00;
+    internal_e_prefactor[ost::conop::THR] = 2.96;
+    internal_e_prefactor[ost::conop::VAL] = 1.62;
+    internal_e_prefactor[ost::conop::ILE] = 2.18;
+    internal_e_prefactor[ost::conop::LEU] = 2.25;
+    internal_e_prefactor[ost::conop::PRO] = 0.76;
+    internal_e_prefactor[ost::conop::HIS] = 2.01;
+    internal_e_prefactor[ost::conop::PHE] = 1.71;
+
+    // set all parameters specific to SCWRL4RotamerParam to default values
+    for(uint i = 0 ; i < promod3::loop::XXX_NUM_HYDROGENS; ++i) {
+      hydrogen_charges_[i] = 0.0;
+      polar_anchor_[i] = -1;
     }
-  }
-}
 
-SCWRL4RotamerConstructor::SCWRL4RotamerConstructor(bool cb_in_sidechain): 
-                                rotamer_lookup_(cb_in_sidechain) {
-  hydrogen_buffer_ = boost::make_shared<promod3::loop::HydrogenStorage>();
-}
-
-
-FrameResiduePtr SCWRL4RotamerConstructor::ConstructBackboneFrameResidue(
-          const ost::mol::ResidueHandle& res, RotamerID id, uint residue_index,
-          Real phi, bool n_ter, bool c_ter) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructBackboneFrameResidue", 2);
-
-  if(id == XXX) {
-    throw promod3::Error("Cannot construct FrameResidue for unknown "
-                         "rotamer id!");
-  }
-
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetBackboneInfo(id);
-
-  for(uint i = 0; i < info.particles.size(); ++i){
-    if(!info.particles[i].is_hydrogen){
-      ost::mol::AtomHandle a = res.FindAtom(info.particles[i].name);
-      if(!a.IsValid()){
-        throw promod3::Error("Expected atom " + info.particles[i].name + 
-                             " to be present in input residue!");
-      }
-      pos_buffer_->SetPos(id, info.particles[i].atom_idx, a.GetPos());
+    for(uint i = 0; i < promod3::loop::XXX_NUM_ATOMS; ++i) {
+      heavy_atom_charges_[i] = 0.0;
+      lone_pair_info_idx_[i] = -1;
     }
-  }
 
-  //set bb hydrogen
-  if(info.has_hydrogens){
-    promod3::loop::ConstructHydrogenN(*pos_buffer_, id, phi, *hydrogen_buffer_); 
-  }
-
-  int num_particles = info.particles.size();
-  if(n_ter) num_particles += 2;
-  if(c_ter) num_particles += 1;
-  std::vector<Particle> particles(num_particles);
-  this->ConstructBBFrameParticles(info, id, n_ter, c_ter, particles);
-
-  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
-                                                       residue_index);
-
-  return p;
-}
-
-FrameResiduePtr SCWRL4RotamerConstructor::ConstructBackboneFrameResidue(
-          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
-          RotamerID id, uint residue_index,
-          Real phi, bool n_ter, bool c_ter) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructBackboneFrameResidue", 2);
-
-  if(id == XXX) {
-    throw promod3::Error("Cannot construct FrameResidue for unknown "
-                         "rotamer id!");
-  }
-
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetBackboneInfo(id);
-
-  for(uint i = 0; i < info.particles.size(); ++i){
-    if(!info.particles[i].is_hydrogen){
-
-      if(!all_atom.IsSet(aa_res_idx, info.particles[i].atom_idx)){
-        throw promod3::Error("Expected atom " + info.particles[i].name +
-                             " to be set in all_atom");
+    // set anchor indices for all polar hydrogens
+    polar_anchor_[promod3::loop::ALA_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ALA_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ALA_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ALA_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ARG_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ARG_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ARG_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ARG_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASN_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASN_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASN_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASN_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASP_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASP_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASP_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ASP_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLN_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLN_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLN_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLN_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLU_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLU_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLU_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLU_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LYS_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LYS_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LYS_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LYS_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::SER_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::SER_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::SER_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::SER_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::CYS_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::CYS_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::CYS_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::CYS_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::MET_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::MET_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::MET_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::MET_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TRP_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TRP_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TRP_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TRP_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TYR_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TYR_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TYR_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::TYR_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::THR_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::THR_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::THR_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::THR_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::VAL_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::VAL_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::VAL_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::VAL_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ILE_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ILE_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ILE_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::ILE_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LEU_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LEU_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LEU_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::LEU_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLY_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLY_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLY_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::GLY_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PRO_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PRO_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::HIS_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::HIS_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::HIS_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::HIS_H3] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PHE_H] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PHE_H1] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PHE_H2] = promod3::loop::BB_N_INDEX;
+    polar_anchor_[promod3::loop::PHE_H3] = promod3::loop::BB_N_INDEX;
+    
+    polar_anchor_[promod3::loop::ARG_HE] = promod3::loop::ARG_NE_INDEX;
+    polar_anchor_[promod3::loop::ARG_HH11] = promod3::loop::ARG_NH1_INDEX; 
+    polar_anchor_[promod3::loop::ARG_HH12] = promod3::loop::ARG_NH1_INDEX; 
+    polar_anchor_[promod3::loop::ARG_HH21] = promod3::loop::ARG_NH2_INDEX; 
+    polar_anchor_[promod3::loop::ARG_HH22] = promod3::loop::ARG_NH2_INDEX; 
+    polar_anchor_[promod3::loop::ASN_HD21] = promod3::loop::ASN_ND2_INDEX;
+    polar_anchor_[promod3::loop::ASN_HD22] = promod3::loop::ASN_ND2_INDEX;
+    polar_anchor_[promod3::loop::GLN_HE21] = promod3::loop::GLN_NE2_INDEX;
+    polar_anchor_[promod3::loop::GLN_HE22] = promod3::loop::GLN_NE2_INDEX;
+    polar_anchor_[promod3::loop::LYS_HZ1] = promod3::loop::LYS_NZ_INDEX;
+    polar_anchor_[promod3::loop::LYS_HZ2] = promod3::loop::LYS_NZ_INDEX;
+    polar_anchor_[promod3::loop::LYS_HZ3] = promod3::loop::LYS_NZ_INDEX;
+    polar_anchor_[promod3::loop::SER_HG] = promod3::loop::SER_OG_INDEX;
+    polar_anchor_[promod3::loop::TRP_HE1] = promod3::loop::TRP_NE1_INDEX;
+    polar_anchor_[promod3::loop::TYR_HH] = promod3::loop::TYR_OH_INDEX;
+    polar_anchor_[promod3::loop::THR_HG1] = promod3::loop::THR_OG1_INDEX;
+    polar_anchor_[promod3::loop::HIS_HD1] = promod3::loop::HIS_ND1_INDEX;
+    polar_anchor_[promod3::loop::HIS_HE2] = promod3::loop::HIS_NE2_INDEX;
+
+    // set lone pair infos 
+    // Special care has to be taken for the terminal oxygen and
+    // histidine
+    int o_lp_idx = AddLP(promod3::loop::BB_CA_INDEX, promod3::loop::BB_C_INDEX, 
+                         promod3::loop::BB_O_INDEX, false, false, false, 
+                         LONE_PAIR_CARBONYL);
+    lone_pair_info_idx_[promod3::loop::ALA_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::ARG_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::ASN_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::ASP_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::GLN_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::GLU_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::LYS_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::SER_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::CYS_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::MET_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::TRP_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::TYR_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::THR_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::VAL_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::ILE_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::LEU_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::GLY_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::PRO_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::HIS_O] = o_lp_idx;
+    lone_pair_info_idx_[promod3::loop::PHE_O] = o_lp_idx;
+
+    AddLP(ASN, promod3::loop::ASN_OD1_INDEX,
+          promod3::loop::ASN_ND2_INDEX, promod3::loop::ASN_CG_INDEX, 
+          promod3::loop::ASN_OD1_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(ASP, promod3::loop::ASP_OD1_INDEX,
+          promod3::loop::ASP_OD2_INDEX, promod3::loop::ASP_CG_INDEX, 
+          promod3::loop::ASP_OD1_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(ASP, promod3::loop::ASP_OD2_INDEX,
+          promod3::loop::ASP_OD1_INDEX, promod3::loop::ASP_CG_INDEX, 
+          promod3::loop::ASP_OD2_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(GLN, promod3::loop::GLN_OE1_INDEX,
+          promod3::loop::GLN_NE2_INDEX, promod3::loop::GLN_CD_INDEX, 
+          promod3::loop::GLN_OE1_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(GLU, promod3::loop::GLU_OE1_INDEX,
+          promod3::loop::GLU_OE2_INDEX, promod3::loop::GLU_CD_INDEX, 
+          promod3::loop::GLU_OE1_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(GLU, promod3::loop::GLU_OE2_INDEX,
+          promod3::loop::GLU_OE1_INDEX, promod3::loop::GLU_CD_INDEX, 
+          promod3::loop::GLU_OE2_INDEX, false, false, false, LONE_PAIR_CARBONYL);
+
+    AddLP(SER, promod3::loop::SER_OG_INDEX,
+          promod3::loop::BB_CB_INDEX, promod3::loop::SER_OG_INDEX, 
+          promod3::loop::SER_HG_INDEX, false, false, true, LONE_PAIR_COH);
+
+    AddLP(TYR, promod3::loop::TYR_OH_INDEX,
+          promod3::loop::TYR_CZ_INDEX, promod3::loop::TYR_OH_INDEX, 
+          promod3::loop::TYR_HH_INDEX, false, false, true, LONE_PAIR_COH);
+
+    AddLP(THR, promod3::loop::THR_OG1_INDEX,
+          promod3::loop::BB_CB_INDEX, promod3::loop::THR_OG1_INDEX, 
+          promod3::loop::THR_HG1_INDEX, false, false, true, LONE_PAIR_COH);
+
+    AddLP(HIS, promod3::loop::HIS_NE2_INDEX,
+          promod3::loop::HIS_CD2_INDEX, promod3::loop::HIS_NE2_INDEX, 
+          promod3::loop::HIS_CE1_INDEX, false, false, false, LONE_PAIR_CNC);
+
+    AddLP(HIS, promod3::loop::HIS_ND1_INDEX,
+          promod3::loop::HIS_CG_INDEX, promod3::loop::HIS_ND1_INDEX, 
+          promod3::loop::HIS_CE1_INDEX, false, false, false, LONE_PAIR_CNC);
+
+    // set charges for polar hydrogen
+    hydrogen_charges_[promod3::loop::ALA_H] = 0.25;
+    hydrogen_charges_[promod3::loop::ALA_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::ALA_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::ALA_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_H] = 0.25;
+    hydrogen_charges_[promod3::loop::ARG_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::ASN_H] = 0.25;
+    hydrogen_charges_[promod3::loop::ASN_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::ASN_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::ASN_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::ASP_H] = 0.25;
+    hydrogen_charges_[promod3::loop::ASP_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::ASP_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::ASP_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::GLN_H] = 0.25;
+    hydrogen_charges_[promod3::loop::GLN_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::GLN_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::GLN_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::GLU_H] = 0.25;
+    hydrogen_charges_[promod3::loop::GLU_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::GLU_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::GLU_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::LYS_H] = 0.25;
+    hydrogen_charges_[promod3::loop::LYS_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::LYS_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::LYS_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::SER_H] = 0.25;
+    hydrogen_charges_[promod3::loop::SER_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::SER_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::SER_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::CYS_H] = 0.25;
+    hydrogen_charges_[promod3::loop::CYS_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::CYS_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::CYS_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::MET_H] = 0.25;
+    hydrogen_charges_[promod3::loop::MET_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::MET_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::MET_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::TRP_H] = 0.25;
+    hydrogen_charges_[promod3::loop::TRP_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::TRP_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::TRP_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::TYR_H] = 0.25;
+    hydrogen_charges_[promod3::loop::TYR_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::TYR_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::TYR_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::THR_H] = 0.25;
+    hydrogen_charges_[promod3::loop::THR_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::THR_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::THR_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::VAL_H] = 0.25;
+    hydrogen_charges_[promod3::loop::VAL_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::VAL_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::VAL_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::ILE_H] = 0.25;
+    hydrogen_charges_[promod3::loop::ILE_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::ILE_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::ILE_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::LEU_H] = 0.25;
+    hydrogen_charges_[promod3::loop::LEU_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::LEU_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::LEU_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::GLY_H] = 0.25;
+    hydrogen_charges_[promod3::loop::GLY_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::GLY_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::GLY_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::PRO_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::PRO_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::HIS_H] = 0.25;
+    hydrogen_charges_[promod3::loop::HIS_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::HIS_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::HIS_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::PHE_H] = 0.25;
+    hydrogen_charges_[promod3::loop::PHE_H1] = 0.35;
+    hydrogen_charges_[promod3::loop::PHE_H2] = 0.35;
+    hydrogen_charges_[promod3::loop::PHE_H3] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_HE] = 0.3;
+    hydrogen_charges_[promod3::loop::ARG_HH11] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_HH12] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_HH21] = 0.35;
+    hydrogen_charges_[promod3::loop::ARG_HH22] = 0.35;
+    hydrogen_charges_[promod3::loop::ASN_HD21] = 0.3;
+    hydrogen_charges_[promod3::loop::ASN_HD22] = 0.3;
+    hydrogen_charges_[promod3::loop::GLN_HE21] = 0.3;
+    hydrogen_charges_[promod3::loop::GLN_HE22] = 0.3;
+    hydrogen_charges_[promod3::loop::LYS_HZ1] = 0.35;
+    hydrogen_charges_[promod3::loop::LYS_HZ2] = 0.35;
+    hydrogen_charges_[promod3::loop::LYS_HZ3] = 0.35;
+    hydrogen_charges_[promod3::loop::SER_HG] = 0.40;
+    hydrogen_charges_[promod3::loop::TRP_HE1] = 0.30;
+    hydrogen_charges_[promod3::loop::TYR_HH] = 0.40;
+    hydrogen_charges_[promod3::loop::THR_HG1] = 0.40;
+    hydrogen_charges_[promod3::loop::HIS_HD1] = 0.30;
+    hydrogen_charges_[promod3::loop::HIS_HE2] = 0.30;
+
+    // set charges for hydrogen bond acceptors
+    heavy_atom_charges_[promod3::loop::ALA_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::ARG_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::ASN_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::ASP_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::GLN_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::GLU_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::LYS_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::SER_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::CYS_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::MET_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::TRP_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::TYR_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::THR_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::VAL_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::ILE_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::LEU_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::GLY_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::PRO_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::HIS_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::PHE_O] = -0.55;
+    heavy_atom_charges_[promod3::loop::ASN_OD1] = -0.55;
+    heavy_atom_charges_[promod3::loop::ASP_OD1] = -0.60;
+    heavy_atom_charges_[promod3::loop::ASP_OD2] = -0.60;
+    heavy_atom_charges_[promod3::loop::GLN_OE1] = -0.55;
+    heavy_atom_charges_[promod3::loop::GLU_OE1] = -0.60;
+    heavy_atom_charges_[promod3::loop::GLU_OE2] = -0.60;
+    heavy_atom_charges_[promod3::loop::SER_OG] = -0.65;
+    heavy_atom_charges_[promod3::loop::TYR_OH] = -0.65;
+    heavy_atom_charges_[promod3::loop::THR_OG1] = -0.65;
+    heavy_atom_charges_[promod3::loop::HIS_NE2] = -0.40;
+    heavy_atom_charges_[promod3::loop::HIS_ND1] = -0.40;
+
+    // set most common atomtypes by element
+    for(int i = 0; i < promod3::loop::XXX_NUM_ATOMS; ++i) {
+      particle_types_[i] = CParticle;
+      promod3::loop::AminoAcidAtom aaa = promod3::loop::AminoAcidAtom(i);
+      const String& ele = 
+      promod3::loop::AminoAcidLookup::GetInstance().GetElement(aaa);
+      if(ele == "N") {
+        particle_types_[i] = NParticle;
       }
-
-      pos_buffer_->SetPos(id, info.particles[i].atom_idx, 
-                          all_atom.GetPos(aa_res_idx, info.particles[i].atom_idx));
-    }
-  }
-
-  //set hydrogens
-  if(info.has_hydrogens){
-    promod3::loop::ConstructHydrogenN(*pos_buffer_, id, phi, *hydrogen_buffer_); 
-  }
-
-  int num_particles = info.particles.size();
-  if(n_ter) num_particles += 2;
-  if(c_ter) num_particles += 1;
-  std::vector<Particle> particles(num_particles);
-  this->ConstructBBFrameParticles(info, id, n_ter, c_ter, particles);
-
-  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
-                                                       residue_index);
-
-  return p; 
-}
-
-FrameResiduePtr SCWRL4RotamerConstructor::ConstructSidechainFrameResidue(
-        const ost::mol::ResidueHandle& res, RotamerID id, uint residue_index) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructSidechainFrameResidue", 2);
-
-  if(id == XXX) {
-    throw promod3::Error("Cannot construct FrameResidue for unknown "
-                         "rotamer id!");
-  }
-
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
-
-  for(uint i = 0; i < info.particles.size(); ++i){
-    if(!info.particles[i].is_hydrogen){
-      ost::mol::AtomHandle a = res.FindAtom(info.particles[i].name);
-      if(!a.IsValid()){
-        throw promod3::Error("Expected atom " + info.particles[i].name + 
-                             " to be present in input residue!");
+      if(ele == "O") {
+        particle_types_[i] = OParticle;
+      }
+      if(ele == "S") {
+        particle_types_[i] = SParticle;
       }
-      pos_buffer_->SetPos(id, info.particles[i].atom_idx, a.GetPos());
     }
-  }
 
-  //set bb hydrogen
-  if(info.has_hydrogens){
-    // to construct hydrogens, we might also need backbone atoms in the buffer
-    const SCWRLRotamerInfo& bb_info = rotamer_lookup_.GetBackboneInfo(id);
-
-    for(uint i = 0; i < bb_info.particles.size(); ++i){
-      if(!bb_info.particles[i].is_hydrogen){
-        ost::mol::AtomHandle a = res.FindAtom(bb_info.particles[i].name);
-        if(!a.IsValid()){
-          throw promod3::Error("Expected atom " + bb_info.particles[i].name + 
-                               " to be present in input residue!");
-        }
-        pos_buffer_->SetPos(id, bb_info.particles[i].atom_idx, a.GetPos());
-      }
+    // atoms of following types must be set manually:
+    // CH1Particle, CH2Particle, CH3Particle, OCParticle
+    particle_types_[promod3::loop::ARG_CG] = CH2Particle;
+    particle_types_[promod3::loop::ARG_CD] = CH2Particle;
+    particle_types_[promod3::loop::ARG_CB] = CH2Particle;
+    particle_types_[promod3::loop::ARG_CA] = CH1Particle;
+    particle_types_[promod3::loop::ASN_CB] = CH2Particle;
+    particle_types_[promod3::loop::ASN_CA] = CH1Particle;
+    particle_types_[promod3::loop::ASP_CB] = CH2Particle;
+    particle_types_[promod3::loop::ASP_CA] = CH1Particle;
+    particle_types_[promod3::loop::GLN_CG] = CH2Particle;
+    particle_types_[promod3::loop::GLN_CB] = CH2Particle;
+    particle_types_[promod3::loop::GLN_CA] = CH1Particle;
+    particle_types_[promod3::loop::GLU_CG] = CH2Particle;
+    particle_types_[promod3::loop::GLU_CB] = CH2Particle;
+    particle_types_[promod3::loop::GLU_CA] = CH1Particle;
+    particle_types_[promod3::loop::LYS_CG] = CH2Particle;
+    particle_types_[promod3::loop::LYS_CD] = CH2Particle;
+    particle_types_[promod3::loop::LYS_CE] = CH2Particle;
+    particle_types_[promod3::loop::LYS_CB] = CH2Particle;
+    particle_types_[promod3::loop::LYS_CA] = CH1Particle;
+    particle_types_[promod3::loop::SER_CB] = CH2Particle;
+    particle_types_[promod3::loop::SER_CA] = CH1Particle;
+    particle_types_[promod3::loop::CYS_CB] = CH2Particle;
+    particle_types_[promod3::loop::CYS_CA] = CH1Particle;
+    particle_types_[promod3::loop::MET_CG] = CH2Particle;
+    particle_types_[promod3::loop::MET_CE] = CH3Particle;
+    particle_types_[promod3::loop::MET_CB] = CH2Particle;
+    particle_types_[promod3::loop::MET_CA] = CH1Particle;
+    particle_types_[promod3::loop::TRP_CB] = CH2Particle;
+    particle_types_[promod3::loop::TRP_CA] = CH1Particle;
+    particle_types_[promod3::loop::TYR_CB] = CH2Particle;
+    particle_types_[promod3::loop::TYR_CA] = CH1Particle;
+    particle_types_[promod3::loop::THR_CG2] = CH3Particle;
+    particle_types_[promod3::loop::THR_CB] = CH2Particle;
+    particle_types_[promod3::loop::THR_CA] = CH1Particle;
+    particle_types_[promod3::loop::VAL_CG1] = CH3Particle;
+    particle_types_[promod3::loop::VAL_CG2] = CH3Particle;
+    particle_types_[promod3::loop::VAL_CB] = CH2Particle;
+    particle_types_[promod3::loop::VAL_CA] = CH1Particle;
+    particle_types_[promod3::loop::ILE_CG1] = CH2Particle;
+    particle_types_[promod3::loop::ILE_CG2] = CH3Particle;
+    particle_types_[promod3::loop::ILE_CD1] = CH3Particle;
+    particle_types_[promod3::loop::ILE_CB] = CH2Particle;
+    particle_types_[promod3::loop::ILE_CA] = CH1Particle;
+    particle_types_[promod3::loop::LEU_CG] = CH1Particle;
+    particle_types_[promod3::loop::LEU_CD1] = CH3Particle;
+    particle_types_[promod3::loop::LEU_CD2] = CH3Particle;
+    particle_types_[promod3::loop::LEU_CB] = CH2Particle;
+    particle_types_[promod3::loop::LEU_CA] = CH1Particle;
+    particle_types_[promod3::loop::PRO_CG] = CH2Particle;
+    particle_types_[promod3::loop::PRO_CD] = CH2Particle;
+    particle_types_[promod3::loop::PRO_CB] = CH2Particle;
+    particle_types_[promod3::loop::PRO_CA] = CH1Particle;
+    particle_types_[promod3::loop::HIS_CB] = CH2Particle;
+    particle_types_[promod3::loop::HIS_CA] = CH1Particle;
+    particle_types_[promod3::loop::PHE_CB] = CH2Particle;
+    particle_types_[promod3::loop::PHE_CA] = CH1Particle;
+    particle_types_[promod3::loop::ALA_CB] = CH3Particle;
+    particle_types_[promod3::loop::ALA_CA] = CH1Particle;
+    particle_types_[promod3::loop::GLY_CA] = CH2Particle;
+  }  
+
+
+  static const SCWRL4RotamerParam& Instance() {
+    static SCWRL4RotamerParam scwrl4_param;
+    return scwrl4_param;
+  }
+
+
+  Real GetHydrogenCharge(RotamerID rot_id, int hydrogen_idx) const{
+    ost::conop::AminoAcid aa = RotIDToAA(rot_id);
+    promod3::loop::AminoAcidHydrogen aah = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAH(aa, hydrogen_idx);
+    return hydrogen_charges_[aah];
+  }
+
+
+  Real GetHeavyAtomCharge(RotamerID rot_id, int atom_idx) const{
+    ost::conop::AminoAcid aa = RotIDToAA(rot_id);
+    promod3::loop::AminoAcidAtom aaa = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAA(aa, atom_idx);
+    return heavy_atom_charges_[aaa];
+  }
+
+
+  int GetPolarAnchor(RotamerID rot_id, int hydrogen_idx) const {
+    ost::conop::AminoAcid aa = RotIDToAA(rot_id);
+    promod3::loop::AminoAcidHydrogen aah = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAH(aa, hydrogen_idx);
+    return polar_anchor_[aah];    
+  }
+
+
+  SCWRL4ParticleType GetParticleType(RotamerID rot_id, int atom_idx) const {
+    ost::conop::AminoAcid aa = RotIDToAA(rot_id);
+    promod3::loop::AminoAcidAtom aaa = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAA(aa, atom_idx);
+    return particle_types_[aaa];
+  }
+
+
+  int GetLPInfoIdx(RotamerID rot_id, int atom_idx) const {
+
+    // this is an ugly hack for histidine... 
+    if((rot_id == HSD && atom_idx == promod3::loop::HIS_ND1_INDEX) ||
+       (rot_id == HSE && atom_idx == promod3::loop::HIS_NE2_INDEX)) {
+      return -1;
     }
 
-    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, true, 
-                                      promod3::loop::PROT_STATE_HISH);
+    ost::conop::AminoAcid aa = RotIDToAA(rot_id);
+    promod3::loop::AminoAcidAtom aaa = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAA(aa, atom_idx);
+    return lone_pair_info_idx_[aaa];
   }
 
-  int num_particles = info.particles.size();
-  std::vector<Particle> particles(num_particles);
-
-  this->ConstructBaseParticles(info, id, particles);
-
-  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
-                                                       residue_index);
 
-  return p;
-}
-
-FrameResiduePtr SCWRL4RotamerConstructor::ConstructSidechainFrameResidue(
-          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
-          RotamerID id, uint residue_index) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructSidechainFrameResidue", 2);
-
-  if(id == XXX) {
-    throw promod3::Error("Cannot construct FrameResidue for unknown "
-                         "rotamer id!");
+  const SCWRL4LPInfo& GetLP(int idx) const {
+    return lone_pair_infos_[idx];
   }
 
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
 
-  for(uint i = 0; i < info.particles.size(); ++i){
-    if(!info.particles[i].is_hydrogen){
-      if(!all_atom.IsSet(aa_res_idx, info.particles[i].atom_idx)){
-        throw promod3::Error("Expected atom " + info.particles[i].name +
-                             " to be set in all_atom");
-      }
-      pos_buffer_->SetPos(id, info.particles[i].atom_idx, 
-                          all_atom.GetPos(aa_res_idx, info.particles[i].atom_idx));
-    }
+  void AddLP(RotamerID id, int p_idx, int idx_a, int idx_b, int idx_c, 
+             bool a_ih, bool b_ih, bool c_ih, SCWRL4LPRule r) {
+    ost::conop::AminoAcid aa = RotIDToAA(id);
+    promod3::loop::AminoAcidAtom aaa = 
+    promod3::loop::AminoAcidLookup::GetInstance().GetAAA(aa, p_idx);
+    lone_pair_info_idx_[aaa] = lone_pair_infos_.size();
+    SCWRL4LPInfo lp(idx_a, idx_b, idx_c, a_ih, b_ih, c_ih, r);
+    lone_pair_infos_.push_back(lp);
   }
 
-  //set hydrogens
-  if(info.has_hydrogens){
-    // to construct hydrogens, we might also need backbone atoms in the buffer
-    const SCWRLRotamerInfo& bb_info = rotamer_lookup_.GetBackboneInfo(id);
-
-    for(uint i = 0; i < bb_info.particles.size(); ++i){
-      if(!bb_info.particles[i].is_hydrogen){
-        if(!all_atom.IsSet(aa_res_idx, bb_info.particles[i].atom_idx)){
-          throw promod3::Error("Expected atom " + bb_info.particles[i].name +
-                               " to be set in all_atom");
-        }
-        pos_buffer_->SetPos(id, bb_info.particles[i].atom_idx, 
-                            all_atom.GetPos(aa_res_idx, bb_info.particles[i].atom_idx));
-      }
-    }
 
-    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, true, 
-                                      promod3::loop::PROT_STATE_HISH);
+  int AddLP(int idx_a, int idx_b, int idx_c, 
+            bool a_ih, bool b_ih, bool c_ih, SCWRL4LPRule r) {
+    SCWRL4LPInfo lp(idx_a, idx_b, idx_c, a_ih, b_ih, c_ih, r);
+    lone_pair_infos_.push_back(lp);
+    return lone_pair_infos_.size() - 1;
   }
+ 
 
-  int num_particles = info.particles.size();
-  std::vector<Particle> particles(num_particles);
+  Real hydrogen_charges_[promod3::loop::XXX_NUM_HYDROGENS];
+  Real heavy_atom_charges_[promod3::loop::XXX_NUM_ATOMS];
+  int polar_anchor_[promod3::loop::XXX_NUM_HYDROGENS];
+  int lone_pair_info_idx_[promod3::loop::XXX_NUM_ATOMS];
+  std::vector<SCWRL4LPInfo> lone_pair_infos_;
+  SCWRL4ParticleType particle_types_[promod3::loop::XXX_NUM_ATOMS];
+};
 
-  this->ConstructBaseParticles(info, id, particles);
 
-  FrameResiduePtr p = boost::make_shared<FrameResidue>(particles, 
-                                                       residue_index);
+SCWRL4RotamerConstructor::SCWRL4RotamerConstructor(bool cb_in_sidechain): 
+                                RotamerConstructor(cb_in_sidechain, POLAR_HYDROGEN_MODE,
+                                                   SCWRL4RotamerParam::Instance()) { }
 
-  return p; 
-}
 
 FrameResiduePtr SCWRL4RotamerConstructor::ConstructFrameResidue(
           const ost::mol::ResidueHandle& res, uint residue_index) {
@@ -1708,8 +932,11 @@ FrameResiduePtr SCWRL4RotamerConstructor::ConstructFrameResidueHeuristic(
 }
 
 
-
-void SCWRL4RotamerConstructor::AssignInternalEnergies(RRMRotamerGroupPtr group) {
+void SCWRL4RotamerConstructor::AssignInternalEnergies(RRMRotamerGroupPtr group,
+                                                      RotamerID id, 
+                                                      uint residue_index,
+                                                      Real phi, Real psi,
+                                                      bool n_ter, bool c_ter) {
 
   core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
           "SCWRL4RotamerConstructor::AssignInternalEnergies", 2);
@@ -1724,7 +951,12 @@ void SCWRL4RotamerConstructor::AssignInternalEnergies(RRMRotamerGroupPtr group)
   }
 }
 
-void SCWRL4RotamerConstructor::AssignInternalEnergies(FRMRotamerGroupPtr group) {
+
+void SCWRL4RotamerConstructor::AssignInternalEnergies(FRMRotamerGroupPtr group,
+                                                      RotamerID id, 
+                                                      uint residue_index,
+                                                      Real phi, Real psi,
+                                                      bool n_ter, bool c_ter) {
 
   core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
           "SCWRL4RotamerConstructor::AssignInternalEnergies", 2);
@@ -1739,466 +971,70 @@ void SCWRL4RotamerConstructor::AssignInternalEnergies(FRMRotamerGroupPtr group)
   }
 }
 
-// INTERNAL FUNCTIONS
-
-RRMRotamerGroupPtr SCWRL4RotamerConstructor::ConstructRRMGroup(
-          RotamerID id, uint residue_index, 
-          std::pair<RotamerLibEntry*,uint> lib_entries, 
-          Real probability_cutoff) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructRRMGroup", 2);
-
-  std::vector<RRMRotamerPtr> rotamers;
-  Real summed_prob = 0.0;
-
-  // in case of his, we have to move the backbone positions in the buffer
-  // to the locations defining his in the different protonation states
-  if(id == HIS){
-    MVBBPosBuffer(HIS, HSD);
-    MVBBPosBuffer(HIS, HSE);
-  }
-
-  // in case of alanine and glycine, the rotamer libraries won't have any 
-  // entries. For consistency we nevertheless construct rotamers.
-  // We simply add a fake RotamerLibEntry in this case that has
-  // no sidechain dihedrals set.
-  std::vector<RotamerLibEntry> fake_rotamers(1);
-  if(lib_entries.second == 0 && (id == ALA || id == GLY)) {
-    // we have to make sure, that the according probability really is one!
-    fake_rotamers[0].probability = 1.0;
-    lib_entries = std::make_pair(&fake_rotamers[0], 1);
-  }
-  else if(lib_entries.second == 0) {
-    throw promod3::Error("Did not find any rotamers in Rotamer Library!");
-  }
-
-  for(uint i = 0; i < lib_entries.second; ++i){
-
-    probability_ = lib_entries.first[i].probability;
-    summed_prob += probability_;
-    chi_angles_[0] = lib_entries.first[i].chi1;
-    chi_angles_[1] = lib_entries.first[i].chi2;
-    chi_angles_[2] = lib_entries.first[i].chi3;
-    chi_angles_[3] = lib_entries.first[i].chi4;
-
-    switch(id){
-      case HIS:{
-        rotamers.push_back(ConstructRRM(HSE, residue_index));
-        rotamers.push_back(ConstructRRM(HSD, residue_index));
-        break;
-      }
-      case SER:{
-        chi_angles_[1] = Real(M_PI);
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        chi_angles_[1] = Real(M_PI) / 3.0;
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        chi_angles_[1] = -Real(M_PI) / 3.0;
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        break;
-      }
-      case THR:{
-        chi_angles_[1] = Real(M_PI);
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        chi_angles_[1] = Real(M_PI) / 3.0;
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        chi_angles_[1] = -Real(M_PI) / 3.0;
-        rotamers.push_back(ConstructRRM(id, residue_index)); 
-        break;       
-      }
-      case TYR:{
-        chi_angles_[2] = Real(M_PI);
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        chi_angles_[2] = Real(0.0);
-        rotamers.push_back(ConstructRRM(id, residue_index));
-        break;
-      }
-      default:{
-        rotamers.push_back(ConstructRRM(id, residue_index));
-      }
-    }
-
-    if(summed_prob >= probability_cutoff && !rotamers.empty()) break;
-  } 
-  
-  RRMRotamerGroupPtr group = boost::make_shared<RRMRotamerGroup>(rotamers,
-                                                                 residue_index);
-  this->AssignInternalEnergies(group);
-  return group;
-}
-
-FRMRotamerGroupPtr SCWRL4RotamerConstructor::ConstructFRMGroup(
-          RotamerID id, uint residue_index, 
-          std::pair<RotamerLibEntry*,uint> lib_entries, 
-          Real probability_cutoff) {
 
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructFRMGroup", 2);
+void SCWRL4RotamerConstructor::ParametrizeParticle(int at_idx, 
+                                                   bool is_hydrogen, 
+                                                   Particle& particle) {
 
-  std::vector<FRMRotamerPtr> rotamers;
-  Real summed_prob = 0.0;
-
-  // in case of his, we have to move the backbone positions in the buffer
-  // to the locations defining his in the different protonation states
-  if(id == HIS){
-    MVBBPosBuffer(HIS, HSD);
-    MVBBPosBuffer(HIS, HSE);
-  }
-
-  // in case of alanine and glycine, the rotamer libraries won't have any 
-  // entries. For consistency we nevertheless construct rotamers.
-  // We simply add a fake RotamerLibEntry in this case that has
-  // no sidechain dihedrals set.
-  std::vector<RotamerLibEntry> fake_rotamers(1);
-  if(lib_entries.second == 0 && (id == ALA || id == GLY)) {
-    // we have to make sure, that the according probability really is one!
-    fake_rotamers[0].probability = 1.0;
-    lib_entries = std::make_pair(&fake_rotamers[0], 1);
-  }
-  else if(lib_entries.second == 0) {
-    throw promod3::Error("Did not find any rotamers in Rotamer Library!");
-  }
+  if(is_hydrogen) {
 
-  for(uint i = 0; i < lib_entries.second; ++i){
-    probability_ = lib_entries.first[i].probability;
-    summed_prob += probability_;
-    chi_angles_[0] = lib_entries.first[i].chi1;
-    chi_angles_[1] = lib_entries.first[i].chi2;
-    chi_angles_[2] = lib_entries.first[i].chi3;
-    chi_angles_[3] = lib_entries.first[i].chi4;
-    chi_dev_[0] = lib_entries.first[i].sig1;
-    chi_dev_[1] = lib_entries.first[i].sig2;
-    chi_dev_[2] = lib_entries.first[i].sig3;
-    chi_dev_[3] = lib_entries.first[i].sig4;
-
-    switch(id){
-      case HIS:{
-        rotamers.push_back(ConstructFRM(HSE, residue_index));
-        rotamers.push_back(ConstructFRM(HSD, residue_index));
-        break;
-      }
-      case SER:{
-        chi_dev_[1] = Real(0.17453);
-        chi_angles_[1] = Real(M_PI);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        chi_angles_[1] = Real(M_PI) / Real(3.0);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        chi_angles_[1] = -Real(M_PI) / Real(3.0);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        break;
-      }
-      case THR:{
-        chi_dev_[1] = Real(0.17453);
-        chi_angles_[1] = Real(M_PI);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        chi_angles_[1] = Real(M_PI) / Real(3.0);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        chi_angles_[1] = -Real(M_PI) / Real(3.0);
-        rotamers.push_back(ConstructFRM(id, residue_index)); 
-        break;       
-      }
-      case TYR:{
-        chi_dev_[2] = Real(0.17453);
-        chi_angles_[2] = Real(M_PI);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        chi_angles_[2] = Real(0.0);
-        rotamers.push_back(ConstructFRM(id, residue_index));
-        break;
-      }
-      default: rotamers.push_back(ConstructFRM(id, residue_index));
-    }
-
-    if(summed_prob >= probability_cutoff && !rotamers.empty()) break;
-  } 
-  
-  FRMRotamerGroupPtr group = boost::make_shared<FRMRotamerGroup>(rotamers,
-                                                                 residue_index);
-  this->AssignInternalEnergies(group);
-  return group;
-}
-
-RRMRotamerPtr SCWRL4RotamerConstructor::ConstructRRM(RotamerID id, 
-                                                    uint residue_idx) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructRRM", 2);
-
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
-  int num_particles = rotamer_lookup_.GetNumSidechainParticles(id);
-  std::vector<Particle> particles(num_particles);
-
-  //set the positions
-  promod3::loop::ConstructSidechainAtoms(*pos_buffer_, id, chi_angles_[0], 
-                                         chi_angles_[1], chi_angles_[2],
-                                         chi_angles_[3]);
-
-  if(info.has_hydrogens){
-
-    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, true, 
-                                      promod3::loop::PROT_STATE_HISH);
-
-    // If there are any custom rules, we apply them now and overrule the
-    // default hydrogen construction
-    if(!info.custom_hydrogens.empty()){
-      for(uint i = 0; i < info.custom_hydrogens.size(); ++i){
-        const SCWRLCustomHydrogenInfo& h_info = info.custom_hydrogens[i];
-        geom::Vec3 anchor_one, anchor_two, anchor_three, new_h_pos;
-        anchor_one = pos_buffer_->GetPos(id, h_info.anchor_idx_one);
-        anchor_two = pos_buffer_->GetPos(id, h_info.anchor_idx_two);
-        anchor_three = pos_buffer_->GetPos(id, h_info.anchor_idx_three);
-        promod3::core::ConstructAtomPos(anchor_one, anchor_two, anchor_three,
-                                        h_info.bond_length, h_info.angle, 
-                                        chi_angles_[h_info.chi_idx], new_h_pos);
-        hydrogen_buffer_->SetPos(h_info.atom_idx, new_h_pos);
-      }
-    }
-  }
-
-  this->ConstructBaseParticles(info, id, particles);
-
-  RRMRotamerPtr rot = boost::make_shared<RRMRotamer>(particles, 
-                                                     probability_, 
-                                                     info.internal_e_prefactor);
-
-  return rot;  
-}
-
-FRMRotamerPtr SCWRL4RotamerConstructor::ConstructFRM(RotamerID id,
-                                                    uint residue_idx) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructFRM", 2);
-
-  const SCWRLRotamerInfo& info = rotamer_lookup_.GetSidechainInfo(id);
-  int num_rrm_particles = rotamer_lookup_.GetNumSidechainParticles(id);
-  int num_particles = rotamer_lookup_.GetNumFRMSidechainParticles(id);
-  std::vector<Particle> particles(num_particles);
-
-  //set the positions
-  promod3::loop::ConstructSidechainAtoms(*pos_buffer_, id, chi_angles_[0], 
-                                         chi_angles_[1], chi_angles_[2],
-                                         chi_angles_[3]);
-  if(info.has_hydrogens){
-    promod3::loop::ConstructHydrogens(*pos_buffer_, id, *hydrogen_buffer_, true, 
-                                      promod3::loop::PROT_STATE_HISH);
-    // If there are any custom rules, we apply them now an overrule the
-    // default hydrogen construction
-    if(!info.custom_hydrogens.empty()){
-      for(uint i = 0; i < info.custom_hydrogens.size(); ++i){
-        const SCWRLCustomHydrogenInfo& h_info = info.custom_hydrogens[i];
-        geom::Vec3 anchor_one, anchor_two, anchor_three, new_h_pos;
-        anchor_one = pos_buffer_->GetPos(id, h_info.anchor_idx_one);
-        anchor_two = pos_buffer_->GetPos(id, h_info.anchor_idx_two);
-        anchor_three = pos_buffer_->GetPos(id, h_info.anchor_idx_three);
-        promod3::core::ConstructAtomPos(anchor_one, anchor_two, anchor_three,
-                                        h_info.bond_length, h_info.angle, 
-                                        chi_angles_[h_info.chi_idx], new_h_pos);
-        hydrogen_buffer_->SetPos(h_info.atom_idx, new_h_pos);
-      }
+    Real charge = SCWRL4RotamerParam::Instance().GetHydrogenCharge(id_, at_idx);
+    SCWRL4Param* p = new SCWRL4Param(HParticle, 
+                                     hydrogen_buffer_->GetPos(at_idx), 
+                                     charge);
+    int polar_anchor = SCWRL4RotamerParam::Instance().GetPolarAnchor(id_, at_idx);
+    if(polar_anchor != -1) {
+      geom::Vec3 polar_direction = hydrogen_buffer_->GetPos(at_idx) - 
+                                   pos_buffer_->GetPos(id_, polar_anchor);
+      p->SetPolarDirection(polar_direction);
     }
-  }
-
-  this->ConstructBaseParticles(info, id, particles);
-
-  // Keep track of the subrotamers
-  std::vector<std::vector<int> > subrotamer_definitions;
-  std::vector<int> actual_definition;
-  actual_definition.resize(num_rrm_particles);
-  // Directly add the first particles as first subrotamer
-  for(int i = 0; i < num_rrm_particles; ++i) actual_definition[i] = i;
-  subrotamer_definitions.push_back(actual_definition);
-
-  const std::vector<SCWRLFRMRule>& frm_rules = rotamer_lookup_.GetFRMRules(id);
-  geom::Vec3 rot_axis, rot_anchor;
-  geom::Vec3 orig_pos, rot_pos;
-  geom::Mat4 transform;
-  int base_idx = num_rrm_particles;
-
-  for(uint frm_rule_idx = 0; frm_rule_idx < frm_rules.size(); ++frm_rule_idx){
-    const SCWRLFRMRule& frm_rule = frm_rules[frm_rule_idx];
-    int num_fix_particles = frm_rule.fix_particles.size();
-    int num_rotating_particles = frm_rule.rotating_particles.size();
-
-    // Update the subrotamer definition... all particles that are fixed are 
-    // taken from the first subrotamer.
-    for(int i = 0; i < num_fix_particles; ++i) {
-      actual_definition[i] = frm_rule.fix_particles[i];
-    }
-
-    // The data required for the rotation around the specified axis
-    rot_anchor = pos_buffer_->GetPos(id, frm_rule.anchor_idx_two);
-    rot_axis = rot_anchor - pos_buffer_->GetPos(id, frm_rule.anchor_idx_one); 
-
-    // Every rotation results in a new subrotamer
-    for(uint prefac_idx = 0; prefac_idx < frm_rule.prefactors.size(); 
-        ++prefac_idx){
-
-      // Get the rotation matrix
-      Real rot_angle = frm_rule.prefactors[prefac_idx] * chi_dev_[frm_rule_idx];
-      transform = promod3::core::RotationAroundLine(rot_axis, rot_anchor,
-                                                    rot_angle);
-
-      for(int i = 0; i < num_rotating_particles; ++i){
-        int orig_particle_idx = frm_rule.rotating_particles[i];
-        int new_particle_idx = base_idx + i;
-
-        // replace the old with the new index...
-        actual_definition[orig_particle_idx] = new_particle_idx;
-
-        // construct the rotated particle
-        particles[new_particle_idx] = particles[orig_particle_idx];
-        particles[new_particle_idx].ApplyTransform(transform);
-      }
-
-      subrotamer_definitions.push_back(actual_definition);
-
-      // start of next subrotamer
-      base_idx += num_rotating_particles;
-    }
-  }
-
-  FRMRotamerPtr r = boost::make_shared<FRMRotamer>(particles,
-                                                   info.frm_t, probability_,
-                                                   info.internal_e_prefactor);
-
-  for(uint i = 0; i < subrotamer_definitions.size(); ++i) {
-    r->AddSubrotamerDefinition(subrotamer_definitions[i]);
-  }
-
-  return r;
-}
-
-void SCWRL4RotamerConstructor::MVBBPosBuffer(RotamerID from, RotamerID to) {
-  pos_buffer_->SetPos(to, promod3::loop::BB_N_INDEX, 
-                      pos_buffer_->GetPos(from, promod3::loop::BB_N_INDEX));
-  pos_buffer_->SetPos(to, promod3::loop::BB_CA_INDEX, 
-                      pos_buffer_->GetPos(from, promod3::loop::BB_CA_INDEX));
-  pos_buffer_->SetPos(to, promod3::loop::BB_C_INDEX, 
-                      pos_buffer_->GetPos(from, promod3::loop::BB_C_INDEX));
-  pos_buffer_->SetPos(to, promod3::loop::BB_O_INDEX, 
-                      pos_buffer_->GetPos(from, promod3::loop::BB_O_INDEX));
-  // Even though we officially count CB as a sidechain atom, we still move it
-  // since its completely independent of any sidechain dihedral angle and
-  // cannot be constructed anyway
-  pos_buffer_->SetPos(to, promod3::loop::BB_CB_INDEX, 
-                      pos_buffer_->GetPos(from, promod3::loop::BB_CB_INDEX));
-}
-
-void SCWRL4RotamerConstructor::ConstructBaseParticles(const SCWRLRotamerInfo& info,
-                                                     RotamerID id,
-                                                     std::vector<Particle>& particles) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructBaseParticles", 2);
-
-  geom::Vec3 a, b, c;
-
-  // generate the particles
-  for(uint i = 0; i < info.particles.size(); ++i){
-    const SCWRLPInfo& pinfo = info.particles[i];
-    if(pinfo.is_hydrogen){
-      a = hydrogen_buffer_->GetPos(pinfo.atom_idx);
-    }
-    else a = pos_buffer_->GetPos(id, pinfo.atom_idx);
-    particles[i] = Particle(pinfo.name, new SCWRL4Param(pinfo.type, a, 
-                                                        pinfo.charge));
-  }
-
-  // set the polar directions
-  for(uint i = 0; i < info.polar_directions.size(); ++i){
-    a = hydrogen_buffer_->GetPos(info.polar_directions[i].polar_idx);
-    b = pos_buffer_->GetPos(id, info.polar_directions[i].anchor_idx);
-    PScoringParam* p = particles[info.polar_directions[i].p_idx].GetSParam();
-    reinterpret_cast<SCWRL4Param*>(p)->SetPolarDirection(a - b);
-  }
-
-  // set the lone pairs
-  for(uint i = 0; i < info.lone_pairs.size(); ++i){
-    const SCWRLLPInfo& lp = info.lone_pairs[i];
-
-    if(lp.A_is_hydrogen) a = hydrogen_buffer_->GetPos(lp.index_A);
-    else a = pos_buffer_->GetPos(id, lp.index_A);
+    particle.SetSParam(p);
+  } else {
+
+    // deal with terminal special cases
+    if(at_idx == -1) {
+      // manual setup
+      SCWRL4Param* p = new SCWRL4Param(OParticle, terminal_o_pos_,  -0.55);
+      _AddLonePairsCarbonyl(pos_buffer_->GetPos(id_, promod3::loop::BB_CA_INDEX), 
+                            pos_buffer_->GetPos(id_, promod3::loop::BB_C_INDEX), 
+                            terminal_o_pos_, p);
+      particle.SetSParam(p);
+    } else if(at_idx == -2) {
+      // manual setup
+      SCWRL4Param* p = new SCWRL4Param(OParticle, terminal_oxt_pos_,  -0.55);
+      _AddLonePairsCarbonyl(pos_buffer_->GetPos(id_, promod3::loop::BB_CA_INDEX), 
+                            pos_buffer_->GetPos(id_, promod3::loop::BB_C_INDEX), 
+                            terminal_oxt_pos_, p);
+      particle.SetSParam(p);
+    } else {
+      SCWRL4ParticleType particle_type = 
+      SCWRL4RotamerParam::Instance().GetParticleType(id_, at_idx);
+      geom::Vec3 pos = pos_buffer_->GetPos(id_, at_idx);      
+      Real charge = 
+      SCWRL4RotamerParam::Instance().GetHeavyAtomCharge(id_, at_idx);
+      SCWRL4Param* p = new SCWRL4Param(particle_type, pos, charge);
+
+      int lpi_idx = SCWRL4RotamerParam::Instance().GetLPInfoIdx(id_, at_idx);
+
+      // check whether we have a valid lone pair idx, as well as whether we're
+      // with a n_terminal nitrogen. The latter also has no lone pair
+      //if(lpi_idx != -1 && !(n_ter_ && at_idx == promod3::loop::BB_N_INDEX)) {
+      if(lpi_idx != -1) {
+        const SCWRL4LPInfo& lp = SCWRL4RotamerParam::Instance().GetLP(lpi_idx);
+        geom::Vec3 a, b, c;
+
+        if(lp.A_is_hydrogen) a = hydrogen_buffer_->GetPos(lp.index_A);
+        else a = pos_buffer_->GetPos(id_, lp.index_A);
     
-    if(lp.B_is_hydrogen) b = hydrogen_buffer_->GetPos(lp.index_B);
-    else  b = pos_buffer_->GetPos(id, lp.index_B);
+        if(lp.B_is_hydrogen) b = hydrogen_buffer_->GetPos(lp.index_B);
+        else  b = pos_buffer_->GetPos(id_, lp.index_B);
     
-    if(lp.C_is_hydrogen) c = hydrogen_buffer_->GetPos(lp.index_C);
-    else c = pos_buffer_->GetPos(id, lp.index_C);
+        if(lp.C_is_hydrogen) c = hydrogen_buffer_->GetPos(lp.index_C);
+        else c = pos_buffer_->GetPos(id_, lp.index_C);
     
-    EvalLonePairRule(reinterpret_cast<SCWRL4Param*>(particles[lp.p_idx].GetSParam()), 
-                     lp.rule, a, b, c);
-  }
-}
-
-void SCWRL4RotamerConstructor::ConstructBBFrameParticles(
-                                 const SCWRLRotamerInfo& info, RotamerID id,
-                                 bool n_ter, bool c_ter,
-                                 std::vector<Particle>& particles) {
-
-  core::ScopedTimerPtr prof = core::StaticRuntimeProfiler::StartScoped(
-          "SCWRL4RotamerConstructor::ConstructBBFrameParticles", 2);
-
-  ConstructBaseParticles(info, id, particles);
-  if(!(n_ter || c_ter)) return; // we're already done
-  
-  int p_idx = info.particles.size();
-
-  if(c_ter){
-    geom::Vec3 oxt_pos;
-    geom::Vec3 c_pos = pos_buffer_->GetPos(id, promod3::loop::BB_C_INDEX);
-    geom::Vec3 ca_pos = pos_buffer_->GetPos(id, promod3::loop::BB_CA_INDEX);
-    geom::Vec3 n_pos = pos_buffer_->GetPos(id, promod3::loop::BB_N_INDEX);
-    geom::Vec3 o_pos = pos_buffer_->GetPos(id, promod3::loop::BB_O_INDEX);
-    promod3::core::ConstructCTerminalOxygens(c_pos, ca_pos, n_pos,
-                                             o_pos, oxt_pos);
-    //manually add oxygen without a rule...    
-    particles[p_idx] = Particle("OT", new SCWRL4Param(OParticle, 
-                                                      oxt_pos, -0.55));
-    _AddLonePairsCarbonyl(ca_pos, c_pos, oxt_pos, 
-      reinterpret_cast<SCWRL4Param*>(particles[p_idx].GetSParam()));
-    ++p_idx;
-  }
-
-  if(n_ter){
-    geom::Vec3 ht1_pos, ht2_pos, ht3_pos;
-    geom::Vec3 n_pos, ca_pos, c_pos;
-    n_pos = pos_buffer_->GetPos(id, promod3::loop::BB_N_INDEX);
-    ca_pos = pos_buffer_->GetPos(id, promod3::loop::BB_CA_INDEX);
-    c_pos = pos_buffer_->GetPos(id, promod3::loop::BB_C_INDEX);
-    promod3::core::ConstructAtomPos(c_pos, ca_pos, n_pos, 0.997, 2.042, 
-                                    1.0472, ht1_pos);
-    promod3::core::ConstructAtomPos(c_pos,ca_pos,n_pos,0.997, 2.042, 
-                                    -1.0472, ht2_pos);
-    particles[p_idx] = Particle("HT1", new SCWRL4Param(HParticle, 
-                                                       ht1_pos, 0.35));
-    SCWRL4Param* p = reinterpret_cast<SCWRL4Param*>(particles[p_idx].GetSParam());
-    p->SetPolarDirection(ht1_pos - n_pos);
-
-    particles[p_idx + 1] = Particle("HT2", new SCWRL4Param(HParticle, 
-                                                           ht2_pos, 0.35));
-    p = reinterpret_cast<SCWRL4Param*>(particles[p_idx + 1].GetSParam());
-    p->SetPolarDirection(ht2_pos - n_pos);
-
-    if(id == PRO || id == TPR || id == CPR) {
-      // there are only two hydrogens... please note, that they are not
-      // optimally placed in case of proline. 
-      // we would have to consider CD for that. This costs a good bottle 
-      // of wine that I implement that correctly...
-      return;
-    }
-
-    promod3::core::ConstructAtomPos(c_pos, ca_pos, n_pos, 0.997, 2.042, 
-                                    M_PI, ht3_pos);
-    // we assume, that there is currently one hydrogen apart from ht1 and ht2 
-    // and replace it with ht3
-    for(uint i = 0; i < info.particles.size(); ++i){
-      if(info.particles[i].is_hydrogen){
-        particles[i] = Particle("HT3", new SCWRL4Param(HParticle, 
-                                                       ht3_pos, 0.35));
-        SCWRL4Param* p = reinterpret_cast<SCWRL4Param*>(particles[i].GetSParam());
-        p->SetPolarDirection(ht3_pos - n_pos);
-        break;
-      }
+        EvalLonePairRule(p, lp.rule, a, b, c);
+      } 
+      particle.SetSParam(p);     
     }
   }
 }
diff --git a/sidechain/src/scwrl4_rotamer_constructor.hh b/sidechain/src/scwrl4_rotamer_constructor.hh
index 887ea3c3..ea2bdb33 100644
--- a/sidechain/src/scwrl4_rotamer_constructor.hh
+++ b/sidechain/src/scwrl4_rotamer_constructor.hh
@@ -18,235 +18,12 @@
 #define PROMOD3_SCWRL_ROTAMER_CONSTRUCTOR_HH
 
 #include <promod3/sidechain/rotamer_constructor.hh>
-#include <promod3/sidechain/scwrl4_particle_scoring.hh>
 
 namespace promod3 { namespace sidechain {
 
 class SCWRL4RotamerConstructor;
 typedef boost::shared_ptr<SCWRL4RotamerConstructor> SCWRL4RotamerConstructorPtr;
 
-/// \brief Types of lone pair construction
-enum SCWRLLPRule {
-  LONE_PAIR_CARBONYL, LONE_PAIR_COH, LONE_PAIR_CNC
-};
-
-/// \brief Info for lone pair construction (always involves 3 particles)
-/// -> indices are in same order as particles. The lone pair gets finally added
-/// to particle with p_idx
-/// A, B and C are indices as they are stored in AllAtomPositions, p_idx is the 
-/// index of the particle in the rotamer, where the lone pairs get added
-struct SCWRLLPInfo {
-  SCWRLLPInfo() { }
-  SCWRLLPInfo(int idx_A, int idx_B, int idx_C,
-              bool a_ih, bool b_ih, bool c_ih, 
-              int p, SCWRLLPRule r)
-              : index_A(idx_A), index_B(idx_B),
-                index_C(idx_C), A_is_hydrogen(a_ih),
-                B_is_hydrogen(b_ih), C_is_hydrogen(c_ih),
-                p_idx(p), rule(r) { }
-  int index_A;
-  int index_B;
-  int index_C;
-  bool A_is_hydrogen;
-  bool B_is_hydrogen;
-  bool C_is_hydrogen;
-  int p_idx;
-  SCWRLLPRule rule;
-};
-
-/// \brief Info for polar direction construction. The polar direction is 
-///        particle_pos[polar_idx] - particle_pos[anchor_idx]
-///        The direction gets finally added to the particle with p_idx
-///        polar_idx and anchor idx are indices as they are stored in
-///        AllAtomPositions, p_idx is the index of the particle in the
-///        rotamer
-struct SCWRLPDInfo {
-  SCWRLPDInfo() { }
-  SCWRLPDInfo(int pol_idx, int a_idx, int p_idx) : polar_idx(pol_idx), 
-                                                   anchor_idx(a_idx),
-                                                   p_idx(p_idx) { }
-  int polar_idx;
-  int anchor_idx;
-  int p_idx;
-};
-
-/// \brief Info for particle construction
-struct SCWRLPInfo {
-  SCWRLPInfo() { }
-  SCWRLPInfo(SCWRL4ParticleType t, Real c, 
-             const String& n, int idx, bool ih) : type(t), charge(c), 
-                                                  name(n), atom_idx(idx), 
-                                                  is_hydrogen(ih) { }
-  SCWRL4ParticleType type;
-  Real charge;
-  String name;   // PDB naming
-  int atom_idx;  // for AllAtomPositions 
-                 // (idx in HydrogenStorage if is_hydrogen is true)
-  bool is_hydrogen;
-};
-
-/// \brief Info for custom particle construction...
-///        In the example of SER / THR and TYR we construct several hydrogens
-///        looking in different directions, they do therefore not follow the
-///        default hydrogen positioning conventions. 
-///        This rule defines how to construct them by using
-///        three indices of heavy atoms, a bond length and an angle. 
-///        The dihedral is defined as an index and is set globally in
-///        SCWRL4RotamerConstructor. The default hydrogen construction
-///        gets overriden for cases defined with such a SCWRLCustomHydrogenInfo
-struct SCWRLCustomHydrogenInfo {
-  SCWRLCustomHydrogenInfo() { }
-  SCWRLCustomHydrogenInfo(int idx, int a_idx_one, int a_idx_two, int a_idx_three, 
-                          Real bl, Real a, int c_idx): atom_idx(idx),
-                                                       anchor_idx_one(a_idx_one), 
-                                                       anchor_idx_two(a_idx_two), 
-                                                       anchor_idx_three(a_idx_three), 
-                                                       bond_length(bl), angle(a),
-                                                       chi_idx(c_idx){ }
-  int atom_idx; //the idx in the hydrogen constructor
-  int anchor_idx_one; // idx in AllAtomPositions
-  int anchor_idx_two; 
-  int anchor_idx_three;
-  Real bond_length;
-  Real angle;
-  int chi_idx;
-};
-
-/// \brief Info to generate FRM rotamers
-///        The idea is to only rotate around one bond at a time.
-///        This bond gets defined by anchor_idx_one and anchor_idx_two.
-///        All particles defined in rotating_particles get then rotated by
-///        a user defined angle times the defined prefactors.
-///        (three prefactors result in three subrotamers)
-struct SCWRLFRMRule{
-  SCWRLFRMRule() { }
-  int anchor_idx_one;
-  int anchor_idx_two;
-  std::vector<Real> prefactors;
-  std::vector<int> fix_particles;
-  std::vector<int> rotating_particles;
-};
-
-/// \brief Info to construct a full rotamer. 
-struct SCWRLRotamerInfo{
-  SCWRLRotamerInfo() { }
-  std::vector<SCWRLPInfo> particles;
-  std::vector<SCWRLCustomHydrogenInfo> custom_hydrogens;
-  std::vector<SCWRLLPInfo> lone_pairs;
-  std::vector<SCWRLPDInfo> polar_directions;
-  Real internal_e_prefactor;
-  Real frm_t;
-  bool has_hydrogens;
-};
-
-/// \brief Defines lookups to build rotamer stuff.
-class SCWRLRotamerLookup {
-public:
-
-  SCWRLRotamerLookup(bool cb_in_sidechain);
-
-  // Data access
-  const SCWRLRotamerInfo& GetSidechainInfo(RotamerID id) const { 
-    return sidechain_infos_[id]; 
-  }
-
-  const SCWRLRotamerInfo& GetBackboneInfo(RotamerID id) const { 
-    return backbone_infos_[id]; 
-  }
-
-  const std::vector<SCWRLFRMRule>& GetFRMRules(RotamerID id) const { 
-    return frm_rules_[id]; 
-  }
-
-  int GetNumSidechainParticles(RotamerID id) const { 
-    return num_sidechain_particles_[id]; 
-  }
-
-  int GetNumBackboneParticles(RotamerID id) const { 
-    return num_sidechain_particles_[id]; 
-  }
-
-  int GetNumFRMSidechainParticles(RotamerID id) const { 
-    return num_frm_particles_[id]; 
-  }
-
-private:
-
-  void AddInfo(RotamerID id, SCWRL4ParticleType p_type, Real charge, 
-               const String& name, int idx, bool is_h){
-    SCWRLPInfo p(p_type, charge, name, idx, is_h);
-    sidechain_infos_[id].particles.push_back(p);
-  }
-
-  void AddCustomHydrogenInfo(RotamerID id, int idx, 
-                             int a_idx_one, int a_idx_two, int a_idx_three, 
-                             Real bl, Real a, int c_idx){
-    SCWRLCustomHydrogenInfo i(idx, a_idx_one, a_idx_two, a_idx_three, bl, 
-                              a, c_idx);
-    sidechain_infos_[id].custom_hydrogens.push_back(i);
-  }
-
-  void AddBBInfo(RotamerID id, SCWRL4ParticleType p_type, Real charge, 
-                 const String& name, int idx, bool is_h){
-    SCWRLPInfo p(p_type, charge, name, idx, is_h);
-    backbone_infos_[id].particles.push_back(p);
-  }
-
-  void AddPDir(RotamerID id, int polar_idx, int anchor_idx, int p_idx){
-    SCWRLPDInfo p(polar_idx, anchor_idx, p_idx);
-    sidechain_infos_[id].polar_directions.push_back(p);
-  }
-
-  void AddBBPDir(RotamerID id, int polar_idx, int anchor_idx, int p_idx){
-    SCWRLPDInfo p(polar_idx, anchor_idx, p_idx);
-    backbone_infos_[id].polar_directions.push_back(p);    
-  }
-
-  void AddLP(RotamerID id, int idx_a, int idx_b, int idx_c, 
-             bool a_ih, bool b_ih, bool c_ih, int p_idx, SCWRLLPRule r){
-    SCWRLLPInfo lp(idx_a, idx_b, idx_c, a_ih, b_ih, c_ih, p_idx, r);
-    sidechain_infos_[id].lone_pairs.push_back(lp);
-  }
-
-  void AddBBLP(RotamerID id, int idx_a, int idx_b, int idx_c, 
-               bool a_ih, bool b_ih, bool c_ih, int p_idx, SCWRLLPRule r){
-    SCWRLLPInfo lp(idx_a, idx_b, idx_c, a_ih, b_ih, c_ih, p_idx, r);
-    backbone_infos_[id].lone_pairs.push_back(lp);
-  }
-
-  void AddFRMRule(RotamerID id, int idx_one, int idx_two){
-    frm_rules_[id].push_back(SCWRLFRMRule());
-    frm_rules_[id].back().anchor_idx_one = idx_one;
-    frm_rules_[id].back().anchor_idx_two = idx_two;
-  }
-
-  void AddFRMPrefactor(RotamerID id, int rule_idx, Real prefactor){
-    frm_rules_[id][rule_idx].prefactors.push_back(prefactor);
-  }
-
-  void AddFRMRotatingParticle(RotamerID id, int rule_idx, int p_idx){
-    frm_rules_[id][rule_idx].rotating_particles.push_back(p_idx);
-  }
-
-  void AddFRMFixParticle(RotamerID id, int rule_idx, int p_idx){
-    frm_rules_[id][rule_idx].fix_particles.push_back(p_idx);
-  }
-
-  // To construct classical rotamers or as lookup for sidechain frame residues
-  SCWRLRotamerInfo sidechain_infos_[XXX + 1];
-
-  // To construct backbone frame residues
-  SCWRLRotamerInfo backbone_infos_[XXX + 1];
-
-  // Additional info required for generating frm rotamers
-  std::vector<SCWRLFRMRule> frm_rules_[XXX + 1];
-
-  int num_sidechain_particles_[XXX + 1];
-  int num_backbone_particles_[XXX + 1];
-  int num_frm_particles_[XXX+1];
-};
-
-
 class SCWRL4RotamerConstructor : public RotamerConstructor{
 
 public:
@@ -255,26 +32,6 @@ public:
 
   virtual ~SCWRL4RotamerConstructor() { }
 
-  // Construct frame residues
-  virtual FrameResiduePtr ConstructBackboneFrameResidue(
-          const ost::mol::ResidueHandle& res, RotamerID id, uint residue_index,
-          Real phi, bool n_ter = false,
-          bool c_ter = false);
-
-  virtual FrameResiduePtr ConstructBackboneFrameResidue(
-          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
-          RotamerID id, uint residue_index,
-          Real phi, bool n_ter = false,
-          bool c_ter = false);
-  
-  virtual FrameResiduePtr ConstructSidechainFrameResidue(
-          const ost::mol::ResidueHandle& res, RotamerID id, 
-          uint residue_index);
-  
-  virtual FrameResiduePtr ConstructSidechainFrameResidue(
-          const promod3::loop::AllAtomPositions& all_atom, uint aa_res_idx, 
-          RotamerID id, uint residue_index);
-
   FrameResiduePtr ConstructFrameResidue(const ost::mol::ResidueHandle& res,
                                         uint residue_index);
 
@@ -283,44 +40,25 @@ public:
           ost::conop::CompoundLibPtr comp_lib);
 
   // Assign internal energies to rotamer groups
-  virtual void AssignInternalEnergies(RRMRotamerGroupPtr group);
-
-  virtual void AssignInternalEnergies(FRMRotamerGroupPtr group);
+  virtual void AssignInternalEnergies(RRMRotamerGroupPtr group,
+                                      RotamerID id,
+                                      uint residue_index,
+                                      Real phi = -1.0472, 
+                                      Real psi =  -0.7854,
+                                      bool n_ter = false,
+                                      bool c_ter = false);
+
+  virtual void AssignInternalEnergies(FRMRotamerGroupPtr group,
+                                      RotamerID id,
+                                      uint residue_index,
+                                      Real phi = -1.0472, 
+                                      Real psi =  -0.7854,
+                                      bool n_ter = false,
+                                      bool c_ter = false);
 
 private:
 
-  // Construct the rotamer groups after all backbone position information has 
-  // been set into the internal positin buffer objects
-  virtual RRMRotamerGroupPtr ConstructRRMGroup(
-          RotamerID id, uint residue_index, 
-          std::pair<RotamerLibEntry*,uint> lib_entries, 
-          Real probability_cutoff);
-
-  virtual FRMRotamerGroupPtr ConstructFRMGroup(
-          RotamerID id, uint residue_index, 
-          std::pair<RotamerLibEntry*,uint> lib_entries, 
-          Real probability_cutoff);
-
-  // assumes positions / probabilities, chi angles and chi deviations 
-  // to be set in buffer
-  RRMRotamerPtr ConstructRRM(RotamerID id, uint residue_idx);
-  FRMRotamerPtr ConstructFRM(RotamerID id, uint residue_idx);
-
-  // helpers
-  void MVBBPosBuffer(RotamerID from, RotamerID to);
-
-  void ConstructBaseParticles(const SCWRLRotamerInfo& info, RotamerID id,
-                              std::vector<Particle>& particles);
-
-  void ConstructBBFrameParticles(const SCWRLRotamerInfo& info, RotamerID id,
-                                 bool n_ter, bool c_ter,
-                                 std::vector<Particle>& particles);
-
-  Real chi_angles_[4];
-  Real chi_dev_[4];
-  Real probability_;
-  SCWRLRotamerLookup rotamer_lookup_;
-  promod3::loop::HydrogenStoragePtr hydrogen_buffer_;
+  void ParametrizeParticle(int atom_idx, bool is_hydrogen, Particle& p);
 };
 
 }} // ns
-- 
GitLab