From a1fb75b94a10a132932656e79d60634a44913368 Mon Sep 17 00:00:00 2001
From: Gareth Tribello <gareth.tribello@gmail.com>
Date: Sat, 24 Aug 2013 18:57:24 +0100
Subject: [PATCH] Removed colvar_atoms arrays

This modification ensures that multicolvar uses less memory and makes
it a tiny bit faster
---
 src/manyrestraints/Sphere.cpp                 |   4 +-
 src/multicolvar/ActionVolume.cpp              |   5 +-
 src/multicolvar/ActionVolume.h                |   2 +-
 src/multicolvar/AlphaBeta.cpp                 |   8 +-
 src/multicolvar/Angles.cpp                    |  20 +--
 src/multicolvar/Bridge.cpp                    |  19 +-
 src/multicolvar/CoordinationNumbers.cpp       |  16 +-
 src/multicolvar/Density.cpp                   |   6 +-
 src/multicolvar/Distances.cpp                 |   4 +-
 src/multicolvar/MultiColvar.cpp               | 163 ++++++++++--------
 src/multicolvar/MultiColvar.h                 |   5 +-
 src/multicolvar/MultiColvarBase.cpp           |  82 ++++++---
 src/multicolvar/MultiColvarBase.h             |  33 ++--
 src/multicolvar/MultiColvarFunction.cpp       |  17 +-
 src/multicolvar/MultiColvarFunction.h         |  30 +---
 src/multicolvar/StoreCentralAtomsVessel.cpp   |   2 +
 .../SecondaryStructureRMSD.cpp                |   2 +-
 .../SecondaryStructureRMSD.h                  |   2 +-
 src/vesselbase/ActionWithVessel.cpp           |   4 +-
 src/vesselbase/ActionWithVessel.h             |   4 +-
 src/vesselbase/BridgeVessel.cpp               |   2 +-
 src/vesselbase/StoreDataVessel.cpp            |   9 +-
 src/vesselbase/StoreDataVessel.h              |   2 +-
 23 files changed, 255 insertions(+), 186 deletions(-)

diff --git a/src/manyrestraints/Sphere.cpp b/src/manyrestraints/Sphere.cpp
index 1d7333455..a094467a9 100644
--- a/src/manyrestraints/Sphere.cpp
+++ b/src/manyrestraints/Sphere.cpp
@@ -39,7 +39,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Sphere( const ActionOptions& );
   bool isPeriodic(){ return false; }
-  void performTask( const unsigned& j );
+  void performTask();
   void calculate();
 };
 
@@ -90,7 +90,7 @@ void Sphere::calculate(){
   runAllTasks();
 }
 
