Index: kernel/test/pair_scores/test_transform.py
===================================================================
--- kernel/test/pair_scores/test_transform.py	(revision 0)
+++ kernel/test/pair_scores/test_transform.py	(revision 0)
@@ -0,0 +1,96 @@
+import unittest
+import IMP.utils
+import IMP.test, IMP
+
+class DistanceTests(IMP.test.TestCase):
+    """Test the symmetry restraint"""
+    def test_symmetry(self):
+        """Test the transform pair score basics"""
+        IMP.set_log_level(IMP.VERBOSE)
+        m= IMP.Model()
+        p0= IMP.Particle()
+        m.add_particle(p0)
+        d0= IMP.XYZDecorator.create(p0)
+        p1= IMP.Particle()
+        m.add_particle(p1)
+        d1= IMP.XYZDecorator.create(p1)
+        tps= IMP.TransformedDistancePairScore(IMP.Harmonic(0,1))
+        tps.set_translation(0,1,0)
+        tps.set_rotation(1, 0, 0,
+                         0, 1, 0,
+                         0, 0, 1)
+        d0.set_coordinates(IMP.Vector3D(2,3,4))
+        d1.set_coordinates(IMP.Vector3D(2,2,4))
+        self.assertEqual(tps.evaluate(p0, p1, None), 0)
+        self.assert_(tps.evaluate(p1, p0, None) != 0)
+        tps.set_center(10,13,4)
+        self.assertEqual(tps.evaluate(p0, p1, None), 0)
+        self.assert_(tps.evaluate(p1, p0, None) != 0)
+        tps.set_center(0,0,0)
+        print "test rotation"
+        tps.set_rotation(0, 0,-1,
+                         0, 1, 0,
+                         1, 0, 0)
+        d1.set_coordinates(IMP.Vector3D(4, 2, -2))
+        self.assertEqual(tps.evaluate(p0, p1, None), 0)
+        self.assert_(tps.evaluate(p1, p0, None) != 0)
+        tps.set_translation(0,0,0)
+        tps.set_rotation(0,-1, 0,
+                         1, 0, 0,
+                         0, 0, 1)
+        d0.set_coordinates(IMP.Vector3D(0,1,0))
+        d1.set_coordinates(IMP.Vector3D(1,1,0))
+        # clear derivs
+        print "test derivs"
+        m.evaluate(True)
+        tps.evaluate(p0, p1, IMP.DerivativeAccumulator(1))
+        print d0.get_coordinate_derivative(0)
+        print d0.get_coordinate_derivative(1)
+        print d0.get_coordinate_derivative(2)
+        print d1.get_coordinate_derivative(0)
+        print d1.get_coordinate_derivative(1)
+        print d1.get_coordinate_derivative(2)
+        self.assert_(d0.get_coordinate_derivative(0) > 0)
+        self.assert_(d0.get_coordinate_derivative(1) == 0)
+        self.assert_(d0.get_coordinate_derivative(2) == 0)
+        self.assert_(d1.get_coordinate_derivative(1) > 0)
+        self.assert_(d1.get_coordinate_derivative(0) == 0)
+        self.assert_(d1.get_coordinate_derivative(2) == 0)
+    def test_symmetry2(self):
+        """Test the transform pair score optimization"""
+        IMP.set_log_level(IMP.VERBOSE)
+        m= IMP.Model()
+        p0= IMP.Particle()
+        m.add_particle(p0)
+        d0= IMP.XYZDecorator.create(p0)
+        p1= IMP.Particle()
+        m.add_particle(p1)
+        d1= IMP.XYZDecorator.create(p1)
+        d0.set_coordinates(IMP.Vector3D(2,3,4))
+        d1.set_coordinates(IMP.Vector3D(20,20,40))
+        d0.set_coordinates_are_optimized(True)
+        d1.set_coordinates_are_optimized(True)
+        tps= IMP.TransformedDistancePairScore(IMP.Harmonic(0,1))
+        tps.set_translation(0,1,0)
+        tps.set_rotation(1, 0, 0,
+                         0, 0,-1,
+                         0, 1, 0)
+        pr= IMP.PairListRestraint(tps)
+        pr.add_particle_pair(IMP.ParticlePair(p0, p1))
+        m.add_restraint(pr)
+        cg= IMP.ConjugateGradients()
+        cg.set_model(m)
+        cg.optimize(100)
+        d0.show()
+        d1.show()
+        vt= IMP.Vector3D(d1.get_vector()*IMP.Vector3D(1,0,0)+0,
+                         d1.get_vector()*IMP.Vector3D(0,0,-1)+1,
+                         d1.get_vector()*IMP.Vector3D(0,1,0)+0)
+        print "trans"
+        print str(vt[0]) + " " + str(vt[1])+" " + str(vt[2])
+        self.assertEqual(vt[0], d0.get_coordinate(0))
+        self.assertEqual(vt[1], d0.get_coordinate(1))
+        self.assertEqual(vt[2], d0.get_coordinate(2))
+
+if __name__ == '__main__':
+    unittest.main()
Index: kernel/include/IMP/singleton_scores/DistanceToSingletonScore.h
===================================================================
--- kernel/include/IMP/singleton_scores/DistanceToSingletonScore.h	(revision 620)
+++ kernel/include/IMP/singleton_scores/DistanceToSingletonScore.h	(working copy)
@@ -31,6 +31,7 @@
   virtual void show(std::ostream &out=std::cout) const;
 };
 
