Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2016-2021 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 : namespace PLMD { 32 : namespace ves { 33 : 34 : //+PLUMEDOC VES_TARGETDIST TD_PRODUCT_DISTRIBUTION 35 : /* 36 : Target distribution given by a separable product of one-dimensional distributions (static or dynamic). 37 : 38 : Employ a target distribution that is a separable product 39 : of one-dimensional distributions, defined as 40 : 41 : $$ 42 : p(\mathbf{s}) = 43 : \prod_{k}^{d} p_{k}(s_{k}) 44 : $$ 45 : 46 : where $d$ is the number of arguments used and $p_{k}(s_{k})$ is the 47 : one-dimensional distribution corresponding to the $k$-th argument. 48 : 49 : Note the difference between this target distribution and the one defined in 50 : [TD_PRODUCT_COMBINATION](TD_PRODUCT_COMBINATION.md). Here we have a separable distribution given as a 51 : product of one-dimensional distribution $p_{k}(s_{k})$. 52 : 53 : The labels of the one-dimensional distributions $p_{k}(s_{k})$ to be 54 : used in the product distribution are given in the DISTRIBUTIONS keyword. 55 : Note that the order of the labels is very important. 56 : 57 : It is assumed that all the distributions to be used in the product distribution 58 : are normalized. If that is not the case you need to 59 : normalize the distributions by using the NORMALIZE keyword. 60 : Here it does not matter if you normalize each distribution separately 61 : or the overall product, it will give the same results. 62 : 63 : The product distribution will be a dynamic target distribution if one or more 64 : of the distributions used is a dynamic distribution. Otherwise it will be a 65 : static distribution. 66 : 67 : ## Examples 68 : 69 : In the following example we employ a uniform distribution for 70 : argument 1 and a Gaussian distribution for argument 2. 71 : 72 : ```plumed 73 : target_uniform: TD_UNIFORM 74 : 75 : target_Gaussian: TD_GAUSSIAN CENTER1=-2.0 SIGMA1=0.5 76 : 77 : td_pd: TD_PRODUCT_DISTRIBUTION DISTRIBUTIONS=target_uniform,target_Gaussian 78 : ``` 79 : 80 : Note that order of the labels is important, using DISTRIBUTIONS=target_Gaussian,target_uniform 81 : would mean that we would employ a Gaussian distribution for argument 1 and a uniform 82 : distribution for argument 2, which would lead to completely different results. 83 : 84 : */ 85 : //+ENDPLUMEDOC 86 : 87 : class TD_ProductDistribution: public TargetDistribution { 88 : private: 89 : std::vector<TargetDistribution*> distribution_pntrs_; 90 : std::vector<Grid*> grid_pntrs_; 91 : unsigned int ndist_; 92 : void setupAdditionalGrids(const std::vector<Value*>&, const std::vector<std::string>&, const std::vector<std::string>&, const std::vector<unsigned int>&) override; 93 : public: 94 : static void registerKeywords(Keywords&); 95 : explicit TD_ProductDistribution(const ActionOptions& ao); 96 : void updateGrid() override; 97 : double getValue(const std::vector<double>&) const override; 98 : // 99 : void linkVesBias(VesBias*) override; 100 : void linkAction(Action*) override; 101 : void linkBiasGrid(Grid*) override; 102 : void linkBiasWithoutCutoffGrid(Grid*) override; 103 : void linkFesGrid(Grid*) override; 104 : }; 105 : 106 : 107 : PLUMED_REGISTER_ACTION(TD_ProductDistribution,"TD_PRODUCT_DISTRIBUTION") 108 : 109 : 110 17 : void TD_ProductDistribution::registerKeywords(Keywords& keys) { 111 17 : TargetDistribution::registerKeywords(keys); 112 17 : keys.add("compulsory","DISTRIBUTIONS","Labels of the one-dimensional target distribution actions for each argument to be used in the product distribution. Note that order of the labels is important."); 113 17 : keys.use("WELLTEMPERED_FACTOR"); 114 17 : keys.use("SHIFT_TO_ZERO"); 115 17 : keys.use("NORMALIZE"); 116 17 : } 117 : 118 : 119 15 : TD_ProductDistribution::TD_ProductDistribution(const ActionOptions& ao): 120 : PLUMED_VES_TARGETDISTRIBUTION_INIT(ao), 121 30 : distribution_pntrs_(0), 122 15 : grid_pntrs_(0), 123 30 : ndist_(0) { 124 : std::vector<std::string> targetdist_labels; 125 15 : parseVector("DISTRIBUTIONS",targetdist_labels); 126 : 127 15 : std::string error_msg = ""; 128 30 : distribution_pntrs_ = VesTools::getPointersFromLabels<TargetDistribution*>(targetdist_labels,plumed.getActionSet(),error_msg); 129 15 : if(error_msg.size()>0) { 130 0 : plumed_merror("Error in keyword DISTRIBUTIONS of "+getName()+": "+error_msg); 131 : } 132 : 133 45 : for(unsigned int i=0; i<distribution_pntrs_.size(); i++) { 134 30 : if(distribution_pntrs_[i]->isDynamic()) { 135 : setDynamic(); 136 : } 137 30 : if(distribution_pntrs_[i]->fesGridNeeded()) { 138 : setFesGridNeeded(); 139 : } 140 30 : if(distribution_pntrs_[i]->biasGridNeeded()) { 141 : setBiasGridNeeded(); 142 : } 143 : } 144 : 145 15 : ndist_ = distribution_pntrs_.size(); 146 15 : grid_pntrs_.assign(ndist_,NULL); 147 15 : setDimension(ndist_); 148 : 149 15 : checkRead(); 150 15 : } 151 : 152 : 153 0 : double TD_ProductDistribution::getValue(const std::vector<double>& argument) const { 154 0 : plumed_merror("getValue not implemented for TD_ProductDistribution"); 155 : return 0.0; 156 : } 157 : 158 : 159 15 : void TD_ProductDistribution::setupAdditionalGrids(const std::vector<Value*>& arguments, const std::vector<std::string>& min, const std::vector<std::string>& max, const std::vector<unsigned int>& nbins) { 160 45 : for(unsigned int i=0; i<ndist_; i++) { 161 30 : std::vector<Value*> arg1d(1); 162 30 : std::vector<std::string> min1d(1); 163 30 : std::vector<std::string> max1d(1); 164 30 : std::vector<unsigned int> nbins1d(1); 165 30 : arg1d[0]=arguments[i]; 166 : min1d[0]=min[i]; 167 : max1d[0]=max[i]; 168 30 : nbins1d[0]=nbins[i]; 169 30 : distribution_pntrs_[i]->setupGrids(arg1d,min1d,max1d,nbins1d); 170 30 : grid_pntrs_[i]=distribution_pntrs_[i]->getTargetDistGridPntr(); 171 30 : if(distribution_pntrs_[i]->getDimension()!=1 || grid_pntrs_[i]->getDimension()!=1) { 172 0 : plumed_merror(getName() + ": all target distributions must be one dimensional"); 173 : } 174 30 : } 175 15 : } 176 : 177 : 178 15 : void TD_ProductDistribution::updateGrid() { 179 45 : for(unsigned int i=0; i<ndist_; i++) { 180 30 : distribution_pntrs_[i]->updateTargetDist(); 181 : } 182 153030 : for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) { 183 153015 : std::vector<unsigned int> indices = targetDistGrid().getIndices(l); 184 : double value = 1.0; 185 459045 : for(unsigned int i=0; i<ndist_; i++) { 186 306030 : value *= grid_pntrs_[i]->getValue(indices[i]); 187 : } 188 153015 : targetDistGrid().setValue(l,value); 189 153015 : logTargetDistGrid().setValue(l,-std::log(value)); 190 : } 191 15 : logTargetDistGrid().setMinToZero(); 192 15 : } 193 : 194 : 195 0 : void TD_ProductDistribution::linkVesBias(VesBias* vesbias_pntr_in) { 196 0 : TargetDistribution::linkVesBias(vesbias_pntr_in); 197 0 : for(unsigned int i=0; i<ndist_; i++) { 198 0 : distribution_pntrs_[i]->linkVesBias(vesbias_pntr_in); 199 : } 200 0 : } 201 : 202 : 203 0 : void TD_ProductDistribution::linkAction(Action* action_pntr_in) { 204 0 : TargetDistribution::linkAction(action_pntr_in); 205 0 : for(unsigned int i=0; i<ndist_; i++) { 206 0 : distribution_pntrs_[i]->linkAction(action_pntr_in); 207 : } 208 0 : } 209 : 210 : 211 0 : void TD_ProductDistribution::linkBiasGrid(Grid* bias_grid_pntr_in) { 212 0 : TargetDistribution::linkBiasGrid(bias_grid_pntr_in); 213 0 : for(unsigned int i=0; i<ndist_; i++) { 214 0 : distribution_pntrs_[i]->linkBiasGrid(bias_grid_pntr_in); 215 : } 216 0 : } 217 : 218 : 219 0 : void TD_ProductDistribution::linkBiasWithoutCutoffGrid(Grid* bias_withoutcutoff_grid_pntr_in) { 220 0 : TargetDistribution::linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in); 221 0 : for(unsigned int i=0; i<ndist_; i++) { 222 0 : distribution_pntrs_[i]->linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in); 223 : } 224 0 : } 225 : 226 : 227 0 : void TD_ProductDistribution::linkFesGrid(Grid* fes_grid_pntr_in) { 228 0 : TargetDistribution::linkFesGrid(fes_grid_pntr_in); 229 0 : for(unsigned int i=0; i<ndist_; i++) { 230 0 : distribution_pntrs_[i]->linkFesGrid(fes_grid_pntr_in); 231 : } 232 0 : } 233 : 234 : 235 : } 236 : }