From 8435cbf5913ce8fca5fa58a735e18be8a5e8cd68 Mon Sep 17 00:00:00 2001
From: Gareth Tribello <gt@eider.phy.qub.ac.uk>
Date: Fri, 30 Oct 2015 10:01:09 +0000
Subject: [PATCH] Some small changes that allow for opitimisations of
 multicolvars

It is now possible to specify a different link cell cutoff for the
third bodies.  In addition, the way that connectivity is determined
in adjacency matrix actions works better given that we can now
operate with non-contact matrix contact matrices.  Also added some
cutoff stuff to HistogramBead.  This is currently not used in many
places
---
 src/adjmat/AdjacencyMatrixBase.cpp   |  4 ++--
 src/adjmat/AdjacencyMatrixBase.h     |  9 +++++++
 src/adjmat/AdjacencyMatrixVessel.cpp | 33 +++++++++++++++-----------
 src/adjmat/ContactAlignedMatrix.cpp  |  3 +++
 src/adjmat/ContactMatrix.cpp         |  2 ++
 src/multicolvar/AtomValuePack.cpp    |  5 ++--
 src/multicolvar/MultiColvarBase.cpp  | 10 ++++----
 src/multicolvar/MultiColvarBase.h    |  9 ++++++-
 src/tools/HistogramBead.cpp          | 35 +++++++++++++++++++++++++++-
 src/tools/HistogramBead.h            |  6 +++++
 10 files changed, 92 insertions(+), 24 deletions(-)

diff --git a/src/adjmat/AdjacencyMatrixBase.cpp b/src/adjmat/AdjacencyMatrixBase.cpp
index 037ca71e8..1fc3357cd 100644
--- a/src/adjmat/AdjacencyMatrixBase.cpp
+++ b/src/adjmat/AdjacencyMatrixBase.cpp
@@ -143,9 +143,9 @@ void AdjacencyMatrixBase::requestAtoms( const std::vector<AtomNumber>& atoms, co
   if( symmetric ){
     for(unsigned i=1;i<dims[0];++i){
       for(unsigned j=0;j<i;++j){
-        bookeeping(i,j).first=getFullNumberOfTasks();
+        bookeeping(j,i).first=bookeeping(i,j).first=getFullNumberOfTasks();
         for(unsigned k=0;k<kcount;++k) addTaskToList( i*icoef + j*jcoef + k*kcoef );
-        bookeeping(i,j).second=getFullNumberOfTasks();
+        bookeeping(j,i).second=bookeeping(i,j).second=getFullNumberOfTasks();
       }
     }
   } else {
diff --git a/src/adjmat/AdjacencyMatrixBase.h b/src/adjmat/AdjacencyMatrixBase.h
index 019b5934e..3b269b60d 100644
--- a/src/adjmat/AdjacencyMatrixBase.h
+++ b/src/adjmat/AdjacencyMatrixBase.h
@@ -78,6 +78,10 @@ public:
   Vector getCentralAtom(){ plumed_merror("cannot find central atoms for adjacency matrix actions"); Vector dum; return dum; }
 /// Get the absolute index of an atom
 //  AtomNumber getAbsoluteIndexOfCentralAtom(const unsigned& i) const ;
+/// Transforms the stored values in whatever way is required
+  virtual double transformStoredValues( const std::vector<double>& myvals, unsigned& vout, double& df ) const ;
+/// Used to check for connections between atoms
+  virtual bool checkForConnection( const std::vector<double>& myvals ) const=0;
 };
 
 inline
@@ -98,6 +102,11 @@ void AdjacencyMatrixBase::getOrientationVector( const unsigned& ind, const bool&
   mybasedata[mmc]->retrieveValue( convertToLocalIndex(ind,mmc), normed, orient );
 }
 
+inline
+double AdjacencyMatrixBase::transformStoredValues( const std::vector<double>& myvals, unsigned& vout, double& df  ) const {
+  plumed_dbg_assert( myvals.size()==2 ); vout=1; df=1; return myvals[1]; 
+}
+
 }
 }
 