+
 } // namespace IMP
 
 #endif  /* __IMP_DISTANCE_TO_SINGLETON_SCORE_H */
Index: kernel/include/IMP/decorators/XYZDecorator.h
===================================================================
--- kernel/include/IMP/decorators/XYZDecorator.h	(revision 620)
+++ kernel/include/IMP/decorators/XYZDecorator.h	(working copy)
@@ -71,6 +71,13 @@
                                     DerivativeAccumulator &d) {
     get_particle()->add_to_derivative(get_coordinate_key(i), v, d);
   }
+  //! Add something to the derivative of the coordinates
+  void add_to_coordinates_derivative(const Vector3D& v, 
+                         DerivativeAccumulator &d) {
+    add_to_coordinate_derivative(0, v[0], d);
+    add_to_coordinate_derivative(1, v[1], d);
+    add_to_coordinate_derivative(2, v[2], d);
+  }
   //! Get whether the coordinates are optimized
   /** \return true only if all of them are optimized. 
     */
Index: kernel/include/IMP/pair_scores/SConscript
===================================================================
--- kernel/include/IMP/pair_scores/SConscript	(revision 620)
+++ kernel/include/IMP/pair_scores/SConscript	(working copy)
@@ -2,7 +2,8 @@
 Import('env')
 
 files = ['DistancePairScore.h', 'SphereDistancePairScore.h',
-         'RefineOncePairScore.h', 'TypedPairScore.h']
+         'RefineOncePairScore.h', 'TypedPairScore.h',
+         'TransformedDistancePairScore.h']
 
 # Install the include files:
 includedir = os.path.join(env['includedir'], 'IMP', 'pair_scores')
Index: kernel/include/IMP/pair_scores/DistancePairScore.h
===================================================================
--- kernel/include/IMP/pair_scores/DistancePairScore.h	(revision 620)
+++ kernel/include/IMP/pair_scores/DistancePairScore.h	(working copy)
@@ -29,20 +29,6 @@
   virtual void show(std::ostream &out=std::cout) const;
 };
 
-namespace internal
-{
-
-//! An internal helper function for evaluating distance potentials
-/** The function applies f to scale*(distance-offset).
- */
-Float evaluate_distance_pair_score(Particle *a, Particle *b,
-                                   DerivativeAccumulator *da,
-                                   UnaryFunction *f,
-                                   Float offset,
-                                   Float scale);
-
-} // namespace internal
-
 } // namespace IMP
 
 #endif  /* __IMP_DISTANCE_PAIR_SCORE_H */
