From 06734ff18d590d117d681dc1e272b568e90e0643 Mon Sep 17 00:00:00 2001
From: Gareth Tribello <gareth.tribello@gmail.com>
Date: Mon, 18 Feb 2013 15:31:24 +0100
Subject: [PATCH] Some small changes to core of MultiColvar and Vessels

I want to reuse stuff from these classes to do some other things and
I needed to make a few small changes to make the new things work.
---
 src/multicolvar/MultiColvar.cpp             |  23 +++-
 src/multicolvar/MultiColvar.h               |  11 +-
 src/multicolvar/Region.cpp                  |   3 +-
 src/multicolvar/StoreCentralAtomsVessel.cpp | 121 ++++++++++++++++++++
 src/multicolvar/StoreCentralAtomsVessel.h   |  69 +++++++++++
 src/vesselbase/ActionWithVessel.h           |   7 +-
 src/vesselbase/ShortcutVessel.h             |   2 +-
 src/vesselbase/Sum.cpp                      |   6 +-
 src/vesselbase/Vessel.cpp                   |   5 +-
 src/vesselbase/Vessel.h                     |   7 ++
 10 files changed, 239 insertions(+), 15 deletions(-)
 create mode 100644 src/multicolvar/StoreCentralAtomsVessel.cpp
 create mode 100644 src/multicolvar/StoreCentralAtomsVessel.h

diff --git a/src/multicolvar/MultiColvar.cpp b/src/multicolvar/MultiColvar.cpp
index dd5117505..557120462 100644
--- a/src/multicolvar/MultiColvar.cpp
+++ b/src/multicolvar/MultiColvar.cpp
@@ -326,7 +326,7 @@ void MultiColvar::readSpeciesKeyword( int& natoms ){
 }
 
 void MultiColvar::prepare(){
-  bool updatetime=false;
+  updatetime=false;
   if( reduceAtNextStep ){
       colvar_list.mpi_gatherActiveMembers( comm );
       mpi_gatherActiveMembers( comm, colvar_atoms ); 
@@ -387,7 +387,8 @@ bool MultiColvar::performTask( const unsigned& j ){
   return false;
 }
 
-Vector MultiColvar::retrieveCentralAtomPos(){
+Vector MultiColvar::retrieveCentralAtomPos( const bool& frac ){
+  centralAtomDerivativesAreInFractional=frac; 
   ibox=getPbc().getInvBox().transpose();
   for(unsigned i=0;i<central_derivs.size();++i) central_derivs[i].zero();
   return getPbc().realToScaled( getCentralAtom() );
@@ -470,5 +471,23 @@ void MultiColvar::apply(){
     }
   }
 }
+
+StoreCentralAtomsVessel* MultiColvar::getCentralAtoms(){
+  // Look to see if vectors have already been created
+  StoreCentralAtomsVessel* mycatoms;
+  for(unsigned i=0;i<getNumberOfVessels();++i){
+     mycatoms=dynamic_cast<StoreCentralAtomsVessel*>( getPntrToVessel(i) );
+     if( mycatoms ) return mycatoms;
+  }
+
+  // Create the vessel
+  std::string input; addVessel( "CATOM_STASH", input );
+  resizeFunctions(); // This makes sure resizing of vessels is done
+
+  // And create a pointer to it here
+  mycatoms = dynamic_cast<StoreCentralAtomsVessel*>( getPntrToVessel( getNumberOfVessels() - 1 ) );
+  return mycatoms;
+}
+
 }
 }
diff --git a/src/multicolvar/MultiColvar.h b/src/multicolvar/MultiColvar.h
index f32741878..473021cb5 100644
--- a/src/multicolvar/MultiColvar.h
+++ b/src/multicolvar/MultiColvar.h
@@ -26,6 +26,7 @@
 #include "core/ActionWithValue.h"
 #include "tools/DynamicList.h"
 #include "vesselbase/ActionWithVessel.h"
+#include "StoreCentralAtomsVessel.h"
 #include <vector>
 
 #define PLUMED_MULTICOLVAR_INIT(ao) Action(ao),MultiColvar(ao)
