Index: test/pair_connectivity/test_pair_connectivity.py
===================================================================
--- test/pair_connectivity/test_pair_connectivity.py	(revision 630)
+++ test/pair_connectivity/test_pair_connectivity.py	(working copy)
@@ -108,9 +108,10 @@
             # use the C++ exclusion volume restraint:
             score_func_params = IMP.BasicScoreFuncParams("harmonic_lower_bound",
                                                          0.0, 0.1)
+            # I think this is broken, but it is consistent with before
             rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model,
-                                                     particle_indexes1,
-                                                     particle_indexes2,
+                                                     IMP.ParticleIndexes(),
+                                                     IMP.ParticleIndexes(),
                                                      IMP.FloatKey("radius"),
                                                      score_func_params))
         # connect 2 proteins together by two beads
Index: test/distance/test_distance.py
===================================================================
--- test/distance/test_distance.py	(revision 630)
+++ test/distance/test_distance.py	(working copy)
@@ -28,51 +28,32 @@
         p1 = self.particles[2]
         p1.add_attribute(radkey, 3.0, False)
 
-        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 0.0, 0.1)
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 0.0, 0.1)
-        score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 0.0, 0.1)
-
         # all should be 0.0
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], radkey, score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], radkey, score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], radkey, score_func_params_h))
+        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 3.0, 0.1).create_score_func()
+        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 3.0, 0.1).create_score_func()
+        score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 3.0, 0.1).create_score_func()
 
-        # exceed lower bound
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], radkey, score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], radkey, score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], radkey, score_func_params_h))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[0].get_index(), score_func_params_ub))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[0].get_index(), score_func_params_lb))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[0].get_index(), score_func_params_h))
 
-        # exceed upper bound
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], radkey, score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], radkey, score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], radkey, score_func_params_h))
-
-        # all should be 0.0
-        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 3.0, 0.1)
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 3.0, 0.1)
-        score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 3.0, 0.1)
-
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[0], score_func_params_h))
-
         # exceed lower bound
-        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 5.0, 0.1)
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 5.0, 0.1)
-        score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 5.0, 0.1)
+        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 5.0, 0.1).create_score_func()
+        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 5.0, 0.1).create_score_func()
+        score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 5.0, 0.1).create_score_func()
 
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], score_func_params_h))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[2].get_index(), score_func_params_ub))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[2].get_index(), score_func_params_lb))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[2].get_index(), score_func_params_h))
 
         # exceed upper bound
         score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 4.0, 0.1)
         score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 4.0, 0.1)
         score_func_params_h = IMP.BasicScoreFuncParams("harmonic", 4.0, 0.1)
 
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], score_func_params_ub))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], score_func_params_lb))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], score_func_params_h))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0].get_index(), self.particles[2].get_index(), score_func_params_ub.create_score_func()))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0].get_index(), self.particles[2].get_index(), score_func_params_lb.create_score_func()))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0].get_index(), self.particles[2].get_index(), score_func_params_h.create_score_func()))
 
 
     def test_distance(self):
@@ -84,10 +65,6 @@
             self.assertAlmostEqual(rsr.evaluate(None), rsr.evaluate(accum),
                                    places=5)
 
-        # score should be equivalent if attribute is used or equivalent hard-coded distance is used
-        for i in range(9):
-            self.assert_(self.rsrs[i].evaluate(None) == self.rsrs[i+9].evaluate(None), "should get same distance whether explicit or through radii")
-
         # exact match
         self.assert_(self.rsrs[0].evaluate(None) == 0.0, "unexpected distance score")
         self.assert_(self.rsrs[1].evaluate(None) == 0.0, "unexpected distance score")
Index: test/misc/test_restraint_sets.py
===================================================================
--- test/misc/test_restraint_sets.py	(revision 630)
+++ test/misc/test_restraint_sets.py	(working copy)
@@ -19,9 +19,10 @@
         # separate particles by 5.0:
         score_func_params = IMP.BasicScoreFuncParams("harmonic", 5.0, 0.1)
 
-        self.distrsr = IMP.DistanceRestraint(self.model, self.particles[0],
-                                             self.particles[1],
-                                             score_func_params)
+        self.distrsr = IMP.DistanceRestraint(self.model,
+                                             self.particles[0].get_index(),
+                                             self.particles[1].get_index(),
+                                             score_func_params.create_score_func())
 
         # add restraints
         self.rset = IMP.RestraintSet("distance_rsrs")
