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