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