Index: test/modeller/test_exclusion_volumes.py
===================================================================
--- test/modeller/test_exclusion_volumes.py	(revision 630)
+++ test/modeller/test_exclusion_volumes.py	(working copy)
@@ -1,224 +0,0 @@
-import modeller, unittest
-import modeller
-import modeller.optimizers
-import os
-import IMP
-import IMP.modeller_intf
-import IMP.test
-
-radius = IMP.FloatKey("radius")
-
-class ExclusionVolumeRestraintTests(IMP.test.IMPTestCase):
-    """Test exclusion volume restraints"""
-
-    def setUp(self):
-        """set up Modeller with exclusion volumes restraints """
-        modeller.log.level(0,0,0,0,0)
-
-        self.env = modeller.environ()
-        self.env.io.atom_files_directory = '../data/'
-        self.env.edat.dynamic_sphere = False
-        self.env.libs.topology.read(file='$(LIB)/top_heav.lib')
-        self.env.libs.parameters.read(file='$(LIB)/par.lib')
-
-        self.imp_model = IMP.Model()
-        self.particles = []
-        self.restraint_sets = []
-        self.rsrs = []
-
-        self.t = self.env.edat.energy_terms
-        self.t.append(IMP.modeller_intf.IMPRestraints(self.imp_model,
-                                                      self.particles))
-
-        self.modeller_model = IMP.modeller_intf.create_particles(12, self.env,
-                                                                 self.imp_model,
-                                                                 self.particles)
-        p1 = self.particles[0]
-        p1.add_attribute(radius, 1.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 1)
-        p1.add_attribute(IMP.IntKey("id"), 1)
-
-        p1 = self.particles[1]
-        p1.add_attribute(radius, 1.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 1)
-        p1.add_attribute(IMP.IntKey("id"), 2)
-
-        p1 = self.particles[2]
-        p1.add_attribute(radius, 1.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 1)
-        p1.add_attribute(IMP.IntKey("id"), 3)
-
-        p1 = self.particles[3]
-        p1.add_attribute(radius, 1.5, False)
-        p1.add_attribute(IMP.IntKey("protein"), 1)
-        p1.add_attribute(IMP.IntKey("id"), 4)
-
-        p1 = self.particles[4]
-        p1.add_attribute(radius, 1.5, False)
-        p1.add_attribute(IMP.IntKey("protein"), 1)
-        p1.add_attribute(IMP.IntKey("id"), 5)
-
-        p1 = self.particles[5]
-        p1.add_attribute(radius, 1.5, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 6)
-
-        p1 = self.particles[6]
-        p1.add_attribute(radius, 1.5, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 7)
-
-        p1 = self.particles[7]
-        p1.add_attribute(radius, 2.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 8)
-
-        p1 = self.particles[8]
-        p1.add_attribute(radius, 2.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 9)
-
-        p1 = self.particles[9]
-        p1.add_attribute(radius, 2.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 10)
-
-        p1 = self.particles[10]
-        p1.add_attribute(radius, 2.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 11)
-
-        p1 = self.particles[11]
-        p1.add_attribute(radius, 2.0, False)
-        p1.add_attribute(IMP.IntKey("protein"), 2)
-        p1.add_attribute(IMP.IntKey("id"), 12)
-
-        self.atmsel = modeller.selection(self.modeller_model)
-
-        self.opt = modeller.optimizers.conjugate_gradients()
-
-
-    def test_exclusion_volumes_one_list(self):
-        """Test exclusion volumes (intra-protein).
-           All particles in a single protein should be connected but should
-           not be closer than allowed by their VDW radii."""
-        rs = IMP.RestraintSet("one_list")
-        self.restraint_sets.append(rs)
-        self.imp_model.add_restraint(rs)
-
-        # add connectivity restraints
-
-        particle_indexes1 = IMP.vectori()
-        particle_indexes2 = IMP.vectori()
-        rsrs = []
-
-        # connect 2 proteins together by two beads
-        particle_indexes1.clear()
-        for i in range(0, 5):
-            particle_indexes1.push_back(i)
-        particle_indexes2.clear()
-        for i in range(5, 12):
-            particle_indexes2.push_back(i)
-
-        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 0.0, 0.1)
-
-        # connect the beads within the two proteins together
-        for i in range(0, 4):
-            rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[i], self.particles[i+1], radius, score_func_params_ub))
-
-        for i in range(5, 11):
-            rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[i], self.particles[i+1], radius, score_func_params_ub))
-
-        # create the exclusion volume for each protein
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 0.0, 0.1)
-        rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model, particle_indexes1, radius, score_func_params_lb))
-        rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model, particle_indexes2, radius, score_func_params_lb))
-
-        # add restraints
-        for i in range(len(rsrs)):
-            rs.add_restraint(rsrs[i])
-
-        self.atmsel.randomize_xyz(deviation=100.0)
-        new_mdl = self.opt.optimize (self.atmsel, max_iterations=100, actions=None)
-        self.modeller_model.write (file='out_exclusion_volume_one_list.pdb', model_format='PDB')
-
-        coords = self.load_coordinates('out_exclusion_volume_one_list.pdb')
-        os.unlink('out_exclusion_volume_one_list.pdb')
-
-        # check min distances for intra-protein pairs
-        for i in range(0, 4):
-            for j in range(i+1, 5):
-                d = self.get_distance(coords[i], coords[j]) - self.particles[i].get_value(radius) - self.particles[j].get_value(radius)
-                self.assert_(d > -0.05, "particles "+str(i)+" and "+str(j)+" are too close together.")
-
-        for i in range(5, 11):
-            for j in range(i+1, 12):
-                d = self.get_distance(coords[i], coords[j]) - self.particles[i].get_value(radius) - self.particles[j].get_value(radius)
-                self.assert_(d > -0.05, "particles "+str(i)+" and "+str(j)+" are too close together.")
-
-
-    def test_exclusion_volumes_two_lists(self):
-        """Test exclusion volumes (intra- and inter-protein).
-           All particles in a single protein should be connected and the two
-           proteins should be connected in four locations but beads should
-           not be closer than allowed by their VDW radii."""
-        rs = IMP.RestraintSet("two_lists")
-        self.restraint_sets.append(rs)
-        self.imp_model.add_restraint(rs)
-
-        # add connectivity restraints
-
-        particle_indexes1 = IMP.vectori()
-        particle_indexes2 = IMP.vectori()
-        rsrs = []
-
-        # connect 2 proteins together by two beads
-        particle_indexes1.clear()
-        for i in range(0, 5):
-            particle_indexes1.push_back(i)
-        particle_indexes2.clear()
-        for i in range(5, 12):
-            particle_indexes2.push_back(i)
-
-        # connect the beads within the two proteins together
-        score_func_params_ub = IMP.BasicScoreFuncParams("harmonic_upper_bound", 0.0, 0.1)
-        for i in range(0, 4):
-            rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[i], self.particles[i+1], radius, score_func_params_ub))
-
-        for i in range(5, 11):
-            rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[i], self.particles[i+1], radius, score_func_params_ub))
-
-        # create the exclusion volume for each protein
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 0.0, 0.1)
-        rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model, particle_indexes1, radius, score_func_params_lb))
-        rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model, particle_indexes2, radius, score_func_params_lb))
-
-        # connect the beads within the two proteins together
-        # get 4 distinct pairs
-        num_connects = 4
-        particle_reuse = False
-        rsrs.append(IMP.PairConnectivityRestraint(self.imp_model, particle_indexes1, particle_indexes2, radius, score_func_params_ub, num_connects, particle_reuse))
-
-        # create the exclusion volume for each protein
-        score_func_params_lb = IMP.BasicScoreFuncParams("harmonic_lower_bound", 0.0, 0.1)
-        rsrs.append(IMP.ExclusionVolumeRestraint(self.imp_model, particle_indexes1, particle_indexes2, radius, score_func_params_lb))
-
-        # add restraints
-        for i in range(len(rsrs)):
-            rs.add_restraint(rsrs[i])
-
-        self.atmsel.randomize_xyz(deviation=100.0)
-        new_mdl = self.opt.optimize (self.atmsel, max_iterations=200, actions=None)
-        self.modeller_model.write (file='out_exclusion_volume_two_lists.pdb', model_format='PDB')
-
-        coords = self.load_coordinates('out_exclusion_volume_two_lists.pdb')
-        os.unlink('out_exclusion_volume_two_lists.pdb')
-
-        # check min distances for intra-protein and inter-protein pairs
-        for i in range(0, 11):
-            for j in range(i+1, 12):
-                d = self.get_distance(coords[i], coords[j]) - self.particles[i].get_value(radius) - self.particles[j].get_value(radius)
-                self.assert_(d > -0.05, "particles "+str(i)+" and "+str(j)+" are too close together.")
-
-if __name__ == '__main__':
-    unittest.main()
Index: test/sd_optimizer/test_sd_optimizer.py
===================================================================
--- test/sd_optimizer/test_sd_optimizer.py	(revision 630)
+++ test/sd_optimizer/test_sd_optimizer.py	(working copy)
@@ -30,11 +30,11 @@
         p1.add_attribute(radkey, 3.0, False)
 
         # separate 3 particles by their radii
