diff --git a/src/analysis/AnalysisWithLandmarks.cpp b/src/analysis/AnalysisWithLandmarks.cpp
index 9d158790d7a917747c0128e5b5b232fcd779590c..32df489ef81ee3acbd4677d0629e7c01bb6f91be 100644
--- a/src/analysis/AnalysisWithLandmarks.cpp
+++ b/src/analysis/AnalysisWithLandmarks.cpp
@@ -71,7 +71,7 @@ void AnalysisWithLandmarks::performAnalysis(){
   analyzeLandmarks();
 }
 
-void AnalysisWithLandmarks::performTask(){
+void AnalysisWithLandmarks::performTask( const unsigned& taskIndex, const unsigned& current, vesselbase::MultiValue& myvals ){
   plumed_merror("Should not be here");
 }
 
diff --git a/src/analysis/AnalysisWithLandmarks.h b/src/analysis/AnalysisWithLandmarks.h
index 011998f70258b30431f5729000ac69b02580ba8b..bd9842ddd8e5ad488ee684671b545284440a3acc 100644
--- a/src/analysis/AnalysisWithLandmarks.h
+++ b/src/analysis/AnalysisWithLandmarks.h
@@ -53,7 +53,7 @@ public:
   void performAnalysis();
   virtual void analyzeLandmarks()=0;
 /// This does nothing
-  void performTask();
+  void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& );
 };
 
 }
diff --git a/src/analysis/Histogram.cpp b/src/analysis/Histogram.cpp
index 59f25dafd783f5c10e9daffe9c4f4c6193e8c230..a6fb5ff3ccaaa9bcc5ef9dc095276b947bbe9135 100644
--- a/src/analysis/Histogram.cpp
+++ b/src/analysis/Histogram.cpp
@@ -124,7 +124,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Histogram(const ActionOptions&ao);
   void performAnalysis();
-  void performTask();
+  void performTask(  const unsigned& , const unsigned& , vesselbase::MultiValue& );
 };
 
 PLUMED_REGISTER_ACTION(Histogram,"HISTOGRAM")
@@ -212,7 +212,7 @@ unnormalized(false)
   log.printf("\n");
 }
 
-void Histogram::performTask(){ plumed_error(); }
+void Histogram::performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& ){ plumed_error(); }
 
 void Histogram::performAnalysis(){
   // Back up old histogram files
diff --git a/src/crystallization/DFSClustering.cpp b/src/crystallization/DFSClustering.cpp
index 193cf84c19aa77cd7a3147a188e4bf19cfba19d1..26f5e7aa105d7f91c6f6dc818e0e79efd5acf5c0 100644
--- a/src/crystallization/DFSClustering.cpp
+++ b/src/crystallization/DFSClustering.cpp
@@ -41,8 +41,6 @@ private:
   unsigned clustr;
 /// Used to identify the cluster we are working on 
   int number_of_cluster;
-/// The values from the underlying colvar
-  std::vector<double> myvals;
 /// The number of neighbors each atom has
   std::vector<unsigned> nneigh;
 /// The adjacency list
@@ -68,7 +66,7 @@ public:
   void completeCalculation();
 /// Derivatives of elements of adjacency matrix are unimportant.  We thus
 /// overwrite this routine as this makes the code faster
-  void updateActiveAtoms(){}
+  void updateActiveAtoms( multicolvar::AtomValuePack& myatoms ){}
 };
 
 PLUMED_REGISTER_ACTION(DFSClustering,"DFSCLUSTERING")
@@ -100,8 +98,6 @@ color(getFullNumberOfBaseTasks())
    if( clustr<1 ) error("cannot look for a cluster larger than the largest cluster");
    if( clustr>getFullNumberOfBaseTasks() ) error("cluster selected is invalid - too few atoms in system");
 
-   // Set myvals size equal to number of components in vector + 1 (for norm)
-   myvals.resize( getBaseMultiColvar(0)->getNumberOfQuantities() - 4 );
    // Setup the various things this will calculate
    readVesselKeywords(); 
 }
@@ -150,31 +146,25 @@ void DFSClustering::completeCalculation(){
    }
    unsigned size=comm.Get_size(), rank=comm.Get_rank();
 
-//   for(unsigned i=0;i<cluster_sizes.size();++i) printf("HELLO CLUSTER %d %d \n",i,cluster_sizes[i].first );
    // Now calculate properties of the largest cluster 
    ActionWithVessel::doJobsRequiredBeforeTaskList();  // Note we loose adjacency data by doing this
    // Get size for buffer
    unsigned bsize=0; std::vector<double> buffer( getSizeOfBuffer( bsize ), 0.0 );
+   std::vector<double> vals( getNumberOfQuantities() );
+   vesselbase::MultiValue myvals( getNumberOfQuantities(), getNumberOfDerivatives() );
+   vesselbase::MultiValue bvals( getNumberOfQuantities(), getNumberOfDerivatives() );
    // Get rid of bogus derivatives
    clearDerivatives(); getAdjacencyVessel()->setFinishedTrue(); 
    for(unsigned j=rank;j<myatoms.size();j+=size){
        // Note loop above over array containing atoms so this is load balanced
        unsigned i=myatoms[j];
        // Need to copy values from base action
-       extractValueForBaseTask( i, myvals );
-       //  getValueForBaseTask( i, myvals );
-       setElementValue(0, myvals[0] ); setElementValue(1, 1.0 );
-       for(unsigned i=0;i<myvals.size()-1;++i) setElementValue(2+i, myvals[1+i] );
-       // Prepare dynamic lists
-       atoms_with_derivatives.deactivateAll();
-       // Copy derivatives from base action
-       extractWeightedAverageAndDerivatives( i, 1.0 ); 
-       // Update all dynamic lists
-       atoms_with_derivatives.updateActiveMembers();
+       getVectorForTask( i, false, vals );
+       for(unsigned i=0;i<vals.size();++i) myvals.setValue( i, vals[i] );
+       if( !doNotCalculateDerivatives() ) getVectorDerivatives( i, false, myvals );
        // Run calculate all vessels
-       calculateAllVessels( buffer );
-       // Must clear element values and derivatives
-       clearAfterTask();
+       calculateAllVessels( i, myvals, bvals, buffer );
+       myvals.clearAll();
    }
    // MPI Gather everything
    if( buffer.size()>0 ) comm.Sum( buffer );
diff --git a/src/crystallization/Fccubic.cpp b/src/crystallization/Fccubic.cpp
index b3e569e8c5c8ff58575315f8468c771e8cb10919..a7d40a05e8743a93c805826e00e97f8b6f59c116 100644
--- a/src/crystallization/Fccubic.cpp
+++ b/src/crystallization/Fccubic.cpp
@@ -47,8 +47,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Fccubic(const ActionOptions&);
 // active methods:
-  virtual double compute(); 
-  Vector getCentralAtom();
+  virtual double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ); 
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
 };
@@ -96,15 +95,14 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double Fccubic::compute(){
-   weightHasDerivatives=true;
+double Fccubic::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ){
    double value=0, norm=0, dfunc; Vector distance;
 
    // Calculate the coordination number
    Vector myder, fder;
    double sw, t0, t1, t2, t3, x2, x4, y2, y4, z2, z4, r8, tmp;
-   for(unsigned i=1;i<getNAtoms();++i){
-      distance=getSeparation( getPosition(0), getPosition(i) );
+   for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+      distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) );
       double d2 = distance.modulo2();
       if( d2<rcut2 ){ 
          sw = switchingFunction.calculateSqr( d2, dfunc ); 
@@ -137,29 +135,24 @@ double Fccubic::compute(){
   
          fder = (+dfunc)*tmp*distance + sw*myder;
 
-         addAtomsDerivatives( 0, -fder );
-         addAtomsDerivatives( i, +fder );
-         addBoxDerivatives( Tensor(distance,-fder) );
-         addAtomsDerivativeOfWeight( 0, (-dfunc)*distance );
-         addAtomsDerivativeOfWeight( i, (+dfunc)*distance );
-         addBoxDerivativesOfWeight( (-dfunc)*Tensor(distance,distance) );
+         myatoms.addAtomsDerivatives( 1, 0, -fder );
+         myatoms.addAtomsDerivatives( 1, i, +fder );
+         myatoms.addBoxDerivatives( 1, Tensor(distance,-fder) );
+         myatoms.addAtomsDerivatives( 0, 0, (-dfunc)*distance );
+         myatoms.addAtomsDerivatives( 0, i, (+dfunc)*distance );
+         myatoms.addBoxDerivatives( 0, (-dfunc)*Tensor(distance,distance) );
       }
    }
    
-   setElementValue(0, value); setElementValue(1, norm ); 
+   myatoms.setValue(1, value); myatoms.setValue(0, norm ); 
    // values -> der of... value [0], weight[1], x coord [2], y, z... [more magic]
-   updateActiveAtoms(); quotientRule( 0, 1, 0 ); clearDerivativesAfterTask(1);
+   updateActiveAtoms( myatoms ); myatoms.getUnderlyingMultiValue().quotientRule( 1, 0, 1 );   
    // Weight doesn't really have derivatives (just use the holder for convenience)
-   weightHasDerivatives=false; setElementValue( 1, 1.0 );
+   myatoms.getUnderlyingMultiValue().clear(0); myatoms.setValue( 0, 1.0 );
 
    return value / norm; // this is equivalent to getting an "atomic" CV
 }
 
-Vector Fccubic::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
 
diff --git a/src/crystallization/Gradient.cpp b/src/crystallization/Gradient.cpp
index a33b937252fae17267281ec45585039f9ec45965..498664c3ab45b829d6e16eef27a02bbbde4db79f 100644
--- a/src/crystallization/Gradient.cpp
+++ b/src/crystallization/Gradient.cpp
@@ -79,9 +79,9 @@ nbins(3)
   }
 
   // Find number of quantities
-  if( getPntrToMultiColvar()->isDensity() ) vend=1;
-  else if( getPntrToMultiColvar()->getNumberOfQuantities()==5 ) vend=1;
-  else vend= 1 + getPntrToMultiColvar()->getNumberOfQuantities()-5; // +1 is for weight 
+  if( getPntrToMultiColvar()->isDensity() ) vend=2;
+  else if( getPntrToMultiColvar()->getNumberOfQuantities()==2 ) vend=2;
+  else vend = getPntrToMultiColvar()->getNumberOfQuantities();  
   nquantities = vend + nbins[0] + nbins[1] + nbins[2];
 
   // Output some nice information
@@ -100,19 +100,16 @@ nbins(3)
   finishTaskListUpdate();
 }
 
-unsigned Gradient::getCentralAtomElementIndex(){
-  plumed_error();
-}
-
 void Gradient::setupRegions(){
 //  if( !getPbc().isOrthorombic() ) error("cell must be orthorhombic when using gradient");
 }
 
-void Gradient::calculateAllVolumes(){
-  Vector cpos = pbcDistance( getPosition(0), getPntrToMultiColvar()->retrieveCentralAtomPos() );
-  Vector oderiv, fpos = getPbc().realToScaled( cpos );  
+void Gradient::calculateAllVolumes( const unsigned& curr, vesselbase::MultiValue& outvals ){
+  Vector cpos = pbcDistance( getPosition(0), getPntrToMultiColvar()->getCentralAtomPos( curr ) );
+  // Note we use the pbc from base multicolvar so that we get numerical derivatives correct
+  Vector oderiv, fpos = (getPntrToMultiColvar()->getPbc()).realToScaled( cpos );  
   
-  Vector deriv; unsigned nbase=vend;
+  Vector deriv; unsigned nbase=vend; std::vector<Vector> refder(1); Tensor vir; vir.zero();
   for(unsigned idir=0;idir<3;++idir){
       deriv[0]=deriv[1]=deriv[2]=0.0;
       double delx = 1.0 / static_cast<double>( nbins[idir] );
@@ -120,10 +117,11 @@ void Gradient::calculateAllVolumes(){
           // Calculate what box we are in
           bead.set( -0.5+jbead*delx, -0.5+(jbead+1)*delx, sigma );
           double weight=bead.calculate( fpos[0], deriv[idir] );
-          oderiv = getPbc().realToScaled( deriv );          
+          oderiv = (getPntrToMultiColvar()->getPbc()).realToScaled( deriv );          
           // Set and derivatives
-          setNumberInVolume( nbase+jbead, weight, oderiv ); 
-          addReferenceAtomDerivatives( nbase+jbead, 0, -oderiv );
+          refder[0]=-oderiv; // vir = -Tensor(cpos,oderiv);
+          setNumberInVolume( nbase+jbead, curr, weight, oderiv, vir, refder, outvals ); 
+//          addReferenceAtomDerivatives( nbase+jbead, 0, -oderiv );
 //          addBoxDerivatives( nbase+jbead, -Tensor(cpos,oderiv) );
       }
       nbase += nbins[idir];
diff --git a/src/crystallization/Gradient.h b/src/crystallization/Gradient.h
index 80be920dc845b805e6c578253c9a715297edde02..b16d0376d9d5dceb29675a01e0892136aee328b8 100644
--- a/src/crystallization/Gradient.h
+++ b/src/crystallization/Gradient.h
@@ -43,14 +43,10 @@ public:
   Gradient(const ActionOptions&);
 /// Get the number of quantities that are calculated each time
   virtual unsigned getNumberOfQuantities();
-/// This just throws an error
-  unsigned getCentralAtomElementIndex(); 
 /// Check on pbc - is it orthorhombic
   void setupRegions();
 /// Calculate whats in the volume
-  void calculateAllVolumes();
-  double getValueForTolerance();
-  unsigned getIndexOfWeight();
+  void calculateAllVolumes( const unsigned& curr, vesselbase::MultiValue& outvals );
 };
 
 inline
@@ -58,17 +54,6 @@ unsigned Gradient::getNumberOfQuantities(){
   return nquantities;
 } 
 
-inline
-double Gradient::getValueForTolerance(){
-  return 1.0;
-}
-
-inline
-unsigned Gradient::getIndexOfWeight(){
-  plumed_error();
-  return 1;
-}
-
 }
 }
 #endif
diff --git a/src/crystallization/GradientVessel.cpp b/src/crystallization/GradientVessel.cpp
index ba2466bb1a11ecbd3d7e134b3706220e1f94442b..0f2d6372dbfebd5719bac50621cdfc11e52120f7 100644
--- a/src/crystallization/GradientVessel.cpp
+++ b/src/crystallization/GradientVessel.cpp
@@ -34,15 +34,15 @@ private:
   bool isdens;
   unsigned nweights, ncomponents;
   std::vector<unsigned> starts;
-  std::vector<double> val_interm;
-  Matrix<double> der_interm;
+//  std::vector<double> val_interm;
+//  Matrix<double> der_interm;
 public:
   static void registerKeywords( Keywords& keys );
   static void reserveKeyword( Keywords& keys );
   GradientVessel( const vesselbase::VesselOptions& da );
   std::string function_description();
   void resize();
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer );
   void finish( const std::vector<double>& buffer );
 };
 
@@ -63,7 +63,12 @@ FunctionVessel(da)
    Gradient* vg=dynamic_cast<Gradient*>( getAction() );
    plumed_assert( vg ); isdens=(vg->getPntrToMultiColvar())->isDensity();
    nweights = vg->nbins[0] + vg->nbins[1] + vg->nbins[2];
-   ncomponents = vg->vend;
+   if( (vg->getPntrToMultiColvar())->getNumberOfQuantities()>2 ){
+       ncomponents = (vg->getPntrToMultiColvar())->getNumberOfQuantities() - 2; 
+   } else {
+       ncomponents = 1;
+   }
+   // ncomponents = vg->vend;
 
    starts.push_back(0);
    if( vg->nbins[0]>0 ){
@@ -91,29 +96,34 @@ void GradientVessel::resize(){
      unsigned nder=getAction()->getNumberOfDerivatives();
      resizeBuffer( (1+nder)*(ncomponents+1)*nweights );
      setNumberOfDerivatives( nder );
-     val_interm.resize( ncomponents*nweights );
-     der_interm.resize( ncomponents*nweights, nder );
+//     val_interm.resize( ncomponents*nweights );
+//     der_interm.resize( ncomponents*nweights, nder );
   } else {
      setNumberOfDerivatives(0); 
      resizeBuffer( (ncomponents+1)*nweights );
-     val_interm.resize( ncomponents*nweights );
+//     val_interm.resize( ncomponents*nweights );
   }
 }
 
-bool GradientVessel::calculate( std::vector<double>& buffer ){
+bool GradientVessel::calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer ){
   unsigned nder=getAction()->getNumberOfDerivatives();
+  unsigned wstart, cstart; if( ncomponents==1 ){ cstart=1; wstart=2; } else { cstart=2; wstart=2+ncomponents; }
+
   for(unsigned iw=0;iw<nweights;++iw){
       unsigned xx = (ncomponents+1)*iw;
-      double weight=getAction()->getElementValue(ncomponents + iw);
+      double weight=myvals.get(wstart+iw); // getAction()->getElementValue(ncomponents + iw);
       buffer[bufstart+xx*(nder+1)] += weight;
+      myvals.chainRule( wstart + iw, xx, 1, 0, 1.0, bufstart, buffer );
       // addValueIgnoringTolerance( xx, weight ); 
-      getAction()->chainRuleForElementDerivatives( xx , ncomponents + iw, 1.0, bufstart, buffer );
+      // getAction()->chainRuleForElementDerivatives( xx , ncomponents + iw, 1.0, bufstart, buffer );
       for(unsigned jc=0;jc<ncomponents;++jc){
-          double colvar=getAction()->getElementValue( jc );
+          double colvar=myvals.get( cstart + jc );   // getAction()->getElementValue( jc );
           // addValueIgnoringTolerance( xx + 1 + jc, weight*colvar );
           buffer[bufstart+(xx+1+jc)*(nder+1) ] += weight*colvar;
-          getAction()->chainRuleForElementDerivatives( xx + 1 + jc, jc, weight, bufstart, buffer );
-          getAction()->chainRuleForElementDerivatives( xx + 1 + jc, ncomponents + iw, colvar, bufstart, buffer );   
+          myvals.chainRule( cstart + jc, xx + 1 + jc, 1, 0, weight, bufstart, buffer );
+          myvals.chainRule( wstart + iw, xx + 1 + jc, 1, 0, colvar, bufstart, buffer );
+          // getAction()->chainRuleForElementDerivatives( xx + 1 + jc, jc, weight, bufstart, buffer );
+          // getAction()->chainRuleForElementDerivatives( xx + 1 + jc, ncomponents + iw, colvar, bufstart, buffer );   
       }
   }
 
@@ -121,14 +131,15 @@ bool GradientVessel::calculate( std::vector<double>& buffer ){
 }
 
 void GradientVessel::finish( const std::vector<double>& buffer ){
-  der_interm=0;  // Clear all interim derivatives
+  std::vector<double> val_interm( ncomponents*nweights );
   unsigned nder = getAction()->getNumberOfDerivatives();
+  Matrix<double> der_interm( ncomponents*nweights, nder ); der_interm=0;
 
   if( isdens ){
       for(unsigned iw=0;iw<nweights;++iw){
           val_interm[iw] = buffer[bufstart + 2*iw*(1+nder)]; // getFinalValue( 2*iw );
           if( getAction()->derivativesAreRequired() ){
-              unsigned wstart = 2*iw*(nder+1) + 1;
+              unsigned wstart = bufstart + 2*iw*(nder+1) + 1;
               for(unsigned jder=0;jder<nder;++jder) der_interm( iw, jder ) += buffer[ wstart + jder ]; // getBufferElement( wstart + jder );
           }
       }
@@ -136,7 +147,7 @@ void GradientVessel::finish( const std::vector<double>& buffer ){
       for(unsigned iw=0;iw<nweights;++iw){
           unsigned xx = (ncomponents+1)*iw;
           double ww=buffer[bufstart + xx*(1+nder)];  // getFinalValue( xx );
-          for(unsigned jc=0;jc<ncomponents;++jc) val_interm[ iw*ncomponents + jc ] = buffer[bufstart + (xx+1+jc)*(1+nder)]; //getFinalValue( xx + 1 + jc ) / ww;
+          for(unsigned jc=0;jc<ncomponents;++jc) val_interm[ iw*ncomponents + jc ] = buffer[bufstart + (xx+1+jc)*(1+nder)] / ww; //getFinalValue( xx + 1 + jc ) / ww;
           if( getAction()->derivativesAreRequired() ){
               unsigned wstart = bufstart + xx*(nder+1) + 1;
               for(unsigned jc=0;jc<ncomponents;++jc){
diff --git a/src/crystallization/MoleculeOrientation.cpp b/src/crystallization/MoleculeOrientation.cpp
index 01e7aa08028295c3f52691c71caaf4a99e7ba02a..9517bd0ca6b8a50ba2c584fc0439af62bd4c002e 100644
--- a/src/crystallization/MoleculeOrientation.cpp
+++ b/src/crystallization/MoleculeOrientation.cpp
@@ -54,8 +54,7 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   MoleculeOrientation( const ActionOptions& ao );
-  void calculateVector();
-  Vector getCentralAtom();
+  void calculateVector( multicolvar::AtomValuePack& myatoms );
 };
 
 PLUMED_REGISTER_ACTION(MoleculeOrientation,"MOLECULES")
@@ -80,40 +79,45 @@ VectorMultiColvar(ao)
   if( all_atoms.size()==0 ) error("No atoms were specified");
   ActionAtomistic::requestAtoms( all_atoms );
 
-  setVectorDimensionality( 3, false, natoms );
+  setVectorDimensionality( 3, natoms );
+
+  if( natoms==3 ){
+    std::vector<bool> catom_ind(3, false); catom_ind[2]=true;
+    setAtomsForCentralAtom( catom_ind );
+  } 
 }
 
-void MoleculeOrientation::calculateVector(){
-  Vector distance; distance=getSeparation( getPosition(0), getPosition(1) );
+void MoleculeOrientation::calculateVector( multicolvar::AtomValuePack& myatoms ){
+  Vector distance; distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
 
-  addAtomsDerivative( 0, 0, Vector(-1.0,0,0) ); 
-  addAtomsDerivative( 0, 1, Vector(+1.0,0,0) ); 
-  addBoxDerivatives( 0, Tensor(distance,Vector(-1.0,0,0)) ); 
-  addComponent( 0, distance[0] ); 
+  myatoms.addAtomsDerivatives( 2, 0, Vector(-1.0,0,0) ); 
+  myatoms.addAtomsDerivatives( 2, 1, Vector(+1.0,0,0) ); 
+  myatoms.addBoxDerivatives( 2, Tensor(distance,Vector(-1.0,0,0)) ); 
+  myatoms.addValue( 2, distance[0] ); 
 
-  addAtomsDerivative( 1, 0, Vector(0,-1.0,0) ); 
-  addAtomsDerivative( 1, 1, Vector(0,+1.0,0) ); 
-  addBoxDerivatives( 1, Tensor(distance,Vector(0,-1.0,0)) ); 
-  addComponent( 1, distance[1] ); 
+  myatoms.addAtomsDerivatives( 3, 0, Vector(0,-1.0,0) ); 
+  myatoms.addAtomsDerivatives( 3, 1, Vector(0,+1.0,0) ); 
+  myatoms.addBoxDerivatives( 3, Tensor(distance,Vector(0,-1.0,0)) ); 
+  myatoms.addValue( 3, distance[1] ); 
 
-  addAtomsDerivative( 2, 0, Vector(0,0,-1.0) ); 
-  addAtomsDerivative( 2, 1, Vector(0,0,+1.0) ); 
-  addBoxDerivatives( 2, Tensor(distance,Vector(0,0,-1.0)) ); 
-  addComponent( 2, distance[2] ); 
+  myatoms.addAtomsDerivatives( 4, 0, Vector(0,0,-1.0) ); 
+  myatoms.addAtomsDerivatives( 4, 1, Vector(0,0,+1.0) ); 
+  myatoms.addBoxDerivatives( 4, Tensor(distance,Vector(0,0,-1.0)) ); 
+  myatoms.addValue( 4, distance[2] ); 
 }
 
-Vector MoleculeOrientation::getCentralAtom(){
-  if( getNAtoms()==2 ){
-      Vector com; com.zero();
-      com+=0.5*getPosition(0);
-      com+=0.5*getPosition(1);
-      addCentralAtomDerivatives( 0, 0.5*Tensor::identity() );
-      addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
-      return com;
-  } 
-  addCentralAtomDerivatives( 2, Tensor::identity() );
-  return getPosition(2);
-}
+// Vector MoleculeOrientation::getCentralAtom(){
+//   if( getNAtoms()==2 ){
+//       Vector com; com.zero();
+//       com+=0.5*getPosition(0);
+//       com+=0.5*getPosition(1);
+//       addCentralAtomDerivatives( 0, 0.5*Tensor::identity() );
+//       addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
+//       return com;
+//   } 
+//   addCentralAtomDerivatives( 2, Tensor::identity() );
+//   return getPosition(2);
+// }
 
 }
 }
diff --git a/src/crystallization/MoleculePlane.cpp b/src/crystallization/MoleculePlane.cpp
index 71baafd501aa98ebfaefdb2cb97335661ac3ab63..b38129161bcc46b792fff08698136c1da69a512e 100644
--- a/src/crystallization/MoleculePlane.cpp
+++ b/src/crystallization/MoleculePlane.cpp
@@ -41,8 +41,7 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   MoleculePlane( const ActionOptions& ao );
-  void calculateVector();
-  Vector getCentralAtom();
+  void calculateVector( multicolvar::AtomValuePack& myatoms );
 };
 
 PLUMED_REGISTER_ACTION(MoleculePlane,"PLANES")
@@ -69,78 +68,78 @@ VectorMultiColvar(ao)
   if( all_atoms.size()==0 ) error("No atoms were specified");
   ActionAtomistic::requestAtoms( all_atoms );
 
-  setVectorDimensionality( 3, false, natoms );
+  setVectorDimensionality( 3, natoms );
 }
 
-void MoleculePlane::calculateVector(){
+void MoleculePlane::calculateVector( multicolvar::AtomValuePack& myatoms ){
   Vector d1, d2, cp; 
-  if( getNAtoms()==3 ){
-     d1=getSeparation( getPosition(1), getPosition(0) );
-     d2=getSeparation( getPosition(1), getPosition(2) ); 
+  if( myatoms.getNumberOfAtoms()==3 ){
+     d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) );
+     d2=getSeparation( myatoms.getPosition(1), myatoms.getPosition(2) ); 
   } else {
-     d1=getSeparation( getPosition(1), getPosition(0) );
-     d2=getSeparation( getPosition(2), getPosition(3) );
+     d1=getSeparation( myatoms.getPosition(1), myatoms.getPosition(0) );
+     d2=getSeparation( myatoms.getPosition(2), myatoms.getPosition(3) );
   }
   cp = crossProduct( d1, d2 );
 
-  addAtomsDerivative( 0, 0, crossProduct( Vector(-1.0,0,0), d2 ) );
-  if( getNAtoms()==3 ){
-     addAtomsDerivative( 0, 1, crossProduct( Vector(+1.0,0,0), d2 ) + crossProduct( Vector(-1.0,0,0), d1 ) );
-     addAtomsDerivative( 0, 2, crossProduct( Vector(+1.0,0,0), d1 ) );
+  myatoms.addAtomsDerivatives( 2, 0, crossProduct( Vector(-1.0,0,0), d2 ) );
+  if( myatoms.getNumberOfAtoms()==3 ){
+     myatoms.addAtomsDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ) + crossProduct( Vector(-1.0,0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 2, 2, crossProduct( Vector(+1.0,0,0), d1 ) );
   } else {
-     addAtomsDerivative( 0, 1, crossProduct( Vector(+1.0,0,0), d2 ) ); 
-     addAtomsDerivative( 0, 2, crossProduct( Vector(-1.0,0,0), d1 ) );
-     addAtomsDerivative( 0, 3, crossProduct( Vector(+1.0,0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 2, 1, crossProduct( Vector(+1.0,0,0), d2 ) ); 
+     myatoms.addAtomsDerivatives( 2, 2, crossProduct( Vector(-1.0,0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 2, 3, crossProduct( Vector(+1.0,0,0), d1 ) );
   }
-  addBoxDerivatives( 0, Tensor(d1,crossProduct(Vector(+1.0,0,0), d2)) + Tensor( d2, crossProduct(Vector(-1.0,0,0), d1)) );
-  addComponent( 0, cp[0] );
+  myatoms.addBoxDerivatives( 2, Tensor(d1,crossProduct(Vector(+1.0,0,0), d2)) + Tensor( d2, crossProduct(Vector(-1.0,0,0), d1)) );
+  myatoms.addValue( 2, cp[0] );
 
-  addAtomsDerivative( 1, 0, crossProduct( Vector(0,-1.0,0), d2 ) );
-  if( getNAtoms()==3 ){
-     addAtomsDerivative( 1, 1, crossProduct( Vector(0,+1.0,0), d2 ) + crossProduct( Vector(0,-1.0,0), d1 ) );
-     addAtomsDerivative( 1, 2, crossProduct( Vector(0,+1.0,0), d1 ) );
+  myatoms.addAtomsDerivatives( 3, 0, crossProduct( Vector(0,-1.0,0), d2 ) );
+  if( myatoms.getNumberOfAtoms()==3 ){
+     myatoms.addAtomsDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ) + crossProduct( Vector(0,-1.0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 3, 2, crossProduct( Vector(0,+1.0,0), d1 ) );
   } else {
-     addAtomsDerivative( 1, 1, crossProduct( Vector(0,+1.0,0), d2 ) ); 
-     addAtomsDerivative( 1, 2, crossProduct( Vector(0,-1.0,0), d1 ) );
-     addAtomsDerivative( 1, 3, crossProduct( Vector(0,+1.0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 3, 1, crossProduct( Vector(0,+1.0,0), d2 ) ); 
+     myatoms.addAtomsDerivatives( 3, 2, crossProduct( Vector(0,-1.0,0), d1 ) );
+     myatoms.addAtomsDerivatives( 3, 3, crossProduct( Vector(0,+1.0,0), d1 ) );
   }
-  addBoxDerivatives( 1, Tensor(d1,crossProduct(Vector(0,+1.0,0), d2)) + Tensor( d2, crossProduct(Vector(0,-1.0,0), d1)) );
-  addComponent( 1, cp[1] );
+  myatoms.addBoxDerivatives( 3, Tensor(d1,crossProduct(Vector(0,+1.0,0), d2)) + Tensor( d2, crossProduct(Vector(0,-1.0,0), d1)) );
+  myatoms.addValue( 3, cp[1] );
 
-  addAtomsDerivative( 2, 0, crossProduct( Vector(0,0,-1.0), d2 ) );
-  if( getNAtoms()==3 ){
-     addAtomsDerivative( 2, 1, crossProduct( Vector(0,0,+1.0), d2 ) + crossProduct( Vector(0,0,-1.0), d1 ) );
-     addAtomsDerivative( 2, 2, crossProduct( Vector(0,0,+1.0), d1 ) );
+  myatoms.addAtomsDerivatives( 4, 0, crossProduct( Vector(0,0,-1.0), d2 ) );
+  if( myatoms.getNumberOfAtoms()==3 ){
+     myatoms.addAtomsDerivatives( 4, 1, crossProduct( Vector(0,0,+1.0), d2 ) + crossProduct( Vector(0,0,-1.0), d1 ) );
+     myatoms.addAtomsDerivatives( 4, 2, crossProduct( Vector(0,0,+1.0), d1 ) );
   } else {
-     addAtomsDerivative( 2, 1, crossProduct( Vector(0,0,-1.0), d2 ) ); 
-     addAtomsDerivative( 2, 2, crossProduct( Vector(0,0,-1.0), d1 ) );
-     addAtomsDerivative( 2, 3, crossProduct( Vector(0,0,+1.0), d1 ) );
+     myatoms.addAtomsDerivatives( 4, 1, crossProduct( Vector(0,0,-1.0), d2 ) ); 
+     myatoms.addAtomsDerivatives( 4, 2, crossProduct( Vector(0,0,-1.0), d1 ) );
+     myatoms.addAtomsDerivatives( 4, 3, crossProduct( Vector(0,0,+1.0), d1 ) );
   }
-  addBoxDerivatives( 2, Tensor(d1,crossProduct(Vector(0,0,+1.0), d2)) + Tensor( d2, crossProduct(Vector(0,0,-1.0), d1)) );
-  addComponent( 2, cp[2] );
+  myatoms.addBoxDerivatives( 4, Tensor(d1,crossProduct(Vector(0,0,+1.0), d2)) + Tensor( d2, crossProduct(Vector(0,0,-1.0), d1)) );
+  myatoms.addValue( 4, cp[2] );
 }
 
-Vector MoleculePlane::getCentralAtom(){
-  Vector com; com.zero(); 
-  if( getNAtoms()==3 ){
-      com+=(1.0/3.0)*getPosition(0);
-      com+=(1.0/3.0)*getPosition(1);
-      com+=(1.0/3.0)*getPosition(2);
-      addCentralAtomDerivatives( 0, (1.0/3.0)*Tensor::identity() );
-      addCentralAtomDerivatives( 1, (1.0/3.0)*Tensor::identity() );
-      addCentralAtomDerivatives( 2, (1.0/3.0)*Tensor::identity() );
-      return com;
-  }
-  com+=0.25*getPosition(0);
-  com+=0.25*getPosition(1);
-  com+=0.25*getPosition(2);
-  com+=0.25*getPosition(3);
-  addCentralAtomDerivatives( 0, 0.25*Tensor::identity() );
-  addCentralAtomDerivatives( 1, 0.25*Tensor::identity() );
-  addCentralAtomDerivatives( 2, 0.25*Tensor::identity() );
-  addCentralAtomDerivatives( 3, 0.25*Tensor::identity() );
-  return com;
-}
+// Vector MoleculePlane::getCentralAtom(){
+//   Vector com; com.zero(); 
+//   if( getNAtoms()==3 ){
+//       com+=(1.0/3.0)*getPosition(0);
+//       com+=(1.0/3.0)*getPosition(1);
+//       com+=(1.0/3.0)*getPosition(2);
+//       addCentralAtomDerivatives( 0, (1.0/3.0)*Tensor::identity() );
+//       addCentralAtomDerivatives( 1, (1.0/3.0)*Tensor::identity() );
+//       addCentralAtomDerivatives( 2, (1.0/3.0)*Tensor::identity() );
+//       return com;
+//   }
+//   com+=0.25*getPosition(0);
+//   com+=0.25*getPosition(1);
+//   com+=0.25*getPosition(2);
+//   com+=0.25*getPosition(3);
+//   addCentralAtomDerivatives( 0, 0.25*Tensor::identity() );
+//   addCentralAtomDerivatives( 1, 0.25*Tensor::identity() );
+//   addCentralAtomDerivatives( 2, 0.25*Tensor::identity() );
+//   addCentralAtomDerivatives( 3, 0.25*Tensor::identity() );
+//   return com;
+// }
 
 }
 }
diff --git a/src/crystallization/OrientationSphere.cpp b/src/crystallization/OrientationSphere.cpp
index 34c3554bf630c8bbc432df09c7727726ea9f4e56..a6d8042b881c795b5fe48d6032eb0e38f231e564 100644
--- a/src/crystallization/OrientationSphere.cpp
+++ b/src/crystallization/OrientationSphere.cpp
@@ -45,15 +45,6 @@ OrientationSphere::OrientationSphere(const ActionOptions&ao):
 Action(ao),
 MultiColvarFunction(ao)
 {
-  // Resize everything that stores a vector now that we know the 
-  // number of components
-  unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities() - 5;
-  catom_orient.resize( ncomponents ); 
-  catom_der.resize( ncomponents );
-  this_orient.resize( ncomponents ); 
-
-  // Weight of this does not have derivatives
-  weightHasDerivatives=false;
   // Read in the switching function
   std::string sw, errors; parse("SWITCH",sw);
   if(sw.length()>0){
@@ -74,63 +65,70 @@ MultiColvarFunction(ao)
   buildSymmetryFunctionLists();
 }
 
-void OrientationSphere::calculateWeight(){
-  weightHasDerivatives=true;   // The weight has no derivatives really
-  setElementValue(1,1.0);
-} 
-
-double OrientationSphere::compute(){
+double OrientationSphere::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ){
    // Make sure derivatives for central atom are only calculated once
    VectorMultiColvar* vv = dynamic_cast<VectorMultiColvar*>( getBaseMultiColvar(0) );
    vv->firstcall=true;
 
-   weightHasDerivatives=true;   // The weight has no derivatives really
    double d2, sw, value=0, denom=0, dot, f_dot, dot_df, dfunc; Vector distance;
+   unsigned ncomponents=getBaseMultiColvar(0)->getNumberOfQuantities();
+   unsigned nder=getNumberOfDerivatives();
+   std::vector<double> catom_orient( ncomponents ), this_orient( ncomponents ), catom_der( ncomponents ); 
+
+   Vector catom_pos = myatoms.getPosition(0);
+   getVectorForTask( myatoms.getIndex(0), true, catom_orient );
+   multicolvar::CatomPack atom0; 
+   vesselbase::MultiValue myder0(ncomponents,nder), myder1(ncomponents,nder); 
+   if( !doNotCalculateDerivatives() ){
+       atom0=getCentralAtomPackFromInput( myatoms.getIndex(0) );
+       getVectorDerivatives( myatoms.getIndex(0), true, myder0 );
+   }
 
-   getVectorForBaseTask(0, catom_orient );
-   for(unsigned i=1;i<getNAtoms();++i){
-      distance=getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(i) );
+   for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+      distance=getSeparation( catom_pos, myatoms.getPosition(i) );
       d2 = distance.modulo2();
       if( d2<rcut2 ){ 
          sw = switchingFunction.calculateSqr( d2, dfunc );  
  
-         getVectorForBaseTask( i, this_orient );
+         getVectorForTask( myatoms.getIndex(i), true, this_orient );
          // Calculate the dot product wrt to this position 
-         dot=0; for(unsigned k=0;k<catom_orient.size();++k) dot+=catom_orient[k]*this_orient[k];  
+         dot=0; for(unsigned k=2;k<catom_orient.size();++k) dot+=catom_orient[k]*this_orient[k];  
          f_dot = transformDotProduct( dot, dot_df ); 
-         // N.B. We are assuming here that the imaginary part of the dot product is zero
-         for(unsigned k=0;k<catom_orient.size();++k){
-            this_orient[k]*=sw*dot_df; catom_der[k]=sw*dot_df*catom_orient[k];
-         }  
-
-         // Set the derivatives wrt of the numerator
-         addOrientationDerivatives( 0, this_orient ); 
-         addOrientationDerivatives( i, catom_der );  
-         addCentralAtomsDerivatives( 0, 0, f_dot*(-dfunc)*distance );
-         addCentralAtomsDerivatives( i, 0, f_dot*(dfunc)*distance );
-         addBoxDerivatives( f_dot*(-dfunc)*Tensor(distance,distance) );
+
+         if( !doNotCalculateDerivatives() ){
+             // N.B. We are assuming here that the imaginary part of the dot product is zero
+             for(unsigned k=2;k<catom_orient.size();++k){
+                 this_orient[k]*=sw*dot_df; catom_der[k]=sw*dot_df*catom_orient[k];
+             }
+             getVectorDerivatives( myatoms.getIndex(i), true, myder1 );
+             mergeVectorDerivatives( 1, 2, this_orient.size(), myatoms.getIndex(0), this_orient, myder0, myatoms );  
+             mergeVectorDerivatives( 1, 2, catom_der.size(), myatoms.getIndex(i), catom_der, myder1, myatoms );
+             myatoms.addComDerivatives( 1, f_dot*(-dfunc)*distance, atom0 );
+             multicolvar::CatomPack atom1=getCentralAtomPackFromInput( myatoms.getIndex(i) );
+             myatoms.addComDerivatives( 1, f_dot*(dfunc)*distance, atom1 );
+             myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) );
+             myder1.clearAll();
+              
+             myatoms.addComDerivatives( 0, (-dfunc)*distance, atom0 );
+             myatoms.addComDerivatives( 0, (dfunc)*distance, atom1  );
+             myatoms.addBoxDerivatives( 0, (-dfunc)*Tensor(distance,distance) );
+
+         }
          value += sw*f_dot;
-         // Set the derivatives wrt to the numerator
-         addCentralAtomsDerivatives( 0, 1, (-dfunc)*distance );
-         addCentralAtomsDerivatives( i, 1, (dfunc)*distance );
-         addBoxDerivativesOfWeight( (-dfunc)*Tensor(distance,distance) );
          denom += sw;
       }
    }
    
    // Now divide everything
-   unsigned nder = getNumberOfDerivatives();
-   for(unsigned i=0;i<nder;++i){
-      setElementDerivative( i, getElementDerivative(i)/denom - (value*getElementDerivative(nder+i))/(denom*denom) );  
-      setElementDerivative( nder + i, 0.0 );
-   }
-   weightHasDerivatives=false;   // Weight has no derivatives we just use the holder for weight to store some stuff
-   return value / denom;
-}
+   double denom2=denom*denom;
+   updateActiveAtoms( myatoms ); vesselbase::MultiValue& myvals=myatoms.getUnderlyingMultiValue();
+   for(unsigned i=0;i<myvals.getNumberActive();++i){
+       unsigned ider=myvals.getActiveIndex(i);
+       myvals.setDerivative( 1, ider, myvals.getDerivative(1,ider)/denom - (value*myvals.getDerivative(0,ider))/denom2 );
+   } 
+   myvals.clear(0); myvals.setValue( 0, 1.0 );
 
-Vector OrientationSphere::getCentralAtom(){
-   addDerivativeOfCentralAtomPos( 0, Tensor::identity() );
-   return getPositionOfCentralAtom(0);
+   return value / denom;
 }
 
 }
diff --git a/src/crystallization/OrientationSphere.h b/src/crystallization/OrientationSphere.h
index 44e6a46c69d46cb5e772e167320aa61efced1888..1b137910ae3e1c8b14efc11b6baf38d3d52902e1 100644
--- a/src/crystallization/OrientationSphere.h
+++ b/src/crystallization/OrientationSphere.h
@@ -34,16 +34,12 @@ namespace crystallization {
 class OrientationSphere : public multicolvar::MultiColvarFunction {
 private:
   double rcut2;
-  std::vector<double> catom_orient, catom_der, this_orient;
-  std::vector<double> catom_iorient, catom_ider, this_iorient;
   SwitchingFunction switchingFunction;
 public:
   static void registerKeywords( Keywords& keys );
   OrientationSphere(const ActionOptions&);
-  double compute();
-  void calculateWeight();
+  double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms );
   virtual double transformDotProduct( const double& dot, double& df );
-  Vector getCentralAtom();  
   bool isPeriodic(){ return false; }
 };
 
diff --git a/src/crystallization/SimpleCubic.cpp b/src/crystallization/SimpleCubic.cpp
index 22ea326e2440da4ed2bcc5dbd2094734384e130a..09ab4b73fc83cc8eab7c7f434c499afaf1b01115 100644
--- a/src/crystallization/SimpleCubic.cpp
+++ b/src/crystallization/SimpleCubic.cpp
@@ -64,8 +64,7 @@ public:
   static void registerKeywords( Keywords& keys );
   SimpleCubic(const ActionOptions&);
 // active methods:
-  virtual double compute(); 
-  Vector getCentralAtom();
+  virtual double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ); 
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
 };
@@ -113,15 +112,14 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double SimpleCubic::compute(){
-   weightHasDerivatives=true;
+double SimpleCubic::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ){
    double d2, value=0, norm=0, dfunc; Vector distance;
 
    // Calculate the coordination number
    Vector myder, fder;
    double sw, t1, t2, t3, x2, x3, x4, y2, y3, y4, z2, z3, z4, r4, tmp;
-   for(unsigned i=1;i<getNAtoms();++i){
-      distance=getSeparation( getPosition(0), getPosition(i) );
+   for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+      distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) );
       d2 = distance.modulo2();
       if( d2<rcut2 ){ 
          sw = switchingFunction.calculateSqr( d2, dfunc );        
@@ -147,32 +145,26 @@ double SimpleCubic::compute(){
          myder[2] = 4*z3/t2-4*distance[2]*t3; 
 
          value += sw*tmp; fder = (+dfunc)*tmp*distance + sw*myder;
-         addAtomsDerivatives( 0, -fder );
-         addAtomsDerivatives( i, +fder );
+         myatoms.addAtomsDerivatives( 1, 0, -fder );
+         myatoms.addAtomsDerivatives( 1, i, +fder );
          // Tens is a constructor that you build by taking the vector product of two vectors (remember the scalars!)
-         addBoxDerivatives( Tensor(distance,-fder) );
+         myatoms.addBoxDerivatives( 1, Tensor(distance,-fder) );
  
          norm += sw;
-         addAtomsDerivativeOfWeight( 0, (-dfunc)*distance );
-         addAtomsDerivativeOfWeight( i, (+dfunc)*distance );
-         addBoxDerivativesOfWeight( (-dfunc)*Tensor(distance,distance) );
+         myatoms.addAtomsDerivatives( 0, 0, (-dfunc)*distance );
+         myatoms.addAtomsDerivatives( 0, i, (+dfunc)*distance );
+         myatoms.addBoxDerivatives( 0, (-dfunc)*Tensor(distance,distance) );
       }
    }
    
-   setElementValue(0, value); setElementValue(1, norm ); 
+   myatoms.setValue(1, value); myatoms.setValue(0, norm ); 
    // values -> der of... value [0], weight[1], x coord [2], y, z... [more magic]
-   updateActiveAtoms(); quotientRule( 0, 1, 0 ); clearDerivativesAfterTask(1);
-   // Weight doesn't really have derivatives (just use the holder for convenience)
-   weightHasDerivatives=false; setElementValue( 1, 1.0 );
+   updateActiveAtoms( myatoms ); myatoms.getUnderlyingMultiValue().quotientRule( 1, 0, 1 ); 
+   myatoms.getUnderlyingMultiValue().clear(0); myatoms.setValue( 0, 1.0 );
 
    return value / norm; // this is equivalent to getting an "atomic" CV
 }
 
-Vector SimpleCubic::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
 
diff --git a/src/crystallization/Steinhardt.cpp b/src/crystallization/Steinhardt.cpp
index 9a1761791899f544b9f609f4a27852178be6da03..61382e07519f5c290397e9a969f970a8fbe968ae 100644
--- a/src/crystallization/Steinhardt.cpp
+++ b/src/crystallization/Steinhardt.cpp
@@ -61,18 +61,19 @@ VectorMultiColvar(ao)
 }
 
 void Steinhardt::setAngularMomentum( const unsigned& ang ){
-  tmom=ang; setVectorDimensionality( 2*ang + 1, true, 2 );
+  tmom=ang; setVectorDimensionality( 2*(2*ang + 1), 2 );
 } 
 
-void Steinhardt::calculateVector(){
+void Steinhardt::calculateVector( multicolvar::AtomValuePack& myatoms ){
   double dfunc, dpoly_ass, md, tq6, itq6, real_z, imag_z; 
   Vector distance, dz, myrealvec, myimagvec, real_dz, imag_dz;
   // The square root of -1
   std::complex<double> ii( 0.0, 1.0 ), dp_x, dp_y, dp_z;
 
+  unsigned ncomp=2*tmom+1;
   double sw, poly_ass, dlen, nbond=0.0; std::complex<double> powered;
-  for(unsigned i=1;i<getNAtoms();++i){
-     distance=getSeparation( getPosition(0), getPosition(i) );
+  for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+     distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) );
      dlen=distance.modulo(); 
      if( dlen<rcut ){
          sw = switchingFunction.calculate( dlen, dfunc ); 
@@ -81,9 +82,9 @@ void Steinhardt::calculateVector(){
          double dlen3 = dlen*dlen*dlen;
 
          // Store derivatives of weight
-         MultiColvarBase::addAtomsDerivatives( 0, current_atoms[0], (-dfunc)*distance );
-         MultiColvarBase::addAtomsDerivatives( 0, current_atoms[i], (+dfunc)*distance );
-         MultiColvarBase::addBoxDerivatives( 0, (-dfunc)*Tensor( distance,distance ) ); 
+         myatoms.addAtomsDerivatives( 1, 0, (-dfunc)*distance );
+         myatoms.addAtomsDerivatives( 1, i, (+dfunc)*distance );
+         myatoms.addBoxDerivatives( 1, (-dfunc)*Tensor( distance,distance ) ); 
 
          // Do stuff for m=0
          poly_ass=deriv_poly( 0, distance[2]/dlen, dpoly_ass );
@@ -92,11 +93,11 @@ void Steinhardt::calculateVector(){
          // Derivative wrt to the vector connecting the two atoms
          myrealvec = (+sw)*dpoly_ass*dz + poly_ass*(+dfunc)*distance;
          // Accumulate the derivatives
-         addAtomsDerivative( tmom, 0, -myrealvec );      
-         addAtomsDerivative( tmom, i, myrealvec ); 
-         addBoxDerivatives( tmom, Tensor( -myrealvec,distance ) );
+         myatoms.addAtomsDerivatives( 2 + tmom, 0, -myrealvec );      
+         myatoms.addAtomsDerivatives( 2 + tmom, i, myrealvec ); 
+         myatoms.addBoxDerivatives( 2 + tmom, Tensor( -myrealvec,distance ) );
          // And store the vector function
-         addComponent( tmom, sw*poly_ass );
+         myatoms.addValue( 2 + tmom, sw*poly_ass );
 
          // The complex number of which we have to take powers
          std::complex<double> com1( distance[0]/dlen ,distance[1]/dlen );
@@ -128,38 +129,38 @@ void Steinhardt::calculateVector(){
              myimagvec = (+sw)*dpoly_ass*imag_z*dz + (+dfunc)*distance*itq6 + (+sw)*poly_ass*imag_dz;
 
              // Real part
-             addComponent( tmom+m, sw*tq6 );
-             addAtomsDerivative( tmom+m, 0, -myrealvec );
-             addAtomsDerivative( tmom+m, i, myrealvec );
-             addBoxDerivatives( tmom+m, Tensor( -myrealvec,distance ) );
+             myatoms.addValue( 2+tmom+m, sw*tq6 );
+             myatoms.addAtomsDerivatives( 2+tmom+m, 0, -myrealvec );
+             myatoms.addAtomsDerivatives( 2+tmom+m, i, myrealvec );
+             myatoms.addBoxDerivatives( 2+tmom+m, Tensor( -myrealvec,distance ) );
              // Imaginary part 
-             addImaginaryComponent( tmom+m, sw*itq6 );
-             addImaginaryAtomsDerivative( tmom+m, 0, -myimagvec );
-             addImaginaryAtomsDerivative( tmom+m, i, myimagvec );
-             addImaginaryBoxDerivatives( tmom+m, Tensor( -myimagvec,distance ) );
+             myatoms.addValue( 2+ncomp+tmom+m, sw*itq6 );
+             myatoms.addAtomsDerivatives( 2+ncomp+tmom+m, 0, -myimagvec );
+             myatoms.addAtomsDerivatives( 2+ncomp+tmom+m, i, myimagvec );
+             myatoms.addBoxDerivatives( 2+ncomp+tmom+m, Tensor( -myimagvec,distance ) );
              // Store -m part of vector
              double pref=pow(-1.0,m); 
              // -m part of vector is just +m part multiplied by (-1.0)**m and multiplied by complex
              // conjugate of Legendre polynomial
              // Real part
-             addComponent( tmom-m, pref*sw*tq6 );
-             addAtomsDerivative( tmom-m, 0, -pref*myrealvec );
-             addAtomsDerivative( tmom-m, i, pref*myrealvec );
-             addBoxDerivatives( tmom-m, pref*Tensor( -myrealvec,distance ) );
+             myatoms.addValue( 2+tmom-m, pref*sw*tq6 );
+             myatoms.addAtomsDerivatives( 2+tmom-m, 0, -pref*myrealvec );
+             myatoms.addAtomsDerivatives( 2+tmom-m, i, pref*myrealvec );
+             myatoms.addBoxDerivatives( 2+tmom-m, pref*Tensor( -myrealvec,distance ) );
              // Imaginary part
-             addImaginaryComponent( tmom-m, -pref*sw*itq6 );
-             addImaginaryAtomsDerivative( tmom-m, 0, pref*myimagvec );
-             addImaginaryAtomsDerivative( tmom-m, i, -pref*myimagvec );
-             addImaginaryBoxDerivatives( tmom-m, pref*Tensor( myimagvec,distance ) );
+             myatoms.addValue( 2+ncomp+tmom-m, -pref*sw*itq6 );
+             myatoms.addAtomsDerivatives( 2+ncomp+tmom-m, 0, pref*myimagvec );
+             myatoms.addAtomsDerivatives( 2+ncomp+tmom-m, i, -pref*myimagvec );
+             myatoms.addBoxDerivatives( 2+ncomp+tmom-m, pref*Tensor( myimagvec,distance ) );
          }
      }
   } 
 
   // Normalize 
-  setElementValue(0, nbond ); updateActiveAtoms();
-  for(unsigned i=0;i<2*getNumberOfComponentsInVector();++i) quotientRule( 5+i, 0, 5+i ); 
+  myatoms.setValue(1, nbond ); updateActiveAtoms( myatoms );
+  for(unsigned i=0;i<getNumberOfComponentsInVector();++i) myatoms.getUnderlyingMultiValue().quotientRule( 2+i, 1, 2+i ); 
   // Clear tempory stuff
-  clearDerivativesAfterTask(0);
+  myatoms.getUnderlyingMultiValue().clear(1);
 }
 
 double Steinhardt::deriv_poly( const unsigned& m, const double& val, double& df ){
@@ -179,11 +180,5 @@ double Steinhardt::deriv_poly( const unsigned& m, const double& val, double& df
   return normaliz[m]*res;
 }
 
-Vector Steinhardt::getCentralAtom(){
-  addCentralAtomDerivatives( 0, Tensor::identity() );
-  return getPosition(0);
-
-}
-
 }
 }
diff --git a/src/crystallization/Steinhardt.h b/src/crystallization/Steinhardt.h
index dee921aadf5ad3d8a32a49c707403ab5212ea43b..542ccc3582b076691fe2f5bec3090dd1600a8145 100644
--- a/src/crystallization/Steinhardt.h
+++ b/src/crystallization/Steinhardt.h
@@ -41,8 +41,7 @@ protected:
 public:
   static void registerKeywords( Keywords& keys );
   Steinhardt( const ActionOptions& ao );
-  void calculateVector();
-  Vector getCentralAtom();
+  void calculateVector( multicolvar::AtomValuePack& myatoms );
   double deriv_poly( const unsigned&, const double&, double& );
 };
 
diff --git a/src/crystallization/StoreVectorsVessel.cpp b/src/crystallization/StoreVectorsVessel.cpp
deleted file mode 100644
index 56e73490ec31e61daf832186763199e806bf80c2..0000000000000000000000000000000000000000
--- a/src/crystallization/StoreVectorsVessel.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2013,2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "vesselbase/VesselRegister.h"
-#include "vesselbase/ActionWithVessel.h"
-#include "multicolvar/MultiColvarFunction.h"
-#include "StoreVectorsVessel.h"
-#include "VectorMultiColvar.h"
-
-namespace PLMD {
-namespace crystallization{
-
-void StoreVectorsVessel::registerKeywords( Keywords& keys ){
-  vesselbase::StoreDataVessel::registerKeywords(keys);
-}
-
-StoreVectorsVessel::StoreVectorsVessel( const vesselbase::VesselOptions& da ):
-StoreDataVessel(da),
-store_director(true)
-{
-  vecs=dynamic_cast<VectorMultiColvar*>( getAction() );
-  plumed_assert( vecs );
-  if( vecs->complexvec ) ncomponents=2*vecs->ncomponents;  
-  else ncomponents = vecs->ncomponents;   
-
-  completeSetup( 5, ncomponents ); myfvec.resize( ncomponents );
-}
-
-void StoreVectorsVessel::usedInFunction( const bool& store ){
-  store_director=store; resize();
-}
-
-void StoreVectorsVessel::recompute( const unsigned& ivec, const unsigned& jstore ){
-  plumed_dbg_assert( vecs->derivativesAreRequired() && usingLowMem() ); 
-  // Set the task we want to reperform
-  setTaskToRecompute( ivec );
-  // Reperform the task
-  vecs->performTask();
-  // Store the derivatives
-  storeDerivativesLowMem( jstore );
-  // Normalize the vector if it is required
-  std::vector<double> fake_buffer;
-  if( store_director ) normalizeVector( jstore, fake_buffer ); 
-  // Clear up afterwards
-  vecs->clearAfterTask();
-
-}
-
-bool StoreVectorsVessel::calculate( std::vector<double>& buffer ){
-  if( !hard_cut ){
-      storeValues( vecs->getCurrentPositionInTaskList(), buffer );  // Store the values of the components of the vector
-      if(!store_director) return true;
-      if( !usingLowMem() ) normalizeVector( vecs->getCurrentPositionInTaskList(), buffer );
-      else normalizeVector( -1, buffer );  // Ensures vector components are normalized 
-  } else {
-     if( getAction()->getElementValue(getAction()->getIndexOfWeight())>wtol ){
-         storeValues( vecs->getCurrentPositionInTaskList(), buffer );
-         if(!store_director) return true;
-         if( !usingLowMem() ) normalizeVector( vecs->getCurrentPositionInTaskList(), buffer );
-         else normalizeVector( -1, buffer );  // Ensures vector components are normalized 
-     }
-  }
-  return true;
-}
-
-void StoreVectorsVessel::normalizeVector( const int& jstore, std::vector<double>& buffer ){
-  unsigned myelem = vecs->getCurrentPositionInTaskList();
-  bool lowmemory = usingLowMem(); double norm2=0.0, norm;
-  
-  if( (lowmemory && jstore<0) || !lowmemory ){
-     for(unsigned icomp=0;icomp<ncomponents;++icomp) norm2 += getComponent( myelem, icomp ) * getComponent( myelem, icomp );
-     norm=sqrt( norm2 ); 
-     for(unsigned icomp=0;icomp<ncomponents;++icomp){
-        myfvec[icomp]=getComponent( myelem, icomp );      
-        setComponent( myelem, icomp, getComponent( myelem, icomp ) / norm );
-     }
-  } else {
-     for(unsigned icomp=0;icomp<ncomponents;++icomp){
-        myfvec[icomp] = vecs->getElementValue( 5+icomp ); norm2 += myfvec[icomp] * myfvec[icomp];
-     }
-     norm=sqrt( norm2 );
-  }
-  double norm3=norm2*norm, weight = 1.0 / norm, wdf = -1.0 / norm3;
-
-  if( !lowmemory && vecs->derivativesAreRequired() ) {
-      plumed_dbg_assert( jstore<getAction()->getFullNumberOfTasks() );
-      for(unsigned ider=0;ider<getNumberOfDerivatives(myelem);++ider){
-          double comp2=0.0; unsigned ibuf = myelem * ncomponents * getNumberOfDerivativeSpacesPerComponent() + 1 + ider;
-          for(unsigned jcomp=0;jcomp<ncomponents;++jcomp){
-              //comp2  += myfvec[jcomp]*getBufferElement(ibuf);
-              ibuf += getNumberOfDerivativeSpacesPerComponent();
-          }
-          ibuf = bufstart + myelem * ncomponents * getNumberOfDerivativeSpacesPerComponent() + 1 + ider;
-          for(unsigned jcomp=0;jcomp<ncomponents;++jcomp){
-            buffer[ibuf] = weight*buffer[ibuf] + wdf*comp2*myfvec[jcomp]; 
-            // setBufferElement( ibuf, weight*getBufferElement(ibuf) + wdf*comp2*myfvec[jcomp] );
-             ibuf += getNumberOfDerivativeSpacesPerComponent();
-          }
-      }
-  } else if( jstore>0 && vecs->derivativesAreRequired() ) {
-      unsigned maxder = vecs->getNumberOfDerivatives();
-      for(unsigned ider=0;ider<getNumberOfDerivatives(jstore);++ider){
-          double comp2=0.0; unsigned ibuf = jstore * ncomponents * maxder + ider;
-          for(unsigned jcomp=0;jcomp<ncomponents;++jcomp){
-              comp2 += myfvec[jcomp]*getLocalDerivative( ibuf );    
-              ibuf += maxder;
-          }
-          ibuf = jstore * ncomponents * maxder + ider;
-          for(unsigned jcomp=0;jcomp<ncomponents;++jcomp){
-             setLocalDerivative( ibuf,  weight*getLocalDerivative( ibuf ) + wdf*comp2*myfvec[jcomp] ); 
-             ibuf += maxder;
-          }
-      }
-  }
-}
-
-void StoreVectorsVessel::chainRuleForComponent( const unsigned& icolv, const unsigned& jin, const unsigned& jout, const unsigned& base_cv_no, 
-                                                const double& weight, multicolvar::MultiColvarFunction* funcout ){
-  plumed_dbg_assert( vecs->derivativesAreRequired() );
-
-  if( usingLowMem() ){
-     unsigned ibuf = ( icolv*ncomponents + jin ) * getAction()->getNumberOfDerivatives();
-     for(unsigned ider=0;ider<getNumberOfDerivatives(icolv);++ider){
-         funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( icolv, ider ), weight*getLocalDerivative(ibuf+ider) );
-     }                                         
-  } else {
-     unsigned ibuf = (icolv*ncomponents + jin ) * getNumberOfDerivativeSpacesPerComponent() + 1;
-     for(unsigned ider=0;ider<getNumberOfDerivatives(icolv);++ider){
-         //funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( icolv, ider ), weight*getBufferElement(ibuf+ider) );
-     }   
-  }  
-}
-
-void StoreVectorsVessel::chainRuleForVector( const unsigned& icolv, const unsigned& jout, const unsigned& base_cv_no, 
-                                             const std::vector<double>& df, multicolvar::MultiColvarFunction* funcout ){ 
-   plumed_dbg_assert( vecs->derivativesAreRequired() );
-
-   chainRule( icolv, df );
-   for(unsigned ider=0;ider<getNumberOfDerivatives(icolv);++ider){
-       funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( icolv, ider ), getFinalDerivative(ider) );
-   }
-}
-
-}
-}
diff --git a/src/crystallization/StoreVectorsVessel.h b/src/crystallization/StoreVectorsVessel.h
deleted file mode 100644
index d44c0ae499327713cda0ff61b175ba223a56538c..0000000000000000000000000000000000000000
--- a/src/crystallization/StoreVectorsVessel.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2013,2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifndef __PLUMED_crystallization_StoreVectorsVessel_h
-#define __PLUMED_crystallization_StoreVectorsVessel_h
-
-#include "tools/DynamicList.h"
-#include "vesselbase/StoreDataVessel.h" 
-
-namespace PLMD {
-
-namespace crystallization {
-
-class VectorMultiColvar;
-
-class StoreVectorsVessel : public vesselbase::StoreDataVessel {
-friend class VectorMultiColvar;
-private:
-/// We want to store the director rather than the value
-  bool store_director; 
-  unsigned ncomponents;
-  std::vector<double> myfvec;
-  VectorMultiColvar* vecs;
-  void normalizeVector( const int&, std::vector<double>& );
-public:
-  static void registerKeywords( Keywords& keys );
-/// Constructor
-  StoreVectorsVessel( const vesselbase::VesselOptions& );
-/// This turns on the full use of this action for storage
-  void usedInFunction( const bool& );
-/// This makes sure vectors are normalized (they are already stored)
-  bool calculate( std::vector<double>& buffer );
-/// This reperforms a calculation
-  void recompute( const unsigned& , const unsigned& );
-/// This does nothing
-  std::string description(){ return ""; }
-/// Get the orientation of the ith vector
-  void getVector( const unsigned& , std::vector<double>& );
-/// Chain rule for component
-  void chainRuleForComponent( const unsigned& , const unsigned& , const unsigned& jout, const unsigned& , const double& , multicolvar::MultiColvarFunction* );
-/// Chain rule for whole vector
-  void chainRuleForVector( const unsigned& , const unsigned& , const unsigned& , const std::vector<double>& , multicolvar::MultiColvarFunction* );
-};
-
-inline
-void StoreVectorsVessel::getVector( const unsigned& imol, std::vector<double>& vec ){
-  plumed_dbg_assert( vec.size()==getNumberOfComponents() );
-  for(unsigned i=0;i<getNumberOfComponents();++i) vec[i]=getComponent( imol, i );
-}
-
-
-
-}
-}
-#endif
-
diff --git a/src/crystallization/Tetrahedral.cpp b/src/crystallization/Tetrahedral.cpp
index bac2cb483cae229325ad92c113378c3af2a03ed2..886075a556fb74ca2b26bb1d0e26b33a7cea5489 100644
--- a/src/crystallization/Tetrahedral.cpp
+++ b/src/crystallization/Tetrahedral.cpp
@@ -50,8 +50,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Tetrahedral(const ActionOptions&);
 // active methods:
-  virtual double compute(); 
-  Vector getCentralAtom();
+  virtual double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ); 
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
 };
@@ -99,8 +98,7 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double Tetrahedral::compute(){
-   weightHasDerivatives=true;
+double Tetrahedral::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ){
    double value=0, norm=0, dfunc; Vector distance;
 
    // Calculate the coordination number
@@ -108,8 +106,8 @@ double Tetrahedral::compute(){
    double sw, sp1, sp2, sp3, sp4;
    double sp1c, sp2c, sp3c, sp4c, r3, r5, tmp;
    double d2, t1, t2, t3, t4, tt1, tt2, tt3, tt4;
-   for(unsigned i=1;i<getNAtoms();++i){
-      distance=getSeparation( getPosition(0), getPosition(i) );
+   for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+      distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) );
       d2 = distance.modulo2();
       if( d2<rcut2 ){ 
          sw = switchingFunction.calculateSqr( d2, dfunc );
@@ -139,32 +137,26 @@ double Tetrahedral::compute(){
          myder[2] = (tt1-(distance[2]*t1))  + (-tt2-(distance[2]*t2))  + (-tt3-(distance[2]*t3))  + (tt4-(distance[2]*t4));
 
          value += sw*tmp; fder = (+dfunc)*tmp*distance + sw*myder;
-         addAtomsDerivatives( 0, -fder );
-         addAtomsDerivatives( i, +fder );
+         myatoms.addAtomsDerivatives( 1, 0, -fder );
+         myatoms.addAtomsDerivatives( 1, i, +fder );
          // Tens is a constructor that you build by taking the vector product of two vectors (remember the scalars!)
-         addBoxDerivatives( Tensor(distance,-fder) );
+         myatoms.addBoxDerivatives( 1, Tensor(distance,-fder) );
  
          norm += sw;
-         addAtomsDerivativeOfWeight( 0, (-dfunc)*distance );
-         addAtomsDerivativeOfWeight( i, (+dfunc)*distance );
-         addBoxDerivativesOfWeight( (-dfunc)*Tensor(distance,distance) );
+         myatoms.addAtomsDerivatives( 0, 0, (-dfunc)*distance );
+         myatoms.addAtomsDerivatives( 0, i, (+dfunc)*distance );
+         myatoms.addBoxDerivatives( 0, (-dfunc)*Tensor(distance,distance) );
       }
    }
    
-   setElementValue(0, value); setElementValue(1, norm ); 
+   myatoms.setValue(1, value); myatoms.setValue(0, norm ); 
    // values -> der of... value [0], weight[1], x coord [2], y, z... [more magic]
-   updateActiveAtoms(); quotientRule( 0, 1, 0 ); clearDerivativesAfterTask(1);
-   // Weight doesn't really have derivatives (just use the holder for convenience)
-   weightHasDerivatives=false; setElementValue( 1, 1.0 );
+   updateActiveAtoms( myatoms ); myatoms.getUnderlyingMultiValue().quotientRule( 1, 0, 1 ); 
+   myatoms.getUnderlyingMultiValue().clear(0); myatoms.setValue( 0, 1.0 );
 
    return value / norm; // this is equivalent to getting an "atomic" CV
 }
 
-Vector Tetrahedral::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
 
diff --git a/src/crystallization/VectorMean.cpp b/src/crystallization/VectorMean.cpp
index 2afa504fbbc3c0227d9aa392abc4918de62cd6ea..64c1927014970844564478f04cd044b22123d5e5 100644
--- a/src/crystallization/VectorMean.cpp
+++ b/src/crystallization/VectorMean.cpp
@@ -29,15 +29,13 @@ namespace PLMD {
 namespace crystallization {
 
 class VectorMean : public vesselbase::FunctionVessel {
-private:
-  unsigned ncomp, vstart, wnum;
 public:
   static void registerKeywords( Keywords& keys );
   static void reserveKeyword( Keywords& keys );
   VectorMean( const vesselbase::VesselOptions& da );
   std::string function_description();
   void resize();
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer );
   void finish( const std::vector<double>& buffer );
 };
 
@@ -56,15 +54,6 @@ void VectorMean::reserveKeyword( Keywords& keys ){
 VectorMean::VectorMean( const vesselbase::VesselOptions& da ) :
 FunctionVessel(da)
 {
-   usetol=true;
-   multicolvar::ActionVolume* vg=dynamic_cast<multicolvar::ActionVolume*>( getAction() );
-   if( vg ){
-       ncomp = getAction()->getNumberOfQuantities() - 2;
-       vstart=1; wnum=ncomp+1;
-   } else { 
-       vstart=5; wnum=1; 
-       ncomp = getAction()->getNumberOfQuantities() - 5;
-   }
 }
 
 std::string VectorMean::function_description(){
@@ -72,7 +61,7 @@ std::string VectorMean::function_description(){
 }
 
 void VectorMean::resize(){
-  if( ncomp==0 ) ncomp=getAction()->getNumberOfQuantities() - 5;
+  unsigned ncomp=getAction()->getNumberOfQuantities() - 2;
 
   if( getAction()->derivativesAreRequired() ){
      unsigned nder=getAction()->getNumberOfDerivatives();
@@ -84,36 +73,34 @@ void VectorMean::resize(){
   }
 }
 
-bool VectorMean::calculate( std::vector<double>& buffer ){
-  double weight=getAction()->getElementValue(wnum);
-  unsigned nder=getAction()->getNumberOfDerivatives();
-  plumed_dbg_assert( weight>=getTolerance() ); 
-  // bool addval = addValueUsingTolerance( 0, weight );
+bool VectorMean::calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer ){
+  unsigned ncomp=getAction()->getNumberOfQuantities()-2, nder=getAction()->getNumberOfDerivatives();
+
+  double weight=myvals.get(0); plumed_dbg_assert( weight>=getTolerance() ); 
   buffer[bufstart] += weight;
-  if( diffweight ) getAction()->chainRuleForElementDerivatives( 0, wnum, 1.0, bufstart, buffer );
+  if( diffweight ) myvals.chainRule( 0, 0, 1, 0, 1.0, bufstart, buffer ); 
   for(unsigned i=0;i<ncomp;++i){
-      double colvar=getAction()->getElementValue( vstart  + i );
+      double colvar=myvals.get(2+i); 
       buffer[bufstart + (1+i)*(1+nder)] += weight*colvar;  
-      // addValueIgnoringTolerance( 1 + i, weight*colvar );
-      getAction()->chainRuleForElementDerivatives( 1+i, vstart+i, weight, bufstart, buffer );
-      if( diffweight ) getAction()->chainRuleForElementDerivatives( 1+i, wnum, colvar, bufstart, buffer );
+      myvals.chainRule( 2+i, 1+i, 1, 0, weight, bufstart, buffer );
+      if( diffweight ) myvals.chainRule( 0, 1+i, 1, 0, colvar, bufstart, buffer );
   }
   return true;
 }
 
 void VectorMean::finish( const std::vector<double>& buffer ){
-  double sum=0, ww=buffer[bufstart]; // getFinalValue(0);
+  unsigned ncomp=getAction()->getNumberOfQuantities()-2;
+  double sum=0, ww=buffer[bufstart]; 
   unsigned nder=getAction()->getNumberOfDerivatives();
   for(unsigned i=0;i<ncomp;++i){ 
      double tmp = buffer[bufstart+(nder+1)*(i+1)] / ww;
      sum+=tmp*tmp; 
   }
-  double tw = 1.0 / sqrt(sum);
-  setOutputValue( sqrt(sum) ); 
+  double tw = 1.0 / sqrt(sum); setOutputValue( sqrt(sum) ); 
   if( !getAction()->derivativesAreRequired() ) return;
 
   for(unsigned icomp=0;icomp<ncomp;++icomp){
-      double tmp = buffer[(icomp+1)*(1+nder)] / ww; // getFinalValue(icomp+1) / ww;
+      double tmp = buffer[(icomp+1)*(1+nder)] / ww; 
       unsigned bstart = bufstart + (1+icomp)*(nder+1) + 1;
       for(unsigned jder=0;jder<nder;++jder) addDerivativeToFinalValue( jder, (tw*tmp/ww)*( buffer[bstart + jder] - tmp*buffer[bufstart + 1 + jder] ) );
   }
diff --git a/src/crystallization/VectorMultiColvar.cpp b/src/crystallization/VectorMultiColvar.cpp
index 627e65e41838afe755df914ef53cb285bc84d7c0..414cf8962cb9a162cdac30b540d191e8bd37744e 100644
--- a/src/crystallization/VectorMultiColvar.cpp
+++ b/src/crystallization/VectorMultiColvar.cpp
@@ -32,169 +32,180 @@ void VectorMultiColvar::registerKeywords( Keywords& keys ){
 
 VectorMultiColvar::VectorMultiColvar(const ActionOptions& ao):
 PLUMED_MULTICOLVAR_INIT(ao),
-firstcall(false),
-vecs(NULL)
+store_director(true),
+firstcall(false)
 {
   setLowMemOption(true);
 }
 
-void VectorMultiColvar::setVectorDimensionality( const unsigned& ncomp, const bool& comp, const int& nat ){
-  // Store number of derivatives and if vectors are complex
-  ncomponents = ncomp; complexvec=comp; 
-  if(complexvec) dervec.resize( 2*ncomponents );
-  else dervec.resize( ncomponents );
+void VectorMultiColvar::setVectorDimensionality( const unsigned& ncomp, const int& nat ){
+  // Store number of derivatives 
+  ncomponents = ncomp;  
   // Read in the atoms if we are using multicolvar reading
   int natoms=nat; readAtoms( natoms );
   // Create the store vector object
-  std::string param; vesselbase::VesselOptions da("","",0,param,this);
-  Keywords keys; StoreVectorsVessel::registerKeywords( keys );
-  vesselbase::VesselOptions da2(da,keys);
-  vecs = new StoreVectorsVessel(da2);
-  // Add the vessel to the base
-  addVessel(vecs);
-  // Read in any vessels
-  readVesselKeywords();
+//   std::string param; vesselbase::VesselOptions da("","",0,param,this);
+//   Keywords keys; StoreVectorsVessel::registerKeywords( keys );
+//   vesselbase::VesselOptions da2(da,keys);
+//   vecs = new StoreVectorsVessel(da2);
+//   // Add the vessel to the base
+//   addVessel(vecs);
+//  // Read in any vessels
+//  readVesselKeywords();
   // Resize a holder for the derivatives of the norm of the vector
 }
 
 void VectorMultiColvar::doNotCalculateDirector(){
-  vecs->store_director=false;
+  store_director=false;    // Need a sanity check in here  so that you don't use the same instance of Q4 to calcualte vectors and directors 
 }
 
-double VectorMultiColvar::doCalculation(){
+double VectorMultiColvar::doCalculation( const unsigned& taskIndex, multicolvar::AtomValuePack& myatoms ){
   // Now calculate the vector
-  calculateVector();
+  calculateVector( myatoms );
   // Sort out the active derivatives
-  updateActiveAtoms();
+  updateActiveAtoms( myatoms );
 
   // Now calculate the norm of the vector (this is what we return here)
-  double norm=0, inorm;
-  if(complexvec){
-     for(unsigned i=0;i<ncomponents;++i) norm += getComponent(i)*getComponent(i) + getImaginaryComponent(i)*getImaginaryComponent(i); 
-     norm=sqrt(norm); inorm = 1.0 / norm;
-     for(unsigned i=0;i<ncomponents;++i){ dervec[i] = inorm*getComponent(i); dervec[ncomponents+i] = inorm*getImaginaryComponent(i); } 
-  } else {
-     for(unsigned i=0;i<ncomponents;++i) norm += getComponent(i)*getComponent(i);
-     norm=sqrt(norm); inorm = 1.0 / norm;
-     for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*getComponent(i); 
-  }
-
+  double norm=0; 
+  for(unsigned i=0;i<ncomponents;++i) norm += myatoms.getValue(2+i)*myatoms.getValue(2+i); 
+  norm=sqrt(norm);
+ 
   if( !doNotCalculateDerivatives() ){
-      if( usingLowMem() ){
-         vecs->storeDerivativesLowMem( 0 );
-         vecs->chainRule( 0, dervec );
-      } else {
-         //vecs->storeDerivativesHighMem( getCurrentPositionInTaskList() );
-         vecs->chainRule( getCurrentPositionInTaskList(), dervec );
+      double inorm = 1.0 / norm; std::vector<double> dervec( ncomponents );
+      for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*myatoms.getValue(2+i);
+ 
+      vesselbase::MultiValue& myvals=myatoms.getUnderlyingMultiValue();
+      for(unsigned j=0;j<myvals.getNumberActive();++j){
+          unsigned jder=myvals.getActiveIndex(j);
+          for(unsigned i=0;i<ncomponents;++i) myvals.addDerivative( 1, jder, dervec[i]*myvals.getDerivative( 2+i, jder ) );
       }
-
-      // Add derivatives to base multicolvars
-      Vector tmpd;
-      for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-           unsigned k=atoms_with_derivatives[i];
-           tmpd[0]=vecs->getFinalDerivative(3*i+0); 
-           tmpd[1]=vecs->getFinalDerivative(3*i+1); 
-           tmpd[2]=vecs->getFinalDerivative(3*i+2); 
-           MultiColvarBase::addAtomsDerivatives( 0, k, tmpd );
-      }   
-      unsigned vvbase=3*atoms_with_derivatives.getNumberActive(); Tensor tmpv;
-      for(unsigned i=0;i<3;++i){
-          for(unsigned j=0;j<3;++j){
-              tmpv(i,j) = vecs->getFinalDerivative( vvbase+3*i+j ); 
-          }   
-      }   
-      MultiColvarBase::addBoxDerivatives( 0, tmpv );
   }
+  // if(complexvec){
+  //    for(unsigned i=0;i<ncomponents;++i) norm += getComponent(i)*getComponent(i) + getImaginaryComponent(i)*getImaginaryComponent(i); 
+  //    norm=sqrt(norm); inorm = 1.0 / norm;
+  //    for(unsigned i=0;i<ncomponents;++i){ dervec[i] = inorm*getComponent(i); dervec[ncomponents+i] = inorm*getImaginaryComponent(i); } 
+  // } else {
+  //    for(unsigned i=0;i<ncomponents;++i) norm += getComponent(i)*getComponent(i);
+  //    norm=sqrt(norm); inorm = 1.0 / norm;
+  //    for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*getComponent(i); 
+  // }
+
+  // if( !doNotCalculateDerivatives() ){
+  //     if( usingLowMem() ){
+  //        vecs->storeDerivativesLowMem( 0 );
+  //        vecs->chainRule( 0, dervec );
+  //     } else {
+  //        //vecs->storeDerivativesHighMem( getCurrentPositionInTaskList() );
+  //        vecs->chainRule( getCurrentPositionInTaskList(), dervec );
+  //     }
+
+  //     // Add derivatives to base multicolvars
+  //     Vector tmpd;
+  //     for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
+  //          unsigned k=atoms_with_derivatives[i];
+  //          tmpd[0]=vecs->getFinalDerivative(3*i+0); 
+  //          tmpd[1]=vecs->getFinalDerivative(3*i+1); 
+  //          tmpd[2]=vecs->getFinalDerivative(3*i+2); 
+  //          MultiColvarBase::addAtomsDerivatives( 0, k, tmpd );
+  //     }   
+  //     unsigned vvbase=3*atoms_with_derivatives.getNumberActive(); Tensor tmpv;
+  //     for(unsigned i=0;i<3;++i){
+  //         for(unsigned j=0;j<3;++j){
+  //             tmpv(i,j) = vecs->getFinalDerivative( vvbase+3*i+j ); 
+  //         }   
+  //     }   
+  //     MultiColvarBase::addBoxDerivatives( 0, tmpv );
+  // }
   
   return norm;
 }
 
-vesselbase::StoreDataVessel* VectorMultiColvar::buildDataStashes( const bool& allow_wcutoff, const double& wtol ){
-  // Build everyting for the multicolvar
-  vesselbase::StoreDataVessel* vsv=MultiColvarBase::buildDataStashes( allow_wcutoff, wtol );
-  if( allow_wcutoff ) vsv->setHardCutoffOnWeight( wtol );
-  // Resize the variable
-  vecs->resize();
-  // And make sure we set up the vector storage correctly
-  vv1.resize( 1 ); vv2.resize( getNumberOfQuantities() - 5 );
-  // And return
-  return vsv;
-}
-
-void VectorMultiColvar::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){
-  plumed_dbg_assert( vecs && vals.size()==(getNumberOfQuantities()-4) ); 
-  MultiColvarBase::getValueForTask( iatom, vv1 ); vecs->getVector( iatom, vv2 );
-  vals[0]=vv1[0]; for(unsigned i=0;i<vv2.size();++i) vals[i+1]=vv2[i];
-}
-
-void VectorMultiColvar::addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, multicolvar::MultiColvarFunction* func ){
-  if( usingLowMem() ){
-     vecs->recompute( iatom, 1 ); 
-     for(unsigned j=0;j<getNumberOfQuantities()-5;++j) vecs->chainRuleForComponent( 1, j, 5+j, base_cv_no, weight, func );
-  } else {
-     for(unsigned j=0;j<getNumberOfQuantities()-5;++j) vecs->chainRuleForComponent( iatom, j, 5+j, base_cv_no, weight, func );
-  }
-}
-
-void VectorMultiColvar::finishWeightedAverageCalculation( multicolvar::MultiColvarFunction* func ){
-  // And calculate the norm of the vector
-  double norm=0, inorm; std::vector<unsigned> tmpindices( 1 + func->getNumberOfDerivatives() );
-  if(complexvec){
-     for(unsigned i=0;i<ncomponents;++i){
-        // Calculate average vector
-        func->quotientRule(5+i, 1, 5+i); func->quotientRule(5+ncomponents+i, 1, 5+ncomponents+i);
-        // Calculate length of vector
-        norm += func->getElementValue(5+i)*func->getElementValue(5+i) + func->getElementValue(5+ncomponents+i)*func->getElementValue(5+ncomponents+i);
-     }
-     norm=sqrt(norm); inorm = 1.0 / norm;
-     for(unsigned i=0;i<ncomponents;++i){ 
-        dervec[i] = inorm*func->getElementValue(5+i); dervec[ncomponents+i] = inorm*func->getElementValue(5+ncomponents+i); 
-     }
-     func->getIndexList( 1, 0, func->getNumberOfDerivatives(), tmpindices );
-     unsigned nder = func->getNumberOfDerivatives();
-     for(unsigned i=0;i<tmpindices[0];++i){
-         unsigned ind = tmpindices[1+i];
-         for(unsigned j=0;j<ncomponents;++j){
-             func->addElementDerivative( ind, dervec[j]*func->getElementDerivative(nder*(5+j) + ind) );
-             func->addElementDerivative( ind, dervec[ncomponents+j]*func->getElementDerivative(nder*(5+ncomponents+j) + ind) );
-         }
-     }
-  } else {
-     for(unsigned i=0;i<ncomponents;++i){
-         // Calculate average vector
-         func->quotientRule(5+i, 1, 5+i);
-         // Calculate length of vector
-         norm += func->getElementValue(5+i)*func->getElementValue(5+i);
-     }
-     norm=sqrt(norm); inorm = 1.0 / norm;
-     for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*func->getElementValue(5+i); 
-     func->getIndexList( 1, 0, func->getNumberOfDerivatives(), tmpindices );
-     // And set derivatives given magnitude of the vector
-     unsigned nder = func->getNumberOfDerivatives();
-     for(unsigned i=0;i<tmpindices[0];++i){
-         unsigned ind = tmpindices[1+i];
-         for(unsigned j=0;j<ncomponents;++j){
-             func->addElementDerivative( ind, dervec[j]*func->getElementDerivative(nder*(5+j) + ind) );
-         }
-     }
-  }
-  func->setElementValue( 0, norm );
-}
-
-void VectorMultiColvar::addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
-                                                         const std::vector<double>& der, multicolvar::MultiColvarFunction* func ){
-  if( usingLowMem() ){
-      if(jstore==1){
-         if(firstcall){ vecs->recompute( iatom, jstore ); firstcall=false; }
-         vecs->chainRuleForVector( jstore, 0, base_cv_no, der, func );
-      } else {
-         vecs->recompute( iatom, jstore );
-         vecs->chainRuleForVector( jstore, 0, base_cv_no, der, func );
-      }
-  } else {
-      vecs->chainRuleForVector( iatom, 0, base_cv_no, der, func );
-  }
-}
+// vesselbase::StoreDataVessel* VectorMultiColvar::buildDataStashes( const bool& allow_wcutoff, const double& wtol ){
+//   // Build everyting for the multicolvar
+//   vesselbase::StoreDataVessel* vsv=MultiColvarBase::buildDataStashes( allow_wcutoff, wtol );
+//   if( allow_wcutoff ) vsv->setHardCutoffOnWeight( wtol );
+//   // Resize the variable
+//   vecs->resize();
+//   // And make sure we set up the vector storage correctly
+//   vv1.resize( 1 ); vv2.resize( getNumberOfQuantities() - 5 );
+//   // And return
+//   return vsv;
+// }
+// 
+// void VectorMultiColvar::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){
+//   plumed_dbg_assert( vecs && vals.size()==(getNumberOfQuantities()-4) ); 
+//   MultiColvarBase::getValueForTask( iatom, vv1 ); vecs->getVector( iatom, vv2 );
+//   vals[0]=vv1[0]; for(unsigned i=0;i<vv2.size();++i) vals[i+1]=vv2[i];
+// }
+
+// void VectorMultiColvar::addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, multicolvar::MultiColvarFunction* func ){
+//   if( usingLowMem() ){
+//      vecs->recompute( iatom, 1 ); 
+//      for(unsigned j=0;j<getNumberOfQuantities()-5;++j) vecs->chainRuleForComponent( 1, j, 5+j, base_cv_no, weight, func );
+//   } else {
+//      for(unsigned j=0;j<getNumberOfQuantities()-5;++j) vecs->chainRuleForComponent( iatom, j, 5+j, base_cv_no, weight, func );
+//   }
+// }
+
+// void VectorMultiColvar::finishWeightedAverageCalculation( multicolvar::MultiColvarFunction* func ){
+//   // And calculate the norm of the vector
+//   double norm=0, inorm; std::vector<unsigned> tmpindices( 1 + func->getNumberOfDerivatives() );
+//   if(complexvec){
+//      for(unsigned i=0;i<ncomponents;++i){
+//         // Calculate average vector
+//         func->quotientRule(5+i, 1, 5+i); func->quotientRule(5+ncomponents+i, 1, 5+ncomponents+i);
+//         // Calculate length of vector
+//         norm += func->getElementValue(5+i)*func->getElementValue(5+i) + func->getElementValue(5+ncomponents+i)*func->getElementValue(5+ncomponents+i);
+//      }
+//      norm=sqrt(norm); inorm = 1.0 / norm;
+//      for(unsigned i=0;i<ncomponents;++i){ 
+//         dervec[i] = inorm*func->getElementValue(5+i); dervec[ncomponents+i] = inorm*func->getElementValue(5+ncomponents+i); 
+//      }
+//      func->getIndexList( 1, 0, func->getNumberOfDerivatives(), tmpindices );
+//      unsigned nder = func->getNumberOfDerivatives();
+//      for(unsigned i=0;i<tmpindices[0];++i){
+//          unsigned ind = tmpindices[1+i];
+//          for(unsigned j=0;j<ncomponents;++j){
+//              func->addElementDerivative( ind, dervec[j]*func->getElementDerivative(nder*(5+j) + ind) );
+//              func->addElementDerivative( ind, dervec[ncomponents+j]*func->getElementDerivative(nder*(5+ncomponents+j) + ind) );
+//          }
+//      }
+//   } else {
+//      for(unsigned i=0;i<ncomponents;++i){
+//          // Calculate average vector
+//          func->quotientRule(5+i, 1, 5+i);
+//          // Calculate length of vector
+//          norm += func->getElementValue(5+i)*func->getElementValue(5+i);
+//      }
+//      norm=sqrt(norm); inorm = 1.0 / norm;
+//      for(unsigned i=0;i<ncomponents;++i) dervec[i] = inorm*func->getElementValue(5+i); 
+//      func->getIndexList( 1, 0, func->getNumberOfDerivatives(), tmpindices );
+//      // And set derivatives given magnitude of the vector
+//      unsigned nder = func->getNumberOfDerivatives();
+//      for(unsigned i=0;i<tmpindices[0];++i){
+//          unsigned ind = tmpindices[1+i];
+//          for(unsigned j=0;j<ncomponents;++j){
+//              func->addElementDerivative( ind, dervec[j]*func->getElementDerivative(nder*(5+j) + ind) );
+//          }
+//      }
+//   }
+//   func->setElementValue( 0, norm );
+// }
+
+// void VectorMultiColvar::addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
+//                                                          const std::vector<double>& der, multicolvar::MultiColvarFunction* func ){
+//   if( usingLowMem() ){
+//       if(jstore==1){
+//          if(firstcall){ vecs->recompute( iatom, jstore ); firstcall=false; }
+//          vecs->chainRuleForVector( jstore, 0, base_cv_no, der, func );
+//       } else {
+//          vecs->recompute( iatom, jstore );
+//          vecs->chainRuleForVector( jstore, 0, base_cv_no, der, func );
+//       }
+//   } else {
+//       vecs->chainRuleForVector( iatom, 0, base_cv_no, der, func );
+//   }
+// }
 
 void VectorMultiColvar::addForcesOnAtoms( const std::vector<double>& inforces ){
   plumed_dbg_assert( inforces.size()==getNumberOfDerivatives() );
@@ -204,25 +215,25 @@ void VectorMultiColvar::addForcesOnAtoms( const std::vector<double>& inforces ){
   setForcesOnAtoms( oldforces );
 }
 
-void VectorMultiColvar::copyElementsToBridgedColvar( multicolvar::BridgedMultiColvarFunction* func ){
-  MultiColvarBase::copyElementsToBridgedColvar( func );
-
-  for(unsigned icomp=5;icomp<getNumberOfQuantities();++icomp){
-      func->setElementValue( icomp-4, getElementValue(icomp) );
-      unsigned nbase =  icomp * getNumberOfDerivatives();
-      unsigned nbasev = (icomp-4) * func->getNumberOfDerivatives();
-      for(unsigned jatom=0;jatom<atoms_with_derivatives.getNumberActive();++jatom){
-          unsigned n=atoms_with_derivatives[jatom], nx=nbase + 3*n, ny=nbasev + 3*n;
-          func->addElementDerivative( ny+0, getElementDerivative(nx+0) );
-          func->addElementDerivative( ny+1, getElementDerivative(nx+1) );
-          func->addElementDerivative( ny+2, getElementDerivative(nx+2) );
-     }
-     unsigned nwvir=nbase + 3*getNumberOfAtoms(), nwvirv=nbasev + 3*getNumberOfAtoms();
-     for(unsigned k=0;k<9;++k){
-        func->addElementDerivative( nwvirv, getElementDerivative(nwvir) ); nwvir++; nwvirv++;
-     }
-  }
-}
+// void VectorMultiColvar::copyElementsToBridgedColvar( multicolvar::BridgedMultiColvarFunction* func ){
+//   MultiColvarBase::copyElementsToBridgedColvar( func );
+// 
+//   for(unsigned icomp=5;icomp<getNumberOfQuantities();++icomp){
+//       func->setElementValue( icomp-4, getElementValue(icomp) );
+//       unsigned nbase =  icomp * getNumberOfDerivatives();
+//       unsigned nbasev = (icomp-4) * func->getNumberOfDerivatives();
+//       for(unsigned jatom=0;jatom<atoms_with_derivatives.getNumberActive();++jatom){
+//           unsigned n=atoms_with_derivatives[jatom], nx=nbase + 3*n, ny=nbasev + 3*n;
+//           func->addElementDerivative( ny+0, getElementDerivative(nx+0) );
+//           func->addElementDerivative( ny+1, getElementDerivative(nx+1) );
+//           func->addElementDerivative( ny+2, getElementDerivative(nx+2) );
+//      }
+//      unsigned nwvir=nbase + 3*getNumberOfAtoms(), nwvirv=nbasev + 3*getNumberOfAtoms();
+//      for(unsigned k=0;k<9;++k){
+//         func->addElementDerivative( nwvirv, getElementDerivative(nwvir) ); nwvir++; nwvirv++;
+//      }
+//   }
+// }
 
 }
 }
diff --git a/src/crystallization/VectorMultiColvar.h b/src/crystallization/VectorMultiColvar.h
index f5921f10c46042187321d127eb774ae2c7e5aa41..e0324a27383193aa7bfce83204d9d7c08e4b8288 100644
--- a/src/crystallization/VectorMultiColvar.h
+++ b/src/crystallization/VectorMultiColvar.h
@@ -24,62 +24,56 @@
 
 #include "tools/Matrix.h"
 #include "multicolvar/MultiColvar.h"
-#include "StoreVectorsVessel.h"
 
 namespace PLMD {
 namespace crystallization {
 
 class VectorMultiColvar : public multicolvar::MultiColvar {
-friend class StoreVectorsVessel;
 friend class OrientationSphere;
 friend class VolumeGradientBase;
 private:
-/// Are the vectors complex
-  bool complexvec;
+/// Are we storing the director of the vector of the vector
+  bool store_director;
 /// Used to make sure central atom position is only calculated
 /// once when using orientation sphere
   bool firstcall;
 /// How many components does the vector have
   unsigned ncomponents;
-/// This object stores the vectors
-  StoreVectorsVessel* vecs;
-/// This is a tempory vector that is used to store derivatives
-  std::vector<double> dervec;
 /// These are tempory vectors that are used to store values and directors
   std::vector<double> vv1, vv2;
 protected:
 /// Set the dimensionality of the vector
-  void setVectorDimensionality( const unsigned&, const bool&, const int& );
-/// Add some value to the ith component of the vector
-  void addComponent( const unsigned&, const double& );
-/// Get the ith component
-  double getComponent( const unsigned& ) const ;
-/// Set the ith component
-  void setComponent( const unsigned&, const double& );
-/// Add derivatives of ith component of vector with repect to jth atom
-  void addAtomsDerivative( const unsigned&, const unsigned&, const Vector& );
-/// Add atomic derivatives to all components of matrix (note iatom is treated literally here - cf above)
-  void addAtomDerivativeToAllRealComponents( const unsigned& iatom, const std::vector<double>& vec, const Vector& avec );
-/// Add derivatives of ith component of vector with respect to the box 
-  void addBoxDerivatives( const unsigned&, const Tensor& );
-/// Add box derivatives to all components of matrix
-  void addBoxDerivativesToAllRealComponents( const std::vector<double>& vec, const Tensor& avec );
-/// Add some value to the imaginary part of the ith component of the vector
-  void addImaginaryComponent( const unsigned&, const double& );
-/// Get the ith component
-  double getImaginaryComponent( const unsigned& ) const ;
-/// Set the ith component
-  void setImaginaryComponent( const unsigned&, const double& );
-/// Add derivatives of the imaginary part of the ith component of vector with repect to jth atom
-  void addImaginaryAtomsDerivative( const unsigned&, const unsigned&, const Vector& );
-/// Add atomic derivatives to all components of matrix (note iatom is treated literally here - cf above)
-  void addAtomDerivativeToAllImagComponents( const unsigned& iatom, const std::vector<double>& vec, const Vector& avec );
-/// Add derivatives of the imaginary part of the ith component of vector with respect to the box 
-  void addImaginaryBoxDerivatives( const unsigned&, const Tensor& );
-/// Add box derivatives to all components of matrix
-  void addBoxDerivativesToAllImagComponents( const std::vector<double>& vec, const Tensor& avec );
-/// This can be used to accumulate derivative from a store of vectors
-  void accumulateDerivativesFromVector( const unsigned& ivec, const unsigned& base_cv_no, const double& weight, StoreVectorsVessel* vectors );
+  void setVectorDimensionality( const unsigned&, const int& );
+//  /// Add some value to the ith component of the vector
+//    void addComponent( const unsigned&, const double& );
+//  /// Get the ith component
+//    double getComponent( const unsigned& ) const ;
+//  /// Set the ith component
+//    void setComponent( const unsigned&, const double& );
+//  /// Add derivatives of ith component of vector with repect to jth atom
+//    void addAtomsDerivative( const unsigned&, const unsigned&, const Vector& );
+//  /// Add atomic derivatives to all components of matrix (note iatom is treated literally here - cf above)
+//    void addAtomDerivativeToAllRealComponents( const unsigned& iatom, const std::vector<double>& vec, const Vector& avec );
+//  /// Add derivatives of ith component of vector with respect to the box 
+//    void addBoxDerivatives( const unsigned&, const Tensor& );
+//  /// Add box derivatives to all components of matrix
+//    void addBoxDerivativesToAllRealComponents( const std::vector<double>& vec, const Tensor& avec );
+//  /// Add some value to the imaginary part of the ith component of the vector
+//    void addImaginaryComponent( const unsigned&, const double& );
+//  /// Get the ith component
+//    double getImaginaryComponent( const unsigned& ) const ;
+//  /// Set the ith component
+//    void setImaginaryComponent( const unsigned&, const double& );
+//  /// Add derivatives of the imaginary part of the ith component of vector with repect to jth atom
+//    void addImaginaryAtomsDerivative( const unsigned&, const unsigned&, const Vector& );
+//  /// Add atomic derivatives to all components of matrix (note iatom is treated literally here - cf above)
+//    void addAtomDerivativeToAllImagComponents( const unsigned& iatom, const std::vector<double>& vec, const Vector& avec );
+//  /// Add derivatives of the imaginary part of the ith component of vector with respect to the box 
+//    void addImaginaryBoxDerivatives( const unsigned&, const Tensor& );
+//  /// Add box derivatives to all components of matrix
+//    void addBoxDerivativesToAllImagComponents( const std::vector<double>& vec, const Tensor& avec );
+//  /// This can be used to accumulate derivative from a store of vectors
+//    void accumulateDerivativesFromVector( const unsigned& ivec, const unsigned& base_cv_no, const double& weight, StoreVectorsVessel* vectors );
 /// Used in vector average to add forces from vector the the forces from here
   void addForcesOnAtoms( const std::vector<double>& inforces );
 public:
@@ -89,32 +83,32 @@ public:
 /// The norm of a vector is not periodic
   virtual bool isPeriodic(){ return false; }
 /// Calculate the multicolvar
-  double doCalculation();
+  double doCalculation( const unsigned& taskIndex, multicolvar::AtomValuePack& myatoms );
 /// This shouldn't do anything
-  double compute(){ plumed_error(); }
+  double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ){ plumed_error(); }
 /// Calculate the vector
-  virtual void calculateVector()=0;
+  virtual void calculateVector( multicolvar::AtomValuePack& myatoms )=0;
 /// Get the number of components in the vector
   unsigned getNumberOfComponentsInVector() const ;
 /// Get the number of quantities we are calculating per step
   unsigned getNumberOfQuantities();
 /// Create places to store the data
-  vesselbase::StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
+//  vesselbase::StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
 /// Get the vector
-  void getValueForTask( const unsigned& iatom, std::vector<double>& vals );
+//  void getValueForTask( const unsigned& iatom, std::vector<double>& vals );
 /// Used to accumulate values
-  void addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, multicolvar::MultiColvarFunction* func );
+//  void addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, multicolvar::MultiColvarFunction* func );
 /// Used for calculating weighted averages
-  void finishWeightedAverageCalculation( multicolvar::MultiColvarFunction* func );
+//  void finishWeightedAverageCalculation( multicolvar::MultiColvarFunction* func );
 /// Used in functions to add derivatives to the orientation vector
-  void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
-                                        const std::vector<double>& der, multicolvar::MultiColvarFunction* func );
+//  void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
+//                                        const std::vector<double>& der, multicolvar::MultiColvarFunction* func );
 /// Can we differentiate the orientation - yes we can the multicolvar is a vector
   bool hasDifferentiableOrientation() const { return true; }
 ///  This makes sure we are not calculating the director when we do LocalAverage
   virtual void doNotCalculateDirector();
 /// Used by ActionVolume
-  void copyElementsToBridgedColvar( multicolvar::BridgedMultiColvarFunction* func );
+//  void copyElementsToBridgedColvar( multicolvar::BridgedMultiColvarFunction* func );
 };
 
 inline
@@ -122,71 +116,70 @@ unsigned VectorMultiColvar::getNumberOfComponentsInVector() const {
   return ncomponents; 
 }
 
-inline
-void VectorMultiColvar::addComponent( const unsigned& icomp, const double& val ){
-  plumed_dbg_assert( icomp<ncomponents );
-  addElementValue( 5 + icomp, val );
-}
-
-inline
-void VectorMultiColvar::setComponent( const unsigned& icomp, const double& val ){
-  plumed_dbg_assert( icomp<ncomponents );
-  setElementValue( 5 + icomp, val );
-} 
-  
-inline
-double VectorMultiColvar::getComponent( const unsigned& icomp ) const {
-  plumed_dbg_assert( icomp<ncomponents );
-  return getElementValue( 5 + icomp );
-} 
-
-
-inline
-void VectorMultiColvar::addAtomsDerivative( const unsigned& icomp, const unsigned& jatom, const Vector& der ){
-  plumed_dbg_assert( icomp<ncomponents && jatom<getNAtoms() );
-  MultiColvarBase::addAtomsDerivatives( 5 + icomp, current_atoms[jatom], der );
-}
-
-inline
-void VectorMultiColvar::addBoxDerivatives( const unsigned& icomp, const Tensor& vir ){
-  plumed_dbg_assert( icomp<ncomponents );
-  MultiColvarBase::addBoxDerivatives( 5 + icomp, vir );
-}
-
-inline
-void VectorMultiColvar::addImaginaryComponent( const unsigned& icomp, const double& val ){
-  plumed_dbg_assert( icomp<ncomponents && complexvec );
-  addElementValue( 5 + ncomponents + icomp, val );
-}
-
-inline
-void VectorMultiColvar::setImaginaryComponent( const unsigned& icomp, const double& val ){
-  plumed_dbg_assert( icomp<ncomponents && complexvec );
-  setElementValue( 5 + ncomponents + icomp, val );
-}
-
-inline 
-double VectorMultiColvar::getImaginaryComponent( const unsigned& icomp ) const {
-  plumed_dbg_assert( icomp<ncomponents && complexvec );
-  return getElementValue( 5 + ncomponents + icomp );
-} 
-
-inline
-void VectorMultiColvar::addImaginaryAtomsDerivative( const unsigned& icomp, const unsigned& jatom, const Vector& der){
-  plumed_dbg_assert( icomp<ncomponents && complexvec && jatom<getNAtoms() );
-  MultiColvarBase::addAtomsDerivatives( 5 + ncomponents + icomp, current_atoms[jatom], der );
-}
-
-inline
-void VectorMultiColvar::addImaginaryBoxDerivatives( const unsigned& icomp, const Tensor& vir ){
-  plumed_dbg_assert( icomp<ncomponents && complexvec );
-  MultiColvarBase::addBoxDerivatives( 5 + ncomponents + icomp, vir ); 
-}
+// inline
+// void VectorMultiColvar::addComponent( const unsigned& icomp, const double& val ){
+//   plumed_dbg_assert( icomp<ncomponents );
+//   addElementValue( 5 + icomp, val );
+// }
+// 
+// inline
+// void VectorMultiColvar::setComponent( const unsigned& icomp, const double& val ){
+//   plumed_dbg_assert( icomp<ncomponents );
+//   setElementValue( 5 + icomp, val );
+// } 
+//   
+// inline
+// double VectorMultiColvar::getComponent( const unsigned& icomp ) const {
+//   plumed_dbg_assert( icomp<ncomponents );
+//   return getElementValue( 5 + icomp );
+// } 
+// 
+// 
+// inline
+// void VectorMultiColvar::addAtomsDerivative( const unsigned& icomp, const unsigned& jatom, const Vector& der ){
+//   plumed_dbg_assert( icomp<ncomponents && jatom<getNAtoms() );
+//   MultiColvarBase::addAtomsDerivatives( 5 + icomp, current_atoms[jatom], der );
+// }
+
+// inline
+// void VectorMultiColvar::addBoxDerivatives( const unsigned& icomp, const Tensor& vir ){
+//   plumed_dbg_assert( icomp<ncomponents );
+//   MultiColvarBase::addBoxDerivatives( 5 + icomp, vir );
+// }
+// 
+// inline
+// void VectorMultiColvar::addImaginaryComponent( const unsigned& icomp, const double& val ){
+//   plumed_dbg_assert( icomp<ncomponents && complexvec );
+//   addElementValue( 5 + ncomponents + icomp, val );
+// }
+// 
+// inline
+// void VectorMultiColvar::setImaginaryComponent( const unsigned& icomp, const double& val ){
+//   plumed_dbg_assert( icomp<ncomponents && complexvec );
+//   setElementValue( 5 + ncomponents + icomp, val );
+// }
+// 
+// inline 
+// double VectorMultiColvar::getImaginaryComponent( const unsigned& icomp ) const {
+//   plumed_dbg_assert( icomp<ncomponents && complexvec );
+//   return getElementValue( 5 + ncomponents + icomp );
+// } 
+// 
+// inline
+// void VectorMultiColvar::addImaginaryAtomsDerivative( const unsigned& icomp, const unsigned& jatom, const Vector& der){
+//   plumed_dbg_assert( icomp<ncomponents && complexvec && jatom<getNAtoms() );
+//   MultiColvarBase::addAtomsDerivatives( 5 + ncomponents + icomp, current_atoms[jatom], der );
+// }
+// 
+// inline
+// void VectorMultiColvar::addImaginaryBoxDerivatives( const unsigned& icomp, const Tensor& vir ){
+//   plumed_dbg_assert( icomp<ncomponents && complexvec );
+//   MultiColvarBase::addBoxDerivatives( 5 + ncomponents + icomp, vir ); 
+// }
 
 inline
 unsigned VectorMultiColvar::getNumberOfQuantities(){
-  if( complexvec ) return 5 + 2*ncomponents;
-  return 5 + ncomponents;
+  return 2 + ncomponents;
 }
 
 }
diff --git a/src/crystallization/VectorSum.cpp b/src/crystallization/VectorSum.cpp
index 0e4d75292afc7808b14464f802041f0c4c1f46d4..f12e098f988bd470e7d47e4ee6ae10c85bd01ad2 100644
--- a/src/crystallization/VectorSum.cpp
+++ b/src/crystallization/VectorSum.cpp
@@ -29,15 +29,13 @@ namespace PLMD {
 namespace crystallization {
 
 class VectorSum : public vesselbase::FunctionVessel {
-private:
-  unsigned ncomp, vstart, wnum;
 public:
   static void registerKeywords( Keywords& keys );
   static void reserveKeyword( Keywords& keys );
   VectorSum( const vesselbase::VesselOptions& da );
   std::string function_description();
   void resize();
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer );
   void finish( const std::vector<double>& buffer );
 };
 
@@ -56,15 +54,6 @@ void VectorSum::reserveKeyword( Keywords& keys ){
 VectorSum::VectorSum( const vesselbase::VesselOptions& da ) :
 FunctionVessel(da)
 {
-   usetol=true;
-   multicolvar::ActionVolume* vg=dynamic_cast<multicolvar::ActionVolume*>( getAction() );
-   if( vg ){
-       ncomp = getAction()->getNumberOfQuantities() - 2;
-       vstart=1; wnum=ncomp+1;
-   } else { 
-       vstart=5; wnum=1; 
-       ncomp = getAction()->getNumberOfQuantities() - 5;
-   }
 }
 
 std::string VectorSum::function_description(){
@@ -72,39 +61,39 @@ std::string VectorSum::function_description(){
 }
 
 void VectorSum::resize(){
-  if( ncomp==0 ) ncomp=getAction()->getNumberOfQuantities() - 5;
+  unsigned ncomp=getAction()->getNumberOfQuantities() - 2;
 
   if( getAction()->derivativesAreRequired() ){
      unsigned nder=getAction()->getNumberOfDerivatives();
-     resizeBuffer( (1+nder)*(ncomp+1) );
+     resizeBuffer( (1+nder)*ncomp );
      setNumberOfDerivatives( nder );
   } else {
      setNumberOfDerivatives(0); 
-     resizeBuffer(ncomp+1);
+     resizeBuffer(ncomp);
   }
 }
 
-bool VectorSum::calculate( std::vector<double>& buffer ){
-  double weight=getAction()->getElementValue(wnum);
-  unsigned nder=getAction()->getNumberOfDerivatives();
+bool VectorSum::calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer ){
+  unsigned ncomp=getAction()->getNumberOfQuantities()-2, nder=getAction()->getNumberOfDerivatives();
+
+  double weight=myvals.get(0); 
   plumed_dbg_assert( weight>=getTolerance() );
-  // bool addval = addValueUsingTolerance( 0, weight );
   buffer[bufstart] += weight;
-  if( diffweight ) getAction()->chainRuleForElementDerivatives( 0, wnum, 1.0, bufstart, buffer );
   for(unsigned i=0;i<ncomp;++i){
-      double colvar=getAction()->getElementValue( vstart  + i );
-      buffer[bufstart + (1+i)*(1+nder)] += weight*colvar;
-      // addValueIgnoringTolerance( 1 + i, weight*colvar );
-      getAction()->chainRuleForElementDerivatives( 1+i, vstart+i, weight, bufstart, buffer );
-      if( diffweight ) getAction()->chainRuleForElementDerivatives( 1+i, wnum, colvar, bufstart, buffer );
+      double colvar=myvals.get(2+i);  
+      buffer[bufstart + i*(1+nder)] += weight*colvar;
+      myvals.chainRule( 2+i, i, 1, 0, weight, bufstart, buffer );
+      if( diffweight ) myvals.chainRule( 0, i, 1, 0, colvar, bufstart, buffer );
   }
   return true;
 }
 
 void VectorSum::finish( const std::vector<double>& buffer ){
+  unsigned ncomp=getAction()->getNumberOfQuantities()-2;
+
   double sum=0; unsigned nder=getAction()->getNumberOfDerivatives();
   for(unsigned i=0;i<ncomp;++i){ 
-     double tmp = buffer[bufstart+(nder+1)*(i+1)]; // getFinalValue(i+1);
+     double tmp = buffer[bufstart+(nder+1)*i]; 
      sum+=tmp*tmp; 
   }
   double tw = 1.0 / sqrt(sum);
@@ -112,8 +101,8 @@ void VectorSum::finish( const std::vector<double>& buffer ){
   if( !getAction()->derivativesAreRequired() ) return;
 
   for(unsigned icomp=0;icomp<ncomp;++icomp){
-      double tmp = buffer[(icomp+1)*(1+nder)];    // getFinalValue(icomp+1);
-      unsigned bstart = bufstart + (1+icomp)*(nder+1) + 1;
+      double tmp = buffer[icomp*(1+nder)];    
+      unsigned bstart = bufstart + icomp*(nder+1) + 1;
       for(unsigned jder=0;jder<nder;++jder) addDerivativeToFinalValue( jder, tw*tmp*buffer[bstart + jder] );
   }
 }
diff --git a/src/manyrestraints/ManyRestraintsBase.cpp b/src/manyrestraints/ManyRestraintsBase.cpp
index 05aa13bd21231d42d8015a25a6fd8e35ad9d3cef..f2bc0b9981e9042c25e2bc5d9afe0016ee2a1fc6 100644
--- a/src/manyrestraints/ManyRestraintsBase.cpp
+++ b/src/manyrestraints/ManyRestraintsBase.cpp
@@ -46,6 +46,7 @@ ActionWithInputVessel(ao)
   // Read in the vessel we are action on
   readArgument("bridge");
   aves=dynamic_cast<ActionWithVessel*>( getDependencies()[0] );
+
   plumed_assert( getDependencies().size()==1 && aves );
   log.printf("  adding restraints on variables calculated by %s action with label %s\n",
          aves->getName().c_str(),aves->getLabel().c_str());
@@ -64,16 +65,26 @@ void ManyRestraintsBase::doJobsRequiredBeforeTaskList(){
   ActionWithValue::clearDerivatives();
 }
 
-void ManyRestraintsBase::applyChainRuleForDerivatives( const double& df ){
-   // Value (this could be optimized more -- GAT)
-   for(unsigned i=0;i<aves->getNumberOfDerivatives();++i){
-       setElementDerivative( i, df*aves->getElementDerivative(i) );   
-   }
-   // And weights
-   unsigned nder=aves->getNumberOfDerivatives();
-   for(unsigned i=0;i<aves->getNumberOfDerivatives();++i){
-       setElementDerivative( nder+i, aves->getElementDerivative(nder+i) );
-   }
+void ManyRestraintsBase::transformBridgedDerivatives( const unsigned& current, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals ){
+  outvals.setValue( 0, invals.get(0) );
+  
+  // Get the potential
+  double dval, val=calcPotential( invals.get(1), dval );
+
+  if( val>getTolerance() ){
+      outvals.setValue( 1, val );
+      for(unsigned i=0;i<invals.getNumberActive();++i){
+          unsigned jder=invals.getActiveIndex(i);
+          outvals.addDerivative( 1, jder, dval*invals.getDerivative( 1, jder ) );
+      } 
+
+      // Now update the outvals derivatives lists
+      outvals.emptyActiveMembers();
+      for(unsigned j=0;j<invals.getNumberActive();++j) outvals.updateIndex( invals.getActiveIndex(j) );
+      outvals.sortActiveList();
+      return;
+  }
+  outvals.setValue( 1, 0.0 ); 
 }
 
 void ManyRestraintsBase::apply(){
diff --git a/src/manyrestraints/ManyRestraintsBase.h b/src/manyrestraints/ManyRestraintsBase.h
index 8ab405ee233f667d86c47f2763d75f15232de031..468e01508690def8f0b60a05d0e74e2f65fea503 100644
--- a/src/manyrestraints/ManyRestraintsBase.h
+++ b/src/manyrestraints/ManyRestraintsBase.h
@@ -40,27 +40,26 @@ class ManyRestraintsBase :
 private:
 /// Pointer to underlying action with vessel
   vesselbase::ActionWithVessel* aves;
-protected:
-/// Get the value of the current cv
-  double getValue();
-/// Get the weight of the current cv
-  double getWeight();
-/// Apply the chain rule to calculate the derivatives
-  void applyChainRuleForDerivatives( const double& df );
 public:
   static void registerKeywords( Keywords& keys );
   ManyRestraintsBase(const ActionOptions&);
   bool isPeriodic(){ return false; }
   unsigned getNumberOfDerivatives();
 /// Routines that have to be defined so as not to have problems with virtual methods
-  void deactivate_task(){};
+  void deactivate_task( const unsigned & task_index ){};
 /// Don't actually clear the derivatives when this is called from plumed main.  
 /// They are calculated inside another action and clearing them would be bad  
   void clearDerivatives(){}
 /// Do jobs required before tasks are undertaken
   void doJobsRequiredBeforeTaskList();
+/// This actually does the calculation
+  void transformBridgedDerivatives( const unsigned& current, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals );
+/// Calculate the potential
+  virtual double calcPotential( const double& val, double& df )=0;
 // Calculate does nothing
   void calculate(){};
+/// This should never be called
+  void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& ){ plumed_error(); }
 /// Deactivate task now does nothing
   void apply();
   void applyBridgeForces( const std::vector<double>& bb ){ plumed_assert( bb.size()==0 ); }
@@ -71,16 +70,6 @@ unsigned ManyRestraintsBase::getNumberOfDerivatives(){
   return aves->getNumberOfDerivatives();
 }
 
-inline
-double ManyRestraintsBase::getValue(){
-  return aves->getElementValue(0);
-}
-
-inline
-double ManyRestraintsBase::getWeight(){
-  return aves->getElementValue(1);
-}
-
 }
 }
 
diff --git a/src/manyrestraints/UWalls.cpp b/src/manyrestraints/UWalls.cpp
index c297b9ccd1db4eb7e39eabeb5af4e131181257f3..7292a7872853f4776c57393a961ec21865e0dbee 100644
--- a/src/manyrestraints/UWalls.cpp
+++ b/src/manyrestraints/UWalls.cpp
@@ -69,7 +69,7 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   UWalls( const ActionOptions& );
-  void performTask();
+  double calcPotential( const double& val, double& df );
 };
 
 PLUMED_REGISTER_ACTION(UWalls,"UWALLS")
@@ -95,23 +95,16 @@ ManyRestraintsBase(ao)
   checkRead();
 }
 
-void UWalls::performTask(){
-  double value=getValue(); 
-  double uscale = (value - at + offset)/eps;
+double UWalls::calcPotential( const double& val, double& df ){ 
+  double uscale = (val - at + offset)/eps;
   if( uscale > 0. ){
      double power = pow( uscale, exp );
-     double f = ( kappa / eps ) * exp * power / uscale;
+     df = ( kappa / eps ) * exp * power / uscale;
 
-     setElementValue( 0, kappa*power ); setElementValue( 1, getWeight() );
-     // Add derivatives 
-     applyChainRuleForDerivatives( f );
-    
-     return;
+     return kappa*power;
   }
 
-  // We need do nothing more if this is not true
-  setElementValue( 1, 0.0 );
-  return;
+  return 0.0;
 }
 
 }
diff --git a/src/mapping/Mapping.cpp b/src/mapping/Mapping.cpp
index 9dce33318f58fd43f23794008e6d05aaa83c7d11..25fc1a0dfd98f3849048d80f3d8c8d231bd0b312 100644
--- a/src/mapping/Mapping.cpp
+++ b/src/mapping/Mapping.cpp
@@ -189,32 +189,33 @@ void Mapping::calculateNumericalDerivatives( ActionWithValue* a ){
   }
 }
 
-void Mapping::mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer ){
-  unsigned cur = getCurrentTask(), frameno=ider*getNumberOfReferencePoints() + cur;
-  for(unsigned i=0;i<getNumberOfArguments();++i){
-      buffer[start+ i*stride] += df*dfframes[frameno]*mymap->getArgumentDerivative(cur,i);
-  }
+void Mapping::transferDerivatives( const unsigned& ider, const unsigned& fno, const unsigned& cur, vesselbase::MultiValue& myvals ){
+  if( !derivativesAreRequired() ) return;
+
+  unsigned frameno=fno*getNumberOfReferencePoints() + cur;
+  for(unsigned i=0;i<getNumberOfArguments();++i) myvals.addDerivative( ider, i, dfframes[frameno]*mymap->getArgumentDerivative(cur,i) ); 
+
   if( getNumberOfAtoms()>0 ){
       Vector ader; Tensor tmpvir; tmpvir.zero();
-      unsigned n=getNumberOfArguments(); 
+      unsigned n=getNumberOfArguments();
       for(unsigned i=0;i<getNumberOfAtoms();++i){
-          ader=mymap->getAtomDerivatives( cur, i );            
-          buffer[start+n*stride] += df*dfframes[frameno]*ader[0]; n++;
-          buffer[start+n*stride] += df*dfframes[frameno]*ader[1]; n++;
-          buffer[start+n*stride] += df*dfframes[frameno]*ader[2]; n++;
+          ader=mymap->getAtomDerivatives( cur, i );
+          myvals.addDerivative( ider, n, dfframes[frameno]*ader[0] ); n++;
+          myvals.addDerivative( ider, n, dfframes[frameno]*ader[1] ); n++;
+          myvals.addDerivative( ider, n, dfframes[frameno]*ader[2] ); n++;
           tmpvir += -1.0*Tensor( getPosition(i), ader );
       }
-      Tensor vir; 
+      Tensor vir;
       if( !mymap->getVirial( cur, vir ) ) vir=tmpvir;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(0,0); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(0,1); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(0,2); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(1,0); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(1,1); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(1,2); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(2,0); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(2,1); n++;
-      buffer[start+n*stride] += df*dfframes[frameno]*vir(2,2); 
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(0,0) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(0,1) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(0,2) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(1,0) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(1,1) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(1,2) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(2,0) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(2,1) ); n++;
+      myvals.addDerivative( ider, n, dfframes[frameno]*vir(2,2) );
   }
 }
 
diff --git a/src/mapping/Mapping.h b/src/mapping/Mapping.h
index f5e8a13f0bc97170cc5585a369e82755e5005439..25ab9dad96eb7d0dcb5d3eeb09dc8c8133338d1e 100644
--- a/src/mapping/Mapping.h
+++ b/src/mapping/Mapping.h
@@ -58,7 +58,9 @@ protected:
 /// Store the distance function
   void storeDistanceFunction( const unsigned& ifunc );
 /// Get the value of the weight
-  double getWeight() const ;
+  double getWeight( const unsigned& weight ) const ;
+/// Transfer the derivatives to a MultiValue object
+  void transferDerivatives( const unsigned& ider, const unsigned& fno, const unsigned& cur, vesselbase::MultiValue& myvals );
 public:
   static void registerKeywords( Keywords& keys );
   Mapping(const ActionOptions&);
@@ -85,11 +87,7 @@ public:
 /// Get the name of the ith argument
   std::string getArgumentName( unsigned& iarg );
 /// Get the value of the ith property for the current frame
-  double getPropertyValue( const unsigned& iprop ) const ;
-/// Return the current value of the high dimensional function
-  double getCurrentHighDimFunctionValue( const unsigned& ider ) const ;
-/// Perform chain rule for derivatives
-  void mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer );
+  double getPropertyValue( const unsigned& current, const unsigned& iprop ) const ;
 /// Stuff to do before we do the calculation
   void prepare();
 /// Apply the forces 
@@ -131,20 +129,14 @@ std::string Mapping::getPropertyName( const unsigned& iprop ) const {
 }
 
 inline
-double Mapping::getPropertyValue( const unsigned& iprop ) const {
+double Mapping::getPropertyValue( const unsigned& cur, const unsigned& iprop ) const {
   plumed_dbg_assert( iprop<getNumberOfProperties() );
-  return mymap->getPropertyValue( getCurrentTask(), iprop ); 
+  return mymap->getPropertyValue( cur, iprop ); 
 }
 
 inline
-double Mapping::getWeight() const {
-  return mymap->getWeight( getCurrentTask() ); 
-}
-
-inline 
-double Mapping::getCurrentHighDimFunctionValue( const unsigned& ider ) const {
-  plumed_dbg_assert( ider<2 );
-  return fframes[ider*getNumberOfReferencePoints() + getCurrentTask()];
+double Mapping::getWeight( const unsigned& current ) const {
+  return mymap->getWeight( current ); 
 }
 
 inline
diff --git a/src/mapping/PathBase.cpp b/src/mapping/PathBase.cpp
index eeb4f98896597c2a136bdfbb2752def722e164cc..789edae8e310fcb4b3577b8aae1cf93eefa3b7db 100644
--- a/src/mapping/PathBase.cpp
+++ b/src/mapping/PathBase.cpp
@@ -55,11 +55,12 @@ void PathBase::calculate(){
   runAllTasks();
 }
 
-void PathBase::performTask(){
+void PathBase::performTask( const unsigned& task_index, const unsigned& current, vesselbase::MultiValue& myvals ){
   // Calculate the distance from the frame
-  double val=calculateDistanceFunction( getCurrentTask(), true );
+  double val=calculateDistanceFunction( current, true );
   // Put the element value in element zero
-  setElementValue( 1, val ); setElementValue( 0, 1.0 );
+  myvals.setValue( 0, val ); myvals.setValue( 1, 1.0 );
+  transferDerivatives( 0, 0, current, myvals ); 
   return;
 }
 
diff --git a/src/mapping/PathBase.h b/src/mapping/PathBase.h
index 541c864dcc2f6d42379ed254201487056c527018..238a80d07b074e4984d4a02fb13733b31851a296 100644
--- a/src/mapping/PathBase.h
+++ b/src/mapping/PathBase.h
@@ -35,7 +35,7 @@ public:
   PathBase(const ActionOptions&);
   double getLambda();
   void calculate();
-  void performTask();
+  void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& );
   double transformHD( const double& dist, double& df );
 };
 
diff --git a/src/mapping/SpathVessel.cpp b/src/mapping/SpathVessel.cpp
index ee157ca5d8cdd78f86c0aa98162b33a3927a2d1d..525244eb2fc36b68638ce0225554f98fe9d2a5d9 100644
--- a/src/mapping/SpathVessel.cpp
+++ b/src/mapping/SpathVessel.cpp
@@ -30,6 +30,7 @@ class SpathVessel : public vesselbase::FunctionVessel {
 private:
   bool foundoneclose;
   unsigned mycoordnumber;
+  unsigned nderiv;
   Mapping* mymap;
 public:
   static void registerKeywords( Keywords& keys );
@@ -37,7 +38,7 @@ public:
   SpathVessel( const vesselbase::VesselOptions& da );
   std::string function_description();
   void prepare();
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer );
 };
 
 PLUMED_REGISTER_VESSEL(SpathVessel,"SPATH")
@@ -58,7 +59,11 @@ FunctionVessel(da)
   plumed_massert( mymap, "SpathVessel can only be used with mappings");
   // Retrieve the index of the property in the underlying mapping
   mycoordnumber=mymap->getPropertyIndex( getLabel() ); 
-  usetol=true; norm=true;
+  usetol=true; norm=true; nderiv=mymap->getNumberOfDerivatives();
+
+  for(unsigned i=0;i<mymap->getFullNumberOfTasks();++i){
+     if( mymap->getTaskCode(i)!=mymap->getPositionInFullTaskList(i) ) error("mismatched tasks and codes");
+  }
 }
 
 std::string SpathVessel::function_description(){
@@ -69,9 +74,15 @@ void SpathVessel::prepare(){
   foundoneclose=false;
 }
 
-bool SpathVessel::calculate( std::vector<double>& buffer ){
-  double pp=mymap->getPropertyValue( mycoordnumber );
-  return addToBuffers( pp, 0.0, buffer );
+bool SpathVessel::calculate( const unsigned& current, vesselbase::MultiValue& myvals, std::vector<double>& buffer ){
+  double pp=mymap->getPropertyValue( current, mycoordnumber ), weight=myvals.get(0);
+  if( weight<getTolerance() ) return false;
+  buffer[bufstart] += weight*pp; buffer[bufstart+1+nderiv] += weight; 
+  if( getAction()->derivativesAreRequired() ){
+     myvals.chainRule( 0, 0, 1, 0, pp, bufstart, buffer );
+     myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer );
+  }
+  return true;
 }
 
 }
diff --git a/src/mapping/ZpathVessel.cpp b/src/mapping/ZpathVessel.cpp
index c01e52255d2c8f0619a062066ea1c196770ebfd9..c5ee11d54c8121a674a14ae5501cec3ec6c2de6b 100644
--- a/src/mapping/ZpathVessel.cpp
+++ b/src/mapping/ZpathVessel.cpp
@@ -34,7 +34,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   ZpathVessel( const vesselbase::VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
   double finalTransform( const double& val, double& dv );
 };
 
@@ -61,8 +61,8 @@ std::string ZpathVessel::function_description(){
   return "the distance from the low-dimensional manifold";
 }
 
-bool ZpathVessel::calculate( std::vector<double>& buffer ){
-  return addToBuffers( 1.0, 0.0, buffer );
+double ZpathVessel::calcTransform( const double& val, double& dv ){
+  dv=0.0; return 1.0;
 }
 
 double ZpathVessel::finalTransform( const double& val, double& dv ){
diff --git a/src/multicolvar/ActionVolume.cpp b/src/multicolvar/ActionVolume.cpp
index a51ba9e094bc55d790a7299eb94e5b79e625a430..2ef73aec2bce36a17fca94e101c9071ea730cddf 100644
--- a/src/multicolvar/ActionVolume.cpp
+++ b/src/multicolvar/ActionVolume.cpp
@@ -39,9 +39,9 @@ Action(ao),
 VolumeGradientBase(ao)
 {
   // Find number of quantities
-  if( getPntrToMultiColvar()->isDensity() ) nquantities=5;                           // Value + catom + weight 
-  else if( getPntrToMultiColvar()->getNumberOfQuantities()==5 ) nquantities=5;       // Value + catom + weight
-  else nquantities = 1 + 3 + getPntrToMultiColvar()->getNumberOfQuantities()-5 + 1;  // Norm + catom + vector + weight 
+  if( getPntrToMultiColvar()->isDensity() ) nquantities=2;                           // Value + weight 
+  else if( getPntrToMultiColvar()->getNumberOfQuantities()==2 ) nquantities=2;       // Value + weight
+  else nquantities = 1 + getPntrToMultiColvar()->getNumberOfQuantities()-2 + 1;      // Norm  + vector + weight 
 
   // Output some nice information
   std::string functype=getPntrToMultiColvar()->getName();
@@ -61,13 +61,16 @@ VolumeGradientBase(ao)
   }
 }
 
-void ActionVolume::calculateAllVolumes(){
-  Vector catom_pos=getPntrToMultiColvar()->retrieveCentralAtomPos();
+void ActionVolume::calculateAllVolumes( const unsigned& curr, vesselbase::MultiValue& outvals ){
+  Vector catom_pos=getPntrToMultiColvar()->getCentralAtomPos( curr );
 
-  double weight; Vector wdf; 
-  weight=calculateNumberInside( catom_pos, bead, wdf ); 
-  if( not_in ){ weight = 1.0 - weight; wdf *= -1.; }  
-  setNumberInVolume( nquantities-1, weight, wdf );
+  double weight; Vector wdf; Tensor vir; std::vector<Vector> refders( getNumberOfAtoms() );  
+  weight=calculateNumberInside( catom_pos, bead, wdf, vir, refders ); 
+  if( not_in ){ 
+    weight = 1.0 - weight; wdf *= -1.; vir *=-1; 
+    for(unsigned i=0;i<refders.size();++i) refders[i]*=-1;
+  }  
+  setNumberInVolume( 0, curr, weight, wdf, vir, refders, outvals );
 }
 
 }
diff --git a/src/multicolvar/ActionVolume.h b/src/multicolvar/ActionVolume.h
index 72a40810ad06fb271e883935a3ae6f40afcf5125..10a459b341b19d594fd36fc20c409b03a0d93f1a 100644
--- a/src/multicolvar/ActionVolume.h
+++ b/src/multicolvar/ActionVolume.h
@@ -47,18 +47,14 @@ private:
   HistogramBead bead;
 protected:
   double getSigma() const ;
-  void addReferenceAtomDerivatives( const unsigned& iatom, const Vector& der );
-  void addBoxDerivatives( const Tensor& vir );
 public:
   static void registerKeywords( Keywords& keys );
   ActionVolume(const ActionOptions&);
 /// Get the number of quantities that are calculated each time
   virtual unsigned getNumberOfQuantities();
 /// Calculate whats in the volume
-  void calculateAllVolumes();
-  virtual double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives )=0;
-  double getValueForTolerance();
-  unsigned getIndexOfWeight();
+  void calculateAllVolumes( const unsigned& curr, vesselbase::MultiValue& outvals );
+  virtual double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders )=0;
   unsigned getCentralAtomElementIndex();
 };
 
@@ -72,28 +68,6 @@ double ActionVolume::getSigma() const {
   return sigma;
 }
 
-inline
-void ActionVolume::addReferenceAtomDerivatives( const unsigned& iatom, const Vector& der ){
-  if( not_in ) VolumeGradientBase::addReferenceAtomDerivatives( nquantities-1, iatom, -1.0*der );
-  else VolumeGradientBase::addReferenceAtomDerivatives( nquantities-1, iatom, der );
-}
-
-inline 
-void ActionVolume::addBoxDerivatives( const Tensor& vir ){
-  if( not_in ) VolumeGradientBase::addBoxDerivatives( nquantities-1, -1.0*vir );
-  else VolumeGradientBase::addBoxDerivatives( nquantities-1, vir );
-}
-
-inline
-double ActionVolume::getValueForTolerance(){
-  return getElementValue( nquantities-1 );
-}
-
-inline
-unsigned ActionVolume::getIndexOfWeight(){
-  return nquantities-1;
-}
-
 inline
 unsigned ActionVolume::getCentralAtomElementIndex(){
  return 1;
diff --git a/src/multicolvar/AdjacencyMatrixAction.cpp b/src/multicolvar/AdjacencyMatrixAction.cpp
index eb9af257a1be05c6abf86cc8e2ecb7ecc458e069..0b2664b6467f8a0b8f802dc66befe025a004554b 100644
--- a/src/multicolvar/AdjacencyMatrixAction.cpp
+++ b/src/multicolvar/AdjacencyMatrixAction.cpp
@@ -37,8 +37,8 @@ Action(ao),
 MultiColvarFunction(ao),
 tmpdf(1)
 {
+  use_orient=false;
   if( keywords.exists("USE_ORIENTATION") ) parseFlag("USE_ORIENTATION",use_orient);
-  else use_orient=true;
   // Weight of this does have derivatives
   weightHasDerivatives=true;
   // Read in the switching function
@@ -78,6 +78,9 @@ tmpdf(1)
 
   // Build atom lists
   buildAtomListWithPairs( true );
+
+  if( use_orient && getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) error("using orientation but no orientations in base colvars"); 
+
   // Build active elements array
   for(unsigned i=0;i<getFullNumberOfTasks();++i) active_elements.addIndexToList( i );
   active_elements.setupMPICommunication( comm );
@@ -102,10 +105,6 @@ tmpdf(1)
   addVessel( mat );
   // And resize everything
   resizeFunctions();
-
-  // One component for regular multicolvar and nelements for vectormulticolvar
-  unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities() - 5;;
-  orient0.resize( ncomp ); orient1.resize( ncomp );
 }
 
 void AdjacencyMatrixAction::doJobsRequiredBeforeTaskList(){
@@ -118,22 +117,24 @@ void AdjacencyMatrixAction::doJobsRequiredBeforeTaskList(){
   else dertime=true;
 }
 
-void AdjacencyMatrixAction::calculateWeight(){
-  Vector distance = getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(1) );
-  double dfunc, sw = switchingFunction( getBaseColvarNumber(0),getBaseColvarNumber(1) ).calculate( distance.modulo(), dfunc );
-  setElementValue(1,sw);
+void AdjacencyMatrixAction::calculateWeight( AtomValuePack& myatoms ){
+  Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
+  double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ),getBaseColvarNumber( myatoms.getIndex(1) ) ).calculate( distance.modulo(), dfunc );
+  myatoms.setValue(0,sw);
 }
 
-double AdjacencyMatrixAction::compute(){
-  active_elements.activate( getCurrentPositionInTaskList() );
+double AdjacencyMatrixAction::compute( const unsigned& tindex, AtomValuePack& myatoms ){
+  active_elements.activate( tindex );
 
-  double f_dot, dot_df;
+  double f_dot, dot_df; 
+  unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities();
+  std::vector<double> orient0(ncomp), orient1(ncomp);
   if( use_orient ){
-      getVectorForBaseTask( 0, orient0 );
-      getVectorForBaseTask( 1, orient1 );   
+      getVectorForTask( myatoms.getIndex(0), true, orient0 );
+      getVectorForTask( myatoms.getIndex(1), true, orient1 );      
 
       double dot; dot=0;
-      for(unsigned k=0;k<orient0.size();++k) dot+=orient0[k]*orient1[k];
+      for(unsigned k=2;k<orient0.size();++k) dot+=orient0[k]*orient1[k];
       f_dot=0.5*( 1 + dot ); dot_df=0.5;
       // Add smac stuff here if required
   } else {
@@ -141,43 +142,44 @@ double AdjacencyMatrixAction::compute(){
   }
 
   // Retrieve the weight of the connection
-  double weight = getElementValue(1); 
+  double weight = myatoms.getValue(0); 
 
   if( dertime && !doNotCalculateDerivatives() ){
      // Add contribution due to separation between atoms
-     Vector distance = getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(1) );
-     double dfunc, sw = switchingFunction( getBaseColvarNumber(0), getBaseColvarNumber(1) ).calculate( distance.modulo(), dfunc ); 
-     addCentralAtomsDerivatives( 0, 0, (-dfunc)*f_dot*distance );
-     addCentralAtomsDerivatives( 1, 0, (dfunc)*f_dot*distance );
-     MultiColvarBase::addBoxDerivatives( 0, (-dfunc)*f_dot*Tensor(distance,distance) );
+     Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
+     double dfunc, sw = switchingFunction( getBaseColvarNumber( myatoms.getIndex(0) ), getBaseColvarNumber( myatoms.getIndex(0) ) ).calculate( distance.modulo(), dfunc ); 
+     CatomPack atom0=getCentralAtomPackFromInput( myatoms.getIndex(0) );
+     myatoms.addComDerivatives( 1, (-dfunc)*f_dot*distance, atom0 );
+     CatomPack atom1=getCentralAtomPackFromInput( myatoms.getIndex(1) );
+
+     myatoms.addComDerivatives( 1, (dfunc)*f_dot*distance, atom1 );
+     myatoms.addBoxDerivatives( 1, (-dfunc)*f_dot*Tensor(distance,distance) );
 
      // And derivatives of orientation
      if( use_orient ){
-        for(unsigned k=0;k<orient0.size();++k){
+        for(unsigned k=2;k<orient0.size();++k){
            orient0[k]*=sw*dot_df; orient1[k]*=sw*dot_df;
         }
-        addOrientationDerivatives( 0, orient1 );
-        addOrientationDerivatives( 1, orient0 );
+        vesselbase::MultiValue myder0(0,0); getVectorDerivatives( myatoms.getIndex(0), true, myder0 );
+        mergeVectorDerivatives( 1, 2, orient1.size(), myatoms.getIndex(0), orient1, myder0, myatoms );
+        vesselbase::MultiValue myder1(0,0); getVectorDerivatives( myatoms.getIndex(1), true, myder1 );
+        mergeVectorDerivatives( 1, 2, orient0.size(), myatoms.getIndex(1), orient0, myder1, myatoms );
      }
   }
   return weight*f_dot;
 }
 
-void AdjacencyMatrixAction::setMatrixIndexesForTask( const unsigned& ii ){
-  unsigned icolv = active_elements[ii], tcode = getTaskCode( icolv );
-  bool check = MultiColvarBase::setupCurrentAtomList( tcode );
-  plumed_assert( check );
-}
-
 void AdjacencyMatrixAction::retrieveMatrix( Matrix<double>& mymatrix ){
   // Gather active elements in matrix
   if(!gathered) active_elements.mpi_gatherActiveMembers( comm ); 
   gathered=true;
-  
+ 
+  std::vector<unsigned> myatoms(2); std::vector<double> vals(2);
   for(unsigned i=0;i<active_elements.getNumberActive();++i){
-      setMatrixIndexesForTask( i );
-      unsigned j = current_atoms[1], k = current_atoms[0];
-      mymatrix(k,j)=mymatrix(j,k)=getMatrixElement( i );
+      decodeIndexToAtoms( getTaskCode(active_elements[i]), myatoms ); 
+      unsigned j = myatoms[1], k = myatoms[0];
+      mat->retrieveValue( active_elements[i], false, vals );
+      mymatrix(k,j)=mymatrix(j,k)=vals[1];   
   }
 }
 
@@ -192,26 +194,14 @@ void AdjacencyMatrixAction::retrieveAdjacencyLists( std::vector<unsigned>& nneig
   for(unsigned i=0;i<nneigh.size();++i) nneigh[i]=0;
 
   // And set up the adjacency list
+  std::vector<unsigned> myatoms(2);
   for(unsigned i=0;i<active_elements.getNumberActive();++i){
-      setMatrixIndexesForTask( i );
-      unsigned j = current_atoms[1], k = current_atoms[0];
+      decodeIndexToAtoms( getTaskCode(active_elements[i]), myatoms );
+      unsigned j = myatoms[1], k = myatoms[0];
       adj_list(k,nneigh[k])=j; nneigh[k]++;
       adj_list(j,nneigh[j])=k; nneigh[j]++;
   } 
 } 
 
-void AdjacencyMatrixAction::addDerivativesOnMatrixElement( const unsigned& ielem, const unsigned& jrow, const double& df, Matrix<double>& der ){
-  plumed_dbg_assert( ielem<active_elements.getNumberActive() );
-  tmpdf[0]=df; unsigned jelem=active_elements[ielem];
-
-  if( usingLowMem() ){
-     mat->recompute( jelem, 0 ); mat->chainRule( 0, tmpdf );
-     for(unsigned i=0;i<mat->getNumberOfDerivatives(0);++i) der( jrow, mat->getStoredIndex(0,i) ) += mat->getFinalDerivative(i);
-  } else {
-     mat->chainRule( jelem, tmpdf );
-     for(unsigned i=0;i<mat->getNumberOfDerivatives(jelem);++i) der( jrow, mat->getStoredIndex(jelem,i) ) += mat->getFinalDerivative(i);
-  }
-}
-
 }
 }
diff --git a/src/multicolvar/AdjacencyMatrixAction.h b/src/multicolvar/AdjacencyMatrixAction.h
index eb0d3ee0a23713ec4067140c31135dc704ce06e5..e397e89c0a62a1f684695a9c682f7f10c4d394ad 100644
--- a/src/multicolvar/AdjacencyMatrixAction.h
+++ b/src/multicolvar/AdjacencyMatrixAction.h
@@ -40,7 +40,7 @@ private:
 /// This is the vessel that stores the adjacency matrix
   AdjacencyMatrixVessel* mat;
 ///  Tempory vectors for storing vectors
-  std::vector<double> tmpdf, orient0, orient1;
+  std::vector<double> tmpdf;
 /// switching function
   Matrix<SwitchingFunction> switchingFunction;
 /// Which matrix elements have value
@@ -57,15 +57,15 @@ protected:
   unsigned getNumberOfActiveMatrixElements();
 /// Put the indices of the matrix elements in current atoms
   void setMatrixIndexesForTask( const unsigned& ii );
-/// Get an element of the adjacency matrix
-  double getMatrixElement( const unsigned& ielem ) const ;
+/// Get the matrix elements that are active
+  unsigned getActiveMatrixElement( const unsigned& ival ) const ;
 /// Add derivatives to a matrix element
   void addDerivativesOnMatrixElement( const unsigned& ielem, const unsigned& jrow, const double& df, Matrix<double>& der );
 public:
   static void registerKeywords( Keywords& keys );
   AdjacencyMatrixAction(const ActionOptions&);
-  double compute();
-  void calculateWeight();
+  double compute( const unsigned& tindex, AtomValuePack& myatoms );
+  void calculateWeight( AtomValuePack& myatoms );
   void doJobsRequiredBeforeTaskList();
 /// Finish the calculation
   virtual void completeCalculation()=0;
@@ -81,13 +81,14 @@ unsigned AdjacencyMatrixAction::getNumberOfActiveMatrixElements(){
 }
 
 inline
-double AdjacencyMatrixAction::getMatrixElement( const unsigned& ielem ) const {
-  return mat->getComponent( active_elements[ielem], 0 );
+AdjacencyMatrixVessel* AdjacencyMatrixAction::getAdjacencyVessel(){
+  return mat;
 }
 
 inline
-AdjacencyMatrixVessel* AdjacencyMatrixAction::getAdjacencyVessel(){
-  return mat;
+unsigned AdjacencyMatrixAction::getActiveMatrixElement( const unsigned& ival ) const {
+  plumed_dbg_assert( ival<active_elements.getNumberActive() );
+  return active_elements[ival];
 }
 
 }
diff --git a/src/multicolvar/AdjacencyMatrixVessel.cpp b/src/multicolvar/AdjacencyMatrixVessel.cpp
index b80706788391419dab487bf24f6ba91a1770d845..44cab0b72e306d282c136b414178f23299daba7c 100644
--- a/src/multicolvar/AdjacencyMatrixVessel.cpp
+++ b/src/multicolvar/AdjacencyMatrixVessel.cpp
@@ -31,12 +31,10 @@ void AdjacencyMatrixVessel::registerKeywords( Keywords& keys ){
 }
 
 AdjacencyMatrixVessel::AdjacencyMatrixVessel( const vesselbase::VesselOptions& da ):
-StoreDataVessel(da),
-tmpdf(1)
+StoreDataVessel(da)
 {
   function=dynamic_cast<AdjacencyMatrixAction*>( getAction() );
   plumed_assert( function );
-  completeSetup( 0, 1 ); nrows = function->getFullNumberOfTasks();
 }
 
 void AdjacencyMatrixVessel::prepare(){
@@ -48,19 +46,6 @@ void AdjacencyMatrixVessel::setFinishedTrue(){
   finished=true;
 }
 
-void AdjacencyMatrixVessel::recompute( const unsigned& ivec, const unsigned& jstore ){
-  plumed_dbg_assert( function->usingLowMem() && function->dertime );
-  
-  // Set the task we want to reperform
-  setTaskToRecompute( ivec );
-  // Reperform the task
-  if( function->dertime ){
-     function->performTask();
-     storeDerivativesLowMem( jstore );
-     function->clearAfterTask();
-  }
-} 
-
 void AdjacencyMatrixVessel::finish( const std::vector<double>& buffer ){
   if( !finished ){
      finished=true;
diff --git a/src/multicolvar/AdjacencyMatrixVessel.h b/src/multicolvar/AdjacencyMatrixVessel.h
index 38c64e61d77d9418ee046aa9ed86f07df4d0d15c..c78b790e39d987bf61e55e16a7ff5af9651cee29 100644
--- a/src/multicolvar/AdjacencyMatrixVessel.h
+++ b/src/multicolvar/AdjacencyMatrixVessel.h
@@ -32,36 +32,22 @@ class AdjacencyMatrixAction;
 class AdjacencyMatrixVessel : public vesselbase::StoreDataVessel {
 friend class VectorMultiColvar;
 private:
-  unsigned nrows;
 /// Pointer to underlying action
   AdjacencyMatrixAction* function;
 /// Has the vessel been finished
   bool finished;
-/// Tempory vector for chain rule
-  std::vector<double> tmpdf;
 public:
   static void registerKeywords( Keywords& keys );
 /// Constructor
   AdjacencyMatrixVessel( const vesselbase::VesselOptions& );
 /// Ensures that finish is set properly
   void prepare();
-/// This does nothing
-  std::string description(){ return ""; }
-/// This recomputes the colvar
-  void recompute( const unsigned& ivec, const unsigned& jstore );
-/// Get the i,j th element of the matrix
-  double getElement( const unsigned& ivec ); 
 /// Set the finished flag true
   void setFinishedTrue();
 /// Finish the calculation
   void finish( const std::vector<double>& buffer );
 };
 
-inline
-double AdjacencyMatrixVessel::getElement( const unsigned& ivec ){
-  return getComponent( ivec, 0 );
-} 
-
 }
 }
 #endif
diff --git a/src/multicolvar/AlphaBeta.cpp b/src/multicolvar/AlphaBeta.cpp
index 139cfa1d86b7de4033a282aa692e617c6adf00bd..085fd49c123d609300a0976aeb85ccc9365a2c5f 100644
--- a/src/multicolvar/AlphaBeta.cpp
+++ b/src/multicolvar/AlphaBeta.cpp
@@ -98,9 +98,8 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   AlphaBeta(const ActionOptions&);
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();  
 };
 
 PLUMED_REGISTER_ACTION(AlphaBeta,"ALPHABETA")
@@ -120,6 +119,10 @@ PLUMED_MULTICOLVAR_INIT(ao)
   int natoms=4; readAtoms( natoms );
   // Resize target
   target.resize( getFullNumberOfTasks() );
+  // Setup central atom indices
+  std::vector<bool> catom_ind(4, false); 
+  catom_ind[1]=catom_ind[2]=true;
+  setAtomsForCentralAtom( catom_ind );
 
   // Read in reference values
   unsigned ntarget=0;
@@ -145,16 +148,15 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double AlphaBeta::compute(){
+double AlphaBeta::compute( const unsigned& tindex, AtomValuePack& myatoms ){
   Vector d0,d1,d2;
-  d0=getSeparation(getPosition(1),getPosition(0));
-  d1=getSeparation(getPosition(2),getPosition(1));
-  d2=getSeparation(getPosition(3),getPosition(2));
+  d0=getSeparation(myatoms.getPosition(1),myatoms.getPosition(0));
+  d1=getSeparation(myatoms.getPosition(2),myatoms.getPosition(1));
+  d2=getSeparation(myatoms.getPosition(3),myatoms.getPosition(2));
 
   Vector dd0,dd1,dd2;
   PLMD::Torsion t;
   double value  = t.compute(d0,d1,d2,dd0,dd1,dd2);
-  unsigned tindex = getCurrentPositionInTaskList();
   double svalue = -0.5*sin(value-target[tindex]);
   double cvalue = 1.+cos(value-target[tindex]);
 
@@ -163,21 +165,15 @@ double AlphaBeta::compute(){
   dd2 *= svalue;
   value = 0.5*cvalue;
 
-  addAtomsDerivatives(0,dd0);
-  addAtomsDerivatives(1,dd1-dd0);
-  addAtomsDerivatives(2,dd2-dd1);
-  addAtomsDerivatives(3,-dd2);
+  myatoms.addAtomsDerivatives(1, 0,dd0);
+  myatoms.addAtomsDerivatives(1, 1,dd1-dd0);
+  myatoms.addAtomsDerivatives(1, 2,dd2-dd1);
+  myatoms.addAtomsDerivatives(1, 3,-dd2);
 
-  addBoxDerivatives  (-(extProduct(d0,dd0)+extProduct(d1,dd1)+extProduct(d2,dd2)));
+  myatoms.addBoxDerivatives(1, -(extProduct(d0,dd0)+extProduct(d1,dd1)+extProduct(d2,dd2)));
 
   return value;
 }
 
-Vector AlphaBeta::getCentralAtom(){
-   addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
-   addCentralAtomDerivatives( 2, 0.5*Tensor::identity() );
-   return 0.5*( getPosition(1) + getPosition(2) );
-}
-
 }
 }
diff --git a/src/multicolvar/Angles.cpp b/src/multicolvar/Angles.cpp
index 203d185f3c478188bb259371c4a719e73fcfd0c8..5d412c9fe8329f5751e6fcfc26c5816d9ce22edd 100644
--- a/src/multicolvar/Angles.cpp
+++ b/src/multicolvar/Angles.cpp
@@ -94,11 +94,10 @@ public:
   static void registerKeywords( Keywords& keys );
   Angles(const ActionOptions&);
 /// Updates neighbor list
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& );
 /// Returns the number of coordinates of the field
-  void calculateWeight();
+  void calculateWeight( AtomValuePack& );
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();
 };
 
 PLUMED_REGISTER_ACTION(Angles,"ANGLES")
@@ -165,48 +164,46 @@ use_sf(false)
 
   // And check everything has been read in correctly
   checkRead();
+  // Setup stuff for central atom
+  std::vector<bool> catom_ind(3, false); catom_ind[0]=true;
+  setAtomsForCentralAtom( catom_ind );
 }
 
-void Angles::calculateWeight(){
-  dij=getSeparation( getPosition(0), getPosition(2) );
-  dik=getSeparation( getPosition(0), getPosition(1) );
-  if(!use_sf){ setWeight(1.0); return; }
+void Angles::calculateWeight( AtomValuePack& myatoms ){
+  dij=getSeparation( myatoms.getPosition(0), myatoms.getPosition(2) );
+  dik=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
+  if(!use_sf){ myatoms.setValue( 0, 1.0 ); return; }
 
   double w1, w2, dw1, dw2, wtot;
   double ldij = dij.modulo2(), ldik = dik.modulo2(); 
 
   if( use_sf ){
-     if( ldij>rcut2_1 || ldik>rcut2_2 ){ setWeight(0.0); return; }
+     if( ldij>rcut2_1 || ldik>rcut2_2 ){ myatoms.setValue(0,0.0); return; }
   }
 
   w1=sf1.calculateSqr( ldij, dw1 );
   w2=sf2.calculateSqr( ldik, dw2 );
   wtot=w1*w2; dw1*=w2; dw2*=w1; 
 
-  setWeight( wtot );
-  addAtomsDerivativeOfWeight( 1, dw2*dik );
-  addAtomsDerivativeOfWeight( 0, -dw1*dij - dw2*dik ); 
-  addAtomsDerivativeOfWeight( 2, dw1*dij );
-  addBoxDerivativesOfWeight( (-dw1)*Tensor(dij,dij) + (-dw2)*Tensor(dik,dik) );
+  myatoms.setValue( 0, wtot );
+  myatoms.addAtomsDerivatives( 0, 1, dw2*dik );
+  myatoms.addAtomsDerivatives( 0, 0, -dw1*dij - dw2*dik ); 
+  myatoms.addAtomsDerivatives( 0, 2, dw1*dij );
+  myatoms.addBoxDerivatives( 0, (-dw1)*Tensor(dij,dij) + (-dw2)*Tensor(dik,dik) );
 }
 
-double Angles::compute(){
+double Angles::compute( const unsigned& tindex, AtomValuePack& myatoms ){
   Vector ddij,ddik; PLMD::Angle a; 
   double angle=a.compute(dij,dik,ddij,ddik);
 
   // And finish the calculation
-  addAtomsDerivatives( 1, ddik );
-  addAtomsDerivatives( 0, - ddik - ddij );
-  addAtomsDerivatives( 2, ddij );
-  addBoxDerivatives( -(Tensor(dij,ddij)+Tensor(dik,ddik)) );
+  myatoms.addAtomsDerivatives( 1, 1, ddik );
+  myatoms.addAtomsDerivatives( 1, 0, - ddik - ddij );
+  myatoms.addAtomsDerivatives( 1, 2, ddij );
+  myatoms.addBoxDerivatives( 1, -(Tensor(dij,ddij)+Tensor(dik,ddik)) );
 
   return angle;
 }
 
-Vector Angles::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
diff --git a/src/multicolvar/AtomValuePack.cpp b/src/multicolvar/AtomValuePack.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a42dab9a8946ec6a60b8ffd7faf057f0e43689dd
--- /dev/null
+++ b/src/multicolvar/AtomValuePack.cpp
@@ -0,0 +1,58 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2011-2014 The plumed team
+   (see the PEOPLE file at the root of the distribution for a list of names)
+
+   See http://www.plumed-code.org for more information.
+
+   This file is part of plumed, version 2.
+
+   plumed is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   plumed is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#include "AtomValuePack.h"
+#include "CatomPack.h"
+
+namespace PLMD {
+namespace multicolvar {
+
+AtomValuePack::AtomValuePack( vesselbase::MultiValue& vals, MultiColvarBase* mcolv ):
+myvals(vals),
+mycolv(mcolv)
+{
+  indices.resize( mycolv->getNumberOfDerivatives() );
+}
+
+void AtomValuePack::updateUsingIndices(){
+  if( myvals.updateComplete() ) return;
+  myvals.emptyActiveMembers();
+  for(unsigned i=0;i<natoms;++i){ 
+     myvals.updateIndex( 3*indices[i] + 0 ); 
+     myvals.updateIndex( 3*indices[i] + 1 ); 
+     myvals.updateIndex( 3*indices[i] + 2 );
+  }
+  unsigned nvir=3*mycolv->getNumberOfAtoms();
+  for(unsigned i=0;i<9;++i) myvals.updateIndex( nvir + i );
+  myvals.sortActiveList();
+}
+
+void AtomValuePack::addComDerivatives( const unsigned& ind, const Vector& der, CatomPack& catom_der ){
+  for(unsigned ider=0;ider<catom_der.getNumberOfAtomsWithDerivatives();++ider){
+      unsigned jder=3*catom_der.getIndex(ider);
+      myvals.addDerivative( ind, jder+0, catom_der.getDerivative(ider,0,der) );
+      myvals.addDerivative( ind, jder+1, catom_der.getDerivative(ider,1,der) );
+      myvals.addDerivative( ind, jder+2, catom_der.getDerivative(ider,2,der) );
+  }
+}
+
+}
+}
diff --git a/src/multicolvar/AtomValuePack.h b/src/multicolvar/AtomValuePack.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffe0bbe0f6be42e639b764ba71ca6cd2077b0b82
--- /dev/null
+++ b/src/multicolvar/AtomValuePack.h
@@ -0,0 +1,151 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2011-2014 The plumed team
+   (see the PEOPLE file at the root of the distribution for a list of names)
+
+   See http://www.plumed-code.org for more information.
+
+   This file is part of plumed, version 2.
+
+   plumed is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   plumed is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_multicolvar_AtomValuePack_h
+#define __PLUMED_multicolvar_AtomValuePack_h
+
+#include "vesselbase/MultiValue.h"
+#include "MultiColvarBase.h"
+
+namespace PLMD {
+namespace multicolvar {
+
+class CatomPack;
+
+class AtomValuePack {
+private:
+/// Copy of the values that we are adding to
+  vesselbase::MultiValue& myvals;
+/// Copy of the underlying multicolvar
+  MultiColvarBase* mycolv;
+/// Number of atoms at the moment
+  unsigned natoms;
+/// Atom indices
+  std::vector<unsigned> indices;
+public:
+  AtomValuePack( vesselbase::MultiValue& vals, MultiColvarBase* mcolv );
+/// Set the number of atoms
+  void setNumberOfAtoms( const unsigned& );
+/// Set the index for one of the atoms
+  void setIndex( const unsigned& , const unsigned& );
+///
+  unsigned getIndex( const unsigned& j ) const ;
+///
+  unsigned getNumberOfAtoms() const ;
+/// Get the position of the ith atom
+  Vector getPosition( const unsigned& );
+///
+  void setValue( const unsigned& , const double& );
+///
+  void addValue( const unsigned& ival, const double& vv );
+///
+  double getValue( const unsigned& ) const ;
+///
+  void addDerivative( const unsigned& , const unsigned& , const double& );
+///
+  void addAtomsDerivatives( const unsigned& , const unsigned& , const Vector& );
+///
+  void addBoxDerivatives( const unsigned& , const Tensor& );
+///
+  void updateUsingIndices();
+///
+  void updateDynamicList();
+///
+  void addComDerivatives( const unsigned& , const Vector& , CatomPack& );
+///
+  vesselbase::MultiValue& getUnderlyingMultiValue();
+};
+
+inline
+void AtomValuePack::setNumberOfAtoms( const unsigned& nat ){
+  natoms=nat;
+}
+
+inline
+unsigned AtomValuePack::getNumberOfAtoms() const {
+  return natoms;
+}
+
+inline
+void AtomValuePack::setIndex( const unsigned& j, const unsigned& ind ){
+  plumed_dbg_assert( j<natoms ); indices[j]=ind; 
+}
+
+inline
+unsigned AtomValuePack::getIndex( const unsigned& j ) const {
+  plumed_dbg_assert( j<natoms ); return indices[j];
+}
+
+inline
+Vector AtomValuePack::getPosition( const unsigned& iatom ){
+  plumed_dbg_assert( iatom<natoms );
+  return mycolv->getPositionOfAtomForLinkCells( indices[iatom] );
+}
+
+inline
+void AtomValuePack::setValue( const unsigned& ival, const double& vv ){
+  myvals.setValue( ival, vv );
+}
+
+inline
+void AtomValuePack::addValue( const unsigned& ival, const double& vv ){
+  myvals.addValue( ival, vv );
+}
+
+inline
+double AtomValuePack::getValue( const unsigned& ival ) const {
+  return myvals.get( ival );
+}
+
+inline
+void AtomValuePack::addDerivative( const unsigned& ival, const unsigned& jder, const double& der ){
+  myvals.addDerivative( ival, jder, der ); 
+}
+
+inline
+void AtomValuePack::addAtomsDerivatives( const unsigned& ival, const unsigned& jder, const Vector& der ){
+  plumed_dbg_assert( jder<natoms );
+  myvals.addDerivative( ival, 3*indices[jder] + 0, der[0] );
+  myvals.addDerivative( ival, 3*indices[jder] + 1, der[1] );
+  myvals.addDerivative( ival, 3*indices[jder] + 2, der[2] );
+}
+
+inline
+void AtomValuePack::addBoxDerivatives( const unsigned& ival , const Tensor& vir ){
+  unsigned nvir=3*mycolv->getNumberOfAtoms();
+  for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) myvals.addDerivative( ival, nvir + 3*i+j, vir(i,j) );
+}
+
+inline
+void AtomValuePack::updateDynamicList(){
+  if( myvals.updateComplete() ) return;
+  myvals.updateDynamicList();
+}
+
+inline
+vesselbase::MultiValue& AtomValuePack::getUnderlyingMultiValue(){
+  return myvals;
+} 
+
+}
+}
+#endif
+
diff --git a/src/multicolvar/Bridge.cpp b/src/multicolvar/Bridge.cpp
index 6a44ef6f5bb36d7c75a7b8846cd4d3b55b628916..21ed24ecdb48d138c053e2dde56c5dbee1fb5c8c 100644
--- a/src/multicolvar/Bridge.cpp
+++ b/src/multicolvar/Bridge.cpp
@@ -68,10 +68,9 @@ public:
   static void registerKeywords( Keywords& keys );
   Bridge(const ActionOptions&);
 // active methods:
-  virtual double compute();
-  void calculateWeight();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
+  void calculateWeight( AtomValuePack& myatoms );
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();
 };
 
 PLUMED_REGISTER_ACTION(Bridge,"BRIDGE")
@@ -99,6 +98,9 @@ PLUMED_MULTICOLVAR_INIT(ao)
   if( all_atoms.size()>0 ) ActionAtomistic::requestAtoms( all_atoms );
   // Setup the multicolvar base
   setupMultiColvarBase();
+  // Setup Central atom atoms
+  std::vector<bool> catom_ind(3, false); catom_ind[0]=true;
+  setAtomsForCentralAtom( catom_ind ); 
 
   std::string sfinput,errors; parse("SWITCH",sfinput);
   if( sfinput.length()>0 ){
@@ -136,33 +138,28 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-void Bridge::calculateWeight(){
-  Vector dij=getSeparation( getPosition(0), getPosition(2) );
+void Bridge::calculateWeight( AtomValuePack& myatoms ){
+  Vector dij=getSeparation( myatoms.getPosition(0), myatoms.getPosition(2) );
   double ldij = dij.modulo2();
-  if( ldij>rcut2 ) { setWeight(0); return; }
+  if( ldij>rcut2 ) { myatoms.setValue(0,0); return; }
   double dw, w=sf2.calculateSqr( ldij, dw );
-  setWeight( w );
+  myatoms.setValue( 0, w );
 
-  addAtomsDerivativeOfWeight( 0, -dw*dij );
-  addAtomsDerivativeOfWeight( 2, dw*dij );
-  addBoxDerivativesOfWeight( (-dw)*Tensor(dij,dij) );
+  myatoms.addAtomsDerivatives( 0, 0, -dw*dij );
+  myatoms.addAtomsDerivatives( 0, 2, dw*dij );
+  myatoms.addBoxDerivatives( 0, (-dw)*Tensor(dij,dij) );
 }
 
-double Bridge::compute(){
-  Vector dik=getSeparation( getPosition(0), getPosition(1) );
+double Bridge::compute( const unsigned& tindex, AtomValuePack& myatoms ){
+  Vector dik=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
   double dw, w=sf1.calculateSqr( dik.modulo2(), dw );
 
   // And finish the calculation
-  addAtomsDerivatives( 0, -dw*dik );
-  addAtomsDerivatives( 1,  dw*dik );
-  addBoxDerivatives( (-dw)*Tensor(dik,dik) );
+  myatoms.addAtomsDerivatives( 1, 0, -dw*dik );
+  myatoms.addAtomsDerivatives( 1, 1,  dw*dik );
+  myatoms.addBoxDerivatives( 1, (-dw)*Tensor(dik,dik) );
   return w;
 }
 
-Vector Bridge::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
diff --git a/src/multicolvar/BridgedMultiColvarFunction.cpp b/src/multicolvar/BridgedMultiColvarFunction.cpp
index 4dfa3d47fcd5637fa7e64d4bca769c7309124033..1cdb192ef2183b9d40f3b9b953d417f77fff415e 100644
--- a/src/multicolvar/BridgedMultiColvarFunction.cpp
+++ b/src/multicolvar/BridgedMultiColvarFunction.cpp
@@ -46,106 +46,68 @@ MultiColvarBase(ao)
   if( checkNumericalDerivatives() ) mycolv->useNumericalDerivatives();
 
   myBridgeVessel = mycolv->addBridgingVessel( this ); addDependency(mycolv);
-  weightHasDerivatives=true;
+  weightHasDerivatives=true; usespecies=mycolv->usespecies;
   // Number of tasks is the same as the number in the underlying MultiColvar
   for(unsigned i=0;i<mycolv->getFullNumberOfTasks();++i) addTaskToList( mycolv->getTaskCode(i) );
-  // Do all setup stuff in MultiColvarBase
-  resizeLocalArrays();
 }
 
-void BridgedMultiColvarFunction::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
-  mycolv->getIndexList( ntotal, jstore, maxder, indices );
-}
-
-void BridgedMultiColvarFunction::performTask(){
-  atoms_with_derivatives.deactivateAll();
-
-  if( !myBridgeVessel->prerequisitsCalculated() ){
-      mycolv->setTaskIndexToCompute( getCurrentPositionInTaskList() );
-      mycolv->performTask();
+//void BridgedMultiColvarFunction::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
+//  mycolv->getIndexList( ntotal, jstore, maxder, indices );
+//}
+
+void BridgedMultiColvarFunction::transformBridgedDerivatives( const unsigned& current, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals ){
+  completeTask( current, invals, outvals );
+  
+  // Now update the outvals derivatives lists
+  outvals.emptyActiveMembers();
+  if( mycolv->isDensity() ){
+     for(unsigned j=0;j<3;++j) outvals.updateIndex( 3*current+j ); 
+     for(unsigned j=invals.getNumberOfDerivatives()-9;j<invals.getNumberOfDerivatives();++j) outvals.updateIndex(j);
   } else {
-
+     for(unsigned j=0;j<invals.getNumberActive();++j) outvals.updateIndex( invals.getActiveIndex(j) );
   }
-
-  completeTask();
-  atoms_with_derivatives.updateActiveMembers();
+  for(unsigned j=invals.getNumberOfDerivatives();j<outvals.getNumberOfDerivatives();++j) outvals.updateIndex( j );
+  outvals.sortActiveList(); 
 }
 
-Vector BridgedMultiColvarFunction::retrieveCentralAtomPos(){
-  if( atomsWithCatomDer.getNumberActive()==0 ){
-      Vector cvec = mycolv->retrieveCentralAtomPos();
-
-      // Copy the value and derivatives from the MultiColvar
-      atomsWithCatomDer.emptyActiveMembers();
-      for(unsigned i=0;i<3;++i){
-         setElementValue( getCentralAtomElementIndex() + i, mycolv->getElementValue( mycolv->getCentralAtomElementIndex() + i ) );
-         unsigned nbase = ( getCentralAtomElementIndex() + i)*getNumberOfDerivatives();
-         unsigned nbas2 = ( mycolv->getCentralAtomElementIndex() + i )*mycolv->getNumberOfDerivatives();
-         for(unsigned j=0;j<mycolv->atomsWithCatomDer.getNumberActive();++j){
-             unsigned n=mycolv->atomsWithCatomDer[j], nx=3*n; atomsWithCatomDer.activate(n);
-             addElementDerivative(nbase + nx + 0, mycolv->getElementDerivative(nbas2 + nx + 0) );
-             addElementDerivative(nbase + nx + 1, mycolv->getElementDerivative(nbas2 + nx + 1) );
-             addElementDerivative(nbase + nx + 2, mycolv->getElementDerivative(nbas2 + nx + 2) ); 
-         } 
-      }
-      atomsWithCatomDer.updateActiveMembers();  // This can perhaps be faster
-      return cvec;
-  }
-  Vector cvec;
-  for(unsigned i=0;i<3;++i) cvec[i]=getElementValue(1+i);
-  return cvec;
-}
+/// These two functions (commented out one underneath) are needed and are a bit tricky
+void BridgedMultiColvarFunction::performTask( const unsigned& taskIndex, const unsigned& current, vesselbase::MultiValue& myvals ){
+  //atoms_with_derivatives.deactivateAll();
 
-void BridgedMultiColvarFunction::mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer ){
-  unsigned vstart=getNumberOfDerivatives()*ider;
-  // Merge atom derivatives
-  for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-     unsigned iatom=3*atoms_with_derivatives[i];
-     buffer[start + iatom*stride ] += df*getElementDerivative(vstart+iatom); iatom++;
-     buffer[start + iatom*stride ] += df*getElementDerivative(vstart+iatom); iatom++;
-     buffer[start + iatom*stride ] += df*getElementDerivative(vstart+iatom);
-  }
-  // Merge virial derivatives
-  unsigned nvir=3*mycolv->getNumberOfAtoms();
-  for(unsigned j=0;j<9;++j){
-     buffer[start+nvir*stride] += df*getElementDerivative(vstart+nvir); nvir++;
-  }
-  // Merge local atom derivatives
-  for(unsigned j=0;j<getNumberOfAtoms();++j){
-     buffer[start + stride*nvir] += df*getElementDerivative(vstart+nvir); nvir++;
-     buffer[start + stride*nvir] += df*getElementDerivative(vstart+nvir); nvir++;
-     buffer[start + stride*nvir] += df*getElementDerivative(vstart+nvir); nvir++;
-  }
-  plumed_dbg_assert( nvir==getNumberOfDerivatives() );
-}
+  // GAT this is for recomputing - this needs to work -- how?
+  if( !myBridgeVessel->prerequisitsCalculated() ){
+      mycolv->performTask( taskIndex, current, myvals );
+  } 
 
-void BridgedMultiColvarFunction::clearDerivativesAfterTask( const unsigned& ider ){
-  unsigned vstart=getNumberOfDerivatives()*ider;
-  if( derivativesAreRequired() ){
-     // Clear atom derivatives
-     for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-        unsigned iatom=vstart+3*atoms_with_derivatives[i];
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 );
-     }
-     // Clear virial contribution
-     unsigned nvir=vstart+3*mycolv->getNumberOfAtoms();
-     for(unsigned j=0;j<9;++j){
-        setElementDerivative( nvir, 0.0 ); nvir++;
-     }
-     // Clear derivatives of local atoms
-     for(unsigned j=0;j<getNumberOfAtoms();++j){
-        setElementDerivative( nvir, 0.0 ); nvir++;
-        setElementDerivative( nvir, 0.0 ); nvir++;
-        setElementDerivative( nvir, 0.0 ); nvir++;
-     }
-     plumed_dbg_assert( (nvir-vstart)==getNumberOfDerivatives() );
-  }
-  // Clear values
-  thisval_wasset[ider]=false; setElementValue( ider, 0.0 ); thisval_wasset[ider]=false;
+  // completeTask( myvals, outvals );  -- also need this
+  //atoms_with_derivatives.updateActiveMembers();
 }
 
+// Vector BridgedMultiColvarFunction::retrieveCentralAtomPos(){
+//  if( atomsWithCatomDer.getNumberActive()==0 ){
+//      Vector cvec = mycolv->retrieveCentralAtomPos();
+//
+//      // Copy the value and derivatives from the MultiColvar
+//      atomsWithCatomDer.emptyActiveMembers();
+//      for(unsigned i=0;i<3;++i){
+//         setElementValue( getCentralAtomElementIndex() + i, mycolv->getElementValue( mycolv->getCentralAtomElementIndex() + i ) );
+//         unsigned nbase = ( getCentralAtomElementIndex() + i)*getNumberOfDerivatives();
+//         unsigned nbas2 = ( mycolv->getCentralAtomElementIndex() + i )*mycolv->getNumberOfDerivatives();
+//         for(unsigned j=0;j<mycolv->atomsWithCatomDer.getNumberActive();++j){
+//             unsigned n=mycolv->atomsWithCatomDer[j], nx=3*n; atomsWithCatomDer.activate(n);
+//             addElementDerivative(nbase + nx + 0, mycolv->getElementDerivative(nbas2 + nx + 0) );
+//             addElementDerivative(nbase + nx + 1, mycolv->getElementDerivative(nbas2 + nx + 1) );
+//             addElementDerivative(nbase + nx + 2, mycolv->getElementDerivative(nbas2 + nx + 2) ); 
+//         } 
+//      }
+//      atomsWithCatomDer.updateActiveMembers();  // This can perhaps be faster
+//      return cvec;
+//  }
+//  Vector cvec;
+//  for(unsigned i=0;i<3;++i) cvec[i]=getElementValue(1+i);
+//  return cvec;
+// }
+
 void BridgedMultiColvarFunction::calculateNumericalDerivatives( ActionWithValue* a ){
   if(!a){
     a=dynamic_cast<ActionWithValue*>(this);
@@ -171,7 +133,7 @@ bool BridgedMultiColvarFunction::isPeriodic(){
   return mycolv->isPeriodic();
 }
 
-void BridgedMultiColvarFunction::deactivate_task(){
+void BridgedMultiColvarFunction::deactivate_task( const unsigned& taskno ){
   plumed_merror("This should never be called");
 }
 
diff --git a/src/multicolvar/BridgedMultiColvarFunction.h b/src/multicolvar/BridgedMultiColvarFunction.h
index 67632d8dbf063c6bd36193a583b9371a79ced1c7..192c16c2272425d7544c6556d04456f180975076 100644
--- a/src/multicolvar/BridgedMultiColvarFunction.h
+++ b/src/multicolvar/BridgedMultiColvarFunction.h
@@ -61,25 +61,22 @@ public:
 /// Is the output quantity periodic
   bool isPeriodic();
 /// Routines that have to be defined so as not to have problems with virtual methods 
-  void deactivate_task();
+  void deactivate_task( const unsigned& taskno );
   void calculate(){}
 /// This does the task
-  void performTask();
-  virtual void completeTask()=0;
+  void transformBridgedDerivatives( const unsigned& current, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals );
+  void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& );
+  virtual void completeTask( const unsigned& curr, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals )=0;
 /// Get the central atom position
   Vector retrieveCentralAtomPos();
 /// We need our own calculate numerical derivatives here
   void calculateNumericalDerivatives( ActionWithValue* a=NULL );
   void apply(){};
-/// These routines replace the virtual routines in ActionWithVessel for 
-/// code optimization
-  void mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer );
-  void clearDerivativesAfterTask( const unsigned& ider );
 /// Is this atom currently being copied 
   bool isCurrentlyActive( const unsigned& );
 /// This should not be called
   Vector calculateCentralAtomPosition(){ plumed_error(); }
-  double compute(){ plumed_error(); }
+  double compute( const unsigned& tindex, AtomValuePack& myvals ){ plumed_error(); }
   Vector getPositionOfAtomForLinkCells( const unsigned& iatom ){ plumed_error(); }
   void updateActiveAtoms(){ plumed_error(); }
   void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
@@ -106,6 +103,11 @@ unsigned BridgedMultiColvarFunction::getSizeOfAtomsWithDerivatives(){
   return mycolv->getNumberOfAtoms();
 }
 
+inline 
+Vector BridgedMultiColvarFunction::getPositionOfAtomForLinkCells( const unsigned& iatom ){
+  return mycolv->getPositionOfAtomForLinkCells(iatom);
+}
+
 }
 }
 #endif
diff --git a/src/vesselbase/StoreValueAndWeightVessel.cpp b/src/multicolvar/CatomPack.cpp
similarity index 76%
rename from src/vesselbase/StoreValueAndWeightVessel.cpp
rename to src/multicolvar/CatomPack.cpp
index 925b2f10da8965f42959dadc0eeed71ccd855d54..bea0e8dae2257d76a5cb792b594ade55493a364f 100644
--- a/src/vesselbase/StoreValueAndWeightVessel.cpp
+++ b/src/multicolvar/CatomPack.cpp
@@ -19,19 +19,13 @@
    You should have received a copy of the GNU Lesser General Public License
    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "StoreValueAndWeightVessel.h"
+#include "CatomPack.h"
 
-namespace PLMD {
-namespace vesselbase {
+namespace PLMD{
+namespace multicolvar{
 
-void StoreValueAndWeightVessel::registerKeywords( Keywords& keys ){
-  StoreDataVessel::registerKeywords( keys );
-}
-
-StoreValueAndWeightVessel::StoreValueAndWeightVessel( const VesselOptions& da):
-StoreDataVessel(da)
-{
-  completeSetup( 0, 2 );
+void CatomPack::resize( const unsigned& size ){
+  indices.resize(size); derivs.resize(size);
 }
 
 }
diff --git a/src/multicolvar/CatomPack.h b/src/multicolvar/CatomPack.h
new file mode 100644
index 0000000000000000000000000000000000000000..5e54b05d28f90b0ca279f859e1d08729336f165d
--- /dev/null
+++ b/src/multicolvar/CatomPack.h
@@ -0,0 +1,78 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2011-2014 The plumed team
+   (see the PEOPLE file at the root of the distribution for a list of names)
+
+   See http://www.plumed-code.org for more information.
+
+   This file is part of plumed, version 2.
+
+   plumed is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   plumed is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+#ifndef __PLUMED_multicolvar_CatomPack_h
+#define __PLUMED_multicolvar_CatomPack_h
+
+#include <vector>
+#include "tools/Exception.h"
+#include "tools/Tensor.h"
+#include "tools/Vector.h"
+
+namespace PLMD {
+namespace multicolvar {
+
+class CatomPack {
+private:
+  std::vector<unsigned> indices;
+  std::vector<Tensor> derivs;
+public:
+  void resize( const unsigned& );
+  void setIndex( const unsigned& , const unsigned& );
+  void setDerivative( const unsigned& , const Tensor& );
+  unsigned getNumberOfAtomsWithDerivatives() const ;
+  unsigned getIndex( const unsigned& ) const ;
+  double getDerivative( const unsigned&, const unsigned& , const Vector& ) const ;
+};
+
+inline
+void CatomPack::setIndex( const unsigned& jind, const unsigned& ind ){
+  plumed_dbg_assert( jind<indices.size() );
+  indices[jind]=ind;
+}
+
+inline
+void CatomPack::setDerivative( const unsigned& jind , const Tensor& der ){
+  plumed_dbg_assert( jind<indices.size() );
+  derivs[jind]=der;
+} 
+
+inline
+unsigned CatomPack::getNumberOfAtomsWithDerivatives() const {
+  return indices.size();
+}
+
+inline
+unsigned CatomPack::getIndex( const unsigned& jind ) const {
+  plumed_dbg_assert( jind<indices.size() );
+  return indices[jind];
+}
+
+inline
+double CatomPack::getDerivative( const unsigned& iatom, const unsigned& jcomp, const Vector& df ) const {
+  plumed_dbg_assert( iatom<indices.size() );
+  return df[jcomp]*derivs[iatom](jcomp,0) + df[jcomp]*derivs[iatom](jcomp,1) + df[jcomp]*derivs[iatom](jcomp,2);
+}
+
+}
+}
+
+#endif 
diff --git a/src/multicolvar/CoordinationNumbers.cpp b/src/multicolvar/CoordinationNumbers.cpp
index e42d6622cc7acfcc0c36e02d05577aaa972af0d2..7545b773a21c6790e39173deaf3ed915b6a0f68f 100644
--- a/src/multicolvar/CoordinationNumbers.cpp
+++ b/src/multicolvar/CoordinationNumbers.cpp
@@ -71,8 +71,7 @@ public:
   static void registerKeywords( Keywords& keys );
   CoordinationNumbers(const ActionOptions&);
 // active methods:
-  virtual double compute(); 
-  Vector getCentralAtom();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms ); 
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
 };
@@ -120,32 +119,27 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double CoordinationNumbers::compute(){
+double CoordinationNumbers::compute( const unsigned& tindex, AtomValuePack& myatoms ){
    double value=0, dfunc; Vector distance;
 
    // Calculate the coordination number
    double d2, sw;
-   for(unsigned i=1;i<getNAtoms();++i){
-      distance=getSeparation( getPosition(0), getPosition(i) );
+   for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+      distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(i) );
       d2 = distance.modulo2();
       if( d2<rcut2 ){ 
          sw = switchingFunction.calculateSqr( d2, dfunc );
   
          value += sw;             
-         addAtomsDerivatives( 0, (-dfunc)*distance );
-         addAtomsDerivatives( i,  (dfunc)*distance );
-         addBoxDerivatives( (-dfunc)*Tensor(distance,distance) );
+         myatoms.addAtomsDerivatives( 1, 0, (-dfunc)*distance );
+         myatoms.addAtomsDerivatives( 1, i,  (dfunc)*distance );
+         myatoms.addBoxDerivatives( 1, (-dfunc)*Tensor(distance,distance) );
       }
    }
 
    return value;
 }
 
-Vector CoordinationNumbers::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 }
 }
 
diff --git a/src/multicolvar/DHEnergy.cpp b/src/multicolvar/DHEnergy.cpp
deleted file mode 100644
index 67db87b478bbd8dedfe8e187997a9217c0c8c4b5..0000000000000000000000000000000000000000
--- a/src/multicolvar/DHEnergy.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2013,2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "vesselbase/VesselRegister.h"
-#include "vesselbase/FunctionVessel.h"
-#include "core/PlumedMain.h"
-#include "core/Atoms.h"
-#include "MultiColvar.h"
-
-namespace PLMD {
-namespace multicolvar {
-
-class DHEnergy : public vesselbase::FunctionVessel {
-private:
-  MultiColvar* mycolv;
-  double I, T;
-  double k; // Inverse Debye screening length
-  double constant;
-  double epsilon;
-public:
-  static void registerKeywords( Keywords& keys );
-  static void reserveKeyword( Keywords& keys );
-  DHEnergy( const vesselbase::VesselOptions& da );
-  std::string function_description();
-  bool calculate( std::vector<double>& buffer );
-};
-
-PLUMED_REGISTER_VESSEL(DHEnergy,"DHENERGY")
-
-void DHEnergy::registerKeywords( Keywords& keys ){
-  FunctionVessel::registerKeywords( keys );
-  keys.add("compulsory","I","1.0","Ionic strength (M)");
-  keys.add("compulsory","TEMP","300.0","Simulation temperature (K)");
-  keys.add("compulsory","EPSILON","80.0","Dielectric constant of solvent");
-}
-
-void DHEnergy::reserveKeyword( Keywords& keys ){
-  keys.reserve("numbered","DHENERGY","calculate the Debye-Huckel interaction energy. This is a alternative "
-                                     "implementation of \\ref DHENERGY that is particularly useful if you "
-                                     "want to calculate the Debye-Huckel interaction energy and some other "
-                                     "function of set of distances between the atoms in the two groups. "
-                                     "The input for this keyword should read "
-                                     "DHENERGY={I=\\f$I\\f$ TEMP=\\f$T\\f$ EPSILON=\\f$\\epsilon\\f$}.");
-  keys.addOutputComponent("dhenergy","DHENERGY","the Debye-Huckel interaction energy. You can calculate "
-                                                "this quantity multiple times using different parameters");
-}
-
-DHEnergy::DHEnergy( const vesselbase::VesselOptions& da ) :
-FunctionVessel(da)
-{
-  mycolv=dynamic_cast<MultiColvar*>( getAction() );
-  plumed_massert( mycolv, "DHENERGY can only be used with MultiColvars and should only be used with DISTANCES");
-
-  parse("I",I); parse("TEMP",T); parse("EPSILON",epsilon);
-  
-  Atoms& catoms( getAction()->plumed.getAtoms() ); 
-  if( catoms.usingNaturalUnits() ) error("DHENERGY cannot be used for calculations performed with natural units");
-  constant=138.935458111/catoms.getUnits().getEnergy()/catoms.getUnits().getLength();
-  k=sqrt(I/(epsilon*T))*502.903741125*catoms.getUnits().getLength();
-}
-
-std::string DHEnergy::function_description(){
-  std::ostringstream ostr;
-  ostr<<"the Debye-Huckel interaction energy "<<getAction()->plumed.cite("Do, Carloni, Varani and Bussi, J. Chem. Theory Comput. 9, 1720 (2013)")<<"."; 
-  ostr<<" Parameters : temperature "<<T<<" K, ionic strength "<<I<<" M, ";
-  ostr<<"solvent dielectric constant "<<epsilon;
-  return ostr.str();
-}
-
-bool DHEnergy::calculate( std::vector<double>& buffer ){
-  if( mycolv->getAbsoluteIndex(0)==mycolv->getAbsoluteIndex(1) ) return false;
-
-  double val=getAction()->getElementValue(0), invdistance = 1.0 / val;
-  double f=exp(-k*val)*invdistance*constant*mycolv->getCharge(0)*mycolv->getCharge(1)/epsilon;
-  double dval=-(k+invdistance)*f; 
-  return addToBuffers( f, dval, buffer );
-}
-
-} 
-}
diff --git a/src/multicolvar/Density.cpp b/src/multicolvar/Density.cpp
index 5d1fe23d51f79f8886b61a542c65f5c8968fef34..149db001ce2133a266a32f20300bd8e97df39203 100644
--- a/src/multicolvar/Density.cpp
+++ b/src/multicolvar/Density.cpp
@@ -54,16 +54,15 @@ public:
   static void registerKeywords( Keywords& keys );
   Density(const ActionOptions&);
 // active methods:
-  virtual double compute();
-  Vector getCentralAtom();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
   /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
   bool isDensity(){ return true; }
   bool hasDifferentiableOrientation() const { return true; }
-  void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
-                                        const std::vector<double>& weight, MultiColvarFunction* func ){}
+//  void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
+//                                        const std::vector<double>& weight, MultiColvarFunction* func ){}
   void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
-  unsigned getNumberOfQuantities();
+//  unsigned getNumberOfQuantities();
   void getValueForTask( const unsigned& iatom, std::vector<double>& vals );
 };
 
@@ -82,22 +81,17 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead(); 
 }
 
-double Density::compute(){
+double Density::compute( const unsigned& tindex, AtomValuePack& myvals ){
   return 1.0;
 }
 
-Vector Density::getCentralAtom(){
-   addCentralAtomDerivatives( 0, Tensor::identity() );
-   return getPosition(0);
-}
-
 void Density::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
    indices[jstore]=0; 
 }
 
-unsigned Density::getNumberOfQuantities(){
-   return 6;
-}
+// unsigned Density::getNumberOfQuantities(){
+//    return 2;
+// }
 
 void Density::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){
    plumed_dbg_assert( vals.size()==2 ); vals[0]=vals[1]=1.0;
diff --git a/src/multicolvar/DihedralCorrelation.cpp b/src/multicolvar/DihedralCorrelation.cpp
index 0cca50e08e62c505b56ce124d170fc4662eee82a..579f737b51446ae510f2e84f47c6e7ed59ad91f2 100644
--- a/src/multicolvar/DihedralCorrelation.cpp
+++ b/src/multicolvar/DihedralCorrelation.cpp
@@ -85,9 +85,8 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   DihedralCorrelation(const ActionOptions&);
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();
 };
 
 PLUMED_REGISTER_ACTION(DihedralCorrelation,"DIHCOR")
@@ -102,6 +101,10 @@ PLUMED_MULTICOLVAR_INIT(ao)
 {
   // Read in the atoms
   int natoms=8; readAtoms( natoms );
+  // Stuff for central atoms
+  std::vector<bool> catom_ind(8, false); 
+  catom_ind[1]=catom_ind[2]=catom_ind[5]=catom_ind[6]=true;
+  setAtomsForCentralAtom( catom_ind );
 
   // And setup the ActionWithVessel
   if( getNumberOfVessels()==0 ){
@@ -114,19 +117,19 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double DihedralCorrelation::compute(){
+double DihedralCorrelation::compute( const unsigned& tindex, AtomValuePack& myatoms ){
   Vector d10,d11,d12;
-  d10=getSeparation(getPosition(1),getPosition(0));
-  d11=getSeparation(getPosition(2),getPosition(1));
-  d12=getSeparation(getPosition(3),getPosition(2));
+  d10=getSeparation(myatoms.getPosition(1),myatoms.getPosition(0));
+  d11=getSeparation(myatoms.getPosition(2),myatoms.getPosition(1));
+  d12=getSeparation(myatoms.getPosition(3),myatoms.getPosition(2));
 
   Vector dd10,dd11,dd12; PLMD::Torsion t1;
   double phi1  = t1.compute(d10,d11,d12,dd10,dd11,dd12);
 
   Vector d20,d21,d22;
-  d20=getSeparation(getPosition(5),getPosition(4));
-  d21=getSeparation(getPosition(6),getPosition(5));
-  d22=getSeparation(getPosition(7),getPosition(6));
+  d20=getSeparation(myatoms.getPosition(5),myatoms.getPosition(4));
+  d21=getSeparation(myatoms.getPosition(6),myatoms.getPosition(5));
+  d22=getSeparation(myatoms.getPosition(7),myatoms.getPosition(6));
 
   Vector dd20,dd21,dd22; PLMD::Torsion t2;
   double phi2 = t2.compute( d20, d21, d22, dd20, dd21, dd22 );
@@ -138,32 +141,24 @@ double DihedralCorrelation::compute(){
   dd11 *= 0.5*sin( phi2 - phi1 );
   dd12 *= 0.5*sin( phi2 - phi1 );
   // And add
-  addAtomsDerivatives(0,dd10);
-  addAtomsDerivatives(1,dd11-dd10);
-  addAtomsDerivatives(2,dd12-dd11);
-  addAtomsDerivatives(3,-dd12);
-  addBoxDerivatives  (-(extProduct(d10,dd10)+extProduct(d11,dd11)+extProduct(d12,dd12)));
+  myatoms.addAtomsDerivatives(1, 0, dd10);
+  myatoms.addAtomsDerivatives(1, 1, dd11-dd10);
+  myatoms.addAtomsDerivatives(1, 2, dd12-dd11);
+  myatoms.addAtomsDerivatives(1, 3, -dd12);
+  myatoms.addBoxDerivatives  (1, -(extProduct(d10,dd10)+extProduct(d11,dd11)+extProduct(d12,dd12)));
   // Derivative wrt phi2
   dd20 *= -0.5*sin( phi2 - phi1 );
   dd21 *= -0.5*sin( phi2 - phi1 );
   dd22 *= -0.5*sin( phi2 - phi1 );
   // And add
-  addAtomsDerivatives(4,dd20);
-  addAtomsDerivatives(5,dd21-dd20);
-  addAtomsDerivatives(6,dd22-dd21);
-  addAtomsDerivatives(7,-dd22);
-  addBoxDerivatives  (-(extProduct(d20,dd20)+extProduct(d21,dd21)+extProduct(d22,dd22)));
+  myatoms.addAtomsDerivatives(1, 4, dd20);
+  myatoms.addAtomsDerivatives(1, 5, dd21-dd20);
+  myatoms.addAtomsDerivatives(1, 6, dd22-dd21);
+  myatoms.addAtomsDerivatives(1, 7, -dd22);
+  myatoms.addBoxDerivatives(1, -(extProduct(d20,dd20)+extProduct(d21,dd21)+extProduct(d22,dd22)));
 
   return value;
 }
 
-Vector DihedralCorrelation::getCentralAtom(){
-   addCentralAtomDerivatives( 1, 0.25*Tensor::identity() );
-   addCentralAtomDerivatives( 2, 0.25*Tensor::identity() );
-   addCentralAtomDerivatives( 5, 0.25*Tensor::identity() );
-   addCentralAtomDerivatives( 6, 0.25*Tensor::identity() );
-   return 0.25*( getPosition(1) + getPosition(2) + getPosition(5) + getPosition(6) );
-}
-
 }
 }
diff --git a/src/multicolvar/Distances.cpp b/src/multicolvar/Distances.cpp
index 06f34c3eddda44f4f1f915973334541b963e6ba0..207f74029b859ba83c5785e19e816c27a0393612 100644
--- a/src/multicolvar/Distances.cpp
+++ b/src/multicolvar/Distances.cpp
@@ -82,10 +82,9 @@ public:
   static void registerKeywords( Keywords& keys );
   Distances(const ActionOptions&);
 // active methods:
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();
 };
 
 PLUMED_REGISTER_ACTION(Distances,"DISTANCES")
@@ -93,7 +92,7 @@ PLUMED_REGISTER_ACTION(Distances,"DISTANCES")
 void Distances::registerKeywords( Keywords& keys ){
   MultiColvar::registerKeywords( keys );
   keys.use("ATOMS"); 
-  keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); keys.use("DHENERGY");
+  keys.use("MEAN"); keys.use("MIN"); keys.use("MAX"); keys.use("LESS_THAN"); // keys.use("DHENERGY");
   keys.use("MORE_THAN"); keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS");
   keys.add("atoms-1","GROUP","Calculate the distance between each distinct pair of atoms in the group");
   keys.add("atoms-2","GROUPA","Calculate the distances between all the atoms in GROUPA and all "
@@ -139,25 +138,19 @@ PLUMED_MULTICOLVAR_INIT(ao)
   }
 }
 
-double Distances::compute(){
+double Distances::compute( const unsigned& tindex, AtomValuePack& myatoms ){
    Vector distance; 
-   distance=getSeparation( getPosition(0), getPosition(1) );
+   distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
    const double value=distance.modulo();
    const double invvalue=1.0/value;
 
    // And finish the calculation
-   addAtomsDerivatives( 0,-invvalue*distance );
-   addAtomsDerivatives( 1, invvalue*distance );
-   addBoxDerivatives( -invvalue*Tensor(distance,distance) );
+   myatoms.addAtomsDerivatives( 1, 0,-invvalue*distance );
+   myatoms.addAtomsDerivatives( 1, 1, invvalue*distance );
+   myatoms.addBoxDerivatives( 1, -invvalue*Tensor(distance,distance) );
    return value;
 }
 
-Vector Distances::getCentralAtom(){
-   addCentralAtomDerivatives( 0, 0.5*Tensor::identity() );
-   addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
-   return 0.5*( getPosition(0) + getPosition(1) );
-}
-
 }
 }
 
diff --git a/src/multicolvar/DumpMultiColvar.cpp b/src/multicolvar/DumpMultiColvar.cpp
index cb7f88160d92ff324817de898c9c40fa63b85d20..d70b178e68e80e951fb0c824a8da76fe368fa3a0 100644
--- a/src/multicolvar/DumpMultiColvar.cpp
+++ b/src/multicolvar/DumpMultiColvar.cpp
@@ -32,6 +32,7 @@
 #include "core/ActionSet.h"
 #include "MultiColvarBase.h"
 #include "vesselbase/ActionWithInputVessel.h"
+#include "vesselbase/StoreDataVessel.h"
 
 using namespace std;
 
@@ -132,15 +133,21 @@ void DumpMultiColvar::update(){
                  lenunit*t(2,0),lenunit*t(2,1),lenunit*t(2,2)
            );
   }
-  std::vector<double> cvals( mycolv->getNumberOfQuantities()-4 );
+  vesselbase::StoreDataVessel* stash=dynamic_cast<vesselbase::StoreDataVessel*>( getPntrToArgument() );
+  plumed_dbg_assert( stash );
+  std::vector<double> cvals( mycolv->getNumberOfQuantities() );
   for(unsigned i=0;i<mycolv->getFullNumberOfTasks();++i){
     const char* defname="X";
     const char* name=defname;
 
-    Vector apos = mycolv->getCentralAtomPosition(i);
+    Vector apos = mycolv->getCentralAtomPos( mycolv->getTaskCode(i) );
     of.printf(("%s "+fmt_xyz+" "+fmt_xyz+" "+fmt_xyz).c_str(),name,lenunit*apos[0],lenunit*apos[1],lenunit*apos[2]);
-    mycolv->getValueForTask( i, cvals );
-    for(unsigned j=0;j<cvals.size();++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]);
+    stash->retrieveValue( i, true, cvals );
+    if( mycolv->weightWithDerivatives() ){
+       for(unsigned j=0;j<cvals.size();++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]);
+    } else {
+       for(unsigned j=1;j<cvals.size();++j) of.printf((" "+fmt_xyz).c_str(),cvals[j]);
+    }  
     of.printf("\n");
   }
 }
diff --git a/src/multicolvar/LocalAverage.cpp b/src/multicolvar/LocalAverage.cpp
index b7851bfa7dbf339c44a363ef4c2ddad55a1f1bbb..ea0536c559f3fc9476ebda02ef215572f5a8721c 100644
--- a/src/multicolvar/LocalAverage.cpp
+++ b/src/multicolvar/LocalAverage.cpp
@@ -84,10 +84,6 @@ class LocalAverage : public MultiColvarFunction {
 private:
 /// Cutoff
   double rcut2;
-/// Ensures we deal with vectors properly
-  unsigned jstart;
-/// The values of the quantities we need to differentiate
-  std::vector<double> values;
 /// The switching function that tells us if atoms are close enough together
   SwitchingFunction switchingFunction;
 public:
@@ -96,9 +92,7 @@ public:
 /// We have to overwrite this here
   unsigned getNumberOfQuantities();
 /// Actually do the calculation
-  double compute();
-/// This returns the position of the central atom
-  Vector getCentralAtom();
+  double compute( const unsigned& tindex, AtomValuePack& myatoms );
 /// Is the variable periodic
   bool isPeriodic(){ return false; }   
 };
@@ -118,16 +112,14 @@ void LocalAverage::registerKeywords( Keywords& keys ){
   keys.remove("LOWMEM"); keys.use("MEAN"); keys.use("MORE_THAN"); keys.use("LESS_THAN");
   keys.use("BETWEEN"); keys.use("HISTOGRAM"); keys.use("MOMENTS");
   keys.addFlag("LOWMEM",false,"lower the memory requirements");
+  if( keys.reserved("VMEAN") ) keys.use("VMEAN");
+  if( keys.reserved("VSUM") ) keys.use("VSUM");
 }
 
 LocalAverage::LocalAverage(const ActionOptions& ao):
 Action(ao),
 MultiColvarFunction(ao)
 {
-  // One component for regular multicolvar and nelements for vectormulticolvar
-  if( getBaseMultiColvar(0)->getNumberOfQuantities()==5 ){ values.resize( 1 ); jstart=0; }
-  else { values.resize( getBaseMultiColvar(0)->getNumberOfQuantities() - 5 ); jstart=5; }
-
   // Read in the switching function
   std::string sw, errors; parse("SWITCH",sw);
   if(sw.length()>0){
@@ -142,62 +134,112 @@ MultiColvarFunction(ao)
   log.printf("  averaging over central molecule and those within %s\n",( switchingFunction.description() ).c_str() );
   rcut2 = switchingFunction.get_dmax()*switchingFunction.get_dmax();
   setLinkCellCutoff( 2.*switchingFunction.get_dmax() ); buildSymmetryFunctionLists();
-  for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i) getBaseMultiColvar(i)->doNotCalculateDirector();
 }
 
 unsigned LocalAverage::getNumberOfQuantities(){
-  return jstart + values.size();
+  return getBaseMultiColvar(0)->getNumberOfQuantities();
 }
 
-double LocalAverage::compute(){
-  weightHasDerivatives=true;  
+double LocalAverage::compute( const unsigned& tindex, AtomValuePack& myatoms ){
+  Vector distance; double d2, sw, dfunc, nbond=1; CatomPack atom0, atom1;
+  std::vector<double> values( getBaseMultiColvar(0)->getNumberOfQuantities() );
+  vesselbase::MultiValue myder(values.size(), getNumberOfDerivatives());
 
-  Vector distance; double d2, sw, dfunc, nbond=1;
+  getVectorForTask( myatoms.getIndex(0), false, values );
+  if( values.size()>2 ){
+      for(unsigned j=2;j<values.size();++j) myatoms.addValue( j, values[j] ); 
+  } else {
+      myatoms.addValue( 1, values[1] ); 
+  }
 
-  getVectorForBaseTask( 0, values ); 
-  for(unsigned j=0;j<values.size();++j) addElementValue( jstart + j, values[j] );
+  Vector catom_pos=myatoms.getPosition(0);
+  if( !doNotCalculateDerivatives() ){
+      atom0=getCentralAtomPackFromInput( myatoms.getIndex(0) );
+      getVectorDerivatives( myatoms.getIndex(0), false, myder );
+      if( values.size()>2 ){
+          for(unsigned j=0;j<myder.getNumberActive();++j){
+              unsigned jder=myder.getActiveIndex(j);
+              for(unsigned k=2;k<values.size();++k) myatoms.addDerivative( k, jder, myder.getDerivative(k,jder) );
+          }
+      } else {
+          for(unsigned j=0;j<myder.getNumberActive();++j){
+              unsigned jder=myder.getActiveIndex(j);
+              myatoms.addDerivative( 1, jder, myder.getDerivative(1,jder) ); 
+          }
+      }
+      myder.clearAll();
+  }
 
-  accumulateWeightedAverageAndDerivatives( 0, 1.0 );
-  for(unsigned i=1;i<getNAtoms();++i){
-     distance=getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(i) );
+  for(unsigned i=1;i<myatoms.getNumberOfAtoms();++i){
+     distance=getSeparation( catom_pos, myatoms.getPosition(i) );
      d2 = distance.modulo2(); 
      if( d2<rcut2 ){
          sw = switchingFunction.calculateSqr( d2, dfunc );
-         Tensor vir(distance,distance); 
-         getVectorForBaseTask( i, values ); 
-         accumulateWeightedAverageAndDerivatives( i, sw );
-         for(unsigned j=0;j<values.size();++j){
-             addElementValue( jstart + j, sw*values[j] );
-             addCentralAtomsDerivatives( 0, jstart+j, (-dfunc)*values[j]*distance );
-             addCentralAtomsDerivatives( i, jstart+j, (+dfunc)*values[j]*distance );
-             MultiColvarBase::addBoxDerivatives( jstart+j, (-dfunc)*values[j]*vir );   // This is a complex number?
+         getVectorForTask( myatoms.getIndex(i), false, values );
+         if( values.size()>2 ){
+             for(unsigned j=2;j<values.size();++j) myatoms.addValue( j, sw*values[j] );
+         } else {
+             myatoms.addValue( 1, sw*values[1] );
          }
          nbond += sw;
-         addCentralAtomsDerivatives( 0, 1, (-dfunc)*distance );
-         addCentralAtomsDerivatives( i, 1, (+dfunc)*distance );
-         MultiColvarBase::addBoxDerivatives( 1, (-dfunc)*vir );
+
+         if( !doNotCalculateDerivatives() ){
+             Tensor vir(distance,distance);
+             getVectorDerivatives( myatoms.getIndex(i), false, myder );
+             atom1=getCentralAtomPackFromInput( myatoms.getIndex(i) );
+             if( values.size()>2 ){
+                 for(unsigned j=0;j<myder.getNumberActive();++j){
+                     unsigned jder=myder.getActiveIndex(j);
+                     for(unsigned k=2;k<values.size();++k) myatoms.addDerivative( k, jder, sw*myder.getDerivative(k,jder) );
+                 }
+                 for(unsigned k=2;k<values.size();++k){
+                     myatoms.addComDerivatives( k, (-dfunc)*values[k]*distance, atom0 );
+                     myatoms.addComDerivatives( k, (+dfunc)*values[k]*distance, atom1 );
+                     myatoms.addBoxDerivatives( k, (-dfunc)*values[k]*vir );
+                 }
+             } else {
+                 for(unsigned j=0;j<myder.getNumberActive();++j){
+                     unsigned jder=myder.getActiveIndex(j);
+                     myatoms.addDerivative( 1, jder, sw*myder.getDerivative(1,jder) ); 
+                 }
+                 myatoms.addComDerivatives( 1, (-dfunc)*values[1]*distance, atom0 );
+                 myatoms.addComDerivatives( 1, (+dfunc)*values[1]*distance, atom1 );
+                 myatoms.addBoxDerivatives( 1, (-dfunc)*values[1]*vir );
+             }
+             // And the bit we use to average the vector
+             myatoms.addComDerivatives( 0, (-dfunc)*distance, atom0 );
+             myatoms.addComDerivatives( 0, (+dfunc)*distance, atom1 );
+             myatoms.addBoxDerivatives( 0, (-dfunc)*vir );
+             myder.clearAll();
+         }
      }
   }
 
   // Set the tempory weight
-  setElementValue( 1, nbond ); 
-  // Update all dynamic lists
-  updateActiveAtoms();
-  // Finish the calculation
-  getBaseMultiColvar(0)->finishWeightedAverageCalculation( this );
-
-  // Clear working derivatives
-  clearDerivativesAfterTask(1);
-  // Weight doesn't really have derivatives (just use the holder for convenience)
-  weightHasDerivatives=false; setElementValue( 1, 1.0 );   
+  myatoms.setValue( 0, nbond ); updateActiveAtoms( myatoms );
+  if( values.size()>2){
+      double norm=0;
+      vesselbase::MultiValue& myvals=myatoms.getUnderlyingMultiValue(); 
+      for(unsigned i=2;i<values.size();++i){
+          myvals.quotientRule( i, 0, i );
+          // Calculate length of vector
+          norm+=myvals.get(i)*myvals.get(i);
+      }
+      norm=sqrt(norm); myatoms.setValue(1, norm); double inorm = 1.0 / norm;
+      for(unsigned j=0;j<myvals.getNumberActive();++j){
+         unsigned jder=myvals.getActiveIndex(j);
+         for(unsigned i=2;i<values.size();++i){
+             myvals.addDerivative( 1, jder, myvals.get(i)*inorm*myvals.getDerivative(i,jder) ); 
+         }
+      }
+  } else {
+      myatoms.getUnderlyingMultiValue().quotientRule( 1, 0, 1 ); 
+  }
+  // Weight doesn't really have derivatives (just use the holder for convenience) 
+  myatoms.getUnderlyingMultiValue().clear(0); myatoms.setValue( 0, 1.0 );
    
-  return getElementValue(0);
+  return myatoms.getValue(1);
 }
 
-Vector LocalAverage::getCentralAtom(){
-  addDerivativeOfCentralAtomPos( 0, Tensor::identity() ); 
-  return getPositionOfCentralAtom(0); 
-} 
-
 }
 }
diff --git a/src/multicolvar/MultiColvar.cpp b/src/multicolvar/MultiColvar.cpp
index 56d2f1be238bca722ff9e757fb5b7571dccc5dad..d44c61a1e593f83f6bd34bd1a9dcd3af5f9536f0 100644
--- a/src/multicolvar/MultiColvar.cpp
+++ b/src/multicolvar/MultiColvar.cpp
@@ -102,7 +102,7 @@ void MultiColvar::readAtomsLikeKeyword( const std::string & key, int& natoms, st
      t.resize(0); 
   }
   if( all_atoms.size()>0 ){
-     current_atoms.resize( natoms ); nblock=ablocks[0].size(); 
+     nblock=ablocks[0].size(); 
      if( natoms<4 ) resizeBookeepingArray( nblock, nblock ); 
 
      for(unsigned i=0;i<nblock;++i){
@@ -137,7 +137,7 @@ void MultiColvar::readGroupsKeyword( int& natoms, std::vector<AtomNumber>& all_a
   std::vector<AtomNumber> t;
   parseAtomList("GROUP",t);
   if( !t.empty() ){
-      ablocks.resize( natoms ); current_atoms.resize( natoms );
+      ablocks.resize( natoms ); 
       for(unsigned i=0;i<t.size();++i) all_atoms.push_back( t[i] );
       if(natoms==2){ 
          nblock=t.size(); for(unsigned i=0;i<2;++i) ablocks[i].resize(nblock);
@@ -180,7 +180,7 @@ void MultiColvar::readGroupsKeyword( int& natoms, std::vector<AtomNumber>& all_a
 
 void MultiColvar::readTwoGroups( const std::string& key1, const std::string& key2, std::vector<AtomNumber>& all_atoms ){
   plumed_assert( all_atoms.size()==0 );
-  ablocks.resize( 2 ); current_atoms.resize( 2 );
+  ablocks.resize( 2 ); 
 
   std::vector<AtomNumber> t1, t2; std::vector<unsigned> newlist; 
   parseAtomList(key1,t1); parseAtomList(key2,t2);
@@ -219,7 +219,7 @@ void MultiColvar::readTwoGroups( const std::string& key1, const std::string& key
 
 void MultiColvar::readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3, const bool& allow2, std::vector<AtomNumber>& all_atoms ){
   plumed_assert( all_atoms.size()==0 );
-  ablocks.resize( 3 ); current_atoms.resize( 3 );
+  ablocks.resize( 3 ); 
 
   std::vector<AtomNumber> t1, t2, t3; std::vector<unsigned> newlist;
   parseAtomList(key1,t1); parseAtomList(key2,t2);
@@ -307,7 +307,7 @@ void MultiColvar::readSpeciesKeyword( int& natoms, std::vector<AtomNumber>& all_
   if( !t.empty() ){
       for(unsigned i=0;i<t.size();++i) all_atoms.push_back( t[i] );
       if( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ){
-          plumed_assert( natoms==2 ); current_atoms.resize( t.size() );
+          plumed_assert( natoms==2 ); 
           for(unsigned i=0;i<t.size();++i) addTaskToList(i);
           ablocks[0].resize( t.size() ); for(unsigned i=0;i<t.size();++i) ablocks[0][i]=i; 
           if( !verbose_output ){
@@ -319,7 +319,7 @@ void MultiColvar::readSpeciesKeyword( int& natoms, std::vector<AtomNumber>& all_
       } else if( !( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ) ){
           std::vector<unsigned> newlist; usespecies=false; verbose_output=false; // Make sure we don't do verbose output
           log.printf("  involving atoms : ");
-          current_atoms.resize(1); ablocks.resize(1); ablocks[0].resize( t.size() ); 
+          ablocks.resize(1); ablocks[0].resize( t.size() ); 
           for(unsigned i=0;i<t.size();++i){ 
              addTaskToList(i); ablocks[0][i]=i; log.printf(" %d",t[i].serial() ); 
           }
@@ -333,7 +333,6 @@ void MultiColvar::readSpeciesKeyword( int& natoms, std::vector<AtomNumber>& all_
       if( !t1.empty() ){
          parseAtomList("SPECIESB",t2);
          if ( t2.empty() ) error("SPECIESB keyword defines no atoms or is missing. Use either SPECIESA and SPECIESB or just SPECIES");
-         current_atoms.resize( 1 + t2.size() );
          for(unsigned i=0;i<t1.size();++i){ all_atoms.push_back( t1[i] ); addTaskToList(i); }
          ablocks[0].resize( t2.size() ); 
          unsigned k=0;
@@ -364,19 +363,8 @@ void MultiColvar::calculate(){
   runAllTasks();
 }
 
-void MultiColvar::updateActiveAtoms(){
-  if( atoms_with_derivatives.updateComplete() ) return;
-  atoms_with_derivatives.emptyActiveMembers();
-  for(unsigned i=0;i<getNAtoms();++i) atoms_with_derivatives.updateIndex( current_atoms[i] );
-  atoms_with_derivatives.sortActiveList();
-}
-
-Vector MultiColvar::calculateCentralAtomPosition(){
-  Vector catom=getCentralAtom();
-  atomsWithCatomDer.emptyActiveMembers();
-  for(unsigned i=0;i<getNAtoms();++i) atomsWithCatomDer.updateIndex( current_atoms[i] );
-  atomsWithCatomDer.sortActiveList();
-  return catom;
+void MultiColvar::updateActiveAtoms( AtomValuePack& myatoms ){
+  myatoms.updateUsingIndices();
 }
      
 }
diff --git a/src/multicolvar/MultiColvar.h b/src/multicolvar/MultiColvar.h
index 5547d26e7966e0d394a12b1f1d7108438f6b7568..3b1c728e233588157f5f6c54667e2cb3b3ebda81 100644
--- a/src/multicolvar/MultiColvar.h
+++ b/src/multicolvar/MultiColvar.h
@@ -23,6 +23,7 @@
 #define __PLUMED_multicolvar_MultiColvar_h
 
 #include "MultiColvarBase.h"
+#include "AtomValuePack.h"
 #include "tools/SwitchingFunction.h"
 #include <vector>
 
@@ -56,12 +57,6 @@ protected:
   void readThreeGroups( const std::string& key1, const std::string& key2, const std::string& key3, const bool& allow2, std::vector<AtomNumber>& all_atoms );
 /// Add a collective variable
   void addColvar( const std::vector<unsigned>& newatoms );
-/// Add some derivatives for an atom 
-  void addAtomsDerivatives(const int&,const Vector&);
-/// Set the derivative of the weight (used in MEAN and HISTOGRAM)
-  void addAtomsDerivativeOfWeight( const unsigned& i, const Vector& wder );
-/// Add derivatives to the central atom position
-  void addCentralAtomDerivatives( const unsigned& iatom, const Tensor& der );
 public:
   MultiColvar(const ActionOptions&);
   ~MultiColvar(){}
@@ -71,17 +66,7 @@ public:
 /// Calculate the multicolvar
   virtual void calculate();
 /// Update the atoms that have derivatives
-  void updateActiveAtoms();
-/// Calculate the position of the central atom
-  Vector calculateCentralAtomPosition();
-/// Get the position of the central atom
-  virtual Vector getCentralAtom()=0;
-/// Get the mass of atom iatom
-  double getMass(unsigned) const ;
-/// Get the charge of atom iatom
-  double getCharge(unsigned) const ;
-/// Get the absolute index of atom iatom
-  AtomNumber getAbsoluteIndex(unsigned) const ;
+  void updateActiveAtoms( AtomValuePack& myatoms );
 /// This is used in MultiColvarBase only - it is used to setup the link cells
   Vector getPositionOfAtomForLinkCells( const unsigned& iatom );
 /// Atoms are always active
@@ -93,41 +78,6 @@ Vector MultiColvar::getPositionOfAtomForLinkCells( const unsigned& iatom ){
   return ActionAtomistic::getPosition( iatom );
 }
 
-inline
-const Vector & MultiColvar::getPosition( unsigned iatom ) const {
-  return ActionAtomistic::getPosition( current_atoms[iatom] );
-}
-
-inline
-double MultiColvar::getMass(unsigned iatom ) const {
-  return ActionAtomistic::getMass( current_atoms[iatom] );
-}
-
-inline
-double MultiColvar::getCharge(unsigned iatom ) const {
-  return ActionAtomistic::getCharge( current_atoms[iatom] );
-}
-
-inline
-AtomNumber MultiColvar::getAbsoluteIndex(unsigned iatom) const {
-  return ActionAtomistic::getAbsoluteIndex( current_atoms[iatom] );
-}
-
-inline
-void MultiColvar::addAtomsDerivatives(const int& iatom, const Vector& der){
-  MultiColvarBase::addAtomsDerivatives( 0, current_atoms[iatom], der );
-}
-
-inline
-void MultiColvar::addAtomsDerivativeOfWeight( const unsigned& iatom, const Vector& wder ){
-  MultiColvarBase::addAtomsDerivatives( 1, current_atoms[iatom], wder );
-}
-
-inline
-void MultiColvar::addCentralAtomDerivatives( const unsigned& iatom, const Tensor& der ){
-  MultiColvarBase::addCentralAtomDerivatives( current_atoms[iatom], der );
-}
-
 }
 }
 
diff --git a/src/multicolvar/MultiColvarBase.cpp b/src/multicolvar/MultiColvarBase.cpp
index e018ea9f058ca89f84e0b6a08c42a711ff826c43..62e9ef8a559cd27d0c27eaee865dbf3a5b1e3ca1 100644
--- a/src/multicolvar/MultiColvarBase.cpp
+++ b/src/multicolvar/MultiColvarBase.cpp
@@ -20,10 +20,13 @@
    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 #include "MultiColvarBase.h"
-#include "MultiColvarFunction.h"
+//#include "MultiColvarFunction.h"
 #include "BridgedMultiColvarFunction.h"
 #include "vesselbase/Vessel.h"
 #include "tools/Pbc.h"
+#include "AtomValuePack.h"
+#include "CatomPack.h"
+#include "CatomPack.h"
 #include <vector>
 #include <string>
 
@@ -63,8 +66,8 @@ ActionWithValue(ao),
 ActionWithVessel(ao),
 usepbc(false),
 linkcells(comm),
-mycatoms(NULL),        // This will be destroyed by ActionWithVesel
-myvalues(NULL),        // This will be destroyed by ActionWithVesel 
+//mycatoms(NULL),        // This will be destroyed by ActionWithVesel
+//myvalues(NULL),        // This will be destroyed by ActionWithVesel 
 usespecies(false)
 {
   if( keywords.exists("NOPBC") ){ 
@@ -91,14 +94,26 @@ void MultiColvarBase::setupMultiColvarBase(){
   if( !usespecies && ablocks.size()<4 ){
      decoder.resize( ablocks.size() ); unsigned code=1;
      for(unsigned i=0;i<ablocks.size();++i){ decoder[ablocks.size()-1-i]=code; code *= nblock; } 
-  } 
-  // Resize stuff here
-  resizeLocalArrays();
+     use_for_central_atom.resize( ablocks.size(), true );
+     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
+  } else if( !usespecies ){
+     use_for_central_atom.resize( ablocks.size(), true );
+     numberForCentralAtom = 1.0 / static_cast<double>( ablocks.size() );
+  }
 
   // Setup underlying ActionWithVessel
   readVesselKeywords();
 }
 
+void MultiColvarBase::setAtomsForCentralAtom( const std::vector<bool>& catom_ind ){
+  unsigned nat=0; plumed_assert( catom_ind.size()==ablocks.size() );
+  for(unsigned i=0;i<catom_ind.size();++i){
+      use_for_central_atom[i]=catom_ind[i]; 
+      if( use_for_central_atom[i] ) nat++;
+  }
+  plumed_dbg_assert( nat>0 ); numberForCentralAtom = 1.0 / static_cast<double>( nat );
+}
+
 void MultiColvarBase::turnOnDerivatives(){
   ActionWithValue::turnOnDerivatives();
   needsDerivatives(); 
@@ -106,17 +121,17 @@ void MultiColvarBase::turnOnDerivatives(){
 } 
 
 void MultiColvarBase::setLinkCellCutoff( const double& lcut ){
-  plumed_assert( usespecies || current_atoms.size()<4 );
+  plumed_assert( usespecies || ablocks.size()<4 );
   linkcells.setCutoff( lcut );
 }
 
 void MultiColvarBase::setupLinkCells(){
   if( !linkcells.enabled() ) return ;
 
-  unsigned iblock, jblock;
+  unsigned iblock;
   if( usespecies ){
       iblock=0; 
-  } else if( current_atoms.size()<4 ){ 
+  } else if( ablocks.size()<4 ){ 
       iblock=1;  
   } else {
       plumed_error();
@@ -164,7 +179,7 @@ void MultiColvarBase::setupLinkCells(){
      std::vector<unsigned>  active_tasks( getFullNumberOfTasks(), 0 );
      for(unsigned i=rank;i<ablocks[0].size();i+=stride){
          if( !isCurrentlyActive( ablocks[0][i] ) ) continue;
-         natomsper=1; linked_atoms[0]=ltmp_ind[0];  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
+         unsigned natomsper=1; linked_atoms[0]=ltmp_ind[0];  // Note we always check atom 0 because it is simpler than changing LinkCells.cpp
          linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells( ablocks[0][i] ), natomsper, linked_atoms );
          for(unsigned j=0;j<natomsper;++j){
              for(unsigned k=bookeeping(i,linked_atoms[j]).first;k<bookeeping(i,linked_atoms[j]).second;++k) active_tasks[k]=1;
@@ -178,284 +193,235 @@ void MultiColvarBase::setupLinkCells(){
   }
 }
 
-void MultiColvarBase::resizeLocalArrays(){
-  atoms_with_derivatives.clear(); 
-  for(unsigned i=0;i<getSizeOfAtomsWithDerivatives();++i) atoms_with_derivatives.addIndexToList( i );
-  atoms_with_derivatives.deactivateAll();
-  // Set up stuff for central atoms
-  atomsWithCatomDer.clear();
-  for(unsigned i=0;i<getSizeOfAtomsWithDerivatives();++i) atomsWithCatomDer.addIndexToList( i );
-  atomsWithCatomDer.deactivateAll();
+void MultiColvarBase::decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms ){
+  plumed_dbg_assert( atoms.size()==ablocks.size() && !usespecies && ablocks.size()<4 );
+  unsigned scode = taskCode;
+  for(unsigned i=0;i<ablocks.size();++i){
+      unsigned ind=( scode / decoder[i] );
+      atoms[i] = ablocks[i][ind];
+      scode -= ind*decoder[i];
+  }
 }
 
-bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode ){
+bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms ){
   if( usespecies ){
-     natomsper=1;
+     unsigned natomsper=1; std::vector<unsigned> current_atoms( getNumberOfAtoms() );
      if( isDensity() ) return true;
      current_atoms[0]=taskCode;
      linkcells.retrieveNeighboringAtoms( getPositionOfAtomForLinkCells(current_atoms[0]), natomsper, current_atoms );
+     myatoms.setNumberOfAtoms( natomsper ); 
+     for(unsigned i=0;i<natomsper;++i) myatoms.setIndex( i, current_atoms[i] );  
      return natomsper>1;
-  } else if( current_atoms.size()<4 ){
-     natomsper=current_atoms.size();
-     unsigned scode = taskCode;
-     for(unsigned i=0;i<ablocks.size();++i){
-        unsigned ind=( scode / decoder[i] );
-        current_atoms[i]=ablocks[i][ind];
-        scode -= ind*decoder[i]; 
-     }
+  } else if( ablocks.size()<4 ){
+     std::vector<unsigned> atoms( ablocks.size() );
+     decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() );
+     for(unsigned i=0;i<ablocks.size();++i) myatoms.setIndex( i, atoms[i] ); 
   } else {
-     natomsper=current_atoms.size(); 
-     for(unsigned i=0;i<ablocks.size();++i) current_atoms[i]=ablocks[i][taskCode];
+     myatoms.setNumberOfAtoms( ablocks.size() );
+     for(unsigned i=0;i<ablocks.size();++i) myatoms.setIndex( i, ablocks[i][taskCode] ); 
   } 
   return true;
 }
 
-void MultiColvarBase::performTask(){
-  // Currently no atoms have derivatives so deactivate those that are active
-  atoms_with_derivatives.deactivateAll();
-  // Currently no central atoms have derivatives so deactive them all
-  atomsWithCatomDer.deactivateAll();
+void MultiColvarBase::performTask( const unsigned& task_index, const unsigned& current, vesselbase::MultiValue& myvals ){
+
+  AtomValuePack myatoms( myvals, this );
   // Retrieve the atom list
-  if( !setupCurrentAtomList( getCurrentTask() ) ) return;
+  if( !setupCurrentAtomList( current, myatoms ) ) return;
 
   // Do a quick check on the size of this contribution  
-  calculateWeight(); // printf("HELLO WEIGHT %f \n",getElementValue(1) );
-  if( getElementValue(1)<getTolerance() ){
-     updateActiveAtoms();
+  calculateWeight( myatoms ); 
+  if( myatoms.getValue(0)<getTolerance() ){
+     updateActiveAtoms( myatoms );
      return;   
   }
 
   // Compute everything
-  double vv=doCalculation();
-  // Set the value of this element in ActionWithVessel
-  setElementValue( 0, vv );
+  double vv=doCalculation( task_index, myatoms ); 
+  myatoms.setValue( 1, vv );
   return;
 }
 
-double MultiColvarBase::doCalculation(){
-  double val=compute(); updateActiveAtoms();
-  return val;
+void MultiColvarBase::calculateWeight( AtomValuePack& myatoms ){
+  myatoms.setValue( 0, 1.0 );
 }
 
-Vector MultiColvarBase::retrieveCentralAtomPos(){
-  if( atomsWithCatomDer.getNumberActive()==0 ){
-      Vector cvec = calculateCentralAtomPosition();
-      for(unsigned i=0;i<3;++i) setElementValue( getCentralAtomElementIndex()+i, cvec[i] );
-      return cvec;
-  }
-  Vector cvec; 
-  for(unsigned i=0;i<3;++i) cvec[i]=getElementValue( 2+i );
-  return cvec;
+double MultiColvarBase::doCalculation( const unsigned& taskIndex, AtomValuePack& myatoms ){
+  double val=compute( taskIndex, myatoms ); updateActiveAtoms( myatoms );
+  return val;
 }
 
-void MultiColvarBase::addCentralAtomDerivatives( const unsigned& iatom, const Tensor& der ){
-  plumed_dbg_assert( iatom<getNumberOfAtoms() );
-  atomsWithCatomDer.activate(iatom);
-  unsigned nder = 3*getNumberOfAtoms() + 9;
-  for(unsigned i=0;i<3;++i){ 
-    for(unsigned j=0;j<3;++j){
-        addElementDerivative( (getCentralAtomElementIndex()+j)*nder + 3*iatom + i, der(j,i) );
+Vector MultiColvarBase::getCentralAtomPos( const unsigned& taskIndex ){
+  unsigned curr=getTaskCode( taskIndex );
+
+  if( usespecies || isDensity() ){
+     return getPositionOfAtomForLinkCells(curr);
+  } else if( ablocks.size()<4 ){
+     // double factor=1.0/static_cast<double>( ablocks.size() );
+     Vector mypos; mypos.zero(); 
+     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
+     for(unsigned i=0;i<ablocks.size();++i){
+         if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(atoms[i]); 
      }
+     return mypos;
+  } else {
+     Vector mypos; mypos.zero();
+     for(unsigned i=0;i<ablocks.size();++i){
+         if( use_for_central_atom[i] ) mypos+=numberForCentralAtom*getPositionOfAtomForLinkCells(ablocks[i][curr]);
+     }
+     return mypos;
   }
 }
 
-double MultiColvarBase::getCentralAtomDerivative( const unsigned& iatom, const unsigned& jcomp, const Vector& df ){
-  plumed_dbg_assert( atomsWithCatomDer.isActive(iatom) && jcomp<3 );
-  unsigned nder = 3*getNumberOfAtoms() + 9;
-  return df[0]*getElementDerivative( (getCentralAtomElementIndex()+0)*nder + 3*iatom + jcomp ) +
-         df[1]*getElementDerivative( (getCentralAtomElementIndex()+1)*nder + 3*iatom + jcomp ) +
-         df[2]*getElementDerivative( (getCentralAtomElementIndex()+2)*nder + 3*iatom + jcomp ); 
-}
+CatomPack MultiColvarBase::getCentralAtomPack( const unsigned& basn, const unsigned& taskIndex ){
+  unsigned curr=getTaskCode( taskIndex );
+
+  CatomPack mypack;
+  if(usespecies){
+     mypack.resize(1);
+     mypack.setIndex( 0, basn + curr );
+     mypack.setDerivative( 0, Tensor::identity() );
+  } else if( ablocks.size()<4 ){
+     mypack.resize(ablocks.size());
+     unsigned k=0;
+     std::vector<unsigned> atoms( ablocks.size() ); decodeIndexToAtoms( curr, atoms );
+     for(unsigned i=0;i<ablocks.size();++i){
+         if( use_for_central_atom[i] ){
+             mypack.setIndex( k, basn + atoms[i] );
+             mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
+             k++;
+         }
+     }
+  } else {
+     unsigned k=0;
+     for(unsigned i=0;i<ablocks.size();++i){
+         if( use_for_central_atom[i] ){
+             mypack.setIndex( k, basn + ablocks[i][curr] );
+             mypack.setDerivative( k, numberForCentralAtom*Tensor::identity() );
+             k++;
+         }
+     }
+  }
+  return mypack;
+} 
 
 Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 ) const {
   if(usepbc){ return pbcDistance( vec1, vec2 ); }
   else{ return delta( vec1, vec2 ); }
 }
 
-void MultiColvarBase::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
-  plumed_dbg_assert( !doNotCalculateDerivatives() );
-  indices[jstore]=3*atoms_with_derivatives.getNumberActive() + 9;
-  if( indices[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
-
-  unsigned kder = ntotal + jstore*maxder;
-  for(unsigned jder=0;jder<atoms_with_derivatives.getNumberActive();++jder){
-     unsigned iatom = 3*atoms_with_derivatives[jder];
-     for(unsigned icomp=0;icomp<3;++icomp){ indices[ kder ] = iatom+icomp; kder++; }
-  }
-  unsigned nbase = 3*getNumberOfAtoms(); 
-  for(unsigned icomp=0;icomp<9;++icomp){ indices[ kder ] = nbase + icomp; kder++; }   
-}   
-
-void MultiColvarBase::getCentralAtomIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ) const {
-  plumed_dbg_assert( !doNotCalculateDerivatives() );
-
-  indices[jstore]=3*atomsWithCatomDer.getNumberActive();
-  if( indices[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
-
-  unsigned kder  = ntotal + jstore*maxder;
-  for(unsigned jder=0;jder<atomsWithCatomDer.getNumberActive();++jder){
-     unsigned iatom = 3*atomsWithCatomDer[jder];
-     for(unsigned icomp=0;icomp<3;++icomp){ indices[ kder ] = iatom+icomp; kder++; }
-  }
-}
+// void MultiColvarBase::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
+//  plumed_dbg_assert( !doNotCalculateDerivatives() );
+//  indices[jstore]=3*atoms_with_derivatives.getNumberActive() + 9;
+//  if( indices[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
+//
+//  unsigned kder = ntotal + jstore*maxder;
+//  for(unsigned jder=0;jder<atoms_with_derivatives.getNumberActive();++jder){
+//     unsigned iatom = 3*atoms_with_derivatives[jder];
+//     for(unsigned icomp=0;icomp<3;++icomp){ indices[ kder ] = iatom+icomp; kder++; }
+//  }
+//  unsigned nbase = 3*getNumberOfAtoms(); 
+//  for(unsigned icomp=0;icomp<9;++icomp){ indices[ kder ] = nbase + icomp; kder++; }   
+// }   
 
 void MultiColvarBase::activateIndexes( const unsigned& istart, const unsigned& number, const std::vector<unsigned>& indexes ){
   plumed_assert( number>0 );
   for(unsigned i=0;i<number-9;i+=3){
-      plumed_dbg_assert( indexes[istart+i]%3==0 ); unsigned iatom=indexes[istart+i]/3; 
-      atoms_with_derivatives.activate( iatom ); 
-  }
-}
-
-void MultiColvarBase::quotientRule( const unsigned& uder, const unsigned& vder, const unsigned& iout ){
-  unsigned ustart=uder*getNumberOfDerivatives();
-  unsigned vstart=vder*getNumberOfDerivatives();
-  unsigned istart=iout*getNumberOfDerivatives();
-  double weight = getElementValue( vder ), pref = getElementValue( uder ) / (weight*weight);
-  if( !doNotCalculateDerivatives() ){
-      for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-          unsigned n=3*atoms_with_derivatives[i], nx=n, ny=n+1, nz=n+2;
-          setElementDerivative( istart + nx, getElementDerivative(ustart+nx) / weight - pref*getElementDerivative(vstart+nx) );
-          setElementDerivative( istart + ny, getElementDerivative(ustart+ny) / weight - pref*getElementDerivative(vstart+ny) );
-          setElementDerivative( istart + nz, getElementDerivative(ustart+nz) / weight - pref*getElementDerivative(vstart+nz) );
-      }
-      unsigned vbase=3*getNumberOfAtoms();
-      for(unsigned i=0;i<9;++i){ 
-          setElementDerivative( istart + vbase + i, getElementDerivative(ustart+vbase+i) / weight - pref*getElementDerivative(vstart+vbase+i) );
-      }
+      plumed_dbg_assert( indexes[istart+i]%3==0 ); // unsigned iatom=indexes[istart+i]/3; 
+      //atoms_with_derivatives.activate( iatom ); 
   }
-  thisval_wasset[iout]=false; setElementValue( iout, getElementValue(uder) / weight );
 }
 
-void MultiColvarBase::mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer ){
-  unsigned vstart=getNumberOfDerivatives()*ider;
-  for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-     unsigned iatom=3*atoms_with_derivatives[i];
-     buffer[start+iatom*stride] += df*getElementDerivative(vstart+iatom); iatom++;
-     buffer[start+iatom*stride] += df*getElementDerivative(vstart+iatom); iatom++;
-     buffer[start+iatom*stride] += df*getElementDerivative(vstart+iatom); 
-  }
-  unsigned nvir=3*getNumberOfAtoms();
-  for(unsigned j=0;j<9;++j){
-     buffer[start+nvir*stride] += df*getElementDerivative(vstart+nvir); nvir++;
-  }
-}
-
-void MultiColvarBase::clearDerivativesAfterTask( const unsigned& ider ){
-  unsigned vstart=getNumberOfDerivatives()*ider;
-  thisval_wasset[ider]=false; setElementValue( ider, 0.0 );
-  thisval_wasset[ider]=false;
-  if( ider>1 && ider<5 && derivativesAreRequired() ){
-     for(unsigned i=0;i<atomsWithCatomDer.getNumberActive();++i){
-        unsigned iatom=vstart+3*atomsWithCatomDer[i];
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 );
-     }  
-  } else if( derivativesAreRequired() ) {
-     for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-        unsigned iatom=vstart+3*atoms_with_derivatives[i];
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 ); iatom++;
-        setElementDerivative( iatom, 0.0 );
-     }   
-     unsigned nvir=vstart+3*getNumberOfAtoms();
-     for(unsigned j=0;j<9;++j){
-        setElementDerivative( nvir, 0.0 ); nvir++;
-     }
-  }
-}
+// void MultiColvarBase::quotientRule( const unsigned& uder, const unsigned& vder, const unsigned& iout ){
+//  unsigned ustart=uder*getNumberOfDerivatives();
+//  unsigned vstart=vder*getNumberOfDerivatives();
+//  unsigned istart=iout*getNumberOfDerivatives();
+//  double weight = getElementValue( vder ), pref = getElementValue( uder ) / (weight*weight);
+//  if( !doNotCalculateDerivatives() ){
+//      for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
+//          unsigned n=3*atoms_with_derivatives[i], nx=n, ny=n+1, nz=n+2;
+//          setElementDerivative( istart + nx, getElementDerivative(ustart+nx) / weight - pref*getElementDerivative(vstart+nx) );
+//          setElementDerivative( istart + ny, getElementDerivative(ustart+ny) / weight - pref*getElementDerivative(vstart+ny) );
+//          setElementDerivative( istart + nz, getElementDerivative(ustart+nz) / weight - pref*getElementDerivative(vstart+nz) );
+//      }
+//      unsigned vbase=3*getNumberOfAtoms();
+//      for(unsigned i=0;i<9;++i){ 
+//          setElementDerivative( istart + vbase + i, getElementDerivative(ustart+vbase+i) / weight - pref*getElementDerivative(vstart+vbase+i) );
+//      }
+//  }
+//  thisval_wasset[iout]=false; setElementValue( iout, getElementValue(uder) / weight );
+// }
 
 void MultiColvarBase::apply(){
   if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply );
 }
 
-vesselbase::StoreDataVessel* MultiColvarBase::buildDataStashes( const bool& allow_wcutoff, const double& wtol ){
-  // Check if vessels have already been setup
-  for(unsigned i=0;i<getNumberOfVessels();++i){
-     StoreColvarVessel* ssc=dynamic_cast<StoreColvarVessel*>( getPntrToVessel(i) );
-     if(ssc){
-        if( allow_wcutoff && !ssc->weightCutoffIsOn() ) error("Cannot have more than one data stash with different properties");
-        if( !allow_wcutoff && ssc->weightCutoffIsOn() ) error("Cannot have more than one data stash with different properties");
-        return ssc;
-     }
-  }
- 
-  // Setup central atoms
-  vesselbase::VesselOptions da("","",0,"",this);
-  mycatoms=new StoreCentralAtomsVessel(da);
-  if( allow_wcutoff ) mycatoms->setHardCutoffOnWeight( wtol );
-  addVessel(mycatoms); 
-
-  // Setup store values vessel
-  vesselbase::VesselOptions ta("","",0,"",this);
-  myvalues=new StoreColvarVessel(ta);   
-  if( allow_wcutoff ) myvalues->setHardCutoffOnWeight( wtol );
-  addVessel(myvalues);
-
-  // Make sure resizing of vessels is done
-  resizeFunctions();
-  return myvalues;
-}
-
-
-Vector MultiColvarBase::getCentralAtomPosition( const unsigned& iatom ) const {
-  plumed_dbg_assert( mycatoms );
-  return mycatoms->getPosition( iatom );
-}
-
-void MultiColvarBase::addCentralAtomDerivativeToFunction( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, const Vector& der, MultiColvarFunction* func ){
-  plumed_dbg_assert( mycatoms ); 
-  if( usingLowMem() ){
-      mycatoms->recompute( iatom, 0 ); ;
-      mycatoms->addAtomsDerivatives( 0, jout, base_cv_no, der, func );
-  } else{
-      mycatoms->addAtomsDerivatives( iatom, jout, base_cv_no, der, func ); 
-  }
-}
-
-void MultiColvarBase::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){
-  // plumed_dbg_assert( myvalues && vals.size()==1 );  // Problem if we want to do MultiColvar + Bridge + MultiColvarFunction
-  vals[0]=myvalues->getValue( iatom );
-}
-
-void MultiColvarBase::copyElementsToBridgedColvar( BridgedMultiColvarFunction* func ){
-  func->setElementValue( 0, getElementValue(0) ); 
-  for(unsigned i=0;i<atoms_with_derivatives.getNumberActive();++i){
-     unsigned n=atoms_with_derivatives[i], nx=3*n;
-     func->atoms_with_derivatives.activate(n);
-     func->addElementDerivative( nx+0, getElementDerivative(nx+0) );
-     func->addElementDerivative( nx+1, getElementDerivative(nx+1) );
-     func->addElementDerivative( nx+2, getElementDerivative(nx+2) ); 
-  }
-  unsigned nvir=3*getNumberOfAtoms();
-  for(unsigned i=0;i<9;++i){ 
-     func->addElementDerivative( nvir, getElementDerivative(nvir) ); nvir++;
-  }
-}
-
-void MultiColvarBase::addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, MultiColvarFunction* func ){
-  plumed_dbg_assert( myvalues );
-  if( usingLowMem() ){
-     myvalues->recompute( iatom, 0 );
-     myvalues->chainRuleForComponent( 0, 0, base_cv_no, weight, func );
-  } else {
-     myvalues->chainRuleForComponent( iatom, 0, base_cv_no, weight, func );
-  }
-}
-
-bool MultiColvarBase::storedValueIsActive( const unsigned& iatom ){
-  return myvalues->storedValueIsActive( iatom );
-}
-
-void MultiColvarBase::finishWeightedAverageCalculation( MultiColvarFunction* func ){
-  func->quotientRule( 0, 1, 0 );
-}
-
-void MultiColvarBase::addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
-                                                       const std::vector<double>& weight, MultiColvarFunction* func ) {
-  plumed_merror("This should not be called - invalid use of multicolvar in function");
-} 
+// vesselbase::StoreDataVessel* MultiColvarBase::buildDataStashes( const bool& allow_wcutoff, const double& wtol ){
+//   // Check if vessels have already been setup
+//   for(unsigned i=0;i<getNumberOfVessels();++i){
+//      StoreColvarVessel* ssc=dynamic_cast<StoreColvarVessel*>( getPntrToVessel(i) );
+//      if(ssc){
+//         if( allow_wcutoff && !ssc->weightCutoffIsOn() ) error("Cannot have more than one data stash with different properties");
+//         if( !allow_wcutoff && ssc->weightCutoffIsOn() ) error("Cannot have more than one data stash with different properties");
+//         return ssc;
+//      }
+//   }
+//  
+//   // Setup central atoms
+//   // vesselbase::VesselOptions da("","",0,"",this);
+//   // mycatoms=new StoreCentralAtomsVessel(da);
+//   // if( allow_wcutoff ) mycatoms->setHardCutoffOnWeight( wtol );
+//   // addVessel(mycatoms); 
+// 
+//   // Setup store values vessel
+//   vesselbase::VesselOptions ta("","",0,"",this);
+//   myvalues=new StoreColvarVessel(ta);   
+//   if( allow_wcutoff ) myvalues->setHardCutoffOnWeight( wtol );
+//   addVessel(myvalues);
+// 
+//   // Make sure resizing of vessels is done
+//   resizeFunctions();
+//   return myvalues;
+// }
+
+
+//void MultiColvarBase::addCentralAtomDerivativeToFunction( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, const Vector& der, MultiColvarFunction* func ){
+////   plumed_dbg_assert( mycatoms ); 
+////   if( usingLowMem() ){
+////       mycatoms->recompute( iatom, 0 ); ;
+////       mycatoms->addAtomsDerivatives( 0, jout, base_cv_no, der, func );
+////   } else{
+////       mycatoms->addAtomsDerivatives( iatom, jout, base_cv_no, der, func ); 
+////   }
+//}
+
+// void MultiColvarBase::getValueForTask( const unsigned& iatom, std::vector<double>& vals ){
+//   // plumed_dbg_assert( myvalues && vals.size()==1 );  // Problem if we want to do MultiColvar + Bridge + MultiColvarFunction
+//   vals[0]=myvalues->getValue( iatom );
+// }
+// 
+// bool MultiColvarBase::storedValueIsActive( const unsigned& iatom ){
+//   return myvalues->storedValueIsActive( iatom );
+// }
+
+// void MultiColvarBase::finishWeightedAverageCalculation( MultiColvarFunction* func ){
+// //  func->quotientRule( 0, 1, 0 );
+// }
+
+// void MultiColvarBase::addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
+//                                                        const std::vector<double>& weight, MultiColvarFunction* func ) {
+//   plumed_merror("This should not be called - invalid use of multicolvar in function");
+// }
+
+// void MultiColvarBase::addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, MultiColvarFunction* func ){
+//   plumed_dbg_assert( myvalues );
+//   if( usingLowMem() ){
+//      myvalues->recompute( iatom, 0 );
+//      myvalues->chainRuleForComponent( 0, 0, base_cv_no, weight, func );
+//   } else {
+//      myvalues->chainRuleForComponent( iatom, 0, base_cv_no, weight, func );
+//   }
+// } 
      
 }
 }
diff --git a/src/multicolvar/MultiColvarBase.h b/src/multicolvar/MultiColvarBase.h
index b9438965b3b4b89805cbd5e1d762df7926a78893..06b2cdf93620e878de06abc8df6cbb4d0188f850 100644
--- a/src/multicolvar/MultiColvarBase.h
+++ b/src/multicolvar/MultiColvarBase.h
@@ -27,13 +27,15 @@
 #include "tools/DynamicList.h"
 #include "tools/LinkCells.h"
 #include "vesselbase/ActionWithVessel.h"
-#include "StoreColvarVessel.h"
-#include "StoreCentralAtomsVessel.h"
+// #include "StoreColvarVessel.h"
+// #include "StoreCentralAtomsVessel.h"
 #include <vector>
 
 namespace PLMD {
 namespace multicolvar {
 
+class AtomValuePack;
+class CatomPack;
 class BridgedMultiColvarFunction;
 
 class MultiColvarBase :
@@ -50,26 +52,21 @@ friend class MultiColvar;
 private:
 /// Use periodic boundary conditions
   bool usepbc;
-/// Variables used for central atoms
-  Tensor ibox;
-  DynamicList<unsigned> atomsWithCatomDer;
 /// The forces we are going to apply to things
   std::vector<double> forcesToApply;
 /// Stuff for link cells - this is used to make coordination number like variables faster
   LinkCells linkcells;
 /// This remembers where the boundaries are for the tasks. It makes link cells work fast
   Matrix<std::pair<unsigned,unsigned> > bookeeping;
-/// A copy of the vessel containing the catoms
-  StoreCentralAtomsVessel* mycatoms;
+/// Bool vector telling us which atoms are required to calculate central atom position
+  std::vector<bool> use_for_central_atom;
+/// 1/number of atoms involved in central atoms
+  double numberForCentralAtom;
 /// A copy of the vessel containg the values of each colvar
-  StoreColvarVessel* myvalues;
-/// This resizes the local arrays after neighbor list updates and during initialization
-  void resizeLocalArrays();
+//  StoreColvarVessel* myvalues;
 /// This resizes the arrays that are used for link cell update
   void resizeBookeepingArray( const unsigned& num1, const unsigned& num2 );
 protected:
-/// A dynamic list containing those atoms with derivatives
-  DynamicList<unsigned> atoms_with_derivatives;
 /// Using the species keyword to read in atoms
   bool usespecies;
 /// Number of atoms in each block
@@ -78,14 +75,12 @@ protected:
   std::vector<unsigned> decoder;
 /// Blocks of atom numbers
   std::vector< std::vector<unsigned> > ablocks;
-/// Number of atoms in the cv - set at start of calculation
-  unsigned natomsper;  
-/// Vector containing the indices of the current atoms
-  std::vector<unsigned> current_atoms;
 /// Add a task to the list of tasks
   void addTaskToList( const unsigned& taskCode );
 /// Finish setting up the multicolvar base
   void setupMultiColvarBase();
+/// Set which atoms are to be used to calculate the central atom position
+  void setAtomsForCentralAtom( const std::vector<bool>& catom_ind );
 /// Set the value of the cutoff for the link cells
   void setLinkCellCutoff( const double& lcut );
 /// Setup link cells in order to make this calculation faster
@@ -94,91 +89,62 @@ protected:
   Vector getSeparation( const Vector& vec1, const Vector& vec2 ) const ;
 /// Do we use pbc to calculate this quantity
   bool usesPbc() const ;
-/// Add some derivatives for an atom
-  void addAtomsDerivatives(const unsigned&, const unsigned&, const Vector& );
-/// Add some derivatives for a box
-  void addBoxDerivatives(const unsigned&, const Tensor& );
-/// Add some derivatives of the value to the virial
-  void addBoxDerivatives(const Tensor&);
-/// Retrieve derivative of central atom position wrt jcomp'th component of position of iatom'th atom
-  double getCentralAtomDerivative( const unsigned& iatom, const unsigned& jcomp, const Vector& df );
-/// Set a weight for this colvar (used in MEAN and HISTOGRAM)
-  void setWeight( const double& weight );
-/// Set the derivative of the weight (used in MEAN and HISTOGRAM)
-  void addBoxDerivativesOfWeight( const Tensor& vir );
 /// Get the number of atoms in this particular colvar
   unsigned getNAtoms() const;
-/// Add derivative of central atom position wrt to position of iatom'th atom
-  void addCentralAtomDerivatives( const unsigned& iatom, const Tensor& der );
-/// Get the indices for the central atom
-  void getCentralAtomIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ) const ;
 /// This sets up the list of atoms that are involved in this colvar
-  bool setupCurrentAtomList( const unsigned& taskCode );
+  bool setupCurrentAtomList( const unsigned& taskCode, AtomValuePack& myatoms );
+/// Decode indices if there are 2 or 3 atoms involved
+  void decodeIndexToAtoms( const unsigned& taskCode, std::vector<unsigned>& atoms );
 public:
   MultiColvarBase(const ActionOptions&);
   ~MultiColvarBase(){}
   static void registerKeywords( Keywords& keys );
-/// Used in setupCurrentAtomList to get atom numbers 
-/// Base quantities are different in MultiColvar and MultiColvarFunction
 /// Turn on the derivatives 
   virtual void turnOnDerivatives();
 /// Prepare for the calculation
 /// Perform one of the tasks
-  virtual void performTask();
+  virtual void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& );
 /// This gets the position of an atom for the link cell setup
   virtual Vector getPositionOfAtomForLinkCells( const unsigned& iatom )=0;
 /// And a virtual function which actually computes the colvar
-  virtual double doCalculation();  
+  virtual double doCalculation( const unsigned& tindex, AtomValuePack& myatoms );  
 /// Update the atoms that have derivatives
-  virtual void updateActiveAtoms()=0;
+  virtual void updateActiveAtoms( AtomValuePack& myatoms ){};
 /// This is replaced once we have a function to calculate the cv
-  virtual double compute()=0;
-/// These replace the functions in ActionWithVessel to make the code faster
-  virtual void mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer );
-  virtual void clearDerivativesAfterTask( const unsigned& ider );
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms )=0;
 /// Apply the forces from this action
   virtual void apply();
 /// Get the number of derivatives for this action
   virtual unsigned getNumberOfDerivatives();  // N.B. This is replacing the virtual function in ActionWithValue
-/// Get number size of atoms with derivatives array
-  virtual unsigned getSizeOfAtomsWithDerivatives();
 /// Checks if an task is being performed at the present time
   virtual bool isCurrentlyActive( const unsigned& code )=0;
-/// Get the number of quantities that are calculated each time
-  virtual unsigned getNumberOfQuantities();
+///
+  virtual CatomPack getCentralAtomPack( const unsigned& basn, const unsigned& curr );
 /// Get the index where the central atom is stored
-  virtual unsigned getCentralAtomElementIndex();
-/// Retrieve the position of the central atom
-  virtual Vector retrieveCentralAtomPos();
+  virtual Vector getCentralAtomPos( const unsigned& curr );
 /// You can use this to screen contributions that are very small so we can avoid expensive (and pointless) calculations
-  virtual void calculateWeight();
-/// A virtual routine to get the position of the central atom - used for things like cv gradient
-  virtual Vector calculateCentralAtomPosition()=0; 
+  virtual void calculateWeight( AtomValuePack& myatoms );
 /// Get the list of indices that have derivatives
- virtual void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
+// virtual void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
 /// Is this a density?
   virtual bool isDensity(){ return false; }
 /// Store central atoms so that this can be used in a function
-  virtual vesselbase::StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
+//  virtual vesselbase::StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
 /// Calculate and store getElementValue(uder)/getElementValue(vder) and its derivatives in getElementValue(iout)
-  void quotientRule( const unsigned& uder, const unsigned& vder, const unsigned& iout );
+//  void quotientRule( const unsigned& uder, const unsigned& vder, const unsigned& iout );
 /// Activate the atoms that have derivatives from a storeDataVessel
   void activateIndexes( const unsigned& istart, const unsigned& number, const std::vector<unsigned>& indexes ); 
-/// Get the position of the iatom th central atom (used in multicolvarfunction)
-  Vector getCentralAtomPosition( const unsigned& iatom ) const ;
 /// Add central atom derivatives to a multicolvar function
-  void addCentralAtomDerivativeToFunction( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, const Vector& der, MultiColvarFunction* func ); 
+//  void addCentralAtomDerivativeToFunction( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, const Vector& der, MultiColvarFunction* func ); 
 /// Get the value for this task
-  virtual void getValueForTask( const unsigned& iatom, std::vector<double>& vals ); 
-//// Used in ActionVolume and Gradient
-  virtual void copyElementsToBridgedColvar( BridgedMultiColvarFunction* );
+//  virtual void getValueForTask( const unsigned& iatom, std::vector<double>& vals ); 
 /// Used to accumulate values
-  virtual void addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, MultiColvarFunction* func );
+//  virtual void addWeightedValueDerivatives( const unsigned& iatom, const unsigned& base_cv_no, const double& weight, MultiColvarFunction* func );
 /// Used for calculating weighted averages
-  virtual void finishWeightedAverageCalculation( MultiColvarFunction* func );
+//  virtual void finishWeightedAverageCalculation( MultiColvarFunction* func );
 /// Add derivatives to the orientations
-  virtual void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
-                                                const std::vector<double>& weight, MultiColvarFunction* func );
+//  virtual void addOrientationDerivativesToBase( const unsigned& iatom, const unsigned& jstore, const unsigned& base_cv_no, 
+//                                                const std::vector<double>& weight, MultiColvarFunction* func );
 /// Is the iatom'th stored value currently active
   bool storedValueIsActive( const unsigned& iatom );
 /// This is true if multicolvar is calculating a vector or if the multicolvar is the density
@@ -197,58 +163,39 @@ bool MultiColvarBase::usesPbc() const {
   return usepbc;
 }
 
-inline
-unsigned MultiColvarBase::getNumberOfQuantities(){
-  return 5;
-}
-
-inline
-unsigned MultiColvarBase::getCentralAtomElementIndex(){
-  return 2;
-}
-
-inline
-unsigned MultiColvarBase::getNAtoms() const {
-  return natomsper;   // colvar_atoms[current].getNumberActive();
-}
-
-inline
-void MultiColvarBase::addAtomsDerivatives(const unsigned& ielem, const unsigned& iatom, const Vector& der ){
-  atoms_with_derivatives.activate(iatom);
-  unsigned ibase=ielem*getNumberOfDerivatives() + 3*iatom;
-  for(unsigned i=0;i<3;++i) addElementDerivative( ibase + i, der[i] );
-}
+// inline
+// unsigned MultiColvarBase::getNAtoms() const {
+//   return natomsper;   // colvar_atoms[current].getNumberActive();
+// }
+
+// inline
+// void MultiColvarBase::addAtomsDerivatives(const unsigned& ielem, const unsigned& iatom, const Vector& der ){
+//   atoms_with_derivatives.activate(iatom);
+//   unsigned ibase=ielem*getNumberOfDerivatives() + 3*iatom;
+//   for(unsigned i=0;i<3;++i) addElementDerivative( ibase + i, der[i] );
+// }
+// 
+// inline 
+// void MultiColvarBase::addBoxDerivatives(const unsigned& ielem, const Tensor& vir ){
+//   unsigned ibase=ielem*getNumberOfDerivatives() + 3*getNumberOfAtoms();
+//   for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) addElementDerivative( ibase+3*i+j, vir(i,j) );
+// }
+// 
+// inline
+// void MultiColvarBase::addBoxDerivatives(const Tensor& vir){
+//   addBoxDerivatives( 0, vir );
+// }
+
+// inline
+// void MultiColvarBase::setWeight( const double& weight ){
+//   setElementValue( 1, weight );
+// }
+
+// inline
+// void MultiColvarBase::addBoxDerivativesOfWeight( const Tensor& vir ){
+//   addBoxDerivatives( 1, vir );
+// }
 
-inline 
-void MultiColvarBase::addBoxDerivatives(const unsigned& ielem, const Tensor& vir ){
-  unsigned ibase=ielem*getNumberOfDerivatives() + 3*getNumberOfAtoms();
-  for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) addElementDerivative( ibase+3*i+j, vir(i,j) );
-}
-
-inline
-void MultiColvarBase::addBoxDerivatives(const Tensor& vir){
-  addBoxDerivatives( 0, vir );
-}
-
-inline
-void MultiColvarBase::calculateWeight(){
-  setElementValue( 1, 1.0 );
-}
-
-inline
-void MultiColvarBase::setWeight( const double& weight ){
-  setElementValue( 1, weight );
-}
-
-inline
-void MultiColvarBase::addBoxDerivativesOfWeight( const Tensor& vir ){
-  addBoxDerivatives( 1, vir );
-}
-
-inline
-unsigned MultiColvarBase::getSizeOfAtomsWithDerivatives(){
-  return getNumberOfAtoms();
-}
 
 }
 }
diff --git a/src/multicolvar/MultiColvarFilter.cpp b/src/multicolvar/MultiColvarFilter.cpp
index db194977173338aa91ee5fada8d5ce0f3f085100..8e583713309da03f66e53424a8adabdab90a4976 100644
--- a/src/multicolvar/MultiColvarFilter.cpp
+++ b/src/multicolvar/MultiColvarFilter.cpp
@@ -43,38 +43,29 @@ void MultiColvarFilter::doJobsRequiredBeforeTaskList(){
   ActionWithVessel::doJobsRequiredBeforeTaskList();
 }
 
-void MultiColvarFilter::completeTask(){
-  MultiColvarBase* mcolv=getPntrToMultiColvar(); 
-  // Copy the derivatives across
-  mcolv->copyElementsToBridgedColvar( this );
+void MultiColvarFilter::completeTask( const unsigned& curr, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals ){
+  invals.copyValues( outvals );
+  if( derivativesAreRequired() ) invals.copyDerivatives( outvals );
+ 
   // Retrive the value of the multicolvar and apply filter
-  double val=getElementValue(0), df, weight=applyFilter( val, df );
+  double val=invals.get(1), df, weight=applyFilter( val, df );
 
   // Now propegate derivatives
-  if( !mcolv->weightHasDerivatives ){
-     unsigned nstart=getNumberOfDerivatives(); setElementValue( 1, weight );
-     for(unsigned i=0;i<mcolv->atoms_with_derivatives.getNumberActive();++i){
-        unsigned n=mcolv->atoms_with_derivatives[i], nx=3*n;
-        atoms_with_derivatives.activate(n);
-        addElementDerivative( nstart+nx+0, df*getElementDerivative(nx+0) );
-        addElementDerivative( nstart+nx+1, df*getElementDerivative(nx+1) );
-        addElementDerivative( nstart+nx+2, df*getElementDerivative(nx+2) );
-     }
-     for(unsigned i=3*mcolv->getNumberOfAtoms();i<mcolv->getNumberOfDerivatives();++i){
-        addElementDerivative( nstart+i, df*getElementDerivative(i) );
+  if( !getPntrToMultiColvar()->weightHasDerivatives ){
+     outvals.setValue( 0, weight );
+     if( derivativesAreRequired() ){
+         for(unsigned i=0;i<invals.getNumberActive();++i){
+             unsigned jder=invals.getActiveIndex(i);
+             outvals.addDerivative( 0, jder, df*invals.getDerivative(1, jder ) );
+         }
      }
   } else {
-      unsigned nstart=getNumberOfDerivatives();
-      double ww=mcolv->getElementValue(1); setElementValue( 1, ww*weight );
-      for(unsigned i=0;i<mcolv->atoms_with_derivatives.getNumberActive();++i){
-          unsigned n=mcolv->atoms_with_derivatives[i], nx=3*n;
-          atoms_with_derivatives.activate(n);
-          addElementDerivative( nstart+nx+0, weight*mcolv->getElementDerivative(nstart+nx+0) + ww*df*getElementDerivative(nx+0) );
-          addElementDerivative( nstart+nx+1, weight*mcolv->getElementDerivative(nstart+nx+0) + ww*df*getElementDerivative(nx+1) );
-          addElementDerivative( nstart+nx+2, weight*mcolv->getElementDerivative(nstart+nx+0) + ww*df*getElementDerivative(nx+2) );
-     }
-     for(unsigned i=3*mcolv->getNumberOfAtoms();i<mcolv->getNumberOfDerivatives();++i){
-         addElementDerivative( nstart+i, weight*mcolv->getElementDerivative(nstart+i) + ww*df*getElementDerivative(i) );
+     double ww=outvals.get(0); outvals.setValue( 0, ww*weight );
+     if( derivativesAreRequired() ){
+         for(unsigned i=0;i<outvals.getNumberActive();++i){
+             unsigned ider=outvals.getActiveIndex(i);
+             outvals.setDerivative( 0, ider, weight*outvals.getDerivative(1,ider) + ww*df*outvals.getDerivative(0,ider) );
+         }
      }
   }
 }
diff --git a/src/multicolvar/MultiColvarFilter.h b/src/multicolvar/MultiColvarFilter.h
index ea44d76f4fc1c1b3589d4ec786ba060155d533a5..5fa523ede97ba2f521e714288c71d422b1ba874c 100644
--- a/src/multicolvar/MultiColvarFilter.h
+++ b/src/multicolvar/MultiColvarFilter.h
@@ -43,7 +43,7 @@ public:
 /// Get the number of quantities in the colvar
   unsigned getNumberOfQuantities();
 /// Actually do what we are asked
-  void completeTask();
+  void completeTask( const unsigned& curr, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals );
 /// Do the filtering
   virtual double applyFilter( const double& val, double& df )=0;
 /// Just checks there are no bridging forces
diff --git a/src/multicolvar/MultiColvarFunction.cpp b/src/multicolvar/MultiColvarFunction.cpp
index 3304f262b4a2b339966ac7085a84d1af2d3161fb..a562c64db80fef731b8f6b5bb0fab8b524a5f0f4 100644
--- a/src/multicolvar/MultiColvarFunction.cpp
+++ b/src/multicolvar/MultiColvarFunction.cpp
@@ -42,7 +42,8 @@ MultiColvarBase(ao),
 wtolerance(0.0)
 {
   // Read in the arguments
-  std::string mname; std::vector<std::string> mlabs; parseVector("DATA",mlabs);
+  std::string mname; 
+  std::vector<std::string> mlabs; parseVector("DATA",mlabs);
   log.printf("  using colvars calculated by actions "); bool useweights=false;
   for(unsigned i=0;i<mlabs.size();++i){
       log.printf("%s ",mlabs[i].c_str() );
@@ -51,7 +52,6 @@ wtolerance(0.0)
       // Check all base multicolvars are of same type
       if( i==0 ){ 
           mname = mycolv->getName();
-          tvals.resize( mycolv->getNumberOfQuantities()-4 );
           if( mycolv->isPeriodic() ) error("multicolvar functions don't work with this multicolvar");
       } else {
           if( mname!=mycolv->getName() ) error("All input multicolvars must be of same type"); 
@@ -67,10 +67,13 @@ wtolerance(0.0)
       // And track which variable stores each colvar
       for(unsigned j=0;j<mycolv->getFullNumberOfTasks();++j) colvar_label.push_back( i );
   }
-  log.printf("\n");
+  log.printf("\n"); 
   if( keywords.exists("WTOL") && useweights ){
-      parse("WTOL",wtolerance);
+      parse("WTOL",wtolerance); 
       log.printf("  only considering those colvars with a weight greater than %f \n",wtolerance);
+      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasedata.push_back( mybasemulticolvars[i]->buildDataStashes( true, wtolerance ) ); 
+  } else {
+      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasedata.push_back( mybasemulticolvars[i]->buildDataStashes( false, 0.0 ) );
   }
 }
 
@@ -95,11 +98,11 @@ void MultiColvarFunction::buildSymmetryFunctionLists(){
   if( mybasemulticolvars.size()>2 ) error("Found too many multicolvars in DATA specification. You can use either 1 or 2");
 
   // Make sure information is stored in the required multicolvars
-  if( keywords.exists("WTOL") ){
-      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( true, wtolerance );
-  } else {
-      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( false, 0.0 ); 
-  }
+//  if( keywords.exists("WTOL") ){
+//      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( true, wtolerance );
+//  } else {
+//      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( false, 0.0 ); 
+//  }
 
   usespecies=true; ablocks.resize( 1 );
   for(unsigned i=0;i<mybasemulticolvars[0]->getFullNumberOfTasks();++i) addTaskToList( i );
@@ -109,7 +112,8 @@ void MultiColvarFunction::buildSymmetryFunctionLists(){
       ntotal += mybasemulticolvars[i]->getFullNumberOfTasks();
   }
   unsigned k=0, start=0;
-  current_atoms.resize( 1 + ntotal ); ablocks[0].resize( ntotal ); 
+  // current_atoms.resize( 1 + ntotal ); 
+  ablocks[0].resize( ntotal ); 
   for(unsigned i=0;i<mybasemulticolvars.size();++i){
       for(unsigned j=0;j<mybasemulticolvars[i]->getFullNumberOfTasks();++j){
           ablocks[0][k]=start + j; k++;
@@ -125,10 +129,10 @@ void MultiColvarFunction::buildSets(){
      if( mybasemulticolvars[i]->getFullNumberOfTasks()!=nblock ){
           error("mismatch between numbers of tasks in various base multicolvars");
      }
-     mybasemulticolvars[i]->buildDataStashes( false, 0.0 );
+//     mybasemulticolvars[i]->buildDataStashes( false, 0.0 );
   }
   ablocks.resize( mybasemulticolvars.size() );
-  usespecies=false; current_atoms.resize( mybasemulticolvars.size() );
+  usespecies=false; // current_atoms.resize( mybasemulticolvars.size() );
   for(unsigned i=0;i<mybasemulticolvars.size();++i){
       ablocks[i].resize( nblock ); 
       for(unsigned j=0;j<nblock;++j) ablocks[i][j]=i*nblock+j;  
@@ -149,13 +153,13 @@ void MultiColvarFunction::buildAtomListWithPairs( const bool& allow_intra_group
   if( !allow_intra_group && mybasemulticolvars.size()>2 ) error("only two input multicolvars allowed with this function"); 
 
   // Make sure information is stored in the required multicolvars
-  if( keywords.exists("WTOL") ){
-      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( true, wtolerance );
-  } else {
-      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( false, 0.0 );
-  }
+//  if( keywords.exists("WTOL") ){
+//      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( true, wtolerance );
+//  } else {
+//      for(unsigned i=0;i<mybasemulticolvars.size();++i) mybasemulticolvars[i]->buildDataStashes( false, 0.0 );
+//  }
   
-  usespecies=false; ablocks.resize(2); current_atoms.resize( 2 );
+  usespecies=false; ablocks.resize(2); // current_atoms.resize( 2 );
   if( !allow_intra_group && mybasemulticolvars.size()==2 ){
      nblock = mybasemulticolvars[0]->getFullNumberOfTasks();
      if( mybasemulticolvars[1]->getFullNumberOfTasks()>nblock ) nblock = mybasemulticolvars[1]->getFullNumberOfTasks();
@@ -237,35 +241,73 @@ void MultiColvarFunction::calculateNumericalDerivatives( ActionWithValue* a ){
   }
 }
 
-void MultiColvarFunction::addStoredDerivative( const unsigned& jout, const unsigned& base_cv_no, const unsigned& base_index, const double& der ){
-  plumed_dbg_assert( jout<getNumberOfQuantities() && base_cv_no<mybasemulticolvars.size() && base_index<mybasemulticolvars[base_cv_no]->getNumberOfDerivatives() );
-
-  unsigned mbase = 3*mybasemulticolvars[base_cv_no]->getSizeOfAtomsWithDerivatives(), tbase = 3*getNumberOfAtoms();
-  if( base_index>=mbase ){
-      // Add virial element
-      unsigned jindex = base_index - mbase + tbase;
-      addElementDerivative( jout*getNumberOfDerivatives() + jindex, der ); 
-  } else {
-      // Add atomic element
-      unsigned offset=0; for(unsigned i=0;i<base_cv_no;++i) offset += 3*mybasemulticolvars[i]->getNumberOfAtoms();
-      unsigned jindex = offset + base_index; 
-      plumed_dbg_assert( jindex<3*getNumberOfAtoms() );
-      addElementDerivative( jout*getNumberOfDerivatives() + jindex, der );
-      unsigned iatom = ( jindex / 3 );
-      atoms_with_derivatives.activate( iatom );
-  }
+void MultiColvarFunction::updateActiveAtoms( AtomValuePack& myatoms ){
+  myatoms.updateDynamicList();
 }
 
-void MultiColvarFunction::updateActiveAtoms(){
-  if( atoms_with_derivatives.updateComplete() ) return;
-  atoms_with_derivatives.updateActiveMembers();
+void MultiColvarFunction::getVectorDerivatives( const unsigned& ind, const bool& normed, vesselbase::MultiValue& myder ){
+  plumed_dbg_assert( ind<getFullNumberOfBaseTasks() ); unsigned mmc=colvar_label[ind];
+  plumed_dbg_assert( mybasedata[mmc]->storedValueIsActive( convertToLocalIndex(ind,mmc) ) );
+  myder.resize( mybasemulticolvars[mmc]->getNumberOfQuantities(), mybasemulticolvars[mmc]->getNumberOfDerivatives() );
+  mybasedata[mmc]->retrieveDerivatives( convertToLocalIndex(ind,mmc), normed, myder );
 }
 
-Vector MultiColvarFunction::calculateCentralAtomPosition(){
-  Vector catom=getCentralAtom();
-  atomsWithCatomDer.updateActiveMembers();
-  return catom;
+void MultiColvarFunction::mergeVectorDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end, 
+                                                  const unsigned& jatom, const std::vector<double>& der, 
+                                                  vesselbase::MultiValue& myder, AtomValuePack& myatoms ){
+  plumed_dbg_assert( ival<myatoms.getUnderlyingMultiValue().getNumberOfValues() );
+  plumed_dbg_assert( start<myder.getNumberOfValues() && end<=myder.getNumberOfValues() );
+  plumed_dbg_assert( der.size()==myder.getNumberOfValues() && jatom<getFullNumberOfBaseTasks() );
+
+  unsigned mmc=colvar_label[jatom]; plumed_dbg_assert( mybasedata[mmc]->storedValueIsActive( convertToLocalIndex(jatom,mmc) ) );
+
+  // Get start of indices for this atom
+  unsigned basen=0; for(unsigned i=0;i<mmc;++i) basen+=3*mybasemulticolvars[i]->getNumberOfAtoms();
+  // Now get the start of the virial
+  unsigned virbas = 3*getNumberOfAtoms();
+
+  vesselbase::MultiValue& myvals=myatoms.getUnderlyingMultiValue();
+  for(unsigned j=0;j<myder.getNumberActive();++j){
+     unsigned jder=myder.getActiveIndex(j);
+     if( jder<3*mybasemulticolvars[mmc]->getNumberOfAtoms() ){
+         unsigned kder=basen+jder;
+         for(unsigned icomp=start;icomp<end;++icomp){
+             myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
+         }
+     } else {
+         unsigned kder=virbas + (jder - 3*mybasemulticolvars[mmc]->getNumberOfAtoms());
+         for(unsigned icomp=start;icomp<end;++icomp){
+             myvals.addDerivative( ival, kder, der[icomp]*myder.getDerivative( icomp, jder ) );
+         }
+     }
+  }
 }
+ 
+
+// void MultiColvarFunction::addStoredDerivative( const unsigned& jout, const unsigned& base_cv_no, const unsigned& base_index, const double& der ){
+//   plumed_dbg_assert( jout<getNumberOfQuantities() && base_cv_no<mybasemulticolvars.size() && base_index<mybasemulticolvars[base_cv_no]->getNumberOfDerivatives() );
+// 
+//   unsigned mbase = 3*mybasemulticolvars[base_cv_no]->getSizeOfAtomsWithDerivatives(), tbase = 3*getNumberOfAtoms();
+//   if( base_index>=mbase ){
+//       // Add virial element
+//       unsigned jindex = base_index - mbase + tbase;
+//       addElementDerivative( jout*getNumberOfDerivatives() + jindex, der ); 
+//   } else {
+//       // Add atomic element
+//       unsigned offset=0; for(unsigned i=0;i<base_cv_no;++i) offset += 3*mybasemulticolvars[i]->getNumberOfAtoms();
+//       unsigned jindex = offset + base_index; 
+//       plumed_dbg_assert( jindex<3*getNumberOfAtoms() );
+//       addElementDerivative( jout*getNumberOfDerivatives() + jindex, der );
+//       unsigned iatom = ( jindex / 3 );
+//       atoms_with_derivatives.activate( iatom );
+//   }
+// }
+
+// Vector MultiColvarFunction::calculateCentralAtomPosition(){
+//   Vector catom=getCentralAtom();
+//   atomsWithCatomDer.updateActiveMembers();
+//   return catom;
+// }
 
 }
 }
diff --git a/src/multicolvar/MultiColvarFunction.h b/src/multicolvar/MultiColvarFunction.h
index 6105ab60bef18f0789234bf20e67830d5b4ba5e9..cd8e95ab1b4a5c31d945dff97d8f530b23fb75fb 100644
--- a/src/multicolvar/MultiColvarFunction.h
+++ b/src/multicolvar/MultiColvarFunction.h
@@ -24,7 +24,9 @@
 
 #include "tools/Matrix.h"
 #include "MultiColvarBase.h"
-#include "StoreCentralAtomsVessel.h"
+#include "AtomValuePack.h"
+#include "CatomPack.h"
+#include "vesselbase/StoreDataVessel.h"
 
 namespace PLMD {
 namespace multicolvar {
@@ -33,8 +35,10 @@ class MultiColvarFunction : public MultiColvarBase {
 private:
 /// Tolerance used for weights of elements
   double wtolerance;
-/// The multicolvar from which we construct these quantities
-  std::vector<multicolvar::MultiColvarBase*> mybasemulticolvars;
+/// The multicolvars from which we construct these quantities
+  std::vector<MultiColvarBase*> mybasemulticolvars;
+/// The vessels in these multicolvars in which the data is stored
+  std::vector<vesselbase::StoreDataVessel*> mybasedata;
 /// This is used to keep track of what is calculated where
   std::vector<unsigned> colvar_label;
 /// A tempory vector that is used for retrieving vectors
@@ -44,28 +48,38 @@ private:
 protected:
 /// Get the total number of tasks that this calculation is based on
   unsigned getFullNumberOfBaseTasks() const ;
+/// Get the derivatives for the central atom with index ind
+  CatomPack getCentralAtomPackFromInput( const unsigned& ind );
+///
+  void getVectorForTask( const unsigned& ind, const bool& normed, std::vector<double>& orient0 );
+///
+  void getVectorDerivatives( const unsigned& ind, const bool& normed, vesselbase::MultiValue& myder0 );
+///
+  void mergeVectorDerivatives( const unsigned& ival, const unsigned& start, const unsigned& end,
+                               const unsigned& jatom, const std::vector<double>& der, 
+                               vesselbase::MultiValue& myder, AtomValuePack& myatoms );
 /// Get the index of the ith colvar we are using
-  unsigned getColvarIndex( const unsigned& ) const;
+//  unsigned getColvarIndex( const unsigned& ) const;
 /// Get the position of one of the central atoms
-  Vector getPositionOfCentralAtom(const unsigned&) const;
+//  Vector getPositionOfCentralAtom(const unsigned&) const;
 /// Add derivatives of value wrt to an atomic position 
-  void addCentralAtomsDerivatives( const unsigned& , const unsigned& , const Vector& );
+//  void addCentralAtomsDerivatives( const unsigned& , const unsigned& , const Vector& );
 /// Extract the value for the iatom th base task (this ignores current_atoms)
-  void extractValueForBaseTask( const unsigned& iatom, std::vector<double>& vals );
+//  void extractValueForBaseTask( const unsigned& iatom, std::vector<double>& vals );
 /// Retrieve the value calculated by the iatom th base task (this uses current_atoms)
-  void getValueForBaseTask( const unsigned& iatom, std::vector<double>& vals );
+//  void getValueForBaseTask( const unsigned& iatom, std::vector<double>& vals );
 /// Retrieve the vector calculated by the iatom th base task (this uses current_atoms)
-  void getVectorForBaseTask( const unsigned& iatom, std::vector<double>& vecs );
+//  void getVectorForBaseTask( const unsigned& iatom, std::vector<double>& vecs );
 /// Add the derivatives of this quantity (this ignores current_atoms)
-  void extractWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight );
+//  void extractWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight );
 /// Add the value and derivatives of this quantity (this uses current_atoms)
-  void accumulateWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight );
+//  void accumulateWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight );
 /// Add derivative wrt to the position of the central atom
-  void addDerivativeOfCentralAtomPos( const unsigned& iatom, const Tensor& der );
+//  void addDerivativeOfCentralAtomPos( const unsigned& iatom, const Tensor& der );
 /// Convert an index in the global array to an index in the individual base colvars
   unsigned convertToLocalIndex( const unsigned& index, const unsigned& mcv_code ) const ;
 /// Add derivatives to the orientation
-  void addOrientationDerivatives( const unsigned& iatom, const std::vector<double>& der );
+//  void addOrientationDerivatives( const unsigned& iatom, const std::vector<double>& der );
 /// Build sets by taking one multicolvar from each base
   void buildSets();
 /// Build colvars for atoms as if they were symmetry functions
@@ -82,21 +96,21 @@ public:
   MultiColvarFunction(const ActionOptions&);
   static void registerKeywords( Keywords& keys );
 /// Active element in atoms_with_derivatives
-  void atomHasDerivative( const unsigned& iatom );
+//  void atomHasDerivative( const unsigned& iatom );
 /// Resize the dynamic arrays 
-  void resizeDynamicArrays();
+//  void resizeDynamicArrays();
 /// Update the atoms that are active
-  virtual void updateActiveAtoms();
+  virtual void updateActiveAtoms( AtomValuePack& myatoms );
 /// Regular calculate
   void calculate();
 /// Calculate the numerical derivatives for this action
   void calculateNumericalDerivatives( ActionWithValue* a=NULL );
 /// Calculate the position of the central atom
-  Vector calculateCentralAtomPosition();
+//  Vector calculateCentralAtomPosition();
 /// Get the position of the central atom
-  virtual Vector getCentralAtom()=0;
+//  virtual Vector getCentralAtom()=0;
 /// Add derivatives from storage vessels in MultiColvarBase
-  void addStoredDerivative( const unsigned&, const unsigned&, const unsigned&, const double& );
+//  void addStoredDerivative( const unsigned&, const unsigned&, const unsigned&, const double& );
 /// This is used in MultiColvarBase only - it is used to setup the link cells
   Vector getPositionOfAtomForLinkCells( const unsigned& iatom );
 /// Some things can be inactive in functions
@@ -106,7 +120,7 @@ public:
 inline
 bool MultiColvarFunction::isCurrentlyActive( const unsigned& code ){
   plumed_dbg_assert( code<getFullNumberOfBaseTasks() ); unsigned mmc=colvar_label[code];
-  return mybasemulticolvars[mmc]->storedValueIsActive( convertToLocalIndex(code,mmc) );
+  return mybasedata[mmc]->storedValueIsActive( convertToLocalIndex(code,mmc) );
 }
 
 inline
@@ -135,83 +149,98 @@ unsigned MultiColvarFunction::convertToLocalIndex( const unsigned& index, const
 
 inline
 unsigned MultiColvarFunction::getBaseColvarNumber( const unsigned& iatom ) const {
-  return colvar_label[ current_atoms[iatom] ];
+  return colvar_label[iatom];
 }
 
 inline
 Vector MultiColvarFunction::getPositionOfAtomForLinkCells( const unsigned& iatom ){
   plumed_dbg_assert( iatom<getFullNumberOfBaseTasks() ); unsigned mmc=colvar_label[ iatom ];
-  return mybasemulticolvars[mmc]->getCentralAtomPosition( convertToLocalIndex(iatom,mmc) );
-}
-
-inline
-Vector MultiColvarFunction::getPositionOfCentralAtom( const unsigned& iatom ) const {
-  plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ];
-  return mybasemulticolvars[mmc]->getCentralAtomPosition( convertToLocalIndex(current_atoms[iatom],mmc) );   
-}
-
-inline
-void MultiColvarFunction::addCentralAtomsDerivatives( const unsigned& iatom, const unsigned& jout, const Vector& der ){
-  if( doNotCalculateDerivatives() ) return ;
-
-  plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ]; 
-  mybasemulticolvars[mmc]->addCentralAtomDerivativeToFunction( convertToLocalIndex(current_atoms[iatom],mmc), jout, mmc, der, this );
-}
-
-inline
-void MultiColvarFunction::atomHasDerivative( const unsigned& iatom ){
-  plumed_dbg_assert( !doNotCalculateDerivatives() );
-  atoms_with_derivatives.activate( iatom );
-}
-
-inline
-void MultiColvarFunction::addDerivativeOfCentralAtomPos( const unsigned& iatom, const Tensor& der ){
-  if( doNotCalculateDerivatives() ) return;
-
-  plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ]; Vector tmpder;
-  for(unsigned i=0;i<3;++i){
-      for(unsigned j=0;j<3;++j) tmpder[j]=der(i,j);
-      mybasemulticolvars[mmc]->addCentralAtomDerivativeToFunction( convertToLocalIndex(current_atoms[iatom],mmc), (2+i), mmc, tmpder, this );
-  }
-}
-
-inline
-void MultiColvarFunction::extractValueForBaseTask( const unsigned& iatom, std::vector<double>& vals ){
-  unsigned mmc = colvar_label[iatom]; mybasemulticolvars[mmc]->getValueForTask( convertToLocalIndex(iatom,mmc), vals ); 
-}
-
-inline
-void MultiColvarFunction::getValueForBaseTask( const unsigned& iatom, std::vector<double>& vals ){
-  plumed_dbg_assert( iatom<natomsper ); extractValueForBaseTask( current_atoms[iatom], vals );
-}
-
-inline
-void MultiColvarFunction::getVectorForBaseTask( const unsigned& iatom, std::vector<double>& vec ){
-  plumed_dbg_assert( vec.size()==mybasemulticolvars[0]->getNumberOfQuantities()-5 && tvals.size()>1 );
-  getValueForBaseTask( iatom, tvals ); for(unsigned i=0;i<vec.size();++i) vec[i]=tvals[i+1];
-}
-
-inline
-void MultiColvarFunction::extractWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight ){
-  if( doNotCalculateDerivatives() ) return;
-  unsigned mmc = colvar_label[iatom];
-  mybasemulticolvars[mmc]->addWeightedValueDerivatives( convertToLocalIndex(iatom, mmc), mmc, weight, this );
-}
-
-inline
-void MultiColvarFunction::accumulateWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight ){
-  if( doNotCalculateDerivatives() ) return;
-  plumed_dbg_assert( iatom<natomsper ); extractWeightedAverageAndDerivatives( current_atoms[iatom], weight ); 
-}
-
-inline
-void MultiColvarFunction::addOrientationDerivatives( const unsigned& iatom , const std::vector<double>& der ){
-  if( doNotCalculateDerivatives() ) return;
-
-  plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ];
-  unsigned jout=2; if( usespecies && iatom==0 ) jout=1;
-  mybasemulticolvars[mmc]->addOrientationDerivativesToBase( convertToLocalIndex(current_atoms[iatom],mmc), jout, mmc, der, this );
-}
+  return mybasemulticolvars[mmc]->getCentralAtomPos( convertToLocalIndex(iatom,mmc) );
+}
+
+inline
+CatomPack MultiColvarFunction::getCentralAtomPackFromInput( const unsigned& ind ){
+  plumed_dbg_assert( ind<getFullNumberOfBaseTasks() ); unsigned mmc=colvar_label[ind];
+  unsigned basen=0;
+  for(unsigned i=0;i<mmc;++i) basen+=mybasemulticolvars[i]->getNumberOfAtoms();
+  return mybasemulticolvars[mmc]->getCentralAtomPack( basen, convertToLocalIndex(ind,mmc) );
+}
+
+inline
+void MultiColvarFunction::getVectorForTask( const unsigned& ind, const bool& normed, std::vector<double>& orient ){
+  plumed_dbg_assert( ind<getFullNumberOfBaseTasks() ); unsigned mmc=colvar_label[ind];
+  plumed_dbg_assert( mybasedata[mmc]->storedValueIsActive( convertToLocalIndex(ind,mmc) ) );
+  mybasedata[mmc]->retrieveValue( convertToLocalIndex(ind,mmc), normed, orient );
+}
+
+// inline
+// Vector MultiColvarFunction::getPositionOfCentralAtom( const unsigned& iatom ) const {
+//   plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ];
+//   return mybasemulticolvars[mmc]->getCentralAtomPosition( convertToLocalIndex(current_atoms[iatom],mmc) );   
+// }
+// 
+// inline
+// void MultiColvarFunction::addCentralAtomsDerivatives( const unsigned& iatom, const unsigned& jout, const Vector& der ){
+//   if( doNotCalculateDerivatives() ) return ;
+// 
+//   plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ]; 
+//   mybasemulticolvars[mmc]->addCentralAtomDerivativeToFunction( convertToLocalIndex(current_atoms[iatom],mmc), jout, mmc, der, this );
+// }
+
+// inline
+// void MultiColvarFunction::atomHasDerivative( const unsigned& iatom ){
+//   plumed_dbg_assert( !doNotCalculateDerivatives() );
+//   atoms_with_derivatives.activate( iatom );
+// }
+
+// inline
+// void MultiColvarFunction::addDerivativeOfCentralAtomPos( const unsigned& iatom, const Tensor& der ){
+//   if( doNotCalculateDerivatives() ) return;
+// 
+//   plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ]; Vector tmpder;
+//   for(unsigned i=0;i<3;++i){
+//       for(unsigned j=0;j<3;++j) tmpder[j]=der(i,j);
+//       mybasemulticolvars[mmc]->addCentralAtomDerivativeToFunction( convertToLocalIndex(current_atoms[iatom],mmc), (2+i), mmc, tmpder, this );
+//   }
+// }
+
+// inline
+// void MultiColvarFunction::extractValueForBaseTask( const unsigned& iatom, std::vector<double>& vals ){
+//   unsigned mmc = colvar_label[iatom]; mybasemulticolvars[mmc]->getValueForTask( convertToLocalIndex(iatom,mmc), vals ); 
+// }
+// 
+// inline
+// void MultiColvarFunction::getValueForBaseTask( const unsigned& iatom, std::vector<double>& vals ){
+//   plumed_dbg_assert( iatom<natomsper ); extractValueForBaseTask( current_atoms[iatom], vals );
+// }
+
+// inline
+// void MultiColvarFunction::getVectorForBaseTask( const unsigned& iatom, std::vector<double>& vec ){
+//   plumed_dbg_assert( vec.size()==mybasemulticolvars[0]->getNumberOfQuantities()-5 && tvals.size()>1 );
+//   getValueForBaseTask( iatom, tvals ); for(unsigned i=0;i<vec.size();++i) vec[i]=tvals[i+1];
+// }
+
+// inline
+// void MultiColvarFunction::extractWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight ){
+//   if( doNotCalculateDerivatives() ) return;
+//   unsigned mmc = colvar_label[iatom];
+//   mybasemulticolvars[mmc]->addWeightedValueDerivatives( convertToLocalIndex(iatom, mmc), mmc, weight, this );
+// }
+// 
+// inline
+// void MultiColvarFunction::accumulateWeightedAverageAndDerivatives( const unsigned& iatom, const double& weight ){
+//   if( doNotCalculateDerivatives() ) return;
+//   plumed_dbg_assert( iatom<natomsper ); extractWeightedAverageAndDerivatives( current_atoms[iatom], weight ); 
+// }
+// 
+// inline
+// void MultiColvarFunction::addOrientationDerivatives( const unsigned& iatom , const std::vector<double>& der ){
+//   if( doNotCalculateDerivatives() ) return;
+// 
+//   plumed_dbg_assert( iatom<natomsper ); unsigned mmc = colvar_label[ current_atoms[iatom] ];
+//   unsigned jout=2; if( usespecies && iatom==0 ) jout=1;
+//   mybasemulticolvars[mmc]->addOrientationDerivativesToBase( convertToLocalIndex(current_atoms[iatom],mmc), jout, mmc, der, this );
+// }
 
 }
 }
diff --git a/src/multicolvar/NumberOfLinks.cpp b/src/multicolvar/NumberOfLinks.cpp
index 730539252a62070a504b8d0f763de01a5bb37f31..dbc11d8b89556408456f3f7f070da0f58fd92bbb 100644
--- a/src/multicolvar/NumberOfLinks.cpp
+++ b/src/multicolvar/NumberOfLinks.cpp
@@ -75,11 +75,9 @@ public:
   static void registerKeywords( Keywords& keys );
   NumberOfLinks(const ActionOptions&);
 /// Do the stuff with the switching functions
-  void calculateWeight();
+  void calculateWeight( AtomValuePack& myatoms );
 /// Actually do the calculation
-  double compute();
-/// This returns the position of the central atom
-  Vector getCentralAtom();  
+  double compute( const unsigned& tindex, AtomValuePack& myatoms );
 /// Is the variable periodic
   bool isPeriodic(){ return false; }
 };
@@ -124,14 +122,6 @@ MultiColvarFunction(ao)
   for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){
     if( !getBaseMultiColvar(i)->hasDifferentiableOrientation() ) error("cannot use multicolvar of type " + getBaseMultiColvar(i)->getName() );
   }
-  
-  // Resize these ready for business
-  if( getBaseMultiColvar(0)->getNumberOfQuantities()==5 ){ 
-      orient0.resize( 1 ); orient1.resize( 1 ); 
-  } else { 
-      orient0.resize( getBaseMultiColvar(0)->getNumberOfQuantities() - 5 ); 
-      orient1.resize( getBaseMultiColvar(0)->getNumberOfQuantities() - 5 );
-  }
 
   // Create holders for the collective variable
   readVesselKeywords();
@@ -140,36 +130,44 @@ MultiColvarFunction(ao)
   readVesselKeywords();
 }
 
-void NumberOfLinks::calculateWeight(){
-  Vector distance = getSeparation( getPositionOfCentralAtom(0), getPositionOfCentralAtom(1) );
+void NumberOfLinks::calculateWeight( AtomValuePack& myatoms ){
+  Vector distance = getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
   double dfunc, sw = switchingFunction.calculateSqr( distance.modulo2(), dfunc );
-  addCentralAtomsDerivatives( 0, 1, (-dfunc)*distance );
-  addCentralAtomsDerivatives( 1, 1, (dfunc)*distance );
-  MultiColvarBase::addBoxDerivatives( 1, (-dfunc)*Tensor(distance,distance) );
-  setElementValue(1,sw);
+  myatoms.setValue(0,sw);
+
+  if( !doNotCalculateDerivatives() ){
+      CatomPack atom0=getCentralAtomPackFromInput( myatoms.getIndex(0) );
+      myatoms.addComDerivatives( 0, (-dfunc)*distance, atom0 );
+      CatomPack atom1=getCentralAtomPackFromInput( myatoms.getIndex(1) );
+      myatoms.addComDerivatives( 0, (dfunc)*distance, atom1 );
+      myatoms.addBoxDerivatives( 0, (-dfunc)*Tensor(distance,distance) ); 
+  }
 }
 
-double NumberOfLinks::compute(){
-   getVectorForBaseTask( 0, orient0 ); 
-   getVectorForBaseTask( 1, orient1 );
+double NumberOfLinks::compute( const unsigned& tindex, AtomValuePack& myatoms ){
+   if( getBaseMultiColvar(0)->getNumberOfQuantities()<3 ) return 1.0; 
+
+   unsigned ncomp=getBaseMultiColvar(0)->getNumberOfQuantities();
+
+   std::vector<double> orient0( ncomp ), orient1( ncomp );
+   getVectorForTask( myatoms.getIndex(0), true, orient0 ); 
+   getVectorForTask( myatoms.getIndex(1), true, orient1 );
 
    double dot=0;
-   for(unsigned k=0;k<orient0.size();++k){
+   for(unsigned k=2;k<orient0.size();++k){
        dot+=orient0[k]*orient1[k];
    }
-//   for(unsigned k=0;k<orient0.size();++k){
-//      orient0[k]*=dot_df; orient1[k]*=dot_df;
-//   }
-   addOrientationDerivatives( 0, orient1 );
-   addOrientationDerivatives( 1, orient0 );
 
-   return dot;
-}
+   if( !doNotCalculateDerivatives() ){
+     unsigned nder=getNumberOfDerivatives();
+     vesselbase::MultiValue myder0(ncomp,nder), myder1(ncomp,nder);
+     getVectorDerivatives( myatoms.getIndex(0), true, myder0 );
+     mergeVectorDerivatives( 1, 2, orient1.size(), myatoms.getIndex(0), orient1, myder0, myatoms );
+     getVectorDerivatives( myatoms.getIndex(1), true, myder1 ); 
+     mergeVectorDerivatives( 1, 2, orient0.size(), myatoms.getIndex(1), orient0, myder1, myatoms );
+   }
 
-Vector NumberOfLinks::getCentralAtom(){
-   addDerivativeOfCentralAtomPos( 0, 0.5*Tensor::identity() );
-   addDerivativeOfCentralAtomPos( 1, 0.5*Tensor::identity() );
-   return 0.5*( getPositionOfCentralAtom(0) + getPositionOfCentralAtom(1) );
+   return dot;
 }
 
 }
diff --git a/src/multicolvar/Sprint.cpp b/src/multicolvar/Sprint.cpp
index a8d9194eb07f9df2e99fda7578253f3773d8708f..c007ef84a4ecafcbef025aad55612eab2dd9a04d 100644
--- a/src/multicolvar/Sprint.cpp
+++ b/src/multicolvar/Sprint.cpp
@@ -169,17 +169,23 @@ void Sprint::completeCalculation(){
    else { rank=comm.Get_rank(); stride=comm.Get_size(); } 
 
    // Derivatives
-   Matrix<double> mymat_ders( getNumberOfComponents(), getNumberOfDerivatives() ); 
-   unsigned nval = getFullNumberOfBaseTasks(); mymat_ders=0; 
+   vesselbase::MultiValue myvals( 2, getNumberOfDerivatives() );
+   Matrix<double> mymat_ders( getNumberOfComponents(), getNumberOfDerivatives() );  
+   std::vector<unsigned> catoms(2); unsigned nval = getFullNumberOfBaseTasks(); mymat_ders=0; 
    for(unsigned i=rank;i<getNumberOfActiveMatrixElements();i+=stride){
-      setMatrixIndexesForTask( i ); unsigned j=current_atoms[0], k=current_atoms[1];
+      decodeIndexToAtoms( getTaskCode(getActiveMatrixElement(i)), catoms ); unsigned j=catoms[0], k=catoms[1];
       double tmp1 = 2 * eigenvecs(nval-1,j)*eigenvecs(nval-1,k);
       for(unsigned icomp=0;icomp<getNumberOfComponents();++icomp){
           double tmp2 = 0.; 
           for(unsigned n=0;n<nval-1;++n){  // Need care on following line
               tmp2 += eigenvecs(n,maxeig[icomp].second) * ( eigenvecs(n,j)*eigenvecs(nval-1,k) + eigenvecs(n,k)*eigenvecs(nval-1,j) ) / ( lambda - eigvals[n] );
           }
-          addDerivativesOnMatrixElement( i, icomp, sqrtn*( tmp1*maxeig[icomp].first + tmp2*lambda ), mymat_ders );
+          double prefactor=sqrtn*( tmp1*maxeig[icomp].first + tmp2*lambda );
+          getAdjacencyVessel()->retrieveDerivatives( getActiveMatrixElement(i), false, myvals );
+          for(unsigned jd=0;jd<myvals.getNumberActive();++jd){
+              unsigned ider=myvals.getActiveIndex(jd);
+              mymat_ders( icomp, ider ) += prefactor*myvals.getDerivative( 1, ider );
+          }
       }
    }
    if( !serialCalculation() ) comm.Sum( mymat_ders );
diff --git a/src/multicolvar/StoreCentralAtomsVessel.cpp b/src/multicolvar/StoreCentralAtomsVessel.cpp
deleted file mode 100644
index 1a762cff009affbd51fdec7a223136e3e267ce27..0000000000000000000000000000000000000000
--- a/src/multicolvar/StoreCentralAtomsVessel.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2013,2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "vesselbase/VesselRegister.h"
-#include "vesselbase/ActionWithVessel.h"
-#include "tools/DynamicList.h"
-#include "MultiColvar.h"
-#include "MultiColvarFunction.h"
-#include "StoreCentralAtomsVessel.h"
-
-namespace PLMD {
-namespace multicolvar {
-
-StoreCentralAtomsVessel::StoreCentralAtomsVessel( const vesselbase::VesselOptions& da ):
-StoreDataVessel(da),
-tmpdf(3)
-{
-  mycolv=dynamic_cast<MultiColvarBase*>( getAction() );
-  plumed_assert( mycolv ); completeSetup( mycolv->getCentralAtomElementIndex(), 3 );
-}
-
-void StoreCentralAtomsVessel::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& aindexes ){
-  plumed_dbg_assert( mycolv->derivativesAreRequired() );
-
-  aindexes[jstore]=3*mycolv->atomsWithCatomDer.getNumberActive();
-  if( aindexes[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
-  unsigned kder = ntotal + jstore*maxder;
-  for(unsigned jder=0;jder<mycolv->atomsWithCatomDer.getNumberActive();++jder){
-     unsigned iatom = 3*mycolv->atomsWithCatomDer[jder];
-     for(unsigned icomp=0;icomp<3;++icomp){ aindexes[ kder ] = iatom+icomp; kder++; }
-  }
-}
-
-Vector StoreCentralAtomsVessel::getPosition( const unsigned& iatom ){
-  Vector pos; for(unsigned i=0;i<3;++i) pos[i]=getComponent( iatom, i );
-  return pos;
-}
-
-void StoreCentralAtomsVessel::performTask( const unsigned& itask ){
-  mycolv->atomsWithCatomDer.deactivateAll();
-  bool check=mycolv->setupCurrentAtomList( mycolv->getCurrentTask() );
-  plumed_dbg_assert( check );
-  Vector ignore = mycolv->retrieveCentralAtomPos();
-}
-
-void StoreCentralAtomsVessel::finishTask( const unsigned& itask ){
-  mycolv->atomsWithCatomDer.deactivateAll();
-  Vector ignore = mycolv->retrieveCentralAtomPos();
-}
-
-void StoreCentralAtomsVessel::addAtomsDerivatives( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, 
-                                                   const Vector& df, MultiColvarFunction* funcout ){
-  plumed_dbg_assert( mycolv->derivativesAreRequired() );
-
-  for(unsigned ider=0;ider<getNumberOfDerivatives(iatom);ider+=3){
-     for(unsigned i=0;i<3;++i) tmpdf[i]=df[0];
-     funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( iatom, ider+0 ), chainRule(iatom, ider+0, tmpdf)  ); 
-     for(unsigned i=0;i<3;++i) tmpdf[i]=df[1];
-     funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( iatom, ider+1 ), chainRule(iatom, ider+1, tmpdf)  );
-     for(unsigned i=0;i<3;++i) tmpdf[i]=df[2];
-     funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( iatom, ider+2 ), chainRule(iatom, ider+2, tmpdf)  );
-  }
-}
-
-}
-}
diff --git a/src/multicolvar/StoreCentralAtomsVessel.h b/src/multicolvar/StoreCentralAtomsVessel.h
deleted file mode 100644
index cb8421146987204f38857e982721d3034faa6dfa..0000000000000000000000000000000000000000
--- a/src/multicolvar/StoreCentralAtomsVessel.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2012-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifndef __PLUMED_multicolvar_StoreCentralAtomsVessel_h
-#define __PLUMED_multicolvar_StoreCentralAtomsVessel_h
-
-#include "vesselbase/StoreDataVessel.h" 
-
-namespace PLMD {
-namespace multicolvar {
-
-class MultiColvarBase;
-class MultiColvarFunction;
-
-class StoreCentralAtomsVessel : public vesselbase::StoreDataVessel {
-private:
-/// The base multicolvar
-  MultiColvarBase* mycolv;
-/// A vector that is used to store derivatives
-  std::vector<double> tmpdf;
-public:
-/// Constructor
-  StoreCentralAtomsVessel( const vesselbase::VesselOptions& );
-/// This does nothing
-  std::string description(){ return ""; }
-/// Get the orientation of the ith vector
-  Vector getPosition( const unsigned& );
-/// Recalculate the central atom position
-  void performTask( const unsigned& );
-  void finishTask( const unsigned& );
-/// Get the indices
-  void getIndexList( const unsigned& , const unsigned& , const unsigned& , std::vector<unsigned>& );
-/// Add derivatives to central atom position
-  void addAtomsDerivatives( const unsigned& iatom, const unsigned& jout, const unsigned& base_cv_no, const Vector& df, MultiColvarFunction* funcout );
-};
-
-}
-}
-#endif
-
diff --git a/src/multicolvar/StoreColvarVessel.cpp b/src/multicolvar/StoreColvarVessel.cpp
deleted file mode 100644
index 332aa0126bf8b7d0d1c773dd6953b813c3771831..0000000000000000000000000000000000000000
--- a/src/multicolvar/StoreColvarVessel.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2011-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "StoreColvarVessel.h"
-#include "MultiColvarFunction.h"
-
-namespace PLMD {
-namespace multicolvar {
-
-void StoreColvarVessel::registerKeywords( Keywords& keys ){
-  StoreDataVessel::registerKeywords( keys );
-}
-
-StoreColvarVessel::StoreColvarVessel( const vesselbase::VesselOptions& da):
-StoreDataVessel(da)
-{
-  completeSetup( 0, 1 );
-}
-
-void StoreColvarVessel::chainRuleForComponent( const unsigned& icolv, const unsigned& jout, const unsigned& base_cv_no, 
-                                               const double& weight, MultiColvarFunction* funcout ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() );  
-
-  if( usingLowMem() ){
-     unsigned ibuf = icolv*getAction()->getNumberOfDerivatives();
-     for(unsigned ider=0;ider<getNumberOfDerivatives(icolv);++ider){
-         funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( icolv, ider ), weight*getLocalDerivative(ibuf+ider) );
-     } 
-  } else {
-     unsigned ibuf = icolv*getNumberOfDerivativeSpacesPerComponent() + 1;
-     for(unsigned ider=0;ider<getNumberOfDerivatives(icolv);++ider){
-//         funcout->addStoredDerivative( jout, base_cv_no, getStoredIndex( icolv, ider ), weight*getBufferElement(ibuf+ider) );
-     } 
-  }
-}
-
-}
-}
diff --git a/src/multicolvar/StoreColvarVessel.h b/src/multicolvar/StoreColvarVessel.h
deleted file mode 100644
index 751b51b19d802feaa367b8bed2fb74e2d6ea16c4..0000000000000000000000000000000000000000
--- a/src/multicolvar/StoreColvarVessel.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2012-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifndef __PLUMED_multicolvar_StoreColvarVessel_h
-#define __PLUMED_multicolvar_StoreColvarVessel_h
-
-#include <string>
-#include <cstring>
-#include <vector>
-#include "vesselbase/StoreDataVessel.h"
-
-namespace PLMD {
-namespace multicolvar {
-
-class MultiColvarFunction;
-
-class StoreColvarVessel : public vesselbase::StoreDataVessel {
-public:
-  static void registerKeywords( Keywords& keys );
-  StoreColvarVessel( const vesselbase::VesselOptions& );
-  double getValue( const unsigned& );
-  virtual std::string description(){ return ""; }
-  void chainRuleForComponent( const unsigned& , const unsigned& , const unsigned& , const double& , MultiColvarFunction* );
-};
-
-inline
-double StoreColvarVessel::getValue( const unsigned& ival ){
-  return getComponent( ival, 0 );
-}
-
-}
-}
-#endif
diff --git a/src/multicolvar/Torsions.cpp b/src/multicolvar/Torsions.cpp
index 6a8a44fe458e23833344a708997d9e0791a23c2b..154547a4964784b28e9b37c1070e7077077f98c7 100644
--- a/src/multicolvar/Torsions.cpp
+++ b/src/multicolvar/Torsions.cpp
@@ -75,10 +75,9 @@ class Torsions : public MultiColvar {
 public:
   static void registerKeywords( Keywords& keys );
   Torsions(const ActionOptions&);
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
   bool isPeriodic(){ return true; }
   void retrieveDomain( std::string& min, std::string& max ){ min="-pi"; max="pi"; }
-  Vector getCentralAtom();  
 };
 
 PLUMED_REGISTER_ACTION(Torsions,"TORSIONS")
@@ -93,36 +92,33 @@ PLUMED_MULTICOLVAR_INIT(ao)
 {
   // Read in the atoms
   int natoms=4; readAtoms( natoms );
+  std::vector<bool> catom_ind(4, false); 
+  catom_ind[1]=catom_ind[2]=true;
+  setAtomsForCentralAtom( catom_ind );
   // Read in the vessels
   readVesselKeywords();  
   // And check everything has been read in correctly
   checkRead();
 }
 
-double Torsions::compute(){
+double Torsions::compute( const unsigned& tindex, AtomValuePack& myatoms ){
   Vector d0,d1,d2;
-  d0=getSeparation(getPosition(1),getPosition(0));
-  d1=getSeparation(getPosition(2),getPosition(1));
-  d2=getSeparation(getPosition(3),getPosition(2));
+  d0=getSeparation(myatoms.getPosition(1),myatoms.getPosition(0));
+  d1=getSeparation(myatoms.getPosition(2),myatoms.getPosition(1));
+  d2=getSeparation(myatoms.getPosition(3),myatoms.getPosition(2));
 
   Vector dd0,dd1,dd2; PLMD::Torsion t;
   double value  = t.compute(d0,d1,d2,dd0,dd1,dd2);
 
-  addAtomsDerivatives(0,dd0);
-  addAtomsDerivatives(1,dd1-dd0);
-  addAtomsDerivatives(2,dd2-dd1);
-  addAtomsDerivatives(3,-dd2);
+  myatoms.addAtomsDerivatives(1,0,dd0);
+  myatoms.addAtomsDerivatives(1,1,dd1-dd0);
+  myatoms.addAtomsDerivatives(1,2,dd2-dd1);
+  myatoms.addAtomsDerivatives(1,3,-dd2);
 
-  addBoxDerivatives  (-(extProduct(d0,dd0)+extProduct(d1,dd1)+extProduct(d2,dd2)));
+  myatoms.addBoxDerivatives  (1, -(extProduct(d0,dd0)+extProduct(d1,dd1)+extProduct(d2,dd2)));
 
   return value;
 }
 
-Vector Torsions::getCentralAtom(){
-   addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
-   addCentralAtomDerivatives( 2, 0.5*Tensor::identity() );
-   return 0.5*( getPosition(1) + getPosition(2) );
-}
-
 }
 }
diff --git a/src/multicolvar/VolumeAround.cpp b/src/multicolvar/VolumeAround.cpp
index 5440fb4284a2bbf21749256f45cd459c9e0c0f8b..1a70cabb8bea7f2f27f6b94b564236a4448adc0e 100644
--- a/src/multicolvar/VolumeAround.cpp
+++ b/src/multicolvar/VolumeAround.cpp
@@ -78,7 +78,7 @@ public:
   static void registerKeywords( Keywords& keys );
   VolumeAround(const ActionOptions& ao);
   void setupRegions();
-  double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives );
+  double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders );
 }; 
 
 PLUMED_REGISTER_ACTION(VolumeAround,"AROUND")
@@ -116,7 +116,7 @@ ActionVolume(ao)
 
 void VolumeAround::setupRegions(){ }
 
-double VolumeAround::calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives ){
+double VolumeAround::calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders ){
   // Calculate position of atom wrt to origin
   Vector fpos=pbcDistance( getPosition(0), cpos );
 
@@ -143,9 +143,9 @@ double VolumeAround::calculateNumberInside( const Vector& cpos, HistogramBead& b
   derivatives[1]=xcontr*yder*zcontr; 
   derivatives[2]=xcontr*ycontr*zder;
   // Add derivatives wrt to position of origin atom
-  addReferenceAtomDerivatives( 0, -derivatives );
+  refders[0] = -derivatives;
   // Add virial contribution
-  addBoxDerivatives( -Tensor(fpos,derivatives) );
+  vir -= Tensor(fpos,derivatives);
   return xcontr*ycontr*zcontr;
 }
 
diff --git a/src/multicolvar/VolumeCavity.cpp b/src/multicolvar/VolumeCavity.cpp
index bc93f3dd1c65757588136aef62e6aa7ffcc76c07..d0f5b59a95560c9ccbcd4cf0013800394f5f7acd 100644
--- a/src/multicolvar/VolumeCavity.cpp
+++ b/src/multicolvar/VolumeCavity.cpp
@@ -122,7 +122,7 @@ public:
   ~VolumeCavity();
   void setupRegions();
   void update();
-  double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives );
+  double calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives, Tensor& vir, std::vector<Vector>& refders );
 };
 
 PLUMED_REGISTER_ACTION(VolumeCavity,"CAVITY")
@@ -340,7 +340,7 @@ void VolumeCavity::update(){
   }
 }
 
-double VolumeCavity::calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives ){
+double VolumeCavity::calculateNumberInside( const Vector& cpos, HistogramBead& bead, Vector& derivatives, Tensor& vir, std::vector<Vector>& rderiv ){
   // Calculate distance of atom from origin of new coordinate frame
   Vector datom=pbcDistance( origin, cpos );
   double ucontr, uder, vcontr, vder, wcontr, wder;
@@ -373,7 +373,6 @@ double VolumeCavity::calculateNumberInside( const Vector& cpos, HistogramBead& b
   double tot = ucontr*vcontr*wcontr*jacob_det; 
 
   // Add reference atom derivatives
-  std::vector<Vector> rderiv(4);
   dfd[0]=uder2*vcontr*wcontr; dfd[1]=ucontr*vder2*wcontr; dfd[2]=ucontr*vcontr*wder2;
   Vector dfld; dfld[0]=udlen*vcontr*wcontr; dfld[1]=ucontr*vdlen*wcontr; dfld[2]=ucontr*vcontr*wdlen;
   rderiv[0] = dfd[0]*matmul(datom,dbi[0]) + dfd[1]*matmul(datom,dcross[0]) + dfd[2]*matmul(datom,dperp[0]) +
@@ -384,12 +383,10 @@ double VolumeCavity::calculateNumberInside( const Vector& cpos, HistogramBead& b
               dfld[0]*dlbi[2] + dfld[1]*dlcross[2] + dfld[2]*dlperp[2];
   rderiv[3] = dfld[0]*dlbi[3] + dfld[1]*dlcross[3] + dfld[2]*dlperp[3];
 
-  Tensor vir; vir.zero();
-  vir-=Tensor( cpos,derivatives );
+  vir.zero(); vir-=Tensor( cpos,derivatives );
   for(unsigned i=0;i<4;++i){
-     vir -= Tensor( getPosition(i), rderiv[i] ); addReferenceAtomDerivatives( i, rderiv[i] );
+     vir -= Tensor( getPosition(i), rderiv[i] ); 
   }
-  addBoxDerivatives( vir );
  
   return tot;
 }
diff --git a/src/multicolvar/VolumeGradientBase.cpp b/src/multicolvar/VolumeGradientBase.cpp
index d2dcdb769573dcec347758d47c39ec924bd3ea29..3f08a5e63b9ff76f5276ae480829d26d7e0b65c2 100644
--- a/src/multicolvar/VolumeGradientBase.cpp
+++ b/src/multicolvar/VolumeGradientBase.cpp
@@ -20,6 +20,7 @@
    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 #include "VolumeGradientBase.h"
+#include "CatomPack.h"
 
 namespace PLMD {
 namespace multicolvar {
@@ -46,50 +47,81 @@ void VolumeGradientBase::doJobsRequiredBeforeTaskList(){
   ActionWithVessel::doJobsRequiredBeforeTaskList();
 }
 
-void VolumeGradientBase::completeTask(){
+void VolumeGradientBase::completeTask( const unsigned& curr, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals ){
   if( getPntrToMultiColvar()->isDensity() ){ 
-     setElementValue( 0, 1.0 );
+     outvals.setValue(0, 1.0); outvals.setValue(1, 1.0);
   } else {
      // Copy derivatives of the colvar and the value of the colvar
-     getPntrToMultiColvar()->copyElementsToBridgedColvar( this );
+     invals.copyValues( outvals ); 
+     if( derivativesAreRequired() ) invals.copyDerivatives( outvals );
   }
-  calculateAllVolumes(); 
+  calculateAllVolumes( curr, outvals ); 
 }
 
-void VolumeGradientBase::setNumberInVolume( const unsigned& ivol, const double& weight, const Vector& wdf ){
-  MultiColvarBase* mcolv=getPntrToMultiColvar();
+void VolumeGradientBase::setNumberInVolume( const unsigned& ivol, const unsigned& curr, const double& weight, 
+                                            const Vector& wdf, const Tensor& virial, const std::vector<Vector>& refders, 
+                                            vesselbase::MultiValue& outvals ){
+  MultiColvarBase* mcolv=getPntrToMultiColvar(); 
   if( !mcolv->weightHasDerivatives ){
-      unsigned nstart=ivol*getNumberOfDerivatives();
-      setElementValue( ivol, weight ); 
-      for(unsigned i=0;i<mcolv->atomsWithCatomDer.getNumberActive();++i){
-         unsigned n=mcolv->atomsWithCatomDer[i], nx=nstart + 3*n;
-         atoms_with_derivatives.activate(n);
-         addElementDerivative( nx+0, mcolv->getCentralAtomDerivative(n, 0, wdf ) );
-         addElementDerivative( nx+1, mcolv->getCentralAtomDerivative(n, 1, wdf ) );
-         addElementDerivative( nx+2, mcolv->getCentralAtomDerivative(n, 2, wdf ) );
-      } 
+      outvals.setValue(ivol, weight ); 
+      if( derivativesAreRequired() ){
+         CatomPack catom( mcolv->getCentralAtomPack( 0, curr ) );
+         for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){
+             unsigned jatom=3*catom.getIndex(i);
+             outvals.addDerivative( ivol, jatom+0, catom.getDerivative(i,0,wdf) );
+             outvals.addDerivative( ivol, jatom+1, catom.getDerivative(i,1,wdf) );
+             outvals.addDerivative( ivol, jatom+2, catom.getDerivative(i,2,wdf) );
+         }
+         unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives();
+         for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, virial(i,j) );
+         for(unsigned i=0;i<refders.size();++i){
+             unsigned iatom=nmder+3*i;
+             
+             outvals.addDerivative( ivol, iatom+0, refders[i][0] );
+             outvals.addDerivative( ivol, iatom+1, refders[i][1] );
+             outvals.addDerivative( ivol, iatom+2, refders[i][2] );
+         }
+      }
+  } else if(ivol==0){
+      double ww=outvals.get(0); outvals.setValue(ivol,ww*weight);
+      if( derivativesAreRequired() ){
+         plumed_merror("This needs testing");
+         CatomPack catom( mcolv->getCentralAtomPack( 0, curr ) );
+         for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){
+             unsigned jatom=3*catom.getIndex(i);
+             outvals.addDerivative( ivol, jatom+0, weight*outvals.getDerivative(ivol,jatom+0) + ww*catom.getDerivative(i,0,wdf) );
+             outvals.addDerivative( ivol, jatom+1, weight*outvals.getDerivative(ivol,jatom+1) + ww*catom.getDerivative(i,1,wdf) );
+             outvals.addDerivative( ivol, jatom+2, weight*outvals.getDerivative(ivol,jatom+2) + ww*catom.getDerivative(i,2,wdf) );
+         }
+         unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives();
+         for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) );
+         for(unsigned i=0;i<refders.size();++i){
+             unsigned iatom=nmder+3*i;
+             outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] );
+             outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] );
+             outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] );
+         }
+      }
   } else {
-      unsigned nstart=ivol*getNumberOfDerivatives();
-      double ww=mcolv->getElementValue(1); setElementValue( ivol, ww*weight );
-      for(unsigned i=0;i<mcolv->atomsWithCatomDer.getNumberActive();++i){
-          unsigned n=mcolv->atomsWithCatomDer[i], nx=nstart + 3*n;
-          atoms_with_derivatives.activate(n);
-          addElementDerivative( nx+0, ww*mcolv->getCentralAtomDerivative(n, 0, wdf ) );
-          addElementDerivative( nx+1, ww*mcolv->getCentralAtomDerivative(n, 1, wdf ) );
-          addElementDerivative( nx+2, ww*mcolv->getCentralAtomDerivative(n, 2, wdf ) );
-     }
-     unsigned nder=mcolv->getNumberOfDerivatives(); 
-     for(unsigned i=0;i<mcolv->atoms_with_derivatives.getNumberActive();++i){
-        unsigned n=mcolv->atoms_with_derivatives[i], nx=nder + 3*n, ny=nstart + 3*n;
-        atoms_with_derivatives.activate(n);
-        addElementDerivative( ny+0, weight*mcolv->getElementDerivative(nx+0) );
-        addElementDerivative( ny+1, weight*mcolv->getElementDerivative(nx+1) );
-        addElementDerivative( ny+2, weight*mcolv->getElementDerivative(nx+2) );
-     }
-     unsigned nwvir=mcolv->getNumberOfDerivatives()-9, nwvir2=nstart + 3*mcolv->getNumberOfAtoms();
-     for(unsigned i=0;i<9;++i){
-        addElementDerivative( nwvir2, weight*mcolv->getElementDerivative(nwvir) ); nwvir++; nwvir2++;
-     }
+      double ww=outvals.get(0); outvals.setValue(ivol,ww*weight);
+      if( derivativesAreRequired() ){
+         plumed_merror("This needs testing");
+         CatomPack catom( mcolv->getCentralAtomPack( 0, curr ) ); 
+         for(unsigned i=0;i<catom.getNumberOfAtomsWithDerivatives();++i){
+             unsigned jatom=3*catom.getIndex(i);
+             outvals.addDerivative( ivol, jatom+0, ww*catom.getDerivative(i,0,wdf) );
+             outvals.addDerivative( ivol, jatom+1, ww*catom.getDerivative(i,1,wdf) );
+             outvals.addDerivative( ivol, jatom+2, ww*catom.getDerivative(i,2,wdf) );
+         }
+         unsigned nmder=getPntrToMultiColvar()->getNumberOfDerivatives();
+         for(unsigned i=0;i<3;++i) for(unsigned j=0;j<3;++j) outvals.addDerivative( ivol, nmder-9+3*i+j, ww*virial(i,j) );
+         for(unsigned i=0;i<refders.size();++i){
+             unsigned iatom=nmder+3*i;
+             outvals.addDerivative( ivol, iatom+0, ww*refders[i][0] );
+             outvals.addDerivative( ivol, iatom+1, ww*refders[i][1] );
+             outvals.addDerivative( ivol, iatom+2, ww*refders[i][2] );
+         }
+      }
   }
 }
 
diff --git a/src/multicolvar/VolumeGradientBase.h b/src/multicolvar/VolumeGradientBase.h
index fe85c12ae95b65e663094a37d0eaad5b4bd2d694..12a9c09344acd345b1118a94c3b79f5a0950fd6a 100644
--- a/src/multicolvar/VolumeGradientBase.h
+++ b/src/multicolvar/VolumeGradientBase.h
@@ -46,20 +46,16 @@ protected:
 /// Request the atoms 
   void requestAtoms( const std::vector<AtomNumber>& atoms );
 /// Set the number in the volume
-  void setNumberInVolume( const unsigned& ivol, const double& weight, const Vector& wdf );
-/// Add derivatinve to one of the reference atoms here
-  void addReferenceAtomDerivatives( const unsigned& jvol, const unsigned& iatom, const Vector& der );
-/// Add derivatives wrt to the virial
-  void addBoxDerivatives( const unsigned& jvol, const Tensor& vir );
+  void setNumberInVolume( const unsigned& , const unsigned& , const double& , const Vector& , const Tensor& , const std::vector<Vector>& , vesselbase::MultiValue& );
 public:
   static void registerKeywords( Keywords& keys );
   VolumeGradientBase(const ActionOptions&);
 /// Do jobs required before tasks are undertaken
   void doJobsRequiredBeforeTaskList();
 /// Actually do what we are asked
-  void completeTask();
+  void completeTask( const unsigned& curr, vesselbase::MultiValue& invals, vesselbase::MultiValue& outvals );
 /// Calculate what is in the volumes
-  virtual void calculateAllVolumes()=0;
+  virtual void calculateAllVolumes( const unsigned& curr, vesselbase::MultiValue& outvals )=0;
 /// Setup the regions that this is based on 
   virtual void setupRegions()=0;
 /// Forces here are applied through the bridge
@@ -95,32 +91,6 @@ const Vector & VolumeGradientBase::getPosition( int iatom ){
  return tmp_p;
 } 
 
-inline
-void VolumeGradientBase::addReferenceAtomDerivatives( const unsigned& jvol, const unsigned& iatom, const Vector& der ){
-  // This is used for storing the derivatives wrt to the 
-  // positions of any additional reference atoms
-  double pref=getPntrToMultiColvar()->getElementValue(1); 
-  unsigned nstart = jvol*getNumberOfDerivatives() + getPntrToMultiColvar()->getNumberOfDerivatives() + 3*iatom;
-  addElementDerivative( nstart + 0, pref*der[0] );
-  addElementDerivative( nstart + 1, pref*der[1] );
-  addElementDerivative( nstart + 2, pref*der[2] );
-}
-
-inline
-void VolumeGradientBase::addBoxDerivatives( const unsigned& jvol, const Tensor& vir ){
-  double pref=getPntrToMultiColvar()->getElementValue(1);
-  unsigned nstart = jvol*getNumberOfDerivatives() + getPntrToMultiColvar()->getNumberOfDerivatives() - 9;
-  addElementDerivative( nstart + 0, pref*vir(0,0) );  
-  addElementDerivative( nstart + 1, pref*vir(0,1) ); 
-  addElementDerivative( nstart + 2, pref*vir(0,2) ); 
-  addElementDerivative( nstart + 3, pref*vir(1,0) ); 
-  addElementDerivative( nstart + 4, pref*vir(1,1) ); 
-  addElementDerivative( nstart + 5, pref*vir(1,2) ); 
-  addElementDerivative( nstart + 6, pref*vir(2,0) ); 
-  addElementDerivative( nstart + 7, pref*vir(2,1) ); 
-  addElementDerivative( nstart + 8, pref*vir(2,2) ); 
-}
-
 }
 }
 #endif
diff --git a/src/multicolvar/XDistances.cpp b/src/multicolvar/XDistances.cpp
index 41e40524aa0eff48e2cad6177f877e5016170649..c6ac26e960b9ad975cb29837b61b8797e947ebae 100644
--- a/src/multicolvar/XDistances.cpp
+++ b/src/multicolvar/XDistances.cpp
@@ -115,10 +115,9 @@ public:
   static void registerKeywords( Keywords& keys );
   XDistances(const ActionOptions&);
 // active methods:
-  virtual double compute();
+  virtual double compute( const unsigned& tindex, AtomValuePack& myatoms );
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
-  Vector getCentralAtom();
 };
 
 PLUMED_REGISTER_ACTION(XDistances,"XDISTANCES")
@@ -151,25 +150,19 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double XDistances::compute(){
+double XDistances::compute( const unsigned& tindex, AtomValuePack& myatoms ){
    Vector distance; 
-   distance=getSeparation( getPosition(0), getPosition(1) );
+   distance=getSeparation( myatoms.getPosition(0), myatoms.getPosition(1) );
    const double value=distance[myc];
 
    Vector myvec; myvec.zero(); 
    // And finish the calculation
-   myvec[myc]=+1; addAtomsDerivatives( 1,myvec  );
-   myvec[myc]=-1; addAtomsDerivatives( 0,myvec );
-   addBoxDerivatives( Tensor(distance,myvec) );
+   myvec[myc]=+1; myatoms.addAtomsDerivatives( 1, 1, myvec  );
+   myvec[myc]=-1; myatoms.addAtomsDerivatives( 1, 0, myvec );
+   myatoms.addBoxDerivatives( 1, Tensor(distance,myvec) );
    return value;
 }
 
-Vector XDistances::getCentralAtom(){
-   addCentralAtomDerivatives( 0, 0.5*Tensor::identity() );
-   addCentralAtomDerivatives( 1, 0.5*Tensor::identity() );
-   return 0.5*( getPosition(0) + getPosition(1) );
-}
-
 }
 }
 
diff --git a/src/secondarystructure/SecondaryStructureRMSD.cpp b/src/secondarystructure/SecondaryStructureRMSD.cpp
index 012c49bf92b4381be4793fd08c87e9f774247350..3eaa972e34cf7495484aa93a63db2682a90df4ce 100644
--- a/src/secondarystructure/SecondaryStructureRMSD.cpp
+++ b/src/secondarystructure/SecondaryStructureRMSD.cpp
@@ -205,15 +205,15 @@ void SecondaryStructureRMSD::calculate(){
   runAllTasks();
 }
 
-void SecondaryStructureRMSD::performTask(){
+void SecondaryStructureRMSD::performTask( const unsigned& task_index, const unsigned& current, vesselbase::MultiValue& myvals ){
   // Retrieve the positions
-  for(unsigned i=0;i<pos.size();++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(i) );
+  for(unsigned i=0;i<pos.size();++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(current,i) );
 
   // This does strands cutoff
   Vector distance=pbcDistance( pos[align_atom_1],pos[align_atom_2] ); 
   if( s_cutoff>0 ){
      if( distance.modulo()>s_cutoff ){
-       setElementValue(1,0.0);
+       myvals.setValue( 0, 0.0 );
        return;
      }
   }
@@ -234,49 +234,40 @@ void SecondaryStructureRMSD::performTask(){
       nr=references[i]->calculate( pos, pbc, false );
       if( nr<r ){ closest=i; r=nr; }
   }
-  setElementValue(1,1.0); 
-  setElementValue(0,r);
-  return;
-}
 
-void SecondaryStructureRMSD::mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer ){
-  plumed_dbg_assert( ider==0 );
-  printf("MERGING \n");
-  for(unsigned i=0;i<colvar_atoms[getCurrentTask()].size();++i){
-     unsigned thisatom=getAtomIndex(i), thispos=3*thisatom; 
+  // Transfer everything to the value
+  myvals.setValue( 0, 1.0 ); myvals.setValue( 1, r );
+  for(unsigned i=0;i<colvar_atoms[current].size();++i){
+     unsigned thisatom=3*getAtomIndex(current,i);
      Vector ader=references[closest]->getAtomDerivative(i);
-     buffer[start+stride*thispos] += df*ader[0]; thispos++;
-     buffer[start+stride*thispos] += df*ader[1]; thispos++;
-     buffer[start+stride*thispos] += df*ader[2];
+     myvals.addDerivative( 1, thisatom, ader[0] ); thisatom++;
+     myvals.addDerivative( 1, thisatom, ader[1] ); thisatom++;
+     myvals.addDerivative( 1, thisatom, ader[2] );
   }
   Tensor virial;
-  if( !references[closest]->getVirial( virial ) ){ 
+  if( !references[closest]->getVirial( virial ) ){
      virial.zero();
-     for(unsigned i=0;i<colvar_atoms[getCurrentTask()].size();++i){
+     for(unsigned i=0;i<colvar_atoms[current].size();++i){
          virial+=(-1.0*Tensor( pos[i], references[closest]->getAtomDerivative(i) ));
      }
-  } 
-
-  // Easy to merge the virial
+  }
   unsigned outnat=3*getNumberOfAtoms();
-  buffer[start+stride*outnat] += df*virial(0,0); outnat++;
-  buffer[start+stride*outnat] += df*virial(0,1); outnat++;
-  buffer[start+stride*outnat] += df*virial(0,2); outnat++;
-  buffer[start+stride*outnat] += df*virial(1,0); outnat++;
-  buffer[start+stride*outnat] += df*virial(1,1); outnat++;
-  buffer[start+stride*outnat] += df*virial(1,2); outnat++;
-  buffer[start+stride*outnat] += df*virial(2,0); outnat++;
-  buffer[start+stride*outnat] += df*virial(2,1); outnat++;
-  buffer[start+stride*outnat] += df*virial(2,2); 
+  myvals.addDerivative( 1, outnat, virial(0,0) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(0,1) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(0,2) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(1,0) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(1,1) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(1,2) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(2,0) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(2,1) ); outnat++;
+  myvals.addDerivative( 1, outnat, virial(2,2) );
+
+  return;
 }
 
 void SecondaryStructureRMSD::apply(){
   if( getForcesFromVessels( forcesToApply ) ) setForcesOnAtoms( forcesToApply );
 }
 
-void SecondaryStructureRMSD::clearDerivativesAfterTask( const unsigned& ival ){
-  thisval_wasset[ival]=false; setElementValue( ival, 0.0 ); thisval_wasset[ival]=false;
-}
-
 }
 }
diff --git a/src/secondarystructure/SecondaryStructureRMSD.h b/src/secondarystructure/SecondaryStructureRMSD.h
index c953ba2b8da47d46ff0022e3fea389e23b9c14ae..141bedba76e5d309e966f272c2de08e4cb54019f 100644
--- a/src/secondarystructure/SecondaryStructureRMSD.h
+++ b/src/secondarystructure/SecondaryStructureRMSD.h
@@ -63,7 +63,7 @@ private:
   std::vector<Vector> pos;
   std::vector<double> forcesToApply;
 /// Get the index of an atom
-  unsigned getAtomIndex( const unsigned& iatom );
+  unsigned getAtomIndex( const unsigned& current, const unsigned& iatom );
 protected:
 /// Get the atoms in the backbone
   void readBackboneAtoms( const std::string& backnames, std::vector<unsigned>& chain_lengths );
@@ -83,10 +83,8 @@ public:
   void prepare();
   void finishTaskListUpdate();
   void calculate();
-  void performTask();
-  void clearDerivativesAfterTask( const unsigned& );
+  void performTask( const unsigned& , const unsigned& , vesselbase::MultiValue& );
   void apply();
-  void mergeDerivatives( const unsigned& , const double&, const unsigned, const unsigned, std::vector<double>& );
   bool isPeriodic(){ return false; }
 };
 
@@ -101,8 +99,8 @@ unsigned SecondaryStructureRMSD::getNumberOfDerivatives(){
 }
 
 inline
-unsigned SecondaryStructureRMSD::getAtomIndex( const unsigned& iatom ){
-  return all_atoms.linkIndex( colvar_atoms[getCurrentTask()][iatom] );
+unsigned SecondaryStructureRMSD::getAtomIndex( const unsigned& current, const unsigned& iatom ){
+  return all_atoms.linkIndex( colvar_atoms[current][iatom] );
 }
 
 }
diff --git a/src/vesselbase/ActionWithVessel.cpp b/src/vesselbase/ActionWithVessel.cpp
index 8e24d808eb6f26d134572da097c8116bbc96a6da..47529851960ac982eb8a39d9b39632ff2d9e6760 100644
--- a/src/vesselbase/ActionWithVessel.cpp
+++ b/src/vesselbase/ActionWithVessel.cpp
@@ -27,6 +27,7 @@
 #include "VesselRegister.h"
 #include "BridgeVessel.h"
 #include "FunctionVessel.h"
+#include "StoreDataVessel.h"
 
 using namespace std;
 namespace PLMD{
@@ -54,6 +55,7 @@ ActionWithVessel::ActionWithVessel(const ActionOptions&ao):
   serial(false),
   lowmem(false),
   noderiv(true),
+  actionIsBridged(false),
   contributorsAreUnlocked(false),
   weightHasDerivatives(false)
 {
@@ -108,6 +110,7 @@ BridgeVessel* ActionWithVessel::addBridgingVessel( ActionWithVessel* tome ){
   VesselOptions da("","",0,"",this); 
   BridgeVessel* bv=new BridgeVessel(da);
   bv->setOutputAction( tome );
+  tome->actionIsBridged=true;
   functions.push_back( dynamic_cast<Vessel*>(bv) );
   resizeFunctions();
   return bv; 
@@ -118,7 +121,16 @@ StoreDataVessel* ActionWithVessel::buildDataStashes( const bool& allow_wcutoff,
       StoreDataVessel* vsv=dynamic_cast<StoreDataVessel*>( functions[i] );
       if( vsv ) return vsv;
   }
-  return NULL;
+  
+  VesselOptions da("","",0,"",this);
+  StoreDataVessel* mydata=new StoreDataVessel(da);
+  if( allow_wcutoff ) mydata->setHardCutoffOnWeight( wtol );
+  addVessel(mydata);
+
+  // Make sure resizing of vessels is done
+  resizeFunctions();
+
+  return mydata;
 }
 
 void ActionWithVessel::addTaskToList( const unsigned& taskCode ){
@@ -169,8 +181,6 @@ void ActionWithVessel::readVesselKeywords(){
 
 void ActionWithVessel::resizeFunctions(){
   for(unsigned i=0;i<functions.size();++i) functions[i]->resize();
-  thisval.resize( getNumberOfQuantities() ); thisval_wasset.resize( getNumberOfQuantities(), false );
-  derivatives.resize( getNumberOfQuantities()*getNumberOfDerivatives(), 0.0 );
 }
 
 void ActionWithVessel::needsDerivatives(){
@@ -235,7 +245,7 @@ void ActionWithVessel::activateTheseTasks( std::vector<unsigned>& additionalTask
   contributorsAreUnlocked=false;
 }
 
-void ActionWithVessel::deactivate_task(){
+void ActionWithVessel::deactivate_task( const unsigned & task_index ){
   plumed_dbg_assert( contributorsAreUnlocked );
   taskFlags[task_index]=1;
 }
@@ -268,32 +278,34 @@ void ActionWithVessel::runAllTasks(){
   // Get size for buffer
   unsigned bsize=0, bufsize=getSizeOfBuffer( bsize ); 
 
+  // Build storage stuff for loop
   std::vector<double> buffer( bufsize, 0.0 );
+  MultiValue myvals( getNumberOfQuantities(), getNumberOfDerivatives() );
+  MultiValue bvals( getNumberOfQuantities(), getNumberOfDerivatives() );
+  myvals.clearAll(); bvals.clearAll();
+ 
   for(unsigned i=rank;i<nactive_tasks;i+=stride){
-      // The index of the task in the full list
-      task_index=indexOfTaskInFullList[i];
-      // Store the task we are currently working on
-      current=partialTaskList[i];
       // Calculate the stuff in the loop for this action
-      performTask();
+      performTask( indexOfTaskInFullList[i], partialTaskList[i], myvals );
       // Weight should be between zero and one
-      plumed_dbg_assert( getValueForTolerance()>=0 && getValueForTolerance()<=1.0 );
+      plumed_dbg_assert( myvals.get(0)>=0 && myvals.get(0)<=1.0 );
 
       // Check for conditions that allow us to just to skip the calculation
       // the condition is that the weight of the contribution is low 
       // N.B. Here weights are assumed to be between zero and one
-      if( getValueForTolerance()<tolerance ){
-         // Clear the derivatives
-         clearAfterTask();  
+      if( myvals.get(0)<tolerance ){
          // Deactivate task if it is less than the neighbor list tolerance
-         if( getValueForTolerance()<nl_tolerance && contributorsAreUnlocked ) deactivate_task();
+         if( myvals.get(0)<nl_tolerance && contributorsAreUnlocked ) deactivate_task( indexOfTaskInFullList[i] );
+         // Clear the derivatives
+         myvals.clearAll();
          continue;
       }
 
       // Now calculate all the functions
       // If the contribution of this quantity is very small at neighbour list time ignore it
       // untill next neighbour list time
-      if( !calculateAllVessels( buffer ) && contributorsAreUnlocked ) deactivate_task();
+      if( !calculateAllVessels( indexOfTaskInFullList[i], myvals, bvals, buffer ) && contributorsAreUnlocked ) deactivate_task( indexOfTaskInFullList[i] );
+      myvals.clearAll();
   }
   // MPI Gather everything
   if( !serial && buffer.size()>0 ) comm.Sum( buffer );
@@ -304,35 +316,26 @@ void ActionWithVessel::runAllTasks(){
   finishComputations( buffer );
 }
 
-void ActionWithVessel::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
-  indices[jstore]=getNumberOfDerivatives();
-  if( indices[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
-
-  unsigned kder = ntotal + jstore*getNumberOfDerivatives();
-  for(unsigned jder=0;jder<getNumberOfDerivatives();++jder){ indices[ kder ] = jder; kder++; }
-}
-
-void ActionWithVessel::clearAfterTask(){
-  // Clear the derivatives from this step
-  for(unsigned k=0;k<thisval.size();++k) clearDerivativesAfterTask(k);
+void ActionWithVessel::transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ){
+  plumed_error();
 }
 
-void ActionWithVessel::clearDerivativesAfterTask( const unsigned& ider ){
-  thisval[ider]=0.0; thisval_wasset[ider]=false;
-  if( !noderiv ){
-     unsigned kstart=ider*getNumberOfDerivatives();
-     for(unsigned j=0;j<getNumberOfDerivatives();++j) derivatives[ kstart+j ]=0.0;
-  }
-}
+// void ActionWithVessel::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
+//   indices[jstore]=getNumberOfDerivatives();
+//   if( indices[jstore]>maxder ) error("too many derivatives to store. Run with LOWMEM");
+// 
+//   unsigned kder = ntotal + jstore*getNumberOfDerivatives();
+//   for(unsigned jder=0;jder<getNumberOfDerivatives();++jder){ indices[ kder ] = jder; kder++; }
+// }
 
-bool ActionWithVessel::calculateAllVessels( std::vector<double>& buffer ){
-  bool keep=false;
+bool ActionWithVessel::calculateAllVessels( const unsigned& taskCode, MultiValue& myvals, MultiValue& bvals, std::vector<double>& buffer ){
+  bool keep=false; 
   for(unsigned j=0;j<functions.size();++j){
       // Calculate returns a bool that tells us if this particular
       // quantity is contributing more than the tolerance
-      if( functions[j]->calculate( buffer ) ) keep=true;
+      if( functions[j]->calculate( taskCode, functions[j]->transformDerivatives(taskCode, myvals, bvals), buffer ) ) keep=true;
+      if( !actionIsBridged ) bvals.clearAll(); 
   }
-  clearAfterTask();
   return keep;
 }
 
@@ -341,25 +344,6 @@ void ActionWithVessel::finishComputations( const std::vector<double>& buffer ){
   for(unsigned j=0;j<functions.size();++j) functions[j]->finish( buffer ); 
 }
 
-void ActionWithVessel::chainRuleForElementDerivatives( const unsigned& ider, const unsigned& iout, const double& df, const unsigned& buffer_start, std::vector<double>& buffer ){
-  if( noderiv ) return;
-  mergeDerivatives( ider, df, buffer_start + (getNumberOfDerivatives()+1)*iout + 1 , 1, buffer );
-} 
-
-void ActionWithVessel::chainRuleForElementDerivatives( const unsigned& ider, const unsigned& iout, const unsigned& stride, 
-                                                       const unsigned& off, const double& df, const unsigned& bufstart, 
-                                                       std::vector<double>& buffer ){
-  if( noderiv ) return;
-  plumed_dbg_assert( off<stride );
-  unsigned buffer_start=bufstart + stride*(getNumberOfDerivatives()+1)*iout + stride + off;
-  mergeDerivatives( ider, df, buffer_start, stride, buffer );
-}
-
-void ActionWithVessel::mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer ){
-  unsigned nder=getNumberOfDerivatives(), vstart=nder*ider; 
-  for(unsigned i=0;i<getNumberOfDerivatives();++i) buffer[start+stride*i] += df*derivatives[vstart+i];
-}
-
 bool ActionWithVessel::getForcesFromVessels( std::vector<double>& forcesToApply ){
 #ifndef DNDEBUG
   if( forcesToApply.size()>0 ) plumed_dbg_assert( forcesToApply.size()==getNumberOfDerivatives() );
diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h
index b5442c63b17310e458b175760281d9fe3e2c25c6..e57a93ce18aec3e4ac413c30e9cb412c5036292e 100644
--- a/src/vesselbase/ActionWithVessel.h
+++ b/src/vesselbase/ActionWithVessel.h
@@ -26,6 +26,7 @@
 #include "core/ActionAtomistic.h"
 #include "tools/Exception.h"
 #include "tools/DynamicList.h"
+#include "MultiValue.h"
 #include <vector>
 
 namespace PLMD{
@@ -57,16 +58,14 @@ private:
   bool lowmem;
 /// Are we skipping the calculation of the derivatives
   bool noderiv;
+/// This tells plumed that this is used in a bridge
+  bool actionIsBridged;
 /// The maximum number of derivatives we can use before we need to invoke lowmem
   unsigned maxderivatives;
 /// The tolerance on the accumulators 
   double tolerance;
 /// Tolerance for quantities being put in neighbor lists
   double nl_tolerance;
-/// The value of the current element in the sum
-  std::vector<double> thisval;
-/// Vector of derivatives for the object
-  std::vector<double> derivatives;
 /// Pointers to the functions we are using on each value
   std::vector<Vessel*> functions;
 /// Tempory storage for forces
@@ -74,7 +73,7 @@ private:
 /// Ths full list of tasks we have to perform
   std::vector<unsigned> fullTaskList;
 /// The current number of active tasks
-  unsigned nactive_tasks, task_index, current;
+  unsigned nactive_tasks;
 /// The indices of the tasks in the full list of tasks
   std::vector<unsigned> indexOfTaskInFullList;
 /// The list of currently active tasks
@@ -82,16 +81,12 @@ private:
 /// This list is used to update the neighbor list
   std::vector<unsigned> taskFlags;
 protected:
-/// A boolean that makes sure we don't accumulate very wrong derivatives
-  std::vector<bool> thisval_wasset; 
 /// The terms in the series are locked
   bool contributorsAreUnlocked;
 /// Does the weight have derivatives
   bool weightHasDerivatives;
 /// This is used for numerical derivatives of bridge variables
   unsigned bridgeVariable;
-/// Set the maximum number of derivatives
-  void setMaximumNumberOfDerivatives( const unsigned& );
 /// Add a vessel to the list of vessels
   void addVessel( const std::string& name, const std::string& input, const int numlab=0 );
   void addVessel( Vessel* vv );
@@ -115,11 +110,9 @@ protected:
   void resizeFunctions();
 /// This loops over all the vessels calculating them and also 
 /// sets all the element derivatives equal to zero
-  bool calculateAllVessels( std::vector<double>& buffer );
+  bool calculateAllVessels( const unsigned& taskCode, MultiValue& myvals, MultiValue& bvals, std::vector<double>& buffer );
 /// Retrieve the forces from all the vessels (used in apply)
   bool getForcesFromVessels( std::vector<double>& forcesToApply );
-/// Clear tempory data that is calculated for each task
-  void clearAfterTask();
 /// Is the calculation being done in serial
   bool serialCalculation() const;
 /// Are we using low memory
@@ -130,12 +123,6 @@ protected:
   unsigned getCurrentNumberOfActiveTasks() const ;
 /// Get the ith of the currently active tasks
   unsigned getActiveTask( const unsigned& ii ) const ;
-/// Get the position of the ith active task in the full list
-  unsigned getPositionInFullTaskList( const unsigned& ii ) const ;
-/// Get the current task's position in the task list
-  unsigned getCurrentPositionInTaskList() const ;
-/// Return the number that provides instructions for the current task
-  unsigned getCurrentTask() const ;
 /// Deactivate all the tasks in the task list
   void deactivateAllTasks();
 /// Deactivate all tasks with i in lower \f$\le\f$  i < upper
@@ -153,12 +140,7 @@ public:
   virtual void finishTaskListUpdate(){};
 /// Activate the jth colvar
 /// Deactivate the current task in future loops
-  virtual void deactivate_task();
-/// Merge the derivatives
-  void chainRuleForElementDerivatives( const unsigned&, const unsigned&, const double& , const unsigned& , std::vector<double>& );
-  void chainRuleForElementDerivatives( const unsigned&, const unsigned& , const unsigned& , const unsigned& , const double& , const unsigned& , std::vector<double>& );
-  virtual void mergeDerivatives( const unsigned& ider, const double& df, const unsigned start, const unsigned stride, std::vector<double>& buffer );
-  virtual void clearDerivativesAfterTask( const unsigned& );
+  virtual void deactivate_task( const unsigned & task_index );
 /// Are derivatives required for this quantity
   bool derivativesAreRequired() const ;
 /// Finish running all the calculations
@@ -172,43 +154,31 @@ public:
 /// Get the number of quantities that are calculated during each task
   virtual unsigned getNumberOfQuantities();
 /// Get the list of indices that have derivatives
-  virtual void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
-/// This returns the value on which we apply the tolerance - by default this is element 1 - the weight
-  virtual double getValueForTolerance();
-/// Get the index of the element in which we are storing the weight
-  virtual unsigned getIndexOfWeight();
+//  virtual void getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices );
 /// Switch on additional tasks 
   void activateTheseTasks( std::vector<unsigned>& addtionalTasks );
 /// Do any jobs that are required before the task list is undertaken
   virtual void doJobsRequiredBeforeTaskList();
 /// Get the full size of the taskList dynamic list
   unsigned getFullNumberOfTasks() const ;
+/// Get the position of the ith active task in the full list
+  unsigned getPositionInFullTaskList( const unsigned& ii ) const ;
 /// Get the code for the ii th task in the list
   unsigned getTaskCode( const unsigned& ii ) const ;
-/// Set the indices for computing a task
-  void setTaskIndexToCompute( const unsigned& itask );
 /// Calculate one of the functions in the distribution
-  virtual void performTask()=0;
-/// Set the derivative of the jth element wrt to a numbered element
-  void setElementDerivative( const unsigned&, const double& );
-///  Add some derivative of the quantity in the sum wrt to a numbered element
-  void addElementDerivative( const unsigned&, const double& );
-/// Set the value of the element
-  void setElementValue( const unsigned& , const double& );
-/// Add to an element value
-  void addElementValue( const unsigned&, const double& );
-/// Get the value of this element
-  double getElementValue( const unsigned& ival ) const ;
-/// Retrieve the derivative of the quantity in the sum wrt to a numbered element
-  double getElementDerivative( const unsigned& ) const ;
+  virtual void performTask( const unsigned& , const unsigned& , MultiValue& )=0;
+/// Do the task if we have a bridge
+  virtual void transformBridgedDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals );
 /// Ensure that data required in other vessels is stored
-  virtual StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
+  StoreDataVessel* buildDataStashes( const bool& allow_wcutoff, const double& wtol );
 /// Apply forces from bridge vessel - this is rarely used - currently only in ActionVolume
   virtual void applyBridgeForces( const std::vector<double>& bb ){ plumed_error(); }
 /// These are overwritten in MultiColvarFunction
   virtual void activateIndexes( const unsigned&, const unsigned&, const std::vector<unsigned>& ){}
 /// Return a particular named vessel
   Vessel* getVesselWithName( const std::string& mynam );
+/// Does the weight have derivatives
+  bool weightWithDerivatives() const ;
 };
 
 inline
@@ -237,48 +207,6 @@ Vessel* ActionWithVessel::getPntrToVessel( const unsigned& i ){
   return functions[i];
 }
 
-inline
-double ActionWithVessel::getElementValue(const unsigned& ival) const {
-  return thisval[ival];
-}
-
-inline
-void ActionWithVessel::setElementValue( const unsigned& ival, const double& val ){
-  // Element 0 is reserved for the value we are accumulating
-  // Element 1 is reserved for the normalization constant for calculating AVERAGES, normalized HISTOGRAMS
-  // plumed_dbg_massert( !thisval_wasset[ival], "In action named " + getName() + " with label " + getLabel() );
-  thisval[ival]=val;
-  thisval_wasset[ival]=true;
-}
-
-inline
-void ActionWithVessel::addElementValue( const unsigned& ival, const double& val ){
-  thisval[ival]+=val;
-  thisval_wasset[ival]=true;
-}
-
-inline
-double ActionWithVessel::getElementDerivative( const unsigned& ider ) const {
-  plumed_dbg_assert( ider<derivatives.size() );
-  return derivatives[ider];
-}
-
-inline
-void ActionWithVessel::addElementDerivative( const unsigned& ider, const double& der ){
-#ifndef NDEBUG
-  unsigned ndertmp=getNumberOfDerivatives();
-  if( ider>=ndertmp && ider<2*ndertmp ) plumed_dbg_massert( weightHasDerivatives, "In " + getLabel() );
-#endif
-  plumed_dbg_assert( ider<derivatives.size() );
-  derivatives[ider] += der;
-}
-
-inline
-void ActionWithVessel::setElementDerivative( const unsigned& ider, const double& der ){
-  plumed_dbg_assert( ider<derivatives.size() );
-  derivatives[ider] = der;
-}
-
 inline
 unsigned ActionWithVessel::getFullNumberOfTasks() const {
   return fullTaskList.size();
@@ -322,34 +250,14 @@ void ActionWithVessel::setLowMemOption(const bool& l){
   lowmem=l;
 }
 
-inline
-unsigned ActionWithVessel::getCurrentTask() const {
-  return current;
-}
-
-inline
-unsigned ActionWithVessel::getCurrentPositionInTaskList() const {
-  return task_index; 
-}
-
 inline
 bool ActionWithVessel::derivativesAreRequired() const {
   return !noderiv;
 }
 
 inline
-double ActionWithVessel::getValueForTolerance(){
-  return thisval[1];
-}
-
-inline
-unsigned ActionWithVessel::getIndexOfWeight(){
-  return 1;
-}
-
-inline
-void ActionWithVessel::setTaskIndexToCompute( const unsigned& itask ){
-  current=fullTaskList[itask]; task_index=itask;
+bool ActionWithVessel::weightWithDerivatives() const {
+  return weightHasDerivatives;
 }
 
 } 
diff --git a/src/vesselbase/Between.cpp b/src/vesselbase/Between.cpp
index d167f6ae2f35bd7a210e13511f5d73a68a98b862..2a3dabea53d84ca2f8aed576de6b59c915c36045 100644
--- a/src/vesselbase/Between.cpp
+++ b/src/vesselbase/Between.cpp
@@ -67,10 +67,8 @@ std::string Between::function_description(){
   return "the number of values " + hist.description();
 }
 
-bool Between::calculate( std::vector<double>& buffer ){
-  double val=getAction()->getElementValue(0);
-  double dval, f = hist.calculate(val, dval);
-  return addToBuffers( f, dval, buffer );
+double Between::calcTransform( const double& val, double& dv ){
+  double f = hist.calculate(val, dv); return f; 
 }
 
 double Between::getCutoff(){
diff --git a/src/vesselbase/Between.h b/src/vesselbase/Between.h
index 2d8aa9488455a86850bc708bbeca3a010a414669..593f1993d17378f5331fde6bc429b0f15eb32560 100644
--- a/src/vesselbase/Between.h
+++ b/src/vesselbase/Between.h
@@ -36,7 +36,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   Between( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
   double getCutoff();
 };
 
diff --git a/src/vesselbase/BridgeVessel.cpp b/src/vesselbase/BridgeVessel.cpp
index 572d2d786680ee4f809ce7246017f53dd4b5b901..dceec770437191c5a221de5ccb4349c59eaf7fcb 100644
--- a/src/vesselbase/BridgeVessel.cpp
+++ b/src/vesselbase/BridgeVessel.cpp
@@ -62,16 +62,21 @@ void BridgeVessel::setBufferStart( unsigned& start ){
   unsigned tmp=myOutputAction->getSizeOfBuffer( start );
 }
 
-bool BridgeVessel::calculate( std::vector<double>& buffer ){
+MultiValue& BridgeVessel::transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals ){
+  if( outvals.getNumberOfValues()!=myOutputAction->getNumberOfQuantities() ||
+      outvals.getNumberOfDerivatives()!=myOutputAction->getNumberOfDerivatives() ){
+       outvals.resize( myOutputAction->getNumberOfQuantities(), myOutputAction->getNumberOfDerivatives() );
+  }
+  myOutputAction->transformBridgedDerivatives( current, invals, outvals );
+  return outvals;
+}
+
+bool BridgeVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer ){
   in_normal_calculate=true;
-  myOutputAction->task_index = getAction()->task_index;
-  myOutputAction->current = getAction()->current;
-  myOutputAction->performTask();
-  if( myOutputAction->getValueForTolerance()<myOutputAction->getTolerance() ){
-      myOutputAction->clearAfterTask();
-      return ( !myOutputAction->contributorsAreUnlocked || myOutputAction->getValueForTolerance()>=myOutputAction->getNLTolerance() );
+  if( myvals.get(0)<myOutputAction->getTolerance() ){
+      return ( !myOutputAction->contributorsAreUnlocked || myvals.get(0)>=myOutputAction->getNLTolerance() );
   }
-  bool keep=myOutputAction->calculateAllVessels( buffer );    
+  bool keep=myOutputAction->calculateAllVessels( current, myvals, myvals, buffer );    
   in_normal_calculate=false;
   return ( !myOutputAction->contributorsAreUnlocked || keep );
 }
diff --git a/src/vesselbase/BridgeVessel.h b/src/vesselbase/BridgeVessel.h
index 71216676689af6112d23db0504bb79ea0428dbc3..fc6c914bd3dc06a01a70b4029c504552c393d768 100644
--- a/src/vesselbase/BridgeVessel.h
+++ b/src/vesselbase/BridgeVessel.h
@@ -60,8 +60,10 @@ public:
   void prepare();
 /// Set the start of the buffer 
   void setBufferStart( unsigned& start );
+/// This transforms the derivatives using the output value
+  MultiValue& transformDerivatives( const unsigned& current, MultiValue& invals, MultiValue& outvals );
 /// Actually do the calculation
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer );
 /// Finish the calculation
   void finish( const std::vector<double>& buffer );
 /// Calculate numerical derivatives
diff --git a/src/vesselbase/FunctionVessel.cpp b/src/vesselbase/FunctionVessel.cpp
index a195da74e28f4a4cc3c5221f57c93ed011f1afe5..5aad279d770862235bd21d97e04e6c03faac9acf 100644
--- a/src/vesselbase/FunctionVessel.cpp
+++ b/src/vesselbase/FunctionVessel.cpp
@@ -48,7 +48,6 @@ usetol(false)
   }
   final_value=a->copyOutput( a->getNumberOfComponents()-1 );
   diffweight=getAction()->weightHasDerivatives;
-  wnum=getAction()->getIndexOfWeight();
 }
 
 std::string FunctionVessel::description(){
@@ -61,9 +60,11 @@ void FunctionVessel::resize(){
      nderivatives=getAction()->getNumberOfDerivatives();
      resizeBuffer( (1+nderivatives)*2 ); 
      final_value->resizeDerivatives( nderivatives );
+     diffweight=getAction()->weightHasDerivatives;
   } else {
      nderivatives=0;
      resizeBuffer(2);
+     diffweight=false;  // Don't need to worry about differentiable weights if no derivatives
   }
 }
 
@@ -72,26 +73,33 @@ void FunctionVessel::setNumberOfDerivatives( const unsigned& nder ){
   final_value->resizeDerivatives( nder );
 }
 
-bool FunctionVessel::addToBuffers( const double& f, const double& dval, std::vector<double>& buffer ){
-  double weight=getAction()->getElementValue(wnum);
+bool FunctionVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer ){
+  double weight=myvals.get(0); 
   plumed_dbg_assert( weight>=getTolerance() );  
 
+  // This deals with the value
+  double dval, f=calcTransform( myvals.get(1), dval );
+
   if( norm ){
      if( usetol && weight<getTolerance() ) return false;
      buffer[bufstart+1+nderivatives] += weight;
-     if( diffweight ) getAction()->chainRuleForElementDerivatives( wnum, 1, 1.0, bufstart, buffer );
+     if( diffweight ) myvals.chainRule( 0, 1, 1, 0, 1.0, bufstart, buffer );
   }
 
   double contr=weight*f;
   if( usetol && contr<getTolerance() ) return false;
   buffer[bufstart] += contr;
 
-  if( diffweight ) getAction()->chainRuleForElementDerivatives( wnum, 0, f, bufstart, buffer );
-  if(fabs(dval)>0.0) getAction()->chainRuleForElementDerivatives( 0, 0, weight*dval, bufstart, buffer );
+  if( diffweight ) myvals.chainRule( 0, 0, 1, 0, f, bufstart, buffer ); 
+  if( getAction()->derivativesAreRequired() && fabs(dval)>0.0 ) myvals.chainRule( 1, 0, 1, 0, weight*dval, bufstart, buffer );
 
   return true;
 }
 
+double FunctionVessel::calcTransform( const double& , double& ){ 
+  plumed_error(); return 1.0; 
+}
+
 void FunctionVessel::finish( const std::vector<double>& buffer ){
   if( norm && diffweight ){
       double dv, val=finalTransform( buffer[bufstart], dv), weight=buffer[bufstart+1+nderivatives];
diff --git a/src/vesselbase/FunctionVessel.h b/src/vesselbase/FunctionVessel.h
index 064dfedaf8784d71661ec1bebe926f06d11c3842..08157928f0ac309db713e91edeb979bad261d34a 100644
--- a/src/vesselbase/FunctionVessel.h
+++ b/src/vesselbase/FunctionVessel.h
@@ -42,8 +42,6 @@ class FunctionVessel : public Vessel {
 private:
 /// The number of derivatives
   unsigned nderivatives;
-/// The index of the weight
-  unsigned wnum;
 /// This is the pointer to the value we are creating
   Value* final_value;
 protected:
@@ -61,8 +59,6 @@ protected:
   void setNumberOfDerivatives( const unsigned& nder );
 /// Return a pointer to the final value
   void addDerivativeToFinalValue( const unsigned& j, const double& der  );
-/// Add some value to the buffers
-  bool addToBuffers( const double& f, const double& dval, std::vector<double>& buffer );
 public:
   static void registerKeywords( Keywords& keys );
   FunctionVessel( const VesselOptions& );
@@ -74,6 +70,10 @@ public:
   std::string description();
 /// The rest of the description of what we are calculating
   virtual std::string function_description()=0;
+/// Do the calcualtion
+  virtual bool calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer );
+/// Do any transformations of the value that are required
+  virtual double calcTransform( const double& val, double& df );
 /// Finish the calculation of the quantity
   virtual void finish( const std::vector<double>& buffer );
 /// Finish with any transforms required
diff --git a/src/vesselbase/LessThan.cpp b/src/vesselbase/LessThan.cpp
index 2b30c7c0cc204a4ce2a6983c221cd535a7b5037f..479f3afac78e3c101afd4942af97c5f67b09e2ff 100644
--- a/src/vesselbase/LessThan.cpp
+++ b/src/vesselbase/LessThan.cpp
@@ -54,10 +54,8 @@ std::string LessThan::function_description(){
   return "the number of values less than " + sf.description();
 }
 
-bool LessThan::calculate( std::vector<double>& buffer ){
-  double val=getAction()->getElementValue(0);
-  double dval, f = sf.calculate(val, dval); dval*=val;
-  return addToBuffers( f, dval, buffer );
+double LessThan::calcTransform( const double& val, double& dv ){
+  double f = sf.calculate(val, dv); dv*=val; return f;
 }
 
 double LessThan::getCutoff(){
diff --git a/src/vesselbase/LessThan.h b/src/vesselbase/LessThan.h
index a7f6616f1677bd19103587f1ce8a304b1d2ad359..24bf15148f2c37e5da16ecb28025f2a318467428 100644
--- a/src/vesselbase/LessThan.h
+++ b/src/vesselbase/LessThan.h
@@ -37,7 +37,7 @@ public:
   static void reserveKeyword( Keywords& keys ); 
   LessThan( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
   double getCutoff();
 };
 
diff --git a/src/vesselbase/Max.cpp b/src/vesselbase/Max.cpp
index d81cb1a306ce5ac63a97f0606decd44973ce1549..13b5a995ce6770dffcadaad33e84569f225a283c 100644
--- a/src/vesselbase/Max.cpp
+++ b/src/vesselbase/Max.cpp
@@ -34,7 +34,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   Max( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
   double finalTransform( const double& val, double& dv );
 };
 
@@ -69,10 +69,8 @@ std::string Max::function_description(){
   return "the maximum value. Beta is equal to " + str_beta;
 }
 
-bool Max::calculate( std::vector<double>& buffer ){
-  double val=getAction()->getElementValue(0);
-  double dval, f = exp(val/beta); dval=f/beta;
-  return addToBuffers( f, dval, buffer );
+double Max::calcTransform( const double& val, double& dv ){
+  double f = exp(val/beta); dv=f/beta; return f;
 }
 
 double Max::finalTransform( const double& val, double& dv ){
diff --git a/src/vesselbase/Mean.cpp b/src/vesselbase/Mean.cpp
index ebc79b8c69e42c19b9e904e72cc9c3544f951a65..529788360d4ecf1a270300ed77e00cd42d6a48de 100644
--- a/src/vesselbase/Mean.cpp
+++ b/src/vesselbase/Mean.cpp
@@ -32,7 +32,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   Mean( const vesselbase::VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
 };
 
 PLUMED_REGISTER_VESSEL(Mean,"MEAN")
@@ -58,9 +58,8 @@ std::string Mean::function_description(){
   return "the mean value";
 }
 
-bool Mean::calculate( std::vector<double>& buffer ){
- double colvar=getAction()->getElementValue(0);
- return addToBuffers( colvar, 1.0, buffer ); 
+double Mean::calcTransform( const double& val, double& dv ){
+  dv=1.0; return val;
 }
 
 }
diff --git a/src/vesselbase/Min.cpp b/src/vesselbase/Min.cpp
index f91372bff9b16d99b9e9eb6b14111e5208c6c784..a14c1f6bb8fc51c021100a3be15ed926105bcac7 100644
--- a/src/vesselbase/Min.cpp
+++ b/src/vesselbase/Min.cpp
@@ -34,7 +34,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   Min( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
   double finalTransform( const double& val, double& dv );
 };
 
@@ -68,10 +68,9 @@ std::string Min::function_description(){
   return "the minimum value. Beta is equal to " + str_beta;
 }
 
-bool Min::calculate( std::vector<double>& buffer ){
-  double val=getAction()->getElementValue(0);
-  double dval, f = exp(beta/val); dval=f/(val*val);
-  return addToBuffers( f, dval, buffer );
+double Min::calcTransform( const double& val, double& dv ){
+  double f = exp(beta/val); dv=f/(val*val);
+  return f; 
 }
 
 double Min::finalTransform( const double& val, double& dv ){
diff --git a/src/vesselbase/Moments.cpp b/src/vesselbase/Moments.cpp
index 83b23db2cd59997f5bbdcc8ee6a9978b129633ee..89264c0bcb631efdbceb8ad0a16cd634c1d319e4 100644
--- a/src/vesselbase/Moments.cpp
+++ b/src/vesselbase/Moments.cpp
@@ -20,7 +20,7 @@
    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 #include "VesselRegister.h"
-#include "StoreValueVessel.h"
+#include "StoreDataVessel.h"
 #include "ActionWithVessel.h"
 
 namespace PLMD {
@@ -30,7 +30,7 @@ namespace vesselbase{
 // The calculation of all the colvars is parallelized 
 // but the loops for calculating moments are not
 // Feel free to reimplement this if you know how
-class Moments : public StoreValueVessel {
+class Moments : public StoreDataVessel {
 private:
   std::vector<unsigned> powers;
   std::vector<Value*> value_out;
@@ -47,7 +47,7 @@ public:
 PLUMED_REGISTER_VESSEL(Moments,"MOMENTS")
 
 void Moments::registerKeywords( Keywords& keys ){
-  StoreValueVessel::registerKeywords( keys );
+  StoreDataVessel::registerKeywords( keys );
 }
 
 void Moments::reserveKeyword( Keywords& keys ){
@@ -61,7 +61,7 @@ void Moments::reserveKeyword( Keywords& keys ){
 }
 
 Moments::Moments( const vesselbase::VesselOptions& da) :
-StoreValueVessel(da)
+StoreDataVessel(da)
 {
    ActionWithValue* a=dynamic_cast<ActionWithValue*>( getAction() );
    plumed_massert(a,"cannot create passable values as base action does not inherit from ActionWithValue");
@@ -80,9 +80,6 @@ StoreValueVessel(da)
 
 void Moments::resize(){
    StoreDataVessel::resize();
-   if( value_out[0]->getNumberOfDerivatives()>0 ){
-      unsigned nder=getAction()->getNumberOfDerivatives();
-   }
 }
 
 std::string Moments::description(){
@@ -108,33 +105,34 @@ void Moments::finish( const std::vector<double>& buffer ){
      double pfactor, min, max; Tools::convert(str_min,min); Tools::convert(str_max,max);
      pfactor = 2*pi / ( max-min ); myvalue.setDomain( str_min, str_max );
      double sinsum=0, cossum=0, val;
-     for(unsigned i=0;i<nvals;++i){ val=pfactor*( getValue(i) - min ); sinsum+=sin(val); cossum+=cos(val); }
+     for(unsigned i=0;i<nvals;++i){ val=pfactor*( buffer[i*nspace*vecsize+nspace] - min ); sinsum+=sin(val); cossum+=cos(val); }
      mean = 0.5 + atan2( sinsum / static_cast<double>( nvals ) , cossum / static_cast<double>( nvals ) ) / (2*pi);
      mean = min + (max-min)*mean;
   } else {
-     for(unsigned i=0;i<nvals;++i) mean+=getValue(i);    
+     for(unsigned i=0;i<nvals;++i) mean+=buffer[i*nspace*vecsize+nspace];    
      mean/=static_cast<double>( nvals ); myvalue.setNotPeriodic();
   }
 
   for(unsigned npow=0;npow<powers.size();++npow){
      double dev1=0; 
      if( value_out[0]->getNumberOfDerivatives()>0 ){
-         for(unsigned i=0;i<nvals;++i) dev1+=pow( myvalue.difference( mean, getValue(i) ), powers[npow] - 1 ); 
+         for(unsigned i=0;i<nvals;++i) dev1+=pow( myvalue.difference( mean, buffer[i*nspace*vecsize+nspace] ), powers[npow] - 1 ); 
          dev1/=static_cast<double>( nvals );
      }
 
-     std::vector<double> pref(1); double tmp, moment=0; 
+     double moment=0;
+     MultiValue myvals( getNumberOfComponents(), getAction()->getNumberOfDerivatives() ); myvals.clearAll();
      for(unsigned i=0;i<nvals;++i){
-         tmp=myvalue.difference( mean, getValue(i) );
+         double tmp=myvalue.difference( mean, buffer[i*nspace*vecsize+nspace] );
          moment+=pow( tmp, powers[npow] );
          if( value_out[npow]->getNumberOfDerivatives() ){
-             pref[0]=pow( tmp, powers[npow] - 1 ) - dev1;
-             if( usingLowMem() ){
-                recompute( i, 0 ); // Not very efficient 
-                chainRule( 0, pref, value_out[npow] );
-             } else {
-                chainRule( i, pref, value_out[npow] );
-             }
+             double pref=pow( tmp, powers[npow] - 1 ) - dev1;
+             retrieveDerivatives( i, false, myvals );
+             for(unsigned j=0;j<myvals.getNumberActive();++j){   
+                 unsigned jatom=myvals.getActiveIndex(j);
+                 value_out[npow]->addDerivative(jatom, pref*myvals.getDerivative( 1, jatom ) );
+             } 
+             myvals.clearAll();
          }
      }
      if( value_out[npow]->getNumberOfDerivatives()>0 ) value_out[npow]->chainRule( powers[npow] / static_cast<double>( nvals ) );
diff --git a/src/vesselbase/MoreThan.cpp b/src/vesselbase/MoreThan.cpp
index d1abe6fa30c810537233f09a7925c18d7100d5eb..8012481550d10fc9bfd80a11f75385ceeb151c37 100644
--- a/src/vesselbase/MoreThan.cpp
+++ b/src/vesselbase/MoreThan.cpp
@@ -36,7 +36,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   MoreThan( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
 };
 
 PLUMED_REGISTER_VESSEL(MoreThan,"MORE_THAN")
@@ -68,10 +68,8 @@ std::string MoreThan::function_description(){
   return "the number of values more than " + sf.description();
 }
 
-bool MoreThan::calculate( std::vector<double>& buffer ){
-  double val=getAction()->getElementValue(0);
-  double dval, f = 1.0 - sf.calculate(val, dval); dval*=-val;
-  return addToBuffers( f, dval, buffer );   
+double MoreThan::calcTransform( const double& val, double& dv ){
+  double f = 1.0 - sf.calculate(val, dv); dv*=-val; return f; 
 }
 
 }
diff --git a/src/vesselbase/MultiValue.cpp b/src/vesselbase/MultiValue.cpp
index 2d117db28f0ef494ab028c513f2b8ae7293b6ef9..3a7823e3fbf1f1a2e7bbbd859e5f292ec86be746 100644
--- a/src/vesselbase/MultiValue.cpp
+++ b/src/vesselbase/MultiValue.cpp
@@ -33,6 +33,13 @@ derivatives(nvals,nder)
   hasDerivatives.deactivateAll();
 }
 
+void MultiValue::resize( const unsigned& nvals, const unsigned& nder ){
+  values.resize(nvals); derivatives.resize( nvals, nder );
+  hasDerivatives.clear();
+  for(unsigned i=0;i<nder;++i) hasDerivatives.addIndexToList( i );
+  hasDerivatives.deactivateAll();
+}
+
 void MultiValue::clearAll(){
   if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers();
   for(unsigned i=0;i<values.size();++i) clear(i);
@@ -58,5 +65,37 @@ void MultiValue::chainRule( const unsigned& ival, const unsigned& iout, const un
   }
 }
 
+void MultiValue::copyValues( MultiValue& outvals ) const { 
+  plumed_dbg_assert( values.size()<=outvals.getNumberOfValues() );
+  for(unsigned i=0;i<values.size();++i) outvals.setValue( i, values[i] ); 
+  
+}
+
+void MultiValue::copyDerivatives( MultiValue& outvals ){
+  plumed_dbg_assert( values.size()<=outvals.getNumberOfValues() && derivatives.ncols()<=outvals.getNumberOfDerivatives() );
+
+  if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers();
+
+  for(unsigned i=0;i<values.size();++i){
+     for(unsigned j=0;j<hasDerivatives.getNumberActive();++j){
+        unsigned jder=hasDerivatives[j];
+        outvals.addDerivative( i, jder, derivatives(i,jder) );
+     }
+  }
+}
+
+void MultiValue::quotientRule( const unsigned& nder, const unsigned& dder, const unsigned& oder ){
+  plumed_dbg_assert( nder<values.size() && dder<values.size() && oder<values.size() );
+
+  if( !hasDerivatives.updateComplete() ) hasDerivatives.updateActiveMembers();
+
+  double weight = values[dder], pref = values[nder] / (weight*weight);
+  for(unsigned j=0;j<hasDerivatives.getNumberActive();++j){
+      unsigned jder=hasDerivatives[j];
+      derivatives(oder,jder) = derivatives(nder,jder) / weight - pref*derivatives(dder,jder);
+  }
+  values[oder] = values[nder] / values[dder];
+}
+
 }
 }
diff --git a/src/vesselbase/MultiValue.h b/src/vesselbase/MultiValue.h
index 051abbb063a38b9716afa24f3062a975ca004dbf..57203c3231e61cf1987ac0e1c0d3ab99c91f6fab 100644
--- a/src/vesselbase/MultiValue.h
+++ b/src/vesselbase/MultiValue.h
@@ -40,20 +40,57 @@ private:
   Matrix<double> derivatives;
 public:
   MultiValue( const unsigned& , const unsigned& );
+  void resize( const unsigned& , const unsigned& );
+/// Get the number of values in the stash
+  unsigned getNumberOfValues() const ; 
+/// Get the number of derivatives in the stash
+  unsigned getNumberOfDerivatives() const ;
 /// Set value numbered
   void setValue( const unsigned&,  const double& );
+/// Add value numbered
+  void addValue( const unsigned&,  const double& );
 /// Add derivative
   void addDerivative( const unsigned& , const unsigned& , const double& );
+/// Set the value of the derivative
+  void setDerivative( const unsigned& ival, const unsigned& jder, const double& der);
 /// Return the ith value
   double get( const unsigned& ) const ;
+/// Return a derivative value
+  double getDerivative( const unsigned&, const unsigned& ) const ;
 /// Clear all values
   void clearAll();
 /// Clear a value
   void clear( const unsigned& );
+/// Functions for accessing active list
+  bool updateComplete();
+  void emptyActiveMembers();
+  void updateIndex( const unsigned & );
+  void sortActiveList();
+  void updateDynamicList();
+///
+  unsigned getNumberActive();
+///
+  unsigned getActiveIndex( const unsigned& ) const ;
 /// Transfer derivatives to buffer
   void chainRule( const unsigned& , const unsigned& , const unsigned&, const unsigned& , const double& , const unsigned& , std::vector<double>& buffer );
+///
+  void copyValues( MultiValue& ) const ;
+///
+  void copyDerivatives( MultiValue& );
+///
+  void quotientRule( const unsigned& nder, const unsigned& dder, const unsigned& oder );
 };
 
+inline
+unsigned MultiValue::getNumberOfValues() const {
+  return values.size();
+}
+
+inline
+unsigned MultiValue::getNumberOfDerivatives() const {
+  return derivatives.ncols();
+}
+
 inline
 double MultiValue::get( const unsigned& ival ) const {
   plumed_dbg_assert( ival<=values.size() );
@@ -66,12 +103,67 @@ void MultiValue::setValue( const unsigned& ival,  const double& val){
   values[ival]=val;
 }
 
+inline
+void MultiValue::addValue( const unsigned& ival,  const double& val){
+  plumed_dbg_assert( ival<=values.size() );
+  values[ival]+=val;
+}
+
 inline
 void MultiValue::addDerivative( const unsigned& ival, const unsigned& jder, const double& der){
   plumed_dbg_assert( ival<=values.size() );
   hasDerivatives.activate(jder); derivatives(ival,jder) += der;
 }
 
+inline
+void MultiValue::setDerivative( const unsigned& ival, const unsigned& jder, const double& der){
+  plumed_dbg_assert( ival<=values.size() );
+  hasDerivatives.activate(jder); derivatives(ival,jder)=der;
+}
+
+
+inline
+double MultiValue::getDerivative( const unsigned& ival, const unsigned& jder ) const {
+  plumed_dbg_assert( jder<derivatives.ncols() && hasDerivatives.isActive(jder) );
+  return derivatives(ival,jder);
+}
+
+inline
+bool MultiValue::updateComplete(){
+  return hasDerivatives.updateComplete();
+}
+
+inline
+void MultiValue::emptyActiveMembers(){
+  hasDerivatives.emptyActiveMembers();
+}
+
+inline
+void MultiValue::updateIndex( const unsigned& ind ){
+  hasDerivatives.updateIndex( ind );
+}
+
+inline
+void MultiValue::sortActiveList(){
+  hasDerivatives.sortActiveList();
+}
+
+inline
+unsigned MultiValue::getNumberActive(){
+  return hasDerivatives.getNumberActive();
+}
+
+inline
+unsigned MultiValue::getActiveIndex( const unsigned& ind ) const {
+  plumed_dbg_assert( ind<hasDerivatives.getNumberActive() );
+  return hasDerivatives[ind];
+}
+
+inline
+void MultiValue::updateDynamicList(){
+  hasDerivatives.updateActiveMembers();
+}
+
 }
 }
 #endif
diff --git a/src/vesselbase/ShortcutVessel.h b/src/vesselbase/ShortcutVessel.h
index 90b6a7d942b0dec132666de769db9a2edefec1fe..b1a2d88f2fd8d274a9aa8fb5157120d53f1775ce 100644
--- a/src/vesselbase/ShortcutVessel.h
+++ b/src/vesselbase/ShortcutVessel.h
@@ -39,7 +39,7 @@ public:
   ShortcutVessel( const VesselOptions& );
   std::string description(){ return ""; }
   void resize(){ plumed_error(); }
-  bool calculate( std::vector<double>& buffer ){ plumed_error(); }
+  bool calculate( const unsigned& taskCode, MultiValue& myvals, std::vector<double>& buffer ){ plumed_error(); }
   void finish( const std::vector<double>& buffer ){ plumed_error(); }
   bool applyForce( std::vector<double>& forces ){ plumed_error(); }
 };
diff --git a/src/vesselbase/StoreDataVessel.cpp b/src/vesselbase/StoreDataVessel.cpp
index baa132d40d2177e48e9e232f00f8f2e8fd8dd7f5..b1b35f484c82eccc8a58083873f9a84b035a7406 100644
--- a/src/vesselbase/StoreDataVessel.cpp
+++ b/src/vesselbase/StoreDataVessel.cpp
@@ -37,6 +37,8 @@ hard_cut(false)
   ActionWithValue* myval=dynamic_cast<ActionWithValue*>( getAction() );
   if( !myval ) hasderiv=false;
   else hasderiv=!myval->doNotCalculateDerivatives();
+
+  vecsize=getAction()->getNumberOfQuantities();
 }
 
 void StoreDataVessel::setHardCutoffOnWeight( const double& mytol ){
@@ -47,19 +49,19 @@ bool StoreDataVessel::weightCutoffIsOn() const {
   return hard_cut;
 }
 
-void StoreDataVessel::completeSetup( const unsigned& dstart, const unsigned& nvec ){
-  if( (dstart+nvec)>getAction()->getNumberOfQuantities() ) error("this vessel can not be used with this action");
-  data_start=dstart; vecsize = nvec; fvec.resize( vecsize ); 
-}
+// void StoreDataVessel::completeSetup( const unsigned& dstart, const unsigned& nvec ){
+//   if( (dstart+nvec)>getAction()->getNumberOfQuantities() ) error("this vessel can not be used with this action");
+//   data_start=dstart; vecsize = nvec; // fvec.resize( vecsize ); 
+// }
 
 void StoreDataVessel::resize(){
   plumed_dbg_assert( vecsize>0 );
-  if( getAction()->derivativesAreRequired() ) final_derivatives.resize( getAction()->getNumberOfDerivatives() );
+//  if( getAction()->derivativesAreRequired() ) final_derivatives.resize( getAction()->getNumberOfDerivatives() );
 
   if( getAction()->lowmem || !getAction()->derivativesAreRequired() ){
      nspace = 1;
      active_der.resize( max_lowmem_stash * ( 1 + getAction()->getNumberOfDerivatives() ) );
-     local_derivatives.resize( max_lowmem_stash * vecsize * getAction()->getNumberOfDerivatives() );
+//     local_derivatives.resize( max_lowmem_stash * vecsize * getAction()->getNumberOfDerivatives() );
   } else {
      nspace = 1 + getAction()->maxderivatives;
      active_der.resize( getAction()->getFullNumberOfTasks() * ( 1 + getAction()->maxderivatives ) );
@@ -75,89 +77,173 @@ void StoreDataVessel::prepare(){
   active_val.assign(active_val.size(),0);
 }
 
-void StoreDataVessel::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
-  getAction()->getIndexList( ntotal, jstore, maxder, indices );
-}
-
-void StoreDataVessel::setTaskToRecompute( const unsigned& ivec ){
- getAction()->current = getAction()->fullTaskList[ivec];
- getAction()->task_index = ivec;
-}
-
-void StoreDataVessel::recompute( const unsigned& ivec, const unsigned& jstore ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() && getAction()->lowmem && jstore<max_lowmem_stash );
-  // Set the task we want to reperform
-  setTaskToRecompute( ivec );
-  // Reperform the task
-  performTask( jstore );
-  // Store the derivatives
-  storeDerivativesLowMem( jstore );
- 
-  // Clear up afterwards
-  getAction()->clearAfterTask();
-}
-
-void StoreDataVessel::storeValues( const unsigned& myelem, std::vector<double>& buffer ){
-  ActionWithVessel* act = getAction(); active_val[myelem]=1; // Keeps track of which values are stashed
-  unsigned ibuf = bufstart + myelem * vecsize * nspace;
-  for(unsigned icomp=data_start;icomp<data_start + vecsize;++icomp){
-     buffer[ibuf] = act->getElementValue( icomp ); ibuf+=nspace;
-     //setBufferElement( ibuf, act->getElementValue( icomp ) ); ibuf+=nspace;  
+// void StoreDataVessel::getIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ){
+// //  getAction()->getIndexList( ntotal, jstore, maxder, indices );
+// }
+// 
+// void StoreDataVessel::setTaskToRecompute( const unsigned& ivec ){
+// // getAction()->current = getAction()->fullTaskList[ivec];
+// // getAction()->task_index = ivec;
+// }
+// 
+// void StoreDataVessel::recompute( const unsigned& ivec, const unsigned& jstore ){
+//   plumed_dbg_assert( getAction()->derivativesAreRequired() && getAction()->lowmem && jstore<max_lowmem_stash );
+//   // Set the task we want to reperform
+//   setTaskToRecompute( ivec );
+//   // Reperform the task
+//   performTask( jstore );
+//   // Store the derivatives
+//   storeDerivativesLowMem( jstore );
+//  
+//   // Clear up afterwards
+//   // getAction()->clearAfterTask();
+// }
+
+void StoreDataVessel::storeValues( const unsigned& myelem, MultiValue& myvals, std::vector<double>& buffer ){
+  unsigned ibuf = bufstart + myelem * vecsize * nspace; active_val[myelem]=1;
+  for(unsigned icomp=0;icomp<vecsize;++icomp){
+      buffer[ibuf] = myvals.get(icomp); ibuf+=nspace;
   }
 }
 
-void StoreDataVessel::storeDerivativesHighMem( const unsigned& myelem, std::vector<double>& buffer ){
+void StoreDataVessel::storeDerivatives( const unsigned& myelem, MultiValue& myvals, std::vector<double>& buffer ){
   plumed_dbg_assert( getAction()->derivativesAreRequired() && myelem<getAction()->getFullNumberOfTasks() );
-  ActionWithVessel* act=getAction();
-  getIndexList( act->getFullNumberOfTasks(), myelem, nspace-1, active_der );
+  active_der[myelem]=myvals.getNumberActive();
+  // getIndexList( act->getFullNumberOfTasks(), myelem, nspace-1, active_der );
 
   // Store the values of the components and the derivatives if 
-  unsigned nder = act->getNumberOfDerivatives();
-  for(unsigned icomp=data_start;icomp<data_start + vecsize;++icomp){
-     unsigned ibuf = bufstart + myelem * ( vecsize*nspace ) + (icomp-data_start)*nspace + 1;
-     unsigned kder = act->getFullNumberOfTasks() + myelem * ( nspace - 1 );
-     for(unsigned jder=0;jder<active_der[myelem];++jder){
-        buffer[ibuf] += act->getElementDerivative(nder*icomp + active_der[ kder ]);
+  // unsigned nder =getAction()->getNumberOfDerivatives();
+  for(unsigned icomp=0;icomp<vecsize;++icomp){
+     unsigned ibuf = bufstart + myelem * ( vecsize*nspace ) + icomp*nspace + 1;
+     unsigned kder = getAction()->getFullNumberOfTasks() + myelem * ( nspace - 1 );
+     for(unsigned j=0;j<myvals.getNumberActive();++j){
+        unsigned jder=myvals.getActiveIndex(j);
+        buffer[ibuf] = myvals.getDerivative( icomp, jder ); 
+        active_der[kder] =  jder;
+        // act->getElementDerivative(nder*icomp + active_der[ kder ]);
         //addToBufferElement( ibuf, act->getElementDerivative(nder*icomp + active_der[ kder ]) );
-        kder++; ibuf++;
+        ibuf++; kder++;
      }
   }
 }
 
-void StoreDataVessel::storeDerivativesLowMem( const unsigned& jstore ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() );
-  // Store the indexes that have derivatives
-  ActionWithVessel* act=getAction();
-  unsigned nder = act->getNumberOfDerivatives();
-  getIndexList( max_lowmem_stash, jstore, nder, active_der );
-
-  // Stash the derivatives
-  for(unsigned icomp=data_start;icomp<data_start + vecsize;++icomp){
-     unsigned ibuf = jstore * vecsize * nder + (icomp-data_start)*nder;
-     unsigned kder = max_lowmem_stash + jstore*nder;
-     for(unsigned jder=0;jder<active_der[jstore];++jder){
-        local_derivatives[ibuf] = act->getElementDerivative( nder*icomp + active_der[ kder ] );
-        ibuf++; kder++;
-     }
+void StoreDataVessel::retrieveValue( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const {
+  plumed_dbg_assert( values.size()==vecsize );
+  if( normed && values.size()>2 ){
+     unsigned ibuf = myelem * vecsize * nspace;
+     values[0]=local_buffer[ibuf]; ibuf+=nspace;
+     values[1]=local_buffer[ibuf]; ibuf+=nspace;   // Element 1 contains the norm of the vector
+     for(unsigned i=2;i<vecsize;++i){ values[i]=local_buffer[ibuf]/values[1]; ibuf+=nspace; } 
+  } else {
+     unsigned ibuf = myelem * vecsize * nspace;
+     for(unsigned i=0;i<vecsize;++i){ values[i]=local_buffer[ibuf]; ibuf+=nspace; }
   }
 }
 
-bool StoreDataVessel::calculate( std::vector<double>& buffer ){
-  unsigned myelem = getAction()->getCurrentPositionInTaskList();
+void StoreDataVessel::retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals ){
+  plumed_dbg_assert( myvals.getNumberOfValues()==vecsize && myvals.getNumberOfDerivatives()==getAction()->getNumberOfDerivatives() );
+
+  myvals.clearAll();
+  if( getAction()->lowmem ){
+      getAction()->performTask( getAction()->getPositionInFullTaskList(myelem), getAction()->getTaskCode(myelem), myvals );
+      if( normed ){
+          plumed_dbg_assert( myvals.getNumberOfValues()>2 );
+          double v = myvals.get(1), weight = 1.0 / v,  wdf = 1.0 / ( v*v*v );
+          for(unsigned j=0;j<myvals.getNumberActive();++j){
+              double comp2=0.0; unsigned jder=myvals.getActiveIndex(j);
+              for(unsigned jcomp=2;jcomp<vecsize;++jcomp) comp2 += myvals.get(jcomp)*myvals.getDerivative( jcomp, jder );
+              for(unsigned jcomp=2;jcomp<vecsize;++jcomp) myvals.setDerivative( jcomp, jder, weight*myvals.getDerivative( jcomp, jder ) - wdf*comp2*myvals.get(jcomp) );
+          }
+      }
+  } else {
+      // Retrieve the derivatives for elements 0 and 1 - weight and norm
+      for(unsigned icomp=0;icomp<2;++icomp){
+          unsigned ibuf = myelem * ( vecsize*nspace ) + icomp*nspace + 1;
+          unsigned kder = getAction()->getFullNumberOfTasks() + myelem * ( nspace - 1 );
+          for(unsigned j=0;j<active_der[myelem];++j){
+              myvals.addDerivative( icomp, active_der[kder], local_buffer[ibuf] );
+              kder++; ibuf++;
+          }
+      }
+
+      // Retrieve the derivatives for the vector
+      if( vecsize>2 && normed ){
+         plumed_dbg_assert( myvals.getNumberOfValues()>2 );
+         unsigned kder = getAction()->getFullNumberOfTasks() + myelem * ( nspace - 1 );
+         double v = local_buffer[myelem*vecsize*nspace + nspace], weight = 1.0 / v, wdf = 1.0 / ( v*v*v );
+         for(unsigned ider=0;ider<active_der[myelem];++ider){
+             unsigned ibuf = myelem * vecsize * nspace + 2 * nspace + 1 + ider; double comp2=0.0; 
+             for(unsigned jcomp=2;jcomp<vecsize;++jcomp){ comp2 += local_buffer[ibuf-ider-1]*local_buffer[ibuf]; ibuf+=nspace; }  
+             ibuf = myelem * vecsize * nspace + 2 * nspace + 1 + ider;
+             for(unsigned jcomp=2;jcomp<vecsize;++jcomp){
+                 myvals.addDerivative( jcomp, active_der[kder], weight*local_buffer[ibuf] - wdf*comp2*local_buffer[ibuf-ider-1] );
+                 ibuf+=nspace;
+             }
+             kder++;
+         }
+      } else if( vecsize>2 ){
+         for(unsigned icomp=2;icomp<vecsize;++icomp){
+             unsigned ibuf = myelem * ( vecsize*nspace ) + icomp*nspace + 1;
+             unsigned kder = getAction()->getFullNumberOfTasks() + myelem * ( nspace - 1 );
+             for(unsigned j=0;j<active_der[myelem];++j){
+                 myvals.addDerivative( icomp, active_der[kder], local_buffer[ibuf] );
+                 kder++; ibuf++;
+             } 
+         } 
+      }
+      // Now ensure appropriate parts of list are activated
+      myvals.emptyActiveMembers();
+      unsigned kder = getAction()->getFullNumberOfTasks() + myelem * ( nspace - 1 );
+      for(unsigned j=0;j<active_der[myelem];++j){ myvals.updateIndex( active_der[kder] ); kder++; }
+      myvals.sortActiveList();
+  } 
+}
+
+
+// 
+// void StoreDataVessel::storeDerivativesLowMem( const unsigned& jstore ){
+//   plumed_dbg_assert( getAction()->derivativesAreRequired() );
+//   // Store the indexes that have derivatives
+//   ActionWithVessel* act=getAction();
+//   unsigned nder = act->getNumberOfDerivatives();
+//   getIndexList( max_lowmem_stash, jstore, nder, active_der );
+// 
+//   // Stash the derivatives
+//   for(unsigned icomp=data_start;icomp<data_start + vecsize;++icomp){
+//      unsigned ibuf = jstore * vecsize * nder + (icomp-data_start)*nder;
+//      unsigned kder = max_lowmem_stash + jstore*nder;
+//      for(unsigned jder=0;jder<active_der[jstore];++jder){
+//         // local_derivatives[ibuf] = act->getElementDerivative( nder*icomp + active_der[ kder ] );
+//         ibuf++; kder++;
+//      }
+//   }
+// }
+
+bool StoreDataVessel::calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer ){
+
+   if( !hard_cut ){
+      storeValues( current, myvals, buffer );
+      if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivatives( current, myvals, buffer );
+   } else if( myvals.get(0)>wtol ){
+      storeValues( current, myvals, buffer );
+      if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivatives( current, myvals, buffer );
+   } 
+
+//  unsigned myelem = getAction()->getCurrentPositionInTaskList();
   // Normalize vector if it is required
-  finishTask( myelem );
+//  unsigned myelem; finishTask( myelem );
 
   // Store the values 
-  if( !hard_cut ){
-     storeValues( myelem, buffer );
-     // Store the derivatives if we are not using low memory
-     if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivativesHighMem( myelem, buffer );  
-  } else if( getAction()->getElementValue(getAction()->getIndexOfWeight())>wtol ){ 
-     storeValues( myelem, buffer );
-     // Store the derivatives if we are not using low memory
-     if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivativesHighMem( myelem, buffer );
-  }
-
+//  if( !hard_cut ){
+//     storeValues( myelem, buffer );
+//     // Store the derivatives if we are not using low memory
+//     if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivativesHighMem( myelem, buffer );  
+//  } else if( getAction()->getElementValue(0)>wtol ){ 
+//     storeValues( myelem, buffer );
+//     // Store the derivatives if we are not using low memory
+//     if( !(getAction()->lowmem) && getAction()->derivativesAreRequired() ) storeDerivativesHighMem( myelem, buffer );
+//  }
+//
   return true;
 }
 
@@ -172,71 +258,71 @@ void StoreDataVessel::finish( const std::vector<double>& buffer ){
   if(!getAction()->lowmem && getAction()->derivativesAreRequired() ) comm.Sum( &active_der[0], active_der.size() );
 }
 
-double StoreDataVessel::chainRule( const unsigned& ival, const unsigned& ider, const std::vector<double>& df ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() && df.size()==vecsize );
-  // Clear final derivatives array
-  final_derivatives.assign( final_derivatives.size(), 0.0 );
-
-  double dfout = 0.0;
-  if(getAction()->lowmem){
-     plumed_dbg_assert( ival<max_lowmem_stash );
-     unsigned maxder = getAction()->getNumberOfDerivatives();
-     unsigned ibuf=ival*(vecsize*maxder) + ider;
-     for(unsigned icomp=0;icomp<vecsize;++icomp){
-         dfout+=df[icomp]*local_derivatives[ibuf];
-         ibuf+=maxder;
-     }  
-  } else {
-     plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
-     unsigned ibuf=ival*(vecsize*nspace) + 1 + ider;
-     for(unsigned icomp=0;icomp<vecsize;++icomp){
-         dfout+=df[icomp]*local_buffer[ibuf]; //getBufferElement(ibuf);
-         ibuf+=nspace;
-     }
-  }
-  return dfout;
-}
-
-void StoreDataVessel::chainRule( const unsigned& ival, const std::vector<double>& df ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() && df.size()==vecsize );
-  // Clear final derivatives array
-  final_derivatives.assign( final_derivatives.size(), 0.0 );
-
-  if(getAction()->lowmem){
-     plumed_dbg_assert( ival<max_lowmem_stash );
-     unsigned maxder = getAction()->getNumberOfDerivatives();
-     for(unsigned ider=0;ider<active_der[ival];++ider){
-        final_derivatives[ider]=0.0;
-        unsigned ibuf=ival*(vecsize*maxder) + ider; 
-        for(unsigned jcomp=0;jcomp<vecsize;++jcomp){
-            final_derivatives[ider]+=df[jcomp]*local_derivatives[ibuf]; 
-            ibuf+=maxder;
-        }
-     }
-  } else {
-     plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
-     for(unsigned ider=0;ider<active_der[ival];++ider){
-         final_derivatives[ider]=0.0;
-         unsigned ibuf=ival*(vecsize*nspace) + 1 + ider; 
-         for(unsigned jcomp=0;jcomp<vecsize;++jcomp){
-             final_derivatives[ider]+=df[jcomp]*local_buffer[ibuf];
-             //final_derivatives[ider]+=df[jcomp]*getBufferElement(ibuf);
-             ibuf+=nspace;
-         }
-     }
-  }
-}
-
-void StoreDataVessel::chainRule( const unsigned& ival, const std::vector<double>& df, Value* val ){
-  plumed_dbg_assert( getAction()->derivativesAreRequired() && val->getNumberOfDerivatives()==final_derivatives.size() );
-  chainRule( ival, df );
-
-  unsigned kder;
-  if( getAction()->lowmem ) kder = max_lowmem_stash + ival*getAction()->getNumberOfDerivatives();
-  else kder = getAction()->getFullNumberOfTasks() + ival*(nspace-1);
-
-  for(unsigned i=0;i<active_der[ival];++i) val->addDerivative( active_der[kder+i] , final_derivatives[i] );
-}
+// double StoreDataVessel::chainRule( const unsigned& ival, const unsigned& ider, const std::vector<double>& df ){
+//   plumed_dbg_assert( getAction()->derivativesAreRequired() && df.size()==vecsize );
+//   // Clear final derivatives array
+//   final_derivatives.assign( final_derivatives.size(), 0.0 );
+// 
+//   double dfout = 0.0;
+//   if(getAction()->lowmem){
+//      plumed_dbg_assert( ival<max_lowmem_stash );
+//      unsigned maxder = getAction()->getNumberOfDerivatives();
+//      unsigned ibuf=ival*(vecsize*maxder) + ider;
+//      for(unsigned icomp=0;icomp<vecsize;++icomp){
+//          dfout+=df[icomp]*local_derivatives[ibuf];
+//          ibuf+=maxder;
+//      }  
+//   } else {
+//      plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
+//      unsigned ibuf=ival*(vecsize*nspace) + 1 + ider;
+//      for(unsigned icomp=0;icomp<vecsize;++icomp){
+//          dfout+=df[icomp]*local_buffer[ibuf]; //getBufferElement(ibuf);
+//          ibuf+=nspace;
+//      }
+//   }
+//   return dfout;
+// }
+
+// void StoreDataVessel::chainRule( const unsigned& ival, const std::vector<double>& df ){
+//   plumed_dbg_assert( getAction()->derivativesAreRequired() && df.size()==vecsize );
+//   // Clear final derivatives array
+//   final_derivatives.assign( final_derivatives.size(), 0.0 );
+// 
+//   if(getAction()->lowmem){
+//      plumed_dbg_assert( ival<max_lowmem_stash );
+//      unsigned maxder = getAction()->getNumberOfDerivatives();
+//      for(unsigned ider=0;ider<active_der[ival];++ider){
+//         final_derivatives[ider]=0.0;
+//         unsigned ibuf=ival*(vecsize*maxder) + ider; 
+//         for(unsigned jcomp=0;jcomp<vecsize;++jcomp){
+//             final_derivatives[ider]+=df[jcomp]*local_derivatives[ibuf]; 
+//             ibuf+=maxder;
+//         }
+//      }
+//   } else {
+//      plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
+//      for(unsigned ider=0;ider<active_der[ival];++ider){
+//          final_derivatives[ider]=0.0;
+//          unsigned ibuf=ival*(vecsize*nspace) + 1 + ider; 
+//          for(unsigned jcomp=0;jcomp<vecsize;++jcomp){
+//              final_derivatives[ider]+=df[jcomp]*local_buffer[ibuf];
+//              //final_derivatives[ider]+=df[jcomp]*getBufferElement(ibuf);
+//              ibuf+=nspace;
+//          }
+//      }
+//   }
+// }
+
+// void StoreDataVessel::chainRule( const unsigned& ival, const std::vector<double>& df, Value* val ){
+//   plumed_dbg_assert( getAction()->derivativesAreRequired() && val->getNumberOfDerivatives()==final_derivatives.size() );
+//   chainRule( ival, df );
+// 
+//   unsigned kder;
+//   if( getAction()->lowmem ) kder = max_lowmem_stash + ival*getAction()->getNumberOfDerivatives();
+//   else kder = getAction()->getFullNumberOfTasks() + ival*(nspace-1);
+// 
+//   for(unsigned i=0;i<active_der[ival];++i) val->addDerivative( active_der[kder+i] , final_derivatives[i] );
+// }
 
 }
 }
diff --git a/src/vesselbase/StoreDataVessel.h b/src/vesselbase/StoreDataVessel.h
index 36375648ffe67839b26c92858b2fcbcc15b2fad0..02a0f7f93147938b5fda421c216003b3d8438564 100644
--- a/src/vesselbase/StoreDataVessel.h
+++ b/src/vesselbase/StoreDataVessel.h
@@ -39,14 +39,13 @@ second step.
 */
 
 class StoreDataVessel : public Vessel {
+friend class Moments;
 private:
 /// Do the quantities being stored in here need derivatives
   bool hasderiv;
 /// What is the maximum number of vectors we are going to 
 /// have to store when using lowmem option 
   unsigned max_lowmem_stash;
-/// The start point for the data we are storing in this particular object
-  unsigned data_start;
 /// The size of the vector we are computing 
   unsigned vecsize;
 /// The amount of data per vector element
@@ -56,13 +55,13 @@ private:
 /// The active derivative elements
   std::vector<unsigned> active_der;
 /// This is a tempory vector that is used to store data
-  std::vector<double> fvec;
+//  std::vector<double> fvec;
 /// The buffer
-  std::vector<double> local_buffer;
-/// The local derivatives
-  std::vector<double> local_derivatives;
-/// The final derivatives
-  std::vector<double> final_derivatives;
+   std::vector<double> local_buffer;
+// /// The local derivatives
+//   std::vector<double> local_derivatives;
+// /// The final derivatives
+//   std::vector<double> final_derivatives;
 protected:
 /// Apply a hard cutoff on the weight
   bool hard_cut;
@@ -78,15 +77,15 @@ protected:
 /// Return value of nspace
   unsigned getNumberOfDerivativeSpacesPerComponent() const ;
 /// Retrieve the values from the underlying ActionWithVessel
-  void storeValues( const unsigned& , std::vector<double>& );
+   void storeValues( const unsigned& , MultiValue& , std::vector<double>& );
 /// Set the Task that needs redoing
-  void setTaskToRecompute( const unsigned& ivec );
+//   void setTaskToRecompute( const unsigned& ivec );
 /// Set a component of one of the vectors
-  void setComponent( const unsigned& , const unsigned& , const double& );
+//   void setComponent( const unsigned& , const unsigned& , const double& );
 /// This is the proper chain rule for vectors
-  double chainRule( const unsigned&, const unsigned&, const std::vector<double>& );
-/// Chain rule the vector and output derivatives to a value
-  void chainRule( const unsigned& , const std::vector<double>&, Value* );
+//    double chainRule( const unsigned&, const unsigned&, const std::vector<double>& );
+//  /// Chain rule the vector and output derivatives to a value
+//    void chainRule( const unsigned& , const std::vector<double>&, Value* );
 /// Get the ibuf'th local derivative value
   double getLocalDerivative( const unsigned& ibuf );
 /// Set the ibuf'th local derivative value
@@ -100,33 +99,39 @@ public:
   bool weightCutoffIsOn() const ;
 /// Return the number of components in the vector
   unsigned getNumberOfComponents() const { return vecsize; }
+/// Get the values of all the components in the vector
+  void retrieveValue( const unsigned& myelem, const bool& normed, std::vector<double>& values ) const ;
+/// Get the derivatives for one of the components in the vector
+  void retrieveDerivatives( const unsigned& myelem, const bool& normed, MultiValue& myvals );
 /// Do all resizing of data
   virtual void resize();
 /// Clear certain data before start of main loop
   virtual void prepare();
+///
+  virtual std::string description(){ return ""; }
 /// Get the number of derivatives for the ith value
   unsigned getNumberOfDerivatives( const unsigned& );
 /// Get one of the stored indexes
-  unsigned getStoredIndex( const unsigned& , const unsigned& );
+//  unsigned getStoredIndex( const unsigned& , const unsigned& );
 /// Get a component of the stored vector
-  double getComponent( const unsigned& , const unsigned& );
+//  double getComponent( const unsigned& , const unsigned& );
 /// Recalculate a vector - used in lowmem mode
-  virtual void recompute( const unsigned& , const unsigned& );
+//  virtual void recompute( const unsigned& , const unsigned& );
 /// This reperforms the task in the underlying action
-  virtual void performTask( const unsigned& );
+//  virtual void performTask( const unsigned& );
 /// This reperforms the task
-  virtual void finishTask( const unsigned& ){};
+//  virtual void finishTask( const unsigned& ){};
 /// Chain rule and store output in local array called final_derivatives
 /// with vectors this does chain rule for dot products
-  void chainRule( const unsigned& , const std::vector<double>& );
+//   void chainRule( const unsigned& , const std::vector<double>& );
 /// Get the ider'th final derivative value
-  double getFinalDerivative( const unsigned& ider ) const ;
+//  double getFinalDerivative( const unsigned& ider ) const ;
 /// This stores the data when not using lowmem
-  bool calculate( std::vector<double>& buffer );
+  bool calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer );
 /// This stores the data we get from the calculation
-  void storeDerivativesLowMem( const unsigned& );
+//   void storeDerivativesLowMem( const unsigned& );
 /// This stores the data we get from the calculation
-  void storeDerivativesHighMem( const unsigned& , std::vector<double>& );
+  void storeDerivatives( const unsigned& , MultiValue& myvals, std::vector<double>& );
 /// Final step in gathering data
   virtual void finish( const std::vector<double>& buffer );
 /// Is a particular stored value active at the present time
@@ -134,7 +139,7 @@ public:
 /// Activate indexes (this is used at end of chain rule)
   virtual void activateIndices( ActionWithVessel* ){}
 /// Get the list of indices that we are storing data for
-  virtual void getIndexList( const unsigned& , const unsigned& , const unsigned& , std::vector<unsigned>& );
+//  virtual void getIndexList( const unsigned& , const unsigned& , const unsigned& , std::vector<unsigned>& );
 /// Forces on vectors should always be applied elsewhere
   virtual bool applyForce(std::vector<double>&){ return false; }
 };
@@ -149,63 +154,63 @@ bool StoreDataVessel::usingLowMem(){
   return getAction()->lowmem;
 }
 
-inline
-void StoreDataVessel::performTask( const unsigned& ivec ){
-  if( usingLowMem() ) getAction()->performTask();
-}
-
-inline
-double StoreDataVessel::getComponent( const unsigned& ival, const unsigned& jcomp ){
-  plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jcomp<vecsize );
-  return 0.0;    // GAT Broken
-//  return getBufferElement( ival*(vecsize*nspace) + jcomp*nspace ); 
-}
-
-inline
-void StoreDataVessel::setComponent( const unsigned& ival, const unsigned& jcomp, const double& val ){
-  plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jcomp<vecsize );
-//  setBufferElement( ival*(vecsize*nspace) + jcomp*nspace, val );
-}
+// inline
+// void StoreDataVessel::performTask( const unsigned& ivec ){
+// //  if( usingLowMem() ) getAction()->performTask();
+// }
+
+// inline
+// double StoreDataVessel::getComponent( const unsigned& ival, const unsigned& jcomp ){
+//   plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jcomp<vecsize );
+//   return 0.0;    // GAT Broken
+// //  return getBufferElement( ival*(vecsize*nspace) + jcomp*nspace ); 
+// }
+// 
+// inline
+// void StoreDataVessel::setComponent( const unsigned& ival, const unsigned& jcomp, const double& val ){
+//   plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jcomp<vecsize );
+// //  setBufferElement( ival*(vecsize*nspace) + jcomp*nspace, val );
+// }
 
 inline
 unsigned StoreDataVessel::getNumberOfDerivativeSpacesPerComponent() const {
   return nspace;
 }
 
-inline
-unsigned StoreDataVessel::getNumberOfDerivatives( const unsigned& ival ){
-  plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
-  return active_der[ival];
-}
-
-inline
-unsigned StoreDataVessel::getStoredIndex( const unsigned& ival, const unsigned& jindex ){
-  plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jindex<active_der[ival] );
-
-  unsigned kder;
-  if( getAction()->lowmem ) kder = max_lowmem_stash + ival*getAction()->getNumberOfDerivatives();
-  else kder = getAction()->getFullNumberOfTasks() + ival*(nspace-1); 
-
-  return active_der[kder + jindex];
-}
-
-inline
-double StoreDataVessel::getLocalDerivative( const unsigned& ibuf ){
-  plumed_dbg_assert( getAction()->lowmem && ibuf<local_derivatives.size() );
-  return local_derivatives[ibuf];
-}
-
-inline
-double StoreDataVessel::getFinalDerivative( const unsigned& ider ) const {
-  plumed_dbg_assert( ider<final_derivatives.size() );
-  return final_derivatives[ider];
-}
-
-inline
-void StoreDataVessel::setLocalDerivative( const unsigned& ibuf, const double& val ){
-  plumed_dbg_assert( getAction()->lowmem && ibuf<local_derivatives.size() );
-  local_derivatives[ibuf]=val;
-}
+// inline
+// unsigned StoreDataVessel::getNumberOfDerivatives( const unsigned& ival ){
+//   plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() );
+//   return active_der[ival];
+// }
+
+// inline
+// unsigned StoreDataVessel::getStoredIndex( const unsigned& ival, const unsigned& jindex ){
+//   plumed_dbg_assert( ival<getAction()->getFullNumberOfTasks() && jindex<active_der[ival] );
+// 
+//   unsigned kder;
+//   if( getAction()->lowmem ) kder = max_lowmem_stash + ival*getAction()->getNumberOfDerivatives();
+//   else kder = getAction()->getFullNumberOfTasks() + ival*(nspace-1); 
+// 
+//   return active_der[kder + jindex];
+// }
+
+// inline
+// double StoreDataVessel::getLocalDerivative( const unsigned& ibuf ){
+//   plumed_dbg_assert( getAction()->lowmem && ibuf<local_derivatives.size() );
+//   return local_derivatives[ibuf];
+// }
+// 
+// inline
+// double StoreDataVessel::getFinalDerivative( const unsigned& ider ) const {
+//   plumed_dbg_assert( ider<final_derivatives.size() );
+//   return final_derivatives[ider];
+// }
+// 
+// inline
+// void StoreDataVessel::setLocalDerivative( const unsigned& ibuf, const double& val ){
+//   plumed_dbg_assert( getAction()->lowmem && ibuf<local_derivatives.size() );
+//   local_derivatives[ibuf]=val;
+// }
 
 inline
 bool StoreDataVessel::storedValueIsActive( const unsigned& iatom ){
diff --git a/src/vesselbase/StoreValueAndWeightVessel.h b/src/vesselbase/StoreValueAndWeightVessel.h
deleted file mode 100644
index 3dbf5563884761c4a94f80d9d147252856b1dd62..0000000000000000000000000000000000000000
--- a/src/vesselbase/StoreValueAndWeightVessel.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2012-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifndef __PLUMED_vesselbase_StoreValueAndWeightVessel_h
-#define __PLUMED_vesselbase_StoreValueAndWeightVessel_h
-
-#include <string>
-#include <cstring>
-#include <vector>
-#include "StoreDataVessel.h"
-
-namespace PLMD {
-namespace vesselbase {
-
-class StoreValueAndWeightVessel : public StoreDataVessel {
-public:
-  static void registerKeywords( Keywords& keys );
-  StoreValueAndWeightVessel( const VesselOptions& );
-  double getValue( const unsigned& );
-  double getWeight( const unsigned& );
-};
-
-inline
-double StoreValueAndWeightVessel::getValue( const unsigned& ival ){
-  return getComponent( ival, 0 );
-}
-
-inline
-double StoreValueAndWeightVessel::getWeight( const unsigned& ival ){
-  return getComponent( ival, 1 );
-}
-
-
-}
-}
-#endif
diff --git a/src/vesselbase/StoreValueVessel.cpp b/src/vesselbase/StoreValueVessel.cpp
deleted file mode 100644
index 38af097c541c8602a7685fd43b3508ce5bc482d9..0000000000000000000000000000000000000000
--- a/src/vesselbase/StoreValueVessel.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2011-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#include "StoreValueVessel.h"
-
-namespace PLMD {
-namespace vesselbase {
-
-void StoreValueVessel::registerKeywords( Keywords& keys ){
-  StoreDataVessel::registerKeywords( keys );
-}
-
-StoreValueVessel::StoreValueVessel( const VesselOptions& da):
-StoreDataVessel(da)
-{
-  if( weightHasDerivatives() ) error("this quantity cannot be calculated if weights have derivatives");
-  completeSetup( 0, 1 );
-}
-
-}
-}
diff --git a/src/vesselbase/StoreValueVessel.h b/src/vesselbase/StoreValueVessel.h
deleted file mode 100644
index ccd3de4df879165a348b65eebf1c8ae7458426f8..0000000000000000000000000000000000000000
--- a/src/vesselbase/StoreValueVessel.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-   Copyright (c) 2012-2014 The plumed team
-   (see the PEOPLE file at the root of the distribution for a list of names)
-
-   See http://www.plumed-code.org for more information.
-
-   This file is part of plumed, version 2.
-
-   plumed is free software: you can redistribute it and/or modify
-   it under the terms of the GNU Lesser General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   plumed is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public License
-   along with plumed.  If not, see <http://www.gnu.org/licenses/>.
-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-#ifndef __PLUMED_vesselbase_StoreValueVessel_h
-#define __PLUMED_vesselbase_StoreValueVessel_h
-
-#include <string>
-#include <cstring>
-#include <vector>
-#include "StoreDataVessel.h"
-
-namespace PLMD {
-namespace vesselbase {
-
-class StoreValueVessel : public StoreDataVessel {
-public:
-  static void registerKeywords( Keywords& keys );
-  StoreValueVessel( const VesselOptions& );
-  double getValue( const unsigned& );
-  virtual std::string description(){ return ""; }
-};
-
-inline
-double StoreValueVessel::getValue( const unsigned& ival ){
-  return getComponent( ival, 0 );
-}
-
-}
-}
-#endif
diff --git a/src/vesselbase/Sum.cpp b/src/vesselbase/Sum.cpp
index 7fc58422c840dae9c757a55d7c442cd8b1daa4e2..08ce670bece4c78d4c9c4a034d6c8711156062c9 100644
--- a/src/vesselbase/Sum.cpp
+++ b/src/vesselbase/Sum.cpp
@@ -31,7 +31,7 @@ public:
   static void reserveKeyword( Keywords& keys );
   Sum( const VesselOptions& da );
   std::string function_description();
-  bool calculate( std::vector<double>& buffer );
+  double calcTransform( const double& val, double& dv );
 };
 
 PLUMED_REGISTER_VESSEL(Sum,"SUM")
@@ -54,9 +54,8 @@ std::string Sum::function_description(){
   return "the sum of all the values"; 
 }
 
-bool Sum::calculate( std::vector<double>& buffer ){
-   double val=getAction()->getElementValue(0);
-   return addToBuffers( val, 1.0, buffer );
+double Sum::calcTransform( const double& val, double& dv ){
+  dv=1.0; return val;
 }
 
 }
diff --git a/src/vesselbase/Vessel.h b/src/vesselbase/Vessel.h
index 2ed69e4f18df43e472aaead141eb1aac1289a3f8..8ff117e6ac33981467b31d4737a403e22ad16928 100644
--- a/src/vesselbase/Vessel.h
+++ b/src/vesselbase/Vessel.h
@@ -143,8 +143,10 @@ public:
  virtual void setBufferStart( unsigned& start );
 /// Do something before the loop
   virtual void prepare(){}
+/// This is replaced in bridges so we can transform the derivatives
+  virtual MultiValue& transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals );
 /// Calculate the part of the vessel that is done in the loop
-  virtual bool calculate( std::vector<double>& buffer )=0;
+  virtual bool calculate( const unsigned& current, MultiValue& myvals, std::vector<double>& buffer )=0;
 /// Complete the calculation once the loop is finished
   virtual void finish( const std::vector<double>& )=0;
 /// Reset the size of the buffers
@@ -210,6 +212,11 @@ void Vessel::setBufferStart( unsigned& start ){
   bufstart=start; start+=bufsize;
 }
 
+inline
+MultiValue& Vessel::transformDerivatives( const unsigned& current, MultiValue& myvals, MultiValue& bvals ){
+  return myvals;
+}
+
 inline
 void Vessel::resizeBuffer( const unsigned& n ){
   bufsize=n;