diff --git a/modules/mol/alg/doc/molalg.rst b/modules/mol/alg/doc/molalg.rst
index e64bdcfd798f882b6e70ae12432d37f1ed0b9699..9d128af1e1823abfb7da4e2f384b60543a31102c 100644
--- a/modules/mol/alg/doc/molalg.rst
+++ b/modules/mol/alg/doc/molalg.rst
@@ -46,6 +46,8 @@
 
 .. autofunction:: MatchResidueByNum
 
+.. autofunction:: MatchResidueByIdx
+
 .. autofunction:: Superpose
 
 
diff --git a/modules/mol/alg/pymod/superpose.py b/modules/mol/alg/pymod/superpose.py
index 44c337d8788d91e9daf33c32b6b14dd976addfe3..5e842b8f1150618371049645adbcf152ec52de5b 100644
--- a/modules/mol/alg/pymod/superpose.py
+++ b/modules/mol/alg/pymod/superpose.py
@@ -27,6 +27,7 @@ def ParseAtomNames(atoms):
   :param atoms: Identifier or list of atoms
   :type atoms: :class:`str`, :class:`list`, :class:`set`
   """
+  ## get a set of atoms or None
   if atoms==None:
     return None
   if isinstance(atoms, str):
@@ -62,6 +63,16 @@ def _fetch_atoms(r_a, r_b, result_a, result_b, atmset):
   return result_a, result_b
 
 
+def _no_of_chains(ent_a, ent_b):
+  """
+  for internal use, only
+  """
+  ## get lower no. of chains
+  if ent_a.chain_count < ent_b.chain_count:
+    return ent_a.chain_count
+  return ent_b.chain_count
+
+
 def MatchResidueByNum(ent_a, ent_b, atoms='all'):
   """
   Returns a tuple of views containing exactly the same number of atoms.
@@ -82,20 +93,15 @@ def MatchResidueByNum(ent_a, ent_b, atoms='all'):
   ## init. final views
   result_a=_EmptyView(ent_a)
   result_b=_EmptyView(ent_b)
-  ## get lower no. of chains
-  if ent_a.chain_count < ent_b.chain_count:
-    n_chains=ent_a.chain_count
-  else:
-    n_chains=ent_b.chain_count
-  ## get a set of atoms or None
+  n_chains=_no_of_chains(ent_a, ent_b)
   atmset=ParseAtomNames(atoms)
   ## iterate chains
   for i in range(0, n_chains):
     chain_a=ent_a.chains[i]
     chain_b=ent_b.chains[i]
-    ## residues of chains need to be consecutively numbered (sorted)
+    residues_a=iter(chain_a.residues)
+    ## decide on order of residues
     if chain_a.InSequence() and chain_b.InSequence():
-      residues_a=iter(chain_a.residues)
       residues_b=iter(chain_b.residues)
       ## check residues & copy to views
       try:
@@ -112,7 +118,6 @@ def MatchResidueByNum(ent_a, ent_b, atoms='all'):
         pass
     else:
       ## iterate one list of residues, search in other list
-      residues_a=iter(chain_a.residues)
       try:
         while True:
           r_a=residues_a.next()
@@ -126,6 +131,46 @@ def MatchResidueByNum(ent_a, ent_b, atoms='all'):
   return result_a, result_b
 
 