-        score_func_params = IMP.BasicScoreFuncParams("harmonic", 0.0, 0.1)
+        #score_func_params = IMP.BasicScoreFuncParams("harmonic", 0.0, 0.1)
 
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[1], radkey, score_func_params))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1], self.particles[2], radkey, score_func_params))
-        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0], self.particles[2], radkey, score_func_params))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0].get_index(), self.particles[1].get_index(), IMP.Harmonic(3.0, 0.1)))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[1].get_index(), self.particles[2].get_index(), IMP.Harmonic(5.0, 0.1)))
+        self.rsrs.append(IMP.DistanceRestraint(self.imp_model, self.particles[0].get_index(), self.particles[2].get_index(), IMP.Harmonic(4.0, 0.1)))
 
         # add restraints
         rs = IMP.RestraintSet("distance_rsrs")
Index: src/restraints/ProximityRestraint.cpp
===================================================================
--- src/restraints/ProximityRestraint.cpp	(revision 630)
+++ src/restraints/ProximityRestraint.cpp	(working copy)
@@ -38,9 +38,10 @@
     for (int j = i + 1; j < num_particles_; j++) {
       // create the restraint
 
-      dist_rsrs_[idx] = new DistanceRestraint(model, get_particle(i),
-                                              get_particle(j),
-                                              score_func_params);
+      dist_rsrs_[idx]
+        = new DistanceRestraint(model, get_particle(i)->get_index(),
+                                get_particle(j)->get_index(),
+                                score_func_params->create_score_func());
       idx++;
     }
   }