Index: kernel/include/IMP/pair_scores/TransformedDistancePairScore.h
===================================================================
--- kernel/include/IMP/pair_scores/TransformedDistancePairScore.h	(revision 0)
+++ kernel/include/IMP/pair_scores/TransformedDistancePairScore.h	(revision 0)
@@ -0,0 +1,52 @@
+/**
+ *  \file TransformedDistancePairScore.h    
+ *  \brief A Score on the distance between a pair of particles.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ */
+
+#ifndef __IMP_TRADISTANCE_PAIR_SCORE_H
+#define __IMP_TRADISTANCE_PAIR_SCORE_H
+
+#include "../PairScore.h"
+#include "../UnaryFunction.h"
+#include "../Pointer.h"
+#include "../Vector3D.h"
+
+namespace IMP
+{
+
+/** 
+    \brief  Apply a function to the distance between two particles
+    after transforming the first
+
+    Apply a transform to the second particle and then apply the unary
+    function to the distance between the transformed particle and the
+    second. This can be used to implement symmetry restraints.
+
+    The second particle, x, is transformed as R*(x-center)+ translation+center
+
+    \ingroup pairscore
+ */
+class IMPDLLEXPORT TransformedDistancePairScore : public PairScore
+{
+  Pointer<UnaryFunction> f_;
+  Vector3D tc_, c_;
+  Vector3D r_[3], ri_[3];
+ public:
+  TransformedDistancePairScore(UnaryFunction *f);
+  virtual ~TransformedDistancePairScore(){}
+  virtual Float evaluate(Particle *a, Particle *b,
+                         DerivativeAccumulator *da);
+  virtual void show(std::ostream &out=std::cout) const;
+
+  void set_rotation(float r00, float r01, float r02,
+                    float r10, float r11, float r12,
+                    float r20, float r21, float r22);
+  void set_translation(float t0, float t1, float t2);
+  void set_center(float t0, float t1, float t2);
+};
+
+} // namespace IMP
+
+#endif  /* __IMP_TRADISTANCE_PAIR_SCORE_H */
Index: kernel/include/IMP/internal/SConscript
===================================================================
--- kernel/include/IMP/internal/SConscript	(revision 620)
+++ kernel/include/IMP/internal/SConscript	(working copy)
@@ -5,7 +5,8 @@
          'ref_counting.h', 'ObjectContainer.h', 'ParticleGrid.h',
          'kernel_version_info.h', 'constants.h', 'units.h',
          'utility.h', 'bbox_nbl_helpers.h',
-         'ArrayOnAttributesHelper.h', 'Unit.h', 'ExponentialNumber.h']
+         'ArrayOnAttributesHelper.h', 'Unit.h', 'ExponentialNumber.h',
+         'evaluate_distance_pair_score.h']
 
 # Install the include files:
 includedir = os.path.join(env['includedir'], 'IMP', 'internal')
Index: kernel/include/IMP/internal/units.h
===================================================================
--- kernel/include/IMP/internal/units.h	(revision 620)
+++ kernel/include/IMP/internal/units.h	(working copy)
@@ -119,6 +119,8 @@
 typedef Multiply<Multiply<Centimeter, Centimeter>::type,
                       Centimeter>::type CubicCentimeter;
 typedef Divide<Gram, CubicCentimeter>::type GramPerCubicCentimeter;
+typedef Shift<Second, -9>::type NanoSecond;
+typedef Shift<Second, -15>::type FemtoSecond;
 
 
 