+def MatchResidueByIdx(ent_a, ent_b, atoms='all'):
+  """
+  Returns a tuple of views containing exactly the same number of atoms.
+  Residues are matched by position in the chains of an entity. A subset of
+  atoms to be included in the views can be specified in the **atoms** argument.
+  Regardless of what the list of **atoms** says, only those present in two
+  matched residues will be included in the views. Chains are processed in order
+  of appearance. If **ent_a** and **ent_b** contain a different number of
+  chains, processing stops with the lower count. The number of residues per
+  chain is supposed to be the same.
+
+  :param ent_a: The first entity
+  :type ent_a: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
+  :param ent_b: The second entity
+  :type ent_b: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
+  :param atoms: The subset of atoms to be included in the two views.
+  :type atoms: :class:`str`, :class:`list`, :class:`set`
+  """
+  not_supported="MatchResidueByIdx has no support for chains of different "\
+               +"lengths"
+  ## init. final views
+  result_a=_EmptyView(ent_a)
+  result_b=_EmptyView(ent_b)
+  n_chains=_no_of_chains(ent_a, ent_b)
+  atmset=ParseAtomNames(atoms)
+  ## iterate chains
+  for i in range(0, n_chains):
+    chain_a=ent_a.chains[i]
+    chain_b=ent_b.chains[i]
+    ## check equal no. of residues
+    if chain_a.residue_count!=chain_b.residue_count:
+      raise RuntimeError(not_supported)
+    ## iterate residues & copy to views
+    for r_a,r_b in zip(chain_a.residues, chain_b.residues):
+      result_a,result_b=_fetch_atoms(r_a, r_b, result_a, result_b, atmset)
+  result_a.AddAllInclusiveBonds()
+  result_b.AddAllInclusiveBonds()
+  return result_a, result_b
+
+
 def Superpose(ent_a, ent_b, match='number', atoms='all'):
   """
   Superposes the first entity onto the second. To do so, two views are created,
@@ -137,6 +182,9 @@ def Superpose(ent_a, ent_b, match='number', atoms='all'):
   * ``number`` - select residues by residue number, includes **atoms**, calls
     :func:`~ost.mol.alg.MatchResidueByNum`
 
+  * ``index`` - select residues by index in chain, includes **atoms**, calls
+    :func:`~ost.mol.alg.MatchResidueByIdx`
+
   :param ent_a: The first entity
   :type ent_a: :class:`~ost.mol.EntityView` or :class:`~ost.mol.EntityHandle`
   :param ent_b: The second entity
@@ -150,6 +198,8 @@ def Superpose(ent_a, ent_b, match='number', atoms='all'):
   ## create views to superpose
   if match.upper()=='NUMBER':
     view_a, view_b=MatchResidueByNum(ent_a, ent_b, atoms)
+  elif match.upper()=='INDEX':
+    view_a, view_b=MatchResidueByIdx(ent_a, ent_b, atoms)
   else:
     raise ValueError(not_supported)
   ## action
diff --git a/modules/mol/alg/tests/test_convenient_superpose.py b/modules/mol/alg/tests/test_convenient_superpose.py
index 0b8e5bc4f0613f03f3af27fb92866c35c22a7e90..e247b68b2de26b8b5ee0cbf3b66b4a5c3219e8cf 100644
--- a/modules/mol/alg/tests/test_convenient_superpose.py
+++ b/modules/mol/alg/tests/test_convenient_superpose.py
@@ -7,11 +7,6 @@ class TestConvenientSuperpose(unittest.TestCase):
   def setUp(self):
     pass
   
-  def runAtomOrdering(self, view1, view2):
-    # call atom ordering function here
-    view1, view2 = ost.mol.alg.MatchResidueByNum(view1, view2)
-    return view1, view2
-  
   def assertEqualAtomOrder(self, view1, view2):
     self.assertEquals(len(view1.atoms),len(view2.atoms))
     for a1, a2 in zip(view1.atoms, view2.atoms):
@@ -30,45 +25,74 @@ class TestConvenientSuperpose(unittest.TestCase):
   def testCorrectlyOrdered(self):
     ent1_ent = io.LoadEntity(os.path.join("testfiles","1aho.pdb"))
     ent1_view = ent1_ent.Select("")
-    view1, view2 = self.runAtomOrdering(ent1_ent, ent1_ent)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent1_ent, ent1_ent)
+    self.assertEqualAtomOrder(view1, view2)    
+    view1, view2 = mol.alg.MatchResidueByNum(ent1_view, ent1_ent)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent1_ent, ent1_view)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent1_view, ent1_view)
+    self.assertEqualAtomOrder(view1, view2)
+    ## test MatchResidueByIdx
+    view1, view2 = mol.alg.MatchResidueByIdx(ent1_ent, ent1_ent)
     self.assertEqualAtomOrder(view1, view2)    
-    view1, view2 = self.runAtomOrdering(ent1_view, ent1_ent)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent1_view, ent1_ent)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent1_ent, ent1_view)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent1_ent, ent1_view)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent1_view, ent1_view)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent1_view, ent1_view)
     self.assertEqualAtomOrder(view1, view2)
     
   def testMissingFirstAtom(self):
     ent_view = io.LoadEntity(os.path.join("testfiles","1aho.pdb")).Select("")
     ent_view_missing = ent_view.Select("not (cname=A and rnum=1 and aname=N)")
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_missing)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_missing, ent_view)
+    ## test MatchResidueByIdx
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
     
   def testMissingManyAtoms(self):
     ent_view = io.LoadEntity(os.path.join("testfiles","1aho.pdb")).Select("")
     ent_view_missing = ent_view.Select("not (cname=A and rnum=3,19,32 and aname=CB,CA,CD)")
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_missing)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_missing, ent_view)
+    ## test MatchResidueByIdx
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
     
   def testMissingFirstResidue(self):
     ent_view = io.LoadEntity(os.path.join("testfiles","1aho.pdb")).Select("")
     ent_view_missing = ent_view.Select("not (cname=A and rnum=1)")
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_missing)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_missing)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_missing, ent_view)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
-  
+
   def testMissingHydrogens(self):
     ent_view = io.LoadEntity(os.path.join("testfiles","1aho.pdb")).Select("")
     ent_view_missing = ent_view.Select("ele!=H")
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_missing)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_missing, ent_view)
+    ## test MatchResidueByIdx
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view, ent_view_missing)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view_missing, ent_view)
     self.assertEqualAtomOrder(view1, view2)
   
   def testWrongAtomOrder(self):
@@ -82,9 +106,15 @@ class TestConvenientSuperpose(unittest.TestCase):
         random.shuffle(atoms)
         for a in atoms:
           ent_view_wrong.AddAtom(a)
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_wrong)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_wrong)
+    self.assertEqualAtomOrder(view1, view2)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_wrong, ent_view)
+    self.assertEqualAtomOrder(view1, view2)
+    ## test MatchResidueByIdx
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view, ent_view_wrong)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_wrong, ent_view)
+    view1, view2 = mol.alg.MatchResidueByIdx(ent_view_wrong, ent_view)
     self.assertEqualAtomOrder(view1, view2)
   
   def testWrongResidueOrder(self): 
@@ -98,9 +128,10 @@ class TestConvenientSuperpose(unittest.TestCase):
         ent_view_wrong.AddResidue(r)
         for a in r.atoms:
           av=ent_view_wrong.AddAtom(a)
-    view1, view2 = self.runAtomOrdering(ent_view, ent_view_wrong)
+    ## test MatchResidueByNum
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view, ent_view_wrong)
     self.assertEqualAtomOrder(view1, view2)
-    view1, view2 = self.runAtomOrdering(ent_view_wrong, ent_view)
+    view1, view2 = mol.alg.MatchResidueByNum(ent_view_wrong, ent_view)
     self.assertEqualAtomOrder(view1, view2)
     
 if __name__ == "__main__":