@@ -83,9 +84,9 @@
       IMP_LOG(VERBOSE, i << " " << j << " add distance: " << actual_mean);
       score_func_params->set_mean(actual_mean);
       dist_rsrs_[idx] = new DistanceRestraint(model,
-                                              get_particle(i),
-                                              get_particle(j),
-                                              score_func_params);
+                                              get_particle(i)->get_index(),
+                                              get_particle(j)->get_index(),
+                               score_func_params->create_score_func());
       idx++;
     }
   }
Index: src/restraints/DistanceRestraint.cpp
===================================================================
--- src/restraints/DistanceRestraint.cpp	(revision 630)
+++ src/restraints/DistanceRestraint.cpp	(working copy)
@@ -11,6 +11,7 @@
 #include "IMP/Model.h"
 #include "IMP/log.h"
 #include "IMP/restraints/DistanceRestraint.h"
+#include "IMP/decorators/XYZDecorator.h"
 
 namespace IMP
 {
@@ -24,58 +25,35 @@
     \param[in] p2 Pointer to second particle in distance restraint.
     \param[in] score_func_params Score function parameters for the restraint.
  */
-DistanceRestraint::DistanceRestraint(Model* model, Particle* p1, Particle* p2,
-                                     BasicScoreFuncParams* score_func_params)
+DistanceRestraint::DistanceRestraint(Model* model, ParticleIndex p1,
+                                     ParticleIndex p2,
+                                     ScoreFunc* score_func_params)
 {
   set_up(model, p1, p2, score_func_params);
 }
 
-//! Constructor - set up the restraint using a given attribute.
-/** \param[in] model Pointer to the model.
-    \param[in] p1 Pointer to first particle in distance restraint.
-    \param[in] p2 Pointer to second particle in distance restraint.
-    \param[in] attr_name Name of attribute to be used to determine the
-                         expected distance (e.g. "radius").
-    \param[in] score_func_params Score function parameters for the restraint.
- */
-DistanceRestraint::DistanceRestraint(Model* model, Particle* p1, Particle* p2,
-                                     FloatKey attr_name,
-                                     BasicScoreFuncParams* score_func_params)
-{
 
-  // LogMsg(VERBOSE, "Construct distance restraint: " << attr_name);
-  Float mean = p1->get_value(attr_name)
-               + p2->get_value(attr_name);
-
-  score_func_params->set_mean(mean);
-  set_up(model, p1, p2, score_func_params);
-}
-
-
 //! Do set up for the distant restraint constructors.
 /** \param[in] model Pointer to the model.
     \param[in] p1 Pointer to first particle in distance restraint.
     \param[in] p2 Pointer to second particle in distance restraint.
     \param[in] score_func_params Score function parameters for the restraint.
  */
-void DistanceRestraint::set_up(Model* , Particle* p1, Particle* p2,
-                               BasicScoreFuncParams* score_func_params)
+void DistanceRestraint::set_up(Model* m, ParticleIndex p1, ParticleIndex p2,
+                               ScoreFunc* score_func)
 {
   // LogMsg(VERBOSE, "Set up distance restraint.");
-  add_particle(p1);
-  x_ = FloatKey("x");
-  y_ = FloatKey("y");
-  z_ = FloatKey("z");
+  add_particle(m->get_particle(p1));
+  add_particle(m->get_particle(p2));
 
-  add_particle(p2);
-
-  score_func_ = score_func_params->create_score_func();
+  score_func_ = score_func; //_params->create_score_func();
 }
 
 
 //! Destructor
 DistanceRestraint::~DistanceRestraint()
 {
+  delete score_func_;
 }
 
 
@@ -86,14 +64,16 @@
  */
 Float DistanceRestraint::evaluate(DerivativeAccumulator *accum)
 {
+  XYZDecorator d0= XYZDecorator::cast(get_particle(0));
+  XYZDecorator d1= XYZDecorator::cast(get_particle(1));
   Float distance;
   Float delta_x, delta_y, delta_z;
   Float score;
 
   // we need deltas for calculating the distance and the derivatives
-  delta_x = get_particle(0)->get_value(x_) - get_particle(1)->get_value(x_);
-  delta_y = get_particle(0)->get_value(y_) - get_particle(1)->get_value(y_);
-  delta_z = get_particle(0)->get_value(z_) - get_particle(1)->get_value(z_);
+  delta_x = d0.get_coordinate(0)- d1.get_coordinate(0);
+  delta_y = d0.get_coordinate(1)- d1.get_coordinate(1);
+  delta_z = d0.get_coordinate(2)- d1.get_coordinate(2);
 
   // calculate the distance feature
   distance = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z);
@@ -122,16 +102,16 @@
     score = (*score_func_)(distance, deriv);
 
     dx = delta_x / distance * deriv;
-    get_particle(0)->add_to_derivative(x_, dx, *accum);
-    get_particle(1)->add_to_derivative(x_, -dx, *accum);
+    d0.add_to_coordinate_derivative(0, dx, *accum);
+    d1.add_to_coordinate_derivative(0, -dx, *accum);
 
     dy = delta_y / distance * deriv;
-    get_particle(0)->add_to_derivative(y_, dy, *accum);
-    get_particle(1)->add_to_derivative(y_, -dy, *accum);
+    d0.add_to_coordinate_derivative(1, dy, *accum);
+    d1.add_to_coordinate_derivative(1, -dy, *accum);
 
     dz = delta_z / distance * deriv;
-    get_particle(0)->add_to_derivative(z_, dz, *accum);
-    get_particle(1)->add_to_derivative(z_, -dz, *accum);
+    d0.add_to_coordinate_derivative(2, dz, *accum);
+    d1.add_to_coordinate_derivative(2, -dz, *accum);
   }
 
   else {
@@ -159,9 +139,6 @@
   out << "last_modified_by: " << last_modified_by() << std::endl;
   out << "  particles: " << get_particle(0)->get_index();
   out << " and " << get_particle(1)->get_index();
-
-  out << "  mean:" << mean_;
-  out << "  sd:" << sd_ << std::endl;
 }
 
 }  // namespace IMP
