diff --git a/doc/tests/CMakeLists.txt b/doc/tests/CMakeLists.txt
index 25154b379fda594dee9f5f97c0f99736b1300831..df61bbb87e86667c3572a225a808dcac5794e405 100644
--- a/doc/tests/CMakeLists.txt
+++ b/doc/tests/CMakeLists.txt
@@ -32,6 +32,7 @@ set (DOC_TEST_SCRIPTS
   scripts/loop_frag_db.py
   scripts/loop_fragger.py
   scripts/loop_torsion_sampler.py
+  scripts/loop_all_atom.py
 
   scripts/scoring_main.py
 
diff --git a/doc/tests/scripts/loop_all_atom.py b/doc/tests/scripts/loop_all_atom.py
new file mode 100644
index 0000000000000000000000000000000000000000..d491873f1cd5db0cdc0d855c6eacf55d43034662
--- /dev/null
+++ b/doc/tests/scripts/loop_all_atom.py
@@ -0,0 +1,26 @@
+from ost import io, geom
+from promod3 import loop
+
+# load example (has res. numbering starting at 1)
+ent = io.LoadPDB("data/1CRN.pdb")
+res_list = ent.residues
+seqres_str = ''.join([r.one_letter_code for r in res_list])
+
+# initialize an environment
+env = loop.AllAtomEnv(seqres_str)
+env.SetInitialEnvironment(ent)
+
+# get all atom position for part of it
+all_atoms = loop.AllAtomPositions(res_list[35:44])
+# change pos. at res. index 1 (= res. number 37)
+idx_ca_res_37 = all_atoms.GetIndex(1, "CA")
+new_pos = all_atoms.GetPos(idx_ca_res_37) + geom.Vec3(0.2, 0.2, 0.2)
+all_atoms.SetPos(idx_ca_res_37, new_pos)
+# insert into ent and store updated entity
+all_atoms.InsertInto(1, ent.chains[0], 37)
+io.SavePDB(ent, "all_atom_pos.pdb")
+
+# update environment with new positions
+env.SetEnvironment(all_atoms, 36)
+# store all positions of environment
+io.SavePDB(env.GetAllAtomPositions().ToEntity(), "all_atom_env.pdb")
diff --git a/doc/tests/test_doctests.py b/doc/tests/test_doctests.py
index 31a1b93f8d59a531559ee2b6d1ecfb20ab4f7a79..201aee01b7ed2b33c9c0827805bfae70bfaed01e 100644
--- a/doc/tests/test_doctests.py
+++ b/doc/tests/test_doctests.py
@@ -271,6 +271,16 @@ class DocTests(unittest.TestCase):
         # clean up
         os.remove('torsion_plot.png')
 
+    def testAllAtom(self):
+        # run it
+        self.checkPMRun('loop_all_atom.py', [], 0)
+        # check that result exists and is readable
+        io.LoadPDB('all_atom_pos.pdb')
+        io.LoadPDB('all_atom_env.pdb')
+        # clean up
+        os.remove('all_atom_pos.pdb')
+        os.remove('all_atom_env.pdb')
+        
     ################################################################
 
     def testScoringMain(self):
diff --git a/loop/doc/CMakeLists.txt b/loop/doc/CMakeLists.txt
index 47136ac14ad223f27623bdf64a885967df745dd0..a6f2ae30e67f8ae7dfbfbc86b4f9aecbe844c1ad 100644
--- a/loop/doc/CMakeLists.txt
+++ b/loop/doc/CMakeLists.txt
@@ -1,8 +1,9 @@
 set(LOOP_RST
   index.rst
-  torsion_sampler.rst
   backbone.rst
+  torsion_sampler.rst
   structure_db.rst
+  all_atom.rst
   load_loop_objects.rst
 )
 
diff --git a/loop/doc/all_atom.rst b/loop/doc/all_atom.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3d8a99fee1c2a96ae6321d738de367ae2dbe35b8
--- /dev/null
+++ b/loop/doc/all_atom.rst
@@ -0,0 +1,356 @@
+Handling All Atom Positions
+================================================================================
+
+.. currentmodule:: promod3.loop
+
+To represent and handle all atom loops, we a container
+(:class:`AllAtomPositions`) to represent arbitrary amino acid sequences with the
+positions of all their heavy atom and an environment (:class:`AllAtomEnv`) to
+handle changes during loop modelling.
+
+The example below showcases some operations on the two classes:
+
+.. literalinclude:: ../../../tests/doc/scripts/loop_all_atom.py
+
+
+The AllAtomEnv class
+--------------------------------------------------------------------------------
+
+.. class:: AllAtomEnv(seqres)
+
+  The all atom environment contains and handles positions of all atoms during
+  loop modelling. It is linked to a (list of) seqres (one per chain) at
+  construction. The idea is to initialize it at the beginning of the modelling
+  process with all known positions and then update the environment whenever a
+  new loop is being added.
+
+  :param seqres: Internal SEQRES to be set (single chain or list with one per
+                 chain). Whenever setting structural data, consistency with this SEQRES is enforced.
+  :type seqres:  :class:`str` / :class:`ost.seq.SequenceHandle` / 
+                 :class:`list` of :class:`str` / :class:`ost.seq.SequenceList`
+
+  Indexing to access parts of the environment:
+
+  * *chain_idx*: Index of chain as it occurs in *seqres* (0 for single sequence)
+  * *start_resnum*: Residue number defining the position in the SEQRES of chain
+    with index *chain_idx*. **The numbering starts for every chain with the
+    value 1**.
+
+  .. method:: SetInitialEnvironment(env_structure)
+
+    Sets full environment. Existing data is cleared first.
+
+    :param env_structure:  Structral data to be set as environment. The chains
+                           in *env_structure* are expected to be in the same
+                           order as the SEQRES items provided in constructor.
+    :type env_structure:   :class:`ost.mol.EntityHandle`
+
+    :raises:  :exc:`~exceptions.RuntimeError` if *env* is inconsistent with
+              SEQRES set in constructor. This can be because of corrupt residue
+              numbers or sequence mismatches.
+
+  .. method:: SetEnvironment(new_pos, start_resnum, chain_idx=0)
+
+    Add/update atom positions in environment. In the end, all residues covered
+    in *new_pos* will be set as in *new_pos*. This means, that positions in the
+    env. may be reset, newly set or cleared.
+
+    :param new_pos: Structural data to be set as environment.
+    :type new_pos:  :class:`AllAtomPositions`
+    :param start_resnum: Res. number defining the start position in the SEQRES.
+    :type start_resnum:  :class:`int` / :class:`ost.mol.ResNum`
+    :param chain_idx: Index of chain the structural data belongs to.
+    :type chain_idx:  :class:`int`
+
+    :raises:  :exc:`~exceptions.RuntimeError` if sequence of *new_pos* is
+              inconsistent with previously SEQRES set in constructor or when
+              either *start_resnum* or *chain_idx* point to invalid positions in
+              the SEQRES.
+
+  .. method:: ClearEnvironment(start_resnum, num_residues, chain_idx=0)
+
+    Clears a stretch of length *num_residues* in the environment in chain 
+    with idx *chain_idx* starting from residue number *start_resnum*
+
+    :param start_resnum: Start of stretch to clear
+    :type start_resnum:  :class:`int`
+    :param num_residues: Length of stretch to clear
+    :type num_residues:  :class:`int`
+    :param chain_idx: Chain the stretch belongs to
+    :type chain_idx:  :class:`int`
+
+    :raises:  :exc:`~exceptions.RuntimeError` when either *start_resnum* or 
+              *chain_idx* point to invalid positions in the SEQRES.
+
+  .. method:: GetSeqres()
+
+    :return: SEQRES that was set in constructor (one sequence per chain).
+    :rtype:  :class:`ost.seq.SequenceList`
+
+  .. method:: GetAllAtomPositions()
+
+    :return: Reference (use with caution!) to the internal storage of all atom
+             positions for the environment. All residues of all chains are
+             stored continuously in there.
+    :rtype:  :class:`AllAtomPositions`
+
+
+The AllAtomPositions class
+--------------------------------------------------------------------------------
+
+.. class:: AllAtomPositions
+
+  Container for the positions of all heavy atoms of an arbitrary amino acid sequence. This is tailored for fast operations within |C++| codes. The Python export described here, is mainly meant for debugging or to initialize the object and feed it to other classes using it.
+
+  Indexing of positions and residues:
+
+  - residue indexing is in the range [0, :meth:`GetNumResidues`-1] and is in the
+    order of the sequence used to initialize the object
+  - indexing of single atoms is in the range [0, :meth:`GetNumAtoms`-1]. For
+    each residue you can find the bounds with :meth:`GetFirstIndex` and
+    :meth:`GetLastIndex` or find a single atom with :meth:`GetIndex`
+
+  Each atom position is initially unset (unless a list of residues is passed
+  when constructing it) and can only be set with calls to :meth:`SetPos` or
+  :meth:`SetResidue`.
+
+  .. method:: AllAtomPositions()
+
+    Creates empty object. Use :meth:`Initialize` to set a sequence..
+
+  .. method:: AllAtomPositions(sequence)
+
+    Creates a container for the given *sequence* with all positions unset.
+
+    :param sequence: Sequence of amino acid one letter codes.
+    :type sequence:  :class:`str`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *sequence* contains a one letter
+             code which is not one of the 20 default amino acids.
+
+  .. method:: AllAtomPositions(residues)
+
+    Creates a container for the given *residues*. Both sequence and positions
+    are extracted from the given residues.
+
+    :param residues: List of residues
+    :type residues:  :class:`ost.mol.ResidueHandleList`
+
+    :raises: :exc:`~exceptions.RuntimeError` if any residue has a one letter
+             code which is not one of the 20 default amino acids.
+
+  .. method:: AllAtomPositions(sequence, residues)
+
+    Creates a container for the given *sequence* and extracts positions from
+    *residues*. The residues may be different amino acids than the given
+    *sequence* (see :meth:`SetResidue`).
+
+    :param sequence: Sequence of amino acid one letter codes.
+    :type sequence:  :class:`str`
+    :param residues: List of residues from which positions are extracted.
+    :type residues:  :class:`ost.mol.ResidueHandleList`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *sequence* contains a one letter
+             code which is not one of the 20 default amino acids or if
+             *sequence* and *residues* are inconsistent in size.
+
+  .. method:: Initialize(sequence)
+
+    Initializes the container for the given *sequence* with all positions unset.
+    Existing data is overwritten.
+
+    :param sequence: Sequence of amino acid one letter codes.
+    :type sequence:  :class:`str`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *sequence* contains a one letter
+             code which is not one of the 20 default amino acids.
+
+  .. method:: SetResidue(res_index, res)
+
+    Set positions for residue at index *res_index* given the atoms in *res*.
+    For each expected heavy atom, we search for an atom of that name in *res*
+    and if found set the corresponding position, otherwise we unset it.
+
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+    :param res: Residue providing atoms
+    :type res:  :class:`ost.mol.ResidueHandle`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: SetResidue(res_index, other, other_res_index)
+
+    Set positions for residue at index *res_index* given the positions of
+    residue at index *other_res_index* in *other* position container. Each
+    position is set or cleared according to the data in *other*.
+
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+    :param other: Position container from which we take data
+    :type other:  :class:`AllAtomPositions`
+    :param other_res_index: Residue index in *other*
+    :type other_res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* or *other_res_index*
+             out of bounds or if residues in the two containers are inconsistent
+             (different amino acids).
+
+  .. method:: SetPos(index, pos)
+
+    :param index: Set position at that index.
+    :type index:  :class:`int`
+    :param pos: Set position to *pos*.
+    :type pos:  :class:`ost.geom.Vec3`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *index* out of bounds.
+
+  .. method:: ClearPos(index)
+
+    :param index: Unset position at that index.
+    :type index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *index* out of bounds.
+
+  .. method:: ClearResidue(res_index)
+
+    :param res_index: Unset all positions for residue at that index.
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: GetPos(index)
+
+    :return: Position at given index.
+    :rtype:  :class:`ost.geom.Vec3`
+    :param index: Atom position index.
+    :type index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *index* out of bounds.
+
+  .. method:: IsSet(index)
+
+    :return: True, if the position at that index is currently set.
+    :rtype:  :class:`bool`
+    :param index: Atom position index.
+    :type index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *index* out of bounds.
+
+  .. method:: GetIndex(res_index, atom_name)
+
+    :return: Atom position index for atom named *atom_name* (standard PDB
+             naming) for residue at index *res_index*.
+    :rtype:  :class:`int`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+    :param atom_name: Atom name
+    :type atom_name:  :class:`str`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds or
+             if *atom_name* is not one of that residue's heavy atoms.
+
+  .. method:: GetFirstIndex(res_index)
+
+    :return: First atom position index for residue at index *res_index*.
+    :rtype:  :class:`int`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: GetLastIndex(res_index)
+
+    :return: Last atom position index for residue at index *res_index*.
+    :rtype:  :class:`int`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: GetAA(res_index)
+
+    :return: Amino acid type of residue at index *res_index*.
+    :rtype:  :class:`ost.conop.AminoAcid`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: IsAnySet(res_index)
+
+    :return: True, if any atom position of residue at index *res_index* is set.
+    :rtype:  :class:`bool`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: IsAllSet(res_index)
+
+    :return: True, if all atom positions of residue at index *res_index* are set.
+    :rtype:  :class:`bool`
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds.
+
+  .. method:: GetNumAtoms()
+
+    :return: Number of atom positions stored in this container.
+    :rtype:  :class:`int`
+
+  .. method:: GetNumResidues()
+
+    :return: Number of residues stored in this container.
+    :rtype:  :class:`int`
+
+  .. method:: GetSequence()
+
+    :return: Sequence of one letter codes of all residues stored here.
+    :rtype:  :class:`str`
+
+  .. method:: Extract(from, to)
+
+    :return: Container with residues with indices in range [*from*, *to*-1].
+    :rtype:  :class:`AllAtomPositions`
+    :param from: First residue index
+    :type from:  :class:`int`
+    :param to: One after last residue index
+    :type to:  :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *from* >= *to* or if any residue
+             index is out of bounds.
+
+  .. method:: Extract(res_indices)
+
+    :return: Container with residues with indices in *res_indices*.
+    :rtype:  :class:`AllAtomPositions`
+    :param res_indices: List of residue index
+    :type res_indices:  :class:`list` of :class:`int`
+
+    :raises: :exc:`~exceptions.RuntimeError` if any residue index is out of
+             bounds.
+
+  .. method:: ToEntity()
+
+    :return: All residues packed in a single chain as an OST entity.
+             Connectivity resolved with :class:`ost.conop.HeuristicProcessor`.
+    :rtype:  :class:`ost.mol.EntityHandle`
+
+  .. method:: InsertInto(res_index, chain, res_num)
+
+    Insert a single residue (taken from given index) into the *chain* (with
+    given res. number). Existing data is replaced and atoms are (re)connected
+    according to the default connectivity of that amino acid. Peptide links to
+    neighboring residues are set according to residue numbering. To make this
+    function efficient, we require the backbone atoms (N, C, CA) to be set.
+
+    :param res_index: Residue index
+    :type res_index:  :class:`int`
+    :param chain: Chain into which we insert
+    :type chain:  :class:`ost.mol.ChainHandle`
+    :param start_resnum: Residue number for the inserted residue
+    :type start_resnum:  :class:`int` / :class:`ost.mol.ResNum`
+
+    :raises: :exc:`~exceptions.RuntimeError` if *res_index* out of bounds, if
+             *chain* is invalid or if not all backbone atoms (N, C, CA) set.
diff --git a/loop/doc/index.rst b/loop/doc/index.rst
index 0039b60caca7f3f93abdf8d553e989b71b53b120..7120d93106bb3e44a81f71bce43c8ccce46ee99a 100644
--- a/loop/doc/index.rst
+++ b/loop/doc/index.rst
@@ -20,4 +20,5 @@ Contents:
    backbone
    torsion_sampler
    structure_db
+   all_atom
    load_loop_objects
diff --git a/loop/pymod/export_all_atom_env.cc b/loop/pymod/export_all_atom_env.cc
index 0f502f0e2146b4c01c9ac2d3a216d5efb4c8d7b5..63e0353a00f3e28779dcd31af84e8e1f27c01d4d 100644
--- a/loop/pymod/export_all_atom_env.cc
+++ b/loop/pymod/export_all_atom_env.cc
@@ -75,8 +75,9 @@ void export_AllAtomEnv() {
          (arg("new_pos"), arg("start_resnum"), arg("chain_idx") = 0))
     .def("SetEnvironment", WrapSetEnvironmentResNum,
          (arg("new_pos"), arg("start_resnum"), arg("chain_idx") = 0))
-    .def("SetEnvironment", WrapSetEnvironmentResIndices,
-         (arg("new_pos"), arg("res_indices")))
+    // variant with indices only to be exported if Pythonic way to get indices
+    // .def("SetEnvironment", WrapSetEnvironmentResIndices,
+    //      (arg("new_pos"), arg("res_indices")))
     .def("ClearEnvironment", &AllAtomEnv::ClearEnvironment,
          (arg("start_resnum"), arg("num_residues"), arg("chain_idx") = 0))
     .def("GetSeqres", &AllAtomEnv::GetSeqres)
diff --git a/loop/pymod/export_all_atom_positions.cc b/loop/pymod/export_all_atom_positions.cc
index 2caefb7b6aba14b91496652c6bfcde67ab1fe5b9..334d2e77bcfb994b81bd55f3750c319bd7d3ee63 100644
--- a/loop/pymod/export_all_atom_positions.cc
+++ b/loop/pymod/export_all_atom_positions.cc
@@ -79,8 +79,8 @@ void export_AllAtomPositions() {
     .def("GetPos", WrapGetPos, (arg("index")),
          return_value_policy<copy_const_reference>())
     .def("IsSet", WrapIsSet, (arg("index")))
-    .def("GetIndex", WrapGetIndex, (arg("index"), arg("atom_name")))
-
+    
+    .def("GetIndex", WrapGetIndex, (arg("res_index"), arg("atom_name")))
     .def("GetFirstIndex", &AllAtomPositions::GetFirstIndex, (arg("res_index")))
     .def("GetLastIndex", &AllAtomPositions::GetLastIndex, (arg("res_index")))
     .def("GetAA", &AllAtomPositions::GetAA, (arg("res_index")))
diff --git a/scoring/doc/backbone_score_env.rst b/scoring/doc/backbone_score_env.rst
index cab4cc3488669549dd569408c96c6373e56182a2..20657cb38acba081c4b2f507ca3debe7b714cbdc 100644
--- a/scoring/doc/backbone_score_env.rst
+++ b/scoring/doc/backbone_score_env.rst
@@ -52,7 +52,7 @@ BackboneScoreEnv class
     :param bb_list: Structural data to be set as environment.
     :type bb_list:  :class:`~promod3.loop.BackboneList`
     :param start_resnum: Res. number defining the position in the SEQRES.
-    :type start_resnum:  :class:`int`
+    :type start_resnum:  :class:`int` / :class:`ost.mol.ResNum`
     :param chain_idx: Index of chain the structural data belongs to.
     :type chain_idx:  :class:`int`