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