diff --git a/src/Action.cpp b/src/Action.cpp
index 3da7ff8405417f9c24603cd391f8fed0393451cc..60a45f96f92b9f0e3da2b572a243f0918969c836 100644
--- a/src/Action.cpp
+++ b/src/Action.cpp
@@ -62,8 +62,13 @@ void Action::addDependency(Action*action){
 }
 
 void Action::activate(){
-  active=true;
+// preparation step is called only the first time an Action is activated.
+// since it could change its dependences (e.g. in an ActionAtomistic which is
+// accessing to a virtual atom), this is done just before dependencies are
+// activated
+  if(!active) prepare();
   for(Dependencies::iterator p=after.begin();p!=after.end();p++) (*p)->activate();
+  active=true;
 }
 
 void Action::clearDependencies(){
diff --git a/src/ActionAtomistic.cpp b/src/ActionAtomistic.cpp
index 9ed62297b1a7ae1cb20fec787735547f019269c2..6a18a42eea046e00c0d8da4ec5dd9c7ea0b69212 100644
--- a/src/ActionAtomistic.cpp
+++ b/src/ActionAtomistic.cpp
@@ -5,6 +5,7 @@
 #include <cassert>
 #include "ActionWithValue.h"
 #include "Colvar.h"
+#include "ActionWithVirtualAtom.h"
 
 using namespace std;
 using namespace PLMD;
@@ -21,6 +22,7 @@ Action(ao)
 }
 
 void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a){
+  Atoms&atoms(plumed.getAtoms());
   int nat=a.size();
   indexes.resize(nat);
   for(int i=0;i<nat;i++) indexes[i]=a[i].index();
@@ -28,8 +30,12 @@ void ActionAtomistic::requestAtoms(const vector<AtomNumber> & a){
   forces.resize(nat);
   masses.resize(nat);
   charges.resize(nat);
-  unsigned n=plumed.getAtoms().natoms;
-  for(unsigned i=0;i<indexes.size();i++) assert(indexes[i]<n);
+  int n=atoms.positions.size();
+  clearDependencies();
+  for(unsigned i=0;i<indexes.size();i++){
+    assert(indexes[i]<n);
+    if(indexes[i]>=atoms.getNatoms()) addDependency(atoms.virtualAtomsActions[indexes[i]-atoms.getNatoms()]);
+  }
   unique.clear();
   unique.insert(indexes.begin(),indexes.end());
 
@@ -96,7 +102,21 @@ void ActionAtomistic::parseAtomList(const std::string&key,std::vector<AtomNumber
   Tools::interpretRanges(strings);
   t.resize(strings.size());
   for(unsigned i=0;i<t.size();++i){
-   Tools::convert(strings[i],t[i]); // this is converting strings to AtomNumbers
+   bool ok=false;
+   ok=Tools::convert(strings[i],t[i]); // this is converting strings to AtomNumbers
+// here we check if the atom name is the name of an added virtual atom
+   if(!ok){
+     const ActionSet&actionSet(plumed.getActionSet());
+     for(ActionSet::const_iterator a=actionSet.begin();a!=actionSet.end();++a){
+       ActionWithVirtualAtom* c=dynamic_cast<ActionWithVirtualAtom*>(*a);
+       if(c) if(c->getLabel()==strings[i]){
+         ok=true;
+         t[i]=c->getIndex();
+         break;
+       }
+     }
+   }
+   assert(ok);
   }
 }
 
diff --git a/src/ActionWithVirtualAtom.cpp b/src/ActionWithVirtualAtom.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2b0a5dbf3a580a037699010f6561022b0a3e171d
--- /dev/null
+++ b/src/ActionWithVirtualAtom.cpp
@@ -0,0 +1,32 @@
+#include "ActionWithVirtualAtom.h"
+#include "Atoms.h"
+#include "PlumedMain.h"
+
+using namespace std;
+
+namespace PLMD{
+
+ActionWithVirtualAtom::ActionWithVirtualAtom(const ActionOptions&ao):
+  Action(ao),
+  ActionAtomistic(ao)
+{
+  index=plumed.getAtoms().addVirtualAtom(this);
+  AtomNumber a=AtomNumber::index(index);
+  log.printf("  serial associated to this virtual atom is %d\n",a.serial());
+}
+
+ActionWithVirtualAtom::~ActionWithVirtualAtom(){
+  plumed.getAtoms().removeVirtualAtom(this);
+}
+
+void ActionWithVirtualAtom::apply(){
+  const Vector & f(plumed.getAtoms().forces[index]);
+  for(int i=0;i<getNatoms();i++) modifyForces()[i]=matmul(derivatives[i],f);
+}
+
+void ActionWithVirtualAtom::requestAtoms(const std::vector<AtomNumber> & a){
+  ActionAtomistic::requestAtoms(a);
+  derivatives.resize(a.size());
+}
+
+}
diff --git a/src/ActionWithVirtualAtom.h b/src/ActionWithVirtualAtom.h
new file mode 100644
index 0000000000000000000000000000000000000000..f76b2fd10ef550c7c56d5c46d44c8d79c9ab84e3
--- /dev/null
+++ b/src/ActionWithVirtualAtom.h
@@ -0,0 +1,64 @@
+#ifndef __PLUMED_ActionWithVirtualAtom_h
+#define __PLUMED_ActionWithVirtualAtom_h
+
+#include "ActionAtomistic.h"
+#include "AtomNumber.h"
+#include "Vector.h"
+#include "Tensor.h"
+
+namespace PLMD{
+
+/// Class to add a single virtual atom to the system.
+/// (it might be extended to add multiple virtual atoms).
+class ActionWithVirtualAtom:
+  public ActionAtomistic
+{
+  unsigned index;
+  std::vector<Tensor> derivatives;
+  void apply();
+protected:
+/// Set position of the virtual atom
+  void setPosition(const Vector &);
+/// Set its mass
+  void setMass(double);
+/// Set its charge
+  void setCharge(double);
+/// Request atoms on which the calculation depends
+  void requestAtoms(const std::vector<AtomNumber> & a);
+/// Set the derivatives of virtual atom coordinate wrt atoms on which it dependes
+  void setAtomsDerivatives(const std::vector<Tensor> &d);
+public:
+/// Return the atom id of the corresponding virtual atom
+  AtomNumber getIndex()const;
+  ActionWithVirtualAtom(const ActionOptions&ao);
+  ~ActionWithVirtualAtom();
+};
+
+inline
+AtomNumber ActionWithVirtualAtom::getIndex()const{
+  return AtomNumber::index(index);
+}
+
+inline
+void ActionWithVirtualAtom::setPosition(const Vector & pos){
+  plumed.getAtoms().positions[index]=pos;
+}
+
+inline
+void ActionWithVirtualAtom::setMass(double m){
+  plumed.getAtoms().masses[index]=m;
+}
+
+inline
+void ActionWithVirtualAtom::setCharge(double c){
+  plumed.getAtoms().charges[index]=c;
+}
+
+inline
+void ActionWithVirtualAtom::setAtomsDerivatives(const std::vector<Tensor> &d){
+  derivatives=d;
+}
+
+}
+
+#endif
diff --git a/src/Atoms.cpp b/src/Atoms.cpp
index afaecc1c6ddd62ab1bec65ecfbe3a16fb53cc2ed..0dabd8ebc20587da9fe940575abe950df4d75927 100644
--- a/src/Atoms.cpp
+++ b/src/Atoms.cpp
@@ -32,7 +32,7 @@ Atoms::Atoms(PlumedMain&plumed):
 
 Atoms::~Atoms(){
   assert(actions.size()==0);
-  if(mdatoms) delete mdatoms;
+  delete mdatoms;
 }
 
 void Atoms::setBox(void*p){
@@ -132,6 +132,7 @@ void Atoms::share(){
   }
   virial.clear();
   for(unsigned i=0;i<gatindex.size();i++) forces[gatindex[i]].clear();
+  for(unsigned i=getNatoms();i<positions.size();i++) forces[i].clear(); // virtual atoms
   forceOnEnergy=0.0;
 }
 
@@ -275,7 +276,30 @@ void Atoms::init(){
   }
 }
 
+void Atoms::setDomainDecomposition(PlumedCommunicator& comm){
+  dd.enable(comm);
+}
 
+void Atoms::resizeVectors(unsigned n){
+  positions.resize(n);
+  forces.resize(n);
+  masses.resize(n);
+  charges.resize(n);
+}
+
+unsigned Atoms::addVirtualAtom(ActionWithVirtualAtom*a){
+  unsigned n=positions.size();
+  resizeVectors(n+1);
+  virtualAtomsActions.push_back(a);
+  return n;
+}
+
+void Atoms::removeVirtualAtom(ActionWithVirtualAtom*a){
+  unsigned n=positions.size();
+  assert(a==virtualAtomsActions[n-1]);
+  resizeVectors(n-1);
+  virtualAtomsActions.pop_back();
+}
 
 }
 