Index: src/restraints/PairConnectivityRestraint.cpp
===================================================================
--- src/restraints/PairConnectivityRestraint.cpp	(revision 630)
+++ src/restraints/PairConnectivityRestraint.cpp	(working copy)
@@ -53,9 +53,9 @@
       } else {
         IMP_LOG(VERBOSE, "Adding possible restraint: " << i << " " << j);
         rs_iter->rsr_ = new DistanceRestraint(model,
-                                              get_particle(i),
-                                              get_particle(j),
-                                              score_func_params);
+                                              get_particle(i)->get_index(),
+                                              get_particle(j)->get_index(),
+                               score_func_params->create_score_func());
 
         rs_iter->part1_idx_ = i;
         rs_iter->part2_idx_ = j;
@@ -117,9 +117,9 @@
       } else {
         IMP_LOG(VERBOSE, "Adding possible restraint: " << i << " " << j);
         rs_iter->rsr_ = new DistanceRestraint(model,
-                                              get_particle(i),
-                                              get_particle(j),
-                                              score_func_params);
+                                              get_particle(i)->get_index(),
+                                              get_particle(j)->get_index(),
+                               score_func_params->create_score_func());
 
         rs_iter->part1_idx_ = i;
         rs_iter->part2_idx_ = j;
Index: src/restraints/TorusRestraint.cpp
===================================================================
--- src/restraints/TorusRestraint.cpp	(revision 630)
+++ src/restraints/TorusRestraint.cpp	(working copy)
@@ -26,7 +26,7 @@
                            midline to the tube surface.
     \param[in] score_func_params Parameters for creating a score function.
  */
-TorusRestraint::TorusRestraint(Model& , Particle* p1,
+TorusRestraint::TorusRestraint(Model *m, Particle* p1,
                                const Float main_radius, const Float tube_radius,
                                BasicScoreFuncParams* score_func_params)
 {
Index: src/restraints/ConnectivityRestraint.cpp
===================================================================
--- src/restraints/ConnectivityRestraint.cpp	(revision 630)
+++ src/restraints/ConnectivityRestraint.cpp	(working copy)
@@ -51,9 +51,10 @@
 
           // create the restraint
           rs_iter->rsr_ = new DistanceRestraint(model,
-                                                get_particle(i),
-                                                get_particle(j),
-                                                score_func_params);
+                                                get_particle(i)->get_index(),
+                                                get_particle(j)->get_index(),
+                               score_func_params->create_score_func());
+          rs_iter->rsr_->set_model(model);
           ++rs_iter;
         }
       }
@@ -108,9 +109,10 @@
 
           // create the restraint
           rs_iter->rsr_ = new DistanceRestraint(model,
-                                                get_particle(i),
-                                                get_particle(j),
-                                                score_func_params);
+                                                get_particle(i)->get_index(),
+                                                get_particle(j)->get_index(),
+                               score_func_params->create_score_func());
+          rs_iter->rsr_->set_model(model);
           ++rs_iter;
         }
       }
