diff --git a/src/pamm/HBPammObject.cpp b/src/pamm/HBPammObject.cpp index 4919d02f9cb601f0e2e02367fcdd83d009f7a14a..55ceb596e511cedde4fad50517d213e9db5b422d 100644 --- a/src/pamm/HBPammObject.cpp +++ b/src/pamm/HBPammObject.cpp @@ -25,54 +25,17 @@ namespace PLMD { namespace pamm { -HBPammObject::HBPammObject(): -mymulti(NULL), -regulariser(0.001) -{ -} - -HBPammObject::HBPammObject( const HBPammObject& in ): -mymulti(in.mymulti), -regulariser(in.regulariser) -{ - for(unsigned i=0;i<in.kernels.size();++i) kernels.push_back( new KernelFunctions( in.kernels[i] ) ); -} - -HBPammObject::~HBPammObject(){ - for(unsigned i=0;i<kernels.size();++i) delete kernels[i]; -} - void HBPammObject::setup( const std::string& filename, const double& reg, multicolvar::MultiColvarBase* mybase, std::string& errorstr ){ - IFile ifile; regulariser=reg; mymulti=mybase; - if( !ifile.FileExist(filename) ){ - errorstr = "could not find file named " + filename; - return; - } - - std::vector<std::string> valnames(3); - valnames[0]="ptc"; valnames[1]="ssc"; valnames[2]="adc"; - - std::vector<Value*> pos; - for(unsigned i=0;i<3;++i){ - pos.push_back( new Value() ); pos[i]->setNotPeriodic(); - } - - ifile.open(filename); ifile.allowIgnoredFields(); kernels.resize(0); - for(unsigned k=0;;++k){ - KernelFunctions* kk = KernelFunctions::read( &ifile, false, valnames ); - if( !kk ) break ; - kk->normalize( pos ); - kernels.push_back( kk ); - ifile.scanField(); - } - ifile.close(); - for(unsigned i=0;i<3;++i) delete pos[i]; + mymulti=mybase; std::vector<std::string> valnames(3); + valnames[0]="ptc"; valnames[1]="ssc"; valnames[2]="adc"; + std::vector<std::string> min(3), max(3); std::vector<bool> pbc(3, false); + mypamm.setup( filename, reg, valnames, pbc, min, max, errorstr ); } double HBPammObject::get_cutoff() const { double sfmax=0; - for(unsigned k=0;k<kernels.size();++k){ - double rcut = kernels[k]->getCenter()[2] + kernels[k]->getContinuousSupport()[2]; + for(unsigned k=0;k<mypamm.getNumberOfKernels();++k){ + double rcut = mypamm.getKernelCenter(k)[2] + mypamm.getKernelSupport(k)[2]; if( rcut>sfmax ){ sfmax=rcut; } } return sfmax; @@ -83,47 +46,29 @@ double HBPammObject::evaluate( const unsigned& dno, const unsigned& ano, const u Vector d_dh = mymulti->getSeparation( myatoms.getPosition(dno), myatoms.getPosition(hno) ); double md_dh = d_dh.modulo(); // hydrogen - donor Vector d_ah = mymulti->getSeparation( myatoms.getPosition(ano), myatoms.getPosition(hno) ); double md_ah = d_ah.modulo(); // hydrogen - acceptor - std::vector<Value*> pos; - for(unsigned i=0;i<3;++i){ - pos.push_back( new Value() ); pos[i]->setNotPeriodic(); - } - // Proton transfer coordinate - pos[0]->set( md_dh - md_ah ); - // Symmetric stretch coordinate - pos[1]->set( md_dh + md_ah ); - // Acceptor donor distance - pos[2]->set( md_da ); - - std::vector<double> tderiv(3), tmderiv(3), dderiv(3,0); - - // Now evaluate all kernels - double denom=regulariser, numer=0; - for(unsigned i=0;i<kernels.size();++i){ - double val=kernels[i]->evaluate( pos, tmderiv ); denom+=val; - if(i==0){ numer=val; for(unsigned j=0;j<3;++j) tderiv[j]=tmderiv[j]; } - for(unsigned j=0;j<3;++j) dderiv[j] += tmderiv[j]; - } + // Create some vectors locally for pamm evaluation + std::vector<double> invals( 3 ), outvals( mypamm.getNumberOfKernels() ); + std::vector<std:: vector<double> > der( mypamm.getNumberOfKernels() ); + for(unsigned i=0;i<der.size();++i) der[i].resize(3); + + // Evaluate the pamm object + invals[0]=md_dh - md_ah; invals[1]=md_dh+md_ah; invals[2]=md_da; + mypamm.evaluate( invals, outvals, der ); if( !mymulti->doNotCalculateDerivatives() ){ - double denom2 = denom*denom, pref; - pref = tderiv[0] / denom - numer*dderiv[0]/denom2; - mymulti->addAtomDerivatives( 1, dno, ((-pref)/md_dh)*d_dh, myatoms ); - mymulti->addAtomDerivatives( 1, ano, ((+pref)/md_ah)*d_ah, myatoms ); - mymulti->addAtomDerivatives( 1, hno, ((+pref)/md_dh)*d_dh - ((+pref)/md_ah)*d_ah, myatoms ); - myatoms.addBoxDerivatives( 1, ((-pref)/md_dh)*Tensor(d_dh,d_dh) - ((-pref)/md_ah)*Tensor(d_ah,d_ah) ); - pref = tderiv[1] / denom - numer*dderiv[1]/denom2; - mymulti->addAtomDerivatives( 1, dno, ((-pref)/md_dh)*d_dh, myatoms ); - mymulti->addAtomDerivatives( 1, ano, ((-pref)/md_ah)*d_ah, myatoms ); - mymulti->addAtomDerivatives( 1, hno, ((+pref)/md_dh)*d_dh + ((+pref)/md_ah)*d_ah, myatoms ); - myatoms.addBoxDerivatives( 1, ((-pref)/md_dh)*Tensor(d_dh,d_dh) + ((-pref)/md_ah)*Tensor(d_ah,d_ah) ); - pref = tderiv[2] / denom - numer*dderiv[2]/denom2; - mymulti->addAtomDerivatives( 1, dno, ((-pref)/md_da)*d_da, myatoms ); - mymulti->addAtomDerivatives( 1, ano, ((+pref)/md_da)*d_da, myatoms ); - myatoms.addBoxDerivatives( 1, ((-pref)/md_da)*Tensor(d_da,d_da) ); + mymulti->addAtomDerivatives( 1, dno, ((-der[0][0])/md_dh)*d_dh, myatoms ); + mymulti->addAtomDerivatives( 1, ano, ((+der[0][0])/md_ah)*d_ah, myatoms ); + mymulti->addAtomDerivatives( 1, hno, ((+der[0][0])/md_dh)*d_dh - ((+der[0][0])/md_ah)*d_ah, myatoms ); + myatoms.addBoxDerivatives( 1, ((-der[0][0])/md_dh)*Tensor(d_dh,d_dh) - ((-der[0][0])/md_ah)*Tensor(d_ah,d_ah) ); + mymulti->addAtomDerivatives( 1, dno, ((-der[0][1])/md_dh)*d_dh, myatoms ); + mymulti->addAtomDerivatives( 1, ano, ((-der[0][1])/md_ah)*d_ah, myatoms ); + mymulti->addAtomDerivatives( 1, hno, ((+der[0][1])/md_dh)*d_dh + ((+der[0][1])/md_ah)*d_ah, myatoms ); + myatoms.addBoxDerivatives( 1, ((-der[0][1])/md_dh)*Tensor(d_dh,d_dh) + ((-der[0][1])/md_ah)*Tensor(d_ah,d_ah) ); + mymulti->addAtomDerivatives( 1, dno, ((-der[0][2])/md_da)*d_da, myatoms ); + mymulti->addAtomDerivatives( 1, ano, ((+der[0][2])/md_da)*d_da, myatoms ); + myatoms.addBoxDerivatives( 1, ((-der[0][2])/md_da)*Tensor(d_da,d_da) ); } - for(unsigned i=0;i<3;++i) delete pos[i]; - pos.resize(0); - return numer/denom; + return outvals[0]; } diff --git a/src/pamm/HBPammObject.h b/src/pamm/HBPammObject.h index 2c0baf6ef7e49f2c3a2197b0afe92bd6d94e2d0e..8de589da4ecb822b33d2d4319bf56911dda5c5bb 100644 --- a/src/pamm/HBPammObject.h +++ b/src/pamm/HBPammObject.h @@ -22,28 +22,20 @@ #ifndef __PLUMED_pamm_HBPammObject_h #define __PLUMED_pamm_HBPammObject_h -#include <vector> #include "tools/Vector.h" -#include "core/Value.h" #include "multicolvar/AtomValuePack.h" -#include "tools/KernelFunctions.h" +#include "PammObject.h" namespace PLMD { namespace pamm { class HBPammObject { private: +/// The Pamm object underlying this HBPamm calculation + PammObject mypamm; /// Pointer to base class in multicolvar multicolvar::MultiColvarBase* mymulti; -/// Regularisation parameter to use - double regulariser; -/// List of kernel functions involved - std::vector<KernelFunctions*> kernels; public: -// Explicit definitions for constructor, copy constructor and destructor - HBPammObject(); - HBPammObject( const HBPammObject& ); - ~HBPammObject(); /// Setup the HBPamm object void setup( const std::string& filename, const double& reg, multicolvar::MultiColvarBase* mybase, std::string& errorstr ); /// Get the cutoff to use throughout diff --git a/src/pamm/PAMM.cpp b/src/pamm/PAMM.cpp index add0803ea7f5c20010e3e465276927424d01975a..71476d285ca42818948d391a21f02be3c7f41bc4 100644 --- a/src/pamm/PAMM.cpp +++ b/src/pamm/PAMM.cpp @@ -23,6 +23,7 @@ #include "tools/KernelFunctions.h" #include "tools/IFile.h" #include "multicolvar/MultiColvarFunction.h" +#include "PammObject.h" //+PLUMEDOC MCOLVARF PAMM /* @@ -108,13 +109,10 @@ namespace pamm { class PAMM : public multicolvar::MultiColvarFunction { private: - double regulariser; - std::vector<KernelFunctions*> kernels; - std::vector<Value*> pos; + PammObject mypamm; public: static void registerKeywords( Keywords& keys ); PAMM(const ActionOptions&); - ~PAMM(); /// We have to overwrite this here unsigned getNumberOfQuantities(); /// Calculate the weight of this object ( average of input weights ) @@ -162,48 +160,27 @@ MultiColvarFunction(ao) } bool mixed=getBaseMultiColvar(0)->isPeriodic(); + std::vector<bool> pbc( getNumberOfBaseMultiColvars() ); + std::vector<std::string> valnames( getNumberOfBaseMultiColvars() ); + std::vector<std::string> min( getNumberOfBaseMultiColvars() ), max( getNumberOfBaseMultiColvars() ); for(unsigned i=0;i<getNumberOfBaseMultiColvars();++i){ - pos.push_back( new Value() ); if( getBaseMultiColvar(i)->isPeriodic()!=mixed ) warning("mixing of periodic and aperiodic base variables in pamm is untested"); - if( !getBaseMultiColvar(i)->isPeriodic() ){ - pos[i]->setNotPeriodic(); - } else { - std::string min, max; - getBaseMultiColvar(i)->retrieveDomain( min, max ); - pos[i]->setDomain( min, max ); - } - } - - // Get labels for base multicolvars - std::vector<std::string> valnames( getNumberOfBaseMultiColvars() ); - for(unsigned i=0;i<valnames.size();++i) valnames[i]=getBaseMultiColvar(i)->getLabel(); - - std::string filename; parse("CLUSTERS",filename); IFile ifile; - if( !ifile.FileExist(filename) ) error("could not find file named " + filename); - ifile.open(filename); ifile.allowIgnoredFields(); - - for(unsigned i=0;;++i){ - KernelFunctions* kk = KernelFunctions::read( &ifile, false, valnames ); - if( !kk ) break ; - kk->normalize( pos ); - kernels.push_back( kk ); - ifile.scanField(); + pbc[i]=getBaseMultiColvar(i)->isPeriodic(); + if( pbc[i] ) getBaseMultiColvar(i)->retrieveDomain( min[i], max[i] ); + valnames[i]=getBaseMultiColvar(i)->getLabel(); } - ifile.close(); + + double regulariser; parse("REGULARISE",regulariser); + std::string errorstr, filename; parse("CLUSTERS",filename); + mypamm.setup( filename, regulariser, valnames, pbc, min, max, errorstr ); + if( errorstr.length()>0 ) error( errorstr ); // This builds the lists buildSets( false ); - // Read the regularisation parameter - parse("REGULARISE",regulariser); -} - -PAMM::~PAMM(){ - for(unsigned i=0;i<pos.size();++i) delete pos[i]; - for(unsigned i=0;i<kernels.size();++i) delete kernels[i]; } unsigned PAMM::getNumberOfQuantities(){ - return 1 + kernels.size(); + return 1 + mypamm.getNumberOfKernels(); } void PAMM::calculateWeight( multicolvar::AtomValuePack& myatoms ){ @@ -230,40 +207,34 @@ void PAMM::calculateWeight( multicolvar::AtomValuePack& myatoms ){ double PAMM::compute( const unsigned& tindex, multicolvar::AtomValuePack& myatoms ) const { unsigned nvars = getNumberOfBaseMultiColvars(); - std::vector<std::vector<double> > tderiv( kernels.size() ); - for(unsigned i=0;i<kernels.size();++i) tderiv[i].resize( nvars ); - std::vector<double> tval(2), vals( kernels.size() ), dderiv( kernels.size(), 0 ); + std::vector<std::vector<double> > tderiv( mypamm.getNumberOfKernels() ); + for(unsigned i=0;i<tderiv.size();++i) tderiv[i].resize( nvars ); + std::vector<double> tval(2), invals( nvars ), vals( mypamm.getNumberOfKernels() ); for(unsigned i=0;i<nvars;++i){ - getVectorForTask( myatoms.getIndex(i), false, tval ); pos[i]->set( tval[1] ); + getVectorForTask( myatoms.getIndex(i), false, tval ); invals[i]=tval[1]; } + mypamm.evaluate( invals, vals, tderiv ); - // Evaluate the set of kernels - double denom=regulariser; - for(unsigned i=0;i<kernels.size();++i){ - vals[i]=kernels[i]->evaluate( pos, tderiv[i] ); - denom+=vals[i]; - for(unsigned j=0;j<nvars;++j) dderiv[j] += tderiv[i][j]; - } // Now set all values other than the first one // This is because of some peverse choices in multicolvar - for(unsigned i=1;i<kernels.size();++i) myatoms.setValue( 1+i, vals[i]/denom ); + for(unsigned i=1;i<vals.size();++i) myatoms.setValue( 1+i, vals[i] ); if( !doNotCalculateDerivatives() ){ - double denom2=denom*denom; std::vector<double> mypref( 1 + kernels.size() ); + std::vector<double> mypref( 1 + vals.size() ); for(unsigned ivar=0;ivar<nvars;++ivar){ // Get the values of the derivatives MultiValue& myder = getVectorDerivatives( myatoms.getIndex(ivar), false ); // And calculate the derivatives - for(unsigned i=0;i<kernels.size();++i) mypref[1+i] = tderiv[i][ivar]/denom - vals[i]*dderiv[ivar]/denom2; + for(unsigned i=0;i<vals.size();++i) mypref[1+i] = tderiv[i][ivar]; // This is basically doing the chain rule to get the final derivatives - superChainRule( 1, 1, 1+kernels.size(), myatoms.getIndex(ivar), mypref, myder, myatoms ); + superChainRule( 1, 1, 1+vals.size(), myatoms.getIndex(ivar), mypref, myder, myatoms ); // And clear the derivatives myder.clearAll(); } } - return vals[0] / denom; + return vals[0]; } Vector PAMM::getCentralAtom(){ diff --git a/src/pamm/PammObject.cpp b/src/pamm/PammObject.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31fe049d861e0de8193aa8ad7e41d02709aa1525 --- /dev/null +++ b/src/pamm/PammObject.cpp @@ -0,0 +1,107 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2012-2015 The plumed team + (see the PEOPLE file at the root of the distribution for a list of names) + + See http://www.plumed-code.org for more information. + + This file is part of plumed, version 2. + + plumed is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + plumed is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with plumed. If not, see <http://www.gnu.org/licenses/>. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +#include "PammObject.h" +#include "tools/IFile.h" + +namespace PLMD { +namespace pamm { + +PammObject::PammObject(): +regulariser(0.001) +{ +} + +PammObject::PammObject( const PammObject& in ): +regulariser(in.regulariser), +pbc(in.pbc), +min(in.min), +max(in.max) +{ + for(unsigned i=0;i<in.kernels.size();++i) kernels.push_back( new KernelFunctions( in.kernels[i] ) ); +} + +PammObject::~PammObject(){ + for(unsigned i=0;i<kernels.size();++i) delete kernels[i]; +} + +void PammObject::setup( const std::string& filename, const double& reg, const std::vector<std::string>& valnames, + const std::vector<bool>& pbcin, const std::vector<std::string>& imin, const std::vector<std::string>& imax, + std::string& errorstr ){ + IFile ifile; regulariser=reg; + if( !ifile.FileExist(filename) ){ + errorstr = "could not find file named " + filename; + return; + } + + std::vector<Value*> pos; + pbc.resize( valnames.size() ); + min.resize( valnames.size() ); + max.resize( valnames.size() ); + for(unsigned i=0;i<valnames.size();++i){ + pbc[i]=pbcin[i]; min[i]=imin[i]; max[i]=imax[i]; + pos.push_back( new Value() ); + if( !pbc[i] ) pos[i]->setNotPeriodic(); + else pos[i]->setDomain( min[i], max[i] ); + } + + ifile.open(filename); ifile.allowIgnoredFields(); kernels.resize(0); + for(unsigned k=0;;++k){ + KernelFunctions* kk = KernelFunctions::read( &ifile, false, valnames ); + if( !kk ) break ; + kk->normalize( pos ); + kernels.push_back( kk ); + ifile.scanField(); + } + ifile.close(); + for(unsigned i=0;i<valnames.size();++i) delete pos[i]; +} + +void PammObject::evaluate( const std::vector<double>& invar, std::vector<double>& outvals, std::vector<std::vector<double> >& der ) const { + std::vector<Value*> pos; + for(unsigned i=0;i<pbc.size();++i){ + pos.push_back( new Value() ); + if( !pbc[i] ) pos[i]->setNotPeriodic(); + else pos[i]->setDomain( min[i], max[i] ); + // And set the value + pos[i]->set( invar[i] ); + } + + // Evaluate the set of kernels + double denom=regulariser; + std::vector<double> dderiv( der[0].size(), 0 ); + for(unsigned i=0;i<kernels.size();++i){ + outvals[i]=kernels[i]->evaluate( pos, der[i] ); + denom+=outvals[i]; + for(unsigned j=0;j<der[i].size();++j) dderiv[j] += der[i][j]; + } + // Evaluate the set of derivatives + for(unsigned i=0;i<kernels.size();++i){ + outvals[i]/=denom; + for(unsigned j=0;j<der[i].size();++j) der[i][j]=der[i][j]/denom - outvals[i]*dderiv[j]/denom; + } + + for(unsigned i=0;i<pbc.size();++i) delete pos[i]; +} + + +} +} diff --git a/src/pamm/PammObject.h b/src/pamm/PammObject.h new file mode 100644 index 0000000000000000000000000000000000000000..34690e33859a7149c6fbf49868901bb54925cbf8 --- /dev/null +++ b/src/pamm/PammObject.h @@ -0,0 +1,80 @@ +/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Copyright (c) 2012-2015 The plumed team + (see the PEOPLE file at the root of the distribution for a list of names) + + See http://www.plumed-code.org for more information. + + This file is part of plumed, version 2. + + plumed is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + plumed is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with plumed. If not, see <http://www.gnu.org/licenses/>. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ +#ifndef __PLUMED_pamm_PammObject_h +#define __PLUMED_pamm_PammObject_h + +#include <vector> +#include "core/Value.h" +#include "tools/KernelFunctions.h" + +namespace PLMD { +namespace pamm { + +class PammObject { +private: +/// Regularisation parameter to use + double regulariser; +/// Is the domain periodic + std::vector<bool> pbc; +/// The domain of the function + std::vector<std::string> min, max; +/// List of kernel functions involved + std::vector<KernelFunctions*> kernels; +public: +// Explicit definitions for constructor, copy constructor and destructor + PammObject(); + PammObject( const PammObject& ); + ~PammObject(); +/// Setup the Pamm object + void setup( const std::string& filename, const double& reg, const std::vector<std::string>& valnames, + const std::vector<bool>& pbcin, const std::vector<std::string>& imin, const std::vector<std::string>& imax, + std::string& errorstr ); +/// + void evaluate( const std::vector<double>& invar, std::vector<double>& outvals, std::vector<std::vector<double> >& der ) const ; +/// + unsigned getNumberOfKernels() const ; +/// + std::vector<double> getKernelCenter( const unsigned& kno ) const ; +/// + std::vector<double> getKernelSupport( const unsigned& kno ) const ; +}; + +inline +unsigned PammObject::getNumberOfKernels() const { + return kernels.size(); +} + +inline +std::vector<double> PammObject::getKernelCenter( const unsigned& kno ) const { + return kernels[kno]->getCenter(); +} + +inline +std::vector<double> PammObject::getKernelSupport( const unsigned& kno ) const { + return kernels[kno]->getContinuousSupport(); +} + +} +} + +#endif +