Index: kernel/include/IMP/internal/evaluate_distance_pair_score.h
===================================================================
--- kernel/include/IMP/internal/evaluate_distance_pair_score.h	(revision 0)
+++ kernel/include/IMP/internal/evaluate_distance_pair_score.h	(revision 0)
@@ -0,0 +1,76 @@
+/**
+ *  \file evaluate_distance_pair_score.h
+ *  \brief A Score on the distance between a pair of particles.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ */
+
+#ifndef IMP_EVALUTE_DISTANCE_PAIR_SCORE_H
+#define IMP_EVALUTE_DISTANCE_PAIR_SCORE_H
+
+#include "../Vector3D.h"
+
+namespace IMP
+{
+
+namespace internal
+{
+
+template <class W0, class W1, class SD>
+Float evaluate_distance_pair_score(W0 d0, W1 d1,
+                                   DerivativeAccumulator *da,
+                                   UnaryFunction *f,
+                                   SD sd)
+{
+  static const Float MIN_DISTANCE = .00001;
+  IMP_CHECK_OBJECT(f);
+  //IMP_CHECK_OBJECT(a);
+  //IMP_CHECK_OBJECT(b);
+
+  Float d2 = 0;
+  Vector3D delta;
+  Float score;
+
+  /*IMP_IF_CHECK(CHEAP) {
+    XYZDecorator::cast(a);
+    XYZDecorator::cast(b);
+    }*/
+
+  //XYZDecorator d0(a);
+  //XYZDecorator d1(b);
+  for (int i = 0; i < 3; ++i) {
+    delta[i] = d0.get_coordinate(i) - d1.get_coordinate(i);
+    d2 += square(delta[i]);
+  }
+
+  Float distance = std::sqrt(d2);
+
+  Float shifted_distance = sd(distance); //scale*(distance - offset);
+
+  // if needed, calculate the partial derivatives of the scores with respect
+  // to the particle attributes
+  // avoid division by zero if the distance is too small
+  if (da && distance >= MIN_DISTANCE) {
+    Float deriv;
+
+    score = f->evaluate_deriv(shifted_distance, deriv);
+
+    Vector3D d= delta/distance *deriv;
+    //for (int i = 0; i < 3; ++i) {
+    // Float d = delta[i] / distance * deriv;
+    d0.add_to_coordinates_derivative(d, *da);
+    d1.add_to_coordinates_derivative(-d, *da);
+      //}
+  } else {
+    // calculate the score based on the distance feature
+    score = f->evaluate(shifted_distance);
+  }
+
+  return score;
+}
+
+} // namespace internal
+
+} // IMP
+
+#endif
Index: kernel/include/IMP/Vector3D.h
===================================================================
--- kernel/include/IMP/Vector3D.h	(revision 620)
+++ kernel/include/IMP/Vector3D.h	(working copy)
@@ -65,6 +65,20 @@
                     operator[](2) * s); 
   }
 
+  //! product with scalar
+  Vector3D operator/(Float s) const {
+    return Vector3D(operator[](0) / s, 
+                    operator[](1) / s,
+                    operator[](2) / s); 
+  }
+
+  //! negation
+  Vector3D operator-() const {
+    return Vector3D(-operator[](0), 
+                    -operator[](1),
+                    -operator[](2)); 
+  }
+
   //! \return the vector product of two vectors.
   /** \param[in] vec2 The other vector to use in the product.
    */
@@ -106,7 +120,7 @@
                     operator[](2) + o[2]);
   }
 