diff --git a/src/Atoms.h b/src/Atoms.h
index 267b5c8dfda127e9aaf422db8e16b2e6bbd34e32..45afa9dcdb1581c9230d77f5acc21bd6b67f27af 100644
--- a/src/Atoms.h
+++ b/src/Atoms.h
@@ -19,16 +19,20 @@ class Atoms
 {
   friend class ActionAtomistic;
   friend class GenericWholeMolecules;
+  friend class ActionWithVirtualAtom;
   int natoms;
   std::vector<Vector> positions;
   std::vector<Vector> forces;
   std::vector<double> masses;
   std::vector<double> charges;
+  std::vector<ActionWithVirtualAtom*> virtualAtomsActions;
   Tensor box;
   Tensor virial;
   double energy;
   bool   collectEnergy;
 
+  void resizeVectors(unsigned);
+
   std::vector<int> fullList;
   
   MDAtomsBase* mdatoms;
@@ -41,29 +45,6 @@ class Atoms
   double timestep;
   double forceOnEnergy;
 
-
-public:
-
-  double getEnergy()const{assert(collectEnergy);return energy;};
-  void setCollectEnergy(bool b){collectEnergy=b;};
-  void setMDEnergyUnits(double d){MDEnergyUnits=d;};
-  void setMDLengthUnits(double d){MDLengthUnits=d;};
-  void setMDTimeUnits(double d){MDTimeUnits=d;};
-  double getMDEnergyUnits()const{return MDEnergyUnits;};
-  double getMDLengthUnits()const{return MDLengthUnits;};
-  double getMDTimeUnits()const{return MDTimeUnits;};
-  void setInternalEnergyUnits(double d){internalEnergyUnits=d;};
-  void setInternalLengthUnits(double d){internalLengthUnits=d;};
-  void setInternalTimeUnits(double d){internalTimeUnits=d;};
-  double getInternalEnergyUnits()const{return internalEnergyUnits;};
-  double getInternalLengthUnits()const{return internalLengthUnits;};
-  double getInternalTimeUnits()const{return internalTimeUnits;};
-  void updateUnits();
-
-  void setTimeStep(void*);
-  double getTimeStep()const;
-
-private:
   std::vector<const ActionAtomistic*> actions;
   std::vector<int>    gatindex;
 
@@ -91,38 +72,69 @@ private:
   DomainDecomposition dd;
 
 public:
+
   Atoms(PlumedMain&plumed);
   ~Atoms();
+
   void init();
+
+  void share();
+  void wait();
+  void updateForces();
+
+  void setRealPrecision(int);
+  int  getRealPrecision()const;
+
+  void setTimeStep(void*);
+  double getTimeStep()const;
+
   void setNatoms(int);
   const int & getNatoms()const;
-  void updateForces();
+
+  void setCollectEnergy(bool b){collectEnergy=b;};
+
   void setDomainDecomposition(PlumedCommunicator&);
   void setAtomsGatindex(int*);
   void setAtomsContiguous(int);
   void setAtomsNlocal(int);
 
+  void setEnergy(void*);
   void setBox(void*);
+  void setVirial(void*);
   void setPositions(void*);
   void setPositions(void*,int);
-  void setMasses(void*);
-  void setCharges(void*);
-  void setVirial(void*);
   void setForces(void*);
   void setForces(void*,int);
-  void setEnergy(void*);
+  void setMasses(void*);
+  void setCharges(void*);
 
-  void share();
-  void wait();
   void MD2double(const void*m,double&d)const;
   void double2MD(const double&d,void*m)const;
-  void setRealPrecision(int);
-  int  getRealPrecision()const;
+
   void createFullList(int*);
   void getFullList(int**);
   void clearFullList();
+
   void add(const ActionAtomistic*);
   void remove(const ActionAtomistic*);
+
+  double getEnergy()const{assert(collectEnergy);return energy;};
+
+  void setMDEnergyUnits(double d){MDEnergyUnits=d;};
+  void setMDLengthUnits(double d){MDLengthUnits=d;};
+  void setMDTimeUnits(double d){MDTimeUnits=d;};
+  double getMDEnergyUnits()const{return MDEnergyUnits;};
+  double getMDLengthUnits()const{return MDLengthUnits;};
+  double getMDTimeUnits()const{return MDTimeUnits;};
+  void setInternalEnergyUnits(double d){internalEnergyUnits=d;};
+  void setInternalLengthUnits(double d){internalLengthUnits=d;};
+  void setInternalTimeUnits(double d){internalTimeUnits=d;};
+  double getInternalEnergyUnits()const{return internalEnergyUnits;};
+  double getInternalLengthUnits()const{return internalLengthUnits;};
+  double getInternalTimeUnits()const{return internalTimeUnits;};
+  void updateUnits();
+  unsigned int addVirtualAtom(ActionWithVirtualAtom*);
+  void removeVirtualAtom(ActionWithVirtualAtom*);
 };
 
 inline