@@ -45,6 +46,7 @@ class MultiColvar :
   public vesselbase::ActionWithVessel
   {
 friend class Region;
+friend class StoreCentralAtomsVessel;
 private:
   bool usepbc;
   bool readatoms;
@@ -77,6 +79,8 @@ private:
 /// Update the atoms request
   void requestAtoms();
 protected:
+/// Are we on an update step
+  bool updatetime;
 /// Read in all the keywords that can be used to define atoms
   void readAtoms( int& natoms );
 /// Read in the atoms that form the backbone of a polymeric chain
@@ -118,7 +122,7 @@ public:
 /// Calculate the multicolvar
   void calculate();
 /// Prepare for the calculation
-  void prepare();
+  virtual void prepare();
 /// Apply the forces on the values
   void apply();
 /// Get the number of derivatives for this action
@@ -128,7 +132,7 @@ public:
 /// Return the number of derivatives for a given colvar
   unsigned getNumberOfDerivatives( const unsigned& j );
 /// Retrieve the position of the central atom
-  Vector retrieveCentralAtomPos();
+  Vector retrieveCentralAtomPos( const bool& frac );
 /// Make sure we calculate the position of the central atom
   void useCentralAtom();
 /// Merge the derivatives 
@@ -159,6 +163,9 @@ public:
   double getCharge(unsigned) const ;
 /// Get the absolute index of atom iatom
   AtomNumber getAbsoluteIndex(unsigned) const ;
+/// Return a pointer to the vessel that stores the positions of 
+/// all the central atoms
+  StoreCentralAtomsVessel* getCentralAtoms();
 };
 
 inline
diff --git a/src/multicolvar/Region.cpp b/src/multicolvar/Region.cpp
index cada68362..254a3c056 100644
--- a/src/multicolvar/Region.cpp
+++ b/src/multicolvar/Region.cpp
@@ -135,7 +135,6 @@ not_in(false)
   if( volname.substr(0,1)=="!" ){ volname=volname.substr(1); not_in=true; }
   myvol = (mycolv->plumed).getActionSet().selectWithLabel<ActionVolume*>(volname);
   if(!myvol){ error( "in REGION " + volname + " is not a valid volume element"); return; }
-  mycolv->centralAtomDerivativesAreInFractional=myvol->derivativesOfFractionalCoordinates();
   mycolv->addDependency( myvol );
 
   parse("SIGMA",sigma); myvol->setSigma( sigma );