-  void show(std::ostream &out) const {
+  void show(std::ostream &out=std::cout) const {
     out << "(" << operator[](0) << ", " << operator[](1) << ", "
         << operator[](2) << ")";
   }
Index: kernel/include/IMP.h
===================================================================
--- kernel/include/IMP.h	(revision 620)
+++ kernel/include/IMP.h	(working copy)
@@ -60,6 +60,7 @@
 #include "IMP/pair_scores/SphereDistancePairScore.h"
 #include "IMP/pair_scores/RefineOncePairScore.h"
 #include "IMP/pair_scores/TypedPairScore.h"
+#include "IMP/pair_scores/TransformedDistancePairScore.h"
 #include "IMP/singleton_scores/DistanceToSingletonScore.h"
 #include "IMP/singleton_scores/AttributeSingletonScore.h"
 #include "IMP/triplet_scores/AngleTripletScore.h"
Index: kernel/src/singleton_scores/DistanceToSingletonScore.cpp
===================================================================
--- kernel/src/singleton_scores/DistanceToSingletonScore.cpp	(revision 620)
+++ kernel/src/singleton_scores/DistanceToSingletonScore.cpp	(working copy)
@@ -8,60 +8,19 @@
 #include "IMP/singleton_scores/DistanceToSingletonScore.h"
 #include "IMP/decorators/XYZDecorator.h"
 #include "IMP/UnaryFunction.h"
+#include "IMP/internal/evaluate_distance_pair_score.h"
+#include <boost/lambda/lambda.hpp>
 
 namespace IMP
 {
 
-namespace internal
-{
+struct StaticD {
+  Vector3D v_;
+  StaticD(Vector3D v): v_(v){}
+  Float get_coordinate(unsigned int i) {return v_[i];}
+  void add_to_coordinates_derivative(Vector3D, DerivativeAccumulator){}
+};
 
-static const Float MIN_DISTANCE = .00001;
-Float evaluate_distance_to_singleton_score(const Vector3D &v, 
-                                           Particle *b,
-                                           DerivativeAccumulator *da,
-                                           UnaryFunction *f,
-                                           Float offset,
-                                           Float scale)
-{
-  IMP_CHECK_OBJECT(f);
-  IMP_CHECK_OBJECT(b);
-
-  Float d2 = 0, delta[3];
-  Float score;
-
-  XYZDecorator d1 = XYZDecorator::cast(b);
-
-  for (int i = 0; i < 3; ++i) {
-    delta[i] = v[i] - d1.get_coordinate(i);
-    d2 += square(delta[i]);
-  }
-
-  Float distance = std::sqrt(d2);
-
-  Float shifted_distance = scale*(distance - offset);
-
-  // if needed, calculate the partial derivatives of the scores with respect
-  // to the particle attributes
-  // avoid division by zero if the distance is too small
-  if (da && distance >= MIN_DISTANCE) {
-    Float deriv;
-
-    score = f->evaluate_deriv(shifted_distance, deriv);
-
-    for (int i = 0; i < 3; ++i) {
-      Float d = delta[i] / distance * deriv;
-      d1.add_to_coordinate_derivative(i, -d, *da);
-    }
-  } else {
-    // calculate the score based on the distance feature
-    score = f->evaluate(shifted_distance);
-  }
-
-  return score;
-}
-
-} // namespace internal
-
 DistanceToSingletonScore::DistanceToSingletonScore(UnaryFunction *f,
                                                    const Vector3D &v): f_(f),
                                                                        pt_(v){}
@@ -69,8 +28,9 @@
 Float DistanceToSingletonScore::evaluate(Particle *b,
                                          DerivativeAccumulator *da)
 {
-  return internal::evaluate_distance_to_singleton_score(pt_,b, da,
-                                                        f_.get(), 0,1);
+  return internal::evaluate_distance_pair_score(XYZDecorator(b),
+                                                StaticD(pt_), da,
+                                                f_.get(), boost::lambda::_1);
 }
 
 void DistanceToSingletonScore::show(std::ostream &out) const
Index: kernel/src/restraints/BondDecoratorRestraint.cpp
===================================================================
--- kernel/src/restraints/BondDecoratorRestraint.cpp	(revision 620)
+++ kernel/src/restraints/BondDecoratorRestraint.cpp	(working copy)
@@ -11,6 +11,9 @@
 #include "IMP/score_states/BondDecoratorListScoreState.h"
 #include "IMP/decorators/bond_decorators.h"
 #include "IMP/pair_scores/DistancePairScore.h"
+#include "IMP/internal/evaluate_distance_pair_score.h"
+#include "IMP/decorators/XYZDecorator.h"
+#include <boost/lambda/lambda.hpp>
 
 namespace IMP
 {
@@ -47,11 +50,11 @@
     }
     if (pa && pb) {
       sum+= 
-        internal::evaluate_distance_pair_score(pa,
-                                               pb,
+        internal::evaluate_distance_pair_score(XYZDecorator(pa),
+                                               XYZDecorator(pb),
                                                accum,
                                                f_.get(),
-                                               l, s);
+                                               s*(boost::lambda::_1-l));
     }
   }
   return sum;
Index: kernel/src/pair_scores/DistancePairScore.cpp
===================================================================
--- kernel/src/pair_scores/DistancePairScore.cpp	(revision 620)
+++ kernel/src/pair_scores/DistancePairScore.cpp	(working copy)
@@ -8,72 +8,26 @@
 #include "IMP/pair_scores/DistancePairScore.h"
 #include "IMP/decorators/XYZDecorator.h"
 #include "IMP/UnaryFunction.h"
+#include "IMP/internal/evaluate_distance_pair_score.h"
+#include <boost/lambda/lambda.hpp>
 
 namespace IMP
 {
 
-namespace internal
-{
+DistancePairScore::DistancePairScore(UnaryFunction *f): f_(f){}
 
-static const Float MIN_DISTANCE = .00001;
-Float evaluate_distance_pair_score(Particle *a, Particle *b,
-                                   DerivativeAccumulator *da,
-                                   UnaryFunction *f,
-                                   Float offset,
-                                   Float scale)
+struct Identity
 {
-  IMP_CHECK_OBJECT(f);
-  IMP_CHECK_OBJECT(a);
-  IMP_CHECK_OBJECT(b);
+  Float operator()(Float t) const {return t;}
+};
 
-  Float d2 = 0, delta[3];
-  Float score;
-
-  IMP_IF_CHECK(CHEAP) {
-    XYZDecorator::cast(a);
-    XYZDecorator::cast(b);
-  }
-
-  XYZDecorator d0(a);
-  XYZDecorator d1(b);
-  for (int i = 0; i < 3; ++i) {
-    delta[i] = d0.get_coordinate(i) - d1.get_coordinate(i);
-    d2 += square(delta[i]);
-  }
-
-  Float distance = std::sqrt(d2);
-
-  Float shifted_distance = scale*(distance - offset);
-
-  // if needed, calculate the partial derivatives of the scores with respect
-  // to the particle attributes
-  // avoid division by zero if the distance is too small
-  if (da && distance >= MIN_DISTANCE) {
-    Float deriv;
-
-    score = f->evaluate_deriv(shifted_distance, deriv);
-
-    for (int i = 0; i < 3; ++i) {
-      Float d = delta[i] / distance * deriv;
-      d0.add_to_coordinate_derivative(i, d, *da);
-      d1.add_to_coordinate_derivative(i, -d, *da);
-    }
-  } else {
-    // calculate the score based on the distance feature
-    score = f->evaluate(shifted_distance);
-  }
-
-  return score;
-}
-
-} // namespace internal
-
-DistancePairScore::DistancePairScore(UnaryFunction *f): f_(f){}
-
 Float DistancePairScore::evaluate(Particle *a, Particle *b,
                                   DerivativeAccumulator *da)
 {
-  return internal::evaluate_distance_pair_score(a,b, da, f_.get(), 0,1);
+  return internal::evaluate_distance_pair_score(XYZDecorator(a),
+                                                XYZDecorator(b),
+                                                da, f_.get(),
+                                                boost::lambda::_1);
 }
 
 void DistancePairScore::show(std::ostream &out) const
Index: kernel/src/pair_scores/SConscript
===================================================================
--- kernel/src/pair_scores/SConscript	(revision 620)
+++ kernel/src/pair_scores/SConscript	(working copy)
@@ -1,7 +1,8 @@
 Import('env')
 
 files = ['DistancePairScore.cpp', 'SphereDistancePairScore.cpp',
-         'RefineOncePairScore.cpp', 'TypedPairScore.cpp']
+         'RefineOncePairScore.cpp', 'TypedPairScore.cpp',
+         'TransformedDistancePairScore.cpp']
 
 files = [File(x) for x in files]
 Return('files')
