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 : 27 : #include "core/ActionRegister.h" 28 : #include "core/ActionSet.h" 29 : #include "core/PlumedMain.h" 30 : #include "tools/Grid.h" 31 : 32 : #include "GridIntegrationWeights.h" 33 : 34 : 35 : namespace PLMD { 36 : 37 : // class Grid; 38 : class Action; 39 : 40 : namespace ves { 41 : 42 : //+PLUMEDOC VES_TARGETDIST TD_PRODUCT_COMBINATION 43 : /* 44 : Target distribution given by product combination of distributions (static or dynamic). 45 : 46 : Employ a target distribution that is a product combination of the other 47 : distributions, defined as 48 : 49 : $$ 50 : p(\mathbf{s}) = 51 : \frac{\prod_{i} p_{i}(\mathbf{s})} 52 : {\int d \mathbf{s} \prod_{i} p_{i}(\mathbf{s})} 53 : $$ 54 : 55 : where the distributions $p_{i}(\mathbf{s})$ are in full dimensional space 56 : of the arguments used. 57 : 58 : Note the difference between this target distribution and the one defined in 59 : [TD_PRODUCT_DISTRIBUTION](TD_PRODUCT_DISTRIBUTION.md). Here we have a non-separable distribution given 60 : as a product of distribution $p_{i}(\mathbf{s})$ which are in full dimensional 61 : space of the arguments used. 62 : 63 : The labels of the distributions $p_{i}(\mathbf{s})$ to be used in the 64 : product combination are given in the DISTRIBUTIONS keyword. 65 : 66 : The target distribution resulting from the product combination will be 67 : automatically normalized. Therefore, the product combination needs to 68 : be a proper distribution that is non-negative and that can be normalized. The 69 : code will perform checks to make sure that this is indeed the case. 70 : 71 : The product combination will be a dynamic target distribution if one or more 72 : of the distributions used is a dynamic distribution. Otherwise it will be a 73 : static distribution. 74 : 75 : ## Examples 76 : 77 : In the following example the overall interval on which the 78 : target distribution is defined is from 0.23 to 0.8. 79 : We employ a product combination of a well-tempered 80 : distribution and a uniform distribution that decays to 81 : zero at 0.6. This results in a target distribution that 82 : is well-tempered from 0.23 to 0.6 and then decays to zero. 83 : In other words, we cut off the tail of the well-tempered 84 : distribution at 0.6 85 : 86 : ```plumed 87 : td_welltemp: TD_WELLTEMPERED BIASFACTOR=5 88 : td_uniform: TD_UNIFORM MINIMA=0.23 MAXIMA=0.6 SIGMA_MAXIMA=0.05 89 : td_combination: TD_PRODUCT_COMBINATION DISTRIBUTIONS=td_uniform,td_welltemp 90 : ``` 91 : 92 : In the following example the overall interval on which the 93 : target distribution is defined is from -4 to 4. 94 : We employ a product of a Gaussian distribution with two centers 95 : and distribution that is uniform on the interval -3 to 3 and 96 : then smoothly decays to zero outside that interval. 97 : The overall effect will then be to cut off the tails of the 98 : Gaussian distribution 99 : 100 : ```plumed 101 : TD_GAUSSIAN ... 102 : CENTER1=-2.9 SIGMA1=1.0 103 : CENTER2=+2.9 SIGMA2=0.4 104 : LABEL=td_gauss 105 : ... TD_GAUSSIAN 106 : 107 : TD_UNIFORM ... 108 : MINIMA=-3.0 SIGMA_MINIMA=0.20 109 : MAXIMA=+3.0 SIGMA_MAXIMA=0.15 110 : LABEL=td_uni 111 : ... TD_UNIFORM 112 : 113 : td_pc: TD_PRODUCT_COMBINATION DISTRIBUTIONS=td_gauss,td_uni 114 : ``` 115 : 116 : */ 117 : //+ENDPLUMEDOC 118 : 119 : class VesBias; 120 : 121 : class TD_ProductCombination: public TargetDistribution { 122 : private: 123 : std::vector<TargetDistribution*> distribution_pntrs_; 124 : std::vector<Grid*> grid_pntrs_; 125 : unsigned int ndist_; 126 : void setupAdditionalGrids(const std::vector<Value*>&, const std::vector<std::string>&, const std::vector<std::string>&, const std::vector<unsigned int>&) override; 127 : public: 128 : static void registerKeywords(Keywords&); 129 : explicit TD_ProductCombination(const ActionOptions& ao); 130 : void updateGrid() override; 131 : double getValue(const std::vector<double>&) const override; 132 : // 133 : void linkVesBias(VesBias*) override; 134 : void linkAction(Action*) override; 135 : // 136 : void linkBiasGrid(Grid*) override; 137 : void linkBiasWithoutCutoffGrid(Grid*) override; 138 : void linkFesGrid(Grid*) override; 139 : // 140 : }; 141 : 142 : 143 : PLUMED_REGISTER_ACTION(TD_ProductCombination,"TD_PRODUCT_COMBINATION") 144 : 145 : 146 6 : void TD_ProductCombination::registerKeywords(Keywords& keys) { 147 6 : TargetDistribution::registerKeywords(keys); 148 6 : keys.add("compulsory","DISTRIBUTIONS","The labels of the target distribution actions to be used in the product combination."); 149 6 : keys.use("WELLTEMPERED_FACTOR"); 150 6 : keys.use("SHIFT_TO_ZERO"); 151 6 : } 152 : 153 : 154 4 : TD_ProductCombination::TD_ProductCombination(const ActionOptions& ao): 155 : PLUMED_VES_TARGETDISTRIBUTION_INIT(ao), 156 8 : distribution_pntrs_(0), 157 4 : grid_pntrs_(0), 158 8 : ndist_(0) { 159 : std::vector<std::string> targetdist_labels; 160 4 : parseVector("DISTRIBUTIONS",targetdist_labels); 161 : 162 4 : std::string error_msg = ""; 163 8 : distribution_pntrs_ = VesTools::getPointersFromLabels<TargetDistribution*>(targetdist_labels,plumed.getActionSet(),error_msg); 164 4 : if(error_msg.size()>0) { 165 0 : plumed_merror("Error in keyword DISTRIBUTIONS of "+getName()+": "+error_msg); 166 : } 167 : 168 12 : for(unsigned int i=0; i<distribution_pntrs_.size(); i++) { 169 8 : if(distribution_pntrs_[i]->isDynamic()) { 170 : setDynamic(); 171 : } 172 8 : if(distribution_pntrs_[i]->fesGridNeeded()) { 173 : setFesGridNeeded(); 174 : } 175 8 : if(distribution_pntrs_[i]->biasGridNeeded()) { 176 : setBiasGridNeeded(); 177 : } 178 : } 179 : 180 4 : ndist_ = distribution_pntrs_.size(); 181 4 : grid_pntrs_.assign(ndist_,NULL); 182 4 : if(ndist_==0) { 183 0 : plumed_merror(getName()+ ": no distributions are given."); 184 : } 185 4 : if(ndist_==1) { 186 0 : plumed_merror(getName()+ ": giving only one distribution does not make sense."); 187 : } 188 : // 189 4 : checkRead(); 190 4 : } 191 : 192 : 193 0 : double TD_ProductCombination::getValue(const std::vector<double>& argument) const { 194 0 : plumed_merror("getValue not implemented for TD_ProductCombination"); 195 : return 0.0; 196 : } 197 : 198 : 199 4 : void TD_ProductCombination::setupAdditionalGrids(const std::vector<Value*>& arguments, const std::vector<std::string>& min, const std::vector<std::string>& max, const std::vector<unsigned int>& nbins) { 200 12 : for(unsigned int i=0; i<ndist_; i++) { 201 8 : distribution_pntrs_[i]->setupGrids(arguments,min,max,nbins); 202 8 : if(distribution_pntrs_[i]->getDimension()!=this->getDimension()) { 203 0 : plumed_merror(getName() + ": all target distribution must have the same dimension"); 204 : } 205 8 : grid_pntrs_[i]=distribution_pntrs_[i]->getTargetDistGridPntr(); 206 : } 207 4 : } 208 : 209 : 210 14 : void TD_ProductCombination::updateGrid() { 211 42 : for(unsigned int i=0; i<ndist_; i++) { 212 28 : distribution_pntrs_[i]->updateTargetDist(); 213 : } 214 28 : std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(getTargetDistGridPntr()); 215 : double norm = 0.0; 216 11717 : for(Grid::index_t l=0; l<targetDistGrid().getSize(); l++) { 217 : double value = 1.0; 218 35109 : for(unsigned int i=0; i<ndist_; i++) { 219 23406 : value *= grid_pntrs_[i]->getValue(l); 220 : } 221 11703 : if(value<0.0 && !isTargetDistGridShiftedToZero()) { 222 0 : plumed_merror(getName()+": The target distribution function gives negative values. You should change the definition of the target distribution to avoid this. You can also use the SHIFT_TO_ZERO keyword to avoid this problem."); 223 : } 224 11703 : norm += integration_weights[l]*value; 225 11703 : targetDistGrid().setValue(l,value); 226 11703 : logTargetDistGrid().setValue(l,-std::log(value)); 227 : } 228 : 229 14 : if(norm>0.0) { 230 14 : targetDistGrid().scaleAllValuesAndDerivatives(1.0/norm); 231 0 : } else if(!isTargetDistGridShiftedToZero()) { 232 0 : plumed_merror(getName()+": The target distribution function cannot be normalized proberly. You should change the definition of the target distribution to avoid this. You can also use the SHIFT_TO_ZERO keyword to avoid this problem."); 233 : } 234 14 : logTargetDistGrid().setMinToZero(); 235 14 : } 236 : 237 : 238 1 : void TD_ProductCombination::linkVesBias(VesBias* vesbias_pntr_in) { 239 1 : TargetDistribution::linkVesBias(vesbias_pntr_in); 240 3 : for(unsigned int i=0; i<ndist_; i++) { 241 2 : distribution_pntrs_[i]->linkVesBias(vesbias_pntr_in); 242 : } 243 1 : } 244 : 245 : 246 0 : void TD_ProductCombination::linkAction(Action* action_pntr_in) { 247 0 : TargetDistribution::linkAction(action_pntr_in); 248 0 : for(unsigned int i=0; i<ndist_; i++) { 249 0 : distribution_pntrs_[i]->linkAction(action_pntr_in); 250 : } 251 0 : } 252 : 253 : 254 0 : void TD_ProductCombination::linkBiasGrid(Grid* bias_grid_pntr_in) { 255 0 : TargetDistribution::linkBiasGrid(bias_grid_pntr_in); 256 0 : for(unsigned int i=0; i<ndist_; i++) { 257 0 : distribution_pntrs_[i]->linkBiasGrid(bias_grid_pntr_in); 258 : } 259 0 : } 260 : 261 : 262 0 : void TD_ProductCombination::linkBiasWithoutCutoffGrid(Grid* bias_withoutcutoff_grid_pntr_in) { 263 0 : TargetDistribution::linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in); 264 0 : for(unsigned int i=0; i<ndist_; i++) { 265 0 : distribution_pntrs_[i]->linkBiasWithoutCutoffGrid(bias_withoutcutoff_grid_pntr_in); 266 : } 267 0 : } 268 : 269 : 270 1 : void TD_ProductCombination::linkFesGrid(Grid* fes_grid_pntr_in) { 271 1 : TargetDistribution::linkFesGrid(fes_grid_pntr_in); 272 3 : for(unsigned int i=0; i<ndist_; i++) { 273 2 : distribution_pntrs_[i]->linkFesGrid(fes_grid_pntr_in); 274 : } 275 1 : } 276 : 277 : 278 : } 279 : }