Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2016-2018 The VES code team
3 : (see the PEOPLE-VES file at the root of this folder for a list of names)
4 :
5 : See http://www.ves-code.org for more information.
6 :
7 : This file is part of VES code module.
8 :
9 : The VES code module 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 : The VES code module 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 the VES code module. If not, see <http://www.gnu.org/licenses/>.
21 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 :
23 : #include "TargetDistribution.h"
24 : #include "VesTools.h"
25 :
26 : #include "core/ActionRegister.h"
27 : #include "core/ActionSet.h"
28 : #include "core/PlumedMain.h"
29 : #include "tools/Grid.h"
30 :
31 :
32 : namespace PLMD {
33 :
34 : // class Grid;
35 : class Action;
36 :
37 : namespace ves {
38 :
39 : //+PLUMEDOC VES_TARGETDIST TD_LINEAR_COMBINATION
40 : /*
41 : Target distribution given by linear combination of distributions (static or dynamic).
42 :
43 : Employ a target distribution that is a linear combination of the other
44 : distributions, defined as
45 : \f[
46 : p(\mathbf{s}) = \sum_{i} w_{i} \, p_{i}(\mathbf{s})
47 : \f]
48 : where the weights \f$w_{i}\f$ are normalized to 1, \f$\sum_{i}w_{i}=1\f$.
49 :
50 : The labels of the distributions \f$p_{i}(\mathbf{s})\f$ to be used in the
51 : linear combination are given in the DISTRIBUTIONS keyword.
52 :
53 : The weights \f$w_{i}\f$ can be given using
54 : the WEIGHTS keyword. The distributions are weighted equally if no weights are given.
55 :
56 : It is assumed that all the distributions \f$p_{i}(\mathbf{s})\f$ are normalized.
57 : If that is not the case for some reason should you
58 : normalize each distribution separately by using the NORMALIZE
59 : keyword when defining them in the input file (i.e. before the
60 : TD_LINEAR_COMBINATION action).
61 : Note that normalizing the overall
62 : linear combination will generally lead to different results than normalizing
63 : each distribution separately.
64 :
65 : The linear combination will be a dynamic target distribution if one or more
66 : of the distributions used is a dynamic distribution, otherwise it will be a
67 : static distribution.
68 :
69 : \par Examples
70 :
71 : Here we employ a linear combination of a uniform and a Gaussian distribution.
72 : No weights are given so the two distributions will be weighted equally.
73 : \plumedfile
74 : td_uni: TD_UNIFORM
75 :
76 : td_gauss: TD_GAUSSIAN CENTER1=-2.0 SIGMA1=0.5
77 :
78 : td_comb: TD_LINEAR_COMBINATION DISTRIBUTIONS=td_uniform,td_gaussian
79 : \endplumedfile
80 :
81 : Here we employ a linear combination of a uniform and two Gaussian distribution.
82 : The weights are automatically normalized to 1 such that giving
83 : WEIGHTS=1.0,1.0,2.0 as we do here is equal to giving WEIGHTS=0.25,0.25,0.50.
84 : \plumedfile
85 : td_uni: TD_UNIFORM
86 :
87 : td_gauss1: TD_GAUSSIAN CENTER1=-2.0,-2.0 SIGMA1=0.5,0.3
88 :
89 : td_gauss2: TD_GAUSSIAN CENTER1=+2.0,+2.0 SIGMA1=0.3,0.5
90 :
91 : TD_LINEAR_COMBINATION ...
92 : DISTRIBUTIONS=td_uni,td_gauss1,td_gauss2
93 : WEIGHTS=1.0,1.0,2.0
94 : LABEL=td_comb
95 : ... TD_LINEAR_COMBINATION
96 : \endplumedfile
97 :
98 : In the above example the two Gaussians are given using two separate
99 : DISTRIBUTION keywords. As the \ref TD_GAUSSIAN target distribution allows multiple
100 : centers is it also possible to use just one DISTRIBUTION keyword for the two
101 : Gaussians. This is shown in the following example which will give the
102 : exact same result as the one above as the weights have been appropriately
103 : adjusted
104 : \plumedfile
105 : td_uni: TD_UNIFORM
106 :
107 : TD_GAUSSIAN ...
108 : CENTER1=-2.0,-2.0 SIGMA1=0.5,0.3
109 : CENTER2=+2.0,+2.0 SIGMA2=0.3,0.5
110 : WEIGHTS=1.0,2.0
111 : LABEL=td_gauss
112 : ... TD_GAUSSIAN
113 :
114 : TD_LINEAR_COMBINATION ...
115 : DISTRIBUTIONS=td_uni,td_gauss
116 : WEIGHTS=0.25,0.75
117 : LABEL=td_comb
118 : ... TD_LINEAR_COMBINATION
119 : \endplumedfile
120 :
121 : */
122 : //+ENDPLUMEDOC
123 :
124 : class VesBias;
125 :
126 36 : class TD_LinearCombination: public TargetDistribution {
127 : private:
128 : std::vector<TargetDistribution*> distribution_pntrs_;
129 : std::vector<Grid*> grid_pntrs_;
130 : std::vector<double> weights_;
131 : unsigned int ndist_;
132 : void setupAdditionalGrids(const std::vector<Value*>&, const std::vector<std::string>&, const std::vector<std::string>&, const std::vector<unsigned int>&);
133 : public:
134 : static void registerKeywords(Keywords&);
135 : explicit TD_LinearCombination(const ActionOptions& ao);
136 : void updateGrid();
137 : double getValue(const std::vector<double>&) const;
138 : //
139 : void linkVesBias(VesBias*);
140 : void linkAction(Action*);
141 : //
142 : void linkBiasGrid(Grid*);
143 : void linkBiasWithoutCutoffGrid(Grid*);
144 : void linkFesGrid(Grid*);
145 : //
146 : };
147 :
148 :
149 6464 : PLUMED_REGISTER_ACTION(TD_LinearCombination,"TD_LINEAR_COMBINATION")
150 :
151 :
152 13 : void TD_LinearCombination::registerKeywords(Keywords& keys) {
153 13 : TargetDistribution::registerKeywords(keys);
154 52 : keys.add("compulsory","DISTRIBUTIONS","The labels of the target distribution actions to be used in the linear combination.");
155 52 : keys.add("optional","WEIGHTS","The weights of target distributions. Have to be as many as the number of target distribution labels given in DISTRIBUTIONS. If no weights are given the distributions are weighted equally. The weights are automatically normalized to 1.");
156 26 : keys.use("WELLTEMPERED_FACTOR");
157 : //keys.use("SHIFT_TO_ZERO");
158 26 : keys.use("NORMALIZE");
159 13 : }
160 :
161 :
162 12 : TD_LinearCombination::TD_LinearCombination(const ActionOptions& ao):
163 : PLUMED_VES_TARGETDISTRIBUTION_INIT(ao),
164 : distribution_pntrs_(0),
165 : grid_pntrs_(0),
166 : weights_(0),
167 12 : ndist_(0)
168 : {
169 12 : std::vector<std::string> targetdist_labels;
170 24 : parseVector("DISTRIBUTIONS",targetdist_labels);
171 :
172 12 : std::string error_msg = "";
173 36 : distribution_pntrs_ = VesTools::getPointersFromLabels<TargetDistribution*>(targetdist_labels,plumed.getActionSet(),error_msg);
174 12 : if(error_msg.size()>0) {plumed_merror("Error in keyword DISTRIBUTIONS of "+getName()+": "+error_msg);}
175 :
176 108 : for(unsigned int i=0; i<distribution_pntrs_.size(); i++) {
177 56 : if(distribution_pntrs_[i]->isDynamic()) {setDynamic();}
178 56 : if(distribution_pntrs_[i]->fesGridNeeded()) {setFesGridNeeded();}
179 56 : if(distribution_pntrs_[i]->biasGridNeeded()) {setBiasGridNeeded();}
180 : }
181 :
182 12 : ndist_ = distribution_pntrs_.size();
183 24 : grid_pntrs_.assign(ndist_,NULL);
184 12 : if(ndist_==0) {plumed_merror(getName()+ ": no distributions are given.");}
185 12 : if(ndist_==1) {plumed_merror(getName()+ ": giving only one distribution does not make sense.");}
186 : //
187 24 : parseVector("WEIGHTS",weights_);
188 16 : if(weights_.size()==0) {weights_.assign(distribution_pntrs_.size(),1.0);}
189 12 : if(distribution_pntrs_.size()!=weights_.size()) {
190 0 : plumed_merror(getName()+ ": there has to be as many weights given in WEIGHTS as the number of target distribution labels given in DISTRIBUTIONS");
191 : }
192 : //
193 : double sum_weights=0.0;
194 68 : for(unsigned int i=0; i<weights_.size(); i++) {sum_weights+=weights_[i];}
195 108 : for(unsigned int i=0; i<weights_.size(); i++) {weights_[i]/=sum_weights;}
196 12 : checkRead();
197 12 : }
198 :
199 :
200 0 : double TD_LinearCombination::getValue(const std::vector<double>& argument) const {
201 0 : plumed_merror("getValue not implemented for TD_LinearCombination");
202 : return 0.0;
203 : }
204 :
205 :
206 12 : void TD_LinearCombination::setupAdditionalGrids(const std::vector<Value*>& arguments, const std::vector<std::string>& min, const std::vector<std::string>& max, const std::vector<unsigned int>& nbins) {
207 68 : for(unsigned int i=0; i<ndist_; i++) {
208 56 : distribution_pntrs_[i]->setupGrids(arguments,min,max,nbins);
209 56 : if(distribution_pntrs_[i]->getDimension()!=this->getDimension()) {
210 0 : plumed_merror(getName() + ": all target distribution must have the same dimension");
211 : }
212 28 : grid_pntrs_[i]=distribution_pntrs_[i]->getTargetDistGridPntr();
213 : }
214 12 : }
215 :
216 :
217 22 : void TD_LinearCombination::updateGrid() {
218 118 : for(unsigned int i=0; i<ndist_; i++) {
219 96 : distribution_pntrs_[i]->updateTargetDist();
220 : }
221 324044 : for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) {
222 : double value = 0.0;
223 851663 : for(unsigned int i=0; i<ndist_; i++) {
224 1034478 : value += weights_[i]*grid_pntrs_[i]->getValue(l);
225 : }
226 162011 : targetDistGrid().setValue(l,value);
227 162011 : logTargetDistGrid().setValue(l,-std::log(value));
228 : }
229 22 : logTargetDistGrid().setMinToZero();
230 22 : }
231 :
232 :
233 1 : void TD_LinearCombination::linkVesBias(VesBias* vesbias_pntr_in) {
234 1 : TargetDistribution::linkVesBias(vesbias_pntr_in);
235 5 : for(unsigned int i=0; i<ndist_; i++) {
236 4 : distribution_pntrs_[i]->linkVesBias(vesbias_pntr_in);
237 : }
238 1 : }
239 :
240 :
241 0 : void TD_LinearCombination::linkAction(Action* action_pntr_in) {
242 0 : TargetDistribution::linkAction(action_pntr_in);
243 0 : for(unsigned int i=0; i<ndist_; i++) {
244 0 : distribution_pntrs_[i]->linkAction(action_pntr_in);
245 : }
246 0 : }
247 :
248 :
249 0 : void TD_LinearCombination::linkBiasGrid(Grid* bias_grid_pntr_in) {
250 0 : TargetDistribution::linkBiasGrid(bias_grid_pntr_in);
251 0 : for(unsigned int i=0; i<ndist_; i++) {
252 0 : distribution_pntrs_[i]->linkBiasGrid(bias_grid_pntr_in);
253 : }
254 0 : }
255 :
256 :
257 0 : void TD_LinearCombination::linkBiasWithoutCutoffGrid(Grid* bias_withoutcutoff_grid_pntr_in) {
258 0 : TargetDistribution::linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in);
259 0 : for(unsigned int i=0; i<ndist_; i++) {
260 0 : distribution_pntrs_[i]->linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in);
261 : }
262 0 : }
263 :
264 :
265 1 : void TD_LinearCombination::linkFesGrid(Grid* fes_grid_pntr_in) {
266 1 : TargetDistribution::linkFesGrid(fes_grid_pntr_in);
267 5 : for(unsigned int i=0; i<ndist_; i++) {
268 4 : distribution_pntrs_[i]->linkFesGrid(fes_grid_pntr_in);
269 : }
270 1 : }
271 :
272 :
273 : }
274 4839 : }
|