@@ -130,11 +142,6 @@ const int & Atoms::getNatoms()const{
   return natoms;
 }
 
-inline
-void Atoms::setDomainDecomposition(PlumedCommunicator& comm){
-  dd.enable(comm);
-}
-
 
 }
 #endif
diff --git a/src/GenericCOM.cpp b/src/GenericCOM.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e2060f77f3421ace01d4c073d66f3b60dafd387c
--- /dev/null
+++ b/src/GenericCOM.cpp
@@ -0,0 +1,73 @@
+#include "ActionWithVirtualAtom.h"
+#include "ActionRegister.h"
+
+using namespace std;
+
+namespace PLMD{
+
+//+PLUMEDOC GENERIC COM
+/**
+Calculate the center of mass of a group of atoms
+
+\par Syntax
+\verbatim
+COM LABEL=label ATOMS=x,y,z,...
+\endverbatim
+The center of mass of atoms x,y,z,... is computed and stored in a virtual
+atom which can be accessed through the label "label"
+
+\par Example
+The following input is printing the distance between the
+center of mass of atoms 1,2,3,4,5,6,7 and that of atoms 15,20:
+\verbatim
+COM ATOMS=1-7         LABEL=c1
+COM ATOMS=15,20       LABEL=c2
+DISTANCE ATOMS=c1,c2  LABEL=d1
+PRINT ARG=d1
+\endverbatim
+(See also \ref DISTANCE and \ref PRINT).
+
+*/
+//+ENDPLUMEDOC
+
+
+class GenericCOM:
+  public ActionWithVirtualAtom
+{
+public:
+  GenericCOM(const ActionOptions&ao);
+  void calculate();
+};
+
+PLUMED_REGISTER_ACTION(GenericCOM,"COM")
+
+GenericCOM::GenericCOM(const ActionOptions&ao):
+  Action(ao),
+  ActionWithVirtualAtom(ao)
+{
+  vector<AtomNumber> atoms;
+  parseAtomList("ATOMS",atoms);
+  checkRead();
+  log.printf("  of atoms");
+  for(unsigned i=0;i<atoms.size();++i) log.printf(" %d",atoms[i].serial());
+  log.printf("\n");
+  requestAtoms(atoms);
+}
+
+void GenericCOM::calculate(){
+  Vector pos;
+  double mass(0.0),charge(0.0);
+  vector<Tensor> deriv(getNatoms());
+  for(int i=0;i<getNatoms();i++) mass+=getMasses(i);
+  for(int i=0;i<getNatoms();i++) charge+=getCharges(i);
+  for(int i=0;i<getNatoms();i++){
+    pos+=(getMasses(i)/mass)*getPositions(i);
+    deriv[i]=(getMasses(i)/mass)*Tensor::identity();
+  }
+  setPosition(pos);
+  setMass(mass);
+  setCharge(charge);
+  setAtomsDerivatives(deriv);
+}
+
+}
diff --git a/src/PlumedMain.cpp b/src/PlumedMain.cpp
index 24ab1cfc7daa2f140e739b56a88eeaf6c5632e35..fe1cbc28d78392d797047e2673e82e4e1619f3f3 100644
--- a/src/PlumedMain.cpp
+++ b/src/PlumedMain.cpp
@@ -394,6 +394,10 @@ void PlumedMain::prepareDependencies(){
 
 // activate all the actions which are on step
 // activation is recursive and enables also the dependencies
+// before doing that, the prepare() method is called to see if there is some
+// new/changed dependency (up to now, only useful for dependences on virtual atoms,
+// which can be dynamically changed).
+//
 // for optimization, an "active" flag remains false if no action at all is active
   active=false;
   for(unsigned i=0;i<pilots.size();++i){
@@ -403,7 +407,6 @@ void PlumedMain::prepareDependencies(){
      }
   };
 
-// allow actions to update their request list before atoms are shared
 // also, if one of them is the total energy, tell to atoms that energy should be collected
   bool collectEnergy=false;
   for(ActionSet::iterator p=actionSet.begin();p!=actionSet.end();p++){
@@ -411,7 +414,6 @@ void PlumedMain::prepareDependencies(){
       if(Colvar *c=dynamic_cast<Colvar*>(*p)) {
         if(c->checkIsEnergy()) collectEnergy=true;
       }
-      (*p)->prepare();
     }
   }
   atoms.setCollectEnergy(collectEnergy);