LCOV - code coverage report
Current view: top level - ves - TargetDistribution.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 190 219 86.8 %
Date: 2019-08-13 10:39:37 Functions: 22 26 84.6 %

          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 "TargetDistModifer.h"
      25             : 
      26             : #include "VesBias.h"
      27             : #include "GridIntegrationWeights.h"
      28             : #include "VesTools.h"
      29             : 
      30             : #include "core/Value.h"
      31             : #include "tools/Grid.h"
      32             : #include "tools/File.h"
      33             : #include "tools/Keywords.h"
      34             : 
      35             : #include "GridProjWeights.h"
      36             : 
      37             : namespace PLMD {
      38             : namespace ves {
      39             : 
      40         356 : void TargetDistribution::registerKeywords( Keywords& keys ) {
      41         356 :   Action::registerKeywords(keys);
      42         356 :   keys.reserve("optional","WELLTEMPERED_FACTOR","Broaden the target distribution such that it is taken as [p(s)]^(1/\\f$\\gamma\\f$) where \\f$\\gamma\\f$ is the well tempered factor given here. If this option is active the distribution will be automatically normalized.");
      43         356 :   keys.reserveFlag("SHIFT_TO_ZERO",false,"Shift the minimum value of the target distribution to zero. This can for example be used to avoid negative values in the target distribution. If this option is active the distribution will be automatically normalized.");
      44         356 :   keys.reserveFlag("NORMALIZE",false,"Renormalized the target distribution over the intervals on which it is defined to make sure that it is properly normalized to 1. In most cases this should not be needed as the target distributions should be normalized. The code will issue a warning (but still run) if this is needed for some reason.");
      45         356 : }
      46             : 
      47             : 
      48         341 : TargetDistribution::TargetDistribution(const ActionOptions&ao):
      49             :   Action(ao),
      50             :   type_(static_targetdist),
      51             :   force_normalization_(false),
      52             :   check_normalization_(true),
      53             :   check_nonnegative_(true),
      54             :   check_nan_inf_(false),
      55             :   shift_targetdist_to_zero_(false),
      56             :   dimension_(0),
      57             :   grid_args_(0),
      58             :   targetdist_grid_pntr_(NULL),
      59             :   log_targetdist_grid_pntr_(NULL),
      60             :   targetdist_modifer_pntrs_(0),
      61             :   action_pntr_(NULL),
      62             :   vesbias_pntr_(NULL),
      63             :   needs_bias_grid_(false),
      64             :   needs_bias_withoutcutoff_grid_(false),
      65             :   needs_fes_grid_(false),
      66             :   bias_grid_pntr_(NULL),
      67             :   bias_withoutcutoff_grid_pntr_(NULL),
      68             :   fes_grid_pntr_(NULL),
      69             :   static_grid_calculated(false),
      70             :   allow_bias_cutoff_(true),
      71         341 :   bias_cutoff_active_(false)
      72             : {
      73             :   //
      74         341 :   if(keywords.exists("WELLTEMPERED_FACTOR")) {
      75         253 :     double welltempered_factor=0.0;
      76         253 :     parse("WELLTEMPERED_FACTOR",welltempered_factor);
      77             :     //
      78         253 :     if(welltempered_factor>0.0) {
      79           6 :       TargetDistModifer* pntr = new WellTemperedModifer(welltempered_factor);
      80           6 :       targetdist_modifer_pntrs_.push_back(pntr);
      81             :     }
      82         247 :     else if(welltempered_factor<0.0) {
      83           0 :       plumed_merror(getName()+": negative value in WELLTEMPERED_FACTOR does not make sense");
      84             :     }
      85             :   }
      86             :   //
      87         341 :   if(keywords.exists("SHIFT_TO_ZERO")) {
      88         241 :     parseFlag("SHIFT_TO_ZERO",shift_targetdist_to_zero_);
      89         241 :     if(shift_targetdist_to_zero_) {
      90           3 :       if(bias_cutoff_active_) {plumed_merror(getName()+": using SHIFT_TO_ZERO with bias cutoff is not allowed.");}
      91           3 :       check_nonnegative_=false;
      92             :     }
      93             :   }
      94             :   //
      95         341 :   if(keywords.exists("NORMALIZE")) {
      96         215 :     bool force_normalization=false;
      97         215 :     parseFlag("NORMALIZE",force_normalization);
      98         215 :     if(force_normalization) {
      99           3 :       if(shift_targetdist_to_zero_) {plumed_merror(getName()+" with label "+getLabel()+": using NORMALIZE with SHIFT_TO_ZERO is not needed, the target distribution will be automatically normalized.");}
     100           3 :       setForcedNormalization();
     101             :     }
     102             :   }
     103             : 
     104         341 : }
     105             : 
     106             : 
     107         682 : TargetDistribution::~TargetDistribution() {
     108         341 :   if(targetdist_grid_pntr_!=NULL) {
     109         341 :     delete targetdist_grid_pntr_;
     110             :   }
     111         341 :   if(log_targetdist_grid_pntr_!=NULL) {
     112         341 :     delete log_targetdist_grid_pntr_;
     113             :   }
     114         347 :   for(unsigned int i=0; i<targetdist_modifer_pntrs_.size(); i++) {
     115           6 :     delete targetdist_modifer_pntrs_[i];
     116             :   }
     117         341 : }
     118             : 
     119             : 
     120         341 : double TargetDistribution::getBeta() const {
     121         341 :   plumed_massert(vesbias_pntr_!=NULL,"The VesBias has to be linked to use TargetDistribution::getBeta()");
     122         341 :   return vesbias_pntr_->getBeta();
     123             : }
     124             : 
     125             : 
     126         354 : void TargetDistribution::setDimension(const unsigned int dimension) {
     127         354 :   plumed_massert(dimension_==0,"setDimension: the dimension of the target distribution has already been set");
     128         354 :   dimension_=dimension;
     129         354 : }
     130             : 
     131             : 
     132          43 : void TargetDistribution::linkVesBias(VesBias* vesbias_pntr_in) {
     133          43 :   vesbias_pntr_ = vesbias_pntr_in;
     134          43 :   action_pntr_ = static_cast<Action*>(vesbias_pntr_in);
     135          43 : }
     136             : 
     137             : 
     138           0 : void TargetDistribution::linkAction(Action* action_pntr_in) {
     139           0 :   action_pntr_ = action_pntr_in;
     140           0 : }
     141             : 
     142             : 
     143           0 : void TargetDistribution::linkBiasGrid(Grid* bias_grid_pntr_in) {
     144           0 :   bias_grid_pntr_ = bias_grid_pntr_in;
     145           0 : }
     146             : 
     147             : 
     148           3 : void TargetDistribution::linkBiasWithoutCutoffGrid(Grid* bias_withoutcutoff_grid_pntr_in) {
     149           3 :   bias_withoutcutoff_grid_pntr_ = bias_withoutcutoff_grid_pntr_in;
     150           3 : }
     151             : 
     152             : 
     153          34 : void TargetDistribution::linkFesGrid(Grid* fes_grid_pntr_in) {
     154          34 :   fes_grid_pntr_ = fes_grid_pntr_in;
     155          34 : }
     156             : 
     157             : 
     158           3 : void TargetDistribution::setupBiasCutoff() {
     159           3 :   if(!allow_bias_cutoff_) {
     160           0 :     plumed_merror(getName()+" with label "+getLabel()+": this target distribution does not support a bias cutoff");
     161             :   }
     162           3 :   if(targetdist_modifer_pntrs_.size()>0) {
     163           0 :     plumed_merror(getName()+" with label "+getLabel()+": using a bias cutoff with a target distribution modifer like WELLTEMPERED_FACTOR is not allowed");
     164             :   }
     165           3 :   bias_cutoff_active_=true;
     166           3 :   setBiasWithoutCutoffGridNeeded();
     167           3 :   setDynamic();
     168             :   // as the p(s) includes the derivative factor so normalization
     169             :   // check can be misleading
     170           3 :   check_normalization_=false;
     171           3 :   force_normalization_=false;
     172           3 : }
     173             : 
     174             : 
     175         341 : void TargetDistribution::setupGrids(const std::vector<Value*>& arguments, const std::vector<std::string>& min, const std::vector<std::string>& max, const std::vector<unsigned int>& nbins) {
     176         341 :   if(getDimension()==0) {
     177          72 :     setDimension(arguments.size());
     178             :   }
     179         341 :   unsigned int dimension = getDimension();
     180         341 :   plumed_massert(arguments.size()==dimension,"TargetDistribution::setupGrids: mismatch between number of values given for grid parameters");
     181         341 :   plumed_massert(min.size()==dimension,"TargetDistribution::setupGrids: mismatch between number of values given for grid parameters");
     182         341 :   plumed_massert(max.size()==dimension,"TargetDistribution::setupGrids: mismatch between number of values given for grid parameters");
     183         341 :   plumed_massert(nbins.size()==dimension,"TargetDistribution::setupGrids: mismatch between number of values given for grid parameters");
     184         341 :   grid_args_=arguments;
     185         341 :   targetdist_grid_pntr_ =     new Grid("targetdist",arguments,min,max,nbins,false,false);
     186         341 :   log_targetdist_grid_pntr_ = new Grid("log_targetdist",arguments,min,max,nbins,false,false);
     187         341 :   setupAdditionalGrids(arguments,min,max,nbins);
     188         341 : }
     189             : 
     190             : 
     191         308 : void TargetDistribution::calculateStaticDistributionGrid() {
     192         616 :   if(static_grid_calculated && !bias_cutoff_active_) {return;}
     193             :   // plumed_massert(isStatic(),"this should only be used for static distributions");
     194         288 :   plumed_massert(targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     195         288 :   plumed_massert(log_targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     196      449855 :   for(Grid::index_t l=0; l<targetdist_grid_pntr_->getSize(); l++)
     197             :   {
     198      449567 :     std::vector<double> argument = targetdist_grid_pntr_->getPoint(l);
     199      449567 :     double value = getValue(argument);
     200      449567 :     targetdist_grid_pntr_->setValue(l,value);
     201      449567 :     log_targetdist_grid_pntr_->setValue(l,-std::log(value));
     202      449567 :   }
     203         288 :   log_targetdist_grid_pntr_->setMinToZero();
     204         288 :   static_grid_calculated = true;
     205             : }
     206             : 
     207             : 
     208         801 : double TargetDistribution::integrateGrid(const Grid* grid_pntr) {
     209         801 :   std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(grid_pntr);
     210         801 :   double sum = 0.0;
     211     2417251 :   for(Grid::index_t l=0; l<grid_pntr->getSize(); l++) {
     212     2416450 :     sum += integration_weights[l]*grid_pntr->getValue(l);
     213             :   }
     214         801 :   return sum;
     215             : }
     216             : 
     217             : 
     218          78 : double TargetDistribution::normalizeGrid(Grid* grid_pntr) {
     219          78 :   double normalization = TargetDistribution::integrateGrid(grid_pntr);
     220          78 :   grid_pntr->scaleAllValuesAndDerivatives(1.0/normalization);
     221          78 :   return normalization;
     222             : }
     223             : 
     224             : 
     225          22 : Grid TargetDistribution::getMarginalDistributionGrid(Grid* grid_pntr, const std::vector<std::string>& args) {
     226          22 :   plumed_massert(grid_pntr->getDimension()>1,"doesn't make sense calculating the marginal distribution for a one-dimensional distribution");
     227          22 :   plumed_massert(args.size()<grid_pntr->getDimension(),"the number of arguments for the marginal distribution should be less than the dimension of the full distribution");
     228             :   //
     229          22 :   std::vector<std::string> argnames = grid_pntr->getArgNames();
     230          44 :   std::vector<unsigned int> args_index(0);
     231          66 :   for(unsigned int i=0; i<argnames.size(); i++) {
     232          88 :     for(unsigned int l=0; l<args.size(); l++) {
     233          44 :       if(argnames[i]==args[l]) {args_index.push_back(i);}
     234             :     }
     235             :   }
     236          22 :   plumed_massert(args.size()==args_index.size(),"getMarginalDistributionGrid: problem with the arguments of the marginal");
     237             :   //
     238          22 :   MarginalWeight* Pw = new MarginalWeight();
     239          22 :   Grid proj_grid = grid_pntr->project(args,Pw);
     240          22 :   delete Pw;
     241             :   //
     242             :   // scale with the bin volume used for the integral such that the
     243             :   // marginals are proberly normalized to 1.0
     244          22 :   double intVol = grid_pntr->getBinVolume();
     245          44 :   for(unsigned int l=0; l<args_index.size(); l++) {
     246          22 :     intVol/=grid_pntr->getDx()[args_index[l]];
     247             :   }
     248          22 :   proj_grid.scaleAllValuesAndDerivatives(intVol);
     249             :   //
     250          44 :   return proj_grid;
     251             : }
     252             : 
     253             : 
     254           8 : Grid TargetDistribution::getMarginal(const std::vector<std::string>& args) {
     255           8 :   return TargetDistribution::getMarginalDistributionGrid(targetdist_grid_pntr_,args);
     256             : }
     257             : 
     258             : 
     259         702 : void TargetDistribution::updateTargetDist() {
     260             :   //
     261         702 :   updateGrid();
     262             :   //
     263         708 :   for(unsigned int i=0; i<targetdist_modifer_pntrs_.size(); i++) {
     264           6 :     applyTargetDistModiferToGrid(targetdist_modifer_pntrs_[i]);
     265             :   }
     266             :   //
     267         702 :   if(bias_cutoff_active_) {updateBiasCutoffForTargetDistGrid();}
     268             :   //
     269         702 :   if(shift_targetdist_to_zero_ && !(bias_cutoff_active_)) {setMinimumOfTargetDistGridToZero();}
     270         702 :   if(force_normalization_ && !(bias_cutoff_active_) ) {normalizeTargetDistGrid();}
     271             :   //
     272             :   // if(check_normalization_ && !force_normalization_ && !shift_targetdist_to_zero_){
     273         702 :   if(check_normalization_ && !(bias_cutoff_active_)) {
     274         603 :     double normalization = integrateGrid(targetdist_grid_pntr_);
     275         603 :     const double normalization_thrshold = 0.1;
     276         603 :     if(normalization < 1.0-normalization_thrshold || normalization > 1.0+normalization_thrshold) {
     277           3 :       std::string norm_str; Tools::convert(normalization,norm_str);
     278           6 :       std::string msg = "the target distribution grid is not proberly normalized, integrating over the grid gives: " + norm_str + " - You can avoid this problem by using the NORMALIZE keyword";
     279           6 :       warning(msg);
     280             :     }
     281             :   }
     282             :   //
     283         702 :   if(check_nonnegative_) {
     284         699 :     const double nonnegative_thrshold = -0.02;
     285         699 :     double grid_min_value = targetdist_grid_pntr_->getMinValue();
     286         699 :     if(grid_min_value<nonnegative_thrshold) {
     287           0 :       std::string grid_min_value_str; Tools::convert(grid_min_value,grid_min_value_str);
     288           0 :       std::string msg = "the target distribution grid has negative values, the lowest value is: " + grid_min_value_str + " - You can avoid this problem by using the SHIFT_TO_ZERO keyword";
     289           0 :       warning(msg);
     290             :     }
     291             :   }
     292             :   //
     293         702 :   if(check_nan_inf_) {checkNanAndInf();}
     294             :   //
     295         702 : }
     296             : 
     297             : 
     298          24 : void TargetDistribution::updateBiasCutoffForTargetDistGrid() {
     299          24 :   plumed_massert(vesbias_pntr_!=NULL,"The VesBias has to be linked to use updateBiasCutoffForTargetDistGrid()");
     300          24 :   plumed_massert(vesbias_pntr_->biasCutoffActive(),"updateBiasCutoffForTargetDistGrid() should only be used if the bias cutoff is active");
     301             :   // plumed_massert(targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     302             :   // plumed_massert(log_targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     303          24 :   plumed_massert(getBiasWithoutCutoffGridPntr()!=NULL,"the bias without cutoff grid has to be linked");
     304             :   //
     305          24 :   std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(targetdist_grid_pntr_);
     306          24 :   double norm = 0.0;
     307        2624 :   for(Grid::index_t l=0; l<targetdist_grid_pntr_->getSize(); l++)
     308             :   {
     309        2600 :     double value = targetdist_grid_pntr_->getValue(l);
     310        2600 :     double bias = getBiasWithoutCutoffGridPntr()->getValue(l);
     311        2600 :     double deriv_factor_swf = 0.0;
     312        2600 :     double swf = vesbias_pntr_->getBiasCutoffSwitchingFunction(bias,deriv_factor_swf);
     313             :     // this comes from the p(s)
     314        2600 :     value *= swf;
     315        2600 :     norm += integration_weights[l]*value;
     316             :     // this comes from the derivative of V(s)
     317        2600 :     value *= deriv_factor_swf;
     318        2600 :     targetdist_grid_pntr_->setValue(l,value);
     319             :     // double log_value = log_targetdist_grid_pntr_->getValue(l) - std::log(swf);
     320             :     // log_targetdist_grid_pntr_->setValue(l,log_value);
     321             :   }
     322          24 :   targetdist_grid_pntr_->scaleAllValuesAndDerivatives(1.0/norm);
     323             :   // log_targetdist_grid_pntr_->setMinToZero();
     324          24 : }
     325             : 
     326           6 : void TargetDistribution::applyTargetDistModiferToGrid(TargetDistModifer* modifer_pntr) {
     327             :   // plumed_massert(targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     328             :   // plumed_massert(log_targetdist_grid_pntr_!=NULL,"the grids have not been setup using setupGrids");
     329             :   //
     330           6 :   std::vector<double> integration_weights = GridIntegrationWeights::getIntegrationWeights(targetdist_grid_pntr_);
     331           6 :   double norm = 0.0;
     332       21212 :   for(Grid::index_t l=0; l<targetdist_grid_pntr_->getSize(); l++)
     333             :   {
     334       21206 :     double value = targetdist_grid_pntr_->getValue(l);
     335       21206 :     std::vector<double> cv_values = targetdist_grid_pntr_->getPoint(l);
     336       21206 :     value = modifer_pntr->getModifedTargetDistValue(value,cv_values);
     337       21206 :     norm += integration_weights[l]*value;
     338       21206 :     targetdist_grid_pntr_->setValue(l,value);
     339       21206 :     log_targetdist_grid_pntr_->setValue(l,-std::log(value));
     340       21206 :   }
     341           6 :   targetdist_grid_pntr_->scaleAllValuesAndDerivatives(1.0/norm);
     342           6 :   log_targetdist_grid_pntr_->setMinToZero();
     343           6 : }
     344             : 
     345             : 
     346          11 : void TargetDistribution::updateLogTargetDistGrid() {
     347       11414 :   for(Grid::index_t l=0; l<targetdist_grid_pntr_->getSize(); l++)
     348             :   {
     349       11403 :     log_targetdist_grid_pntr_->setValue(l,-std::log(targetdist_grid_pntr_->getValue(l)));
     350             :   }
     351          11 :   log_targetdist_grid_pntr_->setMinToZero();
     352          11 : }
     353             : 
     354             : 
     355           3 : void TargetDistribution::setMinimumOfTargetDistGridToZero() {
     356           3 :   targetDistGrid().setMinToZero();
     357           3 :   normalizeTargetDistGrid();
     358           3 :   updateLogTargetDistGrid();
     359           3 : }
     360             : 
     361             : 
     362           8 : void TargetDistribution::readInRestartTargetDistGrid(const std::string& grid_fname) {
     363           8 :   plumed_massert(isDynamic(),"this should only be used for dynamically updated target distributions!");
     364           8 :   IFile gridfile;
     365           8 :   if(!gridfile.FileExist(grid_fname)) {
     366           0 :     plumed_merror(getName()+": problem with reading previous target distribution when restarting, cannot find file " + grid_fname);
     367             :   }
     368           8 :   gridfile.open(grid_fname);
     369           8 :   Grid* restart_grid = Grid::create("targetdist",grid_args_,gridfile,false,false,false);
     370           8 :   if(restart_grid->getSize()!=targetdist_grid_pntr_->getSize()) {
     371           0 :     plumed_merror(getName()+": problem with reading previous target distribution when restarting, the grid is not of the correct size!");
     372             :   }
     373           8 :   VesTools::copyGridValues(restart_grid,targetdist_grid_pntr_);
     374           8 :   updateLogTargetDistGrid();
     375           8 :   delete restart_grid;
     376           8 : }
     377             : 
     378           1 : void TargetDistribution::clearLogTargetDistGrid() {
     379           1 :   log_targetdist_grid_pntr_->clear();
     380           1 : }
     381             : 
     382             : 
     383           0 : void TargetDistribution::checkNanAndInf() {
     384           0 :   for(Grid::index_t l=0; l<targetdist_grid_pntr_->getSize(); l++)
     385             :   {
     386           0 :     double value = targetdist_grid_pntr_->getValue(l);
     387           0 :     if(std::isnan(value) || std::isinf(value)) {
     388           0 :       std::string vs; Tools::convert(value,vs);
     389           0 :       std::vector<double> p = targetdist_grid_pntr_->getPoint(l);
     390           0 :       std::string ps; Tools::convert(p[0],ps);
     391           0 :       ps = "(" + ps;
     392           0 :       for(unsigned int k=1; k<p.size(); k++) {
     393           0 :         std::string t1; Tools::convert(p[k],t1);
     394           0 :         ps = ps + "," + t1;
     395           0 :       }
     396           0 :       ps = ps + ")";
     397           0 :       plumed_merror(getName()+": problem with target distribution, the value at " + ps + " is " + vs);
     398             :     }
     399             :   }
     400           0 : }
     401             : 
     402             : }
     403             : }

Generated by: LCOV version 1.13