-void Sphere::performTask( const unsigned& j ){
+void Sphere::performTask(){
   Vector distance;
 
   if(!nopbc){
diff --git a/src/multicolvar/ActionVolume.cpp b/src/multicolvar/ActionVolume.cpp
index 4f08834e2..4c0e68f80 100644
--- a/src/multicolvar/ActionVolume.cpp
+++ b/src/multicolvar/ActionVolume.cpp
@@ -113,7 +113,8 @@ void ActionVolume::prepare(){
   if( updateFreq>0 && (getStep()-lastUpdate)>=updateFreq ){
       if( !mycolv->isDensity() ){
           mycolv->taskList.activateAll();
-          for(unsigned i=0;i<mycolv->taskList.getNumberActive();++i) mycolv->colvar_atoms[i].activateAll();
+          // GAT broken neighbor list
+          // for(unsigned i=0;i<mycolv->taskList.getNumberActive();++i) mycolv->colvar_atoms[i].activateAll();
           mycolv->unlockContributors(); mycolv->resizeDynamicArrays();
           plumed_dbg_assert( mycolv->getNumberOfVessels()==0 );
       } else {
@@ -131,7 +132,7 @@ void ActionVolume::resizeLocalArrays(){
   activeAtoms.deactivateAll();
 }
 
-void ActionVolume::performTask( const unsigned& j ){
+void ActionVolume::performTask(){
   activeAtoms.deactivateAll(); // Currently no atoms are active so deactivate them all
   Vector catom_pos=mycolv->retrieveCentralAtomPos();
 
diff --git a/src/multicolvar/ActionVolume.h b/src/multicolvar/ActionVolume.h
index d1a8ee86c..5947d0ffb 100644
--- a/src/multicolvar/ActionVolume.h
+++ b/src/multicolvar/ActionVolume.h
@@ -100,7 +100,7 @@ public:
 /// Do jobs required before tasks are undertaken
   void doJobsRequiredBeforeTaskList();
 /// This calculates all the vessels and is called from within a bridge vessel
-  void performTask(const unsigned& i );
+  void performTask();
 /// Routines that have to be defined so as not to have problems with virtual methods 
   void deactivate_task();
   void calculate(){}
diff --git a/src/multicolvar/AlphaBeta.cpp b/src/multicolvar/AlphaBeta.cpp
index dc2858895..3f9092adc 100644
--- a/src/multicolvar/AlphaBeta.cpp
+++ b/src/multicolvar/AlphaBeta.cpp
@@ -79,7 +79,7 @@ private:
 public:
   static void registerKeywords( Keywords& keys );
   AlphaBeta(const ActionOptions&);
-  virtual double compute( const unsigned& j );
+  virtual double compute();
   bool isPeriodic(){ return false; }
   Vector getCentralAtom();  
 };
@@ -127,7 +127,7 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double AlphaBeta::compute( const unsigned& j ){
+double AlphaBeta::compute(){
   Vector d0,d1,d2;
   d0=getSeparation(getPosition(1),getPosition(0));
   d1=getSeparation(getPosition(2),getPosition(1));
@@ -136,8 +136,8 @@ double AlphaBeta::compute( const unsigned& j ){
   Vector dd0,dd1,dd2;
   PLMD::Torsion t;
   double value  = t.compute(d0,d1,d2,dd0,dd1,dd2);
-  double svalue = -0.5*sin(value-target[current]);
-  double cvalue = 1.+cos(value-target[current]);
+  double svalue = -0.5*sin(value-target[lindex]);
+  double cvalue = 1.+cos(value-target[lindex]);
 
   dd0 *= svalue;
   dd1 *= svalue;
diff --git a/src/multicolvar/Angles.cpp b/src/multicolvar/Angles.cpp
index 06e8daa06..f14963b82 100644
--- a/src/multicolvar/Angles.cpp
+++ b/src/multicolvar/Angles.cpp
@@ -93,7 +93,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Angles(const ActionOptions&);
 // active methods:
-  virtual double compute( const unsigned& j );
+  virtual double compute();
 /// Returns the number of coordinates of the field
   void calculateWeight();
   bool isPeriodic(){ return false; }
@@ -159,8 +159,8 @@ use_sf(false)
 }
 
 void Angles::calculateWeight(){
-  dij=getSeparation( getPosition(1), getPosition(2) );
-  dik=getSeparation( getPosition(1), getPosition(0) );
+  dij=getSeparation( getPosition(0), getPosition(2) );
+  dik=getSeparation( getPosition(0), getPosition(1) );
   if(!use_sf){ setWeight(1.0); return; }
 
   double w1, w2, dw1, dw2, wtot;
@@ -170,19 +170,19 @@ void Angles::calculateWeight(){
 
   setWeight( wtot );
   if( wtot<getTolerance() ) return; 
-  addAtomsDerivativeOfWeight( 0, dw2*dik );
-  addAtomsDerivativeOfWeight( 1, -dw1*dij - dw2*dik ); 
+  addAtomsDerivativeOfWeight( 1, dw2*dik );
+  addAtomsDerivativeOfWeight( 0, -dw1*dij - dw2*dik ); 
   addAtomsDerivativeOfWeight( 2, dw1*dij );
   addBoxDerivativesOfWeight( (-dw1)*Tensor(dij,dij) + (-dw2)*Tensor(dik,dik) );
 }
 
-double Angles::compute( const unsigned& j ){
+double Angles::compute(){
   Vector ddij,ddik; PLMD::Angle a; 
   double angle=a.compute(dij,dik,ddij,ddik);
 
   // And finish the calculation
-  addAtomsDerivatives( 0, ddik );
-  addAtomsDerivatives( 1, - ddik - ddij );
+  addAtomsDerivatives( 1, ddik );
+  addAtomsDerivatives( 0, - ddik - ddij );
   addAtomsDerivatives( 2, ddij );
   addBoxDerivatives( -(Tensor(dij,ddij)+Tensor(dik,ddik)) );
 
@@ -190,8 +190,8 @@ double Angles::compute( const unsigned& j ){
 }
 
 Vector Angles::getCentralAtom(){
-   addCentralAtomDerivatives( 1, Tensor::identity() );
-   return getPosition(1);
+   addCentralAtomDerivatives( 0, Tensor::identity() );
+   return getPosition(0);
 }
 
 }
diff --git a/src/multicolvar/Bridge.cpp b/src/multicolvar/Bridge.cpp
index 2732a1455..27304d835 100644
--- a/src/multicolvar/Bridge.cpp
+++ b/src/multicolvar/Bridge.cpp
@@ -67,11 +67,10 @@ public:
   static void registerKeywords( Keywords& keys );
   Bridge(const ActionOptions&);
 // active methods:
-  virtual double compute( const unsigned& j );
+  virtual double compute();
 /// Returns the number of coordinates of the field
   void calculateWeight();
   bool isPeriodic(){ return false; }
-  unsigned getNumberOfAtomsInCentralAtomDerivatives(){ return 1; }
   Vector getCentralAtom();
 };
 
@@ -128,30 +127,30 @@ PLUMED_MULTICOLVAR_INIT(ao)
 }
 
 void Bridge::calculateWeight(){
-  Vector dij=getSeparation( getPosition(1), getPosition(0) );
+  Vector dij=getSeparation( getPosition(0), getPosition(1) );
   double dw, w=sf1.calculate( dij.modulo(), dw );
   setWeight( w );
 
   if( w<getTolerance() ) return; 
-  addAtomsDerivativeOfWeight( 1, -dw*dij );
-  addAtomsDerivativeOfWeight( 0, dw*dij );
+  addAtomsDerivativeOfWeight( 0, -dw*dij );
+  addAtomsDerivativeOfWeight( 1, dw*dij );
   addBoxDerivativesOfWeight( (-dw)*Tensor(dij,dij) );
 }
 
-double Bridge::compute( const unsigned& j ){
-  Vector dik=getSeparation( getPosition(1), getPosition(2) );
+double Bridge::compute(){
+  Vector dik=getSeparation( getPosition(0), getPosition(2) );
   double dw, w=sf2.calculate( dik.modulo(), dw );
 
   // And finish the calculation
-  addAtomsDerivatives( 1, -dw*dik );
+  addAtomsDerivatives( 0, -dw*dik );
   addAtomsDerivatives( 2,  dw*dik );
   addBoxDerivatives( (-dw)*Tensor(dik,dik) );
   return w;
 }
 
 Vector Bridge::getCentralAtom(){
-   addCentralAtomDerivatives( 1, Tensor::identity() );
-   return getPosition(1);
+   addCentralAtomDerivatives( 0, Tensor::identity() );
+   return getPosition(0);
 }
 
 }
diff --git a/src/multicolvar/CoordinationNumbers.cpp b/src/multicolvar/CoordinationNumbers.cpp
index 7038374b6..7869299a8 100644
--- a/src/multicolvar/CoordinationNumbers.cpp
+++ b/src/multicolvar/CoordinationNumbers.cpp
@@ -70,7 +70,7 @@ public:
   static void registerKeywords( Keywords& keys );
   CoordinationNumbers(const ActionOptions&);
 // active methods:
-  virtual double compute( const unsigned& j ); 
+  virtual double compute(); 
   Vector getCentralAtom();
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
@@ -110,19 +110,13 @@ PLUMED_MULTICOLVAR_INIT(ao)
   log.printf("  coordination of central atom and those within %s\n",( switchingFunction.description() ).c_str() );
 
   // Read in the atoms
-  int natoms; readAtoms( natoms );
+  int natoms=2; readAtoms( natoms );
   // And setup the ActionWithVessel
   readVesselKeywords();
-
-  // Create the groups for the neighbor list
-  std::vector<AtomNumber> ga_lista, gb_lista; AtomNumber aa;
-  aa.setIndex(0); ga_lista.push_back(aa);
-  for(unsigned i=1;i<natoms;++i){ aa.setIndex(i); gb_lista.push_back(aa); }
-  // And check everything has been read in correctly
   checkRead();
 }
 
-double CoordinationNumbers::compute( const unsigned& j ){
+double CoordinationNumbers::compute(){
    double value=0, dfunc; Vector distance;
 
    // Calculate the coordination number
@@ -130,8 +124,8 @@ double CoordinationNumbers::compute( const unsigned& j ){
    for(unsigned i=1;i<getNAtoms();++i){
       distance=getSeparation( getPosition(0), getPosition(i) );
       sw = switchingFunction.calculate( distance.modulo(), dfunc );
-      if( sw>=getTolerance() ){    //  nl_cut<0 ){
-         value += sw;             // switchingFunction.calculate( distance.modulo(), dfunc );
+      if( sw>=getTolerance() ){   
+         value += sw;             
          addAtomsDerivatives( 0, (-dfunc)*distance );
          addAtomsDerivatives( i,  (dfunc)*distance );
          addBoxDerivatives( (-dfunc)*Tensor(distance,distance) );
diff --git a/src/multicolvar/Density.cpp b/src/multicolvar/Density.cpp
index 0794f598c..365da74c6 100644
--- a/src/multicolvar/Density.cpp
+++ b/src/multicolvar/Density.cpp
@@ -54,7 +54,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Density(const ActionOptions&);
 // active methods:
-  virtual double compute( const unsigned& j );
+  virtual double compute();
   Vector getCentralAtom();
   /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
@@ -71,13 +71,13 @@ void Density::registerKeywords( Keywords& keys ){
 Density::Density(const ActionOptions&ao):
 PLUMED_MULTICOLVAR_INIT(ao)
 {
-  int nat; readAtoms( nat ); 
+  int nat=1; readAtoms( nat ); 
   readVesselKeywords();
   // And check everything has been read in correctly
   checkRead(); 
 }
 
-double Density::compute( const unsigned& j ){
+double Density::compute(){
   return 1.0;
 }
 
diff --git a/src/multicolvar/Distances.cpp b/src/multicolvar/Distances.cpp
index bbe066e2b..970c06b27 100644
--- a/src/multicolvar/Distances.cpp
+++ b/src/multicolvar/Distances.cpp
@@ -80,7 +80,7 @@ public:
   static void registerKeywords( Keywords& keys );
   Distances(const ActionOptions&);
 // active methods:
-  virtual double compute( const unsigned& j );
+  virtual double compute();
 /// Returns the number of coordinates of the field
   bool isPeriodic(){ return false; }
   Vector getCentralAtom();
@@ -111,7 +111,7 @@ PLUMED_MULTICOLVAR_INIT(ao)
   checkRead();
 }
 
-double Distances::compute( const unsigned& j ){
+double Distances::compute(){
    Vector distance; 
    distance=getSeparation( getPosition(0), getPosition(1) );
    const double value=distance.modulo();
diff --git a/src/multicolvar/MultiColvar.cpp b/src/multicolvar/MultiColvar.cpp
index 0f9ad26ea..204a5cfbb 100644
--- a/src/multicolvar/MultiColvar.cpp
+++ b/src/multicolvar/MultiColvar.cpp
@@ -59,15 +59,6 @@ verbose_output(false)
   parseFlag("VERBOSE",verbose_output);
 }
 
-void MultiColvar::addColvar( const std::vector<unsigned>& newatoms ){
-  if( verbose_output ){
-     log.printf("  Colvar %d is calculated from atoms : ", colvar_atoms.size()+1);
-     for(unsigned i=0;i<newatoms.size();++i) log.printf("%d ",all_atoms(newatoms[i]).serial() );
-     log.printf("\n");
-  }
-  MultiColvarBase::addColvar( newatoms );
-} 
-
 void MultiColvar::readAtoms( int& natoms ){
   if( keywords.exists("ATOMS") ) readAtomsLikeKeyword( "ATOMS", natoms );
   if( keywords.exists("GROUP") ) readGroupsKeyword( natoms );
@@ -79,9 +70,10 @@ void MultiColvar::readAtoms( int& natoms ){
 }
 
 void MultiColvar::readAtomsLikeKeyword( const std::string & key, int& natoms ){ 
+  plumed_assert( !usespecies );
   if( all_atoms.fullSize()>0 ) return; 
 
-  std::vector<AtomNumber> t; std::vector<unsigned> newlist;
+  std::vector<AtomNumber> t; 
   for(int i=1;;++i ){
      parseAtomList(key, i, t );
      if( t.empty() ) break;
@@ -92,21 +84,29 @@ void MultiColvar::readAtomsLikeKeyword( const std::string & key, int& natoms ){
         log.printf("\n"); 
      }
 
-     if( i==1 && natoms<0 ) natoms=t.size();
+     if( i==1 && natoms<0 ){ natoms=t.size(); ablocks.resize(natoms); }
+     else if( i==1 ) ablocks.resize(natoms);
      if( t.size()!=natoms ){
-         std::string ss; Tools::convert(i,ss); 
-         error(key + ss + " keyword has the wrong number of atoms"); 
+        std::string ss; Tools::convert(i,ss); 
+        error(key + ss + " keyword has the wrong number of atoms"); 
      }
      for(unsigned j=0;j<natoms;++j){ 
-        newlist.push_back( natoms*(i-1)+j ); 
-        all_atoms.addIndexToList( t[j] );
+        ablocks[j].push_back( natoms*(i-1)+j ); all_atoms.addIndexToList( t[j] );
+     }
+     t.resize(0); 
+  }
+  if( all_atoms.fullSize()>0 ){
+     current_atoms.resize( natoms ); nblock=ablocks[0].size();
+     for(unsigned i=0;i<nblock;++i){
+         unsigned cvcode=0, tmpc=1;
+         for(unsigned j=0;j<natoms;++j){ cvcode += i*tmpc; tmpc *= nblock; }
+         taskList.addIndexToList( cvcode );  
      }
-     t.resize(0); addColvar( newlist );
-     newlist.clear(); 
   }
 }
 
 void MultiColvar::readGroupsKeyword( int& natoms ){
+  plumed_assert( !usespecies ); 
   if( all_atoms.fullSize()>0 ) return;
 
   if( natoms==2 ){
@@ -123,22 +123,20 @@ void MultiColvar::readGroupsKeyword( int& natoms ){
   std::vector<AtomNumber> t;
   parseAtomList("GROUP",t);
   if( !t.empty() ){
+      ablocks.resize( natoms ); current_atoms.resize( natoms );
       for(unsigned i=0;i<t.size();++i) all_atoms.addIndexToList( t[i] );
-      std::vector<unsigned> newlist;
       if(natoms==2){ 
+         nblock=t.size(); for(unsigned i=0;i<2;++i) ablocks[i].resize(nblock);
+         for(unsigned i=0;i<t.size();++i){ ablocks[0][i]=i; ablocks[1][i]=i; }
          for(unsigned i=1;i<t.size();++i){ 
-             for(unsigned j=0;j<i;++j){ 
-                newlist.push_back(i); newlist.push_back(j); addColvar( newlist ); newlist.clear();
-             }
+             for(unsigned j=0;j<i;++j) taskList.addIndexToList( i*nblock + j );
          }
       } else if(natoms==3){
+         nblock=t.size(); for(unsigned i=0;i<3;++i) ablocks[i].resize(nblock); 
+         for(unsigned i=0;i<t.size();++i){ ablocks[0][i]=i; ablocks[1][i]=i; ablocks[2][i]=i; }
          for(unsigned i=2;i<t.size();++i){
             for(unsigned j=1;j<i;++j){
-               for(unsigned k=0;k<j;++k){
-                   newlist.push_back(i); newlist.push_back(j);
-                   newlist.push_back(k); addColvar( newlist );
-                   newlist.clear();
-               }
+               for(unsigned k=0;k<j;++k) taskList.addIndexToList( i*nblock*nblock + j*nblock + k );
             }
          }
       }
@@ -160,17 +158,26 @@ void MultiColvar::readGroupsKeyword( int& natoms ){
 
 void MultiColvar::readTwoGroups( const std::string& key1, const std::string& key2 ){
   plumed_assert( all_atoms.fullSize()==0 );
+  ablocks.resize( 2 ); current_atoms.resize( 2 );
 
   std::vector<AtomNumber> t1, t2; std::vector<unsigned> newlist; 
   parseAtomList(key1,t1); parseAtomList(key2,t2);
   if( t1.empty() ) error("missing atom specification " + key1);
   if ( t2.empty() ) error("missing atom specification " + key2); 
-  for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] ); 
-  for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] ); 
+
+  if( t1.size()>t2.size() ) nblock = t1.size();
+  else nblock=t2.size();
+
+  ablocks[0].resize( t1.size() ); 
   for(unsigned i=0;i<t1.size();++i){
-     for(unsigned j=0;j<t2.size();++j){
-         newlist.push_back(i); newlist.push_back( t1.size() + j ); addColvar( newlist ); newlist.clear();
-     }
+     all_atoms.addIndexToList( t1[i] ); ablocks[0][i]=i;
+  }
+  ablocks[1].resize( t2.size() ); 
+  for(unsigned i=0;i<t2.size();++i){
+     all_atoms.addIndexToList( t2[i] ); ablocks[1][i]=t1.size() + i;
+  }
+  for(unsigned i=0;i<t1.size();++i){
+     for(unsigned j=0;j<t2.size();++j) taskList.addIndexToList( i*nblock + j );
   }
   if( !verbose_output ){
       log.printf("  constructing colvars from two groups containing %d and %d atoms respectively\n",t1.size(),t2.size() );
@@ -185,25 +192,32 @@ 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 ){
   plumed_assert( all_atoms.fullSize()==0 );
+  ablocks.resize( 3 ); current_atoms.resize( 3 );
 
   std::vector<AtomNumber> t1, t2, t3; std::vector<unsigned> newlist;
   parseAtomList(key1,t1); parseAtomList(key2,t2);
   if( t1.empty() ) error("missing atom specification " + key1);
   if( t2.empty() ) error("missing atom specification " + key2);
-  for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] );
-  for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] );
+  ablocks[0].resize( t1.size() ); 
+  for(unsigned i=0;i<t1.size();++i){
+    all_atoms.addIndexToList( t1[i] ); ablocks[0][i]=i;
+  }
+  ablocks[1].resize( t2.size() ); 
+  for(unsigned i=0;i<t2.size();++i){
+     all_atoms.addIndexToList( t2[i] ); ablocks[1][i] = t1.size() + i;
+  }
   parseAtomList(key3,t3);
   if( t3.empty() && !allow2 ){
       error("missing atom specification " + key3);
   } else if( t3.empty() ){
+      if( t2.size()>t1.size() ) nblock=t2.size(); 
+      else nblock=t1.size();
+
+      ablocks[2].resize( t2.size() ); 
+      for(unsigned i=0;i<t2.size();++i) ablocks[2][i]=t1.size() + i;
       for(unsigned i=0;i<t1.size();++i){
         for(unsigned j=1;j<t2.size();++j){ 
-           for(unsigned k=0;k<j;++k){
-                newlist.push_back( t1.size() + j );
-                newlist.push_back(i);
-                newlist.push_back( t1.size() + k );
-                addColvar( newlist ); newlist.clear();
-           }
+           for(unsigned k=0;k<j;++k) taskList.addIndexToList( nblock*nblock*i + nblock*j + k );
         }
       }
       if( !verbose_output ){
@@ -216,15 +230,17 @@ void MultiColvar::readThreeGroups( const std::string& key1, const std::string& k
         log.printf("\n");
       }
   } else {
-      for(unsigned i=0;i<t3.size();++i) all_atoms.addIndexToList( t3[i] );
+      if( t2.size()>t1.size() ) nblock=t2.size();
+      else nblock=t1.size();
+      if( t3.size()>nblock ) nblock=t3.size();
+
+      ablocks[2].resize( t3.size() ); 
+      for(unsigned i=0;i<t3.size();++i){
+         all_atoms.addIndexToList( t3[i] ); ablocks[2][i] = t1.size() + t2.size() + i;
+      }
       for(unsigned i=0;i<t1.size();++i){
           for(unsigned j=0;j<t2.size();++j){
-              for(unsigned k=0;k<t3.size();++k){
-                 newlist.push_back( t1.size() + j );
-                 newlist.push_back(i); 
-                 newlist.push_back( t1.size() + t2.size() + k );
-                 addColvar( newlist ); newlist.clear();
-              }
+              for(unsigned k=0;k<t3.size();++k) taskList.addIndexToList( nblock*nblock*i + nblock*j + k );
           }
       }
       if( !verbose_output ){
@@ -243,22 +259,25 @@ void MultiColvar::readThreeGroups( const std::string& key1, const std::string& k
 }
 
 void MultiColvar::readSpeciesKeyword( int& natoms ){
+  plumed_assert( usespecies );
   if( all_atoms.fullSize()>0 ) return ;
+  ablocks.resize( natoms-1 );
 
   std::vector<AtomNumber> t;
   parseAtomList("SPECIES",t);
   if( !t.empty() ){
-      natoms=t.size();
       for(unsigned i=0;i<t.size();++i) all_atoms.addIndexToList( t[i] );
-      std::vector<unsigned> newlist;
       if( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ){
-          for(unsigned i=0;i<t.size();++i){
-              newlist.push_back(i);
-              for(unsigned j=0;j<t.size();++j){
-                  if(i!=j) newlist.push_back(j); 
-              }
-              addColvar( newlist ); newlist.clear();
-          }
+          plumed_assert( natoms==2 ); current_atoms.resize( t.size() );
+          for(unsigned i=0;i<t.size();++i) taskList.addIndexToList(i);
+          ablocks[0].resize( t.size() ); for(unsigned i=0;i<t.size();++i) ablocks[0][i]=i; 
+          // for(unsigned i=0;i<t.size();++i){
+          //     newlist.push_back(i);
+          //     for(unsigned j=0;j<t.size();++j){
+          //         if(i!=j) newlist.push_back(j); 
+          //     }
+          //     addColvar( newlist ); newlist.clear();
+          // }
           if( !verbose_output ){
               log.printf("  generating colvars from %d atoms of a particular type\n",t.size() );
               log.printf("  atoms involved : "); 
@@ -268,9 +287,9 @@ void MultiColvar::readSpeciesKeyword( int& natoms ){
       } else if( !( keywords.exists("SPECIESA") && keywords.exists("SPECIESB") ) ){
           std::vector<unsigned> newlist; verbose_output=false; // Make sure we don't do verbose output
           log.printf("  involving atoms : ");
+          current_atoms.resize(1); 
           for(unsigned i=0;i<t.size();++i){ 
-             newlist.push_back(i); addColvar( newlist ); newlist.clear();
-             log.printf(" %d",t[i].serial() ); 
+             taskList.addIndexToList(i); log.printf(" %d",t[i].serial() ); 
           }
           log.printf("\n");  
       } else {
@@ -282,17 +301,16 @@ void MultiColvar::readSpeciesKeyword( int& natoms ){
       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");
-         natoms=1+t2.size();
-         for(unsigned i=0;i<t1.size();++i) all_atoms.addIndexToList( t1[i] );
-         for(unsigned i=0;i<t2.size();++i) all_atoms.addIndexToList( t2[i] );
-         std::vector<unsigned> newlist;
-         for(unsigned i=0;i<t1.size();++i){
-            newlist.push_back(i);
-            for(unsigned j=0;j<t2.size();++j){
-                if( t1[i]!=t2[j] ) newlist.push_back( t1.size() + j ); 
-            }
-            addColvar( newlist ); newlist.clear();
-         }
+         current_atoms.resize( 1+ t2.size() );
+         for(unsigned i=0;i<t1.size();++i){ all_atoms.addIndexToList( t1[i] ); taskList.addIndexToList(i); }
+         ablocks[0].resize( t2.size() ); for(unsigned i=0;i<t2.size();++i){ all_atoms.addIndexToList( t2[i] ); ablocks[0][i]=t1.size() + i; }
+         // for(unsigned i=0;i<t1.size();++i){
+         //    newlist.push_back(i);
+         //    for(unsigned j=0;j<t2.size();++j){
+         //        if( t1[i]!=t2[j] ) newlist.push_back( t1.size() + j ); 
+         //    }
+         //    addColvar( newlist ); newlist.clear();
+         // }
          if( !verbose_output ){
              log.printf("  generating colvars from a group of %d central atoms and %d other atoms\n",t1.size(), t2.size() );
              log.printf("  central atoms are : ");
@@ -309,10 +327,11 @@ void MultiColvar::readSpeciesKeyword( int& natoms ){
 void MultiColvar::resizeDynamicArrays(){
   all_atoms.deactivateAll();
   for(unsigned i=0;i<taskList.getNumberActive();++i){
-      unsigned n=taskList[i];
-      for(unsigned j=0;j<colvar_atoms[n].getNumberActive();++j){ 
-         all_atoms.activate( colvar_atoms[n][j] );
-      }
+      lindex=taskList.linkIndex(i);
+      current=taskList[i]; 
+      bool check=setupCurrentAtomList();
+      plumed_dbg_assert( check );
+      for(unsigned j=0;j<natomsper;++j) all_atoms.activate( current_atoms[j] );
   }
   all_atoms.updateActiveMembers(); 
   // Request the atoms
diff --git a/src/multicolvar/MultiColvar.h b/src/multicolvar/MultiColvar.h
index 37e66714f..4455837d0 100644
--- a/src/multicolvar/MultiColvar.h
+++ b/src/multicolvar/MultiColvar.h
@@ -92,8 +92,9 @@ public:
 
 inline
 unsigned MultiColvar::getAtomIndex( const unsigned& iatom ) const {
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
-  return all_atoms.linkIndex( colvar_atoms[current][iatom] );
+  plumed_dbg_assert( iatom<natomsper );
+  return current_atoms[iatom];
+//  return all_atoms.linkIndex( colvar_atoms[current][iatom] );
 }
 
 inline
diff --git a/src/multicolvar/MultiColvarBase.cpp b/src/multicolvar/MultiColvarBase.cpp
index 17e591704..e88f245ca 100644
--- a/src/multicolvar/MultiColvarBase.cpp
+++ b/src/multicolvar/MultiColvarBase.cpp
@@ -48,24 +48,19 @@ ActionWithValue(ao),
 ActionWithVessel(ao),
 usepbc(false),
 updateFreq(0),
-lastUpdate(0)
+lastUpdate(0),
+usespecies(false)
 {
   if( keywords.exists("NOPBC") ){ 
     bool nopbc=!usepbc; parseFlag("NOPBC",nopbc);
     usepbc=!nopbc;
   } 
+  if( keywords.exists("SPECIES") ) usespecies=true;
   if( keywords.exists("NL_STRIDE") ) parse("NL_STRIDE",updateFreq);
   if(updateFreq>0) log.printf("  Updating contributors every %d steps.\n",updateFreq);
   else log.printf("  Updating contributors every step.\n");
 }
 
-void MultiColvarBase::addColvar( const std::vector<unsigned>& newatoms ){
-  DynamicList<unsigned> newlist; newlist.setupMPICommunication( comm );
-  for(unsigned i=0;i<newatoms.size();++i) newlist.addIndexToList( newatoms[i] );
-  taskList.addIndexToList( colvar_atoms.size() );
-  colvar_atoms.push_back( newlist );
-}
-
 void MultiColvarBase::copyAtomListToFunction( MultiColvarBase* myfunction ){
   for(unsigned i=0;i<all_atoms.fullSize();++i) myfunction->all_atoms.addIndexToList( all_atoms(i) );
 }
@@ -83,7 +78,22 @@ void MultiColvarBase::copyActiveAtomsToFunction( MultiColvarBase* myfunction ){
 void MultiColvarBase::setupMultiColvarBase(){
   // Activate everything
   taskList.activateAll();
-  for(unsigned i=0;i<colvar_atoms.size();++i) colvar_atoms[i].activateAll();
+  // Setup decoder array
+  if( !usespecies ){
+     decoder.resize( ablocks.size() ); unsigned code=1;
+     for(unsigned i=0;i<ablocks.size();++i){ decoder[ablocks.size()-1-i]=code; code *= nblock; } 
+  } else if( ablocks.size()>0 ) {
+     plumed_assert( ablocks.size()==1 );
+     // Setup coordination sphere
+     csphere_atoms.resize( taskList.fullSize() );
+     for(unsigned i=0;i<taskList.fullSize();++i){
+        for(unsigned j=0;j<ablocks[0].size();++j){
+           if( taskList(i)!=ablocks[0][j] ) csphere_atoms[i].addIndexToList( ablocks[0][j] );
+        }
+        csphere_atoms[i].activateAll();
+     } 
+  }
+  
   // Resize stuff in derived classes 
   resizeDynamicArrays();
   // Resize local arrays
@@ -100,12 +110,14 @@ void MultiColvarBase::prepare(){
   bool updatetime=false;
   if( contributorsAreUnlocked ){
       taskList.mpi_gatherActiveMembers( comm );
-      mpi_gatherActiveMembers( comm, colvar_atoms ); 
+      if( usespecies ) mpi_gatherActiveMembers( comm, csphere_atoms ); 
       lockContributors(); updatetime=true;
   }
   if( updateFreq>0 && (getStep()-lastUpdate)>=updateFreq ){
       taskList.activateAll(); 
-      for(unsigned i=0;i<taskList.getNumberActive();++i) colvar_atoms[i].activateAll();
+      if(usespecies){ 
+         for(unsigned i=0;i<taskList.getNumberActive();++i) csphere_atoms[i].activateAll();
+      }
       unlockContributors(); updatetime=true; lastUpdate=getStep();
   }
   if(updatetime){
@@ -130,17 +142,43 @@ void MultiColvarBase::resizeLocalArrays(){
   forcesToApply.resize( getNumberOfDerivatives() );
 }
 
-void MultiColvarBase::performTask( const unsigned& j ){
+bool MultiColvarBase::setupCurrentAtomList(){
+  if( usespecies ){
+     natomsper=1;
+     current_atoms[0]=all_atoms.linkIndex( current );
+     for(unsigned j=0;j<ablocks.size();++j){
+        for(unsigned i=0;i<csphere_atoms[current].getNumberActive();++i){
+           current_atoms[natomsper]=all_atoms.linkIndex( csphere_atoms[current][i] );
+           natomsper++; 
+        }
+     }
+     if( natomsper==1 ) return isDensity();
+  } else {
+     natomsper=current_atoms.size();
+     unsigned scode = current;
+     for(unsigned i=0;i<ablocks.size();++i){
+        unsigned ind=std::floor( scode / decoder[i] );
+        current_atoms[i]=all_atoms.linkIndex( ablocks[i][ind] );
+        scode -= ind*decoder[i];
+     }
+  }  
+  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();
+  // Retrieve the atom list
+  if( !setupCurrentAtomList() ) return;
 
   // Do nothing if there are no active atoms in the colvar
-  if( colvar_atoms[current].getNumberActive()==0 ){  
-     setElementValue(1,0.0);
-     return;                      
-  }
+//  if( colvar_atoms[current].getNumberActive()==0 ){  
+//     setElementValue(1,0.0);
+//     return;                      
+//  }   Add retrieve atoms here
+
   // Do a quick check on the size of this contribution  
   calculateWeight();
   if( getElementValue(1)<getTolerance() ){
@@ -149,14 +187,14 @@ void MultiColvarBase::performTask( const unsigned& j ){
   }
 
   // Compute everything
-  double vv=doCalculation( j );
+  double vv=doCalculation();
   // Set the value of this element in ActionWithVessel
   setElementValue( 0, vv );
   return;
 }
 
-double MultiColvarBase::doCalculation( const unsigned& j ){
-  double val=compute(j); updateActiveAtoms();
+double MultiColvarBase::doCalculation(){
+  double val=compute(); updateActiveAtoms();
   return val;
 }
 
@@ -198,10 +236,10 @@ Vector MultiColvarBase::getSeparation( const Vector& vec1, const Vector& vec2 )
 }
 
 unsigned MultiColvarBase::getInternalIndex( const AtomNumber& iatom ) const {
+  plumed_massert( usespecies && ablocks.size()==1, "This should only be used to interogate atom centered multicolvars");
   unsigned katom; bool found=false;
-  for(unsigned i=0;i<colvar_atoms.size();++i){
-      unsigned jatom = colvar_atoms[i][0];
-      if( all_atoms[ all_atoms.linkIndex(jatom) ]==iatom ){
+  for(unsigned i=0;i<ablocks[0].size();++i){
+      if( all_atoms[ all_atoms.linkIndex(ablocks[0][i]) ]==iatom ){
          katom=i; found=true;
       }
   }
diff --git a/src/multicolvar/MultiColvarBase.h b/src/multicolvar/MultiColvarBase.h
index 728e8c4f1..648cb8cdf 100644
--- a/src/multicolvar/MultiColvarBase.h
+++ b/src/multicolvar/MultiColvarBase.h
@@ -56,15 +56,25 @@ private:
   DynamicList<unsigned> atomsWithCatomDer;
 /// The forces we are going to apply to things
   std::vector<double> forcesToApply;
+/// Neighbor lists for coordination numbers
+  std::vector<DynamicList<unsigned> > csphere_atoms;
 /// This resizes the local arrays after neighbor list updates and during initialization
   void resizeLocalArrays();
 protected:
 /// A dynamic list containing those atoms with derivatives
   DynamicList<unsigned> atoms_with_derivatives;
-/// The lists of the atoms involved in each of the individual colvars
-  std::vector< DynamicList<unsigned> > colvar_atoms;
-/// Add a colvar to the set of colvars we are calculating (in practise just a list of atoms)
-  void addColvar( const std::vector<unsigned>& newatoms );
+/// Using the species keyword to read in atoms
+  bool usespecies;
+/// Number of atoms in each block
+  unsigned nblock;
+/// This is used when turning cvcodes into atom numbers
+  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;
 /// Finish setting up the multicolvar base
   void setupMultiColvarBase();
 /// Request the atoms from action atomistic
@@ -95,6 +105,8 @@ protected:
   void getCentralAtomIndexList( const unsigned& ntotal, const unsigned& jstore, const unsigned& maxder, std::vector<unsigned>& indices ) const ;
 /// Calculate and store getElementValue(uder)/getElementValue(vder) and its derivatives in getElementValue(iout)
   void quotientRule( const unsigned& uder, const unsigned& vder, const unsigned& iout );
+/// This sets up the list of atoms that are involved in this colvar
+  bool setupCurrentAtomList();
 public:
   MultiColvarBase(const ActionOptions&);
   ~MultiColvarBase(){}
@@ -103,13 +115,13 @@ public:
   void prepare();
   virtual void resizeDynamicArrays()=0;
 /// Perform one of the tasks
-  void performTask( const unsigned& j );
+  void performTask();
 /// And a virtual function which actually computes the colvar
-  virtual double doCalculation( const unsigned& j );  
+  virtual double doCalculation();  
 /// Update the atoms that have derivatives
   virtual void updateActiveAtoms()=0;
 /// This is replaced once we have a function to calculate the cv
-  virtual double compute( const unsigned& j )=0;
+  virtual double compute()=0;
 /// These replace the functions in ActionWithVessel to make the code faster
   void mergeDerivatives( const unsigned& ider, const double& df );
   void clearDerivativesAfterTask( const unsigned& ider );
@@ -152,15 +164,16 @@ unsigned MultiColvarBase::getNumberOfDerivatives(){
 
 inline
 void MultiColvarBase::removeAtomRequest( const unsigned& i, const double& weight ){
+  plumed_dbg_assert( usespecies );
   if( !contributorsAreUnlocked ) return;
   plumed_dbg_assert( weight<getTolerance() );
-  if( weight<getNLTolerance() ) colvar_atoms[current].deactivate( i );
+// GAT neighbor list
+  if( weight<getNLTolerance() ) csphere_atoms[current].deactivate( i );
 }
 
 inline
 void MultiColvarBase::deactivate_task(){
   if( !contributorsAreUnlocked ) return;      // Deactivating tasks only possible during neighbor list update
-  colvar_atoms[current].deactivateAll();      // Deactivate all atom requests for this colvar
   ActionWithVessel::deactivate_task();        // Deactivate the colvar from the list
 }
 
@@ -176,7 +189,7 @@ unsigned MultiColvarBase::getNumberOfQuantities(){
 
 inline
 unsigned MultiColvarBase::getNAtoms() const {
-  return colvar_atoms[current].getNumberActive();
+  return natomsper;   // colvar_atoms[current].getNumberActive();
 }
 
 inline
diff --git a/src/multicolvar/MultiColvarFunction.cpp b/src/multicolvar/MultiColvarFunction.cpp
index 970eda643..614c422e8 100644
--- a/src/multicolvar/MultiColvarFunction.cpp
+++ b/src/multicolvar/MultiColvarFunction.cpp
@@ -59,13 +59,24 @@ MultiColvarBase(ao)
          log.printf("  calculating function for atoms ");
          for(unsigned i=0;i<atoms.size();++i){
             log.printf("%d ",atoms[i].serial() );
-            subatomlist.push_back( mycolv->getInternalIndex(atoms[i]) );
+            taskList.addIndexToList( mycolv->getInternalIndex(atoms[i]) );
          }
          log.printf("\n");
       } else {
-         for(unsigned i=0;i<mycolv->colvar_atoms.size();++i) subatomlist.push_back( i );
+         for(unsigned i=0;i<mycolv->taskList.fullSize();++i) taskList.addIndexToList( i );
       }
-  } 
+      usespecies=true; ablocks.resize(1); ablocks[0].resize( getNumberOfBaseFunctions() );
+      for(unsigned i=0;i<getNumberOfBaseFunctions();++i) ablocks[0][i]=i; 
+      current_atoms.resize( 1 + ablocks[0].size() );
+  } else {
+      usespecies=false; nblock=getNumberOfBaseFunctions(); ablocks.resize(2);
+      for(unsigned i=0;i<2;++i) ablocks[i].resize(nblock);
+      for(unsigned i=0;i<getNumberOfBaseFunctions();++i){ ablocks[0][i]=i; ablocks[1][i]=i; }
+      for(unsigned i=1;i<getNumberOfBaseFunctions();++i){
+         for(unsigned j=0;j<i;++j) taskList.addIndexToList( i*nblock + j );
+      }
+      current_atoms.resize( 2 );
+  }
 }
 
 void MultiColvarFunction::completeSetup(){
diff --git a/src/multicolvar/MultiColvarFunction.h b/src/multicolvar/MultiColvarFunction.h
index eb57c303f..a4392d13d 100644
--- a/src/multicolvar/MultiColvarFunction.h
+++ b/src/multicolvar/MultiColvarFunction.h
@@ -30,15 +30,11 @@ namespace multicolvar {
 
 class MultiColvarFunction : public MultiColvarBase {
 private:
-/// The list of atoms that are involved in this colvar
-  std::vector<unsigned> subatomlist;
 /// The multicolvar from which we construct these quantities
   multicolvar::MultiColvarBase* mycolv;
 /// The central atom positions
   multicolvar::StoreCentralAtomsVessel* catoms;
 protected:
-/// Get the number of colvar functions we are calculating
-  unsigned getNumberOfColvarFunctions() const;
 /// Get the index of the ith colvar we are using
   unsigned getColvarIndex( const unsigned& ) const;
 /// Get the number of functions in the multicolvar we are operating on
@@ -83,25 +79,13 @@ public:
 
 inline
 unsigned MultiColvarFunction::getNumberOfBaseFunctions() const {
-  return mycolv->colvar_atoms.size();
-}
-
-inline
-unsigned MultiColvarFunction::getNumberOfColvarFunctions() const {
-  plumed_dbg_assert( subatomlist.size()>0 );
-  return subatomlist.size();
-}
-
-inline
-unsigned MultiColvarFunction::getColvarIndex( const unsigned& jindex ) const {
-  plumed_dbg_assert( subatomlist.size()>0 && jindex<subatomlist.size() );
-  return subatomlist[jindex];
+  return mycolv->taskList.fullSize(); 
 }
 
 inline
 unsigned MultiColvarFunction::getAtomIndex( const unsigned& iatom ) const {
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
-  return mycolv->getIndexForTask( colvar_atoms[current][iatom] ); 
+  plumed_dbg_assert( iatom<natomsper );
+  return mycolv->getIndexForTask( current_atoms[iatom] ); 
 }
 
 inline
@@ -111,13 +95,13 @@ MultiColvarBase* MultiColvarFunction::getPntrToMultiColvar(){
 
 inline
 Vector MultiColvarFunction::getPositionOfCentralAtom( const unsigned& iatom ) const {
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
+  plumed_dbg_assert( iatom<natomsper );
   return catoms->getPosition( getAtomIndex(iatom) );
 }
 
 inline
 void MultiColvarFunction::addCentralAtomsDerivatives( const unsigned& iatom, const Vector& der ){
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
+  plumed_dbg_assert( iatom<natomsper );
   if( usingLowMem() ){
       catoms->recompute( getAtomIndex(iatom), 0 ); 
       catoms->addAtomsDerivatives( 0, 0, der, this );
@@ -128,7 +112,7 @@ void MultiColvarFunction::addCentralAtomsDerivatives( const unsigned& iatom, con
 
 inline
 void MultiColvarFunction::addCentralAtomsDerivativesOfWeight( const unsigned& iatom, const Vector& der ){
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
+  plumed_dbg_assert( iatom<natomsper );
   if( usingLowMem() ){
      catoms->recompute( getAtomIndex(iatom), 0 );
      catoms->addAtomsDerivatives( 0, 1, der, this );
@@ -144,7 +128,7 @@ void MultiColvarFunction::atomHasDerivative( const unsigned& iatom ){
 
 inline
 void MultiColvarFunction::addDerivativeOfCentralAtomPos( const unsigned& iatom, const Tensor& der ){
-  plumed_dbg_assert( iatom<colvar_atoms[current].getNumberActive() );
+  plumed_dbg_assert( iatom<natomsper );
   if( usingLowMem() ){
      catoms->recompute( getAtomIndex(iatom), 0 ); Vector tmpder;
      for(unsigned i=0;i<3;++i){
diff --git a/src/multicolvar/StoreCentralAtomsVessel.cpp b/src/multicolvar/StoreCentralAtomsVessel.cpp
index 6577c3104..cda1acafc 100644
--- a/src/multicolvar/StoreCentralAtomsVessel.cpp
+++ b/src/multicolvar/StoreCentralAtomsVessel.cpp
@@ -54,6 +54,8 @@ Vector StoreCentralAtomsVessel::getPosition( const unsigned& iatom ){
 
 void StoreCentralAtomsVessel::performTask( const unsigned& itask ){
   mycolv->atomsWithCatomDer.deactivateAll();
+  bool check=mycolv->setupCurrentAtomList();
+  plumed_dbg_assert( !check );
   Vector ignore = mycolv->retrieveCentralAtomPos();
 }
 
diff --git a/src/secondarystructure/SecondaryStructureRMSD.cpp b/src/secondarystructure/SecondaryStructureRMSD.cpp
index ed9835bb9..61c32650d 100644
--- a/src/secondarystructure/SecondaryStructureRMSD.cpp
+++ b/src/secondarystructure/SecondaryStructureRMSD.cpp
@@ -217,7 +217,7 @@ void SecondaryStructureRMSD::calculate(){
   runAllTasks();
 }
 
-void SecondaryStructureRMSD::performTask( const unsigned& j ){
+void SecondaryStructureRMSD::performTask(){
   // Retrieve the positions
   for(unsigned i=0;i<pos.size();++i) pos[i]=ActionAtomistic::getPosition( getAtomIndex(i) );
 
diff --git a/src/secondarystructure/SecondaryStructureRMSD.h b/src/secondarystructure/SecondaryStructureRMSD.h
index 915fdd26e..2a72dc7fd 100644
--- a/src/secondarystructure/SecondaryStructureRMSD.h
+++ b/src/secondarystructure/SecondaryStructureRMSD.h
@@ -90,7 +90,7 @@ public:
   unsigned getNumberOfDerivatives();
   void prepare();
   void calculate();
-  void performTask( const unsigned& j );
+  void performTask();
   void clearDerivativesAfterTask( const unsigned& );
   void apply();
   void mergeDerivatives( const unsigned& , const double& );
diff --git a/src/vesselbase/ActionWithVessel.cpp b/src/vesselbase/ActionWithVessel.cpp
index d1d495005..69d4ad0f9 100644
--- a/src/vesselbase/ActionWithVessel.cpp
+++ b/src/vesselbase/ActionWithVessel.cpp
@@ -182,10 +182,12 @@ void ActionWithVessel::runAllTasks(){
   doJobsRequiredBeforeTaskList();
 
   for(unsigned i=rank;i<taskList.getNumberActive();i+=stride){
+      // This is the position of the task in the dynamic list
+      lindex=taskList.linkIndex(i);
       // Store the task we are currently working on
       current=taskList[i];
       // Calculate the stuff in the loop for this action
-      performTask(i);
+      performTask();
       // Weight should be between zero and one
       plumed_dbg_assert( thisval[1]>=0 && thisval[1]<=1.0 );
 
diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h
index af098eb4d..fc814c3b3 100644
--- a/src/vesselbase/ActionWithVessel.h
+++ b/src/vesselbase/ActionWithVessel.h
@@ -78,6 +78,8 @@ protected:
   bool contributorsAreUnlocked;
 /// Does the weight have derivatives
   bool weightHasDerivatives;
+/// The position of the current task in the taskList
+  unsigned lindex;
 /// The numerical index of the task we are curently performing
   unsigned current;
 /// This is used for numerical derivatives of bridge variables
@@ -153,7 +155,7 @@ public:
 /// Get the index for a particular numbered task
   unsigned getIndexForTask( const unsigned& itask ) const ;
 /// Calculate one of the functions in the distribution
-  virtual void performTask( const unsigned& j )=0;
+  virtual void performTask()=0;
 /// Return a pointer to the field 
   Vessel* getVessel( const std::string& name );
 /// Set the derivative of the jth element wrt to a numbered element
diff --git a/src/vesselbase/BridgeVessel.cpp b/src/vesselbase/BridgeVessel.cpp
index c206c15dc..72b018e38 100644
--- a/src/vesselbase/BridgeVessel.cpp
+++ b/src/vesselbase/BridgeVessel.cpp
@@ -57,7 +57,7 @@ void BridgeVessel::prepare(){
 }
 
 bool BridgeVessel::calculate(){
-  myOutputAction->performTask( getAction()->current );
+  myOutputAction->performTask();
   if( myOutputAction->thisval[1]<myOutputAction->getTolerance() ){
       myOutputAction->clearAfterTask();
       return ( !myOutputAction->contributorsAreUnlocked || myOutputAction->thisval[1]>=myOutputAction->getNLTolerance() );
diff --git a/src/vesselbase/StoreDataVessel.cpp b/src/vesselbase/StoreDataVessel.cpp
index 86e7cb1b1..e41314546 100644
--- a/src/vesselbase/StoreDataVessel.cpp
+++ b/src/vesselbase/StoreDataVessel.cpp
@@ -69,7 +69,8 @@ void StoreDataVessel::recompute( const unsigned& ivec, const unsigned& jstore ){
   ActionWithVessel* act = getAction();
 
   // Set the task we want to reperform
-  act->current = ivec;
+  act->current = act->taskList(ivec);
+  act->lindex = act->taskList.linkIndex(ivec);
   // Reperform the task
   performTask( jstore );
   // Store the derivatives
@@ -88,6 +89,7 @@ void StoreDataVessel::storeValues( const unsigned& myelem ){
 }
 
 void StoreDataVessel::storeDerivativesHighMem( const unsigned& myelem ){
+  plumed_dbg_assert( myelem<getAction()->getNumberOfTasks() );
   ActionWithVessel* act=getAction();
   getIndexList( act->getNumberOfTasks(), myelem, nspace-1, active_der );
 
@@ -121,7 +123,7 @@ void StoreDataVessel::storeDerivativesLowMem( const unsigned& jstore ){
 }
 
 bool StoreDataVessel::calculate(){
-  unsigned myelem = getAction()->current;
+  unsigned myelem = getAction()->lindex;
   // Normalize vector if it is required
   finishTask( myelem );
 
@@ -245,7 +247,7 @@ void StoreDataVessel::chainRule( const unsigned& ival, const std::vector<double>
 void StoreDataVessel::transformComponents( const unsigned& jstore, const double& weight, double& wdf, const std::vector<double>& dfvec ){
   plumed_dbg_assert( dfvec.size()==vecsize );
   ActionWithVessel* act = getAction();
-  unsigned myelem = act->current;
+  unsigned myelem = act->lindex;
 
   unsigned ibuf = myelem * vecsize * nspace;
   for(unsigned icomp=0;icomp<vecsize;++icomp){
@@ -254,6 +256,7 @@ void StoreDataVessel::transformComponents( const unsigned& jstore, const double&
   }  
 
   if( !act->lowmem ) {
+      plumed_dbg_assert( jstore<getAction()->getNumberOfTasks() ); 
       for(unsigned ider=0;ider<active_der[myelem];++ider){
           double comp2=0.0; unsigned ibuf = myelem * vecsize * nspace + 1 + ider;
           for(unsigned jcomp=0;jcomp<vecsize;++jcomp){
diff --git a/src/vesselbase/StoreDataVessel.h b/src/vesselbase/StoreDataVessel.h
index cf8c9c74c..96b1aa1e9 100644
--- a/src/vesselbase/StoreDataVessel.h
+++ b/src/vesselbase/StoreDataVessel.h
@@ -132,7 +132,7 @@ bool StoreDataVessel::usingLowMem(){
 
 inline
 void StoreDataVessel::performTask( const unsigned& ivec ){
-  if( usingLowMem() ) getAction()->performTask( ivec );
+  if( usingLowMem() ) getAction()->performTask();
 }
 
 inline
-- 
GitLab