Index: kernel/src/pair_scores/TransformedDistancePairScore.cpp
===================================================================
--- kernel/src/pair_scores/TransformedDistancePairScore.cpp	(revision 0)
+++ kernel/src/pair_scores/TransformedDistancePairScore.cpp	(revision 0)
@@ -0,0 +1,140 @@
+/**
+ *  \file TransformedDistancePairScore.cpp
+ *  \brief A Score on the distance between a pair of particles.
+ *
+ *  Copyright 2007-8 Sali Lab. All rights reserved.
+ */
+
+#include "IMP/pair_scores/TransformedDistancePairScore.h"
+#include "IMP/decorators/XYZDecorator.h"
+#include "IMP/UnaryFunction.h"
+#include "IMP/decorators/XYZDecorator.h"
+#include "IMP/internal/evaluate_distance_pair_score.h"
+#include <boost/lambda/lambda.hpp>
+
+
+namespace IMP
+{
+
+static void inverse(float r00, float r01, float r02,
+                    float r10, float r11, float r12,
+                    float r20, float r21, float r22,
+                    Vector3D *inv) {
+  Float t4 = r00*r11;
+  Float t6 = r00*r12;
+  Float t8 = r01*r10;
+  Float t10 = r02*r10;
+  Float t12 = r01*r20;
+  Float t14 = r02*r20;
+  Float t17i = (t4*r22-t6*r21-t8*r22+t10*r21+t12*r12-t14*r11);
+  IMP_check(t17i != 0, "Singular matrix", ValueException);
+  Float t17= 1.0/t17i;
+  inv[0][0] = (r11*r22-r12*r21)*t17;
+  inv[0][1] = -(r01*r22-r02*r21)*t17;
+  inv[0][2] = (r01*r12-r02*r11)*t17;
+  inv[1][0] = -(r10*r22-r12*r20)*t17;
+  inv[1][1] = (r00*r22-t14)*t17;
+  inv[1][2] = -(t6-t10)*t17;
+  inv[2][0] = (r10*r21-r11*r20)*t17;
+  inv[2][1] = -(r00*r21-t12)*t17;
+  inv[2][2] = (t4-t8)*t17;
+}
+
+TransformedDistancePairScore
+::TransformedDistancePairScore(UnaryFunction *f): f_(f),
+                                                  tc_(0,0,0),
+                                                  c_(0,0,0)
+{
+  set_rotation(1,0,0,
+               0,1,0,
+               0,0,1);
+}
+
+
+/*
+  Compute R(x-c)+tc and the reverse
+  dt= R(d-c)+tc-> Rt(dt-tc)+c
+ */
+struct TransformParticle
+{
+  const Vector3D *r_, *ri_;
+  const Vector3D &tc_;
+  const Vector3D &c_;
+  XYZDecorator d_;
+  TransformParticle(const Vector3D *r,
+                    const Vector3D *ri,
+                    const Vector3D &tc,
+                    const Vector3D &c,
+                    Particle *p): r_(r), ri_(ri),
+                                  tc_(tc), c_(c), d_(p){}
+
+  Float get_coordinate(unsigned int i) const {
+    return (d_.get_vector()-c_)*r_[i] + tc_[i];
+  }
+
+  void add_to_coordinates_derivative(const Vector3D& f,
+                                     DerivativeAccumulator &da) {
+    Vector3D r(f*ri_[0],
+               f*ri_[1],
+               f*ri_[2]);
+    d_.add_to_coordinates_derivative(r, da);
+  }
+};
+
+Float TransformedDistancePairScore::evaluate(Particle *a, Particle *b,
+                                             DerivativeAccumulator *da)
+{
+  TransformParticle tb(r_,ri_, tc_,c_,b);
+  IMP_LOG(VERBOSE, "Transformed particle is " 
+          << tb.get_coordinate(0) << " " << tb.get_coordinate(1)
+          << " " << tb.get_coordinate(2) << std::endl);
+  return internal::evaluate_distance_pair_score(XYZDecorator(a),
+                                                tb,
+                                                da, f_.get(), 
+                                                boost::lambda::_1);
+}
+
+
+void TransformedDistancePairScore::set_rotation(float r00, float r01, float r02,
+                                                float r10, float r11, float r12,
+                                                float r20, float r21, float r22)
+{
+  // do in two steps in case inverse throws an exception
+  Vector3D v[3];
+  inverse(r00, r01, r02,
+          r10, r11, r12,
+          r20, r21, r22,
+          v);
+  r_[0]= Vector3D(r00, r01, r02);
+  r_[1]= Vector3D(r10, r11, r12);
+  r_[2]= Vector3D(r20, r21, r22);
+  ri_[0]= v[0];
+  ri_[1]= v[1];
+  ri_[2]= v[2];
+  IMP_LOG(VERBOSE, "Rotation is \n" << r_[0] << "\n" << r_[1] << "\n"
+          << r_[2] << "\nand inverse is \n"
+          << ri_[0] << "\n" << ri_[1] << "\n"
+          << ri_[2] << std::endl);
+}
+
+void TransformedDistancePairScore::set_translation(float t0, float t1, float t2)
+{
+  tc_= Vector3D(t0, t1, t2) + c_;
+}
+
+
+void TransformedDistancePairScore::set_center(float t0, float t1, float t2)
+{
+  tc_= tc_-c_;
+  c_= Vector3D(t0, t1, t2);
+  tc_= tc_+c_;
+}
+
+
+void TransformedDistancePairScore::show(std::ostream &out) const
+{
+  out << "TransformedDistancePairScore using ";
+  f_->show(out);
+}
+
+} // namespace IMP
Index: kernel/src/pair_scores/SphereDistancePairScore.cpp
===================================================================
--- kernel/src/pair_scores/SphereDistancePairScore.cpp	(revision 620)
+++ kernel/src/pair_scores/SphereDistancePairScore.cpp	(working copy)
@@ -8,6 +8,9 @@
 #include "IMP/pair_scores/SphereDistancePairScore.h"
 #include "IMP/UnaryFunction.h"
 #include "IMP/pair_scores/DistancePairScore.h"