diff --git a/src/adjmat/AdjacencyMatrixVessel.cpp b/src/adjmat/AdjacencyMatrixVessel.cpp
index dbfc6989a..180a20a0b 100644
--- a/src/adjmat/AdjacencyMatrixVessel.cpp
+++ b/src/adjmat/AdjacencyMatrixVessel.cpp
@@ -87,7 +87,8 @@ void AdjacencyMatrixVessel::getMatrixIndices( const unsigned& code, unsigned& i,
 }
 
 void AdjacencyMatrixVessel::retrieveMatrix( DynamicList<unsigned>& myactive_elements, Matrix<double>& mymatrix ){
-  myactive_elements.deactivateAll(); std::vector<double> vals( getNumberOfComponents() );
+  unsigned vin; double df;
+  myactive_elements.deactivateAll(); std::vector<double> vals( getNumberOfComponents() ); 
   for(unsigned i=0;i<getNumberOfStoredValues();++i){
       // Ignore any non active members
       if( !storedValueIsActive(i) ) continue ;
@@ -95,11 +96,8 @@ void AdjacencyMatrixVessel::retrieveMatrix( DynamicList<unsigned>& myactive_elem
       unsigned j, k; getMatrixIndices( i, k, j );
       retrieveValue( i, false, vals );
 
-      // Find the maximum element in the stored values
-      double max=vals[1]; for(unsigned j=2;j<vals.size();++j){ if( vals[j]>max ) max=vals[j]; }
-
-      if( symmetric ) mymatrix(k,j)=mymatrix(j,k)=max / vals[0];
-      else mymatrix(k,j) = max / vals[0];
+      if( symmetric ) mymatrix(k,j)=mymatrix(j,k)=function->transformStoredValues( vals, vin, df );      
+      else mymatrix(k,j)=function->transformStoredValues( vals, vin, df );                                 
   }
   myactive_elements.updateActiveMembers();  
 }
@@ -110,10 +108,17 @@ void AdjacencyMatrixVessel::retrieveAdjacencyLists( std::vector<unsigned>& nneig
   for(unsigned i=0;i<nneigh.size();++i) nneigh[i]=0;
 
   // And set up the adjacency list
+  std::vector<double> myvals( getNumberOfComponents() );
   for(unsigned i=0;i<getNumberOfStoredValues();++i){
       // Ignore any non active members
       if( !storedValueIsActive(i) ) continue ;
-      unsigned j, k; getMatrixIndices( i, k, j );
+      // Check if atoms are connected 
+      retrieveValue( i, false, myvals );
+      unsigned j, k; getMatrixIndices( i, k, j ); 
+      if( !function->checkForConnection( myvals ) ) continue ;       
+      
+      // Store if atoms are connected
+      // unsigned j, k; getMatrixIndices( i, k, j );
       adj_list(k,nneigh[k])=j; nneigh[k]++;
       adj_list(j,nneigh[j])=k; nneigh[j]++;
   }
@@ -121,9 +126,14 @@ void AdjacencyMatrixVessel::retrieveAdjacencyLists( std::vector<unsigned>& nneig
 
 void AdjacencyMatrixVessel::retrieveEdgeList( unsigned& nedge, std::vector<std::pair<unsigned,unsigned> >& edge_list ){
   plumed_dbg_assert( undirectedGraph() ); nedge=0;
+  std::vector<double> myvals( getNumberOfComponents() );
   for(unsigned i=0;i<getNumberOfStoredValues();++i){
       // Ignore any non active members
       if( !storedValueIsActive(i) ) continue ;
+      // Check if atoms are connected 
+      retrieveValue( i, false, myvals );
+      if( !function->checkForConnection( myvals ) ) continue ;
+
       getMatrixIndices( i, edge_list[nedge].first, edge_list[nedge].second );
       nedge++;
   }
@@ -133,16 +143,13 @@ void AdjacencyMatrixVessel::retrieveDerivatives( const unsigned& myelem, const b
   StoreDataVessel::retrieveDerivatives( myelem, normed, myvals );
   if( !function->weightHasDerivatives ) return ;
 
-  std::vector<double> vals( getNumberOfComponents() ); retrieveValue( myelem, normed, vals ); 
-  unsigned vi=1; double max=vals[1]; 
-  for(unsigned j=2;j<vals.size();++j){ 
-    if( vals[j]>max ){ vi=j; max=vals[j]; } 
-  }
+  unsigned vi; std::vector<double> vals( getNumberOfComponents() ); retrieveValue( myelem, normed, vals ); 
+  double df, max=function->transformStoredValues( vals, vi, df );
 
   double pref = max/(vals[0]*vals[0]);
   for(unsigned i=0;i<myvals.getNumberActive();++i){
       unsigned jder=myvals.getActiveIndex(i);
-      myvals.setDerivative( 1, jder, myvals.getDerivative(vi, jder)/vals[0] - pref*myvals.getDerivative(0, jder) );
+      myvals.setDerivative( 1, jder, df*myvals.getDerivative(vi, jder)/vals[0] - pref*myvals.getDerivative(0, jder) );
   }
 }
 
diff --git a/src/adjmat/ContactAlignedMatrix.cpp b/src/adjmat/ContactAlignedMatrix.cpp
index 0e4764231..a90c242a2 100644
--- a/src/adjmat/ContactAlignedMatrix.cpp
+++ b/src/adjmat/ContactAlignedMatrix.cpp
@@ -54,6 +54,9 @@ public:
   void calculateWeight( const unsigned& taskCode, multicolvar::AtomValuePack& myatoms ) const ;
 /// This does nothing
   double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ;
+///
+  /// Used to check for connections between atoms
+  bool checkForConnection( const std::vector<double>& myvals ) const { return !(myvals[1]>epsilon); }
 };
 
 PLUMED_REGISTER_ACTION(ContactAlignedMatrix,"ALIGNED_MATRIX")
diff --git a/src/adjmat/ContactMatrix.cpp b/src/adjmat/ContactMatrix.cpp
index c1284f4bb..111424b22 100644
--- a/src/adjmat/ContactMatrix.cpp
+++ b/src/adjmat/ContactMatrix.cpp
@@ -55,6 +55,8 @@ public:
   void calculateWeight( const unsigned& taskCode, multicolvar::AtomValuePack& myatoms ) const ;
 /// This does nothing
   double compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const ;
+/// Used to check for connections between atoms
+  virtual bool checkForConnection( const std::vector<double>& myvals ) const { return true; }
 };
 
 PLUMED_REGISTER_ACTION(ContactMatrix,"CONTACT_MATRIX")
diff --git a/src/multicolvar/AtomValuePack.cpp b/src/multicolvar/AtomValuePack.cpp
index c9ee792a0..66f7e4cbf 100644
--- a/src/multicolvar/AtomValuePack.cpp
+++ b/src/multicolvar/AtomValuePack.cpp
@@ -43,9 +43,8 @@ myatoms( vals.getAtomVector() )
 
 unsigned AtomValuePack::setupAtomsFromLinkCells( const std::vector<unsigned>& cind, const Vector& cpos, const LinkCells& linkcells ){
   natoms=cind.size(); for(unsigned i=0;i<natoms;++i) indices[i]=cind[i];
-  linkcells.retrieveNeighboringAtoms( cpos, natoms, indices ); myatoms[0]=Vector(0.0,0.0,0.0);
-  for(unsigned i=1;i<cind.size();++i) myatoms[i]=mycolv->getPositionOfAtomForLinkCells( cind[i] ) - cpos;
-  for(unsigned i=cind.size();i<natoms;++i) myatoms[i]=mycolv->getPositionOfAtomForLinkCells( indices[i] ) - cpos;
+  linkcells.retrieveNeighboringAtoms( cpos, natoms, indices ); 
+  for(unsigned i=0;i<natoms;++i) myatoms[i]=mycolv->getPositionOfAtomForLinkCells( indices[i] ) - cpos;
   if( mycolv->usesPbc() ) mycolv->applyPbc( myatoms, natoms );
   return natoms;
 }
diff --git a/src/multicolvar/MultiColvarBase.cpp b/src/multicolvar/MultiColvarBase.cpp
index 422867966..915de80e8 100644
--- a/src/multicolvar/MultiColvarBase.cpp
+++ b/src/multicolvar/MultiColvarBase.cpp
@@ -190,9 +190,11 @@ void MultiColvarBase::turnOnDerivatives(){
   forcesToApply.resize( getNumberOfDerivatives() );
 } 
 
-void MultiColvarBase::setLinkCellCutoff( const double& lcut ){
+void MultiColvarBase::setLinkCellCutoff( const double& lcut, double tcut ){
   plumed_assert( usespecies || ablocks.size()<4 );
-  linkcells.setCutoff( lcut ); threecells.setCutoff( lcut );
+  if( tcut<0 ) tcut=lcut;
+  linkcells.setCutoff( lcut ); 
+  threecells.setCutoff( tcut );
 }
 
 void MultiColvarBase::setupLinkCells(){
@@ -395,11 +397,11 @@ bool MultiColvarBase::setupCurrentAtomList( const unsigned& taskCode, AtomValueP
   if( usespecies ){
      if( isDensity() ) return true;
      std::vector<unsigned> task_atoms(1); task_atoms[0]=taskCode;
-     unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getPositionOfAtomForLinkCells(taskCode), linkcells );
+     unsigned natomsper=myatoms.setupAtomsFromLinkCells( task_atoms, getLinkCellPosition(task_atoms), linkcells );
      return natomsper>1;
   } else if( allthirdblockintasks ){ 
      plumed_dbg_assert( ablocks.size()==3 ); std::vector<unsigned> atoms(2); decodeIndexToAtoms( taskCode, atoms );
-     unsigned natomsper=myatoms.setupAtomsFromLinkCells( atoms, getPositionOfAtomForLinkCells(atoms[0]), threecells );
+     unsigned natomsper=myatoms.setupAtomsFromLinkCells( atoms, getLinkCellPosition(atoms), threecells );
   } else if( ablocks.size()<4 ){
      std::vector<unsigned> atoms( ablocks.size() );
      decodeIndexToAtoms( taskCode, atoms ); myatoms.setNumberOfAtoms( ablocks.size() );
diff --git a/src/multicolvar/MultiColvarBase.h b/src/multicolvar/MultiColvarBase.h
index 55c64f55e..b3eaed4bb 100644
--- a/src/multicolvar/MultiColvarBase.h
+++ b/src/multicolvar/MultiColvarBase.h
@@ -94,7 +94,7 @@ protected:
 /// 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 );
+  void setLinkCellCutoff( const double& lcut, double tcut=-1.0 );
 /// Setup link cells in order to make this calculation faster
   void setupLinkCells();
 /// Get the separation between a pair of vectors
@@ -123,6 +123,8 @@ public:
   virtual void updateActiveAtoms( AtomValuePack& myatoms ) const ;
 /// This gets the position of an atom for the link cell setup
   virtual Vector getPositionOfAtomForLinkCells( const unsigned& iatom ) const ;
+/// Returns the position where we should assume the center is for link cell calculations
+  virtual Vector getLinkCellPosition( const std::vector<unsigned>& atoms ) const ;
 /// And a virtual function which actually computes the colvar
   virtual double doCalculation( const unsigned& tindex, AtomValuePack& myatoms ) const ;  
 /// Get the absolute index of the central atom
@@ -187,6 +189,11 @@ Vector MultiColvarBase::getPositionOfAtomForLinkCells( const unsigned& iatom ) c
   return ActionAtomistic::getPosition( iatom );
 }
 
+inline
+Vector MultiColvarBase::getLinkCellPosition( const std::vector<unsigned>& atoms ) const {
+  return getPositionOfAtomForLinkCells( atoms[0] );
+} 
+
 inline
 unsigned MultiColvarBase::getNumberOfDerivatives(){
   return 3*getNumberOfAtoms()+9;
diff --git a/src/tools/HistogramBead.cpp b/src/tools/HistogramBead.cpp
index 5ca59f9ed..2d7261721 100644
--- a/src/tools/HistogramBead.cpp
+++ b/src/tools/HistogramBead.cpp
@@ -157,7 +157,11 @@ void HistogramBead::set( const std::string& params, std::string& errormsg ){
 }
 
 void HistogramBead::set( double l, double h, double w){
-  init=true; lowb=l; highb=h; width=w;  
+  init=true; lowb=l; highb=h; width=w; 
+  const double DP2CUTOFF=6.25;
+  if( type==gaussian ) cutoff=sqrt(2.0*DP2CUTOFF);
+  else if( type==triangular ) cutoff=1.;
+  else plumed_error();
 } 
 
 void HistogramBead::setKernelType( const std::string& ktype ){
@@ -194,6 +198,35 @@ double HistogramBead::calculate( double x, double& df ) const {
   return f;
 }
 
+double HistogramBead::calculateWithCutoff( double x, double& df ) const {
+  plumed_dbg_assert(init && periodicity!=unset );
+
+  double lowB, upperB, f;
+  lowB = difference( x, lowb ) / width ; upperB = difference( x, highb ) / width;
+  if( upperB<=-cutoff || lowB>=cutoff ){ double df=0; return 0; }
+
+  if( type==gaussian ){
+     lowB /= sqrt(2.0); upperB /= sqrt(2.0); 
+     df = ( exp( -lowB*lowB ) - exp( -upperB*upperB ) ) / ( sqrt(2*pi)*width );
+     f = 0.5*( erf( upperB ) - erf( lowB ) );
+  } else if( type==triangular ){
+     df=0;
+     if( fabs(lowB)<1. ) df = (1 - fabs(lowB)) / width;
+     if( fabs(upperB)<1. ) df -= (1 - fabs(upperB)) / width;
+     if (upperB<=-1. || lowB >=1.){
+        f=0.;
+     } else {
+       double ia, ib;
+       if( lowB>-1.0 ){ ia=lowB; }else{ ia=-1.0; }
+       if( upperB<1.0 ){ ib=upperB; } else{ ib=1.0; }
+       f = (ib*(2.-fabs(ib))-ia*(2.-fabs(ia)))*0.5;
+     }
+  } else {
+     plumed_merror("function type does not exist");
+  }
+  return f;
+}
+
 double HistogramBead::lboundDerivative( const double& x ) const {
   double lowB;
   if( type==gaussian ){
diff --git a/src/tools/HistogramBead.h b/src/tools/HistogramBead.h
index a8c78b156..3c7b892b9 100644
--- a/src/tools/HistogramBead.h
+++ b/src/tools/HistogramBead.h
@@ -44,6 +44,7 @@ private:
 	double lowb;
 	double highb;
 	double width;
+        double cutoff;
         enum {gaussian,triangular} type;
         enum {unset,periodic,notperiodic} periodicity;
         double min, max, max_minus_min, inv_max_minus_min;
@@ -60,10 +61,12 @@ public:
         void set(const std::string& params, std::string& errormsg);
 	void set(double l, double h, double w);
 	double calculate(double x, double&df) const;
+        double calculateWithCutoff( double x, double& df ) const; 
         double lboundDerivative( const double& x ) const;
         double uboundDerivative( const double& x ) const;
 	double getlowb() const ;
 	double getbigb() const ;
+        double getCutoff() const ;
 };	
 
 inline
@@ -90,6 +93,9 @@ double HistogramBead::getlowb() const { return lowb; }
 inline
 double HistogramBead::getbigb() const { return highb; }
 
+inline
+double HistogramBead::getCutoff() const { return cutoff*width; }
+
 inline
 double HistogramBead::difference( const double& d1, const double& d2 ) const {
   if(periodicity==notperiodic){
-- 
GitLab