@@ -152,7 +151,7 @@ std::string Region::function_description(){
 }
 
 bool Region::calculate(){
-  Vector catom_pos=mycolv->retrieveCentralAtomPos();
+  Vector catom_pos=mycolv->retrieveCentralAtomPos( myvol->derivativesOfFractionalCoordinates() );
 
   double weight; Vector wdf;
   weight=myvol->calculateNumberInside( catom_pos, bead, wdf );
diff --git a/src/multicolvar/StoreCentralAtomsVessel.cpp b/src/multicolvar/StoreCentralAtomsVessel.cpp
new file mode 100644
index 000000000..565c9420e
--- /dev/null
+++ b/src/multicolvar/StoreCentralAtomsVessel.cpp
@@ -0,0 +1,121 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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.h"
+#include "StoreCentralAtomsVessel.h"
+
+namespace PLMD {
+namespace multicolvar {
+
+PLUMED_REGISTER_VESSEL(StoreCentralAtomsVessel,"CATOM_STASH")
+
+void StoreCentralAtomsVessel::registerKeywords( Keywords& keys ){
+  Vessel::registerKeywords( keys );
+  plumed_assert( keys.size()==0 );
+}
+
+void StoreCentralAtomsVessel::reserveKeyword( Keywords& keys ){
+  keys.reserve("optional","CATOM_STASH","This documentation shouldn't appear");
+}
+
+StoreCentralAtomsVessel::StoreCentralAtomsVessel( const vesselbase::VesselOptions& da ):
+Vessel(da),
+wasforced(false)
+{
+  mycolv=dynamic_cast<MultiColvar*>( getAction() );
+  plumed_assert( mycolv );
+}
+
+void StoreCentralAtomsVessel::resize(){
+  unsigned nfunc=mycolv->getNumberOfFunctionsInAction();
+  unsigned bsize=0; start.resize( nfunc +1 );
+  for(unsigned i=0;i<nfunc;++i){
+      start[i] = bsize;
+      bsize += 3*( 1 + mycolv->getNumberOfDerivatives(i) );
+  }
+  start[nfunc]=bsize;
+  resizeBuffer( bsize ); 
+  forces.resize( mycolv->getNumberOfDerivatives() );
+}
+
+void StoreCentralAtomsVessel::prepare(){
+  wasforced=false;
+  forces.assign( forces.size(), 0.0 );
+}
+
+bool StoreCentralAtomsVessel::calculate(){
+  Vector catom_pos=mycolv->retrieveCentralAtomPos( false );
+  Vector wdf; wdf.zero(); 
+
+  unsigned ibuf=start[mycolv->current];
+  for(unsigned i=0;i<3;++i){
+      addToBufferElement( ibuf, catom_pos[i] ); ibuf++; wdf[i]=1.0;
+      for(unsigned j=0;j<mycolv->getNAtoms();++j){
+         addToBufferElement( ibuf, mycolv->getCentralAtomDerivative( j, i, wdf ) ); ibuf++;
+      }
+      wdf.zero();
+  }
+  plumed_dbg_assert( ibuf==start[mycolv->current+1] );
+  return true;
+}
+
+Vector StoreCentralAtomsVessel::getPosition( const unsigned& ivec ) const {
+  plumed_dbg_assert( ivec<mycolv->getNumberOfFunctionsInAction() );
+  unsigned pos=start[ivec]; Vector mypos;
+  for(unsigned i=0;i<3;++i){
+      mypos[i] = getBufferElement( pos ); pos+=mycolv->getNumberOfDerivatives(ivec)+1;
+  }
+  plumed_dbg_assert( pos==start[ivec+1] );
+  return mypos;
+}
+
+void StoreCentralAtomsVessel::addForces( const std::vector<double>& ff){
+  plumed_dbg_assert( ff.size()==forces.size() );
+  wasforced=true;
+  for(unsigned i=0;i<forces.size();++i) forces[i]+=ff[i];
+}
+
+bool StoreCentralAtomsVessel::applyForce(std::vector<double>& ff){
+  plumed_dbg_assert( ff.size()==forces.size() );
+  if(wasforced){
+    for(unsigned i=0;i<forces.size();++i) ff[i]=forces[i];
+  }
+  return wasforced;
+}
+
+void StoreCentralAtomsVessel::chainRuleForCentralAtom( const unsigned& iatom, const unsigned& iderno, const Vector& df, vesselbase::ActionWithVessel* act) const {
+  plumed_dbg_assert( iatom<mycolv->getNumberOfFunctionsInAction() );
+
+  unsigned nder=mycolv->getNumberOfDerivatives(iatom);
+  unsigned nder2=mycolv->getNumberOfDerivatives();
+  for(unsigned ider=0;ider<nder;++ider){
+      for(unsigned jcomp=0;jcomp<3;++jcomp){
+          unsigned ibuf=start[iatom] + jcomp*(nder+1) + ider;
+          act->addElementDerivative( iderno*nder2 + mycolv->getOutputDerivativeIndex(iatom, ider), df[jcomp]*getBufferElement(ibuf) );
+      }
+  }
+}
+ 
+
+}
+}
diff --git a/src/multicolvar/StoreCentralAtomsVessel.h b/src/multicolvar/StoreCentralAtomsVessel.h
new file mode 100644
index 000000000..eaa113e95
--- /dev/null
+++ b/src/multicolvar/StoreCentralAtomsVessel.h
@@ -0,0 +1,69 @@
+/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Copyright (c) 2012 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.0.
+
+   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/Vessel.h" 
+#include "MultiColvar.h"
+
+namespace PLMD {
+namespace multicolvar {
+
+class MultiColvar;
+
+class StoreCentralAtomsVessel : public vesselbase::Vessel {
+private:
+  MultiColvar* mycolv;
+  std::vector<unsigned> start;
+  bool wasforced;
+  std::vector<double> forces;
+public:
+  static void reserveKeyword( Keywords& keys );
+  static void registerKeywords( Keywords& keys );
+/// Constructor
+  StoreCentralAtomsVessel( const vesselbase::VesselOptions& );
+/// Return the number of terms
+  unsigned getNumberOfTerms(){ return 2; }
+/// This does the resizing of the buffer
+  void resize();
+/// This does nothing
+  std::string description(){ return""; }
+/// This does nothing
+  void finish(){}
+/// Add some force to the atoms
+  void addForces( const std::vector<double>& );
+/// Copy forces to local arrays
+  bool applyForce(std::vector<double>&);
+/// Set all forces equal to zero before main loop
+  void prepare();
+/// This makes sure all vectors are stored
+  bool calculate();
+/// Get the orientation of the ith vector
+  Vector getPosition( const unsigned&  ) const ;
+/// Chain rule for central atom
+  void chainRuleForCentralAtom( const unsigned& iatom, const unsigned& iderno, const Vector& df, vesselbase::ActionWithVessel* act ) const ;
+};
+
+}
+}
+#endif
+
diff --git a/src/vesselbase/ActionWithVessel.h b/src/vesselbase/ActionWithVessel.h
index 616be2f70..220cd8538 100644
--- a/src/vesselbase/ActionWithVessel.h
+++ b/src/vesselbase/ActionWithVessel.h
@@ -85,8 +85,6 @@ protected:
   void runAllTasks( const unsigned& ntasks );
 /// Resize all the functions when the number of derivatives change
   void resizeFunctions();
-///  Add some derivative of the quantity in the sum wrt to a numbered element
-  void addElementDerivative( const unsigned&, const double& );
 /// Set the derivative of the jth element wrt to a numbered element
   void setElementDerivative( const unsigned&, const double& );
 public:
@@ -116,6 +114,8 @@ public:
   virtual bool performTask( const unsigned& j )=0;
 /// Return a pointer to the field 
   Vessel* getVessel( const std::string& name );
+///  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& );
 /// Get the value of this element
@@ -183,7 +183,8 @@ void ActionWithVessel::addElementDerivative( const unsigned& ider, const double&
 inline
 void ActionWithVessel::setElementDerivative( const unsigned& ider, const double& der ){
 #ifndef NDEBUG
-  if(ider==1) plumed_dbg_assert( weightHasDerivatives );
+  unsigned ndertmp=getNumberOfDerivatives();
+  if( ider>=ndertmp && ider<2*ndertmp ) plumed_dbg_assert( weightHasDerivatives );
 #endif
   plumed_dbg_assert( ider<derivatives.size() );
   derivatives[ider] = der;
diff --git a/src/vesselbase/ShortcutVessel.h b/src/vesselbase/ShortcutVessel.h
index 374ec80ee..2ef876cb4 100644
--- a/src/vesselbase/ShortcutVessel.h
+++ b/src/vesselbase/ShortcutVessel.h
@@ -37,7 +37,7 @@ protected:
 public:
   static void registerKeywords( Keywords& keys );
   ShortcutVessel( const VesselOptions& );
-  std::string description(){ plumed_error(); }
+  std::string description(){ return ""; }
   unsigned getNumberOfTerms(){ plumed_error(); return 0; }
   void resize(){ plumed_error(); }
   bool calculate(){ plumed_error(); }
diff --git a/src/vesselbase/Sum.cpp b/src/vesselbase/Sum.cpp
index 973b13d72..b3f8283cc 100644
--- a/src/vesselbase/Sum.cpp
+++ b/src/vesselbase/Sum.cpp
@@ -49,7 +49,7 @@ void Sum::reserveKeyword( Keywords& keys ){
 
 Sum::Sum( const VesselOptions& da ) :
 FunctionVessel(da),
-df(1,1.0)
+df(2)
 {
 }
 
@@ -69,7 +69,9 @@ bool Sum::calculate(){
 }
 
 void Sum::finish(){
-  setOutputValue( getFinalValue(0) ); mergeFinalDerivatives( df );
+  setOutputValue( getFinalValue(0) ); 
+  df[0]=1.0; df[1]=0.0;
+  mergeFinalDerivatives( df );
 }
 
 
diff --git a/src/vesselbase/Vessel.cpp b/src/vesselbase/Vessel.cpp
index 51bf34e0b..ce4265ee9 100644
--- a/src/vesselbase/Vessel.cpp
+++ b/src/vesselbase/Vessel.cpp
@@ -21,7 +21,6 @@
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
 #include "ActionWithVessel.h"
 #include "Vessel.h"
-#include "ShortcutVessel.h"
 #include "tools/Exception.h"
 #include "tools/Communicator.h"
 #include "tools/Log.h"
@@ -116,8 +115,8 @@ void Vessel::checkRead(){
     error(msg);
   }
   finished_read=true;
-  ShortcutVessel* sv=dynamic_cast<ShortcutVessel*>(this);
-  if(!sv) log.printf("  %s\n", description().c_str() );
+  std::string describe=description();
+  if( describe.length()>0 ) log.printf("  %s\n", describe.c_str() );
 }
 
 void Vessel::error( const std::string& msg ){
diff --git a/src/vesselbase/Vessel.h b/src/vesselbase/Vessel.h
index 464825d19..1f1689983 100644
--- a/src/vesselbase/Vessel.h
+++ b/src/vesselbase/Vessel.h
@@ -145,6 +145,8 @@ public:
   std::string getLabel() const ;
 /// Check that readin was fine
   void checkRead();
+/// Set all the buffer elements to zero
+  void zero();
 /// Add something to the ith element in the buffer
   void addToBufferElement( const unsigned& i, const double& val);
 /// Return a description of the vessel contents
@@ -230,6 +232,11 @@ ActionWithVessel* Vessel::getAction(){
   return action;
 }
 
+inline
+void Vessel::zero(){
+  for(unsigned i=0;i<bufsize;++i) setBufferElement( i, 0.0 );
+}
+
 inline
 void Vessel::setBufferElement( const unsigned& i, const double& val){
   plumed_dbg_assert( i<bufsize );
-- 
GitLab