+#include "IMP/decorators/XYZDecorator.h"
+#include "IMP/internal/evaluate_distance_pair_score.h"
+#include "boost/lambda/lambda.hpp"
 
 namespace IMP
 {
@@ -18,6 +21,13 @@
 {
 }
 
+struct Shift
+{
+  Float s_;
+  Shift(Float s): s_(s){}
+  Float operator()(Float t) const {return t-s_;}
+};
+
 Float SphereDistancePairScore::evaluate(Particle *a, Particle *b,
                                         DerivativeAccumulator *da)
 {
@@ -29,8 +39,10 @@
             ValueException);
   Float ra = a->get_value(radius_);
   Float rb = b->get_value(radius_);
-  return internal::evaluate_distance_pair_score(a,b, da, f_.get(), 
-                                                ra+rb, 1);
+  return internal::evaluate_distance_pair_score(XYZDecorator(a),
+                                                XYZDecorator(b),
+                                                da, f_.get(), 
+                                                boost::lambda::_1-(ra+rb));
 }
 
 void SphereDistancePairScore::show(std::ostream &out) const
Index: kernel/pyext/IMP.i
===================================================================
--- kernel/pyext/IMP.i	(revision 620)
+++ kernel/pyext/IMP.i	(working copy)
@@ -81,6 +81,9 @@
   %pythonprepend DistancePairScore::DistancePairScore %{
         args[0].thisown=0
   %}
+  %pythonprepend TransformedDistancePairScore::TransformedDistancePairScore %{
+        args[0].thisown=0
+  %}
   %pythonprepend BondCoverPairScore::BondCoverPairScore %{
         args[0].thisown=0
   %}
@@ -216,6 +219,7 @@
 %include "IMP/pair_scores/RefineOncePairScore.h"
 %include "IMP/pair_scores/SphereDistancePairScore.h"
 %include "IMP/pair_scores/TypedPairScore.h"
+%include "IMP/pair_scores/TransformedDistancePairScore.h"
 %include "IMP/particle_refiners/BondCoverParticleRefiner.h"
 %include "IMP/particle_refiners/ChildrenParticleRefiner.h"
 %include "IMP/singleton_scores/DistanceToSingletonScore.h"