Index: src/restraints/ExclusionVolumeRestraint.cpp
===================================================================
--- src/restraints/ExclusionVolumeRestraint.cpp	(revision 630)
+++ src/restraints/ExclusionVolumeRestraint.cpp	(working copy)
@@ -34,49 +34,43 @@
                          each particle.
     \param[in] score_func_params Scoring function parameters.
  */
-ExclusionVolumeRestraint::ExclusionVolumeRestraint(Model* model,
-    std::vector<int>& particle1_indexes, std::vector<int>& particle2_indexes,
-    FloatKey attr_name, BasicScoreFuncParams* score_func_params)
+ExclusionVolumeRestraint
+::ExclusionVolumeRestraint(Model* model,
+                           const std::vector<ParticleIndex>& particle1_indexes,
+                           const std::vector<ParticleIndex>& particle2_indexes,
+                           FloatKey attr_name,
+                           BasicScoreFuncParams& score_func_params)
 {
-  Particle* p1;
-
   num_particles1_ = particle1_indexes.size();
-  num_particles2_ = particle2_indexes.size();
-  num_particles_ = num_particles1_ + num_particles2_;
-  for (int i = 0; i < num_particles1_; i++) {
-    p1 = model->get_particle(particle1_indexes[i]);
-    add_particle(p1);
-  }
 
-  for (int i = 0; i < num_particles2_; i++) {
-    p1 = model->get_particle(particle2_indexes[i]);
-    add_particle(p1);
+  for (unsigned int i=0; i< particle1_indexes.size(); ++i) {
+    add_particle(model->get_particle(particle1_indexes[i]));
   }
+  for (unsigned int i=0; i< particle2_indexes.size(); ++i) {
+    add_particle(model->get_particle(particle2_indexes[i]));
+  }
 
-  num_restraints_ = num_particles1_ * num_particles2_;
-
   // get the indexes associated with the restraints
-  Float actual_mean;
-  IMP_LOG(VERBOSE, "Add inter-body exclusion volume restraints "
-          << num_restraints_);
+  IMP_LOG(VERBOSE, "Add inter-body exclusion volume restraints ");
 
   // particle 1 indexes
   for (int i = 0; i < num_particles1_; i++) {
     // particle 2 indexes
-    for (int j = num_particles1_; j < num_particles_; j++) {
+    for (unsigned int j = num_particles1_; j < number_of_particles(); j++) {
       // Use those radii to calculate the expected distance
       Float attri, attrj;
       attri = get_particle(i)->get_value(attr_name);
       attrj = get_particle(j)->get_value(attr_name);
-      actual_mean = attri + attrj;
+      Float actual_mean = attri + attrj;
 
-      score_func_params->set_mean(actual_mean);
+      score_func_params.set_mean(actual_mean);
 
       // create the restraint
       dist_rsrs_.push_back(new DistanceRestraint(model,
-                                                 get_particle(i),
-                                                 get_particle(j),
-                                                 score_func_params));
+                                                 get_particle(i)->get_index(),
+                                                 get_particle(j)->get_index(),
+                               score_func_params.create_score_func()));
+      dist_rsrs_.back()->set_model(model);
     }
   }
 }
@@ -94,43 +88,35 @@
     \param[in] score_func_params Scoring function parameters.
  */
 ExclusionVolumeRestraint::ExclusionVolumeRestraint(Model* model,
-    std::vector<int>& particle_indexes, FloatKey attr_name,
-    BasicScoreFuncParams* score_func_params)
+    const std::vector<ParticleIndex>& particle_indexes, FloatKey attr_name,
+    BasicScoreFuncParams& score_func_params)
 {
-  Particle* p1;
 
-  num_particles_ = particle_indexes.size();
-  for (int i = 0; i < num_particles_; i++) {
-    p1 = model->get_particle(particle_indexes[i]);
-    add_particle(p1);
+  num_particles1_ = -1;
+  for (unsigned int i=0; i< particle_indexes.size(); ++i) {
+    add_particle(model->get_particle(particle_indexes[i]));
   }
 
-  num_restraints_ = num_particles_ * (num_particles_ - 1) / 2;
-
   // get the indexes associated with the restraints
-  int idx = 0;
-  Float actual_mean;
-  IMP_LOG(VERBOSE, "Add intra-body exclusion volume restraints "
-          << num_restraints_);
+  IMP_LOG(VERBOSE, "Add intra-body exclusion volume restraints ");
 
   // particle 1 indexes
-  for (int i = 0; i < num_particles_ - 1; i++) {
+  for (unsigned int i = 0; i < number_of_particles(); i++) {
     // particle 2 indexes (avoid duplicates and particle with itself)
-    for (int j = i + 1; j < num_particles_; j++) {
+    for (unsigned int j = 0; j < i; j++) {
       // Use those radii to calculate the expected distance
-      Float attri, attrj;
-      attri = get_particle(i)->get_value(attr_name);
-      attrj = get_particle(j)->get_value(attr_name);
-      actual_mean = attri + attrj;
+      Float attri = get_particle(i)->get_value(attr_name);
+      Float attrj = get_particle(j)->get_value(attr_name);
+      Float actual_mean = attri + attrj;
 
-      score_func_params->set_mean(actual_mean);
+      score_func_params.set_mean(actual_mean);
 
       // create the restraint
       dist_rsrs_.push_back(new DistanceRestraint(model,
-                                                 get_particle(i),
-                                                 get_particle(j),
-                                                 score_func_params));
-      idx++;
+                                                 get_particle(i)->get_index(),
+                                                 get_particle(j)->get_index(),
+                                  score_func_params.create_score_func()));
+      dist_rsrs_.back()->set_model(model);
     }
   }
 }
@@ -188,7 +174,6 @@
 
   out << "version: " << version() << "  ";
   out << "last_modified_by: " << last_modified_by() << std::endl;
-  out << "  num particles:" << num_particles_;
 }
 
 }  // namespace IMP
