1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2012-2021 The plumed team
3    (see the PEOPLE file at the root of the distribution for a list of names)
4 
5    See http://www.plumed.org for more information.
6 
7    This file is part of plumed, version 2.
8 
9    plumed is free software: you can redistribute it and/or modify
10    it under the terms of the GNU Lesser General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    plumed is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU Lesser General Public License
20    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #include "BiasRepresentation.h"
23 #include "core/Value.h"
24 #include "Communicator.h"
25 #include <iostream>
26 #include "KernelFunctions.h"
27 #include "File.h"
28 #include "Grid.h"
29 
30 
31 namespace PLMD {
32 
33 using namespace std;
34 
35 /// the constructor here
BiasRepresentation(const vector<Value * > & tmpvalues,Communicator & cc)36 BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc ):hasgrid(false),rescaledToBias(false),mycomm(cc) {
37   lowI_=0.0;
38   uppI_=0.0;
39   doInt_=false;
40   ndim=tmpvalues.size();
41   for(int i=0; i<ndim; i++) {
42     values.push_back(tmpvalues[i]);
43     names.push_back(values[i]->getName());
44   }
45 }
46 /// overload the constructor: add the sigma  at constructor time
BiasRepresentation(const vector<Value * > & tmpvalues,Communicator & cc,const vector<double> & sigma)47 BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc,  const vector<double> & sigma ):hasgrid(false), rescaledToBias(false), histosigma(sigma),mycomm(cc) {
48   lowI_=0.0;
49   uppI_=0.0;
50   doInt_=false;
51   ndim=tmpvalues.size();
52   for(int i=0; i<ndim; i++) {
53     values.push_back(tmpvalues[i]);
54     names.push_back(values[i]->getName());
55   }
56 }
57 /// overload the constructor: add the grid at constructor time
BiasRepresentation(const vector<Value * > & tmpvalues,Communicator & cc,const vector<string> & gmin,const vector<string> & gmax,const vector<unsigned> & nbin,bool doInt,double lowI,double uppI)58 BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<string> & gmin, const vector<string> & gmax,
59                                        const vector<unsigned> & nbin, bool doInt, double lowI, double uppI ):hasgrid(false), rescaledToBias(false), mycomm(cc) {
60   ndim=tmpvalues.size();
61   for(int  i=0; i<ndim; i++) {
62     values.push_back(tmpvalues[i]);
63     names.push_back(values[i]->getName());
64   }
65   doInt_=doInt;
66   lowI_=lowI;
67   uppI_=uppI;
68   // initialize the grid
69   addGrid(gmin,gmax,nbin);
70 }
71 /// overload the constructor with some external sigmas: needed for histogram
BiasRepresentation(const vector<Value * > & tmpvalues,Communicator & cc,const vector<string> & gmin,const vector<string> & gmax,const vector<unsigned> & nbin,const vector<double> & sigma)72 BiasRepresentation::BiasRepresentation(const vector<Value*> & tmpvalues, Communicator &cc, const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin, const vector<double> & sigma):hasgrid(false), rescaledToBias(false),histosigma(sigma),mycomm(cc) {
73   lowI_=0.0;
74   uppI_=0.0;
75   doInt_=false;
76   ndim=tmpvalues.size();
77   for(int  i=0; i<ndim; i++) {
78     values.push_back(tmpvalues[i]);
79     names.push_back(values[i]->getName());
80   }
81   // initialize the grid
82   addGrid(gmin,gmax,nbin);
83 }
84 
addGrid(const vector<string> & gmin,const vector<string> & gmax,const vector<unsigned> & nbin)85 void  BiasRepresentation::addGrid( const vector<string> & gmin, const vector<string> & gmax, const vector<unsigned> & nbin ) {
86   plumed_massert(hills.size()==0,"you can set the grid before loading the hills");
87   plumed_massert(hasgrid==false,"to build the grid you should not having the grid in this bias representation");
88   string ss; ss="file.free";
89   vector<Value*> vv; for(unsigned i=0; i<values.size(); i++)vv.push_back(values[i]);
90   //cerr<<" initializing grid "<<endl;
91   BiasGrid_.reset(new Grid(ss,vv,gmin,gmax,nbin,false,true));
92   hasgrid=true;
93 }
hasSigmaInInput()94 bool BiasRepresentation::hasSigmaInInput() {
95   if(histosigma.size()==0) {return false;} else {return true;}
96 }
setRescaledToBias(bool rescaled)97 void BiasRepresentation::setRescaledToBias(bool rescaled) {
98   plumed_massert(hills.size()==0,"you can set the rescaling function only before loading hills");
99   rescaledToBias=rescaled;
100 }
isRescaledToBias()101 const bool & BiasRepresentation::isRescaledToBias() {
102   return rescaledToBias;
103 }
104 
getNumberOfDimensions()105 unsigned BiasRepresentation::getNumberOfDimensions() {
106   return values.size();
107 }
getNames()108 vector<string> BiasRepresentation::getNames() {
109   return names;
110 }
getName(unsigned i)111 const string & BiasRepresentation::getName(unsigned i) {
112   return names[i];
113 }
114 
getPtrToValues()115 const vector<Value*>& BiasRepresentation::getPtrToValues() {
116   return values;
117 }
getPtrToValue(unsigned i)118 Value*  BiasRepresentation::getPtrToValue(unsigned i) {
119   return values[i];
120 }
121 
readFromPoint(IFile * ifile)122 std::unique_ptr<KernelFunctions> BiasRepresentation::readFromPoint(IFile *ifile) {
123   vector<double> cc( names.size() );
124   for(unsigned i=0; i<names.size(); ++i) {
125     ifile->scanField(names[i],cc[i]);
126   }
127   double h=1.0;
128   return std::unique_ptr<KernelFunctions>( new KernelFunctions(cc,histosigma,"gaussian","DIAGONAL",h) );
129 }
pushKernel(IFile * ifile)130 void BiasRepresentation::pushKernel( IFile *ifile ) {
131   std::unique_ptr<KernelFunctions> kk;
132   // here below the reading of the kernel is completely hidden
133   if(histosigma.size()==0) {
134     ifile->allowIgnoredFields();
135     kk=KernelFunctions::read(ifile,true,names);
136   } else {
137     // when doing histogram assume gaussian with a given diagonal sigma
138     // and neglect all the rest
139     kk=readFromPoint(ifile);
140   }
141   // the bias factor is not something about the kernels but
142   // must be stored to keep the  bias/free energy duality
143   string dummy; double dummyd;
144   if(ifile->FieldExist("biasf")) {
145     ifile->scanField("biasf",dummy);
146     Tools::convert(dummy,dummyd);
147   } else {dummyd=1.0;}
148   biasf.push_back(dummyd);
149   // the domain does not pertain to the kernel but to the values here defined
150   string	mins,maxs,minv,maxv,mini,maxi; mins="min_"; maxs="max_";
151   for(int i=0 ; i<ndim; i++) {
152     if(values[i]->isPeriodic()) {
153       ifile->scanField(mins+names[i],minv);
154       ifile->scanField(maxs+names[i],maxv);
155       // verify that the domain is correct
156       values[i]->getDomain(mini,maxi);
157       plumed_massert(mini==minv,"the input periodicity in hills and in value definition does not match"  );
158       plumed_massert(maxi==maxv,"the input periodicity in hills and in value definition does not match"  );
159     }
160   }
161   // if grid is defined then it should be added on the grid
162   //cerr<<"now with "<<hills.size()<<endl;
163   if(hasgrid) {
164     vector<unsigned> nneighb;
165     if(doInt_&&(kk->getCenter()[0]+kk->getContinuousSupport()[0] > uppI_ || kk->getCenter()[0]-kk->getContinuousSupport()[0] < lowI_ )) {
166       nneighb=BiasGrid_->getNbin();
167     } else nneighb=kk->getSupport(BiasGrid_->getDx());
168     vector<Grid::index_t> neighbors=BiasGrid_->getNeighbors(kk->getCenter(),nneighb);
169     vector<double> der(ndim);
170     vector<double> xx(ndim);
171     if(mycomm.Get_size()==1) {
172       for(unsigned i=0; i<neighbors.size(); ++i) {
173         Grid::index_t ineigh=neighbors[i];
174         for(int j=0; j<ndim; ++j) {der[j]=0.0;}
175         BiasGrid_->getPoint(ineigh,xx);
176         // assign xx to a new vector of values
177         for(int j=0; j<ndim; ++j) {values[j]->set(xx[j]);}
178         double bias;
179         if(doInt_) bias=kk->evaluate(values,der,true,doInt_,lowI_,uppI_);
180         else bias=kk->evaluate(values,der,true);
181         if(rescaledToBias) {
182           double f=(biasf.back()-1.)/(biasf.back());
183           bias*=f;
184           for(int j=0; j<ndim; ++j) {der[j]*=f;}
185         }
186         BiasGrid_->addValueAndDerivatives(ineigh,bias,der);
187       }
188     } else {
189       unsigned stride=mycomm.Get_size();
190       unsigned rank=mycomm.Get_rank();
191       vector<double> allder(ndim*neighbors.size(),0.0);
192       vector<double> allbias(neighbors.size(),0.0);
193       vector<double> tmpder(ndim);
194       for(unsigned i=rank; i<neighbors.size(); i+=stride) {
195         Grid::index_t ineigh=neighbors[i];
196         BiasGrid_->getPoint(ineigh,xx);
197         for(int j=0; j<ndim; ++j) {values[j]->set(xx[j]);}
198         if(doInt_) allbias[i]=kk->evaluate(values,der,true,doInt_,lowI_,uppI_);
199         else allbias[i]=kk->evaluate(values,der,true);
200         if(rescaledToBias) {
201           double f=(biasf.back()-1.)/(biasf.back());
202           allbias[i]*=f;
203           for(int j=0; j<ndim; ++j) {tmpder[j]*=f;}
204         }
205         // this solution with the temporary vector is rather bad, probably better to take
206         // a pointer of double as it was in old gaussian
207         for(int j=0; j<ndim; ++j) { allder[ndim*i+j]=tmpder[j]; tmpder[j]=0.;}
208       }
209       mycomm.Sum(allbias);
210       mycomm.Sum(allder);
211       for(unsigned i=0; i<neighbors.size(); ++i) {
212         Grid::index_t ineigh=neighbors[i];
213         for(int j=0; j<ndim; ++j) {der[j]=allder[ndim*i+j];}
214         BiasGrid_->addValueAndDerivatives(ineigh,allbias[i],der);
215       }
216     }
217   }
218   hills.emplace_back(std::move(kk));
219 }
getNumberOfKernels()220 int BiasRepresentation::getNumberOfKernels() {
221   return hills.size();
222 }
getGridPtr()223 Grid* BiasRepresentation::getGridPtr() {
224   plumed_massert(hasgrid,"if you want the grid pointer then you should have defined a grid before");
225   return BiasGrid_.get();
226 }
getMinMaxBin(vector<double> & vmin,vector<double> & vmax,vector<unsigned> & vbin)227 void BiasRepresentation::getMinMaxBin(vector<double> &vmin, vector<double> &vmax, vector<unsigned> &vbin) {
228   vector<double> ss,cc,binsize;
229   vmin.clear(); vmin.resize(ndim,10.e20);
230   vmax.clear(); vmax.resize(ndim,-10.e20);
231   vbin.clear(); vbin.resize(ndim);
232   binsize.clear(); binsize.resize(ndim,10.e20);
233   int ndiv=10; // adjustable parameter: division per support
234   for(unsigned i=0; i<hills.size(); i++) {
235     if(histosigma.size()!=0) {
236       ss=histosigma;
237     } else {
238       ss=hills[i]->getContinuousSupport();
239     }
240     cc=hills[i]->getCenter();
241     for(int j=0; j<ndim; j++) {
242       double dmin=cc[j]-ss[j];
243       double dmax=cc[j]+ss[j];
244       double ddiv=ss[j]/double(ndiv);
245       if(dmin<vmin[j])vmin[j]=dmin;
246       if(dmax>vmax[j])vmax[j]=dmax;
247       if(ddiv<binsize[j])binsize[j]=ddiv;
248     }
249   }
250   for(int j=0; j<ndim; j++) {
251     // reset to periodicity
252     if(values[j]->isPeriodic()) {
253       double minv,maxv;
254       values[j]->getDomain(minv,maxv);
255       if(minv>vmin[j])vmin[j]=minv;
256       if(maxv<vmax[j])vmax[j]=maxv;
257     }
258     vbin[j]=static_cast<unsigned>(ceil((vmax[j]-vmin[j])/binsize[j]) );
259   }
260 }
clear()261 void BiasRepresentation::clear() {
262   hills.clear();
263   // clear the grid
264   if(hasgrid) {
265     BiasGrid_->clear();
266   }
267 }
268 
269 
270 }
271