Index: include/IMP/restraints/ExclusionVolumeRestraint.h
===================================================================
--- include/IMP/restraints/ExclusionVolumeRestraint.h	(revision 630)
+++ include/IMP/restraints/ExclusionVolumeRestraint.h	(working copy)
@@ -36,29 +36,25 @@
 class IMPDLLEXPORT ExclusionVolumeRestraint : public Restraint
 {
 public:
-  ExclusionVolumeRestraint(Model* model, std::vector<int>& particle1_indexes,
-                           std::vector<int>& particle2_indexes,
+  ExclusionVolumeRestraint(Model* model,
+                           const std::vector<ParticleIndex>& particle1_indexes,
+                           const std::vector<ParticleIndex>& particle2_indexes,
                            FloatKey attr_name,
-                           BasicScoreFuncParams* score_func_params);
+                           BasicScoreFuncParams& score_func_params);
 
-  ExclusionVolumeRestraint(Model* model, std::vector<int>& particle_indexes,
+  ExclusionVolumeRestraint(Model* model, 
+                           const std::vector<ParticleIndex>& particle_indexes,
                            FloatKey attr_name,
-                           BasicScoreFuncParams* score_func_params);
+                           BasicScoreFuncParams& score_func_params);
 
   virtual ~ExclusionVolumeRestraint();
 
-  IMP_RESTRAINT("0.5", "Daniel Russel")
+  IMP_RESTRAINT("0.6", "Daniel Russel")
 
 protected:
-  //! number of particles all together
-  int num_particles_;
   //! number of particles in vector 1
   int num_particles1_;
-  //! number of particles in vector 2
-  int num_particles2_;
 
-  //! total number of restraints
-  int num_restraints_;
   //! restraints and their scores
   std::vector<DistanceRestraint*> dist_rsrs_;
 };
Index: include/IMP/restraints/DistanceRestraint.h
===================================================================
--- include/IMP/restraints/DistanceRestraint.h	(revision 630)
+++ include/IMP/restraints/DistanceRestraint.h	(working copy)
@@ -21,38 +21,30 @@
 {
 
 //! Distance restraint between two particles
+/**
+   This class implements a restraint that is a function of the distance 
+   between two restraints. 
+ */
 class IMPDLLEXPORT DistanceRestraint : public Restraint
 {
 public:
   //! particles must be at least this far apart to calculate the restraint
   static const Float MIN_DISTANCE;
 
-  DistanceRestraint(Model* model, Particle* p1, Particle* p2,
-                    BasicScoreFuncParams* score_func_params);
-  DistanceRestraint(Model* model, Particle* p1, Particle* p2,
-                    FloatKey attr_name,
-                    BasicScoreFuncParams* score_func_params);
+  //! Create a distance restraint based on ScoreFunc between the particles
+  DistanceRestraint(Model* model, ParticleIndex p1, ParticleIndex p2,
+                    ScoreFunc* score_func_params);
   virtual ~DistanceRestraint();
 
   IMP_RESTRAINT("0.5", "Daniel Russel")
 
 protected:
-  //! Do set up for the distant restraint constructors.
-  /** \param[in] model Pointer to the model.
-      \param[in] p1 Pointer to first particle in distance restraint.
-      \param[in] p2 Pointer to second particle in distance restraint.
-      \param[in] score_func_params Score function parameters for the restraint.
-   */
-  void set_up(Model* model, Particle* p1, Particle* p2,
-              BasicScoreFuncParams* score_func_params);
+  void set_up(Model* model, ParticleIndex p1, ParticleIndex p2,
+              ScoreFunc* score_func_params);
 
-  //! variables used to determine the distance
-  FloatKey x_, y_, z_;
-
-  //! variables used to calculate the math form
-  Float mean_, sd_;
   //! math form for this restraint (typically one of the harmonics)
   ScoreFunc* score_func_;
+  FloatKey x_,y_,z_;
 };
 
 } // namespace IMP
Index: include/IMP/restraints/TorusRestraint.h
===================================================================
--- include/IMP/restraints/TorusRestraint.h	(revision 630)
+++ include/IMP/restraints/TorusRestraint.h	(working copy)
@@ -20,7 +20,7 @@
 class IMPDLLEXPORT TorusRestraint : public Restraint
 {
 public:
-  TorusRestraint(Model& model, Particle* p1, const Float main_radius,
+  TorusRestraint(Model* model, Particle* p1, const Float main_radius,
                  const Float tube_radius,
                  BasicScoreFuncParams* score_func_params);
   virtual ~TorusRestraint();
Index: pyext/IMP_macros.i
===================================================================
--- pyext/IMP_macros.i	(revision 630)
+++ pyext/IMP_macros.i	(working copy)
@@ -6,7 +6,7 @@
 #define IMP_OUTPUT_OPERATOR(f)
 #define IMP_RESTRAINT(a,b) \
    virtual Float evaluate(DerivativeAccumulator *accum);\
-   virtual void show(std::ostream &out) const;\
+   virtual void show(std::ostream &out=std::cout) const;\
    virtual std::string version() const {return std::string(a);}\
    virtual std::string last_modified_by() const {return std::string(b);}
 #define IMP_OPTIMIZER(a, b)                       \
Index: pyext/IMP/utils.py
===================================================================
--- pyext/IMP/utils.py	(revision 630)
+++ pyext/IMP/utils.py	(working copy)
@@ -89,8 +89,8 @@
                    + particles[j].get_value(radius_name)
             score_func_params = IMP.BasicScoreFuncParams("harmonic_lower_bound",
                                                          mean, sd)
-            rsrs.append(IMP.DistanceRestraint(model, particles[i], particles[j],
-                                              score_func_params))
+            rsrs.append(IMP.DistanceRestraint(model, particles[i].get_index(), particles[j].get_index(),
+                                              score_func_params.create_score_func()))
 
 
 def write_pdb(model, fname):
Index: pyext/IMP/xml_loader.py
===================================================================
--- pyext/IMP/xml_loader.py	(revision 630)
+++ pyext/IMP/xml_loader.py	(working copy)
@@ -197,7 +197,9 @@
                 + p2.get_value(IMP.FloatKey(distance_attribute))
 
         score_func_params = get_basic_score_func_params(score_func_str, distance, sd)
-        model.restraints.append(IMP.DistanceRestraint(model, p1, p2, score_func_params))
+        model.restraints.append(IMP.DistanceRestraint(model, p1.get_index(),
+                                                      p2.get_index(),
+                                                      score_func_params.create_score_func()))
         model.restraint_sets[rs_idx].add_restraint(model.restraints[len(model.restraints)-1])
 
 
Index: pyext/IMP.i
===================================================================
--- pyext/IMP.i	(revision 630)
+++ pyext/IMP.i	(working copy)
@@ -28,6 +28,9 @@
   %pythonprepend RestraintSet::add_restraint %{
         args[1].thisown=0
   %}
+  %pythonprepend DistanceRestraint::DistanceRestraint %{
+        args[3].thisown=0
+  %}
 }
 
 %feature("director");
@@ -82,7 +85,8 @@
   %template(ResidueType) Key<ResidueTypeTag>;     
   %template(show_named_nierarchy) show<NameDecorator>;
   %template(show_molecular_hierarchy) show<MolecularHierarchyDecorator>;
-  %template(ParticleVector) ::std::vector<Particle*>;       
+  %template(Particles) ::std::vector<Particle*>;       
+  %template(ParticleIndexes) ::std::vector<ParticleIndex>;       
   %template(FloatKeys) ::std::vector<FloatKey>;
   %template(StringKeys) ::std::vector<StringKey>;
   %template(IntKeys) ::std::vector<IntKey>;
Index: include/IMP/utility.h
===================================================================
--- include/IMP/utility.h	(revision 630)
+++ include/IMP/utility.h	(working copy)
@@ -69,7 +69,7 @@
   /** evaluate the restraint*/                                          \
   virtual Float evaluate(DerivativeAccumulator *accum);                 \
   /** write information about the restraint to the stream*/             \
-  virtual void show(std::ostream &out) const;                           \
+  virtual void show(std::ostream &out=std::cout) const;                 \
   /** \return the current version*/                                     \
   virtual std::string version() const {return std::string(version_string);}\
   /** \return the last person to modify this restraint */               \